include_code.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. """
  2. Include Code Tag
  3. ----------------
  4. This implements a Liquid-style video tag for Pelican,
  5. based on the octopress video tag [1]_
  6. Syntax
  7. ------
  8. {% include_code path/to/code [lang:python] [Title text] %}
  9. The "path to code" is specified relative to the ``code`` subdirectory of
  10. the content directory Optionally, this subdirectory can be specified in the
  11. config file:
  12. CODE_DIR = 'code'
  13. Example
  14. -------
  15. {% include_code myscript.py %}
  16. This will import myscript.py from content/code/myscript.py
  17. and output the contents in a syntax highlighted code block inside a figure,
  18. with a figcaption listing the file name and download link.
  19. The file link will be valid only if the 'code' directory is listed
  20. in the STATIC_PATHS setting, e.g.:
  21. STATIC_PATHS = ['images', 'code']
  22. [1] https://github.com/imathis/octopress/blob/master/plugins/include_code.rb
  23. """
  24. import re
  25. import os
  26. from .mdx_liquid_tags import LiquidTags
  27. SYNTAX = "{% include_code /path/to/code.py [lang:python] [lines:X-Y] [:hidefilename:] [title] %}"
  28. FORMAT = re.compile(r"""
  29. ^(?:\s+)? # Allow whitespace at beginning
  30. (?P<src>\S+) # Find the path
  31. (?:\s+)? # Whitespace
  32. (?:(?:lang:)(?P<lang>\S+))? # Optional language
  33. (?:\s+)? # Whitespace
  34. (?:(?:lines:)(?P<lines>\d+-\d+))? # Optional lines
  35. (?:\s+)? # Whitespace
  36. (?P<hidefilename>:hidefilename:)? # Hidefilename flag
  37. (?:\s+)? # Whitespace
  38. (?P<title>.+)?$ # Optional title
  39. """, re.VERBOSE)
  40. @LiquidTags.register('include_code')
  41. def include_code(preprocessor, tag, markup):
  42. title = None
  43. lang = None
  44. src = None
  45. match = FORMAT.search(markup)
  46. if match:
  47. argdict = match.groupdict()
  48. title = argdict['title'] or ""
  49. lang = argdict['lang']
  50. lines = argdict['lines']
  51. hide_filename = bool(argdict['hidefilename'])
  52. if lines:
  53. first_line, last_line = map(int, lines.split("-"))
  54. src = argdict['src']
  55. if not src:
  56. raise ValueError("Error processing input, "
  57. "expected syntax: {0}".format(SYNTAX))
  58. code_dir = preprocessor.configs.getConfig('CODE_DIR')
  59. code_path = os.path.join('content', code_dir, src)
  60. if not os.path.exists(code_path):
  61. raise ValueError("File {0} could not be found".format(code_path))
  62. with open(code_path) as fh:
  63. if lines:
  64. code = fh.readlines()[first_line - 1: last_line]
  65. code[-1] = code[-1].rstrip()
  66. code = "".join(code)
  67. else:
  68. code = fh.read()
  69. if not title and hide_filename:
  70. raise ValueError("Either title must be specified or filename must "
  71. "be available")
  72. if not hide_filename:
  73. title += " %s" % os.path.basename(src)
  74. if lines:
  75. title += " [Lines %s]" % lines
  76. title = title.strip()
  77. url = '/{0}/{1}'.format(code_dir, src)
  78. url = re.sub('/+', '/', url)
  79. open_tag = ("<figure class='code'>\n<figcaption><span>{title}</span> "
  80. "<a href='{url}'>download</a></figcaption>".format(title=title,
  81. url=url))
  82. close_tag = "</figure>"
  83. # store HTML tags in the stash. This prevents them from being
  84. # modified by markdown.
  85. open_tag = preprocessor.configs.htmlStash.store(open_tag, safe=True)
  86. close_tag = preprocessor.configs.htmlStash.store(close_tag, safe=True)
  87. if lang:
  88. lang_include = ':::' + lang + '\n '
  89. else:
  90. lang_include = ''
  91. source = (open_tag
  92. + '\n\n '
  93. + lang_include
  94. + '\n '.join(code.split('\n')) + '\n\n'
  95. + close_tag + '\n')
  96. return source
  97. #----------------------------------------------------------------------
  98. # This import allows image tag to be a Pelican plugin
  99. from liquid_tags import register