From 37f1f6e8d609a3ab1be47057557c93352f0a0365 Mon Sep 17 00:00:00 2001 From: Stein Martin Hustad Date: Sun, 18 Apr 2021 10:01:04 +0200 Subject: [PATCH 1/2] Upgrade to rescript-vscode 1.0.8 --- rescript-vscode/extension.vsixmanifest | 2 +- rescript-vscode/extension/CHANGELOG.md | 9 +- .../grammars/rescript.tmLanguage.json | 11 +++ rescript-vscode/extension/package.json | 5 +- .../server/out/RescriptEditorSupport.js | 1 + .../extension/server/out/constants.js | 3 +- .../extension/server/out/server.js | 95 +++++++++++-------- rescript-vscode/extension/server/out/utils.js | 36 ++++--- 8 files changed, 103 insertions(+), 59 deletions(-) diff --git a/rescript-vscode/extension.vsixmanifest b/rescript-vscode/extension.vsixmanifest index 0a4027f..5d7379b 100644 --- a/rescript-vscode/extension.vsixmanifest +++ b/rescript-vscode/extension.vsixmanifest @@ -1,7 +1,7 @@ - + rescript-vscode The official VSCode plugin for ReScript. rescript,language-server,snippet,json,ReScript,__ext_res,__ext_resi diff --git a/rescript-vscode/extension/CHANGELOG.md b/rescript-vscode/extension/CHANGELOG.md index 4f9abf5..1c14af9 100644 --- a/rescript-vscode/extension/CHANGELOG.md +++ b/rescript-vscode/extension/CHANGELOG.md @@ -1,8 +1,15 @@ +## 1.0.8 +Fixes: +- Diagnostics display for long lines. + +Features: +- Full support for the newest `rescript` npm package! +- Highlight type parameters. + ## 1.0.7 Fixes: - Highlighting for some decorators and keywords. -- Diagnostics display for long lines. - Various hover & autocomplete opportunities. Features: diff --git a/rescript-vscode/extension/grammars/rescript.tmLanguage.json b/rescript-vscode/extension/grammars/rescript.tmLanguage.json index 59ce03f..00396b8 100644 --- a/rescript-vscode/extension/grammars/rescript.tmLanguage.json +++ b/rescript-vscode/extension/grammars/rescript.tmLanguage.json @@ -188,6 +188,14 @@ } ] }, + "typeParameter": { + "patterns": [ + { + "match": "'[A-Za-z][A-Za-z0-9_]*", + "name": "support.type" + } + ] + }, "number": { "patterns": [ { @@ -431,6 +439,9 @@ { "include": "#character" }, + { + "include": "#typeParameter" + }, { "include": "#string" }, diff --git a/rescript-vscode/extension/package.json b/rescript-vscode/extension/package.json index acd6fc2..a749949 100644 --- a/rescript-vscode/extension/package.json +++ b/rescript-vscode/extension/package.json @@ -3,7 +3,7 @@ "description": "The official VSCode plugin for ReScript.", "author": "chenglou", "license": "MIT", - "version": "1.0.7", + "version": "1.0.8", "repository": { "type": "git", "url": "https://github.com/rescript-lang/rescript-vscode" @@ -99,7 +99,8 @@ ] }, "scripts": { - "vscode:prepublish": "npm run compile", + "clean": "rm -r client/out server/out", + "vscode:prepublish": "npm run clean && npm run compile", "compile": "tsc -b", "watch": "tsc -b -w", "postinstall": "cd client && npm install && cd ../server && npm install && cd ..", diff --git a/rescript-vscode/extension/server/out/RescriptEditorSupport.js b/rescript-vscode/extension/server/out/RescriptEditorSupport.js index c262760..1b561b4 100644 --- a/rescript-vscode/extension/server/out/RescriptEditorSupport.js +++ b/rescript-vscode/extension/server/out/RescriptEditorSupport.js @@ -72,6 +72,7 @@ function runDumpCommand(msg) { } } exports.runDumpCommand = runDumpCommand; +// TODO: the result will never be null soon when the updated binary syncs function runCompletionCommand(msg, code) { let executable = findExecutable(msg.params.textDocument.uri); if (executable == null) { diff --git a/rescript-vscode/extension/server/out/constants.js b/rescript-vscode/extension/server/out/constants.js index a251ab3..3a85eca 100644 --- a/rescript-vscode/extension/server/out/constants.js +++ b/rescript-vscode/extension/server/out/constants.js @@ -19,12 +19,13 @@ var __importStar = (this && this.__importStar) || function (mod) { return result; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.startBuildAction = exports.resiExt = exports.resExt = exports.compilerLogPartialPath = exports.bsconfigPartialPath = exports.bsbLock = exports.bsbNodePartialPath = exports.bscExePartialPath = exports.jsonrpcVersion = void 0; +exports.startBuildAction = exports.resiExt = exports.resExt = exports.compilerLogPartialPath = exports.bsconfigPartialPath = exports.bsbLock = exports.bsbNodePartialPath = exports.bscExeReScriptPartialPath = exports.bscExePartialPath = exports.jsonrpcVersion = void 0; const path = __importStar(require("path")); // See https://microsoft.github.io/language-server-protocol/specification Abstract Message // version is fixed to 2.0 exports.jsonrpcVersion = "2.0"; exports.bscExePartialPath = path.join("node_modules", "bs-platform", process.platform, "bsc.exe"); +exports.bscExeReScriptPartialPath = path.join("node_modules", "rescript", process.platform, "bsc.exe"); // can't use the native bsb since we might need the watcher -w flag, which is only in the js wrapper // export let bsbPartialPath = path.join('node_modules', 'bs-platform', process.platform, 'bsb.exe'); exports.bsbNodePartialPath = path.join("node_modules", ".bin", "bsb"); diff --git a/rescript-vscode/extension/server/out/server.js b/rescript-vscode/extension/server/out/server.js index 93f44f4..49038ea 100644 --- a/rescript-vscode/extension/server/out/server.js +++ b/rescript-vscode/extension/server/out/server.js @@ -26,6 +26,7 @@ const process_1 = __importDefault(require("process")); const p = __importStar(require("vscode-languageserver-protocol")); const m = __importStar(require("vscode-jsonrpc/lib/messages")); const v = __importStar(require("vscode-languageserver")); +const rpc = __importStar(require("vscode-jsonrpc")); const path = __importStar(require("path")); const fs_1 = __importDefault(require("fs")); // TODO: check DidChangeWatchedFilesNotification. @@ -45,6 +46,8 @@ let shutdownRequestAlreadyReceived = false; let stupidFileContentCache = new Map(); let projectsFiles = new Map(); // ^ caching AND states AND distributed system. Why does LSP has to be stupid like this +// will be properly defined later depending on the mode (stdio/node-rpc) +let send = (_) => { }; let sendUpdatedDiagnostics = () => { projectsFiles.forEach(({ filesWithDiagnostics }, projectRootPath) => { let content = fs_1.default.readFileSync(path.join(projectRootPath, c.compilerLogPartialPath), { encoding: "utf-8" }); @@ -60,7 +63,7 @@ let sendUpdatedDiagnostics = () => { method: "textDocument/publishDiagnostics", params: params, }; - process_1.default.send(notification); + send(notification); filesWithDiagnostics.add(file); }); if (done) { @@ -77,7 +80,7 @@ let sendUpdatedDiagnostics = () => { method: "textDocument/publishDiagnostics", params: params, }; - process_1.default.send(notification); + send(notification); filesWithDiagnostics.delete(file); } }); @@ -97,7 +100,7 @@ let deleteProjectDiagnostics = (projectRootPath) => { method: "textDocument/publishDiagnostics", params: params, }; - process_1.default.send(notification); + send(notification); }); projectsFiles.delete(projectRootPath); } @@ -155,7 +158,7 @@ let openedFile = (fileUri, fileContent) => { method: "window/showMessageRequest", params: params, }; - process_1.default.send(request); + send(request); // the client might send us back the "start build" action, which we'll // handle in the isResponseMessage check in the message handling way // below @@ -199,7 +202,23 @@ let getOpenedFileContent = (fileUri) => { console_1.assert(content != null); return content; }; -process_1.default.on("message", (msg) => { +// Start listening now! +// We support two modes: the regular node RPC mode for VSCode, and the --stdio +// mode for other editors The latter is _technically unsupported_. It's an +// implementation detail that might change at any time +if (process_1.default.argv.includes("--stdio")) { + let writer = new rpc.StreamMessageWriter(process_1.default.stdout); + let reader = new rpc.StreamMessageReader(process_1.default.stdin); + // proper `this` scope for writer + send = (msg) => writer.write(msg); + reader.listen(onMessage); +} +else { + // proper `this` scope for process + send = (msg) => process_1.default.send(msg); + process_1.default.on("message", onMessage); +} +function onMessage(msg) { if (m.isNotificationMessage(msg)) { // notification message, aka the client ends it and doesn't want a reply if (!initialized && msg.method !== "exit") { @@ -253,7 +272,7 @@ process_1.default.on("message", (msg) => { message: "Server not initialized.", }, }; - process_1.default.send(response); + send(response); } else if (msg.method === "initialize") { // send the list of features we support @@ -278,7 +297,7 @@ process_1.default.on("message", (msg) => { result: result, }; initialized = true; - process_1.default.send(response); + send(response); } else if (msg.method === "initialized") { // sent from client after initialize. Nothing to do for now @@ -287,7 +306,7 @@ process_1.default.on("message", (msg) => { id: msg.id, result: null, }; - process_1.default.send(response); + send(response); } else if (msg.method === "shutdown") { // https://microsoft.github.io/language-server-protocol/specification#shutdown @@ -300,7 +319,7 @@ process_1.default.on("message", (msg) => { message: `Language server already received the shutdown request`, }, }; - process_1.default.send(response); + send(response); } else { shutdownRequestAlreadyReceived = true; @@ -312,7 +331,7 @@ process_1.default.on("message", (msg) => { id: msg.id, result: null, }; - process_1.default.send(response); + send(response); } } else if (msg.method === p.HoverRequest.method) { @@ -329,10 +348,10 @@ process_1.default.on("message", (msg) => { ...emptyHoverResponse, result: { contents: result.hover }, }; - process_1.default.send(hoverResponse); + send(hoverResponse); } else { - process_1.default.send(emptyHoverResponse); + send(emptyHoverResponse); } } else if (msg.method === p.DefinitionRequest.method) { @@ -352,30 +371,20 @@ process_1.default.on("message", (msg) => { range: result.definition.range, }, }; - process_1.default.send(definitionResponse); + send(definitionResponse); } else { - process_1.default.send(emptyDefinitionResponse); + send(emptyDefinitionResponse); } } else if (msg.method === p.CompletionRequest.method) { - let emptyCompletionResponse = { + let code = getOpenedFileContent(msg.params.textDocument.uri); + let completionResponse = { jsonrpc: c.jsonrpcVersion, id: msg.id, - result: null, + result: RescriptEditorSupport_1.runCompletionCommand(msg, code), }; - let code = getOpenedFileContent(msg.params.textDocument.uri); - let result = RescriptEditorSupport_1.runCompletionCommand(msg, code); - if (result === null) { - process_1.default.send(emptyCompletionResponse); - } - else { - let definitionResponse = { - ...emptyCompletionResponse, - result: result, - }; - process_1.default.send(definitionResponse); - } + send(completionResponse); } else if (msg.method === p.DocumentFormattingRequest.method) { // technically, a formatting failure should reply with the error. Sadly @@ -403,8 +412,8 @@ process_1.default.on("message", (msg) => { method: "window/showMessage", params: params, }; - process_1.default.send(fakeSuccessResponse); - process_1.default.send(response); + send(fakeSuccessResponse); + send(response); } else { // See comment on findBscExeDirOfFile for why we need @@ -413,30 +422,32 @@ process_1.default.on("message", (msg) => { if (bscExeDir === null) { let params = { type: p.MessageType.Error, - message: `Cannot find a nearby ${c.bscExePartialPath}. It's needed for formatting.`, + message: `Cannot find a nearby bsc.exe in bs-platform or rescript. It's needed for formatting.`, }; let response = { jsonrpc: c.jsonrpcVersion, method: "window/showMessage", params: params, }; - process_1.default.send(fakeSuccessResponse); - process_1.default.send(response); + send(fakeSuccessResponse); + send(response); } else { - let resolvedBscExePath = path.join(bscExeDir, c.bscExePartialPath); + let bscExePath1 = path.join(bscExeDir, c.bscExeReScriptPartialPath); + let bscExePath2 = path.join(bscExeDir, c.bscExePartialPath); + let resolvedBscExePath = fs_1.default.existsSync(bscExePath1) + ? bscExePath1 + : bscExePath2; // code will always be defined here, even though technically it can be undefined let code = getOpenedFileContent(params.textDocument.uri); let formattedResult = utils.formatUsingValidBscExePath(code, resolvedBscExePath, extension === c.resiExt); if (formattedResult.kind === "success") { + let max = formattedResult.result.length; let result = [ { range: { start: { line: 0, character: 0 }, - end: { - line: Number.MAX_VALUE, - character: Number.MAX_VALUE, - }, + end: { line: max, character: max }, }, newText: formattedResult.result, }, @@ -446,14 +457,14 @@ process_1.default.on("message", (msg) => { id: msg.id, result: result, }; - process_1.default.send(response); + send(response); } else { // let the diagnostics logic display the updated syntax errors, // from the build. // Again, not sending the actual errors. See fakeSuccessResponse // above for explanation - process_1.default.send(fakeSuccessResponse); + send(fakeSuccessResponse); } } } @@ -467,7 +478,7 @@ process_1.default.on("message", (msg) => { message: "Unrecognized editor request.", }, }; - process_1.default.send(response); + send(response); } } else if (m.isResponseMessage(msg)) { @@ -494,5 +505,5 @@ process_1.default.on("message", (msg) => { } } } -}); +} //# sourceMappingURL=server.js.map \ No newline at end of file diff --git a/rescript-vscode/extension/server/out/utils.js b/rescript-vscode/extension/server/out/utils.js index 5d2e802..6255373 100644 --- a/rescript-vscode/extension/server/out/utils.js +++ b/rescript-vscode/extension/server/out/utils.js @@ -64,8 +64,9 @@ exports.findProjectRootOfFile = (source) => { // from the dependent. exports.findBscExeDirOfFile = (source) => { let dir = path.dirname(source); - let bscPath = path.join(dir, c.bscExePartialPath); - if (fs_1.default.existsSync(bscPath)) { + let bscExePath1 = path.join(dir, c.bscExeReScriptPartialPath); + let bscExePath2 = path.join(dir, c.bscExePartialPath); + if (fs_1.default.existsSync(bscExePath1) || fs_1.default.existsSync(bscExePath2)) { return dir; } else { @@ -85,7 +86,12 @@ exports.formatUsingValidBscExePath = (code, bscExePath, isInterface) => { encoding: "utf-8", }); try { - let result = childProcess.execFileSync(bscExePath, ["-color", "never", "-format", formatTempFileFullPath]); + let result = childProcess.execFileSync(bscExePath, [ + "-color", + "never", + "-format", + formatTempFileFullPath, + ]); return { kind: "success", result: result.toString(), @@ -286,6 +292,9 @@ exports.parseCompilerLogOutput = (content) => { content: [], }); } + else if (line.startsWith("#Start(")) { + // do nothing for now + } else if (line.startsWith("#Done(")) { done = true; } @@ -300,6 +309,16 @@ exports.parseCompilerLogOutput = (content) => { // 10 ┆ } else if (line.startsWith(" ")) { + // part of the actual diagnostics message + parsedDiagnostics[parsedDiagnostics.length - 1].content.push(line.slice(2)); + } + else if (line.trim() != "") { + // We'll assume that everything else is also part of the diagnostics too. + // Most of these should have been indented 2 spaces; sadly, some of them + // aren't (e.g. outcome printer printing badly, and certain old ocaml type + // messages not printing with indent). We used to get bug reports and fix + // the messages, but that strategy turned out too slow. One day we should + // revert to not having this branch... parsedDiagnostics[parsedDiagnostics.length - 1].content.push(line); } } @@ -310,21 +329,14 @@ exports.parseCompilerLogOutput = (content) => { if (result[file] == null) { result[file] = []; } - let cleanedUpDiagnostic = diagnosticMessage - .map((line) => { - // remove the spaces in front - return line.slice(2); - }) - .join("\n") - // remove start and end whitespaces/newlines - .trim() + "\n"; result[file].push({ severity: parsedDiagnostic.severity, tags: parsedDiagnostic.tag === undefined ? [] : [parsedDiagnostic.tag], code: parsedDiagnostic.code, range, source: "ReScript", - message: cleanedUpDiagnostic, + // remove start and end whitespaces/newlines + message: diagnosticMessage.join("\n").trim() + "\n", }); }); return { done, result }; From aec13a55527a2d10beb3df3a86ad19721e407cdd Mon Sep 17 00:00:00 2001 From: Stein Martin Hustad Date: Sun, 18 Apr 2021 10:01:46 +0200 Subject: [PATCH 2/2] Support changed location for binaries in rescript 9.1 --- autoload/rescript.vim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/autoload/rescript.vim b/autoload/rescript.vim index bee512b..619296c 100644 --- a/autoload/rescript.vim +++ b/autoload/rescript.vim @@ -26,7 +26,12 @@ endfunction " bs-platform setups function! rescript#UpdateProjectEnv() " Looks for the nearest node_modules directory - let l:res_bin_dir = finddir('node_modules/bs-platform/', ".;") . s:rescript_arch + let l:res_bin_dir = finddir('node_modules/rescript/', ".;") . s:rescript_arch + + if l:res_bin_dir == s:rescript_arch + " look for bs-platform if rescript node module not found + let l:res_bin_dir = finddir('node_modules/bs-platform/', ".;") . s:rescript_arch + endif "if !exists("g:rescript_compile_exe") let g:rescript_compile_exe = getcwd() . "/" . l:res_bin_dir . "/bsc.exe"