added some color tools, readline seems to work

This commit is contained in:
Anthony Scopatz 2016-02-15 01:47:49 -05:00
parent dfd780c560
commit 1cb9ab832b
5 changed files with 2345 additions and 91 deletions

2256
xonsh/ansi_colors.py Normal file

File diff suppressed because it is too large Load diff

View file

@ -5,13 +5,12 @@ from itertools import zip_longest
from difflib import SequenceMatcher
from xonsh import lazyjson
from xonsh.tools import TERM_COLORS
NO_COLOR = TERM_COLORS['NO_COLOR'].replace('\001', '').replace('\002', '')
RED = TERM_COLORS['RED'].replace('\001', '').replace('\002', '')
GREEN = TERM_COLORS['GREEN'].replace('\001', '').replace('\002', '')
BOLD_RED = TERM_COLORS['BOLD_RED'].replace('\001', '').replace('\002', '')
BOLD_GREEN = TERM_COLORS['BOLD_GREEN'].replace('\001', '').replace('\002', '')
#NO_COLOR = TERM_COLORS['NO_COLOR'].replace('\001', '').replace('\002', '')
#RED = TERM_COLORS['RED'].replace('\001', '').replace('\002', '')
#GREEN = TERM_COLORS['GREEN'].replace('\001', '').replace('\002', '')
#BOLD_RED = TERM_COLORS['BOLD_RED'].replace('\001', '').replace('\002', '')
#BOLD_GREEN = TERM_COLORS['BOLD_GREEN'].replace('\001', '').replace('\002', '')
# intern some strings
REPLACE = 'replace'

View file

@ -17,7 +17,7 @@ from collections import MutableMapping, MutableSequence, MutableSet, namedtuple
from xonsh import __version__ as XONSH_VERSION
from xonsh.tools import (
TERM_COLORS, ON_WINDOWS, ON_MAC, ON_LINUX, ON_ARCH, IS_ROOT,
ON_WINDOWS, ON_MAC, ON_LINUX, ON_ARCH, IS_ROOT,
always_true, always_false, ensure_string, is_env_path, str_to_env_path,
env_path_to_str, is_bool, to_bool, bool_to_str, is_history_tuple, to_history_tuple,
history_tuple_to_str, is_float, string_types, is_string, DEFAULT_ENCODING,
@ -81,6 +81,7 @@ DEFAULT_ENSURERS = {
'RAISE_SUBPROC_ERROR': (is_bool, to_bool, bool_to_str),
'TEEPTY_PIPE_DELAY': (is_float, float, str),
'XONSHRC': (is_env_path, str_to_env_path, env_path_to_str),
'XONSH_COLOR_STYLE': (is_string, ensure_string, ensure_string),
'XONSH_ENCODING': (is_string, ensure_string, ensure_string),
'XONSH_ENCODING_ERRORS': (is_string, ensure_string, ensure_string),
'XONSH_HISTORY_SIZE': (is_history_tuple, to_history_tuple, history_tuple_to_str),
@ -195,6 +196,7 @@ DEFAULT_VALUES = {
'xonsh', 'xonshrc'),
os.path.expanduser('~/.xonshrc')) if ON_WINDOWS
else ('/etc/xonshrc', os.path.expanduser('~/.xonshrc'))),
'XONSH_COLOR_STYLE': 'default',
'XONSH_CONFIG_DIR': xonsh_config_dir,
'XONSH_DATA_DIR': xonsh_data_dir,
'XONSH_ENCODING': DEFAULT_ENCODING,
@ -408,6 +410,9 @@ DEFAULT_DOCS = {
'control file if there is a naming collision.', default=(
"On Linux & Mac OSX: ('/etc/xonshrc', '~/.xonshrc')\n"
"On Windows: ('%ALLUSERSPROFILE%\\xonsh\\xonshrc', '~/.xonshrc')")),
'XONSH_COLOR_STYLE': VarDocs(
'Sets the color style for xonsh colors. This is a style name, not '
'a color map.'),
'XONSH_CONFIG_DIR': VarDocs(
'This is location where xonsh configuration information is stored.',
configurable=False, default="'$XDG_CONFIG_HOME/xonsh'"),
@ -882,14 +887,14 @@ def dirty_working_directory(cwd=None):
def branch_color():
"""Return red if the current branch is dirty, otherwise green"""
return (TERM_COLORS['BOLD_INTENSE_RED'] if dirty_working_directory() else
TERM_COLORS['BOLD_INTENSE_GREEN'])
return ('{BOLD_INTENSE_RED}' if dirty_working_directory() else
'{BOLD_INTENSE_GREEN}')
def branch_bg_color():
"""Return red if the current branch is dirty, otherwise green"""
return (TERM_COLORS['BACKGROUND_RED'] if dirty_working_directory() else
TERM_COLORS['BACKGROUND_GREEN'])
return ('{BACKGROUND_RED}' if dirty_working_directory() else
'{BACKGROUND_GREEN}')
def _replace_home(x):
@ -961,7 +966,7 @@ FORMATTER_DICT = dict(
branch_bg_color=branch_bg_color,
current_job=_current_job,
env_name=env_name,
**TERM_COLORS)
)
DEFAULT_VALUES['FORMATTER_DICT'] = dict(FORMATTER_DICT)
_FORMATTER = string.Formatter()
@ -983,13 +988,18 @@ def is_template_string(template, formatter_dict=None):
return included_names <= known_names
def format_prompt(template=DEFAULT_PROMPT, formatter_dict=None):
"""Formats a xonsh prompt template string."""
template = template() if callable(template) else template
def _get_fmtter(formatter_dict=None):
if formatter_dict is None:
fmtter = builtins.__xonsh_env__.get('FORMATTER_DICT', FORMATTER_DICT)
else:
fmtter = formatter_dict
return fmtter
def format_prompt(template=DEFAULT_PROMPT, formatter_dict=None):
"""Formats a xonsh prompt template string."""
template = template() if callable(template) else template
fmtter = _get_fmtter(formatter_dict)
included_names = set(i[1] for i in _FORMATTER.parse(template))
fmt = {}
for name in included_names:
@ -1005,12 +1015,47 @@ def format_prompt(template=DEFAULT_PROMPT, formatter_dict=None):
return template.format(**fmt)
def partial_format_prompt(template=DEFAULT_PROMPT, formatter_dict=None):
"""Formats a xonsh prompt template string."""
template = template() if callable(template) else template
fmtter = _get_fmtter(formatter_dict)
bopen = '{'
bclose = '}'
colon = ':'
expl = '!'
toks = []
for literal, field, spec, conv in _FORMATTER.parse(template):
toks.append(literal)
if field is None:
continue
elif field.startswith('$'):
v = builtins.__xonsh_env__[name[1:]]
v = _FORMATTER.convert_field(v, conv)
v = _FORMATTER.format_field(v, spec)
toks.append(v)
continue
elif field in fmtter:
v = fmtter[field]
val = v() if callable(v) else v
val = '' if val is None else val
toks.append(val)
else:
toks.append(bopen)
toks.append(field)
if conv is not None and len(conv) > 0:
toks.append(expl)
toks.append(conv)
if spec is not None and len(spec) > 0:
toks.append(colon)
toks.append(spec)
toks.append(bclose)
return ''.join(toks)
RE_HIDDEN = re.compile('\001.*?\002')
def multiline_prompt():
def multiline_prompt(curr=''):
"""Returns the filler text for the prompt in multiline scenarios."""
curr = builtins.__xonsh_env__.get('PROMPT')
curr = format_prompt(curr)
line = curr.rsplit('\n', 1)[1] if '\n' in curr else curr
line = RE_HIDDEN.sub('', line) # gets rid of colors
# most prompts end in whitespace, head is the part before that.

