ぶらっ記ぃ

日本語の練習をしています

scalafmtでfor式の `<-` と `=` をAlignする

Scalaコードをフォーマットするのによくscalafmtが用いられると思います。

scalameta.org

自身は仕事/個人開発でよく下記の設定を使っています。(宣伝)

github.com

sbtプロジェクトのディレクトリ下でちょこっとコマンドを叩くだけでscalafmtの環境が整うので便利です!

for式の <-= をAlignしたい

しかし、コードを書いているとある点が気になりました。

以下のようなコードがあるとします。

for {
  a <- Some(10)
  bbbbbbbbbbbbbbb <- Some(20)
  ccc = 300
  dddddddddd <- Try {
    4000
  }.toOption
  eeeeee = 50000
} yield a + bbbbbbbbbbbbbbb + ccc + dddddddddd + eeeeee

scalafmt.conf は以下のような設定です。

style                          = defaultWithAlign
danglingParentheses            = true
indentOperator                 = spray
maxColumn                      = 120
rewrite.rules                  = [RedundantParens, SortImports, PreferCurlyFors]
binPack.literalArgumentLists   = false
unindentTopLevelOperators      = true

scalafmtを実行すると以下のようにフォーマットされます。

for {
  a               <- Some(10)
  bbbbbbbbbbbbbbb <- Some(20)
  ccc = 300
  dddddddddd <- Try {
    4000
  }.toOption
  eeeeee = 50000
} yield a + bbbbb + ccc + dddddddddd + eeeeee

いい感じになりました!
…が、 ccc = 300 の部分がAlignされていませんね。

この = をAlignしたいときにどういう設定をすればよいのでしょうか?

align = most を使う

ドキュメントを見てみると align = most が使えそうでした。

scalafmt.conf に以下を追加します。

align = most

scalafmtを実行します。

for {
  a               <- Some(10)
  bbbbbbbbbbbbbbb <- Some(20)
  ccc             = 300
  dddddddddd <- Try {
                 4000
               }.toOption
  eeeeee = 50000
} yield a + bbbbbbbbbbbbbbb + ccc + dddddddddd + eeeeee

<-= がAlignされましたね!

しかし、 Try のブロックのインデントがちょっと深いのが気になる人が居るかもしれません…

align.arrowEnumeratorGeneratoralign.tokenCategory を設定する

most の設定がどうなっているか見てみます。

github.com

  val most: Align = more.copy(
    arrowEnumeratorGenerator = true,
    tokenCategory = Map(
      "Equals" -> "Assign",
      "LeftArrow" -> "Assign"
    )
  )

more の設定から align.arrowEnumeratorGeneratoralign.tokenCategory を追加しています。

align.arrowEnumeratorGeneratorをtrueに設定されていることで問題のインデントがなされていそうです。

most の設定を参考にしつつ以下のように scalafmt.conf を書き換えます。

//align = most
align.arrowEnumeratorGenerator = false
align.tokenCategory            = {
  Equals = Assign
  LeftArrow = Assign
}

scalafmtを実行します。

for {
  a               <- Some(10)
  bbbbbbbbbbbbbbb <- Some(20)
  ccc             = 300
  dddddddddd <- Try {
    4000
  }.toOption
  eeeeee = 50000
} yield a + bbbbbbbbbbbbbbb + ccc + dddddddddd + eeeeee

<-= をAlignしつつ、 Try のインデントをおさえることができました!


scalafmtは柔軟にフォーマットを定義できて便利ですね~~~