mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-31 09:10:30 -04:00
This reverts commit d15a3fcc98.
This commit is contained in:
@@ -128,7 +128,7 @@
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (e.g. tmux), revert to the standard pointer cursor */
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,10 +260,15 @@ configurationRegistry.registerConfiguration({
|
||||
default: 'inherited'
|
||||
},
|
||||
'terminal.integrated.windowsEnableConpty': {
|
||||
description: nls.localize('terminal.integrated.windowsEnableConpty', "Whether to use ConPTY for Windows terminal process communication (requires Windows 10 build number 18309+). Winpty will be used if this is false."),
|
||||
description: nls.localize('terminal.integrated.windowsEnableConpty', "Whether to use ConPTY for Windows terminal process communication. Winpty will be used if this is false. Note that ConPTY will be disabled regardless of this setting when the Windows 10 build number is lower than 18309 or when you're running the 32-bit VS Code client under 64-bit Windows."),
|
||||
type: 'boolean',
|
||||
default: true
|
||||
},
|
||||
'terminal.integrated.enableLatencyMitigation': {
|
||||
description: nls.localize('terminal.integrated.enableLatencyMitigation', "Whether to enable the latency mitigation feature for high-latency terminals."),
|
||||
type: 'boolean',
|
||||
default: false
|
||||
},
|
||||
'terminal.integrated.experimentalRefreshOnResume': {
|
||||
description: nls.localize('terminal.integrated.experimentalRefreshOnResume', "An experimental setting that will refresh the terminal renderer when the system is resumed."),
|
||||
type: 'boolean',
|
||||
@@ -392,7 +397,8 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveToLineEndTer
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow }
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line End', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SplitTerminalAction, SplitTerminalAction.ID, SplitTerminalAction.LABEL, {
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5],
|
||||
mac: {
|
||||
primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH,
|
||||
secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_5]
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Terminal as XTermTerminal } from 'xterm';
|
||||
import { WebLinksAddon as XTermWebLinksAddon } from 'xterm-addon-web-links';
|
||||
import { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
|
||||
import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { Terminal as XTermTerminal } from 'vscode-xterm';
|
||||
import { ITerminalInstance, IWindowsShellHelper, ITerminalProcessManager, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProcessEnvironment, Platform } from 'vs/base/common/platform';
|
||||
|
||||
@@ -16,9 +14,8 @@ export interface ITerminalInstanceService {
|
||||
_serviceBrand: any;
|
||||
|
||||
getXtermConstructor(): Promise<typeof XTermTerminal>;
|
||||
getXtermWebLinksConstructor(): Promise<typeof XTermWebLinksAddon>;
|
||||
getXtermSearchConstructor(): Promise<typeof XTermSearchAddon>;
|
||||
createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper;
|
||||
createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager;
|
||||
createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess;
|
||||
getDefaultShell(p: Platform): string;
|
||||
}
|
||||
|
||||
@@ -748,10 +748,10 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
|
||||
) {
|
||||
super(null, action, terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }), terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.') });
|
||||
|
||||
this._register(terminalService.onInstancesChanged(this._updateItems, this));
|
||||
this._register(terminalService.onActiveTabChanged(this._updateItems, this));
|
||||
this._register(terminalService.onInstanceTitleChanged(this._updateItems, this));
|
||||
this._register(attachSelectBoxStyler(this.selectBox, themeService));
|
||||
this.toDispose.push(terminalService.onInstancesChanged(this._updateItems, this));
|
||||
this.toDispose.push(terminalService.onActiveTabChanged(this._updateItems, this));
|
||||
this.toDispose.push(terminalService.onInstanceTitleChanged(this._updateItems, this));
|
||||
this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService));
|
||||
}
|
||||
|
||||
private _updateItems(): void {
|
||||
@@ -1041,7 +1041,7 @@ export class QuickOpenActionTermContributor extends ActionBarContributor {
|
||||
super();
|
||||
}
|
||||
|
||||
public getActions(context: any): ReadonlyArray<IAction> {
|
||||
public getActions(context: any): IAction[] {
|
||||
const actions: Action[] = [];
|
||||
if (context.element instanceof TerminalEntry) {
|
||||
actions.push(this.instantiationService.createInstance(RenameTerminalQuickOpenAction, RenameTerminalQuickOpenAction.ID, RenameTerminalQuickOpenAction.LABEL, context.element));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Terminal, IMarker } from 'xterm';
|
||||
import { Terminal, IMarker } from 'vscode-xterm';
|
||||
import { ITerminalCommandTracker } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { ITerminalConfiguration, ITerminalFont, IShellLaunchConfig, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { Terminal as XTermTerminal } from 'xterm';
|
||||
import { Terminal as XTermTerminal } from 'vscode-xterm';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { mergeDefaultShellPathAndArgs } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
|
||||
@@ -32,17 +32,16 @@ import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/term
|
||||
import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler';
|
||||
import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ISearchOptions, Terminal as XTermTerminal, IBuffer } from 'vscode-xterm';
|
||||
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 { SearchAddon, ISearchOptions } from 'xterm-addon-search';
|
||||
|
||||
// How long in milliseconds should an average frame take to render for a notification to appear
|
||||
// which suggests the fallback DOM-based renderer
|
||||
const SLOW_CANVAS_RENDER_THRESHOLD = 50;
|
||||
const NUMBER_OF_FRAMES_TO_MEASURE = 20;
|
||||
|
||||
|
||||
export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [
|
||||
TERMINAL_COMMAND_ID.CLEAR_SELECTION,
|
||||
TERMINAL_COMMAND_ID.CLEAR,
|
||||
@@ -149,8 +148,6 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [
|
||||
'workbench.action.toggleMaximizedPanel'
|
||||
];
|
||||
|
||||
let xtermConstructor: Promise<typeof XTermTerminal> | undefined;
|
||||
|
||||
export class TerminalInstance implements ITerminalInstance {
|
||||
private static readonly EOL_REGEX = /\r?\n/g;
|
||||
|
||||
@@ -169,7 +166,6 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
private _title: string;
|
||||
private _wrapperElement: HTMLDivElement;
|
||||
private _xterm: XTermTerminal;
|
||||
private _xtermSearch: SearchAddon | undefined;
|
||||
private _xtermElement: HTMLDivElement;
|
||||
private _terminalHasTextContextKey: IContextKey<boolean>;
|
||||
private _cols: number;
|
||||
@@ -395,26 +391,11 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
return TerminalInstance._lastKnownDimensions;
|
||||
}
|
||||
|
||||
private async _getXtermConstructor(): Promise<typeof XTermTerminal> {
|
||||
if (xtermConstructor) {
|
||||
return xtermConstructor;
|
||||
}
|
||||
xtermConstructor = new Promise<typeof XTermTerminal>(async (resolve) => {
|
||||
const Terminal = await this._terminalInstanceService.getXtermConstructor();
|
||||
// Localize strings
|
||||
Terminal.strings.blankLine = nls.localize('terminal.integrated.a11yBlankLine', 'Blank line');
|
||||
Terminal.strings.promptLabel = nls.localize('terminal.integrated.a11yPromptLabel', 'Terminal input');
|
||||
Terminal.strings.tooMuchOutput = nls.localize('terminal.integrated.a11yTooMuchOutput', 'Too much output to announce, navigate to rows manually to read');
|
||||
resolve(Terminal);
|
||||
});
|
||||
return xtermConstructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create xterm.js instance and attach data listeners.
|
||||
*/
|
||||
protected async _createXterm(): Promise<void> {
|
||||
const Terminal = await this._getXtermConstructor();
|
||||
const Terminal = await this._terminalInstanceService.getXtermConstructor();
|
||||
const font = this._configHelper.getFont(undefined, true);
|
||||
const config = this._configHelper.config;
|
||||
this._xterm = new Terminal({
|
||||
@@ -433,11 +414,9 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
macOptionClickForcesSelection: config.macOptionClickForcesSelection,
|
||||
rightClickSelectsWord: config.rightClickBehavior === 'selectWord',
|
||||
// TODO: Guess whether to use canvas or dom better
|
||||
rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType
|
||||
});
|
||||
this._terminalInstanceService.getXtermSearchConstructor().then(Addon => {
|
||||
this._xtermSearch = new Addon();
|
||||
this._xterm.loadAddon(this._xtermSearch);
|
||||
rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType,
|
||||
// TODO: Remove this once the setting is removed upstream
|
||||
experimentalCharAtlas: 'dynamic'
|
||||
});
|
||||
if (this._shellLaunchConfig.initialText) {
|
||||
this._xterm.writeln(this._shellLaunchConfig.initialText);
|
||||
@@ -616,6 +595,19 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
if (this._processManager) {
|
||||
this._widgetManager = new TerminalWidgetManager(this._wrapperElement);
|
||||
this._processManager.onProcessReady(() => this._linkHandler.setWidgetManager(this._widgetManager));
|
||||
|
||||
this._processManager.onProcessReady(() => {
|
||||
if (this._configHelper.config.enableLatencyMitigation) {
|
||||
if (!this._processManager) {
|
||||
return;
|
||||
}
|
||||
this._processManager.getLatency().then(latency => {
|
||||
if (latency > 20 && (this._xterm as any).typeAheadInit) {
|
||||
(this._xterm as any).typeAheadInit(this._processManager, this._themeService);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (this._shellLaunchConfig.isRendererOnly) {
|
||||
this._widgetManager = new TerminalWidgetManager(this._wrapperElement);
|
||||
this._linkHandler.setWidgetManager(this._widgetManager);
|
||||
@@ -722,17 +714,11 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
}
|
||||
|
||||
public findNext(term: string, searchOptions: ISearchOptions): boolean {
|
||||
if (!this._xtermSearch) {
|
||||
return false;
|
||||
}
|
||||
return this._xtermSearch.findNext(term, searchOptions);
|
||||
return this._xterm.findNext(term, searchOptions);
|
||||
}
|
||||
|
||||
public findPrevious(term: string, searchOptions: ISearchOptions): boolean {
|
||||
if (!this._xtermSearch) {
|
||||
return false;
|
||||
}
|
||||
return this._xtermSearch.findPrevious(term, searchOptions);
|
||||
return this._xterm.findPrevious(term, searchOptions);
|
||||
}
|
||||
|
||||
public notifyFindWidgetFocusChanged(isFocused: boolean): void {
|
||||
@@ -789,7 +775,7 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
|
||||
public rendererExit(exitCode: number): void {
|
||||
// The use of this API is for cases where there is no backing process behind a terminal
|
||||
// instance (e.g. a custom execution task).
|
||||
// instance (eg. a custom execution task).
|
||||
if (!this.shellLaunchConfig.isRendererOnly) {
|
||||
throw new Error('rendererExit is only expected to be called on a renderer only terminal');
|
||||
}
|
||||
@@ -929,7 +915,7 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
}
|
||||
|
||||
protected _createProcess(): void {
|
||||
this._processManager = this._instantiationService.createInstance(TerminalProcessManager, this._id, this._configHelper);
|
||||
this._processManager = this._terminalInstanceService.createTerminalProcessManager(this._id, this._configHelper);
|
||||
this._processManager.onProcessReady(() => this._onProcessIdReady.fire(this));
|
||||
this._processManager.onProcessExit(exitCode => this._onProcessExit(exitCode));
|
||||
this._processManager.onProcessData(data => this._onData.fire(data));
|
||||
@@ -973,7 +959,7 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
|
||||
/**
|
||||
* Called when either a process tied to a terminal has exited or when a terminal renderer
|
||||
* simulates a process exiting (e.g. custom execution task).
|
||||
* simulates a process exiting (eg. custom execution task).
|
||||
* @param exitCode The exit code of the process, this is undefined when the terminal was exited
|
||||
* through user action.
|
||||
*/
|
||||
@@ -1137,17 +1123,9 @@ export class TerminalInstance implements ITerminalInstance {
|
||||
}
|
||||
|
||||
private _sendLineData(buffer: IBuffer, lineIndex: number): void {
|
||||
let line = buffer.getLine(lineIndex);
|
||||
if (!line) {
|
||||
return;
|
||||
}
|
||||
let lineData = line.translateToString(true);
|
||||
while (lineIndex > 0 && line.isWrapped) {
|
||||
line = buffer.getLine(--lineIndex);
|
||||
if (!line) {
|
||||
break;
|
||||
}
|
||||
lineData = line.translateToString(false) + lineData;
|
||||
let lineData = buffer.getLine(lineIndex)!.translateToString(true);
|
||||
while (lineIndex >= 0 && buffer.getLine(lineIndex--)!.isWrapped) {
|
||||
lineData = buffer.getLine(lineIndex)!.translateToString(false) + lineData;
|
||||
}
|
||||
this._onLineData.fire(lineData);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
@@ -14,10 +14,9 @@ import { ITerminalService, ITerminalProcessManager } from 'vs/workbench/contrib/
|
||||
import { ITextEditorSelection } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ILinkMatcherOptions } from 'xterm';
|
||||
import { ILinkMatcherOptions } from 'vscode-xterm';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { posix, win32 } from 'vs/base/common/path';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
|
||||
const pathPrefix = '(\\.\\.?|\\~)';
|
||||
const pathSeparatorClause = '\\/';
|
||||
@@ -65,14 +64,13 @@ interface IPath {
|
||||
}
|
||||
|
||||
export class TerminalLinkHandler {
|
||||
private readonly _hoverDisposables = new DisposableStore();
|
||||
private _hoverDisposables: IDisposable[] = [];
|
||||
private _mouseMoveDisposable: IDisposable;
|
||||
private _widgetManager: TerminalWidgetManager;
|
||||
private _processCwd: string;
|
||||
private _gitDiffPreImagePattern: RegExp;
|
||||
private _gitDiffPostImagePattern: RegExp;
|
||||
private readonly _tooltipCallback: (event: MouseEvent, uri: string) => boolean | void;
|
||||
private readonly _leaveCallback: () => void;
|
||||
|
||||
constructor(
|
||||
private _xterm: any,
|
||||
@@ -82,7 +80,6 @@ export class TerminalLinkHandler {
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService,
|
||||
@IFileService private readonly _fileService: IFileService
|
||||
) {
|
||||
// Matches '--- a/src/file1', capturing 'src/file1' in group 1
|
||||
@@ -101,11 +98,6 @@ export class TerminalLinkHandler {
|
||||
this._widgetManager.showMessage(e.offsetX, e.offsetY, this._getLinkHoverString());
|
||||
}
|
||||
};
|
||||
this._leaveCallback = () => {
|
||||
if (this._widgetManager) {
|
||||
this._widgetManager.closeMessage();
|
||||
}
|
||||
};
|
||||
|
||||
this.registerWebLinkHandler();
|
||||
if (this._platform) {
|
||||
@@ -126,7 +118,11 @@ export class TerminalLinkHandler {
|
||||
const options: ILinkMatcherOptions = {
|
||||
matchIndex,
|
||||
tooltipCallback: this._tooltipCallback,
|
||||
leaveCallback: this._leaveCallback,
|
||||
leaveCallback: () => {
|
||||
if (this._widgetManager) {
|
||||
this._widgetManager.closeMessage();
|
||||
}
|
||||
},
|
||||
willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e),
|
||||
priority: CUSTOM_LINK_PRIORITY
|
||||
};
|
||||
@@ -137,16 +133,18 @@ export class TerminalLinkHandler {
|
||||
}
|
||||
|
||||
public registerWebLinkHandler(): void {
|
||||
this._terminalInstanceService.getXtermWebLinksConstructor().then((WebLinksAddon) => {
|
||||
const wrappedHandler = this._wrapLinkHandler(uri => {
|
||||
this._handleHypertextLink(uri);
|
||||
});
|
||||
this._xterm.loadAddon(new WebLinksAddon(wrappedHandler, {
|
||||
validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateWebLink(uri, callback),
|
||||
tooltipCallback: this._tooltipCallback,
|
||||
leaveCallback: this._leaveCallback,
|
||||
willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e)
|
||||
}));
|
||||
const wrappedHandler = this._wrapLinkHandler(uri => {
|
||||
this._handleHypertextLink(uri);
|
||||
});
|
||||
this._xterm.webLinksInit(wrappedHandler, {
|
||||
validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateWebLink(uri, callback),
|
||||
tooltipCallback: this._tooltipCallback,
|
||||
leaveCallback: () => {
|
||||
if (this._widgetManager) {
|
||||
this._widgetManager.closeMessage();
|
||||
}
|
||||
},
|
||||
willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -157,7 +155,11 @@ export class TerminalLinkHandler {
|
||||
this._xterm.registerLinkMatcher(this._localLinkRegex, wrappedHandler, {
|
||||
validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateLocalLink(uri, callback),
|
||||
tooltipCallback: this._tooltipCallback,
|
||||
leaveCallback: this._leaveCallback,
|
||||
leaveCallback: () => {
|
||||
if (this._widgetManager) {
|
||||
this._widgetManager.closeMessage();
|
||||
}
|
||||
},
|
||||
willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e),
|
||||
priority: LOCAL_LINK_PRIORITY
|
||||
});
|
||||
@@ -171,7 +173,11 @@ export class TerminalLinkHandler {
|
||||
matchIndex: 1,
|
||||
validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateLocalLink(uri, callback),
|
||||
tooltipCallback: this._tooltipCallback,
|
||||
leaveCallback: this._leaveCallback,
|
||||
leaveCallback: () => {
|
||||
if (this._widgetManager) {
|
||||
this._widgetManager.closeMessage();
|
||||
}
|
||||
},
|
||||
willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e),
|
||||
priority: LOCAL_LINK_PRIORITY
|
||||
};
|
||||
@@ -181,8 +187,7 @@ export class TerminalLinkHandler {
|
||||
|
||||
public dispose(): void {
|
||||
this._xterm = null;
|
||||
|
||||
this._hoverDisposables.dispose();
|
||||
this._hoverDisposables = dispose(this._hoverDisposables);
|
||||
this._mouseMoveDisposable = dispose(this._mouseMoveDisposable);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalConfigHelper, ITerminalChildProcess, IBeforeProcessDataEvent, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
@@ -47,6 +48,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
|
||||
private _process: ITerminalChildProcess | null = null;
|
||||
private _preLaunchInputQueue: string[] = [];
|
||||
private _disposables: IDisposable[] = [];
|
||||
private _latency: number = -1;
|
||||
private _latencyRequest: Promise<number>;
|
||||
private _latencyLastMeasured: number = 0;
|
||||
@@ -94,6 +96,12 @@ export class TerminalProcessManager implements ITerminalProcessManager {
|
||||
this._process.shutdown(immediate);
|
||||
this._process = null;
|
||||
}
|
||||
this._disposables.forEach(d => d.dispose());
|
||||
this._disposables.length = 0;
|
||||
}
|
||||
|
||||
public addDisposable(disposable: IDisposable) {
|
||||
this._disposables.push(disposable);
|
||||
}
|
||||
|
||||
public createProcess(
|
||||
|
||||
@@ -50,16 +50,6 @@ export abstract class TerminalService extends CommonTerminalService implements I
|
||||
}
|
||||
|
||||
public createTerminal(shell: IShellLaunchConfig = {}): ITerminalInstance {
|
||||
if (shell.runInBackground) {
|
||||
const instance = this.createInstance(this._terminalFocusContextKey,
|
||||
this.configHelper,
|
||||
undefined,
|
||||
shell,
|
||||
true);
|
||||
this._backgroundedTerminalInstances.push(instance);
|
||||
this._initInstanceListeners(instance);
|
||||
return instance;
|
||||
}
|
||||
const terminalTab = this._instantiationService.createInstance(TerminalTab,
|
||||
this._terminalFocusContextKey,
|
||||
this.configHelper,
|
||||
@@ -78,24 +68,6 @@ export abstract class TerminalService extends CommonTerminalService implements I
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected _showBackgroundTerminal(instance: ITerminalInstance): void {
|
||||
this._backgroundedTerminalInstances.splice(this._backgroundedTerminalInstances.indexOf(instance), 1);
|
||||
instance.shellLaunchConfig.runInBackground = false;
|
||||
const terminalTab = this._instantiationService.createInstance(TerminalTab,
|
||||
this._terminalFocusContextKey,
|
||||
this.configHelper,
|
||||
this._terminalContainer,
|
||||
instance);
|
||||
this._terminalTabs.push(terminalTab);
|
||||
terminalTab.addDisposable(terminalTab.onDisposed(this._onTabDisposed.fire, this._onTabDisposed));
|
||||
terminalTab.addDisposable(terminalTab.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged));
|
||||
if (this.terminalInstances.length === 1) {
|
||||
// It's the first instance so it should be made active automatically
|
||||
this.setActiveInstanceByIndex(0);
|
||||
}
|
||||
this._onInstancesChanged.fire();
|
||||
}
|
||||
|
||||
public focusFindWidget(): Promise<void> {
|
||||
return this.showPanel(false).then(() => {
|
||||
const panel = this._panelService.getActivePanel() as TerminalPanel;
|
||||
|
||||
@@ -225,7 +225,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
|
||||
terminalFocusContextKey: IContextKey<boolean>,
|
||||
configHelper: ITerminalConfigHelper,
|
||||
private _container: HTMLElement,
|
||||
shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance,
|
||||
shellLaunchConfig: IShellLaunchConfig,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService
|
||||
) {
|
||||
@@ -233,17 +233,12 @@ export class TerminalTab extends Disposable implements ITerminalTab {
|
||||
this._onDisposed = new Emitter<ITerminalTab>();
|
||||
this._onInstancesChanged = new Emitter<void>();
|
||||
|
||||
let instance: ITerminalInstance;
|
||||
if ('id' in shellLaunchConfigOrInstance) {
|
||||
instance = shellLaunchConfigOrInstance;
|
||||
} else {
|
||||
instance = this._terminalService.createInstance(
|
||||
terminalFocusContextKey,
|
||||
configHelper,
|
||||
undefined,
|
||||
shellLaunchConfigOrInstance,
|
||||
true);
|
||||
}
|
||||
const instance = this._terminalService.createInstance(
|
||||
terminalFocusContextKey,
|
||||
configHelper,
|
||||
undefined,
|
||||
shellLaunchConfig,
|
||||
true);
|
||||
this._terminalInstances.push(instance);
|
||||
this._initInstanceListeners(instance);
|
||||
this._activeInstanceIndex = 0;
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Terminal as XTermTerminal } from 'vscode-xterm';
|
||||
import { ITerminalProcessManager } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
export interface ITerminalCore {
|
||||
buffer: any;
|
||||
}
|
||||
|
||||
export interface ITypeAheadAddonTerminal {
|
||||
_core: ITerminalCore;
|
||||
on: any;
|
||||
write(data: string): void;
|
||||
cols: number;
|
||||
|
||||
__typeAheadQueue: string[];
|
||||
__typeAheadState: TypeAheadState;
|
||||
__typeAheadCurrentYBase: number;
|
||||
__typeAheadCurrentY: number;
|
||||
}
|
||||
|
||||
enum TypeAheadState {
|
||||
/**
|
||||
* The normal state, ready to type if it starts.
|
||||
*/
|
||||
Normal,
|
||||
/**
|
||||
* Something happens such that we cannot make a good guess on what to print,
|
||||
* wait until the cursor row changes before proceeding.
|
||||
*/
|
||||
AwaitingRowChange
|
||||
}
|
||||
|
||||
function isCharPrintable(data: string): boolean {
|
||||
const code = data.charCodeAt(0);
|
||||
return data.length === 1 && code >= 32 && code <= 126;
|
||||
}
|
||||
|
||||
function init(terminal: any, processManager: ITerminalProcessManager, themeService: IThemeService): void {
|
||||
const t = terminal as ITypeAheadAddonTerminal;
|
||||
|
||||
t.__typeAheadQueue = [];
|
||||
t.__typeAheadState = TypeAheadState.Normal;
|
||||
t.__typeAheadCurrentYBase = 0;
|
||||
t.__typeAheadCurrentY = 0;
|
||||
|
||||
function typeAhead(data: string): void {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
t.__typeAheadQueue.push(data[i]);
|
||||
}
|
||||
t.write(data);
|
||||
}
|
||||
|
||||
t.on('cursormove', () => {
|
||||
// Reset if the cursor row changed
|
||||
if (t._core.buffer.ybase !== t.__typeAheadCurrentYBase || t._core.buffer.y !== t.__typeAheadCurrentY) {
|
||||
t.__typeAheadCurrentYBase = t._core.buffer.ybase;
|
||||
t.__typeAheadCurrentY = t._core.buffer.y;
|
||||
t.__typeAheadState = TypeAheadState.Normal;
|
||||
}
|
||||
});
|
||||
|
||||
t.on('data', (data: string) => {
|
||||
// Exit if we're waiting for a row change
|
||||
if (t.__typeAheadState === TypeAheadState.AwaitingRowChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only enable in the normal buffer
|
||||
if (!t._core.buffer._hasScrollback) {
|
||||
return;
|
||||
}
|
||||
|
||||
// // Handle enter
|
||||
// if (data === '\r') {
|
||||
// typeAhead('\r\n');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Left arrow
|
||||
// if (data === '\x1b[D') {
|
||||
// // TODO: How to stop it from going beyond prompt?
|
||||
// typeAhead(String.fromCharCode(8));
|
||||
// }
|
||||
|
||||
// // Right arrow
|
||||
// if (data === '\x1b[C') {
|
||||
// // TODO: How to stop it from going beyond prompt?
|
||||
// typeAhead('\x1b[C');
|
||||
// }
|
||||
|
||||
// // Backspace (DEL)
|
||||
// if (data.charCodeAt(0) === 127) {
|
||||
// // TODO: This would require knowing the prompt length to be able to shift everything
|
||||
// }
|
||||
|
||||
if (!isCharPrintable(data)) {
|
||||
t.__typeAheadState = TypeAheadState.AwaitingRowChange;
|
||||
return;
|
||||
}
|
||||
|
||||
if (t._core.buffer.x === t.cols - 1) {
|
||||
// TODO: Does the space get added on Windows/Linux too?
|
||||
data += ' \r';
|
||||
}
|
||||
typeAhead(data);
|
||||
});
|
||||
|
||||
processManager.onBeforeProcessData(event => {
|
||||
let consumeCount = 0;
|
||||
for (let i = 0; i < event.data.length; i++) {
|
||||
if (t.__typeAheadQueue[0] === event.data[i]) {
|
||||
t.__typeAheadQueue.shift();
|
||||
consumeCount++;
|
||||
} else {
|
||||
t.__typeAheadQueue.length = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (consumeCount === event.data.length) {
|
||||
event.data = '';
|
||||
} else if (consumeCount > 0) {
|
||||
event.data = event.data.substr(consumeCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function apply(terminalConstructor: typeof XTermTerminal) {
|
||||
(<any>terminalConstructor.prototype).typeAheadInit = function (processManager: ITerminalProcessManager, themeService: IThemeService): void {
|
||||
init(this, processManager, themeService);
|
||||
};
|
||||
}
|
||||
@@ -101,6 +101,7 @@ export interface ITerminalConfiguration {
|
||||
experimentalBufferImpl: 'JsArray' | 'TypedArray';
|
||||
splitCwd: 'workspaceRoot' | 'initial' | 'inherited';
|
||||
windowsEnableConpty: boolean;
|
||||
enableLatencyMitigation: boolean;
|
||||
experimentalRefreshOnResume: boolean;
|
||||
}
|
||||
|
||||
@@ -161,7 +162,7 @@ export interface IShellLaunchConfig {
|
||||
env?: ITerminalEnvironment;
|
||||
|
||||
/**
|
||||
* Whether to ignore a custom cwd from the `terminal.integrated.cwd` settings key (e.g. if the
|
||||
* Whether to ignore a custom cwd from the `terminal.integrated.cwd` settings key (eg. if the
|
||||
* shell is being launched by an extension).
|
||||
*/
|
||||
ignoreConfigurationCwd?: boolean;
|
||||
@@ -191,15 +192,6 @@ export interface IShellLaunchConfig {
|
||||
* provided as nothing will be inherited from the process or any configuration.
|
||||
*/
|
||||
strictEnv?: boolean;
|
||||
|
||||
/**
|
||||
* When enabled the terminal will run the process as normal but not be surfaced to the user
|
||||
* until `Terminal.show` is called. The typical usage for this is when you need to run
|
||||
* something that may need interactivity but only want to tell the user about it when
|
||||
* interaction is needed. Note that the terminals will still be exposed to all extensions
|
||||
* as normal.
|
||||
*/
|
||||
runInBackground?: boolean;
|
||||
}
|
||||
|
||||
export interface ITerminalService {
|
||||
@@ -434,7 +426,7 @@ export interface ITerminalInstance {
|
||||
|
||||
/**
|
||||
* Whether to disable layout for the terminal. This is useful when the size of the terminal is
|
||||
* being manipulating (e.g. adding a split pane) and we want the terminal to ignore particular
|
||||
* being manipulating (eg. adding a split pane) and we want the terminal to ignore particular
|
||||
* resize events.
|
||||
*/
|
||||
disableLayout: boolean;
|
||||
@@ -671,6 +663,7 @@ export interface ITerminalProcessManager extends IDisposable {
|
||||
readonly onProcessTitle: Event<string>;
|
||||
readonly onProcessExit: Event<number>;
|
||||
|
||||
addDisposable(disposable: IDisposable): void;
|
||||
dispose(immediate?: boolean): void;
|
||||
createProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): void;
|
||||
write(data: string): void;
|
||||
|
||||
@@ -37,7 +37,7 @@ export const TERMINAL_BORDER_COLOR = registerColor('terminal.border', {
|
||||
hc: PANEL_BORDER
|
||||
}, nls.localize('terminal.border', 'The color of the border that separates split panes within the terminal. This defaults to panel.border.'));
|
||||
|
||||
export const ansiColorMap = {
|
||||
const ansiColorMap = {
|
||||
'terminal.ansiBlack': {
|
||||
index: 0,
|
||||
defaults: {
|
||||
|
||||
@@ -5,36 +5,37 @@
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ITerminalService, ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
let hasReceivedResponse: boolean = false;
|
||||
|
||||
export class TerminalProcessExtHostProxy extends Disposable implements ITerminalChildProcess, ITerminalProcessExtHostProxy {
|
||||
export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerminalProcessExtHostProxy {
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
private readonly _onProcessData = this._register(new Emitter<string>());
|
||||
public readonly onProcessData: Event<string> = this._onProcessData.event;
|
||||
private readonly _onProcessExit = this._register(new Emitter<number>());
|
||||
public readonly onProcessExit: Event<number> = this._onProcessExit.event;
|
||||
private readonly _onProcessIdReady = this._register(new Emitter<number>());
|
||||
public readonly onProcessIdReady: Event<number> = this._onProcessIdReady.event;
|
||||
private readonly _onProcessTitleChanged = this._register(new Emitter<string>());
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessData = new Emitter<string>();
|
||||
public get onProcessData(): Event<string> { return this._onProcessData.event; }
|
||||
private readonly _onProcessExit = new Emitter<number>();
|
||||
public get onProcessExit(): Event<number> { return this._onProcessExit.event; }
|
||||
private readonly _onProcessIdReady = new Emitter<number>();
|
||||
public get onProcessIdReady(): Event<number> { return this._onProcessIdReady.event; }
|
||||
private readonly _onProcessTitleChanged = new Emitter<string>();
|
||||
public get onProcessTitleChanged(): Event<string> { return this._onProcessTitleChanged.event; }
|
||||
|
||||
private readonly _onInput = this._register(new Emitter<string>());
|
||||
public readonly onInput: Event<string> = this._onInput.event;
|
||||
private readonly _onResize: Emitter<{ cols: number, rows: number }> = this._register(new Emitter<{ cols: number, rows: number }>());
|
||||
public readonly onResize: Event<{ cols: number, rows: number }> = this._onResize.event;
|
||||
private readonly _onShutdown = this._register(new Emitter<boolean>());
|
||||
public readonly onShutdown: Event<boolean> = this._onShutdown.event;
|
||||
private readonly _onRequestInitialCwd = this._register(new Emitter<void>());
|
||||
public readonly onRequestInitialCwd: Event<void> = this._onRequestInitialCwd.event;
|
||||
private readonly _onRequestCwd = this._register(new Emitter<void>());
|
||||
public readonly onRequestCwd: Event<void> = this._onRequestCwd.event;
|
||||
private readonly _onRequestLatency = this._register(new Emitter<void>());
|
||||
public readonly onRequestLatency: Event<void> = this._onRequestLatency.event;
|
||||
private readonly _onInput = new Emitter<string>();
|
||||
public get onInput(): Event<string> { return this._onInput.event; }
|
||||
private readonly _onResize: Emitter<{ cols: number, rows: number }> = new Emitter<{ cols: number, rows: number }>();
|
||||
public get onResize(): Event<{ cols: number, rows: number }> { return this._onResize.event; }
|
||||
private readonly _onShutdown = new Emitter<boolean>();
|
||||
public get onShutdown(): Event<boolean> { return this._onShutdown.event; }
|
||||
private readonly _onRequestInitialCwd = new Emitter<void>();
|
||||
public get onRequestInitialCwd(): Event<void> { return this._onRequestInitialCwd.event; }
|
||||
private readonly _onRequestCwd = new Emitter<void>();
|
||||
public get onRequestCwd(): Event<void> { return this._onRequestCwd.event; }
|
||||
private readonly _onRequestLatency = new Emitter<void>();
|
||||
public get onRequestLatency(): Event<void> { return this._onRequestLatency.event; }
|
||||
|
||||
private _pendingInitialCwdRequests: ((value?: string | Thenable<string>) => void)[] = [];
|
||||
private _pendingCwdRequests: ((value?: string | Thenable<string>) => void)[] = [];
|
||||
@@ -50,7 +51,6 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@IRemoteAgentService readonly remoteAgentService: IRemoteAgentService
|
||||
) {
|
||||
super();
|
||||
remoteAgentService.getEnvironment().then(env => {
|
||||
if (!env) {
|
||||
throw new Error('Could not fetch environment');
|
||||
@@ -62,6 +62,11 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._disposables.forEach(d => d.dispose());
|
||||
this._disposables.length = 0;
|
||||
}
|
||||
|
||||
public emitData(data: string): void {
|
||||
this._onProcessData.fire(data);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ export abstract class TerminalService implements ITerminalService {
|
||||
protected _findWidgetVisible: IContextKey<boolean>;
|
||||
protected _terminalContainer: HTMLElement;
|
||||
protected _terminalTabs: ITerminalTab[] = [];
|
||||
protected _backgroundedTerminalInstances: ITerminalInstance[] = [];
|
||||
protected get _terminalInstances(): ITerminalInstance[] {
|
||||
return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), <ITerminalInstance[]>[]);
|
||||
}
|
||||
@@ -104,8 +103,8 @@ export abstract class TerminalService implements ITerminalService {
|
||||
|
||||
protected abstract _getWslPath(path: string): Promise<string>;
|
||||
protected abstract _getWindowsBuildNumber(): number;
|
||||
protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void;
|
||||
|
||||
public abstract refreshActiveTab(): 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 getDefaultShell(platform: Platform): string;
|
||||
@@ -207,11 +206,6 @@ export abstract class TerminalService implements ITerminalService {
|
||||
}
|
||||
}
|
||||
|
||||
public refreshActiveTab(): void {
|
||||
// Fire active instances changed
|
||||
this._onActiveTabChanged.fire();
|
||||
}
|
||||
|
||||
public getActiveTab(): ITerminalTab | null {
|
||||
if (this._activeTabIndex < 0 || this._activeTabIndex >= this._terminalTabs.length) {
|
||||
return null;
|
||||
@@ -228,15 +222,6 @@ export abstract class TerminalService implements ITerminalService {
|
||||
}
|
||||
|
||||
public getInstanceFromId(terminalId: number): ITerminalInstance {
|
||||
let bgIndex = -1;
|
||||
this._backgroundedTerminalInstances.forEach((terminalInstance, i) => {
|
||||
if (terminalInstance.id === terminalId) {
|
||||
bgIndex = i;
|
||||
}
|
||||
});
|
||||
if (bgIndex !== -1) {
|
||||
return this._backgroundedTerminalInstances[bgIndex];
|
||||
}
|
||||
return this.terminalInstances[this._getIndexFromId(terminalId)];
|
||||
}
|
||||
|
||||
@@ -245,11 +230,6 @@ export abstract class TerminalService implements ITerminalService {
|
||||
}
|
||||
|
||||
public setActiveInstance(terminalInstance: ITerminalInstance): void {
|
||||
// If this was a runInBackground terminal created by the API this was triggered by show,
|
||||
// in which case we need to create the terminal tab
|
||||
if (terminalInstance.shellLaunchConfig.runInBackground) {
|
||||
this._showBackgroundTerminal(terminalInstance);
|
||||
}
|
||||
this.setActiveInstanceByIndex(this._getIndexFromId(terminalInstance.id));
|
||||
}
|
||||
|
||||
@@ -461,14 +441,15 @@ export abstract class TerminalService implements ITerminalService {
|
||||
|
||||
public preparePathForTerminalAsync(originalPath: string, executable: string, title: string): Promise<string> {
|
||||
return new Promise<string>(c => {
|
||||
if (!executable) {
|
||||
const exe = executable;
|
||||
if (!exe) {
|
||||
c(originalPath);
|
||||
return;
|
||||
}
|
||||
|
||||
const hasSpace = originalPath.indexOf(' ') !== -1;
|
||||
|
||||
const pathBasename = basename(executable, '.exe');
|
||||
const pathBasename = basename(exe, '.exe');
|
||||
const isPowerShell = pathBasename === 'pwsh' ||
|
||||
title === 'pwsh' ||
|
||||
pathBasename === 'powershell' ||
|
||||
@@ -482,9 +463,7 @@ export abstract class TerminalService implements ITerminalService {
|
||||
if (isWindows) {
|
||||
// 17063 is the build number where wsl path was introduced.
|
||||
// Update Windows uriPath to be executed in WSL.
|
||||
const lowerExecutable = executable.toLowerCase();
|
||||
if (this._getWindowsBuildNumber() >= 17063 &&
|
||||
(lowerExecutable.indexOf('wsl') !== -1 || (lowerExecutable.indexOf('bash.exe') !== -1 && lowerExecutable.toLowerCase().indexOf('git') === -1))) {
|
||||
if (((exe.indexOf('wsl') !== -1) || ((exe.indexOf('bash.exe') !== -1) && (exe.indexOf('git') === -1))) && (this._getWindowsBuildNumber() >= 17063)) {
|
||||
c(this._getWslPath(originalPath));
|
||||
return;
|
||||
} else if (hasSpace) {
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Platform } from 'vs/base/common/platform';
|
||||
|
||||
export function registerShellConfiguration(getDefaultShell?: (p: Platform) => string): void {
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||
configurationRegistry.registerConfiguration({
|
||||
id: 'terminal',
|
||||
order: 100,
|
||||
title: nls.localize('terminalIntegratedConfigurationTitle', "Integrated Terminal"),
|
||||
type: 'object',
|
||||
properties: {
|
||||
'terminal.integrated.shell.linux': {
|
||||
markdownDescription:
|
||||
getDefaultShell
|
||||
? nls.localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(Platform.Linux))
|
||||
: nls.localize('terminal.integrated.shell.linux.noDefault', "The path of the shell that the terminal uses on Linux. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."),
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
},
|
||||
'terminal.integrated.shell.osx': {
|
||||
markdownDescription:
|
||||
getDefaultShell
|
||||
? nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(Platform.Mac))
|
||||
: nls.localize('terminal.integrated.shell.osx.noDefault', "The path of the shell that the terminal uses on macOS. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."),
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
},
|
||||
'terminal.integrated.shell.windows': {
|
||||
markdownDescription:
|
||||
getDefaultShell
|
||||
? nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(Platform.Windows))
|
||||
: nls.localize('terminal.integrated.shell.windows.noDefault', "The path of the shell that the terminal uses on Windows. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."),
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3,14 +3,41 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstanceService';
|
||||
import { TerminalService } from 'vs/workbench/contrib/terminal/electron-browser/terminalService';
|
||||
import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { registerShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalShellConfig';
|
||||
|
||||
registerShellConfiguration(getDefaultShell);
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||
configurationRegistry.registerConfiguration({
|
||||
id: 'terminal',
|
||||
order: 100,
|
||||
title: nls.localize('terminalIntegratedConfigurationTitle', "Integrated Terminal"),
|
||||
type: 'object',
|
||||
properties: {
|
||||
'terminal.integrated.shell.linux': {
|
||||
markdownDescription: nls.localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Linux)),
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
},
|
||||
'terminal.integrated.shell.osx': {
|
||||
markdownDescription: nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Mac)),
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
},
|
||||
'terminal.integrated.shell.windows': {
|
||||
markdownDescription: nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Windows)),
|
||||
type: ['string', 'null'],
|
||||
default: null
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
registerSingleton(ITerminalService, TerminalService, true);
|
||||
registerSingleton(ITerminalInstanceService, TerminalInstanceService, true);
|
||||
|
||||
@@ -3,20 +3,19 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { ITerminalInstance, IWindowsShellHelper, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { Terminal as XTermTerminal } from 'vscode-xterm';
|
||||
import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITerminalProcessManager, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager';
|
||||
import { IProcessEnvironment, Platform } from 'vs/base/common/platform';
|
||||
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
||||
import * as typeAheadAddon from 'vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon';
|
||||
import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { Terminal as XTermTerminal } from 'xterm';
|
||||
import { WebLinksAddon as XTermWebLinksAddon } from 'xterm-addon-web-links';
|
||||
import { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
|
||||
|
||||
let Terminal: typeof XTermTerminal;
|
||||
let WebLinksAddon: typeof XTermWebLinksAddon;
|
||||
let SearchAddon: typeof XTermSearchAddon;
|
||||
|
||||
/**
|
||||
* A service used by TerminalInstance (and components owned by it) that allows it to break its
|
||||
@@ -33,29 +32,27 @@ export class TerminalInstanceService implements ITerminalInstanceService {
|
||||
|
||||
public async getXtermConstructor(): Promise<typeof XTermTerminal> {
|
||||
if (!Terminal) {
|
||||
Terminal = (await import('xterm')).Terminal;
|
||||
Terminal = (await import('vscode-xterm')).Terminal;
|
||||
// Enable xterm.js addons
|
||||
Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/search/search'));
|
||||
Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/webLinks/webLinks'));
|
||||
Terminal.applyAddon(typeAheadAddon);
|
||||
// Localize strings
|
||||
Terminal.strings.blankLine = nls.localize('terminal.integrated.a11yBlankLine', 'Blank line');
|
||||
Terminal.strings.promptLabel = nls.localize('terminal.integrated.a11yPromptLabel', 'Terminal input');
|
||||
Terminal.strings.tooMuchOutput = nls.localize('terminal.integrated.a11yTooMuchOutput', 'Too much output to announce, navigate to rows manually to read');
|
||||
}
|
||||
return Terminal;
|
||||
}
|
||||
|
||||
public async getXtermWebLinksConstructor(): Promise<typeof XTermWebLinksAddon> {
|
||||
if (!WebLinksAddon) {
|
||||
WebLinksAddon = (await import('xterm-addon-web-links')).WebLinksAddon;
|
||||
}
|
||||
return WebLinksAddon;
|
||||
}
|
||||
|
||||
public async getXtermSearchConstructor(): Promise<typeof XTermSearchAddon> {
|
||||
if (!SearchAddon) {
|
||||
SearchAddon = (await import('xterm-addon-search')).SearchAddon;
|
||||
}
|
||||
return SearchAddon;
|
||||
}
|
||||
|
||||
public createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper {
|
||||
return new WindowsShellHelper(shellProcessId, instance, xterm);
|
||||
}
|
||||
|
||||
public createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager {
|
||||
return this._instantiationService.createInstance(TerminalProcessManager, id, configHelper);
|
||||
}
|
||||
|
||||
public createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess {
|
||||
return this._instantiationService.createInstance(TerminalProcess, shellLaunchConfig, cwd, cols, rows, env, windowsEnableConpty);
|
||||
}
|
||||
|
||||
@@ -100,6 +100,11 @@ export class TerminalService extends BrowserTerminalService implements ITerminal
|
||||
return getDefaultShell(p);
|
||||
}
|
||||
|
||||
public refreshActiveTab(): void {
|
||||
// Fire active instances changed
|
||||
this._onActiveTabChanged.fire();
|
||||
}
|
||||
|
||||
public selectDefaultWindowsShell(): Promise<string | undefined> {
|
||||
return this._detectWindowsShells().then(shells => {
|
||||
const options: IPickOptions<IQuickPickItem> = {
|
||||
|
||||
@@ -54,7 +54,14 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
||||
|
||||
this._initialCwd = cwd;
|
||||
|
||||
const useConpty = windowsEnableConpty && process.platform === 'win32' && getWindowsBuildNumber() >= 18309;
|
||||
// Only use ConPTY when the client is non WoW64 (see #72190) and the Windows build number is at least 18309 (for
|
||||
// stability/performance reasons)
|
||||
const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
|
||||
const useConpty = windowsEnableConpty &&
|
||||
process.platform === 'win32' &&
|
||||
!is32ProcessOn64Windows &&
|
||||
getWindowsBuildNumber() >= 18309;
|
||||
|
||||
const options: pty.IPtyForkOptions | pty.IWindowsPtyForkOptions = {
|
||||
name: shellName,
|
||||
cwd,
|
||||
@@ -193,9 +200,6 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
if (typeof cols !== 'number' || typeof rows !== 'number' || isNaN(cols) || isNaN(rows)) {
|
||||
return;
|
||||
}
|
||||
// Ensure that cols and rows are always >= 1, this prevents a native
|
||||
// exception in winpty.
|
||||
if (this._ptyProcess) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { ITerminalInstance, IWindowsShellHelper } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { Terminal as XTermTerminal } from 'xterm';
|
||||
import { Terminal as XTermTerminal } from 'vscode-xterm';
|
||||
import WindowsProcessTreeType = require('windows-process-tree');
|
||||
|
||||
const SHELL_EXECUTABLES = [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Terminal, TerminalCore } from 'xterm';
|
||||
import { Terminal, TerminalCore } from 'vscode-xterm';
|
||||
import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import * as assert from 'assert';
|
||||
import { Platform, OperatingSystem } from 'vs/base/common/platform';
|
||||
import { TerminalLinkHandler, LineColumnInfo } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
|
||||
class TestTerminalLinkHandler extends TerminalLinkHandler {
|
||||
public get localLinkRegex(): RegExp {
|
||||
@@ -25,34 +24,10 @@ class TestTerminalLinkHandler extends TerminalLinkHandler {
|
||||
}
|
||||
|
||||
class TestXterm {
|
||||
public loadAddon() { }
|
||||
public webLinksInit() { }
|
||||
public registerLinkMatcher() { }
|
||||
}
|
||||
|
||||
class MockTerminalInstanceService implements ITerminalInstanceService {
|
||||
_serviceBrand: any;
|
||||
getXtermConstructor(): Promise<any> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
async getXtermWebLinksConstructor(): Promise<any> {
|
||||
return (await import('xterm-addon-web-links')).WebLinksAddon;
|
||||
}
|
||||
getXtermSearchConstructor(): Promise<any> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
createWindowsShellHelper(): any {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
createTerminalProcess(): any {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getDefaultShell(p: Platform): string {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
interface LinkFormatInfo {
|
||||
urlFormat: string;
|
||||
line?: string;
|
||||
@@ -65,7 +40,7 @@ suite('Workbench - TerminalLinkHandler', () => {
|
||||
const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, {
|
||||
os: OperatingSystem.Windows,
|
||||
userHome: ''
|
||||
} as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!);
|
||||
} as any, null!, null!, null!, null!, null!);
|
||||
function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) {
|
||||
assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl);
|
||||
assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl);
|
||||
@@ -140,7 +115,7 @@ suite('Workbench - TerminalLinkHandler', () => {
|
||||
const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, {
|
||||
os: OperatingSystem.Linux,
|
||||
userHome: ''
|
||||
} as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!);
|
||||
} as any, null!, null!, null!, null!, null!);
|
||||
function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) {
|
||||
assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl);
|
||||
assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl);
|
||||
@@ -207,7 +182,7 @@ suite('Workbench - TerminalLinkHandler', () => {
|
||||
const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, {
|
||||
os: OperatingSystem.Windows,
|
||||
userHome: 'C:\\Users\\Me'
|
||||
} as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!);
|
||||
} as any, null!, null!, null!, null!, null!);
|
||||
linkHandler.processCwd = 'C:\\base';
|
||||
|
||||
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base\\src\\file1');
|
||||
@@ -220,7 +195,7 @@ suite('Workbench - TerminalLinkHandler', () => {
|
||||
const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, {
|
||||
os: OperatingSystem.Windows,
|
||||
userHome: 'C:\\Users\\M e'
|
||||
} as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!);
|
||||
} as any, null!, null!, null!, null!, null!);
|
||||
linkHandler.processCwd = 'C:\\base dir';
|
||||
|
||||
assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base dir\\src\\file1');
|
||||
@@ -234,7 +209,7 @@ suite('Workbench - TerminalLinkHandler', () => {
|
||||
const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, {
|
||||
os: OperatingSystem.Linux,
|
||||
userHome: '/home/me'
|
||||
} as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!);
|
||||
} as any, null!, null!, null!, null!, null!);
|
||||
linkHandler.processCwd = '/base';
|
||||
|
||||
assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/src/file1');
|
||||
@@ -247,7 +222,7 @@ suite('Workbench - TerminalLinkHandler', () => {
|
||||
const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, {
|
||||
os: OperatingSystem.Linux,
|
||||
userHome: '/home/me'
|
||||
} as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!);
|
||||
} as any, null!, null!, null!, null!, null!);
|
||||
|
||||
assert.equal(linkHandler.preprocessPath('./src/file1'), null);
|
||||
assert.equal(linkHandler.preprocessPath('src/file2'), null);
|
||||
@@ -261,7 +236,7 @@ suite('Workbench - TerminalLinkHandler', () => {
|
||||
const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, {
|
||||
os: OperatingSystem.Linux,
|
||||
userHome: ''
|
||||
} as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!);
|
||||
} as any, null!, null!, null!, null!, null!);
|
||||
|
||||
function assertAreGoodMatches(matches: RegExpMatchArray | null) {
|
||||
if (matches) {
|
||||
|
||||
@@ -11,14 +11,14 @@ import { IStringDictionary } from 'vs/base/common/collections';
|
||||
|
||||
suite('Workbench - TerminalEnvironment', () => {
|
||||
test('addTerminalEnvironmentKeys', () => {
|
||||
const env: { [key: string]: any } = { FOO: 'bar' };
|
||||
const env = { FOO: 'bar' };
|
||||
const locale = 'en-au';
|
||||
terminalEnvironment.addTerminalEnvironmentKeys(env, '1.2.3', locale, true);
|
||||
assert.equal(env['TERM_PROGRAM'], 'vscode');
|
||||
assert.equal(env['TERM_PROGRAM_VERSION'], '1.2.3');
|
||||
assert.equal(env['LANG'], 'en_AU.UTF-8', 'LANG is equal to the requested locale with UTF-8');
|
||||
|
||||
const env2: { [key: string]: any } = { FOO: 'bar' };
|
||||
const env2 = { FOO: 'bar' };
|
||||
terminalEnvironment.addTerminalEnvironmentKeys(env2, '1.2.3', undefined, true);
|
||||
assert.equal(env2['LANG'], 'en_US.UTF-8', 'LANG is equal to en_US.UTF-8 as fallback.'); // More info on issue #14586
|
||||
|
||||
|
||||
Reference in New Issue
Block a user