mainThreadNotebook.ts 24.9 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 DOM from 'vs/base/browser/dom';
R
rebornix 已提交
7
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
R
rebornix 已提交
8
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext, INotebookDocumentsAndEditorsDelta } from '../common/extHost.protocol';
9
import { Disposable, IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
R
rebornix 已提交
10
import { URI, UriComponents } from 'vs/base/common/uri';
11
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/common/notebookService';
12
import { INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, INotebookKernelInfo, INotebookKernelInfoDto, IEditor, INotebookRendererInfo, IOutputRenderRequest, IOutputRenderResponse, INotebookDocumentFilter } from 'vs/workbench/contrib/notebook/common/notebookCommon';
R
rebornix 已提交
13
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
14
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
15 16
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
17
import { CancellationToken } from 'vs/base/common/cancellation';
R
rebornix 已提交
18
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
R
rebornix 已提交
19 20
import { IRelativePattern } from 'vs/base/common/glob';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
R
rebornix 已提交
21
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
22
import { ITextModelService } from 'vs/editor/common/services/resolverService';
R
rebornix 已提交
23
import { Emitter } from 'vs/base/common/event';
R
rebornix 已提交
24

25 26
export class MainThreadNotebookDocument extends Disposable {
	private _textModel: NotebookTextModel;
R
rebornix 已提交
27

28 29
	get textModel() {
		return this._textModel;
R
rebornix 已提交
30
	}
R
rebornix 已提交
31 32

	constructor(
R
rebornix 已提交
33
		private readonly _proxy: ExtHostNotebookShape,
R
rebornix 已提交
34
		public handle: number,
R
rebornix 已提交
35
		public viewType: string,
36
		public supportBackup: boolean,
37
		public uri: URI,
38
		@INotebookService readonly notebookService: INotebookService,
39 40
		@IUndoRedoService readonly undoRedoService: IUndoRedoService,
		@ITextModelService modelService: ITextModelService
41

R
rebornix 已提交
42
	) {
R
rebornix 已提交
43
		super();
44

45
		this._textModel = new NotebookTextModel(handle, viewType, supportBackup, uri, undoRedoService, modelService);
46
		this._register(this._textModel.onDidModelChangeProxy(e => {
R
rebornix 已提交
47
			this._proxy.$acceptModelChanged(this.uri, e);
48
			this._proxy.$acceptEditorPropertiesChanged(uri, { selections: { selections: this._textModel.selections }, metadata: null });
R
rebornix 已提交
49
		}));
R
rebornix 已提交
50 51
		this._register(this._textModel.onDidSelectionChange(e => {
			const selectionsChange = e ? { selections: e } : null;
R
rebornix 已提交
52
			this._proxy.$acceptEditorPropertiesChanged(uri, { selections: selectionsChange, metadata: null });
R
rebornix 已提交
53
		}));
R
rebornix 已提交
54
	}
R
rebornix 已提交
55 56

	dispose() {
57
		// this._textModel.dispose();
R
rebornix 已提交
58 59
		super.dispose();
	}
R
rebornix 已提交
60 61
}

R
rebornix 已提交
62
class DocumentAndEditorState {
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
	static ofSets<T>(before: Set<T>, after: Set<T>): { removed: T[], added: T[] } {
		const removed: T[] = [];
		const added: T[] = [];
		before.forEach(element => {
			if (!after.has(element)) {
				removed.push(element);
			}
		});
		after.forEach(element => {
			if (!before.has(element)) {
				added.push(element);
			}
		});
		return { removed, added };
	}

R
rebornix 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
	static ofMaps<K, V>(before: Map<K, V>, after: Map<K, V>): { removed: V[], added: V[] } {
		const removed: V[] = [];
		const added: V[] = [];
		before.forEach((value, index) => {
			if (!after.has(index)) {
				removed.push(value);
			}
		});
		after.forEach((value, index) => {
			if (!before.has(index)) {
				added.push(value);
			}
		});
		return { removed, added };
	}

	static compute(before: DocumentAndEditorState | undefined, after: DocumentAndEditorState): INotebookDocumentsAndEditorsDelta {
		if (!before) {
			const apiEditors = [];
			for (let id in after.textEditors) {
				const editor = after.textEditors.get(id)!;
				apiEditors.push({ id, documentUri: editor.uri!, selections: editor!.textModel!.selections });
			}

			return {
				addedDocuments: [],
105 106
				addedEditors: apiEditors,
				visibleEditors: [...after.visibleEditors].map(editor => editor[0])
R
rebornix 已提交
107 108
			};
		}
109
		const documentDelta = DocumentAndEditorState.ofSets(before.documents, after.documents);
R
rebornix 已提交
110 111 112 113
		const editorDelta = DocumentAndEditorState.ofMaps(before.textEditors, after.textEditors);
		const addedAPIEditors = editorDelta.added.map(add => ({
			id: add.getId(),
			documentUri: add.uri!,
114
			selections: add.textModel!.selections || []
R
rebornix 已提交
115 116 117 118 119 120 121
		}));

		const removedAPIEditors = editorDelta.removed.map(removed => removed.getId());

		// const oldActiveEditor = before.activeEditor !== after.activeEditor ? before.activeEditor : undefined;
		const newActiveEditor = before.activeEditor !== after.activeEditor ? after.activeEditor : undefined;

122 123
		const visibleEditorDelta = DocumentAndEditorState.ofMaps(before.visibleEditors, after.visibleEditors);

R
rebornix 已提交
124
		return {
125 126 127 128 129 130 131 132 133 134 135
			addedDocuments: documentDelta.added.map(e => {
				return {
					viewType: e.viewType,
					handle: e.handle,
					uri: e.uri,
					metadata: e.metadata,
					versionId: e.versionId,
					cells: e.cells.map(cell => ({
						handle: cell.handle,
						uri: cell.uri,
						source: cell.textBuffer.getLinesContent(),
136
						eol: cell.textBuffer.getEOL(),
137 138 139 140 141 142 143 144 145 146 147 148
						language: cell.language,
						cellKind: cell.cellKind,
						outputs: cell.outputs,
						metadata: cell.metadata
					})),
					// attachedEditor: editorId ? {
					// 	id: editorId,
					// 	selections: document.textModel.selections
					// } : undefined
				};
			}),
			removedDocuments: documentDelta.removed.map(e => e.uri),
R
rebornix 已提交
149 150
			addedEditors: addedAPIEditors,
			removedEditors: removedAPIEditors,
151 152 153 154
			newActiveEditor: newActiveEditor,
			visibleEditors: visibleEditorDelta.added.length === 0 && visibleEditorDelta.removed.length === 0
				? undefined
				: [...after.visibleEditors].map(editor => editor[0])
R
rebornix 已提交
155 156 157 158
		};
	}

	constructor(
159
		readonly documents: Set<NotebookTextModel>,
R
rebornix 已提交
160 161
		readonly textEditors: Map<string, IEditor>,
		readonly activeEditor: string | null | undefined,
162
		readonly visibleEditors: Map<string, IEditor>
R
rebornix 已提交
163 164 165 166 167
	) {
		//
	}
}

R
rebornix 已提交
168 169
@extHostNamedCustomer(MainContext.MainThreadNotebook)
export class MainThreadNotebooks extends Disposable implements MainThreadNotebookShape {
170
	private readonly _notebookProviders = new Map<string, IMainNotebookController>();
R
rebornix 已提交
171
	private readonly _notebookKernels = new Map<string, MainThreadNotebookKernel>();
R
rebornix 已提交
172
	private readonly _notebookKernelProviders = new Map<number, { extension: NotebookExtensionDescription, emitter: Emitter<void>, provider: IDisposable }>();
173
	private readonly _notebookRenderers = new Map<string, MainThreadNotebookRenderer>();
R
rebornix 已提交
174
	private readonly _proxy: ExtHostNotebookShape;
R
rebornix 已提交
175 176
	private _toDisposeOnEditorRemove = new Map<string, IDisposable>();
	private _currentState?: DocumentAndEditorState;
177
	private _editorEventListenersMapping: Map<string, DisposableStore> = new Map();
R
rebornix 已提交
178 179 180

	constructor(
		extHostContext: IExtHostContext,
R
rebornix 已提交
181
		@INotebookService private _notebookService: INotebookService,
182 183
		@IConfigurationService private readonly configurationService: IConfigurationService,
		@IEditorService private readonly editorService: IEditorService,
184
		@IAccessibilityService private readonly accessibilityService: IAccessibilityService
185

R
rebornix 已提交
186 187 188
	) {
		super();
		this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
R
rebornix 已提交
189 190 191
		this.registerListeners();
	}

R
rebornix 已提交
192
	async $tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean> {
193 194 195 196
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
		if (textModel) {
			await this._notebookService.transformEditsOutputs(textModel, edits);
			return textModel.$applyEdit(modelVersionId, edits, true);
R
rebornix 已提交
197 198 199
		}

		return false;
R
rebornix 已提交
200 201
	}

202 203 204 205 206 207 208 209
	async removeNotebookTextModel(uri: URI): Promise<void> {
		// TODO@rebornix, remove cell should use emitDelta as well to ensure document/editor events are sent together
		await this._proxy.$acceptDocumentAndEditorsDelta({ removedDocuments: [uri] });
		let textModelDisposableStore = this._editorEventListenersMapping.get(uri.toString());
		textModelDisposableStore?.dispose();
		this._editorEventListenersMapping.delete(URI.from(uri).toString());
	}

R
rebornix 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
	private _isDeltaEmpty(delta: INotebookDocumentsAndEditorsDelta) {
		if (delta.addedDocuments !== undefined && delta.addedDocuments.length > 0) {
			return false;
		}

		if (delta.removedDocuments !== undefined && delta.removedDocuments.length > 0) {
			return false;
		}

		if (delta.addedEditors !== undefined && delta.addedEditors.length > 0) {
			return false;
		}

		if (delta.removedEditors !== undefined && delta.removedEditors.length > 0) {
			return false;
		}

		if (delta.visibleEditors !== undefined && delta.visibleEditors.length > 0) {
			return false;
		}

		if (delta.newActiveEditor !== undefined) {
			return false;
		}

		return true;
	}

238
	private _emitDelta(delta: INotebookDocumentsAndEditorsDelta) {
R
rebornix 已提交
239 240 241 242
		if (this._isDeltaEmpty(delta)) {
			return;
		}

243
		return this._proxy.$acceptDocumentAndEditorsDelta(delta);
244 245
	}

R
rebornix 已提交
246
	registerListeners() {
R
rebornix 已提交
247 248 249 250
		this._notebookService.listNotebookEditors().forEach((e) => {
			this._addNotebookEditor(e);
		});

R
rebornix 已提交
251
		this._register(this._notebookService.onDidChangeActiveEditor(e => {
252
			this._updateState();
R
rebornix 已提交
253
		}));
R
rebornix 已提交
254

R
rebornix 已提交
255
		this._register(this._notebookService.onDidChangeVisibleEditors(e => {
256 257 258 259 260 261 262 263 264
			if (this._notebookProviders.size > 0) {
				if (!this._currentState) {
					// no current state means we didn't even create editors in ext host yet.
					return;
				}

				// we can't simply update visibleEditors as we need to check if we should create editors first.
				this._updateState();
			}
R
rebornix 已提交
265 266
		}));

R
rebornix 已提交
267 268 269 270
		this._register(this._notebookService.onNotebookEditorAdd(editor => {
			this._addNotebookEditor(editor);
		}));

271 272 273
		this._register(this._notebookService.onNotebookEditorsRemove(editors => {
			this._removeNotebookEditor(editors);
		}));
274

275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
		this._register(this._notebookService.onNotebookDocumentAdd((documents) => {
			documents.forEach(doc => {
				if (!this._editorEventListenersMapping.has(doc.toString())) {
					const disposableStore = new DisposableStore();
					const textModel = this._notebookService.getNotebookTextModel(doc);
					disposableStore.add(textModel!.onDidModelChangeProxy(e => {
						this._proxy.$acceptModelChanged(textModel!.uri, e);
						this._proxy.$acceptEditorPropertiesChanged(doc, { selections: { selections: textModel!.selections }, metadata: null });
					}));
					disposableStore.add(textModel!.onDidSelectionChange(e => {
						const selectionsChange = e ? { selections: e } : null;
						this._proxy.$acceptEditorPropertiesChanged(doc, { selections: selectionsChange, metadata: null });
					}));

					this._editorEventListenersMapping.set(textModel!.uri.toString(), disposableStore);
				}
			});
R
rebornix 已提交
292 293 294
			this._updateState();
		}));

295 296 297 298 299 300
		this._register(this._notebookService.onNotebookDocumentRemove((documents) => {
			documents.forEach(doc => {
				this._editorEventListenersMapping.get(doc.toString())?.dispose();
				this._editorEventListenersMapping.delete(doc.toString());
			});

301
			this._updateState();
R
rebornix 已提交
302 303
		}));

R
rebornix 已提交
304 305 306 307
		this._register(this._notebookService.onDidChangeNotebookActiveKernel(e => {
			this._proxy.$acceptNotebookActiveKernelChange(e);
		}));

R
rebornix 已提交
308 309 310 311 312 313 314
		const updateOrder = () => {
			let userOrder = this.configurationService.getValue<string[]>('notebook.displayOrder');
			this._proxy.$acceptDisplayOrder({
				defaultOrder: this.accessibilityService.isScreenReaderOptimized() ? ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER : NOTEBOOK_DISPLAY_ORDER,
				userOrder: userOrder
			});
		};
R
rebornix 已提交
315

R
rebornix 已提交
316
		updateOrder();
R
rebornix 已提交
317

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

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

		const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
		const notebookEditor = activeEditorPane?.isNotebookEditor ? activeEditorPane.getControl() : undefined;
		this._updateState(notebookEditor);
R
rebornix 已提交
331 332
	}

R
rebornix 已提交
333 334 335
	private _addNotebookEditor(e: IEditor) {
		this._toDisposeOnEditorRemove.set(e.getId(), combinedDisposable(
			e.onDidChangeModel(() => this._updateState()),
R
rebornix 已提交
336 337 338
			e.onDidFocusEditorWidget(() => {
				this._updateState(e);
			}),
R
rebornix 已提交
339 340
		));

R
rebornix 已提交
341 342 343
		const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
		const notebookEditor = activeEditorPane?.isNotebookEditor ? activeEditorPane.getControl() : undefined;
		this._updateState(notebookEditor);
R
rebornix 已提交
344 345
	}

346 347 348 349 350 351 352 353 354 355
	private _removeNotebookEditor(editors: IEditor[]) {
		editors.forEach(e => {
			const sub = this._toDisposeOnEditorRemove.get(e.getId());
			if (sub) {
				this._toDisposeOnEditorRemove.delete(e.getId());
				sub.dispose();
			}
		});

		this._updateState();
R
rebornix 已提交
356 357 358 359 360
	}

	private async _updateState(focusedNotebookEditor?: IEditor) {
		let activeEditor: string | null = null;

361 362 363 364 365 366 367 368 369 370
		const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
		if (activeEditorPane?.isNotebookEditor) {
			const notebookEditor = (activeEditorPane.getControl() as INotebookEditor);
			activeEditor = notebookEditor && notebookEditor.hasModel() ? notebookEditor!.getId() : null;
		}

		const documentEditorsMap = new Map<string, IEditor>();

		const editors = new Map<string, IEditor>();
		this._notebookService.listNotebookEditors().forEach(editor => {
R
rebornix 已提交
371 372
			if (editor.hasModel()) {
				editors.set(editor.getId(), editor);
373 374 375 376 377 378 379 380 381 382
				documentEditorsMap.set(editor.textModel!.uri.toString(), editor);
			}
		});

		const visibleEditorsMap = new Map<string, IEditor>();
		this.editorService.visibleEditorPanes.forEach(editor => {
			if ((editor as any).isNotebookEditor) {
				const nbEditorWidget = (editor as any).getControl() as INotebookEditor;
				if (nbEditorWidget && editors.has(nbEditorWidget.getId())) {
					visibleEditorsMap.set(nbEditorWidget.getId(), nbEditorWidget);
R
rebornix 已提交
383 384
				}
			}
385 386 387 388
		});

		const documents = new Set<NotebookTextModel>();
		this._notebookService.listNotebookDocuments().forEach(document => {
R
rebornix 已提交
389
			documents.add(document);
390
		});
R
rebornix 已提交
391

392
		if (!activeEditor && focusedNotebookEditor && focusedNotebookEditor.hasModel()) {
R
rebornix 已提交
393 394 395
			activeEditor = focusedNotebookEditor.getId();
		}

R
rebornix 已提交
396
		// editors always have view model attached, which means there is already a document in exthost.
397
		const newState = new DocumentAndEditorState(documents, editors, activeEditor, visibleEditorsMap);
R
rebornix 已提交
398 399 400 401 402 403 404 405 406
		const delta = DocumentAndEditorState.compute(this._currentState, newState);
		// const isEmptyChange = (!delta.addedDocuments || delta.addedDocuments.length === 0)
		// 	&& (!delta.removedDocuments || delta.removedDocuments.length === 0)
		// 	&& (!delta.addedEditors || delta.addedEditors.length === 0)
		// 	&& (!delta.removedEditors || delta.removedEditors.length === 0)
		// 	&& (delta.newActiveEditor === undefined)

		// if (!isEmptyChange) {
		this._currentState = newState;
407
		await this._emitDelta(delta);
R
rebornix 已提交
408 409 410
		// }
	}

411 412 413 414
	async $registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, preloads: UriComponents[]): Promise<void> {
		const renderer = new MainThreadNotebookRenderer(this._proxy, type, extension.id, URI.revive(extension.location), selectors, preloads.map(uri => URI.revive(uri)));
		this._notebookRenderers.set(type, renderer);
		this._notebookService.registerNotebookRenderer(type, renderer);
R
rebornix 已提交
415 416
	}

417 418
	async $unregisterNotebookRenderer(id: string): Promise<void> {
		this._notebookService.unregisterNotebookRenderer(id);
R
rebornix 已提交
419 420
	}

421 422 423
	async $registerNotebookProvider(_extension: NotebookExtensionDescription, _viewType: string, _supportBackup: boolean, _kernel: INotebookKernelInfoDto | undefined): Promise<void> {
		const controller: IMainNotebookController = {
			kernel: _kernel,
424
			supportBackup: _supportBackup,
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
			reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => {
				const data = await this._proxy.$resolveNotebookData(_viewType, mainthreadTextModel.uri);
				if (!data) {
					return;
				}

				mainthreadTextModel.languages = data.languages;
				mainthreadTextModel.metadata = data.metadata;

				const edits: ICellEditOperation[] = [
					{ editType: CellEditType.Delete, count: mainthreadTextModel.cells.length, index: 0 },
					{ editType: CellEditType.Insert, index: 0, cells: data.cells }
				];

				await this._notebookService.transformEditsOutputs(mainthreadTextModel, edits);
				await new Promise(resolve => {
					DOM.scheduleAtNextAnimationFrame(() => {
						const ret = mainthreadTextModel!.$applyEdit(mainthreadTextModel!.versionId, edits, true);
						resolve(ret);
					});
				});
			},
447
			createNotebook: async (textModel: NotebookTextModel, backupId?: string) => {
448
				// open notebook document
449
				const data = await this._proxy.$resolveNotebookData(textModel.viewType, textModel.uri, backupId);
450 451 452 453 454 455 456 457 458 459 460 461 462 463
				if (!data) {
					return;
				}

				textModel.languages = data.languages;
				textModel.metadata = data.metadata;

				if (data.cells.length) {
					textModel.initialize(data!.cells);
				} else {
					const mainCell = textModel.createCellTextModel([''], textModel.languages.length ? textModel.languages[0] : '', CellKind.Code, [], undefined);
					textModel.insertTemplateCell(mainCell);
				}

464 465
				this._proxy.$acceptEditorPropertiesChanged(textModel.uri, { selections: null, metadata: textModel.metadata });
				return;
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
			},
			resolveNotebookEditor: async (viewType: string, uri: URI, editorId: string) => {
				await this._proxy.$resolveNotebookEditor(viewType, uri, editorId);
			},
			executeNotebookByAttachedKernel: async (viewType: string, uri: URI, token: CancellationToken) => {
				return this.executeNotebookByAttachedKernel(viewType, uri, token);
			},
			onDidReceiveMessage: (editorId: string, rendererType: string | undefined, message: unknown) => {
				this._proxy.$onDidReceiveMessage(editorId, rendererType, message);
			},
			removeNotebookDocument: async (uri: URI) => {
				return this.removeNotebookTextModel(uri);
			},
			executeNotebookCell: async (uri: URI, handle: number, token: CancellationToken) => {
				return this._proxy.$executeNotebookByAttachedKernel(_viewType, uri, handle, token);
			},
			save: async (uri: URI, token: CancellationToken) => {
				return this._proxy.$saveNotebook(_viewType, uri, token);
			},
			saveAs: async (uri: URI, target: URI, token: CancellationToken) => {
				return this._proxy.$saveNotebookAs(_viewType, uri, target, token);
			},
			backup: async (uri: URI, token: CancellationToken) => {
				return this._proxy.$backup(_viewType, uri, token);
			}
		};

		this._notebookProviders.set(_viewType, controller);
		this._notebookService.registerNotebookController(_viewType, _extension, controller);
R
rebornix 已提交
495
		return;
R
rebornix 已提交
496 497
	}

498
	async $onNotebookChange(viewType: string, uri: UriComponents): Promise<void> {
499 500
		const textModel = this._notebookService.getNotebookTextModel(URI.from(uri));
		textModel?.handleUnknownChange();
501 502
	}

R
rebornix 已提交
503
	async $unregisterNotebookProvider(viewType: string): Promise<void> {
R
rebornix 已提交
504 505
		this._notebookProviders.delete(viewType);
		this._notebookService.unregisterNotebookProvider(viewType);
R
rebornix 已提交
506 507 508
		return;
	}

R
rebornix 已提交
509 510
	async $registerNotebookKernel(extension: NotebookExtensionDescription, id: string, label: string, selectors: (string | IRelativePattern)[], preloads: UriComponents[]): Promise<void> {
		const kernel = new MainThreadNotebookKernel(this._proxy, id, label, selectors, extension.id, URI.revive(extension.location), preloads.map(preload => URI.revive(preload)));
R
rebornix 已提交
511 512 513 514 515 516 517 518 519 520 521
		this._notebookKernels.set(id, kernel);
		this._notebookService.registerNotebookKernel(kernel);
		return;
	}

	async $unregisterNotebookKernel(id: string): Promise<void> {
		this._notebookKernels.delete(id);
		this._notebookService.unregisterNotebookKernel(id);
		return;
	}

R
rebornix 已提交
522 523 524 525 526 527
	async $registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void> {
		const emitter = new Emitter<void>();
		const that = this;
		const provider = this._notebookService.registerNotebookKernelProvider({
			onDidChangeKernels: emitter.event,
			selector: documentFilter,
R
rebornix 已提交
528 529 530 531 532 533 534 535
			provideKernels: async (uri: URI, token: CancellationToken) => {
				const kernels = await that._proxy.$provideNotebookKernels(handle, uri, token);
				return kernels.map(kernel => {
					return {
						...kernel,
						providerHandle: handle
					};
				});
R
rebornix 已提交
536 537 538 539
			},
			resolveKernel: (editorId: string, uri: URI, kernelId: string, token: CancellationToken) => {
				return that._proxy.$resolveNotebookKernel(handle, editorId, uri, kernelId, token);
			},
540 541
			executeNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined, token: CancellationToken) => {
				return that._proxy.$executeNotebookKernelFromProvider(handle, uri, kernelId, cellHandle, token);
R
rebornix 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
			}
		});
		this._notebookKernelProviders.set(handle, {
			extension,
			emitter,
			provider
		});

		return;
	}

	async $unregisterNotebookKernelProvider(handle: number): Promise<void> {
		const entry = this._notebookKernelProviders.get(handle);

		if (entry) {
			entry.emitter.dispose();
			entry.provider.dispose();
			this._notebookKernelProviders.delete(handle);
		}
	}

	$onNotebookKernelChange(handle: number): void {
		const entry = this._notebookKernelProviders.get(handle);

		entry?.emitter.fire();
	}

