editorGroup.ts 18.3 KB
Newer Older
B
Benjamin Pasero 已提交
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.
 *--------------------------------------------------------------------------------------------*/

'use strict';

M
Matt Bierner 已提交
8
import { Event, Emitter, once } from 'vs/base/common/event';
9
import { Extensions, IEditorInputFactoryRegistry, EditorInput, toResource, ILegacyEditorGroup, IEditorIdentifier, IEditorCloseEvent, GroupIdentifier, SideBySideEditorInput, CloseDirection } from 'vs/workbench/common/editor';
10
import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
11
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
12
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
13
import { dispose, IDisposable, Disposable } from 'vs/base/common/lifecycle';
14
import { Registry } from 'vs/platform/registry/common/platform';
B
wip  
Benjamin Pasero 已提交
15
import { ResourceMap } from 'vs/base/common/map';
B
Benjamin Pasero 已提交
16

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

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

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

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

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

44
export interface ISerializedEditorGroup {
45
	id: number;
46 47 48 49 50
	editors: ISerializedEditorInput[];
	mru: number[];
	preview: number;
}

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

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

57
export class EditorGroup extends Disposable implements ILegacyEditorGroup {
58 59 60

	private static IDS = 0;

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
	//#region events

	private readonly _onDidEditorActivate = this._register(new Emitter<EditorInput>());
	get onDidEditorActivate(): Event<EditorInput> { return this._onDidEditorActivate.event; }

	private readonly _onDidEditorOpen = this._register(new Emitter<EditorInput>());
	get onDidEditorOpen(): Event<EditorInput> { return this._onDidEditorOpen.event; }

	private readonly _onDidEditorClose = this._register(new Emitter<EditorCloseEvent>());
	get onDidEditorClose(): Event<EditorCloseEvent> { return this._onDidEditorClose.event; }

	private readonly _onDidEditorDispose = this._register(new Emitter<EditorInput>());
	get onDidEditorDispose(): Event<EditorInput> { return this._onDidEditorDispose.event; }

	private readonly _onDidEditorBecomeDirty = this._register(new Emitter<EditorInput>());
	get onDidEditorBecomeDirty(): Event<EditorInput> { return this._onDidEditorBecomeDirty.event; }

	private readonly _onDidEditorLabelChange = this._register(new Emitter<EditorInput>());
	get onDidEditorLabelChange(): Event<EditorInput> { return this._onDidEditorLabelChange.event; }

	private readonly _onDidEditorMove = this._register(new Emitter<EditorInput>());
	get onDidEditorMove(): Event<EditorInput> { return this._onDidEditorMove.event; }

	private readonly _onDidEditorPin = this._register(new Emitter<EditorInput>());
	get onDidEditorPin(): Event<EditorInput> { return this._onDidEditorPin.event; }

	private readonly _onDidEditorUnpin = this._register(new Emitter<EditorInput>());
	get onDidEditorUnpin(): Event<EditorInput> { return this._onDidEditorUnpin.event; }

	//#endregion
B
Benjamin Pasero 已提交
91

92 93
	private _id: GroupIdentifier;

94 95 96
	private editors: EditorInput[] = [];
	private mru: EditorInput[] = [];
	private mapResourceToEditorCount: ResourceMap<number> = new ResourceMap<number>();
97 98 99 100 101 102

	private preview: EditorInput; // editor in preview state
	private active: EditorInput;  // editor in active state

