editorGroup.ts 18.3 KB
Newer Older
B
Benjamin Pasero 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

J
Joao Moreno 已提交
6
import { Event, Emitter } from 'vs/base/common/event';
B
Benjamin Pasero 已提交
7
import { Extensions, IEditorInputFactoryRegistry, EditorInput, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, CloseDirection, SideBySideEditorInput, IEditorInput, EditorsOrder } from 'vs/workbench/common/editor';
J
Johannes Rieken 已提交
8
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
9
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
10
import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
11
import { Registry } from 'vs/platform/registry/common/platform';
M
Matt Bierner 已提交
12
import { coalesce } from 'vs/base/common/arrays';
13 14
import { isEqual } from 'vs/base/common/resources';
import { IResourceInput } from 'vs/platform/editor/common/editor';
B
Benjamin Pasero 已提交
15

B
Benjamin Pasero 已提交
16 17 18 19 20 21 22
const EditorOpenPositioning = {
	LEFT: 'left',
	RIGHT: 'right',
	FIRST: 'first',
	LAST: 'last'
};

B
Benjamin Pasero 已提交
23
export interface EditorCloseEvent extends IEditorCloseEvent {
24 25 26
	editor: EditorInput;
}

27
export interface EditorIdentifier extends IEditorIdentifier {
I
isidor 已提交
28
	groupId: GroupIdentifier;
29
	editor: EditorInput;
30 31
}

B
Benjamin Pasero 已提交
32 33 34
export interface IEditorOpenOptions {
	pinned?: boolean;
	active?: boolean;
B
Benjamin Pasero 已提交
35
	index?: number;
B
Benjamin Pasero 已提交
36 37
}

38
export interface ISerializedEditorInput {
39 40 41 42
	id: string;
	value: string;
}

43
export interface ISerializedEditorGroup {
44
	id: number;
45 46
	editors: ISerializedEditorInput[];
	mru: number[];
M
Matt Bierner 已提交
47
	preview?: number;
48 49
}

50
export function isSerializedEditorGroup(obj?: any): obj is ISerializedEditorGroup {
51
	const group: ISerializedEditorGroup = obj;
52 53 54 55

	return obj && typeof obj === 'object' && Array.isArray(group.editors) && Array.isArray(group.mru);
}

B
Benjamin Pasero 已提交
56
export class EditorGroup extends Disposable {
57 58 59

	private static IDS = 0;

60 61 62
	//#region events

	private readonly _onDidEditorActivate = this._register(new Emitter<EditorInput>());
63
	readonly onDidEditorActivate = this._onDidEditorActivate.event;
64 65

	private readonly _onDidEditorOpen = this._register(new Emitter<EditorInput>());
66
	readonly onDidEditorOpen = this._onDidEditorOpen.event;
67 68

	private readonly _onDidEditorClose = this._register(new Emitter<EditorCloseEvent>());
69
	readonly onDidEditorClose = this._onDidEditorClose.event;
70 71

	private readonly _onDidEditorDispose = this._register(new Emitter<EditorInput>());
72
	readonly onDidEditorDispose = this._onDidEditorDispose.event;
73 74

	private readonly _onDidEditorBecomeDirty = this._register(new Emitter<EditorInput>());
75
	readonly onDidEditorBecomeDirty = this._onDidEditorBecomeDirty.event;
76 77

	private readonly _onDidEditorLabelChange = this._register(new Emitter<EditorInput>());
78
	readonly onDidEditorLabelChange = this._onDidEditorLabelChange.event;
79 80

	private readonly _onDidEditorMove = this._register(new Emitter<EditorInput>());
81
	readonly onDidEditorMove = this._onDidEditorMove.event;
82 83

	private readonly _onDidEditorPin = this._register(new Emitter<EditorInput>());
84
	readonly onDidEditorPin = this._onDidEditorPin.event;
85 86

	private readonly _onDidEditorUnpin = this._register(new Emitter<EditorInput>());
87
	readonly onDidEditorUnpin = this._onDidEditorUnpin.event;
88 89

