Merge branch 'master' into command

# Conflicts:
#	backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/description/CommandArgumentContext.kt
This commit is contained in:
Him188 2020-09-20 21:57:10 +08:00
commit 2104cc2192
32 changed files with 421 additions and 505 deletions

View File

@ -0,0 +1,6 @@
# Mirai Console - Backend.codegen
后端代码生成模块,用于最小化重复代码的人工成本。
- `MessageScope` 代码生成: [MessageScopeCodegen.kt: Line 33](src/main/kotlin/net/mamoe/mirai/console/codegen/MessageScopeCodegen.kt#L33)
- `Value``PluginData` 相关代码生成: [ValueSettingCodegen.kt: Line 18](src/main/kotlin/net/mamoe/mirai/console/codegen/ValuePluginDataCodegen.kt#L18)

View File

@ -0,0 +1,3 @@
# Mirai Console - Backend
Mirai Console 后端模块. 发布为 `net.mamoe:mirai-console`.

View File

@ -65,11 +65,9 @@ dependencies {
compileAndTestRuntime(kotlinx("serialization-core", Versions.serialization)) compileAndTestRuntime(kotlinx("serialization-core", Versions.serialization))
compileAndTestRuntime(kotlin("reflect")) compileAndTestRuntime(kotlin("reflect"))
implementation("org.jetbrains:annotations:19.0.0") smartImplementation("net.mamoe.yamlkt:yamlkt:${Versions.yamlkt}")
smartImplementation("org.jetbrains:annotations:19.0.0")
smartApi(kotlinx("coroutines-jdk8", Versions.coroutines)) smartApi(kotlinx("coroutines-jdk8", Versions.coroutines))
smartApi("net.mamoe.yamlkt:yamlkt:${Versions.yamlkt}")
smartApi("com.vdurmont:semver4j:3.1.0")
testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}") testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}")
testApi(kotlin("stdlib-jdk8")) testApi(kotlin("stdlib-jdk8"))
@ -102,8 +100,8 @@ tasks {
})""" })"""
} }
.replace( .replace(
Regex("""val version: Semver = Semver\(".*", Semver.SemverType.LOOSE\)""") Regex("""val version: SemVersion = SemVersion.parse\(".*"\)""")
) { """val version: Semver = Semver("${project.version}", Semver.SemverType.LOOSE)""" } ) { """val version: SemVersion = SemVersion.parse("${project.version}")""" }
) )
} }
} }

View File

@ -12,7 +12,6 @@
package net.mamoe.mirai.console package net.mamoe.mirai.console
import com.vdurmont.semver4j.Semver
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
@ -29,6 +28,7 @@ import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInternalApi import net.mamoe.mirai.console.util.ConsoleInternalApi
import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScopeContext import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScopeContext
import net.mamoe.mirai.console.util.SemVersion
import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.MiraiLogger
import java.io.File import java.io.File
@ -79,7 +79,7 @@ public interface MiraiConsole : CoroutineScope {
/** /**
* Console 后端版本号 * Console 后端版本号
*/ */
public val version: Semver public val version: SemVersion
@ConsoleExperimentalApi @ConsoleExperimentalApi

View File

@ -9,7 +9,8 @@
package net.mamoe.mirai.console package net.mamoe.mirai.console
import com.vdurmont.semver4j.Semver import net.mamoe.mirai.console.util.SemVersion
/** /**
* 有关前端实现的信息 * 有关前端实现的信息
@ -28,7 +29,7 @@ public interface MiraiConsoleFrontEndDescription {
/** /**
* 此前端实现的名称 * 此前端实现的名称
*/ */
public val version: Semver public val version: SemVersion
/** /**
* 兼容的 [MiraiConsole] 后端版本号 * 兼容的 [MiraiConsole] 后端版本号
@ -37,7 +38,7 @@ public interface MiraiConsoleFrontEndDescription {
* *
* 返回 `null` 表示禁止 [MiraiConsole] 后端检查版本兼容性. * 返回 `null` 表示禁止 [MiraiConsole] 后端检查版本兼容性.
*/ */
public val compatibleBackendVersion: Semver? get() = null public val compatibleBackendVersion: SemVersion? get() = null
/** /**
* 返回显示在 [MiraiConsole] 启动时的信息 * 返回显示在 [MiraiConsole] 启动时的信息

View File

@ -21,6 +21,8 @@ import net.mamoe.mirai.console.permission.PermitteeId
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.contact.* import net.mamoe.mirai.contact.*
import net.mamoe.mirai.message.data.MessageContent import net.mamoe.mirai.message.data.MessageContent
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.PlainText
import kotlin.internal.LowPriorityInOverloadResolution import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf
@ -76,6 +78,9 @@ public interface CommandArgumentContext {
Double::class with DoubleArgumentParser Double::class with DoubleArgumentParser
Float::class with FloatArgumentParser Float::class with FloatArgumentParser
Image::class with ImageArgumentParser
PlainText::class with PlainTextArgumentParser
Contact::class with ExistingContactArgumentParser Contact::class with ExistingContactArgumentParser
User::class with ExistingUserArgumentParser User::class with ExistingUserArgumentParser
Member::class with ExistingMemberArgumentParser Member::class with ExistingMemberArgumentParser

View File

@ -77,6 +77,35 @@ public object StringArgumentParser : InternalCommandArgumentParserExtensions<Str
public override fun parse(raw: String, sender: CommandSender): String = raw public override fun parse(raw: String, sender: CommandSender): String = raw
} }
/**
* 解析 [String] 通过 [Image].
*/
public object ImageArgumentParser : InternalCommandArgumentParserExtensions<Image> {
public override fun parse(raw: String, sender: CommandSender): Image {
return kotlin.runCatching {
Image(raw)
}.getOrElse {
illegalArgument("无法解析 $raw 为图片.")
}
}
override fun parse(raw: MessageContent, sender: CommandSender): Image {
if (raw is Image) return raw
return super.parse(raw, sender)
}
}
public object PlainTextArgumentParser : InternalCommandArgumentParserExtensions<PlainText> {
public override fun parse(raw: String, sender: CommandSender): PlainText {
return PlainText(raw)
}
override fun parse(raw: MessageContent, sender: CommandSender): PlainText {
if (raw is PlainText) return raw
return super.parse(raw, sender)
}
}
/** /**
* 当字符串内容为(不区分大小写) "true", "yes", "enabled" * 当字符串内容为(不区分大小写) "true", "yes", "enabled"
*/ */

View File

@ -24,7 +24,7 @@ import kotlinx.coroutines.Job
* @see AutoSavePluginData * @see AutoSavePluginData
*/ */
public open class AutoSavePluginConfig : AutoSavePluginData, PluginConfig { public open class AutoSavePluginConfig : AutoSavePluginData, PluginConfig {
@Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginConfig(\"改成保存名称\")")) @Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginConfig(\"把我改成保存名称\")"))
@Suppress("DEPRECATION_ERROR") @Suppress("DEPRECATION_ERROR")
public constructor() : super() public constructor() : super()

View File

@ -30,7 +30,8 @@ import kotlin.reflect.full.findAnnotation
* @see PluginData * @see PluginData
*/ */
public open class AutoSavePluginData private constructor( public open class AutoSavePluginData private constructor(
@Suppress("UNUSED_PARAMETER") primaryConstructorMark: Any? // KEEP THIS PRIMARY CONSTRUCTOR FOR FUTURE USE: WE'LL SUPPORT SERIALIZERS_MODULE FOR POLYMORPHISM
@Suppress("UNUSED_PARAMETER") primaryConstructorMark: Any?,
) : AbstractPluginData() { ) : AbstractPluginData() {
private lateinit var owner_: AutoSavePluginDataHolder private lateinit var owner_: AutoSavePluginDataHolder
private val autoSaveIntervalMillis_: LongRange get() = owner_.autoSaveIntervalMillis private val autoSaveIntervalMillis_: LongRange get() = owner_.autoSaveIntervalMillis
@ -45,7 +46,7 @@ public open class AutoSavePluginData private constructor(
_saveName = saveName _saveName = saveName
} }
@Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginConfig")) @Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginData(\"把我改成保存名称\")"))
public constructor() : this(null) { public constructor() : this(null) {
val clazz = this::class val clazz = this::class
_saveName = clazz.findAnnotation<ValueName>()?.value _saveName = clazz.findAnnotation<ValueName>()?.value
@ -72,7 +73,7 @@ public open class AutoSavePluginData private constructor(
?.let { return@invokeOnCompletion } ?.let { return@invokeOnCompletion }
MiraiConsole.mainLogger.error( MiraiConsole.mainLogger.error(
"An exception occurred when saving config ${this@AutoSavePluginData::class.qualifiedNameOrTip} " + "An exception occurred when saving config ${this@AutoSavePluginData::class.qualifiedNameOrTip} " +
"but CoroutineExceptionHandler not found in PluginDataHolder.coroutineContext for ${owner::class.qualifiedNameOrTip}", "but CoroutineExceptionHandler not found in PluginDataHolder.coroutineContext for ${owner::class.qualifiedNameOrTip}",
e e
) )
} }

View File

@ -9,14 +9,12 @@
package net.mamoe.mirai.console.data package net.mamoe.mirai.console.data
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
/** /**
* 序列化之后的名称. * 序列化之后的名称.
* *
* : * :
* ``` * ```
* object AccountPluginData : PluginData by ... { * object AccountPluginData : AutoSavePluginData() {
* @ValueName("info") * @ValueName("info")
* val map: Map<String, String> by value("a" to "b") * val map: Map<String, String> by value("a" to "b")
* } * }
@ -28,8 +26,10 @@ import net.mamoe.mirai.console.util.ConsoleExperimentalApi
* map: * map:
* a: b * a: b
* ``` * ```
*
* @see PluginData
* @see Value
*/ */
@ConsoleExperimentalApi
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS) @Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
public annotation class ValueName(val value: String) public annotation class ValueName(val value: String)

