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

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