Skip to content

Commit c686970

Browse files
feat: allow whitespace to be removed when rendering tables
## Details Adds new pipe_table `cell` option value `trimmed`. This new option functions nearly identically to the padded option however when computing the visual width of a cell we subtract out any trailing spaces. Based on this new calculation cells can now have a negative offset, meaning they occupy too much space and that space needs to be removed. When this situation is encountered we add a new `extmark` that simply applies a conceal to the end of the cell equal to the size of the negative offset. One other thing to note is for the trimmed style we ignore the width of the delimitter row since users lining up tables visually and adding spaces will also make the delimitter row line up. We add spaces at the end of the overlay virtual text to hide any text that extends beyond the computed widths. Minor other changes: - `str.leading_spaces` -> `str.spaces` where first argument is either `start` or `end` - `str.spaces` -> `str.pad` - Appending strings together is no longer done in `str` module and is instead handled inline to avoid any start vs end type logic
1 parent de6f057 commit c686970

18 files changed

+147
-109
lines changed

Diff for: README.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -421,9 +421,10 @@ require('render-markdown').setup({
421421
-- Determines how individual cells of a table are rendered:
422422
-- overlay: writes completely over the table, removing conceal behavior and highlights
423423
-- raw: replaces only the '|' characters in each row, leaving the cells unmodified
424-
-- padded: raw + cells are padded with inline extmarks to make up for any concealed text
424+
-- padded: raw + cells are padded to maximum visual width for each column
425+
-- trimmed: padded except empty space is subtracted from visual width calculation
425426
cell = 'padded',
426-
-- Minimum column width to use for padded cell
427+
-- Minimum column width to use for padded or trimmed cell
427428
min_width = 0,
428429
-- Characters used to replace table border
429430
-- Correspond to top(3), delimiter(3), bottom(3), vertical, & horizontal
@@ -816,9 +817,10 @@ require('render-markdown').setup({
816817
-- Determines how individual cells of a table are rendered:
817818
-- overlay: writes completely over the table, removing conceal behavior and highlights
818819
-- raw: replaces only the '|' characters in each row, leaving the cells unmodified
819-
-- padded: raw + cells are padded with inline extmarks to make up for any concealed text
820+
-- padded: raw + cells are padded to maximum visual width for each column
821+
-- trimmed: padded except empty space is subtracted from visual width calculation
820822
cell = 'padded',
821-
-- Minimum column width to use for padded cell
823+
-- Minimum column width to use for padded or trimmed cell
822824
min_width = 0,
823825
-- Characters used to replace table border
824826
-- Correspond to top(3), delimiter(3), bottom(3), vertical, & horizontal

Diff for: doc/render-markdown.txt

+6-4
Original file line numberDiff line numberDiff line change
@@ -467,9 +467,10 @@ Full Default Configuration ~
467467
-- Determines how individual cells of a table are rendered:
468468
-- overlay: writes completely over the table, removing conceal behavior and highlights
469469
-- raw: replaces only the '|' characters in each row, leaving the cells unmodified
470-
-- padded: raw + cells are padded with inline extmarks to make up for any concealed text
470+
-- padded: raw + cells are padded to maximum visual width for each column
471+
-- trimmed: padded except empty space is subtracted from visual width calculation
471472
cell = 'padded',
472-
-- Minimum column width to use for padded cell
473+
-- Minimum column width to use for padded or trimmed cell
473474
min_width = 0,
474475
-- Characters used to replace table border
475476
-- Correspond to top(3), delimiter(3), bottom(3), vertical, & horizontal
@@ -874,9 +875,10 @@ Wiki Page
874875
-- Determines how individual cells of a table are rendered:
875876
-- overlay: writes completely over the table, removing conceal behavior and highlights
876877
-- raw: replaces only the '|' characters in each row, leaving the cells unmodified
877-
-- padded: raw + cells are padded with inline extmarks to make up for any concealed text
878+
-- padded: raw + cells are padded to maximum visual width for each column
879+
-- trimmed: padded except empty space is subtracted from visual width calculation
878880
cell = 'padded',
879-
-- Minimum column width to use for padded cell
881+
-- Minimum column width to use for padded or trimmed cell
880882
min_width = 0,
881883
-- Characters used to replace table border
882884
-- Correspond to top(3), delimiter(3), bottom(3), vertical, & horizontal

Diff for: lua/render-markdown/core/str.lua

+7-13
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,26 @@ function M.width(s)
1717
return vim.fn.strdisplaywidth(s)
1818
end
1919

20+
---@param pos 'start'|'end'
2021
---@param s string
2122
---@return integer
22-
function M.leading_spaces(s)
23-
local _, leading_spaces = s:find('^%s*')
24-
return leading_spaces or 0
23+
function M.spaces(pos, s)
24+
local pattern = pos == 'start' and '^%s*' or '%s*$'
25+
local from, to = s:find(pattern)
26+
return (from ~= nil and to ~= nil) and to - from + 1 or 0
2527
end
2628

2729
---@param n integer
2830
---@return string
29-
function M.spaces(n)
31+
function M.pad(n)
3032
return string.rep(' ', n)
3133
end
3234

3335
---@param target string
3436
---@param s string
3537
---@return string
3638
function M.pad_to(target, s)
37-
local n = M.width(target) - M.width(s)
38-
return M.pad(n, s)
39-
end
40-
41-
---@param n integer
42-
---@param s string
43-
---@return string
44-
function M.pad(n, s)
45-
return M.spaces(n) .. s
39+
return M.pad(M.width(target) - M.width(s))
4640
end
4741

4842
return M

Diff for: lua/render-markdown/handler/markdown.lua

+5-5
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function Handler:list_marker(info)
9494
-- List markers from tree-sitter should have leading spaces removed, however there are known
9595
-- edge cases in the parser: https://github.com/tree-sitter-grammars/tree-sitter-markdown/issues/127
9696
-- As a result we account for leading spaces here, can remove if this gets fixed upstream
97-
local leading_spaces = str.leading_spaces(info.text)
97+
local leading_spaces = str.spaces('start', info.text)
9898

9999
if sibling_checkbox() then
100100
-- Hide the list marker for checkboxes rather than replacing with a bullet point
@@ -116,19 +116,19 @@ function Handler:list_marker(info)
116116
self.marks:add(true, info.start_row, info.start_col, {
117117
end_row = info.end_row,
118118
end_col = info.end_col,
119-
virt_text = { { str.pad(leading_spaces, icon), bullet.highlight } },
119+
virt_text = { { str.pad(leading_spaces) .. icon, bullet.highlight } },
120120
virt_text_pos = 'overlay',
121121
})
122122
if bullet.left_pad > 0 then
123123
self.marks:add(false, info.start_row, 0, {
124124
priority = 0,
125-
virt_text = { { str.spaces(bullet.left_pad), 'Normal' } },
125+
virt_text = { { str.pad(bullet.left_pad), 'Normal' } },
126126
virt_text_pos = 'inline',
127127
})
128128
end
129129
if bullet.right_pad > 0 then
130130
self.marks:add(true, info.start_row, info.end_col - 1, {
131-
virt_text = { { str.spaces(bullet.right_pad), 'Normal' } },
131+
virt_text = { { str.pad(bullet.right_pad), 'Normal' } },
132132
virt_text_pos = 'inline',
133133
})
134134
end
@@ -147,7 +147,7 @@ function Handler:checkbox(info, checkbox)
147147
self.marks:add(true, info.start_row, info.start_col, {
148148
end_row = info.end_row,
149149
end_col = info.end_col,
150-
virt_text = { { inline and icon or str.pad_to(info.text, icon), highlight } },
150+
virt_text = { { inline and icon or str.pad_to(info.text, icon) .. icon, highlight } },
151151
virt_text_pos = inline and 'inline' or 'overlay',
152152
conceal = inline and '' or nil,
153153
})

Diff for: lua/render-markdown/handler/markdown_inline.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ function Handler:checkbox(info, checkbox)
122122
local added = self.marks:add(true, info.start_row, info.start_col, {
123123
end_row = info.end_row,
124124
end_col = info.end_col,
125-
virt_text = { { inline and icon or str.pad_to(info.text, icon), highlight } },
125+
virt_text = { { inline and icon or str.pad_to(info.text, icon) .. icon, highlight } },
126126
virt_text_pos = 'inline',
127127
conceal = '',
128128
})

Diff for: lua/render-markdown/health.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ local state = require('render-markdown.state')
44
local M = {}
55

66
---@private
7-
M.version = '7.1.1'
7+
M.version = '7.1.2'
88

99
function M.check()
1010
M.start('version')

Diff for: lua/render-markdown/init.lua

+4-3
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ local M = {}
5151

5252
---@alias render.md.table.Preset 'none'|'round'|'double'|'heavy'
5353
---@alias render.md.table.Style 'full'|'normal'|'none'
54-
---@alias render.md.table.Cell 'padded'|'raw'|'overlay'
54+
---@alias render.md.table.Cell 'trimmed'|'padded'|'raw'|'overlay'
5555

5656
---@class (exact) render.md.UserPipeTable
5757
---@field public enabled? boolean
@@ -488,9 +488,10 @@ M.default_config = {
488488
-- Determines how individual cells of a table are rendered:
489489
-- overlay: writes completely over the table, removing conceal behavior and highlights
490490
-- raw: replaces only the '|' characters in each row, leaving the cells unmodified
491-
-- padded: raw + cells are padded with inline extmarks to make up for any concealed text
491+
-- padded: raw + cells are padded to maximum visual width for each column
492+
-- trimmed: padded except empty space is subtracted from visual width calculation
492493
cell = 'padded',
493-
-- Minimum column width to use for padded cell
494+
-- Minimum column width to use for padded or trimmed cell
494495
min_width = 0,
495496
-- Characters used to replace table border
496497
-- Correspond to top(3), delimiter(3), bottom(3), vertical, & horizontal

Diff for: lua/render-markdown/render/base.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ end
4646
function Base:indent_virt_line(line, level)
4747
local amount = self:indent(level)
4848
if amount > 0 then
49-
table.insert(line, 1, { str.spaces(amount), 'Normal' })
49+
table.insert(line, 1, { str.pad(amount), 'Normal' })
5050
end
5151
return line
5252
end

Diff for: lua/render-markdown/render/code.lua

+4-4
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ function Render:language(add_background)
111111
-- Code blocks will pick up varying amounts of leading white space depending on the
112112
-- context they are in. This gets lumped into the delimiter node and as a result,
113113
-- after concealing, the extmark will be left shifted. Logic below accounts for this.
114-
icon_text = str.pad(str.leading_spaces(self.info.text) + self.code.language_pad, icon_text .. info.text)
114+
icon_text = str.pad(str.spaces('start', self.info.text) + self.code.language_pad) .. icon_text .. info.text
115115
end
116116
return self.marks:add(true, info.start_row, info.start_col, {
117117
virt_text = { { icon_text, highlight } },
@@ -155,7 +155,7 @@ function Render:background(icon_added)
155155
end
156156
end
157157

158-
local padding = str.spaces(vim.o.columns * 2)
158+
local padding = str.pad(vim.o.columns * 2)
159159
for row = self.data.start_row, self.data.end_row - 1 do
160160
self.marks:add(false, row, self.data.col, {
161161
end_row = row + 1,
@@ -189,8 +189,8 @@ function Render:left_pad(add_background)
189189

190190
-- Use low priority to include other marks in padding when code block is at edge
191191
local priority = self.data.col == 0 and 0 or nil
192-
local outer_text = { str.spaces(self.data.col), 'Normal' }
193-
local left_text = { str.spaces(self.code.left_pad), add_background and self.code.highlight or 'Normal' }
192+
local outer_text = { str.pad(self.data.col), 'Normal' }
193+
local left_text = { str.pad(self.code.left_pad), add_background and self.code.highlight or 'Normal' }
194194

195195
for row = self.data.start_row, self.data.end_row - 1 do
196196
local virt_text = {}

Diff for: lua/render-markdown/render/heading.lua

+3-3
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ function Render:icon()
110110
self.marks:add(true, self.info.start_row, self.info.start_col, {
111111
end_row = self.info.end_row,
112112
end_col = self.info.end_col,
113-
virt_text = { { str.pad(padding, self.data.icon), { self.data.foreground, self.data.background } } },
113+
virt_text = { { str.pad(padding) .. self.data.icon, { self.data.foreground, self.data.background } } },
114114
virt_text_pos = 'overlay',
115115
})
116116
return width
@@ -152,7 +152,7 @@ function Render:background(width)
152152
-- Overwrite anything beyond width with Normal
153153
self.marks:add(true, row, 0, {
154154
priority = 0,
155-
virt_text = { { str.spaces(vim.o.columns * 2), 'Normal' } },
155+
virt_text = { { str.pad(vim.o.columns * 2), 'Normal' } },
156156
virt_text_win_col = win_col,
157157
})
158158
end
@@ -213,7 +213,7 @@ function Render:left_pad()
213213
for row = self.info.start_row, self.data.end_row - 1 do
214214
self.marks:add(false, row, 0, {
215215
priority = 0,
216-
virt_text = { { str.spaces(self.heading.left_pad), self.data.background } },
216+
virt_text = { { str.pad(self.heading.left_pad), self.data.background } },
217217
virt_text_pos = 'inline',
218218
})
219219
end

Diff for: lua/render-markdown/render/section.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function Render:render()
6464
for row = start_row, end_row do
6565
self.marks:add(false, row, 0, {
6666
priority = 0,
67-
virt_text = { { str.spaces(self.indent.per_level * self.level_change), 'Normal' } },
67+
virt_text = { { str.pad(self.indent.per_level * self.level_change), 'Normal' } },
6868
virt_text_pos = 'inline',
6969
})
7070
end

0 commit comments

Comments
 (0)