diff --git a/src/dotnet-interactive-vscode/common/interfaces/vscode-like.ts b/src/dotnet-interactive-vscode/common/interfaces/vscode-like.ts index aae39b8b0f..d65745160a 100644 --- a/src/dotnet-interactive-vscode/common/interfaces/vscode-like.ts +++ b/src/dotnet-interactive-vscode/common/interfaces/vscode-like.ts @@ -13,13 +13,12 @@ export const ErrorOutputMimeType = 'application/vnd.code.notebook.error'; export interface NotebookCellOutputItem { readonly mime: string; readonly data: Uint8Array; - readonly metadata?: { [key: string]: any }; [key: string]: any; // this is to make compilation on stable happy } export interface NotebookCellOutput { id: string; - outputs: NotebookCellOutputItem[]; + items: NotebookCellOutputItem[]; metadata?: { [key: string]: any }; } @@ -30,21 +29,6 @@ export enum NotebookCellRunState { Error = 4 } -export interface NotebookCellMetadata { - editable?: boolean, - breakpointMargin?: boolean, - runnable?: boolean, - hasExecutionOrder?: boolean, - executionOrder?: number, - runState?: NotebookCellRunState, - runStartTime?: number, - statusMessage?: string, - lastRunDuration?: number, - inputCollapsed?: boolean, - outputCollapsed?: boolean, - custom?: Record, -} - export interface Uri { fsPath: string; scheme: string; @@ -72,7 +56,7 @@ export interface NotebookCellData { source: string; language: string; outputs: NotebookCellOutput[]; - metadata?: NotebookCellMetadata; + metadata?: { [key: string]: any }; } export interface NotebookDocumentBackup { diff --git a/src/dotnet-interactive-vscode/common/tests/unit/client.test.ts b/src/dotnet-interactive-vscode/common/tests/unit/client.test.ts index a1ff204591..5a8eae855c 100644 --- a/src/dotnet-interactive-vscode/common/tests/unit/client.test.ts +++ b/src/dotnet-interactive-vscode/common/tests/unit/client.test.ts @@ -79,7 +79,7 @@ describe('InteractiveClient tests', () => { expect(decodedResults).to.deep.equal([ { id: '1', - outputs: [ + items: [ { mime: 'text/plain', decodedData: 'deferred output', @@ -88,7 +88,7 @@ describe('InteractiveClient tests', () => { }, { id: '2', - outputs: [ + items: [ { mime: 'text/html', decodedData: '2', @@ -161,7 +161,7 @@ describe('InteractiveClient tests', () => { expect(decodedResults).to.deep.equal([ { id: '1', - outputs: [ + items: [ { mime: 'text/plain', decodedData: 'deferred output', @@ -170,7 +170,7 @@ describe('InteractiveClient tests', () => { }, { id: '3', - outputs: [ + items: [ { mime: 'text/html', decodedData: '2', @@ -258,7 +258,7 @@ describe('InteractiveClient tests', () => { expect(decodedResults).to.deep.equal([ { id: '1', - outputs: [ + items: [ { mime: 'text/plain', decodedData: 'deferred output 1', @@ -267,7 +267,7 @@ describe('InteractiveClient tests', () => { }, { id: '4', - outputs: [ + items: [ { mime: 'text/html', decodedData: '2', @@ -276,7 +276,7 @@ describe('InteractiveClient tests', () => { }, { id: '3', - outputs: [ + items: [ { mime: 'text/plain', decodedData: 'deferred output 2', @@ -342,7 +342,7 @@ describe('InteractiveClient tests', () => { expect(decodedResults1).to.deep.equal([ { id: '1', - outputs: [ + items: [ { mime: 'text/html', decodedData: '1', @@ -361,7 +361,7 @@ describe('InteractiveClient tests', () => { expect(decodedResults1).to.deep.equal([ { id: '2', - outputs: [ + items: [ { mime: 'text/html', decodedData: '2', @@ -481,7 +481,7 @@ describe('InteractiveClient tests', () => { const decodedOutputs = decodeNotebookCellOutputs(seenOutputs); expect(decodedOutputs).to.deep.equal([{ id: '1', - outputs: [{ + items: [{ mime: vscodeLike.ErrorOutputMimeType, decodedData: { name: 'Error', diff --git a/src/dotnet-interactive-vscode/common/tests/unit/notebook.test.ts b/src/dotnet-interactive-vscode/common/tests/unit/notebook.test.ts index 9cd8e88562..ba04d10edb 100644 --- a/src/dotnet-interactive-vscode/common/tests/unit/notebook.test.ts +++ b/src/dotnet-interactive-vscode/common/tests/unit/notebook.test.ts @@ -76,7 +76,7 @@ describe('Notebook tests', () => { expect(decodedResults).to.deep.equal([ { id: '1', - outputs: [ + items: [ { mime: 'text/html', decodedData: '2', @@ -164,7 +164,7 @@ Console.WriteLine(1); expect(decodedResults).to.deep.equal([ { id: '1', - outputs: [ + items: [ { mime: 'text/plain', decodedData: '1\r\n', @@ -173,7 +173,7 @@ Console.WriteLine(1); }, { id: '2', - outputs: [ + items: [ { mime: 'text/plain', decodedData: '2\r\n', @@ -182,7 +182,7 @@ Console.WriteLine(1); }, { id: '3', - outputs: [ + items: [ { mime: 'text/plain', decodedData: '3\r\n', @@ -260,7 +260,7 @@ Console.WriteLine(1); expect(decodedResults).to.deep.equal([ { id: '2', - outputs: [ + items: [ { mime: 'text/plain', decodedData: 'Installed package Newtonsoft.Json version 1.2.3.4', @@ -269,7 +269,7 @@ Console.WriteLine(1); }, { id: '3', - outputs: [ + items: [ { mime: 'text/plain', decodedData: 'sentinel', @@ -326,7 +326,7 @@ Console.WriteLine(1); expect(decodedResults).to.deep.equal([ { id: '1', - outputs: [ + items: [ { mime: 'application/json', decodedData: { diff --git a/src/dotnet-interactive-vscode/common/tests/unit/utilities.ts b/src/dotnet-interactive-vscode/common/tests/unit/utilities.ts index daab008f5c..2e893d8e85 100644 --- a/src/dotnet-interactive-vscode/common/tests/unit/utilities.ts +++ b/src/dotnet-interactive-vscode/common/tests/unit/utilities.ts @@ -65,15 +65,15 @@ export function decodeToString(data: Uint8Array): string { } export function decodeNotebookCellOutputs(outputs: vscodeLike.NotebookCellOutput[]): any[] { - const jsonLikeMimes = new Set(); - jsonLikeMimes.add('application/json'); - jsonLikeMimes.add(vscodeLike.ErrorOutputMimeType); + const jsonLikeMimeTypes = new Set(); + jsonLikeMimeTypes.add('application/json'); + jsonLikeMimeTypes.add(vscodeLike.ErrorOutputMimeType); return outputs.map(o => ({ - ...o, outputs: o.outputs.map(oi => { + ...o, items: o.items.map(oi => { const decoded = decodeToString(oi.data); let result = { ...oi, - decodedData: jsonLikeMimes.has(oi.mime) ? JSON.parse(decoded) : decoded, + decodedData: jsonLikeMimeTypes.has(oi.mime) ? JSON.parse(decoded) : decoded, }; delete result.data; return result; diff --git a/src/dotnet-interactive-vscode/common/utilities.ts b/src/dotnet-interactive-vscode/common/utilities.ts index 7ecc854e9b..1d1f331e58 100644 --- a/src/dotnet-interactive-vscode/common/utilities.ts +++ b/src/dotnet-interactive-vscode/common/utilities.ts @@ -68,7 +68,7 @@ export function createOutput(outputItems: Array, outputI const output: NotebookCellOutput = { id: outputId, - outputs: outputItems, + items: outputItems, }; return output; } diff --git a/src/dotnet-interactive-vscode/common/vscode/commands.ts b/src/dotnet-interactive-vscode/common/vscode/commands.ts index 549b10b5d5..495be6dafa 100644 --- a/src/dotnet-interactive-vscode/common/vscode/commands.ts +++ b/src/dotnet-interactive-vscode/common/vscode/commands.ts @@ -131,7 +131,7 @@ export function registerKernelCommands(context: vscode.ExtensionContext, clientM })); context.subscriptions.push(vscode.commands.registerCommand('dotnet-interactive.stopAllNotebookKernels', async () => { - vscode.notebook.notebookDocuments + versionSpecificFunctions.notebookDocuments .filter(document => clientMapper.isDotNetClient(document.uri)) .forEach(async document => await vscode.commands.executeCommand('dotnet-interactive.stopCurrentNotebookKernel', document)); })); diff --git a/src/dotnet-interactive-vscode/common/vscode/extension.ts b/src/dotnet-interactive-vscode/common/vscode/extension.ts index a2c2c5c5e9..54346d4e06 100644 --- a/src/dotnet-interactive-vscode/common/vscode/extension.ts +++ b/src/dotnet-interactive-vscode/common/vscode/extension.ts @@ -171,7 +171,7 @@ export async function activate(context: vscode.ExtensionContext) { registerFileCommands(context, clientMapper); - context.subscriptions.push(vscode.notebook.onDidCloseNotebookDocument(notebookDocument => clientMapper.closeClient(notebookDocument.uri))); + context.subscriptions.push(versionSpecificFunctions.onDidCloseNotebookDocument(notebookDocument => clientMapper.closeClient(notebookDocument.uri))); context.subscriptions.push(vscode.workspace.onDidRenameFiles(e => handleFileRenames(e, clientMapper))); // language registration @@ -205,7 +205,7 @@ async function waitForSdkInstall(requiredSdkVersion: string): Promise { async function updateNotebookCellLanguageInMetadata(candidateNotebookCellDocument: vscode.TextDocument) { const notebook = candidateNotebookCellDocument.notebook; if (notebook && - isJupyterNotebookViewType(notebook.viewType) && + isJupyterNotebookViewType(versionSpecificFunctions.getNotebookType(notebook)) && isDotnetInteractiveLanguage(candidateNotebookCellDocument.languageId)) { const cell = notebook.getCells().find(c => c.document === candidateNotebookCellDocument); if (cell) { diff --git a/src/dotnet-interactive-vscode/common/vscode/vscodeUtilities.ts b/src/dotnet-interactive-vscode/common/vscode/vscodeUtilities.ts index 39a9707889..988e198a9c 100644 --- a/src/dotnet-interactive-vscode/common/vscode/vscodeUtilities.ts +++ b/src/dotnet-interactive-vscode/common/vscode/vscodeUtilities.ts @@ -8,6 +8,7 @@ import { Diagnostic, DiagnosticSeverity, LinePosition, LinePositionSpan, Noteboo import { getSimpleLanguage } from '../interactiveNotebook'; import * as vscodeLike from '../interfaces/vscode-like'; +import * as versionSpecificFunctions from '../../versionSpecificFunctions'; export function isInsidersBuild(): boolean { return vscode.version.indexOf('-insider') >= 0; @@ -88,7 +89,8 @@ export function toNotebookCell(cell: vscode.NotebookCell): NotebookCell { } export function vsCodeCellOutputToContractCellOutput(output: vscode.NotebookCellOutput): NotebookCellOutput { - const errorOutputItems = output.outputs.filter(oi => oi.mime === vscodeLike.ErrorOutputMimeType || oi.metadata?.mimeType === vscodeLike.ErrorOutputMimeType); + const outputItems = versionSpecificFunctions.getCellOutputItems(output); + const errorOutputItems = outputItems.filter(oi => oi.mime === vscodeLike.ErrorOutputMimeType); if (errorOutputItems.length > 0) { // any error-like output takes precedence const errorOutputItem = errorOutputItems[0]; @@ -101,7 +103,7 @@ export function vsCodeCellOutputToContractCellOutput(output: vscode.NotebookCell } else { //otherwise build the mime=>value dictionary const data: { [key: string]: any } = {}; - for (const outputItem of output.outputs) { + for (const outputItem of outputItems) { data[outputItem.mime] = outputItem.data; } diff --git a/src/dotnet-interactive-vscode/insiders/package.json b/src/dotnet-interactive-vscode/insiders/package.json index 4eb7bd77a4..fce7e5556e 100644 --- a/src/dotnet-interactive-vscode/insiders/package.json +++ b/src/dotnet-interactive-vscode/insiders/package.json @@ -62,7 +62,7 @@ "contributes": { "notebooks": [ { - "viewType": "dotnet-interactive", + "type": "dotnet-interactive", "displayName": ".NET Interactive Notebook", "selector": [ { @@ -71,7 +71,7 @@ ] }, { - "viewType": "dotnet-interactive-legacy", + "type": "dotnet-interactive-legacy", "displayName": ".NET Interactive Notebook", "selector": [ { diff --git a/src/dotnet-interactive-vscode/insiders/src/notebookControllers.ts b/src/dotnet-interactive-vscode/insiders/src/notebookControllers.ts index 13dc383eee..e7f5f6db83 100644 --- a/src/dotnet-interactive-vscode/insiders/src/notebookControllers.ts +++ b/src/dotnet-interactive-vscode/insiders/src/notebookControllers.ts @@ -33,7 +33,7 @@ export class DotNetNotebookKernel { const preloads = config.preloadUris.map(uri => new vscode.NotebookRendererScript(uri)); // .dib execution - const dibController = vscode.notebook.createNotebookController( + const dibController = vscode.notebooks.createNotebookController( 'dotnet-interactive', viewType, '.NET Interactive', @@ -43,7 +43,7 @@ export class DotNetNotebookKernel { this.commonControllerInit(dibController); // .dotnet-interactive execution - const legacyController = vscode.notebook.createNotebookController( + const legacyController = vscode.notebooks.createNotebookController( 'dotnet-interactive-legacy', legacyViewType, '.NET Interactive', @@ -53,7 +53,7 @@ export class DotNetNotebookKernel { this.commonControllerInit(legacyController); // .ipynb execution via Jupyter extension (optional) - const jupyterController = vscode.notebook.createNotebookController( + const jupyterController = vscode.notebooks.createNotebookController( 'dotnet-interactive-for-jupyter', jupyterViewType, '.NET Interactive', @@ -67,8 +67,8 @@ export class DotNetNotebookKernel { } }); this.commonControllerInit(jupyterController); - this.disposables.push(vscode.notebook.onDidOpenNotebookDocument(async notebook => { - if (notebook.viewType === jupyterViewType && isDotNetNotebook(notebook)) { + this.disposables.push(vscode.notebooks.onDidOpenNotebookDocument(async notebook => { + if (notebook.notebookType === jupyterViewType && isDotNetNotebook(notebook)) { jupyterController.updateNotebookAffinity(notebook, vscode.NotebookControllerAffinity.Preferred); await selectDotNetInteractiveKernelForJupyter(); await updateNotebookMetadata(notebook, this.config.clientMapper); @@ -119,11 +119,11 @@ export class DotNetNotebookKernel { }); - executionTask.clearOutput(cell.index); + executionTask.clearOutput(cell); const client = await this.config.clientMapper.getOrAddClient(cell.notebook.uri); executionTask.token.onCancellationRequested(() => { const errorOutput = this.config.createErrorOutput("Cell execution cancelled by user"); - const resultPromise = () => updateCellOutputs(executionTask, cell, [...cell.outputs, errorOutput]) + const resultPromise = () => updateCellOutputs(executionTask, [...cell.outputs, errorOutput]) .then(() => endExecution(cell, false)); client.cancel() .then(resultPromise) @@ -131,7 +131,7 @@ export class DotNetNotebookKernel { }); const source = cell.document.getText(); function outputObserver(outputs: Array) { - updateCellOutputs(executionTask!, cell, outputs).then(() => { }); + updateCellOutputs(executionTask!, outputs).then(() => { }); } const diagnosticCollection = diagnostics.getDiagnosticCollection(cell.document.uri); @@ -145,7 +145,7 @@ export class DotNetNotebookKernel { ).catch(() => endExecution(cell, false)); } catch (err) { const errorOutput = this.config.createErrorOutput(`Error executing cell: ${err}`); - await updateCellOutputs(executionTask, cell, [errorOutput]); + await updateCellOutputs(executionTask, [errorOutput]); endExecution(cell, false); throw err; } @@ -193,9 +193,9 @@ export async function updateCellLanguages(document: vscode.NotebookDocument): Pr await vscode.workspace.applyEdit(edit); } -async function updateCellOutputs(executionTask: vscode.NotebookCellExecution, cell: vscode.NotebookCell, outputs: Array): Promise { - const reshapedOutputs = outputs.map(o => new vscode.NotebookCellOutput(o.outputs.map(oi => generateVsCodeNotebookCellOutputItem(oi.data, oi.mime)))); - await executionTask.replaceOutput(reshapedOutputs, cell.index); +async function updateCellOutputs(executionTask: vscode.NotebookCellExecution, outputs: Array): Promise { + const reshapedOutputs = outputs.map(o => new vscode.NotebookCellOutput(o.items.map(oi => generateVsCodeNotebookCellOutputItem(oi.data, oi.mime)))); + await executionTask.replaceOutput(reshapedOutputs); } export function endExecution(cell: vscode.NotebookCell, success: boolean) { diff --git a/src/dotnet-interactive-vscode/insiders/src/notebookSerializers.ts b/src/dotnet-interactive-vscode/insiders/src/notebookSerializers.ts index 522184bfba..df61b494ec 100644 --- a/src/dotnet-interactive-vscode/insiders/src/notebookSerializers.ts +++ b/src/dotnet-interactive-vscode/insiders/src/notebookSerializers.ts @@ -46,7 +46,6 @@ abstract class DotNetNotebookSerializer implements vscode.NotebookSerializer { } const notebookData: vscode.NotebookData = { - metadata: new vscode.NotebookDocumentMetadata().with({ cellHasExecutionOrder: false }), cells: notebookCells.map(toVsCodeNotebookCellData) }; return notebookData; @@ -86,7 +85,7 @@ export class DotNetDibNotebookSerializer extends DotNetNotebookSerializer { static registerNotebookSerializer(context: vscode.ExtensionContext, notebookType: string, clientMapper: ClientMapper, outputChannel: OutputChannelAdapter) { const serializer = new DotNetDibNotebookSerializer(clientMapper, outputChannel); - const notebookSerializer = vscode.notebook.registerNotebookSerializer(notebookType, serializer); + const notebookSerializer = vscode.notebooks.registerNotebookSerializer(notebookType, serializer); context.subscriptions.push(notebookSerializer); } } @@ -98,7 +97,7 @@ export class DotNetLegacyNotebookSerializer extends DotNetNotebookSerializer { static registerNotebookSerializer(context: vscode.ExtensionContext, notebookType: string, clientMapper: ClientMapper, outputChannel: OutputChannelAdapter) { const serializer = new DotNetLegacyNotebookSerializer(clientMapper, outputChannel); - const notebookSerializer = vscode.notebook.registerNotebookSerializer(notebookType, serializer); + const notebookSerializer = vscode.notebooks.registerNotebookSerializer(notebookType, serializer); context.subscriptions.push(notebookSerializer); } } diff --git a/src/dotnet-interactive-vscode/insiders/src/versionSpecificFunctions.ts b/src/dotnet-interactive-vscode/insiders/src/versionSpecificFunctions.ts index 7652f34361..6d8f29b58f 100644 --- a/src/dotnet-interactive-vscode/insiders/src/versionSpecificFunctions.ts +++ b/src/dotnet-interactive-vscode/insiders/src/versionSpecificFunctions.ts @@ -32,6 +32,18 @@ export function endExecution(cell: vscode.NotebookCell, success: boolean) { notebookControllers.endExecution(cell, success); } +export function getCellOutputItems(cellOutput: vscode.NotebookCellOutput): vscode.NotebookCellOutputItem[] { + return cellOutput.items; +} + +export function getNotebookType(notebook: vscode.NotebookDocument): string { + return notebook.notebookType; +} + +export const onDidCloseNotebookDocument: vscode.Event = vscode.notebooks.onDidCloseNotebookDocument; + +export const notebookDocuments: ReadonlyArray = vscode.notebooks.notebookDocuments; + export function createErrorOutput(message: string, outputId?: string): vscodeLike.NotebookCellOutput { const error = { name: 'Error', message }; const errorItem = vscode.NotebookCellOutputItem.error(error); @@ -54,7 +66,7 @@ export async function createNewBlankNotebook(extension: string, _openNotebook: ( } const ipynbLanguageName = ipynbUtilities.mapIpynbLanguageName(notebookLanguage); - const cellMetadata = new vscode.NotebookCellMetadata().with({ + const cellMetadata = { custom: { metadata: { dotnet_interactive: { @@ -62,9 +74,9 @@ export async function createNewBlankNotebook(extension: string, _openNotebook: ( } } } - }); + }; const cell = new vscode.NotebookCellData(vscode.NotebookCellKind.Code, '', `dotnet-interactive.${ipynbLanguageName}`, undefined, cellMetadata); - const documentMetadata = new vscode.NotebookDocumentMetadata().with({ + const documentMetadata = { custom: { metadata: { kernelspec: { @@ -77,9 +89,10 @@ export async function createNewBlankNotebook(extension: string, _openNotebook: ( } } } - }); - const content = new vscode.NotebookData([cell], documentMetadata); - const notebook = await vscode.notebook.openNotebookDocument(viewType, content); + }; + const content = new vscode.NotebookData([cell]); + content.metadata = documentMetadata; + const notebook = await vscode.notebooks.openNotebookDocument(viewType, content); const _editor = await vscode.window.showNotebookDocument(notebook); } @@ -107,7 +120,7 @@ export async function openNotebookFromUrl(notebookUrl: string, clientMapper: Cli const content = new Uint8Array(arrayBuffer); const cancellationTokenSource = new vscode.CancellationTokenSource(); const notebookData = await serializer.deserializeNotebook(content, cancellationTokenSource.token); - const notebook = await vscode.notebook.openNotebookDocument(viewType, notebookData); + const notebook = await vscode.notebooks.openNotebookDocument(viewType, notebookData); const _editor = await vscode.window.showNotebookDocument(notebook); } catch (e) { vscode.window.showWarningMessage(`Unable to read notebook from '${notebookUrl}': ${e}`); diff --git a/src/dotnet-interactive-vscode/insiders/src/vscode.d.ts b/src/dotnet-interactive-vscode/insiders/src/vscode.d.ts index e8fb80375d..15932e8120 100644 --- a/src/dotnet-interactive-vscode/insiders/src/vscode.d.ts +++ b/src/dotnet-interactive-vscode/insiders/src/vscode.d.ts @@ -5653,7 +5653,7 @@ declare module 'vscode' { command: string | Command | undefined; /** - * Accessibility information used when screen reader interacts with this StatusBar item + * Accessibility information used when a screen reader interacts with this StatusBar item */ accessibilityInformation?: AccessibilityInformation; @@ -9857,7 +9857,7 @@ declare module 'vscode' { readonly onDidTriggerButton: Event; /** - * Items to pick from. + * Items to pick from. This can be read and updated by the extension. */ items: readonly T[]; @@ -11292,6 +11292,939 @@ declare module 'vscode' { } + /** + * A notebook cell kind. + */ + export enum NotebookCellKind { + + /** + * A markup-cell is formatted source that is used for display. + */ + Markup = 1, + + /** + * A code-cell is source that can be {@link NotebookController executed} and that + * produces {@link NotebookCellOutput output}. + */ + Code = 2 + } + + /** + * Represents a cell of a {@link NotebookDocument notebook}, either a {@link NotebookCellKind.Code code}-cell + * or {@link NotebookCellKind.Markup markup}-cell. + * + * NotebookCell instances are immutable and are kept in sync for as long as they are part of their notebook. + */ + export interface NotebookCell { + + /** + * The index of this cell in its {@link NotebookDocument.cellAt containing notebook}. The + * index is updated when a cell is moved within its notebook. The index is `-1` + * when the cell has been removed from its notebook. + */ + readonly index: number; + + /** + * The {@link NotebookDocument notebook} that contains this cell. + */ + readonly notebook: NotebookDocument; + + /** + * The kind of this cell. + */ + readonly kind: NotebookCellKind; + + /** + * The {@link TextDocument text} of this cell, represented as text document. + */ + readonly document: TextDocument; + + /** + * The metadata of this cell. Can be anything but must be JSON-stringifyable. + */ + readonly metadata: { [key: string]: any } + + /** + * The outputs of this cell. + */ + readonly outputs: readonly NotebookCellOutput[]; + + /** + * The most recent {@link NotebookCellExecutionSummary excution summary} for this cell. + */ + readonly executionSummary?: NotebookCellExecutionSummary; + } + + /** + * Represents a notebook which itself is a sequence of {@link NotebookCell code or markup cells}. Notebook documents are + * created from {@link NotebookData notebook data}. + */ + 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 {@link FileSystemProvider} + */ + readonly uri: Uri; + + /** @deprecated */ + // todo@API remove + readonly viewType: string; + + /** + * The type of notebook. + */ + readonly notebookType: string; + + /** + * The version number of this notebook (it will strictly increase after each + * change, including undo/redo). + */ + readonly version: number; + + /** + * `true` if there are unpersisted changes. + */ + readonly isDirty: boolean; + + /** + * Is this notebook representing an untitled file which has not been saved yet. + */ + readonly isUntitled: boolean; + + /** + * `true` if the notebook has been closed. A closed notebook isn't synchronized anymore + * and won't be re-used when the same resource is opened again. + */ + readonly isClosed: boolean; + + /** + * Arbitrary metadata for this notebook. Can be anything but must be JSON-stringifyable. + */ + readonly metadata: { [key: string]: any }; + + /** + * The number of cells in the notebook. + */ + readonly cellCount: number; + + /** + * Return the cell at the specified index. The index will be adjusted to the notebook. + * + * @param index - The index of the cell to retrieve. + * @return A {@link NotebookCell cell}. + */ + cellAt(index: number): NotebookCell; + + /** + * Get the cells of this notebook. A subset can be retrieved by providing + * a range. The range will be adjuset to the notebook. + * + * @param range A notebook range. + * @returns The cells contained by the range or all cells. + */ + getCells(range?: NotebookRange): NotebookCell[]; + + /** + * Save the document. The saving will be handled by the corresponding {@link NotebookSerializer serializer}. + * + * @return A promise that will resolve to true when the document + * has been saved. Will return false if the file was not dirty or when save failed. + */ + save(): Thenable; + } + + /** + * The summary of a notebook cell execution. + */ + export interface NotebookCellExecutionSummary { + + /** + * The order in which the execution happened. + */ + readonly executionOrder?: number; + + /** + * If the exclusive finished successfully. + */ + readonly success?: boolean; + + /** + * The unix timestamp at which execution started. + */ + // @rob + //todo@API think about invalid state (no end, but start and vice versa) + readonly startTime?: number; + + /** + * The unix timestamp at which execution ended. + */ + readonly endTime?: number; + } + + /** + * A notebook range represents an ordered pair of two cell indicies. + * It is guaranteed that start is less than or equal to end. + */ + export class NotebookRange { + + /** + * The zero-based start index of this range. + */ + readonly start: number; + + /** + * The exclusive end index of this range (zero-based). + */ + readonly end: number; + + /** + * `true` if `start` and `end` are equal. + */ + 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); + + /** + * 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; + } + + /** + * One representation of a {@link NotebookCellOutput notebook output}, defined by MIME type and data. + */ + export class NotebookCellOutputItem { + + /** + * Factory function to create a `NotebookCellOutputItem` from a string. + * + * *Note* that an UTF-8 encoder is used to create bytes for the string. + * + * @param value A string. + * @param mime Optional MIME type, defaults to `text/plain`. + * @returns A new output item object. + */ + static text(value: string, mime?: string): NotebookCellOutputItem; + + /** + * Factory function to create a `NotebookCellOutputItem` from + * a JSON object. + * + * *Note* that this function is not expecting "stringified JSON" but + * an object that can be stringified. This function will throw an error + * when the passed value cannot be JSON-stringified. + * + * @param value A JSON-stringifyable value. + * @param mime Optional MIME type, defaults to `application/json` + * @returns A new output item object. + */ + static json(value: any, mime?: string): NotebookCellOutputItem; + + /** + * Factory function to create a `NotebookCellOutputItem` that uses + * uses the `application/vnd.code.notebook.stdout` mime type. + * + * @param value A string. + * @returns A new output item object. + */ + static stdout(value: string): NotebookCellOutputItem; + + /** + * Factory function to create a `NotebookCellOutputItem` that uses + * uses the `application/vnd.code.notebook.stderr` mime type. + * + * @param value A string. + * @returns A new output item object. + */ + static stderr(value: string): NotebookCellOutputItem; + + /** + * Factory function to create a `NotebookCellOutputItem` that uses + * uses the `application/vnd.code.notebook.error` mime type. + * + * @param value An error object. + * @returns A new output item object. + */ + static error(value: Error): NotebookCellOutputItem; + + /** + * The mime type which determines how the {@link NotebookCellOutputItem.value `value`}-property + * is interpreted. + * + * Notebooks have built-in support for certain mime-types, extensions can add support for new + * types and override existing types. + */ + mime: string; + + /** + * The data of this output item. Must always be an array of unsigned 8-bit integers. + */ + data: Uint8Array; + + /** + * Create a new notbook cell output item. + * + * @param data The value of the output item. + * @param mime The mime type of the output item. + */ + constructor(data: Uint8Array, mime: string); + } + + /** + * Notebook cell output represents a result of executing a cell. It is a container type for multiple + * {@link NotebookCellOutputItem output items} where contained items represent the same result but + * use different MIME types. + */ + //todo@API - add sugar function to add more outputs + export class NotebookCellOutput { + + /** + * Identifier for this output. Using the identifier allows a subsequent execution to modify + * existing output. Defaults to a fresh UUID. + */ + id: string; + + /** + * The output items of this output. Each item must represent the same result. _Note_ that repeated + * MIME types per output is invalid and that the editor will just pick one of them. + * + * ```ts + * new vscode.NotebookCellOutput([ + * vscode.NotebookCellOutputItem.text('Hello', 'text/plain'), + * vscode.NotebookCellOutputItem.text('Hello', 'text/html'), + * vscode.NotebookCellOutputItem.text('_Hello_', 'text/markdown'), + * vscode.NotebookCellOutputItem.text('Hey', 'text/plain'), // INVALID: repeated type, editor will pick just one + * ]) + * ``` + */ + items: NotebookCellOutputItem[]; + + /** + * Arbitrary metadata for this cell output. Can be anything but must be JSON-stringifyable. + */ + metadata?: { [key: string]: any }; + + /** + * Create new notebook output. + * + * @param outputs Notebook output items. + * @param metadata Optional metadata. + */ + constructor(outputs: NotebookCellOutputItem[], metadata?: { [key: string]: any }); + + /** + * Create new notebook output. + * + * @param items Notebook output items. + * @param id Identifier of this output. + * @param metadata Optional metadata. + */ + //todo@API id-args is not used by jupyter but we it added with display_id in mind... + // @jupyter check if needed + constructor(items: NotebookCellOutputItem[], id: string, metadata?: { [key: string]: any }); + } + + /** + * NotebookCellData is the raw representation of notebook cells. Its is part of {@link NotebookData `NotebookData`}. + */ + export class NotebookCellData { + + /** + * The {@link NotebookCellKind kind} of this cell data. + */ + kind: NotebookCellKind; + + /** + * The source value of this cell data - either source code or formatted text. + */ + value: string; + + /** + * The language identifier of the source value of this cell data. Any value from + * {@link languages.getLanguages `getLanguages`} is possible. + */ + languageId: string; + + /** + * The outputs of this cell data. + */ + outputs?: NotebookCellOutput[]; + + /** + * Arbitrary metadata of this cell data. Can be anything but must be JSON-stringifyable. + */ + metadata?: { [key: string]: any }; + + /** + * The execution summary of this cell data. + */ + executionSummary?: NotebookCellExecutionSummary; + + /** + * Create new cell data. Minimal cell data specifies its kind, its source value, and the + * language identifier of its source. + * + * @param kind The kind. + * @param value The source value. + * @param languageId The language identifier of the source value. + * @param outputs Optional outputs. + * @param metadata Optional metadata. + * @param executionSummary Optional execution summary. + */ + // todo@API should ctors only have the args for required properties? + constructor(kind: NotebookCellKind, value: string, languageId: string, outputs?: NotebookCellOutput[], metadata?: { [key: string]: any }, executionSummary?: NotebookCellExecutionSummary); + } + + /** + * NotebookData is the raw representation of notebooks. + * + * Extensions are responsible to create {@link NotebookData `NotebookData`} so that the editor + * can create a {@link NotebookDocument `NotebookDocument`}. + * + * @see {@link NotebookSerializer} + */ + export class NotebookData { + /** + * The cell data of this notebook data. + */ + cells: NotebookCellData[]; + + /** + * Arbitrary metadata of notebook data. + */ + metadata?: { [key: string]: any }; + + /** + * Create new notebook data. + * + * @param cells An array of cell data. + */ + constructor(cells: NotebookCellData[]); + } + + /** + * The notebook serializer enables the editor to open notebook files. + * + * At its core the editor only knows a {@link NotebookData notebook data structure} but not + * how that data structure is written to a file, nor how it is read from a file. The + * notebook serializer bridges this gap by deserializing bytes into notebook data and + * vice versa. + */ + export interface NotebookSerializer { + + /** + * Deserialize contents of a notebook file into the notebook data structure. + * + * @param content Contents of a notebook file. + * @param token A cancellation token. + * @return Notebook data or a thenable that resolves to such. + */ + deserializeNotebook(content: Uint8Array, token: CancellationToken): NotebookData | Thenable; + + /** + * Serialize notebook data into file contents. + * + * @param data A notebook data structure. + * @param token A cancellation token. + * @returns An array of bytes or a thenable that resolves to such. + */ + serializeNotebook(data: NotebookData, token: CancellationToken): Uint8Array | Thenable; + } + + /** + * Notebook content options define what parts of a notebook are persisted. Note + * + * For instance, a notebook serializer can opt-out of saving outputs and in that case the editor doesn't mark a + * notebooks as {@link NotebookDocument.isDirty dirty} when its output has changed. + */ + export interface NotebookDocumentContentOptions { + /** + * Controls if outputs 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 the outputs in the file document, this should be set to true. + */ + transientOutputs?: 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?: { [key: string]: boolean | undefined }; + + /** + * 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?: { [key: string]: boolean | undefined }; + } + + /** + * A callback that is invoked by the editor whenever cell execution has been triggered. + */ + //todo@API inline? + export interface NotebookExecuteHandler { + /** + * @param cells The notebook cells to execute. + * @param notebook The notebook for which the execute handler is being called. + * @param controller The controller that the handler is attached to + */ + (cells: NotebookCell[], notebook: NotebookDocument, controller: NotebookController): void | Thenable + } + + /** + * Notebook controller affinity for notebook documents. + * + * @see {@link NotebookController.updateNotebookAffinity} + */ + export enum NotebookControllerAffinity { + /** + * Default affinity. + */ + Default = 1, + /** + * A controller is preferred for a notebook. + */ + Preferred = 2 + } + + /** + * A notebook controller represents an entity that can execute notebook cells. This is often referred to as a kernel. + * + * There can be multiple controllers and the editor will let users choose which controller to use for a certain notebook. The + * {@link NotebookController.notebookType `notebookType`}-property defines for what kind of notebooks a controller is for and + * the {@link NotebookController.updateNotebookAffinity `updateNotebookAffinity`}-function allows controllers to set a preference + * for specific notebook documents. + * + * When a cell is being run the editor will invoke the {@link NotebookController.executeHandler `executeHandler`} and a controller + * is expected to create and finalize a {@link NotebookCellExecution notebook cell execution}. However, controllers are also free + * to create executions by themselves. + */ + export interface NotebookController { + + /** + * The identifier of this notebook controller. + * + * _Note_ that controllers are remembered by their identifier and that extensions should use + * stable identifiers across sessions. + */ + readonly id: string; + + // todo@api remove + /** @deprecated */ + readonly viewType: string; + + /** + * The notebook type this controller is for. + */ + readonly notebookType: string; + + /** + * An array of language identifiers that are supported by this + * controller. Any language identifier from {@link languages.getLanguages `getLanguages`} + * is possible. When falsy all languages are supported. + * + * Samples: + * ```js + * // support JavaScript and TypeScript + * myController.supportedLanguages = ['javascript', 'typescript'] + * + * // support all languages + * myController.supportedLanguages = undefined; // falsy + * myController.supportedLanguages = []; // falsy + * ``` + */ + supportedLanguages?: string[]; + + /** + * The human-readable label of this notebook controller. + */ + label: string; + + /** + * The human-readable description which is rendered less prominent. + */ + description?: string; + + /** + * The human-readable detail which is rendered less prominent. + */ + detail?: string; + + /** + * Whether this controller supports execution order so that the + * editor can render placeholders for them. + */ + supportsExecutionOrder?: boolean; + + // todo@API remove + /** @deprecated */ + hasExecutionOrder?: boolean; + + /** + * Create a cell execution task. + * + * _Note_ that there can only be one execution per cell at a time and that an error is thrown if + * a cell execution is created while another is still active. + * + * This should be used in response to the {@link NotebookController.executeHandler execution handler} + * being called or when cell execution has been started else, e.g when a cell was already + * executing or when cell execution was triggered from another source. + * + * @param cell The notebook cell for which to create the execution. + * @returns A notebook cell execution. + */ + createNotebookCellExecution(cell: NotebookCell): NotebookCellExecution; + + /** + * The execute handler is invoked when the run gestures in the UI are selected, e.g Run Cell, Run All, + * Run Selection etc. The execute handler is responsible for creating and managing {@link NotebookCellExecution execution}-objects. + */ + executeHandler: NotebookExecuteHandler; + + /** + * Optional interrupt handler. + * + * By default cell execution is canceled via {@link NotebookCellExecution.token tokens}. Cancellation + * tokens require that a controller can keep track of its execution so that it can cancel a specific execution at a later + * point. Not all scenarios allow for that, eg. REPL-style controllers often work by interrupting whatever is currently + * running. For those cases the interrupt handler exists - it can be thought of as the equivalent of `SIGINT` + * or `Control+C` in terminals. + * + * _Note_ that supporting {@link NotebookCellExecution.token cancellation tokens} is preferred and that interrupt handlers should + * only be used when tokens cannot be supported. + */ + interruptHandler?: (notebook: NotebookDocument) => void | Thenable; + + /** + * An event that fires whenever a controller has been selected for a notebook document. Selecting a controller + * for a notebook is a user gesture and happens either explicitly or implicitly when interacting while a + * controller was suggested. + */ + //todo@api selected vs associated, jsdoc + readonly onDidChangeNotebookAssociation: Event<{ notebook: NotebookDocument, selected: boolean }>; + + /** + * A controller can set affinities for specific notebook documents. This allows a controller + * to be presented more prominent for some notebooks. + * + * @param notebook The notebook for which a priority is set. + * @param affinity A controller affinity + */ + updateNotebookAffinity(notebook: NotebookDocument, affinity: NotebookControllerAffinity): void; + + /** + * Dispose and free associated resources. + */ + dispose(): void; + } + + // todo@api jsdoc + // todo@api Inline unless we can come up with more (future) properties + export interface NotebookCellExecuteStartContext { + /** + * The time that execution began, in milliseconds in the Unix epoch. Used to drive the clock + * that shows for how long a cell has been running. If not given, the clock won't be shown. + */ + startTime?: number; + } + + // todo@api jsdoc + // todo@api Inline unless we can come up with more (future) properties + export interface NotebookCellExecuteEndContext { + /** + * If true, a green check is shown on the cell status bar. + * If false, a red X is shown. + * If undefined, no check or X icon is shown. + */ + success?: boolean; + + /** + * The time that execution finished, in milliseconds in the Unix epoch. + */ + endTime?: number; + } + + /** + * A NotebookCellExecution is how {@link NotebookController notebook controller} modify a notebook cell as + * it is executing. + * + * When a cell execution object is created, the cell enters the {@link NotebookCellExecutionState.Pending `Pending`} state. + * When {@link NotebookCellExecution.start `start(...)`} is called on the execution task, it enters the {@link NotebookCellExecutionState.Executing `Executing`} state. When + * {@link NotebookCellExecution.end `end(...)`} is called, it enters the {@link NotebookCellExecutionState.Idle `Idle`} state. + */ + export interface NotebookCellExecution { + + /** + * The {@link NotebookCell cell} for which this execution has been created. + */ + readonly cell: NotebookCell; + + /** + * A cancellation token which will be triggered when the cell execution is canceled + * from the UI. + * + * _Note_ that the cancellation token will not be triggered when the {@link NotebookController controller} + * that created this execution uses an {@link NotebookController.interruptHandler interrupt-handler}. + */ + readonly token: CancellationToken; + + /** + * Set and unset the order of this cell execution. + */ + executionOrder: number | undefined; + + // todo@API inline context object? + // @rob inline as arguments + start(context?: NotebookCellExecuteStartContext): void; + + // todo@API inline context object? + // @rob inline as arguments + end(result?: NotebookCellExecuteEndContext): void; + + /** + * Clears the output of the cell that is executing or of another cell that is affected by this execution. + * + * @param cell Cell for which output is cleared. Defaults to the {@link NotebookCellExecution.cell cell} of + * this execution. + * @return A thenable that resolves when the operation finished. + */ + clearOutput(cell?: NotebookCell): Thenable; + + /** + * Replace the output of the cell that is executing or of another cell that is affected by this execution. + * + * @param out Output that replaces the current output. + * @param cell Cell for which output is cleared. Defaults to the {@link NotebookCellExecution.cell cell} of + * this execution. + * @return A thenable that resolves when the operation finished. + */ + replaceOutput(out: NotebookCellOutput | NotebookCellOutput[], cell?: NotebookCell): Thenable; + + /** + * Append to the output of the cell that is executing or to another cell that is affected by this execution. + * + * @param out Output that is appended to the current output. + * @param cell Cell for which output is cleared. Defaults to the {@link NotebookCellExecution.cell cell} of + * this execution. + * @return A thenable that resolves when the operation finished. + */ + appendOutput(out: NotebookCellOutput | NotebookCellOutput[], cell?: NotebookCell): Thenable; + + /** + * Replace all output items of existing cell output. + * + * @param items Output items that replace the items of existing output. + * @param output Output object or the identifier of one. + * @return A thenable that resolves when the operation finished. + */ + replaceOutputItems(items: NotebookCellOutputItem | NotebookCellOutputItem[], output: NotebookCellOutput | string): Thenable; + + /** + * Append output items to existing cell output. + * + * @param items Output items that are append to existing output. + * @param output Output object or the identifier of one. + * @return A thenable that resolves when the operation finished. + */ + appendOutputItems(items: NotebookCellOutputItem | NotebookCellOutputItem[], output: NotebookCellOutput | string): Thenable; + } + + /** + * Represents the alignment of status bar items. + */ + export enum NotebookCellStatusBarAlignment { + + /** + * Aligned to the left side. + */ + Left = 1, + + /** + * Aligned to the right side. + */ + Right = 2 + } + + /** + * A contribution to a cell's status bar + */ + export class NotebookCellStatusBarItem { + /** + * The text to show for the item. + */ + text: string; + + /** + * Whether the item is aligned to the left or right. + */ + alignment: NotebookCellStatusBarAlignment; + + /** + * An optional {@link Command `Command`} or identifier of a command to run on click. + * + * The command must be {@link commands.getCommands known}. + * + * Note that if this is a {@link Command `Command`} object, only the {@link Command.command `command`} and {@link Command.arguments `arguments`} + * are used by VS Code. + */ + command?: string | Command; + + /** + * A tooltip to show when the item is hovered. + */ + tooltip?: string; + + /** + * The priority of the item. A higher value item will be shown more to the left. + */ + priority?: number; + + /** + * Accessibility information used when a screen reader interacts with this item. + */ + accessibilityInformation?: AccessibilityInformation; + + /** + * Creates a new NotebookCellStatusBarItem. + */ + // @rob + // todo@API jsdoc for args + // todo@API should ctors only have the args for required properties? + constructor(text: string, alignment: NotebookCellStatusBarAlignment, command?: string | Command, tooltip?: string, priority?: number, accessibilityInformation?: AccessibilityInformation); + } + + /** + * A provider that can contribute items to the status bar that appears below a cell's editor. + */ + export interface NotebookCellStatusBarItemProvider { + /** + * An optional event to signal that statusbar items have changed. The provide method will be called again. + */ + onDidChangeCellStatusBarItems?: Event; + + /** + * 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. + * @param cell The cell for which to return items. + * @param token A token triggered if this request should be cancelled. + */ + // @rob + //todo@API jsdoc for return-type + //todo@API should this return T | T[] + provideCellStatusBarItems(cell: NotebookCell, token: CancellationToken): ProviderResult; + } + + /** + * Namespace for notebooks. + * + * The notebooks functionality is composed of three loosly coupled components: + * + * 1. {@link NotebookSerializer} enable the editor to open, show, and save notebooks + * 2. {@link NotebookController} own the execution of notebooks, e.g they create output from code cells. + * 3. NotebookRenderer present notebook output in the editor. They run in a separate context. + */ + // todo@api what should be in this namespace? should notebookDocuments and friends be in the workspace namespace? + export namespace notebooks { + + /** + * All notebook documents currently known to the editor. + */ + // todo@api move to workspace + export const notebookDocuments: readonly NotebookDocument[]; + + /** + * Open a notebook. Will return early if this notebook is already {@link notebook.notebookDocuments loaded}. Otherwise + * the notebook is loaded and the {@link notebook.onDidOpenNotebookDocument `onDidOpenNotebookDocument`}-event fires. + * + * *Note* that the lifecycle of the returned notebook is owned by the editor and not by the extension. That means an + * {@link notebook.onDidCloseNotebookDocument `onDidCloseNotebookDocument`}-event can occur at any time after. + * + * *Note* that opening a notebook does not show a notebook editor. This function only returns a notebook document which + * can be showns in a notebook editor but it can also be used for other things. + * + * @param uri The resource to open. + * @returns A promise that resolves to a {@link NotebookDocument notebook} + */ + // todo@api move to workspace + export function openNotebookDocument(uri: Uri): Thenable; + + /** + * Open an untitled notebook. The editor will prompt the user for a file + * path when the document is to be saved. + * + * @see {@link openNotebookDocument} + * @param notebookType The notebook type that should be used. + * @param content The initial contents of the notebook. + * @returns A promise that resolves to a {@link NotebookDocument notebook}. + */ + // todo@api move to workspace + export function openNotebookDocument(notebookType: string, content?: NotebookData): Thenable; + + /** + * An event that is emitted when a {@link NotebookDocument notebook} is opened. + */ + // todo@api move to workspace + export const onDidOpenNotebookDocument: Event; + + /** + * An event that is emitted when a {@link NotebookDocument notebook} is disposed. + * + * *Note 1:* There is no guarantee that this event fires when an editor tab is closed. + * + * *Note 2:* A notebook can be open but not shown in an editor which means this event can fire + * for a notebook that has not been shown in an editor. + */ + // todo@api move to workspace + export const onDidCloseNotebookDocument: Event; + + /** + * Register a {@link NotebookSerializer notebook serializer}. + * + * A notebook serializer must to be contributed through the `notebooks` extension point. When opening a notebook file, the editor will send + * the `onNotebook:` activation event, and extensions must register their serializer in return. + * + * @param notebookType A notebook. + * @param serializer A notebook serialzier. + * @param options Optional context options that define what parts of a notebook should be persisted + * @return A {@link Disposable} that unregisters this serializer when being disposed. + */ + // todo@api move to workspace + export function registerNotebookSerializer(notebookType: string, serializer: NotebookSerializer, options?: NotebookDocumentContentOptions): Disposable; + + /** + * Creates a new notebook controller. + * + * @param id Identifier of the controller. Must be unique per extension. + * @param notebookType A notebook type for which this controller is for. + * @param label The label of the controller. + * @param handler The execute-handler of the controller. + */ + export function createNotebookController(id: string, notebookType: string, label: string, handler?: NotebookExecuteHandler): NotebookController; + + /** + * Register a {@link NotebookCellStatusBarItemProvider cell statusbar item provider} for the given notebook type. + * + * @param notebookType The notebook type to register for. + * @param provider A cell status bar provider. + * @return A {@link Disposable} that unregisters this provider when being disposed. + */ + export function registerNotebookCellStatusBarItemProvider(notebookType: string, provider: NotebookCellStatusBarItemProvider): Disposable; + } + /** * Represents the input box in the Source Control viewlet. */ diff --git a/src/dotnet-interactive-vscode/insiders/src/vscode.proposed.d.ts b/src/dotnet-interactive-vscode/insiders/src/vscode.proposed.d.ts index b1f98b5624..44e8a41af8 100644 --- a/src/dotnet-interactive-vscode/insiders/src/vscode.proposed.d.ts +++ b/src/dotnet-interactive-vscode/insiders/src/vscode.proposed.d.ts @@ -904,972 +904,175 @@ declare module 'vscode' { /** * The icon path or {@link ThemeIcon} for the terminal. */ - readonly iconPath?: Uri | { light: Uri; dark: Uri } | { id: string, color?: { id: string } }; + readonly iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; } export interface ExtensionTerminalOptions { /** * A themeIcon, Uri, or light and dark Uris to use as the terminal tab icon */ - readonly iconPath?: Uri | { light: Uri; dark: Uri } | { id: string, color?: { id: string } }; + readonly iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; } //#endregion - // eslint-disable-next-line vscode-dts-region-comments - //#region @jrieken -> exclusive document filters - - export interface DocumentFilter { - readonly exclusive?: boolean; - } - - //#endregion - - //#region Tree View: https://github.com/microsoft/vscode/issues/61313 @alexr00 - export interface TreeView extends Disposable { - reveal(element: T | undefined, options?: { select?: boolean, focus?: boolean, expand?: boolean | number; }): Thenable; - } - //#endregion - - //#region Custom Tree View Drag and Drop https://github.com/microsoft/vscode/issues/32592 - export interface TreeViewOptions { - dragAndDropController?: DragAndDropController; - } - - export interface DragAndDropController extends Disposable { - /** - * Extensions should fire `TreeDataProvider.onDidChangeTreeData` for any elements that need to be refreshed. - * - * @param source - * @param target - */ - onDrop(source: T[], target: T): Thenable; - } - //#endregion - - //#region Task presentation group: https://github.com/microsoft/vscode/issues/47265 - export interface TaskPresentationOptions { - /** - * Controls whether the task is executed in a specific terminal group using split panes. - */ - group?: string; - } - //#endregion - - //#region Custom editor move https://github.com/microsoft/vscode/issues/86146 - - // TODO: Also for custom editor - - export interface CustomTextEditorProvider { - - /** - * Handle when the underlying resource for a custom editor is renamed. - * - * This allows the webview for the editor be preserved throughout the rename. If this method is not implemented, - * VS Code will destory the previous custom editor and create a replacement one. - * - * @param newDocument New text document to use for the custom editor. - * @param existingWebviewPanel Webview panel for the custom editor. - * @param token A cancellation token that indicates the result is no longer needed. - * - * @return Thenable indicating that the webview editor has been moved. - */ - // eslint-disable-next-line vscode-dts-provider-naming - moveCustomTextEditor?(newDocument: TextDocument, existingWebviewPanel: WebviewPanel, token: CancellationToken): Thenable; - } - - //#endregion - - //#region allow QuickPicks to skip sorting: https://github.com/microsoft/vscode/issues/73904 - - export interface QuickPick extends QuickInput { - /** - * An optional flag to sort the final results by index of first query match in label. Defaults to true. - */ - sortByLabel: boolean; - } - - //#endregion - - //#region https://github.com/microsoft/vscode/issues/122922, Notebook, Finalization 1 - - /** - * A notebook cell kind. - */ - export enum NotebookCellKind { - - /** - * A markup-cell is formatted source that is used for display. - */ - Markup = 1, - - /** - * A code-cell is source that can be {@link NotebookController executed} and that - * produces {@link NotebookCellOutput output}. - */ - Code = 2 - } - - /** - * Represents a cell of a {@link NotebookDocument notebook}, either a {@link NotebookCellKind.Code code}-cell - * or {@link NotebookCellKind.Markup markup}-cell. - * - * NotebookCell instances are immutable and are kept in sync for as long as they are part of their notebook. - */ - export interface NotebookCell { - - /** - * The index of this cell in its {@link NotebookDocument.cellAt containing notebook}. The - * index is updated when a cell is moved within its notebook. The index is `-1` - * when the cell has been removed from its notebook. - */ - readonly index: number; - - /** - * The {@link NotebookDocument notebook} that contains this cell. - */ - readonly notebook: NotebookDocument; - - /** - * The kind of this cell. - */ - readonly kind: NotebookCellKind; - - /** - * The {@link TextDocument text} of this cell, represented as text document. - */ - readonly document: TextDocument; - - /** - * The metadata of this cell. - */ - readonly metadata: NotebookCellMetadata - - /** - * The outputs of this cell. - */ - readonly outputs: ReadonlyArray; - - /** - * The most recent {@link NotebookCellExecutionSummary excution summary} for this cell. - */ - readonly executionSummary?: NotebookCellExecutionSummary; - } - - /** - * Represents a notebook which itself is a sequence of {@link NotebookCell code or markup cells}. Notebook documents are - * created from {@link NotebookData notebook data}. - */ - 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 {@link FileSystemProvider} - * @see {@link TextDocumentContentProvider} - */ - readonly uri: Uri; - - // todo@API should we really expose this? - // todo@API should this be called `notebookType` or `notebookKind` - readonly viewType: string; - - /** - * The version number of this notebook (it will strictly increase after each - * change, including undo/redo). - */ - readonly version: number; - - /** - * `true` if there are unpersisted changes. - */ - readonly isDirty: boolean; - - /** - * Is this notebook representing an untitled file which has not been saved yet. - */ - readonly isUntitled: boolean; - - /** - * `true` if the notebook has been closed. A closed notebook isn't synchronized anymore - * and won't be re-used when the same resource is opened again. - */ - readonly isClosed: boolean; - - /** - * The {@link NotebookDocumentMetadata metadata} for this notebook. - */ - readonly metadata: NotebookDocumentMetadata; - - /** - * The number of cells in the notebook. - */ - readonly cellCount: number; - - /** - * Return the cell at the specified index. The index will be adjusted to the notebook. - * - * @param index - The index of the cell to retrieve. - * @return A {@link NotebookCell cell}. - */ - cellAt(index: number): NotebookCell; - - /** - * Get the cells of this notebook. A subset can be retrieved by providing - * a range. The range will be adjuset to the notebook. - * - * @param range A notebook range. - * @returns The cells contained by the range or all cells. - */ - getCells(range?: NotebookRange): NotebookCell[]; - - /** - * Save the document. The saving will be handled by the corresponding content provider - * - * @return A promise that will resolve to true when the document - * has been saved. If the file was not dirty or the save failed, - * will return false. - */ - save(): Thenable; - } - - export class NotebookCellMetadata { - /** - * Whether a code cell's editor is collapsed - */ - readonly inputCollapsed?: boolean; - - /** - * Whether a code cell's outputs are collapsed - */ - readonly outputCollapsed?: boolean; - - /** - * Additional attributes of a cell metadata. - */ - readonly [key: string]: any; - - /** - * Create a new notebook cell metadata. - * - * @param inputCollapsed Whether a code cell's editor is collapsed - * @param outputCollapsed Whether a code cell's outputs are collapsed - */ - constructor(inputCollapsed?: boolean, outputCollapsed?: boolean); - - /** - * Derived a new cell metadata from this metadata. - * - * @param change An object that describes a change to this NotebookCellMetadata. - * @return A new NotebookCellMetadata that reflects the given change. Will return `this` NotebookCellMetadata if the change - * is not changing anything. - */ - with(change: { inputCollapsed?: boolean | null, outputCollapsed?: boolean | null, [key: string]: any }): NotebookCellMetadata; - } - - export interface NotebookCellExecutionSummary { - readonly executionOrder?: number; - readonly success?: boolean; - readonly startTime?: number; - readonly endTime?: number; - } - - export class NotebookDocumentMetadata { - /** - * Additional attributes of the document metadata. - */ - readonly [key: string]: any; - - /** - * Create a new notebook document metadata - */ - constructor(); - - /** - * Derived a new document metadata from this metadata. - * - * @param change An object that describes a change to this NotebookDocumentMetadata. - * @return A new NotebookDocumentMetadata that reflects the given change. Will return `this` NotebookDocumentMetadata if the change - * is not changing anything. - */ - with(change: { [key: string]: any }): NotebookDocumentMetadata - } - - /** - * 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 { - - /** - * The zero-based start index of this range. - */ - readonly start: number; - - /** - * The exclusive end index of this range (zero-based). - */ - readonly end: number; - - /** - * `true` if `start` and `end` are equal. - */ - 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); - - /** - * 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; - } - - /** - * One representation of a {@link NotebookCellOutput notebook output}, defined by MIME type and data. - */ - // todo@API document which mime types are supported out of the box and - // which are considered secure - export class NotebookCellOutputItem { - - /** - * Factory function to create a `NotebookCellOutputItem` from a string. - * - * *Note* that an UTF-8 encoder is used to create bytes for the string. - * - * @param value A string. - * @param mime Optional MIME type, defaults to `text/plain`. - * @param metadata Optional metadata. - * @returns A new output item object. - */ - static text(value: string, mime?: string, metadata?: { [key: string]: any }): NotebookCellOutputItem; - - /** - * Factory function to create a `NotebookCellOutputItem` from - * a JSON object. - * - * *Note* that this function is not expecting "stringified JSON" but - * an object that can be stringified. This function will throw an error - * when the passed value cannot be JSON-stringified. - * - * @param value A JSON-stringifyable value. - * @param mime Optional MIME type, defaults to `application/json` - * @param metadata Optional metadata. - * @returns A new output item object. - */ - static json(value: any, mime?: string, metadata?: { [key: string]: any }): NotebookCellOutputItem; - - /** - * Factory function to create a `NotebookCellOutputItem` that uses - * uses the `application/vnd.code.notebook.stdout` mime type. - * - * @param value A string. - * @param metadata Optional metadata. - * @returns A new output item object. - */ - static stdout(value: string, metadata?: { [key: string]: any }): NotebookCellOutputItem; - - /** - * Factory function to create a `NotebookCellOutputItem` that uses - * uses the `application/vnd.code.notebook.stderr` mime type. - * - * @param value A string. - * @param metadata Optional metadata. - * @returns A new output item object. - */ - static stderr(value: string, metadata?: { [key: string]: any }): NotebookCellOutputItem; - - /** - * Factory function to create a `NotebookCellOutputItem` that uses - * uses the `application/vnd.code.notebook.error` mime type. - * - * @param value An error object. - * @param metadata Optional metadata. - * @returns A new output item object. - */ - static error(value: Error, metadata?: { [key: string]: any }): NotebookCellOutputItem; - - /** - * The mime type which determines how the {@link NotebookCellOutputItem.value `value`}-property - * is interpreted. - * - * Notebooks have built-in support for certain mime-types, extensions can add support for new - * types and override existing types. - */ - mime: string; - - /** - * The data of this output item. Must always be an array of unsigned 8-bit integers. - */ - data: Uint8Array; - - //todo@API - metadata?: { [key: string]: any }; - - /** - * Create a new notbook cell output item. - * - * @param data The value of the output item. - * @param mime The mime type of the output item. - * @param metadata Optional metadata for this output item. - */ - constructor(data: Uint8Array, mime: string, metadata?: { [key: string]: any }); - } - - /** - * Notebook cell output represents a result of executing a cell. It is a container type for multiple - * {@link NotebookCellOutputItem output items} where contained items represent the same result but - * use different MIME types. - */ - //todo@API - add sugar function to add more outputs - export class NotebookCellOutput { - - /** - * Identifier for this output. Using the identifier allows a subsequent execution to modify - * existing output. Defaults to a fresh UUID. - */ - id: string; - - /** - * The output items of this output. Each item must represent the same result. _Note_ that repeated - * MIME types per output is invalid and that the editor will just pick one of them. - * - * ```ts - * new vscode.NotebookCellOutput([ - * vscode.NotebookCellOutputItem.text('Hello', 'text/plain'), - * vscode.NotebookCellOutputItem.text('Hello', 'text/html'), - * vscode.NotebookCellOutputItem.text('_Hello_', 'text/markdown'), - * vscode.NotebookCellOutputItem.text('Hey', 'text/plain'), // INVALID: repeated type, editor will pick just one - * ]) - * ``` - */ - //todo@API rename to items - outputs: NotebookCellOutputItem[]; - - //todo@API - metadata?: { [key: string]: any }; - - constructor(outputs: NotebookCellOutputItem[], metadata?: { [key: string]: any }); - - constructor(outputs: NotebookCellOutputItem[], id: string, metadata?: { [key: string]: any }); - } - - /** - * NotebookCellData is the raw representation of notebook cells. Its is part of {@link NotebookData `NotebookData`}. - */ - export class NotebookCellData { - - /** - * The {@link NotebookCellKind kind} of this cell data. - */ - kind: NotebookCellKind; - - /** - * The source value of this cell data - either source code or formatted text. - */ - value: string; - - /** - * The language identifier of the source value of this cell data. Any value from - * {@link languages.getLanguages `getLanguages`} is possible. - */ - languageId: string; - - /** - * The outputs of this cell data. - */ - outputs?: NotebookCellOutput[]; - - /** - * The metadata of this cell data. - */ - metadata?: NotebookCellMetadata; - - /** - * The execution summary of this cell data. - */ - executionSummary?: NotebookCellExecutionSummary; - - /** - * Create new cell data. Minimal cell data specifies its kind, its source value, and the - * language identifier of its source. - * - * @param kind The kind. - * @param value The source value. - * @param languageId The language identifier of the source value. - * @param outputs //TODO@API remove ctor? - * @param metadata //TODO@API remove ctor? - * @param executionSummary //TODO@API remove ctor? - */ - constructor(kind: NotebookCellKind, value: string, languageId: string, outputs?: NotebookCellOutput[], metadata?: NotebookCellMetadata, executionSummary?: NotebookCellExecutionSummary); - } - - /** - * NotebookData is the raw representation of notebooks. - * - * Extensions are responsible to create {@link NotebookData `NotebookData`} so that the editor - * can create a {@link NotebookDocument `NotebookDocument`}. - * - * @see {@link NotebookSerializer} - */ - export class NotebookData { - /** - * The cell data of this notebook data. - */ - cells: NotebookCellData[]; - - /** - * The metadata of this notebook data. - */ - metadata: NotebookDocumentMetadata; - - /** - * Create new notebook data. - * - * @param cells An array of cell data. - * @param metadata Notebook metadata. - */ - constructor(cells: NotebookCellData[], metadata?: NotebookDocumentMetadata); - } - - /** - * The notebook serializer enables the editor to open notebook files. - * - * At its core the editor only knows a {@link NotebookData notebook data structure} but not - * how that data structure is written to a file, nor how it is read from a file. The - * notebook serializer bridges this gap by deserializing bytes into notebook data and - * vice versa. - */ - export interface NotebookSerializer { - - /** - * Deserialize contents of a notebook file into the notebook data structure. - * - * @param content Contents of a notebook file. - * @param token A cancellation token. - * @return Notebook data or a thenable that resolves to such. - */ - deserializeNotebook(content: Uint8Array, token: CancellationToken): NotebookData | Thenable; - - /** - * Serialize notebook data into file contents. - * - * @param data A notebook data structure. - * @param token A cancellation token. - * @returns An array of bytes or a thenable that resolves to such. - */ - serializeNotebook(data: NotebookData, token: CancellationToken): Uint8Array | Thenable; - } - - export interface NotebookDocumentContentOptions { - /** - * Controls if outputs 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 the outputs in the file document, this should be set to true. - */ - transientOutputs?: 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 NotebookExecuteHandler { - /** - * @param cells The notebook cells to execute. - * @param notebook The notebook for which the execute handler is being called. - * @param controller The controller that the handler is attached to - */ - (this: NotebookController, cells: NotebookCell[], notebook: NotebookDocument, controller: NotebookController): void | Thenable - } - - export enum NotebookControllerAffinity { - Default = 1, - Preferred = 2 - } - - - export class NotebookRendererScript { - - /** - * APIs that the preload provides to the renderer. These are matched - * against the `dependencies` and `optionalDependencies` arrays in the - * notebook renderer contribution point. - */ - provides: string[]; - - /** - * URI for the file to preload - */ - uri: Uri; - - /** - * @param uri URI for the file to preload - * @param provides Value for the `provides` property - */ - constructor(uri: Uri, provides?: string | string[]); - } + //#region Terminal profile provider https://github.com/microsoft/vscode/issues/120369 - export interface NotebookCellExecuteStartContext { + export namespace window { /** - * The time that execution began, in milliseconds in the Unix epoch. Used to drive the clock - * that shows for how long a cell has been running. If not given, the clock won't be shown. + * Registers a provider for a contributed terminal profile. + * @param id The ID of the contributed terminal profile. + * @param provider The terminal profile provider. */ - startTime?: number; + export function registerTerminalProfileProvider(id: string, provider: TerminalProfileProvider): Disposable; } - export interface NotebookCellExecuteEndContext { - /** - * If true, a green check is shown on the cell status bar. - * If false, a red X is shown. - */ - success?: boolean; - + export interface TerminalProfileProvider { /** - * The time that execution finished, in milliseconds in the Unix epoch. + * Provide terminal profile options for the requested terminal. + * @param token A cancellation token that indicates the result is no longer needed. */ - endTime?: number; + provideProfileOptions(token: CancellationToken): ProviderResult; } - // todo@API jsdoc slightly outdated: kernel, notebook.createNotebookCellExecution - /** - * A NotebookCellExecution is how the kernel modifies a notebook cell as it is executing. When - * {@link notebook.createNotebookCellExecution `createNotebookCellExecution`} is called, the cell - * enters the Pending state. When `start()` is called on the execution task, it enters the Executing state. When - * `end()` is called, it enters the Idle state. While in the Executing state, cell outputs can be - * modified with the methods on the run task. - * - * All outputs methods operate on this NotebookCellExecution's cell by default. They optionally take - * a cellIndex parameter that allows them to modify the outputs of other cells. `appendOutputItems` and - * `replaceOutputItems` operate on the output with the given ID, which can be an output on any cell. They - * all resolve once the output edit has been applied. - */ - export interface NotebookCellExecution { - - /** - * The {@link NotebookCell cell} for which this execution has been created. - */ - readonly cell: NotebookCell; - - /** - * A cancellation token which will be triggered when the cell execution is canceled - * from the UI. - * - * _Note_ that the cancellation token will not be triggered when the {@link NotebookController controller} - * that created this execution uses an {@link NotebookController.interruptHandler interrupt-handler}. - */ - readonly token: CancellationToken; - - //todo@API remove? use cell.notebook instead? - readonly document: NotebookDocument; - - /** - * Set and unset the order of this cell execution. - */ - executionOrder: number | undefined; + //#endregion - // todo@API inline context object? - start(context?: NotebookCellExecuteStartContext): void; - // todo@API inline context object? - end(result?: NotebookCellExecuteEndContext): void; + // eslint-disable-next-line vscode-dts-region-comments + //#region @jrieken -> exclusive document filters - // todo@API use object instead of index? FF - clearOutput(cellIndex?: number): Thenable; - appendOutput(out: NotebookCellOutput | NotebookCellOutput[], cellIndex?: number): Thenable; - replaceOutput(out: NotebookCellOutput | NotebookCellOutput[], cellIndex?: number): Thenable; - // todo@API use object instead of index? - appendOutputItems(items: NotebookCellOutputItem | NotebookCellOutputItem[], outputId: string): Thenable; - replaceOutputItems(items: NotebookCellOutputItem | NotebookCellOutputItem[], outputId: string): Thenable; + export interface DocumentFilter { + readonly exclusive?: boolean; } - export interface NotebookController { + //#endregion - /** - * The identifier of this notebook controller. - * - * _Note_ that controllers are remembered by their identifier and that extensions should use - * stable identifiers across sessions. - */ - readonly id: string; + //#region Tree View: https://github.com/microsoft/vscode/issues/61313 @alexr00 + export interface TreeView extends Disposable { + reveal(element: T | undefined, options?: { select?: boolean, focus?: boolean, expand?: boolean | number; }): Thenable; + } + //#endregion - /** - * The notebook view type this controller is for. - */ - readonly viewType: string; + //#region Custom Tree View Drag and Drop https://github.com/microsoft/vscode/issues/32592 + export interface TreeViewOptions { + dragAndDropController?: DragAndDropController; + } + export interface DragAndDropController extends Disposable { /** - * An array of language identifiers that are supported by this - * controller. Any language identifier from {@link languages.getLanguages `getLanguages`} - * is possible. When falsy all languages are supported. - * - * Samples: - * ```js - * // support JavaScript and TypeScript - * myController.supportedLanguages = ['javascript', 'typescript'] + * Extensions should fire `TreeDataProvider.onDidChangeTreeData` for any elements that need to be refreshed. * - * // support all languages - * myController.supportedLanguages = undefined; // falsy - * myController.supportedLanguages = []; // falsy - * ``` - */ - supportedLanguages?: string[]; - - /** - * The human-readable label of this notebook controller. + * @param source + * @param target */ - label: string; + onDrop(source: T[], target: T): Thenable; + } + //#endregion + //#region Task presentation group: https://github.com/microsoft/vscode/issues/47265 + export interface TaskPresentationOptions { /** - * The human-readable description which is rendered less prominent. + * Controls whether the task is executed in a specific terminal group using split panes. */ - description?: string; + group?: string; + } + //#endregion - /** - * The human-readable detail which is rendered less prominent. - */ - detail?: string; + //#region Custom editor move https://github.com/microsoft/vscode/issues/86146 - /** - * Whether this controller supports execution order so that the - * editor can render placeholders for them. - */ - // todo@API rename to supportsExecutionOrder, usesExecutionOrder - hasExecutionOrder?: boolean; + // TODO: Also for custom editor - /** - * The execute handler is invoked when the run gestures in the UI are selected, e.g Run Cell, Run All, - * Run Selection etc. The execute handler is responsible for creating and managing {@link NotebookCellExecution execution}-objects. - */ - executeHandler: NotebookExecuteHandler; + export interface CustomTextEditorProvider { /** - * Optional interrupt handler. + * Handle when the underlying resource for a custom editor is renamed. + * + * This allows the webview for the editor be preserved throughout the rename. If this method is not implemented, + * VS Code will destory the previous custom editor and create a replacement one. * - * By default cell execution is canceled via {@link NotebookCellExecution.token tokens}. Cancellation - * tokens require that a controller can keep track of its execution so that it can cancel a specific execution at a later - * point. Not all scenarios allow for that, eg. REPL-style controllers often work by interrupting whatever is currently - * running. For those cases the {@link NotebookInterruptHandler interrupt handler} exists - it can be thought of as the - * equivalent of `SIGINT` or `Control+C` in terminals. + * @param newDocument New text document to use for the custom editor. + * @param existingWebviewPanel Webview panel for the custom editor. + * @param token A cancellation token that indicates the result is no longer needed. * - * _Note_ that supporting {@link NotebookCellExecution.token cancellation tokens} is preferred and that interrupt handlers should - * only be used when tokens cannot be supported. + * @return Thenable indicating that the webview editor has been moved. */ - interruptHandler?: (this: NotebookController, notebook: NotebookDocument) => void | Thenable; + // eslint-disable-next-line vscode-dts-provider-naming + moveCustomTextEditor?(newDocument: TextDocument, existingWebviewPanel: WebviewPanel, token: CancellationToken): Thenable; + } - /** - * Dispose and free associated resources. - */ - dispose(): void; + //#endregion - /** - * An event that fires whenever a controller has been selected for a notebook document. Selecting a controller - * for a notebook is a user gesture and happens either explicitly or implicitly when interacting while a - * controller was suggested. - */ - readonly onDidChangeNotebookAssociation: Event<{ notebook: NotebookDocument, selected: boolean }>; + //#region allow QuickPicks to skip sorting: https://github.com/microsoft/vscode/issues/73904 + export interface QuickPick extends QuickInput { /** - * A controller can set affinities for specific notebook documents. This allows a controller - * to be more important for some notebooks. - * - * @param notebook The notebook for which a priority is set. - * @param affinity A controller affinity + * An optional flag to sort the final results by index of first query match in label. Defaults to true. */ - updateNotebookAffinity(notebook: NotebookDocument, affinity: NotebookControllerAffinity): void; + sortByLabel: boolean; + } - /** - * Create a cell execution task. - * - * This should be used in response to the {@link NotebookController.executeHandler execution handler} - * being calleed or when cell execution has been started else, e.g when a cell was already - * executing or when cell execution was triggered from another source. - * - * @param cell The notebook cell for which to create the execution. - * @returns A notebook cell execution. - */ - createNotebookCellExecution(cell: NotebookCell): NotebookCellExecution; + //#endregion - // todo@API allow add, not remove - readonly rendererScripts: NotebookRendererScript[]; + //#region https://github.com/microsoft/vscode/issues/124970, Cell Execution State + /** + * The execution state of a notebook cell. + */ + export enum NotebookCellExecutionState { /** - * An event that fires when a renderer (see `preloads`) has send a message to the controller. + * The cell is idle. */ - readonly onDidReceiveMessage: Event<{ editor: NotebookEditor, message: any }>; - + Idle = 1, /** - * Send a message to the renderer of notebook editors. - * - * Note that only editors showing documents that are bound to this controller - * are receiving the message. - * - * @param message The message to send. - * @param editor A specific editor to send the message to. When `undefined` all applicable editors are receiving the message. - * @returns A promise that resolves to a boolean indicating if the message has been send or not. + * Execution for the cell is pending. */ - postMessage(message: any, editor?: NotebookEditor): Thenable; - - //todo@API validate this works - asWebviewUri(localResource: Uri): Uri; - } - - export enum NotebookCellExecutionState { - Idle = 1, Pending = 2, - Executing = 3, - } - - export interface NotebookCellExecutionStateChangeEvent { /** - * The {@link NotebookDocument notebook document} for which the cell execution state has changed. + * The cell is currently executing. */ - readonly document: NotebookDocument; - readonly cell: NotebookCell; - readonly executionState: NotebookCellExecutionState; + Executing = 3, } /** - * Represents the alignment of status bar items. + * An event describing a cell execution state change. */ - export enum NotebookCellStatusBarAlignment { - + export interface NotebookCellExecutionStateChangeEvent { /** - * Aligned to the left side. + * The {@link NotebookCell cell} for which the execution state has changed. */ - Left = 1, + readonly cell: NotebookCell; /** - * Aligned to the right side. + * The new execution state of the cell. */ - Right = 2 - } - - export class NotebookCellStatusBarItem { - text: string; - alignment: NotebookCellStatusBarAlignment; - command?: string | Command; - tooltip?: string; - priority?: number; - accessibilityInformation?: AccessibilityInformation; - - constructor(text: string, alignment: NotebookCellStatusBarAlignment, command?: string | Command, tooltip?: string, priority?: number, accessibilityInformation?: AccessibilityInformation); + readonly state: NotebookCellExecutionState; } - export interface NotebookCellStatusBarItemProvider { - /** - * Implement and fire this event to signal that statusbar items have changed. The provide method will be called again. - */ - onDidChangeCellStatusBarItems?: Event; + export namespace notebooks { /** - * 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. + * An {@link Event} which fires when the execution state of a cell has changed. */ - provideCellStatusBarItems(cell: NotebookCell, token: CancellationToken): ProviderResult; + // todo@API this is an event that is fired for a property that cells don't have and that makes me wonder + // how a correct consumer works, e.g the consumer could have been late and missed an event? + export const onDidChangeNotebookCellExecutionState: Event; } - export namespace notebook { - - /** - * All notebook documents currently known to the editor. - */ - export const notebookDocuments: ReadonlyArray; - - /** - * Open a notebook. Will return early if this notebook is already {@link notebook.notebookDocuments loaded}. Otherwise - * the notebook is loaded and the {@link notebook.onDidOpenNotebookDocument `onDidOpenNotebookDocument`}-event fires. - * - * *Note* that the lifecycle of the returned notebook is owned by the editor and not by the extension. That means an - * {@link notebook.onDidCloseNotebookDocument `onDidCloseNotebookDocument`}-event can occur at any time after. - * - * *Note* that opening a notebook does not show a notebook editor. This function only returns a notebook document which - * can be showns in a notebook editor but it can also be used for other things. - * - * @param uri The resource to open. - * @returns A promise that resolves to a {@link NotebookDocument notebook} - */ - export function openNotebookDocument(uri: Uri): Thenable; - - /** - * Open an untitled notebook. The editor will prompt the user for a file - * path when the document is to be saved. - * - * @see {@link openNotebookDocument} - * @param viewType The notebook view type that should be used. - * @param content The initial contents of the notebook. - * @returns A promise that resolves to a {@link NotebookDocument notebook}. - */ - export function openNotebookDocument(viewType: string, content?: NotebookData): Thenable; - - /** - * An event that is emitted when a {@link NotebookDocument notebook} is opened. - */ - export const onDidOpenNotebookDocument: Event; - - /** - * An event that is emitted when a {@link NotebookDocument notebook} is disposed. - * - * *Note 1:* There is no guarantee that this event fires when an editor tab is closed. - * - * *Note 2:* A notebook can be open but not shown in an editor which means this event can fire - * for a notebook that has not been shown in an editor. - */ - export const onDidCloseNotebookDocument: Event; - - /** - * Register a {@link NotebookSerializer notebook serializer}. - * - * A notebook serializer must to be contributed through the `notebooks` extension point. When opening a notebook file, the editor will send - * the `onNotebook:` activation event, and extensions must register their serializer in return. - * - * @param notebookType A notebook. - * @param serializer A notebook serialzier. - * @param options Optional context options that define what parts of a notebook should be persisted - * @return A {@link Disposable} that unregisters this serializer when being disposed. - */ - export function registerNotebookSerializer(notebookType: string, serializer: NotebookSerializer, options?: NotebookDocumentContentOptions): Disposable; - - /** - * Creates a new notebook controller. - * - * @param id Identifier of the controller. Must be unique per extension. - * @param viewType A notebook view type for which this controller is for. - * @param label The label of the controller - * @param handler - * @param rendererScripts - */ - export function createNotebookController(id: string, viewType: string, label: string, handler?: NotebookExecuteHandler, rendererScripts?: NotebookRendererScript[]): NotebookController; + //#endregion - // todo@API what is this used for? - // todo@API qualify cell, ...NotebookCell... - export const onDidChangeNotebookCellExecutionState: Event; + //#region https://github.com/microsoft/vscode/issues/106744, Notebook, deprecated - export function registerNotebookCellStatusBarItemProvider(notebookType: string, provider: NotebookCellStatusBarItemProvider): Disposable; - } + /** + * @deprecated use notebooks instead + */ + export const notebook: typeof notebooks; //#endregion //#region https://github.com/microsoft/vscode/issues/106744, NotebookEditor + /** + * Represents a notebook editor that is attached to a {@link NotebookDocument notebook}. + */ export enum NotebookEditorRevealType { /** * The range will be revealed with as little scrolling as possible. @@ -1893,10 +1096,14 @@ declare module 'vscode' { AtTop = 3 } + /** + * Represents a notebook editor that is attached to a {@link NotebookDocument notebook}. + */ export interface NotebookEditor { /** * The document associated with this notebook editor. */ + //todo@api rename to notebook? readonly document: NotebookDocument; /** @@ -1929,6 +1136,7 @@ declare module 'vscode' { /** * The {@link NotebookDocument notebook document} for which the document metadata have changed. */ + //todo@API rename to notebook? readonly document: NotebookDocument; } @@ -1946,6 +1154,7 @@ declare module 'vscode' { /** * The {@link NotebookDocument notebook document} for which the cells have changed. */ + //todo@API rename to notebook? readonly document: NotebookDocument; readonly changes: ReadonlyArray; } @@ -1954,7 +1163,9 @@ declare module 'vscode' { /** * The {@link NotebookDocument notebook document} for which the cell outputs have changed. */ + //todo@API remove? use cell.notebook instead? readonly document: NotebookDocument; + // NotebookCellOutputsChangeEvent.cells vs NotebookCellMetadataChangeEvent.cell readonly cells: NotebookCell[]; } @@ -1962,7 +1173,9 @@ declare module 'vscode' { /** * The {@link NotebookDocument notebook document} for which the cell metadata have changed. */ + //todo@API remove? use cell.notebook instead? readonly document: NotebookDocument; + // NotebookCellOutputsChangeEvent.cells vs NotebookCellMetadataChangeEvent.cell readonly cell: NotebookCell; } @@ -1990,7 +1203,7 @@ declare module 'vscode' { selections?: NotebookRange[]; } - export namespace notebook { + export namespace notebooks { @@ -2040,15 +1253,15 @@ declare module 'vscode' { export interface WorkspaceEdit { // todo@API add NotebookEdit-type which handles all these cases? - replaceNotebookMetadata(uri: Uri, value: NotebookDocumentMetadata): void; + replaceNotebookMetadata(uri: Uri, value: { [key: string]: any }): void; replaceNotebookCells(uri: Uri, range: NotebookRange, cells: NotebookCellData[], metadata?: WorkspaceEditEntryMetadata): void; - replaceNotebookCellMetadata(uri: Uri, index: number, cellMetadata: NotebookCellMetadata, metadata?: WorkspaceEditEntryMetadata): void; + replaceNotebookCellMetadata(uri: Uri, index: number, cellMetadata: { [key: string]: any }, metadata?: WorkspaceEditEntryMetadata): void; } export interface NotebookEditorEdit { - replaceMetadata(value: NotebookDocumentMetadata): void; + replaceMetadata(value: { [key: string]: any }): void; replaceCells(start: number, end: number, cells: NotebookCellData[]): void; - replaceCellMetadata(index: number, metadata: NotebookCellMetadata): void; + replaceCellMetadata(index: number, metadata: { [key: string]: any }): void; } export interface NotebookEditor { @@ -2085,7 +1298,7 @@ declare module 'vscode' { dispose(): void; } - export namespace notebook { + export namespace notebooks { export function createNotebookEditorDecorationType(options: NotebookDecorationRenderOptions): NotebookEditorDecorationType; } @@ -2093,7 +1306,7 @@ declare module 'vscode' { //#region https://github.com/microsoft/vscode/issues/106744, NotebookConcatTextDocument - export namespace notebook { + export namespace notebooks { /** * Create a document that is the concatenation of all notebook cells. By default all code-cells are included * but a selector can be provided to narrow to down the set of cells. @@ -2178,7 +1391,7 @@ declare module 'vscode' { backupNotebook(document: NotebookDocument, context: NotebookDocumentBackupContext, token: CancellationToken): Thenable; } - export namespace notebook { + export namespace notebooks { // TODO@api use NotebookDocumentFilter instead of just notebookType:string? // TODO@API options duplicates the more powerful variant on NotebookContentProvider @@ -2195,7 +1408,7 @@ declare module 'vscode' { exclusive?: boolean; } - export namespace notebook { + export namespace notebooks { // SPECIAL overload with NotebookRegistrationData export function registerNotebookContentProvider(notebookType: string, provider: NotebookContentProvider, options?: NotebookDocumentContentOptions, registrationData?: NotebookRegistrationData): Disposable; // SPECIAL overload with NotebookRegistrationData @@ -2237,7 +1450,7 @@ declare module 'vscode' { //#endregion - //#region @connor4312 - notebook messaging: https://github.com/microsoft/vscode/issues/123601 + //#region @https://github.com/microsoft/vscode/issues/123601, notebook messaging export interface NotebookRendererMessage { /** @@ -2253,7 +1466,7 @@ declare module 'vscode' { /** * Renderer messaging is used to communicate with a single renderer. It's - * returned from {@link notebook.createRendererMessaging}. + * returned from {@link notebooks.createRendererMessaging}. */ export interface NotebookRendererMessaging { /** @@ -2269,15 +1482,72 @@ declare module 'vscode' { postMessage(editor: NotebookEditor, message: TSend): void; } - export namespace notebook { + /** + * Represents a script that is loaded into the notebook renderer before rendering output. This allows + * to provide and share functionality for notebook markup and notebook output renderers. + */ + export class NotebookRendererScript { + + /** + * APIs that the preload provides to the renderer. These are matched + * against the `dependencies` and `optionalDependencies` arrays in the + * notebook renderer contribution point. + */ + provides: string[]; + + /** + * URI for the file to preload + */ + uri: Uri; + + /** + * @param uri URI for the file to preload + * @param provides Value for the `provides` property + */ + constructor(uri: Uri, provides?: string | string[]); + } + + export interface NotebookController { + + // todo@API allow add, not remove + readonly rendererScripts: NotebookRendererScript[]; + + /** + * An event that fires when a {@link NotebookController.rendererScripts renderer script} has send a message to + * the controller. + */ + readonly onDidReceiveMessage: Event<{ editor: NotebookEditor, message: any }>; + + /** + * Send a message to the renderer of notebook editors. + * + * Note that only editors showing documents that are bound to this controller + * are receiving the message. + * + * @param message The message to send. + * @param editor A specific editor to send the message to. When `undefined` all applicable editors are receiving the message. + * @returns A promise that resolves to a boolean indicating if the message has been send or not. + */ + postMessage(message: any, editor?: NotebookEditor): Thenable; + + //todo@API validate this works + asWebviewUri(localResource: Uri): Uri; + } + + export namespace notebooks { + + export function createNotebookController(id: string, viewType: string, label: string, handler?: NotebookExecuteHandler, rendererScripts?: NotebookRendererScript[]): NotebookController; + /** * Creates a new messaging instance used to communicate with a specific * renderer. The renderer only has access to messaging if `requiresMessaging` - * is set in its contribution. + * is set to `always` or `optional` in its `notebookRenderer ` contribution. * * @see https://github.com/microsoft/vscode/issues/123601 * @param rendererId The renderer ID to communicate with - */ + */ + // todo@API can ANY extension talk to renderer or is there a check that the calling extension + // declared the renderer in its package.json? export function createRendererMessaging(rendererId: string): NotebookRendererMessaging; } @@ -3489,11 +2759,20 @@ declare module 'vscode' { //#region https://github.com/microsoft/vscode/issues/124024 @hediet @alexdima export namespace languages { + /** + * Registers an inline completion provider. + */ export function registerInlineCompletionItemProvider(selector: DocumentSelector, provider: InlineCompletionItemProvider): Disposable; } export interface InlineCompletionItemProvider { - provideInlineCompletionItems(document: TextDocument, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult>; + /** + * Provides inline completion items for the given position and document. + * If inline completions are enabled, this method will be called whenever the user stopped typing. + * It will also be called when the user explicitly triggers inline completions or asks for the next or previous inline completion. + * Use `context.triggerKind` to distinguish between these scenarios. + */ + provideInlineCompletionItems(document: TextDocument, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult | T[]>; } export interface InlineCompletionContext { @@ -3537,6 +2816,10 @@ declare module 'vscode' { /** * The range to replace. * Must begin and end on the same line. + * + * Prefer replacements over insertions to avoid cache invalidation. + * Instead of reporting a completion that extends a word, + * the whole word should be replaced with the extended word. */ range?: Range; @@ -3560,6 +2843,9 @@ declare module 'vscode' { * Be aware that this API will not ever be finalized. */ export interface InlineCompletionController { + /** + * Is fired when an inline completion item is shown to the user. + */ // eslint-disable-next-line vscode-dts-event-naming readonly onDidShowCompletionItem: Event>; } diff --git a/src/dotnet-interactive-vscode/stable/package.json b/src/dotnet-interactive-vscode/stable/package.json index 149e72e742..7926332976 100644 --- a/src/dotnet-interactive-vscode/stable/package.json +++ b/src/dotnet-interactive-vscode/stable/package.json @@ -404,4 +404,4 @@ "node-fetch": "2.6.1", "uuid": "8.3.2" } -} \ No newline at end of file +} diff --git a/src/dotnet-interactive-vscode/stable/src/notebookControllers.ts b/src/dotnet-interactive-vscode/stable/src/notebookControllers.ts index 3d3e673e17..1495e3a377 100644 --- a/src/dotnet-interactive-vscode/stable/src/notebookControllers.ts +++ b/src/dotnet-interactive-vscode/stable/src/notebookControllers.ts @@ -108,7 +108,13 @@ export class DotNetNotebookKernel { const client = await this.clientMapper.getOrAddClient(cell.notebook.uri); executionTask.token.onCancellationRequested(() => { const errorOutput = this.createErrorOutput("Cell execution cancelled by user"); - const resultPromise = () => updateCellOutputs(executionTask, cell, [...cell.outputs, errorOutput]) + // the API is changing between stable and insiders, and this is a temporary re-working of the shape + const cellOutputs = cell.outputs.map(o => ({ + id: o.id, + items: o.outputs, // this propery was renamed + metadata: o.metadata, + })); + const resultPromise = () => updateCellOutputs(executionTask, cell, [...cellOutputs, errorOutput]) .then(() => endExecution(cell, false)); client.cancel() .then(resultPromise) @@ -179,7 +185,7 @@ export async function updateCellLanguages(document: vscode.NotebookDocument): Pr } async function updateCellOutputs(executionTask: vscode.NotebookCellExecutionTask, cell: vscode.NotebookCell, outputs: Array): Promise { - const reshapedOutputs = outputs.map(o => new vscode.NotebookCellOutput(o.outputs.map(oi => generateVsCodeNotebookCellOutputItem(oi.mime, oi.data)))); + const reshapedOutputs = outputs.map(o => new vscode.NotebookCellOutput(o.items.map(oi => generateVsCodeNotebookCellOutputItem(oi.mime, oi.data)))); await executionTask.replaceOutput(reshapedOutputs, cell.index); } diff --git a/src/dotnet-interactive-vscode/stable/src/versionSpecificFunctions.ts b/src/dotnet-interactive-vscode/stable/src/versionSpecificFunctions.ts index f6eb6e1c8d..9527710272 100644 --- a/src/dotnet-interactive-vscode/stable/src/versionSpecificFunctions.ts +++ b/src/dotnet-interactive-vscode/stable/src/versionSpecificFunctions.ts @@ -24,6 +24,18 @@ export function endExecution(cell: vscode.NotebookCell, success: boolean) { notebookControllers.endExecution(cell, success); } +export function getCellOutputItems(cellOutput: vscode.NotebookCellOutput): vscode.NotebookCellOutputItem[] { + return cellOutput.outputs; +} + +export function getNotebookType(notebook: vscode.NotebookDocument): string { + return notebook.viewType; +} + +export const onDidCloseNotebookDocument: vscode.Event = vscode.notebook.onDidCloseNotebookDocument; + +export const notebookDocuments: ReadonlyArray = vscode.notebook.notebookDocuments; + export function createErrorOutput(message: string, outputId?: string): vscodeLike.NotebookCellOutput { const errorObject = { ename: 'Error',