@@ -4,36 +4,47 @@ import { ConfigurationTarget, Disposable, QuickPickItem, QuickPickOptions, Uri }
44import { IApplicationShell , ICommandManager , IDocumentManager , IWorkspaceService } from '../../common/application/types' ;
55import * as settings from '../../common/configSettings' ;
66import { Commands } from '../../common/constants' ;
7+ import { IFileSystem } from '../../common/platform/types' ;
78import { IServiceContainer } from '../../ioc/types' ;
89import { IInterpreterService , IShebangCodeLensProvider , PythonInterpreter , WorkspacePythonPath } from '../contracts' ;
910import { IInterpreterSelector , IPythonPathUpdaterServiceManager } from './types' ;
1011
11- interface IInterpreterQuickPickItem extends QuickPickItem {
12+ export interface IInterpreterQuickPickItem extends QuickPickItem {
1213 path : string ;
1314}
1415
1516@injectable ( )
1617export class InterpreterSelector implements IInterpreterSelector {
1718 private disposables : Disposable [ ] = [ ] ;
18- private pythonPathUpdaterService : IPythonPathUpdaterServiceManager ;
1919 private readonly interpreterManager : IInterpreterService ;
2020 private readonly workspaceService : IWorkspaceService ;
2121 private readonly applicationShell : IApplicationShell ;
2222 private readonly documentManager : IDocumentManager ;
23+ private readonly fileSystem : IFileSystem ;
24+
2325 constructor ( @inject ( IServiceContainer ) private serviceContainer : IServiceContainer ) {
2426 this . interpreterManager = serviceContainer . get < IInterpreterService > ( IInterpreterService ) ;
2527 this . workspaceService = this . serviceContainer . get < IWorkspaceService > ( IWorkspaceService ) ;
2628 this . applicationShell = this . serviceContainer . get < IApplicationShell > ( IApplicationShell ) ;
2729 this . documentManager = this . serviceContainer . get < IDocumentManager > ( IDocumentManager ) ;
30+ this . fileSystem = this . serviceContainer . get < IFileSystem > ( IFileSystem ) ;
2831
2932 const commandManager = serviceContainer . get < ICommandManager > ( ICommandManager ) ;
3033 this . disposables . push ( commandManager . registerCommand ( Commands . Set_Interpreter , this . setInterpreter . bind ( this ) ) ) ;
3134 this . disposables . push ( commandManager . registerCommand ( Commands . Set_ShebangInterpreter , this . setShebangInterpreter . bind ( this ) ) ) ;
32- this . pythonPathUpdaterService = serviceContainer . get < IPythonPathUpdaterServiceManager > ( IPythonPathUpdaterServiceManager ) ;
3335 }
3436 public dispose ( ) {
3537 this . disposables . forEach ( disposable => disposable . dispose ( ) ) ;
3638 }
39+
40+ public async getSuggestions ( resourceUri ?: Uri ) {
41+ let interpreters = await this . interpreterManager . getInterpreters ( resourceUri ) ;
42+ interpreters = await this . removeDuplicates ( interpreters ) ;
43+ // tslint:disable-next-line:no-non-null-assertion
44+ interpreters . sort ( ( a , b ) => a . displayName ! > b . displayName ! ? 1 : - 1 ) ;
45+ return Promise . all ( interpreters . map ( item => this . suggestionToQuickPickItem ( item , resourceUri ) ) ) ;
46+ }
47+
3748 private async getWorkspaceToSetPythonPath ( ) : Promise < WorkspacePythonPath | undefined > {
3849 if ( ! Array . isArray ( this . workspaceService . workspaceFolders ) || this . workspaceService . workspaceFolders . length === 0 ) {
3950 return undefined ;
@@ -47,6 +58,7 @@ export class InterpreterSelector implements IInterpreterSelector {
4758 const workspaceFolder = await applicationShell . showWorkspaceFolderPick ( { placeHolder : 'Select a workspace' } ) ;
4859 return workspaceFolder ? { folderUri : workspaceFolder . uri , configTarget : ConfigurationTarget . WorkspaceFolder } : undefined ;
4960 }
61+
5062 private async suggestionToQuickPickItem ( suggestion : PythonInterpreter , workspaceUri ?: Uri ) : Promise < IInterpreterQuickPickItem > {
5163 let detail = suggestion . path ;
5264 if ( workspaceUri && suggestion . path . startsWith ( workspaceUri . fsPath ) ) {
@@ -62,11 +74,19 @@ export class InterpreterSelector implements IInterpreterSelector {
6274 } ;
6375 }
6476
65- private async getSuggestions ( resourceUri ?: Uri ) {
66- const interpreters = await this . interpreterManager . getInterpreters ( resourceUri ) ;
67- // tslint:disable-next-line:no-non-null-assertion
68- interpreters . sort ( ( a , b ) => a . displayName ! > b . displayName ! ? 1 : - 1 ) ;
69- return Promise . all ( interpreters . map ( item => this . suggestionToQuickPickItem ( item , resourceUri ) ) ) ;
77+ private async removeDuplicates ( interpreters : PythonInterpreter [ ] ) : Promise < PythonInterpreter [ ] > {
78+ const result : PythonInterpreter [ ] = [ ] ;
79+ await Promise . all ( interpreters . filter ( async x => {
80+ x . realPath = await this . fileSystem . getRealPathAsync ( x . path ) ;
81+ return true ;
82+ } ) ) ;
83+ interpreters . forEach ( x => {
84+ if ( result . findIndex ( a => a . displayName === x . displayName
85+ && a . type === x . type && this . fileSystem . arePathsSame ( a . realPath ! , x . realPath ! ) ) < 0 ) {
86+ result . push ( x ) ;
87+ }
88+ } ) ;
89+ return result ;
7090 }
7191
7292 private async setInterpreter ( ) {
@@ -95,7 +115,8 @@ export class InterpreterSelector implements IInterpreterSelector {
95115
96116 const selection = await this . applicationShell . showQuickPick ( suggestions , quickPickOptions ) ;
97117 if ( selection !== undefined ) {
98- await this . pythonPathUpdaterService . updatePythonPath ( selection . path , configTarget , 'ui' , wkspace ) ;
118+ const pythonPathUpdaterService = this . serviceContainer . get < IPythonPathUpdaterServiceManager > ( IPythonPathUpdaterServiceManager ) ;
119+ await pythonPathUpdaterService . updatePythonPath ( selection . path , configTarget , 'ui' , wkspace ) ;
99120 }
100121 }
101122
@@ -110,16 +131,17 @@ export class InterpreterSelector implements IInterpreterSelector {
110131 const workspaceFolder = this . workspaceService . getWorkspaceFolder ( this . documentManager . activeTextEditor ! . document . uri ) ;
111132 const isWorkspaceChange = Array . isArray ( this . workspaceService . workspaceFolders ) && this . workspaceService . workspaceFolders . length === 1 ;
112133
134+ const pythonPathUpdaterService = this . serviceContainer . get < IPythonPathUpdaterServiceManager > ( IPythonPathUpdaterServiceManager ) ;
113135 if ( isGlobalChange ) {
114- await this . pythonPathUpdaterService . updatePythonPath ( shebang , ConfigurationTarget . Global , 'shebang' ) ;
136+ await pythonPathUpdaterService . updatePythonPath ( shebang , ConfigurationTarget . Global , 'shebang' ) ;
115137 return ;
116138 }
117139
118140 if ( isWorkspaceChange || ! workspaceFolder ) {
119- await this . pythonPathUpdaterService . updatePythonPath ( shebang , ConfigurationTarget . Workspace , 'shebang' , this . workspaceService . workspaceFolders ! [ 0 ] . uri ) ;
141+ await pythonPathUpdaterService . updatePythonPath ( shebang , ConfigurationTarget . Workspace , 'shebang' , this . workspaceService . workspaceFolders ! [ 0 ] . uri ) ;
120142 return ;
121143 }
122144
123- await this . pythonPathUpdaterService . updatePythonPath ( shebang , ConfigurationTarget . WorkspaceFolder , 'shebang' , workspaceFolder . uri ) ;
145+ await pythonPathUpdaterService . updatePythonPath ( shebang , ConfigurationTarget . WorkspaceFolder , 'shebang' , workspaceFolder . uri ) ;
124146 }
125147}
0 commit comments