Skip to content

Commit 7ad88e0

Browse files
author
LepilkinaElena
authored
Added subcommands list to help message (#21)
1 parent 7ca224f commit 7ad88e0

File tree

3 files changed

+61
-8
lines changed

3 files changed

+61
-8
lines changed

core/commonMain/src/ArgParser.kt

+12-1
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,14 @@ interface ArgumentValueDelegate<T> {
7171
* Abstract base class for subcommands.
7272
*/
7373
@ExperimentalCli
74-
abstract class Subcommand(val name: String): ArgParser(name) {
74+
abstract class Subcommand(val name: String, val actionDescription: String): ArgParser(name) {
7575
/**
7676
* Execute action if subcommand was provided.
7777
*/
7878
abstract fun execute()
79+
80+
val helpMessage: String
81+
get() = " $name - $actionDescription\n"
7982
}
8083

8184
/**
@@ -373,6 +376,7 @@ open class ArgParser(
373376

374377
protected fun parse(args: List<String>): ArgParserResult {
375378
check(parsingState == null) { "Parsing of command line options can be called only once." }
379+
376380
// Add help option.
377381
val helpDescriptor = if (useDefaultHelpShortName) OptionDescriptor<Boolean, Boolean>(
378382
optionFullFormPrefix,
@@ -513,6 +517,13 @@ open class ArgParser(
513517
internal fun makeUsage(): String {
514518
val result = StringBuilder()
515519
result.append("Usage: ${fullCommandName.joinToString(" ")} options_list\n")
520+
if (subcommands.isNotEmpty()) {
521+
result.append("Subcommands: \n")
522+
subcommands.forEach { (_, subcommand) ->
523+
result.append(subcommand.helpMessage)
524+
}
525+
result.append("\n")
526+
}
516527
if (arguments.isNotEmpty()) {
517528
result.append("Arguments: \n")
518529
arguments.forEach {

core/commonTest/src/HelpTests.kt

+43-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Options:
4848

4949
@Test
5050
fun testHelpForSubcommands() {
51-
class Summary: Subcommand("summary") {
51+
class Summary: Subcommand("summary", "Get summary information") {
5252
val exec by option(ArgType.Choice(listOf("samples", "geomean")),
5353
description = "Execution time way of calculation").default("geomean")
5454
val execSamples by option(ArgType.String, "exec-samples",
@@ -96,6 +96,48 @@ Options:
9696
--codesize-normalize -> File with golden results which should be used for normalization { String }
9797
--user, -u -> User access information for authorization { String }
9898
--help, -h -> Usage info
99+
""".trimIndent()
100+
assertEquals(expectedOutput, helpOutput)
101+
}
102+
103+
@Test
104+
fun testHelpMessageWithSubcommands() {
105+
abstract class CommonOptions(name: String, actionDescription: String): Subcommand(name, actionDescription) {
106+
val numbers by argument(ArgType.Int, "numbers", description = "Numbers").vararg()
107+
}
108+
class Summary: CommonOptions("summary", "Calculate summary") {
109+
val invert by option(ArgType.Boolean, "invert", "i", "Invert results")
110+
var result: Int = 0
111+
112+
override fun execute() {
113+
result = numbers.sum()
114+
result = invert?.let { -1 * result } ?: result
115+
}
116+
}
117+
118+
class Subtraction : CommonOptions("sub", "Calculate subtraction") {
119+
var result: Int = 0
120+
121+
override fun execute() {
122+
result = numbers.map { -it }.sum()
123+
}
124+
}
125+
126+
val summaryAction = Summary()
127+
val subtractionAction = Subtraction()
128+
val argParser = ArgParser("testParser")
129+
argParser.subcommands(summaryAction, subtractionAction)
130+
argParser.parse(emptyArray())
131+
val helpOutput = argParser.makeUsage().trimIndent()
132+
println(helpOutput)
133+
val expectedOutput = """
134+
Usage: testParser options_list
135+
Subcommands:
136+
summary - Calculate summary
137+
sub - Calculate subtraction
138+
139+
Options:
140+
--help, -h -> Usage info
99141
""".trimIndent()
100142
assertEquals(expectedOutput, helpOutput)
101143
}

core/commonTest/src/SubcommandsTests.kt

+6-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class SubcommandsTests {
1616
fun testSubcommand() {
1717
val argParser = ArgParser("testParser")
1818
val output by argParser.option(ArgType.String, "output", "o", "Output file")
19-
class Summary: Subcommand("summary") {
19+
class Summary: Subcommand("summary", "Calculate summary") {
2020
val invert by option(ArgType.Boolean, "invert", "i", "Invert results")
2121
val addendums by argument(ArgType.Int, "addendums", description = "Addendums").vararg()
2222
var result: Int = 0
@@ -35,10 +35,10 @@ class SubcommandsTests {
3535

3636
@Test
3737
fun testCommonOptions() {
38-
abstract class CommonOptions(name: String): Subcommand(name) {
38+
abstract class CommonOptions(name: String, actionDescription: String): Subcommand(name, actionDescription) {
3939
val numbers by argument(ArgType.Int, "numbers", description = "Numbers").vararg()
4040
}
41-
class Summary: CommonOptions("summary") {
41+
class Summary: CommonOptions("summary", "Calculate summary") {
4242
val invert by option(ArgType.Boolean, "invert", "i", "Invert results")
4343
var result: Int = 0
4444

@@ -48,7 +48,7 @@ class SubcommandsTests {
4848
}
4949
}
5050

51-
class Subtraction : CommonOptions("sub") {
51+
class Subtraction : CommonOptions("sub", "Calculate subtraction") {
5252
var result: Int = 0
5353

5454
override fun execute() {
@@ -73,7 +73,7 @@ class SubcommandsTests {
7373
fun testRecursiveSubcommands() {
7474
val argParser = ArgParser("testParser")
7575

76-
class Summary: Subcommand("summary") {
76+
class Summary: Subcommand("summary", "Calculate summary") {
7777
val addendums by argument(ArgType.Int, "addendums", description = "Addendums").vararg()
7878
var result: Int = 0
7979

@@ -82,7 +82,7 @@ class SubcommandsTests {
8282
}
8383
}
8484

85-
class Calculation: Subcommand("calc") {
85+
class Calculation: Subcommand("calc", "Execute calculation") {
8686
init {
8787
subcommands(Summary())
8888
}

0 commit comments

Comments
 (0)