notebookServiceImpl.ts 11.1 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 } from 'vs/base/common/lifecycle';
8
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
R
rebornix 已提交
9
import { URI } from 'vs/base/common/uri';
R
rebornix 已提交
10
import { notebookProviderExtensionPoint, notebookRendererExtensionPoint } from 'vs/workbench/contrib/notebook/browser/extensionPoint';
R
rebornix 已提交
11
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
R
rebornix 已提交
12
import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.protocol';
R
rebornix 已提交
13
import { Emitter, Event } from 'vs/base/common/event';
R
rebornix 已提交
14
import { INotebookTextModel, INotebookMimeTypeSelector, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon';
15
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
R
rebornix 已提交
16
import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer';
J
Johannes Rieken 已提交
17
import { Iterable } from 'vs/base/common/iterator';
18
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
19
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
20
import { IEditorService, ICustomEditorViewTypesHandler, ICustomEditorInfo } from 'vs/workbench/services/editor/common/editorService';
R
rebornix 已提交
21
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
22 23
import { NotebookEditorModelManager } from 'vs/workbench/contrib/notebook/common/notebookEditorModel';
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/common/notebookService';
24

R
rebornix 已提交
25 26 27 28
function MODEL_ID(resource: URI): string {
	return resource.toString();
}

R
rebornix 已提交
29
export class NotebookProviderInfoStore {
R
rebornix 已提交
30 31
	private readonly contributedEditors = new Map<string, NotebookProviderInfo>();

R
rebornix 已提交
32
	clear() {
R
rebornix 已提交
33 34 35
		this.contributedEditors.clear();
	}

R
rebornix 已提交
36
	get(viewType: string): NotebookProviderInfo | undefined {
R
rebornix 已提交
37 38 39
		return this.contributedEditors.get(viewType);
	}

R
rebornix 已提交
40
	add(info: NotebookProviderInfo): void {
R
rebornix 已提交
41 42 43 44 45 46 47
		if (this.contributedEditors.has(info.id)) {
			console.log(`Custom editor with id '${info.id}' already registered`);
			return;
		}
		this.contributedEditors.set(info.id, info);
	}

R
rebornix 已提交
48
	getContributedNotebook(resource: URI): readonly NotebookProviderInfo[] {
J
Johannes Rieken 已提交
49
		return [...Iterable.filter(this.contributedEditors.values(), customEditor => customEditor.matches(resource))];
R
rebornix 已提交
50
	}
51 52 53 54

	public [Symbol.iterator](): Iterator<NotebookProviderInfo> {
		return this.contributedEditors.values();
	}
R
rebornix 已提交
55 56
}

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
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)) {
			console.log(`Custom notebook output renderer with id '${info.id}' already registered`);
			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 已提交
82 83 84 85
class ModelData implements IDisposable {
	private readonly _modelEventListeners = new DisposableStore();

	constructor(
86 87
		public model: NotebookTextModel,
		onWillDispose: (model: INotebookTextModel) => void
R
rebornix 已提交
88 89 90 91
	) {
		this._modelEventListeners.add(model.onWillDispose(() => onWillDispose(model)));
	}

R
rebornix 已提交
92
	dispose(): void {
R
rebornix 已提交
93 94 95
		this._modelEventListeners.dispose();
	}
}
96
export class NotebookService extends Disposable implements INotebookService, ICustomEditorViewTypesHandler {
R
rebornix 已提交
97
	_serviceBrand: undefined;
R
rebornix 已提交
98
	private readonly _notebookProviders = new Map<string, { controller: IMainNotebookController, extensionData: NotebookExtensionDescription }>();
R
rebornix 已提交
99 100 101
	private readonly _notebookRenderers = new Map<number, { extensionData: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, preloads: URI[] }>();
	notebookProviderInfoStore: NotebookProviderInfoStore = new NotebookProviderInfoStore();
	notebookRenderersInfoStore: NotebookOutputRendererInfoStore = new NotebookOutputRendererInfoStore();
R
rebornix 已提交
102
	private readonly _models: { [modelId: string]: ModelData; };
R
rebornix 已提交
103 104
	private _onDidChangeActiveEditor = new Emitter<{ viewType: string, uri: URI }>();
	onDidChangeActiveEditor: Event<{ viewType: string, uri: URI }> = this._onDidChangeActiveEditor.event;
R
rebornix 已提交
105

106 107
	private readonly _onDidChangeViewTypes = new Emitter<void>();
	onDidChangeViewTypes: Event<void> = this._onDidChangeViewTypes.event;
R
rebornix 已提交
108
	private cutItems: NotebookCellTextModel[] | undefined;
109

110 111
	modelManager: NotebookEditorModelManager;

112
	constructor(
113
		@IExtensionService private readonly extensionService: IExtensionService,
114 115
		@IEditorService private readonly editorService: IEditorService,
		@IInstantiationService private readonly instantiationService: IInstantiationService
116
	) {
R
rebornix 已提交
117 118
		super();

R
rebornix 已提交
119
		this._models = {};
120 121
		this.modelManager = this.instantiationService.createInstance(NotebookEditorModelManager);

R
rebornix 已提交
122
		notebookProviderExtensionPoint.setHandler((extensions) => {
R
rebornix 已提交
123 124 125 126 127 128 129 130
			this.notebookProviderInfoStore.clear();

			for (const extension of extensions) {
				for (const notebookContribution of extension.value) {
					this.notebookProviderInfoStore.add(new NotebookProviderInfo({
						id: notebookContribution.viewType,
						displayName: notebookContribution.displayName,
						selector: notebookContribution.selector || [],
R
rebornix 已提交
131
						providerDisplayName: extension.description.isBuiltin ? nls.localize('builtinProviderDisplayName', "Built-in") : extension.description.displayName || extension.description.identifier.value,
R
rebornix 已提交
132 133 134 135 136 137
					}));
				}
			}
			// console.log(this._notebookProviderInfoStore);
		});

R
rebornix 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
		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,
						mimeTypes: notebookContribution.mimeTypes || []
					}));
				}
			}

			// console.log(this.notebookRenderersInfoStore);
		});
