Skip to content

Commit 9b938af

Browse files
committed
fix(table): place wrapped tables as visual lines
1 parent 9a09b1f commit 9b938af

2 files changed

Lines changed: 130 additions & 65 deletions

File tree

lua/render-markdown/render/markdown/table.lua

Lines changed: 94 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -462,15 +462,14 @@ end
462462

463463
---@protected
464464
function Render:run()
465-
self:delimiter()
466465
if self.layout.wrap then
467-
for r, row in ipairs(self.data.rows) do
468-
self:row_wrapped(row, r)
469-
end
470-
else
471-
for _, row in ipairs(self.data.rows) do
472-
self:row(row)
473-
end
466+
self:wrapped()
467+
return
468+
end
469+
470+
self:delimiter()
471+
for _, row in ipairs(self.data.rows) do
472+
self:row(row)
474473
end
475474
if self.config.border_enabled and self.data.layout.valid then
476475
self:border()
@@ -603,7 +602,8 @@ end
603602
---@private
604603
---@param row render.md.table.Row
605604
---@param row_index integer
606-
function Render:row_wrapped(row, row_index)
605+
---@return render.md.Line[]
606+
function Render:row_wrapped_lines(row, row_index)
607607
local height = self.layout.row_heights[row_index]
608608
local header = row.node.type == 'pipe_table_header'
609609
local highlight = header and self.config.head or self.config.row
@@ -619,7 +619,8 @@ function Render:row_wrapped(row, row_index)
619619
end
620620

