diff --git a/modules/cli/src/main/scala/scala/cli/commands/fmt/Fmt.scala b/modules/cli/src/main/scala/scala/cli/commands/fmt/Fmt.scala index f08c247048..4c1bcc2f77 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/fmt/Fmt.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/fmt/Fmt.scala @@ -76,19 +76,29 @@ object Fmt extends ScalaCommand[FmtOptions] { case _ => "default" } - val entry = { - val dialect = ScalafmtDialect.fromString(dialectString) - val prevConfMaybe = pathMaybe.map(p => os.read(p)) - scalafmtConfigWithFields(prevConfMaybe.getOrElse(""), Some(version), dialect) - } - val scalaFmtConfPath = { - val confFileName = ".scalafmt.conf" - val path = - if (options.saveScalafmtConf) pathMaybe.getOrElse(workspace / confFileName) - else workspace / Constants.workspaceDirName / confFileName - os.write.over(path, entry, createFolders = true) - path - } + val dialect = ScalafmtDialect.fromString(dialectString) + val prevConfMaybe = pathMaybe.map(os.read(_)) + val entry = scalafmtConfigWithFields(prevConfMaybe.getOrElse(""), Some(version), dialect) + + val confFileName = ".scalafmt.conf" + val canUseDiscoveredInPlace = + !options.saveScalafmtConf + && options.scalafmtConfStr.isEmpty + && options.scalafmtConf.isEmpty + && pathMaybe.isDefined + && versionMaybe.isDefined + && dialectMaybe.isDefined + && options.scalafmtVersion.forall(versionMaybe.contains) + && options.scalafmtDialect.forall(dialectMaybe.contains) + + val scalaFmtConfPath = + if canUseDiscoveredInPlace then pathMaybe.get + else + val path = + if options.saveScalafmtConf then pathMaybe.getOrElse(workspace / confFileName) + else workspace / Constants.workspaceDirName / confFileName + os.write.over(path, entry, createFolders = true) + path val fmtCommand = options.scalafmtLauncher.filter(_.nonEmpty) match { case Some(launcher) => diff --git a/modules/integration/src/test/scala/scala/cli/integration/FmtTests.scala b/modules/integration/src/test/scala/scala/cli/integration/FmtTests.scala index afd439f1bc..c0cc7374d3 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/FmtTests.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/FmtTests.scala @@ -63,6 +63,18 @@ class FmtTests extends ScalaCliSuite { os.rel / "Foo.scala" -> simpleInputsUnformattedContent ) + val simpleInputsWithoutConf: TestInputs = TestInputs( + os.rel / "Foo.scala" -> simpleInputsUnformattedContent + ) + + private def workspaceConfPath(root: os.Path): os.Path = + root / Constants.workspaceDirName / confFileName + + private def expectNoWorkspaceScalafmtConf(root: os.Path): Unit = { + expect(!os.exists(workspaceConfPath(root))) + expect(!os.exists(root / Constants.workspaceDirName)) + } + private def noCrLf(input: String): String = input.replaceAll("\r\n", "\n") @@ -175,12 +187,73 @@ class FmtTests extends ScalaCliSuite { } } + test("complete .scalafmt.conf is not duplicated under .scala-build") { + simpleInputs.fromRoot { root => + os.proc(TestUtil.cli, "fmt", ".").call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Foo.scala")) + expect(updatedContent == expectedSimpleInputsFormattedContent) + expectNoWorkspaceScalafmtConf(root) + } + } + + test("complete .scalafmt.conf + matching --scalafmt-version still avoids .scala-build") { + simpleInputs.fromRoot { root => + os.proc( + TestUtil.cli, + "fmt", + ".", + "--scalafmt-version", + Constants.defaultScalafmtVersion + ).call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Foo.scala")) + expect(updatedContent == expectedSimpleInputsFormattedContent) + expectNoWorkspaceScalafmtConf(root) + } + } + + test("complete .scalafmt.conf + matching --scalafmt-dialect still avoids .scala-build") { + simpleInputs.fromRoot { root => + os.proc(TestUtil.cli, "fmt", ".", "--scalafmt-dialect", "scala213").call(cwd = root) + val updatedContent = noCrLf(os.read(root / "Foo.scala")) + expect(updatedContent == expectedSimpleInputsFormattedContent) + expectNoWorkspaceScalafmtConf(root) + } + } + + test("complete .scalafmt.conf in git root is used in place") { + simpleInputs.fromRoot { root => + TestUtil.initializeGit(root) + val subdir = root / "subdir" + os.makeDir.all(subdir) + os.move(root / "Foo.scala", subdir / "Foo.scala") + os.proc(TestUtil.cli, "fmt", ".").call(cwd = subdir) + val updatedContent = noCrLf(os.read(subdir / "Foo.scala")) + expect(updatedContent == expectedSimpleInputsFormattedContent) + expectNoWorkspaceScalafmtConf(subdir) + expectNoWorkspaceScalafmtConf(root) + } + } + + test("no .scalafmt.conf still triggers .scala-build") { + simpleInputsWithoutConf.fromRoot { root => + // Isolate from the enclosing scala-cli git repo + // (whose .scalafmt.conf would otherwise be discovered) + TestUtil.initializeGit(root) + val confPath = workspaceConfPath(root) + expect(!os.exists(confPath)) + os.proc(TestUtil.cli, "fmt", ".").call(cwd = root) + expect(os.exists(confPath)) + val updatedContent = noCrLf(os.read(root / "Foo.scala")) + expect(updatedContent == expectedSimpleInputsFormattedContent) + } + } + test("creating workspace conf file") { simpleInputsWithDialectOnly.fromRoot { root => - val workspaceConfPath = root / Constants.workspaceDirName / confFileName - expect(!os.exists(workspaceConfPath)) + val confPath = workspaceConfPath(root) + expect(!os.exists(confPath)) os.proc(TestUtil.cli, "fmt", ".").call(cwd = root) - expect(os.exists(workspaceConfPath)) + expect(os.exists(confPath)) val updatedContent = noCrLf(os.read(root / "Foo.scala")) expect(updatedContent == expectedSimpleInputsFormattedContent) }