Commits

Ross Peoples committed 6719bbd

Added Pygments supports for code blocks. Also added live preview support. Right now, only markmin has been tested.

Comments (0)

Files changed (390)

-Write something about this app.
-Developed with web2py.
+web2py plugin for MarkItDown: http://markitup.jaysalvat.com/home/

controllers/default.py

     example action using the internationalization operator T and flash
     rendered by views/default/index.html or views/generic.html
     """
-    response.flash = "Welcome to web2py!"
-    return dict(message=T('Hello World'))
+    from plugin_markitup.markitup import MarkItUp
+    markitup = MarkItUp()
+    return dict(markitup=markitup.markitup())
 
 def user():
     """

controllers/plugin_markitup.py

 __email__ = 'ross.peoples@gmail.com'
 __copyright__ = 'Copyright(c) 2012, Ross Peoples'
 __license__ = 'LGPLv3'
+
+def preview():
+    set_name = request.vars.set_name or error('Missing set_name argument')
+    data = request.vars.data or error('No content to render')
+    
+    from plugin_markitup import render
+    return render.render(data, set_name, 'html')
+    
+def error(text):
+    raise HTTP(400, text)

modules/plugin_markitup.py

-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
-web2py plugin for MarkItUp: http://markitup.jaysalvat.com/home/
-"""
-__author__ = 'Ross Peoples'
-__email__ = 'ross.peoples@gmail.com'
-__copyright__ = 'Copyright(c) 2012, Ross Peoples'
-__license__ = 'LGPLv3'
-
-from gluon import *
-from gluon.storage import Storage
-from gluon.sqlhtml import FormWidget
-    
-class MarkItUp(object):
-    def __init__(self, set_name='markmin', preview='plugin_markitup'):
-        """
-        Initializes the MarkItUp module. Optional parameters:
-        
-        @param set_name Name of the set to use for markup. Default: 'markmin'
-        @param preview  Name of the controller with the 'preview' method that
-                        will be used to render the markup for previewing.
-                        Default: 'plugin_markitup'
-                        
-        Sets included with plugin:
-            - bbcode
-            - html
-            - markdown
-            - markmin
-            - rest (reStructuredText)
-            - textile
-            - wiki
-        """  
-        self.settings = Storage()
-        self.settings.set_name = set_name
-        self.settings.preview = preview
-    
-    def load(self, **attributes):
-        """
-        Loads the required javascript. All parameters are optional:
-        
-        @param _id      The ID of the TEXTAREA. Default: 'markitup'
-        """
-        _id = attributes.get('_id', 'markitup')
-        set_name = self.settings.set_name
-        preview = self.settings.preview
-        
-        javascript = """
-            <script type='text/javascript'>
-                jQuery(function() {
-                    jQuery('#%(_id)s').markItUp(mySettings);
-                })
-            </script>
-        """ % dict(_id=_id)
-        
-        if not current.response['plugin_markitup_%s' % set_name] :
-            current.response.files.append(URL('static','plugin_markitup/jquery.markitup.js'))
-            current.response.files.append(URL('static','plugin_markitup/sets/%s/set.js' % set_name))
-            current.response.files.append(URL('static','plugin_markitup/sets/%s/style.css' % set_name))
-            current.response['plugin_markitup_%s' % set_name] = True
-            
-            preview_sets = [
-                'markdown',
-                'markmin'
-            ]
-            
-            if preview and set_name in preview_sets:
-                javascript += """
-                    <script type="text/javascript">
-                        mySettings.previewParserPath = '%s';
-                    </script>
-                """ % URL(preview, 'preview')
-        
-        return XML(javascript)
-        
-    def markitup(self, value='', **attributes):
-        """
-        Creates the MarkItUp widget. All parameters are optional:
-        
-        @param value    The contents of the TEXTAREA. Default: (empty)
-        @param _id      The ID of the TEXTAREA. Default: 'markitup'
-        @param _class   The class of the TEXTAREA. Default: 'markitup'
-        
-        Example controller:
-            from markitup import MarkItUp
-        
-            def test():
-                markitup = MarkItUp().markitup(request.args(0) or 'Default value')
-                return dict(markitup=markitup)
-        """
-        
-        default = dict(
-            value = value,
-            _id = 'markitup',
-            _class = 'markitup'
-        )
-        
-        default.update(attributes)
-        textarea = TEXTAREA(**default)
-        javascript = load(**default)
-        return CAT(textarea, javascript)
-    
-    def widget(self, field, value, **attributes):
-        """
-        To be used with db.table.field.widget to set MarkItUp as the desired widget
-        for the field. Simply set db.table.field.widget = MarkItUp().widget to use
-        MarkItUp for a 'text' field.
-        
-        Example model:
-            from markitup import MarkItUp
-        
-            db.define_table('content',
-                Field('name', length=20),
-                Field('description', 'text')
-            )
-            db.content.description.widget = MarkItUp().widget
-            
-        Example controller:
-            def test():
-                form = SQLFORM(db.content)
-                if form.accepts(request, session):
-                    redirect(URL())
-                
-                return dict(form=form)
-        """
-        attributes = FormWidget._attributes(field, dict(), **attributes)
-        return markitup(value, **attributes)

modules/plugin_markitup/__init__.py

+

modules/plugin_markitup/markitup.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+web2py plugin for MarkItUp: http://markitup.jaysalvat.com/home/
+"""
+__author__ = 'Ross Peoples'
+__email__ = 'ross.peoples@gmail.com'
+__copyright__ = 'Copyright(c) 2012, Ross Peoples'
+__license__ = 'LGPLv3'
+
+from gluon import *
+from gluon.storage import Storage
+from gluon.sqlhtml import FormWidget
+    
+class MarkItUp(object):
+    def __init__(self, set_name='markmin', preview='plugin_markitup'):
+        """
+        Initializes the MarkItUp module. Optional parameters:
+        
+        @param set_name Name of the set to use for markup. Default: 'markmin'
+        @param preview  Name of the controller with the 'preview' method that
+                        will be used to render the markup for previewing.
+                        Default: 'plugin_markitup'
+                        
+        Sets included with plugin:
+            - bbcode
+            - html
+            - markdown
+            - markmin
+            - rest (reStructuredText)
+            - textile
+            - wiki
+        """  
+        self.settings = Storage()
+        self.settings.set_name = set_name
+        self.settings.preview = preview
+    
+    def load(self, **attributes):
+        """
+        Loads the required javascript. All parameters are optional:
+        
+        @param _id      The ID of the TEXTAREA. Default: 'markitup'
+        """
+        _id = attributes.get('_id', 'markitup')
+        set_name = self.settings.set_name
+        preview = self.settings.preview
+        
+        javascript = """
+            <script type='text/javascript'>
+                jQuery(function() {
+                    jQuery('#%(_id)s').markItUp(mySettings);
+                })
+            </script>
+        """ % dict(_id=_id)
+        
+        if not current.response['plugin_markitup_%s' % set_name]:
+            current.response.files.append(URL('static','plugin_markitup/jquery.markitup.js'))
+            current.response.files.append(URL('static','plugin_markitup/skins/markitup/style.css'))
+            current.response.files.append(URL('static','plugin_markitup/sets/%s/set.js' % set_name))
+            current.response.files.append(URL('static','plugin_markitup/sets/%s/style.css' % set_name))
+            current.response['plugin_markitup_%s' % set_name] = True
+            
+            preview_sets = [
+                'markdown',
+                'markmin'
+            ]
+            
+            if preview and set_name in preview_sets:
+                javascript += """
+                    <script type="text/javascript">
+                        mySettings['previewParserPath'] = '%s';
+                    </script>
+                """ % URL(preview, 'preview', vars=dict(set_name=set_name))
+        
+        return XML(javascript)
+        
+    def markitup(self, value='', **attributes):
+        """
+        Creates the MarkItUp widget. All parameters are optional:
+        
+        @param value    The contents of the TEXTAREA. Default: (empty)
+        @param _id      The ID of the TEXTAREA. Default: 'markitup'
+        @param _class   The class of the TEXTAREA. Default: 'markitup'
+        
+        Example controller:
+            from plugin_markitup.markitup import MarkItUp
+        
+            def test():
+                markitup = MarkItUp().markitup(request.args(0) or 'Default value')
+                return dict(markitup=markitup)
+        """
+        
+        default = dict(
+            value = value,
+            _id = 'markitup',
+            _class = 'markitup',
+            _cols = 20
+        )
+        
+        default.update(attributes)
+        textarea = TEXTAREA(**default)
+        javascript = self.load(**default)
+        return CAT(textarea, javascript)
+    
+    def widget(self, field, value, **attributes):
+        """
+        To be used with db.table.field.widget to set MarkItUp as the desired widget
+        for the field. Simply set db.table.field.widget = MarkItUp().widget to use
+        MarkItUp for a 'text' field.
+        
+        Example model:
+            from plugin_markitup.markitup import MarkItUp
+        
+            db.define_table('content',
+                Field('name', length=20),
+                Field('description', 'text')
+            )
+            db.content.description.widget = MarkItUp().widget
+            
+        Example controller:
+            def test():
+                form = SQLFORM(db.content)
+                if form.accepts(request, session):
+                    redirect(URL())
+                
+                return dict(form=form)
+        """
+        attributes = FormWidget._attributes(field, dict(), **attributes)
+        return markitup(value, **attributes)

