diff --git a/news/1 Enhancements/7800.md b/news/1 Enhancements/7800.md new file mode 100644 index 000000000000..647a10db36eb --- /dev/null +++ b/news/1 Enhancements/7800.md @@ -0,0 +1 @@ +Add command palette commands for native editor (run all cells, run selected cell, add new cell). And remove interactive window commands from contexts where they don't apply. \ No newline at end of file diff --git a/package.json b/package.json index 34f20e4f5b16..f8ffdaa1285c 100644 --- a/package.json +++ b/package.json @@ -511,7 +511,7 @@ }, { "command": "python.datascience.notebookeditor.removeallcells", - "title": "%python.command.python.datascience.removeallcells.title%", + "title": "%python.command.python.datascience.notebookeditor.removeallcells.title%", "category": "Python" }, { @@ -524,6 +524,21 @@ "title": "%python.command.python.datascience.restartkernel.title%", "category": "Python" }, + { + "command": "python.datascience.notebookeditor.runallcells", + "title": "%python.command.python.datascience.notebookeditor.runallcells.title%", + "category": "Python" + }, + { + "command": "python.datascience.notebookeditor.runselectedcell", + "title": "%python.command.python.datascience.notebookeditor.runselectedcell.title%", + "category": "Python" + }, + { + "command": "python.datascience.notebookeditor.addcellbelow", + "title": "%python.command.python.datascience.notebookeditor.addcellbelow.title%", + "category": "Python" + }, { "command": "python.datascience.expandallcells", "title": "%python.command.python.datascience.expandallcells.title%", @@ -778,7 +793,25 @@ "command": "python.datascience.runallcells", "title": "%python.command.python.datascience.runallcells.title%", "category": "Python", - "when": "python.datascience.featureenabled" + "when": "python.datascience.hascodecells && python.datascience.featureenabled" + }, + { + "command": "python.datascience.scrolltocell", + "title": "%python.command.python.datascience.scrolltocell.title%", + "category": "Python", + "when": "false" + }, + { + "command": "python.datascience.debugcell", + "title": "%python.command.python.datascience.debugcell.title%", + "category": "Python", + "when": "python.datascience.hascodecells && python.datascience.featureenabled" + }, + { + "command": "python.datascience.runcell", + "title": "%python.command.python.datascience.runcell.title%", + "category": "Python", + "when": "python.datascience.hascodecells && python.datascience.featureenabled" }, { "command": "python.datascience.runFileInteractive", @@ -858,7 +891,7 @@ }, { "command": "python.datascience.notebookeditor.removeallcells", - "title": "%python.command.python.datascience.removeallcells.title%", + "title": "%python.command.python.datascience.notebookeditor.removeallcells.title%", "category": "Python", "when": "python.datascience.havenativecells && python.datascience.featureenabled" }, @@ -874,6 +907,24 @@ "category": "Python", "when": "python.datascience.havenative && python.datascience.featureenabled" }, + { + "command": "python.datascience.notebookeditor.runallcells", + "title": "%python.command.python.datascience.notebookeditor.runallcells.title%", + "category": "Python", + "when": "python.datascience.havenative && python.datascience.featureenabled" + }, + { + "command": "python.datascience.notebookeditor.runselectedcell", + "title": "%python.command.python.datascience.notebookeditor.runselectedcell.title%", + "category": "Python", + "when": "python.datascience.havenative && python.datascience.featureenabled && python.datascience.havecellselected" + }, + { + "command": "python.datascience.notebookeditor.addcellbelow", + "title": "%python.command.python.datascience.notebookeditor.addcellbelow.title%", + "category": "Python", + "when": "python.datascience.havenative && python.datascience.featureenabled" + }, { "command": "python.datascience.expandallcells", "title": "%python.command.python.datascience.expandallcells.title%", @@ -906,7 +957,7 @@ "command": "python.datascience.addcellbelow", "title": "%python.command.python.datascience.addcellbelow.title%", "category": "Python", - "when": "python.datascience.featureenabled" + "when": "python.datascience.hascodecells && python.datascience.featureenabled" }, { "command": "python.datascience.createnewnotebook", diff --git a/package.nls.json b/package.nls.json index 3ae5d1130558..3248de9ec5bc 100644 --- a/package.nls.json +++ b/package.nls.json @@ -33,6 +33,7 @@ "python.command.python.datascience.runFileInteractive.title": "Run Current File in Python Interactive Window", "python.command.python.datascience.debugFileInteractive.title": "Debug Current File in Python Interactive Window", "python.command.python.datascience.runallcells.title": "Run All Cells", + "python.command.python.datascience.notebookeditor.runallcells.title": "Run All Notebook Cells", "python.command.python.datascience.runallcellsabove.title": "Run Above", "python.command.python.datascience.runcellandallbelow.title": "Run Below", "python.command.python.datascience.runallcellsabove.palette.title": "Run Cells Above Current Cell", @@ -60,6 +61,9 @@ "python.command.python.datascience.undocells.title": "Undo Last Python Interactive Action", "python.command.python.datascience.redocells.title": "Redo Last Python Interactive Action", "python.command.python.datascience.removeallcells.title": "Delete All Python Interactive Cells", + "python.command.python.datascience.notebookeditor.removeallcells.title": "Delete All Notebook Editor Cells", + "python.command.python.datascience.notebookeditor.runselectedcell.title": "Run Selected Notebook Cell", + "python.command.python.datascience.notebookeditor.addcellbelow.title": "Add Empty Cell to Notebook File", "python.command.python.datascience.interruptkernel.title": "Interrupt IPython Kernel", "python.command.python.datascience.restartkernel.title": "Restart IPython Kernel", "python.command.python.datascience.expandallcells.title": "Expand All Python Interactive Cells", diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts index a059e5b4f6fc..bc1c061cd8e6 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -59,6 +59,9 @@ interface ICommandNameWithoutArgumentTypeMapping { [DSCommands.NotebookEditorRemoveAllCells]: []; [DSCommands.NotebookEditorInterruptKernel]: []; [DSCommands.NotebookEditorRestartKernel]: []; + [DSCommands.NotebookEditorRunAllCells]: []; + [DSCommands.NotebookEditorRunSelectedCell]: []; + [DSCommands.NotebookEditorAddCellBelow]: []; [DSCommands.ExpandAllCells]: []; [DSCommands.CollapseAllCells]: []; [DSCommands.ExportOutputAsNotebook]: []; diff --git a/src/client/datascience/constants.ts b/src/client/datascience/constants.ts index 6b22853385a8..6bc7f42a4772 100644 --- a/src/client/datascience/constants.ts +++ b/src/client/datascience/constants.ts @@ -35,6 +35,9 @@ export namespace Commands { export const NotebookEditorRemoveAllCells = 'python.datascience.notebookeditor.removeallcells'; export const NotebookEditorInterruptKernel = 'python.datascience.notebookeditor.interruptkernel'; export const NotebookEditorRestartKernel = 'python.datascience.notebookeditor.restartkernel'; + export const NotebookEditorRunAllCells = 'python.datascience.notebookeditor.runallcells'; + export const NotebookEditorRunSelectedCell = 'python.datascience.notebookeditor.runselectedcell'; + export const NotebookEditorAddCellBelow = 'python.datascience.notebookeditor.addcellbelow'; export const ExpandAllCells = 'python.datascience.expandallcells'; export const CollapseAllCells = 'python.datascience.collapseallcells'; export const ExportOutputAsNotebook = 'python.datascience.exportoutputasnotebook'; @@ -71,6 +74,7 @@ export namespace EditorContexts { export const HaveNativeCells = 'python.datascience.havenativecells'; export const HaveNativeRedoableCells = 'python.datascience.havenativeredoablecells'; export const HaveNative = 'python.datascience.havenative'; + export const HaveCellSelected = 'python.datascience.havecellselected'; } export namespace RegExpValues { diff --git a/src/client/datascience/interactive-common/interactiveWindowTypes.ts b/src/client/datascience/interactive-common/interactiveWindowTypes.ts index c46a6bad5dd3..203dbdd470bc 100644 --- a/src/client/datascience/interactive-common/interactiveWindowTypes.ts +++ b/src/client/datascience/interactive-common/interactiveWindowTypes.ts @@ -72,7 +72,9 @@ export namespace InteractiveWindowMessages { export const SaveAll = 'save_all'; export const NativeCommand = 'native_command'; export const VariablesComplete = 'variables_complete'; - + export const NotebookRunAllCells = 'notebook_run_all_cells'; + export const NotebookRunSelectedCell = 'notebook_run_selected_cell'; + export const NotebookAddCellBelow = 'notebook_add_cell_below'; } export enum NativeCommandType { @@ -318,4 +320,7 @@ export class IInteractiveWindowMapping { public [InteractiveWindowMessages.SaveAll]: ISaveAll; public [InteractiveWindowMessages.NativeCommand]: INativeCommand; public [InteractiveWindowMessages.VariablesComplete]: never | undefined; + public [InteractiveWindowMessages.NotebookRunAllCells]: never | undefined; + public [InteractiveWindowMessages.NotebookRunSelectedCell]: never | undefined; + public [InteractiveWindowMessages.NotebookAddCellBelow]: never | undefined; } diff --git a/src/client/datascience/interactive-ipynb/nativeEditor.ts b/src/client/datascience/interactive-ipynb/nativeEditor.ts index ee49ccfbc2c4..9cc529966dfe 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditor.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditor.ts @@ -225,6 +225,18 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor { return this.ipynbProvider.getNotebookOptions(); } + public runAllCells() { + this.postMessage(InteractiveWindowMessages.NotebookRunAllCells).ignoreErrors(); + } + + public runSelectedCell() { + this.postMessage(InteractiveWindowMessages.NotebookRunSelectedCell).ignoreErrors(); + } + + public addCellBelow() { + this.postMessage(InteractiveWindowMessages.NotebookAddCellBelow).ignoreErrors(); + } + protected async reopen(cells: ICell[]): Promise { try { super.reload(); @@ -317,10 +329,13 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor { interactiveContext.set(!this.isDisposed).catch(); const interactiveCellsContext = new ContextKey(EditorContexts.HaveNativeCells, this.commandManager); const redoableContext = new ContextKey(EditorContexts.HaveNativeRedoableCells, this.commandManager); + const hasCellSelectedContext = new ContextKey(EditorContexts.HaveCellSelected, this.commandManager); if (info) { interactiveCellsContext.set(info.cellCount > 0).catch(); redoableContext.set(info.redoCount > 0).catch(); + hasCellSelectedContext.set(info.selectedCell ? true : false).catch(); } else { + hasCellSelectedContext.set(false).catch(); interactiveCellsContext.set(false).catch(); redoableContext.set(false).catch(); } diff --git a/src/client/datascience/interactive-ipynb/nativeEditorCommandListener.ts b/src/client/datascience/interactive-ipynb/nativeEditorCommandListener.ts index 97636f9366e2..158c27674167 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditorCommandListener.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditorCommandListener.ts @@ -32,6 +32,30 @@ export class NativeEditorCommandListener implements IDataScienceCommandListener this.disposableRegistry.push(commandManager.registerCommand(Commands.NotebookEditorInterruptKernel, () => this.interruptKernel())); this.disposableRegistry.push(commandManager.registerCommand(Commands.NotebookEditorRestartKernel, () => this.restartKernel())); this.disposableRegistry.push(commandManager.registerCommand(Commands.OpenNotebook, (file?: Uri, _cmdSource: CommandSource = CommandSource.commandPalette) => this.openNotebook(file))); + this.disposableRegistry.push(commandManager.registerCommand(Commands.NotebookEditorRunAllCells, () => this.runAllCells())); + this.disposableRegistry.push(commandManager.registerCommand(Commands.NotebookEditorRunSelectedCell, () => this.runSelectedCell())); + this.disposableRegistry.push(commandManager.registerCommand(Commands.NotebookEditorAddCellBelow, () => this.addCellBelow())); + } + + private runAllCells() { + const activeEditor = this.provider.activeEditor; + if (activeEditor) { + activeEditor.runAllCells(); + } + } + + private runSelectedCell() { + const activeEditor = this.provider.activeEditor; + if (activeEditor) { + activeEditor.runSelectedCell(); + } + } + + private addCellBelow() { + const activeEditor = this.provider.activeEditor; + if (activeEditor) { + activeEditor.addCellBelow(); + } } private undoCells() { diff --git a/src/client/datascience/interactive-window/interactiveWindow.ts b/src/client/datascience/interactive-window/interactiveWindow.ts index 2be69ec9d633..b76b2a06cbb1 100644 --- a/src/client/datascience/interactive-window/interactiveWindow.ts +++ b/src/client/datascience/interactive-window/interactiveWindow.ts @@ -235,12 +235,15 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi interactiveContext.set(!this.isDisposed).catch(); const interactiveCellsContext = new ContextKey(EditorContexts.HaveInteractiveCells, this.commandManager); const redoableContext = new ContextKey(EditorContexts.HaveRedoableCells, this.commandManager); + const hasCellSelectedContext = new ContextKey(EditorContexts.HaveCellSelected, this.commandManager); if (info) { interactiveCellsContext.set(info.cellCount > 0).catch(); redoableContext.set(info.redoCount > 0).catch(); + hasCellSelectedContext.set(info.selectedCell ? true : false).catch(); } else { interactiveCellsContext.set(false).catch(); redoableContext.set(false).catch(); + hasCellSelectedContext.set(false).catch(); } } } diff --git a/src/client/datascience/types.ts b/src/client/datascience/types.ts index 637df00766f9..f0edda8be83b 100644 --- a/src/client/datascience/types.ts +++ b/src/client/datascience/types.ts @@ -254,6 +254,9 @@ export interface INotebookEditor extends IInteractiveBase { readonly visible: boolean; readonly active: boolean; load(contents: string, file: Uri): Promise; + runAllCells(): void; + runSelectedCell(): void; + addCellBelow(): void; } export const IInteractiveWindowListener = Symbol('IInteractiveWindowListener'); @@ -347,6 +350,7 @@ export interface IInteractiveWindowInfo { undoCount: number; redoCount: number; visibleCells: ICell[]; + selectedCell: string | undefined; } export interface IMessageCell extends nbformat.IBaseCell { diff --git a/src/datascience-ui/interactive-common/mainStateController.ts b/src/datascience-ui/interactive-common/mainStateController.ts index 6878373735bd..f8262f0b81d3 100644 --- a/src/datascience-ui/interactive-common/mainStateController.ts +++ b/src/datascience-ui/interactive-common/mainStateController.ts @@ -1080,7 +1080,8 @@ export class MainStateController implements IMessageHandler { visibleCells: this.getNonEditCellVMs().map(cvm => cvm.cell), cellCount: this.getNonEditCellVMs().length, undoCount: this.pendingState.undoStack.length, - redoCount: this.pendingState.redoStack.length + redoCount: this.pendingState.redoStack.length, + selectedCell: this.pendingState.selectedCellId }; this.sendMessage(InteractiveWindowMessages.SendInfo, info); } diff --git a/src/datascience-ui/native-editor/nativeEditorStateController.ts b/src/datascience-ui/native-editor/nativeEditorStateController.ts index 80433cf6dfee..41451406f25c 100644 --- a/src/datascience-ui/native-editor/nativeEditorStateController.ts +++ b/src/datascience-ui/native-editor/nativeEditorStateController.ts @@ -43,6 +43,18 @@ export class NativeEditorStateController extends MainStateController { this.waitingForLoadRender = true; break; + case InteractiveWindowMessages.NotebookRunAllCells: + this.runAll(); + break; + + case InteractiveWindowMessages.NotebookRunSelectedCell: + this.runSelectedCell(); + break; + + case InteractiveWindowMessages.NotebookAddCellBelow: + this.addNewCell(); + break; + default: break; } @@ -76,6 +88,18 @@ export class NativeEditorStateController extends MainStateController { return index > 0 && cells.find((cvm, i) => i >= index && cvm.cell.data.cell_type === 'code'); } + public runSelectedCell = () => { + const selectedCellId = this.getState().selectedCellId; + + if (selectedCellId) { + const cells = this.getState().cellVMs; + const selectedCell = cells.find(cvm => cvm.cell.id === selectedCellId); + if (selectedCell) { + this.submitInput(concatMultilineString(selectedCell.cell.data.source), selectedCell); + } + } + } + public runAll = () => { // Run all code cells (markdown don't need to be run) this.suspendUpdates();