@@ -6,6 +6,7 @@ import { config, getCurrentWorkspaceFolder, getRPathConfigEntry } from '../../ut
66import { RExecutablePathStorage } from './pathStorage' ;
77import { RExecutableRegistry } from './registry' ;
88import { AbstractLocatorService , LocatorServiceFactory } from './locator' ;
9+ import { getRenvVersion } from './renv' ;
910
1011export * from './class' ;
1112
@@ -15,7 +16,7 @@ export * from './class';
1516 * @interface WorkspaceExecutableEvent
1617 */
1718export interface WorkspaceExecutableEvent {
18- workingFolder : vscode . WorkspaceFolder ,
19+ workingFolder : vscode . WorkspaceFolder | undefined ,
1920 executable : ExecutableType | undefined
2021}
2122
@@ -26,50 +27,47 @@ export interface WorkspaceExecutableEvent {
2627 * @implements {vscode.Disposable}
2728 */
2829export class RExecutableService implements vscode . Disposable {
29- public readonly executableFactory : RExecutableFactory ;
30- public readonly executablePathLocator : AbstractLocatorService ;
31- private readonly executableStorage : RExecutablePathStorage ;
32- private readonly executableRegistry : RExecutableRegistry ;
33- private executableEmitter : vscode . EventEmitter < ExecutableType > ;
30+ public executableFactory : RExecutableFactory ;
31+ public executablePathLocator : AbstractLocatorService ;
32+ private executableStorage : RExecutablePathStorage ;
33+ private executableRegistry : RExecutableRegistry ;
34+ private executableEmitter : vscode . EventEmitter < ExecutableType | undefined > ;
3435 private workspaceEmitter : vscode . EventEmitter < WorkspaceExecutableEvent > ;
35- private workspaceExecutables : Map < string , ExecutableType > ;
36+ private workspaceExecutables : Map < string , ExecutableType | undefined > ;
3637
38+ public readonly ready : Thenable < this> ;
3739
3840 /**
3941 * Creates an instance of RExecutableService.
4042 * @memberof RExecutableService
4143 */
42- public constructor ( ) {
43- this . executablePathLocator = LocatorServiceFactory . getLocator ( ) ;
44- this . executablePathLocator . refreshPaths ( ) ;
44+ private constructor ( locator : AbstractLocatorService ) {
45+ this . executablePathLocator = locator ;
4546 this . executableRegistry = new RExecutableRegistry ( ) ;
4647 this . executableStorage = new RExecutablePathStorage ( ) ;
4748 this . executableFactory = new RExecutableFactory ( this . executableRegistry ) ;
4849 this . workspaceExecutables = new Map < string , ExecutableType > ( ) ;
49-
5050 this . executableEmitter = new vscode . EventEmitter < ExecutableType > ( ) ;
5151 this . workspaceEmitter = new vscode . EventEmitter < WorkspaceExecutableEvent > ( ) ;
52-
53- // create executables for all executable paths found
5452 this . executablePathLocator . binaryPaths . forEach ( ( path ) => {
5553 this . executableFactory . create ( path ) ;
5654 } ) ;
5755
58- const confPath = config ( ) . get < string > ( getRPathConfigEntry ( ) ) ;
59- // from storage, recreate associations between workspace paths and executable paths
60- for ( const [ dirPath , execPath ] of this . executableStorage . executablePaths ) {
61- if ( validateRExecutablePath ( execPath ) ) {
62- this . workspaceExecutables . set ( dirPath , this . executableFactory . create ( execPath ) ) ;
63- }
64- }
56+ this . selectViableExecutables ( ) ;
57+ }
6558
66- if ( ! this . executableStorage . getActiveExecutablePath ( ) && confPath && validateRExecutablePath ( confPath ) ) {
67- console . log ( `[RExecutableService] Executable set to configuration path: ${ confPath } ` ) ;
68- const exec = this . executableFactory . create ( confPath ) ;
69- this . activeExecutable = exec ;
70- }
59+ static async initialize ( ) : Promise < RExecutableService > {
60+ const locator = LocatorServiceFactory . getLocator ( ) ;
61+ await locator . refreshPaths ( ) ;
62+ return new this ( locator ) ;
7163 }
7264
65+ /**
66+ * @description
67+ * @readonly
68+ * @type {Set<ExecutableType> }
69+ * @memberof RExecutableService
70+ */
7371 public get executables ( ) : Set < ExecutableType > {
7472 return this . executableRegistry . executables ;
7573 }
@@ -78,12 +76,12 @@ export class RExecutableService implements vscode.Disposable {
7876 * @description
7977 * @memberof RExecutableService
8078 */
81- public set activeExecutable ( executable : ExecutableType ) {
82- if ( executable === null ) {
79+ public set activeExecutable ( executable : ExecutableType | undefined ) {
80+ if ( executable === undefined ) {
8381 this . workspaceExecutables . delete ( getCurrentWorkspaceFolder ( ) . uri . fsPath ) ;
84- this . executableStorage . setExecutablePath ( getCurrentWorkspaceFolder ( ) . uri . fsPath , null ) ;
82+ this . executableStorage . setExecutablePath ( getCurrentWorkspaceFolder ( ) . uri . fsPath , undefined ) ;
8583 console . log ( '[RExecutableService] executable cleared' ) ;
86- this . executableEmitter . fire ( null ) ;
84+ this . executableEmitter . fire ( undefined ) ;
8785 } else if ( this . activeExecutable !== executable ) {
8886 this . workspaceExecutables . set ( getCurrentWorkspaceFolder ( ) . uri . fsPath , executable ) ;
8987 this . executableStorage . setExecutablePath ( getCurrentWorkspaceFolder ( ) . uri . fsPath , executable . rBin ) ;
@@ -100,12 +98,17 @@ export class RExecutableService implements vscode.Disposable {
10098 * @memberof RExecutableService
10199 */
102100 public get activeExecutable ( ) : ExecutableType | undefined {
103- const currWorkspacePath = getCurrentWorkspaceFolder ( ) . uri . fsPath ;
101+ const currWorkspacePath = getCurrentWorkspaceFolder ( ) ? .uri ? .fsPath ;
104102 if ( currWorkspacePath ) {
105103 return this . workspaceExecutables . get ( currWorkspacePath ) ;
106- } else {
107- return this . workspaceExecutables . get ( vscode . window . activeTextEditor . document . uri . fsPath ) ;
108104 }
105+
106+ const currentDocument = vscode ?. window ?. activeTextEditor ?. document ?. uri ?. fsPath ;
107+ if ( currentDocument ) {
108+ return this . workspaceExecutables . get ( currentDocument ) ;
109+ }
110+
111+ return undefined ;
109112 }
110113
111114 /**
@@ -115,7 +118,7 @@ export class RExecutableService implements vscode.Disposable {
115118 * @param {RExecutable } executable
116119 * @memberof RExecutableService
117120 */
118- public setWorkspaceExecutable ( folder : string , executable : ExecutableType ) : void {
121+ public setWorkspaceExecutable ( folder : string , executable : ExecutableType | undefined ) : void {
119122 if ( this . workspaceExecutables . get ( folder ) !== executable ) {
120123 if ( executable === undefined ) {
121124 this . executableStorage . setExecutablePath ( folder , undefined ) ;
@@ -137,7 +140,7 @@ export class RExecutableService implements vscode.Disposable {
137140 * @returns {* } {RExecutable}
138141 * @memberof RExecutableService
139142 */
140- public getWorkspaceExecutable ( folder : string ) : ExecutableType | undefined {
143+ public getWorkspaceExecutable ( folder : string ) : ExecutableType | undefined {
141144 return this . workspaceExecutables . get ( folder ) ;
142145 }
143146
@@ -149,7 +152,7 @@ export class RExecutableService implements vscode.Disposable {
149152 * @type {vscode.Event<RExecutable> }
150153 * @memberof RExecutableService
151154 */
152- public get onDidChangeActiveExecutable ( ) : vscode . Event < ExecutableType > {
155+ public get onDidChangeActiveExecutable ( ) : vscode . Event < ExecutableType | undefined > {
153156 return this . executableEmitter . event ;
154157 }
155158
@@ -172,4 +175,54 @@ export class RExecutableService implements vscode.Disposable {
172175 this . executableEmitter . dispose ( ) ;
173176 this . workspaceEmitter . dispose ( ) ;
174177 }
178+
179+ private selectViableExecutables ( ) : void {
180+ // from storage, recreate associations between workspace paths and executable paths
181+ for ( const [ dirPath , execPath ] of this . executableStorage . executablePaths ) {
182+ if ( validateRExecutablePath ( execPath ) ) {
183+ this . workspaceExecutables . set ( dirPath , this . executableFactory . create ( execPath ) ) ;
184+ }
185+ }
186+
187+ const confPath = config ( ) . get < string > ( getRPathConfigEntry ( ) ) ;
188+ if ( vscode . workspace . workspaceFolders ) {
189+ for ( const workspace of vscode . workspace . workspaceFolders ) {
190+ const workspacePath = workspace . uri . path ;
191+ if ( ! this . workspaceExecutables . has ( workspacePath ) ) {
192+ // is there a local virtual env?
193+ // todo
194+
195+ // is there a renv-recommended version?
196+ const renvVersion = getRenvVersion ( workspacePath ) ;
197+ if ( renvVersion ) {
198+ const compatibleExecutables = this . executableRegistry . getExecutablesWithVersion ( renvVersion ) ;
199+ if ( compatibleExecutables ) {
200+ const exec = compatibleExecutables . sort ( ( a , b ) => {
201+ if ( a . rBin === confPath ) {
202+ return - 1 ;
203+ }
204+ if ( b . rBin === confPath ) {
205+ return 1 ;
206+ }
207+ return 0 ;
208+ } ) [ 0 ] ;
209+ this . workspaceExecutables . set ( workspacePath , exec ) ;
210+ return ;
211+ }
212+ }
213+
214+ // fallback to a configured path if it exists
215+ if ( confPath && validateRExecutablePath ( confPath ) ) {
216+ console . log ( `[RExecutableService] Executable set to configuration path: ${ confPath } ` ) ;
217+ const exec = this . executableFactory . create ( confPath ) ;
218+ this . workspaceExecutables . set ( workspacePath , exec ) ;
219+ }
220+ }
221+ }
222+ } else {
223+ // todo
224+ }
225+ }
175226}
227+
228+
0 commit comments