diff --git a/mainargs/src/Renderer.scala b/mainargs/src/Renderer.scala index b70fb01..20733bb 100644 --- a/mainargs/src/Renderer.scala +++ b/mainargs/src/Renderer.scala @@ -13,18 +13,32 @@ object Renderer { val newLine = System.lineSeparator() def normalizeNewlines(s: String) = s.replace("\r", "").replace("\n", newLine) + def makeOptional(s: String) = s"[$s]" + def makeRequired(s: String) = s" $s" + def makeVarargs(s: String) = s"[$s]*" + def makeOnePlus(s: String) = s"[$s]+" def renderArgShort(arg: ArgSig) = arg.reader match { case r: TokensReader.Flag => val shortPrefix = arg.shortName.map(c => s"-$c") val nameSuffix = arg.name.map(s => s"--$s") - (shortPrefix ++ nameSuffix).mkString(" ") + makeOptional((shortPrefix ++ nameSuffix).mkString(" ")) case r: TokensReader.Simple[_] => val shortPrefix = arg.shortName.map(c => s"-$c") val typeSuffix = s"<${r.shortName}>" val nameSuffix = if (arg.positional) arg.name else arg.name.map(s => s"--$s") - (shortPrefix ++ nameSuffix ++ Seq(typeSuffix)).mkString(" ") + val rendered = (shortPrefix ++ nameSuffix ++ Seq(typeSuffix)).mkString(" ") + if (r.allowEmpty && r.alwaysRepeatable) + makeVarargs(rendered) + else if (r.alwaysRepeatable) + makeOnePlus(rendered) + else if (r.allowEmpty) + makeOptional(rendered) + else if (arg.default.isDefined) + makeOptional(rendered) + else + makeRequired(rendered) case r: TokensReader.Leftover[_, _] => s"${arg.name.get} <${r.shortName}>..." diff --git a/mainargs/test/src-jvm-2/AmmoniteTests.scala b/mainargs/test/src-jvm-2/AmmoniteTests.scala index c9ea6db..5b7e199 100644 --- a/mainargs/test/src-jvm-2/AmmoniteTests.scala +++ b/mainargs/test/src-jvm-2/AmmoniteTests.scala @@ -145,30 +145,32 @@ object AmmoniteTests extends TestSuite { val expected = """Ammonite REPL & Script-Runner |usage: amm [ammonite-options] [script-file [script-options]] - | --no-default-predef Disable the default predef and run Ammonite with the minimal predef possible - | -s --silent Make ivy logs go silent instead of printing though failures will still throw - | exception - | -w --watch Watch and re-run your scripts when they change - | --bsp Run a BSP server against the passed scripts - | -c --code Pass in code to be run immediately in the REPL - | -h --home The home directory of the REPL; where it looks for config and caches - | -p --predef Lets you load your predef from a custom location, rather than the default - | location in your Ammonite home - | --color Enable or disable colored output; by default colors are enabled in both REPL - | and scripts if the console is interactive, and disabled otherwise - | --thin Hide parts of the core of Ammonite and some of its dependencies. By default, - | the core of Ammonite and all of its dependencies can be seen by users from - | the Ammonite session. This option mitigates that via class loader isolation. - | --help Print this message - | --predef-code Any commands you want to execute at the start of the REPL session - | --no-home-predef Disables the default behavior of loading predef files from your - | ~/.ammonite/predef.sc, predefScript.sc, or predefShared.sc. You can choose an - | additional predef to use using `--predef - | -b --banner Customize the welcome banner that gets shown when Ammonite starts - | --no-remote-logging (deprecated) Disable remote logging of the number of times a REPL starts and - | runs commands - | --classBased Wrap user code in classes rather than singletons, typically for Java - | serialization friendliness. + | [--no-default-predef] Disable the default predef and run Ammonite with the minimal predef + | possible + | [-s --silent] Make ivy logs go silent instead of printing though failures will still + | throw exception + | [-w --watch] Watch and re-run your scripts when they change + | [--bsp] Run a BSP server against the passed scripts + | [-c --code ] Pass in code to be run immediately in the REPL + | [-h --home ] The home directory of the REPL; where it looks for config and caches + | [-p --predef ] Lets you load your predef from a custom location, rather than the default + | location in your Ammonite home + | [--color ] Enable or disable colored output; by default colors are enabled in both + | REPL and scripts if the console is interactive, and disabled otherwise + | [--thin] Hide parts of the core of Ammonite and some of its dependencies. By + | default, the core of Ammonite and all of its dependencies can be seen by + | users from the Ammonite session. This option mitigates that via class + | loader isolation. + | [--help] Print this message + | [--predef-code ] Any commands you want to execute at the start of the REPL session + | [--no-home-predef] Disables the default behavior of loading predef files from your + | ~/.ammonite/predef.sc, predefScript.sc, or predefShared.sc. You can choose + | an additional predef to use using `--predef + | [-b --banner ] Customize the welcome banner that gets shown when Ammonite starts + | [--no-remote-logging] (deprecated) Disable remote logging of the number of times a REPL starts + | and runs commands + | [--classBased] Wrap user code in classes rather than singletons, typically for Java + | serialization friendliness. | rest ... |""".stripMargin.trim @@ -184,30 +186,32 @@ object AmmoniteTests extends TestSuite { val expected = """Ammonite REPL & Script-Runner |usage: amm [ammonite-options] [script-file [script-options]] - | -b --banner Customize the welcome banner that gets shown when Ammonite starts - | --bsp Run a BSP server against the passed scripts - | -c --code Pass in code to be run immediately in the REPL - | --classBased Wrap user code in classes rather than singletons, typically for Java - | serialization friendliness. - | --color Enable or disable colored output; by default colors are enabled in both REPL - | and scripts if the console is interactive, and disabled otherwise - | -h --home The home directory of the REPL; where it looks for config and caches - | --help Print this message - | --no-default-predef Disable the default predef and run Ammonite with the minimal predef possible - | --no-home-predef Disables the default behavior of loading predef files from your - | ~/.ammonite/predef.sc, predefScript.sc, or predefShared.sc. You can choose an - | additional predef to use using `--predef - | --no-remote-logging (deprecated) Disable remote logging of the number of times a REPL starts and - | runs commands - | -p --predef Lets you load your predef from a custom location, rather than the default - | location in your Ammonite home - | --predef-code Any commands you want to execute at the start of the REPL session - | -s --silent Make ivy logs go silent instead of printing though failures will still throw - | exception - | --thin Hide parts of the core of Ammonite and some of its dependencies. By default, - | the core of Ammonite and all of its dependencies can be seen by users from - | the Ammonite session. This option mitigates that via class loader isolation. - | -w --watch Watch and re-run your scripts when they change + | [-b --banner ] Customize the welcome banner that gets shown when Ammonite starts + | [--bsp] Run a BSP server against the passed scripts + | [-c --code ] Pass in code to be run immediately in the REPL + | [--classBased] Wrap user code in classes rather than singletons, typically for Java + | serialization friendliness. + | [--color ] Enable or disable colored output; by default colors are enabled in both + | REPL and scripts if the console is interactive, and disabled otherwise + | [-h --home ] The home directory of the REPL; where it looks for config and caches + | [--help] Print this message + | [--no-default-predef] Disable the default predef and run Ammonite with the minimal predef + | possible + | [--no-home-predef] Disables the default behavior of loading predef files from your + | ~/.ammonite/predef.sc, predefScript.sc, or predefShared.sc. You can choose + | an additional predef to use using `--predef + | [--no-remote-logging] (deprecated) Disable remote logging of the number of times a REPL starts + | and runs commands + | [-p --predef ] Lets you load your predef from a custom location, rather than the default + | location in your Ammonite home + | [--predef-code ] Any commands you want to execute at the start of the REPL session + | [-s --silent] Make ivy logs go silent instead of printing though failures will still + | throw exception + | [--thin] Hide parts of the core of Ammonite and some of its dependencies. By + | default, the core of Ammonite and all of its dependencies can be seen by + | users from the Ammonite session. This option mitigates that via class + | loader isolation. + | [-w --watch] Watch and re-run your scripts when they change | rest ... |""".stripMargin.trim diff --git a/mainargs/test/src-jvm-2/MillTests.scala b/mainargs/test/src-jvm-2/MillTests.scala index c849fe9..1e8e324 100644 --- a/mainargs/test/src-jvm-2/MillTests.scala +++ b/mainargs/test/src-jvm-2/MillTests.scala @@ -95,35 +95,39 @@ object MillTests extends TestSuite { val expected = { """Mill Build Tool |usage: mill [mill-options] [target [target-options]] - | --repl Run Mill in interactive mode and start a build REPL. In this mode, no mill - | server will be used. Must be the first argument. - | --no-server Run Mill in interactive mode, suitable for opening REPLs and taking user - | input. In this mode, no mill server will be used. Must be the first argument. - | -i --interactive Run Mill in interactive mode, suitable for opening REPLs and taking user - | input. In this mode, no mill server will be used. Must be the first argument. - | -v --version Show mill version and exit. - | -b --bell Ring the bell once if the run completes successfully, twice if it fails. - | --disable-ticker Disable ticker log (e.g. short-lived prints of stages and progress bars) - | -d --debug Show debug output on STDOUT - | -k --keep-going Continue build, even after build failures - | -D --define Define (or overwrite) a system property - | -j --jobs Allow processing N targets in parallel. Use 1 to disable parallel and 0 to - | use as much threads as available processors. - | --no-default-predef Disable the default predef and run Ammonite with the minimal predef possible - | -s --silent Make ivy logs go silent instead of printing though failures will still throw - | exception - | -w --watch Watch and re-run your scripts when they change - | --bsp Run a BSP server against the passed scripts - | -c --code Pass in code to be run immediately in the REPL - | -h --home The home directory of the REPL; where it looks for config and caches - | -p --predef Lets you load your predef from a custom location, rather than the default - | location in your Ammonite home - | --color Enable or disable colored output; by default colors are enabled in both REPL - | and scripts if the console is interactive, and disabled otherwise - | --thin Hide parts of the core of Ammonite and some of its dependencies. By default, - | the core of Ammonite and all of its dependencies can be seen by users from - | the Ammonite session. This option mitigates that via class loader isolation. - | --help Print this message + | [--repl] Run Mill in interactive mode and start a build REPL. In this mode, no mill + | server will be used. Must be the first argument. + | [--no-server] Run Mill in interactive mode, suitable for opening REPLs and taking user + | input. In this mode, no mill server will be used. Must be the first + | argument. + | [-i --interactive] Run Mill in interactive mode, suitable for opening REPLs and taking user + | input. In this mode, no mill server will be used. Must be the first + | argument. + | [-v --version] Show mill version and exit. + | [-b --bell] Ring the bell once if the run completes successfully, twice if it fails. + | [--disable-ticker] Disable ticker log (e.g. short-lived prints of stages and progress bars) + | [-d --debug] Show debug output on STDOUT + | [-k --keep-going] Continue build, even after build failures + | [-D --define ]* Define (or overwrite) a system property + | [-j --jobs ] Allow processing N targets in parallel. Use 1 to disable parallel and 0 to + | use as much threads as available processors. + | [--no-default-predef] Disable the default predef and run Ammonite with the minimal predef + | possible + | [-s --silent] Make ivy logs go silent instead of printing though failures will still + | throw exception + | [-w --watch] Watch and re-run your scripts when they change + | [--bsp] Run a BSP server against the passed scripts + | [-c --code ] Pass in code to be run immediately in the REPL + | [-h --home ] The home directory of the REPL; where it looks for config and caches + | [-p --predef ] Lets you load your predef from a custom location, rather than the default + | location in your Ammonite home + | [--color ] Enable or disable colored output; by default colors are enabled in both + | REPL and scripts if the console is interactive, and disabled otherwise + | [--thin] Hide parts of the core of Ammonite and some of its dependencies. By + | default, the core of Ammonite and all of its dependencies can be seen by + | users from the Ammonite session. This option mitigates that via class + | loader isolation. + | [--help] Print this message |""".stripMargin } assert(rendered == expected) diff --git a/mainargs/test/src/CoreTests.scala b/mainargs/test/src/CoreTests.scala index 03e2aae..a1078da 100644 --- a/mainargs/test/src/CoreTests.scala +++ b/mainargs/test/src/CoreTests.scala @@ -39,12 +39,12 @@ class CoreTests(allowPositional: Boolean) extends TestSuite { | foo | | bar - | -i + | -i | | qux | Qux is a function that does stuff - | -i - | -s Pass in a custom `s` to override it + | -i + | [-s ] Pass in a custom `s` to override it | | ex |""".stripMargin diff --git a/mainargs/test/src/RendererTests.scala b/mainargs/test/src/RendererTests.scala new file mode 100644 index 0000000..bbfbe61 --- /dev/null +++ b/mainargs/test/src/RendererTests.scala @@ -0,0 +1,46 @@ +package mainargs +import utest._ + + +object RenderedTests extends TestSuite{ + @main + case class Config( + a: Int, + b: Int = 0, + c: Option[Int] = None, + d: Seq[Int], + e: Seq[Int] = Seq.empty, + @arg(doc = "this one has a doc") + a1: Int, + @arg(doc = "this one has a doc") + b1: Int = 0, + @arg(doc = "this one has a doc") + c1: Option[Int] = None, + @arg(doc = "this one has a doc") + d1: Seq[Int], + @arg(doc = "this one has a doc") + e1: Seq[Int] = Seq.empty + ) + val parser = ParserForClass[Config] + + val tests = Tests { + test("formatMainMethods"){ + val parsed = parser.helpText() + val expected = + """apply + | -a + | --a1 this one has a doc + | [-b ] + | [--b1 ] this one has a doc + | [-c ] + | [--c1 ] this one has a doc + | [-d ]* + | [--d1 ]* this one has a doc + | [-e ]* + | [--e1 ]* this one has a doc + |""".stripMargin + + parsed ==> expected + } + } +}