Skip to content

Commit e79872c

Browse files
Bart Schuurmanstsnobip
Bart Schuurmans
andauthored
Add rescript.settings.platformPath and correctly determine its default value (#573)
* Tweak description of rescript.settings.binaryPath * Add rescript.settings.platformPath * Add utils.findFilePathFromProjectRoot() * Remove unused utils.findBscBinary() * Rewrite algorithm to find bsc.exe based on platformPath Should fix formatting in monorepos. Fixes #572 Co-authored-by: Paul Tsnobiladzé <paul.tsnobiladze@gmail.com>
1 parent 36dbc3e commit e79872c

File tree

4 files changed

+71
-70
lines changed

4 files changed

+71
-70
lines changed

README.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,15 @@ Even if the pre-release channel seems too experimental to you, we still suggest
104104

105105
You'll find all ReScript specific settings under the scope `rescript.settings`.
106106

107-
| Setting | Description |
108-
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
109-
| Prompt to Start Build | If there's no ReScript build running already in the opened project, the extension will prompt you and ask if you want to start a build automatically. You can turn off this automatic prompt via the setting `rescript.settings.askToStartBuild`. |
110-
| ReScript Binary Path | The extension will look for the existence of a `/node_modules/.bin/rescript` file and use its directory as the `binaryPath`. If it does not find it at the project root (which is where the nearest `bsconfig.json` resides), it goes up folders in the filesystem recursively until it either finds it (often the case in monorepos) or hits the top level. To override this lookup process, the path can be configured explicitly using the setting `rescript.settings.binaryPath` |
111-
| Inlay Hints (experimental) | This allows an editor to place annotations inline with text to display type hints. Enable using `rescript.settings.inlayHints.enable: true` |
112-
| Code Lens (experimental) | This tells the editor to add code lenses to function definitions, showing its full type above the definition. Enable using `rescript.settings.codeLens: true` |
113-
| Signature Help (experimental) | This tells the editor to show signature help when you're writing function calls. Enable using `rescript.settings.signatureHelp.enable: true` |
114-
| Autostarting the Code Analyzer | The Code Analyzer needs to be started manually by default. However, you can configure the extension to start the Code Analyzer automatically via the setting `rescript.settings.autoRunCodeAnalysis`. |
107+
| Setting | Description |
108+
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
109+
| Prompt to Start Build | If there's no ReScript build running already in the opened project, the extension will prompt you and ask if you want to start a build automatically. You can turn off this automatic prompt via the setting `rescript.settings.askToStartBuild`. |
110+
| ReScript Binary Path | The extension will look for the existence of a `node_modules/.bin/rescript` file and use its directory as the `binaryPath`. If it does not find it at the project root (which is where the nearest `bsconfig.json` resides), it goes up folders in the filesystem recursively until it either finds it (often the case in monorepos) or hits the top level. To override this lookup process, the path can be configured explicitly using the setting `rescript.settings.binaryPath` |
111+
| ReScript Platform Path | The extension will look for the existence of a `node_modules/rescript` directory and use the subdirectory corresponding to the current platform as the `platformPath`. If it does not find it at the project root (which is where the nearest `bsconfig.json` resides), it goes up folders in the filesystem recursively until it either finds it (often the case in monorepos) or hits the top level. To override this lookup process, the path can be configured explicitly using the setting `rescript.settings.platformPath` |
112+
| Inlay Hints (experimental) | This allows an editor to place annotations inline with text to display type hints. Enable using `rescript.settings.inlayHints.enable: true` |
113+
| Code Lens (experimental) | This tells the editor to add code lenses to function definitions, showing its full type above the definition. Enable using `rescript.settings.codeLens: true` |
114+
| Signature Help (experimental) | This tells the editor to show signature help when you're writing function calls. Enable using `rescript.settings.signatureHelp.enable: true` |
115+
| Autostarting the Code Analyzer | The Code Analyzer needs to be started manually by default. However, you can configure the extension to start the Code Analyzer automatically via the setting `rescript.settings.autoRunCodeAnalysis`. |
115116

116117
**Default settings:**
117118

@@ -122,9 +123,12 @@ You'll find all ReScript specific settings under the scope `rescript.settings`.
122123
// Automatically start ReScript's code analysis.
123124
"rescript.settings.autoRunCodeAnalysis": false,
124125

125-
// 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.
126+
// Path to the directory where cross-platform 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.
126127
"rescript.settings.binaryPath": null
127128

129+
// Path to the directory where platform-specific 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.
130+
"rescript.settings.platformPath": null
131+
128132
// Enable (experimental) inlay hints.
129133
"rescript.settings.inlayHints.enable": true
130134

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,12 @@
166166
"rescript.settings.binaryPath": {
167167
"type": ["string", "null"],
168168
"default": null,
169-
"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."
169+
"description": "Path to the directory where cross-platform 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."
170+
},
171+
"rescript.settings.platformPath": {
172+
"type": ["string", "null"],
173+
"default": null,
174+
"description": "Path to the directory where platform-specific 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."
170175
}
171176
}
172177
},

