AdRoll/rebar3_format

Allow for non-formatted code sections

paulo-ferraz-oliveira opened this issue · 9 comments

Currently, default_formatter formats this code…

    ["POST", $\n,
     "/", $\n,
     "", $\n,
     "x-amz-content-sha256:", Hash, $\n,
     "x-amz-date:", Date, $\n, $\n,
     "x-amz-content-sha256;x-amz-date", $\n,

…like this…

    ["POST",
     $\n,
     "/",
     $\n,
     "",
     $\n,
     "x-amz-content-sha256:",
     Hash,
     $\n,
     "x-amz-date:",
     Date,
     $\n,
     $\n,
     "x-amz-content-sha256;x-amz-date",
     $\n,

I would like it to not be formatted, e.g. via a "noformat" section, e.g.

%% @noformat=true
    ["POST", $\n,
     "/", $\n,
     "", $\n,
     "x-amz-content-sha256:", Hash, $\n,
     "x-amz-date:", Date, $\n, $\n,
     "x-amz-content-sha256;x-amz-date", $\n,
%% @noformat=false

Nice idea, but I will likely be more akin to…

-format begin_ignore.
…
-format end_ignore.

…or some other attribute-based solution like…

-format_block #{inline_items => false}.
…
-format_block_end.

That will give you some control, but it will always be top-level: you won't be able to determine specifically how to format a group of expressions within a function. You'll have to specify it for the whole function at once.
Hopefully, that's still reasonable for you.

It is absolutely reasonable. Code like this doesn't tend to appear often, so it's easily segregated, for me. Thanks.

I just figured out why we can't do this.
In Erlang… you can't insert custom attributes after the first function declaration.
That would mean we need to rely on comments and that opens up a whole other can of worms.
I wonder if the OTP team will ever be willing to allow custom attributes between functions? 🤔

I wonder if the OTP team will ever be willing to allow custom attributes between functions? 🤔

Well, one of the things I miss from the ol'IDE days was the ability to hide code sections.

So I'd have

-code_section("Public API").
...
-end_code_section.

-code_section("Private API").
...
-end_code_section.

And it'd be possible to expand/collapse them (I'm not sure there's a standard for this, though, I think I used it in Visual Studio). If attributes were allowed, this'd be allowed, but also other stuff (like e.g. having the export next to the function itself - I know having it in the header is sometimes good because you have a sense of what's exported, but with tools you can get that information anyway). Just shooting here, no concrete stuff was actually thoroughly thought about

Want to create an issue next to erlang/otp?

I think I'll first ask around in Slack…

FWIW in erlfmt we support supressing the formatting for an entire form with a preceding %% @erlfmt-ignore comment. Doing it per-form is significantly simpler than supporting arbitrary ranges - in particular because the range can contain partial expressions.

Attributes for things like that are problematic since their use in headers is, at best, ambiguous, and in files like rebar.config impossible

Yeah. Our goal is the same.
I prefer attributes to comments just because comments can be introduced… basically… everywhere. With attributes is clear that you can't put that thing within a form.

And I'm aware of the problems you mention regarding attributes. In my mind, I would like to do the same we did with -format …: We first use attributes, and then we might allow comments as a fallback for when attributes don't work.

On this topic: erlang/otp#5689

💡 Ideas from Slack convo with @hauleth and @plux 💡

  1. Before erlang/otp#5689, we can add stuff like…
-format #{ignore => [this_function/1, this_function/2, this_function_with_any_arity, this_attribute, …], …}.
  1. Furthermore, we can provide specific per-function configuration…
-format #{specifics =>
    #{this_function/1 => #{inline_items => none},
      this_attribute => #{inline_items => all},
      …},
    …}.
  1. When erlang/otp#5689 is merged, we can skip the closing part of the section formatting by using something like…
-format_next #{…}.
the(Thing, That, Is, Formatted, With, The, Previous, Options) ->this_one(Is, Not, Affected) ->