mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-11 02:50:15 +08:00
Merge remote-tracking branch 'origin/reborn' into reborn
# Conflicts: # backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/internal/PluginsLoader.kt
This commit is contained in:
commit
26ebd03300
@ -1,8 +1,6 @@
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("kotlin")
|
kotlin("jvm") version "1.4-M2"
|
||||||
kotlin("plugin.serialization")
|
kotlin("plugin.serialization") version "1.4-M2"
|
||||||
id("java")
|
id("java")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10,8 +8,10 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
all {
|
all {
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
|
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||||
languageSettings.progressiveMode = true
|
languageSettings.progressiveMode = true
|
||||||
|
languageSettings.languageVersion = "1.4"
|
||||||
|
languageSettings.apiVersion = "1.4"
|
||||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference")
|
languageSettings.useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference")
|
||||||
@ -21,21 +21,5 @@ kotlin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(kotlin("stdlib"))
|
api(kotlin("stdlib-jdk8"))
|
||||||
}
|
|
||||||
|
|
||||||
val compileKotlin: KotlinCompile by tasks
|
|
||||||
compileKotlin.kotlinOptions {
|
|
||||||
jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
val compileTestKotlin: KotlinCompile by tasks
|
|
||||||
compileTestKotlin.kotlinOptions {
|
|
||||||
jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
tasks.withType(JavaCompile::class.java) {
|
|
||||||
options.encoding = "UTF8"
|
|
||||||
}
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("FunctionName", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.codegen
|
||||||
|
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
|
|
||||||
|
abstract class Replacer(private val name: String) : (String) -> String {
|
||||||
|
override fun toString(): String {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Codegen.Replacer(block: (String) -> String): Replacer {
|
||||||
|
return object : Replacer(this@Replacer::class.simpleName ?: "<unnamed>") {
|
||||||
|
override fun invoke(p1: String): String = block(p1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CodegenScope : MutableList<Replacer> by mutableListOf() {
|
||||||
|
fun applyTo(fileContent: String): String {
|
||||||
|
return this.fold(fileContent) { acc, replacer -> replacer(acc) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@CodegenDsl
|
||||||
|
operator fun Codegen.invoke(vararg ktTypes: KtType) {
|
||||||
|
if (ktTypes.isEmpty() && this is DefaultInvoke) {
|
||||||
|
invoke(defaultInvokeArgs)
|
||||||
|
}
|
||||||
|
invoke(ktTypes.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
@CodegenDsl
|
||||||
|
operator fun Codegen.invoke(ktTypes: Collection<KtType>) {
|
||||||
|
add(Replacer {
|
||||||
|
it + buildString {
|
||||||
|
ktTypes.forEach { applyTo(this, it) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@RegionCodegenDsl
|
||||||
|
operator fun RegionCodegen.invoke(vararg ktTypes: KtType) = invoke(ktTypes.toList())
|
||||||
|
|
||||||
|
@RegionCodegenDsl
|
||||||
|
operator fun RegionCodegen.invoke(ktTypes: Collection<KtType>) {
|
||||||
|
add(Replacer {
|
||||||
|
it.replace(Regex("""//// region $regionName CODEGEN ////([\s\S]*?)//// endregion $regionName CODEGEN ////""")) {
|
||||||
|
val code = CodegenScope().apply { (this@invoke as Codegen).invoke(*ktTypes.toTypedArray()) }.applyTo("")
|
||||||
|
"""
|
||||||
|
|//// region $regionName CODEGEN ////
|
||||||
|
|
|
||||||
|
|$code
|
||||||
|
|
|
||||||
|
|//// endregion $regionName CODEGEN ////
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@DslMarker
|
||||||
|
annotation class CodegenDsl
|
||||||
|
}
|
||||||
|
|
||||||
|
@DslMarker
|
||||||
|
annotation class RegionCodegenDsl
|
||||||
|
|
||||||
|
interface DefaultInvoke {
|
||||||
|
val defaultInvokeArgs: List<KtType>
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Codegen {
|
||||||
|
fun applyTo(stringBuilder: StringBuilder, ktType: KtType) = this.run { stringBuilder.apply(ktType) }
|
||||||
|
|
||||||
|
protected abstract fun StringBuilder.apply(ktType: KtType)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class RegionCodegen(regionName: String? = null) : Codegen() {
|
||||||
|
val regionName: String by lazy {
|
||||||
|
regionName ?: this::class.simpleName!!.substringBefore("Codegen")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class PrimitiveCodegen : Codegen() {
|
||||||
|
protected abstract fun StringBuilder.apply(ktType: KtPrimitive)
|
||||||
|
|
||||||
|
fun StringBuilder.apply(ktType: List<KtPrimitive>) = ktType.forEach { apply(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun StringBuilder.appendKCode(@Language("kt") ktCode: String): StringBuilder = append(kCode(ktCode)).appendLine()
|
@ -46,35 +46,37 @@ fun JClazz.getTemplate():String = """
|
|||||||
|
|
||||||
fun main(){
|
fun main(){
|
||||||
println(buildString {
|
println(buildString {
|
||||||
appendln(COPYRIGHT)
|
appendLine(COPYRIGHT)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(FILE_SUPPRESS)
|
appendLine(FILE_SUPPRESS)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln("/**\n" +
|
appendLine(
|
||||||
|
"/**\n" +
|
||||||
" * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JSettingCodegen.kt\n" +
|
" * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JSettingCodegen.kt\n" +
|
||||||
" * !!! DO NOT MODIFY THIS FILE MANUALLY\n" +
|
" * !!! DO NOT MODIFY THIS FILE MANUALLY\n" +
|
||||||
" */\n" +
|
" */\n" +
|
||||||
"\"\"\"")
|
"\"\"\""
|
||||||
appendln()
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
|
appendLine()
|
||||||
|
|
||||||
|
|
||||||
//do simplest
|
//do simplest
|
||||||
(J_EXTRA + J_NUMBERS).forEach {
|
(J_EXTRA + J_NUMBERS).forEach {
|
||||||
appendln(it.getTemplate())
|
appendLine(it.getTemplate())
|
||||||
}
|
}
|
||||||
|
|
||||||
(J_EXTRA + J_NUMBERS).forEach {
|
(J_EXTRA + J_NUMBERS).forEach {
|
||||||
appendln(JListClazz(it).getTemplate())
|
appendLine(JListClazz(it).getTemplate())
|
||||||
}
|
}
|
||||||
|
|
||||||
(J_EXTRA + J_NUMBERS).forEach {
|
(J_EXTRA + J_NUMBERS).forEach {
|
||||||
appendln(JArrayClazz(it).getTemplate())
|
appendLine(JArrayClazz(it).getTemplate())
|
||||||
}
|
}
|
||||||
|
|
||||||
(J_EXTRA + J_NUMBERS).forEach {key ->
|
(J_EXTRA + J_NUMBERS).forEach {key ->
|
||||||
(J_EXTRA + J_NUMBERS).forEach { value ->
|
(J_EXTRA + J_NUMBERS).forEach { value ->
|
||||||
appendln(JMapClazz(key, value).getTemplate())
|
appendLine(JMapClazz(key, value).getTemplate())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -19,19 +19,19 @@ fun main() {
|
|||||||
File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Setting.kt").apply {
|
File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Setting.kt").apply {
|
||||||
createNewFile()
|
createNewFile()
|
||||||
}.writeText(buildString {
|
}.writeText(buildString {
|
||||||
appendln(COPYRIGHT)
|
appendLine(COPYRIGHT)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(FILE_SUPPRESS)
|
appendLine(FILE_SUPPRESS)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(PACKAGE)
|
appendLine(PACKAGE)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(IMPORTS)
|
appendLine(IMPORTS)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(DO_NOT_MODIFY)
|
appendLine(DO_NOT_MODIFY)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(genAllValueUseSite())
|
appendLine(genAllValueUseSite())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ import kotlin.internal.LowPriorityInOverloadResolution
|
|||||||
|
|
||||||
fun genAllValueUseSite(): String = buildString {
|
fun genAllValueUseSite(): String = buildString {
|
||||||
fun appendln(@Language("kt") code: String) {
|
fun appendln(@Language("kt") code: String) {
|
||||||
this.appendln(code.trimIndent())
|
this.appendLine(code.trimIndent())
|
||||||
}
|
}
|
||||||
// PRIMITIVE
|
// PRIMITIVE
|
||||||
for (number in NUMBERS + OTHER_PRIMITIVES) {
|
for (number in NUMBERS + OTHER_PRIMITIVES) {
|
||||||
@ -83,7 +83,7 @@ fun genAllValueUseSite(): String = buildString {
|
|||||||
// MUTABLE LIST / MUTABLE SET
|
// MUTABLE LIST / MUTABLE SET
|
||||||
for (collectionName in listOf("List", "Set")) {
|
for (collectionName in listOf("List", "Set")) {
|
||||||
for (number in NUMBERS + OTHER_PRIMITIVES) {
|
for (number in NUMBERS + OTHER_PRIMITIVES) {
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(
|
appendln(
|
||||||
"""
|
"""
|
||||||
@JvmName("valueMutable")
|
@JvmName("valueMutable")
|
||||||
@ -94,7 +94,7 @@ fun genAllValueUseSite(): String = buildString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SPECIAL
|
// SPECIAL
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(
|
appendln(
|
||||||
"""
|
"""
|
||||||
fun <T : Setting> Setting.value(default: T): Value<T> {
|
fun <T : Setting> Setting.value(default: T): Value<T> {
|
||||||
|
@ -19,17 +19,17 @@ fun main() {
|
|||||||
File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt").apply {
|
File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt").apply {
|
||||||
createNewFile()
|
createNewFile()
|
||||||
}.writeText(buildString {
|
}.writeText(buildString {
|
||||||
appendln(COPYRIGHT)
|
appendLine(COPYRIGHT)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(PACKAGE)
|
appendLine(PACKAGE)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(IMPORTS)
|
appendLine(IMPORTS)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(DO_NOT_MODIFY)
|
appendLine(DO_NOT_MODIFY)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(genAllValueImpl())
|
appendLine(genAllValueImpl())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,19 +52,19 @@ import net.mamoe.mirai.console.setting.*
|
|||||||
|
|
||||||
fun genAllValueImpl(): String = buildString {
|
fun genAllValueImpl(): String = buildString {
|
||||||
fun appendln(@Language("kt") code: String) {
|
fun appendln(@Language("kt") code: String) {
|
||||||
this.appendln(code.trimIndent())
|
this.appendLine(code.trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRIMITIVE
|
// PRIMITIVE
|
||||||
for (number in NUMBERS + OTHER_PRIMITIVES) {
|
for (number in NUMBERS + OTHER_PRIMITIVES) {
|
||||||
appendln(genPrimitiveValueImpl(number, number, "$number.serializer()", false))
|
appendln(genPrimitiveValueImpl(number, number, "$number.serializer()", false))
|
||||||
appendln()
|
appendLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRIMITIVE ARRAYS
|
// PRIMITIVE ARRAYS
|
||||||
for (number in NUMBERS + OTHER_PRIMITIVES.filterNot { it == "String" }) {
|
for (number in NUMBERS + OTHER_PRIMITIVES.filterNot { it == "String" }) {
|
||||||
appendln(genPrimitiveValueImpl("${number}Array", "${number}Array", "${number}ArraySerializer()", true))
|
appendln(genPrimitiveValueImpl("${number}Array", "${number}Array", "${number}ArraySerializer()", true))
|
||||||
appendln()
|
appendLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TYPED ARRAYS
|
// TYPED ARRAYS
|
||||||
@ -77,7 +77,7 @@ fun genAllValueImpl(): String = buildString {
|
|||||||
true
|
true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRIMITIVE LISTS / SETS
|
// PRIMITIVE LISTS / SETS
|
||||||
@ -92,11 +92,11 @@ fun genAllValueImpl(): String = buildString {
|
|||||||
false
|
false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
// MUTABLE LIST / MUTABLE SET
|
// MUTABLE LIST / MUTABLE SET
|
||||||
|
|
||||||
@ -141,11 +141,11 @@ fun genAllValueImpl(): String = buildString {
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
|
|
||||||
appendln(
|
appendln(
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.codegen
|
||||||
|
|
||||||
|
|
||||||
|
object ValueKtCodegen {
|
||||||
|
object SettingCodegen {
|
||||||
|
object PrimitiveValuesCodegen : RegionCodegen(), DefaultInvoke {
|
||||||
|
override val defaultInvokeArgs: List<KtType>
|
||||||
|
get() = KtType.Primitives + KtString
|
||||||
|
|
||||||
|
override fun StringBuilder.apply(ktType: KtType) {
|
||||||
|
@Suppress("ClassName")
|
||||||
|
appendKCode(
|
||||||
|
"""
|
||||||
|
/**
|
||||||
|
* Represents a non-null [$ktType] value.
|
||||||
|
*/
|
||||||
|
interface ${ktType}Value : PrimitiveValue<$ktType>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
codegen("Value.kt") {
|
||||||
|
SettingCodegen.PrimitiveValuesCodegen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -56,11 +56,11 @@ internal val OTHER_PRIMITIVES = listOf(
|
|||||||
|
|
||||||
fun genPublicApi() = buildString {
|
fun genPublicApi() = buildString {
|
||||||
fun appendln(@Language("kt") code: String) {
|
fun appendln(@Language("kt") code: String) {
|
||||||
this.appendln(code.trimIndent())
|
this.appendLine(code.trimIndent())
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln(COPYRIGHT.trim())
|
appendln(COPYRIGHT.trim())
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(
|
appendln(
|
||||||
"""
|
"""
|
||||||
package net.mamoe.mirai.console.setting
|
package net.mamoe.mirai.console.setting
|
||||||
@ -70,7 +70,7 @@ fun genPublicApi() = buildString {
|
|||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
appendln(
|
appendln(
|
||||||
"""
|
"""
|
||||||
/**
|
/**
|
||||||
@ -80,7 +80,7 @@ fun genPublicApi() = buildString {
|
|||||||
*/
|
*/
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
appendln(
|
appendln(
|
||||||
"""
|
"""
|
||||||
@ -107,7 +107,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
// PRIMITIVES
|
// PRIMITIVES
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
appendln(template)
|
appendln(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
for (number in OTHER_PRIMITIVES) {
|
for (number in OTHER_PRIMITIVES) {
|
||||||
val template = """
|
val template = """
|
||||||
@ -137,7 +137,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
appendln(template)
|
appendln(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
// ARRAYS
|
// ARRAYS
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
sealed class PrimitiveArrayValue<T : Any> : ArrayValue<T>()
|
sealed class PrimitiveArrayValue<T : Any> : ArrayValue<T>()
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
for (number in (NUMBERS + OTHER_PRIMITIVES).filterNot { it == "String" }) {
|
for (number in (NUMBERS + OTHER_PRIMITIVES).filterNot { it == "String" }) {
|
||||||
appendln(
|
appendln(
|
||||||
@ -164,10 +164,10 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
// TYPED ARRAYS
|
// TYPED ARRAYS
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
for (number in (NUMBERS + OTHER_PRIMITIVES)) {
|
for (number in (NUMBERS + OTHER_PRIMITIVES)) {
|
||||||
appendln(
|
appendln(
|
||||||
@ -188,7 +188,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
// TYPED LISTS / SETS
|
// TYPED LISTS / SETS
|
||||||
for (collectionName in listOf("List", "Set")) {
|
for (collectionName in listOf("List", "Set")) {
|
||||||
@ -207,14 +207,14 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
appendln(template)
|
appendln(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
// SETTING
|
// SETTING
|
||||||
appendln(
|
appendln(
|
||||||
"""
|
"""
|
||||||
abstract class Setting${collectionName}Value<T: Setting> internal constructor() : Value<${collectionName}<T>>(), ${collectionName}<T>
|
abstract class Setting${collectionName}Value<T: Setting> internal constructor() : Value<${collectionName}<T>>(), ${collectionName}<T>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SETTING VALUE
|
// SETTING VALUE
|
||||||
@ -225,7 +225,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
// MUTABLE LIST / MUTABLE SET
|
// MUTABLE LIST / MUTABLE SET
|
||||||
for (collectionName in listOf("List", "Set")) {
|
for (collectionName in listOf("List", "Set")) {
|
||||||
@ -235,7 +235,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
|
|
||||||
for (number in (NUMBERS + OTHER_PRIMITIVES)) {
|
for (number in (NUMBERS + OTHER_PRIMITIVES)) {
|
||||||
appendln(
|
appendln(
|
||||||
@ -245,17 +245,17 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
// SETTING
|
// SETTING
|
||||||
appendln(
|
appendln(
|
||||||
"""
|
"""
|
||||||
abstract class MutableSetting${collectionName}Value<T: Setting> internal constructor() : Value<Mutable${collectionName}<T>>(), Mutable${collectionName}<T>
|
abstract class MutableSetting${collectionName}Value<T: Setting> internal constructor() : Value<Mutable${collectionName}<T>>(), Mutable${collectionName}<T>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
appendln()
|
appendLine()
|
||||||
}
|
}
|
||||||
|
|
||||||
appendln()
|
appendLine()
|
||||||
// DYNAMIC
|
// DYNAMIC
|
||||||
|
|
||||||
appendln(
|
appendln(
|
||||||
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("NOTHING_TO_INLINE", "MemberVisibilityCanBePrivate", "unused")
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.codegen
|
||||||
|
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
|
typealias KtByte = KtType.KtPrimitive.KtByte
|
||||||
|
typealias KtShort = KtType.KtPrimitive.KtShort
|
||||||
|
typealias KtInt = KtType.KtPrimitive.KtInt
|
||||||
|
typealias KtLong = KtType.KtPrimitive.KtLong
|
||||||
|
typealias KtFloat = KtType.KtPrimitive.KtFloat
|
||||||
|
typealias KtDouble = KtType.KtPrimitive.KtDouble
|
||||||
|
typealias KtChar = KtType.KtPrimitive.KtChar
|
||||||
|
typealias KtBoolean = KtType.KtPrimitive.KtBoolean
|
||||||
|
|
||||||
|
typealias KtString = KtType.KtString
|
||||||
|
|
||||||
|
typealias KtCollection = KtType.KtCollection
|
||||||
|
typealias KtMap = KtType.KtMap
|
||||||
|
|
||||||
|
typealias KtPrimitive = KtType.KtPrimitive
|
||||||
|
|
||||||
|
|
||||||
|
sealed class KtType {
|
||||||
|
/**
|
||||||
|
* Its classname in standard library
|
||||||
|
*/
|
||||||
|
abstract val standardName: String
|
||||||
|
override fun toString(): String = standardName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not Including [String]
|
||||||
|
*/
|
||||||
|
sealed class KtPrimitive(
|
||||||
|
override val standardName: String,
|
||||||
|
val jPrimitiveName: String = standardName.toLowerCase(),
|
||||||
|
val jObjectName: String = standardName
|
||||||
|
) : KtType() {
|
||||||
|
object KtByte : KtPrimitive("Byte")
|
||||||
|
object KtShort : KtPrimitive("Short")
|
||||||
|
object KtInt : KtPrimitive("Int", jObjectName = "Integer")
|
||||||
|
object KtLong : KtPrimitive("Long")
|
||||||
|
|
||||||
|
object KtFloat : KtPrimitive("Float")
|
||||||
|
object KtDouble : KtPrimitive("Double")
|
||||||
|
|
||||||
|
object KtChar : KtPrimitive("Char", jObjectName = "Character")
|
||||||
|
object KtBoolean : KtPrimitive("Boolean")
|
||||||
|
}
|
||||||
|
|
||||||
|
object KtString : KtType() {
|
||||||
|
override val standardName: String get() = "String"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [List], [Set]
|
||||||
|
*/
|
||||||
|
data class KtCollection(override val standardName: String) : KtType()
|
||||||
|
|
||||||
|
object KtMap : KtType() {
|
||||||
|
override val standardName: String get() = "Map"
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val PrimitiveIntegers = listOf(KtByte, KtShort, KtInt, KtLong)
|
||||||
|
val PrimitiveFloatings = listOf(KtFloat, KtDouble)
|
||||||
|
|
||||||
|
val PrimitiveNumbers = PrimitiveIntegers + PrimitiveFloatings
|
||||||
|
val PrimitiveNonNumbers = listOf(KtChar, KtBoolean)
|
||||||
|
|
||||||
|
val Primitives = PrimitiveNumbers + PrimitiveNonNumbers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun KtType.plus(type: KtType): List<KtType> {
|
||||||
|
return listOf(this, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
val KtType.lowerCaseName: String get() = this.standardName.toLowerCase()
|
||||||
|
|
||||||
|
inline fun kCode(@Language("kt") source: String) = source.trimIndent()
|
||||||
|
|
||||||
|
fun codegen(targetFile: String, block: CodegenScope.() -> Unit) {
|
||||||
|
//// region PrimitiveValue CODEGEN ////
|
||||||
|
//// region PrimitiveValue CODEGEN ////
|
||||||
|
|
||||||
|
targetFile.findFileSmart().also {
|
||||||
|
println("Codegen target: ${it.absolutePath}")
|
||||||
|
}.apply {
|
||||||
|
writeText(
|
||||||
|
CodegenScope().apply(block).also { list ->
|
||||||
|
list.forEach {
|
||||||
|
println("Applying replacement: $it")
|
||||||
|
}
|
||||||
|
}.applyTo(readText())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.findFileSmart(): File = kotlin.run {
|
||||||
|
if (contains("/")) { // absolute
|
||||||
|
File(this)
|
||||||
|
} else {
|
||||||
|
val list = File(".").walk().filter { it.name == this }.toList()
|
||||||
|
if (list.isNotEmpty()) return list.single()
|
||||||
|
|
||||||
|
File(".").walk().filter { it.name.contains(this) }.single()
|
||||||
|
}
|
||||||
|
}.also {
|
||||||
|
require(it.exists()) { "file doesn't exist" }
|
||||||
|
}
|
@ -1,17 +1,17 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import upload.Bintray
|
import upload.Bintray
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("kotlin")
|
kotlin("jvm") version Versions.kotlin
|
||||||
kotlin("plugin.serialization")
|
kotlin("plugin.serialization") version Versions.kotlin
|
||||||
id("java")
|
id("java")
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
id("com.jfrog.bintray")
|
id("com.jfrog.bintray") version Versions.bintray
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(plugin = "com.github.johnrengelman.shadow")
|
version = Versions.console
|
||||||
|
|
||||||
version = Versions.Mirai.console
|
|
||||||
description = "Console backend for mirai"
|
description = "Console backend for mirai"
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@ -56,14 +56,14 @@ kotlin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileAndRuntime("net.mamoe:mirai-core:${Versions.Mirai.core}")
|
compileAndRuntime("net.mamoe:mirai-core:${Versions.core}")
|
||||||
compileAndRuntime(kotlin("stdlib"))
|
compileAndRuntime(kotlin("stdlib"))
|
||||||
|
|
||||||
api("net.mamoe.yamlkt:yamlkt:0.3.1")
|
api("net.mamoe.yamlkt:yamlkt:0.3.1")
|
||||||
api("org.jetbrains:annotations:19.0.0")
|
api("org.jetbrains:annotations:19.0.0")
|
||||||
api(kotlinx("coroutines-jdk8", Versions.Kotlin.coroutines))
|
api(kotlinx("coroutines-jdk8", Versions.coroutines))
|
||||||
|
|
||||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||||
testApi(kotlin("stdlib-jdk8"))
|
testApi(kotlin("stdlib-jdk8"))
|
||||||
testApi(kotlin("test"))
|
testApi(kotlin("test"))
|
||||||
testApi(kotlin("test-junit5"))
|
testApi(kotlin("test-junit5"))
|
||||||
@ -76,6 +76,33 @@ tasks {
|
|||||||
"test"(Test::class) {
|
"test"(Test::class) {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val compileKotlin by getting {}
|
||||||
|
|
||||||
|
val fillBuildConstants by registering {
|
||||||
|
doLast {
|
||||||
|
(compileKotlin as KotlinCompile).source.filter { it.name == "MiraiConsole.kt" }.single().let { file ->
|
||||||
|
file.writeText(file.readText()
|
||||||
|
.replace(Regex("""val buildDate: Date = Date\((.*)\) //(.*)""")) {
|
||||||
|
"""
|
||||||
|
val buildDate: Date = Date(${System.currentTimeMillis()}L) // ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").apply {
|
||||||
|
timeZone = TimeZone.getTimeZone("GMT+8")
|
||||||
|
}.format(Date())}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
.replace(Regex("""const val version: String = "(.*)"""")) {
|
||||||
|
"""
|
||||||
|
const val version: String = "${Versions.console}"
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"compileKotlin" {
|
||||||
|
dependsOn(fillBuildConstants)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// region PUBLISHING
|
// region PUBLISHING
|
||||||
|
@ -105,10 +105,10 @@ public final class JCommandManager {
|
|||||||
* 解析并执行一个指令
|
* 解析并执行一个指令
|
||||||
*
|
*
|
||||||
* @param args 接受 {@link String} 或 {@link Message} , 其他对象将会被 {@link Object#toString()}
|
* @param args 接受 {@link String} 或 {@link Message} , 其他对象将会被 {@link Object#toString()}
|
||||||
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
* @see CommandExecuteResult
|
||||||
* @see #executeCommandAsync(CoroutineScope, CommandSender, Object...)
|
* @see #executeCommandAsync(CoroutineScope, CommandSender, Object...)
|
||||||
*/
|
*/
|
||||||
public static boolean executeCommand(final @NotNull CommandSender sender, final @NotNull Object... args) throws InterruptedException {
|
public static CommandExecuteResult executeCommand(final @NotNull CommandSender sender, final @NotNull Object... args) throws InterruptedException {
|
||||||
Objects.requireNonNull(sender, "sender");
|
Objects.requireNonNull(sender, "sender");
|
||||||
Objects.requireNonNull(args, "args");
|
Objects.requireNonNull(args, "args");
|
||||||
for (Object arg : args) {
|
for (Object arg : args) {
|
||||||
@ -123,10 +123,10 @@ public final class JCommandManager {
|
|||||||
*
|
*
|
||||||
* @param scope 协程作用域 (用于管理协程生命周期). 一般填入 {@link JavaPlugin} 实例.
|
* @param scope 协程作用域 (用于管理协程生命周期). 一般填入 {@link JavaPlugin} 实例.
|
||||||
* @param args 接受 {@link String} 或 {@link Message} , 其他对象将会被 {@link Object#toString()}
|
* @param args 接受 {@link String} 或 {@link Message} , 其他对象将会被 {@link Object#toString()}
|
||||||
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
* @see CommandExecuteResult
|
||||||
* @see #executeCommand(CommandSender, Object...)
|
* @see #executeCommand(CommandSender, Object...)
|
||||||
*/
|
*/
|
||||||
public static CompletableFuture<Boolean> executeCommandAsync(final @NotNull CoroutineScope scope, final @NotNull CommandSender sender, final @NotNull Object... args) {
|
public static CompletableFuture<CommandExecuteResult> executeCommandAsync(final @NotNull CoroutineScope scope, final @NotNull CommandSender sender, final @NotNull Object... args) {
|
||||||
Objects.requireNonNull(sender, "sender");
|
Objects.requireNonNull(sender, "sender");
|
||||||
Objects.requireNonNull(args, "args");
|
Objects.requireNonNull(args, "args");
|
||||||
Objects.requireNonNull(scope, "scope");
|
Objects.requireNonNull(scope, "scope");
|
||||||
|
@ -13,41 +13,58 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.io.charsets.Charset
|
import kotlinx.io.charsets.Charset
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
|
import net.mamoe.mirai.console.center.CuiPluginCenter
|
||||||
|
import net.mamoe.mirai.console.center.PluginCenter
|
||||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||||
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
|
||||||
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
|
|
||||||
import net.mamoe.mirai.utils.DefaultLogger
|
import net.mamoe.mirai.utils.DefaultLogger
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
|
import java.util.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
internal object MiraiConsoleInitializer {
|
||||||
|
internal lateinit var instance: IMiraiConsole
|
||||||
|
|
||||||
|
/** 由前端调用 */
|
||||||
|
internal fun init(instance: IMiraiConsole) {
|
||||||
|
this.instance = instance
|
||||||
|
MiraiConsole.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
|
||||||
|
@JvmStatic
|
||||||
|
val buildDate: Date = Date(1592799753404L) // 2020-06-22 12:22:33
|
||||||
|
const val version: String = "0.5.1"
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mirai 控制台实例.
|
* mirai 控制台实例.
|
||||||
*/
|
*/
|
||||||
object MiraiConsole : CoroutineScope, IMiraiConsole {
|
object MiraiConsole : CoroutineScope, IMiraiConsole {
|
||||||
private lateinit var instance: IMiraiConsole
|
val pluginCenter: PluginCenter get() = CuiPluginCenter
|
||||||
|
|
||||||
/** 由前端调用 */
|
private val instance: IMiraiConsole
|
||||||
internal fun init(instance: IMiraiConsole) {
|
get() = MiraiConsoleInitializer.instance
|
||||||
this.instance = instance
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `mirai-console` build 号
|
* `mirai-console` build 号
|
||||||
|
*
|
||||||
|
* UTC+8 时间
|
||||||
*/
|
*/
|
||||||
@MiraiExperimentalAPI
|
@JvmStatic
|
||||||
override val build: String
|
val buildDate: Date
|
||||||
get() = instance.build
|
get() = MiraiConsoleBuildConstants.buildDate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `mirai-console` 版本
|
* `mirai-console` 版本
|
||||||
*/
|
*/
|
||||||
@MiraiExperimentalAPI
|
const val version: String = MiraiConsoleBuildConstants.version
|
||||||
override val version: String
|
|
||||||
get() = instance.version
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Console 运行路径
|
* Console 运行路径
|
||||||
@ -79,14 +96,15 @@ object MiraiConsole : CoroutineScope, IMiraiConsole {
|
|||||||
|
|
||||||
@MiraiExperimentalAPI
|
@MiraiExperimentalAPI
|
||||||
fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity)
|
fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity)
|
||||||
|
|
||||||
|
internal fun initialize() {
|
||||||
|
// Only for initialize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 前端使用
|
// 前端使用
|
||||||
internal interface IMiraiConsole : CoroutineScope {
|
internal interface IMiraiConsole : CoroutineScope {
|
||||||
val build: String
|
|
||||||
val version: String
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Console 运行路径
|
* Console 运行路径
|
||||||
*/
|
*/
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
package net.mamoe.mirai.console
|
package net.mamoe.mirai.console
|
||||||
|
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.console.center.CuiPluginCenter
|
|
||||||
import net.mamoe.mirai.console.center.PluginCenter
|
|
||||||
import net.mamoe.mirai.utils.LoginSolver
|
import net.mamoe.mirai.utils.LoginSolver
|
||||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
@ -22,11 +20,6 @@ import net.mamoe.mirai.utils.MiraiLogger
|
|||||||
*/
|
*/
|
||||||
@MiraiInternalAPI
|
@MiraiInternalAPI
|
||||||
interface MiraiConsoleFrontEnd {
|
interface MiraiConsoleFrontEnd {
|
||||||
/**
|
|
||||||
* 提供 [PluginCenter]
|
|
||||||
*/
|
|
||||||
val pluginCenter: PluginCenter get() = CuiPluginCenter
|
|
||||||
|
|
||||||
fun loggerFor(identity: String?): MiraiLogger
|
fun loggerFor(identity: String?): MiraiLogger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,12 +36,6 @@ interface MiraiConsoleFrontEnd {
|
|||||||
bot: Bot
|
bot: Bot
|
||||||
)
|
)
|
||||||
|
|
||||||
fun pushVersion(
|
|
||||||
consoleVersion: String,
|
|
||||||
consoleBuild: String,
|
|
||||||
coreVersion: String
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 让 UI 层提供一个输入, 相当于 [readLine]
|
* 让 UI 层提供一个输入, 相当于 [readLine]
|
||||||
*/
|
*/
|
||||||
|
@ -134,12 +134,14 @@ fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock {
|
|||||||
* Java 调用方式: `<static> CommandManager.executeCommand(Command)`
|
* Java 调用方式: `<static> CommandManager.executeCommand(Command)`
|
||||||
*
|
*
|
||||||
* @param messages 接受 [String] 或 [Message], 其他对象将会被 [Any.toString]
|
* @param messages 接受 [String] 或 [Message], 其他对象将会被 [Any.toString]
|
||||||
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
* @see CommandExecuteResult
|
||||||
*
|
*
|
||||||
* @see JCommandManager.executeCommand Java 方法
|
* @see JCommandManager.executeCommand Java 方法
|
||||||
*/
|
*/
|
||||||
suspend fun CommandSender.executeCommand(vararg messages: Any): Boolean {
|
suspend fun CommandSender.executeCommand(vararg messages: Any): CommandExecuteResult {
|
||||||
if (messages.isEmpty()) return false
|
if (messages.isEmpty()) return CommandExecuteResult(
|
||||||
|
status = CommandExecuteStatus.EMPTY_COMMAND
|
||||||
|
)
|
||||||
return executeCommandInternal(
|
return executeCommandInternal(
|
||||||
messages,
|
messages,
|
||||||
messages[0].let { if (it is SingleMessage) it.toString() else it.toString().substringBefore(' ') })
|
messages[0].let { if (it is SingleMessage) it.toString() else it.toString().substringBefore(' ') })
|
||||||
@ -150,12 +152,14 @@ internal inline fun <reified T> List<T>.dropToTypedArray(n: Int): Array<T> = Arr
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析并执行一个指令
|
* 解析并执行一个指令
|
||||||
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
* @see CommandExecuteResult
|
||||||
*
|
*
|
||||||
* @see JCommandManager.executeCommand Java 方法
|
* @see JCommandManager.executeCommand Java 方法
|
||||||
*/
|
*/
|
||||||
suspend fun CommandSender.executeCommand(message: MessageChain): Boolean {
|
suspend fun CommandSender.executeCommand(message: MessageChain): CommandExecuteResult {
|
||||||
if (message.isEmpty()) return false
|
if (message.isEmpty()) return CommandExecuteResult(
|
||||||
|
status = CommandExecuteStatus.EMPTY_COMMAND
|
||||||
|
)
|
||||||
return executeCommandInternal(message, message[0].toString())
|
return executeCommandInternal(message, message[0].toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,9 +167,63 @@ suspend fun CommandSender.executeCommand(message: MessageChain): Boolean {
|
|||||||
internal suspend inline fun CommandSender.executeCommandInternal(
|
internal suspend inline fun CommandSender.executeCommandInternal(
|
||||||
messages: Any,
|
messages: Any,
|
||||||
commandName: String
|
commandName: String
|
||||||
): Boolean {
|
): CommandExecuteResult {
|
||||||
val command = InternalCommandManager.matchCommand(commandName) ?: return false
|
val command = InternalCommandManager.matchCommand(commandName) ?: return CommandExecuteResult(
|
||||||
|
status = CommandExecuteStatus.COMMAND_NOT_FOUND,
|
||||||
|
commandName = commandName
|
||||||
|
)
|
||||||
val rawInput = messages.flattenCommandComponents()
|
val rawInput = messages.flattenCommandComponents()
|
||||||
|
kotlin.runCatching {
|
||||||
command.onCommand(this, rawInput.dropToTypedArray(1))
|
command.onCommand(this, rawInput.dropToTypedArray(1))
|
||||||
return true
|
}.onFailure {
|
||||||
|
return CommandExecuteResult(
|
||||||
|
status = CommandExecuteStatus.FAILED,
|
||||||
|
commandName = commandName,
|
||||||
|
command = command,
|
||||||
|
exception = it
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
return CommandExecuteResult(
|
||||||
|
status = CommandExecuteStatus.SUCCESSFUL,
|
||||||
|
commandName = commandName,
|
||||||
|
command = command
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 命令的执行返回
|
||||||
|
*
|
||||||
|
* @param status 命令最终执行状态
|
||||||
|
* @param exception 命令执行时发生的错误(如果有)
|
||||||
|
* @param command 尝试执行的命令 (status = SUCCESSFUL | FAILED)
|
||||||
|
* @param commandName 尝试执行的命令的名字 (status != EMPTY_COMMAND)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @see CommandExecuteStatus
|
||||||
|
*/
|
||||||
|
class CommandExecuteResult(
|
||||||
|
val status: CommandExecuteStatus,
|
||||||
|
val exception: Throwable? = null,
|
||||||
|
val command: Command? = null,
|
||||||
|
val commandName: String? = null
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* 命令的执行状态
|
||||||
|
*
|
||||||
|
* 当为 [SUCCESSFUL] 的时候,代表命令执行成功
|
||||||
|
*
|
||||||
|
* 当为 [FAILED] 的时候, 代表命令执行出现了错误
|
||||||
|
*
|
||||||
|
* 当为 [COMMAND_NOT_FOUND] 的时候,代表没有匹配的命令
|
||||||
|
*
|
||||||
|
* 当为 [EMPTY_COMMAND] 的时候, 代表尝试执行 ""
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum class CommandExecuteStatus {
|
||||||
|
SUCCESSFUL, FAILED, COMMAND_NOT_FOUND, EMPTY_COMMAND
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("RemoveRedundantQualifierName")
|
||||||
|
typealias CommandExecuteStatus = CommandExecuteResult.CommandExecuteStatus
|
||||||
|
@ -152,7 +152,8 @@ internal class PluginClassLoader(
|
|||||||
}
|
}
|
||||||
pluginsLoader.addClassCache(name, clazz)
|
pluginsLoader.addClassCache(name, clazz)
|
||||||
this.addClassCache(name, clazz)
|
this.addClassCache(name, clazz)
|
||||||
clazz
|
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
|
||||||
|
clazz!! // compiler bug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS")
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.setting
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import net.mamoe.mirai.console.setting.internal.cast
|
||||||
|
import net.mamoe.mirai.console.setting.internal.valueFromKTypeImpl
|
||||||
|
import net.mamoe.mirai.console.setting.internal.valueImpl
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.internal.LowPriorityInOverloadResolution
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.KType
|
||||||
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: 2020/6/21 move to JvmPlugin to inherit SettingStorage and CoroutineScope for saving
|
||||||
|
// Shows public APIs such as deciding when to auto-save.
|
||||||
|
abstract class Setting : SettingImpl() {
|
||||||
|
|
||||||
|
operator fun <T> SerializerAwareValue<T>.provideDelegate(
|
||||||
|
thisRef: Any?,
|
||||||
|
property: KProperty<*>
|
||||||
|
): SerializerAwareValue<T> {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
valueNodes.add(Node(property as KProperty<T>, this, this.serializer))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal implementation for [Setting] including:
|
||||||
|
* - Reflection on Kotlin properties and Java fields
|
||||||
|
* - Auto-saving
|
||||||
|
*/
|
||||||
|
// TODO move to internal package.
|
||||||
|
internal abstract class SettingImpl {
|
||||||
|
internal class Node<T>(
|
||||||
|
val property: KProperty<T>,
|
||||||
|
val value: Value<T>,
|
||||||
|
val updaterSerializer: KSerializer<Unit>
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val valueNodes: MutableList<Node<*>> = Collections.synchronizedList(mutableListOf())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* flatten
|
||||||
|
*/
|
||||||
|
internal fun onValueChanged(value: Value<*>) {
|
||||||
|
// TODO: 2020/6/22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// region Setting.value primitives CODEGEN ////
|
||||||
|
|
||||||
|
// TODO: 2020/6/19 CODEGEN
|
||||||
|
|
||||||
|
fun Setting.value(default: Int): SerializableValue<Int> = valueImpl(default)
|
||||||
|
|
||||||
|
//// endregion Setting.value primitives CODEGEN ////
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [Value] with reified type.
|
||||||
|
*
|
||||||
|
* @param T reified param type T.
|
||||||
|
* Supports only primitives, Kotlin built-in collections,
|
||||||
|
* and classes that are serializable with Kotlinx.serialization
|
||||||
|
* (typically annotated with [kotlinx.serialization.Serializable])
|
||||||
|
*/
|
||||||
|
@LowPriorityInOverloadResolution
|
||||||
|
@OptIn(ExperimentalStdlibApi::class) // stable in 1.4
|
||||||
|
inline fun <reified T> Setting.valueReified(default: T): SerializableValue<T> = valueFromKTypeImpl(typeOf<T>()).cast()
|
||||||
|
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
fun <T> Setting.valueFromKType(type: KType): SerializableValue<T> = valueFromKTypeImpl(type).cast()
|
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "unused", "NOTHING_TO_INLINE")
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.setting
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import net.mamoe.mirai.console.setting.internal.map
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a observable, immutable value wrapping.
|
||||||
|
*
|
||||||
|
* The value can be modified by delegation just like Kotlin's `var`, however it can also be done by the user, e.g. changing using the UI frontend.
|
||||||
|
*
|
||||||
|
* Some frequently used types are specially treated with performance enhancement by codegen.
|
||||||
|
*
|
||||||
|
* @see PrimitiveValue
|
||||||
|
* @see CompositeValue
|
||||||
|
*/
|
||||||
|
interface Value<T> {
|
||||||
|
var value: T
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typically returned by [Setting.value] functions.
|
||||||
|
*/
|
||||||
|
class SerializableValue<T>(
|
||||||
|
delegate: Value<T>,
|
||||||
|
/**
|
||||||
|
* The serializer used to update and dump [delegate]
|
||||||
|
*/
|
||||||
|
override val serializer: KSerializer<Unit>
|
||||||
|
) : Value<T> by delegate, SerializerAwareValue<T>
|
||||||
|
|
||||||
|
fun <T> Value<T>.serializableValueWith(
|
||||||
|
serializer: KSerializer<T>
|
||||||
|
): SerializableValue<T> {
|
||||||
|
return SerializableValue(this, serializer.map(serializer = { this.value }, deserializer = { this.value = it }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see SerializableValue
|
||||||
|
*/
|
||||||
|
interface SerializerAwareValue<T> : Value<T> {
|
||||||
|
val serializer: KSerializer<Unit>
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator fun <T> Value<T>.getValue(mySetting: Any?, property: KProperty<*>): T = value
|
||||||
|
inline operator fun <T> Value<T>.setValue(mySetting: Any?, property: KProperty<*>, value: T) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The serializer for a specific kind of [Value].
|
||||||
|
*/
|
||||||
|
typealias ValueSerializer<T> = KSerializer<Value<T>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a observable *primitive* value wrapping.
|
||||||
|
*
|
||||||
|
* 9 types that are considered *primitive*:
|
||||||
|
* - Integers: [Byte], [Short], [Int], [Long]
|
||||||
|
* - Floating: [Float], [Double]
|
||||||
|
* - [Boolean]
|
||||||
|
* - [Char], [String]
|
||||||
|
*
|
||||||
|
* Note: The values are actually *boxed* because of the generic type T.
|
||||||
|
* *Primitive* indicates only it is one of the 9 types mentioned above.
|
||||||
|
*/
|
||||||
|
interface PrimitiveValue<T> : Value<T>
|
||||||
|
|
||||||
|
|
||||||
|
//// region PrimitiveValues CODEGEN ////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a non-null [Byte] value.
|
||||||
|
*/
|
||||||
|
interface ByteValue : PrimitiveValue<Byte>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a non-null [Short] value.
|
||||||
|
*/
|
||||||
|
interface ShortValue : PrimitiveValue<Short>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a non-null [Int] value.
|
||||||
|
*/
|
||||||
|
interface IntValue : PrimitiveValue<Int>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a non-null [Long] value.
|
||||||
|
*/
|
||||||
|
interface LongValue : PrimitiveValue<Long>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a non-null [Float] value.
|
||||||
|
*/
|
||||||
|
interface FloatValue : PrimitiveValue<Float>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a non-null [Double] value.
|
||||||
|
*/
|
||||||
|
interface DoubleValue : PrimitiveValue<Double>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a non-null [Char] value.
|
||||||
|
*/
|
||||||
|
interface CharValue : PrimitiveValue<Char>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a non-null [Boolean] value.
|
||||||
|
*/
|
||||||
|
interface BooleanValue : PrimitiveValue<Boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a non-null [String] value.
|
||||||
|
*/
|
||||||
|
interface StringValue : PrimitiveValue<String>
|
||||||
|
|
||||||
|
|
||||||
|
//// endregion PrimitiveValues CODEGEN ////
|
||||||
|
|
||||||
|
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
interface CompositeValue<T> : Value<T>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass of [CompositeListValue], [PrimitiveListValue].
|
||||||
|
*/
|
||||||
|
interface ListValue<E> : CompositeValue<List<E>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elements can by anything, wrapped as [Value].
|
||||||
|
* @param E is not primitive types.
|
||||||
|
*/
|
||||||
|
interface CompositeListValue<E> : ListValue<E>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elements can only be primitives, not wrapped.
|
||||||
|
* @param E is not primitive types.
|
||||||
|
*/
|
||||||
|
interface PrimitiveListValue<E> : ListValue<E>
|
||||||
|
|
||||||
|
|
||||||
|
//// region PrimitiveListValue CODEGEN ////
|
||||||
|
|
||||||
|
interface PrimitiveIntListValue : PrimitiveListValue<Int>
|
||||||
|
interface PrimitiveLongListValue : PrimitiveListValue<Long>
|
||||||
|
// TODO + codegen
|
||||||
|
|
||||||
|
//// endregion PrimitiveListValue CODEGEN ////
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass of [CompositeSetValue], [PrimitiveSetValue].
|
||||||
|
*/
|
||||||
|
interface SetValue<E> : CompositeValue<Set<E>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elements can by anything, wrapped as [Value].
|
||||||
|
* @param E is not primitive types.
|
||||||
|
*/
|
||||||
|
interface CompositeSetValue<E> : SetValue<E>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elements can only be primitives, not wrapped.
|
||||||
|
* @param E is not primitive types.
|
||||||
|
*/
|
||||||
|
interface PrimitiveSetValue<E> : SetValue<E>
|
||||||
|
|
||||||
|
|
||||||
|
//// region PrimitiveSetValue CODEGEN ////
|
||||||
|
|
||||||
|
interface PrimitiveIntSetValue : PrimitiveSetValue<Int>
|
||||||
|
interface PrimitiveLongSetValue : PrimitiveSetValue<Long>
|
||||||
|
// TODO + codegen
|
||||||
|
|
||||||
|
//// endregion PrimitiveSetValue CODEGEN ////
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Superclass of [CompositeMapValue], [PrimitiveMapValue].
|
||||||
|
*/
|
||||||
|
interface MapValue<K, V> : CompositeValue<Map<K, V>>
|
||||||
|
|
||||||
|
interface CompositeMapValue<K, V> : MapValue<K, V>
|
||||||
|
|
||||||
|
interface PrimitiveMapValue<K, V> : MapValue<K, V>
|
||||||
|
|
||||||
|
|
||||||
|
//// region PrimitiveMapValue CODEGEN ////
|
||||||
|
|
||||||
|
interface PrimitiveIntIntMapValue : PrimitiveMapValue<Int, Int>
|
||||||
|
interface PrimitiveIntLongMapValue : PrimitiveMapValue<Int, Long>
|
||||||
|
// TODO + codegen
|
||||||
|
|
||||||
|
//// endregion PrimitiveSetValue CODEGEN ////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.setting.internal
|
||||||
|
|
||||||
|
import net.mamoe.mirai.console.setting.*
|
||||||
|
|
||||||
|
|
||||||
|
// type inference bug
|
||||||
|
internal fun <T> Setting.createCompositeSetValueImpl(tToValue: (T) -> Value<T>): CompositeSetValueImpl<T> {
|
||||||
|
return object : CompositeSetValueImpl<T>(tToValue) {
|
||||||
|
override fun onChanged() {
|
||||||
|
this@createCompositeSetValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class CompositeSetValueImpl<T>(
|
||||||
|
tToValue: (T) -> Value<T> // should override onChanged
|
||||||
|
) : CompositeSetValue<T> {
|
||||||
|
private val internalSet: MutableSet<Value<T>> = mutableSetOf()
|
||||||
|
|
||||||
|
private var _value: Set<T> = internalSet.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
||||||
|
|
||||||
|
override var value: Set<T>
|
||||||
|
get() = _value
|
||||||
|
set(v) {
|
||||||
|
if (_value != v) {
|
||||||
|
onChanged()
|
||||||
|
_value = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// type inference bug
|
||||||
|
internal fun <T> Setting.createCompositeListValueImpl(tToValue: (T) -> Value<T>): CompositeListValueImpl<T> {
|
||||||
|
return object : CompositeListValueImpl<T>(tToValue) {
|
||||||
|
override fun onChanged() {
|
||||||
|
this@createCompositeListValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class CompositeListValueImpl<T>(
|
||||||
|
tToValue: (T) -> Value<T> // should override onChanged
|
||||||
|
) : CompositeListValue<T> {
|
||||||
|
private val internalList: MutableList<Value<T>> = mutableListOf()
|
||||||
|
|
||||||
|
private var _value: List<T> = internalList.shadowMap({ it.value }, tToValue).observable { onChanged() }
|
||||||
|
|
||||||
|
override var value: List<T>
|
||||||
|
get() = _value
|
||||||
|
set(v) {
|
||||||
|
if (_value != v) {
|
||||||
|
onChanged()
|
||||||
|
_value = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
// workaround to a type inference bug
|
||||||
|
internal fun <K, V> Setting.createCompositeMapValueImpl(
|
||||||
|
kToValue: (K) -> Value<K>,
|
||||||
|
vToValue: (V) -> Value<V>
|
||||||
|
): CompositeMapValueImpl<K, V> {
|
||||||
|
return object : CompositeMapValueImpl<K, V>(kToValue, vToValue) {
|
||||||
|
override fun onChanged() {
|
||||||
|
this@createCompositeMapValueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class CompositeMapValueImpl<K, V>(
|
||||||
|
kToValue: (K) -> Value<K>, // should override onChanged
|
||||||
|
vToValue: (V) -> Value<V> // should override onChanged
|
||||||
|
) : CompositeMapValue<K, V> {
|
||||||
|
private val internalList: MutableMap<Value<K>, Value<V>> = mutableMapOf()
|
||||||
|
|
||||||
|
private var _value: Map<K, V> =
|
||||||
|
internalList.shadowMap({ it.value }, kToValue, { it.value }, vToValue).observable { onChanged() }
|
||||||
|
override var value: Map<K, V>
|
||||||
|
get() = _value
|
||||||
|
set(v) {
|
||||||
|
if (_value != v) {
|
||||||
|
onChanged()
|
||||||
|
_value = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("NOTHING_TO_INLINE")
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.setting.internal
|
||||||
|
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.builtins.*
|
||||||
|
import net.mamoe.mirai.console.setting.SerializableValue
|
||||||
|
import net.mamoe.mirai.console.setting.Setting
|
||||||
|
import net.mamoe.mirai.console.setting.serializableValueWith
|
||||||
|
import net.mamoe.mirai.console.setting.valueFromKType
|
||||||
|
import net.mamoe.yamlkt.YamlDynamicSerializer
|
||||||
|
import net.mamoe.yamlkt.YamlNullableDynamicSerializer
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.KType
|
||||||
|
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
@Suppress("UnsafeCall", "SMARTCAST_IMPOSSIBLE", "UNCHECKED_CAST")
|
||||||
|
internal fun Setting.valueFromKTypeImpl(type: KType): SerializableValue<*> {
|
||||||
|
val classifier = type.classifier
|
||||||
|
require(classifier is KClass<*>)
|
||||||
|
|
||||||
|
if (classifier.isPrimitiveOrBuiltInSerializableValue()) {
|
||||||
|
TODO("是基础类型, 可以直接创建 ValueImpl. ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复合类型
|
||||||
|
|
||||||
|
when (classifier) {
|
||||||
|
Map::class -> {
|
||||||
|
val keyClass = type.arguments[0].type?.classifier
|
||||||
|
require(keyClass is KClass<*>)
|
||||||
|
|
||||||
|
val valueClass = type.arguments[1].type?.classifier
|
||||||
|
require(valueClass is KClass<*>)
|
||||||
|
|
||||||
|
if (keyClass.isPrimitiveOrBuiltInSerializableValue() && valueClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||||
|
// PrimitiveIntIntMap
|
||||||
|
// ...
|
||||||
|
TODO()
|
||||||
|
} else {
|
||||||
|
return createCompositeMapValueImpl<Any?, Any?>(
|
||||||
|
kToValue = { valueFromKType(type.arguments[0].type!!) },
|
||||||
|
vToValue = { valueFromKType(type.arguments[1].type!!) }
|
||||||
|
).serializableValueWith(serializerMirai(type) as KSerializer<Map<Any?, Any?>>) // erased
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List::class -> {
|
||||||
|
val elementClass = type.arguments[0].type?.classifier
|
||||||
|
require(elementClass is KClass<*>)
|
||||||
|
|
||||||
|
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||||
|
// PrimitiveIntList
|
||||||
|
// ...
|
||||||
|
TODO()
|
||||||
|
} else {
|
||||||
|
return createCompositeListValueImpl<Any?> { valueFromKType(type.arguments[0].type!!) }
|
||||||
|
.serializableValueWith(serializerMirai(type) as KSerializer<List<Any?>>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Set::class -> {
|
||||||
|
val elementClass = type.arguments[0].type?.classifier
|
||||||
|
require(elementClass is KClass<*>)
|
||||||
|
|
||||||
|
if (elementClass.isPrimitiveOrBuiltInSerializableValue()) {
|
||||||
|
// PrimitiveIntSet
|
||||||
|
// ...
|
||||||
|
TODO()
|
||||||
|
} else {
|
||||||
|
return createCompositeSetValueImpl<Any?> { valueFromKType(type.arguments[0].type!!) }
|
||||||
|
.serializableValueWith(serializerMirai(type) as KSerializer<Set<Any?>>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> error("Custom composite value is not supported yet (${classifier.qualifiedName})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean {
|
||||||
|
return false // debug
|
||||||
|
when (this) {
|
||||||
|
Byte::class, Short::class, Int::class, Long::class,
|
||||||
|
Boolean::class,
|
||||||
|
Char::class, String::class,
|
||||||
|
Pair::class, Triple::class
|
||||||
|
-> return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
internal inline fun <R, T> T.cast(): R = this as R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
|
||||||
|
* Copyright 2017-2020 JetBrains s.r.o.
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST", "NO_REFLECTION_IN_CLASS_PATH", "UNSUPPORTED", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||||
|
@OptIn(ImplicitReflectionSerializer::class)
|
||||||
|
internal fun serializerMirai(type: KType): KSerializer<Any?> {
|
||||||
|
fun serializerByKTypeImpl(type: KType): KSerializer<Any> {
|
||||||
|
val rootClass = when (val t = type.classifier) {
|
||||||
|
is KClass<*> -> t
|
||||||
|
else -> error("Only KClass supported as classifier, got $t")
|
||||||
|
} as KClass<Any>
|
||||||
|
|
||||||
|
val typeArguments = type.arguments
|
||||||
|
.map { requireNotNull(it.type) { "Star projections are not allowed, had $it instead" } }
|
||||||
|
return when {
|
||||||
|
typeArguments.isEmpty() -> rootClass.serializer()
|
||||||
|
else -> {
|
||||||
|
val serializers = typeArguments
|
||||||
|
.map(::serializer)
|
||||||
|
// Array is not supported, see KT-32839
|
||||||
|
when (rootClass) {
|
||||||
|
List::class, MutableList::class, ArrayList::class -> ListSerializer(serializers[0])
|
||||||
|
HashSet::class -> SetSerializer(serializers[0])
|
||||||
|
Set::class, MutableSet::class, LinkedHashSet::class -> SetSerializer(serializers[0])
|
||||||
|
HashMap::class -> MapSerializer(serializers[0], serializers[1])
|
||||||
|
Map::class, MutableMap::class, LinkedHashMap::class -> MapSerializer(serializers[0], serializers[1])
|
||||||
|
Map.Entry::class -> MapEntrySerializer(serializers[0], serializers[1])
|
||||||
|
Pair::class -> PairSerializer(serializers[0], serializers[1])
|
||||||
|
Triple::class -> TripleSerializer(serializers[0], serializers[1], serializers[2])
|
||||||
|
/* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer
|
||||||
|
else -> {
|
||||||
|
if (isReferenceArray(type, rootClass)) {
|
||||||
|
return ArraySerializer(typeArguments[0].classifier as KClass<Any>, serializers[0]).cast()
|
||||||
|
}
|
||||||
|
requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) {
|
||||||
|
"Can't find a method to construct serializer for type ${rootClass.simpleName()}. " +
|
||||||
|
"Make sure this class is marked as @Serializable or provide serializer explicitly."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.cast()
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = serializerByKTypeImpl(type)
|
||||||
|
return if (type.isMarkedNullable) result.nullable else result.cast()
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.setting.internal
|
||||||
|
|
||||||
|
import net.mamoe.mirai.console.setting.IntValue
|
||||||
|
|
||||||
|
|
||||||
|
//// region PrimitiveValues CODEGEN ////
|
||||||
|
|
||||||
|
// TODO: 2020/6/21 CODEGEN
|
||||||
|
|
||||||
|
internal abstract class IntValueImpl : IntValue {
|
||||||
|
constructor()
|
||||||
|
constructor(default: Int) {
|
||||||
|
_value = default
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _value: Int? = null
|
||||||
|
|
||||||
|
override var value: Int
|
||||||
|
get() = _value ?: throw IllegalStateException("IntValue should be initialized before get.")
|
||||||
|
set(v) {
|
||||||
|
if (v != this._value) {
|
||||||
|
this._value = v
|
||||||
|
onChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun onChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
//// endregion PrimitiveValues CODEGEN ////
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.setting.internal
|
||||||
|
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
import net.mamoe.mirai.console.setting.SerializableValue
|
||||||
|
import net.mamoe.mirai.console.setting.Setting
|
||||||
|
|
||||||
|
|
||||||
|
//// region Setting.value primitives impl CODEGEN ////
|
||||||
|
|
||||||
|
// TODO: 2020/6/21 CODEGEN
|
||||||
|
|
||||||
|
internal fun Setting.valueImpl(default: Int): SerializableValue<Int> {
|
||||||
|
val instance = object : IntValueImpl(default) {
|
||||||
|
override fun onChanged() = this@valueImpl.onValueChanged(this)
|
||||||
|
}
|
||||||
|
return SerializableValue(instance, Int.serializer().map(
|
||||||
|
serializer = { instance.value },
|
||||||
|
deserializer = { instance.value = it }
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
//// endregion Setting.value primitives impl CODEGEN ////
|
@ -7,6 +7,8 @@
|
|||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("DuplicatedCode")
|
||||||
|
|
||||||
package net.mamoe.mirai.console.setting.internal
|
package net.mamoe.mirai.console.setting.internal
|
||||||
|
|
||||||
import kotlinx.serialization.ImplicitReflectionSerializer
|
import kotlinx.serialization.ImplicitReflectionSerializer
|
||||||
@ -14,7 +16,89 @@ import kotlinx.serialization.serializer
|
|||||||
import net.mamoe.yamlkt.Yaml
|
import net.mamoe.yamlkt.Yaml
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
internal fun <E, R> MutableList<E>.shadowMap(transform: (E) -> R, transformBack: (R) -> E): MutableList<R> {
|
internal inline fun <K, V, KR, VR> MutableMap<K, V>.shadowMap(
|
||||||
|
crossinline kTransform: (K) -> KR,
|
||||||
|
crossinline kTransformBack: (KR) -> K,
|
||||||
|
crossinline vTransform: (V) -> VR,
|
||||||
|
crossinline vTransformBack: (VR) -> V
|
||||||
|
): MutableMap<KR, VR> {
|
||||||
|
return object : MutableMap<KR, VR> {
|
||||||
|
override val size: Int get() = this@shadowMap.size
|
||||||
|
override fun containsKey(key: KR): Boolean = this@shadowMap.containsKey(key.let(kTransformBack))
|
||||||
|
override fun containsValue(value: VR): Boolean = this@shadowMap.containsValue(value.let(vTransformBack))
|
||||||
|
override fun get(key: KR): VR? = this@shadowMap[key.let(kTransformBack)]?.let(vTransform)
|
||||||
|
override fun isEmpty(): Boolean = this@shadowMap.isEmpty()
|
||||||
|
|
||||||
|
override val entries: MutableSet<MutableMap.MutableEntry<KR, VR>>
|
||||||
|
get() = this@shadowMap.entries.shadowMap(
|
||||||
|
transform = { entry: MutableMap.MutableEntry<K, V> ->
|
||||||
|
object : MutableMap.MutableEntry<KR, VR> {
|
||||||
|
override val key: KR get() = entry.key.let(kTransform)
|
||||||
|
override val value: VR get() = entry.value.let(vTransform)
|
||||||
|
override fun setValue(newValue: VR): VR =
|
||||||
|
entry.setValue(newValue.let(vTransformBack)).let(vTransform)
|
||||||
|
}
|
||||||
|
} as ((MutableMap.MutableEntry<K, V>) -> MutableMap.MutableEntry<KR, VR>), // type inference bug
|
||||||
|
transformBack = { entry ->
|
||||||
|
object : MutableMap.MutableEntry<K, V> {
|
||||||
|
override val key: K get() = entry.key.let(kTransformBack)
|
||||||
|
override val value: V get() = entry.value.let(vTransformBack)
|
||||||
|
override fun setValue(newValue: V): V =
|
||||||
|
entry.setValue(newValue.let(vTransform)).let(vTransformBack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
override val keys: MutableSet<KR>
|
||||||
|
get() = this@shadowMap.keys.shadowMap(kTransform, kTransformBack)
|
||||||
|
override val values: MutableCollection<VR>
|
||||||
|
get() = this@shadowMap.values.shadowMap(vTransform, vTransformBack)
|
||||||
|
|
||||||
|
override fun clear() = this@shadowMap.clear()
|
||||||
|
override fun put(key: KR, value: VR): VR? =
|
||||||
|
this@shadowMap.put(key.let(kTransformBack), value.let(vTransformBack))?.let(vTransform)
|
||||||
|
|
||||||
|
override fun putAll(from: Map<out KR, VR>) {
|
||||||
|
from.forEach { (kr, vr) ->
|
||||||
|
this@shadowMap[kr.let(kTransformBack)] = vr.let(vTransformBack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(key: KR): VR? = this@shadowMap.remove(key.let(kTransformBack))?.let(vTransform)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <E, R> MutableCollection<E>.shadowMap(
|
||||||
|
crossinline transform: (E) -> R,
|
||||||
|
crossinline transformBack: (R) -> E
|
||||||
|
): MutableCollection<R> {
|
||||||
|
return object : MutableCollection<R> {
|
||||||
|
override val size: Int get() = this@shadowMap.size
|
||||||
|
|
||||||
|
override fun contains(element: R): Boolean = this@shadowMap.any { it.let(transform) == element }
|
||||||
|
override fun containsAll(elements: Collection<R>): Boolean = elements.all(::contains)
|
||||||
|
override fun isEmpty(): Boolean = this@shadowMap.isEmpty()
|
||||||
|
override fun iterator(): MutableIterator<R> = object : MutableIterator<R> {
|
||||||
|
private val delegate = this@shadowMap.iterator()
|
||||||
|
override fun hasNext(): Boolean = delegate.hasNext()
|
||||||
|
override fun next(): R = delegate.next().let(transform)
|
||||||
|
override fun remove() = delegate.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(element: R): Boolean = this@shadowMap.add(element.let(transformBack))
|
||||||
|
|
||||||
|
override fun addAll(elements: Collection<R>): Boolean = this@shadowMap.addAll(elements.map(transformBack))
|
||||||
|
override fun clear() = this@shadowMap.clear()
|
||||||
|
|
||||||
|
override fun remove(element: R): Boolean = this@shadowMap.removeIf { it.let(transform) == element }
|
||||||
|
override fun removeAll(elements: Collection<R>): Boolean = elements.all(::remove)
|
||||||
|
override fun retainAll(elements: Collection<R>): Boolean = this@shadowMap.retainAll(elements.map(transformBack))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <E, R> MutableList<E>.shadowMap(
|
||||||
|
crossinline transform: (E) -> R,
|
||||||
|
crossinline transformBack: (R) -> E
|
||||||
|
): MutableList<R> {
|
||||||
return object : MutableList<R> {
|
return object : MutableList<R> {
|
||||||
override val size: Int get() = this@shadowMap.size
|
override val size: Int get() = this@shadowMap.size
|
||||||
|
|
||||||
@ -78,7 +162,10 @@ internal fun <E, R> MutableList<E>.shadowMap(transform: (E) -> R, transformBack:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun <E, R> MutableSet<E>.shadowMap(transform: (E) -> R, transformBack: (R) -> E): MutableSet<R> {
|
internal inline fun <E, R> MutableSet<E>.shadowMap(
|
||||||
|
crossinline transform: (E) -> R,
|
||||||
|
crossinline transformBack: (R) -> E
|
||||||
|
): MutableSet<R> {
|
||||||
return object : MutableSet<R> {
|
return object : MutableSet<R> {
|
||||||
override val size: Int get() = this@shadowMap.size
|
override val size: Int get() = this@shadowMap.size
|
||||||
|
|
||||||
@ -102,7 +189,7 @@ internal fun <E, R> MutableSet<E>.shadowMap(transform: (E) -> R, transformBack:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <T> dynamicList(supplier: () -> List<T>): List<T> {
|
internal inline fun <T> dynamicList(crossinline supplier: () -> List<T>): List<T> {
|
||||||
return object : List<T> {
|
return object : List<T> {
|
||||||
override val size: Int get() = supplier().size
|
override val size: Int get() = supplier().size
|
||||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||||
@ -118,7 +205,7 @@ internal fun <T> dynamicList(supplier: () -> List<T>): List<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <T> dynamicSet(supplier: () -> Set<T>): Set<T> {
|
internal inline fun <T> dynamicSet(crossinline supplier: () -> Set<T>): Set<T> {
|
||||||
return object : Set<T> {
|
return object : Set<T> {
|
||||||
override val size: Int get() = supplier().size
|
override val size: Int get() = supplier().size
|
||||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||||
@ -129,7 +216,7 @@ internal fun <T> dynamicSet(supplier: () -> Set<T>): Set<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun <T> dynamicMutableList(supplier: () -> MutableList<T>): MutableList<T> {
|
internal inline fun <T> dynamicMutableList(crossinline supplier: () -> MutableList<T>): MutableList<T> {
|
||||||
return object : MutableList<T> {
|
return object : MutableList<T> {
|
||||||
override val size: Int get() = supplier().size
|
override val size: Int get() = supplier().size
|
||||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||||
@ -156,7 +243,7 @@ internal fun <T> dynamicMutableList(supplier: () -> MutableList<T>): MutableList
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal fun <T> dynamicMutableSet(supplier: () -> MutableSet<T>): MutableSet<T> {
|
internal inline fun <T> dynamicMutableSet(crossinline supplier: () -> MutableSet<T>): MutableSet<T> {
|
||||||
return object : MutableSet<T> {
|
return object : MutableSet<T> {
|
||||||
override val size: Int get() = supplier().size
|
override val size: Int get() = supplier().size
|
||||||
override fun contains(element: T): Boolean = supplier().contains(element)
|
override fun contains(element: T): Boolean = supplier().contains(element)
|
||||||
@ -172,6 +259,23 @@ internal fun <T> dynamicMutableSet(supplier: () -> MutableSet<T>): MutableSet<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST", "USELESS_CAST") // type inference bug
|
||||||
|
internal inline fun <K, V> MutableMap<K, V>.observable(crossinline onChanged: () -> Unit): MutableMap<K, V> {
|
||||||
|
return object : MutableMap<K, V>, Map<K, V> by (this as Map<K, V>) {
|
||||||
|
override val keys: MutableSet<K>
|
||||||
|
get() = this@observable.keys.observable(onChanged)
|
||||||
|
override val values: MutableCollection<V>
|
||||||
|
get() = this@observable.values.observable(onChanged)
|
||||||
|
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||||
|
get() = this@observable.entries.observable(onChanged)
|
||||||
|
|
||||||
|
override fun clear() = this@observable.clear().also { onChanged() }
|
||||||
|
override fun put(key: K, value: V): V? = this@observable.put(key, value).also { onChanged() }
|
||||||
|
override fun putAll(from: Map<out K, V>) = this@observable.putAll(from).also { onChanged() }
|
||||||
|
override fun remove(key: K): V? = this@observable.remove(key).also { onChanged() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> Unit): MutableList<T> {
|
internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> Unit): MutableList<T> {
|
||||||
return object : MutableList<T> {
|
return object : MutableList<T> {
|
||||||
override val size: Int get() = this@observable.size
|
override val size: Int get() = this@observable.size
|
||||||
@ -234,6 +338,31 @@ internal inline fun <T> MutableList<T>.observable(crossinline onChanged: () -> U
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal inline fun <T> MutableCollection<T>.observable(crossinline onChanged: () -> Unit): MutableCollection<T> {
|
||||||
|
return object : MutableCollection<T> {
|
||||||
|
override val size: Int get() = this@observable.size
|
||||||
|
override fun contains(element: T): Boolean = this@observable.contains(element)
|
||||||
|
override fun containsAll(elements: Collection<T>): Boolean = this@observable.containsAll(elements)
|
||||||
|
override fun isEmpty(): Boolean = this@observable.isEmpty()
|
||||||
|
override fun iterator(): MutableIterator<T> = object : MutableIterator<T> {
|
||||||
|
private val delegate = this@observable.iterator()
|
||||||
|
override fun hasNext(): Boolean = delegate.hasNext()
|
||||||
|
override fun next(): T = delegate.next()
|
||||||
|
override fun remove() = delegate.remove().also { onChanged() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(element: T): Boolean = this@observable.add(element).also { onChanged() }
|
||||||
|
override fun addAll(elements: Collection<T>): Boolean = this@observable.addAll(elements).also { onChanged() }
|
||||||
|
override fun clear() = this@observable.clear().also { onChanged() }
|
||||||
|
override fun remove(element: T): Boolean = this@observable.remove(element).also { onChanged() }
|
||||||
|
override fun removeAll(elements: Collection<T>): Boolean =
|
||||||
|
this@observable.removeAll(elements).also { onChanged() }
|
||||||
|
|
||||||
|
override fun retainAll(elements: Collection<T>): Boolean =
|
||||||
|
this@observable.retainAll(elements).also { onChanged() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal inline fun <T> MutableSet<T>.observable(crossinline onChanged: () -> Unit): MutableSet<T> {
|
internal inline fun <T> MutableSet<T>.observable(crossinline onChanged: () -> Unit): MutableSet<T> {
|
||||||
return object : MutableSet<T> {
|
return object : MutableSet<T> {
|
||||||
override val size: Int get() = this@observable.size
|
override val size: Int get() = this@observable.size
|
||||||
|
@ -10,16 +10,9 @@
|
|||||||
package net.mamoe.mirai.console.setting.internal
|
package net.mamoe.mirai.console.setting.internal
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.builtins.ListSerializer
|
|
||||||
import kotlinx.serialization.builtins.serializer
|
|
||||||
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
|
||||||
import net.mamoe.yamlkt.Yaml
|
|
||||||
import net.mamoe.yamlkt.YamlConfiguration
|
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.full.findAnnotation
|
import kotlin.reflect.full.findAnnotation
|
||||||
|
|
||||||
internal object SettingSerializerMark
|
|
||||||
|
|
||||||
internal val KProperty<*>.serialNameOrPropertyName: String get() = this.findAnnotation<SerialName>()?.value ?: this.name
|
internal val KProperty<*>.serialNameOrPropertyName: String get() = this.findAnnotation<SerialName>()?.value ?: this.name
|
||||||
|
|
||||||
internal inline fun <E> KSerializer<E>.bind(
|
internal inline fun <E> KSerializer<E>.bind(
|
@ -18,8 +18,9 @@ object TestCompositeCommand : CompositeCommand(
|
|||||||
"groupManagement", "grpMgn"
|
"groupManagement", "grpMgn"
|
||||||
) {
|
) {
|
||||||
@SubCommand
|
@SubCommand
|
||||||
suspend fun CommandSender.mute(image: Image, target: Member, seconds: Int) {
|
suspend fun CommandSender.mute(image: Image, target: Member, seconds: Int): Boolean {
|
||||||
target.mute(seconds)
|
target.mute(seconds)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.setting
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
internal class SettingTest {
|
||||||
|
|
||||||
|
class MySetting : Setting() {
|
||||||
|
val int by value(1)
|
||||||
|
val map by valueReified(mapOf("" to ""))
|
||||||
|
val map2 by valueReified(mapOf("" to mapOf("" to mapOf("" to ""))))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPrimitive() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
113
build.gradle.kts
113
build.gradle.kts
@ -1,33 +1,15 @@
|
|||||||
@file:Suppress("UnstableApiUsage")
|
@file:Suppress("UnstableApiUsage")
|
||||||
|
|
||||||
import kotlin.math.pow
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile::class.java) {
|
tasks.withType(JavaCompile::class.java) {
|
||||||
options.encoding = "UTF8"
|
options.encoding = "UTF8"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
|
||||||
maven(url = "https://mirrors.huaweicloud.com/repository/maven")
|
|
||||||
jcenter()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath("com.github.jengelman.gradle.plugins:shadow:5.2.0")
|
|
||||||
classpath("org.jetbrains.kotlin:kotlin-serialization:${Versions.Kotlin.stdlib}")
|
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin.stdlib}")
|
|
||||||
classpath("com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4") // don"t use any other.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "net.mamoe"
|
group = "net.mamoe"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
maven(url = "https://mirrors.huaweicloud.com/repository/maven")
|
|
||||||
jcenter()
|
jcenter()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
@ -35,97 +17,8 @@ allprojects {
|
|||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
apply(plugin = "com.github.johnrengelman.shadow")
|
apply<MiraiConsoleBuildPlugin>()
|
||||||
val kotlin =
|
|
||||||
(this as ExtensionAware).extensions.getByName("kotlin") as? org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
|
||||||
?: return@afterEvaluate
|
|
||||||
|
|
||||||
tasks.getByName("shadowJar") {
|
setJavaCompileTarget()
|
||||||
doLast {
|
|
||||||
this.outputs.files.forEach {
|
|
||||||
if (it.nameWithoutExtension.endsWith("-all")) {
|
|
||||||
val output = File(
|
|
||||||
it.path.substringBeforeLast(File.separator) + File.separator + it.nameWithoutExtension.substringBeforeLast(
|
|
||||||
"-all"
|
|
||||||
) + "." + it.extension
|
|
||||||
)
|
|
||||||
|
|
||||||
println("Renaming to ${output.path}")
|
|
||||||
if (output.exists()) {
|
|
||||||
output.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
it.renameTo(output)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val githubUpload by tasks.creating {
|
|
||||||
group = "mirai"
|
|
||||||
dependsOn(tasks.getByName("shadowJar"))
|
|
||||||
|
|
||||||
doFirst {
|
|
||||||
timeout.set(java.time.Duration.ofHours(3))
|
|
||||||
findLatestFile()?.let { (_, file) ->
|
|
||||||
val filename = file.name
|
|
||||||
println("Uploading file $filename")
|
|
||||||
runCatching {
|
|
||||||
upload.GitHub.upload(
|
|
||||||
file,
|
|
||||||
"https://api.github.com/repos/mamoe/mirai-repo/contents/shadow/${project.name}/$filename",
|
|
||||||
project
|
|
||||||
)
|
|
||||||
}.exceptionOrNull()?.let {
|
|
||||||
System.err.println("GitHub Upload failed")
|
|
||||||
it.printStackTrace() // force show stacktrace
|
|
||||||
throw it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val cuiCloudUpload by tasks.creating {
|
|
||||||
group = "mirai"
|
|
||||||
dependsOn(tasks.getByName("shadowJar"))
|
|
||||||
|
|
||||||
doFirst {
|
|
||||||
timeout.set(java.time.Duration.ofHours(3))
|
|
||||||
findLatestFile()?.let { (_, file) ->
|
|
||||||
val filename = file.name
|
|
||||||
println("Uploading file $filename")
|
|
||||||
runCatching {
|
|
||||||
upload.CuiCloud.upload(
|
|
||||||
file,
|
|
||||||
project
|
|
||||||
)
|
|
||||||
}.exceptionOrNull()?.let {
|
|
||||||
System.err.println("CuiCloud Upload failed")
|
|
||||||
it.printStackTrace() // force show stacktrace
|
|
||||||
throw it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun Project.findLatestFile(): Map.Entry<String, File> {
|
|
||||||
return File(projectDir, "build/libs").walk()
|
|
||||||
.filter { it.isFile }
|
|
||||||
.onEach { println("all files=$it") }
|
|
||||||
.filter { it.name.matches(Regex("""${project.name}-[0-9][0-9]*(\.[0-9]*)*.*\.jar""")) }
|
|
||||||
.onEach { println("matched file: ${it.name}") }
|
|
||||||
.associateBy { it.nameWithoutExtension.substringAfterLast('-') }
|
|
||||||
.onEach { println("versions: $it") }
|
|
||||||
.maxBy { (version, file) ->
|
|
||||||
version.split('.').let {
|
|
||||||
if (it.size == 2) it + "0"
|
|
||||||
else it
|
|
||||||
}.reversed().foldIndexed(0) { index: Int, acc: Int, s: String ->
|
|
||||||
acc + 100.0.pow(index).toInt() * (s.toIntOrNull() ?: 0)
|
|
||||||
}
|
|
||||||
} ?: error("cannot find any file to upload")
|
|
||||||
}
|
|
||||||
|
@ -3,7 +3,10 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
@ -24,4 +27,11 @@ dependencies {
|
|||||||
api(ktor("client-core", "1.3.2"))
|
api(ktor("client-core", "1.3.2"))
|
||||||
api(ktor("client-cio", "1.3.2"))
|
api(ktor("client-cio", "1.3.2"))
|
||||||
api(ktor("client-json", "1.3.2"))
|
api(ktor("client-json", "1.3.2"))
|
||||||
|
|
||||||
|
//api(gradleApi())
|
||||||
|
//compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72")
|
||||||
|
compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72")
|
||||||
|
//runtimeOnly("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72")
|
||||||
|
|
||||||
|
api("com.github.jengelman.gradle.plugins:shadow:6.0.0")
|
||||||
}
|
}
|
115
buildSrc/src/main/kotlin/MiraiConsoleBuildPlugin.kt
Normal file
115
buildSrc/src/main/kotlin/MiraiConsoleBuildPlugin.kt
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("UnstableApiUsage")
|
||||||
|
|
||||||
|
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
|
||||||
|
import org.gradle.api.Plugin
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.kotlin.dsl.apply
|
||||||
|
import org.gradle.kotlin.dsl.creating
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
class MiraiConsoleBuildPlugin : Plugin<Project> {
|
||||||
|
override fun apply(target: Project) = target.run {
|
||||||
|
apply<ShadowPlugin>()
|
||||||
|
|
||||||
|
if (tasks.none { it.name == "shadowJar" }) {
|
||||||
|
return@run
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.getByName("shadowJar") {
|
||||||
|
doLast {
|
||||||
|
this.outputs.files.forEach {
|
||||||
|
if (it.nameWithoutExtension.endsWith("-all")) {
|
||||||
|
val output = File(
|
||||||
|
it.path.substringBeforeLast(File.separator) + File.separator + it.nameWithoutExtension.substringBeforeLast(
|
||||||
|
"-all"
|
||||||
|
) + "." + it.extension
|
||||||
|
)
|
||||||
|
|
||||||
|
println("Renaming to ${output.path}")
|
||||||
|
if (output.exists()) {
|
||||||
|
output.delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
it.renameTo(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.creating {
|
||||||
|
group = "mirai"
|
||||||
|
dependsOn(tasks.getByName("shadowJar"))
|
||||||
|
|
||||||
|
doFirst {
|
||||||
|
timeout.set(java.time.Duration.ofHours(3))
|
||||||
|
findLatestFile().let { (_, file) ->
|
||||||
|
val filename = file.name
|
||||||
|
println("Uploading file $filename")
|
||||||
|
runCatching {
|
||||||
|
upload.GitHub.upload(
|
||||||
|
file,
|
||||||
|
"https://api.github.com/repos/mamoe/mirai-repo/contents/shadow/${project.name}/$filename",
|
||||||
|
project
|
||||||
|
)
|
||||||
|
}.exceptionOrNull()?.let {
|
||||||
|
System.err.println("GitHub Upload failed")
|
||||||
|
it.printStackTrace() // force show stacktrace
|
||||||
|
throw it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.creating {
|
||||||
|
group = "mirai"
|
||||||
|
dependsOn(tasks.getByName("shadowJar"))
|
||||||
|
|
||||||
|
doFirst {
|
||||||
|
timeout.set(java.time.Duration.ofHours(3))
|
||||||
|
findLatestFile().let { (_, file) ->
|
||||||
|
val filename = file.name
|
||||||
|
println("Uploading file $filename")
|
||||||
|
runCatching {
|
||||||
|
upload.CuiCloud.upload(
|
||||||
|
file,
|
||||||
|
project
|
||||||
|
)
|
||||||
|
}.exceptionOrNull()?.let {
|
||||||
|
System.err.println("CuiCloud Upload failed")
|
||||||
|
it.printStackTrace() // force show stacktrace
|
||||||
|
throw it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Project.findLatestFile(): Map.Entry<String, File> {
|
||||||
|
return File(projectDir, "build/libs").walk()
|
||||||
|
.filter { it.isFile }
|
||||||
|
.onEach { println("all files=$it") }
|
||||||
|
.filter { it.name.matches(Regex("""${project.name}-[0-9][0-9]*(\.[0-9]*)*.*\.jar""")) }
|
||||||
|
.onEach { println("matched file: ${it.name}") }
|
||||||
|
.associateBy { it.nameWithoutExtension.substringAfterLast('-') }
|
||||||
|
.onEach { println("versions: $it") }
|
||||||
|
.maxBy { (version, _) ->
|
||||||
|
version.split('.').let {
|
||||||
|
if (it.size == 2) it + "0"
|
||||||
|
else it
|
||||||
|
}.reversed().foldIndexed(0) { index: Int, acc: Int, s: String ->
|
||||||
|
acc + 100.0.pow(index).toInt() * (s.toIntOrNull() ?: 0)
|
||||||
|
}
|
||||||
|
} ?: error("cannot find any file to upload")
|
||||||
|
}
|
45
buildSrc/src/main/kotlin/SetCompileTargetPlugin.kt
Normal file
45
buildSrc/src/main/kotlin/SetCompileTargetPlugin.kt
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.gradle.api.JavaVersion
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.plugins.JavaPluginExtension
|
||||||
|
import org.gradle.api.tasks.compile.JavaCompile
|
||||||
|
import java.lang.reflect.Method
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
|
fun Any.reflectMethod(name: String, vararg params: KClass<out Any>): Pair<Any, Method> {
|
||||||
|
return this to this::class.java.getMethod(name, *params.map { it.java }.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun Pair<Any, Method>.invoke(vararg args: Any?): Any? {
|
||||||
|
return second.invoke(first, *args)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE") // or error
|
||||||
|
fun Project.setJavaCompileTarget() {
|
||||||
|
tasks.filter { it.name in arrayOf("compileKotlin", "compileTestKotlin") }.forEach { task ->
|
||||||
|
task
|
||||||
|
.reflectMethod("getKotlinOptions")()!!
|
||||||
|
.reflectMethod("setJvmTarget", String::class)("1.8")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
kotlin.runCatching { // apply only when java plugin is available
|
||||||
|
(extensions.getByName("java") as JavaPluginExtension).run {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile::class.java) {
|
||||||
|
options.encoding = "UTF8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,18 +8,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
object Versions {
|
object Versions {
|
||||||
object Mirai {
|
const val core = "1.1-EA"
|
||||||
const val core = "1.0.0"
|
|
||||||
const val console = "0.5.1"
|
const val console = "0.5.1"
|
||||||
const val consoleGraphical = "0.0.7"
|
const val consoleGraphical = "0.0.7"
|
||||||
const val consoleTerminal = "0.1.0"
|
const val consoleTerminal = "0.1.0"
|
||||||
const val consolePure = "0.1.0"
|
const val consolePure = "0.1.0"
|
||||||
}
|
|
||||||
|
|
||||||
object Kotlin {
|
const val kotlin = "1.3.72"
|
||||||
const val stdlib = "1.3.72"
|
|
||||||
const val coroutines = "1.3.7"
|
const val coroutines = "1.3.7"
|
||||||
const val serialization = "0.20.0"
|
const val serialization = "0.20.0"
|
||||||
const val ktor = "1.3.2"
|
const val ktor = "1.3.2"
|
||||||
}
|
|
||||||
|
const val androidGradle = "3.6.2"
|
||||||
|
|
||||||
|
const val bintray = "1.8.4"
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ import org.gradle.kotlin.dsl.DependencyHandlerScope
|
|||||||
fun DependencyHandlerScope.kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$version"
|
fun DependencyHandlerScope.kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$version"
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun DependencyHandlerScope.ktor(id: String, version: String = Versions.Kotlin.ktor) = "io.ktor:ktor-$id:$version"
|
fun DependencyHandlerScope.ktor(id: String, version: String = Versions.ktor) = "io.ktor:ktor-$id:$version"
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun DependencyHandler.compileAndRuntime(any: Any) {
|
fun DependencyHandler.compileAndRuntime(any: Any) {
|
||||||
|
@ -29,17 +29,17 @@ version = Versions.Mirai.consoleGraphical
|
|||||||
description = "Graphical frontend for mirai-console"
|
description = "Graphical frontend for mirai-console"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("net.mamoe:mirai-core:${Versions.Mirai.core}")
|
compileOnly("net.mamoe:mirai-core:${Versions.core}")
|
||||||
implementation(project(":mirai-console"))
|
implementation(project(":mirai-console"))
|
||||||
|
|
||||||
api(group = "no.tornado", name = "tornadofx", version = "1.7.19")
|
api(group = "no.tornado", name = "tornadofx", version = "1.7.19")
|
||||||
api(group = "com.jfoenix", name = "jfoenix", version = "9.0.8")
|
api(group = "com.jfoenix", name = "jfoenix", version = "9.0.8")
|
||||||
|
|
||||||
testApi(project(":mirai-console"))
|
testApi(project(":mirai-console"))
|
||||||
testApi(kotlinx("coroutines-core", Versions.Kotlin.coroutines))
|
testApi(kotlinx("coroutines-core", Versions.coroutines))
|
||||||
testApi(group = "org.yaml", name = "snakeyaml", version = "1.25")
|
testApi(group = "org.yaml", name = "snakeyaml", version = "1.25")
|
||||||
testApi("net.mamoe:mirai-core:${Versions.Mirai.core}")
|
testApi("net.mamoe:mirai-core:${Versions.core}")
|
||||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
@ -47,7 +47,7 @@ kotlin {
|
|||||||
all {
|
all {
|
||||||
|
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
|
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||||
languageSettings.progressiveMode = true
|
languageSettings.progressiveMode = true
|
||||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm") version Versions.kotlin
|
||||||
kotlin("plugin.serialization")
|
kotlin("plugin.serialization") version Versions.kotlin
|
||||||
id("java")
|
id("java")
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
id("com.jfrog.bintray")
|
id("com.jfrog.bintray") version Versions.bintray
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(plugin = "com.github.johnrengelman.shadow")
|
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
all {
|
all {
|
||||||
languageSettings.enableLanguageFeature("InlineClasses")
|
languageSettings.enableLanguageFeature("InlineClasses")
|
||||||
|
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
|
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||||
languageSettings.progressiveMode = true
|
languageSettings.progressiveMode = true
|
||||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
||||||
@ -25,31 +21,19 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
|
||||||
compileOnly(project(":mirai-console"))
|
|
||||||
compileOnly("net.mamoe:mirai-core:${Versions.Mirai.core}")
|
|
||||||
compileOnly(kotlin("stdlib")) // embedded by core
|
|
||||||
|
|
||||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
dependencies {
|
||||||
|
implementation("org.jline:jline:3.15.0")
|
||||||
|
implementation("org.fusesource.jansi:jansi:1.18")
|
||||||
|
|
||||||
|
compileAndRuntime(project(":mirai-console"))
|
||||||
|
compileAndRuntime("net.mamoe:mirai-core:${Versions.core}")
|
||||||
|
compileAndRuntime(kotlin("stdlib")) // embedded by core
|
||||||
|
|
||||||
|
testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||||
testApi(project(":mirai-console"))
|
testApi(project(":mirai-console"))
|
||||||
}
|
}
|
||||||
|
|
||||||
version = Versions.Mirai.consolePure
|
version = Versions.consolePure
|
||||||
|
|
||||||
description = "Console Pure CLI frontend for mirai"
|
description = "Console Pure CLI frontend for mirai"
|
||||||
|
|
||||||
val compileKotlin: KotlinCompile by tasks
|
|
||||||
compileKotlin.kotlinOptions {
|
|
||||||
jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
val compileTestKotlin: KotlinCompile by tasks
|
|
||||||
compileTestKotlin.kotlinOptions {
|
|
||||||
jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
tasks.withType(JavaCompile::class.java) {
|
|
||||||
options.encoding = "UTF8"
|
|
||||||
}
|
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.pure
|
||||||
|
|
||||||
|
import org.jline.reader.LineReader
|
||||||
|
import org.jline.reader.LineReaderBuilder
|
||||||
|
import org.jline.reader.impl.completer.NullCompleter
|
||||||
|
import org.jline.terminal.Terminal
|
||||||
|
import org.jline.terminal.TerminalBuilder
|
||||||
|
|
||||||
|
object ConsoleUtils {
|
||||||
|
|
||||||
|
val lineReader: LineReader
|
||||||
|
val terminal: Terminal
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
val dumb = System.getProperty("java.class.path")
|
||||||
|
.contains("idea_rt.jar") || System.getProperty("mirai.idea") !== null
|
||||||
|
|
||||||
|
terminal = TerminalBuilder.builder()
|
||||||
|
.dumb(dumb)
|
||||||
|
.build()
|
||||||
|
lineReader = LineReaderBuilder.builder()
|
||||||
|
.terminal(terminal)
|
||||||
|
.completer(NullCompleter())
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
@ -9,20 +9,90 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.pure
|
package net.mamoe.mirai.console.pure
|
||||||
|
|
||||||
import kotlinx.coroutines.delay
|
//import net.mamoe.mirai.console.command.CommandManager
|
||||||
|
//import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.console.command.CommandManager
|
import net.mamoe.mirai.console.MiraiConsoleFrontEnd
|
||||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
|
||||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
|
||||||
import net.mamoe.mirai.utils.DefaultLogger
|
|
||||||
import net.mamoe.mirai.utils.DefaultLoginSolver
|
import net.mamoe.mirai.utils.DefaultLoginSolver
|
||||||
import net.mamoe.mirai.utils.LoginSolver
|
import net.mamoe.mirai.utils.LoginSolver
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
|
import net.mamoe.mirai.utils.PlatformLogger
|
||||||
|
import org.fusesource.jansi.Ansi
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.concurrent.thread
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
private val ANSI_RESET = Ansi().reset().toString()
|
||||||
|
|
||||||
|
internal val LoggerCreator: (identity: String?) -> MiraiLogger = {
|
||||||
|
PlatformLogger(identity = it, output = { line ->
|
||||||
|
ConsoleUtils.lineReader.printAbove(line + ANSI_RESET)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
||||||
|
private val globalLogger = LoggerCreator("Mirai")
|
||||||
|
private val cachedLoggers = ConcurrentHashMap<String, MiraiLogger>()
|
||||||
|
|
||||||
|
// companion object {
|
||||||
|
// ANSI color codes
|
||||||
|
const val COLOR_RED = "\u001b[38;5;196m"
|
||||||
|
const val COLOR_CYAN = "\u001b[38;5;87m"
|
||||||
|
const val COLOR_GREEN = "\u001b[38;5;82m"
|
||||||
|
|
||||||
|
// use a dark yellow(more like orange) instead of light one to save Solarized-light users
|
||||||
|
const val COLOR_YELLOW = "\u001b[38;5;220m"
|
||||||
|
const val COLOR_GREY = "\u001b[38;5;244m"
|
||||||
|
const val COLOR_BLUE = "\u001b[38;5;27m"
|
||||||
|
const val COLOR_NAVY = "\u001b[38;5;24m" // navy uniform blue
|
||||||
|
const val COLOR_PINK = "\u001b[38;5;207m"
|
||||||
|
const val COLOR_RESET = "\u001b[39;49m"
|
||||||
|
// }
|
||||||
|
|
||||||
|
val sdf by lazy {
|
||||||
|
SimpleDateFormat("HH:mm:ss")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun loggerFor(identity: String?): MiraiLogger {
|
||||||
|
identity?.apply {
|
||||||
|
return cachedLoggers.computeIfAbsent(this, LoggerCreator)
|
||||||
|
}
|
||||||
|
return globalLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun prePushBot(identity: Long) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pushBot(bot: Bot) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun requestInput(hint: String): String {
|
||||||
|
if (hint.isNotEmpty()) {
|
||||||
|
ConsoleUtils.lineReader.printAbove(
|
||||||
|
Ansi.ansi()
|
||||||
|
.fgCyan().a(sdf.format(Date()))
|
||||||
|
.fgMagenta().a(hint)
|
||||||
|
.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return ConsoleUtils.lineReader.readLine("> ")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pushBotAdminStatus(identity: Long, admins: List<Long>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createLoginSolver(): LoginSolver {
|
||||||
|
return DefaultLoginSolver(
|
||||||
|
input = suspend {
|
||||||
|
requestInput("")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
||||||
private var requesting = false
|
private var requesting = false
|
||||||
private var requestStr = ""
|
private var requestStr = ""
|
||||||
@ -106,4 +176,4 @@ class MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 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/master/LICENSE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress(
|
||||||
|
"INVISIBLE_MEMBER",
|
||||||
|
"INVISIBLE_REFERENCE",
|
||||||
|
"CANNOT_OVERRIDE_INVISIBLE_MEMBER",
|
||||||
|
"INVISIBLE_SETTER",
|
||||||
|
"INVISIBLE_GETTER",
|
||||||
|
"INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER",
|
||||||
|
"INVISIBLE_ABSTRACT_MEMBER_FROM_SUPE_WARNING"
|
||||||
|
)
|
||||||
|
|
||||||
|
package net.mamoe.mirai.console.pure
|
||||||
|
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import net.mamoe.mirai.console.IMiraiConsole
|
||||||
|
import net.mamoe.mirai.console.MiraiConsoleFrontEnd
|
||||||
|
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||||
|
import net.mamoe.mirai.utils.DefaultLogger
|
||||||
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
|
private val delegateScope = CoroutineScope(EmptyCoroutineContext)
|
||||||
|
|
||||||
|
object MiraiConsolePure : IMiraiConsole {
|
||||||
|
override val builtInPluginLoaders: List<PluginLoader<*, *>> = LinkedList()
|
||||||
|
override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure
|
||||||
|
override val mainLogger: MiraiLogger = DefaultLogger("Console")
|
||||||
|
override val rootDir: File = File("./test/console").also {
|
||||||
|
it.mkdirs()
|
||||||
|
}
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = delegateScope.coroutineContext
|
||||||
|
}
|
@ -7,68 +7,67 @@
|
|||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:Suppress(
|
||||||
|
"INVISIBLE_MEMBER",
|
||||||
|
"INVISIBLE_REFERENCE",
|
||||||
|
"CANNOT_OVERRIDE_INVISIBLE_MEMBER",
|
||||||
|
"INVISIBLE_SETTER",
|
||||||
|
"INVISIBLE_GETTER",
|
||||||
|
"INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER",
|
||||||
|
"INVISIBLE_ABSTRACT_MEMBER_FROM_SUPE_WARNING"
|
||||||
|
)
|
||||||
|
|
||||||
package net.mamoe.mirai.console.pure
|
package net.mamoe.mirai.console.pure
|
||||||
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsoleInitializer
|
||||||
import net.mamoe.mirai.console.command.CommandManager
|
import net.mamoe.mirai.console.command.CommandExecuteStatus
|
||||||
import net.mamoe.mirai.console.command.DefaultCommands
|
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||||
import net.mamoe.mirai.console.plugins.PluginManager
|
import net.mamoe.mirai.console.command.executeCommand
|
||||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
import net.mamoe.mirai.message.data.Message
|
||||||
|
import net.mamoe.mirai.message.data.PlainText
|
||||||
|
import net.mamoe.mirai.utils.DefaultLogger
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
class MiraiConsolePureLoader {
|
object MiraiConsolePureLoader {
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun load(
|
fun main(args: Array<String>?) {
|
||||||
coreVersion: String,
|
startup()
|
||||||
consoleVersion: String
|
}
|
||||||
) {
|
}
|
||||||
start(
|
|
||||||
MiraiConsoleFrontEndPure(),
|
|
||||||
coreVersion,
|
internal fun startup() {
|
||||||
consoleVersion
|
MiraiConsoleInitializer.init(MiraiConsolePure)
|
||||||
)
|
startConsoleThread()
|
||||||
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
}
|
||||||
MiraiConsole.stop()
|
|
||||||
})
|
internal fun startConsoleThread() {
|
||||||
|
thread(name = "Console", isDaemon = false) {
|
||||||
|
val consoleLogger = DefaultLogger("Console")
|
||||||
|
kotlinx.coroutines.runBlocking {
|
||||||
|
while (true) {
|
||||||
|
val next = MiraiConsoleFrontEndPure.requestInput("")
|
||||||
|
consoleLogger.debug("INPUT> $next")
|
||||||
|
val result = ConsoleCS.executeCommand(PlainText(next))
|
||||||
|
when (result.status) {
|
||||||
|
CommandExecuteStatus.SUCCESSFUL -> {
|
||||||
|
}
|
||||||
|
CommandExecuteStatus.EMPTY_COMMAND -> {
|
||||||
|
}
|
||||||
|
CommandExecuteStatus.FAILED -> {
|
||||||
|
consoleLogger.error("An error occurred while executing the command: $next", result.exception)
|
||||||
|
}
|
||||||
|
CommandExecuteStatus.COMMAND_NOT_FOUND -> {
|
||||||
|
consoleLogger.warning("Unknown command: ${result.commandName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
object ConsoleCS : ConsoleCommandSender() {
|
||||||
* 启动 Console
|
override suspend fun sendMessage(message: Message) {
|
||||||
*/
|
ConsoleUtils.lineReader.printAbove(message.contentToString())
|
||||||
@JvmOverloads
|
|
||||||
internal fun start(
|
|
||||||
frontEnd: MiraiConsoleFrontEnd,
|
|
||||||
coreVersion: String = "0.0.0",
|
|
||||||
consoleVersion: String = "0.0.0",
|
|
||||||
path: String = System.getProperty("user.dir")
|
|
||||||
) {
|
|
||||||
if (MiraiConsole.started) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
MiraiConsole.started = true
|
|
||||||
this.path = path
|
|
||||||
/* 初始化前端 */
|
|
||||||
this.version = consoleVersion
|
|
||||||
this.frontEnd = frontEnd
|
|
||||||
this.frontEnd.pushVersion(consoleVersion, MiraiConsole.build, coreVersion)
|
|
||||||
logger("Mirai-console now running under $path")
|
|
||||||
logger("Get news in github: https://github.com/mamoe/mirai")
|
|
||||||
logger("Mirai为开源项目,请自觉遵守开源项目协议")
|
|
||||||
logger("Powered by Mamoe Technologies and contributors")
|
|
||||||
|
|
||||||
/* 依次启用功能 */
|
|
||||||
DefaultCommands()
|
|
||||||
PluginManager.loadPlugins()
|
|
||||||
CommandManager.start()
|
|
||||||
|
|
||||||
/* 通知启动完成 */
|
|
||||||
logger("Mirai-console 启动完成")
|
|
||||||
logger("\"login qqnumber qqpassword \" to login a bot")
|
|
||||||
logger("\"login qq号 qq密码 \" 来登录一个BOT")
|
|
||||||
|
|
||||||
/* 尝试从系统配置自动登录 */
|
|
||||||
DefaultCommands.tryLoginAuto()
|
|
||||||
}
|
}
|
@ -20,7 +20,7 @@ kotlin {
|
|||||||
all {
|
all {
|
||||||
|
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
|
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||||
languageSettings.progressiveMode = true
|
languageSettings.progressiveMode = true
|
||||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||||
}
|
}
|
||||||
@ -28,7 +28,7 @@ kotlin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
compileOnly("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||||
api(project(":mirai-console"))
|
api(project(":mirai-console"))
|
||||||
api(group = "com.googlecode.lanterna", name = "lanterna", version = "3.0.2")
|
api(group = "com.googlecode.lanterna", name = "lanterna", version = "3.0.2")
|
||||||
}
|
}
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
#Wed Mar 04 22:27:09 CST 2020
|
#Wed Mar 04 22:27:09 CST 2020
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
pluginManagement {
|
|
||||||
resolutionStrategy {
|
|
||||||
eachPlugin {
|
|
||||||
switch (requested.id.id) {
|
|
||||||
case "org.jetbrains.kotlin.multiplatform": useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}"); break
|
|
||||||
case "com.android.library": useModule("com.android.tools.build:gradle:${requested.version}"); break
|
|
||||||
case "com.jfrog.bintray": useModule("com.jfrog.bintray.gradle:gradle-bintray-plugin:${requested.version}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
jcenter()
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
maven { url "https://plugins.gradle.org/m2/" }
|
|
||||||
maven { url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies" }
|
|
||||||
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
|
|
||||||
maven { url 'https://plugins.gradle.org/m2/' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rootProject.name = 'mirai-console'
|
|
||||||
|
|
||||||
def onlyBackEnd = true
|
|
||||||
|
|
||||||
include(':mirai-console')
|
|
||||||
project(':mirai-console').dir = file("backend/mirai-console")
|
|
||||||
|
|
||||||
include(':codegen')
|
|
||||||
project(':codegen').dir = file("backend/codegen")
|
|
||||||
|
|
||||||
|
|
||||||
if (!onlyBackEnd) {
|
|
||||||
|
|
||||||
include(':mirai-console-pure')
|
|
||||||
project(':mirai-console-pure').dir = file("frontend/mirai-console-pure")
|
|
||||||
|
|
||||||
include(':mirai-console-terminal')
|
|
||||||
project(':mirai-console-terminal').dir = file("frontend/mirai-console-terminal")
|
|
||||||
|
|
||||||
try {
|
|
||||||
def javaVersion = System.getProperty("java.version")
|
|
||||||
def versionPos = javaVersion.indexOf(".")
|
|
||||||
def javaVersionNum = javaVersion.substring(0, 1).toInteger()
|
|
||||||
|
|
||||||
if (javaVersion.startsWith("1.")) {
|
|
||||||
javaVersionNum = javaVersion.substring(2, 3).toInteger()
|
|
||||||
} else {
|
|
||||||
if (versionPos == -1) versionPos = javaVersion.indexOf("-")
|
|
||||||
if (versionPos == -1) {
|
|
||||||
println("jdk version unknown")
|
|
||||||
} else {
|
|
||||||
javaVersionNum = javaVersion.substring(0, versionPos).toInteger()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (javaVersionNum >= 9) {
|
|
||||||
include(':mirai-console-graphical')
|
|
||||||
project(':mirai-console-graphical').dir = file("frontend/mirai-console-graphical")
|
|
||||||
} else {
|
|
||||||
println("jdk版本为 " + javaVersionNum)
|
|
||||||
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用JDK 9以上版本引入模块 `:mirai-console-graphical`\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
enableFeaturePreview('GRADLE_METADATA')
|
|
53
settings.gradle.kts
Normal file
53
settings.gradle.kts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
resolutionStrategy {
|
||||||
|
eachPlugin {
|
||||||
|
val version = requested.version
|
||||||
|
when (requested.id.id) {
|
||||||
|
"org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${version}")
|
||||||
|
"org.jetbrains.kotlin.plugin.serialization" -> useModule("org.jetbrains.kotlin:kotlin-serialization:${version}")
|
||||||
|
"com.jfrog.bintray" -> useModule("com.jfrog.bintray.gradle:gradle-bintray-plugin:$version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "mirai-console"
|
||||||
|
|
||||||
|
val disableOldFrontEnds = true
|
||||||
|
|
||||||
|
fun includeProject(projectPath: String, path: String? = null) {
|
||||||
|
include(projectPath)
|
||||||
|
if (path != null) project(projectPath).projectDir = file(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
includeProject(":mirai-console", "backend/mirai-console")
|
||||||
|
includeProject(":mirai-console.codegen", "backend/codegen")
|
||||||
|
includeProject(":mirai-console-pure", "frontend/mirai-console-pure")
|
||||||
|
|
||||||
|
@Suppress("ConstantConditionIf")
|
||||||
|
if (!disableOldFrontEnds) {
|
||||||
|
includeProject(":mirai-console-terminal", "frontend/mirai-console-terminal")
|
||||||
|
|
||||||
|
val jdkVersion = kotlin.runCatching {
|
||||||
|
System.getProperty("java.version").let { v ->
|
||||||
|
v.toIntOrNull() ?: v.removePrefix("1.").substringBefore("-").toIntOrNull()
|
||||||
|
}
|
||||||
|
}.getOrNull() ?: -1
|
||||||
|
|
||||||
|
println("JDK version: $jdkVersion")
|
||||||
|
|
||||||
|
if (jdkVersion >= 9) {
|
||||||
|
includeProject(":mirai-console-graphical", "frontend/mirai-console-graphical")
|
||||||
|
} else {
|
||||||
|
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用 JDK 9 以上版本引入模块 `:mirai-console-graphical`\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enableFeaturePreview("GRADLE_METADATA")
|
Loading…
Reference in New Issue
Block a user