Skip to content

Commit 5279685

Browse files
committed
enable formatting res and resi without needing to be in an actual ReScript project
1 parent 34dc73e commit 5279685

File tree

5 files changed

+82
-53
lines changed

5 files changed

+82
-53
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Report "Fatal error" when it happens in the compiler log (e.g. a make function with type annotation) and don't crash the extension.
99
- Fix issue in functions the form "~foo as name" where the location would only cover "ame".
1010
- Extend the command to create an interface file, to support components and ReScript decorators used in bindings.
11+
- Enable formatting files without needing the file to be in an actual ReScript project.
1112

1213
## 1.2.1
1314

analysis/src/Cli.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ Options:
5656

5757
./rescript-editor-analysis.exe createInterface src/MyFile.res lib/bs/src/MyFile.cmi
5858

59+
format: print to stdout the formatted version of the provided file
60+
61+
./rescript-editor-analysis.exe format src/MyFile.res
62+
5963
test: run tests specified by special comments in file src/MyFile.res
6064

6165
./rescript-editor-analysis.exe test src/src/MyFile.res
@@ -86,6 +90,7 @@ let main () =
8690
| [_; "createInterface"; path; cmiFile] ->
8791
Printf.printf "\"%s\""
8892
(Json.escape (CreateInterface.command ~path ~cmiFile))
93+
| [_; "format"; path] -> Commands.format ~path
8994
| [_; "test"; path] -> Commands.test ~path
9095
| args when List.mem "-h" args || List.mem "--help" args -> prerr_endline help
9196
| _ ->

analysis/src/Commands.ml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,19 @@ let rename ~path ~line ~col ~newName =
250250
in
251251
print_endline result
252252

253+
let format ~path =
254+
if Filename.check_suffix path ".res" then
255+
let {Res_driver.parsetree = structure; comments} =
256+
Res_driver.parsingEngine.parseImplementation ~forPrinter:true
257+
~filename:path
258+
in
259+
Res_driver.printEngine.printImplementation 80 path comments structure
260+
else if Filename.check_suffix path ".resi" then
261+
let {Res_driver.parsetree = structure; comments} =
262+
Res_driver.parsingEngine.parseInterface ~forPrinter:true ~filename:path
263+
in
264+
Res_driver.printEngine.printInterface 80 path comments structure
265+
253266
let test ~path =
254267
Uri2.stripPath := true;
255268
match Files.readFile path with

server/src/server.ts

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -457,49 +457,37 @@ function format(msg: p.RequestMessage): Array<m.Message> {
457457
// See comment on findBscNativeDirOfFile for why we need
458458
// to recursively search for bsc.exe upward
459459
let bscNativePath = utils.findBscNativeOfFile(filePath);
460-
if (bscNativePath === null) {
461-
let params: p.ShowMessageParams = {
462-
type: p.MessageType.Error,
463-
message: `Cannot find a nearby bsc.exe in rescript or bs-platform. It's needed for formatting.`,
464-
};
465-
let response: m.NotificationMessage = {
460+
461+
// code will always be defined here, even though technically it can be undefined
462+
let code = getOpenedFileContent(params.textDocument.uri);
463+
let formattedResult = utils.formatUsingValidBscNativePath(
464+
code,
465+
bscNativePath,
466+
extension === c.resiExt
467+
);
468+
if (formattedResult.kind === "success") {
469+
let max = code.length;
470+
let result: p.TextEdit[] = [
471+
{
472+
range: {
473+
start: { line: 0, character: 0 },
474+
end: { line: max, character: max },
475+
},
476+
newText: formattedResult.result,
477+
},
478+
];
479+
let response: m.ResponseMessage = {
466480
jsonrpc: c.jsonrpcVersion,
467-
method: "window/showMessage",
468-
params: params,
481+
id: msg.id,
482+
result: result,
469483
};
470-
return [fakeSuccessResponse, response];
484+
return [response];
471485
} else {
472-
// code will always be defined here, even though technically it can be undefined
473-
let code = getOpenedFileContent(params.textDocument.uri);
474-
let formattedResult = utils.formatUsingValidBscNativePath(
475-
code,
476-
bscNativePath,
477-
extension === c.resiExt
478-
);
479-
if (formattedResult.kind === "success") {
480-
let max = code.length;
481-
let result: p.TextEdit[] = [
482-
{
483-
range: {
484-
start: { line: 0, character: 0 },
485-
end: { line: max, character: max },
486-
},
487-
newText: formattedResult.result,
488-
},
489-
];
490-
let response: m.ResponseMessage = {
491-
jsonrpc: c.jsonrpcVersion,
492-
id: msg.id,
493-
result: result,
494-
};
495-
return [response];
496-
} else {
497-
// let the diagnostics logic display the updated syntax errors,
498-
// from the build.
499-
// Again, not sending the actual errors. See fakeSuccessResponse
500-
// above for explanation
501-
return [fakeSuccessResponse];
502-
}
486+
// let the diagnostics logic display the updated syntax errors,
487+
// from the build.
488+
// Again, not sending the actual errors. See fakeSuccessResponse
489+
// above for explanation
490+
return [fakeSuccessResponse];
503491
}
504492
}
505493
}

server/src/utils.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ type execResult =
9595
};
9696
export let formatUsingValidBscNativePath = (
9797
code: string,
98-
bscNativePath: p.DocumentUri,
98+
bscNativePath: p.DocumentUri | null,
9999
isInterface: boolean
100100
): execResult => {
101101
let extension = isInterface ? c.resiExt : c.resExt;
@@ -104,16 +104,32 @@ export let formatUsingValidBscNativePath = (
104104
encoding: "utf-8",
105105
});
106106
try {
107-
let result = childProcess.execFileSync(bscNativePath, [
108-
"-color",
109-
"never",
110-
"-format",
111-
formatTempFileFullPath,
112-
]);
113-
return {
114-
kind: "success",
115-
result: result.toString(),
116-
};
107+
// Default to using the project formatter. If not, use the one we ship with
108+
// the analysis binary in the extension itself.
109+
if (bscNativePath != null) {
110+
let result = childProcess.execFileSync(bscNativePath, [
111+
"-color",
112+
"never",
113+
"-format",
114+
formatTempFileFullPath,
115+
]);
116+
return {
117+
kind: "success",
118+
result: result.toString(),
119+
};
120+
} else {
121+
let result = runAnalysisAfterSanityCheck(
122+
formatTempFileFullPath,
123+
["format", formatTempFileFullPath],
124+
false,
125+
false
126+
);
127+
128+
return {
129+
kind: "success",
130+
result,
131+
};
132+
}
117133
} catch (e) {
118134
return {
119135
kind: "error",
@@ -128,7 +144,8 @@ export let formatUsingValidBscNativePath = (
128144
export let runAnalysisAfterSanityCheck = (
129145
filePath: p.DocumentUri,
130146
args: Array<any>,
131-
projectRequired=false
147+
projectRequired = false,
148+
parseJson = true
132149
) => {
133150
let binaryPath;
134151
if (fs.existsSync(c.analysisDevPath)) {
@@ -148,7 +165,12 @@ export let runAnalysisAfterSanityCheck = (
148165
maxBuffer: Infinity,
149166
};
150167
let stdout = childProcess.execFileSync(binaryPath, args, options);
151-
return JSON.parse(stdout.toString());
168+
169+
if (parseJson) {
170+
return JSON.parse(stdout.toString());
171+
} else {
172+
return stdout.toString();
173+
}
152174
};
153175

154176
export let runAnalysisCommand = (

0 commit comments

Comments
 (0)