editorCommands.ts 22.3 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 10
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
11
import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditor, IEditorInput } from 'vs/workbench/common/editor';
J
Johannes Rieken 已提交
12
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
13
import { Position, POSITIONS } from 'vs/platform/editor/common/editor';
14
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
15
import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor';
B
Benjamin Pasero 已提交
16
import { EditorGroup } from 'vs/workbench/common/editor/editorGroup';
I
isidor 已提交
17
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
18
import { TPromise } from 'vs/base/common/winjs.base';
19
import URI from 'vs/base/common/uri';
B
Benjamin Pasero 已提交
20
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
21
import { IDiffEditorOptions } from 'vs/editor/common/config/editorOptions';
I
isidor 已提交
22 23
import { IListService } from 'vs/platform/list/browser/listService';
import { List } from 'vs/base/browser/ui/list/listWidget';
I
isidor 已提交
24
import { distinct } from 'vs/base/common/arrays';
B
Benjamin Pasero 已提交
25
import { INextEditorGroupsService } from 'vs/workbench/services/group/common/nextEditorGroupsService';
26
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
27

B
Benjamin Pasero 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
export const ActiveEditorMovePositioning = {
	FIRST: 'first',
	LAST: 'last',
	LEFT: 'left',
	RIGHT: 'right',
	CENTER: 'center',
	POSITION: 'position',
};

export const ActiveEditorMovePositioningBy = {
	TAB: 'tab',
	GROUP: 'group'
};

export interface ActiveEditorMoveArguments {
	to?: string;
	by?: string;
	value?: number;
}

export const EditorCommands = {
	MoveActiveEditor: 'moveActiveEditor'
};

52
export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors';
I
isidor 已提交
53
export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup';
54
export const CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID = 'workbench.action.closeEditorsToTheRight';
I
isidor 已提交
55
export const CLOSE_EDITOR_COMMAND_ID = 'workbench.action.closeActiveEditor';
56
export const CLOSE_EDITOR_GROUP_COMMAND_ID = 'workbench.action.closeActiveEditorGroup';
I
isidor 已提交
57
export const CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeOtherEditors';
58
export const KEEP_EDITOR_COMMAND_ID = 'workbench.action.keepEditor';
B
Benjamin Pasero 已提交
59
export const SHOW_EDITORS_IN_GROUP = 'workbench.action.showEditorsInGroup';
60
export const TOGGLE_DIFF_INLINE_MODE = 'toggle.diff.editorMode';
B
Benjamin Pasero 已提交
61 62 63 64 65

export const NAVIGATE_IN_GROUP_ONE_PREFIX = 'edt one ';
export const NAVIGATE_IN_GROUP_TWO_PREFIX = 'edt two ';
export const NAVIGATE_IN_GROUP_THREE_PREFIX = 'edt three ';
export const NAVIGATE_ALL_EDITORS_GROUP_PREFIX = 'edt ';
66

67
export function setup(): void {
68 69
	registerActiveEditorMoveCommand();
	registerDiffEditorCommands();
70
	registerOpenEditorAtIndexCommands();
71
	registerEditorCommands();
S
Sandeep Somavarapu 已提交
72 73
}

B
Benjamin Pasero 已提交
74
const isActiveEditorMoveArg = function (arg: ActiveEditorMoveArguments): boolean {
S
Sandeep Somavarapu 已提交
75 76 77 78
	if (!types.isObject(arg)) {
		return false;
	}

79
	const activeEditorMoveArg: ActiveEditorMoveArguments = arg;
S
Sandeep Somavarapu 已提交
80 81 82 83 84 85 86 87 88

	if (!types.isString(activeEditorMoveArg.to)) {
		return false;
	}

	if (!types.isUndefined(activeEditorMoveArg.by) && !types.isString(activeEditorMoveArg.by)) {
		return false;
	}

89
	if (!types.isUndefined(activeEditorMoveArg.value) && !types.isNumber(activeEditorMoveArg.value)) {
S
Sandeep Somavarapu 已提交
90 91 92 93 94 95
		return false;
	}

	return true;
};

