Skip to content

Commit 0c6de74

Browse files
feat: support empty lists for all heading properties
## Details Requst: #202 Adjust `list.clamp` to handle empty lists and return nil much like `list.cycle`. This allows the following heading properties to now be empty: - foregrounds - backgrounds - width - left_margin - left_pad - right_pad - min_width For the following properties an empty list just functions like the default value: - width - left_margin - left_pad - right_pad - min_width This leaves foregrounds & backgrounds which are specially handled as follows: - Without a foreground `signs` use only sign highlight - Icons will use the values availble, if none are an icon will not be rendered - If no background is available rendering a background (block & full) will be skipped - Border lines will use spaces if a highlight is not available - Left padding will use the padding highlight instead of the background when missing Minor refactor to dynamic highlight, `inverse` -> `bg_to_fg`.
1 parent 8968c91 commit 0c6de74

File tree

8 files changed

+72
-41
lines changed

8 files changed

+72
-41
lines changed

lua/render-markdown/colors.lua

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---@class render.md.cache.Colors
22
---@field combine table<string, { fg: string, bg: string }>
3-
---@field inverse table<string, { hl: string }>
3+
---@field bg_to_fg table<string, { hl: string }>
44
local Cache = {
55
combine = {},
6-
inverse = {},
6+
bg_to_fg = {},
77
}
88

99
---@class render.md.Colors
@@ -71,8 +71,8 @@ function M.reload()
7171
for _, color in pairs(Cache.combine) do
7272
M.combine(color.fg, color.bg, true)
7373
end
74-
for _, color in pairs(Cache.inverse) do
75-
M.inverse_bg(color.hl, true)
74+
for _, color in pairs(Cache.bg_to_fg) do
75+
M.bg_to_fg(color.hl, true)
7676
end
7777
end
7878

@@ -100,16 +100,16 @@ end
100100
---@param highlight string
101101
---@param force? boolean
102102
---@return string
103-
function M.inverse_bg(highlight, force)
104-
local name = string.format('%s_Inverse_%s', M.prefix, highlight)
105-
if Cache.inverse[name] == nil or force then
103+
function M.bg_to_fg(highlight, force)
104+
local name = string.format('%s_bgtofg_%s', M.prefix, highlight)
105+
if Cache.bg_to_fg[name] == nil or force then
106106
local hl = M.get_hl(highlight)
107107
vim.api.nvim_set_hl(0, name, {
108108
fg = hl.bg,
109109
---@diagnostic disable-next-line: undefined-field
110110
ctermfg = hl.ctermbg,
111111
})
112-
Cache.inverse[name] = { hl = highlight }
112+
Cache.bg_to_fg[name] = { hl = highlight }
113113
end
114114
return name
115115
end

lua/render-markdown/core/list.lua

