; [ʞ] ansi.b
; ~ lexi hale <lexi@hale.su>
; © AGPLv3
; ? a terminal text formatter for boron
; > do read/text %ansi.b
; @ vim: ft=rebol
stdin: open 0
stdout: open 1
stderr: open 2
fmt-code-stack: []
in-list: func [i lst] [ either (find lst i) [true] [false] ]
ansi: context [
escape: to-string #{1B5B}
fmt: "m" with: ";"
style: context [
hl: "1" ul: "4" rv: "7" sl: "3" dim: "2"
]
color: context [
red: "1" green: "2"
yellow: "3" blue: "4"
purple: "5" cyan: "6"
white: "7" black: "0"
]
fg: color bg: color
frame: context [
kind: none
value: none
]
]
fmt-push: func[k v] [ any [
all [
f-kind: in ansi k
f-val: in (do f-kind) v
frame: make ansi/frame [
kind: f-kind
value: f-val
]
append fmt-code-stack frame
] throw 'bad-argument
]]
fmt-pop: does [ pop fmt-code-stack ]
fmt-seq: func[/local] [
active-styles: []
active-colors: context [
fg: none
bg: none
]
foreach frame fmt-code-stack [
either eq? frame/kind 'style [
ifn in-list frame/value active-styles [
append active-styles frame/value
]
] /* or */ [
ck: in active-colors (unbind frame/kind)
set ck frame/value
]
]
style-string: rejoin (map i active-styles [join ";" (do i)])
key: context [
plain: context [ fg: "3" bg: "4" ]
bright: context [ fg: "9" bg: "10" ]
]
foreach i [fg bg] [
code: do (in key/plain i)
color: do (in active-colors i)
if color [
style-string: join style-string rejoin
[";" code do color]
]
]
free active-styles
rejoin [ ansi/escape style-string ansi/fmt ]
]
fmt: func [lst] [
depth: 0
evaluated: map term (join lst fmt-seq) [
case [
paren? term [
fmt-push (first term) (second term)
++ depth fmt-seq
]
word? term [ do term ]
block? term [ fmt term ]
string? term [ term ]
]
]
loop depth [fmt-pop]
rejoin evaluated
]