Repository: microsoft/vscode
File: src/vs/workbench/contrib/terminal/browser/chatTerminalCommandMirror.ts (TypeScript)

Code before:
				} else {
					resolve();
				}
			} else {
				const appended = vt.text.slice(this._lastVT.length);
				if (appended) {
					detached.xterm.write(appended, resolve);
				} else {
					resolve();
				}
			}
		});

		this._lastVT = vt.text;

		const sourceRaw = this._xtermTerminal.raw;
		if (sourceRaw) {
			this._sourceRaw = sourceRaw;
			this._lastUpToDateCursorY = this._getAbsoluteCursorY(sourceRaw);
			if (!this._isStreaming && (!this._command.endMarker || this._command.endMarker.isDisposed)) {
				this._startStreaming(sourceRaw);
			}
		}

		this._lineCount = this._getRenderedLineCount();
		this._maxColumnWidth = this._computeMaxColumnWidth();

		return { lineCount: this._lineCount, maxColumnWidth: this._maxColumnWidth };
	}

	private async _getCommandOutputAsVT(source: XtermTerminal): Promise<{ text: string } | undefined> {
		if (this._store.isDisposed) {
			return undefined;
		}
		const executedMarker = this._command.executedMarker ?? (this._command as unknown as ICurrentPartialCommand).commandExecutedMarker;
		if (!executedMarker) {
			return undefined;
		}

		const endMarker = this._command.endMarker;
		const text = await source.getRangeAsVT(executedMarker, endMarker, endMarker?.line !== executedMarker.line);
		if (this._store.isDisposed) {
			return undefined;
		}
		if (!text) {
			return { text: '' };
		}

		return { text };
	}


Review comment (performance):
Does this happen after every update? That'll be too expensive. I think we should only do this for commands that are under some reasonable amount (100 lines?) and that have already finished. In other words, compact the xterm.js instance only after the command has finished. That'll slightly improve UX as it would remove a potentially unnecessary scroll bar and also reduce some memory usage.

Code after:
		}

		await new Promise<void>(resolve => {
			if (!this._lastVT) {
				if (vt.text) {
					detached.xterm.write(vt.text, resolve);
				} else {
					resolve();
				}
			} else {
				const appended = vt.text.slice(this._lastVT.length);
				if (appended) {
					detached.xterm.write(appended, resolve);
				} else {
					resolve();
				}
			}
		});

		this._lastVT = vt.text;

		const sourceRaw = this._xtermTerminal.raw;
		if (sourceRaw) {
			this._sourceRaw = sourceRaw;
			this._lastUpToDateCursorY = this._getAbsoluteCursorY(sourceRaw);
			if (!this._isStreaming && (!this._command.endMarker || this._command.endMarker.isDisposed)) {
				this._startStreaming(sourceRaw);
			}
		}

		this._lineCount = this._getRenderedLineCount();
		// Only compute max column width after the command finishes and for small outputs
		const commandFinished = this._command.endMarker && !this._command.endMarker.isDisposed;
		if (commandFinished && this._lineCount <= ChatTerminalMirrorMetrics.MaxLinesForColumnWidthComputation) {
			this._maxColumnWidth = this._computeMaxColumnWidth();
		}

		return { lineCount: this._lineCount, maxColumnWidth: this._maxColumnWidth };
	}

	private async _getCommandOutputAsVT(source: XtermTerminal): Promise<{ text: string } | undefined> {
		if (this._store.isDisposed) {
			return undefined;
		}
		const executedMarker = this._command.executedMarker ?? (this._command as unknown as ICurrentPartialCommand).commandExecutedMarker;
		if (!executedMarker) {
			return undefined;
		}

		const endMarker = this._command.endMarker;
		const text = await source.getRangeAsVT(executedMarker, endMarker, endMarker?.line !== executedMarker.line);