Review command

This commit is contained in:
Him188 2020-10-24 21:19:50 +08:00
parent d10f2b4bea
commit b9580ffcbd
7 changed files with 212 additions and 155 deletions

View File

@ -11,7 +11,6 @@
package net.mamoe.mirai.console.command package net.mamoe.mirai.console.command
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
import net.mamoe.mirai.console.command.descriptor.CommandArgumentContextAware import net.mamoe.mirai.console.command.descriptor.CommandArgumentContextAware
import net.mamoe.mirai.console.command.descriptor.CommandSignatureVariant import net.mamoe.mirai.console.command.descriptor.CommandSignatureVariant
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
@ -25,7 +24,7 @@ import net.mamoe.mirai.console.util.ConsoleExperimentalApi
/** /**
* 指令 * 指令
* *
* @see CommandManager.register 注册这个指令 * @see CommandManager.registerCommand 注册这个指令
* *
* @see RawCommand 无参数解析, 接收原生参数的指令 * @see RawCommand 无参数解析, 接收原生参数的指令
* @see CompositeCommand 复合指令 * @see CompositeCommand 复合指令
@ -52,7 +51,7 @@ public interface Command {
public val secondaryNames: Array<out String> public val secondaryNames: Array<out String>
/** /**
* * 指令可能的参数列表.
*/ */
@ConsoleExperimentalApi("Property name is experimental") @ConsoleExperimentalApi("Property name is experimental")
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
@ -64,12 +63,12 @@ public interface Command {
public val usage: String public val usage: String
/** /**
* 指令描述, 用于显示在 [BuiltInCommands.HelpCommand] * 描述, 用于显示在 [BuiltInCommands.HelpCommand]
*/ */
public val description: String public val description: String
/** /**
* 此指令分配的权限. * 此指令分配的权限.
* *
* ### 实现约束 * ### 实现约束
* - [Permission.id] 应由 [CommandOwner.permissionId] 创建. 因此保证相同的 [PermissionId.namespace] * - [Permission.id] 应由 [CommandOwner.permissionId] 创建. 因此保证相同的 [PermissionId.namespace]
@ -82,6 +81,8 @@ public interface Command {
* *
* 会影响聊天语境中的解析. * 会影响聊天语境中的解析.
*/ */
@ExperimentalCommandDescriptors
@ConsoleExperimentalApi
public val prefixOptional: Boolean public val prefixOptional: Boolean
/** /**
@ -109,7 +110,7 @@ public interface Command {
public fun checkCommandName(@ResolveContext(COMMAND_NAME) name: String) { public fun checkCommandName(@ResolveContext(COMMAND_NAME) name: String) {
when { when {
name.isBlank() -> throw IllegalArgumentException("Command name should not be blank.") name.isBlank() -> throw IllegalArgumentException("Command name should not be blank.")
name.any { it.isWhitespace() } -> throw IllegalArgumentException("Spaces is not yet allowed in command name.") name.any { it.isWhitespace() } -> throw IllegalArgumentException("Spaces are not yet allowed in command name.")
name.contains(':') -> throw IllegalArgumentException("':' is forbidden in command name.") name.contains(':') -> throw IllegalArgumentException("':' is forbidden in command name.")
name.contains('.') -> throw IllegalArgumentException("'.' is forbidden in command name.") name.contains('.') -> throw IllegalArgumentException("'.' is forbidden in command name.")
} }

View File

@ -20,27 +20,17 @@ import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.parse.CommandCall import net.mamoe.mirai.console.command.parse.CommandCall
import net.mamoe.mirai.console.command.parse.CommandCallParser import net.mamoe.mirai.console.command.parse.CommandCallParser
import net.mamoe.mirai.console.command.parse.CommandCallParser.Companion.parseCommandCall
import net.mamoe.mirai.console.command.resolve.CommandCallResolver import net.mamoe.mirai.console.command.resolve.CommandCallResolver
import net.mamoe.mirai.console.command.resolve.ResolvedCommandCall
import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
import net.mamoe.mirai.console.internal.command.CommandManagerImpl import net.mamoe.mirai.console.internal.command.CommandManagerImpl
import net.mamoe.mirai.console.internal.command.CommandManagerImpl.executeCommand import net.mamoe.mirai.console.internal.command.CommandManagerImpl.executeCommand
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage import net.mamoe.mirai.console.internal.command.executeCommandImpl
import net.mamoe.mirai.console.permission.PermissionService.Companion.testPermission import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
/** /**
* 指令管理器 * 指令管理器
*/ */
public interface CommandManager { public interface CommandManager {
/**
* 获取已经注册了的属于这个 [CommandOwner] 的指令列表.
*
* @return 这一时刻的浅拷贝.
*/
public val CommandOwner.registeredCommands: List<Command>
/** /**
* 获取所有已经注册了指令列表. * 获取所有已经注册了指令列表.
* *
@ -54,9 +44,17 @@ public interface CommandManager {
public val commandPrefix: String public val commandPrefix: String
/** /**
* 取消注册所有属于 [this] 的指令 * 获取已经注册了的属于这个 [CommandOwner] 的指令列表.
*
* @return 这一时刻的浅拷贝.
*/ */
public fun CommandOwner.unregisterAllCommands() public fun getRegisteredCommands(owner: CommandOwner): List<Command>
/**
* 取消注册所有属于 [owner] 的指令
*/
public fun unregisterAllCommands(owner: CommandOwner)
/** /**
* 注册一个指令. * 注册一个指令.
@ -75,35 +73,31 @@ public interface CommandManager {
* *
* 注意: [内建指令][BuiltInCommands] 也可以被覆盖. * 注意: [内建指令][BuiltInCommands] 也可以被覆盖.
*/ */
@JvmName("registerCommand") public fun registerCommand(command: Command, override: Boolean = false): Boolean
public fun Command.register(override: Boolean = false): Boolean
/** /**
* 查找并返回重名的指令. 返回重名指令. * 查找并返回重名的指令. 返回重名指令.
*/ */
@JvmName("findCommandDuplicate") public fun findDuplicateCommand(command: Command): Command?
public fun Command.findDuplicate(): Command?
/** /**
* 取消注册这个指令. * 取消注册这个指令.
* *
* 若指令未注册, 返回 `false`. * 若指令未注册, 返回 `false`.
*/ */
@JvmName("unregisterCommand") public fun unregisterCommand(command: Command): Boolean
public fun Command.unregister(): Boolean
/** /**
* [this] 已经 [注册][register] 时返回 `true` * [command] 已经 [注册][registerCommand] 时返回 `true`
*/ */
@JvmName("isCommandRegistered") public fun isCommandRegistered(command: Command): Boolean
public fun Command.isRegistered(): Boolean
/** /**
* 解析并执行一个指令. * 解析并执行一个指令.
* *
* 如要避免参数解析, 请使用 [Command.onCommand]
*
* ### 指令解析流程 * ### 指令解析流程
* 1. [CommandCallParser] [MessageChain] 解析为 [CommandCall]
* 2. [CommandCallResolver] [CommandCall] 解析为 []
* 1. [message] 的第一个消息元素的 [内容][Message.contentToString] 被作为指令名, 在已注册指令列表中搜索. (包含 [Command.prefixOptional] 相关的处理) * 1. [message] 的第一个消息元素的 [内容][Message.contentToString] 被作为指令名, 在已注册指令列表中搜索. (包含 [Command.prefixOptional] 相关的处理)
* 2. 参数语法分析. * 2. 参数语法分析.
* 在当前的实现下, [message] 被以空格和 [SingleMessage] 分割. * 在当前的实现下, [message] 被以空格和 [SingleMessage] 分割.
@ -112,7 +106,7 @@ public interface CommandManager {
* 3. 参数解析. 各类型指令实现不同. 详见 [RawCommand], [CompositeCommand], [SimpleCommand] * 3. 参数解析. 各类型指令实现不同. 详见 [RawCommand], [CompositeCommand], [SimpleCommand]
* *
* ### 扩展 * ### 扩展
* 参数语法分析过程可能会被扩展, 插件可以自定义处理方式, 因此可能不会简单地使用空格分隔. * 参数语法分析过程可能会被扩展, 插件可以自定义处理方式 ([CommandCallParser]), 因此可能不会简单地使用空格分隔.
* *
* @param message 一条完整的指令. "/managers add 123456.123456" * @param message 一条完整的指令. "/managers add 123456.123456"
* @param checkPermission `true` 时检查权限 * @param checkPermission `true` 时检查权限
@ -120,42 +114,48 @@ public interface CommandManager {
* @see CommandCallParser * @see CommandCallParser
* @see CommandCallResolver * @see CommandCallResolver
* *
* @see CommandSender.executeCommand
* @see Command.execute
*
* @return 执行结果 * @return 执行结果
*/ */
@ExperimentalCommandDescriptors
@JvmBlockingBridge @JvmBlockingBridge
@OptIn(ExperimentalCommandDescriptors::class)
public suspend fun executeCommand( public suspend fun executeCommand(
caller: CommandSender, caller: CommandSender,
message: Message, message: Message,
checkPermission: Boolean = true, checkPermission: Boolean = true,
): CommandExecuteResult { ): CommandExecuteResult {
return executeCommandImpl(this, message, caller, checkPermission) return executeCommandImpl(message, caller, checkPermission)
} }
/** /**
* 解析并执行一个指令 * 执行一个确切的指令
* *
* @param message 一条完整的指令. "/managers add 123456.123456" * @param command 目标指令
* @param checkPermission `true` 时检查权限 * @param arguments 参数列表
* *
* @return 执行结果 * @see executeCommand 获取更多信息
* @see executeCommand * @see Command.execute
*/ */
@JvmBlockingBridge @ConsoleExperimentalApi
public suspend fun CommandSender.executeCommand( @JvmName("executeCommand")
message: String,
checkPermission: Boolean = true,
): CommandExecuteResult = executeCommand(this, PlainText(message).asMessageChain(), checkPermission)
@JvmName("resolveCall")
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public fun CommandCall.resolve(): ResolvedCommandCall? { @JvmSynthetic
GlobalComponentStorage.run { public suspend fun executeCommand(
CommandCallResolverProvider.useExtensions { provider -> sender: CommandSender,
provider.instance.resolve(this@resolve)?.let { return it } command: Command,
} arguments: Message = EmptyMessageChain,
checkPermission: Boolean = true,
): CommandExecuteResult {
// TODO: 2020/10/18 net.mamoe.mirai.console.command.CommandManager.execute
val chain = buildMessageChain {
append(CommandManager.commandPrefix)
append(command.primaryName)
append(' ')
append(arguments)
} }
return null return CommandManager.executeCommand(sender, chain, checkPermission)
} }
/** /**
@ -170,78 +170,89 @@ public interface CommandManager {
public fun matchCommand(commandName: String): Command? public fun matchCommand(commandName: String): Command?
public companion object INSTANCE : CommandManager by CommandManagerImpl { public companion object INSTANCE : CommandManager by CommandManagerImpl {
// TODO: 2020/8/20 https://youtrack.jetbrains.com/issue/KT-41191
/**
* @see CommandManager.getRegisteredCommands
*/
@get:JvmName("registeredCommands0")
@get:JvmSynthetic
public inline val CommandOwner.registeredCommands: List<Command>
get() = getRegisteredCommands(this)
override val CommandOwner.registeredCommands: List<Command> get() = CommandManagerImpl.run { this@registeredCommands.registeredCommands } /**
override fun CommandOwner.unregisterAllCommands(): Unit = CommandManagerImpl.run { unregisterAllCommands() } * @see CommandManager.registerCommand
override fun Command.register(override: Boolean): Boolean = CommandManagerImpl.run { register(override) } */
override fun Command.findDuplicate(): Command? = CommandManagerImpl.run { findDuplicate() } @JvmSynthetic
override fun Command.unregister(): Boolean = CommandManagerImpl.run { unregister() } public inline fun Command.register(override: Boolean = false): Boolean = registerCommand(this, override)
override fun Command.isRegistered(): Boolean = CommandManagerImpl.run { isRegistered() }
override val commandPrefix: String get() = CommandManagerImpl.commandPrefix /**
override val allRegisteredCommands: List<Command> * @see CommandManager.unregisterCommand
get() = CommandManagerImpl.allRegisteredCommands */
@JvmSynthetic
public inline fun Command.unregister(): Boolean = unregisterCommand(this)
/**
* @see CommandManager.isCommandRegistered
*/
@get:JvmSynthetic
public inline val Command.isRegistered: Boolean
get() = isCommandRegistered(this)
/**
* @see CommandManager.unregisterAll
*/
@JvmSynthetic
public inline fun CommandOwner.unregisterAll(): Unit = unregisterAllCommands(this)
/**
* @see CommandManager.findDuplicate
*/
@JvmSynthetic
public inline fun Command.findDuplicate(): Command? = findDuplicateCommand(this)
} }
} }
/** /**
* 执行一个确切的指令 * 解析并执行一个指令
* @see executeCommand 获取更多信息 *
* @param message 一条完整的指令. "/managers add 123456.123456"
* @param checkPermission `true` 时检查权限
*
* @return 执行结果
* @see executeCommand
*/ */
// @JvmBlockingBridge @JvmName("execute0")
// @JvmName("executeCommand") @ExperimentalCommandDescriptors
public suspend fun Command.execute( @JvmSynthetic
sender: CommandSender, public suspend inline fun CommandSender.executeCommand(
arguments: String = "", message: String,
checkPermission: Boolean = true, checkPermission: Boolean = true,
): CommandExecuteResult = execute(sender, PlainText(arguments).asMessageChain(), checkPermission) ): CommandExecuteResult = CommandManager.executeCommand(this, PlainText(message).asMessageChain(), checkPermission)
/** /**
* 执行一个确切的指令 * 执行一个确切的指令
* @see executeCommand 获取更多信息 * @see executeCommand 获取更多信息
*/ */
// @JvmBlockingBridge @JvmName("execute0")
// @JvmName("executeCommand") @ExperimentalCommandDescriptors
public suspend fun Command.execute( @JvmSynthetic
public suspend inline fun Command.execute(
sender: CommandSender, sender: CommandSender,
arguments: Message = EmptyMessageChain, arguments: Message = EmptyMessageChain,
checkPermission: Boolean = true, checkPermission: Boolean = true,
): CommandExecuteResult { ): CommandExecuteResult = CommandManager.executeCommand(sender, this, arguments, checkPermission)
// TODO: 2020/10/18 net.mamoe.mirai.console.command.CommandManager.execute
val chain = buildMessageChain {
append(CommandManager.commandPrefix)
append(this@execute.primaryName)
append(' ')
append(arguments)
}
return CommandManager.executeCommand(sender, chain, checkPermission)
}
// Don't move into CommandManager, compilation error / VerifyError
@OptIn(ExperimentalCommandDescriptors::class)
internal suspend fun executeCommandImpl(
receiver: CommandManager,
message: Message,
caller: CommandSender,
checkPermission: Boolean,
): CommandExecuteResult = with(receiver) {
val call = message.asMessageChain().parseCommandCall(caller) ?: return CommandExecuteResult.UnresolvedCall("")
val resolved = call.resolve() ?: return CommandExecuteResult.UnresolvedCall(call.calleeName)
val command = resolved.callee
if (checkPermission && !command.permission.testPermission(caller)) {
return CommandExecuteResult.PermissionDenied(command, call.calleeName)
}
return try {
resolved.calleeSignature.call(resolved)
CommandExecuteResult.Success(resolved.callee, call.calleeName, EmptyMessageChain)
} catch (e: Throwable) {
CommandExecuteResult.ExecutionFailed(e, resolved.callee, call.calleeName, EmptyMessageChain)
}
}
/**
* 执行一个确切的指令
* @see executeCommand 获取更多信息
*/
@JvmName("execute0")
@ExperimentalCommandDescriptors
@JvmSynthetic
public suspend inline fun Command.execute(
sender: CommandSender,
arguments: String = "",
checkPermission: Boolean = true,
): CommandExecuteResult = execute(sender, PlainText(arguments), checkPermission)

