diff --git a/src/vs/workbench/api/browser/mainThreadNotebookDto.ts b/src/vs/workbench/api/browser/mainThreadNotebookDto.ts index 8d7a1f60a14..7545f78906a 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebookDto.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookDto.ts @@ -6,6 +6,7 @@ import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellExecutionUpdateType, ICellExecuteUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; export namespace NotebookDto { @@ -91,23 +92,25 @@ export namespace NotebookDto { }; } - export function fromCellExecuteEditDto(data: extHostProtocol.CellExecuteEditDto): notebookCommon.IImmediateCellEditOperation { - if (data.editType === notebookCommon.CellEditType.PartialInternalMetadata) { - return data; - } else if (data.editType === notebookCommon.CellEditType.Output) { + export function fromCellExecuteUpdateDto(data: extHostProtocol.ICellExecuteUpdateDto): ICellExecuteUpdate { + if (data.editType === CellExecutionUpdateType.Output) { return { editType: data.editType, - handle: data.handle, + executionHandle: data.executionHandle, + cellHandle: data.cellHandle, append: data.append, outputs: data.outputs.map(fromNotebookOutputDto) }; - } else { + } else if (data.editType === CellExecutionUpdateType.OutputItems) { return { editType: data.editType, + executionHandle: data.executionHandle, append: data.append, outputId: data.outputId, items: data.items.map(fromNotebookOutputItemDto) }; + } else { + return data; } } diff --git a/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts b/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts index fefd0ed8f24..f8a63895d67 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookKernels.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { flatten, isNonEmptyArray } from 'vs/base/common/arrays'; +import { flatten, groupBy, isNonEmptyArray } from 'vs/base/common/arrays'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { combinedDisposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; @@ -14,9 +14,9 @@ import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService'; +import { ICellExecuteUpdate, INotebookCellExecution, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; import { INotebookKernel, INotebookKernelChangeEvent, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; -import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; -import { CellExecuteEditDto, ExtHostContext, ExtHostNotebookKernelsShape, IExtHostContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from '../common/extHost.protocol'; +import { ICellExecuteUpdateDto, ExtHostContext, ExtHostNotebookKernelsShape, IExtHostContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from '../common/extHost.protocol'; abstract class MainThreadKernel implements INotebookKernel { @@ -99,11 +99,14 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape private readonly _kernels = new Map(); private readonly _proxy: ExtHostNotebookKernelsShape; + private readonly _executions = new Map(); + constructor( extHostContext: IExtHostContext, @IModeService private readonly _modeService: IModeService, @INotebookKernelService private readonly _notebookKernelService: INotebookKernelService, - @INotebookService private readonly _notebookService: INotebookService, + @INotebookExecutionService private readonly _notebookExecutionService: INotebookExecutionService, + // @INotebookService private readonly _notebookService: INotebookService, @INotebookEditorService notebookEditorService: INotebookEditorService ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookKernels); @@ -223,22 +226,43 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape } } - // --- execution editss + // --- execution - async $applyExecutionEdits(resource: UriComponents, cellEdits: CellExecuteEditDto[]): Promise { - const textModel = this._notebookService.getNotebookTextModel(URI.from(resource)); - if (!textModel) { - throw new Error(`Can't apply edits to unknown notebook model: ${URI.revive(resource).toString()}`); - } + $addExecution(handle: number, uri: UriComponents, cellHandle: number): void { + const execution = new MainThreadExecution(handle, URI.revive(uri), cellHandle); + this._executions.set(handle, execution); + this._notebookExecutionService.registerNotebookCellExecution(execution); + } - const edits = cellEdits.map(NotebookDto.fromCellExecuteEditDto); + $updateExecutions(updates: ICellExecuteUpdateDto[]): void { + const groupedUpdates = groupBy(updates, (a, b) => a.executionHandle - b.executionHandle); + groupedUpdates.forEach(datas => { + const first = datas[0]; + const execution = this._executions.get(first.executionHandle); + if (!execution) { + return; + } - try { - textModel.applyEdits(edits, true, undefined, () => undefined, undefined, false); - } catch (e) { - // Clearing outputs at the same time as the EH calling append/replaceOutputItems is an expected race, and it should be a no-op. - // And any other failure should not throw back to the extension. - onUnexpectedError(e); - } + try { + execution.update(datas.map(NotebookDto.fromCellExecuteUpdateDto)); + } catch (e) { + onUnexpectedError(e); + } + }); + } +} + +class MainThreadExecution implements INotebookCellExecution { + private readonly _onDidChange = new Emitter(); + readonly onDidChange: Event> = this._onDidChange.event; + + constructor( + readonly id: number, + readonly notebook: URI, + readonly cellHandle: number, + ) { } + + update(updates: ICellExecuteUpdate[]): void { + this._onDidChange.fire(updates); } } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index fbe51274076..d26e8313a06 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -55,6 +55,7 @@ import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views'; import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug'; import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellExecutionUpdateType, ICellExecutionComplete, ICellExecutionStateUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm'; import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder'; @@ -909,21 +910,23 @@ export interface INotebookKernelDto2 { preloads?: { uri: UriComponents; provides: string[] }[]; } -export interface CellExecuteOutputEditDto { - editType: notebookCommon.CellEditType.Output; +export interface ICellExecuteOutputEditDto { + editType: CellExecutionUpdateType.Output; + executionHandle: number; + cellHandle: number; append?: boolean; - handle: number; outputs: NotebookOutputDto[] } -export interface CellExecuteOutputItemEditDto { - editType: notebookCommon.CellEditType.OutputItems; +export interface ICellExecuteOutputItemEditDto { + editType: CellExecutionUpdateType.OutputItems; + executionHandle: number; append?: boolean; outputId: string; items: NotebookOutputItemDto[] } -export type CellExecuteEditDto = CellExecuteOutputEditDto | CellExecuteOutputItemEditDto | notebookCommon.ICellPartialInternalMetadataEditByHandle; +export type ICellExecuteUpdateDto = ICellExecuteOutputEditDto | ICellExecuteOutputItemEditDto | ICellExecutionStateUpdate | ICellExecutionComplete; export interface MainThreadNotebookKernelsShape extends IDisposable { $postMessage(handle: number, editorId: string | undefined, message: any): Promise; @@ -932,7 +935,8 @@ export interface MainThreadNotebookKernelsShape extends IDisposable { $removeKernel(handle: number): void; $updateNotebookPriority(handle: number, uri: UriComponents, value: number | undefined): void; - $applyExecutionEdits(resource: UriComponents, edits: CellExecuteEditDto[]): Promise; + $addExecution(handle: number, uri: UriComponents, cellHandle: number): void; + $updateExecutions(data: ICellExecuteUpdateDto[]): void; } export interface MainThreadNotebookRenderersShape extends IDisposable { diff --git a/src/vs/workbench/api/common/extHostNotebookKernels.ts b/src/vs/workbench/api/common/extHostNotebookKernels.ts index 91f25c7b7d9..a83a1504130 100644 --- a/src/vs/workbench/api/common/extHostNotebookKernels.ts +++ b/src/vs/workbench/api/common/extHostNotebookKernels.ts @@ -3,25 +3,25 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { asArray } from 'vs/base/common/arrays'; +import { timeout } from 'vs/base/common/async'; +import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { CellExecuteEditDto, ExtHostNotebookKernelsShape, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape, NotebookOutputDto } from 'vs/workbench/api/common/extHost.protocol'; -import * as vscode from 'vscode'; -import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { URI, UriComponents } from 'vs/base/common/uri'; -import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; -import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; -import { asWebviewUri } from 'vs/workbench/api/common/shared/webview'; import { ResourceMap } from 'vs/base/common/map'; -import { timeout } from 'vs/base/common/async'; -import { ExtHostCell, ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument'; -import { CellEditType, NotebookCellExecutionState, NullablePartialNotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; -import { asArray } from 'vs/base/common/arrays'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; +import { ICellExecuteUpdateDto, ExtHostNotebookKernelsShape, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape, NotebookOutputDto } from 'vs/workbench/api/common/extHost.protocol'; +import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; +import { ExtHostCell, ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument'; +import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import { NotebookCellOutput } from 'vs/workbench/api/common/extHostTypes'; +import { asWebviewUri } from 'vs/workbench/api/common/shared/webview'; +import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import * as vscode from 'vscode'; interface IKernelData { extensionId: ExtensionIdentifier, @@ -324,6 +324,9 @@ enum NotebookCellExecutionTaskState { } class NotebookCellExecutionTask extends Disposable { + private static HANDLE = 0; + private _handle = NotebookCellExecutionTask.HANDLE++; + private _onDidChangeState = new Emitter(); readonly onDidChangeState = this._onDidChangeState.event; @@ -332,7 +335,7 @@ class NotebookCellExecutionTask extends Disposable { private readonly _tokenSource = this._register(new CancellationTokenSource()); - private readonly _collector: TimeoutBasedCollector; + private readonly _collector: TimeoutBasedCollector; private _executionOrder: number | undefined; @@ -343,25 +346,23 @@ class NotebookCellExecutionTask extends Disposable { ) { super(); - this._collector = new TimeoutBasedCollector(10, edits => this.applyEdits(edits)); + this._collector = new TimeoutBasedCollector(10, updates => this.update(updates)); this._executionOrder = _cell.internalMetadata.executionOrder; - this.mixinMetadata({ - runState: NotebookCellExecutionState.Pending, - executionOrder: null - }); + this._proxy.$addExecution(this._handle, this._cell.notebook.uri, this._cell.handle); } cancel(): void { this._tokenSource.cancel(); } - private async applyEditSoon(edit: CellExecuteEditDto): Promise { - await this._collector.addItem(edit); + private async updateSoon(update: ICellExecuteUpdateDto): Promise { + await this._collector.addItem(update); } - private async applyEdits(edits: CellExecuteEditDto[]): Promise { - return this._proxy.$applyExecutionEdits(this._document.uri, edits); + private async update(update: ICellExecuteUpdateDto | ICellExecuteUpdateDto[]): Promise { + const updates = Array.isArray(update) ? update : [update]; + return this._proxy.$updateExecutions(updates); } private verifyStateForOutput() { @@ -374,14 +375,6 @@ class NotebookCellExecutionTask extends Disposable { } } - private mixinMetadata(mixinMetadata: NullablePartialNotebookCellInternalMetadata) { - this.applyEdits([{ - editType: CellEditType.PartialInternalMetadata, - handle: this._cell.handle, - internalMetadata: mixinMetadata - }]); - } - private cellIndexToHandle(cellOrCellIndex: vscode.NotebookCell | undefined): number { let cell: ExtHostCell | undefined = this._cell; if (cellOrCellIndex) { @@ -410,12 +403,25 @@ class NotebookCellExecutionTask extends Disposable { private async updateOutputs(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell: vscode.NotebookCell | undefined, append: boolean): Promise { const handle = this.cellIndexToHandle(cell); const outputDtos = this.validateAndConvertOutputs(asArray(outputs)); - return this.applyEditSoon({ editType: CellEditType.Output, handle, append, outputs: outputDtos }); + return this.updateSoon( + { + editType: CellExecutionUpdateType.Output, + executionHandle: this._handle, + cellHandle: handle, + append, + outputs: outputDtos + }); } private async updateOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput, append: boolean): Promise { items = NotebookCellOutput.ensureUniqueMimeTypes(asArray(items), true); - return this.applyEditSoon({ editType: CellEditType.OutputItems, items: items.map(extHostTypeConverters.NotebookCellOutputItem.from), outputId: output.id, append }); + return this.updateSoon({ + editType: CellExecutionUpdateType.OutputItems, + executionHandle: this._handle, + items: items.map(extHostTypeConverters.NotebookCellOutputItem.from), + outputId: output.id, + append + }); } asApiObject(): vscode.NotebookCellExecution { @@ -426,9 +432,11 @@ class NotebookCellExecutionTask extends Disposable { get executionOrder() { return that._executionOrder; }, set executionOrder(v: number | undefined) { that._executionOrder = v; - that.mixinMetadata({ - executionOrder: v - }); + that.update([{ + editType: CellExecutionUpdateType.ExecutionState, + executionHandle: that._handle, + executionOrder: that._executionOrder + }]); }, start(startTime?: number): void { @@ -439,9 +447,10 @@ class NotebookCellExecutionTask extends Disposable { that._state = NotebookCellExecutionTaskState.Started; that._onDidChangeState.fire(); - that.mixinMetadata({ - runState: NotebookCellExecutionState.Executing, - runStartTime: startTime ?? null + that.update({ + editType: CellExecutionUpdateType.ExecutionState, + executionHandle: that._handle, + runStartTime: startTime }); }, @@ -453,10 +462,11 @@ class NotebookCellExecutionTask extends Disposable { that._state = NotebookCellExecutionTaskState.Resolved; that._onDidChangeState.fire(); - that.mixinMetadata({ - runState: null, - lastRunSuccess: success ?? null, - runEndTime: endTime ?? null, + that.updateSoon({ + editType: CellExecutionUpdateType.Complete, + executionHandle: that._handle, + runEndTime: endTime, + lastRunSuccess: success }); }, @@ -495,7 +505,7 @@ class TimeoutBasedCollector { constructor( private readonly delay: number, - private readonly callback: (items: T[]) => Promise) { } + private readonly callback: (items: T[]) => Promise | void) { } addItem(item: T): Promise { this.batch.push(item); diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 58132aff89e..6614c0ee578 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -89,6 +89,8 @@ import 'vs/workbench/contrib/notebook/browser/diff/notebookDiffActions'; // Output renderers registration import 'vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform'; import { editorOptionsRegistry } from 'vs/editor/common/config/editorOptions'; +import { NotebookExecutionService } from 'vs/workbench/contrib/notebook/browser/notebookExecutionServiceImpl'; +import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; /*--------------------------------------------------------------------------------------------- */ @@ -603,6 +605,7 @@ registerSingleton(INotebookEditorModelResolverService, NotebookModelResolverServ registerSingleton(INotebookCellStatusBarService, NotebookCellStatusBarService, true); registerSingleton(INotebookEditorService, NotebookEditorWidgetService, true); registerSingleton(INotebookKernelService, NotebookKernelService, true); +registerSingleton(INotebookExecutionService, NotebookExecutionService, true); registerSingleton(INotebookRendererMessagingService, NotebookRendererMessagingService, true); const schemas: IJSONSchemaMap = {}; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookExecutionServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookExecutionServiceImpl.ts new file mode 100644 index 00000000000..ff04e182af7 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/notebookExecutionServiceImpl.ts @@ -0,0 +1,92 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; +import { CellEditType, ICellEditOperation, NotebookCellExecutionState, NotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellExecutionUpdateType, ICellExecuteUpdate, INotebookCellExecution, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; +import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; + +export class NotebookExecutionService implements INotebookExecutionService { + declare _serviceBrand: undefined; + + constructor( + @INotebookService private readonly _notebookService: INotebookService, + ) { + } + + registerNotebookCellExecution(execution: INotebookCellExecution): void { + const notebook = this._notebookService.getNotebookTextModel(execution.notebook); + if (!notebook) { + return; + } + + const startExecuteEdit: ICellEditOperation = { + editType: CellEditType.PartialInternalMetadata, + handle: execution.cellHandle, + internalMetadata: { + runState: NotebookCellExecutionState.Pending + } + }; + this._applyExecutionEdits(notebook, [startExecuteEdit]); + + const listener = execution.onDidChange(updates => { + const edits = updates.map(update => updateToEdit(update, execution.cellHandle)); + if (updates.some(update => update.editType === CellExecutionUpdateType.Complete)) { + listener.dispose(); + } + + this._applyExecutionEdits(notebook, edits); + }); + } + + private _applyExecutionEdits(notebook: NotebookTextModel, edits: ICellEditOperation[]): void { + notebook.applyEdits(edits, true, undefined, () => undefined, undefined, false); + } +} + +function updateToEdit(update: ICellExecuteUpdate, cellHandle: number): ICellEditOperation { + if (update.editType === CellExecutionUpdateType.Output) { + return { + editType: CellEditType.Output, + handle: update.cellHandle, + append: update.append, + outputs: update.outputs, + }; + } else if (update.editType === CellExecutionUpdateType.OutputItems) { + return { + editType: CellEditType.OutputItems, + items: update.items, + append: update.append, + outputId: update.outputId + }; + } else if (update.editType === CellExecutionUpdateType.Complete) { + return { + editType: CellEditType.PartialInternalMetadata, + handle: cellHandle, + internalMetadata: { + runState: null, + lastRunSuccess: update.lastRunSuccess, + runEndTime: update.runEndTime + } + }; + } else if (update.editType === CellExecutionUpdateType.ExecutionState) { + const newInternalMetadata: Partial = { + runState: NotebookCellExecutionState.Executing, + }; + if (typeof update.executionOrder !== 'undefined') { + newInternalMetadata.executionOrder = update.executionOrder; + } + if (typeof update.runStartTime !== 'undefined') { + newInternalMetadata.runStartTime = update.runStartTime; + } + return { + editType: CellEditType.PartialInternalMetadata, + handle: cellHandle, + internalMetadata: newInternalMetadata + }; + } + + throw new Error('Unknown cell update type'); +} diff --git a/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts b/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts new file mode 100644 index 00000000000..a95e6eda8b5 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/common/notebookExecutionService.ts @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IOutputDto, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; + +export enum CellExecutionUpdateType { + Output = 1, + OutputItems = 2, + ExecutionState = 3, + Complete = 4, +} + +export interface ICellExecuteOutputEdit { + editType: CellExecutionUpdateType.Output; + executionHandle: number; + cellHandle: number; + append?: boolean; + outputs: IOutputDto[] +} + +export interface ICellExecuteOutputItemEdit { + editType: CellExecutionUpdateType.OutputItems; + executionHandle: number; + append?: boolean; + outputId: string; + items: IOutputItemDto[] +} + +export type ICellExecuteUpdate = ICellExecuteOutputEdit | ICellExecuteOutputItemEdit | ICellExecutionStateUpdate | ICellExecutionComplete; + +export interface ICellExecutionStateUpdate { + editType: CellExecutionUpdateType.ExecutionState; + executionHandle: number; + executionOrder?: number; + runStartTime?: number; +} + +export interface ICellExecutionComplete { + editType: CellExecutionUpdateType.Complete; + executionHandle: number; + runEndTime?: number; + lastRunSuccess?: boolean; +} + +export interface INotebookCellExecution { + readonly id: number; + readonly notebook: URI; + readonly cellHandle: number; + readonly onDidChange: Event>; +} + +export const INotebookExecutionService = createDecorator('INotebookExecutionService'); + +export interface INotebookExecutionService { + _serviceBrand: undefined; + + registerNotebookCellExecution(execution: INotebookCellExecution): void; +} diff --git a/src/vs/workbench/test/browser/api/extHostNotebookKernel.test.ts b/src/vs/workbench/test/browser/api/extHostNotebookKernel.test.ts index 790ab6684d5..d7405c50298 100644 --- a/src/vs/workbench/test/browser/api/extHostNotebookKernel.test.ts +++ b/src/vs/workbench/test/browser/api/extHostNotebookKernel.test.ts @@ -4,27 +4,28 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol'; -import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; -import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; -import { mock } from 'vs/workbench/test/common/workbenchTestServices'; -import { CellExecuteEditDto, INotebookKernelDto2, MainContext, MainThreadCommandsShape, MainThreadNotebookDocumentsShape, MainThreadNotebookKernelsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol'; -import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; -import { NullLogService } from 'vs/platform/log/common/log'; -import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; -import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; -import { ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument'; -import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; -import { URI, UriComponents } from 'vs/base/common/uri'; -import { generateUuid } from 'vs/base/common/uuid'; -import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; -import { CellEditType, CellKind, CellUri, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNotebookDocuments'; -import { NotebookCellOutput, NotebookCellOutputItem } from 'vs/workbench/api/common/extHostTypes'; import { Barrier } from 'vs/base/common/async'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { NullLogService } from 'vs/platform/log/common/log'; +import { ICellExecuteUpdateDto, INotebookKernelDto2, MainContext, MainThreadCommandsShape, MainThreadNotebookDocumentsShape, MainThreadNotebookKernelsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol'; +import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; +import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; +import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; +import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; +import { ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument'; +import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNotebookDocuments'; +import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels'; +import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; +import { NotebookCellOutput, NotebookCellOutputItem } from 'vs/workbench/api/common/extHostTypes'; +import { CellKind, CellUri, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; +import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; +import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol'; +import { mock } from 'vs/workbench/test/common/workbenchTestServices'; suite('NotebookKernel', function () { @@ -40,13 +41,13 @@ suite('NotebookKernel', function () { const kernelData = new Map(); const disposables = new DisposableStore(); - const cellExecuteEdits: CellExecuteEditDto[] = []; + const cellExecuteUpdates: ICellExecuteUpdateDto[] = []; teardown(function () { disposables.clear(); }); setup(async function () { - cellExecuteEdits.length = 0; + cellExecuteUpdates.length = 0; kernelData.clear(); rpcProtocol = new TestRPCProtocol(); @@ -64,8 +65,8 @@ suite('NotebookKernel', function () { assert.strictEqual(kernelData.has(handle), true); kernelData.set(handle, { ...kernelData.get(handle)!, ...data, }); } - override async $applyExecutionEdits(resource: UriComponents, _edits: CellExecuteEditDto[]) { - cellExecuteEdits.push(..._edits); + override $updateExecutions(data: ICellExecuteUpdateDto[]): void { + cellExecuteUpdates.push(...data); } }); rpcProtocol.set(MainContext.MainThreadNotebookDocuments, new class extends mock() { @@ -260,16 +261,16 @@ suite('NotebookKernel', function () { b.open(); // use barrier to signal that cancellation has happened }); - cellExecuteEdits.length = 0; + cellExecuteUpdates.length = 0; await extHostNotebookKernels.$cancelCells(0, notebook.uri, [0]); await b.wait(); - assert.strictEqual(cellExecuteEdits.length > 0, true); + assert.strictEqual(cellExecuteUpdates.length > 0, true); let found = false; - for (let edit of cellExecuteEdits) { - if (edit.editType === CellEditType.Output) { + for (let edit of cellExecuteUpdates) { + if (edit.editType === CellExecutionUpdateType.Output) { assert.strictEqual(edit.append, false); assert.strictEqual(edit.outputs.length, 1); assert.strictEqual(edit.outputs[0].items.length, 1); @@ -296,14 +297,14 @@ suite('NotebookKernel', function () { task.end(true); }; - cellExecuteEdits.length = 0; + cellExecuteUpdates.length = 0; await extHostNotebookKernels.$cancelCells(0, notebook.uri, [0]); - assert.strictEqual(cellExecuteEdits.length > 0, true); + assert.strictEqual(cellExecuteUpdates.length > 0, true); let found = false; - for (let edit of cellExecuteEdits) { - if (edit.editType === CellEditType.Output) { + for (let edit of cellExecuteUpdates) { + if (edit.editType === CellExecutionUpdateType.Output) { assert.strictEqual(edit.append, false); assert.strictEqual(edit.outputs.length, 1); assert.strictEqual(edit.outputs[0].items.length, 1);