Skip to content

Commit be10e63

Browse files
committed
Ensure shell integration is enables for custom keys
Fixes #45705
1 parent 5bb939a commit be10e63

File tree

6 files changed

+75
-13
lines changed

6 files changed

+75
-13
lines changed

src/vs/platform/terminal/common/terminal.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,19 @@ export type ITerminalProfileObject = ITerminalExecutable | ITerminalProfileSourc
785785
export type ITerminalProfileType = ITerminalProfile | IExtensionTerminalProfile;
786786

787787
export interface IShellIntegration {
788-
capabilities: ITerminalCapabilityStore;
788+
readonly capabilities: ITerminalCapabilityStore;
789+
readonly status: ShellIntegrationStatus;
790+
791+
readonly onDidChangeStatus: Event<ShellIntegrationStatus>;
792+
789793
deserialize(serialized: ISerializedCommandDetectionCapability): void;
790794
}
795+
796+
export const enum ShellIntegrationStatus {
797+
/** No shell integration sequences have been encountered. */
798+
Off,
799+
/** Final term shell integration sequences have been encountered. */
800+
FinalTerm,
801+
/** VS Code shell integration sequences have been encountered. Supercedes FinalTerm. */
802+
VSCode
803+
}

src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { IShellIntegration } from 'vs/platform/terminal/common/terminal';
6+
import { IShellIntegration, ShellIntegrationStatus } from 'vs/platform/terminal/common/terminal';
77
import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
88
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
99
import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability';
@@ -16,6 +16,7 @@ import { ILogService } from 'vs/platform/log/common/log';
1616
import type { ITerminalAddon, Terminal } from 'xterm-headless';
1717
import { ISerializedCommandDetectionCapability } from 'vs/platform/terminal/common/terminalProcess';
1818
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
19+
import { Emitter } from 'vs/base/common/event';
1920

