mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-28 16:50:09 +08:00
Review AnsiMessageBuilder
This commit is contained in:
parent
0a2e103bf3
commit
b87a5390b9
@ -13,11 +13,23 @@ package net.mamoe.mirai.console.util
|
|||||||
import net.mamoe.mirai.console.command.CommandSender
|
import net.mamoe.mirai.console.command.CommandSender
|
||||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||||
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
|
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.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 open class AnsiMessageBuilder public constructor(
|
||||||
public val delegate: StringBuilder
|
public val delegate: StringBuilder,
|
||||||
) : Appendable {
|
) : Appendable, Serializable, Comparable<AnsiMessageBuilder> {
|
||||||
override fun toString(): String = delegate.toString()
|
override fun toString(): String = delegate.toString()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,7 +41,7 @@ public open class AnsiMessageBuilder public constructor(
|
|||||||
*
|
*
|
||||||
* @param code Ansi 操作码
|
* @param code Ansi 操作码
|
||||||
*
|
*
|
||||||
* @see from
|
* @see asAnsiMessageBuilder
|
||||||
* @see create
|
* @see create
|
||||||
*/
|
*/
|
||||||
public open fun ansi(code: String): AnsiMessageBuilder = append(code)
|
public open fun ansi(code: String): AnsiMessageBuilder = append(code)
|
||||||
@ -50,44 +62,133 @@ public open class AnsiMessageBuilder public constructor(
|
|||||||
public open fun lightPurple(): AnsiMessageBuilder = append(Color.LIGHT_PURPLE)
|
public open fun lightPurple(): AnsiMessageBuilder = append(Color.LIGHT_PURPLE)
|
||||||
public open fun lightCyan(): AnsiMessageBuilder = append(Color.LIGHT_CYAN)
|
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 {
|
public companion object {
|
||||||
|
/**
|
||||||
|
* 从 [String] 中剔除 ansi 控制符
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
public fun String.dropAnsi(): String = this
|
||||||
|
.replace(DROP_CSI_PATTERN, "") // 先进行 CSI 剔除后进行 ANSI 剔除
|
||||||
|
.replace(DROP_ANSI_PATTERN, "")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 [this] 封装一个 [AnsiMessageBuilder]
|
||||||
|
*
|
||||||
|
* @param noAnsi 为 `true` 时忽略全部与 ansi 有关的方法的调用
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
@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 = StringBuilder(capacity).asAnsiMessageBuilder(noAnsi)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断 [sender] 是否支持带 ansi 控制符的正确显示
|
||||||
|
*/
|
||||||
|
@ConsoleExperimentalApi
|
||||||
|
@JvmStatic
|
||||||
|
public fun isAnsiSupported(sender: CommandSender): Boolean =
|
||||||
|
if (sender is ConsoleCommandSender) {
|
||||||
|
MiraiConsoleImplementationBridge.isAnsiSupported
|
||||||
|
} else false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 往 [StringBuilder] 追加 ansi 控制符
|
||||||
|
*/
|
||||||
|
public inline fun StringBuilder.appendAnsi(
|
||||||
|
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) }
|
||||||
|
override fun append(csq: CharSequence?, start: Int, end: Int): AnsiMessageBuilder = apply { delegate.append(csq, start, end) }
|
||||||
|
public fun append(any: Any?): AnsiMessageBuilder = apply { delegate.append(any) }
|
||||||
|
public fun append(value: String): AnsiMessageBuilder = apply { delegate.append(value) }
|
||||||
|
public fun append(value: String, start: Int, end: Int): AnsiMessageBuilder = apply { delegate.append(value, start, end) }
|
||||||
|
public fun append(value: Boolean): AnsiMessageBuilder = apply { delegate.append(value) }
|
||||||
|
public fun append(value: Float): AnsiMessageBuilder = apply { delegate.append(value) }
|
||||||
|
public fun append(value: Double): AnsiMessageBuilder = apply { delegate.append(value) }
|
||||||
|
public fun append(value: Int): AnsiMessageBuilder = apply { delegate.append(value) }
|
||||||
|
public fun append(value: Long): AnsiMessageBuilder = apply { delegate.append(value) }
|
||||||
|
public fun append(value: Short): AnsiMessageBuilder = apply { delegate.append(value) }
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param capacity [StringBuilder] 初始化大小
|
||||||
|
* @see AnsiMessageBuilder.create
|
||||||
|
* @since 1.1
|
||||||
|
*/
|
||||||
|
@JvmSynthetic
|
||||||
|
public fun AnsiMessageBuilder(capacity: Int = 16): AnsiMessageBuilder = AnsiMessageBuilder(StringBuilder(capacity))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建一条 ANSI 信息
|
||||||
|
*
|
||||||
|
* @see AnsiMessageBuilder
|
||||||
|
* @since 1.1
|
||||||
|
*/
|
||||||
|
@JvmSynthetic
|
||||||
|
public inline fun buildAnsiMessage(
|
||||||
|
capacity: Int = 16,
|
||||||
|
action: AnsiMessageBuilder.() -> Unit,
|
||||||
|
): String = AnsiMessageBuilder.create(capacity, false).apply(action).toString()
|
||||||
|
|
||||||
|
// 不在 top-level 使用者会得到 Internal error: Couldn't inline sendAnsiMessage
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向 [CommandSender] 发送一条带有 ANSI 控制符的信息
|
||||||
|
*
|
||||||
|
* @see AnsiMessageBuilder
|
||||||
|
* @since 1.1
|
||||||
|
*/
|
||||||
|
@JvmSynthetic
|
||||||
|
public suspend inline fun CommandSender.sendAnsiMessage(
|
||||||
|
capacity: Int = 16,
|
||||||
|
builder: AnsiMessageBuilder.() -> Unit,
|
||||||
|
): MessageReceipt<Contact>? {
|
||||||
|
return sendMessage(
|
||||||
|
AnsiMessageBuilder.create(capacity, noAnsi = !AnsiMessageBuilder.isAnsiSupported(this))
|
||||||
|
.apply(builder)
|
||||||
|
.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向 [CommandSender] 发送一条带有 ANSI 控制符的信息
|
||||||
|
*
|
||||||
|
* @see AnsiMessageBuilder.Companion.dropAnsi
|
||||||
|
* @since 1.1
|
||||||
|
*/
|
||||||
|
@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 [、若干个(包括0个)“参数字节”、若干个“中间字节”,以及一个“最终字节”组成。各部分的字符范围如下:
|
||||||
//
|
//
|
||||||
// CSI序列在ESC [之后各个组成部分的字符范围[12]:5.4
|
// CSI序列在ESC [之后各个组成部分的字符范围[12]:5.4
|
||||||
@ -113,118 +214,39 @@ public open class AnsiMessageBuilder public constructor(
|
|||||||
// 注: 缺少详细资料, 只能认定 ansi 长度固定为二字节 (CSI除外)
|
// 注: 缺少详细资料, 只能认定 ansi 长度固定为二字节 (CSI除外)
|
||||||
private val DROP_ANSI_PATTERN = """\u001b[\u0040–\u005F]""".toRegex()
|
private val DROP_ANSI_PATTERN = """\u001b[\u0040–\u005F]""".toRegex()
|
||||||
|
|
||||||
/**
|
private object Color {
|
||||||
* 从 [String] 中剔除 ansi 控制符
|
const val RESET = "\u001b[0m"
|
||||||
*/
|
const val WHITE = "\u001b[30m"
|
||||||
@JvmStatic
|
const val RED = "\u001b[31m"
|
||||||
public fun String.dropAnsi(): String = this
|
const val EMERALD_GREEN = "\u001b[32m"
|
||||||
.replace(DROP_CSI_PATTERN, "") // 先进行 CSI 剔除后进行 ANSI 剔除
|
const val GOLD = "\u001b[33m"
|
||||||
.replace(DROP_ANSI_PATTERN, "")
|
const val BLUE = "\u001b[34m"
|
||||||
|
const val PURPLE = "\u001b[35m"
|
||||||
/**
|
const val GREEN = "\u001b[36m"
|
||||||
* 使用 [builder] 封装一个 [AnsiMessageBuilder]
|
const val GRAY = "\u001b[90m"
|
||||||
*
|
const val LIGHT_RED = "\u001b[91m"
|
||||||
* @param noAnsi 为 `true` 时忽略全部与 ansi 有关的方法的调用
|
const val LIGHT_GREEN = "\u001b[92m"
|
||||||
*/
|
const val LIGHT_YELLOW = "\u001b[93m"
|
||||||
@JvmStatic
|
const val LIGHT_BLUE = "\u001b[94m"
|
||||||
@JvmOverloads
|
const val LIGHT_PURPLE = "\u001b[95m"
|
||||||
public fun from(
|
const val LIGHT_CYAN = "\u001b[96m"
|
||||||
builder: StringBuilder,
|
|
||||||
noAnsi: Boolean = false
|
|
||||||
): AnsiMessageBuilder = if (noAnsi) {
|
|
||||||
NoAnsiMessageBuilder(builder)
|
|
||||||
} else AnsiMessageBuilder(builder)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param capacity [StringBuilder] 的初始化大小
|
|
||||||
*
|
|
||||||
* @param noAnsi 为 `true` 时忽略全部与 ansi 有关的方法的调用
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
@JvmOverloads
|
|
||||||
public fun create(
|
|
||||||
capacity: Int = 16,
|
|
||||||
noAnsi: Boolean = false
|
|
||||||
): AnsiMessageBuilder = from(StringBuilder(capacity), noAnsi)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断 [sender] 是否支持带 ansi 控制符的正确显示
|
|
||||||
*/
|
|
||||||
@ConsoleExperimentalApi
|
|
||||||
@JvmStatic
|
|
||||||
public fun isAnsiSupported(sender: CommandSender): Boolean =
|
|
||||||
if (sender is ConsoleCommandSender) {
|
|
||||||
MiraiConsoleImplementationBridge.isAnsiSupported
|
|
||||||
} else false
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 往 [StringBuilder] 追加 ansi 控制符
|
|
||||||
*/
|
|
||||||
public inline fun StringBuilder.appendAnsi(
|
|
||||||
action: AnsiMessageBuilder.() -> Unit
|
|
||||||
): AnsiMessageBuilder = from(this).apply(action)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////
|
private class NoAnsiMessageBuilder(builder: StringBuilder) : AnsiMessageBuilder(builder) {
|
||||||
override fun append(c: Char): AnsiMessageBuilder = apply { delegate.append(c) }
|
override fun reset(): AnsiMessageBuilder = this
|
||||||
override fun append(csq: CharSequence?): AnsiMessageBuilder = apply { delegate.append(csq) }
|
override fun white(): AnsiMessageBuilder = this
|
||||||
override fun append(csq: CharSequence?, start: Int, end: Int): AnsiMessageBuilder = apply { delegate.append(csq, start, end) }
|
override fun red(): AnsiMessageBuilder = this
|
||||||
public fun append(any: Any?): AnsiMessageBuilder = apply { delegate.append(any) }
|
override fun emeraldGreen(): AnsiMessageBuilder = this
|
||||||
public fun append(value: String): AnsiMessageBuilder = apply { delegate.append(value) }
|
override fun gold(): AnsiMessageBuilder = this
|
||||||
public fun append(value: String, start: Int, end: Int): AnsiMessageBuilder = apply { delegate.append(value, start, end) }
|
override fun blue(): AnsiMessageBuilder = this
|
||||||
public fun append(value: Boolean): AnsiMessageBuilder = apply { delegate.append(value) }
|
override fun purple(): AnsiMessageBuilder = this
|
||||||
public fun append(value: Float): AnsiMessageBuilder = apply { delegate.append(value) }
|
override fun green(): AnsiMessageBuilder = this
|
||||||
public fun append(value: Double): AnsiMessageBuilder = apply { delegate.append(value) }
|
override fun gray(): AnsiMessageBuilder = this
|
||||||
public fun append(value: Int): AnsiMessageBuilder = apply { delegate.append(value) }
|
override fun lightRed(): AnsiMessageBuilder = this
|
||||||
public fun append(value: Long): AnsiMessageBuilder = apply { delegate.append(value) }
|
override fun lightGreen(): AnsiMessageBuilder = this
|
||||||
public fun append(value: Short): AnsiMessageBuilder = apply { delegate.append(value) }
|
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
|
||||||
* @param capacity [StringBuilder] 初始化大小
|
|
||||||
*/
|
|
||||||
public fun AnsiMessageBuilder(capacity: Int = 16): AnsiMessageBuilder = AnsiMessageBuilder(StringBuilder(capacity))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建一条 ansi 信息
|
|
||||||
*
|
|
||||||
* @see [AnsiMessageBuilder]
|
|
||||||
*/
|
|
||||||
public inline fun buildAnsiMessage(
|
|
||||||
capacity: Int = 16,
|
|
||||||
action: AnsiMessageBuilder.() -> Unit
|
|
||||||
): String = AnsiMessageBuilder.create(capacity, false).apply(action).toString()
|
|
||||||
|
|
||||||
// 不在 top-level 使用者会得到 Internal error: Couldn't inline sendAnsiMessage
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 向 [CommandSender] 发送一条带有 ansi 控制符的信息
|
|
||||||
*
|
|
||||||
* @see [AnsiMessageBuilder]
|
|
||||||
*/
|
|
||||||
public suspend inline fun CommandSender.sendAnsiMessage(
|
|
||||||
capacity: Int = 16,
|
|
||||||
builder: AnsiMessageBuilder.() -> Unit
|
|
||||||
) {
|
|
||||||
sendMessage(
|
|
||||||
AnsiMessageBuilder.create(capacity, noAnsi = !AnsiMessageBuilder.isAnsiSupported(this))
|
|
||||||
.apply(builder)
|
|
||||||
.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 向 [CommandSender] 发送一条带有 ansi 控制符的信息
|
|
||||||
*
|
|
||||||
* @see [AnsiMessageBuilder.Companion.dropAnsi]
|
|
||||||
*/
|
|
||||||
public suspend inline fun CommandSender.sendAnsiMessage(message: String) {
|
|
||||||
sendMessage(
|
|
||||||
if (AnsiMessageBuilder.isAnsiSupported(this))
|
|
||||||
message
|
|
||||||
else
|
|
||||||
message.dropAnsi()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user