View file

@ -12,7 +12,9 @@ from collections import deque
from xonsh import lazyjson
from xonsh.base_shell import BaseShell
from xonsh.tools import ON_WINDOWS, print_color
from xonsh.ansi_colors import partial_color_format
from xonsh.environ import partial_format_prompt, multiline_prompt
from xonsh.tools import ON_WINDOWS, print_color, print_exception
RL_COMPLETION_SUPPRESS_APPEND = RL_LIB = None
RL_CAN_RESIZE = False
@ -96,6 +98,7 @@ class ReadlineShell(BaseShell, Cmd):
**kwargs)
setup_readline()
self._current_indent = ''
self._current_prompt = ''
self.cmdqueue = deque()
def __del__(self):
@ -268,7 +271,26 @@ class ReadlineShell(BaseShell, Cmd):
# This is needed to support some system where line-wrapping doesn't
# work. This is a bug in upstream Python, or possibly readline.
RL_LIB.rl_reset_screen_size()
return super().prompt
#return super().prompt
if self.need_more_lines:
if self.mlprompt is None:
try:
self.mlprompt = multiline_prompt(curr=self._current_prompt)
except Exception: # pylint: disable=broad-except
print_exception()
self.mlprompt = '<multiline prompt error> '
return self.mlprompt
env = builtins.__xonsh_env__ # pylint: disable=no-member
p = env.get('PROMPT')
try:
p = partial_format_prompt(p)
except Exception: # pylint: disable=broad-except
print_exception()
p = partial_color_format(p, style=env.get('XONSH_COLOR_STYLE'),
hide=True)
self._current_prompt = p
self.settitle()
return p
class ReadlineHistoryAdder(Thread):

View file

