Skip to content

Commit 185826e

Browse files
fhammerschmidtcristianoc
authored andcommitted
Command to open compiled file
1 parent fdd1fc5 commit 185826e

File tree

8 files changed

+233
-40
lines changed

8 files changed

+233
-40
lines changed

client/src/commands.ts

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,12 @@
1-
import * as fs from "fs";
2-
import { window, DiagnosticCollection } from "vscode";
3-
import { LanguageClient, RequestType } from "vscode-languageclient/node";
1+
import { DiagnosticCollection } from "vscode";
2+
43
import {
54
DiagnosticsResultCodeActionsMap,
65
runDeadCodeAnalysisWithReanalyze,
76
} from "./commands/dead_code_analysis";
87

9-
interface CreateInterfaceRequestParams {
10-
uri: string;
11-
}
12-
13-
let createInterfaceRequest = new RequestType<
14-
CreateInterfaceRequestParams,
15-
string,
16-
void
17-
>("rescript-vscode.create_interface");
18-
19-
export const createInterface = (client: LanguageClient) => {
20-
if (!client) {
21-
return window.showInformationMessage("Language server not running");
22-
}
23-
24-
const editor = window.activeTextEditor;
25-
26-
if (!editor) {
27-
return window.showInformationMessage("No active editor");
28-
}
29-
30-
if (fs.existsSync(editor.document.uri.fsPath + "i")) {
31-
return window.showInformationMessage("Interface file already exists");
32-
}
33-
34-
client.sendRequest(createInterfaceRequest, {
35-
uri: editor.document.uri.toString(),
36-
});
37-
};
8+
export { createInterface } from "./commands/create_interface";
9+
export { openCompiled } from "./commands/open_compiled";
3810

3911
export const deadCodeAnalysisWithReanalyze = (
4012
targetDir: string | null,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as fs from "fs";
2+
import { LanguageClient, RequestType } from "vscode-languageclient/node";
3+
import { window } from "vscode";
4+
5+
interface CreateInterfaceRequestParams {
6+
uri: string;
7+
}
8+
9+
let createInterfaceRequest = new RequestType<
10+
CreateInterfaceRequestParams,
11+
string,
12+
void
13+
>("rescript-vscode.create_interface");
14+
15+
export const createInterface = (client: LanguageClient) => {
16+
if (!client) {
17+
return window.showInformationMessage("Language server not running");
18+
}
19+
20+
const editor = window.activeTextEditor;
21+
22+
if (!editor) {
23+
return window.showInformationMessage("No active editor");
24+
}
25+
26+
if (fs.existsSync(editor.document.uri.fsPath + "i")) {
27+
return window.showInformationMessage("Interface file already exists");
28+
}
29+
30+
client.sendRequest(createInterfaceRequest, {
31+
uri: editor.document.uri.toString(),
32+
});
33+
};

client/src/commands/open_compiled.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import * as fs from "fs";
2+
import { window, Uri, ViewColumn } from "vscode";
3+
import { LanguageClient, RequestType } from "vscode-languageclient/node";
4+
5+
interface OpenCompiledFileRequestParams {
6+
uri: string;
7+
}
8+
9+
interface OpenCompiledFileResponseParams {
10+
uri: string;
11+
}
12+
13+
let openCompiledFileRequest = new RequestType<
14+
OpenCompiledFileRequestParams,
15+
OpenCompiledFileResponseParams,
16+
void
17+
>("rescript-vscode.open_compiled");
18+
19+
export const openCompiled = (client: LanguageClient) => {
20+
if (!client) {
21+
return window.showInformationMessage("Language server not running");
22+
}
23+
24+
const editor = window.activeTextEditor;
25+
26+
if (!editor) {
27+
return window.showInformationMessage("No active editor");
28+
}
29+
30+
if (!fs.existsSync(editor.document.uri.fsPath)) {
31+
return window.showInformationMessage("Compiled file does not exist");
32+
}
33+
34+
client
35+
.sendRequest(openCompiledFileRequest, {
36+
uri: editor.document.uri.toString(),
37+
})
38+
.then((response) => {
39+
const document = Uri.file(response.uri);
40+
41+
return window.showTextDocument(document, {
42+
viewColumn: ViewColumn.Beside,
43+
});
44+
});
45+
};

client/src/extension.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ export function activate(context: ExtensionContext) {
146146
customCommands.createInterface(client);
147147
});
148148

