Efmt - Erlang code formatter

Hi all,

Let me share about a new Erlang code formatter efmt that just released v0.1.0.

Features

  • Opinionated: only maximum line length is configurable by users
  • Emacs Erlang Mode friendly indentation
  • Preserves non-whitespace tokens of the original text as-is
    • Ensures the code after formatting keeps the same semantic meaning
  • Provides a rebar3 plugin: rebar3_efmt
  • Thorough macro support

Example

The original code:

-module(example).
-export(
  [fac/1]
).

fac(1) -> 1; fac(N) -> N*fac(N-1).

After running $ efmt example.erl:

-module(example).
-export([fac/1]).

fac(1) ->
    1;
fac(N) ->
    N * fac(N - 1).

If you are interested, please see the README.md and give it a try.

11 Likes

I skimmed the README and it’s “diff” output seems weird. Is there a way to get unified diff which one could use as patchfiles?

2 Likes

Thank you for taking a look.

Currently, there is no direct way to show the output using a unified diff style.
As a workaround, if you are in a git repo directory, the following commands can show that.

$ git commit -am'save'

// Formats files in place.
$ efmt -w

// Show the diff by using `git`.
$ git diff

BTW, I created efmt#6 to track this issue. Thanks for your feedback!

4 Likes

Good job! The output format is pretty nice. The problem I’ve had with all available erlang formatters I’ve seen so far is that they seem to place more focus on making the code uniform than on making it nice to read. At first glance it looks like efmt comes close to my personal style.

(Though I have to admit I like the unformatted version in Differences with other Erlang formatters the best…)

4 Likes

Thanks! I’m very glad to hear that!

Though I have to admit …

Oh, the formatted code in the section is intendedly ugly. The maximum line length option is set to an unrealistically small value (i.e, --print-width=30) to show the differences between efmt and erlfmt in the cases where many line-wrappings should happen.

I’m going to add a note about the above point to README.md later.

4 Likes

BTW, I tried applying the formatter to jsone library by jsone#71. So you can see a real diff that efmt generated there.

2 Likes

I’d consider this change a bug in the formatter.

Since macros in Erlang are pure string replacement surrounding white space can be significant.

2 Likes

Thank you for your comment.
Indeed, the result ( ?CAPTURE_STACKTRACE->) is a point that should be improved in the future version.
However, as far as the semantic meaning of the code is concerned, I think the current result is okay. This is because, AFAIK, Erlang macros are processed token-level (not string-level), and it’s impossible to make a new token by macro expansions (c.f. The BEAM book – 2.3.1. Compiler Pass: The Erlang Preprocessor (epp).

4 Likes

You are right. I was thinking of some case like

-define(OP, andalso).

f() -> true?OP false.

But that expands correctly on the token level, of course. Never mind. :grinning_face_with_smiling_eyes:

3 Likes