提交 17ea00ea 编写于 作者: A Alex Dima 提交者: Dirk Baeumer

Implement editor.multicursorModifier

上级 bf4d419b
......@@ -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 {
......
......@@ -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));
......
......@@ -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<void> = 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))));
......
......@@ -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]) => {
......
......@@ -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();
}
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册