	//#endregion
B
Benjamin Pasero 已提交
90

B
Benjamin Pasero 已提交
91
	private _id: GroupIdentifier;
B
Benjamin Pasero 已提交
92
	get id(): GroupIdentifier { return this._id; }
93

94 95
	private editors: EditorInput[] = [];
	private mru: EditorInput[] = [];
96

B
Benjamin Pasero 已提交
97 98
	private preview: EditorInput | null = null; // editor in preview state
	private active: EditorInput | null = null;  // editor in active state
99

B
Benjamin Pasero 已提交
100 101
	private editorOpenPositioning: ('left' | 'right' | 'first' | 'last') | undefined;
	private focusRecentEditorAfterClose: boolean | undefined;
102

103
	constructor(
104
		labelOrSerializedGroup: ISerializedEditorGroup | undefined,
105 106
		@IInstantiationService private readonly instantiationService: IInstantiationService,
		@IConfigurationService private readonly configurationService: IConfigurationService
107
	) {
108 109
		super();

110
		if (isSerializedEditorGroup(labelOrSerializedGroup)) {
B
Benjamin Pasero 已提交
111
			this._id = this.deserialize(labelOrSerializedGroup);
112
		} else {
113
			this._id = EditorGroup.IDS++;
114
		}
115

116
		this.onConfigurationUpdated();
117 118 119 120
		this.registerListeners();
	}

	private registerListeners(): void {
121
		this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)));
122 123
	}

124
	private onConfigurationUpdated(event?: IConfigurationChangeEvent): void {
125
		this.editorOpenPositioning = this.configurationService.getValue('workbench.editor.openPositioning');
126
		this.focusRecentEditorAfterClose = this.configurationService.getValue('workbench.editor.focusRecentEditorAfterClose');
B
Benjamin Pasero 已提交
127 128
	}

129
	get count(): number {
130 131 132
		return this.editors.length;
	}

B
Benjamin Pasero 已提交
133 134
	getEditors(order: EditorsOrder): EditorInput[] {
		return order === EditorsOrder.MOST_RECENTLY_ACTIVE ? this.mru.slice(0) : this.editors.slice(0);
B
Benjamin Pasero 已提交
135 136
	}

B
Benjamin Pasero 已提交
137 138
	getEditorByIndex(index: number): EditorInput | undefined {
		return this.editors[index];
139 140
	}

M
Matt Bierner 已提交
141
	get activeEditor(): EditorInput | null {
B
Benjamin Pasero 已提交
142 143 144
		return this.active;
	}

145
	isActive(editor: EditorInput): boolean {
B
Benjamin Pasero 已提交
146
		return this.matches(this.active, editor);
B
Benjamin Pasero 已提交
147 148
	}

M
Matt Bierner 已提交
149
	get previewEditor(): EditorInput | null {
B
Benjamin Pasero 已提交
150 151 152
		return this.preview;
	}

153
	isPreview(editor: EditorInput): boolean {
B
Benjamin Pasero 已提交
154
		return this.matches(this.preview, editor);
B
Benjamin Pasero 已提交
155 156
	}