621621
local filler = self.config.filler
622-
local function build_line(visual_line)
622+
local result = {} ---@type render.md.Line[]
623+
for visual_line = 0, height - 1 do
623624
local line = self:line()
624625
line:pad(spaces, filler)
625626
for i, _ in ipairs(self.data.cols) do
@@ -637,72 +638,100 @@ function Render:row_wrapped(row, row_index)
637638
line:pad(padding, filler)
638639
end
639640
line:text(border_icon, highlight)
640-
return line
641+
result[#result + 1] = line
641642
end
643+
return result
644+
end
642645

643-
local _, buf_line = row.node:line('first', 0)
644-
buf_line = buf_line or ''
645-
local win_width = env.win.width(self.context.win)
646-
local buf_screen_lines =
647-
math.max(1, math.ceil(str.width(buf_line) / win_width))
648-
649-
-- Line 0: conceal the source line then overlay the rendered row on top.
650-
if #buf_line > 0 then
651-
self.marks:add(self.config, 'table_border', row.node.start_row, 0, {
652-
end_row = row.node.start_row,
653-
end_col = #buf_line,
654-
conceal = '',
655-
})
646+
---@private
647+
function Render:wrapped()
648+
local visual = {} ---@type render.md.Line[]
649+
for r, row in ipairs(self.data.rows) do
650+
vim.list_extend(visual, self:row_wrapped_lines(row, r))
651+
if r == 1 then
652+
visual[#visual + 1] = self:delimiter_line(self:delimiter_text())
653+
end
656654
end
657-
local first_line = build_line(0)
658-
self.marks:add(self.config, 'table_border', row.node.start_row, 0, {
659-
virt_text = first_line:get(),
660-
virt_text_pos = 'overlay',
661-
hl_mode = 'combine',
662-
})
655+
if self.config.border_enabled then
656+
if #self.data.rows > 1 then
657+
visual[#visual + 1] = self:border_line(false)
658+
end
663659

664-
-- Lines 1..height-1: overlay buffer wrap continuations, then virt_lines.
665-
local virt_lines = {} ---@type render.md.mark.Line[]
666-
for vl = 1, height - 1 do
667-
if vl < buf_screen_lines then
668-
local byte_col = vim.fn.byteidx(buf_line, vl * win_width)
660+
local first = self.data.rows[1].node
661+
local line = self:border_line(true)
662+
local row, target = first:line('above', 1)
663+
if
664+
target
665+
and str.width(target) == 0
666+
and self.context.used:take(row)
667+
then
668+
self.marks:add(self.config, 'table_border', row, 0, {
669+
virt_text = line:get(),
670+
virt_text_pos = 'overlay',
671+
})
672+
else
673+
self.marks:add(self.config, 'virtual_lines', first.start_row, 0, {
674+
virt_lines = { self:indent():line(true):extend(line):get() },
675+
virt_lines_above = true,
676+
})
677+
end
678+
end
679+
680+
local nodes = { self.data.rows[1].node, self.data.delim } ---@type render.md.Node[]
681+
for i = 2, #self.data.rows do
682+
nodes[#nodes + 1] = self.data.rows[i].node
683+
end
684+
685+
local win_width = env.win.width(self.context.win)
686+
local slots = {} ---@type { row: integer, col: integer }[]
687+
for _, node in ipairs(nodes) do
688+
local _, buf_line = node:line('first', 0)
689+
buf_line = buf_line or ''
690+
if #buf_line > 0 then
691+
self.marks:add(self.config, 'table_border', node.start_row, 0, {
692+
end_row = node.start_row,
693+
end_col = #buf_line,
694+
conceal = '',
695+
})
696+
end
697+
local screen_lines =
698+
math.max(math.ceil(str.width(buf_line) / win_width), 1)
699+
for line = 0, screen_lines - 1 do
700+
local byte_col = line == 0 and 0
701+
or vim.fn.byteidx(buf_line, line * win_width)
669702
if byte_col < 0 then
670703
byte_col = #buf_line
671704
end
672-
if #virt_lines > 0 then
673-
self.marks:add(
674-
self.config,
675-
'virtual_lines',
676-
row.node.start_row,
677-
0,
678-
{
679-
virt_lines = virt_lines,
680-
virt_lines_above = false,
681-
}
682-
)
683-
virt_lines = {}
684-
end
685-
self.marks:add(
686-
self.config,
687-
'table_border',
688-
row.node.start_row,
689-
byte_col,
690-
{
691-
virt_text = build_line(vl):get(),
692-
virt_text_pos = 'overlay',
693-
hl_mode = 'combine',
694-
}
695-
)
705+
slots[#slots + 1] = { row = node.start_row, col = byte_col }
706+
end
707+
end
708+
709+
local virt_lines = {} ---@type render.md.mark.Line[]
710+
for i, line in ipairs(visual) do
711+
local slot = slots[i]
712+
if slot then
713+
self.marks:add(self.config, 'table_border', slot.row, slot.col, {
714+
virt_text = line:get(),
715+
virt_text_pos = 'overlay',
716+
hl_mode = 'combine',
717+
})
696718
else
697-
local vline = self:indent():line(true):extend(build_line(vl))
698-
virt_lines[#virt_lines + 1] = vline:get()
719+
virt_lines[#virt_lines + 1] =
720+
self:indent():line(true):extend(line):get()
699721
end
700722
end
701723
if #virt_lines > 0 then
702-
self.marks:add(self.config, 'virtual_lines', row.node.start_row, 0, {
703-
virt_lines = virt_lines,
704-
virt_lines_above = false,
705-
})
724+
local last = self.data.rows[#self.data.rows].node
725+
self.marks:add(
726+
self.config,
727+
'virtual_lines',
728+
last.start_row,
729+
last.end_col,
730+
{
731+
virt_lines = virt_lines,
732+
virt_lines_above = false,
733+
}
734+
)
706735
end
707736
end
708737

tests/table_spec.lua

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,4 +301,40 @@ describe('table', function()
301301
'└──────┴────────────────────────────────────────┴──────────┘',
302302
})
303303
end)
304+
305+
it('wrapped long delimiter', function()
306+
util.setup.text({
307+
'',
308+
'| ID | Title | Severity | Status |',
309+
'|-------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|--------|',
310+
"| [T-1] | Here's a long text that definitely causes wrapping. My hands are typing words. If you're reading this then my hands continued typing words to make long enough a line for testing. Also you possess the highly coveted skill of reading. Good for you. Sorry, didn't mean to sound so sarcastic there. Honestly I'm thrilled for you. I have just trouble showing it. | High | Open |",
311+
}, {
312+
pipe_table = { max_table_width = 60 },
313+
win_options = { wrap = { default = false, rendered = true } },
314+
})
315+
316+
util.assert_screen({
317+
'┌─────────┬────────────────────────┬────────────┬──────────┐',
318+
'│ ID │ Title │ Severity │ Status │',
319+
'├─────────┼────────────────────────┼────────────┼──────────┤',
320+
"│ T-1 │ Here's a long text tha │ High │ Open │",
321+
'│ │ t definitely causes wr │ │ │',
322+
'│ │ apping. My hands are t │ │ │',
323+
"│ │ yping words. If you're │ │ │",
324+
'│ │ reading this then my │ │ │',
325+
'│ │ hands continued typing │ │ │',
326+
'│ │ words to make long en │ │ │',
327+
'│ │ ough a line for testin │ │ │',
328+
'│ │ g. Also you possess th │ │ │',
329+
'│ │ e highly coveted skill │ │ │',
330+
'│ │ of reading. Good for │ │ │',
331+
"│ │ you. Sorry, didn't mea │ │ │",
332+
'│ │ n to sound so sarcasti │ │ │',
333+
"│ │ c there. Honestly I'm │ │ │",
334+
'│ │ thrilled for you. I ha │ │ │',
335+
'│ │ ve just trouble showin │ │ │',
336+
'│ │ g it. │ │ │',
337+
'└─────────┴────────────────────────┴────────────┴──────────┘',
338+
})
339+
end)
304340
end)

0 commit comments

Comments
 (0)