mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-25 21:23:55 +08:00
Fix parser context
This commit is contained in:
parent
89ac4e863c
commit
b857c8ad41
backend/mirai-console/src
main/kotlin/net/mamoe/mirai/console/command
test/java/net/mamoe/mirai/console/command
@ -97,7 +97,7 @@ class CommandArgs private constructor(
|
||||
|
||||
command.descriptor.params.asSequence().zip(rawArgs.asSequence()).map { (commandParam, any) ->
|
||||
command.parserFor(commandParam)?.parse(any, sender)
|
||||
?: error("ICould not find a parser for param named ${commandParam.name}")
|
||||
?: error("Could not find a parser for param named ${commandParam.name}, typed ${commandParam.type.qualifiedName}")
|
||||
}.toList().let { bakedArgs ->
|
||||
return CommandArgs(bakedArgs, command)
|
||||
}
|
||||
|
@ -29,9 +29,9 @@ class CommandDescriptor(
|
||||
*/
|
||||
description: String = "",
|
||||
/**
|
||||
* 指令参数解析器环境.
|
||||
* 覆盖内建的指令参数解析器环境.
|
||||
*/
|
||||
val context: CommandParserContext = CommandParserContext.Builtins,
|
||||
overrideContext: CommandParserContext = CommandParserContext.Empty,
|
||||
/**
|
||||
* 指令别名
|
||||
*/
|
||||
@ -44,6 +44,11 @@ class CommandDescriptor(
|
||||
*/
|
||||
val permission: CommandPermission = CommandPermission.Default
|
||||
) {
|
||||
/**
|
||||
* 指令参数解析器环境.
|
||||
*/
|
||||
val context: CommandParserContext = CommandParserContext.Builtins + overrideContext
|
||||
|
||||
/**
|
||||
* 指令别名
|
||||
*/
|
||||
@ -132,9 +137,12 @@ internal fun CommandFullName.checkFullName(errorHint: String): CommandFullName {
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
inline fun CommandDescriptor(
|
||||
vararg fullName: Any,
|
||||
/**
|
||||
* 指令全名
|
||||
*/
|
||||
vararg fullNameComponents: Any,
|
||||
block: CommandDescriptorBuilder.() -> Unit = {}
|
||||
): CommandDescriptor = CommandDescriptorBuilder(*fullName).apply(block).build()
|
||||
): CommandDescriptor = CommandDescriptorBuilder(*fullNameComponents).apply(block).build()
|
||||
|
||||
class CommandDescriptorBuilder(
|
||||
vararg fullName: Any
|
||||
|
@ -12,19 +12,27 @@
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.command.AbstractCommandParserContext.ParserPair
|
||||
import net.mamoe.mirai.console.command.CommandParserContext.ParserPair
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import kotlin.internal.LowPriorityInOverloadResolution
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
|
||||
|
||||
/**
|
||||
* [KClass] 到 [CommandArgParser] 的匹配
|
||||
* @see AbstractCommandParserContext
|
||||
* @see CustomCommandParserContext 自定义
|
||||
*/
|
||||
interface CommandParserContext {
|
||||
operator fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>?
|
||||
data class ParserPair<T : Any>(
|
||||
val klass: KClass<T>,
|
||||
val parser: CommandArgParser<T>
|
||||
)
|
||||
|
||||
operator fun <T : Any> get(klass: KClass<out T>): CommandArgParser<T>?
|
||||
|
||||
fun toList(): List<ParserPair<*>>
|
||||
|
||||
/**
|
||||
* 内建的默认 [CommandArgParser]
|
||||
@ -43,6 +51,8 @@ interface CommandParserContext {
|
||||
Group::class with ExistGroupArgParser
|
||||
Bot::class with ExistBotArgParser
|
||||
})
|
||||
|
||||
object Empty : CommandParserContext by CustomCommandParserContext(listOf())
|
||||
}
|
||||
|
||||
fun <T : Any> CommandParserContext.parserFor(param: CommandParam<T>): CommandArgParser<T>? =
|
||||
@ -58,20 +68,38 @@ fun <T : Any> Command.parserFor(param: CommandParam<T>): CommandArgParser<T>? =
|
||||
* 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser.
|
||||
*/
|
||||
operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandParserContext {
|
||||
if (replacer == CommandParserContext.Empty) return this
|
||||
if (this == CommandParserContext.Empty) return replacer
|
||||
return object : CommandParserContext {
|
||||
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? = replacer[klass] ?: this@plus[klass]
|
||||
override fun <T : Any> get(klass: KClass<out T>): CommandArgParser<T>? = replacer[klass] ?: this@plus[klass]
|
||||
override fun toList(): List<ParserPair<*>> = replacer.toList() + this@plus.toList()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并 [this] 与 [replacer], [replacer] 将会替换 [this] 中重复的 parser.
|
||||
*/
|
||||
operator fun CommandParserContext.plus(replacer: List<ParserPair<*>>): CommandParserContext {
|
||||
if (replacer.isEmpty()) return this
|
||||
if (this == CommandParserContext.Empty) return CustomCommandParserContext(replacer)
|
||||
return object : CommandParserContext {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : Any> get(klass: KClass<out T>): CommandArgParser<T>? =
|
||||
replacer.firstOrNull { klass.isSubclassOf(it.klass) }?.parser as CommandArgParser<T>? ?: this@plus[klass]
|
||||
|
||||
override fun toList(): List<ParserPair<*>> = replacer.toList() + this@plus.toList()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
open class AbstractCommandParserContext(val list: List<ParserPair<*>>) : CommandParserContext {
|
||||
class ParserPair<T : Any>(
|
||||
val klass: KClass<T>,
|
||||
val parser: CommandArgParser<T>
|
||||
)
|
||||
open class CustomCommandParserContext(val list: List<ParserPair<*>>) : CommandParserContext {
|
||||
|
||||
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? =
|
||||
this.list.firstOrNull { it.klass == klass }?.parser as CommandArgParser<T>?
|
||||
override fun <T : Any> get(klass: KClass<out T>): CommandArgParser<T>? =
|
||||
this.list.firstOrNull { klass.isSubclassOf(it.klass) }?.parser as CommandArgParser<T>?
|
||||
|
||||
override fun toList(): List<ParserPair<*>> {
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,8 +121,7 @@ open class AbstractCommandParserContext(val list: List<ParserPair<*>>) : Command
|
||||
@Suppress("FunctionName")
|
||||
@JvmSynthetic
|
||||
inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit): CommandParserContext {
|
||||
return AbstractCommandParserContext(
|
||||
CommandParserContextBuilder().apply(block).distinctByReversed { it.klass })
|
||||
return CustomCommandParserContext(CommandParserContextBuilder().apply(block).distinctByReversed { it.klass })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +130,7 @@ inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit):
|
||||
class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf() {
|
||||
@JvmName("add")
|
||||
inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): ParserPair<*> =
|
||||
ParserPair(this, parser)
|
||||
ParserPair(this, parser).also { add(it) }
|
||||
|
||||
/**
|
||||
* 添加一个指令解析器
|
||||
@ -112,7 +139,7 @@ class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf(
|
||||
@LowPriorityInOverloadResolution
|
||||
inline infix fun <T : Any> KClass<T>.with(
|
||||
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
||||
): ParserPair<*> = ParserPair(this, CommandArgParser(parser))
|
||||
): ParserPair<*> = ParserPair(this, CommandArgParser(parser)).also { add(it) }
|
||||
|
||||
/**
|
||||
* 添加一个指令解析器
|
||||
@ -120,16 +147,16 @@ class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf(
|
||||
@JvmSynthetic
|
||||
inline infix fun <T : Any> KClass<T>.with(
|
||||
crossinline parser: CommandArgParser<T>.(s: String) -> T
|
||||
): ParserPair<*> = ParserPair(this, CommandArgParser { s: String, _: CommandSender -> parser(s) })
|
||||
): ParserPair<*> = ParserPair(this, CommandArgParser { s: String, _: CommandSender -> parser(s) }).also { add(it) }
|
||||
}
|
||||
|
||||
|
||||
@PublishedApi
|
||||
internal inline fun <T, K> Iterable<T>.distinctByReversed(selector: (T) -> K): List<T> {
|
||||
internal inline fun <T, K> List<T>.distinctByReversed(selector: (T) -> K): List<T> {
|
||||
val set = HashSet<K>()
|
||||
val list = ArrayList<T>()
|
||||
for (i in list.indices.reversed()) {
|
||||
val element = list[i]
|
||||
for (i in this.indices.reversed()) {
|
||||
val element = this[i]
|
||||
if (set.add(element.let(selector))) {
|
||||
list.add(element)
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ interface CommandSender {
|
||||
/**
|
||||
* 立刻发送一条消息
|
||||
*/
|
||||
suspend fun sendMessage(messageChain: Message)
|
||||
suspend fun sendMessage(message: Message)
|
||||
|
||||
suspend fun sendMessage(message: String)
|
||||
|
||||
@ -56,7 +56,7 @@ abstract class AbstractCommandSender : CommandSender {
|
||||
* 控制台指令执行者. 代表由控制台执行指令
|
||||
*/
|
||||
object ConsoleCommandSender : AbstractCommandSender() {
|
||||
override suspend fun sendMessage(messageChain: Message) {
|
||||
override suspend fun sendMessage(message: Message) {
|
||||
TODO()
|
||||
// MiraiConsole.logger("[Command]", 0, messageChain.toString())
|
||||
}
|
||||
@ -86,8 +86,8 @@ interface BotAware {
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
open class ContactCommandSender(override val bot: Bot, val contact: Contact) : AbstractCommandSender(), BotAware {
|
||||
override suspend fun sendMessage(messageChain: Message) {
|
||||
contact.sendMessage(messageChain)
|
||||
override suspend fun sendMessage(message: Message) {
|
||||
contact.sendMessage(message)
|
||||
}
|
||||
|
||||
override suspend fun sendMessage(message: String) {
|
||||
|
@ -11,10 +11,9 @@
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.mamoe.mirai.console.plugins.PluginBase
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
import net.mamoe.mirai.message.data.messageChainOf
|
||||
import net.mamoe.mirai.message.data.toMessage
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
@ -71,5 +70,35 @@ internal class TestCommands {
|
||||
}.register()
|
||||
)
|
||||
}
|
||||
|
||||
inline fun withSender(block: CommandSender.() -> Unit): MessageChain {
|
||||
val result = MessageChainBuilder()
|
||||
val sender: CommandSender = object : CommandSender {
|
||||
override suspend fun sendMessage(message: Message) {
|
||||
result.add(message)
|
||||
}
|
||||
|
||||
override suspend fun sendMessage(message: String) {
|
||||
result.add(message)
|
||||
}
|
||||
|
||||
override fun appendMessage(message: String) {
|
||||
result.add(message)
|
||||
}
|
||||
}
|
||||
sender.let(block)
|
||||
return result.asMessageChain()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExecute() = runBlocking {
|
||||
TestCommand.register()
|
||||
assertEquals(
|
||||
"ok",
|
||||
withSender {
|
||||
execute("test", "ok", "extra")
|
||||
}.contentToString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user