Revert "Merge from vscode 81d7885dc2e9dc617e1522697a2966bc4025a45d (#5949)" (#5983)

This reverts commit d15a3fcc98.
This commit is contained in:
Karl Burtram
2019-06-11 12:35:58 -07:00
committed by GitHub
parent 95a50b7892
commit 5a7562a37b
926 changed files with 11394 additions and 19540 deletions

View File

@@ -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;
}

View File

@@ -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]

View File

@@ -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;
}

View File

@@ -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));

View File

@@ -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';

View File

@@ -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';

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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(

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
};
}

View File

@@ -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;

View File

@@ -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: {

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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
}
}
});
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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> = {

View File

@@ -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) {

View File

@@ -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 = [

View File

@@ -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';

View File

@@ -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) {

View File

@@ -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