Code.format_string-exclamation-mark

You're seeing just the function format_string-exclamation-mark, go back to Code module for more information.
Link to this function

format_string!(string, opts \\ [])

View Source (since 1.6.0)

Specs

format_string!(binary(), keyword()) :: iodata()

Formats the given code string.

The formatter receives a string representing Elixir code and returns iodata representing the formatted code according to pre-defined rules.

Options

  • :file - the file which contains the string, used for error reporting

  • :line - the line the string starts, used for error reporting

  • :line_length - the line length to aim for when formatting the document. Defaults to 98. Note this value is used as guideline but there are situations where it is not enforced. See the "Line length" section below for more information

  • :locals_without_parens - a keyword list of name and arity pairs that should be kept without parens whenever possible. The arity may be the atom :*, which implies all arities of that name. The formatter already includes a list of functions and this option augments this list.

  • :force_do_end_blocks (since v1.9.0) - when true, converts all inline usages of do: ..., else: ... and friends into do/end blocks. Defaults to false. Note that this option is convergent: once you set it to true, all keywords will be converted. If you set it to false later on, do/end blocks won't be converted back to keywords.

Design principles

The formatter was designed under three principles.

First, the formatter never changes the semantics of the code by default. This means the input AST and the output AST are equivalent.

The second principle is to provide as little configuration as possible. This eases the formatter adoption by removing contention points while making sure a single style is followed consistently by the community as a whole.

The formatter does not hard code names. The formatter will not behave specially because a function is named defmodule, def, or the like. This principle mirrors Elixir's goal of being an extensible language where developers can extend the language with new constructs as if they were part of the language. When it is absolutely necessary to change behaviour based on the name, this behaviour should be configurable, such as the :locals_without_parens option.

Running the formatter

The formatter attempts to fit the most it can on a single line and introduces line breaks wherever possible when it cannot.

In some cases, this may lead to undesired formatting. Therefore, some code generated by the formatter may not be aesthetically pleasing and may require explicit intervention from the developer. That's why we do not recommend to run the formatter blindly in an existing codebase. Instead you should format and sanity check each formatted file.

For example, the formatter may break a long function definition over multiple clauses:

def my_function(
  %User{name: name, age: age, ...},
  arg1,
  arg2
) do
  ...
end

While the code above is completely valid, you may prefer to match on the struct variables inside the function body in order to keep the definition on a single line:

def my_function(%User{} = user, arg1, arg2) do
  %{name: name, age: age, ...} = user
  ...
end

In some situations, you can use the fact the formatter does not generate elegant code as a hint for refactoring. Take this code:

def board?(board_id, %User{} = user, available_permissions, required_permissions) do
  Tracker.OrganizationMembers.user_in_organization?(user.id, board.organization_id) and
    required_permissions == Enum.to_list(MapSet.intersection(MapSet.new(required_permissions), MapSet.new(available_permissions)))
end

The code above has very long lines and running the formatter is not going to address this issue. In fact, the formatter may make it more obvious that you have complex expressions:

def board?(board_id, %User{} = user, available_permissions, required_permissions) do
  Tracker.OrganizationMembers.user_in_organization?(user.id, board.organization_id) and
    required_permissions ==
      Enum.to_list(
        MapSet.intersection(
          MapSet.new(required_permissions),
          MapSet.new(available_permissions)
        )
      )
end

Take such cases as a suggestion that your code should be refactored:

def board?(board_id, %User{} = user, available_permissions, required_permissions) do
  Tracker.OrganizationMembers.user_in_organization?(user.id, board.organization_id) and
    matching_permissions?(required_permissions, available_permissions)
end

defp matching_permissions?(required_permissions, available_permissions) do
  intersection =
    required_permissions
    |> MapSet.new()
    |> MapSet.intersection(MapSet.new(available_permissions))
    |> Enum.to_list()

  required_permissions == intersection
end

To sum it up: since the formatter cannot change the semantics of your code, sometimes it is necessary to tweak or refactor the code to get optimal formatting. To help better understand how to control the formatter, we describe in the next sections the cases where the formatter keeps the user encoding and how to control multiline expressions.

