From 5dde2fba0c0a2ff845c8bf90f8bbe4ab9d701b84 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 17 Apr 2024 15:49:26 -0700 Subject: [PATCH] Take continuation prompt into account for pwsh --- .../common/capabilities/capabilities.ts | 1 + .../commandDetection/promptInputModel.ts | 18 ++++++++++++++---- .../capabilities/commandDetectionCapability.ts | 4 ++++ .../common/xterm/shellIntegrationAddon.ts | 11 +++++++++++ .../browser/media/shellIntegration.ps1 | 6 ++++++ 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/capabilities.ts b/src/vs/platform/terminal/common/capabilities/capabilities.ts index 3300d2d73d4..d820ab63e99 100644 --- a/src/vs/platform/terminal/common/capabilities/capabilities.ts +++ b/src/vs/platform/terminal/common/capabilities/capabilities.ts @@ -178,6 +178,7 @@ export interface ICommandDetectionCapability { readonly onCommandExecuted: Event; readonly onCommandInvalidated: Event; readonly onCurrentCommandInvalidated: Event; + setContinuationPrompt(value: string): void; setCwd(value: string): void; setIsWindowsPty(value: boolean): void; setIsCommandStorageDisabled(): void; diff --git a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts index 7d252044192..687b53f9152 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetection/promptInputModel.ts @@ -26,6 +26,8 @@ export interface IPromptInputModel { readonly value: string; readonly cursorIndex: number; + + setContinuationPrompt(value: string): void; } export class PromptInputModel extends Disposable implements IPromptInputModel { @@ -33,6 +35,7 @@ export class PromptInputModel extends Disposable implements IPromptInputModel { private _commandStartMarker: IMarker | undefined; private _commandStartX: number = 0; + private _continuationPrompt: string | undefined; private _value: string = ''; get value() { return this._value; } @@ -61,7 +64,10 @@ export class PromptInputModel extends Disposable implements IPromptInputModel { this._register(onCommandStart(e => this._handleCommandStart(e as { marker: IMarker }))); this._register(onCommandExecuted(() => this._handleCommandExecuted())); + } + setContinuationPrompt(value: string): void { + this._continuationPrompt = value; } private _handleCommandStart(command: { marker: IMarker }) { @@ -116,13 +122,17 @@ export class PromptInputModel extends Disposable implements IPromptInputModel { // Add multi-lines const absoluteCursorY = buffer.baseY + buffer.cursorY; for (let y = commandStartY + 1; y <= absoluteCursorY; y++) { - const text = buffer.getLine(y)?.translateToString(true); - if (text) { - this._value += `\n${text}`; + let lineText = buffer.getLine(y)?.translateToString(true); + if (lineText) { + if (this._continuationPrompt && lineText.startsWith(this._continuationPrompt)) { + lineText = lineText.substring(this._continuationPrompt.length); + } + this._value += `\n${lineText}`; if (y === absoluteCursorY) { // TODO: Detect continuation + // For pwsh: (Get-PSReadLineOption).ContinuationPrompt // TODO: Wide/emoji length support - this._cursorIndex = Math.max(this._value.length - text.length + buffer.cursorX, 0); + this._cursorIndex = Math.max(this._value.length - lineText.length + buffer.cursorX, 0); } } } diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index e22387595d2..6efbebd22a7 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -199,6 +199,10 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe } } + setContinuationPrompt(value: string): void { + this._promptInputModel.setContinuationPrompt(value); + } + setCwd(value: string) { this._cwd = value; } diff --git a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts index 798fc50f934..2f056816d57 100644 --- a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts +++ b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts @@ -160,6 +160,8 @@ const enum VSCodeOscPt { * - `IsWindows` - Indicates whether the terminal is using a Windows backend like winpty or * conpty. This may be used to enable additional heuristics as the positioning of the shell * integration sequences are not guaranteed to be correct. Valid values: `True`, `False`. + * - `ContinuationPrompt` - Reports the continuation prompt that is printed at the start of + * multi-line inputs. * * WARNING: Any other properties may be changed and are not guaranteed to work in the future. */ @@ -379,6 +381,10 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati return true; } switch (key) { + case 'ContinuationPrompt': { + this._updateContinuationPrompt(value); + return true; + } case 'Cwd': { this._updateCwd(value); return true; @@ -404,6 +410,11 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati return false; } + private _updateContinuationPrompt(value: string) { + const commandDetection = this.capabilities.get(TerminalCapability.CommandDetection); + commandDetection?.setContinuationPrompt(value); + } + private _updateCwd(value: string) { value = sanitizeCwd(value); this._createOrGetCwdDetection().updateCwd(value); diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 index ac30ba1653d..16f7d55e619 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 @@ -135,6 +135,12 @@ else { [Console]::Write("$([char]0x1b)]633;P;IsWindows=$IsWindows`a") } +# Set ContinuationPrompt property +$ContinuationPrompt = (Get-PSReadLineOption).ContinuationPrompt +if ($ContinuationPrompt) { + [Console]::Write("$([char]0x1b)]633;P;ContinuationPrompt=$(__VSCode-Escape-Value $ContinuationPrompt)`a") +} + # Set always on key handlers which map to default VS Code keybindings function Set-MappedKeyHandler { param ([string[]] $Chord, [string[]]$Sequence)