Skip to content

Commit

Permalink
First draft of a diff-friendly profile
Browse files Browse the repository at this point in the history
  • Loading branch information
gpetiot committed Oct 7, 2022
1 parent e48de71 commit 7627f1e
Show file tree
Hide file tree
Showing 10 changed files with 10,936 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
- Add a `break-colon` option to decide whether to break before or after the `:` symbol in value binding declarations and type constraints. This behavior is no longer ensured by `ocp-indent-compat`. (#2149, @gpetiot)
- Format `.mld` files as odoc documentation files (#2008, @gpetiot)
- New value `vertical` for option `if-then-else` (#2174, @gpetiot)
- New profile: `diff-friendly`. This profile aims to minimize the vertical diff. The code is formatted in a "unfolded" style such that locally modifying parts of the code has a minimal impact on the surrounding lines. (#2020, @gpetiot)

## 0.24.1 (2022-07-18)

Expand Down
73 changes: 72 additions & 1 deletion lib/Conf.ml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ type fmt_opts =
{ align_pattern_matching_bar: [`Paren | `Keyword]
; assignment_operator: [`Begin_line | `End_line]
; break_before_in: [`Fit_or_vertical | `Auto]
; break_cases: [`Fit | `Nested | `Toplevel | `Fit_or_vertical | `All]
; break_cases:
[`Fit | `Nested | `Toplevel | `Fit_or_vertical | `Unfold | `All]
; break_collection_expressions: [`Wrap | `Fit_or_vertical]
; break_colon: [`Before | `After]
; break_infix: [`Wrap | `Fit_or_vertical]
Expand Down Expand Up @@ -273,6 +274,8 @@ module Formatting = struct
; C.Value.make ~name:"fit-or-vertical" `Fit_or_vertical
"$(b,fit-or-vertical) tries to fit all or-patterns on the same \
line, otherwise breaks."
; C.Value.make ~name:"unfold" `Unfold
"$(b,unfold) unfolds each branch."
; C.Value.make ~name:"all" `All
"$(b,all) forces all pattern matches to break across lines." ]
in
Expand Down Expand Up @@ -1562,6 +1565,69 @@ let conventional_profile =

let default_profile = conventional_profile

let diff_friendly_profile =
{ align_pattern_matching_bar= `Keyword
; assignment_operator= `End_line
; break_before_in= `Fit_or_vertical
; break_cases= `Unfold
; break_collection_expressions= `Fit_or_vertical
; break_colon= `After
; break_infix= `Fit_or_vertical
; break_infix_before_func= true
; break_fun_decl= `Fit_or_vertical
; break_fun_sig= `Fit_or_vertical
; break_separators= `After
; break_sequences= true
; break_string_literals= `Auto
; break_struct= true
; cases_exp_indent= 4
; cases_matching_exp_indent= `Compact
; disambiguate_non_breaking_match= false
; doc_comments= `Before_except_val
; doc_comments_padding= 2
; doc_comments_tag_only= `Default
; dock_collection_brackets= true
; exp_grouping= `Parens
; extension_indent= 2
; field_space= `Tight
; function_indent= 2
; function_indent_nested= `Never
; if_then_else= `Vertical
; indent_after_in= 0
; indicate_multiline_delimiters= `Closing_on_separate_line
; indicate_nested_or_patterns= `Unsafe_no
; infix_precedence= `Indent
; leading_nested_match_parens= false
; let_and= `Sparse
; let_binding_indent= 2
; let_binding_spacing= `Compact
; let_module= `Sparse
; line_endings= `Lf
; margin= 80
; match_indent= 0
; match_indent_nested= `Never
; max_indent= None
; module_item_spacing= `Sparse
; nested_match= `Wrap
; ocp_indent_compat= false
; parens_ite= false
; parens_tuple= `Always
; parens_tuple_patterns= `Multi_line_only
; parse_docstrings= false
; parse_toplevel_phrases= false
; sequence_blank_line= `Compact
; sequence_style= `Separator
; single_case= `Sparse
; space_around_arrays= false
; space_around_lists= false
; space_around_records= false
; space_around_variants= false
; stritem_extension_indent= 0
; type_decl= `Sparse
; type_decl_indent= 2
; wrap_comments= false
; wrap_fun_args= false }

let janestreet_profile =
{ align_pattern_matching_bar= `Keyword
; assignment_operator= `Begin_line
Expand Down Expand Up @@ -1640,6 +1706,11 @@ let profile =
\"conventional\" appearing as the available options allow."
; C.Value.make ~name:"default" (Some default_profile)
"$(b,default) is an alias for the $(b,conventional) profile."
; C.Value.make ~name:"diff-friendly" (Some diff_friendly_profile)
"The $(b,diff_friendly) profile aims to minimize the vertical diff. \
The code is formatted in a \"unfolded\" style such that locally \
modifying parts of the code has a minimal impact on the \
surrounding lines."
; C.Value.make ~name:"ocamlformat" (Some ocamlformat_profile)
"The $(b,ocamlformat) profile aims to take advantage of the \
strengths of a parsetree-based auto-formatter, and to limit the \
Expand Down
3 changes: 2 additions & 1 deletion lib/Conf.mli
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ type fmt_opts =
{ align_pattern_matching_bar: [`Paren | `Keyword]
; assignment_operator: [`Begin_line | `End_line]
; break_before_in: [`Fit_or_vertical | `Auto]
; break_cases: [`Fit | `Nested | `Toplevel | `Fit_or_vertical | `All]
; break_cases:
[`Fit | `Nested | `Toplevel | `Fit_or_vertical | `Unfold | `All]
; break_collection_expressions: [`Wrap | `Fit_or_vertical]
; break_colon: [`Before | `After]
; break_infix: [`Wrap | `Fit_or_vertical]
Expand Down
1 change: 1 addition & 0 deletions lib/Fmt_ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,7 @@ and fmt_pattern ?ext c ?pro ?parens ?(box = false)
match c.conf.fmt_opts.break_cases with
| `Fit_or_vertical -> open_hvbox
| `Fit | `Nested | `Toplevel | `All -> open_hovbox
| `Unfold -> open_vbox
in
hvbox 0
( list_fl (List.group xpats ~break)
Expand Down
14 changes: 13 additions & 1 deletion lib/Params.ml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ let get_or_pattern_sep ?(cmts_before = false) ?(space = false) (c : Conf.t)
| `Nested -> break nspaces 0 $ str "| "
| _ -> (
let nspaces =
match c.fmt_opts.break_cases with `All -> 1000 | _ -> nspaces
match c.fmt_opts.break_cases with
| `All | `Unfold -> 1000
| _ -> nspaces
in
match c.fmt_opts.indicate_nested_or_patterns with
| `Space ->
Expand Down Expand Up @@ -154,6 +156,16 @@ let get_cases (c : Conf.t) ~first ~indent ~parens_branch ~xbch =
; open_paren_branch
; break_after_opening_paren= fmt "@ "
; close_paren_branch }
| `Unfold ->
{ leading_space= break_unless_newline 1000 0
; bar= str "| "
; box_all= hvbox indent
; box_pattern_arrow= hovbox 0
; break_before_arrow= fmt "@;<1 2>"
; break_after_arrow= fmt_if (not parens_branch) "@;<0 3>"
; open_paren_branch
; break_after_opening_paren= break 1000 0
; close_paren_branch }

let wrap_collec c ~space_around opn cls =
if space_around then wrap_k (str opn $ char ' ') (break 1 0 $ str cls)
Expand Down
17 changes: 10 additions & 7 deletions ocamlformat-help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,16 @@ OPTIONS (CODE FORMATTING STYLE)
auto will only break the line if the in keyword does not fit on
the previous line. The default value is fit-or-vertical.

--break-cases={fit|nested|toplevel|fit-or-vertical|all}
--break-cases={fit|nested|toplevel|fit-or-vertical|unfold|all}
Break pattern match cases. Specifying fit lets pattern matches
break at the margin naturally. nested forces a break after nested
or-patterns to highlight the case body. Note that with nested, the
indicate-nested-or-patterns option is not needed, and so ignored.
toplevel forces top-level cases (i.e. not nested or-patterns) to
break across lines, otherwise break naturally at the margin.
fit-or-vertical tries to fit all or-patterns on the same line,
otherwise breaks. all forces all pattern matches to break across
lines. The default value is fit.
otherwise breaks. unfold unfolds each branch. all forces all
pattern matches to break across lines. The default value is fit.

--break-collection-expressions={fit-or-vertical|wrap}
Break collection expressions (lists and arrays) elements by
Expand Down Expand Up @@ -349,14 +349,17 @@ OPTIONS (CODE FORMATTING STYLE)
Attempt to generate output which does not change (much) when
post-processing with ocp-indent. The flag is unset by default.

-p {conventional|default|ocamlformat|janestreet},
--profile={conventional|default|ocamlformat|janestreet}
-p {conventional|default|diff-friendly|ocamlformat|janestreet},
--profile={conventional|default|diff-friendly|ocamlformat|janestreet}
Select a preset profile which sets all options, overriding lower
priority configuration. The conventional profile aims to be as
familiar and "conventional" appearing as the available options
allow. default is an alias for the conventional profile. The
ocamlformat profile aims to take advantage of the strengths of a
parsetree-based auto-formatter, and to limit the consequences of
diff_friendly profile aims to minimize the vertical diff. The code
is formatted in a "unfolded" style such that locally modifying
parts of the code has a minimal impact on the surrounding lines.
The ocamlformat profile aims to take advantage of the strengths of
a parsetree-based auto-formatter, and to limit the consequences of
the weaknesses imposed by the current implementation. This is a
style which optimizes for what the formatter can do best, rather
than to match the style of any existing code. General guidelines
Expand Down
18 changes: 18 additions & 0 deletions test/passing/dune.inc
Original file line number Diff line number Diff line change
Expand Up @@ -4729,6 +4729,24 @@
(package ocamlformat)
(action (diff tests/skip.ml.err skip.ml.stderr)))

(rule
(deps tests/.ocamlformat )
(package ocamlformat)
(action
(with-stdout-to source-diff-friendly.ml.stdout
(with-stderr-to source-diff-friendly.ml.stderr
(run %{bin:ocamlformat} --margin-check --profile=diff-friendly --max-iters=3 %{dep:tests/source.ml})))))

(rule
(alias runtest)
(package ocamlformat)
(action (diff tests/source-diff-friendly.ml.ref source-diff-friendly.ml.stdout)))

(rule
(alias runtest)
(package ocamlformat)
(action (diff tests/source-diff-friendly.ml.err source-diff-friendly.ml.stderr)))

(rule
(deps tests/.ocamlformat )
(package ocamlformat)
Expand Down
3 changes: 3 additions & 0 deletions test/passing/tests/source-diff-friendly.ml.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Warning: tests/source.ml:5410 exceeds the margin
Warning: tests/source.ml:7198 exceeds the margin
Warning: tests/source.ml:8123 exceeds the margin
2 changes: 2 additions & 0 deletions test/passing/tests/source-diff-friendly.ml.opts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--profile=diff-friendly
--max-iters=3
Loading

0 comments on commit 7627f1e

Please sign in to comment.