Merge pull request #2216 from xonsh/tracer

Tracer fixes
This commit is contained in:
Morten Enemark Lund 2017-02-19 20:55:02 +01:00 committed by GitHub
commit 27a37758c7
5 changed files with 65 additions and 16 deletions

17
news/tracer.rst Normal file
View file

@ -0,0 +1,17 @@
**Added:**
* The ``trace`` will automatically disable color printing when
stdout is not a TTY or stdout is captured.
**Changed:** None
**Deprecated:** None
**Removed:** None
**Fixed:**
* The ``trace`` utility will now correctly color output and not
print extraneous newlines when called in a script.
**Security:** None

View file

@ -48,7 +48,7 @@ def sp(cmd):
class DummyStyler():
styles = defaultdict(None.__class__)
styles = defaultdict(str)
class DummyBaseShell(BaseShell):
@ -92,6 +92,7 @@ class DummyEnv(MutableMapping):
DEFAULTS = {
'XONSH_DEBUG': 1,
'XONSH_COLOR_STYLE': 'default',
}
def __init__(self, *args, **kwargs):

View file

@ -353,11 +353,12 @@ def xonfig(args, stdin=None):
@unthreadable
def trace(args, stdin=None):
def trace(args, stdin=None, stdout=None, stderr=None, spec=None):
"""Runs the xonsh tracer utility."""
from xonsh.tracer import tracermain # lazy import
try:
return tracermain(args)
return tracermain(args, stdin=stdin, stdout=stdout,
stderr=stderr, spec=spec)
except SystemExit:
pass

View file

@ -16,6 +16,8 @@ from xonsh.completer import Completer
from xonsh.prompt.base import multiline_prompt, PromptFormatter
from xonsh.events import events
from xonsh.shell import transform_command
from xonsh.lazyimps import pygments, pyghooks
from xonsh.ansi_colors import ansi_partial_color_format
if ON_WINDOWS:
import ctypes
@ -475,19 +477,32 @@ class BaseShell(object):
self.settitle()
return p
def format_color(self, string, **kwargs):
"""Formats the colors in a string. This base implmentation does not
actually do any coloring, but just returns the string directly.
def format_color(self, string, hide=False, force_string=False, **kwargs):
"""Formats the colors in a string. This base implmentation colors based
on ANSI color codes
"""
return string
style = builtins.__xonsh_env__.get('XONSH_COLOR_STYLE')
return ansi_partial_color_format(string, hide=hide, style=style)
def print_color(self, string, **kwargs):
"""Prints a string in color. This base implmentation does not actually
do any coloring, but just prints the string directly.
def print_color(self, string, hide=False, **kwargs):
"""Prints a string in color. This base implmentation will color based
ANSI color codes if a string was given as input. If a list of token
pairs is given, it will color based on pygments, if available. If
pygments is not available, it will print a colorless string.
"""
if not isinstance(string, str):
string = ''.join([x for _, x in string])
print(string, **kwargs)
if isinstance(string, str):
s = self.format_color(string, hide=hide)
elif HAS_PYGMENTS:
# assume this is a list of (Token, str) tuples and format it
env = builtins.__xonsh_env__
self.styler.style_name = env.get('XONSH_COLOR_STYLE')
style_proxy = pyghooks.xonsh_style_proxy(self.styler)
formatter = pyghooks.XonshTerminal256Formatter(style=style_proxy)
s = pygments.format(string, formatter).rstrip()
else:
# assume this is a list of (Token, str) tuples and remove color
s = ''.join([x for _, x in string])
print(s, **kwargs)
def color_style_names(self):
"""Returns an iterable of all available style names."""

View file

@ -13,9 +13,9 @@ from xonsh.platform import HAS_PYGMENTS
from xonsh.tools import DefaultNotGiven, print_color, normabspath, to_bool
from xonsh.inspectors import find_file, getouterframes
from xonsh.lazyimps import pygments, pyghooks
from xonsh.proc import STDOUT_CAPTURE_KINDS
import xonsh.prompt.cwd as prompt
terminal = LazyObject(lambda: importlib.import_module(
'pygments.formatters.terminal'),
globals(), 'terminal')
@ -45,6 +45,14 @@ class TracerType(object):
for f in set(self.files):
self.stop(f)
def color_output(self, usecolor):
"""Specify whether or not the tracer output should be colored."""
# we have to use a function to set usecolor because of the way that
# lazyasd works. Namely, it cannot dispatch setattr to the target
# object without being unable to access its own __dict__. This makes
# setting an atter look like getting a function.
self.usecolor = usecolor
def start(self, filename):
"""Starts tracing a file."""
files = self.files
@ -109,6 +117,10 @@ def tracer_format_line(fname, lineno, line, color=True, lexer=None, formatter=No
tokens = pyghooks.partial_color_tokenize(cline)
lexer = lexer or pyghooks.XonshLexer()
tokens += pygments.lex(line, lexer=lexer)
if tokens[-1][1] == '\n':
del tokens[-1]
elif tokens[-1][1].endswith('\n'):
tokens[-1] = (tokens[-1][0], tokens[-1][1].rstrip())
return tokens
@ -157,7 +169,7 @@ def _off(ns, args):
def _color(ns, args):
"""Manages color action for tracer CLI."""
tracer.usecolor = ns.toggle
tracer.color_output(ns.toggle)
@functools.lru_cache(1)
@ -194,8 +206,11 @@ _TRACER_MAIN_ACTIONS = {
}
def tracermain(args=None):
def tracermain(args=None, stdin=None, stdout=None, stderr=None, spec=None):
"""Main function for tracer command-line interface."""
parser = _tracer_create_parser()
ns = parser.parse_args(args)
usecolor = ((spec.captured not in STDOUT_CAPTURE_KINDS) and
sys.stdout.isatty())
tracer.color_output(usecolor)
return _TRACER_MAIN_ACTIONS[ns.action](ns, args)