Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/mistune/plugins/table.py: 96%

97 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-01 06:54 +0000

1import re 

2from ..helpers import PREVENT_BACKSLASH 

3 

4# https://michelf.ca/projects/php-markdown/extra/#table 

5 

6__all__ = ['table', 'table_in_quote', 'table_in_list'] 

7 

8 

9TABLE_PATTERN = ( 

10 r'^ {0,3}\|(?P<table_head>.+)\|[ \t]*\n' 

11 r' {0,3}\|(?P<table_align> *[-:]+[-| :]*)\|[ \t]*\n' 

12 r'(?P<table_body>(?: {0,3}\|.*\|[ \t]*(?:\n|$))*)\n*' 

13) 

14NP_TABLE_PATTERN = ( 

15 r'^ {0,3}(?P<nptable_head>\S.*\|.*)\n' 

16 r' {0,3}(?P<nptable_align>[-:]+ *\|[-| :]*)\n' 

17 r'(?P<nptable_body>(?:.*\|.*(?:\n|$))*)\n*' 

18) 

19 

20TABLE_CELL = re.compile(r'^ {0,3}\|(.+)\|[ \t]*$') 

21CELL_SPLIT = re.compile(r' *' + PREVENT_BACKSLASH + r'\| *') 

22ALIGN_CENTER = re.compile(r'^ *:-+: *$') 

23ALIGN_LEFT = re.compile(r'^ *:-+ *$') 

24ALIGN_RIGHT = re.compile(r'^ *-+: *$') 

25 

26 

27def parse_table(block, m, state): 

28 pos = m.end() 

29 header = m.group('table_head') 

30 align = m.group('table_align') 

31 thead, aligns = _process_thead(header, align) 

32 if not thead: 

33 return 

34 

35 rows = [] 

36 body = m.group('table_body') 

37 for text in body.splitlines(): 

38 m = TABLE_CELL.match(text) 

39 if not m: # pragma: no cover 

40 return 

41 row = _process_row(m.group(1), aligns) 

42 if not row: 

43 return 

44 rows.append(row) 

45 

46 children = [thead, {'type': 'table_body', 'children': rows}] 

47 state.append_token({'type': 'table', 'children': children}) 

48 return pos 

49 

50 

51def parse_nptable(block, m, state): 

52 header = m.group('nptable_head') 

53 align = m.group('nptable_align') 

54 thead, aligns = _process_thead(header, align) 

55 if not thead: 

56 return 

57 

58 rows = [] 

59 body = m.group('nptable_body') 

60 for text in body.splitlines(): 

61 row = _process_row(text, aligns) 

62 if not row: 

63 return 

64 rows.append(row) 

65 

66 children = [thead, {'type': 'table_body', 'children': rows}] 

67 state.append_token({'type': 'table', 'children': children}) 

68 return m.end() 

69 

70 

71def _process_thead(header, align): 

72 headers = CELL_SPLIT.split(header) 

73 aligns = CELL_SPLIT.split(align) 

74 if len(headers) != len(aligns): 

75 return None, None 

76 

77 for i, v in enumerate(aligns): 

78 if ALIGN_CENTER.match(v): 

79 aligns[i] = 'center' 

80 elif ALIGN_LEFT.match(v): 

81 aligns[i] = 'left' 

82 elif ALIGN_RIGHT.match(v): 

83 aligns[i] = 'right' 

84 else: 

85 aligns[i] = None 

86 

87 children = [ 

88 { 

89 'type': 'table_cell', 

90 'text': text.strip(), 

91 'attrs': {'align': aligns[i], 'head': True} 

92 } 

93 for i, text in enumerate(headers) 

94 ] 

95 thead = {'type': 'table_head', 'children': children} 

96 return thead, aligns 

97 

98 

99def _process_row(text, aligns): 

100 cells = CELL_SPLIT.split(text) 

101 if len(cells) != len(aligns): 

102 return None 

103 

104 children = [ 

105 { 

106 'type': 'table_cell', 

107 'text': text.strip(), 

108 'attrs': {'align': aligns[i], 'head': False} 

109 } 

110 for i, text in enumerate(cells) 

111 ] 

112 return {'type': 'table_row', 'children': children} 

113 

114 

115def render_table(renderer, text): 

116 return '<table>\n' + text + '</table>\n' 

117 

118 

119def render_table_head(renderer, text): 

120 return '<thead>\n<tr>\n' + text + '</tr>\n</thead>\n' 

121 

122 

123def render_table_body(renderer, text): 

124 return '<tbody>\n' + text + '</tbody>\n' 

125 

126 

127def render_table_row(renderer, text): 

128 return '<tr>\n' + text + '</tr>\n' 

129 

130 

131def render_table_cell(renderer, text, align=None, head=False): 

132 if head: 

133 tag = 'th' 

134 else: 

135 tag = 'td' 

136 

137 html = ' <' + tag 

138 if align: 

139 html += ' style="text-align:' + align + '"' 

140 

141 return html + '>' + text + '</' + tag + '>\n' 

142 

143 

144def table(md): 

145 """A mistune plugin to support table, spec defined at 

146 https://michelf.ca/projects/php-markdown/extra/#table 

147 

148 Here is an example: 

149 

150 .. code-block:: text 

151 

152 First Header | Second Header 

153 ------------- | ------------- 

154 Content Cell | Content Cell 

155 Content Cell | Content Cell 

156 

157 :param md: Markdown instance 

158 """ 

159 md.block.register('table', TABLE_PATTERN, parse_table, before='paragraph') 

160 md.block.register('nptable', NP_TABLE_PATTERN, parse_nptable, before='paragraph') 

161 

162 if md.renderer and md.renderer.NAME == 'html': 

163 md.renderer.register('table', render_table) 

164 md.renderer.register('table_head', render_table_head) 

165 md.renderer.register('table_body', render_table_body) 

166 md.renderer.register('table_row', render_table_row) 

167 md.renderer.register('table_cell', render_table_cell) 

168 

169 

170def table_in_quote(md): 

171 """Enable table plugin in block quotes.""" 

172 md.block.insert_rule(md.block.block_quote_rules, 'table', before='paragraph') 

173 md.block.insert_rule(md.block.block_quote_rules, 'nptable', before='paragraph') 

174 

175 

176def table_in_list(md): 

177 """Enable table plugin in list.""" 

178 md.block.insert_rule(md.block.list_rules, 'table', before='paragraph') 

179 md.block.insert_rule(md.block.list_rules, 'nptable', before='paragraph')