96
function registerActiveEditorMoveCommand(): void {
A
Alex Dima 已提交
97
	KeybindingsRegistry.registerCommandAndKeybindingRule({
98
		id: EditorCommands.MoveActiveEditor,
S
Sandeep Somavarapu 已提交
99
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
100
		when: EditorContextKeys.editorTextFocus,
S
Sandeep Somavarapu 已提交
101
		primary: null,
102
		handler: (accessor, args: any) => moveActiveEditor(args, accessor),
S
Sandeep Somavarapu 已提交
103
		description: {
104
			description: nls.localize('editorCommand.activeEditorMove.description', "Move the active editor by tabs or groups"),
S
Sandeep Somavarapu 已提交
105 106 107
			args: [
				{
					name: nls.localize('editorCommand.activeEditorMove.arg.name', "Active editor move argument"),
J
Joao Moreno 已提交
108
					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 已提交
109 110 111 112 113 114 115
					constraint: isActiveEditorMoveArg
				}
			]
		}
	});
}

116
function moveActiveEditor(args: ActiveEditorMoveArguments = {}, accessor: ServicesAccessor): void {
S
Sandeep Somavarapu 已提交
117
	args.to = args.to || ActiveEditorMovePositioning.RIGHT;
118
	args.by = args.by || ActiveEditorMovePositioningBy.TAB;
119
	args.value = types.isUndefined(args.value) ? 1 : args.value;
S
Sandeep Somavarapu 已提交
120

121
	const activeEditor = accessor.get(IWorkbenchEditorService).getActiveEditor();
122 123 124 125 126 127 128
	if (activeEditor) {
		switch (args.by) {
			case ActiveEditorMovePositioningBy.TAB:
				return moveActiveTab(args, activeEditor, accessor);
			case ActiveEditorMovePositioningBy.GROUP:
				return moveActiveEditorToGroup(args, activeEditor, accessor);
		}
S
Sandeep Somavarapu 已提交
129 130 131
	}
}

132
function moveActiveTab(args: ActiveEditorMoveArguments, activeEditor: IEditor, accessor: ServicesAccessor): void {
133
	const editorGroupsService: IEditorGroupService = accessor.get(IEditorGroupService);
134
	const editorGroup = editorGroupsService.getStacksModel().groupAt(activeEditor.group);
135
	let index = editorGroup.indexOf(activeEditor.input);
S
Sandeep Somavarapu 已提交
136 137 138 139 140 141 142 143
	switch (args.to) {
		case ActiveEditorMovePositioning.FIRST:
			index = 0;
			break;
		case ActiveEditorMovePositioning.LAST:
			index = editorGroup.count - 1;
			break;
		case ActiveEditorMovePositioning.LEFT:
144
			index = index - args.value;
S
Sandeep Somavarapu 已提交
145 146
			break;
		case ActiveEditorMovePositioning.RIGHT:
147
			index = index + args.value;
S
Sandeep Somavarapu 已提交
148 149
			break;
		case ActiveEditorMovePositioning.CENTER:
150
			index = Math.round(editorGroup.count / 2) - 1;
S
Sandeep Somavarapu 已提交
151 152
			break;
		case ActiveEditorMovePositioning.POSITION:
153
			index = args.value - 1;
S
Sandeep Somavarapu 已提交
154 155
			break;
	}
156

S
Sandeep Somavarapu 已提交
157
	index = index < 0 ? 0 : index >= editorGroup.count ? editorGroup.count - 1 : index;
158
	editorGroupsService.moveEditor(activeEditor.input, editorGroup, editorGroup, { index });
S
Sandeep Somavarapu 已提交
159 160
}

