mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-11 02:50:15 +08:00
Review command
This commit is contained in:
parent
d10f2b4bea
commit
b9580ffcbd
@ -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.")
|
||||||
}
|
}
|
||||||
|
@ -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 CommandManager.executeCommand(sender, chain, checkPermission)
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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)
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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())
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user