2021
/**
2122
* Shell integration is a feature that enhances the terminal's understanding of what's happening
@@ -137,6 +138,12 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati
137138
private _hasUpdatedTelemetry: boolean = false;
138139
private _activationTimeout: any;
139140
private _commonProtocolDisposables: IDisposable[] = [];
141+
private _status: ShellIntegrationStatus = ShellIntegrationStatus.Off;
142+
143+
get status(): ShellIntegrationStatus { return this._status; }
144+
145+
private readonly _onDidChangeStatus = new Emitter<ShellIntegrationStatus>();
146+
readonly onDidChangeStatus = this._onDidChangeStatus.event;
140147

141148
constructor(
142149
private readonly _disableTelemetry: boolean | undefined,
@@ -167,6 +174,15 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati
167174
}
168175

169176
private _handleFinalTermSequence(data: string): boolean {
177+
const didHandle = this._doHandleFinalTermSequence(data);
178+
if (this._status === ShellIntegrationStatus.Off) {
179+
this._status = ShellIntegrationStatus.FinalTerm;
180+
this._onDidChangeStatus.fire(this._status);
181+
}
182+
return didHandle;
183+
}
184+
185+
private _doHandleFinalTermSequence(data: string): boolean {
170186
if (!this._terminal) {
171187
return false;
172188
}
@@ -204,6 +220,10 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati
204220
this._hasUpdatedTelemetry = true;
205221
this._clearActivationTimeout();
206222
}
223+
if (this._status !== ShellIntegrationStatus.VSCode) {
224+
this._status = ShellIntegrationStatus.VSCode;
225+
this._onDidChangeStatus.fire(this._status);
226+
}
207227
return didHandle;
208228
}
209229

src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -181,21 +181,21 @@ if (isWindows) {
181181
// Map certain keybindings in pwsh to unused keys which get handled by PSReadLine handlers in the
182182
// shell integration script. This allows keystrokes that cannot be sent via VT sequences to work.
183183
// See https://github.com/microsoft/terminal/issues/879#issuecomment-497775007
184-
registerSendSequenceKeybinding('\x1b[24~a', { // F12,a -> ctrl+space
185-
when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.PowerShell), CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
184+
registerSendSequenceKeybinding('\x1b[24~a', { // F12,a -> ctrl+space (MenuComplete)
185+
when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
186186
primary: KeyMod.CtrlCmd | KeyCode.Space,
187187
mac: { primary: KeyMod.WinCtrl | KeyCode.Space }
188188
});
189-
registerSendSequenceKeybinding('\x1b[24~b', { // F12,b -> alt+space
190-
when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.PowerShell), CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
189+
registerSendSequenceKeybinding('\x1b[24~b', { // F12,b -> alt+space (SetMark)
190+
when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
191191
primary: KeyMod.Alt | KeyCode.Space
192192
});
193-
registerSendSequenceKeybinding('\x1b[24~c', { // F12,c -> shift+enter
194-
when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.PowerShell), CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
193+
registerSendSequenceKeybinding('\x1b[24~c', { // F12,c -> shift+enter (AddLine)
194+
when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
195195
primary: KeyMod.Shift | KeyCode.Enter
196196
});
197-
registerSendSequenceKeybinding('\x1b[24~d', { // F12,d -> shift+end - \x1b[1;2F is supposed to work but it doesn't
198-
when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.PowerShell)),
197+
registerSendSequenceKeybinding('\x1b[24~d', { // F12,d -> shift+end (SelectLine) - HACK: \x1b[1;2F is supposed to work but it doesn't
198+
when: ContextKeyExpr.and(TerminalContextKeys.focus, ContextKeyExpr.equals(TerminalContextKeyStrings.ShellType, WindowsShellType.PowerShell), TerminalContextKeys.terminalShellIntegrationEnabled, CONTEXT_ACCESSIBILITY_MODE_ENABLED.negate()),
199199
mac: { primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.RightArrow }
200200
});
201201

src/vs/workbench/contrib/terminal/browser/terminalInstance.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag
4646
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
4747
import { ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
4848
import { TerminalCapabilityStoreMultiplexer } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
49-
import { IProcessDataEvent, IProcessPropertyMap, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, PosixShellType, ProcessPropertyType, TerminalIcon, TerminalLocation, TerminalSettingId, TerminalShellType, TitleEventSource, WindowsShellType } from 'vs/platform/terminal/common/terminal';
49+
import { IProcessDataEvent, IProcessPropertyMap, IShellLaunchConfig, ITerminalDimensionsOverride, ITerminalLaunchError, PosixShellType, ProcessPropertyType, ShellIntegrationStatus, TerminalIcon, TerminalLocation, TerminalSettingId, TerminalShellType, TitleEventSource, WindowsShellType } from 'vs/platform/terminal/common/terminal';
5050
import { escapeNonWindowsPath, collapseTildePath } from 'vs/platform/terminal/common/terminalEnvironment';
5151
import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry';
5252
import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
@@ -356,6 +356,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
356356
private readonly _terminalShellTypeContextKey: IContextKey<string>,
357357
private readonly _terminalAltBufferActiveContextKey: IContextKey<boolean>,
358358
private readonly _terminalInRunCommandPicker: IContextKey<boolean>,
359+
private readonly _terminalShellIntegrationEnabledContextKey: IContextKey<boolean>,
359360
private readonly _configHelper: TerminalConfigHelper,
360361
private _shellLaunchConfig: IShellLaunchConfig,
361362
resource: URI | undefined,
@@ -1083,6 +1084,13 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
10831084
const screenElement = xterm.attachToElement(xtermElement);
10841085

10851086
xterm.onDidChangeFindResults((results) => this._onDidChangeFindResults.fire(results));
1087+
xterm.shellIntegration.onDidChangeStatus(() => {
1088+
if (this.hasFocus) {
1089+
this._setShellIntegrationContextKey();
1090+
} else {
1091+
this._terminalShellIntegrationEnabledContextKey.reset();
1092+
}
1093+
});
10861094

10871095
if (!xterm.raw.element || !xterm.raw.textarea) {
10881096
throw new Error('xterm elements not set after open');
@@ -1216,16 +1224,25 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
12161224
private _setFocus(focused?: boolean): void {
12171225
if (focused) {
12181226
this._terminalFocusContextKey.set(true);
1227+
this._setShellIntegrationContextKey();
12191228
this._onDidFocus.fire(this);
12201229
} else {
1221-
this._terminalFocusContextKey.reset();
1230+
this.resetFocusContextKey();
12221231
this._onDidBlur.fire(this);
12231232
this._refreshSelectionContextKey();
12241233
}
12251234
}
12261235

1236+
private _setShellIntegrationContextKey(): void {
1237+
console.log('set', this.xterm?.shellIntegration.status === ShellIntegrationStatus.VSCode);
1238+
if (this.xterm) {
1239+
this._terminalShellIntegrationEnabledContextKey.set(this.xterm.shellIntegration.status === ShellIntegrationStatus.VSCode);
1240+
}
1241+
}
1242+
12271243
resetFocusContextKey(): void {
12281244
this._terminalFocusContextKey.reset();
1245+
this._terminalShellIntegrationEnabledContextKey.reset();
12291246
}
12301247

12311248
private _initDragAndDrop(container: HTMLElement) {
@@ -1301,6 +1318,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
13011318
}
13021319
const terminalFocused = !isFocused && (document.activeElement === this.xterm.raw.textarea || document.activeElement === this.xterm.raw.element);
13031320
this._terminalFocusContextKey.set(terminalFocused);
1321+
if (terminalFocused) {
1322+
this._setShellIntegrationContextKey();
1323+
} else {
1324+
this._terminalShellIntegrationEnabledContextKey.reset();
1325+
}
13041326
}
13051327

13061328
private _refreshAltBufferContextKey() {
@@ -1381,7 +1403,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
13811403
// as 'blur' event in xterm.raw.textarea is not triggered on xterm.dispose()
13821404
// See https://github.com/microsoft/vscode/issues/138358
13831405
if (isFirefox) {
1384-
this._terminalFocusContextKey.reset();
1406+
this.resetFocusContextKey();
13851407
this._terminalHasTextContextKey.reset();
13861408
this._onDidBlur.fire(this);
13871409
}

src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
2424
private _terminalShellTypeContextKey: IContextKey<string>;
2525
private _terminalAltBufferActiveContextKey: IContextKey<boolean>;
2626
private _terminalInRunCommandPicker: IContextKey<boolean>;
27+
private _terminalShellIntegrationEnabled: IContextKey<boolean>;
2728
private _configHelper: TerminalConfigHelper;
2829

2930
private readonly _onDidCreateInstance = new Emitter<ITerminalInstance>();
@@ -39,6 +40,7 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
3940
this._terminalShellTypeContextKey = TerminalContextKeys.shellType.bindTo(this._contextKeyService);
4041
this._terminalAltBufferActiveContextKey = TerminalContextKeys.altBufferActive.bindTo(this._contextKeyService);
4142
this._terminalInRunCommandPicker = TerminalContextKeys.inTerminalRunCommandPicker.bindTo(this._contextKeyService);
43+
this._terminalShellIntegrationEnabled = TerminalContextKeys.terminalShellIntegrationEnabled.bindTo(this._contextKeyService);
4244
this._configHelper = _instantiationService.createInstance(TerminalConfigHelper);
4345
}
4446

@@ -52,6 +54,7 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
5254
this._terminalShellTypeContextKey,
5355
this._terminalAltBufferActiveContextKey,
5456
this._terminalInRunCommandPicker,
57+
this._terminalShellIntegrationEnabled,
5558
this._configHelper,
5659
shellLaunchConfig,
5760
resource

src/vs/workbench/contrib/terminal/common/terminalContextKey.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const enum TerminalContextKeyStrings {
3232
SplitTerminal = 'terminalSplitTerminal',
3333
ShellType = 'terminalShellType',
3434
InTerminalRunCommandPicker = 'inTerminalRunCommandPicker',
35+
TerminalShellIntegrationEnabled = 'terminalShellIntegrationEnabled'
3536
}
3637

3738
export namespace TerminalContextKeys {
@@ -123,4 +124,7 @@ export namespace TerminalContextKeys {
123124

124125
/** Whether the terminal run command picker is currently open. */
125126
export const inTerminalRunCommandPicker = new RawContextKey<boolean>(TerminalContextKeyStrings.InTerminalRunCommandPicker, false, localize('inTerminalRunCommandPickerContextKey', "Whether the terminal run command picker is currently open."));
127+
128+
/** Whether shell integration is enabled in the active terminal. This only considers full VS Code shell integration. */
129+
export const terminalShellIntegrationEnabled = new RawContextKey<boolean>(TerminalContextKeyStrings.TerminalShellIntegrationEnabled, false, localize('terminalShellIntegrationEnabled', "Whether shell integration is enabled in the active terminal"));
126130
}

0 commit comments

Comments
 (0)