11from collections import OrderedDict
2- from typing import List , Optional , Tuple
2+ from typing import Any , List , Mapping , MutableMapping
33
44from markdown_it import MarkdownIt
5- from markdown_it . token import Token
6- from mdformat .renderer import MARKERS , MDRenderer
5+ from mdformat . renderer import RenderTreeNode
6+ from mdformat .renderer . typing import RendererFunc
77
88
99def update_mdit (mdit : MarkdownIt ) -> None :
@@ -12,26 +12,18 @@ def update_mdit(mdit: MarkdownIt) -> None:
1212
1313
1414def _parse_cells (
15- rows : List [List [List [Token ]]], renderer : MDRenderer , options : dict , env : dict
15+ rows : List [List [RenderTreeNode ]],
16+ renderer_funcs : Mapping [str , RendererFunc ],
17+ options : Mapping [str , Any ],
18+ env : MutableMapping ,
1619) -> List [List [str ]]:
17- """Convert tokens in each cell to strings."""
18- for i , row in enumerate (rows ):
19- for j , cell_tokens in enumerate (row ):
20- rows [i ][j ] = (
21- renderer .render (
22- [Token ("paragraph_open" , "p" , 1 )] + cell_tokens
23- or [Token ("text" , "" , 0 )] + [Token ("paragraph_close" , "p" , - 1 )],
24- options ,
25- env ,
26- finalize = False ,
27- )
28- .replace (MARKERS .BLOCK_SEPARATOR , "" )
29- .rstrip ()
30- )
31- return rows
20+ """Convert nodes in each cell to strings."""
21+ return [[cell .render (renderer_funcs , options , env ) for cell in row ] for row in rows ]
3222
3323
34- def _to_string (rows : List [List [str ]], align : List [str ], widths : dict ) -> List [str ]:
24+ def _to_string (
25+ rows : List [List [str ]], align : List [List [str ]], widths : Mapping [int , int ]
26+ ) -> List [str ]:
3527 lines = []
3628 lines .append (
3729 "| "
@@ -63,57 +55,54 @@ def _to_string(rows: List[List[str]], align: List[str], widths: dict) -> List[st
6355 return lines
6456
6557
66- def render_token (
67- renderer : MDRenderer ,
68- tokens : List [Token ],
69- index : int ,
70- options : dict ,
71- env : dict ,
72- ) -> Optional [Tuple [str , int ]]:
73- """Convert token(s) to a string, or return None if no render method available.
74-
75- :returns: (text, index) where index is of the final "consumed" token
76- """
77- if tokens [index ].type != "table_open" :
78- return None
79-
80- # gather all cell tokens into row * column array
81- rows = []
82- align = []
83- while index < len (tokens ) and tokens [index ].type != "table_close" :
84- index += 1
85- if tokens [index ].type == "tr_open" :
86- rows .append ([])
87- align .append ([])
88- continue
89- for tag in ["th" , "td" ]:
90- if tokens [index ].type != f"{ tag } _open" :
91- continue
92- rows [- 1 ].append ([])
93- style = tokens [index ].attrGet ("style" ) or ""
94- if "text-align:right" in style :
95- align [- 1 ].append (">" )
96- elif "text-align:left" in style :
97- align [- 1 ].append ("<" )
98- elif "text-align:center" in style :
99- align [- 1 ].append ("^" )
100- else :
101- align [- 1 ].append ("" )
102- while index < len (tokens ) and tokens [index ].type != f"{ tag } _close" :
103- index += 1
104- rows [- 1 ][- 1 ].append (tokens [index ])
58+ def _render_table (
59+ node : RenderTreeNode ,
60+ renderer_funcs : Mapping [str , RendererFunc ],
61+ options : Mapping [str , Any ],
62+ env : MutableMapping ,
63+ ) -> str :
64+ """Render a `RenderTreeNode` of type "table"."""
65+ # gather all cell nodes into row * column array
66+ rows : List [List [RenderTreeNode ]] = []
67+ align : List [List [str ]] = []
68+
69+ def _gather_cell_nodes (node : RenderTreeNode ) -> None :
70+ """Recursively gather cell nodes and alignment to `rows` and
71+ `align`."""
72+ for child in node .children :
73+ if child .type == "tr" :
74+ rows .append ([])
75+ align .append ([])
76+ elif child .type in ("th" , "td" ):
77+ style = child .attrs .get ("style" ) or ""
78+ if "text-align:right" in style :
79+ align [- 1 ].append (">" )
80+ elif "text-align:left" in style :
81+ align [- 1 ].append ("<" )
82+ elif "text-align:center" in style :
83+ align [- 1 ].append ("^" )
84+ else :
85+ align [- 1 ].append ("" )
86+ inline_node = child .children [0 ]
87+ rows [- 1 ].append (inline_node )
88+ _gather_cell_nodes (child )
89+
90+ _gather_cell_nodes (node )
10591
10692 # parse all cells
107- rows = _parse_cells (rows , renderer , options , env )
93+ parsed_rows = _parse_cells (rows , renderer_funcs , options , env )
10894
10995 # work out the widths for each column
110- widths = OrderedDict ()
111- for row in rows :
96+ widths : MutableMapping [ int , int ] = OrderedDict ()
97+ for row in parsed_rows :
11298 for j , cell_text in enumerate (row ):
11399 widths [j ] = max (widths .get (j , 3 ), len (cell_text ))
114100
115101 # write content
116102 # note: assuming always one header row
117- lines = _to_string (rows , align , widths )
103+ lines = _to_string (parsed_rows , align , widths )
104+
105+ return "\n " .join (lines )
106+
118107
119- return " \n " . join ( lines ) + MARKERS . BLOCK_SEPARATOR , index
108+ RENDERER_FUNCS : Mapping [ str , RendererFunc ] = { "table" : _render_table }
0 commit comments