Skip to content

Commit f9fccd4

Browse files
Make OmniSharp launch settings more robust
The extension looks in three locations for OmniSharp: 1. Whatever the user specified in the "csharp.omnisharp" setting. 2. The value of the "OMNISHARP" environment variable. 3. The expected location where the bundled OmniSharp is copied. If #1 was set, dotnet#2 and dotnet#3 would be ignored even if the value of #1 was invalid. Likewise, if dotnet#2 was set, dotnet#3 would be ignored even if the value of dotnet#2 was invalid. This change adds fallback logic to try the next option if an invalid value is encountered. In addition, it is more robust depending on whether a file or directory name is specified. If the value is a directory, it will try 'run' (run.cmd on Windows) or 'omnisharp' (omnisharp.exe on Windows) as possible launch file names.
1 parent 36a47ab commit f9fccd4

File tree

2 files changed

+83
-30
lines changed

2 files changed

+83
-30
lines changed

src/omnisharpPath.ts

+80-27
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,91 @@ import * as fs from 'fs';
99
import * as path from 'path';
1010
import * as vscode from 'vscode';
1111

12-
const omnisharpEnv = 'OMNISHARP';
13-
const isWindows = process.platform === 'win32';
12+
const runFileName = process.platform === 'win32' ? 'run.cmd' : 'run';
13+
const omniSharpFileName = process.platform === 'win32' ? 'omnisharp.exe' : 'omnisharp';
1414

15-
export function getOmnisharpPath(): Promise<string> {
15+
enum PathKind {
16+
File,
17+
Directory
18+
}
1619

17-
let pathCandidate: string;
20+
function getPathKind(filePath: string): Promise<PathKind> {
21+
return new Promise<PathKind>((resolve, reject) => {
22+
fs.lstat(filePath, (err, stats) => {
23+
if (err) {
24+
reject(err);
25+
}
26+
else if (stats.isFile()) {
27+
resolve(PathKind.File);
28+
}
29+
else if (stats.isDirectory()) {
30+
resolve(PathKind.Directory);
31+
}
32+
else {
33+
reject(Error(`Path is not file or directory: ${filePath}`));
34+
}
35+
});
36+
});
37+
}
1838

19-
let config = vscode.workspace.getConfiguration();
20-
if (config.has('csharp.omnisharp')) {
21-
// form config
22-
pathCandidate = config.get<string>('csharp.omnisharp');
39+
function getLaunchFilePath(filePath: string): Promise<string> {
40+
return getPathKind(filePath)
41+
.then(kind => {
42+
if (kind === PathKind.File) {
43+
return filePath;
44+
}
45+
else {
46+
// Look for launch file since kind === PathKind.Directory
47+
48+
let candidate: string;
2349

24-
} else if (typeof process.env[omnisharpEnv] === 'string') {
25-
// form enviroment variable
50+
candidate = path.join(filePath, runFileName);
51+
if (fs.existsSync(candidate)) {
52+
return candidate;
53+
}
54+
55+
candidate = path.join(filePath, omniSharpFileName);
56+
if (fs.existsSync(candidate)) {
57+
return candidate;
58+
}
59+
60+
throw new Error(`Could not find launch file in ${filePath}. Expected '${runFileName}' or '${omniSharpFileName}.`);
61+
}
62+
});
63+
}
64+
65+
function getLaunchPathFromSettings(): Promise<string> {
66+
const setting = vscode.workspace.getConfiguration('csharp').get<string>('omnisharp');
67+
if (setting) {
68+
return getLaunchFilePath(setting);
69+
}
70+
71+
return Promise.reject<string>(Error('OmniSharp user setting does not exist.'));
72+
}
73+
74+
function getLaunchPathFromEnvironmentVariable(): Promise<string> {
75+
const variable = process.env["OMNISHARP"];
76+
if (typeof variable === 'string') {
2677
console.warn('[deprecated] use workspace or user settings with "csharp.omnisharp":"/path/to/omnisharp"');
27-
pathCandidate = process.env[omnisharpEnv];
28-
29-
} else {
30-
// bundled version of Omnisharp
31-
pathCandidate = path.join(__dirname, '../bin/omnisharp')
32-
if (isWindows) {
33-
pathCandidate += '.cmd';
34-
}
78+
return getLaunchFilePath(variable);
3579
}
80+
81+
return Promise.reject<string>(Error('OmniSharp environment variable does not exist.'));
82+
}
83+
84+
function getLaunchPathFromDefaultInstallLocation(): Promise<string> {
85+
const installLocation = getDefaultOmnisharpInstallLocation();
86+
return getLaunchFilePath(installLocation);
87+
}
88+
89+
export function getDefaultOmnisharpInstallLocation(): string {
90+
return path.join(__dirname, '../.omnisharp');
91+
}
3692

37-
return new Promise<string>((resolve, reject) => {
38-
fs.exists(pathCandidate, localExists => {
39-
if (localExists) {
40-
resolve(pathCandidate);
41-
} else {
42-
reject('OmniSharp does not exist at location: ' + pathCandidate);
43-
}
44-
});
45-
});
93+
export function getOmnisharpLaunchFilePath(): Promise<string> {
94+
// Attempt to find launch file path first from settings, then from environment variable, and finally from the default install location.
95+
96+
return getLaunchPathFromSettings()
97+
.catch(getLaunchPathFromEnvironmentVariable)
98+
.catch(getLaunchPathFromDefaultInstallLocation);
4699
}

src/omnisharpServerLauncher.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
'use strict';
77

88
import {spawn, ChildProcess} from 'child_process';
9-
import {getOmnisharpPath} from './omnisharpPath';
9+
import {getOmnisharpLaunchFilePath} from './omnisharpPath';
1010
import {satisfies} from 'semver';
1111

1212
var isWindows = /^win/.test(process.platform);
@@ -36,7 +36,7 @@ export default function launch(cwd: string, args: string[]):Promise < { process:
3636
}
3737

3838
function launchWindows(cwd: string, args: string[]): Promise<{ process: ChildProcess, command: string }> {
39-
return getOmnisharpPath().then(command => {
39+
return getOmnisharpLaunchFilePath().then(command => {
4040

4141
args = args.slice(0);
4242
args.unshift(command);
@@ -71,7 +71,7 @@ function launchNix(cwd: string, args: string[]): Promise<{ process: ChildProcess
7171
}
7272
});
7373
}).then(_ => {
74-
return getOmnisharpPath();
74+
return getOmnisharpLaunchFilePath();
7575
}).then(command => {
7676
let process = spawn(command, args, {
7777
detached: false,

0 commit comments

Comments
 (0)