Scalafmt

Scalafmt

  • Docs
  • GitHub

›Documentation

Documentation

  • Installation
  • Configuration
  • Gotchas
  • FAQ / Troubleshooting
  • Known Issues
  • Changelog

Contributing

  • Contributing
  • Contributing to the website
Edit

Configuration

If you have very specific preferences for configuring your formatting, please make sure you have read this entire document, and identified every single parameter available, along with their interactions.

Many parameters do not have ultimate authority and might be overridden by (possibly, default) values of other parameters.

Configuration for scalafmt is defined in a plain text file .scalafmt.conf using HOCON syntax.

Here is an example .scalafmt.conf:

version = 3.9.6    // mandatory
runner.dialect = scala213    // mandatory, see below for available dialects

// here are some examples of optional settings
align.preset = more    // For pretty alignment.
maxColumn = 1234

🚧 Before using specific configuration make sure that your project agrees on the standards. Settings such as maxColumn could be a source of issues if different tools such as an IDE uses a different default value.

Most popular

maxColumn

Default: maxColumn = 80

  • Keep in mind that 80 characters fit perfectly on a split laptop screen with regular resolution.
  • GitHub mobile view only shows 80 characters and sometimes you might review code on your phone.
  • Consider refactoring your code before choosing a value above 100.

assumeStandardLibraryStripMargin

This parameter simply says the .stripMargin method was not redefined by the user to assign special meaning to indentation preceding the | character. Hence, that indentation can be modified.

# Defaults
assumeStandardLibraryStripMargin = false
align.stripMargin = true

If true, lines starting with the margin character | (or another if specified in the .stripMargin(...) call) will be indented differently.

If align.stripMargin is true, they will align with the opening triple-quote """ in interpolated and raw string literals. Otherwise, they will be indented relative to the start of the opening line.

val example1 =
  s"""Examples:
     |  * one
     |  * two
     |  * $three
     |""".stripMargin
val example1 =
  s"""Examples:
  |  * one
  |  * two
  |  * $three
  |""".stripMargin

Config for this example:

assumeStandardLibraryStripMargin = true
align.stripMargin = true

val example1 =
  s"""|Examples:
    |  * one
    |  * two
    |  * $three
    |""".stripMargin
val example1 =
  s"""|Examples:
      |  * one
      |  * two
      |  * $three
      |""".stripMargin

Config for this example:

assumeStandardLibraryStripMargin = true
align.stripMargin = false

The pipe character can immediately follow the opening """

val example2 =
  s"""|Examples:
      |  * one
      |  * two
      |  * $three
      |""".stripMargin
val example2 =
  s"""|Examples:
  |  * one
  |  * two
  |  * $three
  |""".stripMargin

Config for this example:

assumeStandardLibraryStripMargin = true
align.stripMargin = true

Version

The version parameter specifies the release of the formatter to be used. If the version requested is different from the version of the installed formatter, the correct release will be downloaded dynamically.

Since v3.1.0, the version parameter is required to be specified explicitly.

Since that requires access to artifact repositories, please see more on that on the Installation page.

Scala Dialects

The formatter supports various dialects defined and supported by scalameta parser. However, for any given file, one and only one dialect is supported, and runner.dialect must be used to select it.

Since v3.1.0, the runner.dialect parameter is required to be specified explicitly.

Available dialects are:

  • Scala 2
    • scala211
    • scala212
    • scala212source3
    • scala213
    • scala213source3
  • Scala 3
    • scala3: most recent release
    • Scala3Future: scala3 plus experimental, unreleased features
    • specific versions from Scala30 to Scala36
  • sbt-specific
    • sbt0137
    • sbt1

You can also specify runner.dialect for a subset of files using fileOverride:

fileOverride {
  "glob:**/scala3-subproject/src/main/scala/**" {
    runner.dialect = scala3
  }
}

runner.dialectOverride

Since v3.6.0

Using this section, you can explicitly set scalameta Dialect fields (directly or via their associated withXxxYyy methods).

// top-level def: unsupported by scala213
def foo = // significant indent: unsupported by scala213
  bar
  baz
end foo // end marker: unsupported by scala213
// top-level def: unsupported by scala213
def foo = // significant indent: unsupported by scala213
  bar
  baz
end foo // end marker: unsupported by scala213

Config for this example:

runner.dialect = scala213
runner.dialectOverride.withAllowToplevelTerms = true
runner.dialectOverride.withAllowEndMarker = true
runner.dialectOverride.allowSignificantIndentation = true

Scala 3

Since v3.0.0, scalafmt supports Scala 3 features that can be enabled by changing the dialect of the scalameta parser.

runner.dialect = scala3
---
open class MyOpenClass()
val myQuote = '{ expr }
val mySplice = ${ expr }
enum class Weekday {
  case Monday, Tuesday, Wednesday, Thursday, Friday
}

Please also see rewrite rules for Scala 3.

Scala 2 with -Xsource:3

Also since v3.0.0, if using -Xsource:3 option for Scala 2 compiler, you can change the dialect to Scala213Source3, which will allow to format some of the new syntax backported from Scala 3.

Presets

Some sections provide preset values to set multiple parameters at once. These are always accessed via the preset key of the appropriate section, including top-level.

Top-level presets

preset=default

This preset is implicit and sets all values to their defaults.

preset=IntelliJ

This preset is defined as

    preset = default
    indent.defnSite = 2
    optIn.configStyleArguments = false

preset=defaultWithAlign

This preset is defined as

    preset = default
    align.preset = more

preset=Scala.js

This preset intends to approximate the style used for scala.js.

It uses modified detection of config-style formatting:

  • according to Sébastien Doeraene, config-style should be driven solely by presence of a dangling closing parenthesis
  • to achieve that, use a combination of danglingParentheses.xxxSite = false and newlines.configStyle.xxxSite.prefer = true

The preset itself is defined as:

    preset = default
    binPack.preset = true
    align {
      openParenCtrlSite = false
      arrowEnumeratorGenerator = false
      tokens = [ caseArrow ]
    }
    danglingParentheses {
      callSite = false
      defnSite = false
    }
    docstrings.style = Asterisk
    indent.callSite = 4
    newlines {
      avoidInResultType = true
      neverBeforeJsNative = true
      sometimesBeforeColonInMethodReturnType = false
    }
    runner.optimizer {
      callSite {
        minSpan = 500
        minCount = 5
      }
      defnSite {
        minSpan = 500
        minCount = 5
      }
    }

Appending to preset collections

If, instead of redefining the default or preset value of a list or a map parameter, you'd like to append to it, use the following syntax:

// set
a.b.c.list = [ ... ]
a.b.c.dict = { ... }

// append; "+" must be the only key
a.b.c.list."+" = [ ... ]
a.b.c.dict."+" = { ... }

Indentation

indent.main

Since v3.0.0.

This parameter controls the primary code indentation. Various context-specific overrides are defined below, within this section.

Default: indent.main = 2

indent.significant

Since v3.0.0.

This parameter controls the amount of significant indentation used when optional braces rules apply.

By default, equals to indent.main.

object a {
  if (foo)
    bar
  else
    baz

  if foo then
     bar
     bar
  else
     baz
     baz
}
object a {
  if (foo)
    bar
  else
    baz

  if foo then
    bar
    bar
  else
    baz
    baz
}

Config for this example:

runner.dialect = scala3
indent.main = 2
indent.significant = 3

indent.callSite

This parameter controls indentation of method call arguments.

Default: indent.callSite = 2

Example:

function(
  argument1, // indented by 2
  ""
)
function(
argument1, // indented by 2
""
)

Config for this example:

indent.callSite = 2

indent.binPackCallSite

This parameter controls indentation of method call arguments when they are binpacked (that is, spanning multiple lines but not formatted using config style). Defaults to indent.callSite.

Since v3.8.3.

Example:

func(1, // next indented by 4
    "")
func( // next indented by 2
    1, "")
func(1, // next indented by 4
  "")
func( // next indented by 2
    1,
    "")

Config for this example:

newlines.configStyle.callSite.prefer = false
danglingParentheses.callSite = false
binPack.callSite = always
indent.callSite = 2
indent.binPackCallSite = 4

indent.ctrlSite

This parameter controls indentation within control expressions (if/while/etc). If not set, the value of indent.callSite applies.

Since v3.0.0.

if (
    foo && // indented by 4
    bar
) {
  baz
}
if (
 foo && // indented by 4
 bar
) {
  baz
}

Config for this example:

indent.callSite = 2
indent.ctrlSite = 4

if (
  foo && // indented by 2
  bar
) {
  baz
}
if (
 foo && // indented by 2
 bar
) {
  baz
}

Config for this example:

indent.callSite = 2

indent.defnSite

Default: indent.defnSite = 4

Same as indent.callSite except for definition site. Example:

def function(
    parameter1: Type1 // indented by 4
): ReturnType
def function(
parameter1: Type1 // indented by 4
): ReturnType

Config for this example:

indent.defnSite = 4

indent.binPackDefnSite

This parameter controls indentation of method parameters when they are binpacked (that is, spanning multiple lines but not formatted using config style). Defaults to indent.defnSite.

Since v3.8.3.

Example:

def func(a: Int, // next indented by 4
    b: String)
def func( // next indented by 2
    a: Int, b: String)
def func(a: Int, // next indented by 4
  b: String)
def func( // next indented by 2
    a: Int,
    b: String)

Config for this example:

newlines.configStyle.defnSite.prefer = false
danglingParentheses.defnSite = false
binPack.defnSite = always
indent.defnSite = 2
indent.binPackDefnSite = 4

indent.ctorSite

Since v2.5.0.

Applies to constructors. Defaults to indent.defnSite.

class A(
    field1: Type1 // indented by 4
) {
  def function2(
    parameter1: Type1 // indented by 2
  ): ReturnType = None
}
class A(
 field1: Type1 // indented by 4
) {
 def function2(
  parameter1: Type1 // indented by 2
 ): ReturnType = None
}

Config for this example:

indent.ctorSite = 4
indent.defnSite = 2

indent.matchSite

Since v3.4.4.

If set, applies custom indentation to case clauses in match expressions.

Default: indent.matchSite = null

object a:
  x match
  case _: Aaaaaa |
      _: Bbbbbb |
      _: Cccccc =>
  end match
object a:
  x match
    case _: Aaaaaa |
      _: Bbbbbb |
      _: Cccccc =>
  end match

Config for this example:

maxColumn = 20
indent.matchSite = 0
runner.dialect = scala3

indent.caseSite

Since v3.0.0.

Applies indentation to patterns in case clauses.

Default: indent.caseSite = 4

x match {
  case _: Aaaaaa |
       _: Bbbbbb |
       _: Cccccc =>
}
x match {
  case _: Aaaaaa |
      _: Bbbbbb |
      _: Cccccc =>
}

Config for this example:

maxColumn = 20
indent.caseSite = 5

indent.extendSite

Default: indent.extendSite = 4

This parameter defines indentation used for the extends A with B or derives A, B sequences in a template (class, trait, object, enum, etc.).

trait Foo
    extends A {
  def foo: Boolean =
    true
}
trait Foo extends A {
  def foo: Boolean = true
}

Config for this example:

indent.extendSite = 4
maxColumn = 20

indent.withSiteRelativeToExtends

Since v2.5.0.

This parameter defines additional indentation used for the with elements of an extends A with B sequence in a template.

Default: indent.withSiteRelativeToExtends = 0

trait Foo
    extends A
      with B
      with C
      with D
      with E {
  def foo: Boolean = true
}
trait Foo extends A with B with C with D with E {
  def foo: Boolean = true
}

Config for this example:

indent.extendSite = 4
indent.withSiteRelativeToExtends = 2
maxColumn = 30

indent.commaSiteRelativeToExtends

Since v3.0.0

This parameter defines additional indentation used for the post-comma elements of an extends A, B or derives A, B sequences of a template.

Added to support Scala 3, which allows to specify multiple parents with a comma.

Default: indent.commaSiteRelativeToExtends = 2

trait Foo
    extends A,
        B,
        C,
        D,
        E {
  def foo: Boolean =
    true
}
trait Foo extends A, B, C, D, E {
  def foo: Boolean = true
}

Config for this example:

runner.dialect = scala3
indent.extendSite = 4
indent.commaSiteRelativeToExtends = 4
maxColumn = 20

indent.extraBeforeOpenParenDefnSite

Since v3.0.0

This parameter applies to definitions and sets extra indentation (relative to the indentation of the body) used for parameter groups when

  • the definition has a body (that needs differentiating from)
  • newlines.beforeOpenParenDefnSite is set

Default: indent.extraBeforeOpenParenDefnSite = 0

case class fooClass
  (foo1: String)
  (
      foo2: String,
      foo3: String
  )(foo5: String)
abstract class fooClass
  (foo1: String)
  (
      foo2: String,
      foo3: String
  )(foo5: String) {
  def fooDef
    (foo1: String)
    (
        foo2: String,
        foo3: String
    )(foo5: String)
}
def fooDef(foo1: String)
  (
      foo2: String,
      foo3: String
  )(foo5: String) = {
  // body
}
case class fooClass
  (foo1: String)
  (foo2: String, foo3: String)
  (foo5: String)
abstract class fooClass
  (foo1: String)
  (foo2: String, foo3: String)
  (foo5: String) {
  def fooDef
    (foo1: String)
    (foo2: String, foo3: String)
    (foo5: String)
}
def fooDef
  (foo1: String)
  (foo2: String, foo3: String)
  (foo5: String) = {
  // body
}

Config for this example:

maxColumn = 25
newlines.beforeOpenParenDefnSite = fold

case class fooClass
  (foo1: String)
  (
      foo2: String,
      foo3: String
  )(foo5: String)
abstract class fooClass
    (foo1: String)
    (
        foo2: String,
        foo3: String
    )(foo5: String) {
  def fooDef
    (foo1: String)
    (
        foo2: String,
        foo3: String
    )(foo5: String)
}
def fooDef(foo1: String)
    (
        foo2: String,
        foo3: String
    )(foo5: String) = {
  // body
}
case class fooClass
  (foo1: String)
  (foo2: String, foo3: String)
  (foo5: String)
abstract class fooClass
  (foo1: String)
  (foo2: String, foo3: String)
  (foo5: String) {
  def fooDef
    (foo1: String)
    (foo2: String, foo3: String)
    (foo5: String)
}
def fooDef
  (foo1: String)
  (foo2: String, foo3: String)
  (foo5: String) = {
  // body
}

Config for this example:

maxColumn = 25
indent.extraBeforeOpenParenDefnSite = 2
newlines.beforeOpenParenDefnSite = fold

case class fooClass
  (foo1: String)
  (
      foo2: String,
      foo3: String
  )(foo5: String)
abstract class fooClass
 (foo1: String)
 (
     foo2: String,
     foo3: String
 )(foo5: String) {
  def fooDef
    (foo1: String)
    (
        foo2: String,
        foo3: String
    )(foo5: String)
}
def fooDef(foo1: String)
 (
     foo2: String,
     foo3: String
 )(foo5: String) = {
  // body
}
case class fooClass
  (foo1: String)
  (foo2: String, foo3: String)
  (foo5: String)
abstract class fooClass
  (foo1: String)
  (foo2: String, foo3: String)
  (foo5: String) {
  def fooDef
    (foo1: String)
    (foo2: String, foo3: String)
    (foo5: String)
}
def fooDef
  (foo1: String)
  (foo2: String, foo3: String)
  (foo5: String) = {
  // body
}

Config for this example:

maxColumn = 25
indent.extraBeforeOpenParenDefnSite = -1
newlines.beforeOpenParenDefnSite = fold

indent.relativeToLhsLastLine

When the left-hand side of an infix or match expression is itself broken over several lines, with the last line indented relative to the first line, this flag determines whether the indent is relative to the first or the last line.

This parameter takes a list of values including:

  • match: applies to match expressions
  • infix: applies to infix expressions

Default: indent.relativeToLhsLastLine = []

foo // c1
  .bar match {
  case baz => qux
}
foo // c1
  .bar infix { case baz =>
  qux
}
foo // c1
  .bar match {
    case baz => qux
  }
foo // c1
  .bar infix {
    case baz => qux
  }

Config for this example:

indent.relativeToLhsLastLine = []

foo // c1
  .bar match {
    case baz => qux
  }
foo // c1
  .bar infix { case baz =>
    qux
  }
foo // c1
  .bar match {
  case baz => qux
}
foo // c1
  .bar infix {
  case baz => qux
}

Config for this example:

indent.relativeToLhsLastLine = [match, infix]

indent.fewerBraces

This parameter controls whether extra indent.main is added to the sole argument of a method call using the "fewer braces" syntax. The following values are supported:

  • always: always applies extra indent
  • never: doesn't apply any extra indent
  • beforeSelect: applies extra indent only to fewer-braces expressions followed by a .select

Default: indent.fewerBraces = "never"

In Scala 3.3.0, only never provides compiler-compatible code. Other options will work in 3.3.1-RC1 and later (see Parser section). Also, never is implicitly forced if indentation width is less than 2.

bar:
     2 + 2

foo.bar:
     2 + 2

foo:
     2 + 2
  .bar:
     3 + 3
  .baz // c
  .qux
bar:
  2 + 2

foo.bar:
  2 + 2

foo:
  2 + 2
.bar:
  3 + 3
.baz // c
.qux

Config for this example:

runner.dialect = Scala3
indent.significant = 3
indent.fewerBraces = always

bar:
   2 + 2

foo.bar:
   2 + 2

foo:
   2 + 2
.bar:
   3 + 3
.baz // c
  .qux
bar:
  2 + 2

foo.bar:
  2 + 2

foo:
  2 + 2
.bar:
  3 + 3
.baz // c
.qux

Config for this example:

runner.dialect = Scala3
indent.significant = 3
indent.fewerBraces = never

bar:
   2 + 2

foo.bar:
   2 + 2

foo:
     2 + 2
  .bar:
     3 + 3
  .baz // c
  .qux
bar:
  2 + 2

foo.bar:
  2 + 2

foo:
  2 + 2
.bar:
  3 + 3
.baz // c
.qux

Config for this example:

runner.dialect = Scala3
indent.significant = 3
indent.fewerBraces = beforeSelect

indent.afterInfixSite

This parameter controls indentation after an infix operator (not including assignments). Defaults to indent.main.

Since v3.8.3.

Indent for binPack.callSite

Normally, even when binpacking, there's a new level of indentation added for each opening parenthesis starting a nested argument clause (regardless whether the first argument follows the opening parenthesis on the same line or on a separate one); the parameters below modify this behaviour.

See also indent.binPackCallSite.

binPack.indentCallSiteOnce

When this parameter is enabled, only one level is added to the outermost call, regardless of the number of nested parentheses.

Default: binPack.indentCallSiteOnce = false

With the parameter enabled:

foo(bar1(baz1(qux1,
  qux2), baz2),
  bar2(baz3, baz4))
foo(bar1(baz1(qux1, qux2), baz2), bar2(baz3, baz4))

Config for this example:

binPack.callSite = true
binPack.indentCallSiteOnce = true
indent.callSite = 2
maxColumn = 20

With the parameter disabled:

foo(bar1(baz1(qux1,
      qux2), baz2),
  bar2(baz3, baz4))
foo(bar1(baz1(qux1, qux2), baz2), bar2(baz3, baz4))

Config for this example:

binPack.callSite = true
binPack.indentCallSiteOnce = false
indent.callSite = 2
maxColumn = 20

binPack.indentCallSiteSingleArg

When this parameter is disabled, no indentation is added for same-line single-arg cases; the assumption is that if the argument expression spans multiple lines, it will introduce its own indentation.

Default: binPack.indentCallSiteSingleArg = true

With the parameter enabled:

foo(bar(baz.qux(
      xyz + zyx
    )))
foo(
  bar((_, _) =>
    baz { qux =>
      noop
    } baz { qux =>
      noop
    } baz //
      { qux =>
        noop
      } baz { qux =>
        noop
      }
  )
)
foo(bar(baz.qux(xyz + zyx)))
foo(bar((_, _) =>
  baz { qux =>
    noop
  } baz { qux =>
    noop
  } baz //
    { qux =>
      noop
    } baz { qux =>
      noop
    }))

Config for this example:

binPack.callSite = true
binPack.indentCallSiteSingleArg = true
indent.callSite = 2
maxColumn = 20

With the parameter disabled:

foo(bar(
  baz.qux(xyz + zyx)
))
foo(
  bar((_, _) =>
    baz { qux =>
      noop
    } baz { qux =>
      noop
    } baz //
      { qux =>
        noop
      } baz { qux =>
        noop
      }
  )
)
foo(bar(baz.qux(xyz + zyx)))
foo(bar((_, _) =>
  baz { qux =>
    noop
  } baz { qux =>
    noop
  } baz //
    { qux =>
      noop
    } baz { qux =>
      noop
    }))

Config for this example:

binPack.callSite = true
binPack.indentCallSiteSingleArg = false
indent.callSite = 2
maxColumn = 20

indent.infix

Prior to v3.8.4, this section was called indentOperator.

Normally, the first eligible break inside a chain of infix operators is indented by 2.

This group of parameters allows overriding which infix operators, and in which context, are eligible to be exempted from this, with indentation omitted.

If you wish to disable this functionality, set indent.infix.excludeRegex = '^$'.

indent.infix.exemptScope

Added in 3.4.0, this parameter determines when an infix operator can be exempted from applying continuation indentation.

It accepts the following values, to determine the context in which infix operators are eligible to be exempted from the default indentation rule:

  • oldTopLevel (default): "top-level" infix operators
    • the definition of top-level historically refers to infix expressions whose direct parent is a block (typically as the last statement in that block), if/while (as condition or body), or case clause (as pattern or body)
    • this value replaced deprecated indentOperator.topLevelOnly=true
    • this approach is also somewhat inconsistent with what it was intended to accomplish, and kept only for backwards compatibility; please consider using one of the alternatives
  • aloneEnclosed: infix operators which are enclosed in braces or parens as the only statement in a block or body of a braces-enclosed lambda function; an if/while condition; the only argument of a method call; or similar;
    • it also includes a few scenarios where parens can be omitted, such case clause patterns, conditions in new scala3 if-then and while-do syntax, etc.
    • however, block braces are not optional
  • aloneArgOrBody: infix operators as an if/while condition; an argument of a method call; the only statement in a block; entire body of an assignment, case clause, control statement, etc;
    • it is intended to help implement a requirement of the scala-js coding style.
  • all: all infix operators
    • this value replaced deprecated indentOperator.topLevelOnly=false
  • notAssign (since v3.8.4): any non-assignment operator
    • this value expanded upon deprecated verticalAlignMultilineOperators which now simply maps to { exemptScope = notAssign, excludeRegex = ".*" }
  • notWithinAssign (since v3.8.4): any infix not part of a larger assignment expression
function(
  a &&
    b,
  a &&
    b
)
function(
  a &&
    b
)(
  a &&
    b
)
function(
  a &&
    b
)(
  a &&
    b
)
function {
  a &&
  b
}
function(
  a &&
    b,
  a &&
    b
)
function(a &&
    b)(a &&
    b)
function(
  a &&
    b
)(
  a &&
    b
)
function {
  a &&
    b
}

Config for this example:

indent.infix.exemptScope = oldTopLevel

