# \[ANN\] Release of OCamlFormat 0.10

**URL:** https://discuss.ocaml.org/t/ann-release-of-ocamlformat-0-10/3988
**Category:** Ecosystem
**Created:** [June 27, 2019, 7:48am UTC](https://discuss.ocaml.org/t/ann-release-of-ocamlformat-0-10/3988 "2019-06-27T07:48:38Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![gpetiot](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/gpetiot/32/5184_2.png) [@gpetiot](https://discuss.ocaml.org/u/gpetiot)
#### Post date: [June 27, 2019, 7:48am UTC](https://discuss.ocaml.org/t/ann-release-of-ocamlformat-0-10/3988/1 "2019-06-27T07:48:38Z")

</div>

# Release of OCamlFormat 0.10

We are pleased to announce the release of OCamlFormat 0.10 (available on opam).

There have been numerous changes since the last release, so here is a comprehensive list of the new features and breaking changes to help the transition from OCamlFormat 0.9.

`ocamlformat-0.10` now works on the 4.08 AST, although the formatting should not differ greatly from the one of `ocamlformat-0.9` in this regard.  
Please note that it is necessary to build `ocamlformat` with 4.08 to be able to parse new features like `let*`.

Upgrading from `ocamlformat-0.9` requires to install the following dependencies:

- ocaml-migrate-parsetree \>= 1.3.1 (upgrade)
- uuseg \>= 10.0.0 (new)
- uutf \>= 1.0.1 (upgrade)

This release focuses on preserving the style of the original source and on handling more `ocp-indent` options.

## Style preservation

### Expression grouping

The new option `exp-grouping` has been added to preserve the keywords `begin`/`end` that are used to delimit expressions instead of parentheses. `exp-grouping=parens` always uses parentheses to delimit expressions. `exp-grouping=preserve` preserves the original grouping syntax (parentheses or `begin`/`end`).

### Horizontal alignment

Horizontal alignment is something that users often use to make pattern-matching or type declarations easier to read, and it is a feature that has been requested many times. Three new options have been added to horizontally align the lines.

`align-cases` horizontally aligns the match/try cases:

```ocaml
let fooooooooooo =
  match foooooooooooooooooooooooo with
  | Bfooooooooooooooooo -> foooooooooooo
  | C (a, b, c, d) -> fooooooooooooooooooo
  | _ -> fooooooooooooooooooo

```

`align-constructors-decl` horizontally aligns type declarations:

```ocaml
type t =
  | ( :: ) of a * b
  | [] of looooooooooooooooooooooooooooooooooooooong_break

```

`align-variants-decl` horizontally aligns variants type declarations:

```ocaml
type x =
  [ `Foooooooo of int
  | `Fooooooooooooo of int ]

```

### Preserve blank lines in sequences

The new option `sequence-blank-line` decides whether a blank line is preserved between expressions of a sequence. `sequence-blank-line=compact` will not keep any blank line between expressions of a sequence, this is still the default behavior. `sequence-blank-line=preserve` will keep a blank line between two expressions of a sequence if the input contains at least one.

This option can help preserving the readability of the code in this situation:

```ocaml
let foo x y =
  do_some_setup y ;

  important_function x

```

## Supporting more `ocp-indent` options

The long term goal of `ocamlformat` is to handle every `ocp-indent` option, this release got closer to this goal as the following `ocp-indent` options are now supported by `ocamlformat`:

- max\_indent
- with
- strict\_with
- ppx\_stritem\_ext
- base
- in
- type

### Offset added to a new line

The new option `max-indent` sets the maximum offset (number of columns) added to a new line in addition to the offset of the previous line. If this offset is set to 2 columns, then each new line can only be indented by 2 columns more in addition to the previous line, for example:

```ocaml
let () =
  fooooo
  |> List.iter (fun x ->
    let x = x $ y in
    fooooooooooo x)

```

This option is equivalent to the `max_indent` option of `ocp-indent`, and it will be set if `max_indent` is set in an `.ocp-indent` configuration file.

### Indentation of pattern matching cases

The new options `funtion-indent` and `match-indent` respectively decide the indentation of function cases and the indentation of match/try cases.  
These options are equivalent to the `with` option of `ocp-indent`, and they will be set if `with` is set in an `ocp-indent` configuration file.  
If the indentation is set to 4 columns, cases are formatted like this:

```ocaml
let foooooooo = function
    | fooooooooooooooooooooooo -> foooooooooooooooooooooooooo
    
let foooooooo =
  match fooooooooooooooooooooooo with
      | fooooooooooooooooooooooo -> foooooooooooooooooooooooooo

```

The new options `function-indent-nested` and `match-indent-nested` respectively decide whether the `function-indent` and the `match-indent` parameters should be applied even when in a sub-block. If these options are set to `never`, it only applies `function-indent` or `match-indent` if the function or match block starts a line. If these options are set to `always`, then the indent parameters are always applied. The `auto` value applies the indentation parameter when seen fit.

These options are equivalent to the `strict_with` option of `ocp-indent`, and they will be set if `strict_with` is set in an `ocp-indent` configuration file.

### Indentation inside extension nodes

The new option `extension-indent` sets the indentation of items (that are not at structure level) inside extension nodes.  
The new option `stritem-extension-indent` sets the indentation of structure items inside extension nodes. This option is equivalent to the `ppx_stritem_ext` option of `ocp-indent`, and it will be set if `ppx_stritem_ext` is set in an `.ocp-indent` configuration file.

For example if `extension-indent` is set to 5 and `stritem-extension-indent` is set to 3:

```ocaml
let foo =
  [%foooooooooo
       fooooooooooooooooooooooooooo foooooooooooooooooooooooooooooooooo
         foooooooooooooooooooooooooooo]
  [@@foooooooooo
       fooooooooooooooooooooooooooo foooooooooooooooooooooooooooooooooo
         foooooooooooooooooooooooooooo]

[@@@foooooooooo
   fooooooooooooooooooooooooooo foooooooooooooooooooooooooooooooooo
     foooooooooooooooooooooooooooo]

```

### Let-binding indentation

The new option `let-binding-indent` sets the indentation of let binding expressions if they do not fit on a single line. This option is equivalent to the `base` option of `ocp-indent`.  
The new option `indent-after-in` sets the indentation after `let ... in`, unless followed by another `let`. This option is equivalent to the `in` option of `ocp-indent`.  
The new option `type-decl-indent` sets the indentation of type declarations if they do not fit on a single line. This option is equivalent to the `type` option of `ocp-indent`.

These options will be set if their `ocp-indent` counterparts are set in an `.ocp-indent` configuration file.

## Miscellaneous features

This release also brings some new options, new values for existing features, or corrects erroneous behaviours.

### Indicate multiline delimiters

The former `indicate-multiline-delimiters` boolean option is now a 3-valued option:

- `indicate-multiline-delimiters=space` (was equivalent to `true`) prints a space inside the delimiter to indicate the matching one is on a different line.
- `indicate-multiline-delimiters=no` (was equivalent to `false`) doesn’t do anything special to indicate the closing delimiter.
- `indicate-multiline-delimiters=closing-on-separate-line` is the new feature of this option, it makes sure that the closing delimiter is on its own line.

On this example we can see the closing parenthesis delimiting the nested pattern-matchings are on their own line and are aligned with the matching opening parenthesis:

```ocaml
let () =
   match v with
   | None -> None
   | Some x ->
       ( match x with
       | None -> None
       | Some x ->
           ( match x with
           | None -> None
           | Some x -> x
           )
       )

```

### Formatting of literal strings

`break-string-literals=newlines` now takes into account pretty-printing commands like `@,`, `@;` and `@\n` to produce more readable strings. A new value for this option has been added, `break-string-literals=newlines-and-wrap`, to break lines at newlines delimiters (including pretty-printing commands) and also wrap the string literals at the margin.

Here is how `break-string-literals=newlines-and-wrap` formats a string:

```ocaml
let fooooooooooo =
  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod \
   tempor incididunt ut labore et dolore magna aliqua.@;\
   Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi \
   ut aliquip ex ea commodo consequat.@;\
   Duis aute irure dolor in reprehenderit in voluptate velit esse cillum \
   dolore eu fugiat nulla pariatur.@;\
   Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \
   officia deserunt mollit anim id est laborum."

```

**Warning:** the `break-string-literals` will likely be removed in the next release and the default behavior would be `newlines-and-wrap`.

### Break before the `in` keyword

The new option `break-before-in` has been added to decide whether the line should break before the `in` keyword of a `let` binding. `break-before-in=fit-or-vertical` will always break the line before the `in` keyword if the whole `let` binding does not fit on a single line, it is still the default behavior. `break-before-in=auto` will only break the line if the `in` keyword does not fit on the previous line.

For example:

```ocaml
let _ =
  let short = this is short in
  let fooo =
    (this is very long) but (the in keyword can fit) on the same line in
  foooooo

```

### Indentation of nested pattern-matching

The new option `nested-match` defines the style of pattern-matchings nested in the last case of another pattern-matching. `nested-match=wrap` wraps the nested pattern-matching with parentheses and adds indentation, this is still the default behavior. `nested-match=align` vertically aligns the nested pattern-matching under the encompassing pattern-matching, for example:

```ocaml
let () =
  match v with
  | None -> None
  | Some x ->
  match x with
  | None -> None
  | Some x -> x

```

The new option `cases-matching-exp-indent` decides the indentation of cases right-hand sides which are `match` or `try` expressions. `cases-matching-exp-indent=compact` forces an indentation of 2, unless `nested-match` is set to `align` and this is the last case of the pattern matching. `compact` is the default behavior. `cases-matching-exp-indent=normal` indents as it would any other expression.

### Whitelist of files to format

A new kind of configuration files is now handled by `ocamlformat`: `.ocamlformat-enable` files.  
If the `disable` option is set, an `.ocamlformat-enable` file can list the files that `ocamlformat` should format even when the `disable` option is set. Each line in an `.ocamlformat-enable` file specifies a filename relative to the directory containing the `.ocamlformat-enable` file.

The `.ocamlformat-enable` files are using the same syntax as the `.ocamlformat-ignore` files: lines starting with `#` are ignored and can be used as comments.

These new configuration files do not contradict the existing `.ocamlformat-ignore` files, as `.ocamlformat-enable` are only considered when `disable` is set, and `.ocamlformat-ignore` are only considered when `disable` is not set.

### Disable outside detected project

The `disable-outside-detected-project` option is now set by default.

When the option `--enable-outside-detected-project` is not set, `.ocamlformat` files outside of the project (including the one in `XDG_CONFIG_HOME`) are not read. The project root of an input file is taken to be the nearest ancestor directory that contains a .git or .hg or dune-project file. If no config file is found, formatting is disabled.

### Space around collection-expressions

The former option `space-around-collection-expressions` that was deciding whether a space should be added inside the delimiters of collection expressions (lists, arrays, records, variants) has been replaced by 4 new options: `space-around-arrays`, `space-around-lists`, `space-around-records` and `space-around-variants`, to allow a finer grain customization.

### Fit-or-vertical mode for pattern matching

The `break-cases` option that decides the shape of pattern matching has a new value `fit-or-vertical`. `break-cases=fit-or-vertical` tries to fit all or-patterns on the same line, otherwise breaks each or-pattern (they are wrapped in other modes).  
For example if this set of or-patterns does not fit on a single line, we get the following output:

```ocaml
let ffffff =
  match foooooooooooo with
  | Aaaaaaaaaaaaaaaaa
  | Bbbbbbbbbbbbbbbbb
  | Ccccccccccccccccc
  | Ddddddddddddddddd
  | Eeeeeeeeeeeeeeeee -> foooooooooooooooooooo
  | Fffffffffffffffff -> fooooooooooooooooo

```

### K&R style for if-then-else

The `if-then-else` option now has a new value `k-r` that uses parentheses (when necessary) to reproduce a formatting close to the K&R style. For example:

```ocaml
let _ =
  if b then (
    something loooooooooooooooooooooooooooooooong enough to_trigger a break ;
    this is more
  ) else if b1 then (
    something loooooooooooooooooooooooooooooooong enough to_trigger a break ;
    this is more
  ) else
    e

```

## Breaking changes

- the `indicate-multiline-delimiters` option is no longer a boolean option but now has 3 values: `space`, `no` and `closing-on-separate-line` that are detailed in this patch note.
- the `disable-outside-detected-project` option is now set by default.
- the `default` preset profile has been removed (it was equivalent to the `ocamlformat` profile with `break-cases=fit`).
- the `space-around-collection-expressions` option has been replaced by 4 new options: `space-around-arrays`, `space-around-lists`, `space-around-records` and `space-around-variants`.

## What’s next?

We strongly encourage our users to try out the `conventional` preset profile, as we plan to make it the default profile in a future release. This profile’s purpose is to reproduce the most commonly encountered styles, and it may be more pleasing to the eye than the current default options.

As stated previously, the `break-string-literals` will likely be removed in the next release and the default behavior would be `newlines-and-wrap`.

## Credits

This release also contains many other changes and bug fixes that we cannot detail here.

We would like to thank our maintainers and contributors for this release: Jules Aguillon, Josh Berdine, Hugo Heuzard, Guillaume Petiot and Thomas Refis, and especially our industrial users Jane Street, Ahrefs and Nomadic Labs that made this work possible by funding this project and providing helpful contributions and feedback.

We would be happy to provide support for more customers, please contact us at [contact@tarides.com](mailto:contact@tarides.com)

If you wish to get involved with OCamlFormat development or file an issue, please read the [contributing guide](https://github.com/ocaml-ppx/ocamlformat/blob/master/CONTRIBUTING.md), any contribution is welcomed.

---

<div class="post-metadata">

### Author: ![jbulow](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jbulow/32/644_2.png) [@jbulow](https://discuss.ocaml.org/u/jbulow)
#### Post date: [July 2, 2019, 1:57pm UTC](https://discuss.ocaml.org/t/ann-release-of-ocamlformat-0-10/3988/2 "2019-07-02T13:57:32Z")

</div>

Maybe start the text with telling what OCamlFormat is?
