Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion src/vs/workbench/api/browser/mainThreadNotebook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { URI } from 'vs/base/common/uri';
import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { INotebookCellStatusBarItemProvider, INotebookContributionData, NotebookData as NotebookData, NotebookExtensionDescription, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookStatusBarService';
import { INotebookCellStatusBarItemProvider, INotebookContributionData, INotebookStatusBarItemProvider, NotebookData as NotebookData, NotebookExtensionDescription, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookContentProvider, INotebookService, SimpleNotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookService';
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { ExtHostContext, ExtHostNotebookShape, MainContext, MainThreadNotebookShape } from '../common/extHost.protocol';
Expand All @@ -29,11 +30,13 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
private readonly _notebookProviders = new Map<string, { controller: INotebookContentProvider; disposable: IDisposable }>();
private readonly _notebookSerializer = new Map<number, IDisposable>();
private readonly _notebookCellStatusBarRegistrations = new Map<number, IDisposable>();
private readonly _notebookStatusBarRegistrations = new Map<number, IDisposable>();

constructor(
extHostContext: IExtHostContext,
@INotebookService private readonly _notebookService: INotebookService,
@INotebookCellStatusBarService private readonly _cellStatusBarService: INotebookCellStatusBarService,
@INotebookStatusBarService private readonly _statusBarService: INotebookStatusBarService,
@ILogService private readonly _logService: ILogService,
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
Expand Down Expand Up @@ -185,6 +188,54 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
unregisterThing(eventHandle);
}
}

$emitStatusBarEvent(eventHandle: number): void {
const emitter = this._notebookStatusBarRegistrations.get(eventHandle);
if (emitter instanceof Emitter) {
emitter.fire(undefined);
}
}

async $registerNotebookStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise<void> {
const that = this;
const provider: INotebookStatusBarItemProvider = {
async provideStatusBarItems(uri: URI, token: CancellationToken) {
const result = await that._proxy.$provideNotebookStatusBarItems(handle, uri, token);
return {
items: result?.items ?? [],
dispose() {
if (result) {
that._proxy.$releaseNotebookStatusBarItems(result.cacheId);
}
}
};
},
viewType
};

if (typeof eventHandle === 'number') {
const emitter = new Emitter<void>();
this._notebookStatusBarRegistrations.set(eventHandle, emitter);
provider.onDidChangeStatusBarItems = emitter.event;
}

const disposable = this._statusBarService.registerStatusBarItemProvider(provider);
this._notebookStatusBarRegistrations.set(handle, disposable);
}

async $unregisterNotebookStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise<void> {
const unregisterThing = (handle: number) => {
const entry = this._notebookStatusBarRegistrations.get(handle);
if (entry) {
this._notebookStatusBarRegistrations.get(handle)?.dispose();
this._notebookStatusBarRegistrations.delete(handle);
}
};
unregisterThing(handle);
if (typeof eventHandle === 'number') {
unregisterThing(eventHandle);
}
}
}

CommandsRegistry.registerCommand('_executeDataToNotebook', async (accessor, ...args) => {
Expand Down
6 changes: 5 additions & 1 deletion src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
onDidChangeNotebookCellExecutionState(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension, 'notebookCellExecutionState');
return extHostNotebookKernels.onDidChangeNotebookCellExecutionState(listener, thisArgs, disposables);
}
},
registerNotebookStatusBarItemProvider: (notebookType: string, provider: vscode.NotebookStatusBarItemProvider) => {
return extHostNotebook.registerNotebookStatusBarItemProvider(extension, notebookType, provider);
},
};

