Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/2 Fixes/5067.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Advance to the next cell if cursor is in the current cell and user clicks 'Run Cell'
1 change: 1 addition & 0 deletions news/2 Fixes/5386.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix import/export paths to be escaped on windows.
1 change: 1 addition & 0 deletions news/2 Fixes/5630.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for opening hyperlinks from the interactive window.
1 change: 1 addition & 0 deletions news/2 Fixes/5667.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add 'Add empty cell to file' command. Shortcut for having to type '#%%'
1 change: 1 addition & 0 deletions news/2 Fixes/5673.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add 'ctrl+enter' as a keyboard shortcut for run current cell (runs without advancing)
1 change: 1 addition & 0 deletions news/2 Fixes/5774.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix problem with using up/down arrows in autocomplete.
8 changes: 2 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@
"command": "python.datascience.runcurrentcelladvance",
"key": "shift+enter",
"when": "editorFocus && !editorHasSelection && python.datascience.hascodecells && python.datascience.featureenabled"
},
{
"command": "python.datascience.runcurrentcell",
"key": "ctrl+enter",
"when": "editorFocus && !editorHasSelection && python.datascience.hascodecells && python.datascience.featureenabled"
}
],
"commands": [
Expand Down Expand Up @@ -428,6 +433,11 @@
"command": "python.datascience.collapseallcells",
"title": "%python.command.python.datascience.collapseallcells.title%",
"category": "Python"
},
{
"command": "python.datascience.addcellbelow",
"title": "%python.command.python.datascience.addcellbelow.title%",
"category": "Python"
}
],
"menus": {
Expand Down Expand Up @@ -704,6 +714,12 @@
"command": "python.datascience.runallcellsabove",
"category": "Python",
"when": "config.noExists"
},
{
"command": "python.datascience.addcellbelow",
"title": "%python.command.python.datascience.addcellbelow.title%",
"category": "Python",
"when": "python.datascience.featureenabled"
}
],
"view/title": [
Expand Down Expand Up @@ -1280,6 +1296,12 @@
"description": "Enables code lens for 'cells' in a python file.",
"scope": "resource"
},
"python.dataScience.enableAutoMoveToNextCell": {
"type": "boolean",
"default": true,
"description": "Enables moving to the next cell when clicking on a 'Run Cell' code lens.",
"scope": "resource"
},
"python.disableInstallationCheck": {
"type": "boolean",
"default": false,
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"python.command.python.datascience.restartkernel.title": "Restart IPython Kernel",
"python.command.python.datascience.expandallcells.title": "Expand all Python Interactive cells",
"python.command.python.datascience.collapseallcells.title": "Collapse all Python Interactive cells",
"python.command.python.datascience.addcellbelow.title": "Add empty cell to file",
"python.snippet.launch.standard.label": "Python: Current File",
"python.snippet.launch.module.label": "Python: Module",
"python.snippet.launch.module.default": "enter-your-module-name",
Expand Down
1 change: 1 addition & 0 deletions src/client/common/application/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ interface ICommandNameWithoutArgumentTypeMapping {
[DSCommands.ExpandAllCells]: [];
[DSCommands.CollapseAllCells]: [];
[DSCommands.ExportOutputAsNotebook]: [];
[DSCommands.AddCellBelow]: [];
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/client/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ export interface IDataScienceSettings {
liveShareConnectionTimeout?: number;
decorateCells?: boolean;
enableCellCodeLens?: boolean;
enableAutoMoveToNextCell?: boolean;
}

export const IConfigurationService = Symbol('IConfigurationService');
Expand Down
7 changes: 5 additions & 2 deletions src/client/datascience/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export namespace Commands {
export const ExportOutputAsNotebook = 'python.datascience.exportoutputasnotebook';
export const ExecSelectionInInteractiveWindow = 'python.datascience.execSelectionInteractive';
export const RunFileInInteractiveWindows = 'python.datascience.runFileInteractive';
export const AddCellBelow = 'python.datascience.addcellbelow';
}

export namespace EditorContexts {
Expand Down Expand Up @@ -109,7 +110,8 @@ export enum Telemetry {
PandasTooOld = 'DATASCIENCE.SHOW_DATA_PANDAS_TOO_OLD',
DataScienceSettings = 'DATASCIENCE.SETTINGS',
VariableExplorerToggled = 'DATASCIENCE.VARIABLE_EXPLORER_TOGGLE',
VariableExplorerVariableCount = 'DATASCIENCE.VARIABLE_EXPLORER_VARIABLE_COUNT'
VariableExplorerVariableCount = 'DATASCIENCE.VARIABLE_EXPLORER_VARIABLE_COUNT',
AddCellBelow = 'DATASCIENCE.ADD_CELL_BELOW'
}

export namespace HelpLinks {
Expand All @@ -122,7 +124,8 @@ export namespace Settings {
}

export namespace CodeSnippits {
export const ChangeDirectory = ['{0}', 'import os', 'try:', '\tos.chdir(os.path.join(os.getcwd(), \'{1}\'))', '\tprint(os.getcwd())', 'except:', '\tpass', ''];
export const ChangeDirectory = ['{0}', '{1}', 'import os', 'try:', '\tos.chdir(os.path.join(os.getcwd(), \'{2}\'))', '\tprint(os.getcwd())', 'except:', '\tpass', ''];
export const ChangeDirectoryCommentIdentifier = '# ms-python.python added'; // Not translated so can compare.
}

export namespace Identifiers {
Expand Down
11 changes: 11 additions & 0 deletions src/client/datascience/datascience.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,15 @@ export class DataScience implements IDataScience {
}
}

@captureTelemetry(Telemetry.AddCellBelow)
private async addCellBelow(): Promise<void> {
const activeEditor = this.documentManager.activeTextEditor;
const activeCodeWatcher = this.getCurrentCodeWatcher();
if (activeEditor && activeCodeWatcher) {
return activeCodeWatcher.addEmptyCellToBottom();
}
}

private getCurrentCodeLens() : vscode.CodeLens | undefined {
const activeEditor = this.documentManager.activeTextEditor;
const activeCodeWatcher = this.getCurrentCodeWatcher();
Expand Down Expand Up @@ -349,6 +358,8 @@ export class DataScience implements IDataScience {
this.disposableRegistry.push(disposable);
disposable = this.commandManager.registerCommand(Commands.RunFileInInteractiveWindows, this.runFileInteractive, this);
this.disposableRegistry.push(disposable);
disposable = this.commandManager.registerCommand(Commands.AddCellBelow, this.addCellBelow, this);
this.disposableRegistry.push(disposable);
this.commandListeners.forEach((listener: IDataScienceCommandListener) => {
listener.register(this.commandManager);
});
Expand Down
104 changes: 62 additions & 42 deletions src/client/datascience/editor-integration/codewatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,33 +206,24 @@ export class CodeWatcher implements ICodeWatcher {
}

@captureTelemetry(Telemetry.RunCell)
public async runCell(range: Range) {
if (this.document) {
// Use that to get our code.
const code = this.document.getText(range);

try {
const activeHistory = await this.historyProvider.getOrCreateActive();
await activeHistory.addCode(code, this.getFileName(), range.start.line, this.documentManager.activeTextEditor);
} catch (err) {
this.handleError(err);
}
public runCell(range: Range) : Promise<void> {
if (!this.documentManager.activeTextEditor || !this.documentManager.activeTextEditor.document) {
return Promise.resolve();
}

// Run the cell clicked. Advance if the cursor is inside this cell and we're allowed to
const advance = range.contains(this.documentManager.activeTextEditor.selection.start) && this.configService.getSettings().datascience.enableAutoMoveToNextCell;
return this.runMatchingCell(range, advance);
}

@captureTelemetry(Telemetry.RunCurrentCell)
public async runCurrentCell() {
public runCurrentCell() : Promise<void> {
if (!this.documentManager.activeTextEditor || !this.documentManager.activeTextEditor.document) {
return;
return Promise.resolve();
}

for (const lens of this.codeLenses) {
// Check to see which RunCell lens range overlaps the current selection start
if (lens.range.contains(this.documentManager.activeTextEditor.selection.start) && lens.command && lens.command.command === Commands.RunCell) {
await this.runCell(lens.range);
break;
}
}
// Run the cell that matches the current cursor position.
return this.runMatchingCell(this.documentManager.activeTextEditor.selection, false);
}

@captureTelemetry(Telemetry.RunCurrentCellAndAdvance)
Expand All @@ -241,38 +232,67 @@ export class CodeWatcher implements ICodeWatcher {
return;
}

let currentRunCellLens: CodeLens | undefined;
let nextRunCellLens: CodeLens | undefined;
// Run the cell that matches the current cursor position. Always advance
return this.runMatchingCell(this.documentManager.activeTextEditor.selection, true);
}

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

// Check to see which RunCell lens range overlaps the current selection start
if (lens.range.contains(this.documentManager.activeTextEditor.selection.start) && lens.command && lens.command.command === Commands.RunCell) {
currentRunCellLens = lens;
}
const newPosition = new Position(editor.document.lineCount + 3, 0); // +3 to account for the added spaces and to position after the new mark
return this.advanceToRange(new Range(newPosition, newPosition));
}
}

private async runMatchingCell(range: Range, advance?: boolean) {
const currentRunCellLens = this.getCurrentCellLens(range.start);
const nextRunCellLens = this.getNextCellLens(range.start);

if (currentRunCellLens) {
// Either use the next cell that we found, or add a new one into the document
let nextRange: Range;
if (!nextRunCellLens) {
nextRange = this.createNewCell(currentRunCellLens.range);
} else {
nextRange = nextRunCellLens.range;
}
// Move the next cell if allowed.
if (advance) {
// Either use the next cell that we found, or add a new one into the document
let nextRange: Range;
if (!nextRunCellLens) {
nextRange = this.createNewCell(currentRunCellLens.range);
} else {
nextRange = nextRunCellLens.range;
}

if (nextRange) {
this.advanceToRange(nextRange);
if (nextRange) {
this.advanceToRange(nextRange);
}
}

// Run the cell after moving the selection
await this.runCell(currentRunCellLens.range);
if (this.document) {
// Use that to get our code.
const code = this.document.getText(currentRunCellLens.range);

try {
const activeHistory = await this.historyProvider.getOrCreateActive();
await activeHistory.addCode(code, this.getFileName(), range.start.line, this.documentManager.activeTextEditor);
} catch (err) {
this.handleError(err);
}
}
}
}

private getCurrentCellLens(pos: Position) : CodeLens | undefined {
return this.codeLenses.find(l => l.range.contains(pos) && l.command !== undefined && l.command.command === Commands.RunCell);
}

private getNextCellLens(pos: Position) : CodeLens | undefined {
const currentIndex = this.codeLenses.findIndex(l => l.range.contains(pos) && l.command !== undefined && l.command.command === Commands.RunCell);
if (currentIndex >= 0) {
return this.codeLenses.find((l: CodeLens, i: number) => l.command !== undefined && l.command.command === Commands.RunCell && i > currentIndex);
}
return undefined;
}

private async runFileInteractiveInternal() {
Expand Down
2 changes: 2 additions & 0 deletions src/client/datascience/history/historyTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export namespace HistoryMessages {
export const LoadOnigasmAssemblyResponse = 'load_onigasm_assembly_response';
export const LoadTmLanguageRequest = 'load_tmlanguage_request';
export const LoadTmLanguageResponse = 'load_tmlanguage_response';
export const OpenLink = 'open_link';
}

// These are the messages that will mirror'd to guest/hosts in
Expand Down Expand Up @@ -198,4 +199,5 @@ export class IHistoryMapping {
public [HistoryMessages.LoadOnigasmAssemblyResponse]: Buffer;
public [HistoryMessages.LoadTmLanguageRequest]: never | undefined;
public [HistoryMessages.LoadTmLanguageResponse]: string | undefined;
public [HistoryMessages.OpenLink]: string | undefined;
}
40 changes: 40 additions & 0 deletions src/client/datascience/history/linkProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import '../../common/extensions';

import { inject, injectable } from 'inversify';
import { Event, EventEmitter } from 'vscode';

import { IApplicationShell } from '../../common/application/types';
import { noop } from '../../common/utils/misc';
import { IHistoryListener } from '../types';
import { HistoryMessages } from './historyTypes';

// tslint:disable: no-any
@injectable()
export class LinkProvider implements IHistoryListener {
private postEmitter: EventEmitter<{message: string; payload: any}> = new EventEmitter<{message: string; payload: any}>();
constructor(@inject(IApplicationShell) private applicationShell: IApplicationShell) {
noop();
}

public get postMessage(): Event<{ message: string; payload: any }> {
return this.postEmitter.event;
}

public onMessage(message: string, payload?: any): void {
switch (message) {
case HistoryMessages.OpenLink:
if (payload) {
this.applicationShell.openUrl(payload.toString());
}
break;
default:
break;
}
}
public dispose(): void | undefined {
noop();
}
}
Loading