editorCommands.ts 22.5 KB
Newer Older
S
Sandeep Somavarapu 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as nls from 'vs/nls';
import * as types from 'vs/base/common/types';
J
Johannes Rieken 已提交
8 9
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
10
import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditor, IEditorInput } from 'vs/workbench/common/editor';
11
import { INextEditorService } from 'vs/workbench/services/editor/common/editorService';
12
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
13
import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor';
I
isidor 已提交
14
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
15
import { TPromise } from 'vs/base/common/winjs.base';
16
import URI from 'vs/base/common/uri';
B
Benjamin Pasero 已提交
17
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
18
import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions';
I
isidor 已提交
19 20
import { IListService } from 'vs/platform/list/browser/listService';
import { List } from 'vs/base/browser/ui/list/listWidget';
I
isidor 已提交
21
import { distinct } from 'vs/base/common/arrays';
22
import { INextEditorGroupsService, IEditorGroup, GroupDirection, GroupLocation, GroupsOrder, preferredGroupDirection } from 'vs/workbench/services/group/common/editorGroupsService';
23
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
B
Benjamin Pasero 已提交
24
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
25

26
export const MOVE_ACTIVE_EDITOR_COMMAND_ID = 'moveActiveEditor';
27
export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors';
I
isidor 已提交
28
export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup';
29
export const CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID = 'workbench.action.closeEditorsToTheRight';
I
isidor 已提交
30
export const CLOSE_EDITOR_COMMAND_ID = 'workbench.action.closeActiveEditor';
31
export const CLOSE_EDITOR_GROUP_COMMAND_ID = 'workbench.action.closeEditorGroup';
I
isidor 已提交
32
export const CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeOtherEditors';
33
export const KEEP_EDITOR_COMMAND_ID = 'workbench.action.keepEditor';
B
Benjamin Pasero 已提交
34
export const SHOW_EDITORS_IN_GROUP = 'workbench.action.showEditorsInGroup';
35
export const TOGGLE_DIFF_INLINE_MODE = 'toggle.diff.editorMode';
B
Benjamin Pasero 已提交
36 37

export const NAVIGATE_ALL_EDITORS_GROUP_PREFIX = 'edt ';
B
Benjamin Pasero 已提交
38
export const NAVIGATE_IN_ACTIVE_GROUP_PREFIX = 'edt active ';
39

40
export interface ActiveEditorMoveArguments {
41
	to?: 'first' | 'last' | 'left' | 'right' | 'up' | 'down' | 'center' | 'position' | 'previous' | 'next';
42 43
	by?: 'tab' | 'group';
	value?: number;
S
Sandeep Somavarapu 已提交
44 45
}

B
Benjamin Pasero 已提交
46
const isActiveEditorMoveArg = function (arg: ActiveEditorMoveArguments): boolean {
S
Sandeep Somavarapu 已提交
47 48 49 50
	if (!types.isObject(arg)) {
		return false;
	}

51
	if (!types.isString(arg.to)) {
S
Sandeep Somavarapu 已提交
52 53 54
		return false;
	}

55
	if (!types.isUndefined(arg.by) && !types.isString(arg.by)) {
S
Sandeep Somavarapu 已提交
56 57 58
		return false;
	}

59
	if (!types.isUndefined(arg.value) && !types.isNumber(arg.value)) {
S
Sandeep Somavarapu 已提交
60 61 62 63 64 65
		return false;
	}

	return true;
};