return <typeof vscode>{
Expand Down Expand Up @@ -1326,6 +1329,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
NotebookCellOutput: extHostTypes.NotebookCellOutput,
NotebookCellOutputItem: extHostTypes.NotebookCellOutputItem,
NotebookCellStatusBarItem: extHostTypes.NotebookCellStatusBarItem,
NotebookStatusBarItem: extHostTypes.NotebookStatusBarItem,
NotebookControllerAffinity: extHostTypes.NotebookControllerAffinity,
NotebookEdit: extHostTypes.NotebookEdit,
PortAttributes: extHostTypes.PortAttributes,
Expand Down
14 changes: 14 additions & 0 deletions src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,13 @@ export interface INotebookCellStatusBarListDto {
cacheId: number;
}

export type INotebookStatusBarEntryDto = Dto<notebookCommon.INotebookStatusBarItem>;

export interface INotebookStatusBarListDto {
items: INotebookStatusBarEntryDto[];
cacheId: number;
}

export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(extension: notebookCommon.NotebookExtensionDescription, viewType: string, options: notebookCommon.TransientOptions, registration: notebookCommon.INotebookContributionData | undefined): Promise<void>;
$updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientCellMetadata: notebookCommon.TransientCellMetadata; transientDocumentMetadata: notebookCommon.TransientDocumentMetadata }): Promise<void>;
Expand All @@ -971,6 +978,10 @@ export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise<void>;
$unregisterNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise<void>;
$emitCellStatusBarEvent(eventHandle: number): void;

$registerNotebookStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise<void>;
$unregisterNotebookStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise<void>;
$emitStatusBarEvent(eventHandle: number): void;
}