View File

@ -12,6 +12,8 @@ package net.mamoe.mirai.console.command.resolve
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.parse.CommandCall import net.mamoe.mirai.console.command.parse.CommandCall
import net.mamoe.mirai.console.extensions.CommandCallResolverProvider import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
/** /**
* The resolver converting a [CommandCall] into [ResolvedCommandCall] based on registered [] * The resolver converting a [CommandCall] into [ResolvedCommandCall] based on registered []
@ -22,4 +24,18 @@ import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public interface CommandCallResolver { public interface CommandCallResolver {
public fun resolve(call: CommandCall): ResolvedCommandCall? public fun resolve(call: CommandCall): ResolvedCommandCall?
public companion object {
@JvmName("resolveCall")
@ConsoleExperimentalApi
@ExperimentalCommandDescriptors
public fun CommandCall.resolve(): ResolvedCommandCall? {
GlobalComponentStorage.run {
CommandCallResolverProvider.useExtensions { provider ->
provider.instance.resolve(this@resolve)?.let { return it }
}
}
return null
}
}
} }

View File

@ -15,12 +15,19 @@ import kotlinx.coroutines.CoroutineScope
import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.command.* import net.mamoe.mirai.console.command.*
import net.mamoe.mirai.console.command.Command.Companion.allNames 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.CommandSender.Companion.toCommandSender
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors 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
import net.mamoe.mirai.console.permission.PermissionService.Companion.testPermission
import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope
import net.mamoe.mirai.event.Listener import net.mamoe.mirai.event.Listener
import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.event.subscribeAlways
import net.mamoe.mirai.message.MessageEvent import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.message.data.EmptyMessageChain
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.asMessageChain
import net.mamoe.mirai.message.data.content import net.mamoe.mirai.message.data.content
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.MiraiLogger
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
@ -94,64 +101,90 @@ internal object CommandManagerImpl : CommandManager, CoroutineScope by MiraiCons
///// IMPL ///// IMPL
override val CommandOwner.registeredCommands: List<Command> get() = _registeredCommands.filter { it.owner == this } override fun getRegisteredCommands(owner: CommandOwner): List<Command> = _registeredCommands.filter { it.owner == owner }
override val allRegisteredCommands: List<Command> get() = _registeredCommands.toList() // copy override val allRegisteredCommands: List<Command> get() = _registeredCommands.toList() // copy
override val commandPrefix: String get() = "/" override val commandPrefix: String get() = "/"
override fun CommandOwner.unregisterAllCommands() { override fun unregisterAllCommands(owner: CommandOwner) {
for (registeredCommand in registeredCommands) { for (registeredCommand in getRegisteredCommands(owner)) {
registeredCommand.unregister() unregisterCommand(registeredCommand)
} }
} }
override fun Command.register(override: Boolean): Boolean { override fun registerCommand(command: Command, override: Boolean): Boolean {
if (this is CompositeCommand) { if (command is CompositeCommand) {
this.overloads // init lazy command.overloads // init lazy
} }
kotlin.runCatching { kotlin.runCatching {
this.permission // init lazy command.permission // init lazy
this.secondaryNames // init lazy command.secondaryNames // init lazy
this.description // init lazy command.description // init lazy
this.usage // init lazy command.usage // init lazy
}.onFailure { }.onFailure {
throw IllegalStateException("Failed to init command ${this@register}.", it) throw IllegalStateException("Failed to init command ${command}.", it)
} }
modifyLock.withLock { this@CommandManagerImpl.modifyLock.withLock {
if (!override) { if (!override) {
if (findDuplicate() != null) return false if (command.findDuplicate() != null) return false
} }
_registeredCommands.add(this@register) this@CommandManagerImpl._registeredCommands.add(command)
if (this.prefixOptional) { if (command.prefixOptional) {
for (name in this.allNames) { for (name in command.allNames) {
val lowerCaseName = name.toLowerCase() val lowerCaseName = name.toLowerCase()
optionalPrefixCommandMap[lowerCaseName] = this this@CommandManagerImpl.optionalPrefixCommandMap[lowerCaseName] = command
requiredPrefixCommandMap[lowerCaseName] = this this@CommandManagerImpl.requiredPrefixCommandMap[lowerCaseName] = command
} }
} else { } else {
for (name in this.allNames) { for (name in command.allNames) {
val lowerCaseName = name.toLowerCase() val lowerCaseName = name.toLowerCase()
optionalPrefixCommandMap.remove(lowerCaseName) // ensure resolution consistency this@CommandManagerImpl.optionalPrefixCommandMap.remove(lowerCaseName) // ensure resolution consistency
requiredPrefixCommandMap[lowerCaseName] = this this@CommandManagerImpl.requiredPrefixCommandMap[lowerCaseName] = command
} }
} }
return true return true
} }
} }
override fun Command.findDuplicate(): Command? = override fun findDuplicateCommand(command: Command): Command? =
_registeredCommands.firstOrNull { it.allNames intersectsIgnoringCase this.allNames } _registeredCommands.firstOrNull { it.allNames intersectsIgnoringCase command.allNames }
override fun Command.unregister(): Boolean = modifyLock.withLock { override fun unregisterCommand(command: Command): Boolean = modifyLock.withLock {
if (this.prefixOptional) { if (command.prefixOptional) {
this.allNames.forEach { command.allNames.forEach {
optionalPrefixCommandMap.remove(it.toLowerCase()) optionalPrefixCommandMap.remove(it.toLowerCase())
} }
} }
this.allNames.forEach { command.allNames.forEach {
requiredPrefixCommandMap.remove(it.toLowerCase()) requiredPrefixCommandMap.remove(it.toLowerCase())
} }
_registeredCommands.remove(this) _registeredCommands.remove(command)
} }
override fun Command.isRegistered(): Boolean = this in _registeredCommands override fun isCommandRegistered(command: Command): Boolean = command in _registeredCommands
} }
// Don't move into CommandManager, compilation error / VerifyError
@OptIn(ExperimentalCommandDescriptors::class)
internal suspend fun executeCommandImpl(
message: Message,
caller: CommandSender,
checkPermission: Boolean,
): CommandExecuteResult {
val call = message.asMessageChain().parseCommandCall(caller) ?: return CommandExecuteResult.UnresolvedCall("")
val resolved = call.resolve() ?: return CommandExecuteResult.UnresolvedCall(call.calleeName)
val command = resolved.callee
if (checkPermission && !command.permission.testPermission(caller)) {
return CommandExecuteResult.PermissionDenied(command, call.calleeName)
}
return try {
resolved.calleeSignature.call(resolved)
CommandExecuteResult.Success(resolved.callee, call.calleeName, EmptyMessageChain)
} catch (e: Throwable) {
CommandExecuteResult.ExecutionFailed(e, resolved.callee, call.calleeName, EmptyMessageChain)
}
}

View File

@ -16,11 +16,11 @@ import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.Testing import net.mamoe.mirai.console.Testing
import net.mamoe.mirai.console.Testing.withTesting import net.mamoe.mirai.console.Testing.withTesting
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand import net.mamoe.mirai.console.command.CommandManager.INSTANCE.getRegisteredCommands
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.registeredCommands import net.mamoe.mirai.console.command.CommandManager.INSTANCE.registerCommand
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregister
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregisterAllCommands import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregisterAllCommands
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregisterCommand
import net.mamoe.mirai.console.command.descriptor.CommandValueArgumentParser import net.mamoe.mirai.console.command.descriptor.CommandValueArgumentParser
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.descriptor.buildCommandArgumentContext import net.mamoe.mirai.console.command.descriptor.buildCommandArgumentContext
@ -78,20 +78,20 @@ internal class TestCommand {
@Test @Test
fun testRegister() { fun testRegister() {
try { try {
ConsoleCommandOwner.unregisterAllCommands() // builtins unregisterAllCommands(ConsoleCommandOwner) // builtins
TestSimpleCommand.unregister() unregisterCommand(TestSimpleCommand)
assertTrue(TestCompositeCommand.register()) assertTrue(TestCompositeCommand.register())
assertFalse(TestCompositeCommand.register()) assertFalse(TestCompositeCommand.register())
assertEquals(1, ConsoleCommandOwner.registeredCommands.size) assertEquals(1, getRegisteredCommands(ConsoleCommandOwner).size)
assertEquals(1, CommandManagerImpl._registeredCommands.size) assertEquals(1, CommandManagerImpl._registeredCommands.size)
assertEquals(2, assertEquals(2,
CommandManagerImpl.requiredPrefixCommandMap.size, CommandManagerImpl.requiredPrefixCommandMap.size,
CommandManagerImpl.requiredPrefixCommandMap.entries.joinToString { it.toString() }) CommandManagerImpl.requiredPrefixCommandMap.entries.joinToString { it.toString() })
} finally { } finally {
TestCompositeCommand.unregister() unregisterCommand(TestCompositeCommand)
} }
} }
@ -194,7 +194,7 @@ internal class TestCommand {
} }
} }
composite.register() registerCommand(composite)
println(composite.overloads.joinToString()) println(composite.overloads.joinToString())

View File

@ -10,13 +10,13 @@
package net.mamoe.mirai.console.command package net.mamoe.mirai.console.command
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregister import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregisterCommand
inline fun <T : Command, R> T.withRegistration(block: T.() -> R): R { inline fun <T : Command, R> T.withRegistration(block: T.() -> R): R {
this.register() this.register()
try { try {
return block() return block()
} finally { } finally {
this.unregister() unregisterCommand(this)
} }
} }

View File

@ -15,11 +15,7 @@ import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.command.BuiltInCommands import net.mamoe.mirai.console.command.*
import net.mamoe.mirai.console.command.CommandExecuteStatus
import net.mamoe.mirai.console.command.CommandManager
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand
import net.mamoe.mirai.console.command.ConsoleCommandSender
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.terminal.noconsole.NoConsole import net.mamoe.mirai.console.terminal.noconsole.NoConsole
import net.mamoe.mirai.console.util.ConsoleInternalApi import net.mamoe.mirai.console.util.ConsoleInternalApi