mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-05 17:00:58 +01:00
initial translation from ANSI codes to xonsh color names
This commit is contained in:
parent
bf1fd1d284
commit
efea8f05dc
3 changed files with 104 additions and 6 deletions
34
tests/test_ansi_colors.py
Normal file
34
tests/test_ansi_colors.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
"""Tests ANSI color tools."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from xonsh.ansi_colors import ansi_color_escape_code_to_name, ansi_reverse_style
|
||||||
|
|
||||||
|
RS = ansi_reverse_style(style='default')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('key, value', [
|
||||||
|
('', 'NO_COLOR'),
|
||||||
|
('31', 'RED'),
|
||||||
|
])
|
||||||
|
def test_ansi_reverse_style(key, value):
|
||||||
|
assert key in RS
|
||||||
|
assert RS[key] == value
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('inp, exp', [
|
||||||
|
('0', ('NO_COLOR',)),
|
||||||
|
('\0010\002', ('NO_COLOR',)),
|
||||||
|
('\033[0m', ('NO_COLOR',)),
|
||||||
|
('\001\033[0m\002', ('NO_COLOR',)),
|
||||||
|
('00;36', ('CYAN',)),
|
||||||
|
('01;31', ('BOLD_RED',)),
|
||||||
|
('04;31', ('UNDERLINE_RED',)),
|
||||||
|
('1;4;31', ('BOLD_UNDERLINE_RED',)),
|
||||||
|
('4;1;31', ('BOLD_UNDERLINE_RED',)),
|
||||||
|
('31;42', ('RED', 'BACKGROUND_GREEN')),
|
||||||
|
('42;31', ('BACKGROUND_GREEN', 'RED')),
|
||||||
|
('40', ('BACKGROUND_BLACK',)),
|
||||||
|
])
|
||||||
|
def test_ansi_color_escape_code_to_name(inp, exp):
|
||||||
|
obs = ansi_color_escape_code_to_name(inp, reversed_style=RS)
|
||||||
|
assert obs == exp
|
|
@ -1,10 +1,11 @@
|
||||||
"""Tools for helping with ANSI color codes."""
|
"""Tools for helping with ANSI color codes."""
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
import builtins
|
import builtins
|
||||||
|
|
||||||
from xonsh.platform import HAS_PYGMENTS
|
from xonsh.platform import HAS_PYGMENTS
|
||||||
from xonsh.lazyasd import LazyDict
|
from xonsh.lazyasd import LazyDict, lazyobject
|
||||||
from xonsh.color_tools import (
|
from xonsh.color_tools import (
|
||||||
RE_BACKGROUND,
|
RE_BACKGROUND,
|
||||||
BASE_XONSH_COLORS,
|
BASE_XONSH_COLORS,
|
||||||
|
@ -114,6 +115,74 @@ def ansi_color_style(style="default"):
|
||||||
return cmap
|
return cmap
|
||||||
|
|
||||||
|
|
||||||
|
def ansi_reverse_style(style='default', return_style=False):
|
||||||
|
"""Reverses an ANSI color style mapping so that escape codes map to
|
||||||
|
colors. Style may either be string or mapping. May also return
|
||||||
|
the style it looked up.
|
||||||
|
"""
|
||||||
|
style = ansi_style_by_name(style) if isinstance(style, str) else style
|
||||||
|
reversed_style = {v: k for k, v in style.items()}
|
||||||
|
# add keys to make this more useful
|
||||||
|
updates = {
|
||||||
|
'1': 'BOLD_',
|
||||||
|
'4': 'UNDERLINE_',
|
||||||
|
'1;4': 'BOLD_UNDERLINE_',
|
||||||
|
'4;1': 'BOLD_UNDERLINE_',
|
||||||
|
}
|
||||||
|
for ec, name in reversed_style.items():
|
||||||
|
no_left_zero = ec.lstrip('0')
|
||||||
|
if no_left_zero.startswith(';'):
|
||||||
|
updates[no_left_zero[1:]] = name
|
||||||
|
elif no_left_zero != ec:
|
||||||
|
updates[no_left_zero] = name
|
||||||
|
reversed_style.update(updates)
|
||||||
|
# return results
|
||||||
|
if return_style:
|
||||||
|
return style, reversed_style
|
||||||
|
else:
|
||||||
|
return reversed_style
|
||||||
|
|
||||||
|
|
||||||
|
@lazyobject
|
||||||
|
def ANSI_ESCAPE_CODE_RE():
|
||||||
|
return re.compile(r'\001?(\033\[)?([0-9;]+)m?\002?')
|
||||||
|
|
||||||
|
|
||||||
|
def ansi_color_escape_code_to_name(escape_code, style='default', reversed_style=None):
|
||||||
|
"""Converts an ASNI color code escape sequence to a tuple of color names
|
||||||
|
in the provided style ('default', by default). For example,
|
||||||
|
'0' becomes ('NO_COLOR',) and '32;41' becomes ('GREEN', 'BACKGROUND_RED').
|
||||||
|
The style keyword may either be a string, in which the style is looked up,
|
||||||
|
or an actual style dict. You can also provide a reversed style mapping,
|
||||||
|
too, which is just the keys/values of the style dict swapped. If reversed
|
||||||
|
style is not provided, it is computed.
|
||||||
|
"""
|
||||||
|
if reversed_style is None:
|
||||||
|
style, reversed_style = ansi_reverse_style(style, return_style=True)
|
||||||
|
# strip some actual escape codes, if needed.
|
||||||
|
ec = ANSI_ESCAPE_CODE_RE.match(escape_code).group(2)
|
||||||
|
names = [reversed_style[e.lstrip('0')] for e in ec.split(';')]
|
||||||
|
# normalize names
|
||||||
|
n = ''
|
||||||
|
norm_names = []
|
||||||
|
for name in names:
|
||||||
|
if name == 'NO_COLOR':
|
||||||
|
# skip '0' entries
|
||||||
|
continue
|
||||||
|
n = n + name if n else name
|
||||||
|
if n == 'UNDERLINE_BOLD_':
|
||||||
|
n = 'BOLD_UNDERLINE_'
|
||||||
|
if n.endswith('_'):
|
||||||
|
continue
|
||||||
|
norm_names.append(n)
|
||||||
|
n = ''
|
||||||
|
# return
|
||||||
|
if len(norm_names) == 0:
|
||||||
|
return ('NO_COLOR',)
|
||||||
|
else:
|
||||||
|
return tuple(norm_names)
|
||||||
|
|
||||||
|
|
||||||
def _ansi_expand_style(cmap):
|
def _ansi_expand_style(cmap):
|
||||||
"""Expands a style in order to more quickly make color map changes."""
|
"""Expands a style in order to more quickly make color map changes."""
|
||||||
for key, val in list(cmap.items()):
|
for key, val in list(cmap.items()):
|
||||||
|
|
|
@ -413,8 +413,3 @@ def make_palette(strings):
|
||||||
t, _, s = t.partition(" ")
|
t, _, s = t.partition(" ")
|
||||||
palette[t] = rgb_to_ints(t)
|
palette[t] = rgb_to_ints(t)
|
||||||
return palette
|
return palette
|
||||||
|
|
||||||
|
|
||||||
@deprecated(deprecated_in="0.5.10", removed_in="0.6.0")
|
|
||||||
def make_pallete(*args, **kwargs):
|
|
||||||
make_palette(*args, **kwargs)
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue