mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-02 05:00:35 +08:00
Add String.parserMiraiCode
, close #264
This commit is contained in:
parent
0af6639e9d
commit
094bd72efb
build.gradle.kts
mirai-serialization
build.gradle.kts
settings.gradlesrc
commonMain/kotlin/net/mamoe/mirai/message/code
commonTest/kotlin/net/mamoe/mirai/message/code
@ -68,8 +68,9 @@ subprojects {
|
||||
afterEvaluate {
|
||||
apply(plugin = "com.github.johnrengelman.shadow")
|
||||
val kotlin =
|
||||
(this as ExtensionAware).extensions.getByName("kotlin") as? org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
?: return@afterEvaluate
|
||||
runCatching {
|
||||
(this as ExtensionAware).extensions.getByName("kotlin") as? org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
}.getOrNull() ?: return@afterEvaluate
|
||||
|
||||
val shadowJvmJar by tasks.creating(com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar::class) {
|
||||
group = "mirai"
|
||||
|
95
mirai-serialization/build.gradle.kts
Normal file
95
mirai-serialization/build.gradle.kts
Normal file
@ -0,0 +1,95 @@
|
||||
@file:Suppress("UNUSED_VARIABLE")
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
id("kotlinx-atomicfu")
|
||||
kotlin("plugin.serialization")
|
||||
id("signing")
|
||||
`maven-publish`
|
||||
id("com.jfrog.bintray") version Versions.Publishing.bintray
|
||||
}
|
||||
|
||||
description = "Mirai serialization module"
|
||||
|
||||
val isAndroidSDKAvailable: Boolean by project
|
||||
|
||||
kotlin {
|
||||
if (isAndroidSDKAvailable) {
|
||||
apply(from = rootProject.file("gradle/android.gradle"))
|
||||
android("android") {
|
||||
publishAllLibraryVariants()
|
||||
}
|
||||
} else {
|
||||
println(
|
||||
"""Android SDK 可能未安装.
|
||||
$name 的 Android 目标编译将不会进行.
|
||||
这不会影响 Android 以外的平台的编译.
|
||||
""".trimIndent()
|
||||
)
|
||||
println(
|
||||
"""Android SDK might not be installed.
|
||||
Android target of $name will not be compiled.
|
||||
It does no influence on the compilation of other platforms.
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
jvm()
|
||||
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings.enableLanguageFeature("InlineClasses")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiExperimentalAPI")
|
||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.LowLevelAPI")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.time.ExperimentalTime")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
|
||||
languageSettings.progressiveMode = true
|
||||
}
|
||||
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
api(kotlin("stdlib"))
|
||||
api(project(":mirai-core"))
|
||||
}
|
||||
}
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
api(kotlin("test-annotations-common"))
|
||||
api(kotlin("test-common"))
|
||||
}
|
||||
}
|
||||
|
||||
if (isAndroidSDKAvailable) {
|
||||
val androidMain by getting {
|
||||
dependencies {
|
||||
}
|
||||
}
|
||||
|
||||
val androidTest by getting {
|
||||
dependencies {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE
|
||||
}
|
||||
}
|
||||
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
implementation(kotlin("test-junit"))
|
||||
|
||||
runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply(from = rootProject.file("gradle/publish.gradle"))
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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:JvmMultifileClass
|
||||
@file:JvmName("MiraiCode")
|
||||
@file:Suppress("INVISIBLE_MEMBER")
|
||||
|
||||
package net.mamoe.mirai.message.code
|
||||
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.SinceMirai
|
||||
import kotlin.jvm.JvmMultifileClass
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
@Suppress("RegExpRedundantEscape") // required on android
|
||||
internal val codeRegex = Regex("""(?:\[mirai:([^\]]*)?:(.*?)?\])|(?:\[mirai:(.*?)\])""")
|
||||
|
||||
/**
|
||||
* 解析形如 "[mirai:]" 的 mirai 码, 即 [Message.toString] 返回的内容.
|
||||
*/
|
||||
@SinceMirai("1.1.0")
|
||||
fun String.parseMiraiCode(): MessageChain = buildMessageChain {
|
||||
forEachMiraiCode { origin, name, args ->
|
||||
if (name == null) {
|
||||
add(origin.toMessage())
|
||||
return@forEachMiraiCode
|
||||
}
|
||||
val parser = MiraiCodeParsers[name] ?: kotlin.run {
|
||||
add(origin.toMessage())
|
||||
return@forEachMiraiCode
|
||||
}
|
||||
parser.argsRegex.matchEntire(args)
|
||||
?.destructured
|
||||
?.let {
|
||||
parser.runCatching {
|
||||
mapper(it)
|
||||
}.getOrNull()
|
||||
}
|
||||
?.let(::add)
|
||||
?: add(origin.toMessage())
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun String.forEachMiraiCode(crossinline block: (origin: String, name: String?, args: String) -> Unit) {
|
||||
var lastIndex = 0
|
||||
for (result in codeRegex.findAll(this)) {
|
||||
if (result.range.first != lastIndex) {
|
||||
// skipped string
|
||||
block(result.value, null, substring(lastIndex, result.range.first))
|
||||
}
|
||||
|
||||
lastIndex = result.range.last + 1
|
||||
if (result.groups[3] != null) {
|
||||
// no param
|
||||
block(result.value, result.groups[3]!!.value, "")
|
||||
} else block(result.value, result.groups[1]!!.value, result.groups[2]?.value ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
internal object MiraiCodeParsers : Map<String, MiraiCodeParser> by mapOf(
|
||||
"at" to MiraiCodeParser(Regex("""(\d*),(.*)""")) { (target, display) ->
|
||||
At._lowLevelConstructAtInstance(target.toLong(), display)
|
||||
},
|
||||
"atall" to MiraiCodeParser(Regex("")) {
|
||||
AtAll
|
||||
},
|
||||
"poke" to MiraiCodeParser(Regex("(.*)?,(\\d*),(-?\\d*)")) { (name, type, id) ->
|
||||
PokeMessage(name, type.toInt(), id.toInt())
|
||||
},
|
||||
"vipface" to MiraiCodeParser(Regex("""\((\d*),(.*)\),(\d*)""")) { (id, name, count) ->
|
||||
VipFace(VipFace.Kind(id.toInt(), name), count.toInt())
|
||||
},
|
||||
"face" to MiraiCodeParser(Regex("""(\d*)""")) { (id) ->
|
||||
Face(id.toInt())
|
||||
},
|
||||
"image" to MiraiCodeParser(Regex("""(.*)""")) { (id) ->
|
||||
Image(id)
|
||||
},
|
||||
"flash" to MiraiCodeParser(Regex("""(.*)""")) { (id) ->
|
||||
Image(id).flash()
|
||||
}
|
||||
)
|
||||
|
||||
/*
|
||||
internal object MiraiCodeParsers2 : Map<String, (args: String) -> Message?> by mapOf(
|
||||
"at" to l@{ args ->
|
||||
val group = args.split(',')
|
||||
if (group.size != 2) return@l null
|
||||
val target = group[0].toLongOrNull() ?: return@l null
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
At(target, group[1])
|
||||
},
|
||||
"atall" to l@{
|
||||
AtAll
|
||||
},
|
||||
"poke" to l@{ args ->
|
||||
val group = args.split(',')
|
||||
if (group.size != 2) return@l null
|
||||
val type = group[1].toIntOrNull() ?: return@l null
|
||||
val id = group[2].toIntOrNull() ?: return@l null
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
PokeMessage(group[0], type, id)
|
||||
},
|
||||
"vipface" to l@{ args ->
|
||||
val group = args.split(',')
|
||||
if (group.size != 2) return@l null
|
||||
val type = group[1].toIntOrNull() ?: return@l null
|
||||
val id = group[2].toIntOrNull() ?: return@l null
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
PokeMessage(group[0], type, id)
|
||||
}
|
||||
)*/
|
||||
|
||||
internal class MiraiCodeParser(
|
||||
val argsRegex: Regex,
|
||||
val mapper: MiraiCodeParser.(MatchResult.Destructured) -> Message?
|
||||
)
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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")
|
||||
|
||||
package net.mamoe.mirai.message.code
|
||||
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.message.data.VipFace.Companion.AiXin
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class MiraiCodeParserTest {
|
||||
|
||||
@Test
|
||||
fun testSplit() {
|
||||
val str = "sadvass][ [mirai:at:1,test]]vdsavs [mirai:atall]"
|
||||
assertEquals(str, str.parseMiraiCode().toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun at() {
|
||||
val str = "[mirai:at:1,test]"
|
||||
assertEquals(At._lowLevelConstructAtInstance(1, "test"), str.parseMiraiCode()[0])
|
||||
|
||||
fun testPlain(str: String) {
|
||||
assertEquals(str, (str.parseMiraiCode()[0] as PlainText).content)
|
||||
}
|
||||
testPlain("[mirai:at:bad,test]")
|
||||
testPlain("[mirai:at:bad]")
|
||||
testPlain("[mirai:at:]")
|
||||
testPlain("[mirai:at]")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun atAll() {
|
||||
val str = "[mirai:atall]"
|
||||
assertEquals(AtAll, str.parseMiraiCode()[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun poke() {
|
||||
assertEquals(PokeMessage.Poke, PokeMessage.Poke.toString().parseMiraiCode()[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun vipFace() {
|
||||
val instance = VipFace(AiXin, 1)
|
||||
assertEquals(instance, instance.toString().parseMiraiCode()[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun image() {
|
||||
val instance = Image("{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai")
|
||||
assertEquals(instance, instance.toString().parseMiraiCode()[0])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun flash() {
|
||||
val instance = Image("{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai").flash()
|
||||
assertEquals(instance, instance.toString().parseMiraiCode()[0])
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ rootProject.name = 'mirai'
|
||||
|
||||
include(':mirai-core')
|
||||
include(':mirai-core-qqandroid')
|
||||
include(':mirai-serialization')
|
||||
//include(':compatibility-validator') // THIS WILL CAUSE A DEPENDENCY RESOLUTION BUG
|
||||
//include(':java-compatibility-validator')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user