153 154 155 156 157 158 159 160 161 162

		this.editorService.registerCustomEditorViewTypesHandler('Notebook', this);
	}

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

165 166 167 168
	async canResolve(viewType: string): Promise<boolean> {
		if (!this._notebookProviders.has(viewType)) {
			// this awaits full activation of all matching extensions
			await this.extensionService.activateByEvent(`onNotebookEditor:${viewType}`);
R
rebornix 已提交
169
		}
170
		return this._notebookProviders.has(viewType);
171 172
	}

R
rebornix 已提交
173 174
	registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: IMainNotebookController) {
		this._notebookProviders.set(viewType, { extensionData, controller });
175
		this._onDidChangeViewTypes.fire();
R
rebornix 已提交
176 177 178 179
	}

	unregisterNotebookProvider(viewType: string): void {
		this._notebookProviders.delete(viewType);
180
		this._onDidChangeViewTypes.fire();
R
rebornix 已提交
181 182
	}

R
rebornix 已提交
183 184
	registerNotebookRenderer(handle: number, extensionData: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, preloads: URI[]) {
		this._notebookRenderers.set(handle, { extensionData, type, selectors, preloads });
185 186 187 188 189 190
	}

	unregisterNotebookRenderer(handle: number) {
		this._notebookRenderers.delete(handle);
	}

191
	getRendererInfo(handle: number): INotebookRendererInfo | undefined {
192 193 194 195
		const renderer = this._notebookRenderers.get(handle);

		if (renderer) {
			return {
196
				id: renderer.extensionData.id,
197 198 199 200 201 202
				extensionLocation: URI.revive(renderer.extensionData.location),
				preloads: renderer.preloads
			};
		}

		return;
203 204
	}

