Implemented ansi-colour backgrounds in webclient. Added a new @color command for displaying colour spaces. Also changed a number of other features outlined in Issue 309.

This commit is contained in:
Griatch 2012-10-24 21:41:07 +02:00
parent e534d5f9a0
commit ec46465656
7 changed files with 177 additions and 61 deletions

View file

@ -11,7 +11,7 @@ snippet #577349 on http://code.activestate.com.
import re
import cgi
from src.utils import ansi
from ansi import *
class TextToHTMLparser(object):
"""
@ -20,47 +20,80 @@ class TextToHTMLparser(object):
tabstop = 4
# mapping html color name <-> ansi code.
# note that \[ is used here since they go into regexes.
colorcodes = [('white', '\033\[1m\033\[37m'),
('cyan', '\033\[1m\033\[36m'),
('blue', '\033\[1m\033\[34m'),
('red', '\033\[1m\033\[31m'),
('magenta', '\033\[1m\033\[35m'),
('lime', '\033\[1m\033\[32m'),
('yellow', '\033\[1m\033\[33m'),
('gray', '\033\[37m'),
('teal', '\033\[36m'),
('navy', '\033\[34m'),
('maroon', '\033\[31m'),
('purple', '\033\[35m'),
('green', '\033\[32m'),
('olive', '\033\[33m')]
normalcode = '\033\[0m'
bold = '\033\[1m'
underline = '\033\[4m'
codestop = "|".join(co[1] for co in colorcodes + [("", normalcode), ("", bold), ("", underline), ("", "$")])
hilite = ANSI_HILITE
normal = ANSI_NORMAL
underline = ANSI_UNDERLINE
colorcodes = [
('red', hilite + ANSI_RED),
('maroon', ANSI_RED),
('lime', hilite + ANSI_GREEN),
('green', ANSI_GREEN),
('yellow', hilite + ANSI_YELLOW),
('olive', ANSI_YELLOW),
('blue', hilite + ANSI_BLUE),
('navy', ANSI_BLUE),
('magenta', hilite + ANSI_MAGENTA),
('purple', ANSI_MAGENTA),
('cyan', hilite + ANSI_CYAN),
('teal', ANSI_CYAN),
('white', hilite + ANSI_WHITE), # pure white
('gray', ANSI_WHITE), #light grey
('dimgray', hilite + ANSI_BLACK), #dark grey
('black', ANSI_BLACK), #pure black
]
colorback = [
('bgred', hilite + ANSI_BACK_RED),
('bgmaroon', ANSI_BACK_RED),
('bglime', hilite + ANSI_BACK_GREEN),
('bggreen', ANSI_BACK_GREEN),
('bgyellow', hilite + ANSI_BACK_YELLOW),
('bgolive', ANSI_BACK_YELLOW),
('bgblue', hilite + ANSI_BACK_BLUE),
('bgnavy', ANSI_BACK_BLUE),
('bgmagenta', hilite + ANSI_BACK_MAGENTA),
('bgpurple', ANSI_BACK_MAGENTA),
('bgcyan', hilite + ANSI_BACK_CYAN),
('bgteal', ANSI_BACK_CYAN),
('bgwhite', hilite + ANSI_BACK_WHITE),
('bggray', ANSI_BACK_WHITE),
('bgdimgray', hilite + ANSI_BACK_BLACK),
('bgblack', ANSI_BACK_BLACK),
]
# make sure to escape [
colorcodes = [(c, code.replace("[",r"\[")) for c, code in colorcodes]
colorback = [(c, code.replace("[",r"\[")) for c, code in colorback]
# create stop markers
fgstop = [("", c.replace("[", r"\[")) for c in (normal, hilite, underline)]
bgstop = [("", c.replace("[", r"\[")) for c in (normal,)]
fgstop = "|".join(co[1] for co in colorcodes + fgstop + [("", "$")])
bgstop = "|".join(co[1] for co in colorback + bgstop + [("", "$")])
# pre-compile regexes
re_fgs = [(cname, re.compile("(?:%s)(.*?)(?=%s)" % (code, fgstop))) for cname, code in colorcodes]
re_bgs = [(cname, re.compile("(?:%s)(.*?)(?=%s)" % (code, bgstop))) for cname, code in colorback]
re_normal = re.compile(normal.replace("[", r"\["))
re_hilite = re.compile("(?:%s)(.*)(?=%s)" % (hilite.replace("[", r"\["), fgstop))
re_uline = re.compile("(?:%s)(.*?)(?=%s)" % (ANSI_UNDERLINE.replace("[",r"\["), fgstop))
re_string = re.compile(r'(?P<htmlchars>[<&>])|(?P<space>^[ \t]+)|(?P<lineend>\r\n|\r|\n)', re.S|re.M|re.I)
def re_color(self, text):
"""Replace ansi colors with html color class names.
Let the client choose how it will display colors, if it wishes to."""
for colorname, code in self.colorcodes:
regexp = "(?:%s)(.*?)(?=%s)" % (code, self.codestop)
text = re.sub(regexp, r'''<span class="%s">\1</span>''' % colorname, text)
return re.sub(self.normalcode, "", text)
"""
Replace ansi colors with html color class names.
Let the client choose how it will display colors, if it wishes to. """
for colorname, regex in self.re_fgs:
text = regex.sub(r'''<span class="%s">\1</span>''' % colorname, text)
for bgname, regex in self.re_bgs:
text = regex.sub(r'''<span class="%s">\1</span>''' % bgname, text)
return self.re_normal.sub("", text)
def re_bold(self, text):
"Clean out superfluous hilights rather than set <strong>to make it match the look of telnet."
#"Replace ansi hilight with strong text element."
#regexp = "(?:%s)(.*?)(?=%s)" % (self.bold, self.codestop)
#return re.sub(regexp, r'<strong>\1</strong>', text)
return re.sub(self.bold, "", text)
return self.re_hilite.sub(r'<strong>\1</strong>', text)
def re_underline(self, text):
"Replace ansi underline with html underline class name."
regexp = "(?:%s)(.*?)(?=%s)" % (self.underline, self.codestop)
return re.sub(regexp, r'<span class="underline">\1</span>', text)
return self.re_uline.sub(r'<span class="underline">\1</span>', text)
def remove_bells(self, text):
"Remove ansi specials"
@ -99,15 +132,13 @@ class TextToHTMLparser(object):
t = t.replace(' ', '&nbsp;')
return t
def parse(self, text):
def parse(self, text, strip_ansi=False):
"""
Main access function, converts a text containing
ansi codes into html statements.
"""
# parse everything to ansi first
text = ansi.parse_ansi(text)
text = parse_ansi(text, strip_ansi=strip_ansi, xterm256=False)
# convert all ansi to html
result = re.sub(self.re_string, self.do_sub, text)
result = self.re_color(result)
@ -118,7 +149,7 @@ class TextToHTMLparser(object):
result = self.remove_backspaces(result)
result = self.convert_urls(result)
# clean out eventual ansi that was missed
result = ansi.parse_ansi(result, strip_ansi=True)
#result = parse_ansi(result, strip_ansi=True)
return result
@ -128,8 +159,8 @@ HTML_PARSER = TextToHTMLparser()
# Access function
#
def parse_html(string, parser=HTML_PARSER):
def parse_html(string, strip_ansi=False, parser=HTML_PARSER):
"""
Parses a string, replace ansi markup with html
"""
return parser.parse(string)
return parser.parse(string, strip_ansi=strip_ansi)