Saturday, August 15, 2009

Syntax highlighting for Pyblosxom, S5, etc.

Oct. 2010 - note this also works for apps. like rst2s5 - just make your own version of rst2s5 which includes the required module as shown below. rst2s5 is a wrapper script of just a few lines, so it's easy to do.

After running around in circles a bit I've found it's quite easy to
get syntax highlighting in Pyblosxom if you're using the rst plugin.

  1. Install the rst plugin.

  2. Make sure pygments is installed on your system. It's available as
    a package for Ubuntu, so you can just do:

    sudo apt-get install python-pygments
    
  3. Get rst-directive.py from the pygments distribution (or from the
    end of this article). It's
    in the 'external' folder. It may not be included in the package
    for your system, but you can get the file by itself by browsing
    the pygments site.

  4. Rename it rst_directive.py because that seems more sensible,
    and put it in you plugins folder. You would think you would need
    to import it from the rst plugin, but you don't, because
    Pyblosxom will have imported it just because it's in the plugins
    folder.

  5. Edit rst_directive.py and change:

    INLINESTYLES = False
    

    to

    INLINESTYLES = True
    

    Doing so causes pygments to use <span style="color: #BA2121">

    instead of <span class="comment"> etc., but it saves a lot of
    trouble trying to ensure the CSS file is available.

That's it. Now in your rst you can use the sourcecode directive:


That's it.  *Now* in your rst you can use the `sourcecode` directive:

.. sourcecode: python

  import foo  # get access to foo
  foo.bar("test") or raise SystemExit

to syntax highlight rst (above), python (below), and all the other languages and markups pygments knows.

import foo  # get access to foo

foo.bar("test") or raise SystemExit

Graham Higgins's post may have set me off on the right track here, at least by making me aware of pygments.

Syntax highlighting on external files


To make pygment's sourcecode directive even more useful I added a
quick tweak to allow inclusion of a file like this:

.. sourcecode:: python
  :filename: ../tlog/plugins/rst_directive.py

In this form the inline content is ignored and the content of

filename is formatted instead.

Here's the complete, modified, rst_directive.py (original from external
folder on pygments Trac site). Put it in your
plugins directory. Modifications are:

  • INLINESTYLES = True
  • the if 'filename'... block
  • setting ...options['filename'] = directives.path
# -*- coding: utf-8 -*-
"""
    The Pygments reStructuredText directive
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    This fragment is a Docutils_ 0.4 directive that renders source code
    (to HTML only, currently) via Pygments.

    To use it, adjust the options below and copy the code into a module
    that you import on initialization.  The code then automatically
    registers a ``sourcecode`` directive that you can use instead of
    normal code blocks like this::

        .. sourcecode:: python

            My code goes here.

    If you want to have different code styles, e.g. one with line numbers
    and one without, add formatters with their names in the VARIANTS dict
    below.  You can invoke them instead of the DEFAULT one by using a

    directive option::

        .. sourcecode:: python
            :linenos:

            My code goes here.

    Look at the `directive documentation`_ to get all the gory details.

    .. _Docutils: http://docutils.sf.net/
    .. _directive documentation:
       http://docutils.sourceforge.net/docs/howto/rst-directives.html

    :copyright: Copyright 2006-2009 by the Pygments team, see AUTHORS.
    :license: BSD, see LICENSE for details.

"""

# Options
# ~~~~~~~

# Set to True if you want inline CSS styles instead of classes
INLINESTYLES = True

from pygments.formatters import HtmlFormatter


# The default formatter
DEFAULT = HtmlFormatter(noclasses=INLINESTYLES)

# Add name -> formatter pairs for every variant you want to use
VARIANTS = {
    'linenos': HtmlFormatter(noclasses=INLINESTYLES, linenos=True),
}



from docutils import nodes
from docutils.parsers.rst import directives

from pygments import highlight

from pygments.lexers import get_lexer_by_name, TextLexer

def pygments_directive(name, arguments, options, content, lineno,
                       content_offset, block_text, state, state_machine):

    if 'filename' in options:
        if options['filename']:
            content = [line.rstrip('\n') for line in file(options['filename'])] 
        del options['filename'] 

    try:
        lexer = get_lexer_by_name(arguments[0])
    except ValueError:
        # no lexer found - use the text one instead of an exception

        lexer = TextLexer()

    # take an arbitrary option if more than one is given
    formatter = options and VARIANTS[options.keys()[0]] or DEFAULT
    parsed = highlight(u'\n'.join(content), lexer, formatter)
    return [nodes.raw('', parsed, format='html')]

pygments_directive.arguments = (1, 0, 1)
pygments_directive.content = 1

pygments_directive.options = dict([(key, directives.flag) for key in VARIANTS])

pygments_directive.options['filename'] = directives.path

directives.register_directive('sourcecode', pygments_directive)

No comments:

Post a Comment