157
	openEditor(candidate: EditorInput, options?: IEditorOpenOptions): EditorInput {
B
Benjamin Pasero 已提交
158 159
		const makePinned = options?.pinned;
		const makeActive = options?.active || !this.activeEditor || (!makePinned && this.matches(this.preview, this.activeEditor));
B
Benjamin Pasero 已提交
160

161 162
		const existingEditor = this.findEditor(candidate);

B
Benjamin Pasero 已提交
163
		// New editor
164 165
		if (!existingEditor) {
			const newEditor = candidate;
166
			const indexOfActive = this.indexOf(this.active);
B
Benjamin Pasero 已提交
167

168
			// Insert into specific position
169
			let targetIndex: number;
170 171 172
			if (options && typeof options.index === 'number') {
				targetIndex = options.index;
			}
B
Benjamin Pasero 已提交
173

174
			// Insert to the BEGINNING
175
			else if (this.editorOpenPositioning === EditorOpenPositioning.FIRST) {
176 177 178 179
				targetIndex = 0;
			}

			// Insert to the END
180
			else if (this.editorOpenPositioning === EditorOpenPositioning.LAST) {
181
				targetIndex = this.editors.length;
182
			}
B
Benjamin Pasero 已提交
183

184
			// Insert to the LEFT of active editor
185
			else if (this.editorOpenPositioning === EditorOpenPositioning.LEFT) {
186 187 188
				if (indexOfActive === 0 || !this.editors.length) {
					targetIndex = 0; // to the left becoming first editor in list
				} else {
189
					targetIndex = indexOfActive; // to the left of active editor
B
Benjamin Pasero 已提交
190
				}
191
			}
B
Benjamin Pasero 已提交
192

193 194 195 196 197
			// Insert to the RIGHT of active editor
			else {
				targetIndex = indexOfActive + 1;
			}

198 199
			// Insert into our list of editors if pinned or we have no preview editor
			if (makePinned || !this.preview) {
200
				this.splice(targetIndex, false, newEditor);
B
Benjamin Pasero 已提交
201 202
			}

203 204
			// Handle preview
			if (!makePinned) {
B
Benjamin Pasero 已提交
205 206

				// Replace existing preview with this editor if we have a preview
207 208
				if (this.preview) {
					const indexOfPreview = this.indexOf(this.preview);
209 210
					if (targetIndex > indexOfPreview) {
						targetIndex--; // accomodate for the fact that the preview editor closes
211 212
					}

213
					this.replaceEditor(this.preview, newEditor, targetIndex, !makeActive);
214
				}
B
Benjamin Pasero 已提交
215

216
				this.preview = newEditor;
B
Benjamin Pasero 已提交
217 218
			}

219
			// Listeners
220
			this.registerEditorListeners(newEditor);
221

B
Benjamin Pasero 已提交
222
			// Event
223
			this._onDidEditorOpen.fire(newEditor);
B
Benjamin Pasero 已提交
224

225
			// Handle active
B
Benjamin Pasero 已提交
226
			if (makeActive) {
227
				this.doSetActive(newEditor);
B
Benjamin Pasero 已提交
228
			}
229 230

			return newEditor;
B
Benjamin Pasero 已提交
231 232 233 234 235 236 237
		}

		// Existing editor
		else {

			// Pin it
			if (makePinned) {
238
				this.doPin(existingEditor);
B
Benjamin Pasero 已提交
239 240 241 242
			}

			// Activate it
			if (makeActive) {
243
				this.doSetActive(existingEditor);
B
Benjamin Pasero 已提交
244
			}
B
Benjamin Pasero 已提交
245 246 247

			// Respect index
			if (options && typeof options.index === 'number') {
248
				this.moveEditor(existingEditor, options.index);
B
Benjamin Pasero 已提交
249
			}
250 251

			return existingEditor;
B
Benjamin Pasero 已提交
252 253 254
		}
	}

B
Benjamin Pasero 已提交
255
	private registerEditorListeners(editor: EditorInput): void {
256
		const listeners = new DisposableStore();
257 258

		// Re-emit disposal of editor input as our own event
J
Joao Moreno 已提交
259
		const onceDispose = Event.once(editor.onDispose);
260
		listeners.add(onceDispose(() => {
261
			if (this.indexOf(editor) >= 0) {
262
				this._onDidEditorDispose.fire(editor);
263
			}
264 265 266
		}));

		// Re-Emit dirty state changes
267
		listeners.add(editor.onDidChangeDirty(() => {
268
			this._onDidEditorBecomeDirty.fire(editor);
269
		}));
270

B
Benjamin Pasero 已提交
271
		// Re-Emit label changes
272
		listeners.add(editor.onDidChangeLabel(() => {
273
			this._onDidEditorLabelChange.fire(editor);
B
Benjamin Pasero 已提交
274 275
		}));

276
		// Clean up dispose listeners once the editor gets closed
277
		listeners.add(this.onDidEditorClose(event => {
278
			if (event.editor.matches(editor)) {
279
				dispose(listeners);
280
			}
281
		}));
282 283
	}

