Skip to content

Commit f001bd1

Browse files
Issue 12414 python interactive cell editing shortcuts (#12529)
* refactored ICellRange definition to type.ts since it's now used across multiple modules * add command insertCellBelowPosition * add method insertCell to CodeWatcher which inserts at current line * add method insertCellBelowPosition which inserts below current selection * link insertCellBelowPosition to command python.datascience.insertCellBelowPosition * add command insertCellBelow * add method insertCellBelow to the CodeWatcher * link insertCellBelow to python.datascience.insertCellBelow This will insert a cell below the last cell of the current selection * add command insertCellAbove * add method insertCellAbove to the CodeWatcher * link insertCellAbove to python.datascience.insertCellAbove * will insert cell above the top cell of the current selection * add deleteCells command * add deleteCells method to CodeWatcher * link deleteCells to python.datascience.deleteCells * add selectCell command * add selectCell method to CodeWatcher * link selectCell to python.datascience.selectCell * add selectCellContents command * add selectCellContents method to CodeWatcher * link selectCellContents to python.datascience.selectCellContents * modify selectCell to maintain previous orientation of selection anchor and active * fix detection of anchor and active position direction * add extendSelectionByCellAbove * Works similar to excell extend selection by one cell above * Linked command to python.datascience.extendSelectionByCellAbove * add extendSelectionByCellBelow * Works similar to excell extend selection by one cell below * Linked command to python.datascience.extendSelectionByCellBelow * add moveCellsUp * Command to take selected cells and move them one cell up * linked command to python.datascience.moveCellsUp * add moveCellsDown * Moves selected cells one cell down * Linked to python.datascience.moveCellsDown * added news file for enhancement changes being added * add changeCellToMarkdown * command will use selected cell and if cell_type is not markdown will convert to markdown * linked to python.datascience.changeCellToMarkdown * add changeCellToCode * command will use selected cell and if cell_type is not code then it'll convert to code * linked to python.datascience.changeCellToCode * Remove cell edit commands from context menu * Use the insertCell method to insert a cell when RunCellAndAdvance reaches the last cell * Use the insertCell method to insert cell within addEmptyCellToBottom * Add telemetry for cell edit commands in interactive python * Add codeLensFactory.getCodeLensCacheData and abstracted the cell range creation Abstracts the cells behind a method on codeLensFactory. Consolidates storage into the single cached data store on the codeLensFactory though it requires updating again on the codeWatcher. * clean up async and promises within codewatcher.ts * clean up unnecessary Promise.resolve() * refactor unnecessary async functions to sync functions * added unit tests for move cells down * change the when for commands to display when the python file has cells Co-authored-by: earthastronaut <>
1 parent a7b023e commit f001bd1

13 files changed

Lines changed: 2151 additions & 76 deletions

File tree

news/1 Enhancements/12414.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add cell editing shortcuts for python interactive cells. Thanks [@earthastronaut](https://github.com/earthastronaut/)!

package.json

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,66 @@
528528
"title": "%python.command.python.datascience.debugcontinue.title%",
529529
"category": "Python"
530530
},
531+
{
532+
"command": "python.datascience.insertCellBelowPosition",
533+
"title": "%python.command.python.datascience.insertCellBelowPosition.title%",
534+
"category": "Python"
535+
},
536+
{
537+
"command": "python.datascience.insertCellBelow",
538+
"title": "%python.command.python.datascience.insertCellBelow.title%",
539+
"category": "Python"
540+
},
541+
{
542+
"command": "python.datascience.insertCellAbove",
543+
"title": "%python.command.python.datascience.insertCellAbove.title%",
544+
"category": "Python"
545+
},
546+
{
547+
"command": "python.datascience.deleteCells",
548+
"title": "%python.command.python.datascience.deleteCells.title%",
549+
"category": "Python"
550+
},
551+
{
552+
"command": "python.datascience.selectCell",
553+
"title": "%python.command.python.datascience.selectCell.title%",
554+
"category": "Python"
555+
},
556+
{
557+
"command": "python.datascience.selectCellContents",
558+
"title": "%python.command.python.datascience.selectCellContents.title%",
559+
"category": "Python"
560+
},
561+
{
562+
"command": "python.datascience.extendSelectionByCellAbove",
563+
"title": "%python.command.python.datascience.extendSelectionByCellAbove.title%",
564+
"category": "Python"
565+
},
566+
{
567+
"command": "python.datascience.extendSelectionByCellBelow",
568+
"title": "%python.command.python.datascience.extendSelectionByCellBelow.title%",
569+
"category": "Python"
570+
},
571+
{
572+
"command": "python.datascience.moveCellsUp",
573+
"title": "%python.command.python.datascience.moveCellsUp.title%",
574+
"category": "Python"
575+
},
576+
{
577+
"command": "python.datascience.moveCellsDown",
578+
"title": "%python.command.python.datascience.moveCellsDown.title%",
579+
"category": "Python"
580+
},
581+
{
582+
"command": "python.datascience.changeCellToMarkdown",
583+
"title": "%python.command.python.datascience.changeCellToMarkdown.title%",
584+
"category": "Python"
585+
},
586+
{
587+
"command": "python.datascience.changeCellToCode",
588+
"title": "%python.command.python.datascience.changeCellToCode.title%",
589+
"category": "Python"
590+
},
531591
{
532592
"command": "python.datascience.runcurrentcelladvance",
533593
"title": "%python.command.python.datascience.runcurrentcelladvance.title%",
@@ -1011,6 +1071,78 @@
10111071
"category": "Python",
10121072
"when": "config.noExists"
10131073
},
1074+
{
1075+
"command": "python.datascience.insertCellBelowPosition",
1076+
"title": "%python.command.python.datascience.insertCellBelowPosition.title%",
1077+
"category": "Python",
1078+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1079+
},
1080+
{
1081+
"command": "python.datascience.insertCellBelow",
1082+
"title": "%python.command.python.datascience.insertCellBelow.title%",
1083+
"category": "Python",
1084+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1085+
},
1086+
{
1087+
"command": "python.datascience.insertCellAbove",
1088+
"title": "%python.command.python.datascience.insertCellAbove.title%",
1089+
"category": "Python",
1090+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1091+
},
1092+
{
1093+
"command": "python.datascience.deleteCells",
1094+
"title": "%python.command.python.datascience.deleteCells.title%",
1095+
"category": "Python",
1096+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1097+
},
1098+
{
1099+
"command": "python.datascience.selectCell",
1100+
"title": "%python.command.python.datascience.selectCell.title%",
1101+
"category": "Python",
1102+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1103+
},
1104+
{
1105+
"command": "python.datascience.selectCellContents",
1106+
"title": "%python.command.python.datascience.selectCellContents.title%",
1107+
"category": "Python",
1108+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1109+
},
1110+
{
1111+
"command": "python.datascience.extendSelectionByCellAbove",
1112+
"title": "%python.command.python.datascience.extendSelectionByCellAbove.title%",
1113+
"category": "Python",
1114+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1115+
},
1116+
{
1117+
"command": "python.datascience.extendSelectionByCellBelow",
1118+
"title": "%python.command.python.datascience.extendSelectionByCellBelow.title%",
1119+
"category": "Python",
1120+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1121+
},
1122+
{
1123+
"command": "python.datascience.moveCellsUp",
1124+
"title": "%python.command.python.datascience.moveCellsUp.title%",
1125+
"category": "Python",
1126+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1127+
},
1128+
{
1129+
"command": "python.datascience.moveCellsDown",
1130+
"title": "%python.command.python.datascience.moveCellsDown.title%",
1131+
"category": "Python",
1132+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1133+
},
1134+
{
1135+
"command": "python.datascience.changeCellToMarkdown",
1136+
"title": "%python.command.python.datascience.changeCellToMarkdown.title%",
1137+
"category": "Python",
1138+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1139+
},
1140+
{
1141+
"command": "python.datascience.changeCellToCode",
1142+
"title": "%python.command.python.datascience.changeCellToCode.title%",
1143+
"category": "Python",
1144+
"when": "python.datascience.hascodecells && editorFocus && editorLangId == python && python.datascience.featureenabled"
1145+
},
10141146
{
10151147
"command": "python.datascience.runcurrentcell",
10161148
"title": "%python.command.python.datascience.runcurrentcell.title%",
@@ -3532,4 +3664,4 @@
35323664
"publisherDisplayName": "Microsoft",
35333665
"publisherId": "998b010b-e2af-44a5-a6cd-0b5fd3b9b6f8"
35343666
}
3535-
}
3667+
}