R
rebornix 已提交
569
	async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
570 571
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
		textModel?.updateLanguages(languages);
R
rebornix 已提交
572
	}
R
rebornix 已提交
573

R
rebornix 已提交
574
	async $updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata): Promise<void> {
575 576
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
		textModel?.updateNotebookMetadata(metadata);
R
rebornix 已提交
577 578
	}

579
	async $updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata): Promise<void> {
580 581
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
		textModel?.updateNotebookCellMetadata(handle, metadata);
582 583
	}

584
	async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void> {
585 586 587 588 589 590
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));

		if (textModel) {
			await this._notebookService.transformSpliceOutputs(textModel, splices);
			textModel.$spliceNotebookCellOutputs(cellHandle, splices);
		}
591 592
	}

593 594
	async executeNotebookByAttachedKernel(viewType: string, uri: URI, token: CancellationToken): Promise<void> {
		return this._proxy.$executeNotebookByAttachedKernel(viewType, uri, undefined, token);
R
rebornix 已提交
595
	}
596

597 598 599 600 601
	async $postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean> {
		const editor = this._notebookService.getNotebookEditor(editorId) as INotebookEditor | undefined;
		if (editor?.isNotebookEditor) {
			editor.postMessage(forRendererId, value);
			return true;
602 603 604 605
		}

		return false;
	}
