code_include.py 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import os.path
  4. from docutils import io, nodes, statemachine, utils
  5. from docutils.utils.error_reporting import SafeString, ErrorString
  6. from docutils.parsers.rst import directives, Directive
  7. from pelican.rstdirectives import Pygments
  8. class CodeInclude(Directive):
  9. required_arguments = 1
  10. optional_arguments = 0
  11. final_argument_whitespace = True
  12. option_spec = {'lexer': directives.unchanged,
  13. 'encoding': directives.encoding,
  14. 'tab-width': int,
  15. 'start-line': int,
  16. 'end-line': int}
  17. def run(self):
  18. """Include a file as part of the content of this reST file."""
  19. if not self.state.document.settings.file_insertion_enabled:
  20. raise self.warning('"%s" directive disabled.' % self.name)
  21. source = self.state_machine.input_lines.source(
  22. self.lineno - self.state_machine.input_offset - 1)
  23. source_dir = os.path.dirname(os.path.abspath(source))
  24. path = directives.path(self.arguments[0])
  25. path = os.path.normpath(os.path.join(source_dir, path))
  26. path = utils.relative_path(None, path)
  27. path = nodes.reprunicode(path)
  28. encoding = self.options.get(
  29. 'encoding', self.state.document.settings.input_encoding)
  30. e_handler = self.state.document.settings.input_encoding_error_handler
  31. tab_width = self.options.get(
  32. 'tab-width', self.state.document.settings.tab_width)
  33. try:
  34. self.state.document.settings.record_dependencies.add(path)
  35. include_file = io.FileInput(source_path=path,
  36. encoding=encoding,
  37. error_handler=e_handler)
  38. except UnicodeEncodeError as error:
  39. raise self.severe('Problems with "%s" directive path:\n'
  40. 'Cannot encode input file path "%s" '
  41. '(wrong locale?).' %
  42. (self.name, SafeString(path)))
  43. except IOError as error:
  44. raise self.severe('Problems with "%s" directive path:\n%s.' %
  45. (self.name, ErrorString(error)))
  46. startline = self.options.get('start-line', None)
  47. endline = self.options.get('end-line', None)
  48. try:
  49. if startline or (endline is not None):
  50. lines = include_file.readlines()
  51. rawtext = ''.join(lines[startline:endline])
  52. else:
  53. rawtext = include_file.read()
  54. except UnicodeError as error:
  55. raise self.severe('Problem with "%s" directive:\n%s' %
  56. (self.name, ErrorString(error)))
  57. include_lines = statemachine.string2lines(rawtext, tab_width,
  58. convert_whitespace=True)
  59. # default lexer to 'text'
  60. lexer = self.options.get('lexer', 'text')
  61. self.options['source'] = path
  62. codeblock = Pygments(self.name,
  63. [lexer], # arguments
  64. {}, # no options for this directive
  65. include_lines, # content
  66. self.lineno,
  67. self.content_offset,
  68. self.block_text,
  69. self.state,
  70. self.state_machine)
  71. return codeblock.run()
  72. def register():
  73. directives.register_directive('code-include', CodeInclude)