B
Benjamin Pasero 已提交
284
	private replaceEditor(toReplace: EditorInput, replaceWith: EditorInput, replaceIndex: number, openNext = true): void {
285
		const event = this.doCloseEditor(toReplace, openNext, true); // optimization to prevent multiple setActive() in one call
286 287 288 289

		// We want to first add the new editor into our model before emitting the close event because
		// firing the close event can trigger a dispose on the same editor that is now being added.
		// This can lead into opening a disposed editor which is not what we want.
B
Benjamin Pasero 已提交
290
		this.splice(replaceIndex, false, replaceWith);
291 292

		if (event) {
293
			this._onDidEditorClose.fire(event);
294 295 296
		}
	}

297
	closeEditor(candidate: EditorInput, openNext = true): EditorInput | undefined {
298
		const event = this.doCloseEditor(candidate, openNext, false);
299 300

		if (event) {
301
			this._onDidEditorClose.fire(event);
302

303
			return event.editor;
304
		}
305

R
Rob Lourens 已提交
306
		return undefined;
307 308
	}

309
	private doCloseEditor(candidate: EditorInput, openNext: boolean, replaced: boolean): EditorCloseEvent | undefined {
310
		const index = this.indexOf(candidate);
B
Benjamin Pasero 已提交
311
		if (index === -1) {
312
			return undefined; // not found
B
Benjamin Pasero 已提交
313 314
		}

315 316
		const editor = this.editors[index];

B
Benjamin Pasero 已提交
317
		// Active Editor closed
B
Benjamin Pasero 已提交
318
		if (openNext && this.matches(this.active, editor)) {
B
Benjamin Pasero 已提交
319 320

			// More than one editor
B
Benjamin Pasero 已提交
321
			if (this.mru.length > 1) {
322
				let newActive: EditorInput;
323
				if (this.focusRecentEditorAfterClose) {
324
					newActive = this.mru[1]; // active editor is always first in MRU, so pick second editor after as new active
B
Benjamin Pasero 已提交
325
				} else {
326 327
					if (index === this.editors.length - 1) {
						newActive = this.editors[index - 1]; // last editor is closed, pick previous as new active
B
Benjamin Pasero 已提交
328
					} else {
329 330 331
						newActive = this.editors[index + 1]; // pick next editor as new active
					}
				}
B
Benjamin Pasero 已提交
332

333
				this.doSetActive(newActive);
B
Benjamin Pasero 已提交
334 335 336 337 338 339 340 341 342
			}

			// One Editor
			else {
				this.active = null;
			}
		}

		// Preview Editor closed
B
Benjamin Pasero 已提交
343
		if (this.matches(this.preview, editor)) {
B
Benjamin Pasero 已提交
344 345 346
			this.preview = null;
		}

B
Benjamin Pasero 已提交
347
		// Remove from arrays
B
Benjamin Pasero 已提交
348
		this.splice(index, true);
B
Benjamin Pasero 已提交
349 350

		// Event
I
isidor 已提交
351
		return { editor, replaced, index, groupId: this.id };
B
Benjamin Pasero 已提交
352 353
	}

B
Benjamin Pasero 已提交
354
	closeEditors(except: EditorInput, direction?: CloseDirection): void {
B
Benjamin Pasero 已提交
355 356 357 358 359 360
		const index = this.indexOf(except);
		if (index === -1) {
			return; // not found
		}

		// Close to the left
B
Benjamin Pasero 已提交
361
		if (direction === CloseDirection.LEFT) {
B
Benjamin Pasero 已提交
362 363 364 365 366 367
			for (let i = index - 1; i >= 0; i--) {
				this.closeEditor(this.editors[i]);
			}
		}

		// Close to the right
B
Benjamin Pasero 已提交
368
		else if (direction === CloseDirection.RIGHT) {
B
Benjamin Pasero 已提交
369 370 371 372 373 374 375
			for (let i = this.editors.length - 1; i > index; i--) {
				this.closeEditor(this.editors[i]);
			}
		}

		// Both directions
		else {
B
Benjamin Pasero 已提交
376
			this.mru.filter(e => !this.matches(e, except)).forEach(e => this.closeEditor(e));
B
Benjamin Pasero 已提交
377 378 379
		}
	}

