mainThreadNotebook.ts 10.7 KB
Newer Older
R
rebornix 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext } from '../common/extHost.protocol';
R
rebornix 已提交
8
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
R
rebornix 已提交
9
import { URI, UriComponents } from 'vs/base/common/uri';
R
rebornix 已提交
10
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/browser/notebookService';
R
rebornix 已提交
11
import { INotebook, ICell, IOutput } from 'vs/editor/common/modes';
R
rebornix 已提交
12 13 14 15 16 17
import { Emitter, Event } from 'vs/base/common/event';

export class MainThreadCell implements ICell {
	private _onDidChangeOutputs = new Emitter<void>();
	onDidChangeOutputs: Event<void> = this._onDidChangeOutputs.event;

R
rebornix 已提交
18 19 20
	private _onDidChangeDirtyState = new Emitter<boolean>();
	onDidChangeDirtyState: Event<boolean> = this._onDidChangeDirtyState.event;

R
rebornix 已提交
21 22 23 24 25 26 27 28 29 30 31
	private _outputs: IOutput[];

	public get outputs(): IOutput[] {
		return this._outputs;
	}

	public set outputs(newOutputs: IOutput[]) {
		this._outputs = newOutputs;
		this._onDidChangeOutputs.fire();
	}

R
rebornix 已提交
32 33 34 35 36 37 38 39 40 41 42
	private _isDirty: boolean = false;

	get isDirty() {
		return this._isDirty;
	}

	set isDirty(newState: boolean) {
		this._isDirty = newState;
		this._onDidChangeDirtyState.fire(newState);
	}

R
rebornix 已提交
43 44 45
	constructor(
		public handle: number,
		public source: string[],
R
rebornix 已提交
46
		public language: string,
R
rebornix 已提交
47 48 49 50 51
		public cell_type: 'markdown' | 'code',
		outputs: IOutput[]
	) {
		this._outputs = outputs;
	}
R
rebornix 已提交
52 53 54 55

	save() {
		this._isDirty = false;
	}
R
rebornix 已提交
56 57
}

R
rebornix 已提交
58 59 60
export class MainThreadNotebookDocument extends Disposable implements INotebook {
	private readonly _onWillDispose: Emitter<void> = this._register(new Emitter<void>());
	public readonly onWillDispose: Event<void> = this._onWillDispose.event;
R
rebornix 已提交
61 62
	private readonly _onDidChangeCells = new Emitter<void>();
	get onDidChangeCells(): Event<void> { return this._onDidChangeCells.event; }
R
rebornix 已提交
63 64
	private _onDidChangeDirtyState = new Emitter<boolean>();
	onDidChangeDirtyState: Event<boolean> = this._onDidChangeDirtyState.event;
R
rebornix 已提交
65
	private _mapping: Map<number, MainThreadCell> = new Map();
R
rebornix 已提交
66
	private _cellListeners: Map<number, IDisposable> = new Map();
R
rebornix 已提交
67
	public cells: MainThreadCell[];
R
rebornix 已提交
68
	public activeCell: MainThreadCell | undefined;
R
rebornix 已提交
69 70 71 72 73 74 75 76 77 78 79 80
	public languages: string[] = [];

	private _isDirty: boolean = false;

	get isDirty() {
		return this._isDirty;
	}

	set isDirty(newState: boolean) {
		this._isDirty = newState;
		this._onDidChangeDirtyState.fire(newState);
	}
R
rebornix 已提交
81 82

	constructor(
R
rebornix 已提交
83
		private readonly _proxy: ExtHostNotebookShape,
R
rebornix 已提交
84
		public handle: number,
R
rebornix 已提交
85
		public viewType: string,
R
rebornix 已提交
86
		public uri: URI
R
rebornix 已提交
87
	) {
R
rebornix 已提交
88
		super();
R
rebornix 已提交
89
		this.cells = [];
R
rebornix 已提交
90 91
	}

R
rebornix 已提交
92 93 94 95
	updateLanguages(languages: string[]) {
		this.languages = languages;
	}

R
rebornix 已提交
96 97 98 99 100 101
	updateCell(cell: ICell) {
		let mcell = this._mapping.get(cell.handle);

		if (mcell) {
			mcell.outputs = cell.outputs;
		}
R
rebornix 已提交
102 103 104 105
	}

