--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ThirdParty/Pygments/pygments/cmdline.py Mon Dec 28 16:03:33 2009 +0000 @@ -0,0 +1,430 @@ +# -*- coding: utf-8 -*- +""" + pygments.cmdline + ~~~~~~~~~~~~~~~~ + + Command line interface. + + :copyright: Copyright 2006-2009 by the Pygments team, see AUTHORS. + :license: BSD, see LICENSE for details. +""" +import sys +import getopt +from textwrap import dedent + +from pygments import __version__, highlight +from pygments.util import ClassNotFound, OptionError, docstring_headline +from pygments.lexers import get_all_lexers, get_lexer_by_name, get_lexer_for_filename, \ + find_lexer_class, guess_lexer, TextLexer +from pygments.formatters import get_all_formatters, get_formatter_by_name, \ + get_formatter_for_filename, find_formatter_class, \ + TerminalFormatter # pylint:disable-msg=E0611 +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>] [-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. + +<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. + +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 -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: + 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('=') + 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 = find_lexer_class(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__) + except AttributeError: + print >>sys.stderr, "%s not found!" % what + + +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(args=sys.argv): + """ + Main command line entry point. + """ + # pylint: disable-msg=R0911,R0912,R0915 + + usage = USAGE % ((args[0],) * 6) + + try: + popts, args = getopt.getopt(args[1:], "l:f:F:o:O:P:LS:a:N:hVHg") + except getopt.GetoptError, err: + print >>sys.stderr, usage + return 2 + 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 not opts and not args: + print usage + return 0 + + 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-2008 by Georg Brandl.' % __version__ + return 0 + + # handle ``pygmentize -L`` + L_opt = opts.pop('-L', None) + if L_opt is not None: + if opts: + print >>sys.stderr, usage + 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 >>sys.stderr, usage + return 2 + + what, name = args + if what not in ('lexer', 'formatter', 'filter'): + print >>sys.stderr, usage + return 2 + + _print_help(what, name) + return 0 + + # 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) + + # handle ``pygmentize -N`` + infn = opts.pop('-N', None) + if infn is not None: + try: + lexer = get_lexer_for_filename(infn, **parsed_opts) + except ClassNotFound, err: + lexer = TextLexer() + except OptionError, err: + print >>sys.stderr, 'Error:', err + return 1 + + 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 >>sys.stderr, usage + return 2 + if opts or args: + print >>sys.stderr, usage + return 2 + + try: + parsed_opts['style'] = S_opt + fmter = get_formatter_by_name(f_opt, **parsed_opts) + except ClassNotFound, err: + print >>sys.stderr, err + return 1 + + arg = a_opt or '' + try: + print fmter.get_style_defs(arg) + except Exception, err: + print >>sys.stderr, 'Error:', err + return 1 + return 0 + + # if no -S is given, -a is not allowed + if a_opt is not None: + print >>sys.stderr, usage + return 2 + + # parse -F options + F_opts = _parse_filters(F_opts) + opts.pop('-F', None) + + # select formatter + outfn = opts.pop('-o', None) + fmter = opts.pop('-f', None) + if fmter: + try: + fmter = get_formatter_by_name(fmter, **parsed_opts) + except (OptionError, ClassNotFound), err: + print >>sys.stderr, 'Error:', err + return 1 + + if outfn: + if not fmter: + try: + fmter = get_formatter_for_filename(outfn, **parsed_opts) + except (OptionError, ClassNotFound), err: + print >>sys.stderr, 'Error:', err + return 1 + try: + outfile = open(outfn, 'wb') + except Exception, err: + print >>sys.stderr, 'Error: cannot open outfile:', err + return 1 + else: + if not fmter: + fmter = TerminalFormatter(**parsed_opts) + outfile = sys.stdout + + # select lexer + lexer = opts.pop('-l', None) + if lexer: + try: + lexer = get_lexer_by_name(lexer, **parsed_opts) + except (OptionError, ClassNotFound), err: + print >>sys.stderr, 'Error:', err + return 1 + + if args: + if len(args) > 1: + print >>sys.stderr, usage + return 2 + + infn = args[0] + try: + code = open(infn, 'rb').read() + except Exception, err: + print >>sys.stderr, 'Error: cannot read infile:', err + return 1 + + if not lexer: + try: + lexer = get_lexer_for_filename(infn, code, **parsed_opts) + except ClassNotFound, err: + if '-g' in opts: + try: + lexer = guess_lexer(code) + except ClassNotFound: + lexer = TextLexer() + else: + print >>sys.stderr, 'Error:', err + return 1 + except OptionError, err: + print >>sys.stderr, 'Error:', err + return 1 + + else: + if '-g' in opts: + code = sys.stdin.read() + try: + lexer = guess_lexer(code) + except ClassNotFound: + lexer = TextLexer() + elif not lexer: + print >>sys.stderr, 'Error: no lexer name given and reading ' + \ + 'from stdin (try using -g or -l <lexer>)' + return 2 + else: + code = sys.stdin.read() + + # No encoding given? Use latin1 if output file given, + # stdin/stdout encoding otherwise. + # (This is a compromise, I'm not too happy with it...) + if 'encoding' not in parsed_opts and 'outencoding' not in parsed_opts: + if outfn: + # encoding pass-through + fmter.encoding = 'latin1' + else: + if sys.version_info < (3,): + # use terminal encoding; Python 3's terminals already do that + lexer.encoding = getattr(sys.stdin, 'encoding', + None) or 'ascii' + fmter.encoding = getattr(sys.stdout, 'encoding', + None) or 'ascii' + + # ... and do it! + try: + # process filters + for fname, fopts in F_opts: + lexer.add_filter(fname, **fopts) + highlight(code, lexer, fmter, outfile) + except Exception, err: + 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 >>sys.stderr + print >>sys.stderr, '*** Error while highlighting:' + print >>sys.stderr, msg + return 1 + + return 0