Skip to content

Commit 2c5fb50

Browse files
authored
Merge pull request #385 from rescript-lang/format-without-res-project
relax requirement of files being in a ReScript project for formatting
2 parents b022c94 + 3c6c580 commit 2c5fb50

File tree

5 files changed

+93
-53
lines changed

5 files changed

+93
-53
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
## master
2+
23
- Fix issue where using paths of the form `./something` would show multiple copies of the same file in vscode.
34
- When hovering on a field access, show the instantiated type of the field.
45
- Support autocomplete for objects from another module `M.x[...`.
@@ -8,6 +9,7 @@
89
- Report "Fatal error" when it happens in the compiler log (e.g. a make function with type annotation) and don't crash the extension.
910
- Fix issue in functions the form "~foo as name" where the location would only cover "ame".
1011
- Extend the command to create an interface file, to support components and ReScript decorators used in bindings.
12+
- Enable formatting files without needing the file to be in an actual ReScript project.
1113
- New feature: Show Outline which was previously disabled.
1214

1315
## 1.2.1

analysis/src/Cli.ml

Lines changed: 6 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,8 @@ let main () =
8690
| [_; "createInterface"; path; cmiFile] ->
8791
Printf.printf "\"%s\""
8892
(Json.escape (CreateInterface.command ~path ~cmiFile))
93+
| [_; "format"; path] ->
94+
Printf.printf "\"%s\"" (Json.escape (Commands.format ~path))
8995
| [_; "test"; path] -> Commands.test ~path
9096
| args when List.mem "-h" args || List.mem "--help" args -> prerr_endline help
9197
| _ ->

analysis/src/Commands.ml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,24 @@ let rename ~path ~line ~col ~newName =
210210
in
211211
print_endline result
212212

213+
let format ~path =
214+
if Filename.check_suffix path ".res" then
215+
let {Res_driver.parsetree = structure; comments; diagnostics} =
216+
Res_driver.parsingEngine.parseImplementation ~forPrinter:true
217+
~filename:path
218+
in
219+
if List.length diagnostics > 0 then ""
220+
else
221+
Res_printer.printImplementation !Res_cli.ResClflags.width structure
222+
comments
223+
else if Filename.check_suffix path ".resi" then
224+
let {Res_driver.parsetree = signature; comments; diagnostics} =
225+
Res_driver.parsingEngine.parseInterface ~forPrinter:true ~filename:path
226+
in
227+
if List.length diagnostics > 0 then ""
228+
else Res_printer.printInterface !Res_cli.ResClflags.width signature comments
229+
else ""
230+
213231
let test ~path =
214232
Uri2.stripPath := true;
215233
match Files.readFile path with

server/src/server.ts

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

server/src/utils.ts

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ type execResult =
9393
kind: "error";
9494
error: string;
9595
};
96-
export let formatUsingValidBscNativePath = (
96+
export let formatCode = (
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,41 @@ 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+
);
126+
127+
// The formatter returning an empty string means it couldn't format the
128+
// sources, probably because of errors. In that case, we bail from
129+
// formatting by returning the unformatted content.
130+
if (result === "") {
131+
return {
132+
kind: "success",
133+
result: code,
134+
};
135+
}
136+
137+
return {
138+
kind: "success",
139+
result,
140+
};
141+
}
117142
} catch (e) {
118143
return {
119144
kind: "error",
@@ -128,7 +153,7 @@ export let formatUsingValidBscNativePath = (
128153
export let runAnalysisAfterSanityCheck = (
129154
filePath: p.DocumentUri,
130155
args: Array<any>,
131-
projectRequired=false
156+
projectRequired = false
132157
) => {
133158
let binaryPath;
134159
if (fs.existsSync(c.analysisDevPath)) {
@@ -148,6 +173,7 @@ export let runAnalysisAfterSanityCheck = (
148173
maxBuffer: Infinity,
149174
};
150175
let stdout = childProcess.execFileSync(binaryPath, args, options);
176+
151177
return JSON.parse(stdout.toString());
152178
};
153179

0 commit comments

Comments
 (0)