@ -223,74 +223,6 @@ def get_sep():
os.sep)
TERM_COLORS = {
# Reset
'NO_COLOR': '\001\033[0m\002', # Text Reset
# Regular Colors
'BLACK': '\001\033[0;30m\002', # BLACK
'RED': '\001\033[0;31m\002', # RED
'GREEN': '\001\033[0;32m\002', # GREEN
'YELLOW': '\001\033[0;33m\002', # YELLOW
'BLUE': '\001\033[0;34m\002', # BLUE
'PURPLE': '\001\033[0;35m\002', # PURPLE
'CYAN': '\001\033[0;36m\002', # CYAN
'WHITE': '\001\033[0;37m\002', # WHITE
# Bold
'BOLD_BLACK': '\001\033[1;30m\002', # BLACK
'BOLD_RED': '\001\033[1;31m\002', # RED
'BOLD_GREEN': '\001\033[1;32m\002', # GREEN
'BOLD_YELLOW': '\001\033[1;33m\002', # YELLOW
'BOLD_BLUE': '\001\033[1;34m\002', # BLUE
'BOLD_PURPLE': '\001\033[1;35m\002', # PURPLE
'BOLD_CYAN': '\001\033[1;36m\002', # CYAN
'BOLD_WHITE': '\001\033[1;37m\002', # WHITE
# Underline
'UNDERLINE_BLACK': '\001\033[4;30m\002', # BLACK
'UNDERLINE_RED': '\001\033[4;31m\002', # RED
'UNDERLINE_GREEN': '\001\033[4;32m\002', # GREEN
'UNDERLINE_YELLOW': '\001\033[4;33m\002', # YELLOW
'UNDERLINE_BLUE': '\001\033[4;34m\002', # BLUE
'UNDERLINE_PURPLE': '\001\033[4;35m\002', # PURPLE
'UNDERLINE_CYAN': '\001\033[4;36m\002', # CYAN
'UNDERLINE_WHITE': '\001\033[4;37m\002', # WHITE
# Background
'BACKGROUND_BLACK': '\001\033[40m\002', # BLACK
'BACKGROUND_RED': '\001\033[41m\002', # RED
'BACKGROUND_GREEN': '\001\033[42m\002', # GREEN
'BACKGROUND_YELLOW': '\001\033[43m\002', # YELLOW
'BACKGROUND_BLUE': '\001\033[44m\002', # BLUE
'BACKGROUND_PURPLE': '\001\033[45m\002', # PURPLE
'BACKGROUND_CYAN': '\001\033[46m\002', # CYAN
'BACKGROUND_WHITE': '\001\033[47m\002', # WHITE
# High Intensity
'INTENSE_BLACK': '\001\033[0;90m\002', # BLACK
'INTENSE_RED': '\001\033[0;91m\002', # RED
'INTENSE_GREEN': '\001\033[0;92m\002', # GREEN
'INTENSE_YELLOW': '\001\033[0;93m\002', # YELLOW
'INTENSE_BLUE': '\001\033[0;94m\002', # BLUE
'INTENSE_PURPLE': '\001\033[0;95m\002', # PURPLE
'INTENSE_CYAN': '\001\033[0;96m\002', # CYAN
'INTENSE_WHITE': '\001\033[0;97m\002', # WHITE
# Bold High Intensity
'BOLD_INTENSE_BLACK': '\001\033[1;90m\002', # BLACK
'BOLD_INTENSE_RED': '\001\033[1;91m\002', # RED
'BOLD_INTENSE_GREEN': '\001\033[1;92m\002', # GREEN
'BOLD_INTENSE_YELLOW': '\001\033[1;93m\002', # YELLOW
'BOLD_INTENSE_BLUE': '\001\033[1;94m\002', # BLUE
'BOLD_INTENSE_PURPLE': '\001\033[1;95m\002', # PURPLE
'BOLD_INTENSE_CYAN': '\001\033[1;96m\002', # CYAN
'BOLD_INTENSE_WHITE': '\001\033[1;97m\002', # WHITE
# High Intensity backgrounds
'BACKGROUND_INTENSE_BLACK': '\001\033[0;100m\002', # BLACK
'BACKGROUND_INTENSE_RED': '\001\033[0;101m\002', # RED
'BACKGROUND_INTENSE_GREEN': '\001\033[0;102m\002', # GREEN
'BACKGROUND_INTENSE_YELLOW': '\001\033[0;103m\002', # YELLOW
'BACKGROUND_INTENSE_BLUE': '\001\033[0;104m\002', # BLUE
'BACKGROUND_INTENSE_PURPLE': '\001\033[0;105m\002', # PURPLE
'BACKGROUND_INTENSE_CYAN': '\001\033[0;106m\002', # CYAN
'BACKGROUND_INTENSE_WHITE': '\001\033[0;107m\002', # WHITE
}
def fallback(cond, backup):
"""Decorator for returning the object if cond is true and a backup if cond is false.
@ -756,7 +688,7 @@ def pygments_version():
COLOR_CODE_SPLIT_RE = re.compile(r'(\001\033\[[\d;m]+\002)')
TERM_COLORS_REVERSED = {v: k for k, v in TERM_COLORS.items()}
#TERM_COLORS_REVERSED = {v: k for k, v in TERM_COLORS.items()}
COLOR_NAME_REGEX = re.compile(r'(?:(\w+)_)?(\w+)')
_PT_COLORS = {