1+ from typing import Match , Type
2+
13import mistune
24import re
35
@@ -55,7 +57,7 @@ def parse_text(self, m):
5557 self .tokens .append (node )
5658
5759
58- class BlockLexer (mistune .BlockLexer ):
60+ class MdParser (mistune .BlockLexer ):
5961 default_rules = [
6062 'newline' , 'list_block' , 'block_html' ,
6163 'heading' , 'lheading' ,
@@ -67,6 +69,10 @@ class BlockLexer(mistune.BlockLexer):
6769 'hrule' , 'list_block' , 'text' ,
6870 )
6971
72+ @classmethod
73+ def get_lexer (cls ):
74+ return cls ()
75+
7076 def __init__ (self ):
7177 super ().__init__ ()
7278 self .grammar_class .block_html = re .compile (
@@ -156,13 +162,48 @@ def _process_list_item(self, cap, bull):
156162 loose = _next
157163
158164 node = ListItem ()
159- block_lexer = BlockLexer ()
165+ block_lexer = self . get_lexer ()
160166 nodes = block_lexer .parse (item , self .list_rules )
161167 node .add_nodes (nodes )
162168 result .append (node )
163169 return result
164170
165171
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+
166207def _remove_spaces_from_empty_lines (text ):
167208 return '\n ' .join ([re .sub (r'^( {1,}|\t{1,})$' , '\n ' , line ) for line in text .splitlines ()])
168209
@@ -171,9 +212,9 @@ def _remove_ltr_rtl_marks(text):
171212 return re .sub (r'(\u200e|\u200f)' , '' , text )
172213
173214
174- def parse (text ):
215+ def parse (text , parser_cls : Type [ MdParser ] = MdParser ):
175216 # HACK dirty hack to be consistent with Markdown list_block
176217 text = _remove_spaces_from_empty_lines (text )
177218 text = _remove_ltr_rtl_marks (text )
178- block_lexer = BlockLexer ()
219+ block_lexer = parser_cls ()
179220 return Root (block_lexer .parse (text ))
0 commit comments