Add NotebookExecutionService

Towards #125668
This commit is contained in:
Rob Lourens 2021-08-10 21:10:12 -07:00
parent 8bf9cfa21b
commit 99104943f5
8 changed files with 307 additions and 107 deletions

View file

@ -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;
}
}

View file

@ -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<number, [kernel: MainThreadKernel, registraion: IDisposable]>();
private readonly _proxy: ExtHostNotebookKernelsShape;
private readonly _executions = new Map<number, MainThreadExecution>();
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<void> {
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<ICellExecuteUpdate[]>();
readonly onDidChange: Event<Readonly<ICellExecuteUpdate[]>> = this._onDidChange.event;
constructor(
readonly id: number,
readonly notebook: URI,
readonly cellHandle: number,
) { }
update(updates: ICellExecuteUpdate[]): void {
this._onDidChange.fire(updates);
}
}

View file

@ -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<boolean>;
@ -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<void>;
$addExecution(handle: number, uri: UriComponents, cellHandle: number): void;
$updateExecutions(data: ICellExecuteUpdateDto[]): void;
}
export interface MainThreadNotebookRenderersShape extends IDisposable {

View file

@ -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<void>();
readonly onDidChangeState = this._onDidChangeState.event;
@ -332,7 +335,7 @@ class NotebookCellExecutionTask extends Disposable {
private readonly _tokenSource = this._register(new CancellationTokenSource());
private readonly _collector: TimeoutBasedCollector<CellExecuteEditDto>;
private readonly _collector: TimeoutBasedCollector<ICellExecuteUpdateDto>;
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<void> {
await this._collector.addItem(edit);
private async updateSoon(update: ICellExecuteUpdateDto): Promise<void> {
await this._collector.addItem(update);
}
private async applyEdits(edits: CellExecuteEditDto[]): Promise<void> {
return this._proxy.$applyExecutionEdits(this._document.uri, edits);
private async update(update: ICellExecuteUpdateDto | ICellExecuteUpdateDto[]): Promise<void> {
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<void> {
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<void> {
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<T> {
constructor(
private readonly delay: number,
private readonly callback: (items: T[]) => Promise<void>) { }
private readonly callback: (items: T[]) => Promise<void> | void) { }
addItem(item: T): Promise<void> {
this.batch.push(item);

View file

@ -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 = {};

View file

@ -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<NotebookCellInternalMetadata> = {
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');
}

View file

@ -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<Readonly<ICellExecuteUpdate[]>>;
}
export const INotebookExecutionService = createDecorator<INotebookExecutionService>('INotebookExecutionService');
export interface INotebookExecutionService {
_serviceBrand: undefined;
registerNotebookCellExecution(execution: INotebookCellExecution): void;
}

View file

@ -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<number, INotebookKernelDto2>();
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<MainThreadNotebookDocumentsShape>() {
@ -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);