Merge remote-tracking branch 'origin/reborn' into reborn

This commit is contained in:
jiahua.liu 2020-05-15 00:12:24 +08:00
commit 5b4ef278fd
5 changed files with 72 additions and 138 deletions

View File

@ -2,106 +2,51 @@
package net.mamoe.mirai.console.command package net.mamoe.mirai.console.command
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.PlainText import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.SingleMessage import net.mamoe.mirai.message.data.SingleMessage
import kotlin.reflect.KClass
/** /**
* 指令描述. 包含名称, 权限要求, 参数解析器环境, 参数列表. * 指令描述. 包含名称, 权限要求, 参数解析器环境, 参数列表.
*
* 这是指令系统较低级的 API. 大部分情况下请使用 [Command]
*/ */
class CommandDescriptor( class CommandDescriptor(
/** /**
* 包含子命令的全名. "`group kick`", 其中 `kick` `group` 的子命令 * 子指令列表
*/ */
fullName: CommandFullName, val subCommands: List<SubCommandDescriptor>,
/** /**
* 用法说明 * 是否建议 console 将这个指令强制注册为需要带 [前缀][CommandPrefix] 的指令.
*/
usage: String,
/**
* 指令参数列表, 有顺序.
*/ */
val suggestForcePrefix: Boolean = true,
/** 覆盖内建的指令参数解析器环境. */
overrideContext: CommandParserContext = CommandParserContext.Empty
) {
/** 子指令描述 */
inner class SubCommandDescriptor(
/** 为空字符串时代表默认 */
val name: String,
/** 用法说明 */
val usage: String,
/** 指令参数列表, 有顺序. */
val params: List<CommandParam<*>>, val params: List<CommandParam<*>>,
/** /** 指令说明 */
* 指令说明 val description: String,
*/ /** 指令别名 */
description: String = "", val aliases: Array<String> = arrayOf(),
/**
* 覆盖内建的指令参数解析器环境.
*/
overrideContext: CommandParserContext = CommandParserContext.Empty,
/**
* 指令别名
*/
aliases: Array<CommandFullName> = arrayOf(),
/** /**
* 指令权限 * 指令权限
*
* @see CommandPermission.or 要求其中一个权限 * @see CommandPermission.or 要求其中一个权限
* @see CommandPermission.and 同时要求两个权限 * @see CommandPermission.and 同时要求两个权限
*/ */
val permission: CommandPermission = CommandPermission.Default val permission: CommandPermission = CommandPermission.Default
) { )
/** /**
* 指令参数解析器环境. * 指令参数解析器环境.
*/ */
val context: CommandParserContext = CommandParserContext.Builtins + overrideContext val context: CommandParserContext = CommandParserContext.Builtins + overrideContext
/**
* 指令别名
*/
val aliases: Array<CommandFullName> = aliases.map { it.checkFullName("alias") }.toTypedArray()
/**
* 指令说明
*/
val description: String = description.trim()
/**
* 用法说明
*/
val usage: String = usage.trim()
/**
* 包含子命令的全名. "`group kick`", 其中 `kick` `group` 的子命令
* 元素类型可以为 [Message] [String]
*/
val fullName: CommandFullName = fullName.checkFullName("fullName")
/**
* `fullName + aliases`
*/
val allNames: Array<CommandFullName> = arrayOf(fullName, *aliases)
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CommandDescriptor
if (!fullName.contentEquals(other.fullName)) return false
if (usage != other.usage) return false
if (params != other.params) return false
if (description != other.description) return false
if (context != other.context) return false
if (!aliases.contentEquals(other.aliases)) return false
if (permission != other.permission) return false
return true
}
override fun hashCode(): Int {
var result = fullName.hashCode()
result = 31 * result + usage.hashCode()
result = 31 * result + params.hashCode()
result = 31 * result + description.hashCode()
result = 31 * result + context.hashCode()
result = 31 * result + aliases.contentHashCode()
result = 31 * result + permission.hashCode()
return result
}
} }
@ -109,13 +54,7 @@ class CommandDescriptor(
* 检查指令参数数量是否足够, 类型是否匹配. * 检查指令参数数量是否足够, 类型是否匹配.
* @throws IllegalArgumentException * @throws IllegalArgumentException
*/ */
fun Command.checkArgs(args: CommandArgs) = this.descriptor.checkArgs(args) fun CommandDescriptor.SubCommandDescriptor.checkArgs(args: CommandArgs) {
/**
* 检查指令参数数量是否足够, 类型是否匹配.
* @throws IllegalArgumentException
*/
fun CommandDescriptor.checkArgs(args: CommandArgs) {
require(args.size >= this.params.size) { "No enough args. Required ${params.size}, but given ${args.size}" } require(args.size >= this.params.size) { "No enough args. Required ${params.size}, but given ${args.size}" }
params.forEachIndexed { index, commandParam -> params.forEachIndexed { index, commandParam ->
require(commandParam.type.isInstance(args[index])) { require(commandParam.type.isInstance(args[index])) {
@ -125,6 +64,7 @@ fun CommandDescriptor.checkArgs(args: CommandArgs) {
} }
/*
/** /**
* 构建一个 [CommandDescriptor] * 构建一个 [CommandDescriptor]
*/ */
@ -133,15 +73,15 @@ inline fun CommandDescriptor(
/** /**
* 指令全名 * 指令全名
*/ */
vararg fullNameComponents: Any, vararg fullNameComponents: String,
block: CommandDescriptorBuilder.() -> Unit = {} block: CommandDescriptorBuilder.() -> Unit = {}
): CommandDescriptor = CommandDescriptorBuilder(*fullNameComponents).apply(block).build() ): CommandDescriptor = CommandDescriptorBuilder(*fullNameComponents).apply(block).build()
class CommandDescriptorBuilder( class CommandDescriptorBuilder(
vararg fullName: Any vararg fullName: String
) { ) {
@PublishedApi @PublishedApi
internal var fullName: CommandFullName = fullName.checkFullName("fullName") internal var fullName: Array<String> = fullName.checkFullName("fullName")
@PublishedApi @PublishedApi
internal var context: CommandParserContext = CommandParserContext.Builtins internal var context: CommandParserContext = CommandParserContext.Builtins
@ -156,7 +96,7 @@ class CommandDescriptorBuilder(
internal var usage: String = "<no usage>" internal var usage: String = "<no usage>"
@PublishedApi @PublishedApi
internal var aliases: MutableList<CommandFullName> = mutableListOf() internal var aliases: MutableList<Array<String>> = mutableListOf()
@PublishedApi @PublishedApi
internal var description: String = "" internal var description: String = ""
@ -194,9 +134,10 @@ class CommandDescriptorBuilder(
/** /**
* 添加一个别名 * 添加一个别名
* @param fullName 全名称. [CommandDescriptor.fullName]
*/ */
fun alias(vararg fullName: Any): CommandDescriptorBuilder = apply { fun alias(fullName: String): CommandDescriptorBuilder = apply {
this.aliases.add(fullName) this.aliases.add(fullName.checkFullName("fullName"))
} }
fun param(vararg params: CommandParam<*>): CommandDescriptorBuilder = apply { fun param(vararg params: CommandParam<*>): CommandDescriptorBuilder = apply {
@ -250,6 +191,7 @@ class CommandDescriptorBuilder(
CommandDescriptor(fullName, usage, params, description, context, aliases.toTypedArray(), permission) CommandDescriptor(fullName, usage, params, description, context, aliases.toTypedArray(), permission)
} }
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS") @Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
inline class ParamBlock internal constructor(@PublishedApi internal val list: MutableList<CommandParam<*>>) { inline class ParamBlock internal constructor(@PublishedApi internal val list: MutableList<CommandParam<*>>) {
/** 添加一个名称为 [this], 类型为 [klass] 的参数. 返回添加成功的对象 */ /** 添加一个名称为 [this], 类型为 [klass] 的参数. 返回添加成功的对象 */
@ -265,23 +207,24 @@ inline class ParamBlock internal constructor(@PublishedApi internal val list: Mu
this typed T::class using parser this typed T::class using parser
} }
*/
/////// ///////
/// internal /// internal
internal fun Any.flattenCommandComponents(): Sequence<Any> = when (this) { internal fun Any.flattenCommandComponents(): Sequence<String> = when (this) {
is Array<*> -> this.asSequence().flatMap { is Array<*> -> this.asSequence().flatMap {
it?.flattenCommandComponents() ?: throw java.lang.IllegalArgumentException("unexpected null value") it?.flattenCommandComponents() ?: throw java.lang.IllegalArgumentException("unexpected null value")
} }
is String -> splitToSequence(' ').filterNot { it.isBlank() } is String -> splitToSequence(' ').filterNot { it.isBlank() }
is PlainText -> content.flattenCommandComponents() is PlainText -> content.flattenCommandComponents()
is SingleMessage -> sequenceOf(this) is SingleMessage -> sequenceOf(this.toString())
is MessageChain -> this.asSequence().flatMap { it.flattenCommandComponents() } is MessageChain -> this.asSequence().flatMap { it.flattenCommandComponents() }
else -> throw IllegalArgumentException("Illegal component: $this") else -> throw IllegalArgumentException("Illegal component: $this")
} }
internal fun CommandFullName.checkFullName(errorHint: String): CommandFullName { internal fun Any.checkFullName(errorHint: String): Array<String> {
return flattenCommandComponents().toList().also { return flattenCommandComponents().toList().also {
require(it.isNotEmpty()) { "$errorHint must not be empty" } require(it.isNotEmpty()) { "$errorHint must not be empty" }
}.toTypedArray() }.toTypedArray()

View File

@ -10,8 +10,6 @@ import net.mamoe.mirai.message.data.MessageChain
import java.util.* import java.util.*
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
typealias CommandFullName = Array<out Any>
sealed class CommandOwner sealed class CommandOwner
abstract class PluginCommandOwner(plugin: PluginBase) : CommandOwner() abstract class PluginCommandOwner(plugin: PluginBase) : CommandOwner()
@ -21,6 +19,10 @@ internal abstract class ConsoleCommandOwner : CommandOwner()
val CommandOwner.registeredCommands: List<Command> get() = InternalCommandManager.registeredCommands.filter { it.owner == this } val CommandOwner.registeredCommands: List<Command> get() = InternalCommandManager.registeredCommands.filter { it.owner == this }
@get:JvmName("getCommandPrefix")
val CommandPrefix: String
get() = InternalCommandManager._commandPrefix
fun CommandOwner.unregisterAllCommands() { fun CommandOwner.unregisterAllCommands() {
for (registeredCommand in registeredCommands) { for (registeredCommand in registeredCommands) {
registeredCommand.unregister() registeredCommand.unregister()
@ -112,7 +114,7 @@ internal suspend fun List<Any>.executeCommand(sender: CommandSender): Boolean {
} }
} }
internal infix fun CommandFullName.matchesBeginning(list: List<Any>): Boolean { internal infix fun Array<String>.matchesBeginning(list: List<Any>): Boolean {
this.forEachIndexed { index, any -> this.forEachIndexed { index, any ->
if (list[index] != any) return false if (list[index] != any) return false
} }
@ -124,11 +126,12 @@ internal object InternalCommandManager {
internal val registeredCommands: MutableList<Command> = mutableListOf() internal val registeredCommands: MutableList<Command> = mutableListOf()
@JvmField @JvmField
internal val nameToCommandMap: TreeMap<CommandFullName, Command> = TreeMap(Comparator.comparingInt { it.size }) internal val nameToCommandMap: TreeMap<Array<String>, Command> = TreeMap(Comparator.comparingInt { it.size })
@JvmField @JvmField
internal val modifyLock = ReentrantLock() internal val modifyLock = ReentrantLock()
internal var _commandPrefix: String = "/"
internal fun matchCommand(splitted: List<Any>): Command? { internal fun matchCommand(splitted: List<Any>): Command? {
nameToCommandMap.entries.forEach { nameToCommandMap.entries.forEach {

View File

@ -9,17 +9,15 @@ import kotlin.reflect.KClass
*/ */
data class CommandParam<T : Any>( data class CommandParam<T : Any>(
/** /**
* 参数名, `null` 时即为匿名参数. * 参数名. 不允许重复.
* 参数名允许重复 (尽管并不建议这样做).
* 参数名仅提供给 [CommandArgParser] 以发送更好的错误信息.
*/ */
val name: String?, val name: String,
/** /**
* 参数类型. 将从 [CommandDescriptor.context] 中寻找 [CommandArgParser] 解析. * 参数类型. 将从 [CommandDescriptor.context] 中寻找 [CommandArgParser] 解析.
*/ */
val type: KClass<T> // exact type val type: KClass<T> // exact type
) { ) {
constructor(name: String?, type: KClass<T>, parser: CommandArgParser<T>) : this(name, type) { constructor(name: String, type: KClass<T>, parser: CommandArgParser<T>) : this(name, type) {
this._overrideParser = parser this._overrideParser = parser
} }

View File

@ -22,11 +22,11 @@ import net.mamoe.mirai.contact.isOwner
* *
* @see AnonymousCommandPermission * @see AnonymousCommandPermission
*/ */
abstract class CommandPermission { interface CommandPermission {
/** /**
* 判断 [this] 是否拥有这个指令的权限 * 判断 [this] 是否拥有这个指令的权限
*/ */
abstract fun CommandSender.hasPermission(): Boolean fun CommandSender.hasPermission(): Boolean
/** /**
@ -43,14 +43,14 @@ abstract class CommandPermission {
/** /**
* 任何人都可以使用这个指令 * 任何人都可以使用这个指令
*/ */
object Any : CommandPermission() { object Any : CommandPermission {
override fun CommandSender.hasPermission(): Boolean = true override fun CommandSender.hasPermission(): Boolean = true
} }
/** /**
* 任何人都不能使用这个指令. 指令只能通过代码在 [execute] 使用 * 任何人都不能使用这个指令. 指令只能通过代码在 [execute] 使用
*/ */
object None : CommandPermission() { object None : CommandPermission {
override fun CommandSender.hasPermission(): Boolean = false override fun CommandSender.hasPermission(): Boolean = false
} }
@ -62,7 +62,7 @@ abstract class CommandPermission {
* 指定只有来自某个 [Bot] 的管理员或群主才可以使用这个指令 * 指定只有来自某个 [Bot] 的管理员或群主才可以使用这个指令
*/ */
vararg val fromBot: Long vararg val fromBot: Long
) : CommandPermission() { ) : CommandPermission {
constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray()) constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray())
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
@ -72,7 +72,7 @@ abstract class CommandPermission {
/** /**
* 来自任何 [Bot] 的任何一个管理员或群主都可以使用这个指令 * 来自任何 [Bot] 的任何一个管理员或群主都可以使用这个指令
*/ */
companion object Any : CommandPermission() { companion object Any : CommandPermission {
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
return this is MemberCommandSender && this.user.isOperator() return this is MemberCommandSender && this.user.isOperator()
} }
@ -87,7 +87,7 @@ abstract class CommandPermission {
* 指定只有来自某个 [Bot] 的群主才可以使用这个指令 * 指定只有来自某个 [Bot] 的群主才可以使用这个指令
*/ */
vararg val fromBot: Long vararg val fromBot: Long
) : CommandPermission() { ) : CommandPermission {
constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray()) constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray())
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
@ -97,7 +97,7 @@ abstract class CommandPermission {
/** /**
* 来自任何 [Bot] 的任何一个群主都可以使用这个指令 * 来自任何 [Bot] 的任何一个群主都可以使用这个指令
*/ */
companion object Any : CommandPermission() { companion object Any : CommandPermission {
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
return this is MemberCommandSender && this.user.isOwner() return this is MemberCommandSender && this.user.isOwner()
} }
@ -112,7 +112,7 @@ abstract class CommandPermission {
* 指定只有来自某个 [Bot] 的管理员 (不包含群主) 才可以使用这个指令 * 指定只有来自某个 [Bot] 的管理员 (不包含群主) 才可以使用这个指令
*/ */
vararg val fromBot: Long vararg val fromBot: Long
) : CommandPermission() { ) : CommandPermission {
constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray()) constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray())
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
@ -122,7 +122,7 @@ abstract class CommandPermission {
/** /**
* 来自任何 [Bot] 的任何一个管理员 (不包含群主) 都可以使用这个指令 * 来自任何 [Bot] 的任何一个管理员 (不包含群主) 都可以使用这个指令
*/ */
companion object Any : CommandPermission() { companion object Any : CommandPermission {
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
return this is MemberCommandSender && this.user.isAdministrator() return this is MemberCommandSender && this.user.isAdministrator()
} }
@ -137,7 +137,7 @@ abstract class CommandPermission {
* 指定只有来自某个 [Bot] 的管理员或群主才可以使用这个指令 * 指定只有来自某个 [Bot] 的管理员或群主才可以使用这个指令
*/ */
vararg val fromBot: Long vararg val fromBot: Long
) : CommandPermission() { ) : CommandPermission {
constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray()) constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray())
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
@ -147,7 +147,7 @@ abstract class CommandPermission {
/** /**
* 任何 [Bot] manager 都可以使用这个指令 * 任何 [Bot] manager 都可以使用这个指令
*/ */
companion object Any : CommandPermission() { companion object Any : CommandPermission {
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
return this is MemberCommandSender && this.user.isManager return this is MemberCommandSender && this.user.isManager
} }
@ -157,7 +157,7 @@ abstract class CommandPermission {
/** /**
* 仅控制台能使用和这个指令 * 仅控制台能使用和这个指令
*/ */
object Console : CommandPermission() { object Console : CommandPermission {
override fun CommandSender.hasPermission(): Boolean = false override fun CommandSender.hasPermission(): Boolean = false
} }
@ -173,7 +173,7 @@ abstract class CommandPermission {
@JvmSynthetic @JvmSynthetic
@Suppress("FunctionName") @Suppress("FunctionName")
inline fun AnonymousCommandPermission(crossinline block: CommandSender.() -> Boolean): CommandPermission { inline fun AnonymousCommandPermission(crossinline block: CommandSender.() -> Boolean): CommandPermission {
return object : CommandPermission() { return object : CommandPermission {
override fun CommandSender.hasPermission(): Boolean = block() override fun CommandSender.hasPermission(): Boolean = block()
} }
} }
@ -188,7 +188,7 @@ inline fun CommandPermission.hasPermission(sender: CommandSender): Boolean = thi
internal class OrCommandPermission( internal class OrCommandPermission(
private val first: CommandPermission, private val first: CommandPermission,
private val second: CommandPermission private val second: CommandPermission
) : CommandPermission() { ) : CommandPermission {
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
return this.hasPermission(first) || this.hasPermission(second) return this.hasPermission(first) || this.hasPermission(second)
} }
@ -197,7 +197,7 @@ internal class OrCommandPermission(
internal class AndCommandPermission( internal class AndCommandPermission(
private val first: CommandPermission, private val first: CommandPermission,
private val second: CommandPermission private val second: CommandPermission
) : CommandPermission() { ) : CommandPermission {
override fun CommandSender.hasPermission(): Boolean { override fun CommandSender.hasPermission(): Boolean {
return this.hasPermission(first) && this.hasPermission(second) return this.hasPermission(first) && this.hasPermission(second)
} }

View File

@ -6,23 +6,13 @@
* *
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package net.mamoe.mirai.console.plugins package net.mamoe.mirai.console.plugins
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.command.Command
import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.command.description
import net.mamoe.mirai.console.encodeToString
import net.mamoe.mirai.utils.LockFreeLinkedList
import java.io.File
import java.io.InputStream
import java.net.JarURLConnection
import java.net.URL
import java.util.jar.JarFile
sealed class JarPlugin : Plugin(), CoroutineScope { sealed class JarPlugin : Plugin(), CoroutineScope {
@ -62,7 +52,7 @@ object JarPluginLoader : PluginLoader<JarPlugin> {
} }
} }
/*
object PluginManagerOld { object PluginManagerOld {
/** /**
* 通过插件获取介绍 * 通过插件获取介绍
@ -433,4 +423,4 @@ object PluginManagerOld {
jar.entries().asSequence().filter { it.name == toFind }.firstOrNull() ?: return null jar.entries().asSequence().filter { it.name == toFind }.firstOrNull() ?: return null
return URL("jar:file:" + jarFile.absoluteFile + "!/" + toFindFile.name).openConnection().inputStream return URL("jar:file:" + jarFile.absoluteFile + "!/" + toFindFile.name).openConnection().inputStream
} }
} }*/