diff options
| author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
|---|---|---|
| committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 | 
| commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
| tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/python/Pygments/py2/pygments/cmdline.py | |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/python/Pygments/py2/pygments/cmdline.py')
| -rw-r--r-- | contrib/python/Pygments/py2/pygments/cmdline.py | 573 | 
1 files changed, 573 insertions, 0 deletions
| diff --git a/contrib/python/Pygments/py2/pygments/cmdline.py b/contrib/python/Pygments/py2/pygments/cmdline.py new file mode 100644 index 00000000000..34752d66b2e --- /dev/null +++ b/contrib/python/Pygments/py2/pygments/cmdline.py @@ -0,0 +1,573 @@ +# -*- coding: utf-8 -*- +""" +    pygments.cmdline +    ~~~~~~~~~~~~~~~~ + +    Command line interface. + +    :copyright: Copyright 2006-2019 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 + +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, \ +    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, \ +    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] [-x] [-o <outfile>] [<infile>] + +       %s -S <style> -f <formatter> [-a <arg>] [-O <options>] [-P <option=value>] +       %s -L [<which> ...] +       %s -N <filename> +       %s -H <type> <name> +       %s -h | -V + +Highlight the input file and write the result to <outfile>. + +If no input file is given, use stdin, if -o is not given, use stdout. + +If -s is passed, lexing will be done in "streaming" mode, reading and +highlighting one line at a time.  This will only work properly with +lexers that have no constructs spanning multiple lines! + +<lexer> is a lexer name (query all lexer names with -L). If -l is not +given, the lexer is guessed from the extension of the input file name +(this obviously doesn't work if the input is stdin).  If -g is passed, +attempt to guess the lexer from the file contents, or pass through as +plain text if this fails (this can work for stdin). + +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``. + +The -P option adds lexer and formatter options like the -O option, but +you can only give one option per -P. That way, the option value may +contain commas and equals signs, which it can't with -O, e.g. +``-P "heading=Pygments, the Python highlighter". + +With the -F option, you can add filters to the token stream, you can +give options in the same way as for -O after a colon (note: there must +not be spaces around the colon). + +The -O, -P and -F options can be given multiple times. + +With the -S option, print out style definitions for style <style> +for formatter <formatter>. The argument given by -a is formatter +dependent. + +The -L option lists lexers, formatters, styles or filters -- set +`which` to the thing you want to list (e.g. "styles"), or omit it to +list everything. + +The -N option guesses and prints out a lexer name based solely on +the given filename. It does not take input or highlight anything. +If no specific lexer can be determined "text" is returned. + +The -H option prints detailed help for the object <name> of type <type>, +where <type> is one of "lexer", "formatter" or "filter". + +The -s option processes lines one at a time until EOF, rather than +waiting to process the entire file.  This only works for stdin, and +is intended for streaming input such as you get from 'tail -f'. +Example usage: "tail -f sql.log | pygmentize -s -l sql" + +The -v option prints a detailed traceback on unhandled exceptions, +which is useful for debugging and bug reports. + +The -h option prints this help. +The -V option prints the package version. +""" + + +def _parse_options(o_strs): +    opts = {} +    if not o_strs: +        return opts +    for o_str in o_strs: +        if not o_str.strip(): +            continue +        o_args = o_str.split(',') +        for o_arg in o_args: +            o_arg = o_arg.strip() +            try: +                o_key, o_val = o_arg.split('=', 1) +                o_key = o_key.strip() +                o_val = o_val.strip() +            except ValueError: +                opts[o_arg] = True +            else: +                opts[o_key] = o_val +    return opts + + +def _parse_filters(f_strs): +    filters = [] +    if not f_strs: +        return filters +    for f_str in f_strs: +        if ':' in f_str: +            fname, fopts = f_str.split(':', 1) +            filters.append((fname, _parse_options([fopts]))) +        else: +            filters.append((f_str, {})) +    return filters + + +def _print_help(what, name): +    try: +        if what == 'lexer': +            cls = get_lexer_by_name(name) +            print("Help on the %s lexer:" % cls.name) +            print(dedent(cls.__doc__)) +        elif what == 'formatter': +            cls = find_formatter_class(name) +            print("Help on the %s formatter:" % cls.name) +            print(dedent(cls.__doc__)) +        elif what == 'filter': +            cls = find_filter_class(name) +            print("Help on the %s filter:" % name) +            print(dedent(cls.__doc__)) +        return 0 +    except (AttributeError, ValueError): +        print("%s not found!" % what, file=sys.stderr) +        return 1 + + +def _print_list(what): +    if what == 'lexer': +        print() +        print("Lexers:") +        print("~~~~~~~") + +        info = [] +        for fullname, names, exts, _ in get_all_lexers(): +            tup = (', '.join(names)+':', fullname, +                   exts and '(filenames ' + ', '.join(exts) + ')' or '') +            info.append(tup) +        info.sort() +        for i in info: +            print(('* %s\n    %s %s') % i) + +    elif what == 'formatter': +        print() +        print("Formatters:") +        print("~~~~~~~~~~~") + +        info = [] +        for cls in get_all_formatters(): +            doc = docstring_headline(cls) +            tup = (', '.join(cls.aliases) + ':', doc, cls.filenames and +                   '(filenames ' + ', '.join(cls.filenames) + ')' or '') +            info.append(tup) +        info.sort() +        for i in info: +            print(('* %s\n    %s %s') % i) + +    elif what == 'filter': +        print() +        print("Filters:") +        print("~~~~~~~~") + +        for name in get_all_filters(): +            cls = find_filter_class(name) +            print("* " + name + ':') +            print("    %s" % docstring_headline(cls)) + +    elif what == 'style': +        print() +        print("Styles:") +        print("~~~~~~~") + +        for name in get_all_styles(): +            cls = get_style_by_name(name) +            print("* " + name + ':') +            print("    %s" % docstring_headline(cls)) + + +def main_inner(popts, args, usage): +    opts = {} +    O_opts = [] +    P_opts = [] +    F_opts = [] +    for opt, arg in popts: +        if opt == '-O': +            O_opts.append(arg) +        elif opt == '-P': +            P_opts.append(arg) +        elif opt == '-F': +            F_opts.append(arg) +        opts[opt] = arg + +    if opts.pop('-h', None) is not None: +        print(usage) +        return 0 + +    if opts.pop('-V', None) is not None: +        print('Pygments version %s, (c) 2006-2019 by Georg Brandl.' % __version__) +        return 0 + +    # handle ``pygmentize -L`` +    L_opt = opts.pop('-L', None) +    if L_opt is not None: +        if opts: +            print(usage, file=sys.stderr) +            return 2 + +        # print version +        main(['', '-V']) +        if not args: +            args = ['lexer', 'formatter', 'filter', 'style'] +        for arg in args: +            _print_list(arg.rstrip('s')) +        return 0 + +    # handle ``pygmentize -H`` +    H_opt = opts.pop('-H', None) +    if H_opt is not None: +        if opts or len(args) != 2: +            print(usage, file=sys.stderr) +            return 2 + +        what, name = args  # pylint: disable=unbalanced-tuple-unpacking +        if what not in ('lexer', 'formatter', 'filter'): +            print(usage, file=sys.stderr) +            return 2 + +        return _print_help(what, name) + +    # parse -O options +    parsed_opts = _parse_options(O_opts) +    opts.pop('-O', None) + +    # parse -P options +    for p_opt in P_opts: +        try: +            name, value = p_opt.split('=', 1) +        except ValueError: +            parsed_opts[p_opt] = True +        else: +            parsed_opts[name] = value +    opts.pop('-P', None) + +    # encodings +    inencoding = parsed_opts.get('inencoding', parsed_opts.get('encoding')) +    outencoding = parsed_opts.get('outencoding', parsed_opts.get('encoding')) + +    # handle ``pygmentize -N`` +    infn = opts.pop('-N', None) +    if infn is not None: +        lexer = find_lexer_class_for_filename(infn) +        if lexer is None: +            lexer = TextLexer + +        print(lexer.aliases[0]) +        return 0 + +    # handle ``pygmentize -S`` +    S_opt = opts.pop('-S', None) +    a_opt = opts.pop('-a', None) +    if S_opt is not None: +        f_opt = opts.pop('-f', None) +        if not f_opt: +            print(usage, file=sys.stderr) +            return 2 +        if opts or args: +            print(usage, file=sys.stderr) +            return 2 + +        try: +            parsed_opts['style'] = S_opt +            fmter = get_formatter_by_name(f_opt, **parsed_opts) +        except ClassNotFound as err: +            print(err, file=sys.stderr) +            return 1 + +        print(fmter.get_style_defs(a_opt or '')) +        return 0 + +    # if no -S is given, -a is not allowed +    if a_opt is not None: +        print(usage, file=sys.stderr) +        return 2 + +    # parse -F options +    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: +        # 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 + +    if args: +        if len(args) > 1: +            print(usage, file=sys.stderr) +            return 2 + +        if '-s' in opts: +            print('Error: -s option not usable when input file specified', +                  file=sys.stderr) +            return 2 + +        infn = args[0] +        try: +            with open(infn, 'rb') as infp: +                code = infp.read() +        except Exception as err: +            print('Error: cannot read infile:', err, file=sys.stderr) +            return 1 +        if not inencoding: +            code, inencoding = guess_decode(code) + +        # do we have to guess the lexer? +        if not lexer: +            try: +                lexer = get_lexer_for_filename(infn, code, **parsed_opts) +            except ClassNotFound as err: +                if '-g' in opts: +                    try: +                        lexer = guess_lexer(code, **parsed_opts) +                    except ClassNotFound: +                        lexer = TextLexer(**parsed_opts) +                else: +                    print('Error:', err, file=sys.stderr) +                    return 1 +            except OptionError as err: +                print('Error:', err, file=sys.stderr) +                return 1 + +    elif '-s' not in opts:  # treat stdin as full file (-s support is later) +        # read code from terminal, always in binary mode since we want to +        # decode ourselves and be tolerant with it +        if sys.version_info > (3,): +            # Python 3: we have to use .buffer to get a binary stream +            code = sys.stdin.buffer.read() +        else: +            code = sys.stdin.read() +        if not inencoding: +            code, inencoding = guess_decode_from_terminal(code, sys.stdin) +            # else the lexer will do the decoding +        if not lexer: +            try: +                lexer = guess_lexer(code, **parsed_opts) +            except ClassNotFound: +                lexer = TextLexer(**parsed_opts) + +    else:  # -s option needs a lexer with -l +        if not lexer: +            print('Error: when using -s a lexer has to be selected with -l', +                  file=sys.stderr) +            return 2 + +    # process filters +    for fname, fopts in F_opts: +        try: +            lexer.add_filter(fname, **fopts) +        except ClassNotFound as err: +            print('Error:', err, file=sys.stderr) +            return 1 + +    # select formatter +    outfn = opts.pop('-o', None) +    fmter = opts.pop('-f', None) +    if fmter: +        # 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: +            try: +                fmter = get_formatter_for_filename(outfn, **parsed_opts) +            except (OptionError, ClassNotFound) as err: +                print('Error:', err, file=sys.stderr) +                return 1 +        try: +            outfile = open(outfn, 'wb') +        except Exception as err: +            print('Error: cannot open outfile:', err, file=sys.stderr) +            return 1 +    else: +        if not fmter: +            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 +        else: +            outfile = sys.stdout + +    # determine output encoding if not explicitly selected +    if not outencoding: +        if outfn: +            # output file? use lexer encoding for now (can still be None) +            fmter.encoding = inencoding +        else: +            # else use terminal encoding +            fmter.encoding = terminal_encoding(sys.stdout) + +    # provide coloring under Windows, if possible +    if not outfn and sys.platform in ('win32', 'cygwin') and \ +       fmter.name in ('Terminal', 'Terminal256'):  # pragma: no cover +        # unfortunately colorama doesn't support binary streams on Py3 +        if sys.version_info > (3,): +            from pygments.util import UnclosingTextIOWrapper +            outfile = UnclosingTextIOWrapper(outfile, encoding=fmter.encoding) +            fmter.encoding = None +        try: +            import colorama.initialise +        except ImportError: +            pass +        else: +            outfile = colorama.initialise.wrap_stream( +                outfile, convert=None, strip=None, autoreset=False, wrap=True) + +    # When using the LaTeX formatter and the option `escapeinside` is +    # specified, we need a special lexer which collects escaped text +    # before running the chosen language lexer. +    escapeinside = parsed_opts.get('escapeinside', '') +    if len(escapeinside) == 2 and isinstance(fmter, LatexFormatter): +        left = escapeinside[0] +        right = escapeinside[1] +        lexer = LatexEmbeddedLexer(left, right, lexer) + +    # ... and do it! +    if '-s' not in opts: +        # process whole input as per normal... +        highlight(code, lexer, fmter, outfile) +        return 0 +    else: +        # line by line processing of stdin (eg: for 'tail -f')... +        try: +            while 1: +                if sys.version_info > (3,): +                    # Python 3: we have to use .buffer to get a binary stream +                    line = sys.stdin.buffer.readline() +                else: +                    line = sys.stdin.readline() +                if not line: +                    break +                if not inencoding: +                    line = guess_decode_from_terminal(line, sys.stdin)[0] +                highlight(line, lexer, fmter, outfile) +                if hasattr(outfile, 'flush'): +                    outfile.flush() +            return 0 +        except KeyboardInterrupt:  # pragma: no cover +            return 0 + + +def main(args=sys.argv): +    """ +    Main command line entry point. +    """ +    usage = USAGE % ((args[0],) * 6) + +    try: +        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 + +    try: +        return main_inner(popts, args, usage) +    except Exception: +        if '-v' in dict(popts): +            print(file=sys.stderr) +            print('*' * 65, file=sys.stderr) +            print('An unhandled exception occurred while highlighting.', +                  file=sys.stderr) +            print('Please report the whole traceback to the issue tracker at', +                  file=sys.stderr) +            print('<https://github.com/pygments/pygments/issues>.', +                  file=sys.stderr) +            print('*' * 65, file=sys.stderr) +            print(file=sys.stderr) +            raise +        import traceback +        info = traceback.format_exception(*sys.exc_info()) +        msg = info[-1].strip() +        if len(info) >= 3: +            # extract relevant file and position info +            msg += '\n   (f%s)' % info[-2].split('\n')[0].strip()[1:] +        print(file=sys.stderr) +        print('*** Error while highlighting:', file=sys.stderr) +        print(msg, file=sys.stderr) +        print('*** If this is a bug you want to report, please rerun with -v.', +              file=sys.stderr) +        return 1 | 
