rebar3_format

Build StatusHex pm

A rebar plugin for code formatting

Build

$ rebar3 compile

Use

Add the plugin to your rebar config:

{plugins, [rebar3_format]}

Then just call your plugin directly in an existing application:

$ rebar3 format

This will format every Erlang file under /src by default. You can specify the directory/file to format as following:

$ rebar3 format --files src/my_subdir/*.erl
$ rebar3 format --files src/other_subdir/my_file.erl
$ rebar3 format --files test/**/*.erl

To save the formatted files in a different directory you have to pass it as a parameter:

$ rebar3 format --output formatted/

Configuration

The plugin supports the following configuration options in the format section of rebar.config:

Per-File Configuration

You can tweak any of the formatter options for a particular file, using the format attribute in it, like this:

-format(#{paper => 80}).

Test

To test the plugin just run rebar3 test. It will essentially run rebar3 format inside test_app. Add modules with any "tricky" formatting you want to test_app/src, and push them to github including the after results. The after results can be tought as the expected output behaviour.


Proposed Workflow

When we created this tool, we envisioned a workflow for teams where each member can use their preferred style for code formatting. The idea is to take advantage of rebar3 profiles and write the following on your rebar.config file:

%% The canonical format used when pushing code to the central repository
{format, [
{files, ["src/*.erl", "include/*.hrl", "test/*.erl"]},
{formatter, default_formatter},
{options, #{paper => 100}}
]}.
{profiles, [
{brujo, [
{format, [
{files, ["src/*.erl", "include/*.hrl", "test/*.erl"]},
{formatter, rok_formatter}, % I prefer comma-first formatting
{options, #{paper => 100}}
]}
]},
{miriam, [
{format, [
{files, ["src/*.erl", "include/*.hrl", "test/*.erl"]},
{formatter, default_formatter},
{options, #{
inline_clause_bodies => false, % she doesn't like one-liners
inline_items => all % but she does like long lists of items
}}
]}
]}
]}

Then whenever you're about to work on something, follow this ritual:

git checkout master
git checkout -b my-branch
rebar3 as brujo format
# Work on your code...
rebar3 format # This can be a git hook for commits
git commit -am "Apply my changes"
git push origin my-branch --set-upstream

Other developers do the same but using as $THEIR_NAME instead of as brujo.

That way each developer can read code in the way they understand it better, write code exactly how they like to write it, etc. Then push it to the central repository in a consistent way that matches the style of the rest of the project.


Using External Formatters

Through rebar3 format, you can use other formatters that are not included in this repository. That way you can follow our proposed workflow and allow each developer to format the code with their favorite formatter using rebar3 plugins while still maintaining an unique canonical formatter when pushing to your central git repository. You also get -format attribute compliance (including -format ignore.) for free, since they're respected when using any formatter.

Steamroller

If you want to use @old-reliable's steamroller, you just need to add the following things to your rebar.config file:

{plugins, [rebar3_format, steamroller]}.
{format, [
{files, ["src/*.erl", "include/*.hrl"]},
{ignore, ["src/*_ignore.erl", "src/ignored_file_config.erl"]},
{formatter, sr_formatter}, %% The steamroller formatter.
{options, #{line_length => 80}}
]}.

erlfmt

If you want to use @whatsapp's erlfmt, you just need to add the following things to your rebar.config file:

{plugins, [rebar3_format, erlfmt]}.
{format, [
{files, ["src/*.erl", "include/*.hrl"]},
{ignore, ["src/*_ignore.erl", "src/ignored_file_config.erl"]},
{formatter, erlfmt_formatter} %% The erlfmt formatter interface.
]}.

Compatibility Note

erlfmt_formatter is compatible with version v0.1.0 of erlfmt, which is the only one that's currently available at hex.pm. When a new version is published, we'll need to adjust our code since the API for erlfmt will change (it already changed in their master branch).

Implementing your own Formatter

To create a new formatter, you need to implement the rebar3_formatter behaviour. It defines just one callback:

-callback format(file:filename_all(), opts()) -> result().

That means you need to write a function that receives a filename and a map with options (some of them are specified in the rebar3_formatter module, but you can add as many others as you want) and returns a result (either changed or unchanged). It's expected for your formatter to honor the predefined options as described below:

It's a good practice, although not enforced by the formatter itself to respect -format attributes in files as the formatters provided in this repo do. To remove the need for parsing and writing files, you can use the rebar3_ast_formatter module/behaviour as default_formatter and otp_formatter do.

Editor Integration

Visual Studio Code

You can use rebar3_format from Visual Studio Code with the Erlang Formatter extension.

Contribute

To contribute to rebar3_format, please refer to CONTRIBUTING.