Items marked with an asterisk (*) are changes that are likely to format existing code differently from the previous release when using the default profile. This started with version 0.26.0.
((module M) : (module S)) are no longer rewritten to (module M : S) because these are now two different syntaxes.* Reduce indentation after |> map (fun (#2694, @EmileTrotignon) Notably, the indentation no longer depends on the length of the infix operator, for example:
(* before *)
v
|>>>>>> map (fun x ->
x )
(* after *)
v
|>>>>>> map (fun x ->
x )@@ match can now also be on one line.
Added option module-indent option (#2711, @HPRIOR) to control the indentation of items within modules. This affects modules and signatures. For example, module-indent=4:
module type M = sig
type t
val f : (string * int) list -> int
endexp-grouping=preserve is now the default in default and ocamlformat profiles. This means that its now possible to use begin ... end without tweaking ocamlformat. (#2716, @EmileTrotignon)--max-iter is not accepted anymore, you have to pass the full option --max-iters. This does not apply to the keys in the .ocamlformat configuration files, which have always required the full name. See dbuenzli/cmdliner#200. (#2680, @emillon)f @@ match%e expressions to the level of indentation in f @@ match. Other unknown inconsistencies might also be fixed. (#2676, @EmileTrotignon)begin function, and fun had attributes stuck to the keyword: match[@a], but fun [@a]. Now its also fun[@a]. (#2676, @EmileTrotignon)let a = b in fun ... is now consistent with other contexts like a ; fun .... A check for the syntax let a = fun ... in ... was made more precise. (#2705, @EmileTrotignon)* |> begin, ~arg:begin, begin if, lazy begin, begin match, begin fun and map li begin fun can now be printed on the same line, with one less indentation level for the body of the inner expression. (#2664, #2666, #2671, #2672, #2681, #2685, #2693, @EmileTrotignon) For example :
(* before *)
begin
fun x ->
some code
end
(* after *)
begin fun x ->
some code
endbreak-struct=natural now also applies to sig ... end. (#2682, @EmileTrotignon)wrap-comments=true not working with the janestreet profile (#2645, @Julow) Asterisk-prefixed comments are also now formatted the same way as with the default profile.nested-match=align not working with match%ext (#2648, @EmileTrotignon)let pattern : type = function ... (#2651, @v-gb)Ast_mapper.default_mapper now iterates on the location of in in let+ .. in .. (#2658, @v-gb)let+ (Cstr _) : _ = _ (#2661, @Julow) This caused a crash as the generated code wasn't valid syntax.let%ext { ... (#2663, @EmileTrotignon) with dock-collection-brackets enabled.mld files that cannot be lexed as ocaml (e.g. containing LaTeX or C code) (#2684, @emillon)module M = F ((A : T)) becomes module M = F (A : T). (#2678, @EmileTrotignon);; due to interaction with floating doc comments. (#2691, @EmileTrotignon)((fun [@a] x -> y) [@b]) is formatted without moving attributes. (#2676, @EmileTrotignon)begin%e ... end and begin [@a] ... end nodes are always preserved. (#2676, @EmileTrotignon)begin end syntax for () is now preserved. (#2676, @EmileTrotignon)type 'a t = A : 'a. {a: 'a} -> 'a t. (#2710, @EmileTrotignon)type%e nonrec t = t was formatted as type nonrec%e t = t, which is invalid syntax. (#2712, @EmileTrotignon)* Fix ;; being added after a documentation comment (#2683, @EmileTrotignon) This results in more ;; being inserted, for example:
(* before *)
print_endline "foo"
let a = 3
(* after *)
print_endline "foo" ;;
let a = 3if then (* comment *) begin .. end (#2734, @Julow)Support OCaml 5.3 syntax (#2609, #2610, #2611, #2622, #2623, #2562, #2624, #2625, #2627, @Julow, @Zeta611) This adds support for effect patterns, short functor type arguments and utf8 identifiers. To format code using the new effect syntax, add this option to your .ocamlformat:
ocaml-version = 5.3parse-docstrings = false to restore the previous behavior.* Consistent indentation of polymorphic variant arguments (#2427, @Julow) Increases the indentation by one to make the formatting consistent with normal variants. For example:
...
(* before *)
(`Msg
(foo bar))
(* after *)
(`Msg
(foo bar))Added option let-binding-deindent-fun (#2521, @henrytill) to control the indentation of the fun in:
let f =
fun foo ->
bar--disable-outside-detected-project (#2439, @gpetiot) It was removed in version 0.22.* Improve formatting of type constraints with type variables (#2437, @gpetiot) For example:
let f : type a b c.
a -> b -> c =
...* Undo let-bindings and methods normalizations (#2523, #2529, @gpetiot) This remove the rewriting of some forms of let-bindings and methods:
let f x = (x : int) is no longer rewritten into let f x : int = xlet f (type a) (type b) ... is no longer rewritten into let f (type a b) ...let f = fun x -> ... is no longer rewritten into let f x = ...break-colon option is now taken into account for method type constraints (#2529, @gpetiot)* Force a break around comments following an infix operator (fix non-stabilizing comments) (#2478, @gpetiot) This adds a line break:
a
||
(* this comment is now on its own line *)
bopen[@attr] M as open M [@@attr].[@ocamlformat "disable"] in some cases (#2242, #2525, @EmileTrotignon) This caused a bug inside class type constructs and when attached to a let ... ina##b instead of a ## b and similarly for operators that start with # (#2580, @v-gb)break-separators=before (#2598, @Julow)let%ext (#2615, @Julow)object keyword in class types (#2425, @Julow)with module (#2419, @Julow)--numeric feature (#2333, #2357, @gpetiot)let f (type a) :> a M.u = .. (#2399, @Julow)module T = (val (x : (module S))) (#2370, @Julow)then begin end (#2369, @Julow)fun _ : _ -> (#2352, @Julow)(::) (#2347, @Julow)as-patterns that have parentheses (#2359, @Julow)@@ let+ x = ... (#2315, #2396, @Julow) It was formatted differently than @@ let x = ....fun (type a) -> following fun x -> (#2294, @Julow)((module M) : (module S)) is formatted as (module M : S)) (#2280, #2300, @gpetiot, @Julow)~label:(fun ... (#2271, #2291, #2293, #2298, #2398, @Julow) The fun keyword is docked where possible and the arguments are indented to avoid confusion with the body.max-indent option is not set (#2131, @hhugo, @gpetiot)enable/disable floating attributes (#2156, @gpetiot).ocamlformat-ignore under Windows (#2206, @nojb)initializer keyword (#2145, @gpetiot)(struct end) vs ()) (#2135, #2146, @trefis, @gpetiot)((module X) : (module Y)) vs (module X : Y)) (#2136, @trefis, @gpetiot)Preserve syntax and improve readability of indexop-access expressions (#2150, @trefis, @gpetiot)
if carrying attributes (#2167, @trefis, @gpetiot)ocamlformat package now only contains the binary, the library is available through the ocamlformat-lib package (#2230, @gpetiot)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).mld files as odoc documentation files (#2008, @gpetiot)vertical for option if-then-else (#2174, @gpetiot)vertical for option break-cases (#2176, @gpetiot)wrap-or-vertical for option break-infix that only wraps high precedence infix ops (#1865, @gpetiot)Support odoc-parser.2.0.0 (#2123, @gpetiot)
odoc-parser{m ...} available in doc-comments{math ...} available in doc-commentsbench binary is not distributed anymore to avoid name collisions (#2104, @gpetiot)indicate-multiline-delimiters (#2116, @gpetiot).ocp-indent files (#2103, @gpetiot)max-indent = 2 (#2099, @gpetiot)| under keyword instead of parenthesis (#2102, @gpetiot)compact and sparse are now removed (#2075, @gpetiot)align-cases, align-constructors-decl and align-variants-decl are now removed (#2076, @gpetiot)disable-outside-detected-project is now removed (#2077, @gpetiot)$XDG_CONFIG_HOME or $HOME/.config) is only applied when no project is detected, --enable-outside-detected-project is set, and no applicable .ocamlformat file has been found. Global and local configurations are no longer used at the same time. (#2039, @gpetiot)ocaml-version to a fixed version (4.04.0) by default to avoid reproducibility issues and surprising behaviours (#2064, @kit-ty-kate)--numeric=X-Y into --range=X-Y and --numeric (flag). For now --range can only be used with --numeric. (#2073, #2082, @gpetiot)(*= ... *) for verbatim comments (#2028, @gpetiot)--print-config displays a warning when an .ocamlformat file defines redundant options (already defined by a profile) (#2084, @gpetiot):= when assignment-operator=end-line (#1985, @gpetiot)wrap-comments should only impact non-documentation comments, wrapping invalid docstrings would cause the whole file to not be formatted (#1988, @gpetiot)comment-check, disable, max-iters, ocaml-version, and quiet (#1995, @gpetiot).(x >>= (fun () -> ())) [@a] (#2013, @emillon)More expressions are considered "simple" (not inducing a break e.g. as an argument of an application):
--parse-toplevel-phrases. Toplevel phrases are supported when they are located in doc-comments blocks and cinaps comments. Whole input files can also be formatted as toplevel phrases with the flag --repl-file.Csexp.t types instead of Sexplib0.Sexp.t..ocamlformat (#2011, @panglesd, @Julow){@ocaml kind=toplevel env=e1[ code ]}compact and sparse are now deprecated and will be removed by version 1.0 (#1803, @gpetiot)Options that are not set by the preset profiles are now deprecated and will be removed by version 1.0:
align-cases, align-constructors-decl and align-variants-decl (#1793, @gpetiot)disambiguate-non-breaking-match (#1805, @gpetiot)break-before-in (#1888, @gpetiot)break-cases={toplevel,all} (#1890, @gpetiot)break-collection-expressions (#1891, @gpetiot)break-fun-decl=smart (#1892, @gpetiot)break-fun-sig=smart (#1893, @gpetiot)break-string-literals (#1894, @gpetiot)break-struct (#1895, @gpetiot)extension-indent (#1896, @gpetiot)function-indent (#1897, @gpetiot)function-indent-nested (#1898, @gpetiot)if-then-else={fit-or-vertical,k-r} (#1899, @gpetiot)indicate-multiline-delimiters=closing-on-separate-line (#1900, @gpetiot)indent-after-in (#1901, @gpetiot)let-binding-indent (#1902, @gpetiot)let-binding-spacing=sparse (#1903, @gpetiot)match-indent (#1904, @gpetiot)match-indent-nested (#1905, @gpetiot)module-item-spacing=preserve (#1906, @gpetiot)nested-match (#1907, @gpetiot)parens-tuple-patterns (#1908, @gpetiot)sequence-style=before (#1909, @gpetiot)stritem-extension-indent (#1910, @gpetiot)type-decl-indent (#1911, @gpetiot){|...|} (#1754, @nojb, @hhugo)*, %, #-ops) (#1776, @gpetiot)indicate-multiline-delimiters=closing-on-separate-line (#1786, @gpetiot)foo ~(x:int) instead of the explicit foo ~x:(x:int). (ocaml#10434) (#1756, #1759, @gpetiot). This syntax is only produced when the output syntax is at least OCaml 4.14.ocaml-version option to select the version of OCaml syntax of the output (#1759, @gpetiot)begin%ext syntax for infix opererator expressions (#1653, @gpetiot);; tokens (#1688, @gpetiot)odoc-parser instead of odoc (#1683, #1713, @kit-ty-kate, @jonludlam, @julow). The parser from odoc has been split from the main odoc package and put into its own package, odoc-parser.Implement OCaml 4.13 features (#1680, @gpetiot)
Emacs integration (disabled for ocamlformat < 0.19.0):
tools/build-mingw64.sh is provided to build a native Windows binary of ocamlformat using mingw64 toolchain under Cygwin.let open with closing-on-separate-line (#1612, @Julow)bisect_ppx (#1550, @tmattio)ocamlformat-rpc and a new library ocamlformat-rpc-lib (#1586, @gpetiot, @voodoos)String.get and similar calls used to be automatically rewritten to their corresponding infix form .(), that was incorrect when using the -unsafe compilation flag. Now the concrete syntax of these calls is preserved.if%ext with if-then-else=keyword-first (#1419, #1543, @gpetiot)match and try keywords (#1458, @gpetiot)Clean up ocamlformat.el for submission to MELPA (#1476, #1495, @bcc32)
ocamlformat.el (#1474, @bcc32)ocamlformat.el buffer replacement for MacOS Emacs (#1481, @juxd)function match (#1498, @gpetiot)open%ext M will not get rewritten to [%%ext open M].Use ppxlib instead of ocaml-migrate-parsetree 1.x. (#1482, @emillon)
{i blah} in docstrings (#1346, @jberdine)#**# or #**. where ** can be 0 or more operator chars are considered getter operators and are not surrounded by spaces, as opposed to regular infix operators (#1376, @gpetiot)function body of a fun (#1343, @jberdine)*compilation* buffer on successful reformat (#1350, @jberdine)wrap-comments=false and ocp-indent-compat=true are set to avoid interfering with ocp-indent indentation. (#1352, @gpetiot)[]{} must not be escaped in the arguments of @raise, @author, @version and others.(* *), (** *) and (*$ *) (#1407, @gpetiot)Backport the following PRs:
Merge doc-comments-val option with doc-comments. The placement of documentation comments on val and external items is now controled by doc-comments.
doc-comments=after becomes doc-comments=after-when-possible to take into account the technical limitations of ocamlformat;doc-comments=before is unchanged;doc-comments-val is now replaced with doc-comments. To reproduce the former behaviors
doc-comments=before + doc-comments-val=before: now use doc-comments=before;doc-comments=before + doc-comments-val=after: now use doc-comments=before-except-val;doc-comments=after + doc-comments-val=before: this behavior did not make much sense and is not available anymore;doc-comments=after + doc-comments-val=after: now use doc-comments=after-when-possible. (#1358, @jberdine, @Julow, @gpetiot). This reverts changes introduced in 0.14.1 (#1335) and 0.14.0 (#1012).doc-comments is changed to after (#1335, @Julow). This reverts a change introduced in 0.14.0 (#1012).doc-comments option (#1331, @Julow). This reverts a change introduced in 0.14.0 (#1293).--format-invalid-files to print unparsable parts of the input as verbatim text. This feature is still experimental. (#1026, @gpetiot)module M = functor (K : S) -> struct end and module M (K : S) = struct end would be formatted as the latter, the original syntax is now preserved.doc-comments-val=before|after (#1012, @Julow). This option set the placement of documentation comment on val and external only. It is set to after by default.doc-comments is changed from after to before (#1012, #1325, @Julow). This affects both conventional (default) and ocamlformat profiles.Some options are now deprecated:
doc-comments (#1293, #1012). This option depends on a flawed heuristic. It is replaced by doc-comments-val for val and external declarations. There is no equivalent to this option in the general case.escape-chars, escape-strings and extension-sugar (#1293). These options are rarely used and their default behavior is considered to be the right behavior.row_field attributes and the label or arguments, to be consistent with the non-polymorphic case. (#1299, @CraigFe)let open (#1229, @Julow). eg. M.f (M.(x) [@attr]) would be formatted to M.f M.(x) [@attr], which would crash OCamlformatRemove unecessary parentheses with attributes in some structure items:
[%ext (() [@attr])] or the structure item (() [@attr]) ;;let _ = ... constructs (#1244, @emillon)Fix some bugs related to comments:
(x >>= fun y -> y (* A *)) would be droppedmodule M = (val x : S (* A *))[%a:] (#1236, @emillon){< >} (#1238, @emillon)Retain attributes on various AST nodes:
(a.x <- b) [@a] (#1284, @CraigFe)(a <- b) [@a] (#1288, @CraigFe)(a.(b)) [@a] (#1300, @CraigFe)(a; b) [@a] (#1291, @CraigFe){foo : < .. > [@a]} and { foo : < .. > } (#1296, @CraigFe)f ((0, 0) [@a]) would be formatted to f (0, 0) [@a], crashing OCamlformat.>] when an object type is contained in an extension point or attribute payload (#1298, @CraigFe)(0).*(0) (#1304, @Julow). It was formatting to 0.*(0) which parses as an other expression.(**) would be formatted to (***).class (#1289, @emillon)let f ?a:(A) = () rather than the unparsable let f ?a:A = () (#1305, @CraigFe)--margin-check to emit a warning if the formatted output exceeds the margin (#1110, @gpetiot)wrap-comments is unset (#1138, #1159, @Julow)ocamlformat_reason (#254, #1185, @emillon). This tool has never been released to opam, has no known users, and overlaps with what refmt can do.ocamlformat-diff (#1205, @gpetiot). This tool has never been released to opam, has no known users, and overlaps with what merge-fmt can do.break-cases=fit (#1167, @Julow). This also fixes an unstable comment bug in or-patternsversion-check (#1135, @Wilfred)break-separators=after-and-docked (#1130, @gretay-js)profile = ocamlformat in your .ocamlformat.--opt and --no-opt` are available on the CLI for any boolean option "opt". Previously, only one of them were available depending on the default value.break-string-literals (#1057, @gpetiot). wrap, newlines and newlines-and-wrap values of break-string-literals are removed. auto replaces them, it is equivalent to newlines-and-wrap.after-and-docked value of break-separators is removed and is replaced by a new dock-collection-brackets option.begin and end keywords in if-then-else (#978, @Julow). Previously, begin/end keywords around if-then-else branches were turned into parentheses.sequence-blank-line=preserve-one for let bindings (#1077, @Julow). Preserve a blank line after let .. in when sequence-blank-line set to preserve-one. Previously, only blank lines after ; could be preserved.#directives in .ml files. Previously, files containing a directive needed to be parsed as "use file". The "use file" mode is removed and --use-file is now the same as --impl.--name, require kind, forbid --inplace, allow --check, make --enable-outside-detected-project implicit when reading from stdin (#1018, @gpetiot)(*$ code *) and code blocks in documentation comments (** {[ code ]} *).max-indent (#1105, @gpetiot)Pmty_with (#1103, @jberdine)break-cases=all (#1002, @gpetiot)Fmt API in case Fmt.t goes abstract (#1106, @emillon)Translation_unit (#1078, @gpetiot)sequence_blank_line (#1075, @Julow)Fmt_ast (#1059, @gpetiot)test_branch.sh (#1033, @gpetiot)test_branch.sh and CI checking of CHANGES.md (#1032, #1034, @Julow)test_branch.sh and bisect.sh (#1027, @gpetiot)bisect_ppx dependency and clean the Makefile (#1005, @Julow)CHANGES.md log file again (#1023, @gpetiot)CONTRIBUTING.md (#1007, @gpetiot)--ignore-invalid-option flag is added to ignore invalid options in .ocamlformat files.--doc-comments (#982, @Julow)fmt_code (#974, @gpetiot)Makefile (#973, @hhugo)let%ext (#873, @gpetiot):= (#780, @gpetiot); _ (#549, @jberdine):: (#452, @jberdine)function%ext (#416, @hhugo)while%ext/for%ext (@hhugo)# infix ops (@hhugo)in (#328, @jberdine)make -C test (@jberdine)+/- (@hhugo)%; (@hhugo)not when infix op arg (@jberdine)function cases (@jberdine)>] which is an unparsable keyword (#171, @hhugo)module type of (@jberdine)not to be trivial if their arg ismake -C testnew%js (#136, @hhugo)(type a b c) (#142, hhugo){ !e with a } (#138, @hhugo)(universe) support in jbuilder 1.0+beta20Pexp_new expressions (#76, @smondet)Pexp_send _ expressions (#72, @smondet)[][ and < or > in variant types