From e4f8a604cb87c43a60fa0ae1a567d68d9ab1cd33 Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Sat, 23 Mar 2013 16:05:56 -0500 Subject: [PATCH 1/6] 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. --- pelicanext/code_include/README.rst | 70 ++++++++++ pelicanext/code_include/__init__.py | 0 pelicanext/code_include/code_include.py | 167 ++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 pelicanext/code_include/README.rst create mode 100644 pelicanext/code_include/__init__.py create mode 100644 pelicanext/code_include/code_include.py diff --git a/pelicanext/code_include/README.rst b/pelicanext/code_include/README.rst new file mode 100644 index 0000000..0f3c0dc --- /dev/null +++ b/pelicanext/code_include/README.rst @@ -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 + diff --git a/pelicanext/code_include/__init__.py b/pelicanext/code_include/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pelicanext/code_include/code_include.py b/pelicanext/code_include/code_include.py new file mode 100644 index 0000000..b03a1c7 --- /dev/null +++ b/pelicanext/code_include/code_include.py @@ -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) + From ccef5de59dacb58e2fbd81d95f7c15c64448ca1d Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Sat, 23 Mar 2013 16:24:56 -0500 Subject: [PATCH 2/6] Some minor tweaks: documentation, py3 compliance Pulled most documentation out of code to avoid desync Fixed unicode literals Fixed except syntax for py3 compliance --- pelicanext/code_include/code_include.py | 74 ++----------------------- 1 file changed, 6 insertions(+), 68 deletions(-) diff --git a/pelicanext/code_include/code_include.py b/pelicanext/code_include/code_include.py index b03a1c7..9d108c7 100644 --- a/pelicanext/code_include/code_include.py +++ b/pelicanext/code_include/code_include.py @@ -17,68 +17,6 @@ Include Pygments highlighted code with reStructuredText 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): @@ -123,13 +61,13 @@ class CodeInclude(Directive): 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' + except UnicodeEncodeError as error: + raise self.severe('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.' % + except IOError as error: + raise self.severe('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) @@ -139,8 +77,8 @@ class CodeInclude(Directive): rawtext = ''.join(lines[startline:endline]) else: rawtext = include_file.read() - except UnicodeError, error: - raise self.severe(u'Problem with "%s" directive:\n%s' % + except UnicodeError as error: + raise self.severe('Problem with "%s" directive:\n%s' % (self.name, ErrorString(error))) include_lines = statemachine.string2lines(rawtext, tab_width, From 23d426aed7e098f00e768e94f10c1584bc37bd13 Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Sat, 23 Mar 2013 17:12:22 -0500 Subject: [PATCH 3/6] PEP 8 fixes --- pelicanext/code_include/code_include.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/pelicanext/code_include/code_include.py b/pelicanext/code_include/code_include.py index 9d108c7..3edd94a 100644 --- a/pelicanext/code_include/code_include.py +++ b/pelicanext/code_include/code_include.py @@ -1,12 +1,5 @@ # -*- 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 @@ -19,6 +12,15 @@ maintain the example source files separately from the actual article. """ +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 + + class CodeInclude(Directive): """ @@ -53,7 +55,7 @@ class CodeInclude(Directive): 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 + e_handler = self.state.document.settings.input_encoding_error_handler tab_width = self.options.get( 'tab-width', self.state.document.settings.tab_width) try: @@ -68,7 +70,7 @@ class CodeInclude(Directive): (self.name, SafeString(path))) except IOError as error: raise self.severe('Problems with "%s" directive path:\n%s.' % - (self.name, ErrorString(error))) + (self.name, ErrorString(error))) startline = self.options.get('start-line', None) endline = self.options.get('end-line', None) try: @@ -89,9 +91,9 @@ class CodeInclude(Directive): self.options['source'] = path codeblock = Pygments(self.name, - [lexer], # arguments + [lexer], # arguments {}, # no options for this directive - include_lines, # content + include_lines, # content self.lineno, self.content_offset, self.block_text, @@ -102,4 +104,3 @@ class CodeInclude(Directive): def register(): directives.register_directive('code-include', CodeInclude) - From 1dc73cda430484dbc6ce0b40c5ff827e2dc5b505 Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Sun, 24 Mar 2013 16:34:03 -0500 Subject: [PATCH 4/6] Whitespace fixes --- pelicanext/code_include/code_include.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pelicanext/code_include/code_include.py b/pelicanext/code_include/code_include.py index 3edd94a..728c411 100644 --- a/pelicanext/code_include/code_include.py +++ b/pelicanext/code_include/code_include.py @@ -22,7 +22,6 @@ from pelican.rstdirectives import Pygments class CodeInclude(Directive): - """ Include content read from a separate source file, and highlight it with the given lexer (using pelican.rstdirectives.CodeBlock) @@ -49,15 +48,18 @@ class CodeInclude(Directive): 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, From 4ba1c5fd6b038880303a62f2a14a952e589a9be9 Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Thu, 16 May 2013 20:59:44 -0500 Subject: [PATCH 5/6] Restructured to account for repo layout change --- {pelicanext/code_include => code_include}/README.rst | 1 - code_include/__init__.py | 1 + {pelicanext/code_include => code_include}/code_include.py | 0 pelicanext/code_include/__init__.py | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename {pelicanext/code_include => code_include}/README.rst (99%) create mode 100644 code_include/__init__.py rename {pelicanext/code_include => code_include}/code_include.py (100%) delete mode 100644 pelicanext/code_include/__init__.py diff --git a/pelicanext/code_include/README.rst b/code_include/README.rst similarity index 99% rename from pelicanext/code_include/README.rst rename to code_include/README.rst index 0f3c0dc..b7e08ec 100644 --- a/pelicanext/code_include/README.rst +++ b/code_include/README.rst @@ -6,7 +6,6 @@ Include Pygments highlighted code with reStructuredText 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. diff --git a/code_include/__init__.py b/code_include/__init__.py new file mode 100644 index 0000000..019171c --- /dev/null +++ b/code_include/__init__.py @@ -0,0 +1 @@ +from code_include import * diff --git a/pelicanext/code_include/code_include.py b/code_include/code_include.py similarity index 100% rename from pelicanext/code_include/code_include.py rename to code_include/code_include.py diff --git a/pelicanext/code_include/__init__.py b/pelicanext/code_include/__init__.py deleted file mode 100644 index e69de29..0000000 From 95600f17b7638c230e50792a641ae8e2610ed69c Mon Sep 17 00:00:00 2001 From: Colin Dunklau Date: Thu, 16 May 2013 22:41:13 -0500 Subject: [PATCH 6/6] Removed docstrings to avoid doc duplication. --- code_include/code_include.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/code_include/code_include.py b/code_include/code_include.py index 728c411..b87c8dd 100644 --- a/code_include/code_include.py +++ b/code_include/code_include.py @@ -1,17 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -""" -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. - -""" - import os.path from docutils import io, nodes, statemachine, utils @@ -22,16 +11,6 @@ from pelican.rstdirectives import Pygments 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