66
function registerActiveEditorMoveCommand(): void {
A
Alex Dima 已提交
67
	KeybindingsRegistry.registerCommandAndKeybindingRule({
68
		id: MOVE_ACTIVE_EDITOR_COMMAND_ID,
S
Sandeep Somavarapu 已提交
69
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
70
		when: EditorContextKeys.editorTextFocus,
S
Sandeep Somavarapu 已提交
71
		primary: null,
72
		handler: (accessor, args: any) => moveActiveEditor(args, accessor),
S
Sandeep Somavarapu 已提交
73
		description: {
74
			description: nls.localize('editorCommand.activeEditorMove.description', "Move the active editor by tabs or groups"),
S
Sandeep Somavarapu 已提交
75 76 77
			args: [
				{
					name: nls.localize('editorCommand.activeEditorMove.arg.name', "Active editor move argument"),
78
					description: nls.localize('editorCommand.activeEditorMove.arg.description', "Argument Properties:\n\t* 'to': String value providing where to move.\n\t* 'by': String value providing the unit for move (by tab or by group).\n\t* 'value': Number value providing how many positions or an absolute position to move."),
S
Sandeep Somavarapu 已提交
79 80 81 82 83 84 85
					constraint: isActiveEditorMoveArg
				}
			]
		}
	});
}

86 87 88 89
function moveActiveEditor(args: ActiveEditorMoveArguments = Object.create(null), accessor: ServicesAccessor): void {
	args.to = args.to || 'right';
	args.by = args.by || 'tab';
	args.value = typeof args.value === 'number' ? args.value : 1;
S
Sandeep Somavarapu 已提交
90

91 92
	const activeControl = accessor.get(INextEditorService).activeControl;
	if (activeControl) {
93
		switch (args.by) {
94 95 96 97
			case 'tab':
				return moveActiveTab(args, activeControl, accessor);
			case 'group':
				return moveActiveEditorToGroup(args, activeControl, accessor);
98
		}
S
Sandeep Somavarapu 已提交
99 100 101
	}
}

102 103 104
function moveActiveTab(args: ActiveEditorMoveArguments, control: IEditor, accessor: ServicesAccessor): void {
	const group = control.group;
	let index = group.getIndexOfEditor(control.input);
S
Sandeep Somavarapu 已提交
105
	switch (args.to) {
106
		case 'first':
S
Sandeep Somavarapu 已提交
107 108
			index = 0;
			break;
109
		case 'last':
110
			index = group.count - 1;
S
Sandeep Somavarapu 已提交
111
			break;
112
		case 'left':
113
			index = index - args.value;
S
Sandeep Somavarapu 已提交
114
			break;
115
		case 'right':
116
			index = index + args.value;
S
Sandeep Somavarapu 已提交
117
			break;
118
		case 'center':
119
			index = Math.round(group.count / 2) - 1;
S
Sandeep Somavarapu 已提交
120
			break;
121
		case 'position':
122
			index = args.value - 1;
S
Sandeep Somavarapu 已提交
123 124
			break;
	}
125

126
	index = index < 0 ? 0 : index >= group.count ? group.count - 1 : index;
127
	group.moveEditor(control.input, group, { index });
S
Sandeep Somavarapu 已提交
128 129
}

