Skip to content

Commit b700269

Browse files
feat: add border option to headings
# Details Request: #123 This add a `heading -> border` field that is a boolean. This is slightly different to code borders since it does not seem likely that different styles will be implemented, more just off and on. The characters added above and below are also configurable as new options. The logic attempts to overlay the border on empty lines but will use virtual text lines if the line is not available. Must also be aware of the previous heading that was overlayed since that effectively makes a line non empty as well. This is essentially a port of the `fat_headlines` option in headlines.nvim: https://github.com/lukas-reineke/headlines.nvim
1 parent f365cef commit b700269

File tree

9 files changed

+109
-16
lines changed

9 files changed

+109
-16
lines changed

Diff for: README.md

+12
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ require('render-markdown').setup({
251251
right_pad = 0,
252252
-- Minimum width to use for headings when width is 'block'
253253
min_width = 0,
254+
-- Determins if a border is added above and below headings
255+
border = false,
256+
-- Used above heading for border
257+
above = '',
258+
-- Used below heading for border
259+
below = '',
254260
-- The 'level' is used to index into the array using a clamp
255261
-- Highlight for the heading icon and extends through the entire line
256262
backgrounds = {
@@ -538,6 +544,12 @@ require('render-markdown').setup({
538544
right_pad = 0,
539545
-- Minimum width to use for headings when width is 'block'
540546
min_width = 0,
547+
-- Determins if a border is added above and below headings
548+
border = false,
549+
-- Used above heading for border
550+
above = '',
551+
-- Used below heading for border
552+
below = '',
541553
-- The 'level' is used to index into the array using a clamp
542554
-- Highlight for the heading icon and extends through the entire line
543555
backgrounds = {

Diff for: doc/render-markdown.txt

+12
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,12 @@ Full Default Configuration ~
279279
right_pad = 0,
280280
-- Minimum width to use for headings when width is 'block'
281281
min_width = 0,
282+
-- Determins if a border is added above and below headings
283+
border = false,
284+
-- Used above heading for border
285+
above = '▄',
286+
-- Used below heading for border
287+
below = '▀',
282288
-- The 'level' is used to index into the array using a clamp
283289
-- Highlight for the heading icon and extends through the entire line
284290
backgrounds = {
@@ -565,6 +571,12 @@ HEADINGS *render-markdown-setup-headings*
565571
right_pad = 0,
566572
-- Minimum width to use for headings when width is 'block'
567573
min_width = 0,
574+
-- Determins if a border is added above and below headings
575+
border = false,
576+
-- Used above heading for border
577+
above = '▄',
578+
-- Used below heading for border
579+
below = '▀',
568580
-- The 'level' is used to index into the array using a clamp
569581
-- Highlight for the heading icon and extends through the entire line
570582
backgrounds = {

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

+53-8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ local str = require('render-markdown.str')
1313
---@class render.md.handler.buf.Markdown
1414
---@field private buf integer
1515
---@field private config render.md.BufferConfig
16+
---@field private last_heading_border integer
1617
---@field private marks render.md.Mark[]
1718
local Handler = {}
1819
Handler.__index = Handler
@@ -23,6 +24,7 @@ function Handler.new(buf)
2324
local self = setmetatable({}, Handler)
2425
self.buf = buf
2526
self.config = state.get_config(buf)
27+
self.last_heading_border = -1
2628
self.marks = {}
2729
return self
2830
end
@@ -98,20 +100,45 @@ function Handler:heading(info)
98100
hl_eol = true,
99101
})
100102

103+
local width = self:heading_width(info, icon_width)
104+
101105
if heading.width == 'block' then
102-
-- Overwrite anything beyond left_pad + heading width + right_pad with Normal
103-
local width = heading.left_pad + icon_width + heading.right_pad
104-
local content = info:sibling('inline')
105-
if content ~= nil then
106-
width = width + str.width(content.text) + self:added_width(content) - content:concealed()
107-
end
106+
-- Overwrite anything beyond width with Normal
108107
self:add(true, info.start_row, 0, {
109108
priority = 0,
110109
virt_text = { { str.pad(vim.o.columns * 2), 'Normal' } },
111-
virt_text_win_col = math.max(width, heading.min_width),
110+
virt_text_win_col = width,
112111
})
113112
end
114113

114+
if heading.border then
115+
local text_above = { heading.above:rep(width), colors.inverse(background) }
116+
if info:line('above') == '' and info.start_row - 1 ~= self.last_heading_border then
117+
self:add(true, info.start_row - 1, 0, {
118+
virt_text = { text_above },
119+
virt_text_pos = 'overlay',
120+
})
121+
else
122+
self:add(false, info.start_row, 0, {
123+
virt_lines = { { text_above } },
124+
virt_lines_above = true,
125+
})
126+
end
127+
128+
local text_below = { heading.below:rep(width), colors.inverse(background) }
129+
if info:line('below') == '' then
130+
self:add(true, info.end_row + 1, 0, {
131+
virt_text = { text_below },
132+
virt_text_pos = 'overlay',
133+
})
134+
self.last_heading_border = info.end_row + 1
135+
else
136+
self:add(false, info.end_row, 0, {
137+
virt_lines = { { text_below } },
138+
})
139+
end
140+
end
141+
115142
if heading.left_pad > 0 then
116143
self:add(false, info.start_row, 0, {
117144
priority = 0,
@@ -160,6 +187,24 @@ function Handler:heading_icon(info, level, foreground, background)
160187
end
161188
end
162189

190+
---@private
191+
---@param info render.md.NodeInfo
192+
---@param icon_width integer
193+
---@return integer
194+
function Handler:heading_width(info, icon_width)
195+
local heading = self.config.heading
196+
if heading.width == 'block' then
197+
local width = heading.left_pad + icon_width + heading.right_pad
198+
local content = info:sibling('inline')
199+
if content ~= nil then
200+
width = width + str.width(content.text) + self:added_width(content) - content:concealed()
201+
end
202+
return math.max(width, heading.min_width)
203+
else
204+
return context.get(self.buf):get_width()
205+
end
206+
end
207+
163208
---@private
164209
---@param info render.md.NodeInfo
165210
function Handler:dash(info)
@@ -287,7 +332,7 @@ function Handler:code_background(code_block, icon_added)
287332
})
288333

289334
if code.width == 'block' then
290-
-- Overwrite anything beyond left_pad + block width + right_pad with Normal
335+
-- Overwrite anything beyond width with Normal
291336
local padding = str.pad(vim.o.columns * 2)
292337
for row = code_block.start_row, code_block.end_row - 1 do
293338
self:add(false, row, 0, {

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ function Handler:shortcut(info)
8080
return
8181
end
8282

83-
local line = info:lines()[1]
84-
if line:find('[' .. info.text .. ']', 1, true) ~= nil then
83+
if info:line('on'):find('[' .. info.text .. ']', 1, true) ~= nil then
8584
self:wiki_link(info)
8685
return
8786
end

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ local M = {}
55

66
---@private
77
---@type string
8-
M.version = '6.0.7'
8+
M.version = '6.0.8'
99

1010
function M.check()
1111
vim.health.start('render-markdown.nvim [version]')

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

+9
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ local M = {}
108108
---@field public left_pad? integer
109109
---@field public right_pad? integer
110110
---@field public min_width? integer
111+
---@field public border? boolean
112+
---@field public above? string
113+
---@field public below? string
111114
---@field public backgrounds? string[]
112115
---@field public foregrounds? string[]
113116

@@ -260,6 +263,12 @@ M.default_config = {
260263
right_pad = 0,
261264
-- Minimum width to use for headings when width is 'block'
262265
min_width = 0,
266+
-- Determins if a border is added above and below headings
267+
border = false,
268+
-- Used above heading for border
269+
above = '',
270+
-- Used below heading for border
271+
below = '',
263272
-- The 'level' is used to index into the array using a clamp
264273
-- Highlight for the heading icon and extends through the entire line
265274
backgrounds = {

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

+15-5
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,23 @@ function NodeInfo:for_each_child(callback)
110110
end
111111
end
112112

113+
---@param position 'above'|'below'|'on'
114+
---@return string
115+
function NodeInfo:line(position)
116+
local start_row = nil
117+
if position == 'above' then
118+
start_row = self.start_row - 1
119+
elseif position == 'above' then
120+
start_row = self.end_row + 1
121+
else
122+
start_row = self.start_row
123+
end
124+
return vim.api.nvim_buf_get_lines(self.buf, start_row, start_row + 1, false)[1]
125+
end
126+
113127
---@return string[]
114128
function NodeInfo:lines()
115-
local end_row = self.end_row
116-
if end_row == self.start_row then
117-
end_row = end_row + 1
118-
end
119-
return vim.api.nvim_buf_get_lines(self.buf, self.start_row, end_row, false)
129+
return vim.api.nvim_buf_get_lines(self.buf, self.start_row, self.end_row, false)
120130
end
121131

122132
---@return boolean

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

+3
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ function M.validate()
172172
left_pad = { heading.left_pad, 'number', nilable },
173173
right_pad = { heading.right_pad, 'number', nilable },
174174
min_width = { heading.min_width, 'number', nilable },
175+
border = { heading.border, 'boolean', nilable },
176+
above = { heading.above, 'string', nilable },
177+
below = { heading.below, 'string', nilable },
175178
backgrounds = string_array(heading.backgrounds, nilable),
176179
foregrounds = string_array(heading.foregrounds, nilable),
177180
})

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

+3
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@
9797
---@field public left_pad integer
9898
---@field public right_pad integer
9999
---@field public min_width integer
100+
---@field public border boolean
101+
---@field public above string
102+
---@field public below string
100103
---@field public backgrounds string[]
101104
---@field public foregrounds string[]
102105

0 commit comments

Comments
 (0)