mirror of
https://github.com/daylinmorgan/hwylterm.git
synced 2025-02-23 01:35:50 -06:00
support [color(9)] syntax
This commit is contained in:
parent
a648a8329c
commit
8d5c9bf9e4
4 changed files with 62 additions and 43 deletions
0
bbansi.nim
Normal file
0
bbansi.nim
Normal file
|
@ -7,7 +7,7 @@
|
||||||
{.push raises:[].}
|
{.push raises:[].}
|
||||||
|
|
||||||
import std/[
|
import std/[
|
||||||
macros, os, sequtils, strformat, strutils, terminal
|
macros, os, sequtils, strformat, strscans, strutils, terminal
|
||||||
]
|
]
|
||||||
import ./bbansi/[styles, colors]
|
import ./bbansi/[styles, colors]
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ type
|
||||||
ColorSystem = enum
|
ColorSystem = enum
|
||||||
TrueColor, EightBit, Standard, None
|
TrueColor, EightBit, Standard, None
|
||||||
|
|
||||||
proc checkColorSupport(): BbMode =
|
proc checkColorSupport(file = stdout): BbMode =
|
||||||
|
when defined(bbansiOn):
|
||||||
|
return On
|
||||||
when defined(bbansiOff):
|
when defined(bbansiOff):
|
||||||
return Off
|
return Off
|
||||||
when defined(bbansiNoColor):
|
when defined(bbansiNoColor):
|
||||||
|
@ -28,7 +30,7 @@ proc checkColorSupport(): BbMode =
|
||||||
return On
|
return On
|
||||||
elif getEnv("NO_COLOR") != "":
|
elif getEnv("NO_COLOR") != "":
|
||||||
return NoColor
|
return NoColor
|
||||||
elif (getEnv("TERM") in ["dumb", "unknown"]) or not isatty(stdout):
|
elif (getEnv("TERM") in ["dumb", "unknown"]) or not isatty(file):
|
||||||
return Off
|
return Off
|
||||||
|
|
||||||
proc checkColorSystem(): ColorSystem =
|
proc checkColorSystem(): ColorSystem =
|
||||||
|
@ -44,7 +46,7 @@ proc checkColorSystem(): ColorSystem =
|
||||||
of "16color": Standard
|
of "16color": Standard
|
||||||
else: Standard
|
else: Standard
|
||||||
|
|
||||||
var bbMode* = checkColorSupport()
|
let gbbMode* = checkColorSupport()
|
||||||
let colorSystem* = checkColorSystem()
|
let colorSystem* = checkColorSystem()
|
||||||
|
|
||||||
func firstCapital(s: string): string = s.toLowerAscii().capitalizeAscii()
|
func firstCapital(s: string): string = s.toLowerAscii().capitalizeAscii()
|
||||||
|
@ -69,45 +71,53 @@ macro enumNames(a: typed): untyped =
|
||||||
|
|
||||||
const ColorXTermNames = enumNames(ColorXterm).mapIt(firstCapital(it))
|
const ColorXTermNames = enumNames(ColorXterm).mapIt(firstCapital(it))
|
||||||
const BbStyleNames = enumNames(BbStyle).mapIt(firstCapital(it))
|
const BbStyleNames = enumNames(BbStyle).mapIt(firstCapital(it))
|
||||||
const ColorDigitStrings = (1..255).toSeq().mapIt($it)
|
# const ColorDigitStrings = (1..255).toSeq().mapIt($it)
|
||||||
|
|
||||||
|
func get256Color(s: string): int =
|
||||||
template parseUnsafe(body: untyped): untyped =
|
try:
|
||||||
try: body
|
if scanf(s, "Color($i)", result):
|
||||||
|
if result > 255:
|
||||||
|
result = 0
|
||||||
except: discard
|
except: discard
|
||||||
|
|
||||||
proc parseStyle(codes: var seq[string], style: string) =
|
func parseStyle(mode: BbMode, style: string): string =
|
||||||
var style = normalizeStyle(style)
|
try:
|
||||||
|
var style = normalizeStyle(style)
|
||||||
|
|
||||||
if style in ["B", "I", "U"]:
|
if style in ["B", "I", "U"]:
|
||||||
parseUnsafe: codes.add parseEnum[BbStyleAbbr](style).toCode()
|
return parseEnum[BbStyleAbbr](style).toCode()
|
||||||
elif style in BbStyleNames:
|
elif style in BbStyleNames:
|
||||||
parseUnsafe: codes.add parseEnum[BbStyle](style).toCode()
|
return parseEnum[BbStyle](style).toCode()
|
||||||
|
|
||||||
if not (bbMode == On): return
|
if not (mode == On): return
|
||||||
|
|
||||||
if style in ColorXtermNames:
|
if style in ColorXtermNames:
|
||||||
parseUnsafe: codes.add parseEnum[ColorXterm](style).toCode()
|
return parseEnum[ColorXterm](style).toCode()
|
||||||
elif style.isHex():
|
elif style.isHex():
|
||||||
codes.add style.hexToRgb.toCode()
|
return style.hexToRgb.toCode()
|
||||||
elif style in ColorDigitStrings:
|
elif "Color(" in style:
|
||||||
parseUnsafe: codes.add parseInt(style).toCode()
|
if (let num = style.get256Color(); num > 0):
|
||||||
else:
|
return num.toCode()
|
||||||
when defined(debugBB): echo "unknown style: " & normalizedStyle
|
else:
|
||||||
|
when defined(debugBB): debugEcho "unknown style: " & style
|
||||||
|
except: discard
|
||||||
|
|
||||||
func parseBgStyle(codes: var seq[string], style: string) =
|
func parseBgStyle(mode: BbMode, style: string): string =
|
||||||
|
try:
|
||||||
var style = normalizeStyle(style)
|
var style = normalizeStyle(style)
|
||||||
if style in ColorXtermNames:
|
if style in ColorXtermNames:
|
||||||
parseUnsafe: codes.add parseEnum[ColorXTerm](style).toBgCode()
|
return parseEnum[ColorXTerm](style).toBgCode()
|
||||||
elif style.isHex():
|
elif style.isHex():
|
||||||
codes.add style.hexToRgb().toBgCode()
|
return style.hexToRgb().toBgCode()
|
||||||
elif style in ColorDigitStrings:
|
elif "Color(" in style:
|
||||||
parseUnsafe: codes.add parseInt(style).toBgCode()
|
if (let num = style.get256Color(); num > 0):
|
||||||
|
return num.toBgCode()
|
||||||
else:
|
else:
|
||||||
when defined(debugBB): echo "unknown bg style: " & style
|
when defined(debugBB): debugEcho "unknown style: " & style
|
||||||
|
except: discard
|
||||||
|
|
||||||
proc toAnsiCode*(s: string): string =
|
func toAnsiCode*(mode: BbMode, s: string ): string =
|
||||||
if bbMode == Off: return
|
if mode == Off: return
|
||||||
var
|
var
|
||||||
codes: seq[string]
|
codes: seq[string]
|
||||||
styles: seq[string]
|
styles: seq[string]
|
||||||
|
@ -118,17 +128,21 @@ proc toAnsiCode*(s: string): string =
|
||||||
bgStyle = fgBgSplit[1].strip().toLowerAscii()
|
bgStyle = fgBgSplit[1].strip().toLowerAscii()
|
||||||
else:
|
else:
|
||||||
styles = s.splitWhitespace()
|
styles = s.splitWhitespace()
|
||||||
for style in styles:
|
|
||||||
parseStyle codes, style
|
|
||||||
|
|
||||||
if bbMode == On and bgStyle != "":
|
for style in styles:
|
||||||
parseBgStyle codes, bgStyle
|
let code = parseStyle(mode, style)
|
||||||
|
if code != "": codes.add code
|
||||||
|
|
||||||
|
if mode == On and bgStyle != "":
|
||||||
|
let code = parseBgStyle(mode, bgStyle)
|
||||||
|
if code != "": codes.add code
|
||||||
|
|
||||||
if codes.len > 0:
|
if codes.len > 0:
|
||||||
result.add "\e["
|
result.add "\e["
|
||||||
result.add codes.join ";"
|
result.add codes.join ";"
|
||||||
result.add "m"
|
result.add "m"
|
||||||
|
|
||||||
|
proc toAnsiCode*(s: string): string {.inline.} = toAnsiCode(gBbMode, s)
|
||||||
|
|
||||||
func stripAnsi*(s: string): string =
|
func stripAnsi*(s: string): string =
|
||||||
## remove all ansi escape codes from a string
|
## remove all ansi escape codes from a string
|
||||||
|
@ -264,6 +278,7 @@ func bb*(s: string): BbString =
|
||||||
|
|
||||||
result.closeFinalSpan
|
result.closeFinalSpan
|
||||||
|
|
||||||
|
|
||||||
proc bb*(s: string, style: string): BbString =
|
proc bb*(s: string, style: string): BbString =
|
||||||
bb("[" & style & "]" & s & "[/" & style & "]")
|
bb("[" & style & "]" & s & "[/" & style & "]")
|
||||||
|
|
||||||
|
@ -290,20 +305,23 @@ proc `&`*(x: string, y: BbString): BbString =
|
||||||
func len*(bbs: BbString): int =
|
func len*(bbs: BbString): int =
|
||||||
bbs.plain.len
|
bbs.plain.len
|
||||||
|
|
||||||
proc `$`*(bbs: BbString): string =
|
func toString(bbs: Bbstring, mode: BbMode): string =
|
||||||
if bbMode == Off:
|
if mode == Off:
|
||||||
return bbs.plain
|
return bbs.plain
|
||||||
|
|
||||||
for span in bbs.spans:
|
for span in bbs.spans:
|
||||||
var codes = ""
|
var codes = ""
|
||||||
if span.styles.len > 0:
|
if span.styles.len > 0:
|
||||||
codes = span.styles.join(" ").toAnsiCode
|
codes = toAnsiCode(mode, span.styles.join(" "))
|
||||||
|
|
||||||
result.add codes
|
result.add codes
|
||||||
result.add bbs.plain[span.slice[0] .. span.slice[1]]
|
result.add bbs.plain[span.slice[0] .. span.slice[1]]
|
||||||
|
|
||||||
if codes != "":
|
if codes != "":
|
||||||
result.add toAnsiCode("reset")
|
result.add toAnsiCode(mode, "reset")
|
||||||
|
|
||||||
|
proc `$`*(bbs: BbString): string =
|
||||||
|
bbs.toString(gBbMode)
|
||||||
|
|
||||||
func align*(bs: BbString, count: Natural, padding = ' '): Bbstring =
|
func align*(bs: BbString, count: Natural, padding = ' '): Bbstring =
|
||||||
if bs.len < count:
|
if bs.len < count:
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
{.define: bbansiOn.}
|
||||||
import std/[os, strutils, unittest]
|
import std/[os, strutils, unittest]
|
||||||
|
|
||||||
import hwylterm/bbansi
|
import hwylterm/bbansi
|
||||||
bbMode = On
|
|
||||||
|
|
||||||
template bbCheck(input: string, output: string): untyped =
|
template bbCheck(input: string, output: string): untyped =
|
||||||
check escape($bb(input)) == escape(output)
|
check escape($bb(input)) == escape(output)
|
||||||
|
@ -17,6 +16,8 @@ suite "basic":
|
||||||
bbCheck "[red]5[/]", "\e[38;5;1m5\e[0m"
|
bbCheck "[red]5[/]", "\e[38;5;1m5\e[0m"
|
||||||
bbCheck "[bold][red]5","\e[1;38;5;1m5\e[0m"
|
bbCheck "[bold][red]5","\e[1;38;5;1m5\e[0m"
|
||||||
check "[bold]bold[/bold]" == "bold".bbMarkup("bold")
|
check "[bold]bold[/bold]" == "bold".bbMarkup("bold")
|
||||||
|
bbCheck "[color(9)]red[/color(9)][color(2)]blue[/color(2)]", "\x1B[38;5;9mred\x1B[0m\x1B[38;5;2mblue\x1B[0m"
|
||||||
|
bbCheck "[color(256)]no color![/]", "no color!"
|
||||||
|
|
||||||
test "compile time":
|
test "compile time":
|
||||||
const s = bb"[red]red text"
|
const s = bb"[red]red text"
|
||||||
|
|
4
todo.md
4
todo.md
|
@ -33,8 +33,8 @@
|
||||||
- [x] confirmation proc
|
- [x] confirmation proc
|
||||||
- [ ] basic progress bar
|
- [ ] basic progress bar
|
||||||
- [ ] support for 256 and truecolors
|
- [ ] support for 256 and truecolors
|
||||||
- [ ] support for rgb colors
|
- [x] support for rgb colors
|
||||||
- [ ] modify 256 colors w/parser changes to be `"[color(9)]red"` instead of `[9]red`
|
- [x] modify 256 colors w/parser changes to be `"[color(9)]red"` instead of `[9]red`
|
||||||
- [x] improve color detection [ref](https://github.com/Textualize/rich/blob/4101991898ee7a09fe1706daca24af5e1e054862/rich/console.py#L791)
|
- [x] improve color detection [ref](https://github.com/Textualize/rich/blob/4101991898ee7a09fe1706daca24af5e1e054862/rich/console.py#L791)
|
||||||
|
|
||||||
## testing
|
## testing
|
||||||
|
|
Loading…
Add table
Reference in a new issue