Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/markdown/extensions/def_list.py: 95%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

60 statements  

1# Definition List Extension for Python-Markdown 

2# ============================================= 

3 

4# Adds parsing of Definition Lists to Python-Markdown. 

5 

6# See https://Python-Markdown.github.io/extensions/definition_lists 

7# for documentation. 

8 

9# Original code Copyright 2008 [Waylan Limberg](http://achinghead.com) 

10 

11# All changes Copyright 2008-2014 The Python Markdown Project 

12 

13# License: [BSD](https://opensource.org/licenses/bsd-license.php) 

14 

15""" 

16Adds parsing of Definition Lists to Python-Markdown. 

17 

18See the [documentation](https://Python-Markdown.github.io/extensions/definition_lists) 

19for details. 

20""" 

21 

22from __future__ import annotations 

23 

24from . import Extension 

25from ..blockprocessors import BlockProcessor, ListIndentProcessor 

26import xml.etree.ElementTree as etree 

27import re 

28 

29 

30class DefListProcessor(BlockProcessor): 

31 """ Process Definition Lists. """ 

32 

33 RE = re.compile(r'(^|\n)[ ]{0,3}:[ ]{1,3}(.*?)(\n|$)') 

34 NO_INDENT_RE = re.compile(r'^[ ]{0,3}[^ :]') 

35 

36 def test(self, parent: etree.Element, block: str) -> bool: 

37 return bool(self.RE.search(block)) 

38 

39 def run(self, parent: etree.Element, blocks: list[str]) -> bool | None: 

40 

41 raw_block = blocks.pop(0) 

42 m = self.RE.search(raw_block) 

43 terms = [term.strip() for term in 

44 raw_block[:m.start()].split('\n') if term.strip()] 

45 block = raw_block[m.end():] 

46 no_indent = self.NO_INDENT_RE.match(block) 

47 if no_indent: 

48 d, theRest = (block, None) 

49 else: 

50 d, theRest = self.detab(block) 

51 if d: 

52 d = '{}\n{}'.format(m.group(2), d) 

53 else: 

54 d = m.group(2) 

55 sibling = self.lastChild(parent) 

56 if not terms and sibling is None: 

57 # This is not a definition item. Most likely a paragraph that 

58 # starts with a colon at the beginning of a document or list. 

59 blocks.insert(0, raw_block) 

60 return False 

61 if not terms and sibling.tag == 'p': 

62 # The previous paragraph contains the terms 

63 state = 'looselist' 

64 terms = sibling.text.split('\n') 

65 parent.remove(sibling) 

66 # Acquire new sibling 

67 sibling = self.lastChild(parent) 

68 else: 

69 state = 'list' 

70 

71 if sibling is not None and sibling.tag == 'dl': 

72 # This is another item on an existing list 

73 dl = sibling 

74 if not terms and len(dl) and dl[-1].tag == 'dd' and len(dl[-1]): 

75 state = 'looselist' 

76 else: 

77 # This is a new list 

78 dl = etree.SubElement(parent, 'dl') 

79 # Add terms 

80 for term in terms: 

81 dt = etree.SubElement(dl, 'dt') 

82 dt.text = term 

83 # Add definition 

84 self.parser.state.set(state) 

85 dd = etree.SubElement(dl, 'dd') 

86 self.parser.parseBlocks(dd, [d]) 

87 self.parser.state.reset() 

88 

89 if theRest: 

90 blocks.insert(0, theRest) 

91 

92 

93class DefListIndentProcessor(ListIndentProcessor): 

94 """ Process indented children of definition list items. """ 

95 

96 # Definition lists need to be aware of all list types 

97 ITEM_TYPES = ['dd', 'li'] 

98 """ Include `dd` in list item types. """ 

99 LIST_TYPES = ['dl', 'ol', 'ul'] 

100 """ Include `dl` is list types. """ 

101 

102 def create_item(self, parent: etree.Element, block: str) -> None: 

103 """ Create a new `dd` or `li` (depending on parent) and parse the block with it as the parent. """ 

104 

105 dd = etree.SubElement(parent, 'dd') 

106 self.parser.parseBlocks(dd, [block]) 

107 

108 

109class DefListExtension(Extension): 

110 """ Add definition lists to Markdown. """ 

111 

112 def extendMarkdown(self, md): 

113 """ Add an instance of `DefListProcessor` to `BlockParser`. """ 

114 md.parser.blockprocessors.register(DefListIndentProcessor(md.parser), 'defindent', 85) 

115 md.parser.blockprocessors.register(DefListProcessor(md.parser), 'deflist', 25) 

116 

117 

118def makeExtension(**kwargs): # pragma: no cover 

119 return DefListExtension(**kwargs)