From cceac1afda8335625e2ba0ddd49781cf7be04640 Mon Sep 17 00:00:00 2001 From: John Sanchirico <59657471+sanchirico@users.noreply.github.com> Date: Mon, 2 Mar 2026 13:07:18 -0500 Subject: [PATCH] Fix chat terminal flicker during streaming (#298598) --- .../browser/chatTerminalCommandMirror.ts | 20 ++++++++----------- .../browser/chatTerminalCommandMirror.test.ts | 6 ++---- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/chatTerminalCommandMirror.ts b/src/vs/workbench/contrib/terminal/browser/chatTerminalCommandMirror.ts index 64715a47835..6d399910388 100644 --- a/src/vs/workbench/contrib/terminal/browser/chatTerminalCommandMirror.ts +++ b/src/vs/workbench/contrib/terminal/browser/chatTerminalCommandMirror.ts @@ -308,12 +308,10 @@ export class DetachedTerminalCommandMirror extends Disposable implements IDetach // if we blindly append. const canAppend = !!this._lastVT && vt.text.length >= this._lastVT.length && this._vtBoundaryMatches(vt.text, this._lastVT.length); if (!canAppend) { - // Reset the terminal if we had previous content (can't append, need full rewrite) - if (this._lastVT) { - detached.xterm.reset(); - } - if (vt.text) { - detached.xterm.write(vt.text, resolve); + // Use \x1bc (RIS) + new content in one write to avoid a blank frame + const payload = this._lastVT ? `\x1bc${vt.text}` : vt.text; + if (payload) { + detached.xterm.write(payload, resolve); } else { resolve(); } @@ -542,12 +540,10 @@ export class DetachedTerminalCommandMirror extends Disposable implements IDetach const canAppend = !!this._lastVT && startLine >= previousCursor && vt.text.length >= this._lastVT.length && this._vtBoundaryMatches(vt.text, this._lastVT.length); await new Promise(resolve => { if (!canAppend) { - // Reset the terminal if we had previous content (can't append, need full rewrite) - if (this._lastVT) { - detachedRaw.reset(); - } - if (vt.text) { - detachedRaw.write(vt.text, resolve); + // Use \x1bc (RIS) + new content in one write to avoid a blank frame + const payload = this._lastVT ? `\x1bc${vt.text}` : vt.text; + if (payload) { + detachedRaw.write(payload, resolve); } else { resolve(); } diff --git a/src/vs/workbench/contrib/terminal/test/browser/chatTerminalCommandMirror.test.ts b/src/vs/workbench/contrib/terminal/test/browser/chatTerminalCommandMirror.test.ts index 851c3d5f702..3d91b41d178 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/chatTerminalCommandMirror.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/chatTerminalCommandMirror.test.ts @@ -261,10 +261,8 @@ suite('Workbench - ChatTerminalCommandMirror', () => { // Boundary should NOT match because the prefix diverged strictEqual(boundaryMatches, false, 'Boundary check should detect divergence'); - // When boundary doesn't match, the fix does a full reset + rewrite - // instead of corrupting the output by blind slicing - mirror.raw.reset(); - await write(mirror, vt2); + // Use \x1bc (RIS) + new content in one write to avoid a blank frame + await write(mirror, `\x1bc${vt2}`); // Final content should be the complete new VT, not corrupted strictEqual(getBufferText(mirror), 'DifferentPrefixLine3');