Skip to content

Commit 663190e

Browse files
committed
Refactor dump command
1 parent 441959d commit 663190e

File tree

4 files changed

+108
-78
lines changed

4 files changed

+108
-78
lines changed

client/src/commands.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export { createInterface } from "./commands/create_interface";
99
export { openCompiled } from "./commands/open_compiled";
1010
export { switchImplIntf } from "./commands/switch_impl_intf";
1111
export { dumpDebug, dumpDebugRetrigger } from "./commands/dump_debug";
12-
export { dumpServerState } from "./commands/dump_server_state";
1312
export { pasteAsRescriptJson } from "./commands/paste_as_rescript_json";
1413
export { pasteAsRescriptJsx } from "./commands/paste_as_rescript_jsx";
1514

client/src/commands/dump_server_state.ts

Lines changed: 0 additions & 38 deletions
This file was deleted.

client/src/extension.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,15 @@ export function activate(context: ExtensionContext) {
373373
customCommands.dumpDebug(context, debugDumpStatusBarItem);
374374
});
375375

376-
commands.registerCommand("rescript-vscode.dump-server-state", () => {
377-
customCommands.dumpServerState(client, context, debugDumpStatusBarItem);
376+
commands.registerCommand("rescript-vscode.dump-server-state", async () => {
377+
// Server handles everything: writing to disk and opening the file via window/showDocument
378+
try {
379+
await client.sendRequest("workspace/executeCommand", {
380+
command: "rescript/dumpServerState",
381+
});
382+
} catch (e) {
383+
console.error("Failed to dump server state:", e);
384+
}
378385
});
379386

380387
commands.registerCommand("rescript-vscode.showProblems", async () => {

server/src/server.ts

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as rpc from "vscode-jsonrpc/node";
55
import * as path from "path";
66
import semver from "semver";
77
import fs from "fs";
8+
import fsAsync from "fs/promises";
89
import {
910
DidChangeWatchedFilesNotification,
1011
DidOpenTextDocumentNotification,
@@ -1260,6 +1261,93 @@ function openCompiledFile(msg: p.RequestMessage): p.Message {
12601261
return response;
12611262
}
12621263

1264+
async function dumpServerState(
1265+
msg: p.RequestMessage,
1266+
): Promise<p.ResponseMessage> {
1267+
// Custom debug endpoint: dump current server state (config + projectsFiles)
1268+
try {
1269+
// Read the server version from package.json
1270+
let serverVersion: string | undefined;
1271+
try {
1272+
const packageJsonPath = path.join(__dirname, "..", "package.json");
1273+
const packageJsonContent = await fsAsync.readFile(packageJsonPath, {
1274+
encoding: "utf-8",
1275+
});
1276+
const packageJson = JSON.parse(packageJsonContent);
1277+
serverVersion = packageJson.version;
1278+
} catch (e) {
1279+
// If we can't read the version, that's okay - we'll just omit it
1280+
serverVersion = undefined;
1281+
}
1282+
1283+
const projects = Array.from(projectsFiles.entries()).map(
1284+
([projectRootPath, pf]) => ({
1285+
projectRootPath,
1286+
openFiles: Array.from(pf.openFiles),
1287+
filesWithDiagnostics: Array.from(pf.filesWithDiagnostics),
1288+
filesDiagnostics: pf.filesDiagnostics,
1289+
rescriptVersion: pf.rescriptVersion,
1290+
bscBinaryLocation: pf.bscBinaryLocation,
1291+
editorAnalysisLocation: pf.editorAnalysisLocation,
1292+
namespaceName: pf.namespaceName,
1293+
hasPromptedToStartBuild: pf.hasPromptedToStartBuild,
1294+
bsbWatcherByEditor:
1295+
pf.bsbWatcherByEditor != null
1296+
? { pid: pf.bsbWatcherByEditor.pid ?? null }
1297+
: null,
1298+
}),
1299+
);
1300+
1301+
const state = {
1302+
lspServerVersion: serverVersion,
1303+
config: config.extensionConfiguration,
1304+
projects,
1305+
workspaceFolders: Array.from(workspaceFolders),
1306+
runtimePathCache: utils.getRuntimePathCacheSnapshot(),
1307+
};
1308+
1309+
// Format JSON with pretty-printing (2-space indent) on the server side
1310+
// This ensures consistent formatting and handles any Maps/Sets that might
1311+
// have been converted to plain objects/arrays above
1312+
const formattedJson = JSON.stringify(state, null, 2);
1313+
1314+
// Write the file to disk on the server side
1315+
const outputFile = utils.createFileInTempDir("_server_state.json");
1316+
fs.writeFileSync(outputFile, formattedJson, { encoding: "utf-8" });
1317+
1318+
// Request the client to open the document
1319+
const fileUri = utils.pathToURI(outputFile);
1320+
const showDocumentRequest: p.RequestMessage = {
1321+
jsonrpc: c.jsonrpcVersion,
1322+
id: serverSentRequestIdCounter++,
1323+
method: "window/showDocument",
1324+
params: {
1325+
uri: fileUri,
1326+
external: false,
1327+
takeFocus: true,
1328+
},
1329+
};
1330+
send(showDocumentRequest);
1331+
1332+
let response: p.ResponseMessage = {
1333+
jsonrpc: c.jsonrpcVersion,
1334+
id: msg.id,
1335+
result: { uri: fileUri },
1336+
};
1337+
return response;
1338+
} catch (e) {
1339+
let response: p.ResponseMessage = {
1340+
jsonrpc: c.jsonrpcVersion,
1341+
id: msg.id,
1342+
error: {
1343+
code: p.ErrorCodes.InternalError,
1344+
message: `Failed to dump server state: ${String(e)}`,
1345+
},
1346+
};
1347+
return response;
1348+
}
1349+
}
1350+
12631351
async function onMessage(msg: p.Message) {
12641352
if (p.Message.isNotification(msg)) {
12651353
// notification message, aka the client ends it and doesn't want a reply
@@ -1458,6 +1546,9 @@ async function onMessage(msg: p.Message) {
14581546
retriggerCharacters: ["=", ","],
14591547
}
14601548
: undefined,
1549+
executeCommandProvider: {
1550+
commands: ["rescript/dumpServerState"],
1551+
},
14611552
},
14621553
};
14631554
let response: p.ResponseMessage = {
@@ -1555,47 +1646,18 @@ async function onMessage(msg: p.Message) {
15551646
if (extName === c.resExt) {
15561647
send(await signatureHelp(msg));
15571648
}
1558-
} else if (msg.method === "rescript/dumpServerState") {
1559-
// Custom debug endpoint: dump current server state (config + projectsFiles)
1560-
try {
1561-
const projects = Array.from(projectsFiles.entries()).map(
1562-
([projectRootPath, pf]) => ({
1563-
projectRootPath,
1564-
openFiles: Array.from(pf.openFiles),
1565-
filesWithDiagnostics: Array.from(pf.filesWithDiagnostics),
1566-
filesDiagnostics: pf.filesDiagnostics,
1567-
rescriptVersion: pf.rescriptVersion,
1568-
bscBinaryLocation: pf.bscBinaryLocation,
1569-
editorAnalysisLocation: pf.editorAnalysisLocation,
1570-
namespaceName: pf.namespaceName,
1571-
hasPromptedToStartBuild: pf.hasPromptedToStartBuild,
1572-
bsbWatcherByEditor:
1573-
pf.bsbWatcherByEditor != null
1574-
? { pid: pf.bsbWatcherByEditor.pid ?? null }
1575-
: null,
1576-
}),
1577-
);
1578-
1579-
const result = {
1580-
config: config.extensionConfiguration,
1581-
projects,
1582-
workspaceFolders: Array.from(workspaceFolders),
1583-
runtimePathCache: utils.getRuntimePathCacheSnapshot(),
1584-
};
1585-
1586-
let response: p.ResponseMessage = {
1587-
jsonrpc: c.jsonrpcVersion,
1588-
id: msg.id,
1589-
result,
1590-
};
1591-
send(response);
1592-
} catch (e) {
1649+
} else if (msg.method === p.ExecuteCommandRequest.method) {
1650+
// Standard LSP executeCommand - supports editor-agnostic command execution
1651+
const params = msg.params as p.ExecuteCommandParams;
1652+
if (params.command === "rescript/dumpServerState") {
1653+
send(await dumpServerState(msg));
1654+
} else {
15931655
let response: p.ResponseMessage = {
15941656
jsonrpc: c.jsonrpcVersion,
15951657
id: msg.id,
15961658
error: {
1597-
code: p.ErrorCodes.InternalError,
1598-
message: `Failed to dump server state: ${String(e)}`,
1659+
code: p.ErrorCodes.InvalidRequest,
1660+
message: `Unknown command: ${params.command}`,
15991661
},
16001662
};
16011663
send(response);

0 commit comments

Comments
 (0)