diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 2306ffaedb5a3..01a089f82644a 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -440,9 +440,9 @@ "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.0.tgz" }, "xterm": { - "version": "2.6.0", - "from": "Tyriar/xterm.js#vscode-release/1.13", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#55e0399c1b3ccf06c5d677bf7945b9b2d598fc16" + "version": "2.7.0", + "from": "Tyriar/xterm.js#vscode-release/1.14", + "resolved": "git+https://github.com/Tyriar/xterm.js.git#1d7007669dec1f60e5878aa102a36473d8cbd97f" }, "yauzl": { "version": "2.3.1", diff --git a/package.json b/package.json index 333ee2253b61c..09d83d51cb262 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "vscode-ripgrep": "0.0.12", "vscode-textmate": "^3.1.5", "winreg": "1.2.0", - "xterm": "Tyriar/xterm.js#vscode-release/1.13", + "xterm": "Tyriar/xterm.js#vscode-release/1.14", "yauzl": "2.3.1" }, "devDependencies": { diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index d790e964b0cf8..2cd9b78d5ec6c 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -137,7 +137,7 @@ export const focusBorder = registerColor('focusBorder', { dark: Color.fromHex('# export const contrastBorder = registerColor('contrastBorder', { light: null, dark: null, hc: '#6FC3DF' }, nls.localize('contrastBorder', "An extra border around elements to separate them from others for greater contrast.")); export const activeContrastBorder = registerColor('contrastActiveBorder', { light: null, dark: null, hc: focusBorder }, nls.localize('activeContrastBorder', "An extra border around active elements to separate them from others for greater contrast.")); -export const selectionBackground = registerColor('selection.background', { light: null, dark: null, hc: null }, nls.localize('selectionBackground', "The background color of text selections in the workbench (e.g. for input fields or text areas). Note that this does not apply to selections within the editor and the terminal.")); +export const selectionBackground = registerColor('selection.background', { light: null, dark: null, hc: null }, nls.localize('selectionBackground', "The background color of text selections in the workbench (e.g. for input fields or text areas). Note that this does not apply to selections within the editor.")); // ------ text colors diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index 1093b3ee7e075..e2458c190e7e8 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -230,6 +230,11 @@ export interface ITerminalInstance { */ clearSelection(): void; + /** + * Select all text in the terminal. + */ + selectAll(): void; + /** * Focuses the terminal instance. * diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css index 4b6de38e73913..fe96994dcc95e 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css @@ -6,6 +6,7 @@ .monaco-workbench .panel.integrated-terminal .xterm { position: relative; height: 100%; + user-select: none; } .monaco-workbench .panel.integrated-terminal .xterm:focus { @@ -126,6 +127,22 @@ left: -9999em; } +.monaco-workbench .panel.integrated-terminal .xterm.enable-mouse-events { + /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ + cursor: default; +} + +.monaco-workbench .panel.integrated-terminal .xterm .xterm-selection { + position: absolute; + left: 0; + bottom: 0; +} + +.monaco-workbench .panel.integrated-terminal .xterm .xterm-selection div { + position: absolute; + opacity: 0.5; +} + .monaco-workbench .panel.integrated-terminal .xterm .xterm-bold { font-weight: bold; } @@ -157,23 +174,6 @@ display: block; } -/* Base selection colors */ - -.monaco-workbench .panel.integrated-terminal .xterm ::selection { - color: #FFF; - background-color: rgba(51, 51, 51, 0.996); -} - -.vs-dark .monaco-workbench .panel.integrated-terminal .xterm ::selection { - color: #1e1e1e; - background-color: rgba(204, 204, 204, 0.996); -} - -.hc-black .monaco-workbench .panel.integrated-terminal .xterm ::selection { - color: #000; - background-color: rgba(255, 255, 255, 0.996); -} - /* Terminal colors 16-255 */ .monaco-workbench .panel.integrated-terminal .xterm .xterm-color-16 { diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts index 94e7e9a4b5215..84dc99b921274 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -18,7 +18,7 @@ import { TERMINAL_DEFAULT_SHELL_LINUX, TERMINAL_DEFAULT_SHELL_OSX, TERMINAL_DEFA import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, FocusTerminalAtIndexAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; +import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, FocusTerminalAtIndexAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, SelectAllTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; import { Registry } from 'vs/platform/platform'; import { ShowAllCommandsAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; @@ -185,7 +185,8 @@ configurationRegistry.registerConfiguration({ OpenPreviousRecentlyUsedEditorInGroupAction.ID, FocusFirstGroupAction.ID, FocusSecondGroupAction.ID, - FocusThirdGroupAction.ID + FocusThirdGroupAction.ID, + SelectAllTerminalAction.ID ].sort() } } @@ -209,9 +210,7 @@ let actionRegistry = Registry.as(ActionExtensions.Work actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.LABEL), 'Terminal: Kill the Active Terminal Instance', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CopyTerminalSelectionAction, CopyTerminalSelectionAction.ID, CopyTerminalSelectionAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_C, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C }, - // Don't apply to Mac since cmd+c works - mac: { primary: null } + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_C } }, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, KEYBINDING_CONTEXT_TERMINAL_FOCUS)), 'Terminal: Copy Selection', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(CreateNewTerminalAction, CreateNewTerminalAction.ID, CreateNewTerminalAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_BACKTICK, @@ -229,6 +228,15 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TerminalPasteAct // Don't apply to Mac since cmd+v works mac: { primary: null } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Paste into Active Terminal', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectAllTerminalAction, SelectAllTerminalAction.ID, SelectAllTerminalAction.LABEL, { + // Don't use ctrl+a by default as that would override the common go to start + // of prompt shell binding + primary: null, + // Technically this doesn't need to be here as it will fall back to this + // behavior anyway when handed to xterm.js, having this handled by VS Code + // makes it easier for users to see how it works though. + mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_A } +}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select All', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunSelectedTextInTerminalAction, RunSelectedTextInTerminalAction.ID, RunSelectedTextInTerminalAction.LABEL), 'Terminal: Run Selected Text In Active Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RunActiveFileInTerminalAction, RunActiveFileInTerminalAction.ID, RunActiveFileInTerminalAction.LABEL), 'Terminal: Run Active File In Active Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTerminalAction, ToggleTerminalAction.ID, ToggleTerminalAction.LABEL, { diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts index 3b62f9642edb8..62780aee350d1 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts @@ -93,6 +93,27 @@ export class CopyTerminalSelectionAction extends Action { } } +export class SelectAllTerminalAction extends Action { + + public static ID = 'workbench.action.terminal.selectAll'; + public static LABEL = nls.localize('workbench.action.terminal.selectAll', "Select All"); + + constructor( + id: string, label: string, + @ITerminalService private terminalService: ITerminalService + ) { + super(id, label); + } + + public run(event?: any): TPromise { + let terminalInstance = this.terminalService.getActiveInstance(); + if (terminalInstance) { + terminalInstance.selectAll(); + } + return TPromise.as(void 0); + } +} + export class CreateNewTerminalAction extends Action { public static ID = 'workbench.action.terminal.new'; diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 4b70c062ba879..919dd7dbdff23 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -31,7 +31,8 @@ import { TerminalLinkHandler } from 'vs/workbench/parts/terminal/electron-browse import { TerminalWidgetManager } from 'vs/workbench/parts/terminal/browser/terminalWidgetManager'; import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { scrollbarSliderBackground, scrollbarSliderHoverBackground, scrollbarSliderActiveBackground } from 'vs/platform/theme/common/colorRegistry'; -import { TPromise } from "vs/base/common/winjs.base"; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; /** The amount of time to consider terminal errors to be related to the launch */ const LAUNCHING_DURATION = 500; @@ -99,7 +100,8 @@ export class TerminalInstance implements ITerminalInstance { @IPanelService private _panelService: IPanelService, @IWorkspaceContextService private _contextService: IWorkspaceContextService, @IWorkbenchEditorService private _editorService: IWorkbenchEditorService, - @IInstantiationService private _instantiationService: IInstantiationService + @IInstantiationService private _instantiationService: IInstantiationService, + @IClipboardService private _clipboardService: IClipboardService ) { this._instanceDisposables = []; this._processDisposables = []; @@ -323,19 +325,23 @@ export class TerminalInstance implements ITerminalInstance { } public hasSelection(): boolean { - return !document.getSelection().isCollapsed; + return this._xterm.hasSelection(); } public copySelection(): void { - if (document.activeElement.classList.contains('xterm')) { - document.execCommand('copy'); + if (this.hasSelection()) { + this._clipboardService.writeText(this._xterm.getSelection()); } else { - this._messageService.show(Severity.Warning, nls.localize('terminal.integrated.copySelection.noSelection', 'Cannot copy terminal selection when terminal does not have focus')); + this._messageService.show(Severity.Warning, nls.localize('terminal.integrated.copySelection.noSelection', 'The terminal has no selection to copy')); } } public clearSelection(): void { - window.getSelection().empty(); + this._xterm.clearSelection(); + } + + public selectAll(): void { + this._xterm.selectAll(); } public dispose(): void { @@ -439,8 +445,8 @@ export class TerminalInstance implements ITerminalInstance { private _refreshSelectionContextKey() { const activePanel = this._panelService.getActivePanel(); - const isFocused = activePanel && activePanel.getId() === TERMINAL_PANEL_ID; - this._terminalHasTextContextKey.set(isFocused && !window.getSelection().isCollapsed); + const isActive = activePanel && activePanel.getId() === TERMINAL_PANEL_ID; + this._terminalHasTextContextKey.set(isActive && this.hasSelection()); } private _sanitizeInput(data: any) { diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index c3e600af19dda..dc7558d33e91c 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -16,7 +16,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITerminalService, ITerminalFont, TERMINAL_PANEL_ID } from 'vs/workbench/parts/terminal/common/terminal'; import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_FOREGROUND_COLOR } from './terminalColorRegistry'; -import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; +import { ColorIdentifier, selectionBackground } from 'vs/platform/theme/common/colorRegistry'; import { KillTerminalAction, CreateNewTerminalAction, SwitchTerminalInstanceAction, SwitchTerminalInstanceActionItem, CopyTerminalSelectionAction, TerminalPasteAction, ClearTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions'; import { Panel } from 'vs/workbench/browser/panel'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; @@ -243,13 +243,8 @@ export class TerminalPanel extends Panel { ansiColorIdentifiers.forEach((colorId: ColorIdentifier, index: number) => { if (colorId) { // should not happen, all indices should have a color defined. let color = theme.getColor(colorId); - let rgba = color.transparent(0.996); css += `.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-${index} { color: ${color}; }` + - `.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-${index}::selection,` + - `.monaco-workbench .panel.integrated-terminal .xterm .xterm-color-${index} *::selection { background-color: ${rgba}; }` + - `.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-${index} { background-color: ${color}; }` + - `.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-${index}::selection,` + - `.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-${index} *::selection { color: ${color}; }`; + `.monaco-workbench .panel.integrated-terminal .xterm .xterm-bg-color-${index} { background-color: ${color}; }`; } }); const bgColor = theme.getColor(TERMINAL_BACKGROUND_COLOR); @@ -267,6 +262,12 @@ export class TerminalPanel extends Panel { `.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-bar.focus.xterm-cursor-blink .terminal-cursor::before,` + `.monaco-workbench .panel.integrated-terminal .xterm.xterm-cursor-style-underline.focus.xterm-cursor-blink .terminal-cursor::before { background-color: ${fgColor}; }`; } + // Use selection.background as the terminal selection, this is temporary + // until proper color inverting is implemented to ensure contrast. + const selectionColor = theme.getColor(selectionBackground); + if (selectionColor) { + css += `.monaco-workbench .panel.integrated-terminal .xterm .xterm-selection div { background-color: ${selectionColor}; }`; + } this._themeStyleElement.innerHTML = css; }