mirror of
https://github.com/daylinmorgan/hwylterm.git
synced 2024-11-16 06:28:32 -06:00
start work to support truecolor and hexcodes
This commit is contained in:
parent
f2590506da
commit
c1738c9504
6 changed files with 134 additions and 69 deletions
|
@ -4,11 +4,11 @@
|
|||
use BB style markup to add color to strings using VT100 escape codes
|
||||
]##
|
||||
|
||||
import std/[os, sequtils, strutils]
|
||||
import std/[os, sequtils, strformat, strutils]
|
||||
|
||||
import ./bbansi/[styles, utils]
|
||||
export utils
|
||||
export bbReset
|
||||
# export bbReset
|
||||
|
||||
type
|
||||
BbSpan* = object
|
||||
|
@ -124,6 +124,9 @@ proc `&`*(x: BbString, y: string): BbString =
|
|||
result.plain &= y
|
||||
result.spans[^1].slice[1] = result.plain.len - 1
|
||||
|
||||
template bbfmt*(pattern: static string): BbString =
|
||||
bb(fmt(pattern))
|
||||
|
||||
proc `&`*(x: string, y: BbString): BbString =
|
||||
result.raw = x & y.raw
|
||||
result.plain = x & y.plain
|
||||
|
|
30
src/hwylterm/bbansi/colors.nim
Normal file
30
src/hwylterm/bbansi/colors.nim
Normal file
|
@ -0,0 +1,30 @@
|
|||
import std/[parseutils, strutils]
|
||||
|
||||
type
|
||||
ColorRgb* = object
|
||||
red, green, blue: int
|
||||
ColorHex* = object
|
||||
code: string
|
||||
ColorXterm* = enum
|
||||
# 0-7
|
||||
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White,
|
||||
# 8-15
|
||||
BrightBlack, BrightRed, BrightGreen, BrightYellow,
|
||||
BrightBlue, BrightMagenta, BrightCyan, BrightWhite
|
||||
|
||||
func rgb*(r, g, b: int): ColorRgb =
|
||||
ColorRgb(red: r, green: g, blue: b)
|
||||
|
||||
func hexToRgb*(s: string): ColorRgb =
|
||||
let code = s.replace("#", "")
|
||||
assert code.len == 6
|
||||
discard parseHex(code[0..1], result.red)
|
||||
discard parseHex(code[2..3], result.green)
|
||||
discard parseHex(code[4..5], result.blue)
|
||||
|
||||
func `$`*(c: ColorRgb): string =
|
||||
result.add $c.red
|
||||
result.add ";"
|
||||
result.add $c.green
|
||||
result.add ";"
|
||||
result.add $c.blue
|
|
@ -2,30 +2,44 @@ import std/tables
|
|||
export tables
|
||||
|
||||
|
||||
const
|
||||
bbReset* = "\e[0m"
|
||||
bbStyles* = {
|
||||
"reset": "0",
|
||||
"bold": "1",
|
||||
"b": "1",
|
||||
"faint": "2",
|
||||
"italic": "3",
|
||||
"i": "3",
|
||||
"underline": "4",
|
||||
"u": "4",
|
||||
"blink": "5",
|
||||
"reverse": "7",
|
||||
"conceal": "8",
|
||||
"strike": "9",
|
||||
}.toTable
|
||||
type
|
||||
BbStyleAbbr* = enum
|
||||
B, I, U
|
||||
|
||||
bbColors* = {
|
||||
"black": "0",
|
||||
"red": "1",
|
||||
"green": "2",
|
||||
"yellow": "3",
|
||||
"blue": "4",
|
||||
"magenta": "5",
|
||||
"cyan": "6",
|
||||
"white": "7",
|
||||
}.toTable
|
||||
BbStyle* = enum
|
||||
Reset,
|
||||
Bold, Faint, Italic, Underline, Blink,
|
||||
Reverse = 7, Conceal, Strike
|
||||
|
||||
func toStyle*(a: BbStyleAbbr): BbStyle =
|
||||
case a:
|
||||
of B: Bold
|
||||
of I: Italic
|
||||
of U: Underline
|
||||
|
||||
const bbReset* = "\e[0m"
|
||||
# bbStyles* = {
|
||||
# "reset": "0",
|
||||
# "bold": "1",
|
||||
# "b": "1",
|
||||
# "faint": "2",
|
||||
# "italic": "3",
|
||||
# "i": "3",
|
||||
# "underline": "4",
|
||||
# "u": "4",
|
||||
# "blink": "5",
|
||||
# "reverse": "7",
|
||||
# "conceal": "8",
|
||||
# "strike": "9",
|
||||
# }.toTable
|
||||
#
|
||||
# bbColors* = {
|
||||
# "black": "0",
|
||||
# "red": "1",
|
||||
# "green": "2",
|
||||
# "yellow": "3",
|
||||
# "blue": "4",
|
||||
# "magenta": "5",
|
||||
# "cyan": "6",
|
||||
# "white": "7",
|
||||
# }.toTable
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import std/[os, strutils, terminal]
|
||||
import ./styles
|
||||
import std/[
|
||||
enumutils, os, strutils, terminal, sequtils]
|
||||
import ./[styles, colors]
|
||||
|
||||
type
|
||||
BbMode* = enum
|
||||
|
@ -20,6 +21,22 @@ proc checkColorSupport(): BbMode =
|
|||
|
||||
let bbMode* = checkColorSupport()
|
||||
|
||||
func normStyle(style: string): string = style.replace("_","").capitalizeAscii()
|
||||
func toCode(style: BbStyle): string = $ord(style)
|
||||
func toCode(abbr: BbStyleAbbr): string = abbr.toStyle().toCode()
|
||||
func toCode(color: ColorXterm): string = "38;5;" & $ord(color)
|
||||
func toBgCode(color: ColorXterm): string = "48;5;" & $ord(color)
|
||||
func toCode(c: ColorRgb): string = "38;2;" & $c
|
||||
func toBgCode(c: ColorRgb): string = "48:2;" & $c
|
||||
|
||||
const ColorXTermNames = ColorXterm.items().toSeq().mapIt(($it).toLowerAscii().capitalizeAscii())
|
||||
const BbStyleNames = BbStyle.items().toSeq().mapIt(($it).toLowerAscii().capitalizeAscii())
|
||||
|
||||
func isHex(s: string): bool =
|
||||
(s.startswith "#") and (s.len == 7)
|
||||
|
||||
# TODO: write seperate parseStyle procedure
|
||||
|
||||
proc toAnsiCode*(s: string): string =
|
||||
if bbMode == Off: return
|
||||
var
|
||||
|
@ -33,12 +50,26 @@ proc toAnsiCode*(s: string): string =
|
|||
else:
|
||||
styles = s.splitWhitespace()
|
||||
for style in styles:
|
||||
if style in bbStyles:
|
||||
codes.add bbStyles[style]
|
||||
elif style in bbColors and bbMode == On:
|
||||
codes.add "3" & bbColors[style]
|
||||
if bgStyle in bbColors and bbMode == On:
|
||||
codes.add "4" & bbColors[bgStyle]
|
||||
let normalizedStyle = style.normStyle
|
||||
if normalizedStyle in ["B", "I", "U"]:
|
||||
codes.add parseEnum[BbStyleAbbr](normalizedStyle).toCode()
|
||||
elif normalizedStyle in BbStyleNames:
|
||||
codes.add parseEnum[BbStyle](normalizedStyle).toCode()
|
||||
elif normalizedStyle in ColorXtermNames and bbMode == On:
|
||||
codes.add parseEnum[ColorXterm](normalizedStyle).toCode()
|
||||
elif normalizedStyle.isHex():
|
||||
codes.add normalizedStyle.hexToRgb.toCode()
|
||||
else:
|
||||
when defined(debugBB): echo "unknown style: " & normalizedStyle
|
||||
|
||||
if bbMode == On and bgStyle != "":
|
||||
let normalizedBgStyle = bgStyle.normStyle
|
||||
if normalizedBgStyle in ColorXtermNames:
|
||||
codes.add parseEnum[ColorXTerm](normalizedBgStyle).toBgCode()
|
||||
elif normalizedBgStyle.isHex():
|
||||
codes.add normalizedBgStyle.hexToRgb().toBgCode()
|
||||
else:
|
||||
when defined(debugBB): echo "unknown bg style: " & normalizedBgStyle
|
||||
|
||||
if codes.len > 0:
|
||||
result.add "\e["
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
import std/[os, terminal]
|
||||
|
||||
type
|
||||
BbMode* = enum
|
||||
On, NoColor, Off
|
||||
|
||||
proc checkColorSupport(): BbMode =
|
||||
when defined(bbansiOff):
|
||||
return Off
|
||||
when defined(bbansiNoColor):
|
||||
return NoColor
|
||||
else:
|
||||
if os.getEnv("HWYLTERM_FORCE_COLOR") != "":
|
||||
return On
|
||||
if os.getEnv("NO_COLOR") != "":
|
||||
return NoColor
|
||||
if not isatty(stdout):
|
||||
return Off
|
||||
|
||||
let bbMode* = checkColorSupport()
|
||||
|
||||
|
|
@ -8,16 +8,16 @@ template bbCheck(input: string, output: string): untyped =
|
|||
suite "basic":
|
||||
test "simple":
|
||||
bbCheck "[red][/red]", ""
|
||||
bbCheck "[red]red text", "\e[31mred text\e[0m"
|
||||
bbCheck "[red]Red Text", "\e[31mRed Text\e[0m"
|
||||
bbCheck "[yellow]Yellow Text", "\e[33mYellow Text\e[0m"
|
||||
bbCheck "[bold red]Bold Red Text", "\e[1;31mBold Red Text\e[0m"
|
||||
bbCheck "[red]5[/]", "\e[31m5\e[0m"
|
||||
bbCheck "[bold][red]5","\e[1;31m5\e[0m"
|
||||
bbCheck "[red]red text", "\e[38;5;1mred text\e[0m"
|
||||
bbCheck "[red]Red Text", "\e[38;5;1mRed Text\e[0m"
|
||||
bbCheck "[yellow]Yellow Text", "\e[38;5;3mYellow Text\e[0m"
|
||||
bbCheck "[bold red]Bold Red Text", "\e[1;38;5;1mBold Red Text\e[0m"
|
||||
bbCheck "[red]5[/]", "\e[38;5;1m5\e[0m"
|
||||
bbCheck "[bold][red]5","\e[1;38;5;1m5\e[0m"
|
||||
|
||||
test "closing":
|
||||
bbCheck "[bold]Bold[red] Bold Red[/red] Bold Only",
|
||||
"\e[1mBold\e[0m\e[1;31m Bold Red\e[0m\e[1m Bold Only\e[0m"
|
||||
"\e[1mBold\e[0m\e[1;38;5;1m Bold Red\e[0m\e[1m Bold Only\e[0m"
|
||||
|
||||
test "abbreviated":
|
||||
bbCheck "[b]Bold[/] Not Bold", "\e[1mBold\e[0m Not Bold"
|
||||
|
@ -30,10 +30,10 @@ suite "basic":
|
|||
bbCheck "[[red] ignored pattern", "[red] ignored pattern"
|
||||
|
||||
test "newlines":
|
||||
bbCheck "[red]Red Text[/]\nNext Line", "\e[31mRed Text\e[0m\nNext Line"
|
||||
bbCheck "[red]Red Text[/]\nNext Line", "\e[38;5;1mRed Text\e[0m\nNext Line"
|
||||
|
||||
test "on color":
|
||||
bbCheck "[red on yellow]Red on Yellow", "\e[31;43mRed on Yellow\e[0m"
|
||||
bbCheck "[red on yellow]Red on Yellow", "\e[38;5;1;48;5;3mRed on Yellow\e[0m"
|
||||
|
||||
test "concat-ops":
|
||||
check "[red]RED[/]".bb & " plain string" == "[red]RED[/] plain string".bb
|
||||
|
@ -43,8 +43,9 @@ suite "basic":
|
|||
check "a plain string" & "[blue] a blue string".bb ==
|
||||
"a plain string[blue] a blue string".bb
|
||||
|
||||
test "case":
|
||||
bbCheck "[red]no case sensitivity[/RED]", "\e[31mno case sensitivity\e[0m"
|
||||
test "style insensitive":
|
||||
bbCheck "[red]no case sensitivity[/RED]", "\e[38;5;1mno case sensitivity\e[0m"
|
||||
bbCheck "[bright_red]should be BrightRed[/]", "\e[38;5;9mshould be BrightRed\e[0m"
|
||||
|
||||
test "style full":
|
||||
check "[red]Red[/red]".bb == bb("Red", "red")
|
||||
|
@ -53,3 +54,11 @@ suite "basic":
|
|||
test "escape":
|
||||
check bbEscape("[info] brackets") == "[[info] brackets"
|
||||
bbCheck bbEscape("[info] brackets"), "[info] brackets"
|
||||
|
||||
test "fmt":
|
||||
let x = 5
|
||||
check $bbfmt"[red]{x}" == "\e[38;5;1m5\e[0m"
|
||||
|
||||
test "hex":
|
||||
bbCheck "[#FF0000]red", "\e[38;2;255;0;0mred\e[0m"
|
||||
|
||||
|
|
Loading…
Reference in a new issue