Home > Blockchain >  scalafmt - docstrings conflict with significant indentation
scalafmt - docstrings conflict with significant indentation

Time:11-24

The following piece of code:

class Test:
  /** A very
    * useful
    * piece
    * of
    * documentation
    */
  def helloWorld =
    42 match
      case 42 =>
        a()
        b()

  /** A very
    * useful
    * piece
    * of
    * documentation
    */
  def helloAgain = ???

is transformed into

class Test:
  /** A very
    * useful
    * piece
    * of
    * documentation
    */
  def helloWorld =
    42 match
      case 42 =>
        a()
        b()

        /** A very
    * useful
    * piece
    * of
    * documentation
    */
  def helloAgain = ???

by scalafmt despite the

docstrings.style = keep

It seems that it is aligning /** as if it belonged to the same block as b().

The same thing happens with one-line defs:

class C:
  def foo = bar
  
  /** doc
    */
  def baz = ???

which is also turned into

class C:
  def foo = bar
  
    /** doc
    */
  def baz = ???

because it thinks that /** doc is in same block as bar.

Question: Is there anything I can do to prevent it from quasi-randomly indenting all the documentation comments? Or should one just switch back to curly braces for now?


Full .scalafmt.conf

Here is a preliminary sketch of the config that I copied together from various bits and pieces so far:

version = 3.6.1
runner.dialect = scala3
preset = default
maxColumn = 120
indent.main = 2
indent.significant = 2
indent.extendSite = 2
indent.withSiteRelativeToExtends = 3
indent.ctrlSite = 2
indent.defnSite = 2
indent.ctorSite = 2
indent.relativeToLhsLastLine = [match, infix]
indentOperator.exemptScope = all
align.preset = more
align.openParenCallSite = false
align.openParenDefnSite = false
align.multiline = true
align.tokens." " = [
  {
    code = "<-"
    owners = [{
      regex = "Enumerator\\.Generator",
      parents = [ "Term\\.ForYield" ]
    }]
  },
  {
    code = "="
    owners = [{
      regex = "Enumerator\\.Val",
      parents = [ "Term\\.ForYield" ]
    }]
  }
]

align.tokenCategory {
  Equals = Assign
  LeftArrow = Assign
}

align.treeCategory {
  "Defn.Trait" = "class/object/trait"
  "Defn.Class" = "class/object/trait"
  "Defn.Object" = "class/object/trait"
  "Defn.Val" = "val/var/def"
  "Defn.Def" = "val/var/def"
  "Defn.Var" = "val/var/def"
  "Enumerator.Generator" = forComp
  "Enumerator.Val" = forComp
}

rewrite.rules = [AvoidInfix, SortImports, RedundantParens, SortModifiers]
newlines.afterCurlyLambda = preserve

docstrings.style = keep

The exact Scala version of the example is 3.2.1 (latest at the time of writing).

CodePudding user response:

I found out that the problem is indent.relativeToLhsLastLine = [match, infix]. Without this setting scalafmt doesn't indent the first line of your docstring.

I believe that the cause of this behaviour is this fix https://github.com/scalameta/scalafmt/pull/3359.

Upd: I added an issue related to your problem https://github.com/scalameta/scalafmt/issues/3383

  • Related