Skip to content

Commit ea8c7a9

Browse files
committed
The binaryPath option was added to the rescript.settings
1 parent 10a5b8d commit ea8c7a9

File tree

4 files changed

+92
-15
lines changed

4 files changed

+92
-15
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@
131131
"type": "boolean",
132132
"default": false,
133133
"description": "Automatically start ReScript's code analysis."
134+
},
135+
"rescript.settings.binaryPath": {
136+
"type": ["string", "null"],
137+
"default": null,
138+
"description": "Path to the directory where ReScript binaries are. You can use it if you haven't or don't want to use the installed ReScript from node_modules in your project."
134139
}
135140
}
136141
},

server/src/constants.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,19 @@ export let analysisProdPath = path.join(
3232
"rescript-editor-analysis.exe"
3333
);
3434

35+
export let rescriptBinName = "rescript";
36+
37+
export let bsbBinName = "bsb";
38+
39+
export let bscBinName = "bsc";
40+
3541
// can't use the native bsb/rescript since we might need the watcher -w flag, which is only in the JS wrapper
3642
export let rescriptNodePartialPath = path.join(
3743
"node_modules",
3844
".bin",
39-
"rescript"
45+
rescriptBinName,
4046
);
41-
export let bsbNodePartialPath = path.join("node_modules", ".bin", "bsb");
47+
export let bsbNodePartialPath = path.join("node_modules", ".bin", bsbBinName);
4248

4349
export let bsbLock = ".bsb.lock";
4450
export let bsconfigPartialPath = "bsconfig.json";

