notebookServiceImpl.ts 38.8 KB
Newer Older
R
rebornix 已提交
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.
 *--------------------------------------------------------------------------------------------*/

R
rebornix 已提交
6
import * as nls from 'vs/nls';
R
rebornix 已提交
7
import { Disposable, IDisposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
8
import { URI, UriComponents } from 'vs/base/common/uri';
9 10
import { notebookProviderExtensionPoint, notebookRendererExtensionPoint, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/extensionPoint';
import { NotebookProviderInfo, NotebookEditorDescriptor } from 'vs/workbench/contrib/notebook/common/notebookProvider';
R
rebornix 已提交
11
import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol';
R
rebornix 已提交
12
import { Emitter, Event } from 'vs/base/common/event';
13
import { INotebookTextModel, INotebookRendererInfo, INotebookKernelInfo, CellOutputKind, ITransformedDisplayOutputDto, IDisplayOutput, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, NOTEBOOK_DISPLAY_ORDER, sortMimeTypes, IOrderedMimeType, mimeTypeSupportedByCore, IOutputRenderRequestOutputInfo, IOutputRenderRequestCellInfo, NotebookCellOutputsSplice, ICellEditOperation, CellEditType, ICellInsertEdit, IOutputRenderResponse, IProcessedOutput, BUILTIN_RENDERER_ID, NotebookEditorPriority, INotebookKernelProvider, notebookDocumentFilterMatch, INotebookKernelInfo2, CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
14
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
R
rebornix 已提交
15
import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer';
J
Johannes Rieken 已提交
16
import { Iterable } from 'vs/base/common/iterator';
17
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
R
rebornix 已提交
18
import { CancellationToken } from 'vs/base/common/cancellation';
19
import { IEditorService, ICustomEditorViewTypesHandler, ICustomEditorInfo } from 'vs/workbench/services/editor/common/editorService';
R
rebornix 已提交
20
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
21
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/common/notebookService';
R
rebornix 已提交
22
import * as glob from 'vs/base/common/glob';
R
rebornix 已提交
23
import { basename } from 'vs/base/common/path';
R
rebornix 已提交
24
import { getActiveNotebookEditor, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
25 26
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
27 28 29
import { Memento } from 'vs/workbench/common/memento';
import { StorageScope, IStorageService } from 'vs/platform/storage/common/storage';
import { IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
30
import { generateUuid } from 'vs/base/common/uuid';
R
rebornix 已提交
31
import { flatten } from 'vs/base/common/arrays';
32
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
R
rebornix 已提交
33
import { NotebookKernelProviderAssociationRegistry, updateNotebookKernelProvideAssociationSchema, NotebookViewTypesExtensionRegistry } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation';
34
import { PureNotebookOutputRenderer } from 'vs/workbench/contrib/notebook/browser/notebookPureOutputRenderer';
R
rebornix 已提交
35
import { RedoCommand, UndoCommand } from 'vs/editor/browser/editorExtensions';
36 37 38
import { CopyAction, CutAction, PasteAction } from 'vs/editor/contrib/clipboard/clipboard';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
39

R
rebornix 已提交
40 41 42 43
function MODEL_ID(resource: URI): string {
	return resource.toString();
}

R
rebornix 已提交
44 45 46 47 48 49 50 51 52 53 54 55
export class NotebookKernelProviderInfoStore extends Disposable {
	private readonly _notebookKernelProviders: INotebookKernelProvider[] = [];

	constructor() {
		super();
	}

	add(provider: INotebookKernelProvider) {
		this._notebookKernelProviders.push(provider);
		this._updateProviderExtensionsInfo();

		return toDisposable(() => {
R
Rob Lourens 已提交
56
			const idx = this._notebookKernelProviders.indexOf(provider);
R
rebornix 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
			if (idx >= 0) {
				this._notebookKernelProviders.splice(idx, 1);
			}

			this._updateProviderExtensionsInfo();
		});
	}

	get(viewType: string, resource: URI) {
		return this._notebookKernelProviders.filter(provider => notebookDocumentFilterMatch(provider.selector, viewType, resource));
	}

	private _updateProviderExtensionsInfo() {
		NotebookKernelProviderAssociationRegistry.extensionIds.length = 0;
		NotebookKernelProviderAssociationRegistry.extensionDescriptions.length = 0;

		this._notebookKernelProviders.forEach(provider => {
			NotebookKernelProviderAssociationRegistry.extensionIds.push(provider.providerExtensionId);
			NotebookKernelProviderAssociationRegistry.extensionDescriptions.push(provider.providerDescription || '');
		});

		updateNotebookKernelProvideAssociationSchema();
	}
}

82
export class NotebookProviderInfoStore extends Disposable {
83 84 85 86
	private static readonly CUSTOM_EDITORS_STORAGE_ID = 'notebookEditors';
	private static readonly CUSTOM_EDITORS_ENTRY_ID = 'editors';

	private readonly _memento: Memento;
87 88 89 90 91 92 93
	private _handled: boolean = false;
	constructor(
		storageService: IStorageService,
		extensionService: IExtensionService

	) {
		super();
94 95 96 97 98 99
		this._memento = new Memento(NotebookProviderInfoStore.CUSTOM_EDITORS_STORAGE_ID, storageService);

		const mementoObject = this._memento.getMemento(StorageScope.GLOBAL);
		for (const info of (mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] || []) as NotebookEditorDescriptor[]) {
			this.add(new NotebookProviderInfo(info));
		}
100

R
rebornix 已提交
101 102
		this._updateProviderExtensionsInfo();

103 104 105 106 107 108 109
		this._register(extensionService.onDidRegisterExtensions(() => {
			if (!this._handled) {
				// there is no extension point registered for notebook content provider
				// clear the memento and cache
				this.clear();
				mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = [];
				this._memento.saveMemento();
R
rebornix 已提交
110 111

				this._updateProviderExtensionsInfo();
112 113
			}
		}));
114 115
	}

116 117
	setupHandler(extensions: readonly IExtensionPointUser<INotebookEditorContribution[]>[]) {
		this._handled = true;
118 119 120 121 122 123 124 125
		this.clear();

		for (const extension of extensions) {
			for (const notebookContribution of extension.value) {
				this.add(new NotebookProviderInfo({
					id: notebookContribution.viewType,
					displayName: notebookContribution.displayName,
					selector: notebookContribution.selector || [],
R
rebornix 已提交
126
					priority: this._convertPriority(notebookContribution.priority),
R
rebornix 已提交
127 128
					providerExtensionId: extension.description.identifier.value,
					providerDescription: extension.description.description,
129 130 131 132 133 134 135
					providerDisplayName: extension.description.isBuiltin ? nls.localize('builtinProviderDisplayName', "Built-in") : extension.description.displayName || extension.description.identifier.value,
					providerExtensionLocation: extension.description.extensionLocation
				}));
			}
		}

		const mementoObject = this._memento.getMemento(StorageScope.GLOBAL);
R
rebornix 已提交
136
		mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = Array.from(this._contributedEditors.values());
137
		this._memento.saveMemento();
R
rebornix 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153

		this._updateProviderExtensionsInfo();
	}

	private _updateProviderExtensionsInfo() {
		NotebookViewTypesExtensionRegistry.viewTypes.length = 0;
		NotebookViewTypesExtensionRegistry.viewTypeDescriptions.length = 0;

		for (const contribute of this._contributedEditors) {
			if (contribute[1].providerExtensionId) {
				NotebookViewTypesExtensionRegistry.viewTypes.push(contribute[1].id);
				NotebookViewTypesExtensionRegistry.viewTypeDescriptions.push(`${contribute[1].displayName}`);
			}
		}

		updateNotebookKernelProvideAssociationSchema();
154 155
	}

R
rebornix 已提交
156
	private _convertPriority(priority?: string) {
157 158 159 160 161 162 163 164 165 166 167 168
		if (!priority) {
			return NotebookEditorPriority.default;
		}

		if (priority === NotebookEditorPriority.default) {
			return NotebookEditorPriority.default;
		}

		return NotebookEditorPriority.option;

	}

R
rebornix 已提交
169
	private readonly _contributedEditors = new Map<string, NotebookProviderInfo>();
R
rebornix 已提交
170

R
rebornix 已提交
171
	clear() {
R
rebornix 已提交
172
		this._contributedEditors.clear();
R
rebornix 已提交
173 174
	}

R
rebornix 已提交
175
	get(viewType: string): NotebookProviderInfo | undefined {
R
rebornix 已提交
176
		return this._contributedEditors.get(viewType);
R
rebornix 已提交
177 178
	}

R
rebornix 已提交
179
	add(info: NotebookProviderInfo): void {
R
rebornix 已提交
180
		if (this._contributedEditors.has(info.id)) {
R
rebornix 已提交
181 182
			return;
		}
R
rebornix 已提交
183
		this._contributedEditors.set(info.id, info);
R
rebornix 已提交
184 185
	}

R
rebornix 已提交
186
	getContributedNotebook(resource: URI): readonly NotebookProviderInfo[] {
R
rebornix 已提交
187
		return [...Iterable.filter(this._contributedEditors.values(), customEditor => resource.scheme === 'untitled' || customEditor.matches(resource))];
R
rebornix 已提交
188
	}
189 190

	public [Symbol.iterator](): Iterator<NotebookProviderInfo> {
R
rebornix 已提交
191
		return this._contributedEditors.values();
192
	}
R
rebornix 已提交
193 194
}

R
rebornix 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
export class NotebookOutputRendererInfoStore {
	private readonly contributedRenderers = new Map<string, NotebookOutputRendererInfo>();

	clear() {
		this.contributedRenderers.clear();
	}

	get(viewType: string): NotebookOutputRendererInfo | undefined {
		return this.contributedRenderers.get(viewType);
	}

	add(info: NotebookOutputRendererInfo): void {
		if (this.contributedRenderers.has(info.id)) {
			return;
		}
		this.contributedRenderers.set(info.id, info);
	}

	getContributedRenderer(mimeType: string): readonly NotebookOutputRendererInfo[] {
		return Array.from(this.contributedRenderers.values()).filter(customEditor =>
			customEditor.matches(mimeType));
	}
}

R
rebornix 已提交
219 220 221 222
class ModelData implements IDisposable {
	private readonly _modelEventListeners = new DisposableStore();

	constructor(
223 224
		public model: NotebookTextModel,
		onWillDispose: (model: INotebookTextModel) => void
R
rebornix 已提交
225 226 227 228
	) {
		this._modelEventListeners.add(model.onWillDispose(() => onWillDispose(model)));
	}

R
rebornix 已提交
229
	dispose(): void {
R
rebornix 已提交
230 231 232
		this._modelEventListeners.dispose();
	}
}
233
export class NotebookService extends Disposable implements INotebookService, ICustomEditorViewTypesHandler {
234
	declare readonly _serviceBrand: undefined;
235
	static mainthreadNotebookDocumentHandle: number = 0;
R
rebornix 已提交
236
	private readonly _notebookProviders = new Map<string, { controller: IMainNotebookController, extensionData: NotebookExtensionDescription }>();
237
	private readonly _notebookRenderers = new Map<string, INotebookRendererInfo>();
R
rebornix 已提交
238
	private readonly _notebookKernels = new Map<string, INotebookKernelInfo>();
239
	notebookProviderInfoStore: NotebookProviderInfoStore;
R
rebornix 已提交
240
	notebookRenderersInfoStore: NotebookOutputRendererInfoStore = new NotebookOutputRendererInfoStore();
R
rebornix 已提交
241
	notebookKernelProviderInfoStore: NotebookKernelProviderInfoStore = new NotebookKernelProviderInfoStore();
242
	private readonly _models = new Map<string, ModelData>();
R
rebornix 已提交
243 244
	private _onDidChangeActiveEditor = new Emitter<string | null>();
	onDidChangeActiveEditor: Event<string | null> = this._onDidChangeActiveEditor.event;
R
rebornix 已提交
245
	private _activeEditorDisposables = new DisposableStore();
R
rebornix 已提交
246 247
	private _onDidChangeVisibleEditors = new Emitter<string[]>();
	onDidChangeVisibleEditors: Event<string[]> = this._onDidChangeVisibleEditors.event;
R
rebornix 已提交
248 249
	private readonly _onNotebookEditorAdd: Emitter<INotebookEditor> = this._register(new Emitter<INotebookEditor>());
	public readonly onNotebookEditorAdd: Event<INotebookEditor> = this._onNotebookEditorAdd.event;
250 251
	private readonly _onNotebookEditorsRemove: Emitter<INotebookEditor[]> = this._register(new Emitter<INotebookEditor[]>());
	public readonly onNotebookEditorsRemove: Event<INotebookEditor[]> = this._onNotebookEditorsRemove.event;
R
rebornix 已提交
252 253
	private readonly _onNotebookDocumentAdd: Emitter<URI[]> = this._register(new Emitter<URI[]>());
	public readonly onNotebookDocumentAdd: Event<URI[]> = this._onNotebookDocumentAdd.event;
254 255
	private readonly _onNotebookDocumentRemove: Emitter<URI[]> = this._register(new Emitter<URI[]>());
	public readonly onNotebookDocumentRemove: Event<URI[]> = this._onNotebookDocumentRemove.event;
256 257
	private readonly _onNotebookDocumentSaved: Emitter<URI> = this._register(new Emitter<URI>());
	public readonly onNotebookDocumentSaved: Event<URI> = this._onNotebookDocumentSaved.event;
258
	private readonly _notebookEditors = new Map<string, INotebookEditor>();
R
rebornix 已提交
259

260 261
	private readonly _onDidChangeViewTypes = new Emitter<void>();
	onDidChangeViewTypes: Event<void> = this._onDidChangeViewTypes.event;
R
rebornix 已提交
262 263 264

	private readonly _onDidChangeKernels = new Emitter<void>();
	onDidChangeKernels: Event<void> = this._onDidChangeKernels.event;
R
rebornix 已提交
265 266
	private readonly _onDidChangeNotebookActiveKernel = new Emitter<{ uri: URI, providerHandle: number | undefined, kernelId: string | undefined }>();
	onDidChangeNotebookActiveKernel: Event<{ uri: URI, providerHandle: number | undefined, kernelId: string | undefined }> = this._onDidChangeNotebookActiveKernel.event;
R
rebornix 已提交
267
	private cutItems: NotebookCellTextModel[] | undefined;
R
rebornix 已提交
268
	private _lastClipboardIsCopy: boolean = true;
269

270
	private _displayOrder: { userOrder: string[], defaultOrder: string[] } = Object.create(null);
271

272
	constructor(
R
rebornix 已提交
273 274 275 276
		@IExtensionService private readonly _extensionService: IExtensionService,
		@IEditorService private readonly _editorService: IEditorService,
		@IConfigurationService private readonly _configurationService: IConfigurationService,
		@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
277 278
		@IStorageService private readonly _storageService: IStorageService,
		@IInstantiationService private readonly _instantiationService: IInstantiationService
279
	) {
R
rebornix 已提交
280 281
		super();

282
		this.notebookProviderInfoStore = new NotebookProviderInfoStore(this._storageService, this._extensionService);
283
		this._register(this.notebookProviderInfoStore);
284

R
rebornix 已提交
285
		notebookProviderExtensionPoint.setHandler((extensions) => {
286
			this.notebookProviderInfoStore.setupHandler(extensions);
R
rebornix 已提交
287 288
		});

R
rebornix 已提交
289 290 291 292 293 294 295 296
		notebookRendererExtensionPoint.setHandler((renderers) => {
			this.notebookRenderersInfoStore.clear();

			for (const extension of renderers) {
				for (const notebookContribution of extension.value) {
					this.notebookRenderersInfoStore.add(new NotebookOutputRendererInfo({
						id: notebookContribution.viewType,
						displayName: notebookContribution.displayName,
297
						mimeTypes: notebookContribution.mimeTypes || [],
R
rebornix 已提交
298
					}));
299 300 301 302

					if (notebookContribution.entrypoint) {
						this._notebookRenderers.set(notebookContribution.viewType, new PureNotebookOutputRenderer(notebookContribution.viewType, extension.description, notebookContribution.entrypoint));
					}
R
rebornix 已提交
303 304 305 306 307
				}
			}

			// console.log(this.notebookRenderersInfoStore);
		});
308

R
rebornix 已提交
309
		this._editorService.registerCustomEditorViewTypesHandler('Notebook', this);
310 311

		const updateOrder = () => {
R
Rob Lourens 已提交
312
			const userOrder = this._configurationService.getValue<string[]>('notebook.displayOrder');
313
			this._displayOrder = {
R
rebornix 已提交
314
				defaultOrder: this._accessibilityService.isScreenReaderOptimized() ? ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER : NOTEBOOK_DISPLAY_ORDER,
315 316 317 318 319 320
				userOrder: userOrder
			};
		};

		updateOrder();

R
rebornix 已提交
321
		this._register(this._configurationService.onDidChangeConfiguration(e => {
322 323 324 325 326
			if (e.affectedKeys.indexOf('notebook.displayOrder') >= 0) {
				updateOrder();
			}
		}));

R
rebornix 已提交
327
		this._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => {
328 329
			updateOrder();
		}));
R
rebornix 已提交
330

331
		const getContext = () => {
R
rebornix 已提交
332
			const editor = getActiveNotebookEditor(this._editorService);
333 334 335 336 337 338 339 340 341 342 343
			const activeCell = editor?.getActiveCell();

			return {
				editor,
				activeCell
			};
		};

		const PRIORITY = 50;
		this._register(UndoCommand.addImplementation(PRIORITY, () => {
			const { editor } = getContext();
R
rebornix 已提交
344 345 346 347 348 349 350 351 352
			if (editor?.viewModel) {
				editor?.viewModel.undo();
				return true;
			}

			return false;
		}));

		this._register(RedoCommand.addImplementation(PRIORITY, () => {
353
			const { editor } = getContext();
R
rebornix 已提交
354 355 356 357 358 359 360
			if (editor?.viewModel) {
				editor?.viewModel.redo();
				return true;
			}

			return false;
		}));
361 362 363 364 365 366 367 368

		if (CopyAction) {
			this._register(CopyAction.addImplementation(PRIORITY, accessor => {
				const { editor, activeCell } = getContext();
				if (!editor || !activeCell) {
					return false;
				}

R
rebornix 已提交
369 370 371 372 373
				if (editor.hasOutputTextSelection()) {
					document.execCommand('copy');
					return true;
				}

374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
				const clipboardService = accessor.get<IClipboardService>(IClipboardService);
				const notebookService = accessor.get<INotebookService>(INotebookService);
				clipboardService.writeText(activeCell.getText());
				notebookService.setToCopy([activeCell.model], true);

				return true;
			}));
		}

		if (PasteAction) {
			PasteAction.addImplementation(PRIORITY, () => {
				const pasteCells = this.getToCopy();

				if (!pasteCells) {
					return false;
				}

				const { editor, activeCell } = getContext();
				if (!editor || !activeCell) {
					return false;
				}

				const viewModel = editor.viewModel;

				if (!viewModel) {
					return false;
				}

R
rebornix 已提交
402 403 404 405
				if (!viewModel.metadata.editable) {
					return false;
				}

406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
				const currCellIndex = viewModel.getCellIndex(activeCell);

				let topPastedCell: CellViewModel | undefined = undefined;
				pasteCells.items.reverse().map(cell => {
					const data = CellUri.parse(cell.uri);

					if (pasteCells.isCopy || data?.notebook.toString() !== viewModel.uri.toString()) {
						return viewModel.notebookDocument.createCellTextModel(
							cell.getValue(),
							cell.language,
							cell.cellKind,
							[],
							cell.metadata
						);
					} else {
						return cell;
					}
				}).forEach(pasteCell => {
					const newIdx = typeof currCellIndex === 'number' ? currCellIndex + 1 : 0;
					topPastedCell = viewModel.insertCell(newIdx, pasteCell, true);
				});

				if (topPastedCell) {
					editor.focusNotebookCell(topPastedCell, 'container');
				}

				return true;
			});
		}

		if (CutAction) {
			CutAction.addImplementation(PRIORITY, accessor => {
				const { editor, activeCell } = getContext();
				if (!editor || !activeCell) {
					return false;
				}

				const viewModel = editor.viewModel;

				if (!viewModel) {
					return false;
				}

R
rebornix 已提交
449 450 451 452
				if (!viewModel.metadata.editable) {
					return false;
				}

453 454 455 456 457 458 459 460 461 462
				const clipboardService = accessor.get<IClipboardService>(IClipboardService);
				const notebookService = accessor.get<INotebookService>(INotebookService);
				clipboardService.writeText(activeCell.getText());
				viewModel.deleteCell(viewModel.getCellIndex(activeCell), true);
				notebookService.setToCopy([activeCell.model], false);

				return true;
			});
		}

463 464 465 466 467 468 469 470
	}

	getViewTypes(): ICustomEditorInfo[] {
		return [...this.notebookProviderInfoStore].map(info => ({
			id: info.id,
			displayName: info.displayName,
			providerDisplayName: info.providerDisplayName
		}));
R
rebornix 已提交
471 472
	}

473 474
	async canResolve(viewType: string): Promise<boolean> {
		if (!this._notebookProviders.has(viewType)) {
R
rebornix 已提交
475
			await this._extensionService.whenInstalledExtensionsRegistered();
476
			// notebook providers/kernels/renderers might use `*` as activation event.
R
rebornix 已提交
477
			await this._extensionService.activateByEvent(`*`);
478
			// this awaits full activation of all matching extensions
R
rebornix 已提交
479
			await this._extensionService.activateByEvent(`onNotebookEditor:${viewType}`);
R
rebornix 已提交
480
		}
481
		return this._notebookProviders.has(viewType);
482 483
	}

R
rebornix 已提交
484 485
	registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: IMainNotebookController) {
		this._notebookProviders.set(viewType, { extensionData, controller });
R
rebornix 已提交
486
		this.notebookProviderInfoStore.get(viewType)!.kernel = controller.kernel;
487
		this._onDidChangeViewTypes.fire();
R
rebornix 已提交
488 489 490 491
	}

	unregisterNotebookProvider(viewType: string): void {
		this._notebookProviders.delete(viewType);
492
		this._onDidChangeViewTypes.fire();
R
rebornix 已提交
493 494
	}

495 496
	registerNotebookRenderer(id: string, renderer: INotebookRendererInfo) {
		this._notebookRenderers.set(id, renderer);
497 498
	}

499 500
	unregisterNotebookRenderer(id: string) {
		this._notebookRenderers.delete(id);
501 502
	}

R
rebornix 已提交
503 504 505 506 507 508 509 510 511
	registerNotebookKernel(notebook: INotebookKernelInfo): void {
		this._notebookKernels.set(notebook.id, notebook);
		this._onDidChangeKernels.fire();
	}

	unregisterNotebookKernel(id: string): void {
		this._notebookKernels.delete(id);
		this._onDidChangeKernels.fire();
	}
R
rebornix 已提交
512 513

	registerNotebookKernelProvider(provider: INotebookKernelProvider): IDisposable {
R
rebornix 已提交
514
		const d = this.notebookKernelProviderInfoStore.add(provider);
R
rebornix 已提交
515 516 517
		const kernelChangeEventListener = provider.onDidChangeKernels(() => {
			this._onDidChangeKernels.fire();
		});
518 519

		this._onDidChangeKernels.fire();
R
rebornix 已提交
520
		return toDisposable(() => {
R
rebornix 已提交
521
			kernelChangeEventListener.dispose();
R
rebornix 已提交
522
			d.dispose();
R
rebornix 已提交
523 524 525 526
		});
	}

	async getContributedNotebookKernels2(viewType: string, resource: URI, token: CancellationToken): Promise<INotebookKernelInfo2[]> {
R
rebornix 已提交
527
		const filteredProvider = this.notebookKernelProviderInfoStore.get(viewType, resource);
R
rebornix 已提交
528 529 530 531 532 533 534
		const result = new Array<INotebookKernelInfo2[]>(filteredProvider.length);

		const promises = filteredProvider.map(async (provider, index) => {
			const data = await provider.provideKernels(resource, token);
			result[index] = data.map(dto => {
				return {
					extension: dto.extension,
R
rebornix 已提交
535
					extensionLocation: URI.revive(dto.extensionLocation),
R
rebornix 已提交
536 537 538 539 540
					id: dto.id,
					label: dto.label,
					description: dto.description,
					isPreferred: dto.isPreferred,
					preloads: dto.preloads,
R
rebornix 已提交
541
					providerHandle: dto.providerHandle,
R
rebornix 已提交
542 543
					resolve: async (uri: URI, editorId: string, token: CancellationToken) => {
						return provider.resolveKernel(editorId, uri, dto.id, token);
R
rebornix 已提交
544
					},
R
Rob Lourens 已提交
545 546
					executeNotebookCell: async (uri: URI, handle: number | undefined) => {
						return provider.executeNotebook(uri, dto.id, handle);
547 548 549
					},
					cancelNotebookCell: (uri: URI, handle: number | undefined): Promise<void> => {
						return provider.cancelNotebook(uri, dto.id, handle);
R
rebornix 已提交
550 551 552 553 554 555 556 557 558
					}
				};
			});
		});

		await Promise.all(promises);

		return flatten(result);
	}
R
rebornix 已提交
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591

	getContributedNotebookKernels(viewType: string, resource: URI): INotebookKernelInfo[] {
		let kernelInfos: INotebookKernelInfo[] = [];
		this._notebookKernels.forEach(kernel => {
			if (this._notebookKernelMatch(resource, kernel!.selectors)) {
				kernelInfos.push(kernel!);
			}
		});

		// sort by extensions

		const notebookContentProvider = this._notebookProviders.get(viewType);

		if (!notebookContentProvider) {
			return kernelInfos;
		}

		kernelInfos = kernelInfos.sort((a, b) => {
			if (a.extension.value === notebookContentProvider!.extensionData.id.value) {
				return -1;
			} else if (b.extension.value === notebookContentProvider!.extensionData.id.value) {
				return 1;
			} else {
				return 0;
			}
		});

		return kernelInfos;
	}

	private _notebookKernelMatch(resource: URI, selectors: (string | glob.IRelativePattern)[]): boolean {
		for (let i = 0; i < selectors.length; i++) {
			const pattern = typeof selectors[i] !== 'string' ? selectors[i] : selectors[i].toString();
R
rebornix 已提交
592
			if (glob.match(pattern, basename(resource.fsPath).toLowerCase())) {
R
rebornix 已提交
593 594 595 596 597 598 599
				return true;
			}
		}

		return false;
	}

600 601
	getRendererInfo(id: string): INotebookRendererInfo | undefined {
		const renderer = this._notebookRenderers.get(id);
602

603
		return renderer;
604 605
	}

606
	async resolveNotebook(viewType: string, uri: URI, forceReload: boolean, editorId?: string, backupId?: string): Promise<NotebookTextModel | undefined> {
R
rebornix 已提交
607 608 609 610 611
		const provider = this._notebookProviders.get(viewType);
		if (!provider) {
			return undefined;
		}

612 613 614 615 616 617 618 619 620
		const modelId = MODEL_ID(uri);

		let notebookModel: NotebookTextModel | undefined = undefined;
		if (this._models.has(modelId)) {
			// the model already exists
			notebookModel = this._models.get(modelId)!.model;
			if (forceReload) {
				await provider.controller.reloadNotebook(notebookModel);
			}
621 622

			return notebookModel;
623
		} else {
624 625
			notebookModel = this._instantiationService.createInstance(NotebookTextModel, NotebookService.mainthreadNotebookDocumentHandle++, viewType, provider.controller.supportBackup, uri);
			await provider.controller.createNotebook(notebookModel, backupId);
626 627 628 629

			if (!notebookModel) {
				return undefined;
			}
R
rebornix 已提交
630 631
		}

R
rebornix 已提交
632 633 634
		// new notebook model created
		const modelData = new ModelData(
			notebookModel!,
635
			(model) => this._onWillDisposeDocument(model),
R
rebornix 已提交
636 637
		);

638
		this._models.set(modelId, modelData);
R
rebornix 已提交
639
		this._onNotebookDocumentAdd.fire([notebookModel!.uri]);
640 641
		// after the document is added to the store and sent to ext host, we transform the ouputs
		await this.transformTextModelOutputs(notebookModel!);
642 643 644 645 646

		if (editorId) {
			await provider.controller.resolveNotebookEditor(viewType, uri, editorId);
		}

647
		return modelData.model;
R
rebornix 已提交
648 649
	}

650 651 652 653 654 655
	getNotebookTextModel(uri: URI): NotebookTextModel | undefined {
		const modelId = MODEL_ID(uri);

		return this._models.get(modelId)?.model;
	}

656 657 658 659 660 661
	private async _fillInTransformedOutputs<T>(
		renderers: Set<string>,
		requestItems: IOutputRenderRequestCellInfo<T>[],
		renderFunc: (rendererId: string, items: IOutputRenderRequestCellInfo<T>[]) => Promise<IOutputRenderResponse<T> | undefined>,
		lookUp: (key: T) => { outputs: IProcessedOutput[] }
	) {
R
Rob Lourens 已提交
662
		for (const id of renderers) {
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
			const requestsPerRenderer: IOutputRenderRequestCellInfo<T>[] = requestItems.map(req => {
				return {
					key: req.key,
					outputs: req.outputs.filter(output => output.handlerId === id)
				};
			});

			const response = await renderFunc(id, requestsPerRenderer);

			// mix the response with existing outputs, which will replace the picked transformed mimetype with resolved result
			if (response) {
				response.items.forEach(cellInfo => {
					const cell = lookUp(cellInfo.key)!;
					cellInfo.outputs.forEach(outputInfo => {
						const output = cell.outputs[outputInfo.index];
						if (output.outputKind === CellOutputKind.Rich && output.orderedMimeTypes && output.orderedMimeTypes.length) {
							output.orderedMimeTypes[0] = {
								mimeType: outputInfo.mimeType,
								isResolved: true,
								rendererId: outputInfo.handlerId,
								output: outputInfo.transformedOutput
							};
						}
					});
				});
			}
		}
	}

	async transformTextModelOutputs(textModel: NotebookTextModel) {
		const renderers = new Set<string>();

		const cellMapping: Map<string, NotebookCellTextModel> = new Map();

		const requestItems: IOutputRenderRequestCellInfo<UriComponents>[] = [];
		for (let i = 0; i < textModel.cells.length; i++) {
			const cell = textModel.cells[i];
			cellMapping.set(cell.uri.fragment, cell);
			const outputs = cell.outputs;
			const outputRequest: IOutputRenderRequestOutputInfo[] = [];

			outputs.forEach((output, index) => {
				if (output.outputKind === CellOutputKind.Rich) {
					// TODO no string[] casting
707
					const ret = this._transformMimeTypes(output, output.outputId, textModel.metadata.displayOrder as string[] || []);
708 709 710 711 712
					const orderedMimeTypes = ret.orderedMimeTypes!;
					const pickedMimeTypeIndex = ret.pickedMimeTypeIndex!;
					output.pickedMimeTypeIndex = pickedMimeTypeIndex;
					output.orderedMimeTypes = orderedMimeTypes;

713
					if (orderedMimeTypes[pickedMimeTypeIndex!].rendererId && orderedMimeTypes[pickedMimeTypeIndex].rendererId !== BUILTIN_RENDERER_ID) {
714
						outputRequest.push({ index, handlerId: orderedMimeTypes[pickedMimeTypeIndex].rendererId!, mimeType: orderedMimeTypes[pickedMimeTypeIndex].mimeType, outputId: output.outputId });
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
						renderers.add(orderedMimeTypes[pickedMimeTypeIndex].rendererId!);
					}
				}
			});

			requestItems.push({ key: cell.uri, outputs: outputRequest });
		}

		await this._fillInTransformedOutputs<UriComponents>(renderers, requestItems, async (rendererId, items) => {
			return await this._notebookRenderers.get(rendererId)?.render(textModel.uri, { items: items });
		}, (key: UriComponents) => { return cellMapping.get(URI.revive(key).fragment)!; });

		textModel.updateRenderers([...renderers]);
	}

	async transformEditsOutputs(textModel: NotebookTextModel, edits: ICellEditOperation[]) {
		const renderers = new Set<string>();
		const requestItems: IOutputRenderRequestCellInfo<[number, number]>[] = [];

		edits.forEach((edit, editIndex) => {
			if (edit.editType === CellEditType.Insert) {
				edit.cells.forEach((cell, cellIndex) => {
					const outputs = cell.outputs;
					const outputRequest: IOutputRenderRequestOutputInfo[] = [];
					outputs.map((output, index) => {
						if (output.outputKind === CellOutputKind.Rich) {
741
							const ret = this._transformMimeTypes(output, output.outputId, textModel.metadata.displayOrder as string[] || []);
742 743 744 745 746
							const orderedMimeTypes = ret.orderedMimeTypes!;
							const pickedMimeTypeIndex = ret.pickedMimeTypeIndex!;
							output.pickedMimeTypeIndex = pickedMimeTypeIndex;
							output.orderedMimeTypes = orderedMimeTypes;

747
							if (orderedMimeTypes[pickedMimeTypeIndex!].rendererId && orderedMimeTypes[pickedMimeTypeIndex].rendererId !== BUILTIN_RENDERER_ID) {
748
								outputRequest.push({ index, handlerId: orderedMimeTypes[pickedMimeTypeIndex].rendererId!, mimeType: orderedMimeTypes[pickedMimeTypeIndex].mimeType, output: output, outputId: output.outputId });
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
								renderers.add(orderedMimeTypes[pickedMimeTypeIndex].rendererId!);
							}
						}
					});

					requestItems.push({ key: [editIndex, cellIndex], outputs: outputRequest });
				});
			}
		});

		await this._fillInTransformedOutputs<[number, number]>(renderers, requestItems, async (rendererId, items) => {
			return await this._notebookRenderers.get(rendererId)?.render2<[number, number]>(textModel.uri, { items: items });
		}, (key: [number, number]) => {
			return (edits[key[0]] as ICellInsertEdit).cells[key[1]];
		});

		textModel.updateRenderers([...renderers]);
	}

	async transformSpliceOutputs(textModel: NotebookTextModel, splices: NotebookCellOutputsSplice[]) {
		const renderers = new Set<string>();
		const requestItems: IOutputRenderRequestCellInfo<number>[] = [];

		splices.forEach((splice, spliceIndex) => {
			const outputs = splice[2];
			const outputRequest: IOutputRenderRequestOutputInfo[] = [];
			outputs.map((output, index) => {
				if (output.outputKind === CellOutputKind.Rich) {
777
					const ret = this._transformMimeTypes(output, output.outputId, textModel.metadata.displayOrder as string[] || []);
778 779 780 781 782
					const orderedMimeTypes = ret.orderedMimeTypes!;
					const pickedMimeTypeIndex = ret.pickedMimeTypeIndex!;
					output.pickedMimeTypeIndex = pickedMimeTypeIndex;
					output.orderedMimeTypes = orderedMimeTypes;

783
					if (orderedMimeTypes[pickedMimeTypeIndex!].rendererId && orderedMimeTypes[pickedMimeTypeIndex].rendererId !== BUILTIN_RENDERER_ID) {
784
						outputRequest.push({ index, handlerId: orderedMimeTypes[pickedMimeTypeIndex].rendererId!, mimeType: orderedMimeTypes[pickedMimeTypeIndex].mimeType, output: output, outputId: output.outputId });
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
						renderers.add(orderedMimeTypes[pickedMimeTypeIndex].rendererId!);
					}
				}
			});
			requestItems.push({ key: spliceIndex, outputs: outputRequest });
		});

		await this._fillInTransformedOutputs<number>(renderers, requestItems, async (rendererId, items) => {
			return await this._notebookRenderers.get(rendererId)?.render2<number>(textModel.uri, { items: items });
		}, (key: number) => {
			return { outputs: splices[key][2] };
		});

		textModel.updateRenderers([...renderers]);
	}

801 802 803 804 805 806 807
	async transformSingleOutput(textModel: NotebookTextModel, output: IProcessedOutput, rendererId: string, mimeType: string): Promise<IOrderedMimeType | undefined> {
		const items = [
			{
				key: 0,
				outputs: [
					{
						index: 0,
808
						outputId: generateUuid(),
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
						handlerId: rendererId,
						mimeType: mimeType,
						output: output
					}
				]
			}
		];
		const response = await this._notebookRenderers.get(rendererId)?.render2<number>(textModel.uri, { items: items });

		if (response) {
			textModel.updateRenderers([rendererId]);
			const outputInfo = response.items[0].outputs[0];

			return {
				mimeType: outputInfo.mimeType,
				isResolved: true,
				rendererId: outputInfo.handlerId,
				output: outputInfo.transformedOutput
			};
		}

		return;
	}

833
	private _transformMimeTypes(output: IDisplayOutput, outputId: string, documentDisplayOrder: string[]): ITransformedDisplayOutputDto {
R
Rob Lourens 已提交
834 835
		const mimeTypes = Object.keys(output.data);
		const coreDisplayOrder = this._displayOrder;
836 837
		const sorted = sortMimeTypes(mimeTypes, coreDisplayOrder?.userOrder || [], documentDisplayOrder, coreDisplayOrder?.defaultOrder || []);

R
Rob Lourens 已提交
838
		const orderMimeTypes: IOrderedMimeType[] = [];
839 840

		sorted.forEach(mimeType => {
R
Rob Lourens 已提交
841
			const handlers = this._findBestMatchedRenderer(mimeType);
842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863

			if (handlers.length) {
				const handler = handlers[0];

				orderMimeTypes.push({
					mimeType: mimeType,
					isResolved: false,
					rendererId: handler.id,
				});

				for (let i = 1; i < handlers.length; i++) {
					orderMimeTypes.push({
						mimeType: mimeType,
						isResolved: false,
						rendererId: handlers[i].id
					});
				}

				if (mimeTypeSupportedByCore(mimeType)) {
					orderMimeTypes.push({
						mimeType: mimeType,
						isResolved: false,
864
						rendererId: BUILTIN_RENDERER_ID
865 866 867 868 869
					});
				}
			} else {
				orderMimeTypes.push({
					mimeType: mimeType,
870 871
					isResolved: false,
					rendererId: BUILTIN_RENDERER_ID
872 873 874 875 876 877
				});
			}
		});

		return {
			outputKind: output.outputKind,
878
			outputId,
879 880 881 882 883 884
			data: output.data,
			orderedMimeTypes: orderMimeTypes,
			pickedMimeTypeIndex: 0
		};
	}

885
	private _findBestMatchedRenderer(mimeType: string): readonly NotebookOutputRendererInfo[] {
886 887 888
		return this.notebookRenderersInfoStore.getContributedRenderer(mimeType);
	}

R
Rob Lourens 已提交
889
	async executeNotebook(viewType: string, uri: URI): Promise<void> {
R
Rob Lourens 已提交
890
		const provider = this._notebookProviders.get(viewType);
R
rebornix 已提交
891 892

		if (provider) {
R
Rob Lourens 已提交
893
			return provider.controller.executeNotebookByAttachedKernel(viewType, uri);
R
rebornix 已提交
894 895 896 897 898
		}

		return;
	}

R
Rob Lourens 已提交
899
	async executeNotebookCell(viewType: string, uri: URI, handle: number): Promise<void> {
900 901
		const provider = this._notebookProviders.get(viewType);
		if (provider) {
R
Rob Lourens 已提交
902
			await provider.controller.executeNotebookCell(uri, handle);
903 904 905
		}
	}

R
Rob Lourens 已提交
906
	async cancelNotebook(viewType: string, uri: URI): Promise<void> {
R
Rob Lourens 已提交
907
		const provider = this._notebookProviders.get(viewType);
R
Rob Lourens 已提交
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923

		if (provider) {
			return provider.controller.cancelNotebookByAttachedKernel(viewType, uri);
		}

		return;
	}

	async cancelNotebookCell(viewType: string, uri: URI, handle: number): Promise<void> {
		const provider = this._notebookProviders.get(viewType);
		if (provider) {
			await provider.controller.cancelNotebookCell(uri, handle);
		}
	}

	async executeNotebook2(viewType: string, uri: URI, kernelId: string): Promise<void> {
R
rebornix 已提交
924 925
		const kernel = this._notebookKernels.get(kernelId);
		if (kernel) {
R
Rob Lourens 已提交
926
			await kernel.executeNotebook(viewType, uri, undefined);
R
rebornix 已提交
927 928 929
		}
	}

R
Rob Lourens 已提交
930
	async executeNotebookCell2(viewType: string, uri: URI, handle: number, kernelId: string): Promise<void> {
R
rebornix 已提交
931 932
		const kernel = this._notebookKernels.get(kernelId);
		if (kernel) {
R
Rob Lourens 已提交
933
			await kernel.executeNotebook(viewType, uri, handle);
R
rebornix 已提交
934 935 936
		}
	}

R
rebornix 已提交
937
	getContributedNotebookProviders(resource: URI): readonly NotebookProviderInfo[] {
R
rebornix 已提交
938 939
		return this.notebookProviderInfoStore.getContributedNotebook(resource);
	}
R
rebornix 已提交
940

R
rebornix 已提交
941 942 943 944
	getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined {
		return this.notebookProviderInfoStore.get(viewType);
	}

R
rebornix 已提交
945 946 947 948
	getContributedNotebookOutputRenderers(mimeType: string): readonly NotebookOutputRendererInfo[] {
		return this.notebookRenderersInfoStore.getContributedRenderer(mimeType);
	}

R
rebornix 已提交
949
	getNotebookProviderResourceRoots(): URI[] {
R
Rob Lourens 已提交
950
		const ret: URI[] = [];
R
rebornix 已提交
951 952 953 954 955 956
		this._notebookProviders.forEach(val => {
			ret.push(URI.revive(val.extensionData.location));
		});

		return ret;
	}
R
rebornix 已提交
957

R
rebornix 已提交
958
	removeNotebookEditor(editor: INotebookEditor) {
R
Rob Lourens 已提交
959
		const editorCache = this._notebookEditors.get(editor.getId());
960 961 962 963

		if (editorCache) {
			this._notebookEditors.delete(editor.getId());
			this._onNotebookEditorsRemove.fire([editor]);
R
rebornix 已提交
964 965 966 967
		}
	}

	addNotebookEditor(editor: INotebookEditor) {
968
		this._notebookEditors.set(editor.getId(), editor);
R
rebornix 已提交
969 970 971
		this._onNotebookEditorAdd.fire(editor);
	}

972 973 974 975
	getNotebookEditor(editorId: string) {
		return this._notebookEditors.get(editorId);
	}

R
rebornix 已提交
976
	listNotebookEditors(): INotebookEditor[] {
977 978 979 980
		return [...this._notebookEditors].map(e => e[1]);
	}

	listVisibleNotebookEditors(): INotebookEditor[] {
R
rebornix 已提交
981
		return this._editorService.visibleEditorPanes
R
rebornix 已提交
982
			.filter(pane => (pane as unknown as { isNotebookEditor?: boolean }).isNotebookEditor)
983 984 985
			.map(pane => pane.getControl() as INotebookEditor)
			.filter(editor => !!editor)
			.filter(editor => this._notebookEditors.has(editor.getId()));
R
rebornix 已提交
986 987 988
	}

	listNotebookDocuments(): NotebookTextModel[] {
989
		return [...this._models].map(e => e[1].model);
R
rebornix 已提交
990 991
	}

992
	destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void {
993
		this._onWillDisposeDocument(notebook);
R
rebornix 已提交
994 995
	}

R
rebornix 已提交
996
	updateActiveNotebookEditor(editor: INotebookEditor | null) {
R
rebornix 已提交
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
		this._activeEditorDisposables.clear();

		if (editor) {
			this._activeEditorDisposables.add(editor.onDidChangeKernel(() => {
				this._onDidChangeNotebookActiveKernel.fire({
					uri: editor.uri!,
					providerHandle: editor.activeKernel?.providerHandle,
					kernelId: editor.activeKernel?.id
				});
			}));
		}
R
rebornix 已提交
1008 1009 1010 1011
		this._onDidChangeActiveEditor.fire(editor ? editor.getId() : null);
	}

	updateVisibleNotebookEditor(editors: string[]) {
1012 1013
		const alreadyCreated = editors.filter(editorId => this._notebookEditors.has(editorId));
		this._onDidChangeVisibleEditors.fire(alreadyCreated);
R
rebornix 已提交
1014 1015
	}

R
rebornix 已提交
1016
	setToCopy(items: NotebookCellTextModel[], isCopy: boolean) {
R
rebornix 已提交
1017
		this.cutItems = items;
R
rebornix 已提交
1018
		this._lastClipboardIsCopy = isCopy;
R
rebornix 已提交
1019 1020
	}

R
rebornix 已提交
1021 1022 1023 1024 1025 1026
	getToCopy(): { items: NotebookCellTextModel[], isCopy: boolean; } | undefined {
		if (this.cutItems) {
			return { items: this.cutItems, isCopy: this._lastClipboardIsCopy };
		}

		return undefined;
R
rebornix 已提交
1027 1028
	}

R
rebornix 已提交
1029
	async save(viewType: string, resource: URI, token: CancellationToken): Promise<boolean> {
R
Rob Lourens 已提交
1030
		const provider = this._notebookProviders.get(viewType);
1031 1032

		if (provider) {
1033 1034 1035 1036 1037 1038
			const ret = await provider.controller.save(resource, token);
			if (ret) {
				this._onNotebookDocumentSaved.fire(resource);
			}

			return ret;
1039 1040 1041 1042 1043
		}

		return false;
	}

R
saveAs  
rebornix 已提交
1044
	async saveAs(viewType: string, resource: URI, target: URI, token: CancellationToken): Promise<boolean> {
R
Rob Lourens 已提交
1045
		const provider = this._notebookProviders.get(viewType);
R
saveAs  
rebornix 已提交
1046 1047

		if (provider) {
1048 1049 1050 1051 1052 1053
			const ret = await provider.controller.saveAs(resource, target, token);
			if (ret) {
				this._onNotebookDocumentSaved.fire(resource);
			}

			return ret;
R
saveAs  
rebornix 已提交
1054 1055 1056 1057 1058
		}

		return false;
	}

1059
	async backup(viewType: string, uri: URI, token: CancellationToken): Promise<string | undefined> {
R
Rob Lourens 已提交
1060
		const provider = this._notebookProviders.get(viewType);
1061 1062 1063 1064 1065 1066 1067 1068

		if (provider) {
			return provider.controller.backup(uri, token);
		}

		return;
	}

1069
	onDidReceiveMessage(viewType: string, editorId: string, rendererType: string | undefined, message: any): void {
R
Rob Lourens 已提交
1070
		const provider = this._notebookProviders.get(viewType);
1071 1072

		if (provider) {
1073
			return provider.controller.onDidReceiveMessage(editorId, rendererType, message);
1074 1075 1076
		}
	}

1077
	private _onWillDisposeDocument(model: INotebookTextModel): void {
R
Rob Lourens 已提交
1078
		const modelId = MODEL_ID(model.uri);
R
rebornix 已提交
1079

R
Rob Lourens 已提交
1080
		const modelData = this._models.get(modelId);
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
		this._models.delete(modelId);

		if (modelData) {
			// delete editors and documents
			const willRemovedEditors: INotebookEditor[] = [];
			this._notebookEditors.forEach(editor => {
				if (editor.textModel === modelData!.model) {
					willRemovedEditors.push(editor);
				}
			});

			willRemovedEditors.forEach(e => this._notebookEditors.delete(e.getId()));

R
Rob Lourens 已提交
1094
			const provider = this._notebookProviders.get(modelData!.model.viewType);
R
rebornix 已提交
1095

1096
			if (provider) {
1097 1098
				provider.controller.removeNotebookDocument(modelData!.model.uri);
				modelData!.model.dispose();
1099 1100 1101 1102 1103 1104 1105
			}


			this._onNotebookEditorsRemove.fire(willRemovedEditors.map(e => e));
			this._onNotebookDocumentRemove.fire([modelData.model.uri]);
			modelData?.dispose();
		}
R
rebornix 已提交
1106
	}
R
rebornix 已提交
1107
}