From 7bae5ce36f60a3f4c26547e243d444957b48e01f Mon Sep 17 00:00:00 2001 From: Albert Meltzer <7529386+kitbellew@users.noreply.github.com> Date: Sat, 30 Mar 2024 07:37:45 -0700 Subject: [PATCH] scalafmt: enable newlines.source=fold formatting --- .scalafmt.conf | 1 + build.sbt | 386 ++-- project/Dependencies.scala | 2 +- .../scala/org/scalafmt/readme/Adopters.scala | 37 +- .../scala/org/scalafmt/readme/Readme.scala | 218 +-- .../benchmarks/MacroBenchmark.scala | 22 +- .../scalafmt/benchmarks/FormatBenchmark.scala | 15 +- .../scalafmt/benchmarks/MicroBenchmark.scala | 15 +- .../org/scalafmt/benchmarks/BenchmarkOK.scala | 10 +- .../src/main/scala/org/scalafmt/cli/Cli.scala | 132 +- .../scala/org/scalafmt/cli/CliArgParser.scala | 145 +- .../scala/org/scalafmt/cli/CliOptions.scala | 76 +- .../scala/org/scalafmt/cli/ExitCode.scala | 11 +- .../org/scalafmt/cli/FileFetchMode.scala | 11 +- .../scala/org/scalafmt/cli/InputMethod.scala | 59 +- .../scalafmt/cli/ScalafmtCliReporter.scala | 25 +- .../org/scalafmt/cli/ScalafmtCoreRunner.scala | 65 +- .../scalafmt/cli/ScalafmtDynamicRunner.scala | 18 +- .../org/scalafmt/cli/ScalafmtRunner.scala | 6 +- .../scala/org/scalafmt/cli/TermDisplay.scala | 225 +-- .../src/main/scala/org/scalafmt/Error.scala | 10 +- .../main/scala/org/scalafmt/Formatted.scala | 18 +- .../main/scala/org/scalafmt/Scalafmt.scala | 20 +- .../scala/org/scalafmt/config/Align.scala | 21 +- .../org/scalafmt/config/AlignToken.scala | 30 +- .../scalafmt/config/AvoidInfixSettings.scala | 129 +- .../scala/org/scalafmt/config/BinPack.scala | 22 +- .../main/scala/org/scalafmt/config/Case.scala | 15 +- .../scala/org/scalafmt/config/Comments.scala | 15 +- .../scalafmt/config/DanglingParentheses.scala | 27 +- .../org/scalafmt/config/Docstrings.scala | 31 +- .../org/scalafmt/config/FilterMatcher.scala | 5 +- .../org/scalafmt/config/ImportSelectors.scala | 4 +- .../org/scalafmt/config/IndentOperator.scala | 28 +- .../scala/org/scalafmt/config/Indents.scala | 20 +- .../org/scalafmt/config/LineEndings.scala | 4 +- .../scala/org/scalafmt/config/Literals.scala | 4 +- .../org/scalafmt/config/NamedDialect.scala | 14 +- .../scala/org/scalafmt/config/Newlines.scala | 146 +- .../scala/org/scalafmt/config/OptIn.scala | 4 +- .../scala/org/scalafmt/config/Presets.scala | 9 +- .../org/scalafmt/config/ProjectFiles.scala | 70 +- .../org/scalafmt/config/ReaderUtil.scala | 19 +- .../config/RedundantBracesSettings.scala | 4 +- .../config/RedundantParensSettings.scala | 8 +- .../config/RewriteScala3Settings.scala | 23 +- .../org/scalafmt/config/RewriteSettings.scala | 35 +- .../config/ScalafmtConfDecoders.scala | 10 +- .../org/scalafmt/config/ScalafmtConfig.scala | 186 +- .../scalafmt/config/ScalafmtOptimizer.scala | 4 +- .../org/scalafmt/config/ScalafmtParser.scala | 4 +- .../org/scalafmt/config/ScalafmtRunner.scala | 47 +- .../org/scalafmt/config/SortSettings.scala | 26 +- .../scala/org/scalafmt/config/Spaces.scala | 4 +- .../org/scalafmt/config/TrailingCommas.scala | 8 +- .../scalafmt/config/VerticalMultiline.scala | 4 +- .../org/scalafmt/config/XmlLiterals.scala | 8 +- .../scalafmt/internal/BestFirstSearch.scala | 98 +- .../org/scalafmt/internal/Decision.scala | 29 +- .../org/scalafmt/internal/FormatOps.scala | 1629 ++++++++--------- .../org/scalafmt/internal/FormatToken.scala | 52 +- .../org/scalafmt/internal/FormatTokens.scala | 184 +- .../org/scalafmt/internal/FormatWriter.scala | 704 ++++--- .../scala/org/scalafmt/internal/Indent.scala | 30 +- .../scala/org/scalafmt/internal/ModExt.scala | 25 +- .../org/scalafmt/internal/Modification.scala | 3 +- .../scala/org/scalafmt/internal/Policy.scala | 122 +- .../org/scalafmt/internal/PolicySummary.scala | 18 +- .../scala/org/scalafmt/internal/Router.scala | 1401 ++++++-------- .../scala/org/scalafmt/internal/Split.scala | 41 +- .../org/scalafmt/internal/SplitTag.scala | 4 +- .../scala/org/scalafmt/internal/State.scala | 188 +- .../scalafmt/internal/SyntacticGroup.scala | 88 +- .../scalafmt/internal/SyntacticGroupOps.scala | 89 +- .../org/scalafmt/internal/TokenRange.scala | 3 +- .../internal/TreeSyntacticGroup.scala | 147 +- .../org/scalafmt/rewrite/AvoidInfix.scala | 88 +- .../rewrite/ConvertToNewScala3Syntax.scala | 29 +- .../rewrite/FormatTokensRewrite.scala | 93 +- .../scala/org/scalafmt/rewrite/Imports.scala | 129 +- .../scala/org/scalafmt/rewrite/Patch.scala | 43 +- .../scalafmt/rewrite/PreferCurlyFors.scala | 30 +- .../scalafmt/rewrite/RedundantBraces.scala | 448 +++-- .../scalafmt/rewrite/RedundantParens.scala | 184 +- .../rewrite/RemoveEmptyDocstrings.scala | 3 +- .../rewrite/RemoveScala3OptionalBraces.scala | 124 +- .../scala/org/scalafmt/rewrite/Rewrite.scala | 97 +- .../rewrite/RewriteTrailingCommas.scala | 32 +- .../org/scalafmt/rewrite/SortModifiers.scala | 52 +- .../scala/org/scalafmt/util/LiteralOps.scala | 12 +- .../scala/org/scalafmt/util/LoggerOps.scala | 60 +- .../scala/org/scalafmt/util/PolicyOps.scala | 77 +- .../scala/org/scalafmt/util/StyleMap.scala | 99 +- .../org/scalafmt/util/TokenClasses.scala | 6 +- .../scala/org/scalafmt/util/TokenOps.scala | 70 +- .../org/scalafmt/util/TokenTraverser.scala | 38 +- .../org/scalafmt/util/TreeExtractors.scala | 20 +- .../scala/org/scalafmt/util/TreeOps.scala | 612 +++---- .../org/scalafmt/util/ValidationOps.scala | 62 +- .../main/scala/docs/DefaultsModifier.scala | 12 +- .../src/main/scala/docs/Docusaurus.scala | 6 +- .../src/main/scala/docs/FileModifier.scala | 7 +- scalafmt-docs/src/main/scala/docs/Main.scala | 28 +- .../main/scala/docs/ScalafmtModifier.scala | 10 +- .../src/main/scala/website/package.scala | 44 +- .../org/scalafmt/dynamic/package.scala | 19 +- .../org/scalafmt/dynamic/Dependency.scala | 4 +- .../dynamic/ScalafmtConfigLoader.scala | 37 +- .../scalafmt/dynamic/ScalafmtDynamic.scala | 7 +- .../dynamic/ScalafmtDynamicError.scala | 9 +- .../dynamic/ScalafmtDynamicSession.scala | 25 +- .../dynamic/ScalafmtModuleLoader.scala | 25 +- .../scalafmt/dynamic/ScalafmtProperties.scala | 17 +- .../scalafmt/dynamic/ScalafmtReflect.scala | 50 +- .../dynamic/ScalafmtReflectConfig.scala | 48 +- .../scalafmt/dynamic/ScalafmtVersion.scala | 35 +- .../exceptions/ScalafmtException.scala | 3 +- .../dynamic/utils/ReentrantCache.scala | 67 +- .../org/scalafmt/dynamic/DynamicSuite.scala | 198 +- .../org/scalafmt/dynamic/PositionSyntax.scala | 101 +- .../dynamic/ScalafmtVersionSuite.scala | 15 +- .../org/scalafmt/sysops/AbsoluteFile.scala | 51 +- .../org/scalafmt/sysops/BatchPathFinder.scala | 17 +- .../scala/org/scalafmt/sysops/FileOps.scala | 64 +- .../scala/org/scalafmt/sysops/GitOps.scala | 40 +- .../test/scala/org/scalafmt/CommentTest.scala | 4 +- .../org/scalafmt/CustomStructureTest.scala | 48 +- .../src/test/scala/org/scalafmt/Debug.scala | 53 +- .../scala/org/scalafmt/FidelityTest.scala | 12 +- .../test/scala/org/scalafmt/FormatTests.scala | 40 +- .../scala/org/scalafmt/LineEndingsTest.scala | 42 +- .../test/scala/org/scalafmt/ManualTests.scala | 9 +- .../test/scala/org/scalafmt/RangeTest.scala | 6 +- .../scala/org/scalafmt/ScalafmtProps.scala | 71 +- .../org/scalafmt/ScalafmtRunnerTest.scala | 23 +- .../test/scala/org/scalafmt/UnitTests.scala | 7 +- .../org/scalafmt/cli/CliOptionsTest.scala | 41 +- .../test/scala/org/scalafmt/cli/CliTest.scala | 894 ++++----- .../scala/org/scalafmt/cli/FakeGitOps.scala | 4 +- .../scala/org/scalafmt/cli/FileTestOps.scala | 28 +- .../config/AvoidInfixSettingsTest.scala | 11 +- .../scalafmt/config/ScalafmtConfigTest.scala | 122 +- .../scala/org/scalafmt/stats/GitInfo.scala | 10 +- .../scala/org/scalafmt/stats/JavaInfo.scala | 11 +- .../org/scalafmt/stats/MachineStats.scala | 7 +- .../scala/org/scalafmt/stats/OsInfo.scala | 6 +- .../scala/org/scalafmt/stats/TestStats.scala | 21 +- .../org/scalafmt/sysops/FileOpsTest.scala | 9 +- .../org/scalafmt/sysops/GitOpsTest.scala | 52 +- .../scala/org/scalafmt/util/CanRunTests.scala | 20 +- .../scala/org/scalafmt/util/DeleteTree.scala | 8 +- .../scala/org/scalafmt/util/ErrorTest.scala | 6 +- .../org/scalafmt/util/FormatAssertions.scala | 24 +- .../scala/org/scalafmt/util/HasTests.scala | 111 +- .../test/scala/org/scalafmt/util/Report.scala | 175 +- .../org/scalafmt/util/StyleMapTest.scala | 50 +- 156 files changed, 5405 insertions(+), 7237 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index b93b47d5fc..ed7c0ff472 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -14,6 +14,7 @@ align { newlines { avoidForSimpleOverflow = [punct, slc, tooLong] ignoreInSyntax = false + source = fold } rewrite { rules = [ diff --git a/build.sbt b/build.sbt index 5b2f16d7f5..5b7badc64a 100644 --- a/build.sbt +++ b/build.sbt @@ -12,37 +12,28 @@ def isCI = System.getenv("CI") != null def scala212 = "2.12.19" def scala213 = "2.13.13" -inThisBuild( - List( - version ~= { dynVer => - if (isCI) dynVer - else localSnapshotVersion // only for local publishing - }, - organization := "org.scalameta", - homepage := Some(url("https://github.com/scalameta/scalafmt")), - licenses := List( - "Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0") - ), - developers := List( - Developer( - "olafurpg", - "Ólafur Páll Geirsson", - "olafurpg@gmail.com", - url("https://geirsson.com") - ) - ), - scalaVersion := scala213, - crossScalaVersions := List(scala213, scala212), - resolvers ++= Resolver.sonatypeOssRepos("releases"), - resolvers ++= Resolver.sonatypeOssRepos("snapshots"), - libraryDependencies ++= List( - munit.value % Test, - scalacheck % Test, - scalametaTestkit % Test - ), - testFrameworks += new TestFramework("munit.Framework") - ) -) +inThisBuild(List( + version ~= { dynVer => + if (isCI) dynVer else localSnapshotVersion // only for local publishing + }, + organization := "org.scalameta", + homepage := Some(url("https://github.com/scalameta/scalafmt")), + licenses := + List("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")), + developers := List(Developer( + "olafurpg", + "Ólafur Páll Geirsson", + "olafurpg@gmail.com", + url("https://geirsson.com") + )), + scalaVersion := scala213, + crossScalaVersions := List(scala213, scala212), + resolvers ++= Resolver.sonatypeOssRepos("releases"), + resolvers ++= Resolver.sonatypeOssRepos("snapshots"), + libraryDependencies ++= + List(munit.value % Test, scalacheck % Test, scalametaTestkit % Test), + testFrameworks += new TestFramework("munit.Framework") +)) name := "scalafmtRoot" publish / skip := true @@ -55,133 +46,97 @@ commands += Command.command("ci-test") { s => case _ => scala213 } val docsTest = if (scalaVersion == scala212) "docs/run" else "version" - s"++$scalaVersion" :: - "tests/test" :: - "dynamic/test" :: - "publishLocal" :: - docsTest :: - s + s"++$scalaVersion" :: "tests/test" :: "dynamic/test" :: "publishLocal" :: + docsTest :: s } -lazy val dynamic = project - .in(file("scalafmt-dynamic")) - .settings( - moduleName := "scalafmt-dynamic", - description := "Implementation of scalafmt-interfaces", - buildInfoSettings, - buildInfoPackage := "org.scalafmt.dynamic", - buildInfoObject := "BuildInfo", - libraryDependencies ++= List( - "io.get-coursier" % "interface" % "0.0.17", - "com.typesafe" % "config" % "1.4.3", - munit.value % Test, - scalametaTestkit % Test - ), - scalacOptions ++= scalacJvmOptions.value - ) - .dependsOn(interfaces) - .dependsOn(core.jvm % "test") +lazy val dynamic = project.in(file("scalafmt-dynamic")).settings( + moduleName := "scalafmt-dynamic", + description := "Implementation of scalafmt-interfaces", + buildInfoSettings, + buildInfoPackage := "org.scalafmt.dynamic", + buildInfoObject := "BuildInfo", + libraryDependencies ++= List( + "io.get-coursier" % "interface" % "0.0.17", + "com.typesafe" % "config" % "1.4.3", + munit.value % Test, + scalametaTestkit % Test + ), + scalacOptions ++= scalacJvmOptions.value +).dependsOn(interfaces).dependsOn(core.jvm % "test") .enablePlugins(BuildInfoPlugin) -lazy val interfaces = project - .in(file("scalafmt-interfaces")) - .settings( - moduleName := "scalafmt-interfaces", - description := "Dependency-free, pure Java public interfaces to integrate with Scalafmt through a build tool or editor plugin.", - crossVersion := CrossVersion.disabled, - autoScalaLibrary := false, - Compile / resourceGenerators += Def.task { - val out = - (Compile / managedResourceDirectories).value.head / "scalafmt.properties" - val props = new java.util.Properties() - props.put("version", version.value) - IO.write(props, "scalafmt properties", out) - List(out) - } - ) +lazy val interfaces = project.in(file("scalafmt-interfaces")).settings( + moduleName := "scalafmt-interfaces", + description := + "Dependency-free, pure Java public interfaces to integrate with Scalafmt through a build tool or editor plugin.", + crossVersion := CrossVersion.disabled, + autoScalaLibrary := false, + Compile / resourceGenerators += Def.task { + val out = (Compile / managedResourceDirectories).value.head / + "scalafmt.properties" + val props = new java.util.Properties() + props.put("version", version.value) + IO.write(props, "scalafmt properties", out) + List(out) + } +) -lazy val sysops = crossProject(JVMPlatform) - .withoutSuffixFor(JVMPlatform) - .in(file("scalafmt-sysops")) - .settings( +lazy val sysops = crossProject(JVMPlatform).withoutSuffixFor(JVMPlatform) + .in(file("scalafmt-sysops")).settings( moduleName := "scalafmt-sysops", description := "Scalafmt systems operations", scalacOptions ++= scalacJvmOptions.value, libraryDependencies ++= { CrossVersion.partialVersion(scalaVersion.value) match { case Some((2, 12)) => - Seq( - "com.github.bigwheel" %% "util-backports" % "2.1" - ) + Seq("com.github.bigwheel" %% "util-backports" % "2.1") case Some((2, 13)) => - Seq( - "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4" - ) - case _ => - Seq( - ) + Seq("org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4") + case _ => Seq() } } ) -lazy val config = crossProject(JVMPlatform) - .withoutSuffixFor(JVMPlatform) - .in(file("scalafmt-config")) - .settings( +lazy val config = crossProject(JVMPlatform).withoutSuffixFor(JVMPlatform) + .in(file("scalafmt-config")).settings( moduleName := "scalafmt-config", description := "Scalafmt config parsing", scalacOptions ++= scalacJvmOptions.value, - libraryDependencies ++= Seq( - metaconfig.value - ) - ) - .jvmSettings( - libraryDependencies ++= Seq( - metaconfigTypesafe.value - ) - ) + libraryDependencies ++= Seq(metaconfig.value) + ).jvmSettings(libraryDependencies ++= Seq(metaconfigTypesafe.value)) // .jsSettings( // libraryDependencies ++= Seq( // metaconfigHocon.value, // ) // ) -lazy val core = crossProject(JVMPlatform) - .in(file("scalafmt-core")) - .settings( - moduleName := "scalafmt-core", - buildInfoSettings, - scalacOptions ++= scalacJvmOptions.value, - libraryDependencies ++= Seq( - scalameta.value, - "org.scalameta" %% "mdoc-parser" % mdocV, - // scala-reflect is an undeclared dependency of fansi, see #1252. - // Scalafmt itself does not require scala-reflect. - "org.scala-lang" % "scala-reflect" % scalaVersion.value - ), - libraryDependencies ++= { - CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, 13)) => - Seq( - ) - case _ => - Seq( - compilerPlugin( - "org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full - ) - ) - } +lazy val core = crossProject(JVMPlatform).in(file("scalafmt-core")).settings( + moduleName := "scalafmt-core", + buildInfoSettings, + scalacOptions ++= scalacJvmOptions.value, + libraryDependencies ++= Seq( + scalameta.value, + "org.scalameta" %% "mdoc-parser" % mdocV, + // scala-reflect is an undeclared dependency of fansi, see #1252. + // Scalafmt itself does not require scala-reflect. + "org.scala-lang" % "scala-reflect" % scalaVersion.value + ), + libraryDependencies ++= { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, 13)) => Seq() + case _ => Seq(compilerPlugin( + "org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full + )) } - ) + } +) // .jsSettings( // libraryDependencies ++= List( // scalatest.value % Test // must be here for coreJS/test to run anything // ) // ) - .jvmSettings( - Test / run / fork := true - ) - .dependsOn(sysops, config) + .jvmSettings(Test / run / fork := true).dependsOn(sysops, config) .enablePlugins(BuildInfoPlugin) lazy val coreJVM = core.jvm // lazy val coreJS = core.js @@ -191,125 +146,96 @@ import sbtassembly.AssemblyPlugin.defaultUniversalScript val scalacJvmOptions = Def.setting { val cross = CrossVersion.partialVersion(scalaVersion.value) match { case Some((2, 13)) => - Seq( - "-Ymacro-annotations", - "-Xfatal-warnings", - "-deprecation:false" - ) + Seq("-Ymacro-annotations", "-Xfatal-warnings", "-deprecation:false") case _ => Seq.empty } - val unused = Seq( - "imports", - "privates", - "locals", - "patvars", - "implicits" - ).map(x => s"-Ywarn-unused:$x") + val unused = Seq("imports", "privates", "locals", "patvars", "implicits") + .map(x => s"-Ywarn-unused:$x") cross ++ unused } -lazy val cli = project - .in(file("scalafmt-cli")) - .settings( - moduleName := "scalafmt-cli", - assembly / mainClass := Some("org.scalafmt.cli.Cli"), - assembly / assemblyOption := (assembly / assemblyOption).value - .withPrependShellScript(Some(defaultUniversalScript(shebang = false))), - assembly / assemblyJarName := "scalafmt.jar", - assembly / assemblyMergeStrategy := { - case "reflect.properties" => MergeStrategy.first - case x => - val oldStrategy = (assembly / assemblyMergeStrategy).value - oldStrategy(x) - }, - libraryDependencies ++= Seq( - "com.googlecode.java-diff-utils" % "diffutils" % "1.3.0", - "com.martiansoftware" % "nailgun-server" % "0.9.1", - "com.github.scopt" %% "scopt" % "4.1.0" - ), - scalacOptions ++= scalacJvmOptions.value, - Compile / mainClass := Some("org.scalafmt.cli.Cli"), - nativeImageVersion := "22.3.0", - nativeImageInstalled := isCI, - nativeImageOptions ++= { - val isMusl = sys.env.get("NATIVE_IMAGE_MUSL").exists(_.toBoolean) - if (isMusl) Seq("--libc=musl") else Nil - }, - nativeImageOptions ++= { - val isStatic = sys.env.get("NATIVE_IMAGE_STATIC").exists(_.toBoolean) - if (isStatic) Seq("--static") else Nil - } - ) - .dependsOn(coreJVM, dynamic) - .enablePlugins(NativeImagePlugin) +lazy val cli = project.in(file("scalafmt-cli")).settings( + moduleName := "scalafmt-cli", + assembly / mainClass := Some("org.scalafmt.cli.Cli"), + assembly / assemblyOption := (assembly / assemblyOption).value + .withPrependShellScript(Some(defaultUniversalScript(shebang = false))), + assembly / assemblyJarName := "scalafmt.jar", + assembly / assemblyMergeStrategy := { + case "reflect.properties" => MergeStrategy.first + case x => + val oldStrategy = (assembly / assemblyMergeStrategy).value + oldStrategy(x) + }, + libraryDependencies ++= Seq( + "com.googlecode.java-diff-utils" % "diffutils" % "1.3.0", + "com.martiansoftware" % "nailgun-server" % "0.9.1", + "com.github.scopt" %% "scopt" % "4.1.0" + ), + scalacOptions ++= scalacJvmOptions.value, + Compile / mainClass := Some("org.scalafmt.cli.Cli"), + nativeImageVersion := "22.3.0", + nativeImageInstalled := isCI, + nativeImageOptions ++= { + val isMusl = sys.env.get("NATIVE_IMAGE_MUSL").exists(_.toBoolean) + if (isMusl) Seq("--libc=musl") else Nil + }, + nativeImageOptions ++= { + val isStatic = sys.env.get("NATIVE_IMAGE_STATIC").exists(_.toBoolean) + if (isStatic) Seq("--static") else Nil + } +).dependsOn(coreJVM, dynamic).enablePlugins(NativeImagePlugin) -lazy val tests = project - .in(file("scalafmt-tests")) - .settings( - publish / skip := true, - libraryDependencies ++= Seq( - // Test dependencies - "com.lihaoyi" %% "scalatags" % "0.12.0", - scalametaTestkit, - munit.value - ), - scalacOptions ++= scalacJvmOptions.value, - javaOptions += "-Dfile.encoding=UTF8", - buildInfoPackage := "org.scalafmt.tests", - buildInfoKeys := Seq[BuildInfoKey]( - "resourceDirectory" -> (Test / resourceDirectory).value - ) - ) - .enablePlugins(BuildInfoPlugin) - .dependsOn(coreJVM, dynamic, cli) +lazy val tests = project.in(file("scalafmt-tests")).settings( + publish / skip := true, + libraryDependencies ++= Seq( + // Test dependencies + "com.lihaoyi" %% "scalatags" % "0.12.0", + scalametaTestkit, + munit.value + ), + scalacOptions ++= scalacJvmOptions.value, + javaOptions += "-Dfile.encoding=UTF8", + buildInfoPackage := "org.scalafmt.tests", + buildInfoKeys := + Seq[BuildInfoKey]("resourceDirectory" -> (Test / resourceDirectory).value) +).enablePlugins(BuildInfoPlugin).dependsOn(coreJVM, dynamic, cli) -lazy val benchmarks = project - .in(file("scalafmt-benchmarks")) - .settings( - publish / skip := true, - moduleName := "scalafmt-benchmarks", - libraryDependencies ++= Seq( - scalametaTestkit - ), - run / javaOptions ++= Seq( - "-Djava.net.preferIPv4Stack=true", - "-XX:+AggressiveOpts", - "-XX:+UseParNewGC", - "-XX:+UseConcMarkSweepGC", - "-XX:+CMSParallelRemarkEnabled", - "-XX:+CMSClassUnloadingEnabled", - "-XX:ReservedCodeCacheSize=128m", - "-XX:MaxMetaspaceSize=1024m", - "-XX:SurvivorRatio=128", - "-XX:MaxTenuringThreshold=0", - "-Xss8M", - "-Xms512M", - "-Xmx2G", - "-server" - ) +lazy val benchmarks = project.in(file("scalafmt-benchmarks")).settings( + publish / skip := true, + moduleName := "scalafmt-benchmarks", + libraryDependencies ++= Seq(scalametaTestkit), + run / javaOptions ++= Seq( + "-Djava.net.preferIPv4Stack=true", + "-XX:+AggressiveOpts", + "-XX:+UseParNewGC", + "-XX:+UseConcMarkSweepGC", + "-XX:+CMSParallelRemarkEnabled", + "-XX:+CMSClassUnloadingEnabled", + "-XX:ReservedCodeCacheSize=128m", + "-XX:MaxMetaspaceSize=1024m", + "-XX:SurvivorRatio=128", + "-XX:MaxTenuringThreshold=0", + "-Xss8M", + "-Xms512M", + "-Xmx2G", + "-server" ) - .dependsOn(coreJVM) - .enablePlugins(JmhPlugin) +).dependsOn(coreJVM).enablePlugins(JmhPlugin) -lazy val docs = project - .in(file("scalafmt-docs")) - .settings( - crossScalaVersions := List(scala212), - publish / skip := true, - mdoc := (Compile / run).evaluated - ) - .dependsOn(cli, dynamic) - .enablePlugins(DocusaurusPlugin) +lazy val docs = project.in(file("scalafmt-docs")).settings( + crossScalaVersions := List(scala212), + publish / skip := true, + mdoc := (Compile / run).evaluated +).dependsOn(cli, dynamic).enablePlugins(DocusaurusPlugin) val V = "\\d+\\.\\d+\\.\\d+" val ReleaseCandidate = s"($V-RC\\d+).*".r val Milestone = s"($V-M\\d+).*".r -lazy val stableVersion = Def.setting { - (ThisBuild / version).value.replaceAll("\\+.*", "") -} +lazy val stableVersion = Def + .setting { (ThisBuild / version).value.replaceAll("\\+.*", "") } lazy val buildInfoSettings: Seq[Def.Setting[_]] = Seq( buildInfoKeys := Seq[BuildInfoKey]( diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 7e45ed997a..47921d0363 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -3,7 +3,7 @@ import sbt.Keys._ import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._ import org.portablescala.sbtplatformdeps.PlatformDepsPlugin.autoImport._ -// scalafmt: { maxColumn = 120, align.preset = more } +// scalafmt: { maxColumn = 100, align.preset = more, align.allowOverflow = true } object Dependencies { val metaconfigV = "0.12.0" diff --git a/readme/src/main/scala/org/scalafmt/readme/Adopters.scala b/readme/src/main/scala/org/scalafmt/readme/Adopters.scala index 7f6d6238c2..09bd56f599 100644 --- a/readme/src/main/scala/org/scalafmt/readme/Adopters.scala +++ b/readme/src/main/scala/org/scalafmt/readme/Adopters.scala @@ -2,26 +2,15 @@ package org.scalafmt.readme import scalatags.Text.TypedTag -case class Adopter( - name: String, - url: String, - description: Option[String] = None -) { +case class Adopter(name: String, url: String, description: Option[String] = None) { import scalatags.Text.all._ def bullet: TypedTag[String] = - li( - a(href := url, name), - description.fold("")(x => s": $x") - ) + li(a(href := url, name), description.fold("")(x => s": $x")) } object Adopters { val adopters = Seq[Adopter]( - Adopter( - "scalafmt", - "http://scalafmt.org", - Some("Code formatter for Scala") - ), + Adopter("scalafmt", "http://scalafmt.org", Some("Code formatter for Scala")), Adopter( "sbt", "https://github.com/sbt/sbt", @@ -47,9 +36,7 @@ object Adopters { Adopter( "Venatus Media", "https://venatusmedia.com", - Some( - "We represent some of the largest entertainment publishers and monetize billions of ads." - ) + Some("We represent some of the largest entertainment publishers and monetize billions of ads.") ), Adopter( "http4s", @@ -59,30 +46,22 @@ object Adopters { Adopter( "Mendix", "https://mendix.com", - Some( - "The fastest and easiest platform to create and continuously improve mobile and web apps at scale." - ) + Some("The fastest and easiest platform to create and continuously improve mobile and web apps at scale.") ), Adopter( "Foursquare", "https://enterprise.foursquare.com", - Some( - "We use location intelligence to build meaningful consumer experiences and business solutions." - ) + Some("We use location intelligence to build meaningful consumer experiences and business solutions.") ), Adopter( "Codacy", "https://codacy.com", - Some( - "Codacy is an Automated Code Review Tool that monitors your technical debt, helps you improve your code quality, teaches best practices to your developers, and helps you save time in Code Reviews." - ) + Some("Codacy is an Automated Code Review Tool that monitors your technical debt, helps you improve your code quality, teaches best practices to your developers, and helps you save time in Code Reviews.") ), Adopter( "ZyseMe", "https://www.zyse.me/", - Some( - "We use ML to predict body measurements and automate pattern creation to integrate with production, allowing companies to produce and/or sell made-to-measure garments at scale." - ) + Some("We use ML to predict body measurements and automate pattern creation to integrate with production, allowing companies to produce and/or sell made-to-measure garments at scale.") ) ) } diff --git a/readme/src/main/scala/org/scalafmt/readme/Readme.scala b/readme/src/main/scala/org/scalafmt/readme/Readme.scala index ff6ee99ef8..6d111bb545 100644 --- a/readme/src/main/scala/org/scalafmt/readme/Readme.scala +++ b/readme/src/main/scala/org/scalafmt/readme/Readme.scala @@ -21,15 +21,15 @@ object hl extends scalatex.site.Highlighter object Readme { - def gitter = - a( - href := "https://gitter.im/scalameta/scalafmt", - img( - src := "https://camo.githubusercontent.com/da2edb525cde1455a622c58c0effc3a90b9a181c/68747470733a2f2f6261646765732e6769747465722e696d2f4a6f696e253230436861742e737667", - alt := "Join the chat at https://gitter.im/scalameta/scalameta", - maxWidth := "100%;" - ) + def gitter = a( + href := "https://gitter.im/scalameta/scalafmt", + img( + src := + "https://camo.githubusercontent.com/da2edb525cde1455a622c58c0effc3a90b9a181c/68747470733a2f2f6261646765732e6769747465722e696d2f4a6f696e253230436861742e737667", + alt := "Join the chat at https://gitter.im/scalameta/scalameta", + maxWidth := "100%;" ) + ) val eval = new Eval() implicit def bool2frag(boolean: Boolean): StringFrag = @@ -54,22 +54,18 @@ object Readme { val expressions = s"{$code}".parse[Stat].get.asInstanceOf[Term.Block].stats val evaluated = eval[Any](code) val output = evaluated match { - case s: String => - s""" + case s: String => s""" |"$s"""".stripMargin case x => x.toString } - val result = s"""${expressions - .map(x => s"scala> ${x.toString().trim}") - .mkString("\n")} - |res0: ${evaluated.getClass.getName} = $output - |""".stripMargin + val result = + s"""${expressions.map(x => s"scala> ${x.toString().trim}").mkString("\n")} + |res0: ${evaluated.getClass.getName} = $output + |""".stripMargin hl.scala(result) } - def config(frags: Frag*) = { - cliFlags(frags.render) - } + def config(frags: Frag*) = { cliFlags(frags.render) } def cliFlags(flags: String) = { Config.fromHoconString(flags).get hl.scala(flags) @@ -86,10 +82,9 @@ object Readme { def gitRepo: String = repo + ".git" def user(name: String) = a(href := s"$github/$name", s"@$name") - def users(names: String*) = - span( - names.dropRight(1).map(x => span(user(x), ", ")) :+ user(names.last): _* - ) + def users(names: String*) = span( + names.dropRight(1).map(x => span(user(x), ", ")) :+ user(names.last): _* + ) def pr(id: Int) = a(href := repo + s"/pull/$id", s"#$id") def issue(id: Int) = a(href := repo + s"/issues/$id", s"#$id") @@ -118,8 +113,7 @@ object Readme { Conf.printHocon(diff) } - def allOptions = - hl.scala.apply(Conf.printHocon(ScalafmtConfig.default)) + def allOptions = hl.scala.apply(Conf.printHocon(ScalafmtConfig.default)) def configurationBlock( style: ScalafmtConfig, @@ -132,10 +126,7 @@ object Readme { ), pre(changedConfig(style)), `class` := { - "scalafmt-configuration" + ( - if (collapsed) " collapsed" - else "" - ) + "scalafmt-configuration" + (if (collapsed) " collapsed" else "") } ) } @@ -143,23 +134,18 @@ object Readme { def fullWidthDemo(style: ScalafmtConfig)(code: String): TypedTag[String] = { val formatted = Scalafmt.format(code, style).get div( - rows( - List( - div(hl.scala(code), `class` := "before"), - div(hl.scala(formatted), `class` := "after") - ) - ), + rows(List( + div(hl.scala(code), `class` := "before"), + div(hl.scala(formatted), `class` := "after") + )), configurationBlock(style) ) } def demoStyle(style: ScalafmtConfig)(code: String): TypedTag[String] = { - val formatted = - Scalafmt.format(code, style.copy(runner = ScalafmtRunner.sbt)).get - div( - sideBySide(code, formatted), - configurationBlock(style) - ) + val formatted = Scalafmt + .format(code, style.copy(runner = ScalafmtRunner.sbt)).get + div(sideBySide(code, formatted), configurationBlock(style)) } def example(code: String): TypedTag[String] = { @@ -167,72 +153,47 @@ object Readme { } def exampleAlign(code: String): TypedTag[String] = { - val formatted = Scalafmt - .format( - code, - ScalafmtConfig.default40.copy( - align = - ScalafmtConfig.default40.align.copy(tokens = AlignToken.default) - ) + val formatted = Scalafmt.format( + code, + ScalafmtConfig.default40.copy(align = + ScalafmtConfig.default40.align.copy(tokens = AlignToken.default) ) - .get + ).get hl.scala(formatted) } - val stripMarginStyle = - ScalafmtConfig.default.copy(assumeStandardLibraryStripMargin = true) + val stripMarginStyle = ScalafmtConfig.default + .copy(assumeStandardLibraryStripMargin = true) - val rewriteInfix = - ScalafmtConfig.default.copy( - rewrite = ScalafmtConfig.default.rewrite.copy( - rules = Seq(AvoidInfix) - ) - ) + val rewriteInfix = ScalafmtConfig.default + .copy(rewrite = ScalafmtConfig.default.rewrite.copy(rules = Seq(AvoidInfix))) - val rewriteImportSelectors = - ScalafmtConfig.default.copy( - rewrite = ScalafmtConfig.default.rewrite.copy( - rules = Seq(ExpandImportSelectors) - ) - ) + val rewriteImportSelectors = ScalafmtConfig.default.copy(rewrite = + ScalafmtConfig.default.rewrite.copy(rules = Seq(ExpandImportSelectors)) + ) - val rewriteBraces = - ScalafmtConfig.default.copy( - rewrite = ScalafmtConfig.default.rewrite.copy( - redundantBraces = ScalafmtConfig.default.rewrite.redundantBraces.copy( - stringInterpolation = true - ), - rules = Seq(RedundantBraces) - ) + val rewriteBraces = ScalafmtConfig.default.copy(rewrite = + ScalafmtConfig.default.rewrite.copy( + redundantBraces = ScalafmtConfig.default.rewrite.redundantBraces + .copy(stringInterpolation = true), + rules = Seq(RedundantBraces) ) + ) - val rewriteParens = - ScalafmtConfig.default.copy( - rewrite = ScalafmtConfig.default.rewrite.copy( - rules = Seq(RedundantParens) - ) - ) + val rewriteParens = ScalafmtConfig.default.copy(rewrite = + ScalafmtConfig.default.rewrite.copy(rules = Seq(RedundantParens)) + ) - val rewriteImports = - ScalafmtConfig.default.copy( - rewrite = ScalafmtConfig.default.rewrite.copy( - rules = Seq(SortImports) - ) - ) + val rewriteImports = ScalafmtConfig.default + .copy(rewrite = ScalafmtConfig.default.rewrite.copy(rules = Seq(SortImports))) - val rewriteAsciiImports = - ScalafmtConfig.default.copy( - rewrite = ScalafmtConfig.default.rewrite.copy( - rules = Seq(AsciiSortImports) - ) - ) + val rewriteAsciiImports = ScalafmtConfig.default.copy(rewrite = + ScalafmtConfig.default.rewrite.copy(rules = Seq(AsciiSortImports)) + ) - val rewriteSortModifiers = - ScalafmtConfig.default120.copy( - rewrite = ScalafmtConfig.default.rewrite.copy( - rules = Seq(SortModifiers) - ) - ) + val rewriteSortModifiers = ScalafmtConfig.default120.copy(rewrite = + ScalafmtConfig.default.rewrite.copy(rules = Seq(SortModifiers)) + ) /** This looks way too hacky. But can't seem to find a typeclass that ought to * "encode" the ``ModKey`` enum. @@ -246,44 +207,34 @@ object Readme { * [error] @code{rewrite.sortModifiers.order} = @rewriteSortModifiers.rewrite.sortModifiers.order * }}} */ - val rewriteSortModifiersDefaultString = - SortSettings.defaultOrder - .map(_.productPrefix) - .mkString("[\"", "\", \"", "\"]") - - val rewritePreferCurlyFors = - ScalafmtConfig.default.copy( - rewrite = ScalafmtConfig.default.rewrite.copy( - rules = Seq(PreferCurlyFors) - ) - ) + val rewriteSortModifiersDefaultString = SortSettings.defaultOrder + .map(_.productPrefix).mkString("[\"", "\", \"", "\"]") + + val rewritePreferCurlyFors = ScalafmtConfig.default.copy(rewrite = + ScalafmtConfig.default.rewrite.copy(rules = Seq(PreferCurlyFors)) + ) val verticalAlign = ScalafmtConfig.default.copy( maxColumn = 60, verticalMultiline = VerticalMultiline(atDefnSite = true) ) - val verticalMultilineDefaultConfigStr = Conf.printHocon( - Conf.Obj( - "verticalMultiline" -> ConfEncoder[VerticalMultiline] + val verticalMultilineDefaultConfigStr = Conf.printHocon(Conf.Obj( + "verticalMultiline" -> + ConfEncoder[VerticalMultiline] .write(ScalafmtConfig.default.verticalMultiline) - ) - ) + )) val verticalAlignImplicitBefore = ScalafmtConfig.default.copy( maxColumn = 60, - verticalMultiline = VerticalMultiline( - atDefnSite = true, - newlineBeforeImplicitKW = true - ) + verticalMultiline = + VerticalMultiline(atDefnSite = true, newlineBeforeImplicitKW = true) ) val verticalAlignImplicitAfter = ScalafmtConfig.default.copy( maxColumn = 60, - verticalMultiline = VerticalMultiline( - atDefnSite = true, - newlineAfterImplicitKW = true - ) + verticalMultiline = + VerticalMultiline(atDefnSite = true, newlineAfterImplicitKW = true) ) val multilineNewlineAfterParen = ScalafmtConfig.default.copy( @@ -304,22 +255,20 @@ object Readme { ) ) - val newlineAlwaysBeforeTopLevelStatements = ScalafmtConfig.default.copy( - newlines = ScalafmtConfig.default.newlines - .copy(alwaysBeforeTopLevelStatements = true) - ) - - val arityThreshold = - ScalafmtConfig.default.copy( - verticalMultiline = - VerticalMultiline(atDefnSite = true, arityThreshold = 2) + val newlineAlwaysBeforeTopLevelStatements = ScalafmtConfig.default + .copy(newlines = + ScalafmtConfig.default.newlines.copy(alwaysBeforeTopLevelStatements = true) ) + val arityThreshold = ScalafmtConfig.default.copy(verticalMultiline = + VerticalMultiline(atDefnSite = true, arityThreshold = 2) + ) + def fmt(style: ScalafmtConfig)(code: String): TypedTag[String] = example(code, style) - def lastUpdated = - new SimpleDateFormat("MMM d, y").format(new Date(Versions.timestamp.toLong)) + def lastUpdated = new SimpleDateFormat("MMM d, y") + .format(new Date(Versions.timestamp.toLong)) def format(code: String): TypedTag[String] = { format(ScalafmtConfig.default)(code) @@ -330,9 +279,8 @@ object Readme { val alignMore = ScalafmtConfig.default.copy(align = Align.more) val alignMost = ScalafmtConfig.default.copy(align = Align.most) val alignCaseArrow = ScalafmtConfig.default - val alignArrowEnum = ScalafmtConfig.defaultWithAlign.copy( - align = Align.default.copy(arrowEnumeratorGenerator = true) - ) + val alignArrowEnum = ScalafmtConfig.defaultWithAlign + .copy(align = Align.default.copy(arrowEnumeratorGenerator = true)) val alignModuleId = ScalafmtConfig.defaultWithAlign def format(style: ScalafmtConfig)(code: String): TypedTag[String] = { @@ -344,9 +292,5 @@ object Readme { hl.scala(formatted) } def image(url: String) = - img( - src := url, - width := "100%", - textAlign := "center" - ) + img(src := url, width := "100%", textAlign := "center") } diff --git a/scalafmt-benchmarks/src/main/scala-2.12/benchmarks/MacroBenchmark.scala b/scalafmt-benchmarks/src/main/scala-2.12/benchmarks/MacroBenchmark.scala index e83276e431..c33062fa5b 100644 --- a/scalafmt-benchmarks/src/main/scala-2.12/benchmarks/MacroBenchmark.scala +++ b/scalafmt-benchmarks/src/main/scala-2.12/benchmarks/MacroBenchmark.scala @@ -19,8 +19,7 @@ import scala.util.Try @org.openjdk.jmh.annotations.State(Scope.Benchmark) @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@BenchmarkMode(Array(Mode.AverageTime)) -@OutputTimeUnit(TimeUnit.SECONDS) +@BenchmarkMode(Array(Mode.AverageTime)) @OutputTimeUnit(TimeUnit.SECONDS) abstract class MacroBenchmark(parallel: Boolean, maxFiles: Int) extends FormatBenchmark { var files: GenIterable[String] = _ @@ -30,19 +29,12 @@ abstract class MacroBenchmark(parallel: Boolean, maxFiles: Int) @Setup def setup(): Unit = { files = { - val x = Corpus - .files( - Corpus.fastparse.copy( - // TODO(olafur) remove once testkit 1.7 is out - url = Corpus.fastparse.url.replace("olafurpg", "scalameta") - ) - ) - .filter { f => f.projectUrl.contains("scala-js") } - .take(maxFiles) - .map(_.read) - .toBuffer - if (parallel) x.par - else x + val x = Corpus.files(Corpus.fastparse.copy( + // TODO(olafur) remove once testkit 1.7 is out + url = Corpus.fastparse.url.replace("olafurpg", "scalameta") + )).filter { f => f.projectUrl.contains("scala-js") }.take(maxFiles) + .map(_.read).toBuffer + if (parallel) x.par else x } } diff --git a/scalafmt-benchmarks/src/main/scala/org/scalafmt/benchmarks/FormatBenchmark.scala b/scalafmt-benchmarks/src/main/scala/org/scalafmt/benchmarks/FormatBenchmark.scala index b991fd8c9e..c83eaeeb78 100644 --- a/scalafmt-benchmarks/src/main/scala/org/scalafmt/benchmarks/FormatBenchmark.scala +++ b/scalafmt-benchmarks/src/main/scala/org/scalafmt/benchmarks/FormatBenchmark.scala @@ -6,15 +6,10 @@ import org.scalafmt.rewrite.{RedundantBraces, SortImports} trait FormatBenchmark { def formatRewrite(code: String): String = { - Scalafmt - .formatCode( - code, - baseStyle = ScalafmtConfig.default.copy( - rewrite = RewriteSettings( - rules = Seq(SortImports, RedundantBraces) - ) - ) - ) - .get + Scalafmt.formatCode( + code, + baseStyle = ScalafmtConfig.default + .copy(rewrite = RewriteSettings(rules = Seq(SortImports, RedundantBraces))) + ).get } } diff --git a/scalafmt-benchmarks/src/main/scala/org/scalafmt/benchmarks/MicroBenchmark.scala b/scalafmt-benchmarks/src/main/scala/org/scalafmt/benchmarks/MicroBenchmark.scala index 87ab7ff7e1..4a00627fc4 100644 --- a/scalafmt-benchmarks/src/main/scala/org/scalafmt/benchmarks/MicroBenchmark.scala +++ b/scalafmt-benchmarks/src/main/scala/org/scalafmt/benchmarks/MicroBenchmark.scala @@ -20,16 +20,13 @@ import org.scalafmt.sysops.FileOps @org.openjdk.jmh.annotations.State(Scope.Benchmark) @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) -@BenchmarkMode(Array(Mode.AverageTime)) -@OutputTimeUnit(TimeUnit.MILLISECONDS) +@BenchmarkMode(Array(Mode.AverageTime)) @OutputTimeUnit(TimeUnit.MILLISECONDS) abstract class MicroBenchmark(path: String*) extends FormatBenchmark { val classLoader = getClass.getClassLoader var code: String = _ @Setup - def setup(): Unit = { - code = FileOps.readFile(getPath) - } + def setup(): Unit = { code = FileOps.readFile(getPath) } def getPath: Path = { val filename = FileOps.getFile(Seq("src", "resources") ++ path) @@ -45,14 +42,10 @@ abstract class MicroBenchmark(path: String*) extends FormatBenchmark { } @Benchmark - def scalafmt(): String = { - Scalafmt.format(code).get - } + def scalafmt(): String = { Scalafmt.format(code).get } @Benchmark - def scalafmt_rewrite(): String = { - formatRewrite(code) - } + def scalafmt_rewrite(): String = { formatRewrite(code) } def testMe(): Unit = { setup() diff --git a/scalafmt-benchmarks/src/test/scala-2.12/org/scalafmt/benchmarks/BenchmarkOK.scala b/scalafmt-benchmarks/src/test/scala-2.12/org/scalafmt/benchmarks/BenchmarkOK.scala index 92b9e59642..4efac1dd0a 100644 --- a/scalafmt-benchmarks/src/test/scala-2.12/org/scalafmt/benchmarks/BenchmarkOK.scala +++ b/scalafmt-benchmarks/src/test/scala-2.12/org/scalafmt/benchmarks/BenchmarkOK.scala @@ -11,10 +11,7 @@ class TestMicroMedium extends ScalaJsFile("PrintStreamTest.scala") class BenchmarkOK extends FunSuite { - Seq( - new TestMacroP, - new TestMacroS - ).foreach { benchmark => + Seq(new TestMacroP, new TestMacroS).foreach { benchmark => val name = s"macroBenchmark: $benchmark" test(name) { benchmark.testMe() @@ -22,10 +19,7 @@ class BenchmarkOK extends FunSuite { } } - Seq( - new TestMicroMedium, - new TestMicroSmall - ).foreach { formatBenchmark => + Seq(new TestMicroMedium, new TestMicroSmall).foreach { formatBenchmark => val name = s"microBenchmark: ${formatBenchmark.getClass}" test(name) { formatBenchmark.testMe() diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/Cli.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/Cli.scala index 771d8c6ea4..981d96507d 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/Cli.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/Cli.scala @@ -12,17 +12,18 @@ import scala.util.control.NoStackTrace object Cli { def nailMain(nGContext: NGContext): Unit = { - val workingDirectory = - AbsoluteFile.fromPathIfAbsolute(nGContext.getWorkingDirectory).getOrElse { - throw new IllegalStateException( - s"Expected absolute path, " + - s"obtained nGContext.getWorkingDirectory = ${nGContext.getWorkingDirectory}" - ) - } + val workingDirectory = AbsoluteFile.fromPathIfAbsolute( + nGContext.getWorkingDirectory + ).getOrElse { + throw new IllegalStateException( + s"Expected absolute path, " + + s"obtained nGContext.getWorkingDirectory = ${nGContext.getWorkingDirectory}" + ) + } val exit = mainWithOptions( nGContext.getArgs, - CliOptions.default.copy( - common = CliOptions.default.common.copy( + CliOptions.default.copy(common = + CliOptions.default.common.copy( cwd = Some(workingDirectory), out = nGContext.out, in = nGContext.in, @@ -65,9 +66,7 @@ object Cli { def getConfig(args: Array[String], init: CliOptions): Option[CliOptions] = { val expandedArguments = expandArguments(args) - CliArgParser.scoptParser - .parse(expandedArguments, init) - .map(CliOptions.auto) + CliArgParser.scoptParser.parse(expandedArguments, init).map(CliOptions.auto) } private def expandArguments(args: Seq[String]): Seq[String] = { @@ -87,73 +86,69 @@ object Cli { case Left(message) => options.common.err.println(message) ExitCode.UnsupportedVersion - case Right(runner) => - runWithRunner(options, runner) + case Right(runner) => runWithRunner(options, runner) } } - private val isNativeImage: Boolean = - "true" == System.getProperty("scalafmt.native-image", "false") + private val isNativeImage: Boolean = "true" == + System.getProperty("scalafmt.native-image", "false") private def getProposedConfigVersion(options: CliOptions): String = s"version = $stableVersion" private type MaybeRunner = Either[String, ScalafmtRunner] - private def findRunner( - options: CliOptions - ): MaybeRunner = options.hoconOpt.fold[MaybeRunner] { - Left( - s"""error: missing Scalafmt configuration file. - |Consider creating '${options.getProposedConfigFile}' - |with the following (other parameters may also be required): - |${getProposedConfigVersion(options)} - |""".stripMargin - ) - } { - // Run format using - // - `scalafmt-dynamic` if the specified `version` setting doesn't match build version. - // - `scalafmt-core` if the specified `version` setting match with build version - // (or if the `version` is not specified). - _.version.fold[MaybeRunner] { - val where = options.configStr match { - case None => - options.canonicalConfigFile - .fold(options.getProposedConfigFile)(_.get) - .toString - case _ => "--config-str option" - } + private def findRunner(options: CliOptions): MaybeRunner = options.hoconOpt + .fold[MaybeRunner] { Left( - s"""error: missing Scalafmt version. - |Consider adding the following to $where: + s"""error: missing Scalafmt configuration file. + |Consider creating '${options.getProposedConfigFile}' + |with the following (other parameters may also be required): |${getProposedConfigVersion(options)} |""".stripMargin ) } { - case Left(error) => - Left(s"error: invalid configuration: ${error}") - case Right(`stableVersion`) => - options.common.debug.println(s"Using core runner [$stableVersion]") - Right(ScalafmtCoreRunner) - case Right(v) if isNativeImage => + // Run format using + // - `scalafmt-dynamic` if the specified `version` setting doesn't match build version. + // - `scalafmt-core` if the specified `version` setting match with build version + // (or if the `version` is not specified). + _.version.fold[MaybeRunner] { + val where = options.configStr match { + case None => options.canonicalConfigFile + .fold(options.getProposedConfigFile)(_.get).toString + case _ => "--config-str option" + } Left( - s"""error: invalid Scalafmt version. - | - |This Scalafmt installation has version '$stableVersion' and the version configured in '${options.configPath}' is '$v'. - |To fix this problem, add the following line to .scalafmt.conf: - |``` - |version = $stableVersion - |``` - | - |NOTE: this error happens only when running a native Scalafmt binary. - |Scalafmt automatically installs and invokes the correct version of Scalafmt when running on the JVM. + s"""error: missing Scalafmt version. + |Consider adding the following to $where: + |${getProposedConfigVersion(options)} |""".stripMargin ) - case Right(v) => - options.common.debug.println(s"Using dynamic runner [$v]") - Right(ScalafmtDynamicRunner) + } { + case Left(error) => Left(s"error: invalid configuration: ${error}") + case Right(`stableVersion`) => + options.common.debug.println(s"Using core runner [$stableVersion]") + Right(ScalafmtCoreRunner) + case Right(v) if isNativeImage => + Left( + s"""error: invalid Scalafmt version. + | + |This Scalafmt installation has version '$stableVersion' and the version configured in '${options + .configPath}' is '$v'. + |To fix this problem, add the following line to .scalafmt.conf: + |``` + |version = $stableVersion + |``` + | + |NOTE: this error happens only when running a native Scalafmt binary. + |Scalafmt automatically installs and invokes the correct version of Scalafmt when running on the JVM. + |""".stripMargin + ) + case Right(v) => + options.common.debug.println(s"Using dynamic runner [$v]") + Right(ScalafmtDynamicRunner) + } } - } private[cli] def runWithRunner( options: CliOptions, @@ -171,23 +166,16 @@ object Cli { if (exit.isOk) { options.common.out.println("All files are formatted with scalafmt :)") } else if (exit.is(ExitCode.TestError)) { - options.common.out.println( - "error: --test failed" - ) + options.common.out.println("error: --test failed") options.onTestFailure.foreach(options.common.out.println) - } else { - options.common.out.println(s"error: $exit") - } + } else { options.common.out.println(s"error: $exit") } } if ( - options.writeMode == WriteMode.Test && - !options.fatalWarnings && + options.writeMode == WriteMode.Test && !options.fatalWarnings && exit.is(ExitCode.ParseError) ) { // Ignore parse errors etc. ExitCode.Ok - } else { - exit - } + } else { exit } } } diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/CliArgParser.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/CliArgParser.scala index f015e048a9..ad07a9332a 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/CliArgParser.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/CliArgParser.scala @@ -25,7 +25,8 @@ object CliArgParser { |scalafmt --stdout Code.scala # print formatted contents to stdout. |scalafmt --exclude target # format all files in directory excluding target |scalafmt --config .scalafmt.conf # read custom style from file. - |scalafmt --config-str "style=IntelliJ" # define custom style as a flag, must be quoted.""".stripMargin + |scalafmt --config-str "style=IntelliJ" # define custom style as a flag, must be quoted.""" + .stripMargin val scoptParser: OptionParser[CliOptions] = new scopt.OptionParser[CliOptions]("scalafmt") { @@ -34,8 +35,7 @@ object CliArgParser { private def printAndExit( includeUsage: Boolean )(ignore: Unit, c: CliOptions): CliOptions = { - if (includeUsage) displayToOut(usage) - else displayToOut(header) + if (includeUsage) displayToOut(usage) else displayToOut(header) sys.exit c } @@ -45,126 +45,90 @@ object CliArgParser { } head("scalafmt", Versions.nightly) - opt[Unit]('h', "help") - .action(printAndExit(includeUsage = true)) + opt[Unit]('h', "help").action(printAndExit(includeUsage = true)) .text("prints this usage text") - opt[Unit]('v', "version") - .action(printAndExit(includeUsage = false)) + opt[Unit]('v', "version").action(printAndExit(includeUsage = false)) .text("print version ") - arg[Path]("...") - .optional() - .unbounded() - .action((file, c) => c.addFile(file)) - .text( - """file, or directory (in which all *.scala files are to be formatted); - |if starts with '@', refers to path listing files to be formatted - |(with "@-" referring to standard input as a special case)""".stripMargin - ) + arg[Path]("...").optional().unbounded().action((file, c) => + c.addFile(file) + ).text( + """file, or directory (in which all *.scala files are to be formatted); + |if starts with '@', refers to path listing files to be formatted + |(with "@-" referring to standard input as a special case)""" + .stripMargin + ) - opt[Seq[Path]]('f', "files") - .action((files, c) => c.withFiles(files)) + opt[Seq[Path]]('f', "files").action((files, c) => c.withFiles(files)) .hidden() // this option isn't needed anymore. Simply pass the files as // arguments. Keeping for backwards compatibility - .text( - "file or directory, in which case all *.scala files are formatted. Deprecated: pass files as arguments" - ) + .text("file or directory, in which case all *.scala files are formatted. Deprecated: pass files as arguments") opt[Unit]('i', "in-place") - .action((_, c) => writeMode(c, WriteMode.Override)) - .hidden() // this option isn't needed anymore. Simply don't pass + .action((_, c) => writeMode(c, WriteMode.Override)).hidden() // this option isn't needed anymore. Simply don't pass // --stdout. Keeping for backwards compatibility .text("format files in-place (default)") - opt[Unit]("stdout") - .action((_, c) => writeMode(c, WriteMode.Stdout)) + opt[Unit]("stdout").action((_, c) => writeMode(c, WriteMode.Stdout)) .text("write formatted files to stdout") - opt[Seq[String]]("exclude") - .unbounded() + opt[Seq[String]]("exclude").unbounded() .action((excludes, c) => c.copy(customExcludes = excludes)) - .text( - "file or directory, when missing all *.scala files are formatted." - ) + .text("file or directory, when missing all *.scala files are formatted.") opt[Unit]("respect-project-filters") - .action((_, c) => c.copy(respectProjectFilters = true)) - .text( + .action((_, c) => c.copy(respectProjectFilters = true)).text( "use project filters even when specific files to format are provided" ) - opt[Path]('c', "config") - .action((file, c) => c.copy(config = Some(file))) + opt[Path]('c', "config").action((file, c) => c.copy(config = Some(file))) .text("a file path to .scalafmt.conf.") - opt[String]("config-str") - .action(readConfig) + opt[String]("config-str").action(readConfig) .text("configuration defined as a string") - opt[Unit]("stdin") - .action((_, c) => c.copy(stdIn = true)) + opt[Unit]("stdin").action((_, c) => c.copy(stdIn = true)) .text("read from stdin and print to stdout") - opt[Unit]("no-stderr") - .action((_, c) => c.copy(noStdErr = true)) + opt[Unit]("no-stderr").action((_, c) => c.copy(noStdErr = true)) .text("don't use strerr for messages, output to stdout") opt[String]("assume-filename") .action((filename, c) => c.copy(assumeFilename = filename)) - .text( - "when using --stdin, use --assume-filename to hint to scalafmt that the input is an .sbt file." - ) - opt[Unit]("reportError") - .action((_, c) => c.copy(error = true)) + .text("when using --stdin, use --assume-filename to hint to scalafmt that the input is an .sbt file.") + opt[Unit]("reportError").action((_, c) => c.copy(error = true)) .text("exit with status 1 if any mis-formatted code found.") - opt[Unit]("test") - .action((_, c) => writeMode(c, WriteMode.Test).copy(error = true)) - .text( - "test for mis-formatted code only, exits with status 1 on failure." - ) - opt[Unit]("check") - .action((_, c) => - writeMode(c, WriteMode.Test).copy(error = true, check = true) - ) - .text( - "test for mis-formatted code only, exits with status 1 on first failure." - ) - opt[FileFetchMode]("mode") - .action((m, c) => c.copy(mode = Option(m))) - .text( - s"""Sets the files to be formatted fetching mode. - |Options: - |${FileFetchMode.help} - |""".stripMargin - ) + opt[Unit]("test").action((_, c) => + writeMode(c, WriteMode.Test).copy(error = true) + ).text("test for mis-formatted code only, exits with status 1 on failure.") + opt[Unit]("check").action((_, c) => + writeMode(c, WriteMode.Test).copy(error = true, check = true) + ).text("test for mis-formatted code only, exits with status 1 on first failure.") + opt[FileFetchMode]("mode").action((m, c) => c.copy(mode = Option(m))).text( + s"""Sets the files to be formatted fetching mode. + |Options: + |${FileFetchMode.help} + |""".stripMargin + ) opt[Unit]("diff") - .action((_, c) => c.copy(mode = Option(DiffFiles("master")))) - .text( + .action((_, c) => c.copy(mode = Option(DiffFiles("master")))).text( s"""Format files listed in `git diff` against master. |Deprecated: use --mode diff instead""".stripMargin ) opt[String]("diff-branch") - .action((branch, c) => c.copy(mode = Option(DiffFiles(branch)))) - .text( + .action((branch, c) => c.copy(mode = Option(DiffFiles(branch)))).text( s"""Format files listed in `git diff` against given git ref. |Deprecated: use --mode diff-ref= instead""".stripMargin ) - opt[Unit]("build-info") - .action((_, _) => { println(buildInfo); sys.exit }) + opt[Unit]("build-info").action((_, _) => { println(buildInfo); sys.exit }) .text("prints build information") - opt[Unit]("quiet") - .action((_, c) => c.copy(quiet = true)) + opt[Unit]("quiet").action((_, c) => c.copy(quiet = true)) .text("don't print out stuff to console.") - opt[Unit]("debug") - .action((_, c) => c.copy(debug = true)) + opt[Unit]("debug").action((_, c) => c.copy(debug = true)) .text("print out diagnostics to console.") - opt[Unit]("non-interactive") - .action((_, c) => c.copy(nonInteractive = true)) + opt[Unit]("non-interactive").action((_, c) => c.copy(nonInteractive = true)) .text("disable fancy progress bar, useful in ci or sbt plugin.") opt[Unit]("list") .action((_, c) => writeMode(c, WriteMode.List).copy(error = true)) .text("list files that are different from scalafmt formatting") - opt[(Int, Int)]("range") - .hidden() - .action { case ((from, to), c) => - val offset = if (from == to) 0 else -1 - c.copy(range = c.range + Range(from - 1, to + offset)) - } - .text("(experimental) only format line range from=to") + opt[(Int, Int)]("range").hidden().action { case ((from, to), c) => + val offset = if (from == to) 0 else -1 + c.copy(range = c.range + Range(from - 1, to + offset)) + }.text("(experimental) only format line range from=to") note( s"""|Examples: @@ -179,14 +143,11 @@ object CliArgParser { else success } } - def buildInfo = - s"""build commit: ${Versions.commit} - |build time: ${new Date(Versions.timestamp.toLong)}""".stripMargin - - private def writeMode(c: CliOptions, writeMode: WriteMode): CliOptions = - c.writeModeOpt.fold { - c.copy(writeModeOpt = Some(writeMode)) - } { x => + def buildInfo = s"""build commit: ${Versions.commit} + |build time: ${new Date(Versions.timestamp.toLong)}""".stripMargin + + private def writeMode(c: CliOptions, writeMode: WriteMode): CliOptions = c + .writeModeOpt.fold { c.copy(writeModeOpt = Some(writeMode)) } { x => if (x != writeMode) throw new Conflict(s"writeMode changing from $x to $writeMode") c diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/CliOptions.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/CliOptions.scala index d6f2020f7c..3ad7cc76f8 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/CliOptions.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/CliOptions.scala @@ -31,16 +31,15 @@ object CliOptions { if ( parsed.noStdErr || !(parsed.stdIn || parsed.writeMode == WriteMode.Stdout) - ) - parsed.common.out + ) parsed.common.out else parsed.common.err - parsed.copy( - common = parsed.common.copy( - out = - guardPrintStream(parsed.quiet && !parsed.stdIn)(parsed.common.out), + parsed.copy(common = + parsed.common.copy( + out = guardPrintStream(parsed.quiet && !parsed.stdIn)(parsed.common.out), info = guardPrintStream( - parsed.stdIn || parsed.writeMode == WriteMode.Stdout || parsed.quiet || parsed.writeMode == WriteMode.List + parsed.stdIn || parsed.writeMode == WriteMode.Stdout || + parsed.quiet || parsed.writeMode == WriteMode.List )(auxOut), debug = guardPrintStream(parsed.quiet)( if (parsed.debug) auxOut else parsed.common.debug @@ -50,14 +49,14 @@ object CliOptions { ) } - private def guardPrintStream( - p: => Boolean - )(candidate: PrintStream): PrintStream = - if (p) NoopOutputStream.printStream else candidate + private def guardPrintStream(p: => Boolean)( + candidate: PrintStream + ): PrintStream = if (p) NoopOutputStream.printStream else candidate } -object NoopOutputStream extends OutputStream { self => +object NoopOutputStream extends OutputStream { + self => override def write(b: Int): Unit = () override def write(b: Array[Byte]): Unit = () @@ -75,8 +74,8 @@ case class CommonOptions( debug: PrintStream = NoopOutputStream.printStream, info: PrintStream = NoopOutputStream.printStream ) { - private[cli] lazy val workingDirectory: AbsoluteFile = - cwd.getOrElse(AbsoluteFile.userDir) + private[cli] lazy val workingDirectory: AbsoluteFile = cwd + .getOrElse(AbsoluteFile.userDir) } case class CliOptions( @@ -128,13 +127,12 @@ case class CliOptions( .fold(throw new NoSuchFileException("Config file not found"))(_.get) } - private[cli] lazy val canonicalConfigFile: Option[Try[Path]] = - gitOps.getCanonicalConfigFile(cwd, config) + private[cli] lazy val canonicalConfigFile: Option[Try[Path]] = gitOps + .getCanonicalConfigFile(cwd, config) - private[cli] def getProposedConfigFile: Path = - canonicalConfigFile.flatMap(_.toOption).getOrElse { - gitOps.getProposedConfigFile(cwd, config).path - } + private[cli] def getProposedConfigFile: Path = canonicalConfigFile + .flatMap(_.toOption) + .getOrElse { gitOps.getProposedConfigFile(cwd, config).path } /** Parse the scalafmt configuration and try to encode it to `ScalafmtConfig`. * If `--config-str` is specified, this will parse the configuration string @@ -144,23 +142,18 @@ case class CliOptions( * If `--config-str` is not specified and configuration file is missing, this * will return the default configuration */ - def scalafmtConfig: Configured[ScalafmtConfig] = - hoconOpt.fold(Configured.ok(baseConfig))( - ScalafmtConfig.fromConf(_, baseConfig) - ) + def scalafmtConfig: Configured[ScalafmtConfig] = hoconOpt + .fold(Configured.ok(baseConfig))(ScalafmtConfig.fromConf(_, baseConfig)) - private[cli] lazy val hoconOpt: Option[ConfParsed] = - configStr.map(ConfParsed.fromString(_)).orElse { + private[cli] lazy val hoconOpt: Option[ConfParsed] = configStr + .map(ConfParsed.fromString(_)).orElse { canonicalConfigFile.map( - _.fold( - x => new ConfParsed(Configured.exception(x)), - ConfParsed.fromPath(_) - ) + _.fold(x => new ConfParsed(Configured.exception(x)), ConfParsed.fromPath(_)) ) } - lazy val fileFetchMode: FileFetchMode = - mode.getOrElse(if (isGit) GitFiles else RecursiveSearch) + lazy val fileFetchMode: FileFetchMode = mode + .getOrElse(if (isGit) GitFiles else RecursiveSearch) lazy val customFilesOpt = if (customFiles.isEmpty) None else Some(cwd.join(customFiles)) @@ -184,17 +177,15 @@ case class CliOptions( private def getHoconValueOpt[A]( f: ConfParsed => Option[Either[String, A]] - ): Option[A] = - hoconOpt.flatMap(f).map { - case Right(x) => x - case Left(x) => throw new ScalafmtConfigException(x) - } + ): Option[A] = hoconOpt.flatMap(f).map { + case Right(x) => x + case Left(x) => throw new ScalafmtConfigException(x) + } private def getHoconValue[A]( default: A, f: ConfParsed => Option[Either[String, A]] - ): A = - getHoconValueOpt[A](f).getOrElse(default) + ): A = getHoconValueOpt[A](f).getOrElse(default) private[cli] def isGit: Boolean = getHoconValue(baseConfig.project.git, _.isGit) @@ -208,12 +199,11 @@ case class CliOptions( private[cli] def onTestFailure: Option[String] = getHoconValueOpt(_.onTestFailure) - private[cli] def encoding: Codec = - getHoconValueOpt(_.encoding).getOrElse(baseConfig.encoding) + private[cli] def encoding: Codec = getHoconValueOpt(_.encoding) + .getOrElse(baseConfig.encoding) /** Returns None if .scalafmt.conf is not found or version setting is missing. */ - private[cli] def getVersionOpt: Option[String] = - getHoconValueOpt(_.version) + private[cli] def getVersionOpt: Option[String] = getHoconValueOpt(_.version) } diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ExitCode.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ExitCode.scala index b9e7f74f43..89207babd7 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ExitCode.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ExitCode.scala @@ -4,8 +4,7 @@ import scala.collection.mutable sealed abstract case class ExitCode(code: Int, name: String) { def isOk: Boolean = this == ExitCode.Ok - def is(c: ExitCode): Boolean = - (code & c.code) != 0 + def is(c: ExitCode): Boolean = (code & c.code) != 0 override def toString: String = s"$name=$code" } @@ -14,8 +13,7 @@ object ExitCode { // for example how the name is calculated for merged exit codes. private var counter = 0 private val allInternal = mutable.ListBuffer.empty[ExitCode] - private val cache = - new java.util.concurrent.ConcurrentHashMap[Int, ExitCode] + private val cache = new java.util.concurrent.ConcurrentHashMap[Int, ExitCode] private def generateExitStatus(implicit name: sourcecode.Name) = { val code = counter counter = if (counter == 0) 1 else counter << 1 @@ -37,9 +35,8 @@ object ExitCode { private def codeToName(code: Int): String = { if (code == 0) Ok.name else { - val names = all.collect { - case exit if (exit.code & code) != 0 => exit.name - } + val names = all + .collect { case exit if (exit.code & code) != 0 => exit.name } names.mkString("+") } } diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/FileFetchMode.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/FileFetchMode.scala index 1a73dd1766..51a720da19 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/FileFetchMode.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/FileFetchMode.scala @@ -20,10 +20,8 @@ object FileFetchMode { private val availableModesMap: Map[String, FileFetchMode] = availableModes.toMap - def help: String = - (("diff-ref=xxx", DiffFiles("xxx")) +: availableModes) - .map { case (k, v) => s"$k: ${v.desc}" } - .mkString(" ", "\n ", "") + def help: String = (("diff-ref=xxx", DiffFiles("xxx")) +: availableModes) + .map { case (k, v) => s"$k: ${v.desc}" }.mkString(" ", "\n ", "") /** The read instance is practically is not exhaustive due to the * RecursiveSearch and GitFiles are the fallback used in the absence of other @@ -32,9 +30,8 @@ object FileFetchMode { implicit val read: Read[FileFetchMode] = Read.reads { x => if (x.startsWith(diffRefPrefix)) DiffFiles(x.substring(diffRefPrefix.length).trim) - else - availableModesMap - .getOrElse(x, throw new IllegalArgumentException(s"unknown mode: $x")) + else availableModesMap + .getOrElse(x, throw new IllegalArgumentException(s"unknown mode: $x")) } } diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/InputMethod.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/InputMethod.scala index b4c9410122..ca0ea9cbea 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/InputMethod.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/InputMethod.scala @@ -23,19 +23,18 @@ sealed abstract class InputMethod { ): ExitCode = { val codeChanged = formatted != original if (options.writeMode == WriteMode.Stdout) print(formatted, options) - else if (codeChanged) - options.writeMode match { - case WriteMode.Test => - val pathStr = path.toString - val diff = InputMethod.unifiedDiff(pathStr, original, formatted) - val msg = - if (diff.nonEmpty) diff - else s"--- +$pathStr\n => modified line endings only" - throw MisformattedFile(path, msg) - case WriteMode.Override => overwrite(formatted, options) - case WriteMode.List => list(options) - case _ => - } + else if (codeChanged) options.writeMode match { + case WriteMode.Test => + val pathStr = path.toString + val diff = InputMethod.unifiedDiff(pathStr, original, formatted) + val msg = + if (diff.nonEmpty) diff + else s"--- +$pathStr\n => modified line endings only" + throw MisformattedFile(path, msg) + case WriteMode.Override => overwrite(formatted, options) + case WriteMode.List => list(options) + case _ => + } if (options.error && codeChanged) ExitCode.TestError else ExitCode.Ok } @@ -45,10 +44,8 @@ object InputMethod { object StdinCode { def apply(assumeFilename: String, inputStream: InputStream): StdinCode = { - StdinCode.apply( - assumeFilename, - Source.fromInputStream(inputStream).mkString - ) + StdinCode + .apply(assumeFilename, Source.fromInputStream(inputStream).mkString) } } case class StdinCode(filename: String, input: String) extends InputMethod { @@ -62,14 +59,13 @@ object InputMethod { override protected def overwrite(text: String, options: CliOptions): Unit = print(text, options) - override protected def list(options: CliOptions): Unit = - options.common.out.println(filename) + override protected def list(options: CliOptions): Unit = options.common.out + .println(filename) } case class FileContents(file: AbsoluteFile) extends InputMethod { override def path = file.path - def readInput(options: CliOptions): String = - file.readFile(options.encoding) + def readInput(options: CliOptions): String = file.readFile(options.encoding) override protected def print(text: String, options: CliOptions): Unit = options.common.out.print(text) @@ -83,13 +79,10 @@ object InputMethod { } } - def unifiedDiff( - filename: String, - original: String, - revised: String - ): String = { + def unifiedDiff(filename: String, original: String, revised: String): String = { import org.scalafmt.CompatCollections.JavaConverters._ - @inline def noEol(ch: Char) = ch != '\n' && ch != '\r' + @inline + def noEol(ch: Char) = ch != '\n' && ch != '\r' def jList(code: String, addEol: Boolean) = { val last = if (addEol) Iterator.single("") else Iterator.empty (code.linesIterator ++ last).toList.asJava @@ -101,16 +94,8 @@ object InputMethod { if (diff.getDeltas.isEmpty) "" else { difflib.DiffUtils - .generateUnifiedDiff( - s"a$filename", - s"b$filename", - a, - diff, - 1 - ) - .iterator() - .asScala - .mkString("\n") + .generateUnifiedDiff(s"a$filename", s"b$filename", a, diff, 1) + .iterator().asScala.mkString("\n") } } } diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtCliReporter.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtCliReporter.scala index 6d954e051d..bd72b62ab8 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtCliReporter.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtCliReporter.scala @@ -16,19 +16,13 @@ class ScalafmtCliReporter(options: CliOptions) extends ScalafmtReporter { def getExitCode: ExitCode = exitCode.get() - override def error( - file: Path, - message: String - ): Unit = { + override def error(file: Path, message: String): Unit = { if (!options.ignoreWarnings) { options.common.err.println(s"$message: $file") exitCode.getAndUpdate(ExitCode.merge(ExitCode.UnexpectedError, _)) } } - override def error( - file: Path, - e: Throwable - ): Unit = { + override def error(file: Path, e: Throwable): Unit = { e match { case _: PositionException if !options.ignoreWarnings => options.common.err.println(s"${e.toString}: $file") @@ -38,19 +32,15 @@ class ScalafmtCliReporter(options: CliOptions) extends ScalafmtReporter { exitCode.getAndUpdate(ExitCode.merge(ExitCode.TestError, _)) case ScalafmtException(_, cause) => error(file, cause) case _ if !options.ignoreWarnings => - new FailedToFormat(file.toString, e) - .printStackTrace(options.common.err) + new FailedToFormat(file.toString, e).printStackTrace(options.common.err) exitCode.getAndUpdate(ExitCode.merge(ExitCode.UnexpectedError, _)) } } - override def excluded(file: Path): Unit = - options.common.debug.println(s"file excluded: $file") + override def excluded(file: Path): Unit = options.common.debug + .println(s"file excluded: $file") - override def parsedConfig( - config: Path, - scalafmtVersion: String - ): Unit = + override def parsedConfig(config: Path, scalafmtVersion: String): Unit = options.common.debug.println(s"parsed config (v$scalafmtVersion): $config") override def downloadWriter(): PrintWriter = @@ -61,5 +51,4 @@ class ScalafmtCliReporter(options: CliOptions) extends ScalafmtReporter { } private class FailedToFormat(filename: String, cause: Throwable) - extends Exception(filename, cause) - with NoStackTrace + extends Exception(filename, cause) with NoStackTrace diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtCoreRunner.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtCoreRunner.scala index 834fa397fa..729acb9b0a 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtCoreRunner.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtCoreRunner.scala @@ -16,41 +16,36 @@ object ScalafmtCoreRunner extends ScalafmtRunner { override private[cli] def run( options: CliOptions, termDisplayMessage: String - ): ExitCode = - options.scalafmtConfig.fold { e => - options.common.err.println(s"${e.msg}") - ExitCode.UnexpectedError - } { scalafmtConf => - options.common.debug.println(s"parsed config (v${Versions.version})") - val filterMatcher = - try { - ProjectFiles.FileMatcher( - scalafmtConf.project, - options.customExcludes - ) - } catch { - case e: ScalafmtConfigException => - options.common.err.println(e.getMessage()) - return ExitCode.UnexpectedError // RETURNING EARLY! - } + ): ExitCode = options.scalafmtConfig.fold { e => + options.common.err.println(s"${e.msg}") + ExitCode.UnexpectedError + } { scalafmtConf => + options.common.debug.println(s"parsed config (v${Versions.version})") + val filterMatcher = + try { + ProjectFiles.FileMatcher(scalafmtConf.project, options.customExcludes) + } catch { + case e: ScalafmtConfigException => + options.common.err.println(e.getMessage()) + return ExitCode.UnexpectedError // RETURNING EARLY! + } - val inputMethods = getInputMethods(options, filterMatcher.matchesPath) + val inputMethods = getInputMethods(options, filterMatcher.matchesPath) - val termDisplay = - newTermDisplay(options, inputMethods, termDisplayMessage) - val exitCode = new AtomicReference(ExitCode.Ok) - Breaks.breakable { - inputMethods.par.foreach { inputMethod => - val code = handleFile(inputMethod, options, scalafmtConf) - exitCode.getAndUpdate(ExitCode.merge(code, _)) - if (options.check && !code.isOk) Breaks.break - termDisplay.taskProgress(termDisplayMessage) - } + val termDisplay = newTermDisplay(options, inputMethods, termDisplayMessage) + val exitCode = new AtomicReference(ExitCode.Ok) + Breaks.breakable { + inputMethods.par.foreach { inputMethod => + val code = handleFile(inputMethod, options, scalafmtConf) + exitCode.getAndUpdate(ExitCode.merge(code, _)) + if (options.check && !code.isOk) Breaks.break + termDisplay.taskProgress(termDisplayMessage) } - termDisplay.completedTask(termDisplayMessage, exitCode.get.isOk) - termDisplay.stop() - exitCode.get() } + termDisplay.completedTask(termDisplayMessage, exitCode.get.isOk) + termDisplay.stop() + exitCode.get() + } private[this] def handleFile( inputMethod: InputMethod, @@ -72,11 +67,11 @@ object ScalafmtCoreRunner extends ScalafmtRunner { ): ExitCode = { val input = inputMethod.readInput(options) val filename = inputMethod.path.toString - val formatResult = - Scalafmt.formatCode(input, scalafmtConfig, options.range, filename) + val formatResult = Scalafmt + .formatCode(input, scalafmtConfig, options.range, filename) formatResult.formatted match { - case Formatted.Success(formatted) => - inputMethod.write(formatted, input, options) + case Formatted.Success(formatted) => inputMethod + .write(formatted, input, options) case _: Formatted.Failure if scalafmtConfig.runner.ignoreWarnings => ExitCode.Ok // do nothing case Formatted.Failure(e @ (_: ParseException | _: TokenizeException)) => diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtDynamicRunner.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtDynamicRunner.scala index 7501109ef9..bd9056e89f 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtDynamicRunner.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtDynamicRunner.scala @@ -18,22 +18,18 @@ object ScalafmtDynamicRunner extends ScalafmtRunner { termDisplayMessage: String ): ExitCode = { val reporter = new ScalafmtCliReporter(options) - val scalafmtInstance = Scalafmt - .create(this.getClass.getClassLoader) - .withReporter(reporter) - .withRespectProjectFilters(false) + val scalafmtInstance = Scalafmt.create(this.getClass.getClassLoader) + .withReporter(reporter).withRespectProjectFilters(false) val session = - try { - scalafmtInstance.createSession(options.configPath) - } catch { - case _: ScalafmtDynamicError.ConfigError => - return reporter.getExitCode // XXX: returning + try { scalafmtInstance.createSession(options.configPath) } + catch { + case _: ScalafmtDynamicError.ConfigError => return reporter.getExitCode // XXX: returning } val sessionMatcher = session.matchesProjectFilters _ - val filterMatcher: Path => Boolean = - options.customFilesOpt.fold(sessionMatcher) { customFiles => + val filterMatcher: Path => Boolean = options.customFilesOpt + .fold(sessionMatcher) { customFiles => val customMatcher = FileOps.getFileMatcher(customFiles.map(_.path)) x => customMatcher(x) && sessionMatcher(x) } diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtRunner.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtRunner.scala index 4f6024aa14..5987ceb476 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtRunner.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/ScalafmtRunner.scala @@ -56,14 +56,12 @@ trait ScalafmtRunner { ): Seq[AbsoluteFile] = { val gitOps = options.gitOps val finder = options.fileFetchMode match { - case GitFiles => - new BatchPathFinder.GitFiles(gitOps)(canFormat) + case GitFiles => new BatchPathFinder.GitFiles(gitOps)(canFormat) case RecursiveSearch => new BatchPathFinder.DirFiles(options.cwd)(canFormat) case DiffFiles(branch) => new BatchPathFinder.GitBranchFiles(gitOps, branch)(canFormat) - case ChangedFiles => - new BatchPathFinder.GitDirtyFiles(gitOps)(canFormat) + case ChangedFiles => new BatchPathFinder.GitDirtyFiles(gitOps)(canFormat) } val files = finder.findMatchingFiles( options.respectProjectFilters, diff --git a/scalafmt-cli/src/main/scala/org/scalafmt/cli/TermDisplay.scala b/scalafmt-cli/src/main/scala/org/scalafmt/cli/TermDisplay.scala index 0bca1745b3..1341dead72 100644 --- a/scalafmt-cli/src/main/scala/org/scalafmt/cli/TermDisplay.scala +++ b/scalafmt-cli/src/main/scala/org/scalafmt/cli/TermDisplay.scala @@ -31,10 +31,8 @@ object Terminal { def buffer[T](f: => T): T = f } Try( - Process(Seq("bash", "-c", s"$pathedTput $s 2> /dev/tty")) - .!!(nullLog) - .trim - .toInt + Process(Seq("bash", "-c", s"$pathedTput $s 2> /dev/tty")).!!(nullLog) + .trim.toInt ).toOption } @@ -104,15 +102,15 @@ object TermDisplay { assert(decile >= 0) assert(decile <= 10) - fraction.fold(" " * 6)(p => f"${100.0 * p}%5.1f%%") + - " [" + ("#" * decile) + (" " * (10 - decile)) + "] " + - downloaded + " source files formatted" + fraction.fold(" " * 6)(p => f"${100.0 * p}%5.1f%%") + " [" + + ("#" * decile) + (" " * (10 - decile)) + "] " + downloaded + + " source files formatted" } } private val format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss") - private def formatTimestamp(ts: Long): String = - format.format(new Timestamp(ts)) + private def formatTimestamp(ts: Long): String = format + .format(new Timestamp(ts)) private case class CheckUpdateInfo( currentTimeOpt: Option[Long], @@ -121,30 +119,25 @@ object TermDisplay { ) extends Info { def fraction = None def display(): String = { - if (isDone) - (currentTimeOpt, remoteTimeOpt) match { - case (Some(current), Some(remote)) => - if (current < remote) - s"Updated since ${formatTimestamp(current)} (${formatTimestamp(remote)})" - else if (current == remote) - s"No new update since ${formatTimestamp(current)}" - else - s"Warning: local copy newer than remote one (${formatTimestamp(current)} > ${formatTimestamp(remote)})" - case (Some(_), None) => - // FIXME Likely a 404 Not found, that should be taken into account by the cache - "No modified time in response" - case (None, Some(remote)) => - s"Last update: ${formatTimestamp(remote)}" - case (None, None) => - "" // ??? - } - else - currentTimeOpt match { - case Some(current) => - s"Checking for updates since ${formatTimestamp(current)}" - case None => - "" // ??? - } + if (isDone) (currentTimeOpt, remoteTimeOpt) match { + case (Some(current), Some(remote)) => + if (current < remote) + s"Updated since ${formatTimestamp(current)} (${formatTimestamp(remote)})" + else if (current == remote) + s"No new update since ${formatTimestamp(current)}" + else + s"Warning: local copy newer than remote one (${formatTimestamp(current)} > ${formatTimestamp(remote)})" + case (Some(_), None) => + // FIXME Likely a 404 Not found, that should be taken into account by the cache + "No modified time in response" + case (None, Some(remote)) => s"Last update: ${formatTimestamp(remote)}" + case (None, None) => "" // ??? + } + else currentTimeOpt match { + case Some(current) => + s"Checking for updates since ${formatTimestamp(current)}" + case None => "" // ??? + } } } @@ -157,10 +150,8 @@ object TermDisplay { private val refreshInterval = 1000 / 60 private val fallbackRefreshInterval = 1000 - private class UpdateDisplayThread( - out: Writer, - var fallbackMode: Boolean - ) extends Thread("TermDisplay") { + private class UpdateDisplayThread(out: Writer, var fallbackMode: Boolean) + extends Thread("TermDisplay") { import Terminal.Ansi @@ -171,10 +162,7 @@ object TermDisplay { private val q = new LinkedBlockingDeque[Message] - def update(): Unit = { - if (q.size() == 0) - q.put(Message.Update) - } + def update(): Unit = { if (q.size() == 0) q.put(Message.Update) } def end(): Unit = { q.put(Message.Stop) @@ -185,11 +173,7 @@ object TermDisplay { private val doneQueue = new ArrayBuffer[(String, Info)] val infos = new ConcurrentHashMap[String, Info] - def newEntry( - url: String, - info: Info, - fallbackMessage: => String - ): Unit = { + def newEntry(url: String, info: Info, fallbackMessage: => String): Unit = { assert(!infos.containsKey(url)) val prev = infos.putIfAbsent(url, info) assert(prev == null) @@ -200,18 +184,12 @@ object TermDisplay { out.flush() } - downloads.synchronized { - downloads.append(url) - } + downloads.synchronized { downloads.append(url) } update() } - def removeEntry( - url: String, - success: Boolean, - fallbackMessage: => String - )( + def removeEntry(url: String, success: Boolean, fallbackMessage: => String)( update0: Info => Info ): Unit = { downloads.synchronized { @@ -219,8 +197,7 @@ object TermDisplay { val info = infos.remove(url) - if (success) - doneQueue += (url -> update0(info)) + if (success) doneQueue += (url -> update0(info)) } if (fallbackMode && success) { @@ -237,17 +214,14 @@ object TermDisplay { case downloadInfo: DownloadInfo => val pctOpt = downloadInfo.fraction.map(100.0 * _) - if (downloadInfo.length.isEmpty && downloadInfo.downloaded == 0L) - "" + if (downloadInfo.length.isEmpty && downloadInfo.downloaded == 0L) "" else { - val pctOptStr = - pctOpt.map(pct => f"$pct%.2f %%, ").mkString + val pctOptStr = pctOpt.map(pct => f"$pct%.2f %%, ").mkString val downloadInfoStr = downloadInfo.length.map(" / " + _).mkString s"($pctOptStr${downloadInfo.downloaded}$downloadInfoStr)" } - case _: CheckUpdateInfo => - "Checking for updates" + case _: CheckUpdateInfo => "Checking for updates" } val baseExtraWidth = width / 5 @@ -258,27 +232,21 @@ object TermDisplay { val overflow = total - width + 1 val extra0 = - if (extra.length > baseExtraWidth) - extra.take( - (baseExtraWidth max (extra.length - overflow)) - 1 - ) + "…" - else - extra + if (extra.length > baseExtraWidth) extra + .take((baseExtraWidth max (extra.length - overflow)) - 1) + "…" + else extra val total0 = url.length + 1 + extra0.length val overflow0 = total0 - width + 1 val url0 = - if (total0 >= width) - url.take( - ((width - baseExtraWidth - 1) max (url.length - overflow0)) - 1 - ) + "…" - else - url + if (total0 >= width) url.take( + ((width - baseExtraWidth - 1) max (url.length - overflow0)) - 1 + ) + "…" + else url (url0, extra0) - } else - (url, extra) + } else (url, extra) (url0, extra0) } @@ -287,18 +255,17 @@ object TermDisplay { out.clearLine(2) - if (s.length <= width) - out.write(s + "\n") - else - out.write(s.take(width - 1) + "…\n") + if (s.length <= width) out.write(s + "\n") + else out.write(s.take(width - 1) + "…\n") } - private def getDownloadInfos: Vector[(String, Info)] = - downloads.toVector - .map { url => url -> infos.get(url) } - .sortBy { case (_, info) => -info.fraction.sum } + private def getDownloadInfos: Vector[(String, Info)] = downloads.toVector + .map { url => url -> infos.get(url) }.sortBy { case (_, info) => + -info.fraction.sum + } - @tailrec private def updateDisplayLoop(lineCount: Int): Unit = { + @tailrec + private def updateDisplayLoop(lineCount: Int): Unit = { currentHeight = lineCount Option(q.poll(100L, TimeUnit.MILLISECONDS)) match { @@ -306,11 +273,9 @@ object TermDisplay { case Some(Message.Stop) => // poison pill case Some(Message.Update) => val (done0, downloads0) = downloads.synchronized { - val q = doneQueue.toVector - .filter { case (url, _) => - !url.endsWith(".sha1") && !url.endsWith(".md5") - } - .sortBy { case (url, _) => url } + val q = doneQueue.toVector.filter { case (url, _) => + !url.endsWith(".sha1") && !url.endsWith(".md5") + }.sortBy { case (url, _) => url } doneQueue.clear() @@ -335,12 +300,10 @@ object TermDisplay { out.down(1) } - for (_ <- displayedCount until lineCount) - out.up(2) + for (_ <- displayedCount until lineCount) out.up(2) } - for (_ <- downloads0.indices) - out.up(2) + for (_ <- downloads0.indices) out.up(2) out.left(10000) @@ -350,7 +313,8 @@ object TermDisplay { } } - @tailrec private def fallbackDisplayLoop(previous: Set[String]): Unit = + @tailrec + private def fallbackDisplayLoop(previous: Set[String]): Unit = Option(q.poll(100L, TimeUnit.MILLISECONDS)) match { case None => fallbackDisplayLoop(previous) case Some(Message.Stop) => // poison pill @@ -359,14 +323,10 @@ object TermDisplay { out.clearLine(2) out.down(1) } - for (_ <- 0 until currentHeight) { - out.up(2) - } + for (_ <- 0 until currentHeight) { out.up(2) } case Some(Message.Update) => - val downloads0 = downloads.synchronized { - getDownloadInfos - } + val downloads0 = downloads.synchronized { getDownloadInfos } var displayedSomething = false for ((url, info) <- downloads0 if previous(url)) { @@ -378,8 +338,7 @@ object TermDisplay { out.write(s"$url0 $extra0\n") } - if (displayedSomething) - out.write("\n") + if (displayedSomething) out.write("\n") out.flush() Thread.sleep(fallbackRefreshInterval) @@ -394,14 +353,10 @@ object TermDisplay { case Some(cols) => width = cols out.clearLine(2) - case None => - fallbackMode = true + case None => fallbackMode = true } - if (fallbackMode) - fallbackDisplayLoop(Set.empty) - else - updateDisplayLoop(0) + if (fallbackMode) fallbackDisplayLoop(Set.empty) else updateDisplayLoop(0) } } @@ -426,26 +381,15 @@ class TermDisplay( private val counter = new atomic.AtomicInteger() private val updateThread = new UpdateDisplayThread(out, fallbackMode) - def init(): Unit = { - updateThread.start() - } + def init(): Unit = { updateThread.start() } - def stop(): Unit = { - updateThread.end() - } + def stop(): Unit = { updateThread.end() } - override def startTask(msg: String, file: File): Unit = - updateThread.newEntry( - msg, - DownloadInfo( - 0L, - 0L, - None, - System.currentTimeMillis(), - updateCheck = false - ), - s"$msg\n" - ) + override def startTask(msg: String, file: File): Unit = updateThread.newEntry( + msg, + DownloadInfo(0L, 0L, None, System.currentTimeMillis(), updateCheck = false), + s"$msg\n" + ) def taskLength( url: String, @@ -455,13 +399,11 @@ class TermDisplay( val info = updateThread.infos.get(url) assert(info != null) val newInfo = info match { - case info0: DownloadInfo => - info0.copy( + case info0: DownloadInfo => info0.copy( length = Some(totalLength), previouslyDownloaded = alreadyDownloaded ) - case _ => - throw new Exception(s"Incoherent display state for $url") + case _ => throw new Exception(s"Incoherent display state for $url") } updateThread.infos.put(url, newInfo) @@ -472,10 +414,8 @@ class TermDisplay( val info = updateThread.infos.get(url) if (info != null) { // We might not want the progress bar. val newInfo = info match { - case info0: DownloadInfo => - info0.copy(downloaded = downloaded) - case _ => - throw new Exception(s"Incoherent display state for $url") + case info0: DownloadInfo => info0.copy(downloaded = downloaded) + case _ => throw new Exception(s"Incoherent display state for $url") } updateThread.infos.put(url, newInfo) @@ -483,17 +423,16 @@ class TermDisplay( } } - override def completedTask(url: String, success: Boolean): Unit = - updateThread.removeEntry(url, success, s"$url\n")(x => x) + override def completedTask(url: String, success: Boolean): Unit = updateThread + .removeEntry(url, success, s"$url\n")(x => x) override def checkingUpdates( url: String, currentTimeOpt: Option[Long] - ): Unit = - updateThread.newEntry( - url, - CheckUpdateInfo(currentTimeOpt, None, isDone = false), - s"$url\n" - ) + ): Unit = updateThread.newEntry( + url, + CheckUpdateInfo(currentTimeOpt, None, isDone = false), + s"$url\n" + ) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/Error.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/Error.scala index eabc6db63f..7ae2750c99 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/Error.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/Error.scala @@ -30,15 +30,11 @@ object Error { case class PreciseIncomplete(pos: Position, formattedCode: String) extends Error( - pos.formatMessage( - "error", - "Unable to format file due to bug in scalafmt" - ) + pos + .formatMessage("error", "Unable to format file due to bug in scalafmt") ) case class CantFindDefnToken(what: String, tree: Tree) - extends Error( - s"Expected keyword of type $what in tree $tree" - ) + extends Error(s"Expected keyword of type $what in tree $tree") case class CaseMissingArrow(tree: Case) extends Error(s"Missing => in case: \n$tree") diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/Formatted.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/Formatted.scala index 7c821d8805..536c58cd2b 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/Formatted.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/Formatted.scala @@ -4,17 +4,15 @@ import org.scalafmt.config.ScalafmtConfig sealed abstract class Formatted { - def toEither: Either[Throwable, String] = - this match { - case Formatted.Success(s) => Right(s) - case Formatted.Failure(e) => Left(e) - } + def toEither: Either[Throwable, String] = this match { + case Formatted.Success(s) => Right(s) + case Formatted.Failure(e) => Left(e) + } - def get: String = - this match { - case Formatted.Success(code) => code - case Formatted.Failure(e) => throw e - } + def get: String = this match { + case Formatted.Success(code) => code + case Formatted.Failure(e) => throw e + } } object Formatted { diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/Scalafmt.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/Scalafmt.scala index 47941a9dac..063dd65ac4 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/Scalafmt.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/Scalafmt.scala @@ -55,9 +55,7 @@ object Scalafmt { style: ScalafmtConfig, range: Set[Range], filename: String - ): Formatted = { - formatCode(code, style, range, filename).formatted - } + ): Formatted = { formatCode(code, style, range, filename).formatted } private[scalafmt] def formatCode( code: String, @@ -122,10 +120,9 @@ object Scalafmt { file: String, range: Set[Range] ): Try[String] = - if (FileOps.isMarkdown(file)) - MarkdownParser.transformMdoc(code)(doFormatOne(_, style, file, range)) - else - doFormatOne(code, style, file, range) + if (FileOps.isMarkdown(file)) MarkdownParser + .transformMdoc(code)(doFormatOne(_, style, file, range)) + else doFormatOne(code, style, file, range) private[scalafmt] def toInput(code: String, file: String): Input = { val fileInput = Input.VirtualFile(file, code) @@ -172,9 +169,7 @@ object Scalafmt { code: String, style: ScalafmtConfig = ScalafmtConfig.default, range: Set[Range] = Set.empty[Range] - ): Formatted = { - formatCode(code, style, range).formatted - } + ): Formatted = { formatCode(code, style, range).formatted } // used by ScalafmtReflect.parseConfig def parseHoconConfigFile(configPath: Path): Configured[ScalafmtConfig] = @@ -182,9 +177,6 @@ object Scalafmt { // used by ScalafmtReflect.parseConfig def parseHoconConfig(configString: String): Configured[ScalafmtConfig] = - ScalafmtConfig.fromHoconString( - configString, - ScalafmtConfig.uncheckedDefault - ) + ScalafmtConfig.fromHoconString(configString, ScalafmtConfig.uncheckedDefault) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Align.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Align.scala index 8d78d3ddb7..7b498a2cb3 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Align.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Align.scala @@ -98,10 +98,10 @@ case class Align( def getOpenParenTupleSite = openParenTupleSite.getOrElse(openParenCallSite) def getOpenDelimSite(bracket: Boolean, defnSite: Boolean): Boolean = - if (defnSite) - (if (bracket) openBracketDefnSite else None).getOrElse(openParenDefnSite) - else - (if (bracket) openBracketCallSite else None).getOrElse(openParenCallSite) + if (defnSite) (if (bracket) openBracketDefnSite else None) + .getOrElse(openParenDefnSite) + else (if (bracket) openBracketCallSite else None) + .getOrElse(openParenCallSite) } @@ -123,8 +123,8 @@ object Align { val more: Align = some.copy(tokens = AlignToken.default) implicit lazy val surface: Surface[Align] = generic.deriveSurface[Align] implicit lazy val encoder: ConfEncoder[Align] = generic.deriveEncoder - implicit lazy val decoder: ConfDecoderEx[Align] = - Presets.mapDecoder(generic.deriveDecoderEx(default).noTypos, "align") + implicit lazy val decoder: ConfDecoderEx[Align] = Presets + .mapDecoder(generic.deriveDecoderEx(default).noTypos, "align") // only for the truest vertical aligners, this setting is open for changes, // please open PR adding more stuff to it if you like. @@ -132,10 +132,7 @@ object Align { allowOverflow = true, multiline = true, arrowEnumeratorGenerator = true, - tokenCategory = Map( - "Equals" -> "Assign", - "LeftArrow" -> "Assign" - ) + tokenCategory = Map("Equals" -> "Assign", "LeftArrow" -> "Assign") ) val allValues = List(default, none, some, most) @@ -155,8 +152,8 @@ object Align { """'align.tokens.add' is deprecated; use align.tokens."+" instead.""" ) base.read(None, c).map(x => state.fold(x)(_ ++ x)) - case (state, c) => - preset.lift(c).fold(base.read(state, c))(x => Configured.Ok(x.tokens)) + case (state, c) => preset.lift(c) + .fold(base.read(state, c))(x => Configured.Ok(x.tokens)) } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/AlignToken.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/AlignToken.scala index 88625d3b17..cd7f9dc2cd 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/AlignToken.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/AlignToken.scala @@ -34,8 +34,7 @@ case class AlignToken( object AlignToken { - private def pattern(value: String): jurPattern = - value.r.pattern + private def pattern(value: String): jurPattern = value.r.pattern /** @param regex * regexp for class name of scala.meta.Tree "owner". @@ -52,8 +51,8 @@ object AlignToken { implicit val ownerSurface: Surface[Owner] = generic.deriveSurface[Owner] implicit val ownerCodec: ConfCodecEx[Owner] = generic.deriveCodecEx(Owner()) - implicit lazy val surface: Surface[AlignToken] = - generic.deriveSurface[AlignToken] + implicit lazy val surface: Surface[AlignToken] = generic + .deriveSurface[AlignToken] implicit lazy val encoder: ConfEncoder[AlignToken] = generic.deriveEncoder val applyInfix = "Term.ApplyInfix" val caseArrow = AlignToken("=>", "Case") @@ -88,20 +87,21 @@ object AlignToken { ) class Matcher(val owner: Option[jurPattern], val parents: Seq[jurPattern]) { - def matches(tree: meta.Tree): Boolean = - owner.forall(check(tree)) && - (parents.isEmpty || tree.parent.exists { p => - parents.forall(check(p)) || (p match { - case ParamClauseParent(pp) => parents.forall(check(pp)) - case _: meta.Member.SyntaxValuesClause => - p.parent.exists { pp => parents.forall(check(pp)) } - case _ => false - }) + def matches(tree: meta.Tree): Boolean = owner.forall(check(tree)) && + (parents.isEmpty || tree.parent.exists { p => + parents.forall(check(p)) || + (p match { + case ParamClauseParent(pp) => parents.forall(check(pp)) + case _: meta.Member.SyntaxValuesClause => p.parent.exists { pp => + parents.forall(check(pp)) + } + case _ => false }) + }) } @inline - private def check(tree: meta.Tree)(pattern: jurPattern): Boolean = - pattern.matcher(tree.productPrefix).find() + private def check(tree: meta.Tree)(pattern: jurPattern): Boolean = pattern + .matcher(tree.productPrefix).find() } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/AvoidInfixSettings.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/AvoidInfixSettings.scala index 12b0c78850..f50e1b846b 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/AvoidInfixSettings.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/AvoidInfixSettings.scala @@ -14,7 +14,8 @@ case class AvoidInfixSettings( excludePlaceholderArg: Option[Boolean] = None ) { // if the user completely redefined (rather than appended), we don't touch - @inline private def isMainExclude: Boolean = + @inline + private def isMainExclude: Boolean = excludeStartsWith(AvoidInfixSettings.mainExclude) private[config] def forSbtOpt: Option[AvoidInfixSettings] = @@ -28,10 +29,11 @@ case class AvoidInfixSettings( if (excludeScalaTest.getOrElse(isMainExclude)) Some(withTestExclude) else None - private def withTestExclude: AvoidInfixSettings = - getExcludeWithExtra(AvoidInfixSettings.testExclude).fold( - copy(excludeScalaTest = Some(false)) - )(x => copy(excludeFilters = x, excludeScalaTest = Some(false))) + private def withTestExclude: AvoidInfixSettings = getExcludeWithExtra( + AvoidInfixSettings.testExclude + ).fold(copy(excludeScalaTest = Some(false)))(x => + copy(excludeFilters = x, excludeScalaTest = Some(false)) + ) @inline private def excludeStartsWith(obj: Seq[AvoidInfixSettings.Filter]): Boolean = @@ -49,47 +51,39 @@ case class AvoidInfixSettings( private[config] def withExtraExclude( obj: Seq[AvoidInfixSettings.Filter] - ): Option[AvoidInfixSettings] = - getExcludeWithExtra(obj).map(x => copy(excludeFilters = x)) + ): Option[AvoidInfixSettings] = getExcludeWithExtra(obj) + .map(x => copy(excludeFilters = x)) - def matches(lhs: String, op: String): Boolean = - includeFilters.forall(_.matches(lhs, op)(_.find())) && - !excludeFilters.exists(_.matches(lhs, op)(_.matches())) + def matches(lhs: String, op: String): Boolean = includeFilters + .forall(_.matches(lhs, op)(_.find())) && + !excludeFilters.exists(_.matches(lhs, op)(_.matches())) } object AvoidInfixSettings { - private[config] case class Filter( - lhs: Option[Pattern], - op: Pattern - ) { + private[config] case class Filter(lhs: Option[Pattern], op: Pattern) { private def pattern: String = { val opPat = op.pattern() lhs.fold(opPat) { lhs => s"${lhs.pattern()}\\.$opPat" } } - def matches(lhs: String, op: String)( - f: Matcher => Boolean - ): Boolean = + def matches(lhs: String, op: String)(f: Matcher => Boolean): Boolean = f(this.op.matcher(op)) && this.lhs.forall(r => f(r.matcher(lhs))) override def equals(obj: Any): Boolean = obj match { - case x: Filter => - x.op.pattern() == op.pattern() && x.lhs.fold(lhs.isEmpty) { y => - lhs.exists(_.pattern() == y.pattern()) - } + case x: Filter => x.op.pattern() == op.pattern() && + x.lhs.fold(lhs.isEmpty) { y => lhs.exists(_.pattern() == y.pattern()) } case _ => false } - override def hashCode(): Int = - lhs.fold(0)(_.pattern().##) ^ op.pattern().## + override def hashCode(): Int = lhs.fold(0)(_.pattern().##) ^ op.pattern().## } private[config] object Filter { implicit lazy val surface: Surface[Filter] = generic.deriveSurface - implicit lazy val encoder: ConfEncoder[Filter] = - ConfEncoder.instance(x => Conf.Str(x.pattern)) - implicit lazy val decoder: ConfDecoderEx[Filter] = - ConfDecoderEx.fromPartial("String") { case (_, Conf.Str(x)) => parse(x) } + implicit lazy val encoder: ConfEncoder[Filter] = ConfEncoder + .instance(x => Conf.Str(x.pattern)) + implicit lazy val decoder: ConfDecoderEx[Filter] = ConfDecoderEx + .fromPartial("String") { case (_, Conf.Str(x)) => parse(x) } private def parse(str: String): Configured[Filter] = { val idx = str.lastIndexOf("\\.") @@ -104,55 +98,42 @@ object AvoidInfixSettings { def apply(value: String): Filter = parse(value).get } - implicit lazy val surface: Surface[AvoidInfixSettings] = - generic.deriveSurface - implicit lazy val codec: ConfCodecEx[AvoidInfixSettings] = - generic.deriveCodecEx(default).noTypos - - private[config] def mainInclude = - Seq( - "[\\w\\d_]+" - ).map(Filter.apply) - - private[config] val mainExclude = - Seq( - "until", - "to", - "by", - "eq", - "ne" - ).map(Filter.apply) - - private val testExclude = - Seq( - "should.*", - "contain.*", - "must.*", - "in", - "ignore", - "be", - "behavior\\.of", - "taggedAs", - "thrownBy", - "synchronized", - "have", - "when", - "size", - "only", - "noneOf", - "oneElementOf", - "noElementsOf", - "atLeastOneElementOf", - "atMostOneElementOf", - "allElementsOf", - "inOrderElementsOf", - "theSameElementsAs" - ).map(Filter.apply) - - private[config] val sbtExclude = Seq( - "cross" + implicit lazy val surface: Surface[AvoidInfixSettings] = generic.deriveSurface + implicit lazy val codec: ConfCodecEx[AvoidInfixSettings] = generic + .deriveCodecEx(default).noTypos + + private[config] def mainInclude = Seq("[\\w\\d_]+").map(Filter.apply) + + private[config] val mainExclude = Seq("until", "to", "by", "eq", "ne") + .map(Filter.apply) + + private val testExclude = Seq( + "should.*", + "contain.*", + "must.*", + "in", + "ignore", + "be", + "behavior\\.of", + "taggedAs", + "thrownBy", + "synchronized", + "have", + "when", + "size", + "only", + "noneOf", + "oneElementOf", + "noElementsOf", + "atLeastOneElementOf", + "atMostOneElementOf", + "allElementsOf", + "inOrderElementsOf", + "theSameElementsAs" ).map(Filter.apply) + private[config] val sbtExclude = Seq("cross").map(Filter.apply) + private[config] val default = AvoidInfixSettings( includeFilters = mainInclude, excludeFilters = mainExclude diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/BinPack.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/BinPack.scala index 55708a629e..118ea4f884 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/BinPack.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/BinPack.scala @@ -52,12 +52,14 @@ case class BinPack( style.newlines.source.eq(Newlines.keep) && parentConstructors.eq(BinPack.ParentCtors.source) - @inline def callSite(open: Token): BinPack.Unsafe = + @inline + def callSite(open: Token): BinPack.Unsafe = callSite(open.is[Token.LeftBracket]) def callSite(isBracket: Boolean): BinPack.Unsafe = (if (isBracket) bracketCallSite else None).getOrElse(unsafeCallSite) - @inline def defnSite(open: Token): BinPack.Unsafe = + @inline + def defnSite(open: Token): BinPack.Unsafe = defnSite(open.is[Token.LeftBracket]) def defnSite(isBracket: Boolean): BinPack.Unsafe = (if (isBracket) bracketDefnSite else None).getOrElse(unsafeDefnSite) @@ -65,8 +67,8 @@ case class BinPack( } object BinPack { - implicit lazy val surface: generic.Surface[BinPack] = - generic.deriveSurface[BinPack] + implicit lazy val surface: generic.Surface[BinPack] = generic + .deriveSurface[BinPack] implicit lazy val encoder: ConfEncoder[BinPack] = generic.deriveEncoder val enabled = BinPack( @@ -75,8 +77,8 @@ object BinPack { parentConstructors = ParentCtors.Always ) - implicit val decoder: ConfDecoderEx[BinPack] = - Presets.mapDecoder(generic.deriveDecoderEx(BinPack()).noTypos, "binPack") { + implicit val decoder: ConfDecoderEx[BinPack] = Presets + .mapDecoder(generic.deriveDecoderEx(BinPack()).noTypos, "binPack") { case Conf.Bool(true) => enabled case Conf.Bool(false) => BinPack() } @@ -90,8 +92,8 @@ object BinPack { case object Oneline extends ParentCtors case object OnelineIfPrimaryOneline extends ParentCtors - implicit val oneOfReader: ConfCodecEx[ParentCtors] = - ReaderUtil.oneOfCustom[ParentCtors]( + implicit val oneOfReader: ConfCodecEx[ParentCtors] = ReaderUtil + .oneOfCustom[ParentCtors]( source, keep, Always, @@ -113,8 +115,8 @@ object BinPack { case object Always extends Unsafe case object Oneline extends Unsafe - implicit val oneOfReader: ConfCodecEx[Unsafe] = - ReaderUtil.oneOfCustom[Unsafe](Never, Always, Oneline) { + implicit val oneOfReader: ConfCodecEx[Unsafe] = ReaderUtil + .oneOfCustom[Unsafe](Never, Always, Oneline) { case Conf.Bool(true) => Configured.ok(Always) case Conf.Bool(false) => Configured.ok(Never) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Case.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Case.scala index 9c5cca3621..cef2480390 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Case.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Case.scala @@ -4,17 +4,16 @@ import metaconfig.ConfCodecEx sealed abstract class Case { import Case._ - def process(str: String): String = - this match { - case Unchanged => str - case Lower => str.toLowerCase() - case Upper => str.toUpperCase() - } + def process(str: String): String = this match { + case Unchanged => str + case Lower => str.toLowerCase() + case Upper => str.toUpperCase() + } } object Case { - implicit val codec: ConfCodecEx[Case] = - ReaderUtil.oneOf[Case](Upper, Lower, Unchanged) + implicit val codec: ConfCodecEx[Case] = ReaderUtil + .oneOf[Case](Upper, Lower, Unchanged) case object Upper extends Case case object Lower extends Case case object Unchanged extends Case diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Comments.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Comments.scala index dfb71b92c0..c7d0670245 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Comments.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Comments.scala @@ -19,23 +19,24 @@ case class Comments( wrapSingleLineMlcAsSlc: Boolean = false, wrapStandaloneSlcAsSlc: Boolean = false ) { - @inline def willWrap: Boolean = wrap ne Comments.Wrap.no + @inline + def willWrap: Boolean = wrap ne Comments.Wrap.no } object Comments { - implicit val surface: generic.Surface[Comments] = - generic.deriveSurface[Comments] - implicit val codec: ConfCodecEx[Comments] = - generic.deriveCodecEx(Comments()).noTypos + implicit val surface: generic.Surface[Comments] = generic + .deriveSurface[Comments] + implicit val codec: ConfCodecEx[Comments] = generic.deriveCodecEx(Comments()) + .noTypos sealed abstract class Wrap object Wrap { case object no extends Wrap case object standalone extends Wrap case object trailing extends Wrap - implicit val reader: ConfCodecEx[Wrap] = - ReaderUtil.oneOf[Wrap](no, standalone, trailing) + implicit val reader: ConfCodecEx[Wrap] = ReaderUtil + .oneOf[Wrap](no, standalone, trailing) } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/DanglingParentheses.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/DanglingParentheses.scala index 9f8554ce16..e409bdf05f 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/DanglingParentheses.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/DanglingParentheses.scala @@ -9,16 +9,16 @@ case class DanglingParentheses( private[config] val tupleSite: Option[Boolean] = None, private val exclude: Option[List[DanglingParentheses.Exclude]] = None ) { - @inline def tupleOrCallSite(isTuple: Boolean) = + @inline + def tupleOrCallSite(isTuple: Boolean) = if (isTuple) tupleSite.getOrElse(callSite) else callSite def getExclude( isVerticalMultiline: Boolean - ): Seq[DanglingParentheses.Exclude] = - exclude.getOrElse { - if (!isVerticalMultiline) Nil - else DanglingParentheses.Exclude.defaultVerticalMultiline - } + ): Seq[DanglingParentheses.Exclude] = exclude.getOrElse { + if (!isVerticalMultiline) Nil + else DanglingParentheses.Exclude.defaultVerticalMultiline + } } @@ -32,16 +32,13 @@ object DanglingParentheses { implicit lazy val surface: generic.Surface[DanglingParentheses] = generic.deriveSurface - implicit val encoder: ConfEncoder[DanglingParentheses] = - generic.deriveEncoder + implicit val encoder: ConfEncoder[DanglingParentheses] = generic.deriveEncoder - implicit val decoder: ConfDecoderEx[DanglingParentheses] = Presets.mapDecoder( - generic.deriveDecoderEx(default).noTypos, - "danglingParentheses" - ) { - case Conf.Bool(true) => shortcutTrue - case Conf.Bool(false) => shortcutFalse - } + implicit val decoder: ConfDecoderEx[DanglingParentheses] = Presets + .mapDecoder(generic.deriveDecoderEx(default).noTypos, "danglingParentheses") { + case Conf.Bool(true) => shortcutTrue + case Conf.Bool(false) => shortcutFalse + } sealed abstract class Exclude diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Docstrings.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Docstrings.scala index 1a2b3e3cdc..0982fbdc3e 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Docstrings.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Docstrings.scala @@ -52,10 +52,10 @@ case class Docstrings( object Docstrings { - implicit val surface: generic.Surface[Docstrings] = - generic.deriveSurface[Docstrings] - implicit val codec: ConfCodecEx[Docstrings] = - generic.deriveCodecEx(Docstrings()).noTypos + implicit val surface: generic.Surface[Docstrings] = generic + .deriveSurface[Docstrings] + implicit val codec: ConfCodecEx[Docstrings] = generic + .deriveCodecEx(Docstrings()).noTypos sealed abstract class Style { def skipFirstLine: Boolean @@ -75,14 +75,9 @@ object Docstrings { override def skipFirstLine: Boolean = false } - implicit val reader: ConfCodecEx[Style] = - ReaderUtil.oneOfCustom[Style]( - Preserve, - Asterisk, - SpaceAsterisk, - AsteriskSpace - ) { case Conf.Str("keep") => - Configured.Ok(Preserve) + implicit val reader: ConfCodecEx[Style] = ReaderUtil + .oneOfCustom[Style](Preserve, Asterisk, SpaceAsterisk, AsteriskSpace) { + case Conf.Str("keep") => Configured.Ok(Preserve) } sealed abstract class Oneline @@ -90,16 +85,16 @@ object Docstrings { case object keep extends Oneline case object fold extends Oneline case object unfold extends Oneline - implicit val reader: ConfCodecEx[Oneline] = - ReaderUtil.oneOf[Oneline](keep, fold, unfold) + implicit val reader: ConfCodecEx[Oneline] = ReaderUtil + .oneOf[Oneline](keep, fold, unfold) } sealed abstract class Wrap object Wrap { case object no extends Wrap case object yes extends Wrap - implicit val codec: ConfCodecEx[Wrap] = - ReaderUtil.oneOfCustom[Wrap](no, yes) { + implicit val codec: ConfCodecEx[Wrap] = ReaderUtil + .oneOfCustom[Wrap](no, yes) { case Conf.Bool(true) => Configured.Ok(yes) case Conf.Bool(false) => Configured.Ok(no) } @@ -110,8 +105,8 @@ object Docstrings { case object yes extends BlankFirstLine case object no extends BlankFirstLine case object keep extends BlankFirstLine - implicit val codec: ConfCodecEx[BlankFirstLine] = - ReaderUtil.oneOfCustom[BlankFirstLine](yes, no, keep) { + implicit val codec: ConfCodecEx[BlankFirstLine] = ReaderUtil + .oneOfCustom[BlankFirstLine](yes, no, keep) { case Conf.Bool(true) => Configured.Ok(yes) case Conf.Bool(false) => Configured.Ok(no) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/FilterMatcher.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/FilterMatcher.scala index 1c01238a8c..215762834a 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/FilterMatcher.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/FilterMatcher.scala @@ -6,9 +6,8 @@ import org.scalafmt.sysops.AbsoluteFile case class FilterMatcher(include: Regex, exclude: Regex) { def matchesFile(file: AbsoluteFile): Boolean = matches(file.toString()) - def matches(input: String): Boolean = - include.pattern.matcher(input).find() && - !exclude.pattern.matcher(input).find() + def matches(input: String): Boolean = include.pattern.matcher(input).find() && + !exclude.pattern.matcher(input).find() } object FilterMatcher { diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ImportSelectors.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ImportSelectors.scala index c4d065f0f3..5bd81b5e78 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ImportSelectors.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ImportSelectors.scala @@ -42,8 +42,8 @@ sealed abstract class ImportSelectors object ImportSelectors { - implicit val codec: ConfCodecEx[ImportSelectors] = - ReaderUtil.oneOfCustom[ImportSelectors](noBinPack, binPack, singleLine) { + implicit val codec: ConfCodecEx[ImportSelectors] = ReaderUtil + .oneOfCustom[ImportSelectors](noBinPack, binPack, singleLine) { case Conf.Bool(true) => Configured.ok(ImportSelectors.binPack) case Conf.Bool(false) => Configured.ok(ImportSelectors.noBinPack) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/IndentOperator.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/IndentOperator.scala index 35f2037c2c..7776ff0e49 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/IndentOperator.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/IndentOperator.scala @@ -63,14 +63,13 @@ case class IndentOperator( private val includeRegexp = includeRegex.r.pattern private val excludeRegexp = excludeRegex.r.pattern - def noindent(op: String): Boolean = - excludeRegexp.matcher(op).find() || !includeRegexp.matcher(op).find() + def noindent(op: String): Boolean = excludeRegexp.matcher(op).find() || + !includeRegexp.matcher(op).find() - lazy val getExemptScope: IndentOperator.Exempt = - exemptScope.getOrElse( - if (topLevelOnly) IndentOperator.Exempt.oldTopLevel - else IndentOperator.Exempt.all - ) + lazy val getExemptScope: IndentOperator.Exempt = exemptScope.getOrElse( + if (topLevelOnly) IndentOperator.Exempt.oldTopLevel + else IndentOperator.Exempt.all + ) } object IndentOperator { @@ -79,16 +78,13 @@ object IndentOperator { implicit lazy val surface: generic.Surface[IndentOperator] = generic.deriveSurface - implicit lazy val encoder: ConfEncoder[IndentOperator] = - generic.deriveEncoder + implicit lazy val encoder: ConfEncoder[IndentOperator] = generic.deriveEncoder - implicit val decoder: ConfDecoderEx[IndentOperator] = Presets.mapDecoder( - generic.deriveDecoderEx(default).noTypos, - "indentOperator" - ) { - case Conf.Str("spray" | "akka" | "akka-http") => IndentOperator.akka - case Conf.Str("default") => IndentOperator.default - } + implicit val decoder: ConfDecoderEx[IndentOperator] = Presets + .mapDecoder(generic.deriveDecoderEx(default).noTypos, "indentOperator") { + case Conf.Str("spray" | "akka" | "akka-http") => IndentOperator.akka + case Conf.Str("default") => IndentOperator.default + } sealed abstract class Exempt object Exempt { diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Indents.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Indents.scala index 9ea58beb71..ebc567f25a 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Indents.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Indents.scala @@ -41,20 +41,18 @@ case class Indents( ) { lazy val getSignificant = significant.getOrElse(main) - def getDefnSite(tree: meta.Tree): Int = - (tree match { - case _: meta.Member.ParamClause | _: meta.Member.ParamClauseGroup => - tree.parent.map(getDefnSite) - case _: meta.Ctor => ctorSite - case _ => None - }).getOrElse(defnSite) + def getDefnSite(tree: meta.Tree): Int = (tree match { + case _: meta.Member.ParamClause | _: meta.Member.ParamClauseGroup => tree + .parent.map(getDefnSite) + case _: meta.Ctor => ctorSite + case _ => None + }).getOrElse(defnSite) } object Indents { - implicit lazy val surface: generic.Surface[Indents] = - generic.deriveSurface - implicit lazy val codec: ConfCodecEx[Indents] = - generic.deriveCodecEx(Indents()).noTypos + implicit lazy val surface: generic.Surface[Indents] = generic.deriveSurface + implicit lazy val codec: ConfCodecEx[Indents] = generic + .deriveCodecEx(Indents()).noTypos sealed abstract class RelativeToLhs object RelativeToLhs { diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/LineEndings.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/LineEndings.scala index 56944d5cda..a3cac4305d 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/LineEndings.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/LineEndings.scala @@ -7,8 +7,8 @@ import metaconfig.Configured sealed abstract class LineEndings object LineEndings { - implicit val reader: ConfCodecEx[LineEndings] = - ReaderUtil.oneOfCustom[LineEndings](unix, windows, preserve) { + implicit val reader: ConfCodecEx[LineEndings] = ReaderUtil + .oneOfCustom[LineEndings](unix, windows, preserve) { case Conf.Str("keep") => Configured.Ok(preserve) } case object unix extends LineEndings diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Literals.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Literals.scala index 1a6e2536d9..24bbaf1b66 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Literals.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Literals.scala @@ -13,6 +13,6 @@ case class Literals( object Literals { implicit val surface: generic.Surface[Literals] = generic.deriveSurface - implicit val codec: ConfCodecEx[Literals] = - generic.deriveCodecEx(Literals()).noTypos + implicit val codec: ConfCodecEx[Literals] = generic.deriveCodecEx(Literals()) + .noTypos } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/NamedDialect.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/NamedDialect.scala index 9958a74349..c2026367cc 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/NamedDialect.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/NamedDialect.scala @@ -14,10 +14,8 @@ object NamedDialect { apply(name.toLowerCase, pair.value) } - val scala212 = Scala212 - .withAllowTrailingCommas(true) // SIP-27, 2.12.2 - val scala213 = Scala213 - .withAllowTrailingCommas(true) + val scala212 = Scala212.withAllowTrailingCommas(true) // SIP-27, 2.12.2 + val scala213 = Scala213.withAllowTrailingCommas(true) val scala3 = Scala3 private[config] val known = Seq[sourcecode.Text[Dialect]]( @@ -36,8 +34,8 @@ object NamedDialect { // current default is 213 private[config] val default = apply(defaultName, scala213) - def getName(dialect: Dialect): Option[String] = - known.find(_.dialect eq dialect).map(_.name) + def getName(dialect: Dialect): Option[String] = known + .find(_.dialect eq dialect).map(_.name) def getUnknownError = { val knownStr = known.map(_.name).mkString(",") @@ -46,7 +44,7 @@ object NamedDialect { |""".stripMargin } - implicit val codec: ConfCodecEx[NamedDialect] = - ReaderUtil.oneOf(known.map(x => sourcecode.Text(x, x.name)): _*) + implicit val codec: ConfCodecEx[NamedDialect] = ReaderUtil + .oneOf(known.map(x => sourcecode.Text(x, x.name)): _*) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Newlines.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Newlines.scala index ff222ea4fb..9ec53121fe 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Newlines.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Newlines.scala @@ -219,22 +219,20 @@ case class Newlines( def sourceIgnored: Boolean = source.ignoreSourceSplit @inline - def keepBreak(newlines: => Int): Boolean = - source.eq(Newlines.keep) && newlines != 0 + def keepBreak(newlines: => Int): Boolean = source.eq(Newlines.keep) && + newlines != 0 @inline - def keepBreak(ft: FormatToken): Boolean = - keepBreak(ft.newlinesBetween) - - val breakAfterInfix: AfterInfix = - afterInfix.getOrElse { - source match { - case Newlines.unfold => AfterInfix.many - case Newlines.fold => AfterInfix.some - case Newlines.keep => AfterInfix.keep - case Newlines.classic => AfterInfix.keep - } + def keepBreak(ft: FormatToken): Boolean = keepBreak(ft.newlinesBetween) + + val breakAfterInfix: AfterInfix = afterInfix.getOrElse { + source match { + case Newlines.unfold => AfterInfix.many + case Newlines.fold => AfterInfix.some + case Newlines.keep => AfterInfix.keep + case Newlines.classic => AfterInfix.keep } + } val formatInfix: Boolean = breakAfterInfix ne AfterInfix.keep def checkInfixConfig(infixCount: Int): Newlines = { @@ -255,19 +253,18 @@ case class Newlines( lazy val notBeforeImplicitParamListModifier: Boolean = if (implicitParamListModifierForce.isEmpty) !preferBeforeImplicitParamListModifier - else - !forceBeforeImplicitParamListModifier + else !forceBeforeImplicitParamListModifier - lazy val avoidForSimpleOverflowPunct: Boolean = - avoidForSimpleOverflow.contains(AvoidForSimpleOverflow.punct) - lazy val avoidForSimpleOverflowTooLong: Boolean = - avoidForSimpleOverflow.contains(AvoidForSimpleOverflow.tooLong) - lazy val avoidForSimpleOverflowSLC: Boolean = - avoidForSimpleOverflow.contains(AvoidForSimpleOverflow.slc) + lazy val avoidForSimpleOverflowPunct: Boolean = avoidForSimpleOverflow + .contains(AvoidForSimpleOverflow.punct) + lazy val avoidForSimpleOverflowTooLong: Boolean = avoidForSimpleOverflow + .contains(AvoidForSimpleOverflow.tooLong) + lazy val avoidForSimpleOverflowSLC: Boolean = avoidForSimpleOverflow + .contains(AvoidForSimpleOverflow.slc) @inline - def alwaysBeforeCurlyLambdaParams = - beforeCurlyLambdaParams eq BeforeCurlyLambdaParams.always + def alwaysBeforeCurlyLambdaParams = beforeCurlyLambdaParams eq + BeforeCurlyLambdaParams.always lazy val getBeforeMultiline = beforeMultiline.getOrElse(source) lazy val shouldForceBeforeMultilineAssign = { @@ -302,35 +299,33 @@ case class Newlines( } } - @inline def hasTopStatBlankLines = topStatBlankLinesSorted.nonEmpty + @inline + def hasTopStatBlankLines = topStatBlankLinesSorted.nonEmpty def getTopStatBlankLines( tree: Tree, numBreaks: Int, nest: Int - ): Option[NumBlanks] = - topStatBlankLinesSorted.iterator - .takeWhile(_.minBreaks <= numBreaks) - .find { x => - x.minNest <= nest && x.maxNest >= nest && - x.pattern.forall(_.matcher(tree.productPrefix).find()) - } - .flatMap(_.blanks) + ): Option[NumBlanks] = topStatBlankLinesSorted.iterator + .takeWhile(_.minBreaks <= numBreaks).find { x => + x.minNest <= nest && x.maxNest >= nest && + x.pattern.forall(_.matcher(tree.productPrefix).find()) + }.flatMap(_.blanks) private def getBeforeOpenParen(bop: BeforeOpenParen): SourceHints = Option(bop.src).getOrElse(source) - def getBeforeOpenParenCallSite: Option[SourceHints] = - beforeOpenParenCallSite.map(getBeforeOpenParen) - def getBeforeOpenParenDefnSite: Option[SourceHints] = - beforeOpenParenDefnSite.map(getBeforeOpenParen) + def getBeforeOpenParenCallSite: Option[SourceHints] = beforeOpenParenCallSite + .map(getBeforeOpenParen) + def getBeforeOpenParenDefnSite: Option[SourceHints] = beforeOpenParenDefnSite + .map(getBeforeOpenParen) def isBeforeOpenParenCallSite: Boolean = beforeOpenParenCallSite.isDefined def isBeforeOpenParenDefnSite: Boolean = beforeOpenParenDefnSite.isDefined } object Newlines { implicit lazy val surface: Surface[Newlines] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[Newlines] = - generic.deriveCodecEx(Newlines()).noTypos + implicit lazy val codec: ConfCodecEx[Newlines] = generic + .deriveCodecEx(Newlines()).noTypos sealed abstract class IgnoreSourceSplit { val ignoreSourceSplit: Boolean @@ -351,8 +346,8 @@ object Newlines { object SourceHints { // NB: don't allow specifying classic, only by default - implicit val codec: ConfCodecEx[SourceHints] = - ReaderUtil.oneOfCustom[SourceHints](keep, fold, unfold) { + implicit val codec: ConfCodecEx[SourceHints] = ReaderUtil + .oneOfCustom[SourceHints](keep, fold, unfold) { case Conf.Bool(true) => Configured.Ok(unfold) case Conf.Bool(false) => Configured.Ok(fold) } @@ -364,24 +359,24 @@ object Newlines { case object some extends AfterInfix case object many extends AfterInfix - implicit val reader: ConfCodecEx[AfterInfix] = - ReaderUtil.oneOf[AfterInfix](keep, some, many) + implicit val reader: ConfCodecEx[AfterInfix] = ReaderUtil + .oneOf[AfterInfix](keep, some, many) } sealed abstract class BeforeAfter case object before extends BeforeAfter case object after extends BeforeAfter - implicit val beforeAfterReader: ConfCodecEx[BeforeAfter] = - ReaderUtil.oneOf[BeforeAfter](before, after) + implicit val beforeAfterReader: ConfCodecEx[BeforeAfter] = ReaderUtil + .oneOf[BeforeAfter](before, after) sealed abstract class AvoidForSimpleOverflow object AvoidForSimpleOverflow { case object punct extends AvoidForSimpleOverflow case object tooLong extends AvoidForSimpleOverflow case object slc extends AvoidForSimpleOverflow - implicit val codec: ConfCodecEx[AvoidForSimpleOverflow] = - ReaderUtil.oneOf[AvoidForSimpleOverflow](punct, tooLong, slc) + implicit val codec: ConfCodecEx[AvoidForSimpleOverflow] = ReaderUtil + .oneOf[AvoidForSimpleOverflow](punct, tooLong, slc) } sealed abstract class InInterpolation @@ -389,8 +384,8 @@ object Newlines { case object allow extends InInterpolation case object avoid extends InInterpolation case object oneline extends InInterpolation - implicit val codec: ConfCodecEx[InInterpolation] = - ReaderUtil.oneOf[InInterpolation](allow, avoid, oneline) + implicit val codec: ConfCodecEx[InInterpolation] = ReaderUtil + .oneOf[InInterpolation](allow, avoid, oneline) } sealed abstract class AfterCurlyLambdaParams @@ -399,14 +394,9 @@ object Newlines { case object always extends AfterCurlyLambdaParams case object never extends AfterCurlyLambdaParams case object squash extends AfterCurlyLambdaParams - implicit val codec: ConfCodecEx[AfterCurlyLambdaParams] = - ReaderUtil.oneOfCustom[AfterCurlyLambdaParams]( - preserve, - always, - never, - squash - ) { case Conf.Str("keep") => - Configured.Ok(preserve) + implicit val codec: ConfCodecEx[AfterCurlyLambdaParams] = ReaderUtil + .oneOfCustom[AfterCurlyLambdaParams](preserve, always, never, squash) { + case Conf.Str("keep") => Configured.Ok(preserve) } } @@ -416,8 +406,8 @@ object Newlines { case object never extends BeforeCurlyLambdaParams case object multiline extends BeforeCurlyLambdaParams case object multilineWithCaseOnly extends BeforeCurlyLambdaParams - implicit val codec: ConfCodecEx[BeforeCurlyLambdaParams] = - ReaderUtil.oneOfCustom[BeforeCurlyLambdaParams]( + implicit val codec: ConfCodecEx[BeforeCurlyLambdaParams] = ReaderUtil + .oneOfCustom[BeforeCurlyLambdaParams]( never, always, multiline, @@ -434,14 +424,8 @@ object Newlines { object ForceBeforeMultilineAssign { - implicit val codec: ConfCodecEx[ForceBeforeMultilineAssign] = - ReaderUtil.oneOf[ForceBeforeMultilineAssign]( - never, - any, - `def`, - anyMember, - topMember - ) + implicit val codec: ConfCodecEx[ForceBeforeMultilineAssign] = ReaderUtil + .oneOf[ForceBeforeMultilineAssign](never, any, `def`, anyMember, topMember) case object never extends ForceBeforeMultilineAssign { def apply(tree: Tree): Boolean = false @@ -488,8 +472,8 @@ object Newlines { } object NumBlanks { implicit val surface: Surface[NumBlanks] = generic.deriveSurface[NumBlanks] - implicit val encoder: ConfEncoder[NumBlanks] = - generic.deriveEncoder[NumBlanks] + implicit val encoder: ConfEncoder[NumBlanks] = generic + .deriveEncoder[NumBlanks] implicit val decoder: ConfDecoderEx[NumBlanks] = { val base = generic.deriveDecoderEx(NumBlanks()).noTypos ConfDecoderEx.from[NumBlanks] { @@ -521,24 +505,22 @@ object Newlines { lazy val pattern = regex.map(_.r.pattern) } object TopStatBlanks { - implicit val surface: Surface[TopStatBlanks] = - generic.deriveSurface[TopStatBlanks] - implicit val codec: ConfCodecEx[TopStatBlanks] = - generic.deriveCodecEx(TopStatBlanks()).noTypos + implicit val surface: Surface[TopStatBlanks] = generic + .deriveSurface[TopStatBlanks] + implicit val codec: ConfCodecEx[TopStatBlanks] = generic + .deriveCodecEx(TopStatBlanks()).noTypos } case class BeforeOpenParen(src: SourceHints = null) object BeforeOpenParen { - implicit val encoder: ConfEncoder[BeforeOpenParen] = - SourceHints.codec.contramap(_.src) - implicit val decoder: ConfDecoderEx[BeforeOpenParen] = - ConfDecoderEx.from { - case (_, Conf.Str("source")) => Configured.Ok(BeforeOpenParen()) - case (_, _: Conf.Bool) => - Configured.error("beforeOpenParen can't be bool") - case (_, conf) => - SourceHints.codec.read(None, conf).map(BeforeOpenParen.apply) - } + implicit val encoder: ConfEncoder[BeforeOpenParen] = SourceHints.codec + .contramap(_.src) + implicit val decoder: ConfDecoderEx[BeforeOpenParen] = ConfDecoderEx.from { + case (_, Conf.Str("source")) => Configured.Ok(BeforeOpenParen()) + case (_, _: Conf.Bool) => Configured.error("beforeOpenParen can't be bool") + case (_, conf) => SourceHints.codec.read(None, conf) + .map(BeforeOpenParen.apply) + } } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/OptIn.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/OptIn.scala index b22daec74a..f0df93616d 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/OptIn.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/OptIn.scala @@ -116,6 +116,6 @@ case class OptIn( object OptIn { implicit lazy val surface: Surface[OptIn] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[OptIn] = - generic.deriveCodecEx(OptIn()).noTypos + implicit lazy val codec: ConfCodecEx[OptIn] = generic.deriveCodecEx(OptIn()) + .noTypos } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Presets.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Presets.scala index 220f49d115..2312a1505a 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Presets.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Presets.scala @@ -14,8 +14,7 @@ object Presets { decodePresets(conf, sectionName, presets) match { case Some(x: Configured.NotOk) => x case Some(Configured.Ok((obj, null))) => Configured.ok(obj) - case Some(Configured.Ok((obj, cfg))) => - baseDecoder.read(Some(obj), cfg) + case Some(Configured.Ok((obj, cfg))) => baseDecoder.read(Some(obj), cfg) case _ => baseDecoder.read(state, conf) } @@ -29,14 +28,12 @@ object Presets { def unapply(conf: Conf): Option[A] = presets.lift(conf) } conf match { - case Conf.Obj(v) => - v.collectFirst { case (`presetKey`, x) => x }.map { + case Conf.Obj(v) => v.collectFirst { case (`presetKey`, x) => x }.map { case presetsMatch(x) => val filtered = v.filter(_._1 != presetKey) val newConf = if (filtered.isEmpty) null else Conf.Obj(filtered) Configured.ok((x, newConf)) - case x => - Configured.error(s"$me: unsupported preset: $x") + case x => Configured.error(s"$me: unsupported preset: $x") } case presetsMatch(_) => val section = Option(sectionName).fold("subsection '")(x => s"'$x.") diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ProjectFiles.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ProjectFiles.scala index 314a913074..da9230f31e 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ProjectFiles.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ProjectFiles.scala @@ -37,13 +37,12 @@ case class ProjectFiles( object ProjectFiles { implicit lazy val surface: generic.Surface[ProjectFiles] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[ProjectFiles] = - generic.deriveCodecEx(ProjectFiles()).noTypos + implicit lazy val codec: ConfCodecEx[ProjectFiles] = generic + .deriveCodecEx(ProjectFiles()).noTypos private implicit val fs: file.FileSystem = file.FileSystems.getDefault - val defaultIncludePaths = - Seq("glob:**.scala", "glob:**.sbt", "glob:**.sc") + val defaultIncludePaths = Seq("glob:**.scala", "glob:**.sbt", "glob:**.sc") private sealed abstract class PathMatcher { def matches(path: file.Path): Boolean @@ -55,8 +54,8 @@ object ProjectFiles { regexExclude: Seq[String] = Nil ): FileMatcher = { // check if includePaths were specified explicitly - val useIncludePaths = - pf.includePaths.ne(defaultIncludePaths) || pf.includeFilters.isEmpty + val useIncludePaths = pf.includePaths.ne(defaultIncludePaths) || + pf.includeFilters.isEmpty val includePaths = if (useIncludePaths) pf.includePaths else Seq.empty new FileMatcher( nio(includePaths) ++ regex(pf.includeFilters), @@ -64,8 +63,8 @@ object ProjectFiles { ) } - private def create(seq: Seq[String], f: String => PathMatcher) = - seq.map(_.asFilename).distinct.map(f) + private def create(seq: Seq[String], f: String => PathMatcher) = seq + .map(_.asFilename).distinct.map(f) private def nio(seq: Seq[String]) = create(seq, new Nio(_)) private def regex(seq: Seq[String]) = create(seq, new Regex(_)) @@ -73,8 +72,7 @@ object ProjectFiles { private val matcher = try { fs.getPathMatcher(pattern) } catch { - case _: IllegalArgumentException => - throw new ScalafmtConfigException( + case _: IllegalArgumentException => throw new ScalafmtConfigException( s"Illegal pattern in configuration: $pattern" ) } @@ -91,18 +89,16 @@ object ProjectFiles { ) } - def matches(path: file.Path): Boolean = - pattern.matcher(path.toString).find() + def matches(path: file.Path): Boolean = pattern.matcher(path.toString) + .find() } } class FileMatcher(include: Seq[PathMatcher], exclude: Seq[PathMatcher]) { - def matchesPath(path: file.Path): Boolean = - include.exists(_.matches(path)) && !exclude.exists(_.matches(path)) - def matches(filename: String): Boolean = - matchesPath(fs.getPath(filename)) - def matchesFile(file: AbsoluteFile): Boolean = - matchesPath(file.path) + def matchesPath(path: file.Path): Boolean = include + .exists(_.matches(path)) && !exclude.exists(_.matches(path)) + def matches(filename: String): Boolean = matchesPath(fs.getPath(filename)) + def matchesFile(file: AbsoluteFile): Boolean = matchesPath(file.path) } case class FileInfo(lang: String, isTest: Boolean) @@ -112,8 +108,8 @@ object ProjectFiles { protected[config] def getDialectByLang(lang: String)(implicit dialect: Dialect ): Option[NamedDialect] - final def getLang(path: AbsoluteFile): Option[String] = - getInfo(path).map(_.lang) + final def getLang(path: AbsoluteFile): Option[String] = getInfo(path) + .map(_.lang) final def withLang(lang: String, style: ScalafmtConfig): ScalafmtConfig = style.withDialect(getDialectByLang(lang)(style.dialect)) } @@ -133,10 +129,7 @@ object ProjectFiles { } @tailrec - private def getInfo( - dirs: Array[String], - len: Int - ): Option[FileInfo] = { + private def getInfo(dirs: Array[String], len: Int): Option[FileInfo] = { // src/phase/lang val srcIdx = dirs.lastIndexOf("src", len - 3) if (srcIdx < 0) None @@ -149,16 +142,19 @@ object ProjectFiles { } } - @inline private def is211(implicit dialect: Dialect) = + @inline + private def is211(implicit dialect: Dialect) = !dialect.allowCaseClassWithoutParameterList - @inline private def is212(implicit dialect: Dialect) = - dialect.allowTrailingCommas - @inline private def is213(implicit dialect: Dialect) = - dialect.allowLiteralTypes - @inline private def is3(implicit dialect: Dialect) = + @inline + private def is212(implicit dialect: Dialect) = dialect.allowTrailingCommas + @inline + private def is213(implicit dialect: Dialect) = dialect.allowLiteralTypes + @inline + private def is3(implicit dialect: Dialect) = dialect.allowSignificantIndentation - @inline private[config] def nd(text: sourcecode.Text[Dialect]) = + @inline + private[config] def nd(text: sourcecode.Text[Dialect]) = Some(NamedDialect(text)) private[config] val s210 = nd(dialects.Scala210) private[config] val s211 = nd(dialects.Scala211) @@ -166,9 +162,9 @@ object ProjectFiles { private[config] val s213 = nd(NamedDialect.scala213) private[config] val s3 = nd(NamedDialect.scala3) - override protected[config] def getDialectByLang(lang: String)(implicit - dialect: Dialect - ): Option[NamedDialect] = lang match { + override protected[config] def getDialectByLang( + lang: String + )(implicit dialect: Dialect): Option[NamedDialect] = lang match { case "scala-2.10" if is211 => s210 case "scala-2.11" if is212 || !is211 => s211 case "scala-2.12" if is213 || !is212 => s212 @@ -179,10 +175,8 @@ object ProjectFiles { } } - implicit val reader: ConfCodecEx[Layout] = - ReaderUtil.oneOf[Layout]( - StandardConvention - ) + implicit val reader: ConfCodecEx[Layout] = ReaderUtil + .oneOf[Layout](StandardConvention) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ReaderUtil.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ReaderUtil.scala index 7bcb732057..1842673d71 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ReaderUtil.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ReaderUtil.scala @@ -6,8 +6,8 @@ import metaconfig._ object ReaderUtil { - private def lowerCaseNoBackticks(s: String): String = - s.toLowerCase().replace("`", "") + private def lowerCaseNoBackticks(s: String): String = s.toLowerCase() + .replace("`", "") // Poor mans coproduct reader def oneOf[T: ClassTag](options: sourcecode.Text[T]*): ConfCodecEx[T] = { @@ -27,20 +27,17 @@ object ReaderUtil { options: sourcecode.Text[T]* )(f: PartialFunction[(Option[T], Conf), Configured[T]]): ConfCodecEx[T] = { val m = options.map(x => lowerCaseNoBackticks(x.source) -> x.value).toMap - val decoder = - ConfDecoderEx.fromPartial[T]("String")(f.orElse { case (_, Conf.Str(x)) => - Configured.opt(m.get(lowerCaseNoBackticks(x))) { + val decoder = ConfDecoderEx.fromPartial[T]("String")(f.orElse { + case (_, Conf.Str(x)) => Configured.opt(m.get(lowerCaseNoBackticks(x))) { val available = m.keys.mkString(", ") val msg = s"Unknown input '$x'. Expected one of: $available" ConfError.message(msg) } - }) + }) val encoder = ConfEncoder.instance[T] { value => - options - .collectFirst { case sourcecode.Text(`value`, source) => - Conf.Str(source) - } - .getOrElse(Conf.Null()) + options.collectFirst { case sourcecode.Text(`value`, source) => + Conf.Str(source) + }.getOrElse(Conf.Null()) } new ConfCodecEx(encoder, decoder) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RedundantBracesSettings.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RedundantBracesSettings.scala index b797f64771..d7ff16908c 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RedundantBracesSettings.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RedundantBracesSettings.scala @@ -22,8 +22,8 @@ object RedundantBracesSettings { implicit lazy val surface: generic.Surface[RedundantBracesSettings] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[RedundantBracesSettings] = - generic.deriveCodecEx(default).noTypos + implicit lazy val codec: ConfCodecEx[RedundantBracesSettings] = generic + .deriveCodecEx(default).noTypos sealed abstract class DefnBodies diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RedundantParensSettings.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RedundantParensSettings.scala index adeb42a94b..2aae04ebb0 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RedundantParensSettings.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RedundantParensSettings.scala @@ -10,13 +10,13 @@ object RedundantParensSettings { val default = RedundantParensSettings() implicit lazy val surface: generic.Surface[RedundantParensSettings] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[RedundantParensSettings] = - generic.deriveCodecEx(default).noTypos + implicit lazy val codec: ConfCodecEx[RedundantParensSettings] = generic + .deriveCodecEx(default).noTypos sealed abstract class InfixSide object InfixSide { - implicit val codec: ConfCodecEx[InfixSide] = - ReaderUtil.oneOf[InfixSide](all, many, some) + implicit val codec: ConfCodecEx[InfixSide] = ReaderUtil + .oneOf[InfixSide](all, many, some) case object all extends InfixSide case object many extends InfixSide case object some extends InfixSide diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RewriteScala3Settings.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RewriteScala3Settings.scala index 16b13e7c5d..1e36747315 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RewriteScala3Settings.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RewriteScala3Settings.scala @@ -17,15 +17,14 @@ case class RewriteScala3Settings( object RewriteScala3Settings { implicit val surface: generic.Surface[RewriteScala3Settings] = generic.deriveSurface - implicit val encoder: ConfEncoder[RewriteScala3Settings] = - generic.deriveEncoder[RewriteScala3Settings] + implicit val encoder: ConfEncoder[RewriteScala3Settings] = generic + .deriveEncoder[RewriteScala3Settings] val default = new RewriteScala3Settings implicit val decodec: ConfDecoderEx[RewriteScala3Settings] = Presets .mapDecoder(generic.deriveDecoderEx(default).noTypos, "rewrite.scala3") { - case Conf.Bool(true) => - new RewriteScala3Settings( + case Conf.Bool(true) => new RewriteScala3Settings( convertToNewSyntax = true, removeOptionalBraces = RemoveOptionalBraces.yes ) @@ -47,8 +46,8 @@ object RewriteScala3Settings { implicit val surface: generic.Surface[RemoveOptionalBraces] = generic.deriveSurface - implicit val encoder: ConfEncoder[RemoveOptionalBraces] = - generic.deriveEncoder[RemoveOptionalBraces] + implicit val encoder: ConfEncoder[RemoveOptionalBraces] = generic + .deriveEncoder[RemoveOptionalBraces] implicit final val decoder: ConfDecoderEx[RemoveOptionalBraces] = { val baseDecoder = generic.deriveDecoderEx[RemoveOptionalBraces](no) @@ -56,8 +55,8 @@ object RewriteScala3Settings { conf match { case Conf.Bool(true) | Conf.Str("yes") => Configured.Ok(yes) case Conf.Bool(false) | Conf.Str("no") => Configured.Ok(no) - case Conf.Str("oldSyntaxToo") => - Configured.Ok(RemoveOptionalBraces(oldSyntaxToo = true)) + case Conf.Str("oldSyntaxToo") => Configured + .Ok(RemoveOptionalBraces(oldSyntaxToo = true)) case _ => baseDecoder.read(stateOpt, conf) } } @@ -67,8 +66,8 @@ object RewriteScala3Settings { object EndMarkerLines { - implicit val codec: ConfCodecEx[EndMarkerLines] = - ReaderUtil.oneOf[EndMarkerLines](all, lastBlockOnly) + implicit val codec: ConfCodecEx[EndMarkerLines] = ReaderUtil + .oneOf[EndMarkerLines](all, lastBlockOnly) case object all extends EndMarkerLines case object lastBlockOnly extends EndMarkerLines @@ -90,8 +89,8 @@ object RewriteScala3Settings { implicit val surface: generic.Surface[ConvertToNewSyntax] = generic.deriveSurface - implicit val codec: ConfCodecEx[ConvertToNewSyntax] = - generic.deriveCodecEx(default).noTypos + implicit val codec: ConfCodecEx[ConvertToNewSyntax] = generic + .deriveCodecEx(default).noTypos } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RewriteSettings.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RewriteSettings.scala index 506a38b564..1ae15ef64c 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RewriteSettings.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/RewriteSettings.scala @@ -22,14 +22,14 @@ case class RewriteSettings( @annotation.ExtraName("neverInfix") avoidInfix: AvoidInfixSettings = AvoidInfixSettings.default ) { - def isAllowInfixPlaceholderArg: Boolean = - avoidInfix.excludePlaceholderArg.getOrElse(allowInfixPlaceholderArg) + def isAllowInfixPlaceholderArg: Boolean = avoidInfix.excludePlaceholderArg + .getOrElse(allowInfixPlaceholderArg) def withoutRewrites: RewriteSettings = copy(rules = Nil, trailingCommas = trailingCommas.withoutRewrites) - def rewriteFactoryRules: Seq[RewriteFactory] = - rules.collect { case x: RewriteFactory => x } + def rewriteFactoryRules: Seq[RewriteFactory] = rules + .collect { case x: RewriteFactory => x } def rulesChanged(v2: RewriteSettings): Option[Seq[String]] = { val v1rules = rewriteFactoryRules.toSet @@ -41,14 +41,14 @@ case class RewriteSettings( .filter(_.nonEmpty) } - private[config] def forSbtOpt: Option[RewriteSettings] = - avoidInfix.forSbtOpt.map(x => copy(avoidInfix = x)) + private[config] def forSbtOpt: Option[RewriteSettings] = avoidInfix.forSbtOpt + .map(x => copy(avoidInfix = x)) - private[config] def forMainOpt: Option[RewriteSettings] = - avoidInfix.forMainOpt.map(x => copy(avoidInfix = x)) + private[config] def forMainOpt: Option[RewriteSettings] = avoidInfix + .forMainOpt.map(x => copy(avoidInfix = x)) - private[config] def forTestOpt: Option[RewriteSettings] = - avoidInfix.forTestOpt.map(x => copy(avoidInfix = x)) + private[config] def forTestOpt: Option[RewriteSettings] = avoidInfix + .forTestOpt.map(x => copy(avoidInfix = x)) } object RewriteSettings { @@ -60,20 +60,15 @@ object RewriteSettings { implicit lazy val encoder: ConfEncoder[RewriteSettings] = generic.deriveEncoder - implicit lazy val decoder: ConfDecoderEx[RewriteSettings] = - generic.deriveDecoderEx(default).noTypos.flatMap { - Imports.validateImports - } + implicit lazy val decoder: ConfDecoderEx[RewriteSettings] = generic + .deriveDecoderEx(default).noTypos.flatMap { Imports.validateImports } - case class InsertBraces( - minLines: Int = 0, - allBlocks: Boolean = false - ) + case class InsertBraces(minLines: Int = 0, allBlocks: Boolean = false) private[RewriteSettings] object InsertBraces { implicit val surface: generic.Surface[InsertBraces] = generic.deriveSurface - implicit val codec: ConfCodecEx[InsertBraces] = - generic.deriveCodecEx(new InsertBraces) + implicit val codec: ConfCodecEx[InsertBraces] = generic + .deriveCodecEx(new InsertBraces) } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtConfDecoders.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtConfDecoders.scala index 4fdae7971f..6b55605349 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtConfDecoders.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtConfDecoders.scala @@ -12,16 +12,14 @@ object ScalafmtConfDecoders extends ScalafmtConfDecoders trait ScalafmtConfDecoders { type FormatEventCb = FormatEvent => Unit - implicit lazy val eventReader: ConfDecoderEx[FormatEventCb] = - ConfDecoderEx.from[FormatEventCb] { case _ => - Configured.Ok((_: FormatEvent) => ()) - } + implicit lazy val eventReader: ConfDecoderEx[FormatEventCb] = ConfDecoderEx + .from[FormatEventCb] { case _ => Configured.Ok((_: FormatEvent) => ()) } implicit lazy val parseReader: ConfCodecEx[MetaParser] = { ReaderUtil.oneOf[MetaParser](parseSource, parseStat, parseCase) } - implicit lazy val codecReader: ConfDecoderEx[Codec] = - ConfDecoderEx.fromPartial[Codec]("String") { case (_, Conf.Str(s)) => + implicit lazy val codecReader: ConfDecoderEx[Codec] = ConfDecoderEx + .fromPartial[Codec]("String") { case (_, Conf.Str(s)) => Configured.fromExceptionThrowing(Codec(s)) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtConfig.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtConfig.scala index a4c3b668cd..b71d705dec 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtConfig.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtConfig.scala @@ -158,15 +158,12 @@ case class ScalafmtConfig( k -> v.getMatcher } - private[scalafmt] def withDialect( - dialect: NamedDialect - ): ScalafmtConfig = + private[scalafmt] def withDialect(dialect: NamedDialect): ScalafmtConfig = copy(runner = runner.withDialect(dialect)) private[scalafmt] def withDialect( dialect: Option[NamedDialect] - ): ScalafmtConfig = - dialect.fold(this)(withDialect) + ): ScalafmtConfig = dialect.fold(this)(withDialect) def withDialect(dialect: Dialect, name: String): ScalafmtConfig = withDialect(NamedDialect(name, dialect)) @@ -180,11 +177,11 @@ case class ScalafmtConfig( if (project.layout.isEmpty) forTest else rewrite.forMainOpt.fold(this)(x => copy(rewrite = x)) - private lazy val forTest: ScalafmtConfig = - rewrite.forTestOpt.fold(this)(x => copy(rewrite = x)) + private lazy val forTest: ScalafmtConfig = rewrite.forTestOpt + .fold(this)(x => copy(rewrite = x)) - def forSbt: ScalafmtConfig = - rewrite.forSbtOpt.fold(this)(x => copy(rewrite = x)) + def forSbt: ScalafmtConfig = rewrite.forSbtOpt + .fold(this)(x => copy(rewrite = x)) private lazy val expandedFileOverride = Try { val langPrefix = "lang:" @@ -215,13 +212,12 @@ case class ScalafmtConfig( private def getConfigViaLayoutInfoFor(absfile: AbsoluteFile)( f: (ProjectFiles.Layout, String) => ScalafmtConfig - ): Option[ScalafmtConfig] = - project.layout.flatMap { layout => - layout.getInfo(absfile).map { info => - val style = f(layout, info.lang) - if (info.isTest) style.forTest else style.forMain - } + ): Option[ScalafmtConfig] = project.layout.flatMap { layout => + layout.getInfo(absfile).map { info => + val style = f(layout, info.lang) + if (info.isTest) style.forTest else style.forMain } + } def getConfigFor(filename: String): Try[ScalafmtConfig] = { val absfile = AbsoluteFile(filename) @@ -232,24 +228,23 @@ case class ScalafmtConfig( } val pmStyle = pmStyles.collectFirst { case (pm, style) if pm.matches(absfile.path) => - style - .getConfigViaLayoutInfoFor(absfile) { (layout, lang) => - val sameDialect = style.dialect.isEquivalentTo(dialect) - if (sameDialect) layout.withLang(lang, style) else style - } - .getOrElse(style) + style.getConfigViaLayoutInfoFor(absfile) { (layout, lang) => + val sameDialect = style.dialect.isEquivalentTo(dialect) + if (sameDialect) layout.withLang(lang, style) else style + }.getOrElse(style) } pmStyle.orElse(langStyle).getOrElse(forTest) } } - private[scalafmt] lazy val encloseSelectChains = - optIn.encloseClassicChains || newlines.source.ne(Newlines.classic) + private[scalafmt] lazy val encloseSelectChains = optIn.encloseClassicChains || + newlines.source.ne(Newlines.classic) - private[scalafmt] lazy val docstringsWrapMaxColumn: Int = - docstrings.wrapMaxColumn.getOrElse(maxColumn) + private[scalafmt] lazy val docstringsWrapMaxColumn: Int = docstrings + .wrapMaxColumn.getOrElse(maxColumn) - @inline private[scalafmt] def dialect = runner.getDialectForParser + @inline + private[scalafmt] def dialect = runner.getDialectForParser private[scalafmt] def getTrailingCommas = rewrite.trailingCommas.style @@ -266,19 +261,18 @@ case class ScalafmtConfig( rewrite = rewrite.withoutRewrites ) - lazy val forceNewlineBeforeDocstring: Boolean = - docstrings.forceBlankLineBefore - .getOrElse(optIn.forceBlankLineBeforeDocstring) + lazy val forceNewlineBeforeDocstring: Boolean = docstrings + .forceBlankLineBefore.getOrElse(optIn.forceBlankLineBeforeDocstring) - def breakAfterInfix(tree: => Tree): Newlines.AfterInfix = - newlines.afterInfix.getOrElse { + def breakAfterInfix(tree: => Tree): Newlines.AfterInfix = newlines.afterInfix + .getOrElse { val useSome = newlines.source == Newlines.classic && tree.is[Type.ApplyInfix] && dialect.useInfixTypePrecedence if (useSome) Newlines.AfterInfix.some else newlines.breakAfterInfix } - def formatInfix(tree: => Tree): Boolean = - breakAfterInfix(tree) ne Newlines.AfterInfix.keep + def formatInfix(tree: => Tree): Boolean = breakAfterInfix(tree) ne + Newlines.AfterInfix.keep def getFewerBraces(): Indents.FewerBraces = if (indent.getSignificant < 2) Indents.FewerBraces.never @@ -288,11 +282,11 @@ case class ScalafmtConfig( object ScalafmtConfig { implicit lazy val surface: generic.Surface[ScalafmtConfig] = generic.deriveSurface - implicit lazy val encoder: ConfEncoder[ScalafmtConfig] = - generic.deriveEncoder[ScalafmtConfig] + implicit lazy val encoder: ConfEncoder[ScalafmtConfig] = generic + .deriveEncoder[ScalafmtConfig] - implicit lazy val codecEncoder: ConfEncoder[Codec] = - ConfEncoder.StringEncoder.contramap(_.name) + implicit lazy val codecEncoder: ConfEncoder[Codec] = ConfEncoder.StringEncoder + .contramap(_.name) val default = ScalafmtConfig() private[scalafmt] val uncheckedDefault = ScalafmtConfig(version = null) @@ -300,18 +294,12 @@ object ScalafmtConfig { val intellij: ScalafmtConfig = default.copy( indent = Indents(callSite = 2, defnSite = 2), align = default.align.copy(openParenCallSite = false), - optIn = default.optIn.copy( - configStyleArguments = false - ), + optIn = default.optIn.copy(configStyleArguments = false), danglingParentheses = DanglingParentheses.shortcutTrue ) - def addAlign(style: ScalafmtConfig): ScalafmtConfig = - style.copy( - align = style.align.copy( - tokens = AlignToken.default - ) - ) + def addAlign(style: ScalafmtConfig): ScalafmtConfig = style + .copy(align = style.align.copy(tokens = AlignToken.default)) val defaultWithAlign: ScalafmtConfig = addAlign(default) /** Experimental implementation of: @@ -346,23 +334,16 @@ object ScalafmtConfig { /** Ready styles provided by scalafmt. */ private val activeStyles: Map[String, ScalafmtConfig] = - Map( - "Scala.js" -> scalaJs, - "IntelliJ" -> intellij - ) ++ LoggerOps.name2style( - default, - defaultWithAlign - ) + Map("Scala.js" -> scalaJs, "IntelliJ" -> intellij) ++ + LoggerOps.name2style(default, defaultWithAlign) private val availableStyles: Map[String, ScalafmtConfig] = { - activeStyles ++ LoggerOps.name2style( - scalaJs - ) + activeStyles ++ LoggerOps.name2style(scalaJs) }.map { case (k, v) => k.toLowerCase -> v } - private[scalafmt] def conservativeRunner: ScalafmtRunner = - default.runner.copy( - optimizer = default.runner.optimizer.copy( + private[scalafmt] def conservativeRunner: ScalafmtRunner = default.runner + .copy(optimizer = + default.runner.optimizer.copy( // The tests were not written in this style forceConfigStyleMinSpan = 500, forceConfigStyleMinArgCount = 5 @@ -371,8 +352,7 @@ object ScalafmtConfig { private def readActiveStylePresets(conf: Conf): Configured[ScalafmtConfig] = (conf match { - case Conf.Str(x) => - availableStyles.get(x.toLowerCase).map { style => + case Conf.Str(x) => availableStyles.get(x.toLowerCase).map { style => Configured.ok(style) } case _ => None @@ -393,8 +373,7 @@ object ScalafmtConfig { if (newlines.sourceIgnored) { addIf(optIn.configStyleArguments && align.openParenCallSite && newlines.beforeOpenParenCallSite.isEmpty) addIf(optIn.configStyleArguments && align.openParenDefnSite && newlines.beforeOpenParenDefnSite.isEmpty) - def mustIgnoreSourceSplit(what: sourcecode.Text[Option[Newlines.IgnoreSourceSplit]]) = - what.value.foreach(x => addIfDirect(!x.ignoreSourceSplit, s"${what.source}=$x")) + def mustIgnoreSourceSplit(what: sourcecode.Text[Option[Newlines.IgnoreSourceSplit]]) = what.value.foreach(x => addIfDirect(!x.ignoreSourceSplit, s"${what.source}=$x")) mustIgnoreSourceSplit(newlines.beforeMultiline) mustIgnoreSourceSplit(newlines.beforeMultilineDef) addIf(newlines.beforeTypeBounds eq Newlines.keep) @@ -404,9 +383,7 @@ object ScalafmtConfig { addIf(newlines.selectChains.exists(_ eq Newlines.keep)) addIf(getTrailingCommas.eq(TrailingCommas.keep)) } - if (newlines.source == Newlines.unfold) { - addIf(align.arrowEnumeratorGenerator) - } + if (newlines.source == Newlines.unfold) { addIf(align.arrowEnumeratorGenerator) } if (newlines.source != Newlines.classic) { addIf(optIn.breaksInsideChains) addIf(!includeCurlyBraceInSelectChains) @@ -424,37 +401,18 @@ object ScalafmtConfig { addIf(getTrailingCommas eq TrailingCommas.always, errDialect) addIf(getTrailingCommas eq TrailingCommas.multiple, errDialect) } - if (!dialect.allowSignificantIndentation) { - addIf(newlines.beforeOpenParenCallSite.nonEmpty, errDialect) - } + if (!dialect.allowSignificantIndentation) { addIf(newlines.beforeOpenParenCallSite.nonEmpty, errDialect) } addIfDirect( // can't use addIf on multiline conditions - !(binPack.unsafeCallSite.isNever && binPack.unsafeDefnSite.isNever) && { - newlines.implicitParamListModifierForce.nonEmpty || - newlines.implicitParamListModifierPrefer.nonEmpty - }, + !(binPack.unsafeCallSite.isNever && binPack.unsafeDefnSite.isNever) && { newlines.implicitParamListModifierForce.nonEmpty || newlines.implicitParamListModifierPrefer.nonEmpty }, "binPack.unsafeXXXSite && newlines.implicitParamListModifierXXX (not implemented)" ) - checkPositive( - indent.main, - indent.callSite, - indent.defnSite, - indent.commaSiteRelativeToExtends - ) - checkNonNeg( - indent.caseSite, - indent.extendSite, - indent.withSiteRelativeToExtends - ) - checkPositiveOpt( - indent.significant, - indent.ctorSite - ) - if (rewrite.scala3.insertEndMarkerMinLines != 0) - addIf(rewrite.scala3.removeEndMarkerMaxLines >= rewrite.scala3.insertEndMarkerMinLines) + checkPositive(indent.main, indent.callSite, indent.defnSite, indent.commaSiteRelativeToExtends) + checkNonNeg(indent.caseSite, indent.extendSite, indent.withSiteRelativeToExtends) + checkPositiveOpt(indent.significant, indent.ctorSite) + if (rewrite.scala3.insertEndMarkerMinLines != 0) addIf(rewrite.scala3.removeEndMarkerMaxLines >= rewrite.scala3.insertEndMarkerMinLines) addIf(rewrite.insertBraces.minLines != 0 && rewrite.scala3.insertEndMarkerMinLines != 0) addIf(rewrite.insertBraces.minLines != 0 && rewrite.scala3.removeOptionalBraces.oldSyntaxToo) - if (rewrite.insertBraces.minLines != 0 && rewrite.rules.contains(RedundantBraces)) - addIf(rewrite.insertBraces.minLines < rewrite.redundantBraces.maxBreaks) + if (rewrite.insertBraces.minLines != 0 && rewrite.rules.contains(RedundantBraces)) addIf(rewrite.insertBraces.minLines < rewrite.redundantBraces.maxBreaks) addIf(align.beforeOpenParenDefnSite && !align.closeParenSite) addIf(align.beforeOpenParenCallSite && !align.closeParenSite) addIf(rewrite.scala3.removeOptionalBraces.fewerBracesMinSpan <= 0) @@ -465,8 +423,7 @@ object ScalafmtConfig { } // scalafmt: {} if (allErrors.isEmpty) Configured.ok(cfg) - else - Configured.error(allErrors.mkString("can't use: [\n\t", "\n\t", "\n]")) + else Configured.error(allErrors.mkString("can't use: [\n\t", "\n\t", "\n]")) } private val baseDecoder = generic.deriveDecoderEx(default).noTypos @@ -484,29 +441,28 @@ object ScalafmtConfig { case _ => None } val parsed = stylePreset match { - case Some((styleConf, restConf)) => - readActiveStylePresets(styleConf).andThen { x => - val preset = stateOpt.fold(x) { state => - val isDefaultDialect = x.runner.isDefaultDialect - val dialect = (if (isDefaultDialect) state else x).runner.dialect - x.copy( - version = state.version, - runner = - x.runner.withParser(state.runner.parser).withDialect(dialect) - ) + case Some((styleConf, restConf)) => readActiveStylePresets(styleConf) + .andThen { x => + val preset = stateOpt.fold(x) { state => + val isDefaultDialect = x.runner.isDefaultDialect + val dialect = + (if (isDefaultDialect) state else x).runner.dialect + x.copy( + version = state.version, + runner = x.runner.withParser(state.runner.parser) + .withDialect(dialect) + ) + } + baseDecoder.read(Some(preset), restConf) } - baseDecoder.read(Some(preset), restConf) - } case _ => baseDecoder.read(stateOpt, conf) } - parsed - .map { cfg => - cfg.trailingCommas.fold(cfg) { tc => - val rt = cfg.rewrite.trailingCommas.copy(style = tc) - cfg.copy(rewrite = cfg.rewrite.copy(trailingCommas = rt)) - } + parsed.map { cfg => + cfg.trailingCommas.fold(cfg) { tc => + val rt = cfg.rewrite.trailingCommas.copy(style = tc) + cfg.copy(rewrite = cfg.rewrite.copy(trailingCommas = rt)) } - .andThen(validate) + }.andThen(validate) } def fromHoconString( @@ -530,8 +486,8 @@ object ScalafmtConfig { ): Configured[ScalafmtConfig] = { ScalafmtConfig.decoder.read(Option(default), parsed.conf) match { case Configured.Ok(x) - if default.version == null && - x.version != Versions.stable && x.version != Versions.version => + if default.version == null && x.version != Versions.stable && + x.version != Versions.version => val version = Option(x.version).getOrElse("missing") val expected = s"${Versions.stable} or ${Versions.version}" Configured.error(s"version [expected $expected]: $version") diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtOptimizer.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtOptimizer.scala index 08d1d57355..9d778a04f5 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtOptimizer.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtOptimizer.scala @@ -72,8 +72,8 @@ case class ScalafmtOptimizer( object ScalafmtOptimizer { implicit lazy val surface: generic.Surface[ScalafmtOptimizer] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[ScalafmtOptimizer] = - generic.deriveCodecEx(ScalafmtOptimizer()).noTypos + implicit lazy val codec: ConfCodecEx[ScalafmtOptimizer] = generic + .deriveCodecEx(ScalafmtOptimizer()).noTypos val default = ScalafmtOptimizer() // TODO(olafur) uncomment once scala.meta converter supports default args. diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtParser.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtParser.scala index 454219d1b1..bfb37f840e 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtParser.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtParser.scala @@ -13,8 +13,8 @@ object ScalafmtParser { case object Stat extends ScalafmtParser(Parse.parseStat) case object Source extends ScalafmtParser(SourceParser) - implicit val codec: ConfCodecEx[ScalafmtParser] = - ReaderUtil.oneOf[ScalafmtParser](Case, Stat, Source) + implicit val codec: ConfCodecEx[ScalafmtParser] = ReaderUtil + .oneOf[ScalafmtParser](Case, Stat, Source) private object SourceParser extends Parse[Tree] { override def apply(input: Input, dialect: Dialect): Parsed[Tree] = { diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtRunner.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtRunner.scala index 2036f63529..9049a3bbc5 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtRunner.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/ScalafmtRunner.scala @@ -27,14 +27,17 @@ case class ScalafmtRunner( ignoreWarnings: Boolean = false, fatalWarnings: Boolean = false ) { - @inline private[scalafmt] def getDialect = dialect.dialect - private[scalafmt] lazy val getDialectForParser: Dialect = - getDialect.withAllowToplevelTerms(true).withAllowToplevelStatements(true) - @inline private[scalafmt] def dialectName = { + @inline + private[scalafmt] def getDialect = dialect.dialect + private[scalafmt] lazy val getDialectForParser: Dialect = getDialect + .withAllowToplevelTerms(true).withAllowToplevelStatements(true) + @inline + private[scalafmt] def dialectName = { val name = dialect.name if (dialectOverride.values.isEmpty) name else s"$name [with overrides]" } - @inline private[scalafmt] def getParser = parser.parse + @inline + private[scalafmt] def getParser = parser.parse @inline def withDialect(dialect: sourcecode.Text[Dialect]): ScalafmtRunner = @@ -48,11 +51,8 @@ case class ScalafmtRunner( private[scalafmt] def withParser(parser: ScalafmtParser): ScalafmtRunner = copy(parser = parser) - private[scalafmt] def forCodeBlock: ScalafmtRunner = copy( - debug = false, - eventCallback = null, - parser = ScalafmtParser.Source - ) + private[scalafmt] def forCodeBlock: ScalafmtRunner = + copy(debug = false, eventCallback = null, parser = ScalafmtParser.Source) def event(evt: => FormatEvent): Unit = if (null != eventCallback) eventCallback(evt) @@ -63,7 +63,8 @@ case class ScalafmtRunner( def parse(input: meta.inputs.Input): Parsed[_ <: Tree] = getParser(input, getDialectForParser) - @inline def isDefaultDialect = dialect.name == NamedDialect.defaultName + @inline + def isDefaultDialect = dialect.name == NamedDialect.defaultName } @@ -84,8 +85,7 @@ object ScalafmtRunner { val sbt = default.withDialect(meta.dialects.Sbt) - implicit val encoder: ConfEncoder[ScalafmtRunner] = - generic.deriveEncoder + implicit val encoder: ConfEncoder[ScalafmtRunner] = generic.deriveEncoder private def overrideDialect[T: ClassTag](d: Dialect, k: String, v: T) = { import org.scalafmt.config.ReflectOps._ @@ -95,20 +95,19 @@ object ScalafmtRunner { d.invokeAs[Dialect](methodName, v.asParam) } - implicit val decoder: ConfDecoderEx[ScalafmtRunner] = - generic.deriveDecoderEx(default).noTypos.flatMap { runner => + implicit val decoder: ConfDecoderEx[ScalafmtRunner] = generic + .deriveDecoderEx(default).noTypos.flatMap { runner => val overrides = runner.dialectOverride.values if (overrides.isEmpty) Configured.Ok(runner) - else - Configured.fromExceptionThrowing { - val srcDialect = runner.getDialect - val dialect = overrides.foldLeft(srcDialect) { - case (cur, (k, Conf.Bool(v))) => overrideDialect(cur, k, v) - case (cur, _) => cur // other config types are unsupported - } - if (dialect.isEquivalentTo(srcDialect)) runner - else runner.withDialect(runner.dialect.copy(dialect = dialect)) + else Configured.fromExceptionThrowing { + val srcDialect = runner.getDialect + val dialect = overrides.foldLeft(srcDialect) { + case (cur, (k, Conf.Bool(v))) => overrideDialect(cur, k, v) + case (cur, _) => cur // other config types are unsupported } + if (dialect.isEquivalentTo(srcDialect)) runner + else runner.withDialect(runner.dialect.copy(dialect = dialect)) + } } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/SortSettings.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/SortSettings.scala index 9d34f931c8..14869c64bd 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/SortSettings.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/SortSettings.scala @@ -6,21 +6,15 @@ import sourcecode.Text import scala.meta.classifiers.Classifier -case class SortSettings( - order: List[SortSettings.ModKey] -) +case class SortSettings(order: List[SortSettings.ModKey]) object SortSettings { - final case class ModKey( - name: String, - matches: Mod => Boolean - ) + final case class ModKey(name: String, matches: Mod => Boolean) object ModKey { def apply[A](name: String)(implicit classifier: Classifier[Mod, A] - ): ModKey = - ModKey(name, _.is[A]) + ): ModKey = ModKey(name, _.is[A]) } private val modImplicit = ModKey[Mod.Implicit]("implicit") @@ -83,8 +77,8 @@ object SortSettings { modOpaque ) - implicit val sortSettingsModKeyCodec: ConfCodecEx[ModKey] = - ReaderUtil.oneOf[ModKey](defaultOrder.map(v => Text(v, v.name)): _*) + implicit val sortSettingsModKeyCodec: ConfCodecEx[ModKey] = ReaderUtil + .oneOf[ModKey](defaultOrder.map(v => Text(v, v.name)): _*) implicit val surface: generic.Surface[SortSettings] = generic.deriveSurface @@ -102,13 +96,9 @@ object SortSettings { case Conf.Str("styleGuide") => styleGuide } - implicit val encoder: ConfEncoder[SortSettings] = - generic.deriveEncoder + implicit val encoder: ConfEncoder[SortSettings] = generic.deriveEncoder - implicit final val decoder: ConfDecoderEx[SortSettings] = - Presets.mapDecoder( - generic.deriveDecoderEx(default).noTypos, - "sortModifiers" - ) + implicit final val decoder: ConfDecoderEx[SortSettings] = Presets + .mapDecoder(generic.deriveDecoderEx(default).noTypos, "sortModifiers") } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Spaces.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Spaces.scala index 1ee3c9d199..23a7167b5a 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Spaces.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Spaces.scala @@ -67,8 +67,8 @@ case class Spaces( object Spaces { implicit lazy val surface: generic.Surface[Spaces] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[Spaces] = - generic.deriveCodecEx(Spaces()).noTypos + implicit lazy val codec: ConfCodecEx[Spaces] = generic.deriveCodecEx(Spaces()) + .noTypos sealed abstract class BeforeContextBound object BeforeContextBound { diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/TrailingCommas.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/TrailingCommas.scala index 99b373f2a4..2c6c9120b9 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/TrailingCommas.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/TrailingCommas.scala @@ -13,8 +13,8 @@ object TrailingCommas { implicit lazy val surface: generic.Surface[TrailingCommas] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[TrailingCommas] = - generic.deriveCodecEx(TrailingCommas()) + implicit lazy val codec: ConfCodecEx[TrailingCommas] = generic + .deriveCodecEx(TrailingCommas()) /** ADT representing trailing commas settings * @@ -34,8 +34,8 @@ object TrailingCommas { sealed abstract class Style object Style { - implicit val codec: ConfCodecEx[Style] = - ReaderUtil.oneOfCustom[Style](always, never, keep, multiple) { + implicit val codec: ConfCodecEx[Style] = ReaderUtil + .oneOfCustom[Style](always, never, keep, multiple) { case Conf.Str(str) if str.equalsIgnoreCase("preserve") => Configured.Ok(keep) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/VerticalMultiline.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/VerticalMultiline.scala index 398a213ea3..3ab67d4ddd 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/VerticalMultiline.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/VerticalMultiline.scala @@ -13,6 +13,6 @@ case class VerticalMultiline( object VerticalMultiline { implicit lazy val surface: generic.Surface[VerticalMultiline] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[VerticalMultiline] = - generic.deriveCodecEx(VerticalMultiline()).noTypos + implicit lazy val codec: ConfCodecEx[VerticalMultiline] = generic + .deriveCodecEx(VerticalMultiline()).noTypos } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/XmlLiterals.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/XmlLiterals.scala index ce586011f5..c4e2448ee7 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/XmlLiterals.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/XmlLiterals.scala @@ -2,12 +2,10 @@ package org.scalafmt.config import metaconfig._ -case class XmlLiterals( - assumeFormatted: Boolean = false -) +case class XmlLiterals(assumeFormatted: Boolean = false) object XmlLiterals { implicit val surface: generic.Surface[XmlLiterals] = generic.deriveSurface - implicit lazy val codec: ConfCodecEx[XmlLiterals] = - generic.deriveCodecEx(XmlLiterals()).noTypos + implicit lazy val codec: ConfCodecEx[XmlLiterals] = generic + .deriveCodecEx(XmlLiterals()).noTypos } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/BestFirstSearch.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/BestFirstSearch.scala index 00386e91ea..de6648b180 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/BestFirstSearch.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/BestFirstSearch.scala @@ -52,11 +52,10 @@ private class BestFirstSearch private ( /** Returns true if it's OK to skip over state. */ - def shouldEnterState(curr: State): Boolean = - keepSlowStates || curr.policy.noDequeue || - isInsideNoOptZone(tokens(curr.depth)) || - // TODO(olafur) document why/how this optimization works. - !best.get(curr.depth).exists(_.alwaysBetter(curr)) + def shouldEnterState(curr: State): Boolean = keepSlowStates || + curr.policy.noDequeue || isInsideNoOptZone(tokens(curr.depth)) || + // TODO(olafur) document why/how this optimization works. + !best.get(curr.depth).exists(_.alwaysBetter(curr)) def shouldRecurseOnBlock(ft: FormatToken, stop: Token)(implicit style: ScalafmtConfig @@ -67,8 +66,7 @@ private class BestFirstSearch private ( val closeOpt = formatOps.getEndOfBlock(left, false) closeOpt.filter(close => // Block must span at least 3 lines to be worth recursing. - close != stop && - distance(left.left, close) > style.maxColumn * 3 && + close != stop && distance(left.left, close) > style.maxColumn * 3 && extractStatementsIfAny(left.meta.leftOwner).nonEmpty ) } @@ -110,41 +108,33 @@ private class BestFirstSearch private ( def newGeneration = new mutable.PriorityQueue[State]() var Q = newGeneration var generations: List[mutable.PriorityQueue[State]] = Nil - def addGeneration() = - if (Q.nonEmpty) { - generations = Q :: generations - Q = newGeneration - } + def addGeneration() = if (Q.nonEmpty) { + generations = Q :: generations + Q = newGeneration + } Q += start - def enqueue(state: State) = { - Q.enqueue(state) - } + def enqueue(state: State) = { Q.enqueue(state) } // TODO(olafur) this while loop is waaaaaaaaaaaaay tooo big. while (true) { val curr = Q.dequeue() - if (curr.depth >= tokens.length) - return curr + if (curr.depth >= tokens.length) return curr val splitToken = tokens(curr.depth) val leftTok = splitToken.left - if ( - splitToken.right.start > stop.start && - leftTok.start < leftTok.end - ) { + if (splitToken.right.start > stop.start && leftTok.start < leftTok.end) { return curr } if (shouldEnterState(curr)) { trackState(curr, depth, Q.length) - if (explored > runner.maxStateVisits) - throw SearchStateExploded( - deepestYet, - formatWriter.mkString(deepestYet), - tokens(deepestYet.depth) - ) + if (explored > runner.maxStateVisits) throw SearchStateExploded( + deepestYet, + formatWriter.mkString(deepestYet), + tokens(deepestYet.depth) + ) implicit val style = styleMap.at(splitToken) @@ -155,20 +145,17 @@ private class BestFirstSearch private ( dequeueOnNewStatements && curr.allAltAreNL && (leftTok.is[Token.KwElse] || statementStarts.contains(tokenHash)) && (depth > 0 || !isInsideNoOptZone(splitToken)) - ) - addGeneration() + ) addGeneration() } val blockClose = if (start.eq(curr) && 0 != maxCost) None else shouldRecurseOnBlock(splitToken, stop) - if (blockClose.nonEmpty) - blockClose.foreach { end => - shortestPathMemo(curr, end, depth + 1, maxCost).foreach(enqueue) - } + if (blockClose.nonEmpty) blockClose.foreach { end => + shortestPathMemo(curr, end, depth + 1, maxCost).foreach(enqueue) + } else if ( - escapeInPathologicalCases && - isSeqMulti(routes(curr.depth)) && + escapeInPathologicalCases && isSeqMulti(routes(curr.depth)) && visits(curr.depth) > maxVisitsPerToken ) { complete(deepestYet) @@ -184,11 +171,9 @@ private class BestFirstSearch private ( var optimalNotFound = true actualSplit.foreach { split => val nextState = curr.next(split, allAltAreNL) - val updateBest = !keepSlowStates && depth == 0 && - split.isNL && !best.contains(curr.depth) - if (updateBest) { - best.update(curr.depth, nextState) - } + val updateBest = !keepSlowStates && depth == 0 && split.isNL && + !best.contains(curr.depth) + if (updateBest) { best.update(curr.depth, nextState) } runner.event(Enqueue(split)) split.optimalAt match { case Some(OptimalToken(token, killOnFail)) @@ -201,26 +186,21 @@ private class BestFirstSearch private ( if (null == nextNextState) null else traverseSameLine(nextNextState, depth) if (null != furtherState) { - val overflow = - furtherState.appliedPenalty > nextNextState.appliedPenalty - if (overflow) - enqueue(nextNextState) + val overflow = furtherState.appliedPenalty > + nextNextState.appliedPenalty + if (overflow) enqueue(nextNextState) else { optimalNotFound = false enqueue(furtherState) } - } else if ( - !killOnFail && - nextState.cost - curr.cost <= maxCost - ) { + } else if (!killOnFail && nextState.cost - curr.cost <= maxCost) { // TODO(olafur) DRY. This solution can still be optimal. enqueue(nextState) } else { // else kill branch if (updateBest) best.remove(curr.depth) } case _ - if optimalNotFound && - nextState.cost - curr.cost <= maxCost => + if optimalNotFound && nextState.cost - curr.cost <= maxCost => enqueue(nextState) case _ => // Kill branch. if (updateBest) best.remove(curr.depth) @@ -230,8 +210,7 @@ private class BestFirstSearch private ( } if (Q.isEmpty) { - if (generations.isEmpty) - return null + if (generations.isEmpty) return null Q = generations.head generations = generations.tail @@ -245,9 +224,7 @@ private class BestFirstSearch private ( private def getActiveSplits(state: State, maxCost: Int): Seq[Split] = { val ft = tokens(state.depth) val useProvided = ft.meta.formatOff || !ft.inside(range) - val active = state.policy - .execute(Decision(ft, routes(state.depth))) - .splits + val active = state.policy.execute(Decision(ft, routes(state.depth))).splits .filter(x => x.isActive && x.cost <= maxCost) val splits = if (useProvided && active.nonEmpty) { @@ -278,8 +255,7 @@ private class BestFirstSearch private ( trackState(state, depth, 0) val activeSplits = getActiveSplits(state, Int.MaxValue) - if (!isSeqSingle(activeSplits)) - if (activeSplits.isEmpty) null else state // dead end if empty + if (!isSeqSingle(activeSplits)) if (activeSplits.isEmpty) null else state // dead end if empty else { val split = activeSplits.head if (split.isNL) state @@ -292,8 +268,8 @@ private class BestFirstSearch private ( } } - private def complete(state: State): Unit = - runner.event(CompleteFormat(explored, state, visits)) + private def complete(state: State): Unit = runner + .event(CompleteFormat(explored, state, visits)) def getBestPath: SearchResult = { val state = { @@ -312,8 +288,8 @@ private class BestFirstSearch private ( } else { val nextSplits = routes(deepestYet.depth) val tok = tokens(deepestYet.depth) - val splitsAfterPolicy = - deepestYet.policy.execute(Decision(tok, nextSplits)) + val splitsAfterPolicy = deepestYet.policy + .execute(Decision(tok, nextSplits)) val msg = s"""UNABLE TO FORMAT, |tok=$tok |toks.length=${tokens.length} diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Decision.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Decision.scala index 40eb5791ed..24b229c5af 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Decision.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Decision.scala @@ -6,17 +6,17 @@ package org.scalafmt.internal */ case class Decision(formatToken: FormatToken, splits: Seq[Split]) { - @inline def noNewlines: Seq[Split] = - Decision.noNewlineSplits(splits) + @inline + def noNewlines: Seq[Split] = Decision.noNewlineSplits(splits) - @inline def onlyNewlinesWithFallback(default: => Split): Seq[Split] = - Decision.onlyNewlinesWithFallback(splits, default) + @inline + def onlyNewlinesWithFallback(default: => Split): Seq[Split] = Decision + .onlyNewlinesWithFallback(splits, default) - def onlyNewlinesWithoutFallback: Seq[Split] = - onlyNewlineSplits + def onlyNewlinesWithoutFallback: Seq[Split] = onlyNewlineSplits - @inline private def onlyNewlineSplits: Seq[Split] = - Decision.onlyNewlineSplits(splits) + @inline + private def onlyNewlineSplits: Seq[Split] = Decision.onlyNewlineSplits(splits) def withSplits(splits: Seq[Split]): Decision = copy(splits = splits) @@ -24,14 +24,15 @@ case class Decision(formatToken: FormatToken, splits: Seq[Split]) { object Decision { - @inline def noNewlineSplits(s: Seq[Split]): Seq[Split] = - filterNewlineSplits(s, false) + @inline + def noNewlineSplits(s: Seq[Split]): Seq[Split] = filterNewlineSplits(s, false) - @inline def onlyNewlineSplits(s: Seq[Split]): Seq[Split] = - filterNewlineSplits(s, true) + @inline + def onlyNewlineSplits(s: Seq[Split]): Seq[Split] = filterNewlineSplits(s, true) - @inline def filterNewlineSplits(s: Seq[Split], isNL: Boolean): Seq[Split] = - s.filter(_.isNL == isNL) + @inline + def filterNewlineSplits(s: Seq[Split], isNL: Boolean): Seq[Split] = s + .filter(_.isNL == isNL) def onlyNewlinesWithFallback(s: Seq[Split], fb: => Split): Seq[Split] = { val filtered = onlyNewlineSplits(s) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala index 9a617f8979..81a1b3a539 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala @@ -60,8 +60,7 @@ class FormatOps( private val usedTokens = tokens.head.left +: tokens.map(_.right) private[internal] val soft = new SoftKeywordClasses(dialect) - private[internal] val statementStarts = - getStatementStarts(topSourceTree, soft) + private[internal] val statementStarts = getStatementStarts(topSourceTree, soft) // Maps token to number of non-whitespace bytes before the token's position. private final val nonWhitespaceOffset: Map[T, Int] = { val resultB = Map.newBuilder[T, Int] @@ -91,14 +90,13 @@ class FormatOps( val (argumentStarts, optionalNewlines) = { val arguments = mutable.Map.empty[TokenHash, Tree] val optional = Set.newBuilder[TokenHash] - def getHeadHash(tree: Tree): Option[TokenHash] = - tokens.getHeadOpt(tree).map(x => hash(x.left)) - def add(tree: Tree): Unit = - getHeadHash(tree).foreach { x => - if (!arguments.contains(x)) arguments += x -> tree - } - def addOptional(tree: Tree): Unit = - getHeadHash(tree).foreach { optional += _ } + def getHeadHash(tree: Tree): Option[TokenHash] = tokens.getHeadOpt(tree) + .map(x => hash(x.left)) + def add(tree: Tree): Unit = getHeadHash(tree).foreach { x => + if (!arguments.contains(x)) arguments += x -> tree + } + def addOptional(tree: Tree): Unit = getHeadHash(tree) + .foreach { optional += _ } val queue = new mutable.ListBuffer[Seq[Tree]] queue += topSourceTree :: Nil @@ -125,9 +123,7 @@ class FormatOps( @inline final def findFirst(start: FormatToken, end: T)( f: FormatToken => Boolean - ): Option[FormatToken] = { - findFirst(start, end.end)(f) - } + ): Option[FormatToken] = { findFirst(start, end.end)(f) } @tailrec final def findFirst(start: FormatToken, end: Int)( @@ -137,35 +133,30 @@ class FormatOps( else if (f(start)) Some(start) else { val next_ = next(start) - if (next_ == start) None - else findFirst(next_, end)(f) + if (next_ == start) None else findFirst(next_, end)(f) } } def findFirstOnRight[A](start: FormatToken, end: T)(implicit classifier: Classifier[T, A] - ): Option[T] = - findFirst(start, end.start)(x => classifier(x.right)).map(_.right) + ): Option[T] = findFirst(start, end.start)(x => classifier(x.right)) + .map(_.right) - final def rhsOptimalToken( - start: FormatToken, - end: Int = Int.MaxValue - ): T = + final def rhsOptimalToken(start: FormatToken, end: Int = Int.MaxValue): T = findTokenWith(start, next) { start => start.right match { case t if t.end >= end => Some(start.left) case _ if start.hasBlankLine => Some(start.left) case _: T.RightParen - if start.left.is[T.RightParen] || start.left.is[T.LeftParen] => - None + if start.left.is[T.RightParen] || start.left.is[T.LeftParen] => None case _: T.RightBracket if start.left.is[T.RightBracket] => None case _: T.Comma | _: T.LeftParen | _: T.Semicolon | _: T.RightArrow | _: T.Equals if isInfixRhs(start) || !startsNewBlockOnRight(start) => None case c: T.Comment - if start.noBreak && (!start.left.is[T.LeftParen] || - tokens.isBreakAfterRight(start)) => - Some(c) + if start.noBreak && + (!start.left.is[T.LeftParen] || + tokens.isBreakAfterRight(start)) => Some(c) case _ => Some(start.left) } }.fold(_.right, identity) @@ -177,8 +168,7 @@ class FormatOps( lazy val isInfix = isInfixRhs(start) val endFound = start.right match { case _: T.Comma | _: T.LeftParen | _: T.Semicolon | _: T.RightArrow | - _: T.Equals => - None + _: T.Equals => None case _: T.RightParen if start.left.is[T.LeftParen] => None case c: T.Comment if start.noBreak && tokens.isBreakAfterRight(start) => Some(c) @@ -197,13 +187,13 @@ class FormatOps( final def isInfixRhs(ft: FormatToken): Boolean = { val tree = ft.meta.rightOwner - @inline def checkToken = tokens.tokenJustBeforeOpt(tree).contains(ft) + @inline + def checkToken = tokens.tokenJustBeforeOpt(tree).contains(ft) tree.parent.exists { - case ia: Member.Infix => - (ia.op eq tree) || (ia.arg eq tree) && + case ia: Member.Infix => (ia.op eq tree) || (ia.arg eq tree) && (ft.right.is[T.LeftParen] || checkToken) - case t: Member.ArgClause => - t.parent.exists(_.is[Member.Infix]) && checkToken + case t: Member.ArgClause => t.parent.exists(_.is[Member.Infix]) && + checkToken case _ => false } } @@ -219,65 +209,57 @@ class FormatOps( * Context: https://github.com/scalameta/scalafmt/issues/108 */ def isJsNative(body: Tree): Boolean = - initStyle.newlines.neverBeforeJsNative && (body match { - case Term.Select(Term.Name("js"), Term.Name("native")) => true - case _ => false - }) + initStyle.newlines.neverBeforeJsNative && + (body match { + case Term.Select(Term.Name("js"), Term.Name("native")) => true + case _ => false + }) @inline final def startsStatement(tok: FormatToken): Option[Tree] = startsStatement(tok.right) @inline - final def startsStatement(token: T): Option[Tree] = - statementStarts.get(hash(token)) + final def startsStatement(token: T): Option[Tree] = statementStarts + .get(hash(token)) val StartsStatementRight = new ExtractFromMeta[Tree](startsStatement) - def parensTuple(token: T): TokenRanges = - matchingOpt(token).fold(TokenRanges.empty) { other => - TokenRanges(TokenRange(token, other)) - } + def parensTuple(token: T): TokenRanges = matchingOpt(token) + .fold(TokenRanges.empty) { other => TokenRanges(TokenRange(token, other)) } def insideBlock[A](start: FormatToken, end: T)(implicit classifier: Classifier[T, A] - ): TokenRanges = - insideBlock(start, end, x => classifier(x.left)) + ): TokenRanges = insideBlock(start, end, x => classifier(x.left)) def insideBlock( start: FormatToken, end: T, matches: FormatToken => Boolean - ): TokenRanges = - insideBlock { x => - if (matches(x)) matchingOpt(x.left) else None - }(start, end) + ): TokenRanges = insideBlock { x => + if (matches(x)) matchingOpt(x.left) else None + }(start, end) - def insideBracesBlock( - start: FormatToken, - end: T, - parensToo: Boolean = false - )(implicit style: ScalafmtConfig): TokenRanges = - insideBlock(x => getEndOfBlock(x, parensToo))(start, end) + def insideBracesBlock(start: FormatToken, end: T, parensToo: Boolean = false)( + implicit style: ScalafmtConfig + ): TokenRanges = insideBlock(x => getEndOfBlock(x, parensToo))(start, end) - def insideBlock(matches: FormatToken => Option[T])( - start: FormatToken, - end: T - ): TokenRanges = { + def insideBlock( + matches: FormatToken => Option[T] + )(start: FormatToken, end: T): TokenRanges = { var result = TokenRanges.empty @tailrec - def run(tok: FormatToken): Unit = - if (tok.left.start < end.start) { - val nextTokOpt = matches(tok).flatMap { close => - val open = tok.left - if (open.start >= close.end) None - else { - result = result.append(TokenRange(open, close)) - Some(tokens(close)) - } + def run(tok: FormatToken): Unit = if (tok.left.start < end.start) { + val nextTokOpt = matches(tok).flatMap { close => + val open = tok.left + if (open.start >= close.end) None + else { + result = result.append(TokenRange(open, close)) + Some(tokens(close)) } - val nextTok = nextTokOpt.getOrElse(next(tok)) - if (nextTok ne tok) run(nextTok) } + val nextTok = nextTokOpt.getOrElse(next(tok)) + if (nextTok ne tok) run(nextTok) + } run(next(start)) result @@ -289,26 +271,23 @@ class FormatOps( def alt = getLastToken(t) t match { case _: Term.ParamClause | _: Type.FuncParamClause | - _: Member.ParamClauseGroup => - t.parent match { + _: Member.ParamClauseGroup => t.parent match { case Some(p) => defnSiteLastToken(close, p) case _ => alt } - case t: Defn.Def => - tokens.getHeadOpt(t.body).fold(alt) { ft => + case t: Defn.Def => tokens.getHeadOpt(t.body).fold(alt) { ft => if (ft.left.is[T.LeftBrace] && t.body.is[Term.Block]) ft.left else prevNonCommentBefore(ft).left } - case _: Ctor.Primary => - close match { + case _: Ctor.Primary => close match { // This is a terrible terrible hack. Please consider removing this. // The RightParen() LeftBrace() pair is presumably a ") {" combination // at a class definition case FormatToken(_: T.RightParen, b: T.LeftBrace, _) => b case _ => close.left } - case t => - t.tokens.find(x => x.is[T.Equals] && owners(x) == t).getOrElse(alt) + case t => t.tokens.find(x => x.is[T.Equals] && owners(x) == t) + .getOrElse(alt) } } @@ -320,8 +299,7 @@ class FormatOps( val pf = if (style.poorMansTrailingCommasInConfigStyle) splitOneArgPerLineBeforeComma(owner) - else - splitOneArgPerLineAfterComma(owner) + else splitOneArgPerLineAfterComma(owner) Policy.before(close)(pf) } @@ -332,8 +310,7 @@ class FormatOps( splits.map(x => if (x.modExt.mod ne NoSplit) x else x.withMod(Newline)) case Decision(t @ FormatToken(_: T.Comma, right, _), splits) - if owner == t.meta.leftOwner && - !right.is[T.LeftBrace] && + if owner == t.meta.leftOwner && !right.is[T.LeftBrace] && // If comment is bound to comma, see unit/Comment. (!right.is[T.Comment] || t.hasBreak) => val isNewline = right.is[T.Comment] @@ -368,8 +345,8 @@ class FormatOps( ): Policy = { val policy = Policy.before(to) { case Decision(FormatToken(l, _, m), s) => val nonBoolPenalty = if (isBoolOperator(l)) 0 else 5 - val penalty = nestedSelect(m.leftOwner) + - nestedApplies(m.rightOwner) + nonBoolPenalty + val penalty = nestedSelect(m.leftOwner) + nestedApplies(m.rightOwner) + + nonBoolPenalty s.map { x => if (x.isNL) x.withPenalty(penalty) else x } } new Policy.Delay(policy, Policy.End.Before(from)) @@ -392,23 +369,22 @@ class FormatOps( def templateCurlyFt(template: Template): Option[FormatToken] = getStartOfTemplateBody(template).map(tokenBefore) - def templateCurly(template: Template): Option[T] = - templateCurlyFt(template).map(_.left) + def templateCurly(template: Template): Option[T] = templateCurlyFt(template) + .map(_.left) def templateCurlyOrLastNonTrivial(template: Template): T = templateCurly(template).getOrElse(getLastNonTrivialToken(template)) - def templateDerivesOrCurlyOrLastNonTrivial( - template: Template - )(implicit ft: FormatToken): T = - findTemplateGroupOnRight(_.getExpireToken)(template) - .getOrElse(templateCurlyOrLastNonTrivial(template)) + def templateDerivesOrCurlyOrLastNonTrivial(template: Template)(implicit + ft: FormatToken + ): T = findTemplateGroupOnRight(_.getExpireToken)(template) + .getOrElse(templateCurlyOrLastNonTrivial(template)) private def findTreeInGroup[A]( trees: Seq[Tree], func: TemplateSupertypeGroup => A - )(expireFunc: Seq[Tree] => T)(implicit ft: FormatToken): Option[A] = - trees.find(_.pos.end >= ft.right.end).map { x => + )(expireFunc: Seq[Tree] => T)(implicit ft: FormatToken): Option[A] = trees + .find(_.pos.end >= ft.right.end).map { x => func(TemplateSupertypeGroup(x, trees, expireFunc)) } @@ -431,12 +407,12 @@ class FormatOps( } @inline - def getBreakBeforeElsePolicy(term: Term.If): Policy = - getElseChain(term, Nil).foldLeft(Policy.noPolicy) { case (res, els) => - val policy = Policy.on(els) { - case d @ Decision(FormatToken(_, `els`, _), _) => + def getBreakBeforeElsePolicy(term: Term.If): Policy = getElseChain(term, Nil) + .foldLeft(Policy.noPolicy) { case (res, els) => + val policy = Policy + .on(els) { case d @ Decision(FormatToken(_, `els`, _), _) => d.onlyNewlinesWithFallback(Split(Newline, 0)) - } + } Policy.Relay(policy, res) } @@ -448,8 +424,7 @@ class FormatOps( val newRes = beforeElsep.left match { case els: T.KwElse if initStyle.newlines.alwaysBeforeElseAfterCurlyIf || - !prev(beforeElsep).left.is[T.RightBrace] => - els +: res + !prev(beforeElsep).left.is[T.RightBrace] => els +: res case _ => res } term.elsep match { @@ -463,56 +438,52 @@ class FormatOps( } } - def getOptimalTokenFor(token: T): T = - getOptimalTokenFor(tokens(token)) + def getOptimalTokenFor(token: T): T = getOptimalTokenFor(tokens(token)) def getOptimalTokenFor(ft: FormatToken): T = if (tokens.isAttachedCommentThenBreak(ft)) ft.right else ft.left - def insideInfixSplit( - app: Member.Infix, - ft: FormatToken - )(implicit style: ScalafmtConfig): Seq[Split] = - app match { - case t: Type.ApplyInfix - if style.spaces.neverAroundInfixTypes.contains(t.op.value) => - Seq(Split(NoSplit, 0)) - case t => - val isBeforeOp = ft.meta.leftOwner ne app.op - def useSpace = style.spaces.beforeInfixArgInParens(app.op.value) || - (app.arg match { - case _: Lit.Unit => false - case x: Member.ArgClause if x.values.lengthCompare(1) != 0 => false - case x => !isEnclosedInParens(x) - }) - val afterInfix = style.breakAfterInfix(t) - if (isBeforeOp && isFewerBracesLhs(app.lhs)) Seq(Split(Newline, 0)) - else if (afterInfix ne Newlines.AfterInfix.keep) { - if (isBeforeOp) Seq(Split(Space, 0)) - else { - val spaceMod = Space(useSpace) - val fullInfix = InfixSplits.findEnclosingInfix(app) - val ok = isEnclosedInParens(fullInfix) || fullInfix.parent.forall { - case t: Defn.Val => t.rhs eq fullInfix - case t: Defn.Var => t.body eq fullInfix - case _ => true - } - if (ok) - InfixSplits(app, ft, fullInfix) - .getBeforeLhsOrRhs(afterInfix, spaceMod = spaceMod) - else Seq(Split(spaceMod, 0)) + def insideInfixSplit(app: Member.Infix, ft: FormatToken)(implicit + style: ScalafmtConfig + ): Seq[Split] = app match { + case t: Type.ApplyInfix + if style.spaces.neverAroundInfixTypes.contains(t.op.value) => + Seq(Split(NoSplit, 0)) + case t => + val isBeforeOp = ft.meta.leftOwner ne app.op + def useSpace = style.spaces.beforeInfixArgInParens(app.op.value) || + (app.arg match { + case _: Lit.Unit => false + case x: Member.ArgClause if x.values.lengthCompare(1) != 0 => false + case x => !isEnclosedInParens(x) + }) + val afterInfix = style.breakAfterInfix(t) + if (isBeforeOp && isFewerBracesLhs(app.lhs)) Seq(Split(Newline, 0)) + else if (afterInfix ne Newlines.AfterInfix.keep) { + if (isBeforeOp) Seq(Split(Space, 0)) + else { + val spaceMod = Space(useSpace) + val fullInfix = InfixSplits.findEnclosingInfix(app) + val ok = isEnclosedInParens(fullInfix) || fullInfix.parent.forall { + case t: Defn.Val => t.rhs eq fullInfix + case t: Defn.Var => t.body eq fullInfix + case _ => true } - } else { - // we don't modify line breaks generally around infix expressions - // TODO: if that ever changes, modify how rewrite rules handle infix - val mod = getMod(ft) - val modOrNoSplit = - if (mod != Space || isBeforeOp || useSpace) mod else NoSplit - val split = Split(modOrNoSplit, 0) - if (isBeforeOp && isFewerBracesRhs(app.arg)) Seq(split) - else Seq(InfixSplits.withNLIndent(split)(app, ft)) + if (ok) InfixSplits(app, ft, fullInfix) + .getBeforeLhsOrRhs(afterInfix, spaceMod = spaceMod) + else Seq(Split(spaceMod, 0)) } - } + } else { + // we don't modify line breaks generally around infix expressions + // TODO: if that ever changes, modify how rewrite rules handle infix + val mod = getMod(ft) + val modOrNoSplit = + if (mod != Space || isBeforeOp || useSpace) mod else NoSplit + val split = Split(modOrNoSplit, 0) + if (isBeforeOp && isFewerBracesRhs(app.arg)) Seq(split) + else Seq(InfixSplits.withNLIndent(split)(app, ft)) + } + } def getInfixSplitsBeforeLhs( lhsApp: Member.Infix, @@ -520,8 +491,7 @@ class FormatOps( afterInfix: Newlines.AfterInfix, newStmtMod: Option[Modification] = None )(implicit style: ScalafmtConfig): Seq[Split] = { - val fullInfixTreeOpt = - findTreeWithParentSimple(lhsApp, false)(isInfixApp) + val fullInfixTreeOpt = findTreeWithParentSimple(lhsApp, false)(isInfixApp) val fullInfix = fullInfixTreeOpt.flatMap(asInfixApp).getOrElse(lhsApp) val app = findLeftInfix(fullInfix) new InfixSplits(app, ft, fullInfix, app) @@ -531,9 +501,7 @@ class FormatOps( final def maybeGetInfixSplitsBeforeLhs( ft: FormatToken, mod: => Option[Modification] = None - )(nonInfixSplits: => Seq[Split])(implicit - style: ScalafmtConfig - ): Seq[Split] = { + )(nonInfixSplits: => Seq[Split])(implicit style: ScalafmtConfig): Seq[Split] = { val tree = ft.meta.rightOwner val ai = style.breakAfterInfix(tree) val app = if (ai eq Newlines.AfterInfix.keep) None else asInfixApp(tree) @@ -544,8 +512,7 @@ class FormatOps( def apply(app: Member.Infix, ft: FormatToken)(implicit style: ScalafmtConfig - ): InfixSplits = - apply(app, ft, findEnclosingInfix(app)) + ): InfixSplits = apply(app, ft, findEnclosingInfix(app)) def apply(app: Member.Infix, ft: FormatToken, fullInfix: Member.Infix)( implicit style: ScalafmtConfig @@ -554,8 +521,8 @@ class FormatOps( new InfixSplits(app, ft, fullInfix, leftInfix) } - private def switch(splits: Seq[Split], triggers: T*): Seq[Split] = - splits.map { x => + private def switch(splits: Seq[Split], triggers: T*): Seq[Split] = splits + .map { x => triggers.foldLeft(x) { case (y, trigger) => y.switch(trigger, false) } } @@ -565,14 +532,11 @@ class FormatOps( childTree: Tree ): Member.Infix = if (isEnclosedInParens(childTree)) child - else - childTree.parent match { - case Some(p: Member.Infix) if !p.isAssignment => - findEnclosingInfix(p, p) - case Some(p @ Member.ArgClause(_ :: Nil)) => - findEnclosingInfix(child, p) - case _ => child - } + else childTree.parent match { + case Some(p: Member.Infix) if !p.isAssignment => findEnclosingInfix(p, p) + case Some(p @ Member.ArgClause(_ :: Nil)) => findEnclosingInfix(child, p) + case _ => child + } private[FormatOps] def findEnclosingInfix(app: Member.Infix): Member.Infix = findEnclosingInfix(app, app) @@ -616,11 +580,10 @@ class FormatOps( private val skipInfixIndent: Boolean = { @tailrec - def getLastPat(t: Tree): Tree = - t.parent match { - case Some(p @ (_: Pat | _: Pat.ArgClause)) => getLastPat(p) - case _ => t - } + def getLastPat(t: Tree): Tree = t.parent match { + case Some(p @ (_: Pat | _: Pat.ArgClause)) => getLastPat(p) + case _ => t + } def getChild = fullInfix match { case t: Pat => getLastPat(t) case t => t @@ -687,14 +650,13 @@ class FormatOps( val (nlIndent, nlPolicy) = { def policy(triggers: T*)(implicit fileLine: FileLine) = if (triggers.isEmpty) Policy.NoPolicy - else - Policy.on(fullExpire) { - case Decision(t: FormatToken, s) - if isInfixOp(t.meta.leftOwner) || - isInfixOp(t.meta.rightOwner) && - !t.meta.rightOwner.parent.exists(style.formatInfix(_)) => - InfixSplits.switch(s, triggers: _*) - } + else Policy.on(fullExpire) { + case Decision(t: FormatToken, s) + if isInfixOp(t.meta.leftOwner) || + isInfixOp(t.meta.rightOwner) && + !t.meta.rightOwner.parent.exists(style.formatInfix(_)) => + InfixSplits.switch(s, triggers: _*) + } val fullTok = getIndentTrigger(fullInfix) val noAssign = assignBodyExpire.isEmpty @@ -711,8 +673,8 @@ class FormatOps( } } - private def withNLIndent(split: Split): Split = - split.withIndent(nlIndent).andPolicy(nlPolicy) + private def withNLIndent(split: Split): Split = split.withIndent(nlIndent) + .andPolicy(nlPolicy) def getBeforeLhsOrRhs( afterInfix: Newlines.AfterInfix, @@ -760,9 +722,8 @@ class FormatOps( else if (end eq t) Some(decideNewlinesOnlyAfterToken(end.left)) else Some(decideNewlinesOnlyAfterClose(end.left)) } - val nlMod = newStmtMod.getOrElse { - Space.orNL(ft.noBreak && ft.right.is[T.Comment]) - } + val nlMod = newStmtMod + .getOrElse { Space.orNL(ft.noBreak && ft.right.is[T.Comment]) } val delayedBreak = if (nlMod.isNewline) None else breakAfterComment(ft) val (singleLineExpire, singleLineIndent) = { @@ -781,14 +742,10 @@ class FormatOps( else Some(getSingleLineInfixPolicy(fullExpire)) val nlSinglelineSplit = Split(nlMod, 0) .onlyIf(singleLinePolicy.isDefined && beforeLhs) - .withIndent(singleLineIndent) - .withSingleLine(singleLineExpire) - .andPolicyOpt(singleLinePolicy) - .andPolicyOpt(delayedBreak) - val spaceSingleLine = Split(spaceMod, 0) - .onlyIf(newStmtMod.isEmpty) - .withSingleLine(singleLineExpire) - .andPolicyOpt(singleLinePolicy) + .withIndent(singleLineIndent).withSingleLine(singleLineExpire) + .andPolicyOpt(singleLinePolicy).andPolicyOpt(delayedBreak) + val spaceSingleLine = Split(spaceMod, 0).onlyIf(newStmtMod.isEmpty) + .withSingleLine(singleLineExpire).andPolicyOpt(singleLinePolicy) val singleLineSplits = Seq( spaceSingleLine.onlyFor(SplitTag.InfixChainNoNL), spaceSingleLine.onlyIf(singleLinePolicy.isDefined), @@ -804,20 +761,16 @@ class FormatOps( val nextOp = if (!style.newlines.afterInfixBreakOnNested) None else if (beforeLhs) Some(app.op) - else - getInfixRhsAsInfix(app) match { - case Some(ia) => Some(findLeftInfix(ia).op) - case _ => findNextInfixInParent(app, fullInfix) - } + else getInfixRhsAsInfix(app) match { + case Some(ia) => Some(findLeftInfix(ia).op) + case _ => findNextInfixInParent(app, fullInfix) + } val endOfNextOp = nextOp.map(tokens.getLast) val breakAfterClose = endOfNextOp.flatMap(breakAfterComment) - val nlSplit = Split(nlMod, 0) - .andPolicyOpt(breakAfterClose) - .withIndent(nlIndent) - .withPolicy(nlPolicy) - val singleLineSplit = Split(spaceMod, 0) - .notIf(noSingleLine) + val nlSplit = Split(nlMod, 0).andPolicyOpt(breakAfterClose) + .withIndent(nlIndent).withPolicy(nlPolicy) + val singleLineSplit = Split(spaceMod, 0).notIf(noSingleLine) .withSingleLine(endOfNextOp.fold(close)(_.left)) .andPolicyOpt(breakAfterClose) .andPolicy(getSingleLineInfixPolicy(close)) @@ -844,11 +797,10 @@ class FormatOps( } - def getSingleLineInfixPolicy(end: T) = - Policy.on(end) { - case Decision(t: FormatToken, s) if isInfixOp(t.meta.leftOwner) => - SplitTag.InfixChainNoNL.activateOnly(s) - } + def getSingleLineInfixPolicy(end: T) = Policy.on(end) { + case Decision(t: FormatToken, s) if isInfixOp(t.meta.leftOwner) => + SplitTag.InfixChainNoNL.activateOnly(s) + } def getMidInfixToken(app: Member.Infix): T = { val opToken = app.op.tokens.head @@ -865,22 +817,19 @@ class FormatOps( fullTree: Tree, tree: Tree, res: mutable.Buffer[Member.Infix] - ): Unit = if (tree ne fullTree) - tree.parent match { - case Some(ia: Member.Infix) => - if (ia.lhs eq tree) { - res += ia - findNestedInfixes(ia.arg, res) - } - findNextInfixes(fullTree, ia, res) - case Some(p: Member.ArgClause) => - p.parent match { - case Some(pp: Member.Infix) => - findNextInfixes(fullTree, pp, res) - case _ => - } - case _ => - } + ): Unit = if (tree ne fullTree) tree.parent match { + case Some(ia: Member.Infix) => + if (ia.lhs eq tree) { + res += ia + findNestedInfixes(ia.arg, res) + } + findNextInfixes(fullTree, ia, res) + case Some(p: Member.ArgClause) => p.parent match { + case Some(pp: Member.Infix) => findNextInfixes(fullTree, pp, res) + case _ => + } + case _ => + } private def findNestedInfixes( tree: Tree, @@ -896,12 +845,10 @@ class FormatOps( } @tailrec - final def findLeftInfix(app: Member.Infix): Member.Infix = - app.lhs match { - case t: Member.Infix if !isEnclosedInParens(t) => - findLeftInfix(t) - case _ => app - } + final def findLeftInfix(app: Member.Infix): Member.Infix = app.lhs match { + case t: Member.Infix if !isEnclosedInParens(t) => findLeftInfix(t) + case _ => app + } private def getInfixRhsAsInfix(app: Member.Infix): Option[Member.Infix] = app.singleArg match { @@ -916,20 +863,17 @@ class FormatOps( while (queue.nonEmpty) { val elem = queue.dequeue() val elemPrecedence = elem.precedence - if (maxPrecedence < elemPrecedence) - maxPrecedence = elemPrecedence + if (maxPrecedence < elemPrecedence) maxPrecedence = elemPrecedence queue ++= elem.nestedInfixApps.filter(x => !isEnclosedInParens(x)) } maxPrecedence } - def functionExpire(function: Term.FunctionTerm): (T, ExpiresOn) = - function.parent match { - case Some(SingleArgInBraces.OrBlock(_, _, e)) => - e.left -> ExpiresOn.Before - case _ => - tokens.getLastExceptParen(function).left -> ExpiresOn.After - } + def functionExpire(function: Term.FunctionTerm): (T, ExpiresOn) = function + .parent match { + case Some(SingleArgInBraces.OrBlock(_, _, e)) => e.left -> ExpiresOn.Before + case _ => tokens.getLastExceptParen(function).left -> ExpiresOn.After + } def noOptimizationZones(): Set[T] = { val result = Set.newBuilder[T] @@ -942,14 +886,12 @@ class FormatOps( case lo: Term.ArgClause => !lo.parent.exists(_.is[Term.ApplyInfix]) case _: Term.Apply => true // legacy: when enclosed in parens case _ => false - }) => - expire = matching(t) + }) => expire = matching(t) case FormatToken(t: T.LeftBrace, _, m) if (m.leftOwner match { // Type compounds can be inside defn.defs case _: Type.Refine => true case _ => false - }) => - expire = matching(t) + }) => expire = matching(t) case _ => } result.result() @@ -968,32 +910,31 @@ class FormatOps( beforeCloseFt: => FormatToken, allowForce: => Boolean = true )(implicit style: ScalafmtConfig): Boolean = { - def opensImplicit = (next(ft).hasBreak || - style.newlines.forceAfterImplicitParamListModifier) && - opensConfigStyleImplicitParamList(ft) + def opensImplicit = + (next(ft).hasBreak || + style.newlines.forceAfterImplicitParamListModifier) && + opensConfigStyleImplicitParamList(ft) val opensConfigStyle = !style.newlines.sourceIgnored && // classic (ft.hasBreak || opensImplicit) && beforeCloseFt.hasBreak opensConfigStyle || allowForce && forceConfigStyle(hash(ft.left)) } /** Works for `using` as well */ - def opensConfigStyleImplicitParamList( - formatToken: FormatToken - )(implicit style: ScalafmtConfig): Boolean = - soft.ImplicitOrUsing.unapply(formatToken.right) && - style.newlines.notBeforeImplicitParamListModifier && - hasImplicitParamList(formatToken.meta.rightOwner) + def opensConfigStyleImplicitParamList(formatToken: FormatToken)(implicit + style: ScalafmtConfig + ): Boolean = soft.ImplicitOrUsing.unapply(formatToken.right) && + style.newlines.notBeforeImplicitParamListModifier && + hasImplicitParamList(formatToken.meta.rightOwner) val ImplicitUsingOnLeft = new ExtractFromMeta(ft => getImplicitParamList(ft.meta.leftOwner)) def isSingleIdentifierAnnotation(tok: FormatToken): Boolean = { - val toMatch = if (tok.right.is[T.RightParen]) { - // Hack to allow any annotations with arguments like @foo(1) - tokens(matching(tok.right), -2) - } else { - tok - } + val toMatch = + if (tok.right.is[T.RightParen]) { + // Hack to allow any annotations with arguments like @foo(1) + tokens(matching(tok.right), -2) + } else { tok } toMatch match { case FormatToken(T.At(), _: T.Ident, _) => true case _ => false @@ -1028,22 +969,19 @@ class FormatOps( val indent = if (!x.isSecond) Indent.Empty else Indent(Num(indentIfSecond), expire, ExpiresOn.After) - def nlSplit(cost: Int) = - Split(Newline, cost).withPolicy(getPolicy(expire)).withIndent(indent) + def nlSplit(cost: Int) = Split(Newline, cost) + .withPolicy(getPolicy(expire)).withIndent(indent) if (!style.binPack.keepParentConstructors) Seq(Split(Space, 0).withIndent(indent), nlSplit(1)) - else if (ft.hasBreak) - Seq(nlSplit(0)) + else if (ft.hasBreak) Seq(nlSplit(0)) else { val slbEnd = getLastToken(x.superType) Seq( - Split(Space, 0) - .withIndent(indent) - .withSingleLine( - slbEnd, - exclude = insideBlock[T.LeftParen](ft, slbEnd), - noSyntaxNL = true - ), + Split(Space, 0).withIndent(indent).withSingleLine( + slbEnd, + exclude = insideBlock[T.LeftParen](ft, slbEnd), + noSyntaxNL = true + ), nlSplit(1) ) } @@ -1052,21 +990,19 @@ class FormatOps( } } - def ctorWithChain( - ownerSet: Set[Tree], - lastToken: T - )(implicit style: ScalafmtConfig): Policy = + def ctorWithChain(ownerSet: Set[Tree], lastToken: T)(implicit + style: ScalafmtConfig + ): Policy = if (style.binPack.parentConstructors eq BinPack.ParentCtors.Always) NoPolicy else if (ownerSet.isEmpty) NoPolicy - else - Policy.after(lastToken) { - case d @ Decision(t @ FormatToken(_, _: T.KwWith, _), _) - if ownerSet.contains(t.meta.rightOwner) => - d.onlyNewlinesWithoutFallback - case d @ Decision(t @ FormatToken(T.Comma(), _, _), _) - if ownerSet.contains(t.meta.leftOwner) => - d.onlyNewlinesWithoutFallback - } + else Policy.after(lastToken) { + case d @ Decision(t @ FormatToken(_, _: T.KwWith, _), _) + if ownerSet.contains(t.meta.rightOwner) => + d.onlyNewlinesWithoutFallback + case d @ Decision(t @ FormatToken(T.Comma(), _, _), _) + if ownerSet.contains(t.meta.leftOwner) => + d.onlyNewlinesWithoutFallback + } def binPackParentConstructorSplits( isFirstCtor: Boolean, @@ -1085,18 +1021,15 @@ class FormatOps( if (!isFirstCtor) Indent.Empty else Indent(Num(indentLen), lastToken, ExpiresOn.After) if (style.binPack.keepParentConstructors) { - if (ft.hasBreak) - Seq(Split(nlMod, 0).withIndent(indent)) + if (ft.hasBreak) Seq(Split(nlMod, 0).withIndent(indent)) else { val slbEnd = rhs.fold(lastToken)(getLastToken) Seq( - Split(Space, 0) - .withIndent(indent) - .withSingleLine( - slbEnd, - exclude = insideBracesBlock(ft, slbEnd, true), - noSyntaxNL = extendsThenWith - ), + Split(Space, 0).withIndent(indent).withSingleLine( + slbEnd, + exclude = insideBracesBlock(ft, slbEnd, true), + noSyntaxNL = extendsThenWith + ), Split(nlMod, 1).withIndent(indent) ) } @@ -1108,8 +1041,7 @@ class FormatOps( Left(SplitTag.OnelineWithChain) case BinPack.ParentCtors.Always | BinPack.ParentCtors.Never => Right(false) - case _ => - Right(style.newlines.source eq Newlines.fold) + case _ => Right(style.newlines.source eq Newlines.fold) } val exclude = style.binPack.parentConstructors match { case BinPack.ParentCtors.Always @@ -1122,10 +1054,8 @@ class FormatOps( Seq( Split(Space, 0) .withSingleLine(lastToken, exclude = exclude, noSyntaxNL = noSyntaxNL) - .orPolicy(pnlPolicy) - .withIndent(indent), - Split(nlMod, 0) - .onlyIf(nlOnelineTag != Right(false)) + .orPolicy(pnlPolicy).withIndent(indent), + Split(nlMod, 0).onlyIf(nlOnelineTag != Right(false)) .preActivateFor(nlOnelineTag.left.toOption) .withSingleLine(lastToken, noSyntaxNL = noSyntaxNL) .withIndent(indent), @@ -1136,8 +1066,7 @@ class FormatOps( def getForceConfigStyle: (Set[TokenHash], Set[TokenHash]) = { val maxDistance = runner.optimizer.forceConfigStyleMinSpan - if (maxDistance < 0) - (Set.empty, Set.empty) + if (maxDistance < 0) (Set.empty, Set.empty) else { val clearQueues = Set.newBuilder[TokenHash] val forces = Set.newBuilder[TokenHash] @@ -1148,21 +1077,17 @@ class FormatOps( distance(open, close) > maxDistance ) { forces += hash(open) - args.foreach { arg => - clearQueues += hash(getHeadToken(arg)) - } + args.foreach { arg => clearQueues += hash(getHeadToken(arg)) } } tokens.foreach { - case FormatToken(left: T.LeftParen, _, meta) => - meta.leftOwner match { + case FormatToken(left: T.LeftParen, _, meta) => meta.leftOwner match { case t: Term.ArgClause if !t.parent.exists(_.is[Term.ApplyInfix]) => matchingOpt(left).foreach(process(t.values, left, _)) case _ => } - case FormatToken(left: T.LeftBracket, _, meta) => - meta.leftOwner match { - case t: Type.ArgClause => - matchingOpt(left).foreach(process(t.values, left, _)) + case FormatToken(left: T.LeftBracket, _, meta) => meta.leftOwner match { + case t: Type.ArgClause => matchingOpt(left) + .foreach(process(t.values, left, _)) case _ => } case _ => @@ -1191,14 +1116,13 @@ class FormatOps( if (tparams.isEmpty) params else tparams :: params } val allClauses = lpOwner match { - case ParamClauseParent(p) => - p match { - case t: Tree.WithParamClauseGroups => - t.paramClauseGroups.flatMap(getClausesFromClauseGroup) - case t: Tree.WithParamClauseGroup => - t.paramClauseGroup.map(getClausesFromClauseGroup).getOrElse(Nil) - case t: Stat.WithCtor with Tree.WithTParamClause => - t.tparamClause +: t.ctor.paramClauses + case ParamClauseParent(p) => p match { + case t: Tree.WithParamClauseGroups => t.paramClauseGroups + .flatMap(getClausesFromClauseGroup) + case t: Tree.WithParamClauseGroup => t.paramClauseGroup + .map(getClausesFromClauseGroup).getOrElse(Nil) + case t: Stat.WithCtor with Tree.WithTParamClause => t.tparamClause +: + t.ctor.paramClauses case t: Tree.WithParamClauses => t.paramClauses case t: Stat.WithCtor => t.ctor.paramClauses case t: Tree.WithTParamClause => t.tparamClause :: Nil @@ -1219,8 +1143,7 @@ class FormatOps( // Since classes and defs aren't the same (see below), we need to // create two (2) OneArgOneLineSplit when dealing with classes. One // deals with the type params and the other with the value params. - val oneLinePerArg = allOwners - .zip(close +: lastParens) + val oneLinePerArg = allOwners.zip(close +: lastParens) .map { case (owner, end) => splitOneArgOneLine(end, owner) } .reduceRight(new Policy.Relay(_, _)) @@ -1246,8 +1169,7 @@ class FormatOps( case Decision(ftd @ FormatToken(soft.ImplicitOrUsing(), _, m), _) if style.newlines.forceAfterImplicitParamListModifier && !tokens.isRightCommentThenBreak(ftd) && - hasImplicitParamList(m.leftOwner) => - Seq(Split(Newline, 0)) + hasImplicitParamList(m.leftOwner) => Seq(Split(Newline, 0)) } // Our policy is a combination of OneArgLineSplit and a custom splitter @@ -1257,8 +1179,7 @@ class FormatOps( val firstIndent = if (r.is[T.RightParen]) // An empty param group Indent(indentSep, close, ExpiresOn.After) - else - Indent(indentParam, close, ExpiresOn.Before) + else Indent(indentParam, close, ExpiresOn.Before) def aboveArityThreshold = { val threshold = style.verticalMultiline.arityThreshold @@ -1275,8 +1196,7 @@ class FormatOps( val afterLastParen = tokens.before(lastParen).right if (afterLastParen.is[T.Colon]) afterLastParen else lastParen } - val slbSplit = Split(space, 0) - .withSingleLine(slbEnd, killOnFail = true) + val slbSplit = Split(space, 0).withSingleLine(slbEnd, killOnFail = true) .preActivateFor(SplitTag.VerticalMultilineSingleLine) if (isBracket) { @@ -1286,8 +1206,7 @@ class FormatOps( ss.filter(!_.isActiveFor(SplitTag.VerticalMultilineSingleLine)) } val noSplit = - if (allParenOwners.isEmpty) - Split(space, 0).withSingleLine(close) + if (allParenOwners.isEmpty) Split(space, 0).withSingleLine(close) else { val lpNext = tokens.getHead(allParenOwners.head) val lpNextLeft = lpNext.left @@ -1303,10 +1222,13 @@ class FormatOps( val rightIsImplicit = soft.ImplicitOrUsing.unapply(r) val implicitNL = rightIsImplicit && style.newlines.forceBeforeImplicitParamListModifier - val implicitParams = if (rightIsImplicit) { - getImplicitParamList(ft.meta.rightOwner).fold(Nil: List[Tree])(_.values) - } else Nil - val noSlb = implicitNL || aboveArityThreshold || ft.hasBreak && + val implicitParams = + if (rightIsImplicit) { + getImplicitParamList(ft.meta.rightOwner) + .fold(Nil: List[Tree])(_.values) + } else Nil + val noSlb = implicitNL || aboveArityThreshold || + ft.hasBreak && !style.newlines.sourceIgnored && style.optIn.configStyleArguments || implicitParams.nonEmpty && style.newlines.forceAfterImplicitParamListModifier @@ -1318,13 +1240,10 @@ class FormatOps( Seq( // If we can fit all in one block, make it so slbSplit.notIf(noSlb), - Split(space, 0, policy = policy) - .onlyIf(spaceImplicit) - .andPolicy( - decideNewlinesOnlyAfterClose(r), - tokens.isRightCommentThenBreak(next(ft)) - ) - .withIndent(firstIndent), + Split(space, 0, policy = policy).onlyIf(spaceImplicit).andPolicy( + decideNewlinesOnlyAfterClose(r), + tokens.isRightCommentThenBreak(next(ft)) + ).withIndent(firstIndent), // Otherwise split vertically Split(nlMod, 1, policy = policy).withIndent(firstIndent) ) @@ -1359,53 +1278,47 @@ class FormatOps( if (!ft.right.is[T.Comment] || isDone(ft)) ft else iter(ft) } - def getSpaceAndNewlineAfterCurlyLambda( - newlines: Int - )(implicit style: ScalafmtConfig): (Boolean, NewlineT) = - style.newlines.afterCurlyLambdaParams match { - case Newlines.AfterCurlyLambdaParams.squash => (true, Newline) - case Newlines.AfterCurlyLambdaParams.never => - val space = style.newlines.source match { - case Newlines.fold => true - case Newlines.unfold => false - case _ => newlines == 0 - } - (space, Newline) - case Newlines.AfterCurlyLambdaParams.always => (false, Newline2x) - case Newlines.AfterCurlyLambdaParams.preserve => - val noBlanks = newlines < 2 - val space = style.newlines.source match { - case Newlines.fold => noBlanks - case Newlines.unfold => false - case _ => newlines == 0 - } - (space, if (noBlanks) Newline else Newline2x) - } + def getSpaceAndNewlineAfterCurlyLambda(newlines: Int)(implicit + style: ScalafmtConfig + ): (Boolean, NewlineT) = style.newlines.afterCurlyLambdaParams match { + case Newlines.AfterCurlyLambdaParams.squash => (true, Newline) + case Newlines.AfterCurlyLambdaParams.never => + val space = style.newlines.source match { + case Newlines.fold => true + case Newlines.unfold => false + case _ => newlines == 0 + } + (space, Newline) + case Newlines.AfterCurlyLambdaParams.always => (false, Newline2x) + case Newlines.AfterCurlyLambdaParams.preserve => + val noBlanks = newlines < 2 + val space = style.newlines.source match { + case Newlines.fold => noBlanks + case Newlines.unfold => false + case _ => newlines == 0 + } + (space, if (noBlanks) Newline else Newline2x) + } - def getNoSplit( - ft: FormatToken, - spaceOk: Boolean - )(implicit style: ScalafmtConfig): Modification = - ft.right match { - case _: T.Comment => - val isDetachedSlc = ft.hasBreak && tokens.isBreakAfterRight(ft) - if (isDetachedSlc || ft.rightHasNewline) null else Space - case _ => - Space(style.spaces.inParentheses && spaceOk) - } + def getNoSplit(ft: FormatToken, spaceOk: Boolean)(implicit + style: ScalafmtConfig + ): Modification = ft.right match { + case _: T.Comment => + val isDetachedSlc = ft.hasBreak && tokens.isBreakAfterRight(ft) + if (isDetachedSlc || ft.rightHasNewline) null else Space + case _ => Space(style.spaces.inParentheses && spaceOk) + } // look for arrow before body, if any, else after params - def getFuncArrow(term: Term.FunctionTerm): Option[FormatToken] = - tokens - .tokenBeforeOpt(term.body) - .orElse(tokens.tokenAfterOpt(term.paramClause).map(getArrowAfter)) - .orElse { - findFirst(tokens.getHead(term), term.pos.end)(_.left.is[T.RightArrow]) - } + def getFuncArrow(term: Term.FunctionTerm): Option[FormatToken] = tokens + .tokenBeforeOpt(term.body) + .orElse(tokens.tokenAfterOpt(term.paramClause).map(getArrowAfter)).orElse { + findFirst(tokens.getHead(term), term.pos.end)(_.left.is[T.RightArrow]) + } // look for arrow before body, if any, else after cond/pat - def getCaseArrow(term: Case): FormatToken = - tokens.tokenBeforeOpt(term.body).getOrElse { + def getCaseArrow(term: Case): FormatToken = tokens.tokenBeforeOpt(term.body) + .getOrElse { getArrowAfter(tokens.tokenAfter(term.cond.getOrElse(term.pat))) } @@ -1419,24 +1332,23 @@ class FormatOps( else tokens.nextAfterNonComment(maybeArrow) } - def getArgs(owner: Tree, orNil: Boolean = false): Seq[Tree] = - owner match { - case _: Lit.Unit => Nil - case t: Term.Super => t.superp :: Nil - case Member.Tuple(v) => v - case Member.SyntaxValuesClause(v) => v - case t: Member.Function => t.paramClause.values - case _ if orNil => Nil - case t => - logger.debug( - s"""getApplyArgs: unknown tree - |Tree: ${log(t)} - |Parent: ${log(t.parent)} - |GrandParent: ${log(t.parent.flatMap(_.parent))} - |""".stripMargin - ) - throw UnexpectedTree[Member.SyntaxValuesClause](t) - } + def getArgs(owner: Tree, orNil: Boolean = false): Seq[Tree] = owner match { + case _: Lit.Unit => Nil + case t: Term.Super => t.superp :: Nil + case Member.Tuple(v) => v + case Member.SyntaxValuesClause(v) => v + case t: Member.Function => t.paramClause.values + case _ if orNil => Nil + case t => + logger.debug( + s"""getApplyArgs: unknown tree + |Tree: ${log(t)} + |Parent: ${log(t.parent)} + |GrandParent: ${log(t.parent.flatMap(_.parent))} + |""".stripMargin + ) + throw UnexpectedTree[Member.SyntaxValuesClause](t) + } @tailrec final def findPrevSelectAndApply( @@ -1444,10 +1356,10 @@ class FormatOps( enclosed: Boolean, applyTree: Option[Member.Apply] = None ): (Option[SelectLike], Option[Member.Apply]) = { - @inline def isEnclosed: Boolean = enclosed && isEnclosedInParens(tree) + @inline + def isEnclosed: Boolean = enclosed && isEnclosedInParens(tree) tree match { - case GetSelectLike(t) if !isEnclosed => - (Some(t), applyTree) + case GetSelectLike(t) if !isEnclosed => (Some(t), applyTree) case t: Member.Apply if !isEnclosed => findPrevSelectAndApply(t.fun, enclosed, applyTree.orElse(Some(t))) case Term.AnonymousFunction(body) if !enclosed => @@ -1459,8 +1371,7 @@ class FormatOps( def findPrevSelect( tree: SelectLike, enclosed: Boolean = true - ): Option[SelectLike] = - findPrevSelectAndApply(tree.qual, enclosed)._1 + ): Option[SelectLike] = findPrevSelectAndApply(tree.qual, enclosed)._1 @tailrec private def findLastApplyAndNextSelectEnclosed( @@ -1468,35 +1379,33 @@ class FormatOps( select: Option[SelectLike] = None ): (Tree, Option[SelectLike]) = if (isEnclosedInParens(tree)) (tree, select) - else - tree.parent match { - case Some(GetSelectLike(p)) => - findLastApplyAndNextSelectEnclosed(p.tree, select.orElse(Some(p))) - case Some(p: Member.Apply) if p.fun eq tree => - findLastApplyAndNextSelectEnclosed(p, select) - case _ => (tree, select) - } + else tree.parent match { + case Some(GetSelectLike(p)) => + findLastApplyAndNextSelectEnclosed(p.tree, select.orElse(Some(p))) + case Some(p: Member.Apply) if p.fun eq tree => + findLastApplyAndNextSelectEnclosed(p, select) + case _ => (tree, select) + } @tailrec private def findLastApplyAndNextSelectPastEnclosed( tree: Tree, select: Option[SelectLike] = None, prevEnclosed: Option[Tree] = None - ): (Tree, Option[SelectLike]) = - tree.parent match { - case Some(GetSelectLike(p)) => - findLastApplyAndNextSelectPastEnclosed(p.tree, select.orElse(Some(p))) - case Some(p: Member.Apply) if p.fun eq tree => - prevEnclosed match { - case Some(t) => (t, select) - case _ => - val nextEnclosed = Some(tree).filter(isEnclosedInParens) - findLastApplyAndNextSelectPastEnclosed(p, select, nextEnclosed) - } - case Some(p: Term.AnonymousFunction) => - findLastApplyAndNextSelectPastEnclosed(p, select, Some(p)) - case _ => (prevEnclosed.getOrElse(tree), select) - } + ): (Tree, Option[SelectLike]) = tree.parent match { + case Some(GetSelectLike(p)) => + findLastApplyAndNextSelectPastEnclosed(p.tree, select.orElse(Some(p))) + case Some(p: Member.Apply) if p.fun eq tree => + prevEnclosed match { + case Some(t) => (t, select) + case _ => + val nextEnclosed = Some(tree).filter(isEnclosedInParens) + findLastApplyAndNextSelectPastEnclosed(p, select, nextEnclosed) + } + case Some(p: Term.AnonymousFunction) => + findLastApplyAndNextSelectPastEnclosed(p, select, Some(p)) + case _ => (prevEnclosed.getOrElse(tree), select) + } final def findLastApplyAndNextSelect( tree: Tree, @@ -1516,15 +1425,15 @@ class FormatOps( def checkParent = thisTree.parent match { case `nextSelect` => style.includeNoParensInSelectChains case Some(p: Term.Apply) if getHeadToken(p.argClause).is[T.LeftBrace] => - style.includeCurlyBraceInSelectChains && - !nextSelect.contains(lastApply) // exclude short curly + style.includeCurlyBraceInSelectChains && !nextSelect.contains(lastApply) // exclude short curly case Some(p: Member.Apply) => p.fun eq thisTree case _ => false } - ok && (thisTree match { + ok && + (thisTree match { case _: Term.Match => // like select and apply in one - val hasBrace = - nextNonComment(tokens(thisSelectLike.nameToken)).right.is[T.LeftBrace] + val hasBrace = nextNonComment(tokens(thisSelectLike.nameToken)).right + .is[T.LeftBrace] !hasBrace || style.includeCurlyBraceInSelectChains && nextSelect.isDefined && !nextSelect.contains(lastApply) @@ -1538,31 +1447,25 @@ class FormatOps( prevSelect: Option[SelectLike], thisSelect: SelectLike, lastApply: Tree - )(implicit style: ScalafmtConfig): Boolean = - prevSelect match { - case None => false - case Some(p) - if canStartSelectChain(p, Some(thisSelect.tree), lastApply) => - true - case Some(p) => - val prevPrevSelect = findPrevSelect(p, style.encloseSelectChains) - inSelectChain(prevPrevSelect, p, lastApply) - } + )(implicit style: ScalafmtConfig): Boolean = prevSelect match { + case None => false + case Some(p) if canStartSelectChain(p, Some(thisSelect.tree), lastApply) => + true + case Some(p) => + val prevPrevSelect = findPrevSelect(p, style.encloseSelectChains) + inSelectChain(prevPrevSelect, p, lastApply) + } @tailrec - final def findXmlLastLineIndent(ft: FormatToken): Int = - ft.left match { - case _: T.Xml.Start => 0 - case t: T.Xml.Part => - TokenOps.getXmlLastLineIndent(t) match { - case Some(x) => x - case None => findXmlLastLineIndent(prev(ft)) - } - case t: T.Xml.SpliceEnd => - findXmlLastLineIndent(tokens(matching(t), -1)) - case _ => - findXmlLastLineIndent(prev(ft)) - } + final def findXmlLastLineIndent(ft: FormatToken): Int = ft.left match { + case _: T.Xml.Start => 0 + case t: T.Xml.Part => TokenOps.getXmlLastLineIndent(t) match { + case Some(x) => x + case None => findXmlLastLineIndent(prev(ft)) + } + case t: T.Xml.SpliceEnd => findXmlLastLineIndent(tokens(matching(t), -1)) + case _ => findXmlLastLineIndent(prev(ft)) + } def withIndentOnXmlStart(tok: T.Xml.Start, splits: Seq[Split])(implicit style: ScalafmtConfig @@ -1628,19 +1531,18 @@ class FormatOps( def getFoldedPolicy( body: Tree, policy: Policy = Policy.NoPolicy - ): Policy = - body match { - case t: Member.Apply if t.fun ne body => - val opens = getNestedOpens(t.argClause, Nil) - getFoldedPolicy(t.fun, getNestedOpensPolicy(opens, policy)) - case t: Init => - val opens = t.argClauses.foldLeft(List.empty[FormatToken]) { - case (res, x) => getNestedOpens(x, res) - } - getNestedOpensPolicy(opens, policy) - case t: Term.Select => getFoldedPolicy(t.qual, policy) - case _ => policy - } + ): Policy = body match { + case t: Member.Apply if t.fun ne body => + val opens = getNestedOpens(t.argClause, Nil) + getFoldedPolicy(t.fun, getNestedOpensPolicy(opens, policy)) + case t: Init => + val opens = t.argClauses.foldLeft(List.empty[FormatToken]) { + case (res, x) => getNestedOpens(x, res) + } + getNestedOpensPolicy(opens, policy) + case t: Term.Select => getFoldedPolicy(t.qual, policy) + case _ => policy + } } @@ -1660,46 +1562,39 @@ class FormatOps( def getNlSplit(penalty: Int)(implicit fileLine: FileLine): Split = { nlSplitFunc(1).andPolicy(penalize(penalty)).forThisLine(nextLine) } - def getSplits(spaceSplit: Split) = - ( - spaceSplit.withIndents(spaceIndents), - getNlSplit(1)(nextLine(spaceSplit.fileLine)) - ) + def getSplits(spaceSplit: Split) = ( + spaceSplit.withIndents(spaceIndents), + getNlSplit(1)(nextLine(spaceSplit.fileLine)) + ) def getSlb(end: T, excl: TokenRanges)(implicit fileLine: FileLine) = SingleLineBlock(end, exclude = excl, noSyntaxNL = true) def getSlbSplit( end: T, exclude: TokenRanges = TokenRanges.empty, policy: Policy = Policy.NoPolicy - )(implicit fileLine: FileLine) = - Split(Space, 0) - .withPolicy(policy | getSlb(end, exclude)) - .withOptimalToken(end, ignore = blast.start > end.start) - def getSpaceSplit( - penalty: Int, - policy: Policy = Policy.NoPolicy - )(implicit fileLine: FileLine) = { + )(implicit fileLine: FileLine) = Split(Space, 0) + .withPolicy(policy | getSlb(end, exclude)) + .withOptimalToken(end, ignore = blast.start > end.start) + def getSpaceSplit(penalty: Int, policy: Policy = Policy.NoPolicy)(implicit + fileLine: FileLine + ) = { val spacePolicy = policy | penalize(penalty) Split(Space, 0).withPolicy(spacePolicy).withOptimalToken(blast) } - def getPolicySplits( - penalty: Int, - policy: Policy - )(implicit fileLine: FileLine) = - getSplits(getSpaceSplit(penalty, policy)) + def getPolicySplits(penalty: Int, policy: Policy)(implicit + fileLine: FileLine + ) = getSplits(getSpaceSplit(penalty, policy)) def getSlbSplits( exclude: TokenRanges = TokenRanges.empty, policy: Policy = Policy.NoPolicy - )(implicit fileLine: FileLine) = - ( - getSlbSplit(expire, exclude, policy), - getNlSplit(if (policy.isEmpty) 0 else 1) - ) + )(implicit fileLine: FileLine) = ( + getSlbSplit(expire, exclude, policy), + getNlSplit(if (policy.isEmpty) 0 else 1) + ) def hasStateColumn = spaceIndents.exists(_.hasStateColumn) @tailrec def getBlockStat(t: Tree): Tree = t match { - case b: Term.Block => - getSingleStatExceptEndMarker(b.stats) match { + case b: Term.Block => getSingleStatExceptEndMarker(b.stats) match { case Some(s) if !isEnclosedInMatching(b) => getBlockStat(s) case _ => t } @@ -1714,13 +1609,10 @@ class FormatOps( getSplits(getSlbSplit(end.left)) case _: Term.If => getSlbSplits() case _: Term.Try | _: Term.TryWithHandler => - if (hasStateColumn) getSplits(getSpaceSplit(1)) - else getSlbSplits() + if (hasStateColumn) getSplits(getSpaceSplit(1)) else getSlbSplits() case _: Term.Block | _: Term.Match | _: Type.Match | - _: Term.NewAnonymous => - getSplits(getSpaceSplit(1)) - case Term.ForYield(_, b) => - nextNonComment(bheadFT).right match { // skipping `for` + _: Term.NewAnonymous => getSplits(getSpaceSplit(1)) + case Term.ForYield(_, b) => nextNonComment(bheadFT).right match { // skipping `for` case x @ LeftParenOrBrace() => val exclude = TokenRanges(TokenRange(x, matching(x))) if (b.is[Term.Block]) @@ -1754,13 +1646,12 @@ class FormatOps( if (body.tokens.isEmpty) Seq(Split(Space, 0)) else foldedNonEmptyNonComment(body, nlSplitFunc, isKeep, spaceIndents) - private def unfoldedSpaceNonEmptyNonComment( - body: Tree, - slbOnly: Boolean - )(implicit style: ScalafmtConfig): Split = { + private def unfoldedSpaceNonEmptyNonComment(body: Tree, slbOnly: Boolean)( + implicit style: ScalafmtConfig + ): Split = { val expire = nextNonCommentSameLine(tokens.getLastNonTrivial(body)).left - def slbSplit(end: T)(implicit fileLine: FileLine) = - Split(Space, 0).withSingleLine(end, noSyntaxNL = true) + def slbSplit(end: T)(implicit fileLine: FileLine) = Split(Space, 0) + .withSingleLine(end, noSyntaxNL = true) body match { // we force newlines in for/yield case _: Term.ForYield => Split.ignored @@ -1785,10 +1676,9 @@ class FormatOps( Seq(spaceSplit.withIndents(spaceIndents), nlSplitFunc(1).forThisLine) } - def checkComment( - ft: FormatToken, - nlSplitFunc: Int => Split - )(splitsFunc: FormatToken => Seq[Split]): Seq[Split] = + def checkComment(ft: FormatToken, nlSplitFunc: Int => Split)( + splitsFunc: FormatToken => Seq[Split] + ): Seq[Split] = if (!ft.right.is[T.Comment]) splitsFunc(ft) else if (ft.hasBreak) Seq(nlSplitFunc(0).forThisLine) else { @@ -1824,21 +1714,16 @@ class FormatOps( unfoldedNonComment(body, nlSplitFunc, spaceIndents, true) } - def get( - ft: FormatToken, - body: Tree, - spaceIndents: Seq[Indent] = Seq.empty - )(classicNoBreakFunc: => Split)(nlSplitFunc: Int => Split)(implicit - style: ScalafmtConfig - ): Seq[Split] = + def get(ft: FormatToken, body: Tree, spaceIndents: Seq[Indent] = Seq.empty)( + classicNoBreakFunc: => Split + )(nlSplitFunc: Int => Split)(implicit style: ScalafmtConfig): Seq[Split] = checkComment(ft, nlSplitFunc) { x => style.newlines.getBeforeMultiline match { case Newlines.unfold => unfoldedNonComment(body, nlSplitFunc, spaceIndents, false) case Newlines.classic | Newlines.keep if x.hasBreak => Seq(nlSplitFunc(0).forThisLine) - case Newlines.classic => - Option(classicNoBreakFunc).fold { + case Newlines.classic => Option(classicNoBreakFunc).fold { foldedNonComment(body, nlSplitFunc, isKeep = true, spaceIndents) } { func => val spcSplit = func.forThisLine @@ -1857,24 +1742,22 @@ class FormatOps( spaceIndents: Seq[Indent] = Seq.empty )(classicNoBreakFunc: => Split)(nlSplitFunc: Int => Split)(implicit style: ScalafmtConfig - ): Seq[Split] = - get(ft, body, spaceIndents)(classicNoBreakFunc)(x => - withIndent(nlSplitFunc(x), ft, body) - ) + ): Seq[Split] = get(ft, body, spaceIndents)(classicNoBreakFunc)(x => + withIndent(nlSplitFunc(x), ft, body) + ) def withIndent(nlSplit: Split, ft: FormatToken, body: Tree)(implicit style: ScalafmtConfig - ): Split = - asInfixApp(body).fold { - val lastFt = tokens.getLast(body) - val right = nextNonComment(ft).right - val rpOpt = if (right.is[T.LeftParen]) matchingOpt(right) else None - val expireFt = rpOpt.fold(lastFt) { rp => - if (rp.end >= lastFt.left.end) tokens.before(rp) else lastFt - } - val expire = tokens.nextNonCommentSameLine(expireFt).left - nlSplit.withIndent(Num(style.indent.main), expire, ExpiresOn.After) - }(app => InfixSplits.withNLIndent(nlSplit)(app, ft)) + ): Split = asInfixApp(body).fold { + val lastFt = tokens.getLast(body) + val right = nextNonComment(ft).right + val rpOpt = if (right.is[T.LeftParen]) matchingOpt(right) else None + val expireFt = rpOpt.fold(lastFt) { rp => + if (rp.end >= lastFt.left.end) tokens.before(rp) else lastFt + } + val expire = tokens.nextNonCommentSameLine(expireFt).left + nlSplit.withIndent(Num(style.indent.main), expire, ExpiresOn.After) + }(app => InfixSplits.withNLIndent(nlSplit)(app, ft)) } @@ -1884,7 +1767,8 @@ class FormatOps( ): Boolean = { val body = caseStat.body (ft.noBreak || style.newlines.getBeforeMultiline.ignoreSourceSplit) && - body.eq(ft.meta.rightOwner) && (body match { + body.eq(ft.meta.rightOwner) && + (body match { case _: Lit.Unit | _: Term.Tuple => false case t: Term.ApplyInfix => val op = t.op.value @@ -1899,14 +1783,15 @@ class FormatOps( if (ft.right.is[T.Dot]) Some(ft) else None } else None - def getKwMatchAfterDot(ft: FormatToken): T.KwMatch = - tokens.nextNonCommentAfter(ft).right.asInstanceOf[T.KwMatch] + def getKwMatchAfterDot(ft: FormatToken): T.KwMatch = tokens + .nextNonCommentAfter(ft).right.asInstanceOf[T.KwMatch] object GetSelectLike { def unapply(tree: Tree): Option[SelectLike] = tree match { case t: Term.Select => Some(SelectLike(t)) - case t: Term.Match => - getMatchDot(t).map { ft => SelectLike(t, getKwMatchAfterDot(ft)) } + case t: Term.Match => getMatchDot(t).map { ft => + SelectLike(t, getKwMatchAfterDot(ft)) + } case _ => None } } @@ -1932,26 +1817,21 @@ class FormatOps( val boundEnd = boundEndOpt.getOrElse(typeEnd) def indent = Indent(Num(style.indent.main), boundEnd, ExpiresOn.After) def unfoldPolicy = typeOwner match { - case tparam: Type.Param => - Policy.on(typeEnd) { + case tparam: Type.Param => Policy.on(typeEnd) { case Decision(t @ FormatToken(_, _: T.Colon | _: T.Viewbound, _), s) - if t.meta.rightOwner eq tparam => - Decision.onlyNewlineSplits(s) + if t.meta.rightOwner eq tparam => Decision.onlyNewlineSplits(s) } case _ => NoPolicy } style.newlines.beforeTypeBounds match { - case Newlines.classic => - Seq(Split(noNLMod, 0)) - case Newlines.unfold => - Seq( + case Newlines.classic => Seq(Split(noNLMod, 0)) + case Newlines.unfold => Seq( Split(noNLMod, 0).withSingleLine(typeEnd), Split(Newline, 1).withIndent(indent).withPolicy(unfoldPolicy) ) case Newlines.keep if ft.hasBreak => Seq(Split(Newline, 1).withIndent(indent)) - case _ => - Seq( + case _ => Seq( Split(noNLMod, 0).withSingleLine(boundEnd), Split(Newline, 1).withIndent(indent) ) @@ -1970,41 +1850,38 @@ class FormatOps( // Optional braces after any token that can start indentation: // ) = => ?=> <- catch do else finally for // if match return then throw try while yield - def unapply( - ftMeta: FormatToken.Meta - )(implicit style: ScalafmtConfig): Option[Seq[Split]] = - get(tokens(ftMeta.idx)).flatMap(_.splits) - - def get(ft: FormatToken)(implicit + def unapply(ftMeta: FormatToken.Meta)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = { + ): Option[Seq[Split]] = get(tokens(ftMeta.idx)).flatMap(_.splits) + + def get( + ft: FormatToken + )(implicit style: ScalafmtConfig): Option[OptionalBracesRegion] = { if (!style.dialect.allowSignificantIndentation) None - else - Option(ft.left match { - case _: T.Colon | _: T.KwWith => ColonEolImpl - case _: T.RightArrow => RightArrowImpl - case _: T.RightParen => RightParenImpl - case _: T.KwFor => ForImpl - case _: T.KwWhile => WhileImpl - case _: T.KwDo => DoImpl - case _: T.Equals => EqualsImpl - case _: T.KwTry => TryImpl - case _: T.KwCatch => CatchImpl - case _: T.KwFinally => FinallyImpl - case _: T.KwMatch => MatchImpl - case _: T.KwThen => ThenImpl - case _: T.KwIf => IfImpl - case _: T.KwElse => ElseImpl - case _: T.KwReturn | _: T.ContextArrow | _: T.LeftArrow | - _: T.KwThrow | _: T.KwYield => - BlockImpl - case _ => null - }).flatMap { impl => - val nft = nextNonComment(ft) - impl.create(ft, nft).filter { ob => - !nft.right.is[T.LeftBrace] || nft.meta.rightOwner.parent != ob.owner - } + else Option(ft.left match { + case _: T.Colon | _: T.KwWith => ColonEolImpl + case _: T.RightArrow => RightArrowImpl + case _: T.RightParen => RightParenImpl + case _: T.KwFor => ForImpl + case _: T.KwWhile => WhileImpl + case _: T.KwDo => DoImpl + case _: T.Equals => EqualsImpl + case _: T.KwTry => TryImpl + case _: T.KwCatch => CatchImpl + case _: T.KwFinally => FinallyImpl + case _: T.KwMatch => MatchImpl + case _: T.KwThen => ThenImpl + case _: T.KwIf => IfImpl + case _: T.KwElse => ElseImpl + case _: T.KwReturn | _: T.ContextArrow | _: T.LeftArrow | _: T.KwThrow | + _: T.KwYield => BlockImpl + case _ => null + }).flatMap { impl => + val nft = nextNonComment(ft) + impl.create(ft, nft).filter { ob => + !nft.right.is[T.LeftBrace] || nft.meta.rightOwner.parent != ob.owner } + } } private def getSplits( @@ -2049,42 +1926,38 @@ class FormatOps( private object ColonEolImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case t: Template if templateCurlyFt(t).contains(ft) => - Some(new OptionalBracesRegion { - def owner = t.parent - def splits = Some(getSplits(ft, t, forceNL = true)) - def rightBrace = if (isSeqMulti(t.stats)) treeLast(t) else None - }) - case t: Pkg if tokenAfter(t.ref).right eq ft.left => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = Some(getSplits(ft, t, forceNL = true)) - def rightBrace = if (isSeqMulti(t.stats)) treeLast(t) else None - }) - case t: Type.Refine => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = Some(getSplits(ft, t, forceNL = true)) - def rightBrace = treeLast(t) - }) - case t: Term.ArgClause if tokens.getHead(t) eq ft => - onArgClause(ft, t, t.values) - case t: Term => - t.parent match { - case Some(p: Term.ArgClause) - if isSingleElement(p.values, t) && - (tokens.getHead(p) eq ft) => - val stats = t match { - case b: Term.Block => b.stats - case _ => t :: Nil - } - onArgClause(ft, p, stats) - case _ => None - } - case _ => None - } + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case t: Template if templateCurlyFt(t).contains(ft) => + Some(new OptionalBracesRegion { + def owner = t.parent + def splits = Some(getSplits(ft, t, forceNL = true)) + def rightBrace = if (isSeqMulti(t.stats)) treeLast(t) else None + }) + case t: Pkg if tokenAfter(t.ref).right eq ft.left => + Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = Some(getSplits(ft, t, forceNL = true)) + def rightBrace = if (isSeqMulti(t.stats)) treeLast(t) else None + }) + case t: Type.Refine => Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = Some(getSplits(ft, t, forceNL = true)) + def rightBrace = treeLast(t) + }) + case t: Term.ArgClause if tokens.getHead(t) eq ft => + onArgClause(ft, t, t.values) + case t: Term => t.parent match { + case Some(p: Term.ArgClause) + if isSingleElement(p.values, t) && (tokens.getHead(p) eq ft) => + val stats = t match { + case b: Term.Block => b.stats + case _ => t :: Nil + } + onArgClause(ft, p, stats) + case _ => None + } + case _ => None + } private def onArgClause( ft: FormatToken, @@ -2094,8 +1967,7 @@ class FormatOps( def funcSplit(arg: Term.FunctionTerm)(implicit fl: FileLine) = { val end = tokens.getLast(arg) val opt = getOptimalTokenFor(getFuncArrow(arg).getOrElse(end)) - Split(Space, 0) - .withSingleLine(opt) + Split(Space, 0).withSingleLine(opt) .andPolicy(decideNewlinesOnlyAfterToken(opt)) } val indent = ac.parent match { @@ -2105,12 +1977,13 @@ class FormatOps( case x: Member.Apply => isSelect(x) case x => x.is[Term.Select] } - val ok = (style.getFewerBraces() match { - case Indents.FewerBraces.never => true - case Indents.FewerBraces.always => false - case Indents.FewerBraces.beforeSelect => - !p.parent.exists(_.is[Term.Select]) - }) || isSelect(p) + val ok = + (style.getFewerBraces() match { + case Indents.FewerBraces.never => true + case Indents.FewerBraces.always => false + case Indents.FewerBraces.beforeSelect => + !p.parent.exists(_.is[Term.Select]) + }) || isSelect(p) if (ok) None // select is taken care off elsewhere else Some(style.indent.main + style.indent.getSignificant) case _ => None @@ -2123,8 +1996,8 @@ class FormatOps( // https://dotty.epfl.ch/docs/internals/syntax.html (tf.paramClause match { // LambdaStart case tpc @ Term.ParamClause(tp :: Nil, mod) => - (mod.isEmpty && tp.mods.isEmpty && - tp.decltpe.isEmpty) || isEnclosedInParens(tpc) + (mod.isEmpty && tp.mods.isEmpty && tp.decltpe.isEmpty) || + isEnclosedInParens(tpc) case _ => true // multiple params are always in parens }) => getSplits(ft, ac, forceNL = false, indentOpt = indent) match { @@ -2159,143 +2032,134 @@ class FormatOps( private object RightParenImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case ParamClauseParent(t: Defn.ExtensionGroup) - if isBlockStart(t.body, nft) => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = Some(getSplitsMaybeBlock(ft, nft, t.body)) - def rightBrace = blockLast(t.body) - }) - case t: Term.If if !nft.right.is[T.KwThen] && { - !isTreeSingleExpr(t.thenp) || !ifWithoutElse(t) && - (isElsePWithOptionalBraces(t) || - existsBlockIfWithoutElse(t.thenp, false)) - } => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = Some(getSplitsForIf(ft, nft, t)) - def rightBrace = blockLast(t.thenp) - }) - case t @ Term.For(_, b) if !nft.right.is[T.KwDo] => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = - if (isTreeSingleExpr(b)) None - else Some(getSplits(ft, b, true)) - def rightBrace = blockLast(b) - }) - case t @ Term.While(_, b) if !nft.right.is[T.KwDo] => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = - if (isTreeSingleExpr(b)) None - else Some(getSplits(ft, b, true)) - def rightBrace = blockLast(b) - }) - case _ => None - } + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case ParamClauseParent(t: Defn.ExtensionGroup) + if isBlockStart(t.body, nft) => + Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = Some(getSplitsMaybeBlock(ft, nft, t.body)) + def rightBrace = blockLast(t.body) + }) + case t: Term.If if !nft.right.is[T.KwThen] && { + !isTreeSingleExpr(t.thenp) || + !ifWithoutElse(t) && + (isElsePWithOptionalBraces(t) || + existsBlockIfWithoutElse(t.thenp, false)) + } => + Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = Some(getSplitsForIf(ft, nft, t)) + def rightBrace = blockLast(t.thenp) + }) + case t @ Term.For(_, b) if !nft.right.is[T.KwDo] => + Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = + if (isTreeSingleExpr(b)) None else Some(getSplits(ft, b, true)) + def rightBrace = blockLast(b) + }) + case t @ Term.While(_, b) if !nft.right.is[T.KwDo] => + Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = + if (isTreeSingleExpr(b)) None else Some(getSplits(ft, b, true)) + def rightBrace = blockLast(b) + }) + case _ => None + } } private object RightArrowImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case t: Case => // unsupported except for right brace - Some(new OptionalBracesRegion { - def owner = None - def splits = None - def rightBrace = blockLast(t.body) - }) - case _ => BlockImpl.create(ft, nft) - } + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case t: Case => // unsupported except for right brace + Some(new OptionalBracesRegion { + def owner = None + def splits = None + def rightBrace = blockLast(t.body) + }) + case _ => BlockImpl.create(ft, nft) + } } private object ForImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case t @ Term.For(enums, _) if isSeqMulti(enums) => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = getSplitsForStats(ft, nft, enums) - def rightBrace = seqLast(enums) - }) - case t @ Term.ForYield(enums, _) if isSeqMulti(enums) => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = getSplitsForStats(ft, nft, enums) - def rightBrace = seqLast(enums) - }) - case _ => BlockImpl.create(ft, nft) - } + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case t @ Term.For(enums, _) if isSeqMulti(enums) => + Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = getSplitsForStats(ft, nft, enums) + def rightBrace = seqLast(enums) + }) + case t @ Term.ForYield(enums, _) if isSeqMulti(enums) => + Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = getSplitsForStats(ft, nft, enums) + def rightBrace = seqLast(enums) + }) + case _ => BlockImpl.create(ft, nft) + } } private object WhileImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case t @ Term.While(b: Term.Block, _) - if !matchingOpt(nft.right).exists(_.end >= b.pos.end) => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = Some { - val dangle = style.danglingParentheses.ctrlSite - val forceNL = !nft.right.is[T.LeftParen] - getSplits(ft, b, forceNL = forceNL, danglingKeyword = dangle) - } - def rightBrace = blockLast(b) - }) - case _ => None - } + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case t @ Term.While(b: Term.Block, _) + if !matchingOpt(nft.right).exists(_.end >= b.pos.end) => + Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = Some { + val dangle = style.danglingParentheses.ctrlSite + val forceNL = !nft.right.is[T.LeftParen] + getSplits(ft, b, forceNL = forceNL, danglingKeyword = dangle) + } + def rightBrace = blockLast(b) + }) + case _ => None + } } private object DoImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case t @ Term.While(_, body) => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = Some(getSplitsMaybeBlock(ft, nft, body)) - def rightBrace = blockLast(body) - }) - case t @ Term.For(_, body) => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = Some(getSplitsMaybeBlock(ft, nft, body)) - def rightBrace = blockLast(body) - }) - case _ => None - } + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case t @ Term.While(_, body) => Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = Some(getSplitsMaybeBlock(ft, nft, body)) + def rightBrace = blockLast(body) + }) + case t @ Term.For(_, body) => Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = Some(getSplitsMaybeBlock(ft, nft, body)) + def rightBrace = blockLast(body) + }) + case _ => None + } } private object EqualsImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case t: Ctor.Secondary => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = - if (t.stats.isEmpty) None - else getSplitsForStatsImpl(ft, nft, t.init, t.stats) - def rightBrace = treeLast(t) - }) - case t @ Tree.WithBody(x: Term.PartialFunction) => - Some(new OptionalBracesRegion { + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case t: Ctor.Secondary => Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = + if (t.stats.isEmpty) None + else getSplitsForStatsImpl(ft, nft, t.init, t.stats) + def rightBrace = treeLast(t) + }) + case t @ Tree.WithBody(x: Term.PartialFunction) => Some( + new OptionalBracesRegion { def owner = Some(t) def splits = getSplitsForStats(ft, nft, x.cases, nlOnly = true) def rightBrace = treeLast(x) - }) - case _ => BlockImpl.create(ft, nft) - } + } + ) + case _ => BlockImpl.create(ft, nft) + } } private object TryImpl extends Factory { @@ -2308,40 +2172,40 @@ class FormatOps( Some(getSplits(ft, expr, shouldBreakInOptionalBraces(nft))) else None ft.meta.leftOwner match { - case t @ Term.Try(expr, _, finallyp) => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = - trySplits(expr, finallyp, isCatchUsingOptionalBraces(t)) - def rightBrace = blockLast(expr) - }) - case t @ Term.TryWithHandler(expr, _, finallyp) => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = trySplits(expr, finallyp, false) - def rightBrace = blockLast(expr) - }) + case t @ Term.Try(expr, _, finallyp) => Some( + new OptionalBracesRegion { + def owner = Some(t) + def splits = + trySplits(expr, finallyp, isCatchUsingOptionalBraces(t)) + def rightBrace = blockLast(expr) + } + ) + case t @ Term.TryWithHandler(expr, _, finallyp) => Some( + new OptionalBracesRegion { + def owner = Some(t) + def splits = trySplits(expr, finallyp, false) + def rightBrace = blockLast(expr) + } + ) case _ => None } } } - private def isCatchUsingOptionalBraces(tree: Term.Try): Boolean = - tree.catchp.headOption.exists(x => !tokenBefore(x).left.is[T.LeftBrace]) + private def isCatchUsingOptionalBraces(tree: Term.Try): Boolean = tree + .catchp.headOption.exists(x => !tokenBefore(x).left.is[T.LeftBrace]) private object CatchImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case t @ Term.Try(_, catchp, _) => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = getSplitsForStats(ft, nft, catchp) - def rightBrace = seqLast(catchp) - }) - case _ => None - } + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case t @ Term.Try(_, catchp, _) => Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = getSplitsForStats(ft, nft, catchp) + def rightBrace = seqLast(catchp) + }) + case _ => None + } } private object FinallyImpl extends Factory { @@ -2361,12 +2225,11 @@ class FormatOps( } } lo match { - case t: Term.Try => - t.finallyp.map(createImpl { + case t: Term.Try => t.finallyp.map(createImpl { isCatchUsingOptionalBraces(t) || isTreeUsingOptionalBraces(t.expr) }) - case t: Term.TryWithHandler => - t.finallyp.map(createImpl(isTreeUsingOptionalBraces(t.expr))) + case t: Term.TryWithHandler => t.finallyp + .map(createImpl(isTreeUsingOptionalBraces(t.expr))) case _ => None } } @@ -2381,14 +2244,12 @@ class FormatOps( Some(getSplits(ft, tree, true, indentOpt = style.indent.matchSite)) else None ft.meta.leftOwner match { - case t: Term.Match => - Some(new OptionalBracesRegion { + case t: Term.Match => Some(new OptionalBracesRegion { def owner = Some(t) def splits = result(t, t.cases) def rightBrace = treeLast(t) }) - case t: Type.Match => - Some(new OptionalBracesRegion { + case t: Type.Match => Some(new OptionalBracesRegion { def owner = Some(t) def splits = result(t, t.cases) def rightBrace = treeLast(t) @@ -2401,16 +2262,14 @@ class FormatOps( private object ThenImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case t: Term.If => - Some(new OptionalBracesRegion { - def owner = Some(t) - def splits = Some(getSplitsForIf(ft, nft, t)) - def rightBrace = blockLast(t.thenp) - }) - case _ => None - } + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case t: Term.If => Some(new OptionalBracesRegion { + def owner = Some(t) + def splits = Some(getSplitsForIf(ft, nft, t)) + def rightBrace = blockLast(t.thenp) + }) + case _ => None + } } private object IfImpl extends Factory { @@ -2444,30 +2303,27 @@ class FormatOps( private object ElseImpl extends Factory { def create(ft: FormatToken, nft: FormatToken)(implicit style: ScalafmtConfig - ): Option[OptionalBracesRegion] = - ft.meta.leftOwner match { - case t: Term.If => - (t.elsep match { - case _: Term.If => None - case x if !isTreeSingleExpr(x) => Some(true) - case b @ Term.Block(List(_: Term.If)) - if (matchingOpt(nft.right) match { - case Some(t) => t.end < b.pos.end - case None => true - }) => - None - case _ if isThenPWithOptionalBraces(t) => - Some(shouldBreakInOptionalBraces(nft)) - case _ => None - }).map { forceNL => - new OptionalBracesRegion { - def owner = Some(t) - def splits = Some(getSplits(ft, t.elsep, forceNL)) - def rightBrace = blockLast(t.elsep) - } + ): Option[OptionalBracesRegion] = ft.meta.leftOwner match { + case t: Term.If => (t.elsep match { + case _: Term.If => None + case x if !isTreeSingleExpr(x) => Some(true) + case b @ Term.Block(List(_: Term.If)) + if (matchingOpt(nft.right) match { + case Some(t) => t.end < b.pos.end + case None => true + }) => None + case _ if isThenPWithOptionalBraces(t) => + Some(shouldBreakInOptionalBraces(nft)) + case _ => None + }).map { forceNL => + new OptionalBracesRegion { + def owner = Some(t) + def splits = Some(getSplits(ft, t.elsep, forceNL)) + def rightBrace = blockLast(t.elsep) } - case _ => None - } + } + case _ => None + } } private def getSplitsMaybeBlock( @@ -2476,8 +2332,8 @@ class FormatOps( tree: Tree, danglingKeyword: Boolean = true )(implicit fileLine: FileLine, style: ScalafmtConfig): Seq[Split] = { - val forceNL = - !hasSingleTermStatIfBlock(tree) || shouldBreakInOptionalBraces(nft) + val forceNL = !hasSingleTermStatIfBlock(tree) || + shouldBreakInOptionalBraces(nft) getSplits(ft, tree, forceNL, danglingKeyword) } @@ -2487,10 +2343,7 @@ class FormatOps( head: => Tree, tail: Seq[Tree], nlOnly: Boolean = false - )(implicit - fileLine: FileLine, - style: ScalafmtConfig - ): Option[Seq[Split]] = + )(implicit fileLine: FileLine, style: ScalafmtConfig): Option[Seq[Split]] = if (tokens.tokenJustBeforeOpt(head).contains(nft)) Some { val forceNL = nlOnly || shouldBreakInOptionalBraces(ft) getSplits(ft, tail.lastOption.getOrElse(head), forceNL) @@ -2502,12 +2355,10 @@ class FormatOps( nft: FormatToken, trees: Seq[Tree], nlOnly: Boolean = false - )(implicit - fileLine: FileLine, - style: ScalafmtConfig - ): Option[Seq[Split]] = trees.headOption.flatMap { head => - getSplitsForStatsImpl(ft, nft, head, trees.tail, nlOnly) - } + )(implicit fileLine: FileLine, style: ScalafmtConfig): Option[Seq[Split]] = + trees.headOption.flatMap { head => + getSplitsForStatsImpl(ft, nft, head, trees.tail, nlOnly) + } private def getSplitsForIf( ft: FormatToken, @@ -2532,21 +2383,20 @@ class FormatOps( prevNonComment(before).left match { case _: T.KwThen => true case _: T.LeftBrace => false - case _ => - !isTreeSingleExpr(thenp) && (!before.right.is[T.LeftBrace] || - matchingOpt(before.right).exists(rb => rb.end < thenp.pos.end)) + case _ => !isTreeSingleExpr(thenp) && + (!before.right.is[T.LeftBrace] || matchingOpt(before.right) + .exists(rb => rb.end < thenp.pos.end)) } } @tailrec private def isElsePWithOptionalBraces(tree: Term.If): Boolean = { val elsep = tree.elsep - !getHeadToken(elsep).is[T.LeftBrace] && (elsep match { - case t: Term.If => - isThenPWithOptionalBraces(t) || + !getHeadToken(elsep).is[T.LeftBrace] && + (elsep match { + case t: Term.If => isThenPWithOptionalBraces(t) || !ifWithoutElse(t) && isElsePWithOptionalBraces(t) - case Term.Block(List(t: Term.If)) => - isThenPWithOptionalBraces(t) || + case Term.Block(List(t: Term.If)) => isThenPWithOptionalBraces(t) || !ifWithoutElse(t) && isElsePWithOptionalBraces(t) case t => !isTreeSingleExpr(t) }) @@ -2554,12 +2404,11 @@ class FormatOps( private def shouldBreakInOptionalBraces( ft: FormatToken - )(implicit style: ScalafmtConfig): Boolean = - style.newlines.source match { - case Newlines.unfold => true - case Newlines.keep => ft.hasBreak - case _ => false - } + )(implicit style: ScalafmtConfig): Boolean = style.newlines.source match { + case Newlines.unfold => true + case Newlines.keep => ft.hasBreak + case _ => false + } private def isTreeUsingOptionalBraces(tree: Tree): Boolean = !isTreeSingleExpr(tree) && !tokenBefore(tree).left.is[T.LeftBrace] @@ -2573,13 +2422,16 @@ class FormatOps( case _ => false } - @inline private def treeLast(tree: Tree): Option[T] = - getLastTokenOpt(tree) - @inline private def blockLast(tree: Tree): Option[T] = + @inline + private def treeLast(tree: Tree): Option[T] = getLastTokenOpt(tree) + @inline + private def blockLast(tree: Tree): Option[T] = if (isTreeMultiStatBlock(tree)) treeLast(tree) else None - @inline private def blockLast(tree: Term.Block): Option[T] = + @inline + private def blockLast(tree: Term.Block): Option[T] = if (isMultiStatBlock(tree)) treeLast(tree) else None - @inline private def seqLast(seq: Seq[Tree]): Option[T] = + @inline + private def seqLast(seq: Seq[Tree]): Option[T] = if (isSeqMulti(seq)) treeLast(seq.last) else None def indentAndBreakBeforeCtrl[A](tree: Tree, split: Split)(implicit @@ -2593,13 +2445,12 @@ class FormatOps( else { val kw = tokenAfter(tree).right if (kw.is[A]) Some { - val indent = - style.indent.ctrlSite.getOrElse(style.indent.getSignificant) + val indent = style.indent.ctrlSite + .getOrElse(style.indent.getSignificant) def policy = if (split.isNL) decideNewlinesOnlyBeforeClose(kw) else decideNewlinesOnlyBeforeCloseOnBreak(kw) - split - .withIndent(Num(indent), kw, ExpiresOn.Before) + split.withIndent(Num(indent), kw, ExpiresOn.Before) .andPolicy(policy, !style.danglingParentheses.ctrlSite) } else None @@ -2640,8 +2491,8 @@ class FormatOps( private def seq(all: Boolean, t: Tree): Ranges = if (all) Seq(t -> t) else Nil - private def seq(all: Boolean, t: Option[Tree]): Ranges = - t.map(seq(all, _)).getOrElse(Nil) + private def seq(all: Boolean, t: Option[Tree]): Ranges = t.map(seq(all, _)) + .getOrElse(Nil) private def seq(all: Boolean, t: Seq[Tree]): Ranges = if (all && t.nonEmpty) Seq(t.head -> t.last) else Nil @@ -2651,8 +2502,8 @@ class FormatOps( private object BlockImpl extends Factory { def getBlocks(ft: FormatToken, nft: FormatToken, all: Boolean): Result = { - def ok(stat: Tree): Boolean = - tokens.tokenJustBeforeOpt(stat).contains(nft) + def ok(stat: Tree): Boolean = tokens.tokenJustBeforeOpt(stat) + .contains(nft) val leftOwner = ft.meta.leftOwner findTreeWithParentSimple(nft.meta.rightOwner)(_ eq leftOwner) match { case Some(t: Term.Block) => @@ -2678,8 +2529,7 @@ class FormatOps( case x: Term.If if !nft.right.is[T.KwThen] => val hasElse = all && !ifWithoutElse(x) Some((x.thenp, seq(hasElse, x.elsep) ++ seq(all, x.cond))) - case Term.For(s, b) if !nft.right.is[T.KwDo] => - Some((b, seq(all, s))) + case Term.For(s, b) if !nft.right.is[T.KwDo] => Some((b, seq(all, s))) case Term.While(c, b) if !nft.right.is[T.KwDo] => Some((b, seq(all, c))) case _ => None @@ -2738,10 +2588,10 @@ class FormatOps( private object FinallyImpl extends Factory { def getBlocks(ft: FormatToken, nft: FormatToken, all: Boolean): Result = ft.meta.leftOwner match { - case t: Term.Try => - t.finallyp.map(x => (x, seq(all, t.expr) ++ seq(all, t.catchp))) - case t: Term.TryWithHandler => - t.finallyp.map(x => (x, seq(all, t.expr) ++ seq(all, t.catchp))) + case t: Term.Try => t.finallyp + .map(x => (x, seq(all, t.expr) ++ seq(all, t.catchp))) + case t: Term.TryWithHandler => t.finallyp + .map(x => (x, seq(all, t.expr) ++ seq(all, t.catchp))) case _ => None } } @@ -2765,11 +2615,10 @@ class FormatOps( } - def isBlockWithoutBraces(t: Term.Block): Boolean = - t.tokens.head match { - case lb: T.LeftBrace => lb ne tokens(lb).left - case _ => true - } + def isBlockWithoutBraces(t: Term.Block): Boolean = t.tokens.head match { + case lb: T.LeftBrace => lb ne tokens(lb).left + case _ => true + } def existsBlockIfWithoutElse(t: Term.If): Boolean = existsBlockIfWithoutElse(t.thenp, false) || @@ -2777,34 +2626,31 @@ class FormatOps( def existsBlockIfWithoutElse(t: Tree, other: => Boolean): Boolean = t match { case x: Term.If => existsBlockIfWithoutElse(x) - case b @ Term.Block(List(x: Term.If)) => - isBlockWithoutBraces(b) && existsBlockIfWithoutElse(x) + case b @ Term.Block(List(x: Term.If)) => isBlockWithoutBraces(b) && + existsBlockIfWithoutElse(x) case _ => other } - def getHeadToken(tree: Tree): T = - tokens.getHead(tree).left + def getHeadToken(tree: Tree): T = tokens.getHead(tree).left - def getLastToken(tree: Tree): T = - tokens.getLast(tree).left + def getLastToken(tree: Tree): T = tokens.getLast(tree).left - def getLastTokenOpt(tree: Tree): Option[T] = - tokens.getLastOpt(tree).map(_.left) + def getLastTokenOpt(tree: Tree): Option[T] = tokens.getLastOpt(tree) + .map(_.left) - def getLastNonTrivialToken(tree: Tree): T = - tokens.getLastNonTrivial(tree).left + def getLastNonTrivialToken(tree: Tree): T = tokens.getLastNonTrivial(tree) + .left - def getLastNonTrivialTokenOpt(tree: Tree): Option[T] = - tokens.getLastNonTrivialOpt(tree).map(_.left) + def getLastNonTrivialTokenOpt(tree: Tree): Option[T] = tokens + .getLastNonTrivialOpt(tree).map(_.left) def getEndOfBlock(ft: FormatToken, parensToo: Boolean)(implicit style: ScalafmtConfig - ): Option[T] = - ft.left match { - case x: T.LeftBrace => matchingOpt(x) - case x: T.LeftParen => if (parensToo) matchingOpt(x) else None - case _ => OptionalBraces.get(ft).flatMap(_.rightBrace) - } + ): Option[T] = ft.left match { + case x: T.LeftBrace => matchingOpt(x) + case x: T.LeftParen => if (parensToo) matchingOpt(x) else None + case _ => OptionalBraces.get(ft).flatMap(_.rightBrace) + } def isCloseDelimForTrailingCommasMultiple(ft: FormatToken): Boolean = ft.meta.rightOwner match { @@ -2819,33 +2665,30 @@ class FormatOps( def rightIsCloseDelimToAddTrailingComma(left: T, ft: => FormatToken)(implicit style: ScalafmtConfig - ): Boolean = - style.getTrailingCommas match { - case TrailingCommas.keep => - left.is[T.Comma] && - TreeOps.rightIsCloseDelimForTrailingComma(left, ft) - case TrailingCommas.always => - TreeOps.rightIsCloseDelimForTrailingComma(left, ft) - case TrailingCommas.multiple => - val ftEval = ft - TreeOps.rightIsCloseDelimForTrailingComma(left, ftEval) && - isCloseDelimForTrailingCommasMultiple(ftEval) - case _ => false - } + ): Boolean = style.getTrailingCommas match { + case TrailingCommas.keep => left.is[T.Comma] && + TreeOps.rightIsCloseDelimForTrailingComma(left, ft) + case TrailingCommas.always => TreeOps + .rightIsCloseDelimForTrailingComma(left, ft) + case TrailingCommas.multiple => + val ftEval = ft + TreeOps.rightIsCloseDelimForTrailingComma(left, ftEval) && + isCloseDelimForTrailingCommasMultiple(ftEval) + case _ => false + } def getMustDangleForTrailingCommas(getCloseFt: => FormatToken)(implicit style: ScalafmtConfig - ): Boolean = - !style.rewrite.trailingCommas.allowFolding && { - val closeFt = getCloseFt - val beforeClose = - if (!closeFt.left.is[T.Comment]) Some(closeFt.left) - else { - val tok = tokens.prevNonCommentSameLineBefore(closeFt).left - if (tok.is[T.Comment]) None else Some(tok) - } - beforeClose.exists(rightIsCloseDelimToAddTrailingComma(_, closeFt)) - } + ): Boolean = !style.rewrite.trailingCommas.allowFolding && { + val closeFt = getCloseFt + val beforeClose = + if (!closeFt.left.is[T.Comment]) Some(closeFt.left) + else { + val tok = tokens.prevNonCommentSameLineBefore(closeFt).left + if (tok.is[T.Comment]) None else Some(tok) + } + beforeClose.exists(rightIsCloseDelimToAddTrailingComma(_, closeFt)) + } } @@ -2882,13 +2725,11 @@ object FormatOps { def getOpenParenAlignIndents( end: T )(implicit style: ScalafmtConfig): Seq[Indent] = - if (style.align.closeParenSite) - Seq( - Indent(Length.StateColumn, end, ExpiresOn.After), - Indent(Length.Num(1), end, ExpiresOn.Before), - Indent(Length.Num(-1), end, ExpiresOn.After) - ) - else - Seq(Indent(Length.StateColumn, end, ExpiresOn.Before)) + if (style.align.closeParenSite) Seq( + Indent(Length.StateColumn, end, ExpiresOn.After), + Indent(Length.Num(1), end, ExpiresOn.Before), + Indent(Length.Num(-1), end, ExpiresOn.After) + ) + else Seq(Indent(Length.StateColumn, end, ExpiresOn.Before)) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatToken.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatToken.scala index 17d7faa53e..3036945177 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatToken.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatToken.scala @@ -31,8 +31,7 @@ case class FormatToken(left: Token, right: Token, meta: FormatToken.Meta) { } def inside(range: Set[Range]): Boolean = { - if (range.isEmpty) true - else range.exists(_.contains(right.pos.endLine)) + if (range.isEmpty) true else range.exists(_.contains(right.pos.endLine)) } def between = meta.between @@ -44,13 +43,19 @@ case class FormatToken(left: Token, right: Token, meta: FormatToken.Meta) { else if (right.is[Token.Comment] && isDocstring(meta.right.text)) 1 else 0 } - @inline def noBreak: Boolean = FormatToken.noBreak(newlinesBetween) - @inline def hasBreak: Boolean = !noBreak - @inline def hasBlankLine: Boolean = FormatToken.hasBlankLine(newlinesBetween) - - @inline def leftHasNewline = meta.left.hasNL - @inline def rightHasNewline = meta.right.hasNL - @inline def hasBreakOrEOF: Boolean = hasBreak || right.is[Token.EOF] + @inline + def noBreak: Boolean = FormatToken.noBreak(newlinesBetween) + @inline + def hasBreak: Boolean = !noBreak + @inline + def hasBlankLine: Boolean = FormatToken.hasBlankLine(newlinesBetween) + + @inline + def leftHasNewline = meta.left.hasNL + @inline + def rightHasNewline = meta.right.hasNL + @inline + def hasBreakOrEOF: Boolean = hasBreak || right.is[Token.EOF] /** A format token is uniquely identified by its left token. */ @@ -63,10 +68,13 @@ case class FormatToken(left: Token, right: Token, meta: FormatToken.Meta) { object FormatToken { - @inline def noBreak(newlines: Int): Boolean = newlines == 0 - @inline def hasBlankLine(newlines: Int): Boolean = newlines > 1 + @inline + def noBreak(newlines: Int): Boolean = newlines == 0 + @inline + def hasBlankLine(newlines: Int): Boolean = newlines > 1 - @inline def isNL(token: Token): Boolean = token.is[Token.LF] + @inline + def isNL(token: Token): Boolean = token.is[Token.LF] /** @param between * The whitespace tokens between left and right. @@ -82,8 +90,10 @@ object FormatToken { left: TokenMeta, right: TokenMeta ) { - @inline def leftOwner: Tree = left.owner - @inline def rightOwner: Tree = right.owner + @inline + def leftOwner: Tree = left.owner + @inline + def rightOwner: Tree = right.owner /** returns a value between 0 and 2 (2 for a blank line) */ lazy val newlinesBetween: Int = { @@ -92,22 +102,18 @@ object FormatToken { if (idx == between.length) maxCount else { val token = between(idx) - if (isNL(token)) - if (maxCount == 0) count(idx + 1, 1) else 2 - else - count(idx + 1, maxCount) + if (isNL(token)) if (maxCount == 0) count(idx + 1, 1) else 2 + else count(idx + 1, maxCount) } } count(0, 0) } } - case class TokenMeta( - owner: Tree, - text: String - ) { + case class TokenMeta(owner: Tree, text: String) { lazy val firstNL = text.indexOf('\n') - @inline def hasNL: Boolean = firstNL >= 0 + @inline + def hasNL: Boolean = firstNL >= 0 def countNL: Int = { var cnt = 0 var idx = firstNL diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatTokens.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatTokens.scala index fc166623e1..b5ec2fc890 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatTokens.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatTokens.scala @@ -11,9 +11,8 @@ import org.scalafmt.util._ import TokenOps._ -class FormatTokens(leftTok2tok: Map[TokenHash, Int])( - val arr: Array[FormatToken] -) extends IndexedSeq[FormatToken] { +class FormatTokens(leftTok2tok: Map[TokenHash, Int])(val arr: Array[FormatToken]) + extends IndexedSeq[FormatToken] { private def this(arr: Array[FormatToken]) = this { val result = Map.newBuilder[TokenHash, Int] @@ -23,8 +22,8 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( result.result() }(arr) - private lazy val matchingParentheses: Map[TokenHash, Token] = - TreeOps.getMatchingParentheses(arr.view.map(_.right)) + private lazy val matchingParentheses: Map[TokenHash, Token] = TreeOps + .getMatchingParentheses(arr.view.map(_.right)) override def length: Int = arr.length override def apply(idx: Int): FormatToken = arr(idx) @@ -40,11 +39,8 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( else { val ft = arr(idx) if (ft.left eq tok) ft - else if (isBefore) { - if (ft.left.start <= tok.start) ft else at(idx - 1) - } else { - if (ft.left.start >= tok.start) ft else at(idx + 1) - } + else if (isBefore) { if (ft.left.start <= tok.start) ft else at(idx - 1) } + else { if (ft.left.start >= tok.start) ft else at(idx + 1) } } } @@ -52,10 +48,13 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( if (off < 0) arr.head else if (off < arr.length) arr(off) else arr.last // get token; if rewritten, the one before - @inline def before(tok: Token): FormatToken = get(tok, true) + @inline + def before(tok: Token): FormatToken = get(tok, true) // get token; if rewritten, the one after - @inline def after(tok: Token): FormatToken = get(tok, false) - @inline def apply(tok: Token): FormatToken = before(tok) + @inline + def after(tok: Token): FormatToken = get(tok, false) + @inline + def apply(tok: Token): FormatToken = before(tok) /** If the token is missing: * - to go backward, start from the next token @@ -66,34 +65,40 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( apply(if (off < 0) after(tok) else before(tok), off) def apply(ft: FormatToken, off: Int): FormatToken = at(ft.meta.idx + off) - @inline def hasNext(ft: FormatToken): Boolean = ft.meta.idx < (arr.length - 1) - @inline def hasPrev(ft: FormatToken): Boolean = ft.meta.idx > 0 + @inline + def hasNext(ft: FormatToken): Boolean = ft.meta.idx < (arr.length - 1) + @inline + def hasPrev(ft: FormatToken): Boolean = ft.meta.idx > 0 - @inline def prev(ft: FormatToken): FormatToken = apply(ft, -1) - @inline def next(ft: FormatToken): FormatToken = apply(ft, 1) + @inline + def prev(ft: FormatToken): FormatToken = apply(ft, -1) + @inline + def next(ft: FormatToken): FormatToken = apply(ft, 1) - @inline def matching(token: Token): Token = - matchingParentheses.getOrElse( - FormatTokens.thash(token), - throw new NoSuchElementException( - s"Missing matching token index [${token.start}:${token.end}]: `$token`" - ) + @inline + def matching(token: Token): Token = matchingParentheses.getOrElse( + FormatTokens.thash(token), + throw new NoSuchElementException( + s"Missing matching token index [${token.start}:${token.end}]: `$token`" ) - @inline def matchingOpt(token: Token): Option[Token] = - matchingParentheses.get(FormatTokens.thash(token)) - @inline def hasMatching(token: Token): Boolean = - matchingParentheses.contains(FormatTokens.thash(token)) - @inline def areMatching(t1: Token)(t2: => Token): Boolean = - matchingOpt(t1) match { - case Some(x) => x eq t2 - case _ => false - } + ) + @inline + def matchingOpt(token: Token): Option[Token] = matchingParentheses + .get(FormatTokens.thash(token)) + @inline + def hasMatching(token: Token): Boolean = matchingParentheses + .contains(FormatTokens.thash(token)) + @inline + def areMatching(t1: Token)(t2: => Token): Boolean = matchingOpt(t1) match { + case Some(x) => x eq t2 + case _ => false + } def getDelimsIfEnclosed( tokens: Tokens, tree: Tree - ): Option[(FormatToken, FormatToken)] = - getHeadOpt(tokens, tree).flatMap { head => + ): Option[(FormatToken, FormatToken)] = getHeadOpt(tokens, tree) + .flatMap { head => matchingOpt(head.left).flatMap { other => val last = getLastNonTrivial(tokens, tree) if (last.left eq other) Some((head, last)) else None @@ -117,11 +122,12 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( def isEnclosedInMatching(tree: Tree): Boolean = isEnclosedInMatching(tree.tokens, tree) - @inline private def areMatchingParens(close: Token)(open: => Token): Boolean = - close.is[Token.RightParen] && areMatching(close)(open) + @inline + private def areMatchingParens(close: Token)(open: => Token): Boolean = close + .is[Token.RightParen] && areMatching(close)(open) - def isEnclosedInParens(tree: Tree): Boolean = - getClosingIfInParens(tree).isDefined + def isEnclosedInParens(tree: Tree): Boolean = getClosingIfInParens(tree) + .isDefined def getClosingIfInParens( last: FormatToken @@ -146,23 +152,18 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( } @tailrec - final def findTokenWith[A]( - ft: FormatToken, - iter: FormatToken => FormatToken - )(f: FormatToken => Option[A]): Either[FormatToken, A] = - f(ft) match { - case Some(a) => Right(a) - case _ => - val nextFt = iter(ft) - if (nextFt eq ft) Left(ft) - else findTokenWith(nextFt, iter)(f) - } + final def findTokenWith[A](ft: FormatToken, iter: FormatToken => FormatToken)( + f: FormatToken => Option[A] + ): Either[FormatToken, A] = f(ft) match { + case Some(a) => Right(a) + case _ => + val nextFt = iter(ft) + if (nextFt eq ft) Left(ft) else findTokenWith(nextFt, iter)(f) + } - final def findToken( - ft: FormatToken, - iter: FormatToken => FormatToken - )(f: FormatToken => Boolean): FormatToken = - findTokenWith(ft, iter)(Some(_).filter(f)).merge + final def findToken(ft: FormatToken, iter: FormatToken => FormatToken)( + f: FormatToken => Boolean + ): FormatToken = findTokenWith(ft, iter)(Some(_).filter(f)).merge final def nextNonCommentSameLine(curr: FormatToken): FormatToken = findToken(curr, next)(ft => ft.hasBreak || !ft.right.is[Token.Comment]) @@ -211,23 +212,23 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( def getHead(tokens: Tokens, tree: Tree): FormatToken = getOnOrBeforeOwned(after(tokens.head), tree) - @inline def getHead(tree: Tree): FormatToken = - getHead(tree.tokens, tree) + @inline + def getHead(tree: Tree): FormatToken = getHead(tree.tokens, tree) - def getHeadOpt(tokens: Tokens, tree: Tree): Option[FormatToken] = - tokens.headOption.map(x => getOnOrBeforeOwned(after(x), tree)) - @inline def getHeadOpt(tree: Tree): Option[FormatToken] = - getHeadOpt(tree.tokens, tree) + def getHeadOpt(tokens: Tokens, tree: Tree): Option[FormatToken] = tokens + .headOption.map(x => getOnOrBeforeOwned(after(x), tree)) + @inline + def getHeadOpt(tree: Tree): Option[FormatToken] = getHeadOpt(tree.tokens, tree) def getLast(tokens: Tokens, tree: Tree): FormatToken = getOnOrAfterOwned(apply(findLastVisibleToken(tokens)), tree) - @inline def getLast(tree: Tree): FormatToken = - getLast(tree.tokens, tree) + @inline + def getLast(tree: Tree): FormatToken = getLast(tree.tokens, tree) def getLastOpt(tokens: Tokens, tree: Tree): Option[FormatToken] = findLastVisibleTokenOpt(tokens).map(x => getOnOrAfterOwned(apply(x), tree)) - @inline def getLastOpt(tree: Tree): Option[FormatToken] = - getLastOpt(tree.tokens, tree) + @inline + def getLastOpt(tree: Tree): Option[FormatToken] = getLastOpt(tree.tokens, tree) def getLastNonTrivial(tokens: Tokens, tree: Tree): FormatToken = prevNonComment(getLast(tokens, tree)) @@ -248,10 +249,10 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( @inline def tokenAfter(trees: Seq[Tree]): FormatToken = tokenAfter(trees.last) - def tokenAfterOpt(tree: Tree): Option[FormatToken] = - getLastOpt(tree).map(nextNonComment) - def tokenAfterOpt(trees: Seq[Tree]): Option[FormatToken] = - trees.lastOption.flatMap(tokenAfterOpt) + def tokenAfterOpt(tree: Tree): Option[FormatToken] = getLastOpt(tree) + .map(nextNonComment) + def tokenAfterOpt(trees: Seq[Tree]): Option[FormatToken] = trees.lastOption + .flatMap(tokenAfterOpt) /* the following methods return the last format token such that * its `left` is before the parameter */ @@ -260,10 +261,10 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( @inline def tokenJustBefore(tree: Tree): FormatToken = prev(getHead(tree)) - def tokenJustBeforeOpt(tree: Tree): Option[FormatToken] = - getHeadOpt(tree).map(prev) - def tokenJustBeforeOpt(trees: Seq[Tree]): Option[FormatToken] = - trees.headOption.flatMap(tokenJustBeforeOpt) + def tokenJustBeforeOpt(tree: Tree): Option[FormatToken] = getHeadOpt(tree) + .map(prev) + def tokenJustBeforeOpt(trees: Seq[Tree]): Option[FormatToken] = trees + .headOption.flatMap(tokenJustBeforeOpt) /* the following methods return the last format token such that * its `left` is before the parameter and is not a comment */ @@ -277,26 +278,25 @@ class FormatTokens(leftTok2tok: Map[TokenHash, Int])( @inline def tokenBefore(trees: Seq[Tree]): FormatToken = tokenBefore(trees.head) - def tokenBeforeOpt(tree: Tree): Option[FormatToken] = - tokenJustBeforeOpt(tree).map(prevNonComment) - def tokenBeforeOpt(trees: Seq[Tree]): Option[FormatToken] = - trees.headOption.flatMap(tokenBeforeOpt) + def tokenBeforeOpt(tree: Tree): Option[FormatToken] = tokenJustBeforeOpt(tree) + .map(prevNonComment) + def tokenBeforeOpt(trees: Seq[Tree]): Option[FormatToken] = trees.headOption + .flatMap(tokenBeforeOpt) @inline - def isBreakAfterRight(ft: FormatToken): Boolean = - next(ft).hasBreakOrEOF + def isBreakAfterRight(ft: FormatToken): Boolean = next(ft).hasBreakOrEOF @inline - def isRightCommentThenBreak(ft: FormatToken): Boolean = - ft.right.is[Token.Comment] && isBreakAfterRight(ft) + def isRightCommentThenBreak(ft: FormatToken): Boolean = ft.right + .is[Token.Comment] && isBreakAfterRight(ft) @inline def isRightLikeSingleLineComment(ft: FormatToken): Boolean = isRightCommentThenBreak(ft) && !ft.rightHasNewline @inline - def isAttachedCommentThenBreak(ft: FormatToken): Boolean = - ft.noBreak && isRightCommentThenBreak(ft) + def isAttachedCommentThenBreak(ft: FormatToken): Boolean = ft.noBreak && + isRightCommentThenBreak(ft) } @@ -320,9 +320,8 @@ object FormatTokens { val arr = tokens.toArray def process(right: Token): Unit = { val rmeta = FormatToken.TokenMeta(owner(right), right.syntax) - if (left eq null) { - fmtWasOff = isFormatOff(right) - } else { + if (left eq null) { fmtWasOff = isFormatOff(right) } + else { val between = arr.slice(wsIdx, tokIdx) val fmtIsOff = fmtWasOff || isFormatOff(right) fmtWasOff = if (fmtWasOff) !isFormatOn(right) else fmtIsOff @@ -334,14 +333,13 @@ object FormatTokens { lmeta = rmeta } val tokCnt = arr.length - while (tokIdx < tokCnt) - arr(tokIdx) match { - case _: Token.Whitespace => tokIdx += 1 - case right => - process(right) - tokIdx += 1 - wsIdx = tokIdx - } + while (tokIdx < tokCnt) arr(tokIdx) match { + case _: Token.Whitespace => tokIdx += 1 + case right => + process(right) + tokIdx += 1 + wsIdx = tokIdx + } val ftoks = new FormatTokens(result.result) val styleMap = new StyleMap(ftoks, style) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatWriter.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatWriter.scala index 1a5c02a390..4592a624ba 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatWriter.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatWriter.scala @@ -41,27 +41,25 @@ class FormatWriter(formatOps: FormatOps) { formatToken.left match { case _ if entry.previous.formatToken.meta.formatOff => sb.append(formatToken.meta.left.text) // checked the state for left - case _: T.Comment => - entry.formatComment - case _: T.Interpolation.Part | _: T.Constant.String => - sb.append(entry.formatMarginized) - case _: T.Constant.Int => - sb.append(LiteralOps.prettyPrintInteger(formatToken.meta.left.text)) - case _: T.Constant.Long => - sb.append(LiteralOps.prettyPrintInteger(formatToken.meta.left.text)) - case _: T.Constant.Float => - sb.append(LiteralOps.prettyPrintFloat(formatToken.meta.left.text)) - case _: T.Constant.Double => - sb.append(LiteralOps.prettyPrintDouble(formatToken.meta.left.text)) + case _: T.Comment => entry.formatComment + case _: T.Interpolation.Part | _: T.Constant.String => sb + .append(entry.formatMarginized) + case _: T.Constant.Int => sb + .append(LiteralOps.prettyPrintInteger(formatToken.meta.left.text)) + case _: T.Constant.Long => sb + .append(LiteralOps.prettyPrintInteger(formatToken.meta.left.text)) + case _: T.Constant.Float => sb + .append(LiteralOps.prettyPrintFloat(formatToken.meta.left.text)) + case _: T.Constant.Double => sb + .append(LiteralOps.prettyPrintDouble(formatToken.meta.left.text)) case _ => - val syntax = - Option(location.replace).getOrElse(formatToken.meta.left.text) + val syntax = Option(location.replace) + .getOrElse(formatToken.meta.left.text) val rewrittenToken = style.rewriteTokens.getOrElse(syntax, syntax) sb.append(rewrittenToken) } - location.optionalBraces.toSeq - .sortBy { case (indent, _) => -indent } + location.optionalBraces.toSeq.sortBy { case (indent, _) => -indent } .foreach { case (indent, owner) => val label = getEndMarkerLabel(owner) if (label != null) { @@ -70,30 +68,23 @@ class FormatWriter(formatOps: FormatOps) { .fold(0) { case (blanks, _, last) => val numBlanks = blanks.beforeEndMarker if (numBlanks > 0) numBlanks - else - locations.extraBlankTokens - .get(last.meta.idx) - .fold(0)(x => if (x > 0) 1 else 0) + else locations.extraBlankTokens.get(last.meta.idx) + .fold(0)(x => if (x > 0) 1 else 0) } - sb.append(getNewlines(numBlanks)) - .append(getIndentation(indent)) - .append("end ") - .append(label) + sb.append(getNewlines(numBlanks)).append(getIndentation(indent)) + .append("end ").append(label) } } // missing braces if (location.missingBracesIndent.nonEmpty) { - location.missingBracesIndent.toSeq - .sorted(Ordering.Int.reverse) + location.missingBracesIndent.toSeq.sorted(Ordering.Int.reverse) .foreach(i => sb.append('\n').append(getIndentation(i)).append("}")) if (location.missingBracesOpenOrTuck) { skipWs = true sb.append(" ") - } else if (formatToken.right.is[T.RightParen]) - skipWs = true - } else if (location.missingBracesOpenOrTuck) - sb.append(" {") + } else if (formatToken.right.is[T.RightParen]) skipWs = true + } else if (location.missingBracesOpenOrTuck) sb.append(" {") if (!skipWs) delayedAlign = entry.formatWhitespace(delayedAlign) } @@ -107,18 +98,17 @@ class FormatWriter(formatOps: FormatOps) { val result = new Array[FormatLocation](state.depth) @tailrec - def iter(state: State, lineId: Int): Unit = - if (state.depth != 0) { - val prev = state.prev - val idx = prev.depth - val ft = toks(idx) - val newlines = - if (idx == 0) 0 - else state.split.modExt.mod.newlines + ft.meta.left.countNL - val newLineId = lineId + newlines - result(idx) = FormatLocation(ft, state, styleMap.at(ft), newLineId) - iter(prev, newLineId) - } + def iter(state: State, lineId: Int): Unit = if (state.depth != 0) { + val prev = state.prev + val idx = prev.depth + val ft = toks(idx) + val newlines = + if (idx == 0) 0 + else state.split.modExt.mod.newlines + ft.meta.left.countNL + val newLineId = lineId + newlines + result(idx) = FormatLocation(ft, state, styleMap.at(ft), newLineId) + iter(prev, newLineId) + } iter(state, 0) if (state.depth == toks.length) { // format completed @@ -129,13 +119,11 @@ class FormatWriter(formatOps: FormatOps) { if (initStyle.rewrite.scala3.insertEndMarkerMinLines > 0) checkInsertEndMarkers(result) } - if (initStyle.rewrite.insertBraces.minLines > 0) - checkInsertBraces(result) + if (initStyle.rewrite.insertBraces.minLines > 0) checkInsertBraces(result) if ( initStyle.rewrite.rules.contains(RedundantBraces) && initStyle.rewrite.redundantBraces.parensForOneLineApply - ) - replaceRedundantBraces(result) + ) replaceRedundantBraces(result) } new FormatLocations(result) @@ -146,8 +134,7 @@ class FormatWriter(formatOps: FormatOps) { val lookup = mutable.Map.empty[Int, (Int, Int)] def checkApply(t: Tree): Boolean = t.parent match { - case Some(p @ Term.ArgClause(`t` :: Nil, _)) => - TreeOps.isParentAnApply(p) + case Some(p @ Term.ArgClause(`t` :: Nil, _)) => TreeOps.isParentAnApply(p) case _ => false } @@ -159,13 +146,13 @@ class FormatWriter(formatOps: FormatOps) { tok.left match { case rb: T.RightBrace => // look for "foo { bar }" val ok = tok.meta.leftOwner match { - case b: Term.Block => - checkApply(b) && RedundantBraces.canRewriteBlockWithParens(b) && + case b: Term.Block => checkApply(b) && + RedundantBraces.canRewriteBlockWithParens(b) && b.parent.exists(tokens.getLast(_) eq tok) - case f: Term.FunctionTerm => - checkApply(f) && RedundantBraces.canRewriteFuncWithParens(f) - case t @ TreeOps.SingleArgInBraces(_, arg, _) => - TreeOps.isParentAnApply(t) && + case f: Term.FunctionTerm => checkApply(f) && + RedundantBraces.canRewriteFuncWithParens(f) + case t @ TreeOps.SingleArgInBraces(_, arg, _) => TreeOps + .isParentAnApply(t) && RedundantBraces.canRewriteStatWithParens(arg) case _ => false } @@ -188,22 +175,17 @@ class FormatWriter(formatOps: FormatOps) { state.prev else { val prevloc = locations(idx - 1) - val prevState = - state.prev.copy(split = state.prev.split.withMod(NoSplit)) - locations(idx - 1) = prevloc.copy( - shift = prevloc.shift - 1, - state = prevState - ) + val prevState = state.prev + .copy(split = state.prev.split.withMod(NoSplit)) + locations(idx - 1) = prevloc + .copy(shift = prevloc.shift - 1, state = prevState) prevState } // update "{" locations(idx) = - if (inParentheses) - loc.copy( - replace = "(", - state = state.copy(prev = prevBegState) - ) + if (inParentheses) loc + .copy(replace = "(", state = state.copy(prev = prevBegState)) else { // remove space after "{" val split = state.split.withMod(NoSplit) @@ -264,11 +246,12 @@ class FormatWriter(formatOps: FormatOps) { val endMarkers = new mutable.ListBuffer[(Int, Int)] locations.foreach { x => val idx = x.formatToken.meta.idx - val floc = if (removedLines > 0 && x.isNotRemoved) { - val floc = x.copy(leftLineId = x.leftLineId + removedLines) - locations(idx) = floc - floc - } else x + val floc = + if (removedLines > 0 && x.isNotRemoved) { + val floc = x.copy(leftLineId = x.leftLineId + removedLines) + locations(idx) = floc + floc + } else x if (endMarkers.nonEmpty && endMarkers(0)._1 == idx) { val begIdx = endMarkers.remove(0)._2 val endIdx = locations.lastIndexWhere(_.isNotRemoved, idx) @@ -284,32 +267,31 @@ class FormatWriter(formatOps: FormatOps) { removedLines += 1 } } - } else - getOptionalBracesOwner(floc, 3).foreach { owner => - // do not skip comment lines, as the parser doesn't handle comments - // at end of optional braces region and treats them as outside - val endFt = tokens.nextNonCommentSameLine(tokens.getLast(owner)) - val ok = endFt.meta.rightOwner match { - case em: Term.EndMarker => em.parent == owner.parent - case _ => false - } - if (ok) { - // " end name " - val end = endFt.meta.idx - val isStandalone = locations(end).hasBreakAfter && - end + 2 < locations.length && locations(end + 2).hasBreakAfter - if (isStandalone) { - val settings = floc.style.rewrite.scala3 - val idx = settings.countEndMarkerLines match { - case RewriteScala3Settings.EndMarkerLines.lastBlockOnly => - tokens.nextNonCommentSameLine(floc.formatToken).meta.idx + 1 - case RewriteScala3Settings.EndMarkerLines.all => - tokens.getHead(owner).meta.idx - } - endMarkers.prepend(end -> idx) + } else getOptionalBracesOwner(floc, 3).foreach { owner => + // do not skip comment lines, as the parser doesn't handle comments + // at end of optional braces region and treats them as outside + val endFt = tokens.nextNonCommentSameLine(tokens.getLast(owner)) + val ok = endFt.meta.rightOwner match { + case em: Term.EndMarker => em.parent == owner.parent + case _ => false + } + if (ok) { + // " end name " + val end = endFt.meta.idx + val isStandalone = locations(end).hasBreakAfter && + end + 2 < locations.length && locations(end + 2).hasBreakAfter + if (isStandalone) { + val settings = floc.style.rewrite.scala3 + val idx = settings.countEndMarkerLines match { + case RewriteScala3Settings.EndMarkerLines.lastBlockOnly => tokens + .nextNonCommentSameLine(floc.formatToken).meta.idx + 1 + case RewriteScala3Settings.EndMarkerLines.all => tokens + .getHead(owner).meta.idx } + endMarkers.prepend(end -> idx) } } + } } } @@ -326,17 +308,14 @@ class FormatWriter(formatOps: FormatOps) { val eLoc = locations(end) val bLoc = locations(tokens.getHead(owner).meta.idx) val begIndent = bLoc.state.prev.indentation - def appendOwner() = - locations(end) = eLoc.copy(optionalBraces = - eLoc.optionalBraces + (begIndent -> owner) - ) - def removeOwner() = - locations(end) = - eLoc.copy(optionalBraces = eLoc.optionalBraces - begIndent) + def appendOwner() = locations(end) = eLoc + .copy(optionalBraces = eLoc.optionalBraces + (begIndent -> owner)) + def removeOwner() = locations(end) = eLoc + .copy(optionalBraces = eLoc.optionalBraces - begIndent) def processOwner() = { val settings = floc.style.rewrite.scala3 - def okSpan(loc: FormatLocation) = - 1 + getLineDiff(loc, eLoc) >= settings.insertEndMarkerMinLines + def okSpan(loc: FormatLocation) = 1 + getLineDiff(loc, eLoc) >= + settings.insertEndMarkerMinLines settings.countEndMarkerLines match { case RewriteScala3Settings.EndMarkerLines.lastBlockOnly => val i = tokens.nextNonCommentSameLine(floc.formatToken).meta.idx @@ -353,10 +332,10 @@ class FormatWriter(formatOps: FormatOps) { private def checkInsertBraces(locations: Array[FormatLocation]): Unit = { def checkInfix(tree: Tree): Boolean = tree match { - case ai: Term.ApplyInfix => - tokens.isEnclosedInParens(ai) || + case ai: Term.ApplyInfix => tokens.isEnclosedInParens(ai) || tokens.prevNonCommentSameLine(tokens.tokenJustBefore(ai.op)).noBreak && - checkInfix(ai.lhs) && (ai.argClause.values match { + checkInfix(ai.lhs) && + (ai.argClause.values match { case head :: Nil => checkInfix(head) case _ => true }) @@ -366,11 +345,12 @@ class FormatWriter(formatOps: FormatOps) { val willAddLines = new mutable.ListBuffer[Int] locations.foreach { x => val idx = x.formatToken.meta.idx - val floc = if (addedLines > 0 && x.isNotRemoved) { - val floc = x.copy(leftLineId = x.leftLineId - addedLines) - locations(idx) = floc - floc - } else x + val floc = + if (addedLines > 0 && x.isNotRemoved) { + val floc = x.copy(leftLineId = x.leftLineId - addedLines) + locations(idx) = floc + floc + } else x if (willAddLines.nonEmpty && willAddLines(0) == idx) { addedLines += 1 willAddLines.remove(0) @@ -389,9 +369,8 @@ class FormatWriter(formatOps: FormatOps) { val ok = !ft.meta.formatOff && ib.minLines > 0 && floc.missingBracesIndent.isEmpty val mb = - if (ok) formatOps.MissingBraces.getBlocks(ft, ib.allBlocks).filter { - case (y, _) => checkInfix(y) && hasBreakAfter(idx) - } + if (ok) formatOps.MissingBraces.getBlocks(ft, ib.allBlocks) + .filter { case (y, _) => checkInfix(y) && hasBreakAfter(idx) } else None mb.foreach { case (owner, otherBlocks) => val endFt = tokens.nextNonCommentSameLine(tokens.getLast(owner)) @@ -445,9 +424,12 @@ class FormatWriter(formatOps: FormatOps) { private implicit val style: ScalafmtConfig = curr.style def previous = locations(math.max(i - 1, 0)) - @inline def tok = curr.formatToken - @inline def state = curr.state - @inline def prevState = curr.state.prev + @inline + def tok = curr.formatToken + @inline + def state = curr.state + @inline + def prevState = curr.state.prev private def appendWhitespace(alignOffset: Int, delayedAlign: Int)(implicit sb: StringBuilder @@ -474,9 +456,7 @@ class FormatWriter(formatOps: FormatOps) { 0 } - def formatWhitespace(delayedAlign: Int)(implicit - sb: StringBuilder - ): Int = { + def formatWhitespace(delayedAlign: Int)(implicit sb: StringBuilder): Int = { import org.scalafmt.config.TrailingCommas @@ -504,8 +484,9 @@ class FormatWriter(formatOps: FormatOps) { if (idx == locations.length) None else iter(locations(idx), gotNL) case _ => - val ok = gotNL == whenNL && TreeOps - .rightIsCloseDelimForTrailingComma(tok.left, ft, whenNL) + val ok = gotNL == whenNL && + TreeOps + .rightIsCloseDelimForTrailingComma(tok.left, ft, whenNL) if (ok) Some(ft) else None } } @@ -514,43 +495,41 @@ class FormatWriter(formatOps: FormatOps) { iter(curr, false) } - @inline def ws(offset: Int) = appendWhitespace(offset, delayedAlign) + @inline + def ws(offset: Int) = appendWhitespace(offset, delayedAlign) - val noExtraOffset = - !dialect.allowTrailingCommas || - tok.left.is[T.Comment] || - previous.formatToken.meta.formatOff + val noExtraOffset = !dialect.allowTrailingCommas || + tok.left.is[T.Comment] || previous.formatToken.meta.formatOff - if (noExtraOffset) - ws(0) - else - style.getTrailingCommas match { - // remove comma if no newline - case TrailingCommas.keep - if tok.left.is[T.Comma] && (isClosedDelimWithNewline(false) || + if (noExtraOffset) ws(0) + else style.getTrailingCommas match { + // remove comma if no newline + case TrailingCommas.keep + if tok.left.is[T.Comma] && + (isClosedDelimWithNewline(false) || (tok.meta.leftOwner match { // closing paren could have been removed by rewrite case x: Term.ArgClause => tokens.getLast(x) eq tok case _ => false })) => - sb.setLength(sb.length - 1) - if (!tok.right.is[T.RightParen]) ws(1) - else if (style.spaces.inParentheses) { - sb.append(getIndentation(1 + delayedAlign)); 0 - } else delayedAlign - // append comma if newline - case TrailingCommas.always - if !tok.left.is[T.Comma] && isClosedDelimWithNewline(true) => - sb.append(',') - ws(-1) - // append comma if newline and multiple args - case TrailingCommas.multiple - if !tok.left.is[T.Comma] && getClosedDelimWithNewline(true) - .exists(isCloseDelimForTrailingCommasMultiple) => - sb.append(',') - ws(-1) - case _ => ws(0) - } + sb.setLength(sb.length - 1) + if (!tok.right.is[T.RightParen]) ws(1) + else if (style.spaces.inParentheses) { + sb.append(getIndentation(1 + delayedAlign)); 0 + } else delayedAlign + // append comma if newline + case TrailingCommas.always + if !tok.left.is[T.Comma] && isClosedDelimWithNewline(true) => + sb.append(',') + ws(-1) + // append comma if newline and multiple args + case TrailingCommas.multiple + if !tok.left.is[T.Comma] && getClosedDelimWithNewline(true) + .exists(isCloseDelimForTrailingCommasMultiple) => + sb.append(',') + ws(-1) + case _ => ws(0) + } } def formatMarginized: String = { @@ -558,23 +537,23 @@ class FormatWriter(formatOps: FormatOps) { val tupleOpt = tok.left match { case _ if !style.assumeStandardLibraryStripMargin => None case _ if !tok.meta.left.hasNL => None - case _: T.Constant.String => - TreeOps.getStripMarginChar(tok.meta.leftOwner).map { pipe => - def isPipeFirstChar = text.find(_ != '"').contains(pipe) - val noAlign = !style.align.stripMargin || curr.hasBreakBefore - val thisOffset = - if (style.align.stripMargin) if (isPipeFirstChar) 3 else 2 - else style.indent.main - val prevIndent = - if (noAlign) prevState.indentation - else prevState.prev.column + prevState.prev.split.length - (pipe, thisOffset + prevIndent) - } - case _: T.Interpolation.Part => - TreeOps.getStripMarginCharForInterpolate(tok.meta.leftOwner).map { - val alignPipeOffset = if (style.align.stripMargin) 1 else 0 - (_, prevState.indentation + alignPipeOffset) - } + case _: T.Constant.String => TreeOps + .getStripMarginChar(tok.meta.leftOwner).map { pipe => + def isPipeFirstChar = text.find(_ != '"').contains(pipe) + val noAlign = !style.align.stripMargin || curr.hasBreakBefore + val thisOffset = + if (style.align.stripMargin) if (isPipeFirstChar) 3 else 2 + else style.indent.main + val prevIndent = + if (noAlign) prevState.indentation + else prevState.prev.column + prevState.prev.split.length + (pipe, thisOffset + prevIndent) + } + case _: T.Interpolation.Part => TreeOps + .getStripMarginCharForInterpolate(tok.meta.leftOwner).map { + val alignPipeOffset = if (style.align.stripMargin) 1 else 0 + (_, prevState.indentation + alignPipeOffset) + } case _ => None } tupleOpt.fold(text) { case (pipe, indent) => @@ -585,14 +564,10 @@ class FormatWriter(formatOps: FormatOps) { def formatComment(implicit sb: StringBuilder): Unit = { val text = tok.meta.left.text - if (text.startsWith("//")) - new FormatSlc(text).format() - else if (text == "/**/") - sb.append(text) - else if (isDocstring(text)) - formatDocstring(text) - else - new FormatMlc(text).format() + if (text.startsWith("//")) new FormatSlc(text).format() + else if (text == "/**/") sb.append(text) + else if (isDocstring(text)) formatDocstring(text) + else new FormatMlc(text).format() } private def formatOnelineDocstring( @@ -600,16 +575,16 @@ class FormatWriter(formatOps: FormatOps) { )(implicit sb: StringBuilder): Boolean = { curr.isStandalone && { val matcher = onelineDocstring.matcher(text) - matcher.matches() && (style.docstrings.oneline match { + matcher.matches() && + (style.docstrings.oneline match { case Docstrings.Oneline.fold => true case Docstrings.Oneline.unfold => false - case Docstrings.Oneline.keep => - matcher.start(1) == -1 && matcher.start(3) == -1 + case Docstrings.Oneline.keep => matcher.start(1) == -1 && + matcher.start(3) == -1 }) && { val content = matcher.group(2) val folding = style.docstrings.wrap match { - case Docstrings.Wrap.yes => - content.length <= // 7 is the length of "/** " and " */" + case Docstrings.Wrap.yes => content.length <= // 7 is the length of "/** " and " */" style.docstringsWrapMaxColumn - prevState.indentation - 7 case _ => true } @@ -623,8 +598,7 @@ class FormatWriter(formatOps: FormatOps) { text: String )(implicit sb: StringBuilder): Unit = { if (style.docstrings.style eq Docstrings.Preserve) sb.append(text) - else if (!formatOnelineDocstring(text)) - new FormatMlDoc(text).format() + else if (!formatOnelineDocstring(text)) new FormatMlDoc(text).format() } private abstract class FormatCommentBase( @@ -639,16 +613,14 @@ class FormatWriter(formatOps: FormatOps) { protected final def getFirstLineLength = if (breakBefore) leadingMargin - else - prevState.prev.column - prevState.prev.indentation + - prevState.split.length - - protected final def canRewrite = - style.comments.wrap match { - case Comments.Wrap.no => false - case Comments.Wrap.trailing => curr.hasBreakAfter - case Comments.Wrap.standalone => breakBefore && curr.hasBreakAfter - } + else prevState.prev.column - prevState.prev.indentation + + prevState.split.length + + protected final def canRewrite = style.comments.wrap match { + case Comments.Wrap.no => false + case Comments.Wrap.trailing => curr.hasBreakAfter + case Comments.Wrap.standalone => breakBefore && curr.hasBreakAfter + } protected final type WordIter = Iterator[String] @@ -677,37 +649,37 @@ class FormatWriter(formatOps: FormatOps) { linesSoFar: Int, atLineBeg: Boolean = false, needSpaceIfAtLineBeg: Boolean = false - ): Int = if (iter.hasNext) { - val word = iter.next() - var lines = linesSoFar - var nextLineBeg = lineBeg - def firstWordPrefix = prefixFirstWord(word) - def nextLineLength = 1 + word.length + sb.length - lineBeg - if (atLineBeg) { - if (needSpaceIfAtLineBeg) sb.append(' ') - sb.append(firstWordPrefix) - } else if (nextLineLength <= maxLength) { - sb.append(' ') - } else { - appendLineBreak() - lines += 1 - nextLineBeg = sb.length - sb.append(extraMargin) - sb.append(firstWordPrefix) - } - sb.append(word) - iterate(iter, nextLineBeg, lines) - } else linesSoFar + ): Int = + if (iter.hasNext) { + val word = iter.next() + var lines = linesSoFar + var nextLineBeg = lineBeg + def firstWordPrefix = prefixFirstWord(word) + def nextLineLength = 1 + word.length + sb.length - lineBeg + if (atLineBeg) { + if (needSpaceIfAtLineBeg) sb.append(' ') + sb.append(firstWordPrefix) + } else if (nextLineLength <= maxLength) { sb.append(' ') } + else { + appendLineBreak() + lines += 1 + nextLineBeg = sb.length + sb.append(extraMargin) + sb.append(firstWordPrefix) + } + sb.append(word) + iterate(iter, nextLineBeg, lines) + } else linesSoFar } protected def terminateMlc(begpos: Int, lines: Int): Unit = { - if (lines == 0 && style.comments.wrapSingleLineMlcAsSlc) - sb.setCharAt(begpos - 1, '/') + if (lines == 0 && style.comments.wrapSingleLineMlcAsSlc) sb + .setCharAt(begpos - 1, '/') else sb.append(" */") } - protected def append(csq: CharSequence, beg: Int, end: Int) = - sb.append(CharBuffer.wrap(csq, beg, end)) + protected def append(csq: CharSequence, beg: Int, end: Int) = sb + .append(CharBuffer.wrap(csq, beg, end)) } @@ -724,8 +696,8 @@ class FormatWriter(formatOps: FormatOps) { val nonSlash = trimmed.indexWhere(_ != '/') val hasSpace = nonSlash < 0 || // else space not needed Character.isWhitespace(trimmed.charAt(nonSlash)) - val column = prevState.column - text.length + - trimmed.length + (if (hasSpace) 0 else 1) + val column = prevState.column - text.length + trimmed.length + + (if (hasSpace) 0 else 1) if (column > maxColumn && canRewrite) reFormat(trimmed) else if (hasSpace) sb.append(trimmed) else { @@ -735,8 +707,7 @@ class FormatWriter(formatOps: FormatOps) { } } private def reFormat(text: String): Unit = { - val useSlc = - breakBefore && style.comments.wrapStandaloneSlcAsSlc + val useSlc = breakBefore && style.comments.wrapStandaloneSlcAsSlc val appendLineBreak: () => Unit = if (useSlc) { val spaces: String = getIndentation(indent) @@ -776,15 +747,14 @@ class FormatWriter(formatOps: FormatOps) { class ParaIter extends AbstractIterator[WordIter] { private var hasPara: Boolean = true - override def hasNext: Boolean = - hasPara && lineIter.hasNext && { - hasPara = !paraEnds - if (!hasPara) - do lineIter.next() while (lineIter.hasNext && paraEnds) - hasPara - } - override def next() = - new ParaLineIter().flatMap(splitAsIterator(slcDelim)) + override def hasNext: Boolean = hasPara && lineIter.hasNext && { + hasPara = !paraEnds + if (!hasPara) + do lineIter.next() while (lineIter.hasNext && paraEnds) + hasPara + } + override def next() = new ParaLineIter() + .flatMap(splitAsIterator(slcDelim)) class ParaLineIter extends AbstractIterator[String] { private var hasLine: Boolean = true @@ -934,17 +904,13 @@ class FormatWriter(formatOps: FormatOps) { // therefore, let's start by "rewinding" if (sbNonEmpty || leadingMargin == 0) { sb.setLength(sb.length - termIndent.length) - } else { - forceFirstLine() - } + } else { forceFirstLine() } val listIndent = // shift initial only by 2 if (termIndent ne margin) termIndent else getIndentation(margin.length + 2) formatListBlock(listIndent)(t) - case t: Scaladoc.Text => - formatTextAfterMargin(t, termIndent) - case t: Scaladoc.Table => - formatTable(t, termIndent) + case t: Scaladoc.Text => formatTextAfterMargin(t, termIndent) + case t: Scaladoc.Table => formatTable(t, termIndent) } } @@ -1009,8 +975,7 @@ class FormatWriter(formatOps: FormatOps) { case Some((offset, lineStart)) => sb.append(offset) append(x, lineStart, x.length) - case _ => - sb.append(x) + case _ => sb.append(x) } } appendBreak() @@ -1054,13 +1019,10 @@ class FormatWriter(formatOps: FormatOps) { item.terms.foreach(formatTerm(_, itemIndent, sbNonEmpty = true)) } - private def formatTable( - table: Scaladoc.Table, - termIndent: String - ): Unit = { + private def formatTable(table: Scaladoc.Table, termIndent: String): Unit = { val align = table.align - def getRowMax(f: Scaladoc.Table.Row => Int): Int = - table.rows.foldLeft(f(table.header)) { case (out, row) => + def getRowMax(f: Scaladoc.Table.Row => Int): Int = table.rows + .foldLeft(f(table.header)) { case (out, row) => math.max(out, f(row)) } val colsRange = 0 until getRowMax(_.cols.length) @@ -1068,10 +1030,14 @@ class FormatWriter(formatOps: FormatOps) { getRowMax(_.cols.view.drop(x).headOption.fold(0)(_.length)) } - @inline def beforeAll(): Unit = sb.append(termIndent) - @inline def beforeEach(): Unit = sb.append('|') - @inline def afterAll(): Unit = { sb.append('|'); appendBreak() } - @inline def getAlign(col: Int) = + @inline + def beforeAll(): Unit = sb.append(termIndent) + @inline + def beforeEach(): Unit = sb.append('|') + @inline + def afterAll(): Unit = { sb.append('|'); appendBreak() } + @inline + def getAlign(col: Int) = if (col < align.length) align(col) else Scaladoc.Table.Left def formatCols(useMargin: Boolean)(f: Int => Unit): Unit = { if (useMargin) beforeAll() @@ -1084,8 +1050,7 @@ class FormatWriter(formatOps: FormatOps) { val cell = if (col < row.cols.length) row.cols(col) else "" val pad = maxLengths(col) - cell.length val lpad = getAlign(col).leftPad(pad) - sb.append(getIndentation(1 + lpad)) - .append(cell) + sb.append(getIndentation(1 + lpad)).append(cell) .append(getIndentation(1 + pad - lpad)) } formatRow(false)(table.header) @@ -1115,8 +1080,8 @@ class FormatWriter(formatOps: FormatOps) { appendBreak().append(margin) else sb.append(' ') } - val extraMargin = - matcher.end(1) - matcher.start(1) - margin.length + val extraMargin = matcher.end(1) - matcher.start(1) - + margin.length if (extraMargin > 0) sb.append(getIndentation(extraMargin)) append(trimmed, contentBeg, contentEnd) iter(false) @@ -1126,8 +1091,8 @@ class FormatWriter(formatOps: FormatOps) { appendBreak().append('/') } - @inline private def appendBreak() = - sb.append('\n').append(spaces).append('*') + @inline + private def appendBreak() = sb.append('\n').append(spaces).append('*') } } @@ -1139,8 +1104,8 @@ class FormatWriter(formatOps: FormatOps) { // imperative and error-prone right now. private def alignmentTokens: Map[Int, Int] = { lazy val noAlignTokens = styleMap.forall(_.align.tokens.isEmpty) - if (locations.length != tokens.length || noAlignTokens) - Map.empty[Int, Int] + if (locations.length != tokens.length || noAlignTokens) Map + .empty[Int, Int] else { var columnShift = 0 implicit val finalResult = Map.newBuilder[Int, Int] @@ -1150,8 +1115,7 @@ class FormatWriter(formatOps: FormatOps) { val blocks = new mutable.HashMap[Tree, AlignBlock] def createBlock(x: Tree) = blocks.getOrElseUpdate(x, new AlignBlock) var prevAlignContainer: Tree = null - var prevBlock: AlignBlock = - if (isMultiline) null else createBlock(null) + var prevBlock: AlignBlock = if (isMultiline) null else createBlock(null) val getOrCreateBlock: Tree => AlignBlock = if (isMultiline) createBlock else _ => prevBlock val getBlockToFlush: (=> Tree, Boolean) => Option[AlignBlock] = @@ -1159,11 +1123,9 @@ class FormatWriter(formatOps: FormatOps) { (x, isBlankLine) => if (isBlankLine) blocks.get(x) else None else (_, _) => Some(prevBlock) val shouldFlush: Tree => Boolean = - if (!isMultiline) _ => true - else (x: Tree) => x eq prevAlignContainer + if (!isMultiline) _ => true else (x: Tree) => x eq prevAlignContainer val wasSameContainer: Tree => Boolean = - if (isMultiline) _ => true - else (x: Tree) => x eq prevAlignContainer + if (isMultiline) _ => true else (x: Tree) => x eq prevAlignContainer var idx = 0 while (idx < locations.length) { @@ -1183,14 +1145,12 @@ class FormatWriter(formatOps: FormatOps) { if (floc.hasBreakAfter || ft.leftHasNewline) floc else { getAlignContainer(floc).foreach { container => - def appendCandidate() = - columnCandidates += new AlignStop( - getAlignColumn(floc) + columnShift, - floc, - getAlignHashKey(floc) - ) - if (alignContainer eq null) - alignContainer = container + def appendCandidate() = columnCandidates += new AlignStop( + getAlignColumn(floc) + columnShift, + floc, + getAlignHashKey(floc) + ) + if (alignContainer eq null) alignContainer = container else if (alignContainer ne container) { val pos1 = alignContainer.pos val pos2 = container.pos @@ -1202,8 +1162,7 @@ class FormatWriter(formatOps: FormatOps) { columnCandidates.clear() } } - if (alignContainer eq container) - appendCandidate() + if (alignContainer eq container) appendCandidate() } if (idx < locations.length) processLine else floc } @@ -1223,9 +1182,8 @@ class FormatWriter(formatOps: FormatOps) { } block.appendToEmptyBlock(alignLine) } - if (block.isEmpty) { - if (!isBlankLine) appendToBlock() - } else { + if (block.isEmpty) { if (!isBlankLine) appendToBlock() } + else { val matches = columnMatches( wasSameContainer(alignContainer), block.refStops, @@ -1242,11 +1200,10 @@ class FormatWriter(formatOps: FormatOps) { prevAlignContainer = alignContainer prevBlock = block } - if (isBlankLine || alignContainer.eq(null)) - getBlockToFlush( - getAlignContainer(location.formatToken.meta.rightOwner), - isBlankLine - ).foreach(flushAlignBlock) + if (isBlankLine || alignContainer.eq(null)) getBlockToFlush( + getAlignContainer(location.formatToken.meta.rightOwner), + isBlankLine + ).foreach(flushAlignBlock) } blocks.valuesIterator.foreach(flushAlignBlock) finalResult.result() @@ -1267,25 +1224,22 @@ class FormatWriter(formatOps: FormatOps) { } object AlignContainer { - def unapply(tree: Tree): Option[Tree] = - tree match { - case _: Source | _: Template | _: Term.Block | _: Term.Match | - _: Type.Match | _: Term.FunctionTerm | _: Term.PartialFunction => - Some(tree) - case _ => None - } + def unapply(tree: Tree): Option[Tree] = tree match { + case _: Source | _: Template | _: Term.Block | _: Term.Match | + _: Type.Match | _: Term.FunctionTerm | _: Term.PartialFunction => + Some(tree) + case _ => None + } object WithBody { - def unapply(tree: Tree): Option[(List[meta.Mod], Tree)] = - tree match { - case wm: Stat.WithMods => - tree match { - case t: Tree.WithBody => Some(wm.mods -> t.body) - case t: Stat.WithTemplate => Some(wm.mods -> t.templ) - case _ => None - } - case _ => None - } + def unapply(tree: Tree): Option[(List[meta.Mod], Tree)] = tree match { + case wm: Stat.WithMods => tree match { + case t: Tree.WithBody => Some(wm.mods -> t.body) + case t: Stat.WithTemplate => Some(wm.mods -> t.templ) + case _ => None + } + case _ => None + } } } @@ -1301,8 +1255,7 @@ class FormatWriter(formatOps: FormatOps) { case Some(p: Term.Apply) if (p.argClause.values match { case (_: Term.Apply) :: Nil => true case _ => p.fun eq child - }) => - getAlignContainerParent(p) + }) => getAlignContainerParent(p) // containers that can be traversed further if on same line case Some(p @ (_: Case | _: Enumerator)) => if (isEarlierLine(p)) p else getAlignContainerParent(p) @@ -1320,8 +1273,7 @@ class FormatWriter(formatOps: FormatOps) { } if (keepGoing) getAlignContainerParent(p) else p case Some(p: Term.ForYield) if child ne p.body => p - case Some(p: Member.ParamClause) => - p.parent match { + case Some(p: Member.ParamClause) => p.parent match { // if all on single line, keep going case Some(q) if onSingleLine(q) => getAlignContainerParent(p) // if this one not on single line, use parent as the owner @@ -1343,8 +1295,7 @@ class FormatWriter(formatOps: FormatOps) { case _: Defn | _: Case | _: Term.Apply | _: Init | _: Ctor.Primary => getAlignContainerParent(t, Some(t)) - case _: Mod => - t.parent match { + case _: Mod => t.parent match { case Some(p) => getAlignContainer(p) case None => t } @@ -1366,17 +1317,16 @@ class FormatWriter(formatOps: FormatOps) { } } - private def flushAlignBlock(block: AlignBlock)(implicit - builder: mutable.Builder[(Int, Int), Map[Int, Int]] - ): Unit = { - if (block.hasMultiple) - flushMultiEntryAlignBlock(block) + private def flushAlignBlock( + block: AlignBlock + )(implicit builder: mutable.Builder[(Int, Int), Map[Int, Int]]): Unit = { + if (block.hasMultiple) flushMultiEntryAlignBlock(block) block.clear() } - private def flushMultiEntryAlignBlock(block: AlignBlock)(implicit - builder: mutable.Builder[(Int, Int), Map[Int, Int]] - ): Unit = { + private def flushMultiEntryAlignBlock( + block: AlignBlock + )(implicit builder: mutable.Builder[(Int, Int), Map[Int, Int]]): Unit = { val endIndex = locations.length - 1 block.foreach { x => val headStop = x.stops.head @@ -1398,8 +1348,7 @@ class FormatWriter(formatOps: FormatOps) { private def shiftStateColumnIndent(startIdx: Int, offset: Int): Unit = { // look for StateColumn; it returns indent=0 for withStateOffset(0) val stateIndentOpt = locations(startIdx).state.split.modExt.indents - .filter(_.hasStateColumn) - .flatMap(_.withStateOffset(0)) + .filter(_.hasStateColumn).flatMap(_.withStateOffset(0)) stateIndentOpt.headOption.foreach { indent => @tailrec def updateLocation(idx: Int): Unit = { @@ -1422,12 +1371,15 @@ class FormatWriter(formatOps: FormatOps) { lazy val extraBlankTokens = { val extraBlankMap = new mutable.HashMap[Int, Int] def setIdx(idx: Int, cnt: Int) = - if (extraBlankMap.getOrElseUpdate(idx, cnt) < cnt) - extraBlankMap.update(idx, cnt) - @inline def setIdxCheck(idx: => Int, cnt: Int, force: => Boolean) = + if (extraBlankMap.getOrElseUpdate(idx, cnt) < cnt) extraBlankMap + .update(idx, cnt) + @inline + def setIdxCheck(idx: => Int, cnt: Int, force: => Boolean) = if (cnt > 0) setIdx(idx, cnt) else if (cnt < 0 && force) setIdx(idx, 0) - @inline def setFt(ft: FormatToken) = setIdx(ft.meta.idx, 1) - @inline def setFtCheck(ft: FormatToken, cnt: Int, force: => Boolean) = + @inline + def setFt(ft: FormatToken) = setIdx(ft.meta.idx, 1) + @inline + def setFtCheck(ft: FormatToken, cnt: Int, force: => Boolean) = setIdxCheck(ft.meta.idx, cnt, force) def setTopStats(owner: Tree, stats: Seq[Stat]): Unit = { val nest = getNest(stats.head) @@ -1441,8 +1393,7 @@ class FormatWriter(formatOps: FormatOps) { stat: Tree, idx: Int, isLast: Boolean - ): Option[(Int, Newlines.NumBlanks)] = - setStats(idx, stat, stat, isLast) + ): Option[(Int, Newlines.NumBlanks)] = setStats(idx, stat, stat, isLast) def blanks(cnt: => Int, edge: Boolean, edgeCnt: => Option[Int]): Int = if (edge) edgeCnt.getOrElse(math.min(cnt, 1)) else cnt @inline @@ -1475,10 +1426,8 @@ class FormatWriter(formatOps: FormatOps) { isLast: Boolean ): Unit = { val last = tokens.getLast(stat) - if (prevBlanks.beforeEndMarker <= 0) - extraBlankMap.remove(prevIdx) - else - extraBlankMap.update(prevIdx, prevBlanks.beforeEndMarker) + if (prevBlanks.beforeEndMarker <= 0) extraBlankMap.remove(prevIdx) + else extraBlankMap.update(prevIdx, prevBlanks.beforeEndMarker) val cnt = blanksAfter(prevBlanks, isLast) val afterFt = trailingComment(last, end) setFtCheck(afterFt, cnt, afterFt eq last) @@ -1505,8 +1454,9 @@ class FormatWriter(formatOps: FormatOps) { } val newImports = stat match { case t: ImportExportStat => - val (idxHead, head) = - imports.fold((idx, t)) { case (i, h, _) => (i, h) } + val (idxHead, head) = imports.fold((idx, t)) { case (i, h, _) => + (i, h) + } if (!isLast) Some((idxHead, head, t)) else { setStats(idxHead, head, t, true) @@ -1582,8 +1532,7 @@ class FormatWriter(formatOps: FormatOps) { case pkg: Pkg => indentedPackage(pkg) case _ => true } - ) - beforeBody(stats)(_.hasTopStatBlankLines) + ) beforeBody(stats)(_.hasTopStatBlankLines) setTopStats(t, stats) super.apply(stats) // skip ref } @@ -1592,8 +1541,7 @@ class FormatWriter(formatOps: FormatOps) { } } - if (locations.length == tokens.length) - trav(topSourceTree) + if (locations.length == tokens.length) trav(topSourceTree) extraBlankMap.toMap } @@ -1642,8 +1590,7 @@ class FormatWriter(formatOps: FormatOps) { private def getAlignOwnerNonComment(ft: FormatToken): Tree = ft.meta.rightOwner match { - case name: Term.Name => - name.parent match { + case name: Term.Name => name.parent match { case Some(p: Term.ApplyInfix) => p case _ => name } @@ -1658,28 +1605,27 @@ class FormatWriter(formatOps: FormatOps) { ): Int = { val endOfLineOwner = eol.meta.rightOwner @tailrec - def iter(pairs: Seq[(AlignStop, AlignStop)], cnt: Int): Int = - pairs match { - case (r1, r2) +: tail => - val ft1 = r1.floc.formatToken - val ft2 = r2.floc.formatToken - def checkEol = r1.floc.style.align.multiline || { - val row1Owner = getAlignOwnerNonComment(ft1) - val row2Owner = getAlignOwnerNonComment(ft2) - def isRowOwner(x: Tree) = (x eq row1Owner) || (x eq row2Owner) - TreeOps.findTreeWithParentSimple(endOfLineOwner)(isRowOwner).isEmpty - } - // skip checking if row1 and row2 matches if both of them continues to a single line of comment - // in order to vertical align adjacent single lines of comment. - // see: https://github.com/scalameta/scalafmt/issues/1242 - val slc1 = tokens.isRightLikeSingleLineComment(ft1) - val slc2 = tokens.isRightLikeSingleLineComment(ft2) - val ok = - if (slc1) slc2 - else !slc2 && sameOwner && (r1.hashKey == r2.hashKey) && checkEol - if (ok) iter(tail, cnt + 1) else cnt - case _ => cnt - } + def iter(pairs: Seq[(AlignStop, AlignStop)], cnt: Int): Int = pairs match { + case (r1, r2) +: tail => + val ft1 = r1.floc.formatToken + val ft2 = r2.floc.formatToken + def checkEol = r1.floc.style.align.multiline || { + val row1Owner = getAlignOwnerNonComment(ft1) + val row2Owner = getAlignOwnerNonComment(ft2) + def isRowOwner(x: Tree) = (x eq row1Owner) || (x eq row2Owner) + TreeOps.findTreeWithParentSimple(endOfLineOwner)(isRowOwner).isEmpty + } + // skip checking if row1 and row2 matches if both of them continues to a single line of comment + // in order to vertical align adjacent single lines of comment. + // see: https://github.com/scalameta/scalafmt/issues/1242 + val slc1 = tokens.isRightLikeSingleLineComment(ft1) + val slc2 = tokens.isRightLikeSingleLineComment(ft2) + val ok = + if (slc1) slc2 + else !slc2 && sameOwner && (r1.hashKey == r2.hashKey) && checkEol + if (ok) iter(tail, cnt + 1) else cnt + case _ => cnt + } iter(a.zip(b), 0) } @@ -1706,8 +1652,10 @@ object FormatWriter { // first token is BOF formatToken.meta.idx <= 1 || state.prev.split.isNL def isStandalone: Boolean = hasBreakAfter && hasBreakBefore - @inline def isNotRemoved: Boolean = leftLineId != NoLine - @inline def remove: FormatLocation = copy(leftLineId = NoLine) + @inline + def isNotRemoved: Boolean = leftLineId != NoLine + @inline + def remove: FormatLocation = copy(leftLineId = NoLine) } class AlignStop(val column: Int, val floc: FormatLocation, val hashKey: Int) @@ -1799,9 +1747,12 @@ object FormatWriter { stopColumns = IndexedSeq.empty } - @inline def isEmpty: Boolean = buffer.isEmpty - @inline def hasMultiple: Boolean = buffer.lengthCompare(1) > 0 - @inline def foreach[A](f: AlignLine => A): Unit = buffer.foreach(f) + @inline + def isEmpty: Boolean = buffer.isEmpty + @inline + def hasMultiple: Boolean = buffer.lengthCompare(1) > 0 + @inline + def foreach[A](f: AlignLine => A): Unit = buffer.foreach(f) } /** Separator length gap needed to align blocks with different token lengths @@ -1875,8 +1826,8 @@ object FormatWriter { private val mlcParagraphBeg = Pattern.compile("^(?:[-*@=]|\\d++[.:])") private val leadingAsteriskSpace = Pattern.compile("(?<=\n)\\h*+(?=[*][^*])") - private val docstringLine = - Pattern.compile("^(?:\\h*+\\*)?(\\h*+)(.*?)\\h*+$", Pattern.MULTILINE) + private val docstringLine = Pattern + .compile("^(?:\\h*+\\*)?(\\h*+)(.*?)\\h*+$", Pattern.MULTILINE) private val emptyLines = "\\h*+(\n\\h*+\\*?\\h*+)*" private val emptyDocstring = Pattern.compile(s"^/\\*\\*$emptyLines\\*/$$") private val onelineDocstring = { @@ -1890,8 +1841,8 @@ object FormatWriter { if (pipe == '|') leadingPipeSpace else compileStripMarginPattern(pipe) @inline - private def compileStripMarginPattern(pipe: Char) = - Pattern.compile(s"(?<=\n)\\h*+(?=\\$pipe)") + private def compileStripMarginPattern(pipe: Char) = Pattern + .compile(s"(?<=\n)\\h*+(?=\\$pipe)") private val leadingPipeSpace = compileStripMarginPattern('|') @@ -1915,19 +1866,16 @@ object FormatWriter { val label = t.name.toString if (label.isEmpty) "given" else label case t: Defn.Type => t.name.toString - case t: Defn.Val => - t.pats match { + case t: Defn.Val => t.pats match { case List(Pat.Var(n)) => n.toString case _ => "val" } - case t: Defn.Var => - t.pats match { + case t: Defn.Var => t.pats match { case List(Pat.Var(n)) => n.toString case _ => "var" } // other - case t: Pkg => - t.ref match { + case t: Pkg => t.ref match { case x: Term.Name => x.toString case x: Term.Select => x.name.toString case _ => null @@ -1942,18 +1890,18 @@ object FormatWriter { case _ => null } - @inline private def getLineDiff( - beg: FormatLocation, - end: FormatLocation - ): Int = beg.leftLineId - end.leftLineId + @inline + private def getLineDiff(beg: FormatLocation, end: FormatLocation): Int = + beg.leftLineId - end.leftLineId - @inline private def getLineDiff( + @inline + private def getLineDiff( toks: Array[FormatLocation], beg: FormatToken, end: FormatToken ): Int = getLineDiff(toks(beg.meta.idx), toks(end.meta.idx)) - def isEmptyDocstring(text: String): Boolean = - emptyDocstring.matcher(text).matches() + def isEmptyDocstring(text: String): Boolean = emptyDocstring.matcher(text) + .matches() } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Indent.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Indent.scala index 93bbeddd29..4bdb1269f6 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Indent.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Indent.scala @@ -14,8 +14,8 @@ object ExpiresOn { } case object Before extends ExpiresOn { - def notExpiredBy(ft: FormatToken, expireEnd: Int): Boolean = - ft.right.end < expireEnd + def notExpiredBy(ft: FormatToken, expireEnd: Int): Boolean = ft.right.end < + expireEnd } @inline @@ -55,8 +55,8 @@ case class ActualIndent( reset: Boolean ) { @inline - def notExpiredBy(ft: FormatToken): Boolean = - expiresAt.notExpiredBy(ft, expireEnd) + def notExpiredBy(ft: FormatToken): Boolean = expiresAt + .notExpiredBy(ft, expireEnd) } abstract class Indent { @@ -85,15 +85,14 @@ private class IndentImpl(length: Length, expire: Token, expiresAt: ExpiresOn) extends Indent { override def hasStateColumn: Boolean = length eq Length.StateColumn override def switch(trigger: Token, on: Boolean): Indent = this - override def withStateOffset(offset: Int): Option[ActualIndent] = - Some( - ActualIndent( - length.withStateOffset(offset), - expire.end, - expiresAt, - length.reset - ) + override def withStateOffset(offset: Int): Option[ActualIndent] = Some( + ActualIndent( + length.withStateOffset(offset), + expire.end, + expiresAt, + length.reset ) + ) override def toString: String = { val when = if (expiresAt == ExpiresOn.Before) '<' else '>' s"$length$when$expire:${expire.end}" @@ -108,7 +107,8 @@ object Indent { case x => new IndentImpl(x, expire, expiresAt) } - @inline def empty: Indent = Empty + @inline + def empty: Indent = Empty case object Empty extends Indent { override def withStateOffset(offset: Int): Option[ActualIndent] = None override def switch(trigger: Token, on: Boolean): Indent = this @@ -120,8 +120,8 @@ object Indent { override def switch(trigger: Token, on: Boolean): Indent = if (trigger ne this.trigger) this else { if (on) before else after.switch(trigger, false) } - override def withStateOffset(offset: Int): Option[ActualIndent] = - before.withStateOffset(offset) + override def withStateOffset(offset: Int): Option[ActualIndent] = before + .withStateOffset(offset) override def hasStateColumn: Boolean = before.hasStateColumn override def toString: String = s"$before>($trigger:${trigger.end})?$after" } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/ModExt.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/ModExt.scala index 0da8ba2e4b..363a431f31 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/ModExt.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/ModExt.scala @@ -8,10 +8,7 @@ import scala.meta.tokens.Token * @param indents * Does this add indentation? */ -case class ModExt( - mod: Modification, - indents: Seq[Indent] = Seq.empty -) { +case class ModExt(mod: Modification, indents: Seq[Indent] = Seq.empty) { lazy val indentation = indents.mkString("[", ", ", "]") @inline @@ -27,20 +24,18 @@ case class ModExt( length: => Length, expire: Option[Token], when: ExpiresOn - ): ModExt = - expire.fold(this)(withIndent(length, _, when)) + ): ModExt = expire.fold(this)(withIndent(length, _, when)) - def withIndent(indent: => Indent): ModExt = - indent match { - case Indent.Empty => this - case x => withIndentImpl(x) - } + def withIndent(indent: => Indent): ModExt = indent match { + case Indent.Empty => this + case x => withIndentImpl(x) + } - def withIndentOpt(indent: => Option[Indent]): ModExt = - indent.fold(this)(withIndent(_)) + def withIndentOpt(indent: => Option[Indent]): ModExt = indent + .fold(this)(withIndent(_)) - def withIndents(indents: Seq[Indent]): ModExt = - indents.foldLeft(this)(_ withIndent _) + def withIndents(indents: Seq[Indent]): ModExt = indents + .foldLeft(this)(_ withIndent _) private def withIndentImpl(indent: Indent): ModExt = copy(indents = indent +: indents) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Modification.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Modification.scala index 645505cebe..5f46b5cca2 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Modification.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Modification.scala @@ -3,7 +3,8 @@ package org.scalafmt.internal sealed abstract class Modification { val newlines: Int val length: Int - @inline final def isNewline: Boolean = newlines != 0 + @inline + final def isNewline: Boolean = newlines != 0 } case class Provided(ft: FormatToken) extends Modification { diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Policy.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Policy.scala index eb9e1617c7..9040af8b07 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Policy.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Policy.scala @@ -24,8 +24,8 @@ abstract class Policy { if (other.isEmpty) this else new Policy.OrElse(this, other) @inline - final def unexpiredOpt(ft: FormatToken): Option[Policy] = - Some(unexpired(ft)).filter(_.nonEmpty) + final def unexpiredOpt(ft: FormatToken): Option[Policy] = Some(unexpired(ft)) + .filter(_.nonEmpty) @inline final def &(other: Option[Policy]): Policy = other.fold(this)(&) @@ -59,42 +59,30 @@ object Policy { override def noDequeue: Boolean = false } - def apply( - endPolicy: End.WithPos, - noDequeue: Boolean = false, - rank: Int = 0 - )(f: Pf)(implicit fileLine: FileLine): Policy = + def apply(endPolicy: End.WithPos, noDequeue: Boolean = false, rank: Int = 0)( + f: Pf + )(implicit fileLine: FileLine): Policy = new ClauseImpl(f, endPolicy, noDequeue, rank) - def after( - token: Token, - noDequeue: Boolean = false, - rank: Int = 0 - )(f: Pf)(implicit fileLine: FileLine): Policy = - apply(End.After(token), noDequeue, rank)(f) + def after(token: Token, noDequeue: Boolean = false, rank: Int = 0)(f: Pf)( + implicit fileLine: FileLine + ): Policy = apply(End.After(token), noDequeue, rank)(f) - def before( - token: Token, - noDequeue: Boolean = false, - rank: Int = 0 - )(f: Pf)(implicit fileLine: FileLine): Policy = - apply(End.Before(token), noDequeue, rank)(f) + def before(token: Token, noDequeue: Boolean = false, rank: Int = 0)(f: Pf)( + implicit fileLine: FileLine + ): Policy = apply(End.Before(token), noDequeue, rank)(f) def after(trigger: Token, policy: Policy)(implicit fileLine: FileLine - ): Policy = - new Switch(NoPolicy, trigger, policy) + ): Policy = new Switch(NoPolicy, trigger, policy) def before(policy: Policy, trigger: Token)(implicit fileLine: FileLine - ): Policy = - new Switch(policy, trigger, NoPolicy) + ): Policy = new Switch(policy, trigger, NoPolicy) - def on( - token: Token, - noDequeue: Boolean = false - )(f: Pf)(implicit fileLine: FileLine): Policy = - apply(End.On(token), noDequeue)(f) + def on(token: Token, noDequeue: Boolean = false)(f: Pf)(implicit + fileLine: FileLine + ): Policy = apply(End.On(token), noDequeue)(f) abstract class Clause(implicit val fileLine: FileLine) extends Policy { val endPolicy: End.WithPos @@ -126,17 +114,16 @@ object Policy { override def rank: Int = math.min(p1.rank, p2.rank) - override def unexpired(ft: FormatToken): Policy = - p1.unexpired(ft) | p2.unexpired(ft) + override def unexpired(ft: FormatToken): Policy = p1.unexpired(ft) | + p2.unexpired(ft) - override def filter(pred: Clause => Boolean): Policy = - p1.filter(pred) | p2.filter(pred) + override def filter(pred: Clause => Boolean): Policy = p1.filter(pred) | + p2.filter(pred) - override def switch(trigger: Token, on: Boolean): Policy = - p1.switch(trigger, on) | p2.switch(trigger, on) + override def switch(trigger: Token, on: Boolean): Policy = p1 + .switch(trigger, on) | p2.switch(trigger, on) - override def noDequeue: Boolean = - p1.noDequeue || p2.noDequeue + override def noDequeue: Boolean = p1.noDequeue || p2.noDequeue override def toString: String = s"($p1 | $p2)" } @@ -151,17 +138,16 @@ object Policy { override def rank: Int = math.min(p1.rank, p2.rank) - override def unexpired(ft: FormatToken): Policy = - p1.unexpired(ft) & p2.unexpired(ft) + override def unexpired(ft: FormatToken): Policy = p1.unexpired(ft) & + p2.unexpired(ft) - override def filter(pred: Clause => Boolean): Policy = - p1.filter(pred) & p2.filter(pred) + override def filter(pred: Clause => Boolean): Policy = p1.filter(pred) & + p2.filter(pred) - override def switch(trigger: Token, on: Boolean): Policy = - p1.switch(trigger, on) & p2.switch(trigger, on) + override def switch(trigger: Token, on: Boolean): Policy = p1 + .switch(trigger, on) & p2.switch(trigger, on) - override def noDequeue: Boolean = - p1.noDequeue || p2.noDequeue + override def noDequeue: Boolean = p1.noDequeue || p2.noDequeue override def toString: String = s"($p1 & $p2)" } @@ -185,13 +171,11 @@ object Policy { object Delay { def apply(policy: Policy, begPolicy: End.WithPos)(implicit fileLine: FileLine - ): Policy = - if (policy.isEmpty) policy else new Delay(policy, begPolicy) + ): Policy = if (policy.isEmpty) policy else new Delay(policy, begPolicy) } - class Relay(before: Policy, after: Policy)(implicit - fileLine: FileLine - ) extends Policy { + class Relay(before: Policy, after: Policy)(implicit fileLine: FileLine) + extends Policy { override def f: Pf = before.f override def rank: Int = before.rank override def filter(pred: Clause => Boolean): Policy = conv(_.filter(pred)) @@ -233,18 +217,15 @@ object Policy { private def conv(func: Policy => Policy): Policy = { val filtered = func(before) - if (filtered eq before) this - else new Switch(filtered, trigger, after) + if (filtered eq before) this else new Switch(filtered, trigger, after) } } object Proxy { - def apply( - policy: Policy, - end: End.WithPos - )(factory: Policy => Pf)(implicit fileLine: FileLine): Policy = - if (policy.isEmpty) NoPolicy - else new Proxy(policy, factory, end) + def apply(policy: Policy, end: End.WithPos)( + factory: Policy => Pf + )(implicit fileLine: FileLine): Policy = + if (policy.isEmpty) NoPolicy else new Proxy(policy, factory, end) } private class Proxy( @@ -283,25 +264,22 @@ object Policy { def notExpiredBy(ft: FormatToken): Boolean } case object After extends End { - def apply(endPos: Int): WithPos = - new End.WithPos { - def notExpiredBy(ft: FormatToken): Boolean = ft.left.end <= endPos - override def toString: String = s">$endPos" - } + def apply(endPos: Int): WithPos = new End.WithPos { + def notExpiredBy(ft: FormatToken): Boolean = ft.left.end <= endPos + override def toString: String = s">$endPos" + } } case object Before extends End { - def apply(endPos: Int): WithPos = - new End.WithPos { - def notExpiredBy(ft: FormatToken): Boolean = ft.right.end < endPos - override def toString: String = s"<$endPos" - } + def apply(endPos: Int): WithPos = new End.WithPos { + def notExpiredBy(ft: FormatToken): Boolean = ft.right.end < endPos + override def toString: String = s"<$endPos" + } } case object On extends End { - def apply(endPos: Int): WithPos = - new End.WithPos { - def notExpiredBy(ft: FormatToken): Boolean = ft.right.end <= endPos - override def toString: String = s"@$endPos" - } + def apply(endPos: Int): WithPos = new End.WithPos { + def notExpiredBy(ft: FormatToken): Boolean = ft.right.end <= endPos + override def toString: String = s"@$endPos" + } } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/PolicySummary.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/PolicySummary.scala index 52b67fef11..a78ef100ea 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/PolicySummary.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/PolicySummary.scala @@ -7,24 +7,22 @@ import org.scalafmt.util.LoggerOps class PolicySummary(val policies: Seq[Policy]) extends AnyVal { import LoggerOps._ - @inline def noDequeue = policies.exists(_.noDequeue) + @inline + def noDequeue = policies.exists(_.noDequeue) def combine(other: Policy, ft: FormatToken): PolicySummary = if (ft.right.is[Token.EOF]) PolicySummary.empty - else - new PolicySummary( - (other +: policies).flatMap(_.unexpiredOpt(ft)).sortBy(_.rank) - ) + else new PolicySummary( + (other +: policies).flatMap(_.unexpiredOpt(ft)).sortBy(_.rank) + ) - def execute(decision: Decision, debug: Boolean = false): Decision = - policies.foldLeft(decision) { case (result, policy) => + def execute(decision: Decision, debug: Boolean = false): Decision = policies + .foldLeft(decision) { case (result, policy) => def withSplits(splits: Seq[Split]): Decision = { if (debug) logger.debug(s"$policy defined at $result") result.withSplits(splits) } - policy.f - .andThen(withSplits _) - .applyOrElse(result, identity[Decision]) + policy.f.andThen(withSplits _).applyOrElse(result, identity[Decision]) } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala index 7066451681..1016d72f40 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala @@ -70,38 +70,34 @@ class Router(formatOps: FormatOps) { case FormatToken(_: T.EOF, _, _) => Seq(Split(Newline, 0)) case ft @ FormatToken(_, _: T.BOF, _) => Seq(Split(NoSplit.orNL(next(ft).right.is[T.EOF]), 0)) - case FormatToken(_: T.BOF, _, _) => - Seq( - Split(NoSplit, 0) - ) - case FormatToken(_, _: T.EOF, _) => - Seq( + case FormatToken(_: T.BOF, _, _) => Seq(Split(NoSplit, 0)) + case FormatToken(_, _: T.EOF, _) => Seq( Split(Newline, 0) // End files with trailing newline ) case FormatToken(start: T.Interpolation.Start, _, m) => val end = matching(start) - val okNewlines = - style.newlines.inInterpolation.ne(Newlines.InInterpolation.avoid) && - isTripleQuote(m.left.text) + val okNewlines = style.newlines.inInterpolation + .ne(Newlines.InInterpolation.avoid) && isTripleQuote(m.left.text) def policy = PenalizeAllNewlines(end, BreakSingleLineInterpolatedString) val split = Split(NoSplit, 0).withPolicy(policy, okNewlines) - val alignIndents = if (style.align.stripMargin) { - findInterpolate(leftOwner).flatMap { ti => - getStripMarginChar(ti).map { pipe => - val startsWithPipe = ti.parts.headOption match { - case Some(Lit.String(x)) => x.headOption.contains(pipe) - case _ => false + val alignIndents = + if (style.align.stripMargin) { + findInterpolate(leftOwner).flatMap { ti => + getStripMarginChar(ti).map { pipe => + val startsWithPipe = ti.parts.headOption match { + case Some(Lit.String(x)) => x.headOption.contains(pipe) + case _ => false + } + Seq( + Indent(StateColumn, end, After), + // -1 because of margin characters | + Indent(if (startsWithPipe) -1 else -2, end, After) + ) } - Seq( - Indent(StateColumn, end, After), - // -1 because of margin characters | - Indent(if (startsWithPipe) -1 else -2, end, After) - ) } - } - } else None - val indents = - alignIndents.getOrElse(Seq(Indent(style.indent.main, end, After))) + } else None + val indents = alignIndents + .getOrElse(Seq(Indent(style.indent.main, end, After))) Seq(split.withIndents(indents)) // Interpolation case FormatToken( @@ -109,23 +105,15 @@ class Router(formatOps: FormatOps) { _: T.Interpolation.Start | _: T.Interpolation.SpliceStart, _, _ - ) => - Seq( - Split(NoSplit, 0) - ) + ) => Seq(Split(NoSplit, 0)) case FormatToken( _, - T.Interpolation.Part(_) | T.Interpolation.End() | - T.Interpolation.SpliceEnd(), + T.Interpolation.Part(_) | T.Interpolation.End() | T.Interpolation + .SpliceEnd(), _ - ) => - Seq( - Split(NoSplit, 0) - ) + ) => Seq(Split(NoSplit, 0)) case FormatToken(T.LeftBrace(), T.RightBrace(), _) => - Seq( - Split(NoSplit, 0) - ) + Seq(Split(NoSplit, 0)) // Import case FormatToken(_: T.Dot, _, _) if existsParentOfType[ImportExportStat](rightOwner) => @@ -146,22 +134,18 @@ class Router(formatOps: FormatOps) { val mustUseNL = newlines != 0 && tokens.isRightCommentThenBreak(formatToken) val newlinePolicy = style.importSelectors match { - case ImportSelectors.singleLine if mustUseNL => - policy + case ImportSelectors.singleLine if mustUseNL => policy case ImportSelectors.singleLine if !mustDangleForTrailingCommas => NoPolicy - case ImportSelectors.binPack => - newlineBeforeClosingCurly - case _ => - newlineBeforeClosingCurly & splitOneArgOneLine(close, leftOwner) + case ImportSelectors.binPack => newlineBeforeClosingCurly + case _ => newlineBeforeClosingCurly & + splitOneArgOneLine(close, leftOwner) } Seq( Split(Space(style.spaces.inImportCurlyBraces), 0) - .notIf(mustUseNL || mustDangleForTrailingCommas) - .withPolicy(policy), - Split(Newline, 1) - .onlyIf(newlinePolicy ne NoPolicy) + .notIf(mustUseNL || mustDangleForTrailingCommas).withPolicy(policy), + Split(Newline, 1).onlyIf(newlinePolicy ne NoPolicy) .withPolicy(newlinePolicy) .withIndent(style.indent.main, close, Before) ) @@ -186,11 +170,9 @@ class Router(formatOps: FormatOps) { Split(Space(style.spaces.inInterpolatedStringCurlyBraces), 0) .withIndents(alignIndents.getOrElse(Nil)) def newlineSplit(cost: Int)(implicit fileLine: FileLine) = { - def mainIndents = Seq( - Indent(style.indent.main, close, ExpiresOn.Before) - ) - Split(Newline, cost) - .withIndents(alignIndents.getOrElse(mainIndents)) + def mainIndents = + Seq(Indent(style.indent.main, close, ExpiresOn.Before)) + Split(Newline, cost).withIndents(alignIndents.getOrElse(mainIndents)) .withPolicy(decideNewlinesOnlyBeforeClose(close)) } def isSimpleInterpolate = (leftOwner match { @@ -202,8 +184,7 @@ class Router(formatOps: FormatOps) { style.newlines.inInterpolation match { case Newlines.InInterpolation.avoid => Seq(spaceSplit) - case _ if style.newlines.keepBreak(newlines) => - Seq(newlineSplit(0)) + case _ if style.newlines.keepBreak(newlines) => Seq(newlineSplit(0)) case Newlines.InInterpolation.allow if !dialect.allowSignificantIndentation || isSimpleInterpolate => Seq(spaceSplit) @@ -217,10 +198,7 @@ class Router(formatOps: FormatOps) { val afterClose = tokens(close, 3) val lastPart = afterClose.left.is[T.Interpolation.End] val slbEnd = if (lastPart) afterClose.left else afterClose.right - Seq( - spaceSplit.withSingleLine(slbEnd), - newlineSplit(1) - ) + Seq(spaceSplit.withSingleLine(slbEnd), newlineSplit(1)) } case FormatToken(_, _: T.RightBrace, _) if isInterpolate(rightOwner) => @@ -235,8 +213,7 @@ class Router(formatOps: FormatOps) { _: T.KwFor | _: T.KwDo | _: T.KwWhile | _: T.KwYield | _: T.KwIf, _, OptionalBraces(splits) - ) if dialect.allowSignificantIndentation => - splits + ) if dialect.allowSignificantIndentation => splits // { ... } Blocks case tok @ FormatToken(open @ T.LeftBrace(), right, _) => @@ -256,8 +233,9 @@ class Router(formatOps: FormatOps) { if (rightIsComment && tok.noBreak) Space else { val double = tok.hasBlankLine || - !isSelfAnnotationNL && - rightIsComment && blankLineBeforeDocstring(tok) + !isSelfAnnotationNL && rightIsComment && blankLineBeforeDocstring( + tok + ) NewlineT(double) } @@ -265,8 +243,8 @@ class Router(formatOps: FormatOps) { val (lambdaExpire, lambdaArrow, lambdaIndent, lambdaNLOnly) = startsStatement(right) match { case Some(owner: Term.FunctionTerm) if (leftOwner match { - case t: Template => - t.parent.exists(_.is[Term.NewAnonymous]) && + case t: Template => t.parent + .exists(_.is[Term.NewAnonymous]) && isSingleElement(t.stats, owner) case _ => true }) => @@ -280,14 +258,15 @@ class Router(formatOps: FormatOps) { ) None else Some(false) (expire, arrow.map(_.left), 0, nlOnly) - case Some(t: Case) if t.cond.isEmpty && (leftOwner match { - case x: Term.PartialFunction => - isSingleElement(x.cases, t) - case x: Term.Match => - isSingleElement(x.cases, t) && getMatchDot(x).isDefined - case _: Term.Try => false - case _ => tokens.tokenAfter(t).right eq close - }) => + case Some(t: Case) + if t.cond.isEmpty && + (leftOwner match { + case x: Term.PartialFunction => isSingleElement(x.cases, t) + case x: Term.Match => isSingleElement(x.cases, t) && + getMatchDot(x).isDefined + case _: Term.Try => false + case _ => tokens.tokenAfter(t).right eq close + }) => val arrow = getCaseArrow(t) val nlOnly = if (style.newlines.alwaysBeforeCurlyLambdaParams) Some(true) @@ -311,20 +290,18 @@ class Router(formatOps: FormatOps) { if (lambdaExpire == null) null else { val arrowOptimal = getOptimalTokenFor(lambdaExpire) - newlineBeforeClosingCurly & - SingleLineBlock(arrowOptimal) & + newlineBeforeClosingCurly & SingleLineBlock(arrowOptimal) & decideNewlinesOnlyAfterToken(arrowOptimal) } def getSingleLineDecision = { type Classifiers = Seq[Classifier[T, _]] - def classifiersByParent: Classifiers = - leftOwner.parent match { - case Some(_: Term.If) => Seq(T.KwElse.classifier) - case Some(_: Term.Try | _: Term.TryWithHandler) => - Seq(T.KwCatch.classifier, T.KwFinally.classifier) - case _ => Seq.empty - } + def classifiersByParent: Classifiers = leftOwner.parent match { + case Some(_: Term.If) => Seq(T.KwElse.classifier) + case Some(_: Term.Try | _: Term.TryWithHandler) => + Seq(T.KwCatch.classifier, T.KwFinally.classifier) + case _ => Seq.empty + } val classifiers: Classifiers = leftOwner match { // for catch with case, we should go up only one level case _: Term.Try if rightOwner.is[Case] => @@ -340,8 +317,7 @@ class Router(formatOps: FormatOps) { else decideNewlinesOnlyAfterClose(close) } def getClassicSingleLineDecisionOpt = - if (newlines > 0) None - else Some(getSingleLineDecision) + if (newlines > 0) None else Some(getSingleLineDecision) def getSingleLineLambdaDecisionOpt = { val ok = !lambdaNLOnly.contains(true) && @@ -354,8 +330,8 @@ class Router(formatOps: FormatOps) { case Newlines.keep if newlines != 0 => None case Newlines.unfold => None case Newlines.fold => - val isTopLevelBlock = - leftOwner.parent.exists(_.parent.isEmpty) || (leftOwner match { + val isTopLevelBlock = leftOwner.parent.exists(_.parent.isEmpty) || + (leftOwner match { case t: Template => // false for // new A { () => @@ -373,39 +349,35 @@ class Router(formatOps: FormatOps) { // do not fold top-level blocks if (isTopLevelBlock) None else if (lambdaPolicy != null) getSingleLineLambdaDecisionOpt - else - Some(getSingleLineDecision match { - case NoPolicy if leftOwner.is[Term.ForYield] => - val postClose = nextNonComment(closeFT).right - val bodySlb = SingleLineBlock(getLastToken(leftOwner)) - new Policy.Delay(bodySlb, Policy.End.On(postClose)) - case x => x - }) + else Some(getSingleLineDecision match { + case NoPolicy if leftOwner.is[Term.ForYield] => + val postClose = nextNonComment(closeFT).right + val bodySlb = SingleLineBlock(getLastToken(leftOwner)) + new Policy.Delay(bodySlb, Policy.End.On(postClose)) + case x => x + }) // old behaviour case _ => if (lambdaPolicy == null) getClassicSingleLineDecisionOpt else getSingleLineLambdaDecisionOpt } - val singleLineSplit = - singleLineDecisionOpt.fold(Split.ignored) { sld => - val expire = endOfSingleLineBlock(closeFT) - Split(xmlSpace(leftOwner), 0) - .withSingleLine(expire, noSyntaxNL = true, killOnFail = true) - .andPolicy(sld) - } + val singleLineSplit = singleLineDecisionOpt.fold(Split.ignored) { sld => + val expire = endOfSingleLineBlock(closeFT) + Split(xmlSpace(leftOwner), 0) + .withSingleLine(expire, noSyntaxNL = true, killOnFail = true) + .andPolicy(sld) + } val splits = Seq( singleLineSplit, - Split(nl, 1) - .withPolicy(newlineBeforeClosingCurly) + Split(nl, 1).withPolicy(newlineBeforeClosingCurly) .withIndent(style.indent.main, close, Before), Split(Space, 0) .onlyIf(lambdaNLOnly.contains(false) && lambdaPolicy != null) .notIf(style.newlines.keepBreak(newlines)) .withOptimalTokenOpt(lambdaArrow) - .withIndent(lambdaIndent, close, Before) - .withPolicy(lambdaPolicy) + .withIndent(lambdaIndent, close, Before).withPolicy(lambdaPolicy) ) right match { case t: T.Xml.Start => withIndentOnXmlStart(t, splits) @@ -425,11 +397,10 @@ class Router(formatOps: FormatOps) { else if ( afterCurlySpace && (!rightOwner.is[Defn] || style.newlines.source.eq(Newlines.fold)) + ) Split(Space, 0).withSingleLineNoOptimal( + getOptimalTokenFor(getLastNonTrivial(leftFunc.body).left), + noSyntaxNL = true ) - Split(Space, 0).withSingleLineNoOptimal( - getOptimalTokenFor(getLastNonTrivial(leftFunc.body).left), - noSyntaxNL = true - ) else Split.ignored val (endIndent, expiresOn) = functionExpire(leftFunc) Seq( @@ -455,32 +426,29 @@ class Router(formatOps: FormatOps) { val indent = // don't indent if the body is empty `{ x => }` if (isEmptyFunctionBody(leftOwner) && !right.is[T.Comment]) 0 else if (leftOwner.is[Template]) 0 // { applied the indent - else - (leftOwner.parent match { - case Some(ac: Term.ArgClause) => ac.parent - case Some(x: Term) => - x.parent.flatMap { - case ac: Term.ArgClause => ac.parent - case _ => None - } - case _ => None - }) match { - case Some(p: Term.Apply) if isFewerBraces(p) => - style.indent.getSignificant - case _ => style.indent.main - } + else (leftOwner.parent match { + case Some(ac: Term.ArgClause) => ac.parent + case Some(x: Term) => x.parent.flatMap { + case ac: Term.ArgClause => ac.parent + case _ => None + } + case _ => None + }) match { + case Some(p: Term.Apply) if isFewerBraces(p) => + style.indent.getSignificant + case _ => style.indent.main + } def noSingleLine = { // for constructors with empty args lambda // new Foo { () => // println("wow") // } - val isCurlyLambda = - leftOwner.is[Template] || leftOwner.parent.exists(_.is[Template]) + val isCurlyLambda = leftOwner.is[Template] || + leftOwner.parent.exists(_.is[Template]) - def noSquash = - style.newlines.afterCurlyLambdaParams ne - Newlines.AfterCurlyLambdaParams.squash + def noSquash = style.newlines.afterCurlyLambdaParams ne + Newlines.AfterCurlyLambdaParams.squash style.newlines.source match { case Newlines.fold => false @@ -489,23 +457,19 @@ class Router(formatOps: FormatOps) { case Newlines.classic => isCurlyLambda && newlines != 0 && noSquash } } - val singleLineSplit = - Split(Space, 0) - .notIf(hasSingleLineComment || noSingleLine) - .withSingleLineNoOptimal(endOfFunction) - def newlineSplit = - Split(Newline, 1 + nestedApplies(leftOwner)) - .withIndent(indent, endOfFunction, expiresOn) + val singleLineSplit = Split(Space, 0) + .notIf(hasSingleLineComment || noSingleLine) + .withSingleLineNoOptimal(endOfFunction) + def newlineSplit = Split(Newline, 1 + nestedApplies(leftOwner)) + .withIndent(indent, endOfFunction, expiresOn) val multiLineSplits = - if (hasSingleLineComment) - Seq(newlineSplit) + if (hasSingleLineComment) Seq(newlineSplit) else { // 2020-01: break after same-line comments, and any open brace val nonComment = nextNonCommentSameLine(formatToken) val hasBlock = nonComment.right.is[T.LeftBrace] && (matching(nonComment.right) eq endOfFunction) - if (!hasBlock && (nonComment eq formatToken)) - Seq(newlineSplit) + if (!hasBlock && (nonComment eq formatToken)) Seq(newlineSplit) else { // break after the brace or comment if fits, or now if doesn't // if brace, don't add indent, the LeftBrace rule will do that @@ -549,8 +513,7 @@ class Router(formatOps: FormatOps) { if (style.newlines.source ne Newlines.unfold) withSlbSplit else Seq(nlSplit(ft)(0)) } else if ( - condIsDefined || - beforeMultiline.eq(Newlines.classic) || + condIsDefined || beforeMultiline.eq(Newlines.classic) || getSingleStatExceptEndMarker(body).isEmpty ) withSlbSplit else { @@ -582,37 +545,28 @@ class Router(formatOps: FormatOps) { def nlSplit(cost: Int = 0)(implicit fileLine: FileLine) = Split(Newline, cost).withIndent(style.indent.main, expireToken, After) style.newlines.source match { - case Newlines.unfold => - Seq(nlSplit()) - case Newlines.keep if newlines != 0 => - Seq(nlSplit()) + case Newlines.unfold => Seq(nlSplit()) + case Newlines.keep if newlines != 0 => Seq(nlSplit()) case _ => - Seq( - Split(Space, 0).withSingleLine(expireToken), - nlSplit(cost = 1) - ) + Seq(Split(Space, 0).withSingleLine(expireToken), nlSplit(cost = 1)) } case tok @ FormatToken(left, right, StartsStatementRight(_)) => - val expire = rightOwner.tokens - .find(_.is[T.Equals]) + val expire = rightOwner.tokens.find(_.is[T.Equals]) .fold(getLastToken(rightOwner)) { equalsToken => val equalsFormatToken = tokens(equalsToken) if (equalsFormatToken.right.is[T.LeftBrace]) { equalsFormatToken.right - } else { - equalsToken - } + } else { equalsToken } } val annoRight = right.is[T.At] val annoLeft = isSingleIdentifierAnnotation(prev(tok)) if ( - (annoRight || annoLeft) && - style.optIn.annotationNewlines && !style.newlines.sourceIgnored - ) - Seq(Split(getMod(formatToken), 0)) + (annoRight || annoLeft) && style.optIn.annotationNewlines && + !style.newlines.sourceIgnored + ) Seq(Split(getMod(formatToken), 0)) else { maybeGetInfixSplitsBeforeLhs( formatToken, @@ -621,38 +575,31 @@ class Router(formatOps: FormatOps) { else NewlineT(isDouble = tok.hasBlankLine) ) ) { - val spaceCouldBeOk = annoLeft && (style.newlines.source match { - case Newlines.unfold => - right.is[T.Comment] || - !style.optIn.annotationNewlines && annoRight - case Newlines.fold => - right.is[T.Comment] || annoRight || - !style.optIn.annotationNewlines && Reserved.unapply(right) - case Newlines.keep => - newlines == 0 && (annoRight || Reserved.unapply(right)) - case _ => - newlines == 0 && Reserved.unapply(right) - }) + val spaceCouldBeOk = annoLeft && + (style.newlines.source match { + case Newlines.unfold => right.is[T.Comment] || + !style.optIn.annotationNewlines && annoRight + case Newlines.fold => right.is[T.Comment] || annoRight || + !style.optIn.annotationNewlines && Reserved.unapply(right) + case Newlines.keep => newlines == 0 && + (annoRight || Reserved.unapply(right)) + case _ => newlines == 0 && Reserved.unapply(right) + }) Seq( // This split needs to have an optimalAt field. - Split(Space, 0) - .onlyIf(spaceCouldBeOk) - .withSingleLine(expire), + Split(Space, 0).onlyIf(spaceCouldBeOk).withSingleLine(expire), // For some reason, this newline cannot cost 1. Split(NewlineT(isDouble = tok.hasBlankLine), 0) ) } } - case FormatToken(_, T.RightBrace(), _) => - Seq( + case FormatToken(_, T.RightBrace(), _) => Seq( Split(xmlSpace(rightOwner), 0), Split(NewlineT(isDouble = formatToken.hasBlankLine), 0) ) case FormatToken(_: T.KwPackage, _, _) if leftOwner.is[Pkg] => - Seq( - Split(Space, 0) - ) + Seq(Split(Space, 0)) // Opening [ with no leading space. // Opening ( with no leading space. case ft @ FormatToken(left, open @ LeftParenOrBracket(), _) @@ -665,8 +612,7 @@ class Router(formatOps: FormatOps) { case _ => true } case _: T.RightBracket | _: T.KwSuper | _: T.KwThis | _: T.Ident | - _: T.Underscore | _: T.Constant.Symbol => - true + _: T.Underscore | _: T.Constant.Symbol => true case _ => false } } => @@ -678,17 +624,15 @@ class Router(formatOps: FormatOps) { // https://github.com/scalameta/scalafmt/pull/1516 // https://github.com/scalameta/scalafmt/issues/1528 case t: Init => t.parent.forall(_.is[Mod.Annot]) - case Term.Name(name) => - style.spaces.afterTripleEquals && name == "===" || + case Term.Name(name) => style.spaces.afterTripleEquals && + name == "===" || (rightOwner match { - case _: Term.ArgClause => - style.spaces.beforeApplyArgInParens(name) - case _: Member.ParamClause => - style.spaces.afterSymbolicDefs && isSymbolicName(name) + case _: Term.ArgClause => style.spaces.beforeApplyArgInParens(name) + case _: Member.ParamClause => style.spaces.afterSymbolicDefs && + isSymbolicName(name) case _ => false }) - case _: Defn.ExtensionGroup => - style.spaces.afterKeywordBeforeParen && + case _: Defn.ExtensionGroup => style.spaces.afterKeywordBeforeParen && soft.KwExtension.unapply(left) case _ => false }) @@ -712,55 +656,44 @@ class Router(formatOps: FormatOps) { case Newlines.unfold => val rightParent = rightOwner.parent.get val slbEnd = - if (defn) - beforeDefRhs - .fold(getLastToken(rightParent))(prevNonComment(_).left) + if (defn) beforeDefRhs + .fold(getLastToken(rightParent))(prevNonComment(_).left) else getLastToken(getLastCall(rightParent)) val multipleArgs = isSeqMulti(getArgs(next(ft).meta.leftOwner)) val nft = tokens.tokenAfter(close) val nlPolicy = nft.right match { case t: T.LeftParen => decideNewlinesOnlyBeforeClose(t) case t: T.Colon - if defn && (nft.left.is[T.Comment] || - style.newlines.sometimesBeforeColonInMethodReturnType - && defDefReturnType(rightOwner).isDefined) => + if defn && + (nft.left.is[T.Comment] || + style.newlines.sometimesBeforeColonInMethodReturnType && + defDefReturnType(rightOwner).isDefined) => decideNewlinesOnlyBeforeClose(t) case _ => NoPolicy } Seq( baseNoSplit.withSingleLine(slbEnd), - Split(Newline, 1) - .withIndent(indent) - .withPolicy( - penalizeNewlineByNesting(open, close), - multipleArgs - ) - .andPolicy(nlPolicy) + Split(Newline, 1).withIndent(indent).withPolicy( + penalizeNewlineByNesting(open, close), + multipleArgs + ).andPolicy(nlPolicy) ) case Newlines.keep => - if (newlines != 0) - Seq(Split(Newline, 0).withIndent(indent)) - else - Seq( - noSplitSplit, - Split(Newline, 1).withIndent(indent) - ) + if (newlines != 0) Seq(Split(Newline, 0).withIndent(indent)) + else Seq(noSplitSplit, Split(Newline, 1).withIndent(indent)) case _ => def nlColonPolicy = if (!style.newlines.sometimesBeforeColonInMethodReturnType) None else if (!defn) None - else - defDefReturnType(rightOwner).flatMap { declTpe => - tokenBefore(declTpe).left match { - case t: T.Colon => Some(decideNewlinesOnlyBeforeClose(t)) - case _ => None - } + else defDefReturnType(rightOwner).flatMap { declTpe => + tokenBefore(declTpe).left match { + case t: T.Colon => Some(decideNewlinesOnlyBeforeClose(t)) + case _ => None } + } Seq( noSplitSplit, - Split(Newline, 1) - .withIndent(indent) - .withPolicyOpt(nlColonPolicy) + Split(Newline, 1).withIndent(indent).withPolicyOpt(nlColonPolicy) ) } val argsOpt = if (isAlignFirstParen) lastSyntaxClause else None @@ -769,40 +702,36 @@ class Router(formatOps: FormatOps) { Indent(StateColumn, x, ExpiresOn.Before), Indent(-indentLen, x, ExpiresOn.Before) ) - splits.map { s => - if (s.isNL) s else s.withIndents(noSplitIndents) - } + splits.map { s => if (s.isNL) s else s.withIndents(noSplitIndents) } } } val beforeOpenParenSplits = if (!open.is[T.LeftParen]) None - else if (defn) - style.newlines.getBeforeOpenParenDefnSite.map { x => - val beforeBody = defRhs.flatMap { - case t: Template => templateCurlyFt(t) - case _ => beforeDefRhs - } - val indent = beforeBody.fold(style.indent.main) { y => - val ob = OptionalBraces.get(y).nonEmpty - style.indent.extraBeforeOpenParenDefnSite + - (if (ob) style.indent.getSignificant else style.indent.main) - } - getSplitsBeforeOpenParen(x, indent, _.beforeOpenParenDefnSite) { - @tailrec - def iter(tree: Tree): Option[Member.ParamClause] = tree match { - case _: Member.ParamClause => - tree.parent match { - case Some(p) => iter(p) - case None => None - } - case p: Tree.WithParamClauses => p.paramClauses.lastOption - case _ => None - } - iter(rightOwner) + else if (defn) style.newlines.getBeforeOpenParenDefnSite.map { x => + val beforeBody = defRhs.flatMap { + case t: Template => templateCurlyFt(t) + case _ => beforeDefRhs + } + val indent = beforeBody.fold(style.indent.main) { y => + val ob = OptionalBraces.get(y).nonEmpty + style.indent.extraBeforeOpenParenDefnSite + + (if (ob) style.indent.getSignificant else style.indent.main) + } + getSplitsBeforeOpenParen(x, indent, _.beforeOpenParenDefnSite) { + @tailrec + def iter(tree: Tree): Option[Member.ParamClause] = tree match { + case _: Member.ParamClause => tree.parent match { + case Some(p) => iter(p) + case None => None + } + case p: Tree.WithParamClauses => p.paramClauses.lastOption + case _ => None } + iter(rightOwner) } - else if (style.dialect.allowSignificantIndentation) - style.newlines.getBeforeOpenParenCallSite.map { x => + } + else if (style.dialect.allowSignificantIndentation) style.newlines + .getBeforeOpenParenCallSite.map { x => val indent = style.indent.getSignificant @tailrec def findLastCallArgs(t: Member.Apply): Member.ArgClause = @@ -811,8 +740,9 @@ class Router(formatOps: FormatOps) { case _ => t.argClause } getSplitsBeforeOpenParen(x, indent, _.beforeOpenParenCallSite) { - rightOwner.parent - .collect { case p: Member.Apply => findLastCallArgs(p) } + rightOwner.parent.collect { case p: Member.Apply => + findLastCallArgs(p) + } } } else None @@ -834,15 +764,13 @@ class Router(formatOps: FormatOps) { } val policy = if (style.binPack.keepParentConstructors) None - else - template.tokens.headOption.map { head => - val policyEnd = Policy.End.Before(head) - delayedBreakPolicy(policyEnd)(forceNewlineBeforeExtends) - } + else template.tokens.headOption.map { head => + val policyEnd = Policy.End.Before(head) + delayedBreakPolicy(policyEnd)(forceNewlineBeforeExtends) + } Seq(Split(Space, 0).withPolicyOpt(policy)) // DefDef - case FormatToken(_: T.KwDef, _: T.Ident, _) => - Seq(Split(Space, 0)) + case FormatToken(_: T.KwDef, _: T.Ident, _) => Seq(Split(Space, 0)) case ft @ FormatToken(_: T.Equals, _, DefValAssignLeft(rhs)) => maybeGetInfixSplitsBeforeLhs(ft) { getSplitsDefValEquals(ft, rhs) { @@ -855,8 +783,7 @@ class Router(formatOps: FormatOps) { // on the WHOLE defnSite (via policies) case ft @ FormatToken(LeftParenOrBracket(), _, _) if style.verticalMultiline.atDefnSite && - isParamClauseSite(leftOwner) => - verticalMultiline(ft)(style) + isParamClauseSite(leftOwner) => verticalMultiline(ft)(style) // Term.Apply and friends case FormatToken(lp: T.LeftParen, _, LambdaAtSingleArgCallSite(lambda)) => @@ -872,8 +799,8 @@ class Router(formatOps: FormatOps) { else getNoSplit(formatToken, true) def multilineSpaceSplit(implicit fileLine: FileLine): Split = { - val lambdaLeft: Option[T] = - matchingOpt(functionExpire(lambda)._1).filter(_.is[T.LeftBrace]) + val lambdaLeft: Option[T] = matchingOpt(functionExpire(lambda)._1) + .filter(_.is[T.LeftBrace]) val arrowFt = getFuncArrow(lambda).get val lambdaIsABlock = lambdaLeft.contains(arrowFt.right) @@ -882,22 +809,17 @@ class Router(formatOps: FormatOps) { val spacePolicy = SingleLineBlock(lambdaToken) | { if (lambdaIsABlock) None - else - newlinePolicy.map( - delayedBreakPolicy(Policy.End.On(lambdaLeft.getOrElse(close))) - ) + else newlinePolicy + .map(delayedBreakPolicy(Policy.End.On(lambdaLeft.getOrElse(close)))) } - Split(noSplitMod, 0) - .withPolicy(spacePolicy) + Split(noSplitMod, 0).withPolicy(spacePolicy) .withOptimalToken(lambdaToken) } - if (noSplitMod == null) - Seq( - Split(Newline, 0) - .withPolicyOpt(newlinePolicy) - .withIndent(style.indent.callSite, close, Before) - ) + if (noSplitMod == null) Seq( + Split(Newline, 0).withPolicyOpt(newlinePolicy) + .withIndent(style.indent.callSite, close, Before) + ) else { val newlinePenalty = 3 + nestedApplies(leftOwner) val noMultiline = style.newlines.beforeCurlyLambdaParams eq @@ -905,8 +827,7 @@ class Router(formatOps: FormatOps) { Seq( Split(noSplitMod, 0).withSingleLine(close), if (noMultiline) Split.ignored else multilineSpaceSplit, - Split(Newline, newlinePenalty) - .withPolicyOpt(newlinePolicy) + Split(Newline, newlinePenalty).withPolicyOpt(newlinePolicy) .withIndent(style.indent.callSite, close, Before) ) } @@ -916,11 +837,9 @@ class Router(formatOps: FormatOps) { Seq(Split(NoSplit.orNL(noNL), 0)) case tok @ FormatToken(open @ LeftParenOrBracket(), right, _) if { - if (isArgClauseSite(leftOwner)) - style.binPack.callSite(open).isNever - else - style.binPack.defnSite(open).isNever && - isParamClauseSite(leftOwner) + if (isArgClauseSite(leftOwner)) style.binPack.callSite(open).isNever + else style.binPack.defnSite(open).isNever && + isParamClauseSite(leftOwner) } => val close = matching(open) val closeFormatToken = tokens(close) @@ -934,8 +853,7 @@ class Router(formatOps: FormatOps) { // parens furthest to the right. def leftOwnerIsEnclosed = leftOwner.is[Member.Function] val lhsPenalty = leftOwner match { - case t: Member.SyntaxValuesClause => - t.parent match { + case t: Member.SyntaxValuesClause => t.parent match { case Some(p: Init) => treeDepth(p.tpe) case Some(p: Member.Apply) => treeDepth(p.fun) case Some(_: Member.Function) => maxTreeDepth(t.values) @@ -962,35 +880,30 @@ class Router(formatOps: FormatOps) { val arg = args(0) val maybeEnclosed = arg.parent match { case Some(p: Member.SyntaxValuesClause) - if lhsPenalty != 0 && !p.is[Member.ArgClause] => - p + if lhsPenalty != 0 && !p.is[Member.ArgClause] => p case _ => arg } val isEnclosed = tokens.isEnclosedInMatching(maybeEnclosed) if (isEnclosed) (maybeEnclosed, true) else (arg, false) } else (null, false) - val useConfigStyle = onlyConfigStyle || (sourceIgnored && - style.optIn.configStyleArguments && !isSingleEnclosedArgument) + val useConfigStyle = onlyConfigStyle || + (sourceIgnored && style.optIn.configStyleArguments && + !isSingleEnclosedArgument) val nestedPenalty = 1 + nestedApplies(leftOwner) + lhsPenalty val indent = - if (anyDefnSite) - Num(style.indent.getDefnSite(leftOwner)) - else - Num(style.indent.callSite) + if (anyDefnSite) Num(style.indent.getDefnSite(leftOwner)) + else Num(style.indent.callSite) val isBeforeOpenParen = - if (defnSite) - style.newlines.isBeforeOpenParenDefnSite - else - style.newlines.isBeforeOpenParenCallSite + if (defnSite) style.newlines.isBeforeOpenParenDefnSite + else style.newlines.isBeforeOpenParenCallSite val expirationToken: T = if (isBeforeOpenParen) close else if (defnSite && !isBracket) defnSiteLastToken(closeFormatToken, leftOwner) - else - rhsOptimalToken(closeFormatToken) + else rhsOptimalToken(closeFormatToken) val mustDangleForTrailingCommas = getMustDangleForTrailingCommas(beforeClose) @@ -1006,15 +919,12 @@ class Router(formatOps: FormatOps) { val newlinePolicy: Policy = if (wouldDangle || mustDangle) { decideNewlinesOnlyBeforeClose(close) - } else { - Policy.NoPolicy - } + } else { Policy.NoPolicy } // covers using as well - val handleImplicit = !tupleSite && ( - if (onlyConfigStyle) opensConfigStyleImplicitParamList(formatToken) - else hasImplicitParamList(rightOwner) - ) + val handleImplicit = !tupleSite && + (if (onlyConfigStyle) opensConfigStyleImplicitParamList(formatToken) + else hasImplicitParamList(rightOwner)) val noSplitMod = if ( @@ -1022,54 +932,49 @@ class Router(formatOps: FormatOps) { if (!handleImplicit) onlyConfigStyle else style.newlines.forceBeforeImplicitParamListModifier } - ) - null + ) null else getNoSplit(formatToken, !isBracket) val noSplitIndent = if (rightIsComment) indent else Num(0) val align = !rightIsComment && { if (tupleSite) style.align.getOpenParenTupleSite else style.align.getOpenDelimSite(isBracket, defnSite) - } && (!handleImplicit || - style.newlines.forceAfterImplicitParamListModifier) + } && + (!handleImplicit || style.newlines.forceAfterImplicitParamListModifier) val alignTuple = align && tupleSite && !onlyConfigStyle val keepConfigStyleSplit = !sourceIgnored && style.optIn.configStyleArguments && newlines != 0 val splitsForAssign = if (defnSite || isBracket || keepConfigStyleSplit) None - else - getAssignAtSingleArgCallSite(args).map { assign => - val assignToken = assign.rhs match { - case b: Term.Block => tokens.getHead(b) - case _ => tokens(assign.tokens.find(_.is[T.Equals]).get) - } - val breakToken = getOptimalTokenFor(assignToken) - val newlineAfterAssignDecision = - if (newlinePolicy.isEmpty) Policy.NoPolicy - else decideNewlinesOnlyAfterToken(breakToken) - Seq( - Split(Newline, nestedPenalty + Constants.ExceedColumnPenalty) - .withPolicy(newlinePolicy) - .withIndent(indent, close, Before), - Split(NoSplit, nestedPenalty) - .withSingleLine(breakToken) - .andPolicy(newlinePolicy & newlineAfterAssignDecision) - ) + else getAssignAtSingleArgCallSite(args).map { assign => + val assignToken = assign.rhs match { + case b: Term.Block => tokens.getHead(b) + case _ => tokens(assign.tokens.find(_.is[T.Equals]).get) } - - def isExcludedTree(tree: Tree): Boolean = - tree match { - case t: Init => t.argClauses.nonEmpty - case t: Term.Apply => t.argClause.nonEmpty - case t: Term.ApplyType => t.argClause.nonEmpty - case t: Term.Match => t.cases.nonEmpty - case t: Type.Match => t.cases.nonEmpty - case t: Term.New => t.init.argClauses.nonEmpty - case _: Term.NewAnonymous => true - case _ => false + val breakToken = getOptimalTokenFor(assignToken) + val newlineAfterAssignDecision = + if (newlinePolicy.isEmpty) Policy.NoPolicy + else decideNewlinesOnlyAfterToken(breakToken) + Seq( + Split(Newline, nestedPenalty + Constants.ExceedColumnPenalty) + .withPolicy(newlinePolicy).withIndent(indent, close, Before), + Split(NoSplit, nestedPenalty).withSingleLine(breakToken) + .andPolicy(newlinePolicy & newlineAfterAssignDecision) + ) } + def isExcludedTree(tree: Tree): Boolean = tree match { + case t: Init => t.argClauses.nonEmpty + case t: Term.Apply => t.argClause.nonEmpty + case t: Term.ApplyType => t.argClause.nonEmpty + case t: Term.Match => t.cases.nonEmpty + case t: Type.Match => t.cases.nonEmpty + case t: Term.New => t.init.argClauses.nonEmpty + case _: Term.NewAnonymous => true + case _ => false + } + val excludeBlocks = if (isBracket) { val excludeBeg = if (align) tokens.getHead(args.last) else tok @@ -1078,8 +983,7 @@ class Router(formatOps: FormatOps) { multipleArgs || (!isSingleEnclosedArgument || leftOwnerIsEnclosed) && style.newlines.source.eq(Newlines.unfold) - ) - TokenRanges.empty + ) TokenRanges.empty else if ( style.newlines.source.eq(Newlines.fold) && { isSingleEnclosedArgument || @@ -1096,15 +1000,10 @@ class Router(formatOps: FormatOps) { if (multipleArgs && (isBracket || excludeBlocks.ranges.isEmpty)) { SingleLineBlock(close, noSyntaxNL = true) } else if (isBracket) { - PenalizeAllNewlines( - close, - newlinePenalty, - penalizeLambdas = false - ) + PenalizeAllNewlines(close, newlinePenalty, penalizeLambdas = false) } else { val penalty = - if (!multipleArgs) newlinePenalty - else Constants.ShouldBeNewline + if (!multipleArgs) newlinePenalty else Constants.ShouldBeNewline policyWithExclude(excludeBlocks, Policy.End.On, Policy.End.On)( Policy.End.Before(close), new PenalizeAllNewlines( @@ -1119,11 +1018,12 @@ class Router(formatOps: FormatOps) { val keepNoNL = style.newlines.source.eq(Newlines.keep) && tok.noBreak val preferNoSplit = keepNoNL && singleArgument - val oneArgOneLine = newlinePolicy & (leftOwner match { - case t @ (_: Member.SyntaxValuesClause | _: Member.Tuple) => - splitOneArgOneLine(close, t) - case _ => Policy.NoPolicy - }) + val oneArgOneLine = newlinePolicy & + (leftOwner match { + case t @ (_: Member.SyntaxValuesClause | _: Member.Tuple) => + splitOneArgOneLine(close, t) + case _ => Policy.NoPolicy + }) val extraOneArgPerLineIndent = if (multipleArgs && style.poorMansTrailingCommasInConfigStyle) Indent(Num(2), right, After) @@ -1134,14 +1034,12 @@ class Router(formatOps: FormatOps) { val splitsNoNL = if (noSplitMod == null) Seq.empty - else if (onlyConfigStyle) - Seq( - Split(noSplitMod, 0) - .withPolicy(oneArgOneLine & implicitPolicy) - .withOptimalToken(right, killOnFail = true) - .withIndent(extraOneArgPerLineIndent) - .withIndent(indent, close, Before) - ) + else if (onlyConfigStyle) Seq( + Split(noSplitMod, 0).withPolicy(oneArgOneLine & implicitPolicy) + .withOptimalToken(right, killOnFail = true) + .withIndent(extraOneArgPerLineIndent) + .withIndent(indent, close, Before) + ) else { val noSplitPolicy = if (preferNoSplit && splitsForAssign.isEmpty) singleLine(2) @@ -1151,22 +1049,19 @@ class Router(formatOps: FormatOps) { exclude = excludeBlocks, noSyntaxNL = multipleArgs ) - else if (splitsForAssign.isDefined) - singleLine(3) - else - singleLine(10) + else if (splitsForAssign.isDefined) singleLine(3) + else singleLine(10) Seq( Split(noSplitMod, 0, policy = noSplitPolicy) .notIf(mustDangleForTrailingCommas) .withOptimalToken(expirationToken) .withIndent(noSplitIndent, close, Before), Split(noSplitMod, (implicitPenalty + lhsPenalty) * bracketCoef) - .withPolicy(oneArgOneLine & implicitPolicy) - .onlyIf( - (notTooManyArgs && align) || (handleImplicit && - style.newlines.notBeforeImplicitParamListModifier) - ) - .withIndents( + .withPolicy(oneArgOneLine & implicitPolicy).onlyIf( + (notTooManyArgs && align) || + (handleImplicit && + style.newlines.notBeforeImplicitParamListModifier) + ).withIndents( if (align) getOpenParenAlignIndents(close) else Seq(Indent(indent, close, ExpiresOn.Before)) ) @@ -1175,28 +1070,23 @@ class Router(formatOps: FormatOps) { val splitsNL = if ( - alignTuple || !(onlyConfigStyle || - multipleArgs || splitsForAssign.isEmpty) - ) - Seq.empty + alignTuple || + !(onlyConfigStyle || multipleArgs || splitsForAssign.isEmpty) + ) Seq.empty else { val cost = - if (onlyConfigStyle) - if (splitsNoNL.isEmpty) 0 else 1 - else - (if (preferNoSplit) Constants.ExceedColumnPenalty else 0) + - bracketCoef * (nestedPenalty + (if (multipleArgs) 2 else 0)) + if (onlyConfigStyle) if (splitsNoNL.isEmpty) 0 else 1 + else (if (preferNoSplit) Constants.ExceedColumnPenalty else 0) + + bracketCoef * (nestedPenalty + (if (multipleArgs) 2 else 0)) val split = - if (multipleArgs) - Split(Newline, cost, policy = oneArgOneLine) - .withIndent(extraOneArgPerLineIndent) + if (multipleArgs) Split(Newline, cost, policy = oneArgOneLine) + .withIndent(extraOneArgPerLineIndent) else { val noSplit = !onlyConfigStyle && right.is[T.LeftBrace] - val noConfigStyle = noSplit || - newlinePolicy.isEmpty || !style.optIn.configStyleArguments + val noConfigStyle = noSplit || newlinePolicy.isEmpty || + !style.optIn.configStyleArguments Split(NoSplit.orNL(noSplit), cost, policy = newlinePolicy) - .andPolicy(singleLine(4), !noConfigStyle) - .andPolicyOpt( + .andPolicy(singleLine(4), !noConfigStyle).andPolicyOpt( asInfixApp(args.head).map(InfixSplits(_, tok).nlPolicy), !singleArgument ) @@ -1212,33 +1102,30 @@ class Router(formatOps: FormatOps) { val close = matching(open) def slbPolicy = SingleLineBlock(close, okSLC = true, noSyntaxNL = true) val baseNoSplitMod = Space(style.spaces.inParentheses) - if (close eq right) - Seq(Split(baseNoSplitMod, 0)) + if (close eq right) Seq(Split(baseNoSplitMod, 0)) else { val isBracket = open.is[T.LeftBracket] - val indent = - Indent(style.indent.getDefnSite(leftOwner), close, Before) + val indent = Indent(style.indent.getDefnSite(leftOwner), close, Before) val align = style.align.getOpenDelimSite(isBracket, true) val noSplitIndents = if (align) getOpenParenAlignIndents(close) else Seq(indent) val bracketPenalty = if (isBracket) Some(Constants.BracketPenalty) else None - val penalizeBrackets = - bracketPenalty.map(p => PenalizeAllNewlines(close, p + 3)) + val penalizeBrackets = bracketPenalty + .map(p => PenalizeAllNewlines(close, p + 3)) val beforeClose = tokens.justBefore(close) val onlyConfigStyle = mustUseConfigStyle(formatToken, beforeClose) || getMustDangleForTrailingCommas(beforeClose) val argsHeadOpt = argumentStarts.get(hash(right)) val isSingleArg = isSeqSingle(getArgs(leftOwner)) - val oneline = - style.binPack.defnSite(isBracket) == BinPack.Unsafe.Oneline + val oneline = style.binPack.defnSite(isBracket) == + BinPack.Unsafe.Oneline val nlOnelinePolicy = argsHeadOpt.flatMap { x => if (isSingleArg || !oneline) None - else - findFirstOnRight[T.Comma](tokens.getLast(x), close) - .map(splitOneArgPerLineAfterCommaOnBreak) + else findFirstOnRight[T.Comma](tokens.getLast(x), close) + .map(splitOneArgPerLineAfterCommaOnBreak) } val mustDangle = onlyConfigStyle || @@ -1278,8 +1165,7 @@ class Router(formatOps: FormatOps) { Seq( Split(mustUseNL, 0)(noSplitModification) .withOptimalToken(close, ignore = !slbOnly, killOnFail = true) - .withPolicy(noSplitPolicy) - .withIndents(noSplitIndents), + .withPolicy(noSplitPolicy).withIndents(noSplitIndents), Split(nlMod, if (mustUseNL || slbOnly) 0 else nlCost) .withPolicy(nlDanglePolicy & nlOnelinePolicy & penalizeBrackets) .withIndent(indent) @@ -1300,10 +1186,10 @@ class Router(formatOps: FormatOps) { val singleArgAsInfix = if (isSingleArg) firstArg.flatMap(asInfixApp) else None - val opensLiteralArgumentList = - styleMap.opensLiteralArgumentList(formatToken) - val singleLineOnly = - style.binPack.literalsSingleLine && opensLiteralArgumentList + val opensLiteralArgumentList = styleMap + .opensLiteralArgumentList(formatToken) + val singleLineOnly = style.binPack.literalsSingleLine && + opensLiteralArgumentList val mustDangleForTrailingCommas = getMustDangleForTrailingCommas(beforeClose) @@ -1321,16 +1207,17 @@ class Router(formatOps: FormatOps) { val nextCommaOneline = if (!oneline || isSingleArg) None else firstArg.map(tokens.getLast).flatMap(findComma) - val needOnelinePolicy = oneline && (nextCommaOneline.isDefined || - leftOwner.parent.exists(followedBySelectOrApply)) - val nextCommaOnelinePolicy = if (needOnelinePolicy) { - nextCommaOneline.map(splitOneArgPerLineAfterCommaOnBreak) - } else None + val needOnelinePolicy = oneline && + (nextCommaOneline.isDefined || + leftOwner.parent.exists(followedBySelectOrApply)) + val nextCommaOnelinePolicy = + if (needOnelinePolicy) { + nextCommaOneline.map(splitOneArgPerLineAfterCommaOnBreak) + } else None val indentLen = style.indent.callSite val indent = Indent(Num(indentLen), close, Before) - val noNoSplitIndents = nlOnly || - singleArgAsInfix.isDefined || + val noNoSplitIndents = nlOnly || singleArgAsInfix.isDefined || isSingleArg && oneline && !needOnelinePolicy || !isBracket && getAssignAtSingleArgCallSite(args).isDefined val noSplitIndents = @@ -1351,8 +1238,7 @@ class Router(formatOps: FormatOps) { ) getOpenParenAlignIndents(close) else Seq(indent) def baseNoSplit(implicit fileLine: FileLine) = - Split(Space(style.spaces.inParentheses), 0) - .withIndents(noSplitIndents) + Split(Space(style.spaces.inParentheses), 0).withIndents(noSplitIndents) val exclude = if (!isBracket) insideBracesBlock(formatToken, close) @@ -1366,8 +1252,7 @@ class Router(formatOps: FormatOps) { val noSplit = if (nlOnly) Split.ignored else if ( - singleLineOnly || - needOnelinePolicy && nextCommaOneline.isEmpty || + singleLineOnly || needOnelinePolicy && nextCommaOneline.isEmpty || // multiline binpack is at odds with unfold, at least force a break style.newlines.source.eq(Newlines.unfold) ) baseNoSplit.withSingleLine(close, noSyntaxNL = true) @@ -1377,15 +1262,17 @@ class Router(formatOps: FormatOps) { else if (style.newlines.source.eq(Newlines.fold)) None else findComma(formatToken).orElse(Some(close)) def unindentPolicy = unindentAtExclude(exclude, Num(-indentLen)) - val noSplitPolicy = if (needOnelinePolicy) { - val alignPolicy = if (noSplitIndents.exists(_.hasStateColumn)) { - nextCommaOnelinePolicy.map(_ & penalizeNewlinesPolicy) - } else None - alignPolicy.getOrElse { - val slbEnd = nextCommaOneline.getOrElse(close) - SingleLineBlock(slbEnd, noSyntaxNL = true) - } - } else penalizeNewlinesPolicy + val noSplitPolicy = + if (needOnelinePolicy) { + val alignPolicy = + if (noSplitIndents.exists(_.hasStateColumn)) { + nextCommaOnelinePolicy.map(_ & penalizeNewlinesPolicy) + } else None + alignPolicy.getOrElse { + val slbEnd = nextCommaOneline.getOrElse(close) + SingleLineBlock(slbEnd, noSyntaxNL = true) + } + } else penalizeNewlinesPolicy def indentOncePolicy = if (style.binPack.indentCallSiteOnce) { val trigger = getIndentTrigger(leftOwner) @@ -1395,29 +1282,27 @@ class Router(formatOps: FormatOps) { s.map { x => if (x.isNL) x else x.switch(trigger, false) } } } else NoPolicy - baseNoSplit - .withOptimalTokenOpt(opt) - .withPolicy(noSplitPolicy) + baseNoSplit.withOptimalTokenOpt(opt).withPolicy(noSplitPolicy) .andPolicy(unindentPolicy, !isSingleArg || noSplitIndents.isEmpty) .andPolicy(indentOncePolicy, noSplitIndents.isEmpty) } val nlPolicy = { def newlineBeforeClose = decideNewlinesOnlyBeforeClose(close) - def binPackOnelinePolicy = if (needOnelinePolicy) { - nextCommaOnelinePolicy - .getOrElse(decideNewlinesOnlyBeforeCloseOnBreak(close)) - } else NoPolicy + def binPackOnelinePolicy = + if (needOnelinePolicy) { + nextCommaOnelinePolicy + .getOrElse(decideNewlinesOnlyBeforeCloseOnBreak(close)) + } else NoPolicy if (onlyConfigStyle) { - if (styleMap.forcedBinPack(leftOwner)) - newlineBeforeClose & binPackOnelinePolicy + if (styleMap.forcedBinPack(leftOwner)) newlineBeforeClose & + binPackOnelinePolicy else splitOneArgOneLine(close, leftOwner) | newlineBeforeClose } else if ( mustDangleForTrailingCommas || style.danglingParentheses.tupleOrCallSite(isTuple(leftOwner)) && (style.newlines.sourceIgnored || !style.optIn.configStyleArguments) - ) - newlineBeforeClose & binPackOnelinePolicy + ) newlineBeforeClose & binPackOnelinePolicy else binPackOnelinePolicy } val nlMod = @@ -1435,8 +1320,8 @@ class Router(formatOps: FormatOps) { // Closing def site ): ReturnType case FormatToken(left, _: T.Colon, DefDefReturnTypeRight(returnType)) - if style.newlines.sometimesBeforeColonInMethodReturnType - || left.is[T.Comment] && newlines != 0 => + if style.newlines.sometimesBeforeColonInMethodReturnType || + left.is[T.Comment] && newlines != 0 => val expireFt = getLastNonTrivial(returnType) val expire = expireFt.left val sameLineSplit = Space(endsWithSymbolIdent(left)) @@ -1445,12 +1330,10 @@ class Router(formatOps: FormatOps) { def extraIfBody = style.indent.extraBeforeOpenParenDefnSite val indent = if (ob) style.indent.getSignificant + extraIfBody - else - style.indent.main + - (if (defDefBody(rightOwner).isEmpty) 0 else extraIfBody) + else style.indent.main + + (if (defDefBody(rightOwner).isEmpty) 0 else extraIfBody) Seq( - Split(sameLineSplit, 0) - .onlyIf(newlines == 0 || x.ne(Newlines.keep)) + Split(sameLineSplit, 0).onlyIf(newlines == 0 || x.ne(Newlines.keep)) .withSingleLine(expire), Split(Newline, 1).withIndent(indent, expire, After) ) @@ -1464,8 +1347,7 @@ class Router(formatOps: FormatOps) { // Spark style guide allows this: // https://github.com/databricks/scala-style-guide#indent Split(Newline, Constants.SparkColonNewline) - .withIndent(indent, expire, After) - .withPolicy(penalizeNewlines) + .withIndent(indent, expire, After).withPolicy(penalizeNewlines) ) } case FormatToken(_: T.Colon, _, DefDefReturnTypeLeft(returnType)) @@ -1474,21 +1356,13 @@ class Router(formatOps: FormatOps) { val policy = PenalizeAllNewlines(expire, Constants.ShouldBeNewline) Seq(Split(Space, 0).withPolicy(policy).withOptimalToken(expire)) - case FormatToken(T.LeftParen(), T.LeftBrace(), _) => - Seq( - Split(NoSplit, 0) - ) + case FormatToken(T.LeftParen(), T.LeftBrace(), _) => Seq(Split(NoSplit, 0)) case FormatToken(_, T.LeftBrace(), _) if isXmlBrace(rightOwner) => - withIndentOnXmlSpliceStart( - formatToken, - Seq(Split(NoSplit, 0)) - ) + withIndentOnXmlSpliceStart(formatToken, Seq(Split(NoSplit, 0))) case FormatToken(T.RightBrace(), _, _) if isXmlBrace(leftOwner) => - Seq( - Split(NoSplit, 0) - ) + Seq(Split(NoSplit, 0)) // non-statement starting curly brace case FormatToken(_: T.Comma, open: T.LeftBrace, _) if !style.poorMansTrailingCommasInConfigStyle && @@ -1500,24 +1374,22 @@ class Router(formatOps: FormatOps) { if (!binPackIsEnabled) Split(Space.orNL(useSpace), 0) else Split(Space, 0).onlyIf(useSpace).withSingleLine(close) val otherSplits = rightOwner match { - case _: Term.PartialFunction | Term.Block( - List(_: Term.FunctionTerm | _: Term.PartialFunction) - ) => + case _: Term.PartialFunction | Term + .Block(List(_: Term.FunctionTerm | _: Term.PartialFunction)) => Seq(Split(Newline, 0)) case _ => val breakAfter = rhsOptimalToken(next(nextNonCommentSameLine(formatToken))) - val multiLine = - decideNewlinesOnlyBeforeClose(close) | - decideNewlinesOnlyAfterToken(breakAfter) + val multiLine = decideNewlinesOnlyBeforeClose(close) | + decideNewlinesOnlyAfterToken(breakAfter) Seq( Split(Newline, 0).withSingleLine(close, killOnFail = true), Split(Space, 1, policy = multiLine) ) } val oneArgPerLineSplits = - if (binPackIsEnabled) - otherSplits.map(_.preActivateFor(SplitTag.OneArgPerLine)) + if (binPackIsEnabled) otherSplits + .map(_.preActivateFor(SplitTag.OneArgPerLine)) else otherSplits.map(_.onlyFor(SplitTag.OneArgPerLine)) singleSplit +: oneArgPerLineSplits @@ -1525,38 +1397,31 @@ class Router(formatOps: FormatOps) { _: T.MacroSplice | _: T.MacroQuote, _: T.LeftBrace | _: T.LeftBracket, _ - ) => - Seq(Split(NoSplit, 0)) + ) => Seq(Split(NoSplit, 0)) case FormatToken(_: T.KwMatch, _, _) => val indentLen = style.indent.matchSite.fold(0)(_ - style.indent.main) def expire = getLastNonTrivialToken(leftOwner) // should rbrace Seq(Split(Space, 0).withIndent(indentLen, expire, ExpiresOn.Before)) case FormatToken(_, lb: T.LeftBrace, _) if ! { // partial initial expr @tailrec - def startsInfix(ai: Term.ApplyInfix): Boolean = - ai.parent match { - case Some(_: Term.ArgClause) => false - case Some(p: Term.ApplyInfix) => startsInfix(p) - case _ => true - } + def startsInfix(ai: Term.ApplyInfix): Boolean = ai.parent match { + case Some(_: Term.ArgClause) => false + case Some(p: Term.ApplyInfix) => startsInfix(p) + case _ => true + } val roPos = rightOwner.pos isTokenHeadOrBefore(lb, roPos) && rightOwner.parent.exists { case p: Term.ApplyInfix => // exclude start of infix startsInfix(p) case _: Term.ArgClause => false - case p => - isTokenHeadOrBefore(lb, p) && - matchingOpt(lb).exists(isTokenLastOrAfter(_, roPos)) + case p => isTokenHeadOrBefore(lb, p) && matchingOpt(lb) + .exists(isTokenLastOrAfter(_, roPos)) } - } => - Seq(Split(Space, 0)) + } => Seq(Split(Space, 0)) // Delim case FormatToken(left, _: T.Comma, _) - if !left.is[T.Comment] || newlines == 0 => - Seq( - Split(NoSplit, 0) - ) + if !left.is[T.Comment] || newlines == 0 => Seq(Split(NoSplit, 0)) // These are mostly filtered out/modified by policies. case ft @ FormatToken(lc: T.Comma, _: T.Comment, m) => val nextFt = next(ft) @@ -1585,12 +1450,11 @@ class Router(formatOps: FormatOps) { val lastFT = tokens.getLast(nextArg) val loEnd = leftOwner.tokens.last.end val oneline = binPack == BinPack.Unsafe.Oneline - val nextCommaOrParen = - findFirst(lastFT, loEnd) { - case FormatToken(_, _: T.Comma, _) => true - case FormatToken(_, RightParenOrBracket(), _) => true - case _ => false - } + val nextCommaOrParen = findFirst(lastFT, loEnd) { + case FormatToken(_, _: T.Comma, _) => true + case FormatToken(_, RightParenOrBracket(), _) => true + case _ => false + } val optFT = nextCommaOrParen match { case Some(ft @ FormatToken(_, _: T.Comma, _)) if oneline => ft case Some(FormatToken(_, _: T.RightParen, _)) @@ -1641,33 +1505,24 @@ class Router(formatOps: FormatOps) { case _: Defn.RepeatedEnumCase if { if (!style.newlines.sourceIgnored) newlines != 0 else style.newlines.source eq Newlines.unfold - } => - Seq(Split(Newline, 0)) + } => Seq(Split(Newline, 0)) case _: ImportExportStat => val indent = Indent(style.indent.main, right, ExpiresOn.After) Seq(Split(Space, 0), Split(Newline, 1).withIndent(indent)) - case _ => - Seq(Split(Space, 0), Split(Newline, 1)) + case _ => Seq(Split(Space, 0), Split(Newline, 1)) } splitsOpt.getOrElse(altSplits) - case FormatToken(_, T.Semicolon(), _) => - Seq( - Split(NoSplit, 0) - ) + case FormatToken(_, T.Semicolon(), _) => Seq(Split(NoSplit, 0)) case FormatToken(_: T.KwReturn, _, _) => val mod = if (formatToken.hasBlankLine) Newline2x - else - leftOwner match { - case Term.Return(unit @ Lit.Unit()) if unit.tokens.isEmpty => - // Always force blank line for Unit "return". - Newline - case _ => - Space - } - Seq( - Split(mod, 0) - ) + else leftOwner match { + case Term.Return(unit @ Lit.Unit()) if unit.tokens.isEmpty => + // Always force blank line for Unit "return". + Newline + case _ => Space + } + Seq(Split(mod, 0)) /* * Type Bounds @@ -1675,15 +1530,13 @@ class Router(formatOps: FormatOps) { case FormatToken(_, _: T.Colon, _) if rightOwner.is[Type.Param] => val tp = rightOwner.asInstanceOf[Type.Param] - def noNLMod = Space( - style.spaces.beforeContextBoundColon match { - case Spaces.BeforeContextBound.Always => true - case Spaces.BeforeContextBound.IfMultipleBounds => - 1 < tp.cbounds.length + tp.vbounds.length + - tp.tbounds.lo.size + tp.tbounds.hi.size - case _ => false - } - ) + def noNLMod = Space(style.spaces.beforeContextBoundColon match { + case Spaces.BeforeContextBound.Always => true + case Spaces.BeforeContextBound.IfMultipleBounds => 1 < + tp.cbounds.length + + tp.vbounds.length + tp.tbounds.lo.size + tp.tbounds.hi.size + case _ => false + }) getSplitsForTypeBounds(formatToken, noNLMod, tp, _.cbounds) case FormatToken(_, _: T.Viewbound, _) if rightOwner.is[Type.Param] => val tp = rightOwner.asInstanceOf[Type.Param] @@ -1717,8 +1570,7 @@ class Router(formatOps: FormatOps) { case _: Type.Select | _: Importer | _: Pkg => Some(true) case _: Term.Select | _: Member.Apply => None case _ => Some(false) - }.isDefined => - Seq(Split(NoSplit, 0)) + }.isDefined => Seq(Split(NoSplit, 0)) case t @ FormatToken(left, _: T.Dot, _) if rightOwner.is[Term.Select] || @@ -1739,8 +1591,8 @@ class Router(formatOps: FormatOps) { def checkFewerBraces(tree: Tree) = tree match { case p: Term.Apply => isFewerBraces(p) case p: Term.Match => !tokenBefore(p.cases).left.is[T.LeftBrace] - case p: Term.NewAnonymous => - templateCurly(p.templ).exists(_.is[T.Colon]) + case p: Term.NewAnonymous => templateCurly(p.templ) + .exists(_.is[T.Colon]) case _ => false } val nextDotIfSig = nextSelect.flatMap { ns => @@ -1751,13 +1603,12 @@ class Router(formatOps: FormatOps) { val tree = selectLike.tree Policy.before(selectLike.nameToken) { case d @ Decision(FormatToken(_, _: T.Dot, m), _) - if m.rightOwner eq tree => - d.onlyNewlinesWithoutFallback + if m.rightOwner eq tree => d.onlyNewlinesWithoutFallback } } - def breakOnNextDot: Policy = - nextSelect.fold(Policy.noPolicy) { selectLike => + def breakOnNextDot: Policy = nextSelect + .fold(Policy.noPolicy) { selectLike => val tree = selectLike.tree Policy.before(selectLike.nameToken) { case Decision(FormatToken(_, _: T.Dot, m), s) @@ -1770,8 +1621,7 @@ class Router(formatOps: FormatOps) { else { val minCost = math.max(0, filtered.map(_.cost).min - 1) filtered.map { x => - val p = - x.policy.filter(!_.isInstanceOf[PenalizeAllNewlines]) + val p = x.policy.filter(!_.isInstanceOf[PenalizeAllNewlines]) x.copy(cost = x.cost - minCost, policy = p) } } @@ -1799,8 +1649,8 @@ class Router(formatOps: FormatOps) { if (canStartSelectChain(thisSelect, nextSelectTree, expireTree)) { val chainExpire = if (nextSelect.isEmpty) thisSelect.nameToken else expire - val nestedPenalty = - nestedSelect(rightOwner) + nestedApplies(leftOwner) + val nestedPenalty = nestedSelect(rightOwner) + + nestedApplies(leftOwner) // This policy will apply to both the space and newline splits, otherwise // the newline is too cheap even it doesn't actually prevent other newlines. val penalizeBreaks = PenalizeAllNewlines(chainExpire, 2) @@ -1811,7 +1661,8 @@ class Router(formatOps: FormatOps) { SingleLineBlock(chainExpire, exclude, noSyntaxNL = true) } val newlinePolicy = breakOnNextDot & penalizeBreaks - val ignoreNoSplit = nlOnly || t.hasBreak && + val ignoreNoSplit = nlOnly || + t.hasBreak && (left.is[T.Comment] || style.optIn.breakChainOnFirstMethodDot) val chainLengthPenalty = if ( @@ -1840,12 +1691,10 @@ class Router(formatOps: FormatOps) { Split(!prevChain, 1) { // must come first, for backwards compat if (style.optIn.breaksInsideChains) NoSplit.orNL(t.noBreak) else nlMod - } - .withPolicy(newlinePolicy) + }.withPolicy(newlinePolicy) .onlyFor(SplitTag.SelectChainSecondNL), Split(ignoreNoSplit, 0)(NoSplit) - .withPolicy(slbPolicy, prevChain) - .andPolicy(penalizeBreaks), + .withPolicy(slbPolicy, prevChain).andPolicy(penalizeBreaks), Split(if (ignoreNoSplit) Newline else nlMod, nlCost) .withPolicy(newlinePolicy) ) @@ -1857,18 +1706,15 @@ class Router(formatOps: FormatOps) { if (style.optIn.breaksInsideChains) NoSplit.orNL(t.noBreak) else if (doBreak) Newline else getNlMod - } - .withPolicy(breakOnNextDot) + }.withPolicy(breakOnNextDot) .onlyFor(SplitTag.SelectChainSecondNL), Split(if (doBreak) Newline else Space(isComment), 0) ) } - case _ if left.is[T.Comment] => - Seq(Split(Space.orNL(t.noBreak), 0)) + case _ if left.is[T.Comment] => Seq(Split(Space.orNL(t.noBreak), 0)) - case Newlines.keep => - Seq(Split(NoSplit.orNL(t.noBreak), 0)) + case Newlines.keep => Seq(Split(NoSplit.orNL(t.noBreak), 0)) case Newlines.unfold => val nlCost = if (nlOnly) 0 else 1 @@ -1891,8 +1737,8 @@ class Router(formatOps: FormatOps) { val noSplit = if (nlOnly) noSplitBase else { - val end = - nextSelect.fold(expire)(x => getLastNonTrivialToken(x.qual)) + val end = nextSelect + .fold(expire)(x => getLastNonTrivialToken(x.qual)) def exclude = insideBracesBlock(t, end, true) noSplitBase.withSingleLine(end, exclude) } @@ -1948,28 +1794,17 @@ class Router(formatOps: FormatOps) { // ApplyUnary case FormatToken(T.Ident(_), T.Literal(), _) if leftOwner == rightOwner => - Seq( - Split(NoSplit, 0) - ) + Seq(Split(NoSplit, 0)) case FormatToken(op: T.Ident, right, _) if leftOwner.parent.exists { - case unary: Term.ApplyUnary => - unary.op.tokens.head == op + case unary: Term.ApplyUnary => unary.op.tokens.head == op case _ => false - } => - Seq( - Split(Space(isSymbolicIdent(right)), 0) - ) + } => Seq(Split(Space(isSymbolicIdent(right)), 0)) // Annotations, see #183 for discussion on this. case FormatToken(_, _: T.At, _) if rightOwner.is[Pat.Bind] => - Seq( - Split(Space, 0) - ) + Seq(Split(Space, 0)) case FormatToken(_: T.At, _, _) if leftOwner.is[Pat.Bind] => - Seq( - Split(Space, 0) - ) - case FormatToken(T.At(), _: T.Symbolic, _) => - Seq(Split(NoSplit, 0)) + Seq(Split(Space, 0)) + case FormatToken(T.At(), _: T.Symbolic, _) => Seq(Split(NoSplit, 0)) case FormatToken(T.At(), right @ T.Ident(_), _) => // Add space if right starts with a symbol Seq(Split(identModification(right), 0)) @@ -2006,8 +1841,7 @@ class Router(formatOps: FormatOps) { val template = leftOwner.asInstanceOf[Template] typeTemplateSplits(template, style.indent.commaSiteRelativeToExtends) - case FormatToken(_, r: T.KwWith, _) => - rightOwner match { + case FormatToken(_, r: T.KwWith, _) => rightOwner match { // something like new A with B with C case template: Template if template.parent.exists { p => p.is[Term.New] || p.is[Term.NewAnonymous] || p.is[Defn.Given] @@ -2023,8 +1857,7 @@ class Router(formatOps: FormatOps) { // trait A extends B with C with D with E case template: Template => typeTemplateSplits(template, style.indent.withSiteRelativeToExtends) - case t @ WithChain(top) => - binPackParentConstructorSplits( + case t @ WithChain(top) => binPackParentConstructorSplits( !t.lhs.is[Type.With], withChain(top).toSet, Some(t.rhs), @@ -2036,11 +1869,9 @@ class Router(formatOps: FormatOps) { val expire = getLastToken(enumCase) Seq( Split(Space, 0).withIndent(indent, expire, ExpiresOn.After), - Split(Newline, 1) - .withIndent(indent, expire, ExpiresOn.After) + Split(Newline, 1).withIndent(indent, expire, ExpiresOn.After) ) - case _ => - Seq(Split(Space, 0)) + case _ => Seq(Split(Space, 0)) } // If/For/While/For with ( case FormatToken(open: T.LeftParen, _, _) if (leftOwner match { @@ -2056,35 +1887,28 @@ class Router(formatOps: FormatOps) { val penalizeNewlines = penalizeNewlineByNesting(open, close) if (style.danglingParentheses.ctrlSite) { val noSplit = - if (style.align.openParenCtrlSite) - Split(NoSplit, 0) - .withIndents(indents) - .withOptimalToken(close) - .withPolicy(penalizeNewlines) - .andPolicy(decideNewlinesOnlyBeforeCloseOnBreak(close)) - else - Split(NoSplit, 0).withSingleLine(close) + if (style.align.openParenCtrlSite) Split(NoSplit, 0) + .withIndents(indents).withOptimalToken(close) + .withPolicy(penalizeNewlines) + .andPolicy(decideNewlinesOnlyBeforeCloseOnBreak(close)) + else Split(NoSplit, 0).withSingleLine(close) Seq( noSplit, - Split(Newline, 1) - .withIndent(indentLen, close, Before) + Split(Newline, 1).withIndent(indentLen, close, Before) .withPolicy(penalizeNewlines) .andPolicy(decideNewlinesOnlyBeforeClose(close)) ) - } else - Seq( - Split(NoSplit, 0) - .withIndents(indents) - .withPolicy(penalizeNewlines) - ) + } else Seq( + Split(NoSplit, 0).withIndents(indents).withPolicy(penalizeNewlines) + ) case FormatToken(_: T.KwIf, right, _) if leftOwner.is[Term.If] => val owner = leftOwner.asInstanceOf[Term.If] val expire = getLastToken(owner) val mod = if (style.newlines.keepBreak(newlines)) Newline else Space(style.spaces.isSpaceAfterKeyword(right)) - val slb = - Split(mod.isNewline, 0)(mod).withSingleLine(expire, killOnFail = true) + val slb = Split(mod.isNewline, 0)(mod) + .withSingleLine(expire, killOnFail = true) val mlSplitBase = Split(mod, if (slb.isIgnored) 0 else 1) .withPolicy(getBreakBeforeElsePolicy(owner)) val mlSplitOpt = OptionalBraces @@ -2098,13 +1922,13 @@ class Router(formatOps: FormatOps) { } val split = (leftOwner match { // block expr case is handled in OptionalBraces.WhileImpl - case t: Term.While => - OptionalBraces.indentAndBreakBeforeCtrl[T.KwDo](t.expr, splitBase) + case t: Term.While => OptionalBraces + .indentAndBreakBeforeCtrl[T.KwDo](t.expr, splitBase) // below, multi-enum cases are handled in OptionalBraces.ForImpl - case Term.For(List(enum), _) => - OptionalBraces.indentAndBreakBeforeCtrl[T.KwDo](enum, splitBase) - case Term.ForYield(List(enum), _) => - OptionalBraces.indentAndBreakBeforeCtrl[T.KwYield](enum, splitBase) + case Term.For(List(enum), _) => OptionalBraces + .indentAndBreakBeforeCtrl[T.KwDo](enum, splitBase) + case Term.ForYield(List(enum), _) => OptionalBraces + .indentAndBreakBeforeCtrl[T.KwYield](enum, splitBase) case _ => None }).getOrElse(Split(spaceMod, 0)) Seq(split) @@ -2124,58 +1948,47 @@ class Router(formatOps: FormatOps) { val expire = getLastToken(body) def nlSplitFunc(cost: Int)(implicit l: sourcecode.Line) = Split(Newline, cost).withIndent(style.indent.main, expire, After) - if (style.newlines.getBeforeMultiline eq Newlines.unfold) - CtrlBodySplits.checkComment(formatToken, nlSplitFunc) { ft => + if (style.newlines.getBeforeMultiline eq Newlines.unfold) CtrlBodySplits + .checkComment(formatToken, nlSplitFunc) { ft => if (ft.right.is[T.LeftBrace]) { val nextFt = nextNonCommentSameLine(next(ft)) val policy = decideNewlinesOnlyAfterToken(nextFt.left) Seq(Split(Space, 0, policy = policy)) - } else - Seq(nlSplitFunc(0)) + } else Seq(nlSplitFunc(0)) } - else - CtrlBodySplits.get(formatToken, body) { - Split(Space, 0).withSingleLineNoOptimal( - expire, - insideBracesBlock(formatToken, expire), - noSyntaxNL = leftOwner.is[Term.ForYield] && right.is[T.KwYield] - ) - }(nlSplitFunc) + else CtrlBodySplits.get(formatToken, body) { + Split(Space, 0).withSingleLineNoOptimal( + expire, + insideBracesBlock(formatToken, expire), + noSyntaxNL = leftOwner.is[Term.ForYield] && right.is[T.KwYield] + ) + }(nlSplitFunc) case FormatToken(T.RightBrace(), T.KwElse(), _) => val nlOnly = style.newlines.alwaysBeforeElseAfterCurlyIf || !leftOwner.is[Term.Block] || !leftOwner.parent.forall(_ == rightOwner) - Seq( - Split(Space.orNL(!nlOnly), 0) - ) + Seq(Split(Space.orNL(!nlOnly), 0)) - case FormatToken(T.RightBrace(), T.KwYield(), _) => - Seq( - Split(Space, 0) - ) + case FormatToken(T.RightBrace(), T.KwYield(), _) => Seq(Split(Space, 0)) case FormatToken(_, kw @ (_: T.KwElse | _: T.KwYield), _) => val expire = getLastToken(rightOwner) val noSpace = shouldBreak(formatToken) def exclude = insideBracesBlock(formatToken, expire) val noSyntaxNL = kw.is[T.KwYield] Seq( - Split(Space, 0) - .notIf(noSpace) + Split(Space, 0).notIf(noSpace) .withSingleLineNoOptimal(expire, exclude, noSyntaxNL = noSyntaxNL), Split(Newline, 1) ) case ft @ FormatToken(_, _: T.KwThen | _: T.KwDo, _) => - if (style.newlines.sourceIgnored || newlines == 0) - Seq( - Split(Space, 0) - .withOptimalToken(nextNonCommentSameLine(next(ft)).left), - Split(Newline, 1) - ) - else - Seq(Split(Newline, 0)) + if (style.newlines.sourceIgnored || newlines == 0) Seq( + Split(Space, 0) + .withOptimalToken(nextNonCommentSameLine(next(ft)).left), + Split(Newline, 1) + ) + else Seq(Split(Newline, 0)) // Last else branch case FormatToken(_: T.KwElse, _, _) if (leftOwner match { - case t: Term.If => - t.elsep match { + case t: Term.If => t.elsep match { case _: Term.If => false case b @ Term.Block(List(_: Term.If)) => matchingOpt(nextNonComment(formatToken).right) @@ -2186,14 +1999,13 @@ class Router(formatOps: FormatOps) { }) => val body = leftOwner.asInstanceOf[Term.If].elsep val expire = getLastToken(body) - def nlSplitFunc(cost: Int) = - Split(Newline, cost).withIndent(style.indent.main, expire, After) + def nlSplitFunc(cost: Int) = Split(Newline, cost) + .withIndent(style.indent.main, expire, After) if (style.newlines.getBeforeMultiline eq Newlines.unfold) Seq(nlSplitFunc(0)) - else - CtrlBodySplits.get(formatToken, body) { - Split(Space, 0).withSingleLineNoOptimal(expire) - }(nlSplitFunc) + else CtrlBodySplits.get(formatToken, body) { + Split(Space, 0).withSingleLineNoOptimal(expire) + }(nlSplitFunc) // Type variance case FormatToken(_: T.Ident, right @ (_: T.Ident | _: T.Underscore), _) @@ -2202,14 +2014,11 @@ class Router(formatOps: FormatOps) { // Kind projector type lambda case FormatToken(T.Ident("+" | "-"), T.Underscore(), _) - if rightOwner.is[Type] => - Seq(Split(NoSplit, 0)) + if rightOwner.is[Type] => Seq(Split(NoSplit, 0)) // Var args case FormatToken(_, T.Ident("*"), _) if rightOwner.is[Type.Repeated] => - Seq( - Split(NoSplit, 0) - ) + Seq(Split(NoSplit, 0)) case FormatToken(open: T.LeftParen, right, _) => val close = matching(open) @@ -2239,12 +2048,11 @@ class Router(formatOps: FormatOps) { val useSpace = style.spaces.inParentheses || right.is[T.Comment] Split(Space(useSpace), 0).withIndent(indent, close, Before) } - def spaceSplit(implicit fileLine: FileLine) = - spaceSplitWithoutPolicy.withPolicy(PenalizeAllNewlines(close, 1)) - def newlineSplit( - cost: Int, - forceDangle: Boolean - )(implicit fileLine: FileLine) = { + def spaceSplit(implicit fileLine: FileLine) = spaceSplitWithoutPolicy + .withPolicy(PenalizeAllNewlines(close, 1)) + def newlineSplit(cost: Int, forceDangle: Boolean)(implicit + fileLine: FileLine + ) = { val shouldDangle = forceDangle || style.danglingParentheses.callSite Split(Newline, cost) .withPolicy(decideNewlinesOnlyBeforeClose(close), !shouldDangle) @@ -2252,33 +2060,30 @@ class Router(formatOps: FormatOps) { } if (tokens.isRightCommentThenBreak(formatToken)) Seq(newlineSplit(0, isConfig)) - else - style.newlines.source match { - case Newlines.classic => - Seq(if (isConfig) newlineSplit(0, true) else spaceSplit) - case Newlines.keep => - Seq(if (newlines != 0) newlineSplit(0, isConfig) else spaceSplit) - case _ => - val singleLine = enclosed.forall { x => - style.newlines.source.eq(Newlines.unfold) && - x.parent.exists { - case _: Template | _: Defn | _: Member.Infix => false - case _ => true - } + else style.newlines.source match { + case Newlines.classic => + Seq(if (isConfig) newlineSplit(0, true) else spaceSplit) + case Newlines.keep => + Seq(if (newlines != 0) newlineSplit(0, isConfig) else spaceSplit) + case _ => + val singleLine = enclosed.forall { x => + style.newlines.source.eq(Newlines.unfold) && x.parent.exists { + case _: Template | _: Defn | _: Member.Infix => false + case _ => true } - Seq( - if (!singleLine) spaceSplit - else { - val singleLineInfixPolicy = - if (!enclosed.exists(isInfixApp)) None - else Some(getSingleLineInfixPolicy(close)) - spaceSplitWithoutPolicy - .withSingleLine(close) - .andPolicyOpt(singleLineInfixPolicy) - }, - newlineSplit(10, true) - ) - } + } + Seq( + if (!singleLine) spaceSplit + else { + val singleLineInfixPolicy = + if (!enclosed.exists(isInfixApp)) None + else Some(getSingleLineInfixPolicy(close)) + spaceSplitWithoutPolicy.withSingleLine(close) + .andPolicyOpt(singleLineInfixPolicy) + }, + newlineSplit(10, true) + ) + } // Infix operator. case FormatToken(_: T.Ident, _, FormatToken.LeftOwner(AsInfixOp(app))) => @@ -2349,8 +2154,7 @@ class Router(formatOps: FormatOps) { ) case tok @ FormatToken(_, cond @ T.KwIf(), _) if rightOwner.is[Case] => - if (style.newlines.keepBreak(newlines)) - Seq(Split(Newline, 0)) + if (style.newlines.keepBreak(newlines)) Seq(Split(Newline, 0)) else { val arrow = getCaseArrow(rightOwner.asInstanceOf[Case]).left val afterIf = nextNonCommentSameLine(next(tok)) @@ -2388,15 +2192,13 @@ class Router(formatOps: FormatOps) { _ ) => val body = leftOwner match { - case t: Term.Try => - kw match { + case t: Term.Try => kw match { case _: T.KwTry => t.expr case _: T.KwCatch => t case _: T.KwFinally => t.finallyp.getOrElse(t) case _ => t } - case t: Term.TryWithHandler => - kw match { + case t: Term.TryWithHandler => kw match { case _: T.KwTry => t.expr case _: T.KwCatch => t.catchp case _: T.KwFinally => t.finallyp.getOrElse(t) @@ -2412,8 +2214,7 @@ class Router(formatOps: FormatOps) { // Term.ForYield case FormatToken(T.KwYield(), _, _) if leftOwner.is[Term.ForYield] => - val lastToken = - getLastToken(leftOwner.asInstanceOf[Term.ForYield].body) + val lastToken = getLastToken(leftOwner.asInstanceOf[Term.ForYield].body) val indent = Indent(style.indent.main, lastToken, ExpiresOn.After) if (style.newlines.avoidAfterYield && !rightOwner.is[Term.If]) { val nextFt = nextNonCommentSameLine(formatToken) @@ -2437,8 +2238,7 @@ class Router(formatOps: FormatOps) { CtrlBodySplits.get(ft, body)(null)(nlSplit) // After comment - case FormatToken(_: T.Comment, _, _) => - Seq(Split(getMod(formatToken), 0)) + case FormatToken(_: T.Comment, _, _) => Seq(Split(getMod(formatToken), 0)) // Inline comment case FormatToken(_, _: T.Comment, _) => val forceBlankLine = formatToken.hasBreak && @@ -2459,15 +2259,11 @@ class Router(formatOps: FormatOps) { if style.binPack.unsafeDefnSite.isNever && !style.verticalMultiline.atDefnSite => val spaceSplit = Split(Space, 0) - .notIf(style.newlines.forceAfterImplicitParamListModifier) - .withPolicy( + .notIf(style.newlines.forceAfterImplicitParamListModifier).withPolicy( SingleLineBlock(params.tokens.last), style.newlines.notPreferAfterImplicitParamListModifier ) - Seq( - spaceSplit, - Split(Newline, if (spaceSplit.isActive) 1 else 0) - ) + Seq(spaceSplit, Split(Newline, if (spaceSplit.isActive) 1 else 0)) case FormatToken(_, r, _) if optionalNewlines(hash(r)) => @tailrec @@ -2499,25 +2295,18 @@ class Router(formatOps: FormatOps) { case FormatToken(T.Ident("|"), _, _) if leftOwner.is[Pat.Alternative] => if (style.newlines.source eq Newlines.keep) Seq(Split(Space.orNL(newlines == 0), 0)) - else - Seq(Split(Space, 0), Split(Newline, 1)) + else Seq(Split(Space, 0), Split(Newline, 1)) case FormatToken(_, T.Ident("|"), _) if rightOwner.is[Pat.Alternative] => val noNL = !style.newlines.keepBreak(newlines) Seq(Split(Space.orNL(noNL), 0)) case FormatToken(_, T.Ident("*"), _) - if rightOwner.is[Pat.SeqWildcard] || - rightOwner.is[Term.Repeated] || rightOwner.is[Pat.Repeated] => - Seq( - Split(NoSplit, 0) - ) + if rightOwner.is[Pat.SeqWildcard] || rightOwner.is[Term.Repeated] || + rightOwner.is[Pat.Repeated] => Seq(Split(NoSplit, 0)) case FormatToken( T.Ident(_) | T.Literal() | T.Interpolation.End() | T.Xml.End(), T.Ident(_) | T.Literal() | T.Xml.Start(), _ - ) => - Seq( - Split(Space, 0) - ) + ) => Seq(Split(Space, 0)) // Case case FormatToken(left, _: T.KwMatch, _) => @@ -2527,15 +2316,9 @@ class Router(formatOps: FormatOps) { // Protected [] case FormatToken(_, T.LeftBracket(), _) - if isModPrivateProtected(leftOwner) => - Seq( - Split(NoSplit, 0) - ) + if isModPrivateProtected(leftOwner) => Seq(Split(NoSplit, 0)) case FormatToken(T.LeftBracket(), _, _) - if isModPrivateProtected(leftOwner) => - Seq( - Split(NoSplit, 0) - ) + if isModPrivateProtected(leftOwner) => Seq(Split(NoSplit, 0)) // Term.ForYield case FormatToken(_, _: T.KwIf, _) if rightOwner.is[Enumerator.Guard] => @@ -2545,95 +2328,49 @@ class Router(formatOps: FormatOps) { style.newlines.source match { case Newlines.fold => val endOfGuard = getLastToken(rightOwner) - val exclude = - insideBracesBlock(formatToken, endOfGuard, true) + val exclude = insideBracesBlock(formatToken, endOfGuard, true) Seq( Split(Space, 0).withSingleLine(endOfGuard, exclude = exclude), Split(Newline, 1) ) - case Newlines.unfold => - Seq(Split(Newline, 0)) - case _ => - Seq( - Split(Space, 0).onlyIf(newlines == 0), - Split(Newline, 1) - ) + case Newlines.unfold => Seq(Split(Newline, 0)) + case _ => Seq(Split(Space, 0).onlyIf(newlines == 0), Split(Newline, 1)) } // Interpolation - case FormatToken(_, _: T.Interpolation.Id, _) => - Seq( - Split(Space, 0) - ) + case FormatToken(_, _: T.Interpolation.Id, _) => Seq(Split(Space, 0)) // Throw exception - case FormatToken(T.KwThrow(), _, _) => - Seq( - Split(Space, 0) - ) + case FormatToken(T.KwThrow(), _, _) => Seq(Split(Space, 0)) // Singleton types case FormatToken(_, T.KwType(), _) if rightOwner.is[Type.Singleton] => - Seq( - Split(NoSplit, 0) - ) + Seq(Split(NoSplit, 0)) // seq to var args foo(seq:_*) case FormatToken(T.Colon(), T.Underscore(), _) - if next(formatToken).meta.right.text == "*" => - Seq( - Split(Space, 0) - ) + if next(formatToken).meta.right.text == "*" => Seq(Split(Space, 0)) case FormatToken(T.Underscore(), T.Ident("*"), _) - if prev(formatToken).left.is[T.Colon] => - Seq( - Split(NoSplit, 0) - ) + if prev(formatToken).left.is[T.Colon] => Seq(Split(NoSplit, 0)) // Xml - case FormatToken(_, _: T.Xml.Start, _) => - Seq( - Split(Space, 0) - ) + case FormatToken(_, _: T.Xml.Start, _) => Seq(Split(Space, 0)) case FormatToken(open: T.Xml.Start, _, _) => val splits = Seq(Split(NoSplit, 0)) - if (prev(formatToken).left.is[T.LeftBrace]) - splits - else - withIndentOnXmlStart(open, splits) + if (prev(formatToken).left.is[T.LeftBrace]) splits + else withIndentOnXmlStart(open, splits) case FormatToken(_: T.Xml.SpliceStart, _, _) if style.xmlLiterals.assumeFormatted => - withIndentOnXmlSpliceStart( - formatToken, - Seq(Split(NoSplit, 0)) - ) - case FormatToken(T.Xml.Part(_), _, _) => - Seq( - Split(NoSplit, 0) - ) - case FormatToken(_, T.Xml.Part(_), _) => - Seq( - Split(NoSplit, 0) - ) + withIndentOnXmlSpliceStart(formatToken, Seq(Split(NoSplit, 0))) + case FormatToken(T.Xml.Part(_), _, _) => Seq(Split(NoSplit, 0)) + case FormatToken(_, T.Xml.Part(_), _) => Seq(Split(NoSplit, 0)) // Fallback - case FormatToken(_, T.Dot(), _) => - Seq( - Split(NoSplit, 0) - ) + case FormatToken(_, T.Dot(), _) => Seq(Split(NoSplit, 0)) case FormatToken(left, T.Hash(), _) => - Seq( - Split(Space(endsWithSymbolIdent(left)), 0) - ) + Seq(Split(Space(endsWithSymbolIdent(left)), 0)) case FormatToken(T.Hash(), ident: T.Ident, _) => - Seq( - Split(Space(isSymbolicIdent(ident)), 0) - ) + Seq(Split(Space(isSymbolicIdent(ident)), 0)) case FormatToken(T.Dot(), T.Ident(_) | T.KwThis() | T.KwSuper(), _) => - Seq( - Split(NoSplit, 0) - ) - case FormatToken(_, T.RightBracket(), _) => - Seq( - Split(NoSplit, 0) - ) + Seq(Split(NoSplit, 0)) + case FormatToken(_, T.RightBracket(), _) => Seq(Split(NoSplit, 0)) case FormatToken(_, close: T.RightParen, _) => def modNoNL = { def allowSpace = rightOwner match { @@ -2648,45 +2385,22 @@ class Router(formatOps: FormatOps) { Seq(Split(if (isNL) Newline else modNoNL, 0)) case FormatToken(left, _: T.KwCatch | _: T.KwFinally, _) - if style.newlines.alwaysBeforeElseAfterCurlyIf - || !left.is[T.RightBrace] || - !(leftOwner.eq(rightOwner) || + if style.newlines.alwaysBeforeElseAfterCurlyIf || + !left.is[T.RightBrace] || !(leftOwner.eq(rightOwner) || leftOwner.is[Term.Block] && leftOwner.parent.contains(rightOwner)) => - Seq( - Split(NewlineT(formatToken.hasBlankLine), 0) - ) + Seq(Split(NewlineT(formatToken.hasBlankLine), 0)) - case FormatToken(_, Reserved(), _) => - Seq( - Split(Space, 0) - ) + case FormatToken(_, Reserved(), _) => Seq(Split(Space, 0)) - case FormatToken(Reserved(), _, _) => - Seq( - Split(Space, 0) - ) - case FormatToken(T.LeftBracket(), _, _) => - Seq( - Split(NoSplit, 0) - ) - case FormatToken(_, _: T.Symbolic, _) => - Seq( - Split(Space, 0) - ) - case FormatToken(T.Underscore(), T.Ident("*"), _) => - Seq( - Split(NoSplit, 0) - ) + case FormatToken(Reserved(), _, _) => Seq(Split(Space, 0)) + case FormatToken(T.LeftBracket(), _, _) => Seq(Split(NoSplit, 0)) + case FormatToken(_, _: T.Symbolic, _) => Seq(Split(Space, 0)) + case FormatToken(T.Underscore(), T.Ident("*"), _) => Seq(Split(NoSplit, 0)) case FormatToken(T.RightArrow(), _, _) if leftOwner.is[Type.ByName] => val mod = Space(style.spaces.inByNameTypes) - Seq( - Split(mod, 0) - ) - case FormatToken(_: T.Symbolic, _, _) => - Seq( - Split(Space, 0) - ) + Seq(Split(mod, 0)) + case FormatToken(_: T.Symbolic, _, _) => Seq(Split(Space, 0)) case tok => logger.debug("MISSING CASE:\n" + log(tok)) Seq() // No solution available, partially format tree. @@ -2733,27 +2447,22 @@ class Router(formatOps: FormatOps) { ft: FormatToken, body: Tree, spaceIndents: Seq[Indent] = Seq.empty - )(splits: => Seq[Split])(implicit - style: ScalafmtConfig - ): Seq[Split] = { + )(splits: => Seq[Split])(implicit style: ScalafmtConfig): Seq[Split] = { def expire = getLastToken(body) if (ft.right.is[T.LeftBrace]) // The block will take care of indenting by 2 Seq(Split(Space, 0).withIndents(spaceIndents)) else if ( ft.right.is[T.Comment] && (ft.hasBreak || nextNonCommentSameLine(next(ft)).hasBreak) - ) - Seq(CtrlBodySplits.withIndent(Split(Space.orNL(ft.noBreak), 0), ft, body)) - else if (isJsNative(body)) - Seq(Split(Space, 0).withSingleLine(expire)) + ) Seq(CtrlBodySplits.withIndent(Split(Space.orNL(ft.noBreak), 0), ft, body)) + else if (isJsNative(body)) Seq(Split(Space, 0).withSingleLine(expire)) else if (style.newlines.forceBeforeAssign(ft.meta.leftOwner)) Seq(CtrlBodySplits.withIndent(Split(Newline, 0), ft, body)) else if (style.newlines.shouldForceBeforeMultilineAssign(ft.meta.leftOwner)) CtrlBodySplits.slbOnly(ft, body, spaceIndents) { x => CtrlBodySplits.withIndent(Split(Newline, x), ft, body) } - else - splits + else splits } private def getSplitsDefEquals(ft: FormatToken, body: Tree)(implicit @@ -2761,12 +2470,11 @@ class Router(formatOps: FormatOps) { ): Seq[Split] = { val expire = getLastToken(body) def baseSplit = Split(Space, 0) - def newlineSplit(cost: Int)(implicit fileLine: FileLine) = - CtrlBodySplits.withIndent(Split(Newline, cost), ft, body) + def newlineSplit(cost: Int)(implicit fileLine: FileLine) = CtrlBodySplits + .withIndent(Split(Newline, cost), ft, body) def getClassicSplits = - if (ft.hasBreak) Seq(newlineSplit(0)) - else Seq(baseSplit, newlineSplit(1)) + if (ft.hasBreak) Seq(newlineSplit(0)) else Seq(baseSplit, newlineSplit(1)) style.newlines.beforeMultilineDef.fold { getSplitsValEquals(ft, body)(getClassicSplits) @@ -2778,8 +2486,7 @@ class Router(formatOps: FormatOps) { case Newlines.unfold => Seq(baseSplit.withSingleLine(expire), newlineSplit(1)) - case x => - CtrlBodySplits.folded(ft, body, x eq Newlines.keep)(newlineSplit) + case x => CtrlBodySplits.folded(ft, body, x eq Newlines.keep)(newlineSplit) } } @@ -2793,14 +2500,13 @@ class Router(formatOps: FormatOps) { style: ScalafmtConfig ): Seq[Split] = { def wouldDangle = ft.meta.leftOwner.parent.exists { - case p: Member.ParamClause => - !shouldNotDangleAtDefnSite(p.parent, false) - case _: Member.Tuple => - style.danglingParentheses.tupleOrCallSite(true) - case p: Member.ArgClause => - style.danglingParentheses.tupleOrCallSite(false) && (p.parent match { - case Some(_: Term.ApplyInfix) => - style.newlines.formatInfix && p.values.lengthCompare(1) > 0 + case p: Member.ParamClause => !shouldNotDangleAtDefnSite(p.parent, false) + case _: Member.Tuple => style.danglingParentheses.tupleOrCallSite(true) + case p: Member.ArgClause => style.danglingParentheses + .tupleOrCallSite(false) && + (p.parent match { + case Some(_: Term.ApplyInfix) => style.newlines.formatInfix && + p.values.lengthCompare(1) > 0 case _ => true }) case _ => false @@ -2815,11 +2521,10 @@ class Router(formatOps: FormatOps) { case _ => expireFt } val optimal = optimalFt.left - def optimalWithComment = - optimalFt.right match { - case x: T.Comment if optimalFt.noBreak => x - case _ => optimal - } + def optimalWithComment = optimalFt.right match { + case x: T.Comment if optimalFt.noBreak => x + case _ => optimal + } val penalty = ft.meta.leftOwner match { case _: Term.Assign if !style.binPack.unsafeCallSite.isNever => @@ -2831,16 +2536,14 @@ class Router(formatOps: FormatOps) { def baseSpaceSplit(implicit fileLine: FileLine) = Split(tokens.isRightCommentThenBreak(ft), 0)(Space) - def twoBranches(implicit fileLine: FileLine) = - baseSpaceSplit - .withOptimalToken(optimal) - .withPolicy { - val exclude = insideBracesBlock(ft, expire) - policyWithExclude(exclude, Policy.End.On, Policy.End.After)( - Policy.End.Before(expire), - new PenalizeAllNewlines(_, Constants.ShouldBeSingleLine) - ) - } + def twoBranches(implicit fileLine: FileLine) = baseSpaceSplit + .withOptimalToken(optimal).withPolicy { + val exclude = insideBracesBlock(ft, expire) + policyWithExclude(exclude, Policy.End.On, Policy.End.After)( + Policy.End.Before(expire), + new PenalizeAllNewlines(_, Constants.ShouldBeSingleLine) + ) + } val spaceSplit = body match { case _ if ft.hasBreak && ft.meta.leftOwner.is[Defn] => Split.ignored case _: Term.If => twoBranches @@ -2849,8 +2552,7 @@ class Router(formatOps: FormatOps) { case _: Term.Try | _: Term.TryWithHandler => Split.ignored case t: Term.Apply if t.argClause.nonEmpty => baseSpaceSplit.withOptimalToken(optimalWithComment) - case _ => - baseSpaceSplit.withOptimalToken(optimal) + case _ => baseSpaceSplit.withOptimalToken(optimal) } Seq( spaceSplit, @@ -2858,30 +2560,27 @@ class Router(formatOps: FormatOps) { ) } - private def getSplitsEnumerator( - ft: FormatToken, - body: Tree - )(implicit style: ScalafmtConfig): Seq[Split] = - maybeGetInfixSplitsBeforeLhs(ft) { - val expire = getLastNonTrivialToken(body) - val spaceIndents = - if (!style.align.arrowEnumeratorGenerator) Seq.empty - else Seq(Indent(StateColumn, expire, After)) - getSplitsDefValEquals(ft, body, spaceIndents) { - CtrlBodySplits.get(ft, body, spaceIndents) { - if (spaceIndents.nonEmpty) - Split(Space, 0).withIndents(spaceIndents) - else { - val noSlb = body match { - case _: Term.Try | _: Term.TryWithHandler => false - case t: Term.If => ifWithoutElse(t) - case _ => true - } - if (noSlb) Split(Space, 0).withOptimalToken(ft.right) - else Split(Space, 0).withSingleLine(expire) + private def getSplitsEnumerator(ft: FormatToken, body: Tree)(implicit + style: ScalafmtConfig + ): Seq[Split] = maybeGetInfixSplitsBeforeLhs(ft) { + val expire = getLastNonTrivialToken(body) + val spaceIndents = + if (!style.align.arrowEnumeratorGenerator) Seq.empty + else Seq(Indent(StateColumn, expire, After)) + getSplitsDefValEquals(ft, body, spaceIndents) { + CtrlBodySplits.get(ft, body, spaceIndents) { + if (spaceIndents.nonEmpty) Split(Space, 0).withIndents(spaceIndents) + else { + val noSlb = body match { + case _: Term.Try | _: Term.TryWithHandler => false + case t: Term.If => ifWithoutElse(t) + case _ => true } - }(Split(Newline, _).withIndent(style.indent.main, expire, After)) - } + if (noSlb) Split(Space, 0).withOptimalToken(ft.right) + else Split(Space, 0).withSingleLine(expire) + } + }(Split(Newline, _).withIndent(style.indent.main, expire, After)) } + } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Split.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Split.scala index d81af529ae..568971eb75 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Split.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Split.scala @@ -95,11 +95,10 @@ case class Split( def preActivateFor(splitTag: SplitTag): Split = if (isIgnored) this - else - copy( - activeTags = activeTags + splitTag, - neededTags = neededTags + splitTag - ) + else copy( + activeTags = activeTags + splitTag, + neededTags = neededTags + splitTag + ) def preActivateFor(splitTag: Option[SplitTag]): Split = if (isIgnored) this else splitTag.fold(this)(preActivateFor) @@ -113,8 +112,7 @@ case class Split( def withOptimalTokenOpt( token: => Option[Token], killOnFail: Boolean = false - ): Split = - withOptimalAt(token.map(OptimalToken(_, killOnFail))) + ): Split = withOptimalAt(token.map(OptimalToken(_, killOnFail))) def withOptimalToken( token: => Token, @@ -159,10 +157,8 @@ case class Split( noSyntaxNL: Boolean = false, killOnFail: Boolean = false, rank: Int = 0 - )(implicit fileLine: FileLine, style: ScalafmtConfig): Split = - expire.fold(this)( - withSingleLine(_, exclude, noSyntaxNL, killOnFail, rank) - ) + )(implicit fileLine: FileLine, style: ScalafmtConfig): Split = expire + .fold(this)(withSingleLine(_, exclude, noSyntaxNL, killOnFail, rank)) def withSingleLineAndOptimal( expire: Token, @@ -180,10 +176,9 @@ case class Split( exclude: => TokenRanges = TokenRanges.empty, noSyntaxNL: Boolean = false, rank: Int = 0 - )(implicit fileLine: FileLine, style: ScalafmtConfig): Split = - withPolicy( - SingleLineBlock(expire, exclude, noSyntaxNL = noSyntaxNL, rank = rank) - ) + )(implicit fileLine: FileLine, style: ScalafmtConfig): Split = withPolicy( + SingleLineBlock(expire, exclude, noSyntaxNL = noSyntaxNL, rank = rank) + ) def withPolicyOpt(newPolicy: => Option[Policy]): Split = if (isIgnored) this else newPolicy.fold(this)(withPolicy(_)) @@ -222,8 +217,7 @@ case class Split( length: => Length, expire: Option[Token], when: ExpiresOn - ): Split = - withMod(modExt.withIndentOpt(length, expire, when)) + ): Split = withMod(modExt.withIndentOpt(length, expire, when)) def withIndent(indent: => Indent, ignore: Boolean = false): Split = withMod(modExt.withIndent(indent), ignore) @@ -264,7 +258,8 @@ case class Split( else "" } val opt = optimalAt.fold("")(", opt=" + _) - s"""$prefix${modExt.mod}:[$fileLine](cost=$cost, indents=$indentation, $policy$opt)""" + s"""$prefix${modExt + .mod}:[$fileLine](cost=$cost, indents=$indentation, $policy$opt)""" } } @@ -272,12 +267,10 @@ object Split { private val ignoredTags = Set[SplitTag](null) - def ignored(implicit fileLine: FileLine) = - Split(ModExt(NoSplit), 0).ignored + def ignored(implicit fileLine: FileLine) = Split(ModExt(NoSplit), 0).ignored - def apply(ignore: Boolean, cost: Int)( - modExt: ModExt - )(implicit fileLine: FileLine): Split = - if (ignore) ignored else Split(modExt, cost) + def apply(ignore: Boolean, cost: Int)(modExt: ModExt)(implicit + fileLine: FileLine + ): Split = if (ignore) ignored else Split(modExt, cost) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SplitTag.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SplitTag.scala index 7293622fb5..e3d67f155c 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SplitTag.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SplitTag.scala @@ -2,8 +2,8 @@ package org.scalafmt.internal sealed abstract class SplitTag { - final def activateOnly(splits: Seq[Split]): Seq[Split] = - splits.map(_.activateFor(this)) + final def activateOnly(splits: Seq[Split]): Seq[Split] = splits + .map(_.activateFor(this)) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/State.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/State.scala index ed056dd214..ab49871b5f 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/State.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/State.scala @@ -27,15 +27,15 @@ final case class State( override def toString = s"State($cost, $depth)" - def alwaysBetter(other: State): Boolean = - this.cost <= other.cost && this.indentation <= other.indentation + def alwaysBetter(other: State): Boolean = this.cost <= other.cost && + this.indentation <= other.indentation /** Calculates next State given split at tok. */ - def next( - initialNextSplit: Split, - nextAllAltAreNL: Boolean - )(implicit style: ScalafmtConfig, tokens: FormatTokens): State = { + def next(initialNextSplit: Split, nextAllAltAreNL: Boolean)(implicit + style: ScalafmtConfig, + tokens: FormatTokens + ): State = { val tok = tokens(depth) val right = tok.right @@ -47,9 +47,8 @@ final case class State( val extendedEnd = getRelativeToLhsLastLineEnd(modExt.isNL) (modExt.getActualIndents(offset) ++ indents).flatMap { x => if (x.notExpiredBy(tok)) Some(x) - else - extendedEnd - .map(y => x.copy(expireEnd = y, expiresAt = ExpiresOn.After)) + else extendedEnd + .map(y => x.copy(expireEnd = y, expiresAt = ExpiresOn.After)) } } @@ -66,8 +65,7 @@ final case class State( val altIndent = Indent.getIndent(altPushes) val split = initialNextSplit.withMod(alt.withIndents(indents)) (split, nextIndent + altIndent, nextPushes ++ altPushes) - case _ => - (initialNextSplit, nextIndent, nextPushes) + case _ => (initialNextSplit, nextIndent, nextPushes) } } @@ -76,21 +74,19 @@ final case class State( case m: NewlineT => if (m.noIndent) 0 else nextIndent case m => if (m.isNewline) nextIndent else column + m.length } - val (columnOnCurrentLine, nextStateColumn) = - State.getColumns(tok, nextIndent, startColumn) + val (columnOnCurrentLine, nextStateColumn) = State + .getColumns(tok, nextIndent, startColumn) val nextTok = tokens.next(tok) val nextPolicy: PolicySummary = policy.combine(nextSplit.policy, nextTok) - def noOverflowPenalties = - (math.max(0, delayedPenalty), 0) // fits inside column + def noOverflowPenalties = (math.max(0, delayedPenalty), 0) // fits inside column def overflowPenalties(column: Int) = { val defaultOverflowPenalty = Constants.ExceedColumnPenalty + column if (style.newlines.avoidForSimpleOverflow.isEmpty) (defaultOverflowPenalty, 0) - else - getOverflowPenalty(nextSplit, defaultOverflowPenalty) + else getOverflowPenalty(nextSplit, defaultOverflowPenalty) } val (penalty, nextDelayedPenalty) = @@ -163,8 +159,8 @@ final case class State( if (!State.allowSplitForLineStart(nextSplit, ft, isComment)) None else lineStartsStatement(isComment) val delay = startFtOpt.exists { - case FormatToken(_, t: Token.Interpolation.Start, _) => - tokens.matching(t) ne ft.right + case FormatToken(_, t: Token.Interpolation.Start, _) => tokens + .matching(t) ne ft.right case _ => true } // if delaying, estimate column if the split had been a newline @@ -184,8 +180,8 @@ final case class State( result(tokLength, true) } } else if ( - ft.right.isInstanceOf[Product] && - tokLength == 1 && !ft.meta.right.text.head.isLetterOrDigit + ft.right.isInstanceOf[Product] && tokLength == 1 && + !ft.meta.right.text.head.isLetterOrDigit ) { // delimiter val ok = delayedPenalty != 0 || { style.newlines.avoidForSimpleOverflowPunct && @@ -196,16 +192,11 @@ final case class State( } else if ( style.newlines.avoidForSimpleOverflowSLC && tokens.isRightCommentThenBreak(ft) - ) { - result(0, prevActive) - } else if ( - style.newlines.avoidForSimpleOverflowTooLong && - delayedPenalty == 0 // can't delay multiple times - ) { - getCustomPenalty - } else { - getFullPenalty - } + ) { result(0, prevActive) } + else if ( + style.newlines.avoidForSimpleOverflowTooLong && delayedPenalty == 0 // can't delay multiple times + ) { getCustomPenalty } + else { getFullPenalty } } } @@ -226,10 +217,10 @@ final case class State( State.allowSplitForLineStart(split, ft, isComment) if (ok) prev.getLineStartOwner(isComment) else None } else { - def startsWithLeft(tree: Tree): Boolean = - tokens.getHeadOpt(tree).contains(ft) - def optionIfStartsWithLeft(tree: Tree): Option[Tree] = - Some(tree).filter(startsWithLeft) + def startsWithLeft(tree: Tree): Boolean = tokens.getHeadOpt(tree) + .contains(ft) + def optionIfStartsWithLeft(tree: Tree): Option[Tree] = Some(tree) + .filter(startsWithLeft) val owner = optionIfStartsWithLeft(ft.meta.rightOwner) .orElse(optionIfStartsWithLeft(ft.meta.leftOwner)) owner.map { x => @@ -245,10 +236,9 @@ final case class State( /** Check that the current line starts a statement which also contains the * current token. */ - private def lineStartsStatement(isComment: Boolean)(implicit - style: ScalafmtConfig, - tokens: FormatTokens - ): Option[FormatToken] = { + private def lineStartsStatement( + isComment: Boolean + )(implicit style: ScalafmtConfig, tokens: FormatTokens): Option[FormatToken] = { getLineStartOwner(isComment).flatMap { case (lineFt, lineOwner) => val ft = tokens(depth) val ok = { @@ -259,16 +249,14 @@ final case class State( case t: Member.SyntaxValuesClause => t.parent.contains(lineOwner) case _ => false }) - } || - findTreeOrParentSimple(ft.meta.leftOwner)(_ eq lineOwner).isDefined + } || findTreeOrParentSimple(ft.meta.leftOwner)(_ eq lineOwner).isDefined if (ok) Some(lineFt) else None } } - private def getRelativeToLhsLastLineEnd(isNL: Boolean)(implicit - style: ScalafmtConfig, - tokens: FormatTokens - ): Option[Int] = { + private def getRelativeToLhsLastLineEnd( + isNL: Boolean + )(implicit style: ScalafmtConfig, tokens: FormatTokens): Option[Int] = { val allowed = style.indent.relativeToLhsLastLine def treeEnd(x: Tree) = tokens.getLast(x).left.end @@ -296,22 +284,21 @@ final case class State( val right = tok.right if (allowed.isEmpty) None else if (!isNL && right.is[Token.Comment]) Some(right.end) - else - indentEnd(tok, isNL) { - val earlierState = prev.prevNonCommentSameLine - indentEnd(tokens(earlierState.depth), earlierState.split.isNL)(None) - }.orElse { - val delay = !isNL && (right match { - case _: Token.KwMatch => - tok.meta.rightOwner.is[Term.Match] && + else indentEnd(tok, isNL) { + val earlierState = prev.prevNonCommentSameLine + indentEnd(tokens(earlierState.depth), earlierState.split.isNL)(None) + }.orElse { + val delay = !isNL && + (right match { + case _: Token.KwMatch => tok.meta.rightOwner.is[Term.Match] && allowed.contains(Indents.RelativeToLhs.`match`) - case _: Token.Ident => - tok.meta.rightOwner.parent.exists(_.is[Term.ApplyInfix]) && + case _: Token.Ident => tok.meta.rightOwner.parent + .exists(_.is[Term.ApplyInfix]) && allowed.contains(Indents.RelativeToLhs.`infix`) case _ => false }) - if (delay) Some(right.end) else None - } + if (delay) Some(right.end) else None + } } @tailrec @@ -322,63 +309,46 @@ final case class State( object State { - val start = State( - 0, - PolicySummary.empty, - null, - 0, - null, - 0, - Seq.empty, - 0, - false, - 0, - 0 - ) + val start = + State(0, PolicySummary.empty, null, 0, null, 0, Seq.empty, 0, false, 0, 0) // this is not best state, it's higher priority for search object Ordering extends Ordering[State] { override def compare(x: State, y: State): Int = compareAt(x, y, 0) // each should compare priorities, i.e. define reverse ordering - private val comparisons: Seq[(State, State) => Int] = Seq( - compareCost, - compareDepth, - compareSplitOrigin - ) + private val comparisons: Seq[(State, State) => Int] = + Seq(compareCost, compareDepth, compareSplitOrigin) @tailrec private def compareAt(s1: State, s2: State, i: Int): Int = { val r = comparisons(i)(s1, s2) - if (r != 0 || i == comparisons.length - 1) r - else compareAt(s1, s2, i + 1) + if (r != 0 || i == comparisons.length - 1) r else compareAt(s1, s2, i + 1) } // higher priority on lower cost - private def compareCost(s1: State, s2: State): Int = - Integer.compare(s2.cost, s1.cost) + private def compareCost(s1: State, s2: State): Int = Integer + .compare(s2.cost, s1.cost) // higher priority on deeper state - private def compareDepth(s1: State, s2: State): Int = - Integer.compare(s1.depth, s2.depth) + private def compareDepth(s1: State, s2: State): Int = Integer + .compare(s1.depth, s2.depth) // higher priority on later line defining the last split @tailrec private def compareSplitOrigin(s1: State, s2: State): Int = { // We assume the same number of splits, see compareSplitsLength // Break ties by the last split's line origin. - val r = Integer.compare( - s1.split.fileLine.line.value, - s2.split.fileLine.line.value - ) + val r = Integer + .compare(s1.split.fileLine.line.value, s2.split.fileLine.line.value) if (r != 0 || s1.prev.depth == 0) r else compareSplitOrigin(s1.prev, s2.prev) } } @inline - private def compileStripMarginPattern(pipe: Char) = - Pattern.compile(s"\n(\\h*+\\$pipe)?([^\n]*+)") + private def compileStripMarginPattern(pipe: Char) = Pattern + .compile(s"\n(\\h*+\\$pipe)?([^\n]*+)") @inline private def getStripMarginPattern(pipe: Char) = @@ -388,11 +358,9 @@ object State { private val slcLine = Pattern.compile("^/\\/\\/*+\\h*+(.*?)\\h*+$") - def getColumns( - ft: FormatToken, - indent: Int, - column: Int - )(implicit style: ScalafmtConfig): (Int, Int) = { + def getColumns(ft: FormatToken, indent: Int, column: Int)(implicit + style: ScalafmtConfig + ): (Int, Int) = { val syntax = ft.meta.right.text val firstNL = ft.meta.right.firstNL if (firstNL < 0) { @@ -408,19 +376,22 @@ object State { val firstLength = column + firstNL ft.right match { case _: Token.Constant.String => - val margin: Int => Int = if (style.assumeStandardLibraryStripMargin) { - // 3 for '|' + 2 spaces - val adjusted = 3 + (if (style.align.stripMargin) column else indent) - _ => adjusted - } else identity + val margin: Int => Int = + if (style.assumeStandardLibraryStripMargin) { + // 3 for '|' + 2 spaces + val adjusted = 3 + + (if (style.align.stripMargin) column else indent) + _ => adjusted + } else identity val pipe = getStripMarginChar(ft.meta.rightOwner) getColumnsWithStripMargin(pipe, syntax, firstNL, margin, firstLength) case _: Token.Interpolation.Part => - val margin: Int => Int = if (style.assumeStandardLibraryStripMargin) { - // 1 for '|' - val adjusted = 1 + indent - _ => adjusted - } else identity + val margin: Int => Int = + if (style.assumeStandardLibraryStripMargin) { + // 1 for '|' + val adjusted = 1 + indent + _ => adjusted + } else identity val pipe = getStripMarginCharForInterpolate(ft.meta.rightOwner) getColumnsWithStripMargin(pipe, syntax, firstNL, margin, firstLength) case _ => @@ -451,10 +422,9 @@ object State { firstNL: Int, adjustMargin: Int => Int, firstLength: Int - ): (Int, Int) = - pipeOpt.fold(getColumnsFromMultiline(syntax, firstNL, firstLength))( - getColumnsWithStripMargin(_, syntax, firstNL, adjustMargin, firstLength) - ) + ): (Int, Int) = pipeOpt.fold( + getColumnsFromMultiline(syntax, firstNL, firstLength) + )(getColumnsWithStripMargin(_, syntax, firstNL, adjustMargin, firstLength)) private def getColumnsWithStripMargin( pipe: Char, @@ -492,15 +462,13 @@ object State { isComment: Boolean ): Boolean = { { - split.length == 0 || isComment || - isInterpolation(ft.meta.rightOwner) || + split.length == 0 || isComment || isInterpolation(ft.meta.rightOwner) || ft.meta.leftOwner.is[meta.Term.Assign] } && !split.modExt.indents.exists(_.hasStateColumn) } @inline - private def isInterpolation(tree: Tree): Boolean = - tree.is[Term.Interpolate] + private def isInterpolation(tree: Tree): Boolean = tree.is[Term.Interpolate] @inline private def isWithinInterpolation(tree: Tree): Boolean = diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SyntacticGroup.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SyntacticGroup.scala index 991ffa41e0..eb032fa454 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SyntacticGroup.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SyntacticGroup.scala @@ -12,25 +12,53 @@ object SyntacticGroup { def categories = List("Type") } object Type { - case object ParamTyp extends Type { def precedence = 0 } - case object Typ extends Type { def precedence = 1 } - case object AnyInfixTyp extends Type { def precedence = 1.5 } - case class InfixTyp(operator: String) extends Type { def precedence = 2 } - case object RefineTyp extends Type { def precedence = 3 } - case object WithTyp extends Type { def precedence = 3.5 } - case object AnnotTyp extends Type { def precedence = 4 } - case object SimpleTyp extends Type { def precedence = 6 } + case object ParamTyp extends Type { + def precedence = 0 + } + case object Typ extends Type { + def precedence = 1 + } + case object AnyInfixTyp extends Type { + def precedence = 1.5 + } + case class InfixTyp(operator: String) extends Type { + def precedence = 2 + } + case object RefineTyp extends Type { + def precedence = 3 + } + case object WithTyp extends Type { + def precedence = 3.5 + } + case object AnnotTyp extends Type { + def precedence = 4 + } + case object SimpleTyp extends Type { + def precedence = 6 + } } sealed trait Term extends SyntacticGroup { def categories = List("Term") } object Term { - case object Expr extends Term { def precedence = 0 } - case object Expr1 extends Term { def precedence = 1 } - case object Ascription extends Term { def precedence = 2 } - case object PostfixExpr extends Term { def precedence = 2 } - case class InfixExpr(operator: String) extends Term { def precedence = 3 } - case class PrefixExpr(operator: String) extends Term { def precedence = 4 } + case object Expr extends Term { + def precedence = 0 + } + case object Expr1 extends Term { + def precedence = 1 + } + case object Ascription extends Term { + def precedence = 2 + } + case object PostfixExpr extends Term { + def precedence = 2 + } + case class InfixExpr(operator: String) extends Term { + def precedence = 3 + } + case class PrefixExpr(operator: String) extends Term { + def precedence = 4 + } object PrefixArg { def apply(tree: Tree): PrefixArg = PrefixArg(tree, TreeSyntacticGroup(tree)) @@ -38,19 +66,35 @@ object SyntacticGroup { case class PrefixArg(tree: Tree, innerGroup: SyntacticGroup) extends Term { def precedence = innerGroup.precedence } - case object SimpleExpr extends Term { def precedence = 5 } - case object SimpleExpr1 extends Term { def precedence = 6 } + case object SimpleExpr extends Term { + def precedence = 5 + } + case object SimpleExpr1 extends Term { + def precedence = 6 + } } sealed trait Pat extends SyntacticGroup { def categories = List("Pat") } object Pat { - case object Pattern extends Pat { def precedence = 0 } - case object Pattern1 extends Pat { def precedence = 1 } - case object Pattern2 extends Pat { def precedence = 2 } - case object AnyPattern3 extends Pat { def precedence = 2.5 } - case class Pattern3(operator: String) extends Pat { def precedence = 3 } - case object SimplePattern extends Pat { def precedence = 6 } + case object Pattern extends Pat { + def precedence = 0 + } + case object Pattern1 extends Pat { + def precedence = 1 + } + case object Pattern2 extends Pat { + def precedence = 2 + } + case object AnyPattern3 extends Pat { + def precedence = 2.5 + } + case class Pattern3(operator: String) extends Pat { + def precedence = 3 + } + case object SimplePattern extends Pat { + def precedence = 6 + } } case object Literal extends Term with Pat { override def categories = List("Term", "Pat"); def precedence = 6 diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SyntacticGroupOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SyntacticGroupOps.scala index 96f7fb67f5..b8a83536d4 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SyntacticGroupOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/SyntacticGroupOps.scala @@ -18,8 +18,8 @@ object SyntacticGroupOps { forceRight: Boolean = false ): Boolean = { - def isLeftAssociative(name: String): Boolean = - !customAssociativity || InfixApp.isLeftAssoc(name) + def isLeftAssociative(name: String): Boolean = !customAssociativity || + InfixApp.isLeftAssoc(name) def precedence(name: String): Int = if (customPrecedence) Term.Name(name).precedence else 0 @@ -35,13 +35,10 @@ object SyntacticGroupOps { val outerOperatorPrecedence = precedence(outerOperator) val innerOperatorPrecedence = precedence(innerOperator) - if (outerOperatorPrecedence < innerOperatorPrecedence) { - isRight - } else if (outerOperatorPrecedence == innerOperatorPrecedence) { + if (outerOperatorPrecedence < innerOperatorPrecedence) { isRight } + else if (outerOperatorPrecedence == innerOperatorPrecedence) { isLeft ^ side.isLeft - } else { - isLeft || forceRight - } + } else { isLeft || forceRight } } } @@ -49,8 +46,7 @@ object SyntacticGroupOps { def startsWithNumericLiteral(tree: Tree): Boolean = { tree match { case _: Lit.Int | _: Lit.Long | _: Lit.Double | _: Lit.Float | - _: Lit.Byte | _: Lit.Short => - true + _: Lit.Byte | _: Lit.Short => true case Term.Select(tree0, _) => startsWithNumericLiteral(tree0) case _ => false } @@ -60,43 +56,40 @@ object SyntacticGroupOps { outerGroup: SyntacticGroup, innerGroup: SyntacticGroup, side: Side - ): Boolean = - (outerGroup, innerGroup) match { - case (g.Term.InfixExpr(outerOperator), g.Term.InfixExpr(innerOperator)) => - operatorNeedsParenthesis( - outerOperator, - innerOperator, - customAssociativity = true, - customPrecedence = true, - side, - forceRight = true - ) - case (g.Type.InfixTyp(outerOperator), g.Type.InfixTyp(innerOperator)) => - operatorNeedsParenthesis( - outerOperator, - innerOperator, - customAssociativity = true, - customPrecedence = false, - side - ) - case (g.Pat.Pattern3(outerOperator), g.Pat.Pattern3(innerOperator)) => - operatorNeedsParenthesis( - outerOperator, - innerOperator, - customAssociativity = true, - customPrecedence = true, - side - ) - - case (_: g.Term.PrefixExpr, g.Term.PrefixArg(_, _: g.Term.PrefixExpr)) => - true - - case (g.Term.PrefixExpr("-"), g.Term.PrefixArg(Term.Select(tree, _), _)) - if startsWithNumericLiteral(tree) => - true - - case _ => - outerGroup.precedence > innerGroup.precedence - } + ): Boolean = (outerGroup, innerGroup) match { + case (g.Term.InfixExpr(outerOperator), g.Term.InfixExpr(innerOperator)) => + operatorNeedsParenthesis( + outerOperator, + innerOperator, + customAssociativity = true, + customPrecedence = true, + side, + forceRight = true + ) + case (g.Type.InfixTyp(outerOperator), g.Type.InfixTyp(innerOperator)) => + operatorNeedsParenthesis( + outerOperator, + innerOperator, + customAssociativity = true, + customPrecedence = false, + side + ) + case (g.Pat.Pattern3(outerOperator), g.Pat.Pattern3(innerOperator)) => + operatorNeedsParenthesis( + outerOperator, + innerOperator, + customAssociativity = true, + customPrecedence = true, + side + ) + + case (_: g.Term.PrefixExpr, g.Term.PrefixArg(_, _: g.Term.PrefixExpr)) => + true + + case (g.Term.PrefixExpr("-"), g.Term.PrefixArg(Term.Select(tree, _), _)) + if startsWithNumericLiteral(tree) => true + + case _ => outerGroup.precedence > innerGroup.precedence + } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/TokenRange.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/TokenRange.scala index 11b379924c..71569b336f 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/TokenRange.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/TokenRange.scala @@ -28,7 +28,6 @@ object TokenRanges { val empty = new TokenRanges(Seq.empty) - def apply(range: TokenRange): TokenRanges = - new TokenRanges(Seq(range)) + def apply(range: TokenRange): TokenRanges = new TokenRanges(Seq(range)) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/TreeSyntacticGroup.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/TreeSyntacticGroup.scala index 276c000640..4c7e7ee91d 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/TreeSyntacticGroup.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/TreeSyntacticGroup.scala @@ -8,80 +8,79 @@ import scala.meta.Type import org.scalafmt.internal.{SyntacticGroup => g} object TreeSyntacticGroup { - def apply(tree: Tree): SyntacticGroup = - tree match { - case _: Lit => g.Literal - // Term - case _: Term.Name => g.Path - case _: Term.Select => g.Path - case _: Term.Interpolate => g.Term.SimpleExpr1 - case _: Term.Xml => g.Term.SimpleExpr1 - case _: Term.Apply => g.Term.SimpleExpr1 - case _: Term.ApplyType => g.Term.SimpleExpr1 - case t: Term.ApplyInfix => g.Term.InfixExpr(t.op.value) - case t: Term.ApplyUnary => g.Term.PrefixExpr(t.op.value) - case _: Term.Assign => g.Term.Expr1 - case _: Term.Return => g.Term.Expr1 - case _: Term.Throw => g.Term.Expr1 - case _: Term.Ascribe => g.Term.Expr1 - case _: Term.Annotate => g.Term.Expr1 - case _: Term.Block => g.Term.SimpleExpr1 - case _: Term.Tuple => g.Term.SimpleExpr1 // ???, breaks a op ((b, c)) + def apply(tree: Tree): SyntacticGroup = tree match { + case _: Lit => g.Literal + // Term + case _: Term.Name => g.Path + case _: Term.Select => g.Path + case _: Term.Interpolate => g.Term.SimpleExpr1 + case _: Term.Xml => g.Term.SimpleExpr1 + case _: Term.Apply => g.Term.SimpleExpr1 + case _: Term.ApplyType => g.Term.SimpleExpr1 + case t: Term.ApplyInfix => g.Term.InfixExpr(t.op.value) + case t: Term.ApplyUnary => g.Term.PrefixExpr(t.op.value) + case _: Term.Assign => g.Term.Expr1 + case _: Term.Return => g.Term.Expr1 + case _: Term.Throw => g.Term.Expr1 + case _: Term.Ascribe => g.Term.Expr1 + case _: Term.Annotate => g.Term.Expr1 + case _: Term.Block => g.Term.SimpleExpr1 + case _: Term.Tuple => g.Term.SimpleExpr1 // ???, breaks a op ((b, c)) // case _: Term.Tuple => g.Term.Expr1 // ??? Was SimpleExpr1, which is buggy for `a op ((b, c)) - case _: Term.If => g.Term.Expr1 - case _: Term.Match => g.Term.Expr1 - case _: Term.Try => g.Term.Expr1 - case _: Term.TryWithHandler => g.Term.Expr1 - case _: Term.FunctionTerm => g.Term.Expr - case _: Term.PolyFunction => g.Term.Expr - case _: Term.PartialFunction => g.Term.SimpleExpr - case _: Term.While => g.Term.Expr1 - case _: Term.Do => g.Term.Expr1 - case _: Term.For => g.Term.Expr1 - case _: Term.ForYield => g.Term.Expr1 - case _: Term.New => g.Term.SimpleExpr - case _: Term.Placeholder => g.Term.SimpleExpr1 - case _: Term.Eta => g.Term.SimpleExpr - case _: Term.Repeated => g.Term.PostfixExpr - case _: Term.Param => g.Path // ??? - // Type - case _: Type.Name => g.Path - case _: Type.TypedParam => g.Type.SimpleTyp - case _: Type.Select => g.Type.SimpleTyp - case _: Type.Project => g.Type.SimpleTyp - case _: Type.Singleton => g.Type.SimpleTyp - case _: Type.Apply => g.Type.SimpleTyp - case t: Type.ApplyInfix => g.Type.InfixTyp(t.op.value) - case _: Type.FunctionType => g.Type.Typ - case _: Type.PolyFunction => g.Type.Typ - case _: Type.Tuple => g.Type.SimpleTyp - case _: Type.With => g.Type.WithTyp - case _: Type.Refine => g.Type.RefineTyp - case _: Type.Existential => g.Type.Typ - case _: Type.Annotate => g.Type.AnnotTyp - case _: Type.Lambda => g.Type.Typ - case _: Type.AnonymousParam => g.Type.SimpleTyp - case _: Type.Wildcard => g.Type.SimpleTyp - case _: Type.Bounds => g.Path // ??? - case _: Type.Repeated => g.Type.ParamTyp - case _: Type.ByName => g.Type.ParamTyp - case _: Type.Var => g.Type.ParamTyp - case _: Type.Param => g.Path // ??? - case _: Type.Match => g.Type.Typ - // Pat - case _: Pat.Var => g.Pat.SimplePattern - case _: Pat.Wildcard => g.Pat.SimplePattern - case _: Pat.SeqWildcard => g.Pat.SimplePattern - case _: Pat.Bind => g.Pat.Pattern2 - case _: Pat.Alternative => g.Pat.Pattern - case _: Pat.Tuple => g.Pat.SimplePattern - case _: Pat.Extract => g.Pat.SimplePattern - case t: Pat.ExtractInfix => g.Pat.Pattern3(t.op.value) - case _: Pat.Interpolate => g.Pat.SimplePattern - case _: Pat.Xml => g.Pat.SimplePattern - case _: Pat.Typed => g.Pat.Pattern1 + case _: Term.If => g.Term.Expr1 + case _: Term.Match => g.Term.Expr1 + case _: Term.Try => g.Term.Expr1 + case _: Term.TryWithHandler => g.Term.Expr1 + case _: Term.FunctionTerm => g.Term.Expr + case _: Term.PolyFunction => g.Term.Expr + case _: Term.PartialFunction => g.Term.SimpleExpr + case _: Term.While => g.Term.Expr1 + case _: Term.Do => g.Term.Expr1 + case _: Term.For => g.Term.Expr1 + case _: Term.ForYield => g.Term.Expr1 + case _: Term.New => g.Term.SimpleExpr + case _: Term.Placeholder => g.Term.SimpleExpr1 + case _: Term.Eta => g.Term.SimpleExpr + case _: Term.Repeated => g.Term.PostfixExpr + case _: Term.Param => g.Path // ??? + // Type + case _: Type.Name => g.Path + case _: Type.TypedParam => g.Type.SimpleTyp + case _: Type.Select => g.Type.SimpleTyp + case _: Type.Project => g.Type.SimpleTyp + case _: Type.Singleton => g.Type.SimpleTyp + case _: Type.Apply => g.Type.SimpleTyp + case t: Type.ApplyInfix => g.Type.InfixTyp(t.op.value) + case _: Type.FunctionType => g.Type.Typ + case _: Type.PolyFunction => g.Type.Typ + case _: Type.Tuple => g.Type.SimpleTyp + case _: Type.With => g.Type.WithTyp + case _: Type.Refine => g.Type.RefineTyp + case _: Type.Existential => g.Type.Typ + case _: Type.Annotate => g.Type.AnnotTyp + case _: Type.Lambda => g.Type.Typ + case _: Type.AnonymousParam => g.Type.SimpleTyp + case _: Type.Wildcard => g.Type.SimpleTyp + case _: Type.Bounds => g.Path // ??? + case _: Type.Repeated => g.Type.ParamTyp + case _: Type.ByName => g.Type.ParamTyp + case _: Type.Var => g.Type.ParamTyp + case _: Type.Param => g.Path // ??? + case _: Type.Match => g.Type.Typ + // Pat + case _: Pat.Var => g.Pat.SimplePattern + case _: Pat.Wildcard => g.Pat.SimplePattern + case _: Pat.SeqWildcard => g.Pat.SimplePattern + case _: Pat.Bind => g.Pat.Pattern2 + case _: Pat.Alternative => g.Pat.Pattern + case _: Pat.Tuple => g.Pat.SimplePattern + case _: Pat.Extract => g.Pat.SimplePattern + case t: Pat.ExtractInfix => g.Pat.Pattern3(t.op.value) + case _: Pat.Interpolate => g.Pat.SimplePattern + case _: Pat.Xml => g.Pat.SimplePattern + case _: Pat.Typed => g.Pat.Pattern1 - // Misc - case _ => g.Path - } + // Misc + case _ => g.Path + } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/AvoidInfix.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/AvoidInfix.scala index 89fffa4fc1..5af8460c23 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/AvoidInfix.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/AvoidInfix.scala @@ -12,8 +12,7 @@ object AvoidInfix extends RewriteFactory { override def hasChanged(v1: RewriteSettings, v2: RewriteSettings): Boolean = v2.avoidInfix ne v1.avoidInfix - override def create(implicit ctx: RewriteCtx): RewriteSession = - new AvoidInfix + override def create(implicit ctx: RewriteCtx): RewriteSession = new AvoidInfix } @@ -28,54 +27,54 @@ class AvoidInfix(implicit ctx: RewriteCtx) extends RewriteSession { // and be done with it. However, until transform becomes token aware (see https://github.com/scalameta/scalameta/pull/457) // we will do these dangerous rewritings by hand. - override def rewrite(tree: Tree): Unit = - tree match { - case (x: Term.ApplyInfix) if checkMatchingInfix(x) => - val builder = Seq.newBuilder[TokenPatch] + override def rewrite(tree: Tree): Unit = tree match { + case (x: Term.ApplyInfix) if checkMatchingInfix(x) => + val builder = Seq.newBuilder[TokenPatch] - val (opHead, opLast) = ends(x.op) - builder += TokenPatch.AddLeft(opHead, ".", keepTok = true) + val (opHead, opLast) = ends(x.op) + builder += TokenPatch.AddLeft(opHead, ".", keepTok = true) - def moveOpenDelim(prev: Token, open: Token): Unit = { - // move delimiter (before comment or newline) - builder += TokenPatch.AddRight(prev, open.syntax, keepTok = true) - builder += TokenPatch.Remove(open) - } + def moveOpenDelim(prev: Token, open: Token): Unit = { + // move delimiter (before comment or newline) + builder += TokenPatch.AddRight(prev, open.syntax, keepTok = true) + builder += TokenPatch.Remove(open) + } - // move the left bracket if targs - val beforeLp = - if (x.targClause.values.isEmpty) opLast - else { - val (targsHead, targsLast) = ends(x.targClause) - moveOpenDelim(opLast, targsHead) - targsLast - } - // move the left paren if enclosed, else enclose - val (argsHead, argsLast) = ends(x.argClause) - if (ctx.getMatchingOpt(argsHead).exists(argsLast.end <= _.end)) - moveOpenDelim(beforeLp, argsHead) + // move the left bracket if targs + val beforeLp = + if (x.targClause.values.isEmpty) opLast else { - builder += TokenPatch.AddRight(beforeLp, "(", keepTok = true) - builder += TokenPatch.AddRight(argsLast, ")", keepTok = true) + val (targsHead, targsLast) = ends(x.targClause) + moveOpenDelim(opLast, targsHead) + targsLast } + // move the left paren if enclosed, else enclose + val (argsHead, argsLast) = ends(x.argClause) + if (ctx.getMatchingOpt(argsHead).exists(argsLast.end <= _.end)) + moveOpenDelim(beforeLp, argsHead) + else { + builder += TokenPatch.AddRight(beforeLp, "(", keepTok = true) + builder += TokenPatch.AddRight(argsLast, ")", keepTok = true) + } - val (lhsHead, lhsLast) = ends(x.lhs) - val shouldWrapLhs = !isWrapped(lhsHead, lhsLast) && (x.lhs match { + val (lhsHead, lhsLast) = ends(x.lhs) + val shouldWrapLhs = !isWrapped(lhsHead, lhsLast) && + (x.lhs match { case y: Term.ApplyInfix => !checkMatchingInfix(y) // foo _ compose bar => (foo _).compose(bar) // new Foo compose bar => (new Foo).compose(bar) case _: Term.Eta | _: Term.New => true case _ => false }) - if (shouldWrapLhs) { - builder += TokenPatch.AddLeft(lhsHead, "(", keepTok = true) - builder += TokenPatch.AddRight(lhsLast, ")", keepTok = true) - } + if (shouldWrapLhs) { + builder += TokenPatch.AddLeft(lhsHead, "(", keepTok = true) + builder += TokenPatch.AddRight(lhsLast, ")", keepTok = true) + } - ctx.addPatchSet(builder.result(): _*) + ctx.addPatchSet(builder.result(): _*) - case _ => - } + case _ => + } @tailrec private def checkMatchingInfix(ai: Term.ApplyInfix): Boolean = { @@ -85,7 +84,8 @@ class AvoidInfix(implicit ctx: RewriteCtx) extends RewriteSession { case ac @ Term.ArgClause(arg :: Nil, _) if !isWrapped(ac) => !hasPlaceholder(arg, ctx.style.rewrite.isAllowInfixPlaceholderArg) case _ => true - }) && (ai.lhs match { + }) && + (ai.lhs match { case lhs: Term.ApplyInfix if hasPlaceholder(lhs, true) => isWrapped(lhs) || checkMatchingInfix(lhs) case _ => true @@ -93,14 +93,12 @@ class AvoidInfix(implicit ctx: RewriteCtx) extends RewriteSession { } @inline - private def isMatching(head: Token, last: => Token): Boolean = - head.is[Token.LeftParen] && ctx.isMatching(head, last) + private def isMatching(head: Token, last: => Token): Boolean = head + .is[Token.LeftParen] && ctx.isMatching(head, last) private def isWrapped(head: Token, last: Token): Boolean = - isMatching(head, last) || - ctx.tokenTraverser.prevNonTrivialToken(head).exists { - isMatching(_, nextNonTrivial(last).orNull) - } + isMatching(head, last) || ctx.tokenTraverser.prevNonTrivialToken(head) + .exists { isMatching(_, nextNonTrivial(last).orNull) } private def ends(t: Tree): (Token, Token) = { val tokens = t.tokens @@ -113,7 +111,7 @@ class AvoidInfix(implicit ctx: RewriteCtx) extends RewriteSession { } @inline - private def nextNonTrivial(token: Token): Option[Token] = - ctx.tokenTraverser.nextNonTrivialToken(token) + private def nextNonTrivial(token: Token): Option[Token] = ctx.tokenTraverser + .nextNonTrivialToken(token) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/ConvertToNewScala3Syntax.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/ConvertToNewScala3Syntax.scala index 2abb510931..5df92439bf 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/ConvertToNewScala3Syntax.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/ConvertToNewScala3Syntax.scala @@ -40,30 +40,24 @@ private class ConvertToNewScala3Syntax(implicit val ftoks: FormatTokens) case _: Token.LeftParen if flag.control && dialect.allowSignificantIndentation => ft.meta.rightOwner match { - case _: Term.If if left.is[Token.KwIf] => - removeToken - case _: Term.While if left.is[Token.KwWhile] => - removeToken - case _: Term.For if left.is[Token.KwFor] => - removeToken - case _: Term.ForYield if left.is[Token.KwFor] => - removeToken + case _: Term.If if left.is[Token.KwIf] => removeToken + case _: Term.While if left.is[Token.KwWhile] => removeToken + case _: Term.For if left.is[Token.KwFor] => removeToken + case _: Term.ForYield if left.is[Token.KwFor] => removeToken case _ => null } case _: Token.Colon if flag.deprecated && dialect.allowPostfixStarVarargSplices => ft.meta.rightOwner match { - case t: Term.Repeated if isSimpleRepeated(t) => - removeToken // trick: to get "*", just remove ":" and "_" + case t: Term.Repeated if isSimpleRepeated(t) => removeToken // trick: to get "*", just remove ":" and "_" case _ => null } case _: Token.At if flag.deprecated && dialect.allowPostfixStarVarargSplices => ft.meta.rightOwner match { - case Pat.Bind(_, _: Pat.SeqWildcard) => - removeToken // trick: to get "*", just remove "@" and "_" + case Pat.Bind(_, _: Pat.SeqWildcard) => removeToken // trick: to get "*", just remove "@" and "_" case _ => null } @@ -80,8 +74,7 @@ private class ConvertToNewScala3Syntax(implicit val ftoks: FormatTokens) removeToken // see above, under Colon case t: Pat.SeqWildcard if dialect.allowPostfixStarVarargSplices && - t.parent.exists(_.is[Pat.Bind]) => - removeToken // see above, under At + t.parent.exists(_.is[Pat.Bind]) => removeToken // see above, under At case _ => null } @@ -119,9 +112,7 @@ private class ConvertToNewScala3Syntax(implicit val ftoks: FormatTokens) ft.meta.rightOwner match { case _: Term.If => if (!nextRight.is[Token.KwThen]) - replaceToken("then")( - new Token.KwThen(x.input, x.dialect, x.start) - ) + replaceToken("then")(new Token.KwThen(x.input, x.dialect, x.start)) else removeToken case _: Term.While | _: Term.For => if (!nextRight.is[Token.KwDo]) @@ -134,7 +125,7 @@ private class ConvertToNewScala3Syntax(implicit val ftoks: FormatTokens) } }.map((left, _)) - private def isSimpleRepeated(t: Term.Repeated): Boolean = - t.expr.isNot[Term.ApplyInfix] || ftoks.isEnclosedInParens(t.expr) + private def isSimpleRepeated(t: Term.Repeated): Boolean = t.expr + .isNot[Term.ApplyInfix] || ftoks.isEnclosedInParens(t.expr) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/FormatTokensRewrite.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/FormatTokensRewrite.scala index 0226c39787..17e0e421a4 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/FormatTokensRewrite.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/FormatTokensRewrite.scala @@ -61,7 +61,8 @@ class FormatTokensRewrite( val idx = ft.meta.idx val ftOld = arr(idx) val rtOld = ftOld.right - @inline def mapOld(dstidx: Int) = { + @inline + def mapOld(dstidx: Int) = { remapped = true tokenMap += FormatTokens.thash(rtOld) -> dstidx } @@ -155,26 +156,24 @@ class FormatTokensRewrite( formatOffStack.prepend(formatOff) val ldelimIdxOpt = if (formatOff) None - else - session.claimedRule match { - case Some(c) => applyRule(c.rule) - case _ => applyRules - } + else session.claimedRule match { + case Some(c) => applyRule(c.rule) + case _ => applyRules + } val ldelimIdx = ldelimIdxOpt.getOrElse(session.claim(null)) leftDelimIndex.prepend(ldelimIdx) case _: T.RightBrace | _: T.RightParen | _: T.RightBracket => val formatOff = formatOffStack.remove(0) val ldelimIdx = leftDelimIndex.remove(0) - if (formatOff && formatOffStack.nonEmpty) - formatOffStack.update(0, true) + if (formatOff && formatOffStack.nonEmpty) formatOffStack + .update(0, true) val left = tokens(ldelimIdx) if (left ne null) { val ko = ft.meta.formatOff || session.claimedRule.exists(_.rule ne left.rule) - if (ko) { - tokens(ldelimIdx) = null - } else { + if (ko) { tokens(ldelimIdx) = null } + else { implicit val style = styleMap.at(ft.right) left.onRightAndClaim(formatOff, ldelimIdx) } @@ -185,8 +184,7 @@ class FormatTokensRewrite( case _: T.Comment => // formatOff gets set only by comment if (!ft.meta.formatOff) applyRules - else if (formatOffStack.nonEmpty) - formatOffStack.update(0, true) + else if (formatOffStack.nonEmpty) formatOffStack.update(0, true) case _ if ft.meta.formatOff => @@ -206,10 +204,9 @@ class FormatTokensRewrite( session.applyRules(rules) } - private def applyRule(rule: Rule)(implicit - ft: FormatToken, - session: Session - ): Option[Int] = { + private def applyRule( + rule: Rule + )(implicit ft: FormatToken, session: Session): Option[Int] = { implicit val style = styleMap.at(ft.right) session.applyRule(rule) } @@ -243,13 +240,11 @@ object FormatTokensRewrite { protected final def removeToken(implicit ft: FormatToken, style: ScalafmtConfig - ): Replacement = - removeToken(Nil) + ): Replacement = removeToken(Nil) - protected final def removeToken(claim: Iterable[Int] = Nil)(implicit - ft: FormatToken, - style: ScalafmtConfig - ): Replacement = + protected final def removeToken( + claim: Iterable[Int] = Nil + )(implicit ft: FormatToken, style: ScalafmtConfig): Replacement = Replacement(this, ft, ReplacementType.Remove, style, claim) protected final def replaceToken( @@ -293,10 +288,7 @@ object FormatTokensRewrite { def getEnabledFactories(implicit style: ScalafmtConfig): Seq[RuleFactory] = getFactories.filter(_.enabled) - def apply( - ftoks: FormatTokens, - styleMap: StyleMap - ): FormatTokens = { + def apply(ftoks: FormatTokens, styleMap: StyleMap): FormatTokens = { val enabledFactories = getEnabledFactories(styleMap.init).sortBy(_.priority) val rules = enabledFactories.map(_.create(ftoks)) if (rules.isEmpty) ftoks @@ -325,35 +317,32 @@ object FormatTokensRewrite { claimedRule(ft.meta.idx) @inline - private[rewrite] def claimedRule(ftIdx: Int): Option[Replacement] = - claimed.get(ftIdx).map(tokens.apply).filter(_ ne null) + private[rewrite] def claimedRule(ftIdx: Int): Option[Replacement] = claimed + .get(ftIdx).map(tokens.apply).filter(_ ne null) private[rewrite] def claim(ftIdx: Int, repl: Replacement): Int = { justClaim(ftIdx) { if (repl eq null) null - else - (repl.how match { - case rt: ReplacementType.RemoveAndResurrect => - val rtidx = rt.ft.meta.idx - def swapWith(oldidx: Int) = Some { - tokens(oldidx) = repl.copy(ft = repl.ft.withIdx(rtidx)) - repl.copy(ft = rt.ft.withIdx(repl.idx)) - } - getClaimed(rtidx) match { - case Some((oidx, x)) if x != null && x.isRemove => - swapWith(oidx) - case _ => None - } - case _ => None - }).getOrElse(repl) + else (repl.how match { + case rt: ReplacementType.RemoveAndResurrect => + val rtidx = rt.ft.meta.idx + def swapWith(oldidx: Int) = Some { + tokens(oldidx) = repl.copy(ft = repl.ft.withIdx(rtidx)) + repl.copy(ft = rt.ft.withIdx(repl.idx)) + } + getClaimed(rtidx) match { + case Some((oidx, x)) if x != null && x.isRemove => swapWith(oidx) + case _ => None + } + case _ => None + }).getOrElse(repl) } } @inline private[rewrite] def claim(repl: Replacement)(implicit ft: FormatToken - ): Int = - claim(ft.meta.idx, repl) + ): Int = claim(ft.meta.idx, repl) private def justClaim(ftIdx: Int)(repl: Replacement): Int = { val idx = tokens.length @@ -370,8 +359,7 @@ object FormatTokensRewrite { } else { require(ftIdx > maxClaimed, s"claiming token at $ftIdx <= $maxClaimed") maxClaimed = ftIdx - if (preClaimed) - claimed.update(ftIdx, idx) + if (preClaimed) claimed.update(ftIdx, idx) tokens.append(repl) idx } @@ -392,8 +380,7 @@ object FormatTokensRewrite { )(implicit ft: FormatToken, style: ScalafmtConfig): Option[Int] = { @tailrec def iter(remainingRules: Seq[Rule]): Option[Int] = remainingRules match { - case r +: rs => - applyRule(r) match { + case r +: rs => applyRule(r) match { case None => iter(rs) case x => x } @@ -428,8 +415,10 @@ object FormatTokensRewrite { // list of FormatToken indices, with the claimed token on the **right** claim: Iterable[Int] = Nil ) { - @inline def isRemove: Boolean = how eq ReplacementType.Remove - @inline def idx: Int = ft.meta.idx + @inline + def isRemove: Boolean = how eq ReplacementType.Remove + @inline + def idx: Int = ft.meta.idx def onRight(hasFormatOff: Boolean)(implicit ft: FormatToken, diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Imports.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Imports.scala index 38f2fedff4..5cf9b95210 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Imports.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Imports.scala @@ -33,14 +33,14 @@ object Imports extends RewriteFactory { def noGroups: Boolean = sort.eq(Sort.none) && numGroups == 0 - def group(str: String): Int = - regex.find(_._1.matcher(str).matches()).fold(numGroups)(_._2) + def group(str: String): Int = regex.find(_._1.matcher(str).matches()) + .fold(numGroups)(_._2) } object Settings { implicit val surface: generic.Surface[Settings] = generic.deriveSurface - implicit val codec: ConfCodecEx[Settings] = - generic.deriveCodecEx(new Settings).noTypos + implicit val codec: ConfCodecEx[Settings] = generic + .deriveCodecEx(new Settings).noTypos } sealed abstract class ContiguousGroups @@ -48,8 +48,8 @@ object Imports extends RewriteFactory { case object no extends ContiguousGroups case object only extends ContiguousGroups - implicit val codec: ConfCodecEx[ContiguousGroups] = - ReaderUtil.oneOf(only, no) + implicit val codec: ConfCodecEx[ContiguousGroups] = ReaderUtil + .oneOf(only, no) } override def hasChanged(v1: RewriteSettings, v2: RewriteSettings): Boolean = @@ -57,22 +57,18 @@ object Imports extends RewriteFactory { override def create(implicit ctx: RewriteCtx): RewriteSession = { val settings = ctx.style.rewrite.imports - if (settings.expand) - new ExpandFull - else if (settings.numGroups != 0) - new ExpandPart - else if (settings.sort ne Sort.none) - new ExpandNone - else - new RewriteSession.None() + if (settings.expand) new ExpandFull + else if (settings.numGroups != 0) new ExpandPart + else if (settings.sort ne Sort.none) new ExpandNone + else new RewriteSession.None() } private val allImportRules: Set[Rewrite] = Set(Imports, ExpandImportSelectors, SortImports, AsciiSortImports) def validateImports(obj: RewriteSettings): Configured[RewriteSettings] = { - val (importRules, nonImportRules) = - obj.rules.partition(allImportRules.contains) + val (importRules, nonImportRules) = obj.rules + .partition(allImportRules.contains) val ok = importRules.isEmpty || TreeOps.isSeqSingle(importRules) && importRules.head.eq(Imports) if (ok) Configured.Ok(obj) @@ -83,8 +79,8 @@ object Imports extends RewriteFactory { val err = "Incompatible rewrites: SortImports and AsciiSortImports" Configured.error(err) } else { - val expand = - obj.imports.expand || importRules.contains(ExpandImportSelectors) + val expand = obj.imports.expand || + importRules.contains(ExpandImportSelectors) val sort = if (sortAscii) Imports.Sort.ascii else if (sortOriginal) Imports.Sort.original @@ -117,8 +113,7 @@ object Imports extends RewriteFactory { owner: Importer ): Unit = { val stat = s"$kw $ref${selectors.pretty}" - if (stats.add(stat)) - buffer += GroupingEntry(stat, ref, selectors, owner) + if (stats.add(stat)) buffer += GroupingEntry(stat, ref, selectors, owner) } def result(): Seq[GroupingEntry] = try buffer.result() @@ -147,12 +142,12 @@ object Imports extends RewriteFactory { private object Sort { - implicit val reader: ConfCodecEx[Sort] = - ReaderUtil.oneOf[Sort](none, ascii, original, scalastyle) + implicit val reader: ConfCodecEx[Sort] = ReaderUtil + .oneOf[Sort](none, ascii, original, scalastyle) case object none extends Sort { - def sortSelector(buf: Seq[Importee]): Seq[(Importee, String)] = - buf.map(selectorToTuple) + def sortSelector(buf: Seq[Importee]): Seq[(Importee, String)] = buf + .map(selectorToTuple) def sortGrouping(buf: Seq[GroupingEntry]): Iterable[GroupingEntry] = buf } @@ -188,7 +183,8 @@ object Imports extends RewriteFactory { val others = new ListBuffer[(Importee, String)] val givens = new ListBuffer[(Importee, String)] val wildcards = new ListBuffer[(Importee, String)] - @inline def getDstBuf(x: Importee) = + @inline + def getDstBuf(x: Importee) = if (x.is[Importee.Given]) givens else if (isWildcard(x)) wildcards else others @@ -197,8 +193,8 @@ object Imports extends RewriteFactory { .flatMap(_.result().sortBy(_._2)(selectorOrdering)) } - def sortGrouping(buf: Seq[GroupingEntry]): Iterable[GroupingEntry] = - buf.view.sorted(GroupingEntryOrdering) + def sortGrouping(buf: Seq[GroupingEntry]): Iterable[GroupingEntry] = buf + .view.sorted(GroupingEntryOrdering) } case object ascii extends SortBase { @@ -225,8 +221,8 @@ object Imports extends RewriteFactory { case Character.LOWERCASE_LETTER => 1 case _ => 0 } - override protected def compareTail(x: String, y: String): Int = - x.compare(y) + override protected def compareTail(x: String, y: String): Int = x + .compare(y) } } @@ -240,8 +236,8 @@ object Imports extends RewriteFactory { case Character.LOWERCASE_LETTER => 2 case _ => 0 } - override protected def compareTail(x: String, y: String): Int = - x.compareToIgnoreCase(y) + override protected def compareTail(x: String, y: String): Int = x + .compareToIgnoreCase(y) } private object SelectorOrdering extends FirstLetterRankOrdering { @@ -250,17 +246,17 @@ object Imports extends RewriteFactory { case Character.LOWERCASE_LETTER => 1 case _ => 0 } - override protected def compareTail(x: String, y: String): Int = - x.compareToIgnoreCase(y) + override protected def compareTail(x: String, y: String): Int = x + .compareToIgnoreCase(y) } } } - private final def isRename(importee: Importee): Boolean = - importee.is[Importee.Rename] || importee.is[Importee.Unimport] + private final def isRename(importee: Importee): Boolean = importee + .is[Importee.Rename] || importee.is[Importee.Unimport] - private final def isWildcard(importee: Importee): Boolean = - importee.is[Importee.Wildcard] || importee.is[Importee.GivenAll] + private final def isWildcard(importee: Importee): Boolean = importee + .is[Importee.Wildcard] || importee.is[Importee.GivenAll] private abstract class Base(implicit ctx: RewriteCtx) extends RewriteSession { @@ -368,16 +364,15 @@ object Imports extends RewriteFactory { } } - private final def mustUseBraces(tree: Importee): Boolean = - (tree match { - case t: Importee.Rename => Some(t.name) - case t: Importee.Unimport => Some(t.name) - case _ => None - }).exists { x => - val tokenAfter = ctx.tokenTraverser.nextNonTrivialToken(x.tokens.last) - // in scala3, `as` doesn't need braces - tokenAfter.exists(_.is[Token.RightArrow]) - } + private final def mustUseBraces(tree: Importee): Boolean = (tree match { + case t: Importee.Rename => Some(t.name) + case t: Importee.Unimport => Some(t.name) + case _ => None + }).exists { x => + val tokenAfter = ctx.tokenTraverser.nextNonTrivialToken(x.tokens.last) + // in scala3, `as` doesn't need braces + tokenAfter.exists(_.is[Token.RightArrow]) + } protected final def getCommentsAround( tree: Tree @@ -392,8 +387,7 @@ object Imports extends RewriteFactory { var hadLf = false val slc = new ListBuffer[Token] ctx.tokenTraverser.findAtOrBefore(ctx.getIndex(tok) - 1) { - case _: Token.LF => - if (hadLf) Some(true) else { hadLf = true; None } + case _: Token.LF => if (hadLf) Some(true) else { hadLf = true; None } case t: Token.Comment if TokenOps.isSingleLineIfComment(t) => slc.prepend(t); hadLf = false; None case _: Token.Whitespace => None @@ -402,11 +396,10 @@ object Imports extends RewriteFactory { slc.result() } - protected final def getCommentAfter(tok: Token): Option[Token] = - ctx.tokenTraverser.findAtOrAfter(ctx.getIndex(tok) + 1) { + protected final def getCommentAfter(tok: Token): Option[Token] = ctx + .tokenTraverser.findAtOrAfter(ctx.getIndex(tok) + 1) { case _: Token.LF => Some(false) - case t: Token.Comment if TokenOps.isSingleLineIfComment(t) => - Some(true) + case t: Token.Comment if TokenOps.isSingleLineIfComment(t) => Some(true) case _: Token.Whitespace | _: Token.Comma => None case _ => Some(false) } @@ -429,8 +422,7 @@ object Imports extends RewriteFactory { ref: String, selector: Importee, importer: Importer - ): Unit = - group.add(kw, ref, getSelector(selector, true), importer) + ): Unit = group.add(kw, ref, getSelector(selector, true), importer) protected final def addToGroup( group: Grouping, @@ -438,9 +430,8 @@ object Imports extends RewriteFactory { ref: String, selectors: Seq[Importee], importer: Importer - ): Unit = - if (selectors.nonEmpty) - group.add(kw, ref, getSelectors(selectors, true), importer) + ): Unit = if (selectors.nonEmpty) group + .add(kw, ref, getSelectors(selectors, true), importer) private def processImports(stats: Iterable[ImportExportStat]): String = { val indent = { @@ -468,7 +459,8 @@ object Imports extends RewriteFactory { } val seenImports = new HashMap[Importer, Int] val sb = new StringBuilder() - @inline def appendIndent(): Unit = if (sb.nonEmpty) sb.append(indent) + @inline + def appendIndent(): Unit = if (sb.nonEmpty) sb.append(indent) groups.foreach { group => val entries = group.result() if (entries.nonEmpty) { @@ -493,8 +485,7 @@ object Imports extends RewriteFactory { if (newImporteeCount != x.owner.importees.length) None else if (p.importers.lastOption.contains(x.owner)) getCommentAfter(p.tokens.last) - else - getCommentAfter(x.owner.tokens.last) + else getCommentAfter(x.owner.tokens.last) } (headComments ++ x.selectors.commentsBefore, tailComments) case _ => (Seq.empty, None) @@ -516,12 +507,10 @@ object Imports extends RewriteFactory { override protected def processImports( stats: Seq[Seq[ImportExportStat]] ): Unit = - if (settings.noGroups) - processEachLine(stats) + if (settings.noGroups) processEachLine(stats) else if (settings.contiguousGroups eq ContiguousGroups.only) processEachGroup(stats) - else - processAllGroups(stats) + else processAllGroups(stats) private def getTokenRange(x: Seq[ImportExportStat]): (Token, Token) = { val headTok = x.head.tokens.head @@ -532,8 +521,8 @@ object Imports extends RewriteFactory { ) } - private def processEachLine(stats: Seq[Seq[ImportExportStat]]): Unit = - stats.flatten.foreach { stat => + private def processEachLine(stats: Seq[Seq[ImportExportStat]]): Unit = stats + .flatten.foreach { stat => val group = Seq(stat) val importString = processImports(group) processTokenRanges(importString, getTokenRange(group)) @@ -567,8 +556,7 @@ object Imports extends RewriteFactory { tokenRanges.foreach { case (beg, end) => val begIdx = ctx.tokenTraverser.getIndex(beg) val endIdx = ctx.tokenTraverser.getIndex(end) - tokens - .slice(if (beg eq first) begIdx + 1 else begIdx, endIdx + 1) + tokens.slice(if (beg eq first) begIdx + 1 else begIdx, endIdx + 1) .foreach(patchBuilder += TokenPatch.Remove(_)) ctx.removeLFToAvoidEmptyLine(begIdx, endIdx) } @@ -627,8 +615,7 @@ object Imports extends RewriteFactory { kw: String, ref: String, importer: Importer - ): Unit = - addToGroup(group, kw, ref, importer.importees, importer) + ): Unit = addToGroup(group, kw, ref, importer.importees, importer) } /** convert diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Patch.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Patch.scala index 8f252901dc..b50cd4e717 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Patch.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Patch.scala @@ -16,8 +16,7 @@ object TokenPatch { tok: Token, toAdd: String, keepTok: Boolean = false - ): TokenPatch = - Add(tok, "", toAdd, keepTok) + ): TokenPatch = Add(tok, "", toAdd, keepTok) def AddLeft(tok: Token, toAdd: String, keepTok: Boolean = false): TokenPatch = Add(tok, toAdd, "", keepTok) case class Add( @@ -25,32 +24,26 @@ object TokenPatch { addLeft: String, addRight: String, keepTok: Boolean - ) extends TokenPatch( - tok, - s"""$addLeft${if (keepTok) tok else ""}$addRight""" - ) + ) extends TokenPatch(tok, s"""$addLeft${if (keepTok) tok else ""}$addRight""") } object Patch { - def merge(a: TokenPatch, b: TokenPatch): TokenPatch = - (a, b) match { - case (add1: Add, add2: Add) => - Add( - add1.tok, - add1.addLeft + add2.addLeft, - add1.addRight + add2.addRight, - add1.keepTok && add2.keepTok - ) - case (_: Remove, add: Add) => add.copy(keepTok = false) - case (add: Add, _: Remove) => add.copy(keepTok = false) - case (rem: Remove, _: Remove) => rem - case _ => - sys.error( - s"""Can't merge token patches: - |1. $a - |2. $b""".stripMargin - ) - } + def merge(a: TokenPatch, b: TokenPatch): TokenPatch = (a, b) match { + case (add1: Add, add2: Add) => Add( + add1.tok, + add1.addLeft + add2.addLeft, + add1.addRight + add2.addRight, + add1.keepTok && add2.keepTok + ) + case (_: Remove, add: Add) => add.copy(keepTok = false) + case (add: Add, _: Remove) => add.copy(keepTok = false) + case (rem: Remove, _: Remove) => rem + case _ => sys.error( + s"""Can't merge token patches: + |1. $a + |2. $b""".stripMargin + ) + } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/PreferCurlyFors.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/PreferCurlyFors.scala index 82152a709b..35a85b215d 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/PreferCurlyFors.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/PreferCurlyFors.scala @@ -21,15 +21,12 @@ object PreferCurlyFors extends Rewrite with FormatTokensRewrite.RuleFactory { // first one is never a guard enums.view.drop(1).exists(!_.is[Enumerator.Guard]) - case class Settings( - removeTrailingSemicolonsOnly: Boolean = false - ) + case class Settings(removeTrailingSemicolonsOnly: Boolean = false) object Settings { - implicit lazy val surface: generic.Surface[Settings] = - generic.deriveSurface - implicit lazy val codec: ConfCodecEx[Settings] = - generic.deriveCodecEx(Settings()).noTypos + implicit lazy val surface: generic.Surface[Settings] = generic.deriveSurface + implicit lazy val codec: ConfCodecEx[Settings] = generic + .deriveCodecEx(Settings()).noTypos } } @@ -94,15 +91,14 @@ private class PreferCurlyFors(implicit val ftoks: FormatTokens) ft: FormatToken, session: Session, style: ScalafmtConfig - ): Option[(Replacement, Replacement)] = - ft.right match { - case x: Token.RightParen - if left.how == ReplacementType.Replace && - left.ft.right.is[Token.LeftBrace] => - val right = - replaceToken("}")(new Token.RightBrace(x.input, x.dialect, x.start)) - Some((left, right)) - case _ => None - } + ): Option[(Replacement, Replacement)] = ft.right match { + case x: Token.RightParen + if left.how == ReplacementType.Replace && + left.ft.right.is[Token.LeftBrace] => + val right = + replaceToken("}")(new Token.RightBrace(x.input, x.dialect, x.start)) + Some((left, right)) + case _ => None + } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RedundantBraces.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RedundantBraces.scala index 655e3628d1..f60e0e929c 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RedundantBraces.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RedundantBraces.scala @@ -14,23 +14,21 @@ object RedundantBraces extends Rewrite with FormatTokensRewrite.RuleFactory { override def enabled(implicit style: ScalafmtConfig): Boolean = true - override def create(implicit ftoks: FormatTokens): Rule = - new RedundantBraces + override def create(implicit ftoks: FormatTokens): Rule = new RedundantBraces def needParensAroundParams(f: Term.FunctionTerm): Boolean = /* either we have parens or no type; multiple params or * no params guarantee parens, so we look for type and * parens only for a single param */ f.paramClause match { - case pc @ Term.ParamClause(param :: Nil, _) => - param.decltpe.nonEmpty && !pc.tokens.head.is[Token.LeftParen] + case pc @ Term.ParamClause(param :: Nil, _) => param.decltpe.nonEmpty && + !pc.tokens.head.is[Token.LeftParen] case _ => false } def canRewriteBlockWithParens(b: Term.Block)(implicit ftoks: FormatTokens - ): Boolean = - getBlockSingleStat(b).exists(canRewriteStatWithParens) + ): Boolean = getBlockSingleStat(b).exists(canRewriteStatWithParens) def canRewriteStatWithParens(t: Stat)(implicit ftoks: FormatTokens): Boolean = t match { @@ -49,8 +47,8 @@ object RedundantBraces extends Rewrite with FormatTokensRewrite.RuleFactory { def canRewriteFuncWithParens( f: Term.FunctionTerm, nested: Boolean = false - ): Boolean = - !needParensAroundParams(f) && (getTreeSingleStat(f.body) match { + ): Boolean = !needParensAroundParams(f) && + (getTreeSingleStat(f.body) match { case Some(t: Term.FunctionTerm) => canRewriteFuncWithParens(t, true) case Some(_: Defn) => false case x => nested || x.isDefined @@ -96,10 +94,9 @@ class RedundantBraces(implicit val ftoks: FormatTokens) private def replaceWithEquals(implicit ft: FormatToken, style: ScalafmtConfig - ): Replacement = - replaceTokenBy("=") { x => - new Token.Equals(x.input, x.dialect, x.start) - } + ): Replacement = replaceTokenBy("=") { x => + new Token.Equals(x.input, x.dialect, x.start) + } private def onLeftParen(implicit ft: FormatToken, @@ -108,10 +105,8 @@ class RedundantBraces(implicit val ftoks: FormatTokens) val rt = ft.right val rtOwner = ft.meta.rightOwner def lpFunction = okToReplaceFunctionInSingleArgApply(rtOwner).map { - case (`rt`, f) => - f.body match { - case b: Term.Block => - ftoks.getHead(b) match { + case (`rt`, f) => f.body match { + case b: Term.Block => ftoks.getHead(b) match { case FormatToken(_: Token.LeftBrace, _, lbm) => replaceToken("{", claim = lbm.idx - 1 :: Nil) { new Token.LeftBrace(rt.input, rt.dialect, rt.start) @@ -129,12 +124,11 @@ class RedundantBraces(implicit val ftoks: FormatTokens) if !ta.parent.exists(_.is[Init]) => getOpeningParen(ta).map { lp => if (lp.ne(rt) || getBlockNestedPartialFunction(arg).isEmpty) null - else - ftoks.nextNonCommentAfter(ft) match { - case FormatToken(_, _: Token.LeftBrace, lbm) => - removeToken(claim = lbm.idx :: Nil) - case _ => null - } + else ftoks.nextNonCommentAfter(ft) match { + case FormatToken(_, _: Token.LeftBrace, lbm) => + removeToken(claim = lbm.idx :: Nil) + case _ => null + } } case _ => None } @@ -150,18 +144,18 @@ class RedundantBraces(implicit val ftoks: FormatTokens) case ReplacementType.Remove => val resOpt = getRightBraceBeforeRightParen(false).map { rb => ft.meta.rightOwner match { - case ac: Term.ArgClause => - ftoks.matchingOpt(rb.left).map(ftoks.justBefore).foreach { lb => - session.rule[RemoveScala3OptionalBraces].foreach { r => - session.getClaimed(lb.meta.idx).foreach { case (leftIdx, _) => - val repl = r.onLeftForArgClause(ac)(lb, left.style) - if (null ne repl) { - implicit val ft: FormatToken = ftoks.prev(rb) - repl.onRightAndClaim(hasFormatOff, leftIdx) + case ac: Term.ArgClause => ftoks.matchingOpt(rb.left) + .map(ftoks.justBefore).foreach { lb => + session.rule[RemoveScala3OptionalBraces].foreach { r => + session.getClaimed(lb.meta.idx).foreach { case (leftIdx, _) => + val repl = r.onLeftForArgClause(ac)(lb, left.style) + if (null ne repl) { + implicit val ft: FormatToken = ftoks.prev(rb) + repl.onRightAndClaim(hasFormatOff, leftIdx) + } } } } - } case _ => } (left, removeToken) @@ -171,8 +165,7 @@ class RedundantBraces(implicit val ftoks: FormatTokens) case ReplacementType.Replace if { val lft = left.ft val ro = ft.meta.rightOwner - (lft.meta.rightOwner eq ro) && - lft.right.is[Token.LeftBrace] + (lft.meta.rightOwner eq ro) && lft.right.is[Token.LeftBrace] } => val pftOpt = getRightBraceBeforeRightParen(true) def replaceIfAfterRightBrace = pftOpt.map { pft => @@ -185,11 +178,11 @@ class RedundantBraces(implicit val ftoks: FormatTokens) } } (ft.meta.rightOwner match { - case ac: Term.ArgClause => - session.rule[RemoveScala3OptionalBraces].flatMap { r => - val repl = r.onLeftForArgClause(ac)(left.ft, left.style) - if (repl eq null) None else repl.onRight(hasFormatOff) - } + case ac: Term.ArgClause => session.rule[RemoveScala3OptionalBraces] + .flatMap { r => + val repl = r.onLeftForArgClause(ac)(left.ft, left.style) + if (repl eq null) None else repl.onRight(hasFormatOff) + } case _ => None }).getOrElse { replaceIfAfterRightBrace.orNull // don't know how to Replace @@ -214,8 +207,7 @@ class RedundantBraces(implicit val ftoks: FormatTokens) session.claim(crepl)(crt) true } - case _: Token.RightBrace => - !session.isRemovedOnLeft(pft, !shouldBeRemoved) + case _: Token.RightBrace => !session.isRemovedOnLeft(pft, !shouldBeRemoved) case _ => false } if (ok) Some(pft) else None @@ -225,9 +217,7 @@ class RedundantBraces(implicit val ftoks: FormatTokens) ft: FormatToken, session: Session, style: ScalafmtConfig - ): Replacement = { - onLeftBrace(ft.meta.rightOwner) - } + ): Replacement = { onLeftBrace(ft.meta.rightOwner) } private def onLeftBrace(owner: Tree)(implicit ft: FormatToken, @@ -243,29 +233,23 @@ class RedundantBraces(implicit val ftoks: FormatTokens) owner match { case t: Term.FunctionTerm if t.tokens.last.is[Token.RightBrace] => - if (!okToRemoveFunctionInApplyOrInit(t)) null - else removeToken + if (!okToRemoveFunctionInApplyOrInit(t)) null else removeToken case t: Term.PartialFunction if t.parent.exists { p => SingleArgInBraces.orBlock(p).exists(_._2 eq t) && t.pos.start != p.pos.start - } => - removeToken - case t: Term.Block => - t.parent match { + } => removeToken + case t: Term.Block => t.parent match { case Some(f: Term.FunctionTerm) - if okToReplaceFunctionInSingleArgApply(f) => - removeToken + if okToReplaceFunctionInSingleArgApply(f) => removeToken case Some(_: Term.Interpolate) => handleInterpolation - case _ => - if (processBlock(t)) removeToken else null + case _ => if (processBlock(t)) removeToken else null } case _: Term.Interpolate => handleInterpolation case Importer(_, List(x)) if !(x.is[Importee.Rename] || x.is[Importee.Unimport]) || style.dialect.allowAsForImportRename && (ConvertToNewScala3Syntax.enabled || - !x.tokens.exists(_.is[Token.RightArrow])) => - removeToken + !x.tokens.exists(_.is[Token.RightArrow])) => removeToken case t: Ctor.Secondary if t.stats.isEmpty && isDefnBodiesEnabled(noParams = false) => val prevIsEquals = ftoks.prevNonComment(ft).left.is[Token.Equals] @@ -277,17 +261,15 @@ class RedundantBraces(implicit val ftoks: FormatTokens) private def onRightBrace(left: Replacement)(implicit ft: FormatToken, style: ScalafmtConfig - ): (Replacement, Replacement) = - (left, removeToken) + ): (Replacement, Replacement) = (left, removeToken) private def settings(implicit style: ScalafmtConfig - ): RedundantBracesSettings = - style.rewrite.redundantBraces + ): RedundantBracesSettings = style.rewrite.redundantBraces private def processInterpolation(implicit ft: FormatToken): Boolean = { - def isIdentifierAtStart(value: String) = - value.headOption.exists(x => Character.isLetterOrDigit(x) || x == '_') + def isIdentifierAtStart(value: String) = value.headOption + .exists(x => Character.isLetterOrDigit(x) || x == '_') def isLiteralIdentifier(arg: Term.Name): Boolean = { val syntax = arg.toString() @@ -300,14 +282,16 @@ class RedundantBraces(implicit val ftoks: FormatTokens) * formatting will result in compilation error (see * https://github.com/scalameta/scalafmt/issues/1420) */ - def shouldTermBeEscaped(arg: Term.Name): Boolean = - arg.value.head == '_' || isLiteralIdentifier(arg) + def shouldTermBeEscaped(arg: Term.Name): Boolean = arg.value.head == '_' || + isLiteralIdentifier(arg) val ft2 = ftoks(ft, 2) // should point to "name}" - ft2.right.is[Token.RightBrace] && (ft2.meta.leftOwner match { + ft2.right.is[Token.RightBrace] && + (ft2.meta.leftOwner match { case t: Term.Name => !shouldTermBeEscaped(t) case _ => false - }) && (ftoks(ft2, 2).right match { // skip splice end, to get interpolation part + }) && + (ftoks(ft2, 2).right match { // skip splice end, to get interpolation part case Token.Interpolation.Part(value) => !isIdentifierAtStart(value) case _ => false }) @@ -315,8 +299,8 @@ class RedundantBraces(implicit val ftoks: FormatTokens) private def okToReplaceFunctionInSingleArgApply(f: Term.FunctionTerm)(implicit style: ScalafmtConfig - ): Boolean = - f.parent.flatMap(okToReplaceFunctionInSingleArgApply).exists(_._2 eq f) + ): Boolean = f.parent.flatMap(okToReplaceFunctionInSingleArgApply) + .exists(_._2 eq f) private def getOpeningParen(t: Term.ArgClause): Option[Token.LeftParen] = ftoks.getHead(t).left match { @@ -328,16 +312,14 @@ class RedundantBraces(implicit val ftoks: FormatTokens) // a(b => { c; d }) change to a { b => c; d } private def okToReplaceFunctionInSingleArgApply(tree: Tree)(implicit style: ScalafmtConfig - ): Option[(Token.LeftParen, Term.FunctionTerm)] = - tree match { - case ta @ Term.ArgClause((func: Term.FunctionTerm) :: Nil, _) if { - val body = func.body - (body.is[Term.Block] || func.tokens.last.ne(body.tokens.last)) && - isParentAnApply(ta) && okToRemoveAroundFunctionBody(body, true) - } => - getOpeningParen(ta).map((_, func)) - case _ => None - } + ): Option[(Token.LeftParen, Term.FunctionTerm)] = tree match { + case ta @ Term.ArgClause((func: Term.FunctionTerm) :: Nil, _) if { + val body = func.body + (body.is[Term.Block] || func.tokens.last.ne(body.tokens.last)) && + isParentAnApply(ta) && okToRemoveAroundFunctionBody(body, true) + } => getOpeningParen(ta).map((_, func)) + case _ => None + } // multi-arg apply of single-stat lambdas // a(b => { c }, d => { e }) change to a(b => c, d => e) @@ -345,65 +327,57 @@ class RedundantBraces(implicit val ftoks: FormatTokens) // but the reverse conversion isn't always possible private def okToRemoveFunctionInApplyOrInit( t: Term.FunctionTerm - )(implicit style: ScalafmtConfig): Boolean = - t.parent match { - case Some(p: Term.ArgClause) => - p.parent match { - case Some(_: Init) => - okToRemoveAroundFunctionBody(t.body, false) - case Some(_: Term.Apply) => - getOpeningParen(p).isDefined && - okToRemoveAroundFunctionBody(t.body, p.values) - case _ => false - } - case _ => false - } + )(implicit style: ScalafmtConfig): Boolean = t.parent match { + case Some(p: Term.ArgClause) => p.parent match { + case Some(_: Init) => okToRemoveAroundFunctionBody(t.body, false) + case Some(_: Term.Apply) => getOpeningParen(p).isDefined && + okToRemoveAroundFunctionBody(t.body, p.values) + case _ => false + } + case _ => false + } private def processBlock(b: Term.Block)(implicit ft: FormatToken, session: Session, style: ScalafmtConfig ): Boolean = - (b.tokens.headOption.contains(ft.right) - && b.tokens.last.is[Token.RightBrace] - && okToRemoveBlock(b)) && (b.parent match { - case Some(p: Term.ArgClause) => p.parent.exists(checkValidInfixParent) - case Some(p) => checkValidInfixParent(p) - case _ => true - }) + (b.tokens.headOption.contains(ft.right) && + b.tokens.last.is[Token.RightBrace] && okToRemoveBlock(b)) && + (b.parent match { + case Some(p: Term.ArgClause) => p.parent.exists(checkValidInfixParent) + case Some(p) => checkValidInfixParent(p) + case _ => true + }) private def checkValidInfixParent( p: Tree - )(implicit ft: FormatToken, style: ScalafmtConfig): Boolean = - p match { - case _: Member.Infix => - /* for infix, we will preserve the block unless the closing brace - * follows a non-whitespace character on the same line as we don't - * break lines around infix expressions. - * we shouldn't join with the previous line (which might also end - * in a comment), and if we keep the break before the right brace - * we are removing, that will likely invalidate the expression. */ - def checkOpen = { - val nft = ftoks.next(ft) - nft.noBreak || - style.formatInfix(p) && !nft.right.is[Token.Comment] - } - def checkClose = { - val nft = ftoks(ftoks.matching(ft.right), -1) - nft.noBreak || - style.formatInfix(p) && !nft.left.is[Token.Comment] - } - checkOpen && checkClose - case _ => true - } + )(implicit ft: FormatToken, style: ScalafmtConfig): Boolean = p match { + case _: Member.Infix => + /* for infix, we will preserve the block unless the closing brace + * follows a non-whitespace character on the same line as we don't + * break lines around infix expressions. + * we shouldn't join with the previous line (which might also end + * in a comment), and if we keep the break before the right brace + * we are removing, that will likely invalidate the expression. */ + def checkOpen = { + val nft = ftoks.next(ft) + nft.noBreak || style.formatInfix(p) && !nft.right.is[Token.Comment] + } + def checkClose = { + val nft = ftoks(ftoks.matching(ft.right), -1) + nft.noBreak || style.formatInfix(p) && !nft.left.is[Token.Comment] + } + checkOpen && checkClose + case _ => true + } private def okToRemoveBlock( b: Term.Block )(implicit style: ScalafmtConfig, session: Session): Boolean = { b.parent.exists { - case p: Case => - settings.generalExpressions && { + case p: Case => settings.generalExpressions && { (p.body eq b) || shouldRemoveSingleStatBlock(b) } @@ -415,14 +389,13 @@ class RedundantBraces(implicit val ftoks: FormatTokens) else (t.pos.start != b.pos.start) && SingleArgInBraces.inBraces(t) case d: Defn.Def => - def disqualifiedByUnit = - !settings.includeUnitMethods && d.decltpe.exists { + def disqualifiedByUnit = !settings.includeUnitMethods && + d.decltpe.exists { case Type.Name("Unit") => true case _ => false } checkBlockAsBody(b, d.body, noParams(d.paramClauseGroup)) && - !isProcedureSyntax(d) && - !disqualifiedByUnit + !isProcedureSyntax(d) && !disqualifiedByUnit case d: Defn.Var => d.rhs.exists(checkBlockAsBody(b, _, noParams = true)) case d: Defn.Val => checkBlockAsBody(b, d.rhs, noParams = true) @@ -436,152 +409,142 @@ class RedundantBraces(implicit val ftoks: FormatTokens) case p: Term.FunctionTerm if isFunctionWithBraces(p) => okToRemoveAroundFunctionBody(b, true) - case _: Term.If => - settings.ifElseExpressions && shouldRemoveSingleStatBlock(b) + case _: Term.If => settings.ifElseExpressions && + shouldRemoveSingleStatBlock(b) case Term.Block(List(`b`)) => true case _: Term.QuotedMacroExpr | _: Term.SplicedMacroExpr => false - case _ => - settings.generalExpressions && shouldRemoveSingleStatBlock(b) + case _ => settings.generalExpressions && shouldRemoveSingleStatBlock(b) } } private def checkBlockAsBody(b: Term.Block, rhs: Tree, noParams: => Boolean)( implicit style: ScalafmtConfig - ): Boolean = - rhs.eq(b) && getSingleStatIfLineSpanOk(b).exists(innerOk(b)) && - isDefnBodiesEnabled(noParams) + ): Boolean = rhs.eq(b) && getSingleStatIfLineSpanOk(b).exists(innerOk(b)) && + isDefnBodiesEnabled(noParams) private def isDefnBodiesEnabled( noParams: => Boolean - )(implicit style: ScalafmtConfig): Boolean = - settings.defnBodies match { - case RedundantBracesSettings.DefnBodies.all => true - case RedundantBracesSettings.DefnBodies.none => false - case RedundantBracesSettings.DefnBodies.noParams => noParams - } + )(implicit style: ScalafmtConfig): Boolean = settings.defnBodies match { + case RedundantBracesSettings.DefnBodies.all => true + case RedundantBracesSettings.DefnBodies.none => false + case RedundantBracesSettings.DefnBodies.noParams => noParams + } private def noParams(group: Member.ParamClauseGroup): Boolean = group.tparamClause.values.isEmpty && group.paramClauses.isEmpty - private def noParams(group: Option[Member.ParamClauseGroup]): Boolean = - group.forall(noParams) - - private def innerOk(b: Term.Block)(s: Stat): Boolean = - s match { - case t: Term.NewAnonymous => - // can't allow: new A with B .foo - // can allow if: no ".foo", no "with B", or has braces - !b.parent.exists(_.is[Term.Select]) || - t.templ.inits.lengthCompare(1) <= 0 || - t.templ.stats.nonEmpty || t.tokens.last.is[Token.RightBrace] - case tree => tree.is[Term] && tree.isNot[Term.FunctionTerm] - } + private def noParams(group: Option[Member.ParamClauseGroup]): Boolean = group + .forall(noParams) + + private def innerOk(b: Term.Block)(s: Stat): Boolean = s match { + case t: Term.NewAnonymous => + // can't allow: new A with B .foo + // can allow if: no ".foo", no "with B", or has braces + !b.parent.exists(_.is[Term.Select]) || + t.templ.inits.lengthCompare(1) <= 0 || t.templ.stats.nonEmpty || + t.tokens.last.is[Token.RightBrace] + case tree => tree.is[Term] && tree.isNot[Term.FunctionTerm] + } - private def okToRemoveBlockWithinApply( - b: Term.Block - )(implicit style: ScalafmtConfig): Boolean = - getSingleStatIfLineSpanOk(b).exists { - case f: Term.FunctionTerm => - !needParensAroundParams(f) && { - val fb = f.body - !fb.is[Term.Block] || - // don't rewrite block if the inner block will be rewritten, too - // sometimes a function body block doesn't have braces - fb.tokens.headOption.exists(_.is[Token.LeftBrace]) && - !okToRemoveAroundFunctionBody(fb, true) - } - case _: Term.Assign => false // f({ a = b }) is not the same as f(a = b) - case _ => true - } + private def okToRemoveBlockWithinApply(b: Term.Block)(implicit + style: ScalafmtConfig + ): Boolean = getSingleStatIfLineSpanOk(b).exists { + case f: Term.FunctionTerm => !needParensAroundParams(f) && { + val fb = f.body + !fb.is[Term.Block] || + // don't rewrite block if the inner block will be rewritten, too + // sometimes a function body block doesn't have braces + fb.tokens.headOption.exists(_.is[Token.LeftBrace]) && + !okToRemoveAroundFunctionBody(fb, true) + } + case _: Term.Assign => false // f({ a = b }) is not the same as f(a = b) + case _ => true + } /** Some blocks look redundant but aren't */ - private def shouldRemoveSingleStatBlock( - b: Term.Block - )(implicit style: ScalafmtConfig, session: Session): Boolean = - getSingleStatIfLineSpanOk(b).exists { stat => - @tailrec - def checkParent(tree: Tree): Boolean = tree match { - case t: Term.ArgClause => - t.parent match { - case Some(p) => checkParent(p) - case _ => true - } - case _: Term.Try | _: Term.TryWithHandler => - // "try (x).y" or "try { x }.y" isn't supported until scala 2.13 - // inside exists, return true if rewrite is OK - !stat.tokens.headOption.exists { - case x: Token.LeftParen => - ftoks.matchingOpt(x) match { - case Some(y) if y ne stat.tokens.last => - session.rule[RedundantParens].exists { - _.onToken(ftoks(x, -1), session, style).exists(_.isRemove) - } - case _ => true - } - case x: Token.LeftBrace => - ftoks.matchingOpt(x) match { - case Some(y) if y ne stat.tokens.last => - findFirstTreeBetween(stat, x, y).exists { - case z: Term.Block => okToRemoveBlock(z) - case _ => false - } - case _ => true - } - case _ => true - } - - // can't do it for try until 2.13.3 - case _ if isPrefixExpr(stat) => false - - case parentIf: Term.If if stat.is[Term.If] => - // if (a) { if (b) c } else d - // ↑ cannot be replaced by ↓ - // if (a) if (b) c else d - // which would be equivalent to - // if (a) { if (b) c else d } - (parentIf.thenp eq b) && !ifWithoutElse(parentIf) && - existsIfWithoutElse(stat.asInstanceOf[Term.If]) - - case p: Term.ApplyInfix => - stat match { - case t: Term.ApplyInfix => - val useRight = isSingleElement(p.argClause.values, b) - SyntacticGroupOps.groupNeedsParenthesis( - TreeSyntacticGroup(p), - TreeSyntacticGroup(t), - if (useRight) Side.Right else Side.Left - ) - case _ => true // don't allow other non-infix - } + private def shouldRemoveSingleStatBlock(b: Term.Block)(implicit + style: ScalafmtConfig, + session: Session + ): Boolean = getSingleStatIfLineSpanOk(b).exists { stat => + @tailrec + def checkParent(tree: Tree): Boolean = tree match { + case t: Term.ArgClause => t.parent match { + case Some(p) => checkParent(p) + case _ => true + } + case _: Term.Try | _: Term.TryWithHandler => + // "try (x).y" or "try { x }.y" isn't supported until scala 2.13 + // inside exists, return true if rewrite is OK + !stat.tokens.headOption.exists { + case x: Token.LeftParen => ftoks.matchingOpt(x) match { + case Some(y) if y ne stat.tokens.last => + session.rule[RedundantParens].exists { + _.onToken(ftoks(x, -1), session, style).exists(_.isRemove) + } + case _ => true + } + case x: Token.LeftBrace => ftoks.matchingOpt(x) match { + case Some(y) if y ne stat.tokens.last => + findFirstTreeBetween(stat, x, y).exists { + case z: Term.Block => okToRemoveBlock(z) + case _ => false + } + case _ => true + } + case _ => true + } - case p: Term.Match => p.expr eq b - case p: Type.Match => p.tpe eq b + // can't do it for try until 2.13.3 + case _ if isPrefixExpr(stat) => false + + case parentIf: Term.If if stat.is[Term.If] => + // if (a) { if (b) c } else d + // ↑ cannot be replaced by ↓ + // if (a) if (b) c else d + // which would be equivalent to + // if (a) { if (b) c else d } + (parentIf.thenp eq b) && !ifWithoutElse(parentIf) && + existsIfWithoutElse(stat.asInstanceOf[Term.If]) + + case p: Term.ApplyInfix => stat match { + case t: Term.ApplyInfix => + val useRight = isSingleElement(p.argClause.values, b) + SyntacticGroupOps.groupNeedsParenthesis( + TreeSyntacticGroup(p), + TreeSyntacticGroup(t), + if (useRight) Side.Right else Side.Left + ) + case _ => true // don't allow other non-infix + } - case parent => - SyntacticGroupOps.groupNeedsParenthesis( - TreeSyntacticGroup(parent), - TreeSyntacticGroup(stat), - Side.Left - ) - } + case p: Term.Match => p.expr eq b + case p: Type.Match => p.tpe eq b - innerOk(b)(stat) && !b.parent.exists(checkParent) + case parent => SyntacticGroupOps.groupNeedsParenthesis( + TreeSyntacticGroup(parent), + TreeSyntacticGroup(stat), + Side.Left + ) } + innerOk(b)(stat) && !b.parent.exists(checkParent) + } + @inline private def okToRemoveAroundFunctionBody(b: Term, s: Seq[Tree])(implicit style: ScalafmtConfig - ): Boolean = - okToRemoveAroundFunctionBody(b, isSeqSingle(s)) + ): Boolean = okToRemoveAroundFunctionBody(b, isSeqSingle(s)) private def okToRemoveAroundFunctionBody( b: Term, okIfMultipleStats: => Boolean - )(implicit style: ScalafmtConfig): Boolean = - isDefnBodiesEnabled(noParams = false) && (getTreeSingleStat(b) match { + )(implicit style: ScalafmtConfig): Boolean = isDefnBodiesEnabled(noParams = + false + ) && + (getTreeSingleStat(b) match { case Some(_: Term.PartialFunction) => false case Some(_: Term.Block) => true case Some(s) => okLineSpan(s) @@ -607,15 +570,14 @@ class RedundantBraces(implicit val ftoks: FormatTokens) private def getSingleStatIfLineSpanOk(b: Term.Block)(implicit style: ScalafmtConfig - ): Option[Stat] = - getBlockSingleStat(b).filter(okLineSpan(_)) + ): Option[Stat] = getBlockSingleStat(b).filter(okLineSpan(_)) private def okLineSpan(tree: Tree)(implicit style: ScalafmtConfig): Boolean = getTreeLineSpan(tree) <= settings.maxBreaks // special case for Select which might contain a space instead of dot - private def isPrefixExpr(expr: Tree): Boolean = - RewriteCtx.isSimpleExprOr(expr) { case t: Term.Select => + private def isPrefixExpr(expr: Tree): Boolean = RewriteCtx + .isSimpleExprOr(expr) { case t: Term.Select => ftoks(t.name.tokens.head, -1).left.is[Token.Dot] } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RedundantParens.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RedundantParens.scala index 8a6593c10c..982ec8cff2 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RedundantParens.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RedundantParens.scala @@ -33,7 +33,8 @@ object RedundantParens extends Rewrite with FormatTokensRewrite.RuleFactory { object IsExprBody { def unapply(t: Tree): Option[Boolean] = { - @inline def okIf(body: Tree) = if (body eq t) Some(true) else None + @inline + def okIf(body: Tree) = if (body eq t) Some(true) else None t.parent.flatMap { case p: Case => okIf(p.body) case p: Term.If if p.cond ne t => @@ -41,8 +42,7 @@ object RedundantParens extends Rewrite with FormatTokensRewrite.RuleFactory { case p: Term.While => okIf(p.body) case p: Tree.WithBody => Some(t eq p.body) case _: Term.Return | _: Term.Throw | _: Term.QuotedMacroExpr | - _: Term.SplicedMacroExpr | _: Term.Block => - Some(true) + _: Term.SplicedMacroExpr | _: Term.Block => Some(true) case _ => None } } @@ -50,8 +50,7 @@ object RedundantParens extends Rewrite with FormatTokensRewrite.RuleFactory { object IsInBraces { def unapply(t: Tree): Option[Boolean] = t match { - case _: Term.Block | _: Term.PartialFunction => - t.parent.collect { + case _: Term.Block | _: Term.PartialFunction => t.parent.collect { case _: Term.ArgClause => true case _: Term.Block => false } @@ -74,14 +73,12 @@ class RedundantParens(implicit val ftoks: FormatTokens) ft: FormatToken, session: Session, style: ScalafmtConfig - ): Option[Replacement] = - ft.right match { - case _: Token.LeftParen => - findEnclosed.flatMap { case (cnt, tree) => - if (okToReplaceWithCount(cnt, tree)) Some(removeToken) else None - } - case _ => None - } + ): Option[Replacement] = ft.right match { + case _: Token.LeftParen => findEnclosed.flatMap { case (cnt, tree) => + if (okToReplaceWithCount(cnt, tree)) Some(removeToken) else None + } + case _ => None + } override def onRight(left: Replacement, hasFormatOff: Boolean)(implicit ft: FormatToken, @@ -90,87 +87,74 @@ class RedundantParens(implicit val ftoks: FormatTokens) ): Option[(Replacement, Replacement)] = if (left.isRemove && RewriteTrailingCommas.checkIfPrevious) Some((left, removeToken)) - else - None + else None private def okToReplaceWithCount(numParens: Int, tree: Tree)(implicit style: ScalafmtConfig - ): Boolean = - tree match { - case _: Lit.Unit | _: Member.Tuple => numParens >= 3 - case _ if numParens >= 2 => true - - case _: Term.AnonymousFunction | _: Term.Param => false - case _: Type.FunctionType => false - - case t: Member.ArgClause => okToReplaceArgClause(t) - case Term.ParamClause(t :: Nil, _) => - tree.parent.exists { - case _: Term.FunctionTerm => t.decltpe.isEmpty && t.mods.isEmpty - case _ => false - } - case _: Member.SyntaxValuesClause => false - - case IsInBraces(ok) => ok - case t @ IsExprBody(ok) => ok && canRewriteBody(t) - - case t => - t.parent.forall { - case _: Enumerator.Guard => RewriteCtx.isPostfixExpr(t) - case p: Case => p.cond.contains(t) && RewriteCtx.isPostfixExpr(t) - case p: Term.While => - p.expr.eq(t) && - style.dialect.allowSignificantIndentation && - ftoks.tokenBefore(p.body).left.is[Token.KwDo] - case p: Term.If => - p.cond.eq(t) && - style.dialect.allowSignificantIndentation && - ftoks.tokenBefore(p.thenp).left.is[Token.KwThen] - case p: Term.Try => - (style.dialect.allowTryWithAnyExpr || p.expr.ne(t)) && - canRewriteBody(t) - case p: Term.TryWithHandler => - (style.dialect.allowTryWithAnyExpr || p.expr.ne(t)) && - canRewriteBody(t) - case p: Term.ArgClause => - p.parent.exists { - case pia: Member.Infix => - !infixNeedsParens(pia, t) && okToReplaceInfix(pia, t) - case _ => true - } - case pia: Member.Infix if !infixNeedsParens(pia, t) => - okToReplaceInfix(pia, t) - case _ => - okToReplaceOther(t) - } - } + ): Boolean = tree match { + case _: Lit.Unit | _: Member.Tuple => numParens >= 3 + case _ if numParens >= 2 => true - private def okToReplaceOther(t: Tree)(implicit - style: ScalafmtConfig - ): Boolean = - t match { - case _: Lit | _: Name | _: Term.Interpolate => true - case _: Term.PartialFunction | _: Member.Apply => true - case t: Term.Select => - ftoks.tokenBefore(t.name).left.is[Token.Dot] - case t: Term.Match - if style.dialect.allowMatchAsOperator && - ftoks.tokenAfter(t.expr).right.is[Token.Dot] && - ftoks.tokenBefore(t.cases).left.is[Token.LeftBrace] => - true - case _ => false - } + case _: Term.AnonymousFunction | _: Term.Param => false + case _: Type.FunctionType => false - private def okToReplaceArgClause(t: Member.ArgClause)(implicit - style: ScalafmtConfig - ): Boolean = t.values match { - case arg :: Nil => - arg match { - case _: Term.Block | _: Term.PartialFunction => - t.parent.exists(!_.is[Init]) + case t: Member.ArgClause => okToReplaceArgClause(t) + case Term.ParamClause(t :: Nil, _) => tree.parent.exists { + case _: Term.FunctionTerm => t.decltpe.isEmpty && t.mods.isEmpty + case _ => false + } + case _: Member.SyntaxValuesClause => false + + case IsInBraces(ok) => ok + case t @ IsExprBody(ok) => ok && canRewriteBody(t) + + case t => t.parent.forall { + case _: Enumerator.Guard => RewriteCtx.isPostfixExpr(t) + case p: Case => p.cond.contains(t) && RewriteCtx.isPostfixExpr(t) + case p: Term.While => p.expr.eq(t) && + style.dialect.allowSignificantIndentation && ftoks.tokenBefore(p.body) + .left.is[Token.KwDo] + case p: Term.If => p.cond.eq(t) && + style.dialect.allowSignificantIndentation && + ftoks.tokenBefore(p.thenp).left.is[Token.KwThen] + case p: Term.Try => + (style.dialect.allowTryWithAnyExpr || p.expr.ne(t)) && + canRewriteBody(t) + case p: Term.TryWithHandler => + (style.dialect.allowTryWithAnyExpr || p.expr.ne(t)) && + canRewriteBody(t) + case p: Term.ArgClause => p.parent.exists { + case pia: Member.Infix => !infixNeedsParens(pia, t) && + okToReplaceInfix(pia, t) + case _ => true + } + case pia: Member.Infix if !infixNeedsParens(pia, t) => + okToReplaceInfix(pia, t) + case _ => okToReplaceOther(t) + } + } + + private def okToReplaceOther( + t: Tree + )(implicit style: ScalafmtConfig): Boolean = t match { + case _: Lit | _: Name | _: Term.Interpolate => true + case _: Term.PartialFunction | _: Member.Apply => true + case t: Term.Select => ftoks.tokenBefore(t.name).left.is[Token.Dot] + case t: Term.Match + if style.dialect.allowMatchAsOperator && + ftoks.tokenAfter(t.expr).right.is[Token.Dot] && + ftoks.tokenBefore(t.cases).left.is[Token.LeftBrace] => true + case _ => false + } + + private def okToReplaceArgClause( + t: Member.ArgClause + )(implicit style: ScalafmtConfig): Boolean = t.values match { + case arg :: Nil => arg match { + case _: Term.Block | _: Term.PartialFunction => t.parent + .exists(!_.is[Init]) case _: Lit.Unit | _: Member.Tuple => false - case _ => - t.parent.exists { + case _ => t.parent.exists { case pia: Member.Infix => val keep = infixNeedsParens(pia, arg) if (keep) okToReplaceOther(arg) else okToReplaceInfix(pia, arg) @@ -183,19 +167,16 @@ class RedundantParens(implicit val ftoks: FormatTokens) private def okToReplaceInfix(pia: Member.Infix, tia: Member.Infix)(implicit style: ScalafmtConfig ): Boolean = { - !breaksBeforeOp(tia) && - style.rewrite.redundantParens.infixSide.exists { + !breaksBeforeOp(tia) && style.rewrite.redundantParens.infixSide.exists { case RedundantParensSettings.InfixSide.many if tia.op.value != pia.op.value => val tiaPrecedence = tia.precedence tiaPrecedence <= precedenceHigh || - tiaPrecedence < precedenceLowest && - pia.precedence >= precedenceLowest + tiaPrecedence < precedenceLowest && pia.precedence >= precedenceLowest case RedundantParensSettings.InfixSide.some => val tiaPrecedence = tia.precedence tiaPrecedence <= precedenceVeryHigh || - tiaPrecedence <= precedenceMedium && - pia.precedence >= precedenceLowest + tiaPrecedence <= precedenceMedium && pia.precedence >= precedenceLowest case _ => true } } @@ -220,11 +201,10 @@ class RedundantParens(implicit val ftoks: FormatTokens) ia.nestedInfixApps.exists(breaksBeforeOpAndNotEnclosed) } - private def canRewriteBody(tree: Tree): Boolean = - tree match { - case ia: Member.Infix => !breaksBeforeOp(ia) - case _ => true - } + private def canRewriteBody(tree: Tree): Boolean = tree match { + case ia: Member.Infix => !breaksBeforeOp(ia) + case _ => true + } private def findEnclosed(implicit ft: FormatToken): Option[Enclosed] = { // counts consecutive parent pairs starting with the given one as the innermost @@ -235,10 +215,8 @@ class RedundantParens(implicit val ftoks: FormatTokens) case ( prev @ FormatToken(_: Token.LeftParen, _, _), next @ FormatToken(_, _: Token.RightParen, _) - ) => - iter(ftoks.prev(prev), ftoks.next(next), cnt + 1) - case _ => - TreeOps + ) => iter(ftoks.prev(prev), ftoks.next(next), cnt + 1) + case _ => TreeOps .findEnclosedBetweenParens(lt.right, rt.left, ft.meta.rightOwner) .map((cnt, _)) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RemoveEmptyDocstrings.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RemoveEmptyDocstrings.scala index 3a5c80cbd1..ec981f0385 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RemoveEmptyDocstrings.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RemoveEmptyDocstrings.scala @@ -9,8 +9,7 @@ import org.scalafmt.internal.FormatTokens import org.scalafmt.internal.FormatWriter object RemoveEmptyDocstrings - extends FormatTokensRewrite.Rule - with FormatTokensRewrite.RuleFactory { + extends FormatTokensRewrite.Rule with FormatTokensRewrite.RuleFactory { import FormatTokensRewrite._ diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RemoveScala3OptionalBraces.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RemoveScala3OptionalBraces.scala index 56c09f846d..f3e4b2cd16 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RemoveScala3OptionalBraces.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RemoveScala3OptionalBraces.scala @@ -47,32 +47,27 @@ private class RemoveScala3OptionalBraces(implicit val ftoks: FormatTokens) case t: Term.Block if t.stats.nonEmpty => onLeftForBlock(t) case t: Template if t.stats.nonEmpty || t.self.tokens.nonEmpty => if (t.parent.exists(_.is[Defn.Given])) removeToken - else - replaceToken(":")(new Token.Colon(x.input, x.dialect, x.start)) + else replaceToken(":")(new Token.Colon(x.input, x.dialect, x.start)) case t: Term.ArgClause => onLeftForArgClause(t) - case t: Term.PartialFunction => - t.parent match { + case t: Term.PartialFunction => t.parent match { case Some(p: Term.ArgClause) if (p.tokens.head match { case px: Token.LeftBrace => px eq x case px: Token.LeftParen => shouldRewriteArgClauseWithLeftParen[RedundantBraces](px) case _ => false - }) => - onLeftForArgClause(p) + }) => onLeftForArgClause(p) case _ => null } case _: Term.For if allowOldSyntax || { val rbFt = ftoks(ftoks.matching(ft.right)) ftoks.nextNonComment(rbFt).right.is[Token.KwDo] - } => - removeToken + } => removeToken case _: Term.ForYield => removeToken case _: Term.Match => removeToken case _: Type.Match => removeToken case _: Term.Try => removeToken case _: Ctor.Secondary - if ftoks.prevNonComment(ft).left.is[Token.Equals] => - removeToken + if ftoks.prevNonComment(ft).left.is[Token.Equals] => removeToken case _ => null } case _ => null @@ -87,8 +82,7 @@ private class RemoveScala3OptionalBraces(implicit val ftoks: FormatTokens) val nextFt = ftoks.nextNonComment(ftoks.next(ft)) val notOkToRewrite = hasFormatOff || // can't force significant indentation (nextFt.meta.rightOwner match { - case t: Term.Name => - t.parent.exists { + case t: Term.Name => t.parent.exists { case p: Term.Select => p.name eq t // select without `.` case p: Term.ApplyInfix if p.op eq t => !style.dialect.allowInfixOperatorAfterNL || @@ -96,7 +90,8 @@ private class RemoveScala3OptionalBraces(implicit val ftoks: FormatTokens) case _ => false } case _ => false - }) || (left.ft.right match { + }) || + (left.ft.right match { case _: Token.Colon => !shouldRewriteColonOnRight(left) case _ => false }) @@ -119,62 +114,57 @@ private class RemoveScala3OptionalBraces(implicit val ftoks: FormatTokens) ft: FormatToken, session: Session, style: ScalafmtConfig - ): Replacement = - tree.parent.fold(null: Replacement) { - case t: Term.If => - val ok = ftoks.prevNonComment(ft).left match { - case _: Token.KwIf => true - case _: Token.KwThen => true - case _: Token.KwElse => - !isTreeMultiStatBlock(t.elsep) || - ftoks.tokenAfter(t.cond).right.is[Token.KwThen] - case _: Token.RightParen => allowOldSyntax - case _ => false - } - if (ok) removeToken else null - case _: Term.While => - val ok = ftoks.prevNonComment(ft).left match { - case _: Token.KwDo => true - case _: Token.RightParen => allowOldSyntax - case _ => false - } - if (ok) removeToken else null - case _: Term.For => - val ok = ftoks.prevNonComment(ft).left match { - case _: Token.KwDo => true - case _: Token.RightParen | _: Token.RightBrace => allowOldSyntax - case _ => false - } - if (ok) removeToken else null - case _: Term.ForYield => removeToken - case _: Term.Try => removeToken - case _: Term.Throw => removeToken - case _: Term.Return => removeToken - case _: Defn.ExtensionGroup => removeToken - case _: Term.FunctionTerm => removeToken - case t: Defn.Def => - if (tree ne t.body) null - else if (ftoks.prevNonComment(ft).left.is[Token.Equals]) removeToken - else null - case p: Tree.WithBody => if (p.body eq tree) removeToken else null - case p: Term.ArgClause => - p.tokens.head match { - case _: Token.LeftBrace => - onLeftForArgClause(p) - case px: Token.LeftParen - if shouldRewriteArgClauseWithLeftParen[RedundantParens](px) => - onLeftForArgClause(p) - case _ => null - } - case _ => null - } + ): Replacement = tree.parent.fold(null: Replacement) { + case t: Term.If => + val ok = ftoks.prevNonComment(ft).left match { + case _: Token.KwIf => true + case _: Token.KwThen => true + case _: Token.KwElse => !isTreeMultiStatBlock(t.elsep) || + ftoks.tokenAfter(t.cond).right.is[Token.KwThen] + case _: Token.RightParen => allowOldSyntax + case _ => false + } + if (ok) removeToken else null + case _: Term.While => + val ok = ftoks.prevNonComment(ft).left match { + case _: Token.KwDo => true + case _: Token.RightParen => allowOldSyntax + case _ => false + } + if (ok) removeToken else null + case _: Term.For => + val ok = ftoks.prevNonComment(ft).left match { + case _: Token.KwDo => true + case _: Token.RightParen | _: Token.RightBrace => allowOldSyntax + case _ => false + } + if (ok) removeToken else null + case _: Term.ForYield => removeToken + case _: Term.Try => removeToken + case _: Term.Throw => removeToken + case _: Term.Return => removeToken + case _: Defn.ExtensionGroup => removeToken + case _: Term.FunctionTerm => removeToken + case t: Defn.Def => + if (tree ne t.body) null + else if (ftoks.prevNonComment(ft).left.is[Token.Equals]) removeToken + else null + case p: Tree.WithBody => if (p.body eq tree) removeToken else null + case p: Term.ArgClause => p.tokens.head match { + case _: Token.LeftBrace => onLeftForArgClause(p) + case px: Token.LeftParen + if shouldRewriteArgClauseWithLeftParen[RedundantParens](px) => + onLeftForArgClause(p) + case _ => null + } + case _ => null + } private def shouldRewriteArgClauseWithLeftParen[A <: Rule]( lp: Token )(implicit ft: FormatToken, session: Session, tag: ClassTag[A]) = { val prevFt = ftoks.prevNonComment(ft) - prevFt.left.eq(lp) && session - .claimedRule(prevFt.meta.idx - 1) + prevFt.left.eq(lp) && session.claimedRule(prevFt.meta.idx - 1) .exists(x => tag.runtimeClass.isInstance(x.rule)) } @@ -205,8 +195,7 @@ private class RemoveScala3OptionalBraces(implicit val ftoks: FormatTokens) val lft = left.ft lft.meta.rightOwner match { case t: Term.ArgClause => shouldRewriteArgClauseColonOnRight(t, lft) - case t @ (_: Term.Block | _: Term.PartialFunction) => - t.parent match { + case t @ (_: Term.Block | _: Term.PartialFunction) => t.parent match { case Some(p: Term.ArgClause) => shouldRewriteArgClauseColonOnRight(p, lft) case _ => false @@ -232,8 +221,7 @@ private class RemoveScala3OptionalBraces(implicit val ftoks: FormatTokens) (begIdx until endIdx).foreach { idx => val tokOpt = session.claimedRule(idx) match { case Some(x) if x.ft.meta.idx == idx => - if (x.how == ReplacementType.Remove) None - else Some(x.ft.right) + if (x.how == ReplacementType.Remove) None else Some(x.ft.right) case _ => val tok = ftoks(idx).right if (tok.is[Token.Whitespace]) None else Some(tok) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Rewrite.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Rewrite.scala index 11e9fdda72..f709148fb9 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Rewrite.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/Rewrite.scala @@ -12,11 +12,7 @@ import org.scalafmt.config.RewriteSettings import org.scalafmt.config.ScalafmtConfig import org.scalafmt.util.{TokenOps, TokenTraverser, TreeOps} -case class RewriteCtx( - style: ScalafmtConfig, - input: Input, - tree: Tree -) { +case class RewriteCtx(style: ScalafmtConfig, input: Input, tree: Tree) { implicit val dialect: Dialect = style.dialect private val patchBuilder = mutable.Map.empty[(Int, Int), TokenPatch] @@ -25,25 +21,26 @@ case class RewriteCtx( val tokenTraverser = new TokenTraverser(tokens, input) val matchingParens = TreeOps.getMatchingParentheses(tokens) - @inline def getMatching(a: Token): Token = - matchingParens(TokenOps.hash(a)) + @inline + def getMatching(a: Token): Token = matchingParens(TokenOps.hash(a)) - @inline def getMatchingOpt(a: Token): Option[Token] = - matchingParens.get(TokenOps.hash(a)) + @inline + def getMatchingOpt(a: Token): Option[Token] = matchingParens + .get(TokenOps.hash(a)) - @inline def isMatching(a: Token, b: => Token) = - getMatchingOpt(a).exists(_ eq b) + @inline + def isMatching(a: Token, b: => Token) = getMatchingOpt(a).exists(_ eq b) - @inline def getIndex(token: Token) = tokenTraverser.getIndex(token) + @inline + def getIndex(token: Token) = tokenTraverser.getIndex(token) - def applyPatches: String = - tokens.iterator - .map(x => patchBuilder.get(x.start -> x.end).fold(x.syntax)(_.newTok)) - .mkString + def applyPatches: String = tokens.iterator + .map(x => patchBuilder.get(x.start -> x.end).fold(x.syntax)(_.newTok)) + .mkString def addPatchSet(patches: TokenPatch*): Unit = - if (!patches.exists(x => tokenTraverser.isExcluded(x.tok))) - patches.foreach { patch => + if (!patches.exists(x => tokenTraverser.isExcluded(x.tok))) patches + .foreach { patch => val key = (patch.tok.start, patch.tok.end) val value = patchBuilder.get(key) match { case Some(prev) => Patch.merge(prev, patch) @@ -52,23 +49,19 @@ case class RewriteCtx( patchBuilder.update(key, value) } - def onlyWhitespaceBefore(index: Int): Boolean = - tokenTraverser - .findAtOrBefore(index - 1) { - case _: T.LF | _: T.BOF => Some(true) - case _: T.Whitespace => None - case _ => Some(false) - } - .isDefined + def onlyWhitespaceBefore(index: Int): Boolean = tokenTraverser + .findAtOrBefore(index - 1) { + case _: T.LF | _: T.BOF => Some(true) + case _: T.Whitespace => None + case _ => Some(false) + }.isDefined def findNonWhitespaceWith( f: (Token => Option[Boolean]) => Option[Token] ): Option[(Token, Option[T.LF])] = { var lf: Option[T.LF] = None val nonWs = f { - case t: T.LF => - if (lf.nonEmpty) Some(false) - else { lf = Some(t); None } + case t: T.LF => if (lf.nonEmpty) Some(false) else { lf = Some(t); None } case _: T.Whitespace => None case _ => Some(true) } @@ -76,23 +69,17 @@ case class RewriteCtx( } // end is inclusive - def removeLFToAvoidEmptyLine( - beg: Int, - end: Int - )(implicit builder: Rewrite.PatchBuilder): Unit = - if (onlyWhitespaceBefore(beg)) - tokenTraverser - .findAtOrAfter(end + 1) { - case _: T.LF => Some(true) - case _: T.Whitespace => None - case _ => Some(false) - } - .map(TokenPatch.Remove) - .foreach(builder += _) + def removeLFToAvoidEmptyLine(beg: Int, end: Int)(implicit + builder: Rewrite.PatchBuilder + ): Unit = if (onlyWhitespaceBefore(beg)) tokenTraverser.findAtOrAfter(end + 1) { + case _: T.LF => Some(true) + case _: T.Whitespace => None + case _ => Some(false) + }.map(TokenPatch.Remove).foreach(builder += _) // special case for Select which might contain a space instead of dot - def isPrefixExpr(expr: Tree): Boolean = - RewriteCtx.isSimpleExprOr(expr) { case t: Term.Select => + def isPrefixExpr(expr: Tree): Boolean = RewriteCtx + .isSimpleExprOr(expr) { case t: Term.Select => val maybeDot = tokenTraverser.findBefore(t.name.tokens.head) { case _: T.Trivia => None case x => Some(x.is[T.Dot]) @@ -139,8 +126,8 @@ object Rewrite { implicit val reader: ConfCodecEx[Rewrite] = ReaderUtil.oneOf(rewrites: _*) - val name2rewrite: Map[String, Rewrite] = - rewrites.view.map(x => x.source -> x.value).toMap + val name2rewrite: Map[String, Rewrite] = rewrites.view + .map(x => x.source -> x.value).toMap val rewrite2name: Map[Rewrite, String] = name2rewrite.map(_.swap) val available = name2rewrite.keys.mkString(", ") @@ -152,9 +139,8 @@ object Rewrite { toInput: String => Input ): Input = { val rewrites = style.rewrite.rewriteFactoryRules - if (rewrites.isEmpty) { - input - } else { + if (rewrites.isEmpty) { input } + else { style.runner.parse(input) match { case Parsed.Success(ast) => val ctx = RewriteCtx(style, input, ast) @@ -179,13 +165,12 @@ object RewriteCtx { // https://www.scala-lang.org/files/archive/spec/2.13/06-expressions.html#prefix-infix-and-postfix-operations def isSimpleExprOr( expr: Tree - )(orElse: PartialFunction[Tree, Boolean]): Boolean = - expr match { - case _: Lit | _: Name | _: Term.Interpolate => true - case _: Term.New | _: Term.NewAnonymous => true - case _: Term.Apply | _: Term.ApplyUnary => true - case _ => orElse.applyOrElse(expr, (_: Tree) => false) - } + )(orElse: PartialFunction[Tree, Boolean]): Boolean = expr match { + case _: Lit | _: Name | _: Term.Interpolate => true + case _: Term.New | _: Term.NewAnonymous => true + case _: Term.Apply | _: Term.ApplyUnary => true + case _ => orElse.applyOrElse(expr, (_: Tree) => false) + } @inline def isPostfixExpr(expr: Tree)(implicit style: ScalafmtConfig): Boolean = diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RewriteTrailingCommas.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RewriteTrailingCommas.scala index e415946b13..d8c9b6c77e 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RewriteTrailingCommas.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/RewriteTrailingCommas.scala @@ -23,14 +23,13 @@ object RewriteTrailingCommas extends FormatTokensRewrite.RuleFactory { ft: FormatToken, session: Session, ftoks: FormatTokens - ): Boolean = - ft.right match { - case _: Token.RightParen => - val maybeCommaFt = ftoks.prevNonComment(ft) - !maybeCommaFt.left.is[Token.Comma] || - session.isRemovedOnLeft(maybeCommaFt, true) - case _ => true - } + ): Boolean = ft.right match { + case _: Token.RightParen => + val maybeCommaFt = ftoks.prevNonComment(ft) + !maybeCommaFt.left.is[Token.Comma] || + session.isRemovedOnLeft(maybeCommaFt, true) + case _ => true + } } @@ -51,9 +50,7 @@ private class RewriteTrailingCommas(implicit val ftoks: FormatTokens) ft: FormatToken, session: Session, style: ScalafmtConfig - ): Option[Replacement] = { - if (shouldRemove(ft)) Some(removeToken) else None - } + ): Option[Replacement] = { if (shouldRemove(ft)) Some(removeToken) else None } private[rewrite] def shouldRemove( ft: FormatToken @@ -63,19 +60,18 @@ private class RewriteTrailingCommas(implicit val ftoks: FormatTokens) val nft = ftoks.nextNonCommentAfter(ft) // comma and paren/bracket/brace need to have the same owner - (rightOwner eq nft.meta.rightOwner) && (nft.right match { - case rp: Token.RightParen => - rightOwner.isAny[Member.SyntaxValuesClause, Member.Tuple] || + (rightOwner eq nft.meta.rightOwner) && + (nft.right match { + case rp: Token.RightParen => rightOwner + .isAny[Member.SyntaxValuesClause, Member.Tuple] || ftoks.matchingOpt(rp).exists { lp => val claimant = session.claimedRule(ftoks.justBefore(lp)) claimant.forall(_.rule.isInstanceOf[RedundantParens]) } - case _: Token.RightBracket => - rightOwner.is[Member.SyntaxValuesClause] + case _: Token.RightBracket => rightOwner.is[Member.SyntaxValuesClause] - case _: Token.RightBrace => - rightOwner.is[Importer] + case _: Token.RightBrace => rightOwner.is[Importer] case _ => false }) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/SortModifiers.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/SortModifiers.scala index 6a13600b93..5e35a11b59 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/SortModifiers.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/SortModifiers.scala @@ -19,32 +19,30 @@ class SortModifiers(implicit ctx: RewriteCtx) extends RewriteSession { private val order: Seq[SortSettings.ModKey] = ctx.style.rewrite.sortModifiers.order - override def rewrite(tree: Tree): Unit = - tree match { + override def rewrite(tree: Tree): Unit = tree match { - /* - * in the case of Class, Object, and of class constructor parameters - * some Mods are immovable, e.g. 'case' in "case class X". - * - * The case of parameters is a bit more curious because there the - * "val" or "var" in, say: - * {{{ - * class Test(private final val x: Int) - * }}} - * are considered Mods, instead of being similar to `Defn.Val`, or `Defn.Var`. - */ - case c: Defn.Class => sortMods(c.mods.filterNot(_.is[Mod.Case])) - case o: Defn.Object => sortMods(o.mods.filterNot(_.is[Mod.Case])) - case s: Stat.WithMods => sortMods(s.mods) - case p: Term.Param => - val start = p.pos.start - sortMods(p.mods.filterNot { m => - m.is[Mod.ValParam] || m.is[Mod.VarParam] || - m.is[Mod.Using] || m.is[Mod.Erased] || - TreeOps.noExplicitImplicit(start, false)(m) - }) - case _ => - } + /* + * in the case of Class, Object, and of class constructor parameters + * some Mods are immovable, e.g. 'case' in "case class X". + * + * The case of parameters is a bit more curious because there the + * "val" or "var" in, say: + * {{{ + * class Test(private final val x: Int) + * }}} + * are considered Mods, instead of being similar to `Defn.Val`, or `Defn.Var`. + */ + case c: Defn.Class => sortMods(c.mods.filterNot(_.is[Mod.Case])) + case o: Defn.Object => sortMods(o.mods.filterNot(_.is[Mod.Case])) + case s: Stat.WithMods => sortMods(s.mods) + case p: Term.Param => + val start = p.pos.start + sortMods(p.mods.filterNot { m => + m.is[Mod.ValParam] || m.is[Mod.VarParam] || m.is[Mod.Using] || + m.is[Mod.Erased] || TreeOps.noExplicitImplicit(start, false)(m) + }) + case _ => + } private def sortMods(oldMods: Seq[Mod]): Unit = { if (oldMods.nonEmpty) { @@ -55,8 +53,8 @@ class SortModifiers(implicit ctx: RewriteCtx) extends RewriteSession { // format new keywords. However, the choice of putting unconfigured // modifiers to the front of the list instead of back of the list is // mostly arbitrary. - val sortedMods: Seq[Mod] = - sanitized.sortBy(mod => order.indexWhere(_.matches(mod))) + val sortedMods: Seq[Mod] = sanitized + .sortBy(mod => order.indexWhere(_.matches(mod))) ctx.addPatchSet(sortedMods.zip(sanitized).flatMap { case (next, old) => if (next eq old) Seq.empty diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/LiteralOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/LiteralOps.scala index 7c10e7c83b..ea1d98bfe0 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/LiteralOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/LiteralOps.scala @@ -18,15 +18,11 @@ object LiteralOps { * - literals.hexDigits applies to body and * - literals.long applies to suffix */ - def prettyPrintInteger( - str: String - )(implicit style: ScalafmtConfig): String = + def prettyPrintInteger(str: String)(implicit style: ScalafmtConfig): String = if (str.endsWith("L") || str.endsWith("l")) { prettyPrintHex(str.dropRight(1)) + style.literals.long.process(str.takeRight(1)) - } else { - prettyPrintHex(str) - } + } else { prettyPrintHex(str) } def prettyPrintFloat(str: String)(implicit style: ScalafmtConfig): String = prettyPrintFloatingPoint(str, 'F', 'f', style.literals.float) @@ -55,9 +51,7 @@ object LiteralOps { if (str.last == suffixUpper || str.last == suffixLower) { style.literals.scientific.process(str.dropRight(1)) + suffixCase.process(str.takeRight(1)) - } else { - style.literals.scientific.process(str) - } + } else { style.literals.scientific.process(str) } private def prettyPrintHex( str: String diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/LoggerOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/LoggerOps.scala index 8208fab288..07f7e6d558 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/LoggerOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/LoggerOps.scala @@ -18,34 +18,31 @@ object LoggerOps { val logger = org.scalameta.logger // TODO(olafur) parameterize - def name2style[T](styles: Text[T]*): Map[String, T] = - styles.map(x => x.source -> x.value).toMap + def name2style[T](styles: Text[T]*): Map[String, T] = styles + .map(x => x.source -> x.value).toMap def log(s: State): String = { val policies = s.policy.policies.map(_.toString).mkString("P[", ",", "]") - s"d=${s.depth} w=${s.cost} i=${s.indentation} col=${s.column}; $policies; s=${log(s.split)}" + s"d=${s.depth} w=${s.cost} i=${s.indentation} col=${s + .column}; $policies; s=${log(s.split)}" } def log(split: Split): String = s"$split" - def log(formatToken: FormatToken): String = - s"""${log(formatToken.left)} - |${log(formatToken.between: _*)} - |${log(formatToken.right)}""".stripMargin + def log(formatToken: FormatToken): String = s"""${log(formatToken.left)} + |${log(formatToken.between: _*)} + |${log(formatToken.right)}""".stripMargin def log2(formatToken: FormatToken): String = formatToken.toString - def escape(raw: String): String = { - raw - } + def escape(raw: String): String = { raw } def log(tokens: Token*): String = tokens.map(log).mkString("\n") - def cleanup(token: Token): String = - token match { - case Token.Literal() | Interpolation.Part(_) => - escape(token.syntax).stripPrefix("\"").stripSuffix("\"") - case _ => token.syntax.replace("\n", "") - } + def cleanup(token: Token): String = token match { + case Token.Literal() | Interpolation.Part(_) => escape(token.syntax) + .stripPrefix("\"").stripSuffix("\"") + case _ => token.syntax.replace("\n", "") + } def log(tokens: Tokens): String = tokens.map(log).mkString("\n") @@ -53,27 +50,24 @@ object LoggerOps { def log(t: Tree): String = log(t, false) def log(t: Tree, tokensOnly: Boolean): String = { - val tokens = - s"TOKENS: ${t.tokens.map(x => reveal(x.syntax)).mkString(",")}" + val tokens = s"TOKENS: ${t.tokens.map(x => reveal(x.syntax)).mkString(",")}" if (tokensOnly) tokens - else - s"""TYPE: ${t.getClass.getName.stripPrefix("scala.meta.")} - |SOURCE: $t - |STRUCTURE: ${t.show[Structure]} - |$tokens - |""".stripMargin + else s"""TYPE: ${t.getClass.getName.stripPrefix("scala.meta.")} + |SOURCE: $t + |STRUCTURE: ${t.show[Structure]} + |$tokens + |""".stripMargin } def log(t: Option[Tree]): String = log(t, false) - def log(t: Option[Tree], tokensOnly: Boolean): String = - t.fold("")(log(_, tokensOnly)) - - def reveal(s: String): String = - s.map { - case '\n' => '¶' - case ' ' => '∙' - case ch => ch - } + def log(t: Option[Tree], tokensOnly: Boolean): String = t + .fold("")(log(_, tokensOnly)) + + def reveal(s: String): String = s.map { + case '\n' => '¶' + case ' ' => '∙' + case ch => ch + } def header[T](t: T): String = { val line = s"=" * (t.toString.length + 3) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/PolicyOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/PolicyOps.scala index 1d915477b3..031b400647 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/PolicyOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/PolicyOps.scala @@ -137,10 +137,9 @@ object PolicyOps { exclude: TokenRanges, endLt: T => Policy.End.WithPos, endRt: T => Policy.End.WithPos - )( - expire: Policy.End.WithPos, - policyFunc: Policy.End.WithPos => Policy - )(implicit fileLine: FileLine): Policy = { + )(expire: Policy.End.WithPos, policyFunc: Policy.End.WithPos => Policy)( + implicit fileLine: FileLine + ): Policy = { val lastPolicy = policyFunc(expire) exclude.ranges.foldLeft(lastPolicy) { case (policy, range) => new Policy.Relay( @@ -164,73 +163,59 @@ object PolicyOps { if (replaced) Some(splits) else None } } - { case OnBreakDecision(d) => - d - } + { case OnBreakDecision(d) => d } } - def delayedBreakPolicy( - end: Policy.End.WithPos - )(onBreakPolicy: Policy)(implicit fileLine: FileLine): Policy = - Policy.Proxy(onBreakPolicy, end)(delayedBreakPolicyFactory) + def delayedBreakPolicy(end: Policy.End.WithPos)(onBreakPolicy: Policy)( + implicit fileLine: FileLine + ): Policy = Policy.Proxy(onBreakPolicy, end)(delayedBreakPolicyFactory) - def delayedBreakPolicyBefore( - token: T - )(onBreakPolicy: Policy)(implicit fileLine: FileLine): Policy = - delayedBreakPolicy(Policy.End.Before(token))(onBreakPolicy) + def delayedBreakPolicyBefore(token: T)(onBreakPolicy: Policy)(implicit + fileLine: FileLine + ): Policy = delayedBreakPolicy(Policy.End.Before(token))(onBreakPolicy) - def delayedBreakPolicyFor( - token: T - )(f: T => Policy)(implicit fileLine: FileLine): Policy = - delayedBreakPolicyBefore(token)(f(token)) + def delayedBreakPolicyFor(token: T)(f: T => Policy)(implicit + fileLine: FileLine + ): Policy = delayedBreakPolicyBefore(token)(f(token)) def decideNewlinesOnlyBeforeClose(close: T)(implicit fileLine: FileLine - ): Policy = - decideNewlinesOnlyBeforeClose(Split(Newline, 0))(close) + ): Policy = decideNewlinesOnlyBeforeClose(Split(Newline, 0))(close) def decideNewlinesOnlyBeforeCloseOnBreak(close: T)(implicit fileLine: FileLine - ): Policy = - delayedBreakPolicyFor(close)(decideNewlinesOnlyBeforeClose) + ): Policy = delayedBreakPolicyFor(close)(decideNewlinesOnlyBeforeClose) - def decideNewlinesOnlyBeforeClose( - split: Split - )(close: T)(implicit fileLine: FileLine): Policy = - new DecideNewlinesOnlyBeforeToken(close, Option(split)) + def decideNewlinesOnlyBeforeClose(split: Split)(close: T)(implicit + fileLine: FileLine + ): Policy = new DecideNewlinesOnlyBeforeToken(close, Option(split)) def decideNewlinesOnlyAfterClose(close: T)(implicit fileLine: FileLine - ): Policy = - decideNewlinesOnlyAfterClose(Split(Newline, 0))(close) + ): Policy = decideNewlinesOnlyAfterClose(Split(Newline, 0))(close) - def decideNewlinesOnlyAfterClose( - split: Split - )(close: T)(implicit fileLine: FileLine): Policy = - new DecideNewlinesOnlyAfterToken(close, Option(split)) + def decideNewlinesOnlyAfterClose(split: Split)(close: T)(implicit + fileLine: FileLine + ): Policy = new DecideNewlinesOnlyAfterToken(close, Option(split)) - def decideNewlinesOnlyAfterToken( - token: T - )(implicit fileLine: FileLine): Policy = - new DecideNewlinesOnlyAfterToken(token, None) + def decideNewlinesOnlyAfterToken(token: T)(implicit + fileLine: FileLine + ): Policy = new DecideNewlinesOnlyAfterToken(token, None) - def unindentAtExclude( - exclude: TokenRanges, - indent: Length - ): Policy = { + def unindentAtExclude(exclude: TokenRanges, indent: Length): Policy = { exclude.ranges.foldLeft(Policy.noPolicy) { case (policy, range) => val (lt, rt) = (range.lt, range.rt) val trigger = rt val unindent = Indent(indent, rt, ExpiresOn.After) val triggeredIndent = Indent.before(unindent, trigger) - val triggerUnindent = Policy.on(rt) { - case Decision(FormatToken(`lt`, _, _), s) => + val triggerUnindent = Policy + .on(rt) { case Decision(FormatToken(`lt`, _, _), s) => s.map(_.withIndent(triggeredIndent)) - } + } val cancelUnindent = delayedBreakPolicy(Policy.End.On(lt)) { Policy.after(lt, rank = 1) { // use rank to apply after policy above - case Decision(FormatToken(`lt`, _, _), s) => - s.map(_.switch(trigger, false)) + case Decision(FormatToken(`lt`, _, _), s) => s + .map(_.switch(trigger, false)) } } Policy.Relay(policy, triggerUnindent & cancelUnindent) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/StyleMap.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/StyleMap.scala index 2da884c34f..bc655f80be 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/StyleMap.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/StyleMap.scala @@ -16,18 +16,12 @@ import org.scalafmt.internal.FormatTokens import org.scalameta.FileLine import org.scalameta.logger -class StyleMap( - tokens: FormatTokens, - val init: ScalafmtConfig -) { +class StyleMap(tokens: FormatTokens, val init: ScalafmtConfig) { import StyleMap._ val literalR: FilterMatcher = init.binPack.literalsRegex private val prefix = "\\s*scalafmt: ".r.pattern val forcedBinPack: mutable.Set[Tree] = mutable.Set.empty - private val ( - starts: Array[Int], - styles: Array[ScalafmtConfig] - ) = { + private val (starts: Array[Int], styles: Array[ScalafmtConfig]) = { var curr = init val startBuilder = Array.newBuilder[Int] val styleBuilder = Array.newBuilder[ScalafmtConfig] @@ -49,8 +43,8 @@ class StyleMap( } tok.left match { case Comment(c) if prefix.matcher(c).find() => - val configured = - ScalafmtConfig.fromHoconString(c, init, Some("scalafmt")) + val configured = ScalafmtConfig + .fromHoconString(c, init, Some("scalafmt")) // TODO(olafur) report error via callback configured.foreach(logger.elem(_)) { style => init.rewrite.rulesChanged(style.rewrite).foreach { x => @@ -68,8 +62,7 @@ class StyleMap( val unsafe = x.binPack.unsafeCallSite tokens.matchingOpt(open).foreach(disableBinPack.update(_, unsafe)) } - case close @ RightParen() => - disableBinPack.remove(close).foreach { x => + case close @ RightParen() => disableBinPack.remove(close).foreach { x => changeStyle(setBinPack(curr, callSite = x)) } case _ => @@ -81,49 +74,46 @@ class StyleMap( @tailrec private def isBasicLiteral( tree: Tree - )(implicit style: ScalafmtConfig): Boolean = - tree match { - case lit: Lit => - val strName = tree match { - case t: Lit.Int - if 0 <= t.value && t.value < Byte.MaxValue && - lit.tokens.head.toString.startsWith("0x") => - "Byte" - case _: Lit.Null => "Null" - case _ => lit.value.getClass.getName - } - literalR.matches(strName) - case x: Name => literalR.matches(x.productPrefix) - case _ if !style.binPack.literalsIncludeSimpleExpr => false - case t: Term.Select => isBasicLiteral(t.qual) - case t: Term.Assign => isBasicLiteral(t.rhs) - case _ => - tree.children match { - case Nil => true - case one :: Nil => isBasicLiteral(one) - case _ => false - } - } + )(implicit style: ScalafmtConfig): Boolean = tree match { + case lit: Lit => + val strName = tree match { + case t: Lit.Int + if 0 <= t.value && t.value < Byte.MaxValue && + lit.tokens.head.toString.startsWith("0x") => "Byte" + case _: Lit.Null => "Null" + case _ => lit.value.getClass.getName + } + literalR.matches(strName) + case x: Name => literalR.matches(x.productPrefix) + case _ if !style.binPack.literalsIncludeSimpleExpr => false + case t: Term.Select => isBasicLiteral(t.qual) + case t: Term.Assign => isBasicLiteral(t.rhs) + case _ => tree.children match { + case Nil => true + case one :: Nil => isBasicLiteral(one) + case _ => false + } + } @tailrec private def isLiteral(tree: Tree)(implicit style: ScalafmtConfig): Boolean = isBasicLiteral(tree) || - style.binPack.literalsIncludeSimpleExpr && (tree match { + style.binPack.literalsIncludeSimpleExpr && + (tree match { case t: Term.Assign => isLiteral(t.rhs) - case t: Term.Apply => - isBasicLiteral(t.fun) && (t.argClause match { + case t: Term.Apply => isBasicLiteral(t.fun) && + (t.argClause match { case Term.ArgClause(Nil, None) => true case Term.ArgClause(arg :: Nil, None) => isLiteral(arg) case _ => false }) - case Term.New(t) => - isBasicLiteral(t.name) && (t.argClauses match { + case Term.New(t) => isBasicLiteral(t.name) && + (t.argClauses match { case Nil | Term.ArgClause(Nil, None) :: Nil => true case Term.ArgClause(arg :: Nil, None) :: Nil => isLiteral(arg) case _ => false }) - case _ => - tree.children match { + case _ => tree.children match { case Nil => true case one :: Nil => isLiteral(one) case _ => false @@ -132,19 +122,17 @@ class StyleMap( def opensLiteralArgumentList( ft: FormatToken - )(implicit style: ScalafmtConfig): Boolean = - (ft.meta.leftOwner match { - case Member.Tuple(v) => Some(v) - case Member.SyntaxValuesClause(v) => Some(v) - case _ => None - }).exists { args => - args.lengthCompare(style.binPack.literalsMinArgCount) >= 0 && - args.forall(isLiteral) - } + )(implicit style: ScalafmtConfig): Boolean = (ft.meta.leftOwner match { + case Member.Tuple(v) => Some(v) + case Member.SyntaxValuesClause(v) => Some(v) + case _ => None + }).exists { args => + args.lengthCompare(style.binPack.literalsMinArgCount) >= 0 && + args.forall(isLiteral) + } @inline - def at(token: FormatToken): ScalafmtConfig = - at(token.left) + def at(token: FormatToken): ScalafmtConfig = at(token.left) @inline def forall(f: ScalafmtConfig => Boolean): Boolean = styles.forall(f) @@ -161,10 +149,7 @@ class StyleMap( object StyleMap { - def setBinPack( - curr: ScalafmtConfig, - callSite: BinPack.Unsafe - ): ScalafmtConfig = + def setBinPack(curr: ScalafmtConfig, callSite: BinPack.Unsafe): ScalafmtConfig = if (curr.binPack.unsafeCallSite == callSite) curr else curr.copy(binPack = curr.binPack.copy(unsafeCallSite = callSite)) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenClasses.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenClasses.scala index b76069bfc3..ee8b44ff0b 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenClasses.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenClasses.scala @@ -13,13 +13,11 @@ object Reserved { } object LeftParenOrBracket { - def unapply(tok: Token): Boolean = - tok.is[LeftParen] || tok.is[LeftBracket] + def unapply(tok: Token): Boolean = tok.is[LeftParen] || tok.is[LeftBracket] } object RightParenOrBracket { - def unapply(tok: Token): Boolean = - tok.is[RightParen] || tok.is[RightBracket] + def unapply(tok: Token): Boolean = tok.is[RightParen] || tok.is[RightBracket] } object LeftParenOrBrace { diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenOps.scala index 156eac319e..000cf654c0 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenOps.scala @@ -36,31 +36,27 @@ object TokenOps { */ @inline def hash(token: Token): TokenHash = { - val longHash: Long = - (token.productPrefix.hashCode.toLong << (62 - 8)) | - (token.start.toLong << (62 - (8 + 28))) | token.end + val longHash: Long = (token.productPrefix.hashCode.toLong << (62 - 8)) | + (token.start.toLong << (62 - (8 + 28))) | token.end longHash } - def isDocstring(text: String): Boolean = - text.length > 4 && text.startsWith("/**") // excludes /**/ - - def blankLineBeforeDocstring( - ft: FormatToken - )(implicit style: ScalafmtConfig): Boolean = - style.forceNewlineBeforeDocstring && - isDocstring(ft.meta.right.text) && - TreeOps - .findTreeOrParent(ft.meta.leftOwner) { - case t if t.pos.end <= ft.right.start => None - case _: Pkg | _: Source | _: Template | _: Term.Block => Some(false) - case _ => Some(true) - } - .isEmpty + def isDocstring(text: String): Boolean = text.length > 4 && + text.startsWith("/**") // excludes /**/ + + def blankLineBeforeDocstring(ft: FormatToken)(implicit + style: ScalafmtConfig + ): Boolean = style.forceNewlineBeforeDocstring && + isDocstring(ft.meta.right.text) && + TreeOps.findTreeOrParent(ft.meta.leftOwner) { + case t if t.pos.end <= ft.right.start => None + case _: Pkg | _: Source | _: Template | _: Term.Block => Some(false) + case _ => Some(true) + }.isEmpty // 2.13 implements SeqOps.findLast - def findLast[A](seq: Seq[A])(cond: A => Boolean): Option[A] = - seq.reverseIterator.find(cond) + def findLast[A](seq: Seq[A])(cond: A => Boolean): Option[A] = seq + .reverseIterator.find(cond) def findLastVisibleTokenOpt(tokens: Tokens): Option[Token] = findLast(tokens) { @@ -72,15 +68,15 @@ object TokenOps { findLastVisibleTokenOpt(tokens).getOrElse(tokens.last) @inline - def withNoIndent(ft: FormatToken): Boolean = - ft.between.lastOption.exists(_.is[LF]) + def withNoIndent(ft: FormatToken): Boolean = ft.between.lastOption + .exists(_.is[LF]) - def rhsIsCommentedOut(ft: FormatToken): Boolean = - ft.right.is[Comment] && withNoIndent(ft) && isSingleLineIfComment(ft.right) + def rhsIsCommentedOut(ft: FormatToken): Boolean = ft.right.is[Comment] && + withNoIndent(ft) && isSingleLineIfComment(ft.right) @inline - def isLeftCommentThenBreak(ft: FormatToken): Boolean = - ft.left.is[Token.Comment] && ft.hasBreak + def isLeftCommentThenBreak(ft: FormatToken): Boolean = ft.left + .is[Token.Comment] && ft.hasBreak def isSingleLineIfComment(c: Token): Boolean = { val off = c.start @@ -92,8 +88,8 @@ object TokenOps { val booleanOperators = Set("&&", "||") - def isBoolOperator(token: Token): Boolean = - booleanOperators.contains(token.syntax) + def isBoolOperator(token: Token): Boolean = booleanOperators + .contains(token.syntax) def identModification(ident: Ident): Modification = { val lastCharacter = ident.syntax.last @@ -125,17 +121,15 @@ object TokenOps { case _ => false } - def endsWithSymbolIdent(tok: Token): Boolean = - tok match { - case Ident(name) => !name.last.isLetterOrDigit - case _ => false - } + def endsWithSymbolIdent(tok: Token): Boolean = tok match { + case Ident(name) => !name.last.isLetterOrDigit + case _ => false + } - def isSymbolicIdent(tok: Token): Boolean = - tok match { - case Ident(name) => isSymbolicName(name) - case _ => false - } + def isSymbolicIdent(tok: Token): Boolean = tok match { + case Ident(name) => isSymbolicName(name) + case _ => false + } def isSymbolicName(name: String): Boolean = { val head = name.head diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenTraverser.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenTraverser.scala index 51321e6834..e7f1c49a11 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenTraverser.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TokenTraverser.scala @@ -12,9 +12,8 @@ class TokenTraverser(tokens: Tokens, input: Input) { var formatOff = false var i = 0 tokens.foreach { tok => - if (!formatOff) { - if (TokenOps.isFormatOff(tok)) formatOff = true - } else { + if (!formatOff) { if (TokenOps.isFormatOff(tok)) formatOff = true } + else { if (TokenOps.isFormatOn(tok)) formatOff = false else excluded += TokenOps.hash(tok) } @@ -36,11 +35,13 @@ class TokenTraverser(tokens: Tokens, input: Input) { (map.result(), excluded.result()) } - final def isExcluded(token: Token): Boolean = - excludedTokens.contains(TokenOps.hash(token)) + final def isExcluded(token: Token): Boolean = excludedTokens + .contains(TokenOps.hash(token)) - @inline def getIndex(token: Token): Int = tok2idx(token) - @inline def getIndexOpt(token: Token): Option[Int] = tok2idx.get(token) + @inline + def getIndex(token: Token): Int = tok2idx(token) + @inline + def getIndexOpt(token: Token): Option[Int] = tok2idx.get(token) def nextToken(token: Token): Token = { tok2idx.get(token) match { @@ -69,8 +70,8 @@ class TokenTraverser(tokens: Tokens, input: Input) { */ def findAfter( token: Token - )(predicate: Token => Option[Boolean]): Option[Token] = - tok2idx.get(token).flatMap(x => findAtOrAfter(x + 1)(predicate)) + )(predicate: Token => Option[Boolean]): Option[Token] = tok2idx.get(token) + .flatMap(x => findAtOrAfter(x + 1)(predicate)) /** Find a token before the given one. The search stops when the predicate * returns Some value (or the end is reached). @@ -79,13 +80,13 @@ class TokenTraverser(tokens: Tokens, input: Input) { */ def findBefore( token: Token - )(predicate: Token => Option[Boolean]): Option[Token] = - tok2idx.get(token).flatMap(x => findAtOrBefore(x - 1)(predicate)) + )(predicate: Token => Option[Boolean]): Option[Token] = tok2idx.get(token) + .flatMap(x => findAtOrBefore(x - 1)(predicate)) @tailrec - final def findAtOrAfter(off: Int)( - pred: Token => Option[Boolean] - ): Option[Token] = + final def findAtOrAfter( + off: Int + )(pred: Token => Option[Boolean]): Option[Token] = if (off >= tokens.length) None else { val token = tokens(off) @@ -97,9 +98,9 @@ class TokenTraverser(tokens: Tokens, input: Input) { } @tailrec - final def findAtOrBefore(off: Int)( - pred: Token => Option[Boolean] - ): Option[Token] = + final def findAtOrBefore( + off: Int + )(pred: Token => Option[Boolean]): Option[Token] = if (off < 0) None else { val token = tokens(off) @@ -116,8 +117,7 @@ class TokenTraverser(tokens: Tokens, input: Input) { if (start == end || nextToken(start) == start) Nil else { val tail = filter(nextToken(start), end)(predicate) - if (predicate(start)) start +: tail - else tail + if (predicate(start)) start +: tail else tail } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeExtractors.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeExtractors.scala index 44c9ca3b6e..13ef892e00 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeExtractors.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeExtractors.scala @@ -21,8 +21,8 @@ object InfixApp { case arg => arg :: Nil } - def nestedInfixApps: Seq[Member.Infix] = - (tree.lhs :: singleArg.toList).collect { case x: Member.Infix => x } + def nestedInfixApps: Seq[Member.Infix] = (tree.lhs :: singleArg.toList) + .collect { case x: Member.Infix => x } } @@ -35,8 +35,8 @@ object InfixApp { private val infixOpPrecedence: Map[Char, Int] = { val builder = Map.newBuilder[Char, Int] def add(precedence: Int, ops: Char*): Unit = addSeq(precedence, ops) - def addSeq(precedence: Int, ops: Iterable[Char]): Unit = - ops.foreach(builder += _ -> precedence) + def addSeq(precedence: Int, ops: Iterable[Char]): Unit = ops + .foreach(builder += _ -> precedence) // start with 1; all other special characters will get 0 by omission add(1, '*', '/', '%') add(2, '+', '-') @@ -56,16 +56,16 @@ object InfixApp { // https://scala-lang.org/files/archive/spec/2.11/06-expressions.html#infix-operations // The precedence of an assignment ... is lower than the precedence of any other ... - def isAssignment(op: String): Boolean = - op.lastOption.contains('=') && (op.length == 1 || - op.head != '=' && !nonAssignmentOperators.contains(op)) + def isAssignment(op: String): Boolean = op.lastOption.contains('=') && + (op.length == 1 || op.head != '=' && !nonAssignmentOperators.contains(op)) // https://scala-lang.org/files/archive/spec/2.11/06-expressions.html#infix-operations // Operators ending in a colon `:' are right-associative. All other operators are left-associative. - @inline def isLeftAssoc(op: String): Boolean = op.last != ':' + @inline + def isLeftAssoc(op: String): Boolean = op.last != ':' - @inline def getPrecedence(op: String): Int = - infixOpPrecedence.getOrElse(op.head, 0) + @inline + def getPrecedence(op: String): Int = infixOpPrecedence.getOrElse(op.head, 0) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeOps.scala index 2d431dd761..583c8c0b45 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/TreeOps.scala @@ -22,11 +22,10 @@ object TreeOps { import TokenOps._ @tailrec - def topTypeWith(typeWith: Type.With): Type.With = - typeWith.parent match { - case Some(t: Type.With) => topTypeWith(t) - case _ => typeWith - } + def topTypeWith(typeWith: Type.With): Type.With = typeWith.parent match { + case Some(t: Type.With) => topTypeWith(t) + case _ => typeWith + } @tailrec def withChain(top: Tree, res: Seq[Type.With] = Seq.empty): Seq[Type.With] = @@ -41,9 +40,7 @@ object TreeOps { case (x, 0) => x case (enum: Enumerator.Guard, i) => // Only guard that follows another guards starts a statement. - if (enums(i - 1).is[Enumerator.Guard]) { - ret += enum - } + if (enums(i - 1).is[Enumerator.Guard]) { ret += enum } case (x, _) => ret += x } ret.result() @@ -62,21 +59,22 @@ object TreeOps { case arg :: Nil => getBraces(tree).map { case (b, e) => (b, arg, e) } case _ => None } - @inline def inBraces(tree: Tree)(implicit - ftoks: FormatTokens - ): Boolean = + @inline + def inBraces(tree: Tree)(implicit ftoks: FormatTokens): Boolean = getBraces(tree).isDefined - @inline def getBraces(tree: Tree)(implicit + @inline + def getBraces(tree: Tree)(implicit ftoks: FormatTokens - ): Option[(FormatToken, FormatToken)] = - ftoks.getDelimsIfEnclosed(tree).filter(_._1.left.is[LeftBrace]) + ): Option[(FormatToken, FormatToken)] = ftoks.getDelimsIfEnclosed(tree) + .filter(_._1.left.is[LeftBrace]) def orBlock(tree: Tree)(implicit ftoks: FormatTokens ): Option[(FormatToken, Stat, FormatToken)] = tree match { case t: Term.ArgClause => unapply(t) - case Term.Block(arg :: Nil) => - getBraces(tree).map { case (b, e) => (b, arg, e) } + case Term.Block(arg :: Nil) => getBraces(tree).map { case (b, e) => + (b, arg, e) + } case _ => None } @@ -88,51 +86,46 @@ object TreeOps { } @tailrec - def isBlockFunction(fun: Term.FunctionTerm)(implicit - ftoks: FormatTokens - ): Boolean = - fun.parent match { - case Some(p: Term.FunctionTerm) => isBlockFunction(p) - case Some(p) => isExprWithParentInBraces(fun)(p) - case None => false - } + def isBlockFunction( + fun: Term.FunctionTerm + )(implicit ftoks: FormatTokens): Boolean = fun.parent match { + case Some(p: Term.FunctionTerm) => isBlockFunction(p) + case Some(p) => isExprWithParentInBraces(fun)(p) + case None => false + } def isFunctionWithBraces(fun: Term.FunctionTerm)(implicit ftoks: FormatTokens - ): Boolean = - fun.parent.exists(isExprWithParentInBraces(fun)) + ): Boolean = fun.parent.exists(isExprWithParentInBraces(fun)) def isExprWithParentInBraces(expr: Tree)(parent: Tree)(implicit ftoks: FormatTokens - ): Boolean = - SingleArgInBraces.orBlock(parent).exists(_._2 eq expr) + ): Boolean = SingleArgInBraces.orBlock(parent).exists(_._2 eq expr) - def extractStatementsIfAny(tree: Tree)(implicit - ftoks: FormatTokens - ): Seq[Tree] = - tree match { - case b: Term.Block => b.stats - case SingleArgInBraces(_, fun: Term.FunctionTerm, _) => fun :: Nil - case b: Term.FunctionTerm if isBlockFunction(b) => b.body :: Nil - case t: Pkg => t.stats - // TODO(olafur) would be nice to have an abstract "For" superclass. - case t: Term.For => getEnumStatements(t.enums) - case t: Term.ForYield => getEnumStatements(t.enums) - case t: Term.Match => t.cases - case t: Type.Match => t.cases - case t: Term.PartialFunction => t.cases - case t: Term.Try => t.catchp - case t: Type.Refine => t.stats - case t: Source => t.stats - case t: Template => t.stats - case t: CaseTree if t.body.tokens.nonEmpty => t.body :: Nil - case _ => Nil - } + def extractStatementsIfAny( + tree: Tree + )(implicit ftoks: FormatTokens): Seq[Tree] = tree match { + case b: Term.Block => b.stats + case SingleArgInBraces(_, fun: Term.FunctionTerm, _) => fun :: Nil + case b: Term.FunctionTerm if isBlockFunction(b) => b.body :: Nil + case t: Pkg => t.stats + // TODO(olafur) would be nice to have an abstract "For" superclass. + case t: Term.For => getEnumStatements(t.enums) + case t: Term.ForYield => getEnumStatements(t.enums) + case t: Term.Match => t.cases + case t: Type.Match => t.cases + case t: Term.PartialFunction => t.cases + case t: Term.Try => t.catchp + case t: Type.Refine => t.stats + case t: Source => t.stats + case t: Template => t.stats + case t: CaseTree if t.body.tokens.nonEmpty => t.body :: Nil + case _ => Nil + } - def getStatementStarts( - tree: Tree, - soft: SoftKeywordClasses - )(implicit ftoks: FormatTokens): Map[TokenHash, Tree] = { + def getStatementStarts(tree: Tree, soft: SoftKeywordClasses)(implicit + ftoks: FormatTokens + ): Map[TokenHash, Tree] = { val ret = Map.newBuilder[TokenHash, Tree] ret.sizeHint(tree.tokens.length) @@ -216,10 +209,9 @@ object TreeOps { ac.values match { case (f: Term.FunctionTerm) :: Nil if ac.tokens.lastOption.exists { x => // see if closing paren is now brace - x.is[Token.RightParen] && - ftoks.prevNonComment(ftoks(x)).left.is[Token.RightBrace] - } => - addOne(f) + x.is[Token.RightParen] && ftoks.prevNonComment(ftoks(x)) + .left.is[Token.RightBrace] + } => addOne(f) case _ => } case t => // Nothing @@ -239,11 +231,10 @@ object TreeOps { val ret = Map.newBuilder[TokenHash, Token] var stack = List.empty[Token] tokens.foreach { - case open @ (LeftBrace() | LeftBracket() | LeftParen() | - Interpolation.Start() | Xml.Start() | Xml.SpliceStart()) => - stack = open :: stack - case close @ (RightBrace() | RightBracket() | RightParen() | - Interpolation.End() | Xml.End() | Xml.SpliceEnd()) => + case open @ (LeftBrace() | LeftBracket() | LeftParen() | Interpolation + .Start() | Xml.Start() | Xml.SpliceStart()) => stack = open :: stack + case close @ (RightBrace() | RightBracket() | RightParen() | Interpolation + .End() | Xml.End() | Xml.SpliceEnd()) => val open = stack.head assertValidParens(open, close) ret += hash(open) -> close @@ -251,10 +242,9 @@ object TreeOps { stack = stack.tail case _ => } - if (stack.nonEmpty) - throw new IllegalArgumentException( - stack.map(x => s"[${x.end}]$x").mkString("Orphan parens (", ", ", ")") - ) + if (stack.nonEmpty) throw new IllegalArgumentException( + stack.map(x => s"[${x.end}]$x").mkString("Orphan parens (", ", ", ")") + ) val result = ret.result() result } @@ -286,49 +276,44 @@ object TreeOps { */ def findTreeOrParent( tree: Tree - )(pred: Tree => Option[Boolean]): Option[Tree] = - findTreeEx(tree) { t => - pred(t) match { - case None => t.parent - case Some(true) => Some(null) - case Some(false) => None - } + )(pred: Tree => Option[Boolean]): Option[Tree] = findTreeEx(tree) { t => + pred(t) match { + case None => t.parent + case Some(true) => Some(null) + case Some(false) => None } + } /** Returns first tree which matches the given predicate. The predicate * returns None to indicate failure; or the tree to recurse to; if the tree * is null (or the same as current tree), the current tree is returned. */ @tailrec - def findTreeEx( - tree: Tree - )(pred: Tree => Option[Tree]): Option[Tree] = + def findTreeEx(tree: Tree)(pred: Tree => Option[Tree]): Option[Tree] = pred(tree) match { case None => None case Some(null | `tree`) => Some(tree) case Some(r) => findTreeEx(r)(pred) } - def findTreeOrParentSimple( - tree: Tree, - flag: Boolean = true - )(pred: Tree => Boolean): Option[Tree] = + def findTreeOrParentSimple(tree: Tree, flag: Boolean = true)( + pred: Tree => Boolean + ): Option[Tree] = findTreeOrParent(tree)(x => if (pred(x) == flag) Some(true) else None) /** Returns first ancestor whose parent matches the given predicate. The * predicate returns None to continue with the parent, or the boolean match * flag, which terminates the search. */ - def findTreeWithParent( - tree: Tree - )(pred: Tree => Option[Boolean]): Option[Tree] = - findTreeWithParentEx(tree) { t => - pred(t) match { - case None => Some(t) - case Some(true) => Some(null) - case Some(false) => None - } + def findTreeWithParent(tree: Tree)( + pred: Tree => Option[Boolean] + ): Option[Tree] = findTreeWithParentEx(tree) { t => + pred(t) match { + case None => Some(t) + case Some(true) => Some(null) + case Some(false) => None } + } /** Returns first ancestor whose parent matches the given predicate. The * predicate returns None to indicate failure; or the tree to recurse to; if @@ -337,51 +322,44 @@ object TreeOps { @tailrec def findTreeWithParentEx( tree: Tree - )(pred: Tree => Option[Tree]): Option[Tree] = - tree.parent match { - case None => None - case Some(p) => - pred(p) match { - case None => None - case Some(null) => Some(tree) - case Some(r) => findTreeWithParentEx(r)(pred) - } - } + )(pred: Tree => Option[Tree]): Option[Tree] = tree.parent match { + case None => None + case Some(p) => pred(p) match { + case None => None + case Some(null) => Some(tree) + case Some(r) => findTreeWithParentEx(r)(pred) + } + } - def findTreeWithParentSimple( - tree: Tree, - flag: Boolean = true - )(pred: Tree => Boolean): Option[Tree] = + def findTreeWithParentSimple(tree: Tree, flag: Boolean = true)( + pred: Tree => Boolean + ): Option[Tree] = findTreeWithParent(tree)(x => if (pred(x) == flag) Some(true) else None) /** Returns first ancestor with a parent of a given type. */ def findTreeWithParentOfType[A <: Tree](tree: Tree)(implicit classifier: Classifier[Tree, A] - ): Option[Tree] = - findTreeWithParentSimple(tree)(classifier.apply) + ): Option[Tree] = findTreeWithParentSimple(tree)(classifier.apply) /** Returns true if a matching ancestor of a given type exists. */ @inline - def existsParentOfType[A <: Tree]( - tree: Tree - )(implicit classifier: Classifier[Tree, A]): Boolean = - findTreeWithParentOfType[A](tree).isDefined + def existsParentOfType[A <: Tree](tree: Tree)(implicit + classifier: Classifier[Tree, A] + ): Boolean = findTreeWithParentOfType[A](tree).isDefined @tailrec - def defDefBody(tree: Tree): Option[Tree] = - tree match { - case d: Defn with Tree.WithBody => Some(d.body) - case d: Defn with Stat.WithTemplate => Some(d.templ) - case t: Ctor.Secondary => Some(t.init) - case _: Ctor.Primary | _: Pat.Var | _: Term.Name => - tree.parent match { - case Some(p) => defDefBody(p) - case _ => None - } - case _ => None - } + def defDefBody(tree: Tree): Option[Tree] = tree match { + case d: Defn with Tree.WithBody => Some(d.body) + case d: Defn with Stat.WithTemplate => Some(d.templ) + case t: Ctor.Secondary => Some(t.init) + case _: Ctor.Primary | _: Pat.Var | _: Term.Name => tree.parent match { + case Some(p) => defDefBody(p) + case _ => None + } + case _ => None + } @tailrec def defDefBodyParent(tree: Tree): Option[Tree] = tree.parent match { case Some(p: Member.ParamClauseGroup) => defDefBodyParent(p) @@ -390,65 +368,61 @@ object TreeOps { } @tailrec - private def defDefReturnTypeImpl(tree: Tree): Option[Type] = - tree match { - case d: Decl.Def => Some(d.decltpe) - case d: Defn.Def => d.decltpe - case d: Defn.Macro => d.decltpe - case d: Defn.Given => d.templ.inits.headOption.map(_.tpe) - case d: Defn.GivenAlias => Some(d.decltpe) - case d: Decl.Given => Some(d.decltpe) - case d: Defn.Val => d.decltpe - case d: Defn.Var => d.decltpe - case _: Pat.Var | _: Term.Name | _: Member.ParamClause | - _: Member.ParamClauseGroup => - tree.parent match { - case Some(p) => defDefReturnTypeImpl(p) - case _ => None - } - case _ => None - } - def defDefReturnType(tree: Tree): Option[Type] = - defDefReturnTypeImpl(tree).filter(!_.pos.isEmpty) + private def defDefReturnTypeImpl(tree: Tree): Option[Type] = tree match { + case d: Decl.Def => Some(d.decltpe) + case d: Defn.Def => d.decltpe + case d: Defn.Macro => d.decltpe + case d: Defn.Given => d.templ.inits.headOption.map(_.tpe) + case d: Defn.GivenAlias => Some(d.decltpe) + case d: Decl.Given => Some(d.decltpe) + case d: Defn.Val => d.decltpe + case d: Defn.Var => d.decltpe + case _: Pat.Var | _: Term.Name | _: Member.ParamClause | + _: Member.ParamClauseGroup => tree.parent match { + case Some(p) => defDefReturnTypeImpl(p) + case _ => None + } + case _ => None + } + def defDefReturnType(tree: Tree): Option[Type] = defDefReturnTypeImpl(tree) + .filter(!_.pos.isEmpty) val DefDefReturnTypeLeft = new FormatToken.ExtractFromMeta(x => defDefReturnType(x.leftOwner)) val DefDefReturnTypeRight = new FormatToken.ExtractFromMeta(x => defDefReturnType(x.rightOwner)) - def isParamClauseSite(tree: Tree): Boolean = - tree match { - case _: Type.ParamClause => !tree.parent.exists(_.is[Type.Lambda]) - case _: Term.ParamClause => - tree.parent match { - case Some(p: Term.FunctionTerm) => !isSeqSingle(p.paramClause.values) - case _ => true - } - case _: Type.FuncParamClause | _: Type.Tuple => true - case _: Member.Function => true // enclosed - case _ => false - } + def isParamClauseSite(tree: Tree): Boolean = tree match { + case _: Type.ParamClause => !tree.parent.exists(_.is[Type.Lambda]) + case _: Term.ParamClause => tree.parent match { + case Some(p: Term.FunctionTerm) => !isSeqSingle(p.paramClause.values) + case _ => true + } + case _: Type.FuncParamClause | _: Type.Tuple => true + case _: Member.Function => true // enclosed + case _ => false + } @inline def isTokenHeadOrBefore(token: Token, owner: Tree): Boolean = isTokenHeadOrBefore(token, owner.pos) @inline - def isTokenHeadOrBefore(token: Token, pos: Position): Boolean = - pos.start >= token.start + def isTokenHeadOrBefore(token: Token, pos: Position): Boolean = pos.start >= + token.start @inline def isTokenLastOrAfter(token: Token, owner: Tree): Boolean = isTokenLastOrAfter(token, owner.pos) @inline - def isTokenLastOrAfter(token: Token, pos: Position): Boolean = - pos.end <= token.end + def isTokenLastOrAfter(token: Token, pos: Position): Boolean = pos.end <= + token.end def isArgClauseSite(tree: Tree)(implicit style: ScalafmtConfig): Boolean = tree match { - case t: Member.ArgClause => - !t.parent.exists(_.is[Member.Infix]) || (t.values match { + case t: Member.ArgClause => !t.parent.exists(_.is[Member.Infix]) || + (t.values match { case (_: Term.Assign | _: Lit.Unit) :: Nil => true case Nil | _ :: Nil => false case _ => style.newlines.formatInfix @@ -457,39 +431,32 @@ object TreeOps { case _ => false } - def isTuple(tree: Tree): Boolean = - tree.is[Member.Tuple] + def isTuple(tree: Tree): Boolean = tree.is[Member.Tuple] - def noSpaceBeforeOpeningParen( - tree: Tree - ): Boolean = - tree match { - case _: Term.Super => true - case t: Member.ArgClause => !t.parent.exists(_.is[Member.Infix]) - case _: Member.ParamClause => - tree.parent.exists { - case _: Term.FunctionTerm => false - case t: Ctor.Primary => - t.mods.isEmpty || !t.paramClauses.headOption.contains(tree) - case _ => true - } - case _ => false - } + def noSpaceBeforeOpeningParen(tree: Tree): Boolean = tree match { + case _: Term.Super => true + case t: Member.ArgClause => !t.parent.exists(_.is[Member.Infix]) + case _: Member.ParamClause => tree.parent.exists { + case _: Term.FunctionTerm => false + case t: Ctor.Primary => t.mods.isEmpty || + !t.paramClauses.headOption.contains(tree) + case _ => true + } + case _ => false + } - def isModPrivateProtected(tree: Tree): Boolean = - tree match { - case _: Mod.Private | _: Mod.Protected => true - case _ => false - } + def isModPrivateProtected(tree: Tree): Boolean = tree match { + case _: Mod.Private | _: Mod.Protected => true + case _ => false + } - val DefValAssignLeft = - new FormatToken.ExtractFromMeta(_.leftOwner match { - case _: Enumerator => None // it's WithBody - case t: Ctor.Secondary => Some(t.init) - case t: Tree.WithBody => Some(t.body) - case t: Term.Param => t.default - case _ => None - }) + val DefValAssignLeft = new FormatToken.ExtractFromMeta(_.leftOwner match { + case _: Enumerator => None // it's WithBody + case t: Ctor.Secondary => Some(t.init) + case t: Tree.WithBody => Some(t.body) + case t: Term.Param => t.default + case _ => None + }) /** How many parents of tree are Term.Apply? */ @@ -500,8 +467,7 @@ object TreeOps { case Some(p) => nestedApplies(p) case _ => 0 } - case _ => - numParents(tree) { + case _ => numParents(tree) { case _: Term.Apply | _: Term.ApplyInfix | _: Type.Apply => true case _ => false } @@ -522,8 +488,9 @@ object TreeOps { if (children.isEmpty) 0 else 1 + maxTreeDepth(children) } - def maxTreeDepth(trees: Seq[Tree]): Int = - trees.foldLeft(0) { case (res, t) => math.max(res, treeDepth(t)) } + def maxTreeDepth(trees: Seq[Tree]): Int = trees.foldLeft(0) { case (res, t) => + math.max(res, treeDepth(t)) + } @tailrec final def lastLambda(first: Term.FunctionTerm): Term.FunctionTerm = @@ -532,19 +499,16 @@ object TreeOps { case _ => first } - @inline final def isInfixOp(tree: Tree): Boolean = - AsInfixOp.unapply(tree).isDefined + @inline + final def isInfixOp(tree: Tree): Boolean = AsInfixOp.unapply(tree).isDefined object AsInfixOp { - def unapply(tree: Tree): Option[Member.Infix] = - tree.parent.collect { - case ia: Member.Infix if ia.op eq tree => ia - } + def unapply(tree: Tree): Option[Member.Infix] = tree.parent + .collect { case ia: Member.Infix if ia.op eq tree => ia } } @inline - final def asInfixApp(tree: Tree): Option[Member.Infix] = - InfixApp.unapply(tree) + final def asInfixApp(tree: Tree): Option[Member.Infix] = InfixApp.unapply(tree) @inline final def isInfixApp(tree: Tree): Boolean = asInfixApp(tree).isDefined @@ -571,15 +535,14 @@ object TreeOps { } // procedure syntax has decltpe: Some("") - def isProcedureSyntax(defn: Defn.Def): Boolean = - defn.decltpe.exists(_.tokens.isEmpty) + def isProcedureSyntax(defn: Defn.Def): Boolean = defn.decltpe + .exists(_.tokens.isEmpty) - def isXmlBrace(owner: Tree): Boolean = - owner match { - case _: Term.Xml | _: Pat.Xml => true - case b: Term.Block => b.parent.exists(_.isInstanceOf[Term.Xml]) - case _ => false - } + def isXmlBrace(owner: Tree): Boolean = owner match { + case _: Term.Xml | _: Pat.Xml => true + case b: Term.Block => b.parent.exists(_.isInstanceOf[Term.Xml]) + case _ => false + } def getAssignAtSingleArgCallSite(args: Seq[Tree]): Option[Term.Assign] = args match { @@ -617,8 +580,7 @@ object TreeOps { @tailrec def isTreeSingleExpr(tree: Tree): Boolean = tree match { - case t: Term.Block => - t.stats match { + case t: Term.Block => t.stats match { case stat :: Nil => isTreeSingleExpr(stat) case _ => false } @@ -631,8 +593,8 @@ object TreeOps { * block contains only a single statement. NB: in FormatWriter, when choosing * to insert or remove end markers, we avoid such borderline cases. */ - def getSingleStatExceptEndMarker(s: Seq[Stat]): Option[Stat] = - s.headOption.filter { _ => + def getSingleStatExceptEndMarker(s: Seq[Stat]): Option[Stat] = s.headOption + .filter { _ => val len2 = s.lengthCompare(2) len2 < 0 || len2 == 0 && s(1).is[Term.EndMarker] } @@ -642,18 +604,17 @@ object TreeOps { case _ => Some(t) } - def getTreeSingleStat(t: Tree): Option[Tree] = - t match { - case b: Term.Block => getBlockSingleStat(b) - case _ => Some(t) - } + def getTreeSingleStat(t: Tree): Option[Tree] = t match { + case b: Term.Block => getBlockSingleStat(b) + case _ => Some(t) + } def getTreeLineSpan(b: Tree): Int = getTreeLineSpan(b.pos) def getTreeLineSpan(pos: Position): Int = if (pos.isEmpty) 0 else pos.endLine - pos.startLine - def hasSingleTermStat(t: Term.Block): Boolean = - getBlockSingleStat(t).exists(_.is[Term]) + def hasSingleTermStat(t: Term.Block): Boolean = getBlockSingleStat(t) + .exists(_.is[Term]) def hasSingleTermStatIfBlock(t: Tree): Boolean = t match { case b: Term.Block => hasSingleTermStat(b) @@ -694,50 +655,42 @@ object TreeOps { case Some(v @ Term.ArgClause(_, Some(`kwOwner`))) => Some(v) case Some(v @ Term.ParamClause(_ :: rest, Some(`kwOwner`))) if !kwOwner.is[Mod.Implicit] || rest.isEmpty || - rest.exists(noExplicitImplicit) => - Some(v) + rest.exists(noExplicitImplicit) => Some(v) case _ => None } def hasImplicitParamList(kwOwner: Tree): Boolean = getImplicitParamList(kwOwner).isDefined - def shouldNotDangleAtDefnSite( - tree: Option[Tree], - isVerticalMultiline: Boolean - )(implicit style: ScalafmtConfig): Boolean = - !style.danglingParentheses.defnSite || { - val excludes = style.danglingParentheses.getExclude(isVerticalMultiline) - excludes.nonEmpty && tree - .flatMap { - case _: Ctor.Primary | _: Defn.Class => - Some(DanglingParentheses.Exclude.`class`) - case _: Defn.Trait => Some(DanglingParentheses.Exclude.`trait`) - case _: Defn.Enum => Some(DanglingParentheses.Exclude.`enum`) - case t: Member.ParamClauseGroup => - t.parent.collect { - case _: Defn.ExtensionGroup => - DanglingParentheses.Exclude.`extension` - case _: Decl.Def | _: Defn.Def | _: Defn.Macro => - DanglingParentheses.Exclude.`def` - case _: Decl.Given | _: Defn.Given | _: Defn.GivenAlias => - DanglingParentheses.Exclude.`given` - } - case _ => None + def shouldNotDangleAtDefnSite(tree: Option[Tree], isVerticalMultiline: Boolean)( + implicit style: ScalafmtConfig + ): Boolean = !style.danglingParentheses.defnSite || { + val excludes = style.danglingParentheses.getExclude(isVerticalMultiline) + excludes.nonEmpty && tree.flatMap { + case _: Ctor.Primary | _: Defn.Class => + Some(DanglingParentheses.Exclude.`class`) + case _: Defn.Trait => Some(DanglingParentheses.Exclude.`trait`) + case _: Defn.Enum => Some(DanglingParentheses.Exclude.`enum`) + case t: Member.ParamClauseGroup => t.parent.collect { + case _: Defn.ExtensionGroup => DanglingParentheses.Exclude.`extension` + case _: Decl.Def | _: Defn.Def | _: Defn.Macro => + DanglingParentheses.Exclude.`def` + case _: Decl.Given | _: Defn.Given | _: Defn.GivenAlias => + DanglingParentheses.Exclude.`given` } - .exists(excludes.contains) - } + case _ => None + }.exists(excludes.contains) + } - def isChildOfCaseClause(tree: Tree): Boolean = - findTreeWithParent(tree) { - case t: Case => Some(tree ne t.body) - case _: Pat | _: Pat.ArgClause => None - case _ => Some(false) - }.isDefined + def isChildOfCaseClause(tree: Tree): Boolean = findTreeWithParent(tree) { + case t: Case => Some(tree ne t.body) + case _: Pat | _: Pat.ArgClause => None + case _ => Some(false) + }.isDefined object EndOfFirstCall { - def unapply(tree: Tree): Option[Token] = - traverse(tree, None).map(_.tokens.last) + def unapply(tree: Tree): Option[Token] = traverse(tree, None) + .map(_.tokens.last) @tailrec private def traverse(tree: Tree, res: Option[Tree]): Option[Tree] = @@ -760,27 +713,24 @@ object TreeOps { case t: Member.Apply if t.fun eq lastCall => true case _ => tree eq lastCall } - if (matches) - tree.parent match { - case Some(p) => getLastCall(p, tree) - case _ => tree - } + if (matches) tree.parent match { + case Some(p) => getLastCall(p, tree) + case _ => tree + } else lastCall } @tailrec - def findInterpolate(tree: Tree): Option[Term.Interpolate] = - tree match { - case ti: Term.Interpolate => Some(ti) - case _ => - tree.parent match { - case Some(p) => findInterpolate(p) - case _ => None - } - } + def findInterpolate(tree: Tree): Option[Term.Interpolate] = tree match { + case ti: Term.Interpolate => Some(ti) + case _ => tree.parent match { + case Some(p) => findInterpolate(p) + case _ => None + } + } - def findArgAfter(end: Int, trees: Seq[Tree]): Option[Tree] = - trees.find(_.pos.start >= end) + def findArgAfter(end: Int, trees: Seq[Tree]): Option[Tree] = trees + .find(_.pos.start >= end) def getStripMarginCharForInterpolate(tree: Tree): Option[Char] = findInterpolate(tree).flatMap(getStripMarginChar) @@ -811,11 +761,10 @@ object TreeOps { x.nonEmpty && x.head.start <= beg.start && x.last.end >= end.end } if (isWithinRange(tree.tokens)) Some(tree) - else - tree.children.find(matches) match { - case Some(c) => findFirstTreeBetween(c, beg, end) - case _ => None - } + else tree.children.find(matches) match { + case Some(c) => findFirstTreeBetween(c, beg, end) + case _ => None + } } @inline @@ -827,8 +776,8 @@ object TreeOps { } @tailrec - def existsIfWithoutElse(t: Term.If): Boolean = - existsIfWithoutElse(t.thenp) || (t.elsep match { + def existsIfWithoutElse(t: Term.If): Boolean = existsIfWithoutElse(t.thenp) || + (t.elsep match { case x: Term.If => existsIfWithoutElse(x) case _ => ifWithoutElse(t) }) @@ -838,21 +787,20 @@ object TreeOps { case _ => false } - def cannotStartSelectChainOnExpr(expr: Term): Boolean = - expr match { - case _: Term.Placeholder => true - case t: Term.Name => isSymbolicName(t.value) - case t: Term.Select => isSymbolicName(t.name.value) - case _ => false - } + def cannotStartSelectChainOnExpr(expr: Term): Boolean = expr match { + case _: Term.Placeholder => true + case t: Term.Name => isSymbolicName(t.value) + case t: Term.Select => isSymbolicName(t.name.value) + case _ => false + } // Redundant {} block around case statements - def isCaseBodyABlock(ft: FormatToken, caseStat: CaseTree): Boolean = - ft.right.is[Token.LeftBrace] && (caseStat.body eq ft.meta.rightOwner) + def isCaseBodyABlock(ft: FormatToken, caseStat: CaseTree): Boolean = ft.right + .is[Token.LeftBrace] && (caseStat.body eq ft.meta.rightOwner) - def getStartOfTemplateBody(template: Template): Option[Token] = - template.self.tokens.headOption - .orElse(template.stats.headOption.flatMap(_.tokens.headOption)) + def getStartOfTemplateBody(template: Template): Option[Token] = template.self + .tokens.headOption + .orElse(template.stats.headOption.flatMap(_.tokens.headOption)) def getTemplateGroups(template: Template): Option[Seq[List[Tree]]] = { val groups = Seq(template.inits, template.derives).filter(_.nonEmpty) @@ -860,9 +808,9 @@ object TreeOps { } @tailrec - final def followedBySelectOrApply(tree: Tree)(implicit - ftoks: FormatTokens - ): Boolean = tree.parent match { + final def followedBySelectOrApply( + tree: Tree + )(implicit ftoks: FormatTokens): Boolean = tree.parent match { case Some(p: Term.New) => followedBySelectOrApply(p) case Some(_: Term.Select) => true case Some(p: Member.Infix) => p.lhs.eq(tree) || followedBySelectOrApply(p) @@ -889,16 +837,15 @@ object TreeOps { whenNL: Boolean = true )(implicit style: ScalafmtConfig): Boolean = { def owner = ft.meta.rightOwner - def isArgOrParamClauseSite(tree: Tree) = - !whenNL || isArgClauseSite(tree) || isParamClauseSite(tree) + def isArgOrParamClauseSite(tree: Tree) = !whenNL || isArgClauseSite(tree) || + isParamClauseSite(tree) // skip empty parens/braces/brackets ft.right match { - case _: Token.RightBrace => - !left.is[Token.LeftBrace] && owner.is[Importer] - case _: Token.RightParen => - !left.is[Token.LeftParen] && isArgOrParamClauseSite(owner) - case _: Token.RightBracket => - !left.is[Token.LeftBracket] && isArgOrParamClauseSite(owner) + case _: Token.RightBrace => !left.is[Token.LeftBrace] && owner.is[Importer] + case _: Token.RightParen => !left.is[Token.LeftParen] && + isArgOrParamClauseSite(owner) + case _: Token.RightBracket => !left.is[Token.LeftBracket] && + isArgOrParamClauseSite(owner) case _ => false } } @@ -935,8 +882,8 @@ object TreeOps { var infixCount = 0 // Creates lookup table from token offset to its closest scala.meta tree val ownersMap = HashMap.newBuilder[TokenHash, Tree] - @inline def setOwner(tok: Token, tree: Tree): Unit = - ownersMap += hash(tok) -> tree + @inline + def setOwner(tok: Token, tree: Tree): Unit = ownersMap += hash(tok) -> tree val allTokens = topSourceTree.tokens var prevParens: List[Token] = Nil @@ -945,13 +892,11 @@ object TreeOps { if (TreeOps.isInfixApp(elem)) infixCount += 1 val endPos = elem.pos.end - val allChildren: List[(Tree, Int)] = elem.children - .flatMap { x => - val pos = x.pos - val startPos = pos.start - if (startPos == pos.end) None else Some((x, startPos)) - } - .sortBy(_._2) + val allChildren: List[(Tree, Int)] = elem.children.flatMap { x => + val pos = x.pos + val startPos = pos.start + if (startPos == pos.end) None else Some((x, startPos)) + }.sortBy(_._2) allChildren match { case Nil => @@ -1000,13 +945,12 @@ object TreeOps { tokenAt(nextIdx) } else { def excludeRightParen: Boolean = elem match { - case t: Term.If => - prevLPs == 1 && prevChild == t.cond // `expr` after `mods` + case t: Term.If => prevLPs == 1 && prevChild == t.cond // `expr` after `mods` case _: Term.While | _: Term.For | _: Term.ForYield => prevLPs == 1 && prevChild == firstChild // `expr` is first case _: Member.SyntaxValuesClause | _: Member.Tuple | - _: Term.Do | _: Term.AnonymousFunction => - endPos == tok.end + _: Term.Do | _: Term.AnonymousFunction => endPos == + tok.end case t: Init => prevChild ne t.tpe // include tpe case _: Ctor.Primary => true case _ => false @@ -1018,8 +962,7 @@ object TreeOps { else { setOwner(tok, prevChild) setOwner(prevParens.head, prevChild) - if (prevComma != null) - setOwner(prevComma, prevChild) + if (prevComma != null) setOwner(prevComma, prevChild) } prevLPs -= 1 prevParens = prevParens.tail @@ -1073,10 +1016,11 @@ object TreeOps { dialect.allowFewerBraces && ftoks.getHead(tree.argClause).left.is[Colon] @tailrec - def isFewerBracesLhs( - tree: Tree - )(implicit dialect: Dialect, ftoks: FormatTokens): Boolean = - !ftoks.isEnclosedInMatching(tree) && (tree match { + def isFewerBracesLhs(tree: Tree)(implicit + dialect: Dialect, + ftoks: FormatTokens + ): Boolean = !ftoks.isEnclosedInMatching(tree) && + (tree match { case t: Term.Apply => isFewerBraces(t) case t: Term.ApplyInfix => isFewerBracesLhs(t.argClause) case Term.ArgClause(arg :: Nil, _) => isFewerBracesLhs(arg) @@ -1084,18 +1028,18 @@ object TreeOps { }) @tailrec - def isFewerBracesRhs( - tree: Tree - )(implicit dialect: Dialect, ftoks: FormatTokens): Boolean = - !ftoks.isEnclosedInMatching(tree) && (tree match { + def isFewerBracesRhs(tree: Tree)(implicit + dialect: Dialect, + ftoks: FormatTokens + ): Boolean = !ftoks.isEnclosedInMatching(tree) && + (tree match { case t: Term.Apply => isFewerBraces(t) case t: Term.ApplyInfix => isFewerBracesRhs(t.lhs) case Term.ArgClause(arg :: Nil, _) => isFewerBracesRhs(arg) case _ => false }) - def isParentAnApply(t: Tree): Boolean = - t.parent.exists(_.is[Term.Apply]) + def isParentAnApply(t: Tree): Boolean = t.parent.exists(_.is[Term.Apply]) def isTreeOrBlockParent(owner: Tree)(pred: Tree => Boolean): Boolean = if (owner.is[Term.Block]) owner.parent.exists(pred) else pred(owner) @@ -1106,16 +1050,14 @@ object TreeOps { def isInterpolate(tree: Tree): Boolean = isTreeOrBlockParent(tree)(_.isAny[Term.Interpolate, Pat.Interpolate]) - def isEmptyTree(tree: Tree): Boolean = - tree match { - case t: Term.Block => t.stats.isEmpty - case t => t.tokens.isEmpty - } + def isEmptyTree(tree: Tree): Boolean = tree match { + case t: Term.Block => t.stats.isEmpty + case t => t.tokens.isEmpty + } - def isEmptyFunctionBody(tree: Tree): Boolean = - tree match { - case t: Term.FunctionTerm => isEmptyTree(t.body) - case _ => false - } + def isEmptyFunctionBody(tree: Tree): Boolean = tree match { + case t: Term.FunctionTerm => isEmptyTree(t.body) + case _ => false + } } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/ValidationOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/ValidationOps.scala index 870b005133..1686a99795 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/util/ValidationOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/util/ValidationOps.scala @@ -6,53 +6,43 @@ object ValidationOps { def checkNonNeg( ns: sourcecode.Text[Int]* - )(implicit errors: mutable.Buffer[String]): Unit = - ns.foreach { n => - if (n.value < 0) - errors += s"${n.source} must be non-negative, was ${n.value}" - } + )(implicit errors: mutable.Buffer[String]): Unit = ns.foreach { n => + if (n.value < 0) errors += + s"${n.source} must be non-negative, was ${n.value}" + } def checkPositive( ns: sourcecode.Text[Int]* - )(implicit errors: mutable.Buffer[String]): Unit = - ns.foreach { n => - if (n.value <= 0) - errors += s"${n.source} must be positive, was ${n.value}" - } + )(implicit errors: mutable.Buffer[String]): Unit = ns.foreach { n => + if (n.value <= 0) errors += s"${n.source} must be positive, was ${n.value}" + } def checkNonNegOpt( ns: sourcecode.Text[Option[Int]]* - )(implicit errors: mutable.Buffer[String]): Unit = - ns.foreach { n => - n.value.foreach { nv => - if (nv < 0) errors += s"${n.source} must be non-negative, was $nv" - } + )(implicit errors: mutable.Buffer[String]): Unit = ns.foreach { n => + n.value.foreach { nv => + if (nv < 0) errors += s"${n.source} must be non-negative, was $nv" } + } def checkPositiveOpt( ns: sourcecode.Text[Option[Int]]* - )(implicit errors: mutable.Buffer[String]): Unit = - ns.foreach { n => - n.value.foreach { nv => - if (nv <= 0) errors += s"${n.source} must be positive, was $nv" - } + )(implicit errors: mutable.Buffer[String]): Unit = ns.foreach { n => + n.value.foreach { nv => + if (nv <= 0) errors += s"${n.source} must be positive, was $nv" } + } + + def addIf(what: sourcecode.Text[Boolean])(implicit + errors: mutable.Buffer[String] + ): Unit = addIfDirect(what.value, what.source) + + def addIf(what: sourcecode.Text[Boolean], why: => String)(implicit + errors: mutable.Buffer[String] + ): Unit = addIfDirect(what.value, s"$why: ${what.source}") - def addIf( - what: sourcecode.Text[Boolean] - )(implicit errors: mutable.Buffer[String]): Unit = - addIfDirect(what.value, what.source) - - def addIf( - what: sourcecode.Text[Boolean], - why: => String - )(implicit errors: mutable.Buffer[String]): Unit = - addIfDirect(what.value, s"$why: ${what.source}") - - def addIfDirect( - what: Boolean, - why: => String - )(implicit errors: mutable.Buffer[String]): Unit = - if (what) errors += why + def addIfDirect(what: Boolean, why: => String)(implicit + errors: mutable.Buffer[String] + ): Unit = if (what) errors += why } diff --git a/scalafmt-docs/src/main/scala/docs/DefaultsModifier.scala b/scalafmt-docs/src/main/scala/docs/DefaultsModifier.scala index d7f6044118..fba3ebe2fd 100644 --- a/scalafmt-docs/src/main/scala/docs/DefaultsModifier.scala +++ b/scalafmt-docs/src/main/scala/docs/DefaultsModifier.scala @@ -11,8 +11,8 @@ import mdoc.StringModifier class DefaultsModifier extends StringModifier { override val name: String = "defaults" - private val default = - ConfEncoder[ScalafmtConfig].writeObj(ScalafmtConfig.default) + private val default = ConfEncoder[ScalafmtConfig] + .writeObj(ScalafmtConfig.default) override def process( info: String, @@ -20,8 +20,7 @@ class DefaultsModifier extends StringModifier { reporter: Reporter ): String = { if (info == "all") { - val result = - Conf.printHocon(ScalafmtConfig.default) + val result = Conf.printHocon(ScalafmtConfig.default) "```\n" + result + "\n```" } else { def getDefaultValue(param: String): String = { @@ -41,9 +40,8 @@ class DefaultsModifier extends StringModifier { val defaults = params.map { param => s"$param = ${getDefaultValue(param)}" } - ScalafmtModifier.mdConfigCodeBlock( - defaults.mkString("# Defaults\n", "\n", "") - ) + ScalafmtModifier + .mdConfigCodeBlock(defaults.mkString("# Defaults\n", "\n", "")) } } } diff --git a/scalafmt-docs/src/main/scala/docs/Docusaurus.scala b/scalafmt-docs/src/main/scala/docs/Docusaurus.scala index f11573338a..3c35f5ba60 100644 --- a/scalafmt-docs/src/main/scala/docs/Docusaurus.scala +++ b/scalafmt-docs/src/main/scala/docs/Docusaurus.scala @@ -29,10 +29,8 @@ object Docusaurus { npm.submit(new Runnable { override def run(): Unit = { val cwd = Paths.get("website").toFile - process = new java.lang.ProcessBuilder("npm", "start") - .inheritIO() - .directory(cwd) - .start() + process = new java.lang.ProcessBuilder("npm", "start").inheritIO() + .directory(cwd).start() } }) new Docusaurus(() => process, npm) diff --git a/scalafmt-docs/src/main/scala/docs/FileModifier.scala b/scalafmt-docs/src/main/scala/docs/FileModifier.scala index 7021c70c41..253a9c18ea 100644 --- a/scalafmt-docs/src/main/scala/docs/FileModifier.scala +++ b/scalafmt-docs/src/main/scala/docs/FileModifier.scala @@ -26,14 +26,15 @@ class FileModifier extends StringModifier { case _ => "text" } s""" -File: [${file.toNIO.getFileName}](https://github.com/scalameta/mdoc/blob/master/$info) +File: [${file.toNIO + .getFileName}](https://github.com/scalameta/mdoc/blob/master/$info) `````$language $text ````` """ } else { - val pos = - Position.Range(code, 0 - info.length - 1, 0 - 1).toUnslicedPosition + val pos = Position.Range(code, 0 - info.length - 1, 0 - 1) + .toUnslicedPosition reporter.error(pos, s"no such file: $file") "" } diff --git a/scalafmt-docs/src/main/scala/docs/Main.scala b/scalafmt-docs/src/main/scala/docs/Main.scala index f681d3348f..151d4afad4 100644 --- a/scalafmt-docs/src/main/scala/docs/Main.scala +++ b/scalafmt-docs/src/main/scala/docs/Main.scala @@ -7,24 +7,16 @@ object Main { def main(args: Array[String]): Unit = { // val docusaurus = Docusaurus.start() - val settings = mdoc - .MainSettings() - .withOut(Paths.get("website", "target", "docs")) - .withSiteVariables( - Map( - "VERSION" -> Versions.version, - "STABLE_VERSION" -> Versions.stable, - "SCALAMETA_VERSION" -> Versions.scalameta - ) - ) - .withStringModifiers( - List( - new FileModifier, - new ScalafmtModifier, - new DefaultsModifier - ) - ) - .withArgs(args.toList) + val settings = mdoc.MainSettings() + .withOut(Paths.get("website", "target", "docs")).withSiteVariables(Map( + "VERSION" -> Versions.version, + "STABLE_VERSION" -> Versions.stable, + "SCALAMETA_VERSION" -> Versions.scalameta + )).withStringModifiers(List( + new FileModifier, + new ScalafmtModifier, + new DefaultsModifier + )).withArgs(args.toList) val exit = mdoc.Main.process(settings) if (exit != 0) sys.exit(exit) diff --git a/scalafmt-docs/src/main/scala/docs/ScalafmtModifier.scala b/scalafmt-docs/src/main/scala/docs/ScalafmtModifier.scala index 0fe1416452..72a5a61ef4 100644 --- a/scalafmt-docs/src/main/scala/docs/ScalafmtModifier.scala +++ b/scalafmt-docs/src/main/scala/docs/ScalafmtModifier.scala @@ -47,11 +47,8 @@ class ScalafmtModifier extends StringModifier { mdScalaCodeBlock("formatted", formatted.trim) val originalCodeBlock = mdScalaCodeBlock("original", program.text.trim) - List( - formattedCodeBlock, - originalCodeBlock, - configBlock - ).mkString("\n") + List(formattedCodeBlock, originalCodeBlock, configBlock) + .mkString("\n") case Left(e: ParseException) => reporter.error(pos, e.toString()) "parse error" @@ -67,8 +64,7 @@ class ScalafmtModifier extends StringModifier { object ScalafmtModifier { - private val defaultConfig = ScalafmtConfig.default - .copy(maxColumn = 40) + private val defaultConfig = ScalafmtConfig.default.copy(maxColumn = 40) .withDialect(NamedDialect.scala213, "scala213") private val defaultSbtConfig = defaultConfig.forSbt diff --git a/scalafmt-docs/src/main/scala/website/package.scala b/scalafmt-docs/src/main/scala/website/package.scala index d3b486a1ba..95ce3f04cf 100644 --- a/scalafmt-docs/src/main/scala/website/package.scala +++ b/scalafmt-docs/src/main/scala/website/package.scala @@ -24,22 +24,19 @@ package object website { } index += 1 } - if (index < len) { - buf.append(line.substring(index)) - } + if (index < len) { buf.append(line.substring(index)) } buf.append('\n') } buf.toString } - def plaintext(code: String): String = - "```\n" + code + "\n```" + def plaintext(code: String): String = "```\n" + code + "\n```" - private[this] def scalaCode(code: String): String = - "```scala\n" + code + "\n```" + private[this] def scalaCode(code: String): String = "```scala\n" + code + + "\n```" - def preProcess(code: String): String = - replaceMargin(code.trim).replace("'''", "\"\"\"") + def preProcess(code: String): String = replaceMargin(code.trim) + .replace("'''", "\"\"\"") val logger: PrintStream = { val out = Files.newOutputStream( @@ -62,36 +59,25 @@ package object website { def exampleSource(code: String, config: String*): Unit = { example(code, config, ScalafmtRunner.default) } - def example( - code: String, - config: Seq[String], - runner: ScalafmtRunner - ): Unit = { + def example(code: String, config: Seq[String], runner: ScalafmtRunner): Unit = { val processedCode = preProcess(code) - val parsedConfig1 = - ScalafmtConfig - .fromHoconString(config.mkString("\n")) - .get - .copy(runner = runner) + val parsedConfig1 = ScalafmtConfig.fromHoconString(config.mkString("\n")) + .get.copy(runner = runner) val isCustomMaxColumn = config.exists(_.contains("maxColumn")) val parsedConfig = if (isCustomMaxColumn) parsedConfig1 else parsedConfig1.copy(maxColumn = 40) if (code.contains("validatedInstances")) { logger.println("=======") - logger.println( - parsedConfig.newlines.sometimesBeforeColonInMethodReturnType - ) + logger + .println(parsedConfig.newlines.sometimesBeforeColonInMethodReturnType) logger.println(parsedConfig.maxColumn) logger.println() logger.println(config.mkString("\n")) } val formattedCode = Scalafmt.format(processedCode, parsedConfig).get - val result = new StringBuilder() - .append(config.mkString("// ", "\n// ", "")) - .append("\n\n") - .append(formattedCode) - .toString() + val result = new StringBuilder().append(config.mkString("// ", "\n// ", "")) + .append("\n\n").append(formattedCode).toString() println(scalaCode(result)) } @@ -105,9 +91,7 @@ package object website { * the config to format the code (defaults to `default40`) */ def formatExample(code: String, config: String*): Unit = { - val parsedConfig = ScalafmtConfig - .fromHoconString(config.mkString("\n")) - .get + val parsedConfig = ScalafmtConfig.fromHoconString(config.mkString("\n")).get .copy(maxColumn = 40, runner = ScalafmtRunner.sbt) val processedCode = preProcess(code) val formatted = Scalafmt.format(processedCode, parsedConfig).get diff --git a/scalafmt-dynamic/src/main/scala-2.11/org/scalafmt/dynamic/package.scala b/scalafmt-dynamic/src/main/scala-2.11/org/scalafmt/dynamic/package.scala index e50054d906..ac4fd46648 100644 --- a/scalafmt-dynamic/src/main/scala-2.11/org/scalafmt/dynamic/package.scala +++ b/scalafmt-dynamic/src/main/scala-2.11/org/scalafmt/dynamic/package.scala @@ -10,20 +10,17 @@ package object dynamic { case _ => target.asInstanceOf[Either[A1, B1]] } - def map[B1](f: B => B1): Either[A, B1] = - target match { - case Right(b) => Right(f(b)) - case _ => - target.asInstanceOf[Either[A, B1]] - } + def map[B1](f: B => B1): Either[A, B1] = target match { + case Right(b) => Right(f(b)) + case _ => target.asInstanceOf[Either[A, B1]] + } } implicit class TryOps[T](val target: Try[T]) extends AnyVal { - def toEither: Either[Throwable, T] = - target match { - case Success(value) => Right(value) - case Failure(ex) => Left(ex) - } + def toEither: Either[Throwable, T] = target match { + case Success(value) => Right(value) + case Failure(ex) => Left(ex) + } } } diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/Dependency.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/Dependency.scala index 980bf35fa1..30b0b3f4d6 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/Dependency.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/Dependency.scala @@ -15,8 +15,8 @@ object Dependency { } @inline - private def getScalaBinaryVersion(scalaVersion: String): String = - scalaVersion.substring(0, scalaVersion.lastIndexOf('.')) + private def getScalaBinaryVersion(scalaVersion: String): String = scalaVersion + .substring(0, scalaVersion.lastIndexOf('.')) @inline private def getScalaVersion(version: ScalafmtVersion): String = diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtConfigLoader.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtConfigLoader.scala index 8d4b3dead8..169ef056ea 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtConfigLoader.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtConfigLoader.scala @@ -27,19 +27,18 @@ object ScalafmtConfigLoader extends ScalafmtConfigLoader { configPath: Path, properties: ScalafmtProperties, moduleLoader: ScalafmtModuleLoader - ): FormatEval[ScalafmtReflectConfig] = - for { - version <- readVersion(configPath) - // can't use current build directly, -dynamic doesn't include -core - loaded <- moduleLoader.load(configPath, version, properties) - config <- loaded.parseConfig(configPath).toEither.left.map { - case ex: ScalafmtDynamicError => ex - case ex => new UnknownConfigError(configPath, ex) - } - } yield { - properties.reporter.parsedConfig(configPath, config.getVersion.toString) - config + ): FormatEval[ScalafmtReflectConfig] = for { + version <- readVersion(configPath) + // can't use current build directly, -dynamic doesn't include -core + loaded <- moduleLoader.load(configPath, version, properties) + config <- loaded.parseConfig(configPath).toEither.left.map { + case ex: ScalafmtDynamicError => ex + case ex => new UnknownConfigError(configPath, ex) } + } yield { + properties.reporter.parsedConfig(configPath, config.getVersion.toString) + config + } private def readVersion(config: Path): FormatEval[ScalafmtVersion] = Try(ConfigFactory.parseFile(config.toFile).getString("version")) match { @@ -50,10 +49,9 @@ object ScalafmtConfigLoader extends ScalafmtConfigLoader { Left(new ConfigParseError(config, e.getMessage)) case Failure(_: ConfigException.Missing) => Left(new ConfigMissingVersion(config)) - case Failure(e) => - Left(new UnknownConfigError(config, e)) - case Success(v) => - ScalafmtVersion.parse(v).toRight(new ConfigInvalidVersion(config, v)) + case Failure(e) => Left(new UnknownConfigError(config, e)) + case Success(v) => ScalafmtVersion.parse(v) + .toRight(new ConfigInvalidVersion(config, v)) } class CachedProxy(loader: ScalafmtConfigLoader) extends ScalafmtConfigLoader { @@ -68,10 +66,9 @@ object ScalafmtConfigLoader extends ScalafmtConfigLoader { Try(Files.getLastModifiedTime(configPath)).fold( _ => Left(new ConfigDoesNotExist(configPath)), currentTimestamp => { - def evict(value: Value) = - value.fold(_ => true, _._2.compareTo(currentTimestamp) != 0) - def load() = loader - .load(configPath, properties, moduleLoader) + def evict(value: Value) = value + .fold(_ => true, _._2.compareTo(currentTimestamp) != 0) + def load() = loader.load(configPath, properties, moduleLoader) .map((_, currentTimestamp)) cache.getOrAddToCache(configPath, evict)(load).map(_._1) } diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamic.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamic.scala index 3ed39c8668..e3661b1bc7 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamic.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamic.scala @@ -23,9 +23,7 @@ final case class ScalafmtDynamic( ) ) - override def clear(): Unit = { - moduleLoader.close() - } + override def clear(): Unit = { moduleLoader.close() } override def withReporter(value: ScalafmtReporter): ScalafmtDynamic = copy(properties = properties.withReporter(value)) @@ -45,8 +43,7 @@ final case class ScalafmtDynamic( override def withRepositoryCredentials( value: RepositoryCredential* - ): Scalafmt = - copy(properties = properties.withRepositoryCredentials(value)) + ): Scalafmt = copy(properties = properties.withRepositoryCredentials(value)) override def format(config: Path, file: Path, code: String): String = createSession(config).format(file, code) diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamicError.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamicError.scala index a3d0de049d..59150ee794 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamicError.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamicError.scala @@ -5,10 +5,8 @@ import java.nio.file.Path import scala.util.control.NoStackTrace -sealed class ScalafmtDynamicError( - msg: String, - cause: Throwable = null -) extends Error(msg, cause) +sealed class ScalafmtDynamicError(msg: String, cause: Throwable = null) + extends Error(msg, cause) object ScalafmtDynamicError { sealed abstract class ConfigError( @@ -43,8 +41,7 @@ object ScalafmtDynamicError { version: ScalafmtVersion, urls: Seq[URL] ): String = { - urls - .map(x => if (x.getProtocol == "file") x.getFile else x.toString) + urls.map(x => if (x.getProtocol == "file") x.getFile else x.toString) .mkString(s"[v$version] corrupted class path: [", ",", "]") } diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamicSession.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamicSession.scala index 0ada468f84..70fc9e2d38 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamicSession.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtDynamicSession.scala @@ -14,36 +14,29 @@ final case class ScalafmtDynamicSession( import ScalafmtDynamicSession._ - override def format(file: Path, code: String): String = - tryFormat(file, code).getOrElse(code) + override def format(file: Path, code: String): String = tryFormat(file, code) + .getOrElse(code) override def formatOrError(file: Path, code: String): ScalafmtResult = tryFormat(file, code).fold(new ScalafmtResult(_), new ScalafmtResult(_)) - override def matchesProjectFilters(file: Path): Boolean = - cfg.isIncludedInProject(file) + override def matchesProjectFilters(file: Path): Boolean = cfg + .isIncludedInProject(file) override def isGitOnly: Boolean = cfg.projectIsGit - private def tryFormat( - file: Path, - code: String - ): FormatResult = + private def tryFormat(file: Path, code: String): FormatResult = if (properties.respectExcludeFilters && !matchesProjectFilters(file)) { properties.reporter.excluded(file) Right(code) - } else - tryForceFormat(file, code) + } else tryForceFormat(file, code) - private def tryForceFormat( - file: Path, - code: String - ): FormatResult = { + private def tryForceFormat(file: Path, code: String): FormatResult = { val needSbt = cfg.getVersion < ScalafmtVersion(3, 0, 0, 7) && { val extension = getExtension(file.toString) extension == "md" || // added in 3.0.0-RC7 - cfg.getVersion < ScalafmtVersion(2, 6, 3) && - extension == "sbt" || extension == "sc" // added in 2.6.3 + cfg.getVersion < ScalafmtVersion(2, 6, 3) && extension == "sbt" || + extension == "sc" // added in 2.6.3 } val cfgWithDialect = if (needSbt) cfg.withSbtDialect else Success(cfg) val formatResult = cfgWithDialect.flatMap(_.tryFormat(code, Some(file))) diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtModuleLoader.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtModuleLoader.scala index 962eee143e..bbb0b9ed9f 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtModuleLoader.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtModuleLoader.scala @@ -22,9 +22,8 @@ trait ScalafmtModuleLoader extends Closeable { object ScalafmtModuleLoader { - class WithDownloader( - downloader: DependencyDownloaderFactory - ) extends ScalafmtModuleLoader { + class WithDownloader(downloader: DependencyDownloaderFactory) + extends ScalafmtModuleLoader { override def load( configPath: Path, version: ScalafmtVersion, @@ -42,8 +41,7 @@ object ScalafmtModuleLoader { } class CachedProxy(loader: ScalafmtModuleLoader) - extends ScalafmtModuleLoader - with Closeable { + extends ScalafmtModuleLoader with Closeable { private[dynamic] type Value = FormatEval[ScalafmtReflect] private[dynamic] val cache: ReentrantCache[ScalafmtVersion, Value] = ReentrantCache() @@ -67,14 +65,13 @@ object ScalafmtModuleLoader { private def loadClassPath(configPath: Path, version: ScalafmtVersion)( urls: Seq[URL] - ): FormatEval[ScalafmtReflect] = - Try { - val classloader = new URLClassLoader(urls.toArray, null) - ScalafmtReflect(classloader, version) - }.toEither.left.map { - case e: ReflectiveOperationException => - new CorruptedClassPath(configPath, version, urls, e) - case e => new UnknownConfigError(configPath, e) - } + ): FormatEval[ScalafmtReflect] = Try { + val classloader = new URLClassLoader(urls.toArray, null) + ScalafmtReflect(classloader, version) + }.toEither.left.map { + case e: ReflectiveOperationException => + new CorruptedClassPath(configPath, version, urls, e) + case e => new UnknownConfigError(configPath, e) + } } diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtProperties.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtProperties.scala index 46d73a6662..c9f2c9a0e9 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtProperties.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtProperties.scala @@ -23,15 +23,12 @@ final case class ScalafmtProperties( def withRepositoryCredentials( value: Seq[RepositoryCredential] - ): ScalafmtProperties = - copy(repositoryCredentials = value) - - def reportError(file: Path, error: ScalafmtDynamicError): Unit = - error match { - case _: ConfigMissingVersion => - reporter.missingVersion(file, BuildInfo.stable) - case _ => - reporter.error(file, error.getMessage, error.getCause) - } + ): ScalafmtProperties = copy(repositoryCredentials = value) + + def reportError(file: Path, error: ScalafmtDynamicError): Unit = error match { + case _: ConfigMissingVersion => reporter + .missingVersion(file, BuildInfo.stable) + case _ => reporter.error(file, error.getMessage, error.getCause) + } } diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtReflect.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtReflect.scala index 445410468d..34af5e595d 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtReflect.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtReflect.scala @@ -8,10 +8,8 @@ import org.scalafmt.dynamic.utils.ReflectUtils._ import scala.util.Failure import scala.util.Try -case class ScalafmtReflect( - classLoader: ClassLoader, - version: ScalafmtVersion -) extends Closeable { +case class ScalafmtReflect(classLoader: ClassLoader, version: ScalafmtVersion) + extends Closeable { import classLoader.loadClass // FIXME: the class does not exist for version old versions, e.g. v0.2.8 @@ -21,15 +19,13 @@ case class ScalafmtReflect( private lazy val configCls = loadClass("org.scalafmt.config.Config") private val scalafmtCls = loadClass("org.scalafmt.Scalafmt") - private val parseExceptionCls = - loadClass("scala.meta.parsers.ParseException") + private val parseExceptionCls = loadClass("scala.meta.parsers.ParseException") private val tokenizeExceptionCls = loadClass("scala.meta.tokenizers.TokenizeException") - private val defaultScalaFmtConfig = - scalafmtCls.invokeStatic("format$default$2") - private val emptyRange = - scalafmtCls.invokeStatic("format$default$3") + private val defaultScalaFmtConfig = scalafmtCls + .invokeStatic("format$default$2") + private val emptyRange = scalafmtCls.invokeStatic("format$default$3") private val formattedGet = formattedCls.getMethod("get") private val formatMethod = scalafmtCls.getMethod( @@ -38,15 +34,13 @@ case class ScalafmtReflect( defaultScalaFmtConfig.getClass, scalaSetCls ) - private val formatMethodWithFilename = Try( - scalafmtCls.getMethod( - "format", - classOf[String], - defaultScalaFmtConfig.getClass, - scalaSetCls, - classOf[String] - ) - ).toOption + private val formatMethodWithFilename = Try(scalafmtCls.getMethod( + "format", + classOf[String], + defaultScalaFmtConfig.getClass, + scalaSetCls, + classOf[String] + )).toOption lazy val intellijScalaFmtConfig: Option[ScalafmtReflectConfig] = if (version < ScalafmtVersion(1, 5, 1)) None @@ -61,7 +55,8 @@ case class ScalafmtReflect( path: Path = null ): Try[ScalafmtReflectConfig] = { import ScalafmtDynamicError.ConfigParseError - @inline def fail(e: Throwable) = + @inline + def fail(e: Throwable) = Failure(new ConfigParseError(path, e.getMessage, e.getCause)) f.map { configured => new ScalafmtReflectConfig(this)(configured.invoke("get")) @@ -75,10 +70,7 @@ case class ScalafmtReflect( def parseConfig(path: Path): Try[ScalafmtReflectConfig] = parseConfigWith(parseConfigPost300(path), path) - def parseConfigFromString( - path: Path, - text: String - ): Try[ScalafmtReflectConfig] = + def parseConfigFromString(path: Path, text: String): Try[ScalafmtReflectConfig] = parseConfigWith(parseConfigPre300(text), path) def parseConfigFromString(text: String): Try[ScalafmtReflectConfig] = @@ -101,8 +93,8 @@ case class ScalafmtReflect( private def parseConfigPre160(textParam: (Class[_], Object)): Try[Object] = { // scalafmt >= v0.7.0-RC1 && scalafmt < 1.6.0 Try { - val fromHoconEmptyPath = - configCls.invokeStatic("fromHoconString$default$2").asParam(optionCls) + val fromHoconEmptyPath = configCls + .invokeStatic("fromHoconString$default$2").asParam(optionCls) configCls.invokeStatic("fromHoconString", textParam, fromHoconEmptyPath) } } @@ -119,13 +111,11 @@ case class ScalafmtReflect( case (Some(method), Some(file)) => val filename = file.toString method.invoke(null, code, config.target, emptyRange, filename) - case _ => - formatMethod.invoke(null, code, config.target, emptyRange) + case _ => formatMethod.invoke(null, code, config.target, emptyRange) } if (version < ScalafmtVersion(2, 3, 0)) moduleInstance("scala.meta.internal.tokenizers.PlatformTokenizerCache$") - .invoke("megaCache") - .invoke("clear") + .invoke("megaCache").invoke("clear") formattedGet.invoke(formatted).asInstanceOf[String] }.recoverWith { case ReflectionException(e) diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtReflectConfig.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtReflectConfig.scala index 97dc788274..d680392cf6 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtReflectConfig.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtReflectConfig.scala @@ -23,37 +23,37 @@ class ScalafmtReflectConfig private[dynamic] (val fmtReflect: ScalafmtReflect)( private val projectMatcherField = projectField.invoke("matcher") private lazy val indentField = Try { - if (getVersion < ScalafmtVersion(3, 0, 0)) - target.invoke("continuationIndent") - else - target.invoke("indent") + if (getVersion < ScalafmtVersion(3, 0, 0)) target + .invoke("continuationIndent") + else target.invoke("indent") } - lazy val projectIsGit = - Try(projectField.invokeAs[Boolean]("git")).getOrElse(false) + lazy val projectIsGit = Try(projectField.invokeAs[Boolean]("git")) + .getOrElse(false) - @inline def getVersion = fmtReflect.version + @inline + def getVersion = fmtReflect.version - @inline def isIncludedInProject(path: Path): Boolean = + @inline + def isIncludedInProject(path: Path): Boolean = isIncludedInProject(path.toString) - def isIncludedInProject(filename: String): Boolean = - projectMatcherField.invokeAs[Boolean]("matches", filename.asParam) + def isIncludedInProject(filename: String): Boolean = projectMatcherField + .invokeAs[Boolean]("matches", filename.asParam) private def sbtDialect: Object = { try dialectsCls.invokeStatic("Sbt") catch { - case ReflectionException(_: NoSuchMethodException) => - dialectsCls.invokeStatic("Sbt0137") + case ReflectionException(_: NoSuchMethodException) => dialectsCls + .invokeStatic("Sbt0137") } } - lazy val withSbtDialect: Try[ScalafmtReflectConfig] = - Try(target.invoke("forSbt")) - .recover { case ReflectionException(_: NoSuchMethodException) => - target.invoke("withDialect", (dialectCls, sbtDialect)) - } - .map(new ScalafmtReflectConfig(fmtReflect)(_)) + lazy val withSbtDialect: Try[ScalafmtReflectConfig] = Try( + target.invoke("forSbt") + ).recover { case ReflectionException(_: NoSuchMethodException) => + target.invoke("withDialect", (dialectCls, sbtDialect)) + }.map(new ScalafmtReflectConfig(fmtReflect)(_)) def withoutRewriteRules: ScalafmtReflectConfig = { if (getVersion < ScalafmtVersion(3, 2, 0)) withoutRewriteRulesPre320 @@ -91,18 +91,18 @@ class ScalafmtReflectConfig private[dynamic] (val fmtReflect: ScalafmtReflect)( !rules.invokeAs[Boolean]("isEmpty") }.getOrElse(false) - def tryFormat(code: String, file: Option[Path]): Try[String] = - fmtReflect.tryFormat(code, this, file) + def tryFormat(code: String, file: Option[Path]): Try[String] = fmtReflect + .tryFormat(code, this, file) def indentMain: Option[Int] = if (getVersion < ScalafmtVersion(3, 0, 0)) Some(2) else indentField.map(_.invokeAs[Int]("main")).toOption - def indentCallSite: Option[Int] = - indentField.map(_.invokeAs[Int]("callSite")).toOption + def indentCallSite: Option[Int] = indentField.map(_.invokeAs[Int]("callSite")) + .toOption - def indentDefnSite: Option[Int] = - indentField.map(_.invokeAs[Int]("defnSite")).toOption + def indentDefnSite: Option[Int] = indentField.map(_.invokeAs[Int]("defnSite")) + .toOption override def equals(obj: Any): Boolean = target.equals(obj) diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtVersion.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtVersion.scala index 06a6a67cb6..cb27931748 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtVersion.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ScalafmtVersion.scala @@ -19,15 +19,12 @@ case class ScalafmtVersion( def >(other: ScalafmtVersion): Boolean = other < this - override def toString: String = - s"$major.$minor.$patch" + - (if (rc > 0) s"-RC$rc" else "") + - snapshot + override def toString: String = s"$major.$minor.$patch" + + (if (rc > 0) s"-RC$rc" else "") + snapshot override def compareTo(o: ScalafmtVersion): Int = { val cmp = Integer.compare(integerRepr, o.integerRepr) - if (cmp != 0) cmp - else snapshot.compareTo(o.snapshot) + if (cmp != 0) cmp else snapshot.compareTo(o.snapshot) } } @@ -36,20 +33,18 @@ object ScalafmtVersion { private val versionRegex = """(\d{1,2})\.(\d{1,2})\.(\d{1,2})(?:-RC(\d{1,2}))?([+].*|-SNAPSHOT)?""".r - def parse(version: String): Option[ScalafmtVersion] = - version match { - case versionRegex(major, minor, patch, rc, snapshot) => - Try { - ScalafmtVersion( - positiveInt(major), - positiveInt(minor), - positiveInt(patch), - if (rc == null) 0 else positiveInt(rc), - if (snapshot == null) "" else snapshot - ) - }.toOption - case _ => None - } + def parse(version: String): Option[ScalafmtVersion] = version match { + case versionRegex(major, minor, patch, rc, snapshot) => Try { + ScalafmtVersion( + positiveInt(major), + positiveInt(minor), + positiveInt(patch), + if (rc == null) 0 else positiveInt(rc), + if (snapshot == null) "" else snapshot + ) + }.toOption + case _ => None + } private def positiveInt(s: String): Int = { val i = s.toInt diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/exceptions/ScalafmtException.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/exceptions/ScalafmtException.scala index f12407e2b0..b972888426 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/exceptions/ScalafmtException.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/exceptions/ScalafmtException.scala @@ -3,5 +3,4 @@ package org.scalafmt.dynamic.exceptions import scala.util.control.NoStackTrace case class ScalafmtException(message: String, cause: Throwable) - extends Exception(message, cause) - with NoStackTrace + extends Exception(message, cause) with NoStackTrace diff --git a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/utils/ReentrantCache.scala b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/utils/ReentrantCache.scala index 7ab059684f..83e598d07c 100644 --- a/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/utils/ReentrantCache.scala +++ b/scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/utils/ReentrantCache.scala @@ -13,45 +13,40 @@ class ReentrantCache[K, V] { @tailrec final def getOrAddToCache(key: K, shouldEvict: V => Boolean = _ => false)( get: () => V - ): V = - synchronized { // try to exit quickly from synchronized block - cache.get(key) match { - case Some(fut) => Right(fut) - case None => - val p = Promise[V]() - cache += key -> p.future - Left(p) - } - } match { - case Right(fut) => - // we set the timeout to 10 minutes because - // we can't expect everybody to have the same internet connection speed. - // - // get or wait for other thread to finish download - val result = Await.result(fut, 10.minute) - - if (shouldEvict(result)) { - synchronized { - cache -= key - } - getOrAddToCache(key, shouldEvict)(get) - } else - result - case Left(p) => - val result = Try(get()) - p.complete(result) - result.get + ): V = synchronized { // try to exit quickly from synchronized block + cache.get(key) match { + case Some(fut) => Right(fut) + case None => + val p = Promise[V]() + cache += key -> p.future + Left(p) } + } match { + case Right(fut) => + // we set the timeout to 10 minutes because + // we can't expect everybody to have the same internet connection speed. + // + // get or wait for other thread to finish download + val result = Await.result(fut, 10.minute) - def clear(): Iterable[Future[V]] = - synchronized { - val oldValues = cache.values - cache = Map.empty - oldValues - } + if (shouldEvict(result)) { + synchronized { cache -= key } + getOrAddToCache(key, shouldEvict)(get) + } else result + case Left(p) => + val result = Try(get()) + p.complete(result) + result.get + } + + def clear(): Iterable[Future[V]] = synchronized { + val oldValues = cache.values + cache = Map.empty + oldValues + } - def getFromCache(key: K): Option[V] = - cache.get(key).map(Await.result(_, 10.minute)) + def getFromCache(key: K): Option[V] = cache.get(key) + .map(Await.result(_, 10.minute)) } object ReentrantCache { def apply[K, V](): ReentrantCache[K, V] = new ReentrantCache[K, V] diff --git a/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/DynamicSuite.scala b/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/DynamicSuite.scala index aa794a02c8..284dd0459f 100644 --- a/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/DynamicSuite.scala +++ b/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/DynamicSuite.scala @@ -30,33 +30,25 @@ class DynamicSuite extends FunSuite { new ConsoleScalafmtReporter(new PrintStream(out)) { override def downloadWriter(): PrintWriter = new PrintWriter(download) - override def error(file: Path, e: Throwable): Unit = - e match { - case p: PositionException => - val input = m.Input.VirtualFile(file.toString, p.code) - val pos = - m.Position.Range( - input, - p.startLine, - p.startCharacter, - p.endLine, - p.endCharacter - ) - val formattedMessage = pos.formatMessage("error", p.shortMessage) - out.write(formattedMessage.getBytes(StandardCharsets.UTF_8)) - case _ => - super.error(file, e) - } + override def error(file: Path, e: Throwable): Unit = e match { + case p: PositionException => + val input = m.Input.VirtualFile(file.toString, p.code) + val pos = m.Position.Range( + input, + p.startLine, + p.startCharacter, + p.endLine, + p.endCharacter + ) + val formattedMessage = pos.formatMessage("error", p.shortMessage) + out.write(formattedMessage.getBytes(StandardCharsets.UTF_8)) + case _ => super.error(file, e) + } override def missingVersion( config: Path, defaultVersion: String - ): Unit = { - missingVersions += defaultVersion - } - override def parsedConfig( - config: Path, - scalafmtVersion: String - ): Unit = { + ): Unit = { missingVersions += defaultVersion } + override def parsedConfig(config: Path, scalafmtVersion: String): Unit = { val n = parsed.getOrElse(scalafmtVersion, 0) parsed(scalafmtVersion) = n + 1 } @@ -96,16 +88,10 @@ class DynamicSuite extends FunSuite { out.toString.replace(config.toString, "path/.scalafmt.conf") } def errors: String = { - out.toString.linesIterator - .filter(_.startsWith("error")) - .mkString("\n") + out.toString.linesIterator.filter(_.startsWith("error")).mkString("\n") } def assertNotIgnored(filename: String)(implicit loc: Location): Unit = { - assertFormat( - "object A { }", - "object A {}\n", - Paths.get(filename) - ) + assertFormat("object A { }", "object A {}\n", Paths.get(filename)) } def assertIgnored(filename: String): Unit = { out.reset() @@ -119,11 +105,9 @@ class DynamicSuite extends FunSuite { def assertFormat()(implicit loc: Location): Unit = { assertFormat("object A { }", "object A {}\n") } - def assertFormat( - original: String, - expected: String, - file: Path = filename - )(implicit loc: Location): Unit = { + def assertFormat(original: String, expected: String, file: Path = filename)( + implicit loc: Location + ): Unit = { out.reset() val obtained = dynamic.format(config, file, original) if (errors.nonEmpty) { @@ -144,18 +128,14 @@ class DynamicSuite extends FunSuite { code: String = "object A { }" )(implicit loc: Location): A = { out.reset() - intercept[A] { - dynamic.format(config, filename, code) - } + intercept[A] { dynamic.format(config, filename, code) } } def assertError(expected: String)(implicit loc: Location): Unit = { assertError("object A { }", expected) } - def assertError( - code: String, - expected: String, - path: Path = filename - )(implicit loc: Location): Unit = { + def assertError(code: String, expected: String, path: Path = filename)( + implicit loc: Location + ): Unit = { out.reset() val obtained = dynamic.format(config, path, code) assertNoDiff(relevant, expected) @@ -167,10 +147,9 @@ class DynamicSuite extends FunSuite { } } - def check( - name: String, - cfgFunc: ScalafmtDynamic => ScalafmtDynamic = identity - )(fn: Format => Unit): Unit = { + def check(name: String, cfgFunc: ScalafmtDynamic => ScalafmtDynamic = identity)( + fn: Format => Unit + ): Unit = { test(name) { val format = new Format(name, cfgFunc) try fn(format) @@ -196,9 +175,9 @@ class DynamicSuite extends FunSuite { "1.0.0" ) - def checkExhaustive(name: String)(config: String => String)( - fn: (Format, String) => Unit - ): Unit = { + def checkExhaustive( + name: String + )(config: String => String)(fn: (Format, String) => Unit): Unit = { testedVersions.foreach { version => test(s"$name [v=$version]") { val format = new Format(name, identity) @@ -383,18 +362,14 @@ class DynamicSuite extends FunSuite { path ) // test scala doesn't allow top-level terms (not passing path here) - if (version >= "3.0.0" || scalaVersion >= "213") - f.assertFormat( - "lazy val x = project", - "lazy val x = project\n" - ) - else - f.assertError( - "lazy val x = project", - s"""|$name.scala:1:1: error:$dialectError classes cannot be lazy - |lazy val x = project - |^^^^""".stripMargin - ) + if (version >= "3.0.0" || scalaVersion >= "213") f + .assertFormat("lazy val x = project", "lazy val x = project\n") + else f.assertError( + "lazy val x = project", + s"""|$name.scala:1:1: error:$dialectError classes cannot be lazy + |lazy val x = project + |^^^^""".stripMargin + ) // check wrapped literals, supported in sbt using scala 2.13+ val wrappedLiteral = "object a { val x: Option[0] = Some(0) }" def assertIsWrappedLiteralFailure(): Unit = { @@ -408,16 +383,14 @@ class DynamicSuite extends FunSuite { ) } - def assertIsWrappedLiteralSuccess(): Unit = - f.assertFormat( - wrappedLiteral, - wrappedLiteral.replaceAll(" +", " ").trim + "\n", - path - ) + def assertIsWrappedLiteralSuccess(): Unit = f.assertFormat( + wrappedLiteral, + wrappedLiteral.replaceAll(" +", " ").trim + "\n", + path + ) if (!isSbt && scalaVersion >= "213" && version > "2.0") assertIsWrappedLiteralSuccess() - else - assertIsWrappedLiteralFailure() + else assertIsWrappedLiteralFailure() } } } @@ -452,30 +425,28 @@ class DynamicSuite extends FunSuite { checkExhaustive("continuation-indent-callSite-and-defnSite") { _ => "continuationIndent { callSite = 5, defnSite = 3 }" } { (f, _) => - val original = - """class A { - | function1( - | argument1, - | "" - | ) - | - | def function2( - | argument1: Type1 - | ): ReturnType - |} + val original = """class A { + | function1( + | argument1, + | "" + | ) + | + | def function2( + | argument1: Type1 + | ): ReturnType + |} """.stripMargin - val expected = - """class A { - | function1( - | argument1, - | "" - | ) - | - | def function2( - | argument1: Type1 - | ): ReturnType - |} - |""".stripMargin + val expected = """class A { + | function1( + | argument1, + | "" + | ) + | + | def function2( + | argument1: Type1 + | ): ReturnType + |} + |""".stripMargin f.assertFormat(original, expected) } @@ -488,8 +459,7 @@ class DynamicSuite extends FunSuite { case x => fail("ReflectConfigResolver is not cached: " + x.getClass.getSimpleName) } - val configOpt = cache - .getFromCache(f.config) + val configOpt = cache.getFromCache(f.config) .collect { case Right((cfg, _)) => cfg } assert(configOpt.nonEmpty) val config = configOpt.get @@ -562,8 +532,8 @@ class DynamicSuite extends FunSuite { s"""|version=current |""".stripMargin ) - val error = - f.assertThrows[ScalafmtDynamicError.ConfigInvalidVersion]().getMessage + val error = f.assertThrows[ScalafmtDynamicError.ConfigInvalidVersion]() + .getMessage assertEquals(error, "Invalid version: current") } @@ -572,18 +542,17 @@ class DynamicSuite extends FunSuite { s"""|maxColumn = 40 |""".stripMargin ) - val error = - f.assertThrows[ScalafmtDynamicError.ConfigMissingVersion]().getMessage + val error = f.assertThrows[ScalafmtDynamicError.ConfigMissingVersion]() + .getMessage assertEquals(error, "Missing version") } - private def assertDynamicConfig( - fmt: Format - )(f: ScalafmtReflectConfig => Unit): Unit = - fmt.dynamic.resolveConfig(fmt.config) match { - case Left(e) => fail("failed to load config", e) - case Right(cfg) => f(cfg) - } + private def assertDynamicConfig(fmt: Format)( + f: ScalafmtReflectConfig => Unit + ): Unit = fmt.dynamic.resolveConfig(fmt.config) match { + case Left(e) => fail("failed to load config", e) + case Right(cfg) => f(cfg) + } private def checkDynamicConfig( name: String, @@ -620,9 +589,8 @@ class DynamicSuite extends FunSuite { assertEquals(cfg.indentDefnSite, Some(4)) } - Seq(("3.0.0", "indent"), ("2.5.3", "continuationIndent")) - .foreach { case (version, section) => - checkDynamicConfig( + Seq(("3.0.0", "indent"), ("2.5.3", "continuationIndent")).foreach { + case (version, section) => checkDynamicConfig( s"check $section.{call,defn}Site", version, "scala211", @@ -633,7 +601,7 @@ class DynamicSuite extends FunSuite { assertEquals(cfg.indentCallSite, Some(3)) assertEquals(cfg.indentDefnSite, Some(5)) } - } + } } @@ -659,10 +627,8 @@ private object DynamicSuite { override def close(): Unit = downloader.close() } - def getBackQuote(version: String): String = - if (version > "3.8.0") "`" else "" + def getBackQuote(version: String): String = if (version > "3.8.0") "`" else "" - def sbtTreatedDifferently(version: String): Boolean = - version > "3.8.0" + def sbtTreatedDifferently(version: String): Boolean = version > "3.8.0" } diff --git a/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/PositionSyntax.scala b/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/PositionSyntax.scala index 9a590e4d43..06c0c52efc 100644 --- a/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/PositionSyntax.scala +++ b/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/PositionSyntax.scala @@ -6,30 +6,21 @@ object PositionSyntax { def formatMessage(pos: Position, severity: String, message: String): String = pos match { - case Position.None => - s"$severity: $message" - case _ => - new java.lang.StringBuilder() - .append(pos.lineInput) - .append(if (severity.isEmpty) "" else " ") - .append(severity) - .append( + case Position.None => s"$severity: $message" + case _ => new java.lang.StringBuilder().append(pos.lineInput) + .append(if (severity.isEmpty) "" else " ").append(severity).append( if (message.isEmpty) "" else if (severity.isEmpty) " " else if (message.startsWith("\n")) ":" else ": " - ) - .append(message) - .append(pos.rangeText) - .toString + ).append(message).append(pos.rangeText).toString } implicit class XtensionPositionsScalafix(private val pos: Position) extends AnyVal { def contains(other: Position): Boolean = { - pos.start <= other.start && - pos.end >= other.end + pos.start <= other.start && pos.end >= other.end } def formatMessage(severity: String, message: String): String = @@ -44,73 +35,53 @@ object PositionSyntax { def rangeNumber: String = s"${pos.startLine + 1}:${pos.startColumn + 1}..${pos.endLine + 1}:${pos.endColumn + 1}" - def rangeText: String = - pos match { - case Position.None => "" - case _ => - if (pos.startLine != pos.endLine) multilines - else lineTextAndCaret - } + def rangeText: String = pos match { + case Position.None => "" + case _ => + if (pos.startLine != pos.endLine) multilines else lineTextAndCaret + } def lineTextAndCaret: String = { - new StringBuilder() - .append("\n") - .append(lineContent) - .append("\n") - .append(pos.lineCaret) - .toString() + new StringBuilder().append("\n").append(lineContent).append("\n") + .append(pos.lineCaret).toString() } def multilines: String = { var i = pos.startLine val sb = new StringBuilder() while (i <= pos.endLine) { - val startColumn = - if (i == pos.startLine) pos.startColumn - else 0 - val endColumn = - if (i == pos.endLine) pos.endColumn - else Int.MaxValue - sb.append("\n> ") - .append( - lineContent( - i, - startColumn = startColumn, - endColumn = endColumn - ).text - ) + val startColumn = if (i == pos.startLine) pos.startColumn else 0 + val endColumn = if (i == pos.endLine) pos.endColumn else Int.MaxValue + sb.append("\n> ").append( + lineContent(i, startColumn = startColumn, endColumn = endColumn).text + ) i += 1 } sb.toString() } - def lineCaret: String = - pos match { - case Position.None => - "" - case _ => - val span = pos.end - pos.start - val caret = - if (span != 0 && pos.startLine == pos.endLine) "^" * span else "^" - (" " * pos.startColumn) + caret - } + def lineCaret: String = pos match { + case Position.None => "" + case _ => + val span = pos.end - pos.start + val caret = + if (span != 0 && pos.startLine == pos.endLine) "^" * span else "^" + (" " * pos.startColumn) + caret + } private def lineContent( line: Int, startColumn: Int = 0, endColumn: Int = Int.MaxValue - ): Position = - Position.Range( - pos.input, - startLine = line, - startColumn = startColumn, - endLine = line, - endColumn = endColumn - ) + ): Position = Position.Range( + pos.input, + startLine = line, + startColumn = startColumn, + endLine = line, + endColumn = endColumn + ) - private def lineContent: String = - pos match { - case Position.None => "" - case range: Position.Range => - lineContent(range.startLine).text - } + private def lineContent: String = pos match { + case Position.None => "" + case range: Position.Range => lineContent(range.startLine).text + } } } diff --git a/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/ScalafmtVersionSuite.scala b/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/ScalafmtVersionSuite.scala index 36d0b1c907..1d233bdada 100644 --- a/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/ScalafmtVersionSuite.scala +++ b/scalafmt-dynamic/src/test/scala/org/scalafmt/dynamic/ScalafmtVersionSuite.scala @@ -4,22 +4,13 @@ import munit.FunSuite class ScalafmtVersionSuite extends FunSuite { test("parse valid versions") { - assertEquals( - ScalafmtVersion.parse("2.0.0"), - Some(ScalafmtVersion(2, 0, 0)) - ) - assertEquals( - ScalafmtVersion.parse("0.1.3"), - Some(ScalafmtVersion(0, 1, 3)) - ) + assertEquals(ScalafmtVersion.parse("2.0.0"), Some(ScalafmtVersion(2, 0, 0))) + assertEquals(ScalafmtVersion.parse("0.1.3"), Some(ScalafmtVersion(0, 1, 3))) assertEquals( ScalafmtVersion.parse("2.0.0-RC4"), Some(ScalafmtVersion(2, 0, 0, 4)) ) - assertEquals( - ScalafmtVersion.parse("2.1.1"), - Some(ScalafmtVersion(2, 1, 1)) - ) + assertEquals(ScalafmtVersion.parse("2.1.1"), Some(ScalafmtVersion(2, 1, 1))) assertEquals( ScalafmtVersion.parse("2.2.3-SNAPSHOT"), Some(ScalafmtVersion(2, 2, 3, 0, "-SNAPSHOT")) diff --git a/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/AbsoluteFile.scala b/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/AbsoluteFile.scala index 6f63dff32b..28ac2e2e11 100644 --- a/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/AbsoluteFile.scala +++ b/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/AbsoluteFile.scala @@ -17,26 +17,40 @@ final class AbsoluteFile(val path: Path) extends AnyVal { def join(other: String) = new AbsoluteFile(path.resolve(other)) def join(files: Seq[Path]): Seq[AbsoluteFile] = files.map(join) - @inline def toUri: URI = path.toUri - @inline def jfile: File = path.toFile + @inline + def toUri: URI = path.toUri + @inline + def jfile: File = path.toFile - @inline def isDirectory: Boolean = FileOps.isDirectory(path) - @inline def isRegularFile: Boolean = FileOps.isRegularFile(path) - @inline def isRegularFileNoLinks: Boolean = FileOps.isRegularFileNoLinks(path) - @inline def attributes: BasicFileAttributes = FileOps.getAttributes(path) + @inline + def isDirectory: Boolean = FileOps.isDirectory(path) + @inline + def isRegularFile: Boolean = FileOps.isRegularFile(path) + @inline + def isRegularFileNoLinks: Boolean = FileOps.isRegularFileNoLinks(path) + @inline + def attributes: BasicFileAttributes = FileOps.getAttributes(path) - @inline def listFiles: Seq[AbsoluteFile] = join(FileOps.listFiles(path)) - @inline def readFile(implicit codec: Codec): String = FileOps.readFile(path) - @inline def writeFile(content: String)(implicit codec: Codec): Unit = - FileOps.writeFile(path, content) + @inline + def listFiles: Seq[AbsoluteFile] = join(FileOps.listFiles(path)) + @inline + def readFile(implicit codec: Codec): String = FileOps.readFile(path) + @inline + def writeFile(content: String)(implicit codec: Codec): Unit = FileOps + .writeFile(path, content) - @inline def parent: AbsoluteFile = new AbsoluteFile(path.getParent) - @inline def delete(): Unit = Files.delete(path) - @inline def mkdir(): Unit = Files.createDirectory(path) - @inline def mkdirs(): Unit = Files.createDirectories(path) + @inline + def parent: AbsoluteFile = new AbsoluteFile(path.getParent) + @inline + def delete(): Unit = Files.delete(path) + @inline + def mkdir(): Unit = Files.createDirectory(path) + @inline + def mkdirs(): Unit = Files.createDirectories(path) override def toString: String = path.toString - @inline def getFileName: String = path.getFileName.toString + @inline + def getFileName: String = path.getFileName.toString } object AbsoluteFile { @@ -44,9 +58,10 @@ object AbsoluteFile { def apply(file: File): AbsoluteFile = apply(file.toPath) def apply(path: Path): AbsoluteFile = new AbsoluteFile(path.toAbsolutePath) - @inline def apply(path: Seq[String]): AbsoluteFile = - apply(FileOps.getFile(path)) - @inline def apply(head: String, tail: String*): AbsoluteFile = + @inline + def apply(path: Seq[String]): AbsoluteFile = apply(FileOps.getFile(path)) + @inline + def apply(head: String, tail: String*): AbsoluteFile = apply(FileOps.getPath(head, tail: _*)) def fromPathIfAbsolute(path: String): Option[AbsoluteFile] = { diff --git a/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/BatchPathFinder.scala b/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/BatchPathFinder.scala index 160fa5624b..fc23654a18 100644 --- a/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/BatchPathFinder.scala +++ b/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/BatchPathFinder.scala @@ -33,9 +33,8 @@ trait BatchPathFinder { object BatchPathFinder { - final class DirFiles(val cwd: AbsoluteFile)( - val matches: Path => Boolean - ) extends BatchPathFinder { + final class DirFiles(val cwd: AbsoluteFile)(val matches: Path => Boolean) + extends BatchPathFinder { private def filter(path: Path, attrs: BasicFileAttributes): Boolean = attrs.isRegularFile && matches(path) override def findFiles(dir: AbsoluteFile*): Seq[AbsoluteFile] = { @@ -46,21 +45,21 @@ object BatchPathFinder { final class GitFiles(git: GitOps)(val matches: Path => Boolean) extends BatchPathFinder { - override def findFiles(dir: AbsoluteFile*): Seq[AbsoluteFile] = - git.lsTree(dir: _*).filter(x => matches(x.path)) + override def findFiles(dir: AbsoluteFile*): Seq[AbsoluteFile] = git + .lsTree(dir: _*).filter(x => matches(x.path)) } final class GitBranchFiles(git: GitOps, branch: String)( val matches: Path => Boolean ) extends BatchPathFinder { - override def findFiles(dir: AbsoluteFile*): Seq[AbsoluteFile] = - git.diff(branch, dir: _*).filter(x => matches(x.path)) + override def findFiles(dir: AbsoluteFile*): Seq[AbsoluteFile] = git + .diff(branch, dir: _*).filter(x => matches(x.path)) } final class GitDirtyFiles(git: GitOps)(val matches: Path => Boolean) extends BatchPathFinder { - override def findFiles(dir: AbsoluteFile*): Seq[AbsoluteFile] = - git.status(dir: _*).filter(x => matches(x.path)) + override def findFiles(dir: AbsoluteFile*): Seq[AbsoluteFile] = git + .status(dir: _*).filter(x => matches(x.path)) } } diff --git a/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/FileOps.scala b/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/FileOps.scala index 48ad02132b..ec3c6849cb 100644 --- a/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/FileOps.scala +++ b/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/FileOps.scala @@ -17,45 +17,42 @@ object FileOps { def getLastModifiedMsec(file: Path): Long = { val attributes = getAttributesNoLinks(file) val mtime = attributes.lastModifiedTime().toMillis - if (attributes.isSymbolicLink) - math.max(mtime, Files.getLastModifiedTime(file).toMillis) + if (attributes.isSymbolicLink) math + .max(mtime, Files.getLastModifiedTime(file).toMillis) else mtime } @inline - def getLastModifiedMsecNoLinks(file: Path): Long = - Files.getLastModifiedTime(file, LinkOption.NOFOLLOW_LINKS).toMillis + def getLastModifiedMsecNoLinks(file: Path): Long = Files + .getLastModifiedTime(file, LinkOption.NOFOLLOW_LINKS).toMillis @inline - def isDirectory(file: Path): Boolean = - Files.isDirectory(file) + def isDirectory(file: Path): Boolean = Files.isDirectory(file) @inline - def isDirectoryNoLinks(file: Path): Boolean = - Files.isDirectory(file, LinkOption.NOFOLLOW_LINKS) + def isDirectoryNoLinks(file: Path): Boolean = Files + .isDirectory(file, LinkOption.NOFOLLOW_LINKS) @inline - def isRegularFile(file: Path): Boolean = - Files.isRegularFile(file) + def isRegularFile(file: Path): Boolean = Files.isRegularFile(file) @inline - def isRegularFileNoLinks(file: Path): Boolean = - Files.isRegularFile(file, LinkOption.NOFOLLOW_LINKS) + def isRegularFileNoLinks(file: Path): Boolean = Files + .isRegularFile(file, LinkOption.NOFOLLOW_LINKS) @inline - def getAttributes(file: Path): BasicFileAttributes = - Files.readAttributes(file, classOf[BasicFileAttributes]) + def getAttributes(file: Path): BasicFileAttributes = Files + .readAttributes(file, classOf[BasicFileAttributes]) @inline - def getAttributesNoLinks(file: Path): BasicFileAttributes = - Files.readAttributes( + def getAttributesNoLinks(file: Path): BasicFileAttributes = Files + .readAttributes( file, classOf[BasicFileAttributes], LinkOption.NOFOLLOW_LINKS ) - def listFiles(path: String): Seq[Path] = - listFiles(getFile(path)) + def listFiles(path: String): Seq[Path] = listFiles(getFile(path)) def listFiles(file: Path): Seq[Path] = listFiles(file, (_, a) => a.isRegularFile) @@ -83,8 +80,8 @@ object FileOps { } @inline - private[sysops] def readAsURL(url: URL)(implicit codec: Codec): String = - Using.resource(scala.io.Source.fromURL(url)) { + private[sysops] def readAsURL(url: URL)(implicit codec: Codec): String = Using + .resource(scala.io.Source.fromURL(url)) { _.getLines().mkString("", "\n", "\n") } @@ -96,13 +93,14 @@ object FileOps { new String(Files.readAllBytes(file), codec.charSet) } - @inline def getFile(path: String): Path = getPath(path) + @inline + def getFile(path: String): Path = getPath(path) - @inline def getFile(path: Seq[String]): Path = - getPath(path.head, path.tail: _*) + @inline + def getFile(path: Seq[String]): Path = getPath(path.head, path.tail: _*) - @inline def getPath(head: String, tail: String*): Path = - Paths.get(head, tail: _*) + @inline + def getPath(head: String, tail: String*): Path = Paths.get(head, tail: _*) def writeFile(path: Path, content: String)(implicit codec: Codec): Unit = { val bytes = content.getBytes(codec.charSet) @@ -111,9 +109,7 @@ object FileOps { def writeFile(filename: String, content: String)(implicit codec: Codec - ): Unit = { - writeFile(getFile(filename), content) - } + ): Unit = { writeFile(getFile(filename), content) } @inline def isMarkdown(filename: String): Boolean = filename.endsWith(".md") @@ -127,13 +123,11 @@ object FileOps { def getCanonicalConfigFile( workingDirectory: AbsoluteFile, config: Option[Path] = None - ): Option[Try[Path]] = - config.fold(tryGetConfigInDir(workingDirectory)) { x => - val file = workingDirectory.join(x) - tryCheckConfigFile(file).orElse( - Some(Failure(new NoSuchFileException(s"Config missing: $file"))) - ) - } + ): Option[Try[Path]] = config.fold(tryGetConfigInDir(workingDirectory)) { x => + val file = workingDirectory.join(x) + tryCheckConfigFile(file) + .orElse(Some(Failure(new NoSuchFileException(s"Config missing: $file")))) + } def tryGetConfigInDir(dir: AbsoluteFile): Option[Try[Path]] = tryCheckConfigFile(dir / defaultConfigFileName) diff --git a/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/GitOps.scala b/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/GitOps.scala index 1b71d1e67a..103ccebc14 100644 --- a/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/GitOps.scala +++ b/scalafmt-sysops/shared/src/main/scala/org/scalafmt/sysops/GitOps.scala @@ -20,19 +20,18 @@ object GitOps { def getCanonicalConfigFile( cwd: AbsoluteFile, config: Option[Path] = None - ): Option[Try[Path]] = - FileOps.getCanonicalConfigFile(cwd, config).orElse(getRootConfigFile) + ): Option[Try[Path]] = FileOps.getCanonicalConfigFile(cwd, config) + .orElse(getRootConfigFile) - def getRootConfigFile: Option[Try[Path]] = - obj.rootDir.flatMap(FileOps.tryGetConfigInDir) + def getRootConfigFile: Option[Try[Path]] = obj.rootDir + .flatMap(FileOps.tryGetConfigInDir) def getProposedConfigFile( cwd: AbsoluteFile, config: Option[Path] = None - ): AbsoluteFile = - config.fold { - obj.rootDir.getOrElse(cwd) / FileOps.defaultConfigFileName - }(cwd / _) + ): AbsoluteFile = config.fold { + obj.rootDir.getOrElse(cwd) / FileOps.defaultConfigFileName + }(cwd / _) } @@ -105,20 +104,17 @@ private class GitOpsImpl(val workingDirectory: AbsoluteFile) extends GitOps { Method extracts path to changed file from the singular line of the `git status --porcelain` output. (see https://git-scm.com/docs/git-status#_short_format) */ - private def extractPathPart(s: String): String = - Option(s) - // Checks if the line status states the file was renamed (E.g: `R ORIG_PATH -> PATH`) - .filter(_.substring(0, 2).contains(renameStatusCode)) - // takes the part of the string after the `-> ` character sequence - .map(_.split(renameStatusArrowDelimiter).last) - // fallback for the regular status line (E.g.: `XY PATH`) - // Drops the status codes by splitting on white spaces then taking the tail of the result - // Restores spaces in the path by merging the tail back with white space separator - .getOrElse(s.trim.split(' ').tail.mkString(" ")) - .trim - - private def trimQuotes(s: String): String = - s.replaceAll("^\"|\"$", "") + private def extractPathPart(s: String): String = Option(s) + // Checks if the line status states the file was renamed (E.g: `R ORIG_PATH -> PATH`) + .filter(_.substring(0, 2).contains(renameStatusCode)) + // takes the part of the string after the `-> ` character sequence + .map(_.split(renameStatusArrowDelimiter).last) + // fallback for the regular status line (E.g.: `XY PATH`) + // Drops the status codes by splitting on white spaces then taking the tail of the result + // Restores spaces in the path by merging the tail back with white space separator + .getOrElse(s.trim.split(' ').tail.mkString(" ")).trim + + private def trimQuotes(s: String): String = s.replaceAll("^\"|\"$", "") private def getFileFromGitStatusLine(s: String): String = trimQuotes(extractPathPart(s)) diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/CommentTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/CommentTest.scala index 5b2bc7cd2a..155103b295 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/CommentTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/CommentTest.scala @@ -5,8 +5,8 @@ import org.scalafmt.config.{Docstrings, ScalafmtConfig} class CommentTest extends FunSuite { - private val javadocStyle: ScalafmtConfig = - ScalafmtConfig.default.copy(docstrings = + private val javadocStyle: ScalafmtConfig = ScalafmtConfig.default + .copy(docstrings = ScalafmtConfig.default.docstrings .copy(style = Docstrings.Asterisk, wrap = Docstrings.Wrap.no) ) diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/CustomStructureTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/CustomStructureTest.scala index 2975a32815..ca73725717 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/CustomStructureTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/CustomStructureTest.scala @@ -7,11 +7,9 @@ import scala.meta.internal.parsers.ScalametaParser class CustomStructureTest extends FunSuite { - private def check( - original: String, - expected: Tree, - dialect: Dialect - )(implicit loc: munit.Location): Unit = { + private def check(original: String, expected: Tree, dialect: Dialect)(implicit + loc: munit.Location + ): Unit = { val parser = new ScalametaParser(Input.String(original))(dialect) assertNoDiff(parser.parseStat().structure, expected.structure) } @@ -24,31 +22,21 @@ class CustomStructureTest extends FunSuite { Defn.Def( Nil, Term.Name("foo"), - List( - Member.ParamClauseGroup( - Type.ParamClause(Nil), - List( - Term.ParamClause( - List( - Term.Param( - Nil, - Term.Name("a"), - Some( - Type.Apply( - Type.Name("Foo"), - Type.ArgClause( - List(Type.Wildcard(Type.Bounds(None, None))) - ) - ) - ), - None - ) - ), - None - ) - ) - ) - ), + List(Member.ParamClauseGroup( + Type.ParamClause(Nil), + List(Term.ParamClause( + List(Term.Param( + Nil, + Term.Name("a"), + Some(Type.Apply( + Type.Name("Foo"), + Type.ArgClause(List(Type.Wildcard(Type.Bounds(None, None)))) + )), + None + )), + None + )) + )), Some(Type.Name("Unit")), Term.Name("???") ), diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/Debug.scala b/scalafmt-tests/src/test/scala/org/scalafmt/Debug.scala index 0ba589819e..2ee5b97f50 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/Debug.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/Debug.scala @@ -29,10 +29,7 @@ class Debug(val verbose: Boolean) { def elapsedNs = System.nanoTime() - startTime - def enqueued(split: Split): Unit = { - if (verbose) - enqueuedSplits += split - } + def enqueued(split: Split): Unit = { if (verbose) enqueuedSplits += split } def completed(event: CompleteFormat): Unit = { explored += event.totalExplored @@ -47,18 +44,10 @@ class Debug(val verbose: Boolean) { // splits if (enqueuedSplits.nonEmpty) { val sb = new StringBuilder() - enqueuedSplits - .groupBy(_.fileLine.line.value) - .toSeq - .sortBy(-_._2.size) - .iterator - .take(3) - .foreach { case (line, group) => - sb.append("Split(line=") - .append(line) - .append(" count=") - .append(group.size) - .append("=") + enqueuedSplits.groupBy(_.fileLine.line.value).toSeq.sortBy(-_._2.size) + .iterator.take(3).foreach { case (line, group) => + sb.append("Split(line=").append(line).append(" count=") + .append(group.size).append("=") group.foreach(sb.append("\n\t").append(_)) sb.append("\n") } @@ -67,26 +56,24 @@ class Debug(val verbose: Boolean) { val toks = if (null == formatOps) null else formatOps.tokens.arr if (null != toks) { - if (null != formatTokenExplored) - formatTokenExplored.zipWithIndex.sortBy(-_._1).take(3).foreach { - case (visits, idx) => - LoggerOps.logger.debug("Visited " + toks(idx) + ": " + visits) + if (null != formatTokenExplored) formatTokenExplored.zipWithIndex + .sortBy(-_._1).take(3).foreach { case (visits, idx) => + LoggerOps.logger.debug("Visited " + toks(idx) + ": " + visits) } val stack = new mutable.ListBuffer[String] val posWidth = s"%${1 + math.log10(toks.last.left.end).toInt}d" @tailrec - def iter(state: State): Unit = - if (state.prev ne State.start) { - val prev = state.prev - val tok = toks(prev.depth).left - val clean = "%-15s".format(LoggerOps.cleanup(tok).slice(0, 15)) - stack.prepend( - s"${posWidth.format(tok.end)}: $clean" + - s" ${state.split} ${prev.indentation} ${prev.column} [${state.cost}]" - ) - iter(prev) - } + def iter(state: State): Unit = if (state.prev ne State.start) { + val prev = state.prev + val tok = toks(prev.depth).left + val clean = "%-15s".format(LoggerOps.cleanup(tok).slice(0, 15)) + stack.prepend( + s"${posWidth.format(tok.end)}: $clean" + + s" ${state.split} ${prev.indentation} ${prev.column} [${state.cost}]" + ) + iter(prev) + } if (state ne State.start) { iter(state) stack.foreach(LoggerOps.logger.debug) @@ -102,7 +89,7 @@ object Debug { var explored = 0 - def ns2ms(nanoseconds: Long): Long = - TimeUnit.MILLISECONDS.convert(nanoseconds, TimeUnit.NANOSECONDS) + def ns2ms(nanoseconds: Long): Long = TimeUnit.MILLISECONDS + .convert(nanoseconds, TimeUnit.NANOSECONDS) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/FidelityTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/FidelityTest.scala index 690dabedb6..dc6fc4bef6 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/FidelityTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/FidelityTest.scala @@ -29,14 +29,10 @@ class FidelityTest extends FunSuite with FormatAssertions { "/resources/", "/gh-pages/" ).map(_.replace("/", File.separator)) - FileOps - .listFiles(".") - .filter { x => - val filename = x.toString - filename.endsWith(".scala") && - !denyList.exists(filename.contains) - } - .map(x => TestCase(x, FileOps.readFile(x))) + FileOps.listFiles(".").filter { x => + val filename = x.toString + filename.endsWith(".scala") && !denyList.exists(filename.contains) + }.map(x => TestCase(x, FileOps.readFile(x))) } examples.foreach { example => diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/FormatTests.scala b/scalafmt-tests/src/test/scala/org/scalafmt/FormatTests.scala index f025c00742..1bfb265f78 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/FormatTests.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/FormatTests.scala @@ -27,13 +27,10 @@ class FormatTests extends FunSuite with CanRunTests with FormatAssertions { override def ignore(t: DiffTest): Boolean = false override val tests = { - if (onlyManual) ManualTests.tests - else UnitTests.tests + if (onlyManual) ManualTests.tests else UnitTests.tests } - tests - .sortBy(x => (x.loc.path, x.loc.line)) - .withFilter(testShouldRun) + tests.sortBy(x => (x.loc.path, x.loc.line)).withFilter(testShouldRun) .foreach(runTest(run)) def run(t: DiffTest): Unit = { @@ -83,8 +80,7 @@ class FormatTests extends FunSuite with CanRunTests with FormatAssertions { if (onlyManual) { assertEquals(code, obtained, "Idempotency violated") assertObtained - } else if (code == obtained) - assertObtained + } else if (code == obtained) assertObtained else { val diff = new Diff(code, obtained) if (diff.isEmpty) assertObtained @@ -92,25 +88,21 @@ class FormatTests extends FunSuite with CanRunTests with FormatAssertions { val report = AnsiColors.filterAnsi(diff.createDiffOnlyReport()) val eol = if (report.last == '\n') "" else "\n" val error = "Idempotency violated\n" + report + eol - if (error != t.expected) - failComparison(error, code, obtained) + if (error != t.expected) failComparison(error, code, obtained) } } } if ( - result2Either.isRight && - t.style.rewrite.rules.isEmpty && + result2Either.isRight && t.style.rewrite.rules.isEmpty && FormatTokensRewrite.getEnabledFactories(t.style).isEmpty && !t.style.assumeStandardLibraryStripMargin && - !FileOps.isMarkdown(t.filename) && - err.isEmpty + !FileOps.isMarkdown(t.filename) && err.isEmpty + ) assertFormatPreservesAst( + t.filename, + t.original, + obtained, + result.config.runner ) - assertFormatPreservesAst( - t.filename, - t.original, - obtained, - result.config.runner - ) } def testShouldRun(t: DiffTest): Boolean = !onlyOne || t.only @@ -121,12 +113,10 @@ class FormatTests extends FunSuite with CanRunTests with FormatAssertions { // TODO(olafur) don't block printing out test results. // I don't want to deal with scalaz's Tasks :'( val k = for { - _ <- Future( - FileOps.writeFile( - s"target${File.separator}index.html", - Report.heatmap(results) - ) - ) + _ <- Future(FileOps.writeFile( + s"target${File.separator}index.html", + Report.heatmap(results) + )) } yield () // Travis exits right after running tests. if (sys.env.contains("TRAVIS")) Await.ready(k, 20.seconds) diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/LineEndingsTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/LineEndingsTest.scala index cee9d72614..c875170590 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/LineEndingsTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/LineEndingsTest.scala @@ -6,69 +6,51 @@ import org.scalafmt.config.ScalafmtConfig class LineEndingsTest extends FunSuite { - test( - "code with windows line endings after formatting with line endings preserve setting should have the same endings" - ) { + test("code with windows line endings after formatting with line endings preserve setting should have the same endings") { val original = "@ Singleton\r\nobject a {\r\nval y = 2\r\n}" val expected = "@Singleton\r\nobject a {\r\n val y = 2\r\n}\r\n" val obtained = Scalafmt - .format(original, ScalafmtConfig.default.copy(lineEndings = preserve)) - .get + .format(original, ScalafmtConfig.default.copy(lineEndings = preserve)).get assertNoDiff(obtained, expected) } - test( - "code with unix line endings after formatting with line endings preserve setting should have the same endings" - ) { + test("code with unix line endings after formatting with line endings preserve setting should have the same endings") { val original = "@ Singleton\nobject a {\nval y = 2\n}" val expected = "@Singleton\nobject a {\n val y = 2\n}\n" val obtained = Scalafmt - .format(original, ScalafmtConfig.default.copy(lineEndings = preserve)) - .get + .format(original, ScalafmtConfig.default.copy(lineEndings = preserve)).get assertNoDiff(obtained, expected) } - test( - "code with windows line endings after formatting with line endings windows setting should have windows endings" - ) { + test("code with windows line endings after formatting with line endings windows setting should have windows endings") { val original = "@ Singleton\r\nobject a {\r\nval y = 2\r\n}" val expected = "@Singleton\r\nobject a {\r\n val y = 2\r\n}\r\n" val obtained = Scalafmt - .format(original, ScalafmtConfig.default.copy(lineEndings = windows)) - .get + .format(original, ScalafmtConfig.default.copy(lineEndings = windows)).get assertNoDiff(obtained, expected) } - test( - "code with unix line endings after formatting with line endings windows setting should have windows endings" - ) { + test("code with unix line endings after formatting with line endings windows setting should have windows endings") { val original = "@ Singleton\nobject a {\nval y = 2\n}" val expected = "@Singleton\r\nobject a {\r\n val y = 2\r\n}\r\n" val obtained = Scalafmt - .format(original, ScalafmtConfig.default.copy(lineEndings = windows)) - .get + .format(original, ScalafmtConfig.default.copy(lineEndings = windows)).get assertNoDiff(obtained, expected) } - test( - "code with windows line endings after formatting with line endings unix setting should have unix endings" - ) { + test("code with windows line endings after formatting with line endings unix setting should have unix endings") { val original = "@ Singleton\r\nobject a {\r\nval y = 2\r\n}" val expected = "@Singleton\nobject a {\n val y = 2\n}\n" val obtained = Scalafmt - .format(original, ScalafmtConfig.default.copy(lineEndings = unix)) - .get + .format(original, ScalafmtConfig.default.copy(lineEndings = unix)).get assertNoDiff(obtained, expected) } - test( - "code with unix line endings after formatting with line endings unix setting should have unix endings" - ) { + test("code with unix line endings after formatting with line endings unix setting should have unix endings") { val original = "@ Singleton\nobject a {\nval y = 2\n}" val expected = "@Singleton\nobject a {\n val y = 2\n}\n" val obtained = Scalafmt - .format(original, ScalafmtConfig.default.copy(lineEndings = unix)) - .get + .format(original, ScalafmtConfig.default.copy(lineEndings = unix)).get assertNoDiff(obtained, expected) } } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/ManualTests.scala b/scalafmt-tests/src/test/scala/org/scalafmt/ManualTests.scala index 53435f8646..7b52230d63 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/ManualTests.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/ManualTests.scala @@ -14,11 +14,9 @@ object ManualTests extends HasTests { val testPrefix = testDir + File.separator val testFiles = listFiles(testDir).map(x => (x, x.toString)) val manualFiles = for { - (path, filename) <- testFiles - if filename.endsWith(manual) + (path, filename) <- testFiles if filename.endsWith(manual) test <- { - readFile(path).linesIterator - .withFilter(_.startsWith("ONLY")) + readFile(path).linesIterator.withFilter(_.startsWith("ONLY")) .map { name => val testPath = stripPrefix(name) val original = readFile(testPath) @@ -37,8 +35,7 @@ object ManualTests extends HasTests { } } yield test val scalaFiles = for { - (path, filename) <- testFiles - if filename.endsWith(".scala") + (path, filename) <- testFiles if filename.endsWith(".scala") } yield { val content = readFile(path) DiffTest( diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/RangeTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/RangeTest.scala index d5bc0db2a7..7f69f3b499 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/RangeTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/RangeTest.scala @@ -16,11 +16,7 @@ class RangeTest extends FunSuite { |} """.stripMargin val obtained = Scalafmt - .format( - original, - HasTests.unitTest40, - range = Set(Range(2, 2).inclusive) - ) + .format(original, HasTests.unitTest40, range = Set(Range(2, 2).inclusive)) .get assertNoDiff(obtained, expected) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/ScalafmtProps.scala b/scalafmt-tests/src/test/scala/org/scalafmt/ScalafmtProps.scala index 729c511f26..f56fb4e3b0 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/ScalafmtProps.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/ScalafmtProps.scala @@ -18,16 +18,11 @@ class ScalafmtProps extends FunSuite with FormatAssertions { config: ScalafmtConfig = ScalafmtConfig.default, count: Int = Int.MaxValue ): mutable.Seq[(CorpusFile, Observation[Bug])] = { - val corpus = Corpus - .files( - // TODO(olafur) remove once testkit 1.7 is out - Corpus.fastparse.copy( - Corpus.fastparse.url.replace("olafurpg", "scalameta") - ) - ) - .take(count) - .toBuffer - .par + val corpus = Corpus.files( + // TODO(olafur) remove once testkit 1.7 is out + Corpus.fastparse + .copy(Corpus.fastparse.url.replace("olafurpg", "scalameta")) + ).take(count).toBuffer.par SyntaxAnalysis.run[Observation[Bug]](corpus) { file => val code = file.read try { @@ -37,8 +32,7 @@ class ScalafmtProps extends FunSuite with FormatAssertions { val formattedSecondTime = Scalafmt.format(formatted, config).get try assertNoDiff(formattedSecondTime, formatted, "Idempotence") catch { - case diff: FailException => - throw DiffFailure( + case diff: FailException => throw DiffFailure( "Idempotence", formatted, formattedSecondTime, @@ -56,48 +50,31 @@ class ScalafmtProps extends FunSuite with FormatAssertions { } catch { case e: Error.FormatterChangedAST => List(Observation(e.getMessage, -1, AstChanged)) - case e: Error.FormatterOutputDoesNotParse => - List( - Observation( - e.getMessage.linesIterator.slice(1, 2).mkString(""), - e.line, - FormattedOutputDoesNotParse - ) - ) - case e: Error => - List(Observation(e.getMessage, -1, Unknown(e))) + case e: Error.FormatterOutputDoesNotParse => List(Observation( + e.getMessage.linesIterator.slice(1, 2).mkString(""), + e.line, + FormattedOutputDoesNotParse + )) + case e: Error => List(Observation(e.getMessage, -1, Unknown(e))) case e: DiffFailure => - val line = e.obtained.linesIterator - .zip(e.expected.linesIterator) - .takeWhile { case (a, b) => a == b } - .length - List( - Observation( - e.diff.linesIterator.take(3).mkString("\n"), - line, - NonIdempotent - ) - ) + val line = e.obtained.linesIterator.zip(e.expected.linesIterator) + .takeWhile { case (a, b) => a == b }.length + List(Observation( + e.diff.linesIterator.take(3).mkString("\n"), + line, + NonIdempotent + )) } } } def printReport(bugs: List[(CorpusFile, Observation[Bug])]): Unit = { val table = Observation.markdownTable(bugs) - val summary = - bugs - .groupBy(_._2.kind.toString) - .mapValues(_.length) - .toSeq - .sortBy(_._2) - .map { case (a, b) => - s"$a=$b" - } - .mkString("\n") - val report = - s"""|$summary - | - |$table """.stripMargin + val summary = bugs.groupBy(_._2.kind.toString).mapValues(_.length).toSeq + .sortBy(_._2).map { case (a, b) => s"$a=$b" }.mkString("\n") + val report = s"""|$summary + | + |$table """.stripMargin logger.elem(summary) logger.elem(report) logger.elem(summary) diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/ScalafmtRunnerTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/ScalafmtRunnerTest.scala index 6e05c90801..7d62ed5b3c 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/ScalafmtRunnerTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/ScalafmtRunnerTest.scala @@ -6,19 +6,16 @@ import munit.FunSuite class ScalafmtRunnerTest extends FunSuite { test("sbt dialect supports trailing commas") { - ScalafmtRunner.sbt - .getDialect( - """ - |lazy - |val x = project( - | a, - | - | - | b, - |) + ScalafmtRunner.sbt.getDialect( + """ + |lazy + |val x = project( + | a, + | + | + | b, + |) """.stripMargin - ) - .parse[Source] - .get + ).parse[Source].get } } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/UnitTests.scala b/scalafmt-tests/src/test/scala/org/scalafmt/UnitTests.scala index bab009a47f..dc2af6e720 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/UnitTests.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/UnitTests.scala @@ -10,11 +10,10 @@ object UnitTests extends HasTests { /** Avoids parsing all files if some tests are marked ONLY. */ def getTestFiles: Seq[String] = { - val testsFiles = - listFiles(testDir).map(_.toString).filter(filename2parse(_).isDefined) + val testsFiles = listFiles(testDir).map(_.toString) + .filter(filename2parse(_).isDefined) val onlyTests = testsFiles.filter(_.contains("\n<<< ONLY")) - if (onlyTests.nonEmpty) onlyTests - else testsFiles + if (onlyTests.nonEmpty) onlyTests else testsFiles } // TODO(olafur) make possible to limit states per unit test. diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/cli/CliOptionsTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/cli/CliOptionsTest.scala index b1894e7bb8..82023eaf5d 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/cli/CliOptionsTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/cli/CliOptionsTest.scala @@ -42,17 +42,11 @@ class CliOptionsTest extends FunSuite { ) } - test( - ".configPath returns a path to the temporary file that contains configuration specified by --config-str" - ) { + test(".configPath returns a path to the temporary file that contains configuration specified by --config-str") { val expected = "foo bar" val path: Path = baseCliOptions - .copy( - configStr = Some( - s"""{version="${Versions.version}", onTestFailure="$expected"}""" - ) - ) - .configPath + .copy(configStr = Some(s"""{version="${Versions + .version}", onTestFailure="$expected"}""")).configPath val config = ScalafmtConfig.fromHoconFile(path).get assertEquals(config.onTestFailure, expected) } @@ -63,28 +57,20 @@ class CliOptionsTest extends FunSuite { assertEquals(opt.configPath, tempPath) } - test( - ".configPath returns path to workingDirectory's .scalafmt.conf by default, if exists" - ) { + test(".configPath returns path to workingDirectory's .scalafmt.conf by default, if exists") { assertEquals(baseCliOptions.config, None) assertEquals(baseCliOptions.configStr, None) intercept[NoSuchFileException](baseCliOptions.configPath) } - test( - ".scalafmtConfig returns the configuration encoded from configStr if configStr is exists" - ) { + test(".scalafmtConfig returns the configuration encoded from configStr if configStr is exists") { val expected = "foo bar" - val opt = baseCliOptions.copy( - configStr = - Some(s"""{version="${Versions.version}", onTestFailure="$expected"}""") - ) + val opt = baseCliOptions.copy(configStr = Some(s"""{version="${Versions + .version}", onTestFailure="$expected"}""")) assertEquals(opt.scalafmtConfig.get.onTestFailure, expected) } - test( - ".scalafmtConfig returns the configuration read from configuration file located on configPath" - ) { + test(".scalafmtConfig returns the configuration read from configuration file located on configPath") { val expected = "foo bar" val configPath = Files.createTempFile(".scalafmt", ".conf") val config = s""" @@ -98,9 +84,7 @@ class CliOptionsTest extends FunSuite { assertEquals(opt.scalafmtConfig.get.onTestFailure, expected) } - test( - ".scalafmtConfig returns default ScalafmtConfig if configuration file is missing" - ) { + test(".scalafmtConfig returns default ScalafmtConfig if configuration file is missing") { val configDir = Files.createTempDirectory("temp-dir") val configPath = Paths.get(configDir.toString + "/.scalafmt.conf") val opt = baseCliOptions.copy(config = Some(configPath)) @@ -111,11 +95,8 @@ class CliOptionsTest extends FunSuite { test(".scalafmtConfig returns Configured.NotOk for invalid configuration") { val expected = "foo bar" - val opt = baseCliOptions.copy( - configStr = Some( - s"""{invalidKey="${Versions.version}", onTestFailure="$expected"}""" - ) - ) + val opt = baseCliOptions.copy(configStr = Some(s"""{invalidKey="${Versions + .version}", onTestFailure="$expected"}""")) assert(opt.scalafmtConfig.isNotOk) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/cli/CliTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/cli/CliTest.scala index c02cc2d3f9..6b9d2ae828 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/cli/CliTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/cli/CliTest.scala @@ -19,8 +19,7 @@ import org.scalafmt.sysops.{AbsoluteFile, FileOps} import org.scalafmt.sysops.OsSpecific._ abstract class AbstractCliTest extends FunSuite { - def mkArgs(str: String): Array[String] = - str.split(' ') + def mkArgs(str: String): Array[String] = str.split(' ') def runWith(root: AbsoluteFile, argStr: String): Unit = runArgs(mkArgs(argStr), getMockOptions(root)) @@ -29,8 +28,7 @@ abstract class AbstractCliTest extends FunSuite { args: Array[String], init: CliOptions = baseCliOptions, exitCode: ExitCode = ExitCode.Ok - ): Unit = - run(Cli.getConfig(args, init).get, exitCode) + ): Unit = run(Cli.getConfig(args, init).get, exitCode) def run(options: CliOptions, exitCode: ExitCode = ExitCode.Ok) = assertEquals(Cli.run(options), exitCode) @@ -63,24 +61,21 @@ abstract class AbstractCliTest extends FunSuite { | pr("h") |} |""".stripMargin - val customConfig = - """ - |maxColumn = 2 + val customConfig = """ + |maxColumn = 2 """.stripMargin - val sbtOriginal = - """|lazy val x = project - | lazy val y = project - | """.stripMargin - - val sbtExpected = - """|lazy val x = - | project - |lazy val y = - | project - |""".stripMargin + val sbtOriginal = """|lazy val x = project + | lazy val y = project + | """.stripMargin + + val sbtExpected = """|lazy val x = + | project + |lazy val y = + | project + |""".stripMargin - def gimmeConfig(string: String): ScalafmtConfig = - ScalafmtConfig.fromHoconString(string).get + def gimmeConfig(string: String): ScalafmtConfig = ScalafmtConfig + .fromHoconString(string).get def noArgTest( input: AbsoluteFile, @@ -106,7 +101,8 @@ abstract class AbstractCliTest extends FunSuite { } -trait CliTestBehavior { this: AbstractCliTest => +trait CliTestBehavior { + this: AbstractCliTest => def testCli(version: String): Unit = { val isCore = version == stableVersion val label = if (isCore) "core" else "dynamic" @@ -147,9 +143,8 @@ trait CliTestBehavior { this: AbstractCliTest => ) val baos = new ByteArrayOutputStream() val ps = new PrintStream(baos) - val init = baseCliOptions.copy( - common = baseCliOptions.common.copy(out = ps) - ) + val init = baseCliOptions + .copy(common = baseCliOptions.common.copy(out = ps)) runArgs(args, init) val obtained = new String(baos.toByteArray, StandardCharsets.UTF_8) assertNoDiff(obtained, formatted) @@ -232,23 +227,20 @@ trait CliTestBehavior { this: AbstractCliTest => |lazy val x = project |""".stripMargin ) - val expected = - s"""|/foo.sbt - |lazy val x = project - | - |/foo.sc - |lazy val x = project - | - |/foobar.scala - |object A {} - |""".stripMargin - runArgs( - Array( - input.toString(), - "--config-str", - s"""{version="$version",style=IntelliJ}""" - ) - ) + val expected = s"""|/foo.sbt + |lazy val x = project + | + |/foo.sc + |lazy val x = project + | + |/foobar.scala + |object A {} + |""".stripMargin + runArgs(Array( + input.toString(), + "--config-str", + s"""{version="$version",style=IntelliJ}""" + )) val obtained = dir2string(input) assertNoDiff(obtained, expected) } @@ -271,31 +263,28 @@ trait CliTestBehavior { this: AbstractCliTest => |object CIgnoreME { } |""".stripMargin ) - val expected = - s"""|/foo.sbt - |lazy val x = project - | - |/target/FormatMe.scala - |object PleaseFormatMeOtherwiseIWillBeReallySad {} - | - |/target/nested1/DoNotFormatMe.scala - |object AAAAAAIgnoreME { } - | - |/target/nested1/nested2/DoNotFormatMeToo.scala - |object BBBBBBIgnoreME { } - | - |/target/nested3/DoNotFormatMe.scala - |object CIgnoreME { } - |""".stripMargin - runArgs( - Array( - "--config-str", - s"""{version="$version",style=IntelliJ}""", - input.toString(), - "--exclude", - "target/nested".asFilename - ) - ) + val expected = s"""|/foo.sbt + |lazy val x = project + | + |/target/FormatMe.scala + |object PleaseFormatMeOtherwiseIWillBeReallySad {} + | + |/target/nested1/DoNotFormatMe.scala + |object AAAAAAIgnoreME { } + | + |/target/nested1/nested2/DoNotFormatMeToo.scala + |object BBBBBBIgnoreME { } + | + |/target/nested3/DoNotFormatMe.scala + |object CIgnoreME { } + |""".stripMargin + runArgs(Array( + "--config-str", + s"""{version="$version",style=IntelliJ}""", + input.toString(), + "--exclude", + "target/nested".asFilename + )) val obtained = dir2string(input) assertNoDiff(obtained, expected) @@ -324,31 +313,21 @@ trait CliTestBehavior { this: AbstractCliTest => """.stripMargin Files.write(scalafmtConfig, config.getBytes) val options = baseCliOptions.copy(config = Some(scalafmtConfig)) - intercept[NoMatchingFiles.type] { - Cli.run(options) - } + intercept[NoMatchingFiles.type] { Cli.run(options) } } - test( - s"scalafmt (no matching files) is okay with --mode diff and --stdin: $label" - ) { - runArgs( - Array( - "--mode", - "diff", - "--config-str", - s"""{version="$version",style=IntelliJ}""" - ) - ) - val stdin = getConfig( - Array( - "--stdin", - "--config-str", - s"""{version="$version",style=IntelliJ}""" - ) - ).copy( - common = CommonOptions(in = new ByteArrayInputStream("".getBytes)) - ) + test(s"scalafmt (no matching files) is okay with --mode diff and --stdin: $label") { + runArgs(Array( + "--mode", + "diff", + "--config-str", + s"""{version="$version",style=IntelliJ}""" + )) + val stdin = getConfig(Array( + "--stdin", + "--config-str", + s"""{version="$version",style=IntelliJ}""" + )).copy(common = CommonOptions(in = new ByteArrayInputStream("".getBytes))) run(stdin) } @@ -368,26 +347,21 @@ trait CliTestBehavior { this: AbstractCliTest => |""".stripMargin ) - val expected = - s"""|/.scalafmt.conf - |version = "$version" - |maxColumn = 2 - |project.excludeFilters = [target] - | - |/foo.scala - |object FormatMe { - | val x = - | 1 - |} - | - |/target/foo.scala - |object A { } - |""".stripMargin - noArgTest( - input, - expected, - Seq(Array.empty[String], Array("--mode", "diff")) - ) + val expected = s"""|/.scalafmt.conf + |version = "$version" + |maxColumn = 2 + |project.excludeFilters = [target] + | + |/foo.scala + |object FormatMe { + | val x = + | 1 + |} + | + |/target/foo.scala + |object A { } + |""".stripMargin + noArgTest(input, expected, Seq(Array.empty[String], Array("--mode", "diff"))) } test(s"scalafmt (no arg, no config): $label") { @@ -405,20 +379,17 @@ trait CliTestBehavior { this: AbstractCliTest => |/foo.scala |object FormatMe |""".stripMargin, - Seq( - Array("--config-str", s"""{version="$version"}""") - ) + Seq(Array("--config-str", s"""{version="$version"}""")) ) } test(s"config is read even from nested dir: $label") { val original = "object a { val x = 1 }" - val expected = - """|object a { - | val x = - | 1 - |} - |""".stripMargin + val expected = """|object a { + | val x = + | 1 + |} + |""".stripMargin val input = string2dir( s"""|/nested/foo.scala |$original @@ -437,24 +408,21 @@ trait CliTestBehavior { this: AbstractCliTest => assertNoDiff(obtained, expected) } - test( - s"if project.includeFilters isn't modified (and files aren't passed manually), it should ONLY accept scala and sbt files: $label" - ) { - val root = - string2dir( - s""" - |/scalafmt.conf - |style = default - |version="$version" - |/scalafile.scala - |$unformatted - |/scalatex.scalatex - |$unformatted - |/sbt.sbt - |$sbtOriginal - |/sbt.sbtfile - |$sbtOriginal""".stripMargin - ) + test(s"if project.includeFilters isn't modified (and files aren't passed manually), it should ONLY accept scala and sbt files: $label") { + val root = string2dir( + s""" + |/scalafmt.conf + |style = default + |version="$version" + |/scalafile.scala + |$unformatted + |/scalatex.scalatex + |$unformatted + |/sbt.sbt + |$sbtOriginal + |/sbt.sbtfile + |$sbtOriginal""".stripMargin + ) val config = root / "scalafmt.conf" runWith(root, s"--config $config") @@ -463,37 +431,32 @@ trait CliTestBehavior { this: AbstractCliTest => assertNoDiff(dir2string(root / "sbt.sbtfile"), sbtOriginal) assertNoDiff(dir2string(root / "scalafile.scala"), formatted) - val sbtFormatted = - """|lazy val x = project - |lazy val y = project - |""".stripMargin + val sbtFormatted = """|lazy val x = project + |lazy val y = project + |""".stripMargin assertNoDiff(dir2string(root / "sbt.sbt"), sbtFormatted) } - test( - s"includeFilters are ignored for full paths but NOT test for passed directories: $label" - ) { - val root = - string2dir( - s""" - |/inner1/file1.scala - |$unformatted - |/inner2/file2.scalahala - |$unformatted - |/inner3/file1.scala - |$unformatted - |/inner3/file2.scalahala - |$unformatted""".stripMargin - ) + test(s"includeFilters are ignored for full paths but NOT test for passed directories: $label") { + val root = string2dir( + s""" + |/inner1/file1.scala + |$unformatted + |/inner2/file2.scalahala + |$unformatted + |/inner3/file1.scala + |$unformatted + |/inner3/file2.scalahala + |$unformatted""".stripMargin + ) val inner1 = root / "inner1" val inner2 = root / "inner2" val inner3 = root / "inner3" val full1 = inner3 / "file1.scala" val full2 = inner3 / "file2.scalahala" - val opts = Seq( - s"""--config-str {version="$version"}""" - ) ++ Seq(inner1, inner2, full1, full2) + val opts = Seq(s"""--config-str {version="$version"}""") ++ + Seq(inner1, inner2, full1, full2) runWith(root, opts.mkString(" ")) assertNoDiff(dir2string(inner1 / "file1.scala"), formatted) @@ -502,21 +465,18 @@ trait CliTestBehavior { this: AbstractCliTest => assertNoDiff(dir2string(full2), formatted) } - test( - s"includeFilters are respected for full paths but NOT test for passed directories: $label" - ) { - val root = - string2dir( - s""" - |/inner1/file1.scala - |$unformatted - |/inner2/file2.scalahala - |$unformatted - |/inner3/file1.scala - |$unformatted - |/inner3/file2.scalahala - |$unformatted""".stripMargin - ) + test(s"includeFilters are respected for full paths but NOT test for passed directories: $label") { + val root = string2dir( + s""" + |/inner1/file1.scala + |$unformatted + |/inner2/file2.scalahala + |$unformatted + |/inner3/file1.scala + |$unformatted + |/inner3/file2.scalahala + |$unformatted""".stripMargin + ) val inner1 = root / "inner1" val inner2 = root / "inner2" val inner3 = root / "inner3" @@ -546,11 +506,7 @@ trait CliTestBehavior { this: AbstractCliTest => ) val config = (root / "scalafmt.conf").toString() val toFormat = (root / "foo.scala").toString() - val args = Array[String]( - "--config", - config, - toFormat - ) + val args = Array[String]("--config", config, toFormat) Cli.exceptionThrowingMainWithOptions(args, baseCliOptions) val obtained = FileOps.readFile(toFormat) assertNoDiff(obtained, "object A\n") @@ -582,19 +538,13 @@ trait CliTestBehavior { this: AbstractCliTest => } test(s"parse error is formatted nicely: $label") { - val input = - """|/foo.scala - |object A { foo( } - |""".stripMargin + val input = """|/foo.scala + |object A { foo( } + |""".stripMargin noArgTest( string2dir(input), input, - Seq( - Array( - "--config-str", - s"""{version="$version",style=IntelliJ}""" - ) - ), + Seq(Array("--config-str", s"""{version="$version",style=IntelliJ}""")), ExitCode.ParseError, assertOut = out => { assertContains( @@ -620,14 +570,13 @@ trait CliTestBehavior { this: AbstractCliTest => test(s"--test failure prints out unified diff: $label") { val fooFile = "foo.scala" - val input = - s"""|/.scalafmt.conf - |onTestFailure = "To fix this ..." - |version = "$version" - | - |/$fooFile - |object A { } - |""".stripMargin + val input = s"""|/.scalafmt.conf + |onTestFailure = "To fix this ..." + |version = "$version" + | + |/$fooFile + |object A { } + |""".stripMargin val dir = string2dir(input) val fooPath = dir / fooFile noArgTest( @@ -650,10 +599,9 @@ trait CliTestBehavior { this: AbstractCliTest => } test(s"--test succeeds even with parse error: $label") { - val input = - """|/foo.scala - |object A { - |""".stripMargin + val input = """|/foo.scala + |object A { + |""".stripMargin noArgTest( string2dir(input), input, @@ -661,8 +609,7 @@ trait CliTestBehavior { this: AbstractCliTest => assertOut = out => { assert( out.contains(s"foo.scala:2: error:$dialectError") && - out.contains("end of file") && - out.contains("error: ParseError=2"), + out.contains("end of file") && out.contains("error: ParseError=2"), out ) } @@ -670,13 +617,12 @@ trait CliTestBehavior { this: AbstractCliTest => } test(s"--test fails with parse error if fatalWarnings=true: $label") { - val input = - s"""|/.scalafmt.conf - |runner.fatalWarnings = true - |version = "$version" - |/foo.scala - |object A { - |""".stripMargin + val input = s"""|/.scalafmt.conf + |runner.fatalWarnings = true + |version = "$version" + |/foo.scala + |object A { + |""".stripMargin noArgTest( string2dir(input), input, @@ -685,8 +631,7 @@ trait CliTestBehavior { this: AbstractCliTest => assertOut = out => { assert( out.contains(s"foo.scala:2: error:$dialectError") && - out.contains(s"end of file") && - out.contains("error: ParseError=2"), + out.contains(s"end of file") && out.contains("error: ParseError=2"), out ) } @@ -694,12 +639,11 @@ trait CliTestBehavior { this: AbstractCliTest => } test(s"exception is thrown on invalid .scalafmt.conf: $label") { - val input = - s"""/.scalafmt.conf - |version="$version" - |blah = intellij - |/foo.scala - |object A {} + val input = s"""/.scalafmt.conf + |version="$version" + |blah = intellij + |/foo.scala + |object A {} """.stripMargin noArgTest( string2dir(input), @@ -729,50 +673,40 @@ trait CliTestBehavior { this: AbstractCliTest => test(s"--config-str should be used if it is specified: $label") { val expected = "This message should be shown" val unexpected = "This message should not be shown" - val input = - s"""|/.scalafmt.conf - |onTestFailure = "$unexpected" - |version = "$version" - | - |/foo.scala - |object A { } - |""".stripMargin + val input = s"""|/.scalafmt.conf + |onTestFailure = "$unexpected" + |version = "$version" + | + |/foo.scala + |object A { } + |""".stripMargin noArgTest( string2dir(input), input, - Seq( - Array( - "--config-str", - s"""{version="$version",onTestFailure="$expected"}""", - "--test" - ) - ), + Seq(Array( + "--config-str", + s"""{version="$version",onTestFailure="$expected"}""", + "--test" + )), ExitCode.TestError, - assertOut = out => { - assert( - out.contains(expected) && - !out.contains(unexpected) - ) - } + assertOut = + out => { assert(out.contains(expected) && !out.contains(unexpected)) } ) } - test( - s"--list enable scalafmt to output a list of unformatted files with ExitCode.TestError: $label" - ) { - val input = - s"""|/.scalafmt.conf - |version = "$version" - | - |/bar.scala - |object A { } - | - |/baz.scala - |object A {} - | - |/dir/foo.scala - |object A { } - |""".stripMargin + test(s"--list enable scalafmt to output a list of unformatted files with ExitCode.TestError: $label") { + val input = s"""|/.scalafmt.conf + |version = "$version" + | + |/bar.scala + |object A { } + | + |/baz.scala + |object A {} + | + |/dir/foo.scala + |object A { } + |""".stripMargin val dir = string2dir(input) noArgTest( dir, @@ -781,8 +715,7 @@ trait CliTestBehavior { this: AbstractCliTest => ExitCode.TestError, assertOut = out => { assert( - out.contains("bar.scala") && - !out.contains("baz.scala") && + out.contains("bar.scala") && !out.contains("baz.scala") && out.contains("dir/foo.scala") ) } @@ -796,16 +729,15 @@ class CliTest extends AbstractCliTest with CliTestBehavior { testCli(stableVersion) // test for runScalafmt test(s"path-error") { - val input = - s"""|/.scalafmt.conf - |version = "${stableVersion}" - |project.excludePaths = [ - | "glob:**/src/main/scala/besom/rpc/**.scala", - | "foo.scala" - |] - |/foo.scala - |object A { foo( } - |""".stripMargin + val input = s"""|/.scalafmt.conf + |version = "${stableVersion}" + |project.excludePaths = [ + | "glob:**/src/main/scala/besom/rpc/**.scala", + | "foo.scala" + |] + |/foo.scala + |object A { foo( } + |""".stripMargin noArgTest( string2dir(input), @@ -824,15 +756,14 @@ class CliTest extends AbstractCliTest with CliTestBehavior { } test(s"regex-error") { - val input = - s"""|/.scalafmt.conf - |version = "${stableVersion}" - |project.excludeFilters = [ - | ".*foo(" - |] - |/foo.scala - |object A { foo( } - |""".stripMargin + val input = s"""|/.scalafmt.conf + |version = "${stableVersion}" + |project.excludeFilters = [ + | ".*foo(" + |] + |/foo.scala + |object A { foo( } + |""".stripMargin noArgTest( string2dir(input), @@ -854,17 +785,14 @@ class CliTest extends AbstractCliTest with CliTestBehavior { } test("Fail if .scalafmt.conf is missing.") { - val input = - s"""|/foo.scala - |object A {} - |""".stripMargin + val input = s"""|/foo.scala + |object A {} + |""".stripMargin noArgTest( string2dir(input), input, Seq( - Array( - "--debug" - ) // debug options is needed to output running scalafmt version + Array("--debug") // debug options is needed to output running scalafmt version ), ExitCode.UnsupportedVersion, assertOut = out => { @@ -878,20 +806,17 @@ class CliTest extends AbstractCliTest with CliTestBehavior { } test("Fail if `version` setting is missing.") { - val input = - s"""|/.scalafmt.conf - |maxColumn = 10 - | - |/foo.scala - |object A {} - |""".stripMargin + val input = s"""|/.scalafmt.conf + |maxColumn = 10 + | + |/foo.scala + |object A {} + |""".stripMargin noArgTest( string2dir(input), input, Seq( - Array( - "--debug" - ) // debug options is needed to output running scalafmt version + Array("--debug") // debug options is needed to output running scalafmt version ), ExitCode.UnsupportedVersion, assertOut = out => { @@ -910,14 +835,11 @@ class CliTest extends AbstractCliTest with CliTestBehavior { val arguments = List("--config", configFile.toString, "foobar.scala") Files.write(argumentsFile, arguments.asJava) Files.write(configFile, List("maxColumn=40").asJava) - val obtained = - Cli.getConfig(Array(s"@$argumentsFile"), CliTest.defaultOptions).get + val obtained = Cli + .getConfig(Array(s"@$argumentsFile"), CliTest.defaultOptions).get val config = obtained.scalafmtConfig.get assertEquals(config.maxColumn, 40) - assertEquals( - obtained.customFiles.head.getFileName.toString, - "foobar.scala" - ) + assertEquals(obtained.customFiles.head.getFileName.toString, "foobar.scala") } test("can't specify both --config and --config-str") { @@ -952,26 +874,21 @@ class CliTest extends AbstractCliTest with CliTestBehavior { |""".stripMargin ) - val expected = - s"""|/.scalafmt.conf - |version = $stableVersion - |maxColumn = 2 - |project { includePaths = ["glob:**/bar.scala"] } - | - |/bar.scala - |object FormatMe { - | val x = - | 1 - |} - | - |/target/foo.scala - |object A { } - |""".stripMargin - noArgTest( - input, - expected, - Seq(Array.empty[String], Array("--mode", "diff")) - ) + val expected = s"""|/.scalafmt.conf + |version = $stableVersion + |maxColumn = 2 + |project { includePaths = ["glob:**/bar.scala"] } + | + |/bar.scala + |object FormatMe { + | val x = + | 1 + |} + | + |/target/foo.scala + |object A { } + |""".stripMargin + noArgTest(input, expected, Seq(Array.empty[String], Array("--mode", "diff"))) } test(s"scalafmt use excludePaths") { @@ -991,26 +908,21 @@ class CliTest extends AbstractCliTest with CliTestBehavior { |""".stripMargin ) - val expected = - s"""|/.scalafmt.conf - |version = $stableVersion - |maxColumn = 2 - |project { excludePaths = ["glob:**target**"] } - | - |/foo.scala - |object FormatMe { - | val x = - | 1 - |} - | - |/target/foo.scala - |object A { } - |""".stripMargin - noArgTest( - input, - expected, - Seq(Array.empty[String], Array("--mode", "diff")) - ) + val expected = s"""|/.scalafmt.conf + |version = $stableVersion + |maxColumn = 2 + |project { excludePaths = ["glob:**target**"] } + | + |/foo.scala + |object FormatMe { + | val x = + | 1 + |} + | + |/target/foo.scala + |object A { } + |""".stripMargin + noArgTest(input, expected, Seq(Array.empty[String], Array("--mode", "diff"))) } test(s"scalafmt: includeFilters overrides default includePaths") { @@ -1030,31 +942,26 @@ class CliTest extends AbstractCliTest with CliTestBehavior { |""".stripMargin ) - val expected = - s"""|/.scalafmt.conf - |version = $stableVersion - |maxColumn = 2 - |project { includeFilters = ["bar"] } - | - |/bar.scala - |object FormatMe { - | val x = - | 1 - |} - | - |/target/foo.scala - |object A { } - |""".stripMargin - noArgTest( - input, - expected, - Seq(Array.empty[String], Array("--mode", "diff")) - ) + val expected = s"""|/.scalafmt.conf + |version = $stableVersion + |maxColumn = 2 + |project { includeFilters = ["bar"] } + | + |/bar.scala + |object FormatMe { + | val x = + | 1 + |} + | + |/target/foo.scala + |object A { } + |""".stripMargin + noArgTest(input, expected, Seq(Array.empty[String], Array("--mode", "diff"))) } test(s"scalafmt: includeFilters with explicit includePaths") { - val defaultIncludePathsJson = - ProjectFiles.defaultIncludePaths.mkString("[\"", "\", \"", "\"]") + val defaultIncludePathsJson = ProjectFiles.defaultIncludePaths + .mkString("[\"", "\", \"", "\"]") val input = string2dir( s"""|/bar.scala |object FormatMe { @@ -1074,29 +981,24 @@ class CliTest extends AbstractCliTest with CliTestBehavior { |""".stripMargin ) - val expected = - s"""|/.scalafmt.conf - |version = $stableVersion - |maxColumn = 2 - |project { - | includePaths = $defaultIncludePathsJson - | includeFilters = ["bar"] - |} - | - |/bar.scala - |object FormatMe { - | val x = - | 1 - |} - | - |/target/foo.scala - |object A {} - |""".stripMargin - noArgTest( - input, - expected, - Seq(Array.empty[String], Array("--mode", "diff")) - ) + val expected = s"""|/.scalafmt.conf + |version = $stableVersion + |maxColumn = 2 + |project { + | includePaths = $defaultIncludePathsJson + | includeFilters = ["bar"] + |} + | + |/bar.scala + |object FormatMe { + | val x = + | 1 + |} + | + |/target/foo.scala + |object A {} + |""".stripMargin + noArgTest(input, expected, Seq(Array.empty[String], Array("--mode", "diff"))) } test(s"handles .md files when present in includePaths") { @@ -1117,31 +1019,26 @@ class CliTest extends AbstractCliTest with CliTestBehavior { |project.includePaths."+" = ["glob:**.md"] |""".stripMargin ) - val expected = - s"""| - |/.scalafmt.conf - |version = $stableVersion - |maxColumn = 8 - |project.includePaths."+" = ["glob:**.md"] - | - |/foobar.md - |# Hello - |Example usage 1 with long spaced line - |```scala mdoc - |val x = - | 42 - |``` - |Example usage 2 - |```java - |val x = 42 - |``` - |""".stripMargin + val expected = s"""| + |/.scalafmt.conf + |version = $stableVersion + |maxColumn = 8 + |project.includePaths."+" = ["glob:**.md"] + | + |/foobar.md + |# Hello + |Example usage 1 with long spaced line + |```scala mdoc + |val x = + | 42 + |``` + |Example usage 2 + |```java + |val x = 42 + |``` + |""".stripMargin - noArgTest( - input, - expected, - Seq(Array.empty[String], Array("--mode", "diff")) - ) + noArgTest(input, expected, Seq(Array.empty[String], Array("--mode", "diff"))) } test(s"ignores .md files if not present in includePaths") { @@ -1156,31 +1053,22 @@ class CliTest extends AbstractCliTest with CliTestBehavior { |version = $stableVersion |""".stripMargin ) - val expected = - s"""| - |/.scalafmt.conf - |version = $stableVersion - | - |/foobar.md - |# Hello - |Example usage 1 - |```scala mdoc - |val x = 42 - |``` - |""".stripMargin + val expected = s"""| + |/.scalafmt.conf + |version = $stableVersion + | + |/foobar.md + |# Hello + |Example usage 1 + |```scala mdoc + |val x = 42 + |``` + |""".stripMargin try { - noArgTest( - input, - expected, - Seq(Array.empty[String], Array("--mode", "diff")) - ) - fail( - "Should have thrown noMatchingFiles because our markdown file was skipped" - ) - } catch { - case _: org.scalafmt.Error.NoMatchingFiles.type => () - } + noArgTest(input, expected, Seq(Array.empty[String], Array("--mode", "diff"))) + fail("Should have thrown noMatchingFiles because our markdown file was skipped") + } catch { case _: org.scalafmt.Error.NoMatchingFiles.type => () } } test(s"handles .md with normal comment that contains a nested fence") { @@ -1198,26 +1086,23 @@ class CliTest extends AbstractCliTest with CliTestBehavior { |``` |""".stripMargin ) - val expected = - s"""|/foobar.md - | Intro - |```scala mdoc - |object A { - | /* - | * ```scala mdoc - | * val example = "text" - | * ``` - | */ - |} - |``` - |""".stripMargin - runArgs( - Array( - input.toString(), - "--config-str", - s"""{version = "$stableVersion", project.includePaths."+" = ["glob:**.md"]}""" - ) - ) + val expected = s"""|/foobar.md + | Intro + |```scala mdoc + |object A { + | /* + | * ```scala mdoc + | * val example = "text" + | * ``` + | */ + |} + |``` + |""".stripMargin + runArgs(Array( + input.toString(), + "--config-str", + s"""{version = "$stableVersion", project.includePaths."+" = ["glob:**.md"]}""" + )) val obtained = dir2string(input) assertNoDiff(obtained, expected) } @@ -1232,20 +1117,17 @@ class CliTest extends AbstractCliTest with CliTestBehavior { | ``` |""".stripMargin ) - val expected = - s"""|/foobar2.md - | Intro text: - | ```scala mdoc - | object A {} - | ``` - |""".stripMargin - runArgs( - Array( - input.toString(), - "--config-str", - s"""{version = "$stableVersion", project.includePaths."+" = ["glob:**.md"]}""" - ) - ) + val expected = s"""|/foobar2.md + | Intro text: + | ```scala mdoc + | object A {} + | ``` + |""".stripMargin + runArgs(Array( + input.toString(), + "--config-str", + s"""{version = "$stableVersion", project.includePaths."+" = ["glob:**.md"]}""" + )) val obtained = dir2string(input) assertNoDiff(obtained, expected) } @@ -1265,18 +1147,17 @@ class CliTest extends AbstractCliTest with CliTestBehavior { |``` |""".stripMargin ) - val expected = - s"""|/foobar.md - |```scala mdoc - |object A { - | /* - |```scala mdoc - | val example = "text" - |``` - | */ - | } - |``` - |""".stripMargin + val expected = s"""|/foobar.md + |```scala mdoc + |object A { + | /* + |```scala mdoc + | val example = "text" + |``` + | */ + | } + |``` + |""".stripMargin runArgs( Array( input.toString(), @@ -1307,41 +1188,35 @@ class CliTest extends AbstractCliTest with CliTestBehavior { |project.includePaths."+" = ["glob:**.md"] |""".stripMargin ) - val expected = - s"""| - |/.scalafmt.conf - |version = $stableVersion - |maxColumn = 8 - |project.includePaths."+" = ["glob:**.md"] - | - |/foobar.md - |# Hello - |Example usage 1 with long spaced line - |```scala mdoc - |val x = - | 42 - |````` - |Example usage 2 - |```java - |val x = 42 - |``` - |""".stripMargin + val expected = s"""| + |/.scalafmt.conf + |version = $stableVersion + |maxColumn = 8 + |project.includePaths."+" = ["glob:**.md"] + | + |/foobar.md + |# Hello + |Example usage 1 with long spaced line + |```scala mdoc + |val x = + | 42 + |````` + |Example usage 2 + |```java + |val x = 42 + |``` + |""".stripMargin - noArgTest( - input, - expected, - Seq(Array.empty[String], Array("--mode", "diff")) - ) + noArgTest(input, expected, Seq(Array.empty[String], Array("--mode", "diff"))) } test("no final EOL") { val out = new ByteArrayOutputStream() val err = new ByteArrayOutputStream() - val codeNoEol = - """|object FormatMe { - | val x = - | 1 - |}""".stripMargin + val codeNoEol = """|object FormatMe { + | val x = + | 1 + |}""".stripMargin Console.withOut(out) { Console.withErr(err) { val options = getConfig(Array("--stdin", "--test")) @@ -1356,10 +1231,7 @@ class CliTest extends AbstractCliTest with CliTestBehavior { run(options2, ExitCode.TestError) } } - assertEquals( - CliTest.stripCR(out.toString), - "error: --test failed\n" - ) + assertEquals(CliTest.stripCR(out.toString), "error: --test failed\n") assertEquals( CliTest.stripCR(err.toString), """--- astdin.scala @@ -1380,7 +1252,7 @@ object CliTest { if (eol == "\n") identity else _.replace(eol, "\n") } - val defaultOptions = - CliOptions.default.copy(baseConfig = ScalafmtConfig.default) + val defaultOptions = CliOptions.default + .copy(baseConfig = ScalafmtConfig.default) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/cli/FakeGitOps.scala b/scalafmt-tests/src/test/scala/org/scalafmt/cli/FakeGitOps.scala index 0e82cda993..ddfcbbe3a8 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/cli/FakeGitOps.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/cli/FakeGitOps.scala @@ -3,8 +3,8 @@ package org.scalafmt.cli import org.scalafmt.sysops.{AbsoluteFile, GitOps} class FakeGitOps(root: AbsoluteFile) extends GitOps { - override def lsTree(dir: AbsoluteFile*): Seq[AbsoluteFile] = - dir.flatMap(_.listFiles) + override def lsTree(dir: AbsoluteFile*): Seq[AbsoluteFile] = dir + .flatMap(_.listFiles) override def rootDir: Option[AbsoluteFile] = Some(root) override def status(dir: AbsoluteFile*): Seq[AbsoluteFile] = lsTree(root) override def diff(branch: String, dir: AbsoluteFile*): Seq[AbsoluteFile] = diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/cli/FileTestOps.scala b/scalafmt-tests/src/test/scala/org/scalafmt/cli/FileTestOps.scala index a9f8a7dd41..6f2c19916a 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/cli/FileTestOps.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/cli/FileTestOps.scala @@ -14,8 +14,7 @@ object FileTestOps { def string2dir(layout: String): AbsoluteFile = { val root = AbsoluteFile(Files.createTempDirectory("root")) layout.split("(?=\n/)").foreach { row => - val path :: contents :: Nil = - row.stripPrefix("\n").split("\n", 2).toList + val path :: contents :: Nil = row.stripPrefix("\n").split("\n", 2).toList val file = root / path.stripPrefix("/") file.parent.mkdirs() file.writeFile(contents) @@ -36,15 +35,10 @@ object FileTestOps { def dir2string(file: AbsoluteFile): String = { val rootPath = file.path val prefix = rootPath.toString - FileOps - .listFiles(rootPath) - .sortBy(_.toString) - .map { path => - s"""|${path.toString.stripPrefix(prefix)} - |${FileOps.readFile(path)}""".stripMargin - } - .mkString("\n") - .replace(File.separator, "/") // ensure original separators + FileOps.listFiles(rootPath).sortBy(_.toString).map { path => + s"""|${path.toString.stripPrefix(prefix)} + |${FileOps.readFile(path)}""".stripMargin + }.mkString("\n").replace(File.separator, "/") // ensure original separators } def getMockOptions(baseDir: AbsoluteFile): CliOptions = @@ -58,15 +52,11 @@ object FileTestOps { CliOptions.default.copy( baseConfig = ScalafmtConfig.default, gitOpsConstructor = _ => new FakeGitOps(baseDir), - common = CliOptions.default.common.copy( - cwd = Some(workingDir), - out = out, - err = out - ) + common = CliOptions.default.common + .copy(cwd = Some(workingDir), out = out, err = out) ) } - val baseCliOptions: CliOptions = getMockOptions( - AbsoluteFile(Files.createTempDirectory("base-dir")) - ) + val baseCliOptions: CliOptions = + getMockOptions(AbsoluteFile(Files.createTempDirectory("base-dir"))) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/config/AvoidInfixSettingsTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/config/AvoidInfixSettingsTest.scala index 5c6b9d8795..0f0a3f51d4 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/config/AvoidInfixSettingsTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/config/AvoidInfixSettingsTest.scala @@ -2,12 +2,7 @@ package org.scalafmt.config class AvoidInfixSettingsTest extends munit.FunSuite { - Seq( - Nil, - Seq("foo"), - Seq("cross"), - Seq("cross", "foo") - ).foreach { extra => + Seq(Nil, Seq("foo"), Seq("cross"), Seq("cross", "foo")).foreach { extra => test(s"AvoidInfixSettings.forSbtOpt: [${extra.mkString(",")}]") { val settings = AvoidInfixSettings.default .withExtraExclude(extra.map(AvoidInfixSettings.Filter.apply)) @@ -16,8 +11,8 @@ class AvoidInfixSettingsTest extends munit.FunSuite { case None => if (!extra.contains("cross")) fail("forSbtOpt shouldn't be None") case Some(sbtSettings) => - val expected = - settings.excludeFilters :+ AvoidInfixSettings.Filter("cross") + val expected = settings.excludeFilters :+ + AvoidInfixSettings.Filter("cross") assertEquals(sbtSettings.excludeFilters, expected) } } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/config/ScalafmtConfigTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/config/ScalafmtConfigTest.scala index 26b5923b31..6fe7880876 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/config/ScalafmtConfigTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/config/ScalafmtConfigTest.scala @@ -5,36 +5,32 @@ import munit.FunSuite class ScalafmtConfigTest extends FunSuite { test("project.matcher") { - val config = ScalafmtConfig - .fromHoconString( - """ - |project.excludeFilters = [ - | "scalafmt-benchmarks/src/resources" - | "/sbt-test/" - | "bin/issue" - |] + val config = ScalafmtConfig.fromHoconString( + """ + |project.excludeFilters = [ + | "scalafmt-benchmarks/src/resources" + | "/sbt-test/" + | "bin/issue" + |] """.stripMargin - ) - .get + ).get assert(config.project.matcher.matches("qux/Kazbar.scala")) assert(!config.project.matcher.matches("foo/sbt-test/src/main")) } test("file overrides") { - val config = ScalafmtConfig - .fromHoconString( - """ - |newlines.source = fold - |newlines.topLevelBodyIfMinStatements = [before,after] - |fileOverride { - | "glob:**/src/test/scala/**" { - | newlines.source = unfold - | newlines.topLevelBodyIfMinStatements = [] - | } - |} + val config = ScalafmtConfig.fromHoconString( + """ + |newlines.source = fold + |newlines.topLevelBodyIfMinStatements = [before,after] + |fileOverride { + | "glob:**/src/test/scala/**" { + | newlines.source = unfold + | newlines.topLevelBodyIfMinStatements = [] + | } + |} """.stripMargin - ) - .get + ).get val nlCfg1 = config.getConfigFor("/x/src/main/scala/foo.scala").get.newlines val nlCfg2 = config.getConfigFor("/x/src/test/scala/bar.scala").get.newlines assertEquals(nlCfg1.source, Newlines.fold) @@ -47,74 +43,62 @@ class ScalafmtConfigTest extends FunSuite { } test("align preset no override") { - val config = ScalafmtConfig - .fromHoconString( - """ - |align = none - |align.stripMargin = true + val config = ScalafmtConfig.fromHoconString( + """ + |align = none + |align.stripMargin = true """.stripMargin - ) - .get + ).get // none was ignored assertEquals(config.align, Align(stripMargin = true)) } test("align preset with override") { - val config = ScalafmtConfig - .fromHoconString( - """ - |align.preset = none - |align.stripMargin = true + val config = ScalafmtConfig.fromHoconString( + """ + |align.preset = none + |align.stripMargin = true """.stripMargin - ) - .get + ).get assertEquals(config.align, Align.none.copy(stripMargin = true)) } test("dialect override") { - val config1 = ScalafmtConfig - .fromHoconString( - """ - |runner.dialect = scala213 - |""".stripMargin - ) - .get + val config1 = ScalafmtConfig.fromHoconString( + """ + |runner.dialect = scala213 + |""".stripMargin + ).get assert(!config1.runner.getDialect.allowToplevelTerms) - val config2 = ScalafmtConfig - .fromHoconString( - """ - |runner.dialectOverride.allowToplevelTerms = true - |runner.dialect = scala213 - |""".stripMargin - ) - .get + val config2 = ScalafmtConfig.fromHoconString( + """ + |runner.dialectOverride.allowToplevelTerms = true + |runner.dialect = scala213 + |""".stripMargin + ).get assert(config2.runner.getDialect.allowToplevelTerms) } test("hasRewriteRules-and-withoutRewriteRules trailingCommas") { - val config1 = ScalafmtConfig - .fromHoconString( - """ - |runner.dialect = scala213 - |rewrite.trailingCommas = never - |""".stripMargin - ) - .get + val config1 = ScalafmtConfig.fromHoconString( + """ + |runner.dialect = scala213 + |rewrite.trailingCommas = never + |""".stripMargin + ).get assert(config1.hasRewrites) val config2 = config1.withoutRewrites assert(!config2.hasRewrites) } test("hasRewriteRules-and-withoutRewriteRules docstrings") { - val config1 = ScalafmtConfig - .fromHoconString( - """ - |runner.dialect = scala213 - |rewrite.trailingCommas = keep - |docstrings.removeEmpty = true - |""".stripMargin - ) - .get + val config1 = ScalafmtConfig.fromHoconString( + """ + |runner.dialect = scala213 + |rewrite.trailingCommas = keep + |docstrings.removeEmpty = true + |""".stripMargin + ).get assert(config1.hasRewrites) val config2 = config1.withoutRewrites assert(!config2.hasRewrites) diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/stats/GitInfo.scala b/scalafmt-tests/src/test/scala/org/scalafmt/stats/GitInfo.scala index 79edebddde..9997b9c4a8 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/stats/GitInfo.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/stats/GitInfo.scala @@ -19,14 +19,10 @@ object GitInfo { val travis: Option[GitInfo] = for { isCi <- sys.env.get("CI") if isCi == "true" - } yield { - GitInfo("CI", "CI", currentBranch, currentCommit) - } + } yield { GitInfo("CI", "CI", currentBranch, currentCommit) } - def apply(): GitInfo = - travis.getOrElse { - GitInfo(user, email, currentBranch, currentCommit) - } + def apply(): GitInfo = travis + .getOrElse { GitInfo(user, email, currentBranch, currentCommit) } def currentCommit = exec("git", "rev-parse", "HEAD") diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/stats/JavaInfo.scala b/scalafmt-tests/src/test/scala/org/scalafmt/stats/JavaInfo.scala index 8561fc6098..1d6a0a1fb1 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/stats/JavaInfo.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/stats/JavaInfo.scala @@ -4,10 +4,9 @@ case class JavaInfo(name: String, vendor: String, version: String) object JavaInfo { - def apply(): JavaInfo = - JavaInfo( - sys.props("java.vm.name"), - sys.props("java.vm.vendor"), - sys.props("java.vm.version") - ) + def apply(): JavaInfo = JavaInfo( + sys.props("java.vm.name"), + sys.props("java.vm.vendor"), + sys.props("java.vm.version") + ) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/stats/MachineStats.scala b/scalafmt-tests/src/test/scala/org/scalafmt/stats/MachineStats.scala index c7de3267c7..35af0188bf 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/stats/MachineStats.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/stats/MachineStats.scala @@ -10,10 +10,5 @@ case class MachineStats( object MachineStats { def apply(): MachineStats = - MachineStats( - JavaInfo(), - OsInfo(), - RuntimeInfo(), - GitInfo() - ) + MachineStats(JavaInfo(), OsInfo(), RuntimeInfo(), GitInfo()) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/stats/OsInfo.scala b/scalafmt-tests/src/test/scala/org/scalafmt/stats/OsInfo.scala index 48a3a9a94c..270d84513a 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/stats/OsInfo.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/stats/OsInfo.scala @@ -5,9 +5,5 @@ case class OsInfo(name: String, architecture: String, version: String) object OsInfo { def apply(): OsInfo = - OsInfo( - sys.props("os.name"), - sys.props("os.arch"), - sys.props("os.version") - ) + OsInfo(sys.props("os.name"), sys.props("os.arch"), sys.props("os.version")) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/stats/TestStats.scala b/scalafmt-tests/src/test/scala/org/scalafmt/stats/TestStats.scala index 3dcc7effca..086724d323 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/stats/TestStats.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/stats/TestStats.scala @@ -13,8 +13,8 @@ case class TestStats( gitInfo: GitInfo ) { - def shortInfo: String = - s"TestStats(created=${new Date(createdAt)}," + s"commit=${gitInfo.commit})" + def shortInfo: String = s"TestStats(created=${new Date(createdAt)}," + + s"commit=${gitInfo.commit})" def shortCommit: String = gitInfo.commit.take(6) @@ -29,13 +29,12 @@ case class TestStats( object TestStats { - def apply(results: Seq[Result]): TestStats = - TestStats( - System.currentTimeMillis(), - results, - JavaInfo(), - OsInfo(), - RuntimeInfo(), - GitInfo() - ) + def apply(results: Seq[Result]): TestStats = TestStats( + System.currentTimeMillis(), + results, + JavaInfo(), + OsInfo(), + RuntimeInfo(), + GitInfo() + ) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/sysops/FileOpsTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/sysops/FileOpsTest.scala index 32badf5313..0f64fd97db 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/sysops/FileOpsTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/sysops/FileOpsTest.scala @@ -18,9 +18,8 @@ class FileOpsTest extends munit.FunSuite { } override def afterEach(context: AfterEach): Unit = { - try { - deleteTree(path) - } catch { + try { deleteTree(path) } + catch { case e: Throwable => println("Unable to delete test files") e.printStackTrace() @@ -62,7 +61,7 @@ class FileOpsTest extends munit.FunSuite { object FileOpsTest { - private def subpath(path: Path): Path = - path.resolve(Random.alphanumeric.take(10).mkString) + private def subpath(path: Path): Path = path + .resolve(Random.alphanumeric.take(10).mkString) } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/sysops/GitOpsTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/sysops/GitOpsTest.scala index 77c5909e8e..8c19a52bc0 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/sysops/GitOpsTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/sysops/GitOpsTest.scala @@ -33,9 +33,8 @@ class GitOpsTest extends FunSuite { } override def afterEach(context: AfterEach): Unit = { - try { - deleteTree(path.path) - } catch { + try { deleteTree(path.path) } + catch { case e: Throwable => println("Unable to delete test files") e.printStackTrace() @@ -59,8 +58,8 @@ class GitOpsTest extends FunSuite { name: String = Random.alphanumeric.take(10).mkString, dir: Option[AbsoluteFile] = None ): AbsoluteFile = { - val linkFile = - File.createTempFile(name, ".ext", dir.orElse(ops.rootDir).get.jfile) + val linkFile = File + .createTempFile(name, ".ext", dir.orElse(ops.rootDir).get.jfile) linkFile.delete() val link = AbsoluteFile(linkFile) Files.createSymbolicLink(link.path, file.path) @@ -68,15 +67,10 @@ class GitOpsTest extends FunSuite { } def mv(f: AbsoluteFile, dir: Option[AbsoluteFile] = None): AbsoluteFile = { - val destDir = Files.createTempDirectory( - dir.orElse(ops.rootDir).get.path, - "dir_" - ) - val dest = Files.move( - f.path, - destDir, - java.nio.file.StandardCopyOption.REPLACE_EXISTING - ) + val destDir = Files + .createTempDirectory(dir.orElse(ops.rootDir).get.path, "dir_") + val dest = Files + .move(f.path, destDir, java.nio.file.StandardCopyOption.REPLACE_EXISTING) rm(f) AbsoluteFile(dest) } @@ -89,9 +83,7 @@ class GitOpsTest extends FunSuite { def ls(implicit ops: GitOpsImpl) = // DESNOTE(2017-08-17, pjrt): Filter out the initial file since it will // just annoy us in the tests below - ops - .lsTree(ops.workingDirectory) - .filterNot(_ == initFile) + ops.lsTree(ops.workingDirectory).filterNot(_ == initFile) def mkDir( dirName: String = Random.alphanumeric.take(10).mkString @@ -137,9 +129,7 @@ class GitOpsTest extends FunSuite { assertEquals(ls, Seq.empty) } - test( - "lsTree should return files properly when the working directory is under the git root directory" - ) { + test("lsTree should return files properly when the working directory is under the git root directory") { val f1 = touch() add(f1) @@ -161,8 +151,7 @@ class GitOpsTest extends FunSuite { def diff(br: String, cwd: AbsoluteFile*)(implicit ops: GitOpsImpl - ): Seq[AbsoluteFile] = - ops.diff(br, cwd: _*) + ): Seq[AbsoluteFile] = ops.diff(br, cwd: _*) def diff(cwd: AbsoluteFile*)(implicit ops: GitOpsImpl): Seq[AbsoluteFile] = diff("HEAD", cwd: _*) @@ -236,9 +225,7 @@ class GitOpsTest extends FunSuite { assertEquals(diff(defaultBranch, dir).toSet, Set(f2)) } - test( - "diff should return added files that are then modified against a different branch" - ) { + test("diff should return added files that are then modified against a different branch") { val f = touch() add(f) commit @@ -341,21 +328,18 @@ private object GitOpsTest { private final val defaultBranch = "main" // Filesystem commands - def rmfs(file: AbsoluteFile): Unit = - file.delete() + def rmfs(file: AbsoluteFile): Unit = file.delete() // Git commands def git(cmd: String, args: String*)(implicit ops: GitOpsImpl, loc: Location - ): Seq[String] = - Try(ops.exec("git" +: cmd +: args)) match { - case Failure(f) => Assertions.fail(s"Failed git command. Got: $f") - case Success(s) => s - } + ): Seq[String] = Try(ops.exec("git" +: cmd +: args)) match { + case Failure(f) => Assertions.fail(s"Failed git command. Got: $f") + case Success(s) => s + } - def init(implicit ops: GitOpsImpl): Unit = - git("init", "-b", defaultBranch) + def init(implicit ops: GitOpsImpl): Unit = git("init", "-b", defaultBranch) def add(file: AbsoluteFile*)(implicit ops: GitOpsImpl): Unit = git("add", file.map(_.toString()): _*) diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/util/CanRunTests.scala b/scalafmt-tests/src/test/scala/org/scalafmt/util/CanRunTests.scala index 6f628b9ecf..13ea94464a 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/util/CanRunTests.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/util/CanRunTests.scala @@ -11,26 +11,18 @@ trait CanRunTests extends FunSuite with HasTests { if (ignore(t)) { // Not even ignore(t), save console space. - } else if (t.skip) { - test(paddedName.ignore) {} - } else { + } else if (t.skip) { test(paddedName.ignore) {} } + else { test(paddedName) { - try { - run(t) - } catch { + try { run(t) } + catch { case FormatException(e: ParseException, code) => - fail( - "test does not parse\n" + - parseException2Message(e, code), - e - ) + fail("test does not parse\n" + parseException2Message(e, code), e) } } } } - def runTestsDefault(): Unit = { - testsToRun.foreach(runTest(defaultRun)) - } + def runTestsDefault(): Unit = { testsToRun.foreach(runTest(defaultRun)) } } diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/util/DeleteTree.scala b/scalafmt-tests/src/test/scala/org/scalafmt/util/DeleteTree.scala index ef02bda700..5c11d23117 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/util/DeleteTree.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/util/DeleteTree.scala @@ -15,9 +15,7 @@ class DeleteTree extends FileVisitor[Path] { override def preVisitDirectory( dir: Path, attrs: BasicFileAttributes - ): FileVisitResult = { - FileVisitResult.CONTINUE - } + ): FileVisitResult = { FileVisitResult.CONTINUE } override def visitFile( file: Path, @@ -30,9 +28,7 @@ class DeleteTree extends FileVisitor[Path] { override def visitFileFailed( file: Path, exc: IOException - ): FileVisitResult = { - throw exc - } + ): FileVisitResult = { throw exc } override def postVisitDirectory( dir: Path, diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/util/ErrorTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/util/ErrorTest.scala index db32d69326..37db1c0fad 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/util/ErrorTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/util/ErrorTest.scala @@ -5,11 +5,7 @@ import org.scalafmt.Scalafmt import munit.FunSuite class ErrorTest extends FunSuite { - private val nonSourceFile = Seq( - "class A {", - "val x + 1", - "println 1" - ) + private val nonSourceFile = Seq("class A {", "val x + 1", "println 1") nonSourceFile.foreach { original => test(s"errors are caught: $original") { Scalafmt.format(original, HasTests.unitTest40) match { diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/util/FormatAssertions.scala b/scalafmt-tests/src/test/scala/org/scalafmt/util/FormatAssertions.scala index dd1578fbd9..3fa353d58e 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/util/FormatAssertions.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/util/FormatAssertions.scala @@ -20,11 +20,10 @@ trait FormatAssertions { original: String, obtained: String, runner: ScalafmtRunner - ): Unit = - assertFormatPreservesAst(filename, original, obtained)( - runner.getParser, - runner.getDialectForParser - ) + ): Unit = assertFormatPreservesAst(filename, original, obtained)( + runner.getParser, + runner.getDialectForParser + ) def assertFormatPreservesAst[T <: Tree]( filename: String, @@ -32,16 +31,15 @@ trait FormatAssertions { obtained: String )(implicit ev: Parse[T], dialect: Dialect): Unit = { import scala.meta._ - def toInput(code: String) = - Scalafmt.toInput(Scalafmt.splitCodePrefix(code)._2, filename) + def toInput(code: String) = Scalafmt + .toInput(Scalafmt.splitCodePrefix(code)._2, filename) toInput(original).parse[T] match { case Parsed.Error(pos, message, _) => val msgWithPos = pos.formatMessage("error", message) val error = s"original does not parse ($msgWithPos) [$filename]" logger.debug(error) throw FormatterOutputDoesNotParse(error, pos.startLine) - case Parsed.Success(originalParsed) => - toInput(obtained).parse[T] match { + case Parsed.Success(originalParsed) => toInput(obtained).parse[T] match { case Parsed.Success(obtainedParsed) => StructurallyEqual(originalParsed, obtainedParsed) match { case Right(_) => // OK @@ -73,12 +71,8 @@ trait FormatAssertions { */ def diffAsts(original: String, obtained: String): String = { Diffs - .unifiedDiff( - original.replace("(", "\n("), - obtained.replace("(", "\n(") - ) - .linesIterator - .mkString("\n") + .unifiedDiff(original.replace("(", "\n("), obtained.replace("(", "\n(")) + .linesIterator.mkString("\n") } // TODO(olafur) move this to scala.meta? diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/util/HasTests.scala b/scalafmt-tests/src/test/scala/org/scalafmt/util/HasTests.scala index 45711151b1..4ebded1f21 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/util/HasTests.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/util/HasTests.scala @@ -26,20 +26,19 @@ trait HasTests extends FormatAssertions { import HasTests._ import LoggerOps._ - def scalafmtRunner(sr: ScalafmtRunner, dg: Debug): ScalafmtRunner = - sr.copy( - debug = true, - maxStateVisits = 150000, - eventCallback = { - case CreateFormatOps(ops) => dg.formatOps = ops - case explored: Explored if explored.n % 10000 == 0 => - logger.elem(explored) - case Enqueue(split) => dg.enqueued(split) - case evt: CompleteFormat => dg.completed(evt) - case x: Written => dg.locations = x.formatLocations - case _ => - } - ) + def scalafmtRunner(sr: ScalafmtRunner, dg: Debug): ScalafmtRunner = sr.copy( + debug = true, + maxStateVisits = 150000, + eventCallback = { + case CreateFormatOps(ops) => dg.formatOps = ops + case explored: Explored if explored.n % 10000 == 0 => + logger.elem(explored) + case Enqueue(split) => dg.enqueued(split) + case evt: CompleteFormat => dg.completed(evt) + case x: Written => dg.locations = x.formatLocations + case _ => + } + ) lazy val debugResults = mutable.ArrayBuilder.make[Result] val testDir = BuildInfo.resourceDirectory.toPath @@ -49,23 +48,19 @@ trait HasTests extends FormatAssertions { def testsToRun: Seq[DiffTest] = { val evalTests = tests val onlyTests = evalTests.filter(_.only) - if (onlyTests.nonEmpty) onlyTests - else tests + if (onlyTests.nonEmpty) onlyTests else tests } def isOnly(name: String) = isPrefix(name, onlyPrefix) def isSkip(name: String) = isPrefix(name, skipPrefix) - def stripPrefix(name: String) = - stripPrefixOpt(name, skipPrefix) - .orElse(stripPrefixOpt(name, onlyPrefix)) - .getOrElse(name) + def stripPrefix(name: String) = stripPrefixOpt(name, skipPrefix) + .orElse(stripPrefixOpt(name, onlyPrefix)).getOrElse(name) def filename2parse(filename: String): Option[ScalafmtParser] = extension(filename) match { - case "source" | "scala" | "scalafmt" => - Some(ScalafmtParser.Source) + case "source" | "scala" | "scalafmt" => Some(ScalafmtParser.Source) case "stat" => Some(ScalafmtParser.Stat) case "case" => Some(ScalafmtParser.Case) case _ => None @@ -76,13 +71,10 @@ trait HasTests extends FormatAssertions { def parseDiffTests(filename: String): Seq[DiffTest] = { val content = FileOps.readFile(filename) val sep = { - if (content.contains(System.lineSeparator)) System.lineSeparator - else "\n" + if (content.contains(System.lineSeparator)) System.lineSeparator else "\n" } val spec = BuildInfo.resourceDirectory.toPath - .relativize(Paths.get(filename)) - .getName(0) - .toString + .relativize(Paths.get(filename)).getName(0).toString val split = content.split(s"(?:^|$sep)<<< ") if (split.length <= 1) return Seq.empty // RETURNING!!! @@ -121,9 +113,7 @@ trait HasTests extends FormatAssertions { tail.map { t => val matcher = inputOutputRegex.matcher(t) if (!matcher.matches()) - throw new IllegalStateException( - s"invalid test, missing delimiters:\n$t" - ) + throw new IllegalStateException(s"invalid test, missing delimiters:\n$t") val name = matcher.group(1) val extraConfig = Option(matcher.group(2)) val original = matcher.group(3) @@ -146,17 +136,15 @@ trait HasTests extends FormatAssertions { } } - private def spec2style(spec: String): ScalafmtConfig = - spec match { - case "unit" => HasTests.unitTest40 - case "default" | "standard" | "scala" => HasTests.unitTest80 - case "scalajs" => - ScalafmtConfig.scalaJs.copy(maxColumn = 79).withDialect(defaultDialect) - case "scala3" => - ScalafmtConfig.default.withDialect(NamedDialect.scala3, "scala3") - case _ => - ScalafmtConfig.default.withDialect(defaultDialect) - } + private def spec2style(spec: String): ScalafmtConfig = spec match { + case "unit" => HasTests.unitTest40 + case "default" | "standard" | "scala" => HasTests.unitTest80 + case "scalajs" => ScalafmtConfig.scalaJs.copy(maxColumn = 79) + .withDialect(defaultDialect) + case "scala3" => ScalafmtConfig.default + .withDialect(NamedDialect.scala3, "scala3") + case _ => ScalafmtConfig.default.withDialect(defaultDialect) + } def saveResult(t: DiffTest, obtained: String, debug: Debug): Result = { val output = getFormatOutput(debug) @@ -174,25 +162,21 @@ trait HasTests extends FormatAssertions { def ignore(t: DiffTest): Boolean = false - def defaultRun(t: DiffTest)(implicit - loc: Location - ): Unit = { + def defaultRun(t: DiffTest)(implicit loc: Location): Unit = { val debug = new Debug(false) val runner = scalafmtRunner(t.style.runner, debug) - val result = Scalafmt - .formatCode( - t.original, - t.style.copy(runner = runner), - filename = t.filename - ) + val result = Scalafmt.formatCode( + t.original, + t.style.copy(runner = runner), + filename = t.filename + ) val obtained = result.formatted.get - if (t.style.rewrite.rules.isEmpty) - assertFormatPreservesAst( - t.filename, - t.original, - obtained, - result.config.runner - ) + if (t.style.rewrite.rules.isEmpty) assertFormatPreservesAst( + t.filename, + t.original, + obtained, + result.config.runner + ) assertNoDiff(obtained, t.expected) } @@ -228,9 +212,8 @@ object HasTests { openParenCallSite = true, openParenDefnSite = true ), - optIn = ScalafmtConfig.default.optIn.copy( - breakChainOnFirstMethodDot = false - ), + optIn = ScalafmtConfig.default.optIn + .copy(breakChainOnFirstMethodDot = false), // The new aggressive config style breaks ~40 unit tests. The diff output // looks nice, but updating the unit tests would take too much time. // I can imagine that I will throw away most of the tests and replace them @@ -238,17 +221,15 @@ object HasTests { runner = ScalafmtConfig.conservativeRunner.withDialect(defaultDialect) ) - val unitTest80 = testing.copy( - indent = Indents(callSite = 4, defnSite = 4) - ) + val unitTest80 = testing.copy(indent = Indents(callSite = 4, defnSite = 4)) val unitTest40 = unitTest80.copy(maxColumn = 39) private val onlyPrefix = "ONLY" private val skipPrefix = "SKIP" - private def isPrefix(name: String, prefix: String) = - name.startsWith(prefix) && !name.charAt(prefix.length).isLetterOrDigit + private def isPrefix(name: String, prefix: String) = name + .startsWith(prefix) && !name.charAt(prefix.length).isLetterOrDigit private def stripPrefixOpt(name: String, prefix: String) = if (isPrefix(name, prefix)) Some(name.substring(prefix.length).trim) diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/util/Report.scala b/scalafmt-tests/src/test/scala/org/scalafmt/util/Report.scala index 6623cd60e6..b048fc7c69 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/util/Report.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/util/Report.scala @@ -9,41 +9,35 @@ import org.scalafmt.stats.TestStats object Report { val MaxVisits = 8 // 2 ** 6 - def heatmap(results: Seq[Result]): String = - reportBody( + def heatmap(results: Seq[Result]): String = reportBody(div( + h1(id := "title", "Heatmap"), + explanation, + for ( + result <- results.sortBy(-_.maxVisitsOnSingleToken) + if result.test.name != "Warmup" + ) yield { div( - h1(id := "title", "Heatmap"), - explanation, - for ( - result <- results.sortBy(-_.maxVisitsOnSingleToken) - if result.test.name != "Warmup" - ) yield { - div( - h2(result.title), - pre( - fontFamily := "monospace", - background := "#fff", - fontSize := "16px", - width := testWidth(result), - code( - heatmapBar(result.test.style), - raw(result.obtainedHtml), - span("\n" + ("‾" * result.test.style.maxColumn)) - ) - ) + h2(result.title), + pre( + fontFamily := "monospace", + background := "#fff", + fontSize := "16px", + width := testWidth(result), + code( + heatmapBar(result.test.style), + raw(result.obtainedHtml), + span("\n" + ("‾" * result.test.style.maxColumn)) ) - } + ) ) - ).render + } + )).render def heatmapBar(scalaStyle: ScalafmtConfig): Seq[Text.Modifier] = (1 to MaxVisits).map { i => val v = Math.pow(2, i).toInt val color = red(v) - span( - background := s"rgb(256, $color, $color)", - s" $v " - ) + span(background := s"rgb(256, $color, $color)", s" $v ") } :+ span("\n" + ("_" * scalaStyle.maxColumn) + "\n") def red(visits: Int): Int = { @@ -53,87 +47,66 @@ object Report { result } - def log(x: Int, base: Int): Double = { - Math.log(x) / Math.log(base) - } + def log(x: Int, base: Int): Double = { Math.log(x) / Math.log(base) } - def explanation = - div( - p( - """Formatting output from scalafmt's test suite. - |The formatter uses Dijkstra's shortest path to determine the - |formatting with the "cheapest" cost. The red regions are - |tokens the formatter visits often. + def explanation = div( + p( + """Formatting output from scalafmt's test suite. + |The formatter uses Dijkstra's shortest path to determine the + |formatting with the "cheapest" cost. The red regions are + |tokens the formatter visits often. """.stripMargin - ), - ul( - li("Declaration arguments: bin packed"), - li("Callsite arguments: one arg per line if overflowing") - ) + ), + ul( + li("Declaration arguments: bin packed"), + li("Callsite arguments: one arg per line if overflowing") ) + ) def testWidth(result: Result) = result.test.style.maxColumn.toDouble * 9.625 - def reportBody(xs: Text.Modifier*) = - html( - body(background := "#f9f9f9", xs) - ) + def reportBody(xs: Text.Modifier*) = html(body(background := "#f9f9f9", xs)) - def compare(before: TestStats, after: TestStats): String = - reportBody( - div( - h1( - id := "title", - s"Compare ${after.gitInfo.branch} and" + - s" ${before.gitInfo.branch}" + - s" (${before.shortCommit}...${after.shortCommit})" - ), - explanation, - after - .intersectResults(before) - .sortBy { case (aft, bef) => - -Math.abs(aft.visitedStates - bef.visitedStates) - } - .map { case (aft, bef) => - div( - h2(aft.test.fullName), - table( - tr( - th(""), - th("Before"), - th("After"), - th("Diff") - ), - tr( - td("Time (ms)"), - td(bef.timeMs), - td(aft.timeMs), - td(bef.timeMs - aft.timeMs) - ), - tr( - td("States"), - td(bef.visitedStates), - td(aft.visitedStates), - td(aft.visitedStates - bef.visitedStates) - ) - ), - pre( - fontFamily := "monospace", - background := "#fff", - fontSize := "16px", - width := testWidth(aft), - code( - heatmapBar(aft.test.style), - raw(mkHtml(mergeResults(aft, bef))) - ) - ) + def compare(before: TestStats, after: TestStats): String = reportBody(div( + h1( + id := "title", + s"Compare ${after.gitInfo.branch} and" + s" ${before.gitInfo.branch}" + + s" (${before.shortCommit}...${after.shortCommit})" + ), + explanation, + after.intersectResults(before).sortBy { case (aft, bef) => + -Math.abs(aft.visitedStates - bef.visitedStates) + }.map { + case (aft, bef) => div( + h2(aft.test.fullName), + table( + tr(th(""), th("Before"), th("After"), th("Diff")), + tr( + td("Time (ms)"), + td(bef.timeMs), + td(aft.timeMs), + td(bef.timeMs - aft.timeMs) + ), + tr( + td("States"), + td(bef.visitedStates), + td(aft.visitedStates), + td(aft.visitedStates - bef.visitedStates) ) - } - ) - ).render + ), + pre( + fontFamily := "monospace", + background := "#fff", + fontSize := "16px", + width := testWidth(aft), + code(heatmapBar(aft.test.style), raw(mkHtml(mergeResults(aft, bef)))) + ) + ) + } + )).render - def mergeResults(after: Result, before: Result): Seq[FormatOutput] = - after.tokens.zip(before.tokens).map { case (aft, bef) => + def mergeResults(after: Result, before: Result): Seq[FormatOutput] = after + .tokens.zip(before.tokens).map { case (aft, bef) => FormatOutput(aft.token, aft.visits - bef.visits) } @@ -142,9 +115,7 @@ object Report { output.foreach { x => import scalatags.Text.all._ val redness = red(Math.abs(x.visits)) - val isRed = - if (x.visits > 0) true - else false + val isRed = if (x.visits > 0) true else false val styleBackground = if (isRed) s"rgb(256, $redness, $redness)" else s"rgb($redness, 256, $redness)" // green diff --git a/scalafmt-tests/src/test/scala/org/scalafmt/util/StyleMapTest.scala b/scalafmt-tests/src/test/scala/org/scalafmt/util/StyleMapTest.scala index 7f9b8c328e..6291f0b1f9 100644 --- a/scalafmt-tests/src/test/scala/org/scalafmt/util/StyleMapTest.scala +++ b/scalafmt-tests/src/test/scala/org/scalafmt/util/StyleMapTest.scala @@ -10,35 +10,29 @@ import munit.FunSuite class StyleMapTest extends FunSuite { test("basic") { - val code = - """object a { - | // scalafmt: { maxColumn = 100 } - | println(1) - | // scalafmt: { maxColumn = 110 } - |} + val code = """object a { + | // scalafmt: { maxColumn = 100 } + | println(1) + | // scalafmt: { maxColumn = 110 } + |} """.stripMargin.parse[Source].get val m = new FormatOps(code, ScalafmtConfig.default) assertEquals( - m.styleMap - .at(m.tokens.head) - .maxColumn, + m.styleMap.at(m.tokens.head).maxColumn, ScalafmtConfig.default.maxColumn ) assertEquals( - m.styleMap - .at(m.tokens.find(_.left.syntax == "println").get) - .maxColumn, + m.styleMap.at(m.tokens.find(_.left.syntax == "println").get).maxColumn, 100 ) assertEquals(m.styleMap.at(m.tokens.last).maxColumn, 110) } test("align.tokens.+") { - val code = - """object a { - | // scalafmt: { align.tokens."+" = [{ code="=", owner=".*" }] } - | println(1) - |} + val code = """object a { + | // scalafmt: { align.tokens."+" = [{ code="=", owner=".*" }] } + | println(1) + |} """.stripMargin.parse[Source].get val formatOps = new FormatOps(code, ScalafmtConfig.defaultWithAlign) val headToken = formatOps.tokens.head @@ -73,11 +67,10 @@ class StyleMapTest extends FunSuite { } test("newlines.implicitParamListModifierForce") { - val code = - """object a { - | // scalafmt: { newlines.implicitParamListModifierForce = [after] } - | println(1) - |} + val code = """object a { + | // scalafmt: { newlines.implicitParamListModifierForce = [after] } + | println(1) + |} """.stripMargin.parse[Source].get val formatOps = new FormatOps( code, @@ -120,13 +113,12 @@ class StyleMapTest extends FunSuite { * One test uses the default settings (meaning, unsafeCallSite=false) while * the other starts with BinPack.enabled, which includes unsafeCallSite=true. */ - val code = - """object a { - | println(1, 2, 3, 4, 5, 6) - | println(1, 2, 3, 4, 5, 6) - | // scalafmt: { binPack.unsafeCallSite = false } - | println(1, 2, 3, 4, 5, 6) - |} + val code = """object a { + | println(1, 2, 3, 4, 5, 6) + | println(1, 2, 3, 4, 5, 6) + | // scalafmt: { binPack.unsafeCallSite = false } + | println(1, 2, 3, 4, 5, 6) + |} """.stripMargin.parse[Source].get val fops1 = new FormatOps(code, ScalafmtConfig.default) val fops2 = new FormatOps(code, ScalafmtConfig(binPack = BinPack.enabled))