130 131 132 133 134
function moveActiveEditorToGroup(args: ActiveEditorMoveArguments, control: IEditor, accessor: ServicesAccessor): void {
	const editorGroupService = accessor.get(INextEditorGroupsService);

	const groups = editorGroupService.groups;
	const sourceGroup = control.group;
135
	let targetGroup: IEditorGroup;
136

S
Sandeep Somavarapu 已提交
137
	switch (args.to) {
138
		case 'left':
139 140
			targetGroup = editorGroupService.findGroup({ direction: GroupDirection.LEFT }, sourceGroup);
			if (!targetGroup) {
B
Benjamin Pasero 已提交
141
				targetGroup = editorGroupService.addGroup(sourceGroup, GroupDirection.LEFT, { activate: true });
142
			}
143 144
			break;
		case 'right':
145 146
			targetGroup = editorGroupService.findGroup({ direction: GroupDirection.RIGHT }, sourceGroup);
			if (!targetGroup) {
B
Benjamin Pasero 已提交
147
				targetGroup = editorGroupService.addGroup(sourceGroup, GroupDirection.RIGHT, { activate: true });
148
			}
S
Sandeep Somavarapu 已提交
149
			break;
150
		case 'up':
151 152
			targetGroup = editorGroupService.findGroup({ direction: GroupDirection.UP }, sourceGroup);
			if (!targetGroup) {
B
Benjamin Pasero 已提交
153
				targetGroup = editorGroupService.addGroup(sourceGroup, GroupDirection.UP, { activate: true });
154
			}
S
Sandeep Somavarapu 已提交
155
			break;
156
		case 'down':
157 158
			targetGroup = editorGroupService.findGroup({ direction: GroupDirection.DOWN }, sourceGroup);
			if (!targetGroup) {
B
Benjamin Pasero 已提交
159
				targetGroup = editorGroupService.addGroup(sourceGroup, GroupDirection.DOWN, { activate: true });
160
			}
S
Sandeep Somavarapu 已提交
161
			break;
162
		case 'first':
163
			targetGroup = editorGroupService.findGroup({ location: GroupLocation.FIRST }, sourceGroup);
S
Sandeep Somavarapu 已提交
164
			break;
165
		case 'last':
166 167 168 169 170 171 172
			targetGroup = editorGroupService.findGroup({ location: GroupLocation.LAST }, sourceGroup);
			break;
		case 'previous':
			targetGroup = editorGroupService.findGroup({ location: GroupLocation.PREVIOUS }, sourceGroup);
			break;
		case 'next':
			targetGroup = editorGroupService.findGroup({ location: GroupLocation.NEXT }, sourceGroup);
S
Sandeep Somavarapu 已提交
173
			break;
174 175 176 177 178
		case 'center':
			targetGroup = groups[(groups.length / 2) - 1];
			break;
		case 'position':
			targetGroup = groups[args.value - 1];
S
Sandeep Somavarapu 已提交
179 180
			break;
	}
181

182 183 184
	if (targetGroup) {
		sourceGroup.moveEditor(control.input, targetGroup);
	}
185 186 187 188 189 190
}

function registerDiffEditorCommands(): void {
	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: 'workbench.action.compareEditor.nextChange',
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
191
		when: TextCompareEditorVisibleContext,
192 193 194 195 196 197 198
		primary: null,
		handler: accessor => navigateInDiffEditor(accessor, true)
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: 'workbench.action.compareEditor.previousChange',
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
199
		when: TextCompareEditorVisibleContext,
200 201 202 203 204
		primary: null,
		handler: accessor => navigateInDiffEditor(accessor, false)
	});

	function navigateInDiffEditor(accessor: ServicesAccessor, next: boolean): void {
205 206
		const editorService = accessor.get(INextEditorService);
		const candidates = [editorService.activeControl, ...editorService.visibleControls].filter(e => e instanceof TextDiffEditor);
207 208 209 210 211 212 213

		if (candidates.length > 0) {
			next ? (<TextDiffEditor>candidates[0]).getDiffNavigator().next() : (<TextDiffEditor>candidates[0]).getDiffNavigator().previous();
		}
	}

	KeybindingsRegistry.registerCommandAndKeybindingRule({
214 215
		id: TOGGLE_DIFF_INLINE_MODE,
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
216
		when: void 0,
217
		primary: void 0,
B
Benjamin Pasero 已提交
218
		handler: (accessor, resource, context: IEditorCommandsContext) => {
219 220
			const editorGroupService = accessor.get(INextEditorGroupsService);

I
isidor 已提交
221
			const { control } = resolveCommandsContext(editorGroupService, context);
222 223 224 225
			if (control instanceof TextDiffEditor) {
				const widget = control.getControl();
				const isInlineMode = !widget.renderSideBySide;
				widget.updateOptions(<IDiffEditorOptions>{
226 227 228 229
					renderSideBySide: isInlineMode
				});
			}
		}
230
	});
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
}

