Default style

JuliaFormatter has a default style. This page is intended to give a rough overview of how the output of a formatted file looks like when using the default style. Additional examples can be found in JuliaFormatter's codebase itself.

All examples assume indentation of 4 spaces.

Nesting decisions

Where possible JuliaFormatter's default style attempts to keep code on a single line.

With no arguments

Functions, macros, and structs with no arguments are placed on a single line. This also applies to abstract and primitive types:

function  fooendabstract typeAbstractFooend

is formatted to

function foo endabstract type AbstractFoo end

With arguments

Functions calls foo(args...), tuples (args...), arrays [args...], braces {args...}, and type parameter definitions Foo{args...} are placed on a single line. This applies to any code which has opening and closing punctuation: (...), {...}, [...].

Whitespace is inserted after commas, but not for type definitions:

f(a,b,c )Foo{a,b,c }

is formatted to

f(a, b, c)Foo{a,b,c}

Blocks

Blocks and their bodies are spread across multiple lines and properly indented.

Example 1:

begin  a    b; c       endstruct Foo{A, B} a::A  b::Bend

is formatted to

begin    a    b    cendstruct Foo{A,B}    a::A    b::Bend

Binary operators (without nesting)

Binary calls are placed on a single line where possible. Their operands are separated by whitespace, except for : operators (i.e. ranges), and for operators which are inside indexing brackets.

Example 1:

a+ba : a : clist[a + b]
a + ba:b:clist[a+b]

Ternary expressions are placed on a single line and separated by whitespace:

cond1 ?expr1 :     expr2

is formatted to

cond1 ? expr1 : expr2

Comments are aligned with surrounding code blocks.

# commentif a# commentelse# commentend# comment

is formatted to

# commentif a    # commentelse    # commentend# comment

Binary operators (with nesting)

If a binary operation exceeds the margin, they are nested back-to-front:

arg1 + arg2

becomes (with a small margin)

arg1 + arg2

For the ternary operator, as the margin decreases, the : is first moved to the next line, and then the ?:

cond ? e1 : e2

becomes (with a small margin)

cond ? e1 :e2

and with an even smaller margin

cond ? e1 : e2

and with a yet smaller margin

cond ? e1 :e2

If nesting is required for an assignment (i.e., a binary operation with = as the operator), the RHS is placed on the following line and indented.

foo() = body

is formatted to

foo() =    body

All arguments of a function call (applies to any opening/closing punctuation type) are nested if the expression exceeds the margin. The arguments are indented one level.

function longfunctionname_that_is_long(lots, of, args, even, more, args)    bodyend

becomes

function longfunctionname_that_is_long(    lots,     of,     args,    even,     more,     args,)    bodyend

With where operations (A where B), A is nested prior to B.

function f(arg1::A, key1 = val1; key2 = val2) where {A,B,C}    bodyend

becomes

function f(    arg1::A,    key1 = val1;    key2 = val2,) where {A,B,C}    bodyend

and if the margin is shrunk even more,

function f(    arg1::A,    key1 = val1;    key2 = val2,) where {    A,    B,    C,}    bodyend

If a comment is detected inside of an expression, that expression is automatically nested:

var = foo(    a, b, # comment    c,)

becomes

var = foo(    a,    b, # comment    c,)

Unnesting

In certain cases it is desirable to unnest parts of a FST to avoid excessive whitespace. For example, the following

var =    funccall(        arg1,        arg2,        arg3,    )

will be un-nested to

var = funccall(arg1, arg2, arg3)

or

var = funccall(    arg1,    arg2,    arg3,)

Syntax transformations

for in vs. for =

By default if the RHS is a range, e.g. 1:10, then for ... in ... is converted to for ... = .... Otherwise for ... = ... is converted to for ... in .... See this issue for the rationale and further explanation.

This behaviour can be controlled using the always_for_in option. Setting always_for_in=true will always convert = to in even if the RHS is a range. always_for_in=nothing will leave the choice of in vs = up to the user.

Trailing Commas

If the node is iterable, for example a function call or list and is nested, a trailing comma is added to the last argument. The trailing comma is removed if unnested:

func(a, b, c)

becomes

func(    a,    b,    c,)

See this issue for more details.

Trailing Semicolons

If a matrix node is nested, the semicolons are removed.

A = [1 0; 0 1]->A = [    1 0    0 1]

See this issue for more details.

Leading and trailing 0s for float literals

If a float literal is missing a trailing or leading 0, it is added:

a = 1.b = .1

becomes

a = 1.0b = 0.1

For Float32 literals, if there is no decimal point, .0 is added:

a = 1f0->a = 1.0f0

See this issue for more details.

Surround where arguments with curly brackets

If the arguments of a where call are not surrounded by curly brackets, they are added:

foo(x::T) where T = ...

becomes

foo(x::T) where {T} = ...

This can be controlled with the surround_whereop_typeparameters option.

See this issue for more details.

Annotate unannotated type fields with Any

In structs, if a field is unannotated, it is annotated with Any:

struct Foo    fieldend

becomes

struct Foo    field::Anyend

This can be controlled with the annotate_untyped_fields_with_any option.

Move @ in macro calls to the final identifier

@Module.macro

becomes

Module.@macro