Skip to content

Commit 178a24b

Browse files
committed
search known paths
1 parent dd5619f commit 178a24b

1 file changed

Lines changed: 86 additions & 26 deletions

File tree

src/client/providers/setInterpreterProvider.ts

Lines changed: 86 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,47 @@ import * as utils from "./../common/utils";
77
let ncp = require("copy-paste");
88

99
// where to find the Python binary within a conda env
10-
const CONDA_RELATIVE_PY_PATH = utils.IS_WINDOWS ? ['python'] : ['bin', 'python']
11-
const REPLACE_PYTHONPATH_REGEXP = /("python\.pythonPath"\s*:\s*)"(.*)"/;
10+
const CONDA_RELATIVE_PY_PATH = utils.IS_WINDOWS ? ['python'] : ['bin', 'python']
11+
const REPLACE_PYTHONPATH_REGEXP = /("python\.pythonPath"\s*:\s*)"(.*)"/g;
1212

1313
interface PythonPathSuggestion {
1414
label: string, // myenvname
1515
path: string, // /full/path/to/bin/python
1616
type: string // conda
1717
}
1818

19+
function getSearchPaths(): string[] {
20+
if (utils.IS_WINDOWS) {
21+
return [
22+
'C:\\Python2.7',
23+
'C:\\Python27',
24+
'C:\\Python3.4',
25+
'C:\\Python34',
26+
'C:\\Python3.5',
27+
'C:\\Python35',
28+
'C:\\Python35-32',
29+
'C:\\Program Files (x86)\\Python 2.7',
30+
'C:\\Program Files (x86)\\Python 3.4',
31+
'C:\\Program Files (x86)\\Python 3.5',
32+
'C:\\Program Files (x64)\\Python 2.7',
33+
'C:\\Program Files (x64)\\Python 3.4',
34+
'C:\\Program Files (x64)\\Python 3.5',
35+
'C:\\Program Files\\Python 2.7',
36+
'C:\\Program Files\\Python 3.4',
37+
'C:\\Program Files\\Python 3.5'
38+
].map(p => path.join(p, 'python.exe'));
39+
} else {
40+
const pyPaths = [];
41+
const pyExecutables = ['python', 'python2.6', 'python2.7', 'python3.3', 'python3.4', 'python3.5'];
42+
['/usr/local/bin', '/usr/bin', '/bin', '/usr/sbin', '/sbin'].forEach(p => {
43+
pyExecutables.forEach(pyExecName => {
44+
pyPaths.push(path.join(p, pyExecName));
45+
});
46+
});
47+
return pyPaths;
48+
}
49+
}
50+
1951
function workspaceSettingsPath() {
2052
return path.join(vscode.workspace.rootPath, '.vscode', 'settings.json')
2153
}
@@ -40,6 +72,19 @@ export function activateSetInterpreterProvider() {
4072
vscode.commands.registerCommand("python.setInterpreter", setInterpreter);
4173
}
4274

