Adding new plugin Code Include

This plugin allows you to include other files as a code block with
syntax highlighting in ReST articles. You'll need docutils>0.10, as
there was a circular import bug in the 0.10 release.
This commit is contained in:
Colin Dunklau
2013-03-23 16:05:56 -05:00
parent 3a3a92183d
commit e4f8a604cb
3 changed files with 237 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
Include Pygments highlighted code with reStructuredText
=======================================================
:author: Colin Dunklau
Use this plugin to make writing coding tutorials easier! You can
maintain the example source files separately from the actual article.
Based heavily on ``docutils.parsers.rst.directives.Include``. Include
a file and output as a code block formatted with pelican's Pygments
directive.
Note that this is broken with the Docutils 0.10 release, there's a
circular import. It was fixed in trunk:
http://sourceforge.net/p/docutils/bugs/214/
Directives
----------
.. code:: rst
.. code-include:: incfile.py
:lexer: string, name of the Pygments lexer to use, default 'text'
:encoding: string, encoding with which to open the file
:tab-width: integer, hard tabs are replaced with `tab-width` spaces
:start-line: integer, starting line to begin reading include file
:end-line: integer, last line from include file to display
``start-line``, and ``end-line`` have the same meaning as in the
docutils ``include`` directive, that is, they index from zero.
Example
-------
./incfile.py:
.. code:: python
# These two comment lines will not
# be included in the output
import random
insults = ['I fart in your general direction',
'your mother was a hampster',
'your father smelt of elderberries']
def insult():
print random.choice(insults)
# This comment line will be included
# ...but this one won't
./yourfile.rst:
.. code:: rst
How to Insult the English
=========================
:author: Pierre Devereaux
A function to help insult those silly English knnnnnnniggets:
.. code-include:: incfile.py
:lexer: python
:encoding: utf-8
:tab-width: 4
:start-line: 3
:end-line: 11

View File

View File

@@ -0,0 +1,167 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os.path
from docutils import io, nodes, statemachine, utils
from docutils.utils.error_reporting import SafeString, ErrorString
from docutils.parsers.rst import directives, Directive
from pelican.rstdirectives import Pygments
"""
Include Pygments highlighted code with reStructuredText
=======================================================
:author: Colin Dunklau
Use this plugin to make writing coding tutorials easier! You can
maintain the example source files separately from the actual article.
Based heavily on ``docutils.parsers.rst.directives.Include``. Include
a file and output as a code block formatted with pelican's Pygments
directive.
Note that this is broken with the Docutils 0.10 release, there's a
circular import. It was fixed in trunk:
http://sourceforge.net/p/docutils/bugs/214/
Directives
----------
.. code:: rst
.. code-include:: incfile.py
:lexer: string, name of the Pygments lexer to use, default 'text'
:encoding: string, encoding with which to open the file
:tab-width: integer, hard tabs are replaced with `tab-width` spaces
:start-line: integer, starting line to begin reading include file
:end-line: integer, last line from include file to display
``start-line``, and ``end-line`` have the same meaning as in the
docutils ``include`` directive, that is, they index from zero.
Example
-------
./incfile.py:
.. code:: python
# These two comment lines will not
# be included in the output
import random
insults = ['I fart in your general direction',
'your mother was a hampster',
'your father smelt of elderberries']
def insult():
print random.choice(insults)
# This comment line will be included
# ...but this one won't
./yourfile.rst:
.. code:: rst
How to Insult the English
=========================
:author: Pierre Devereaux
A function to help insult those silly English knnnnnnniggets:
.. code-include:: incfile.py
:lexer: python
:encoding: utf-8
:tab-width: 4
:start-line: 3
:end-line: 11
"""
class CodeInclude(Directive):
"""
Include content read from a separate source file, and highlight
it with the given lexer (using pelican.rstdirectives.CodeBlock)
The encoding of the included file can be specified. Only a part
of the given file argument may be included by specifying start
and end line. Hard tabs will be replaced with ``tab-width``
spaces.
"""
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
option_spec = {'lexer': directives.unchanged,
'encoding': directives.encoding,
'tab-width': int,
'start-line': int,
'end-line': int}
def run(self):
"""Include a file as part of the content of this reST file."""
if not self.state.document.settings.file_insertion_enabled:
raise self.warning('"%s" directive disabled.' % self.name)
source = self.state_machine.input_lines.source(
self.lineno - self.state_machine.input_offset - 1)
source_dir = os.path.dirname(os.path.abspath(source))
path = directives.path(self.arguments[0])
path = os.path.normpath(os.path.join(source_dir, path))
path = utils.relative_path(None, path)
path = nodes.reprunicode(path)
encoding = self.options.get(
'encoding', self.state.document.settings.input_encoding)
e_handler=self.state.document.settings.input_encoding_error_handler
tab_width = self.options.get(
'tab-width', self.state.document.settings.tab_width)
try:
self.state.document.settings.record_dependencies.add(path)
include_file = io.FileInput(source_path=path,
encoding=encoding,
error_handler=e_handler)
except UnicodeEncodeError, error:
raise self.severe(u'Problems with "%s" directive path:\n'
'Cannot encode input file path "%s" '
'(wrong locale?).' %
(self.name, SafeString(path)))
except IOError, error:
raise self.severe(u'Problems with "%s" directive path:\n%s.' %
(self.name, ErrorString(error)))
startline = self.options.get('start-line', None)
endline = self.options.get('end-line', None)
try:
if startline or (endline is not None):
lines = include_file.readlines()
rawtext = ''.join(lines[startline:endline])
else:
rawtext = include_file.read()
except UnicodeError, error:
raise self.severe(u'Problem with "%s" directive:\n%s' %
(self.name, ErrorString(error)))
include_lines = statemachine.string2lines(rawtext, tab_width,
convert_whitespace=True)
# default lexer to 'text'
lexer = self.options.get('lexer', 'text')
self.options['source'] = path
codeblock = Pygments(self.name,
[lexer], # arguments
{}, # no options for this directive
include_lines, # content
self.lineno,
self.content_offset,
self.block_text,
self.state,
self.state_machine)
return codeblock.run()
def register():
directives.register_directive('code-include', CodeInclude)