From 17ea00ea442b951f9b1b6bd910d4dd70a2b7022d Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 25 May 2017 00:00:54 +0200 Subject: [PATCH] Implement editor.multicursorModifier --- src/vs/editor/browser/view/viewController.ts | 99 +++++++++---------- src/vs/editor/browser/view/viewImpl.ts | 2 +- .../browser/clickLinkGesture.ts | 63 ++++++++++-- .../browser/goToDeclarationMouse.ts | 13 +-- src/vs/editor/contrib/hover/browser/hover.ts | 3 +- src/vs/editor/contrib/links/browser/links.ts | 11 +-- 6 files changed, 110 insertions(+), 81 deletions(-) diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index f37a97d9344..e05ca74ea60 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -12,6 +12,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents'; import { CoreNavigationCommands, CoreEditorCommand } from 'vs/editor/common/controller/coreCommands'; +import { Configuration } from "vs/editor/browser/config/configuration"; export interface ExecCoreEditorCommandFunc { (editorCommand: CoreEditorCommand, args: any): void; @@ -35,17 +36,20 @@ export interface IMouseDispatchData { export class ViewController { + private readonly configuration: Configuration; private readonly viewModel: IViewModel; private readonly _execCoreEditorCommandFunc: ExecCoreEditorCommandFunc; private readonly outgoingEvents: ViewOutgoingEvents; private readonly commandService: ICommandService; constructor( + configuration: Configuration, viewModel: IViewModel, execCommandFunc: ExecCoreEditorCommandFunc, outgoingEvents: ViewOutgoingEvents, commandService: ICommandService ) { + this.configuration = configuration; this.viewModel = viewModel; this._execCoreEditorCommandFunc = execCommandFunc; this.outgoingEvents = outgoingEvents; @@ -97,10 +101,34 @@ export class ViewController { return viewPosition; } + private _hasMulticursorModifier(data: IMouseDispatchData): boolean { + switch (this.configuration.editor.multicursorModifier) { + case 'altKey': + return data.altKey; + case 'ctrlKey': + return data.ctrlKey; + case 'metaKey': + return data.metaKey; + } + return false; + } + + private _hasNonMulticursorModifier(data: IMouseDispatchData): boolean { + switch (this.configuration.editor.multicursorModifier) { + case 'altKey': + return data.ctrlKey || data.metaKey; + case 'ctrlKey': + return data.altKey || data.metaKey; + case 'metaKey': + return data.ctrlKey || data.altKey; + } + return false; + } + public dispatchMouse(data: IMouseDispatchData): void { if (data.startedOnLineNumbers) { // If the dragging started on the gutter, then have operations work on the entire line - if (data.altKey) { + if (this._hasMulticursorModifier(data)) { if (data.inSelectionMode) { this.lastCursorLineSelect(data.position); } else { @@ -116,7 +144,7 @@ export class ViewController { } else if (data.mouseDownCount >= 4) { this.selectAll(); } else if (data.mouseDownCount === 3) { - if (data.altKey) { + if (this._hasMulticursorModifier(data)) { if (data.inSelectionMode) { this.lastCursorLineSelectDrag(data.position); } else { @@ -130,7 +158,7 @@ export class ViewController { } } } else if (data.mouseDownCount === 2) { - if (data.altKey) { + if (this._hasMulticursorModifier(data)) { this.lastCursorWordSelect(data.position); } else { if (data.inSelectionMode) { @@ -140,8 +168,8 @@ export class ViewController { } } } else { - if (data.altKey) { - if (!data.ctrlKey && !data.metaKey) { + if (this._hasMulticursorModifier(data)) { + if (!this._hasNonMulticursorModifier(data)) { if (data.shiftKey) { this.columnSelect(data.position, data.mouseColumn); } else { @@ -163,20 +191,20 @@ export class ViewController { } } - public moveTo(viewPosition: Position): void { + private _usualArgs(viewPosition: Position) { viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.MoveTo, { + return { position: this.convertViewToModelPosition(viewPosition), viewPosition: viewPosition - }); + }; + } + + public moveTo(viewPosition: Position): void { + this._execMouseCommand(CoreNavigationCommands.MoveTo, this._usualArgs(viewPosition)); } private moveToSelect(viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.MoveToSelect, { - position: this.convertViewToModelPosition(viewPosition), - viewPosition: viewPosition - }); + this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition)); } private columnSelect(viewPosition: Position, mouseColumn: number): void { @@ -198,64 +226,35 @@ export class ViewController { } private lastCursorMoveToSelect(viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.LastCursorMoveToSelect, { - position: this.convertViewToModelPosition(viewPosition), - viewPosition: viewPosition - }); + this._execMouseCommand(CoreNavigationCommands.LastCursorMoveToSelect, this._usualArgs(viewPosition)); } private wordSelect(viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.WordSelect, { - position: this.convertViewToModelPosition(viewPosition) - }); + this._execMouseCommand(CoreNavigationCommands.WordSelect, this._usualArgs(viewPosition)); } private wordSelectDrag(viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.WordSelectDrag, { - position: this.convertViewToModelPosition(viewPosition) - }); + this._execMouseCommand(CoreNavigationCommands.WordSelectDrag, this._usualArgs(viewPosition)); } private lastCursorWordSelect(viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.LastCursorWordSelect, { - position: this.convertViewToModelPosition(viewPosition) - }); + this._execMouseCommand(CoreNavigationCommands.LastCursorWordSelect, this._usualArgs(viewPosition)); } private lineSelect(viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.LineSelect, { - position: this.convertViewToModelPosition(viewPosition), - viewPosition: viewPosition - }); + this._execMouseCommand(CoreNavigationCommands.LineSelect, this._usualArgs(viewPosition)); } private lineSelectDrag(viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.LineSelectDrag, { - position: this.convertViewToModelPosition(viewPosition), - viewPosition: viewPosition - }); + this._execMouseCommand(CoreNavigationCommands.LineSelectDrag, this._usualArgs(viewPosition)); } private lastCursorLineSelect(viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelect, { - position: this.convertViewToModelPosition(viewPosition), - viewPosition: viewPosition - }); + this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelect, this._usualArgs(viewPosition)); } private lastCursorLineSelectDrag(viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelectDrag, { - position: this.convertViewToModelPosition(viewPosition), - viewPosition: viewPosition - }); + this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelectDrag, this._usualArgs(viewPosition)); } private selectAll(): void { diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 321c4719a6d..927c1d19486 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -105,7 +105,7 @@ export class View extends ViewEventHandler { this._renderAnimationFrame = null; this.outgoingEvents = new ViewOutgoingEvents(model); - let viewController = new ViewController(model, execCoreEditorCommandFunc, this.outgoingEvents, commandService); + let viewController = new ViewController(configuration, model, execCoreEditorCommandFunc, this.outgoingEvents, commandService); // The event dispatcher will always go through _renderOnce before dispatching any events this.eventDispatcher = new ViewEventDispatcher((callback: () => void) => this._renderOnce(callback)); diff --git a/src/vs/editor/contrib/goToDeclaration/browser/clickLinkGesture.ts b/src/vs/editor/contrib/goToDeclaration/browser/clickLinkGesture.ts index bec68dcf19a..79d1043cf50 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/clickLinkGesture.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/clickLinkGesture.ts @@ -13,6 +13,11 @@ import { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/ import { Disposable } from 'vs/base/common/lifecycle'; import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import Event, { Emitter } from 'vs/base/common/event'; +import * as platform from 'vs/base/common/platform'; + +function hasModifier(e: { ctrlKey: boolean; shiftKey: boolean; altKey: boolean; metaKey: boolean }, modifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey'): boolean { + return !!e[modifier]; +} /** * An event that encapsulates the various trigger modifiers logic needed for go to definition. @@ -26,8 +31,8 @@ export class ClickLinkMouseEvent { constructor(source: IEditorMouseEvent, opts: ClickLinkOptions) { this.target = source.target; - this.hasTriggerModifier = !!source.event[opts.triggerModifier]; - this.hasSideBySideModifier = source.event.altKey; + this.hasTriggerModifier = hasModifier(source.event, opts.triggerModifier); + this.hasSideBySideModifier = hasModifier(source.event, opts.triggerSideBySideModifier); this.isNoneOrSingleMouseDown = (browser.isIE || source.event.detail <= 1); // IE does not support event.detail properly } } @@ -44,7 +49,7 @@ export class ClickLinkKeyboardEvent { constructor(source: IKeyboardEvent, opts: ClickLinkOptions) { this.keyCodeIsTriggerKey = (source.keyCode === opts.triggerKey); this.keyCodeIsSideBySideKey = (source.keyCode === opts.triggerSideBySideKey); - this.hasTriggerModifier = !!source[opts.triggerModifier]; + this.hasTriggerModifier = hasModifier(source, opts.triggerModifier); } } @@ -53,14 +58,44 @@ export class ClickLinkOptions { public readonly triggerKey: KeyCode; public readonly triggerModifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey'; public readonly triggerSideBySideKey: KeyCode; - - constructor(triggerKey: KeyCode, triggerModifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey', triggerSideBySideKey: KeyCode) { + public readonly triggerSideBySideModifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey'; + + constructor( + triggerKey: KeyCode, + triggerModifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey', + triggerSideBySideKey: KeyCode, + triggerSideBySideModifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey' + ) { this.triggerKey = triggerKey; this.triggerModifier = triggerModifier; this.triggerSideBySideKey = triggerSideBySideKey; + this.triggerSideBySideModifier = triggerSideBySideModifier; + } + + public equals(other: ClickLinkOptions): boolean { + return ( + this.triggerKey === other.triggerKey + && this.triggerModifier === other.triggerModifier + && this.triggerSideBySideKey === other.triggerSideBySideKey + && this.triggerSideBySideModifier === other.triggerSideBySideModifier + ); } } +function createOptions(multicursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'): ClickLinkOptions { + if (multicursorModifier === 'altKey') { + if (platform.isMacintosh) { + return new ClickLinkOptions(KeyCode.Meta, 'metaKey', KeyCode.Alt, 'altKey'); + } + return new ClickLinkOptions(KeyCode.Ctrl, 'ctrlKey', KeyCode.Alt, 'altKey'); + } + + if (platform.isMacintosh) { + return new ClickLinkOptions(KeyCode.Alt, 'altKey', KeyCode.Meta, 'metaKey'); + } + return new ClickLinkOptions(KeyCode.Alt, 'altKey', KeyCode.Ctrl, 'ctrlKey'); +} + export class ClickLinkGesture extends Disposable { private readonly _onMouseMoveOrRelevantKeyDown: Emitter<[ClickLinkMouseEvent, ClickLinkKeyboardEvent]> = this._register(new Emitter<[ClickLinkMouseEvent, ClickLinkKeyboardEvent]>()); @@ -73,20 +108,32 @@ export class ClickLinkGesture extends Disposable { public readonly onCancel: Event = this._onCancel.event; private readonly _editor: ICodeEditor; - private readonly _opts: ClickLinkOptions; + private _opts: ClickLinkOptions; private lastMouseMoveEvent: ClickLinkMouseEvent; private hasTriggerKeyOnMouseDown: boolean; - constructor(editor: ICodeEditor, opts: ClickLinkOptions) { + constructor(editor: ICodeEditor) { super(); this._editor = editor; - this._opts = opts; + this._opts = createOptions(this._editor.getConfiguration().multicursorModifier); this.lastMouseMoveEvent = null; this.hasTriggerKeyOnMouseDown = false; + this._register(this._editor.onDidChangeConfiguration((e) => { + if (e.multicursorModifier) { + const newOpts = createOptions(this._editor.getConfiguration().multicursorModifier); + if (this._opts.equals(newOpts)) { + return; + } + this._opts = newOpts; + this.lastMouseMoveEvent = null; + this.hasTriggerKeyOnMouseDown = false; + this._onCancel.fire(); + } + })); this._register(this._editor.onMouseMove((e: IEditorMouseEvent) => this.onEditorMouseMove(new ClickLinkMouseEvent(e, this._opts)))); this._register(this._editor.onMouseDown((e: IEditorMouseEvent) => this.onEditorMouseDown(new ClickLinkMouseEvent(e, this._opts)))); this._register(this._editor.onMouseUp((e: IEditorMouseEvent) => this.onEditorMouseUp(new ClickLinkMouseEvent(e, this._opts)))); diff --git a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationMouse.ts b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationMouse.ts index e063801f2d9..a29f1511b44 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationMouse.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclarationMouse.ts @@ -10,8 +10,6 @@ import * as nls from 'vs/nls'; import { Throttler } from 'vs/base/common/async'; import { onUnexpectedError } from 'vs/base/common/errors'; import { MarkedString } from 'vs/base/common/htmlContent'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import * as platform from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; import { IModeService } from 'vs/editor/common/services/modeService'; import { Range } from 'vs/editor/common/core/range'; @@ -26,15 +24,12 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { EditorState, CodeEditorStateFlag } from 'vs/editor/common/core/editorState'; import { DefinitionAction, DefinitionActionConfig } from './goToDeclarationCommands'; -import { ClickLinkGesture, ClickLinkOptions, ClickLinkMouseEvent, ClickLinkKeyboardEvent } from "vs/editor/contrib/goToDeclaration/browser/clickLinkGesture"; +import { ClickLinkGesture, ClickLinkMouseEvent, ClickLinkKeyboardEvent } from "vs/editor/contrib/goToDeclaration/browser/clickLinkGesture"; @editorContribution class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorContribution { private static ID = 'editor.contrib.gotodefinitionwithmouse'; - static TRIGGER_MODIFIER: 'metaKey' | 'ctrlKey' = platform.isMacintosh ? 'metaKey' : 'ctrlKey'; - static TRIGGER_SIDEBYSIDE_KEY_VALUE = KeyCode.Alt; - static TRIGGER_KEY_VALUE = platform.isMacintosh ? KeyCode.Meta : KeyCode.Ctrl; static MAX_SOURCE_PREVIEW_LINES = 8; private editor: ICodeEditor; @@ -53,11 +48,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC this.editor = editor; this.throttler = new Throttler(); - let linkGesture = new ClickLinkGesture(editor, new ClickLinkOptions( - GotoDefinitionWithMouseEditorContribution.TRIGGER_KEY_VALUE, - GotoDefinitionWithMouseEditorContribution.TRIGGER_MODIFIER, - GotoDefinitionWithMouseEditorContribution.TRIGGER_SIDEBYSIDE_KEY_VALUE - )); + let linkGesture = new ClickLinkGesture(editor); this.toUnhook.push(linkGesture); this.toUnhook.push(linkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => { diff --git a/src/vs/editor/contrib/hover/browser/hover.ts b/src/vs/editor/contrib/hover/browser/hover.ts index 7660cff426e..b0229e73f1b 100644 --- a/src/vs/editor/contrib/hover/browser/hover.ts +++ b/src/vs/editor/contrib/hover/browser/hover.ts @@ -112,8 +112,7 @@ export class ModesHoverController implements editorCommon.IEditorContribution { } private _onKeyDown(e: IKeyboardEvent): void { - var stopKey = platform.isMacintosh ? KeyCode.Meta : KeyCode.Ctrl; - if (e.keyCode !== stopKey) { + if (e.keyCode !== KeyCode.Ctrl && e.keyCode !== KeyCode.Alt && e.keyCode !== KeyCode.Meta) { // Do not hide hover when Ctrl/Meta is pressed this._hideWidgets(); } diff --git a/src/vs/editor/contrib/links/browser/links.ts b/src/vs/editor/contrib/links/browser/links.ts index c14eaf2d911..58808a66a34 100644 --- a/src/vs/editor/contrib/links/browser/links.ts +++ b/src/vs/editor/contrib/links/browser/links.ts @@ -8,7 +8,6 @@ import 'vs/css!./links'; import * as nls from 'vs/nls'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { KeyCode } from 'vs/base/common/keyCodes'; import * as platform from 'vs/base/common/platform'; import Severity from 'vs/base/common/severity'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -26,7 +25,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { Position } from 'vs/editor/common/core/position'; import { ModelDecorationOptions } from "vs/editor/common/model/textModelWithDecorations"; -import { ClickLinkGesture, ClickLinkOptions, ClickLinkMouseEvent, ClickLinkKeyboardEvent } from "vs/editor/contrib/goToDeclaration/browser/clickLinkGesture"; +import { ClickLinkGesture, ClickLinkMouseEvent, ClickLinkKeyboardEvent } from "vs/editor/contrib/goToDeclaration/browser/clickLinkGesture"; const HOVER_MESSAGE_GENERAL = ( platform.isMacintosh @@ -91,8 +90,6 @@ class LinkDetector implements editorCommon.IEditorContribution { } static RECOMPUTE_TIME = 1000; // ms - static TRIGGER_KEY_VALUE = platform.isMacintosh ? KeyCode.Meta : KeyCode.Ctrl; - static TRIGGER_MODIFIER: 'metaKey' | 'ctrlKey' = platform.isMacintosh ? 'metaKey' : 'ctrlKey'; private editor: ICodeEditor; private listenersToRemove: IDisposable[]; @@ -116,11 +113,7 @@ class LinkDetector implements editorCommon.IEditorContribution { this.editorWorkerService = editorWorkerService; this.listenersToRemove = []; - let clickLinkGesture = new ClickLinkGesture(editor, new ClickLinkOptions( - LinkDetector.TRIGGER_KEY_VALUE, - LinkDetector.TRIGGER_MODIFIER, - KeyCode.Alt - )); + let clickLinkGesture = new ClickLinkGesture(editor); this.listenersToRemove.push(clickLinkGesture); this.listenersToRemove.push(clickLinkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => { this._onEditorMouseMove(mouseEvent, keyboardEvent); -- GitLab