This feels like a feature request to me: I understand why sigils are generally not touched by the formatter without plugins, but I feel like the sigil_w included in the standard library should have smarter formatting by default.
NOTE: I'm using Elixir 1.14.2 here to observe the behaviour of the formatter, this may be out-of-date with the mainline branch.
General formatting of sigils
Conceptually, to the compiler, the contents of a sigil is a potentially multi-line string. However, actually using a multiline string does get forced into a format as expected:
@words """
ONE
TWO
THREE
FOUR
FIVE
"""
|> String.split
|> Enum.filter(&String.contains?(&1, "F"))
Elixir literal multiline strings have special semantics for stripping the whitespace on the left, based on the indentation of the closing """. Try increasing and decreasing the indentation of that lexeme and watch how the formatter reacts.
I'd personally intuitively expect the sigil_w case to do the same, but you can see why we cannot apply multiline string semantics to every sigil—the sigil macro, called at compile-time, receives the verbatim contents of the string, extra whitespace and all. Correctly handling that whitespace, including stripping it, is the job of the sigil itself, which may vary depending on the intentions of the sigil developer. (Consider: a custom sigil for parsing the
Whitespace esolang or a python program has different multiline-stripping semantics than literal multiline strings or sigil_w.)
Since the formatter cannot know what whitespace semantics any particular sigil expects, it cannot modify the contents of the string with the knowledge that it will not impact the program, unlike multiline string literals. So it will do absolutely no work on the sigil's contents; leaving your awkward indentation in place. The good news is that if you correct the indentation manually, knowing how this particular sigil handles whitespace, that rewriting will pass formatting and stay unchanged.
Formatting stdlib sigils
~w(
ONE
TWO
THREE
FOUR
FIVE
)
However, I'd really imagine that the stdlib formatter would understand the special whitespace semantics of the stdlib sigil_w and format it out-of-the-box. This is the feature request I see here.
I also think that other stdlib sigil formatting could be improved; for example I feel like
should automatically be formatted to
without any plugins.
Formatting module attributes
> Is there reason why when I pipe the module attribute that it gets intended differently than when I do not pipe it (compare @other with @xs)?
I believe this is an emergent behaviour of whatever order the formatter calculates rules for determining:
- the indentation of the module attribute's argument
- the indentation of the pipeline
- the indentation of the (list) argument to the pipeline
- the indentation of list items within the list
These determinations add up in an unexpected way I do not understand. Essentially, Pipelines want to have their indentation flush with the leftmost character of their argument, so that you get:
|> Enum.map(&(&1 * 2))
|> Enum.reject(&(&1 < 5))
|> length()
[
1,
2,
3
]
|> Enum.map(&(&1 * 2))
|> Enum.reject(&(&1 < 5))
|> length()
Somehow this interacts with how module attributes want to indent things, and we get
@nums [
1,
2,
3
]
|> Enum.map(&(&1 * 2))
|> Enum.reject(&(&1 < 5))
|> length()
This does not seem like a bug per se, but I also personally think that this should format as
@nums [
1,
2,
3
]
|> Enum.map(&(&1 * 2))
|> Enum.reject(&(&1 < 5))
|> length()
This seems like it would be a backwards-compatible enhancement.
Summary
The combination of sigil_w not being internally normalized with sigil_w whitespace semantics, alongside the current behaviour of multi-line expressions in module attributes, leads to this particularly unexpected appearance.
I feel like improvements to both would be welcome in PRs. It may be worth first discussing the impact of releasing changes to the formatter, though. Even semantically backwards-compatible changes have the potential to lead to a lot of syntactic line diff noise and churn when upgrading Elixir, so I'm not certain if there is a more cautious release policy for such things—such as only releasing major formatter changes in minor version bumps.