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.kt117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/main/kotlin/util/textutil.kt b/src/main/kotlin/util/textutil.kt
new file mode 100644
index 0000000..a05733c
--- /dev/null
+++ b/src/main/kotlin/util/textutil.kt
@@ -0,0 +1,117 @@
+
+
+package moe.nea.firmament.util
+
+import net.minecraft.text.MutableText
+import net.minecraft.text.PlainTextContent
+import net.minecraft.text.Style
+import net.minecraft.text.Text
+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 {
+ var nextParagraph = indexOf('§')
+ if (nextParagraph < 0) return this.toString()
+ val stringBuffer = StringBuilder(this.length)
+ var readIndex = 0
+ while (nextParagraph >= 0) {
+ stringBuffer.append(this, readIndex, nextParagraph)
+ if (keepNonColorCodes && nextParagraph + 1 < length && this[nextParagraph + 1] in formattingChars) {
+ readIndex = nextParagraph
+ nextParagraph = indexOf('§', startIndex = readIndex + 1)
+ } else {
+ readIndex = nextParagraph + 2
+ nextParagraph = indexOf('§', startIndex = readIndex)
+ }
+ if (readIndex > this.length)
+ readIndex = this.length
+ }
+ stringBuffer.append(this, readIndex, this.length)
+ return stringBuffer.toString()
+}
+
+val Text.unformattedString: String
+ get() = string.removeColorCodes()
+
+
+fun MutableText.withColor(formatting: Formatting) = this.styled { it.withColor(formatting).withItalic(false) }
+
+fun Text.transformEachRecursively(function: (Text) -> Text): Text {
+ val c = this.content
+ if (c is TranslatableTextContent) {
+ return Text.translatableWithFallback(c.key, c.fallback, *c.args.map {
+ (if (it is Text) it else Text.literal(it.toString())).transformEachRecursively(function)
+ }.toTypedArray()).also { new ->
+ new.style = this.style
+ new.siblings.clear()
+ this.siblings.forEach { child ->
+ new.siblings.add(child.transformEachRecursively(function))
+ }
+ }
+ }
+ return function(this.copy().also { it.siblings.clear() }).also { tt ->
+ this.siblings.forEach {
+ tt.siblings.add(it.transformEachRecursively(function))
+ }
+ }
+}