1
0
mirror of https://github.com/mamoe/mirai.git synced 2025-04-24 20:43:33 +08:00

rebase dev with solve

This commit is contained in:
hundun 2022-06-26 10:11:15 +08:00
parent f7649d225d
commit db5d0b327c
3 changed files with 110 additions and 1 deletions
mirai-console/backend/mirai-console

View File

@ -20,6 +20,7 @@ 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
/**
@ -96,6 +97,13 @@ public abstract class CompositeCommand(
private val reflector by lazy { CommandReflector(this, CompositeCommandSubCommandAnnotationResolver) }
@ExperimentalCommandDescriptors
public val overloadImpls: List<@JvmWildcard CommandSignatureFromKFunctionImpl> by lazy {
reflector.findSubCommands().also {
reflector.validate(it)
}
}
@ExperimentalCommandDescriptors
public final override val overloads: List<@JvmWildcard CommandSignatureFromKFunction> by lazy {
reflector.findSubCommands().also {
@ -126,6 +134,14 @@ public abstract class CompositeCommand(
@ResolveContext(COMMAND_NAME) vararg val value: String = [],
)
/**
* 标记一个属性为子指令集合
*/
@Retention(RUNTIME)
@Target(PROPERTY)
protected annotation class ChildCommand(
)
/** 指令描述 */
@Retention(RUNTIME)
@Target(FUNCTION)

View File

@ -81,6 +81,10 @@ internal object CompositeCommandSubCommandAnnotationResolver :
override fun getDescription(ownerCommand: Command, function: KFunction<*>): String? =
function.findAnnotation<CompositeCommand.Description>()?.value
override fun hasPropertyAnnotation(command: Command, property: KProperty<*>): Boolean =
property.hasAnnotation<CompositeCommand.ChildCommand>()
}
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
@ -97,6 +101,8 @@ internal object SimpleCommandSubCommandAnnotationResolver :
override fun getDescription(ownerCommand: Command, function: KFunction<*>): String =
ownerCommand.description
override fun hasPropertyAnnotation(command: Command, kProperty: KProperty<*>): Boolean = false
}
internal interface SubCommandAnnotationResolver {
@ -104,6 +110,7 @@ internal interface SubCommandAnnotationResolver {
fun getSubCommandNames(ownerCommand: Command, function: KFunction<*>): Array<out String>
fun getAnnotatedName(ownerCommand: Command, parameter: KParameter): String?
fun getDescription(ownerCommand: Command, function: KFunction<*>): String?
fun hasPropertyAnnotation(command: Command, kProperty: KProperty<*>): Boolean
}
@ConsoleExperimentalApi
@ -139,6 +146,7 @@ internal class CommandReflector(
throw IllegalCommandDeclarationException(command, this, message)
}
private fun KProperty<*>.isSubCommandProperty(): Boolean = annotationResolver.hasPropertyAnnotation(command, this)
private fun KFunction<*>.isSubCommandFunction(): Boolean = annotationResolver.hasAnnotation(command, this)
private fun KFunction<*>.checkExtensionReceiver() {
this.extensionReceiverParameter?.let { receiver ->
@ -260,7 +268,7 @@ internal class CommandReflector(
@Throws(IllegalCommandDeclarationException::class)
fun findSubCommands(): List<CommandSignatureFromKFunctionImpl> {
return command::class.functions // exclude static later
val fromMemberFunctions = command::class.functions // exclude static later
.asSequence()
.filter { it.isSubCommandFunction() }
.onEach { it.checkExtensionReceiver() }
@ -342,6 +350,19 @@ internal class CommandReflector(
}
}
}.toList()
val fromMemberProperties = command::class.declaredMemberProperties
.asSequence()
.filter { it.isSubCommandProperty() }
.filterIsInstance(CompositeCommand::class.java)
.flatMap { property ->
property.overloadImpls
}.toList()
val list: MutableList<CommandSignatureFromKFunctionImpl> = ArrayList()
list.addAll(fromMemberFunctions)
list.addAll(fromMemberProperties)
return list
}
private fun isAcceptableReceiverType(classifier: KClass<Any>) =

View File

@ -34,6 +34,48 @@ import java.time.temporal.TemporalAccessor
import kotlin.reflect.KClass
import kotlin.test.*
class TestParentCompositeCommand : CompositeCommand(
owner,
"testParentComposite", "tsPC"
) {
class ChildCompositeCommand1 : CompositeCommand(
owner,
"testChildComposite1", "tsCC1"
) {
@SubCommand
fun foo(seconds: Int) {
Testing.ok(seconds)
}
}
class ChildCompositeCommand2 : CompositeCommand(
owner,
"testChildComposite2", "tsCC2"
) {
@SubCommand
fun bar(seconds: Int) {
Testing.ok(seconds)
}
}
@ChildCommand
val child1: ChildCompositeCommand1 = ChildCompositeCommand1();
@ChildCommand
val child2: ChildCompositeCommand2 = ChildCompositeCommand2();
@SubCommand
fun parentFoo(seconds: Int) {
Testing.ok(seconds)
}
@SubCommand
fun parentBar(seconds: Int) {
Testing.ok(seconds)
}
}
class TestCompositeCommand : CompositeCommand(
owner,
"testComposite", "tsC"
@ -163,6 +205,7 @@ internal class InstanceTestCommand : AbstractConsoleInstanceTest() {
private val simpleCommand by lazy { TestSimpleCommand() }
private val rawCommand by lazy { TestRawCommand() }
private val compositeCommand by lazy { TestCompositeCommand() }
private val parentCompositeCommand by lazy { TestParentCompositeCommand() }
@BeforeTest
fun grantPermission() {
@ -499,6 +542,35 @@ internal class InstanceTestCommand : AbstractConsoleInstanceTest() {
}
}
@Test
fun `parent composite command executing`() = runBlocking {
parentCompositeCommand.withRegistration {
assertEquals(1, withTesting {
assertSuccess(
parentCompositeCommand.execute(sender, "parentFoo 1")
)
})
assertEquals(1, withTesting {
assertSuccess(
parentCompositeCommand.execute(sender, "parentBar 1")
)
})
assertEquals(1, withTesting {
assertSuccess(
parentCompositeCommand.execute(sender, "foo 1")
)
})
assertEquals(1, withTesting {
assertSuccess(
parentCompositeCommand.execute(sender, "foo 1")
)
})
assertEquals(2, withTesting {
assertSuccess(parentCompositeCommand.execute(sender, "bar 2"))
})
}
}
@Test
fun `test first param command sender`() = runTest {
object : CompositeCommand(owner, "cmd") {