2
2
Preprocessor that transforms markdown cells: Insert numbering in from of heading
3
3
"""
4
4
5
- import re
6
-
7
5
from nbconvert .preprocessors .base import Preprocessor
8
6
7
+ try : # for Mistune >= 3.0
8
+ import mistune
9
+ from mistune .core import BlockState
10
+ from mistune .renderers .markdown import MarkdownRenderer
11
+
12
+ MISTUNE_V3 = True
13
+ except ImportError : # for Mistune >= 2.0
14
+ MISTUNE_V3 = False
15
+
16
+ WRONG_MISTUNE_VERSION_ERROR = "Error: NumberedHeadingsPreprocessor requires mistune >= 3"
17
+
9
18
10
19
class NumberedHeadingsPreprocessor (Preprocessor ):
11
20
"""Pre-processor that will rewrite markdown headings to include numberings."""
12
21
13
22
def __init__ (self , * args , ** kwargs ):
14
23
"""Init"""
15
24
super ().__init__ (* args , ** kwargs )
25
+ if not MISTUNE_V3 :
26
+ raise Exception (WRONG_MISTUNE_VERSION_ERROR )
27
+ self .md_parser = mistune .create_markdown (renderer = None )
28
+ self .md_renderer = MarkdownRenderer ()
16
29
self .current_numbering = [0 ]
17
30
18
31
def format_numbering (self ):
@@ -29,23 +42,24 @@ def _inc_current_numbering(self, level):
29
42
self .current_numbering = self .current_numbering [:level ]
30
43
self .current_numbering [level - 1 ] += 1
31
44
32
- def _transform_markdown_line (self , line , resources ):
33
- """Rewrites one markdown line, if needed"""
34
- if m := re .match (r"^(?P<level>#+) (?P<heading>.*)" , line ):
35
- level = len (m .group ("level" ))
36
- self ._inc_current_numbering (level )
37
- old_heading = m .group ("heading" ).strip ()
38
- new_heading = self .format_numbering () + " " + old_heading
39
- return "#" * level + " " + new_heading
40
-
41
- return line
42
-
43
45
def preprocess_cell (self , cell , resources , index ):
44
46
"""Rewrites all the headings in the cell if it is markdown"""
45
- if cell ["cell_type" ] == "markdown" :
46
- cell ["source" ] = "\n " .join (
47
- self ._transform_markdown_line (line , resources )
48
- for line in cell ["source" ].splitlines ()
49
- )
50
-
51
- return cell , resources
47
+ if cell ["cell_type" ] != "markdown" :
48
+ return cell , resources
49
+ try :
50
+ md_ast = self .md_parser (cell ["source" ])
51
+ assert not isinstance (md_ast , str ) # type guard ; str is not returned by ast parser
52
+ for element in md_ast :
53
+ if element ["type" ] == "heading" :
54
+ level = element ["attrs" ]["level" ]
55
+ self ._inc_current_numbering (level )
56
+ if len (element ["children" ]) > 0 :
57
+ child = element ["children" ][0 ]
58
+ if child ["type" ] == "text" :
59
+ child ["raw" ] = self .format_numbering () + " " + child ["raw" ]
60
+ new_source = self .md_renderer (md_ast , BlockState ())
61
+ cell ["source" ] = new_source
62
+ return cell , resources
63
+ except Exception :
64
+ self .log .warning ("Failed processing cell headings" , exc_info = True )
65
+ return cell , resources
0 commit comments