modules/plugin_markitup/pygments/__init__.py

+# -*- coding: utf-8 -*-
+"""
+    Pygments
+    ~~~~~~~~
+
+    Pygments is a syntax highlighting package written in Python.
+
+    It is a generic syntax highlighter for general use in all kinds of software
+    such as forum systems, wikis or other applications that need to prettify
+    source code. Highlights are:
+
+    * a wide range of common languages and markup formats is supported
+    * special attention is paid to details, increasing quality by a fair amount
+    * support for new languages and formats are added easily
+    * a number of output formats, presently HTML, LaTeX, RTF, SVG, all image
+      formats that PIL supports, and ANSI sequences
+    * it is usable as a command-line tool and as a library
+    * ... and it highlights even Brainfuck!
+
+    The `Pygments tip`_ is installable with ``easy_install Pygments==dev``.
+
+    .. _Pygments tip:
+       http://bitbucket.org/birkenfeld/pygments-main/get/tip.zip#egg=Pygments-dev
+
+    :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+__version__ = '1.4'
+__docformat__ = 'restructuredtext'
+
+__all__ = ['lex', 'format', 'highlight']
+
+
+import sys
+
+from pygments.util import StringIO, BytesIO
+
+
+def lex(code, lexer):
+    """
+    Lex ``code`` with ``lexer`` and return an iterable of tokens.
+    """
+    try:
+        return lexer.get_tokens(code)
+    except TypeError, err:
+        if isinstance(err.args[0], str) and \
+           'unbound method get_tokens' in err.args[0]:
+            raise TypeError('lex() argument must be a lexer instance, '
+                            'not a class')
+        raise
+
+
+def format(tokens, formatter, outfile=None):
+    """
+    Format a tokenlist ``tokens`` with the formatter ``formatter``.
+
+    If ``outfile`` is given and a valid file object (an object
+    with a ``write`` method), the result will be written to it, otherwise
+    it is returned as a string.
+    """
+    try:
+        if not outfile:
+            #print formatter, 'using', formatter.encoding
+            realoutfile = formatter.encoding and BytesIO() or StringIO()
+            formatter.format(tokens, realoutfile)
+            return realoutfile.getvalue()
+        else:
+            formatter.format(tokens, outfile)
+    except TypeError, err:
+        if isinstance(err.args[0], str) and \
+           'unbound method format' in err.args[0]:
+            raise TypeError('format() argument must be a formatter instance, '
+                            'not a class')
+        raise
+
+
+def highlight(code, lexer, formatter, outfile=None):
+    """
+    Lex ``code`` with ``lexer`` and format it with the formatter ``formatter``.
+
+    If ``outfile`` is given and a valid file object (an object
+    with a ``write`` method), the result will be written to it, otherwise
+    it is returned as a string.
+    """
+    return format(lex(code, lexer), formatter, outfile)
+
+
+if __name__ == '__main__':
+    from pygments.cmdline import main
+    sys.exit(main(sys.argv))

modules/plugin_markitup/pygments/cmdline.py

+# -*- coding: utf-8 -*-
+"""
+    pygments.cmdline
+    ~~~~~~~~~~~~~~~~
+
+    Command line interface.
+
+    :copyright: Copyright 2006-2010 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

