Skip to content

Commit

Permalink
Add support for 8-bit indexed colors
Browse files Browse the repository at this point in the history
Fixes #72
  • Loading branch information
bitspittle committed Dec 26, 2021
1 parent 1c9f2fe commit 6add8e8
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,10 @@ private fun toWhiteCommand(layer: ColorLayer, isBright: Boolean) = when(layer) {
ColorLayer.BG -> if (isBright) BG_WHITE_BRIGHT_COMMAND else BG_WHITE_COMMAND
}

//// TODO(#72): Add support for lookup colors
//private fun toLookupCommand(layer: ColorLayer, index: Int) = when(layer) {
// ColorLayer.FG -> fgLookupCommand(index)
// ColorLayer.BG -> bgLookupCommand(index)
//}
private fun toLookupCommand(layer: ColorLayer, index: Int) = when(layer) {
ColorLayer.FG -> fgLookupCommand(index)
ColorLayer.BG -> bgLookupCommand(index)
}

private fun toTruecolorCommand(layer: ColorLayer, r: Int, g: Int, b: Int) = when(layer) {
ColorLayer.FG -> fgTruecolorCommand(r, g, b)
Expand Down Expand Up @@ -182,10 +181,9 @@ fun RenderScope.color(color: Color, layer: ColorLayer = ColorLayer.FG) {
})
}

// TODO(#72): Add support for lookup colors
//fun RenderScope.color(index: Int, layer: ColorLayer = ColorLayer.FG) {
// applyCommand(toLookupCommand(layer, index))
//}
fun RenderScope.color(index: Int, layer: ColorLayer = ColorLayer.FG) {
applyCommand(toLookupCommand(layer, index))
}

fun RenderScope.rgb(r: Int, g: Int, b: Int, layer: ColorLayer = ColorLayer.FG) {
applyCommand(toTruecolorCommand(layer, r, g, b))
Expand Down Expand Up @@ -309,17 +307,21 @@ fun RenderScope.white(
}
}

// TODO(#72): Add support for lookup colors
//fun RenderScope.color(
// index: Int,
// layer: ColorLayer = ColorLayer.FG,
// scopedBlock: RenderScope.() -> Unit
//) {
// scopedState {
// color(index, layer)
// scopedBlock()
// }
//}
/**
* Use an index to lookup an 8-bit color.
*
* See also: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
*/
fun RenderScope.color(
index: Int,
layer: ColorLayer = ColorLayer.FG,
scopedBlock: RenderScope.() -> Unit
) {
scopedState {
color(index, layer)
scopedBlock()
}
}

fun RenderScope.rgb(
r: Int,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,7 @@ internal object Ansi {

object CLEAR : Code("39${Identifiers.SGR}")

// TODO(#72): Add support for lookup colors
//fun lookup(index: Int) = Code("$FG_NUMERIC;$LOOKUP_SUBCODE;$index${Identifiers.SGR}")
fun lookup(index: Int) = Code("$FG_NUMERIC;$LOOKUP_SUBCODE;$index${Identifiers.SGR}")
fun truecolor(r: Int, g: Int, b: Int) = Code("$FG_NUMERIC;$TRUECOLOR_SUBCODE;$r;$g;$b${Identifiers.SGR}")
}

Expand All @@ -186,8 +185,7 @@ internal object Ansi {

object CLEAR : Code("49${Identifiers.SGR}")

// TODO(#72): Add support for lookup colors
// fun lookup(index: Int) = Code("$BG_NUMERIC;$LOOKUP_SUBCODE;$index${Identifiers.SGR}")
fun lookup(index: Int) = Code("$BG_NUMERIC;$LOOKUP_SUBCODE;$index${Identifiers.SGR}")
fun truecolor(r: Int, g: Int, b: Int) = Code("$BG_NUMERIC;$TRUECOLOR_SUBCODE;$r;$g;$b${Identifiers.SGR}")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ internal val CLEAR_INVERT_COMMAND = object : AnsiCsiCommand(Colors.CLEAR_INVERT)
}
}

// internal fun fgLookupCommand(index: Int) = FgColorCommand(Colors.Fg.lookup(index))
internal fun fgLookupCommand(index: Int) = FgColorCommand(Colors.Fg.lookup(index))
internal fun fgTruecolorCommand(r: Int, g: Int, b: Int) = FgColorCommand(Colors.Fg.truecolor(r, g, b))
// TODO(#72): Add support for lookup colors
// internal fun bgLookupCommand(index: Int) = BgColorCommand(Colors.Bg.lookup(index))
internal fun bgLookupCommand(index: Int) = BgColorCommand(Colors.Bg.lookup(index))
internal fun bgTruecolorCommand(r: Int, g: Int, b: Int) = BgColorCommand(Colors.Bg.truecolor(r, g, b))
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,54 @@ import com.varabyte.konsole.foundation.text.Color as AnsiColor