606 607

	$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void {
608 609 610 611 612 613 614 615 616
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));

		if (textModel) {
			textModel.$handleEdit(label, () => {
				return this._proxy.$undoNotebook(textModel.viewType, textModel.uri, editId, textModel.isDirty);
			}, () => {
				return this._proxy.$redoNotebook(textModel.viewType, textModel.uri, editId, textModel.isDirty);
			});
		}
617 618 619
	}

	$onContentChange(resource: UriComponents, viewType: string): void {
620 621
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
		textModel?.handleUnknownChange();
622
	}
R
rebornix 已提交
623 624
}

R
rebornix 已提交
625 626 627 628
export class MainThreadNotebookKernel implements INotebookKernelInfo {
	constructor(
		private readonly _proxy: ExtHostNotebookShape,
		readonly id: string,
R
rebornix 已提交
629
		readonly label: string,
R
rebornix 已提交
630 631 632 633 634 635 636 637 638 639 640
		readonly selectors: (string | IRelativePattern)[],
		readonly extension: ExtensionIdentifier,
		readonly extensionLocation: URI,
		readonly preloads: URI[]
	) {
	}

	async executeNotebook(viewType: string, uri: URI, handle: number | undefined, token: CancellationToken): Promise<void> {
		return this._proxy.$executeNotebook2(this.id, viewType, uri, handle, token);
	}
}
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661

export class MainThreadNotebookRenderer implements INotebookRendererInfo {
	constructor(
		private readonly _proxy: ExtHostNotebookShape,
		readonly id: string,
		readonly extensionId: ExtensionIdentifier,
		readonly extensionLocation: URI,
		readonly selectors: INotebookMimeTypeSelector,
		readonly preloads: URI[]
	) {

	}

	render(uri: URI, request: IOutputRenderRequest<UriComponents>): Promise<IOutputRenderResponse<UriComponents> | undefined> {
		return this._proxy.$renderOutputs(uri, this.id, request);
	}

	render2<T>(uri: URI, request: IOutputRenderRequest<T>): Promise<IOutputRenderResponse<T> | undefined> {
		return this._proxy.$renderOutputs2(uri, this.id, request);
	}
}