380
	closeAllEditors(): void {
381 382

		// Optimize: close all non active editors first to produce less upstream work
B
Benjamin Pasero 已提交
383
		this.mru.filter(e => !this.matches(e, this.active)).forEach(e => this.closeEditor(e));
M
Matt Bierner 已提交
384 385 386
		if (this.active) {
			this.closeEditor(this.active);
		}
387 388
	}

389
	moveEditor(candidate: EditorInput, toIndex: number): EditorInput | undefined {
390
		const index = this.indexOf(candidate);
B
Benjamin Pasero 已提交
391 392 393 394
		if (index < 0) {
			return;
		}

395 396
		const editor = this.editors[index];

B
Benjamin Pasero 已提交
397 398 399 400 401
		// Move
		this.editors.splice(index, 1);
		this.editors.splice(toIndex, 0, editor);

		// Event
402
		this._onDidEditorMove.fire(editor);
403 404

		return editor;
B
Benjamin Pasero 已提交
405 406
	}

407
	setActive(candidate: EditorInput): EditorInput | undefined {
408 409
		const editor = this.findEditor(candidate);
		if (!editor) {
B
Benjamin Pasero 已提交
410 411 412
			return; // not found
		}

413
		this.doSetActive(editor);
414 415

		return editor;
416 417 418
	}

	private doSetActive(editor: EditorInput): void {
B
Benjamin Pasero 已提交
419
		if (this.matches(this.active, editor)) {
B
Benjamin Pasero 已提交
420 421 422 423 424
			return; // already active
		}

		this.active = editor;

B
Benjamin Pasero 已提交
425
		// Bring to front in MRU list
426 427 428
		const mruIndex = this.indexOf(editor, this.mru);
		this.mru.splice(mruIndex, 1);
		this.mru.unshift(editor);
B
Benjamin Pasero 已提交
429

B
Benjamin Pasero 已提交
430
		// Event
431
		this._onDidEditorActivate.fire(editor);
B
Benjamin Pasero 已提交
432 433
	}

434
	pin(candidate: EditorInput): EditorInput | undefined {
435 436
		const editor = this.findEditor(candidate);
		if (!editor) {
437 438 439
			return; // not found
		}

440
		this.doPin(editor);
441 442

		return editor;
443 444 445
	}

	private doPin(editor: EditorInput): void {
B
Benjamin Pasero 已提交
446 447
		if (!this.isPreview(editor)) {
			return; // can only pin a preview editor
B
Benjamin Pasero 已提交
448 449 450 451 452 453
		}

		// Convert the preview editor to be a pinned editor
		this.preview = null;

		// Event
454
		this._onDidEditorPin.fire(editor);
B
Benjamin Pasero 已提交
455 456
	}

457
	unpin(candidate: EditorInput): EditorInput | undefined {
458 459
		const editor = this.findEditor(candidate);
		if (!editor) {
460 461
			return; // not found
		}
462

463
		this.doUnpin(editor);
464 465

		return editor;
466 467 468
	}

	private doUnpin(editor: EditorInput): void {
B
Benjamin Pasero 已提交
469 470 471 472 473 474 475 476 477
		if (!this.isPinned(editor)) {
			return; // can only unpin a pinned editor
		}

		// Set new
		const oldPreview = this.preview;
		this.preview = editor;

		// Event
478
		this._onDidEditorUnpin.fire(editor);
B
Benjamin Pasero 已提交
479 480

		// Close old preview editor if any
M
Matt Bierner 已提交
481 482 483
		if (oldPreview) {
			this.closeEditor(oldPreview);
		}
B
Benjamin Pasero 已提交
484 485
	}

