From 0b03e946903237b12bdb2986860c90bba740faf5 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 5 Sep 2022 15:24:13 +0200 Subject: [PATCH 1/5] Tweak description of rescript.settings.binaryPath --- README.md | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7b6c9eaf2..ea5d56940 100644 --- a/README.md +++ b/README.md @@ -104,8 +104,8 @@ You'll find all ReScript specific settings under the scope `rescript.settings`. | Setting | Description | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| 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`. | -| 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` | +| 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`. | +| 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` | | Inlay Hints (experimental) | This allows an editor to place annotations inline with text to display type hints. Enable using `rescript.settings.inlayHints.enable: true` | | 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` | | 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`. | @@ -119,7 +119,7 @@ You'll find all ReScript specific settings under the scope `rescript.settings`. // Automatically start ReScript's code analysis. "rescript.settings.autoRunCodeAnalysis": false, -// 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. +// 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. "rescript.settings.binaryPath": null // Enable (experimental) inlay hints. diff --git a/package.json b/package.json index 02d239506..004d569ed 100644 --- a/package.json +++ b/package.json @@ -161,7 +161,7 @@ "rescript.settings.binaryPath": { "type": ["string", "null"], "default": null, - "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." + "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." } } }, From 1a08cfa72352c7fc2680830f4280b1501406d237 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 5 Sep 2022 15:24:45 +0200 Subject: [PATCH 2/5] Add rescript.settings.platformPath --- README.md | 4 ++++ package.json | 5 +++++ server/src/server.ts | 2 ++ 3 files changed, 11 insertions(+) diff --git a/README.md b/README.md index ea5d56940..77a691d14 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ You'll find all ReScript specific settings under the scope `rescript.settings`. | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 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`. | | 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` | +| 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` | | Inlay Hints (experimental) | This allows an editor to place annotations inline with text to display type hints. Enable using `rescript.settings.inlayHints.enable: true` | | 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` | | 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`. | @@ -122,6 +123,9 @@ You'll find all ReScript specific settings under the scope `rescript.settings`. // 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. "rescript.settings.binaryPath": null +// 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. +"rescript.settings.platformPath": null + // Enable (experimental) inlay hints. "rescript.settings.inlayHints.enable": true diff --git a/package.json b/package.json index 004d569ed..8fcd20303 100644 --- a/package.json +++ b/package.json @@ -162,6 +162,11 @@ "type": ["string", "null"], "default": null, "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." + }, + "rescript.settings.platformPath": { + "type": ["string", "null"], + "default": null, + "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." } } }, diff --git a/server/src/server.ts b/server/src/server.ts index 1c5e6c2e8..41a82b5c3 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -33,6 +33,7 @@ interface extensionConfiguration { }; codeLens: boolean; binaryPath: string | null; + platformPath: string | null; } // All values here are temporary, and will be overridden as the server is @@ -46,6 +47,7 @@ let extensionConfiguration: extensionConfiguration = { }, codeLens: false, binaryPath: null, + platformPath: null, }; // Below here is some state that's not important exactly how long it lives. let hasPromptedAboutBuiltInFormatter = false; From 85e39fc6dd2dcd0d4056cfc7bd7ef297d3640fb2 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 5 Sep 2022 15:31:11 +0200 Subject: [PATCH 3/5] Add utils.findFilePathFromProjectRoot() --- server/src/server.ts | 27 +++------------------------ server/src/utils.ts | 31 +++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 41a82b5c3..476c74a24 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -85,31 +85,10 @@ let codeActionsFromDiagnostics: codeActions.filesCodeActions = {}; // will be properly defined later depending on the mode (stdio/node-rpc) let send: (msg: p.Message) => void = (_) => {}; -// Check if the rescript binary is available at node_modules/.bin/rescript, -// otherwise recursively check parent directories for it. -let findBinaryPathFromProjectRoot = ( - directory: p.DocumentUri // This must be a directory and not a file! -): null | p.DocumentUri => { - let binaryDirPath = path.join(directory, c.nodeModulesBinDir); - let binaryPath = path.join(binaryDirPath, c.rescriptBinName); - - if (fs.existsSync(binaryPath)) { - return binaryPath; - } - - let parentDir = path.dirname(directory); - if (parentDir === directory) { - // reached the top - return null; - } - - return findBinaryPathFromProjectRoot(parentDir); -}; - -let findRescriptBinary = (projectRootPath: p.DocumentUri) => +let findRescriptBinary = (projectRootPath: p.DocumentUri | null) => extensionConfiguration.binaryPath == null - ? findBinaryPathFromProjectRoot(projectRootPath) - : utils.findRescriptBinary(extensionConfiguration.binaryPath); + ? utils.findFilePathFromProjectRoot(projectRootPath, path.join(c.nodeModulesBinDir, c.rescriptBinName)) + : utils.findBinary(extensionConfiguration.binaryPath, c.rescriptBinName); let findBscBinary = (projectRootPath: p.DocumentUri) => { let rescriptBinaryPath = findRescriptBinary(projectRootPath); diff --git a/server/src/utils.ts b/server/src/utils.ts index 11c41c11c..f4f9a08ed 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -38,6 +38,31 @@ export let findProjectRootOfFile = ( } }; +// Check if filePartialPath exists at directory and return the joined path, +// otherwise recursively check parent directories for it. +export let findFilePathFromProjectRoot = ( + directory: p.DocumentUri | null, // This must be a directory and not a file! + filePartialPath: string +): null | p.DocumentUri => { + if (directory == null) { + return null; + } + + let filePath: p.DocumentUri = path.join(directory, filePartialPath); + if (fs.existsSync(filePath)) { + return filePath; + } + + let parentDir: p.DocumentUri = path.dirname(directory); + if (parentDir === directory) { + // reached the top + return null; + } + + return findFilePathFromProjectRoot(parentDir, filePartialPath); +}; + +// Check if binaryName exists inside binaryDirPath and return the joined path. export let findBinary = ( binaryDirPath: p.DocumentUri | null, binaryName: string @@ -53,12 +78,6 @@ export let findBinary = ( } }; -export let findRescriptBinary = ( - binaryDirPath: p.DocumentUri | null -): p.DocumentUri | null => { - return findBinary(binaryDirPath, c.rescriptBinName); -}; - export let findBscBinary = ( binaryDirPath: p.DocumentUri | null ): p.DocumentUri | null => { From 07bc57ebddd26b9aaf43ed6bbdb96dfa3f53a922 Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 5 Sep 2022 15:31:59 +0200 Subject: [PATCH 4/5] Remove unused utils.findBscBinary() --- server/src/utils.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/server/src/utils.ts b/server/src/utils.ts index f4f9a08ed..8cb3cca7f 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -78,12 +78,6 @@ export let findBinary = ( } }; -export let findBscBinary = ( - binaryDirPath: p.DocumentUri | null -): p.DocumentUri | null => { - return findBinary(binaryDirPath, c.bscBinName); -}; - type execResult = | { kind: "success"; From cc7923e256b851dde46feb225ff190e0c224406d Mon Sep 17 00:00:00 2001 From: Bart Schuurmans Date: Mon, 5 Sep 2022 15:48:40 +0200 Subject: [PATCH 5/5] Rewrite algorithm to find bsc.exe based on platformPath Should fix formatting in monorepos. Fixes #572 --- server/src/server.ts | 52 +++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index 476c74a24..6e9c1b4ce 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -90,34 +90,32 @@ let findRescriptBinary = (projectRootPath: p.DocumentUri | null) => ? utils.findFilePathFromProjectRoot(projectRootPath, path.join(c.nodeModulesBinDir, c.rescriptBinName)) : utils.findBinary(extensionConfiguration.binaryPath, c.rescriptBinName); -let findBscBinary = (projectRootPath: p.DocumentUri) => { - let rescriptBinaryPath = findRescriptBinary(projectRootPath); - if (rescriptBinaryPath !== null) { - let rescriptDirPath = path.join( - path.dirname(rescriptBinaryPath), - "..", - "rescript" - ); +let findPlatformPath = (projectRootPath: p.DocumentUri | null) => { + if (extensionConfiguration.platformPath != null) { + return extensionConfiguration.platformPath; + } - let bscBinaryPath = path.join(rescriptDirPath, c.platformDir, c.bscExeName); + let rescriptDir = utils.findFilePathFromProjectRoot(projectRootPath, path.join("node_modules", "rescript")); + if (rescriptDir == null) { + return null; + } - // Workaround for darwinarm64 which has no folder yet in ReScript <= 9.1.4 - if ( - process.platform == "darwin" && - process.arch == "arm64" && - !fs.existsSync(bscBinaryPath) - ) { - bscBinaryPath = path.join( - rescriptDirPath, - process.platform, - c.bscExeName - ); - } + let platformPath = path.join(rescriptDir, c.platformDir) - return bscBinaryPath; + // Workaround for darwinarm64 which has no folder yet in ReScript <= 9.1.4 + if ( + process.platform == "darwin" && + process.arch == "arm64" && + !fs.existsSync(platformPath) + ) { + platformPath = path.join(rescriptDir, process.platform); } - return null; -}; + + return platformPath; +} + +let findBscExeBinary = (projectRootPath: p.DocumentUri | null) => + utils.findBinary(findPlatformPath(projectRootPath), c.bscExeName) interface CreateInterfaceRequestParams { uri: string; @@ -718,12 +716,12 @@ function format(msg: p.RequestMessage): Array { } else { // code will always be defined here, even though technically it can be undefined let code = getOpenedFileContent(params.textDocument.uri); + let projectRootPath = utils.findProjectRootOfFile(filePath); - let bscBinaryPath = - projectRootPath === null ? null : findBscBinary(projectRootPath); + let bscExeBinaryPath = findBscExeBinary(projectRootPath); let formattedResult = utils.formatCode( - bscBinaryPath, + bscExeBinaryPath, filePath, code, extensionConfiguration.allowBuiltInFormatter