goToDeclaration.ts 17.7 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import 'vs/css!./goToDeclaration';
A
Alex Dima 已提交
9
import * as nls from 'vs/nls';
A
Alex Dima 已提交
10 11
import {Throttler} from 'vs/base/common/async';
import {onUnexpectedError} from 'vs/base/common/errors';
12
import {MarkedString, textToMarkedString} from 'vs/base/common/htmlContent';
A
Alex Dima 已提交
13 14
import {KeyCode, KeyMod} from 'vs/base/common/keyCodes';
import * as platform from 'vs/base/common/platform';
E
Erich Gamma 已提交
15
import Severity from 'vs/base/common/severity';
A
Alex Dima 已提交
16
import * as strings from 'vs/base/common/strings';
E
Erich Gamma 已提交
17
import {TPromise} from 'vs/base/common/winjs.base';
A
Alex Dima 已提交
18 19 20 21 22
import * as browser from 'vs/base/browser/browser';
import {IKeyboardEvent} from 'vs/base/browser/keyboardEvent';
import {IEditorService} from 'vs/platform/editor/common/editor';
import {IMessageService} from 'vs/platform/message/common/message';
import {Range} from 'vs/editor/common/core/range';
A
Alex Dima 已提交
23 24
import {EditorAction} from 'vs/editor/common/editorAction';
import {Behaviour} from 'vs/editor/common/editorActionEnablement';
A
Alex Dima 已提交
25 26
import * as editorCommon from 'vs/editor/common/editorCommon';
import {CommonEditorRegistry, ContextKey, EditorActionDescriptor} from 'vs/editor/common/editorCommonExtensions';
27
import {Location, DefinitionProviderRegistry} from 'vs/editor/common/modes';
A
Alex Dima 已提交
28 29
import {ICodeEditor, IEditorMouseEvent, IMouseTarget} from 'vs/editor/browser/editorBrowser';
import {EditorBrowserRegistry} from 'vs/editor/browser/editorBrowserExtensions';
30
import {getDeclarationsAtPosition} from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
31
import {ReferencesController} from 'vs/editor/contrib/referenceSearch/browser/referencesController';
32
import {ReferencesModel} from 'vs/editor/contrib/referenceSearch/browser/referencesModel';
A
Alex Dima 已提交
33
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
34 35 36
import {IPeekViewService} from 'vs/editor/contrib/zoneWidget/browser/peekViewWidget';
import {optional} from 'vs/platform/instantiation/common/instantiation';

E
Erich Gamma 已提交
37

J
Johannes Rieken 已提交
38
export class DefinitionActionConfig {
E
Erich Gamma 已提交
39

40
	constructor(
41 42 43 44
		public condition = Behaviour.WidgetFocus | Behaviour.ShowInContextMenu | Behaviour.UpdateOnCursorPositionChange,
		public openToSide = false,
		public openInPeek = false,
		public filterCurrent = true
45
	) {
46
		//
E
Erich Gamma 已提交
47 48 49
	}
}

50
export class DefinitionAction extends EditorAction {
E
Erich Gamma 已提交
51

52
	constructor(
A
Alex Dima 已提交
53 54
		descriptor: editorCommon.IEditorActionDescriptorData,
		editor: editorCommon.ICommonCodeEditor,
55 56
		private _messageService: IMessageService,
		private _editorService: IEditorService,
J
Johannes Rieken 已提交
57
		private _configuration: DefinitionActionConfig
58
	) {
59
		super(descriptor, editor, _configuration.condition);
E
Erich Gamma 已提交
60 61 62
	}

