mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Fix command call
This commit is contained in:
parent
4c30e3d9d7
commit
084e2c5c55
@ -90,9 +90,9 @@ public sealed class CommandExecuteResult {
|
||||
}
|
||||
|
||||
/** 没有匹配的指令 */
|
||||
public class CommandNotFound(
|
||||
public class UnresolvedCall(
|
||||
/** 尝试执行的指令名 */
|
||||
public override val commandName: String
|
||||
public override val commandName: String,
|
||||
) : CommandExecuteResult() {
|
||||
/** 指令执行时发生的错误, 总是 `null` */
|
||||
public override val exception: Nothing? get() = null
|
||||
@ -196,19 +196,19 @@ public fun CommandExecuteResult.isPermissionDenied(): Boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* 当 [this] 为 [CommandExecuteResult.CommandNotFound] 时返回 `true`
|
||||
* 当 [this] 为 [CommandExecuteResult.UnresolvedCall] 时返回 `true`
|
||||
*/
|
||||
@JvmSynthetic
|
||||
public fun CommandExecuteResult.isCommandNotFound(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isCommandNotFound is CommandExecuteResult.CommandNotFound)
|
||||
returns(false) implies (this@isCommandNotFound !is CommandExecuteResult.CommandNotFound)
|
||||
returns(true) implies (this@isCommandNotFound is CommandExecuteResult.UnresolvedCall)
|
||||
returns(false) implies (this@isCommandNotFound !is CommandExecuteResult.UnresolvedCall)
|
||||
}
|
||||
return this is CommandExecuteResult.CommandNotFound
|
||||
return this is CommandExecuteResult.UnresolvedCall
|
||||
}
|
||||
|
||||
/**
|
||||
* 当 [this] 为 [CommandExecuteResult.ExecutionFailed], [CommandExecuteResult.IllegalArgument] 或 [CommandExecuteResult.CommandNotFound] 时返回 `true`
|
||||
* 当 [this] 为 [CommandExecuteResult.ExecutionFailed], [CommandExecuteResult.IllegalArgument] 或 [CommandExecuteResult.UnresolvedCall] 时返回 `true`
|
||||
*/
|
||||
@JvmSynthetic
|
||||
public fun CommandExecuteResult.isFailure(): Boolean {
|
||||
|
@ -228,8 +228,8 @@ internal suspend fun executeCommandImpl(
|
||||
caller: CommandSender,
|
||||
checkPermission: Boolean,
|
||||
): CommandExecuteResult = with(receiver) {
|
||||
val call = message.asMessageChain().parseCommandCall(caller) ?: return CommandExecuteResult.CommandNotFound("")
|
||||
val resolved = call.resolve() ?: return CommandExecuteResult.CommandNotFound(call.calleeName)
|
||||
val call = message.asMessageChain().parseCommandCall(caller) ?: return CommandExecuteResult.UnresolvedCall("")
|
||||
val resolved = call.resolve() ?: return CommandExecuteResult.UnresolvedCall(call.calleeName)
|
||||
|
||||
val command = resolved.callee
|
||||
|
||||
|
@ -62,12 +62,16 @@ public abstract class SimpleCommand(
|
||||
CommandArgumentContextAware {
|
||||
|
||||
@ExperimentalCommandDescriptors
|
||||
override val overloads: List<CommandSignatureVariant> = listOf(
|
||||
CommandSignatureVariantImpl(listOf(CommandValueParameter.UserDefinedType.createRequired<MessageChain>("args", true))) { call ->
|
||||
override val overloads: List<CommandSignatureVariant> by lazy {
|
||||
CommandSignatureVariantImpl(
|
||||
valueParameters = subCommands.single().params.map {
|
||||
CommandValueParameter.UserDefinedType(it.name, null, isOptional = false, isVararg = false, type = it.type)
|
||||
}
|
||||
) { call ->
|
||||
val sender = call.caller
|
||||
subCommands.single().onCommand(sender, call.resolvedValueArguments)
|
||||
}
|
||||
)
|
||||
}.let { listOf(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动根据带有 [Handler] 注解的函数签名生成 [usage]. 也可以被覆盖.
|
||||
|
@ -81,7 +81,7 @@ internal object CommandManagerImpl : CommandManager, CoroutineScope by MiraiCons
|
||||
sender.catchExecutionException(result.exception)
|
||||
intercept()
|
||||
}
|
||||
is CommandExecuteResult.CommandNotFound -> {
|
||||
is CommandExecuteResult.UnresolvedCall -> {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
@ -140,11 +140,11 @@ internal object CommandManagerImpl : CommandManager, CoroutineScope by MiraiCons
|
||||
override fun Command.unregister(): Boolean = modifyLock.withLock {
|
||||
if (this.prefixOptional) {
|
||||
this.allNames.forEach {
|
||||
optionalPrefixCommandMap.remove(it)
|
||||
optionalPrefixCommandMap.remove(it.toLowerCase())
|
||||
}
|
||||
}
|
||||
this.allNames.forEach {
|
||||
requiredPrefixCommandMap.remove(it)
|
||||
requiredPrefixCommandMap.remove(it.toLowerCase())
|
||||
}
|
||||
_registeredCommands.remove(this)
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ package net.mamoe.mirai.console.internal.command
|
||||
|
||||
import net.mamoe.mirai.console.command.*
|
||||
import net.mamoe.mirai.console.command.descriptor.*
|
||||
import net.mamoe.mirai.console.internal.command.hasAnnotation
|
||||
import net.mamoe.mirai.console.permission.Permission
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
@ -22,10 +23,7 @@ import kotlin.reflect.KAnnotatedElement
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.KParameter
|
||||
import kotlin.reflect.full.callSuspendBy
|
||||
import kotlin.reflect.full.declaredFunctions
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.*
|
||||
|
||||
internal object CompositeCommandSubCommandAnnotationResolver :
|
||||
AbstractReflectionCommand.SubCommandAnnotationResolver {
|
||||
@ -322,7 +320,9 @@ internal fun AbstractReflectionCommand.createSubCommand(
|
||||
subDescription, // overridePermission?.value
|
||||
permission,//overridePermission?.value?.let { PermissionService.INSTANCE[PermissionId.parseFromString(it)] } ?: permission,
|
||||
onCommand = { _: CommandSender, args ->
|
||||
val result = function.callSuspendBy(parameters.zip(args).toMap())
|
||||
val p = parameters.zip(args).toMap(LinkedHashMap())
|
||||
if (notStatic) p[function.instanceParameter!!] = this@createSubCommand
|
||||
val result = function.callSuspendBy(p)
|
||||
|
||||
checkNotNull(result) { "sub command return value is null (at ${this::class.qualifiedName}.${function.name})" }
|
||||
|
||||
|
@ -73,6 +73,7 @@ internal class TestCommand {
|
||||
fun testRegister() {
|
||||
try {
|
||||
ConsoleCommandOwner.unregisterAllCommands() // builtins
|
||||
TestSimpleCommand.unregister()
|
||||
|
||||
assertTrue(TestCompositeCommand.register())
|
||||
assertFalse(TestCompositeCommand.register())
|
||||
@ -80,7 +81,9 @@ internal class TestCommand {
|
||||
assertEquals(1, ConsoleCommandOwner.registeredCommands.size)
|
||||
|
||||
assertEquals(1, CommandManagerImpl._registeredCommands.size)
|
||||
assertEquals(2, CommandManagerImpl.requiredPrefixCommandMap.size)
|
||||
assertEquals(2,
|
||||
CommandManagerImpl.requiredPrefixCommandMap.size,
|
||||
CommandManagerImpl.requiredPrefixCommandMap.entries.joinToString { it.toString() })
|
||||
} finally {
|
||||
TestCompositeCommand.unregister()
|
||||
}
|
||||
@ -107,24 +110,28 @@ internal class TestCommand {
|
||||
|
||||
@Test
|
||||
fun testSimpleArgsSplitting() = runBlocking {
|
||||
assertEquals(arrayOf("test", "ttt", "tt").joinToString(), withTesting<MessageChain> {
|
||||
assertSuccess(TestSimpleCommand.execute(sender, PlainText("test ttt tt")))
|
||||
}.joinToString())
|
||||
TestSimpleCommand.withRegistration {
|
||||
assertEquals(arrayOf("test", "ttt", "tt").joinToString(), withTesting<MessageChain> {
|
||||
assertSuccess(TestSimpleCommand.execute(sender, PlainText("test ttt tt")))
|
||||
}.joinToString())
|
||||
}
|
||||
}
|
||||
|
||||
val image = Image("/f8f1ab55-bf8e-4236-b55e-955848d7069f")
|
||||
|
||||
@Test
|
||||
fun `PlainText and Image args splitting`() = runBlocking {
|
||||
val result = withTesting<MessageChain> {
|
||||
assertSuccess(TestSimpleCommand.execute(sender, buildMessageChain {
|
||||
+"test"
|
||||
+image
|
||||
+"tt"
|
||||
}))
|
||||
TestSimpleCommand.withRegistration {
|
||||
val result = withTesting<MessageChain> {
|
||||
assertSuccess(TestSimpleCommand.execute(sender, buildMessageChain {
|
||||
+"test"
|
||||
+image
|
||||
+"tt"
|
||||
}))
|
||||
}
|
||||
assertEquals<Any>(arrayOf("test", image, "tt").joinToString(), result.toTypedArray().joinToString())
|
||||
assertSame(image, result[1])
|
||||
}
|
||||
assertEquals<Any>(arrayOf("test", image, "tt").joinToString(), result.toTypedArray().joinToString())
|
||||
assertSame(image, result[1])
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -147,9 +154,11 @@ internal class TestCommand {
|
||||
|
||||
@Test
|
||||
fun `composite command executing`() = runBlocking {
|
||||
assertEquals(1, withTesting {
|
||||
assertSuccess(TestCompositeCommand.execute(sender, "mute 1"))
|
||||
})
|
||||
TestCompositeCommand.withRegistration {
|
||||
assertEquals(1, withTesting {
|
||||
assertSuccess(TestCompositeCommand.execute(sender, "mute 1"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -187,7 +196,7 @@ internal class TestCommand {
|
||||
fun `composite sub command parsing`() {
|
||||
runBlocking {
|
||||
class MyClass(
|
||||
val value: Int
|
||||
val value: Int,
|
||||
)
|
||||
|
||||
val composite = object : CompositeCommand(
|
||||
@ -215,10 +224,12 @@ internal class TestCommand {
|
||||
composite.withRegistration {
|
||||
assertEquals(333, withTesting<MyClass> { execute(sender, "mute 333") }.value)
|
||||
assertEquals(2, withTesting<MyClass> {
|
||||
execute(sender, buildMessageChain {
|
||||
+"mute"
|
||||
+image
|
||||
})
|
||||
assertSuccess(
|
||||
execute(sender, buildMessageChain {
|
||||
+"mute"
|
||||
+image
|
||||
})
|
||||
)
|
||||
}.value)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user