Merge from vscode 8aa90d444f5d051984e8055f547c4252d53479b3 (#5587)

* Merge from vscode 8aa90d444f5d051984e8055f547c4252d53479b3

* pipeline errors

* fix build
This commit is contained in:
Anthony Dresser
2019-05-23 11:16:03 -07:00
committed by GitHub
parent ca36f20c6b
commit cf8f8907ee
141 changed files with 6450 additions and 1228 deletions

View File

@@ -35,6 +35,7 @@ import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { isWindows } from 'vs/base/common/platform';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export const TERMINAL_PICKER_PREFIX = 'term ';
@@ -85,7 +86,7 @@ export class ToggleTerminalAction extends TogglePanelAction {
if (this.terminalService.terminalInstances.length === 0) {
// If there is not yet an instance attempt to create it here so that we can suggest a
// new shell on Windows (and not do so when the panel is restored on reload).
const newTerminalInstance = this.terminalService.createTerminal(undefined, true);
const newTerminalInstance = this.terminalService.createTerminal(undefined);
const toDispose = newTerminalInstance.onProcessIdReady(() => {
newTerminalInstance.focus();
toDispose.dispose();
@@ -329,7 +330,7 @@ export class CreateNewTerminalAction extends Action {
if (folders.length <= 1) {
// Allow terminal service to handle the path when there is only a
// single root
instancePromise = Promise.resolve(this.terminalService.createTerminal(undefined, true));
instancePromise = Promise.resolve(this.terminalService.createTerminal(undefined));
} else {
const options: IPickOptions<IQuickPickItem> = {
placeHolder: nls.localize('workbench.action.terminal.newWorkspacePlaceholder', "Select current working directory for new terminal")
@@ -339,7 +340,7 @@ export class CreateNewTerminalAction extends Action {
// Don't create the instance if the workspace picker was canceled
return null;
}
return this.terminalService.createTerminal({ cwd: workspace.uri }, true);
return this.terminalService.createTerminal({ cwd: workspace.uri });
});
}
@@ -366,7 +367,7 @@ export class CreateNewInActiveWorkspaceTerminalAction extends Action {
}
public run(event?: any): Promise<any> {
const instance = this.terminalService.createTerminal(undefined, true);
const instance = this.terminalService.createTerminal(undefined);
if (!instance) {
return Promise.resolve(undefined);
}
@@ -720,6 +721,14 @@ export class SwitchTerminalAction extends Action {
if (!item || !item.split) {
return Promise.resolve(null);
}
if (item === SwitchTerminalActionViewItem.SEPARATOR) {
this.terminalService.refreshActiveTab();
return Promise.resolve(null);
}
if (item === SelectDefaultShellWindowsTerminalAction.LABEL) {
this.terminalService.refreshActiveTab();
return this.terminalService.selectDefaultWindowsShell();
}
const selectedTabIndex = parseInt(item.split(':')[0], 10) - 1;
this.terminalService.setActiveTabByIndex(selectedTabIndex);
return this.terminalService.showPanel(true);
@@ -728,11 +737,14 @@ export class SwitchTerminalAction extends Action {
export class SwitchTerminalActionViewItem extends SelectActionViewItem {
public static readonly SEPARATOR = '─────────';
constructor(
action: IAction,
@ITerminalService private readonly terminalService: ITerminalService,
@IThemeService themeService: IThemeService,
@IContextViewService contextViewService: IContextViewService
@IContextViewService contextViewService: IContextViewService,
@IWorkbenchEnvironmentService private workbenchEnvironmentService: IWorkbenchEnvironmentService
) {
super(null, action, terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }), terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.') });
@@ -743,7 +755,13 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
}
private _updateItems(): void {
this.setOptions(this.terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }), this.terminalService.activeTabIndex);
const items = this.terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label });
let enableSelectDefaultShell = this.workbenchEnvironmentService.configuration.remoteAuthority ? false : isWindows;
if (enableSelectDefaultShell) {
items.push({ text: SwitchTerminalActionViewItem.SEPARATOR });
items.push({ text: SelectDefaultShellWindowsTerminalAction.LABEL });
}
this.setOptions(items, this.terminalService.activeTabIndex);
}
}

View File

@@ -635,7 +635,7 @@ export class TerminalInstance implements ITerminalInstance {
private _measureRenderTime(): void {
const frameTimes: number[] = [];
const textRenderLayer = this._xterm._core.renderer._renderLayers[0];
const textRenderLayer = this._xterm._core._renderCoordinator._renderer._renderLayers[0];
const originalOnGridChanged = textRenderLayer.onGridChanged;
const evaluateCanvasRenderer = () => {
@@ -647,11 +647,7 @@ export class TerminalInstance implements ITerminalInstance {
const promptChoices: IPromptChoice[] = [
{
label: nls.localize('yes', "Yes"),
run: () => {
this._configurationService.updateValue('terminal.integrated.rendererType', 'dom', ConfigurationTarget.USER).then(() => {
this._notificationService.info(nls.localize('terminal.rendererInAllNewTerminals', "The terminal is now using the fallback renderer."));
});
}
run: () => this._configurationService.updateValue('terminal.integrated.rendererType', 'dom', ConfigurationTarget.USER)
} as IPromptChoice,
{
label: nls.localize('no', "No"),
@@ -1264,7 +1260,7 @@ export class TerminalInstance implements ITerminalInstance {
// maximize on Windows/Linux would fire an event saying that the terminal was not
// visible.
if (this._xterm.getOption('rendererType') === 'canvas') {
this._xterm._core.renderer.onIntersectionChange({ intersectionRatio: 1 });
this._xterm._core._renderCoordinator._onIntersectionChange({ intersectionRatio: 1 });
// HACK: Force a refresh of the screen to ensure links are refresh corrected.
// This can probably be removed when the above hack is fixed in Chromium.
this._xterm.refresh(0, this._xterm.rows - 1);

View File

@@ -88,6 +88,9 @@ export class TerminalLinkHandler {
this._gitDiffPostImagePattern = /^\+\+\+ b\/(\S*)/;
this._tooltipCallback = (e: MouseEvent) => {
if (!this._widgetManager) {
return;
}
if (this._terminalService && this._terminalService.configHelper.config.rendererType === 'dom') {
const target = (e.target as HTMLElement);
this._widgetManager.showMessage(target.offsetLeft, target.offsetTop, this._getLinkHoverString());
@@ -115,7 +118,11 @@ export class TerminalLinkHandler {
const options: ILinkMatcherOptions = {
matchIndex,
tooltipCallback: this._tooltipCallback,
leaveCallback: () => this._widgetManager.closeMessage(),
leaveCallback: () => {
if (this._widgetManager) {
this._widgetManager.closeMessage();
}
},
willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e),
priority: CUSTOM_LINK_PRIORITY
};
@@ -132,7 +139,11 @@ export class TerminalLinkHandler {
this._xterm.webLinksInit(wrappedHandler, {
validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateWebLink(uri, callback),
tooltipCallback: this._tooltipCallback,
leaveCallback: () => this._widgetManager.closeMessage(),
leaveCallback: () => {
if (this._widgetManager) {
this._widgetManager.closeMessage();
}
},
willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e)
});
}
@@ -144,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._widgetManager.closeMessage(),
leaveCallback: () => {
if (this._widgetManager) {
this._widgetManager.closeMessage();
}
},
willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e),
priority: LOCAL_LINK_PRIORITY
});
@@ -158,7 +173,11 @@ export class TerminalLinkHandler {
matchIndex: 1,
validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateLocalLink(uri, callback),
tooltipCallback: this._tooltipCallback,
leaveCallback: () => this._widgetManager.closeMessage(),
leaveCallback: () => {
if (this._widgetManager) {
this._widgetManager.closeMessage();
}
},
willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e),
priority: LOCAL_LINK_PRIORITY
};
@@ -242,12 +261,16 @@ export class TerminalLinkHandler {
private _getLinkHoverString(): string {
const editorConf = this._configurationService.getValue<{ multiCursorModifier: 'ctrlCmd' | 'alt' }>('editor');
if (editorConf.multiCursorModifier === 'ctrlCmd') {
return nls.localize('terminalLinkHandler.followLinkAlt', 'Alt + click to follow link');
if (platform.isMacintosh) {
return nls.localize('terminalLinkHandler.followLinkAlt.mac', "Option + click to follow link");
} else {
return nls.localize('terminalLinkHandler.followLinkAlt', "Alt + click to follow link");
}
}
if (platform.isMacintosh) {
return nls.localize('terminalLinkHandler.followLinkCmd', 'Cmd + click to follow link');
return nls.localize('terminalLinkHandler.followLinkCmd', "Cmd + click to follow link");
}
return nls.localize('terminalLinkHandler.followLinkCtrl', 'Ctrl + click to follow link');
return nls.localize('terminalLinkHandler.followLinkCtrl', "Ctrl + click to follow link");
}
private get osPath(): IPath {

View File

@@ -3,21 +3,19 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as platform from 'vs/base/common/platform';
import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, IShellLaunchConfig, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal';
import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal';
import { TerminalService as CommonTerminalService } from 'vs/workbench/contrib/terminal/common/terminalService';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
@@ -36,7 +34,6 @@ export abstract class TerminalService extends CommonTerminalService implements I
@INotificationService notificationService: INotificationService,
@IDialogService dialogService: IDialogService,
@IInstantiationService protected readonly _instantiationService: IInstantiationService,
@IWorkbenchEnvironmentService private _environmentService: IWorkbenchEnvironmentService,
@IExtensionService extensionService: IExtensionService,
@IFileService fileService: IFileService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
@@ -52,7 +49,7 @@ export abstract class TerminalService extends CommonTerminalService implements I
return instance;
}
public createTerminal(shell: IShellLaunchConfig = {}, wasNewTerminalAction?: boolean): ITerminalInstance {
public createTerminal(shell: IShellLaunchConfig = {}): ITerminalInstance {
const terminalTab = this._instantiationService.createInstance(TerminalTab,
this._terminalFocusContextKey,
this.configHelper,
@@ -68,74 +65,9 @@ export abstract class TerminalService extends CommonTerminalService implements I
this.setActiveInstanceByIndex(0);
}
this._onInstancesChanged.fire();
this._suggestShellChange(wasNewTerminalAction);
return instance;
}
private _suggestShellChange(wasNewTerminalAction?: boolean): void {
// Only suggest on Windows since $SHELL works great for macOS/Linux
if (!platform.isWindows) {
return;
}
if (this._environmentService.configuration.remoteAuthority) {
// Don't suggest if the opened workspace is remote
return;
}
// Only suggest when the terminal instance is being created by an explicit user action to
// launch a terminal, as opposed to something like tasks, debug, panel restore, etc.
if (!wasNewTerminalAction) {
return;
}
if (this._environmentService.configuration.remoteAuthority) {
// Don't suggest if the opened workspace is remote
return;
}
// Don't suggest if the user has explicitly opted out
const neverSuggest = this._storageService.getBoolean(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, StorageScope.GLOBAL, false);
if (neverSuggest) {
return;
}
// Never suggest if the setting is non-default already (ie. they set the setting manually)
if (this.configHelper.config.shell.windows !== this.getDefaultShell(platform.Platform.Windows)) {
this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL);
return;
}
this._notificationService.prompt(
Severity.Info,
nls.localize('terminal.integrated.chooseWindowsShellInfo', "You can change the default terminal shell by selecting the customize button."),
[{
label: nls.localize('customize', "Customize"),
run: () => {
this.selectDefaultWindowsShell().then(shell => {
if (!shell) {
return Promise.resolve(null);
}
// Launch a new instance with the newly selected shell
const instance = this.createTerminal({
executable: shell,
args: this.configHelper.config.shellArgs.windows
});
if (instance) {
this.setActiveInstance(instance);
}
return Promise.resolve(null);
});
}
},
{
label: nls.localize('never again', "Don't Show Again"),
isSecondary: true,
run: () => this._storageService.store(NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, true, StorageScope.GLOBAL)
}]
);
}
public focusFindWidget(): Promise<void> {
return this.showPanel(false).then(() => {
const panel = this._panelService.getActivePanel() as TerminalPanel;

View File

@@ -37,7 +37,6 @@ export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED = new RawContextKey
export const KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED.toNegated();
export const IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY = 'terminal.integrated.isWorkspaceShellAllowed';
export const NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY = 'terminal.integrated.neverSuggestSelectWindowsShell';
export const NEVER_MEASURE_RENDER_TIME_STORAGE_KEY = 'terminal.integrated.neverMeasureRenderTime';
// The creation of extension host terminals is delayed by this value (milliseconds). The purpose of
@@ -64,9 +63,9 @@ export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '50
export interface ITerminalConfiguration {
shell: {
linux: string;
osx: string;
windows: string;
linux: string | null;
osx: string | null;
windows: string | null;
};
shellArgs: {
linux: string[];
@@ -216,10 +215,8 @@ export interface ITerminalService {
/**
* Creates a terminal.
* @param shell The shell launch configuration to use.
* @param wasNewTerminalAction Whether this was triggered by a new terminal action, if so a
* default shell selection dialog may display.
*/
createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
createTerminal(shell?: IShellLaunchConfig): ITerminalInstance;
/**
* Creates a terminal renderer.
@@ -245,6 +242,12 @@ export interface ITerminalService {
setActiveTabToPrevious(): void;
setActiveTabByIndex(tabIndex: number): void;
/**
* Fire the onActiveTabChanged event, this will trigger the terminal dropdown to be updated,
* among other things.
*/
refreshActiveTab(): void;
showPanel(focus?: boolean): Promise<void>;
hidePanel(): void;
focusFindWidget(): Promise<void>;

View File

@@ -98,6 +98,7 @@ function _getLangEnvVariable(locale?: string) {
es: 'ES',
fi: 'FI',
fr: 'FR',
hu: 'HU',
it: 'IT',
ja: 'JP',
ko: 'KR',

View File

@@ -41,7 +41,7 @@ export abstract class TerminalService implements ITerminalService {
public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; }
public get terminalTabs(): ITerminalTab[] { return this._terminalTabs; }
private readonly _onActiveTabChanged = new Emitter<void>();
protected readonly _onActiveTabChanged = new Emitter<void>();
public get onActiveTabChanged(): Event<void> { return this._onActiveTabChanged.event; }
protected readonly _onInstanceCreated = new Emitter<ITerminalInstance>();
public get onInstanceCreated(): Event<ITerminalInstance> { return this._onInstanceCreated.event; }
@@ -104,6 +104,7 @@ export abstract class TerminalService implements ITerminalService {
protected abstract _getWslPath(path: string): Promise<string>;
protected abstract _getWindowsBuildNumber(): number;
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;

View File

@@ -20,7 +20,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ipcRenderer as ipc } from 'electron';
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
import { coalesce } from 'vs/base/common/arrays';
@@ -45,11 +44,10 @@ export class TerminalService extends BrowserTerminalService implements ITerminal
@INotificationService notificationService: INotificationService,
@IDialogService dialogService: IDialogService,
@IExtensionService extensionService: IExtensionService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IFileService fileService: IFileService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
) {
super(contextKeyService, panelService, layoutService, lifecycleService, storageService, notificationService, dialogService, instantiationService, environmentService, extensionService, fileService, remoteAgentService);
super(contextKeyService, panelService, layoutService, lifecycleService, storageService, notificationService, dialogService, instantiationService, extensionService, fileService, remoteAgentService);
this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, linuxDistro);
ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => {
@@ -102,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

@@ -62,13 +62,14 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
!is32ProcessOn64Windows &&
getWindowsBuildNumber() >= 18309;
const options: pty.IPtyForkOptions = {
const options: pty.IPtyForkOptions | pty.IWindowsPtyForkOptions = {
name: shellName,
cwd,
env,
cols,
rows,
experimentalUseConpty: useConpty
experimentalUseConpty: useConpty,
conptyInheritCursor: true
};
// TODO: Need to verify whether executable is on $PATH, otherwise things like cmd.exe will break
@@ -91,14 +92,14 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
this._processStartupComplete = new Promise<void>(c => {
this.onProcessIdReady(() => c());
});
ptyProcess.on('data', (data) => {
ptyProcess.on('data', data => {
this._onProcessData.fire(data);
if (this._closeTimeout) {
clearTimeout(this._closeTimeout);
this._queueProcessExit();
}
});
ptyProcess.on('exit', (code) => {
ptyProcess.on('exit', code => {
this._exitCode = code;
this._queueProcessExit();
});
@@ -126,12 +127,14 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
setTimeout(() => {
this._sendProcessTitle(ptyProcess);
}, 0);
// Setup polling
this._titleInterval = setInterval(() => {
if (this._currentTitle !== ptyProcess.process) {
this._sendProcessTitle(ptyProcess);
}
}, 200);
// Setup polling for non-Windows, for Windows `process` doesn't change
if (!platform.isWindows) {
this._titleInterval = setInterval(() => {
if (this._currentTitle !== ptyProcess.process) {
this._sendProcessTitle(ptyProcess);
}
}, 200);
}
}
// Allow any trailing data events to be sent before the exit event is sent.
@@ -189,7 +192,7 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable {
if (this._isDisposed || !this._ptyProcess) {
return;
}
this._logService.trace('IPty#write', data);
this._logService.trace('IPty#write', `${data.length} characters`);
this._ptyProcess.write(data);
}