alpha-one
Version:
ideas about recurring tasks in Web- and Backend-Application building
378 lines (357 loc) • 10.3 kB
text/coffeescript
############################################################################################################
njs_path = require 'path'
#...........................................................................................................
TRM = require 'coffeenode-trm'
rpr = TRM.rpr.bind TRM
badge = 'ansi256'
log = TRM.get_logger 'plain', badge
info = TRM.get_logger 'info', badge
alert = TRM.get_logger 'alert', badge
debug = TRM.get_logger 'debug', badge
warn = TRM.get_logger 'warn', badge
help = TRM.get_logger 'help', badge
#-----------------------------------------------------------------------------------------------------------
rgb_hex_by_vt100_colorcode =
# Primary 3-bit 8 colors. Unique representation!
'0': '000000'
'1': '800000'
'2': '008000'
'3': '808000'
'4': '000080'
'5': '800080'
'6': '008080'
'7': 'c0c0c0'
# Equivalent "bright" versions of original 8 colors.
'8': '808080'
'9': 'ff0000'
'10': '00ff00'
'11': 'ffff00'
'12': '0000ff'
'13': 'ff00ff'
'14': '00ffff'
'15': 'ffffff'
# Strictly ascending.
'16': '000000'
'17': '00005f'
'18': '000087'
'19': '0000af'
'20': '0000d7'
'21': '0000ff'
'22': '005f00'
'23': '005f5f'
'24': '005f87'
'25': '005faf'
'26': '005fd7'
'27': '005fff'
'28': '008700'
'29': '00875f'
'30': '008787'
'31': '0087af'
'32': '0087d7'
'33': '0087ff'
'34': '00af00'
'35': '00af5f'
'36': '00af87'
'37': '00afaf'
'38': '00afd7'
'39': '00afff'
'40': '00d700'
'41': '00d75f'
'42': '00d787'
'43': '00d7af'
'44': '00d7d7'
'45': '00d7ff'
'46': '00ff00'
'47': '00ff5f'
'48': '00ff87'
'49': '00ffaf'
'50': '00ffd7'
'51': '00ffff'
'52': '5f0000'
'53': '5f005f'
'54': '5f0087'
'55': '5f00af'
'56': '5f00d7'
'57': '5f00ff'
'58': '5f5f00'
'59': '5f5f5f'
'60': '5f5f87'
'61': '5f5faf'
'62': '5f5fd7'
'63': '5f5fff'
'64': '5f8700'
'65': '5f875f'
'66': '5f8787'
'67': '5f87af'
'68': '5f87d7'
'69': '5f87ff'
'70': '5faf00'
'71': '5faf5f'
'72': '5faf87'
'73': '5fafaf'
'74': '5fafd7'
'75': '5fafff'
'76': '5fd700'
'77': '5fd75f'
'78': '5fd787'
'79': '5fd7af'
'80': '5fd7d7'
'81': '5fd7ff'
'82': '5fff00'
'83': '5fff5f'
'84': '5fff87'
'85': '5fffaf'
'86': '5fffd7'
'87': '5fffff'
'88': '870000'
'89': '87005f'
'90': '870087'
'91': '8700af'
'92': '8700d7'
'93': '8700ff'
'94': '875f00'
'95': '875f5f'
'96': '875f87'
'97': '875faf'
'98': '875fd7'
'99': '875fff'
'100': '878700'
'101': '87875f'
'102': '878787'
'103': '8787af'
'104': '8787d7'
'105': '8787ff'
'106': '87af00'
'107': '87af5f'
'108': '87af87'
'109': '87afaf'
'110': '87afd7'
'111': '87afff'
'112': '87d700'
'113': '87d75f'
'114': '87d787'
'115': '87d7af'
'116': '87d7d7'
'117': '87d7ff'
'118': '87ff00'
'119': '87ff5f'
'120': '87ff87'
'121': '87ffaf'
'122': '87ffd7'
'123': '87ffff'
'124': 'af0000'
'125': 'af005f'
'126': 'af0087'
'127': 'af00af'
'128': 'af00d7'
'129': 'af00ff'
'130': 'af5f00'
'131': 'af5f5f'
'132': 'af5f87'
'133': 'af5faf'
'134': 'af5fd7'
'135': 'af5fff'
'136': 'af8700'
'137': 'af875f'
'138': 'af8787'
'139': 'af87af'
'140': 'af87d7'
'141': 'af87ff'
'142': 'afaf00'
'143': 'afaf5f'
'144': 'afaf87'
'145': 'afafaf'
'146': 'afafd7'
'147': 'afafff'
'148': 'afd700'
'149': 'afd75f'
'150': 'afd787'
'151': 'afd7af'
'152': 'afd7d7'
'153': 'afd7ff'
'154': 'afff00'
'155': 'afff5f'
'156': 'afff87'
'157': 'afffaf'
'158': 'afffd7'
'159': 'afffff'
'160': 'd70000'
'161': 'd7005f'
'162': 'd70087'
'163': 'd700af'
'164': 'd700d7'
'165': 'd700ff'
'166': 'd75f00'
'167': 'd75f5f'
'168': 'd75f87'
'169': 'd75faf'
'170': 'd75fd7'
'171': 'd75fff'
'172': 'd78700'
'173': 'd7875f'
'174': 'd78787'
'175': 'd787af'
'176': 'd787d7'
'177': 'd787ff'
'178': 'd7af00'
'179': 'd7af5f'
'180': 'd7af87'
'181': 'd7afaf'
'182': 'd7afd7'
'183': 'd7afff'
'184': 'd7d700'
'185': 'd7d75f'
'186': 'd7d787'
'187': 'd7d7af'
'188': 'd7d7d7'
'189': 'd7d7ff'
'190': 'd7ff00'
'191': 'd7ff5f'
'192': 'd7ff87'
'193': 'd7ffaf'
'194': 'd7ffd7'
'195': 'd7ffff'
'196': 'ff0000'
'197': 'ff005f'
'198': 'ff0087'
'199': 'ff00af'
'200': 'ff00d7'
'201': 'ff00ff'
'202': 'ff5f00'
'203': 'ff5f5f'
'204': 'ff5f87'
'205': 'ff5faf'
'206': 'ff5fd7'
'207': 'ff5fff'
'208': 'ff8700'
'209': 'ff875f'
'210': 'ff8787'
'211': 'ff87af'
'212': 'ff87d7'
'213': 'ff87ff'
'214': 'ffaf00'
'215': 'ffaf5f'
'216': 'ffaf87'
'217': 'ffafaf'
'218': 'ffafd7'
'219': 'ffafff'
'220': 'ffd700'
'221': 'ffd75f'
'222': 'ffd787'
'223': 'ffd7af'
'224': 'ffd7d7'
'225': 'ffd7ff'
'226': 'ffff00'
'227': 'ffff5f'
'228': 'ffff87'
'229': 'ffffaf'
'230': 'ffffd7'
'231': 'ffffff'
# Gray-scale range
'232': '080808'
'233': '121212'
'234': '1c1c1c'
'235': '262626'
'236': '303030'
'237': '3a3a3a'
'238': '444444'
'239': '4e4e4e'
'240': '585858'
'241': '626262'
'242': '6c6c6c'
'243': '767676'
'244': '808080'
'245': '8a8a8a'
'246': '949494'
'247': '9e9e9e'
'248': 'a8a8a8'
'249': 'b2b2b2'
'250': 'bcbcbc'
'251': 'c6c6c6'
'252': 'd0d0d0'
'253': 'dadada'
'254': 'e4e4e4'
'255': 'eeeeee'
#-----------------------------------------------------------------------------------------------------------
ansi_vt100_cc_matcher = /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g
#-----------------------------------------------------------------------------------------------------------
@analyze = ( text ) ->
### Parse ANSI control codes out of `text` and return a list of alternating text / opcode chunks; the
first element of the list and all elements with even indexes will represent (possibly empty) literal
texts, while elements with even indexes will be sub-lists representing control codes. Each control
code looks like `[ 'm', 38, 5, 199 ]` or `[ 'm', 0 ]`, with the opcode letter coming first, followed
by the integer parameters.
Adapted from https://github.com/atdt/escapes.js/blob/master/escapes.js ###
R = []
#.........................................................................................................
loop
position = ansi_vt100_cc_matcher.lastIndex
match = ansi_vt100_cc_matcher.exec text
if match isnt null
R.push text.slice position, match.index
parameters = [ match[ 2 ], ]
parameters.push parseInt x, 10 for x in match[ 1 ].split ';'
R.push parameters
break if ansi_vt100_cc_matcher.lastIndex is 0
#.........................................................................................................
R.push text.slice position if position < text.length
return R
#-----------------------------------------------------------------------------------------------------------
@as_html = ( text, options ) ->
return ( @_as_html text, options ).join ''
#-----------------------------------------------------------------------------------------------------------
@_as_html = ( text, options ) ->
is_ansicode = yes
R = []
open_span_count = 0
css_prefix = if options? and options[ 'css-prefix' ]? then options[ 'css-prefix' ] else 'ansi'
vt100_reset = css_prefix.concat '-m-0'
vt100_clear = css_prefix.concat '-K'
#.........................................................................................................
for chunk in @analyze text
is_ansicode = not is_ansicode
if is_ansicode
css_class = css_prefix.concat '-', chunk.join '-'
if css_class is vt100_reset or css_class is vt100_clear
R.push '</span>'
open_span_count -= 1
else
R.push "<span class='#{css_class}'>"
open_span_count += 1
continue
else
### TAINT must escape ###
R.push chunk
#.........................................................................................................
if open_span_count > 0 and ( options? and options[ 'close-spans' ] )
R.push '</span>' for n in [ 0 ... open_span_count ]
#.........................................................................................................
return R
#-----------------------------------------------------------------------------------------------------------
@get_css_source = ( options ) ->
R = []
css_prefix = if options? and options[ 'css-prefix' ]? then options[ 'css-prefix' ] else 'ansi'
for color_code, rgb_hex of rgb_hex_by_vt100_colorcode
R.push ".#{css_prefix}-m-38-5-#{color_code} { color: #{rgb_hex}; }"
#.........................................................................................................
return R.join '\n'
############################################################################################################
colortext = TRM.pen 'foo', ( TRM.steel 'helo', 42 ), 'bar', ( TRM.pink 'baz' )
console.log colortext
# color_matcher = /\x1b\[(38);(05);([0-9]{1,3})m([^\x1b]*)\x1b\[(?:0m|K)/
# console.log rpr colortext.match color_matcher
# info rpr TRM.pen ( TRM.pink 'helo' ), 'foo', ( TRM.gold 'oops' )
colortext = '\x1b[38;05;199mhelo\x1b[0m foo \x1b[38;05;214moops\x1b[0m'
colortext = '\x1b[38;05;199mhelo\x1b[0m foo \x1b[38;05;214moops'
info @analyze colortext
info @as_html colortext
info @as_html colortext, 'css-prefix': 'xxxx', 'close-spans': yes
debug @get_css_source()
# console.log colortext.split /\x1b/
# recolorize = ( text ) ->
# parts = text.split /\x1b/
# is_colorized = no
# R = []
# for in parts
# if is_colorized
# null