Merge pull request #749 from scopatz/fix_colors_for_cmd_exe

Fix colors for cmd exe
This commit is contained in:
Anthony Scopatz 2016-03-29 14:18:08 -04:00
commit 58e5ff61d5
5 changed files with 112 additions and 20 deletions

View file

@ -9,7 +9,11 @@ Current Developments
* Added a new shell type ``'none'``, used to avoid importing ``readline`` or
``prompt_toolkit`` when running scripts or running a single command.
* New: `sudo` functionality on Windows through an alias
* Automatically enhance colors for readability in the default terminal (cmd.exe)
on Windows. This functionality can be enabled/disabled with the
$INTENSIFY_COLORS_ON_WIN environment variable.
**Changed:**
* Running scripts through xonsh (or running a single command with ``-c``) no

View file

@ -25,7 +25,8 @@ from xonsh.tools import (
history_tuple_to_str, is_float, string_types, is_string, DEFAULT_ENCODING,
is_completions_display_value, to_completions_display_value, is_string_set,
csv_to_set, set_to_csv, get_sep, is_int, is_bool_seq, csv_to_bool_seq,
bool_seq_to_csv, DefaultNotGiven, setup_win_unicode_console
bool_seq_to_csv, DefaultNotGiven, setup_win_unicode_console,
intensify_colors_on_win_setter
)
from xonsh.dirstack import _get_cwd
from xonsh.foreign_shells import DEFAULT_SHELLS, load_foreign_envs
@ -69,6 +70,7 @@ DEFAULT_ENSURERS = {
'FORCE_POSIX_PATHS': (is_bool, to_bool, bool_to_str),
'HISTCONTROL': (is_string_set, csv_to_set, set_to_csv),
'IGNOREEOF': (is_bool, to_bool, bool_to_str),
'INTENSIFY_COLORS_ON_WIN':(always_false, intensify_colors_on_win_setter, bool_to_str),
'LC_COLLATE': (always_false, locale_convert('LC_COLLATE'), ensure_string),
'LC_CTYPE': (always_false, locale_convert('LC_CTYPE'), ensure_string),
'LC_MESSAGES': (always_false, locale_convert('LC_MESSAGES'), ensure_string),
@ -169,6 +171,7 @@ DEFAULT_VALUES = {
'HISTCONTROL': set(),
'IGNOREEOF': False,
'INDENT': ' ',
'INTENSIFY_COLORS_ON_WIN': True,
'LC_CTYPE': locale.setlocale(locale.LC_CTYPE),
'LC_COLLATE': locale.setlocale(locale.LC_COLLATE),
'LC_TIME': locale.setlocale(locale.LC_TIME),
@ -181,8 +184,6 @@ DEFAULT_VALUES = {
'PATH': (),
'PATHEXT': (),
'PROMPT': DEFAULT_PROMPT,
'PROMPT_TOOLKIT_COLORS': {},
'PROMPT_TOOLKIT_STYLES': None,
'PUSHD_MINUS': False,
'PUSHD_SILENT': False,
'RAISE_SUBPROC_ERROR': False,
@ -309,6 +310,10 @@ DEFAULT_DOCS = {
"exit status) to not be added to the history list."),
'IGNOREEOF': VarDocs('Prevents Ctrl-D from exiting the shell.'),
'INDENT': VarDocs('Indentation string for multiline input'),
'INTENSIFY_COLORS_ON_WIN': VarDocs('Enhance style colors for readability '
'when using the default terminal (cmd.exe) on winodws. Blue colors, '
'which are hard to read, are replaced with cyan. Other colors are '
'generally replaced by their bright counter parts.'),
'LOADED_CONFIG': VarDocs('Whether or not the xonsh config file was loaded',
configurable=False),
'LOADED_RC_FILES': VarDocs(
@ -335,17 +340,6 @@ DEFAULT_DOCS = {
"auto-formatted, see 'Customizing the Prompt' at "
'http://xon.sh/tutorial.html#customizing-the-prompt.',
default='xonsh.environ.DEFAULT_PROMPT'),
'PROMPT_TOOLKIT_COLORS': VarDocs(
'This is a mapping of from color names to HTML color codes. Whenever '
'prompt-toolkit would color a word a particular color (in the prompt, '
'or in syntax highlighting), it will use the value specified here to '
'represent that color, instead of its default. If a color is not '
'specified here, prompt-toolkit uses the colors from '
"'xonsh.tools._PT_COLORS'.", configurable=False),
'PROMPT_TOOLKIT_STYLES': VarDocs(
'This is a mapping of pygments tokens to user-specified styles for '
'prompt-toolkit. See the prompt-toolkit and pygments documentation '
'for more details. If None, this is skipped.', configurable=False),
'PUSHD_MINUS': VarDocs(
'Flag for directory pushing functionality. False is the normal '
'behavior.'),

View file

@ -16,6 +16,8 @@ from pygments.style import Style
from pygments.styles import get_style_by_name
import pygments.util
from xonsh.tools import (ON_WINDOWS, intensify_colors_for_cmd_exe,
expand_gray_colors_for_cmd_exe)
class XonshSubprocLexer(BashLexer):
"""Lexer for xonsh subproc mode."""
@ -281,7 +283,8 @@ class XonshStyle(Style):
style_name : str, optional
The style name to initialize with.
"""
self.trap = {} # for custom colors
self.trap = {} # for traping custom colors set by user
self._smap = {}
self._style_name = ''
self.style_name = style_name
super().__init__()
@ -301,17 +304,34 @@ class XonshStyle(Style):
RuntimeWarning)
cmap = DEFAULT_STYLE
try:
smap = get_style_by_name(value)().styles
self._smap = get_style_by_name(value)().styles.copy()
except (ImportError, pygments.util.ClassNotFound):
smap = XONSH_BASE_STYLE
compound = CompoundColorMap(ChainMap(self.trap, cmap, PTK_STYLE, smap))
self.styles = ChainMap(self.trap, cmap, PTK_STYLE, smap, compound)
self._smap = XONSH_BASE_STYLE.copy()
compound = CompoundColorMap(ChainMap(self.trap, cmap, PTK_STYLE, self._smap))
self.styles = ChainMap(self.trap, cmap, PTK_STYLE, self._smap, compound)
self._style_name = value
if ON_WINDOWS:
self.enhance_colors_for_cmd_exe()
@style_name.deleter
def style_name(self):
self._style_name = ''
def enhance_colors_for_cmd_exe(self):
""" Enhance colors when using cmd.exe on windows.
When using the default style all blue and dark red colors
are changed to CYAN and intence red.
"""
env = builtins.__xonsh_env__
# Ensure we are not using ConEmu
if 'CONEMUANSI' not in env:
# Auto suggest needs to be a darker shade to be distinguishable
# from the default color
self.styles[Token.AutoSuggestion] = '#444444'
if env.get('INTENSIFY_COLORS_ON_WIN', False):
self._smap.update(expand_gray_colors_for_cmd_exe(self._smap))
self._smap.update(intensify_colors_for_cmd_exe(self._smap))
def xonsh_style_proxy(styler):
"""Factory for a proxy class to a xonsh style."""

View file

@ -733,6 +733,78 @@ def color_style():
return builtins.__xonsh_shell__.shell.color_style()
try:
import prompt_toolkit
except ImportError:
prompt_toolkit = None
def _get_color_indexes(style_map):
""" Generates the color and windows color index for a style """
table = prompt_toolkit.terminal.win32_output.ColorLookupTable()
pt_style = prompt_toolkit.styles.style_from_dict(style_map)
for token in style_map:
attr = pt_style.token_to_attrs[token]
if attr.color is not None:
index = table.lookup_color(attr.color, attr.bgcolor)
try:
rgb = (int(attr.color[0:2], 16),
int(attr.color[2:4], 16),
int(attr.color[4:6], 16))
except:
rgb = None
yield token, index, rgb
def intensify_colors_for_cmd_exe(style_map, replace_colors=None):
"""Returns a modified style to where colors that maps to dark
colors are replaced with brighter versions. Also expands the
range used by the gray colors
"""
modified_style = {}
if not ON_WINDOWS or prompt_toolkit is None:
return modified_style
if replace_colors is None:
replace_colors = {1: '#44ffff', # subst blue with bright cyan
2: '#44ff44', # subst green with bright green
4: '#ff4444', # subst red with bright red
5: '#ff44ff', # subst magenta with bright magenta
6: '#ffff44', # subst yellow with bright yellow
9: '#00aaaa', # subst intense blue (hard to read)
# with dark cyan (which is readable)
}
for token, idx, _ in _get_color_indexes(style_map):
if idx in replace_colors:
modified_style[token] = replace_colors[idx]
return modified_style
def expand_gray_colors_for_cmd_exe(style_map):
""" Expand the style's gray scale color range.
All gray scale colors has a tendency to map to the same default GRAY
in cmd.exe.
"""
modified_style = {}
if not ON_WINDOWS or prompt_toolkit is None:
return modified_style
for token, idx, rgb in _get_color_indexes(style_map):
if idx == 7 and rgb:
if sum(rgb) <= 306:
# Equal and below '#666666 is reset to dark gray
modified_style[token] = '#444444'
elif sum(rgb) >= 408:
# Equal and above 0x888888 is reset to white
modified_style[token] = '#ffffff'
return modified_style
def intensify_colors_on_win_setter(enable):
""" Resets the style when setting the INTENSIFY_COLORS_ON_WIN
environment variable. """
enable = to_bool(enable)
delattr(builtins.__xonsh_shell__.shell.styler, 'style_name')
return enable
_RE_STRING_START = "[bBrRuU]*"
_RE_STRING_TRIPLE_DOUBLE = '"""'

View file

@ -324,6 +324,8 @@ def _tok_colors(cmap, cols):
def _colors(ns):
cols, _ = shutil.get_terminal_size()
if tools.ON_WINDOWS:
cols -= 1
cmap = tools.color_style()
akey = next(iter(cmap))
if isinstance(akey, str):