Skip to content

Commit e20f518

Browse files
map begin fun on one line, second attempt (#2693)
* apply begin fun on one line * fmt * changelog * showcase infix apply begin function issue * fix infix apply begin function issue
1 parent 73fe1ca commit e20f518

17 files changed

+534
-126
lines changed

CHANGES.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,11 @@ profile. This started with version 0.26.0.
6969

7070
### Changed
7171

72-
- \* `|> begin`, `~arg:begin`, `begin if`, `lazy begin`, `begin match` and
73-
`begin fun` can now be printed on the same line, with one less indentation
74-
level for the body of the inner expression. (#2664, #2666, #2671, #2672,
75-
#2681, #2685, @EmileTrotignon) For example :
72+
- `|> begin`, `~arg:begin`, `begin if`, `lazy begin`, `begin match`,
73+
`begin fun` and `map li begin fun` can now be printed on the same line, with
74+
one less indentation level for the body of the inner expression.
75+
(#2664, #2666, #2671, #2672, #2681, #2685, #2693, @EmileTrotignon)
76+
For example :
7677
```ocaml
7778
(* before *)
7879
begin

bin/ocamlformat/dune

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
(:standard -open Ocamlformat_stdlib))
1919
(instrumentation
2020
(backend bisect_ppx))
21-
(libraries ocamlformat-lib bin_conf))
21+
(libraries ocamlformat-lib bin_conf)
22+
(modes byte native))
2223

2324
(rule
2425
(with-stdout-to

lib/Fmt_ast.ml

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,8 +1665,9 @@ and fmt_function ?force_closing_paren ~ctx ~ctx0 ?pro ~wrap_intro
16651665
$ hvbox_if has_cmts_outer 0
16661666
( cmts_outer
16671667
$ Params.Exp.box_fun_decl ~ctx0 c.conf
1668-
(pro_inner $ cmts_inner $ opn_attr_paren $ opn_paren $ head)
1669-
) )
1668+
( pro_inner $ cmts_inner
1669+
$ Params.Exp.box_fun_decl_after_pro ~ctx0
1670+
(opn_attr_paren $ opn_paren $ head) ) ) )
16701671
in
16711672
body ~pro $ cls_paren
16721673
$ fmt_attributes c ~pre:Space attrs
@@ -1874,7 +1875,8 @@ and fmt_infix_op_args c ~parens xexp op_args =
18741875
in
18751876
if Params.Exp.Infix_op_arg.dock c.conf xarg then
18761877
(* Indentation of docked fun or function start before the operator. *)
1877-
hovbox 2 (fmt_expression c ~parens ~box:false ~pro xarg)
1878+
hovbox ~name:"Infix_op_arg docked" 2
1879+
(fmt_expression c ~parens ~box:false ~pro xarg)
18781880
else
18791881
match xarg.ast.pexp_desc with
18801882
| Pexp_function _ | Pexp_beginend _ ->
@@ -2289,6 +2291,26 @@ and fmt_expression c ?(box = true) ?(pro = noop) ?eol ?parens
22892291
( expr_epi
22902292
$ Params.parens_if outer_parens c.conf
22912293
(args $ fmt_atrs $ fmt_if inner_parens (str ")")) )
2294+
| Pexp_beginend ({pexp_desc= Pexp_function _; _}, _) ->
2295+
let fmt_atrs =
2296+
fmt_attributes c ~pre:(Break (1, -2)) pexp_attributes
2297+
in
2298+
let force =
2299+
if Location.is_single_line pexp_loc c.conf.fmt_opts.margin.v then
2300+
Fit
2301+
else Break
2302+
in
2303+
let pro =
2304+
intro_epi
2305+
$ fmt_if parens (str "(")
2306+
$ ( fmt_args_grouped ~epi:fmt_atrs e0 args_before
2307+
$ fmt_if parens (closing_paren c ~force ~offset:(-3)) )
2308+
in
2309+
let label_sep = Params.Exp.fun_label_sep c.conf in
2310+
let pro = pro $ break 1 0 $ fmt_label lbl label_sep in
2311+
expr_epi
2312+
$ hovbox 4
2313+
(fmt_expression c ~pro ~box:false (sub_exp ~ctx last_arg))
22922314
| _ ->
22932315
let fmt_atrs =
22942316
fmt_attributes c ~pre:(Break (1, -2)) pexp_attributes
@@ -2927,8 +2949,8 @@ and fmt_expression c ?(box = true) ?(pro = noop) ?eol ?parens
29272949
pro $ fmt_indexop_access c ctx ~fmt_atrs ~has_attr ~parens x
29282950
| Pexp_hole -> pro $ hvbox 0 (fmt_hole () $ fmt_atrs)
29292951
| Pexp_beginend (e, infix_ext_attrs) ->
2930-
fmt_beginend c ~loc:pexp_loc ~box ~pro ~ctx ~fmt_atrs ~infix_ext_attrs
2931-
~indent_wrap ?eol e
2952+
fmt_beginend c ~loc:pexp_loc ~box ~pro ~ctx ~ctx0 ~fmt_atrs
2953+
~infix_ext_attrs ~indent_wrap ?eol e
29322954
| Pexp_parens e ->
29332955
pro
29342956
$ hvbox 0
@@ -2959,27 +2981,36 @@ and fmt_lazy c ~ctx ?(pro = noop) ~fmt_atrs ~infix_ext_attrs ~parens e =
29592981
$ fmt_expression c ~pro:kw_inner (sub_exp ~ctx e)
29602982
$ fmt_atrs ) )
29612983

2962-
and fmt_beginend c ~loc ?(box = true) ?(pro = noop) ~ctx ~fmt_atrs
2984+
and fmt_beginend c ~loc ?(box = true) ?(pro = noop) ~ctx ~ctx0 ~fmt_atrs
29632985
~infix_ext_attrs ~indent_wrap ?eol e =
29642986
let cmts_before = Cmts.fmt_before c ?eol loc in
29652987
let begin_ = fmt_infix_ext_attrs c ~pro:(str "begin") infix_ext_attrs
2966-
and end_ = str "end" $ fmt_atrs in
2988+
and end_ =
2989+
(if not box then break 1000 (-2) else break 1000 0)
2990+
$ str "end" $ fmt_atrs
2991+
in
2992+
let box_beginend_sb = Params.Exp.box_beginend_subexpr c.conf ~ctx ~ctx0 in
2993+
let beginend_box =
2994+
if Params.Exp.box_beginend c.conf ~ctx ~ctx0 then
2995+
hvbox ~name:"beginend" 2
2996+
else Fn.id
2997+
in
29672998
cmts_before
29682999
$
29693000
match e.pexp_desc with
29703001
| Pexp_match _ | Pexp_try _ | Pexp_function _ | Pexp_ifthenelse _ ->
2971-
hvbox 0
2972-
( fmt_expression c
2973-
~pro:(pro $ begin_ $ str " ")
2974-
~box ?eol ~parens:false ~indent_wrap (sub_exp ~ctx e)
2975-
$ break 1 0 $ end_ )
3002+
beginend_box
3003+
(fmt_expression c
3004+
~pro:(pro $ begin_ $ str " ")
3005+
~box:false ?eol ~parens:false ~indent_wrap (sub_exp ~ctx e) )
3006+
$ end_
29763007
| _ ->
2977-
hvbox 0
3008+
beginend_box
29783009
( hvbox 0 (pro $ begin_)
29793010
$ break 1 2
2980-
$ fmt_expression c ~box ?eol ~parens:false ~indent_wrap
2981-
(sub_exp ~ctx e)
2982-
$ force_break $ end_ )
3011+
$ fmt_expression c ~box:box_beginend_sb ?eol ~parens:false
3012+
~indent_wrap (sub_exp ~ctx e) )
3013+
$ end_
29833014

29843015
and fmt_let_bindings c ~ctx0 ~parens ~has_attr ~fmt_atrs ~fmt_expr ~loc_in
29853016
rec_flag bindings body =

lib/Params.ml

Lines changed: 72 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,11 @@ module Exp = struct
145145
| Pexp_apply (_, args) -> (
146146
(* Rhs is an apply and it ends with a [fun]. *)
147147
match List.last_exn args with
148-
| _, {pexp_desc= Pexp_function _; _} -> true
148+
| _, {pexp_desc= Pexp_function _; _}
149+
|( _
150+
, { pexp_desc= Pexp_beginend ({pexp_desc= Pexp_function _; _}, _)
151+
; _ } ) ->
152+
true
149153
| _ -> false )
150154
| Pexp_match _ | Pexp_try _ -> true
151155
| _ -> false
@@ -172,10 +176,16 @@ module Exp = struct
172176
| Some ((Labelled _ | Optional _), _, _) -> true
173177
| _ -> false
174178
in
179+
let is_ctx_beginend =
180+
match ctx0 with
181+
| Exp {pexp_desc= Pexp_beginend _; _} -> true
182+
| _ -> false
183+
in
175184
if Conf.(c.fmt_opts.ocp_indent_compat.v) then
176185
if last_arg || is_labelled_arg then break 1 2 else str " "
177186
else if is_labelled_arg then break 1 2
178187
else if last_arg then break 1 0
188+
else if is_ctx_beginend then break 1 0
179189
else str " "
180190

181191
let box_fun_decl_args ~ctx ~ctx0 ?(last_arg = false) ?epi c ~parens ~kw
@@ -224,38 +234,42 @@ module Exp = struct
224234
$ hvbox_if should_box_args 0 (args $ fmt_opt annot $ fmt_opt epi) )
225235

226236
let box_fun_expr (c : Conf.t) ~source ~ctx0 ~ctx =
227-
let indent =
228-
if ctx_is_rhs_of_infix ~ctx0 ~ctx then 0
229-
else if Poly.equal c.fmt_opts.function_indent_nested.v `Always then
230-
c.fmt_opts.function_indent.v
231-
else if ctx_is_let_or_fun ~ctx ctx0 then
232-
if c.fmt_opts.let_binding_deindent_fun.v then 1 else 0
233-
else if ocp c then
234-
let begins_line loc =
235-
Source.begins_line ~ignore_spaces:true source loc
237+
match ctx0 with
238+
| Exp {pexp_desc= Pexp_beginend _; _} -> (Fn.id, 0)
239+
| _ ->
240+
let indent =
241+
if ctx_is_rhs_of_infix ~ctx0 ~ctx then 0
242+
else if Poly.equal c.fmt_opts.function_indent_nested.v `Always then
243+
c.fmt_opts.function_indent.v
244+
else if ctx_is_let_or_fun ~ctx ctx0 then
245+
if c.fmt_opts.let_binding_deindent_fun.v then 1 else 0
246+
else if ocp c then
247+
let begins_line loc =
248+
Source.begins_line ~ignore_spaces:true source loc
249+
in
250+
match ctx_is_apply_and_exp_is_arg ~ctx ~ctx0 with
251+
| Some (Nolabel, fun_exp, is_last_arg) ->
252+
if begins_line fun_exp.pexp_loc then
253+
if is_last_arg then 5 else 3
254+
else 2
255+
| Some ((Labelled x | Optional x), fun_exp, is_last_arg) ->
256+
if begins_line fun_exp.pexp_loc then
257+
(* The [fun] had to break after the label, nested boxes
258+
must be indented less. The last argument is special as
259+
the box structure is different. *)
260+
if is_last_arg then 4 else 2
261+
else if begins_line x.loc then 4
262+
else 2
263+
| None -> if ctx_is_apply_and_exp_is_func ~ctx ctx0 then 3 else 2
264+
else if
265+
ctx_is_apply_and_exp_is_last_arg_and_other_args_are_simple c ~ctx
266+
~ctx0
267+
then 4
268+
else 2
236269
in
237-
match ctx_is_apply_and_exp_is_arg ~ctx ~ctx0 with
238-
| Some (Nolabel, fun_exp, is_last_arg) ->
239-
if begins_line fun_exp.pexp_loc then if is_last_arg then 5 else 3
240-
else 2
241-
| Some ((Labelled x | Optional x), fun_exp, is_last_arg) ->
242-
if begins_line fun_exp.pexp_loc then
243-
(* The [fun] had to break after the label, nested boxes must be
244-
indented less. The last argument is special as the box
245-
structure is different. *)
246-
if is_last_arg then 4 else 2
247-
else if begins_line x.loc then 4
248-
else 2
249-
| None -> if ctx_is_apply_and_exp_is_func ~ctx ctx0 then 3 else 2
250-
else if
251-
ctx_is_apply_and_exp_is_last_arg_and_other_args_are_simple c ~ctx
252-
~ctx0
253-
then 4
254-
else 2
255-
in
256-
let name = "Params.box_fun_expr" in
257-
let mkbox = if ctx_is_let_or_fun ~ctx ctx0 then hvbox else hovbox in
258-
(mkbox ~name indent, ~-indent)
270+
let name = "Params.box_fun_expr" in
271+
let mkbox = if ctx_is_let_or_fun ~ctx ctx0 then hvbox else hovbox in
272+
(mkbox ~name indent, ~-indent)
259273

260274
(* if the function is the last argument of an apply and no other arguments
261275
are "complex" (approximation). *)
@@ -317,6 +331,7 @@ module Exp = struct
317331

318332
let box_fun_decl ~ctx0 c k =
319333
match ctx0 with
334+
| Exp {pexp_desc= Pexp_beginend _; _} -> hovbox 2 k
320335
| _ when ocp c -> hvbox 2 k
321336
(* Avoid large indentation for [let _ = function]. *)
322337
| Lb
@@ -326,6 +341,30 @@ module Exp = struct
326341
| Str _ | Lb _ | Clf _ | Exp {pexp_desc= Pexp_let _; _} -> hovbox 4 k
327342
| _ -> hvbox 2 k
328343

344+
let box_fun_decl_after_pro ~ctx0 =
345+
match ctx0 with
346+
| Exp {pexp_desc= Pexp_beginend _; _} ->
347+
hvbox (2 - String.length "begin ")
348+
| _ -> Fn.id
349+
350+
let box_beginend c ~ctx0 ~ctx =
351+
let contains_fun =
352+
match ctx with
353+
| Exp {pexp_desc= Pexp_beginend ({pexp_desc= Pexp_function _; _}, _); _}
354+
->
355+
true
356+
| _ -> false
357+
in
358+
contains_fun
359+
&& not
360+
(ctx_is_apply_and_exp_is_last_arg_and_other_args_are_simple c ~ctx
361+
~ctx0 )
362+
363+
let box_beginend_subexpr c ~ctx0 ~ctx =
364+
not
365+
(ctx_is_apply_and_exp_is_last_arg_and_other_args_are_simple c ~ctx
366+
~ctx0 )
367+
329368
let match_inner_pro ~ctx0 ~parens =
330369
if parens then false
331370
else
@@ -854,7 +893,7 @@ let get_if_then_else (c : Conf.t) ~pro ~first ~last ~parens_bch
854893
; box_keyword_and_expr= Fn.id
855894
; branch_pro= branch_pro ()
856895
; wrap_parens= wrap_parens ~wrap_breaks:(wrap (break 1000 2) noop)
857-
; box_expr= Some false
896+
; box_expr= Some beginend
858897
; expr_pro= None
859898
; expr_eol= Some (break 1 2)
860899
; branch_expr

lib/Params.mli

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ module Exp : sig
8181
val box_fun_decl : ctx0:Ast.t -> Conf.t -> Fmt.t -> Fmt.t
8282
(** Box a function decl from the label to the arrow. *)
8383

84+
val box_fun_decl_after_pro : ctx0:Ast.t -> Fmt.t -> Fmt.t
85+
(** Box a function decl from after the [pro] to the arrow. *)
86+
87+
val box_beginend : Conf.t -> ctx0:Ast.t -> ctx:Ast.t -> bool
88+
89+
val box_beginend_subexpr : Conf.t -> ctx0:Ast.t -> ctx:Ast.t -> bool
90+
8491
val match_inner_pro : ctx0:Ast.t -> parens:bool -> bool
8592
(** whether the [pro] argument of [fmt_match] should be displayed as an inner
8693
or outer prologue.*)

test/passing/refs.default/attributes.ml.ref

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,7 @@ include [@foo] M [@boo]
395395
let () =
396396
let () =
397397
S.ntyp Cbor_type.Reserved
398-
@@ S.tok
399-
begin[@warning "-4"] fun ev ->
398+
@@ S.tok begin[@warning "-4"] fun ev ->
400399
match ev with Cbor_event.Reserved int -> Some int | _ -> None
401400
end
402401
in

test/passing/refs.default/cases_exp_grouping.ml.ref

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ let a =
116116
| B -> bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
117117
end
118118

119-
let a = begin match f x i with A -> a | B -> b end
119+
let a =
120+
begin match f x i with A -> a | B -> b
121+
end
120122

121123
let a =
122124
begin[@a] match[@b]
@@ -175,7 +177,9 @@ let a =
175177
| B -> bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
176178
end
177179

178-
let a = begin try f x i with A -> a | B -> b end
180+
let a =
181+
begin try f x i with A -> a | B -> b
182+
end
179183

180184
let a =
181185
begin[@a] try[@b]

test/passing/refs.default/exp_grouping-parens.ml.ref

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,7 @@ let v =
388388
a f b)
389389

390390
let v =
391-
map x
392-
begin%ext1 fun%ext2 x y z ->
391+
map x begin%ext1 fun%ext2 x y z ->
393392
ya f;
394393
a f b
395394
end
@@ -554,3 +553,47 @@ let _ =
554553
a
555554
end
556555
[@a]
556+
557+
let () =
558+
fooooo
559+
|>>>>> List.iter (fun a ->
560+
let x =
561+
some_really_really_really_long_name_that_doesn't_fit_on_the_line
562+
$ y
563+
in
564+
fooooooooooo x)
565+
566+
let () =
567+
fooooo
568+
|>>>>> List.iter
569+
(fun aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ->
570+
let x =
571+
some_really_really_really_long_name_that_doesn't_fit_on_the_line
572+
$ y
573+
in
574+
fooooooooooo x)
575+
576+
let () =
577+
fooooo
578+
|>>>>> List.iter (fun a ->
579+
let x =
580+
some_really_really_really_long_name_that_doesn't_fit_on_the_line
581+
$ y
582+
in
583+
fooooooooooo x)
584+
585+
let () =
586+
fooooo
587+
|>>>>> List.iter aaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaa
588+
aaaaaaaaaaaaaa
589+
(fun
590+
aaaaaaaaaaaaaaaaaaaaaaaaaaa
591+
aa
592+
aaaaaaaaaaa
593+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
594+
->
595+
let x =
596+
some_really_really_really_long_name_that_doesn't_fit_on_the_line
597+
$ y
598+
in
599+
fooooooooooo x)

0 commit comments

Comments
 (0)