mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 16:34:47 +01:00
added some color tools, readline seems to work
This commit is contained in:
parent
dfd780c560
commit
1cb9ab832b
5 changed files with 2345 additions and 91 deletions
2256
xonsh/ansi_colors.py
Normal file
2256
xonsh/ansi_colors.py
Normal file
File diff suppressed because it is too large
Load diff
|
@ -5,13 +5,12 @@ from itertools import zip_longest
|
||||||
from difflib import SequenceMatcher
|
from difflib import SequenceMatcher
|
||||||
|
|
||||||
from xonsh import lazyjson
|
from xonsh import lazyjson
|
||||||
from xonsh.tools import TERM_COLORS
|
|
||||||
|
|
||||||
NO_COLOR = TERM_COLORS['NO_COLOR'].replace('\001', '').replace('\002', '')
|
#NO_COLOR = TERM_COLORS['NO_COLOR'].replace('\001', '').replace('\002', '')
|
||||||
RED = TERM_COLORS['RED'].replace('\001', '').replace('\002', '')
|
#RED = TERM_COLORS['RED'].replace('\001', '').replace('\002', '')
|
||||||
GREEN = TERM_COLORS['GREEN'].replace('\001', '').replace('\002', '')
|
#GREEN = TERM_COLORS['GREEN'].replace('\001', '').replace('\002', '')
|
||||||
BOLD_RED = TERM_COLORS['BOLD_RED'].replace('\001', '').replace('\002', '')
|
#BOLD_RED = TERM_COLORS['BOLD_RED'].replace('\001', '').replace('\002', '')
|
||||||
BOLD_GREEN = TERM_COLORS['BOLD_GREEN'].replace('\001', '').replace('\002', '')
|
#BOLD_GREEN = TERM_COLORS['BOLD_GREEN'].replace('\001', '').replace('\002', '')
|
||||||
|
|
||||||
# intern some strings
|
# intern some strings
|
||||||
REPLACE = 'replace'
|
REPLACE = 'replace'
|
||||||
|
|
|
@ -17,7 +17,7 @@ from collections import MutableMapping, MutableSequence, MutableSet, namedtuple
|
||||||
|
|
||||||
from xonsh import __version__ as XONSH_VERSION
|
from xonsh import __version__ as XONSH_VERSION
|
||||||
from xonsh.tools import (
|
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,
|
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,
|
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,
|
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),
|
'RAISE_SUBPROC_ERROR': (is_bool, to_bool, bool_to_str),
|
||||||
'TEEPTY_PIPE_DELAY': (is_float, float, str),
|
'TEEPTY_PIPE_DELAY': (is_float, float, str),
|
||||||
'XONSHRC': (is_env_path, str_to_env_path, env_path_to_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': (is_string, ensure_string, ensure_string),
|
||||||
'XONSH_ENCODING_ERRORS': (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),
|
'XONSH_HISTORY_SIZE': (is_history_tuple, to_history_tuple, history_tuple_to_str),
|
||||||
|
@ -195,6 +196,7 @@ DEFAULT_VALUES = {
|
||||||
'xonsh', 'xonshrc'),
|
'xonsh', 'xonshrc'),
|
||||||
os.path.expanduser('~/.xonshrc')) if ON_WINDOWS
|
os.path.expanduser('~/.xonshrc')) if ON_WINDOWS
|
||||||
else ('/etc/xonshrc', os.path.expanduser('~/.xonshrc'))),
|
else ('/etc/xonshrc', os.path.expanduser('~/.xonshrc'))),
|
||||||
|
'XONSH_COLOR_STYLE': 'default',
|
||||||
'XONSH_CONFIG_DIR': xonsh_config_dir,
|
'XONSH_CONFIG_DIR': xonsh_config_dir,
|
||||||
'XONSH_DATA_DIR': xonsh_data_dir,
|
'XONSH_DATA_DIR': xonsh_data_dir,
|
||||||
'XONSH_ENCODING': DEFAULT_ENCODING,
|
'XONSH_ENCODING': DEFAULT_ENCODING,
|
||||||
|
@ -408,6 +410,9 @@ DEFAULT_DOCS = {
|
||||||
'control file if there is a naming collision.', default=(
|
'control file if there is a naming collision.', default=(
|
||||||
"On Linux & Mac OSX: ('/etc/xonshrc', '~/.xonshrc')\n"
|
"On Linux & Mac OSX: ('/etc/xonshrc', '~/.xonshrc')\n"
|
||||||
"On Windows: ('%ALLUSERSPROFILE%\\xonsh\\xonshrc', '~/.xonshrc')")),
|
"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(
|
'XONSH_CONFIG_DIR': VarDocs(
|
||||||
'This is location where xonsh configuration information is stored.',
|
'This is location where xonsh configuration information is stored.',
|
||||||
configurable=False, default="'$XDG_CONFIG_HOME/xonsh'"),
|
configurable=False, default="'$XDG_CONFIG_HOME/xonsh'"),
|
||||||
|
@ -882,14 +887,14 @@ def dirty_working_directory(cwd=None):
|
||||||
|
|
||||||
def branch_color():
|
def branch_color():
|
||||||
"""Return red if the current branch is dirty, otherwise green"""
|
"""Return red if the current branch is dirty, otherwise green"""
|
||||||
return (TERM_COLORS['BOLD_INTENSE_RED'] if dirty_working_directory() else
|
return ('{BOLD_INTENSE_RED}' if dirty_working_directory() else
|
||||||
TERM_COLORS['BOLD_INTENSE_GREEN'])
|
'{BOLD_INTENSE_GREEN}')
|
||||||
|
|
||||||
|
|
||||||
def branch_bg_color():
|
def branch_bg_color():
|
||||||
"""Return red if the current branch is dirty, otherwise green"""
|
"""Return red if the current branch is dirty, otherwise green"""
|
||||||
return (TERM_COLORS['BACKGROUND_RED'] if dirty_working_directory() else
|
return ('{BACKGROUND_RED}' if dirty_working_directory() else
|
||||||
TERM_COLORS['BACKGROUND_GREEN'])
|
'{BACKGROUND_GREEN}')
|
||||||
|
|
||||||
|
|
||||||
def _replace_home(x):
|
def _replace_home(x):
|
||||||
|
@ -961,7 +966,7 @@ FORMATTER_DICT = dict(
|
||||||
branch_bg_color=branch_bg_color,
|
branch_bg_color=branch_bg_color,
|
||||||
current_job=_current_job,
|
current_job=_current_job,
|
||||||
env_name=env_name,
|
env_name=env_name,
|
||||||
**TERM_COLORS)
|
)
|
||||||
DEFAULT_VALUES['FORMATTER_DICT'] = dict(FORMATTER_DICT)
|
DEFAULT_VALUES['FORMATTER_DICT'] = dict(FORMATTER_DICT)
|
||||||
|
|
||||||
_FORMATTER = string.Formatter()
|
_FORMATTER = string.Formatter()
|
||||||
|
@ -983,13 +988,18 @@ def is_template_string(template, formatter_dict=None):
|
||||||
return included_names <= known_names
|
return included_names <= known_names
|
||||||
|
|
||||||
|
|
||||||
def format_prompt(template=DEFAULT_PROMPT, formatter_dict=None):
|
def _get_fmtter(formatter_dict=None):
|
||||||
"""Formats a xonsh prompt template string."""
|
|
||||||
template = template() if callable(template) else template
|
|
||||||
if formatter_dict is None:
|
if formatter_dict is None:
|
||||||
fmtter = builtins.__xonsh_env__.get('FORMATTER_DICT', FORMATTER_DICT)
|
fmtter = builtins.__xonsh_env__.get('FORMATTER_DICT', FORMATTER_DICT)
|
||||||
else:
|
else:
|
||||||
fmtter = formatter_dict
|
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))
|
included_names = set(i[1] for i in _FORMATTER.parse(template))
|
||||||
fmt = {}
|
fmt = {}
|
||||||
for name in included_names:
|
for name in included_names:
|
||||||
|
@ -1005,12 +1015,47 @@ def format_prompt(template=DEFAULT_PROMPT, formatter_dict=None):
|
||||||
return template.format(**fmt)
|
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')
|
RE_HIDDEN = re.compile('\001.*?\002')
|
||||||
|
|
||||||
def multiline_prompt():
|
def multiline_prompt(curr=''):
|
||||||
"""Returns the filler text for the prompt in multiline scenarios."""
|
"""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 = curr.rsplit('\n', 1)[1] if '\n' in curr else curr
|
||||||
line = RE_HIDDEN.sub('', line) # gets rid of colors
|
line = RE_HIDDEN.sub('', line) # gets rid of colors
|
||||||
# most prompts end in whitespace, head is the part before that.
|
# most prompts end in whitespace, head is the part before that.
|
||||||
|
|
|
@ -12,7 +12,9 @@ from collections import deque
|
||||||
|
|
||||||
from xonsh import lazyjson
|
from xonsh import lazyjson
|
||||||
from xonsh.base_shell import BaseShell
|
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_COMPLETION_SUPPRESS_APPEND = RL_LIB = None
|
||||||
RL_CAN_RESIZE = False
|
RL_CAN_RESIZE = False
|
||||||
|
@ -96,6 +98,7 @@ class ReadlineShell(BaseShell, Cmd):
|
||||||
**kwargs)
|
**kwargs)
|
||||||
setup_readline()
|
setup_readline()
|
||||||
self._current_indent = ''
|
self._current_indent = ''
|
||||||
|
self._current_prompt = ''
|
||||||
self.cmdqueue = deque()
|
self.cmdqueue = deque()
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
|
@ -268,7 +271,26 @@ class ReadlineShell(BaseShell, Cmd):
|
||||||
# This is needed to support some system where line-wrapping doesn't
|
# This is needed to support some system where line-wrapping doesn't
|
||||||
# work. This is a bug in upstream Python, or possibly readline.
|
# work. This is a bug in upstream Python, or possibly readline.
|
||||||
RL_LIB.rl_reset_screen_size()
|
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):
|
class ReadlineHistoryAdder(Thread):
|
||||||
|
|
|
@ -223,74 +223,6 @@ def get_sep():
|
||||||
os.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):
|
def fallback(cond, backup):
|
||||||
"""Decorator for returning the object if cond is true and a backup if cond is false.
|
"""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)')
|
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+)')
|
COLOR_NAME_REGEX = re.compile(r'(?:(\w+)_)?(\w+)')
|
||||||
|
|
||||||
_PT_COLORS = {
|
_PT_COLORS = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue