Skip to content

Commit cb86bc5

Browse files
authored
feat: terminal coloring module (#18)
1 parent 4dfb167 commit cb86bc5

File tree

7 files changed

+505
-0
lines changed

7 files changed

+505
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.tnboot.logging.util.colorful
2+
3+
/** Internal, don't touch, or you will be fired. */
4+
class Code private constructor(
5+
private val open: String,
6+
private val close: String,
7+
private val regexp: Regex,
8+
) : Stylus {
9+
@OptIn(ExperimentalUnsignedTypes::class)
10+
internal constructor(close: UByte, vararg open: UByte) : this(
11+
"\u001b[${open.joinToString(";")}m",
12+
"\u001b[${close}m",
13+
Regex("\\u001b\\[${close}m"),
14+
)
15+
16+
override fun style(str: String): String {
17+
return if (isEnabled) {
18+
"$open${str.replace(regexp, open)}$close"
19+
} else {
20+
str
21+
}
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package io.tnboot.logging.util.colorful
2+
3+
/* @formatter:off */
4+
@OptIn(ExperimentalUnsignedTypes::class) val RESET = Code(0U, 0U)
5+
@OptIn(ExperimentalUnsignedTypes::class) val BOLD = Code(22U, 1U)
6+
@OptIn(ExperimentalUnsignedTypes::class) val DIM = Code(22U, 2U)
7+
@OptIn(ExperimentalUnsignedTypes::class) val ITALIC = Code(23U, 3U)
8+
@OptIn(ExperimentalUnsignedTypes::class) val UNDERLINE = Code(24U, 4U)
9+
@OptIn(ExperimentalUnsignedTypes::class) val INVERSE = Code(27U, 7U)
10+
@OptIn(ExperimentalUnsignedTypes::class) val HIDDEN = Code(28U, 8U)
11+
@OptIn(ExperimentalUnsignedTypes::class) val STRIKETHROUGH = Code(29U, 9U)
12+
@OptIn(ExperimentalUnsignedTypes::class) val BLACK = Code(39U, 30U)
13+
@OptIn(ExperimentalUnsignedTypes::class) val RED = Code(39U, 31U)
14+
@OptIn(ExperimentalUnsignedTypes::class) val GREEN = Code(39U, 32U)
15+
@OptIn(ExperimentalUnsignedTypes::class) val YELLOW = Code(39U, 33U)
16+
@OptIn(ExperimentalUnsignedTypes::class) val BLUE = Code(39U, 34U)
17+
@OptIn(ExperimentalUnsignedTypes::class) val MAGENTA = Code(39U, 35U)
18+
@OptIn(ExperimentalUnsignedTypes::class) val CYAN = Code(39U, 36U)
19+
@OptIn(ExperimentalUnsignedTypes::class) val WHITE = Code(39U, 37U)
20+
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_BLACK = Code(39U, 90U)
21+
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_RED = Code(39U, 91U)
22+
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_GREEN = Code(39U, 92U)
23+
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_YELLOW = Code(39U, 93U)
24+
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_BLUE = Code(39U, 94U)
25+
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_MAGENTA = Code(39U, 95U)
26+
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_CYAN = Code(39U, 96U)
27+
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_WHITE = Code(39U, 97U)
28+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BLACK = Code(49U, 40U)
29+
@OptIn(ExperimentalUnsignedTypes::class) val BG_RED = Code(49U, 41U)
30+
@OptIn(ExperimentalUnsignedTypes::class) val BG_GREEN = Code(49U, 42U)
31+
@OptIn(ExperimentalUnsignedTypes::class) val BG_YELLOW = Code(49U, 43U)
32+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BLUE = Code(49U, 44U)
33+
@OptIn(ExperimentalUnsignedTypes::class) val BG_MAGENTA = Code(49U, 45U)
34+
@OptIn(ExperimentalUnsignedTypes::class) val BG_CYAN = Code(49U, 46U)
35+
@OptIn(ExperimentalUnsignedTypes::class) val BG_WHITE = Code(49U, 47U)
36+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_BLACK = Code(49U, 100U)
37+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_RED = Code(49U, 101U)
38+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_GREEN = Code(49U, 102U)
39+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_YELLOW = Code(49U, 103U)
40+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_BLUE = Code(49U, 104U)
41+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_MAGENTA = Code(49U, 105U)
42+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_CYAN = Code(49U, 106U)
43+
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_WHITE = Code(49U, 107U)
44+
/* @formatter:on */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.tnboot.logging.util.colorful
2+
3+
/**
4+
* Internal object to store the colors enabled state. Used for thread
5+
* safety.
6+
*/
7+
internal object Enabled {
8+
/** Whether colors wil be rendered. */
9+
internal var enabled = System.getenv("NO_COLOR")?.let { false } ?: true
10+
}
11+
12+
/** Whether colors wil be rendered. */
13+
val isEnabled get() = synchronized(Enabled) { Enabled.enabled }
14+
15+
/** Enable color rendering. */
16+
fun enable() = synchronized(Enabled) {
17+
Enabled.enabled = true
18+
}
19+
20+
/** Disable color rendering. */
21+
fun disable() = synchronized(Enabled) {
22+
Enabled.enabled = false
23+
}
24+
25+
/** Toggle the enabled state. */
26+
fun toggleEnabledState() = synchronized(Enabled) {
27+
Enabled.enabled = !Enabled.enabled
28+
}
29+
30+
/** Set the enabled state. */
31+
fun setEnabledState(enabled: Boolean) = synchronized(Enabled) {
32+
Enabled.enabled = enabled
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package io.tnboot.logging.util.colorful
2+
3+
fun reset(text: String) = RESET.style(text)
4+
fun bold(text: String) = BOLD.style(text)
5+
fun dim(text: String) = DIM.style(text)
6+
fun italic(text: String) = ITALIC.style(text)
7+
fun underline(text: String) = UNDERLINE.style(text)
8+
fun inverse(text: String) = INVERSE.style(text)
9+
fun hidden(text: String) = HIDDEN.style(text)
10+
fun strikeThrough(text: String) = STRIKETHROUGH.style(text)
11+
fun black(text: String) = BLACK.style(text)
12+
fun red(text: String) = RED.style(text)
13+
fun green(text: String) = GREEN.style(text)
14+
fun yellow(text: String) = YELLOW.style(text)
15+
fun blue(text: String) = BLUE.style(text)
16+
fun magenta(text: String) = MAGENTA.style(text)
17+
fun cyan(text: String) = CYAN.style(text)
18+
fun white(text: String) = WHITE.style(text)
19+
fun brightBlack(text: String) = BRIGHT_BLACK.style(text)
20+
fun brightRed(text: String) = BRIGHT_RED.style(text)
21+
fun brightGreen(text: String) = BRIGHT_GREEN.style(text)
22+
fun brightYellow(text: String) = BRIGHT_YELLOW.style(text)
23+
fun brightBlue(text: String) = BRIGHT_BLUE.style(text)
24+
fun brightMagenta(text: String) = BRIGHT_MAGENTA.style(text)
25+
fun brightCyan(text: String) = BRIGHT_CYAN.style(text)
26+
fun brightWhite(text: String) = BRIGHT_WHITE.style(text)
27+
fun bgBlack(text: String) = BG_BLACK.style(text)
28+
fun bgRed(text: String) = BG_RED.style(text)
29+
fun bgGreen(text: String) = BG_GREEN.style(text)
30+
fun bgYellow(text: String) = BG_YELLOW.style(text)
31+
fun bgBlue(text: String) = BG_BLUE.style(text)
32+
fun bgMagenta(text: String) = BG_MAGENTA.style(text)
33+
fun bgCyan(text: String) = BG_CYAN.style(text)
34+
fun bgWhite(text: String) = BG_WHITE.style(text)
35+
fun bgBrightBlack(text: String) = BG_BRIGHT_BLACK.style(text)
36+
fun bgBrightRed(text: String) = BG_BRIGHT_RED.style(text)
37+
fun bgBrightGreen(text: String) = BG_BRIGHT_GREEN.style(text)
38+
fun bgBrightYellow(text: String) = BG_BRIGHT_YELLOW.style(text)
39+
fun bgBrightBlue(text: String) = BG_BRIGHT_BLUE.style(text)
40+
fun bgBrightMagenta(text: String) = BG_BRIGHT_MAGENTA.style(text)
41+
fun bgBrightCyan(text: String) = BG_BRIGHT_CYAN.style(text)
42+
fun bgBrightWhite(text: String) = BG_BRIGHT_WHITE.style(text)
43+
44+
@OptIn(ExperimentalUnsignedTypes::class)
45+
fun rgb8(color: UByte) = Code(39U, 38U, 5U, color)
46+
47+
fun rgb8(str: String, color: UByte) = rgb8(color).style(str)
48+
49+
@OptIn(ExperimentalUnsignedTypes::class)
50+
fun bgRgb8(color: UByte) = Code(49U, 48U, 5U, color)
51+
52+
fun bgRgb8(str: String, color: UByte) = bgRgb8(color).style(str)
53+
54+
@OptIn(ExperimentalUnsignedTypes::class)
55+
fun rgb24(r: UByte, g: UByte, b: UByte) = Code(39U, 38U, 2U, r, g, b)
56+
57+
fun rgb24(str: String, r: UByte, g: UByte, b: UByte) = rgb24(r, g, b).style(str)
58+
59+
fun rgb24(color: UInt) = rgb24(
60+
((color shr 16) and 0xFFU).toUByte(),
61+
((color shr 8) and 0xFFU).toUByte(),
62+
(color and 0xFFU).toUByte(),
63+
)
64+
65+
fun rgb24(str: String, color: UInt) = rgb24(color).style(str)
66+
67+
@OptIn(ExperimentalUnsignedTypes::class)
68+
fun bgRgb24(r: UByte, g: UByte, b: UByte) = Code(49U, 48U, 2U, r, g, b)
69+
70+
fun bgRgb24(str: String, r: UByte, g: UByte, b: UByte) = bgRgb24(r, g, b).style(str)
71+
72+
fun bgRgb24(color: UInt) = bgRgb24(
73+
((color shr 16) and 0xFFU).toUByte(),
74+
((color shr 8) and 0xFFU).toUByte(),
75+
(color and 0xFFU).toUByte(),
76+
)
77+
78+
fun bgRgb24(str: String, color: UInt) = bgRgb24(color).style(str)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.tnboot.logging.util.colorful
2+
3+
/**
4+
* Container for a ANSI color codes.
5+
*/
6+
interface Stylus {
7+
/**
8+
* Apply the style to the string.
9+
*
10+
* @param str The string to apply the style to.
11+
* @return The string with the style applied.
12+
*/
13+
fun style(str: String): String
14+
}

0 commit comments

Comments
 (0)