Line length

Another point about the formatter is that the :line_length configuration is a guideline. In many cases, it is not possible for the formatter to break your code apart, which means it will go over the line length. For example, if you have a long string:

"this is a very long string that will go over the line length"

The formatter doesn't know how to break it apart without changing the code underlying syntax representation, so it is up to you to step in:

"this is a very long string " <>
   "that will go over the line length"

The string concatenation makes the code fit on a single line and also gives more options to the formatter.

This may also appear in do/end blocks, where the do keyword (or ->) may go over the line lenth because there is no opportunity for the formatter to introduce a line break in a readable way. For example, if you do:

case very_long_expression() do

And only the do keyword is above the line length, Elixir will not emit this:

case very_long_expression()
do

So it prefers to not touch the line at all and leave do above the line limit.

Keeping user's formatting

The formatter respects the input format in some cases. Those are listed below:

  • Insignificant digits in numbers are kept as is. The formatter however always inserts underscores for decimal numbers with more than 5 digits and converts hexadecimal digits to uppercase

  • Strings, charlists, atoms and sigils are kept as is. No character is automatically escaped or unescaped. The choice of delimiter is also respected from the input

  • Newlines inside blocks are kept as in the input except for:

    1. expressions that take multiple lines will always have an empty line before and after and 2) empty lines are always squeezed together into a single empty line
  • The choice between :do keyword and do/end blocks is left to the user

  • Lists, tuples, bitstrings, maps, structs and function calls will be broken into multiple lines if they are followed by a newline in the opening bracket and preceded by a new line in the closing bracket

  • Newlines before certain operators (such as the pipeline operators) and before other operators (such as comparison operators)

The behaviours above are not guaranteed. We may remove or add new rules in the future. The goal of documenting them is to provide better understanding on what to expect from the formatter.

Multi-line lists, maps, tuples, and the like

You can force lists, tuples, bitstrings, maps, structs and function calls to have one entry per line by adding a newline after the opening bracket and a new line before the closing bracket lines. For example:

[
  foo,
  bar
]

If there are no newlines around the brackets, then the formatter will try to fit everything on a single line, such that the snippet below

[foo,
 bar]

will be formatted as

[foo, bar]

You can also force function calls and keywords to be rendered on multiple lines by having each entry on its own line:

defstruct name: nil,
          age: 0

The code above will be kept with one keyword entry per line by the formatter. To avoid that, just squash everything into a single line.

Parens and no parens in function calls

Elixir has two syntaxes for function calls. With parens and no parens. By default, Elixir will add parens to all calls except for:

  1. calls that have do/end blocks
  2. local calls without parens where the name and arity of the local call is also listed under :locals_without_parens (except for calls with arity 0, where the compiler always require parens)

The choice of parens and no parens also affects indentation. When a function call with parens doesn't fit on the same line, the formatter introduces a newline around parens and indents the arguments with two spaces:

some_call(
  arg1,
  arg2,
  arg3
)

On the other hand, function calls without parens are always indented by the function call length itself, like this:

some_call arg1,
          arg2,
          arg3

If the last argument is a data structure, such as maps and lists, and the beginning of the data structure fits on the same line as the function call, then no indentation happens, this allows code like this:

Enum.reduce(some_collection, initial_value, fn element, acc ->
  # code
end)

some_function_without_parens %{
  foo: :bar,
  baz: :bat
}

Code comments

The formatter also handles code comments in a way to guarantee a space is always added between the beginning of the comment (#) and the next character.

The formatter also extracts all trailing comments to their previous line. For example, the code below

hello #world

will be rewritten to

# world
hello

Because code comments are handled apart from the code representation (AST), there are some situations where code comments are seen as ambiguous by the code formatter. For example, the comment in the anonymous function below

fn
  arg1 ->
    body1
    # comment

  arg2 ->
    body2
end

and in this one

fn
  arg1 ->
    body1

  # comment
  arg2 ->
    body2
end

are considered equivalent (the nesting is discarded alongside most of user formatting). In such cases, the code formatter will always format to the latter.

Newlines

The formatter converts all newlines in code from \r\n to \n.