From 614f446e912822aa887edb5735936cd4e7971c3e Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 25 Sep 2025 09:41:21 +0200 Subject: [PATCH 1/2] Add command to dump LSP server state --- client/src/commands.ts | 1 + client/src/commands/dump_server_state.ts | 38 ++++++++++++++++++++ client/src/extension.ts | 4 +++ package.json | 4 +++ server/src/server.ts | 44 ++++++++++++++++++++++++ 5 files changed, 91 insertions(+) create mode 100644 client/src/commands/dump_server_state.ts diff --git a/client/src/commands.ts b/client/src/commands.ts index c75a85564..eff3280e0 100644 --- a/client/src/commands.ts +++ b/client/src/commands.ts @@ -9,6 +9,7 @@ export { createInterface } from "./commands/create_interface"; export { openCompiled } from "./commands/open_compiled"; export { switchImplIntf } from "./commands/switch_impl_intf"; export { dumpDebug, dumpDebugRetrigger } from "./commands/dump_debug"; +export { dumpServerState } from "./commands/dump_server_state"; export const codeAnalysisWithReanalyze = ( targetDir: string | null, diff --git a/client/src/commands/dump_server_state.ts b/client/src/commands/dump_server_state.ts new file mode 100644 index 000000000..5b61008c8 --- /dev/null +++ b/client/src/commands/dump_server_state.ts @@ -0,0 +1,38 @@ +import { + ExtensionContext, + StatusBarItem, + Uri, + ViewColumn, + window, +} from "vscode"; +import { LanguageClient } from "vscode-languageclient/node"; +import * as fs from "fs"; +import { createFileInTempDir } from "../utils"; + +export async function dumpServerState( + client: LanguageClient, + _context?: ExtensionContext, + _statusBarItem?: StatusBarItem, +) { + try { + const result = await client.sendRequest("rescript/dumpServerState"); + const outputFile = createFileInTempDir("server_state", ".json"); + + // Pretty-print JSON with stable ordering where possible + const replacer = (_key: string, value: any) => { + if (value instanceof Map) return Object.fromEntries(value); + if (value instanceof Set) return Array.from(value); + return value; + }; + + const json = JSON.stringify(result, replacer, 2); + fs.writeFileSync(outputFile, json, { encoding: "utf-8" }); + + await window.showTextDocument(Uri.parse(outputFile), { + viewColumn: ViewColumn.Beside, + preview: false, + }); + } catch (e) { + window.showErrorMessage(`Failed to dump server state: ${String(e)}`); + } +} diff --git a/client/src/extension.ts b/client/src/extension.ts index 2c1c88b28..9f17147a8 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -371,6 +371,10 @@ export function activate(context: ExtensionContext) { customCommands.dumpDebug(context, debugDumpStatusBarItem); }); + commands.registerCommand("rescript-vscode.dump-server-state", () => { + customCommands.dumpServerState(client, context, debugDumpStatusBarItem); + }); + commands.registerCommand("rescript-vscode.showProblems", async () => { try { await commands.executeCommand("workbench.actions.view.problems"); diff --git a/package.json b/package.json index 530cc76ea..7b7408432 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,10 @@ { "command": "rescript-vscode.debug-dump-start", "title": "DEBUG ReScript: Dump analysis info" + }, + { + "command": "rescript-vscode.dump-server-state", + "title": "DEBUG ReScript: Dump LSP Server State" } ], "keybindings": [ diff --git a/server/src/server.ts b/server/src/server.ts index 31ca545f7..24f0d3ee1 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1485,6 +1485,50 @@ async function onMessage(msg: p.Message) { if (extName === c.resExt) { send(await signatureHelp(msg)); } + } else if (msg.method === "rescript/dumpServerState") { + // Custom debug endpoint: dump current server state (config + projectsFiles) + try { + const projects = Array.from(projectsFiles.entries()).map( + ([projectRootPath, pf]) => ({ + projectRootPath, + openFiles: Array.from(pf.openFiles), + filesWithDiagnostics: Array.from(pf.filesWithDiagnostics), + filesDiagnostics: pf.filesDiagnostics, + rescriptVersion: pf.rescriptVersion, + bscBinaryLocation: pf.bscBinaryLocation, + editorAnalysisLocation: pf.editorAnalysisLocation, + namespaceName: pf.namespaceName, + hasPromptedToStartBuild: pf.hasPromptedToStartBuild, + bsbWatcherByEditor: + pf.bsbWatcherByEditor != null + ? { pid: pf.bsbWatcherByEditor.pid ?? null } + : null, + }), + ); + + const result = { + config: config.extensionConfiguration, + projects, + workspaceFolders: Array.from(workspaceFolders), + }; + + let response: p.ResponseMessage = { + jsonrpc: c.jsonrpcVersion, + id: msg.id, + result, + }; + send(response); + } catch (e) { + let response: p.ResponseMessage = { + jsonrpc: c.jsonrpcVersion, + id: msg.id, + error: { + code: p.ErrorCodes.InternalError, + message: `Failed to dump server state: ${String(e)}`, + }, + }; + send(response); + } } else { let response: p.ResponseMessage = { jsonrpc: c.jsonrpcVersion, From 380793089c7cd32e639eaf3fed8c13b2acc32b5c Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 25 Sep 2025 09:55:07 +0200 Subject: [PATCH 2/2] Changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e3b1f5c6..27f41a6ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,8 @@ - Find `@rescript/runtime` for Rewatch compiler-args call. https://github.com/rescript-lang/rescript-vscode/pull/1125 - Use `prepareRename` command (when a new enough ReScript version is used) to speed up the `rename` command. https://github.com/rescript-lang/rescript-vscode/pull/1124 -- Use `compiler-info.json` to find the `@rescript/runtime` and `bsc.exe` if available. +- Use `compiler-info.json` to find the `@rescript/runtime` and `bsc.exe` if available. https://github.com/rescript-lang/rescript-vscode/pull/1129 +- Add `Dump LSP Server State` command to client. https://github.com/rescript-lang/rescript-vscode/pull/1130 ## 1.64.0