	updateCells(newCells: ICell[]) {
		// todo, handle cell insertion and deletion
R
rebornix 已提交
106 107 108

		if (this.cells.length === 0) {
			newCells.forEach(cell => {
R
rebornix 已提交
109
				let mainCell = new MainThreadCell(cell.handle, cell.source, cell.language, cell.cell_type, cell.outputs);
R
rebornix 已提交
110 111
				this._mapping.set(cell.handle, mainCell);
				this.cells.push(mainCell);
R
rebornix 已提交
112 113 114 115
				let dirtyStateListener = mainCell.onDidChangeDirtyState((cellState) => {
					this.isDirty = this.isDirty || cellState;
				});
				this._cellListeners.set(cell.handle, dirtyStateListener);
R
rebornix 已提交
116 117 118 119 120 121 122 123 124
			});
		} else {
			newCells.forEach(newCell => {
				let cell = this._mapping.get(newCell.handle);
				if (cell) {
					cell.outputs = newCell.outputs;
				}
			});
		}
R
rebornix 已提交
125 126 127

		this._onDidChangeCells.fire();
	}
R
rebornix 已提交
128 129 130 131

	updateActiveCell(handle: number) {
		this.activeCell = this._mapping.get(handle);
	}
R
rebornix 已提交
132

R
rebornix 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
	async createRawCell(viewType: string, uri: URI, index: number, language: string, type: 'markdown' | 'code'): Promise<MainThreadCell | undefined> {
		let cell = await this._proxy.$createRawCell(viewType, uri, index, language, type);
		if (cell) {
			let mainCell = new MainThreadCell(cell.handle, cell.source, cell.language, cell.cell_type, cell.outputs);
			this._mapping.set(cell.handle, mainCell);
			this.cells.splice(index, 0, mainCell);

			let dirtyStateListener = mainCell.onDidChangeDirtyState((cellState) => {
				this.isDirty = this.isDirty || cellState;
			});

			this._cellListeners.set(cell.handle, dirtyStateListener);
			return mainCell;
		}

		return;
	}

	async removeCell(viewType: string, uri: URI, index: number): Promise<boolean> {
		return true;
	}

	async save(): Promise<boolean> {
		let ret = await this._proxy.$saveNotebook(this.viewType, this.uri);

		if (ret) {
			this.cells.forEach((cell) => {
				cell.save();
			});
		}

		return ret;
	}

R
rebornix 已提交
167 168 169 170
	dispose() {
		this._onWillDispose.fire();
		super.dispose();
	}
R
rebornix 已提交
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
}

@extHostNamedCustomer(MainContext.MainThreadNotebook)
export class MainThreadNotebooks extends Disposable implements MainThreadNotebookShape {
	private readonly _notebookProviders = new Map<string, MainThreadNotebookController>();
	private readonly _proxy: ExtHostNotebookShape;

	constructor(
		extHostContext: IExtHostContext,
		@INotebookService private _notebookService: INotebookService
	) {
		super();
		this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
	}

R
rebornix 已提交
186 187
	async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string): Promise<void> {
		let controller = new MainThreadNotebookController(this._proxy, this, viewType);
R
rebornix 已提交
188
		this._notebookProviders.set(viewType, controller);
R
rebornix 已提交
189
		this._notebookService.registerNotebookController(viewType, extension, controller);
R
rebornix 已提交
190
		return;
R
rebornix 已提交
191 192
	}

R
rebornix 已提交
193
	async $unregisterNotebookProvider(viewType: string): Promise<void> {
R
rebornix 已提交
194 195
		this._notebookProviders.delete(viewType);
		this._notebookService.unregisterNotebookProvider(viewType);
R
rebornix 已提交
196 197 198
		return;
	}

R
rebornix 已提交
199 200 201 202 203 204 205 206 207
	async $createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void> {
		let controller = this._notebookProviders.get(viewType);

		if (controller) {
			controller.createNotebookDocument(handle, viewType, resource);
		}

		// let document = new MainThreadNotebookDocument(this._proxy, handle, viewType, URI.revive(resource));
		// this._documents.set(handle, document);
R
rebornix 已提交
208 209 210
		return;
	}

R
rebornix 已提交
211 212
	async $updateNotebookCells(viewType: string, resource: UriComponents, cells: ICell[]): Promise<void> {
		let controller = this._notebookProviders.get(viewType);
R
rebornix 已提交
213

R
rebornix 已提交
214 215
		if (controller) {
			controller.updateNotebookCells(resource, cells);
R
rebornix 已提交
216 217 218
		}
	}

R
rebornix 已提交
219 220
	async $updateNotebookCell(viewType: string, resource: UriComponents, cell: ICell): Promise<void> {
		let controller = this._notebookProviders.get(viewType);
R
rebornix 已提交
221

R
rebornix 已提交
222 223
		if (controller) {
			controller.updateNotebookCell(resource, cell);
R
rebornix 已提交
224
		}
R
rebornix 已提交
225

R
rebornix 已提交
226
	}
R
rebornix 已提交
227

R
rebornix 已提交
228
	async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
R
rebornix 已提交
229 230 231
		let controller = this._notebookProviders.get(viewType);

		if (controller) {
R
rebornix 已提交
232
			controller.updateLanguages(resource, languages);
R
rebornix 已提交
233 234
		}
	}
