Skip to content

Commit f7df23d

Browse files
committed
Fix 3 bugs (#5773)
Run cell moves to next cell Ctrl+Enter keyboard shortcut Add an empty cell
1 parent d61802f commit f7df23d

File tree

13 files changed

+109
-50
lines changed

13 files changed

+109
-50
lines changed

news/2 Fixes/5067.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Advance to the next cell if cursor is in the current cell and user clicks 'Run Cell'

news/2 Fixes/5667.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add 'Add empty cell to file' command. Shortcut for having to type '#%%'

news/2 Fixes/5673.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add 'ctrl+enter' as a keyboard shortcut for run current cell (runs without advancing)

package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@
9999
"command": "python.datascience.runcurrentcelladvance",
100100
"key": "shift+enter",
101101
"when": "editorFocus && !editorHasSelection && python.datascience.hascodecells && python.datascience.featureenabled"
102+
},
103+
{
104+
"command": "python.datascience.runcurrentcell",
105+
"key": "ctrl+enter",
106+
"when": "editorFocus && !editorHasSelection && python.datascience.hascodecells && python.datascience.featureenabled"
102107
}
103108
],
104109
"commands": [
@@ -428,6 +433,11 @@
428433
"command": "python.datascience.collapseallcells",
429434
"title": "%python.command.python.datascience.collapseallcells.title%",
430435
"category": "Python"
436+
},
437+
{
438+
"command": "python.datascience.addcellbelow",
439+
"title": "%python.command.python.datascience.addcellbelow.title%",
440+
"category": "Python"
431441
}
432442
],
433443
"menus": {
@@ -704,6 +714,12 @@
704714
"command": "python.datascience.runallcellsabove",
705715
"category": "Python",
706716
"when": "config.noExists"
717+
},
718+
{
719+
"command": "python.datascience.addcellbelow",
720+
"title": "%python.command.python.datascience.addcellbelow.title%",
721+
"category": "Python",
722+
"when": "python.datascience.featureenabled"
707723
}
708724
],
709725
"view/title": [
@@ -1280,6 +1296,12 @@
12801296
"description": "Enables code lens for 'cells' in a python file.",
12811297
"scope": "resource"
12821298
},
1299+
"python.dataScience.enableAutoMoveToNextCell": {
1300+
"type": "boolean",
1301+
"default": true,
1302+
"description": "Enables moving to the next cell when clicking on a 'Run Cell' code lens.",
1303+
"scope": "resource"
1304+
},
12831305
"python.disableInstallationCheck": {
12841306
"type": "boolean",
12851307
"default": false,

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"python.command.python.datascience.restartkernel.title": "Restart IPython Kernel",
5454
"python.command.python.datascience.expandallcells.title": "Expand all Python Interactive cells",
5555
"python.command.python.datascience.collapseallcells.title": "Collapse all Python Interactive cells",
56+
"python.command.python.datascience.addcellbelow.title": "Add empty cell to file",
5657
"python.snippet.launch.standard.label": "Python: Current File",
5758
"python.snippet.launch.module.label": "Python: Module",
5859
"python.snippet.launch.module.default": "enter-your-module-name",

src/client/common/application/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ interface ICommandNameWithoutArgumentTypeMapping {
4949
[DSCommands.ExpandAllCells]: [];
5050
[DSCommands.CollapseAllCells]: [];
5151
[DSCommands.ExportOutputAsNotebook]: [];
52+
[DSCommands.AddCellBelow]: [];
5253
}
5354

5455
/**

src/client/common/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ export interface IDataScienceSettings {
311311
liveShareConnectionTimeout?: number;
312312
decorateCells?: boolean;
313313
enableCellCodeLens?: boolean;
314+
enableAutoMoveToNextCell?: boolean;
314315
}
315316

316317
export const IConfigurationService = Symbol('IConfigurationService');

src/client/datascience/constants.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export namespace Commands {
3333
export const ExportOutputAsNotebook = 'python.datascience.exportoutputasnotebook';
3434
export const ExecSelectionInInteractiveWindow = 'python.datascience.execSelectionInteractive';
3535
export const RunFileInInteractiveWindows = 'python.datascience.runFileInteractive';
36+
export const AddCellBelow = 'python.datascience.addcellbelow';
3637
}
3738

3839
export namespace EditorContexts {
@@ -109,7 +110,8 @@ export enum Telemetry {
109110
PandasTooOld = 'DATASCIENCE.SHOW_DATA_PANDAS_TOO_OLD',
110111
DataScienceSettings = 'DATASCIENCE.SETTINGS',
111112
VariableExplorerToggled = 'DATASCIENCE.VARIABLE_EXPLORER_TOGGLE',
112-
VariableExplorerVariableCount = 'DATASCIENCE.VARIABLE_EXPLORER_VARIABLE_COUNT'
113+
VariableExplorerVariableCount = 'DATASCIENCE.VARIABLE_EXPLORER_VARIABLE_COUNT',
114+
AddCellBelow = 'DATASCIENCE.ADD_CELL_BELOW'
113115
}
114116

115117
export namespace HelpLinks {

src/client/datascience/datascience.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,15 @@ export class DataScience implements IDataScience {
235235
}
236236
}
237237

238+
@captureTelemetry(Telemetry.AddCellBelow)
239+
private async addCellBelow(): Promise<void> {
240+
const activeEditor = this.documentManager.activeTextEditor;
241+
const activeCodeWatcher = this.getCurrentCodeWatcher();
242+
if (activeEditor && activeCodeWatcher) {
243+
return activeCodeWatcher.addEmptyCellToBottom();
244+
}
245+
}
246+
238247
private getCurrentCodeLens() : vscode.CodeLens | undefined {
239248
const activeEditor = this.documentManager.activeTextEditor;
240249
const activeCodeWatcher = this.getCurrentCodeWatcher();
@@ -349,6 +358,8 @@ export class DataScience implements IDataScience {
349358
this.disposableRegistry.push(disposable);
350359
disposable = this.commandManager.registerCommand(Commands.RunFileInInteractiveWindows, this.runFileInteractive, this);
351360
this.disposableRegistry.push(disposable);
361+
disposable = this.commandManager.registerCommand(Commands.AddCellBelow, this.addCellBelow, this);
362+
this.disposableRegistry.push(disposable);
352363
this.commandListeners.forEach((listener: IDataScienceCommandListener) => {
353364
listener.register(this.commandManager);
354365
});

src/client/datascience/editor-integration/codewatcher.ts

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -206,33 +206,24 @@ export class CodeWatcher implements ICodeWatcher {
206206
}
207207

208208
@captureTelemetry(Telemetry.RunCell)
209-
public async runCell(range: Range) {
210-
if (this.document) {
211-
// Use that to get our code.
212-
const code = this.document.getText(range);
213-
214-
try {
215-
const activeHistory = await this.historyProvider.getOrCreateActive();
216-
await activeHistory.addCode(code, this.getFileName(), range.start.line, this.documentManager.activeTextEditor);
217-
} catch (err) {
218-
this.handleError(err);
219-
}
209+
public runCell(range: Range) : Promise<void> {
210+
if (!this.documentManager.activeTextEditor || !this.documentManager.activeTextEditor.document) {
211+
return Promise.resolve();
220212
}
213+
214+
// Run the cell clicked. Advance if the cursor is inside this cell and we're allowed to
215+
const advance = range.contains(this.documentManager.activeTextEditor.selection.start) && this.configService.getSettings().datascience.enableAutoMoveToNextCell;
216+
return this.runMatchingCell(range, advance);
221217
}
222218

223219
@captureTelemetry(Telemetry.RunCurrentCell)
224-
public async runCurrentCell() {
220+
public runCurrentCell() : Promise<void> {
225221
if (!this.documentManager.activeTextEditor || !this.documentManager.activeTextEditor.document) {
226-
return;
222+
return Promise.resolve();
227223
}
228224

229-
for (const lens of this.codeLenses) {
230-
// Check to see which RunCell lens range overlaps the current selection start
231-
if (lens.range.contains(this.documentManager.activeTextEditor.selection.start) && lens.command && lens.command.command === Commands.RunCell) {
232-
await this.runCell(lens.range);
233-
break;
234-
}
235-
}
225+
// Run the cell that matches the current cursor position.
226+
return this.runMatchingCell(this.documentManager.activeTextEditor.selection, false);
236227
}
237228

238229
@captureTelemetry(Telemetry.RunCurrentCellAndAdvance)
@@ -241,38 +232,67 @@ export class CodeWatcher implements ICodeWatcher {
241232
return;
242233
}
243234

244-
let currentRunCellLens: CodeLens | undefined;
245-
let nextRunCellLens: CodeLens | undefined;
235+
// Run the cell that matches the current cursor position. Always advance
236+
return this.runMatchingCell(this.documentManager.activeTextEditor.selection, true);
237+
}
246238

247-
for (const lens of this.codeLenses) {
248-
// If we have already found the current code lens, then the next run cell code lens will give us the next cell
249-
if (currentRunCellLens && lens.command && lens.command.command === Commands.RunCell) {
250-
nextRunCellLens = lens;
251-
break;
252-
}
239+
public async addEmptyCellToBottom() : Promise<void> {
240+
const editor = this.documentManager.activeTextEditor;
241+
if (editor) {
242+
editor.edit((editBuilder) => {
243+
editBuilder.insert(new Position(editor.document.lineCount, 0), '\n\n#%%\n');
244+
});
253245

254-
// Check to see which RunCell lens range overlaps the current selection start
255-
if (lens.range.contains(this.documentManager.activeTextEditor.selection.start) && lens.command && lens.command.command === Commands.RunCell) {
256-
currentRunCellLens = lens;
257-
}
246+
const newPosition = new Position(editor.document.lineCount + 3, 0); // +3 to account for the added spaces and to position after the new mark
247+
return this.advanceToRange(new Range(newPosition, newPosition));
258248
}
249+
}
250+
251+
private async runMatchingCell(range: Range, advance?: boolean) {
252+
const currentRunCellLens = this.getCurrentCellLens(range.start);
253+
const nextRunCellLens = this.getNextCellLens(range.start);
259254

260255
if (currentRunCellLens) {
261-
// Either use the next cell that we found, or add a new one into the document
262-
let nextRange: Range;
263-
if (!nextRunCellLens) {
264-
nextRange = this.createNewCell(currentRunCellLens.range);
265-
} else {
266-
nextRange = nextRunCellLens.range;
267-
}
256+
// Move the next cell if allowed.
257+
if (advance) {
258+
// Either use the next cell that we found, or add a new one into the document
259+
let nextRange: Range;
260+
if (!nextRunCellLens) {
261+
nextRange = this.createNewCell(currentRunCellLens.range);
262+
} else {
263+
nextRange = nextRunCellLens.range;
264+
}
268265

269-
if (nextRange) {
270-
this.advanceToRange(nextRange);
266+
if (nextRange) {
267+
this.advanceToRange(nextRange);
268+
}
271269
}
272270

273271
// Run the cell after moving the selection
274-
await this.runCell(currentRunCellLens.range);
272+
if (this.document) {
273+
// Use that to get our code.
274+
const code = this.document.getText(currentRunCellLens.range);
275+
276+
try {
277+
const activeHistory = await this.historyProvider.getOrCreateActive();
278+
await activeHistory.addCode(code, this.getFileName(), range.start.line, this.documentManager.activeTextEditor);
279+
} catch (err) {
280+
this.handleError(err);
281+
}
282+
}
283+
}
284+
}
285+
286+
private getCurrentCellLens(pos: Position) : CodeLens | undefined {
287+
return this.codeLenses.find(l => l.range.contains(pos) && l.command !== undefined && l.command.command === Commands.RunCell);
288+
}
289+
290+
private getNextCellLens(pos: Position) : CodeLens | undefined {
291+
const currentIndex = this.codeLenses.findIndex(l => l.range.contains(pos) && l.command !== undefined && l.command.command === Commands.RunCell);
292+
if (currentIndex >= 0) {
293+
return this.codeLenses.find((l: CodeLens, i: number) => l.command !== undefined && l.command.command === Commands.RunCell && i > currentIndex);
275294
}
295+
return undefined;
276296
}
277297

278298
private async runFileInteractiveInternal() {

0 commit comments

Comments
 (0)