Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
cmdline.py669 linesDownload Raw Back to pygments
1"""2    pygments.cmdline3    ~~~~~~~~~~~~~~~~4 5    Command line interface.6 7    :copyright: Copyright 2006-present by the Pygments team, see AUTHORS.8    :license: BSD, see LICENSE for details.9"""10 11import os12import sys13import shutil14import argparse15from textwrap import dedent16 17from pygments import __version__, highlight18from pygments.util import ClassNotFound, OptionError, docstring_headline, \19    guess_decode, guess_decode_from_terminal, terminal_encoding, \20    UnclosingTextIOWrapper21from pygments.lexers import get_all_lexers, get_lexer_by_name, guess_lexer, \22    load_lexer_from_file, get_lexer_for_filename, find_lexer_class_for_filename23from pygments.lexers.special import TextLexer24from pygments.formatters.latex import LatexEmbeddedLexer, LatexFormatter25from pygments.formatters import get_all_formatters, get_formatter_by_name, \26    load_formatter_from_file, get_formatter_for_filename, find_formatter_class27from pygments.formatters.terminal import TerminalFormatter28from pygments.formatters.terminal256 import Terminal256Formatter, TerminalTrueColorFormatter29from pygments.filters import get_all_filters, find_filter_class30from pygments.styles import get_all_styles, get_style_by_name31 32 33def _parse_options(o_strs):34    opts = {}35    if not o_strs:36        return opts37    for o_str in o_strs:38        if not o_str.strip():39            continue40        o_args = o_str.split(',')41        for o_arg in o_args:42            o_arg = o_arg.strip()43            try:44                o_key, o_val = o_arg.split('=', 1)45                o_key = o_key.strip()46                o_val = o_val.strip()47            except ValueError:48                opts[o_arg] = True49            else:50                opts[o_key] = o_val51    return opts52 53 54def _parse_filters(f_strs):55    filters = []56    if not f_strs:57        return filters58    for f_str in f_strs:59        if ':' in f_str:60            fname, fopts = f_str.split(':', 1)61            filters.append((fname, _parse_options([fopts])))62        else:63            filters.append((f_str, {}))64    return filters65 66 67def _print_help(what, name):68    try:69        if what == 'lexer':70            cls = get_lexer_by_name(name)71            print(f"Help on the {cls.name} lexer:")72            print(dedent(cls.__doc__))73        elif what == 'formatter':74            cls = find_formatter_class(name)75            print(f"Help on the {cls.name} formatter:")76            print(dedent(cls.__doc__))77        elif what == 'filter':78            cls = find_filter_class(name)79            print(f"Help on the {name} filter:")80            print(dedent(cls.__doc__))81        return 082    except (AttributeError, ValueError):83        print(f"{what} not found!", file=sys.stderr)84        return 185 86 87def _print_list(what):88    if what == 'lexer':89        print()90        print("Lexers:")91        print("~~~~~~~")92 93        info = []94        for fullname, names, exts, _ in get_all_lexers():95            tup = (', '.join(names)+':', fullname,96                   exts and '(filenames ' + ', '.join(exts) + ')' or '')97            info.append(tup)98        info.sort()99        for i in info:100            print(('* {}\n    {} {}').format(*i))101 102    elif what == 'formatter':103        print()104        print("Formatters:")105        print("~~~~~~~~~~~")106 107        info = []108        for cls in get_all_formatters():109            doc = docstring_headline(cls)110            tup = (', '.join(cls.aliases) + ':', doc, cls.filenames and111                   '(filenames ' + ', '.join(cls.filenames) + ')' or '')112            info.append(tup)113        info.sort()114        for i in info:115            print(('* {}\n    {} {}').format(*i))116 117    elif what == 'filter':118        print()119        print("Filters:")120        print("~~~~~~~~")121 122        for name in get_all_filters():123            cls = find_filter_class(name)124            print("* " + name + ':')125            print(f"    {docstring_headline(cls)}")126 127    elif what == 'style':128        print()129        print("Styles:")130        print("~~~~~~~")131 132        for name in get_all_styles():133            cls = get_style_by_name(name)134            print("* " + name + ':')135            print(f"    {docstring_headline(cls)}")136 137 138def _print_list_as_json(requested_items):139    import json140    result = {}141    if 'lexer' in requested_items:142        info = {}143        for fullname, names, filenames, mimetypes in get_all_lexers():144            info[fullname] = {145                'aliases': names,146                'filenames': filenames,147                'mimetypes': mimetypes148            }149        result['lexers'] = info150 151    if 'formatter' in requested_items:152        info = {}153        for cls in get_all_formatters():154            doc = docstring_headline(cls)155            info[cls.name] = {156                'aliases': cls.aliases,157                'filenames': cls.filenames,158                'doc': doc159            }160        result['formatters'] = info161 162    if 'filter' in requested_items:163        info = {}164        for name in get_all_filters():165            cls = find_filter_class(name)166            info[name] = {167                'doc': docstring_headline(cls)168            }169        result['filters'] = info170 171    if 'style' in requested_items:172        info = {}173        for name in get_all_styles():174            cls = get_style_by_name(name)175            info[name] = {176                'doc': docstring_headline(cls)177            }178        result['styles'] = info179 180    json.dump(result, sys.stdout)181 182def main_inner(parser, argns):183    if argns.help:184        parser.print_help()185        return 0186 187    if argns.V:188        print(f'Pygments version {__version__}, (c) 2006-present by Georg Brandl, Matthäus '189              'Chajdas and contributors.')190        return 0191 192    def is_only_option(opt):193        return not any(v for (k, v) in vars(argns).items() if k != opt)194 195    # handle ``pygmentize -L``196    if argns.L is not None:197        arg_set = set()198        for k, v in vars(argns).items():199            if v:200                arg_set.add(k)201 202        arg_set.discard('L')203        arg_set.discard('json')204 205        if arg_set:206            parser.print_help(sys.stderr)207            return 2208 209        # print version210        if not argns.json:211            main(['', '-V'])212        allowed_types = {'lexer', 'formatter', 'filter', 'style'}213        largs = [arg.rstrip('s') for arg in argns.L]214        if any(arg not in allowed_types for arg in largs):215            parser.print_help(sys.stderr)216            return 0217        if not largs:218            largs = allowed_types219        if not argns.json:220            for arg in largs:221                _print_list(arg)222        else:223            _print_list_as_json(largs)224        return 0225 226    # handle ``pygmentize -H``227    if argns.H:228        if not is_only_option('H'):229            parser.print_help(sys.stderr)230            return 2231        what, name = argns.H232        if what not in ('lexer', 'formatter', 'filter'):233            parser.print_help(sys.stderr)234            return 2235        return _print_help(what, name)236 237    # parse -O options238    parsed_opts = _parse_options(argns.O or [])239 240    # parse -P options241    for p_opt in argns.P or []:242        try:243            name, value = p_opt.split('=', 1)244        except ValueError:245            parsed_opts[p_opt] = True246        else:247            parsed_opts[name] = value248 249    # encodings250    inencoding = parsed_opts.get('inencoding', parsed_opts.get('encoding'))251    outencoding = parsed_opts.get('outencoding', parsed_opts.get('encoding'))252 253    # handle ``pygmentize -N``254    if argns.N:255        lexer = find_lexer_class_for_filename(argns.N)256        if lexer is None:257            lexer = TextLexer258 259        print(lexer.aliases[0])260        return 0261 262    # handle ``pygmentize -C``263    if argns.C:264        inp = sys.stdin.buffer.read()265        try:266            lexer = guess_lexer(inp, inencoding=inencoding)267        except ClassNotFound:268            lexer = TextLexer269 270        print(lexer.aliases[0])271        return 0272 273    # handle ``pygmentize -S``274    S_opt = argns.S275    a_opt = argns.a276    if S_opt is not None:277        f_opt = argns.f278        if not f_opt:279            parser.print_help(sys.stderr)280            return 2281        if argns.l or argns.INPUTFILE:282            parser.print_help(sys.stderr)283            return 2284 285        try:286            parsed_opts['style'] = S_opt287            fmter = get_formatter_by_name(f_opt, **parsed_opts)288        except ClassNotFound as err:289            print(err, file=sys.stderr)290            return 1291 292        print(fmter.get_style_defs(a_opt or ''))293        return 0294 295    # if no -S is given, -a is not allowed296    if argns.a is not None:297        parser.print_help(sys.stderr)298        return 2299 300    # parse -F options301    F_opts = _parse_filters(argns.F or [])302 303    # -x: allow custom (eXternal) lexers and formatters304    allow_custom_lexer_formatter = bool(argns.x)305 306    # select lexer307    lexer = None308 309    # given by name?310    lexername = argns.l311    if lexername:312        # custom lexer, located relative to user's cwd313        if allow_custom_lexer_formatter and '.py' in lexername:314            try:315                filename = None316                name = None317                if ':' in lexername:318                    filename, name = lexername.rsplit(':', 1)319 320                    if '.py' in name:321                        # This can happen on Windows: If the lexername is322                        # C:\lexer.py -- return to normal load path in that case323                        name = None324 325                if filename and name:326                    lexer = load_lexer_from_file(filename, name,327                                                 **parsed_opts)328                else:329                    lexer = load_lexer_from_file(lexername, **parsed_opts)330            except ClassNotFound as err:331                print('Error:', err, file=sys.stderr)332                return 1333        else:334            try:335                lexer = get_lexer_by_name(lexername, **parsed_opts)336            except (OptionError, ClassNotFound) as err:337                print('Error:', err, file=sys.stderr)338                return 1339 340    # read input code341    code = None342 343    if argns.INPUTFILE:344        if argns.s:345            print('Error: -s option not usable when input file specified',346                  file=sys.stderr)347            return 2348 349        infn = argns.INPUTFILE350        try:351            with open(infn, 'rb') as infp:352                code = infp.read()353        except Exception as err:354            print('Error: cannot read infile:', err, file=sys.stderr)355            return 1356        if not inencoding:357            code, inencoding = guess_decode(code)358 359        # do we have to guess the lexer?360        if not lexer:361            try:362                lexer = get_lexer_for_filename(infn, code, **parsed_opts)363            except ClassNotFound as err:364                if argns.g:365                    try:366                        lexer = guess_lexer(code, **parsed_opts)367                    except ClassNotFound:368                        lexer = TextLexer(**parsed_opts)369                else:370                    print('Error:', err, file=sys.stderr)371                    return 1372            except OptionError as err:373                print('Error:', err, file=sys.stderr)374                return 1375 376    elif not argns.s:  # treat stdin as full file (-s support is later)377        # read code from terminal, always in binary mode since we want to378        # decode ourselves and be tolerant with it379        code = sys.stdin.buffer.read()  # use .buffer to get a binary stream380        if not inencoding:381            code, inencoding = guess_decode_from_terminal(code, sys.stdin)382            # else the lexer will do the decoding383        if not lexer:384            try:385                lexer = guess_lexer(code, **parsed_opts)386            except ClassNotFound:387                lexer = TextLexer(**parsed_opts)388 389    else:  # -s option needs a lexer with -l390        if not lexer:391            print('Error: when using -s a lexer has to be selected with -l',392                  file=sys.stderr)393            return 2394 395    # process filters396    for fname, fopts in F_opts:397        try:398            lexer.add_filter(fname, **fopts)399        except ClassNotFound as err:400            print('Error:', err, file=sys.stderr)401            return 1402 403    # select formatter404    outfn = argns.o405    fmter = argns.f406    if fmter:407        # custom formatter, located relative to user's cwd408        if allow_custom_lexer_formatter and '.py' in fmter:409            try:410                filename = None411                name = None412                if ':' in fmter:413                    # Same logic as above for custom lexer414                    filename, name = fmter.rsplit(':', 1)415 416                    if '.py' in name:417                        name = None418 419                if filename and name:420                    fmter = load_formatter_from_file(filename, name,421                                                     **parsed_opts)422                else:423                    fmter = load_formatter_from_file(fmter, **parsed_opts)424            except ClassNotFound as err:425                print('Error:', err, file=sys.stderr)426                return 1427        else:428            try:429                fmter = get_formatter_by_name(fmter, **parsed_opts)430            except (OptionError, ClassNotFound) as err:431                print('Error:', err, file=sys.stderr)432                return 1433 434    if outfn:435        if not fmter:436            try:437                fmter = get_formatter_for_filename(outfn, **parsed_opts)438            except (OptionError, ClassNotFound) as err:439                print('Error:', err, file=sys.stderr)440                return 1441        try:442            outfile = open(outfn, 'wb')443        except Exception as err:444            print('Error: cannot open outfile:', err, file=sys.stderr)445            return 1446    else:447        if not fmter:448            if os.environ.get('COLORTERM','') in ('truecolor', '24bit'):449                fmter = TerminalTrueColorFormatter(**parsed_opts)450            elif '256' in os.environ.get('TERM', ''):451                fmter = Terminal256Formatter(**parsed_opts)452            else:453                fmter = TerminalFormatter(**parsed_opts)454        outfile = sys.stdout.buffer455 456    # determine output encoding if not explicitly selected457    if not outencoding:458        if outfn:459            # output file? use lexer encoding for now (can still be None)460            fmter.encoding = inencoding461        else:462            # else use terminal encoding463            fmter.encoding = terminal_encoding(sys.stdout)464 465    # provide coloring under Windows, if possible466    if not outfn and sys.platform in ('win32', 'cygwin') and \467       fmter.name in ('Terminal', 'Terminal256'):  # pragma: no cover468        # unfortunately colorama doesn't support binary streams on Py3469        outfile = UnclosingTextIOWrapper(outfile, encoding=fmter.encoding)470        fmter.encoding = None471        try:472            import colorama.initialise473        except ImportError:474            pass475        else:476            outfile = colorama.initialise.wrap_stream(477                outfile, convert=None, strip=None, autoreset=False, wrap=True)478 479    # When using the LaTeX formatter and the option `escapeinside` is480    # specified, we need a special lexer which collects escaped text481    # before running the chosen language lexer.482    escapeinside = parsed_opts.get('escapeinside', '')483    if len(escapeinside) == 2 and isinstance(fmter, LatexFormatter):484        left = escapeinside[0]485        right = escapeinside[1]486        lexer = LatexEmbeddedLexer(left, right, lexer)487 488    # ... and do it!489    if not argns.s:490        # process whole input as per normal...491        try:492            highlight(code, lexer, fmter, outfile)493        finally:494            if outfn:495                outfile.close()496        return 0497    else:498        # line by line processing of stdin (eg: for 'tail -f')...499        try:500            while 1:501                line = sys.stdin.buffer.readline()502                if not line:503                    break504                if not inencoding:505                    line = guess_decode_from_terminal(line, sys.stdin)[0]506                highlight(line, lexer, fmter, outfile)507                if hasattr(outfile, 'flush'):508                    outfile.flush()509            return 0510        except KeyboardInterrupt:  # pragma: no cover511            return 0512        finally:513            if outfn:514                outfile.close()515 516 517class HelpFormatter(argparse.HelpFormatter):518    def __init__(self, prog, indent_increment=2, max_help_position=16, width=None):519        if width is None:520            try:521                width = shutil.get_terminal_size().columns - 2522            except Exception:523                pass524        argparse.HelpFormatter.__init__(self, prog, indent_increment,525                                        max_help_position, width)526 527 528def main(args=sys.argv):529    """530    Main command line entry point.531    """532    desc = "Highlight an input file and write the result to an output file."533    parser = argparse.ArgumentParser(description=desc, add_help=False,534                                     formatter_class=HelpFormatter)535 536    operation = parser.add_argument_group('Main operation')537    lexersel = operation.add_mutually_exclusive_group()538    lexersel.add_argument(539        '-l', metavar='LEXER',540        help='Specify the lexer to use.  (Query names with -L.)  If not '541        'given and -g is not present, the lexer is guessed from the filename.')542    lexersel.add_argument(543        '-g', action='store_true',544        help='Guess the lexer from the file contents, or pass through '545        'as plain text if nothing can be guessed.')546    operation.add_argument(547        '-F', metavar='FILTER[:options]', action='append',548        help='Add a filter to the token stream.  (Query names with -L.) '549        'Filter options are given after a colon if necessary.')550    operation.add_argument(551        '-f', metavar='FORMATTER',552        help='Specify the formatter to use.  (Query names with -L.) '553        'If not given, the formatter is guessed from the output filename, '554        'and defaults to the terminal formatter if the output is to the '555        'terminal or an unknown file extension.')556    operation.add_argument(557        '-O', metavar='OPTION=value[,OPTION=value,...]', action='append',558        help='Give options to the lexer and formatter as a comma-separated '559        'list of key-value pairs. '560        'Example: `-O bg=light,python=cool`.')561    operation.add_argument(562        '-P', metavar='OPTION=value', action='append',563        help='Give a single option to the lexer and formatter - with this '564        'you can pass options whose value contains commas and equal signs. '565        'Example: `-P "heading=Pygments, the Python highlighter"`.')566    operation.add_argument(567        '-o', metavar='OUTPUTFILE',568        help='Where to write the output.  Defaults to standard output.')569 570    operation.add_argument(571        'INPUTFILE', nargs='?',572        help='Where to read the input.  Defaults to standard input.')573 574    flags = parser.add_argument_group('Operation flags')575    flags.add_argument(576        '-v', action='store_true',577        help='Print a detailed traceback on unhandled exceptions, which '578        'is useful for debugging and bug reports.')579    flags.add_argument(580        '-s', action='store_true',581        help='Process lines one at a time until EOF, rather than waiting to '582        'process the entire file.  This only works for stdin, only for lexers '583        'with no line-spanning constructs, and is intended for streaming '584        'input such as you get from `tail -f`. '585        'Example usage: `tail -f sql.log | pygmentize -s -l sql`.')586    flags.add_argument(587        '-x', action='store_true',588        help='Allow custom lexers and formatters to be loaded from a .py file '589        'relative to the current working directory. For example, '590        '`-l ./customlexer.py -x`. By default, this option expects a file '591        'with a class named CustomLexer or CustomFormatter; you can also '592        'specify your own class name with a colon (`-l ./lexer.py:MyLexer`). '593        'Users should be very careful not to use this option with untrusted '594        'files, because it will import and run them.')595    flags.add_argument('--json', help='Output as JSON. This can '596        'be only used in conjunction with -L.',597        default=False,598        action='store_true')599 600    special_modes_group = parser.add_argument_group(601        'Special modes - do not do any highlighting')602    special_modes = special_modes_group.add_mutually_exclusive_group()603    special_modes.add_argument(604        '-S', metavar='STYLE -f formatter',605        help='Print style definitions for STYLE for a formatter '606        'given with -f. The argument given by -a is formatter '607        'dependent.')608    special_modes.add_argument(609        '-L', nargs='*', metavar='WHAT',610        help='List lexers, formatters, styles or filters -- '611        'give additional arguments for the thing(s) you want to list '612        '(e.g. "styles"), or omit them to list everything.')613    special_modes.add_argument(614        '-N', metavar='FILENAME',615        help='Guess and print out a lexer name based solely on the given '616        'filename. Does not take input or highlight anything. If no specific '617        'lexer can be determined, "text" is printed.')618    special_modes.add_argument(619        '-C', action='store_true',620        help='Like -N, but print out a lexer name based solely on '621        'a given content from standard input.')622    special_modes.add_argument(623        '-H', action='store', nargs=2, metavar=('NAME', 'TYPE'),624        help='Print detailed help for the object <name> of type <type>, '625        'where <type> is one of "lexer", "formatter" or "filter".')626    special_modes.add_argument(627        '-V', action='store_true',628        help='Print the package version.')629    special_modes.add_argument(630        '-h', '--help', action='store_true',631        help='Print this help.')632    special_modes_group.add_argument(633        '-a', metavar='ARG',634        help='Formatter-specific additional argument for the -S (print '635        'style sheet) mode.')636 637    argns = parser.parse_args(args[1:])638 639    try:640        return main_inner(parser, argns)641    except BrokenPipeError:642        # someone closed our stdout, e.g. by quitting a pager.643        return 0644    except Exception:645        if argns.v:646            print(file=sys.stderr)647            print('*' * 65, file=sys.stderr)648            print('An unhandled exception occurred while highlighting.',649                  file=sys.stderr)650            print('Please report the whole traceback to the issue tracker at',651                  file=sys.stderr)652            print('<https://github.com/pygments/pygments/issues>.',653                  file=sys.stderr)654            print('*' * 65, file=sys.stderr)655            print(file=sys.stderr)656            raise657        import traceback658        info = traceback.format_exception(*sys.exc_info())659        msg = info[-1].strip()660        if len(info) >= 3:661            # extract relevant file and position info662            msg += '\n   (f{})'.format(info[-2].split('\n')[0].strip()[1:])663        print(file=sys.stderr)664        print('*** Error while highlighting:', file=sys.stderr)665        print(msg, file=sys.stderr)666        print('*** If this is a bug you want to report, please rerun with -v.',667              file=sys.stderr)668        return 1669 
codekingpro/portable-devtools · Team Ai