Code samples in reStructuredText documents are normally shown as plain literal blocks. This recipe uses the SilverCity ( http://silvercity.sourceforge.net/ ) lexing package to generate syntax highlighted code blocks instead.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #!/usr/bin/env python
import SilverCity
import docutils.parsers.rst
import StringIO
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:: CPP
#include <iostream>
int main( int argc, char* argv[] )
{
std::cout << "Hello world" << std::endl;
}
The directive requires the name of a language supported by SilverCity
as its only argument. All code in the indented block following
the directive will be colourized. Note that this directive is only
supported for HTML writers.
"""
language = arguments[0]
try:
module = getattr(SilverCity, language)
generator = getattr(module, language+"HTMLGenerator")
except AttributeError:
error = state_machine.reporter.error( "No SilverCity lexer found "
"for language '%s'." % language,
docutils.nodes.literal_block(block_text, block_text), line=lineno )
return [error]
io = StringIO.StringIO()
generator().generate_html( io, '\n'.join(content) )
html = '<div class="code-block">\n%s\n</div>\n' % io.getvalue()
raw = docutils.nodes.raw('',html, format = 'html')
return [raw]
code_block.arguments = (1,0,0)
code_block.options = {'language' : docutils.parsers.rst.directives.unchanged }
code_block.content = 1
# Simply importing this module will make the directive available.
docutils.parsers.rst.directives.register_directive( 'code-block', code_block )
if __name__ == "__main__":
import docutils.core
docutils.core.publish_cmdline(writer_name='html')
|
This module adds a new directive, "code-block", to docutils. The directive can be used wherever you otherwise might use a literal block. For example: <pre>.. code-block:: Python
def hello( name ): print "Hello,",name </pre> instead of, <pre>::
def hello( name ): print "Hello,",name </pre> Displaying the HTML output requires a stylesheet that merges the 'default.css' from docutils, the 'default.css' from SilverCity and the following style:
div.code-block{ margin-left: 2em ; margin-right: 2em ; background-color: #eeeeee; font-family: "Courier New", Courier, monospace; font-size: 10pt; }
The syntax-highlighted text is inserted into the docutils tree as a raw-node with HTML format. So, it will only be displayed when generating HTML documents, and will be ignored by other writers (e.g., LaTex)
You can run this as a standalone script to generate HTML, or import it into other modules that invoke the docutils HTML writer. Simply importing the module registers the code-block directive and makes it available.
Small feature addition. I like this a lot, but I want it to stay up-to-date with the current source. I changed the recipie a bit so that you can specify a source-file instead of including source directly.
(comment continued...)
(...continued from previous comment)
This also lets you specify language directly as an option.
oops. small correction:
should be changed to
to be a little more graceful
SilverCity won't work with unicode strings.
Update of recipe for new style Docutils directive. When I tried to reuse this recipe in the latest SVN snapshot of Docutils (0.5 [repository]), I discovered that the rst directive code has changed from a functional interface to a class-based interface.
After a bit of fiddling I was able to get it to work. Here is the revised code.
(comment continued...)
(...continued from previous comment)
During my researches for this change I discovered that the original recipe has been adapted by the TRAC developers (http://trac.edgewall.org/) where it is used in both code pretty-printing and revision browsing and with an reST directive in their wiki. Their solution is more sophisticated than the one here because it makes use of GNU/Enscript to typeset languages other than those supported by SilverCity. It would be nice if this code could be backported into Docutils.
Another comment is that this recipe could usefully subclass the Raw directive which provides support for inserting code from URLs as well as files. This also provides support for specifying text encoding of the code (although from the above comment, this would appear to be unsupported by SilverCity). Unfortunately, this is beyond my current skills!