Create cell execution beforehand (#150410)

This commit is contained in:
Peng Lyu 2022-05-25 17:30:39 -07:00 committed by GitHub
parent 5fca335f5b
commit 12cb993238
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 42 additions and 29 deletions

View file

@ -18,6 +18,7 @@ import { INotebookCellExecution, INotebookExecutionStateService } from 'vs/workb
import { INotebookKernel, INotebookKernelChangeEvent, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { INotebookKernel, INotebookKernelChangeEvent, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { ExtHostContext, ExtHostNotebookKernelsShape, ICellExecuteUpdateDto, ICellExecutionCompleteDto, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from '../common/extHost.protocol'; import { ExtHostContext, ExtHostNotebookKernelsShape, ICellExecuteUpdateDto, ICellExecutionCompleteDto, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from '../common/extHost.protocol';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
abstract class MainThreadKernel implements INotebookKernel { abstract class MainThreadKernel implements INotebookKernel {
private readonly _onDidChange = new Emitter<INotebookKernelChangeEvent>(); private readonly _onDidChange = new Emitter<INotebookKernelChangeEvent>();
@ -112,6 +113,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
@ILanguageService private readonly _languageService: ILanguageService, @ILanguageService private readonly _languageService: ILanguageService,
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService, @INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
@INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService, @INotebookExecutionStateService private readonly _notebookExecutionStateService: INotebookExecutionStateService,
@INotebookService private readonly _notebookService: INotebookService,
@INotebookEditorService notebookEditorService: INotebookEditorService @INotebookEditorService notebookEditorService: INotebookEditorService
) { ) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookKernels); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookKernels);
@ -246,7 +248,16 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
$createExecution(handle: number, controllerId: string, rawUri: UriComponents, cellHandle: number): void { $createExecution(handle: number, controllerId: string, rawUri: UriComponents, cellHandle: number): void {
const uri = URI.revive(rawUri); const uri = URI.revive(rawUri);
const execution = this._notebookExecutionStateService.createCellExecution(controllerId, uri, cellHandle); const notebook = this._notebookService.getNotebookTextModel(uri);
if (!notebook) {
throw new Error(`Notebook not found: ${uri.toString()}`);
}
const kernel = this._notebookKernelService.getMatchingKernel(notebook);
if (!kernel.selected || kernel.selected.id !== controllerId) {
throw new Error(`Kernel is not selected: ${kernel.selected?.id} !== ${controllerId}`);
}
const execution = this._notebookExecutionStateService.createCellExecution(uri, cellHandle);
execution.confirm(); execution.confirm();
this._executions.set(handle, execution); this._executions.set(handle, execution);
} }

View file

@ -13,7 +13,7 @@ import { SELECT_KERNEL_ID } from 'vs/workbench/contrib/notebook/browser/controll
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { CellKind, INotebookTextModel, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellKind, INotebookTextModel, NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; import { INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; import { INotebookCellExecution, INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
import { INotebookKernel, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { INotebookKernel, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
export class NotebookExecutionService implements INotebookExecutionService, IDisposable { export class NotebookExecutionService implements INotebookExecutionService, IDisposable {
@ -38,6 +38,16 @@ export class NotebookExecutionService implements INotebookExecutionService, IDis
return; return;
} }
// create cell executions
const cellExecutions: [NotebookCellTextModel, INotebookCellExecution][] = [];
for (const cell of cellsArr) {
const cellExe = this._notebookExecutionStateService.getCellExecution(cell.uri);
if (cell.cellKind !== CellKind.Code || !!cellExe) {
continue;
}
cellExecutions.push([cell, this._notebookExecutionStateService.createCellExecution(notebook.uri, cell.handle)]);
}
let kernel = this._notebookKernelService.getSelectedOrSuggestedKernel(notebook); let kernel = this._notebookKernelService.getSelectedOrSuggestedKernel(notebook);
if (!kernel) { if (!kernel) {
kernel = await this.resolveSourceActions(notebook); kernel = await this.resolveSourceActions(notebook);
@ -49,28 +59,27 @@ export class NotebookExecutionService implements INotebookExecutionService, IDis
} }
if (!kernel) { if (!kernel) {
// clear all pending cell executions
cellExecutions.forEach(cellExe => cellExe[1].complete({}));
return; return;
} }
const executeCells: NotebookCellTextModel[] = []; // filter cell executions based on selected kernel
for (const cell of cellsArr) { const validCellExecutions: INotebookCellExecution[] = [];
const cellExe = this._notebookExecutionStateService.getCellExecution(cell.uri); for (const [cell, cellExecution] of cellExecutions) {
if (cell.cellKind !== CellKind.Code || !!cellExe) {
continue;
}
if (!kernel.supportedLanguages.includes(cell.language)) { if (!kernel.supportedLanguages.includes(cell.language)) {
continue; cellExecution.complete({});
} else {
validCellExecutions.push(cellExecution);
} }
executeCells.push(cell);
} }
if (executeCells.length > 0) { // request execution
if (validCellExecutions.length > 0) {
this._notebookKernelService.selectKernelForNotebook(kernel, notebook); this._notebookKernelService.selectKernelForNotebook(kernel, notebook);
await kernel.executeNotebookCellsRequest(notebook.uri, validCellExecutions.map(c => c.cellHandle));
const exes = executeCells.map(c => this._notebookExecutionStateService.createCellExecution(kernel!.id, notebook.uri, c.handle));
await kernel.executeNotebookCellsRequest(notebook.uri, executeCells.map(c => c.handle));
// the connecting state can change before the kernel resolves executeNotebookCellsRequest // the connecting state can change before the kernel resolves executeNotebookCellsRequest
const unconfirmed = exes.filter(exe => exe.state === NotebookCellExecutionState.Unconfirmed); const unconfirmed = validCellExecutions.filter(exe => exe.state === NotebookCellExecutionState.Unconfirmed);
if (unconfirmed.length) { if (unconfirmed.length) {
this._logService.debug(`NotebookExecutionService#executeNotebookCells completing unconfirmed executions ${JSON.stringify(unconfirmed.map(exe => exe.cellHandle))}`); this._logService.debug(`NotebookExecutionService#executeNotebookCells completing unconfirmed executions ${JSON.stringify(unconfirmed.map(exe => exe.cellHandle))}`);
unconfirmed.forEach(exe => exe.complete({})); unconfirmed.forEach(exe => exe.complete({}));

View file

@ -14,7 +14,6 @@ import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/no
import { CellEditType, CellUri, ICellEditOperation, NotebookCellExecutionState, NotebookCellInternalMetadata, NotebookTextModelWillAddRemoveEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellEditType, CellUri, ICellEditOperation, NotebookCellExecutionState, NotebookCellInternalMetadata, NotebookTextModelWillAddRemoveEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellExecutionUpdateType, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; import { CellExecutionUpdateType, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
import { ICellExecuteUpdate, ICellExecutionComplete, ICellExecutionStateChangedEvent, ICellExecutionStateUpdate, INotebookCellExecution, INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; import { ICellExecuteUpdate, ICellExecutionComplete, ICellExecutionStateChangedEvent, ICellExecutionStateUpdate, INotebookCellExecution, INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
export class NotebookExecutionStateService extends Disposable implements INotebookExecutionStateService { export class NotebookExecutionStateService extends Disposable implements INotebookExecutionStateService {
@ -28,7 +27,6 @@ export class NotebookExecutionStateService extends Disposable implements INotebo
onDidChangeCellExecution = this._onDidChangeCellExecution.event; onDidChangeCellExecution = this._onDidChangeCellExecution.event;
constructor( constructor(
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
@IInstantiationService private readonly _instantiationService: IInstantiationService, @IInstantiationService private readonly _instantiationService: IInstantiationService,
@ILogService private readonly _logService: ILogService, @ILogService private readonly _logService: ILogService,
@INotebookService private readonly _notebookService: INotebookService, @INotebookService private readonly _notebookService: INotebookService,
@ -91,17 +89,12 @@ export class NotebookExecutionStateService extends Disposable implements INotebo
this._onDidChangeCellExecution.fire(new NotebookExecutionEvent(notebookUri, cellHandle)); this._onDidChangeCellExecution.fire(new NotebookExecutionEvent(notebookUri, cellHandle));
} }
createCellExecution(controllerId: string, notebookUri: URI, cellHandle: number): INotebookCellExecution { createCellExecution(notebookUri: URI, cellHandle: number): INotebookCellExecution {
const notebook = this._notebookService.getNotebookTextModel(notebookUri); const notebook = this._notebookService.getNotebookTextModel(notebookUri);
if (!notebook) { if (!notebook) {
throw new Error(`Notebook not found: ${notebookUri.toString()}`); throw new Error(`Notebook not found: ${notebookUri.toString()}`);
} }
const kernel = this._notebookKernelService.getMatchingKernel(notebook);
if (!kernel.selected || kernel.selected.id !== controllerId) {
throw new Error(`Kernel is not selected: ${kernel.selected?.id} !== ${controllerId}`);
}
let notebookExecutionMap = this._executions.get(notebookUri); let notebookExecutionMap = this._executions.get(notebookUri);
if (!notebookExecutionMap) { if (!notebookExecutionMap) {
const listeners = this._instantiationService.createInstance(NotebookExecutionListeners, notebookUri); const listeners = this._instantiationService.createInstance(NotebookExecutionListeners, notebookUri);

View file

@ -50,7 +50,7 @@ export interface INotebookExecutionStateService {
forceCancelNotebookExecutions(notebookUri: URI): void; forceCancelNotebookExecutions(notebookUri: URI): void;
getCellExecutionStatesForNotebook(notebook: URI): INotebookCellExecution[]; getCellExecutionStatesForNotebook(notebook: URI): INotebookCellExecution[];
getCellExecution(cellUri: URI): INotebookCellExecution | undefined; getCellExecution(cellUri: URI): INotebookCellExecution | undefined;
createCellExecution(controllerId: string, notebook: URI, cellHandle: number): INotebookCellExecution; createCellExecution(notebook: URI, cellHandle: number): INotebookCellExecution;
} }
export interface INotebookCellExecution { export interface INotebookCellExecution {

View file

@ -94,7 +94,7 @@ suite('NotebookExecutionStateService', () => {
const executionStateService: INotebookExecutionStateService = instantiationService.get(INotebookExecutionStateService); const executionStateService: INotebookExecutionStateService = instantiationService.get(INotebookExecutionStateService);
const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true); const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true);
executionStateService.createCellExecution(kernel.id, viewModel.uri, cell.handle); executionStateService.createCellExecution(viewModel.uri, cell.handle);
assert.strictEqual(didCancel, false); assert.strictEqual(didCancel, false);
viewModel.notebookDocument.applyEdits([{ viewModel.notebookDocument.applyEdits([{
editType: CellEditType.Replace, index: 0, count: 1, cells: [] editType: CellEditType.Replace, index: 0, count: 1, cells: []
@ -113,7 +113,7 @@ suite('NotebookExecutionStateService', () => {
const executionStateService: INotebookExecutionStateService = instantiationService.get(INotebookExecutionStateService); const executionStateService: INotebookExecutionStateService = instantiationService.get(INotebookExecutionStateService);
const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true); const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true);
const exe = executionStateService.createCellExecution(kernel.id, viewModel.uri, cell.handle); const exe = executionStateService.createCellExecution(viewModel.uri, cell.handle);
let didFire = false; let didFire = false;
disposables.add(executionStateService.onDidChangeCellExecution(e => { disposables.add(executionStateService.onDidChangeCellExecution(e => {
@ -154,7 +154,7 @@ suite('NotebookExecutionStateService', () => {
deferred.complete(); deferred.complete();
})); }));
executionStateService.createCellExecution(kernel.id, viewModel.uri, cell.handle); executionStateService.createCellExecution(viewModel.uri, cell.handle);
return deferred.p; return deferred.p;
}); });
@ -170,7 +170,7 @@ suite('NotebookExecutionStateService', () => {
const executionStateService: INotebookExecutionStateService = instantiationService.get(INotebookExecutionStateService); const executionStateService: INotebookExecutionStateService = instantiationService.get(INotebookExecutionStateService);
const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true); const cell = insertCellAtIndex(viewModel, 0, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true);
executionStateService.createCellExecution(kernel.id, viewModel.uri, cell.handle); executionStateService.createCellExecution(viewModel.uri, cell.handle);
const exe = executionStateService.getCellExecution(cell.uri); const exe = executionStateService.getCellExecution(cell.uri);
assert.ok(exe); assert.ok(exe);

View file

@ -422,7 +422,7 @@ class TestNotebookExecutionStateService implements INotebookExecutionStateServic
return this._executions.get(cellUri); return this._executions.get(cellUri);
} }
createCellExecution(controllerId: string, notebook: URI, cellHandle: number): INotebookCellExecution { createCellExecution(notebook: URI, cellHandle: number): INotebookCellExecution {
const onComplete = () => this._executions.delete(CellUri.generate(notebook, cellHandle)); const onComplete = () => this._executions.delete(CellUri.generate(notebook, cellHandle));
const exe = new TestCellExecution(notebook, cellHandle, onComplete); const exe = new TestCellExecution(notebook, cellHandle, onComplete);
this._executions.set(CellUri.generate(notebook, cellHandle), exe); this._executions.set(CellUri.generate(notebook, cellHandle), exe);