I like to write blog postings in reStructuredText, and I use rst2html from Python’s docutils to turn them into HTML before pasting into my blog software.

One thing missing is source highlighting for Haskell, Python etc. Thankfully, Both reST and Python’s docutils are written to be extensible. Below is a replacement ‘rst2html’ which includes support for Haskell colouring using HsColour, and just about everything else using Pygments.

Example usage:

.. code-block :: python import os # Standard hello world stuff class Hello () def do_it ( self ) print "Hello world" if __name__ == '__main__' : Hello () . do_it () def main () print "Hello world"

Output:

import os # Standard hello world stuff class Hello () def do_it ( self ) print "Hello world" if __name__ == '__main__' : Hello () . do_it ()

Some sample Haskell:

class Show a where show :: a -> String showsPrec :: Int -> a -> ShowS showList :: [ a ] -> ShowS show x = showsPrec 0 x "" showsPrec _ x s = show x ++ s showList [] = showString "[]" showList ( x : xs ) = showChar '[' . shows x . showl xs where showl [] = showChar ']' showl ( x : xs ) = showChar ',' . shows x . showl xs class Eq a where ( == ) , ( /= ) :: a -> a -> Bool x == y = not ( x /= y ) x /= y = not ( x == y )

Here is the code:

#!/usr/bin/python """ rst2html A minimal front end to the Docutils Publisher, producing HTML, with an extension for colouring code-blocks """ try : import locale locale . setlocale ( locale . LC_ALL , '' ) except : pass from docutils import nodes , parsers from docutils.parsers.rst import states , directives from docutils.core import publish_cmdline , default_description import tempfile , os def getCommandOutput2 ( command ): child_stdin , child_stdout = os . popen2 ( command ) child_stdin . close () data = child_stdout . read () err = child_stdout . close () if err : raise RuntimeError , ' %s failed w/ exit code %d ' % ( command , err ) return data def hightlight_haskell ( text ): fh , path = tempfile . mkstemp () os . write ( fh , text ) output = getCommandOutput2 ([ "HsColour" , "-css" , "-partial" , path ]) os . close ( fh ) return output def get_highlighter ( language ): if language == 'haskell' : return hightlight_haskell from pygments import lexers , util , highlight , formatters import StringIO try : lexer = lexers . get_lexer_by_name ( language ) except util . ClassNotFound : return None formatter = formatters . get_formatter_by_name ( 'html' ) def _highlighter ( code ): outfile = StringIO . StringIO () highlight ( code , lexer , formatter , outfile ) return outfile . getvalue () return _highlighter # Docutils directives: def code_block ( name , arguments , options , content , lineno , content_offset , block_text , state , state_machine ): """ The code-block directive provides syntax highlighting for blocks of code. It is used with the the following syntax:: .. code-block:: python import sys def main(): sys.stdout.write("Hello world") Currently support languages: python (requires pygments), haskell (requires HsColour), anything else supported by pygments """ language = arguments [ 0 ] highlighter = get_highlighter ( language ) if highlighter is None : error = state_machine . reporter . error ( 'The " %s " directive does not support language " %s ".' % ( name , language ), nodes . literal_block ( block_text , block_text ), line = lineno ) if not content : error = state_machine . reporter . error ( 'The " %s " block is empty; content required.' % ( name ), nodes . literal_block ( block_text , block_text ), line = lineno ) return [ error ] include_text = highlighter ( "

" . join ( content )) html = '<div class="codeblock %s ">

%s

</div>

' % ( language , include_text ) raw = nodes . raw ( '' , html , format = 'html' ) return [ raw ] code_block . arguments = ( 1 , 0 , 0 ) code_block . options = { 'language' : parsers . rst . directives . unchanged } code_block . content = 1 # Register directives . register_directive ( 'code-block' , code_block ) description = ( 'Generates (X)HTML documents from standalone reStructuredText ' 'sources. ' + default_description ) # Command line publish_cmdline ( writer_name = 'html' , description = description )

I borrowed some things from this recipe, thanks. I also discovered Using Pygments in ReST documents after I wrote this.