205
	async resolveNotebook(viewType: string, uri: URI): Promise<NotebookTextModel | undefined> {
206 207 208 209
		const provider = this._notebookProviders.get(viewType);
		if (!provider) {
			return undefined;
		}
R
rebornix 已提交
210

211 212 213
		const notebookModel = await provider.controller.resolveNotebook(viewType, uri);
		if (!notebookModel) {
			return undefined;
R
rebornix 已提交
214 215
		}

216 217 218 219 220 221 222 223
		// new notebook model created
		const modelId = MODEL_ID(uri);
		const modelData = new ModelData(
			notebookModel,
			(model) => this._onWillDispose(model),
		);
		this._models[modelId] = modelData;
		return modelData.model;
R
rebornix 已提交
224 225
	}

R
rebornix 已提交
226 227 228 229
	async executeNotebook(viewType: string, uri: URI): Promise<void> {
		let provider = this._notebookProviders.get(viewType);

		if (provider) {
230
			return provider.controller.executeNotebook(viewType, uri, new CancellationTokenSource().token); // Cancellation for notebooks - TODO
R
rebornix 已提交
231 232 233 234 235
		}

		return;
	}

236
	async executeNotebookCell(viewType: string, uri: URI, handle: number, token: CancellationToken): Promise<void> {
237 238
		const provider = this._notebookProviders.get(viewType);
		if (provider) {
239
			await provider.controller.executeNotebookCell(uri, handle, token);
240 241 242
		}
	}

R
rebornix 已提交
243
	getContributedNotebookProviders(resource: URI): readonly NotebookProviderInfo[] {
R
rebornix 已提交
244 245
		return this.notebookProviderInfoStore.getContributedNotebook(resource);
	}
R
rebornix 已提交
246

R
rebornix 已提交
247 248 249 250
	getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined {
		return this.notebookProviderInfoStore.get(viewType);
	}

R
rebornix 已提交
251 252 253 254
	getContributedNotebookOutputRenderers(mimeType: string): readonly NotebookOutputRendererInfo[] {
		return this.notebookRenderersInfoStore.getContributedRenderer(mimeType);
	}

R
rebornix 已提交
255
	getNotebookProviderResourceRoots(): URI[] {
R
rebornix 已提交
256 257 258 259 260 261 262
		let ret: URI[] = [];
		this._notebookProviders.forEach(val => {
			ret.push(URI.revive(val.extensionData.location));
		});

		return ret;
	}
R
rebornix 已提交
263

264
	destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void {
R
rebornix 已提交
265 266 267 268 269 270 271
		let provider = this._notebookProviders.get(viewType);

		if (provider) {
			provider.controller.destoryNotebookDocument(notebook);
		}
	}

R
rebornix 已提交
272 273 274 275
	updateActiveNotebookDocument(viewType: string, resource: URI): void {
		this._onDidChangeActiveEditor.fire({ viewType, uri: resource });
	}

R
rebornix 已提交
276 277 278 279 280 281 282 283
	setToCopy(items: NotebookCellTextModel[]) {
		this.cutItems = items;
	}

	getToCopy(): NotebookCellTextModel[] | undefined {
		return this.cutItems;
	}

284 285 286 287 288 289 290 291 292 293
	async save(viewType: string, resource: URI): Promise<boolean> {
		let provider = this._notebookProviders.get(viewType);

		if (provider) {
			return provider.controller.save(resource);
		}

		return false;
	}

294 295 296 297 298 299 300 301
	onDidReceiveMessage(viewType: string, uri: URI, message: any): void {
		let provider = this._notebookProviders.get(viewType);

		if (provider) {
			return provider.controller.onDidReceiveMessage(uri, message);
		}
	}

302
	private _onWillDispose(model: INotebookTextModel): void {
R
rebornix 已提交
303 304 305 306
		let modelId = MODEL_ID(model.uri);
		let modelData = this._models[modelId];

		delete this._models[modelId];
R
rebornix 已提交
307
		modelData?.dispose();
R
rebornix 已提交
308 309 310

		// this._onModelRemoved.fire(model);
	}
R
rebornix 已提交
311
}