Merge from vscode 10492ba146318412cbee8b76a8c630f226914734

This commit is contained in:
ADS Merger
2020-04-08 06:33:38 +00:00
parent fca2344c2e
commit 1868a7d370
339 changed files with 3795 additions and 3146 deletions

View File

@@ -161,7 +161,18 @@
transform: rotate(-90deg);
}
.monaco-workbench .part > .title > .title-actions .switch-terminal {
.monaco-workbench .part.sidebar > .title > .title-actions .switch-terminal,
.monaco-pane-view .pane > .pane-header .monaco-action-bar .switch-terminal {
border-width: 1px;
border-style: solid;
}
.part.panel > .title > .title-actions .switch-terminal > .monaco-select-box {
border-width: 1px;
border-style: solid;
}
.monaco-workbench .part.sidebar > .title > .title-actions .switch-terminal {
display: flex;
align-items: center;
font-size: 11px;
@@ -171,11 +182,11 @@
margin-top: 7px;
}
.monaco-workbench.mac .part > .title > .title-actions .switch-terminal {
.monaco-workbench.mac .part.sidebar > .title > .title-actions .switch-terminal {
border-radius: 4px;
}
.monaco-workbench .part > .title > .title-actions .switch-terminal > .monaco-select-box {
.monaco-workbench .part.sidebar > .title > .title-actions .switch-terminal > .monaco-select-box {
border: none !important;
display: block !important;
background-color: unset !important;
@@ -185,7 +196,7 @@
border: none !important;
}
.monaco-workbench .part > .title > .title-actions .switch-terminal > .monaco-select-box {
.monaco-workbench .part.sidebar > .title > .title-actions .switch-terminal > .monaco-select-box {
padding: 0 22px 0 6px;
}

View File

@@ -12,16 +12,16 @@ import 'vs/css!./media/xterm';
import * as nls from 'vs/nls';
import { SyncActionDescriptor, registerAction2 } from 'vs/platform/actions/common/actions';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingWeight, KeybindingsRegistry, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import * as panel from 'vs/workbench/browser/panel';
import { getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess';
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
import { Extensions as ViewContainerExtensions, IViewContainersRegistry, ViewContainerLocation, IViewsRegistry } from 'vs/workbench/common/views';
import { ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickAccessTerminalAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand, NavigationModeFocusPreviousTerminalAction, NavigationModeFocusNextTerminalAction, NavigationModeExitTerminalAction, ManageWorkspaceShellPermissionsTerminalCommand, CreateNewWithCwdTerminalAction, RenameWithArgTerminalAction, SendSequenceTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, QuickAccessTerminalAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand, NavigationModeFocusPreviousTerminalAction, NavigationModeFocusNextTerminalAction, NavigationModeExitTerminalAction, ManageWorkspaceShellPermissionsTerminalCommand, CreateNewWithCwdTerminalAction, RenameWithArgTerminalAction, SendSequenceTerminalAction, terminalSendSequenceCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView';
import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_VIEW_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, TERMINAL_ACTION_CATEGORY, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_VIEW_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, TERMINAL_ACTION_CATEGORY, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { setupTerminalCommands } from 'vs/workbench/contrib/terminal/browser/terminalCommands';
import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu';
@@ -32,7 +32,7 @@ import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalS
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { registerShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalShellConfig';
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalService, WindowsShellType } from 'vs/workbench/contrib/terminal/browser/terminal';
import { BrowserFeatures } from 'vs/base/browser/canIUse';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
@@ -333,6 +333,11 @@ configurationRegistry.registerConfiguration({
type: 'boolean',
default: true
},
'terminal.integrated.wordSeparators': {
description: nls.localize('terminal.integrated.wordSeparators', "A string containing all characters to be considered word separators by the double click to select word feature."),
type: 'string',
default: ' ()[]{}\',"`'
},
'terminal.integrated.experimentalUseTitleEvent': {
description: nls.localize('terminal.integrated.experimentalUseTitleEvent', "An experimental setting that will use the terminal title event for the dropdown title. This setting will only apply to new terminals."),
type: 'boolean',
@@ -447,26 +452,6 @@ actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(HideTerminalF
primary: KeyCode.Escape,
secondary: [KeyMod.Shift | KeyCode.Escape]
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE)), 'Terminal: Hide Find Widget', category);
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(DeleteWordLeftTerminalAction, DeleteWordLeftTerminalAction.ID, DeleteWordLeftTerminalAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.Backspace,
mac: { primary: KeyMod.Alt | KeyCode.Backspace }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Left', category);
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(DeleteWordRightTerminalAction, DeleteWordRightTerminalAction.ID, DeleteWordRightTerminalAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.Delete,
mac: { primary: KeyMod.Alt | KeyCode.Delete }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Right', category);
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(DeleteToLineStartTerminalAction, DeleteToLineStartTerminalAction.ID, DeleteToLineStartTerminalAction.LABEL, {
primary: 0,
mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete To Line Start', category);
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(MoveToLineStartTerminalAction, MoveToLineStartTerminalAction.ID, MoveToLineStartTerminalAction.LABEL, {
primary: 0,
mac: { primary: KeyMod.CtrlCmd | KeyCode.LeftArrow }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line Start', category);
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(MoveToLineEndTerminalAction, MoveToLineEndTerminalAction.ID, MoveToLineEndTerminalAction.LABEL, {
primary: 0,
mac: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line End', category);
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(SplitTerminalAction, SplitTerminalAction.ID, SplitTerminalAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5,
mac: {
@@ -576,14 +561,60 @@ if (BrowserFeatures.clipboard.writeText) {
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C }
}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FOCUS)), 'Terminal: Copy Selection', category);
}
function registerSendSequenceKeybinding(text: string, rule: { when?: ContextKeyExpression } & IKeybindings): void {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: SendSequenceTerminalAction.ID,
weight: KeybindingWeight.WorkbenchContrib,
when: rule.when || KEYBINDING_CONTEXT_TERMINAL_FOCUS,
primary: rule.primary,
mac: rule.mac,
linux: rule.linux,
win: rule.win,
handler: terminalSendSequenceCommand,
args: { text }
});
}
if (BrowserFeatures.clipboard.readText) {
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.create(TerminalPasteAction, TerminalPasteAction.ID, TerminalPasteAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V] },
linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Paste into Active Terminal', category);
// An extra Windows-only ctrl+v keybinding is used for pwsh that sends ctrl+v directly to the
// shell, this gets handled by PSReadLine which properly handles multi-line pastes
if (platform.isWindows) {
registerSendSequenceKeybinding(String.fromCharCode('V'.charCodeAt(0) - 64), { // ctrl+v
when: ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, ContextKeyExpr.equals(KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY, WindowsShellType.PowerShell)),
primary: KeyMod.CtrlCmd | KeyCode.KEY_V
});
}
}
// Delete word left: ctrl+w
registerSendSequenceKeybinding(String.fromCharCode('W'.charCodeAt(0) - 64), {
primary: KeyMod.CtrlCmd | KeyCode.Backspace,
mac: { primary: KeyMod.Alt | KeyCode.Backspace }
});
// Delete word right: alt+d
registerSendSequenceKeybinding('\x1bd', {
primary: KeyMod.CtrlCmd | KeyCode.Delete,
mac: { primary: KeyMod.Alt | KeyCode.Delete }
});
// Delete to line start: ctrl+u
registerSendSequenceKeybinding('\u0015', {
mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace }
});
// Move to line start: ctrl+A
registerSendSequenceKeybinding(String.fromCharCode('A'.charCodeAt(0) - 64), {
mac: { primary: KeyMod.CtrlCmd | KeyCode.LeftArrow }
});
// Move to line end: ctrl+E
registerSendSequenceKeybinding(String.fromCharCode('E'.charCodeAt(0) - 64), {
mac: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow }
});
registerAction2(class extends SendSequenceTerminalAction {
constructor() {
super({

View File

@@ -139,7 +139,7 @@ export interface ITerminalService {
*/
addLinkHandler(key: string, callback: TerminalLinkHandlerCallback): IDisposable;
selectDefaultWindowsShell(): Promise<void>;
selectDefaultShell(): Promise<void>;
setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
manageWorkspaceShellPermissions(): void;
@@ -180,10 +180,10 @@ export interface ISearchOptions {
}
export enum WindowsShellType {
CommandPrompt,
PowerShell,
Wsl,
GitBash
CommandPrompt = 'cmd',
PowerShell = 'pwsh',
Wsl = 'wsl',
GitBash = 'gitbash'
}
export type TerminalShellType = WindowsShellType | undefined;

View File

@@ -165,115 +165,31 @@ export class SelectAllTerminalAction extends Action {
}
}
export abstract class BaseSendTextTerminalAction extends Action {
constructor(
id: string,
label: string,
private _text: string,
@ITerminalService private readonly _terminalService: ITerminalService
) {
super(id, label);
}
public run(event?: any): Promise<any> {
const terminalInstance = this._terminalService.getActiveInstance();
if (terminalInstance) {
terminalInstance.sendText(this._text, false);
}
return Promise.resolve(undefined);
}
}
export class DeleteWordLeftTerminalAction extends BaseSendTextTerminalAction {
public static readonly ID = TERMINAL_COMMAND_ID.DELETE_WORD_LEFT;
public static readonly LABEL = nls.localize('workbench.action.terminal.deleteWordLeft', "Delete Word Left");
constructor(
id: string,
label: string,
@ITerminalService terminalService: ITerminalService
) {
// Send ctrl+W
super(id, label, String.fromCharCode('W'.charCodeAt(0) - 64), terminalService);
}
}
export class DeleteWordRightTerminalAction extends BaseSendTextTerminalAction {
public static readonly ID = TERMINAL_COMMAND_ID.DELETE_WORD_RIGHT;
public static readonly LABEL = nls.localize('workbench.action.terminal.deleteWordRight', "Delete Word Right");
constructor(
id: string,
label: string,
@ITerminalService terminalService: ITerminalService
) {
// Send alt+d
super(id, label, '\x1bd', terminalService);
}
}
export class DeleteToLineStartTerminalAction extends BaseSendTextTerminalAction {
public static readonly ID = TERMINAL_COMMAND_ID.DELETE_TO_LINE_START;
public static readonly LABEL = nls.localize('workbench.action.terminal.deleteToLineStart', "Delete To Line Start");
constructor(
id: string,
label: string,
@ITerminalService terminalService: ITerminalService
) {
// Send ctrl+u
super(id, label, '\u0015', terminalService);
}
}
export class MoveToLineStartTerminalAction extends BaseSendTextTerminalAction {
public static readonly ID = TERMINAL_COMMAND_ID.MOVE_TO_LINE_START;
public static readonly LABEL = nls.localize('workbench.action.terminal.moveToLineStart', "Move To Line Start");
constructor(
id: string,
label: string,
@ITerminalService terminalService: ITerminalService
) {
// Send ctrl+A
super(id, label, String.fromCharCode('A'.charCodeAt(0) - 64), terminalService);
}
}
export class MoveToLineEndTerminalAction extends BaseSendTextTerminalAction {
public static readonly ID = TERMINAL_COMMAND_ID.MOVE_TO_LINE_END;
public static readonly LABEL = nls.localize('workbench.action.terminal.moveToLineEnd', "Move To Line End");
constructor(
id: string,
label: string,
@ITerminalService terminalService: ITerminalService
) {
// Send ctrl+E
super(id, label, String.fromCharCode('E'.charCodeAt(0) - 64), terminalService);
}
}
export class SendSequenceTerminalAction extends Action2 {
public static readonly ID = TERMINAL_COMMAND_ID.SEND_SEQUENCE;
public static readonly LABEL = nls.localize('workbench.action.terminal.sendSequence', "Send Custom Sequence To Terminal");
public run(accessor: ServicesAccessor, args: any): void {
const terminalInstance = accessor.get(ITerminalService).getActiveInstance();
if (!terminalInstance) {
return;
}
const configurationResolverService = accessor.get(IConfigurationResolverService);
const workspaceContextService = accessor.get(IWorkspaceContextService);
const historyService = accessor.get(IHistoryService);
const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(Schemas.file);
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? withNullAsUndefined(workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri)) : undefined;
const resolvedText = configurationResolverService.resolve(lastActiveWorkspaceRoot, args.text);
terminalInstance.sendText(resolvedText, false);
terminalSendSequenceCommand(accessor, args);
}
}
export const terminalSendSequenceCommand = (accessor: ServicesAccessor, args: any) => {
const terminalInstance = accessor.get(ITerminalService).getActiveInstance();
if (!terminalInstance) {
return;
}
const configurationResolverService = accessor.get(IConfigurationResolverService);
const workspaceContextService = accessor.get(IWorkspaceContextService);
const historyService = accessor.get(IHistoryService);
const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(Schemas.file);
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? withNullAsUndefined(workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri)) : undefined;
const resolvedText = configurationResolverService.resolve(lastActiveWorkspaceRoot, args.text);
terminalInstance.sendText(resolvedText, false);
};
export class CreateNewWithCwdTerminalAction extends Action2 {
public static readonly ID = TERMINAL_COMMAND_ID.NEW_WITH_CWD;
public static readonly LABEL = nls.localize('workbench.action.terminal.newWithCwd', "Create New Integrated Terminal Starting in a Custom Working Directory");
@@ -609,7 +525,7 @@ export class SelectDefaultShellWindowsTerminalAction extends Action {
}
public run(event?: any): Promise<any> {
return this._terminalService.selectDefaultWindowsShell();
return this._terminalService.selectDefaultShell();
}
}
@@ -679,6 +595,7 @@ export class RunActiveFileInTerminalAction extends Action {
return Promise.resolve(undefined);
}
// TODO: Convert this to ctrl+c, ctrl+v for pwsh?
const path = await this.terminalService.preparePathForTerminalAsync(uri.fsPath, instance.shellLaunchConfig.executable, instance.title, instance.shellType);
instance.sendText(path, true);
return this.terminalService.showPanel();
@@ -707,7 +624,7 @@ export class SwitchTerminalAction extends Action {
}
if (item === SelectDefaultShellWindowsTerminalAction.LABEL) {
this.terminalService.refreshActiveTab();
return this.terminalService.selectDefaultWindowsShell();
return this.terminalService.selectDefaultShell();
}
const selectedTabIndex = parseInt(item.split(':')[0], 10) - 1;
this.terminalService.setActiveTabByIndex(selectedTabIndex);
@@ -725,7 +642,7 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
@IThemeService private readonly themeService: IThemeService,
@IContextViewService contextViewService: IContextViewService
) {
super(null, action, terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label }), terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.') });
super(null, action, getTerminalSelectOpenItems(terminalService), terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.') });
this._register(terminalService.onInstancesChanged(this._updateItems, this));
this._register(terminalService.onActiveTabChanged(this._updateItems, this));
@@ -738,18 +655,22 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem {
super.render(container);
addClass(container, 'switch-terminal');
this._register(attachStylerCallback(this.themeService, { selectBorder }, colors => {
container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : '';
container.style.borderColor = colors.selectBorder ? `${colors.selectBorder}` : '';
}));
}
private _updateItems(): void {
const items = this.terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label });
items.push({ text: SwitchTerminalActionViewItem.SEPARATOR, isDisabled: true });
items.push({ text: SelectDefaultShellWindowsTerminalAction.LABEL });
this.setOptions(items, this.terminalService.activeTabIndex);
this.setOptions(getTerminalSelectOpenItems(this.terminalService), this.terminalService.activeTabIndex);
}
}
function getTerminalSelectOpenItems(terminalService: ITerminalService): ISelectOptionItem[] {
const items = terminalService.getTabLabels().map(label => <ISelectOptionItem>{ text: label });
items.push({ text: SwitchTerminalActionViewItem.SEPARATOR, isDisabled: true });
items.push({ text: SelectDefaultShellWindowsTerminalAction.LABEL });
return items;
}
export class ScrollDownTerminalAction extends Action {
public static readonly ID = TERMINAL_COMMAND_ID.SCROLL_DOWN_LINE;
@@ -957,6 +878,7 @@ export class ClearTerminalAction extends Action {
const terminalInstance = this.terminalService.getActiveInstance();
if (terminalInstance) {
terminalInstance.clear();
terminalInstance.focus();
}
return Promise.resolve(undefined);
}

View File

@@ -124,9 +124,23 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
fontSize,
letterSpacing,
lineHeight,
charWidth: rect && rect.width ? rect.width : 0,
charHeight: rect && rect.height ? Math.ceil(rect.height) : 0
charWidth: 0,
charHeight: 0
};
if (rect && rect.width && rect.height) {
this._lastFontMeasurement.charHeight = Math.ceil(rect.height);
// Char width is calculated differently for DOM and the other renderer types. Refer to
// how each renderer updates their dimensions in xterm.js
if (this.config.rendererType === 'dom') {
this._lastFontMeasurement.charWidth = rect.width;
} else {
const scaledCharWidth = rect.width * window.devicePixelRatio;
const scaledCellWidth = scaledCharWidth + Math.round(letterSpacing);
this._lastFontMeasurement.charWidth = Math.round(scaledCellWidth / window.devicePixelRatio);
}
}
return this._lastFontMeasurement;
}
@@ -167,14 +181,14 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
// Get the character dimensions from xterm if it's available
if (xtermCore) {
if (xtermCore._charSizeService && xtermCore._charSizeService.width && xtermCore._charSizeService.height) {
if (xtermCore._renderService && xtermCore._renderService.dimensions?.actualCellWidth && xtermCore._renderService.dimensions?.actualCellHeight) {
return {
fontFamily,
fontSize,
letterSpacing,
lineHeight,
charHeight: xtermCore._charSizeService.height,
charWidth: xtermCore._charSizeService.width
charHeight: xtermCore._renderService.dimensions.actualCellHeight / lineHeight,
charWidth: xtermCore._renderService.dimensions.actualCellWidth
};
}
}

View File

@@ -277,6 +277,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
public constructor(
private readonly _terminalFocusContextKey: IContextKey<boolean>,
private readonly _terminalShellTypeContextKey: IContextKey<string>,
private readonly _configHelper: TerminalConfigHelper,
private _container: HTMLElement | undefined,
private _shellLaunchConfig: IShellLaunchConfig,
@@ -488,7 +489,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
fastScrollSensitivity: editorOptions.fastScrollSensitivity,
scrollSensitivity: editorOptions.mouseWheelScrollSensitivity,
rendererType: config.rendererType === 'auto' || config.rendererType === 'experimentalWebgl' ? 'canvas' : config.rendererType,
wordSeparator: ' ()[]{}\',"`'
wordSeparator: config.wordSeparators
});
this._xterm = xterm;
this._xtermCore = (xterm as any)._core as XTermCore;
@@ -671,13 +672,18 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
while (!dom.hasClass(currentElement, 'part')) {
currentElement = currentElement.parentElement!;
}
const hidePanelElement = <HTMLElement>currentElement.querySelector('.hide-panel-action');
hidePanelElement.focus();
const hidePanelElement = currentElement.querySelector<HTMLElement>('.hide-panel-action');
hidePanelElement?.focus();
}));
xtermHelper.insertBefore(focusTrap, xterm.textarea);
this._register(dom.addDisposableListener(xterm.textarea, 'focus', () => {
this._terminalFocusContextKey.set(true);
if (this.shellType) {
this._terminalShellTypeContextKey.set(this.shellType.toString());
} else {
this._terminalShellTypeContextKey.reset();
}
this._onFocused.fire(this);
}));
this._register(dom.addDisposableListener(xterm.textarea, 'blur', () => {
@@ -686,6 +692,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}));
this._register(dom.addDisposableListener(xterm.element, 'focus', () => {
this._terminalFocusContextKey.set(true);
if (this.shellType) {
this._terminalShellTypeContextKey.set(this.shellType.toString());
} else {
this._terminalShellTypeContextKey.reset();
}
}));
this._register(dom.addDisposableListener(xterm.element, 'blur', () => {
this._terminalFocusContextKey.reset();
@@ -1248,6 +1259,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._safeSetOption('macOptionIsMeta', config.macOptionIsMeta);
this._safeSetOption('macOptionClickForcesSelection', config.macOptionClickForcesSelection);
this._safeSetOption('rightClickSelectsWord', config.rightClickBehavior === 'selectWord');
this._safeSetOption('wordSeparator', config.wordSeparators);
if (config.rendererType !== 'experimentalWebgl') {
// Never set webgl as it's an addon not a rendererType
this._safeSetOption('rendererType', config.rendererType === 'auto' ? 'canvas' : config.rendererType);

View File

@@ -24,6 +24,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
import { Disposable } from 'vs/base/common/lifecycle';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IEnvironmentVariableService, IMergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IRemotePathService } from 'vs/workbench/services/path/common/remotePathService';
/** The amount of time to consider terminal errors to be related to the launch */
const LAUNCHING_DURATION = 500;
@@ -90,6 +91,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
@IProductService private readonly _productService: IProductService,
@ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService,
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
@IRemotePathService private readonly _remotePathService: IRemotePathService,
@IEnvironmentVariableService private readonly _environmentVariableService: IEnvironmentVariableService
) {
super();
@@ -133,23 +135,22 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
const hasRemoteAuthority = !!this.remoteAuthority;
let launchRemotely = hasRemoteAuthority || forceExtHostProcess;
this.userHome = this._environmentService.userHome;
const userHomeUri = await this._remotePathService.userHome;
this.os = platform.OS;
if (launchRemotely) {
this.userHome = userHomeUri.path;
if (hasRemoteAuthority) {
this._remoteAgentService.getEnvironment().then(env => {
if (!env) {
return;
}
this.userHome = env.userHome.path;
this.os = env.os;
});
const remoteEnv = await this._remoteAgentService.getEnvironment();
if (remoteEnv) {
this.os = remoteEnv.os;
}
}
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot();
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, this._configHelper);
} else {
this._process = await this._launchProcess(shellLaunchConfig, cols, rows, isScreenReaderModeEnabled);
this.userHome = userHomeUri.fsPath;
this._process = await this._launchProcess(shellLaunchConfig, cols, rows, this.userHome, isScreenReaderModeEnabled);
}
}
this.processState = ProcessState.LAUNCHING;
@@ -194,6 +195,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
shellLaunchConfig: IShellLaunchConfig,
cols: number,
rows: number,
userHome: string,
isScreenReaderModeEnabled: boolean
): Promise<ITerminalChildProcess> {
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot(Schemas.file);
@@ -220,7 +222,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
const initialCwd = terminalEnvironment.getCwd(
shellLaunchConfig,
this._environmentService.userHome,
userHome,
lastActiveWorkspace,
this._configurationResolverService,
activeWorkspaceRootUri,

View File

@@ -4,9 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { TERMINAL_VIEW_ID, IShellLaunchConfig, ITerminalConfigHelper, ITerminalNativeService, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalProcessExtHostProxy, IShellDefinition, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal';
import { TERMINAL_VIEW_ID, IShellLaunchConfig, ITerminalConfigHelper, ITerminalNativeService, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalProcessExtHostProxy, IShellDefinition, LinuxDistro, KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE } from 'vs/workbench/contrib/terminal/common/terminal';
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 { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView';
@@ -26,10 +25,12 @@ import { FindReplaceState } from 'vs/editor/contrib/find/findState';
import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { isWindows, isMacintosh, OperatingSystem } from 'vs/base/common/platform';
import { basename } from 'vs/base/common/path';
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
// TODO@daniel code layering
// eslint-disable-next-line code-layering, code-import-patterns
import { INativeOpenFileRequest } from 'vs/platform/windows/node/window';
import { find } from 'vs/base/common/arrays';
import { timeout } from 'vs/base/common/async';
import { IViewsService } from 'vs/workbench/common/views';
import { IViewsService, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views';
import { IDisposable } from 'vs/base/common/lifecycle';
interface IExtHostReadyEntry {
@@ -40,12 +41,13 @@ interface IExtHostReadyEntry {
export class TerminalService implements ITerminalService {
public _serviceBrand: undefined;
protected _isShuttingDown: boolean;
protected _terminalFocusContextKey: IContextKey<boolean>;
protected _findWidgetVisible: IContextKey<boolean>;
protected _terminalTabs: ITerminalTab[] = [];
protected _backgroundedTerminalInstances: ITerminalInstance[] = [];
protected get _terminalInstances(): ITerminalInstance[] {
private _isShuttingDown: boolean;
private _terminalFocusContextKey: IContextKey<boolean>;
private _terminalShellTypeContextKey: IContextKey<string>;
private _findWidgetVisible: IContextKey<boolean>;
private _terminalTabs: ITerminalTab[] = [];
private _backgroundedTerminalInstances: ITerminalInstance[] = [];
private get _terminalInstances(): ITerminalInstance[] {
return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), <ITerminalInstance[]>[]);
}
private _findState: FindReplaceState;
@@ -62,38 +64,37 @@ export class TerminalService implements ITerminalService {
public get configHelper(): ITerminalConfigHelper { return this._configHelper; }
protected readonly _onActiveTabChanged = new Emitter<void>();
private readonly _onActiveTabChanged = new Emitter<void>();
public get onActiveTabChanged(): Event<void> { return this._onActiveTabChanged.event; }
protected readonly _onInstanceCreated = new Emitter<ITerminalInstance>();
private readonly _onInstanceCreated = new Emitter<ITerminalInstance>();
public get onInstanceCreated(): Event<ITerminalInstance> { return this._onInstanceCreated.event; }
protected readonly _onInstanceDisposed = new Emitter<ITerminalInstance>();
private readonly _onInstanceDisposed = new Emitter<ITerminalInstance>();
public get onInstanceDisposed(): Event<ITerminalInstance> { return this._onInstanceDisposed.event; }
protected readonly _onInstanceProcessIdReady = new Emitter<ITerminalInstance>();
private readonly _onInstanceProcessIdReady = new Emitter<ITerminalInstance>();
public get onInstanceProcessIdReady(): Event<ITerminalInstance> { return this._onInstanceProcessIdReady.event; }
protected readonly _onInstanceRequestSpawnExtHostProcess = new Emitter<ISpawnExtHostProcessRequest>();
private readonly _onInstanceRequestSpawnExtHostProcess = new Emitter<ISpawnExtHostProcessRequest>();
public get onInstanceRequestSpawnExtHostProcess(): Event<ISpawnExtHostProcessRequest> { return this._onInstanceRequestSpawnExtHostProcess.event; }
protected readonly _onInstanceRequestStartExtensionTerminal = new Emitter<IStartExtensionTerminalRequest>();
private readonly _onInstanceRequestStartExtensionTerminal = new Emitter<IStartExtensionTerminalRequest>();
public get onInstanceRequestStartExtensionTerminal(): Event<IStartExtensionTerminalRequest> { return this._onInstanceRequestStartExtensionTerminal.event; }
protected readonly _onInstanceDimensionsChanged = new Emitter<ITerminalInstance>();
private readonly _onInstanceDimensionsChanged = new Emitter<ITerminalInstance>();
public get onInstanceDimensionsChanged(): Event<ITerminalInstance> { return this._onInstanceDimensionsChanged.event; }
protected readonly _onInstanceMaximumDimensionsChanged = new Emitter<ITerminalInstance>();
private readonly _onInstanceMaximumDimensionsChanged = new Emitter<ITerminalInstance>();
public get onInstanceMaximumDimensionsChanged(): Event<ITerminalInstance> { return this._onInstanceMaximumDimensionsChanged.event; }
protected readonly _onInstancesChanged = new Emitter<void>();
private readonly _onInstancesChanged = new Emitter<void>();
public get onInstancesChanged(): Event<void> { return this._onInstancesChanged.event; }
protected readonly _onInstanceTitleChanged = new Emitter<ITerminalInstance>();
private readonly _onInstanceTitleChanged = new Emitter<ITerminalInstance>();
public get onInstanceTitleChanged(): Event<ITerminalInstance> { return this._onInstanceTitleChanged.event; }
protected readonly _onActiveInstanceChanged = new Emitter<ITerminalInstance | undefined>();
private readonly _onActiveInstanceChanged = new Emitter<ITerminalInstance | undefined>();
public get onActiveInstanceChanged(): Event<ITerminalInstance | undefined> { return this._onActiveInstanceChanged.event; }
protected readonly _onTabDisposed = new Emitter<ITerminalTab>();
private readonly _onTabDisposed = new Emitter<ITerminalTab>();
public get onTabDisposed(): Event<ITerminalTab> { return this._onTabDisposed.event; }
protected readonly _onRequestAvailableShells = new Emitter<IAvailableShellsRequest>();
private readonly _onRequestAvailableShells = new Emitter<IAvailableShellsRequest>();
public get onRequestAvailableShells(): Event<IAvailableShellsRequest> { return this._onRequestAvailableShells.event; }
private readonly _terminalNativeService: ITerminalNativeService | undefined;
constructor(
@IContextKeyService private _contextKeyService: IContextKeyService,
@IPanelService private _panelService: IPanelService,
@IWorkbenchLayoutService private _layoutService: IWorkbenchLayoutService,
@ILifecycleService lifecycleService: ILifecycleService,
@IDialogService private _dialogService: IDialogService,
@@ -103,6 +104,7 @@ export class TerminalService implements ITerminalService {
@IQuickInputService private _quickInputService: IQuickInputService,
@IConfigurationService private _configurationService: IConfigurationService,
@IViewsService private _viewsService: IViewsService,
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService,
@optional(ITerminalNativeService) terminalNativeService: ITerminalNativeService
) {
// @optional could give undefined and properly typing it breaks service registration
@@ -118,6 +120,7 @@ export class TerminalService implements ITerminalService {
this._terminalNativeService.onOsResume(() => this._onOsResume());
}
this._terminalFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_FOCUS.bindTo(this._contextKeyService);
this._terminalShellTypeContextKey = KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE.bindTo(this._contextKeyService);
this._findWidgetVisible = KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService);
this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, this._terminalNativeService?.linuxDistro || LinuxDistro.Unknown);
this.onTabDisposed(tab => this._removeTab(tab));
@@ -207,7 +210,7 @@ export class TerminalService implements ITerminalService {
this.terminalInstances.forEach(instance => instance.dispose(true));
}
private async _onOpenFileRequest(request: IOpenFileRequest): Promise<void> {
private async _onOpenFileRequest(request: INativeOpenFileRequest): Promise<void> {
// if the request to open files is coming in from the integrated terminal (identified though
// the termProgram variable) and we are instructed to wait for editors close, wait for the
// marker file to get deleted and then focus back to the integrated terminal.
@@ -582,8 +585,8 @@ export class TerminalService implements ITerminalService {
});
}
public async selectDefaultWindowsShell(): Promise<void> {
const shells = await this._detectWindowsShells();
public async selectDefaultShell(): Promise<void> {
const shells = await this._detectShells();
const options: IPickOptions<IQuickPickItem> = {
placeHolder: nls.localize('terminal.integrated.chooseWindowsShell', "Select your preferred terminal shell, you can change this later in your settings")
};
@@ -605,13 +608,13 @@ export class TerminalService implements ITerminalService {
await this._configurationService.updateValue(`terminal.integrated.shell.${platformKey}`, shell, ConfigurationTarget.USER);
}
private _detectWindowsShells(): Promise<IShellDefinition[]> {
private _detectShells(): Promise<IShellDefinition[]> {
return new Promise(r => this._onRequestAvailableShells.fire({ callback: r }));
}
public createInstance(container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance {
const instance = this._instantiationService.createInstance(TerminalInstance, this._terminalFocusContextKey, this._configHelper, container, shellLaunchConfig);
const instance = this._instantiationService.createInstance(TerminalInstance, this._terminalFocusContextKey, this._terminalShellTypeContextKey, this._configHelper, container, shellLaunchConfig);
this._onInstanceCreated.fire(instance);
return instance;
}
@@ -623,11 +626,7 @@ export class TerminalService implements ITerminalService {
this._initInstanceListeners(instance);
return instance;
}
const terminalTab = this._instantiationService.createInstance(TerminalTab,
this._terminalFocusContextKey,
this.configHelper,
this._terminalContainer,
shell);
const terminalTab = this._instantiationService.createInstance(TerminalTab, this._terminalContainer, shell);
this._terminalTabs.push(terminalTab);
const instance = terminalTab.terminalInstances[0];
terminalTab.addDisposable(terminalTab.onDisposed(this._onTabDisposed.fire, this._onTabDisposed));
@@ -644,11 +643,7 @@ export class TerminalService implements ITerminalService {
protected _showBackgroundTerminal(instance: ITerminalInstance): void {
this._backgroundedTerminalInstances.splice(this._backgroundedTerminalInstances.indexOf(instance), 1);
instance.shellLaunchConfig.hideFromUser = false;
const terminalTab = this._instantiationService.createInstance(TerminalTab,
this._terminalFocusContextKey,
this.configHelper,
this._terminalContainer,
instance);
const terminalTab = this._instantiationService.createInstance(TerminalTab, 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));
@@ -698,9 +693,13 @@ export class TerminalService implements ITerminalService {
}
public hidePanel(): void {
const panel = this._panelService.getActivePanel();
if (panel && panel.getId() === TERMINAL_VIEW_ID) {
this._layoutService.setPanelHidden(true);
// Hide the panel if the terminal is in the panel and it has no sibling views
const location = this._viewDescriptorService.getViewLocation(TERMINAL_VIEW_ID);
if (location === ViewContainerLocation.Panel) {
const panel = this._viewDescriptorService.getViewContainer(TERMINAL_VIEW_ID);
if (panel && this._viewDescriptorService.getViewDescriptors(panel).activeViewDescriptors.length === 1) {
this._layoutService.setPanelHidden(true);
}
}
}
}

View File

@@ -4,8 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as aria from 'vs/base/browser/ui/aria/aria';
import * as nls from 'vs/nls';
import { IShellLaunchConfig, ITerminalConfigHelper, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IShellLaunchConfig, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { SplitView, Orientation, IView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
@@ -228,8 +227,6 @@ export class TerminalTab extends Disposable implements ITerminalTab {
public readonly onInstancesChanged: Event<void> = this._onInstancesChanged.event;
constructor(
terminalFocusContextKey: IContextKey<boolean>,
configHelper: ITerminalConfigHelper,
private _container: HTMLElement | undefined,
shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance,
@ITerminalService private readonly _terminalService: ITerminalService,

View File

@@ -232,6 +232,13 @@ export class TerminalViewPane extends ViewPane {
if (!terminal) {
return;
}
// copyPaste: Shift+right click should open context menu
if (rightClickBehavior === 'copyPaste' && event.shiftKey) {
this._openContextMenu(event);
return;
}
if (rightClickBehavior === 'copyPaste' && terminal.hasSelection()) {
await terminal.copySelection();
terminal.clearSelection();
@@ -253,13 +260,7 @@ export class TerminalViewPane extends ViewPane {
}));
this._register(dom.addDisposableListener(parentDomElement, 'contextmenu', (event: MouseEvent) => {
if (!this._cancelContextMenu) {
const standardEvent = new StandardMouseEvent(event);
const anchor: { x: number, y: number } = { x: standardEvent.posx, y: standardEvent.posy };
this._contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => this._getContextMenuActions(),
getActionsContext: () => this._parentDomElement
});
this._openContextMenu(event);
}
event.preventDefault();
event.stopImmediatePropagation();
@@ -306,6 +307,16 @@ export class TerminalViewPane extends ViewPane {
}));
}
private _openContextMenu(event: MouseEvent): void {
const standardEvent = new StandardMouseEvent(event);
const anchor: { x: number, y: number } = { x: standardEvent.posx, y: standardEvent.posy };
this._contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => this._getContextMenuActions(),
getActionsContext: () => this._parentDomElement
});
}
private _updateTheme(theme?: IColorTheme): void {
if (!theme) {
theme = this.themeService.getColorTheme();

View File

@@ -17,6 +17,10 @@ export interface XTermCore {
};
_renderService: {
dimensions: {
actualCellWidth: number;
actualCellHeight: number;
},
_renderer: {
_renderLayers: any[];
};

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IEnvironmentVariableCollection, EnvironmentVariableMutatorType, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff, IExtensionOwnedEnvironmentVariableMutator } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
export class MergedEnvironmentVariableCollection implements IMergedEnvironmentVariableCollection {
readonly map: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> = new Map();
@@ -42,17 +42,23 @@ export class MergedEnvironmentVariableCollection implements IMergedEnvironmentVa
}
applyToProcessEnvironment(env: IProcessEnvironment): void {
let lowerToActualVariableNames: { [lowerKey: string]: string | undefined } | undefined;
if (isWindows) {
lowerToActualVariableNames = {};
Object.keys(env).forEach(e => lowerToActualVariableNames![e.toLowerCase()] = e);
}
this.map.forEach((mutators, variable) => {
const actualVariable = isWindows ? lowerToActualVariableNames![variable.toLowerCase()] || variable : variable;
mutators.forEach(mutator => {
switch (mutator.type) {
case EnvironmentVariableMutatorType.Append:
env[variable] = (env[variable] || '') + mutator.value;
env[actualVariable] = (env[actualVariable] || '') + mutator.value;
break;
case EnvironmentVariableMutatorType.Prepend:
env[variable] = mutator.value + (env[variable] || '');
env[actualVariable] = mutator.value + (env[actualVariable] || '');
break;
case EnvironmentVariableMutatorType.Replace:
env[variable] = mutator.value;
env[actualVariable] = mutator.value;
break;
}
});

View File

@@ -16,10 +16,17 @@ export const TERMINAL_VIEW_ID = 'workbench.panel.terminal';
/** A context key that is set when there is at least one opened integrated terminal. */
export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey<boolean>('terminalIsOpen', false);
/** A context key that is set when the integrated terminal has focus. */
export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey<boolean>('terminalFocus', false);
export const KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY = 'terminalShellType';
/** A context key that is set to the detected shell for the most recently active terminal, this is set to the last known value when no terminals exist. */
export const KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE = new RawContextKey<string>(KEYBINDING_CONTEXT_TERMINAL_SHELL_TYPE_KEY, undefined);
/** A context key that is set when the integrated terminal does not have focus. */
export const KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED = KEYBINDING_CONTEXT_TERMINAL_FOCUS.toNegated();
/** A context key that is set when the user is navigating the accessibility tree */
export const KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS = new RawContextKey<boolean>('terminalA11yTreeFocus', false);
@@ -120,6 +127,7 @@ export interface ITerminalConfiguration {
showExitAlert: boolean;
splitCwd: 'workspaceRoot' | 'initial' | 'inherited';
windowsEnableConpty: boolean;
wordSeparators: string;
experimentalUseTitleEvent: boolean;
enableFileLinks: boolean;
unicodeVersion: '6' | '11';

View File

@@ -109,8 +109,8 @@ async function detectAvailableWindowsShells(): Promise<IShellDefinition[]> {
const expectedLocations: { [key: string]: string[] } = {
'Command Prompt': [`${system32Path}\\cmd.exe`],
PowerShell: [`${system32Path}\\WindowsPowerShell\\v1.0\\powershell.exe`],
'PowerShell Core': [await getShellPathFromRegistry('pwsh')],
'Windows PowerShell': [`${system32Path}\\WindowsPowerShell\\v1.0\\powershell.exe`],
'PowerShell': [await getShellPathFromRegistry('pwsh')],
'WSL Bash': [`${system32Path}\\${useWSLexe ? 'wsl.exe' : 'bash.exe'}`],
'Git Bash': [
`${process.env['ProgramW6432']}\\Git\\bin\\bash.exe`,

View File

@@ -5,7 +5,7 @@
import { deepStrictEqual, strictEqual } from 'assert';
import { EnvironmentVariableMutatorType } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
@@ -119,6 +119,40 @@ suite('EnvironmentVariable - MergedEnvironmentVariableCollection', () => {
C: 'c'
});
});
test('should apply to variable case insensitively on Windows only', () => {
const merged = new MergedEnvironmentVariableCollection(new Map([
['ext', {
map: deserializeEnvironmentVariableCollection([
['a', { value: 'a', type: EnvironmentVariableMutatorType.Replace }],
['b', { value: 'b', type: EnvironmentVariableMutatorType.Append }],
['c', { value: 'c', type: EnvironmentVariableMutatorType.Prepend }]
])
}]
]));
const env: IProcessEnvironment = {
A: 'A',
B: 'B',
C: 'C'
};
merged.applyToProcessEnvironment(env);
if (isWindows) {
deepStrictEqual(env, {
A: 'a',
B: 'Bb',
C: 'cC'
});
} else {
deepStrictEqual(env, {
a: 'a',
A: 'A',
b: 'b',
B: 'B',
c: 'c',
C: 'C'
});
}
});
});
suite('diff', () => {