function registerOpenEditorAtIndexCommands(): void {

	// Keybindings to focus a specific index in the tab folder if tabs are enabled
	for (let i = 0; i < 9; i++) {
		const editorIndex = i;
		const visibleIndex = i + 1;

		KeybindingsRegistry.registerCommandAndKeybindingRule({
			id: 'workbench.action.openEditorAtIndex' + visibleIndex,
			weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
			when: void 0,
			primary: KeyMod.Alt | toKeyCode(visibleIndex),
			mac: { primary: KeyMod.WinCtrl | toKeyCode(visibleIndex) },
			handler: accessor => {
247
				const editorService = accessor.get(INextEditorService);
248

249 250
				const activeControl = editorService.activeControl;
				if (activeControl) {
251
					const editor = activeControl.group.getEditor(editorIndex);
252
					if (editor) {
B
Benjamin Pasero 已提交
253
						return editorService.openEditor(editor).then(() => void 0);
254 255
					}
				}
256 257

				return void 0;
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
			}
		});
	}

	function toKeyCode(index: number): KeyCode {
		switch (index) {
			case 0: return KeyCode.KEY_0;
			case 1: return KeyCode.KEY_1;
			case 2: return KeyCode.KEY_2;
			case 3: return KeyCode.KEY_3;
			case 4: return KeyCode.KEY_4;
			case 5: return KeyCode.KEY_5;
			case 6: return KeyCode.KEY_6;
			case 7: return KeyCode.KEY_7;
			case 8: return KeyCode.KEY_8;
			case 9: return KeyCode.KEY_9;
		}
275 276

		return void 0;
277
	}
278 279
}

B
Benjamin Pasero 已提交
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
function registerFocusEditorGroupAtIndexCommands(): void {

	// Keybindings to focus a specific group (2-8) in the editor area
	for (let i = 1; i < 8; i++) {
		const groupIndex = i;

		KeybindingsRegistry.registerCommandAndKeybindingRule({
			id: toCommandId(groupIndex),
			weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
			when: void 0,
			primary: KeyMod.CtrlCmd | toKeyCode(groupIndex),
			handler: accessor => {
				const editorGroupService = accessor.get(INextEditorGroupsService);
				const configurationService = accessor.get(IConfigurationService);

				// To keep backwards compatibility (pre-grid), allow to focus a group
				// that does not exist as long as it is the next group after the last
				// opened group. Otherwise we return.
				if (groupIndex > editorGroupService.count) {
					return;
				}

				// Group exists: just focus
				const groups = editorGroupService.getGroups(GroupsOrder.CREATION_TIME);
				if (groups[groupIndex]) {
					return groups[groupIndex].focus();
				}

				// Group does not exist: create new by splitting the active one of the last group
				const direction = preferredGroupDirection(configurationService);
				const lastGroup = editorGroupService.findGroup({ location: GroupLocation.LAST });
				const newGroup = editorGroupService.addGroup(lastGroup, direction, { activate: true });

				// To keep backwards compatibility (pre-grid) we automatically copy the active editor
				// of the last group over to the new group as long as it supports to be split.
				if (lastGroup.activeEditor) {
					if (lastGroup.activeEditor instanceof EditorInput && !lastGroup.activeEditor.supportsSplitEditor()) {
						return;
					}

					lastGroup.copyEditor(lastGroup.activeEditor, newGroup);
				}
			}
		});
	}

	function toCommandId(index: number): string {
		switch (index) {
			case 1: return 'workbench.action.focusSecondEditorGroup';
			case 2: return 'workbench.action.focusThirdEditorGroup';
			case 3: return 'workbench.action.focusFourthEditorGroup';
			case 4: return 'workbench.action.focusFifthEditorGroup';
			case 5: return 'workbench.action.focusSixthEditorGroup';
			case 6: return 'workbench.action.focusSeventhEditorGroup';
			case 7: return 'workbench.action.focusEighthEditorGroup';
		}

		return void 0;
	}

	function toKeyCode(index: number): KeyCode {
		switch (index) {
			case 1: return KeyCode.KEY_2;
			case 2: return KeyCode.KEY_3;
			case 3: return KeyCode.KEY_4;
			case 4: return KeyCode.KEY_5;
			case 5: return KeyCode.KEY_6;
			case 6: return KeyCode.KEY_7;
			case 7: return KeyCode.KEY_8;
		}

		return void 0;
	}
}

