@@ -7,15 +7,47 @@ import * as utils from "./../common/utils";
77let 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 = / ( " p y t h o n \. p y t h o n P a t h " \s * : \s * ) " ( .* ) " / ;
10+ const CONDA_RELATIVE_PY_PATH = utils . IS_WINDOWS ? [ 'python' ] : [ 'bin' , 'python' ]
11+ const REPLACE_PYTHONPATH_REGEXP = / ( " p y t h o n \. p y t h o n P a t h " \s * : \s * ) " ( .* ) " / g ;
1212
1313interface 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+
1951function 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+ }
4388function 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
82127function 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
143210function 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