View File

@ -38,7 +38,7 @@ import net.mamoe.mirai.console.data.PluginData
* @see PluginConfig * @see PluginConfig
*/ */
public abstract class JAutoSavePluginConfig : AutoSavePluginConfig, PluginConfig { public abstract class JAutoSavePluginConfig : AutoSavePluginConfig, PluginConfig {
@Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginConfig(\"改成保存名称\")")) @Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("JAutoSavePluginConfig(\"把我改成保存名称\")"))
@Suppress("DEPRECATION_ERROR") @Suppress("DEPRECATION_ERROR")
public constructor() : super() public constructor() : super()

View File

@ -67,7 +67,7 @@ import kotlin.reflect.full.createType
* @see PluginData * @see PluginData
*/ */
public abstract class JAutoSavePluginData : AutoSavePluginData, PluginConfig { public abstract class JAutoSavePluginData : AutoSavePluginData, PluginConfig {
@Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("AutoSavePluginConfig(\"改成保存的名称\")")) @Deprecated("请手动指定保存名称. 此构造器将在 1.0.0 删除", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("JAutoSavePluginData(\"把我改成保存名称\")"))
@Suppress("DEPRECATION_ERROR") @Suppress("DEPRECATION_ERROR")
public constructor() : super() public constructor() : super()

View File

@ -9,13 +9,13 @@
package net.mamoe.mirai.console.internal package net.mamoe.mirai.console.internal
import com.vdurmont.semver4j.Semver import net.mamoe.mirai.console.util.SemVersion
import java.time.Instant import java.time.Instant
internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants) internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants)
@JvmStatic @JvmStatic
val buildDate: Instant = Instant.ofEpochSecond(1600522812) val buildDate: Instant = Instant.ofEpochSecond(1600596035)
@JvmStatic @JvmStatic
val version: Semver = Semver("1.0-RC-dev-28", Semver.SemverType.LOOSE) val version: SemVersion = SemVersion("1.0-RC-dev-28")
} }

View File

@ -11,7 +11,6 @@
package net.mamoe.mirai.console.internal package net.mamoe.mirai.console.internal
import com.vdurmont.semver4j.Semver
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -47,6 +46,7 @@ import net.mamoe.mirai.console.plugin.jvm.AbstractJvmPlugin
import net.mamoe.mirai.console.plugin.loader.PluginLoader import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInput import net.mamoe.mirai.console.util.ConsoleInput
import net.mamoe.mirai.console.util.SemVersion
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import java.nio.file.Path import java.nio.file.Path
import java.time.Instant import java.time.Instant
@ -66,7 +66,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
private val instance: MiraiConsoleImplementation by MiraiConsoleImplementation.Companion::instance private val instance: MiraiConsoleImplementation by MiraiConsoleImplementation.Companion::instance
override val buildDate: Instant by MiraiConsoleBuildConstants::buildDate override val buildDate: Instant by MiraiConsoleBuildConstants::buildDate
override val version: Semver by MiraiConsoleBuildConstants::version override val version: SemVersion by MiraiConsoleBuildConstants::version
override val rootPath: Path by instance::rootPath override val rootPath: Path by instance::rootPath
override val frontEndDescription: MiraiConsoleFrontEndDescription by instance::frontEndDescription override val frontEndDescription: MiraiConsoleFrontEndDescription by instance::frontEndDescription

View File

@ -9,6 +9,8 @@
package net.mamoe.mirai.console.internal.data package net.mamoe.mirai.console.internal.data
import kotlinx.serialization.json.Json
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.data.* import net.mamoe.mirai.console.data.*
import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
@ -59,23 +61,28 @@ internal open class MultiFilePluginDataStorageImpl(
return file.toFile().also { it.createNewFile() } return file.toFile().also { it.createNewFile() }
} }
private val json = Json {
prettyPrint = true
ignoreUnknownKeys = true
isLenient = true
allowStructuredMapKeys = true
}
private val yaml = Yaml.default
@ConsoleExperimentalApi @ConsoleExperimentalApi
public override fun store(holder: PluginDataHolder, instance: PluginData) { public override fun store(holder: PluginDataHolder, instance: PluginData) {
val yaml =/* if (instance.saveName == "PermissionService") Json {
prettyPrint = true
ignoreUnknownKeys = true
isLenient = true
allowStructuredMapKeys = true
} /*Yaml(
configuration = YamlConfiguration(
mapSerialization = YamlConfiguration.MapSerialization.FLOW_MAP,
listSerialization = YamlConfiguration.ListSerialization.FLOW_SEQUENCE,
classSerialization = YamlConfiguration.MapSerialization.FLOW_MAP
)
)*/ else */Yaml.default
getPluginDataFile(holder, instance).writeText( getPluginDataFile(holder, instance).writeText(
kotlin.runCatching { kotlin.runCatching {
yaml.encodeToString(instance.updaterSerializer, Unit) yaml.encodeToString(instance.updaterSerializer, Unit)
}.recoverCatching {
// Just use mainLogger for convenience.
MiraiConsole.mainLogger.warning(
"Could not save ${instance.saveName} in YAML format due to exception in YAML encoder. " +
"Please report this exception and relevant configurations to https://github.com/mamoe/mirai-console/issues/new",
it
)
json.encodeToString(instance.updaterSerializer, Unit)
}.getOrElse { }.getOrElse {
throw IllegalStateException("Exception while saving $instance, saveName=${instance.saveName}", it) throw IllegalStateException("Exception while saving $instance, saveName=${instance.saveName}", it)
} }

View File

@ -27,6 +27,7 @@ import net.mamoe.mirai.console.plugin.loader.PluginLoadException
import net.mamoe.mirai.console.plugin.loader.PluginLoader import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.plugin.name import net.mamoe.mirai.console.plugin.name
import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope
import net.mamoe.mirai.console.util.SemVersion.Companion.contains
import net.mamoe.mirai.utils.info import net.mamoe.mirai.utils.info
import java.io.File import java.io.File
import java.nio.file.Path import java.nio.file.Path

View File

@ -26,83 +26,132 @@ internal object SemVersionInternal {
private val versionMathRange = private val versionMathRange =
"""\[([0-9]+(\.[0-9]+)+(|[\-+].+))\s*\,\s*([0-9]+(\.[0-9]+)+(|[\-+].+))\]""".toRegex() """\[([0-9]+(\.[0-9]+)+(|[\-+].+))\s*\,\s*([0-9]+(\.[0-9]+)+(|[\-+].+))\]""".toRegex()
private val versionRule = """^((\>\=)|(\<\=)|(\=)|(\>)|(\<))\s*([0-9]+(\.[0-9]+)+(|[\-+].+))$""".toRegex() private val versionRule = """^((\>\=)|(\<\=)|(\=)|(\>)|(\<))\s*([0-9]+(\.[0-9]+)+(|[\-+].+))$""".toRegex()
private fun Collection<*>.dump() {
forEachIndexed { index, value -> private val SEM_VERSION_REGEX =
println("$index, $value") """^(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$""".toRegex()
/** 解析核心版本号, eg: `1.0.0` -> IntArray[1, 0, 0] */
@JvmStatic
private fun String.parseMainVersion(): IntArray =
split('.').map { it.toInt() }.toIntArray()
fun parse(version: String): SemVersion {
if (!SEM_VERSION_REGEX.matches(version)) {
throw IllegalArgumentException("`$version` not a valid version")
} }
var mainVersionEnd = 0
kotlin.run {
val iterator = version.iterator()
while (iterator.hasNext()) {
val next = iterator.next()
if (next == '-' || next == '+') {
break
}
mainVersionEnd++
}
}
var identifier: String? = null
var metadata: String? = null
if (mainVersionEnd != version.length) {
when (version[mainVersionEnd]) {
'-' -> {
val metadataSplitter = version.indexOf('+', startIndex = mainVersionEnd)
if (metadataSplitter == -1) {
identifier = version.substring(mainVersionEnd + 1)
} else {
identifier = version.substring(mainVersionEnd + 1, metadataSplitter)
metadata = version.substring(metadataSplitter + 1)
}
}
'+' -> {
metadata = version.substring(mainVersionEnd + 1)
}
}
}
return SemVersion(
mainVersion = version.substring(0, mainVersionEnd).parseMainVersion(),
identifier = identifier,
metadata = metadata
)
} }
@JvmStatic @JvmStatic
private fun String.parseRule(): SemVersion.RangeRequirement { private fun String.parseRule(): SemVersion.Requirement {
val trimmed = trim() val trimmed = trim()
if (directVersion.matches(trimmed)) { if (directVersion.matches(trimmed)) {
val parsed = SemVersion.parse(trimmed) val parsed = SemVersion.invoke(trimmed)
return SemVersion.RangeRequirement { return object : SemVersion.Requirement {
it.compareTo(parsed) == 0 override fun test(version: SemVersion): Boolean = version.compareTo(parsed) == 0
} }
} }
if (versionSelect.matches(trimmed)) { if (versionSelect.matches(trimmed)) {
val regex = ("^" + val regex = ("^" +
trimmed.replace(".", "\\.") trimmed.replace(".", "\\.")
.replace("x", ".+") + .replace("x", ".+") +
"$" "$"
).toRegex() ).toRegex()
return SemVersion.RangeRequirement { return object : SemVersion.Requirement {
regex.matches(it.toString()) override fun test(version: SemVersion): Boolean = regex.matches(version.toString())
} }
} }
(versionRange.matchEntire(trimmed) ?: versionMathRange.matchEntire(trimmed))?.let { range -> (versionRange.matchEntire(trimmed) ?: versionMathRange.matchEntire(trimmed))?.let { range ->
var start = SemVersion.parse(range.groupValues[1]) var start = SemVersion.invoke(range.groupValues[1])
var end = SemVersion.parse(range.groupValues[4]) var end = SemVersion.invoke(range.groupValues[4])
if (start > end) { if (start > end) {
val c = end val c = end
end = start end = start
start = c start = c
} }
val compareRange = start..end val compareRange = start..end
return SemVersion.RangeRequirement { return object : SemVersion.Requirement {
it in compareRange override fun test(version: SemVersion): Boolean = version in compareRange
} }
} }
versionRule.matchEntire(trimmed)?.let { result -> versionRule.matchEntire(trimmed)?.let { result ->
val operator = result.groupValues[1] val operator = result.groupValues[1]
val version = SemVersion.parse(result.groupValues[7]) val version1 = SemVersion.invoke(result.groupValues[7])
return when (operator) { return when (operator) {
">=" -> { ">=" -> {
SemVersion.RangeRequirement { it >= version } object : SemVersion.Requirement {
override fun test(version: SemVersion): Boolean = version >= version1
}
} }
">" -> { ">" -> {
SemVersion.RangeRequirement { it > version } object : SemVersion.Requirement {
override fun test(version: SemVersion): Boolean = version > version1
}
} }
"<=" -> { "<=" -> {
SemVersion.RangeRequirement { it <= version } object : SemVersion.Requirement {
override fun test(version: SemVersion): Boolean = version <= version1
}
} }
"<" -> { "<" -> {
SemVersion.RangeRequirement { it < version } object : SemVersion.Requirement {
override fun test(version: SemVersion): Boolean = version < version1
}
} }
"=" -> { "=" -> {
SemVersion.RangeRequirement { it.compareTo(version) == 0 } object : SemVersion.Requirement {
override fun test(version: SemVersion): Boolean = version.compareTo(version1) == 0
}
} }
else -> throw AssertionError("operator=$operator, version=$version") else -> error("operator=$operator, version=$version1")
} }
} }
throw UnsupportedOperationException("Cannot parse $this") throw IllegalArgumentException("Cannot parse $this")
} }
private fun SemVersion.RangeRequirement.withRule(rule: String): SemVersion.RangeRequirement { private fun SemVersion.Requirement.withRule(rule: String): SemVersion.Requirement {
return object : SemVersion.RangeRequirement { return object : SemVersion.Requirement {
override fun check(version: SemVersion): Boolean { override fun test(version: SemVersion): Boolean = this@withRule.test(version)
return this@withRule.check(version) override fun toString(): String = rule
}
override fun toString(): String {
return rule
}
} }
} }
@JvmStatic @JvmStatic
fun parseRangeRequirement(requirement: String): SemVersion.RangeRequirement { fun parseRangeRequirement(requirement: String): SemVersion.Requirement {
if (requirement.isBlank()) { if (requirement.isBlank()) {
throw IllegalArgumentException("Invalid requirement: Empty requirement rule.") throw IllegalArgumentException("Invalid requirement: Empty requirement rule.")
} }
@ -110,33 +159,35 @@ internal object SemVersionInternal {
it.parseRule().withRule(it) it.parseRule().withRule(it)
}.let { checks -> }.let { checks ->
if (checks.size == 1) return checks[0] if (checks.size == 1) return checks[0]
SemVersion.RangeRequirement { object : SemVersion.Requirement {
checks.forEach { rule -> override fun test(version: SemVersion): Boolean {
if (rule.check(it)) return@RangeRequirement true checks.forEach { rule ->
if (rule.test(version)) return true
}
return false
} }
return@RangeRequirement false
}.withRule(requirement) }.withRule(requirement)
} }
} }
@JvmStatic @JvmStatic
fun SemVersion.compareInternal(other: SemVersion): Int { fun compareInternal(source: SemVersion, other: SemVersion): Int {
// ignored metadata in comparing // ignored metadata in comparing
// If $this equals $other (without metadata), // If $this equals $other (without metadata),
// return same. // return same.
if (other.mainVersion.contentEquals(mainVersion) && identifier == other.identifier) { if (other.mainVersion.contentEquals(source.mainVersion) && source.identifier == other.identifier) {
return 0 return 0
} }
fun IntArray.getSafe(index: Int) = getOrElse(index) { 0 } fun IntArray.getSafe(index: Int) = getOrElse(index) { 0 }
// Compare main-version // Compare main-version
for (index in 0 until (max(mainVersion.size, other.mainVersion.size))) { for (index in 0 until (max(source.mainVersion.size, other.mainVersion.size))) {
val result = mainVersion.getSafe(index).compareTo(other.mainVersion.getSafe(index)) val result = source.mainVersion.getSafe(index).compareTo(other.mainVersion.getSafe(index))
if (result != 0) return result if (result != 0) return result
} }
// If main-versions are same. // If main-versions are same.
var identifier0 = identifier var identifier0 = source.identifier
var identifier1 = other.identifier var identifier1 = other.identifier
// If anyone doesn't have the identifier... // If anyone doesn't have the identifier...
if (identifier0 == null || identifier1 == null) { if (identifier0 == null || identifier1 == null) {

View File

@ -11,7 +11,6 @@
package net.mamoe.mirai.console.plugin package net.mamoe.mirai.console.plugin
import com.vdurmont.semver4j.Semver
import net.mamoe.mirai.console.command.CommandOwner import net.mamoe.mirai.console.command.CommandOwner
import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.disable import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.disable
import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.enable import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.enable
@ -20,6 +19,7 @@ import net.mamoe.mirai.console.plugin.description.PluginDependency
import net.mamoe.mirai.console.plugin.description.PluginDescription import net.mamoe.mirai.console.plugin.description.PluginDescription
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
import net.mamoe.mirai.console.plugin.loader.PluginLoader import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.SemVersion
/** /**
* 表示一个 mirai-console 插件. * 表示一个 mirai-console 插件.
@ -62,7 +62,7 @@ public inline val Plugin.name: String get() = this.description.name
/** /**
* 获取 [PluginDescription.version] * 获取 [PluginDescription.version]
*/ */
public inline val Plugin.version: Semver get() = this.description.version public inline val Plugin.version: SemVersion get() = this.description.version
/** /**
* 获取 [PluginDescription.info] * 获取 [PluginDescription.info]

View File

@ -11,6 +11,10 @@
package net.mamoe.mirai.console.plugin.description package net.mamoe.mirai.console.plugin.description
import net.mamoe.mirai.console.compiler.common.ResolveContext
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.PLUGIN_ID
import net.mamoe.mirai.console.util.SemVersion
/** /**
* 插件的一个依赖的信息. * 插件的一个依赖的信息.
* *
@ -20,16 +24,15 @@ public data class PluginDependency @JvmOverloads constructor(
/** /**
* 依赖插件 ID, [PluginDescription.id] * 依赖插件 ID, [PluginDescription.id]
*/ */
public val id: String, @ResolveContext(PLUGIN_ID) public val id: String,
/** /**
* 依赖版本号. null 时则为不限制版本. * 依赖版本号. null 时则为不限制版本.
* *
* 版本遵循 [语义化版本 2.0 规范](https://semver.org/lang/zh-CN/), * 版本遵循 [语义化版本 2.0 规范](https://semver.org/lang/zh-CN/),
* *
* ### 示例 * @see SemVersion.Requirement
* `Requirement.buildIvy("[1.0, 2.0)")`
*/ */
public val versionRequirement: VersionRequirement? = null, public val versionRequirement: SemVersion.Requirement? = null,
/** /**
* 若为 `false`, 插件在找不到此依赖时也能正常加载. * 若为 `false`, 插件在找不到此依赖时也能正常加载.
*/ */
@ -46,7 +49,10 @@ public data class PluginDependency @JvmOverloads constructor(
/** /**
* @see PluginDependency * @see PluginDependency
*/ */
public constructor(name: String, isOptional: Boolean = false) : this( public constructor(
name, null, isOptional @ResolveContext(PLUGIN_ID) id: String,
isOptional: Boolean = false,
) : this(
id, null, isOptional
) )
} }

View File

@ -9,10 +9,10 @@
package net.mamoe.mirai.console.plugin.description package net.mamoe.mirai.console.plugin.description
import com.vdurmont.semver4j.Semver
import net.mamoe.mirai.console.compiler.common.ResolveContext import net.mamoe.mirai.console.compiler.common.ResolveContext
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.* import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.*
import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.util.SemVersion
/** /**
@ -93,7 +93,7 @@ public interface PluginDescription {
* @see Semver 语义化版本. 允许 [宽松][Semver.SemverType.LOOSE] 类型版本. * @see Semver 语义化版本. 允许 [宽松][Semver.SemverType.LOOSE] 类型版本.
*/ */
@ResolveContext(PLUGIN_VERSION) @ResolveContext(PLUGIN_VERSION)
public val version: Semver public val version: SemVersion
/** /**
* 插件信息, 允许为空 * 插件信息, 允许为空

View File

@ -1,242 +0,0 @@
package net.mamoe.mirai.console.plugin.description
import com.vdurmont.semver4j.Requirement
import com.vdurmont.semver4j.Semver
public sealed class VersionRequirement {
public abstract operator fun contains(version: Semver): Boolean
public fun contains(version: String): Boolean = contains(Semver(version, Semver.SemverType.LOOSE))
public class Exact
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
constructor(
version: Semver,
) : VersionRequirement() {
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
public val version: Semver = version.toStrict()
@Suppress("DEPRECATION_ERROR")
public constructor(version: String) : this(Semver(version, Semver.SemverType.LOOSE))
@Suppress("DEPRECATION_ERROR")
override fun contains(version: Semver): Boolean = this.version.isEquivalentTo(version.toStrict())
}
public data class MatchesNpmPattern(
val pattern: String,
) : VersionRequirement() {
private val requirement = Requirement.buildNPM(pattern)
override fun contains(version: Semver): Boolean = requirement.isSatisfiedBy(version.toStrict())
}
public data class MatchesIvyPattern(
val pattern: String,
) : VersionRequirement() {
private val requirement = Requirement.buildIvy(pattern)
override fun contains(version: Semver): Boolean = requirement.isSatisfiedBy(version.toStrict())
}
public data class MatchesCocoapodsPattern(
val pattern: String,
) : VersionRequirement() {
private val requirement = Requirement.buildCocoapods(pattern)
override fun contains(version: Semver): Boolean = requirement.isSatisfiedBy(version.toStrict())
}
public abstract class Custom : VersionRequirement()
@Suppress("MemberVisibilityCanBePrivate")
public class InRange(
begin: Semver,
public val beginInclusive: Boolean,
end: Semver,
public val endInclusive: Boolean,
) : VersionRequirement() {
public val end: Semver = end.toStrict()
public val begin: Semver = begin.toStrict()
public constructor(
begin: String,
beginInclusive: Boolean,
end: Semver,
endInclusive: Boolean,
) : this(Semver(begin, Semver.SemverType.LOOSE), beginInclusive, end, endInclusive)
public constructor(
begin: String,
beginInclusive: Boolean,
end: String,
endInclusive: Boolean,
) : this(Semver(begin, Semver.SemverType.LOOSE),
beginInclusive,
Semver(end, Semver.SemverType.LOOSE),
endInclusive)
public constructor(
begin: Semver,
beginInclusive: Boolean,
end: String,
endInclusive: Boolean,
) : this(begin, beginInclusive, Semver(end, Semver.SemverType.LOOSE), endInclusive)
override fun contains(version: Semver): Boolean {
val strict = version.toStrict()
return if (beginInclusive) {
strict.isGreaterThanOrEqualTo(begin)
} else {
strict.isGreaterThan(begin)
} && if (endInclusive) {
strict.isLowerThanOrEqualTo(end)
} else {
strict.isLowerThan(end)
}
}
override fun toString(): String {
return buildString {
append(if (beginInclusive) "[" else "(")
append(begin)
append(",")
append(end)
append(if (endInclusive) "]" else ")")
}
}
}
@Suppress("unused", "DeprecatedCallableAddReplaceWith")
public class Builder {
@Suppress("DEPRECATION_ERROR")
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKafuuChinoForever
public fun exact(version: Semver): VersionRequirement = Exact(version)
@ILoveKafuuChinoForever
public fun exact(version: String): VersionRequirement = Exact(version)
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKafuuChinoForever
public fun custom(checker: (version: Semver) -> Boolean): VersionRequirement {
return object : Custom() {
override fun contains(version: Semver): Boolean = checker(version)
}
}
/**
* @see Semver.SemverType.NPM
*/
@ILoveKafuuChinoForever
public fun npmPattern(versionPattern: String): VersionRequirement {
return MatchesNpmPattern(versionPattern)
}
/**
* @see Semver.SemverType.IVY
*/
@ILoveKafuuChinoForever
public fun ivyPattern(versionPattern: String): VersionRequirement {
return MatchesIvyPattern(versionPattern)
}
/**
* @see Semver.SemverType.COCOAPODS
*/
@ILoveKafuuChinoForever
public fun cocoapodsPattern(versionPattern: String): VersionRequirement {
return MatchesCocoapodsPattern(versionPattern)
}
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKafuuChinoForever
public fun range(
begin: Semver,
beginInclusive: Boolean,
end: Semver,
endInclusive: Boolean,
): VersionRequirement = InRange(begin, beginInclusive, end, endInclusive)
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKafuuChinoForever
public fun range(
begin: String,
beginInclusive: Boolean,
end: Semver,
endInclusive: Boolean,
): VersionRequirement = InRange(begin, beginInclusive, end, endInclusive)
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKafuuChinoForever
public fun range(
begin: Semver,
beginInclusive: Boolean,
end: String,
endInclusive: Boolean,
): VersionRequirement = InRange(begin, beginInclusive, end, endInclusive)
@ILoveKafuuChinoForever
public fun range(
begin: String,
beginInclusive: Boolean,
end: String,
endInclusive: Boolean,
): VersionRequirement = InRange(begin, beginInclusive, end, endInclusive)
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKafuuChinoForever
public operator fun Semver.rangeTo(endInclusive: Semver): VersionRequirement {
return InRange(this, true, endInclusive, true)
}
@ILoveKafuuChinoForever
public operator fun Semver.rangeTo(endInclusive: String): VersionRequirement {
return InRange(this, true, Semver(endInclusive, Semver.SemverType.LOOSE), true)
}
@ILoveKafuuChinoForever
public operator fun String.rangeTo(endInclusive: String): VersionRequirement {
return InRange(Semver(this, Semver.SemverType.LOOSE),
true,
Semver(endInclusive, Semver.SemverType.LOOSE),
true)
}
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKafuuChinoForever
public operator fun String.rangeTo(endInclusive: Semver): VersionRequirement {
return InRange(Semver(this, Semver.SemverType.LOOSE), true, endInclusive, true)
}
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKafuuChinoForever
public infix fun Semver.until(endExclusive: Semver): VersionRequirement {
return InRange(this, true, endExclusive, false)
}
@ILoveKafuuChinoForever
public infix fun Semver.until(endExclusive: String): VersionRequirement {
return InRange(this, true, Semver(endExclusive, Semver.SemverType.LOOSE), false)
}
@ILoveKafuuChinoForever
public infix fun String.until(endExclusive: String): VersionRequirement {
return InRange(Semver(this, Semver.SemverType.LOOSE),
true,
Semver(endExclusive, Semver.SemverType.LOOSE),
false)
}
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKafuuChinoForever
public infix fun String.until(endExclusive: Semver): VersionRequirement {
return InRange(Semver(this, Semver.SemverType.LOOSE), true, endExclusive, false)
}
@Suppress("SpellCheckingInspection")
@Retention(AnnotationRetention.BINARY)
@DslMarker
internal annotation class ILoveKafuuChinoForever
}
}

View File

@ -11,12 +11,12 @@
package net.mamoe.mirai.console.plugin.jvm package net.mamoe.mirai.console.plugin.jvm
import com.vdurmont.semver4j.Semver
import net.mamoe.mirai.console.compiler.common.ResolveContext import net.mamoe.mirai.console.compiler.common.ResolveContext
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.* import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.*
import net.mamoe.mirai.console.plugin.description.PluginDependency import net.mamoe.mirai.console.plugin.description.PluginDependency
import net.mamoe.mirai.console.plugin.description.PluginDescription import net.mamoe.mirai.console.plugin.description.PluginDescription
import net.mamoe.mirai.console.plugin.description.VersionRequirement import net.mamoe.mirai.console.util.SemVersion
import net.mamoe.mirai.console.util.SemVersionRangeRequirementBuilder
/** /**
* JVM 插件的描述. 通常作为 `plugin.yml` * JVM 插件的描述. 通常作为 `plugin.yml`
@ -34,6 +34,7 @@ public interface JvmPluginDescription : PluginDescription {
* 构建 [JvmPluginDescription] * 构建 [JvmPluginDescription]
* @see JvmPluginDescriptionBuilder * @see JvmPluginDescriptionBuilder
*/ */
@JvmName("create")
@JvmSynthetic @JvmSynthetic
public operator fun invoke( public operator fun invoke(
/** /**
@ -55,8 +56,7 @@ public interface JvmPluginDescription : PluginDescription {
* 构建 [JvmPluginDescription] * 构建 [JvmPluginDescription]
* @see JvmPluginDescriptionBuilder * @see JvmPluginDescriptionBuilder
*/ */
@Suppress("DEPRECATION_ERROR") @JvmName("create")
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@JvmSynthetic @JvmSynthetic
public operator fun invoke( public operator fun invoke(
/** /**
@ -66,7 +66,7 @@ public interface JvmPluginDescription : PluginDescription {
/** /**
* @see [PluginDescription.version] * @see [PluginDescription.version]
*/ */
@ResolveContext(PLUGIN_VERSION) version: Semver, @ResolveContext(PLUGIN_VERSION) version: SemVersion,
/** /**
* @see [PluginDescription.name] * @see [PluginDescription.name]
*/ */
@ -97,17 +97,14 @@ public interface JvmPluginDescription : PluginDescription {
* *
* @see [JvmPluginDescription.invoke] * @see [JvmPluginDescription.invoke]
*/ */
public class JvmPluginDescriptionBuilder public class JvmPluginDescriptionBuilder(
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
constructor(
private var id: String, private var id: String,
private var version: Semver, private var version: SemVersion,
) { ) {
@Suppress("DEPRECATION_ERROR")
public constructor( public constructor(
@ResolveContext(PLUGIN_NAME) id: String, @ResolveContext(PLUGIN_ID) id: String,
@ResolveContext(PLUGIN_VERSION) version: String, @ResolveContext(PLUGIN_VERSION) version: String,
) : this(id, Semver(version, Semver.SemverType.LOOSE)) ) : this(id, SemVersion(version))
private var name: String = id private var name: String = id
private var author: String = "" private var author: String = ""
@ -118,14 +115,12 @@ constructor(
public fun name(@ResolveContext(PLUGIN_NAME) value: String): JvmPluginDescriptionBuilder = public fun name(@ResolveContext(PLUGIN_NAME) value: String): JvmPluginDescriptionBuilder =
apply { this.name = value.trim() } apply { this.name = value.trim() }
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKuriyamaMiraiForever @ILoveKuriyamaMiraiForever
public fun version(@ResolveContext(PLUGIN_VERSION) value: String): JvmPluginDescriptionBuilder = public fun version(@ResolveContext(PLUGIN_VERSION) value: String): JvmPluginDescriptionBuilder =
apply { this.version = Semver(value, Semver.SemverType.LOOSE) } apply { this.version = SemVersion(value) }
@Deprecated("Semver 将会在 1.0-RC 被替换为 Console 自己实现的版本。请临时使用 String。", level = DeprecationLevel.ERROR)
@ILoveKuriyamaMiraiForever @ILoveKuriyamaMiraiForever
public fun version(@ResolveContext(PLUGIN_VERSION) value: Semver): JvmPluginDescriptionBuilder = public fun version(@ResolveContext(PLUGIN_VERSION) value: SemVersion): JvmPluginDescriptionBuilder =
apply { this.version = value } apply { this.version = value }
@ILoveKuriyamaMiraiForever @ILoveKuriyamaMiraiForever
@ -161,7 +156,7 @@ constructor(
public fun dependsOn( public fun dependsOn(
@ResolveContext(PLUGIN_ID) pluginId: String, @ResolveContext(PLUGIN_ID) pluginId: String,
isOptional: Boolean = false, isOptional: Boolean = false,
versionRequirement: VersionRequirement, versionRequirement: SemVersion.Requirement,
): JvmPluginDescriptionBuilder = apply { ): JvmPluginDescriptionBuilder = apply {
this.dependencies.add(PluginDependency(pluginId, versionRequirement, isOptional)) this.dependencies.add(PluginDependency(pluginId, versionRequirement, isOptional))
} }
@ -174,7 +169,7 @@ constructor(
@ILoveKuriyamaMiraiForever @ILoveKuriyamaMiraiForever
public fun dependsOn( public fun dependsOn(
@ResolveContext(PLUGIN_ID) pluginId: String, @ResolveContext(PLUGIN_ID) pluginId: String,
versionRequirement: VersionRequirement, versionRequirement: SemVersion.Requirement,
): JvmPluginDescriptionBuilder = apply { ): JvmPluginDescriptionBuilder = apply {
this.dependencies.add(PluginDependency(pluginId, versionRequirement, false)) this.dependencies.add(PluginDependency(pluginId, versionRequirement, false))
} }
@ -203,17 +198,17 @@ constructor(
* ``` * ```
* *
* @see PluginDependency * @see PluginDependency
* @see VersionRequirement.Builder * @see SemVersionRangeRequirementBuilder
*/ */
@ILoveKuriyamaMiraiForever @ILoveKuriyamaMiraiForever
public fun dependsOn( public fun dependsOn(
@ResolveContext(PLUGIN_ID) pluginId: String, @ResolveContext(PLUGIN_ID) pluginId: String,
isOptional: Boolean = false, isOptional: Boolean = false,
versionRequirement: VersionRequirement.Builder.() -> VersionRequirement, versionRequirement: SemVersionRangeRequirementBuilder.() -> SemVersion.Requirement,
): JvmPluginDescriptionBuilder = ): JvmPluginDescriptionBuilder =
apply { apply {
this.dependencies.add(PluginDependency(pluginId, this.dependencies.add(PluginDependency(pluginId,
VersionRequirement.Builder().run(versionRequirement), SemVersionRangeRequirementBuilder.run(versionRequirement),
isOptional)) isOptional))
} }
@ -236,56 +231,26 @@ constructor(
* *
* @see JvmPluginDescription * @see JvmPluginDescription
*/ */
@Deprecated( internal data class SimpleJvmPluginDescription
""" @JvmOverloads constructor(
将在 1.0-RC 删除. 请使用 JvmPluginDescription. override val name: String,
""", override val version: SemVersion,
replaceWith = ReplaceWith( override val id: String = name,
"JvmPluginDescription", override val author: String = "",
"net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription" override val info: String = "",
), override val dependencies: Set<PluginDependency> = setOf(),
level = DeprecationLevel.ERROR
)
public data class SimpleJvmPluginDescription
@Deprecated(
"""
构造器不稳定, 将在 1.0-RC 删除. 请使用 JvmPluginDescriptionBuilder.
""",
replaceWith = ReplaceWith(
"JvmPluginDescription(name, version) {}",
"net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription.Companion.invoke"
),
level = DeprecationLevel.ERROR
)
@JvmOverloads public constructor(
public override val name: String,
public override val version: Semver,
public override val id: String = name,
public override val author: String = "",
public override val info: String = "",
public override val dependencies: Set<PluginDependency> = setOf(),
) : JvmPluginDescription { ) : JvmPluginDescription {
@Deprecated(
"""
构造器不稳定, 将在 1.0-RC 删除. 请使用 JvmPluginDescriptionBuilder.
""",
replaceWith = ReplaceWith(
"JvmPluginDescription.invoke(name, version) {}",
"net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription.Companion.invoke"
),
level = DeprecationLevel.ERROR
)
@Suppress("DEPRECATION_ERROR") @Suppress("DEPRECATION_ERROR")
@JvmOverloads @JvmOverloads
public constructor( constructor(
name: String, name: String,
version: String, version: String,
id: String = name, id: String = name,
author: String = "", author: String = "",
info: String = "", info: String = "",
dependencies: Set<PluginDependency> = setOf(), dependencies: Set<PluginDependency> = setOf(),
) : this(name, Semver(version, Semver.SemverType.LOOSE), id, author, info, dependencies) ) : this(name, SemVersion(version), id, author, info, dependencies)
init { init {
require(!name.contains(':')) { "':' is forbidden in plugin name" } require(!name.contains(':')) { "':' is forbidden in plugin name" }

View File

@ -15,7 +15,7 @@ import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl
import net.mamoe.mirai.console.plugin.loader.FilePluginLoader import net.mamoe.mirai.console.plugin.loader.FilePluginLoader
/** /**
* 内建的 Jar (JVM) 插件加载器 * JVM 插件加载器
*/ */
public interface JvmPluginLoader : CoroutineScope, FilePluginLoader<JvmPlugin, JvmPluginDescription> { public interface JvmPluginLoader : CoroutineScope, FilePluginLoader<JvmPlugin, JvmPluginDescription> {
/** /**

View File

@ -61,10 +61,9 @@ public interface PluginLoader<P : Plugin, D : PluginDescription> {
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等). * @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等).
* *
* @see PluginDescription 插件描述 * @see PluginDescription 插件描述
* @see getPluginDescription receiver, 接受参数的版本.
*/ */
@Throws(PluginLoadException::class) @Throws(PluginLoadException::class)
public fun getPluginDescription(plugin: P): D // Java signature: `public D getDescription(P)` public fun getPluginDescription(plugin: P): D
/** /**
* 主动加载一个插件 (实例), 但不 [启用][enable] . 返回加载成功的主类实例 * 主动加载一个插件 (实例), 但不 [启用][enable] . 返回加载成功的主类实例

View File

@ -12,29 +12,27 @@
* @author Karlatemp <karlatemp@vip.qq.com> <https://github.com/Karlatemp> * @author Karlatemp <karlatemp@vip.qq.com> <https://github.com/Karlatemp>
*/ */
@file:Suppress("unused")
package net.mamoe.mirai.console.util package net.mamoe.mirai.console.util
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import kotlinx.serialization.builtins.serializer import kotlinx.serialization.builtins.serializer
import net.mamoe.mirai.console.compiler.common.ResolveContext
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.PLUGIN_VERSION
import net.mamoe.mirai.console.internal.data.map import net.mamoe.mirai.console.internal.data.map
import net.mamoe.mirai.console.internal.util.SemVersionInternal import net.mamoe.mirai.console.internal.util.SemVersionInternal
import net.mamoe.mirai.console.util.SemVersion.Companion.equals import net.mamoe.mirai.console.util.SemVersion.Companion.equals
import net.mamoe.mirai.console.util.SemVersion.Requirement
/** /**
* 语义化版本支持 * [语义化版本](https://semver.org/lang/zh-CN/) 支持
* *
* 在阅读此文件前, 请先阅读 https://semver.org/lang/zh-CN/ * 解析示例:
* 该文档说明了语义化版本是什么, 此文件不再过多描述
* *
* ---- * `1.0.0-M4+c25733b8` 将会解析出三个内容, mainVersion (核心版本号), [identifier] (先行版本号) [metadata] (元数据).
*
* 这是一个例子 `1.0.0-M4+c25733b8`
*
* 将会解析出三个内容, mainVersion(核心版本号), identifier(先行版本号) metadata(元数据).
*
* 对这个例子进行解析会得到
* ``` * ```
* SemVersion( * SemVersion(
* mainVersion = IntArray [1, 0, 0], * mainVersion = IntArray [1, 0, 0],
@ -43,47 +41,45 @@ import net.mamoe.mirai.console.util.SemVersion.Companion.equals
* ) * )
* ``` * ```
* 其中 identifier metadata 都是可选的. * 其中 identifier metadata 都是可选的.
* 对于核心版本号, 此实现稍微比 semver 宽松一些, 允许 x.y 的存在.
* 但是不允许 0.0.0.0 之类的存在
* *
* 对于核心版本号, 此实现稍微比 semver 宽松一些, 允许 x.y 的存在.
*
* @see Requirement
* @see SemVersion.invoke
*/ */
@Serializable(with = SemVersion.SemVersionAsStringSerializer::class) @Serializable(with = SemVersion.SemVersionAsStringSerializer::class)
public data class SemVersion internal constructor( public data class SemVersion
/**
* @see SemVersion.invoke 字符串解析
*/
internal constructor(
/** 核心版本号, 由主版本号, 次版本号和修订号组成, 其中修订号不一定存在 */ /** 核心版本号, 由主版本号, 次版本号和修订号组成, 其中修订号不一定存在 */
public val mainVersion: IntArray, public val mainVersion: IntArray,
/** 先行版本号识别符 */ /** 先行版本号识别符 */
public val identifier: String? = null, public val identifier: String? = null,
/** 版本号元数据, 不参与版本号对比([compareTo]), 但是参与版本号严格对比([equals]) */ /** 版本号元数据, 不参与版本号对比([compareTo]), 但是参与版本号严格对比([equals]) */
public val metadata: String? = null public val metadata: String? = null,
) : Comparable<SemVersion> { ) : Comparable<SemVersion> {
/** /**
* 一条依赖规则 * 一条依赖规则
* @see [parseRangeRequirement] * @see [parseRangeRequirement]
*/ */
public fun interface RangeRequirement { public interface Requirement {
/** 在 [version] 满足此要求时返回 true */ /** 在 [version] 满足此要求时返回 true */
public fun check(version: SemVersion): Boolean public fun test(version: SemVersion): Boolean
} }
public object SemVersionAsStringSerializer : KSerializer<SemVersion> by String.serializer().map( public object SemVersionAsStringSerializer : KSerializer<SemVersion> by String.serializer().map(
serializer = { it.toString() }, serializer = { it.toString() },
deserializer = { parse(it) } deserializer = { SemVersion(it) }
) )
public companion object { public companion object {
private val SEM_VERSION_REGEX =
"""^(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$""".toRegex()
/** 解析核心版本号, eg: `1.0.0` -> IntArray[1, 0, 0] */
@JvmStatic
private fun String.parseMainVersion(): IntArray =
split('.').map { it.toInt() }.toIntArray()
/** /**
* 解析一个版本号, 将会返回一个 [SemVersion], * 解析一个版本号, 将会返回一个 [SemVersion],
* 如果发生解析错误将会抛出一个 [IllegalArgumentException] 或者 [NumberFormatException] * 如果发生解析错误将会抛出一个 [IllegalArgumentException] 或者 [NumberFormatException]
* *
* 对于版本号的组成, 我们有以下规定: * 对于版本号的组成, 有以下规定:
* - 必须包含主版本号和次版本号 * - 必须包含主版本号和次版本号
* - 存在 先行版本号 的时候 先行版本号 不能为空 * - 存在 先行版本号 的时候 先行版本号 不能为空
* - 存在 元数据 的时候 元数据 不能为空 * - 存在 元数据 的时候 元数据 不能为空
@ -100,45 +96,8 @@ public data class SemVersion internal constructor(
*/ */
@Throws(IllegalArgumentException::class, NumberFormatException::class) @Throws(IllegalArgumentException::class, NumberFormatException::class)
@JvmStatic @JvmStatic
public fun parse(version: String): SemVersion { @JvmName("parse")
if (!SEM_VERSION_REGEX.matches(version)) { public operator fun invoke(@ResolveContext(PLUGIN_VERSION) version: String): SemVersion = SemVersionInternal.parse(version)
throw IllegalArgumentException("`$version` not a valid version")
}
var mainVersionEnd: Int = 0
kotlin.run {
val iterator = version.iterator()
while (iterator.hasNext()) {
val next = iterator.next()
if (next == '-' || next == '+') {
break
}
mainVersionEnd++
}
}
var identifier: String? = null
var metadata: String? = null
if (mainVersionEnd != version.length) {
when (version[mainVersionEnd]) {
'-' -> {
val metadataSplitter = version.indexOf('+', startIndex = mainVersionEnd)
if (metadataSplitter == -1) {
identifier = version.substring(mainVersionEnd + 1)
} else {
identifier = version.substring(mainVersionEnd + 1, metadataSplitter)
metadata = version.substring(metadataSplitter + 1)
}
}
'+' -> {
metadata = version.substring(mainVersionEnd + 1)
}
}
}
return SemVersion(
mainVersion = version.substring(0, mainVersionEnd).parseMainVersion(),
identifier = identifier,
metadata = metadata
)
}
/** /**
* 解析一条依赖需求描述, 在无法解析的时候抛出 [IllegalArgumentException] * 解析一条依赖需求描述, 在无法解析的时候抛出 [IllegalArgumentException]
@ -154,7 +113,7 @@ public data class SemVersion internal constructor(
* - `< 1.0.0-RC` 要求 1.0.0-RC 之前的版本, 不能是 1.0.0-RC * - `< 1.0.0-RC` 要求 1.0.0-RC 之前的版本, 不能是 1.0.0-RC
* - `<= 1.0.0-RC` 要求 1.0.0-RC 或之前的版本, 可以是 1.0.0-RC * - `<= 1.0.0-RC` 要求 1.0.0-RC 或之前的版本, 可以是 1.0.0-RC
* *
* 对于多个规则, 也允许使用 `||` 拼接在一起. * 对于多个规则, 也允许使用 `||` 拼接.
* 例如: * 例如:
* - `1.x || 2.x || 3.0.0` * - `1.x || 2.x || 3.0.0`
* - `<= 0.5.3 || >= 1.0.0` * - `<= 0.5.3 || >= 1.0.0`
@ -165,49 +124,47 @@ public data class SemVersion internal constructor(
*/ */
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
@JvmStatic @JvmStatic
public fun parseRangeRequirement(requirement: String): RangeRequirement { public fun parseRangeRequirement(requirement: String): Requirement =
return SemVersionInternal.parseRangeRequirement(requirement) SemVersionInternal.parseRangeRequirement(requirement)
}
/** @see [RangeRequirement.check] */ /** @see [Requirement.test] */
@JvmStatic @JvmStatic
public fun RangeRequirement.check(version: String): Boolean = check(parse(version)) public fun Requirement.test(@ResolveContext(PLUGIN_VERSION) version: String): Boolean = test(invoke(version))
/** /**
* 当满足 [requirement] 时返回 true, 否则返回 false * 当满足 [requirement] 时返回 true, 否则返回 false
*/ */
@JvmStatic @JvmStatic
public fun SemVersion.satisfies(requirement: RangeRequirement): Boolean = requirement.check(this) public fun SemVersion.satisfies(requirement: Requirement): Boolean = requirement.test(this)
/** for Kotlin only */ /** for Kotlin only */
@JvmStatic @JvmStatic
@JvmSynthetic @JvmSynthetic
public operator fun RangeRequirement.contains(version: SemVersion): Boolean = check(version) public operator fun Requirement.contains(version: SemVersion): Boolean = test(version)
/** for Kotlin only */ /** for Kotlin only */
@JvmStatic @JvmStatic
@JvmSynthetic @JvmSynthetic
public operator fun RangeRequirement.contains(version: String): Boolean = check(version) public operator fun Requirement.contains(@ResolveContext(PLUGIN_VERSION) version: String): Boolean = test(version)
} }
@Transient @Transient
private var toString: String? = null // For cache. private val toString: String by lazy(LazyThreadSafetyMode.NONE) {
override fun toString(): String { buildString {
return toString ?: kotlin.run { mainVersion.joinTo(this, ".")
buildString { identifier?.let { identifier ->
mainVersion.joinTo(this, ".") append('-')
identifier?.let { identifier -> append(identifier)
append('-') }
append(identifier) metadata?.let { metadata ->
} append('+')
metadata?.let { metadata -> append(metadata)
append('+') }
append(metadata)
}
}.also { toString = it }
} }
} }
override fun toString(): String = toString
/** /**
* [SemVersion] 转为 Kotlin data class 风格的 [String] * [SemVersion] 转为 Kotlin data class 风格的 [String]
*/ */
@ -237,6 +194,6 @@ public data class SemVersion internal constructor(
* if it's greater than [other]. * if it's greater than [other].
*/ */
public override operator fun compareTo(other: SemVersion): Int { public override operator fun compareTo(other: SemVersion): Int {
return SemVersionInternal.run { compareInternal(other) } return SemVersionInternal.run { compareInternal(this@SemVersion, other) }
} }
} }

View File

@ -0,0 +1,90 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*
*/
package net.mamoe.mirai.console.util
/**
* 构造 [SemVersion.Requirement] DSL
*/
public object SemVersionRangeRequirementBuilder {
/** @see [SemVersion.parseRangeRequirement] */
@ILoveHim188moeForever
public fun parse(rule: String): SemVersion.Requirement = SemVersion.parseRangeRequirement(rule)
@ILoveHim188moeForever
public infix fun SemVersion.Requirement.or(other: SemVersion.Requirement): SemVersion.Requirement {
return object : SemVersion.Requirement {
override fun test(version: SemVersion): Boolean {
return this@or.test(version) || other.test(version)
}
override fun toString(): String {
return "(${this@or}) or ($other)"
}
}
}
@ILoveHim188moeForever
public infix fun String.or(other: String): SemVersion.Requirement = parse(this) or parse(other)
@ILoveHim188moeForever
public infix fun SemVersion.Requirement.or(other: String): SemVersion.Requirement = or(parse(other))
@ILoveHim188moeForever
public infix fun String.or(other: SemVersion.Requirement): SemVersion.Requirement = parse(this) or other
@ILoveHim188moeForever
public infix fun SemVersion.Requirement.and(other: SemVersion.Requirement): SemVersion.Requirement {
return object : SemVersion.Requirement {
override fun test(version: SemVersion): Boolean {
return this@and.test(version) && other.test(version)
}
override fun toString(): String {
return "(${this@and}) or ($other)"
}
}
}
@ILoveHim188moeForever
public infix fun String.and(other: String): SemVersion.Requirement = parse(this) and parse(other)
@ILoveHim188moeForever
public infix fun SemVersion.Requirement.and(other: String): SemVersion.Requirement = and(parse(other))
@ILoveHim188moeForever
public infix fun String.and(other: SemVersion.Requirement): SemVersion.Requirement = parse(this) and other
@Suppress("NOTHING_TO_INLINE")
@ILoveHim188moeForever
public inline fun custom(rule: SemVersion.Requirement): SemVersion.Requirement = rule
/**
* 标注一个 [SemVersionRangeRequirementBuilder] DSL
*/
@Suppress("SpellCheckingInspection")
@Retention(AnnotationRetention.BINARY)
@DslMarker
internal annotation class ILoveHim188moeForever
/** [SemVersionRangeRequirementBuilder] 的使用示例 */
@Suppress("unused")
private class ExampleOfBuilder {
val e1 = SemVersionRangeRequirementBuilder.run {
"1.0.0" or "1.1.5"
}
val e2 = SemVersionRangeRequirementBuilder.run {
parse("> 1.0.0") and parse("< 1.2.3")
}
val e3 = SemVersionRangeRequirementBuilder.run {
("> 1.0.0" and "< 1.2.3") or "2.0.0"
}
}
}

View File

@ -9,7 +9,6 @@
package net.mamoe.mirai.console package net.mamoe.mirai.console
import com.vdurmont.semver4j.Semver
import kotlinx.coroutines.* import kotlinx.coroutines.*
import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
import net.mamoe.mirai.console.command.CommandManager import net.mamoe.mirai.console.command.CommandManager
@ -20,6 +19,7 @@ import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.ConsoleInput import net.mamoe.mirai.console.util.ConsoleInput
import net.mamoe.mirai.console.util.ConsoleInternalApi import net.mamoe.mirai.console.util.ConsoleInternalApi
import net.mamoe.mirai.console.util.SemVersion
import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.LoginSolver import net.mamoe.mirai.utils.LoginSolver
@ -43,8 +43,8 @@ fun initTestEnvironment() {
get() = "Test" get() = "Test"
override val vendor: String override val vendor: String
get() = "Test" get() = "Test"
override val version: Semver override val version: SemVersion
get() = Semver("1.0.0") get() = SemVersion("1.0.0")
} }
override val builtInPluginLoaders: List<Lazy<PluginLoader<*, *>>> = listOf(lazy { JvmPluginLoader }) override val builtInPluginLoaders: List<Lazy<PluginLoader<*, *>>> = listOf(lazy { JvmPluginLoader })

View File

@ -14,13 +14,13 @@
package net.mamoe.mirai.console.util package net.mamoe.mirai.console.util
import net.mamoe.mirai.console.util.SemVersion.Companion.check import net.mamoe.mirai.console.util.SemVersion.Companion.test
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
internal class TestSemVersion { internal class TestSemVersion {
@Test @Test
internal fun testCompare() { internal fun testCompare() {
fun String.sem(): SemVersion = SemVersion.parse(this) fun String.sem(): SemVersion = SemVersion.invoke(this)
assert("1.0".sem() < "1.0.1".sem()) assert("1.0".sem() < "1.0.1".sem())
assert("1.0.0".sem() == "1.0".sem()) assert("1.0.0".sem() == "1.0".sem())
assert("1.1".sem() > "1.0.0".sem()) assert("1.1".sem() > "1.0.0".sem())
@ -43,13 +43,13 @@ internal class TestSemVersion {
@Test @Test
internal fun testRequirement() { internal fun testRequirement() {
fun SemVersion.RangeRequirement.assert(version: String): SemVersion.RangeRequirement { fun SemVersion.Requirement.assert(version: String): SemVersion.Requirement {
assert(check(version)) { version } assert(test(version)) { version }
return this return this
} }
fun SemVersion.RangeRequirement.assertFalse(version: String): SemVersion.RangeRequirement { fun SemVersion.Requirement.assertFalse(version: String): SemVersion.Requirement {
assert(!check(version)) { version } assert(!test(version)) { version }
return this return this
} }
SemVersion.parseRangeRequirement("1.0") SemVersion.parseRangeRequirement("1.0")
@ -85,12 +85,12 @@ internal class TestSemVersion {
} }
private fun String.check() { private fun String.check() {
val sem = SemVersion.parse(this) val sem = SemVersion.invoke(this)
assert(this == sem.toString()) { "$this != $sem" } assert(this == sem.toString()) { "$this != $sem" }
} }
private fun String.checkInvalid() { private fun String.checkInvalid() {
kotlin.runCatching { SemVersion.parse(this) } kotlin.runCatching { SemVersion.invoke(this) }
.onSuccess { assert(false) { "$this not a invalid sem-version" } } .onSuccess { assert(false) { "$this not a invalid sem-version" } }
} }

View File

@ -26,9 +26,22 @@ fun DependencyHandler.compileAndTestRuntime(any: Any) {
fun DependencyHandler.smartApi( fun DependencyHandler.smartApi(
dependencyNotation: String dependencyNotation: String
): ExternalModuleDependency {
return smart("api", dependencyNotation)
}
fun DependencyHandler.smartImplementation(
dependencyNotation: String
): ExternalModuleDependency {
return smart("implementation", dependencyNotation)
}
private fun DependencyHandler.smart(
configuration: String,
dependencyNotation: String
): ExternalModuleDependency { ): ExternalModuleDependency {
return addDependencyTo( return addDependencyTo(
this, "api", dependencyNotation this, configuration, dependencyNotation
) { ) {
fun exclude(group: String, module: String) { fun exclude(group: String, module: String) {
exclude(mapOf( exclude(mapOf(

View File

@ -1,2 +1,32 @@
# Mirai Console - Contributing # Mirai Console - Contributing
感谢你来到这里,感谢你对 Mirai Console 做的一切贡献。
## 开发 Mirai Console
### 模块
Mirai Console 项目由四个模块组成后端前端Gradle 插件Intellij 插件。
```
/
|--- backend 后端
| |--- codegen 后端代码生成工具
| `--- mirai-console 后端主模块, 发布为 net.mamoe:mirai-console
|--- buildSrc 项目构建
|--- frontend 前端
| `--- mirai-console-terminal 终端前端,发布为 net.mamoe:mirai-console-terminal
`--- tools 开发工具
|--- compiler-common 编译器通用模块
|--- gradle-plugin Gradle 插件,发布为 net.mamoe.mirai-console
`--- intellij-plugin IntelliJ 平台 IDE 插件,发布为 Mirai Console
```
请前往各模块内的 README.md 查看详细说明。
### 构建
```shell script
gradlew build
```
首次加载和构建 mirai-console 项目可能要花费数小时时间。

View File

@ -23,7 +23,6 @@
package net.mamoe.mirai.console.terminal package net.mamoe.mirai.console.terminal
import com.vdurmont.semver4j.Semver
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineName
@ -39,10 +38,7 @@ import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.console.terminal.ConsoleInputImpl.requestInput import net.mamoe.mirai.console.terminal.ConsoleInputImpl.requestInput
import net.mamoe.mirai.console.terminal.noconsole.AllEmptyLineReader import net.mamoe.mirai.console.terminal.noconsole.AllEmptyLineReader
import net.mamoe.mirai.console.terminal.noconsole.NoConsole import net.mamoe.mirai.console.terminal.noconsole.NoConsole
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.*
import net.mamoe.mirai.console.util.ConsoleInput
import net.mamoe.mirai.console.util.ConsoleInternalApi
import net.mamoe.mirai.console.util.NamedSupervisorJob
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import org.fusesource.jansi.Ansi import org.fusesource.jansi.Ansi
import org.jline.reader.LineReader import org.jline.reader.LineReader
@ -155,7 +151,7 @@ val terminal: Terminal = run {
private object ConsoleFrontEndDescImpl : MiraiConsoleFrontEndDescription { private object ConsoleFrontEndDescImpl : MiraiConsoleFrontEndDescription {
override val name: String get() = "Terminal" override val name: String get() = "Terminal"
override val vendor: String get() = "Mamoe Technologies" override val vendor: String get() = "Mamoe Technologies"
override val version: Semver = net.mamoe.mirai.console.internal.MiraiConsoleBuildConstants.version override val version: SemVersion = net.mamoe.mirai.console.internal.MiraiConsoleBuildConstants.version
} }
private val ANSI_RESET = Ansi().reset().toString() private val ANSI_RESET = Ansi().reset().toString()