Skip to content

Commit

Permalink
feat: terminal coloring module (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
testersen authored Apr 1, 2024
1 parent 4dfb167 commit cb86bc5
Show file tree
Hide file tree
Showing 7 changed files with 505 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.tnboot.logging.util.colorful

/** Internal, don't touch, or you will be fired. */
class Code private constructor(
private val open: String,
private val close: String,
private val regexp: Regex,
) : Stylus {
@OptIn(ExperimentalUnsignedTypes::class)
internal constructor(close: UByte, vararg open: UByte) : this(
"\u001b[${open.joinToString(";")}m",
"\u001b[${close}m",
Regex("\\u001b\\[${close}m"),
)

override fun style(str: String): String {
return if (isEnabled) {
"$open${str.replace(regexp, open)}$close"
} else {
str
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.tnboot.logging.util.colorful

/* @formatter:off */
@OptIn(ExperimentalUnsignedTypes::class) val RESET = Code(0U, 0U)
@OptIn(ExperimentalUnsignedTypes::class) val BOLD = Code(22U, 1U)
@OptIn(ExperimentalUnsignedTypes::class) val DIM = Code(22U, 2U)
@OptIn(ExperimentalUnsignedTypes::class) val ITALIC = Code(23U, 3U)
@OptIn(ExperimentalUnsignedTypes::class) val UNDERLINE = Code(24U, 4U)
@OptIn(ExperimentalUnsignedTypes::class) val INVERSE = Code(27U, 7U)
@OptIn(ExperimentalUnsignedTypes::class) val HIDDEN = Code(28U, 8U)
@OptIn(ExperimentalUnsignedTypes::class) val STRIKETHROUGH = Code(29U, 9U)
@OptIn(ExperimentalUnsignedTypes::class) val BLACK = Code(39U, 30U)
@OptIn(ExperimentalUnsignedTypes::class) val RED = Code(39U, 31U)
@OptIn(ExperimentalUnsignedTypes::class) val GREEN = Code(39U, 32U)
@OptIn(ExperimentalUnsignedTypes::class) val YELLOW = Code(39U, 33U)
@OptIn(ExperimentalUnsignedTypes::class) val BLUE = Code(39U, 34U)
@OptIn(ExperimentalUnsignedTypes::class) val MAGENTA = Code(39U, 35U)
@OptIn(ExperimentalUnsignedTypes::class) val CYAN = Code(39U, 36U)
@OptIn(ExperimentalUnsignedTypes::class) val WHITE = Code(39U, 37U)
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_BLACK = Code(39U, 90U)
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_RED = Code(39U, 91U)
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_GREEN = Code(39U, 92U)
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_YELLOW = Code(39U, 93U)
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_BLUE = Code(39U, 94U)
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_MAGENTA = Code(39U, 95U)
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_CYAN = Code(39U, 96U)
@OptIn(ExperimentalUnsignedTypes::class) val BRIGHT_WHITE = Code(39U, 97U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BLACK = Code(49U, 40U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_RED = Code(49U, 41U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_GREEN = Code(49U, 42U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_YELLOW = Code(49U, 43U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BLUE = Code(49U, 44U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_MAGENTA = Code(49U, 45U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_CYAN = Code(49U, 46U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_WHITE = Code(49U, 47U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_BLACK = Code(49U, 100U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_RED = Code(49U, 101U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_GREEN = Code(49U, 102U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_YELLOW = Code(49U, 103U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_BLUE = Code(49U, 104U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_MAGENTA = Code(49U, 105U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_CYAN = Code(49U, 106U)
@OptIn(ExperimentalUnsignedTypes::class) val BG_BRIGHT_WHITE = Code(49U, 107U)
/* @formatter:on */
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.tnboot.logging.util.colorful

/**
* Internal object to store the colors enabled state. Used for thread
* safety.
*/
internal object Enabled {
/** Whether colors wil be rendered. */
internal var enabled = System.getenv("NO_COLOR")?.let { false } ?: true
}

/** Whether colors wil be rendered. */
val isEnabled get() = synchronized(Enabled) { Enabled.enabled }

/** Enable color rendering. */
fun enable() = synchronized(Enabled) {
Enabled.enabled = true
}

/** Disable color rendering. */
fun disable() = synchronized(Enabled) {
Enabled.enabled = false
}

/** Toggle the enabled state. */
fun toggleEnabledState() = synchronized(Enabled) {
Enabled.enabled = !Enabled.enabled
}

/** Set the enabled state. */
fun setEnabledState(enabled: Boolean) = synchronized(Enabled) {
Enabled.enabled = enabled
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package io.tnboot.logging.util.colorful

fun reset(text: String) = RESET.style(text)
fun bold(text: String) = BOLD.style(text)
fun dim(text: String) = DIM.style(text)
fun italic(text: String) = ITALIC.style(text)
fun underline(text: String) = UNDERLINE.style(text)
fun inverse(text: String) = INVERSE.style(text)
fun hidden(text: String) = HIDDEN.style(text)
fun strikeThrough(text: String) = STRIKETHROUGH.style(text)
fun black(text: String) = BLACK.style(text)
fun red(text: String) = RED.style(text)
fun green(text: String) = GREEN.style(text)
fun yellow(text: String) = YELLOW.style(text)
fun blue(text: String) = BLUE.style(text)
fun magenta(text: String) = MAGENTA.style(text)
fun cyan(text: String) = CYAN.style(text)
fun white(text: String) = WHITE.style(text)
fun brightBlack(text: String) = BRIGHT_BLACK.style(text)
fun brightRed(text: String) = BRIGHT_RED.style(text)
fun brightGreen(text: String) = BRIGHT_GREEN.style(text)
fun brightYellow(text: String) = BRIGHT_YELLOW.style(text)
fun brightBlue(text: String) = BRIGHT_BLUE.style(text)
fun brightMagenta(text: String) = BRIGHT_MAGENTA.style(text)
fun brightCyan(text: String) = BRIGHT_CYAN.style(text)
fun brightWhite(text: String) = BRIGHT_WHITE.style(text)
fun bgBlack(text: String) = BG_BLACK.style(text)
fun bgRed(text: String) = BG_RED.style(text)
fun bgGreen(text: String) = BG_GREEN.style(text)
fun bgYellow(text: String) = BG_YELLOW.style(text)
fun bgBlue(text: String) = BG_BLUE.style(text)
fun bgMagenta(text: String) = BG_MAGENTA.style(text)
fun bgCyan(text: String) = BG_CYAN.style(text)
fun bgWhite(text: String) = BG_WHITE.style(text)
fun bgBrightBlack(text: String) = BG_BRIGHT_BLACK.style(text)
fun bgBrightRed(text: String) = BG_BRIGHT_RED.style(text)
fun bgBrightGreen(text: String) = BG_BRIGHT_GREEN.style(text)
fun bgBrightYellow(text: String) = BG_BRIGHT_YELLOW.style(text)
fun bgBrightBlue(text: String) = BG_BRIGHT_BLUE.style(text)
fun bgBrightMagenta(text: String) = BG_BRIGHT_MAGENTA.style(text)
fun bgBrightCyan(text: String) = BG_BRIGHT_CYAN.style(text)
fun bgBrightWhite(text: String) = BG_BRIGHT_WHITE.style(text)

@OptIn(ExperimentalUnsignedTypes::class)
fun rgb8(color: UByte) = Code(39U, 38U, 5U, color)

fun rgb8(str: String, color: UByte) = rgb8(color).style(str)

@OptIn(ExperimentalUnsignedTypes::class)
fun bgRgb8(color: UByte) = Code(49U, 48U, 5U, color)

fun bgRgb8(str: String, color: UByte) = bgRgb8(color).style(str)

@OptIn(ExperimentalUnsignedTypes::class)
fun rgb24(r: UByte, g: UByte, b: UByte) = Code(39U, 38U, 2U, r, g, b)

fun rgb24(str: String, r: UByte, g: UByte, b: UByte) = rgb24(r, g, b).style(str)

fun rgb24(color: UInt) = rgb24(
((color shr 16) and 0xFFU).toUByte(),
((color shr 8) and 0xFFU).toUByte(),
(color and 0xFFU).toUByte(),
)

fun rgb24(str: String, color: UInt) = rgb24(color).style(str)

@OptIn(ExperimentalUnsignedTypes::class)
fun bgRgb24(r: UByte, g: UByte, b: UByte) = Code(49U, 48U, 2U, r, g, b)

fun bgRgb24(str: String, r: UByte, g: UByte, b: UByte) = bgRgb24(r, g, b).style(str)

fun bgRgb24(color: UInt) = bgRgb24(
((color shr 16) and 0xFFU).toUByte(),
((color shr 8) and 0xFFU).toUByte(),
(color and 0xFFU).toUByte(),
)

fun bgRgb24(str: String, color: UInt) = bgRgb24(color).style(str)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.tnboot.logging.util.colorful

/**
* Container for a ANSI color codes.
*/
interface Stylus {
/**
* Apply the style to the string.
*
* @param str The string to apply the style to.
* @return The string with the style applied.
*/
fun style(str: String): String
}
Loading

0 comments on commit cb86bc5

Please sign in to comment.