diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 89a22364dc6..462c1a73fcd 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -86,6 +86,17 @@ const enum CellToolbarOrder { DeleteCell } +export interface INotebookActionContext { + readonly cellTemplate?: BaseCellRenderTemplate; + readonly cell?: ICellViewModel; + readonly notebookEditor: INotebookEditor; + readonly ui?: boolean; +} + +export interface INotebookCellActionContext extends INotebookActionContext { + cell: ICellViewModel; +} + abstract class NotebookAction extends Action2 { constructor(desc: IAction2Options) { if (desc.f1 !== false) { @@ -112,9 +123,9 @@ abstract class NotebookAction extends Action2 { super(desc); } - async run(accessor: ServicesAccessor, context?: INotebookCellActionContext): Promise { - if (!this.isCellActionContext(context)) { - context = this.getActiveCellContext(accessor); + async run(accessor: ServicesAccessor, context?: INotebookActionContext): Promise { + if (!this.isNotebookActionContext(context)) { + context = this.getActiveEditorContext(accessor); if (!context) { return; } @@ -123,13 +134,13 @@ abstract class NotebookAction extends Action2 { this.runWithContext(accessor, context); } - abstract async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise; + abstract async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise; - private isCellActionContext(context?: INotebookCellActionContext): context is INotebookCellActionContext { - return !!context && !!context.cell && !!context.notebookEditor; + private isNotebookActionContext(context?: unknown): context is INotebookActionContext { + return !!context && !!(context as INotebookActionContext).notebookEditor; } - private getActiveCellContext(accessor: ServicesAccessor): INotebookCellActionContext | undefined { + protected getActiveEditorContext(accessor: ServicesAccessor): INotebookActionContext | undefined { const editorService = accessor.get(IEditorService); const editor = getActiveNotebookEditor(editorService); @@ -138,10 +149,6 @@ abstract class NotebookAction extends Action2 { } const activeCell = editor.getActiveCell(); - if (!activeCell) { - return; - } - return { cell: activeCell, notebookEditor: editor @@ -149,7 +156,28 @@ abstract class NotebookAction extends Action2 { } } -registerAction2(class extends NotebookAction { +abstract class NotebookCellAction extends NotebookAction { + protected isCellActionContext(context?: unknown): context is INotebookCellActionContext { + return !!context && !!(context as INotebookCellActionContext).notebookEditor && !!(context as INotebookCellActionContext).cell; + } + + async run(accessor: ServicesAccessor, context?: INotebookCellActionContext): Promise { + if (!this.isCellActionContext(context)) { + const activeEditorContext = this.getActiveEditorContext(accessor); + if (this.isCellActionContext(activeEditorContext)) { + context = activeEditorContext; + } else { + return; + } + } + + this.runWithContext(accessor, context); + } + + abstract async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise; +} + +registerAction2(class extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_COMMAND_ID, @@ -171,7 +199,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: CANCEL_CELL_COMMAND_ID, @@ -222,7 +250,7 @@ export class CancelCellAction extends MenuItemAction { } -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_SELECT_BELOW, @@ -258,7 +286,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: EXECUTE_CELL_INSERT_BELOW, @@ -292,7 +320,7 @@ registerAction2(class extends NotebookAction { }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { renderAllMarkdownCells(context); } }); @@ -305,7 +333,7 @@ registerAction2(class extends NotebookAction { }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { renderAllMarkdownCells(context); const editorGroupService = accessor.get(IEditorGroupsService); @@ -321,7 +349,7 @@ registerAction2(class extends NotebookAction { } }); -function renderAllMarkdownCells(context: INotebookCellActionContext): void { +function renderAllMarkdownCells(context: INotebookActionContext): void { context.notebookEditor.viewModel!.viewCells.forEach(cell => { if (cell.cellKind === CellKind.Markdown) { cell.editState = CellEditState.Preview; @@ -337,7 +365,7 @@ registerAction2(class extends NotebookAction { }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { return context.notebookEditor.cancelNotebookExecution(); } }); @@ -364,7 +392,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { when: ContextKeyExpr.and(NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK) }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: CHANGE_CELL_TO_CODE_COMMAND_ID, @@ -383,7 +411,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: CHANGE_CELL_TO_MARKDOWN_COMMAND_ID, @@ -456,13 +484,6 @@ export async function changeCellToKind(kind: CellKind, context: INotebookCellAct return newCell; } -export interface INotebookCellActionContext { - readonly cellTemplate?: BaseCellRenderTemplate; - readonly cell: ICellViewModel; - readonly notebookEditor: INotebookEditor; - readonly ui?: boolean; -} - abstract class InsertCellCommand extends NotebookAction { constructor( desc: Readonly, @@ -472,7 +493,7 @@ abstract class InsertCellCommand extends NotebookAction { super(desc); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { const newCell = context.notebookEditor.insertNotebookCell(context.cell, this.kind, this.direction, undefined, context.ui); if (newCell) { context.notebookEditor.focusNotebookCell(newCell, 'editor'); @@ -558,7 +579,7 @@ MenuRegistry.appendMenuItem(MenuId.NotebookCellBetween, { group: 'inline' }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -587,7 +608,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -624,7 +645,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -657,12 +678,6 @@ registerAction2(class extends NotebookAction { const nextCellIdx = index < context.notebookEditor.viewModel!.length ? index : context.notebookEditor.viewModel!.length - 1; if (nextCellIdx >= 0) { context.notebookEditor.focusNotebookCell(context.notebookEditor.viewModel!.viewCells[nextCellIdx], 'container'); - } else { - // No cells left, insert a new empty one - const newCell = context.notebookEditor.insertNotebookCell(undefined, context.cell.cellKind); - if (newCell) { - context.notebookEditor.focusNotebookCell(newCell, 'editor'); - } } } } @@ -688,7 +703,7 @@ async function copyCell(context: INotebookCellActionContext, direction: 'up' | ' } } -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -708,7 +723,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -728,7 +743,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -750,7 +765,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -779,7 +794,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -848,7 +863,7 @@ registerAction2(class extends NotebookAction { }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext) { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext) { const notebookService = accessor.get(INotebookService); const pasteCells = notebookService.getToCopy(); @@ -862,7 +877,7 @@ registerAction2(class extends NotebookAction { return; } - const currCellIndex = viewModel.getCellIndex(context!.cell); + const currCellIndex = context.cell && viewModel.getCellIndex(context.cell); let topPastedCell: CellViewModel | undefined = undefined; pasteCells.items.reverse().map(cell => { @@ -880,8 +895,8 @@ registerAction2(class extends NotebookAction { return cell; } }).forEach(pasteCell => { - topPastedCell = viewModel.insertCell(currCellIndex + 1, pasteCell, true); - return; + const newIdx = typeof currCellIndex === 'number' ? currCellIndex + 1 : 0; + topPastedCell = viewModel.insertCell(newIdx, pasteCell, true); }); if (topPastedCell) { @@ -890,7 +905,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -909,7 +924,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -928,7 +943,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: NOTEBOOK_FOCUS_NEXT_EDITOR, @@ -975,7 +990,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: NOTEBOOK_FOCUS_PREVIOUS_EDITOR, @@ -1019,7 +1034,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: FOCUS_IN_OUTPUT_COMMAND_ID, @@ -1040,7 +1055,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: FOCUS_OUT_OUTPUT_COMMAND_ID, @@ -1075,7 +1090,7 @@ registerAction2(class extends NotebookAction { }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { await context.notebookEditor.viewModel?.undo(); } }); @@ -1093,7 +1108,7 @@ registerAction2(class extends NotebookAction { }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { await context.notebookEditor.viewModel?.redo(); } }); @@ -1112,7 +1127,7 @@ registerAction2(class extends NotebookAction { }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { const editor = context.notebookEditor; if (!editor.viewModel || !editor.viewModel.length) { return; @@ -1137,7 +1152,7 @@ registerAction2(class extends NotebookAction { }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { const editor = context.notebookEditor; if (!editor.viewModel || !editor.viewModel.length) { return; @@ -1148,7 +1163,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: CLEAR_CELL_OUTPUTS_COMMAND_ID, @@ -1183,7 +1198,7 @@ interface ILanguagePickInput extends IQuickPickItem { description: string; } -export class ChangeCellLanguageAction extends NotebookAction { +export class ChangeCellLanguageAction extends NotebookCellAction { constructor() { super({ id: CHANGE_CELL_LANGUAGE, @@ -1293,7 +1308,7 @@ registerAction2(class extends NotebookAction { }); } - async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise { const editor = context.notebookEditor; if (!editor.viewModel || !editor.viewModel.length) { return; @@ -1312,7 +1327,7 @@ async function splitCell(context: INotebookCellActionContext): Promise { } } -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -1346,7 +1361,7 @@ async function joinCells(context: INotebookCellActionContext, direction: 'above' } } -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -1365,7 +1380,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super( { @@ -1384,7 +1399,7 @@ registerAction2(class extends NotebookAction { } }); -registerAction2(class extends NotebookAction { +registerAction2(class extends NotebookCellAction { constructor() { super({ id: CENTER_ACTIVE_CELL, diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts b/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts index afbc189abe5..6e5cb2b9edb 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/status/editorStatus.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; -import { INotebookCellActionContext, NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; +import { INotebookActionContext, NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/contrib/coreActions'; import { INotebookEditor, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -31,7 +31,7 @@ registerAction2(class extends Action2 { }); } - async run(accessor: ServicesAccessor, context?: INotebookCellActionContext): Promise { + async run(accessor: ServicesAccessor, context?: INotebookActionContext): Promise { const editorService = accessor.get(IEditorService); const notebookService = accessor.get(INotebookService); const quickInputService = accessor.get(IQuickInputService);