package.nls.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,19 @@
7373
"python.command.python.datascience.runcurrentcelladvance.title": "Run Current Cell And Advance",
7474
"python.command.python.datascience.execSelectionInteractive.title": "Run Selection/Line in Python Interactive Window",
7575
"python.command.python.datascience.runcell.title": "Run Cell",
76+
"python.command.python.datascience.insertCellBelowPosition.title": "Insert Cell Below Position",
77+
"python.command.python.datascience.insertCellBelow.title": "Insert Cell Below",
78+
"python.command.python.datascience.insertCellAbove.title": "Insert Cell Above",
79+
"python.command.python.datascience.deleteCells.title": "Delete Selected Cells",
80+
"python.command.python.datascience.selectCell.title": "Select Cell",
81+
"python.command.python.datascience.selectCellContents.title": "Select Cell Contents",
82+
"python.command.python.datascience.extendSelectionByCellAbove.title": "Extend Selection By Cell Above",
83+
"python.command.python.datascience.extendSelectionByCellBelow.title": "Extend Selection By Cell Below",
84+
"python.command.python.datascience.moveCellsUp.title": "Move Selected Cells Up",
85+
"python.command.python.datascience.moveCellsDown.title": "Move Selected Cells Down",
86+
"python.command.python.datascience.changeCellToMarkdown.title": "Change Cell to Markdown",
87+
"python.command.python.datascience.changeCellToCode.title": "Change Cell to Code",
88+
"python.command.python.datascience.showhistorypane.title": "Show Python Interactive Window",
7689
"python.command.python.datascience.createnewinteractive.title": "Create Python Interactive Window",
7790
"python.command.python.datascience.selectjupyteruri.title": "Specify local or remote Jupyter server for connections",
7891
"python.command.python.datascience.selectjupytercommandline.title": "Specify Jupyter command line arguments",