486 487 488
	isPinned(editor: EditorInput): boolean;
	isPinned(index: number): boolean;
	isPinned(arg1: EditorInput | number): boolean {
489 490 491 492 493 494 495 496 497 498 499
		let editor: EditorInput;
		let index: number;
		if (typeof arg1 === 'number') {
			editor = this.editors[arg1];
			index = arg1;
		} else {
			editor = arg1;
			index = this.indexOf(editor);
		}

		if (index === -1 || !editor) {
B
Benjamin Pasero 已提交
500 501 502 503 504 505 506
			return false; // editor not found
		}

		if (!this.preview) {
			return true; // no preview editor
		}

B
Benjamin Pasero 已提交
507
		return !this.matches(this.preview, editor);
B
Benjamin Pasero 已提交
508 509
	}

B
Benjamin Pasero 已提交
510
	private splice(index: number, del: boolean, editor?: EditorInput): void {
511
		const editorToDeleteOrReplace = this.editors[index];
B
Benjamin Pasero 已提交
512

513
		// Perform on editors array
514
		if (editor) {
515 516 517
			this.editors.splice(index, del ? 1 : 0, editor);
		} else {
			this.editors.splice(index, del ? 1 : 0);
518
		}
B
Benjamin Pasero 已提交
519

520
		// Add
B
Benjamin Pasero 已提交
521
		if (!del && editor) {
522 523 524 525 526 527 528 529 530 531 532 533 534
			if (this.mru.length === 0) {
				// the list of most recent editors is empty
				// so this editor can only be the most recent
				this.mru.push(editor);
			} else {
				// we have most recent editors. as such we
				// put this newly opened editor right after
				// the current most recent one because it cannot
				// be the most recently active one unless
				// it becomes active. but it is still more
				// active then any other editor in the list.
				this.mru.splice(1, 0, editor);
			}
B
Benjamin Pasero 已提交
535 536
		}

B
Benjamin Pasero 已提交
537
		// Remove / Replace
B
Benjamin Pasero 已提交
538
		else {
B
Benjamin Pasero 已提交
539 540
			const indexInMRU = this.indexOf(editorToDeleteOrReplace, this.mru);

541
			// Remove
B
Benjamin Pasero 已提交
542
			if (del && !editor) {
543
				this.mru.splice(indexInMRU, 1); // remove from MRU
B
Benjamin Pasero 已提交
544 545
			}

546
			// Replace
B
Benjamin Pasero 已提交
547
			else if (del && editor) {
548
				this.mru.splice(indexInMRU, 1, editor); // replace MRU at location
B
Benjamin Pasero 已提交
549
			}
550 551
		}
	}
B
Benjamin Pasero 已提交
552

553
	indexOf(candidate: IEditorInput | null, editors = this.editors): number {
B
Benjamin Pasero 已提交
554 555
		if (!candidate) {
			return -1;
B
Benjamin Pasero 已提交
556 557
		}

B
Benjamin Pasero 已提交
558
		for (let i = 0; i < editors.length; i++) {
B
Benjamin Pasero 已提交
559
			if (this.matches(editors[i], candidate)) {
B
Benjamin Pasero 已提交
560 561 562 563 564 565
				return i;
			}
		}

		return -1;
	}
B
Benjamin Pasero 已提交
566

567
	private findEditor(candidate: EditorInput | null): EditorInput | undefined {
568 569 570 571 572 573 574 575
		const index = this.indexOf(candidate, this.editors);
		if (index === -1) {
			return undefined;
		}

		return this.editors[index];
	}

576
	contains(candidate: EditorInput | IResourceInput, searchInSideBySideEditors?: boolean): boolean {
577 578 579 580
		for (const editor of this.editors) {
			if (this.matches(editor, candidate)) {
				return true;
			}
581

582 583 584 585 586
			if (searchInSideBySideEditors && editor instanceof SideBySideEditorInput) {
				if (this.matches(editor.master, candidate) || this.matches(editor.details, candidate)) {
					return true;
				}
			}
587 588 589 590 591
		}

		return false;
	}

