Code, mostly.

Archives:

[ Home | RSS 2.0 | ATOM 1.0 | Comment ]

Sat, 15 Aug 2009

Syntax highlighting for Pyblosxom

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)

posted at: 09:02 | path: /code/python/pyblosxom | permanent link to this entry

Made with PyBlosxom