mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Use MessageChain for arguments for executing commands
This commit is contained in:
parent
be9b0293bd
commit
4566403ece
@ -16,6 +16,7 @@ import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
|
||||
import net.mamoe.mirai.console.command.java.JCommand
|
||||
import net.mamoe.mirai.console.internal.command.isValidSubName
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
|
||||
/**
|
||||
@ -71,7 +72,7 @@ public interface Command {
|
||||
* @see CommandManager.executeCommand 查看更多信息
|
||||
*/
|
||||
@JvmBlockingBridge
|
||||
public suspend fun CommandSender.onCommand(args: Array<out Any>)
|
||||
public suspend fun CommandSender.onCommand(args: MessageChain)
|
||||
|
||||
public companion object {
|
||||
/**
|
||||
@ -84,7 +85,7 @@ public interface Command {
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
public suspend inline fun Command.onCommand(sender: CommandSender, args: Array<out Any>): Unit =
|
||||
public suspend inline fun Command.onCommand(sender: CommandSender, args: MessageChain): Unit =
|
||||
sender.run { onCommand(args) }
|
||||
|
||||
/**
|
||||
|
@ -13,6 +13,7 @@ package net.mamoe.mirai.console.command
|
||||
|
||||
import net.mamoe.mirai.console.command.CommandExecuteResult.CommandExecuteStatus
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import kotlin.contracts.contract
|
||||
|
||||
/**
|
||||
@ -34,7 +35,7 @@ public sealed class CommandExecuteResult {
|
||||
public abstract val commandName: String?
|
||||
|
||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||
public abstract val args: Array<out Any>?
|
||||
public abstract val args: MessageChain?
|
||||
|
||||
// abstract val to allow smart casting
|
||||
|
||||
@ -45,7 +46,7 @@ public sealed class CommandExecuteResult {
|
||||
/** 尝试执行的指令名 */
|
||||
public override val commandName: String,
|
||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||
public override val args: Array<out Any>
|
||||
public override val args: MessageChain
|
||||
) : CommandExecuteResult() {
|
||||
/** 指令执行时发生的错误, 总是 `null` */
|
||||
public override val exception: Nothing? get() = null
|
||||
@ -63,7 +64,7 @@ public sealed class CommandExecuteResult {
|
||||
/** 尝试执行的指令名 */
|
||||
public override val commandName: String,
|
||||
/** 基础分割后的实际参数列表, 元素类型可能为 [Message] 或 [String] */
|
||||
public override val args: Array<out Any>
|
||||
public override val args: MessageChain
|
||||
) : CommandExecuteResult() {
|
||||
/** 指令最终执行状态, 总是 [CommandExecuteStatus.EXECUTION_EXCEPTION] */
|
||||
public override val status: CommandExecuteStatus get() = CommandExecuteStatus.EXECUTION_EXCEPTION
|
||||
|
@ -21,6 +21,7 @@ import net.mamoe.mirai.console.command.description.*
|
||||
import net.mamoe.mirai.console.internal.command.AbstractReflectionCommand
|
||||
import net.mamoe.mirai.console.internal.command.CompositeCommandSubCommandAnnotationResolver
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import kotlin.annotation.AnnotationRetention.RUNTIME
|
||||
import kotlin.annotation.AnnotationTarget.FUNCTION
|
||||
import kotlin.reflect.KClass
|
||||
@ -116,14 +117,14 @@ public abstract class CompositeCommand(
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
protected annotation class Name(val value: String)
|
||||
|
||||
public final override suspend fun CommandSender.onCommand(args: Array<out Any>) {
|
||||
public final override suspend fun CommandSender.onCommand(args: MessageChain) {
|
||||
matchSubCommand(args)?.parseAndExecute(this, args, true) ?: kotlin.run {
|
||||
defaultSubCommand.onCommand(this, args)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override suspend fun CommandSender.onDefault(rawArgs: Array<out Any>) {
|
||||
protected override suspend fun CommandSender.onDefault(rawArgs: MessageChain) {
|
||||
sendMessage(usage)
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ package net.mamoe.mirai.console.command
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.execute
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand
|
||||
import net.mamoe.mirai.console.command.java.JRawCommand
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
|
||||
/**
|
||||
* 无参数解析, 接收原生参数的指令.
|
||||
@ -47,11 +47,11 @@ public abstract class RawCommand(
|
||||
/**
|
||||
* 在指令被执行时调用.
|
||||
*
|
||||
* @param args 指令参数. 数组元素类型可能是 [SingleMessage] 或 [String]. 且已经以 ' ' 分割.
|
||||
* @param args 指令参数.
|
||||
*
|
||||
* @see CommandManager.execute 查看更多信息
|
||||
*/
|
||||
public abstract override suspend fun CommandSender.onCommand(args: Array<out Any>)
|
||||
public abstract override suspend fun CommandSender.onCommand(args: MessageChain)
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,6 +22,7 @@ import net.mamoe.mirai.console.command.description.*
|
||||
import net.mamoe.mirai.console.command.java.JSimpleCommand
|
||||
import net.mamoe.mirai.console.internal.command.AbstractReflectionCommand
|
||||
import net.mamoe.mirai.console.internal.command.SimpleCommandSubCommandAnnotationResolver
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
|
||||
/**
|
||||
* 简单的, 支持参数自动解析的指令.
|
||||
@ -71,7 +72,7 @@ public abstract class SimpleCommand(
|
||||
*/
|
||||
public override val context: CommandArgumentContext = CommandArgumentContext.Builtins + overrideContext
|
||||
|
||||
public final override suspend fun CommandSender.onCommand(args: Array<out Any>) {
|
||||
public final override suspend fun CommandSender.onCommand(args: MessageChain) {
|
||||
subCommands.single().parseAndExecute(this, args, false)
|
||||
}
|
||||
|
||||
@ -81,7 +82,7 @@ public abstract class SimpleCommand(
|
||||
}
|
||||
|
||||
@Deprecated("prohibited", level = DeprecationLevel.HIDDEN)
|
||||
internal override suspend fun CommandSender.onDefault(rawArgs: Array<out Any>) {
|
||||
internal override suspend fun CommandSender.onDefault(rawArgs: MessageChain) {
|
||||
sendMessage(usage)
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import net.mamoe.mirai.console.command.Command
|
||||
import net.mamoe.mirai.console.command.CommandManager
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand
|
||||
import net.mamoe.mirai.console.command.CommandSender
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
|
||||
/**
|
||||
@ -25,7 +26,7 @@ import net.mamoe.mirai.message.data.SingleMessage
|
||||
* @see Command
|
||||
*/
|
||||
public interface JCommand : Command {
|
||||
public override suspend fun CommandSender.onCommand(args: Array<out Any>) {
|
||||
public override suspend fun CommandSender.onCommand(args: MessageChain) {
|
||||
withContext(Dispatchers.IO) { onCommand(this@onCommand, args) }
|
||||
}
|
||||
|
||||
@ -36,5 +37,5 @@ public interface JCommand : Command {
|
||||
*
|
||||
* @see CommandManager.executeCommand 查看更多信息
|
||||
*/
|
||||
public fun onCommand(sender: CommandSender, args: Array<out Any>) // overrides bridge
|
||||
public fun onCommand(sender: CommandSender, args: MessageChain) // overrides bridge
|
||||
}
|
@ -11,10 +11,10 @@ package net.mamoe.mirai.console.command.java
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.mamoe.mirai.console.command.Command
|
||||
import net.mamoe.mirai.console.command.CommandOwner
|
||||
import net.mamoe.mirai.console.command.CommandPermission
|
||||
import net.mamoe.mirai.console.command.CommandSender
|
||||
import net.mamoe.mirai.console.command.*
|
||||
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.execute
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
|
||||
/**
|
||||
* 供 Java 用户继承
|
||||
@ -76,9 +76,9 @@ public abstract class JRawCommand(
|
||||
*/
|
||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||
@JvmName("onCommand")
|
||||
public abstract fun onCommand(sender: CommandSender, args: Array<out Any>)
|
||||
public abstract fun onCommand(sender: CommandSender, args: MessageChain)
|
||||
|
||||
public final override suspend fun CommandSender.onCommand(args: Array<out Any>) {
|
||||
public final override suspend fun CommandSender.onCommand(args: MessageChain) {
|
||||
withContext(Dispatchers.IO) { onCommand(this@onCommand, args) }
|
||||
}
|
||||
}
|
@ -147,7 +147,7 @@ internal object CommandManagerImpl : CommandManager, CoroutineScope by Coroutine
|
||||
): CommandExecuteResult {
|
||||
return sender.executeCommandInternal(
|
||||
this,
|
||||
arguments.flattenCommandComponents().toTypedArray(),
|
||||
arguments.flattenCommandComponents(),
|
||||
primaryName,
|
||||
checkPermission
|
||||
)
|
||||
@ -160,7 +160,7 @@ internal object CommandManagerImpl : CommandManager, CoroutineScope by Coroutine
|
||||
): CommandExecuteResult {
|
||||
return sender.executeCommandInternal(
|
||||
this,
|
||||
arguments.flattenCommandComponents().toTypedArray(),
|
||||
arguments.flattenCommandComponents(),
|
||||
primaryName,
|
||||
checkPermission
|
||||
)
|
||||
|
@ -15,8 +15,10 @@ import net.mamoe.mirai.console.command.*
|
||||
import net.mamoe.mirai.console.command.Command.Companion.primaryName
|
||||
import net.mamoe.mirai.console.command.description.CommandArgumentContext
|
||||
import net.mamoe.mirai.console.command.description.CommandArgumentContextAware
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
import net.mamoe.mirai.message.data.buildMessageChain
|
||||
import kotlin.reflect.KAnnotatedElement
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KFunction
|
||||
@ -65,13 +67,13 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
return _usage
|
||||
}
|
||||
|
||||
abstract suspend fun CommandSender.onDefault(rawArgs: Array<out Any>)
|
||||
abstract suspend fun CommandSender.onDefault(rawArgs: MessageChain)
|
||||
|
||||
internal val defaultSubCommand: DefaultSubCommandDescriptor by lazy {
|
||||
DefaultSubCommandDescriptor(
|
||||
"",
|
||||
permission,
|
||||
onCommand = { sender: CommandSender, args: Array<out Any> ->
|
||||
onCommand = { sender: CommandSender, args: MessageChain ->
|
||||
sender.onDefault(args)
|
||||
}
|
||||
)
|
||||
@ -116,7 +118,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
internal class DefaultSubCommandDescriptor(
|
||||
val description: String,
|
||||
val permission: CommandPermission,
|
||||
val onCommand: suspend (sender: CommandSender, rawArgs: Array<out Any>) -> Unit
|
||||
val onCommand: suspend (sender: CommandSender, rawArgs: MessageChain) -> Unit
|
||||
)
|
||||
|
||||
internal inner class SubCommandDescriptor(
|
||||
@ -130,7 +132,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
val usage: String = createUsage(this@AbstractReflectionCommand)
|
||||
internal suspend fun parseAndExecute(
|
||||
sender: CommandSender,
|
||||
argsWithSubCommandNameNotRemoved: Array<out Any>,
|
||||
argsWithSubCommandNameNotRemoved: MessageChain,
|
||||
removeSubName: Boolean
|
||||
) {
|
||||
val args = parseArgs(sender, argsWithSubCommandNameNotRemoved, if (removeSubName) names.size else 0)
|
||||
@ -145,7 +147,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
|
||||
@JvmField
|
||||
internal val bakedSubNames: Array<Array<String>> = names.map { it.bakeSubName() }.toTypedArray()
|
||||
private fun parseArgs(sender: CommandSender, rawArgs: Array<out Any>, offset: Int): Array<out Any>? {
|
||||
private fun parseArgs(sender: CommandSender, rawArgs: MessageChain, offset: Int): Array<out Any>? {
|
||||
if (rawArgs.size < offset + this.params.size)
|
||||
return null
|
||||
//require(rawArgs.size >= offset + this.params.size) { "No enough args. Required ${params.size}, but given ${rawArgs.size - offset}" }
|
||||
@ -154,9 +156,8 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
val param = params[index]
|
||||
val rawArg = rawArgs[offset + index]
|
||||
when (rawArg) {
|
||||
is String -> context[param.type]?.parse(rawArg, sender)
|
||||
is SingleMessage -> context[param.type]?.parse(rawArg, sender)
|
||||
else -> throw IllegalArgumentException("Illegal argument type: ${rawArg::class.qualifiedName}")
|
||||
is PlainText -> context[param.type]?.parse(rawArg.content, sender)
|
||||
else -> context[param.type]?.parse(rawArg, sender)
|
||||
} ?: error("Cannot find a parser for $rawArg")
|
||||
}
|
||||
}
|
||||
@ -165,7 +166,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
/**
|
||||
* @param rawArgs 元素类型必须为 [SingleMessage] 或 [String], 且已经经过扁平化处理. 否则抛出异常 [IllegalArgumentException]
|
||||
*/
|
||||
internal fun matchSubCommand(rawArgs: Array<out Any>): SubCommandDescriptor? {
|
||||
internal fun matchSubCommand(rawArgs: MessageChain): SubCommandDescriptor? {
|
||||
val maxCount = rawArgs.size
|
||||
var cur = 0
|
||||
bakedCommandNameToSubDescriptorArray.forEach { (name, descriptor) ->
|
||||
@ -180,7 +181,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> Array<T>.contentEqualsOffset(other: Array<out Any>, length: Int): Boolean {
|
||||
internal fun <T> Array<T>.contentEqualsOffset(other: MessageChain, length: Int): Boolean {
|
||||
repeat(length) { index ->
|
||||
if (!other[index].toString().equals(this[index].toString(), ignoreCase = true)) {
|
||||
return false
|
||||
@ -193,18 +194,16 @@ internal val ILLEGAL_SUB_NAME_CHARS = "\\/!@#$%^&*()_+-={}[];':\",.<>?`~".toChar
|
||||
internal fun String.isValidSubName(): Boolean = ILLEGAL_SUB_NAME_CHARS.none { it in this }
|
||||
internal fun String.bakeSubName(): Array<String> = split(' ').filterNot { it.isBlank() }.toTypedArray()
|
||||
|
||||
internal fun Any.flattenCommandComponents(): ArrayList<Any> {
|
||||
val list = ArrayList<Any>()
|
||||
when (this) {
|
||||
is PlainText -> this.content.splitToSequence(' ').filterNot { it.isBlank() }
|
||||
.forEach { list.add(it) }
|
||||
is CharSequence -> this.splitToSequence(' ').filterNot { it.isBlank() }.forEach { list.add(it) }
|
||||
is SingleMessage -> list.add(this)
|
||||
is Array<*> -> this.forEach { if (it != null) list.addAll(it.flattenCommandComponents()) }
|
||||
is Iterable<*> -> this.forEach { if (it != null) list.addAll(it.flattenCommandComponents()) }
|
||||
else -> list.add(this.toString())
|
||||
internal fun Any.flattenCommandComponents(): MessageChain = buildMessageChain {
|
||||
when (this@flattenCommandComponents) {
|
||||
is PlainText -> this@flattenCommandComponents.content.splitToSequence(' ').filterNot { it.isBlank() }
|
||||
.forEach { +it }
|
||||
is CharSequence -> this@flattenCommandComponents.splitToSequence(' ').filterNot { it.isBlank() }.forEach { +it }
|
||||
is SingleMessage -> +(this@flattenCommandComponents)
|
||||
is Array<*> -> this@flattenCommandComponents.forEach { if (it != null) addAll(it.flattenCommandComponents()) }
|
||||
is Iterable<*> -> this@flattenCommandComponents.forEach { if (it != null) addAll(it.flattenCommandComponents()) }
|
||||
else -> add(this@flattenCommandComponents.toString())
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
internal inline fun <reified T : Annotation> KAnnotatedElement.hasAnnotation(): Boolean =
|
||||
|
@ -12,6 +12,8 @@ package net.mamoe.mirai.console.internal.command
|
||||
import net.mamoe.mirai.console.command.*
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.asMessageChain
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@ -144,7 +146,7 @@ internal inline fun <reified T> List<T>.dropToTypedArray(n: Int): Array<T> = Arr
|
||||
@Throws(CommandExecutionException::class)
|
||||
internal suspend fun CommandSender.executeCommandInternal(
|
||||
command: Command,
|
||||
args: Array<out Any>,
|
||||
args: MessageChain,
|
||||
commandName: String,
|
||||
checkPermission: Boolean
|
||||
): CommandExecuteResult {
|
||||
@ -182,7 +184,7 @@ internal suspend fun CommandSender.executeCommandInternal(
|
||||
): CommandExecuteResult {
|
||||
val command =
|
||||
CommandManagerImpl.matchCommand(commandName) ?: return CommandExecuteResult.CommandNotFound(commandName)
|
||||
val args = messages.flattenCommandComponents().dropToTypedArray(1)
|
||||
val args = messages.flattenCommandComponents()
|
||||
|
||||
return executeCommandInternal(command, args, commandName, checkPermission)
|
||||
return executeCommandInternal(command, args.drop(1).asMessageChain(), commandName, checkPermission)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user