R
rebornix 已提交
235

R
rebornix 已提交
236 237
	async $updateNotebook(viewType: string, resource: UriComponents, notebook: INotebook): Promise<void> {
		let controller = this._notebookProviders.get(viewType);
R
rebornix 已提交
238

R
rebornix 已提交
239 240
		if (controller) {
			controller.updateNotebook(resource, notebook);
R
rebornix 已提交
241
		}
R
rebornix 已提交
242
	}
R
rebornix 已提交
243

R
rebornix 已提交
244 245 246
	async resolveNotebook(viewType: string, uri: URI): Promise<number | undefined> {
		let handle = await this._proxy.$resolveNotebook(viewType, uri);
		return handle;
R
rebornix 已提交
247 248 249 250 251 252 253 254
	}

	executeNotebook(viewType: string, uri: URI): Promise<void> {
		return this._proxy.$executeNotebook(viewType, uri);
	}
}

export class MainThreadNotebookController implements IMainNotebookController {
R
rebornix 已提交
255
	private _mapping: Map<string, MainThreadNotebookDocument> = new Map();
R
rebornix 已提交
256 257

	constructor(
R
rebornix 已提交
258 259 260
		private readonly _proxy: ExtHostNotebookShape,
		private _mainThreadNotebook: MainThreadNotebooks,
		private _viewType: string
R
rebornix 已提交
261 262 263 264
	) {
	}

	async resolveNotebook(viewType: string, uri: URI): Promise<INotebook | undefined> {
R
rebornix 已提交
265 266 267 268 269 270 271 272 273 274
		let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());

		if (mainthreadNotebook) {
			return mainthreadNotebook;
		}

		let notebookHandle = await this._mainThreadNotebook.resolveNotebook(viewType, uri);
		if (notebookHandle !== undefined) {
			mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
			return mainthreadNotebook;
R
rebornix 已提交
275
		}
R
rebornix 已提交
276

R
rebornix 已提交
277 278 279 280 281 282 283
		return undefined;
	}

	async executeNotebook(viewType: string, uri: URI): Promise<void> {
		this._mainThreadNotebook.executeNotebook(viewType, uri);
	}

R
rebornix 已提交
284 285 286 287 288 289 290 291
	// Methods for ExtHost
	async createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void> {
		let document = new MainThreadNotebookDocument(this._proxy, handle, viewType, URI.revive(resource));
		this._mapping.set(URI.revive(resource).toString(), document);
	}

	updateNotebook(resource: UriComponents, notebook: INotebook): void {
		let mainthreadNotebook = this._mapping.get(URI.from(resource).toString());
R
rebornix 已提交
292 293 294 295 296

		if (mainthreadNotebook) {
			mainthreadNotebook.updateCells(notebook.cells);
		}
	}
R
rebornix 已提交
297

R
rebornix 已提交
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
	updateLanguages(resource: UriComponents, languages: string[]) {
		let document = this._mapping.get(URI.from(resource).toString());

		if (document) {
			document.updateLanguages(languages);
		}
	}

	updateNotebookCells(resource: UriComponents, cells: ICell[]): void {
		let document = this._mapping.get(URI.from(resource).toString());

		if (document) {
			document.updateCells(cells);
		}
	}

	updateNotebookCell(resource: UriComponents, cell: ICell): void {
		let document = this._mapping.get(URI.from(resource).toString());

		if (document) {
			document.updateCell(cell);
		}
	}

R
rebornix 已提交
322 323 324 325 326 327 328 329
	updateNotebookActiveCell(uri: URI, cellHandle: number): void {
		let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());

		if (mainthreadNotebook) {
			mainthreadNotebook.updateActiveCell(cellHandle);
		}
	}

R
rebornix 已提交
330 331 332 333 334 335 336 337 338 339
	async createRawCell(uri: URI, index: number, language: string, type: 'markdown' | 'code'): Promise<ICell | undefined> {
		let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());

		if (mainthreadNotebook) {
			return mainthreadNotebook.createRawCell(this._viewType, uri, index, language, type);
		}

		return;
	}

R
rebornix 已提交
340 341 342 343 344 345 346
	executeNotebookActiveCell(uri: URI): void {
		let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());

		if (mainthreadNotebook && mainthreadNotebook.activeCell) {
			this._proxy.$executeNotebookCell(this._viewType, uri, mainthreadNotebook.activeCell.handle);
		}
	}
R
rebornix 已提交
347 348 349 350 351 352 353 354 355

	destoryNotebookDocument(notebook: INotebook): void {
		let mainthreadNotebook = this._mapping.get(URI.from(notebook.uri).toString());

		if (mainthreadNotebook) {
			mainthreadNotebook.dispose();
			this._mapping.delete(URI.from(notebook.uri).toString());
		}
	}
R
rebornix 已提交
356
}