355
function registerEditorCommands() {
356

I
isidor 已提交
357
	KeybindingsRegistry.registerCommandAndKeybindingRule({
358
		id: CLOSE_SAVED_EDITORS_COMMAND_ID,
I
isidor 已提交
359
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
360
		when: void 0,
I
isidor 已提交
361
		primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_U),
I
isidor 已提交
362
		handler: (accessor, resource: URI | object, context: IEditorCommandsContext) => {
I
isidor 已提交
363 364 365
			const editorGroupService = accessor.get(INextEditorGroupsService);
			const contexts = getMultiSelectedEditorContexts(context, accessor.get(IListService), editorGroupService);
			if (contexts.length === 0 && editorGroupService.activeGroup) {
366
				contexts.push({ groupId: editorGroupService.activeGroup.id }); // If command is triggered from the command palette use the active group
I
isidor 已提交
367
			}
368

I
isidor 已提交
369 370 371
			return TPromise.join(distinct(contexts.map(c => c.groupId)).map(groupId =>
				editorGroupService.getGroup(groupId).closeEditors({ savedOnly: true })
			));
372 373 374
		}
	});

I
isidor 已提交
375
	KeybindingsRegistry.registerCommandAndKeybindingRule({
376
		id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
I
isidor 已提交
377
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
378
		when: void 0,
I
isidor 已提交
379
		primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_W),
I
isidor 已提交
380
		handler: (accessor, resource: URI | object, context: IEditorCommandsContext) => {
I
isidor 已提交
381 382
			const editorGroupService = accessor.get(INextEditorGroupsService);
			const contexts = getMultiSelectedEditorContexts(context, accessor.get(IListService), editorGroupService);
383
			const distinctGroupIds = distinct(contexts.map(c => c.groupId));
384

I
isidor 已提交
385 386
			if (distinctGroupIds.length === 0) {
				distinctGroupIds.push(editorGroupService.activeGroup.id);
387 388
			}

I
isidor 已提交
389 390 391
			return TPromise.join(distinctGroupIds.map(groupId =>
				editorGroupService.getGroup(groupId).closeAllEditors()
			));
392 393 394
		}
	});

I
isidor 已提交
395
	KeybindingsRegistry.registerCommandAndKeybindingRule({
I
isidor 已提交
396
		id: CLOSE_EDITOR_COMMAND_ID,
I
isidor 已提交
397
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
398
		when: void 0,
I
isidor 已提交
399 400
		primary: KeyMod.CtrlCmd | KeyCode.KEY_W,
		win: { primary: KeyMod.CtrlCmd | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_W] },
I
isidor 已提交
401
		handler: (accessor, resource: URI | object, context: IEditorCommandsContext) => {
I
isidor 已提交
402 403 404 405 406
			const editorGroupService = accessor.get(INextEditorGroupsService);
			const contexts = getMultiSelectedEditorContexts(context, accessor.get(IListService), editorGroupService);
			const activeGroup = editorGroupService.activeGroup;
			if (contexts.length === 0 && activeGroup && activeGroup.activeEditor) {
				contexts.push({ groupId: activeGroup.id, editorIndex: activeGroup.getIndexOfEditor(activeGroup.activeEditor) });
407
			}
408

I
isidor 已提交
409 410 411 412 413 414
			const groupIds = distinct(contexts.map(context => context.groupId));
			return TPromise.join(groupIds.map(groupId => {
				const group = editorGroupService.getGroup(groupId);
				const editors = contexts.filter(c => c.groupId === groupId).map(c => group.getEditor(c.editorIndex));
				return group.closeEditors(editors);
			}));
415
		}
416 417 418 419 420 421 422 423 424
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: CLOSE_EDITOR_GROUP_COMMAND_ID,
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
		when: ContextKeyExpr.and(ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext),
		primary: KeyMod.CtrlCmd | KeyCode.KEY_W,
		win: { primary: KeyMod.CtrlCmd | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_W] },
		handler: (accessor, resource: URI | object, context: IEditorCommandsContext) => {
425 426
			const editorGroupService = accessor.get(INextEditorGroupsService);

427
			let group: IEditorGroup;
428 429 430 431 432
			if (context && typeof context.groupId === 'number') {
				group = editorGroupService.getGroup(context.groupId);
			} else {
				group = editorGroupService.activeGroup;
			}
433

434
			editorGroupService.removeGroup(group);
435
		}
