mainThreadNotebook.ts 27.0 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
import { ILogService } from 'vs/platform/log/common/log';
R
rebornix 已提交
25

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

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

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

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

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

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

R
rebornix 已提交
63
class DocumentAndEditorState {
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
	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 已提交
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 105
	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: [],
106 107
				addedEditors: apiEditors,
				visibleEditors: [...after.visibleEditors].map(editor => editor[0])
R
rebornix 已提交
108 109
			};
		}
110
		const documentDelta = DocumentAndEditorState.ofSets(before.documents, after.documents);
R
rebornix 已提交
111 112 113 114
		const editorDelta = DocumentAndEditorState.ofMaps(before.textEditors, after.textEditors);
		const addedAPIEditors = editorDelta.added.map(add => ({
			id: add.getId(),
			documentUri: add.uri!,
115
			selections: add.textModel!.selections || []
R
rebornix 已提交
116 117 118 119 120 121 122
		}));

		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;

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

R
rebornix 已提交
125
		return {
126 127 128 129 130 131 132 133 134 135 136
			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(),
137
						eol: cell.textBuffer.getEOL(),
138 139 140 141 142 143 144 145 146 147 148 149
						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 已提交
150 151
			addedEditors: addedAPIEditors,
			removedEditors: removedAPIEditors,
152 153 154 155
			newActiveEditor: newActiveEditor,
			visibleEditors: visibleEditorDelta.added.length === 0 && visibleEditorDelta.removed.length === 0
				? undefined
				: [...after.visibleEditors].map(editor => editor[0])
R
rebornix 已提交
156 157 158 159
		};
	}

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

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

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

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

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

		return false;
R
rebornix 已提交
202 203
	}

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

R
rebornix 已提交
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 238 239
	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;
	}

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

245
		return this._proxy.$acceptDocumentAndEditorsDelta(delta);
246 247
	}

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

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

R
rebornix 已提交
257
		this._register(this._notebookService.onDidChangeVisibleEditors(e => {
258 259 260 261 262 263 264 265 266
			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 已提交
267 268
		}));

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

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

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
		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 已提交
294 295 296
			this._updateState();
		}));

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

303
			this._updateState();
R
rebornix 已提交
304 305
		}));

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

310 311 312 313
		this._register(this._notebookService.onNotebookDocumentSaved(e => {
			this._proxy.$acceptModelSaved(e);
		}));

R
rebornix 已提交
314 315 316 317 318 319 320
		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 已提交
321

R
rebornix 已提交
322
		updateOrder();
R
rebornix 已提交
323

R
rebornix 已提交
324 325 326
		this._register(this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectedKeys.indexOf('notebook.displayOrder') >= 0) {
				updateOrder();
R
rebornix 已提交
327
			}
R
rebornix 已提交
328 329 330 331 332
		}));

		this._register(this.accessibilityService.onDidChangeScreenReaderOptimized(() => {
			updateOrder();
		}));
R
rebornix 已提交
333 334 335 336

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

R
rebornix 已提交
339 340 341
	private _addNotebookEditor(e: IEditor) {
		this._toDisposeOnEditorRemove.set(e.getId(), combinedDisposable(
			e.onDidChangeModel(() => this._updateState()),
R
rebornix 已提交
342 343 344
			e.onDidFocusEditorWidget(() => {
				this._updateState(e);
			}),
R
rebornix 已提交
345 346
		));

R
rebornix 已提交
347 348 349
		const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
		const notebookEditor = activeEditorPane?.isNotebookEditor ? activeEditorPane.getControl() : undefined;
		this._updateState(notebookEditor);
R
rebornix 已提交
350 351
	}

352 353 354 355 356 357 358 359 360 361
	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 已提交
362 363 364 365 366
	}

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

367 368 369 370 371 372 373 374 375 376
		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 已提交
377 378
			if (editor.hasModel()) {
				editors.set(editor.getId(), editor);
379 380 381 382 383 384 385 386 387 388
				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 已提交
389 390
				}
			}
391 392 393 394
		});

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

398
		if (!activeEditor && focusedNotebookEditor && focusedNotebookEditor.hasModel()) {
R
rebornix 已提交
399 400 401
			activeEditor = focusedNotebookEditor.getId();
		}

R
rebornix 已提交
402
		// editors always have view model attached, which means there is already a document in exthost.
403
		const newState = new DocumentAndEditorState(documents, editors, activeEditor, visibleEditorsMap);
R
rebornix 已提交
404 405 406 407 408 409 410 411 412
		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;
413
		await this._emitDelta(delta);
R
rebornix 已提交
414 415 416
		// }
	}

