Skip to content

Commit 2fd7cd9

Browse files
committed
Make multi-line item spacing the experimental feature MultilineItemSpacing
Why: Spacing multi-line module items changes the output of `rescript format` for most existing projects (341 files in this repository alone), so it is opt-in, like `let?` (LetUnwrap). Without the feature the formatter prints exactly as before, and the snapshots of the previous commit return to their master state. Format modified (multi-line item spacing, opt-in): Example: module A = { let x = 1 } let y = 2 Before (rescript): always, since the previous commit module A = { let x = 1 } let y = 2 After (rescript): "experimental-features": {"MultilineItemSpacing": true} module A = { let x = 1 } let y = 2 Format unchanged (default): Example: module A = { let x = 1 } let y = 2 After (rescript): without the feature module A = { let x = 1 } let y = 2 Diagnostic modified (unknown experimental feature): Example: "experimental-features": {"FooBar": true} Before (diagnostic): Unknown experimental feature 'FooBar'. Available features: LetUnwrap After (diagnostic): Unknown experimental feature 'FooBar'. Available features: LetUnwrap, MultilineItemSpacing Review: How does `rescript format` learn about the feature? Both build systems pass the root project's experimental flags, the same ones a build passes, to `bsc` before `-format`; `-format` runs as soon as bsc reads it, so the order matters. Outside a project, format runs without them, as before. Covered by rewatch/tests/format/06-format-experimental-multiline-item-spacing.sh, which passes for both rescript.exe and rescript-rust.exe. Review: How do the syntax tests enable it? `res_parser` accepts `-enable-experimental`, and scripts/test_syntax.sh prints and round-trips each file under tests/syntax_tests/data/experimental/<Feature>/ with that feature enabled. Review: What about tools that call `bsc -format` directly instead of `rescript format`? They format without the feature unless they pass `-enable-experimental MultilineItemSpacing` before `-format`. Signed-off-by: Roland Peelen <roland@magic.dev>
1 parent e73be3d commit 2fd7cd9

129 files changed

Lines changed: 129 additions & 546 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
- Format a blank line before and after a top-level or module-level item that spans several lines.
1+
- Add the experimental feature `MultilineItemSpacing`: with `"experimental-features": {"MultilineItemSpacing": true}`, `rescript format` puts a blank line before and after a module item that spans several lines.

