Skip to content

Commit d96c84c

Browse files
IwanKaramazowjaredly
authored andcommitted
Add option to supply a formatter for ml files (#368)
* Add support for external .ml files formatter * Simplify fmtCmdForUri: return type result(string, string)
1 parent e4d78b2 commit d96c84c

File tree

8 files changed

+66
-8
lines changed

8 files changed

+66
-8
lines changed

editor-extensions/vscode/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@
7878
"type": "string",
7979
"description": "Provide a location for the reason-lisp lispRefmt binary"
8080
},
81+
"reason_language_server.mlfmt": {
82+
"type": "string",
83+
"description": "Provide a location for an .ml/.mli formatter"
84+
},
8185
"reason_language_server.format_width": {
8286
"type": "number",
8387
"default": 80,

src/analyze/AsYouType.re

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ let convertToRe = (~formatWidth, ~interface, text, refmt) => {
5252
}
5353
};
5454

55-
let format = (~formatWidth, ~interface, text, refmt) => {
56-
let (out, error, success) = Commands.execFull(~input=text, Printf.sprintf("%s --print re --print-width=%d --parse re%s", Commands.shellEscape(refmt), formatWidth |? 80, interface ? " -i true" : ""));
55+
let format = (text, fmtCmd) => {
56+
let (out, error, success) = Commands.execFull(~input=text, fmtCmd);
5757
if (success) {
5858
Ok(String.concat("\n", out))
5959
} else {

src/analyze/Packages.re

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ let newBsPackage = (~overrideBuildSystem=?, ~reportDiagnostics, state, rootPath)
7777
let compiledBase = BuildSystem.getCompiledBase(rootPath, buildSystem);
7878
let%try stdLibDirectories = BuildSystem.getStdlib(rootPath, buildSystem);
7979
let%try compilerPath = BuildSystem.getCompiler(rootPath, buildSystem);
80+
let mlfmtPath = state.settings.mlfmtLocation;
8081
let%try refmtPath = BuildSystem.getRefmt(rootPath, buildSystem);
8182
let%try tmpPath = BuildSystem.hiddenLocation(rootPath, buildSystem);
8283
let%try (dependencyDirectories, dependencyModules) = FindFiles.findDependencyFiles(~debug=true, ~buildSystem, rootPath, config);
@@ -222,6 +223,7 @@ let newBsPackage = (~overrideBuildSystem=?, ~reportDiagnostics, state, rootPath)
222223
stdLibDirectories
223224
,
224225
compilerPath,
226+
mlfmtPath: mlfmtPath,
225227
refmtPath: Some(refmtPath),
226228
/** TODO detect this from node_modules */
227229
lispRefmtPath: None,
@@ -335,6 +337,7 @@ let newJbuilderPackage = (~overrideBuildSystem=?, ~reportDiagnostics, state, roo
335337

336338
let%try compilerPath = BuildSystem.getCompiler(projectRoot, buildSystem);
337339
let%try compilerVersion = BuildSystem.getCompilerVersion(compilerPath);
340+
let mlfmtPath = state.settings.mlfmtLocation;
338341
let refmtPath = BuildSystem.getRefmt(projectRoot, buildSystem) |> RResult.toOptionAndLog;
339342
Ok({
340343
basePath: rootPath,
@@ -354,6 +357,7 @@ let newJbuilderPackage = (~overrideBuildSystem=?, ~reportDiagnostics, state, roo
354357
includeDirectories,
355358
compilerVersion,
356359
compilerPath,
360+
mlfmtPath,
357361
refmtPath,
358362
lispRefmtPath: None,
359363
});

src/analyze/State.re

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,41 @@ let refmtForUri = (uri, package) =>
174174
}
175175
};
176176

177+
let fmtCmdForUri = (~formatWidth, ~interface, uri, package) => {
178+
if (Filename.check_suffix(uri, ".ml") || Filename.check_suffix(uri, ".mli")) {
179+
switch (package.mlfmtPath) {
180+
| None => Error("No formatter available for .ml(i) files")
181+
| Some(fmtPath) => Ok(fmtPath);
182+
};
183+
} else if (Filename.check_suffix(uri, ".rel")
184+
|| Filename.check_suffix(uri, ".reli")) {
185+
switch (package.lispRefmtPath) {
186+
| None =>
187+
Error("No lispRefmt path found, cannot process .rel or .reli files")
188+
| Some(lispRefmt) =>
189+
let cmd = Printf.sprintf(
190+
"%s --print re --print-width=%d --parse re%s",
191+
Commands.shellEscape(lispRefmt),
192+
formatWidth |? 80,
193+
interface ? " -i true" : "",
194+
);
195+
Ok(cmd);
196+
};
197+
} else {
198+
switch (package.refmtPath) {
199+
| None => Error("No refmt found for dune project. Cannot process .re file")
200+
| Some(refmt) =>
201+
let cmd = Printf.sprintf(
202+
"%s --print re --print-width=%d --parse re%s",
203+
Commands.shellEscape(refmt),
204+
formatWidth |? 80,
205+
interface ? " -i true" : "",
206+
);
207+
Ok(cmd);
208+
};
209+
};
210+
};
211+
177212
open Infix;
178213

179214
let getInterfaceFile = (uri, state, ~package: TopTypes.package) => {

src/analyze/TopTypes.re

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type package = {
2929
buildCommand: option((string, string)),
3030
compilerPath: filePath,
3131
compilerVersion: BuildSystem.compilerVersion,
32+
mlfmtPath: option(filePath),
3233
refmtPath: option(filePath),
3334
/** TODO maybe make this general, so that I can support arbitrary syntaxes? */
3435
lispRefmtPath: option(filePath),
@@ -37,6 +38,7 @@ type package = {
3738
type settings = {
3839
formatWidth: option(int),
3940
perValueCodelens: bool,
41+
mlfmtLocation: option(string),
4042
refmtLocation: option(string),
4143
lispRefmtLocation: option(string),
4244
opensCodelens: bool,
@@ -82,6 +84,7 @@ let empty = () => {
8284
lastDefinitions: Hashtbl.create(10),
8385
settings: {
8486
formatWidth: None,
87+
mlfmtLocation: None,
8588
refmtLocation: None,
8689
lispRefmtLocation: None,
8790
crossFileAsYouType: false,

src/analyze_fixture_tests/lib/TestUtils.re

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ let getPackage = (localModules) => {
2424
rebuildTimer: 0.,
2525
includeDirectories: [],
2626
compilerPath,
27+
mlfmtPath: None,
2728
refmtPath: Some(refmtPath),
2829
lispRefmtPath: None,
2930
};
@@ -96,6 +97,7 @@ let getState = () => {
9697
lastDefinitions: Hashtbl.create(10),
9798
settings: {
9899
crossFileAsYouType: false,
100+
mlfmtLocation: None,
99101
refmtLocation: None,
100102
lispRefmtLocation: None,
101103
formatWidth: None,

src/lsp/MessageHandlers.re

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,6 @@ let handlers: list((string, (state, Json.t) => result((state, Json.t), string)))
408408
let%try uri = params |> RJson.get("textDocument") |?> RJson.get("uri") |?> RJson.string;
409409
let%try package = getPackage(uri, state);
410410
let%try (start, end_) = RJson.get("range", params) |?> Protocol.rgetRange;
411-
let%try refmtPath = State.refmtForUri(uri, package);
412-
let%try refmtPath = refmtPath |> R.orError("Cannot refmt ocaml yet");
413411

414412
let text = State.getContents(uri, state);
415413
let maybeResult = {
@@ -470,7 +468,13 @@ let handlers: list((string, (state, Json.t) => result((state, Json.t), string)))
470468
|> String.concat("\n");
471469
};
472470
};
473-
let%try_wrap text = AsYouType.format(~formatWidth=state.settings.formatWidth, ~interface=(Utils.endsWith(uri, "i")), substring, refmtPath);
471+
let%try fmtCmd = State.fmtCmdForUri(
472+
~formatWidth=state.settings.formatWidth,
473+
~interface=(Utils.endsWith(uri, "i")),
474+
uri,
475+
package
476+
);
477+
let%try_wrap text = AsYouType.format(substring, fmtCmd);
474478
Util.JsonShort.(
475479
state,
476480
l([
@@ -540,9 +544,13 @@ let handlers: list((string, (state, Json.t) => result((state, Json.t), string)))
540544
let%try uri = params |> RJson.get("textDocument") |?> RJson.get("uri") |?> RJson.string;
541545
let%try package = getPackage(uri, state);
542546
let text = State.getContents(uri, state);
543-
let%try refmtPath = State.refmtForUri(uri, package);
544-
let%try refmtPath = refmtPath |> R.orError("Cannot refmt ocaml yet");
545-
let%try_wrap newText = AsYouType.format(~formatWidth=state.settings.formatWidth, ~interface=(Utils.endsWith(uri, "i")), text, refmtPath);
547+
let%try fmtCmd = State.fmtCmdForUri(
548+
~formatWidth=state.settings.formatWidth,
549+
~interface=(Utils.endsWith(uri, "i")),
550+
uri,
551+
package
552+
);
553+
let%try_wrap newText = AsYouType.format(text, fmtCmd);
546554
open Util.JsonShort;
547555
(state, text == newText ? Json.Null : l([o([
548556
("range", Protocol.rangeOfInts(

src/lsp/NotificationHandlers.re

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ let notificationHandlers: list((string, (state, Json.t) => result(state, string)
9797
("workspace/didChangeConfiguration", (state, params) => {
9898
let nullIfEmpty = item => item == "" ? None : Some(item);
9999
let settings = params |> Json.get("settings") |?> Json.get("reason_language_server");
100+
let mlfmtLocation = (settings |?> Json.get("mlfmt") |?> Json.string) |?> nullIfEmpty;
100101
let refmtLocation = (settings |?> Json.get("refmt") |?> Json.string) |?> nullIfEmpty;
101102
let lispRefmtLocation = (settings |?> Json.get("lispRefmt") |?> Json.string |?> nullIfEmpty);
102103
let perValueCodelens = (settings |?> Json.get("per_value_codelens") |?> Json.bool) |? false;
@@ -120,6 +121,7 @@ let notificationHandlers: list((string, (state, Json.t) => result(state, string)
120121
settings: {
121122
...state.settings,
122123
perValueCodelens,
124+
mlfmtLocation,
123125
refmtLocation,
124126
lispRefmtLocation,
125127
opensCodelens,

0 commit comments

Comments
 (0)