server/src/server.ts

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as v from "vscode-languageserver";
44
import * as rpc from "vscode-jsonrpc/node";
55
import * as path from "path";
66
import fs from "fs";
7+
import os from "os";
78
// TODO: check DidChangeWatchedFilesNotification.
89
import {
910
DidOpenTextDocumentNotification,
@@ -24,9 +25,11 @@ import { filesDiagnostics } from "./utils";
2425

2526
interface extensionConfiguration {
2627
askToStartBuild: boolean;
28+
binaryPath: string | null;
2729
}
2830
let extensionConfiguration: extensionConfiguration = {
2931
askToStartBuild: true,
32+
binaryPath: null,
3033
};
3134
let pullConfigurationPeriodically: NodeJS.Timeout | null = null;
3235

@@ -232,7 +235,12 @@ let openedFile = (fileUri: string, fileContent: string) => {
232235
// TODO: sometime stale .bsb.lock dangling. bsb -w knows .bsb.lock is
233236
// stale. Use that logic
234237
// TODO: close watcher when lang-server shuts down
235-
if (utils.findNodeBuildOfProjectRoot(projectRootPath) != null) {
238+
if (
239+
utils.findNodeBuildOfProjectRoot(
240+
projectRootPath,
241+
extensionConfiguration.binaryPath
242+
) != null
243+
) {
236244
let payload: clientSentBuildAction = {
237245
title: c.startBuildAction,
238246
projectRootPath: projectRootPath,
@@ -254,7 +262,19 @@ let openedFile = (fileUri: string, fileContent: string) => {
254262
// handle in the isResponseMessage check in the message handling way
255263
// below
256264
} else {
257-
// we should send something to say that we can't find bsb.exe. But right now we'll silently not do anything
265+
let binaryPath = extensionConfiguration.binaryPath === null
266+
? path.join(projectRootPath, "node_modules", ".bin")
267+
: extensionConfiguration.binaryPath;
268+
269+
let request: p.NotificationMessage = {
270+
jsonrpc: c.jsonrpcVersion,
271+
method: "window/showMessage",
272+
params: {
273+
type: p.MessageType.Error,
274+
message: `Can't find ReScript binary on path ${binaryPath}`,
275+
},
276+
};
277+
send(request);
258278
}
259279
}
260280

@@ -593,7 +613,11 @@ function format(msg: p.RequestMessage): Array<p.Message> {
593613
} else {
594614
// code will always be defined here, even though technically it can be undefined
595615
let code = getOpenedFileContent(params.textDocument.uri);
596-
let formattedResult = utils.formatCode(filePath, code);
616+
let formattedResult = utils.formatCode(
617+
extensionConfiguration.binaryPath,
618+
filePath,
619+
code
620+
);
597621
if (formattedResult.kind === "success") {
598622
let max = code.length;
599623
let result: p.TextEdit[] = [
@@ -933,6 +957,17 @@ function onMessage(msg: p.Message) {
933957

934958
if (initialConfiguration != null) {
935959
extensionConfiguration = initialConfiguration;
960+
if (
961+
extensionConfiguration.binaryPath !== null &&
962+
extensionConfiguration.binaryPath[0] === "~"
963+
) {
964+
// What should happen if the path contains the home directory symbol?
965+
// This situation is handled below, but maybe it isn't the best option.
966+
extensionConfiguration.binaryPath = path.join(
967+
os.homedir(),
968+
extensionConfiguration.binaryPath.slice(1)
969+
);
970+
}
936971
}
937972

938973
send(response);
@@ -1041,7 +1076,10 @@ function onMessage(msg: p.Message) {
10411076
// TODO: close watcher when lang-server shuts down. However, by Node's
10421077
// default, these subprocesses are automatically killed when this
10431078
// language-server process exits
1044-
let found = utils.findNodeBuildOfProjectRoot(projectRootPath);
1079+
let found = utils.findNodeBuildOfProjectRoot(
1080+
projectRootPath,
1081+
extensionConfiguration.binaryPath
1082+
);
10451083
if (found != null) {
10461084
let bsbProcess = utils.runBuildWatcherUsingValidBuildPath(
10471085
found.buildPath,

server/src/utils.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,32 @@ export let findBscNativeOfFile = (
7070
}
7171
};
7272

73+
let findBscBinFromConfig = (
74+
pathToBinFromConfig: p.DocumentUri | null
75+
): null | p.DocumentUri => {
76+
if (pathToBinFromConfig === null) {
77+
return null;
78+
}
79+
let bscPath = path.join(pathToBinFromConfig, c.bscBinName);
80+
if (fs.existsSync(bscPath)) {
81+
return bscPath;
82+
}
83+
return null;
84+
};
85+
7386
// TODO: this doesn't handle file:/// scheme
7487
export let findNodeBuildOfProjectRoot = (
75-
projectRootPath: p.DocumentUri
88+
projectRootPath: p.DocumentUri,
89+
pathToBinFromConfig: p.DocumentUri | null
7690
): null | { buildPath: p.DocumentUri; isReScript: boolean } => {
77-
let rescriptNodePath = path.join(projectRootPath, c.rescriptNodePartialPath);
78-
let bsbNodePath = path.join(projectRootPath, c.bsbNodePartialPath);
91+
let rescriptNodePath =
92+
pathToBinFromConfig === null
93+
? path.join(projectRootPath, c.rescriptNodePartialPath)
94+
: path.join(pathToBinFromConfig, c.rescriptBinName);
95+
let bsbNodePath =
96+
pathToBinFromConfig === null
97+
? path.join(projectRootPath, c.bsbNodePartialPath)
98+
: path.join(pathToBinFromConfig, c.bsbBinName);
7999

80100
if (fs.existsSync(rescriptNodePath)) {
81101
return { buildPath: rescriptNodePath, isReScript: true };
@@ -94,21 +114,29 @@ type execResult =
94114
kind: "error";
95115
error: string;
96116
};
97-
export let formatCode = (filePath: string, code: string): execResult => {
117+
export let formatCode = (
118+
pathToBinFromConfig: p.DocumentUri | null,
119+
filePath: string,
120+
code: string
121+
): execResult => {
98122
let extension = path.extname(filePath);
99123
let formatTempFileFullPath = createFileInTempDir(extension);
100124
fs.writeFileSync(formatTempFileFullPath, code, {
101125
encoding: "utf-8",
102126
});
103127
try {
128+
// Try to find the bsc bin from the binaryPath setting from the configuration.
129+
let bscPath = findBscBinFromConfig(pathToBinFromConfig);
130+
104131
// See comment on findBscNativeDirOfFile for why we need
105132
// to recursively search for bsc.exe upward
106-
let bscNativePath = findBscNativeOfFile(filePath);
133+
bscPath = bscPath == null ? findBscNativeOfFile(filePath) : bscPath;
107134

108-
// Default to using the project formatter. If not, use the one we ship with
109-
// the analysis binary in the extension itself.
110-
if (bscNativePath != null) {
111-
let result = childProcess.execFileSync(bscNativePath, [
135+
// Default to using the formatter from the binaryPath setting from the configuration
136+
// or the project formatter.
137+
// If not, use the one we ship with the analysis binary in the extension itself.
138+
if (bscPath != null) {
139+
let result = childProcess.execFileSync(bscPath, [
112140
"-color",
113141
"never",
114142
"-format",

0 commit comments

Comments
 (0)