function(
  a &&
  b,
  a &&
  b
)
function(
  a &&
  b
)(
  a &&
  b
)
function(
  a &&
  b
)(
  a &&
  b
)
function {
  a &&
  b
}
function(
  a &&
    b,
  a &&
    b
)
function(a &&
    b)(a &&
    b)
function(
  a &&
    b
)(
  a &&
    b
)
function {
  a &&
    b
}

Config for this example:

indent.infix.exemptScope = all

function(
  a &&
    b,
  a &&
    b
)
function(
  a &&
  b
)(
  a &&
  b
)
function(
  a &&
  b
)(
  a &&
  b
)
function {
  a &&
  b
}
function(
  a &&
    b,
  a &&
    b
)
function(a &&
    b)(a &&
    b)
function(
  a &&
    b
)(
  a &&
    b
)
function {
  a &&
    b
}

Config for this example:

indent.infix.exemptScope = aloneEnclosed

function(
  a &&
  b,
  a &&
  b
)
function(
  a &&
  b
)(
  a &&
  b
)
function(
  a &&
  b
)(
  a &&
  b
)
function {
  a &&
  b
}
function(
  a &&
    b,
  a &&
    b
)
function(a &&
    b)(a &&
    b)
function(
  a &&
    b
)(
  a &&
    b
)
function {
  a &&
    b
}

Config for this example:

indent.infix.exemptScope = aloneArgOrBody

indent.infix.excludeRegex

Defines a regular expression for excluded infix operators. If an eligible operator matches, it will not be indented.

In v3.1.0, this parameter was renamed from indentOperator.exclude.

Default: indent.infix.excludeRegex = "^(&&|\\|\\|)$"

indent.infix.includeRegex

Defines a regular expression for included infix operators. If an eligible operator matches and is not excluded explicitly by indent.infix.excludeRegex, it be will indented.

In v3.1.0, due to conflict with built-in HOCON keyword, this parameter was renamed from indentOperator.include.

Default: indent.infix.includeRegex = ".*"

indent.infix.preset

  • default
    • use defaults for all fields
  • spray (also akka)
    • set indent.infix.excludeRegex = "^$" and indent.infix.includeRegex = "^.*=$"

Alignment

Alignment describes formatting which inserts additional spaces to align certain tokens on different lines vertically.

