diff --git a/evennia/commands/default/account.py b/evennia/commands/default/account.py index 937c956b1c..51693fe180 100644 --- a/evennia/commands/default/account.py +++ b/evennia/commands/default/account.py @@ -691,6 +691,14 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS): # this is used by the parent account_caller = True + # the slices of the ANSI_PARSER lists to use for retrieving the + # relevant color tags to display. Replace if using another schema. + # This command can only show one set of markup. + slice_bright_fg = slice(7, 15) # from ANSI_PARSER.ansi_map + slice_dark_fg = slice(15, 23) # from ANSI_PARSER.ansi_map + slice_dark_bg = slice(-8, None) # from ANSI_PARSER.ansi_map + slice_bright_bg = slice(None, None) # from ANSI_PARSER.ansi_xterm256_bright_bg_map + def table_format(self, table): """ Helper method to format the ansi/xterm256 tables. @@ -716,14 +724,16 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS): ap = ansi.ANSI_PARSER # ansi colors # show all ansi color-related codes - col1 = ["%s%s|n" % (code, code.replace("|", "||")) for code, _ in ap.ansi_map[48:56]] - col2 = ["%s%s|n" % (code, code.replace("|", "||")) for code, _ in ap.ansi_map[56:64]] - col3 = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) - for code, _ in ap.ansi_map[-8:]] - col4 = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) - for code, _ in ap.ansi_bright_bgs[-8:]] - col2.extend(["" for _ in range(len(col1)-len(col2))]) - table = utils.format_table([col1, col2, col4, col3]) + bright_fg = ["%s%s|n" % (code, code.replace("|", "||")) + for code, _ in ap.ansi_map[self.slice_bright_fg]] + dark_fg = ["%s%s|n" % (code, code.replace("|", "||")) + for code, _ in ap.ansi_map[self.slice_dark_fg]] + dark_bg = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) + for code, _ in ap.ansi_map[self.slice_dark_bg]] + bright_bg = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) + for code, _ in ap.ansi_xterm256_bright_bg_map[self.slice_bright_bg]] + dark_fg.extend(["" for _ in range(len(bright_fg)-len(dark_fg))]) + table = utils.format_table([bright_fg, dark_fg, bright_bg, dark_bg]) string = "ANSI colors:" for row in table: string += "\n " + " ".join(row) diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index cd29301090..be58d83fc1 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -992,69 +992,77 @@ from evennia.contrib import color_markups from evennia.utils import ansi -#class TestColorMarkup(EvenniaTest): -# -# def test_default_markup(self): -# reload(ansi) -# self.assertEqual(ansi.parse_ansi("A |rred test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A {rred test"), 'A {rred test') -# self.assertEqual(ansi.parse_ansi("A %crred test"), "A %crred test") -# -# def tearDown(self): -# reload(ansi) -# -# @override_settings( -# COLOR_ANSI_EXTRA_MAP=color_markups.CURLY_COLOR_ANSI_EXTRA_MAP, -# COLOR_XTERM256_EXTRA_FG=color_markups.CURLY_COLOR_XTERM256_EXTRA_FG, -# COLOR_XTERM256_EXTRA_BG=color_markups.CURLY_COLOR_XTERM256_EXTRA_BG, -# COLOR_XTERM256_EXTRA_GFG=color_markups.CURLY_COLOR_XTERM256_EXTRA_GFG, -# COLOR_XTERM256_EXTRA_GBG=color_markups.CURLY_COLOR_XTERM256_EXTRA_GBG, -# COLOR_ANSI_BRIGHT_BG_EXTRA_MAP=color_markups.CURLY_COLOR_ANSI_BRIGHT_BG_EXTRA_MAP) -# def test_curly_markup(self): -# reload(ansi) # this is important since the module is initialized -# self.assertEqual(ansi.parse_ansi("A |rred test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A {rred test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A {[Rred test"), 'A \x1b[41mred test') -# self.assertEqual(ansi.parse_ansi("A |500red test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A {500red test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A {[500red test"), 'A \x1b[41mred test') -# self.assertEqual(ansi.parse_ansi("A {=hgray test"), 'A \x1b[1m\x1b[30mgray test') -# self.assertEqual(ansi.parse_ansi("A {[=hgray test"), 'A \x1b[40mgray test') -# self.assertEqual(ansi.parse_ansi("A %crred test"), "A %crred test") -# # fake ansi bright background -# self.assertEqual(ansi.parse_ansi("A {[rred test"), 'A \x1b[41mred test') -# -# @override_settings( -# COLOR_ANSI_EXTRA_MAP=color_markups.MUX_COLOR_ANSI_EXTRA_MAP, -# COLOR_XTERM256_EXTRA_FG=color_markups.MUX_COLOR_XTERM256_EXTRA_FG, -# COLOR_XTERM256_EXTRA_BG=color_markups.MUX_COLOR_XTERM256_EXTRA_BG, -# COLOR_XTERM256_EXTRA_GFG=color_markups.MUX_COLOR_XTERM256_EXTRA_GFG, -# COLOR_XTERM256_EXTRA_GBG=color_markups.MUX_COLOR_XTERM256_EXTRA_GBG, -# COLOR_ANSI_BRIGHT_BG_EXTRA_MAP=color_markups.MUX_COLOR_ANSI_BRIGHT_BG_EXTRA_MAP) -# def test_mux_markup(self): -# reload(ansi) -# self.assertEqual(ansi.parse_ansi("A |rred test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A %ch%crred test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A %ch%crred test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A |500red test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A %c500red test"), 'A \x1b[1m\x1b[31mred test') -# self.assertEqual(ansi.parse_ansi("A %c[500red test"), 'A \x1b[41mred test') -# self.assertEqual(ansi.parse_ansi("A %c=hgray test"), 'A \x1b[1m\x1b[30mgray test') -# self.assertEqual(ansi.parse_ansi("A %c[=hgray test"), 'A \x1b[40mgray test') -# self.assertEqual(ansi.parse_ansi("A {rred test"), "A {rred test") -# # fake ansi bright background -# self.assertEqual(ansi.parse_ansi("A %ch%cRred test"), 'A \x1b[41mred test') -# -# @override_settings( -# COLOR_ANSI_EXTRA_MAP=color_markups.MUX_COLOR_ANSI_EXTRA_MAP, -# COLOR_XTERM256_EXTRA_FG=color_markups.MUX_COLOR_XTERM256_EXTRA_FG, -# COLOR_XTERM256_EXTRA_BG=color_markups.MUX_COLOR_XTERM256_EXTRA_BG, -# COLOR_XTERM256_EXTRA_GFG=color_markups.MUX_COLOR_XTERM256_EXTRA_GFG, -# COLOR_XTERM256_EXTRA_GBG=color_markups.MUX_COLOR_XTERM256_EXTRA_GBG, -# COLOR_ANSI_BRIGHT_BG_EXTRA_MAP=color_markups.MUX_COLOR_ANSI_BRIGHT_BG_EXTRA_MAP, -# COLOR_NO_DEFAULT=True) -# def test_override(self): -# reload(ansi) -# self.assertEqual(ansi.parse_ansi("A |rred test"), "A |rred test") -# self.assertEqual(ansi.parse_ansi("A {rred test"), "A {rred test") -# self.assertEqual(ansi.parse_ansi("A %ch%crred test"), 'A \x1b[1m\x1b[31mred test') +class TestColorMarkup(EvenniaTest): + + def test_default_markup(self): + reload(ansi) + self.assertEqual(ansi.parse_ansi("A |rred test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A {rred test"), 'A {rred test') + self.assertEqual(ansi.parse_ansi("A %crred test"), "A %crred test") + + @override_settings( + COLOR_ANSI_EXTRA_MAP=[], + COLOR_XTERM256_EXTRA_FG=[], + COLOR_XTERM256_EXTRA_BG=[], + COLOR_XTERM256_EXTRA_GFG=[], + COLOR_XTERM256_EXTRA_GBG=[], + COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP=[], + COLOR_NO_DEFAULT=False) + def tearDown(self): + reload(ansi) + + @override_settings( + COLOR_ANSI_EXTRA_MAP=color_markups.CURLY_COLOR_ANSI_EXTRA_MAP, + COLOR_XTERM256_EXTRA_FG=color_markups.CURLY_COLOR_XTERM256_EXTRA_FG, + COLOR_XTERM256_EXTRA_BG=color_markups.CURLY_COLOR_XTERM256_EXTRA_BG, + COLOR_XTERM256_EXTRA_GFG=color_markups.CURLY_COLOR_XTERM256_EXTRA_GFG, + COLOR_XTERM256_EXTRA_GBG=color_markups.CURLY_COLOR_XTERM256_EXTRA_GBG, + COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP=color_markups.CURLY_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP) + def test_curly_markup(self): + reload(ansi) # this is important since the module is initialized + self.assertEqual(ansi.parse_ansi("A |rred test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A {rred test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A {[Rred test"), 'A \x1b[41mred test') + self.assertEqual(ansi.parse_ansi("A |500red test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A {500red test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A {[500red test"), 'A \x1b[41mred test') + self.assertEqual(ansi.parse_ansi("A {=hgray test"), 'A \x1b[1m\x1b[30mgray test') + self.assertEqual(ansi.parse_ansi("A {[=hgray test"), 'A \x1b[40mgray test') + self.assertEqual(ansi.parse_ansi("A %crred test"), "A %crred test") + # fake ansi bright background + self.assertEqual(ansi.parse_ansi("A {[rred test"), 'A \x1b[41mred test') + + @override_settings( + COLOR_ANSI_EXTRA_MAP=color_markups.MUX_COLOR_ANSI_EXTRA_MAP, + COLOR_XTERM256_EXTRA_FG=color_markups.MUX_COLOR_XTERM256_EXTRA_FG, + COLOR_XTERM256_EXTRA_BG=color_markups.MUX_COLOR_XTERM256_EXTRA_BG, + COLOR_XTERM256_EXTRA_GFG=color_markups.MUX_COLOR_XTERM256_EXTRA_GFG, + COLOR_XTERM256_EXTRA_GBG=color_markups.MUX_COLOR_XTERM256_EXTRA_GBG, + COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP=color_markups.MUX_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP) + def test_mux_markup(self): + reload(ansi) + self.assertEqual(ansi.parse_ansi("A |rred test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A %ch%crred test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A %ch%crred test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A |500red test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A %c500red test"), 'A \x1b[1m\x1b[31mred test') + self.assertEqual(ansi.parse_ansi("A %c[500red test"), 'A \x1b[41mred test') + self.assertEqual(ansi.parse_ansi("A %c=hgray test"), 'A \x1b[1m\x1b[30mgray test') + self.assertEqual(ansi.parse_ansi("A %c[=hgray test"), 'A \x1b[40mgray test') + self.assertEqual(ansi.parse_ansi("A {rred test"), "A {rred test") + # fake ansi bright background + self.assertEqual(ansi.parse_ansi("A %ch%cRred test"), 'A \x1b[41mred test') + + @override_settings( + COLOR_ANSI_EXTRA_MAP=color_markups.MUX_COLOR_ANSI_EXTRA_MAP, + COLOR_XTERM256_EXTRA_FG=color_markups.MUX_COLOR_XTERM256_EXTRA_FG, + COLOR_XTERM256_EXTRA_BG=color_markups.MUX_COLOR_XTERM256_EXTRA_BG, + COLOR_XTERM256_EXTRA_GFG=color_markups.MUX_COLOR_XTERM256_EXTRA_GFG, + COLOR_XTERM256_EXTRA_GBG=color_markups.MUX_COLOR_XTERM256_EXTRA_GBG, + COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP=color_markups.MUX_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP, + COLOR_NO_DEFAULT=True) + def test_override(self): + reload(ansi) + self.assertEqual(ansi.parse_ansi("A |rred test"), "A |rred test") + self.assertEqual(ansi.parse_ansi("A {rred test"), "A {rred test") + self.assertEqual(ansi.parse_ansi("A %ch%crred test"), 'A \x1b[1m\x1b[31mred test') diff --git a/evennia/settings_default.py b/evennia/settings_default.py index cd33a6709b..33c72b70d9 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -354,7 +354,7 @@ COLOR_XTERM256_EXTRA_GBG = [] # ANSI does not support bright backgrounds, so Evennia fakes this by mapping it to # XTERM256 backgrounds where supported. This is a list of tuples that maps the wanted # regex to a valid XTERM256 background tag, such as `(r'{[r', r'{[500')`. -COLOR_ANSI_BRIGHT_BG_EXTRA_MAP = [] +COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [] # If set True, the above color settings *replace* the default |-style color markdown # rather than extend it. COLOR_NO_DEFAULT = False diff --git a/evennia/utils/ansi.py b/evennia/utils/ansi.py index 7c42dde0c6..947b99c5ad 100644 --- a/evennia/utils/ansi.py +++ b/evennia/utils/ansi.py @@ -87,6 +87,125 @@ class ANSIParser(object): an extra | for Merc-style codes """ + # Mapping using {r {n etc + + ansi_map = [ + + # alternative |-format + + (r'|n', ANSI_NORMAL), # reset + (r'|/', ANSI_RETURN), # line break + (r'|-', ANSI_TAB), # tab + (r'|_', ANSI_SPACE), # space + (r'|*', ANSI_INVERSE), # invert + (r'|^', ANSI_BLINK), # blinking text (very annoying and not supported by all clients) + (r'|u', ANSI_UNDERLINE), # underline + + (r'|r', ANSI_HILITE + ANSI_RED), + (r'|g', ANSI_HILITE + ANSI_GREEN), + (r'|y', ANSI_HILITE + ANSI_YELLOW), + (r'|b', ANSI_HILITE + ANSI_BLUE), + (r'|m', ANSI_HILITE + ANSI_MAGENTA), + (r'|c', ANSI_HILITE + ANSI_CYAN), + (r'|w', ANSI_HILITE + ANSI_WHITE), # pure white + (r'|x', ANSI_HILITE + ANSI_BLACK), # dark grey + + (r'|R', ANSI_UNHILITE + ANSI_RED), + (r'|G', ANSI_UNHILITE + ANSI_GREEN), + (r'|Y', ANSI_UNHILITE + ANSI_YELLOW), + (r'|B', ANSI_UNHILITE + ANSI_BLUE), + (r'|M', ANSI_UNHILITE + ANSI_MAGENTA), + (r'|C', ANSI_UNHILITE + ANSI_CYAN), + (r'|W', ANSI_UNHILITE + ANSI_WHITE), # light grey + (r'|X', ANSI_UNHILITE + ANSI_BLACK), # pure black + + # hilight-able colors + (r'|h', ANSI_HILITE), + (r'|H', ANSI_UNHILITE), + + (r'|!R', ANSI_RED), + (r'|!G', ANSI_GREEN), + (r'|!Y', ANSI_YELLOW), + (r'|!B', ANSI_BLUE), + (r'|!M', ANSI_MAGENTA), + (r'|!C', ANSI_CYAN), + (r'|!W', ANSI_WHITE), # light grey + (r'|!X', ANSI_BLACK), # pure black + + # normal ANSI backgrounds + (r'|[R', ANSI_BACK_RED), + (r'|[G', ANSI_BACK_GREEN), + (r'|[Y', ANSI_BACK_YELLOW), + (r'|[B', ANSI_BACK_BLUE), + (r'|[M', ANSI_BACK_MAGENTA), + (r'|[C', ANSI_BACK_CYAN), + (r'|[W', ANSI_BACK_WHITE), # light grey background + (r'|[X', ANSI_BACK_BLACK) # pure black background + ] + + ansi_xterm256_bright_bg_map = [ + # "bright" ANSI backgrounds using xterm256 since ANSI + # standard does not support it (will + # fallback to dark ANSI background colors if xterm256 + # is not supported by client) + + # |-style variations + (r'|[r', r'|[500'), + (r'|[g', r'|[050'), + (r'|[y', r'|[550'), + (r'|[b', r'|[005'), + (r'|[m', r'|[505'), + (r'|[c', r'|[055'), + (r'|[w', r'|[555'), # white background + (r'|[x', r'|[222')] # dark grey background + + # xterm256. These are replaced directly by + # the sub_xterm256 method + + if settings.COLOR_NO_DEFAULT: + ansi_map = settings.COLOR_ANSI_EXTRA_MAP + xterm256_fg = settings.COLOR_XTERM256_EXTRA_FG + xterm256_bg = settings.COLOR_XTERM256_EXTRA_BG + xterm256_gfg = settings.COLOR_XTERM256_EXTRA_GFG + xterm256_gbg = settings.COLOR_XTERM256_EXTRA_GBG + ansi_xterm256_bright_bg_map = settings.COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP + else: + xterm256_fg = [r'\|([0-5])([0-5])([0-5])'] # |123 - foreground colour + xterm256_bg = [r'\|\[([0-5])([0-5])([0-5])'] # |[123 - background colour + xterm256_gfg = [r'\|=([a-z])'] # |=a - greyscale foreground + xterm256_gbg = [r'\|\[=([a-z])'] # |[=a - greyscale background + ansi_map += settings.COLOR_ANSI_EXTRA_MAP + xterm256_fg += settings.COLOR_XTERM256_EXTRA_FG + xterm256_bg += settings.COLOR_XTERM256_EXTRA_BG + xterm256_gfg += settings.COLOR_XTERM256_EXTRA_GFG + xterm256_gbg += settings.COLOR_XTERM256_EXTRA_GBG + ansi_xterm256_bright_bg_map += settings.COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP + + mxp_re = r'\|lc(.*?)\|lt(.*?)\|le' + + # prepare regex matching + brightbg_sub = re.compile(r"|".join([r"(?