436 437
	});

I
isidor 已提交
438
	KeybindingsRegistry.registerCommandAndKeybindingRule({
I
isidor 已提交
439
		id: CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID,
I
isidor 已提交
440
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
441 442
		when: void 0,
		primary: void 0,
I
isidor 已提交
443
		mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_T },
I
isidor 已提交
444
		handler: (accessor, resource: URI | object, context: IEditorCommandsContext) => {
I
isidor 已提交
445 446
			const editorGroupService = accessor.get(INextEditorGroupsService);
			const contexts = getMultiSelectedEditorContexts(context, accessor.get(IListService), editorGroupService);
447

448 449
			if (contexts.length === 0) {
				// Cover the case when run from command palette
I
isidor 已提交
450 451 452
				const activeGroup = editorGroupService.activeGroup;
				if (activeGroup && activeGroup.activeEditor) {
					contexts.push({ groupId: activeGroup.id, editorIndex: activeGroup.getIndexOfEditor(activeGroup.activeEditor) });
453 454 455 456
				}
			}

			const groupIds = distinct(contexts.map(context => context.groupId));
457

I
isidor 已提交
458 459 460 461
			return TPromise.join(groupIds.map(groupId => {
				const group = editorGroupService.getGroup(groupId);
				const editors = contexts.filter(c => c.groupId === groupId).map(c => group.getEditor(c.editorIndex));
				const editorsToClose = group.editors.filter(e => editors.indexOf(e) === -1);
462

I
isidor 已提交
463 464
				return group.closeEditors(editorsToClose);
			}));
465 466 467 468 469 470 471 472
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID,
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
		when: void 0,
		primary: void 0,
473
		handler: (accessor, resource: URI, context: IEditorCommandsContext) => {
474
			const editorGroupService = accessor.get(INextEditorGroupsService);
475

I
isidor 已提交
476
			const { group, editor } = resolveCommandsContext(editorGroupService, context);
477 478
			if (group && editor) {
				return group.closeEditors({ direction: CloseDirection.RIGHT, except: editor });
479 480
			}

481 482 483 484 485 486 487 488 489
			return TPromise.as(false);
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: KEEP_EDITOR_COMMAND_ID,
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
		when: void 0,
		primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.Enter),
490
		handler: (accessor, resource: URI, context: IEditorCommandsContext) => {
491
			const editorGroupService = accessor.get(INextEditorGroupsService);
492

I
isidor 已提交
493
			const { group, editor } = resolveCommandsContext(editorGroupService, context);
494 495
			if (group && editor) {
				return group.pinEditor(editor);
496 497
			}

I
isidor 已提交
498
			return TPromise.as(false);
499 500
		}
	});
B
Benjamin Pasero 已提交
501 502 503 504 505 506

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: SHOW_EDITORS_IN_GROUP,
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
		when: void 0,
		primary: void 0,
B
Benjamin Pasero 已提交
507
		handler: (accessor, resource: URI, context: IEditorCommandsContext) => {
I
isidor 已提交
508
			const editorGroupService = accessor.get(INextEditorGroupsService);
B
Benjamin Pasero 已提交
509 510
			const quickOpenService = accessor.get(IQuickOpenService);

B
Benjamin Pasero 已提交
511
			if (editorGroupService.count <= 1) {
B
Benjamin Pasero 已提交
512 513 514
				return quickOpenService.show(NAVIGATE_ALL_EDITORS_GROUP_PREFIX);
			}

B
Benjamin Pasero 已提交
515 516 517
			if (context && typeof context.groupId === 'number') {
				editorGroupService.activateGroup(editorGroupService.getGroup(context.groupId)); // we need the group to be active
			}
B
Benjamin Pasero 已提交
518

B
Benjamin Pasero 已提交
519
			return quickOpenService.show(NAVIGATE_IN_ACTIVE_GROUP_PREFIX);
B
Benjamin Pasero 已提交
520 521
		}
	});
