Преглед на файлове

Review AnsiMessageBuilder

Him188 преди 5 години
родител
ревизия
b87a5390b9
променени са 1 файла, в които са добавени 115 реда и са изтрити 93 реда
  1. 115 93
      backend/mirai-console/src/util/AnsiMessageBuilder.kt

+ 115 - 93
backend/mirai-console/src/util/AnsiMessageBuilder.kt

@@ -13,11 +13,23 @@ package net.mamoe.mirai.console.util
 import net.mamoe.mirai.console.command.CommandSender
 import net.mamoe.mirai.console.command.ConsoleCommandSender
 import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
+import net.mamoe.mirai.console.util.AnsiMessageBuilder.Companion.asAnsiMessageBuilder
 import net.mamoe.mirai.console.util.AnsiMessageBuilder.Companion.dropAnsi
+import net.mamoe.mirai.contact.Contact
+import net.mamoe.mirai.message.MessageReceipt
+import java.io.Serializable
 
+/**
+ * @see buildAnsiMessage
+ * @see sendAnsiMessage
+ * @see AnsiMessageBuilder
+ * @see AnsiMessageBuilder.create
+ * @see asAnsiMessageBuilder
+ * @since 1.1
+ */
 public open class AnsiMessageBuilder public constructor(
-    public val delegate: StringBuilder
-) : Appendable {
+    public val delegate: StringBuilder,
+) : Appendable, Serializable, Comparable<AnsiMessageBuilder> {
     override fun toString(): String = delegate.toString()
 
     /**
@@ -29,7 +41,7 @@ public open class AnsiMessageBuilder public constructor(
      *
      * @param code Ansi 操作码
      *
-     * @see from
+     * @see asAnsiMessageBuilder
      * @see create
      */
     public open fun ansi(code: String): AnsiMessageBuilder = append(code)
@@ -50,69 +62,7 @@ public open class AnsiMessageBuilder public constructor(
     public open fun lightPurple(): AnsiMessageBuilder = append(Color.LIGHT_PURPLE)
     public open fun lightCyan(): AnsiMessageBuilder = append(Color.LIGHT_CYAN)
 
-    internal object Color {
-        const val RESET = "\u001b[0m"
-        const val WHITE = "\u001b[30m"
-        const val RED = "\u001b[31m"
-        const val EMERALD_GREEN = "\u001b[32m"
-        const val GOLD = "\u001b[33m"
-        const val BLUE = "\u001b[34m"
-        const val PURPLE = "\u001b[35m"
-        const val GREEN = "\u001b[36m"
-        const val GRAY = "\u001b[90m"
-        const val LIGHT_RED = "\u001b[91m"
-        const val LIGHT_GREEN = "\u001b[92m"
-        const val LIGHT_YELLOW = "\u001b[93m"
-        const val LIGHT_BLUE = "\u001b[94m"
-        const val LIGHT_PURPLE = "\u001b[95m"
-        const val LIGHT_CYAN = "\u001b[96m"
-    }
-
-    internal class NoAnsiMessageBuilder(builder: StringBuilder) : AnsiMessageBuilder(builder) {
-        override fun reset(): AnsiMessageBuilder = this
-        override fun white(): AnsiMessageBuilder = this
-        override fun red(): AnsiMessageBuilder = this
-        override fun emeraldGreen(): AnsiMessageBuilder = this
-        override fun gold(): AnsiMessageBuilder = this
-        override fun blue(): AnsiMessageBuilder = this
-        override fun purple(): AnsiMessageBuilder = this
-        override fun green(): AnsiMessageBuilder = this
-        override fun gray(): AnsiMessageBuilder = this
-        override fun lightRed(): AnsiMessageBuilder = this
-        override fun lightGreen(): AnsiMessageBuilder = this
-        override fun lightYellow(): AnsiMessageBuilder = this
-        override fun lightBlue(): AnsiMessageBuilder = this
-        override fun lightPurple(): AnsiMessageBuilder = this
-        override fun lightCyan(): AnsiMessageBuilder = this
-        override fun ansi(code: String): AnsiMessageBuilder = this
-    }
-
     public companion object {
-        // CSI序列由ESC [、若干个(包括0个)“参数字节”、若干个“中间字节”,以及一个“最终字节”组成。各部分的字符范围如下:
-        //
-        // CSI序列在ESC [之后各个组成部分的字符范围[12]:5.4
-        // 组成部分	字符范围	ASCII
-        // 参数字节	0x30–0x3F	0–9:;<=>?
-        // 中间字节	0x20–0x2F	空格、!"#$%&'()*+,-./
-        // 最终字节	0x40–0x7E	@A–Z[\]^_`a–z{|}~
-        //
-        // @see https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#CSI%E5%BA%8F%E5%88%97
-        @Suppress("RegExpRedundantEscape")
-        private val DROP_CSI_PATTERN = """\u001b\[([\u0030-\u003F])*?([\u0020-\u002F])*?[\u0040-\u007E]""".toRegex()
-
-        // 序列具有不同的长度。所有序列都以ASCII字符ESC(27 / 十六进制 0x1B)开头,
-        // 第二个字节则是0x40–0x5F(ASCII @A–Z[\]^_)范围内的字符。[12]:5.3.a
-        //
-        // 标准规定,在8位环境中,这两个字节的序列可以合并为0x80-0x9F范围内的单个字节(详情请参阅C1控制字符集)。
-        // 但是,在现代设备上,这些代码通常用于其他目的,例如UTF-8的一部分或CP-1252字符,因此并不使用这种合并的方式。
-        //
-        // 除ESC之外的其他C0代码(通常是BEL,BS,CR,LF,FF,TAB,VT,SO和SI)在输出时也可能会产生与某些控制序列相似或相同的效果。
-        //
-        // @see https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97
-        //
-        // 注: 缺少详细资料, 只能认定 ansi 长度固定为二字节 (CSI除外)
-        private val DROP_ANSI_PATTERN = """\u001b[\u0040–\u005F]""".toRegex()
-
         /**
          * 从 [String] 中剔除 ansi 控制符
          */
@@ -122,30 +72,28 @@ public open class AnsiMessageBuilder public constructor(
             .replace(DROP_ANSI_PATTERN, "")
 
         /**
-         * 使用 [builder] 封装一个 [AnsiMessageBuilder]
+         * 使用 [this] 封装一个 [AnsiMessageBuilder]
          *
          * @param noAnsi 为 `true` 时忽略全部与 ansi 有关的方法的调用
          */
         @JvmStatic
         @JvmOverloads
-        public fun from(
-            builder: StringBuilder,
-            noAnsi: Boolean = false
-        ): AnsiMessageBuilder = if (noAnsi) {
-            NoAnsiMessageBuilder(builder)
-        } else AnsiMessageBuilder(builder)
+        @JvmName("from")
+        public fun StringBuilder.asAnsiMessageBuilder(noAnsi: Boolean = false): AnsiMessageBuilder =
+            if (noAnsi) NoAnsiMessageBuilder(this) else AnsiMessageBuilder(this)
 
         /**
          * @param capacity [StringBuilder] 的初始化大小
          *
          * @param noAnsi 为 `true` 时忽略全部与 ansi 有关的方法的调用
+         * @see AnsiMessageBuilder
          */
         @JvmStatic
         @JvmOverloads
         public fun create(
             capacity: Int = 16,
-            noAnsi: Boolean = false
-        ): AnsiMessageBuilder = from(StringBuilder(capacity), noAnsi)
+            noAnsi: Boolean = false,
+        ): AnsiMessageBuilder = StringBuilder(capacity).asAnsiMessageBuilder(noAnsi)
 
         /**
          * 判断 [sender] 是否支持带 ansi 控制符的正确显示
@@ -161,11 +109,12 @@ public open class AnsiMessageBuilder public constructor(
          * 往 [StringBuilder] 追加 ansi 控制符
          */
         public inline fun StringBuilder.appendAnsi(
-            action: AnsiMessageBuilder.() -> Unit
-        ): AnsiMessageBuilder = from(this).apply(action)
-
+            action: AnsiMessageBuilder.() -> Unit,
+        ): AnsiMessageBuilder = this.asAnsiMessageBuilder().apply(action)
     }
 
+    override fun compareTo(other: AnsiMessageBuilder): Int = this.delegate.compareTo(other.delegate)
+
     /////////////////////////////////////////////////////////////////////////////////
     override fun append(c: Char): AnsiMessageBuilder = apply { delegate.append(c) }
     override fun append(csq: CharSequence?): AnsiMessageBuilder = apply { delegate.append(csq) }
@@ -184,31 +133,38 @@ public open class AnsiMessageBuilder public constructor(
 
 /**
  * @param capacity [StringBuilder] 初始化大小
+ * @see AnsiMessageBuilder.create
+ * @since 1.1
  */
+@JvmSynthetic
 public fun AnsiMessageBuilder(capacity: Int = 16): AnsiMessageBuilder = AnsiMessageBuilder(StringBuilder(capacity))
 
 /**
- * 构建一条 ansi 信息
+ * 构建一条 ANSI 信息
  *
- * @see [AnsiMessageBuilder]
+ * @see AnsiMessageBuilder
+ * @since 1.1
  */
+@JvmSynthetic
 public inline fun buildAnsiMessage(
     capacity: Int = 16,
-    action: AnsiMessageBuilder.() -> Unit
+    action: AnsiMessageBuilder.() -> Unit,
 ): String = AnsiMessageBuilder.create(capacity, false).apply(action).toString()
 
 // 不在 top-level 使用者会得到 Internal error: Couldn't inline sendAnsiMessage
 
 /**
- * 向 [CommandSender] 发送一条带有 ansi 控制符的信息
+ * 向 [CommandSender] 发送一条带有 ANSI 控制符的信息
  *
- * @see [AnsiMessageBuilder]
+ * @see AnsiMessageBuilder
+ * @since 1.1
  */
+@JvmSynthetic
 public suspend inline fun CommandSender.sendAnsiMessage(
     capacity: Int = 16,
-    builder: AnsiMessageBuilder.() -> Unit
-) {
-    sendMessage(
+    builder: AnsiMessageBuilder.() -> Unit,
+): MessageReceipt<Contact>? {
+    return sendMessage(
         AnsiMessageBuilder.create(capacity, noAnsi = !AnsiMessageBuilder.isAnsiSupported(this))
             .apply(builder)
             .toString()
@@ -216,15 +172,81 @@ public suspend inline fun CommandSender.sendAnsiMessage(
 }
 
 /**
- * 向 [CommandSender] 发送一条带有 ansi 控制符的信息
+ * 向 [CommandSender] 发送一条带有 ANSI 控制符的信息
  *
- * @see [AnsiMessageBuilder.Companion.dropAnsi]
+ * @see AnsiMessageBuilder.Companion.dropAnsi
+ * @since 1.1
  */
-public suspend inline fun CommandSender.sendAnsiMessage(message: String) {
-    sendMessage(
-        if (AnsiMessageBuilder.isAnsiSupported(this))
-            message
-        else
-            message.dropAnsi()
+@JvmSynthetic
+public suspend inline fun CommandSender.sendAnsiMessage(message: String): MessageReceipt<Contact>? {
+    return sendMessage(
+        if (AnsiMessageBuilder.isAnsiSupported(this)) message
+        else message.dropAnsi()
     )
 }
+
+
+// internals
+
+
+// CSI序列由ESC [、若干个(包括0个)“参数字节”、若干个“中间字节”,以及一个“最终字节”组成。各部分的字符范围如下:
+//
+// CSI序列在ESC [之后各个组成部分的字符范围[12]:5.4
+// 组成部分	字符范围	ASCII
+// 参数字节	0x30–0x3F	0–9:;<=>?
+// 中间字节	0x20–0x2F	空格、!"#$%&'()*+,-./
+// 最终字节	0x40–0x7E	@A–Z[\]^_`a–z{|}~
+//
+// @see https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#CSI%E5%BA%8F%E5%88%97
+@Suppress("RegExpRedundantEscape")
+private val DROP_CSI_PATTERN = """\u001b\[([\u0030-\u003F])*?([\u0020-\u002F])*?[\u0040-\u007E]""".toRegex()
+
+// 序列具有不同的长度。所有序列都以ASCII字符ESC(27 / 十六进制 0x1B)开头,
+// 第二个字节则是0x40–0x5F(ASCII @A–Z[\]^_)范围内的字符。[12]:5.3.a
+//
+// 标准规定,在8位环境中,这两个字节的序列可以合并为0x80-0x9F范围内的单个字节(详情请参阅C1控制字符集)。
+// 但是,在现代设备上,这些代码通常用于其他目的,例如UTF-8的一部分或CP-1252字符,因此并不使用这种合并的方式。
+//
+// 除ESC之外的其他C0代码(通常是BEL,BS,CR,LF,FF,TAB,VT,SO和SI)在输出时也可能会产生与某些控制序列相似或相同的效果。
+//
+// @see https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97#%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97
+//
+// 注: 缺少详细资料, 只能认定 ansi 长度固定为二字节 (CSI除外)
+private val DROP_ANSI_PATTERN = """\u001b[\u0040–\u005F]""".toRegex()
+
+private object Color {
+    const val RESET = "\u001b[0m"
+    const val WHITE = "\u001b[30m"
+    const val RED = "\u001b[31m"
+    const val EMERALD_GREEN = "\u001b[32m"
+    const val GOLD = "\u001b[33m"
+    const val BLUE = "\u001b[34m"
+    const val PURPLE = "\u001b[35m"
+    const val GREEN = "\u001b[36m"
+    const val GRAY = "\u001b[90m"
+    const val LIGHT_RED = "\u001b[91m"
+    const val LIGHT_GREEN = "\u001b[92m"
+    const val LIGHT_YELLOW = "\u001b[93m"
+    const val LIGHT_BLUE = "\u001b[94m"
+    const val LIGHT_PURPLE = "\u001b[95m"
+    const val LIGHT_CYAN = "\u001b[96m"
+}
+
+private class NoAnsiMessageBuilder(builder: StringBuilder) : AnsiMessageBuilder(builder) {
+    override fun reset(): AnsiMessageBuilder = this
+    override fun white(): AnsiMessageBuilder = this
+    override fun red(): AnsiMessageBuilder = this
+    override fun emeraldGreen(): AnsiMessageBuilder = this
+    override fun gold(): AnsiMessageBuilder = this
+    override fun blue(): AnsiMessageBuilder = this
+    override fun purple(): AnsiMessageBuilder = this
+    override fun green(): AnsiMessageBuilder = this
+    override fun gray(): AnsiMessageBuilder = this
+    override fun lightRed(): AnsiMessageBuilder = this
+    override fun lightGreen(): AnsiMessageBuilder = this
+    override fun lightYellow(): AnsiMessageBuilder = this
+    override fun lightBlue(): AnsiMessageBuilder = this
+    override fun lightPurple(): AnsiMessageBuilder = this
+    override fun lightCyan(): AnsiMessageBuilder = this
+    override fun ansi(code: String): AnsiMessageBuilder = this
+}