@@ -4,14 +4,11 @@ local log = require('render-markdown.core.log')
44local str = require (' render-markdown.lib.str' )
55
66--- @class render.md.table.Data
7- --- @field delim render.md.table.delim.Row
8- --- @field rows render.md.table.body.Row[]
7+ --- @field delim render.md.Node
8+ --- @field cols render.md.table.Col[]
9+ --- @field rows render.md.table.Row[]
910
10- --- @class render.md.table.delim.Row
11- --- @field node render.md.Node
12- --- @field cols render.md.table.delim.Col[]
13-
14- --- @class render.md.table.delim.Col
11+ --- @class render.md.table.Col
1512--- @field width integer
1613--- @field alignment render.md.table.Alignment
1714
@@ -23,12 +20,12 @@ local Alignment = {
2320 default = ' default' ,
2421}
2522
26- --- @class render.md.table.body. Row
23+ --- @class render.md.table.Row
2724--- @field node render.md.Node
2825--- @field pipes render.md.Node[]
29- --- @field cols render.md.table.body.Col []
26+ --- @field cells render.md.table.Cell []
3027
31- --- @class render.md.table.body.Col
28+ --- @class render.md.table.Cell
3229--- @field node render.md.Node
3330--- @field width integer
3431--- @field space render.md.table.Space
@@ -37,7 +34,7 @@ local Alignment = {
3734--- @field left integer
3835--- @field right integer
3936
40- --- @class render.md.table.Row
37+ --- @class render.md.table.row.Parts
4138--- @field pipes render.md.Node[]
4239--- @field cells render.md.Node[]
4340
@@ -56,7 +53,7 @@ function Render:setup()
5653 end
5754
5855 -- ensure delimiter and rows exist
59- local delim_node = nil --- @type render.md.Node ?
56+ local delim = nil --- @type render.md.Node ?
6057 local row_nodes = {} --- @type render.md.Node[]
6158 local types = {
6259 delim = ' pipe_table_delimiter_row' ,
@@ -65,7 +62,7 @@ function Render:setup()
6562 }
6663 self .node :for_each_child (function (node )
6764 if node .type == types .delim then
68- delim_node = node
65+ delim = node
6966 elseif self .context .view :overlaps (node :get ()) then
7067 if vim .tbl_contains (types .row , node .type ) then
7168 row_nodes [# row_nodes + 1 ] = node
@@ -74,21 +71,19 @@ function Render:setup()
7471 end
7572 end
7673 end )
77- if not delim_node or # row_nodes == 0 then
74+ if not delim or # row_nodes == 0 then
7875 return false
7976 end
8077
81- -- double check delimiter exists after parsing
82- local delim = self :parse_delim_row (delim_node )
83- if not delim then
78+ local cols = self :parse_cols (delim )
79+ if not cols then
8480 return false
8581 end
8682
87- -- double check rows exist after parsing
88- local rows = {} --- @type render.md.table.body.Row[]
83+ local rows = {} --- @type render.md.table.Row[]
8984 table.sort (row_nodes )
9085 for _ , row_node in ipairs (row_nodes ) do
91- local row = self :parse_body_row (row_node , # delim . cols )
86+ local row = self :parse_row (row_node , # cols )
9287 if row then
9388 rows [# rows + 1 ] = row
9489 end
@@ -97,41 +92,40 @@ function Render:setup()
9792 return false
9893 end
9994
100- -- store the max width in the delimiter
95+ -- store the max width in cols
10196 for _ , row in ipairs (rows ) do
102- for i , col in ipairs (row .cols ) do
103- local space = col .space .left + col .space .right
97+ for i , cell in ipairs (row .cells ) do
98+ local space = cell .space .left + cell .space .right
10499 local available = space - (2 * self .config .padding )
105100 -- if we don't have enough space for padding add it to the width
106- local width = col .width
101+ local width = cell .width
107102 if available < 0 then
108103 width = width - available
109104 end
110105 if self .config .cell == ' trimmed' then
111106 width = width - math.max (available , 0 )
112107 end
113- local delim_col = delim .cols [i ]
114- delim_col .width = math.max (delim_col .width , width )
108+ cols [i ].width = math.max (cols [i ].width , width )
115109 end
116110 end
117111
118- self .data = { delim = delim , rows = rows }
112+ self .data = { delim = delim , cols = cols , rows = rows }
119113
120114 return true
121115end
122116
123117--- @private
124118--- @param node render.md.Node
125- --- @return render.md.table.delim.Row ?
126- function Render :parse_delim_row (node )
127- local row = self :parse_row (node , ' pipe_table_delimiter_cell' )
128- if not row then
119+ --- @return render.md.table.Col[] ?
120+ function Render :parse_cols (node )
121+ local parts = self :parse_row_parts (node , ' pipe_table_delimiter_cell' )
122+ if not parts then
129123 return nil
130124 end
131- local cols = {} --- @type render.md.table.delim. Col[]
132- for i , cell in ipairs (row .cells ) do
133- local start_col = row .pipes [i ].end_col
134- local end_col = row .pipes [i + 1 ].start_col
125+ local cols = {} --- @type render.md.table.Col[]
126+ for i , cell in ipairs (parts .cells ) do
127+ local start_col = parts .pipes [i ].end_col
128+ local end_col = parts .pipes [i + 1 ].start_col
135129 local width = end_col - start_col
136130 assert (width >= 0 , ' invalid table layout' )
137131 if self .config .cell == ' padded' then
@@ -144,8 +138,7 @@ function Render:parse_delim_row(node)
144138 alignment = Render .alignment (cell ),
145139 }
146140 end
147- --- @type render.md.table.delim.Row
148- return { node = node , cols = cols }
141+ return cols
149142end
150143
151144--- @private
@@ -168,23 +161,23 @@ end
168161--- @private
169162--- @param node render.md.Node
170163--- @param num_cols integer
171- --- @return render.md.table.body. Row ?
172- function Render :parse_body_row (node , num_cols )
173- local row = self :parse_row (node , ' pipe_table_cell' )
174- if not row or # row .cells ~= num_cols then
164+ --- @return render.md.table.Row ?
165+ function Render :parse_row (node , num_cols )
166+ local parts = self :parse_row_parts (node , ' pipe_table_cell' )
167+ if not parts or # parts .cells ~= num_cols then
175168 return nil
176169 end
177- local cols = {} --- @type render.md.table.body.Col []
178- for i , cell in ipairs (row .cells ) do
170+ local cells = {} --- @type render.md.table.Cell []
171+ for i , cell in ipairs (parts .cells ) do
179172 -- account for double width glyphs by replacing cell range with width
180- local start_col = row .pipes [i ].end_col
181- local end_col = row .pipes [i + 1 ].start_col
173+ local start_col = parts .pipes [i ].end_col
174+ local end_col = parts .pipes [i + 1 ].start_col
182175 local width = (end_col - start_col )
183176 - (cell .end_col - cell .start_col )
184177 + self .context :width (cell )
185178 + self .config .cell_offset ({ node = cell :get () })
186179 assert (width >= 0 , ' invalid table layout' )
187- cols [ # cols + 1 ] = {
180+ cells [ # cells + 1 ] = {
188181 node = cell ,
189182 width = width ,
190183 space = {
@@ -195,15 +188,15 @@ function Render:parse_body_row(node, num_cols)
195188 },
196189 }
197190 end
198- --- @type render.md.table.body. Row
199- return { node = node , pipes = row .pipes , cols = cols }
191+ --- @type render.md.table.Row
192+ return { node = node , pipes = parts .pipes , cells = cells }
200193end
201194
202195--- @private
203196--- @param node render.md.Node
204197--- @param cell_type string
205- --- @return render.md.table.Row ?
206- function Render :parse_row (node , cell_type )
198+ --- @return render.md.table.row.Parts ?
199+ function Render :parse_row_parts (node , cell_type )
207200 local pipes = {} --- @type render.md.Node[]
208201 local cells = {} --- @type render.md.Node[]
209202 node :for_each_child (function (child )
@@ -220,7 +213,7 @@ function Render:parse_row(node, cell_type)
220213 end
221214 table.sort (pipes )
222215 table.sort (cells )
223- --- @type render.md.table.Row
216+ --- @type render.md.table.row.Parts
224217 return { pipes = pipes , cells = cells }
225218end
226219
@@ -237,10 +230,12 @@ end
237230
238231--- @private
239232function Render :delimiter ()
240- local delim , border = self .data .delim , self .config .border
233+ local delim = self .data .delim
234+ local border = self .config .border
235+ local indicator = self .config .alignment_indicator
241236
242- local indicator , icon = self . config . alignment_indicator , border [11 ]
243- local parts = iter .list .map (delim .cols , function (col )
237+ local icon = border [11 ]
238+ local parts = iter .list .map (self . data .cols , function (col )
244239 -- must have enough space to put the alignment indicator
245240 -- alignment indicator must be exactly one character wide
246241 -- do not put an indicator for default alignment
@@ -261,17 +256,17 @@ function Render:delimiter()
261256 local delimiter = border [4 ] .. table.concat (parts , border [5 ]) .. border [6 ]
262257
263258 local line = self :line ()
264- line :pad (str .spaces (' start' , delim .node . text ))
259+ line :pad (str .spaces (' start' , delim .text ))
265260 line :text (delimiter , self .config .head )
266- line :pad (str .width (delim .node . text ) - line :width ())
267- self .marks :over (self .config , ' table_border' , delim . node , {
261+ line :pad (str .width (delim .text ) - line :width ())
262+ self .marks :over (self .config , ' table_border' , delim , {
268263 virt_text = line :get (),
269264 virt_text_pos = ' overlay' ,
270265 })
271266end
272267
273268--- @private
274- --- @param row render.md.table.body. Row
269+ --- @param row render.md.table.Row
275270function Render :row (row )
276271 local icon = self .config .border [10 ]
277272 local header = row .node .type == ' pipe_table_header'
@@ -287,25 +282,25 @@ function Render:row(row)
287282 end
288283
289284 if vim .tbl_contains ({ ' trimmed' , ' padded' }, self .config .cell ) then
290- for i , col in ipairs (row .cols ) do
291- local delim = self .data . delim .cols [i ]
292- local node = col .node
293- local space = col .space
294- local fill = delim .width - col .width
285+ for i , cell in ipairs (row .cells ) do
286+ local col = self .data .cols [i ]
287+ local node = cell .node
288+ local space = cell .space
289+ local fill = col .width - cell .width
295290 -- delim(20) : --------------------
296291 -- col(4,7,2): ----XXXXXXX--
297292 -- fill(7) : _______
298293 if not self .context .conceal :enabled () then
299294 -- result: ----XXXXXXX--_______
300295 -- without concealing it is impossible to do full alignment
301296 self :shift (node , ' right' , fill )
302- elseif delim .alignment == Alignment .center then
297+ elseif col .alignment == Alignment .center then
303298 -- (7 + 2 - 4) // 2 = 5 // 2 = 2 -> move two spaces to the right
304299 -- result: __----XXXXXXX--_____
305300 local shift = math.floor ((fill + space .right - space .left ) / 2 )
306301 self :shift (node , ' left' , shift )
307302 self :shift (node , ' right' , fill - shift )
308- elseif delim .alignment == Alignment .right then
303+ elseif col .alignment == Alignment .right then
309304 -- 2 - 1 = 1 -> conceal one space on right side
310305 -- result: -_______----XXXXXXX-
311306 local shift = space .right - self .config .padding
@@ -356,29 +351,30 @@ function Render:border()
356351 local rows = self .data .rows
357352 local border = self .config .border
358353
359- --- @param row render.md.table.body. Row
354+ --- @param row render.md.table.Row
360355 --- @return boolean
361356 local function width_equal (row )
362357 if vim .tbl_contains ({ ' trimmed' , ' padded' }, self .config .cell ) then
363358 -- assume table was modified to match
364359 return true
365360 elseif self .config .cell == ' raw' then
366361 -- want the computed widths to match
367- for i , col in ipairs (row .cols ) do
368- if delim . cols [ i ]. width ~= col .width then
362+ for i , cell in ipairs (row .cells ) do
363+ if cell . width ~= self . data . cols [ i ] .width then
369364 return false
370365 end
371366 end
372367 return true
373368 elseif self .config .cell == ' overlay' then
374369 -- want the underlying text widths to match
375- return str .width (delim .node .text ) == str .width (row . node .text )
370+ return str .width (row .node .text ) == str .width (delim .text )
376371 else
377372 return false
378373 end
379374 end
380375
381- local first , last = rows [1 ], rows [# rows ]
376+ local first = rows [1 ]
377+ local last = rows [# rows ]
382378 if not width_equal (first ) or not width_equal (last ) then
383379 return
384380 end
@@ -391,21 +387,22 @@ function Render:border()
391387 end
392388
393389 local first_node = first .node
394- local last_node = # rows == 1 and delim . node or last .node
390+ local last_node = # rows == 1 and delim or last .node
395391 local spaces = get_spaces (first_node )
396392 if spaces ~= get_spaces (last_node ) then
397393 return
398394 end
399395
400- local sections = iter .list .map (delim .cols , function (col )
401- return border [11 ]:rep (col .width )
396+ local icon = border [11 ]
397+ local parts = iter .list .map (self .data .cols , function (col )
398+ return icon :rep (col .width )
402399 end )
403400
404401 --- @param node render.md.Node
405402 --- @param above boolean
406403 --- @param chars [string , string , string]
407404 local function table_border (node , above , chars )
408- local text = chars [1 ] .. table.concat (sections , chars [2 ]) .. chars [3 ]
405+ local text = chars [1 ] .. table.concat (parts , chars [2 ]) .. chars [3 ]
409406 local highlight = above and self .config .head or self .config .row
410407 local line = self :line ():pad (spaces ):text (text , highlight )
411408
0 commit comments