1
1
'use strict' ;
2
2
3
+ import * as os from 'os' ;
3
4
import * as path from 'path' ;
4
5
import * as vscode from 'vscode' ;
5
6
import { spawnSync } from 'child_process' ;
@@ -13,7 +14,6 @@ import {
13
14
getOuterMostWorkspaceFolder ,
14
15
pipInstall ,
15
16
resolveVariables ,
16
- pathRelToAbs ,
17
17
} from '../lib/tools' ;
18
18
import { Logger } from '../services/logging' ;
19
19
import { RestartLS } from '../features/commands' ;
@@ -84,9 +84,7 @@ export class FortlsClient {
84
84
if ( ! isFortran ( document ) ) return ;
85
85
86
86
const args : string [ ] = await this . fortlsArguments ( ) ;
87
- const fortlsPath = workspace . getConfiguration ( EXTENSION_ID ) . get < string > ( 'fortls.path' ) ;
88
- let executablePath = resolveVariables ( fortlsPath ) ;
89
- if ( fortlsPath !== 'fortls' ) executablePath = pathRelToAbs ( fortlsPath , document . uri ) ;
87
+ const executablePath : string = await this . fortlsPath ( document ) ;
90
88
91
89
// Detect language server version and verify selected options
92
90
this . version = this . getLSVersion ( executablePath , args ) ;
@@ -308,14 +306,7 @@ export class FortlsClient {
308
306
*/
309
307
private async fortlsDownload ( ) : Promise < boolean > {
310
308
const config = workspace . getConfiguration ( EXTENSION_ID ) ;
311
- let ls = resolveVariables ( config . get < string > ( 'fortls.path' ) ) ;
312
- // The path can be resolved as a relative path if it's part of a workspace
313
- // AND it does not have the default value `fortls` or is an absolute path
314
- if ( workspace . workspaceFolders == undefined && ls !== 'fortls' && ! path . isAbsolute ( ls ) ) {
315
- const root = workspace . workspaceFolders [ 0 ] ;
316
- this . logger . debug ( `[lsp.client] Assuming relative fortls path is to ${ root . uri . fsPath } ` ) ;
317
- ls = pathRelToAbs ( ls , root . uri ) ;
318
- }
309
+ const ls = await this . fortlsPath ( ) ;
319
310
320
311
// Check for version, if this fails fortls provided is invalid
321
312
const results = spawnSync ( ls , [ '--version' ] ) ;
@@ -349,6 +340,50 @@ export class FortlsClient {
349
340
} ) ;
350
341
}
351
342
343
+ /**
344
+ * Try and find the path to the `fortls` executable.
345
+ * It will first try and fetch the top-most workspaceFolder from `document`.
346
+ * If that fails because the document is standalone and does not belong in a
347
+ * workspace it will assume that relative paths are wrt `os.homedir()`.
348
+ *
349
+ * If the `document` argument is missing, then it will try and find the
350
+ * first workspaceFolder and use that as the root. If that fails it will
351
+ * revert back to `os.homedir()`.
352
+ *
353
+ * @param document Optional textdocument
354
+ * @returns a promise with the path to the fortls executable
355
+ */
356
+ private async fortlsPath ( document ?: TextDocument ) : Promise < string > {
357
+ // Get the workspace folder that contains the document, this can be undefined
358
+ // which means that the document is standalone and not part of any workspace.
359
+ let folder : vscode . WorkspaceFolder | undefined ;
360
+ if ( document ) {
361
+ folder = workspace . getWorkspaceFolder ( document . uri ) ;
362
+ }
363
+ // If the document argument is missing, such as in the case of the Client's
364
+ // activation, then try and fetch the first workspace folder to use as a root.
365
+ else {
366
+ folder = workspace . workspaceFolders [ 0 ] ? workspace . workspaceFolders [ 0 ] : undefined ;
367
+ }
368
+
369
+ // Get the outer most workspace folder to resolve relative paths, but if
370
+ // the folder is undefined then use the home directory of the OS
371
+ const root = folder ? getOuterMostWorkspaceFolder ( folder ) . uri : vscode . Uri . parse ( os . homedir ( ) ) ;
372
+
373
+ const config = workspace . getConfiguration ( EXTENSION_ID ) ;
374
+ let executablePath = resolveVariables ( config . get < string > ( 'fortls.path' ) ) ;
375
+
376
+ // The path can be resolved as a relative path if:
377
+ // 1. it does not have the default value `fortls` AND
378
+ // 2. is not an absolute path
379
+ if ( executablePath !== 'fortls' && ! path . isAbsolute ( executablePath ) ) {
380
+ this . logger . debug ( `[lsp.client] Assuming relative fortls path is to ${ root . fsPath } ` ) ;
381
+ executablePath = path . join ( root . fsPath , executablePath ) ;
382
+ }
383
+
384
+ return executablePath ;
385
+ }
386
+
352
387
/**
353
388
* Restart the language server
354
389
*/
0 commit comments