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 -- Minimal complete definition: show or showsPrec 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 -- Minimal complete definition: (==) or (/=) 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 highlight_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 highlight_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("\n".join(content))
html = '<div class="codeblock %s">\n%s\n</div>\n' % (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.
Comments §
No comments.