aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/util/textutil.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/util/textutil.kt')
-rw-r--r--src/main/kotlin/util/textutil.kt164
1 files changed, 101 insertions, 63 deletions
diff --git a/src/main/kotlin/util/textutil.kt b/src/main/kotlin/util/textutil.kt
index 5d95d7a..cfda2e9 100644
--- a/src/main/kotlin/util/textutil.kt
+++ b/src/main/kotlin/util/textutil.kt
@@ -1,71 +1,18 @@
package moe.nea.firmament.util
+import java.util.Optional
import net.minecraft.text.ClickEvent
+import net.minecraft.text.HoverEvent
import net.minecraft.text.MutableText
+import net.minecraft.text.OrderedText
import net.minecraft.text.PlainTextContent
+import net.minecraft.text.StringVisitable
+import net.minecraft.text.Style
import net.minecraft.text.Text
import net.minecraft.text.TextColor
import net.minecraft.text.TranslatableTextContent
import net.minecraft.util.Formatting
-import moe.nea.firmament.Firmament
-
-
-class TextMatcher(text: Text) {
- data class State(
- var iterator: MutableList<Text>,
- var currentText: Text?,
- var offset: Int,
- var textContent: String,
- )
-
- var state = State(
- mutableListOf(text),
- null,
- 0,
- ""
- )
-
- fun pollChunk(): Boolean {
- val firstOrNull = state.iterator.removeFirstOrNull() ?: return false
- state.offset = 0
- state.currentText = firstOrNull
- state.textContent = when (val content = firstOrNull.content) {
- is PlainTextContent.Literal -> content.string
- else -> {
- Firmament.logger.warn("TextContent of type ${content.javaClass} not understood.")
- return false
- }
- }
- state.iterator.addAll(0, firstOrNull.siblings)
- return true
- }
-
- fun pollChunks(): Boolean {
- while (state.offset !in state.textContent.indices) {
- if (!pollChunk()) {
- return false
- }
- }
- return true
- }
-
- fun pollChar(): Char? {
- if (!pollChunks()) return null
- return state.textContent[state.offset++]
- }
-
- fun expectString(string: String): Boolean {
- var found = ""
- while (found.length < string.length) {
- if (!pollChunks()) return false
- val takeable = state.textContent.drop(state.offset).take(string.length - found.length)
- state.offset += takeable.length
- found += takeable
- }
- return found == string
- }
-}
val formattingChars = "kmolnrKMOLNR".toSet()
fun CharSequence.removeColorCodes(keepNonColorCodes: Boolean = false): String {
@@ -89,20 +36,94 @@ fun CharSequence.removeColorCodes(keepNonColorCodes: Boolean = false): String {
return stringBuffer.toString()
}
+fun OrderedText.reconstitute(): MutableText {
+ val base = Text.literal("")
+ base.setStyle(Style.EMPTY.withItalic(false))
+ var lastColorCode = Style.EMPTY
+ val text = StringBuilder()
+ this.accept { index, style, codePoint ->
+ if (style != lastColorCode) {
+ if (text.isNotEmpty())
+ base.append(Text.literal(text.toString()).setStyle(lastColorCode))
+ lastColorCode = style
+ text.clear()
+ }
+ text.append(codePoint.toChar())
+ true
+ }
+ if (text.isNotEmpty())
+ base.append(Text.literal(text.toString()).setStyle(lastColorCode))
+ return base
+
+}
+
+fun StringVisitable.reconstitute(): MutableText {
+ val base = Text.literal("")
+ base.setStyle(Style.EMPTY.withItalic(false))
+ var lastColorCode = Style.EMPTY
+ val text = StringBuilder()
+ this.visit({ style, string ->
+ if (style != lastColorCode) {
+ if (text.isNotEmpty())
+ base.append(Text.literal(text.toString()).setStyle(lastColorCode))
+ lastColorCode = style
+ text.clear()
+ }
+ text.append(string)
+ Optional.empty<Unit>()
+ }, Style.EMPTY)
+ if (text.isNotEmpty())
+ base.append(Text.literal(text.toString()).setStyle(lastColorCode))
+ return base
+
+}
+
val Text.unformattedString: String
get() = string.removeColorCodes() // TODO: maybe shortcircuit this with .visit
val Text.directLiteralStringContent: String? get() = (this.content as? PlainTextContent)?.string()
-fun Text.getLegacyFormatString() =
+fun Text.getLegacyFormatString(trimmed: Boolean = false): String =
run {
+ var lastCode = "§r"
val sb = StringBuilder()
+ fun appendCode(code: String) {
+ if (code != lastCode || !trimmed) {
+ sb.append(code)
+ lastCode = code
+ }
+ }
for (component in iterator()) {
- sb.append(component.style.color?.toChatFormatting()?.toString() ?: "§r")
+ if (component.directLiteralStringContent.isNullOrEmpty() && component.siblings.isEmpty()) {
+ continue
+ }
+ appendCode(component.style.let { style ->
+ var color = style.color?.toChatFormatting()?.toString() ?: "§r"
+ if (style.isBold)
+ color += LegacyFormattingCode.BOLD.formattingCode
+ if (style.isItalic)
+ color += LegacyFormattingCode.ITALIC.formattingCode
+ if (style.isUnderlined)
+ color += LegacyFormattingCode.UNDERLINE.formattingCode
+ if (style.isObfuscated)
+ color += LegacyFormattingCode.OBFUSCATED.formattingCode
+ if (style.isStrikethrough)
+ color += LegacyFormattingCode.STRIKETHROUGH.formattingCode
+ color
+ })
sb.append(component.directLiteralStringContent)
- sb.append("§r")
+ if (!trimmed)
+ appendCode("§r")
}
sb.toString()
+ }.also {
+ var it = it
+ if (trimmed) {
+ it = it.removeSuffix("§r")
+ if (it.length == 2 && it.startsWith("§"))
+ it = ""
+ }
+ it
}
private val textColorLUT = Formatting.entries
@@ -133,20 +154,27 @@ fun MutableText.darkGreen() = withColor(Formatting.DARK_GREEN)
fun MutableText.purple() = withColor(Formatting.DARK_PURPLE)
fun MutableText.pink() = withColor(Formatting.LIGHT_PURPLE)
fun MutableText.yellow() = withColor(Formatting.YELLOW)
+fun MutableText.gold() = withColor(Formatting.GOLD)
fun MutableText.grey() = withColor(Formatting.GRAY)
+fun MutableText.darkGrey() = withColor(Formatting.DARK_GRAY)
fun MutableText.red() = withColor(Formatting.RED)
fun MutableText.white() = withColor(Formatting.WHITE)
fun MutableText.bold(): MutableText = styled { it.withBold(true) }
+fun MutableText.hover(text: Text): MutableText = styled { it.withHoverEvent(HoverEvent.ShowText(text)) }
fun MutableText.clickCommand(command: String): MutableText {
require(command.startsWith("/"))
return this.styled {
- it.withClickEvent(ClickEvent(ClickEvent.Action.RUN_COMMAND,
- "/firm disablereiwarning"))
+ it.withClickEvent(ClickEvent.RunCommand(command))
}
}
+fun MutableText.prepend(text: Text): MutableText {
+ siblings.addFirst(text)
+ return this
+}
+
fun Text.transformEachRecursively(function: (Text) -> Text): Text {
val c = this.content
if (c is TranslatableTextContent) {
@@ -169,4 +197,14 @@ fun Text.transformEachRecursively(function: (Text) -> Text): Text {
fun tr(key: String, default: String): MutableText = error("Compiler plugin did not run.")
fun trResolved(key: String, vararg args: Any): MutableText = Text.stringifiedTranslatable(key, *args)
+fun titleCase(str: String): String {
+ return str
+ .lowercase()
+ .replace("_", " ")
+ .split(" ")
+ .joinToString(" ") { word ->
+ word.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
+ }
+}
+