Add docs and more useful functions

This commit is contained in:
Him188 2019-12-04 12:53:30 +08:00
parent b8323a5ed6
commit 33409f3a82
2 changed files with 106 additions and 22 deletions

View File

@ -3,6 +3,9 @@
package net.mamoe.mirai.event
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.isAdministrator
import net.mamoe.mirai.contact.isOperator
import net.mamoe.mirai.contact.isOwner
import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.any
import net.mamoe.mirai.network.protocol.tim.packet.event.FriendMessage
@ -18,12 +21,12 @@ import kotlin.jvm.JvmName
*/
@UseExperimental(ExperimentalContracts::class)
@MessageDsl
suspend inline fun subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder<MessagePacket<*>>.() -> Unit) {
suspend inline fun subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder<MessagePacket<*, *>>.() -> Unit) {
contract {
callsInPlace(listeners, InvocationKind.EXACTLY_ONCE)
}
MessageSubscribersBuilder<MessagePacket<*>> { listener ->
subscribeAlways<MessagePacket<*>> {
MessageSubscribersBuilder<MessagePacket<*, *>> { listener ->
subscribeAlways<MessagePacket<*, *>> {
listener(it)
}
}.apply { listeners() }
@ -66,12 +69,12 @@ suspend inline fun subscribeFriendMessages(crossinline listeners: suspend Messag
*/
@UseExperimental(ExperimentalContracts::class)
@MessageDsl
suspend inline fun Bot.subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder<MessagePacket<*>>.() -> Unit) {
suspend inline fun Bot.subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder<MessagePacket<*, *>>.() -> Unit) {
contract {
callsInPlace(listeners, InvocationKind.EXACTLY_ONCE)
}
MessageSubscribersBuilder<MessagePacket<*>> { listener ->
this.subscribeAlways<MessagePacket<*>> {
MessageSubscribersBuilder<MessagePacket<*, *>> { listener ->
this.subscribeAlways<MessagePacket<*, *>> {
listener(it)
}
}.apply { listeners() }
@ -111,11 +114,11 @@ suspend inline fun Bot.subscribeFriendMessages(crossinline listeners: suspend Me
private typealias AnyReplier<T> = @MessageDsl suspend T.(String) -> Any?
private suspend inline operator fun <T : MessagePacket<*>> (@MessageDsl suspend T.(String) -> Unit).invoke(t: T) =
private suspend inline operator fun <T : MessagePacket<*, *>> (@MessageDsl suspend T.(String) -> Unit).invoke(t: T) =
this.invoke(t, t.message.stringValue)
@JvmName("invoke1") //Avoid Platform declaration clash
private suspend inline operator fun <T : MessagePacket<*>> AnyReplier<T>.invoke(t: T): Any? =
private suspend inline operator fun <T : MessagePacket<*, *>> AnyReplier<T>.invoke(t: T): Any? =
this.invoke(t, t.message.stringValue)
/**
@ -127,7 +130,7 @@ private suspend inline operator fun <T : MessagePacket<*>> AnyReplier<T>.invoke(
// TODO: 2019/11/29 应定义为 inline, 但这会导致一个 JVM run-time VerifyError. 等待 kotlin 修复 bug
@Suppress("unused")
@MessageDsl
class MessageSubscribersBuilder<T : MessagePacket<*>>(
class MessageSubscribersBuilder<T : MessagePacket<*, *>>(
inline val subscriber: suspend (@MessageDsl suspend T.(String) -> Unit) -> Unit
) {
/**
@ -194,6 +197,27 @@ class MessageSubscribersBuilder<T : MessagePacket<*>>(
@MessageDsl
suspend inline fun sentBy(qqId: Long, noinline onEvent: @MessageDsl suspend T.(String) -> Unit) = sentBy(qqId.toUInt(), onEvent)
/**
* 如果是管理员或群主发的消息, 就执行 [onEvent]
*/
@MessageDsl
suspend inline fun sentByOperator(noinline onEvent: @MessageDsl suspend T.(String) -> Unit) =
content({ this is GroupMessage && sender.permission.isOperator() }, onEvent)
/**
* 如果是管理员发的消息, 就执行 [onEvent]
*/
@MessageDsl
suspend inline fun sentByAdministrator(noinline onEvent: @MessageDsl suspend T.(String) -> Unit) =
content({ this is GroupMessage && sender.permission.isAdministrator() }, onEvent)
/**
* 如果是群主发的消息, 就执行 [onEvent]
*/
@MessageDsl
suspend inline fun sentByOwner(noinline onEvent: @MessageDsl suspend T.(String) -> Unit) =
content({ this is GroupMessage && sender.permission.isOwner() }, onEvent)
/**
* 如果是来自这个群的消息, 就执行 [onEvent]
*/
@ -221,21 +245,74 @@ class MessageSubscribersBuilder<T : MessagePacket<*>>(
suspend inline fun content(noinline filter: T.(String) -> Boolean, noinline onEvent: @MessageDsl suspend T.(String) -> Unit) =
subscriber { if (this.filter(message.stringValue)) onEvent(this) }
/**
* 若消息内容包含 [this] 则回复 [reply]
*/
@MessageDsl
suspend inline infix fun String.containsReply(replier: String) =
content({ this@containsReply in it }) { this@content.reply(replier) }
suspend inline infix fun String.containsReply(reply: String) =
content({ this@containsReply in it }) { this@content.reply(reply) }
/**
* 若消息内容包含 [this] 则执行 [replier] 并将其返回值回复给发信对象.
*
* [replier] `it` 将会是消息内容 string.
*
* @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他情况则 [Any.toString] 后回复
*/
@MessageDsl
suspend inline infix fun String.containsReply(noinline replier: AnyReplier<T>) =
content({ this@containsReply in it }) { replier(this) }
content({ this@containsReply in it }) {
@Suppress("DSL_SCOPE_VIOLATION_WARNING") // false negative warning
executeAndReply(replier)
}
/**
* 不考虑空格, 若消息内容以 [this] 开始则执行 [replier] 并将其返回值回复给发信对象.
*
* [replier] `it` 将会是去掉用来判断的前缀并删除前后空格后的字符串.
* 如当消息为 "kick 123456 "
* ```kotlin
* "kick" startsWithReply {
* println(it) // it 为 "123456"
* }
* ```
*
* @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他类型则 [Any.toString] 后回复
*/
@MessageDsl
suspend inline infix fun String.startsWithReply(noinline replier: AnyReplier<T>) =
content({ it.startsWith(this@startsWithReply) }) { replier(this) }
suspend inline infix fun String.startsWithReply(noinline replier: AnyReplier<T>) {
val toCheck = this.trimStart()
content({ it.trimStart().startsWith(toCheck) }) {
@Suppress("DSL_SCOPE_VIOLATION_WARNING") // false negative warning
executeAndReply {
replier(it.removePrefix(toCheck).trim())
}
}
}
/**
* 不考虑空格, 若消息内容以 [this] 结尾则执行 [replier] 并将其返回值回复给发信对象.
*
* [replier] `it` 将会是去掉用来判断的后缀并删除前后空格后的字符串.
* 如当消息为 " 123456 test"
* ```kotlin
* "test" endswithReply {
* println(it) // it 为 "123456"
* }
* ```
*
* @param replier 若返回 [Message] 则直接发送; 若返回 [Unit] 则不回复; 其他情况则 [Any.toString] 后回复
*/
@MessageDsl
suspend inline infix fun String.endswithReply(noinline replier: AnyReplier<T>) =
content({ it.endsWith(this@endswithReply) }) { replier(this) }
suspend inline infix fun String.endswithReply(noinline replier: AnyReplier<T>) {
val toCheck = this.trimEnd()
content({ it.endsWith(this@endswithReply) }) {
@Suppress("DSL_SCOPE_VIOLATION_WARNING") // false negative warning
executeAndReply {
replier(it.removeSuffix(toCheck).trim())
}
}
}
@MessageDsl
suspend inline infix fun String.reply(reply: String) = case(this) {
@ -243,17 +320,23 @@ class MessageSubscribersBuilder<T : MessagePacket<*>>(
}
@MessageDsl
suspend inline infix fun String.reply(noinline reply: AnyReplier<T>) = case(this) {
when (val message = reply(this)) {
is Message -> reply(message)
suspend inline infix fun String.reply(noinline replier: AnyReplier<T>) = case(this) {
@Suppress("DSL_SCOPE_VIOLATION_WARNING") // false negative warning
executeAndReply(replier)
}
@PublishedApi
@Suppress("NOTHING_TO_INLINE")
internal suspend inline fun T.executeAndReply(noinline replier: AnyReplier<T>) {
when (val message = replier(this)) {
is Message -> this.reply(message)
is Unit -> {
}
else -> reply(message.toString())
else -> this.reply(message.toString())
}
}
/* 易产生迷惑感
suspend inline fun replyCase(equals: String, trim: Boolean = true, noinline replier: MessageReplier<T>) = case(equals, trim) { reply(replier(this)) }
suspend inline fun replyContains(value: String, noinline replier: MessageReplier<T>) = content({ value in it }) { replier(this) }
@ -265,6 +348,7 @@ class MessageSubscribersBuilder<T : MessagePacket<*>>(
/**
* DSL 标记. 将能让 IDE 阻止一些错误的方法调用.
*/
@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS, AnnotationTarget.TYPE)
@DslMarker
internal annotation class MessageDsl

View File

@ -118,7 +118,7 @@ suspend fun Bot.messageDSL() {
// 如果是这个 QQ 号发送的消息(可以是好友消息也可以是群消息)
sentBy(1040400290) {
sentBy(123456789) {
}