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:
parent
e534d5f9a0
commit
ec46465656
7 changed files with 177 additions and 61 deletions
|
|
@ -29,6 +29,7 @@ class DefaultCmdSet(CmdSet):
|
||||||
self.add(general.CmdDrop())
|
self.add(general.CmdDrop())
|
||||||
self.add(general.CmdSay())
|
self.add(general.CmdSay())
|
||||||
self.add(general.CmdAccess())
|
self.add(general.CmdAccess())
|
||||||
|
self.add(general.CmdColorTest())
|
||||||
|
|
||||||
# The help system
|
# The help system
|
||||||
self.add(help.CmdHelp())
|
self.add(help.CmdHelp())
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ from src.commands.default.muxcommand import MuxCommand, MuxCommandOOC
|
||||||
__all__ = ("CmdHome", "CmdLook", "CmdPassword", "CmdNick",
|
__all__ = ("CmdHome", "CmdLook", "CmdPassword", "CmdNick",
|
||||||
"CmdInventory", "CmdGet", "CmdDrop", "CmdQuit", "CmdWho",
|
"CmdInventory", "CmdGet", "CmdDrop", "CmdQuit", "CmdWho",
|
||||||
"CmdSay", "CmdPose", "CmdEncoding", "CmdAccess",
|
"CmdSay", "CmdPose", "CmdEncoding", "CmdAccess",
|
||||||
"CmdOOCLook", "CmdIC", "CmdOOC")
|
"CmdOOCLook", "CmdIC", "CmdOOC", "CmdColorTest")
|
||||||
|
|
||||||
AT_SEARCH_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
AT_SEARCH_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||||
BASE_PLAYER_TYPECLASS = settings.BASE_PLAYER_TYPECLASS
|
BASE_PLAYER_TYPECLASS = settings.BASE_PLAYER_TYPECLASS
|
||||||
|
|
@ -753,3 +753,61 @@ class CmdOOC(MuxCommandOOC):
|
||||||
|
|
||||||
caller.msg("\n{GYou go OOC.{n\n")
|
caller.msg("\n{GYou go OOC.{n\n")
|
||||||
caller.execute_cmd("look")
|
caller.execute_cmd("look")
|
||||||
|
|
||||||
|
class CmdColorTest(MuxCommand):
|
||||||
|
"""
|
||||||
|
testing colors
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
@color ansi|xterm256
|
||||||
|
|
||||||
|
Print a color map along with in-mud color codes, while testing what is supported in your client.
|
||||||
|
Choices are 16-color ansi (supported in most muds) or the 256-color xterm256 standard.
|
||||||
|
No checking is done to determine your client supports color - if not you will
|
||||||
|
see rubbish appear.
|
||||||
|
"""
|
||||||
|
key = "@color"
|
||||||
|
locks = "cmd:all()"
|
||||||
|
help_category = "General"
|
||||||
|
|
||||||
|
def func(self):
|
||||||
|
"Show color tables"
|
||||||
|
|
||||||
|
if not self.args or not self.args in ("ansi", "xterm256"):
|
||||||
|
self.caller.msg("Usage: @color ansi|xterm256")
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.args == "ansi":
|
||||||
|
from src.utils import ansi
|
||||||
|
ap = ansi.ANSI_PARSER
|
||||||
|
# ansi colors
|
||||||
|
# show all ansi color-related codes
|
||||||
|
col1 = ["%s%s{n" % (code, code.replace("{","{{")) for code, _ in ap.ext_ansi_map[:-1]]
|
||||||
|
hi = "%ch"
|
||||||
|
col2 = ["%s%s{n" % (code, code.replace("%", "%%")) for code, _ in ap.mux_ansi_map[:-2]]
|
||||||
|
col3 = ["%s%s{n" % (hi+code, (hi+code).replace("%", "%%")) for code, _ in ap.mux_ansi_map[:-2]]
|
||||||
|
table = utils.format_table([col1, col2, col3], extra_space=1)
|
||||||
|
string = "ANSI colors:"
|
||||||
|
for row in table:
|
||||||
|
string += "\n" + "".join(row)
|
||||||
|
print string
|
||||||
|
self.caller.msg(string)
|
||||||
|
self.caller.msg("{{X and %%cx are black-on-black)")
|
||||||
|
elif self.args == "xterm256":
|
||||||
|
table = [[],[],[],[],[],[],[],[],[],[],[],[]]
|
||||||
|
for ir in range(6):
|
||||||
|
for ig in range(6):
|
||||||
|
for ib in range(6):
|
||||||
|
# foreground table
|
||||||
|
table[ir].append("%%c%i%i%i%s{n" % (ir,ig,ib, "{{%i%i%i" % (ir,ig,ib)))
|
||||||
|
# background table
|
||||||
|
table[6+ir].append("%%cb%i%i%i%%c%i%i%i%s{n" % (ir,ig,ib,
|
||||||
|
5-ir,5-ig,5-ib,
|
||||||
|
"{{b%i%i%i" % (ir,ig,ib)))
|
||||||
|
table = utils.format_table(table)
|
||||||
|
string = "Xterm256 colors:"
|
||||||
|
for row in table:
|
||||||
|
string += "\n" + "".join(row)
|
||||||
|
self.caller.msg(string)
|
||||||
|
self.caller.msg("(e.g. %%c123 and %%cb123 also work)")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -690,6 +690,7 @@ class CmdServerLoad(MuxCommand):
|
||||||
string += "\n{w On-entity Attribute cache usage:{n %5.2f MB (%i items)" % (size, count)
|
string += "\n{w On-entity Attribute cache usage:{n %5.2f MB (%i items)" % (size, count)
|
||||||
caller.msg(string)
|
caller.msg(string)
|
||||||
|
|
||||||
|
|
||||||
# class CmdPs(MuxCommand):
|
# class CmdPs(MuxCommand):
|
||||||
# """
|
# """
|
||||||
# list processes
|
# list processes
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ class WebClientSession(session.Session):
|
||||||
if raw:
|
if raw:
|
||||||
self.client.lineSend(self.suid, string)
|
self.client.lineSend(self.suid, string)
|
||||||
else:
|
else:
|
||||||
self.client.lineSend(self.suid, parse_html(ansi.parse_ansi(string, strip_ansi=nomarkup)))
|
self.client.lineSend(self.suid, parse_html(string, strip_ansi=nomarkup))
|
||||||
return
|
return
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
logger.log_trace()
|
logger.log_trace()
|
||||||
|
|
|
||||||
|
|
@ -75,15 +75,12 @@ class ANSIParser(object):
|
||||||
# MUX-style mappings %cr %cn etc
|
# MUX-style mappings %cr %cn etc
|
||||||
|
|
||||||
self.mux_ansi_map = [
|
self.mux_ansi_map = [
|
||||||
(r'%r', ANSI_RETURN),
|
# commented out by default; they (especially blink) are potentially annoying
|
||||||
(r'%t', ANSI_TAB),
|
#(r'%r', ANSI_RETURN),
|
||||||
(r'%b', ANSI_SPACE),
|
#(r'%t', ANSI_TAB),
|
||||||
(r'%cf', ANSI_BLINK),
|
#(r'%b', ANSI_SPACE),
|
||||||
(r'%ci', ANSI_INVERSE),
|
#(r'%cf', ANSI_BLINK),
|
||||||
(r'%ch', ANSI_HILITE),
|
#(r'%ci', ANSI_INVERSE),
|
||||||
(r'%cn', ANSI_NORMAL),
|
|
||||||
(r'%cx', ANSI_BLACK),
|
|
||||||
(r'%cX', ANSI_BACK_BLACK),
|
|
||||||
(r'%cr', ANSI_RED),
|
(r'%cr', ANSI_RED),
|
||||||
(r'%cR', ANSI_BACK_RED),
|
(r'%cR', ANSI_BACK_RED),
|
||||||
(r'%cg', ANSI_GREEN),
|
(r'%cg', ANSI_GREEN),
|
||||||
|
|
@ -98,6 +95,10 @@ class ANSIParser(object):
|
||||||
(r'%cC', ANSI_BACK_CYAN),
|
(r'%cC', ANSI_BACK_CYAN),
|
||||||
(r'%cw', ANSI_WHITE),
|
(r'%cw', ANSI_WHITE),
|
||||||
(r'%cW', ANSI_BACK_WHITE),
|
(r'%cW', ANSI_BACK_WHITE),
|
||||||
|
(r'%cx', ANSI_BLACK),
|
||||||
|
(r'%cX', ANSI_BACK_BLACK),
|
||||||
|
(r'%ch', ANSI_HILITE),
|
||||||
|
(r'%cn', ANSI_NORMAL),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Expanded mapping {r {n etc
|
# Expanded mapping {r {n etc
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ snippet #577349 on http://code.activestate.com.
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import cgi
|
import cgi
|
||||||
from src.utils import ansi
|
from ansi import *
|
||||||
|
|
||||||
class TextToHTMLparser(object):
|
class TextToHTMLparser(object):
|
||||||
"""
|
"""
|
||||||
|
|
@ -20,47 +20,80 @@ class TextToHTMLparser(object):
|
||||||
|
|
||||||
tabstop = 4
|
tabstop = 4
|
||||||
# mapping html color name <-> ansi code.
|
# mapping html color name <-> ansi code.
|
||||||
# note that \[ is used here since they go into regexes.
|
hilite = ANSI_HILITE
|
||||||
colorcodes = [('white', '\033\[1m\033\[37m'),
|
normal = ANSI_NORMAL
|
||||||
('cyan', '\033\[1m\033\[36m'),
|
underline = ANSI_UNDERLINE
|
||||||
('blue', '\033\[1m\033\[34m'),
|
colorcodes = [
|
||||||
('red', '\033\[1m\033\[31m'),
|
('red', hilite + ANSI_RED),
|
||||||
('magenta', '\033\[1m\033\[35m'),
|
('maroon', ANSI_RED),
|
||||||
('lime', '\033\[1m\033\[32m'),
|
('lime', hilite + ANSI_GREEN),
|
||||||
('yellow', '\033\[1m\033\[33m'),
|
('green', ANSI_GREEN),
|
||||||
('gray', '\033\[37m'),
|
('yellow', hilite + ANSI_YELLOW),
|
||||||
('teal', '\033\[36m'),
|
('olive', ANSI_YELLOW),
|
||||||
('navy', '\033\[34m'),
|
('blue', hilite + ANSI_BLUE),
|
||||||
('maroon', '\033\[31m'),
|
('navy', ANSI_BLUE),
|
||||||
('purple', '\033\[35m'),
|
('magenta', hilite + ANSI_MAGENTA),
|
||||||
('green', '\033\[32m'),
|
('purple', ANSI_MAGENTA),
|
||||||
('olive', '\033\[33m')]
|
('cyan', hilite + ANSI_CYAN),
|
||||||
normalcode = '\033\[0m'
|
('teal', ANSI_CYAN),
|
||||||
bold = '\033\[1m'
|
('white', hilite + ANSI_WHITE), # pure white
|
||||||
underline = '\033\[4m'
|
('gray', ANSI_WHITE), #light grey
|
||||||
codestop = "|".join(co[1] for co in colorcodes + [("", normalcode), ("", bold), ("", underline), ("", "$")])
|
('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)
|
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):
|
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."""
|
Replace ansi colors with html color class names.
|
||||||
for colorname, code in self.colorcodes:
|
Let the client choose how it will display colors, if it wishes to. """
|
||||||
regexp = "(?:%s)(.*?)(?=%s)" % (code, self.codestop)
|
for colorname, regex in self.re_fgs:
|
||||||
text = re.sub(regexp, r'''<span class="%s">\1</span>''' % colorname, text)
|
text = regex.sub(r'''<span class="%s">\1</span>''' % colorname, text)
|
||||||
return re.sub(self.normalcode, "", 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):
|
def re_bold(self, text):
|
||||||
"Clean out superfluous hilights rather than set <strong>to make it match the look of telnet."
|
"Clean out superfluous hilights rather than set <strong>to make it match the look of telnet."
|
||||||
#"Replace ansi hilight with strong text element."
|
return self.re_hilite.sub(r'<strong>\1</strong>', text)
|
||||||
#regexp = "(?:%s)(.*?)(?=%s)" % (self.bold, self.codestop)
|
|
||||||
#return re.sub(regexp, r'<strong>\1</strong>', text)
|
|
||||||
return re.sub(self.bold, "", text)
|
|
||||||
|
|
||||||
def re_underline(self, text):
|
def re_underline(self, text):
|
||||||
"Replace ansi underline with html underline class name."
|
"Replace ansi underline with html underline class name."
|
||||||
regexp = "(?:%s)(.*?)(?=%s)" % (self.underline, self.codestop)
|
return self.re_uline.sub(r'<span class="underline">\1</span>', text)
|
||||||
return re.sub(regexp, r'<span class="underline">\1</span>', text)
|
|
||||||
|
|
||||||
def remove_bells(self, text):
|
def remove_bells(self, text):
|
||||||
"Remove ansi specials"
|
"Remove ansi specials"
|
||||||
|
|
@ -99,15 +132,13 @@ class TextToHTMLparser(object):
|
||||||
t = t.replace(' ', ' ')
|
t = t.replace(' ', ' ')
|
||||||
return t
|
return t
|
||||||
|
|
||||||
def parse(self, text):
|
def parse(self, text, strip_ansi=False):
|
||||||
"""
|
"""
|
||||||
Main access function, converts a text containing
|
Main access function, converts a text containing
|
||||||
ansi codes into html statements.
|
ansi codes into html statements.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# parse everything to ansi first
|
# 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
|
# convert all ansi to html
|
||||||
result = re.sub(self.re_string, self.do_sub, text)
|
result = re.sub(self.re_string, self.do_sub, text)
|
||||||
result = self.re_color(result)
|
result = self.re_color(result)
|
||||||
|
|
@ -118,7 +149,7 @@ class TextToHTMLparser(object):
|
||||||
result = self.remove_backspaces(result)
|
result = self.remove_backspaces(result)
|
||||||
result = self.convert_urls(result)
|
result = self.convert_urls(result)
|
||||||
# clean out eventual ansi that was missed
|
# clean out eventual ansi that was missed
|
||||||
result = ansi.parse_ansi(result, strip_ansi=True)
|
#result = parse_ansi(result, strip_ansi=True)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
@ -128,8 +159,8 @@ HTML_PARSER = TextToHTMLparser()
|
||||||
# Access function
|
# 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
|
Parses a string, replace ansi markup with html
|
||||||
"""
|
"""
|
||||||
return parser.parse(string)
|
return parser.parse(string, strip_ansi=strip_ansi)
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,17 @@ body {
|
||||||
font-family: 'DejaVu Sans Mono', Consolas, Inconsolata, 'Lucida Console', monospace;
|
font-family: 'DejaVu Sans Mono', Consolas, Inconsolata, 'Lucida Console', monospace;
|
||||||
line-height: 1.6em }
|
line-height: 1.6em }
|
||||||
|
|
||||||
|
|
||||||
a:link, a:visited { color: #fff }
|
a:link, a:visited { color: #fff }
|
||||||
a:hover, a:active { color: #ccc }
|
a:hover, a:active { color: #ccc }
|
||||||
|
|
||||||
|
/* Set this to e.g. bolder if wanting to have ansi-highlights bolden
|
||||||
|
* stand-alone text.*/
|
||||||
|
strong {font-weight:normal;}
|
||||||
|
|
||||||
/* Base style for new messages in the main message area */
|
/* Base style for new messages in the main message area */
|
||||||
.msg {
|
.msg {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
padding: .5em .9em;}
|
padding: .5em .9em;}
|
||||||
/*border-bottom: 1px dotted #222 } /*optional line between messages */
|
/*border-bottom: 1px dotted #222 } /*optional line between messages */
|
||||||
|
|
||||||
|
|
@ -40,22 +45,41 @@ a:hover, a:active { color: #ccc }
|
||||||
.err { color: #f00 }
|
.err { color: #f00 }
|
||||||
|
|
||||||
/* Style specific classes corresponding to formatted, narative text. */
|
/* Style specific classes corresponding to formatted, narative text. */
|
||||||
.white { color: white; }
|
|
||||||
.cyan { color: #00FFFF; }
|
|
||||||
.blue { color: blue; }
|
|
||||||
.red { color: red; }
|
.red { color: red; }
|
||||||
.magenta { color: #FF00FF; }
|
|
||||||
.lime { color: lime; }
|
|
||||||
.yellow { color: yellow; }
|
|
||||||
.gray { color: gray; }
|
|
||||||
.teal { color: teal; }
|
|
||||||
.navy { color: navy; }
|
|
||||||
.maroon { color: maroon; }
|
.maroon { color: maroon; }
|
||||||
.purple { color: purple; }
|
.lime { color: lime; }
|
||||||
.green { color: green; }
|
.green { color: green; }
|
||||||
|
.yellow { color: yellow; }
|
||||||
.olive { color: olive; }
|
.olive { color: olive; }
|
||||||
|
.blue { color: blue; }
|
||||||
|
.navy { color: navy; }
|
||||||
|
.magenta { color: #FF00FF; }
|
||||||
|
.purple { color: purple; }
|
||||||
|
.cyan { color: #00FFFF; }
|
||||||
|
.teal { color: teal; }
|
||||||
|
.white { color: white; }
|
||||||
|
.gray { color: gray; }
|
||||||
|
.dimgray {color: #696969;}
|
||||||
|
.black {color: black;}
|
||||||
.underline { text-decoration: underline; }
|
.underline { text-decoration: underline; }
|
||||||
|
|
||||||
|
.bgred { background-color: red;}
|
||||||
|
.bgmaroon { background-color: maroon;}
|
||||||
|
.bglime { background-color: lime;}
|
||||||
|
.bggreen { background-color: green;}
|
||||||
|
.bgyellow { background-color: yellow;}
|
||||||
|
.bgolive { background-color: olive;}
|
||||||
|
.bgblue { background-color: blue;}
|
||||||
|
.bgnavy { background-color: navy;}
|
||||||
|
.bgmagenta { background-color: #FF00FF;}
|
||||||
|
.bgpurple { background-color: purple;}
|
||||||
|
.bgcyan { background-color: #00FFFF;}
|
||||||
|
.bgteal { background-color: teal;}
|
||||||
|
.bgwhite { background-color: white;}
|
||||||
|
.bggray { background-color: gray;}
|
||||||
|
.bgdimgray { background-color: #696969;}
|
||||||
|
.bgblack { background-color: black;}
|
||||||
|
|
||||||
/* Container surrounding entire chat */
|
/* Container surrounding entire chat */
|
||||||
#wrapper {
|
#wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue