未验证 提交 1845b9d2 编写于 作者: R rebornix

Merge branch 'notebook/dev' into main

...@@ -996,10 +996,10 @@ declare module 'vscode' { ...@@ -996,10 +996,10 @@ declare module 'vscode' {
} }
export interface NotebookCellExecutionSummary { export interface NotebookCellExecutionSummary {
executionOrder?: number; readonly executionOrder?: number;
success?: boolean; readonly success?: boolean;
startTime?: number; readonly startTime?: number;
endTime?: number; readonly endTime?: number;
} }
// todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md // todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md
...@@ -1043,17 +1043,67 @@ declare module 'vscode' { ...@@ -1043,17 +1043,67 @@ declare module 'vscode' {
transientOutputs?: boolean; transientOutputs?: boolean;
/** /**
* Controls if a meetadata property change will trigger notebook document content change and if it will be used in the diff editor * @deprecated use transientCellMetadata instead
* Default to false. If the content provider doesn't persisit a metadata property in the file document, it should be set to true.
*/ */
transientMetadata?: { [K in keyof NotebookCellMetadata]?: boolean }; transientMetadata?: { [K in keyof NotebookCellMetadata]?: boolean };
/**
* Controls if a cell metadata property change will trigger notebook document content change and if it will be used in the diff editor
* Default to false. If the content provider doesn't persisit a metadata property in the file document, it should be set to true.
*/
transientCellMetadata?: { [K in keyof NotebookCellMetadata]?: boolean };
/**
* Controls if a document metadata property change will trigger notebook document content change and if it will be used in the diff editor
* Default to false. If the content provider doesn't persisit a metadata property in the file document, it should be set to true.
*/
transientDocumentMetadata?: { [K in keyof NotebookDocumentMetadata]?: boolean };
} }
export interface NotebookDocumentContentOptions {
/**
* Not ready for production or development use yet.
*/
viewOptions?: {
displayName: string;
filenamePattern: NotebookFilenamePattern[];
exclusive?: boolean;
};
}
/**
* Represents a notebook. Notebooks are composed of cells and metadata.
*/
export interface NotebookDocument { export interface NotebookDocument {
/**
* The associated uri for this notebook.
*
* *Note* that most notebooks use the `file`-scheme, which means they are files on disk. However, **not** all notebooks are
* saved on disk and therefore the `scheme` must be checked before trying to access the underlying file or siblings on disk.
*
* @see [FileSystemProvider](#FileSystemProvider)
* @see [TextDocumentContentProvider](#TextDocumentContentProvider)
*/
readonly uri: Uri; readonly uri: Uri;
// todo@API should we really expose this?
readonly viewType: string;
/**
* The version number of this notebook (it will strictly increase after each
* change, including undo/redo).
*/
readonly version: number; readonly version: number;
/**
* `true` if there are unpersisted changes.
*/
readonly isDirty: boolean; readonly isDirty: boolean;
/**
* Is this notebook representing an untitled file which has not been saved yet.
*/
readonly isUntitled: boolean; readonly isUntitled: boolean;
/** /**
...@@ -1062,13 +1112,13 @@ declare module 'vscode' { ...@@ -1062,13 +1112,13 @@ declare module 'vscode' {
*/ */
readonly isClosed: boolean; readonly isClosed: boolean;
/**
* The [metadata](#NotebookDocumentMetadata) for this notebook.
*/
readonly metadata: NotebookDocumentMetadata; readonly metadata: NotebookDocumentMetadata;
// todo@API should we really expose this?
readonly viewType: string;
/** /**
* The number of cells in the notebook document. * The number of cells in the notebook.
*/ */
readonly cellCount: number; readonly cellCount: number;
...@@ -1099,17 +1149,43 @@ declare module 'vscode' { ...@@ -1099,17 +1149,43 @@ declare module 'vscode' {
save(): Thenable<boolean>; save(): Thenable<boolean>;
} }
/**
* A notebook range represents on ordered pair of two cell indicies.
* It is guaranteed that start is less than or equal to end.
*/
export class NotebookRange { export class NotebookRange {
/**
* The zero-based start index of this range.
*/
readonly start: number; readonly start: number;
/** /**
* exclusive * The exclusive end index of this range (zero-based).
*/ */
readonly end: number; readonly end: number;
/**
* `true` if `start` and `end` are equals
*/
readonly isEmpty: boolean; readonly isEmpty: boolean;
/**
* Create a new notebook range. If `start` is not
* before or equal to `end`, the values will be swapped.
*
* @param start start index
* @param end end index.
*/
constructor(start: number, end: number); constructor(start: number, end: number);
/**
* Derive a new range for this range.
*
* @param change An object that describes a change to this range.
* @return A range that reflects the given change. Will return `this` range if the change
* is not changing anything.
*/
with(change: { start?: number, end?: number }): NotebookRange; with(change: { start?: number, end?: number }): NotebookRange;
} }
...@@ -1216,13 +1292,11 @@ declare module 'vscode' { ...@@ -1216,13 +1292,11 @@ declare module 'vscode' {
// todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md // todo@API support ids https://github.com/jupyter/enhancement-proposals/blob/master/62-cell-id/cell-id.md
export class NotebookCellData { export class NotebookCellData {
// todo@API should they all be readonly?
kind: NotebookCellKind; kind: NotebookCellKind;
// todo@API better names: value? text? // todo@API better names: value? text?
source: string; source: string;
// todo@API how does language and MD relate? // todo@API how does language and MD relate?
language: string; language: string;
// todo@API ReadonlyArray?
outputs?: NotebookCellOutput[]; outputs?: NotebookCellOutput[];
metadata?: NotebookCellMetadata; metadata?: NotebookCellMetadata;
latestExecutionSummary?: NotebookCellExecutionSummary; latestExecutionSummary?: NotebookCellExecutionSummary;
...@@ -1230,50 +1304,23 @@ declare module 'vscode' { ...@@ -1230,50 +1304,23 @@ declare module 'vscode' {
} }
export class NotebookData { export class NotebookData {
// todo@API should they all be readonly?
cells: NotebookCellData[]; cells: NotebookCellData[];
metadata: NotebookDocumentMetadata; metadata: NotebookDocumentMetadata;
constructor(cells: NotebookCellData[], metadata?: NotebookDocumentMetadata); constructor(cells: NotebookCellData[], metadata?: NotebookDocumentMetadata);
} }
/** /** @deprecated used NotebookController */
* Communication object passed to the {@link NotebookContentProvider} and
* {@link NotebookOutputRenderer} to communicate with the webview.
*/
export interface NotebookCommunication { export interface NotebookCommunication {
/** /** @deprecated used NotebookController */
* ID of the editor this object communicates with. A single notebook
* document can have multiple attached webviews and editors, when the
* notebook is split for instance. The editor ID lets you differentiate
* between them.
*/
readonly editorId: string; readonly editorId: string;
/** @deprecated used NotebookController */
/**
* Fired when the output hosting webview posts a message.
*/
readonly onDidReceiveMessage: Event<any>; readonly onDidReceiveMessage: Event<any>;
/** /** @deprecated used NotebookController */
* Post a message to the output hosting webview.
*
* Messages are only delivered if the editor is live.
*
* @param message Body of the message. This must be a string or other json serializable object.
*/
postMessage(message: any): Thenable<boolean>; postMessage(message: any): Thenable<boolean>;
/** @deprecated used NotebookController */
/**
* Convert a uri for the local file system to one that can be used inside outputs webview.
*/
asWebviewUri(localResource: Uri): Uri; asWebviewUri(localResource: Uri): Uri;
// @rebornix
// readonly onDidDispose: Event<void>;
} }
// export function registerNotebookKernel(selector: string, kernel: NotebookKernel): Disposable;
export interface NotebookDocumentShowOptions { export interface NotebookDocumentShowOptions {
viewColumn?: ViewColumn; viewColumn?: ViewColumn;
preserveFocus?: boolean; preserveFocus?: boolean;
...@@ -1419,6 +1466,18 @@ declare module 'vscode' { ...@@ -1419,6 +1466,18 @@ declare module 'vscode' {
export type NotebookSelector = NotebookFilter | string | ReadonlyArray<NotebookFilter | string>; export type NotebookSelector = NotebookFilter | string | ReadonlyArray<NotebookFilter | string>;
export interface NotebookExecutionHandler {
/**
* @param cells The notebook cells to execute
* @param controller The controller that the handler is attached to
*/
(this: NotebookController, cells: NotebookCell[], controller: NotebookController): void
}
export interface NotebookInterruptHandler {
(this: NotebookController): void;
}
export interface NotebookController { export interface NotebookController {
readonly id: string; readonly id: string;
...@@ -1440,18 +1499,15 @@ declare module 'vscode' { ...@@ -1440,18 +1499,15 @@ declare module 'vscode' {
supportedLanguages: string[]; supportedLanguages: string[];
hasExecutionOrder?: boolean; hasExecutionOrder?: boolean;
preloads?: NotebookKernelPreload[];
/** /**
* The execute handler is invoked when the run gestures in the UI are selected, e.g Run Cell, Run All, * The execute handler is invoked when the run gestures in the UI are selected, e.g Run Cell, Run All,
* Run Selection etc. * Run Selection etc.
*/ */
readonly executeHandler: (cells: NotebookCell[], controller: NotebookController) => void; executeHandler: NotebookExecutionHandler;
// optional kernel interrupt command // optional kernel interrupt command
interruptHandler?: (notebook: NotebookDocument) => void interruptHandler?: NotebookInterruptHandler
// remove kernel
dispose(): void; dispose(): void;
/** /**
...@@ -1465,24 +1521,24 @@ declare module 'vscode' { ...@@ -1465,24 +1521,24 @@ declare module 'vscode' {
createNotebookCellExecutionTask(cell: NotebookCell): NotebookCellExecutionTask; createNotebookCellExecutionTask(cell: NotebookCell): NotebookCellExecutionTask;
// ipc // ipc
readonly preloads: NotebookKernelPreload[];
readonly onDidReceiveMessage: Event<{ editor: NotebookEditor, message: any }>; readonly onDidReceiveMessage: Event<{ editor: NotebookEditor, message: any }>;
postMessage(message: any, editor?: NotebookEditor): Thenable<boolean>; postMessage(message: any, editor?: NotebookEditor): Thenable<boolean>;
asWebviewUri(localResource: Uri, editor: NotebookEditor): Uri; asWebviewUri(localResource: Uri): Uri;
}
export interface NotebookControllerOptions {
id: string;
label: string;
description?: string;
selector: NotebookSelector;
supportedLanguages?: string[];
hasExecutionOrder?: boolean;
executeHandler: (cells: NotebookCell[], controller: NotebookController) => void;
interruptHandler?: (notebook: NotebookDocument) => void
} }
export namespace notebook { export namespace notebook {
export function createNotebookController(options: NotebookControllerOptions): NotebookController;
/**
* Creates a new notebook controller.
*
* @param id Unique identifier of the controller
* @param selector A notebook selector to narrow down notebook type or path
* @param label The label of the controller
* @param handler
* @param preloads
*/
export function createNotebookController(id: string, selector: NotebookSelector, label: string, handler?: NotebookExecutionHandler, preloads?: NotebookKernelPreload[]): NotebookController;
} }
//#endregion //#endregion
...@@ -1543,18 +1599,7 @@ declare module 'vscode' { ...@@ -1543,18 +1599,7 @@ declare module 'vscode' {
// TODO@api use NotebookDocumentFilter instead of just notebookType:string? // TODO@api use NotebookDocumentFilter instead of just notebookType:string?
// TODO@API options duplicates the more powerful variant on NotebookContentProvider // TODO@API options duplicates the more powerful variant on NotebookContentProvider
export function registerNotebookContentProvider(notebookType: string, provider: NotebookContentProvider, export function registerNotebookContentProvider(notebookType: string, provider: NotebookContentProvider, options?: NotebookDocumentContentOptions): Disposable;
options?: NotebookDocumentContentOptions & {
/**
* Not ready for production or development use yet.
*/
viewOptions?: {
displayName: string;
filenamePattern: NotebookFilenamePattern[];
exclusive?: boolean;
};
}
): Disposable;
} }
//#endregion //#endregion
...@@ -1566,6 +1611,7 @@ declare module 'vscode' { ...@@ -1566,6 +1611,7 @@ declare module 'vscode' {
uri: Uri; uri: Uri;
} }
/** @deprecated used NotebookController */
export interface NotebookKernel { export interface NotebookKernel {
// todo@API make this mandatory? // todo@API make this mandatory?
...@@ -1679,8 +1725,7 @@ declare module 'vscode' { ...@@ -1679,8 +1725,7 @@ declare module 'vscode' {
filenamePattern?: NotebookFilenamePattern; filenamePattern?: NotebookFilenamePattern;
} }
// todo@API very unclear, provider MUST not return alive object but only data object /** @deprecated used NotebookController */
// todo@API unclear how the flow goes
export interface NotebookKernelProvider<T extends NotebookKernel = NotebookKernel> { export interface NotebookKernelProvider<T extends NotebookKernel = NotebookKernel> {
onDidChangeKernels?: Event<NotebookDocument | undefined>; onDidChangeKernels?: Event<NotebookDocument | undefined>;
provideKernels(document: NotebookDocument, token: CancellationToken): ProviderResult<T[]>; provideKernels(document: NotebookDocument, token: CancellationToken): ProviderResult<T[]>;
...@@ -1688,9 +1733,6 @@ declare module 'vscode' { ...@@ -1688,9 +1733,6 @@ declare module 'vscode' {
} }
export interface NotebookEditor { export interface NotebookEditor {
// todo@API unsure about that
// kernel, kernel selection, kernel provider
/** @deprecated kernels are private object*/ /** @deprecated kernels are private object*/
readonly kernel?: NotebookKernel; readonly kernel?: NotebookKernel;
} }
...@@ -1698,7 +1740,7 @@ declare module 'vscode' { ...@@ -1698,7 +1740,7 @@ declare module 'vscode' {
export namespace notebook { export namespace notebook {
/** @deprecated */ /** @deprecated */
export const onDidChangeActiveNotebookKernel: Event<{ document: NotebookDocument, kernel: NotebookKernel | undefined; }>; export const onDidChangeActiveNotebookKernel: Event<{ document: NotebookDocument, kernel: NotebookKernel | undefined; }>;
/** @deprecated use createNotebookKernel */ /** @deprecated used NotebookController */
export function registerNotebookKernelProvider(selector: NotebookDocumentFilter, provider: NotebookKernelProvider): Disposable; export function registerNotebookKernelProvider(selector: NotebookDocumentFilter, provider: NotebookKernelProvider): Disposable;
} }
...@@ -1757,7 +1799,14 @@ declare module 'vscode' { ...@@ -1757,7 +1799,14 @@ declare module 'vscode' {
} }
interface NotebookCellStatusBarItemProvider { interface NotebookCellStatusBarItemProvider {
/**
* Implement and fire this event to signal that statusbar items have changed. The provide method will be called again.
*/
onDidChangeCellStatusBarItems?: Event<void>; onDidChangeCellStatusBarItems?: Event<void>;
/**
* The provider will be called when the cell scrolls into view, when its content, outputs, language, or metadata change, and when it changes execution state.
*/
provideCellStatusBarItems(cell: NotebookCell, token: CancellationToken): ProviderResult<NotebookCellStatusBarItem[]>; provideCellStatusBarItems(cell: NotebookCell, token: CancellationToken): ProviderResult<NotebookCellStatusBarItem[]>;
} }
......
...@@ -14,7 +14,7 @@ import { ILogService } from 'vs/platform/log/common/log'; ...@@ -14,7 +14,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService'; import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { ICellRange, INotebookCellStatusBarItemProvider, INotebookDocumentFilter, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookDataDto, TransientMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellRange, INotebookCellStatusBarItemProvider, INotebookDocumentFilter, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookDataDto, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainContext, MainThreadNotebookShape, NotebookExtensionDescription } from '../common/extHost.protocol'; import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainContext, MainThreadNotebookShape, NotebookExtensionDescription } from '../common/extHost.protocol';
...@@ -65,17 +65,19 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { ...@@ -65,17 +65,19 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: { async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: {
transientOutputs: boolean; transientOutputs: boolean;
transientMetadata: TransientMetadata; transientCellMetadata: TransientCellMetadata;
transientDocumentMetadata: TransientDocumentMetadata;
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; }; viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
}): Promise<void> { }): Promise<void> {
let contentOptions = { transientOutputs: options.transientOutputs, transientMetadata: options.transientMetadata }; let contentOptions = { transientOutputs: options.transientOutputs, transientCellMetadata: options.transientCellMetadata, transientDocumentMetadata: options.transientDocumentMetadata };
const controller: IMainNotebookController = { const controller: IMainNotebookController = {
get options() { get options() {
return contentOptions; return contentOptions;
}, },
set options(newOptions) { set options(newOptions) {
contentOptions.transientMetadata = newOptions.transientMetadata; contentOptions.transientCellMetadata = newOptions.transientCellMetadata;
contentOptions.transientDocumentMetadata = newOptions.transientDocumentMetadata;
contentOptions.transientOutputs = newOptions.transientOutputs; contentOptions.transientOutputs = newOptions.transientOutputs;
}, },
viewOptions: options.viewOptions, viewOptions: options.viewOptions,
...@@ -107,7 +109,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape { ...@@ -107,7 +109,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
this._notebookProviders.set(viewType, { controller, disposable }); this._notebookProviders.set(viewType, { controller, disposable });
} }
async $updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientMetadata: TransientMetadata; }): Promise<void> { async $updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; }): Promise<void> {
const provider = this._notebookProviders.get(viewType); const provider = this._notebookProviders.get(viewType);
if (provider && options) { if (provider && options) {
......
...@@ -177,7 +177,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape ...@@ -177,7 +177,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
// --- kernel adding/updating/removal // --- kernel adding/updating/removal
$addKernel(handle: number, data: INotebookKernelDto2): void { async $addKernel(handle: number, data: INotebookKernelDto2): Promise<void> {
const that = this; const that = this;
const kernel = new class extends MainThreadKernel { const kernel = new class extends MainThreadKernel {
executeNotebookCellsRequest(uri: URI, ranges: ICellRange[]): void { executeNotebookCellsRequest(uri: URI, ranges: ICellRange[]): void {
......
...@@ -1106,9 +1106,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I ...@@ -1106,9 +1106,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension); checkProposedApiEnabled(extension);
return extHostNotebook.createNotebookCellExecution(uri, index, kernelId); return extHostNotebook.createNotebookCellExecution(uri, index, kernelId);
}, },
createNotebookController(options) { createNotebookController(id, selector, label, executeHandler, preloads) {
checkProposedApiEnabled(extension); checkProposedApiEnabled(extension);
return extHostNotebookKernels.createKernel(extension, options); return extHostNotebookKernels.createNotebookController(extension, id, selector, label, executeHandler, preloads);
} }
}; };
......
...@@ -50,7 +50,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; ...@@ -50,7 +50,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, ProvidedPortAttributes } from 'vs/platform/remote/common/tunnel'; import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, ProvidedPortAttributes } from 'vs/platform/remote/common/tunnel';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline'; import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling'; import { revive } from 'vs/base/common/marshalling';
import { NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, TransientMetadata, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto, TransientOptions, IImmediateCellEditOperation, INotebookCellStatusBarItem } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, TransientCellMetadata, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto, TransientOptions, IImmediateCellEditOperation, INotebookCellStatusBarItem, TransientDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types'; import { Dto } from 'vs/base/common/types';
import { DebugConfigurationProviderTriggerKind, TestResultState } from 'vs/workbench/api/common/extHostTypes'; import { DebugConfigurationProviderTriggerKind, TestResultState } from 'vs/workbench/api/common/extHostTypes';
...@@ -874,10 +874,11 @@ export interface INotebookCellStatusBarListDto { ...@@ -874,10 +874,11 @@ export interface INotebookCellStatusBarListDto {
export interface MainThreadNotebookShape extends IDisposable { export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: { $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: {
transientOutputs: boolean; transientOutputs: boolean;
transientMetadata: TransientMetadata; transientCellMetadata: TransientCellMetadata;
transientDocumentMetadata: TransientDocumentMetadata;
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; }; viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
}): Promise<void>; }): Promise<void>;
$updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientMetadata: TransientMetadata; }): Promise<void>; $updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; }): Promise<void>;
$unregisterNotebookProvider(viewType: string): Promise<void>; $unregisterNotebookProvider(viewType: string): Promise<void>;
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void; $registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void;
...@@ -923,7 +924,7 @@ export interface INotebookKernelDto2 { ...@@ -923,7 +924,7 @@ export interface INotebookKernelDto2 {
export interface MainThreadNotebookKernelsShape extends IDisposable { export interface MainThreadNotebookKernelsShape extends IDisposable {
$postMessage(handle: number, editorId: string | undefined, message: any): Promise<boolean>; $postMessage(handle: number, editorId: string | undefined, message: any): Promise<boolean>;
$addKernel(handle: number, data: INotebookKernelDto2): void; $addKernel(handle: number, data: INotebookKernelDto2): Promise<void>;
$updateKernel(handle: number, data: Partial<INotebookKernelDto2>): void; $updateKernel(handle: number, data: Partial<INotebookKernelDto2>): void;
$removeKernel(handle: number): void; $removeKernel(handle: number): void;
} }
......
...@@ -18,7 +18,7 @@ import { ICommandsExecutor, RemoveFromRecentlyOpenedAPICommand, OpenIssueReporte ...@@ -18,7 +18,7 @@ import { ICommandsExecutor, RemoveFromRecentlyOpenedAPICommand, OpenIssueReporte
import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IRange } from 'vs/editor/common/core/range'; import { IRange } from 'vs/editor/common/core/range';
import { IPosition } from 'vs/editor/common/core/position'; import { IPosition } from 'vs/editor/common/core/position';
import { TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { TransientCellMetadata, TransientDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { VSBuffer } from 'vs/base/common/buffer'; import { VSBuffer } from 'vs/base/common/buffer';
import { decodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto'; import { decodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto';
...@@ -343,7 +343,7 @@ const newCommands: ApiCommand[] = [ ...@@ -343,7 +343,7 @@ const newCommands: ApiCommand[] = [
new ApiCommandResult<{ new ApiCommandResult<{
viewType: string; viewType: string;
displayName: string; displayName: string;
options: { transientOutputs: boolean; transientMetadata: TransientMetadata }; options: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; };
filenamePattern: (string | types.RelativePattern | { include: string | types.RelativePattern, exclude: string | types.RelativePattern })[] filenamePattern: (string | types.RelativePattern | { include: string | types.RelativePattern, exclude: string | types.RelativePattern })[]
}[], { }[], {
viewType: string; viewType: string;
...@@ -354,7 +354,12 @@ const newCommands: ApiCommand[] = [ ...@@ -354,7 +354,12 @@ const newCommands: ApiCommand[] = [
return { return {
viewType: item.viewType, viewType: item.viewType,
displayName: item.displayName, displayName: item.displayName,
options: { transientOutputs: item.options.transientOutputs, transientMetadata: item.options.transientMetadata }, options: {
transientOutputs: item.options.transientOutputs,
transientMetadata: item.options.transientCellMetadata,
transientCellMetadata: item.options.transientCellMetadata,
transientDocumentMetadata: item.options.transientDocumentMetadata
},
filenamePattern: item.filenamePattern.map(pattern => typeConverters.NotebookExclusiveDocumentPattern.to(pattern)) filenamePattern: item.filenamePattern.map(pattern => typeConverters.NotebookExclusiveDocumentPattern.to(pattern))
}; };
})) }))
......
...@@ -376,7 +376,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { ...@@ -376,7 +376,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
const internalOptions = typeConverters.NotebookDocumentContentOptions.from(options); const internalOptions = typeConverters.NotebookDocumentContentOptions.from(options);
this._notebookProxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, { this._notebookProxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, {
transientOutputs: internalOptions.transientOutputs, transientOutputs: internalOptions.transientOutputs,
transientMetadata: internalOptions.transientMetadata, transientCellMetadata: internalOptions.transientCellMetadata,
transientDocumentMetadata: internalOptions.transientDocumentMetadata,
viewOptions: options?.viewOptions && viewOptionsFilenamePattern ? { displayName: options.viewOptions.displayName, filenamePattern: viewOptionsFilenamePattern, exclusive: options.viewOptions.exclusive || false } : undefined viewOptions: options?.viewOptions && viewOptionsFilenamePattern ? { displayName: options.viewOptions.displayName, filenamePattern: viewOptionsFilenamePattern, exclusive: options.viewOptions.exclusive || false } : undefined
}); });
...@@ -623,7 +624,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { ...@@ -623,7 +624,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
} }
} }
private cancelOneNotebookCellExecution(cell: ExtHostCell): void { cancelOneNotebookCellExecution(cell: ExtHostCell): void {
const execution = this._activeExecutions.get(cell.uri); const execution = this._activeExecutions.get(cell.uri);
execution?.cancel(); execution?.cancel();
} }
......
...@@ -8,7 +8,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; ...@@ -8,7 +8,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
import { ExtHostNotebookKernelsShape, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostNotebookKernelsShape, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from 'vs/workbench/api/common/extHost.protocol';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { URI, UriComponents } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
...@@ -16,10 +16,8 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; ...@@ -16,10 +16,8 @@ import { isNonEmptyArray } from 'vs/base/common/arrays';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { asWebviewUri } from 'vs/workbench/api/common/shared/webview'; import { asWebviewUri } from 'vs/workbench/api/common/shared/webview';
type ExecuteHandler = (cells: vscode.NotebookCell[], controller: vscode.NotebookController) => void;
type InterruptHandler = (notebook: vscode.NotebookDocument) => void;
interface IKernelData { interface IKernelData {
extensionId: ExtensionIdentifier,
controller: vscode.NotebookController; controller: vscode.NotebookController;
onDidChangeSelection: Emitter<{ selected: boolean; notebook: vscode.NotebookDocument; }>; onDidChangeSelection: Emitter<{ selected: boolean; notebook: vscode.NotebookDocument; }>;
onDidReceiveMessage: Emitter<{ editor: vscode.NotebookEditor, message: any }>; onDidReceiveMessage: Emitter<{ editor: vscode.NotebookEditor, message: any }>;
...@@ -40,11 +38,20 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { ...@@ -40,11 +38,20 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebookKernels); this._proxy = mainContext.getProxy(MainContext.MainThreadNotebookKernels);
} }
createKernel(extension: IExtensionDescription, options: vscode.NotebookControllerOptions): vscode.NotebookController { createNotebookController(extension: IExtensionDescription, id: string, selector: vscode.NotebookSelector, label: string, handler?: vscode.NotebookExecutionHandler, preloads?: vscode.NotebookKernelPreload[]): vscode.NotebookController {
for (let data of this._kernelData.values()) {
if (data.controller.id === id) {
throw new Error(`notebook controller with id '${id}' ALREADY exist`);
}
}
const handle = this._handlePool++; const handle = this._handlePool++;
const that = this; const that = this;
const _defaultSupportedLanguages = ['plaintext'];
const _defaultExecutHandler = () => console.warn(`NO execute handler from notebook controller '${data.id}' of extension: '${extension.identifier}'`);
let isDisposed = false; let isDisposed = false;
const commandDisposables = new DisposableStore(); const commandDisposables = new DisposableStore();
...@@ -52,20 +59,25 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { ...@@ -52,20 +59,25 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
const onDidReceiveMessage = new Emitter<{ editor: vscode.NotebookEditor, message: any }>(); const onDidReceiveMessage = new Emitter<{ editor: vscode.NotebookEditor, message: any }>();
const data: INotebookKernelDto2 = { const data: INotebookKernelDto2 = {
id: options.id, id: id,
selector: options.selector, selector: selector,
extensionId: extension.identifier, extensionId: extension.identifier,
extensionLocation: extension.extensionLocation, extensionLocation: extension.extensionLocation,
label: options.label, label: label || extension.identifier.value,
supportedLanguages: [], supportedLanguages: _defaultSupportedLanguages,
preloads: preloads ? preloads.map(extHostTypeConverters.NotebookKernelPreload.from) : []
}; };
// //
let _executeHandler: ExecuteHandler = options.executeHandler; let _executeHandler: vscode.NotebookExecutionHandler = handler ?? _defaultExecutHandler;
let _interruptHandler: InterruptHandler | undefined = options.interruptHandler; let _interruptHandler: vscode.NotebookInterruptHandler | undefined;
// todo@jrieken the selector needs to be massaged // todo@jrieken the selector needs to be massaged
this._proxy.$addKernel(handle, data); this._proxy.$addKernel(handle, data).catch(err => {
// this can happen when a kernel with that ID is already registered
console.log(err);
isDisposed = true;
});
// update: all setters write directly into the dto object // update: all setters write directly into the dto object
// and trigger an update. the actual update will only happen // and trigger an update. the actual update will only happen
...@@ -91,7 +103,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { ...@@ -91,7 +103,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
return data.label; return data.label;
}, },
set label(value) { set label(value) {
data.label = value; data.label = value ?? extension.displayName ?? extension.name;
_update(); _update();
}, },
get description() { get description() {
...@@ -112,7 +124,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { ...@@ -112,7 +124,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
return data.supportedLanguages; return data.supportedLanguages;
}, },
set supportedLanguages(value) { set supportedLanguages(value) {
data.supportedLanguages = isNonEmptyArray(value) ? value : ['plaintext']; data.supportedLanguages = isNonEmptyArray(value) ? value : _defaultSupportedLanguages;
_update(); _update();
}, },
get hasExecutionOrder() { get hasExecutionOrder() {
...@@ -123,15 +135,14 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { ...@@ -123,15 +135,14 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
_update(); _update();
}, },
get preloads() { get preloads() {
return data.preloads && data.preloads.map(extHostTypeConverters.NotebookKernelPreload.to); return data.preloads ? data.preloads.map(extHostTypeConverters.NotebookKernelPreload.to) : [];
},
set preloads(value) {
data.preloads = value && value.map(extHostTypeConverters.NotebookKernelPreload.from);
_update();
}, },
get executeHandler() { get executeHandler() {
return _executeHandler; return _executeHandler;
}, },
set executeHandler(value) {
_executeHandler = value ?? _defaultExecutHandler;
},
get interruptHandler() { get interruptHandler() {
return _interruptHandler; return _interruptHandler;
}, },
...@@ -162,17 +173,12 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { ...@@ -162,17 +173,12 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
postMessage(message, editor) { postMessage(message, editor) {
return that._proxy.$postMessage(handle, editor && that._extHostNotebook.getIdByEditor(editor), message); return that._proxy.$postMessage(handle, editor && that._extHostNotebook.getIdByEditor(editor), message);
}, },
asWebviewUri(uri: URI, editor) { asWebviewUri(uri: URI) {
return asWebviewUri(that._initData.environment, that._extHostNotebook.getIdByEditor(editor)!, uri); return asWebviewUri(that._initData.environment, data.id, uri);
} }
}; };
this._kernelData.set(handle, { controller, onDidChangeSelection, onDidReceiveMessage }); this._kernelData.set(handle, { extensionId: extension.identifier, controller, onDidChangeSelection, onDidReceiveMessage });
controller.supportedLanguages = options.supportedLanguages ?? [];
controller.interruptHandler = options.interruptHandler;
controller.hasExecutionOrder = options.hasExecutionOrder ?? false;
return controller; return controller;
} }
...@@ -203,7 +209,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { ...@@ -203,7 +209,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
} }
try { try {
obj.controller.executeHandler(cells, obj.controller); obj.controller.executeHandler.call(obj.controller, cells, obj.controller);
} catch (err) { } catch (err) {
// //
console.error(err); console.error(err);
...@@ -221,7 +227,17 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape { ...@@ -221,7 +227,17 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
throw new Error('MISSING notebook'); throw new Error('MISSING notebook');
} }
if (obj.controller.interruptHandler) { if (obj.controller.interruptHandler) {
obj.controller.interruptHandler(document.notebookDocument); obj.controller.interruptHandler.call(obj.controller);
}
// we do both? interrupt and cancellation or should we be selective?
for (const range of ranges) {
for (let i = range.start; i < range.end; i++) {
const cell = document.getCellFromIndex(i);
if (cell) {
this._extHostNotebook.cancelOneNotebookCellExecution(cell);
}
}
} }
} }
......
...@@ -1419,7 +1419,17 @@ export namespace NotebookRange { ...@@ -1419,7 +1419,17 @@ export namespace NotebookRange {
export namespace NotebookCellMetadata { export namespace NotebookCellMetadata {
export function to(data: notebooks.NotebookCellMetadata): types.NotebookCellMetadata { export function to(data: notebooks.NotebookCellMetadata): types.NotebookCellMetadata {
return new types.NotebookCellMetadata(data.inputCollapsed, data.outputCollapsed).with({ custom: data.custom }); return new types.NotebookCellMetadata().with({
...data,
...{
executionOrder: null,
lastRunSuccess: null,
runState: null,
runStartTime: null,
runStartTimeAdjustment: null,
runEndTime: null
}
});
} }
} }
...@@ -1430,7 +1440,7 @@ export namespace NotebookDocumentMetadata { ...@@ -1430,7 +1440,7 @@ export namespace NotebookDocumentMetadata {
} }
export function to(data: notebooks.NotebookDocumentMetadata): types.NotebookDocumentMetadata { export function to(data: notebooks.NotebookDocumentMetadata): types.NotebookDocumentMetadata {
return new types.NotebookDocumentMetadata(data.trusted, data.custom); return new types.NotebookDocumentMetadata().with(data);
} }
} }
...@@ -1633,15 +1643,16 @@ export namespace NotebookDocumentContentOptions { ...@@ -1633,15 +1643,16 @@ export namespace NotebookDocumentContentOptions {
export function from(options: vscode.NotebookDocumentContentOptions | undefined): notebooks.TransientOptions { export function from(options: vscode.NotebookDocumentContentOptions | undefined): notebooks.TransientOptions {
return { return {
transientOutputs: options?.transientOutputs ?? false, transientOutputs: options?.transientOutputs ?? false,
transientMetadata: { transientCellMetadata: {
...options?.transientMetadata, ...(options?.transientCellMetadata ?? options?.transientMetadata),
executionOrder: true, executionOrder: true,
runState: true, runState: true,
runStartTime: true, runStartTime: true,
runStartTimeAdjustment: true, runStartTimeAdjustment: true,
runEndTime: true, runEndTime: true,
lastRunSuccess: true lastRunSuccess: true
} },
transientDocumentMetadata: options?.transientDocumentMetadata ?? {}
}; };
} }
} }
......
...@@ -2916,11 +2916,16 @@ export class NotebookRange { ...@@ -2916,11 +2916,16 @@ export class NotebookRange {
if (start < 0) { if (start < 0) {
throw illegalArgument('start must be positive'); throw illegalArgument('start must be positive');
} }
if (end < start) { if (end < 0) {
throw illegalArgument('end cannot be smaller than start'); throw illegalArgument('end must be positive');
}
if (start <= end) {
this._start = start;
this._end = end;
} else {
this._start = end;
this._end = start;
} }
this._start = start;
this._end = end;
} }
with(change: { start?: number, end?: number }): NotebookRange { with(change: { start?: number, end?: number }): NotebookRange {
......
...@@ -18,8 +18,8 @@ import { InputFocusedContext, InputFocusedContextKey } from 'vs/platform/context ...@@ -18,8 +18,8 @@ import { InputFocusedContext, InputFocusedContextKey } from 'vs/platform/context
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
import { BaseCellRenderTemplate, CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, EXPAND_CELL_INPUT_COMMAND_ID, getNotebookEditorFromEditorPane, IActiveNotebookEditor, ICellViewModel, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_OUTPUT_FOCUSED, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_HAS_RUNNING_CELL } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { BaseCellRenderTemplate, CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, EXPAND_CELL_INPUT_COMMAND_ID, getNotebookEditorFromEditorPane, IActiveNotebookEditor, ICellViewModel, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_KERNEL_COUNT, NOTEBOOK_OUTPUT_FOCUSED, NOTEBOOK_INTERRUPTIBLE_KERNEL, NOTEBOOK_HAS_RUNNING_CELL, CHANGE_CELL_LANGUAGE, QUIT_EDIT_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellEditType, CellKind, ICellEditOperation, ICellRange, INotebookDocumentFilter, isDocumentExcludePattern, NotebookCellMetadata, NotebookCellExecutionState, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, TransientMetadata, SelectionStateType, ICellReplaceEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellEditType, CellKind, ICellEditOperation, ICellRange, INotebookDocumentFilter, isDocumentExcludePattern, NotebookCellMetadata, NotebookCellExecutionState, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, TransientCellMetadata, TransientDocumentMetadata, SelectionStateType, ICellReplaceEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
...@@ -53,14 +53,12 @@ const CHANGE_CELL_TO_CODE_COMMAND_ID = 'notebook.cell.changeToCode'; ...@@ -53,14 +53,12 @@ const CHANGE_CELL_TO_CODE_COMMAND_ID = 'notebook.cell.changeToCode';
const CHANGE_CELL_TO_MARKDOWN_COMMAND_ID = 'notebook.cell.changeToMarkdown'; const CHANGE_CELL_TO_MARKDOWN_COMMAND_ID = 'notebook.cell.changeToMarkdown';
const EDIT_CELL_COMMAND_ID = 'notebook.cell.edit'; const EDIT_CELL_COMMAND_ID = 'notebook.cell.edit';
const QUIT_EDIT_CELL_COMMAND_ID = 'notebook.cell.quitEdit';
const DELETE_CELL_COMMAND_ID = 'notebook.cell.delete'; const DELETE_CELL_COMMAND_ID = 'notebook.cell.delete';
const CANCEL_CELL_COMMAND_ID = 'notebook.cell.cancelExecution'; const CANCEL_CELL_COMMAND_ID = 'notebook.cell.cancelExecution';
const EXECUTE_CELL_SELECT_BELOW = 'notebook.cell.executeAndSelectBelow'; const EXECUTE_CELL_SELECT_BELOW = 'notebook.cell.executeAndSelectBelow';
const EXECUTE_CELL_INSERT_BELOW = 'notebook.cell.executeAndInsertBelow'; const EXECUTE_CELL_INSERT_BELOW = 'notebook.cell.executeAndInsertBelow';
const CLEAR_CELL_OUTPUTS_COMMAND_ID = 'notebook.cell.clearOutputs'; const CLEAR_CELL_OUTPUTS_COMMAND_ID = 'notebook.cell.clearOutputs';
const CHANGE_CELL_LANGUAGE = 'notebook.cell.changeLanguage';
const CENTER_ACTIVE_CELL = 'notebook.centerActiveCell'; const CENTER_ACTIVE_CELL = 'notebook.centerActiveCell';
const FOCUS_IN_OUTPUT_COMMAND_ID = 'notebook.cell.focusInOutput'; const FOCUS_IN_OUTPUT_COMMAND_ID = 'notebook.cell.focusInOutput';
...@@ -1339,7 +1337,7 @@ interface IChangeCellContext extends INotebookCellActionContext { ...@@ -1339,7 +1337,7 @@ interface IChangeCellContext extends INotebookCellActionContext {
language?: string; language?: string;
} }
export class ChangeCellLanguageAction extends NotebookCellAction<ICellRange> { registerAction2(class ChangeCellLanguageAction extends NotebookCellAction<ICellRange> {
constructor() { constructor() {
super({ super({
id: CHANGE_CELL_LANGUAGE, id: CHANGE_CELL_LANGUAGE,
...@@ -1495,8 +1493,7 @@ export class ChangeCellLanguageAction extends NotebookCellAction<ICellRange> { ...@@ -1495,8 +1493,7 @@ export class ChangeCellLanguageAction extends NotebookCellAction<ICellRange> {
return fakeResource; return fakeResource;
} }
} });
registerAction2(ChangeCellLanguageAction);
registerAction2(class extends NotebookAction { registerAction2(class extends NotebookAction {
constructor() { constructor() {
...@@ -1695,7 +1692,7 @@ CommandsRegistry.registerCommand('notebook.trust', (accessor, args) => { ...@@ -1695,7 +1692,7 @@ CommandsRegistry.registerCommand('notebook.trust', (accessor, args) => {
CommandsRegistry.registerCommand('_resolveNotebookContentProvider', (accessor, args): { CommandsRegistry.registerCommand('_resolveNotebookContentProvider', (accessor, args): {
viewType: string; viewType: string;
displayName: string; displayName: string;
options: { transientOutputs: boolean; transientMetadata: TransientMetadata; }; options: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; };
filenamePattern: (string | glob.IRelativePattern | { include: string | glob.IRelativePattern, exclude: string | glob.IRelativePattern; })[]; filenamePattern: (string | glob.IRelativePattern | { include: string | glob.IRelativePattern, exclude: string | glob.IRelativePattern; })[];
}[] => { }[] => {
const notebookService = accessor.get<INotebookService>(INotebookService); const notebookService = accessor.get<INotebookService>(INotebookService);
...@@ -1724,7 +1721,11 @@ CommandsRegistry.registerCommand('_resolveNotebookContentProvider', (accessor, a ...@@ -1724,7 +1721,11 @@ CommandsRegistry.registerCommand('_resolveNotebookContentProvider', (accessor, a
viewType: provider.id, viewType: provider.id,
displayName: provider.displayName, displayName: provider.displayName,
filenamePattern: filenamePatterns, filenamePattern: filenamePatterns,
options: { transientMetadata: provider.options.transientMetadata, transientOutputs: provider.options.transientOutputs } options: {
transientCellMetadata: provider.options.transientCellMetadata,
transientDocumentMetadata: provider.options.transientDocumentMetadata,
transientOutputs: provider.options.transientOutputs
}
}; };
}); });
}); });
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
import { flatten } from 'vs/base/common/arrays'; import { flatten } from 'vs/base/common/arrays';
import { Throttler } from 'vs/base/common/async'; import { Throttler } from 'vs/base/common/async';
import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { ICellViewModel, INotebookEditor, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { ICellViewModel, INotebookEditor, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
...@@ -18,6 +18,8 @@ export class NotebookStatusBarController extends Disposable implements INotebook ...@@ -18,6 +18,8 @@ export class NotebookStatusBarController extends Disposable implements INotebook
private readonly _visibleCells = new Map<number, CellStatusBarHelper>(); private readonly _visibleCells = new Map<number, CellStatusBarHelper>();
private readonly _viewModelDisposables = new DisposableStore();
constructor( constructor(
private readonly _notebookEditor: INotebookEditor, private readonly _notebookEditor: INotebookEditor,
@INotebookCellStatusBarService private readonly _notebookCellStatusBarService: INotebookCellStatusBarService @INotebookCellStatusBarService private readonly _notebookCellStatusBarService: INotebookCellStatusBarService
...@@ -25,11 +27,22 @@ export class NotebookStatusBarController extends Disposable implements INotebook ...@@ -25,11 +27,22 @@ export class NotebookStatusBarController extends Disposable implements INotebook
super(); super();
this._updateVisibleCells(); this._updateVisibleCells();
this._register(this._notebookEditor.onDidChangeVisibleRanges(this._updateVisibleCells, this)); this._register(this._notebookEditor.onDidChangeVisibleRanges(this._updateVisibleCells, this));
this._register(this._notebookEditor.onDidChangeModel(this._updateEverything, this)); this._register(this._notebookEditor.onDidChangeModel(this._onModelChange, this));
this._register(this._notebookCellStatusBarService.onDidChangeProviders(this._updateEverything, this)); this._register(this._notebookCellStatusBarService.onDidChangeProviders(this._updateEverything, this));
this._register(this._notebookCellStatusBarService.onDidChangeItems(this._updateEverything, this)); this._register(this._notebookCellStatusBarService.onDidChangeItems(this._updateEverything, this));
} }
private _onModelChange() {
this._viewModelDisposables.clear();
const vm = this._notebookEditor.viewModel;
if (!vm) {
return;
}
this._viewModelDisposables.add(vm.onDidChangeViewCells(() => this._updateEverything()));
this._updateEverything();
}
private _updateEverything(): void { private _updateEverything(): void {
this._visibleCells.forEach(cell => cell.dispose()); this._visibleCells.forEach(cell => cell.dispose());
this._visibleCells.clear(); this._visibleCells.clear();
......
...@@ -3,36 +3,55 @@ ...@@ -3,36 +3,55 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { isWindows } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Registry } from 'vs/platform/registry/common/platform'; import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { CellStatusbarAlignment, INotebookCellStatusBarItem, INotebookCellStatusBarItemList, INotebookCellStatusBarItemProvider, INotebookDocumentFilter } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellKind, CellStatusbarAlignment, INotebookCellStatusBarItem, INotebookCellStatusBarItemList, INotebookCellStatusBarItemProvider, INotebookDocumentFilter } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IModeService } from 'vs/editor/common/services/modeService';
import { CHANGE_CELL_LANGUAGE, EXECUTE_CELL_COMMAND_ID, QUIT_EDIT_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
class CellStatusBarPlaceholderProvider implements INotebookCellStatusBarItemProvider { class CellStatusBarPlaceholderProvider implements INotebookCellStatusBarItemProvider {
readonly selector: INotebookDocumentFilter = { readonly selector: INotebookDocumentFilter = {
filenamePattern: '**/*' filenamePattern: '**/*'
}; };
constructor(@INotebookService private readonly _notebookService: INotebookService) { } constructor(
@INotebookService private readonly _notebookService: INotebookService,
onDidChangeStatusBarItems?: Event<void> | undefined; @IKeybindingService private readonly _keybindingService: IKeybindingService,
) { }
async provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken): Promise<INotebookCellStatusBarItemList> { async provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken): Promise<INotebookCellStatusBarItemList | undefined> {
const doc = this._notebookService.getNotebookTextModel(uri); const doc = this._notebookService.getNotebookTextModel(uri);
const cell = doc?.cells[index]; const cell = doc?.cells[index];
if (typeof cell?.metadata.runState !== 'undefined' || typeof cell?.metadata.lastRunSuccess !== 'undefined') { if (!cell || typeof cell.metadata.runState !== 'undefined' || typeof cell.metadata.lastRunSuccess !== 'undefined') {
return { items: [] }; return;
}
let text: string;
if (cell.cellKind === CellKind.Code) {
const keybinding = this._keybindingService.lookupKeybinding(EXECUTE_CELL_COMMAND_ID)?.getLabel();
if (!keybinding) {
return;
}
text = localize('notebook.cell.status.codeExecuteTip', "Press {0} to execute cell", keybinding);
} else {
const keybinding = this._keybindingService.lookupKeybinding(QUIT_EDIT_CELL_COMMAND_ID)?.getLabel();
if (!keybinding) {
return;
}
text = localize('notebook.cell.status.markdownExecuteTip', "Press {0} to stop editing", keybinding);
} }
const text = isWindows ? 'Ctrl + Alt + Enter to run' : 'Ctrl + Enter to run';
const item = <INotebookCellStatusBarItem>{ const item = <INotebookCellStatusBarItem>{
text, text,
tooltip: text, tooltip: text,
...@@ -46,12 +65,47 @@ class CellStatusBarPlaceholderProvider implements INotebookCellStatusBarItemProv ...@@ -46,12 +65,47 @@ class CellStatusBarPlaceholderProvider implements INotebookCellStatusBarItemProv
} }
} }
class CellStatusBarLanguagePickerProvider implements INotebookCellStatusBarItemProvider {
readonly selector: INotebookDocumentFilter = {
filenamePattern: '**/*'
};
constructor(
@INotebookService private readonly _notebookService: INotebookService,
@IModeService private readonly _modeService: IModeService,
) { }
async provideCellStatusBarItems(uri: URI, index: number, _token: CancellationToken): Promise<INotebookCellStatusBarItemList | undefined> {
const doc = this._notebookService.getNotebookTextModel(uri);
const cell = doc?.cells[index];
if (!cell) {
return;
}
const modeId = cell.cellKind === CellKind.Markdown ?
'markdown' :
(this._modeService.getModeIdForLanguageName(cell.language) || cell.language);
const text = this._modeService.getLanguageName(modeId) || this._modeService.getLanguageName('plaintext');
const item = <INotebookCellStatusBarItem>{
text,
command: CHANGE_CELL_LANGUAGE,
tooltip: localize('notebook.cell.status.language', "Select Cell Language Mode"),
alignment: CellStatusbarAlignment.Right,
priority: -Number.MAX_SAFE_INTEGER
};
return {
items: [item]
};
}
}
class BuiltinCellStatusBarProviders extends Disposable { class BuiltinCellStatusBarProviders extends Disposable {
constructor( constructor(
@IInstantiationService instantiationService: IInstantiationService, @IInstantiationService instantiationService: IInstantiationService,
@INotebookCellStatusBarService notebookCellStatusBarService: INotebookCellStatusBarService) { @INotebookCellStatusBarService notebookCellStatusBarService: INotebookCellStatusBarService) {
super(); super();
this._register(notebookCellStatusBarService.registerCellStatusBarItemProvider(instantiationService.createInstance(CellStatusBarPlaceholderProvider))); this._register(notebookCellStatusBarService.registerCellStatusBarItemProvider(instantiationService.createInstance(CellStatusBarPlaceholderProvider)));
this._register(notebookCellStatusBarService.registerCellStatusBarItemProvider(instantiationService.createInstance(CellStatusBarLanguagePickerProvider)));
} }
} }
......
...@@ -493,11 +493,11 @@ export function getFormatedMetadataJSON(documentTextModel: NotebookTextModel, me ...@@ -493,11 +493,11 @@ export function getFormatedMetadataJSON(documentTextModel: NotebookTextModel, me
let filteredMetadata: { [key: string]: any } = {}; let filteredMetadata: { [key: string]: any } = {};
if (documentTextModel) { if (documentTextModel) {
const transientMetadata = documentTextModel.transientOptions.transientMetadata; const transientCellMetadata = documentTextModel.transientOptions.transientCellMetadata;
const keys = new Set([...Object.keys(metadata)]); const keys = new Set([...Object.keys(metadata)]);
for (let key of keys) { for (let key of keys) {
if (!(transientMetadata[key as keyof NotebookCellMetadata]) if (!(transientCellMetadata[key as keyof NotebookCellMetadata])
) { ) {
filteredMetadata[key] = metadata[key as keyof NotebookCellMetadata]; filteredMetadata[key] = metadata[key as keyof NotebookCellMetadata];
} }
......
...@@ -420,7 +420,6 @@ ...@@ -420,7 +420,6 @@
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-left, .monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-left,
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-right { .monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-right {
padding-right: 12px;
display: flex; display: flex;
z-index: 26; z-index: 26;
} }
...@@ -448,24 +447,15 @@ ...@@ -448,24 +447,15 @@
cursor: pointer; cursor: pointer;
} }
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-language-picker {
cursor: pointer;
}
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-run-duration { .monaco-workbench .notebookOverlay .cell-statusbar-container .cell-run-duration {
margin-right: 8px; margin-right: 8px;
} }
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-run-duration, .monaco-workbench .notebookOverlay .cell-statusbar-container .cell-run-duration {
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-message {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-status-message {
margin-right: 6px;
}
.monaco-workbench .notebookOverlay .cell-statusbar-container .cell-run-status { .monaco-workbench .notebookOverlay .cell-statusbar-container .cell-run-status {
height: 100%; height: 100%;
display: flex; display: flex;
......
...@@ -72,6 +72,8 @@ export const NOTEBOOK_INTERRUPTIBLE_KERNEL = new RawContextKey<boolean>('noteboo ...@@ -72,6 +72,8 @@ export const NOTEBOOK_INTERRUPTIBLE_KERNEL = new RawContextKey<boolean>('noteboo
//#region Shared commands //#region Shared commands
export const EXPAND_CELL_INPUT_COMMAND_ID = 'notebook.cell.expandCellInput'; export const EXPAND_CELL_INPUT_COMMAND_ID = 'notebook.cell.expandCellInput';
export const EXECUTE_CELL_COMMAND_ID = 'notebook.cell.execute'; export const EXECUTE_CELL_COMMAND_ID = 'notebook.cell.execute';
export const CHANGE_CELL_LANGUAGE = 'notebook.cell.changeLanguage';
export const QUIT_EDIT_CELL_COMMAND_ID = 'notebook.cell.quitEdit';
//#endregion //#endregion
......
...@@ -43,9 +43,9 @@ export class NotebookCellStatusBarService extends Disposable implements INoteboo ...@@ -43,9 +43,9 @@ export class NotebookCellStatusBarService extends Disposable implements INoteboo
async getStatusBarItemsForCell(docUri: URI, cellIndex: number, viewType: string, token: CancellationToken): Promise<INotebookCellStatusBarItemList[]> { async getStatusBarItemsForCell(docUri: URI, cellIndex: number, viewType: string, token: CancellationToken): Promise<INotebookCellStatusBarItemList[]> {
const providers = this._providers.filter(p => notebookDocumentFilterMatch(p.selector, viewType, docUri)); const providers = this._providers.filter(p => notebookDocumentFilterMatch(p.selector, viewType, docUri));
return await Promise.all(providers.map(p => { return await Promise.all(providers.map(async p => {
try { try {
return p.provideCellStatusBarItems(docUri, cellIndex, token); return await p.provideCellStatusBarItems(docUri, cellIndex, token) ?? { items: [] };
} catch (e) { } catch (e) {
onUnexpectedExternalError(e); onUnexpectedExternalError(e);
return { items: [] }; return { items: [] };
......
...@@ -40,7 +40,7 @@ export class NotebookKernelService implements INotebookKernelService { ...@@ -40,7 +40,7 @@ export class NotebookKernelService implements INotebookKernelService {
registerKernel(kernel: INotebookKernel2): IDisposable { registerKernel(kernel: INotebookKernel2): IDisposable {
if (this._kernels.has(kernel.id)) { if (this._kernels.has(kernel.id)) {
throw new Error(`KERNEL with id '${kernel.id}' already exists`); throw new Error(`NOTEBOOK CONTROLLER with id '${kernel.id}' already exists`);
} }
this._kernels.set(kernel.id, kernel); this._kernels.set(kernel.id, kernel);
......
...@@ -83,18 +83,23 @@ export class NotebookKernelProviderInfoStore { ...@@ -83,18 +83,23 @@ export class NotebookKernelProviderInfoStore {
} }
export class NotebookProviderInfoStore extends Disposable { export class NotebookProviderInfoStore extends Disposable {
private static readonly CUSTOM_EDITORS_STORAGE_ID = 'notebookEditors'; private static readonly CUSTOM_EDITORS_STORAGE_ID = 'notebookEditors';
private static readonly CUSTOM_EDITORS_ENTRY_ID = 'editors'; private static readonly CUSTOM_EDITORS_ENTRY_ID = 'editors';
private readonly _memento: Memento; private readonly _memento: Memento;
private _handled: boolean = false; private _handled: boolean = false;
private readonly _contributedEditors = new Map<string, NotebookProviderInfo>();
private readonly _contributedEditorDisposables = new DisposableStore();
constructor( constructor(
storageService: IStorageService, @IStorageService storageService: IStorageService,
extensionService: IExtensionService, @IExtensionService extensionService: IExtensionService,
private readonly _editorOverrideService: IEditorOverrideService, @IEditorOverrideService private readonly _editorOverrideService: IEditorOverrideService,
private readonly _instantiationService: IInstantiationService, @IConfigurationService private readonly _configurationService: IConfigurationService,
private readonly _configurationService: IConfigurationService, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
private readonly _accessibilityService: IAccessibilityService, @IInstantiationService private readonly _instantiationService: IInstantiationService,
) { ) {
super(); super();
this._memento = new Memento(NotebookProviderInfoStore.CUSTOM_EDITORS_STORAGE_ID, storageService); this._memento = new Memento(NotebookProviderInfoStore.CUSTOM_EDITORS_STORAGE_ID, storageService);
...@@ -110,18 +115,25 @@ export class NotebookProviderInfoStore extends Disposable { ...@@ -110,18 +115,25 @@ export class NotebookProviderInfoStore extends Disposable {
if (!this._handled) { if (!this._handled) {
// there is no extension point registered for notebook content provider // there is no extension point registered for notebook content provider
// clear the memento and cache // clear the memento and cache
this.clear(); this._clear();
mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = []; mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = [];
this._memento.saveMemento(); this._memento.saveMemento();
this._updateProviderExtensionsInfo(); this._updateProviderExtensionsInfo();
} }
})); }));
notebookProviderExtensionPoint.setHandler(extensions => this._setupHandler(extensions));
} }
setupHandler(extensions: readonly IExtensionPointUser<INotebookEditorContribution[]>[]) { override dispose(): void {
this._clear();
super.dispose();
}
private _setupHandler(extensions: readonly IExtensionPointUser<INotebookEditorContribution[]>[]) {
this._handled = true; this._handled = true;
this.clear(); this._clear();
for (const extension of extensions) { for (const extension of extensions) {
for (const notebookContribution of extension.value) { for (const notebookContribution of extension.value) {
...@@ -174,10 +186,10 @@ export class NotebookProviderInfoStore extends Disposable { ...@@ -174,10 +186,10 @@ export class NotebookProviderInfoStore extends Disposable {
} }
private registerContributionPoint(notebookProviderInfo: NotebookProviderInfo): void { private _registerContributionPoint(notebookProviderInfo: NotebookProviderInfo): void {
for (const selector of notebookProviderInfo.selectors) { for (const selector of notebookProviderInfo.selectors) {
const globPattern = (selector as INotebookExclusiveDocumentFilter).include || selector as glob.IRelativePattern | string; const globPattern = (selector as INotebookExclusiveDocumentFilter).include || selector as glob.IRelativePattern | string;
this._register(this._editorOverrideService.registerContributionPoint( this._contributedEditorDisposables.add(this._editorOverrideService.registerContributionPoint(
globPattern, globPattern,
priorityToRank(notebookProviderInfo.exclusive ? ContributedEditorPriority.exclusive : notebookProviderInfo.priority), priorityToRank(notebookProviderInfo.exclusive ? ContributedEditorPriority.exclusive : notebookProviderInfo.priority),
{ {
...@@ -215,10 +227,10 @@ export class NotebookProviderInfoStore extends Disposable { ...@@ -215,10 +227,10 @@ export class NotebookProviderInfoStore extends Disposable {
} }
} }
private readonly _contributedEditors = new Map<string, NotebookProviderInfo>();
clear() { private _clear(): void {
this._contributedEditors.clear(); this._contributedEditors.clear();
this._contributedEditorDisposables.clear();
} }
get(viewType: string): NotebookProviderInfo | undefined { get(viewType: string): NotebookProviderInfo | undefined {
...@@ -230,7 +242,7 @@ export class NotebookProviderInfoStore extends Disposable { ...@@ -230,7 +242,7 @@ export class NotebookProviderInfoStore extends Disposable {
return; return;
} }
this._contributedEditors.set(info.id, info); this._contributedEditors.set(info.id, info);
this.registerContributionPoint(info); this._registerContributionPoint(info);
const mementoObject = this._memento.getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE); const mementoObject = this._memento.getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE);
mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = Array.from(this._contributedEditors.values()); mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = Array.from(this._contributedEditors.values());
...@@ -318,8 +330,6 @@ class ModelData implements IDisposable { ...@@ -318,8 +330,6 @@ class ModelData implements IDisposable {
} }
} }
export class NotebookService extends Disposable implements INotebookService, IEditorTypesHandler { export class NotebookService extends Disposable implements INotebookService, IEditorTypesHandler {
declare readonly _serviceBrand: undefined; declare readonly _serviceBrand: undefined;
...@@ -352,25 +362,15 @@ export class NotebookService extends Disposable implements INotebookService, IEd ...@@ -352,25 +362,15 @@ export class NotebookService extends Disposable implements INotebookService, IEd
@IExtensionService private readonly _extensionService: IExtensionService, @IExtensionService private readonly _extensionService: IExtensionService,
@IConfigurationService private readonly _configurationService: IConfigurationService, @IConfigurationService private readonly _configurationService: IConfigurationService,
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
@IStorageService private readonly _storageService: IStorageService,
@IInstantiationService private readonly _instantiationService: IInstantiationService, @IInstantiationService private readonly _instantiationService: IInstantiationService,
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService, @ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IEditorOverrideService private readonly _editorOverrideService: IEditorOverrideService,
) { ) {
super(); super();
this._notebookProviderInfoStore = new NotebookProviderInfoStore( this._notebookProviderInfoStore = _instantiationService.createInstance(NotebookProviderInfoStore);
this._storageService,
this._extensionService, this._editorOverrideService,
this._instantiationService, this._configurationService,
this._accessibilityService
);
this._register(this._notebookProviderInfoStore); this._register(this._notebookProviderInfoStore);
notebookProviderExtensionPoint.setHandler((extensions) => {
this._notebookProviderInfoStore.setupHandler(extensions);
});
notebookRendererExtensionPoint.setHandler((renderers) => { notebookRendererExtensionPoint.setHandler((renderers) => {
this._notebookRenderersInfoStore.clear(); this._notebookRenderersInfoStore.clear();
......
...@@ -7,22 +7,19 @@ import * as DOM from 'vs/base/browser/dom'; ...@@ -7,22 +7,19 @@ import * as DOM from 'vs/base/browser/dom';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { SimpleIconLabel } from 'vs/base/browser/ui/iconLabel/simpleIconLabel'; import { SimpleIconLabel } from 'vs/base/browser/ui/iconLabel/simpleIconLabel';
import { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions'; import { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';
import { stripIcons } from 'vs/base/common/iconLabels';
import { toErrorMessage } from 'vs/base/common/errorMessage'; import { toErrorMessage } from 'vs/base/common/errorMessage';
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
import { stripIcons } from 'vs/base/common/iconLabels';
import { KeyCode } from 'vs/base/common/keyCodes'; import { KeyCode } from 'vs/base/common/keyCodes';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver'; import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
import { IDimension } from 'vs/editor/common/editorCommon'; import { IDimension } from 'vs/editor/common/editorCommon';
import { IModeService } from 'vs/editor/common/services/modeService';
import { localize } from 'vs/nls';
import { ICommandService } from 'vs/platform/commands/common/commands'; import { ICommandService } from 'vs/platform/commands/common/commands';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { INotificationService } from 'vs/platform/notification/common/notification'; import { INotificationService } from 'vs/platform/notification/common/notification';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ChangeCellLanguageAction, INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; import { INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions';
import { ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellStatusbarAlignment, INotebookCellStatusBarItem } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellKind, CellStatusbarAlignment, INotebookCellStatusBarItem } from 'vs/workbench/contrib/notebook/common/notebookCommon';
const $ = DOM.$; const $ = DOM.$;
...@@ -41,7 +38,6 @@ export const enum ClickTargetType { ...@@ -41,7 +38,6 @@ export const enum ClickTargetType {
export class CellEditorStatusBar extends Disposable { export class CellEditorStatusBar extends Disposable {
readonly cellRunStatusContainer: HTMLElement; readonly cellRunStatusContainer: HTMLElement;
readonly statusBarContainer: HTMLElement; readonly statusBarContainer: HTMLElement;
readonly languageStatusBarItem: CellLanguageStatusBarItem;
readonly durationContainer: HTMLElement; readonly durationContainer: HTMLElement;
private readonly leftContributedItemsContainer: HTMLElement; private readonly leftContributedItemsContainer: HTMLElement;
...@@ -65,7 +61,6 @@ export class CellEditorStatusBar extends Disposable { ...@@ -65,7 +61,6 @@ export class CellEditorStatusBar extends Disposable {
this.durationContainer = DOM.append(leftItemsContainer, $('.cell-run-duration')); this.durationContainer = DOM.append(leftItemsContainer, $('.cell-run-duration'));
this.leftContributedItemsContainer = DOM.append(leftItemsContainer, $('.cell-contributed-items.cell-contributed-items-left')); this.leftContributedItemsContainer = DOM.append(leftItemsContainer, $('.cell-contributed-items.cell-contributed-items-left'));
this.rightContributedItemsContainer = DOM.append(rightItemsContainer, $('.cell-contributed-items.cell-contributed-items-right')); this.rightContributedItemsContainer = DOM.append(rightItemsContainer, $('.cell-contributed-items.cell-contributed-items-right'));
this.languageStatusBarItem = instantiationService.createInstance(CellLanguageStatusBarItem, rightItemsContainer);
this.itemsDisposable = this._register(new DisposableStore()); this.itemsDisposable = this._register(new DisposableStore());
...@@ -104,7 +99,6 @@ export class CellEditorStatusBar extends Disposable { ...@@ -104,7 +99,6 @@ export class CellEditorStatusBar extends Disposable {
update(context: INotebookCellActionContext) { update(context: INotebookCellActionContext) {
this.currentContext = context; this.currentContext = context;
this.itemsDisposable.clear(); this.itemsDisposable.clear();
this.languageStatusBarItem.update(context.cell, context.notebookEditor);
this.updateStatusBarItems(); this.updateStatusBarItems();
} }
...@@ -224,61 +218,6 @@ class CellStatusBarItem extends Disposable { ...@@ -224,61 +218,6 @@ class CellStatusBarItem extends Disposable {
} }
} }
export class CellLanguageStatusBarItem extends Disposable {
private readonly labelElement: HTMLElement;
private cell: ICellViewModel | undefined;
private editor: INotebookEditor | undefined;
private cellDisposables: DisposableStore;
constructor(
readonly container: HTMLElement,
@IModeService private readonly modeService: IModeService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super();
this.labelElement = DOM.append(container, $('.cell-language-picker.cell-status-item'));
this.labelElement.tabIndex = 0;
this.labelElement.classList.add('cell-status-item-has-command');
this._register(DOM.addDisposableListener(this.labelElement, DOM.EventType.CLICK, () => {
this.run();
}));
this._register(DOM.addDisposableListener(this.labelElement, DOM.EventType.KEY_DOWN, e => {
const event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {
this.run();
}
}));
this._register(this.cellDisposables = new DisposableStore());
}
private run() {
this.instantiationService.invokeFunction(accessor => {
if (!this.editor || !this.editor.hasModel() || !this.cell) {
return;
}
new ChangeCellLanguageAction().run(accessor, { notebookEditor: this.editor, cell: this.cell });
});
}
update(cell: ICellViewModel, editor: INotebookEditor): void {
this.cellDisposables.clear();
this.cell = cell;
this.editor = editor;
this.render();
this.cellDisposables.add(this.cell.model.onDidChangeLanguage(() => this.render()));
}
private render(): void {
const modeId = this.cell?.cellKind === CellKind.Markdown ? 'markdown' : this.modeService.getModeIdForLanguageName(this.cell!.language) || this.cell!.language;
this.labelElement.textContent = this.modeService.getLanguageName(modeId) || this.modeService.getLanguageName('plaintext');
this.labelElement.title = localize('notebook.cell.status.language', "Select Cell Language Mode");
}
}
declare const ResizeObserver: any; declare const ResizeObserver: any;
export interface IResizeObserver { export interface IResizeObserver {
......
...@@ -159,11 +159,11 @@ export class NotebookCellTextModel extends Disposable implements ICell { ...@@ -159,11 +159,11 @@ export class NotebookCellTextModel extends Disposable implements ICell {
private _getPersisentMetadata() { private _getPersisentMetadata() {
let filteredMetadata: { [key: string]: any } = {}; let filteredMetadata: { [key: string]: any } = {};
const transientMetadata = this.transientOptions.transientMetadata; const transientCellMetadata = this.transientOptions.transientCellMetadata;
const keys = new Set([...Object.keys(this.metadata)]); const keys = new Set([...Object.keys(this.metadata)]);
for (let key of keys) { for (let key of keys) {
if (!(transientMetadata[key as keyof NotebookCellMetadata]) if (!(transientCellMetadata[key as keyof NotebookCellMetadata])
) { ) {
filteredMetadata[key] = this.metadata[key as keyof NotebookCellMetadata]; filteredMetadata[key] = this.metadata[key as keyof NotebookCellMetadata];
} }
......
...@@ -193,7 +193,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel ...@@ -193,7 +193,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
private _cells: NotebookCellTextModel[] = []; private _cells: NotebookCellTextModel[] = [];
metadata: NotebookDocumentMetadata = notebookDocumentMetadataDefaults; metadata: NotebookDocumentMetadata = notebookDocumentMetadataDefaults;
transientOptions: TransientOptions = { transientMetadata: {}, transientOutputs: false }; transientOptions: TransientOptions = { transientCellMetadata: {}, transientDocumentMetadata: {}, transientOutputs: false };
private _versionId = 0; private _versionId = 0;
/** /**
...@@ -515,25 +515,28 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel ...@@ -515,25 +515,28 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
private _updateNotebookMetadata(metadata: NotebookDocumentMetadata, computeUndoRedo: boolean) { private _updateNotebookMetadata(metadata: NotebookDocumentMetadata, computeUndoRedo: boolean) {
const oldMetadata = this.metadata; const oldMetadata = this.metadata;
this.metadata = metadata; const triggerDirtyChange = this._isDocumentMetadataChanged(this.metadata, metadata);
if (computeUndoRedo) { if (triggerDirtyChange) {
const that = this; if (computeUndoRedo) {
this._operationManager.pushEditOperation(new class implements IResourceUndoRedoElement { const that = this;
readonly type: UndoRedoElementType.Resource = UndoRedoElementType.Resource; this._operationManager.pushEditOperation(new class implements IResourceUndoRedoElement {
get resource() { readonly type: UndoRedoElementType.Resource = UndoRedoElementType.Resource;
return that.uri; get resource() {
} return that.uri;
readonly label = 'Update Notebook Metadata'; }
undo() { readonly label = 'Update Notebook Metadata';
that._updateNotebookMetadata(oldMetadata, false); undo() {
} that._updateNotebookMetadata(oldMetadata, false);
redo() { }
that._updateNotebookMetadata(metadata, false); redo() {
} that._updateNotebookMetadata(metadata, false);
}(), undefined, undefined); }
}(), undefined, undefined);
}
} }
this.metadata = metadata;
this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeDocumentMetadata, metadata: this.metadata, transient: this._isDocumentMetadataChangeTransient(oldMetadata, metadata) }, true); this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeDocumentMetadata, metadata: this.metadata, transient: this._isDocumentMetadataChangeTransient(oldMetadata, metadata) }, true);
} }
...@@ -595,20 +598,42 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel ...@@ -595,20 +598,42 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
} }
private _isDocumentMetadataChanged(a: NotebookDocumentMetadata, b: NotebookDocumentMetadata) {
const keys = new Set([...Object.keys(a || {}), ...Object.keys(b || {})]);
for (let key of keys) {
if (key === 'custom') {
if (!this._customMetadataEqual(a[key], b[key])
&&
!(this.transientOptions.transientCellMetadata[key as keyof NotebookCellMetadata])
) {
return true;
}
} else if (
(a[key as keyof NotebookDocumentMetadata] !== b[key as keyof NotebookDocumentMetadata])
&&
!(this.transientOptions.transientDocumentMetadata[key as keyof NotebookDocumentMetadata])
) {
return true;
}
}
return false;
}
private _isCellMetadataChanged(a: NotebookCellMetadata, b: NotebookCellMetadata) { private _isCellMetadataChanged(a: NotebookCellMetadata, b: NotebookCellMetadata) {
const keys = new Set([...Object.keys(a || {}), ...Object.keys(b || {})]); const keys = new Set([...Object.keys(a || {}), ...Object.keys(b || {})]);
for (let key of keys) { for (let key of keys) {
if (key === 'custom') { if (key === 'custom') {
if (!this._customMetadataEqual(a[key], b[key]) if (!this._customMetadataEqual(a[key], b[key])
&& &&
!(this.transientOptions.transientMetadata[key as keyof NotebookCellMetadata]) !(this.transientOptions.transientCellMetadata[key as keyof NotebookCellMetadata])
) { ) {
return true; return true;
} }
} else if ( } else if (
(a[key as keyof NotebookCellMetadata] !== b[key as keyof NotebookCellMetadata]) (a[key as keyof NotebookCellMetadata] !== b[key as keyof NotebookCellMetadata])
&& &&
!(this.transientOptions.transientMetadata[key as keyof NotebookCellMetadata]) !(this.transientOptions.transientCellMetadata[key as keyof NotebookCellMetadata])
) { ) {
return true; return true;
} }
......
...@@ -92,11 +92,13 @@ export interface NotebookCellMetadata { ...@@ -92,11 +92,13 @@ export interface NotebookCellMetadata {
custom?: { [key: string]: unknown }; custom?: { [key: string]: unknown };
} }
export type TransientMetadata = { [K in keyof NotebookCellMetadata]?: boolean }; export type TransientCellMetadata = { [K in keyof NotebookCellMetadata]?: boolean };
export type TransientDocumentMetadata = { [K in keyof NotebookDocumentMetadata]?: boolean };
export interface TransientOptions { export interface TransientOptions {
transientOutputs: boolean; transientOutputs: boolean;
transientMetadata: TransientMetadata; transientCellMetadata: TransientCellMetadata;
transientDocumentMetadata: TransientDocumentMetadata;
} }
export interface INotebookMimeTypeSelector { export interface INotebookMimeTypeSelector {
...@@ -793,7 +795,7 @@ export interface INotebookKernelProvider { ...@@ -793,7 +795,7 @@ export interface INotebookKernelProvider {
export interface INotebookCellStatusBarItemProvider { export interface INotebookCellStatusBarItemProvider {
selector: INotebookDocumentFilter; selector: INotebookDocumentFilter;
onDidChangeStatusBarItems?: Event<void>; onDidChangeStatusBarItems?: Event<void>;
provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken): Promise<INotebookCellStatusBarItemList>; provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken): Promise<INotebookCellStatusBarItemList | undefined>;
} }
export class CellSequence implements ISequence { export class CellSequence implements ISequence {
......
...@@ -61,7 +61,8 @@ export class NotebookProviderInfo { ...@@ -61,7 +61,8 @@ export class NotebookProviderInfo {
this.dynamicContribution = descriptor.dynamicContribution; this.dynamicContribution = descriptor.dynamicContribution;
this.exclusive = descriptor.exclusive; this.exclusive = descriptor.exclusive;
this._options = { this._options = {
transientMetadata: {}, transientCellMetadata: {},
transientDocumentMetadata: {},
transientOutputs: false transientOutputs: false
}; };
} }
......
...@@ -31,11 +31,9 @@ suite('NotebookProviderInfoStore', function () { ...@@ -31,11 +31,9 @@ suite('NotebookProviderInfoStore', function () {
override onDidRegisterExtensions = Event.None; override onDidRegisterExtensions = Event.None;
}, },
instantiationService.createInstance(EditorOverrideService), instantiationService.createInstance(EditorOverrideService),
instantiationService,
new TestConfigurationService(), new TestConfigurationService(),
new class extends mock<IAccessibilityService>() { new class extends mock<IAccessibilityService>() { },
instantiationService,
}
); );
const fooInfo = new NotebookProviderInfo({ const fooInfo = new NotebookProviderInfo({
......
...@@ -34,7 +34,7 @@ suite('NotebookViewModel', () => { ...@@ -34,7 +34,7 @@ suite('NotebookViewModel', () => {
instantiationService.stub(IThemeService, new TestThemeService()); instantiationService.stub(IThemeService, new TestThemeService());
test('ctor', function () { test('ctor', function () {
const notebook = new NotebookTextModel('notebook', URI.parse('test'), [], notebookDocumentMetadataDefaults, { transientMetadata: {}, transientOutputs: false }, undoRedoService, modelService, modeService); const notebook = new NotebookTextModel('notebook', URI.parse('test'), [], notebookDocumentMetadataDefaults, { transientCellMetadata: {}, transientDocumentMetadata: {}, transientOutputs: false }, undoRedoService, modelService, modeService);
const model = new NotebookEditorTestModel(notebook); const model = new NotebookEditorTestModel(notebook);
const eventDispatcher = new NotebookEventDispatcher(); const eventDispatcher = new NotebookEventDispatcher();
const viewModel = new NotebookViewModel('notebook', model.notebook, eventDispatcher, null, instantiationService, bulkEditService, undoRedoService, textModelService); const viewModel = new NotebookViewModel('notebook', model.notebook, eventDispatcher, null, instantiationService, bulkEditService, undoRedoService, textModelService);
......
...@@ -47,7 +47,7 @@ export class TestCell extends NotebookCellTextModel { ...@@ -47,7 +47,7 @@ export class TestCell extends NotebookCellTextModel {
outputs: IOutputDto[], outputs: IOutputDto[],
modeService: IModeService, modeService: IModeService,
) { ) {
super(CellUri.generate(URI.parse('test:///fake/notebook'), handle), handle, source, language, cellKind, outputs, undefined, { transientMetadata: {}, transientOutputs: false }, modeService); super(CellUri.generate(URI.parse('test:///fake/notebook'), handle), handle, source, language, cellKind, outputs, undefined, { transientCellMetadata: {}, transientDocumentMetadata: {}, transientOutputs: false }, modeService);
} }
} }
...@@ -152,7 +152,7 @@ function _createTestNotebookEditor(instantiationService: TestInstantiationServic ...@@ -152,7 +152,7 @@ function _createTestNotebookEditor(instantiationService: TestInstantiationServic
outputs: cell[3] ?? [], outputs: cell[3] ?? [],
metadata: cell[4] metadata: cell[4]
}; };
}), notebookDocumentMetadataDefaults, { transientMetadata: {}, transientOutputs: false }); }), notebookDocumentMetadataDefaults, { transientCellMetadata: {}, transientDocumentMetadata: {}, transientOutputs: false });
const model = new NotebookEditorTestModel(notebook); const model = new NotebookEditorTestModel(notebook);
const eventDispatcher = new NotebookEventDispatcher(); const eventDispatcher = new NotebookEventDispatcher();
......
...@@ -29,7 +29,7 @@ suite('NotebookKernel', function () { ...@@ -29,7 +29,7 @@ suite('NotebookKernel', function () {
override $registerCommand() { } override $registerCommand() { }
}); });
rpcProtocol.set(MainContext.MainThreadNotebookKernels, new class extends mock<MainThreadNotebookKernelsShape>() { rpcProtocol.set(MainContext.MainThreadNotebookKernels, new class extends mock<MainThreadNotebookKernelsShape>() {
override $addKernel(handle: number, data: INotebookKernelDto2): void { async override $addKernel(handle: number, data: INotebookKernelDto2): Promise<void> {
kernelData.set(handle, data); kernelData.set(handle, data);
} }
override $removeKernel(handle: number) { override $removeKernel(handle: number) {
...@@ -50,7 +50,7 @@ suite('NotebookKernel', function () { ...@@ -50,7 +50,7 @@ suite('NotebookKernel', function () {
test('create/dispose kernel', async function () { test('create/dispose kernel', async function () {
const kernel = extHostNotebookKernels.createKernel(nullExtensionDescription, { id: 'foo', label: 'Foo', selector: '*', executeHandler: () => { }, supportedLanguages: ['plaintext'] }); const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
assert.ok(kernel); assert.ok(kernel);
assert.strictEqual(kernel.id, 'foo'); assert.strictEqual(kernel.id, 'foo');
...@@ -73,7 +73,7 @@ suite('NotebookKernel', function () { ...@@ -73,7 +73,7 @@ suite('NotebookKernel', function () {
test('update kernel', async function () { test('update kernel', async function () {
const kernel = extHostNotebookKernels.createKernel(nullExtensionDescription, { id: 'foo', label: 'Foo', selector: '*', executeHandler: () => { }, supportedLanguages: ['plaintext'] }); const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
await rpcProtocol.sync(); await rpcProtocol.sync();
assert.ok(kernel); assert.ok(kernel);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册