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

View File

@ -10,8 +10,6 @@ import net.mamoe.mirai.message.data.MessageChain
import java.util.*
import java.util.concurrent.locks.ReentrantLock
typealias CommandFullName = Array<out Any>
sealed class 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 }
@get:JvmName("getCommandPrefix")
val CommandPrefix: String
get() = InternalCommandManager._commandPrefix
fun CommandOwner.unregisterAllCommands() {
for (registeredCommand in registeredCommands) {
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 ->
if (list[index] != any) return false
}
@ -124,11 +126,12 @@ internal object InternalCommandManager {
internal val registeredCommands: MutableList<Command> = mutableListOf()
@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
internal val modifyLock = ReentrantLock()
internal var _commandPrefix: String = "/"
internal fun matchCommand(splitted: List<Any>): Command? {
nameToCommandMap.entries.forEach {

View File

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

View File

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

View File

@ -6,23 +6,13 @@
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package net.mamoe.mirai.console.plugins
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
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 {
@ -62,7 +52,7 @@ object JarPluginLoader : PluginLoader<JarPlugin> {
}
}
/*
object PluginManagerOld {
/**
* 通过插件获取介绍
@ -433,4 +423,4 @@ object PluginManagerOld {
jar.entries().asSequence().filter { it.name == toFind }.firstOrNull() ?: return null
return URL("jar:file:" + jarFile.absoluteFile + "!/" + toFindFile.name).openConnection().inputStream
}
}
}*/