From cff5f7ef4bbcecf21176cdf4748f17c9cd731c0f Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 15 Sep 2022 06:44:07 -0700 Subject: [PATCH 1/3] Send ctrl+c before running a command unless there is no input Fixes #144279 --- .../common/capabilities/capabilities.ts | 5 ++++ .../commandDetectionCapability.ts | 27 +++++++++++++++++++ .../browser/terminalRunRecentQuickPick.ts | 12 ++++++++- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/capabilities.ts b/src/vs/platform/terminal/common/capabilities/capabilities.ts index 8301b35a1b3..e2e9f8bab98 100644 --- a/src/vs/platform/terminal/common/capabilities/capabilities.ts +++ b/src/vs/platform/terminal/common/capabilities/capabilities.ts @@ -146,6 +146,11 @@ export interface ICommandDetectionCapability { readonly executingCommandObject: ITerminalCommand | undefined; /** The current cwd at the cursor's position. */ readonly cwd: string | undefined; + /** + * Whether a command is currently being input. If the a command is current not being input or + * the state cannot reliably be detected the fallback of undefined will be used. + */ + readonly hasInput: boolean | undefined; readonly onCommandStarted: Event; readonly onCommandFinished: Event; readonly onCommandInvalidated: Event; diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 5bcc9a3e690..d54badb4720 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -72,6 +72,23 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { return undefined; } get cwd(): string | undefined { return this._cwd; } + private get _isInputting(): boolean { + return !!(this._currentCommand.commandStartMarker && !this._currentCommand.commandExecutedMarker); + } + + get hasInput(): boolean | undefined { + if (!this._isInputting || !this._currentCommand?.commandStartMarker) { + return undefined; + } + if (this._terminal.buffer.active.cursorY === this._currentCommand.commandStartMarker?.line) { + const line = this._terminal.buffer.active.getLine(this._terminal.buffer.active.cursorY)?.translateToString(true, this._currentCommand.commandStartX); + if (!line) { + return undefined; + } + return line.length > 0; + } + return true; + } private readonly _onCommandStarted = new Emitter(); readonly onCommandStarted = this._onCommandStarted.event; @@ -316,6 +333,16 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { } this._currentCommand.commandStartX = this._terminal.buffer.active.cursorX; this._currentCommand.commandStartMarker = options?.marker || this._terminal.registerMarker(0); + + // Clear executed as it much happen after command start + this._currentCommand.commandExecutedMarker?.dispose(); + this._currentCommand.commandExecutedMarker = undefined; + this._currentCommand.commandExecutedX = undefined; + for (const m of this._commandMarkers) { + m.dispose(); + } + this._commandMarkers.length = 0; + this._onCommandStarted.fire({ marker: options?.marker || this._currentCommand.commandStartMarker, markProperties: options?.markProperties } as ITerminalCommand); this._logService.debug('CommandDetectionCapability#handleCommandStart', this._currentCommand.commandStartX, this._currentCommand.commandStartMarker?.line); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts b/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts index ac800e634ee..13eae8cc2b8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts @@ -264,8 +264,8 @@ export async function showRunRecentQuickPick( } else { // command text = result.rawLabel; } - instance.sendText(text, !quickPick.keyMods.alt, true); quickPick.hide(); + runCommand(instance, text, !quickPick.keyMods.alt); if (quickPick.keyMods.alt) { instance.focus(); } @@ -283,6 +283,16 @@ export async function showRunRecentQuickPick( }); } +async function runCommand(instance: ITerminalInstance, commandLine: string, addNewLine: boolean): Promise { + // Determine whether to send ETX (ctrl+c) before running the command. This should always + // happen unless command detection can reliably say that a command is being entered and + // there is no content in the prompt + if (instance.capabilities.get(TerminalCapability.CommandDetection)?.hasInput !== false) { + await instance.sendText('\x03', false); + } + await instance.sendText(commandLine, addNewLine, true); +} + class TerminalOutputProvider implements ITextModelContentProvider { static scheme = 'TERMINAL_OUTPUT'; From 4d11494d118391dabf9c4e4c43b5f11ed6160710 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 15 Sep 2022 08:00:26 -0700 Subject: [PATCH 2/3] Polish clearing command before run on unix --- .../common/capabilities/commandDetectionCapability.ts | 4 ++-- .../contrib/terminal/browser/terminalRunRecentQuickPick.ts | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index d54badb4720..fbf23753980 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -80,9 +80,9 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { if (!this._isInputting || !this._currentCommand?.commandStartMarker) { return undefined; } - if (this._terminal.buffer.active.cursorY === this._currentCommand.commandStartMarker?.line) { + if (this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY === this._currentCommand.commandStartMarker?.line) { const line = this._terminal.buffer.active.getLine(this._terminal.buffer.active.cursorY)?.translateToString(true, this._currentCommand.commandStartX); - if (!line) { + if (line === undefined) { return undefined; } return line.length > 0; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts b/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts index 13eae8cc2b8..207ea0f8ba3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick.ts @@ -26,6 +26,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { showWithPinnedItems } from 'vs/platform/quickinput/browser/quickPickPin'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { timeout } from 'vs/base/common/async'; export async function showRunRecentQuickPick( accessor: ServicesAccessor, @@ -289,8 +290,12 @@ async function runCommand(instance: ITerminalInstance, commandLine: string, addN // there is no content in the prompt if (instance.capabilities.get(TerminalCapability.CommandDetection)?.hasInput !== false) { await instance.sendText('\x03', false); + // Wait a little before running the command to avoid the sequences being echoed while the ^C + // is being evaluated + await timeout(100); } - await instance.sendText(commandLine, addNewLine, true); + // Use bracketed paste mode only when not running the command + await instance.sendText(commandLine, addNewLine, !addNewLine); } class TerminalOutputProvider implements ITextModelContentProvider { From 6f1527d71748a3f6dfabda3102e5b82b4105e179 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 15 Sep 2022 10:12:50 -0700 Subject: [PATCH 3/3] Update src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts Co-authored-by: Megan Rogge --- .../terminal/common/capabilities/commandDetectionCapability.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index fbf23753980..1d268538a0a 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -334,7 +334,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { this._currentCommand.commandStartX = this._terminal.buffer.active.cursorX; this._currentCommand.commandStartMarker = options?.marker || this._terminal.registerMarker(0); - // Clear executed as it much happen after command start + // Clear executed as it must happen after command start this._currentCommand.commandExecutedMarker?.dispose(); this._currentCommand.commandExecutedMarker = undefined; this._currentCommand.commandExecutedX = undefined;