modules/plugin_markitup/pygments/console.py

+# -*- coding: utf-8 -*-
+"""
+    pygments.console
+    ~~~~~~~~~~~~~~~~
+
+    Format colored console output.
+
+    :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+esc = "\x1b["
+
+codes = {}
+codes[""]          = ""
+codes["reset"]     = esc + "39;49;00m"
+
+codes["bold"]      = esc + "01m"
+codes["faint"]     = esc + "02m"
+codes["standout"]  = esc + "03m"
+codes["underline"] = esc + "04m"
+codes["blink"]     = esc + "05m"
+codes["overline"]  = esc + "06m"
+
+dark_colors  = ["black", "darkred", "darkgreen", "brown", "darkblue",
+                "purple", "teal", "lightgray"]
+light_colors = ["darkgray", "red", "green", "yellow", "blue",
+                "fuchsia", "turquoise", "white"]
+
+x = 30
+for d, l in zip(dark_colors, light_colors):
+    codes[d] = esc + "%im" % x
+    codes[l] = esc + "%i;01m" % x
+    x += 1
+
+del d, l, x
+
+codes["darkteal"]   = codes["turquoise"]
+codes["darkyellow"] = codes["brown"]
+codes["fuscia"]     = codes["fuchsia"]
+codes["white"]      = codes["bold"]
+
+
+def reset_color():
+    return codes["reset"]
+
+
+def colorize(color_key, text):
+    return codes[color_key] + text + codes["reset"]
+
+
+def ansiformat(attr, text):
+    """
+    Format ``text`` with a color and/or some attributes::
+
+        color       normal color
+        *color*     bold color
+        _color_     underlined color
+        +color+     blinking color
+    """
+    result = []
+    if attr[:1] == attr[-1:] == '+':
+        result.append(codes['blink'])
+        attr = attr[1:-1]
+    if attr[:1] == attr[-1:] == '*':
+        result.append(codes['bold'])
+        attr = attr[1:-1]
+    if attr[:1] == attr[-1:] == '_':
+        result.append(codes['underline'])
+        attr = attr[1:-1]
+    result.append(codes[attr])
+    result.append(text)
+    result.append(codes['reset'])
+    return ''.join(result)

modules/plugin_markitup/pygments/filter.py

+# -*- coding: utf-8 -*-
+"""
+    pygments.filter
+    ~~~~~~~~~~~~~~~
+
+    Module that implements the default filter.
+
+    :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+
+def apply_filters(stream, filters, lexer=None):
+    """
+    Use this method to apply an iterable of filters to
+    a stream. If lexer is given it's forwarded to the
+    filter, otherwise the filter receives `None`.
+    """
+    def _apply(filter_, stream):
+        for token in filter_.filter(lexer, stream):
+            yield token
+    for filter_ in filters:
+        stream = _apply(filter_, stream)
+    return stream
+
+
+def simplefilter(f):
+    """
+    Decorator that converts a function into a filter::
+
+        @simplefilter
+        def lowercase(lexer, stream, options):
+            for ttype, value in stream:
+                yield ttype, value.lower()
+    """
+    return type(f.__name__, (FunctionFilter,), {
+                'function':     f,
+                '__module__':   getattr(f, '__module__'),
+                '__doc__':      f.__doc__
+            })
+
+
+class Filter(object):
+    """
+    Default filter. Subclass this class or use the `simplefilter`
+    decorator to create own filters.
+    """
+
+    def __init__(self, **options):
+        self.options = options
+
+    def filter(self, lexer, stream):
+        raise NotImplementedError()
+
+
+class FunctionFilter(Filter):
+    """
+    Abstract class used by `simplefilter` to create simple
+    function filters on the fly. The `simplefilter` decorator
+    automatically creates subclasses of this class for
+    functions passed to it.
+    """
+    function = None
+
+    def __init__(self, **options):
+        if not hasattr(self, 'function'):
+            raise TypeError('%r used without bound function' %
+                            self.__class__.__name__)
+        Filter.__init__(self, **options)
+
+    def filter(self, lexer, stream):
+        # pylint: disable-msg=E1102
+        for ttype, value in self.function(lexer, stream, self.options):
+            yield ttype, value

