diff --git a/package.json b/package.json index 45bf867d5930..a201154793f9 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "onCommand:python.selectAndDebugTestMethod", "onCommand:python.runFailedTests", "onCommand:python.execSelectionInTerminal", + "onCommand:python.execSelectionInDjangoShell", "onCommand:jupyter.runSelectionLine", "onCommand:jupyter.execCurrentCell", "onCommand:jupyter.execCurrentCellAndAdvance", @@ -174,6 +175,11 @@ "title": "Run Selection in Python Terminal", "category": "Python" }, + { + "command": "python.execSelectionInDjangoShell", + "title": "Run Selection in Django Shell", + "category": "Python" + }, { "command": "jupyter.runSelectionLine", "title": "Run Selection/Line", @@ -230,6 +236,11 @@ "group": "Python", "when": "editorHasSelection && editorLangId == python" }, + { + "command": "python.execSelectionInDjangoShell", + "group": "Python", + "when": "editorHasSelection && editorLangId == python && python.isDjangoProject" + }, { "when": "resourceLangId == python", "command": "python.execInTerminal", diff --git a/src/client/common/constants.ts b/src/client/common/constants.ts index 16bfe28e93da..6be3f5a095fd 100644 --- a/src/client/common/constants.ts +++ b/src/client/common/constants.ts @@ -5,6 +5,7 @@ export namespace Commands { export const Set_Interpreter = 'python.setInterpreter'; export const Exec_In_Terminal = 'python.execInTerminal'; export const Exec_Selection_In_Terminal = 'python.execSelectionInTerminal'; + export const Exec_Selection_In_Django_Shell = 'python.execSelectionInDjangoShell'; export const Tests_View_UI = 'python.viewTestUI'; export const Tests_Picker_UI = 'python.selectTestToRun'; export const Tests_Picker_UI_Debug = 'python.selectTestToDebug'; diff --git a/src/client/extension.ts b/src/client/extension.ts index cbf1336e59c6..a0a9d5243002 100644 --- a/src/client/extension.ts +++ b/src/client/extension.ts @@ -26,6 +26,7 @@ import { activateFormatOnSaveProvider } from './providers/formatOnSaveProvider'; import { WorkspaceSymbols } from './workspaceSymbols/main'; import { BlockFormatProviders } from './typeFormatters/blockFormatProvider'; import * as os from 'os'; +import * as fs from 'fs'; const PYTHON: vscode.DocumentFilter = { language: 'python', scheme: 'file' }; @@ -36,6 +37,7 @@ let jupMain: jup.Jupyter; export function activate(context: vscode.ExtensionContext) { let pythonSettings = settings.PythonSettings.getInstance(); + let pythonExt = new PythonExt() const hasPySparkInCompletionPath = pythonSettings.autoComplete.extraPaths.some(p => p.toLowerCase().indexOf('spark') >= 0); telemetryHelper.sendTelemetryEvent(telemetryContracts.EVENT_LOAD, { CodeComplete_Has_ExtraPaths: pythonSettings.autoComplete.extraPaths.length > 0 ? 'true' : 'false', @@ -119,4 +121,36 @@ export function activate(context: vscode.ExtensionContext) { // this method is called when your extension is deactivated export function deactivate() { -} \ No newline at end of file +} + +class PythonExt { + + private _isDjangoProject: ContextKey; + + constructor() { + this._isDjangoProject = new ContextKey('python.isDjangoProject'); + this._ensureState(); + } + + private _ensureState(): void { + // context: python.isDjangoProject + this._isDjangoProject.set(fs.existsSync(vscode.workspace.rootPath.concat("/manage.py"))); + } +} + +class ContextKey { + private _name: string; + private _lastValue: boolean; + + constructor(name:string) { + this._name = name; + } + + public set(value:boolean): void { + if (this._lastValue === value) { + return; + } + this._lastValue = value; + vscode.commands.executeCommand('setContext', this._name, this._lastValue); + } +} diff --git a/src/client/providers/execInTerminalProvider.ts b/src/client/providers/execInTerminalProvider.ts index 7cb1fac468ad..7db6363198d6 100644 --- a/src/client/providers/execInTerminalProvider.ts +++ b/src/client/providers/execInTerminalProvider.ts @@ -10,6 +10,7 @@ export function activateExecInTerminalProvider(): vscode.Disposable[] { const disposables: vscode.Disposable[] = []; disposables.push(vscode.commands.registerCommand(Commands.Exec_In_Terminal, execInTerminal)); disposables.push(vscode.commands.registerCommand(Commands.Exec_Selection_In_Terminal, execSelectionInTerminal)); + disposables.push(vscode.commands.registerCommand(Commands.Exec_Selection_In_Django_Shell, execSelectionInDjangoShell)); disposables.push(vscode.window.onDidCloseTerminal((closedTermina: vscode.Terminal) => { if (terminal === closedTermina) { terminal = null; @@ -19,9 +20,16 @@ export function activateExecInTerminalProvider(): vscode.Disposable[] { } function execInTerminal(fileUri?: vscode.Uri) { + const terminalShellSettings = vscode.workspace.getConfiguration('terminal.integrated.shell'); + const IS_POWERSHELL = /powershell/.test(terminalShellSettings.get('windows')); + let pythonSettings = settings.PythonSettings.getInstance(); - const currentPythonPath = pythonSettings.pythonPath; let filePath: string; + + let currentPythonPath = pythonSettings.pythonPath; + if (currentPythonPath.indexOf(' ') > 0 ) { + currentPythonPath = `"${currentPythonPath}"` + } if (fileUri === undefined || typeof fileUri.fsPath !== 'string') { const activeEditor = vscode.window.activeTextEditor; @@ -48,6 +56,7 @@ function execInTerminal(fileUri?: vscode.Uri) { if (filePath.indexOf(' ') > 0) { filePath = `"${filePath}"`; } + terminal = terminal ? terminal : vscode.window.createTerminal(`Python`); if (pythonSettings.terminal && pythonSettings.terminal.executeInFileDir) { const fileDirPath = path.dirname(filePath); @@ -57,18 +66,31 @@ function execInTerminal(fileUri?: vscode.Uri) { } const launchArgs = settings.PythonSettings.getInstance().terminal.launchArgs; const launchArgsString = launchArgs.length > 0 ? " ".concat(launchArgs.join(" ")) : ""; + const command = `${currentPythonPath}${launchArgsString} ${filePath}` if (IS_WINDOWS) { - const cmd = `"${currentPythonPath}"${launchArgsString} ${filePath}`; - terminal.sendText(cmd.replace(/\\/g, "/")); + const commandWin = command.replace(/\\/g, "/"); + if (IS_POWERSHELL) { + terminal.sendText(`& ${commandWin}`); + } + else { + terminal.sendText(commandWin); + } } else { - terminal.sendText(`${currentPythonPath}${launchArgsString} ${filePath}`); + terminal.sendText(command); } terminal.show(); } function execSelectionInTerminal() { - const currentPythonPath = settings.PythonSettings.getInstance().pythonPath; + const terminalShellSettings = vscode.workspace.getConfiguration('terminal.integrated.shell'); + const IS_POWERSHELL = /powershell/.test(terminalShellSettings.get('windows')); + + let currentPythonPath = settings.PythonSettings.getInstance().pythonPath; + if (currentPythonPath.indexOf(' ') > 0 ) { + currentPythonPath = `"${currentPythonPath}"` + } + const activeEditor = vscode.window.activeTextEditor; if (!activeEditor) { return; @@ -79,22 +101,81 @@ function execSelectionInTerminal() { return; } const code = vscode.window.activeTextEditor.document.getText(new vscode.Range(selection.start, selection.end)); - terminal = terminal ? terminal : vscode.window.createTerminal(`Python`); const launchArgs = settings.PythonSettings.getInstance().terminal.launchArgs; const launchArgsString = launchArgs.length > 0 ? " ".concat(launchArgs.join(" ")) : ""; + const command = `${currentPythonPath}${launchArgsString}` + if (!terminal) { + terminal = vscode.window.createTerminal(`Python`); + if (IS_WINDOWS) { + const commandWin = command.replace(/\\/g, "/"); + if (IS_POWERSHELL) { + terminal.sendText(`& ${commandWin}`); + } + else { + terminal.sendText(commandWin); + } + } + else { + terminal.sendText(command); + } + } + const unix_code = code.replace(/\r\n/g, "\n") if (IS_WINDOWS) { - // Multi line commands don't work the same way on windows terminals as it does on other OS - // So just start the Python REPL, then send the commands - if (currentPythonPath.indexOf(' ') > 0) { - terminal.sendText(`"${currentPythonPath}"${launchArgsString}`); + terminal.sendText(unix_code.replace(/\n/g, "\r\n")); + } + else + { + terminal.sendText(unix_code) + } + terminal.show(); +} + +function execSelectionInDjangoShell() { + const terminalShellSettings = vscode.workspace.getConfiguration('terminal.integrated.shell'); + const IS_POWERSHELL = /powershell/.test(terminalShellSettings.get('windows')); + + let currentPythonPath = settings.PythonSettings.getInstance().pythonPath; + if (currentPythonPath.indexOf(' ') > 0 ) { + currentPythonPath = `"${currentPythonPath}"` + } + + const activeEditor = vscode.window.activeTextEditor; + if (!activeEditor) { + return; + } + + const workspaceRoot = vscode.workspace.rootPath; + const djangoShellCmd = `"${workspaceRoot}/manage.py" shell` + const selection = vscode.window.activeTextEditor.selection; + if (selection.isEmpty) { + return; + } + const code = vscode.window.activeTextEditor.document.getText(new vscode.Range(selection.start, selection.end)); + const launchArgs = settings.PythonSettings.getInstance().terminal.launchArgs; + const launchArgsString = launchArgs.length > 0 ? " ".concat(launchArgs.join(" ")) : ""; + const command = `${currentPythonPath}${launchArgsString} ${djangoShellCmd}` + if (!terminal) { + terminal = vscode.window.createTerminal(`Django Shell`); + if (IS_WINDOWS) { + const commandWin = command.replace(/\\/g, "/"); + if (IS_POWERSHELL) { + terminal.sendText(`& ${commandWin}`); + } + else { + terminal.sendText(commandWin); + } } else { - terminal.sendText(`${currentPythonPath}${launchArgsString}`); + terminal.sendText(command); } - terminal.sendText(code); } - else { - terminal.sendText(`${currentPythonPath}${launchArgsString} -c "${code}"`); + const unix_code = code.replace(/\r\n/g, "\n") + if (IS_WINDOWS) { + terminal.sendText(unix_code.replace(/\n/g, "\r\n")); + } + else + { + terminal.sendText(unix_code) } terminal.show(); } \ No newline at end of file