	public getGroupId(): string {
63
		return '1_goto/2_visitDefinition';
E
Erich Gamma 已提交
64 65
	}

66
	public isSupported(): boolean {
67
		return DefinitionProviderRegistry.has(this.editor.getModel()) && super.isSupported();
E
Erich Gamma 已提交
68 69
	}

70 71
	public getEnablementState(): boolean {
		if (!super.getEnablementState()) {
E
Erich Gamma 已提交
72 73
			return false;
		}
74

75
		return DefinitionProviderRegistry.has(this.editor.getModel());
E
Erich Gamma 已提交
76 77
	}

78
	public run(): TPromise<any> {
E
Erich Gamma 已提交
79

80 81
		let model = this.editor.getModel();
		let pos = this.editor.getPosition();
E
Erich Gamma 已提交
82

83
		return getDeclarationsAtPosition(model, pos).then(references => {
E
Erich Gamma 已提交
84

85 86 87
			if (!references) {
				return;
			}
E
Erich Gamma 已提交
88

89 90 91
			// * remove falsy references
			// * remove reference at the current pos
			// * collapse ranges to start pos
92
			let result: Location[] = [];
93 94 95 96 97
			for (let i = 0; i < references.length; i++) {
				let reference = references[i];
				if (!reference) {
					continue;
				}
98
				let {uri, range} = reference;
99
				if (!this._configuration.filterCurrent
100
					|| uri.toString() !== model.uri.toString()
101 102 103
					|| !Range.containsPosition(range, pos)) {

					result.push({
104
						uri,
105 106 107 108
						range: Range.collapseToStart(range)
					});
				}
			}
E
Erich Gamma 已提交
109

110 111 112
			if (result.length === 0) {
				return;
			}
E
Erich Gamma 已提交
113

114
			return this._onResult(new ReferencesModel(result));
E
Erich Gamma 已提交
115

116 117 118 119
		}, (err) => {
			// report an error
			this._messageService.show(Severity.Error, err);
			return false;
E
Erich Gamma 已提交
120 121 122
		});
	}

123
	private _onResult(model: ReferencesModel) {
124
		if (this._configuration.openInPeek) {
125
			this._openInPeek(this.editor, model);
126
		} else {
127 128 129 130
			let next = model.nearestReference(this.editor.getModel().uri, this.editor.getPosition());
			this._openReference(next, this._configuration.openToSide).then(editor => {
				if (model.references.length > 1) {
					this._openInPeek(editor, model);
131 132 133 134 135
				}
			});
		}
	}

136 137 138
	private _openReference(reference: Location, sideBySide: boolean): TPromise<editorCommon.ICommonCodeEditor>{
		let {uri, range} = reference;
		return this._editorService.openEditor({ resource:uri, options: { selection: range } }, sideBySide).then(editor => {
139 140 141
			return <editorCommon.IEditor> editor.getControl();
		});
	}
142

143
	private _openInPeek(target: editorCommon.ICommonCodeEditor, model: ReferencesModel) {
144
		let controller = ReferencesController.getController(target);
145
		controller.toggleWidget(target.getSelection(), TPromise.as(model), {
146 147
			getMetaTitle: (model) => {
				return model.references.length > 1 && nls.localize('meta.title', " – {0} definitions", model.references.length);
148 149
			},
			onGoto: (reference) => {
150
				controller.closeWidget();
151 152 153
				return this._openReference(reference, false);
			}
		});
E
Erich Gamma 已提交
154 155 156
	}
}

157
export class GoToDefinitionAction extends DefinitionAction {
158

159
	public static ID = 'editor.action.goToDeclaration';
160 161

	constructor(
A
Alex Dima 已提交
162 163
		descriptor: editorCommon.IEditorActionDescriptorData,
		editor: editorCommon.ICommonCodeEditor,
164 165 166
		@IMessageService messageService: IMessageService,
		@IEditorService editorService: IEditorService
	) {
J
Johannes Rieken 已提交
167
		super(descriptor, editor, messageService, editorService, new DefinitionActionConfig());
168
	}
169

170 171
}

172
export class OpenDefinitionToSideAction extends DefinitionAction {
173

174 175 176 177 178 179 180 181
	public static ID = 'editor.action.openDeclarationToTheSide';

	constructor(
		descriptor: editorCommon.IEditorActionDescriptorData,
		editor: editorCommon.ICommonCodeEditor,
		@IMessageService messageService: IMessageService,
		@IEditorService editorService: IEditorService
	) {
J
Johannes Rieken 已提交
182
		super(descriptor, editor, messageService, editorService, new DefinitionActionConfig(Behaviour.WidgetFocus | Behaviour.UpdateOnCursorPositionChange, true));
183 184 185
	}
}

186
export class PeekDefinitionAction extends DefinitionAction {
E
Erich Gamma 已提交
187 188 189