src/client/common/application/commands.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,18 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu
171171
[DSCommands.DebugStop]: [];
172172
[DSCommands.DebugContinue]: [];
173173
[DSCommands.RunCurrentCellAndAddBelow]: [Uri];
174+
[DSCommands.InsertCellBelowPosition]: [];
175+
[DSCommands.InsertCellBelow]: [];
176+
[DSCommands.InsertCellAbove]: [];
177+
[DSCommands.DeleteCells]: [];
178+
[DSCommands.SelectCell]: [];
179+
[DSCommands.SelectCellContents]: [];
180+
[DSCommands.ExtendSelectionByCellAbove]: [];
181+
[DSCommands.ExtendSelectionByCellBelow]: [];
182+
[DSCommands.MoveCellsUp]: [];
183+
[DSCommands.MoveCellsDown]: [];
184+
[DSCommands.ChangeCellToMarkdown]: [];
185+
[DSCommands.ChangeCellToCode]: [];
174186
[DSCommands.ScrollToCell]: [Uri, string];
175187
[DSCommands.ViewJupyterOutput]: [];
176188
[DSCommands.ExportAsPythonScript]: [INotebookModel];

src/client/datascience/cellFactory.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { IDataScienceSettings, Resource } from '../common/types';
1212
import { noop } from '../common/utils/misc';
1313
import { CellMatcher } from './cellMatcher';
1414
import { Identifiers } from './constants';
15-
import { CellState, ICell } from './types';
15+
import { CellState, ICell, ICellRange } from './types';
1616

1717
function generateCodeCell(
1818
code: string[],
@@ -109,13 +109,6 @@ export function hasCells(document: TextDocument, settings?: IDataScienceSettings
109109
return false;
110110
}
111111

112-
// CellRange is used as the basis for creating new ICells. We only use it in this file.
113-
export interface ICellRange {
114-
range: Range;
115-
title: string;
116-
cell_type: string;
117-
}
118-
119112
export function generateCellsFromString(source: string, settings?: IDataScienceSettings): ICell[] {
120113
const lines: string[] = source.splitLines({ trim: false, removeEmptyEntries: false });
121114

src/client/datascience/cellMatcher.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import { noop } from '../common/utils/misc';
88
import { RegExpValues } from './constants';
99

1010
export class CellMatcher {
11+
public codeExecRegEx: RegExp;
12+
public markdownExecRegEx: RegExp;
13+
1114
private codeMatchRegEx: RegExp;
1215
private markdownMatchRegEx: RegExp;
13-
private codeExecRegEx: RegExp;
14-
private markdownExecRegEx: RegExp;
1516
private defaultCellMarker: string;
1617
private defaultCellMarkerExec: RegExp;
1718

0 commit comments

Comments
 (0)