From 743d74290ee24fe25cbeab86f9c7281a0222a312 Mon Sep 17 00:00:00 2001 From: jonathanchang31 <55106972+jonathanchang31@users.noreply.github.com> Date: Sun, 12 Apr 2026 18:31:21 +0200 Subject: [PATCH] [2.x] Add English aliases `cross` and `switch` for `+` and `++` commands Fixes #3137. Adds discoverable English-name alternatives for the symbolic cross-build commands using the | parser combinator, making them more beginner-friendly without adding separate commands. --- main/src/main/scala/sbt/Cross.scala | 25 +++++++++++-------- .../scala/sbt/internal/CommandStrings.scala | 12 ++++++--- .../sbt-test/actions/cross-alias/build.sbt | 9 +++++++ sbt-app/src/sbt-test/actions/cross-alias/test | 11 ++++++++ 4 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 sbt-app/src/sbt-test/actions/cross-alias/build.sbt create mode 100644 sbt-app/src/sbt-test/actions/cross-alias/test diff --git a/main/src/main/scala/sbt/Cross.scala b/main/src/main/scala/sbt/Cross.scala index 3bc838184..6a78cb08b 100644 --- a/main/src/main/scala/sbt/Cross.scala +++ b/main/src/main/scala/sbt/Cross.scala @@ -41,7 +41,7 @@ object Cross { private def switchParser(state: State): Parser[Switch] = { import DefaultParsers.* - def versionAndCommand(spacePresent: Boolean) = { + def versionAndCommand(commandName: String)(spacePresent: Boolean) = { val x = Project.extract(state) import x.* val knownVersions = crossVersions(x, currentRef) @@ -56,7 +56,7 @@ object Cross { ScalaHomeVersion(new File(home), Some(v).filterNot(_.isEmpty), force) } } - val spacedVersion = if (spacePresent) version else version & spacedFirst(SwitchCommand) + val spacedVersion = if (spacePresent) version else version & spacedFirst(commandName) val verboseOpt = Parser.opt(token(Space ~> "-v")) // Accept valid commands, or project/command patterns that may reference projects // not yet available after version switch (fixes #7574) @@ -74,19 +74,24 @@ object Cross { switch1 | switch2 } - token(SwitchCommand ~> OptSpace) flatMap { sp => - versionAndCommand(sp.nonEmpty) - } + def parse(commandName: String) = + token(commandName ~> OptSpace) flatMap { sp => + versionAndCommand(commandName)(sp.nonEmpty) + } + parse(SwitchCommand) | parse(SwitchAlias) } private case class CrossArgs(command: String, verbose: Boolean) - private def crossParser(state: State): Parser[CrossArgs] = - token(CrossCommand <~ OptSpace) flatMap { _ => - (token(Parser.opt("-v" <~ Space)) ~ token(matched(state.combinedParser))).map { - (verbose, command) => CrossArgs(command, verbose.isDefined) + private def crossParser(state: State): Parser[CrossArgs] = { + def parse(commandName: String) = + token(commandName <~ OptSpace) flatMap { _ => + (token(Parser.opt("-v" <~ Space)) ~ token(matched(state.combinedParser))).map { + (verbose, command) => CrossArgs(command, verbose.isDefined) + } } - } + parse(CrossCommand) | parse(CrossAlias) + } private def crossRestoreSessionParser: Parser[String] = token(CrossRestoreSessionCommand) diff --git a/main/src/main/scala/sbt/internal/CommandStrings.scala b/main/src/main/scala/sbt/internal/CommandStrings.scala index 9761fc724..08c7e7b74 100644 --- a/main/src/main/scala/sbt/internal/CommandStrings.scala +++ b/main/src/main/scala/sbt/internal/CommandStrings.scala @@ -331,15 +331,19 @@ defaults Nil val CrossCommand = "+" + val CrossAlias = "cross" val CrossRestoreSessionCommand = "+-" val SwitchCommand = "++" + val SwitchAlias = "switch" - def crossHelp: Help = Help.more(CrossCommand, CrossDetailed) + def crossHelp: Help = + Help.more(CrossCommand, CrossDetailed) ++ Help.more(CrossAlias, CrossDetailed) def crossRestoreSessionHelp = Help.more(CrossRestoreSessionCommand, CrossRestoreSessionDetailed) - def switchHelp: Help = Help.more(SwitchCommand, SwitchDetailed) + def switchHelp: Help = + Help.more(SwitchCommand, SwitchDetailed) ++ Help.more(SwitchAlias, SwitchDetailed) def CrossDetailed = - s"""$CrossCommand [-v] + s"""$CrossCommand (or $CrossAlias) [-v] Runs for each Scala version specified for cross-building. For each string in `crossScalaVersions` in each project project, this command sets @@ -359,7 +363,7 @@ defaults """ def SwitchDetailed = - s"""$SwitchCommand [!] [-v] [] + s"""$SwitchCommand (or $SwitchAlias) [!] [-v] [] Changes the Scala version and runs a command. may be an actual Scala version such as 3.1.3, or a Semantic Version selector diff --git a/sbt-app/src/sbt-test/actions/cross-alias/build.sbt b/sbt-app/src/sbt-test/actions/cross-alias/build.sbt new file mode 100644 index 000000000..c7a4657c7 --- /dev/null +++ b/sbt-app/src/sbt-test/actions/cross-alias/build.sbt @@ -0,0 +1,9 @@ +lazy val scala212 = "2.12.21" +lazy val scala213 = "2.13.12" + +ThisBuild / scalaVersion := scala212 + +lazy val root = (project in file(".")) + .settings( + crossScalaVersions := Seq(scala212, scala213), + ) diff --git a/sbt-app/src/sbt-test/actions/cross-alias/test b/sbt-app/src/sbt-test/actions/cross-alias/test new file mode 100644 index 000000000..2ecf14b37 --- /dev/null +++ b/sbt-app/src/sbt-test/actions/cross-alias/test @@ -0,0 +1,11 @@ +# Test that "cross" works as an alias for "+" +> cross clean + +# Test that "cross" works with verbose flag +> cross -v compile + +# Test that "switch" works as an alias for "++" +> switch 2.13.12! + +# Test that "switch" works with a command +> switch 2.12.21! compile