161
function moveActiveEditorToGroup(args: ActiveEditorMoveArguments, activeEditor: IEditor, accessor: ServicesAccessor): void {
162
	let newPosition = activeEditor.group;
S
Sandeep Somavarapu 已提交
163 164
	switch (args.to) {
		case ActiveEditorMovePositioning.LEFT:
S
Sandeep Somavarapu 已提交
165 166 167 168 169 170
			newPosition = newPosition - 1;
			break;
		case ActiveEditorMovePositioning.RIGHT:
			newPosition = newPosition + 1;
			break;
		case ActiveEditorMovePositioning.FIRST:
171
			newPosition = Position.ONE;
S
Sandeep Somavarapu 已提交
172 173
			break;
		case ActiveEditorMovePositioning.LAST:
174
			newPosition = Position.THREE;
S
Sandeep Somavarapu 已提交
175 176
			break;
		case ActiveEditorMovePositioning.CENTER:
177
			newPosition = Position.TWO;
S
Sandeep Somavarapu 已提交
178 179
			break;
		case ActiveEditorMovePositioning.POSITION:
180
			newPosition = args.value - 1;
S
Sandeep Somavarapu 已提交
181 182
			break;
	}
183

184 185
	newPosition = POSITIONS.indexOf(newPosition) !== -1 ? newPosition : activeEditor.group;
	accessor.get(IEditorGroupService).moveEditor(activeEditor.input, activeEditor.group, newPosition);
186 187 188 189 190 191
}

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

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: 'workbench.action.compareEditor.previousChange',
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
200
		when: TextCompareEditorVisibleContext,
201 202 203 204 205 206 207 208 209 210 211 212 213 214
		primary: null,
		handler: accessor => navigateInDiffEditor(accessor, false)
	});

	function navigateInDiffEditor(accessor: ServicesAccessor, next: boolean): void {
		let editorService = accessor.get(IWorkbenchEditorService);
		const candidates = [editorService.getActiveEditor(), ...editorService.getVisibleEditors()].filter(e => e instanceof TextDiffEditor);

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

	KeybindingsRegistry.registerCommandAndKeybindingRule({
215 216
		id: TOGGLE_DIFF_INLINE_MODE,
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
217
		when: void 0,
218
		primary: void 0,
B
Benjamin Pasero 已提交
219
		handler: (accessor, resource, context: IEditorCommandsContext) => {
220
			const editorService = accessor.get(IWorkbenchEditorService);
B
Benjamin Pasero 已提交
221 222 223 224 225 226 227 228 229
			const editorGroupService = accessor.get(IEditorGroupService);

			let editor: IEditor;
			if (context) {
				const position = positionAndInput(editorGroupService, editorService, context).position;
				editor = editorService.getVisibleEditors()[position];
			} else {
				editor = editorService.getActiveEditor();
			}
230

231 232 233 234 235 236 237 238
			if (editor instanceof TextDiffEditor) {
				const control = editor.getControl();
				const isInlineMode = !control.renderSideBySide;
				control.updateOptions(<IDiffEditorOptions>{
					renderSideBySide: isInlineMode
				});
			}
		}
239
	});
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
}

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 => {
				const editorService = accessor.get(IWorkbenchEditorService);
				const editorGroupService = accessor.get(IEditorGroupService);

				const active = editorService.getActiveEditor();
				if (active) {
261
					const group = editorGroupService.getStacksModel().groupAt(active.group);
262 263 264
					const editor = group.getEditor(editorIndex);

					if (editor) {
B
Benjamin Pasero 已提交
265
						return editorService.openEditor(editor).then(() => void 0);
266 267
					}
				}
268 269

				return void 0;
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
			}
		});
	}

	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;
		}
287 288

		return void 0;
289
	}
290 291
}

292
function registerEditorCommands() {
293

I
isidor 已提交
294
	KeybindingsRegistry.registerCommandAndKeybindingRule({
295
		id: CLOSE_SAVED_EDITORS_COMMAND_ID,
I
isidor 已提交
296
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
297
		when: void 0,
I
isidor 已提交
298
		primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_U),
I
isidor 已提交
299
		handler: (accessor, resource: URI | object, context: IEditorCommandsContext) => {
300
			const editorGroupService = accessor.get(IEditorGroupService);
I
isidor 已提交
301
			const model = editorGroupService.getStacksModel();
302
			const editorService = accessor.get(IWorkbenchEditorService);
303
			const contexts = getMultiSelectedEditorContexts(context, accessor.get(IListService), accessor.get(INextEditorGroupsService));
I
isidor 已提交
304 305 306 307
			if (contexts.length === 0 && model.activeGroup) {
				// If command is triggered from the command palette use the active group
				contexts.push({ groupId: model.activeGroup.id });
			}
308

309 310 311
			let positionOne: { savedOnly: boolean } = void 0;
			let positionTwo: { savedOnly: boolean } = void 0;
			let positionThree: { savedOnly: boolean } = void 0;
I
isidor 已提交
312
			contexts.forEach(c => {
313
				switch (model.positionOfGroup(model.getGroup(c.groupId))) {
314 315 316
					case Position.ONE: positionOne = { savedOnly: true }; break;
					case Position.TWO: positionTwo = { savedOnly: true }; break;
					case Position.THREE: positionThree = { savedOnly: true }; break;
I
isidor 已提交
317 318 319 320
				}
			});

			return editorService.closeEditors({ positionOne, positionTwo, positionThree });
321 322 323
		}
	});