export interface MainThreadNotebookEditorsShape extends IDisposable {
Expand Down Expand Up @@ -2055,6 +2066,9 @@ export interface ExtHostNotebookShape extends ExtHostNotebookDocumentsAndEditors
$provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined>;
$releaseNotebookCellStatusBarItems(id: number): void;

$provideNotebookStatusBarItems(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookStatusBarListDto | undefined>;
$releaseNotebookStatusBarItems(id: number): void;

$openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<SerializableObjectWithBuffers<NotebookDataDto>>;
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
Expand Down
68 changes: 59 additions & 9 deletions src/vs/workbench/api/common/extHostNotebook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { assertIsDefined } from 'vs/base/common/types';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { Cache } from 'vs/workbench/api/common/cache';
import { ExtHostNotebookShape, IMainContext, IModelAddedData, INotebookCellStatusBarListDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookEditorsShape, MainThreadNotebookShape, NotebookDataDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostNotebookShape, IMainContext, IModelAddedData, INotebookCellStatusBarListDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, INotebookStatusBarListDto, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookEditorsShape, MainThreadNotebookShape, NotebookDataDto } from 'vs/workbench/api/common/extHost.protocol';
import { ApiCommand, ApiCommandArgument, ApiCommandResult, CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
Expand All @@ -36,14 +36,16 @@ type NotebookContentProviderData = {
};

export class ExtHostNotebookController implements ExtHostNotebookShape {
private static _notebookCellStatusBarItemProviderHandlePool: number = 0;
private static _notebookStatusBarItemProviderHandlePool: number = 0;

private readonly _notebookProxy: MainThreadNotebookShape;
private readonly _notebookDocumentsProxy: MainThreadNotebookDocumentsShape;
private readonly _notebookEditorsProxy: MainThreadNotebookEditorsShape;

private readonly _notebookContentProviders = new Map<string, NotebookContentProviderData>();
private readonly _notebookStatusBarItemProviders = new Map<number, vscode.NotebookCellStatusBarItemProvider>();
private readonly _notebookCellStatusBarItemProviders = new Map<number, vscode.NotebookCellStatusBarItemProvider>();
private readonly _notebookStatusBarItemProviders = new Map<number, vscode.NotebookStatusBarItemProvider>();
private readonly _documents = new ResourceMap<ExtHostNotebookDocument>();
private readonly _editors = new Map<string, ExtHostNotebookEditor>();
private readonly _commandsConverter: CommandsConverter;
Expand All @@ -68,7 +70,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;

private _statusBarCache = new Cache<IDisposable>('NotebookCellStatusBarCache');
private _cellStatusBarCache = new Cache<IDisposable>('NotebookCellStatusBarCache');
private _statusBarCache = new Cache<IDisposable>('NotebookStatusBarCache');

constructor(
mainContext: IMainContext,
Expand Down Expand Up @@ -201,10 +204,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {

registerNotebookCellStatusBarItemProvider(extension: IExtensionDescription, notebookType: string, provider: vscode.NotebookCellStatusBarItemProvider) {

const handle = ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++;
const eventHandle = typeof provider.onDidChangeCellStatusBarItems === 'function' ? ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++ : undefined;
const handle = ExtHostNotebookController._notebookCellStatusBarItemProviderHandlePool++;
const eventHandle = typeof provider.onDidChangeCellStatusBarItems === 'function' ? ExtHostNotebookController._notebookCellStatusBarItemProviderHandlePool++ : undefined;

this._notebookStatusBarItemProviders.set(handle, provider);
this._notebookCellStatusBarItemProviders.set(handle, provider);
this._notebookProxy.$registerNotebookCellStatusBarItemProvider(handle, eventHandle, notebookType);

let subscription: vscode.Disposable | undefined;
Expand All @@ -213,12 +216,32 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
}

return new extHostTypes.Disposable(() => {
this._notebookStatusBarItemProviders.delete(handle);
this._notebookCellStatusBarItemProviders.delete(handle);
this._notebookProxy.$unregisterNotebookCellStatusBarItemProvider(handle, eventHandle);
subscription?.dispose();
});
}

registerNotebookStatusBarItemProvider(extension: IExtensionDescription, notebookType: string, provider: vscode.NotebookStatusBarItemProvider) {

const handle = ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++;
const eventHandle = typeof provider.onDidChangeStatusBarItems === 'function' ? ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++ : undefined;

this._notebookStatusBarItemProviders.set(handle, provider);
this._notebookProxy.$registerNotebookStatusBarItemProvider(handle, eventHandle, notebookType);

let subscription: vscode.Disposable | undefined;
if (eventHandle !== undefined) {
subscription = provider.onDidChangeStatusBarItems!(_ => this._notebookProxy.$emitStatusBarEvent(eventHandle));
}

return new extHostTypes.Disposable(() => {
this._notebookStatusBarItemProviders.delete(handle);
this._notebookProxy.$unregisterNotebookStatusBarItemProvider(handle, eventHandle);
subscription?.dispose();
});
}

async createNotebookDocument(options: { viewType: string; content?: vscode.NotebookData }): Promise<URI> {
const canonicalUri = await this._notebookDocumentsProxy.$tryCreateNotebook({
viewType: options.viewType,
Expand Down Expand Up @@ -273,7 +296,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
}

async $provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined> {
const provider = this._notebookStatusBarItemProviders.get(handle);
const provider = this._notebookCellStatusBarItemProviders.get(handle);
const revivedUri = URI.revive(uri);
const document = this._documents.get(revivedUri);
if (!document || !provider) {
Expand All @@ -290,6 +313,33 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
return undefined;
}

const disposables = new DisposableStore();
const cacheId = this._cellStatusBarCache.add([disposables]);
const resultArr = Array.isArray(result) ? result : [result];
const items = resultArr.map(item => typeConverters.NotebookCellStatusBarItem.from(item, this._commandsConverter, disposables));
return {
cacheId,
items
};
}

$releaseNotebookCellStatusBarItems(cacheId: number): void {
this._cellStatusBarCache.delete(cacheId);
}

async $provideNotebookStatusBarItems(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookStatusBarListDto | undefined> {
const provider = this._notebookStatusBarItemProviders.get(handle);
const revivedUri = URI.revive(uri);
const document = this._documents.get(revivedUri);
if (!document || !provider) {
return;
}

const result = await provider.provideStatusBarItems(document.apiNotebook, token);
if (!result) {
return undefined;
}

const disposables = new DisposableStore();
const cacheId = this._statusBarCache.add([disposables]);
const resultArr = Array.isArray(result) ? result : [result];
Expand All @@ -300,7 +350,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
};
}

$releaseNotebookCellStatusBarItems(cacheId: number): void {
$releaseNotebookStatusBarItems(cacheId: number): void {
this._statusBarCache.delete(cacheId);
}

Expand Down
15 changes: 14 additions & 1 deletion src/vs/workbench/api/common/extHostTypeConverters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1691,7 +1691,7 @@ export namespace NotebookExclusiveDocumentPattern {
}
}

export namespace NotebookStatusBarItem {
export namespace NotebookCellStatusBarItem {
export function from(item: vscode.NotebookCellStatusBarItem, commandsConverter: Command.ICommandsConverter, disposables: DisposableStore): notebooks.INotebookCellStatusBarItem {
const command = typeof item.command === 'string' ? { title: '', command: item.command } : item.command;
return {
Expand All @@ -1705,6 +1705,19 @@ export namespace NotebookStatusBarItem {
}
}

export namespace NotebookStatusBarItem {
export function from(item: vscode.NotebookStatusBarItem, commandsConverter: Command.ICommandsConverter, disposables: DisposableStore): notebooks.INotebookStatusBarItem {
const command = typeof item.command === 'string' ? { title: '', command: item.command } : item.command;
return {
command: commandsConverter.toInternal(command, disposables), // TODO@roblou
text: item.text,
tooltip: item.tooltip,
accessibilityInformation: item.accessibilityInformation,
priority: item.priority
};
}
}

export namespace NotebookDocumentContentOptions {
export function from(options: vscode.NotebookDocumentContentOptions | undefined): notebooks.TransientOptions {
return {
Expand Down
4 changes: 4 additions & 0 deletions src/vs/workbench/api/common/extHostTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3579,6 +3579,10 @@ export class NotebookCellStatusBarItem {
public text: string,
public alignment: NotebookCellStatusBarAlignment) { }
}
export class NotebookStatusBarItem {
constructor(
public text: string) { }
}


export enum NotebookControllerAffinity {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/brow
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { INotebookCellStatusBarItemList } from 'vs/workbench/contrib/notebook/common/notebookCommon';

export class ContributedStatusBarItemController extends Disposable implements INotebookEditorContribution {
export class ContributedCellStatusBarItemController extends Disposable implements INotebookEditorContribution {
static id: string = 'workbench.notebook.statusBar.contributed';

private readonly _visibleCells = new Map<number, CellStatusBarHelper>();
Expand Down Expand Up @@ -135,4 +135,4 @@ class CellStatusBarHelper extends Disposable {
}
}

registerNotebookContribution(ContributedStatusBarItemController.id, ContributedStatusBarItemController);
registerNotebookContribution(ContributedCellStatusBarItemController.id, ContributedCellStatusBarItemController);
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function formatCellDuration(duration: number): string {
}
}

export class NotebookStatusBarController extends Disposable {
export class NotebookExecutionStatusBarController extends Disposable {
private readonly _visibleCells = new Map<number, IDisposable>();
private readonly _observer: NotebookVisibleCellObserver;

Expand Down Expand Up @@ -80,7 +80,7 @@ export class ExecutionStateCellStatusBarContrib extends Disposable implements IN
@IInstantiationService instantiationService: IInstantiationService
) {
super();
this._register(new NotebookStatusBarController(notebookEditor, (vm, cell) => instantiationService.createInstance(ExecutionStateCellStatusBarItem, vm, cell)));
this._register(new NotebookExecutionStatusBarController(notebookEditor, (vm, cell) => instantiationService.createInstance(ExecutionStateCellStatusBarItem, vm, cell)));
}
}
registerNotebookContribution(ExecutionStateCellStatusBarContrib.id, ExecutionStateCellStatusBarContrib);
Expand Down Expand Up @@ -203,7 +203,7 @@ export class TimerCellStatusBarContrib extends Disposable implements INotebookEd
notebookEditor: INotebookEditor,
@IInstantiationService instantiationService: IInstantiationService) {
super();
this._register(new NotebookStatusBarController(notebookEditor, (vm, cell) => instantiationService.createInstance(TimerCellStatusBarItem, vm, cell)));
this._register(new NotebookExecutionStatusBarController(notebookEditor, (vm, cell) => instantiationService.createInstance(TimerCellStatusBarItem, vm, cell)));
}
}
registerNotebookContribution(TimerCellStatusBarContrib.id, TimerCellStatusBarContrib);
Expand Down
Loading