From a2752ec71f68191293c59b36ab8703682400ad20 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Mon, 12 Jan 2026 09:27:50 -0800 Subject: [PATCH 1/4] Clear promptInputModel value onDidCommandFinish --- .../capabilities/commandDetection/promptInputModel.ts | 8 ++++++++ .../common/capabilities/commandDetectionCapability.ts | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts index 328f5f941ef82..875d9889e104c 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts @@ -113,6 +113,7 @@ export class PromptInputModel extends Disposable implements IPromptInputModel { onCommandStart: Event, onCommandStartChanged: Event, onCommandExecuted: Event, + onCommandFinished: Event, @ILogService private readonly _logService: ILogService ) { super(); @@ -127,6 +128,7 @@ export class PromptInputModel extends Disposable implements IPromptInputModel { this._register(onCommandStart(e => this._handleCommandStart(e as { marker: IMarker }))); this._register(onCommandStartChanged(() => this._handleCommandStartChanged())); this._register(onCommandExecuted(() => this._handleCommandExecuted())); + this._register(onCommandFinished(() => this._handleCommandFinished())); this._register(this.onDidStartInput(() => this._logCombinedStringIfTrace('PromptInputModel#onDidStartInput'))); this._register(this.onDidChangeInput(() => this._logCombinedStringIfTrace('PromptInputModel#onDidChangeInput'))); @@ -261,6 +263,12 @@ export class PromptInputModel extends Disposable implements IPromptInputModel { this._onDidChangeInput.fire(event); } + private _handleCommandFinished() { + // Clear the prompt input value when command finishes to prepare for the next command + // This prevents runCommand from detecting leftover text and sending ^C unnecessarily + this._value = ''; + } + @throttle(0) private _sync() { try { diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index e52d286d20e9b..259fc6ef00c85 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -84,7 +84,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe ) { super(); this._currentCommand = new PartialTerminalCommand(this._terminal); - this._promptInputModel = this._register(new PromptInputModel(this._terminal, this.onCommandStarted, this.onCommandStartChanged, this.onCommandExecuted, this._logService)); + this._promptInputModel = this._register(new PromptInputModel(this._terminal, this.onCommandStarted, this.onCommandStartChanged, this.onCommandExecuted, this.onCommandFinished, this._logService)); // Pull command line from the buffer if it was not set explicitly this._register(this.onCommandExecuted(command => { From 2c337019bb38ed5cb2194d793191fb0da9efa41d Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Mon, 12 Jan 2026 09:34:12 -0800 Subject: [PATCH 2/4] Add test --- .../commandDetection/promptInputModel.test.ts | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/test/common/capabilities/commandDetection/promptInputModel.test.ts b/src/vs/platform/terminal/test/common/capabilities/commandDetection/promptInputModel.test.ts index 64fe94b7ab953..e625ae66a9b86 100644 --- a/src/vs/platform/terminal/test/common/capabilities/commandDetection/promptInputModel.test.ts +++ b/src/vs/platform/terminal/test/common/capabilities/commandDetection/promptInputModel.test.ts @@ -24,6 +24,7 @@ suite('PromptInputModel', () => { let onCommandStart: Emitter; let onCommandStartChanged: Emitter; let onCommandExecuted: Emitter; + let onCommandFinished: Emitter; async function writePromise(data: string) { await new Promise(r => xterm.write(data, r)); @@ -37,6 +38,10 @@ suite('PromptInputModel', () => { onCommandExecuted.fire(null!); } + function fireCommandFinished() { + onCommandFinished.fire(null!); + } + function setContinuationPrompt(prompt: string) { promptInputModel.setContinuationPrompt(prompt); } @@ -68,7 +73,8 @@ suite('PromptInputModel', () => { onCommandStart = store.add(new Emitter()); onCommandStartChanged = store.add(new Emitter()); onCommandExecuted = store.add(new Emitter()); - promptInputModel = store.add(new PromptInputModel(xterm, onCommandStart.event, onCommandStartChanged.event, onCommandExecuted.event, new NullLogService)); + onCommandFinished = store.add(new Emitter()); + promptInputModel = store.add(new PromptInputModel(xterm, onCommandStart.event, onCommandStartChanged.event, onCommandExecuted.event, onCommandFinished.event, new NullLogService)); }); test('basic input and execute', async () => { @@ -138,6 +144,21 @@ suite('PromptInputModel', () => { }); }); + test('should clear value when command finishes', async () => { + await writePromise('$ '); + fireCommandStart(); + await assertPromptInput('|'); + + await writePromise('echo hello'); + await assertPromptInput('echo hello|'); + + fireCommandExecuted(); + strictEqual(promptInputModel.value, 'echo hello'); + + fireCommandFinished(); + strictEqual(promptInputModel.value, ''); + }); + test('cursor navigation', async () => { await writePromise('$ '); fireCommandStart(); From d604ce4b4df8b2e842b13c60ab6910b89ec90d64 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Mon, 12 Jan 2026 09:52:06 -0800 Subject: [PATCH 3/4] Remove stale state that doesnt exist anymore --- .../recordings/rich/macos_zsh_omz_echo_3_times.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/recordings/rich/macos_zsh_omz_echo_3_times.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/recordings/rich/macos_zsh_omz_echo_3_times.ts index 984e205d9a565..fb03eb65f071b 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/recordings/rich/macos_zsh_omz_echo_3_times.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/recordings/rich/macos_zsh_omz_echo_3_times.ts @@ -137,10 +137,6 @@ export const events = [ "type": "output", "data": "" }, - { - "type": "promptInputChange", - "data": "echo a" - }, { "type": "output", "data": "\u001b]633;P;Cwd=/Users/tyriar/playground/test1\u0007\u001b]633;EnvSingleStart;0;448d50d0-70fe-4ab5-842e-132f3b1c159a;\u0007\u001b]633;EnvSingleEnd;448d50d0-70fe-4ab5-842e-132f3b1c159a;\u0007\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b]633;A\u0007tyriar@Mac test1 % \u001b]633;B\u0007\u001b[K\u001b[?2004h" @@ -245,10 +241,6 @@ export const events = [ "type": "output", "data": "" }, - { - "type": "promptInputChange", - "data": "echo b" - }, { "type": "output", "data": "\u001b]633;P;Cwd=/Users/tyriar/playground/test1\u0007\u001b]633;EnvSingleStart;0;448d50d0-70fe-4ab5-842e-132f3b1c159a;\u0007\u001b]633;EnvSingleEnd;448d50d0-70fe-4ab5-842e-132f3b1c159a;\u0007\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b]633;A\u0007tyriar@Mac test1 % \u001b]633;B\u0007\u001b[K\u001b[?2004h" @@ -357,10 +349,6 @@ export const events = [ "type": "output", "data": "" }, - { - "type": "promptInputChange", - "data": "echo c" - }, { "type": "output", "data": "\u001b]633;P;Cwd=/Users/tyriar/playground/test1\u0007\u001b]633;EnvSingleStart;0;448d50d0-70fe-4ab5-842e-132f3b1c159a;\u0007\u001b]633;EnvSingleEnd;448d50d0-70fe-4ab5-842e-132f3b1c159a;\u0007\r\u001b[0m\u001b[27m\u001b[24m\u001b[J\u001b]633;A\u0007tyriar@Mac test1 % \u001b]633;B\u0007\u001b[K\u001b[?2004h" From f936493238db01432289dc62eec4257185b37353 Mon Sep 17 00:00:00 2001 From: anthonykim1 Date: Tue, 13 Jan 2026 10:16:02 -0800 Subject: [PATCH 4/4] Fire Empty _onDidChangeInput on promptInputModel _handlecommandFinish --- .../common/capabilities/commandDetection/promptInputModel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts index 875d9889e104c..a9a3f6a90d71e 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts @@ -267,6 +267,7 @@ export class PromptInputModel extends Disposable implements IPromptInputModel { // Clear the prompt input value when command finishes to prepare for the next command // This prevents runCommand from detecting leftover text and sending ^C unnecessarily this._value = ''; + this._onDidChangeInput.fire(this._createStateObject()); } @throttle(0)