1
+ from typing import Match , Type
2
+
1
3
import mistune
2
4
import re
3
5
@@ -55,7 +57,7 @@ def parse_text(self, m):
55
57
self .tokens .append (node )
56
58
57
59
58
- class BlockLexer (mistune .BlockLexer ):
60
+ class MdParser (mistune .BlockLexer ):
59
61
default_rules = [
60
62
'newline' , 'list_block' , 'block_html' ,
61
63
'heading' , 'lheading' ,
@@ -67,6 +69,10 @@ class BlockLexer(mistune.BlockLexer):
67
69
'hrule' , 'list_block' , 'text' ,
68
70
)
69
71
72
+ @classmethod
73
+ def get_lexer (cls ):
74
+ return cls ()
75
+
70
76
def __init__ (self ):
71
77
super ().__init__ ()
72
78
self .grammar_class .block_html = re .compile (
@@ -156,13 +162,48 @@ def _process_list_item(self, cap, bull):
156
162
loose = _next
157
163
158
164
node = ListItem ()
159
- block_lexer = BlockLexer ()
165
+ block_lexer = self . get_lexer ()
160
166
nodes = block_lexer .parse (item , self .list_rules )
161
167
node .add_nodes (nodes )
162
168
result .append (node )
163
169
return result
164
170
165
171
172
+ class ZendeskHelpMdParser (MdParser ):
173
+ TAG_CONTENT_GROUP = 'tag_content'
174
+ TAG_PATTERN = r'^\s*(<{tag_name}{attr_re}>(?P<%s>[\s\S]+?)</{tag_name}>)\s*$' % TAG_CONTENT_GROUP
175
+ CALLOUT_STYLE_GROUP = 'style'
176
+ CALLOUT_ATTR_PATTERN = r'( (?P<%s>green|red|yellow))*' % CALLOUT_STYLE_GROUP
177
+
178
+ def __init__ (self ):
179
+ super ().__init__ ()
180
+ self .grammar_class .callout = re .compile (self .TAG_PATTERN .format (tag_name = 'callout' ,
181
+ attr_re = self .CALLOUT_ATTR_PATTERN ))
182
+ self .default_rules .insert (0 , 'callout' )
183
+
184
+ self .grammar_class .steps = re .compile (self .TAG_PATTERN .format (tag_name = 'steps' , attr_re = '' ))
185
+ self .default_rules .insert (0 , 'steps' )
186
+
187
+ self .grammar_class .tabs = re .compile (self .TAG_PATTERN .format (tag_name = 'tabs' , attr_re = '' ))
188
+ self .default_rules .insert (0 , 'tabs' )
189
+
190
+ def parse_callout (self , m : Match [str ]) -> None :
191
+ style = m .group (self .CALLOUT_STYLE_GROUP )
192
+ self ._parse_nested (ZendeskHelpCallout (style ), m )
193
+
194
+ def parse_steps (self , m : Match [str ]) -> None :
195
+ self ._parse_nested (ZendeskHelpSteps (), m )
196
+
197
+ def parse_tabs (self , m : Match [str ]) -> None :
198
+ self ._parse_nested (ZendeskHelpTabs (), m )
199
+
200
+ def _parse_nested (self , node : Node , m : Match [str ]) -> None :
201
+ nested_content = m .group (self .TAG_CONTENT_GROUP )
202
+ nested_nodes = self .get_lexer ().parse (nested_content )
203
+ node .add_nodes (nested_nodes )
204
+ self .tokens .append (node )
205
+
206
+
166
207
def _remove_spaces_from_empty_lines (text ):
167
208
return '\n ' .join ([re .sub (r'^( {1,}|\t{1,})$' , '\n ' , line ) for line in text .splitlines ()])
168
209
@@ -171,9 +212,9 @@ def _remove_ltr_rtl_marks(text):
171
212
return re .sub (r'(\u200e|\u200f)' , '' , text )
172
213
173
214
174
- def parse (text ):
215
+ def parse (text , parser_cls : Type [ MdParser ] = MdParser ):
175
216
# HACK dirty hack to be consistent with Markdown list_block
176
217
text = _remove_spaces_from_empty_lines (text )
177
218
text = _remove_ltr_rtl_marks (text )
178
- block_lexer = BlockLexer ()
219
+ block_lexer = parser_cls ()
179
220
return Root (block_lexer .parse (text ))
0 commit comments