‎compiler/bsc/rescript_compiler_driver.ml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,8 @@ let command_line_flags () : (string * Bsc_args.spec * string) array =
492492
( "-enable-experimental",
493493
string_call Experimental_features.enable_from_string,
494494
"Enable experimental features: repeatable, e.g. -enable-experimental \
495-
LetUnwrap" );
495+
LetUnwrap. Pass it before -format to format with a feature such as \
496+
MultilineItemSpacing" );
496497
(* Not used, the build system did the expansion *)
497498
( "-bs-no-bin-annot",
498499
clear (Clflags.current ()).binary_annotations,

‎compiler/ml/experimental_features.ml‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
type feature = LetUnwrap
1+
type feature = LetUnwrap | MultilineItemSpacing
22

33
let to_string (f : feature) : string =
44
match f with
55
| LetUnwrap -> "LetUnwrap"
6+
| MultilineItemSpacing -> "MultilineItemSpacing"
67

78
let from_string (s : string) : feature option =
89
match s with
910
| "LetUnwrap" -> Some LetUnwrap
11+
| "MultilineItemSpacing" -> Some MultilineItemSpacing
1012
| _ -> None
1113

1214
module Feature_set = Set.Make (struct

‎compiler/ml/experimental_features.mli‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
type feature = LetUnwrap
1+
type feature =
2+
| LetUnwrap
3+
| MultilineItemSpacing
4+
(** The formatter separates module items that span several lines with a
5+
blank line. *)
26

37
val enable_from_string : string -> unit
48

‎compiler/syntax/cli/res_cli.ml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ end = struct
5555
( "-test-ast-conversion",
5656
Arg.Unit (fun () -> test_ast_conversion := true),
5757
"Test the ast conversion" );
58+
( "-enable-experimental",
59+
Arg.String Experimental_features.enable_from_string,
60+
"Enable an experimental feature, e.g. MultilineItemSpacing" );
5861
]
5962

6063
let parse () = Arg.parse spec (fun f -> file := f) usage

‎compiler/syntax/src/res_printer.ml‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -687,12 +687,15 @@ module State = struct
687687
let should_break_callback t = t.custom_layout > custom_layout_threshold
688688
end
689689

690+
let space_multiline () =
691+
Experimental_features.is_enabled Experimental_features.MultilineItemSpacing
692+
690693
let rec print_structure ~state (s : Parsetree.structure) t =
691694
match s with
692695
| [] -> print_comments_inside_file t
693696
| structure ->
694697
let previous_can_continue = ref false in
695-
print_list ~space_multiline:true
698+
print_list ~space_multiline:(space_multiline ())
696699
~get_loc:(fun s -> s.Parsetree.pstr_loc)
697700
~nodes:structure
698701
~print:(fun item cmt_tbl ->
@@ -1110,7 +1113,7 @@ and print_signature ~state signature cmt_tbl =
11101113
match signature with
11111114
| [] -> print_comments_inside_file cmt_tbl
11121115
| signature ->
1113-
print_list ~space_multiline:true
1116+
print_list ~space_multiline:(space_multiline ())
11141117
~get_loc:(fun s -> s.Parsetree.psig_loc)
11151118
~nodes:signature
11161119
~print:(print_signature_item ~state)

‎docs/docson/build-schema.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,10 @@
556556
"LetUnwrap": {
557557
"type": "boolean",
558558
"description": "Enable `let?` syntax."
559+
},
560+
"MultilineItemSpacing": {
561+
"type": "boolean",
562+
"description": "Format a blank line before and after a module item that spans several lines."
559563
}
560564
},
561565
"additionalProperties": false

‎rewatch-ocaml/config.ml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,11 @@ let decode_experimental_features path fields =
246246
reject_duplicates path "experimental-features" features;
247247
features
248248
|> List.concat_map (fun (name, value) ->
249-
if name <> "LetUnwrap" then
249+
if not (List.mem name ["LetUnwrap"; "MultilineItemSpacing"]) then
250250
fail path
251251
(Printf.sprintf
252252
"Unknown experimental feature '%s'. Available features: \
253-
LetUnwrap"
253+
LetUnwrap, MultilineItemSpacing"
254254
name);
255255
match value with
256256
| `Bool true -> ["-enable-experimental"; name]

‎rewatch-ocaml/format.ml‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,22 @@ let files_in_scope ~verbosity =
115115
let formatting_error target stderr =
116116
Printf.sprintf "Error formatting %s: %s" target stderr
117117

118-
let format_request path =
119-
Compiler_process.{args = ["-format"; path]; cwd = Sys.getcwd ()}
118+
(* The experimental features of the current project, such as
119+
MultilineItemSpacing, as bsc flags. They must precede -format. Outside a
120+
project, format runs without them, like Rust rewatch. *)
121+
let experimental_args () =
122+
try
123+
let current = Config.load_root (Sys.getcwd ()) in
124+
(Project_context.workspace_config_for current).experimental_args
125+
with Config.Error _ -> []
126+
127+
let format_request ~experimental_args path =
128+
Compiler_process.
129+
{args = experimental_args @ ["-format"; path]; cwd = Sys.getcwd ()}
120130

121131
let formatted ?poll ~target path =
122-
let result = Compiler_process.run ?poll (format_request path) in
132+
let request = format_request ~experimental_args:(experimental_args ()) path in
133+
let result = Compiler_process.run ?poll request in
123134
if not (Process.succeeded result) then
124135
raise (Error (formatting_error target result.stderr));
125136
result.stdout
@@ -129,6 +140,7 @@ let format_check_summary = function
129140
| count -> Printf.sprintf "The %d files listed above need formatting" count
130141

131142
let format_files ?poll ~check files =
143+
let experimental_args = experimental_args () in
132144
let incorrect = ref 0 in
133145
let works =
134146
files
@@ -137,7 +149,8 @@ let format_files ?poll ~check files =
137149
{key = Printf.sprintf "%08d" index; dependencies = []; value = path})
138150
in
139151
let next path = function
140-
| None -> Some (Compiler_process.task (format_request path))
152+
| None ->
153+
Some (Compiler_process.task (format_request ~experimental_args path))
141154
| Some result ->
142155
if not (Process.succeeded result) then
143156
raise (Error (formatting_error path result.stderr));

‎rewatch/CompilerConfigurationSpec.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ An object of feature flags to enable experimental compiler behavior. Only suppor
122122
Currently supported features:
123123

124124
- LetUnwrap: Enable `let?` syntax.
125+
- MultilineItemSpacing: `rescript format` puts a blank line before and after a module item that spans several lines.
125126

126127
### Warnings
127128

0 commit comments

Comments
 (0)