Files
mirai/backend/mirai-console/src/command/CommandManager.kt
2021-07-02 00:56:54 +08:00

260 lines
8.6 KiB
Kotlin

/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:Suppress(
"NOTHING_TO_INLINE", "unused",
"MemberVisibilityCanBePrivate", "INAPPLICABLE_JVM_NAME"
)
@file:JvmName("CommandManagerKt")
package net.mamoe.mirai.console.command
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.parse.CommandCall
import net.mamoe.mirai.console.command.parse.CommandCallParser
import net.mamoe.mirai.console.command.resolve.CommandCallResolver
import net.mamoe.mirai.console.command.resolve.ResolvedCommandCall
import net.mamoe.mirai.console.internal.command.CommandManagerImpl
import net.mamoe.mirai.console.internal.command.CommandManagerImpl.executeCommand
import net.mamoe.mirai.console.internal.command.executeCommandImpl
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.message.data.*
/**
* 指令管理器
*/
public interface CommandManager {
/**
* 获取所有已经注册了指令列表.
*
* @return 这一时刻的浅拷贝.
*/
public val allRegisteredCommands: List<Command>
/**
* 指令前缀, 如 '/'
*/
public val commandPrefix: String
/**
* 获取已经注册了的属于这个 [CommandOwner] 的指令列表.
*
* @return 这一时刻的浅拷贝.
*/
public fun getRegisteredCommands(owner: CommandOwner): List<Command>
/**
* 取消注册所有属于 [owner] 的指令
*/
public fun unregisterAllCommands(owner: CommandOwner)
/**
* 注册一个指令.
*
* @param override 是否覆盖重名指令.
*
* 若原有指令 P, 其 [Command.secondaryNames] 为 'a', 'b', 'c'.
* 新指令 Q, 其 [Command.secondaryNames] 为 'b', 将会覆盖原指令 A 注册的 'b'.
*
* 即注册完成后, 'a' 和 'c' 将会解析到指令 P, 而 'b' 会解析到指令 Q.
*
* @return
* 若已有重名指令, 且 [override] 为 `false`, 返回 `false`;
* 若已有重名指令, 但 [override] 为 `true`, 覆盖原有指令并返回 `true`.
*
*
* 注意: [内建指令][BuiltInCommands] 也可以被覆盖.
*/
public fun registerCommand(command: Command, override: Boolean = false): Boolean
/**
* 查找并返回重名的指令. 返回重名指令.
*/
public fun findDuplicateCommand(command: Command): Command?
/**
* 取消注册这个指令.
*
* 若指令未注册, 返回 `false`.
*/
public fun unregisterCommand(command: Command): Boolean
/**
* 当 [command] 已经 [注册][registerCommand] 时返回 `true`
*/
public fun isCommandRegistered(command: Command): Boolean
/**
* 解析并执行一个指令.
*
* ### 指令解析流程
* 1. [CommandCallParser] 将 [MessageChain] 解析为 [CommandCall]
* 2. [CommandCallResolver] 将 [CommandCall] 解析为 [ResolvedCommandCall]
* 1. [message] 的第一个消息元素的 [内容][Message.contentToString] 被作为指令名, 在已注册指令列表中搜索. (包含 [Command.prefixOptional] 相关的处理)
* 2. 参数语法分析.
* 在当前的实现下, [message] 被以空格和 [SingleMessage] 分割.
* 如 "MessageChain("foo bar", [Image], " test")" 被分割为 "foo", "bar", [Image], "test".
* 注意: 字符串与消息元素之间不需要空格, 会被强制分割. 如 "bar[mirai:image:]" 会被分割为 "bar" 和 [Image] 类型的消息元素.
* 3. 参数解析. 各类型指令实现不同. 详见 [RawCommand], [CompositeCommand], [SimpleCommand]
*
* ### 扩展
* 参数语法分析过程可能会被扩展, 插件可以自定义处理方式 ([CommandCallParser]), 因此可能不会简单地使用空格分隔.
*
* @param message 一条完整的指令. 如 "/managers add 123456.123456"
* @param checkPermission 为 `true` 时检查权限
*
* @see CommandCallParser
* @see CommandCallResolver
*
* @see CommandSender.executeCommand
* @see Command.execute
*
* @return 执行结果
*/
@ExperimentalCommandDescriptors
@JvmBlockingBridge
public suspend fun executeCommand(
caller: CommandSender,
message: Message,
checkPermission: Boolean = true,
): CommandExecuteResult {
return executeCommandImpl(message, caller, checkPermission)
}
/**
* 执行一个确切的指令
*
* @param command 目标指令
* @param arguments 参数列表
*
* @see executeCommand 获取更多信息
* @see Command.execute
*/
@ConsoleExperimentalApi
@JvmName("executeCommand")
@ExperimentalCommandDescriptors
@JvmSynthetic
public suspend fun executeCommand(
sender: CommandSender,
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)
}
/**
* 从 [指令名称][commandName] 匹配对应的 [Command].
*
* #### 实现细节
* - [commandName] 带有 [commandPrefix] 时可以匹配到所有指令
* - [commandName] 不带有 [commandPrefix] 时只能匹配到 [Command.prefixOptional] 的指令
*
* @param commandName 可能带有或不带有 [commandPrefix].
*/
public fun matchCommand(commandName: String): Command?
public companion object INSTANCE : CommandManager by CommandManagerImpl {
/**
* @see CommandManager.getRegisteredCommands
*/
@get:JvmName("registeredCommands0")
@get:JvmSynthetic
public inline val CommandOwner.registeredCommands: List<Command>
get() = getRegisteredCommands(this)
/**
* @see CommandManager.registerCommand
*/
@JvmSynthetic
public inline fun Command.register(override: Boolean = false): Boolean = registerCommand(this, override)
/**
* @see CommandManager.unregisterCommand
*/
@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)
}
}
/**
* 解析并执行一个指令
*
* @param message 一条完整的指令. 如 "/managers add 123456.123456"
* @param checkPermission 为 `true` 时检查权限
*
* @return 执行结果
* @see executeCommand
*/
@JvmName("execute0")
@ExperimentalCommandDescriptors
@JvmSynthetic
public suspend inline fun CommandSender.executeCommand(
message: String,
checkPermission: Boolean = true,
): CommandExecuteResult = CommandManager.executeCommand(this, PlainText(message).toMessageChain(), checkPermission)
/**
* 执行一个确切的指令
* @see executeCommand 获取更多信息
*/
@JvmName("execute0")
@ExperimentalCommandDescriptors
@JvmSynthetic
public suspend inline fun Command.execute(
sender: CommandSender,
vararg arguments: Message = emptyArray(),
checkPermission: Boolean = true,
): CommandExecuteResult = CommandManager.executeCommand(sender, this, arguments.toMessageChain(), checkPermission)
/**
* 执行一个确切的指令
* @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 = checkPermission)