private const val Inverted = "inverted"

// Taken from https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit and https://stackoverflow.com/a/27165165
private val IndexedColors by lazy {
// Range 0 - 15 (legacy colors)
val legacyColors = listOf(
AnsiColor.BLACK.toSwingColor(),
AnsiColor.RED.toSwingColor(),
AnsiColor.GREEN.toSwingColor(),
AnsiColor.YELLOW.toSwingColor(),
AnsiColor.BLUE.toSwingColor(),
AnsiColor.MAGENTA.toSwingColor(),
AnsiColor.CYAN.toSwingColor(),
AnsiColor.WHITE.toSwingColor(),
AnsiColor.BRIGHT_BLACK.toSwingColor(),
AnsiColor.BRIGHT_RED.toSwingColor(),
AnsiColor.BRIGHT_GREEN.toSwingColor(),
AnsiColor.BRIGHT_YELLOW.toSwingColor(),
AnsiColor.BRIGHT_BLUE.toSwingColor(),
AnsiColor.BRIGHT_MAGENTA.toSwingColor(),
AnsiColor.BRIGHT_CYAN.toSwingColor(),
AnsiColor.BRIGHT_WHITE.toSwingColor(),
).mapIndexed { i, color -> i to color }.toMap()

// Range 16-231: Representative RGB values
val coreColors = (16..231).associateWith { i ->
val zeroOffset = i - 16
val rIndex = zeroOffset / 36
val gIndex = (zeroOffset % 36) / 6
val bIndex = zeroOffset % 6

val r = if (rIndex > 0) 55 + rIndex * 40 else 0
val g = if (gIndex > 0) 55 + gIndex * 40 else 0
val b = if (bIndex > 0) 55 + bIndex * 40 else 0

println("$i -> $r $g $b")
Color(r, g, b)
}

// Range 232 - 255: Grayscale
val grayscaleColors = (232 .. 255).associateWith { i ->
val zeroOffset = i - 232
val gray = zeroOffset * 10 + 8

Color(gray, gray, gray)
}

legacyColors + coreColors + grayscaleColors
}

/**
* Convert ANSI SGR codes to instructions that Swing can understand.
*/
Expand Down Expand Up @@ -76,17 +124,31 @@ internal class SgrCodeConverter(val defaultForeground: Color, val defaultBackgro
else -> {
val optionalCodes = code.parts.optionalCodes ?: return null
var attrSetModifier: (MutableAttributeSet.() -> Unit)? = null
if (code.parts.numericCode == Ansi.Csi.Codes.Sgr.Colors.FG_NUMERIC &&
optionalCodes[0] == Ansi.Csi.Codes.Sgr.Colors.TRUECOLOR_SUBCODE
) {
attrSetModifier =
{ setInverseAwareForeground(Color(optionalCodes[1], optionalCodes[2], optionalCodes[3])) }
if (code.parts.numericCode == Ansi.Csi.Codes.Sgr.Colors.FG_NUMERIC) {
val color = if (optionalCodes[0] == Ansi.Csi.Codes.Sgr.Colors.TRUECOLOR_SUBCODE) {
Color(optionalCodes[1], optionalCodes[2], optionalCodes[3])
} else if (optionalCodes[0] == Ansi.Csi.Codes.Sgr.Colors.LOOKUP_SUBCODE) {
IndexedColors[optionalCodes[1]]
} else {
null
}

if (color != null) {
attrSetModifier = { setInverseAwareForeground(color) }
}
}
else if (code.parts.numericCode == Ansi.Csi.Codes.Sgr.Colors.BG_NUMERIC &&
optionalCodes[0] == Ansi.Csi.Codes.Sgr.Colors.TRUECOLOR_SUBCODE
) {
attrSetModifier =
{ setInverseAwareBackground(Color(optionalCodes[1], optionalCodes[2], optionalCodes[3])) }
else if (code.parts.numericCode == Ansi.Csi.Codes.Sgr.Colors.BG_NUMERIC) {
val color = if (optionalCodes[0] == Ansi.Csi.Codes.Sgr.Colors.TRUECOLOR_SUBCODE) {
Color(optionalCodes[1], optionalCodes[2], optionalCodes[3])
} else if (optionalCodes[0] == Ansi.Csi.Codes.Sgr.Colors.LOOKUP_SUBCODE) {
IndexedColors[optionalCodes[1]]
} else {
null
}

if (color != null) {
attrSetModifier = { setInverseAwareBackground(color) }
}
}

attrSetModifier
Expand Down

0 comments on commit 6add8e8

Please sign in to comment.