Posts Scalafmt
Post
Cancel

Scalafmt

Scalafmt formats code so that it looks consistent between people on your team.
For example, it can automatically rewrite this code, which has a weird indentation:

1
2
3
4
5
// Example 1: parameters with indentation after the parenthesis
case class Demo(a: String,
        b: Int,
                c: Char
                )

to a code that is well formatted:

1
2
3
4
5
6
// Example 2: Parameters with 2 spaces indentation
case class Demo(
  a: String,
  b: Int,
  c: Char
)

The original version of the class had several problems:

  • The field b did not have the same indentation level as the rest of the fields.
  • Even worse, the argument list started immediately after the class name.
    In our example, we started reading the arguments after 16 characters: case class Demo(.
    This means that field c has 16 spaces before it, and if b had the same indentation level then it would also have 16 spaces before it.
    Now imagine that you rename the class from Demo to Demonstration.
    Since we added several characters to the class name, now we also need to indent b, c and ) with 9 extra spaces.
    It means that for a simple refactor, now the reader of the git diff has to read several lines.
    Furthermore, the indentation should not depend on the class name.

See more formatting options in the website.

Formatters allow you not think about this kind of problems, and just focus on the code itself.

Add Scalafmt sbt plugin

Scalafmt has an sbt plugin.
After we add it to the project we can use the sbt task scalafmt to format our code.

Add the plugin to you code by adding the latest version of Scalafmt from the website to project/plugins.sbt. e.g:

1
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.2.1")

Run reload in the sbt shell for the changes to take effect.

Configure Scalafmt

We can now use the sbt task scalafmt in the sbt-shell to format our code.
However, let’s set some custom configuration before that.
Under the root of your project, create a new file called .scalafmt.conf with the following configuration:

1
2
3
4
version = 2.3.2
maxColumn = 120
trailingCommas = preserve
rewrite.rules = [SortImports]
ConfigDescription
maxColumn = 120scalafmt will split the line if it is longer than 120 characters
trailingCommas = preservekeeps the last , in an argument list
rewrite.rules = [SortImports]The imports are sorted by the groups: symbols, lower-case, upper-case
version = 2.3.2The latest stable scalafmt version

Use Scalafmt

Option 1

Use the sbt task scalafmt in the sbt-shell to format our code.

Option 2

Configure IntelliJ to use scalafmt.
Set the formatter as scalafmt under Preferences > Editor > Code Style > Scala.
Now use Option + CMD + L to format the current file.
You can also set Reformat on file save in the setting dialog above.

Note

Below is the code style that I use in IntelliJ for projects that do not have scalafmt.
You should change com.example to your organization’s namespace, save this file as custom-code-style.xml and set in IntelliJ settings with:
File -> Other Settings -> Preferences for New Projects -> Editor -> Code Style -> Scala
Then click on the wheel icon, choose Import Scheme and IntelliJ IDEA code style XML and select this file.
This will set this code style for new projects. You can do so for current projects similarly in the project settings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<code_scheme name="Dvir" version="173">
  <option name="OTHER_INDENT_OPTIONS">
    <value>
      <option name="USE_TAB_CHARACTER" value="true" />
    </value>
  </option>
  <MarkdownNavigatorCodeStyleSettings>
    <option name="RIGHT_MARGIN" value="72" />
  </MarkdownNavigatorCodeStyleSettings>
  <ScalaCodeStyleSettings>
    <option name="alwaysUsedImports">
      <array>
        <option value="pureconfig.generic.auto._" />
      </array>
    </option>
    <option name="importLayout">
      <array>
        <option value="java" />
        <option value="javax" />
        <option value="scala" />
        <option value="_______ blank line _______" />
        <option value="all other imports" />
        <option value="com.example" />
        <option value="_______ blank line _______" />
      </array>
    </option>
    <option name="PLACE_SELF_TYPE_ON_NEW_LINE" value="false" />
    <option name="USE_SCALADOC2_FORMATTING" value="true" />
    <option name="CALL_PARAMETERS_NEW_LINE_AFTER_LPAREN" value="2" />
  </ScalaCodeStyleSettings>
  <codeStyleSettings language="HTML">
    <indentOptions>
      <option name="INDENT_SIZE" value="2" />
      <option name="CONTINUATION_INDENT_SIZE" value="4" />
      <option name="TAB_SIZE" value="2" />
    </indentOptions>
  </codeStyleSettings>
  <codeStyleSettings language="JavaScript">
    <indentOptions>
      <option name="INDENT_SIZE" value="2" />
      <option name="CONTINUATION_INDENT_SIZE" value="2" />
      <option name="TAB_SIZE" value="2" />
    </indentOptions>
  </codeStyleSettings>
  <codeStyleSettings language="Scala">
    <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
    <option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
    <option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
    <option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
  </codeStyleSettings>
  <codeStyleSettings language="ruby">
    <option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="true" />
    <option name="SPACE_WITHIN_BRACES" value="true" />
    <indentOptions>
      <option name="CONTINUATION_INDENT_SIZE" value="2" />
      <option name="USE_RELATIVE_INDENTS" value="false" />
    </indentOptions>
  </codeStyleSettings>