From e8d4fb16b14cd4eb8ed4a074766eb6ed44a2a73b Mon Sep 17 00:00:00 2001 From: alex-s168 <63254202+alex-s168@users.noreply.github.com> Date: Thu, 28 Mar 2024 22:44:15 +0100 Subject: [PATCH] terminal colors, multi-line strings; bump to 0.8 --- README.md | 5 ++ build.gradle.kts | 2 +- src/main/kotlin/blitz/Fnp.kt | 33 --------- src/main/kotlin/blitz/IO.kt | 8 +++ .../kotlin/blitz/str/MutMultiLineString.kt | 53 ++++++++++++++ src/main/kotlin/blitz/str/MutString.kt | 61 ++++++++++++++++ src/main/kotlin/blitz/term/AnsiiStr.kt | 16 +++++ src/main/kotlin/blitz/term/Terminal.kt | 70 +++++++++++++++++++ src/test/kotlin/uniq.kt | 16 +++++ 9 files changed, 230 insertions(+), 34 deletions(-) delete mode 100644 src/main/kotlin/blitz/Fnp.kt create mode 100644 src/main/kotlin/blitz/str/MutMultiLineString.kt create mode 100644 src/main/kotlin/blitz/str/MutString.kt create mode 100644 src/main/kotlin/blitz/term/AnsiiStr.kt create mode 100644 src/main/kotlin/blitz/term/Terminal.kt create mode 100644 src/test/kotlin/uniq.kt diff --git a/README.md b/README.md index fab556b..275927b 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,11 @@ val fib = lazySequence(0 to 1) { i, f -> println(fib[10]) ``` +### Terminal colors +```kotlin +Terminal.print("Hello, ", Terminal.STYLES.BOLD) +Terminal.println("World!", Terminal.COLORS.RED.brighter.fg, Terminal.COLORS.WHITE.bg) +``` ### Unix `uniq` ```kotlin val inp = sequenceOf("AAA", "BBB", "AAA", "AAA", "AAA", "BBB") diff --git a/build.gradle.kts b/build.gradle.kts index 180fc00..cbd3473 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "me.alex_s168" -version = "0.7" +version = "0.8" repositories { mavenCentral() diff --git a/src/main/kotlin/blitz/Fnp.kt b/src/main/kotlin/blitz/Fnp.kt deleted file mode 100644 index ba2713c..0000000 --- a/src/main/kotlin/blitz/Fnp.kt +++ /dev/null @@ -1,33 +0,0 @@ -package blitz - -import blitz.collections.contents -import blitz.collections.easyMappingSequence -import blitz.func.* -import blitz.func.io.* - -fun main(args: Array) { - // pureCat(args) - // .impure() - - val inp = sequenceOf("AAA", "BBB", "AAA", "AAA", "AAA", "BBB") - val out = inp.easyMappingSequence { i, s, m -> - if (s(i-1) == m(i)) null - else m(i) - } - println(out.contents) -} - -// `cat` command -fun pureCat(args: Array): Monad = - args - .ifEmpty { arrayOf("-") } - .map { - if (it == "-") readIn() - else unit(it) - .asPath() - .read() - .stringify() - } - .rewrap() - .flatten() - .reduce { s -> print(s) } \ No newline at end of file diff --git a/src/main/kotlin/blitz/IO.kt b/src/main/kotlin/blitz/IO.kt index 41f69b1..1a50780 100644 --- a/src/main/kotlin/blitz/IO.kt +++ b/src/main/kotlin/blitz/IO.kt @@ -1,5 +1,13 @@ package blitz +@Deprecated( + level = DeprecationLevel.ERROR, + message = "Will be removed in the future!", + replaceWith = ReplaceWith( + "Terminal.warn", + "blitz.term.Terminal" + ) +) fun warn(msg: String) { System.err.println(msg) } \ No newline at end of file diff --git a/src/main/kotlin/blitz/str/MutMultiLineString.kt b/src/main/kotlin/blitz/str/MutMultiLineString.kt new file mode 100644 index 0000000..f68c196 --- /dev/null +++ b/src/main/kotlin/blitz/str/MutMultiLineString.kt @@ -0,0 +1,53 @@ +package blitz.str + +class MutMultiLineString( + var fill: Char +) { + val lines = mutableListOf() + + // TODO: wrap at \n + + /** if out of bounds, extends with @see fill */ + operator fun get(row: Int, col: Int): Char { + if (row >= lines.size) { + repeat(row - lines.size + 1) { + lines.add(MutString(fill = fill)) + } + } + return lines[row][col] + } + + /** if out of bounds, extends with @see fill */ + operator fun set(row: Int, col: Int, value: Char) { + if (row >= lines.size) { + repeat(row - lines.size + 1) { + lines.add(MutString(fill = fill)) + } + } else { + lines[row].fill = fill + } + lines[row][col] = value + } + + /** if out of bounds, extends with @see fill */ + operator fun set(row: Int, colStart: Int, value: CharSequence) { + if (row >= lines.size) { + repeat(row - lines.size + 1) { + lines.add(MutString(fill = fill)) + } + } else { + lines[row].fill = fill + } + lines[row][colStart] = value + } + + /** if out of bounds, extends with @see fill */ + operator fun set(rowStart: Int, colStart: Int, value: MutMultiLineString) { + value.lines.forEachIndexed { index, line -> + this[index + rowStart, colStart] = line + } + } + + override fun toString(): String = + lines.joinToString(separator = "\n") +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/str/MutString.kt b/src/main/kotlin/blitz/str/MutString.kt new file mode 100644 index 0000000..5a0a61e --- /dev/null +++ b/src/main/kotlin/blitz/str/MutString.kt @@ -0,0 +1,61 @@ +package blitz.str + +class MutString( + init: String = "", + var fill: Char +): CharSequence, Appendable { + private val builder = StringBuilder(init) + + override val length: Int + get() = builder.length + + override operator fun get(index: Int): Char { + if (index >= length) { + repeat(index - length + 1) { + builder.append(fill) + } + } + return builder[index] + } + + /** if out of bounds, extends with @see fill */ + operator fun set(index: Int, value: Char) { + if (index >= length) { + repeat(index - length + 1) { + builder.append(fill) + } + } + builder[index] = value + } + + /** if out of bounds, extends with @see fill */ + operator fun set(start: Int, str: CharSequence) { + if (start >= length) { + repeat(start - length + 1) { + builder.append(fill) + } + } + builder.insert(start, str) + } + + override fun toString(): String = + builder.toString() + + override fun append(csq: CharSequence?): Appendable { + builder.append(csq) + return this + } + + override fun append(csq: CharSequence?, start: Int, end: Int): Appendable { + builder.append(csq, start, end) + return this + } + + override fun append(c: Char): Appendable { + builder.append(c) + return this + } + + override fun subSequence(startIndex: Int, endIndex: Int): CharSequence = + builder.subSequence(startIndex, endIndex) +} \ No newline at end of file diff --git a/src/main/kotlin/blitz/term/AnsiiStr.kt b/src/main/kotlin/blitz/term/AnsiiStr.kt new file mode 100644 index 0000000..1475c07 --- /dev/null +++ b/src/main/kotlin/blitz/term/AnsiiStr.kt @@ -0,0 +1,16 @@ +package blitz.term + +class AnsiiMode(internal val values: MutableList) { + constructor(mo: Int): this(mutableListOf(mo)) + + operator fun plus(other: AnsiiMode): AnsiiMode = + AnsiiMode((values + other.values).toMutableList()) +} + +private val escape = (27).toChar() + +fun ansiiStr(str: String, vararg modes: AnsiiMode) = + if (modes.isEmpty()) + str + else + "$escape[${modes.flatMap { it.values }.joinToString(separator = ";")}m$str$escape[0m" \ No newline at end of file diff --git a/src/main/kotlin/blitz/term/Terminal.kt b/src/main/kotlin/blitz/term/Terminal.kt new file mode 100644 index 0000000..d7801eb --- /dev/null +++ b/src/main/kotlin/blitz/term/Terminal.kt @@ -0,0 +1,70 @@ +package blitz.term + +object Terminal { + object COLORS { + val BLACK = Color(AnsiiMode(30), AnsiiMode(40)) + val RED = Color(AnsiiMode(31), AnsiiMode(41)) + val GREEN = Color(AnsiiMode(32), AnsiiMode(42)) + val YELLOW = Color(AnsiiMode(33), AnsiiMode(43)) + val BLUE = Color(AnsiiMode(34), AnsiiMode(44)) + val MAGENTA = Color(AnsiiMode(35), AnsiiMode(45)) + val CYAN = Color(AnsiiMode(36), AnsiiMode(46)) + val WHITE = Color(AnsiiMode(37), AnsiiMode(47)) + } + + object STYLES { + val BOLD = AnsiiMode(1) + val DIM = AnsiiMode(2) + val UNDERLINE = AnsiiMode(4) + val BLINK = AnsiiMode(5) + } + + class Color( + val fg: AnsiiMode, + val bg: AnsiiMode, + brighterIn: Color? = null, + darkerIn: Color? = null + ) { + private fun ch(mode: AnsiiMode): Int = + mode.values[0] + + private fun brighterChannel(va: Int): Int = + if (va <= 50) va + 60 else va + + private fun darkerChannel(va: Int): Int = + if (va >= 50) va - 60 else va + + val brighter by lazy { Color(AnsiiMode(brighterChannel(ch(fg))), AnsiiMode(brighterChannel(ch(bg)))) } + val darker by lazy { Color(AnsiiMode(darkerChannel(ch(fg))), AnsiiMode(darkerChannel(ch(bg)))) } + } + + fun encodeString(str: String, vararg modes: AnsiiMode) = + ansiiStr(str, *modes) + + fun print(str: String, vararg modes: AnsiiMode) { + kotlin.io.print(encodeString(str, *modes)) + } + + fun println(str: String, vararg modes: AnsiiMode) { + kotlin.io.println(encodeString(str, *modes)) + } + + fun err(str: String, vararg modes: AnsiiMode) { + System.err.print(encodeString(str, *modes)) + } + + fun errln(str: String, vararg modes: AnsiiMode) { + System.err.println(encodeString(str, *modes)) + } + + @Deprecated( + "Use errln instead!", + ReplaceWith( + "errln(str, *modes)", + "blitz.term.Terminal.errln" + ) + ) + fun warn(str: String, vararg modes: AnsiiMode) { + errln(str, *modes) + } +} \ No newline at end of file diff --git a/src/test/kotlin/uniq.kt b/src/test/kotlin/uniq.kt new file mode 100644 index 0000000..509ad7c --- /dev/null +++ b/src/test/kotlin/uniq.kt @@ -0,0 +1,16 @@ +import blitz.collections.contents +import blitz.collections.easyMappingSequence +import kotlin.test.Test +import kotlin.test.assertEquals + +class GeneratorSequences { + @Test + fun uniq() { + val inp = sequenceOf("AAA", "BBB", "AAA", "AAA", "AAA", "BBB") + val out = inp.easyMappingSequence { i, s, m -> + if (s(i-1) == m(i)) null + else m(i) + }.filterNotNull() + assertEquals(out.contents, listOf("AAA", "BBB", "AAA", "BBB").contents) + } +} \ No newline at end of file