	private editorOpenPositioning: 'left' | 'right' | 'first' | 'last';

103
	constructor(
B
Benjamin Pasero 已提交
104
		labelOrSerializedGroup: ISerializedEditorGroup,
105 106
		@IInstantiationService private instantiationService: IInstantiationService,
		@IConfigurationService private configurationService: IConfigurationService
107
	) {
108 109
		super();

110 111
		if (isSerializedEditorGroup(labelOrSerializedGroup)) {
			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');
B
Benjamin Pasero 已提交
126 127
	}

128
	get id(): GroupIdentifier {
129 130 131
		return this._id;
	}

132
	get count(): number {
133 134 135
		return this.editors.length;
	}

136
	getEditors(mru?: boolean): EditorInput[] {
B
Benjamin Pasero 已提交
137
		return mru ? this.mru.slice(0) : this.editors.slice(0);
B
Benjamin Pasero 已提交
138 139
	}

140 141 142
	getEditor(index: number): EditorInput;
	getEditor(resource: URI): EditorInput;
	getEditor(arg1: any): EditorInput {
B
Benjamin Pasero 已提交
143 144 145 146 147 148 149 150 151 152 153
		if (typeof arg1 === 'number') {
			return this.editors[arg1];
		}

		const resource: URI = arg1;
		if (!this.contains(resource)) {
			return null; // fast check for resource opened or not
		}

		for (let i = 0; i < this.editors.length; i++) {
			const editor = this.editors[i];
154
			const editorResource = toResource(editor, { supportSideBySide: true });
B
Benjamin Pasero 已提交
155
			if (editorResource && editorResource.toString() === resource.toString()) {
B
Benjamin Pasero 已提交
156
				return editor;
B
Benjamin Pasero 已提交
157 158 159 160
			}
		}

		return null;
161 162
	}

163
	get activeEditor(): EditorInput {
B
Benjamin Pasero 已提交
164 165 166
		return this.active;
	}

167
	isActive(editor: EditorInput): boolean {
B
Benjamin Pasero 已提交
168
		return this.matches(this.active, editor);
B
Benjamin Pasero 已提交
169 170
	}

171
	get previewEditor(): EditorInput {
B
Benjamin Pasero 已提交
172 173 174
		return this.preview;
	}

175
	isPreview(editor: EditorInput): boolean {
B
Benjamin Pasero 已提交
176
		return this.matches(this.preview, editor);
B
Benjamin Pasero 已提交
177 178
	}

179
	openEditor(editor: EditorInput, options?: IEditorOpenOptions): void {
B
Benjamin Pasero 已提交
180 181 182
		const index = this.indexOf(editor);

		const makePinned = options && options.pinned;
B
Benjamin Pasero 已提交
183
		const makeActive = (options && options.active) || !this.activeEditor || (!makePinned && this.matches(this.preview, this.activeEditor));
B
Benjamin Pasero 已提交
184 185 186

		// New editor
		if (index === -1) {
187 188
			let targetIndex: number;
			const indexOfActive = this.indexOf(this.active);
B
Benjamin Pasero 已提交
189

190 191 192 193
			// Insert into specific position
			if (options && typeof options.index === 'number') {
				targetIndex = options.index;
			}
B
Benjamin Pasero 已提交
194

195
			// Insert to the BEGINNING
196
			else if (this.editorOpenPositioning === EditorOpenPositioning.FIRST) {
197 198 199 200
				targetIndex = 0;
			}

			// Insert to the END
201
			else if (this.editorOpenPositioning === EditorOpenPositioning.LAST) {
202
				targetIndex = this.editors.length;
203
			}
B
Benjamin Pasero 已提交
204

205
			// Insert to the LEFT of active editor
206
			else if (this.editorOpenPositioning === EditorOpenPositioning.LEFT) {
207 208 209
				if (indexOfActive === 0 || !this.editors.length) {
					targetIndex = 0; // to the left becoming first editor in list
				} else {
210
					targetIndex = indexOfActive; // to the left of active editor
B
Benjamin Pasero 已提交
211
				}
212
			}
B
Benjamin Pasero 已提交
213

214 215 216 217 218
			// Insert to the RIGHT of active editor
			else {
				targetIndex = indexOfActive + 1;
			}

219 220 221
			// Insert into our list of editors if pinned or we have no preview editor
			if (makePinned || !this.preview) {
				this.splice(targetIndex, false, editor);
B
Benjamin Pasero 已提交
222 223
			}

224 225
			// Handle preview
			if (!makePinned) {
B
Benjamin Pasero 已提交
226 227

				// Replace existing preview with this editor if we have a preview
228 229
				if (this.preview) {
					const indexOfPreview = this.indexOf(this.preview);
230 231
					if (targetIndex > indexOfPreview) {
						targetIndex--; // accomodate for the fact that the preview editor closes
232 233
					}

234
					this.replaceEditor(this.preview, editor, targetIndex, !makeActive);
235
				}
B
Benjamin Pasero 已提交
236

B
Benjamin Pasero 已提交
237 238 239
				this.preview = editor;
			}

240
			// Listeners
B
Benjamin Pasero 已提交
241
			this.registerEditorListeners(editor);
242

B
Benjamin Pasero 已提交
243
			// Event
244
			this._onDidEditorOpen.fire(editor);
B
Benjamin Pasero 已提交
245

246
			// Handle active
B
Benjamin Pasero 已提交
247
			if (makeActive) {
B
Benjamin Pasero 已提交
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
				this.setActive(editor);
			}
		}

		// Existing editor
		else {

			// Pin it
			if (makePinned) {
				this.pin(editor);
			}

			// Activate it
			if (makeActive) {
				this.setActive(editor);
			}
B
Benjamin Pasero 已提交
264 265 266 267 268

			// Respect index
			if (options && typeof options.index === 'number') {
				this.moveEditor(editor, options.index);
			}
B
Benjamin Pasero 已提交
269 270 271
		}
	}

B
Benjamin Pasero 已提交
272
	private registerEditorListeners(editor: EditorInput): void {
273
		const unbind: IDisposable[] = [];
274 275

		// Re-emit disposal of editor input as our own event
276 277
		const onceDispose = once(editor.onDispose);
		unbind.push(onceDispose(() => {
278
			if (this.indexOf(editor) >= 0) {
279
				this._onDidEditorDispose.fire(editor);
280
			}
281 282 283 284
		}));

		// Re-Emit dirty state changes
		unbind.push(editor.onDidChangeDirty(() => {
285
			this._onDidEditorBecomeDirty.fire(editor);
286
		}));
287

B
Benjamin Pasero 已提交
288 289
		// Re-Emit label changes
		unbind.push(editor.onDidChangeLabel(() => {
290
			this._onDidEditorLabelChange.fire(editor);
B
Benjamin Pasero 已提交
291 292
		}));

293
		// Clean up dispose listeners once the editor gets closed
294
		unbind.push(this.onDidEditorClose(event => {
295
			if (event.editor.matches(editor)) {
296
				dispose(unbind);
297
			}
298
		}));
299 300
	}

301 302
	private replaceEditor(toReplace: EditorInput, replaceWidth: EditorInput, replaceIndex: number, openNext = true): void {
		const event = this.doCloseEditor(toReplace, openNext, true); // optimization to prevent multiple setActive() in one call
303 304 305 306 307 308 309

		// 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.
		this.splice(replaceIndex, false, replaceWidth);

		if (event) {
310
			this._onDidEditorClose.fire(event);
311 312 313
		}
	}

314
	closeEditor(editor: EditorInput, openNext = true): number {
315
		const event = this.doCloseEditor(editor, openNext, false);
316 317

		if (event) {
318
			this._onDidEditorClose.fire(event);
319 320

			return event.index;
321
		}
322 323

		return void 0;
324 325
	}

326
	private doCloseEditor(editor: EditorInput, openNext: boolean, replaced: boolean): EditorCloseEvent {
B
Benjamin Pasero 已提交
327 328
		const index = this.indexOf(editor);
		if (index === -1) {
329
			return null; // not found
B
Benjamin Pasero 已提交
330 331 332
		}

		// Active Editor closed
B
Benjamin Pasero 已提交
333
		if (openNext && this.matches(this.active, editor)) {
B
Benjamin Pasero 已提交
334 335

			// More than one editor
B
Benjamin Pasero 已提交
336 337
			if (this.mru.length > 1) {
				this.setActive(this.mru[1]); // active editor is always first in MRU, so pick second editor after as new active
B
Benjamin Pasero 已提交
338 339 340 341 342 343 344 345 346
			}

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

		// Preview Editor closed
B
Benjamin Pasero 已提交
347
		if (this.matches(this.preview, editor)) {
B
Benjamin Pasero 已提交
348 349 350
			this.preview = null;
		}

B
Benjamin Pasero 已提交
351
		// Remove from arrays
B
Benjamin Pasero 已提交
352
		this.splice(index, true);
B
Benjamin Pasero 已提交
353 354

		// Event
I
isidor 已提交
355
		return { editor, replaced, index, groupId: this.id };
B
Benjamin Pasero 已提交
356 357
	}

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

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

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

		// Both directions
		else {
B
Benjamin Pasero 已提交
380
			this.mru.filter(e => !this.matches(e, except)).forEach(e => this.closeEditor(e));
B
Benjamin Pasero 已提交
381 382 383
		}
	}

384
	closeAllEditors(): void {
385 386

		// Optimize: close all non active editors first to produce less upstream work
B
Benjamin Pasero 已提交
387
		this.mru.filter(e => !this.matches(e, this.active)).forEach(e => this.closeEditor(e));
388 389 390
		this.closeEditor(this.active);
	}

391
	moveEditor(editor: EditorInput, toIndex: number): void {
B
Benjamin Pasero 已提交
392 393 394 395 396 397 398 399 400 401
		const index = this.indexOf(editor);
		if (index < 0) {
			return;
		}

		// Move
		this.editors.splice(index, 1);
		this.editors.splice(toIndex, 0, editor);

		// Event
402
		this._onDidEditorMove.fire(editor);
B
Benjamin Pasero 已提交
403 404
	}

405
	setActive(editor: EditorInput): void {
B
Benjamin Pasero 已提交
406 407 408 409 410
		const index = this.indexOf(editor);
		if (index === -1) {
			return; // not found
		}

B
Benjamin Pasero 已提交
411
		if (this.matches(this.active, editor)) {
B
Benjamin Pasero 已提交
412 413 414 415 416
			return; // already active
		}

		this.active = editor;

B
Benjamin Pasero 已提交
417
		// Bring to front in MRU list
B
Benjamin Pasero 已提交
418 419
		this.setMostRecentlyUsed(editor);

B
Benjamin Pasero 已提交
420
		// Event
421
		this._onDidEditorActivate.fire(editor);
B
Benjamin Pasero 已提交
422 423
	}

424
	pin(editor: EditorInput): void {
425 426 427 428 429
		const index = this.indexOf(editor);
		if (index === -1) {
			return; // not found
		}

B
Benjamin Pasero 已提交
430 431
		if (!this.isPreview(editor)) {
			return; // can only pin a preview editor
B
Benjamin Pasero 已提交
432 433 434 435 436 437
		}

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

		// Event
438
		this._onDidEditorPin.fire(editor);
B
Benjamin Pasero 已提交
439 440
	}

441
	unpin(editor: EditorInput): void {
442 443 444 445
		const index = this.indexOf(editor);
		if (index === -1) {
			return; // not found
		}
446

B
Benjamin Pasero 已提交
447 448 449 450 451 452 453 454 455
		if (!this.isPinned(editor)) {
			return; // can only unpin a pinned editor
		}

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

		// Event
456
		this._onDidEditorUnpin.fire(editor);
B
Benjamin Pasero 已提交
457 458 459 460 461

		// Close old preview editor if any
		this.closeEditor(oldPreview);
	}

462 463 464
	isPinned(editor: EditorInput): boolean;
	isPinned(index: number): boolean;
	isPinned(arg1: EditorInput | number): boolean {
465 466 467 468 469 470 471 472 473 474 475
		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 已提交
476 477 478 479 480 481 482
			return false; // editor not found
		}

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

B
Benjamin Pasero 已提交
483
		return !this.matches(this.preview, editor);
B
Benjamin Pasero 已提交
484 485
	}

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

B
Benjamin Pasero 已提交
489
		const args: any[] = [index, del ? 1 : 0];
490 491 492
		if (editor) {
			args.push(editor);
		}
B
Benjamin Pasero 已提交
493

494
		// Perform on editors array
495
		this.editors.splice.apply(this.editors, args);
B
Benjamin Pasero 已提交
496

497
		// Add
B
Benjamin Pasero 已提交
498
		if (!del && editor) {
499 500
			this.mru.push(editor); // make it LRU editor
			this.updateResourceMap(editor, false /* add */); // add new to resource map
B
Benjamin Pasero 已提交
501 502
		}

B
Benjamin Pasero 已提交
503
		// Remove / Replace
B
Benjamin Pasero 已提交
504
		else {
B
Benjamin Pasero 已提交
505 506
			const indexInMRU = this.indexOf(editorToDeleteOrReplace, this.mru);

507
			// Remove
B
Benjamin Pasero 已提交
508
			if (del && !editor) {
509 510
				this.mru.splice(indexInMRU, 1); // remove from MRU
				this.updateResourceMap(editorToDeleteOrReplace, true /* delete */); // remove from resource map
B
Benjamin Pasero 已提交
511 512
			}

513
			// Replace
B
Benjamin Pasero 已提交
514
			else {
515 516 517
				this.mru.splice(indexInMRU, 1, editor); // replace MRU at location
				this.updateResourceMap(editor, false /* add */); // add new to resource map
				this.updateResourceMap(editorToDeleteOrReplace, true /* delete */); // remove replaced from resource map
B
Benjamin Pasero 已提交
518
			}
B
Benjamin Pasero 已提交
519 520 521
		}
	}

