improve command handling, change argument/option registration
This commit is contained in:
@@ -14,18 +14,18 @@ internal class ContextParser(
|
||||
) : Result()
|
||||
|
||||
data class Help(
|
||||
val command: Command,
|
||||
val path: List<Command>,
|
||||
) : Result()
|
||||
|
||||
data class Failure(
|
||||
val command: Command,
|
||||
val path: List<Command>,
|
||||
val error: RunError,
|
||||
) : Result()
|
||||
}
|
||||
|
||||
private fun success(context: Context) = Result.Success(context)
|
||||
private fun help(command: Command) = Result.Help(command)
|
||||
private fun failure(command: Command, exception: RunError) = Result.Failure(command, exception)
|
||||
private fun help(path: List<Command>) = Result.Help(path)
|
||||
private fun failure(path: List<Command>, exception: RunError) = Result.Failure(path, exception)
|
||||
|
||||
private var index = 0
|
||||
private val current: String
|
||||
@@ -41,6 +41,7 @@ internal class ContextParser(
|
||||
fun parse(): Result {
|
||||
// command
|
||||
var command = root
|
||||
val path = mutableListOf(root)
|
||||
val commands = mutableMapOf<Command.Fallback.Key<*>, Any>()
|
||||
|
||||
while (hasNext()) {
|
||||
@@ -52,16 +53,17 @@ internal class ContextParser(
|
||||
}
|
||||
if (cmd == null) {
|
||||
when {
|
||||
command.arguments.isEmpty() -> return failure(command, UnknownCommand(current))
|
||||
command.arguments.isEmpty() -> return failure(path, UnknownCommand(current))
|
||||
else -> break
|
||||
}
|
||||
}
|
||||
|
||||
command = cmd
|
||||
path += cmd
|
||||
if (cmd is Command.Fallback<*>) {
|
||||
val value = when (val result = cmd.parser.parse(current)) {
|
||||
is Parser.Result.Success<*> -> result.value
|
||||
is Parser.Result.Failure<*> -> return failure(command, result.error)
|
||||
is Parser.Result.Failure<*> -> return failure(path, result.error)
|
||||
}
|
||||
commands[cmd.key] = value
|
||||
}
|
||||
@@ -85,11 +87,11 @@ internal class ContextParser(
|
||||
// argument
|
||||
endOfOptions || dashes == 0 -> {
|
||||
val argument = command.arguments.getOrNull(argumentIndex)
|
||||
?: return failure(command, UnexpectedArgument())
|
||||
?: return failure(path, UnexpectedArgument())
|
||||
|
||||
val value = when (val result = argument.parser.parse(trimmed)) {
|
||||
is Parser.Result.Success<*> -> result.value
|
||||
is Parser.Result.Failure<*> -> return failure(command, result.error)
|
||||
is Parser.Result.Failure<*> -> return failure(path, result.error)
|
||||
}
|
||||
arguments[argument]!! += value
|
||||
argumentCount++
|
||||
@@ -109,7 +111,7 @@ internal class ContextParser(
|
||||
}
|
||||
|
||||
if (dashes == 2 && trimmed == "help")
|
||||
return help(command)
|
||||
return help(path)
|
||||
|
||||
val (name, text) = when {
|
||||
trimmed.contains('=') -> {
|
||||
@@ -133,16 +135,16 @@ internal class ContextParser(
|
||||
|
||||
for (name in names) {
|
||||
val option = command.options.firstOrNull { name in it.names }
|
||||
?: return failure(command, UnknownOption(name))
|
||||
?: return failure(path, UnknownOption(name))
|
||||
|
||||
val value = when {
|
||||
text != null ->
|
||||
when (val result = option.parser.parse(current)) {
|
||||
is Parser.Result.Success<*> -> result.value
|
||||
is Parser.Result.Failure<*> -> return failure(command, result.error)
|
||||
is Parser.Result.Failure<*> -> return failure(path, result.error)
|
||||
}
|
||||
option.flag -> option.fallback!!
|
||||
else -> return failure(command, MissingOptionValue(option))
|
||||
else -> return failure(path, MissingOptionValue(option))
|
||||
}
|
||||
options[option]!! += value
|
||||
}
|
||||
@@ -153,9 +155,9 @@ internal class ContextParser(
|
||||
when {
|
||||
current.contains('=') -> {
|
||||
val (option) = current.split('=', limit = 2)
|
||||
return failure(command, MalformedOption(option))
|
||||
return failure(path, MalformedOption(option))
|
||||
}
|
||||
else -> return failure(command, MalformedOption(current))
|
||||
else -> return failure(path, MalformedOption(current))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,16 +168,16 @@ internal class ContextParser(
|
||||
// validate arguments
|
||||
for (argument in command.arguments) {
|
||||
val count = arguments[argument]!!.count()
|
||||
if (count !in argument.min..argument.count) return failure(command, InvalidArgumentCount(argument, count))
|
||||
if (count !in argument.min..argument.count) return failure(path, InvalidArgumentCount(argument, count))
|
||||
}
|
||||
|
||||
// validate options
|
||||
for (option in command.options) {
|
||||
val count = options[option]!!.count()
|
||||
if (count !in option.min..option.count) return failure(command, InvalidOptionCount(option, count))
|
||||
if (count !in option.min..option.count) return failure(path, InvalidOptionCount(option, count))
|
||||
}
|
||||
|
||||
val context = Context(command, commands, arguments, options)
|
||||
val context = Context(path, commands, arguments, options)
|
||||
return success(context)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user