mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-31 09:10:30 -04:00
Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3 (#6516)
* Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3 * fix tests
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Terminal, ITerminalAddon } from 'xterm';
|
||||
import { addDisposableListener } from 'vs/base/browser/dom';
|
||||
import { INavigationMode } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
|
||||
export class NavigationModeAddon implements INavigationMode, ITerminalAddon {
|
||||
private _terminal: Terminal;
|
||||
|
||||
constructor(
|
||||
private _navigationModeContextKey: IContextKey<boolean>
|
||||
) { }
|
||||
|
||||
activate(terminal: Terminal): void {
|
||||
this._terminal = terminal;
|
||||
}
|
||||
|
||||
dispose() { }
|
||||
|
||||
exitNavigationMode(): void {
|
||||
this._terminal.scrollToBottom();
|
||||
this._terminal.focus();
|
||||
}
|
||||
|
||||
focusPreviousLine(): void {
|
||||
// Focus previous row if a row is already focused
|
||||
if (document.activeElement && document.activeElement.parentElement && document.activeElement.parentElement.classList.contains('xterm-accessibility-tree')) {
|
||||
const element = <HTMLElement | null>document.activeElement.previousElementSibling;
|
||||
if (element) {
|
||||
element.focus();
|
||||
const disposable = addDisposableListener(element, 'blur', () => {
|
||||
this._navigationModeContextKey.set(false);
|
||||
disposable.dispose();
|
||||
});
|
||||
this._navigationModeContextKey.set(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure a11y tree exists
|
||||
const treeContainer = this._terminal.element.querySelector('.xterm-accessibility-tree');
|
||||
if (!treeContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Target is row before the cursor
|
||||
const targetRow = Math.max(this._terminal.buffer.cursorY - 1, 0);
|
||||
|
||||
// Check bounds
|
||||
if (treeContainer.childElementCount < targetRow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Focus
|
||||
const element = <HTMLElement>treeContainer.childNodes.item(targetRow);
|
||||
element.focus();
|
||||
const disposable = addDisposableListener(element, 'blur', () => {
|
||||
this._navigationModeContextKey.set(false);
|
||||
disposable.dispose();
|
||||
});
|
||||
this._navigationModeContextKey.set(true);
|
||||
}
|
||||
|
||||
focusNextLine(): void {
|
||||
// Focus previous row if a row is already focused
|
||||
if (document.activeElement && document.activeElement.parentElement && document.activeElement.parentElement.classList.contains('xterm-accessibility-tree')) {
|
||||
const element = <HTMLElement | null>document.activeElement.nextElementSibling;
|
||||
if (element) {
|
||||
element.focus();
|
||||
const disposable = addDisposableListener(element, 'blur', () => {
|
||||
this._navigationModeContextKey.set(false);
|
||||
disposable.dispose();
|
||||
});
|
||||
this._navigationModeContextKey.set(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure a11y tree exists
|
||||
const treeContainer = this._terminal.element.querySelector('.xterm-accessibility-tree');
|
||||
if (!treeContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Target is cursor row
|
||||
const targetRow = this._terminal.buffer.cursorY;
|
||||
|
||||
// Check bounds
|
||||
if (treeContainer.childElementCount < targetRow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Focus row before cursor
|
||||
const element = <HTMLElement>treeContainer.childNodes.item(targetRow);
|
||||
element.focus();
|
||||
const disposable = addDisposableListener(element, 'blur', () => {
|
||||
this._navigationModeContextKey.set(false);
|
||||
disposable.dispose();
|
||||
});
|
||||
this._navigationModeContextKey.set(true);
|
||||
}
|
||||
}
|
||||
@@ -20,10 +20,10 @@ import * as panel from 'vs/workbench/browser/panel';
|
||||
import { getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen';
|
||||
import { Extensions as QuickOpenExtensions, IQuickOpenRegistry, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
|
||||
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
||||
import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions';
|
||||
import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand, NavigationModeFocusPreviousTerminalAction, NavigationModeFocusNextTerminalAction, NavigationModeExitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
|
||||
import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel';
|
||||
import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/terminalQuickOpen';
|
||||
import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService, TERMINAL_ACTION_CATEGORY, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
|
||||
import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands';
|
||||
import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu';
|
||||
@@ -33,6 +33,7 @@ import { DEFAULT_COMMANDS_TO_SKIP_SHELL } from 'vs/workbench/contrib/terminal/br
|
||||
import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { registerShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalShellConfig';
|
||||
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
|
||||
|
||||
registerSingleton(ITerminalService, TerminalService, true);
|
||||
|
||||
@@ -459,6 +460,21 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextComm
|
||||
primary: 0,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow }
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Next Command', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeExitTerminalAction, NavigationModeExitTerminalAction.ID, NavigationModeExitTerminalAction.LABEL, {
|
||||
primary: KeyCode.Escape
|
||||
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Exit Navigation Mode', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.UpArrow
|
||||
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.UpArrow
|
||||
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.DownArrow
|
||||
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.DownArrow
|
||||
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousLineAction, SelectToPreviousLineAction.ID, SelectToPreviousLineAction.LABEL), 'Terminal: Select To Previous Line', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextLineAction, SelectToNextLineAction.ID, SelectToNextLineAction.LABEL), 'Terminal: Select To Next Line', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEscapeSequenceLoggingAction, ToggleEscapeSequenceLoggingAction.ID, ToggleEscapeSequenceLoggingAction.LABEL), 'Terminal: Toggle Escape Sequence Logging', category);
|
||||
|
||||
@@ -607,12 +607,11 @@ export class TerminalPasteAction extends Action {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(event?: any): Promise<any> {
|
||||
public async run(event?: any): Promise<any> {
|
||||
const instance = this.terminalService.getActiveOrCreateInstance();
|
||||
if (instance) {
|
||||
instance.paste();
|
||||
await instance.paste();
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,6 +748,7 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
|
||||
this._register(terminalService.onInstancesChanged(this._updateItems, this));
|
||||
this._register(terminalService.onActiveTabChanged(this._updateItems, this));
|
||||
this._register(terminalService.onInstanceTitleChanged(this._updateItems, this));
|
||||
this._register(terminalService.onTabDisposed(this._updateItems, this));
|
||||
this._register(attachSelectBoxStyler(this.selectBox, themeService));
|
||||
}
|
||||
|
||||
@@ -886,6 +886,71 @@ export class ScrollToTopTerminalAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class NavigationModeExitTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_EXIT;
|
||||
public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeExit', "Exit Navigation Mode");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(event?: any): Promise<any> {
|
||||
const terminalInstance = this.terminalService.getActiveInstance();
|
||||
if (terminalInstance && terminalInstance.navigationMode) {
|
||||
terminalInstance.navigationMode.exitNavigationMode();
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class NavigationModeFocusPreviousTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_PREVIOUS;
|
||||
public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeFocusPrevious', "Focus Previous Line (Navigation Mode)");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(event?: any): Promise<any> {
|
||||
const terminalInstance = this.terminalService.getActiveInstance();
|
||||
if (terminalInstance && terminalInstance.navigationMode) {
|
||||
terminalInstance.navigationMode.focusPreviousLine();
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
export class NavigationModeFocusNextTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_NEXT;
|
||||
public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeFocusNext', "Focus Next Line (Navigation Mode)");
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(event?: any): Promise<any> {
|
||||
const terminalInstance = this.terminalService.getActiveInstance();
|
||||
if (terminalInstance && terminalInstance.navigationMode) {
|
||||
terminalInstance.navigationMode.focusNextLine();
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
export class ClearTerminalAction extends Action {
|
||||
|
||||
public static readonly ID = TERMINAL_COMMAND_ID.CLEAR;
|
||||
|
||||
@@ -19,7 +19,7 @@ export class TerminalFindWidget extends SimpleFindWidget {
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super(_contextViewService, _contextKeyService, findState, true);
|
||||
super(_contextViewService, _contextKeyService, findState, true, true);
|
||||
this._register(findState.onFindReplaceStateChange(() => {
|
||||
this.show();
|
||||
}));
|
||||
@@ -50,7 +50,7 @@ export class TerminalFindWidget extends SimpleFindWidget {
|
||||
// Ignore input changes for now
|
||||
const instance = this._terminalService.getActiveInstance();
|
||||
if (instance !== null) {
|
||||
return instance.findNext(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true });
|
||||
return instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -78,4 +78,4 @@ export class TerminalFindWidget extends SimpleFindWidget {
|
||||
protected onFindInputFocusTrackerBlur() {
|
||||
this._findInputFocused.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB
|
||||
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { PANEL_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager';
|
||||
import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
|
||||
import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands';
|
||||
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
|
||||
@@ -35,8 +35,9 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager';
|
||||
import { Terminal as XTermTerminal, IBuffer } from 'xterm';
|
||||
import { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm';
|
||||
import { SearchAddon, ISearchOptions } from 'xterm-addon-search';
|
||||
import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/addons/navigationModeAddon';
|
||||
|
||||
// How long in milliseconds should an average frame take to render for a notification to appear
|
||||
// which suggests the fallback DOM-based renderer
|
||||
@@ -91,6 +92,9 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [
|
||||
TERMINAL_COMMAND_ID.SPLIT_IN_ACTIVE_WORKSPACE,
|
||||
TERMINAL_COMMAND_ID.SPLIT,
|
||||
TERMINAL_COMMAND_ID.TOGGLE,
|
||||
TERMINAL_COMMAND_ID.NAVIGATION_MODE_EXIT,
|
||||
TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_NEXT,
|
||||
TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_PREVIOUS,
|
||||
'editor.action.toggleTabFocusMode',
|
||||
'workbench.action.quickOpen',
|
||||
'workbench.action.quickOpenPreviousEditor',
|
||||
@@ -183,6 +187,7 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
private _xtermSearch: SearchAddon | undefined;
|
||||
private _xtermElement: HTMLDivElement;
|
||||
private _terminalHasTextContextKey: IContextKey<boolean>;
|
||||
private _terminalA11yTreeFocusContextKey: IContextKey<boolean>;
|
||||
private _cols: number;
|
||||
private _rows: number;
|
||||
private _dimensionsOverride: ITerminalDimensions | undefined;
|
||||
@@ -197,6 +202,7 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
private _widgetManager: TerminalWidgetManager;
|
||||
private _linkHandler: TerminalLinkHandler;
|
||||
private _commandTracker: TerminalCommandTracker;
|
||||
private _navigationModeAddon: INavigationMode & ITerminalAddon | undefined;
|
||||
|
||||
public disableLayout: boolean;
|
||||
public get id(): number { return this._id; }
|
||||
@@ -224,6 +230,7 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
public get isTitleSetByProcess(): boolean { return !!this._messageTitleDisposable; }
|
||||
public get shellLaunchConfig(): IShellLaunchConfig { return this._shellLaunchConfig; }
|
||||
public get commandTracker(): TerminalCommandTracker { return this._commandTracker; }
|
||||
public get navigationMode(): INavigationMode | undefined { return this._navigationModeAddon; }
|
||||
|
||||
private readonly _onExit = new Emitter<number>();
|
||||
public get onExit(): Event<number> { return this._onExit.event; }
|
||||
@@ -280,6 +287,7 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
});
|
||||
|
||||
this._terminalHasTextContextKey = KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED.bindTo(this._contextKeyService);
|
||||
this._terminalA11yTreeFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS.bindTo(this._contextKeyService);
|
||||
this.disableLayout = false;
|
||||
|
||||
this._logService.trace(`terminalInstance#ctor (id: ${this.id})`, this._shellLaunchConfig);
|
||||
@@ -462,13 +470,13 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
letterSpacing: font.letterSpacing,
|
||||
lineHeight: font.lineHeight,
|
||||
bellStyle: config.enableBell ? 'sound' : 'none',
|
||||
screenReaderMode: this._isScreenReaderOptimized(),
|
||||
macOptionIsMeta: config.macOptionIsMeta,
|
||||
macOptionClickForcesSelection: config.macOptionClickForcesSelection,
|
||||
rightClickSelectsWord: config.rightClickBehavior === 'selectWord',
|
||||
// TODO: Guess whether to use canvas or dom better
|
||||
rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType
|
||||
});
|
||||
this.updateAccessibilitySupport();
|
||||
this._terminalInstanceService.getXtermSearchConstructor().then(Addon => {
|
||||
this._xtermSearch = new Addon();
|
||||
this._xterm.loadAddon(this._xtermSearch);
|
||||
@@ -861,9 +869,9 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
return this._xtermReadyPromise.then(() => this.focus(force));
|
||||
}
|
||||
|
||||
public paste(): void {
|
||||
public async paste(): Promise<void> {
|
||||
this.focus();
|
||||
document.execCommand('paste');
|
||||
this._xterm._core._coreService.triggerDataEvent(await this._clipboardService.readText(), true);
|
||||
}
|
||||
|
||||
public write(text: string): void {
|
||||
@@ -958,7 +966,6 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
private _refreshSelectionContextKey() {
|
||||
const activePanel = this._panelService.getActivePanel();
|
||||
const isActive = !!activePanel && activePanel.getId() === TERMINAL_PANEL_ID;
|
||||
|
||||
this._terminalHasTextContextKey.set(isActive && this.hasSelection());
|
||||
}
|
||||
|
||||
@@ -968,6 +975,7 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
this._processManager.onProcessExit(exitCode => this._onProcessExit(exitCode));
|
||||
this._processManager.onProcessData(data => this._onData.fire(data));
|
||||
this._processManager.onProcessOverrideDimensions(e => this.setDimensions(e));
|
||||
this._processManager.onProcessResolvedShellLaunchConfig(e => this._setResolvedShellLaunchConfig(e));
|
||||
|
||||
if (this._shellLaunchConfig.name) {
|
||||
this.setTitle(this._shellLaunchConfig.name, false);
|
||||
@@ -1223,7 +1231,17 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
}
|
||||
|
||||
public updateAccessibilitySupport(): void {
|
||||
this._xterm.setOption('screenReaderMode', this._isScreenReaderOptimized());
|
||||
const isEnabled = this._isScreenReaderOptimized();
|
||||
if (isEnabled) {
|
||||
this._navigationModeAddon = new NavigationModeAddon(this._terminalA11yTreeFocusContextKey);
|
||||
this._xterm.loadAddon(this._navigationModeAddon);
|
||||
} else {
|
||||
if (this._navigationModeAddon) {
|
||||
this._navigationModeAddon.dispose();
|
||||
this._navigationModeAddon = undefined;
|
||||
}
|
||||
}
|
||||
this._xterm.setOption('screenReaderMode', isEnabled);
|
||||
}
|
||||
|
||||
private _setCursorBlink(blink: boolean): void {
|
||||
@@ -1379,6 +1397,13 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
this._resize();
|
||||
}
|
||||
|
||||
private _setResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void {
|
||||
this._shellLaunchConfig.args = shellLaunchConfig.args;
|
||||
this._shellLaunchConfig.cwd = shellLaunchConfig.cwd;
|
||||
this._shellLaunchConfig.executable = shellLaunchConfig.executable;
|
||||
this._shellLaunchConfig.env = shellLaunchConfig.env;
|
||||
}
|
||||
|
||||
private _getXtermTheme(theme?: ITheme): any {
|
||||
if (!theme) {
|
||||
theme = this._themeService.getTheme();
|
||||
@@ -1420,8 +1445,7 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
}
|
||||
|
||||
public toggleEscapeSequenceLogging(): void {
|
||||
this._xterm._core.debug = !this._xterm._core.debug;
|
||||
this._xterm.setOption('debug', this._xterm._core.debug);
|
||||
this._xterm.setOption('logLevel', 'debug');
|
||||
}
|
||||
|
||||
public getInitialCwd(): Promise<string> {
|
||||
|
||||
@@ -31,7 +31,7 @@ const LATENCY_MEASURING_INTERVAL = 1000;
|
||||
|
||||
enum ProcessType {
|
||||
Process,
|
||||
VirtualProcess
|
||||
ExtensionTerminal
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,6 +70,8 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
public get onProcessExit(): Event<number> { return this._onProcessExit.event; }
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensions | undefined>();
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
private readonly _onProcessOverrideShellLaunchConfig = new Emitter<IShellLaunchConfig>();
|
||||
public get onProcessResolvedShellLaunchConfig(): Event<IShellLaunchConfig> { return this._onProcessOverrideShellLaunchConfig.event; }
|
||||
|
||||
constructor(
|
||||
private readonly _terminalId: number,
|
||||
@@ -111,8 +113,8 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
rows: number,
|
||||
isScreenReaderModeEnabled: boolean
|
||||
): Promise<void> {
|
||||
if (shellLaunchConfig.isVirtualProcess) {
|
||||
this._processType = ProcessType.VirtualProcess;
|
||||
if (shellLaunchConfig.isExtensionTerminal) {
|
||||
this._processType = ProcessType.ExtensionTerminal;
|
||||
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, undefined, cols, rows, this._configHelper);
|
||||
} else {
|
||||
const forceExtHostProcess = (this._configHelper.config as any).extHostProcess;
|
||||
@@ -170,6 +172,9 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
if (this._process.onProcessOverrideDimensions) {
|
||||
this._process.onProcessOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e));
|
||||
}
|
||||
if (this._process.onProcessResolvedShellLaunchConfig) {
|
||||
this._process.onProcessResolvedShellLaunchConfig(e => this._onProcessOverrideShellLaunchConfig.fire(e));
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.processState === ProcessState.LAUNCHING) {
|
||||
@@ -234,7 +239,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
}
|
||||
|
||||
public write(data: string): void {
|
||||
if (this.shellProcessId || this._processType === ProcessType.VirtualProcess) {
|
||||
if (this.shellProcessId || this._processType === ProcessType.ExtensionTerminal) {
|
||||
if (this._process) {
|
||||
// Send data if the pty is ready
|
||||
this._process.input(data);
|
||||
@@ -287,4 +292,4 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
|
||||
this._onProcessExit.fire(exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export class TerminalService extends CommonTerminalService implements ITerminalS
|
||||
this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, this.terminalNativeService.linuxDistro);
|
||||
}
|
||||
|
||||
public createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance {
|
||||
public createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance {
|
||||
const instance = this._instantiationService.createInstance(TerminalInstance, terminalFocusContextKey, configHelper, container, shellLaunchConfig);
|
||||
this._onInstanceCreated.fire(instance);
|
||||
return instance;
|
||||
@@ -60,8 +60,7 @@ export class TerminalService extends CommonTerminalService implements ITerminalS
|
||||
const instance = this.createInstance(this._terminalFocusContextKey,
|
||||
this.configHelper,
|
||||
undefined,
|
||||
shell,
|
||||
true);
|
||||
shell);
|
||||
this._backgroundedTerminalInstances.push(instance);
|
||||
this._initInstanceListeners(instance);
|
||||
return instance;
|
||||
|
||||
@@ -246,8 +246,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
|
||||
terminalFocusContextKey,
|
||||
configHelper,
|
||||
undefined,
|
||||
shellLaunchConfigOrInstance,
|
||||
true);
|
||||
shellLaunchConfigOrInstance);
|
||||
}
|
||||
this._terminalInstances.push(instance);
|
||||
this._initInstanceListeners(instance);
|
||||
@@ -389,8 +388,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
|
||||
terminalFocusContextKey,
|
||||
configHelper,
|
||||
undefined,
|
||||
shellLaunchConfig,
|
||||
true);
|
||||
shellLaunchConfig);
|
||||
this._terminalInstances.splice(this._activeInstanceIndex + 1, 0, instance);
|
||||
this._initInstanceListeners(instance);
|
||||
this._setActiveInstance(instance);
|
||||
|
||||
@@ -21,6 +21,8 @@ export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey<boolean>('t
|
||||
export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey<boolean>('terminalFocus', false);
|
||||
/** A context key that is set when the integrated terminal does not have focus. */
|
||||
export const KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FOCUS.toNegated();
|
||||
/** A context key that is set when the user is navigating the accessibility tree */
|
||||
export const KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS = new RawContextKey<boolean>('terminalA11yTreeFocus', false);
|
||||
|
||||
/** A keybinding context key that is set when the integrated terminal has text selected. */
|
||||
export const KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED = new RawContextKey<boolean>('terminalTextSelected', false);
|
||||
@@ -186,14 +188,14 @@ export interface IShellLaunchConfig {
|
||||
initialText?: string;
|
||||
|
||||
/**
|
||||
* @deprecated use `isVirtualProcess`
|
||||
* @deprecated use `isExtensionTerminal`
|
||||
*/
|
||||
isRendererOnly?: boolean;
|
||||
|
||||
/**
|
||||
* When true an extension is acting as the terminal's process.
|
||||
* Whether an extension is controlling the terminal via a `vscode.Pseudoterminal`.
|
||||
*/
|
||||
isVirtualProcess?: boolean;
|
||||
isExtensionTerminal?: boolean;
|
||||
|
||||
/**
|
||||
* Whether the terminal process environment should be exactly as provided in
|
||||
@@ -229,8 +231,8 @@ export interface ITerminalService {
|
||||
onInstanceProcessIdReady: Event<ITerminalInstance>;
|
||||
onInstanceDimensionsChanged: Event<ITerminalInstance>;
|
||||
onInstanceMaximumDimensionsChanged: Event<ITerminalInstance>;
|
||||
onInstanceRequestExtHostProcess: Event<ITerminalProcessExtHostRequest>;
|
||||
onInstanceRequestVirtualProcess: Event<ITerminalVirtualProcessRequest>;
|
||||
onInstanceRequestSpawnExtHostProcess: Event<ISpawnExtHostProcessRequest>;
|
||||
onInstanceRequestStartExtensionTerminal: Event<IStartExtensionTerminalRequest>;
|
||||
onInstancesChanged: Event<void>;
|
||||
onInstanceTitleChanged: Event<ITerminalInstance>;
|
||||
onActiveInstanceChanged: Event<ITerminalInstance | undefined>;
|
||||
@@ -251,7 +253,7 @@ export interface ITerminalService {
|
||||
/**
|
||||
* Creates a raw terminal instance, this should not be used outside of the terminal part.
|
||||
*/
|
||||
createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance;
|
||||
createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance;
|
||||
getInstanceFromId(terminalId: number): ITerminalInstance | undefined;
|
||||
getInstanceFromIndex(terminalIndex: number): ITerminalInstance;
|
||||
getTabLabels(): string[];
|
||||
@@ -297,8 +299,8 @@ export interface ITerminalService {
|
||||
preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise<string>;
|
||||
|
||||
extHostReady(remoteAuthority: string): void;
|
||||
requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void;
|
||||
requestVirtualProcess(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void;
|
||||
requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void;
|
||||
requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -483,6 +485,8 @@ export interface ITerminalInstance {
|
||||
*/
|
||||
readonly commandTracker: ITerminalCommandTracker;
|
||||
|
||||
readonly navigationMode: INavigationMode | undefined;
|
||||
|
||||
/**
|
||||
* Dispose the terminal instance, removing it from the panel/service and freeing up resources.
|
||||
*
|
||||
@@ -584,7 +588,7 @@ export interface ITerminalInstance {
|
||||
/**
|
||||
* Focuses and pastes the contents of the clipboard into the terminal instance.
|
||||
*/
|
||||
paste(): void;
|
||||
paste(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Send text to the terminal instance. The text is written to the stdin of the underlying pty
|
||||
@@ -629,17 +633,6 @@ export interface ITerminalInstance {
|
||||
*/
|
||||
attachToElement(container: HTMLElement): void;
|
||||
|
||||
/**
|
||||
* Updates the configuration of the terminal instance.
|
||||
*/
|
||||
updateConfig(): void;
|
||||
|
||||
/**
|
||||
* Updates the accessibility support state of the terminal instance.
|
||||
* @param isEnabled Whether it's enabled.
|
||||
*/
|
||||
updateAccessibilitySupport(isEnabled: boolean): void;
|
||||
|
||||
/**
|
||||
* Configure the dimensions of the terminal instance.
|
||||
*
|
||||
@@ -687,6 +680,12 @@ export interface ITerminalCommandTracker {
|
||||
selectToNextLine(): void;
|
||||
}
|
||||
|
||||
export interface INavigationMode {
|
||||
exitNavigationMode(): void;
|
||||
focusPreviousLine(): void;
|
||||
focusNextLine(): void;
|
||||
}
|
||||
|
||||
export interface IBeforeProcessDataEvent {
|
||||
/**
|
||||
* The data of the event, this can be modified by the event listener to change what gets sent
|
||||
@@ -709,6 +708,7 @@ export interface ITerminalProcessManager extends IDisposable {
|
||||
readonly onProcessTitle: Event<string>;
|
||||
readonly onProcessExit: Event<number>;
|
||||
readonly onProcessOverrideDimensions: Event<ITerminalDimensions | undefined>;
|
||||
readonly onProcessResolvedShellLaunchConfig: Event<IShellLaunchConfig>;
|
||||
|
||||
dispose(immediate?: boolean): void;
|
||||
createProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number, isScreenReaderModeEnabled: boolean): Promise<void>;
|
||||
@@ -747,6 +747,7 @@ export interface ITerminalProcessExtHostProxy extends IDisposable {
|
||||
emitReady(pid: number, cwd: string): void;
|
||||
emitExit(exitCode: number): void;
|
||||
emitOverrideDimensions(dimensions: ITerminalDimensions | undefined): void;
|
||||
emitResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void;
|
||||
emitInitialCwd(initialCwd: string): void;
|
||||
emitCwd(cwd: string): void;
|
||||
emitLatency(latency: number): void;
|
||||
@@ -759,7 +760,7 @@ export interface ITerminalProcessExtHostProxy extends IDisposable {
|
||||
onRequestLatency: Event<void>;
|
||||
}
|
||||
|
||||
export interface ITerminalProcessExtHostRequest {
|
||||
export interface ISpawnExtHostProcessRequest {
|
||||
proxy: ITerminalProcessExtHostProxy;
|
||||
shellLaunchConfig: IShellLaunchConfig;
|
||||
activeWorkspaceRootUri: URI;
|
||||
@@ -768,7 +769,7 @@ export interface ITerminalProcessExtHostRequest {
|
||||
isWorkspaceShellAllowed: boolean;
|
||||
}
|
||||
|
||||
export interface ITerminalVirtualProcessRequest {
|
||||
export interface IStartExtensionTerminalRequest {
|
||||
proxy: ITerminalProcessExtHostProxy;
|
||||
cols: number;
|
||||
rows: number;
|
||||
@@ -802,6 +803,7 @@ export interface ITerminalChildProcess {
|
||||
onProcessReady: Event<{ pid: number, cwd: string }>;
|
||||
onProcessTitleChanged: Event<string>;
|
||||
onProcessOverrideDimensions?: Event<ITerminalDimensions | undefined>;
|
||||
onProcessResolvedShellLaunchConfig?: Event<IShellLaunchConfig>;
|
||||
|
||||
/**
|
||||
* Shutdown the terminal process.
|
||||
|
||||
@@ -68,6 +68,9 @@ export const enum TERMINAL_COMMAND_ID {
|
||||
TOGGLE_FIND_REGEX_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindRegexTerminalFocus',
|
||||
TOGGLE_FIND_WHOLE_WORD_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindWholeWordTerminalFocus',
|
||||
TOGGLE_FIND_CASE_SENSITIVE_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindCaseSensitiveTerminalFocus',
|
||||
NAVIGATION_MODE_EXIT = 'workbench.action.terminal.navigationModeExit',
|
||||
NAVIGATION_MODE_FOCUS_NEXT = 'workbench.action.terminal.navigationModeFocusNext',
|
||||
NAVIGATION_MODE_FOCUS_PREVIOUS = 'workbench.action.terminal.navigationModeFocusPrevious'
|
||||
}
|
||||
|
||||
export function setupTerminalCommands(): void {
|
||||
|
||||
@@ -106,6 +106,7 @@ function _getLangEnvVariable(locale?: string) {
|
||||
ko: 'KR',
|
||||
pl: 'PL',
|
||||
ru: 'RU',
|
||||
sk: 'SK',
|
||||
zh: 'CN'
|
||||
};
|
||||
if (parts[0] in languageVariants) {
|
||||
|
||||
@@ -24,6 +24,8 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensions | undefined>();
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
private readonly _onProcessResolvedShellLaunchConfig = new Emitter<IShellLaunchConfig>();
|
||||
public get onProcessResolvedShellLaunchConfig(): Event<IShellLaunchConfig> { return this._onProcessResolvedShellLaunchConfig.event; }
|
||||
|
||||
private readonly _onInput = this._register(new Emitter<string>());
|
||||
public readonly onInput: Event<string> = this._onInput.event;
|
||||
@@ -56,14 +58,14 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal
|
||||
|
||||
// Request a process if needed, if this is a virtual process this step can be skipped as
|
||||
// there is no real "process" and we know it's ready on the ext host already.
|
||||
if (shellLaunchConfig.isVirtualProcess) {
|
||||
this._terminalService.requestVirtualProcess(this, cols, rows);
|
||||
if (shellLaunchConfig.isExtensionTerminal) {
|
||||
this._terminalService.requestStartExtensionTerminal(this, cols, rows);
|
||||
} else {
|
||||
remoteAgentService.getEnvironment().then(env => {
|
||||
if (!env) {
|
||||
throw new Error('Could not fetch environment');
|
||||
}
|
||||
this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper.checkWorkspaceShellPermissions(env.os));
|
||||
this._terminalService.requestSpawnExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper.checkWorkspaceShellPermissions(env.os));
|
||||
});
|
||||
if (!hasReceivedResponse) {
|
||||
setTimeout(() => this._onProcessTitleChanged.fire(nls.localize('terminal.integrated.starting', "Starting...")), 0);
|
||||
@@ -93,6 +95,10 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal
|
||||
this._onProcessOverrideDimensions.fire(dimensions);
|
||||
}
|
||||
|
||||
public emitResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void {
|
||||
this._onProcessResolvedShellLaunchConfig.fire(shellLaunchConfig);
|
||||
}
|
||||
|
||||
public emitInitialCwd(initialCwd: string): void {
|
||||
while (this._pendingInitialCwdRequests.length > 0) {
|
||||
this._pendingInitialCwdRequests.pop()!(initialCwd);
|
||||
@@ -143,4 +149,4 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal
|
||||
this._pendingLatencyRequests.push(resolve);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest, ITerminalVirtualProcessRequest } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
@@ -20,11 +20,15 @@ import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/termi
|
||||
import { isWindows, isMacintosh, OperatingSystem } from 'vs/base/common/platform';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
|
||||
import { IPickOptions, IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
interface IExtHostReadyEntry {
|
||||
promise: Promise<void>;
|
||||
resolve: () => void;
|
||||
}
|
||||
|
||||
export abstract class TerminalService implements ITerminalService {
|
||||
public _serviceBrand: any;
|
||||
|
||||
@@ -38,7 +42,7 @@ export abstract class TerminalService implements ITerminalService {
|
||||
return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), <ITerminalInstance[]>[]);
|
||||
}
|
||||
private _findState: FindReplaceState;
|
||||
private _extHostsReady: { [authority: string]: boolean } = {};
|
||||
private _extHostsReady: { [authority: string]: IExtHostReadyEntry | undefined } = {};
|
||||
private _activeTabIndex: number;
|
||||
|
||||
public get activeTabIndex(): number { return this._activeTabIndex; }
|
||||
@@ -53,10 +57,10 @@ export abstract class TerminalService implements ITerminalService {
|
||||
public get onInstanceDisposed(): Event<ITerminalInstance> { return this._onInstanceDisposed.event; }
|
||||
protected readonly _onInstanceProcessIdReady = new Emitter<ITerminalInstance>();
|
||||
public get onInstanceProcessIdReady(): Event<ITerminalInstance> { return this._onInstanceProcessIdReady.event; }
|
||||
protected readonly _onInstanceRequestExtHostProcess = new Emitter<ITerminalProcessExtHostRequest>();
|
||||
public get onInstanceRequestExtHostProcess(): Event<ITerminalProcessExtHostRequest> { return this._onInstanceRequestExtHostProcess.event; }
|
||||
protected readonly _onInstanceRequestVirtualProcess = new Emitter<ITerminalVirtualProcessRequest>();
|
||||
public get onInstanceRequestVirtualProcess(): Event<ITerminalVirtualProcessRequest> { return this._onInstanceRequestVirtualProcess.event; }
|
||||
protected readonly _onInstanceRequestSpawnExtHostProcess = new Emitter<ISpawnExtHostProcessRequest>();
|
||||
public get onInstanceRequestSpawnExtHostProcess(): Event<ISpawnExtHostProcessRequest> { return this._onInstanceRequestSpawnExtHostProcess.event; }
|
||||
protected readonly _onInstanceRequestStartExtensionTerminal = new Emitter<IStartExtensionTerminalRequest>();
|
||||
public get onInstanceRequestStartExtensionTerminal(): Event<IStartExtensionTerminalRequest> { return this._onInstanceRequestStartExtensionTerminal.event; }
|
||||
protected readonly _onInstanceDimensionsChanged = new Emitter<ITerminalInstance>();
|
||||
public get onInstanceDimensionsChanged(): Event<ITerminalInstance> { return this._onInstanceDimensionsChanged.event; }
|
||||
protected readonly _onInstanceMaximumDimensionsChanged = new Emitter<ITerminalInstance>();
|
||||
@@ -119,7 +123,7 @@ export abstract class TerminalService implements ITerminalService {
|
||||
protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void;
|
||||
|
||||
public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
|
||||
public abstract createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance;
|
||||
public abstract createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance;
|
||||
public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
|
||||
|
||||
public createTerminalRenderer(name: string): ITerminalInstance {
|
||||
@@ -131,26 +135,39 @@ export abstract class TerminalService implements ITerminalService {
|
||||
return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction);
|
||||
}
|
||||
|
||||
public requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void {
|
||||
public requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void {
|
||||
this._extensionService.whenInstalledExtensionsRegistered().then(async () => {
|
||||
// Wait for the remoteAuthority to be ready (and listening for events) before proceeding
|
||||
// Wait for the remoteAuthority to be ready (and listening for events) before firing
|
||||
// the event to spawn the ext host process
|
||||
const conn = this._remoteAgentService.getConnection();
|
||||
const remoteAuthority = conn ? conn.remoteAuthority : 'null';
|
||||
let retries = 0;
|
||||
while (!this._extHostsReady[remoteAuthority] && ++retries < 50) {
|
||||
await timeout(100);
|
||||
}
|
||||
this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed });
|
||||
await this._whenExtHostReady(remoteAuthority);
|
||||
this._onInstanceRequestSpawnExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed });
|
||||
});
|
||||
}
|
||||
|
||||
public requestVirtualProcess(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void {
|
||||
// Don't need to wait on extensions here as this can only be triggered by an extension
|
||||
this._onInstanceRequestVirtualProcess.fire({ proxy, cols, rows });
|
||||
public requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void {
|
||||
this._onInstanceRequestStartExtensionTerminal.fire({ proxy, cols, rows });
|
||||
}
|
||||
|
||||
public extHostReady(remoteAuthority: string): void {
|
||||
this._extHostsReady[remoteAuthority] = true;
|
||||
public async extHostReady(remoteAuthority: string): Promise<void> {
|
||||
this._createExtHostReadyEntry(remoteAuthority);
|
||||
this._extHostsReady[remoteAuthority]!.resolve();
|
||||
}
|
||||
|
||||
private async _whenExtHostReady(remoteAuthority: string): Promise<void> {
|
||||
this._createExtHostReadyEntry(remoteAuthority);
|
||||
return this._extHostsReady[remoteAuthority]!.promise;
|
||||
}
|
||||
|
||||
private _createExtHostReadyEntry(remoteAuthority: string): void {
|
||||
if (this._extHostsReady[remoteAuthority]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let resolve!: () => void;
|
||||
const promise = new Promise<void>(r => resolve = r);
|
||||
this._extHostsReady[remoteAuthority] = { promise, resolve };
|
||||
}
|
||||
|
||||
private _onBeforeShutdown(): boolean | Promise<boolean> {
|
||||
|
||||
Reference in New Issue
Block a user