diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index 630dc94ce89..cd6e72a3d9a 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -19,6 +19,8 @@ export const TERMINAL_DEFAULT_SHELL_LINUX = !platform.isWindows ? (process.env.S export const TERMINAL_DEFAULT_SHELL_OSX = !platform.isWindows ? (process.env.SHELL || 'sh') : 'sh'; export const TERMINAL_DEFAULT_SHELL_WINDOWS = processes.getWindowsShell(); +export const TERMINAL_DEFAULT_RIGHT_CLICK_COPY_PASTE = platform.isWindows; + /** A context key that is set when the integrated terminal has focus. */ export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey('terminalFocus', undefined); /** A context key that is set when the integrated terminal does not have focus. */ @@ -44,6 +46,7 @@ export interface ITerminalConfiguration { osx: string[], windows: string[] }, + rightClickCopyPaste: boolean, cursorBlinking: boolean, fontFamily: string, fontLigatures: boolean, @@ -62,6 +65,7 @@ export interface ITerminalConfigHelper { getFont(): ITerminalFont; getFontLigaturesEnabled(): boolean; getCursorBlink(): boolean; + getRightClickCopyPaste(): boolean; getCommandsToSkipShell(): string[]; getScrollback(): number; getCwd(): string; @@ -146,11 +150,21 @@ export interface ITerminalInstance { */ dispose(): void; + /** + * Check if anything is selected in terminal. + */ + hasSelection(): boolean; + /** * Copies the terminal selection to the clipboard. */ copySelection(): void; + /** + * Clear current selection. + */ + clearSelection(): void; + /** * Focuses the terminal instance. * 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 69e4620b875..f4fee11ede3 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.contribution.ts @@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform'; import nls = require('vs/nls'); import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { GlobalQuickOpenAction } from 'vs/workbench/browser/parts/quickopen/quickopen.contribution'; -import { ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, TERMINAL_DEFAULT_SHELL_LINUX, TERMINAL_DEFAULT_SHELL_OSX, TERMINAL_DEFAULT_SHELL_WINDOWS } from 'vs/workbench/parts/terminal/common/terminal'; +import { ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, TERMINAL_DEFAULT_SHELL_LINUX, TERMINAL_DEFAULT_SHELL_OSX, TERMINAL_DEFAULT_SHELL_WINDOWS, TERMINAL_DEFAULT_RIGHT_CLICK_COPY_PASTE } from 'vs/workbench/parts/terminal/common/terminal'; 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'; @@ -73,6 +73,11 @@ configurationRegistry.registerConfiguration({ }, 'default': [] }, + 'terminal.integrated.rightClickCopyPaste': { + 'description': nls.localize('terminal.integrated.rightClickCopyPaste', "When set, this will prevent the context menu from appearing when right clicking within the terminal, instead it will copy when there is a selection and paste when there is no selection."), + 'type': 'boolean', + 'default': TERMINAL_DEFAULT_RIGHT_CLICK_COPY_PASTE + }, 'terminal.integrated.fontFamily': { 'description': nls.localize('terminal.integrated.fontFamily', "Controls the font family of the terminal, this defaults to editor.fontFamily's value."), 'type': 'string' diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts index cbaacda3391..c0949423672 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalActions.ts @@ -57,7 +57,7 @@ export class KillTerminalAction extends Action { /** * Copies the terminal selection. Note that since the command palette takes focus from the terminal, - * this can only be triggered via a keybinding. + * this cannot be triggered through the command palette. */ export class CopyTerminalSelectionAction extends Action { diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts index 7ab53353ef0..113024a23db 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts @@ -138,6 +138,11 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { return terminalConfig.cursorBlinking; } + public getRightClickCopyPaste(): boolean { + let config = this._configurationService.getConfiguration(); + return config.terminal.integrated.rightClickCopyPaste; + } + public getShell(): IShell { let config = this._configurationService.getConfiguration(); let shell: IShell = { diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 5f059610f11..6121cc1c58c 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -195,6 +195,10 @@ export class TerminalInstance implements ITerminalInstance { this.updateConfig(); } + public hasSelection(): boolean { + return !document.getSelection().isCollapsed; + } + public copySelection(): void { if (document.activeElement.classList.contains('xterm')) { document.execCommand('copy'); @@ -203,6 +207,10 @@ export class TerminalInstance implements ITerminalInstance { } } + public clearSelection(): void { + document.getSelection().empty(); + } + public dispose(): void { this._isExiting = true; diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index 3be638f8530..04a0539758b 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -149,25 +149,30 @@ export class TerminalPanel extends Panel { // occurs on the selection itself. this._terminalService.getActiveInstance().focus(); } else if (event.which === 3) { - // Trigger the context menu on right click - let anchor: HTMLElement | { x: number, y: number } = this._parentDomElement; - if (event instanceof MouseEvent) { - const standardEvent = new StandardMouseEvent(event); - anchor = { x: standardEvent.posx, y: standardEvent.posy }; - } - - this._contextMenuService.showContextMenu({ - getAnchor: () => anchor, - getActions: () => TPromise.as(this._getContextMenuActions()), - getActionsContext: () => this._parentDomElement, - getKeyBinding: (action) => { - const opts = this._keybindingService.lookupKeybindings(action.id); - if (opts.length > 0) { - return opts[0]; // only take the first one - } - return null; + if (this._terminalService.configHelper.getRightClickCopyPaste()) { + let terminal = this._terminalService.getActiveInstance(); + if (terminal.hasSelection()) { + terminal.copySelection(); + terminal.clearSelection(); + } else { + terminal.paste(); } - }); + } else { + const standardEvent = new StandardMouseEvent(event); + let anchor: { x: number, y: number } = { x: standardEvent.posx, y: standardEvent.posy }; + this._contextMenuService.showContextMenu({ + getAnchor: () => anchor, + getActions: () => TPromise.as(this._getContextMenuActions()), + getActionsContext: () => this._parentDomElement, + getKeyBinding: (action) => { + const opts = this._keybindingService.lookupKeybindings(action.id); + if (opts.length > 0) { + return opts[0]; // only take the first one + } + return null; + } + }); + } } })); this._register(DOM.addDisposableListener(this._parentDomElement, 'click', (event) => {