I
isidor 已提交
324
	KeybindingsRegistry.registerCommandAndKeybindingRule({
325
		id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
I
isidor 已提交
326
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
327
		when: void 0,
I
isidor 已提交
328
		primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_W),
I
isidor 已提交
329
		handler: (accessor, resource: URI | object, context: IEditorCommandsContext) => {
330 331
			const editorGroupService = accessor.get(IEditorGroupService);
			const editorService = accessor.get(IWorkbenchEditorService);
332
			const contexts = getMultiSelectedEditorContexts(context, accessor.get(IListService), accessor.get(INextEditorGroupsService));
333 334
			const distinctGroupIds = distinct(contexts.map(c => c.groupId));
			const model = editorGroupService.getStacksModel();
335

336 337
			if (distinctGroupIds.length) {
				return editorService.closeEditors(distinctGroupIds.map(gid => model.positionOfGroup(model.getGroup(gid))));
338 339 340
			}
			const activeEditor = editorService.getActiveEditor();
			if (activeEditor) {
341
				return editorService.closeEditors(activeEditor.group);
342 343 344 345 346 347
			}

			return TPromise.as(false);
		}
	});

I
isidor 已提交
348
	KeybindingsRegistry.registerCommandAndKeybindingRule({
I
isidor 已提交
349
		id: CLOSE_EDITOR_COMMAND_ID,
I
isidor 已提交
350
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
351
		when: void 0,
I
isidor 已提交
352 353
		primary: KeyMod.CtrlCmd | KeyCode.KEY_W,
		win: { primary: KeyMod.CtrlCmd | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_W] },
I
isidor 已提交
354
		handler: (accessor, resource: URI | object, context: IEditorCommandsContext) => {
I
isidor 已提交
355
			const editorGroupService = accessor.get(IEditorGroupService);
356
			const editorService = accessor.get(IWorkbenchEditorService);
357
			const nextEditorGroupService = accessor.get(INextEditorGroupsService);
I
isidor 已提交
358

359
			const contexts = getMultiSelectedEditorContexts(context, accessor.get(IListService), accessor.get(INextEditorGroupsService));
360 361
			const groupIds = distinct(contexts.map(context => context.groupId));
			const model = editorGroupService.getStacksModel();
362 363

			const editorsToClose = new Map<Position, IEditorInput[]>();
I
isidor 已提交
364

365 366 367
			groupIds.forEach(groupId => {
				const group = model.getGroup(groupId);
				const position = model.positionOfGroup(group);
368
				if (position >= 0) {
I
isidor 已提交
369 370 371
					const inputs = contexts.map(c => {
						if (c && groupId === c.groupId && types.isNumber(c.editorIndex)) {
							return group.getEditor(c.editorIndex);
372
						}
I
isidor 已提交
373

I
isidor 已提交
374
						return group.activeEditor;
I
isidor 已提交
375 376 377 378 379
					}).filter(input => !!input);

					if (inputs.length) {
						editorsToClose.set(position, inputs);
					}
380
				}
381
			});
I
isidor 已提交
382

383
			if (editorsToClose.size === 0) {
384
				return nextEditorGroupService.activeGroup.closeEditor();
385 386
			}

387 388 389 390 391
			return editorService.closeEditors({
				positionOne: editorsToClose.get(Position.ONE),
				positionTwo: editorsToClose.get(Position.TWO),
				positionThree: editorsToClose.get(Position.THREE)
			});
392
		}
393 394 395 396 397 398 399 400 401 402 403 404 405 406
	});

	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) => {
			const nextEditorGroupService = accessor.get(INextEditorGroupsService);

			// TODO@grid handle more cases from the related CLOSE_EDITOR_COMMAND_ID and also revisit command ID
			nextEditorGroupService.removeGroup(nextEditorGroupService.activeGroup);
		}
