Skip to content

Commit

Permalink
Add cancellation and progress bars for "execute notebook"
Browse files Browse the repository at this point in the history
Fix #93886
  • Loading branch information
roblourens committed Apr 1, 2020
1 parent 433086b commit 2f984aa
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 23 deletions.
4 changes: 4 additions & 0 deletions src/vs/workbench/contrib/notebook/browser/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ export const COPY_CELL_UP_COMMAND_ID = 'workbench.notebook.cell.copyUp';
export const COPY_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.copyDown';

export const EXECUTE_CELL_COMMAND_ID = 'workbench.notebook.cell.execute';
export const EXECUTE_ACTIVE_CELL_COMMAND_ID = 'workbench.notebook.cell.executeActive';
export const CANCEL_CELL_COMMAND_ID = 'workbench.notebook.cell.cancelExecution';
export const EXECUTE_NOTEBOOK_COMMAND_ID = 'workbench.notebook.executeNotebook';
export const CANCEL_NOTEBOOK_COMMAND_ID = 'workbench.notebook.cancelExecution';

// Cell sizing related
export const CELL_MARGIN = 20;
Expand All @@ -44,3 +47,4 @@ export const NOTEBOOK_CELL_RUN_STATE_CONTEXT_KEY = 'notebookCellRunState'; // id

// Notebook context keys
export const NOTEBOOK_EDITABLE_CONTEXT_KEY = 'notebookEditable';
export const NOTEBOOK_EXECUTING_KEY = 'notebookExecuting';
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@
*--------------------------------------------------------------------------------------------*/

import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { localize } from 'vs/nls';
import { Action2, IAction2Options, MenuId, MenuItemAction, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { InputFocusedContext, InputFocusedContextKey, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { COPY_CELL_DOWN_COMMAND_ID, COPY_CELL_UP_COMMAND_ID, DELETE_CELL_COMMAND_ID, EDIT_CELL_COMMAND_ID, EXECUTE_CELL_COMMAND_ID, INSERT_CODE_CELL_ABOVE_COMMAND_ID, INSERT_CODE_CELL_BELOW_COMMAND_ID, INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID, INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, MOVE_CELL_DOWN_COMMAND_ID, MOVE_CELL_UP_COMMAND_ID, SAVE_CELL_COMMAND_ID, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, CANCEL_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants';
import { BaseCellRenderTemplate, CellEditState, ICellViewModel, INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, CellRunState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { CANCEL_CELL_COMMAND_ID, CANCEL_NOTEBOOK_COMMAND_ID, COPY_CELL_DOWN_COMMAND_ID, COPY_CELL_UP_COMMAND_ID, DELETE_CELL_COMMAND_ID, EDIT_CELL_COMMAND_ID, EXECUTE_ACTIVE_CELL_COMMAND_ID, EXECUTE_CELL_COMMAND_ID, EXECUTE_NOTEBOOK_COMMAND_ID, INSERT_CODE_CELL_ABOVE_COMMAND_ID, INSERT_CODE_CELL_BELOW_COMMAND_ID, INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID, INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, MOVE_CELL_DOWN_COMMAND_ID, MOVE_CELL_UP_COMMAND_ID, NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_EXECUTING_KEY, SAVE_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants';
import { BaseCellRenderTemplate, CellEditState, CellRunState, ICellViewModel, INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';

const enum CellToolbarOrder {
MoveCellUp,
Expand Down Expand Up @@ -73,7 +72,7 @@ registerAction2(class extends Action2 {
}
}

context.cell.currentTokenSource?.cancel();
return context.notebookEditor.cancelNotebookCellExecution(context.cell);
}
});

Expand Down Expand Up @@ -186,34 +185,45 @@ registerAction2(class extends Action2 {
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.executeNotebook',
id: EXECUTE_NOTEBOOK_COMMAND_ID,
title: localize('notebookActions.executeNotebook', "Execute Notebook")
});
}

async run(accessor: ServicesAccessor): Promise<void> {
let editorService = accessor.get(IEditorService);
let notebookService = accessor.get(INotebookService);

let resource = editorService.activeEditor?.resource;

if (!resource) {
const editorService = accessor.get(IEditorService);
const editor = getActiveNotebookEditor(editorService);
if (!editor) {
return;
}

let notebookProviders = notebookService.getContributedNotebookProviders(resource!);
return editor.executeNotebook();
}
});

if (notebookProviders.length > 0) {
let viewType = notebookProviders[0].id;
notebookService.executeNotebook(viewType, resource);
registerAction2(class extends Action2 {
constructor() {
super({
id: CANCEL_NOTEBOOK_COMMAND_ID,
title: localize('notebookActions.cancelNotebook', "Cancel Notebook Execution")
});
}

async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const editor = getActiveNotebookEditor(editorService);
if (!editor) {
return;
}

return editor.cancelNotebookExecution();
}
});

registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.executeNotebookCell',
id: EXECUTE_ACTIVE_CELL_COMMAND_ID,
title: localize('notebookActions.executeNotebookCell', "Execute Notebook Active Cell")
});
}
Expand Down Expand Up @@ -309,19 +319,30 @@ registerAction2(class extends Action2 {

MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
command: {
id: 'workbench.action.executeNotebook',
id: EXECUTE_NOTEBOOK_COMMAND_ID,
title: localize('notebookActions.menu.executeNotebook', "Execute Notebook (Run all cells)"),
icon: { id: 'codicon/run-all' }
},
order: -1,
group: 'navigation',
when: NOTEBOOK_EDITOR_FOCUSED
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.not(NOTEBOOK_EXECUTING_KEY))
});

MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
command: {
id: CANCEL_NOTEBOOK_COMMAND_ID,
title: localize('notebookActions.menu.cancelNotebook', "Cancel Notebook Execution"),
icon: { id: 'codicon/stop' }
},
order: -1,
group: 'navigation',
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK)
});


MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
command: {
id: 'workbench.action.executeNotebookCell',
id: EXECUTE_ACTIVE_CELL_COMMAND_ID,
title: localize('notebookActions.menu.execute', "Execute Notebook Cell"),
icon: { id: 'codicon/run' }
},
Expand Down
18 changes: 17 additions & 1 deletion src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { Range } from 'vs/editor/common/core/range';
import { FindMatch } from 'vs/editor/common/model';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { NOTEBOOK_EDITABLE_CONTEXT_KEY } from 'vs/workbench/contrib/notebook/browser/constants';
import { NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_EXECUTING_KEY } from 'vs/workbench/contrib/notebook/browser/constants';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { CellKind, IOutput, IRenderOutput, NotebookCellMetadata, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
Expand All @@ -23,6 +23,7 @@ export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey

export const NOTEBOOK_EDITOR_FOCUSED = new RawContextKey<boolean>('notebookEditorFocused', false);
export const NOTEBOOK_EDITOR_EDITABLE = new RawContextKey<boolean>(NOTEBOOK_EDITABLE_CONTEXT_KEY, true);
export const NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK = new RawContextKey<boolean>(NOTEBOOK_EXECUTING_KEY, false);

export interface NotebookLayoutInfo {
width: number;
Expand Down Expand Up @@ -150,6 +151,21 @@ export interface INotebookEditor {
*/
executeNotebookCell(cell: ICellViewModel): Promise<void>;

/**
* Cancel the cell execution
*/
cancelNotebookCellExecution(cell: ICellViewModel): void;

/**
* Executes all notebook cells in order
*/
executeNotebook(): Promise<void>;

/**
* Cancel the notebook execution
*/
cancelNotebookExecution(): void;

/**
* Get current active cell
*/
Expand Down
60 changes: 58 additions & 2 deletions src/vs/workbench/contrib/notebook/browser/notebookEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
import { EditorOptions, IEditorCloseEvent, IEditorMemento } from 'vs/workbench/common/editor';
import { CELL_MARGIN, CELL_RUN_GUTTER, EDITOR_TOP_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
import { NotebookFindWidget } from 'vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget';
import { CellEditState, CellFocusMode, ICellViewModel, INotebookEditor, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellEditState, CellFocusMode, ICellViewModel, INotebookEditor, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookEditorInput, NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
Expand Down Expand Up @@ -103,6 +103,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
private dimension: DOM.Dimension | null = null;
private editorFocus: IContextKey<boolean> | null = null;
private editorEditable: IContextKey<boolean> | null = null;
private editorExecutingNotebook: IContextKey<boolean> | null = null;
private outputRenderer: OutputRenderer;
private findWidget: NotebookFindWidget;

Expand All @@ -115,6 +116,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
// @IEditorProgressService private readonly progressService: IEditorProgressService,
) {
super(NotebookEditor.ID, telemetryService, themeService, storageService);

Expand Down Expand Up @@ -159,6 +161,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {

this.editorEditable = NOTEBOOK_EDITOR_EDITABLE.bindTo(this.contextKeyService);
this.editorEditable.set(true);
this.editorExecutingNotebook = NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK.bindTo(this.contextKeyService);
}

private generateFontInfo(): void {
Expand Down Expand Up @@ -663,8 +666,62 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
return undefined;
}

cancelNotebookExecution(): void {
if (!this.notebookViewModel!.currentTokenSource) {
throw new Error('Notebook is not executing');
}


this.notebookViewModel!.currentTokenSource.cancel();
this.notebookViewModel!.currentTokenSource = undefined;
}

async executeNotebook(): Promise<void> {
// return this.progressService.showWhile(this._executeNotebook());
return this._executeNotebook();
}

async _executeNotebook(): Promise<void> {
if (this.notebookViewModel!.currentTokenSource) {
return;
}

const tokenSource = new CancellationTokenSource();
try {
this.editorExecutingNotebook!.set(true);
this.notebookViewModel!.currentTokenSource = tokenSource;

for (let cell of this.notebookViewModel!.viewCells) {
if (cell.cellKind === CellKind.Code) {
await this._executeNotebookCell(cell, tokenSource);
}
}
} finally {
this.editorExecutingNotebook!.set(false);
this.notebookViewModel!.currentTokenSource = undefined;
tokenSource.dispose();
}
}

cancelNotebookCellExecution(cell: ICellViewModel): void {
if (!cell.currentTokenSource) {
throw new Error('Cell is not executing');
}

cell.currentTokenSource.cancel();
cell.currentTokenSource = undefined;
}

async executeNotebookCell(cell: ICellViewModel): Promise<void> {
const tokenSource = new CancellationTokenSource();
try {
this._executeNotebookCell(cell, tokenSource);
} finally {
tokenSource.dispose();
}
}

async _executeNotebookCell(cell: ICellViewModel, tokenSource: CancellationTokenSource): Promise<void> {
try {
cell.currentTokenSource = tokenSource;
const provider = this.notebookService.getContributedNotebookProviders(this.viewModel!.uri)[0];
Expand All @@ -677,7 +734,6 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
} finally {
cell.currentTokenSource = undefined;
tokenSource.dispose();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewMod
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
import { CellKind, ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookEventDispatcher, NotebookMetadataChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import { CancellationTokenSource } from 'vs/base/common/cancellation';

export interface INotebookEditorViewState {
editingCells: { [key: number]: boolean };
Expand Down Expand Up @@ -60,6 +61,16 @@ export class NotebookViewModel extends Disposable {
private _localStore: DisposableStore = this._register(new DisposableStore());
private _viewCells: CellViewModel[] = [];

private _currentTokenSource: CancellationTokenSource | undefined;

get currentTokenSource(): CancellationTokenSource | undefined {
return this._currentTokenSource;
}

set currentTokenSource(v: CancellationTokenSource | undefined) {
this._currentTokenSource = v;
}

get viewCells(): ICellViewModel[] {
return this._viewCells;
}
Expand Down
12 changes: 12 additions & 0 deletions src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ export class TestNotebookEditor implements INotebookEditor {
constructor(
) { }

cancelNotebookCellExecution(cell: ICellViewModel): void {
throw new Error('Method not implemented.');
}

executeNotebook(): Promise<void> {
throw new Error('Method not implemented.');
}

cancelNotebookExecution(): void {
throw new Error('Method not implemented.');
}

executeNotebookCell(cell: ICellViewModel): Promise<void> {
throw new Error('Method not implemented.');
}
Expand Down

0 comments on commit 2f984aa

Please sign in to comment.