+7-4
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ end
5555
---@generic T
5656
---@param values T[]
5757
---@param index integer
58-
---@return T?
58+
---@return T|nil
5959
function M.cycle(values, index)
6060
if #values == 0 then
6161
return nil
@@ -66,11 +66,14 @@ end
6666
---@generic T
6767
---@param values `T`|T[]
6868
---@param index integer
69-
---@return T
69+
---@return T|nil
7070
function M.clamp(values, index)
7171
if type(values) == 'table' then
72-
assert(#values >= 1, 'Must have at least one value')
73-
return values[math.min(index, #values)]
72+
if #values == 0 then
73+
return nil
74+
else
75+
return values[math.min(index, #values)]
76+
end
7477
else
7578
return values
7679
end

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.3.3'
7+
M.version = '7.3.4'
88

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

lua/render-markdown/render/base.lua

+6-2
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,19 @@ end
2727

2828
---@protected
2929
---@param text? string
30-
---@param highlight string
30+
---@param highlight? string
3131
function Base:sign(text, highlight)
3232
local sign = self.config.sign
3333
if not sign.enabled or text == nil then
3434
return
3535
end
36+
local sign_highlight = sign.highlight
37+
if highlight ~= nil then
38+
sign_highlight = colors.combine(highlight, sign_highlight)
39+
end
3640
self.marks:add(false, self.info.start_row, self.info.start_col, {
3741
sign_text = text,
38-
sign_hl_group = colors.combine(highlight, sign.highlight),
42+
sign_hl_group = sign_highlight,
3943
})
4044
end
4145

lua/render-markdown/render/code.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ function Render:background(icon_added)
154154
if self.data.margin > 0 then
155155
table.insert(virt_text, { str.pad(self.data.margin), self.config.padding.highlight })
156156
end
157-
table.insert(virt_text, { icon:rep(width - self.data.col), colors.inverse_bg(self.code.highlight) })
157+
table.insert(virt_text, { icon:rep(width - self.data.col), colors.bg_to_fg(self.code.highlight) })
158158
self.marks:add(true, row, self.data.col, {
159159
virt_text = virt_text,
160160
virt_text_pos = 'overlay',

lua/render-markdown/render/heading.lua

+45-21
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ local str = require('render-markdown.core.str')
99
---@field level integer
1010
---@field icon? string
1111
---@field sign? string
12-
---@field foreground string
13-
---@field background string
12+
---@field foreground? string
13+
---@field background? string
1414
---@field width render.md.heading.Width
1515
---@field left_margin number
1616
---@field left_pad number
@@ -59,11 +59,11 @@ function Render:setup()
5959
sign = list.cycle(self.heading.signs, level),
6060
foreground = list.clamp(self.heading.foregrounds, level),
6161
background = list.clamp(self.heading.backgrounds, level),
62-
width = list.clamp(self.heading.width, level),
63-
left_margin = list.clamp(self.heading.left_margin, level),
64-
left_pad = list.clamp(self.heading.left_pad, level),
65-
right_pad = list.clamp(self.heading.right_pad, level),
66-
min_width = list.clamp(self.heading.min_width, level),
62+
width = list.clamp(self.heading.width, level) or 'full',
63+
left_margin = list.clamp(self.heading.left_margin, level) or 0,
64+
left_pad = list.clamp(self.heading.left_pad, level) or 0,
65+
right_pad = list.clamp(self.heading.right_pad, level) or 0,
66+
min_width = list.clamp(self.heading.min_width, level) or 0,
6767
end_row = self.info.end_row + (atx and 1 or 0),
6868
}
6969

@@ -84,10 +84,16 @@ end
8484
---@private
8585
---@return integer
8686
function Render:icon()
87-
local icon, highlight = self.data.icon, { self.data.foreground, self.data.background }
87+
local icon, highlight = self.data.icon, {}
88+
if self.data.foreground ~= nil then
89+
table.insert(highlight, self.data.foreground)
90+
end
91+
if self.data.background ~= nil then
92+
table.insert(highlight, self.data.background)
93+
end
8894

8995
if not self.data.atx then
90-
if icon == nil then
96+
if icon == nil or #highlight == 0 then
9197
return 0
9298
end
9399
local added = true
@@ -107,7 +113,7 @@ function Render:icon()
107113
-- `#` characters, one is added to account for the space after the last `#` but before
108114
-- the heading title, and concealed text is subtracted since that space is not usable
109115
local width = self.data.level + 1 - self.context:concealed(self.info)
110-
if icon == nil then
116+
if icon == nil or #highlight == 0 then
111117
return width
112118
end
113119

@@ -157,6 +163,10 @@ end
157163
---@private
158164
---@param width render.md.width.Heading
159165
function Render:background(width)
166+
local highlight = self.data.background
167+
if highlight == nil then
168+
return
169+
end
160170
local win_col, padding = 0, {}
161171
if self.data.width == 'block' then
162172
win_col = width.margin + width.content + self:indent(self.data.level)
@@ -165,7 +175,7 @@ function Render:background(width)
165175
for row = self.info.start_row, self.data.end_row - 1 do
166176
self.marks:add(true, row, 0, {
167177
end_row = row + 1,
168-
hl_group = self.data.background,
178+
hl_group = highlight,
169179
hl_eol = true,
170180
})
171181
if win_col > 0 and #padding > 0 then
@@ -187,18 +197,29 @@ function Render:border(width)
187197
return
188198
end
189199

190-
local foreground, background = self.data.foreground, colors.inverse_bg(self.data.background)
200+
local foreground = self.data.foreground
201+
local background = self.data.background and colors.bg_to_fg(self.data.background)
191202
local prefix = self.heading.border_prefix and self.data.level or 0
192203
local virtual = self.heading.border_virtual
193204

194205
---@param icon string
195206
---@return { [1]: string, [2]: string }[]
196207
local function line(icon)
208+
---@param size integer
209+
---@param highlight? string
210+
---@return { [1]: string, [2]: string }
211+
local function section(size, highlight)
212+
if highlight ~= nil then
213+
return { icon:rep(size), highlight }
214+
else
215+
return { str.pad(size), self.config.padding.highlight }
216+
end
217+
end
197218
return {
198-
{ str.pad(width.margin), self.config.padding.highlight },
199-
{ icon:rep(width.padding), background },
200-
{ icon:rep(prefix), foreground },
201-
{ icon:rep(width.content - width.padding - prefix), background },
219+
section(width.margin, nil),
220+
section(width.padding, background),
221+
section(prefix, foreground),
222+
section(width.content - width.padding - prefix, background),
202223
}
203224
end
204225

@@ -241,12 +262,15 @@ end
241262
---@param width render.md.width.Heading
242263
function Render:left_pad(width)
243264
local virt_text = {}
244-
if width.margin > 0 then
245-
table.insert(virt_text, { str.pad(width.margin), self.config.padding.highlight })
246-
end
247-
if width.padding > 0 then
248-
table.insert(virt_text, { str.pad(width.padding), self.data.background })
265+
---@param size integer
266+
---@param highlight? string
267+
local function append(size, highlight)
268+
if size > 0 then
269+
table.insert(virt_text, { str.pad(size), highlight or self.config.padding.highlight })
270+
end
249271
end
272+
append(width.margin, nil)
273+
append(width.padding, self.data.background)
250274
if #virt_text > 0 then
251275
for row = self.info.start_row, self.data.end_row - 1 do
252276
self.marks:add(false, row, 0, {

tests/indent_spec.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ end
2222
---@return render.md.MarkInfo
2323
local function border(row, level, position)
2424
local foreground = util.hl(string.format('H%d', level))
25-
local background = util.hl_inverse(string.format('H%dBg', level))
25+
local background = util.hl_bg_to_fg(string.format('H%dBg', level))
2626
local icon = position == 'above' and '' or ''
2727
local line = {
2828
{ '', 'Normal' },

tests/util.lua

+3-3
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ function M.code_below(row, col, width)
275275
return {
276276
row = { row },
277277
col = { col },
278-
virt_text = { { string.rep('', width), M.hl_inverse('Code') } },
278+
virt_text = { { string.rep('', width), M.hl_bg_to_fg('Code') } },
279279
virt_text_pos = 'overlay',
280280
}
281281
end
@@ -408,8 +408,8 @@ end
408408

409409
---@param base string
410410
---@return string
411-
function M.hl_inverse(base)
412-
return M.hl('_Inverse_' .. M.hl(base))
411+
function M.hl_bg_to_fg(base)
412+
return M.hl('_bgtofg_' .. M.hl(base))
413413
end
414414

415415
---@param suffix string

0 commit comments

Comments
 (0)