	public static ID = 'editor.action.previewDeclaration';

190
	constructor(
A
Alex Dima 已提交
191 192
		descriptor: editorCommon.IEditorActionDescriptorData,
		editor: editorCommon.ICommonCodeEditor,
E
Erich Gamma 已提交
193
		@IMessageService messageService: IMessageService,
194 195
		@IEditorService editorService: IEditorService,
		@optional(IPeekViewService) private _peekViewService: IPeekViewService
196
	) {
J
Johannes Rieken 已提交
197
		super(descriptor, editor, messageService, editorService, new DefinitionActionConfig(void 0, void 0, true, false));
E
Erich Gamma 已提交
198
	}
199 200 201 202 203

	getEnablementState(): boolean {
		return (!this._peekViewService || !this._peekViewService.isActive)
			&& super.getEnablementState();
	}
E
Erich Gamma 已提交
204 205 206 207
}

// --- Editor Contribution to goto definition using the mouse and a modifier key

A
Alex Dima 已提交
208
class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorContribution {
E
Erich Gamma 已提交
209 210

	static ID = 'editor.contrib.gotodefinitionwithmouse';
A
Alex Dima 已提交
211
	static TRIGGER_MODIFIER = platform.isMacintosh ? 'metaKey' : 'ctrlKey';
212
	static TRIGGER_SIDEBYSIDE_KEY_VALUE = KeyCode.Alt;
A
Alex Dima 已提交
213
	static TRIGGER_KEY_VALUE = platform.isMacintosh ? KeyCode.Meta : KeyCode.Ctrl;
E
Erich Gamma 已提交
214 215
	static MAX_SOURCE_PREVIEW_LINES = 7;

A
Alex Dima 已提交
216
	private editor: ICodeEditor;
A
Alex Dima 已提交
217
	private toUnhook: IDisposable[];
218
	private decorations: string[];
A
Alex Dima 已提交
219 220 221
	private currentWordUnderMouse: editorCommon.IWordAtPosition;
	private throttler: Throttler;
	private lastMouseMoveEvent: IEditorMouseEvent;
222
	private hasTriggerKeyOnMouseDown: boolean;
E
Erich Gamma 已提交
223

224
	constructor(
A
Alex Dima 已提交
225
		editor: ICodeEditor,
226 227
		@IEditorService private editorService: IEditorService
	) {
E
Erich Gamma 已提交
228 229 230
		this.toUnhook = [];
		this.decorations = [];
		this.editor = editor;
A
Alex Dima 已提交
231
		this.throttler = new Throttler();
E
Erich Gamma 已提交
232

A
Alex Dima 已提交
233 234 235 236 237 238
		this.toUnhook.push(this.editor.onMouseDown((e: IEditorMouseEvent) => this.onEditorMouseDown(e)));
		this.toUnhook.push(this.editor.onMouseUp((e: IEditorMouseEvent) => this.onEditorMouseUp(e)));
		this.toUnhook.push(this.editor.onMouseMove((e: IEditorMouseEvent) => this.onEditorMouseMove(e)));
		this.toUnhook.push(this.editor.onKeyDown((e: IKeyboardEvent) => this.onEditorKeyDown(e)));
		this.toUnhook.push(this.editor.onKeyUp((e: IKeyboardEvent) => this.onEditorKeyUp(e)));

A
Alex Dima 已提交
239
		this.toUnhook.push(this.editor.onDidChangeModel((e) => this.resetHandler()));
A
Alex Dima 已提交
240
		this.toUnhook.push(this.editor.onDidChangeModelContent(() => this.resetHandler()));
A
Alex Dima 已提交
241 242 243 244 245
		this.toUnhook.push(this.editor.onDidScrollChange((e) => {
			if (e.scrollTopChanged || e.scrollLeftChanged) {
				this.resetHandler();
			}
		}));
E
Erich Gamma 已提交
246 247
	}

A
Alex Dima 已提交
248
	private onEditorMouseMove(mouseEvent: IEditorMouseEvent, withKey?: IKeyboardEvent): void {
249
		this.lastMouseMoveEvent = mouseEvent;
E
Erich Gamma 已提交
250 251 252 253

		this.startFindDefinition(mouseEvent, withKey);
	}

A
Alex Dima 已提交
254
	private startFindDefinition(mouseEvent: IEditorMouseEvent, withKey?: IKeyboardEvent): void {
E
Erich Gamma 已提交
255 256 257 258 259 260 261
		if (!this.isEnabled(mouseEvent, withKey)) {
			this.currentWordUnderMouse = null;
			this.removeDecorations();
			return;
		}

		// Find word at mouse position
262 263
		let position = mouseEvent.target.position;
		let word = position ? this.editor.getModel().getWordAtPosition(position) : null;
E
Erich Gamma 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276 277
		if (!word) {
			this.currentWordUnderMouse = null;
			this.removeDecorations();
			return;
		}

		// Return early if word at position is still the same
		if (this.currentWordUnderMouse && this.currentWordUnderMouse.startColumn === word.startColumn && this.currentWordUnderMouse.endColumn === word.endColumn && this.currentWordUnderMouse.word === word.word) {
			return;
		}

		this.currentWordUnderMouse = word;

		// Find definition and decorate word if found
A
Alex Dima 已提交
278
		let state = this.editor.captureState(editorCommon.CodeEditorStateFlag.Position, editorCommon.CodeEditorStateFlag.Value, editorCommon.CodeEditorStateFlag.Selection, editorCommon.CodeEditorStateFlag.Scroll);
E
Erich Gamma 已提交
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
		this.throttler.queue(() => {
			return state.validate(this.editor)
				? this.findDefinition(mouseEvent.target)
				: TPromise.as(null);

		}).then(results => {
			if (!results || !results.length || !state.validate(this.editor)) {
				this.removeDecorations();
				return;
			}

			// Multiple results
			if (results.length > 1) {
				this.addDecoration({
					startLineNumber: position.lineNumber,
					startColumn: word.startColumn,
					endLineNumber: position.lineNumber,
					endColumn: word.endColumn
297
				}, nls.localize('multipleResults', "Click to show the {0} definitions found.", results.length), false);
E
Erich Gamma 已提交
298 299 300 301 302
			}

			// Single result
			else {
				let result = results[0];
303
				this.editorService.resolveEditorModel({ resource: result.uri }).then(model => {
304
					let source: string;
E
Erich Gamma 已提交
305 306
					if (model && model.textEditorModel) {

307
						let from = Math.max(1, result.range.startLineNumber),
E
Erich Gamma 已提交
308
							to: number,
A
Alex Dima 已提交
309
							editorModel: editorCommon.IModel;
E
Erich Gamma 已提交
310

A
Alex Dima 已提交
311
						editorModel = <editorCommon.IModel>model.textEditorModel;
E
Erich Gamma 已提交
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327

						// if we have a range, take that into consideration for the "to" position, otherwise fallback to MAX_SOURCE_PREVIEW_LINES
						if (result.range.startLineNumber !== result.range.endLineNumber || result.range.startColumn !== result.range.endColumn) {
							to = Math.min(result.range.endLineNumber, result.range.startLineNumber + GotoDefinitionWithMouseEditorContribution.MAX_SOURCE_PREVIEW_LINES, editorModel.getLineCount());
						} else {
							to = Math.min(from + GotoDefinitionWithMouseEditorContribution.MAX_SOURCE_PREVIEW_LINES, editorModel.getLineCount());
						}

						source = editorModel.getValueInRange({
							startLineNumber: from,
							startColumn: 1,
							endLineNumber: to,
							endColumn: editorModel.getLineMaxColumn(to)
						}).trim();

						// remove common leading whitespace
328
						let min = Number.MAX_VALUE,
E
Erich Gamma 已提交
329 330 331 332 333 334 335 336 337 338 339 340 341 342
							regexp = /^[ \t]*/,
							match: RegExpExecArray,
							contents: string;

						while (from <= to && min > 0) {
							contents = editorModel.getLineContent(from++);
							if (contents.trim().length === 0) {
								// empty or whitespace only
								continue;
							}
							match = regexp.exec(contents);
							min = Math.min(min, match[0].length);
						}

A
Alex Dima 已提交
343
						source = source.replace(new RegExp(`^([ \\t]{${min}})`, 'gm'), strings.empty);
E
Erich Gamma 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356 357

						if (result.range.endLineNumber - result.range.startLineNumber > GotoDefinitionWithMouseEditorContribution.MAX_SOURCE_PREVIEW_LINES) {
							source += '\n\u2026';
						}
					}

					this.addDecoration({
						startLineNumber: position.lineNumber,
						startColumn: word.startColumn,
						endLineNumber: position.lineNumber,
						endColumn: word.endColumn
					}, source, true);
				});
			}
A
Alex Dima 已提交
358
		}).done(undefined, onUnexpectedError);
E
Erich Gamma 已提交
359 360
	}

A
Alex Dima 已提交
361
	private addDecoration(range: editorCommon.IRange, text: string, isCode: boolean): void {
362
		let model = this.editor.getModel();
E
Erich Gamma 已提交
363 364 365 366
		if (!model) {
			return;
		}

367
		let htmlMessage: MarkedString = void 0;;
E
Erich Gamma 已提交
368
		if (text && text.trim().length > 0) {
369 370 371 372 373 374 375 376
			if (isCode) {
				htmlMessage = {
					language: model.getMode().getId(),
					value: text
				};
			} else {
				htmlMessage = textToMarkedString(text);
			}
E
Erich Gamma 已提交
377 378
		}

379
		let newDecorations = {
E
Erich Gamma 已提交
380 381 382 383 384 385 386 387 388 389
			range: range,
			options: {
				inlineClassName: 'goto-definition-link',
				htmlMessage: [htmlMessage]
			}
		};

		this.decorations = this.editor.deltaDecorations(this.decorations, [newDecorations]);
	}

390
	private removeDecorations(): void {
E
Erich Gamma 已提交
391 392 393 394 395
		if (this.decorations.length > 0) {
			this.decorations = this.editor.deltaDecorations(this.decorations, []);
		}
	}

A
Alex Dima 已提交
396
	private onEditorKeyDown(e: IKeyboardEvent): void {
397 398 399 400 401 402
		if (
			this.lastMouseMoveEvent && (
				e.keyCode === GotoDefinitionWithMouseEditorContribution.TRIGGER_KEY_VALUE || // User just pressed Ctrl/Cmd (normal goto definition)
				e.keyCode === GotoDefinitionWithMouseEditorContribution.TRIGGER_SIDEBYSIDE_KEY_VALUE && e[GotoDefinitionWithMouseEditorContribution.TRIGGER_MODIFIER] // User pressed Ctrl/Cmd+Alt (goto definition to the side)
			)
		) {
403
			this.startFindDefinition(this.lastMouseMoveEvent, e);
E
Erich Gamma 已提交
404 405 406 407 408
		} else if (e[GotoDefinitionWithMouseEditorContribution.TRIGGER_MODIFIER]) {
			this.removeDecorations(); // remove decorations if user holds another key with ctrl/cmd to prevent accident goto declaration
		}
	}

409
	private resetHandler(): void {
410
		this.lastMouseMoveEvent = null;
E
Erich Gamma 已提交
411 412 413
		this.removeDecorations();
	}

A
Alex Dima 已提交
414
	private onEditorMouseDown(mouseEvent: IEditorMouseEvent): void {
415 416 417 418 419 420 421
		// We need to record if we had the trigger key on mouse down because someone might select something in the editor
		// holding the mouse down and then while mouse is down start to press Ctrl/Cmd to start a copy operation and then
		// release the mouse button without wanting to do the navigation.
		// With this flag we prevent goto definition if the mouse was down before the trigger key was pressed.
		this.hasTriggerKeyOnMouseDown = !!mouseEvent.event[GotoDefinitionWithMouseEditorContribution.TRIGGER_MODIFIER];
	}

A
Alex Dima 已提交
422
	private onEditorMouseUp(mouseEvent: IEditorMouseEvent): void {
423
		if (this.isEnabled(mouseEvent) && this.hasTriggerKeyOnMouseDown) {
424
			this.gotoDefinition(mouseEvent.target, mouseEvent.event.altKey).done(() => {
E
Erich Gamma 已提交
425
				this.removeDecorations();
426
			}, (error: Error) => {
E
Erich Gamma 已提交
427
				this.removeDecorations();
A
Alex Dima 已提交
428
				onUnexpectedError(error);
E
Erich Gamma 已提交
429 430 431 432
			});
		}
	}

A
Alex Dima 已提交
433
	private onEditorKeyUp(e: IKeyboardEvent): void {
E
Erich Gamma 已提交
434 435 436 437 438 439
		if (e.keyCode === GotoDefinitionWithMouseEditorContribution.TRIGGER_KEY_VALUE) {
			this.removeDecorations();
			this.currentWordUnderMouse = null;
		}
	}

A
Alex Dima 已提交
440
	private isEnabled(mouseEvent: IEditorMouseEvent, withKey?: IKeyboardEvent): boolean {
441
		return this.editor.getModel() &&
A
Alex Dima 已提交
442 443
			(browser.isIE11orEarlier || mouseEvent.event.detail <= 1) && // IE does not support event.detail properly
			mouseEvent.target.type === editorCommon.MouseTargetType.CONTENT_TEXT &&
E
Erich Gamma 已提交
444
			(mouseEvent.event[GotoDefinitionWithMouseEditorContribution.TRIGGER_MODIFIER] || (withKey && withKey.keyCode === GotoDefinitionWithMouseEditorContribution.TRIGGER_KEY_VALUE)) &&
445
			DefinitionProviderRegistry.has(this.editor.getModel());
E
Erich Gamma 已提交
446 447
	}

448
	private findDefinition(target: IMouseTarget): TPromise<Location[]> {
449
		let model = this.editor.getModel();
E
Erich Gamma 已提交
450 451 452 453
		if (!model) {
			return TPromise.as(null);
		}

454
		return getDeclarationsAtPosition(this.editor.getModel(), target.position);
E
Erich Gamma 已提交
455 456
	}

A
Alex Dima 已提交
457
	private gotoDefinition(target: IMouseTarget, sideBySide: boolean): TPromise<any> {
E
Erich Gamma 已提交
458

459 460 461
		const targetAction = sideBySide
			? OpenDefinitionToSideAction.ID
			: GoToDefinitionAction.ID;
E
Erich Gamma 已提交
462

463 464 465
		// just run the corresponding action
		this.editor.setPosition(target.position);
		return this.editor.getAction(targetAction).run();
E
Erich Gamma 已提交
466 467 468 469 470 471 472
	}

