Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Format things with scalafmt

Format things with scalafmt

Rikito Taniguchi

November 10, 2018
Tweet

More Decks by Rikito Taniguchi

Other Decks in Technology

Transcript

  1. こんにちは - Twitter: tanishiking - GitHub: tanishiking - Hatena: tanishiking24

    株式会社はてな(京都オフィス)で働いています。 Perl/TypeScript/Scala/Golang LinterやFormatterなどの開発支援ツールに興味があります。
  2. Agenda 1. コードフォーマッタを導入する利点 2. scalafmt の紹介 ◦ scalariform との違い /

    scalameta 3. scalafmt の使い方 4. Configuration ◦ とりあえずこの辺設定すればOKというものをいくつか紹介 します。
  3. スタイルガイドを整備しても “any style guide written in English is either so

    brief that it’s ambiguous, or so long that no one reads it.” Bob Nystrom The Hardest Program I've Ever Written http://journal.stuffwithstuff.com/2015/09/08/the-hardest-program-ive-ever-written/
  4. Code Formatter!! “Spend more time discussing important issues in code

    review and less time on code style. Scalafmt formats code so that it looks consistent between people on your team.” scalafmt.org
  5. scalariform or scalafmt - scalariform - 独自実装されたscalaのparserを利用 - 2.12のsyntaxには未対応 -

    scalafmt - scalametaというscalaのコードを解析するライブラリを利用 - 最新のscalaのsyntaxにも対応、Dottyにも対応予定 - maxColumn
  6. Install scalafmt - CLI - coursier - brew - SBT

    Plugin - sbt-scalafmt (こっちが公式) - neo-sbt-scalafmt - Editor/IDE plugin - IntelliJ plugin - vim-autofmt
  7. Install scalafmt (おすすめ) - CLI - coursier (coursier bootstrap で作ったlauncherをgit管理)

    - brew - SBT Plugin - sbt-scalafmt (こっちが公式) - neo-sbt-scalafmt - Editor/IDE plugin - IntelliJ plugin - vim-autofmt
  8. maxColumn (default: 80) // before class ExtendTest extends A with

    B with C with D // after (maxCoulumn=20) class ExtendTest extends A with B with C with D ※必ず指定した値以内に収まるわけではないことに注意
  9. continuationIndent.defnSite (default: 4) // before def function( foo: Type, bar:

    Type ) // after def function( foo: Type, bar: Type )
  10. continuationIndent.extendSite (default: 4) // before class UserProfile extends Profile with

    SomeTrait // after class UserProfile extends Profile with SomeTrait
  11. align 「=」「<-」「%%」「//」などを縦方向で揃える設定 - none - some (default) - more -

    most align.tokens で詳細を設定できるが、上記の4種類で十分
  12. align = none // before x match { case "foo"

    => 1 // comment case "hoge" => 123 // comment case "foobar" => 12345 // comment } // after x match { case "foo" => 1 // comment case "hoge" => 123 // comment case "foobar" => 12345 // comment }
  13. align = some (default) // before x match { case

    "foo" => 1 // comment case "hoge" => 123 // comment case "foobar" => 12345 // comment } // after (case match の => のみ align する) x match { case "foo" => 1 // comment case "hoge" => 123 // comment case "foobar" => 12345 // comment }
  14. align = more // before x match { case "foo"

    => 1 -> 1 // comment case "hoge" => 123 -> 123 // comment case "foobar" => 12345 -> 12345 // comment } // after (// や -> も) x match { case "foo" => 1 -> 1 // comment case "hoge" => 123 -> 123 // comment case "foobar" => 12345 -> 12345 // comment }
  15. align = more // before val foo = 1 val

    hoge = 2 libraryDependencies ++= Seq( "org.scala-lang" % "scala-compiler" % scalaVersion.value, "com.tanishiking" %% "scalaunfmt" % "0.0.1" ) // after (= や sbtの % も) val foo = 1 val hoge = 2 libraryDependencies ++= Seq( "org.scala-lang" % "scala-compiler" % scalaVersion.value, "com.tanishiking" %% "scalaunfmt" % "0.0.1" )
  16. align = most // before for { x <- List()

    yyy = 2 } yield { // ... } // after (<- と = をもalign) for { x <- List() yyy = 2 } yield { // ... }
  17. RewriteRules - AvoidInfix // before foo toList map { x

    => x should have length 5 } // after foo.toList.map { x => (x should have).length(5) }
  18. RewriteRules - RedundantBraces // before val x: Int => String

    = { case 2 => { "two" } case _ => { "other" } } // after val x: Int => String = { case 2 => "two" case _ => "other" }
  19. RewriteRules - RedundantParens // before for { a <- b

    if ((b ++ b).length >= 2) } yield a // after for { a <- b if (b ++ b).length >= 2 } yield a
  20. RewriteRules - SortModifiers // before final lazy private implicit val

    x = 42 lazy final implicit private val y = 42 // after implicit final private lazy val x = 42 implicit final private lazy val y = 42 sortModifiers.order = [“implicit”, “final” … ] で順番の設定も可能
  21. RewriteRules - SortImports // before import a.b.{c, a, b}, k.{

    g, f } // after import a.b.{a, b, c}, k.{f, g}
  22. newlineBeforeImplicitKW (default: false) // before override def load()(implicit taskCtx: Context,

    ec: ExecutionContext ): Future[Seq[A] Or B] // after override def load()( implicit taskCtx: Context, ec: ExecutionContext ): Future[Seq[A] Or B]
  23. newlineAfterImplicitKW (default: false) // before override def load()(implicit taskCtx: Context,

    ec: ExecutionContext ): Future[Seq[A] Or B] // after override def load()(implicit taskCtx: Context, ec: ExecutionContext ): Future[Seq[A] Or B]
  24. diffをできるだけ少なくしたい? https://github.com/mikr/whatstyle $ python whatstyle.py --formatter scalafmt --ignoreopts IGNOREOPTS <scalafile>

    - diffの少ない設定を生成してくれる - 他のフォーマッタ(rustfmt, scalariform, clang-format な ど)にも対応 - フォーマッタ本体と独立している
  25. diffをできるだけ少なくしたい? https://github.com/tanishiking/scalaunfmt maxColumn = [80, 100] align = [some, more,

    most] continuationIndent.callSite = [2, 4] continuationIndent.defnSite = [2, 4] verticalMultiline.newlineAfterImplicitKW = [true, false] $ scalaunfmt --config .scalaunfmt.conf test1.scala test2.scala - 設定の候補を(ホワイトリスト形式で)選べる - JVM warmup によるボトルネックがなく高速(whatstyle比)
  26. FAQ - JVM起動がボトルネックでscalafmtの起動が遅い - nailgun - SubstrateVM - githookでscalafmtしたい -

    https://medium.com/zyseme-technology/code-formatting-scalafmt-a nd-the-git-pre-commit-hook-3de71d099514 - sbtマルチプロジェクトで設定共有したい - common project で scalafmt.conf を生成するタスクを scalafmtConfigに依存させると吉 - コンパイル時にscalafmt走らせたい - scalafmtOnCompile (sbt-scalafmt)