592 593 594 595 596 597 598 599 600 601 602 603
	private matches(editor: IEditorInput | null, candidate: IEditorInput | IResourceInput | null): boolean {
		if (!editor || !candidate) {
			return false;
		}

		if (candidate instanceof EditorInput) {
			return editor.matches(candidate);
		}

		const resource = editor.getResource();

		return !!(resource && isEqual(resource, (candidate as IResourceInput).resource));
B
Benjamin Pasero 已提交
604
	}
605

606
	clone(): EditorGroup {
R
Rob Lourens 已提交
607
		const group = this.instantiationService.createInstance(EditorGroup, undefined);
608 609 610 611 612 613 614 615 616 617
		group.editors = this.editors.slice(0);
		group.mru = this.mru.slice(0);
		group.preview = this.preview;
		group.active = this.active;
		group.editorOpenPositioning = this.editorOpenPositioning;

		return group;
	}

	serialize(): ISerializedEditorGroup {
618
		const registry = Registry.as<IEditorInputFactoryRegistry>(Extensions.EditorInputFactories);
619 620 621 622 623 624

		// Serialize all editor inputs so that we can store them.
		// Editors that cannot be serialized need to be ignored
		// from mru, active and preview if any.
		let serializableEditors: EditorInput[] = [];
		let serializedEditors: ISerializedEditorInput[] = [];
M
Matt Bierner 已提交
625
		let serializablePreviewIndex: number | undefined;
626
		this.editors.forEach(e => {
627
			const factory = registry.getEditorInputFactory(e.getTypeId());
628
			if (factory) {
629
				const value = factory.serialize(e);
630
				if (typeof value === 'string') {
631
					serializedEditors.push({ id: e.getTypeId(), value });
632
					serializableEditors.push(e);
B
Benjamin Pasero 已提交
633 634 635 636

					if (this.preview === e) {
						serializablePreviewIndex = serializableEditors.length - 1;
					}
637 638 639 640
				}
			}
		});

B
Benjamin Pasero 已提交
641
		const serializableMru = this.mru.map(e => this.indexOf(e, serializableEditors)).filter(i => i >= 0);
642 643

		return {
644
			id: this.id,
645 646
			editors: serializedEditors,
			mru: serializableMru,
B
Benjamin Pasero 已提交
647
			preview: serializablePreviewIndex,
648 649 650
		};
	}

B
Benjamin Pasero 已提交
651
	private deserialize(data: ISerializedEditorGroup): number {
652
		const registry = Registry.as<IEditorInputFactoryRegistry>(Extensions.EditorInputFactories);
653

654 655 656 657 658 659 660 661
		if (typeof data.id === 'number') {
			this._id = data.id;

			EditorGroup.IDS = Math.max(data.id + 1, EditorGroup.IDS); // make sure our ID generator is always larger
		} else {
			this._id = EditorGroup.IDS++; // backwards compatibility
		}

M
Matt Bierner 已提交
662
		this.editors = coalesce(data.editors.map(e => {
B
Benjamin Pasero 已提交
663 664
			const factory = registry.getEditorInputFactory(e.id);
			if (factory) {
B
Benjamin Pasero 已提交
665 666 667 668
				const editor = factory.deserialize(this.instantiationService, e.value);
				if (editor) {
					this.registerEditorListeners(editor);
				}
669

B
Benjamin Pasero 已提交
670 671 672 673
				return editor;
			}

			return null;
M
Matt Bierner 已提交
674
		}));
B
Benjamin Pasero 已提交
675

676
		this.mru = data.mru.map(i => this.editors[i]);
B
Benjamin Pasero 已提交
677

678
		this.active = this.mru[0];
B
Benjamin Pasero 已提交
679

M
Matt Bierner 已提交
680 681 682
		if (typeof data.preview === 'number') {
			this.preview = this.editors[data.preview];
		}
B
Benjamin Pasero 已提交
683 684

		return this._id;
685 686
	}
}