Skip to content

Commit 7b3f5ca

Browse files
committed
bug: fortls relative path resolution is unsuccessful
Fixes #693
1 parent 0a64841 commit 7b3f5ca

File tree

2 files changed

+49
-12
lines changed

2 files changed

+49
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
6969

7070
### Fixed
7171

72+
- Fixed bugs in relative path resolution for `fortls`
73+
([#693](https://github.com/fortran-lang/vscode-fortran-support/issues/693))
7274
- Fixed issues with linter unittests running asynchronously
7375
([#623](https://github.com/fortran-lang/vscode-fortran-support/pull/623))
7476
- Fixed `npm run watch-dev` not syncing changes to spawned Extension Dev Host

src/lsp/client.ts

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

3+
import * as os from 'os';
34
import * as path from 'path';
45
import * as vscode from 'vscode';
56
import { spawnSync } from 'child_process';
@@ -13,7 +14,6 @@ import {
1314
getOuterMostWorkspaceFolder,
1415
pipInstall,
1516
resolveVariables,
16-
pathRelToAbs,
1717
} from '../lib/tools';
1818
import { Logger } from '../services/logging';
1919
import { RestartLS } from '../features/commands';
@@ -84,9 +84,7 @@ export class FortlsClient {
8484
if (!isFortran(document)) return;
8585

8686
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);
9088

9189
// Detect language server version and verify selected options
9290
this.version = this.getLSVersion(executablePath, args);
@@ -308,14 +306,7 @@ export class FortlsClient {
308306
*/
309307
private async fortlsDownload(): Promise<boolean> {
310308
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();
319310

320311
// Check for version, if this fails fortls provided is invalid
321312
const results = spawnSync(ls, ['--version']);
@@ -349,6 +340,50 @@ export class FortlsClient {
349340
});
350341
}
351342

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+
352387
/**
353388
* Restart the language server
354389
*/

0 commit comments

Comments
 (0)