Files
azuredatastudio/src/vs/workbench/api/browser/mainThreadNotebook.ts

174 lines
7.3 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter } from 'vs/base/common/event';
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { INotebookCellStatusBarItemProvider, INotebookContributionData, NotebookDataDto, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookContentProvider, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainContext, MainThreadNotebookShape, NotebookExtensionDescription } from '../common/extHost.protocol';
@extHostNamedCustomer(MainContext.MainThreadNotebook)
export class MainThreadNotebooks implements MainThreadNotebookShape {
private readonly _disposables = new DisposableStore();
private readonly _proxy: ExtHostNotebookShape;
private readonly _notebookProviders = new Map<string, { controller: INotebookContentProvider, disposable: IDisposable }>();
private readonly _notebookSerializer = new Map<number, IDisposable>();
private readonly _notebookCellStatusBarRegistrations = new Map<number, IDisposable>();
constructor(
extHostContext: IExtHostContext,
@INotebookService private readonly _notebookService: INotebookService,
@INotebookCellStatusBarService private readonly _cellStatusBarService: INotebookCellStatusBarService,
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
}
dispose(): void {
this._disposables.dispose();
// remove all notebook providers
for (const item of this._notebookProviders.values()) {
item.disposable.dispose();
}
dispose(this._notebookSerializer.values());
}
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, data: INotebookContributionData | undefined): Promise<void> {
let contentOptions = { ...options };
const controller: INotebookContentProvider = {
get options() {
return contentOptions;
},
set options(newOptions) {
contentOptions.transientCellMetadata = newOptions.transientCellMetadata;
contentOptions.transientDocumentMetadata = newOptions.transientDocumentMetadata;
contentOptions.transientOutputs = newOptions.transientOutputs;
},
open: async (uri: URI, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken) => {
const data = await this._proxy.$openNotebook(viewType, uri, backupId, untitledDocumentData, token);
return {
data,
transientOptions: contentOptions
};
},
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.$backupNotebook(viewType, uri, token);
}
};
const disposable = new DisposableStore();
disposable.add(this._notebookService.registerNotebookController(viewType, extension, controller));
if (data) {
disposable.add(this._notebookService.registerContributedNotebookType(viewType, data));
}
this._notebookProviders.set(viewType, { controller, disposable });
}
async $updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; }): Promise<void> {
const provider = this._notebookProviders.get(viewType);
if (provider && options) {
provider.controller.options = options;
this._notebookService.listNotebookDocuments().forEach(document => {
if (document.viewType === viewType) {
document.transientOptions = provider.controller.options;
}
});
}
}
async $unregisterNotebookProvider(viewType: string): Promise<void> {
const entry = this._notebookProviders.get(viewType);
if (entry) {
entry.disposable.dispose();
this._notebookProviders.delete(viewType);
}
}
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, data: INotebookContributionData | undefined): void {
const registration = this._notebookService.registerNotebookSerializer(viewType, extension, {
options,
dataToNotebook: (data: VSBuffer): Promise<NotebookDataDto> => {
return this._proxy.$dataToNotebook(handle, data, CancellationToken.None);
},
notebookToData: (data: NotebookDataDto): Promise<VSBuffer> => {
return this._proxy.$notebookToData(handle, data, CancellationToken.None);
}
});
const disposables = new DisposableStore();
disposables.add(registration);
if (data) {
disposables.add(this._notebookService.registerContributedNotebookType(viewType, data));
}
this._notebookSerializer.set(handle, disposables);
}
$unregisterNotebookSerializer(handle: number): void {
this._notebookSerializer.get(handle)?.dispose();
this._notebookSerializer.delete(handle);
}
$emitCellStatusBarEvent(eventHandle: number): void {
const emitter = this._notebookCellStatusBarRegistrations.get(eventHandle);
if (emitter instanceof Emitter) {
emitter.fire(undefined);
}
}
async $registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise<void> {
const that = this;
const provider: INotebookCellStatusBarItemProvider = {
async provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken) {
const result = await that._proxy.$provideNotebookCellStatusBarItems(handle, uri, index, token);
return {
items: result?.items ?? [],
dispose() {
if (result) {
that._proxy.$releaseNotebookCellStatusBarItems(result.cacheId);
}
}
};
},
viewType
};
if (typeof eventHandle === 'number') {
const emitter = new Emitter<void>();
this._notebookCellStatusBarRegistrations.set(eventHandle, emitter);
provider.onDidChangeStatusBarItems = emitter.event;
}
const disposable = this._cellStatusBarService.registerCellStatusBarItemProvider(provider);
this._notebookCellStatusBarRegistrations.set(handle, disposable);
}
async $unregisterNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise<void> {
const unregisterThing = (handle: number) => {
const entry = this._notebookCellStatusBarRegistrations.get(handle);
if (entry) {
this._notebookCellStatusBarRegistrations.get(handle)?.dispose();
this._notebookCellStatusBarRegistrations.delete(handle);
}
};
unregisterThing(handle);
if (typeof eventHandle === 'number') {
unregisterThing(eventHandle);
}
}
}