Merged nested inlinefuncs from the dev branch. Added |-style ansi-markers. Resolves #818.
This commit is contained in:
parent
492e2e2411
commit
7de036c1d9
5 changed files with 90 additions and 36 deletions
|
|
@ -538,20 +538,17 @@ class CmdColorTest(MuxPlayerCommand):
|
||||||
ap = ansi.ANSI_PARSER
|
ap = ansi.ANSI_PARSER
|
||||||
# ansi colors
|
# ansi colors
|
||||||
# show all ansi color-related codes
|
# show all ansi color-related codes
|
||||||
col1 = ["%s%s{n" % (code, code.replace("{", "{{")) for code, _ in ap.ext_ansi_map[6:14]]
|
col1 = ["%s%s|n" % (code, code.replace("|", "||")) for code, _ in ap.ext_ansi_map[6:14]]
|
||||||
col2 = ["%s%s{n" % (code, code.replace("{", "{{")) for code, _ in ap.ext_ansi_map[14:22]]
|
col2 = ["%s%s|n" % (code, code.replace("|", "||")) for code, _ in ap.ext_ansi_map[14:22]]
|
||||||
col3 = ["%s%s{n" % (code.replace("\\",""), code.replace("{", "{{").replace("\\", "")) for code, _ in ap.ext_ansi_map[-8:]]
|
col3 = ["%s%s|n" % (code.replace("\\",""), code.replace("|", "||").replace("\\", "")) for code, _ in ap.ext_ansi_map[-8:]]
|
||||||
col2.extend(["" for i in range(len(col1)-len(col2))])
|
col2.extend(["" for i in range(len(col1)-len(col2))])
|
||||||
#hi = "%ch"
|
|
||||||
#col2 = ["%s%s{n" % (code, code.replace("%", "%%")) for code, _ in ap.mux_ansi_map[6:]]
|
|
||||||
#col3 = ["%s%s{n" % (hi + code, (hi + code).replace("%", "%%")) for code, _ in ap.mux_ansi_map[3:-2]]
|
|
||||||
table = utils.format_table([col1, col2, col3])
|
table = utils.format_table([col1, col2, col3])
|
||||||
string = "ANSI colors:"
|
string = "ANSI colors:"
|
||||||
for row in table:
|
for row in table:
|
||||||
string += "\n " + " ".join(row)
|
string += "\n " + " ".join(row)
|
||||||
self.msg(string)
|
self.msg(string)
|
||||||
self.msg("{{X : black. {{/ : return, {{- : tab, {{_ : space, {{* : invert, {{u : underline")
|
self.msg("||X : black. ||/ : return, ||- : tab, ||_ : space, ||* : invert, ||u : underline")
|
||||||
self.msg("To combine background and foreground, add background marker last, e.g. {{r{{[b.")
|
self.msg("To combine background and foreground, add background marker last, e.g. ||r||[B.")
|
||||||
|
|
||||||
elif self.args.startswith("x"):
|
elif self.args.startswith("x"):
|
||||||
# show xterm256 table
|
# show xterm256 table
|
||||||
|
|
@ -560,11 +557,11 @@ class CmdColorTest(MuxPlayerCommand):
|
||||||
for ig in range(6):
|
for ig in range(6):
|
||||||
for ib in range(6):
|
for ib in range(6):
|
||||||
# foreground table
|
# foreground table
|
||||||
table[ir].append("{%i%i%i%s{n" % (ir, ig, ib, "{{%i%i%i" % (ir, ig, ib)))
|
table[ir].append("|%i%i%i%s|n" % (ir, ig, ib, "||%i%i%i" % (ir, ig, ib)))
|
||||||
# background table
|
# background table
|
||||||
table[6+ir].append("{[%i%i%i{%i%i%i%s{n" % (ir, ig, ib,
|
table[6+ir].append("|[%i%i%i|%i%i%i%s|n" % (ir, ig, ib,
|
||||||
5 - ir, 5 - ig, 5 - ib,
|
5 - ir, 5 - ig, 5 - ib,
|
||||||
"{{[%i%i%i" % (ir, ig, ib)))
|
"||[%i%i%i" % (ir, ig, ib)))
|
||||||
table = self.table_format(table)
|
table = self.table_format(table)
|
||||||
string = "Xterm256 colors (if not all hues show, your client might not report that it can handle xterm256):"
|
string = "Xterm256 colors (if not all hues show, your client might not report that it can handle xterm256):"
|
||||||
for row in table:
|
for row in table:
|
||||||
|
|
@ -573,7 +570,7 @@ class CmdColorTest(MuxPlayerCommand):
|
||||||
#self.msg("(e.g. %%123 and %%[123 also work)")
|
#self.msg("(e.g. %%123 and %%[123 also work)")
|
||||||
else:
|
else:
|
||||||
# malformed input
|
# malformed input
|
||||||
self.msg("Usage: @color ansi|xterm256")
|
self.msg("Usage: @color ansi||xterm256")
|
||||||
|
|
||||||
|
|
||||||
class CmdQuell(MuxPlayerCommand):
|
class CmdQuell(MuxPlayerCommand):
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ class CommandTest(EvenniaTest):
|
||||||
cmdobj.at_post_cmd()
|
cmdobj.at_post_cmd()
|
||||||
# clean out prettytable sugar
|
# clean out prettytable sugar
|
||||||
stored_msg = [args[0] for name, args, kwargs in receiver.msg.mock_calls]
|
stored_msg = [args[0] for name, args, kwargs in receiver.msg.mock_calls]
|
||||||
returned_msg = "|".join(_RE.sub("", mess) for mess in stored_msg)
|
returned_msg = "||".join(_RE.sub("", mess) for mess in stored_msg)
|
||||||
returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip()
|
returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip()
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()):
|
if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()):
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ ANSI_TAB = "\t"
|
||||||
ANSI_SPACE = " "
|
ANSI_SPACE = " "
|
||||||
|
|
||||||
# Escapes
|
# Escapes
|
||||||
ANSI_ESCAPES = ("{{", "\\\\")
|
ANSI_ESCAPES = ("{{", "\\\\", "\|\|")
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
_PARSE_CACHE = OrderedDict()
|
_PARSE_CACHE = OrderedDict()
|
||||||
|
|
@ -408,14 +408,14 @@ class ANSIParser(object):
|
||||||
|
|
||||||
## |-style variations
|
## |-style variations
|
||||||
|
|
||||||
(r'|[r', r'{[500'),
|
(r'|[r', r'|[500'),
|
||||||
(r'|[g', r'{[050'),
|
(r'|[g', r'|[050'),
|
||||||
(r'|[y', r'{[550'),
|
(r'|[y', r'|[550'),
|
||||||
(r'|[b', r'{[005'),
|
(r'|[b', r'|[005'),
|
||||||
(r'|[m', r'{[505'),
|
(r'|[m', r'|[505'),
|
||||||
(r'|[c', r'{[055'),
|
(r'|[c', r'|[055'),
|
||||||
(r'|[w', r'{[555'), # white background
|
(r'|[w', r'|[555'), # white background
|
||||||
(r'|[x', r'{[222')] # dark grey background
|
(r'|[x', r'|[222')] # dark grey background
|
||||||
|
|
||||||
# xterm256 {123, %c134. These are replaced directly by
|
# xterm256 {123, %c134. These are replaced directly by
|
||||||
# the sub_xterm256 method
|
# the sub_xterm256 method
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ Inline functions (nested form).
|
||||||
This parser accepts nested inlinefunctions on the form
|
This parser accepts nested inlinefunctions on the form
|
||||||
|
|
||||||
```
|
```
|
||||||
$funcname{arg, arg, ...}
|
$funcname(arg, arg, ...)
|
||||||
```
|
```
|
||||||
|
|
||||||
embedded in any text where any arg can be another $funcname{} call.
|
embedded in any text where any arg can be another $funcname{} call.
|
||||||
|
|
@ -69,7 +69,20 @@ from evennia.utils import utils
|
||||||
|
|
||||||
def pad(*args, **kwargs):
|
def pad(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Pad to width. $pad{text, width, align, fillchar}
|
Inlinefunc. Pads text to given width.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str, optional): Text to pad.
|
||||||
|
width (str, optional): Will be converted to integer. Width
|
||||||
|
of padding.
|
||||||
|
align (str, optional): Alignment of padding; one of 'c', 'l' or 'r'.
|
||||||
|
fillchar (str, optional): Character used for padding. Defaults to a space.
|
||||||
|
|
||||||
|
Kwargs:
|
||||||
|
session (Session): Session performing the pad.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`$pad(text, width, align, fillchar)`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
text, width, align, fillchar = "", 78, 'c', ' '
|
text, width, align, fillchar = "", 78, 'c', ' '
|
||||||
|
|
@ -87,7 +100,19 @@ def pad(*args, **kwargs):
|
||||||
|
|
||||||
def crop(*args, **kwargs):
|
def crop(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Crop to width. $crop{text, width=78, suffix='[...]'}
|
Inlinefunc. Crops ingoing text to given widths.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str, optional): Text to crop.
|
||||||
|
width (str, optional): Will be converted to an integer. Width of
|
||||||
|
crop in characters.
|
||||||
|
suffix (str, optional): End string to mark the fact that a part
|
||||||
|
of the string was cropped. Defaults to `[...]`.
|
||||||
|
Kwargs:
|
||||||
|
session (Session): Session performing the crop.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`$crop(text, width=78, suffix='[...]')`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
text, width, suffix = "", 78, "[...]"
|
text, width, suffix = "", 78, "[...]"
|
||||||
|
|
@ -101,6 +126,37 @@ def crop(*args, **kwargs):
|
||||||
return utils.crop(text, width=width, suffix=suffix)
|
return utils.crop(text, width=width, suffix=suffix)
|
||||||
|
|
||||||
|
|
||||||
|
def clr(*args, **kwargs):
|
||||||
|
"""
|
||||||
|
Inlinefunc. Colorizes nested text.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
startclr (str, optional): An ANSI color abbreviation without the
|
||||||
|
prefix `|`, such as `r` (red foreground) or `[r` (red background).
|
||||||
|
text (str, optional): Text
|
||||||
|
endclr (str, optional): The color to use at the end of the string. Defaults
|
||||||
|
to `|n` (reset-color).
|
||||||
|
Kwargs:
|
||||||
|
session (Session): Session object triggering inlinefunc.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`$clr(startclr, text, endclr)`
|
||||||
|
|
||||||
|
"""
|
||||||
|
text = ""
|
||||||
|
nargs = len(args)
|
||||||
|
if nargs > 0:
|
||||||
|
color = args[0].strip()
|
||||||
|
if nargs > 1:
|
||||||
|
text = args[1]
|
||||||
|
text = "|" + color + text
|
||||||
|
if nargs > 2:
|
||||||
|
text += "|" + args[2].strip()
|
||||||
|
else:
|
||||||
|
text += "|n"
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
# we specify a default nomatch function to use if no matching func was
|
# we specify a default nomatch function to use if no matching func was
|
||||||
# found. This will be overloaded by any nomatch function defined in
|
# found. This will be overloaded by any nomatch function defined in
|
||||||
# the imported modules.
|
# the imported modules.
|
||||||
|
|
@ -124,16 +180,16 @@ except AttributeError:
|
||||||
|
|
||||||
# regex definitions
|
# regex definitions
|
||||||
|
|
||||||
_RE_STARTTOKEN = re.compile(r"(?<!\\)\$(\w+)\{") # unescaped $funcname{ (start of function call)
|
_RE_STARTTOKEN = re.compile(r"(?<!\\)\$(\w+)\(") # unescaped $funcname{ (start of function call)
|
||||||
|
|
||||||
_RE_TOKEN = re.compile(r"""
|
_RE_TOKEN = re.compile(r"""
|
||||||
(?<!\\)\'\'\'(?P<singlequote>.*?)(?<!\\)\'\'\'| # unescaped single-triples (escapes all inside them)
|
(?<!\\)\'\'\'(?P<singlequote>.*?)(?<!\\)\'\'\'| # unescaped single-triples (escapes all inside them)
|
||||||
(?<!\\)\"\"\"(?P<doublequote>.*?)(?<!\\)\"\"\"| # unescaped triple quotes (escapes all inside them)
|
(?<!\\)\"\"\"(?P<doublequote>.*?)(?<!\\)\"\"\"| # unescaped normal triple quotes (escapes all inside them)
|
||||||
(?P<comma>(?<!\\)\,)| # unescaped , (argument separator)
|
(?P<comma>(?<!\\)\,)| # unescaped , (argument separator)
|
||||||
(?P<end>(?<!\\)\})| # unescaped } (end of function call)
|
(?P<end>(?<!\\)\))| # unescaped } (end of function call)
|
||||||
(?P<start>(?<!\\)\$\w+\{)| # unescaped $funcname{ (start of function call)
|
(?P<start>(?<!\\)\$\w+\()| # unescaped $funcname{ (start of function call)
|
||||||
(?P<escaped>\\'|\\"|\\\)|\\$\w+\{)| # escaped tokens should re-appear in text
|
(?P<escaped>\\'|\\"|\\\)|\\$\w+\()| # escaped tokens should re-appear in text
|
||||||
(?P<rest>[\w\s.-\/#!%\^&\*;:=\-_`~()\[\]]+) # everything else should also be included""",
|
(?P<rest>[\w\s.-\/#!%\^&\*;:=\-_`~\(}{\[\]]+) # everything else should also be included""",
|
||||||
re.UNICODE + re.IGNORECASE + re.VERBOSE + re.DOTALL)
|
re.UNICODE + re.IGNORECASE + re.VERBOSE + re.DOTALL)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -268,7 +324,7 @@ def parse_inlinefunc(string, strip=False, **kwargs):
|
||||||
_PARSING_CACHE[string] = stack
|
_PARSING_CACHE[string] = stack
|
||||||
|
|
||||||
# run the stack recursively
|
# run the stack recursively
|
||||||
def _run_stack(item):
|
def _run_stack(item, depth=0):
|
||||||
retval = item
|
retval = item
|
||||||
if isinstance(item, tuple):
|
if isinstance(item, tuple):
|
||||||
if strip:
|
if strip:
|
||||||
|
|
@ -282,8 +338,9 @@ def parse_inlinefunc(string, strip=False, **kwargs):
|
||||||
args.append("")
|
args.append("")
|
||||||
else:
|
else:
|
||||||
# all other args should merge into one string
|
# all other args should merge into one string
|
||||||
args[-1] += _run_stack(arg)
|
args[-1] += _run_stack(arg, depth=depth+1)
|
||||||
# execute the inlinefunc at this point or strip it.
|
# execute the inlinefunc at this point or strip it.
|
||||||
|
kwargs["inlinefunc_stack_depth"] = depth
|
||||||
retval = "" if strip else func(*args, **kwargs)
|
retval = "" if strip else func(*args, **kwargs)
|
||||||
return utils.to_str(retval, force_string=True)
|
return utils.to_str(retval, force_string=True)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -326,15 +326,15 @@ class TestNestedInlineFuncs(TestCase):
|
||||||
|
|
||||||
def test_single_func(self):
|
def test_single_func(self):
|
||||||
self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
|
self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
|
||||||
"this is a test with $pad{centered, 20} text in it."),
|
"this is a test with $pad(centered, 20) text in it."),
|
||||||
"this is a test with centered text in it.")
|
"this is a test with centered text in it.")
|
||||||
|
|
||||||
def test_nested(self):
|
def test_nested(self):
|
||||||
self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
|
self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
|
||||||
"this $crop{is a test with $pad{padded, 20} text in $pad{pad2, 10} a crop, 80}"),
|
"this $crop(is a test with $pad(padded, 20) text in $pad(pad2, 10) a crop, 80)"),
|
||||||
"this is a test with padded text in pad2 a crop")
|
"this is a test with padded text in pad2 a crop")
|
||||||
|
|
||||||
def test_escaped(self):
|
def test_escaped(self):
|
||||||
self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
|
self.assertEqual(nested_inlinefuncs.parse_inlinefunc(
|
||||||
"this should be $pad{'''escaped,''' and \"\"\"instead,\"\"\" cropped $crop{with a long,5} text., 80}"),
|
"this should be $pad('''escaped,''' and \"\"\"instead,\"\"\" cropped $crop(with a long,5) text., 80)"),
|
||||||
"this should be escaped, and instead, cropped with text. ")
|
"this should be escaped, and instead, cropped with text. ")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue