From 031c531aae204e94edc13139d0590a18e116f8f7 Mon Sep 17 00:00:00 2001 From: Philipp Nieting Date: Sat, 30 Sep 2017 22:06:00 +0200 Subject: [PATCH 1/3] improved interpreter switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Switching the interpreter is possible if no workspace is opened --- src/client/interpreter/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/client/interpreter/index.ts b/src/client/interpreter/index.ts index 447946d7871c..c7dbbcc8ae58 100644 --- a/src/client/interpreter/index.ts +++ b/src/client/interpreter/index.ts @@ -58,7 +58,11 @@ export class InterpreterManager implements Disposable { pythonPath = path.join('${workspaceRoot}', path.relative(workspace.rootPath!, pythonPath)); } const pythonConfig = workspace.getConfiguration('python'); - pythonConfig.update('pythonPath', pythonPath).then(() => { + var configurationTarget = null; + if (typeof workspace.rootPath !== 'string') { + configurationTarget = true; + } + pythonConfig.update('pythonPath', pythonPath, configurationTarget).then(() => { //Done }, reason => { window.showErrorMessage(`Failed to set 'pythonPath'. Error: ${reason.message}`); From 0512fa7bd3515bbe46f2991aa9d396bb297ba416 Mon Sep 17 00:00:00 2001 From: Philipp Nieting Date: Sat, 30 Sep 2017 22:07:15 +0200 Subject: [PATCH 2/3] added shebang detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • If a shebang is present, prompt the user to switch the specified interpreter --- package.json | 19 ++++ .../providers/setInterpreterProvider.ts | 106 +++++++++++++++++- 2 files changed, 122 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ecc33854217f..8237a9743a89 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "onCommand:python.runtests", "onCommand:python.debugtests", "onCommand:python.setInterpreter", + "onCommand:python.shebangInterpreter", "onCommand:python.viewTestUI", "onCommand:python.viewTestOutput", "onCommand:python.selectAndRunTestMethod", @@ -120,6 +121,11 @@ "title": "Select Workspace Interpreter", "category": "Python" }, + { + "command": "python.setShebangInterpreter", + "title": "Set Interpreter to shebang", + "category": "Python" + }, { "command": "python.updateSparkLibrary", "title": "Update Workspace PySpark Libraries", @@ -975,6 +981,19 @@ ] } }, + "python.disableShebangDetection": { + "type": "boolean", + "default": false, + "description": "Searches for a shebang and asks to set interpreter." + }, + "python.ignoreShebang": { + "type": "array", + "description": "Files where shebang should be ignored.", + "default": [], + "items": { + "type": "string" + } + }, "python.linting.enabled": { "type": "boolean", "default": true, diff --git a/src/client/providers/setInterpreterProvider.ts b/src/client/providers/setInterpreterProvider.ts index 6021a71be60f..233de85c5942 100644 --- a/src/client/providers/setInterpreterProvider.ts +++ b/src/client/providers/setInterpreterProvider.ts @@ -12,8 +12,14 @@ interface PythonPathQuickPickItem extends vscode.QuickPickItem { export class SetInterpreterProvider implements vscode.Disposable { private disposables: vscode.Disposable[] = []; + private ignoreShebangTemp: string[] = []; constructor(private interpreterManager: InterpreterManager) { this.disposables.push(vscode.commands.registerCommand("python.setInterpreter", this.setInterpreter.bind(this))); + this.disposables.push(vscode.commands.registerCommand("python.setShebangInterpreter", this.setShebangInterpreter.bind(this))); + + vscode.workspace.onDidOpenTextDocument(this.detectShebangInterpreter.bind(this)); + vscode.workspace.onDidSaveTextDocument(this.detectShebangInterpreter.bind(this)); + vscode.workspace.onDidCloseTextDocument(this.removeFromIgnoreList.bind(this)); } public dispose() { this.disposables.forEach(disposable => disposable.dispose()); @@ -58,9 +64,103 @@ export class SetInterpreterProvider implements vscode.Disposable { } private setInterpreter() { - if (typeof vscode.workspace.rootPath !== 'string') { - return vscode.window.showErrorMessage('Please open a workspace to select the Python Interpreter'); - } this.presentQuickPick(); } + + private setShebangInterpreter() { + const document = vscode.window.activeTextEditor.document; + let error = false; + + var firstLine = document.lineAt(0); + if (firstLine.isEmptyOrWhitespace) { + error = true; + } + + if (!error && "#!" === firstLine.text.substr(0, 2)) { + // Shebang detected + this.interpreterManager.setPythonPath(firstLine.text.substr(2).trim()); + } + + if (error) { + vscode.window.showErrorMessage("No shebang found.") + } + } + + private removeFromIgnoreList(document: vscode.TextDocument) { + const index = this.ignoreShebangTemp.indexOf(document.fileName) + if (index > -1 ) { + this.ignoreShebangTemp.splice(index, 1); + } + } + + private detectShebangInterpreter(document: vscode.TextDocument) { + if (document.languageId !== 'python' || typeof vscode.workspace.rootPath === "string") { + return; + } + + var firstLine = document.lineAt(0); + if (firstLine.isEmptyOrWhitespace) { + return; + } + + const pythonConfig = vscode.workspace.getConfiguration('python'); + + // check for Shebang + const selectedPythonPath = pythonConfig.get("pythonPath"); + let intendedPythonPath = null; + if ("#!" === firstLine.text.substr(0, 2)) { + // Shebang detected + intendedPythonPath = firstLine.text.substr(2).trim(); + } + else { + return; + } + + // check, if automatic interpreter switch is globally disabled + const disableShebangDetection = pythonConfig.get('disableShebangDetection'); + if (disableShebangDetection) { + return; + } + + // check, if the automatic interpreter switch is disabled for current file + const filesIgnoreAlways = pythonConfig.get('ignoreShebang', [] as string[]); + if (filesIgnoreAlways.indexOf(document.fileName) > -1 || this.ignoreShebangTemp.indexOf(document.fileName) > -1) { + return; + } + + // check, if current interpreter is already the right one + if (selectedPythonPath === intendedPythonPath) { + return; + } + + + const optionChange = 'Change interpreter'; + const optionIgnoreUntilClose = 'Ignore until close'; + const optionIgnoreAlways = 'Ignore always'; + const optionNeverShowAgain = `Don't ask again`; + const options = [optionChange, optionIgnoreUntilClose, optionIgnoreAlways, optionNeverShowAgain]; + const nThis = this; + + vscode.window.showWarningMessage('Detected another interpreter for this file!', ...options).then(item => { + switch(item) { + case optionChange: { + nThis.interpreterManager.setPythonPath(intendedPythonPath); + return; + } + case optionIgnoreUntilClose: { + nThis.ignoreShebangTemp.push(document.fileName); + return; + } + case optionIgnoreAlways: { + filesIgnoreAlways.push(document.fileName); + pythonConfig.update('ignoreShebang', filesIgnoreAlways, true); + return; + } + case optionNeverShowAgain: { + pythonConfig.update('disableShebangDetection', true); + return; + } + } + }); + } } \ No newline at end of file From 73c1070fbab6322a23ba6b57d7fccd6f706c9c8d Mon Sep 17 00:00:00 2001 From: Philipp N Date: Sun, 1 Oct 2017 14:57:03 +0200 Subject: [PATCH 3/3] typo in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8237a9743a89..bd49c4156eb7 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "onCommand:python.runtests", "onCommand:python.debugtests", "onCommand:python.setInterpreter", - "onCommand:python.shebangInterpreter", + "onCommand:python.setShebangInterpreter", "onCommand:python.viewTestUI", "onCommand:python.viewTestOutput", "onCommand:python.selectAndRunTestMethod",