149+
commands.registerCommand("rescript-vscode.open_compiled", () => {
150+
customCommands.openCompiled(client);
151+
});
152+
149153
// Starts the dead code analysis mode.
150154
commands.registerCommand("rescript-vscode.start_dead_code_analysis", () => {
151155
// Save the directory this first ran from, and re-use that when continuously

package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,26 @@
3939
"command": "rescript-vscode.create_interface",
4040
"title": "ReScript: Create an interface file for this implementation file."
4141
},
42+
{
43+
"command": "rescript-vscode.open_compiled",
44+
"category": "ReScript",
45+
"title": "Open the compiled JS file for this implementation file.",
46+
"icon": "$(output)"
47+
},
4248
{
4349
"command": "rescript-vscode.start_dead_code_analysis",
4450
"title": "ReScript: Start dead code analysis."
4551
}
4652
],
53+
"menus": {
54+
"editor/title": [
55+
{
56+
"command": "rescript-vscode.open_compiled",
57+
"when": "editorLangId == rescript",
58+
"group": "navigation"
59+
}
60+
]
61+
},
4762
"snippets": [
4863
{
4964
"language": "rescript",

server/src/constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,7 @@ export let resExt = ".res";
4545
export let resiExt = ".resi";
4646
export let cmiExt = ".cmi";
4747
export let startBuildAction = "Start Build";
48+
49+
// bsconfig defaults according configuration schema (https://rescript-lang.org/docs/manual/latest/build-configuration-schema)
50+
export let bsconfigModuleDefault = "commonjs";
51+
export let bsconfigSuffixDefault = ".js";

server/src/server.ts

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ let createInterfaceRequest =
5050
string,
5151
void>("rescript-vscode.create_interface");
5252

53+
interface OpenCompiledFileParams {
54+
uri: string;
55+
}
56+
57+
let openCompiledFileRequest = new v.RequestType<
58+
OpenCompiledFileParams,
59+
OpenCompiledFileParams,
60+
void
61+
>("rescript-vscode.open_compiled");
62+
5363
let sendUpdatedDiagnostics = () => {
5464
projectsFiles.forEach(({ filesWithDiagnostics }, projectRootPath) => {
5565
let content = fs.readFileSync(
@@ -120,7 +130,7 @@ let sendCompilationFinishedMessage = () => {
120130
jsonrpc: c.jsonrpcVersion,
121131
method: "rescript/compilationFinished",
122132
};
123-
133+
124134
send(notification);
125135
};
126136

@@ -548,7 +558,7 @@ function createInterface(msg: p.RequestMessage): m.Message {
548558
return response;
549559
}
550560

551-
let namespace = namespaceResult.result
561+
let namespace = namespaceResult.result;
552562
let suffixToAppend = namespace.length > 0 ? "-" + namespace : "";
553563

554564
let cmiPartialPath = path.join(
@@ -602,6 +612,56 @@ function createInterface(msg: p.RequestMessage): m.Message {
602612
}
603613
}
604614

615+
function openCompiledFile(msg: p.RequestMessage): m.Message {
616+
let params = msg.params as OpenCompiledFileParams;
617+
let filePath = fileURLToPath(params.uri);
618+
let projDir = utils.findProjectRootOfFile(filePath);
619+
620+
if (projDir === null) {
621+
let params: p.ShowMessageParams = {
622+
type: p.MessageType.Error,
623+
message: `Cannot locate project directory.`,
624+
};
625+
626+
let response: m.NotificationMessage = {
627+
jsonrpc: c.jsonrpcVersion,
628+
method: "window/showMessage",
629+
params: params,
630+
};
631+
632+
return response;
633+
}
634+
635+
let compiledFilePath = utils.getCompiledFilePath(filePath, projDir);
636+
637+
if (compiledFilePath.kind === "error" || !fs.existsSync(compiledFilePath.result)) {
638+
let params: p.ShowMessageParams = {
639+
type: p.MessageType.Error,
640+
message: `No compiled file found. Please compile your project first.`,
641+
};
642+
643+
let response: m.NotificationMessage = {
644+
jsonrpc: c.jsonrpcVersion,
645+
method: "window/showMessage",
646+
params,
647+
};
648+
649+
return response;
650+
}
651+
652+
let result: OpenCompiledFileParams = {
653+
uri: compiledFilePath.result,
654+
};
655+
656+
let response: m.ResponseMessage = {
657+
jsonrpc: c.jsonrpcVersion,
658+
id: msg.id,
659+
result,
660+
};
661+
662+
return response;
663+
}
664+
605665
function onMessage(msg: m.Message) {
606666
if (m.isNotificationMessage(msg)) {
607667
// notification message, aka the client ends it and doesn't want a reply
@@ -734,6 +794,8 @@ function onMessage(msg: m.Message) {
734794
responses.forEach((response) => send(response));
735795
} else if (msg.method === createInterfaceRequest.method) {
736796
send(createInterface(msg));
797+
} else if (msg.method === openCompiledFileRequest.method) {
798+
send(openCompiledFile(msg));
737799
} else {
738800
let response: m.ResponseMessage = {
739801
jsonrpc: c.jsonrpcVersion,

server/src/utils.ts

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,20 @@ export const toCamelCase = (text: string): string => {
186186
.replace(/(\s|-)+/g, "");
187187
};
188188

189+
const readBsConfig = (projDir: p.DocumentUri) => {
190+
let bsconfigFile = fs.readFileSync(
191+
path.join(projDir, c.bsconfigPartialPath),
192+
{ encoding: "utf-8" }
193+
);
194+
195+
return JSON.parse(bsconfigFile);
196+
};
197+
189198
export const getNamespaceNameFromBsConfig = (
190199
projDir: p.DocumentUri
191200
): execResult => {
192201
try {
193-
let bsconfigFile = fs.readFileSync(
194-
path.join(projDir, c.bsconfigPartialPath),
195-
{ encoding: "utf-8" }
196-
);
197-
198-
let bsconfig = JSON.parse(bsconfigFile);
202+
let bsconfig = readBsConfig(projDir);
199203
let result = "";
200204

201205
if (bsconfig.namespace === true) {
@@ -243,6 +247,60 @@ export let createInterfaceFileUsingValidBscExePath = (
243247
}
244248
};
245249

250+
export let getCompiledFilePath = (
251+
filePath: string,
252+
projDir: string
253+
): execResult => {
254+
try {
255+
let bsConfig = readBsConfig(projDir);
256+
257+
let pkgSpecs = bsConfig["package-specs"];
258+
let pathFragment = "";
259+
let moduleFormatObj: any = {};
260+
261+
let module = c.bsconfigModuleDefault;
262+
let suffix = c.bsconfigSuffixDefault;
263+
264+
if (pkgSpecs && pkgSpecs.module) {
265+
moduleFormatObj = pkgSpecs;
266+
} else if (pkgSpecs && pkgSpecs[0]) {
267+
if (typeof pkgSpecs[0] === "string") {
268+
module = pkgSpecs[0];
269+
} else {
270+
moduleFormatObj = pkgSpecs[0];
271+
}
272+
}
273+
274+
if (moduleFormatObj["module"]) {
275+
module = moduleFormatObj["module"];
276+
}
277+
278+
if (!moduleFormatObj["in-source"]) {
279+
pathFragment = "lib/" + module.replace("-", "_");
280+
}
281+
282+
if (moduleFormatObj.suffix) {
283+
suffix = moduleFormatObj.suffix;
284+
} else if (bsConfig.suffix) {
285+
suffix = bsConfig.suffix;
286+
}
287+
288+
let partialFilePath = filePath.split(projDir)[1];
289+
let compiledPartialPath = replaceFileExtension(partialFilePath, suffix);
290+
let result = path.join(projDir, pathFragment, compiledPartialPath);
291+
292+
return {
293+
kind: "success",
294+
result,
295+
};
296+
} catch (e) {
297+
return {
298+
kind: "error",
299+
error: e instanceof Error ? e.message : String(e),
300+
};
301+
}
302+
};
303+
246304
export let runBuildWatcherUsingValidBuildPath = (
247305
buildPath: p.DocumentUri,
248306
isRescript: boolean,

0 commit comments

Comments
 (0)