mdx_liquid_tags.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. """
  2. Markdown Extension for Liquid-style Tags
  3. ----------------------------------------
  4. A markdown extension to allow user-defined tags of the form::
  5. {% tag arg1 arg2 ... argn %}
  6. Where "tag" is associated with some user-defined extension.
  7. These result in a preprocess step within markdown that produces
  8. either markdown or html.
  9. """
  10. import warnings
  11. import markdown
  12. import itertools
  13. import re
  14. import os
  15. from functools import wraps
  16. # Define some regular expressions
  17. LIQUID_TAG = re.compile(r'\{%.*?%\}')
  18. EXTRACT_TAG = re.compile(r'(?:\s*)(\S+)(?:\s*)')
  19. LT_CONFIG = { 'CODE_DIR': 'code',
  20. 'NOTEBOOK_DIR': 'notebooks'
  21. }
  22. LT_HELP = { 'CODE_DIR' : 'Code directory for include_code subplugin',
  23. 'NOTEBOOK_DIR' : 'Notebook directory for notebook subplugin'
  24. }
  25. class _LiquidTagsPreprocessor(markdown.preprocessors.Preprocessor):
  26. _tags = {}
  27. def __init__(self, configs):
  28. self.configs = configs
  29. def run(self, lines):
  30. page = '\n'.join(lines)
  31. liquid_tags = LIQUID_TAG.findall(page)
  32. for i, markup in enumerate(liquid_tags):
  33. # remove {% %}
  34. markup = markup[2:-2]
  35. tag = EXTRACT_TAG.match(markup).groups()[0]
  36. markup = EXTRACT_TAG.sub('', markup, 1)
  37. if tag in self._tags:
  38. liquid_tags[i] = self._tags[tag](self, tag, markup.strip())
  39. # add an empty string to liquid_tags so that chaining works
  40. liquid_tags.append('')
  41. # reconstruct string
  42. page = ''.join(itertools.chain(*zip(LIQUID_TAG.split(page),
  43. liquid_tags)))
  44. # resplit the lines
  45. return page.split("\n")
  46. class LiquidTags(markdown.Extension):
  47. """Wrapper for MDPreprocessor"""
  48. def __init__(self, config):
  49. try:
  50. # Needed for markdown versions >= 2.5
  51. for key,value in LT_CONFIG.items():
  52. self.config[key] = [value,LT_HELP[key]]
  53. super(LiquidTags,self).__init__(**config)
  54. except AttributeError:
  55. # Markdown versions < 2.5
  56. for key,value in LT_CONFIG.items():
  57. config[key] = [config[key],LT_HELP[key]]
  58. super(LiquidTags,self).__init__(config)
  59. @classmethod
  60. def register(cls, tag):
  61. """Decorator to register a new include tag"""
  62. def dec(func):
  63. if tag in _LiquidTagsPreprocessor._tags:
  64. warnings.warn("Enhanced Markdown: overriding tag '%s'" % tag)
  65. _LiquidTagsPreprocessor._tags[tag] = func
  66. return func
  67. return dec
  68. def extendMarkdown(self, md, md_globals):
  69. self.htmlStash = md.htmlStash
  70. md.registerExtension(self)
  71. # for the include_code preprocessor, we need to re-run the
  72. # fenced code block preprocessor after substituting the code.
  73. # Because the fenced code processor is run before, {% %} tags
  74. # within equations will not be parsed as an include.
  75. md.preprocessors.add('mdincludes',
  76. _LiquidTagsPreprocessor(self), ">html_block")
  77. def makeExtension(configs=None):
  78. """Wrapper for a MarkDown extension"""
  79. return LiquidTags(configs=configs)