417
	async $registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, preloads: UriComponents[]): Promise<void> {
R
rebornix 已提交
418 419 420 421 422 423 424
		const staticContribution = this._notebookService.getContributedNotebookOutputRenderers(type);

		if (!staticContribution) {
			throw new Error(`Notebook renderer for '${type}' is not statically registered.`);
		}

		const renderer = new MainThreadNotebookRenderer(this._proxy, type, staticContribution.displayName, extension.id, URI.revive(extension.location), selectors, preloads.map(uri => URI.revive(uri)));
425 426
		this._notebookRenderers.set(type, renderer);
		this._notebookService.registerNotebookRenderer(type, renderer);
R
rebornix 已提交
427 428
	}

429 430
	async $unregisterNotebookRenderer(id: string): Promise<void> {
		this._notebookService.unregisterNotebookRenderer(id);
R
rebornix 已提交
431 432
	}

433 434 435
	async $registerNotebookProvider(_extension: NotebookExtensionDescription, _viewType: string, _supportBackup: boolean, _kernel: INotebookKernelInfoDto | undefined): Promise<void> {
		const controller: IMainNotebookController = {
			kernel: _kernel,
436
			supportBackup: _supportBackup,
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
			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);
					});
				});
			},
459
			createNotebook: async (textModel: NotebookTextModel, backupId?: string) => {
460
				// open notebook document
461
				const data = await this._proxy.$resolveNotebookData(textModel.viewType, textModel.uri, backupId);
462 463 464 465 466 467 468 469 470 471 472 473 474 475
				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);
				}

476 477
				this._proxy.$acceptEditorPropertiesChanged(textModel.uri, { selections: null, metadata: textModel.metadata });
				return;
478 479 480 481
			},
			resolveNotebookEditor: async (viewType: string, uri: URI, editorId: string) => {
				await this._proxy.$resolveNotebookEditor(viewType, uri, editorId);
			},
R
Rob Lourens 已提交
482
			executeNotebookByAttachedKernel: async (viewType: string, uri: URI) => {
483
				return this.executeNotebookByAttachedKernel(viewType, uri, undefined);
R
Rob Lourens 已提交
484 485
			},
			cancelNotebookByAttachedKernel: async (viewType: string, uri: URI) => {
486
				return this.cancelNotebookByAttachedKernel(viewType, uri, undefined);
487 488 489 490 491 492 493
			},
			onDidReceiveMessage: (editorId: string, rendererType: string | undefined, message: unknown) => {
				this._proxy.$onDidReceiveMessage(editorId, rendererType, message);
			},
			removeNotebookDocument: async (uri: URI) => {
				return this.removeNotebookTextModel(uri);
			},
R
Rob Lourens 已提交
494
			executeNotebookCell: async (uri: URI, handle: number) => {
495
				return this.executeNotebookByAttachedKernel(_viewType, uri, handle);
R
Rob Lourens 已提交
496 497
			},
			cancelNotebookCell: async (uri: URI, handle: number) => {
498
				return this.cancelNotebookByAttachedKernel(_viewType, uri, handle);
499 500 501 502 503 504 505 506 507 508 509 510 511 512
			},
			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 已提交
513
		return;
R
rebornix 已提交
514 515
	}

516
	async $onNotebookChange(viewType: string, uri: UriComponents): Promise<void> {
517 518
		const textModel = this._notebookService.getNotebookTextModel(URI.from(uri));
		textModel?.handleUnknownChange();
519 520
	}

R
rebornix 已提交
521
	async $unregisterNotebookProvider(viewType: string): Promise<void> {
R
rebornix 已提交
522 523
		this._notebookProviders.delete(viewType);
		this._notebookService.unregisterNotebookProvider(viewType);
R
rebornix 已提交
524 525 526
		return;
	}

