CommandValueArgumentParser

This commit is contained in:
Him188 2020-10-09 12:35:16 +08:00
parent 1e9b498ba9
commit 86c3b18bca
12 changed files with 122 additions and 110 deletions

View File

@ -150,8 +150,8 @@ public object BuiltInCommands {
ConsoleCommandOwner, "permission", "权限", "perm", ConsoleCommandOwner, "permission", "权限", "perm",
description = "管理权限", description = "管理权限",
overrideContext = buildCommandArgumentContext { overrideContext = buildCommandArgumentContext {
PermitteeId::class with PermitteeIdArgumentParser PermitteeId::class with PermitteeIdValueArgumentParser
Permission::class with PermissionIdArgumentParser.map { id -> Permission::class with PermissionIdValueArgumentParser.map { id ->
kotlin.runCatching { kotlin.runCatching {
id.findCorrespondingPermissionOrFail() id.findCorrespondingPermissionOrFail()
}.getOrElse { illegalArgument("指令不存在: $id", it) } }.getOrElse { illegalArgument("指令不存在: $id", it) }

View File

@ -99,7 +99,7 @@ public abstract class CompositeCommand(
public override val usage: String get() = super.usage public override val usage: String get() = super.usage
/** /**
* [CommandArgumentParser] 的环境 * [CommandValueArgumentParser] 的环境
*/ */
public final override val context: CommandArgumentContext = CommandArgumentContext.Builtins + overrideContext public final override val context: CommandArgumentContext = CommandArgumentContext.Builtins + overrideContext

View File

@ -31,7 +31,7 @@ import net.mamoe.mirai.message.data.MessageChain
* 简单的, 支持参数自动解析的指令. * 简单的, 支持参数自动解析的指令.
* *
* 要查看指令解析流程, 参考 [CommandManager.executeCommand] * 要查看指令解析流程, 参考 [CommandManager.executeCommand]
* 要查看参数解析方式, 参考 [CommandArgumentParser] * 要查看参数解析方式, 参考 [CommandValueArgumentParser]
* *
* Kotlin 实现: * Kotlin 实现:
* ``` * ```

View File

@ -29,7 +29,7 @@ import kotlin.reflect.full.isSubclassOf
/** /**
* 指令参数环境, [CommandArgumentParser] 的集合, 用于 [CompositeCommand] [SimpleCommand]. * 指令参数环境, [CommandValueArgumentParser] 的集合, 用于 [CompositeCommand] [SimpleCommand].
* *
* 在指令解析时, 总是从 [CommandArgumentContextAware.context] 搜索相关解析器 * 在指令解析时, 总是从 [CommandArgumentContextAware.context] 搜索相关解析器
* *
@ -38,20 +38,20 @@ import kotlin.reflect.full.isSubclassOf
* @see SimpleCommandArgumentContext 简单实现 * @see SimpleCommandArgumentContext 简单实现
* @see EmptyCommandArgumentContext 空实现, 类似 [emptyList] * @see EmptyCommandArgumentContext 空实现, 类似 [emptyList]
* *
* @see CommandArgumentContext.Builtins 内建 [CommandArgumentParser] * @see CommandArgumentContext.Builtins 内建 [CommandValueArgumentParser]
* *
* @see buildCommandArgumentContext DSL 构造 * @see buildCommandArgumentContext DSL 构造
*/ */
public interface CommandArgumentContext { public interface CommandArgumentContext {
/** /**
* [KClass] [CommandArgumentParser] 的匹配 * [KClass] [CommandValueArgumentParser] 的匹配
*/ */
public data class ParserPair<T : Any>( public data class ParserPair<T : Any>(
val klass: KClass<T>, val klass: KClass<T>,
val parser: CommandArgumentParser<T>, val parser: CommandValueArgumentParser<T>,
) )
public operator fun <T : Any> get(klass: KClass<out T>): CommandArgumentParser<T>? public operator fun <T : Any> get(klass: KClass<out T>): CommandValueArgumentParser<T>?
public fun toList(): List<ParserPair<*>> public fun toList(): List<ParserPair<*>>
@ -66,32 +66,32 @@ public interface CommandArgumentContext {
} }
/** /**
* 内建的默认 [CommandArgumentParser] * 内建的默认 [CommandValueArgumentParser]
*/ */
public object Builtins : CommandArgumentContext by (buildCommandArgumentContext { public object Builtins : CommandArgumentContext by (buildCommandArgumentContext {
Int::class with IntArgumentParser Int::class with IntValueArgumentParser
Byte::class with ByteArgumentParser Byte::class with ByteValueArgumentParser
Short::class with ShortArgumentParser Short::class with ShortValueArgumentParser
Boolean::class with BooleanArgumentParser Boolean::class with BooleanValueArgumentParser
String::class with StringArgumentParser String::class with StringValueArgumentParser
Long::class with LongArgumentParser Long::class with LongValueArgumentParser
Double::class with DoubleArgumentParser Double::class with DoubleValueArgumentParser
Float::class with FloatArgumentParser Float::class with FloatValueArgumentParser
Image::class with ImageArgumentParser Image::class with ImageValueArgumentParser
PlainText::class with PlainTextArgumentParser PlainText::class with PlainTextValueArgumentParser
Contact::class with ExistingContactArgumentParser Contact::class with ExistingContactValueArgumentParser
User::class with ExistingUserArgumentParser User::class with ExistingUserValueArgumentParser
Member::class with ExistingMemberArgumentParser Member::class with ExistingMemberValueArgumentParser
Group::class with ExistingGroupArgumentParser Group::class with ExistingGroupValueArgumentParser
Friend::class with ExistingFriendArgumentParser Friend::class with ExistingFriendValueArgumentParser
Bot::class with ExistingBotArgumentParser Bot::class with ExistingBotValueArgumentParser
PermissionId::class with PermissionIdArgumentParser PermissionId::class with PermissionIdValueArgumentParser
PermitteeId::class with PermitteeIdArgumentParser PermitteeId::class with PermitteeIdValueArgumentParser
MessageContent::class with RawContentArgumentParser MessageContent::class with RawContentValueArgumentParser
}) })
} }
@ -103,7 +103,7 @@ public interface CommandArgumentContext {
*/ */
public interface CommandArgumentContextAware { public interface CommandArgumentContextAware {
/** /**
* [CommandArgumentParser] 的集合 * [CommandValueArgumentParser] 的集合
*/ */
public val context: CommandArgumentContext public val context: CommandArgumentContext
} }
@ -117,7 +117,7 @@ public operator fun CommandArgumentContext.plus(replacer: CommandArgumentContext
if (replacer == EmptyCommandArgumentContext) return this if (replacer == EmptyCommandArgumentContext) return this
if (this == EmptyCommandArgumentContext) return replacer if (this == EmptyCommandArgumentContext) return replacer
return object : CommandArgumentContext { return object : CommandArgumentContext {
override fun <T : Any> get(klass: KClass<out T>): CommandArgumentParser<T>? = override fun <T : Any> get(klass: KClass<out T>): CommandValueArgumentParser<T>? =
replacer[klass] ?: this@plus[klass] replacer[klass] ?: this@plus[klass]
override fun toList(): List<ParserPair<*>> = replacer.toList() + this@plus.toList() override fun toList(): List<ParserPair<*>> = replacer.toList() + this@plus.toList()
@ -132,8 +132,8 @@ public operator fun CommandArgumentContext.plus(replacer: List<ParserPair<*>>):
if (this == EmptyCommandArgumentContext) return SimpleCommandArgumentContext(replacer) if (this == EmptyCommandArgumentContext) return SimpleCommandArgumentContext(replacer)
return object : CommandArgumentContext { return object : CommandArgumentContext {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
override fun <T : Any> get(klass: KClass<out T>): CommandArgumentParser<T>? = override fun <T : Any> get(klass: KClass<out T>): CommandValueArgumentParser<T>? =
replacer.firstOrNull { klass.isSubclassOf(it.klass) }?.parser as CommandArgumentParser<T>? replacer.firstOrNull { klass.isSubclassOf(it.klass) }?.parser as CommandValueArgumentParser<T>?
?: this@plus[klass] ?: this@plus[klass]
override fun toList(): List<ParserPair<*>> = replacer.toList() + this@plus.toList() override fun toList(): List<ParserPair<*>> = replacer.toList() + this@plus.toList()
@ -149,9 +149,9 @@ public operator fun CommandArgumentContext.plus(replacer: List<ParserPair<*>>):
public class SimpleCommandArgumentContext( public class SimpleCommandArgumentContext(
public val list: List<ParserPair<*>>, public val list: List<ParserPair<*>>,
) : CommandArgumentContext { ) : CommandArgumentContext {
override fun <T : Any> get(klass: KClass<out T>): CommandArgumentParser<T>? = override fun <T : Any> get(klass: KClass<out T>): CommandValueArgumentParser<T>? =
(this.list.firstOrNull { klass == it.klass }?.parser (this.list.firstOrNull { klass == it.klass }?.parser
?: this.list.firstOrNull { klass.isSubclassOf(it.klass) }?.parser) as CommandArgumentParser<T>? ?: this.list.firstOrNull { klass.isSubclassOf(it.klass) }?.parser) as CommandValueArgumentParser<T>?
override fun toList(): List<ParserPair<*>> = list override fun toList(): List<ParserPair<*>> = list
} }
@ -203,14 +203,14 @@ public class CommandArgumentContextBuilder : MutableList<ParserPair<*>> by mutab
* 添加一个指令解析器. * 添加一个指令解析器.
*/ */
@JvmName("add") @JvmName("add")
public infix fun <T : Any> Class<T>.with(parser: CommandArgumentParser<T>): CommandArgumentContextBuilder = public infix fun <T : Any> Class<T>.with(parser: CommandValueArgumentParser<T>): CommandArgumentContextBuilder =
this.kotlin with parser this.kotlin with parser
/** /**
* 添加一个指令解析器 * 添加一个指令解析器
*/ */
@JvmName("add") @JvmName("add")
public inline infix fun <T : Any> KClass<T>.with(parser: CommandArgumentParser<T>): CommandArgumentContextBuilder { public inline infix fun <T : Any> KClass<T>.with(parser: CommandValueArgumentParser<T>): CommandArgumentContextBuilder {
add(ParserPair(this, parser)) add(ParserPair(this, parser))
return this@CommandArgumentContextBuilder return this@CommandArgumentContextBuilder
} }
@ -221,9 +221,9 @@ public class CommandArgumentContextBuilder : MutableList<ParserPair<*>> by mutab
@JvmSynthetic @JvmSynthetic
@LowPriorityInOverloadResolution @LowPriorityInOverloadResolution
public inline infix fun <T : Any> KClass<T>.with( public inline infix fun <T : Any> KClass<T>.with(
crossinline parser: CommandArgumentParser<T>.(s: String, sender: CommandSender) -> T, crossinline parser: CommandValueArgumentParser<T>.(s: String, sender: CommandSender) -> T,
): CommandArgumentContextBuilder { ): CommandArgumentContextBuilder {
add(ParserPair(this, object : CommandArgumentParser<T> { add(ParserPair(this, object : CommandValueArgumentParser<T> {
override fun parse(raw: String, sender: CommandSender): T = parser(raw, sender) override fun parse(raw: String, sender: CommandSender): T = parser(raw, sender)
})) }))
return this@CommandArgumentContextBuilder return this@CommandArgumentContextBuilder
@ -234,16 +234,16 @@ public class CommandArgumentContextBuilder : MutableList<ParserPair<*>> by mutab
*/ */
@JvmSynthetic @JvmSynthetic
public inline infix fun <T : Any> KClass<T>.with( public inline infix fun <T : Any> KClass<T>.with(
crossinline parser: CommandArgumentParser<T>.(s: String) -> T, crossinline parser: CommandValueArgumentParser<T>.(s: String) -> T,
): CommandArgumentContextBuilder { ): CommandArgumentContextBuilder {
add(ParserPair(this, object : CommandArgumentParser<T> { add(ParserPair(this, object : CommandValueArgumentParser<T> {
override fun parse(raw: String, sender: CommandSender): T = parser(raw) override fun parse(raw: String, sender: CommandSender): T = parser(raw)
})) }))
return this@CommandArgumentContextBuilder return this@CommandArgumentContextBuilder
} }
@JvmSynthetic @JvmSynthetic
public inline fun <reified T : Any> add(parser: CommandArgumentParser<T>): CommandArgumentContextBuilder { public inline fun <reified T : Any> add(parser: CommandValueArgumentParser<T>): CommandArgumentContextBuilder {
add(ParserPair(T::class, parser)) add(ParserPair(T::class, parser))
return this@CommandArgumentContextBuilder return this@CommandArgumentContextBuilder
} }
@ -254,8 +254,8 @@ public class CommandArgumentContextBuilder : MutableList<ParserPair<*>> by mutab
@ConsoleExperimentalApi @ConsoleExperimentalApi
@JvmSynthetic @JvmSynthetic
public inline infix fun <reified T : Any> add( public inline infix fun <reified T : Any> add(
crossinline parser: CommandArgumentParser<*>.(s: String) -> T, crossinline parser: CommandValueArgumentParser<*>.(s: String) -> T,
): CommandArgumentContextBuilder = T::class with object : CommandArgumentParser<T> { ): CommandArgumentContextBuilder = T::class with object : CommandValueArgumentParser<T> {
override fun parse(raw: String, sender: CommandSender): T = parser(raw) override fun parse(raw: String, sender: CommandSender): T = parser(raw)
} }
@ -266,8 +266,8 @@ public class CommandArgumentContextBuilder : MutableList<ParserPair<*>> by mutab
@JvmSynthetic @JvmSynthetic
@LowPriorityInOverloadResolution @LowPriorityInOverloadResolution
public inline infix fun <reified T : Any> add( public inline infix fun <reified T : Any> add(
crossinline parser: CommandArgumentParser<*>.(s: String, sender: CommandSender) -> T, crossinline parser: CommandValueArgumentParser<*>.(s: String, sender: CommandSender) -> T,
): CommandArgumentContextBuilder = T::class with object : CommandArgumentParser<T> { ): CommandArgumentContextBuilder = T::class with object : CommandValueArgumentParser<T> {
override fun parse(raw: String, sender: CommandSender): T = parser(raw, sender) override fun parse(raw: String, sender: CommandSender): T = parser(raw, sender)
} }

View File

@ -25,7 +25,7 @@ import net.mamoe.mirai.message.data.*
/** /**
* 使用 [String.toInt] 解析 * 使用 [String.toInt] 解析
*/ */
public object IntArgumentParser : InternalCommandArgumentParserExtensions<Int> { public object IntValueArgumentParser : InternalCommandValueArgumentParserExtensions<Int> {
public override fun parse(raw: String, sender: CommandSender): Int = public override fun parse(raw: String, sender: CommandSender): Int =
raw.toIntOrNull() ?: illegalArgument("无法解析 $raw 为整数") raw.toIntOrNull() ?: illegalArgument("无法解析 $raw 为整数")
} }
@ -33,7 +33,7 @@ public object IntArgumentParser : InternalCommandArgumentParserExtensions<Int> {
/** /**
* 使用 [String.toLong] 解析 * 使用 [String.toLong] 解析
*/ */
public object LongArgumentParser : InternalCommandArgumentParserExtensions<Long> { public object LongValueArgumentParser : InternalCommandValueArgumentParserExtensions<Long> {
public override fun parse(raw: String, sender: CommandSender): Long = public override fun parse(raw: String, sender: CommandSender): Long =
raw.toLongOrNull() ?: illegalArgument("无法解析 $raw 为长整数") raw.toLongOrNull() ?: illegalArgument("无法解析 $raw 为长整数")
} }
@ -41,7 +41,7 @@ public object LongArgumentParser : InternalCommandArgumentParserExtensions<Long>
/** /**
* 使用 [String.toShort] 解析 * 使用 [String.toShort] 解析
*/ */
public object ShortArgumentParser : InternalCommandArgumentParserExtensions<Short> { public object ShortValueArgumentParser : InternalCommandValueArgumentParserExtensions<Short> {
public override fun parse(raw: String, sender: CommandSender): Short = public override fun parse(raw: String, sender: CommandSender): Short =
raw.toShortOrNull() ?: illegalArgument("无法解析 $raw 为短整数") raw.toShortOrNull() ?: illegalArgument("无法解析 $raw 为短整数")
} }
@ -49,7 +49,7 @@ public object ShortArgumentParser : InternalCommandArgumentParserExtensions<Shor
/** /**
* 使用 [String.toByte] 解析 * 使用 [String.toByte] 解析
*/ */
public object ByteArgumentParser : InternalCommandArgumentParserExtensions<Byte> { public object ByteValueArgumentParser : InternalCommandValueArgumentParserExtensions<Byte> {
public override fun parse(raw: String, sender: CommandSender): Byte = public override fun parse(raw: String, sender: CommandSender): Byte =
raw.toByteOrNull() ?: illegalArgument("无法解析 $raw 为字节") raw.toByteOrNull() ?: illegalArgument("无法解析 $raw 为字节")
} }
@ -57,7 +57,7 @@ public object ByteArgumentParser : InternalCommandArgumentParserExtensions<Byte>
/** /**
* 使用 [String.toDouble] 解析 * 使用 [String.toDouble] 解析
*/ */
public object DoubleArgumentParser : InternalCommandArgumentParserExtensions<Double> { public object DoubleValueArgumentParser : InternalCommandValueArgumentParserExtensions<Double> {
public override fun parse(raw: String, sender: CommandSender): Double = public override fun parse(raw: String, sender: CommandSender): Double =
raw.toDoubleOrNull() ?: illegalArgument("无法解析 $raw 为小数") raw.toDoubleOrNull() ?: illegalArgument("无法解析 $raw 为小数")
} }
@ -65,7 +65,7 @@ public object DoubleArgumentParser : InternalCommandArgumentParserExtensions<Dou
/** /**
* 使用 [String.toFloat] 解析 * 使用 [String.toFloat] 解析
*/ */
public object FloatArgumentParser : InternalCommandArgumentParserExtensions<Float> { public object FloatValueArgumentParser : InternalCommandValueArgumentParserExtensions<Float> {
public override fun parse(raw: String, sender: CommandSender): Float = public override fun parse(raw: String, sender: CommandSender): Float =
raw.toFloatOrNull() ?: illegalArgument("无法解析 $raw 为小数") raw.toFloatOrNull() ?: illegalArgument("无法解析 $raw 为小数")
} }
@ -73,14 +73,14 @@ public object FloatArgumentParser : InternalCommandArgumentParserExtensions<Floa
/** /**
* 直接返回 [String], 或取用 [SingleMessage.contentToString] * 直接返回 [String], 或取用 [SingleMessage.contentToString]
*/ */
public object StringArgumentParser : InternalCommandArgumentParserExtensions<String> { public object StringValueArgumentParser : InternalCommandValueArgumentParserExtensions<String> {
public override fun parse(raw: String, sender: CommandSender): String = raw public override fun parse(raw: String, sender: CommandSender): String = raw
} }
/** /**
* 解析 [String] 通过 [Image]. * 解析 [String] 通过 [Image].
*/ */
public object ImageArgumentParser : InternalCommandArgumentParserExtensions<Image> { public object ImageValueArgumentParser : InternalCommandValueArgumentParserExtensions<Image> {
public override fun parse(raw: String, sender: CommandSender): Image { public override fun parse(raw: String, sender: CommandSender): Image {
return kotlin.runCatching { return kotlin.runCatching {
Image(raw) Image(raw)
@ -95,7 +95,7 @@ public object ImageArgumentParser : InternalCommandArgumentParserExtensions<Imag
} }
} }
public object PlainTextArgumentParser : InternalCommandArgumentParserExtensions<PlainText> { public object PlainTextValueArgumentParser : InternalCommandValueArgumentParserExtensions<PlainText> {
public override fun parse(raw: String, sender: CommandSender): PlainText { public override fun parse(raw: String, sender: CommandSender): PlainText {
return PlainText(raw) return PlainText(raw)
} }
@ -109,7 +109,7 @@ public object PlainTextArgumentParser : InternalCommandArgumentParserExtensions<
/** /**
* 当字符串内容为(不区分大小写) "true", "yes", "enabled" * 当字符串内容为(不区分大小写) "true", "yes", "enabled"
*/ */
public object BooleanArgumentParser : InternalCommandArgumentParserExtensions<Boolean> { public object BooleanValueArgumentParser : InternalCommandValueArgumentParserExtensions<Boolean> {
public override fun parse(raw: String, sender: CommandSender): Boolean = raw.trim().let { str -> public override fun parse(raw: String, sender: CommandSender): Boolean = raw.trim().let { str ->
str.equals("true", ignoreCase = true) str.equals("true", ignoreCase = true)
|| str.equals("yes", ignoreCase = true) || str.equals("yes", ignoreCase = true)
@ -121,7 +121,7 @@ public object BooleanArgumentParser : InternalCommandArgumentParserExtensions<Bo
/** /**
* 根据 [Bot.id] 解析一个登录后的 [Bot] * 根据 [Bot.id] 解析一个登录后的 [Bot]
*/ */
public object ExistingBotArgumentParser : InternalCommandArgumentParserExtensions<Bot> { public object ExistingBotValueArgumentParser : InternalCommandValueArgumentParserExtensions<Bot> {
public override fun parse(raw: String, sender: CommandSender): Bot = public override fun parse(raw: String, sender: CommandSender): Bot =
if (raw == "~") sender.inferBotOrFail() if (raw == "~") sender.inferBotOrFail()
else raw.findBotOrFail() else raw.findBotOrFail()
@ -136,7 +136,7 @@ public object ExistingBotArgumentParser : InternalCommandArgumentParserExtension
/** /**
* 解析任意一个存在的好友. * 解析任意一个存在的好友.
*/ */
public object ExistingFriendArgumentParser : InternalCommandArgumentParserExtensions<Friend> { public object ExistingFriendValueArgumentParser : InternalCommandValueArgumentParserExtensions<Friend> {
private val syntax = """ private val syntax = """
- `botId.friendId` - `botId.friendId`
- `botId.friendNick` (模糊搜索, 寻找最优匹配) - `botId.friendNick` (模糊搜索, 寻找最优匹配)
@ -175,7 +175,7 @@ public object ExistingFriendArgumentParser : InternalCommandArgumentParserExtens
/** /**
* 解析任意一个存在的群. * 解析任意一个存在的群.
*/ */
public object ExistingGroupArgumentParser : InternalCommandArgumentParserExtensions<Group> { public object ExistingGroupValueArgumentParser : InternalCommandValueArgumentParserExtensions<Group> {
private val syntax = """ private val syntax = """
- `botId.groupId` - `botId.groupId`
- `~` (指代指令调用人自己所在群. 仅群聊天环境下) - `~` (指代指令调用人自己所在群. 仅群聊天环境下)
@ -202,7 +202,7 @@ public object ExistingGroupArgumentParser : InternalCommandArgumentParserExtensi
} }
} }
public object ExistingUserArgumentParser : InternalCommandArgumentParserExtensions<User> { public object ExistingUserValueArgumentParser : InternalCommandValueArgumentParserExtensions<User> {
private val syntax: String = """ private val syntax: String = """
- `botId.groupId.memberId` - `botId.groupId.memberId`
- `botId.groupId.memberCard` (模糊搜索, 寻找最优匹配) - `botId.groupId.memberCard` (模糊搜索, 寻找最优匹配)
@ -215,11 +215,11 @@ public object ExistingUserArgumentParser : InternalCommandArgumentParserExtensio
""".trimIndent() """.trimIndent()
override fun parse(raw: String, sender: CommandSender): User { override fun parse(raw: String, sender: CommandSender): User {
return parseImpl(sender, raw, ExistingMemberArgumentParser::parse, ExistingFriendArgumentParser::parse) return parseImpl(sender, raw, ExistingMemberValueArgumentParser::parse, ExistingFriendValueArgumentParser::parse)
} }
override fun parse(raw: MessageContent, sender: CommandSender): User { override fun parse(raw: MessageContent, sender: CommandSender): User {
return parseImpl(sender, raw, ExistingMemberArgumentParser::parse, ExistingFriendArgumentParser::parse) return parseImpl(sender, raw, ExistingMemberValueArgumentParser::parse, ExistingFriendValueArgumentParser::parse)
} }
private fun <T> parseImpl( private fun <T> parseImpl(
@ -246,7 +246,7 @@ public object ExistingUserArgumentParser : InternalCommandArgumentParserExtensio
} }
public object ExistingContactArgumentParser : InternalCommandArgumentParserExtensions<Contact> { public object ExistingContactValueArgumentParser : InternalCommandValueArgumentParserExtensions<Contact> {
private val syntax: String = """ private val syntax: String = """
- `botId.groupId.memberId` - `botId.groupId.memberId`
- `botId.groupId.memberCard` (模糊搜索, 寻找最优匹配) - `botId.groupId.memberCard` (模糊搜索, 寻找最优匹配)
@ -259,11 +259,11 @@ public object ExistingContactArgumentParser : InternalCommandArgumentParserExten
""".trimIndent() """.trimIndent()
override fun parse(raw: String, sender: CommandSender): Contact { override fun parse(raw: String, sender: CommandSender): Contact {
return parseImpl(sender, raw, ExistingUserArgumentParser::parse, ExistingGroupArgumentParser::parse) return parseImpl(sender, raw, ExistingUserValueArgumentParser::parse, ExistingGroupValueArgumentParser::parse)
} }
override fun parse(raw: MessageContent, sender: CommandSender): Contact { override fun parse(raw: MessageContent, sender: CommandSender): Contact {
return parseImpl(sender, raw, ExistingUserArgumentParser::parse, ExistingGroupArgumentParser::parse) return parseImpl(sender, raw, ExistingUserValueArgumentParser::parse, ExistingGroupValueArgumentParser::parse)
} }
private fun <T> parseImpl( private fun <T> parseImpl(
@ -286,7 +286,7 @@ public object ExistingContactArgumentParser : InternalCommandArgumentParserExten
/** /**
* 解析任意一个群成员. * 解析任意一个群成员.
*/ */
public object ExistingMemberArgumentParser : InternalCommandArgumentParserExtensions<Member> { public object ExistingMemberValueArgumentParser : InternalCommandValueArgumentParserExtensions<Member> {
private val syntax: String = """ private val syntax: String = """
- `botId.groupId.memberId` - `botId.groupId.memberId`
- `botId.groupId.memberCard` (模糊搜索, 寻找最优匹配) - `botId.groupId.memberCard` (模糊搜索, 寻找最优匹配)
@ -333,7 +333,7 @@ public object ExistingMemberArgumentParser : InternalCommandArgumentParserExtens
} }
} }
public object PermissionIdArgumentParser : CommandArgumentParser<PermissionId> { public object PermissionIdValueArgumentParser : CommandValueArgumentParser<PermissionId> {
override fun parse(raw: String, sender: CommandSender): PermissionId { override fun parse(raw: String, sender: CommandSender): PermissionId {
return kotlin.runCatching { PermissionId.parseFromString(raw) }.getOrElse { return kotlin.runCatching { PermissionId.parseFromString(raw) }.getOrElse {
illegalArgument("无法解析 $raw 为 PermissionId") illegalArgument("无法解析 $raw 为 PermissionId")
@ -341,7 +341,7 @@ public object PermissionIdArgumentParser : CommandArgumentParser<PermissionId> {
} }
} }
public object PermitteeIdArgumentParser : CommandArgumentParser<PermitteeId> { public object PermitteeIdValueArgumentParser : CommandValueArgumentParser<PermitteeId> {
override fun parse(raw: String, sender: CommandSender): PermitteeId { override fun parse(raw: String, sender: CommandSender): PermitteeId {
return if (raw == "~") sender.permitteeId return if (raw == "~") sender.permitteeId
else kotlin.runCatching { AbstractPermitteeId.parseFromString(raw) }.getOrElse { else kotlin.runCatching { AbstractPermitteeId.parseFromString(raw) }.getOrElse {
@ -351,19 +351,19 @@ public object PermitteeIdArgumentParser : CommandArgumentParser<PermitteeId> {
override fun parse(raw: MessageContent, sender: CommandSender): PermitteeId { override fun parse(raw: MessageContent, sender: CommandSender): PermitteeId {
if (raw is At) { if (raw is At) {
return ExistingUserArgumentParser.parse(raw, sender).asCommandSender(false).permitteeId return ExistingUserValueArgumentParser.parse(raw, sender).asCommandSender(false).permitteeId
} }
return super.parse(raw, sender) return super.parse(raw, sender)
} }
} }
/** 直接返回原始参数 [MessageContent] */ /** 直接返回原始参数 [MessageContent] */
public object RawContentArgumentParser : CommandArgumentParser<MessageContent> { public object RawContentValueArgumentParser : CommandValueArgumentParser<MessageContent> {
override fun parse(raw: String, sender: CommandSender): MessageContent = PlainText(raw) override fun parse(raw: String, sender: CommandSender): MessageContent = PlainText(raw)
override fun parse(raw: MessageContent, sender: CommandSender): MessageContent = raw override fun parse(raw: MessageContent, sender: CommandSender): MessageContent = raw
} }
internal interface InternalCommandArgumentParserExtensions<T : Any> : CommandArgumentParser<T> { internal interface InternalCommandValueArgumentParserExtensions<T : Any> : CommandValueArgumentParser<T> {
fun String.parseToLongOrFail(): Long = toLongOrNull() ?: illegalArgument("无法解析 $this 为整数") fun String.parseToLongOrFail(): Long = toLongOrNull() ?: illegalArgument("无法解析 $this 为整数")
fun Long.findBotOrFail(): Bot = Bot.getInstanceOrNull(this) ?: illegalArgument("无法找到 Bot: $this") fun Long.findBotOrFail(): Bot = Bot.getInstanceOrNull(this) ?: illegalArgument("无法找到 Bot: $this")

View File

@ -16,8 +16,8 @@ package net.mamoe.mirai.console.command.descriptor
* *
* [message] 将会发送给指令调用方. * [message] 将会发送给指令调用方.
* *
* @see CommandArgumentParser * @see CommandValueArgumentParser
* @see CommandArgumentParser.illegalArgument * @see CommandValueArgumentParser.illegalArgument
*/ */
public class CommandArgumentParserException : RuntimeException { public class CommandArgumentParserException : RuntimeException {
public constructor() : super() public constructor() : super()

View File

@ -65,7 +65,7 @@ public sealed class CommandValueParameter<T> : ICommandParameter<T> {
} }
/** /**
* Extended by [CommandArgumentParser] * Extended by [CommandValueArgumentParser]
*/ */
public abstract class Extended<T> : CommandValueParameter<T>() public abstract class Extended<T> : CommandValueParameter<T>()
} }

View File

@ -32,27 +32,27 @@ import kotlin.contracts.contract
* ``` * ```
* suspend fun CommandSender.mute(target: Member, duration: Int) * suspend fun CommandSender.mute(target: Member, duration: Int)
* ``` * ```
* [CommandManager] 总是从 [SimpleCommand.context] 搜索一个 [T] [Member] [CommandArgumentParser], 并调用其 [CommandArgumentParser.parse] * [CommandManager] 总是从 [SimpleCommand.context] 搜索一个 [T] [Member] [CommandValueArgumentParser], 并调用其 [CommandValueArgumentParser.parse]
* *
* ### 内建指令解析器 * ### 内建指令解析器
* - 基础类型: [ByteArgumentParser], [ShortArgumentParser], [IntArgumentParser], [LongArgumentParser] * - 基础类型: [ByteValueArgumentParser], [ShortValueArgumentParser], [IntValueArgumentParser], [LongValueArgumentParser]
* [FloatArgumentParser], [DoubleArgumentParser], * [FloatValueArgumentParser], [DoubleValueArgumentParser],
* [BooleanArgumentParser], [StringArgumentParser] * [BooleanValueArgumentParser], [StringValueArgumentParser]
* *
* - [Bot]: [ExistingBotArgumentParser] * - [Bot]: [ExistingBotValueArgumentParser]
* - [Friend]: [ExistingFriendArgumentParser] * - [Friend]: [ExistingFriendValueArgumentParser]
* - [Group]: [ExistingGroupArgumentParser] * - [Group]: [ExistingGroupValueArgumentParser]
* - [Member]: [ExistingMemberArgumentParser] * - [Member]: [ExistingMemberValueArgumentParser]
* - [User]: [ExistingUserArgumentParser] * - [User]: [ExistingUserValueArgumentParser]
* - [Contact]: [ExistingContactArgumentParser] * - [Contact]: [ExistingContactValueArgumentParser]
* *
* *
* @see SimpleCommand 简单指令 * @see SimpleCommand 简单指令
* @see CompositeCommand 复合指令 * @see CompositeCommand 复合指令
* *
* @see buildCommandArgumentContext 指令参数环境, [CommandArgumentParser] 的集合 * @see buildCommandArgumentContext 指令参数环境, [CommandValueArgumentParser] 的集合
*/ */
public interface CommandArgumentParser<out T : Any> { public interface CommandValueArgumentParser<out T : Any> {
/** /**
* 解析一个字符串为 [T] 类型参数 * 解析一个字符串为 [T] 类型参数
* *
@ -84,14 +84,14 @@ public interface CommandArgumentParser<out T : Any> {
/** /**
* 使用原 [this] 解析, 成功后使用 [mapper] 映射为另一个类型. * 使用原 [this] 解析, 成功后使用 [mapper] 映射为另一个类型.
*/ */
public fun <T : Any, R : Any> CommandArgumentParser<T>.map( public fun <T : Any, R : Any> CommandValueArgumentParser<T>.map(
mapper: CommandArgumentParser<R>.(T) -> R mapper: CommandValueArgumentParser<R>.(T) -> R,
): CommandArgumentParser<R> = MappingCommandArgumentParser(this, mapper) ): CommandValueArgumentParser<R> = MappingCommandValueArgumentParser(this, mapper)
private class MappingCommandArgumentParser<T : Any, R : Any>( private class MappingCommandValueArgumentParser<T : Any, R : Any>(
private val original: CommandArgumentParser<T>, private val original: CommandValueArgumentParser<T>,
private val mapper: CommandArgumentParser<R>.(T) -> R private val mapper: CommandValueArgumentParser<R>.(T) -> R,
) : CommandArgumentParser<R> { ) : CommandValueArgumentParser<R> {
override fun parse(raw: String, sender: CommandSender): R = mapper(original.parse(raw, sender)) override fun parse(raw: String, sender: CommandSender): R = mapper(original.parse(raw, sender))
override fun parse(raw: MessageContent, sender: CommandSender): R = mapper(original.parse(raw, sender)) override fun parse(raw: MessageContent, sender: CommandSender): R = mapper(original.parse(raw, sender))
} }
@ -103,7 +103,7 @@ private class MappingCommandArgumentParser<T : Any, R : Any>(
*/ */
@JvmSynthetic @JvmSynthetic
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
public fun <T : Any> CommandArgumentParser<T>.parse(raw: Any, sender: CommandSender): T { public fun <T : Any> CommandValueArgumentParser<T>.parse(raw: Any, sender: CommandSender): T {
contract { contract {
returns() implies (raw is String || raw is SingleMessage) returns() implies (raw is String || raw is SingleMessage)
} }
@ -123,7 +123,7 @@ public fun <T : Any> CommandArgumentParser<T>.parse(raw: Any, sender: CommandSen
@Suppress("unused") @Suppress("unused")
@JvmSynthetic @JvmSynthetic
@Throws(CommandArgumentParserException::class) @Throws(CommandArgumentParserException::class)
public inline fun CommandArgumentParser<*>.illegalArgument(message: String, cause: Throwable? = null): Nothing { public inline fun CommandValueArgumentParser<*>.illegalArgument(message: String, cause: Throwable? = null): Nothing {
throw CommandArgumentParserException(message, cause) throw CommandArgumentParserException(message, cause)
} }
@ -134,9 +134,9 @@ public inline fun CommandArgumentParser<*>.illegalArgument(message: String, caus
*/ */
@Throws(CommandArgumentParserException::class) @Throws(CommandArgumentParserException::class)
@JvmSynthetic @JvmSynthetic
public inline fun CommandArgumentParser<*>.checkArgument( public inline fun CommandValueArgumentParser<*>.checkArgument(
condition: Boolean, condition: Boolean,
crossinline message: () -> String = { "Check failed." } crossinline message: () -> String = { "Check failed." },
) { ) {
contract { contract {
returns() implies condition returns() implies condition

View File

@ -16,6 +16,9 @@ import kotlin.reflect.typeOf
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public interface TypeVariant<out OutType> { public interface TypeVariant<out OutType> {
/**
* The reified type of [OutType]
*/
public val outType: KType public val outType: KType
public fun mapValue(valueParameter: MessageContent): OutType public fun mapValue(valueParameter: MessageContent): OutType
@ -33,8 +36,8 @@ public interface TypeVariant<out OutType> {
} }
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public object StringTypeVariant : TypeVariant<RawCommandArgument> { public object MessageContentTypeVariant : TypeVariant<MessageContent> {
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
override val outType: KType = typeOf<String>() override val outType: KType = typeOf<String>()
override fun mapValue(valueParameter: RawCommandArgument): RawCommandArgument = valueParameter override fun mapValue(valueParameter: MessageContent): MessageContent = valueParameter
} }

View File

@ -10,8 +10,8 @@
package net.mamoe.mirai.console.command.parse package net.mamoe.mirai.console.command.parse
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.descriptor.MessageContentTypeVariant
import net.mamoe.mirai.console.command.descriptor.NoValueArgumentMappingException import net.mamoe.mirai.console.command.descriptor.NoValueArgumentMappingException
import net.mamoe.mirai.console.command.descriptor.StringTypeVariant
import net.mamoe.mirai.console.command.descriptor.TypeVariant import net.mamoe.mirai.console.command.descriptor.TypeVariant
import net.mamoe.mirai.message.data.MessageContent import net.mamoe.mirai.message.data.MessageContent
import kotlin.reflect.full.isSubtypeOf import kotlin.reflect.full.isSubtypeOf
@ -23,20 +23,29 @@ import kotlin.reflect.typeOf
*/ */
public typealias RawCommandArgument = MessageContent public typealias RawCommandArgument = MessageContent
/**
* @see CommandValueArgument
*/
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public interface CommandArgument public interface CommandArgument
/**
* @see InvariantCommandValueArgument
*/
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public interface CommandValueArgument : CommandArgument { public interface CommandValueArgument : CommandArgument {
public val value: RawCommandArgument public val value: RawCommandArgument
public val typeVariants: List<TypeVariant<*>> public val typeVariants: List<TypeVariant<*>>
} }
/**
* The [CommandValueArgument] that doesn't vary in type (remaining [MessageContent]).
*/
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public data class InvariantCommandValueArgument( public data class InvariantCommandValueArgument(
public override val value: RawCommandArgument, public override val value: RawCommandArgument,
) : CommandValueArgument { ) : CommandValueArgument {
override val typeVariants: List<TypeVariant<*>> = listOf(StringTypeVariant) override val typeVariants: List<TypeVariant<*>> = listOf(MessageContentTypeVariant)
} }
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors

View File

@ -12,7 +12,7 @@
package net.mamoe.mirai.console.internal.command package net.mamoe.mirai.console.internal.command
import net.mamoe.mirai.console.command.CompositeCommand import net.mamoe.mirai.console.command.CompositeCommand
import net.mamoe.mirai.console.command.descriptor.CommandArgumentParser import net.mamoe.mirai.console.command.descriptor.CommandValueArgumentParser
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.KParameter import kotlin.reflect.KParameter
@ -37,12 +37,12 @@ internal data class CommandParameter<T : Any>(
*/ */
val name: String, val name: String,
/** /**
* 参数类型. 将从 [CompositeCommand.context] 中寻找 [CommandArgumentParser] 解析. * 参数类型. 将从 [CompositeCommand.context] 中寻找 [CommandValueArgumentParser] 解析.
*/ */
val type: KClass<T>, // exact type val type: KClass<T>, // exact type
val parameter: KParameter, // source parameter val parameter: KParameter, // source parameter
) { ) {
constructor(name: String, type: KClass<T>, parameter: KParameter, parser: CommandArgumentParser<T>) : this( constructor(name: String, type: KClass<T>, parameter: KParameter, parser: CommandValueArgumentParser<T>) : this(
name, type, parameter name, type, parameter
) { ) {
this._overrideParser = parser this._overrideParser = parser
@ -50,14 +50,14 @@ internal data class CommandParameter<T : Any>(
@Suppress("PropertyName") @Suppress("PropertyName")
@JvmField @JvmField
internal var _overrideParser: CommandArgumentParser<T>? = null internal var _overrideParser: CommandValueArgumentParser<T>? = null
/** /**
* 覆盖的 [CommandArgumentParser]. * 覆盖的 [CommandValueArgumentParser].
* *
* 如果非 `null`, 将不会从 [CommandArgumentContext] 寻找 [CommandArgumentParser] * 如果非 `null`, 将不会从 [CommandArgumentContext] 寻找 [CommandValueArgumentParser]
*/ */
val overrideParser: CommandArgumentParser<T>? get() = _overrideParser val overrideParser: CommandValueArgumentParser<T>? get() = _overrideParser
} }

View File

@ -22,7 +22,7 @@ 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.registeredCommands
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregister 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.descriptor.CommandArgumentParser import net.mamoe.mirai.console.command.descriptor.CommandValueArgumentParser
import net.mamoe.mirai.console.command.descriptor.buildCommandArgumentContext import net.mamoe.mirai.console.command.descriptor.buildCommandArgumentContext
import net.mamoe.mirai.console.initTestEnvironment import net.mamoe.mirai.console.initTestEnvironment
import net.mamoe.mirai.console.internal.command.CommandManagerImpl import net.mamoe.mirai.console.internal.command.CommandManagerImpl
@ -191,7 +191,7 @@ internal class TestCommand {
ConsoleCommandOwner, ConsoleCommandOwner,
"test22", "test22",
overrideContext = buildCommandArgumentContext { overrideContext = buildCommandArgumentContext {
add(object : CommandArgumentParser<MyClass> { add(object : CommandValueArgumentParser<MyClass> {
override fun parse(raw: String, sender: CommandSender): MyClass { override fun parse(raw: String, sender: CommandSender): MyClass {
return MyClass(raw.toInt()) return MyClass(raw.toInt())
} }