diff options
Diffstat (limited to 'pygments')
-rw-r--r-- | pygments/cmdline.py | 225 | ||||
-rw-r--r-- | pygments/filters/__init__.py | 79 | ||||
-rw-r--r-- | pygments/formatter.py | 9 | ||||
-rw-r--r-- | pygments/formatters/__init__.py | 87 | ||||
-rwxr-xr-x | pygments/formatters/_mapping.py | 80 | ||||
-rw-r--r-- | pygments/formatters/bbcode.py | 5 | ||||
-rw-r--r-- | pygments/formatters/html.py | 6 | ||||
-rw-r--r-- | pygments/formatters/latex.py | 3 | ||||
-rw-r--r-- | pygments/formatters/other.py | 9 | ||||
-rw-r--r-- | pygments/formatters/rtf.py | 5 | ||||
-rw-r--r-- | pygments/formatters/terminal.py | 5 | ||||
-rw-r--r-- | pygments/lexer.py | 8 | ||||
-rw-r--r-- | pygments/lexers/__init__.py | 30 | ||||
-rw-r--r-- | pygments/styles/__init__.py | 6 | ||||
-rw-r--r-- | pygments/styles/autumn.py | 3 | ||||
-rw-r--r-- | pygments/styles/borland.py | 3 | ||||
-rw-r--r-- | pygments/styles/colorful.py | 3 | ||||
-rw-r--r-- | pygments/styles/friendly.py | 3 | ||||
-rw-r--r-- | pygments/styles/fruity.py | 3 | ||||
-rw-r--r-- | pygments/styles/manni.py | 3 | ||||
-rw-r--r-- | pygments/styles/murphy.py | 3 | ||||
-rw-r--r-- | pygments/styles/native.py | 3 | ||||
-rw-r--r-- | pygments/styles/pastie.py | 3 | ||||
-rw-r--r-- | pygments/styles/perldoc.py | 3 | ||||
-rw-r--r-- | pygments/styles/trac.py | 3 | ||||
-rw-r--r-- | pygments/util.py | 18 |
26 files changed, 444 insertions, 164 deletions
diff --git a/pygments/cmdline.py b/pygments/cmdline.py index b782dc97..53f47206 100644 --- a/pygments/cmdline.py +++ b/pygments/cmdline.py @@ -10,18 +10,26 @@ """ import sys import getopt +from textwrap import dedent from pygments import __version__, __author__, highlight -from pygments.lexers import LEXERS, get_lexer_by_name, get_lexer_for_filename -from pygments.util import OptionError -from pygments.formatters import FORMATTERS, get_formatter_by_name, \ - get_formatter_for_filename, TerminalFormatter +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 +from pygments.formatters import get_all_formatters, get_formatter_by_name, \ + get_formatter_for_filename, TerminalFormatter, find_formatter_class +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>] [-f <formatter>] [-O <options>] [-o <outfile>] [<infile>] +Usage: %s [-l <lexer>] [-F <filter>[:<options]] [-f <formatter>] + [-O <options>] [-o <outfile>] [<infile>] + %s -S <style> -f <formatter> [-a <arg>] [-O <options>] - %s -L | -h | -V + %s -L [<which> ...] + %s -H <type> <name> + %s -h | -V Highlight the input file and write the result to <outfile>. @@ -38,77 +46,151 @@ 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``. +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 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 all available lexers and formatters. +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 -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_str): +def _parse_options(o_strs): opts = {} - if not o_str: + if not o_strs: return opts - 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 + 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 _print_lflist(): - # print version - main(['', '-V']) - - print - print "Lexers:" - print "~~~~~~~" - - info = [] - for _, fullname, names, exts, _ in LEXERS.itervalues(): - tup = (', '.join(names)+':', fullname, - exts and '(extensions ' + ', '.join(exts) + ')' or '') - info.append(tup) - info.sort() - for i in info: - print ('%s\n %s %s') % i +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 - print - print "Formatters:" - print "~~~~~~~~~~~" - info = [] - for fullname, names, exts, doc in FORMATTERS.itervalues(): - tup = (', '.join(names)+':', doc, - exts and '(extensions ' + ', '.join(exts) + ')' or '') - info.append(tup) - info.sort() - for i in info: - print ('%s\n %s %s') % i +def _print_help(type, name): + try: + if type == 'lexer': + cls = find_lexer_class(name) + print "Help on the %s lexer:" % cls.name + print dedent(cls.__doc__) + elif type == 'formatter': + cls = find_formatter_class(name) + print "Help on the %s formatter:" % cls.name + print dedent(cls.__doc__) + elif type == 'filter': + cls = find_filter_class(name) + print "Help on the %s filter:" % name + print dedent(cls.__doc__) + except ClassNotFound: + print >>sys.stderr, "%s not found!" % type + + +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): """ Main command line entry point. """ - usage = USAGE % ((args[0],) * 3) + usage = USAGE % ((args[0],) * 5) try: - opts, args = getopt.getopt(args[1:], "l:f:o:O:LhVS:a:") - except getopt.GetoptError: + popts, args = getopt.getopt(args[1:], "l:f:F:o:O:LS:a:hVH") + except getopt.GetoptError, err: print >>sys.stderr, usage return 2 - opts = dict(opts) + opts = {} + O_opts = [] + F_opts = [] + for opt, arg in popts: + if opt == '-O': + O_opts.append(arg) + elif opt == '-F': + F_opts.append(arg) + opts[opt] = arg if not opts and not args: print usage @@ -125,15 +207,37 @@ def main(args): # handle ``pygmentize -L`` L_opt = opts.pop('-L', None) if L_opt is not None: - if opts or args: + 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 + + type, name = args + if type not in ('lexer', 'formatter', 'filter'): print >>sys.stderr, usage return 2 - _print_lflist() + _print_help(type, name) return 0 # parse -O options - O_opts = _parse_options(opts.pop('-O', None)) + O_opts = _parse_options(O_opts) + # parse -F options + F_opts = _parse_filters(F_opts) # handle ``pygmentize -S`` S_opt = opts.pop('-S', None) @@ -150,7 +254,7 @@ def main(args): try: O_opts['style'] = S_opt fmter = get_formatter_by_name(f_opt, **O_opts) - except ValueError, err: + except ClassNotFound, err: print >>sys.stderr, err return 1 @@ -169,7 +273,7 @@ def main(args): if fmter: try: fmter = get_formatter_by_name(fmter, **O_opts) - except (OptionError, ValueError), err: + except (OptionError, ClassNotFound), err: print >>sys.stderr, 'Error:', err return 1 @@ -177,7 +281,7 @@ def main(args): if not fmter: try: fmter = get_formatter_for_filename(outfn, **O_opts) - except (OptionError, ValueError), err: + except (OptionError, ClassNotFound), err: print >>sys.stderr, 'Error:', err return 1 try: @@ -195,7 +299,7 @@ def main(args): if lexer: try: lexer = get_lexer_by_name(lexer, **O_opts) - except (OptionError, ValueError), err: + except (OptionError, ClassNotFound), err: print >>sys.stderr, 'Error:', err return 1 @@ -208,7 +312,7 @@ def main(args): if not lexer: try: lexer = get_lexer_for_filename(infn, **O_opts) - except (OptionError, ValueError), err: + except (OptionError, ClassNotFound), err: print >>sys.stderr, 'Error:', err return 1 @@ -225,6 +329,9 @@ def main(args): # ... 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 diff --git a/pygments/filters/__init__.py b/pygments/filters/__init__.py index 10c6072a..524e3bbb 100644 --- a/pygments/filters/__init__.py +++ b/pygments/filters/__init__.py @@ -6,7 +6,7 @@ Module containing filter lookup functions and default filters. - :copyright: 2006-2007 by Armin Ronacher. + :copyright: 2006-2007 by Armin Ronacher, Georg Brandl. :license: BSD, see LICENSE for more details. """ try: @@ -17,26 +17,37 @@ except NameError: import re from pygments.token import String, Comment, Keyword, Name, string_to_tokentype from pygments.filter import Filter -from pygments.util import get_list_opt +from pygments.util import get_list_opt, ClassNotFound from pygments.plugin import find_plugin_filters -def find_filter(filter, **options): +def find_filter_class(filter): """ - Lookup a builtin filter. Options are passed to the - filter initialization if wanted. + Lookup a filter by name. Return None if not found. """ if filter in FILTERS: - return FILTERS[filter](**options) + return FILTERS[filter] for name, cls in find_plugin_filters(): if name == filter: - return cls(**options) - raise ValueError('filter %r not found' % filter) + return cls + return None + + +def get_filter_by_name(filter, **options): + """ + Return an instantiated filter. Options are passed to the filter + initializer if wanted. Raise a ClassNotFound if not found. + """ + cls = find_filter_class(filter) + if cls: + return cls(**options) + else: + raise ClassNotFound('filter %r not found' % filter) def get_all_filters(): """ - Return a generator for all filters by name. + Return a generator of all filter names. """ for name in FILTERS: yield name @@ -46,10 +57,11 @@ def get_all_filters(): class CodeTagFilter(Filter): """ - Highlights special code tags in comments and docstrings. Per default, the - list of highlighted tags is ``XXX``, ``TODO``, ``BUG`` and ``NOTE``. You can - override this list by specifying a `codetags` parameter that takes a list of - words. + Highlight special code tags in comments and docstrings. + + Per default, the list of highlighted tags is ``XXX``, ``TODO``, ``BUG`` and + ``NOTE``. You can override this list by specifying a `codetags` parameter + that takes a list of words. """ def __init__(self, **options): Filter.__init__(self, **options) @@ -80,16 +92,17 @@ class CodeTagFilter(Filter): class KeywordCaseFilter(Filter): """ - Converts keywords to ``lower``, ``upper`` or ``capitalize`` which means - first letter uppercase, rest lowercase. This can be useful e.g. if you - highlight Pascal code and want to adapt the code to your styleguide. The - default is ``lower``, override that by providing the `keywordcase` - parameter. + Convert keywords to ``lower``, ``upper`` or ``capitalize`` which means + first letter uppercase, rest lowercase. + + This can be useful e.g. if you highlight Pascal code and want to adapt the + code to your styleguide. The default is ``lower``, override that by + providing the `case` parameter. """ def __init__(self, **options): Filter.__init__(self, **options) - case = options.get('keywordcase', 'lower') + case = options.get('case', 'lower') if case not in ('lower', 'upper', 'capitalize'): raise TypeError('unknown conversion method %r' % case) self.convert = getattr(unicode, case) @@ -104,11 +117,13 @@ class KeywordCaseFilter(Filter): class NameHighlightFilter(Filter): """ - Highlight normal name token with a different one:: + Highlight a normal Name token with a different token type. + + Example:: filter = NameHighlightFilter( - highlight=['foo', 'bar', 'baz'], - highlight_token=Name.Function + names=['foo', 'bar', 'baz'], + tokentype=Name.Function, ) This would highlight the names "foo", "bar" and "baz" @@ -117,23 +132,23 @@ class NameHighlightFilter(Filter): def __init__(self, **options): Filter.__init__(self, **options) - self.words = set(get_list_opt(options, 'highlight', [])) - highlight_token = options.get('highlight_token') - if highlight_token: - self.highlight_token = string_to_tokentype(highlight_token) + self.names = set(get_list_opt(options, 'names', [])) + tokentype = options.get('tokentype') + if tokentype: + self.tokentype = string_to_tokentype(tokentype) else: - self.highlight_token = Name.Function + self.tokentype = Name.Function def filter(self, lexer, stream): for ttype, value in stream: - if ttype is Name and value in self.words: - yield self.highlight_token, value + if ttype is Name and value in self.names: + yield self.tokentype, value else: yield ttype, value FILTERS = { - 'codetagify': CodeTagFilter, - 'keywordcase': KeywordCaseFilter, - 'highlight': NameHighlightFilter + 'codetagify': CodeTagFilter, + 'keywordcase': KeywordCaseFilter, + 'highlight': NameHighlightFilter, } diff --git a/pygments/formatter.py b/pygments/formatter.py index d84e76e6..60848b52 100644 --- a/pygments/formatter.py +++ b/pygments/formatter.py @@ -48,6 +48,15 @@ class Formatter(object): Overrides ``encoding`` if given. """ + #: Name of the formatter + name = None + + #: Shortcuts for the formatter + aliases = [] + + #: fn match rules + filenames = [] + #: If True, this formatter outputs Unicode strings when no encoding #: option is given. unicodeoutput = True diff --git a/pygments/formatters/__init__.py b/pygments/formatters/__init__.py index 2fc55878..397f5027 100644 --- a/pygments/formatters/__init__.py +++ b/pygments/formatters/__init__.py @@ -9,79 +9,54 @@ :license: BSD, see LICENSE for more details. """ import os.path -from pygments.formatters.html import HtmlFormatter -from pygments.formatters.terminal import TerminalFormatter -from pygments.formatters.latex import LatexFormatter -from pygments.formatters.rtf import RtfFormatter -from pygments.formatters.bbcode import BBCodeFormatter -from pygments.formatters.other import NullFormatter, RawTokenFormatter -from pygments.plugin import find_plugin_formatters - - -def _doc_desc(obj): - if not obj.__doc__: - return '' - res = [] - for line in obj.__doc__.strip().splitlines(): - if line.strip(): - res.append(" " + line.strip()) - else: - break - return ''.join(res) +import fnmatch +from pygments.formatters._mapping import FORMATTERS +from pygments.plugin import find_plugin_formatters +from pygments.util import docstring_headline, ClassNotFound -#: Map formatter classes to ``(longname, names, file extensions, descr)``. -FORMATTERS = { - HtmlFormatter: ('HTML', ('html',), ('.htm', '.html'), - _doc_desc(HtmlFormatter)), - LatexFormatter: ('LaTeX', ('latex', 'tex'), ('.tex',), - _doc_desc(LatexFormatter)), - RtfFormatter: ('RTF', ('rtf',), ('.rtf',), - _doc_desc(RtfFormatter)), - TerminalFormatter: ('Terminal', ('terminal', 'console'), (), - _doc_desc(TerminalFormatter)), - BBCodeFormatter: ('BBcode', ('bbcode', 'bb'), (), - _doc_desc(BBCodeFormatter)), - RawTokenFormatter: ('Raw tokens', ('raw', 'tokens'), ('.raw',), - _doc_desc(RawTokenFormatter)), - NullFormatter: ('Text only', ('text', 'null'), ('.txt',), - _doc_desc(NullFormatter)), -} +ns = globals() +for cls in FORMATTERS: + ns[cls.__name__] = cls +__all__ = ['get_formatter_by_name', 'get_formatter_for_filename', + 'get_all_formatters'] + [cls.__name__ for cls in FORMATTERS] + -_formatter_cache = {} +_formatter_alias_cache = {} +_formatter_filename_cache = [] def _init_formatter_cache(): - if _formatter_cache: + if _formatter_alias_cache: return - for cls, info in FORMATTERS.iteritems(): - for alias in info[1]: - _formatter_cache[alias] = cls - for ext in info[2]: - _formatter_cache["/"+ext] = cls - for name, cls in find_plugin_formatters(): - _formatter_cache[name] = cls + for cls in get_all_formatters(): + for alias in cls.aliases: + _formatter_alias_cache[alias] = cls + for fn in cls.filenames: + _formatter_filename_cache.append((fn, cls)) + + +def find_formatter_class(name): + _init_formatter_cache() + cls = _formatter_alias_cache.get(name, None) + return cls def get_formatter_by_name(name, **options): _init_formatter_cache() - cls = _formatter_cache.get(name, None) + cls = _formatter_alias_cache.get(name, None) if not cls: - raise ValueError("No formatter found for name %r" % name) + raise ClassNotFound("No formatter found for name %r" % name) return cls(**options) def get_formatter_for_filename(fn, **options): _init_formatter_cache() - # try by filename extension - cls = _formatter_cache.get("/"+os.path.splitext(fn)[1], None) - if cls: - return cls(**options) - # try by whole file name - cls = _formatter_cache.get("/"+os.path.basename(fn), None) - if not cls: - raise ValueError("No formatter found for file name %r" % fn) - return cls(**options) + fn = os.path.basename(fn) + for pattern, cls in _formatter_filename_cache: + if fnmatch.fnmatch(fn, pattern): + return cls(**options) + raise ClassNotFound("No formatter found for file name %r" % fn) def get_all_formatters(): diff --git a/pygments/formatters/_mapping.py b/pygments/formatters/_mapping.py new file mode 100755 index 00000000..03e3c10f --- /dev/null +++ b/pygments/formatters/_mapping.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +""" + pygments.formatters._mapping + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter mapping defintions. This file is generated by itself. Everytime + you change something on a builtin formatter defintion, run this script from + the formatters folder to update it. + + Do not alter the FORMATTERS dictionary by hand. + + :copyright: 2006-2007 by Armin Ronacher, Georg Brandl. + :license: BSD, see LICENSE for more details. +""" + +from pygments.util import docstring_headline + +# start +from pygments.formatters.bbcode import BBCodeFormatter +from pygments.formatters.html import HtmlFormatter +from pygments.formatters.latex import LatexFormatter +from pygments.formatters.other import NullFormatter +from pygments.formatters.other import RawTokenFormatter +from pygments.formatters.rtf import RtfFormatter +from pygments.formatters.terminal import TerminalFormatter + +FORMATTERS = { + BBCodeFormatter: ('BBCode', ('bbcode', 'bb'), (), 'Format tokens with BBcodes. These formatting codes are used by many bulletin boards, so you can highlight your sourcecode with pygments before posting it there.'), + HtmlFormatter: ('HTML', ('html',), ('*.html', '*.htm'), "Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass` option."), + LatexFormatter: ('LaTeX', ('latex', 'tex'), ('*.tex',), 'Format tokens as LaTeX code. This needs the `fancyvrb` and `color` standard packages.'), + NullFormatter: ('Text only', ('text', 'null'), ('*.txt',), 'Output the text unchanged without any formatting.'), + RawTokenFormatter: ('Raw tokens', ('raw', 'tokens'), ('*.raw',), 'Format tokens as a raw representation for storing token streams.'), + RtfFormatter: ('RTF', ('rtf',), ('*.rtf',), 'Format tokens as RTF markup. This formatter automatically outputs full RTF documents with color information and other useful stuff. Perfect for Copy and Paste into Microsoft\xc2\xae Word\xc2\xae documents.'), + TerminalFormatter: ('Terminal', ('terminal', 'console'), (), 'Format tokens with ANSI color sequences, for output in a text console. Color sequences are terminated at newlines, so that paging the output works correctly.') +} + +if __name__ == '__main__': + import sys + import os + + # lookup formatters + found_formatters = [] + imports = [] + sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) + for filename in os.listdir('.'): + if filename.endswith('.py') and not filename.startswith('_'): + module_name = 'pygments.formatters.%s' % filename[:-3] + print module_name + module = __import__(module_name, None, None, ['']) + for formatter_name in module.__all__: + imports.append((module_name, formatter_name)) + formatter = getattr(module, formatter_name) + found_formatters.append( + '%s: %r' % (formatter_name, + (formatter.name, + tuple(formatter.aliases), + tuple(formatter.filenames), + docstring_headline(formatter)))) + # sort them, that should make the diff files for svn smaller + found_formatters.sort() + imports.sort() + + # extract useful sourcecode from this file + f = file(__file__) + try: + content = f.read() + finally: + f.close() + header = content[:content.find('# start')] + footer = content[content.find("if __name__ == '__main__':"):] + + # write new file + f = file(__file__, 'w') + f.write(header) + f.write('# start\n') + f.write('\n'.join(['from %s import %s' % imp for imp in imports])) + f.write('\n\n') + f.write('FORMATTERS = {\n %s\n}\n\n' % ',\n '.join(found_formatters)) + f.write(footer) + f.close() diff --git a/pygments/formatters/bbcode.py b/pygments/formatters/bbcode.py index 57112d77..0496b463 100644 --- a/pygments/formatters/bbcode.py +++ b/pygments/formatters/bbcode.py @@ -18,7 +18,7 @@ __all__ = ['BBCodeFormatter'] class BBCodeFormatter(Formatter): """ - Formats tokens with BBcodes. These formatting codes are used by many + Format tokens with BBcodes. These formatting codes are used by many bulletin boards, so you can highlight your sourcecode with pygments before posting it there. @@ -41,6 +41,9 @@ class BBCodeFormatter(Formatter): If set to true, add a tag to show the code with a monospace font (default: ``false``). """ + name = 'BBCode' + aliases = ['bbcode', 'bb'] + filenames = [] def __init__(self, **options): Formatter.__init__(self, **options) diff --git a/pygments/formatters/html.py b/pygments/formatters/html.py index d5e9c3f7..01a9edf9 100644 --- a/pygments/formatters/html.py +++ b/pygments/formatters/html.py @@ -99,7 +99,7 @@ td.linenos { background-color: #f0f0f0; padding-right: 10px; } class HtmlFormatter(Formatter): - """ + r""" Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass` option. @@ -254,6 +254,10 @@ class HtmlFormatter(Formatter): and/or "full document" wrappers if the respective options are set. """ + name = 'HTML' + aliases = ['html'] + filenames = ['*.html', '*.htm'] + def __init__(self, **options): Formatter.__init__(self, **options) self.nowrap = get_bool_opt(options, 'nowrap', False) diff --git a/pygments/formatters/latex.py b/pygments/formatters/latex.py index 22256625..a1e35c75 100644 --- a/pygments/formatters/latex.py +++ b/pygments/formatters/latex.py @@ -90,6 +90,9 @@ class LatexFormatter(Formatter): using this prefix and some letters (default: ``'C'``). *New in Pygments 0.7.* """ + name = 'LaTeX' + aliases = ['latex', 'tex'] + filenames = ['*.tex'] def __init__(self, **options): Formatter.__init__(self, **options) diff --git a/pygments/formatters/other.py b/pygments/formatters/other.py index 6b70238e..d83c77ea 100644 --- a/pygments/formatters/other.py +++ b/pygments/formatters/other.py @@ -19,6 +19,10 @@ class NullFormatter(Formatter): """ Output the text unchanged without any formatting. """ + name = 'Text only' + aliases = ['text', 'null'] + filenames = ['*.txt'] + def format(self, tokensource, outfile): enc = self.encoding for ttype, value in tokensource: @@ -30,7 +34,7 @@ class NullFormatter(Formatter): class RawTokenFormatter(Formatter): r""" - Formats tokens as a raw representation for storing token streams. + Format tokens as a raw representation for storing token streams. The format is ``tokentype<TAB>repr(tokenstring)\n``. The output can later be converted to a token stream with the `RawTokenLexer`, described in the @@ -42,6 +46,9 @@ class RawTokenFormatter(Formatter): If set to ``'gz'`` or ``'bz2'``, compress the output with the given compression algorithm after encoding (default: ``''``). """ + name = 'Raw tokens' + aliases = ['raw', 'tokens'] + filenames = ['*.raw'] unicodeoutput = False diff --git a/pygments/formatters/rtf.py b/pygments/formatters/rtf.py index c4078dd8..74538d0a 100644 --- a/pygments/formatters/rtf.py +++ b/pygments/formatters/rtf.py @@ -17,7 +17,7 @@ __all__ = ['RtfFormatter'] class RtfFormatter(Formatter): """ - Formats tokens as RTF markup. This formatter automatically outputs full RTF + Format tokens as RTF markup. This formatter automatically outputs full RTF documents with color information and other useful stuff. Perfect for Copy and Paste into Microsoft® Word® documents. @@ -29,6 +29,9 @@ class RtfFormatter(Formatter): The used font famliy, for example ``Bitstream Vera Sans``. Defaults to some generic font which is supposed to have fixed width. """ + name = 'RTF' + aliases = ['rtf'] + filenames = ['*.rtf'] unicodeoutput = False diff --git a/pygments/formatters/terminal.py b/pygments/formatters/terminal.py index fa030d86..cad37c7d 100644 --- a/pygments/formatters/terminal.py +++ b/pygments/formatters/terminal.py @@ -52,7 +52,7 @@ TERMINAL_COLORS = { class TerminalFormatter(Formatter): r""" - Formats tokens with ANSI color sequences, for output in a text console. + Format tokens with ANSI color sequences, for output in a text console. Color sequences are terminated at newlines, so that paging the output works correctly. @@ -69,6 +69,9 @@ class TerminalFormatter(Formatter): A dictionary mapping token types to (lightbg, darkbg) color names or ``None`` (default: ``None`` = use builtin colorscheme). """ + name = 'Terminal' + aliases = ['terminal', 'console'] + filenames = [] def __init__(self, **options): Formatter.__init__(self, **options) diff --git a/pygments/lexer.py b/pygments/lexer.py index 5f1e6ab1..6cec28f8 100644 --- a/pygments/lexer.py +++ b/pygments/lexer.py @@ -16,7 +16,7 @@ except NameError: from sets import Set as set from pygments.filter import apply_filters, Filter -from pygments.filters import find_filter +from pygments.filters import get_filter_by_name from pygments.token import Error, Text, Other, _TokenType from pygments.util import get_bool_opt, get_int_opt, get_list_opt, \ make_analysator @@ -101,7 +101,7 @@ class Lexer(object): Add a new stream filter to this lexer. """ if not isinstance(filter, Filter): - filter = find_filter(filter, **options) + filter = get_filter_by_name(filter, **options) self.filters.append(filter) def analyse_text(text): @@ -121,8 +121,8 @@ class Lexer(object): def get_tokens(self, text, unfiltered=False): """ Return an iterable of (tokentype, value) pairs generated from - `text`. If `unfiltered` is set to `True` the filtering mechanism - is bypassed, even if filters are defined. + `text`. If `unfiltered` is set to `True`, the filtering mechanism + is bypassed even if filters are defined. Also preprocess the text, i.e. expand tabs and strip it if wanted and applies registered filters. diff --git a/pygments/lexers/__init__.py b/pygments/lexers/__init__.py index b6bba998..255fa022 100644 --- a/pygments/lexers/__init__.py +++ b/pygments/lexers/__init__.py @@ -19,9 +19,10 @@ except NameError: from pygments.lexers._mapping import LEXERS from pygments.plugin import find_plugin_lexers +from pygments.util import ClassNotFound -__all__ = ['get_lexer_by_name', 'get_lexer_for_filename', +__all__ = ['get_lexer_by_name', 'get_lexer_for_filename', 'find_lexer_class', 'guess_lexer'] + LEXERS.keys() _lexer_cache = {} @@ -48,6 +49,23 @@ def get_all_lexers(): yield lexer.name, lexer.aliases, lexer.filenames, lexer.mimetypes +def find_lexer_class(name): + """ + Lookup a lexer class by name. Return None if not found. + """ + if name in _lexer_cache: + return _lexer_cache[name] + # lookup builtin lexers + for module_name, lname, aliases, _, _ in LEXERS.itervalues(): + if name == lname: + _load_lexers(module_name) + return _lexer_cache[name] + # continue with lexers from setuptools entrypoints + for cls in find_plugin_lexers(): + if cls.name == name: + return cls + + def get_lexer_by_name(_alias, **options): """ Get a lexer by an alias. @@ -62,7 +80,7 @@ def get_lexer_by_name(_alias, **options): for cls in find_plugin_lexers(): if _alias in cls.aliases: return cls(**options) - raise ValueError('no lexer for alias %r found' % _alias) + raise ClassNotFound('no lexer for alias %r found' % _alias) def get_lexer_for_filename(_fn, **options): @@ -80,7 +98,7 @@ def get_lexer_for_filename(_fn, **options): for filename in cls.filenames: if fnmatch.fnmatch(fn, filename): return cls(**options) - raise ValueError('no lexer for filename %r found' % _fn) + raise ClassNotFound('no lexer for filename %r found' % _fn) def get_lexer_for_mimetype(_mime, **options): @@ -95,7 +113,7 @@ def get_lexer_for_mimetype(_mime, **options): for cls in find_plugin_lexers(): if _mime in cls.mimetypes: return cls(**options) - raise ValueError('no lexer for mimetype %r found' % _mime) + raise ClassNotFound('no lexer for mimetype %r found' % _mime) def _iter_lexerclasses(): @@ -138,7 +156,7 @@ def guess_lexer_for_filename(_fn, _text, **options): if fnmatch.fnmatch(fn, filename): matching_lexers.add(lexer) if not matching_lexers: - raise ValueError('no lexer for filename %r found' % fn) + raise ClassNotFound('no lexer for filename %r found' % fn) if len(matching_lexers) == 1: return matching_lexers.pop()(**options) result = [] @@ -165,7 +183,7 @@ def guess_lexer(_text, **options): if rv > best_lexer[0]: best_lexer[:] = (rv, lexer) if not best_lexer[0] or best_lexer[1] is None: - raise ValueError('no lexer matching the text found') + raise ClassNotFound('no lexer matching the text found') return best_lexer[1](**options) diff --git a/pygments/styles/__init__.py b/pygments/styles/__init__.py index 1b75dcbc..cd172adf 100644 --- a/pygments/styles/__init__.py +++ b/pygments/styles/__init__.py @@ -8,7 +8,9 @@ :copyright: 2006-2007 by Georg Brandl. :license: BSD, see LICENSE for more details. """ + from pygments.plugin import find_plugin_styles +from pygments.util import ClassNotFound #: Maps style names to 'submodule::classname'. @@ -45,12 +47,12 @@ def get_style_by_name(name): try: mod = __import__('pygments.styles.' + mod, None, None, [cls]) except ImportError: - raise ValueError("Could not find style module %r" % mod + + raise ClassNotFound("Could not find style module %r" % mod + (builtin and ", though it should be builtin") + ".") try: return getattr(mod, cls) except AttributeError: - raise ValueError("Could not find style class %r in style module." % cls) + raise ClassNotFound("Could not find style class %r in style module." % cls) def get_all_styles(): diff --git a/pygments/styles/autumn.py b/pygments/styles/autumn.py index cdb6cde6..4508db17 100644 --- a/pygments/styles/autumn.py +++ b/pygments/styles/autumn.py @@ -15,6 +15,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class AutumnStyle(Style): + """ + A colorful style, inspired by the terminal highlighting style. + """ default_style = "" diff --git a/pygments/styles/borland.py b/pygments/styles/borland.py index 282eb5e3..696178d3 100644 --- a/pygments/styles/borland.py +++ b/pygments/styles/borland.py @@ -15,6 +15,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class BorlandStyle(Style): + """ + Style similar to the style used in the borland IDEs. + """ default_style = '' diff --git a/pygments/styles/colorful.py b/pygments/styles/colorful.py index 667af836..16f084e6 100644 --- a/pygments/styles/colorful.py +++ b/pygments/styles/colorful.py @@ -15,6 +15,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class ColorfulStyle(Style): + """ + A colorful style, inspired by CodeRay. + """ default_style = "" diff --git a/pygments/styles/friendly.py b/pygments/styles/friendly.py index dc2dd2d7..b1e95037 100644 --- a/pygments/styles/friendly.py +++ b/pygments/styles/friendly.py @@ -15,6 +15,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class FriendlyStyle(Style): + """ + A modern style based on the VIM pyte theme. + """ background_color = "#f0f0f0" default_style = "" diff --git a/pygments/styles/fruity.py b/pygments/styles/fruity.py index 1827b2df..ba1f388a 100644 --- a/pygments/styles/fruity.py +++ b/pygments/styles/fruity.py @@ -14,6 +14,9 @@ from pygments.token import Token, Comment, Name, Keyword, \ Generic, Number, String class FruityStyle(Style): + """ + Pygments version of the "native" vim theme. + """ background_color = '#111111' diff --git a/pygments/styles/manni.py b/pygments/styles/manni.py index 19f4b67d..bdc979e2 100644 --- a/pygments/styles/manni.py +++ b/pygments/styles/manni.py @@ -18,6 +18,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class ManniStyle(Style): + """ + A colorful style, inspired by the terminal highlighting style. + """ background_color = '#f0f3f3' diff --git a/pygments/styles/murphy.py b/pygments/styles/murphy.py index d7d27f98..06cc795b 100644 --- a/pygments/styles/murphy.py +++ b/pygments/styles/murphy.py @@ -15,6 +15,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class MurphyStyle(Style): + """ + Murphy's style from CodeRay. + """ default_style = "" diff --git a/pygments/styles/native.py b/pygments/styles/native.py index 978b833b..c9b290b0 100644 --- a/pygments/styles/native.py +++ b/pygments/styles/native.py @@ -15,6 +15,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class NativeStyle(Style): + """ + Pygments version of the "native" vim theme. + """ background_color = '#202020' diff --git a/pygments/styles/pastie.py b/pygments/styles/pastie.py index fe42ab8c..c57fa553 100644 --- a/pygments/styles/pastie.py +++ b/pygments/styles/pastie.py @@ -17,6 +17,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class PastieStyle(Style): + """ + Style similar to the pastie default style. + """ default_style = '' diff --git a/pygments/styles/perldoc.py b/pygments/styles/perldoc.py index 0693bc0d..6ce06624 100644 --- a/pygments/styles/perldoc.py +++ b/pygments/styles/perldoc.py @@ -17,6 +17,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class PerldocStyle(Style): + """ + Style similar to the style used in the perldoc code blocks. + """ background_color = '#eeeedd' default_style = '' diff --git a/pygments/styles/trac.py b/pygments/styles/trac.py index 16808fe5..0e32986f 100644 --- a/pygments/styles/trac.py +++ b/pygments/styles/trac.py @@ -15,6 +15,9 @@ from pygments.token import Keyword, Name, Comment, String, Error, \ class TracStyle(Style): + """ + Port of the default trac highlighter design. + """ default_style = '' diff --git a/pygments/util.py b/pygments/util.py index bf9f1a26..79fa250e 100644 --- a/pygments/util.py +++ b/pygments/util.py @@ -23,6 +23,12 @@ doctype_lookup_re = re.compile(r'''(?smx) tag_re = re.compile(r'<(.+?)(\s.*?)?>.*?</\1>(?uism)') +class ClassNotFound(ValueError): + """ + If one of the get_*_by_* functions didn't find a matching class. + """ + + class OptionError(Exception): pass @@ -63,6 +69,18 @@ def get_list_opt(options, optname, default=None): val, optname)) +def docstring_headline(obj): + if not obj.__doc__: + return '' + res = [] + for line in obj.__doc__.strip().splitlines(): + if line.strip(): + res.append(" " + line.strip()) + else: + break + return ''.join(res).lstrip() + + def make_analysator(f): """ Return a static text analysation function that |