R
rebornix 已提交
527
	async $registerNotebookKernel(extension: NotebookExtensionDescription, id: string, label: string, selectors: (string | IRelativePattern)[], preloads: UriComponents[]): Promise<void> {
528
		const kernel = new MainThreadNotebookKernel(this._proxy, id, label, selectors, extension.id, URI.revive(extension.location), preloads.map(preload => URI.revive(preload)), this.logService);
R
rebornix 已提交
529 530 531 532 533 534 535 536 537 538 539
		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 已提交
540 541 542 543
	async $registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void> {
		const emitter = new Emitter<void>();
		const that = this;
		const provider = this._notebookService.registerNotebookKernelProvider({
R
rebornix 已提交
544 545
			providerExtensionId: extension.id.value,
			providerDescription: extension.description,
R
rebornix 已提交
546 547
			onDidChangeKernels: emitter.event,
			selector: documentFilter,
R
rebornix 已提交
548 549 550 551 552 553 554 555
			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 已提交
556 557 558 559
			},
			resolveKernel: (editorId: string, uri: URI, kernelId: string, token: CancellationToken) => {
				return that._proxy.$resolveNotebookKernel(handle, editorId, uri, kernelId, token);
			},
R
Rob Lourens 已提交
560
			executeNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined) => {
561
				this.logService.debug('MainthreadNotebooks.registerNotebookKernelProvider#executeNotebook', uri.path, kernelId, cellHandle);
R
Rob Lourens 已提交
562
				return that._proxy.$executeNotebookKernelFromProvider(handle, uri, kernelId, cellHandle);
563 564
			},
			cancelNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined) => {
565
				this.logService.debug('MainthreadNotebooks.registerNotebookKernelProvider#cancelNotebook', uri.path, kernelId, cellHandle);
566 567
				return that._proxy.$cancelNotebookKernelFromProvider(handle, uri, kernelId, cellHandle);
			},
R
rebornix 已提交
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
		});
		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 已提交
594
	async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
R
rebornix 已提交
595
		this.logService.debug('MainThreadNotebooks#updateNotebookLanguages', resource.path, languages);
596 597
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
		textModel?.updateLanguages(languages);
R
rebornix 已提交
598
	}
R
rebornix 已提交
599

R
rebornix 已提交
600
	async $updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata): Promise<void> {
R
rebornix 已提交
601
		this.logService.debug('MainThreadNotebooks#updateNotebookMetadata', resource.path, metadata);
602 603
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
		textModel?.updateNotebookMetadata(metadata);
R
rebornix 已提交
604 605
	}

606
	async $updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata): Promise<void> {
R
rebornix 已提交
607
		this.logService.debug('MainThreadNotebooks#updateNotebookCellMetadata', resource.path, handle, metadata);
608 609
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
		textModel?.updateNotebookCellMetadata(handle, metadata);
610 611
	}

612
	async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void> {
R
rebornix 已提交
613
		this.logService.debug('MainThreadNotebooks#spliceNotebookCellOutputs', resource.path, cellHandle);
614 615 616 617 618 619
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));

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

622 623 624
	async executeNotebookByAttachedKernel(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
		this.logService.debug('MainthreadNotebooks#executeNotebookByAttachedKernel', uri.path, handle);
		return this._proxy.$executeNotebookByAttachedKernel(viewType, uri, handle);
R
Rob Lourens 已提交
625 626
	}

627 628 629
	async cancelNotebookByAttachedKernel(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
		this.logService.debug('MainthreadNotebooks#cancelNotebookByAttachedKernel', uri.path, handle);
		return this._proxy.$cancelNotebookByAttachedKernel(viewType, uri, handle);
R
rebornix 已提交
630
	}
631

632 633 634 635 636
	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;
637 638 639 640
		}

		return false;
	}
641 642

	$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void {
643 644 645 646 647 648 649 650 651
		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);
			});
		}
652 653 654
	}

	$onContentChange(resource: UriComponents, viewType: string): void {
655 656
		const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
		textModel?.handleUnknownChange();
657
	}
R
rebornix 已提交
658 659
}

R
rebornix 已提交
660 661 662 663
export class MainThreadNotebookKernel implements INotebookKernelInfo {
	constructor(
		private readonly _proxy: ExtHostNotebookShape,
		readonly id: string,
R
rebornix 已提交
664
		readonly label: string,
R
rebornix 已提交
665 666 667
		readonly selectors: (string | IRelativePattern)[],
		readonly extension: ExtensionIdentifier,
		readonly extensionLocation: URI,
668 669
		readonly preloads: URI[],
		readonly logService: ILogService
R
rebornix 已提交
670 671 672
	) {
	}

R
Rob Lourens 已提交
673
	async executeNotebook(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
674
		this.logService.debug('MainThreadNotebookKernel#executeNotebook', uri.path, handle);
R
Rob Lourens 已提交
675
		return this._proxy.$executeNotebook2(this.id, viewType, uri, handle);
R
rebornix 已提交
676 677
	}
}
678 679 680 681 682

export class MainThreadNotebookRenderer implements INotebookRendererInfo {
	constructor(
		private readonly _proxy: ExtHostNotebookShape,
		readonly id: string,
R
rebornix 已提交
683
		public displayName: string,
684 685 686
		readonly extensionId: ExtensionIdentifier,
		readonly extensionLocation: URI,
		readonly selectors: INotebookMimeTypeSelector,
R
rebornix 已提交
687
		readonly preloads: URI[],
688 689 690 691 692 693 694 695 696 697 698 699
	) {

	}

	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);
	}
}