407 408
	});

I
isidor 已提交
409
	KeybindingsRegistry.registerCommandAndKeybindingRule({
I
isidor 已提交
410
		id: CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID,
I
isidor 已提交
411
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
412 413
		when: void 0,
		primary: void 0,
I
isidor 已提交
414
		mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_T },
I
isidor 已提交
415
		handler: (accessor, resource: URI | object, context: IEditorCommandsContext) => {
I
isidor 已提交
416
			const editorGroupService = accessor.get(IEditorGroupService);
417
			const editorService = accessor.get(IWorkbenchEditorService);
418
			const contexts = getMultiSelectedEditorContexts(context, accessor.get(IListService), accessor.get(INextEditorGroupsService));
419
			const model = editorGroupService.getStacksModel();
420

421 422 423 424 425 426 427 428 429 430 431
			if (contexts.length === 0) {
				// Cover the case when run from command palette
				const activeGroup = model.activeGroup;
				const activeEditor = editorService.getActiveEditorInput();
				if (activeGroup && activeEditor) {
					contexts.push({ groupId: activeGroup.id, editorIndex: activeGroup.indexOf(activeEditor) });
				}
			}

			const groupIds = distinct(contexts.map(context => context.groupId));
			const editorsToClose = new Map<Position, IEditorInput[]>();
432 433
			groupIds.forEach(groupId => {
				const group = model.getGroup(groupId);
434
				const inputsToSkip = contexts.map(c => {
I
isidor 已提交
435
					if (c.groupId === groupId && types.isNumber(c.editorIndex)) {
436
						return group.getEditor(c.editorIndex);
437
					}
438

B
Benjamin Pasero 已提交
439
					return void 0;
440
				}).filter(input => !!input);
441

442
				const toClose = group.getEditors().filter(input => inputsToSkip.indexOf(input) === -1);
443
				editorsToClose.set(model.positionOfGroup(group), toClose);
444 445 446 447 448 449 450
			});

			return editorService.closeEditors({
				positionOne: editorsToClose.get(Position.ONE),
				positionTwo: editorsToClose.get(Position.TWO),
				positionThree: editorsToClose.get(Position.THREE)
			});
451 452 453 454 455 456 457 458
		}
	});

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID,
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
		when: void 0,
		primary: void 0,
459
		handler: (accessor, resource: URI, context: IEditorCommandsContext) => {
460 461
			const editorGroupService = accessor.get(IEditorGroupService);
			const editorService = accessor.get(IWorkbenchEditorService);
I
isidor 已提交
462

B
Benjamin Pasero 已提交
463
			const { position, input } = positionAndInput(editorGroupService, editorService, context);
464 465

			if (typeof position === 'number' && input) {
B
Benjamin Pasero 已提交
466
				return editorService.closeEditors(position, { except: input, direction: CloseDirection.RIGHT });
467 468
			}

469 470 471 472 473 474 475 476 477
			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),
478
		handler: (accessor, resource: URI, context: IEditorCommandsContext) => {
479 480 481
			const editorGroupService = accessor.get(IEditorGroupService);
			const editorService = accessor.get(IWorkbenchEditorService);

B
Benjamin Pasero 已提交
482
			const { position, input } = positionAndInput(editorGroupService, editorService, context);
483

I
isidor 已提交
484
			if (typeof position === 'number' && input) {
485
				return editorGroupService.pinEditor(position, input);
486 487
			}

I
isidor 已提交
488
			return TPromise.as(false);
489 490
		}
	});
B
Benjamin Pasero 已提交
491 492 493 494 495 496

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: SHOW_EDITORS_IN_GROUP,
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
		when: void 0,
		primary: void 0,