75+
function suggestionsFromKnownPaths(): Promise<PythonPathSuggestion[]> {
76+
return new Promise(resolve => {
77+
const validPaths = getSearchPaths().map(p => utils.validatePath(p));
78+
Promise.all<string>(validPaths).then(paths => {
79+
const suggestions = paths.filter(p => p.length > 0).map(p => {
80+
return <PythonPathSuggestion>{
81+
label: path.basename(p), path: p, type: ''
82+
}
83+
});
84+
resolve(suggestions);
85+
});
86+
});
87+
}
4388
function suggestionsFromConda(): Promise<PythonPathSuggestion[]> {
4489
return new Promise((resolve, reject) => {
4590
// interrogate conda (if it's on the path) to find all environments
@@ -71,7 +116,7 @@ function suggestionsFromConda(): Promise<PythonPathSuggestion[]> {
71116
});
72117
}
73118

74-
function suggestionToQuickPickItem(suggestion: PythonPathSuggestion) : vscode.QuickPickItem {
119+
function suggestionToQuickPickItem(suggestion: PythonPathSuggestion): vscode.QuickPickItem {
75120
return {
76121
label: suggestion.label,
77122
description: suggestion.type,
@@ -80,25 +125,43 @@ function suggestionToQuickPickItem(suggestion: PythonPathSuggestion) : vscode.Qu
80125
}
81126

82127
function suggestPythonPaths(): Promise<vscode.QuickPickItem[]> {
83-
84128
// For now we only interrogate conda for suggestions.
85129
const condaSuggestions = suggestionsFromConda();
130+
const knownPathSuggestions = suggestionsFromKnownPaths();
86131

87132
// Here we could also look for virtualenvs/default install locations...
88133

89-
return condaSuggestions.then(
90-
suggestions => suggestions.map(suggestionToQuickPickItem)
91-
);
134+
return Promise.all<PythonPathSuggestion[]>([condaSuggestions, knownPathSuggestions]).then(suggestions => {
135+
const quickPicks: vscode.QuickPickItem[] = [];
136+
suggestions.forEach(list => {
137+
quickPicks.push(...list.map(suggestionToQuickPickItem));
138+
});
139+
140+
return quickPicks;
141+
});
92142
}
93143

94-
function setPythonPath(pythonPath: string) {
95-
vscode.workspace.openTextDocument(workspaceSettingsPath())
144+
function setPythonPath(pythonPath: string, created: boolean = false) {
145+
const settingsFile = workspaceSettingsPath();
146+
utils.validatePath(settingsFile)
147+
.then(validatedPath => {
148+
if (validatedPath.length === 0 && created === true) {
149+
// Something went wrong
150+
return Promise.reject<any>('Unable to create/open the Workspace Settings file');
151+
}
152+
if (validatedPath.length === 0 && !created) {
153+
return new Promise<any>((resolve, reject) => {
154+
vscode.commands.executeCommand('workbench.action.openWorkspaceSettings').then(() => resolve(null), reject);
155+
});
156+
}
157+
return vscode.workspace.openTextDocument(settingsFile)
158+
})
96159
.then(doc => {
97-
const settingsText = doc.getText();
160+
const settingsText = doc ? doc.getText() : '';
98161
if (settingsText.search(REPLACE_PYTHONPATH_REGEXP) === -1) {
99162
// Can't find the setting to replace - will just have to offer a copy button and instruct them to edit themselves.
100163
openWorkspaceSettings().then(() => {
101-
const copyMsg = "Copy to Clipboard"
164+
const copyMsg = "Copy to Clipboard"
102165
const newEntry = `"python.pythonPath": "${pythonPath}"`;
103166
vscode.window.showInformationMessage(`Please add an entry: ${newEntry}`, copyMsg)
104167
.then(item => {
@@ -112,7 +175,7 @@ function setPythonPath(pythonPath: string) {
112175
const newSettingsText = settingsText.replace(REPLACE_PYTHONPATH_REGEXP, `$1"${pythonPath}"`);
113176
replaceContentsOfFile(doc, newSettingsText).then(
114177
() => {
115-
vscode.window.setStatusBarMessage(`Workspace Interpreter set to ${pythonPath}`);
178+
vscode.window.setStatusBarMessage(`Workspace Interpreter set to ${pythonPath}`, 1000);
116179
// As the file is saved the following should be the same as each other but they
117180
// aren't - some form of race condition?
118181
// const currentPythonPath = settings.PythonSettings.getInstance().pythonPath;
@@ -121,6 +184,8 @@ function setPythonPath(pythonPath: string) {
121184
}
122185
)
123186
}
187+
}).catch(reason => {
188+
vscode.window.showErrorMessage('Failed to set the interpreter. ' + reason);
124189
});
125190
}
126191

@@ -132,12 +197,14 @@ function presentQuickPickOfSuggestedPythonPaths() {
132197
placeHolder: `current: ${currentPythonPath}`
133198
}
134199

135-
vscode.window.showQuickPick(suggestPythonPaths(), quickPickOptions).then(
136-
value => {
137-
if (value !== undefined) {
138-
setPythonPath(value.detail);
139-
}
140-
})
200+
suggestPythonPaths().then(suggestions => {
201+
vscode.window.showQuickPick(suggestions, quickPickOptions).then(
202+
value => {
203+
if (value !== undefined) {
204+
setPythonPath(value.detail);
205+
}
206+
});
207+
});
141208
}
142209

143210
function setInterpreter() {
@@ -151,12 +218,5 @@ function setInterpreter() {
151218
vscode.window.showErrorMessage("The interpreter can only be set within a workspace (open a folder)")
152219
return
153220
}
154-
vscode.workspace.openTextDocument(settingsPath).then(
155-
presentQuickPickOfSuggestedPythonPaths,
156-
() => {
157-
// No settings present yet! Trigger the opening of the workspace settings for the first time
158-
// then present the picker.
159-
openWorkspaceSettings().then(presentQuickPickOfSuggestedPythonPaths)
160-
}
161-
)
221+
presentQuickPickOfSuggestedPythonPaths();
162222
}

0 commit comments

Comments
 (0)