Clear promptInput's value onCommandFinished (#287139)

* Clear promptInputModel value onDidCommandFinish

* Add test

* Remove stale state that doesnt exist anymore

* Fire Empty _onDidChangeInput on promptInputModel  _handlecommandFinish
This commit is contained in:
Anthony Kim
2026-01-14 11:29:35 -08:00
committed by GitHub
parent b41e884868
commit ace789bc8d
4 changed files with 32 additions and 14 deletions

View File

@@ -113,6 +113,7 @@ export class PromptInputModel extends Disposable implements IPromptInputModel {
onCommandStart: Event<ITerminalCommand>,
onCommandStartChanged: Event<void>,
onCommandExecuted: Event<ITerminalCommand>,
onCommandFinished: Event<ITerminalCommand>,
@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,13 @@ 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 = '';
this._onDidChangeInput.fire(this._createStateObject());
}
@throttle(0)
private _sync() {
try {

View File

@@ -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 => {

View File

@@ -24,6 +24,7 @@ suite('PromptInputModel', () => {
let onCommandStart: Emitter<ITerminalCommand>;
let onCommandStartChanged: Emitter<void>;
let onCommandExecuted: Emitter<ITerminalCommand>;
let onCommandFinished: Emitter<ITerminalCommand>;
async function writePromise(data: string) {
await new Promise<void>(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();

View File

@@ -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"