Better API visibility

This commit is contained in:
Him188 2020-03-01 15:26:46 +08:00
parent f2843df162
commit 83faf81fb2
3 changed files with 119 additions and 87 deletions

View File

@ -10,6 +10,7 @@
package net.mamoe.mirai.qqandroid.message
import io.ktor.utils.io.core.*
import net.mamoe.mirai.LowLevelAPI
import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
@ -330,14 +331,13 @@ internal class NotOnlineImageFromServer(
internal fun MsgComm.Msg.toMessageChain(): MessageChain {
val elements = this.msgBody.richText.elems
val message = MessageChainBuilder(elements.size + 1)
message.add(MessageSourceFromMsg(delegate = this))
elements.joinToMessageChain(message)
return message.asMessageChain()
return buildMessageChain(elements.size + 1) {
+MessageSourceFromMsg(delegate = this@toMessageChain)
elements.joinToMessageChain(this)
}.removeAtAfterQuoteReply().asMessageChain()
}
// These two functions are not the same.
// These two functions are not identical, dont combine.
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain {
val elements = this.elems!!
@ -345,11 +345,25 @@ internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain {
return buildMessageChain(elements.size + 1) {
+MessageSourceFromServer(delegate = this@toMessageChain)
elements.joinToMessageChain(this)
}.removeAtAfterQuoteReply().asMessageChain()
}
private fun MessageChain.removeAtAfterQuoteReply(): List<Message> {
var last: Message? = null
return this.filterNot { message: Message ->
if (message is At) { // 筛除因 QuoteReply 导致的多余的 At
if (last != null || last !is QuoteReply) {
return@filterNot true
}
} else if (message is MessageContent) {
return@filterNot true
}
last = message
return@filterNot false
}
}
@UseExperimental(MiraiInternalAPI::class, ExperimentalUnsignedTypes::class, MiraiDebugAPI::class)
@UseExperimental(MiraiInternalAPI::class, ExperimentalUnsignedTypes::class, MiraiDebugAPI::class, LowLevelAPI::class)
internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilder) {
this.forEach {
when {
@ -372,7 +386,7 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilde
if (id == 0L) {
message.add(AtAll)
} else {
message.add(At(id, it.text.str))
message.add(At._lowLevelConstructAtInstance(id, it.text.str))
}
}
}

View File

@ -14,11 +14,12 @@
package net.mamoe.mirai.message.data
import net.mamoe.mirai.LowLevelAPI
import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.contact.nameCardOrNick
import net.mamoe.mirai.utils.MiraiInternalAPI
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic
/**
@ -27,13 +28,24 @@ import kotlin.jvm.JvmName
* @see AtAll 全体成员
*/
class At
@MiraiInternalAPI constructor(val target: Long, val display: String) : Message, MessageContent {
@UseExperimental(MiraiInternalAPI::class)
private constructor(val target: Long, val display: String) : Message, MessageContent {
/**
* 构造一个 [At] 实例. 这是唯一的公开的构造方式.
*/
constructor(member: Member) : this(member.id, "@${member.nameCardOrNick}")
override fun toString(): String = display
companion object Key : Message.Key<At>
companion object Key : Message.Key<At> {
/**
* 构造一个 [At], 仅供内部使用, 否则可能造成消息无法发出的问题.
*/
@Suppress("FunctionName")
@JvmStatic
@LowLevelAPI
fun _lowLevelConstructAtInstance(target: Long, display: String): At = At(target, display)
}
// 自动为消息补充 " "

View File

@ -9,12 +9,13 @@
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
@file:Suppress("unused")
@file:Suppress("unused", "NOTHING_TO_INLINE")
package net.mamoe.mirai.message.data
import net.mamoe.mirai.message.data.NullMessageChain.equals
import net.mamoe.mirai.message.data.NullMessageChain.toString
import net.mamoe.mirai.utils.MiraiInternalAPI
import kotlin.js.JsName
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
@ -33,6 +34,8 @@ import kotlin.reflect.KProperty
* @see toChain 将单个 [Message] 转换为 [MessageChain]
* @see asMessageChain [Iterable] [Sequence] 委托为 [MessageChain]
*
* @see foreachContent 遍历内容
*
* @see orNull 属性委托扩展
* @see orElse 属性委托扩展
* @see getValue 属性委托扩展
@ -56,6 +59,18 @@ interface MessageChain : Message, Iterable<SingleMessage> {
* @param key 由各个类型消息的伴生对象持有. [PlainText.Key]
*/
fun <M : Message> getOrNull(key: Message.Key<M>): M? = firstOrNull(key)
/**
* 遍历每一个有内容的消息, [At], [AtAll], [PlainText], [Image], [Face], [XMLMessage].
* 仅供 `Java` 使用
*/
@JsName("forEachContent")
@JvmName("forEachContent")
@Suppress("FunctionName")
@MiraiInternalAPI
fun `__forEachContent for Java__`(block: (Message) -> Unit) {
this.foreachContent(block)
}
}
// region accessors
@ -64,16 +79,8 @@ interface MessageChain : Message, Iterable<SingleMessage> {
* 遍历每一个有内容的消息, [At], [AtAll], [PlainText], [Image], [Face], [XMLMessage]
*/
inline fun MessageChain.foreachContent(block: (Message) -> Unit) {
var last: Message? = null
this.forEach { message: Message ->
if (message is At) { // 筛除因 QuoteReply 导致的多余的 At
if (last != null || last !is QuoteReply) {
block(message)
}
} else if (message is MessageContent) {
block(message)
}
last = message
this.forEach {
if (it !is MessageMetadata) block(it)
}
}
@ -138,6 +145,7 @@ fun <M : Message> MessageChain.any(key: Message.Key<M>): Boolean = firstOrNull(k
* val at: At by message
* val image: Image by message
*/
@JvmSynthetic
inline operator fun <reified T : Message> MessageChain.getValue(thisRef: Any?, property: KProperty<*>): T = this.first()
/**
@ -161,6 +169,7 @@ inline class OrNullDelegate<out R : Message?>(private val value: Any?) {
* @see orNull 提供一个不存在则 null 的委托
* @see orElse 提供一个不存在则使用默认值的委托
*/
@JvmSynthetic
inline fun <reified T : Message> MessageChain.orNull(): OrNullDelegate<T?> = OrNullDelegate(this.firstOrNull<T>())
/**
@ -175,6 +184,7 @@ inline fun <reified T : Message> MessageChain.orNull(): OrNullDelegate<T?> = OrN
* ```
* @see orNull 提供一个不存在则 null 的委托
*/
@JvmSynthetic
inline fun <reified T : Message?> MessageChain.orElse(
lazyDefault: () -> T
): OrNullDelegate<T> =
@ -184,88 +194,61 @@ inline fun <reified T : Message?> MessageChain.orElse(
// region converters
/**
* 返回 [EmptyMessageChain]
*/
@JvmName("newChain")
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(): MessageChain = EmptyMessageChain
/**
* 构造 [MessageChain]
* 若仅提供一个参数, 请考虑使用 [Message.toChain] 以优化性能
*/
@JvmName("newChain")
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(vararg messages: Message): MessageChain =
if (messages.isEmpty()) EmptyMessageChain
else MessageChainImplBySequence(messages.asSequence().flatten())
/**
* 构造 [MessageChain] 的快速途径 ( [Array] 创建)
* 若仅提供一个参数, 请考虑使用 [Message.toChain] 以优化性能
*/
@JvmName("newChain")
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(message: Message): MessageChain =
when (message) {
is SingleMessage -> SingleMessageChainImpl(message)
else -> MessageChainImplBySequence(message.flatten())
}
/**
* 构造 [MessageChain]
*/
@JvmName("newChain")
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(messages: Iterable<Message>): MessageChain =
MessageChainImplBySequence(messages.flatten())
/**
* [扁平化][flatten] [messages] 然后构造 [MessageChain]
*/
@JvmName("newChain")
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(messages: List<Message>): MessageChain =
MessageChainImplByIterable(messages.flatten().asIterable())
/**
* 得到包含 [this] [MessageChain].
*
* [this] [MessageChain] 将直接返回 this,
* [this] [CombinedMessage] [扁平化][flatten] 后委托为 [MessageChain],
* 否则将调用 [MessageChain] 构造一个 [MessageChainImplByIterable]
* 否则将调用 [asMessageChain]
*/
@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
@JvmSynthetic
@JvmName("newChain")
@JsName("newChain")
@Suppress("UNCHECKED_CAST")
fun Message.toChain(): MessageChain = when (this) {
is MessageChain -> this
is CombinedMessage -> MessageChainImplByIterable((this as Iterable<Message>).flatten().asIterable())
is CombinedMessage -> (this as Iterable<Message>).asMessageChain()
else -> SingleMessageChainImpl(this as SingleMessage)
}
/**
* 直接将 [this] 委托为一个 [MessageChain]
*/
@JvmName("asMessageChain1")
@JvmSynthetic
@Suppress("unused", "NOTHING_TO_INLINE")
fun Collection<SingleMessage>.asMessageChain(): MessageChain = MessageChainImplByCollection(this)
/**
* [this] [扁平化后][flatten] 委托为一个 [MessageChain]
*/
@JvmName("newChain")
@JsName("newChain")
fun Collection<Message>.asMessageChain(): MessageChain = MessageChainImplBySequence(this.flatten())
/**
* 直接将 [this] 委托为一个 [MessageChain]
*/
@JvmSynthetic
fun Iterable<SingleMessage>.asMessageChain(): MessageChain = MessageChainImplByIterable(this)
/**
* [this] [扁平化后][flatten] 委托为一个 [MessageChain]
*/
@JvmSynthetic
@Suppress("unused", "NOTHING_TO_INLINE")
@JvmName("newChain")
@JsName("newChain")
fun Iterable<Message>.asMessageChain(): MessageChain = MessageChainImplBySequence(this.flatten())
/**
* 直接将 [this] 委托为一个 [MessageChain]
*/
@JvmSynthetic
fun Sequence<SingleMessage>.asMessageChain(): MessageChain = MessageChainImplBySequence(this)
/**
* [this] [扁平化后][flatten] 委托为一个 [MessageChain]
*/
@JvmName("newChain")
@JsName("newChain")
fun Sequence<Message>.asMessageChain(): MessageChain = MessageChainImplBySequence(this.flatten())
/**
* 扁平化消息序列.
*
@ -280,6 +263,9 @@ fun Iterable<Message>.asMessageChain(): MessageChain = MessageChainImplBySequenc
*/
fun Iterable<Message>.flatten(): Sequence<SingleMessage> = asSequence().flatten()
@JvmSynthetic
fun Iterable<SingleMessage>.flatten(): Sequence<SingleMessage> = this.asSequence() // fast path
/**
* 扁平化消息序列.
*
@ -294,6 +280,9 @@ fun Iterable<Message>.flatten(): Sequence<SingleMessage> = asSequence().flatten(
*/
fun Sequence<Message>.flatten(): Sequence<SingleMessage> = flatMap { it.flatten() }
@JvmSynthetic
fun Sequence<SingleMessage>.flatten(): Sequence<SingleMessage> = this // fast path
/**
* 扁平化 [Message]
*
@ -346,17 +335,34 @@ internal inline class MessageChainImplByIterable constructor(
}
/**
* 使用 [Iterable] 作为委托的 [MessageChain]
* 使用 [Collection] 作为委托的 [MessageChain]
*/
@PublishedApi
internal inline class MessageChainImplBySequence constructor(
private val delegate: Sequence<SingleMessage>
internal inline class MessageChainImplByCollection constructor(
private val delegate: Collection<SingleMessage>
) : Message, Iterable<SingleMessage>, MessageChain {
override fun iterator(): Iterator<SingleMessage> = delegate.iterator()
override fun toString(): String = this.delegate.joinToString("") { it.toString() }
override operator fun contains(sub: String): Boolean = delegate.any { it.contains(sub) }
}
/**
* 使用 [Iterable] 作为委托的 [MessageChain]
*/
@PublishedApi
internal class MessageChainImplBySequence constructor(
delegate: Sequence<SingleMessage>
) : Message, Iterable<SingleMessage>, MessageChain {
/**
* [Sequence] 可能只能消耗一遍, 因此需要先转为 [List]
*/
private val collected: List<SingleMessage> by lazy { delegate.toList() }
override fun iterator(): Iterator<SingleMessage> = collected.iterator()
override fun toString(): String = this.collected.joinToString("") { it.toString() }
override operator fun contains(sub: String): Boolean = collected.any { it.contains(sub) }
}
/**
* 单个 [SingleMessage] 作为 [MessageChain]
*/