[Proposal] Exclude files from .formatter.exs

279 views
Skip to first unread message

Ignacio Aguirrezabal

unread,
Apr 26, 2022, 1:33:47 PM4/26/22
to elixir-lang-core
Hello everyone,

Currently, the only way to exclude files from the formatter is to do something like this:

[

   inputs:

     Enum.flat_map(

       ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],

       &Path.wildcard(&1, match_dot: true)

     ) -- Path.wildcard("test/example_app/**/*.*", match_dot: true)
]



So I think it would be nice to have a more convenient way to do it. Maybe something like:
[
  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
  exclude: ["test/example_app/**/*.*"]
]

I have a working implementation in this branch but I didn't want to open a PR before checking this is actually useful: https://github.com/elixir-lang/elixir/compare/main...iaguirre88:formatter-exclude-dir?expand=1

Thanks,
Ignacio

Jon Rowe

unread,
Apr 26, 2022, 4:35:43 PM4/26/22
to Damir
I wanted this feature recently as with the addition of the heex formatter I wanted to format most of an app, but not one file temporarily due to a whitespace wrapping issue (thats getting addressed :)) but still wanted the rest of the app formatted.

So I'm in favour.

Cheers
Jon
--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

Bruce Tate

unread,
Apr 27, 2022, 8:51:22 AM4/27/22
to elixir-l...@googlegroups.com
+1 from me. Providing convenient ways to opt out will only increase formatter adoption. 

-bt



--

Regards,
Bruce Tate
CEO

Andrea Leopardi

unread,
Apr 27, 2022, 9:03:50 AM4/27/22
to elixir-l...@googlegroups.com
Hey Ignacio, thanks for the proposal.

I don't feel too strongly about this, but I think it could be a useful addition.

One note: I think :exclude should rather be exclude_pattern and be a regex. If an expanded filename matches the regex, it gets excluded. I think having a wildcard limits us unnecessarily since we have to expand the inputs wildcard anyways first.

Unless other members of the team are against this feature, a PR would be welcome 😉

Andrea

Ignacio Aguirrezabal

unread,
Apr 27, 2022, 9:06:12 AM4/27/22
to elixir-lang-core
Thanks, Andrea. I'll change it so it uses a regex instead.

Cheers,
Ignacio

José Valim

unread,
Apr 27, 2022, 9:10:40 AM4/27/22
to elixir-lang-core
Thank you for the proposal, however I would prefer to not add this behaviour.

It is definitely possible to do it today and at the same time we don't want to encourage excluding some files, unless absolutely necessary. And for the cases it is absolutely necessary, the current ways suffice. :)

Ignacio Aguirrezabal

unread,
Apr 27, 2022, 9:13:14 AM4/27/22
to elixir-lang-core
Makes sense José <3
Thanks everyone for your input

Andrea Leopardi

unread,
Apr 27, 2022, 10:24:35 AM4/27/22
to elixir-l...@googlegroups.com
Fair enough. If you wanted to use a simpler string/regex match for the original use case, you might want to write something like this:

[
   inputs:
     ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]

     |> Enum.flat_map(&Path.wildcard(&1, match_dot: true)

     |> Enum.reject(&(&1 =~ "test/example_app"))
]

Steve Golton

unread,
Aug 20, 2022, 6:52:59 AM8/20/22
to elixir-lang-core
Hi all,

I've noticed a problem with using the suggested approach for excluding files in .formatter.exs:

E.g.
[

   inputs:
     Enum.flat_map(
       ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
       &Path.wildcard(&1, match_dot: true)
     ) -- Path.wildcard("test/example_app/**/*.*", match_dot: true)
]

Evaluating wildcards in .formatter.exs like this interferes with the way the formatter caches inputs in its manifest file. The first time the formatter runs, it evaluates .formatter.exs and stores the content it in a manifest file, which is used from then-on for each formatter invocation, until the .formatter.exs file is modified, or the manifest file is deleted.
  • When a simple list of wildcards is provided like this inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"], the formatter stores this list of wildcards in its manifest file which are evaluated on each invocation of the formatter. This is good, because it takes into account the current state of the filesystem on every formatter run.
  • When evaluating the wildcards using Path.wildcard() in the .formatter.exs file itself, files are evaulated and unrolled before the formatter gets its hands on it, so the formatter stores this unrolled list of files in its manifest file, and the wildcards are never again evaluated. This is bad, as the list of files to be formatted is "locked in" the first time the formatter is run.
This results in newly created files getting completely ignored by the formatter until the .formatter.exs file is modified, or the manifest file is deleted!

Perhaps there's an easy way around this, but I was bitten by this issue recently, and the exclude feature in this PR would neatly solve this problem IMO. What do you guys think?

Cheers,
Steve
Reply all
Reply to author
Forward
0 new messages