@@ -8,20 +8,29 @@ import { RExecutableService } from '../service';
88import { getRenvVersion } from '../service/renv' ;
99
1010class ExecutableQuickPickItem implements vscode . QuickPickItem {
11+ public recommended : boolean ;
12+ public category : string ;
1113 public label : string ;
1214 public description : string ;
1315 public detail ?: string ;
1416 public picked ?: boolean ;
1517 public alwaysShow ?: boolean ;
1618 private _executable : ExecutableType ;
1719
18- constructor ( executable : ExecutableType , recommended ? : boolean ) {
20+ constructor ( executable : ExecutableType , recommended : boolean ) {
1921 this . _executable = executable ;
2022 this . description = executable . rBin ;
2123
24+ if ( isVirtual ( executable ) ) {
25+ this . category = 'Virtual' ;
26+ } else {
27+ this . category = 'Global' ;
28+ }
29+
30+ this . recommended = recommended ;
31+
2232 if ( recommended ) {
2333 this . label = `$(star) ${ executable . tooltip } ` ;
24- this . detail = 'ffffffffffff' ;
2534 } else {
2635 this . label = executable . tooltip ;
2736 }
@@ -53,17 +62,6 @@ export class ExecutableQuickPick implements vscode.Disposable {
5362 }
5463
5564 private setItems ( ) : void {
56- function sortBins ( bins : ExecutableType [ ] ) {
57- return bins . sort ( ( a , b ) => {
58- if ( ! isVirtual ( a ) && isVirtual ( b ) ) {
59- return 1 ;
60- } else if ( ! isVirtual ( b ) && isVirtual ( a ) ) {
61- return - 1 ;
62- } else {
63- return a . rVersion . localeCompare ( b . rVersion , undefined , { numeric : true , sensitivity : 'base' } ) ;
64- }
65- } ) ;
66- }
6765 const qpItems : vscode . QuickPickItem [ ] = [ ] ;
6866 const configPath = config ( ) . get < string > ( getRPathConfigEntry ( ) ) ;
6967 qpItems . push (
@@ -83,47 +81,87 @@ export class ExecutableQuickPick implements vscode.Disposable {
8381 } ) ;
8482 }
8583
84+ const renvVersion = getRenvVersion ( this . currentFolder . uri . fsPath ) ?? undefined ;
85+ const recommendedItems : vscode . QuickPickItem [ ] = [
86+ {
87+ label : 'Recommended' ,
88+ kind : vscode . QuickPickItemKind . Separator
89+ }
90+ ] ;
91+ const virtualItems : vscode . QuickPickItem [ ] = [
92+ {
93+ label : 'Virtual' ,
94+ kind : vscode . QuickPickItemKind . Separator
95+ }
96+ ] ;
97+ const globalItems : vscode . QuickPickItem [ ] = [
98+ {
99+ label : 'Global' ,
100+ kind : vscode . QuickPickItemKind . Separator
101+ }
102+ ] ;
86103
87-
88- sortBins ( [ ...this . service . executables ] ) . forEach ( ( bin : ExecutableType ) => {
89- qpItems . push ( new ExecutableQuickPickItem ( bin , recommendPath ( bin , this . currentFolder ) ) ) ;
104+ [ ...this . service . executables ] . forEach ( ( v ) => {
105+ const item = new ExecutableQuickPickItem ( v , recommendPath ( v , this . currentFolder , renvVersion ) ) ;
106+ if ( item . recommended ) {
107+ recommendedItems . push ( item ) ;
108+ } else {
109+ switch ( item . category ) {
110+ case 'Virtual' : {
111+ virtualItems . push ( item ) ;
112+ break ;
113+ }
114+ case 'Global' : {
115+ globalItems . push ( item ) ;
116+ break ;
117+ }
118+ }
119+ }
90120 } ) ;
91-
92- this . quickpick . items = qpItems ;
93-
121+ this . quickpick . items = [ ...qpItems , ...recommendedItems , ...virtualItems , ...globalItems ] ;
94122 for ( const item of this . quickpick . items ) {
95123 if ( item . description === this . service . getWorkspaceExecutable ( this . currentFolder ?. uri ?. fsPath ) ?. rBin ) {
96124 this . quickpick . activeItems = [ item ] ;
97125 }
98126 }
99127 }
100128
129+ /**
130+ * @description
131+ * Basic display of the quickpick is:
132+ * - Manual executable selection
133+ * - Configuration path (may be hidden)
134+ * - Recommended paths (may be hidden)
135+ * - Virtual paths
136+ * - Global paths
137+ * @returns {* } {Promise<void>}
138+ * @memberof ExecutableQuickPick
139+ */
101140 public async showQuickPick ( ) : Promise < void > {
102- function setupQuickpickOpts ( self : ExecutableQuickPick ) : void {
103- self . quickpick = vscode . window . createQuickPick ( ) ;
104- self . quickpick . title = 'Select R executable path' ;
105- self . quickpick . canSelectMany = false ;
106- self . quickpick . ignoreFocusOut = true ;
107- self . quickpick . matchOnDescription = true ;
108- self . quickpick . placeholder = '' ;
109- self . quickpick . buttons = [
141+ const setupQuickpickOpts = ( ) => {
142+ this . quickpick = vscode . window . createQuickPick ( ) ;
143+ this . quickpick . title = 'Select R executable path' ;
144+ this . quickpick . canSelectMany = false ;
145+ this . quickpick . ignoreFocusOut = true ;
146+ this . quickpick . matchOnDescription = true ;
147+ this . quickpick . buttons = [
110148 { iconPath : new vscode . ThemeIcon ( 'clear-all' ) , tooltip : 'Clear stored path' } ,
111149 { iconPath : new vscode . ThemeIcon ( 'refresh' ) , tooltip : 'Refresh paths' }
112150 ] ;
113- }
151+ } ;
114152
115- function setupQuickpickListeners ( self : ExecutableQuickPick , resolver : ( ) => void ) : void {
116- self . quickpick . onDidTriggerButton ( async ( item : vscode . QuickInputButton ) => {
153+ const setupQuickpickListeners = ( resolver : ( ) => void ) => {
154+ this . quickpick . onDidTriggerButton ( async ( item : vscode . QuickInputButton ) => {
117155 if ( item . tooltip === 'Refresh paths' ) {
118- await self . service . executablePathLocator . refreshPaths ( ) ;
119- self . setItems ( ) ;
120- self . quickpick . show ( ) ;
156+ await this . service . executablePathLocator . refreshPaths ( ) ;
157+ this . setItems ( ) ;
158+ this . quickpick . show ( ) ;
121159 } else {
122- self . service . setWorkspaceExecutable ( self . currentFolder ?. uri ?. fsPath , undefined ) ;
123- self . quickpick . hide ( ) ;
160+ this . service . setWorkspaceExecutable ( this . currentFolder ?. uri ?. fsPath , undefined ) ;
161+ this . quickpick . hide ( ) ;
124162 }
125163 } ) ;
126- self . quickpick . onDidChangeSelection ( ( items : vscode . QuickPickItem [ ] ) => {
164+ this . quickpick . onDidChangeSelection ( ( items : vscode . QuickPickItem [ ] ) => {
127165 const qpItem = items [ 0 ] ;
128166 if ( qpItem . label ) {
129167 switch ( qpItem . label ) {
@@ -136,59 +174,74 @@ export class ExecutableQuickPick implements vscode.Disposable {
136174 } ;
137175 void vscode . window . showOpenDialog ( opts ) . then ( ( execPath ) => {
138176 if ( execPath ?. [ 0 ] . fsPath && validateRExecutablePath ( execPath [ 0 ] . fsPath ) ) {
139- const rExec = self . service . executableFactory . create ( execPath [ 0 ] . fsPath ) ;
140- self . service . setWorkspaceExecutable ( self . currentFolder ?. uri ?. fsPath , rExec ) ;
177+ const rExec = this . service . executableFactory . create ( execPath [ 0 ] . fsPath ) ;
178+ this . service . setWorkspaceExecutable ( this . currentFolder ?. uri ?. fsPath , rExec ) ;
141179 } else {
142180 void vscode . window . showErrorMessage ( ExecutableNotifications . badFolder ) ;
143- self . service . setWorkspaceExecutable ( self . currentFolder ?. uri ?. fsPath , undefined ) ;
181+ this . service . setWorkspaceExecutable ( this . currentFolder ?. uri ?. fsPath , undefined ) ;
144182 }
145183 } ) ;
146184 break ;
147185 }
148186 case PathQuickPickMenu . configuration : {
149187 const configPath = config ( ) . get < string > ( getRPathConfigEntry ( ) ) ;
150188 if ( configPath && validateRExecutablePath ( configPath ) ) {
151- const rExec = self . service . executableFactory . create ( configPath ) ;
152- self . service . setWorkspaceExecutable ( self . currentFolder ?. uri ?. fsPath , rExec ) ;
189+ const rExec = this . service . executableFactory . create ( configPath ) ;
190+ this . service . setWorkspaceExecutable ( this . currentFolder ?. uri ?. fsPath , rExec ) ;
153191 } else {
154192 void vscode . window . showErrorMessage ( ExecutableNotifications . badConfig ) ;
155- self . service . setWorkspaceExecutable ( self . currentFolder ?. uri ?. fsPath , undefined ) ;
193+ this . service . setWorkspaceExecutable ( this . currentFolder ?. uri ?. fsPath , undefined ) ;
156194 }
157195 break ;
158196 }
159197 default : {
160- self . service . setWorkspaceExecutable ( self . currentFolder ?. uri ?. fsPath , ( qpItem as ExecutableQuickPickItem ) . executable ) ;
198+ this . service . setWorkspaceExecutable ( this . currentFolder ?. uri ?. fsPath , ( qpItem as ExecutableQuickPickItem ) . executable ) ;
161199 break ;
162200 }
163201 }
164202 }
165- self . quickpick . hide ( ) ;
203+ this . quickpick . hide ( ) ;
166204 resolver ( ) ;
167205 } ) ;
168- }
206+ } ;
169207
170208 return await new Promise ( ( res ) => {
171- setupQuickpickOpts ( this ) ;
172- setupQuickpickListeners ( this , res ) ;
209+ setupQuickpickOpts ( ) ;
210+ setupQuickpickListeners ( res ) ;
173211 void showWorkspaceFolderQP ( ) . then ( ( folder : vscode . WorkspaceFolder ) => {
174212 this . currentFolder = folder ;
213+ const currentExec = this . service . getWorkspaceExecutable ( folder ?. uri ?. fsPath ) ;
214+ if ( currentExec ) {
215+ this . quickpick . placeholder = `Current path: ${ currentExec . rBin } ` ;
216+ } else {
217+ this . quickpick . placeholder = '' ;
218+ }
175219 this . setItems ( ) ;
176220 this . quickpick . show ( ) ;
177221 } ) ;
178222 } ) ;
179223 }
180224}
181225
182- async function showWorkspaceFolderQP ( ) : Promise < vscode . WorkspaceFolder > {
226+ async function showWorkspaceFolderQP ( ) : Promise < vscode . WorkspaceFolder | undefined > {
183227 const opts : vscode . WorkspaceFolderPickOptions = {
184228 ignoreFocusOut : true ,
185229 placeHolder : 'Select a workspace folder to define an R path for'
186230 } ;
231+ const currentDocument = vscode ?. window ?. activeTextEditor ?. document ?. uri ;
187232 if ( isMultiRoot ( ) ) {
188- return await vscode . window . showWorkspaceFolderPick ( opts ) ;
233+ const workspaceFolder = await vscode . window . showWorkspaceFolderPick ( opts ) ;
234+ if ( workspaceFolder ) {
235+ return workspaceFolder ;
236+ } else if ( currentDocument ) {
237+ return {
238+ index : 0 ,
239+ uri : currentDocument ,
240+ name : 'untitled'
241+ } ;
242+ }
189243 }
190244
191- const currentDocument = vscode ?. window ?. activeTextEditor ?. document ?. uri ;
192245 if ( currentDocument ) {
193246 const folder = vscode . workspace . getWorkspaceFolder ( currentDocument ) ;
194247 if ( folder ) {
@@ -201,12 +254,12 @@ async function showWorkspaceFolderQP(): Promise<vscode.WorkspaceFolder> {
201254 } ;
202255 }
203256 }
257+
258+ return undefined ;
204259}
205260
206- function recommendPath ( executable : ExecutableType , workspaceFolder : vscode . WorkspaceFolder ) : boolean {
207- const renvVersion = getRenvVersion ( workspaceFolder ?. uri ?. fsPath ) ;
261+ function recommendPath ( executable : ExecutableType , workspaceFolder : vscode . WorkspaceFolder , renvVersion ?: string ) : boolean {
208262 if ( renvVersion ) {
209- console . log ( renvVersion ) ;
210263 const compatibleBin = renvVersion === executable . rVersion ;
211264 if ( compatibleBin ) {
212265 return true ;
@@ -215,5 +268,5 @@ function recommendPath(executable: ExecutableType, workspaceFolder: vscode.Works
215268 }
216269 const uri = vscode . Uri . file ( executable . rBin ) ;
217270 const possibleWorkspace = vscode . workspace . getWorkspaceFolder ( uri ) ;
218- return possibleWorkspace && possibleWorkspace === workspaceFolder ;
271+ return ! ! possibleWorkspace && possibleWorkspace === workspaceFolder ;
219272}
0 commit comments