SurfaceFormatter
A code formatter for https://hex.pm/packages/surface.
The complete documentation for SurfaceFormatter is located here.
Installation
Add :surface_formatter as a dependency in mix.exs:
defp deps do [ {:surface_formatter, "~> 0.7.5"} ] end
Formatter Plugin Usage (Elixir 1.13 and later)
Configuration
Modify the following in .formatter.exs:
inputs- add patterns for all Surface filesplugins- addSurface.Formatter.Plugin
# .formatter.exs [ ..., # match all .sface files and all .ex files with ~F sigils inputs: ["lib/**/*.{ex,sface}", ...], plugins: [Surface.Formatter.Plugin] ]
For documentation of other .formatter.exs options, see Surface.Formatter.Plugin.
Usage
(Formats both Elixir and Surface code.)
Mix Task Usage (Elixir 1.12 and earlier)
Configuration
Add surface_inputs to .formatter.exs with patterns for all Surface files:
# .formatter.exs [ ..., # match all .sface files and all .ex files with ~F sigils surface_inputs: ["lib/**/*.{ex,sface}", ...] ]
If your project does not use sface files, you can omit :surface_inputs and
specify file patterns in the standard :inputs field instead. (mix surface.format will fall back to :inputs.) But be warned that including
.sface files in :inputs causes mix format to crash in Elixir 1.12 and
earlier.
For documentation of other .formatter.exs options, see mix surface.format.
Usage
Formatting rules
The formatter mostly follows these rules:
- Only formats code inside of
~F"""blocks and.sfacefiles. - Child nodes are typically indented 2 spaces in from their parent.
- Interpolated Elixir code (inside
{ }brackets) is formatted by the official Elixir formatter. - HTML attributes are put on separate lines if the line is too long.
- Retains "lack of whitespace" such as
<p>No whitespace between text and tags</p>. - Collapses extra newlines down to at most one blank line.
See Surface.Formatter.format_string!/2 for further documentation.
Example at a glance
Out of the box, Surface code that looks like this:
<RootComponent with_many_attributes={ true } causing_this_line_to_wrap={ true} because_it_is_too_long={ "yes, this line is long enough to wrap" }> <!-- HTML public comment (hits the browser) --> {!-- Surface private comment (does not hit the browser) --} <div :if={ @show_div } class="container"> <p> Text inside paragraph </p> <span>Text touching parent tags</span> </div> <Child items={[%{name: "Option 1", key: 1}, %{name: "Option 2", key: 2}, %{name: "Option 3", key: 3}, %{name: "Option 4", key: 4}]}> Default slot contents </Child> </RootComponent>
will be formatted like this:
<RootComponent with_many_attributes causing_this_line_to_wrap because_it_is_too_long="yes, this line is long enough to wrap" > <!-- HTML public comment (hits the browser) --> {!-- Surface private comment (does not hit the browser) --} <div :if={@show_div} class="container"> <p> Text inside paragraph </p> <span>Text touching parent tags</span> </div> <Child items={[ %{name: "Option 1", key: 1}, %{name: "Option 2", key: 2}, %{name: "Option 3", key: 3}, %{name: "Option 4", key: 4} ]}> Default slot contents </Child> </RootComponent>