Force chat request height update when codeblock is present (#297706)

* Force chat request height update when codeblock is present
Fix #288361

* Update src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatMarkdownContentPart.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Rob Lourens
2026-02-25 16:05:22 +00:00
committed by GitHub
parent b6f27b3e0a
commit 4a231ff09a
2 changed files with 32 additions and 16 deletions
@@ -15,6 +15,7 @@ import { findLast } from '../../../../../../base/common/arraysFind.js';
import { Codicon } from '../../../../../../base/common/codicons.js';
import { Lazy } from '../../../../../../base/common/lazy.js';
import { Disposable, DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../../../base/common/lifecycle.js';
import { Emitter, Event } from '../../../../../../base/common/event.js';
import { autorun, autorunSelfDisposable, derived } from '../../../../../../base/common/observable.js';
import { ScrollbarVisibility } from '../../../../../../base/common/scrollable.js';
import { equalsIgnoreCase } from '../../../../../../base/common/strings.js';
@@ -89,6 +90,10 @@ export class ChatMarkdownContentPart extends Disposable implements IChatContentP
readonly codeblocksPartId = String(++ChatMarkdownContentPart.ID_POOL);
readonly domNode: HTMLElement;
// This Event exists for one specific scenario and the pattern shouldn't be copied without a good reason
private readonly _onDidChangeHeight = this._register(new Emitter<void>());
readonly onDidChangeHeight: Event<void> = this._onDidChangeHeight.event;
private readonly allRefs: IDisposableReference<CodeBlockPart | CollapsedCodeBlock | MarkdownDiffBlockPart>[] = [];
private readonly _codeblocks: IMarkdownPartCodeBlockInfo[] = [];
@@ -407,7 +412,14 @@ export class ChatMarkdownContentPart extends Disposable implements IChatContentP
this._codeblocks[data.codeBlockPartIndex].codemapperUri = e.codemapperUri;
});
editorInfo.render(data, currentWidth);
editorInfo.render(data, currentWidth).then(() => {
// There is a scenario where we set the model on the editor in a request and the ResizeObserver is not triggered.
// Work around it with this targeted onDidHeightChange. But this pattern generally shouldn't be necessary and
// shouldn't be copied elsewhere.
if (!this._store.isDisposed && isRequestVM(data.element)) {
this._onDidChangeHeight.fire();
}
});
return ref;
}
@@ -324,6 +324,23 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
}
}
private fireItemHeightChange(template: IChatListItemTemplate, measuredHeight?: number): void {
if (!template.currentElement || !template.rowContainer.isConnected) {
return;
}
const height = measuredHeight ?? template.rowContainer.getBoundingClientRect().height;
if (height === 0 || !height) {
return;
}
const normalizedHeight = Math.ceil(height);
template.currentElement.currentRenderedHeight = normalizedHeight;
if (template.currentElement !== this._elementBeingRendered) {
this._onDidChangeItemHeight.fire({ element: template.currentElement, height: normalizedHeight });
}
}
/**
* Compute a rate to render at in words/s.
*/
@@ -610,23 +627,9 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
}));
const resizeObserver = templateDisposables.add(new dom.DisposableResizeObserver((entries) => {
if (!template.currentElement) {
return;
}
const entry = entries[0];
if (entry) {
const height = entry.borderBoxSize.at(0)?.blockSize;
if (height === 0 || !height || !template.rowContainer.isConnected) {
// Don't fire for changes that happen from the row being removed from the DOM
return;
}
const normalizedHeight = Math.ceil(height);
template.currentElement.currentRenderedHeight = normalizedHeight;
if (template.currentElement !== this._elementBeingRendered) {
this._onDidChangeItemHeight.fire({ element: template.currentElement, height: normalizedHeight });
}
this.fireItemHeightChange(template, entry.borderBoxSize.at(0)?.blockSize);
}
}));
templateDisposables.add(resizeObserver.observe(rowContainer));
@@ -2384,6 +2387,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
const fillInIncompleteTokens = isResponseVM(element) && (!element.isComplete || element.isCanceled || element.errorDetails?.responseIsFiltered || element.errorDetails?.responseIsIncomplete || !!element.renderData);
const codeBlockStartIndex = context.codeBlockStartIndex;
const markdownPart = templateData.instantiationService.createInstance(ChatMarkdownContentPart, markdown, context, this._editorPool, fillInIncompleteTokens, codeBlockStartIndex, this.chatContentMarkdownRenderer, undefined, this._currentLayoutWidth.get(), this.codeBlockModelCollection, {});
markdownPart.addDisposable(markdownPart.onDidChangeHeight(() => this.fireItemHeightChange(templateData)));
if (isRequestVM(element)) {
markdownPart.domNode.tabIndex = 0;
if (this.configService.getValue<string>('chat.editRequests') === 'inline' && this.rendererOptions.editable) {