B
Benjamin Pasero 已提交
497
		handler: (accessor, resource: URI, context: IEditorCommandsContext) => {
B
Benjamin Pasero 已提交
498 499 500 501 502 503
			const editorGroupService = accessor.get(IEditorGroupService);
			const editorService = accessor.get(IWorkbenchEditorService);
			const quickOpenService = accessor.get(IQuickOpenService);

			const stacks = editorGroupService.getStacksModel();
			const groupCount = stacks.groups.length;
504
			if (groupCount <= 1) {
B
Benjamin Pasero 已提交
505 506 507
				return quickOpenService.show(NAVIGATE_ALL_EDITORS_GROUP_PREFIX);
			}

B
Benjamin Pasero 已提交
508
			const { position } = positionAndInput(editorGroupService, editorService, context);
B
Benjamin Pasero 已提交
509 510 511 512 513 514 515 516 517 518 519

			switch (position) {
				case Position.TWO:
					return quickOpenService.show(NAVIGATE_IN_GROUP_TWO_PREFIX);
				case Position.THREE:
					return quickOpenService.show(NAVIGATE_IN_GROUP_THREE_PREFIX);
			}

			return quickOpenService.show(NAVIGATE_IN_GROUP_ONE_PREFIX);
		}
	});
520 521 522 523 524 525 526 527 528 529

	KeybindingsRegistry.registerCommandAndKeybindingRule({
		id: '_workbench.printStacksModel',
		weight: KeybindingsRegistry.WEIGHT.workbenchContrib(0),
		handler(accessor: ServicesAccessor) {
			console.log(`${accessor.get(IEditorGroupService).getStacksModel().toString()}\n\n`);
		},
		when: void 0,
		primary: void 0
	});
530
}
531

532
function positionAndInput(editorGroupService: IEditorGroupService, editorService: IWorkbenchEditorService, context?: IEditorCommandsContext): { position: Position, input: IEditorInput } {
B
Benjamin Pasero 已提交
533 534

	// Resolve from context
535 536 537
	const model = editorGroupService.getStacksModel();
	const group = context ? model.getGroup(context.groupId) : undefined;
	let position = group ? model.positionOfGroup(group) : undefined;
I
isidor 已提交
538
	let input = group && types.isNumber(context.editorIndex) ? group.getEditor(context.editorIndex) : undefined;
539 540 541 542

	// If position or input are not passed in take the position and input of the active editor.
	const active = editorService.getActiveEditor();
	if (active) {
543
		position = typeof position === 'number' ? position : active.group;
544 545 546 547 548
		input = input ? input : <EditorInput>active.input;
	}

	return { position, input };
}
I
isidor 已提交
549

550
export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsContext, listService: IListService, editorGroupService: INextEditorGroupsService): IEditorCommandsContext[] {
B
Benjamin Pasero 已提交
551 552
	// First check for a focused list to return the selected items from
	const list = listService.lastFocusedList;
I
isidor 已提交
553
	if (list instanceof List && list.isDOMFocused()) {
I
isidor 已提交
554
		const elementToContext = (element: IEditorIdentifier | EditorGroup) =>
I
isidor 已提交
555
			element instanceof EditorGroup ? { groupId: element.id, editorIndex: undefined } : { groupId: element.groupId, editorIndex: editorGroupService.getGroup(element.groupId).getIndexOfEditor(element.editor) };
556
		const onlyEditorGroupAndEditor = (e: IEditorIdentifier | EditorGroup) => e instanceof EditorGroup || ('editor' in e && 'group' in e);
I
isidor 已提交
557 558

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

		if (focus) {
I
isidor 已提交
563
			const selection: (IEditorIdentifier | EditorGroup)[] = list.getSelectedElements().filter(onlyEditorGroupAndEditor);
564
			// Only respect selection if it contains focused element
I
isidor 已提交
565
			if (selection && selection.some(s => s instanceof EditorGroup ? s.id === focus.groupId : s.groupId === focus.groupId && editorGroupService.getGroup(s.groupId).getIndexOfEditor(s.editor) === focus.editorIndex)) {
566 567
				return selection.map(elementToContext);
			}
I
isidor 已提交
568

569
			return [focus];
I
isidor 已提交
570 571 572
		}
	}

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