Apart from a few special cases, the way alignment works is as follows:

  • for each line, alignment stops are identified, by looking up each token in align.tokens (matching token, owner and, if specified, the owner's parent)
  • for two candidate lines, respective alignment stops are compared (first stop on one line to the first one on the other, etc); the only exception are the single-line comments which are compared regardless of their stop position
  • two tokens will match if:
    • both tokens have the same token category; a token's category is the value associated with its type in align.tokenCategory mapping or, if missing, its type
    • both owners have the same tree category; similarly, a tree's category is the value for its type in align.treeCategory mapping or the type itself
    • both owners belong to the same "statement container"; this is determined internally and usually selects the nearest containing block, template, match, argument or parameter group.
  • for each token that has matches in the surrounding lines:
    • we'll determine the amount of extra space needed to be added before that token, to align it on the right with matching tokens
    • however, if there was no space before the token, and align.delayUntilSpace is set, that extra space will be added to the next space on its line, thus aligning subsequent token on the left.

Align has several nested fields, which you can customize. However, it comes with four possible presets: none, some, more, & most.

align.preset

Default: some

align.preset=none

x match { // false for case arrows
  case 2 => 22 // also comments!
  case 22 => 222 // don't align me!
}
x match { // false for case arrows
  case 2  => 22 // also comments!
  case 22 => 222 // don't align me!
}

Config for this example:

align.preset = none

Pro tip: Enable this setting to minimize git diffs/conflicts from renamings and other refactorings, without having to ignore whitespace changes in diffs or use --ignore-all-space to avoid conflicts when git merging or rebasing.

Starting with the introduction of align.stripMargin parameter in v2.5.0, one must explicitly enable it to get earlier behaviour of align.preset=none. See assumeStandardLibraryStripMargin.

align.preset=some

x match { // true for case arrows
  case 2  => 22
  case 22 => 222
}

val x = 2 // false for assignment
val xx = 22

case object B
    extends A // false for `extends`
case object BB extends A
x match { // true for case arrows
  case 2 => 22
  case 22 => 222
}

val x = 2 // false for assignment
val xx = 22

case object B extends A // false for `extends`
case object BB extends A

Config for this example:

align.preset = some

align.preset=more

val x  = 2 // true for assignment
val xx = 22

case object B  extends A // true for `extends`
case object BB extends A

q  -> 22 // true for various infix operators
qq -> 3  // and also comments!

for {
  x   <- List(1) // true for alignment enumerator
  yyy <- List(2)
} yield x ** yyy

x match { // true for multiple tokens across multiple lines
  case 1  => 1  -> 2  // first
  case 11 => 11 -> 22 // second

  // A blank line separates alignment blocks.
  case `ignoreMe` => 111 -> 222
}

// Align assignments of similar type.
def name   = column[String]("name")
def status = column[Int]("status")
val x      = 1
val xx     = 22

// Align sbt module IDs.
libraryDependencies ++= Seq(
  "org.scala-lang" % "scala-compiler" % scalaVersion.value,
  "com.lihaoyi"   %% "sourcecode"     % "0.1.1"
)
val x = 2 // true for assignment
val xx = 22

case object B extends A // true for `extends`
case object BB extends A

q -> 22 // true for various infix operators
qq -> 3   // and also comments!

for {
  x <- List(1) // true for alignment enumerator
  yyy <- List(2)
} yield x ** yyy

x match { // true for multiple tokens across multiple lines
  case 1 => 1 -> 2 // first
  case 11 => 11 -> 22 // second

  // A blank line separates alignment blocks.
  case `ignoreMe` => 111 -> 222
}

// Align assignments of similar type.
def name = column[String]("name")
def status = column[Int]("status")
val x = 1
val xx = 22

// Align sbt module IDs.
libraryDependencies ++= Seq(
  "org.scala-lang" % "scala-compiler" % scalaVersion.value,
  "com.lihaoyi" %% "sourcecode" % "0.1.1"
)

Config for this example:

maxColumn = 80
align.preset = more

align.preset=most

for {
  // align <- with =
  x   <- List()
  yyy  = 2
  // aligns body by arrow
  zzz <- new Integer {
           def value = 3
         }
} yield x
for {
  // align <- with =
  x <- List()
  yyy = 2
  // aligns body by arrow
  zzz <- new Integer {
    def value = 3
  }
} yield x

Config for this example:

align.preset = most

Note. Only for the truest vertical aligners.

align.tokens

Default: [caseArrow]

An align token contains a code (the string literal of an operator of token) and a list of owners; each owner entry in turn contains an optional regex (the kind of the closest tree node that owns that token), and a list of parents (to match the tree containing the owner of the token).

To find the owner part for a custom tree, look for its type prefix using Scastie Playground or AST Explorer.

The special code // is used for single-line comments. Also, since v3.3.1, this includes multi-line comments /* ... */ which do not themselves contain newlines but are followed by one (i.e., can trivially be changed to a // comment).

x match {
  case 1  => 1 -> 2
  case 11 => 11 -> 22
}
x match {
  case 1 => 1 -> 2
  case 11 => 11 -> 22
}

Config for this example:

align.tokens = [{
  code = "=>"
  owners = [{
    regex = "Case"
  }]
}]

val x = List(
  "org.scala-lang" %% "scala-compiler" % scalaVersion.value,
  "com.lihaoyi" %% "sourcecode" % "0.1.1"
)
val x = List(
"org.scala-lang" %% "scala-compiler" % scalaVersion.value,
"com.lihaoyi" %% "sourcecode" % "0.1.1"
)

Config for this example:

align.tokens = [
  {
    code = "%"
    owners = [{
      regex = "Term.ApplyInfix"
    }]
  }, {
    code = "%%"
    owners = [{
      regex = "Term.ApplyInfix"
    }]
  }
]

case class Foo(
    firstParam:  Int,
    secondParam: String,
    thirdParam:  Boolean
) {
  def Foo(
      firstParam: Int,
      secondParam: String,
      thirdParam: Boolean
  ) = ???
}
case class Foo(
  firstParam: Int,
  secondParam: String,
  thirdParam: Boolean
) {
  def Foo(
    firstParam: Int,
    secondParam: String,
    thirdParam: Boolean
  ) = ???
}

Config for this example:

align.tokens."+" = [{
  code = ":"
  owners = [{
    regex = "Term\\.Param"
    parents = [ "Ctor\\.Primary" ]
  }]
}]

case class Foo(
    firstParam: Int,
    secondParam: String,
    thirdParam: Boolean
) {
  def Foo(
      firstParam:  Int,
      secondParam: String,
      thirdParam:  Boolean
  ) = ???
}
case class Foo(
  firstParam: Int,
  secondParam: String,
  thirdParam: Boolean
) {
  def Foo(
    firstParam: Int,
    secondParam: String,
    thirdParam: Boolean
  ) = ???
}

Config for this example:

align.tokens."+" = [{
  code = ":"
  owners = [{
    parents = [ "Defn\\." ]
  }]
}]

align.arrowEnumeratorGenerator

Default: align.arrowEnumeratorGenerator = false

for {
  x <- new Integer {
    def value = 2
  }
} yield x
for {
  x <- new Integer {
     def value = 2
     }
} yield x

Config for this example:

align.arrowEnumeratorGenerator = false

for {
  x <- new Integer {
         def value = 2
       }
} yield x
for {
  x <- new Integer {
     def value = 2
     }
} yield x

Config for this example:

align.arrowEnumeratorGenerator = true

align.closeParenSite

This parameter controls whether to align the closing parentheses when we aligned the opening one (see openParenXxxSite parameters below) and the respective danglingParentheses.xxxSite is set.

Since v3.0.0.

Default: align.closeParenSite = false

function(arg1, // align by (
         arg2,
         arg3
        )
function(arg1, // align by (
    arg2,
 arg3)

Config for this example:

align.closeParenSite = true
align.openParenCallSite = true
danglingParentheses.callSite = true

function(arg1, // align by (
         arg2,
         arg3
)
function(arg1, // align by (
    arg2,
 arg3)

Config for this example:

align.closeParenSite = false
align.openParenCallSite = true
danglingParentheses.callSite = true

align.openParenCallSite

Default: align.openParenCallSite = false

Default changed from true to false in v1.6.

foo(arg1, arg2)

function(arg1, // align by (
         arg2,
         arg3
)

function(argument1, argument2)
foo(arg1, arg2)

function(arg1, // align by (
    arg2,
 arg3)

function(
  argument1,
  argument2)

Config for this example:

align.openParenCallSite = true

foo(arg1, arg2)

function(
  arg1, // no align by (
  arg2,
  arg3
)

function(argument1, argument2)
foo(arg1, arg2)

function(arg1, // no align by (
    arg2,
 arg3)

function(
  argument1,
  argument2)

Config for this example:

align.openParenCallSite = false

align.openBracketCallSite

Since v3.0.4.

If set explicitly, will be used for the left bracket in type arguments, instead of align.openParenCallSite.

align.openParenCtrlSite

This parameter controls alignment after ( in if/while/for.

Default: align.openParenCtrlSite = false

align.openParenDefnSite

Default: align.openParenDefnSite = false

Default changed from true to false in v1.6.

class IntString(int: Int,
                string: String
)

class IntStringLong(int: Int,
                    string: String,
                    long: Long
)
class IntString(int: Int, string: String)

class IntStringLong(int: Int,
    string: String,
  long: Long)

Config for this example:

align.openParenDefnSite = true

class IntString(
    int: Int,
    string: String
)

class IntStringLong(
    int: Int,
    string: String,
    long: Long
)
class IntString(int: Int, string: String)

class IntStringLong(
      int: Int,
    string: String,
  long: Long
)

Config for this example:

align.openParenDefnSite = false

align.openBracketDefnSite

Since v3.0.4.

If set explicitly, will be used for the left bracket in type parameters, instead of align.openParenDefnSite.

align.openParenTupleSite

This parameter controls aligning of tuples to their opening parenthesis. If not specified, will use the value of align.openParenCallSite.

Since v3.0.0.

object a {
  foo(
    bar,
    baz
  )
  (bar,
   baz
  )
}
object a {
  foo(bar, baz)
  (bar, baz)
}

Config for this example:

maxColumn = 10
align.openParenCallSite = false
align.openParenTupleSite = true

object a {
  foo(bar,
      baz
  )
  (bar,
   baz
  )
}
object a {
  foo(bar, baz)
  (bar, baz)
}

Config for this example:

maxColumn = 10
align.openParenCallSite = true

align.beforeOpenParenXxxSite

Aligns parameter groups (not parameters within a group) if using newlines.beforeOpenParenXxxSite. Requires align.closeParenSite.

Since v3.3.2.

# Defaults
align.beforeOpenParenCallSite = false
align.beforeOpenParenDefnSite = false

align.stripMargin

See assumeStandardLibraryStripMargin.

Default: align.stripMargin = true

This functionality is enabled in all presets except align.preset=none where it was disabled since the parameter's introduction in v2.5.0.

align.multiline

If this flag is set, when alignment is applied, multiline statements will not be excluded from search of tokens to align.

Since v2.5.0.

Default: align.multiline = false

for {
  a      <- aaa
  bbb    <- bb
  cccccc <- c {
    3
  }
  dd     <- ddddd
} yield ()
for {
  a <- aaa
  bbb <- bb
  cccccc <- c {
    3
  }
  dd <- ddddd
} yield ()

Config for this example:

align.preset = more
align.multiline = true

for {
  a   <- aaa
  bbb <- bb
  cccccc <- c {
    3
  }
  dd <- ddddd
} yield ()
for {
  a <- aaa
  bbb <- bb
  cccccc <- c {
    3
  }
  dd <- ddddd
} yield ()

Config for this example:

align.preset = more
align.multiline = false

align.allowOverflow

If this flag is set, as long as unaligned lines did not overflow, we will not check whether alignment causes any lines to overflow the maxColumn setting.

Since v3.0.0.

Default: align.allowOverflow = false

It's also enabled by default in align.preset = most.

align.inInterpolation

If this flag is set, and breaks within interpolated code are allowed (see newlines.inInterpolation, then the interpolated code and the closing } will be indented relative to the opening ${.

Since v3.4.0.

Default: align.inInterpolation = false

Keep in mind that this option might lead to line overflow via "stacking":

object a {
  s"""
    |foo1 ${
             quxQux(
               bazBaz,
               barBar
             )
           } foo2 ${
                     quxQux(
                       bazBaz,
                       barBar
                     )
                   } foo3 ${
                             quxQux(
                               bazBaz,
                               barBar
                             )
                           } foo4
    |""".stripMargin
}
object a {
  s"""
    |foo1 ${quxQux(bazBaz, barBar)} foo2 ${quxQux(bazBaz, barBar)} foo3 ${quxQux(bazBaz, barBar)} foo4
    |""".stripMargin
}

Config for this example:

maxColumn = 30
align.inInterpolation = true
newlines.inInterpolation = oneline

vs

object a {
  s"""
    |foo1 ${
      quxQux(bazBaz, barBar)
    } foo2 ${
      quxQux(bazBaz, barBar)
    } foo3 ${
      quxQux(bazBaz, barBar)
    } foo4
    |""".stripMargin
}
object a {
  s"""
    |foo1 ${quxQux(bazBaz, barBar)} foo2 ${quxQux(bazBaz, barBar)} foo3 ${quxQux(bazBaz, barBar)} foo4
    |""".stripMargin
}

Config for this example:

maxColumn = 30
align.inInterpolation = false
newlines.inInterpolation = oneline

align.delayUntilSpace

If this flag is set, the formatter will not forcefully pull apart two successive non-whitespace tokens that would otherwise be formatted without a space between them.

Instead, the extra alignment spaces will be added to the next space on the same line.

Since v3.7.13. Prior to that, this behaviour was always enabled.

Default: align.delayUntilSpace = true

object a {
  def meeethod1(pram1: AnyRef): Any =
    ???
  def methd2(paaaaaram2: Any): Any = ???
  def meth3(param333333: Any): Any = ???
  def md4(param4:        Any): Any = ???
}
object a {
  def meeethod1(pram1: AnyRef): Any = ???
  def methd2(paaaaaram2: Any): Any = ???
  def meth3(param333333: Any): Any = ???
  def md4(param4: Any): Any = ???
}

Config for this example:

align.preset = more
align.delayUntilSpace = true
align.tokens."+" = [ { code = ":" }, { code = "(" }, { code = ")" }, { code = "=" } ]

vs

object a {
  def meeethod1(pram1: AnyRef): Any =
    ???
  def methd2(paaaaaram2: Any): Any = ???
  def meth3(param333333: Any): Any = ???
  def md4  (param4     : Any): Any = ???
}
object a {
  def meeethod1(pram1: AnyRef): Any = ???
  def methd2(paaaaaram2: Any): Any = ???
  def meth3(param333333: Any): Any = ???
  def md4(param4: Any): Any = ???
}

Config for this example:

align.preset = more
align.delayUntilSpace = false
align.tokens."+" = [ { code = ":" }, { code = "(" }, { code = ")" }, { code = "=" } ]

Newlines

The newlines.* options are used to configure when and where scalafmt should insert newlines.

You might be interested in the Vertical Multiline section.

newlines.source

Since v2.5.0.

This parameter controls the general approach to line breaks, and whether to take into account existing newlines in the source. The default value (if the parameter is not specified) is the classic, original way. Below are the alternatives.

newlines.source=keep

This approach attempts to preserve line breaks in the input whenever possible.

Keep in mind that other parameters will take precedence if they require (or prohibit) breaks in specific places (and that includes their default values).

For instance, default for binPack.callSite will not allow multiple arguments per line in a multiline expression.

newlines.source=fold,unfold

These two approaches completely ignore existing line breaks, except around comments and blank lines (i.e., multiple consecutive newlines).

Might require increasing optimizer limits, to avoid SearchStateExploded exceptions.

fold attempts to remove line breaks whenever possible resulting in a more horizontal, or vertically compact look.

unfold, on the other hand, is intended for those who prefer a more vertical, or horizontally compact look.

Both settings attempt to play nice with other parameters, but some combinations are prohibited and will result in an error.

newlines.topLevelStatementBlankLines

Since v3.0.0.

This parameter controls when to add blank lines before and/or after a top-level statement (a member of a package or template; nesting is allowed but not within a block). Special cases:

  • the rules do not directly apply to package statements at the top of the source file; however, if this parameter is non-empty, there will be at least one blank line before the first non-package statement, and possibly more if the rules match that statement
  • end markers are handled through a setting for the statement they mark
  • imports and exports are processed as a group of consecutive statements
  • also see Newlines around package or template body

This parameter might reduce the number of blank lines but will not eliminate them completely unless corresponding value is negative.

Each entry on this list consists of the following fields (except blanks, all are used to match whether the rule should apply):

  • regex
    • a regular expression to match the type of the statement
    • if unspecified, will match all valid statements
    • see align.tokens for instructions on how to find the type
  • maxNest and (since v3.1.2) minNest
    • basically, limits indentation level (not actual indentation) of a statement
    • unindented statements (under source-level unindented package) have nest level of 0, those under them are 1 etc.
    • if unspecified, will match any nesting level
  • minBreaks (default: 1)
    • sets the minimum number of line breaks between the first and last line of a statement (i.e., one less than the number of lines the statement spans).
    • for instance, minBreaks=0 will apply to all statements, whereas 1 will require at least one line break (that is, a multi-line statement).
  • (since v3.8.3) minBlankGaps and maxBlankGaps
    • sets the range on the number of blank-line gaps (regardless of the number of lines in each gap) that would have been output prior to this rule.
    • if a limit is unspecified, will not constrain on the corresponding end
  • blanks
    • if omitted while the entry matches, serves to exclude another entry
    • before: number of lines to be added before a matching statement; if negative (v3.0.1), lines will be removed unless before a comment
    • after: number of lines to be added after a matching statement
      • for instance, if a package matches, this controls how many lines need to be added after all statements of a package, not after the first line which declares the package name
      • same logic as above applies to negative values
    • beforeEndMarker:
      • end markers themselves will not be matched against any rule; blanks before them will come from beforeEndMarker and blanks after from after
    • beforeAll and afterAll (v3.0.1): if set explicitly, replaces the respective before or after value before the first or after the last statement of a template or indented package; otherwise, the before or after value will be capped at 1
    • can be specified as a single integer, to set just before and after to the same value:
// these two are equivalent
newlines.topLevelStatementBlankLines = [
  { blanks { before = 1, after = 1, beforeEndMarker = 0 } }
]
newlines.topLevelStatementBlankLines = [
  { blanks = 1 }
]

If you'd like to override or exclude some cases, add them explicitly:

newlines.topLevelStatementBlankLines = [
  { maxNest = 0, blanks = 2 } // uses 2 blanks for all unindented statements
  { regex = "^Import" } // excludes import groups; blanks are not specified
]

If multiple entries match a statement, an entry with the lowest minBreaks will be selected. Since we'll be adding lines, this will increase the span of the statement and might potentially lead to another entry, with a higher minBreaks, to match as well, which is undesirable.

Default: newlines.topLevelStatementBlankLines = []

import org.scalafmt
package core { // no newline added here
  class C1 {}
  object O { // nor here
    val x1 = 1
    val x2 = 2
    def A = "A"
    def B = "B"
  } // nor here
  class C2 {}
}
import org.scalafmt
package core { // no newline added here
  class C1 {}
  object O { // nor here
    val x1 = 1
    val x2 = 2
    def A = "A"
    def B = "B"
  } // nor here
  class C2 {}
}

Config for this example:

newlines.topLevelStatementBlankLines = []

import org.scalafmt

package core {
  class C1 {}

  object O {
    val x1 = 1
    val x2 = 2
    def A = "A"
    def B = "B"
  }
  class C2 {}
}
import org.scalafmt
package core {
  class C1 {}
  object O {
    val x1 = 1
    val x2 = 2
    def A = "A"
    def B = "B"
  }
  class C2 {}
}

Config for this example:

newlines.topLevelStatementBlankLines = [
  {
    blanks { before = 1 }
  }
]

import org.scalafmt
package core {
  class C1 {}
  object O {
    val x1 = 1
    val x2 = 2
    def A = "A"
    def B = "B"
  }

  class C2 {}
}
import org.scalafmt
package core {
  class C1 {}
  object O {
    val x1 = 1
    val x2 = 2
    def A = "A"
    def B = "B"
  }
  class C2 {}
}

Config for this example:

newlines.topLevelStatementBlankLines = [
  {
    blanks { after = 1 }
  }
]

import org.scalafmt

package core {
  class C1 {}

  object O {
    val x1 = 1
    val x2 = 2
    def A = "A"
    def B = "B"
  }

  class C2 {}
}
import org.scalafmt
package core {
  class C1 {}
  object O {
    val x1 = 1
    val x2 = 2
    def A = "A"
    def B = "B"
  }
  class C2 {}
}

Config for this example:

newlines.topLevelStatementBlankLines = [
  {
    blanks = 1
  }
]

package core {

  object O {

    val x1 = 1

    val x2 = 2

    def A =
      "A"

    def B = {
      "B"
    }

  }

}
package core {
  object O {
    val x1 = 1
    val x2 = 2
    def A =
      "A"
    def B = {
      "B"
    }
  }
}

Config for this example:

newlines.topLevelStatementBlankLines = [
  {
    minBreaks = 0
    blanks = 1
  }
]

import org.scalafmt

package core {

  object O {
    val x1 = 1
    val x2 = 2
    def A =
      "A"

    def B = {
      "B"
    }

  }

}
import org.scalafmt
package core {
  object O {
    val x1 = 1
    val x2 = 2
    def A =
      "A"
    def B = {
      "B"
    }
  }
}

Config for this example:

newlines.topLevelStatementBlankLines = [
  {
    minBreaks = 2
    blanks = 1
  }
]

Newlines around package or template body

Since v3.0.0.

This group of parameters controls whether to enforce a blank line before the first or after the last statement of a package or template (i.e., body of a class, object, trait, enum).

These parameters will not cause any blank lines to be removed.

newlines.topLevelBodyIfMinStatements

topLevelBodyIfMinStatements can be before and/or after, while topLevelBodyMinStatements limits when the rule is applied.

# Defaults
newlines.topLevelBodyIfMinStatements = []
newlines.topLevelBodyMinStatements = 2
import org.scalafmt
package core {
  class C1 {
    def one = 1
  }
  object O1 {
    val one = 1
    def two = 2
  }
  class C2 {}
}
import org.scalafmt
package core {
  class C1 {
    def one = 1
  }
  object O1 {
    val one = 1
    def two = 2
  }
  class C2 {}
}

Config for this example:

newlines.topLevelBodyIfMinStatements = []

import org.scalafmt
package core {

  class C1 {
    def one = 1
  }
  object O1 {

    val one = 1
    def two = 2
  }
  class C2 {}
}
import org.scalafmt
package core {
  class C1 {
    def one = 1
  }
  object O1 {
    val one = 1
    def two = 2
  }
  class C2 {}
}

Config for this example:

newlines.topLevelBodyIfMinStatements = [before]

package core {
  class C1 {
    def one = 1
  }
  object O1 {
    val one = 1
    def two = 2

  }
  class C2 {}

}
package core {
  class C1 {
    def one = 1
  }
  object O1 {
    val one = 1
    def two = 2
  }
  class C2 {}
}

Config for this example:

newlines.topLevelBodyIfMinStatements = [after]

import org.scalafmt
package core {

  class C1 {
    def one = 1
  }
  object O1 {

    val one = 1
    def two = 2

  }
  class C2 {}

}
import org.scalafmt
package core {
  class C1 {
    def one = 1
  }
  object O1 {
    val one = 1
    def two = 2
  }
  class C2 {}
}

Config for this example:

newlines.topLevelBodyIfMinStatements = [before,after]

newlines.beforeTemplateBodyIfBreakInParentCtors

This parameter will force a blank line before the first statement of a template body if the token before extends and the { (or, in scala3, :) token are not on the same line.

Default: newlines.beforeTemplateBodyIfBreakInParentCtors = false

package core {
  class C1 extends S { // no breaks between "C1" and "{"
    def one = 1
  }
  class C1(
      param: Int
  ) extends S { // no breaks between ")" and "{"
    def one = 1
  }
  class C1 extends S { // no breaks between "C1" and "=>"
    self =>
    def one = 1
  }
  class C1
      extends S { // break between "C1" and "{"

    def one = 1
  }
}
package core {
  class C1 extends S { // no breaks between "C1" and "{"
    def one = 1
  }
  class C1(
    param: Int
  ) extends S { // no breaks between ")" and "{"
    def one = 1
  }
  class C1 extends S { // no breaks between "C1" and "=>"
    self =>
    def one = 1
  }
  class C1
    extends S { // break between "C1" and "{"
    def one = 1
  }
}

Config for this example:

newlines.source = keep
newlines.beforeTemplateBodyIfBreakInParentCtors = true

package core {
  class C1 extends S { // no breaks between "C1" and "{"
    def one = 1
  }
  class C1(
      param: Int
  ) extends S { // no breaks between ")" and "{"
    def one = 1
  }
  class C1 extends S { // no breaks between "C1" and "=>"
    self =>
    def one = 1
  }
  class C1
      extends S { // break between "C1" and "{"
    def one = 1
  }
}
package core {
  class C1 extends S { // no breaks between "C1" and "{"
    def one = 1
  }
  class C1(
    param: Int
  ) extends S { // no breaks between ")" and "{"
    def one = 1
  }
  class C1 extends S { // no breaks between "C1" and "=>"
    self =>
    def one = 1
  }
  class C1
    extends S { // break between "C1" and "{"
    def one = 1
  }
}

Config for this example:

newlines.source = keep
newlines.beforeTemplateBodyIfBreakInParentCtors = false

newlines.beforeMultiline

Since v2.7.0

This parameter controls whether to force a new line before a multi-line body of case/if/def/val and how to format it if the space is allowed. (For additional control with assignment expressions, please also see newlines.forceBeforeMultilineAssign below.)

It accepts the same values as newlines.source (and defaults to that parameter's setting).

NB: for breaks before parameters of a multi-line lambda, use multiline with newlines.beforeCurlyLambdaParams.

a match {
  // had space after "=>"
  case a =>
    if (step != 0)
      d.name should be("dir" + step)
  // had newline after "=>"
  case a =>
    if (step != 0)
      d.name should be("dir" + step)
}
a match {
  // had space after "=>"
  case a => if (step != 0)
      d.name should be("dir" + step)
  // had newline after "=>"
  case a =>
    if (step != 0)
      d.name should be("dir" + step)
}

Config for this example:

newlines.beforeMultiline = unfold

a match {
  // had space after "=>"
  case a => if (step != 0)
      d.name should be("dir" + step)
  // had newline after "=>"
  case a => if (step != 0)
      d.name should be("dir" + step)
}
a match {
  // had space after "=>"
  case a => if (step != 0)
      d.name should be("dir" + step)
  // had newline after "=>"
  case a =>
    if (step != 0)
      d.name should be("dir" + step)
}

Config for this example:

newlines.beforeMultiline = fold

a match {
  // had space after "=>"
  case a => if (step != 0)
      d.name should be("dir" + step)
  // had newline after "=>"
  case a =>
    if (step != 0)
      d.name should be("dir" + step)
}
a match {
  // had space after "=>"
  case a => if (step != 0)
      d.name should be("dir" + step)
  // had newline after "=>"
  case a =>
    if (step != 0)
      d.name should be("dir" + step)
}

Config for this example:

newlines.beforeMultiline = keep

a match {
  // had space after "=>"
  case a =>
    if (step != 0)
      d.name should be("dir" + step)
  // had newline after "=>"
  case a =>
    if (step != 0)
      d.name should be("dir" + step)
}
a match {
  // had space after "=>"
  case a => if (step != 0)
      d.name should be("dir" + step)
  // had newline after "=>"
  case a =>
    if (step != 0)
      d.name should be("dir" + step)
}

Config for this example:

# newlines.beforeMultiline = classic

newlines.forceBeforeMultilineAssign

Since v3.0.0

This section controls whether to force a break before a multi-line body of an assignment expression unless it can be formatted on a single line (or is enclosed in braces). By default, the rule is disabled. It takes precedence over newlines.beforeMultiline settings.

It can take the following values:

  • never: the rule is disabled
  • any: applies to any assignment expression (def, assignment to a var, default value of a method parameter, etc.)
  • def: applies only to definitions which can potentially be parameterized (def, macro, given alias, etc.)
  • anyMember: applies to members of a class/trait/object
  • topMember: applies to members of a class/trait/object which itself can only be nested within a sequence of class/trait/object definitions

It replaces deprecated newlines parameters beforeMultilineDef=unfold and alwaysBeforeMultilineDef=true which, if this parameter is not set, map to def.

class A {
  // break, allows params (even if it doesn't define any)
  def foo =
    func(
      foo,
      bar
    )
  // no break, doesn't allow params
  val foo = func(
    foo,
    bar
  )
  def foo = {
    def a =
      func(
        foo,
        bar
      )
    val a = func(
      foo,
      bar
    )
  }
}
class A {
  // break, allows params (even if it doesn't define any)
  def foo = func(foo, bar)
  // no break, doesn't allow params
  val foo = func(foo, bar)
  def foo = {
    def a = func(foo, bar)
    val a = func(foo, bar)
  }
}

Config for this example:

maxColumn = 17
newlines.forceBeforeMultilineAssign = def

class A {
  class B {
    // break, a top member
    def foo = func(
      foo,
      bar
    )
    // break, a top member
    val foo = func(
      foo,
      bar
    )
  }
  def foo = {
    // no break, not a member
    def a = func(
      foo,
      bar
    )
    // no break, not a member
    val a = func(
      foo,
      bar
    )
    new A with B {
      // no break, not a top member
      def foo =
        func(
          foo,
          bar
        )
      // no break, not a top member
      val foo =
        func(
          foo,
          bar
        )
    }
  }
}
class A {
  class B {
    // break, a top member
    def foo = func(foo, bar)
    // break, a top member
    val foo = func(foo, bar)
  }
  def foo = {
    // no break, not a member
    def a = func(foo, bar)
    // no break, not a member
    val a = func(foo, bar)
    new A with B {
      // no break, not a top member
      def foo = func(foo, bar)
      // no break, not a top member
      val foo = func(foo, bar)
    }
  }
}

Config for this example:

maxColumn = 19
newlines.forceBeforeMultilineAssign = topMember

// all disabled, no breaks
class A {
  def foo = func(
    foo,
    bar
  )
  val foo = func(
    foo,
    bar
  )
  def foo = {
    def a = func(
      foo,
      bar
    )
    val a = func(
      foo,
      bar
    )
  }
}
// all disabled, no breaks
class A {
  def foo = func(foo, bar)
  val foo = func(foo, bar)
  def foo = {
    def a = func(foo, bar)
    val a = func(foo, bar)
  }
}

Config for this example:

maxColumn = 17
newlines.forceBeforeMultilineAssign = never

newlines.forceBeforeAssign

Since v3.5.9

Default: newlines.forceBeforeAssign = "never"

This parameter takes precedence over newlines.forceBeforeMultilineAssign and uses the same values. The difference is, the rule forces a newline before a matching assignment expression whether or not it can be formatted on a single line.

newlines.beforeTypeBounds

Since v3.0.0

This parameter controls formatting of bounds of type parameters: upper <:, lower >:, view <%, and context : bounds. It accepts the same values as newlines.source.

  • classic: simply allows no line breaks (default; can't be specified)
  • keep: preserves a no-break if the next bound fits on the line
  • fold: uses a no-break if the next bound fits on the line
  • unfold: puts all bounds on the same line, or breaks before each

newlines.alwaysBeforeElseAfterCurlyIf

Default: newlines.alwaysBeforeElseAfterCurlyIf = false

if (someCond) {
  foo()
}
else {
  bar()
}
if (someCond) {
  foo()
} else {
  bar()
}

Config for this example:

newlines.alwaysBeforeElseAfterCurlyIf = true

if (someCond) {
  foo()
} else {
  bar()
}
if (someCond) {
  foo()
}
else {
  bar()
}

Config for this example:

newlines.alwaysBeforeElseAfterCurlyIf = false

newlines.beforeCurlyLambdaParams

This parameter controls whether a newline is forced between the opening curly brace and the parameters of a lambda or partial function. Added in 2.7.0, replacing boolean alwaysBeforeCurlyBraceLambdaParams (removed in 3.4.0).

Default: newlines.beforeCurlyLambdaParams = "never"

// should keep one-line
x.map { x => s"${x._1} -> ${x._2}" }
x.map { case (c, i) => s"$c -> $i" }
// should break on arrow since case doesn't fit on a line
x.zipWithIndex.map { case (c, i) =>
  s"$c -> $i"
}
x.zipWithIndex.map { case (c, i) =>
  s"$c -> $i (long comment)"
}
// should keep one-line
x.map { x => s"${x._1} -> ${x._2}" }
x.map { case (c, i) => s"$c -> $i" }
// should break on arrow since case doesn't fit on a line
x.zipWithIndex.map { case (c, i) => s"$c -> $i" }
x.zipWithIndex.map { case (c, i) => s"$c -> $i (long comment)" }

Config for this example:

newlines.beforeCurlyLambdaParams = never

// should break on brace, though fits on the same line
x.map {
  x => s"${x._1} -> ${x._2}"
}
x.map {
  case (c, i) => s"$c -> $i"
}
x.zipWithIndex.map {
  case (c, i) =>
    s"$c -> $i (long comment)"
}
// should break on brace and arrow as lambda doesn't fit on a line
x.zipWithIndex.map {
  x =>
    s"${x._1} -> ${x._2} (long comment)"
}
// should break on brace, though fits on the same line
x.map { x => s"${x._1} -> ${x._2}" }
x.map { case (c, i) => s"$c -> $i" }
x.zipWithIndex.map { case (c, i) => s"$c -> $i (long comment)" }
// should break on brace and arrow as lambda doesn't fit on a line
x.zipWithIndex.map { x => s"${x._1} -> ${x._2} (long comment)" }

Config for this example:

newlines.beforeCurlyLambdaParams = always

// should keep one-line
x.map { x => s"${x._1} -> ${x._2}" }
x.map { case (c, i) => s"$c -> $i" }
// should break on brace as lambda doesn't fit on the same line
x.zipWithIndex.map {
  x => s"${x._1} -> ${x._2}"
}
x.zipWithIndex.map {
  case (c, i) => s"$c -> $i"
}
// should break on brace and arrow as lambda doesn't fit on a line
x.zipWithIndex.map {
  x =>
    s"${x._1} -> ${x._2} (long comment)"
}
x.zipWithIndex.map {
  case (c, i) =>
    s"$c -> $i (long comment)"
}
// should keep one-line
x.map { x => s"${x._1} -> ${x._2}" }
x.map { case (c, i) => s"$c -> $i" }
// should break on brace as lambda doesn't fit on the same line
x.zipWithIndex.map { x => s"${x._1} -> ${x._2}" }
x.zipWithIndex.map { case (c, i) => s"$c -> $i" }
// should break on brace and arrow as lambda doesn't fit on a line
x.zipWithIndex.map { x => s"${x._1} -> ${x._2} (long comment)" }
x.zipWithIndex.map { case (c, i) => s"$c -> $i (long comment)" }

Config for this example:

newlines.beforeCurlyLambdaParams = multiline

// should keep one-line
x.map { x => s"${x._1} -> ${x._2}" }
x.map { case (c, i) => s"$c -> $i" }
// should break after arrow as lambda doesn't fit on the same line
x.zipWithIndex.map { x =>
  s"${x._1} -> ${x._2}"
}
x.zipWithIndex.map { x =>
  s"${x._1} -> ${x._2} (long comment)"
}
// should break on brace as lambda doesn't fit on the same line
x.zipWithIndex.map {
  case (c, i) => s"$c -> $i"
}
// should break on brace and arrow as lambda doesn't fit on a line
x.zipWithIndex.map {
  case (c, i) =>
    s"$c -> $i (long comment)"
}
// should keep one-line
x.map { x => s"${x._1} -> ${x._2}" }
x.map { case (c, i) => s"$c -> $i" }
// should break after arrow as lambda doesn't fit on the same line
x.zipWithIndex.map { x => s"${x._1} -> ${x._2}" }
x.zipWithIndex.map { x => s"${x._1} -> ${x._2} (long comment)" }
// should break on brace as lambda doesn't fit on the same line
x.zipWithIndex.map { case (c, i) => s"$c -> $i" }
// should break on brace and arrow as lambda doesn't fit on a line
x.zipWithIndex.map { case (c, i) => s"$c -> $i (long comment)" }

Config for this example:

newlines.beforeCurlyLambdaParams = multilineWithCaseOnly

newlines.afterCurlyLambdaParams

This parameter controls handling of newlines after the arrow following the parameters of a curly brace lambda or partial function, and whether a space can be used for one-line formatting of the entire function body (if allowed but the body doesn't fit, a break is always forced).

This parameter was renamed in 2.7.0 from afterCurlyLambda, for clarity and consistency with beforeCurlyLambdaParams defined above.

Default: newlines.afterCurlyLambdaParams = "never"

// remove all blank lines if any
// one-line formatting is allowed
something.map { x => f(x) }

something.map { x => f(x) }
// remove all blank lines if any
// one-line formatting is allowed
something.map { x =>



  f(x)
}

something.map { x => f(x) }

Config for this example:

newlines.afterCurlyLambdaParams = squash

// remove all blank lines if any
// one-line formatting depends on newlines.source:
// yes for fold; no for unfold; otherwise, only if there was no break
something.map { x =>
  f(x)
}

something.map { x => f(x) }
// remove all blank lines if any
// one-line formatting depends on newlines.source:
// yes for fold; no for unfold; otherwise, only if there was no break
something.map { x =>



  f(x)
}

something.map { x => f(x) }

Config for this example:

newlines.afterCurlyLambdaParams = never

// if blank lines are present, keep only one
// one-line formatting depends on newlines.source:
// if no blank for fold; no for unfold; otherwise, only if there was no break
something.map { x =>

  f(x)
}

something.map { x => f(x) }
// if blank lines are present, keep only one
// one-line formatting depends on newlines.source:
// if no blank for fold; no for unfold; otherwise, only if there was no break
something.map { x =>



  f(x)
}

something.map { x => f(x) }

Config for this example:

newlines.afterCurlyLambdaParams = keep

// ensure a single blank line
// one-line formatting is not allowed
something.map { x =>

  f(x)
}

something.map { x =>

  f(x)
}
// ensure a single blank line
// one-line formatting is not allowed
something.map { x =>



  f(x)
}

something.map { x => f(x) }

Config for this example:

newlines.afterCurlyLambdaParams = always

newlines.implicitParamListModifierXXX

These parameters control newlines around implicit parameter list modifier.

Since v2.5.0.

Newlines around using parameter and argument list modifier

using soft keyword was introduced in Scala 3 and is supported in scalafmt. Besides parameter lists, using can also be used with argument lists hence provided rules will then also be applied to them.

Since v3.0.0.

The parameters defined below can also be accessed via their alternative names where implicit is replaced with using (for instance, newlines.usingParamListModifierPrefer). Whichever naming you use, formatting will be applied to both implicit and using.

Prefer After (default)

Prefers newline after implicit. Newline will be added unless the entire implicit parameter list fits on a line, or config style is false. Newline can also be added before if the keyword itself would overflow the line.

def format(code: String, age: Int)(implicit
    ev: Parser,
    c: Context
): String
def format(code: String, age: Int)(implicit ev: Parser, c: Context): String

Config for this example:

maxColumn = 60
newlines.implicitParamListModifierPrefer = after

Prefer Before

Prefers newline before implicit. Newline will not be added if the entire implicit parameter list fits on a line.

def format(code: String, age: Int)(
    implicit ev: Parser,
    c: Context
): String
def format(code: String, age: Int)(implicit ev: Parser, c: Context): String

Config for this example:

maxColumn = 60
newlines.implicitParamListModifierPrefer = before

Force Before

If set, forces newline before implicit (even if the parameter list would fit on one line). Otherwise, newline can still be added if the keyword would overflow the line.

def format(code: String, age: Int)(
    implicit ev: Parser,
    c: Context
): String
def format(code: String, age: Int)(implicit ev: Parser, c: Context): String

Config for this example:

maxColumn = 60
newlines.implicitParamListModifierForce = [before]

Force After

If set, forces newline after implicit (even if the parameter list would fit on one line). Otherwise, newline can still be added unless before is true, or the entire implicit parameter list fits on a line, or config style is false.

def format(code: String, age: Int)(implicit
    ev: Parser,
    c: Context
): String
def format(code: String, age: Int)(implicit ev: Parser, c: Context): String

Config for this example:

maxColumn = 60
newlines.implicitParamListModifierForce = [after]

Force both before and after

def format(code: String, age: Int)(
    implicit
    ev: Parser,
    c: Context
): String
def format(code: String, age: Int)(implicit ev: Parser, c: Context): String

Config for this example:

maxColumn = 60
newlines.implicitParamListModifierForce = [before,after]

Implicit with newlines.configStyle.defnSite.prefer

While config-style normally requires a newline after the opening parenthesis, postponing that break until after the implicit keyword is allowed if other parameters require keeping this keyword attached to the opening brace.

Therefore, any of the parameters described in this section will take precedence even when newlines.configStyle.defnSite.prefer = true is used.

newlines.infix

Introduced in v3.8.4, this parameter (and its companions) controls formatting around infix expressions. It contains the following parameter groups:

  • termSite
    • primarily applies to ordinary infix expressions (Term.ApplyInfix)
  • typeSite:
    • applies to infix expressions within types (Type.ApplyInfix) only
    • defaults to termSite if no fields are specified
  • patSite:
    • applies to infix expressions within patterns (Pat.ExtractInfix) only
    • defaults to termSite if no fields are specified

Each of these groups has several parameters of its own (replacing deprecated newlines.afterInfixXxx, originally added in v2.5.0, which moved to termSite):

  • style:
  • maxCountPerFile
  • maxCountPerExprForSome
  • breakOnNested

newlines.infix: style=keep

This approach preserves line breaks in the input. This is the original behaviour, and default for newlines.source=classic,keep.

One caveat is: for classic type infixes with Scala3 (or if the dialect enables the useInfixTypePrecedence flag), some is the default.

newlines.infix: style=many,some

These approaches completely ignore existing newlines around infix, always use a space before an infix operator and occasionally break after it. some is default for newlines.source=fold (also see caveat under keep aboce), and many for newlines.source=unfold.

Might require increasing optimizer limits, to avoid SearchStateExploded exceptions.

some will introduce fewer line breaks than many. Both will attempt to break after higher-precedence operators, and both will always break before an expression enclosed in matching parentheses.

newlines.infix: maxCountPerFile

Default: newlines.infix.termSite.maxCountPerFile = 500

If the total number of matching infix operations in the entire file exceeds newlines.infix.xxxSite.maxCountPerFile, the formatter automatically switches to newlines.infix.xxxSite.style=keep for this file.

newlines.infix: maxCountPerExprForSome

Default: newlines.infix.termSite.maxCountPerExprForSome = 10

If newlines.infix.xxxSite.style is set to some and the number of infix operations in a given expression sequence (top-level or enclosed in parens/braces) exceeds newlines.infix.xxxSite.maxCountPerExprForSome, the formatter switches to many for that sequence only.

newlines.infix: breakOnNested

Default: newlines.infix.termSite.breakOnNested = false

If enabled, will force line breaks around a nested parenthesized sub-expression in a multi-line infix expression.

newlines.avoidForSimpleOverflow

A list parameter (of comma-separated flags), with possible flags described below. These flags relax formatting rules to allow occasional line overflow (i.e., when line exceeds maxColumn) in simple cases instead of introducing a newline.

Default: newlines.avoidForSimpleOverflow = []

newlines.avoidForSimpleOverflow=[tooLong]

Since v2.6.0.

This flag tries to avoid introducing a newline if the line would overflow even with a newline.

object Example {
  foo_bar_baz("the quick brown fox jumps over the lazy dog") {
    println("")
  }
  foo_bar_baz(
    "the quick brown fox jumps over a dog") {
    println("")
  }
}
object Example {
  foo_bar_baz("the quick brown fox jumps over the lazy dog") {
    println("")
  }
  foo_bar_baz("the quick brown fox jumps over a dog") {
    println("")
  }
}

Config for this example:

maxColumn = 50
danglingParentheses.callSite = false
newlines.avoidForSimpleOverflow = [tooLong]

newlines.avoidForSimpleOverflow=[punct]

Since v2.6.0.

This flag tries to avoid a newline if the line would overflow only because of trailing punctuation (non-alphanum symbols of length 1).

With the flag set:

class Engine[TD, EI, PD, Q, P, A](
    val dataSourceClassMap: Map[String, Class[_ <: BaseDataSource[TD, EI, Q, A]]]
) {}
class Engine[TD, EI, PD, Q, P, A](
    val dataSourceClassMap: Map[
      String,
      Class[_ <: BaseDataSource[TD, EI, Q, A]]]) {}

Config for this example:

maxColumn = 80
newlines.avoidForSimpleOverflow = [punct]

newlines.avoidForSimpleOverflow=[slc]

Since v3.0.0.

This flag tries to avoid a newline if the line would overflow only because of trailing single-line comment (one which starts with //). Also, since v3.3.1, this includes a trailing /* ... */ without embedded breaks.

intercept[TestException] {
  val ct = Thread.currentThread() // comment
}
intercept[TestException] {
  val ct = Thread.currentThread() // comment
}

Config for this example:

maxColumn = 40
newlines.avoidForSimpleOverflow = [slc]

intercept[TestException] {
  val ct =
    Thread.currentThread() // comment
}
intercept[TestException] {
  val ct = Thread.currentThread() // comment
}

Config for this example:

maxColumn = 40
newlines.avoidForSimpleOverflow = []

newlines.avoidInResultType

If true, newlines in definition result type will only be used if formatting without them is impossible. This parameter was added in 2.7.0, replacing neverInResultType.

Default: newlines.avoidInResultType = false

// no newlines in result type
def permissionState(
    a: A = js.native
): js.Promise[PushPermissionState] = js.native
// no newlines in result type
val permissionState
    : js.Promise[PushPermissionState] = js.native
// can't format without newlines
implicit protected val td: TildeArrow {
  type Out = RouteTestResult
} = TildeArrow.injectIntoRoute
// no newlines in result type
def permissionState(a: A = js.native): js.Promise[PushPermissionState] = js.native
// no newlines in result type
val permissionState: js.Promise[PushPermissionState] = js.native
// can't format without newlines
implicit protected val td: TildeArrow {
  type Out = RouteTestResult } = TildeArrow.injectIntoRoute

Config for this example:

maxColumn = 40
newlines.avoidInResultType = true
newlines.neverBeforeJsNative = true

newlines.sometimesBeforeColonInMethodReturnType

If true, in some rare cases a newline could be added before the colon which delimits the return type in a method signature.

Normally, this will only happen if formatting otherwise will lead to line overflow or the return type spanning too many lines.

Also, see newlines.beforeOpenParenXxxSite below.

Default: newlines.sometimesBeforeColonInMethodReturnType = true

def someVeryLongMethodName
    : Map[String, String] = ???
def someVeryLongMethodName: Map[String, String] = ???

Config for this example:

maxColumn = 40
newlines.sometimesBeforeColonInMethodReturnType = true

newlines.beforeOpenParenXxxSite

This parameter, if enabled, causes a parameter group which doesn't fit on the same line to be formatted separately, with a newline just before the opening parenthesis.

Since v3.0.0.

Use null (default) to disable it. Otherwise, takes the same values as newlines.source (or explicit source to mirror the current value of newlines.source).

Specific formatting depends on the value: for keep, will preserve a newline; for unfold, will format every parameter group separately unless all fit on a single line; fold will use a more compact formatting.

  • beforeOpenParenDefnSite applies to definitions (methods, ctors, macros, etc.)
  • beforeOpenParenCallSite applies to invocations (method calls) and is only supported for scala3

Additional nuances:

  • if newlines.sometimesBeforeColonInMethodReturnType is true, a newline will be added before the colon unless the entire signature fits on a line (except when set to keep).
  • if the corresponding align.openParenXxxSite is true, multi-line parameters will start on the same line as the opening parenthesis and align; otherwise, formatting will use a newline and an appropriate continuation indent.
  • if the corresponding align.beforeOpenParenXxxSite is true, when the first parameter group starts without a line break, subsequent parameter groups will be aligned to it.
# Defaults
newlines.beforeOpenParenDefnSite = null
newlines.beforeOpenParenCallSite = null
def fooFunc
  (foo1: String)
  (foo2: String,
   foo3: String
  )
  : String = ???
val res = fooFunc
  ("foo1")
  ("foo2", "foo3")
def fooFunc(foo1: String)(foo2: String, foo3: String): String = ???
val res = fooFunc("foo1")("foo2", "foo3")

Config for this example:

maxColumn = 20
runner.dialect = scala3 // for CallSite
align.openParenDefnSite = true
newlines {
  beforeOpenParenDefnSite = fold
  beforeOpenParenCallSite = unfold
  sometimesBeforeColonInMethodReturnType = true
}

def fooFunc
  (foo1: String)
  (
      foo2: String,
      foo3: String
  ): String = ???
val res = fooFunc
  ("foo1")
  ("foo2", "foo3")
def fooFunc(foo1: String)(foo2: String, foo3: String): String = ???
val res = fooFunc("foo1")("foo2", "foo3")

Config for this example:

maxColumn = 20
runner.dialect = scala3 // for CallSite
align.openParenCallSite = true
newlines {
  beforeOpenParenDefnSite = unfold
  beforeOpenParenCallSite = fold
  sometimesBeforeColonInMethodReturnType = false
}

newlines.inInterpolation

This parameter controls how to format spliced scala code within string constants (e.g., s"...", etc). Also see align.inInterpolation.

Default: newlines.inInterpolation = "allow"

Since v3.4.0.

  • allow: allows breaks within spliced code (original)
    • this option will not prevent line overflow even if ${ is within bounds, because this option doesn't allow breaking right after ${
  • avoid: attemps to avoid breaks within the spliced code, regardless of line overflow
  • oneline: formats the splice on a single line, or breaks after ${ if overflows

newlines.ignoreInSyntax

The formatter frequently chooses between adding a newline and continuing the same line but either prohibiting or heavily discouraging subsequent newlines between tokens, to fit the rest of the expression on the same line.

However, in many cases and, for historical reasons, intentionally, newlines within tokens have been frequently ignored, leading to "single-line" blocks which actually span multiple lines.

This boolean parameter now allows controlling whether to ignore newlines found in syntax of strings or other possibly multi-line tokens when newlines are otherwise prohibited or undesirable (such as for single-line formatting).

Default: newlines.ignoreInSyntax = true

Since v3.7.13. Prior to that, this behaviour was always enabled.

// ignores newline in string, pretends everything fits on one line
println(s"""${1}
    """.stripMargin)
// ignores newline in string, pretends everything fits on one line
println(s"""${1}
    """.stripMargin
)

Config for this example:

newlines.ignoreInSyntax = true

// detects newline in string, forces proper multi-line formatting
println(
  s"""${1}
    """.stripMargin
)
// detects newline in string, forces proper multi-line formatting
println(s"""${1}
    """.stripMargin
)

Config for this example:

newlines.ignoreInSyntax = false

newlines.annotation

This boolean parameter controls newlines after annotations. Prior to v3.8.4, was called optIn.annotationNewlines.

Default: newlines.annotation = true

Its behaviour depends on newlines.source:

  • newlines.annotation = true:
    • newlines.source=fold: allows space before another annotation
    • newlines.source=unfold: forces break
    • otherwise: preserves space before or after an annotation
  • newlines.annotation = false:
    • newlines.source=fold: allows space before a keyword or another annotation
    • newlines.source=unfold: allows space before another annotation
    • otherwise: allows space before a keyword

newlines.selfAnnotation

If enabled, this parameter forces a break after a self annotation in a template if newlines.source=fold/unfold, and preserves it otherwise. Prior to v3.8.4, was called optIn.selfAnnotationNewline.

Default: newlines.selfAnnotation = true

Newlines: danglingParentheses

When enabled, these parameters will force a break before the closing parenthesis when there's a break after the opening parenthesis (unless otherwise specified). While this parameter is not technically under the newlines section, it logically belongs there.

danglingParentheses.defnSite

Default: danglingParentheses.defnSite = true

object a {
  // defnSite
  def method(
      a: Int,
      b: String
  ): Boolean

  // callSite
  method(
    argument1,
    argument2)
}
object a {
  // defnSite
  def method(a: Int, b: String): Boolean

  // callSite
  method(argument1, argument2)
}

Config for this example:

danglingParentheses.defnSite = true
danglingParentheses.callSite = false
maxColumn=25

danglingParentheses.callSite

Default: danglingParentheses.callSite = true

object a {
  // defnSite
  def method(
      a: Int,
      b: String): Boolean

  // callSite
  method(
    argument1,
    argument2
  )
}
object a {
  // defnSite
  def method(a: Int, b: String): Boolean

  // callSite
  method(argument1, argument2)
}

Config for this example:

danglingParentheses.defnSite = false
danglingParentheses.callSite = true
maxColumn=25

danglingParentheses.bracketXxxSite

These control the bracketed type clauses in definitions and method calls and by default are equal to their non-bracket counterparts.

object a {
  // defnSite
  def method[A <: Any, B]
      : Boolean

  // callSite
  method[
    String,
    SomeOtherType]
}
object a {
  // defnSite
  def method[A <: Any, B]: Boolean

  // callSite
  method[String, SomeOtherType]
}

Config for this example:

danglingParentheses.defnSite = true
danglingParentheses.callSite = true
danglingParentheses.bracketDefnSite = false
danglingParentheses.bracketCallSite = false
maxColumn=25

object a {
  // defnSite
  def method[A <: Any, B]
      : Boolean

  // callSite
  method[
    String,
    SomeOtherType
  ]
}
object a {
  // defnSite
  def method[A <: Any, B]: Boolean

  // callSite
  method[String, SomeOtherType]
}

Config for this example:

danglingParentheses.defnSite = false
danglingParentheses.callSite = false
danglingParentheses.bracketDefnSite = true
danglingParentheses.bracketCallSite = true
maxColumn=25

danglingParentheses.ctrlSite

Since v2.5.0.

Forces dangling on open/close parens around control structures (if, while, for) when line breaks must occur.

For optional braces in scala3, this parameter also controls whether to break before then or do in a multi-line condition.

Default: danglingParentheses.ctrlSite = true

if (something) {
  // nothing
}
if (
  something_else
) {
  // nothing
}
if (something) {
  // nothing
}
if (something_else) {
  // nothing
}

Config for this example:

danglingParentheses.ctrlSite = true
maxColumn=20

danglingParentheses.tupleSite

This parameter controls dangling of closing parentheses in tuples. If not specified, will use the value of danglingParentheses.callSite.

Since v3.0.0.

val i =
  ( // hello scalafmt, please don't blow up
    (1, 2),
    1,
    3,
    4,
    4
  )
val i =
          ( //hello scalafmt, please don't blow up
                   (1, 2),
                   1,
                   3,
                   4,
                   4)

Config for this example:

danglingParentheses.tupleSite = true

val i =
  ( // hello scalafmt, please don't blow up
    (1, 2),
    1,
    3,
    4,
    4)
val i =
          ( //hello scalafmt, please don't blow up
                   (1, 2),
                   1,
                   3,
                   4,
                   4)

Config for this example:

danglingParentheses.tupleSite = false

danglingParentheses.exclude

Since v2.5.0.

When the appropriate danglingParentheses flag (e.g., defnSite) has been set, this parameter can be used to limit contexts where dangling is applied (currently, class, trait, enum, extension and def are supported).

For backwards compatibility, the default depends on whether Vertical Multiline mode is used. If it is, the default is [class, trait]; otherwise, it's empty.

def other(a: String, b: String)(
  c: String,
  d: String) = a + b + c
other(a, b)(c, d)
def other(a: String, b: String)(c: String, d: String) = a + b + c
other(a, b)(c, d)

Config for this example:

indent.defnSite = 2
danglingParentheses.defnSite = true
danglingParentheses.exclude = [def]

Newlines: Config-style formatting

This formatting applies to argument clauses in method calls or parameter clauses in definitions. It outputs a newline after the opening parenthesis (or after the implicit keyword) and a newline before the closing parenthesis, with arguments or parameters listed one per line.

newlines.configStyle.xxxSite

The xxxSite portion refers to:

  • fallBack [since v3.8.4]: used if a more specific group is not defined
    • its prefer field replaced optIn.configStyleArguments, enabled by default
  • callSite [since v3.8.4]: applies to argument clauses in method calls
    • replaced section called newlines.configStyleCallSite
  • bracketCallSite [since v3.8.4]: applies to type argument clauses, falls back to callSite if not specified
  • defnSite [since v3.8.4]: applies to parameter clauses in method or class definitions
    • replaced section called newlines.configStyleDefnSite
  • bracketDefnSite [since v3.8.4]: applies to type parameter clauses, falls back to defnSite if not specified

newlines.configStyle.xxxSite.prefer

If true, applies config-style formatting:

  • newlines.source = fold/unfold: if single-line formatting is impossible
  • newlines.source = classic/keep: if preference for config-style is detected in the source:
    • there's a newline present before the closing delimiter
    • if danglingParentheses.xxxSite = false (and align.openParenXxxSite = false): no other condition needs to be present (the scala.js rule)
    • otherwise, there needs to be a newline after the opening delimiter, or after the implicit keyword if present.

Please note that other parameters might also force config-style (see below).

object a {
  // keeps single line
  def method1(a: Int, b: String): Boolean

  // forces config style
  def method2(
      a: Int,
      b: String,
      c: String
  ): Boolean

  // preserves config style
  def method3(
      a: Int,
      b: String,
      c: String
  ): Boolean
}
object a {
  // keeps single line
  def method1(a: Int, b: String): Boolean

  // forces config style
  def method2(a: Int, b: String, c: String): Boolean

  // preserves config style
  def method3(
    a: Int, b: String, c: String
  ): Boolean
}

Config for this example:

newlines.configStyle.defnSite.prefer = true
maxColumn=45

Forcing config style

When newlines.configStyle.xxxSite.forceIfOptimized is enabled and route search optimization is applicable to a clause, the formatter will force config-style formatting.

By default, takes the same value as newlines.configStyle.xxxSite.prefer.

object a {
  // this is a definition, not a method call
  def method(a: String, b: String = null): Boolean

  // keeps single line; min offset not satisfied
  method(
    a,
    b
  )

  // keeps single line; min arg not satisfied
  method(SomeVeryVeryVeryVeryLongArgument)

  // forces config style
  method(
    foo,
    bar
  )
}
object a {
  // this is a definition, not a method call
  def method(a: String, b: String = null): Boolean

  // keeps single line; min offset not satisfied
  method(a, b)

  // keeps single line; min arg not satisfied
  method(SomeVeryVeryVeryVeryLongArgument)

  // forces config style
  method(foo, bar)
}

Config for this example:

newlines.configStyle.callSite.forceIfOptimized = true
newlines.configStyle.defnSite.forceIfOptimized = false
runner.optimizer.callSite { minSpan = 5, minCount = 2 }
maxColumn = 60

newlines.configStyle.beforeComma

If enabled, will break before comma (instead of after) when using config style. However, if the runner.dialect supports trailing commas, using rewrite.trailingCommas is recommended (which is why, prior to v3.8.4, this parameter was called poorMansTrailingCommasInConfigStyle). `

Rewrite Rules

To enable a rewrite rule, add it to the config like this rewrite.rules = [Imports].

AvoidInfix

This rule replaces infix expressions a op b with proper method calls a.op(b).

NB: The rule currently does not support right-associative operators (i.e., those which end in :) which would have had to be rewritten as b.op(a).

The rule takes the following parameters under rewrite.avoidInfix:

  • includeFilters and excludeFilters, two lists of regular expressions, which determine which operators are eligible for this rewrite
    • for this rule to be enabled (that is, for the rewrite to be applied), an infix expression must match includeFilters and not match excludeFilters
    • (since 3.8.0) if a regular expression contains \\., matching will be against not only the infix operator but also its left-hand-side expression (with the non-empty operator part following the last \\. in the pattern)
    • (before 3.8.0) these two parameters were nested under rewrite.neverInfix
  • excludePlaceholderArg (default: true) will not rewrite infix expressions if the argument is a solo placeholder (_ or (_: Type))
    • this parameter does not control any other cases with the infix argument containing a placeholder character; some of them will never be rewritten as adding parentheses will change their syntactic meaning, and others will be rewritten as usual
    • (before 3.8.0 and since 3.4.4) this parameter was named rewrite.allowInfixPlaceholderArg
  • (since 3.8.0) excludeScalaTest controls whether the standard set of scalatest assert methods is added to excludeFilters
    • if unspecified, and project.layout determines that the file being formatted is not a test file, then these test assert methods will not be excluded
  • (since 3.8.4) excludePostfix, unless set to true explicitly, will also apply the rule to Term.Select trees specified without a dot
  • (since 3.8.4) excludeMatch, if set to false explicitly and if the dialect enables allowMatchAsOperator (such as Scala 3), will also apply the rule to Term.Match trees specified without a dot
a.success(b)
a.error(b, c)
a map { x =>
  x + 2
}
("o" % "a" % "v").c(D)
(future map { case e: Err =>
  0
}).recover(_.toString)
future.recover { case e: Err =>
  0
} map (_.toString)
a success b
a error (b, c)
a map { x =>
  x + 2
}
"o" % "a" % "v" c(D)
future map {
  case e: Err => 0
} recover (_.toString)
future recover {
  case e: Err => 0
} map (_.toString)

Config for this example:

rewrite.rules = [AvoidInfix]
rewrite.avoidInfix.excludeFilters."+" = [ "map" ]

_.foo(_)
_.bar(_: Int)
_.baz(_.qux)
_ baz _.qux // cannot be rewritten, not the same as previous line
_ foo _
_ bar (_: Int)
_ baz (_.qux)
_ baz _.qux // cannot be rewritten, not the same as previous line

Config for this example:

rewrite.rules = [AvoidInfix]
rewrite.avoidInfix.excludePlaceholderArg = false

RedundantBraces

Warning. This rewrite can cause non-idempotent formatting, see #1055.

def foo =
  List(1, 2, 3).sum
def foo = {
  List(1, 2, 3).sum
}

Config for this example:

rewrite.rules = [RedundantBraces]

q"Hello $name"
q"Hello ${name}"

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.stringInterpolation = true

List(1, 2, 3).map(x => x + 1)
List(1, 2, 3).map { x => x + 1 }

Config for this example:

rewrite.rules = [RedundantBraces]

Entire power of RedundantBraces can be accessed with newlines.afterCurlyLambdaParams=squash. It will try to squash lambda body in one line and then replace braces with parens:

List(1, 2, 3).map(x => x + 1)

List(1, 2, 3).map { x =>
  println("you can't squash me!")
  x + 1
}
List(1, 2, 3).map { x =>
  x + 1
}

List(1, 2, 3).map { x =>
  println("you can't squash me!")
  x + 1
}

Config for this example:

rewrite.rules = [RedundantBraces]
newlines.afterCurlyLambdaParams=squash

RedundantBraces: generalExpressions

Default: rewrite.redundantBraces.generalExpressions = true

while (x < 10)
  x += 1

str match {
  case "a" =>
    println("ok")
  case _ =>
    println("not ok")
}
while (x < 10) {
  x += 1
}

str match {
  case "a" => {
    println("ok")
  }
  case _ => {
    println("not ok")
  }
}

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.generalExpressions = true

RedundantBraces: ifElseExpressions

Default: rewrite.redundantBraces.ifElseExpressions = false

if (a > b)
  doSomething()
else
  doAnything()
if (a > b) {
  doSomething()
} else {
  doAnything()
}

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.ifElseExpressions = true

RedundantBraces: defnBodies

This parameter takes the following values:

  • none: rewriting of a definition body is disabled
  • all: applies to body of any definition (def, val, macro etc.)
  • noParams: applies to body of any definition which doesn't have parameters (e.g.: val; var; parameterless def, without brackets or parentheses)

In v3.3.2, this parameter superseded a boolean methodBodies.

Default: rewrite.redundantBraces.defnBodies = "all"

def f() =
  1 + 1
def f() = {
  1 + 1
}

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.defnBodies = true

RedundantBraces: includeUnitMethods

Default: rewrite.redundantBraces.includeUnitMethods = true

Affects only functions with explicitly specified Unit type

def f() =
  1 + 1

def x(): Unit = {
  println("example")
}
def f() = {
  1 + 1
}

def x(): Unit = {
  println("example")
}

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.methodBodies = true
rewrite.redundantBraces.includeUnitMethods = false

RedundantBraces: stringInterpolation

Default: rewrite.redundantBraces.stringInterpolation = false

s"user id is $id"
s"user id is ${id}"

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.stringInterpolation = true

RedundantBraces: oneStatApply

Added in v3.8.4, controls treatment of single-argument apply delimiters, has lower priority than fewer braces, and takes the following values:

  • parensMaxSpan: if non-negative, converts braces to parentheses in an argument clause if its span is not larger than the specified value (and can be legally used with parentheses)
  • bracesMinSpan: if non-negative, converts parentheses to braces in a single-statement argument clause if its span is strictly larger than the specified value
    • clearly, parensMaxSpan may not exceed bracesMinSpan but might be the same (for convenience of specifying the pivot point)
  • parensMaxSpan=0, bracesMinSpan<0 is a special combination which replaced an earlier parameter parensForOneLineApply = true and uses parens when the argument clause ends up formatted on a single line (rather than looking at the argument clause span)
    • see also newlines.afterCurlyLambdaParams = squash

Here, the span is computed a bit differently than for fewer braces or search optimizer, in that it removes not only whitespace but also all punctuation (opening and closing delimiters, commas, semicolons and dots), comments and any optional syntax tokens in scala3 (such as then, : in coloneol or varargs, end markers etc.), anything that a rewrite rule could modify.

The reason is that this happens during the rewrite phase where this or other rules could modify or remove braces, trim trailing commas, add dots and parentheses to an infix, rewrite scala3 code using new syntax, or reformat comments.

Thus, to avoid non-idempotent formatting, we ignore them.

In all cases, redundant delimiters will be rewritten, as before.

# Defaults
rewrite.redundantBraces.oneStatApply.parensMaxSpan = 0
rewrite.redundantBraces.oneStatApply.bracesMinSpan = -1
xs.map(x => x + 1)
xs.map { x => x + 1 }

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.oneStatApply.parensMaxSpan = 0

xs.map(x => // should rewrite this
  x + 1
)
xs.map {
  x => // should not rewrite this, not a single-stat argument
    x + 1
    x + 2
}
xs.map {
  x => // should not rewrite outer, span too long
    x.foo(
      bar.baz(qux)
    )
}
xs.map { x => // should rewrite this
  x + 1
}
xs.map { x => // should not rewrite this, not a single-stat argument
  x + 1
  x + 2
}
xs.map { x => // should not rewrite outer, span too long
  x.foo {
    bar.baz(qux)
  }
}

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.oneStatApply.parensMaxSpan = 15

xs.map { x => // should rewrite this
  x + 1
}
xs.map( // should not rewrite this, contains an infix with a break before operator
  x
    + 1
)
xs.map { // should rewrite this, contains an infix with a break after operator
  x +
    1
}
// scalafmt: { newlines.infix.termSite.style = some }
xs.map { // should rewrite this, allows formatting infix
  x + 1
}
xs.map( // should not rewrite this, span too short
  xy
)
xs.map(x => // should rewrite this
  x + 1
)
xs.map( // should not rewrite this, contains an infix with a break before operator
  x
  + 1
)
xs.map( // should rewrite this, contains an infix with a break after operator
  x +
  1
)
// scalafmt: { newlines.infix.termSite.style = some }
xs.map( // should rewrite this, allows formatting infix
  x
  + 1
)
xs.map( // should not rewrite this, span too short
  xy)

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.oneStatApply.bracesMinSpan = 2

RedundantBraces: maxBreaks

This parameter limits the number of line breaks inside the input body. Prior to v3.3.2, was incorrectly called maxLines.

Default: rewrite.redundantBraces.maxBreaks = 100

def f() =
  collection
    .map(x => x + 1)
    .filter(_ < 10)
    .map(_ * 2)

def f() = {
  collection
    .map(x => x + 1)
    .filter(_ < 10)
    .map(_ * 2)
    .headOption
}
def f() = {
  collection
    .map(x => x + 1)
    .filter(_ < 10)
    .map(_ * 2)
}

def f() = {
  collection
    .map(x => x + 1)
    .filter(_ < 10)
    .map(_ * 2)
    .headOption
}

Config for this example:

rewrite.rules = [RedundantBraces]
rewrite.redundantBraces.maxBreaks = 3

Inserting braces

Warning: this rewrite might cause non-idempotent formatting, formatter might need to be run twice.

This rule cannot be used with rewrite.scala3.insertEndMarkerMinLines or rewrite.scala3.removeOptionalBraces.oldSyntaxToo == true.

This rewrite in essence provides the opposite of what RedundantBraces achieves, and somewhat similar to Scala3's end marker rewrite rules.

The rule is applied after all whitespace decisions had been made and simply attempts to output curly braces around a single-statement block when it spans at least a given number of lines.

The rule is enabled by configuring rewrite.insertBraces:

  • minLines (default: 0, or disabled): the minimum number of lines to trigger the rule
  • allBlocks (default: false): compute maximum span of all blocks under the parent expression rather than just the statement to be enclosed in curly braces
    • this could be used to have consistent application of curly braces in expressions with multiple sub-expressions (conditions or blocks), such as if-else, try-finally, for-yield, do-while etc.

Here are some limitations:

  • the rule might occasionally lead to non-idempotent formatting (that is, applying the formatter a second time would produce a different result); some examples are:
    • adding braces might overflow a line
    • adding braces might lead to different indentation of infix expressions
  • the rule will not be applied:
    • unless the single statement is preceded by a newline; doing so would definitely lead to non-idempotent formatting
    • if the statement is an infix expression which is not enclosed in parentheses and has a line break before an operator
    • if the code uses Scala3 syntax with significant indentation

RedundantParens

for {
  a <- b
  if a.nonEmpty
} yield a

val z = insertData *> readDatabase(id)
for {
  a <- b
  if (a.nonEmpty)
} yield a

val z = (insertData *> readDatabase(id))

Config for this example:

rewrite.rules = [RedundantParens]

RedundantParens: infixSide

Since v3.5.4.

Parameter rewrite.redundantParens.infixSide controls how the rule applies to expressions which are part of an outer infix expression (either left- or right-hand side). Can take the following values:

  • null (default): rewrites only simple expressions (literals or identifiers)
// null+
foo & 0 // literal
foo & bar // identifier
// some+
foo & (bar.baz) // non-infix
foo & (bar + baz) // very high precedence infix
foo or (bar < baz) // non-symbolic outer op, medium precedence infix
// null+
foo & (0) // literal
foo & (bar) // identifier
// some+
foo & (bar.baz) // non-infix
foo & (bar + baz) // very high precedence infix
foo or (bar < baz) // non-symbolic outer op, medium precedence infix

Config for this example:

rewrite.rules = [RedundantParens]
rewrite.redundantParens.infixSide = null

  • some: additionally, rewrites
    • all non-infix sides
    • very-high-precedence nested infix sides
    • medium-precedence nested infix sides if the outer infix operator is non-symbolic
// some+
foo & bar.baz // non-infix
foo & bar + baz // very high precedence infix
foo or bar < baz // non-symbolic outer op, medium precedence infix
// many+
foo || (bar == baz) // high precedence infix
foo or (bar || baz) // non-symbolic outer op; low precedence infix
foo |: (bar |: baz) // identical op: non-symbolic; right infix, right assoc
(foo :| bar) :| baz // identical op: symbolic; left infix, left assoc
(foo or bar) or baz // identical op: non-symbolic; left infix, left assoc
// some+
foo & (bar.baz) // non-infix
foo & (bar + baz) // very high precedence infix
foo or (bar < baz) // non-symbolic outer op, medium precedence infix
// many+
foo || (bar == baz) // high precedence infix
foo or (bar || baz) // non-symbolic outer op; low precedence infix
foo |: (bar |: baz) // identical op: non-symbolic; right infix, right assoc
(foo :| bar) :| baz // identical op: symbolic; left infix, left assoc
(foo or bar) or baz // identical op: non-symbolic; left infix, left assoc

Config for this example:

rewrite.rules = [RedundantParens]
rewrite.redundantParens.infixSide = some

  • many: additionally, rewrites
    • high-precedence nested infix sides
    • nested infix sides when the operator is identical to the outer infix (and associativity allows)
    • any symbolic nested infix sides if the outer infix operator is non-symbolic
// many+
foo || bar == baz // high precedence infix
foo or bar || baz // non-symbolic outer op; low precedence infix
foo |: bar |: baz // identical op: non-symbolic; right infix, right assoc
foo :| bar :| baz // identical op: symbolic; left infix, left assoc
foo or bar or baz // identical op: non-symbolic; left infix, left assoc
// all
foo || (bar && baz) // low precedence infix
// many+
foo || (bar == baz) // high precedence infix
foo or (bar || baz) // non-symbolic outer op; low precedence infix
foo |: (bar |: baz) // identical op: non-symbolic; right infix, right assoc
(foo :| bar) :| baz // identical op: symbolic; left infix, left assoc
(foo or bar) or baz // identical op: non-symbolic; left infix, left assoc
// all
foo || (bar && baz) // low precedence infix

Config for this example:

rewrite.rules = [RedundantParens]
rewrite.redundantParens.infixSide = many

  • all: rewrites all expressions within an infix
// all
foo || bar && baz // low precedence infix
// all
foo || (bar && baz) // low precedence infix

Config for this example:

rewrite.rules = [RedundantParens]
rewrite.redundantParens.infixSide = all

SortModifiers

Modifiers are sorted based on the given order. Affects modifiers of the following definitions: trait, class, object, type, and val+var, both as fields and class parameters.

implicit final private lazy val x = 42
implicit final private lazy val y = 42

class Test(implicit
    final private val i1: Int,
    final private val i2: String
)

sealed protected[X] trait ADT
final private case object A1 extends ADT
final private case class A2(a: Int)
    extends ADT
final lazy private implicit val x = 42
lazy final implicit private val y = 42

class Test(
    implicit
    final private val i1: Int,
    private final val i2: String
)

sealed protected[X] trait ADT
final private case object A1 extends ADT
private final case class A2(a: Int)
    extends ADT

Config for this example:

rewrite.rules = [SortModifiers]

If you prefer to use the order based on the one partially specified in the Scala Style Guide, you can use the corresponding preset (since v3.8.1):

private implicit final lazy val x = 42
private implicit final lazy val y = 42

class Test(implicit
    private final val i1: Int,
    private final val i2: String
)

protected[X] sealed trait ADT
private final case object A1 extends ADT
private final case class A2(a: Int)
    extends ADT
final lazy private implicit val x = 42
lazy final implicit private val y = 42

class Test(
    implicit
    final private val i1: Int,
    private final val i2: String
)

sealed protected[X] trait ADT
final private case object A1 extends ADT
private final case class A2(a: Int)
    extends ADT

Config for this example:

rewrite.rules = [SortModifiers]
rewrite.sortModifiers.preset = styleGuide

If you choose a custom sort order, you can specify some or all modifiers in the desired order:

implicit final override val x = 2
override implicit final val x = 2

Config for this example:

rewrite.rules = [SortModifiers]
rewrite.sortModifiers.order = [
  "implicit", "final", "sealed", "abstract",
  "override", "private", "protected", "lazy"
]

Hint: since some modifiers are mutually exclusive, you might want to order them next to each other.

If you fail to include some modifiers, they will be moved to the front, before modifiers explicitly configured, while preserving their relative order to each other.

final implicit override val x = 2
override implicit final val x = 2

Config for this example:

rewrite.rules = [SortModifiers]
rewrite.sortModifiers.order = [
  "implicit",  "override"
]

The following modifiers are recognized currently:

  • override
  • private, protected
  • implicit
  • final, sealed, abstract
  • erased, lazy, open, transparent, inline, infix, opaque

PreferCurlyFors

Replaces parentheses into curly braces in for comprehensions that contain multiple enumerator generators.

for {
  a <- as
  b <- bs if b > 2
} yield (a, b)
for(a <- as; b <- bs if b > 2)
 yield (a, b)

Config for this example:

rewrite.rules = [PreferCurlyFors]

This rule accepts the following settings:

  • rewrite.preferCurlyFors.removeTrailingSemicolonsOnly (default: false):
    • if false (default), replaces all semicolons with a newline
    • if true, keeps semicolons unless followed by a newline or single-line comment

Imports

This rule applies to import or, in Scala 3, also export statements found at the top level (source, package or class/object/trait level).

The logic also moves comments attached to each import statement or selector, as follows:

  • all consecutive standalone comments before (no blank lines and not following some other token)
  • the comment right after (possibly after a comma), on the same line
  • only single-line (//) comments are supported; multiline (/*) comments will not be moved and in many cases will likely be removed instead

Since v3.0.0.

Let's define some terminology: an import statement consists of several parts:

  • keyword: import or export
  • one or more comma-separated importers
    • for instance, import foo.bar, foo.baz.{qux => quux} contains two importers, foo.bar and foo.baz.{qux => quux}
  • each importer is split, on the final dot, into
    • reference: foo and foo.baz in the example above
    • selectors: bar and {qux => quux} above

Imports: expand

This parameter will attempt to create a separate line for each selector within a {...}. It replaces the deprecated rule ExpandImportSelectors.

Default: rewrite.imports.expand = false

import a.b
import a.c
import h.k
import h.l
import d.e.f
import d.e.g
import a.{foo => bar, zzzz => _, _}
import a.{
    b,
    c
  }, h.{
    k, l
  }
import d.e.{f, g}
import a.{
    foo => bar,
    zzzz => _,
    _
  }

Config for this example:

rewrite.rules = [Imports]
rewrite.imports.expand = true

Imports: sorting

Sorting is applied as follows:

  • if disabled, no sorting
  • if enabled, it applies to import selectors within one importer
  • if groups are used, sorting will also apply to importers in the same group
    • without groups, multiple import statements will not be sorted
    • importers are sorted one dot-separated label at a time
      • importers foo.bar.baz and foo.bar as fbar will compare:
        • foo and foo: equal
        • bar and bar as fbar: bar comes earlier, just like it does with equivalent scala2 selector syntax {bar => fbar}

Imports: sort = none

This default option causes no sorting.

Imports: sort = original

Replaces the deprecated rule SortImports. The imports are sorted by the groups: symbols, lower-case, upper-case.

import foo.{bar, sand, Random, Zilch}
import foo.{Zilch, bar, Random, sand}

Config for this example:

rewrite.rules = [Imports]
rewrite.imports.sort = original

Imports: sort = ascii

Replaces the deprecated rule AsciiSortImports. The imports are sorted by their Ascii codes.

import foo.{Random, `symbol`, bar, ~>}
import foo.{~>, `symbol`, bar, Random}

Config for this example:

rewrite.rules = [Imports]
rewrite.imports.sort = ascii

Imports: sort = scalastyle

  • Selectors are sorted in a case-insensitive manner (ascii on lowercase), except by first character as follows: non-wildcard symbols, lowercase, uppercase, wildcard.
  • If grouping, import statements are also sorted using case-insensitive order, except by first character in every dot-separated label as follows: symbols (including wildcard), uppercase, lowercase.
import foo._
import foo.`qux`.{`symbol`, ~>, bar, Random}
import foo.Baz.{bar => xyz, _}
import foo.bar.{`symbol`, ~>, bar, Random}
import foo.bar.{Random, bar, ~>, `symbol`}
import foo.Baz.{bar => xyz, _}
import foo.`qux`.{Random, bar, ~>, `symbol`}
import foo._

Config for this example:

maxColumn = 50
rewrite.rules = [Imports]
rewrite.imports.sort = scalastyle
rewrite.imports.groups = [["foo\\..*"]]

Imports: groups

Keep in mind that this functionality should be used very carefully if hierarchical (relative) imports are allowed in your codebase. Groups should only refer to typical top-level domains such as java, org, com or scala, and sorting should be disabled.

The safest way to handle this case is by using scalafix with a semantic rule like OrganizeImports. However, on a large codebase, the overhead of using semantic scalafix rules might be substantial.

This rule will separate all import statements (or, to be more precise, all importers from all import statements) into groups. If sorting is enabled (i.e., not none), imports will also be sorted within each group.

The rule accepts the following parameters:

  • rewrite.imports.groups: defines several sets of regular expressions
    • each set defines a single group, and the groups are output in the order they are configured
    • imports not matching any of the regexes will form their own group at the end
    • regular expressions are applied to the entire parent domain of the import statement, up to and including the final dot
    • the longest patterns are applied first
  • rewrite.imports.contiguousGroups (since v3.0.2):
    • if only (default), only consecutive import statements will be grouped
    • if no, grouping will happen on all imports within the same container (source, package, template etc.)
import foo.Baz.{bar => xyz, _}
import foo._
import foo.`qux`.{
  Random,
  `symbol`,
  bar,
  ~>
}

import bar._
import bar.`qux`.{
  Random,
  `symbol`,
  bar,
  ~>
}
import bar.bar.{
  Random,
  `symbol`,
  bar,
  ~>
}
import bar.bar as bbar
import baz.Baz.{bar => xyz, _}
import baz._
import baz.bar.{
  Random,
  `symbol`,
  bar,
  ~>
}

import qux.Baz.{bar => xyz, _}
import qux.`qux`.{
  Random,
  `symbol`,
  bar,
  ~>
}
import qux.bar.{
  Random,
  `symbol`,
  bar,
  ~>
}
import bar.bar as bbar
import bar.bar.{Random, bar, ~>, `symbol`}
import baz.Baz.{bar => xyz, _}
import qux.`qux`.{Random, bar, ~>, `symbol`}
import foo._
import baz.bar.{Random, bar, ~>, `symbol`}
import qux.Baz.{bar => xyz, _}
import foo.`qux`.{Random, bar, ~>, `symbol`}
import bar._
import qux.bar.{Random, bar, ~>, `symbol`}
import foo.Baz.{bar => xyz, _}
import bar.`qux`.{Random, bar, ~>, `symbol`}
import baz._

Config for this example:

runner.dialect = scala3
rewrite.rules = [Imports]
rewrite.imports.sort = ascii
rewrite.imports.groups = [
  ["foo\\..*"],
  ["bar\\..*", "baz\\..*"]
]

Trailing commas

See SIP

The rule handles how trailing commas are treated in case of a dangling closing delimiter (parenthesis or bracket for definitions or invocations, brace for import statements only).

Regardless of the setting, trailing commas are always removed if the closing delimiter is not dangling (i.e., follows the final argument without a line break).

This logic is not triggered via the rewrite.rules parameter, but by setting parameters within the rewrite.trailingCommas section (since v3.0.5; prior to that there was a single top-level trailingCommas parameter).

Default: rewrite.trailingCommas.style = "never"

Trailing commas: never

Makes sure there are no trailing commas:

import a.{b, c}
def method1(
    a: Int,
    b: Long
) = {}
def method2(
    a: Int,
    b: Long*
) = {}
def method3(
    a: Int
) = {}
method1(
  a,
  b
)
method2(
  a,
  b: _*
)
method3(
  a
)
import a.{
  b,
  c,
}
def method1(
  a: Int,
  b: Long,
) = {}
def method2(
  a: Int,
  b: Long*,
) = {}
def method3(
  a: Int,
) = {}
method1(
  a,
  b,
)
method2(
  a,
  b: _*,
)
method3(
  a,
)

Config for this example:

rewrite.trailingCommas.style = never

Trailing commas: keep

Keeps any trailing commas:

import a.{b, c }
def method1(
    a: Int,
    b: Long,
) = {}
def method2(
    a: Int,
    b: Long*
) = {}
def method3(
    a: Int,
) = {}
method1(
  a,
  b
)
method2(
  a,
  b: _*,
)
method3(
  a,
)
import a.{
  b,
  c,
}
def method1(
  a: Int,
  b: Long,
) = {}
def method2(
  a: Int,
  b: Long*
) = {}
def method3(
  a: Int,
) = {}
method1(
  a,
  b
)
method2(
  a,
  b: _*,
)
method3(
  a,
)

Config for this example:

rewrite.trailingCommas.style = keep

Trailing commas: always

Makes sure there are trailing commas:

import a.{b, c}
def method1(
    a: Int,
    b: Long,
) = {}
def method2(
    a: Int,
    b: Long*,
) = {}
def method3(
    a: Int,
) = {}
method1(
  a,
  b,
)
method2(
  a,
  b: _*,
)
method3(
  a,
)
import a.{
  b,
  c
}
def method1(
  a: Int,
  b: Long
) = {}
def method2(
  a: Int,
  b: Long*
) = {}
def method3(
  a: Int
) = {}
method1(
  a,
  b
)
method2(
  a,
  b: _*
)
method3(
  a
)

Config for this example:

rewrite.trailingCommas.style = always

Trailing commas: multiple

Since v2.5.0.

Makes sure there are trailing commas for multiple-argument expressions only, except when the last argument is repeated:

import a.{b, c}
def method1(
    a: Int,
    b: Long,
) = {}
def method2(
    a: Int,
    b: Long*
) = {}
def method3(
    a: Int
) = {}
method1(
  a,
  b,
)
method2(
  a,
  b: _*
)
method3(
  a
)
import a.{
  b,
  c
}
def method1(
  a: Int,
  b: Long
) = {}
def method2(
  a: Int,
  b: Long*,
) = {}
def method3(
  a: Int,
) = {}
method1(
  a,
  b
)
method2(
  a,
  b: _*,
)
method3(
  a,
)

Config for this example:

rewrite.trailingCommas.style = multiple

rewrite.trailingCommas.allowFolding

This parameter controls whether the trailing comma must be maintained (except for never), or the code can be folded to avoid a dangling closing delimiter which is required by Scala after a trailing comma.

Since v3.0.5

Default: rewrite.trailingCommas.allowFolding = true

If set to false, the trailing comma will always be forced.

rewrite.tokens

Prior to v3.8.4, was called rewriteTokens.

Map of tokens to rewrite. For example, Map("⇒" -> "=>") will rewrite unicode arrows to regular ascii arrows.

Default: rewrite.tokens = {}

val tuple = "a" -> 1
val lambda = (x: Int) => x + 1
for {
  a <- Option(1)
  b <- Option(2)
} yield a + b
val tuple = "a" → 1
val lambda = (x: Int) ⇒ x + 1
for {
  a ← Option(1)
  b ← Option(2)
} yield a + b

Config for this example:

rewrite.tokens = {
  "⇒": "=>"
  "→": "->"
  "←": "<-"
}

Scala3 rewrites

This section describes rules which are applied if the appropriate dialect (e.g., runner.dialect = scala3) is selected.

This logic is not triggered via the rewrite.rules parameter, but by setting parameters under rewrite.scala3 subsection.

rewrite.scala3.convertToNewSyntax

If this flag is enabled, the following new syntax will be applied (also, since 3.8.0, if an appropriate flag under rewrite.scala.newSyntax is not set to false, see below):

  • control syntax
    • if dialect sets allowSignificantIndentation (any scala3 dialect) and ...newSyntax.control is set
      • if (...) to if ... then
      • while (...) to while ... do
      • for (...) to for ... do (or for (...) yield to for ... yield)
  • vararg splices
    • vararg : _* or @ _* to * if dialect sets allowPostfixStarVarargSplices (any scala3, or scala2xxSource3) and ...newSyntax.deprecated is set
  • imports
    • import wildcard _ to * if dialect sets allowStarWildcardImport (any scala3, or scala2xxSource3) and ...newSyntax.deprecated is set
    • import rename => to as if dialect sets allowAsForImportRename (any scala3, or scala2xxSource3) and ...newSyntax.deprecated is set
  • wildcards
    • type wildcard _ to ? if dialect sets allowQuestionMarkAsTypeWildcard (scala212 and later) and ...newSyntax.deprecated is set
    • anonymous type param * to _ if dialect sets allowUnderscoreAsTypePlaceholder (scala3Future only) and ...newSyntax.deprecated is set

NB: You could control these rules individually by overriding dialect properties.

rewrite.scala3.removeOptionalBraces

If this section is enabled, optional braces will be removed and significant indentation applied.

Default: rewrite.scala3.removeOptionalBraces = {"enabled": false, "fewerBracesMinSpan": 2, "fewerBracesMaxSpan": 0, "fewerBracesParensToo": false, "oldSyntaxToo": false}

The section contains the following settings (available since v3.8.1):

  • enabled:
    • if false, disables any rewriting, regardless of other flags in this section
    • if true, enables rewriting
      • applies to expressions using the new control syntax (or those which would rewritten to new syntax if rewrite.scala3.convertToNewSyntax is set)
      • other flags below might extend rewrites to other cases
  • oldSyntaxToo
    • if true, applies also to expressions using deprecated syntax
  • (since v3.8.1) fewerBracesMinSpan and fewerBracesMaxSpan
    • will apply the rewrite to last curried single-argument group if it is enclosed in curly braces (or would be rewritten to curly braces by the RedundantBraces rule)
    • will only apply the rewrite if the cumulative span of all visible (non-whitespace) tokens within the argument is between the two values
    • this rule is disabled if fewerBracesMaxSpan == 0
  • (since v3.8.4) fewerBracesParensToo
    • will apply the rule just above to an argument in parentheses as well, if the one of following is also satisfied:
      • newlines.infix.xxxSite.style is NOT keep; or
      • current dialect supports allowInfixOperatorAfterNL

Prior to v3.8.1, rewrite.scala3.removeOptionalBraces was a flag which took three possible values (with their equivalent current settings shown):

  • no: enabled = false
  • yes: enabled = true
  • oldSyntaxToo: enabled = true and oldSyntaxToo = true

rewrite.scala3.insertEndMarkerMinLines

If this flag is set to a positive value, when an expression containing an optional braces region spans at least as many lines and isn't followed by an end marker, one will be inserted.

We will not insert end markers if the statement is not part of a template body, or a multi-stat block. Doing so might turn a single-stat expression (which doesn't require significant indentation handling) into a multi-stat block.

rewrite.scala3.removeEndMarkerMaxLines

If this flag is set to a positive value, when an expression containing an optional braces region spans at most as many lines and is followed by a standalone end marker (i.e., no other tokens on that line, including comments), the line containing the end marker will be deleted.

We will not remove end markers if

  • the statement is not part of a template body, or a block with at least 3 statements. Doing so might turn a multi-stat expression (which requires significant indentation handling) into a single-stat.
  • there are comments before the end marker, as without the end marker they would be treated as outside of the optional-braces region.

rewrite.scala3.countEndMarkerLines

Since v3.0.6.

This flag dictates which part of the expression terminated by the end marker is used to calculate the span for the purposes of applying insertEndMarkerMinLines and removeEndMarkerMaxLines.

  • all (default): the entire expression
  • lastBlockOnly: only the last block with significant indentation relative to the start of the said expression (as a replacement for the closing curly brace which would have been used otherwise); for instance:
    • in case of a class, this would be the body of the class
    • but for an if-else, this would be just the else part

Vertical Multiline

Since: v1.6.0.

If enabled this formats methods such that parameters are on their own line indented by indent.defnSite. Separation between parameter groups are indented by two spaces less than indent.defnSite. The return type is on its own line at the end.

This formatting is only triggered if the method definition exceeds the maxColumn value in width or if the number of arguments to the method exceeds the verticalMultiline.arityThreshold.

verticalMultiline.arityThreshold

Default: verticalMultiline.arityThreshold = 100

case class Foo(x: String)
case class Bar(
    x: String,
    y: String)
object A {
  def foo(
      x: String,
      y: String
    )
  def hello(
      how: String
    )(are: String
    )(you: String
    ) = how + are + you
}
case class Foo(x: String)
case class Bar(x: String, y: String)
object A {
  def foo(x: String, y: String)
  def hello(how: String)(are: String)(you: String) = how + are + you
}

Config for this example:

verticalMultiline.atDefnSite = true
verticalMultiline.arityThreshold = 2

verticalMultiline.newlineAfterOpenParen

Default: verticalMultiline.newlineAfterOpenParen = false

def other(
  a: String,
  b: String
)(
  c: String,
  d: String
) = a + b + c
def other(a: String, b: String)(c: String, d: String) = a + b + c

Config for this example:

indent.defnSite = 2
verticalMultiline.atDefnSite = true
verticalMultiline.arityThreshold = 2
verticalMultiline.newlineAfterOpenParen = true

verticalMultiline.excludeDanglingParens

This parameter has been removed in 3.4.0, please use danglingParentheses.exclude.

def other(
  a: String,
  b: String
)(
  c: String,
  d: String) = a + b + c
other(a, b)(c, d)
def other(a: String, b: String)(c: String, d: String) = a + b + c
other(a, b)(c, d)

Config for this example:

indent.defnSite = 2
danglingParentheses.exclude = [def]
verticalMultiline.atDefnSite = true
verticalMultiline.arityThreshold = 2
verticalMultiline.newlineAfterOpenParen = true

Vertical multiline with implicit parameter lists

Also see the general section on implicit parameter lists.

Before only

def format(
    code: String,
    age: Int
  )(
    implicit ev: Parser,
    c: Context
  ): String
def format(code: String, age: Int)(implicit ev: Parser, c: Context): String

Config for this example:

maxColumn = 60
verticalMultiline.atDefnSite = true
newlines.implicitParamListModifierForce = [before]

After only

def format(
    code: String,
    age: Int
  )(implicit
    ev: Parser,
    c: Context
  ): String
def format(code: String, age: Int)(implicit ev: Parser, c: Context): String

Config for this example:

maxColumn = 60
verticalMultiline.atDefnSite = true
newlines.implicitParamListModifierForce = [after]

Before and after

def format(
    code: String,
    age: Int
  )(
    implicit
    ev: Parser,
    c: Context
  ): String
def format(code: String, age: Int)(implicit ev: Parser, c: Context): String

Config for this example:

maxColumn = 60
verticalMultiline.atDefnSite = true
newlines.implicitParamListModifierForce = [before,after]

Comment processing

comments.wrap

Since v2.6.0.

Allows wrapping comments exceeding maxColumn.

Default: comments.wrap = "no"

comments.wrap = standalone

A standalone comment is one which is surrounded by line breaks.

/* long multiline
 * comment */
// long singleline comment
val a = 1 // short
val b =
  2 // long singleline comment
/* long multiline comment */
// long singleline comment
val a = 1 // short
val b = 2 // long singleline comment

Config for this example:

maxColumn = 20
comments.wrap = standalone

comments.wrap = trailing

A trailing comment is one which is followed by a line break.

/* long multiline
 * comment */
// long singleline comment
val a = 1 // short
val b =
  2 /* long
   * singleline
   * comment */
/* long multiline comment */
// long singleline comment
val a = 1 // short
val b = 2 // long singleline comment

Config for this example:

maxColumn = 20
comments.wrap = trailing

comments.wrapStandaloneSlcAsSlc

Since v2.6.0.

This parameter allows formatting a standalone single-line comment (i.e., //) to be wrapped using the same type, not a multi-line comment (/* ... */).

Default: comments.wrapStandaloneSlcAsSlc = false

// long singleline comment
val b =
  2 /* long
   * singleline
   * comment */
// long singleline comment
val b = 2 // long singleline comment

Config for this example:

maxColumn = 20
comments.wrap = trailing
comments.wrapStandaloneSlcAsSlc = true

comments.wrapSingleLineMlcAsSlc

Since v3.3.1.

If comment wrapping is enabled (comments.wrap != no), this parameter allows formatting a trailing or standalone multi-line comment (i.e., /* ... */) as a single-line comment (//) if it occupies a single line.

Default: comments.wrapSingleLineMlcAsSlc = false

// standalone multi-line comment
val b = 2 /* mlc */ // trailing mlc
/* standalone multi-line comment */
val b = 2 /* mlc */ /* trailing mlc */

Config for this example:

maxColumn = 50
comments.wrap = trailing
comments.wrapSingleLineMlcAsSlc = true

docstrings.style

Since v2.6.0.

Default: docstrings.style = "SpaceAsterisk"

docstrings.style = keep

Prohibits formatting of docstrings. All other docstrings parameters are ignored.

Since v3.0.0.

/**   do not touch
 * this style
  * keep the text as-is
*/
/**   do not touch
 * this style
  * keep the text as-is
*/

Config for this example:

docstrings.style = keep

docstrings.style = Asterisk

This variant used to be called JavaDoc.

/**
 * Skip first line, format intermediate
 * lines with an asterisk below the
 * first asterisk of the first line (aka
 * JavaDoc). Since v3.8.4,
 * `blankFirstLine = fold` takes
 * precedence.
 */
/** Skip first line, format intermediate lines with an asterisk
  * below the first asterisk of the first line (aka JavaDoc).
  * Since v3.8.4, `blankFirstLine = fold` takes precedence.
  */

Config for this example:

docstrings.style = Asterisk

docstrings.style = SpaceAsterisk

This variant used to be called ScalaDoc.

/** Format intermediate lines with a
  * space and an asterisk, both below
  * the two asterisks of the first line
  */
/** Format intermediate lines with a space and an asterisk,
 * both below the two asterisks of the first line
 */

Config for this example:

docstrings.style = SpaceAsterisk

docstrings.style = AsteriskSpace

/** Format intermediate lines with an
 *  asterisk and a space, both below the
 *  two asterisks of the first line
 */
/** Format intermediate lines with an asterisk and a space,
  * both below the two asterisks of the first line
  */

Config for this example:

docstrings.style = AsteriskSpace

docstrings.removeEmpty

If set, will cause empty docstrings to be removed.

Since v3.0.4.

Default: docstrings.removeEmpty = false

val a = 1
/** */
/**
  *
  */
/** */ /** */
val a = 1

Config for this example:

docstrings.removeEmpty = true

docstrings.oneline

Since v2.6.0. Ignored for docstrings.style = keep.

Default: docstrings.oneline = "keep"

docstrings.oneline = fold

/** Scaladoc oneline */
/** Scaladoc multiline */
val a = 1
/** Scaladoc oneline */
/**
  * Scaladoc multiline
  */
val a = 1

Config for this example:

docstrings.style = Asterisk
docstrings.oneline = fold

docstrings.oneline = unfold

/**
 * Scaladoc oneline
 */
/**
 * Scaladoc multiline
 */
val a = 1
/** Scaladoc oneline */
/**
  * Scaladoc multiline
  */
val a = 1

Config for this example:

docstrings.style = Asterisk
docstrings.oneline = unfold

docstrings.oneline = keep

/** Scaladoc oneline */
/**
 * Scaladoc multiline
 */
val a = 1
/** Scaladoc oneline */
/**
  * Scaladoc multiline
  */
val a = 1

Config for this example:

docstrings.style = Asterisk
docstrings.oneline = keep

docstrings.wrap

Will parse scaladoc comments and reformat them. Takes the following values:

  • keep: preserves scaladoc comments as-is and will not reformat them (replaced no in v3.8.2)
  • fold: will use a more compact, horizontal formatting (added in v3.8.2)
  • unfold: will use a more expanded, vertical formatting (replaced yes in v3.8.2)

This functionality is generally limited to standard scaladoc elements and might lead to undesirable results in corner cases; for instance, the scaladoc parser doesn't have proper support of embedded HTML.

However, tables are supported.

Since v2.6.0. Ignored for docstrings.style = keep.

Default: docstrings.wrap = "unfold"

/** @param d
  *   the Double to square,
  *   meaning multiply by
  *   itself
  * @return
  *   the result of squaring d
  *
  * Thus
  *   - if [[d]] represents a
  *     negative value:
  *     a. the result will be
  *        positive
  *     a. the value will be
  *        {{{d * d}}}
  *     a. it will be the same
  *        as for `-d`
  *   - however, if [[d]] is
  *     positive
  *     - the value will still
  *       be {{{d * d}}}
  *       - i.e., the same as
  *         {{{(-d) * (-d)}}}
  *
  * In other words:
  * {{{
  *    res = d * d
  *        = (-d) * (-d)
  * }}}
  */
def pow2(d: Double): Double
/**
 * @param d the Double to square, meaning multiply by itself
 * @return the result of squaring d
 *
 * Thus
 * - if [[d]] represents a negative value:
 *  a. the result will be positive
 *  a. the value will be {{{d * d}}}
 *  a. it will be the same as for `-d`
 * - however, if [[d]] is positive
 *  - the value will still be {{{d * d}}}
 *    - i.e., the same as {{{(-d) * (-d)}}}
 *
 * In other words:
 * {{{
 *    res = d * d
 *        = (-d) * (-d) }}}
 */
def pow2(d: Double): Double

Config for this example:

docstrings.wrap = yes
maxColumn = 30

docstrings.wrapMaxColumn

If wrapping (or applying oneline), allows specifying a different value than the default maxColumn.

docstrings.blankFirstLine

Controls whether to force the first line to be blank in a multiline docstring. Some values of docstrings.style might take precedence. Takes the following values:

  • keep: preserves the first line as-is
  • fold: will ensure there's no blank first line (default; replaced no in v3.8.2)
  • unfold: will enforce a blank first line (replaced yes in v3.8.2)

Since v2.7.5.

  • Ignored for docstrings.style = keep or docstrings.wrap = no.
  • [since v3.8.4] For docstrings.style = Asterisk, only fold changes default behaviour.
/** Scaladoc oneline */
/** Scaladoc multiline1
  */
/** Scaladoc multiline2
  */
val a = 1
/** Scaladoc oneline */
/** Scaladoc multiline1
  */
/**
  * Scaladoc multiline2
  */
val a = 1

Config for this example:

# do not force a blank first line
docstrings.blankFirstLine = fold
docstrings.style = SpaceAsterisk
maxColumn = 30

/** Scaladoc oneline */
/**
  * Scaladoc multiline1
  */
/**
  * Scaladoc multiline2
  */
val a = 1
/** Scaladoc oneline */
/** Scaladoc multiline1
  */
/**
  * Scaladoc multiline2
  */
val a = 1

Config for this example:

# force a blank first line
docstrings.blankFirstLine = unfold
docstrings.style = SpaceAsterisk
maxColumn = 30

/** Scaladoc oneline */
/** Scaladoc multiline1
  */
/** Scaladoc multiline2
  */
val a = 1
/** Scaladoc oneline */
/** Scaladoc multiline1
  */
/**
  * Scaladoc multiline2
  */
val a = 1

Config for this example:

# preserve a blank first line
docstrings.blankFirstLine = keep
docstrings.style = SpaceAsterisk
maxColumn = 30

docstrings.forceBlankLineBefore

If true (default), always insert a blank line before docstrings. If false, preserves blank line only if one exists before.

Since v3.4.0. Replaced deprecated optIn.forceBlankLineBeforeDocstring.

object Stuff {

  /** Some function */
  def hello = ()
}
object Stuff {
  /** Some function */
  def hello = ()
}

Config for this example:

docstrings.forceBlankLineBefore = true

object Stuff {
  /** Some function */
  def hello = ()
}
object Stuff {
  /** Some function */
  def hello = ()
}

Config for this example:

docstrings.forceBlankLineBefore = false

Disabling or customizing formatting

Search state exploded

If this exception occurs, you can try increasing optimizer limits, globally or using any of the options further in this section.

For code block

There is a possibility to override scalafmt config for a specific code with // scalafmt: {} comment:

// scalafmt: { align.preset = most, danglingParentheses.preset = false }
libraryDependencies ++= Seq(
  "org.scalameta"  %% "scalameta"  % scalametaV,
  "org.scalacheck" %% "scalacheck" % scalacheckV)

// scalafmt: { align.preset = some, danglingParentheses.preset = true } (back to defaults)
libraryDependencies ++= Seq(
  "org.scalameta" %% "scalameta" % scalametaV,
  "org.scalacheck" %% "scalacheck" % scalacheckV
)
// scalafmt: { align.preset = most, danglingParentheses.preset = false }
libraryDependencies ++= Seq(
  "org.scalameta" %% "scalameta" % scalametaV,
  "org.scalacheck" %% "scalacheck" % scalacheckV)

// scalafmt: { align.preset = some, danglingParentheses.preset = true } (back to defaults)
libraryDependencies ++= Seq(
  "org.scalameta" %% "scalameta" % scalametaV,
  "org.scalacheck" %% "scalacheck" % scalacheckV)

// format: off

Disable formatting for specific regions of code by wrapping them in // format: off blocks:

// format: off
val identity = Array(1, 0, 0,
                     0, 1, 0,
                     0, 0, 1)
// format: on
// format: off
val identity = Array(1, 0, 0,
                     0, 1, 0,
                     0, 0, 1)
// format: on

Since v3.8.4, these format on-off tags can be configured:

  • formatOff: tags to turn formatting off
  • formatOn: tags to turn formatting back on
# Defaults
formatOff = ["@formatter:off", "format: off"]
formatOn = ["@formatter:on", "format: on"]

Project

Configure which source files should be formatted in this project.

project.git

If this boolean flag is set, only format files tracked by git.

project.include/exclude

Since v3.0.0.

# Defaults
project.includePaths = ["glob:**.scala", "glob:**.sbt", "glob:**.sc", "glob:**.mill"]
project.excludePaths = []

Allows specifying PathMatcher selection patterns to identify further which files are to be formatted (explicit glob: or regex: prefixes are required; keep in mind that PathMatcher patterns must match the entire path).

For instance,

project {
  includePaths = [
    "glob:**.scala",
    "regex:.*\\.sc"
  ]
  excludePaths = [
    "glob:**/src/test/scala/**.scala"
  ]
}

project.layout

Allows specifying a project structure naming convention which can be used to select an appropriate dialect for cross-building if one is explicitly selected via fileOverride. By default, it's disabled (null).

Currently, the following options are supported:

  • (since v3.2.0) StandardConvention: this is the usual naming convention putting scala source code under src/main/scala or src/test/scala, with alternate cross-build dialects in src/main/scala-2.13

If this parameter is set, some supported dialects will be determined automatically; if the detected dialect is compatible with the overall one (runner.dialect), no change will be applied.

Currently, supports scala binary versions 2.10-2.13 as well as 3; also, if the version is major scala 2 (i.e., scala-2), will select the scala 2.13 dialect.

fileOverride

Since v2.5.0.

  • This parameter does not modify which files are formatted.
  • The match pattern will be applied to the entire absolute, canonical file name; it is not a suffix or a substring match.

Allows specifying an additional subset of parameters for each file matching a PathMatcher pattern (e.g., a glob or a regex):

fileOverride {
  "<PathMatcher pattern>" { # must match the entire filename
    <overridden parameters>
  }
}

For instance,

align.preset = none
fileOverride {
  "glob:**.sbt" {
    align.preset = most
  }
  "glob:**/src/test/scala/**.scala" {
    maxColumn = 120
    binPack.callSite = true
  }
}

uses align.preset=none for all files except .sbt for which align.preset=most will apply. It will also use different parameters for test suites.

File names will be matched against the patterns in the order in which they are specified in the configuration file, in case multiple patterns match a given file.

The parameter also allows the following shortcuts:

  • (since v3.2.0) setting only the dialect:
    • fileOverride { "glob:**/*.sbt" = sbt1 }
  • (since v3.2.0) setting based on the file extension:
    • fileOverride { ".sbt" { runner.dialect = sbt1 } }
    • this is simply a shortcut for glob:**.ext
  • (since v3.2.0) setting based on the language:
    • fileOverride { "lang:scala-2" = scala213 }
    • requires project.layout (sets dialect for minor versions)
    • these patterns will be matched last

Spaces

spaces.beforeContextBoundColon

This parameter controls if a space should be used before a colon that precedes type context bounds and takes values never, always, ifMultipleBounds, and (added in v3.8.6) ifMultipleContextBounds. The difference between the latter two is: the first considers all bounds (including subtype and supertype), whereas the second only the context bounds.

Default: spaces.beforeContextBoundColon = "Never"

def method[A: Bound]: B
def method[A: Bound]: B
def method[A: Bound: Bound2]: B
def method[A: Bound]: B
def method[A : Bound]: B
def method[A: Bound: Bound2]: B

Config for this example:

spaces.beforeContextBoundColon=Never

def method[A : Bound]: B
def method[A : Bound]: B
def method[A : Bound : Bound2]: B
def method[A: Bound]: B
def method[A : Bound]: B
def method[A: Bound: Bound2]: B

Config for this example:

spaces.beforeContextBoundColon=Always

def method[A: Bound]: B
def method[A: Bound]: B
def method[A : Bound : Bound2]: B
def method[A <: Bound : Bound2]: B
def method[A: Bound]: B
def method[A : Bound]: B
def method[A: Bound: Bound2]: B
def method[A <: Bound: Bound2]: B

Config for this example:

spaces.beforeContextBoundColon=IfMultipleBounds

def method[A: Bound]: B
def method[A: Bound]: B
def method[A : Bound : Bound2]: B
def method[A <: Bound: Bound2]: B
def method[A: Bound]: B
def method[A : Bound]: B
def method[A: Bound: Bound2]: B
def method[A <: Bound: Bound2]: B

Config for this example:

spaces.beforeContextBoundColon=IfMultipleContextBounds

spaces.withinContextBoundBraces

This parameter controls if a space should be used within braces which surround type context bounds and takes the same values as beforeContextBoundColon above. Added in v3.8.6.

Default: spaces.withinContextBoundBraces = "Never"

def method[A: {Bound}]: B
def method[A: {Bound, Bound2}]: B
def method[A: {Bound}]: B
def method[A: {Bound, Bound2}]: B

Config for this example:

runner.dialect = scala3
spaces.withinContextBoundBraces=Never

def method[A: { Bound }]: B
def method[A: { Bound, Bound2 }]: B
def method[A: {Bound}]: B
def method[A: {Bound, Bound2}]: B

Config for this example:

runner.dialect = scala3
spaces.withinContextBoundBraces=Always

def method[A: {Bound}]: B
def method[A <: Bound: { Bound2 }]: B
def method[A: { Bound, Bound2 }]: B
def method[A: {Bound}]: B
def method[A <: Bound : {Bound2}]: B
def method[A: {Bound, Bound2}]: B

Config for this example:

runner.dialect = scala3
spaces.withinContextBoundBraces=IfMultipleBounds

def method[A: {Bound}]: B
def method[A <: Bound: {Bound2}]: B
def method[A: { Bound, Bound2 }]: B
def method[A: {Bound}]: B
def method[A <: Bound : {Bound2}]: B
def method[A: {Bound, Bound2}]: B

Config for this example:

runner.dialect = scala3
spaces.withinContextBoundBraces=IfMultipleContextBounds

spaces.inImportCurlyBraces

Default: spaces.inImportCurlyBraces = false

import a.b.{ c, d }
import a.b.{c, d}

Config for this example:

spaces.inImportCurlyBraces=true

spaces.inInterpolatedStringCurlyBraces

Since v3.0.0.

Default: spaces.inInterpolatedStringCurlyBraces = false

s"Hello ${ the } world!"
s"Hello ${ th.e } world!"
s"Hello ${ the() } world!"
s"Hello ${the} world!"
s"Hello ${ th.e} world!"
s"Hello ${the() } world!"

Config for this example:

spaces.inInterpolatedStringCurlyBraces = true

s"Hello ${oneHundred}% world!"
s"Hello ${th.e} world!"
s"Hello ${the()} world!"
s"Hello ${ oneHundred }% world!"
s"Hello ${ th.e} world!"
s"Hello ${the() } world!"

Config for this example:

spaces.inInterpolatedStringCurlyBraces = false

spaces.inParentheses

Default: spaces.inParentheses = false

foo( a, b )
foo(a, b)

Config for this example:

spaces.inParentheses=true

spaces.neverAroundInfixTypes

Default: spaces.neverAroundInfixTypes = []

def f: Foo##Repr
def g: Foo \/ Repr
// usage same operator not as type
def e = a ## b
def f: Foo##Repr
def g: Foo\/Repr
// usage same operator not as type
def e = a##b

Config for this example:

spaces.neverAroundInfixTypes=["##"]

spaces.aroundSymbolicInfixOperators

Added in v3.8.3, this parameter controls spaces around some infix operators (unless spaces.neverAroundInfixTypes above applies).

This parameter contains two subparameters, include and exclude, each either a string containing a regex, or a list of regex alternatives. By default, include is .* (i.e., matches everything) and exclude is ^$ (matches nothing), thus all infix operators would use a space.

The logic is applied as follows:

  • first, the infix operator must be symbolic (i.e., does not start with a letter or underscore) and not an assignment; otherwise, space is enforced;
  • if the two characters on either side of the proposed space (i.e., the last character of the left-hand side and the first character of the operator, for spaces before the operator, or the last character of the operator and the first character of the right-hand side for spaces after the operator) can both be part of a symbolic operator, the space is enforced;
  • otherwise, if the operator doesn't match any of the include patterns or matches one of the exclude patterns, the space is not output.
def f: Foo##Repr
def g(a: Column, b: Column): Boolean = a===b || a ### b
def e(a: Int, b: Int) = a##b || a==b || a != b
def f: Foo ## Repr
def g(a: Column, b: Column): Boolean = a === b || a###b
def e(a: Int, b: Int) = a ## b || a == b || a!=b

Config for this example:

maxColumn = 80
spaces.aroundSymbolicInfixOperators.include = ".*" # default
spaces.aroundSymbolicInfixOperators.exclude = [ "^##$", "==" ]

spaces.afterKeywordBeforeParen

Default: spaces.afterKeywordBeforeParen = true

if(a) println("HELLO!")
while(a) println("HELLO!")
if (a) println("HELLO!")
while (a) println("HELLO!")

Config for this example:

spaces.afterKeywordBeforeParen = false

spaces.inByNameTypes

Default: spaces.inByNameTypes = true

def foo(a: =>A): A
def foo(a: => A): A

Config for this example:

spaces.inByNameTypes = false

spaces.afterSymbolicDefs

Default: spaces.afterSymbolicDefs = false

def +++ (a: A): F[A]
def +++(a: A): F[A]

Config for this example:

spaces.afterSymbolicDefs=true

spaces.beforeXxxArgInParens

Since v3.7.13.

These parameters control whether a space should be added before an argument of a function call or infix expression, if the argument is enclosed in parentheses.

They take the following values:

  • Never: no space is added
  • Always: space is added
  • AfterSymbolic: space is added if the infix operator or function name is symbolic (doesn't start with a letter or underscore)

Please note that these parameters will not affect spacing after an unary operator (i.e., one of +, -, !, ~), as it's neither a function call nor an infix.

Also, spaces.beforeApplyArgInParens generalizes the special-case parameter spaces.afterTripleEquals which only applies to a === function call.

# Defaults
spaces.beforeApplyArgInParens = "Never"
spaces.beforeInfixArgInParens = "Always"
+(baz)
=== (baz)
bar (baz)

foo + (baz)
foo === (baz)
foo bar (baz)
+(baz)
===(baz)
bar(baz)

foo +(baz)
foo ===(baz)
foo bar(baz)

Config for this example:

spaces.beforeApplyArgInParens = Always
spaces.beforeInfixArgInParens = Always

+(baz)
===(baz)
bar(baz)

foo +(baz)
foo ===(baz)
foo bar(baz)
+ (baz)
=== (baz)
bar (baz)

foo + (baz)
foo === (baz)
foo bar (baz)

Config for this example:

spaces.beforeApplyArgInParens = Never
spaces.beforeInfixArgInParens = Never

+(baz)
=== (baz)
bar(baz)

foo + (baz)
foo === (baz)
foo bar(baz)
+ (baz)
===(baz)
bar (baz)

foo +(baz)
foo ===(baz)
foo bar (baz)

Config for this example:

spaces.beforeApplyArgInParens = AfterSymbolic
spaces.beforeInfixArgInParens = AfterSymbolic

spaces.afterColonInMatchPattern

Since v3.8.3.

Default: spaces.afterColonInMatchPattern = "Always"

This parameter controls whether to output a space between a colon and a type in typed match patterns. It takes the following values:

  • Always:
foo match {
  case e: Etype | f: Ftype =>
  case g: Gtype            =>
}
foo match {
  case e: Etype | f: Ftype =>
  case g: Gtype =>
}

Config for this example:

spaces.afterColonInMatchPattern = always

  • Never:
foo match {
  case e:Etype | f:Ftype =>
  case g:Gtype           =>
}
foo match {
  case e: Etype | f: Ftype =>
  case g: Gtype =>
}

Config for this example:

spaces.afterColonInMatchPattern = never

  • NoAlternatives (when there are no pipe-separated alternatives):
foo match {
  case e:Etype | f:Ftype =>
  case g: Gtype          =>
}
foo match {
  case e: Etype | f: Ftype =>
  case g: Gtype =>
}

Config for this example:

spaces.afterColonInMatchPattern = noAlternatives

Literals

Since v2.5.0.

Scalafmt allows flexible configuration of Integer and Floating Point literals formatting.

Default formatting:

123L
0xfff
0x1abL
10e-1
10e-1d
0b111
0b111L
123l
0XFff
0x1Abl
10E-1
10e-1D
0B111
0b111l

Each literals.* setting has three available options: Upper, Lower, Unchanged.

literals.long

Default: literals.long = "Upper"

Responsible for the case of Long literals suffix L

123L
123l

Config for this example:

literals.long=Upper

literals.float

Default: literals.float = "Lower"

Responsible for the case of Float literals suffix F

42.0f
42.0F

Config for this example:

literals.float=Lower

literals.double

Default: literals.double = "Lower"

Responsible for the case of Double literals suffix D

42.0d
42.0d

Config for this example:

literals.double=Lower

literals.hexPrefix

Default: literals.hexPrefix = "Lower"

Responsible for the case of hex integer literals prefix 0x

0x123
0X123

Config for this example:

literals.hexPrefix=Lower

literals.hexDigits

Default: literals.hexDigits = "Lower"

Responsible for the case of hex integer literals digits

0xaaaa
0xaaaaL
0xaAaA
0xaAaAl

Config for this example:

literals.hexDigits=Lower
literals.long=Upper

literals.binPrefix

Since v3.8.4.

Default: literals.binPrefix = "Lower"

Responsible for the case of binary integer literals prefix 0b

0b111
0b111L
0B111
0B111l

Config for this example:

literals.binPrefix=Lower
literals.long=Upper

literals.scientific

Default: literals.scientific = "Lower"

Responsible for the case of Double literals exponent part

10E-1
10E-1f
10e-1
10e-1f

Config for this example:

literals.scientific=Upper
literals.float=Lower

XML

Controls formatting of Scala embedded within XML.

xmlLiterals.assumeFormatted

Since v2.6.0.

If set, formats embedded Scala relative to containing XML, making the assumption that XML itself is properly formatted. Otherwise, formatting is relative to the outer Scala code which contains the XML literals.

Default: xmlLiterals.assumeFormatted = false

object Example2 {
  def apply() = {
      <foo>
        <bar>{
          (1 + 2 + 3).toString(
            "some long format"
          )
        }</bar>
      </foo>
  }
}
object Example2 {
  def apply() = {
      <foo>
        <bar>{ (1 + 2 + 3).toString("some long format") }</bar>
      </foo>
  }
}

Config for this example:

maxColumn = 40
xmlLiterals.assumeFormatted = true

object Example2 {
  def apply() = {
    <foo>
        <bar>{
      (1 + 2 + 3).toString(
        "some long format"
      )
    }</bar>
      </foo>
  }
}
object Example2 {
  def apply() = {
      <foo>
        <bar>{ (1 + 2 + 3).toString("some long format") }</bar>
      </foo>
  }
}

Config for this example:

maxColumn = 40
xmlLiterals.assumeFormatted = false

Binpacking

binPack presets

One can specify the following values to binPack.preset:

  • never or false:
    • callSite = Never
    • defnSite = Never
    • parentConstructors = Never
  • Always or true:
    • callSite = Always
    • defnSite = Always
    • parentConstructors = Always
  • Oneline:
    • callSite = Oneline
    • defnSite = Oneline
    • parentConstructors = Oneline
  • Onelinesjs:
    • callSite = OnelineSjs
    • defnSite = OnelineSjs
    • parentConstructors = Oneline

The rest of parameters retain their default behaviour.

Literal argument lists

This group of parameters controls binpacking of an argument list if all arguments are considered to be literals. These parameters take precedence over forcing of config style.

The following parameters affect this behaviour:

  • binPack.literalArgumentLists: if false, this behaviour is disabled, other parameters ignored
  • binPack.literalsMinArgCount: doesn't apply binpacking to calls with fewer arguments
  • binPack.literals{Include,Exclude}: lists of regular expressions which define a literal
  • (since v2.5.0) binPack.literalsIncludeSimpleExpr: allows a few selects (i.e. a.b), followed by a few nested single-argument apply calls, with literals as arguments
    • since v3.3.2, also includes new
  • (since v2.5.0) binPack.literalsSingleLine: the entire argument list will be formatted on one line, regardless of maxColumn
# Defaults
binPack.literalArgumentLists = true
binPack.literalsMinArgCount = 5
binPack.literalsInclude = [".*"]
binPack.literalsExclude = ["String", "Term.Name"]
binPack.literalsIncludeSimpleExpr = false
binPack.literalsSingleLine = false
val secret: List[Bit] = List(0, 0, 1, 1,
  1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1,
  0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0,
  1, 0, 0, 0, 1, 0, 1)
val secret: List[Bit] = List(0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1,
  0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1)

Config for this example:

binPack.literalArgumentLists = true

val secret: List[Bit] = List(
  0,
  0,
  1,
  1,
  1,
  1,
  1,
  0,
  0,
  1,
  1,
  0,
  1
)
val secret: List[Bit] = List(0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1)

Config for this example:

binPack.literalArgumentLists = false

val secret: List[Bit] = List(
  0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1)
val secret: List[Bit] = List(0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1,
  0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1)

Config for this example:

binPack.literalArgumentLists = true
binPack.literalsSingleLine = true

binPack.parentConstructors

Parent constructors are B (since 3.4.1), C and D in class A extends B with C and D. Changed from a boolean to a wider set of options in v2.6.0.

Default: binPack.parentConstructors = "source"

The behaviour of binPack.parentConstructors = source depends on the value of newlines.source; keep maps to keep and attempts to preserve the space if there's no line break in the source, fold maps to Oneline, rest to Never.

binPack.parentConstructors=Always

This option attempts to binpack parents, formatting as many on each line as will fit.

object A {
  trait Foo
      extends Bar with Baz
  trait Foo
      extends Bar with Baz
}
object A {
  trait Foo
  extends Bar
  with Baz
  trait Foo extends Bar with Baz
}

Config for this example:

binPack.parentConstructors = Always
maxColumn = 30

binPack.parentConstructors=Never

This option will attempt to format the entire declaration on one line (starting with class or trait and including all parents); otherwise, will enforce breaks before each.

object A {
  trait Foo
      extends Bar
      with Baz
}
object A {
  trait Foo extends Bar with Baz
}

Config for this example:

binPack.parentConstructors = Never
maxColumn = 30

binPack.parentConstructors=Oneline

This option will attempt to format all parents on one line (starting with extends and including all parents); otherwise, will enforce breaks before each.

object A {
  class Foo(a: Int)
      extends Bar with Baz

  class Foo(
      a: Int
  ) extends Bar with Baz
}
object A {
  class Foo(a: Int)
  extends Bar
  with Baz

  class Foo(
    a: Int
  )
  extends Bar
  with Baz
}

Config for this example:

binPack.parentConstructors = Oneline
maxColumn = 30

binPack.parentConstructors=OnelineIfPrimaryOneline

This option will attempt to format all parents on one line (from extends and including all parents), but only if the primary constructor fits on one line as well (the same or previous); otherwise, will enforce breaks before each.

object A {
  class Foo(a: Int, b: Int)
      extends Bar with Baz

  class Foo(
      a: Int,
      b: Int
  ) extends Bar
      with Baz
}
object A {
  class Foo(a: Int, b: Int)
  extends Bar
  with Baz

  class Foo(
    a: Int,
    b: Int
  ) extends Bar with Baz
}

Config for this example:

binPack.parentConstructors = OnelineIfPrimaryOneline
maxColumn = 30

binPack.parentConstructors=keep

This option attempts to preserve breaks before each parent.

object A {
  class Foo(a: Int, b: Int) extends Bar(
        a,
        b
      ) with Baz
      with Qux
  class Foo(a: Int, b: Int)
      extends Bar(
        a,
        b
      ) with Baz
      with Qux
}
object A {
  class Foo(a: Int, b: Int) extends Bar(
    a,
    b
  ) with Baz
  with Qux
  class Foo(a: Int, b: Int)
    extends Bar(
      a,
      b
    ) with Baz
    with Qux
}

Config for this example:

binPack.parentConstructors = keep

binPack.parentConstructors=ForceBreak

This option will enforce a break before each parent. As usual, the break is only actually introduced if indented position on the next line is less than the current. Added in 3.8.4.

object A {
  class Foo(a: Int)
      extends Bar
      with Baz
  class Foo(
      a: Int,
      b: Int,
      c: String,
      d: Double
  ) extends Bar
      with Baz
}
object A {
  class Foo(a: Int) extends Bar with Baz
  class Foo(a: Int, b: Int, c: String, d: Double) extends Bar with Baz
}

Config for this example:

binPack.parentConstructors = ForceBreak
maxColumn = 45

binPack.xxxSite

Controls binpacking around method/type definition sites (binPack.defnSite) or method call sites (binPack.callSite) (both were called unsafeXxxSite up until v3.8.1). The following parameter values are supported since v3.0.0:

  • Never disables the functionality (also takes false)
  • Always enables the functionality (also takes true)
  • Oneline ensures multiline arguments are not binpacked, that is, they cannot be on the same line as any other argument; also, if the multiline argument is last and the call site is followed by either a curried argument clause or a chained method, it cannot be on the same line as the next identifier after the closing delimiter
  • OnelineSjs ensures multiline arguments are not binpacked, like Oneline above, but ignores line breaks within expressions in braces

Additionally, when binpacking is enabled (i.e., not Never), some nested expressions in brackets (if the binpacked clause uses brackets) or in braces (if it uses parentheses) wouldn't be indented as would happen in usual cases; this logic is always used for OnelineSjs, and only for single-element clauses otherwise.

When not disabled, these parameters have complex interactions with newline.source, newlines.configStyle.xxxSite.prefer (aka cfgStyle below) and danglingParentheses.xxxSite (aka dangle). Keep in mind that when config-style is forced, it takes precedence over options described below.

The code that is being binpacked might also yield an additional force over the selection of breaks, such as when dealing with multiline arguments (they behave differently under Oneline setting, or depending on alignment).

  • newlines.source=classic
    • cfgStyle=T, dangle=T: use cfg-style if both parens had breaks, otherwise binpack without breaks
      • before v3.8.2, this formatting was used for callSite with dangle=F as well
    • cfgStyle=T, dangle=F: (scala.js) use cfg-style if close paren had a break; otherwise, binpack without breaks
    • cfgStyle=F, dangle=T: binpack; if both parens had breaks, keep; otherwise, use no breaks
      • before v3.8.2, this formatting was used for defnSite with cfgStyle=T and any dangle
    • cfgStyle=F, dangle=F: binpack without breaks
      • before v3.8.2, this formatting was used for callSite with cfgStyle=F and any dangle, and for defnSite with cfgStyle=F and dangle=F
  • newlines.source=keep: always preserve break after open paren
    • cfgStyle=T, dangle=T: use cfg-style if open paren had a break; otherwise, binpack and keep close break
    • cfgStyle=T, dangle=F: (scala.js) use cfg-style if close paren had a break; otherwise, binpack and keep close break
    • cfgStyle=F, dangle=T: binpack; force close break if open paren had a break; otherwise, preserve it
    • cfgStyle=F, dangle=F: binpack; preserve close break
  • newlines.source=fold: if single line is not possible:
    • cfgStyle=T, dangle=T: binpack with both breaks
    • cfgStyle=T, dangle=F: binpack with dangling open and tucked close
    • cfgStyle=F, dangle=T: binpack with tucked open and dangling close
      • if binPack.indentCallSiteOnce is set, we will not force dangling as it might lead to consecutive lines with a closing parenthesis at the same indentation level
    • cfgStyle=F, dangle=F: binpack without breaks
  • newlines.source=unfold: if single line is not possible:
    • open dangles, close break matches dangle, cfgStyle is ignored

Please also see callSite indentation parameters.

binPack.bracketXxxSite

Since v3.0.4.

If set explicitly, will be used for type arguments or parameters, instead of the respective binPack.xxxSite.

binPack.importSelectors

Import selectors (those grouped in {...}) will always be formatted on a single line if they fit without exceeding maxColumn. This parameter controls how they will be handled if they overflow. (Prior to v3.8.4, it was called importSelectors.)

Default: binPack.importSelectors = "unfold"

Takes the following parameters:

  • unfold: format one per line (prior to v3.8.4, called noBinPack)
  • fold: fit as many as possible on each line (prior to v3.8.4, called binPack)
  • singleLine: format all on one line
import a.b.{
  c,
  d,
  e,
  f,
  g
}
import a.b.{c, d, e, f, g}

Config for this example:

maxColumn = 10
binPack.importSelectors = unfold

import a.b.{
  c, d, e,
  f, g
}
import a.b.{c, d, e, f, g}

Config for this example:

maxColumn = 10
binPack.importSelectors = fold

import a.b.{c, d, e, f, g}
import a.b.{c, d, e, f, g}

Config for this example:

maxColumn = 10
binPack.importSelectors = singleLine

Select chains

The parameters below control formatting of select chains, such as which select expressions are considered to start a chain.

Generally, a chain can either be formatted on one line up to the last select, or will have a break on the first select.

when

newlines.selectChains.style

This parameter controls how select chains (sequences of .method invocations) are formatted.

It takes the same values as newlines.source; use null (default) to fall back on the current value of newlines.source.

Since v3.0.0.

  • keep: attempts to preserve break
  • fold: attempts to avoid breaks
  • unfold: forces breaks on each select unless all fit on a single line
  • classic (i.e., null and newlines.source is not specified).

newlines.selectChains.enclose

  • Added in v2.6.2
  • Before v3.8.4, was called optIn.encloseClassicChains and applied only to style = classic
  • By default, enabled unless style = classic

Controls what happens if a chain enclosed in parentheses is followed by additional selects. Those additional selects will be considered part of the enclosed chain if and only if this flag is false.

Default: newlines.selectChains.enclose = null

(foo.map(_ + 1).map(_ + 1))
  .filter(_ > 2)
(foo.map(_ + 1).map(_ + 1))
  .filter(_ > 2)

Config for this example:

newlines.selectChains.enclose = true
maxColumn = 30

(foo
  .map(_ + 1)
  .map(_ + 1))
  .filter(_ > 2)
(foo.map(_ + 1).map(_ + 1))
  .filter(_ > 2)

Config for this example:

newlines.selectChains.enclose = false
maxColumn = 30

newlines.selectChains.classicCanStartWithBraceApply

  • Prior to v3.8.4, was called includeCurlyBraceInSelectChains
  • Applies only if style = classic (always enabled for others)

Controls if select followed by curly braces can start a chain.

Default: newlines.selectChains.classicCanStartWithBraceApply = true

List(1)
  .map { x =>
    x + 2
  }
  .filter(_ > 2)
List(1).map { x =>
    x + 2
  }
  .filter(_ > 2)

Config for this example:

newlines.selectChains.classicCanStartWithBraceApply = true

List(1).map { x =>
  x + 2
}
  .filter(_ > 2)
List(1)
  .map { x =>
    x + 2
  }
  .filter(_ > 2)

Config for this example:

newlines.selectChains.classicCanStartWithBraceApply = false

newlines.selectChains.classicCanStartWithoutApply

  • Prior to v3.8.4, was called includeNoParensInSelectChains
  • Applies only if style = classic (always enabled for others)

Controls if select not followed by an apply can start a chain.

Default: newlines.selectChains.classicCanStartWithoutApply = false

List(1)
  .toIterator
  .buffered
  .map(_ + 2)
  .filter(_ > 2)
List(1).toIterator.buffered
  .map(_ + 2)
  .filter(_ > 2)

Config for this example:

newlines.selectChains.classicCanStartWithoutApply = true

List(1).toIterator.buffered
  .map(_ + 2)
  .filter(_ > 2)
List(1).toIterator.buffered.map(_ + 2).filter(_ > 2)

Config for this example:

newlines.selectChains.classicCanStartWithoutApply = false

newlines.selectChains.classicKeepFirst

  • Prior to v3.8.4, was called optIn.breakChainOnFirstMethodDot
  • Applies only if style = classic

Keeps the break on the first select of the chain if the source contained one. Has no effect if there was no newline in the source.

Default: newlines.selectChains.classicKeepFirst = true

// collapse into a single line
foo.map(_ + 1).filter(_ > 2)
// collapse into a single line
foo
  .map(_ + 1)
  .filter(_ > 2)

Config for this example:

newlines.selectChains.classicKeepFirst = false

// preserve break on first dot and break on subsequent dots
foo
  .map(_ + 1)
  .filter(_ > 2)
// preserve break on first dot and break on subsequent dots
foo
  .map(_ + 1).filter(_ > 2)

Config for this example:

newlines.selectChains.classicKeepFirst = true

newlines.selectChains.classicKeepAfterFirstBreak

  • Prior to v3.8.4, was called optIn.breaksInsideChains
  • Applies only if style = classic

Controls whether to preserve a newline before each subsequent select when the very first one used a line break; that is, this parameter doesn't prohibit single-line formatting even if there are source breaks down the chain.

If false, each subsequent select within the chain will behave exactly like the first, that is, either the entire chain will be formatted on one line, or will contain a break on every select.

If true, preserves existence or lack of breaks on subsequent selects if the first select was formatted with a newline.

Default: newlines.selectChains.classicKeepAfterFirstBreak = false

foo
  .bar(_ + 1)
  .baz(_ > 2).qux
foo.bar(_ + 1).baz(_ > 2).qux
foo
  .bar(_ + 1).baz(_ > 2).qux(
    _ * 12
  )
foo.bar(_ + 1).baz(_ > 2).qux {
  _ * 12
}
foo
  .bar(_ + 1)
  .baz(_ > 2).qux(_ * 12)
foo.bar(_ + 1)
  .baz(_ > 2).qux
foo.bar(_ + 1).baz(_ > 2).qux
foo.bar(_ + 1).baz(_ > 2).qux(_ * 12)
foo.bar(_ + 1).baz(_ > 2).qux { _ * 12 }
foo.bar(_ + 1)
  .baz(_ > 2).qux(_ * 12)

Config for this example:

newlines.selectChains.classicKeepAfterFirstBreak = true
maxColumn = 35

foo
  .bar(_ + 1)
  .baz(_ > 2)
  .qux
foo.bar(_ + 1).baz(_ > 2).qux
foo
  .bar(_ + 1)
  .baz(_ > 2)
  .qux(_ * 12)
foo.bar(_ + 1).baz(_ > 2).qux {
  _ * 12
}
foo
  .bar(_ + 1)
  .baz(_ > 2)
  .qux(_ * 12)
foo.bar(_ + 1)
  .baz(_ > 2).qux
foo.bar(_ + 1).baz(_ > 2).qux
foo.bar(_ + 1).baz(_ > 2).qux(_ * 12)
foo.bar(_ + 1).baz(_ > 2).qux { _ * 12 }
foo.bar(_ + 1)
  .baz(_ > 2).qux(_ * 12)

Config for this example:

newlines.selectChains.classicKeepAfterFirstBreak = false
maxColumn = 35

Miscellaneous

lineEndings

This parameter controls which end-of-line character sequences will be output, takes the following values:

  • unix: outputs LF (U+000A)
  • windows: uses CRLF (U+000D U+000A)
  • preserve: if an input file contains CRLF anywhere, use CRLF for every line; otherwise, LF

By default, this parameter is assumed to be set to unix. However, since v3.8.3, if the formatter is invoked on Windows, project.git is set and git parameter core.autocrlf is configured, then default value will be changed to windows if autocrlf=true, and preserve if false.

Markdown Formatting

Since v3.0.0.

Will format all scala mdoc fences inside Markdown files.

# Format default filetypes + Markdown files
project.includePaths."+" = ["glob:**.md"]

# *Only* format Markdown files
project.includePaths = [ "glob:**.md" ]

Before:

Markdown prose beginning.

```scala mdoc
val x  =       3
```

Markdown prose end.

After:

Markdown prose beginning.

```scala mdoc
val x = 3
```

Markdown prose end.

Advanced: formatting process

Currently, the formatting process consists of several stages:

  • code parsing using scalameta parser
    • keep in mind that any parsing errors output by scalafmt are in fact coming from scalameta
  • format-agnostic rewrites
    • during this step, we apply most of the rewrites rules (except those which depend on how we decided to format the code)
  • preparing whitespace splits
    • we iterate over all pairs of adjacent non-whitespace tokens and identify possible options for the output whitespace between them
    • selection is between
      • a newline with a possible subsequent indentation
      • a single space
      • no space at all
    • each option also comes with a penalty and a possible policy on how to handle subsequent splits
      • for instance, this is how we ensure single-line formatting, by adding a policy which removes all newline splits before a given end token
  • route search
    • we look for an optimal path through the space of non-whitespace tokens and splits between them
    • each partial state includes, among other things:
      • the last token considered
      • the split selection preceding it
      • total cumulative penalty
      • the partial state for the previous token
    • we maintain a priority queue containing these partial states, by preferring states with lower penalty and then higher token offset (i.e. those which are closer to the completion)
    • at each iteration, we select a state from that priority queue (we'll call this event a state visit), apply all available non-expired policies to available subsequent whitespace splits, insert the next state for each of them back into the priority queue
    • we stop as soon as the top state in the priority queue is completed (i.e., refers to the EOF token)
  • output
    • after we have obtained our final formatting state, we need to write out the code applying the splits selected during the route search
    • as part of this final stage, we perform a few steps:
      • apply format-dependent rewrites (as these frequently need to know how many line breaks we have selected to output for a given code passage); for instance,
        • inserting braces,
        • adding or removing end markers
        • modifying blank lines
      • rewrite comments and docstrings if configured
      • rewrite trailing commas: as part of this rule, we remove any trailing commas during the format-agnostic rewrites stage and add them as needed during this stage, if our splits solution ended up with a line break before the closing paren or brace
      • alignment: determine any additional horizontal space to be added
        • if alignment is for some reason is not possible, we don't go back to the previous stage (route search) to determine a different splits solution which might possibly make alignment possible
        • this might happen, for instance, if alignment leads to disallowed line overflow

Advanced: Route search optimizations

There are several configuration parameters (most of them under the runner.optimizer section) which control some aspects of the algorithm during this formatting stage.

Route search optimizations: giving up

The following parameters control when we abort the search and throw a SearchStateExploded exception:

  • runner.maxStateVisits: when the total number of state visits exceeds this value
  • runner.optimizer.maxVisitsPerToken: when the number of state visits for a given token exceeds this value (also see below)
  • runner.optimizer.escapeInPathologicalCases: if this flag is disabled, ignore maxVisitsPerToken above
# Defaults
runner.maxStateVisits = null
runner.optimizer.maxVisitsPerToken = 10000
runner.optimizer.escapeInPathologicalCases = true

Route search optimizations: discarding some states

Normally, the search algorithm considers any state as a possible intermediate state which might complete a valid solution.

However, in some cases we might decide to require certain conditions to be met for a state to be considered. A state need to qualify under at least one of the checks controlled by these parameters:

  • runner.optimizer.pruneSlowStates:
    • accepts true or false; also, since v3.8.4, No, Yes or Only
    • if this flag is disabled (false or No), any state qualifies
    • if it is enabled:
      • if the search algorithm is ultimately unable to find a completed solution (because some states might be discarded) and if the value is not Only, then it will disable the flag and make another attempt
      • during the first run, when the flag is enabled, a state qualifies if it is not "worse" than a previously recorded "best" state for this token
      • the "best" state is the first state with a newline split at the given token (recursive calls over subsequences are excluded, see sections below)
      • a state is "worse" when it has higher penalty and wider indentation
  • runner.optimizer.disableOptimizationsInsideSensitiveAreas: a state qualifies if this flag is disabled or the current token is within a so-called no-optimization zone (and if the state satisfies these criteria, we'll call it a no-optimization state):
    • between matching parentheses of method call (either those enclosing the method arguments, or the entire call itself)
    • between matching braces of a type refinement
# Defaults
runner.optimizer.disableOptimizationsInsideSensitiveAreas = true
runner.optimizer.pruneSlowStates = "Yes"

Route search optimizations: preferential treatment

In some cases, we modify the search logic to boost priority of some states. The following sections describe when and how this might be done.

Route search optimizations: optimal hints

Some splits might be marked as starting a token subsequence with an optimal end token (for example, a segment which must be formatted without line breaks).

In such cases, if flag runner.optimizer.acceptOptimalAtHints is enabled and the hint is deemed valid (see below), the route search algorithm calls itself recursively with the state that ends in this "optimal" split and just on this shorter subsequence, returning the first state which completed this subsequence, with the following restrictions:

  • the state penalty at the end must be the same as at the beginning, so no splits within the subsequence can have non-zero penalty
  • the so-called nested depth is incremented (set to zero initially) and then must not exceed runner.optimizer.maxDepth

There are several checks that are performed to determine validity of the hint:

  • no optimal subsequence has yet been identified for the current state
  • there are multiple possible next states; we don't do this if there's only one
  • the split has zero penalty, including from any unexpired policies
# Defaults
runner.optimizer.acceptOptimalAtHints = true
runner.optimizer.maxDepth = 100

Route search optimizations: longer blocks

Another form of getting ahead faster is by recursing on a long-enough block (whether enclosed in explicit braces or by using significant indentation), where "long enough" is loosely defined as having sufficient non-whitespace characters to fill at least three dense maxColumn lines.

Unlike the case with optimal hints above, there's no restriction on the penalty added by the splits within the block.

This optimization is enabled when:

  • runner.optimizer.recurseOnBlocks is enabled, and
  • the token is within a no-optimization zone.

Default: runner.optimizer.recurseOnBlocks = true

Route search optimizations: statements

Another way to boost priority is simply by adding a new priority queue, so that any earlier states, from the existing priority queue, wouldn't be considered until the new one is exhausted.

We might create a new priority queue if we encounter a new block statement, and this optimization is enabled when:

  • runner.optimizer.dequeueOnNewStatements is enabled, and
  • we are in a recursive call on a subsequence or the token is not within a no-optimization zone.

Default: runner.optimizer.dequeueOnNewStatements = true

Route search optimizations: arg or param clause

Similar to statements above, we might create a new priority queue when we encounter a long-enough call-site argument or defn-site parameter clause.

# Defaults
runner.optimizer.callSite = {"minSpan": 150, "minCount": 2}
runner.optimizer.defnSite = {"minSpan": -1, "minCount": 0}

This optimization is enabled when all these criteria are satisfied:

  • xxxSite.minSpan: must be non-negative and not exceed the character span covered by the entire clause, excluding any whitespace
    • prior to v3.8.1, this parameter was called forceConfigStyleOnOffset
    • prior to v3.8.4, the parameter had to be strictly less than the span, and the span calculation excluded the last token of the clause (a closing delim spanning a single-character, unless optional braces had been used)
  • xxxSite.minCount: must be positive and not exceed the number of arguments (prior to v3.8.2, this parameter was called forceConfigStyleMinCount)

These parameters cannot be overridden within a file

Edition

Removed in 2.7.0

Editions are no longer used. They were kept for backwards compatibility with old configuration files but new changes to the default Scalafmt formatting behavior will not respect the edition setting.

Other

To find all available configuration options, it's best to browse the source code of Scalafmt. A good place to start is ScalafmtConfig. Observe that this listing below is the top-level, there are more configuration options if you visited nested fields like spaces and newlines.

The values for parameters below are purely for informational purposes. They use pseudo-formatting similar to but incompatible with scalafmt.conf. Some of them show values which can't be explicitly specified.

version = "3.9.6"
maxColumn = 80
docstrings.oneline = keep
docstrings.removeEmpty = false
docstrings.wrap = unfold
docstrings.wrapMaxColumn = null
docstrings.forceBlankLineBefore = true
docstrings.blankFirstLine = null
docstrings.style = SpaceAsterisk
comments.wrap = no
comments.wrapSingleLineMlcAsSlc = false
comments.wrapStandaloneSlcAsSlc = false
binPack.callSite = Never
binPack.defnSite = Never
binPack.bracketCallSite = null
binPack.bracketDefnSite = null
binPack.indentCallSiteOnce = false
binPack.indentCallSiteSingleArg = true
binPack.parentConstructors = source
binPack.literalArgumentLists = true
binPack.literalsIncludeSimpleExpr = false
binPack.literalsSingleLine = false
binPack.literalsMinArgCount = 5
binPack.literalsInclude = [
  ".*"
]
binPack.literalsExclude = [
  String
  "Term.Name"
]
binPack.importSelectors = unfold
indent.main = 2
indent.significant = null
indent.callSite = 2
indent.ctrlSite = null
indent.binPackCallSite = null
indent.defnSite = 4
indent.binPackDefnSite = null
indent.caseSite = 4
indent.matchSite = null
indent.ctorSite = null
indent.extraBeforeOpenParenDefnSite = 0
indent.relativeToLhsLastLine = []
indent.fewerBraces = never
indent.afterInfixSite = null
indent.extendSite = 4
indent.withSiteRelativeToExtends = 0
indent.commaSiteRelativeToExtends = 2
indent.yieldKeyword = true
indent.infix.exemptScope = oldTopLevel
indent.infix.includeRegex = ".*"
indent.infix.excludeRegex = "^(&&|\|\|)$"
align.allowOverflow = false
align.delayUntilSpace = true
align.multiline = false
align.stripMargin = true
align.closeParenSite = false
align.openBracketCallSite = null
align.openParenCallSite = false
align.openParenCtrlSite = false
align.openBracketDefnSite = null
align.openParenDefnSite = false
align.openParenTupleSite = null
align.beforeOpenParenDefnSite = false
align.beforeOpenParenCallSite = false
align.inInterpolation = false
align.tokens = [
  {
    code = "=>"
    owners = [
      {
        regex = Case
        parents = []
      }
    ]
  }
]
align.arrowEnumeratorGenerator = false
align.treeCategory."Defn.Trait" = "class/object/trait/enum"
align.treeCategory."Defn.Object" = "class/object/trait/enum"
align.treeCategory."Defn.Val" = "given/val/var/def"
align.treeCategory."Defn.Enum" = "class/object/trait/enum"
align.treeCategory."Defn.Macro" = "given/val/var/def"
align.treeCategory."Decl.Def" = "given/val/var/def"
align.treeCategory."Defn.Def" = "given/val/var/def"
align.treeCategory."Defn.GivenAlias" = "given/val/var/def"
align.treeCategory."Defn.Var" = "given/val/var/def"
align.treeCategory."Enumerator.Generator" = for
align.treeCategory."Enumerator.Val" = for
align.treeCategory."Defn.Class" = "class/object/trait/enum"
spaces.beforeContextBoundColon = Never
spaces.withinContextBoundBraces = Never
spaces.beforeApplyArgInParens = Never
spaces.beforeInfixArgInParens = Always
spaces.afterTripleEquals = false
spaces.inImportCurlyBraces = false
spaces.inInterpolatedStringCurlyBraces = false
spaces.inParentheses = false
spaces.neverAroundInfixTypes = []
spaces.aroundSymbolicInfixOperators = null
spaces.afterKeywordBeforeParen = true
spaces.inByNameTypes = true
spaces.afterSymbolicDefs = false
spaces.afterColonInMatchPattern = Always
literals.long = Upper
literals.float = Lower
literals.double = Lower
literals.hexDigits = Lower
literals.hexPrefix = Lower
literals.binPrefix = Lower
literals.scientific = Lower
lineEndings = null
rewrite.rules = []
rewrite.scala3.convertToNewSyntax = false
rewrite.scala3.newSyntax.control = true
rewrite.scala3.newSyntax.deprecated = true
rewrite.scala3.removeOptionalBraces.enabled = false
rewrite.scala3.removeOptionalBraces.fewerBracesMinSpan = 2
rewrite.scala3.removeOptionalBraces.fewerBracesMaxSpan = 0
rewrite.scala3.removeOptionalBraces.fewerBracesParensToo = false
rewrite.scala3.removeOptionalBraces.oldSyntaxToo = false
rewrite.scala3.countEndMarkerLines = all
rewrite.scala3.removeEndMarkerMaxLines = 0
rewrite.scala3.insertEndMarkerMinLines = 0
rewrite.insertBraces.minLines = 0
rewrite.insertBraces.allBlocks = false
rewrite.redundantBraces.defnBodies = all
rewrite.redundantBraces.includeUnitMethods = true
rewrite.redundantBraces.maxBreaks = 100
rewrite.redundantBraces.stringInterpolation = false
rewrite.redundantBraces.oneStatApply.parensMaxSpan = 0
rewrite.redundantBraces.oneStatApply.bracesMinSpan = -1
rewrite.redundantBraces.generalExpressions = true
rewrite.redundantBraces.ifElseExpressions = false
rewrite.redundantParens.infixSide = null
rewrite.sortModifiers.order = [
  implicit
  final
  sealed
  abstract
  override
  private
  protected
  erased
  lazy
  open
  transparent
  inline
  infix
  opaque
]
rewrite.imports.sort = none
rewrite.imports.expand = false
rewrite.imports.contiguousGroups = only
rewrite.imports.groups = []
rewrite.preferCurlyFors.removeTrailingSemicolonsOnly = false
rewrite.trailingCommas.allowFolding = true
rewrite.trailingCommas.style = never
rewrite.avoidInfix.includeFilters = [
  "[\w\d_]+"
]
rewrite.avoidInfix.excludeFilters = [
  until
  to
  by
  eq
  ne
]
rewrite.avoidInfix.excludeScalaTest = null
rewrite.avoidInfix.excludePlaceholderArg = true
rewrite.avoidInfix.excludePostfix = false
rewrite.avoidInfix.excludeMatch = true
newlines.source = null
newlines.avoidInResultType = false
newlines.beforeTypeBounds = null
newlines.neverBeforeJsNative = false
newlines.sometimesBeforeColonInMethodReturnType = true
newlines.beforeOpenParenDefnSite = null
newlines.beforeOpenParenCallSite = null
newlines.penalizeSingleSelectMultiArgList = true
newlines.beforeCurlyLambdaParams = never
newlines.topLevelStatementBlankLines = []
newlines.topLevelStatementsMinBreaks = 1
newlines.topLevelStatements = []
newlines.beforeTemplateBodyIfBreakInParentCtors = false
newlines.topLevelBodyIfMinStatements = []
newlines.topLevelBodyMinStatements = 2
newlines.afterCurlyLambdaParams = never
newlines.implicitParamListModifierForce = []
newlines.implicitParamListModifierPrefer = null
newlines.alwaysBeforeElseAfterCurlyIf = false
newlines.forceBeforeAssign = never
newlines.forceBeforeMultilineAssign = null
newlines.beforeMultiline = null
newlines.beforeMultilineDef = null
newlines.selectChains.style = null
newlines.selectChains.enclose = null
newlines.selectChains.classicKeepFirst = true
newlines.selectChains.classicKeepAfterFirstBreak = false
newlines.selectChains.classicCanStartWithBraceApply = true
newlines.selectChains.classicCanStartWithoutApply = false
newlines.infix.termSite.style = null
newlines.infix.termSite.breakOnNested = false
newlines.infix.termSite.maxCountPerFile = 500
newlines.infix.termSite.maxCountPerExprForSome = 10
newlines.infix.typeSite = null
newlines.infix.patSite = null
newlines.avoidForSimpleOverflow = []
newlines.inInterpolation = allow
newlines.ignoreInSyntax = true
newlines.avoidAfterYield = true
newlines.configStyle.callSite = null
newlines.configStyle.defnSite = null
newlines.configStyle.bracketCallSite = null
newlines.configStyle.bracketDefnSite = null
newlines.configStyle.fallBack.prefer = true
newlines.configStyle.fallBack.forceIfOptimized = null
newlines.configStyle.beforeComma = false
newlines.annotation = true
newlines.selfAnnotation = true
runner.debug = false
runner.completeCallback = "<FormatEvent => Unit>"
runner.eventCallback = "<FormatEvent => Unit>"
runner.parser = Source
runner.optimizer.dequeueOnNewStatements = true
runner.optimizer.escapeInPathologicalCases = true
runner.optimizer.maxVisitsPerToken = 10000
runner.optimizer.maxDepth = 100
runner.optimizer.acceptOptimalAtHints = true
runner.optimizer.disableOptimizationsInsideSensitiveAreas = true
runner.optimizer.pruneSlowStates = Yes
runner.optimizer.recurseOnBlocks = true
runner.optimizer.callSite.minSpan = 150
runner.optimizer.callSite.minCount = 2
runner.optimizer.defnSite.minSpan = -1
runner.optimizer.defnSite.minCount = 0
runner.maxStateVisits = null
runner.dialect = null
runner.ignoreWarnings = false
runner.fatalWarnings = false
assumeStandardLibraryStripMargin = false
danglingParentheses.callSite = true
danglingParentheses.defnSite = true
danglingParentheses.ctrlSite = true
danglingParentheses.tupleSite = null
danglingParentheses.bracketCallSite = null
danglingParentheses.bracketDefnSite = null
danglingParentheses.exclude = null
verticalMultiline.atDefnSite = false
verticalMultiline.arityThreshold = 100
verticalMultiline.newlineAfterOpenParen = false
onTestFailure = ""
encoding = "UTF-8"
project.git = false
project.layout = null
project.includePaths = [
  "glob:**.scala"
  "glob:**.sbt"
  "glob:**.sc"
  "glob:**.mill"
]
project.excludePaths = []
project.includeFilters = []
project.excludeFilters = []
xmlLiterals.assumeFormatted = false
formatOn = [
  "@formatter:on"
  "format: on"
]
formatOff = [
  "@formatter:off"
  "format: off"
]
← InstallationGotchas →
  • Most popular
    • maxColumn
    • assumeStandardLibraryStripMargin
  • Version
  • Scala Dialects
    • runner.dialectOverride
    • Scala 3
    • Scala 2 with -Xsource:3
  • Presets
    • Top-level presets
    • Appending to preset collections
  • Indentation
    • indent.main
    • indent.significant
    • indent.callSite
    • indent.binPackCallSite
    • indent.ctrlSite
    • indent.defnSite
    • indent.binPackDefnSite
    • indent.ctorSite
    • indent.matchSite
    • indent.caseSite
    • indent.extendSite
    • indent.withSiteRelativeToExtends
    • indent.commaSiteRelativeToExtends
    • indent.extraBeforeOpenParenDefnSite
    • indent.afterInfixSite
    • Indent for binPack.callSite
    • indent.infix
  • Alignment
    • align.preset
    • align.tokens
    • align.arrowEnumeratorGenerator
    • align.closeParenSite
    • align.openParenCallSite
    • align.openBracketCallSite
    • align.openParenCtrlSite
    • align.openParenDefnSite
    • align.openBracketDefnSite
    • align.openParenTupleSite
    • align.beforeOpenParenXxxSite
    • align.stripMargin
    • align.multiline
    • align.allowOverflow
    • align.inInterpolation
    • align.delayUntilSpace
  • Newlines
    • newlines.source
    • newlines.topLevelStatementBlankLines
    • Newlines around package or template body
    • newlines.beforeMultiline
    • newlines.forceBeforeMultilineAssign
    • newlines.forceBeforeAssign
    • newlines.beforeTypeBounds
    • newlines.alwaysBeforeElseAfterCurlyIf
    • newlines.beforeCurlyLambdaParams
    • newlines.afterCurlyLambdaParams
    • newlines.implicitParamListModifierXXX
    • newlines.infix
    • newlines.avoidForSimpleOverflow
    • newlines.avoidInResultType
    • newlines.sometimesBeforeColonInMethodReturnType
    • newlines.beforeOpenParenXxxSite
    • newlines.inInterpolation
    • newlines.ignoreInSyntax
    • newlines.annotation
    • newlines.selfAnnotation
  • Newlines: danglingParentheses
    • danglingParentheses.defnSite
    • danglingParentheses.callSite
    • danglingParentheses.bracketXxxSite
    • danglingParentheses.ctrlSite
    • danglingParentheses.tupleSite
    • danglingParentheses.exclude
  • Newlines: Config-style formatting
    • newlines.configStyle.xxxSite
    • newlines.configStyle.xxxSite.prefer
    • Forcing config style
    • newlines.configStyle.beforeComma
  • Rewrite Rules
    • AvoidInfix
    • RedundantBraces
    • Inserting braces
    • RedundantParens
    • SortModifiers
    • PreferCurlyFors
    • Imports
    • Trailing commas
    • rewrite.tokens
  • Scala3 rewrites
    • rewrite.scala3.convertToNewSyntax
    • rewrite.scala3.removeOptionalBraces
    • rewrite.scala3.insertEndMarkerMinLines
    • rewrite.scala3.removeEndMarkerMaxLines
    • rewrite.scala3.countEndMarkerLines
  • Vertical Multiline
    • verticalMultiline.arityThreshold
    • verticalMultiline.newlineAfterOpenParen
    • verticalMultiline.excludeDanglingParens
    • Vertical multiline with implicit parameter lists
  • Comment processing
    • comments.wrap
    • comments.wrapStandaloneSlcAsSlc
    • comments.wrapSingleLineMlcAsSlc
    • docstrings.style
    • docstrings.removeEmpty
    • docstrings.oneline
    • docstrings.wrap
    • docstrings.wrapMaxColumn
    • docstrings.blankFirstLine
    • docstrings.forceBlankLineBefore
  • Disabling or customizing formatting
    • Search state exploded
    • For code block
    • // format: off
    • Project
    • fileOverride
  • Spaces
    • spaces.beforeContextBoundColon
    • spaces.withinContextBoundBraces
    • spaces.inImportCurlyBraces
    • spaces.inInterpolatedStringCurlyBraces
    • spaces.inParentheses
    • spaces.neverAroundInfixTypes
    • spaces.aroundSymbolicInfixOperators
    • spaces.afterKeywordBeforeParen
    • spaces.inByNameTypes
    • spaces.afterSymbolicDefs
    • spaces.beforeXxxArgInParens
    • spaces.afterColonInMatchPattern
  • Literals
    • literals.long
    • literals.float
    • literals.double
    • literals.hexPrefix
    • literals.hexDigits
    • literals.binPrefix
    • literals.scientific
  • XML
    • xmlLiterals.assumeFormatted
  • Binpacking
    • binPack presets
    • Literal argument lists
    • binPack.parentConstructors
    • binPack.xxxSite
    • binPack.bracketXxxSite
    • binPack.importSelectors
  • Select chains
    • newlines.selectChains.style
    • newlines.selectChains.enclose
    • newlines.selectChains.classicCanStartWithBraceApply
    • newlines.selectChains.classicCanStartWithoutApply
    • newlines.selectChains.classicKeepFirst
    • newlines.selectChains.classicKeepAfterFirstBreak
  • Miscellaneous
    • lineEndings
  • Markdown Formatting
  • Advanced: formatting process
  • Advanced: Route search optimizations
    • Route search optimizations: giving up
    • Route search optimizations: discarding some states
    • Route search optimizations: preferential treatment
  • Edition
  • Other
Scalafmt
Docs
InstallationConfigurationContributing
Community
Join on DiscordChat on Gitter (defunct)
More
GitHub
Copyright © 2025 Scalafmt