md_in_html.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. """
  2. Python-Markdown Markdown in HTML Extension
  3. ===============================
  4. An implementation of [PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/)'s
  5. parsing of Markdown syntax in raw HTML.
  6. See <https://Python-Markdown.github.io/extensions/raw_html>
  7. for documentation.
  8. Copyright The Python Markdown Project
  9. License: [BSD](https://opensource.org/licenses/bsd-license.php)
  10. """
  11. from . import Extension
  12. from ..blockprocessors import BlockProcessor
  13. from .. import util
  14. import re
  15. import xml.etree.ElementTree as etree
  16. class MarkdownInHtmlProcessor(BlockProcessor):
  17. """Process Markdown Inside HTML Blocks."""
  18. def test(self, parent, block):
  19. return block == util.TAG_PLACEHOLDER % \
  20. str(self.parser.blockprocessors.tag_counter + 1)
  21. def _process_nests(self, element, block):
  22. """Process the element's child elements in self.run."""
  23. # Build list of indexes of each nest within the parent element.
  24. nest_index = [] # a list of tuples: (left index, right index)
  25. i = self.parser.blockprocessors.tag_counter + 1
  26. while len(self._tag_data) > i and self._tag_data[i]['left_index']:
  27. left_child_index = self._tag_data[i]['left_index']
  28. right_child_index = self._tag_data[i]['right_index']
  29. nest_index.append((left_child_index - 1, right_child_index))
  30. i += 1
  31. # Create each nest subelement.
  32. for i, (left_index, right_index) in enumerate(nest_index[:-1]):
  33. self.run(element, block[left_index:right_index],
  34. block[right_index:nest_index[i + 1][0]], True)
  35. self.run(element, block[nest_index[-1][0]:nest_index[-1][1]], # last
  36. block[nest_index[-1][1]:], True) # nest
  37. def run(self, parent, blocks, tail=None, nest=False):
  38. self._tag_data = self.parser.md.htmlStash.tag_data
  39. self.parser.blockprocessors.tag_counter += 1
  40. tag = self._tag_data[self.parser.blockprocessors.tag_counter]
  41. # Create Element
  42. markdown_value = tag['attrs'].pop('markdown')
  43. element = etree.SubElement(parent, tag['tag'], tag['attrs'])
  44. # Slice Off Block
  45. if nest:
  46. self.parser.parseBlocks(parent, tail) # Process Tail
  47. block = blocks[1:]
  48. else: # includes nests since a third level of nesting isn't supported
  49. block = blocks[tag['left_index'] + 1: tag['right_index']]
  50. del blocks[:tag['right_index']]
  51. # Process Text
  52. if (self.parser.blockprocessors.contain_span_tags.match( # Span Mode
  53. tag['tag']) and markdown_value != 'block') or \
  54. markdown_value == 'span':
  55. element.text = '\n'.join(block)
  56. else: # Block Mode
  57. i = self.parser.blockprocessors.tag_counter + 1
  58. if len(self._tag_data) > i and self._tag_data[i]['left_index']:
  59. first_subelement_index = self._tag_data[i]['left_index'] - 1
  60. self.parser.parseBlocks(
  61. element, block[:first_subelement_index])
  62. if not nest:
  63. block = self._process_nests(element, block)
  64. else:
  65. self.parser.parseBlocks(element, block)
  66. class MarkdownInHtmlExtension(Extension):
  67. """Add Markdown parsing in HTML to Markdown class."""
  68. def extendMarkdown(self, md):
  69. """ Register extension instances. """
  70. # Turn on processing of markdown text within raw html
  71. md.preprocessors['html_block'].markdown_in_raw = True
  72. md.parser.blockprocessors.register(
  73. MarkdownInHtmlProcessor(md.parser), 'markdown_block', 105
  74. )
  75. md.parser.blockprocessors.tag_counter = -1
  76. md.parser.blockprocessors.contain_span_tags = re.compile(
  77. r'^(p|h[1-6]|li|dd|dt|td|th|legend|address)$', re.IGNORECASE)
  78. def makeExtension(**kwargs): # pragma: no cover
  79. return MarkdownInHtmlExtension(**kwargs)