	public getId(): string {
		return GotoDefinitionWithMouseEditorContribution.ID;
	}

	public dispose(): void {
A
Alex Dima 已提交
473
		this.toUnhook = dispose(this.toUnhook);
E
Erich Gamma 已提交
474 475 476 477
	}
}

// register actions
478
CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(PeekDefinitionAction, PeekDefinitionAction.ID, nls.localize('actions.previewDecl.label', "Peek Definition"), {
E
Erich Gamma 已提交
479 480 481
	context: ContextKey.EditorTextFocus,
	primary: KeyMod.Alt | KeyCode.F12,
	linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.F10 },
482
}, 'Peek Definition'));
483 484

let goToDeclarationKb: number;
A
Alex Dima 已提交
485
if (platform.isWeb) {
486
	goToDeclarationKb = KeyMod.CtrlCmd | KeyCode.F12;
E
Erich Gamma 已提交
487
} else {
488
	goToDeclarationKb = KeyCode.F12;
E
Erich Gamma 已提交
489
}
490

491
CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(GoToDefinitionAction, GoToDefinitionAction.ID, nls.localize('actions.goToDecl.label', "Go to Definition"), {
E
Erich Gamma 已提交
492 493
	context: ContextKey.EditorTextFocus,
	primary: goToDeclarationKb
494
}, 'Go to Definition'));
495

496
CommonEditorRegistry.registerEditorAction(new EditorActionDescriptor(OpenDefinitionToSideAction, OpenDefinitionToSideAction.ID, nls.localize('actions.goToDeclToSide.label', "Open Definition to the Side"), {
497 498
	context: ContextKey.EditorTextFocus,
	primary: KeyMod.chord(KeyMod.CtrlCmd | KeyCode.KEY_K, goToDeclarationKb)
499
}, 'Open Definition to the Side'));
500

E
Erich Gamma 已提交
501
EditorBrowserRegistry.registerEditorContribution(GotoDefinitionWithMouseEditorContribution);