server/src/server.ts

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ interface extensionConfiguration {
3434
};
3535
codeLens: boolean;
3636
binaryPath: string | null;
37+
platformPath: string | null;
3738
signatureHelp: {
3839
enable: boolean;
3940
};
@@ -58,6 +59,7 @@ let extensionConfiguration: extensionConfiguration = {
5859
},
5960
codeLens: false,
6061
binaryPath: null,
62+
platformPath: null,
6163
signatureHelp: {
6264
enable: false,
6365
},
@@ -98,60 +100,37 @@ let codeActionsFromDiagnostics: codeActions.filesCodeActions = {};
98100
// will be properly defined later depending on the mode (stdio/node-rpc)
99101
let send: (msg: p.Message) => void = (_) => {};
100102

101-
// Check if the rescript binary is available at node_modules/.bin/rescript,
102-
// otherwise recursively check parent directories for it.
103-
let findBinaryPathFromProjectRoot = (
104-
directory: p.DocumentUri // This must be a directory and not a file!
105-
): null | p.DocumentUri => {
106-
let binaryDirPath = path.join(directory, c.nodeModulesBinDir);
107-
let binaryPath = path.join(binaryDirPath, c.rescriptBinName);
103+
let findRescriptBinary = (projectRootPath: p.DocumentUri | null) =>
104+
extensionConfiguration.binaryPath == null
105+
? utils.findFilePathFromProjectRoot(projectRootPath, path.join(c.nodeModulesBinDir, c.rescriptBinName))
106+
: utils.findBinary(extensionConfiguration.binaryPath, c.rescriptBinName);
108107

109-
if (fs.existsSync(binaryPath)) {
110-
return binaryPath;
108+
let findPlatformPath = (projectRootPath: p.DocumentUri | null) => {
109+
if (extensionConfiguration.platformPath != null) {
110+
return extensionConfiguration.platformPath;
111111
}
112112

113-
let parentDir = path.dirname(directory);
114-
if (parentDir === directory) {
115-
// reached the top
113+
let rescriptDir = utils.findFilePathFromProjectRoot(projectRootPath, path.join("node_modules", "rescript"));
114+
if (rescriptDir == null) {
116115
return null;
117116
}
118117

119-
return findBinaryPathFromProjectRoot(parentDir);
120-
};
121-
122-
let findRescriptBinary = (projectRootPath: p.DocumentUri) =>
123-
extensionConfiguration.binaryPath == null
124-
? findBinaryPathFromProjectRoot(projectRootPath)
125-
: utils.findRescriptBinary(extensionConfiguration.binaryPath);
126-
127-
let findBscBinary = (projectRootPath: p.DocumentUri) => {
128-
let rescriptBinaryPath = findRescriptBinary(projectRootPath);
129-
if (rescriptBinaryPath !== null) {
130-
let rescriptDirPath = path.join(
131-
path.dirname(rescriptBinaryPath),
132-
"..",
133-
"rescript"
134-
);
118+
let platformPath = path.join(rescriptDir, c.platformDir)
135119

136-
let bscBinaryPath = path.join(rescriptDirPath, c.platformDir, c.bscExeName);
120+
// Workaround for darwinarm64 which has no folder yet in ReScript <= 9.1.4
121+
if (
122+
process.platform == "darwin" &&
123+
process.arch == "arm64" &&
124+
!fs.existsSync(platformPath)
125+
) {
126+
platformPath = path.join(rescriptDir, process.platform);
127+
}
137128

138-
// Workaround for darwinarm64 which has no folder yet in ReScript <= 9.1.4
139-
if (
140-
process.platform == "darwin" &&
141-
process.arch == "arm64" &&
142-
!fs.existsSync(bscBinaryPath)
143-
) {
144-
bscBinaryPath = path.join(
145-
rescriptDirPath,
146-
process.platform,
147-
c.bscExeName
148-
);
149-
}
129+
return platformPath;
130+
}
150131

151-
return bscBinaryPath;
152-
}
153-
return null;
154-
};
132+
let findBscExeBinary = (projectRootPath: p.DocumentUri | null) =>
133+
utils.findBinary(findPlatformPath(projectRootPath), c.bscExeName)
155134

156135
interface CreateInterfaceRequestParams {
157136
uri: string;
@@ -786,12 +765,12 @@ function format(msg: p.RequestMessage): Array<p.Message> {
786765
} else {
787766
// code will always be defined here, even though technically it can be undefined
788767
let code = getOpenedFileContent(params.textDocument.uri);
768+
789769
let projectRootPath = utils.findProjectRootOfFile(filePath);
790-
let bscBinaryPath =
791-
projectRootPath === null ? null : findBscBinary(projectRootPath);
770+
let bscExeBinaryPath = findBscExeBinary(projectRootPath);
792771

793772
let formattedResult = utils.formatCode(
794-
bscBinaryPath,
773+
bscExeBinaryPath,
795774
filePath,
796775
code,
797776
extensionConfiguration.allowBuiltInFormatter

server/src/utils.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,31 @@ export let findProjectRootOfFile = (
3838
}
3939
};
4040

41+
// Check if filePartialPath exists at directory and return the joined path,
42+
// otherwise recursively check parent directories for it.
43+
export let findFilePathFromProjectRoot = (
44+
directory: p.DocumentUri | null, // This must be a directory and not a file!
45+
filePartialPath: string
46+
): null | p.DocumentUri => {
47+
if (directory == null) {
48+
return null;
49+
}
50+
51+
let filePath: p.DocumentUri = path.join(directory, filePartialPath);
52+
if (fs.existsSync(filePath)) {
53+
return filePath;
54+
}
55+
56+
let parentDir: p.DocumentUri = path.dirname(directory);
57+
if (parentDir === directory) {
58+
// reached the top
59+
return null;
60+
}
61+
62+
return findFilePathFromProjectRoot(parentDir, filePartialPath);
63+
};
64+
65+
// Check if binaryName exists inside binaryDirPath and return the joined path.
4166
export let findBinary = (
4267
binaryDirPath: p.DocumentUri | null,
4368
binaryName: string
@@ -53,18 +78,6 @@ export let findBinary = (
5378
}
5479
};
5580

56-
export let findRescriptBinary = (
57-
binaryDirPath: p.DocumentUri | null
58-
): p.DocumentUri | null => {
59-
return findBinary(binaryDirPath, c.rescriptBinName);
60-
};
61-
62-
export let findBscBinary = (
63-
binaryDirPath: p.DocumentUri | null
64-
): p.DocumentUri | null => {
65-
return findBinary(binaryDirPath, c.bscBinName);
66-
};
67-
6881
type execResult =
6982
| {
7083
kind: "success";

0 commit comments

Comments
 (0)