522
}
523

524
function resolveCommandsContext(editorGroupService: INextEditorGroupsService, context?: IEditorCommandsContext): { group: IEditorGroup, editor: IEditorInput, control: IEditor } {
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540

	// Resolve from context
	let group = context && typeof context.groupId === 'number' ? editorGroupService.getGroup(context.groupId) : undefined;
	let editor = group && typeof context.editorIndex === 'number' ? group.getEditor(context.editorIndex) : undefined;
	let control = group ? group.activeControl : undefined;

	// Fallback to active group as needed
	if (!group) {
		group = editorGroupService.activeGroup;
		editor = <EditorInput>group.activeEditor;
		control = group.activeControl;
	}

	return { group, editor, control };
}

541
export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsContext, listService: IListService, editorGroupService: INextEditorGroupsService): IEditorCommandsContext[] {
B
Benjamin Pasero 已提交
542

B
Benjamin Pasero 已提交
543 544
	// First check for a focused list to return the selected items from
	const list = listService.lastFocusedList;
I
isidor 已提交
545
	if (list instanceof List && list.isDOMFocused()) {
B
Benjamin Pasero 已提交
546 547 548 549 550 551 552
		const elementToContext = (element: IEditorIdentifier | IEditorGroup) => {
			if (isEditorGroup(element)) {
				return { groupId: element.id, editorIndex: void 0 };
			}

			return { groupId: element.groupId, editorIndex: editorGroupService.getGroup(element.groupId).getIndexOfEditor(element.editor) };
		};
I
isidor 已提交
553

B
Benjamin Pasero 已提交
554 555 556 557
		const onlyEditorGroupAndEditor = (e: IEditorIdentifier | IEditorGroup) => isEditorGroup(e) || isEditorIdentifier(e);

		const focusedElements: (IEditorIdentifier | IEditorGroup)[] = list.getFocusedElements().filter(onlyEditorGroupAndEditor);
		const focus = editorContext ? editorContext : focusedElements.length ? focusedElements.map(elementToContext)[0] : void 0; // need to take into account when editor context is { group: group }
558 559

		if (focus) {
B
Benjamin Pasero 已提交
560 561
			const selection: (IEditorIdentifier | IEditorGroup)[] = list.getSelectedElements().filter(onlyEditorGroupAndEditor);

562
			// Only respect selection if it contains focused element
B
Benjamin Pasero 已提交
563
			if (selection && selection.some(s => isEditorGroup(s) ? s.id === focus.groupId : s.groupId === focus.groupId && editorGroupService.getGroup(s.groupId).getIndexOfEditor(s.editor) === focus.editorIndex)) {
564 565
				return selection.map(elementToContext);
			}
I
isidor 已提交
566

567
			return [focus];
I
isidor 已提交
568 569 570
		}
	}

B
Benjamin Pasero 已提交
571
	// Otherwise go with passed in context
I
isidor 已提交
572 573
	return !!editorContext ? [editorContext] : [];
}
574

B
Benjamin Pasero 已提交
575 576 577 578 579 580 581 582 583 584 585 586
function isEditorGroup(thing: any): thing is IEditorGroup {
	const group = thing as IEditorGroup;

	return group && typeof group.id === 'number' && Array.isArray(group.editors);
}

function isEditorIdentifier(thing: any): thing is IEditorIdentifier {
	const identifier = thing as IEditorIdentifier;

	return identifier && typeof identifier.groupId === 'number';
}

587 588 589 590 591
export function setup(): void {
	registerActiveEditorMoveCommand();
	registerDiffEditorCommands();
	registerOpenEditorAtIndexCommands();
	registerEditorCommands();
B
Benjamin Pasero 已提交
592
	registerFocusEditorGroupAtIndexCommands();
593
}