diff options
Diffstat (limited to 'pygments/cmdline.py')
-rw-r--r-- | pygments/cmdline.py | 78 |
1 files changed, 61 insertions, 17 deletions
diff --git a/pygments/cmdline.py b/pygments/cmdline.py index 00745edc..2f6c1401 100644 --- a/pygments/cmdline.py +++ b/pygments/cmdline.py @@ -5,12 +5,13 @@ Command line interface. - :copyright: Copyright 2006-2015 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ from __future__ import print_function +import os import sys import getopt from textwrap import dedent @@ -19,19 +20,20 @@ from pygments import __version__, highlight from pygments.util import ClassNotFound, OptionError, docstring_headline, \ guess_decode, guess_decode_from_terminal, terminal_encoding from pygments.lexers import get_all_lexers, get_lexer_by_name, guess_lexer, \ - get_lexer_for_filename, find_lexer_class_for_filename + load_lexer_from_file, get_lexer_for_filename, find_lexer_class_for_filename from pygments.lexers.special import TextLexer from pygments.formatters.latex import LatexEmbeddedLexer, LatexFormatter from pygments.formatters import get_all_formatters, get_formatter_by_name, \ - get_formatter_for_filename, find_formatter_class + load_formatter_from_file, get_formatter_for_filename, find_formatter_class from pygments.formatters.terminal import TerminalFormatter +from pygments.formatters.terminal256 import Terminal256Formatter from pygments.filters import get_all_filters, find_filter_class from pygments.styles import get_all_styles, get_style_by_name USAGE = """\ Usage: %s [-l <lexer> | -g] [-F <filter>[:<options>]] [-f <formatter>] - [-O <options>] [-P <option=value>] [-s] [-v] [-o <outfile>] [<infile>] + [-O <options>] [-P <option=value>] [-s] [-v] [-x] [-o <outfile>] [<infile>] %s -S <style> -f <formatter> [-a <arg>] [-O <options>] [-P <option=value>] %s -L [<which> ...] @@ -57,6 +59,14 @@ Likewise, <formatter> is a formatter name, and will be guessed from the extension of the output file name. If no output file is given, the terminal formatter will be used by default. +The additional option -x allows custom lexers and formatters to be +loaded from a .py file relative to the current working directory. For +example, ``-l ./customlexer.py -x``. By default, this option expects a +file with a class named CustomLexer or CustomFormatter; you can also +specify your own class name with a colon (``-l ./lexer.py:MyLexer``). +Users should be very careful not to use this option with untrusted files, +because it will import and run them. + With the -O option, you can give the lexer and formatter a comma- separated list of options, e.g. ``-O bg=light,python=cool``. @@ -223,7 +233,7 @@ def main_inner(popts, args, usage): return 0 if opts.pop('-V', None) is not None: - print('Pygments version %s, (c) 2006-2015 by Georg Brandl.' % __version__) + print('Pygments version %s, (c) 2006-2017 by Georg Brandl.' % __version__) return 0 # handle ``pygmentize -L`` @@ -314,17 +324,35 @@ def main_inner(popts, args, usage): F_opts = _parse_filters(F_opts) opts.pop('-F', None) + allow_custom_lexer_formatter = False + # -x: allow custom (eXternal) lexers and formatters + if opts.pop('-x', None) is not None: + allow_custom_lexer_formatter = True + # select lexer lexer = None # given by name? lexername = opts.pop('-l', None) if lexername: - try: - lexer = get_lexer_by_name(lexername, **parsed_opts) - except (OptionError, ClassNotFound) as err: - print('Error:', err, file=sys.stderr) - return 1 + # custom lexer, located relative to user's cwd + if allow_custom_lexer_formatter and '.py' in lexername: + try: + if ':' in lexername: + filename, name = lexername.rsplit(':', 1) + lexer = load_lexer_from_file(filename, name, + **parsed_opts) + else: + lexer = load_lexer_from_file(lexername, **parsed_opts) + except ClassNotFound as err: + print('Error:', err, file=sys.stderr) + return 1 + else: + try: + lexer = get_lexer_by_name(lexername, **parsed_opts) + except (OptionError, ClassNotFound) as err: + print('Error:', err, file=sys.stderr) + return 1 # read input code code = None @@ -401,11 +429,24 @@ def main_inner(popts, args, usage): outfn = opts.pop('-o', None) fmter = opts.pop('-f', None) if fmter: - try: - fmter = get_formatter_by_name(fmter, **parsed_opts) - except (OptionError, ClassNotFound) as err: - print('Error:', err, file=sys.stderr) - return 1 + # custom formatter, located relative to user's cwd + if allow_custom_lexer_formatter and '.py' in fmter: + try: + if ':' in fmter: + file, fmtername = fmter.rsplit(':', 1) + fmter = load_formatter_from_file(file, fmtername, + **parsed_opts) + else: + fmter = load_formatter_from_file(fmter, **parsed_opts) + except ClassNotFound as err: + print('Error:', err, file=sys.stderr) + return 1 + else: + try: + fmter = get_formatter_by_name(fmter, **parsed_opts) + except (OptionError, ClassNotFound) as err: + print('Error:', err, file=sys.stderr) + return 1 if outfn: if not fmter: @@ -421,7 +462,10 @@ def main_inner(popts, args, usage): return 1 else: if not fmter: - fmter = TerminalFormatter(**parsed_opts) + if '256' in os.environ.get('TERM', ''): + fmter = Terminal256Formatter(**parsed_opts) + else: + fmter = TerminalFormatter(**parsed_opts) if sys.version_info > (3,): # Python 3: we have to use .buffer to get a binary stream outfile = sys.stdout.buffer @@ -495,7 +539,7 @@ def main(args=sys.argv): usage = USAGE % ((args[0],) * 6) try: - popts, args = getopt.getopt(args[1:], "l:f:F:o:O:P:LS:a:N:vhVHgs") + popts, args = getopt.getopt(args[1:], "l:f:F:o:O:P:LS:a:N:vhVHgsx") except getopt.GetoptError: print(usage, file=sys.stderr) return 2 |