modules/plugin_markitup/pygments/filters/__init__.py

+# -*- coding: utf-8 -*-
+"""
+    pygments.filters
+    ~~~~~~~~~~~~~~~~
+
+    Module containing filter lookup functions and default
+    filters.
+
+    :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+import re
+
+from pygments.token import String, Comment, Keyword, Name, Error, Whitespace, \
+    string_to_tokentype
+from pygments.filter import Filter
+from pygments.util import get_list_opt, get_int_opt, get_bool_opt, \
+     get_choice_opt, ClassNotFound, OptionError
+from pygments.plugin import find_plugin_filters
+
+
+def find_filter_class(filtername):
+    """
+    Lookup a filter by name. Return None if not found.
+    """
+    if filtername in FILTERS:
+        return FILTERS[filtername]
+    for name, cls in find_plugin_filters():
+        if name == filtername:
+            return cls
+    return None
+
+
+def get_filter_by_name(filtername, **options):
+    """
+    Return an instantiated filter. Options are passed to the filter
+    initializer if wanted. Raise a ClassNotFound if not found.
+    """
+    cls = find_filter_class(filtername)
+    if cls:
+        return cls(**options)
+    else:
+        raise ClassNotFound('filter %r not found' % filtername)
+
+
+def get_all_filters():
+    """
+    Return a generator of all filter names.
+    """
+    for name in FILTERS:
+        yield name
+    for name, _ in find_plugin_filters():
+        yield name
+
+
+def _replace_special(ttype, value, regex, specialttype,
+                     replacefunc=lambda x: x):
+    last = 0
+    for match in regex.finditer(value):
+        start, end = match.start(), match.end()
+        if start != last:
+            yield ttype, value[last:start]
+        yield specialttype, replacefunc(value[start:end])
+        last = end
+    if last != len(value):
+        yield ttype, value[last:]
+
+
+class CodeTagFilter(Filter):
+    """
+    Highlight special code tags in comments and docstrings.
+
+    Options accepted:
+
+    `codetags` : list of strings
+       A list of strings that are flagged as code tags.  The default is to
+       highlight ``XXX``, ``TODO``, ``BUG`` and ``NOTE``.
+    """
+
+    def __init__(self, **options):
+        Filter.__init__(self, **options)
+        tags = get_list_opt(options, 'codetags',
+                            ['XXX', 'TODO', 'BUG', 'NOTE'])
+        self.tag_re = re.compile(r'\b(%s)\b' % '|'.join([
+            re.escape(tag) for tag in tags if tag
+        ]))
+
+    def filter(self, lexer, stream):
+        regex = self.tag_re
+        for ttype, value in stream:
+            if ttype in String.Doc or \
+               ttype in Comment and \
+               ttype not in Comment.Preproc:
+                for sttype, svalue in _replace_special(ttype, value, regex,
+                                                       Comment.Special):
+                    yield sttype, svalue
+            else:
+                yield ttype, value
+
+
+class KeywordCaseFilter(Filter):
+    """
+    Convert keywords to lowercase or uppercase or capitalize them, 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.
+
+    Options accepted:
+
+    `case` : string
+       The casing to convert keywords to. Must be one of ``'lower'``,
+       ``'upper'`` or ``'capitalize'``.  The default is ``'lower'``.
+    """
+
+    def __init__(self, **options):
+        Filter.__init__(self, **options)
+        case = get_choice_opt(options, 'case', ['lower', 'upper', 'capitalize'], 'lower')
+        self.convert = getattr(unicode, case)
+
+    def filter(self, lexer, stream):
+        for ttype, value in stream:
+            if ttype in Keyword:
+                yield ttype, self.convert(value)
+            else:
+                yield ttype, value
+
+
+class NameHighlightFilter(Filter):
+    """
+    Highlight a normal Name token with a different token type.
+
+    Example::
+
+        filter = NameHighlightFilter(
+            names=['foo', 'bar', 'baz'],
+            tokentype=Name.Function,
+        )
+
+    This would highlight the names "foo", "bar" and "baz"
+    as functions. `Name.Function` is the default token type.
+
+    Options accepted:
+
+    `names` : list of strings
+      A list of names that should be given the different token type.
+      There is no default.
+    `tokentype` : TokenType or string
+      A token type or a string containing a token type name that is
+      used for highlighting the strings in `names`.  The default is
+      `Name.Function`.
+    """
+
+    def __init__(self, **options):
+        Filter.__init__(self, **options)
+        self.names = set(get_list_opt(options, 'names', []))
+        tokentype = options.get('tokentype')
+        if tokentype:
+            self.tokentype = string_to_tokentype(tokentype)
+        else:
+            self.tokentype = Name.Function
+
+    def filter(self, lexer, stream):
+        for ttype, value in stream:
+            if ttype is Name and value in self.names:
+                yield self.tokentype, value
+            else:
+                yield ttype, value
+
+
+class ErrorToken(Exception):
+    pass
+
+class RaiseOnErrorTokenFilter(Filter):
+    """
+    Raise an exception when the lexer generates an error token.
+
+    Options accepted:
+
+    `excclass` : Exception class
+      The exception class to raise.
+      The default is `pygments.filters.ErrorToken`.
+
+    *New in Pygments 0.8.*
+    """
+
+    def __init__(self, **options):
+        Filter.__init__(self, **options)
+        self.exception = options.get('excclass', ErrorToken)
+        try:
+            # issubclass() will raise TypeError if first argument is not a class
+            if not issubclass(self.exception, Exception):
+                raise TypeError
+        except TypeError:
+            raise OptionError('excclass option is not an exception class')
+
+    def filter(self, lexer, stream):
+        for ttype, value in stream:
+            if ttype is Error:
+                raise self.exception(value)
+            yield ttype, value
+
+
+class VisibleWhitespaceFilter(Filter):
+    """
+    Convert tabs, newlines and/or spaces to visible characters.
+
+    Options accepted:
+
+    `spaces` : string or bool
+      If this is a one-character string, spaces will be replaces by this string.
+      If it is another true value, spaces will be replaced by ``·`` (unicode
+      MIDDLE DOT).  If it is a false value, spaces will not be replaced.  The
+      default is ``False``.
+    `tabs` : string or bool
+      The same as for `spaces`, but the default replacement character is ``»``
+      (unicode RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK).  The default value
+      is ``False``.  Note: this will not work if the `tabsize` option for the
+      lexer is nonzero, as tabs will already have been expanded then.
+    `tabsize` : int
+      If tabs are to be replaced by this filter (see the `tabs` option), this
+      is the total number of characters that a tab should be expanded to.
+      The default is ``8``.
+    `newlines` : string or bool
+      The same as for `spaces`, but the default replacement character is ``¶``
+      (unicode PILCROW SIGN).  The default value is ``False``.
+    `wstokentype` : bool
+      If true, give whitespace the special `Whitespace` token type.  This allows
+      styling the visible whitespace differently (e.g. greyed out), but it can
+      disrupt background colors.  The default is ``True``.
+
+    *New in Pygments 0.8.*
+    """
+
+    def __init__(self, **options):
+        Filter.__init__(self, **options)
+        for name, default in {'spaces': u'·', 'tabs': u'»', 'newlines': u'¶'}.items():
+            opt = options.get(name, False)
+            if isinstance(opt, basestring) and len(opt) == 1:
+                setattr(self, name, opt)
+            else:
+                setattr(self, name, (opt and default or ''))
+        tabsize = get_int_opt(options, 'tabsize', 8)
+        if self.tabs:
+            self.tabs += ' '*(tabsize-1)
+        if self.newlines:
+            self.newlines += '\n'
+        self.wstt = get_bool_opt(options, 'wstokentype', True)
+
+    def filter(self, lexer, stream):
+        if self.wstt:
+            spaces = self.spaces or ' '
+            tabs = self.tabs or '\t'
+            newlines = self.newlines or '\n'
+            regex = re.compile(r'\s')
+            def replacefunc(wschar):
+                if wschar == ' ':
+                    return spaces
+                elif wschar == '\t':
+                    return tabs
+                elif wschar == '\n':
+                    return newlines
+                return wschar
+
+            for ttype, value in stream:
+                for sttype, svalue in _replace_special(ttype, value, regex,
+                                                       Whitespace, replacefunc):
+                    yield sttype, svalue
+        else:
+            spaces, tabs, newlines = self.spaces, self.tabs, self.newlines
+            # simpler processing
+            for ttype, value in stream:
+                if spaces:
+                    value = value.replace(' ', spaces)
+                if tabs:
+                    value = value.replace('\t', tabs)
+                if newlines:
+                    value = value.replace('\n', newlines)
+                yield ttype, value
+
+
+class GobbleFilter(Filter):
+    """
+    Gobbles source code lines (eats initial characters).
+
+    This filter drops the first ``n`` characters off every line of code.  This
+    may be useful when the source code fed to the lexer is indented by a fixed
+    amount of space that isn't desired in the output.
+
+    Options accepted:
+
+    `n` : int
+       The number of characters to gobble.
+
+    *New in Pygments 1.2.*
+    """
+    def __init__(self, **options):
+        Filter.__init__(self, **options)
+        self.n = get_int_opt(options, 'n', 0)
+
+    def gobble(self, value, left):
+        if left < len(value):
+            return value[left:], 0
+        else:
+            return '', left - len(value)
+
+    def filter(self, lexer, stream):
+        n = self.n
+        left = n # How many characters left to gobble.
+        for ttype, value in stream:
+            # Remove ``left`` tokens from first line, ``n`` from all others.
+            parts = value.split('\n')
+            (parts[0], left) = self.gobble(parts[0], left)
+            for i in range(1, len(parts)):
+                (parts[i], left) = self.gobble(parts[i], n)
+            value = '\n'.join(parts)
+
+            if value != '':
+                yield ttype, value
+
+
+class TokenMergeFilter(Filter):
+    """
+    Merges consecutive tokens with the same token type in the output stream of a
+    lexer.
+
+    *New in Pygments 1.2.*
+    """
+    def __init__(self, **options):
+        Filter.__init__(self, **options)
+
+    def filter(self, lexer, stream):
+        output = []
+        current_type = None
+        current_value = None
+        for ttype, value in stream:
+            if ttype is current_type:
+                current_value += value
+            else:
+                if current_type is not None:
+                    yield current_type, current_value
+                current_type = ttype
+                current_value = value
+        if current_type is not None:
+            yield current_type, current_value
+
+
+FILTERS = {
+    'codetagify':     CodeTagFilter,
+    'keywordcase':    KeywordCaseFilter,
+    'highlight':      NameHighlightFilter,
+    'raiseonerror':   RaiseOnErrorTokenFilter,
+    'whitespace':     VisibleWhitespaceFilter,
+    'gobble':         GobbleFilter,
+    'tokenmerge':     TokenMergeFilter,
+}

modules/plugin_markitup/pygments/formatter.py

+# -*- coding: utf-8 -*-
+"""
+    pygments.formatter
+    ~~~~~~~~~~~~~~~~~~
+
+    Base formatter class.
+
+    :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+import codecs
+
+from pygments.util import get_bool_opt
+from pygments.styles import get_style_by_name
+
+__all__ = ['Formatter']
+
+
+def _lookup_style(style):
+    if isinstance(style, basestring):
+        return get_style_by_name(style)
+    return style
+
+
+class Formatter(object):
+    """
+    Converts a token stream to text.
+
+    Options accepted:
+
+    ``style``
+        The style to use, can be a string or a Style subclass
+        (default: "default"). Not used by e.g. the
+        TerminalFormatter.
+    ``full``
+        Tells the formatter to output a "full" document, i.e.
+        a complete self-contained document. This doesn't have
+        any effect for some formatters (default: false).
+    ``title``
+        If ``full`` is true, the title that should be used to
+        caption the document (default: '').
+    ``encoding``
+        If given, must be an encoding name. This will be used to
+        convert the Unicode token strings to byte strings in the
+        output. If it is "" or None, Unicode strings will be written
+        to the output file, which most file-like objects do not
+        support (default: None).
+    ``outencoding``
+        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
+
+    def __init__(self, **options):
+        self.style = _lookup_style(options.get('style', 'default'))
+        self.full  = get_bool_opt(options, 'full', False)
+        self.title = options.get('title', '')
+        self.encoding = options.get('encoding', None) or None
+        self.encoding = options.get('outencoding', None) or self.encoding
+        self.options = options
+
+    def get_style_defs(self, arg=''):
+        """
+        Return the style definitions for the current style as a string.
+
+        ``arg`` is an additional argument whose meaning depends on the
+        formatter used. Note that ``arg`` can also be a list or tuple
+        for some formatters like the html formatter.
+        """
+        return ''
+
+    def format(self, tokensource, outfile):
+        """