Skip to content

Commit dfd1792

Browse files
millinDonJayamanne
authored andcommitted
Add new feature: Run Selection in Django Shell. (DonJayamanne#652)
1) If Django project founded in workspace, add "Run Selection in Django Shell" to selection context menu; 2) Fix issue with Run Selection, that happens if LF file selection run on Windows and CRLF run on Unix.
1 parent c54055e commit dfd1792

File tree

4 files changed

+142
-15
lines changed

4 files changed

+142
-15
lines changed

package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"onCommand:python.selectAndDebugTestMethod",
5454
"onCommand:python.runFailedTests",
5555
"onCommand:python.execSelectionInTerminal",
56+
"onCommand:python.execSelectionInDjangoShell",
5657
"onCommand:jupyter.runSelectionLine",
5758
"onCommand:jupyter.execCurrentCell",
5859
"onCommand:jupyter.execCurrentCellAndAdvance",
@@ -174,6 +175,11 @@
174175
"title": "Run Selection in Python Terminal",
175176
"category": "Python"
176177
},
178+
{
179+
"command": "python.execSelectionInDjangoShell",
180+
"title": "Run Selection in Django Shell",
181+
"category": "Python"
182+
},
177183
{
178184
"command": "jupyter.runSelectionLine",
179185
"title": "Run Selection/Line",
@@ -230,6 +236,11 @@
230236
"group": "Python",
231237
"when": "editorHasSelection && editorLangId == python"
232238
},
239+
{
240+
"command": "python.execSelectionInDjangoShell",
241+
"group": "Python",
242+
"when": "editorHasSelection && editorLangId == python && python.isDjangoProject"
243+
},
233244
{
234245
"when": "resourceLangId == python",
235246
"command": "python.execInTerminal",

src/client/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export namespace Commands {
55
export const Set_Interpreter = 'python.setInterpreter';
66
export const Exec_In_Terminal = 'python.execInTerminal';
77
export const Exec_Selection_In_Terminal = 'python.execSelectionInTerminal';
8+
export const Exec_Selection_In_Django_Shell = 'python.execSelectionInDjangoShell';
89
export const Tests_View_UI = 'python.viewTestUI';
910
export const Tests_Picker_UI = 'python.selectTestToRun';
1011
export const Tests_Picker_UI_Debug = 'python.selectTestToDebug';

src/client/extension.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { activateFormatOnSaveProvider } from './providers/formatOnSaveProvider';
2626
import { WorkspaceSymbols } from './workspaceSymbols/main';
2727
import { BlockFormatProviders } from './typeFormatters/blockFormatProvider';
2828
import * as os from 'os';
29+
import * as fs from 'fs';
2930

3031

3132
const PYTHON: vscode.DocumentFilter = { language: 'python', scheme: 'file' };
@@ -36,6 +37,7 @@ let jupMain: jup.Jupyter;
3637

3738
export function activate(context: vscode.ExtensionContext) {
3839
let pythonSettings = settings.PythonSettings.getInstance();
40+
let pythonExt = new PythonExt()
3941
const hasPySparkInCompletionPath = pythonSettings.autoComplete.extraPaths.some(p => p.toLowerCase().indexOf('spark') >= 0);
4042
telemetryHelper.sendTelemetryEvent(telemetryContracts.EVENT_LOAD, {
4143
CodeComplete_Has_ExtraPaths: pythonSettings.autoComplete.extraPaths.length > 0 ? 'true' : 'false',
@@ -119,4 +121,36 @@ export function activate(context: vscode.ExtensionContext) {
119121

120122
// this method is called when your extension is deactivated
121123
export function deactivate() {
122-
}
124+
}
125+
126+
class PythonExt {
127+
128+
private _isDjangoProject: ContextKey;
129+
130+
constructor() {
131+
this._isDjangoProject = new ContextKey('python.isDjangoProject');
132+
this._ensureState();
133+
}
134+
135+
private _ensureState(): void {
136+
// context: python.isDjangoProject
137+
this._isDjangoProject.set(fs.existsSync(vscode.workspace.rootPath.concat("/manage.py")));
138+
}
139+
}
140+
141+
class ContextKey {
142+
private _name: string;
143+
private _lastValue: boolean;
144+
145+
constructor(name:string) {
146+
this._name = name;
147+
}
148+
149+
public set(value:boolean): void {
150+
if (this._lastValue === value) {
151+
return;
152+
}
153+
this._lastValue = value;
154+
vscode.commands.executeCommand('setContext', this._name, this._lastValue);
155+
}
156+
}

src/client/providers/execInTerminalProvider.ts

Lines changed: 95 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export function activateExecInTerminalProvider(): vscode.Disposable[] {
1010
const disposables: vscode.Disposable[] = [];
1111
disposables.push(vscode.commands.registerCommand(Commands.Exec_In_Terminal, execInTerminal));
1212
disposables.push(vscode.commands.registerCommand(Commands.Exec_Selection_In_Terminal, execSelectionInTerminal));
13+
disposables.push(vscode.commands.registerCommand(Commands.Exec_Selection_In_Django_Shell, execSelectionInDjangoShell));
1314
disposables.push(vscode.window.onDidCloseTerminal((closedTermina: vscode.Terminal) => {
1415
if (terminal === closedTermina) {
1516
terminal = null;
@@ -19,9 +20,16 @@ export function activateExecInTerminalProvider(): vscode.Disposable[] {
1920
}
2021

2122
function execInTerminal(fileUri?: vscode.Uri) {
23+
const terminalShellSettings = vscode.workspace.getConfiguration('terminal.integrated.shell');
24+
const IS_POWERSHELL = /powershell/.test(terminalShellSettings.get<string>('windows'));
25+
2226
let pythonSettings = settings.PythonSettings.getInstance();
23-
const currentPythonPath = pythonSettings.pythonPath;
2427
let filePath: string;
28+
29+
let currentPythonPath = pythonSettings.pythonPath;
30+
if (currentPythonPath.indexOf(' ') > 0 ) {
31+
currentPythonPath = `"${currentPythonPath}"`
32+
}
2533

2634
if (fileUri === undefined || typeof fileUri.fsPath !== 'string') {
2735
const activeEditor = vscode.window.activeTextEditor;
@@ -48,6 +56,7 @@ function execInTerminal(fileUri?: vscode.Uri) {
4856
if (filePath.indexOf(' ') > 0) {
4957
filePath = `"${filePath}"`;
5058
}
59+
5160
terminal = terminal ? terminal : vscode.window.createTerminal(`Python`);
5261
if (pythonSettings.terminal && pythonSettings.terminal.executeInFileDir) {
5362
const fileDirPath = path.dirname(filePath);
@@ -57,18 +66,31 @@ function execInTerminal(fileUri?: vscode.Uri) {
5766
}
5867
const launchArgs = settings.PythonSettings.getInstance().terminal.launchArgs;
5968
const launchArgsString = launchArgs.length > 0 ? " ".concat(launchArgs.join(" ")) : "";
69+
const command = `${currentPythonPath}${launchArgsString} ${filePath}`
6070
if (IS_WINDOWS) {
61-
const cmd = `"${currentPythonPath}"${launchArgsString} ${filePath}`;
62-
terminal.sendText(cmd.replace(/\\/g, "/"));
71+
const commandWin = command.replace(/\\/g, "/");
72+
if (IS_POWERSHELL) {
73+
terminal.sendText(`& ${commandWin}`);
74+
}
75+
else {
76+
terminal.sendText(commandWin);
77+
}
6378
}
6479
else {
65-
terminal.sendText(`${currentPythonPath}${launchArgsString} ${filePath}`);
80+
terminal.sendText(command);
6681
}
6782
terminal.show();
6883
}
6984

7085
function execSelectionInTerminal() {
71-
const currentPythonPath = settings.PythonSettings.getInstance().pythonPath;
86+
const terminalShellSettings = vscode.workspace.getConfiguration('terminal.integrated.shell');
87+
const IS_POWERSHELL = /powershell/.test(terminalShellSettings.get<string>('windows'));
88+
89+
let currentPythonPath = settings.PythonSettings.getInstance().pythonPath;
90+
if (currentPythonPath.indexOf(' ') > 0 ) {
91+
currentPythonPath = `"${currentPythonPath}"`
92+
}
93+
7294
const activeEditor = vscode.window.activeTextEditor;
7395
if (!activeEditor) {
7496
return;
@@ -79,22 +101,81 @@ function execSelectionInTerminal() {
79101
return;
80102
}
81103
const code = vscode.window.activeTextEditor.document.getText(new vscode.Range(selection.start, selection.end));
82-
terminal = terminal ? terminal : vscode.window.createTerminal(`Python`);
83104
const launchArgs = settings.PythonSettings.getInstance().terminal.launchArgs;
84105
const launchArgsString = launchArgs.length > 0 ? " ".concat(launchArgs.join(" ")) : "";
106+
const command = `${currentPythonPath}${launchArgsString}`
107+
if (!terminal) {
108+
terminal = vscode.window.createTerminal(`Python`);
109+
if (IS_WINDOWS) {
110+
const commandWin = command.replace(/\\/g, "/");
111+
if (IS_POWERSHELL) {
112+
terminal.sendText(`& ${commandWin}`);
113+
}
114+
else {
115+
terminal.sendText(commandWin);
116+
}
117+
}
118+
else {
119+
terminal.sendText(command);
120+
}
121+
}
122+
const unix_code = code.replace(/\r\n/g, "\n")
85123
if (IS_WINDOWS) {
86-
// Multi line commands don't work the same way on windows terminals as it does on other OS
87-
// So just start the Python REPL, then send the commands
88-
if (currentPythonPath.indexOf(' ') > 0) {
89-
terminal.sendText(`"${currentPythonPath}"${launchArgsString}`);
124+
terminal.sendText(unix_code.replace(/\n/g, "\r\n"));
125+
}
126+
else
127+
{
128+
terminal.sendText(unix_code)
129+
}
130+
terminal.show();
131+
}
132+
133+
function execSelectionInDjangoShell() {
134+
const terminalShellSettings = vscode.workspace.getConfiguration('terminal.integrated.shell');
135+
const IS_POWERSHELL = /powershell/.test(terminalShellSettings.get<string>('windows'));
136+
137+
let currentPythonPath = settings.PythonSettings.getInstance().pythonPath;
138+
if (currentPythonPath.indexOf(' ') > 0 ) {
139+
currentPythonPath = `"${currentPythonPath}"`
140+
}
141+
142+
const activeEditor = vscode.window.activeTextEditor;
143+
if (!activeEditor) {
144+
return;
145+
}
146+
147+
const workspaceRoot = vscode.workspace.rootPath;
148+
const djangoShellCmd = `"${workspaceRoot}/manage.py" shell`
149+
const selection = vscode.window.activeTextEditor.selection;
150+
if (selection.isEmpty) {
151+
return;
152+
}
153+
const code = vscode.window.activeTextEditor.document.getText(new vscode.Range(selection.start, selection.end));
154+
const launchArgs = settings.PythonSettings.getInstance().terminal.launchArgs;
155+
const launchArgsString = launchArgs.length > 0 ? " ".concat(launchArgs.join(" ")) : "";
156+
const command = `${currentPythonPath}${launchArgsString} ${djangoShellCmd}`
157+
if (!terminal) {
158+
terminal = vscode.window.createTerminal(`Django Shell`);
159+
if (IS_WINDOWS) {
160+
const commandWin = command.replace(/\\/g, "/");
161+
if (IS_POWERSHELL) {
162+
terminal.sendText(`& ${commandWin}`);
163+
}
164+
else {
165+
terminal.sendText(commandWin);
166+
}
90167
}
91168
else {
92-
terminal.sendText(`${currentPythonPath}${launchArgsString}`);
169+
terminal.sendText(command);
93170
}
94-
terminal.sendText(code);
95171
}
96-
else {
97-
terminal.sendText(`${currentPythonPath}${launchArgsString} -c "${code}"`);
172+
const unix_code = code.replace(/\r\n/g, "\n")
173+
if (IS_WINDOWS) {
174+
terminal.sendText(unix_code.replace(/\n/g, "\r\n"));
175+
}
176+
else
177+
{
178+
terminal.sendText(unix_code)
98179
}
99180
terminal.show();
100181
}

0 commit comments

Comments
 (0)