Call parse with errors

This commit is contained in:
Him188 2020-11-16 09:40:54 +08:00
parent 8da8615721
commit 64790d0114
6 changed files with 292 additions and 152 deletions

View File

@ -12,7 +12,10 @@
package net.mamoe.mirai.console.command
import net.mamoe.mirai.console.command.CommandExecuteResult.CommandExecuteStatus
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.descriptor.*
import net.mamoe.mirai.console.command.parse.CommandCall
import net.mamoe.mirai.console.command.parse.CommandValueArgument
import net.mamoe.mirai.console.command.resolve.ResolvedCommandCall
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.MessageChain
@ -37,6 +40,12 @@ public sealed class CommandExecuteResult {
/** 尝试执行的指令 (如果匹配到) */
public abstract val command: Command?
/** 解析的 [CommandCall] (如果匹配到) */
public abstract val call: CommandCall?
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
public abstract val resolvedCall: ResolvedCommandCall?
/** 尝试执行的指令名 (如果匹配到) */
public abstract val commandName: String?
@ -49,10 +58,14 @@ public sealed class CommandExecuteResult {
public class Success(
/** 尝试执行的指令 */
public override val command: Command,
/** 解析的 [CommandCall] (如果匹配到) */
public override val call: CommandCall,
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
public override val resolvedCall: ResolvedCommandCall,
/** 尝试执行的指令名 */
public override val commandName: String,
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
public override val args: MessageChain
public override val args: MessageChain,
) : CommandExecuteResult() {
/** 指令执行时发生的错误, 总是 `null` */
public override val exception: Nothing? get() = null
@ -61,61 +74,82 @@ public sealed class CommandExecuteResult {
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.SUCCESSFUL
}
/** 指令执行失败 */
public abstract class Failure : CommandExecuteResult()
/** 执行执行时发生了一个非法参数错误 */
public class IllegalArgument(
/** 指令执行时发生的错误 */
public override val exception: IllegalCommandArgumentException,
/** 尝试执行的指令 */
public override val command: Command,
/** 解析的 [CommandCall] (如果匹配到) */
public override val call: CommandCall,
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
public override val resolvedCall: ResolvedCommandCall,
/** 尝试执行的指令名 */
public override val commandName: String,
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
public override val args: MessageChain
) : CommandExecuteResult() {
public override val args: MessageChain,
) : Failure() {
/** 指令最终执行状态, 总是 [CommandExecuteStatus.EXECUTION_EXCEPTION] */
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.ILLEGAL_ARGUMENT
}
/** 指令执行过程出现了错误 */
/** 指令方法调用过程出现了错误 */
public class ExecutionFailed(
/** 指令执行时发生的错误 */
public override val exception: Throwable,
/** 尝试执行的指令 */
public override val command: Command,
/** 解析的 [CommandCall] (如果匹配到) */
public override val call: CommandCall,
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
public override val resolvedCall: ResolvedCommandCall,
/** 尝试执行的指令名 */
public override val commandName: String,
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
public override val args: MessageChain
) : CommandExecuteResult() {
public override val args: MessageChain,
) : Failure() {
/** 指令最终执行状态, 总是 [CommandExecuteStatus.EXECUTION_EXCEPTION] */
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.EXECUTION_EXCEPTION
}
/** 没有匹配的指令 */
public class UnresolvedCall(
public class UnresolvedCommand(
/** 尝试执行的指令名 */
public override val commandName: String,
) : CommandExecuteResult() {
) : Failure() {
/** 指令执行时发生的错误, 总是 `null` */
public override val exception: Nothing? get() = null
/** 尝试执行的指令, 总是 `null` */
public override val command: Nothing? get() = null
/** 解析的 [CommandCall] (如果匹配到) */
public override val call: CommandCall? get() = null
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
public override val resolvedCall: ResolvedCommandCall? get() = null
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
public override val args: Nothing? get() = null
/** 指令最终执行状态, 总是 [CommandExecuteStatus.COMMAND_NOT_FOUND] */
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.COMMAND_NOT_FOUND
/** 指令最终执行状态, 总是 [CommandExecuteStatus.UNRESOLVED_COMMAND] */
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.UNRESOLVED_COMMAND
}
/** 权限不足 */
public class PermissionDenied(
/** 尝试执行的指令 */
public override val command: Command,
/** 解析的 [CommandCall] (如果匹配到) */
public override val call: CommandCall,
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
public override val resolvedCall: ResolvedCommandCall,
/** 尝试执行的指令名 */
public override val commandName: String
) : CommandExecuteResult() {
public override val commandName: String,
) : Failure() {
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
public override val args: Nothing? get() = null
@ -126,6 +160,33 @@ public sealed class CommandExecuteResult {
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.PERMISSION_DENIED
}
/** 没有匹配的指令 */
public class UnmatchedSignature(
/** 尝试执行的指令名 */
public override val commandName: String,
/** 尝试执行的指令 */
public override val command: Command,
/** 尝试执行的指令 */
@ExperimentalCommandDescriptors
@ConsoleExperimentalApi
public val failureReasons: List<UnmatchedCommandSignature>,
) : Failure() {
/** 指令执行时发生的错误, 总是 `null` */
public override val exception: Nothing? get() = null
/** 解析的 [CommandCall] (如果匹配到) */
public override val call: CommandCall? get() = null
/** 解析的 [ResolvedCommandCall] (如果匹配到) */
public override val resolvedCall: ResolvedCommandCall? get() = null
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
public override val args: Nothing? get() = null
/** 指令最终执行状态, 总是 [CommandExecuteStatus.UNMATCHED_SIGNATURE] */
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.UNMATCHED_SIGNATURE
}
/**
* 指令的执行状态
*/
@ -137,15 +198,56 @@ public sealed class CommandExecuteResult {
EXECUTION_EXCEPTION,
/** 没有匹配的指令 */
COMMAND_NOT_FOUND,
UNMATCHED_SIGNATURE,
/** 没有匹配的指令 */
UNRESOLVED_COMMAND,
/** 权限不足 */
PERMISSION_DENIED,
/** 非法参数 */
ILLEGAL_ARGUMENT,
}
}
@ExperimentalCommandDescriptors
@ConsoleExperimentalApi
public class UnmatchedCommandSignature(
public val signature: CommandSignature,
public val failureReason: FailureReason,
)
@ExperimentalCommandDescriptors
@ConsoleExperimentalApi
public sealed class FailureReason {
public class InapplicableReceiverArgument(
public override val parameter: CommandReceiverParameter<*>,
public val argument: CommandSender,
) : InapplicableArgument()
public class InapplicableValueArgument(
public override val parameter: CommandValueParameter<*>,
public val argument: CommandValueArgument,
) : InapplicableArgument()
public abstract class InapplicableArgument : FailureReason() {
public abstract val parameter: CommandParameter<*>
}
public abstract class ArgumentLengthMismatch : FailureReason()
public data class ResolutionAmbiguity(
/**
* Including [self][UnmatchedCommandSignature.signature].
*/
public val allCandidates: List<CommandSignature>,
) : FailureReason()
public object TooManyArguments : ArgumentLengthMismatch()
public object NotEnoughArguments : ArgumentLengthMismatch()
}
@ExperimentalCommandDescriptors
@Suppress("RemoveRedundantQualifierName")
public typealias CommandExecuteStatus = CommandExecuteResult.CommandExecuteStatus
@ -164,59 +266,7 @@ public fun CommandExecuteResult.isSuccess(): Boolean {
}
/**
* [this] [CommandExecuteResult.IllegalArgument] 时返回 `true`
*/
@ExperimentalCommandDescriptors
@JvmSynthetic
public fun CommandExecuteResult.isIllegalArgument(): Boolean {
contract {
returns(true) implies (this@isIllegalArgument is CommandExecuteResult.IllegalArgument)
returns(false) implies (this@isIllegalArgument !is CommandExecuteResult.IllegalArgument)
}
return this is CommandExecuteResult.IllegalArgument
}
/**
* [this] [CommandExecuteResult.ExecutionFailed] 时返回 `true`
*/
@ExperimentalCommandDescriptors
@JvmSynthetic
public fun CommandExecuteResult.isExecutionException(): Boolean {
contract {
returns(true) implies (this@isExecutionException is CommandExecuteResult.ExecutionFailed)
returns(false) implies (this@isExecutionException !is CommandExecuteResult.ExecutionFailed)
}
return this is CommandExecuteResult.ExecutionFailed
}
/**
* [this] [CommandExecuteResult.PermissionDenied] 时返回 `true`
*/
@ExperimentalCommandDescriptors
@JvmSynthetic
public fun CommandExecuteResult.isPermissionDenied(): Boolean {
contract {
returns(true) implies (this@isPermissionDenied is CommandExecuteResult.PermissionDenied)
returns(false) implies (this@isPermissionDenied !is CommandExecuteResult.PermissionDenied)
}
return this is CommandExecuteResult.PermissionDenied
}
/**
* [this] [CommandExecuteResult.UnresolvedCall] 时返回 `true`
*/
@ExperimentalCommandDescriptors
@JvmSynthetic
public fun CommandExecuteResult.isCommandNotFound(): Boolean {
contract {
returns(true) implies (this@isCommandNotFound is CommandExecuteResult.UnresolvedCall)
returns(false) implies (this@isCommandNotFound !is CommandExecuteResult.UnresolvedCall)
}
return this is CommandExecuteResult.UnresolvedCall
}
/**
* [this] [CommandExecuteResult.ExecutionFailed], [CommandExecuteResult.IllegalArgument] [CommandExecuteResult.UnresolvedCall] 时返回 `true`
* [this] [CommandExecuteResult.ExecutionFailed], [CommandExecuteResult.IllegalArgument] , [CommandExecuteResult.UnmatchedSignature] [CommandExecuteResult.UnresolvedCommand] 时返回 `true`
*/
@ExperimentalCommandDescriptors
@JvmSynthetic

View File

@ -75,15 +75,15 @@ public sealed class ArgumentAcceptance(
) {
public object Direct : ArgumentAcceptance(Int.MAX_VALUE)
public class WithTypeConversion(
public data class WithTypeConversion(
public val typeVariant: TypeVariant<*>,
) : ArgumentAcceptance(20)
public class WithContextualConversion(
public data class WithContextualConversion(
public val parser: CommandValueArgumentParser<*>,
) : ArgumentAcceptance(10)
public class ResolutionAmbiguity(
public data class ResolutionAmbiguity(
public val candidates: List<TypeVariant<*>>,
) : ArgumentAcceptance(0)
@ -101,7 +101,7 @@ public sealed class ArgumentAcceptance(
}
@ExperimentalCommandDescriptors
public class CommandReceiverParameter<T : CommandSender>(
public data class CommandReceiverParameter<T : CommandSender>(
override val isOptional: Boolean,
override val type: KType,
) : CommandParameter<T>, AbstractCommandParameter<T>() {

View File

@ -9,9 +9,7 @@
package net.mamoe.mirai.console.command.resolve
import net.mamoe.mirai.console.command.Command
import net.mamoe.mirai.console.command.CommandManager
import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.command.*
import net.mamoe.mirai.console.command.descriptor.*
import net.mamoe.mirai.console.command.descriptor.ArgumentAcceptance.Companion.isNotAcceptable
import net.mamoe.mirai.console.command.parse.CommandCall
@ -35,13 +33,19 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
val valueArguments = call.valueArguments
val context = callee.safeCast<CommandArgumentContextAware>()?.context
val signature = resolveImpl(call.caller, callee, valueArguments, context) ?: return CommandResolveResult(null)
val errorSink = ErrorSink()
val signature = resolveImpl(call.caller, callee, valueArguments, context, errorSink) ?: kotlin.run {
return CommandResolveResult(errorSink.createFailure(call, callee))
}
return CommandResolveResult(ResolvedCommandCallImpl(call.caller,
callee,
signature.signature,
signature.zippedArguments.map { it.second },
context ?: EmptyCommandArgumentContext)
return CommandResolveResult(
ResolvedCommandCallImpl(
call.caller,
callee,
signature.signature,
signature.zippedArguments.map { it.second },
context ?: EmptyCommandArgumentContext
)
)
}
@ -59,76 +63,121 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
val acceptance: ArgumentAcceptance,
)
private class ErrorSink {
private val unmatchedCommandSignatures = mutableListOf<UnmatchedCommandSignature>()
private val resolutionAmbiguities = mutableListOf<CommandSignature>()
fun reportUnmatched(failure: UnmatchedCommandSignature) {
unmatchedCommandSignatures.add(failure)
}
fun reportAmbiguity(resolutionAmbiguity: CommandSignature) {
resolutionAmbiguities.add(resolutionAmbiguity)
}
fun createFailure(call: CommandCall, command: Command): CommandExecuteResult.Failure {
val failureReasons = unmatchedCommandSignatures.toMutableList()
val rA = FailureReason.ResolutionAmbiguity(resolutionAmbiguities)
failureReasons.addAll(resolutionAmbiguities.map { UnmatchedCommandSignature(it, rA) })
return CommandExecuteResult.UnmatchedSignature(call.calleeName, command, unmatchedCommandSignatures)
}
}
private
fun CommandSignature.toResolveData(
caller: CommandSender,
valueArguments: List<CommandValueArgument>,
context: CommandArgumentContext?,
errorSink: ErrorSink,
): ResolveData? {
val signature = this
val receiverParameter = signature.receiverParameter
if (receiverParameter?.type?.classifierAsKClass()?.isInstance(caller) == false) {
errorSink.reportUnmatched(
UnmatchedCommandSignature(signature, FailureReason.InapplicableReceiverArgument(receiverParameter, caller))
)// not compatible receiver
return null
}
val valueParameters = signature.valueParameters
val zipped = valueParameters.zip(valueArguments).toMutableList()
val remainingParameters = valueParameters.drop(zipped.size).toMutableList()
if (remainingParameters.any { !it.isOptional && !it.isVararg }) {
errorSink.reportUnmatched(UnmatchedCommandSignature(signature, FailureReason.NotEnoughArguments))// not enough args. // vararg can be empty.
return null
}
return if (zipped.isEmpty()) {
ResolveData(
signature = signature,
zippedArguments = emptyList(),
argumentAcceptances = emptyList(),
remainingParameters = remainingParameters,
)
} else {
if (valueArguments.size > valueParameters.size && zipped.last().first.isVararg) {
// merge vararg arguments
val (varargParameter, _)
= zipped.removeLast()
zipped.add(varargParameter to DefaultCommandValueArgument(valueArguments.drop(zipped.size).map { it.value }.asMessageChain()))
} else {
// add default empty vararg argument
val remainingVararg = remainingParameters.find { it.isVararg }
if (remainingVararg != null) {
zipped.add(remainingVararg to DefaultCommandValueArgument(EmptyMessageChain))
remainingParameters.remove(remainingVararg)
}
}
ResolveData(
signature = signature,
zippedArguments = zipped,
argumentAcceptances = zipped.mapIndexed { index, (parameter, argument) ->
val accepting = parameter.accepting(argument, context)
if (accepting.isNotAcceptable) {
errorSink.reportUnmatched(UnmatchedCommandSignature(signature,
FailureReason.InapplicableValueArgument(parameter, argument)))// argument type not assignable
return null
}
ArgumentAcceptanceWithIndex(index, accepting)
},
remainingParameters = remainingParameters
)
}
}
private fun resolveImpl(
caller: CommandSender,
callee: Command,
valueArguments: List<CommandValueArgument>,
context: CommandArgumentContext?,
errorSink: ErrorSink,
): ResolveData? {
callee.overloads
.mapNotNull l@{ signature ->
if (signature.receiverParameter?.type?.classifierAsKClass()?.isInstance(caller) == false) {
return@l null // not compatible receiver
}
val valueParameters = signature.valueParameters
val zipped = valueParameters.zip(valueArguments).toMutableList()
val remainingParameters = valueParameters.drop(zipped.size).toMutableList()
if (remainingParameters.any { !it.isOptional && !it.isVararg }) return@l null // not enough args. // vararg can be empty.
if (zipped.isEmpty()) {
ResolveData(
signature = signature,
zippedArguments = emptyList(),
argumentAcceptances = emptyList(),
remainingParameters = remainingParameters,
)
} else {
if (valueArguments.size > valueParameters.size && zipped.last().first.isVararg) {
// merge vararg arguments
val (varargParameter, _)
= zipped.removeLast()
zipped.add(varargParameter to DefaultCommandValueArgument(valueArguments.drop(zipped.size).map { it.value }.asMessageChain()))
} else {
// add default empty vararg argument
val remainingVararg = remainingParameters.find { it.isVararg }
if (remainingVararg != null) {
zipped.add(remainingVararg to DefaultCommandValueArgument(EmptyMessageChain))
remainingParameters.remove(remainingVararg)
}
}
ResolveData(
signature = signature,
zippedArguments = zipped,
argumentAcceptances = zipped.mapIndexed { index, (parameter, argument) ->
val accepting = parameter.accepting(argument, context)
if (accepting.isNotAcceptable) {
return@l null // argument type not assignable
}
ArgumentAcceptanceWithIndex(index, accepting)
},
remainingParameters = remainingParameters
)
}
signature.toResolveData(caller, valueArguments, context, errorSink)
}
.also { result -> result.singleOrNull()?.let { return it } }
.also { result -> result.takeSingleResolveData()?.let { return it } }
.takeLongestMatches()
.ifEmpty { return null }
.also { result -> result.singleOrNull()?.let { return it } }
.also { result -> result.takeSingleResolveData()?.let { return it } }
// take single ArgumentAcceptance.Direct
.also { list ->
val candidates = list
.asSequence().filterIsInstance<ResolveData>()
.flatMap { phase ->
phase.argumentAcceptances.filter { it.acceptance is ArgumentAcceptance.Direct }.map { phase to it }
}
}.toList()
candidates.singleOrNull()?.let { return it.first } // single Direct
if (candidates.distinctBy { it.second.index }.size != candidates.size) {
// Resolution ambiguity
/*
@ -142,13 +191,17 @@ public object BuiltInCommandCallResolver : CommandCallResolver {
fun foo(a: AA, c: C) = 1
*/
// The call is foo(AA(), C()) or foo(A(), CC())
return null
candidates.forEach { candidate -> errorSink.reportAmbiguity(candidate.first.signature) }
}
}
return null
}
private fun Collection<Any>.takeSingleResolveData() = asSequence().filterIsInstance<ResolveData>().singleOrNull()
/*

View File

@ -40,9 +40,9 @@ public class CommandResolveResult private constructor(
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
callsInPlace(onFailure, InvocationKind.AT_MOST_ONCE)
}
call?.let(onSuccess)
failure?.let(onFailure)
null!!
call?.let(onSuccess)?.let { return it }
failure?.let(onFailure)?.let { return it }
throw kotlin.AssertionError()
}
public constructor(call: ResolvedCommandCall?) : this(call as Any?)

View File

@ -17,6 +17,7 @@ import net.mamoe.mirai.console.command.*
import net.mamoe.mirai.console.command.Command.Companion.allNames
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.findDuplicate
import net.mamoe.mirai.console.command.CommandSender.Companion.toCommandSender
import net.mamoe.mirai.console.command.descriptor.CommandArgumentParserException
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.parse.CommandCallParser.Companion.parseCommandCall
import net.mamoe.mirai.console.command.resolve.CommandCallResolver.Companion.resolve
@ -94,7 +95,9 @@ internal object CommandManagerImpl : CommandManager, CoroutineScope by MiraiCons
sender.catchExecutionException(result.exception)
intercept()
}
is CommandExecuteResult.UnresolvedCall -> {
is CommandExecuteResult.UnmatchedSignature,
is CommandExecuteResult.UnresolvedCommand,
-> {
// noop
}
}
@ -175,20 +178,25 @@ internal suspend fun executeCommandImpl(
caller: CommandSender,
checkPermission: Boolean,
): CommandExecuteResult {
val call = message.asMessageChain().parseCommandCall(caller) ?: return CommandExecuteResult.UnresolvedCall("")
val resolved = call.resolve() ?: return CommandExecuteResult.UnresolvedCall(call.calleeName)
val call = message.asMessageChain().parseCommandCall(caller) ?: return CommandExecuteResult.UnresolvedCommand("")
val resolved = call.resolve().fold(
onSuccess = { it },
onFailure = { return it }
)
val command = resolved.callee
if (checkPermission && !command.permission.testPermission(caller)) {
return CommandExecuteResult.PermissionDenied(command, call.calleeName)
return CommandExecuteResult.PermissionDenied(command, call, resolved, call.calleeName)
}
return try {
resolved.calleeSignature.call(resolved)
CommandExecuteResult.Success(resolved.callee, call.calleeName, EmptyMessageChain)
CommandExecuteResult.Success(resolved.callee, call, resolved, call.calleeName, EmptyMessageChain)
} catch (e: CommandArgumentParserException) {
CommandExecuteResult.IllegalArgument(e, resolved.callee, call, resolved, call.calleeName, EmptyMessageChain)
} catch (e: Throwable) {
CommandExecuteResult.ExecutionFailed(e, resolved.callee, call.calleeName, EmptyMessageChain)
CommandExecuteResult.ExecutionFailed(e, resolved.callee, call, resolved, call.calleeName, EmptyMessageChain)
}
}

View File

@ -12,11 +12,14 @@ package net.mamoe.mirai.console.terminal
import kotlinx.coroutines.*
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.command.*
import net.mamoe.mirai.console.command.CommandExecuteResult.*
import net.mamoe.mirai.console.command.CommandExecuteResult.CommandExecuteStatus.*
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.terminal.noconsole.NoConsole
import net.mamoe.mirai.console.util.ConsoleInternalApi
import net.mamoe.mirai.console.util.requestInput
import net.mamoe.mirai.utils.DefaultLogger
import net.mamoe.mirai.utils.warning
import org.jline.reader.EndOfFileException
import org.jline.reader.UserInterruptException
@ -55,21 +58,28 @@ internal fun startupConsoleThread() {
continue
}
// consoleLogger.debug("INPUT> $next")
val result = ConsoleCommandSender.executeCommand(next)
when (result.status) {
CommandExecuteStatus.SUCCESSFUL -> {
when (val result = ConsoleCommandSender.executeCommand(next)) {
is Success -> {
}
CommandExecuteStatus.ILLEGAL_ARGUMENT -> {
result.exception?.message?.let { consoleLogger.warning(it) }
is IllegalArgument -> {
result.exception.message?.let { consoleLogger.warning(it) } ?: kotlin.run {
consoleLogger.warning(result.exception)
}
}
CommandExecuteStatus.EXECUTION_EXCEPTION -> {
result.exception?.let(consoleLogger::error)
is ExecutionFailed -> {
consoleLogger.error(result.exception)
}
CommandExecuteStatus.COMMAND_NOT_FOUND -> {
consoleLogger.warning("未知指令: ${result.commandName}, 输入 ? 获取帮助")
is UnresolvedCommand -> {
consoleLogger.warning { "未知指令: ${result.commandName}, 输入 ? 获取帮助" }
}
CommandExecuteStatus.PERMISSION_DENIED -> {
consoleLogger.warning("Permission denied.")
is PermissionDenied -> {
consoleLogger.warning { "权限不足." }
}
is UnmatchedSignature -> {
consoleLogger.warning { "参数不匹配: " + result.failureReasons.joinToString("\n") { it.render() } }
}
is Failure -> {
consoleLogger.warning { result.toString() }
}
}
} catch (e: InterruptedException) {
@ -88,3 +98,22 @@ internal fun startupConsoleThread() {
}
}
}
@OptIn(ExperimentalCommandDescriptors::class)
internal fun UnmatchedCommandSignature.render(): String {
return this.signature.toString() + " ${failureReason.render()}"
}
@OptIn(ExperimentalCommandDescriptors::class)
internal fun FailureReason.render(): String {
return when (this) {
is FailureReason.InapplicableArgument -> "参数类型错误"
is FailureReason.TooManyArguments -> "参数过多"
is FailureReason.NotEnoughArguments -> "参数不足"
is FailureReason.ResolutionAmbiguity -> "调用歧义"
is FailureReason.ArgumentLengthMismatch -> {
// should not happen, render it anyway.
"参数长度不匹配"
}
}
}