522
	private updateResourceMap(editor: EditorInput, remove: boolean): void {
523
		const resource = toResource(editor, { supportSideBySide: true });
524
		if (resource) {
525 526 527

			// It is possible to have the same resource opened twice (once as normal input and once as diff input)
			// So we need to do ref counting on the resource to provide the correct picture
B
wip  
Benjamin Pasero 已提交
528
			let counter = this.mapResourceToEditorCount.get(resource) || 0;
B
Benjamin Pasero 已提交
529
			let newCounter: number;
530 531 532 533 534 535 536 537
			if (remove) {
				if (counter > 1) {
					newCounter = counter - 1;
				}
			} else {
				newCounter = counter + 1;
			}

B
wip  
Benjamin Pasero 已提交
538
			this.mapResourceToEditorCount.set(resource, newCounter);
539 540 541
		}
	}

542
	indexOf(candidate: EditorInput, editors = this.editors): number {
B
Benjamin Pasero 已提交
543 544
		if (!candidate) {
			return -1;
B
Benjamin Pasero 已提交
545 546
		}

B
Benjamin Pasero 已提交
547
		for (let i = 0; i < editors.length; i++) {
B
Benjamin Pasero 已提交
548
			if (this.matches(editors[i], candidate)) {
B
Benjamin Pasero 已提交
549 550 551 552 553 554
				return i;
			}
		}

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

556 557 558
	contains(editorOrResource: EditorInput | URI): boolean;
	contains(editor: EditorInput, supportSideBySide?: boolean): boolean;
	contains(editorOrResource: EditorInput | URI, supportSideBySide?: boolean): boolean {
559
		if (editorOrResource instanceof EditorInput) {
560 561 562 563 564 565 566 567 568 569 570 571 572
			const index = this.indexOf(editorOrResource);
			if (index >= 0) {
				return true;
			}

			if (supportSideBySide && editorOrResource instanceof SideBySideEditorInput) {
				const index = this.indexOf(editorOrResource.master);
				if (index >= 0) {
					return true;
				}
			}

			return false;
573 574
		}

575
		const counter = this.mapResourceToEditorCount.get(editorOrResource);
576 577

		return typeof counter === 'number' && counter > 0;
578 579
	}

B
Benjamin Pasero 已提交
580 581 582 583 584 585 586 587 588
	private setMostRecentlyUsed(editor: EditorInput): void {
		const index = this.indexOf(editor);
		if (index === -1) {
			return; // editor not found
		}

		const mruIndex = this.indexOf(editor, this.mru);

		// Remove old index
B
Benjamin Pasero 已提交
589
		this.mru.splice(mruIndex, 1);
B
Benjamin Pasero 已提交
590

B
Benjamin Pasero 已提交
591
		// Set editor to front
B
Benjamin Pasero 已提交
592 593
		this.mru.unshift(editor);
	}
B
Benjamin Pasero 已提交
594 595 596 597

	private matches(editorA: EditorInput, editorB: EditorInput): boolean {
		return !!editorA && !!editorB && editorA.matches(editorB);
	}
598

599
	clone(): EditorGroup {
B
Benjamin Pasero 已提交
600
		const group = this.instantiationService.createInstance(EditorGroup, void 0);
601 602 603 604 605 606 607 608 609 610 611
		group.editors = this.editors.slice(0);
		group.mru = this.mru.slice(0);
		group.mapResourceToEditorCount = this.mapResourceToEditorCount.clone();
		group.preview = this.preview;
		group.active = this.active;
		group.editorOpenPositioning = this.editorOpenPositioning;

		return group;
	}

	serialize(): ISerializedEditorGroup {
612
		const registry = Registry.as<IEditorInputFactoryRegistry>(Extensions.EditorInputFactories);
613 614 615 616 617 618

		// 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[] = [];
B
Benjamin Pasero 已提交
619
		let serializablePreviewIndex: number;
620
		this.editors.forEach(e => {
621
			let factory = registry.getEditorInputFactory(e.getTypeId());
622 623 624
			if (factory) {
				let value = factory.serialize(e);
				if (typeof value === 'string') {
625
					serializedEditors.push({ id: e.getTypeId(), value });
626
					serializableEditors.push(e);
B
Benjamin Pasero 已提交
627 628 629 630

					if (this.preview === e) {
						serializablePreviewIndex = serializableEditors.length - 1;
					}
631 632 633 634
				}
			}
		});

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

		return {
638
			id: this.id,
639 640
			editors: serializedEditors,
			mru: serializableMru,
B
Benjamin Pasero 已提交
641
			preview: serializablePreviewIndex,
642 643 644 645
		};
	}

	private deserialize(data: ISerializedEditorGroup): void {
646
		const registry = Registry.as<IEditorInputFactoryRegistry>(Extensions.EditorInputFactories);
647

648 649 650 651 652 653 654 655
		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
		}

656
		this.editors = data.editors.map(e => {
B
Benjamin Pasero 已提交
657 658 659
			const factory = registry.getEditorInputFactory(e.id);
			if (factory) {
				const editor = factory.deserialize(this.instantiationService, e.value);
660

B
Benjamin Pasero 已提交
661
				this.registerEditorListeners(editor);
B
Benjamin Pasero 已提交
662
				this.updateResourceMap(editor, false /* add */);
663

B
Benjamin Pasero 已提交
664 665 666 667 668
				return editor;
			}

			return null;
		}).filter(e => !!e);
669 670 671 672 673
		this.mru = data.mru.map(i => this.editors[i]);
		this.active = this.mru[0];
		this.preview = this.editors[data.preview];
	}
}