Skip to content

Commit

Permalink
区分出新的Command
Browse files Browse the repository at this point in the history
  • Loading branch information
hundun000 committed Jul 2, 2022
1 parent 826dbe7 commit 877793d
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 160 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ public abstract class net/mamoe/mirai/console/command/AbstractCommand : net/mamo
public fun getUsage ()Ljava/lang/String;
}

protected abstract interface annotation class net/mamoe/mirai/console/command/AbstractCommand$AsSubCommandProvider : java/lang/annotation/Annotation {
}

public abstract class net/mamoe/mirai/console/command/AbstractCommandSender : kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/console/command/CommandSender {
public abstract fun getBot ()Lnet/mamoe/mirai/Bot;
public abstract fun getSubject ()Lnet/mamoe/mirai/contact/Contact;
Expand Down Expand Up @@ -381,17 +384,15 @@ public abstract interface class net/mamoe/mirai/console/command/CommandSenderOnM
public abstract fun getFromEvent ()Lnet/mamoe/mirai/event/events/MessageEvent;
}

public abstract class net/mamoe/mirai/console/command/CompositeCommand : net/mamoe/mirai/console/command/AbstractCommand, net/mamoe/mirai/console/command/Command, net/mamoe/mirai/console/command/descriptor/CommandArgumentContextAware {
public abstract class net/mamoe/mirai/console/command/CompositeCommand : net/mamoe/mirai/console/command/AbstractCommand, net/mamoe/mirai/console/command/Command, net/mamoe/mirai/console/command/SubCommandProvider, net/mamoe/mirai/console/command/descriptor/CommandArgumentContextAware {
public fun <init> (Lnet/mamoe/mirai/console/command/CommandOwner;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/console/permission/Permission;Lnet/mamoe/mirai/console/command/descriptor/CommandArgumentContext;)V
public synthetic fun <init> (Lnet/mamoe/mirai/console/command/CommandOwner;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/console/permission/Permission;Lnet/mamoe/mirai/console/command/descriptor/CommandArgumentContext;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getContext ()Lnet/mamoe/mirai/console/command/descriptor/CommandArgumentContext;
public final fun getOverloads ()Ljava/util/List;
public final fun getProvideOverloads ()Ljava/util/List;
public fun getUsage ()Ljava/lang/String;
}

protected abstract interface annotation class net/mamoe/mirai/console/command/CompositeCommand$ChildCommand : java/lang/annotation/Annotation {
}

protected abstract interface annotation class net/mamoe/mirai/console/command/CompositeCommand$Description : java/lang/annotation/Annotation {
public abstract fun value ()Ljava/lang/String;
}
Expand Down Expand Up @@ -511,6 +512,15 @@ public final class net/mamoe/mirai/console/command/GroupTempCommandSenderOnMessa
public synthetic fun getFromEvent ()Lnet/mamoe/mirai/event/events/MessageEvent;
}

public abstract class net/mamoe/mirai/console/command/GroupedCommand : net/mamoe/mirai/console/command/AbstractCommand, net/mamoe/mirai/console/command/Command, net/mamoe/mirai/console/command/SubCommandProvider, net/mamoe/mirai/console/command/descriptor/CommandArgumentContextAware {
public fun <init> (Lnet/mamoe/mirai/console/command/CommandOwner;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/console/permission/Permission;Lnet/mamoe/mirai/console/command/descriptor/CommandArgumentContext;)V
public synthetic fun <init> (Lnet/mamoe/mirai/console/command/CommandOwner;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/console/permission/Permission;Lnet/mamoe/mirai/console/command/descriptor/CommandArgumentContext;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getContext ()Lnet/mamoe/mirai/console/command/descriptor/CommandArgumentContext;
public final fun getOverloads ()Ljava/util/List;
public final fun getProvideOverloads ()Ljava/util/List;
public fun getUsage ()Ljava/lang/String;
}

public class net/mamoe/mirai/console/command/IllegalCommandArgumentException : java/lang/IllegalArgumentException {
public fun <init> (Ljava/lang/String;)V
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
Expand Down Expand Up @@ -583,11 +593,12 @@ public abstract class net/mamoe/mirai/console/command/RawCommand : net/mamoe/mir
public fun onCommand (Lnet/mamoe/mirai/console/command/CommandSender;Lnet/mamoe/mirai/message/data/MessageChain;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public abstract class net/mamoe/mirai/console/command/SimpleCommand : net/mamoe/mirai/console/command/AbstractCommand, net/mamoe/mirai/console/command/Command, net/mamoe/mirai/console/command/descriptor/CommandArgumentContextAware {
public abstract class net/mamoe/mirai/console/command/SimpleCommand : net/mamoe/mirai/console/command/AbstractCommand, net/mamoe/mirai/console/command/Command, net/mamoe/mirai/console/command/SubCommandProvider, net/mamoe/mirai/console/command/descriptor/CommandArgumentContextAware {
public fun <init> (Lnet/mamoe/mirai/console/command/CommandOwner;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/console/permission/Permission;Lnet/mamoe/mirai/console/command/descriptor/CommandArgumentContext;)V
public synthetic fun <init> (Lnet/mamoe/mirai/console/command/CommandOwner;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/console/permission/Permission;Lnet/mamoe/mirai/console/command/descriptor/CommandArgumentContext;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getContext ()Lnet/mamoe/mirai/console/command/descriptor/CommandArgumentContext;
public final fun getOverloads ()Ljava/util/List;
public final fun getProvideOverloads ()Ljava/util/List;
public fun getUsage ()Ljava/lang/String;
}

Expand All @@ -613,6 +624,10 @@ public final class net/mamoe/mirai/console/command/StrangerCommandSenderOnMessag
public fun getFromEvent ()Lnet/mamoe/mirai/event/events/StrangerMessageEvent;
}

public abstract interface class net/mamoe/mirai/console/command/SubCommandProvider {
public abstract fun getProvideOverloads ()Ljava/util/List;
}

public abstract interface class net/mamoe/mirai/console/command/SystemCommandSender : net/mamoe/mirai/console/command/CommandSender {
public abstract fun isAnsiSupported ()Z
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ public abstract class AbstractCommand
secondaryNames.forEach(Command.Companion::checkCommandName)
}

/**
* 标记一个属性为子指令集合
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
protected annotation class AsSubCommandProvider(
)

public override val usage: String get() = description
public override val permission: Permission by lazy { findOrCreateCommandPermission(parentPermission) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public abstract class CompositeCommand(
parentPermission: Permission = owner.parentPermission,
overrideContext: CommandArgumentContext = EmptyCommandArgumentContext,
) : Command, AbstractCommand(owner, primaryName, secondaryNames = secondaryNames, description, parentPermission),
CommandArgumentContextAware {
CommandArgumentContextAware, SubCommandProvider {

private val reflector by lazy { CommandReflector(this, CompositeCommandSubCommandAnnotationResolver) }

Expand All @@ -104,6 +104,12 @@ public abstract class CompositeCommand(
}
}

@ExperimentalCommandDescriptors
public final override val provideOverloads: List<CommandSignatureFromKFunction> by lazy {
// TODO 再加上额外的filter/validate?
overloads
}

/**
* 自动根据带有 [SubCommand] 注解的函数签名生成 [usage]. 也可以被覆盖.
*/
Expand All @@ -127,14 +133,6 @@ public abstract class CompositeCommand(
@ResolveContext(COMMAND_NAME) vararg val value: String = [],
)

/**
* 标记一个属性为子指令集合
*/
@Retention(RUNTIME)
@Target(PROPERTY)
protected annotation class ChildCommand(
)

/** 指令描述 */
@Retention(RUNTIME)
@Target(FUNCTION)
Expand Down
129 changes: 129 additions & 0 deletions mirai-console/backend/mirai-console/src/command/GroupedCommand.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/

package net.mamoe.mirai.console.command

import net.mamoe.mirai.console.command.descriptor.*
import net.mamoe.mirai.console.command.java.JCompositeCommand
import net.mamoe.mirai.console.compiler.common.ResolveContext
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.COMMAND_NAME
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.RESTRICTED_CONSOLE_COMMAND_OWNER
import net.mamoe.mirai.console.internal.command.CommandReflector
import net.mamoe.mirai.console.internal.command.CompositeCommandSubCommandAnnotationResolver
import net.mamoe.mirai.console.internal.command.GroupedCommandSubCommandAnnotationResolver
import net.mamoe.mirai.console.permission.Permission
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.FUNCTION
import kotlin.annotation.AnnotationTarget.PROPERTY


/**
* 复合指令. 指令注册时候会通过反射构造指令解析器.
*
* Java 示例查看 [JCompositeCommand].
*
* Kotlin 示例:
* ```
* @OptIn(ConsoleExperimentalAPI::class)
* object MyCompositeCommand : CompositeCommand(
* MyPluginMain, "manage", // "manage" 是主指令名
* description = "示例指令", permission = MyCustomPermission,
* // prefixOptional = true // 还有更多参数可填, 此处忽略
* ) {
*
* // [参数智能解析]
* //
* // 在控制台执行 "/manage <群号>.<群员> <持续时间>",
* // 或在聊天群内发送 "/manage <@一个群员> <持续时间>",
* // 或在聊天群内发送 "/manage <目标群员的群名> <持续时间>",
* // 或在聊天群内发送 "/manage <目标群员的账号> <持续时间>"
* // 时调用这个函数
* @SubCommand // 表示这是一个子指令,使用函数名作为子指令名称
* suspend fun CommandSender.mute(target: Member, duration: Int) { // 通过 /manage mute <target> <duration> 调用
* sendMessage("/manage mute 被调用了, 参数为: $target, $duration")
*
* val result = kotlin.runCatching {
* target.mute(duration).toString()
* }.getOrElse {
* it.stackTraceToString()
* } // 失败时返回堆栈信息
*
* sendMessage("结果: $result")
* }
*
* @SubCommand
* suspend fun SystemCommandSender.foo() {
* // 使用 SystemCommandSender 作为接收者,表示指令只能由系统(控制台或其他插件)执行。
* // 当用户尝试在聊天环境执行时将会收到错误提示。
* }
*
* @SubCommand("list", "查看列表") // 可以设置多个子指令名。此时函数名会被忽略。
* suspend fun CommandSender.list() { // 执行 "/manage list" 时调用这个函数
* sendMessage("/manage list 被调用了")
* }
*
* @SubCommand
* suspend fun CommandContext.repeat() {
* // 使用 CommandContext 作为参数,可以获得触发指令的原消息链 originalMessage,其中包含 MessageMetadata。
* sender.sendMessage(originalMessage)
* }
*
* // 支持 Image 类型, 需在聊天中执行此指令.
* @SubCommand
* suspend fun UserCommandSender.test(image: Image) { // 执行 "/manage test <一张图片>" 时调用这个函数
* // 由于 Image 类型消息只可能在聊天环境,可以直接使用 UserCommandSender。
* sendMessage("/manage image 被调用了, 图片是 ${image.imageId}")
* }
* }
* ```
*
* @see buildCommandArgumentContext
*/
public abstract class GroupedCommand(
@ResolveContext(RESTRICTED_CONSOLE_COMMAND_OWNER) owner: CommandOwner,
@ResolveContext(COMMAND_NAME) primaryName: String,
@ResolveContext(COMMAND_NAME) vararg secondaryNames: String,
description: String = "no description available",
parentPermission: Permission = owner.parentPermission,
overrideContext: CommandArgumentContext = EmptyCommandArgumentContext,
) : Command, AbstractCommand(owner, primaryName, secondaryNames = secondaryNames, description, parentPermission),
CommandArgumentContextAware, SubCommandProvider {

private val reflector by lazy { CommandReflector(this, GroupedCommandSubCommandAnnotationResolver) }

@ExperimentalCommandDescriptors
public final override val overloads: List<@JvmWildcard CommandSignatureFromKFunction> by lazy {
reflector.findSubCommands().also {
reflector.validate(it)
}
}

@ExperimentalCommandDescriptors
public final override val provideOverloads: List<CommandSignatureFromKFunction> by lazy {
// TODO 再加上额外的filter/validate?
overloads
}

/**
* 自动根据带有 [SubCommand] 注解的函数签名生成 [usage]. 也可以被覆盖.
*/
public override val usage: String by lazy {
@OptIn(ExperimentalCommandDescriptors::class)
reflector.generateUsage(overloads)
}

/**
* 智能参数解析环境
*/ // open since 2.12
public override val context: CommandArgumentContext = CommandArgumentContext.Builtins + overrideContext

}


Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public abstract class SimpleCommand(
parentPermission: Permission = owner.parentPermission,
overrideContext: CommandArgumentContext = EmptyCommandArgumentContext,
) : Command, AbstractCommand(owner, primaryName, secondaryNames = secondaryNames, description, parentPermission),
CommandArgumentContextAware {
CommandArgumentContextAware, SubCommandProvider {

private val reflector by lazy { CommandReflector(this, SimpleCommandSubCommandAnnotationResolver) }

Expand All @@ -72,6 +72,12 @@ public abstract class SimpleCommand(
}
}

@ExperimentalCommandDescriptors
public final override val provideOverloads: List<CommandSignatureFromKFunction> by lazy {
// TODO 再加上额外的filter/validate?
overloads
}

/**
* 自动根据带有 [Handler] 注解的函数签名生成 [usage]. 也可以被覆盖.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.mamoe.mirai.console.command

import net.mamoe.mirai.console.command.descriptor.CommandSignatureFromKFunction
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.util.ConsoleExperimentalApi

interface SubCommandProvider {

/**
* 被聚合时提供的子指令
*/
@ConsoleExperimentalApi("Property name is experimental")
@ExperimentalCommandDescriptors
public val provideOverloads: List<@JvmWildcard CommandSignatureFromKFunction>
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,35 @@ internal object CompositeCommandSubCommandAnnotationResolver :
function.findAnnotation<CompositeCommand.Description>()?.value

override fun hasPropertyAnnotation(command: Command, property: KProperty<*>): Boolean =
property.hasAnnotation<CompositeCommand.ChildCommand>()
property.hasAnnotation<AbstractCommand.AsSubCommandProvider>()

}

/*
* - 不看Function上的Annotation
* - 不从Function获取SubCommandNames
* - 看Property上的Annotation
*/
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
internal object GroupedCommandSubCommandAnnotationResolver :
SubCommandAnnotationResolver {
override fun hasAnnotation(ownerCommand: Command, function: KFunction<*>) =
function.hasAnnotation<CompositeCommand.SubCommand>()

override fun getSubCommandNames(ownerCommand: Command, function: KFunction<*>): Array<out String> {
val annotated = function.findAnnotation<CompositeCommand.SubCommand>()!!.value
return if (annotated.isEmpty()) arrayOf(function.name)
else annotated
}

override fun getAnnotatedName(ownerCommand: Command, parameter: KParameter): String? =
parameter.findAnnotation<CompositeCommand.Name>()?.value

override fun getDescription(ownerCommand: Command, function: KFunction<*>): String? =
function.findAnnotation<CompositeCommand.Description>()?.value

override fun hasPropertyAnnotation(command: Command, property: KProperty<*>): Boolean =
property.hasAnnotation<AbstractCommand.AsSubCommandProvider>()

}

Expand Down Expand Up @@ -144,7 +172,7 @@ internal class CommandReflector(
throw IllegalCommandDeclarationException(command, this, message)
}

private fun KProperty<*>.isSubCommandProperty(): Boolean = annotationResolver.hasPropertyAnnotation(command, this)
private fun KProperty<*>.isSubCommandProviderProperty(): Boolean = annotationResolver.hasPropertyAnnotation(command, this)
private fun KFunction<*>.isSubCommandFunction(): Boolean = annotationResolver.hasAnnotation(command, this)
private fun KFunction<*>.checkExtensionReceiver() {
this.extensionReceiverParameter?.let { receiver ->
Expand Down Expand Up @@ -351,12 +379,12 @@ internal class CommandReflector(

val fromMemberProperties = command::class.declaredMemberProperties
.asSequence()
.filter { it.isSubCommandProperty() }
.filter { it.isSubCommandProviderProperty() }
.map { it.getter.call(command) }
.filter { it is CompositeCommand }
.filter { it is SubCommandProvider }
.flatMap { property ->
property as CompositeCommand
property.overloads
property as SubCommandProvider
property.provideOverloads
}.toList()

val list: MutableList<CommandSignatureFromKFunction> = ArrayList()
Expand Down
Loading

0 comments on commit 877793d

Please sign in to comment.