# evennia.utils.ansi

ANSI - Gives colour to text.

Use the codes defined in the ANSIParser class to apply colour to text. The parse_ansi function in this module parses text for markup and strip_ansi removes it.

You should usually not need to call parse_ansi explicitly; it is run by Evennia just before returning data to/from the user. Alternative markup is possible by overriding the parser class (see also contrib/ for deprecated markup schemes).

Supported standards:

- ANSI 8 bright and 8 dark fg (foreground) colors

- ANSI 8 dark bg (background) colors

- ‘ANSI’ 8 bright bg colors ‘faked’ with xterm256 (bright bg not included in ANSI standard)

- Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors

## Markup

ANSI colors: r ed, g reen, y ellow, b lue, m agenta, c yan, n ormal (no color). Capital letters indicate the ‘dark’ variant.

- |r fg bright red

- |R fg dark red

- |[r bg bright red

- |[R bg dark red

- |[R|g bg dark red, fg bright green

    "This is |rRed text|n and this is normal again."

Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5:

- |500 fg bright red

- |050 fg bright green

- |005 fg bright blue

- |110 fg dark brown

- |425 fg pink

- |[431 bg orange

Xterm256 greyscale:

- |=a fg black

- |=g fg dark grey

- |=o fg middle grey

- |=v fg bright grey

- |=z fg white

- |[=r bg middle grey

    "This is |500Red text|n and this is normal again."
    "This is |[=jText on dark grey background"

class `evennia.utils.ansi.``ANSIParser`

  Bases: `object`

  A class that parses ANSI markup to ANSI command sequences

  We also allow to escape colour codes by prepending with an extra |.

  `ansi_map` = [('|n', '\x1b[0m'), ('|/', '\r\n'), ('|-', '\t'), ('|>', ' '), ('|_', ' '), ('|*', '\x1b[7m'), ('|^', '\x1b[5m'), ('|u', '\x1b[4m'), ('|r', '\x1b[1m\x1b[31m'), ('|g', '\x1b[1m\x1b[32m'), ('|y', '\x1b[1m\x1b[33m'), ('|b', '\x1b[1m\x1b[34m'), ('|m', '\x1b[1m\x1b[35m'), ('|c', '\x1b[1m\x1b[36m'), ('|w', '\x1b[1m\x1b[37m'), ('|x', '\x1b[1m\x1b[30m'), ('|R', '\x1b[22m\x1b[31m'), ('|G', '\x1b[22m\x1b[32m'), ('|Y', '\x1b[22m\x1b[33m'), ('|B', '\x1b[22m\x1b[34m'), ('|M', '\x1b[22m\x1b[35m'), ('|C', '\x1b[22m\x1b[36m'), ('|W', '\x1b[22m\x1b[37m'), ('|X', '\x1b[22m\x1b[30m'), ('|h', '\x1b[1m'), ('|H', '\x1b[22m'), ('|!R', '\x1b[31m'), ('|!G', '\x1b[32m'), ('|!Y', '\x1b[33m'), ('|!B', '\x1b[34m'), ('|!M', '\x1b[35m'), ('|!C', '\x1b[36m'), ('|!W', '\x1b[37m'), ('|!X', '\x1b[30m'), ('|[R', '\x1b[41m'), ('|[G', '\x1b[42m'), ('|[Y', '\x1b[43m'), ('|[B', '\x1b[44m'), ('|[M', '\x1b[45m'), ('|[C', '\x1b[46m'), ('|[W', '\x1b[47m'), ('|[X', '\x1b[40m')]
  `ansi_xterm256_bright_bg_map` = [('|[r', '|[500'), ('|[g', '|[050'), ('|[y', '|[550'), ('|[b', '|[005'), ('|[m', '|[505'), ('|[c', '|[055'), ('|[w', '|[555'), ('|[x', '|[222')]
  `xterm256_fg` = ['\\|([0-5])([0-5])([0-5])']
  `xterm256_bg` = ['\\|\\[([0-5])([0-5])([0-5])']
  `xterm256_gfg` = ['\\|=([a-z])']
  `xterm256_gbg` = ['\\|\\[=([a-z])']
  `mxp_re` = '\\|lc(.*?)\\|lt(.*?)\\|le'
  `mxp_url_re` = '\\|lu(.*?)\\|lt(.*?)\\|le'
  `brightbg_sub` = re.compile('(?<!\\|)\\|\\[r|(?<!\\|)\\|\\[g|(?<!\\|)\\|\\[y|(?<!\\|)\\|\\[b|(?<!\\|)\\|\\[m|(?<!\\|)\\|\\[c|(?<!\\|)\\|\\[w|(?<!\\|)\\|\\[x', re.DOTALL)
  `xterm256_fg_sub` = re.compile('\\|([0-5])([0-5])([0-5])', re.DOTALL)
  `xterm256_bg_sub` = re.compile('\\|\\[([0-5])([0-5])([0-5])', re.DOTALL)
  `xterm256_gfg_sub` = re.compile('\\|=([a-z])', re.DOTALL)
  `xterm256_gbg_sub` = re.compile('\\|\\[=([a-z])', re.DOTALL)
  `ansi_sub` = re.compile('\\|n|\\|/|\\|\\-|\\|>|\\|_|\\|\\*|\\|\\^|\\|u|\\|r|\\|g|\\|y|\\|b|\\|m|\\|c|\\|w|\\|x|\\|R|\\|G|\\|Y|\\|B|\\|M|\\|C|\\|W|\\|X|\\|h|\\|H|\\|!R|\\|!G|\\|!Y|\\|!B|\\|!M|\\|!C|\\|!W|\\|!X|\\|\\[R|\\|\\[G, re.DOTALL)
  `mxp_sub` = re.compile('\\|lc(.*?)\\|lt(.*?)\\|le', re.DOTALL)
  `mxp_url_sub` = re.compile('\\|lu(.*?)\\|lt(.*?)\\|le', re.DOTALL)
  `ansi_map_dict` = {'|!B': '\x1b[34m', '|!C': '\x1b[36m', '|!G': '\x1b[32m', '|!M': '\x1b[35m', '|!R': '\x1b[31m', '|!W': '\x1b[37m', '|!X': '\x1b[30m', '|!Y': '\x1b[33m', '|*': '\x1b[7m', '|-': '\t', '|/': '\r\n', '|>': ' ', '|B': '\x1b[22m\x1b[34m', '|C': '\x1b[22m\x1b[36m', '|G': '\x1b[22m\x1b[32m', '|H': '\x1b[22m', '|M': '\x1b[22m\x1b[35m', '|R': '\x1b[22m\x1b[31m', '|W': '\x1b[22m\x1b[37m', '|X': '\x1b[22m\x1b[30m', '|Y': '\x1b[22m\x1b[33m', '|[B': '\x1b[44m', '|[C': '\x1b[46m', '|[G': '\x1b[42m', '|[M': '\x1b[45m', '|[R': '\x1b[41m', '|[W': '\x1b[47m', '|[X': '\x1b[40m', '|[Y': '\x1b[43m', '|^': '\x1b[5m', '|_': ' ', '|b': '\x1b[1m\x1b[34m', '|c': '\x1b[1m\x1b[36m', '|g': '\x1b[1m\x1b[32m', '|h': '\x1b[1m', '|m': '\x1b[1m\x1b[35m', '|n': '\x1b[0m', '|r': '\x1b[1m\x1b[31m', '|u': '\x1b[4m', '|w': '\x1b[1m\x1b[37m', '|x': '\x1b[1m\x1b[30m', '|y': '\x1b[1m\x1b[33m'}
  `ansi_xterm256_bright_bg_map_dict` = {'|[b': '|[005', '|[c': '|[055', '|[g': '|[050', '|[m': '|[505', '|[r': '|[500', '|[w': '|[555', '|[x': '|[222', '|[y': '|[550'}
  `ansi_re` = '\\033\\[[0-9;]+m'
  `ansi_regex` = re.compile('\\033\\[[0-9;]+m')
  `ansi_escapes` = re.compile('({{|\\\\|\\|\\|)', re.DOTALL)
  `unsafe_tokens` = re.compile('\\|\\/|\\|-', re.DOTALL)
  `sub_ansi`(ansimatch)

    Replacer used by re.sub to replace ANSI markers with correct ANSI sequences

    Parameters

      ansimatch (re.matchobject) – The match.

    Returns

      processed (str) – The processed match string.

  `sub_brightbg`(ansimatch)

    Replacer used by re.sub to replace ANSI bright background markers with Xterm256 replacement

    Parameters

      ansimatch (re.matchobject) – The match.

    Returns

      processed (str) – The processed match string.

  `sub_xterm256`(rgbmatch, use_xterm256=False, color_type='fg')

    This is a replacer method called by re.sub with the matched tag. It must return the correct ansi sequence.

    It checks self.do_xterm256 to determine if conversion to standard ANSI should be done or not.

    Parameters

      - rgbmatch (re.matchobject) – The match.

      - use_xterm256 (bool, optional) – Don’t convert 256-colors to 16.

      - color_type (str) – One of ‘fg’, ‘bg’, ‘gfg’, ‘gbg’.

    Returns

      processed (str) – The processed match string.

  `strip_raw_codes`(string)

    Strips raw ANSI codes from a string.

    Parameters

      string (str) – The string to strip.

    Returns

      string (str) – The processed string.

  `strip_mxp`(string)

    Strips all MXP codes from a string.

    Parameters

      string (str) – The string to strip.

    Returns

      string (str) – The processed string.

  `strip_unsafe_tokens`(string)

    Strip explicitly ansi line breaks and tabs.

  `parse_ansi`(string, strip_ansi=False, xterm256=False, mxp=False)

    Parses a string, subbing color codes according to the stored mapping.

    Parameters

      - string (str) – The string to parse.

      - strip_ansi (boolean, optional) – Strip all found ansi markup.

      - xterm256 (boolean, optional) – If actually using xterm256 or if these values should be converted to 16-color ANSI.

      - mxp (boolean, optional) – Parse MXP commands in string.

    Returns

      string (str) – The parsed string.

`evennia.utils.ansi.``parse_ansi`(string, strip_ansi=False, parser=<evennia.utils.ansi.ANSIParser object>, xterm256=False, mxp=False)

  Parses a string, subbing color codes as needed.

  Parameters

    - string (str) – The string to parse.

    - strip_ansi (bool, optional) – Strip all ANSI sequences.

    - parser (ansi.AnsiParser, optional) – A parser instance to use.

    - xterm256 (bool, optional) – Support xterm256 or not.

    - mxp (bool, optional) – Support MXP markup or not.

  Returns

    string (str) – The parsed string.

`evennia.utils.ansi.``strip_ansi`(string, parser=<evennia.utils.ansi.ANSIParser object>)

  Strip all ansi from the string. This handles the Evennia-specific markup.

  Parameters

    - string (str) – The string to strip.

    - parser (ansi.AnsiParser, optional) – The parser to use.

  Returns

    string (str) – The stripped string.

`evennia.utils.ansi.``strip_raw_ansi`(string, parser=<evennia.utils.ansi.ANSIParser object>)

  Remove raw ansi codes from string. This assumes pure ANSI-bytecodes in the string.

  Parameters

    - string (str) – The string to parse.

    - parser (bool, optional) – The parser to use.

  Returns

    string (str) – the stripped string.

`evennia.utils.ansi.``strip_unsafe_tokens`(string, parser=<evennia.utils.ansi.ANSIParser object>)

  Strip markup that can be used to create visual exploits (notably linebreaks and tags)

`evennia.utils.ansi.``strip_mxp`(string, parser=<evennia.utils.ansi.ANSIParser object>)

  Strip MXP markup.

`evennia.utils.ansi.``raw`(string)

  Escapes a string into a form which won’t be colorized by the ansi parser.

  Returns

    string (str) – The raw, escaped string.

class `evennia.utils.ansi.``ANSIMeta`(*args, **kwargs)

  Bases: `type`

  Many functions on ANSIString are just light wrappers around the string base class. We apply them here, as part of the classes construction.

  `__init__`(*args, **kwargs)

    Initialize self. See help(type(self)) for accurate signature.

class `evennia.utils.ansi.``ANSIString`(*args, **kwargs)

  Bases: `str`

  Unicode-like object that is aware of ANSI codes.

  This class can be used nearly identically to strings, in that it will report string length, handle slices, etc, much like a string object would. The methods should be used identically as string methods are.

  There is at least one exception to this (and there may be more, though they have not come up yet). When using ‘’.join() or u’’.join() on an ANSIString, color information will get lost. You must use ANSIString(‘’).join() to preserve color information.

  This implementation isn’t perfectly clean, as it doesn’t really have an understanding of what the codes mean in order to eliminate redundant characters– though cleaning up the strings might end up being inefficient and slow without some C code when dealing with larger values. Such enhancements could be made as an enhancement to ANSI_PARSER if needed, however.

  If one is going to use ANSIString, one should generally avoid converting away from it until one is about to send information on the wire. This is because escape sequences in the string may otherwise already be decoded, and taken literally the second time around.

  `re_format` = re.compile('(?i)(?P<just>(?P<fill>.)?(?P<align>\\<|\\>|\\=|\\^))?(?P<sign>\\+|\\-| )?(?P<alt>\\#)?(?P<zero>0)?(?P<width>\\d+)?(?P<grouping>\\_|\\,)?(?:\\.(?P<precision>\\d+))?(?P<type>b|c|d|e|E|f|F|g|G|n|o|s|x|X, re.IGNORECASE)
  `__init__`(*_, **kwargs)

    When the ANSIString is first initialized, a few internal variables have to be set.

    The first is the parser. It is possible to replace Evennia’s standard ANSI parser with one of your own syntax if you wish, so long as it implements the same interface.

    The second is the _raw_string. This is the original “dumb” string with ansi escapes that ANSIString represents.

    The third thing to set is the _clean_string. This is a string that is devoid of all ANSI Escapes.

    Finally, _code_indexes and _char_indexes are defined. These are lookup tables for which characters in the raw string are related to ANSI escapes, and which are for the readable text.

  `clean`()

    Return a string object without the ANSI escapes.

    Returns

      clean_string (str) – A unicode object with no ANSI escapes.

  `raw`()

    Return a string object with the ANSI escapes.

    Returns

      raw (str) – A unicode object with the raw ANSI escape sequences.

  `partition`(sep, reverse=False)

    Splits once into three sections (with the separator being the middle section)

    We use the same techniques we used in split() to make sure each are colored.

    Parameters

      - sep (str) – The separator to split the string on.

      - reverse (boolean) – Whether to split the string on the last occurrence of the separator rather than the first.

    Returns

      ANSIString – The part of the string before the separator ANSIString: The separator itself ANSIString: The part of the string after the separator.

  `split`(by=None, maxsplit=- 1)

    Splits a string based on a separator.

    Stolen from PyPy’s pure Python string implementation, tweaked for ANSIString.

    PyPy is distributed under the MIT licence. http://opensource.org/licenses/MIT

    Parameters

      - by (str) – A string to search for which will be used to split the string. For instance, ‘,’ for ‘Hello,world’ would result in [‘Hello’, ‘world’]

      - maxsplit (int) – The maximum number of times to split the string. For example, a maxsplit of 2 with a by of ‘,’ on the string ‘Hello,world,test,string’ would result in [‘Hello’, ‘world’, ‘test,string’]

    Returns

      result (list of ANSIStrings) –

      A list of ANSIStrings derived from

        this string.

  `rsplit`(by=None, maxsplit=- 1)

    Like split, but starts from the end of the string rather than the beginning.

    Stolen from PyPy’s pure Python string implementation, tweaked for ANSIString.

    PyPy is distributed under the MIT licence. http://opensource.org/licenses/MIT

    Parameters

      - by (str) – A string to search for which will be used to split the string. For instance, ‘,’ for ‘Hello,world’ would result in [‘Hello’, ‘world’]

      - maxsplit (int) – The maximum number of times to split the string. For example, a maxsplit of 2 with a by of ‘,’ on the string ‘Hello,world,test,string’ would result in [‘Hello,world’, ‘test’, ‘string’]

    Returns

      result (list of ANSIStrings) –

      A list of ANSIStrings derived from

        this string.

  `strip`(chars=None)

    Strip from both ends, taking ANSI markers into account.

    Parameters

      chars (str, optional) – A string containing individual characters to strip off of both ends of the string. By default, any blank spaces are trimmed.

    Returns

      result (ANSIString) –

      A new ANSIString with the ends trimmed of the

        relevant characters.

  `lstrip`(chars=None)

    Strip from the left, taking ANSI markers into account.

    Parameters

      chars (str, optional) – A string containing individual characters to strip off of the left end of the string. By default, any blank spaces are trimmed.

    Returns

      result (ANSIString) –

      A new ANSIString with the left end trimmed of

        the relevant characters.

  `capitalize`(*args, **kwargs)

    Return a capitalized version of the string.

    More specifically, make the first character have upper case and the rest lower case.

  `count`(sub[, start[, end]]) → int

    Return the number of non-overlapping occurrences of substring sub in string S[start:end]. Optional arguments start and end are interpreted as in slice notation.

  `decode`(*args, **kwargs)
  `encode`(*args, **kwargs)

    Encode the string using the codec registered for encoding.

    encoding

      The encoding in which to encode the string.

    errors

      The error handling scheme to use for encoding errors. The default is ‘strict’ meaning that encoding errors raise a UnicodeEncodeError. Other possible values are ‘ignore’, ‘replace’ and ‘xmlcharrefreplace’ as well as any other name registered with codecs.register_error that can handle UnicodeEncodeErrors.

  `endswith`(suffix[, start[, end]]) → bool

    Return True if S ends with the specified suffix, False otherwise. With optional start, test S beginning at that position. With optional end, stop comparing S at that position. suffix can also be a tuple of strings to try.

  `expandtabs`(*args, **kwargs)

    Return a copy where all tab characters are expanded using spaces.

    If tabsize is not given, a tab size of 8 characters is assumed.

  `find`(sub[, start[, end]]) → int

    Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.

    Return -1 on failure.

  `format`(*args, **kwargs) → str

    Return a formatted version of S, using substitutions from args and kwargs. The substitutions are identified by braces (‘{’ and ‘}’).

  `index`(sub[, start[, end]]) → int

    Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.

    Raises ValueError when the substring is not found.

  `isalnum`(*args, **kwargs)

    Return True if the string is an alpha-numeric string, False otherwise.

    A string is alpha-numeric if all characters in the string are alpha-numeric and there is at least one character in the string.

  `isalpha`(*args, **kwargs)

    Return True if the string is an alphabetic string, False otherwise.

    A string is alphabetic if all characters in the string are alphabetic and there is at least one character in the string.

  `isdigit`(*args, **kwargs)

    Return True if the string is a digit string, False otherwise.

    A string is a digit string if all characters in the string are digits and there is at least one character in the string.

  `islower`(*args, **kwargs)

    Return True if the string is a lowercase string, False otherwise.

    A string is lowercase if all cased characters in the string are lowercase and there is at least one cased character in the string.

  `isspace`(*args, **kwargs)

    Return True if the string is a whitespace string, False otherwise.

    A string is whitespace if all characters in the string are whitespace and there is at least one character in the string.

  `istitle`(*args, **kwargs)

    Return True if the string is a title-cased string, False otherwise.

    In a title-cased string, upper- and title-case characters may only follow uncased characters and lowercase characters only cased ones.

  `isupper`(*args, **kwargs)

    Return True if the string is an uppercase string, False otherwise.

    A string is uppercase if all cased characters in the string are uppercase and there is at least one cased character in the string.

  `lower`(*args, **kwargs)

    Return a copy of the string converted to lowercase.

  `replace`(*args, **kwargs)

    Return a copy with all occurrences of substring old replaced by new.

    > count

    >   Maximum number of occurrences to replace. -1 (the default value) means replace all occurrences.

    If the optional argument count is given, only the first count occurrences are replaced.

  `rfind`(sub[, start[, end]]) → int

    Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.

    Return -1 on failure.

  `rindex`(sub[, start[, end]]) → int

    Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.

    Raises ValueError when the substring is not found.

  `rstrip`(chars=None)

    Strip from the right, taking ANSI markers into account.

    Parameters

      chars (str, optional) – A string containing individual characters to strip off of the right end of the string. By default, any blank spaces are trimmed.

    Returns

      result (ANSIString) –

      A new ANSIString with the right end trimmed of

        the relevant characters.

  `startswith`(prefix[, start[, end]]) → bool

    Return True if S starts with the specified prefix, False otherwise. With optional start, test S beginning at that position. With optional end, stop comparing S at that position. prefix can also be a tuple of strings to try.

  `swapcase`(*args, **kwargs)

    Convert uppercase characters to lowercase and lowercase characters to uppercase.

  `translate`(*args, **kwargs)

    Replace each character in the string using the given translation table.

    > table

    >   Translation table, which must be a mapping of Unicode ordinals to Unicode ordinals, strings, or None.

    The table must implement lookup/indexing via __getitem__, for instance a dictionary or list. If this operation raises LookupError, the character is left untouched. Characters mapped to None are deleted.

  `upper`(*args, **kwargs)

    Return a copy of the string converted to uppercase.

  `join`(iterable)

    Joins together strings in an iterable, using this string between each one.

    NOTE: This should always be used for joining strings when ANSIStrings are involved. Otherwise color information will be discarded by python, due to details in the C implementation of strings.

    Parameters

      iterable (list of strings) – A list of strings to join together

    Returns

      ANSIString –

      A single string with all of the iterable’s

        contents concatenated, with this string between each.

    Examples

        >>> ANSIString(', ').join(['up', 'right', 'left', 'down'])
        ANSIString('up, right, left, down')

  `center`(width, fillchar, _difference)

    Center some text with some spaces padding both sides.

    Parameters

      - width (int) – The target width of the output string.

      - fillchar (str) – A single character string to pad the output string with.

    Returns

      result (ANSIString) – A string padded on both ends with fillchar.

  `ljust`(width, fillchar, _difference)

    Left justify some text.

    Parameters

      - width (int) – The target width of the output string.

      - fillchar (str) – A single character string to pad the output string with.

    Returns

      result (ANSIString) – A string padded on the right with fillchar.

  `rjust`(width, fillchar, _difference)

    Right justify some text.

    Parameters

      - width (int) – The target width of the output string.

      - fillchar (str) – A single character string to pad the output string with.

    Returns

      result (ANSIString) – A string padded on the left with fillchar.