diff --git a/mirai-serialization/src/commonMain/kotlin/net/mamoe/mirai/message/code/MiraiCode.kt b/mirai-serialization/src/commonMain/kotlin/net/mamoe/mirai/message/code/MiraiCode.kt index 202f6c461..14ebac393 100644 --- a/mirai-serialization/src/commonMain/kotlin/net/mamoe/mirai/message/code/MiraiCode.kt +++ b/mirai-serialization/src/commonMain/kotlin/net/mamoe/mirai/message/code/MiraiCode.kt @@ -9,115 +9,28 @@ @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.message.code.internal.parseMiraiCodeImpl +import net.mamoe.mirai.message.data.Message +import net.mamoe.mirai.message.data.MessageChain 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()) - } -} +fun String.parseMiraiCode(): MessageChain = parseMiraiCodeImpl() -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(substring(lastIndex, result.range.first), null, "") - } - - 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? -) \ No newline at end of file +/** + * 将消息转为 'mirai 码' 表示形式. + * + * 各类型消息对应的格式: + * + * + */ +@SinceMirai("1.1.0") +fun Message.toMiraiCode(): String = this.toString() \ No newline at end of file diff --git a/mirai-serialization/src/commonMain/kotlin/net/mamoe/mirai/message/code/internal/impl.kt b/mirai-serialization/src/commonMain/kotlin/net/mamoe/mirai/message/code/internal/impl.kt new file mode 100644 index 000000000..786edf4c3 --- /dev/null +++ b/mirai-serialization/src/commonMain/kotlin/net/mamoe/mirai/message/code/internal/impl.kt @@ -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("INVISIBLE_MEMBER") + +package net.mamoe.mirai.message.code.internal + +import net.mamoe.mirai.message.data.* + + +@Suppress("RegExpRedundantEscape") // required on android +internal val codeRegex = Regex("""(?:\[mirai:([^\]]*)?:(.*?)?\])|(?:\[mirai:([^:]+)\])""") + +internal fun String.parseMiraiCodeImpl(): 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()) + } +} + +internal 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(substring(lastIndex, result.range.first), null, "") + } + + 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? +) \ No newline at end of file