Skip to content

Commit 5c2440d

Browse files
feat: support custom heading properties based on heading text
## Details Request: #320 The desired feature was some way to change the icon, foreground, and background for a heading based on the text of the heading. To accomplish have added a new configuration under `heading` called `custom` which functions very similarly to custom links. Users define a `pattern` which will be matched against the heading text and if it does we will use the `icon`, `foreground`, & `background` (if provided) from the matching custom configuration instead of the top level values. For example: ```lua require('render-markdown').setup({ heading = { custom = { codecompanion_me = { pattern = '^## Me$', icon = 'some_icon', foreground = 'some_highlight', background = 'some_highlight', }, }, }, }) ```
1 parent f2bdf9f commit 5c2440d

File tree

8 files changed

+76
-4
lines changed

8 files changed

+76
-4
lines changed

Diff for: README.md

+16
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,14 @@ require('render-markdown').setup({
328328
'RenderMarkdownH5',
329329
'RenderMarkdownH6',
330330
},
331+
-- Define custom heading patterns which allow you to override various properties
332+
-- based on the contents of a heading. Each entry should consist of a string key,
333+
-- which is used mostly as an identifier, and a table value with:
334+
-- 'pattern': Matched against the heading text see :h lua-pattern
335+
-- 'icon': Optional override for the icon
336+
-- 'background': Optional override for the background
337+
-- 'foreground': Optional override for the foreground
338+
custom = {},
331339
},
332340
paragraph = {
333341
-- Turn on / off paragraph rendering
@@ -809,6 +817,14 @@ require('render-markdown').setup({
809817
'RenderMarkdownH5',
810818
'RenderMarkdownH6',
811819
},
820+
-- Define custom heading patterns which allow you to override various properties
821+
-- based on the contents of a heading. Each entry should consist of a string key,
822+
-- which is used mostly as an identifier, and a table value with:
823+
-- 'pattern': Matched against the heading text see :h lua-pattern
824+
-- 'icon': Optional override for the icon
825+
-- 'background': Optional override for the background
826+
-- 'foreground': Optional override for the foreground
827+
custom = {},
812828
},
813829
})
814830
```

Diff for: doc/render-markdown.txt

+16
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,14 @@ Default Configuration ~
389389
'RenderMarkdownH5',
390390
'RenderMarkdownH6',
391391
},
392+
-- Define custom heading patterns which allow you to override various properties
393+
-- based on the contents of a heading. Each entry should consist of a string key,
394+
-- which is used mostly as an identifier, and a table value with:
395+
-- 'pattern': Matched against the heading text see :h lua-pattern
396+
-- 'icon': Optional override for the icon
397+
-- 'background': Optional override for the background
398+
-- 'foreground': Optional override for the foreground
399+
custom = {},
392400
},
393401
paragraph = {
394402
-- Turn on / off paragraph rendering
@@ -868,6 +876,14 @@ Heading Configuration ~
868876
'RenderMarkdownH5',
869877
'RenderMarkdownH6',
870878
},
879+
-- Define custom heading patterns which allow you to override various properties
880+
-- based on the contents of a heading. Each entry should consist of a string key,
881+
-- which is used mostly as an identifier, and a table value with:
882+
-- 'pattern': Matched against the heading text see :h lua-pattern
883+
-- 'icon': Optional override for the icon
884+
-- 'background': Optional override for the background
885+
-- 'foreground': Optional override for the foreground
886+
custom = {},
871887
},
872888
})
873889
<

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

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

77
---@private
8-
M.version = '8.0.0'
8+
M.version = '8.0.1'
99

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

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

+15
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ local M = {}
183183
---@field public left_margin? number
184184
---@field public min_width? integer
185185

186+
---@class (exact) render.md.HeadingCustom
187+
---@field public pattern string
188+
---@field public icon? string
189+
---@field public background? string
190+
---@field public foreground? string
191+
186192
---@class (exact) render.md.HeadingContext
187193
---@field public sections integer[]
188194

@@ -209,6 +215,7 @@ local M = {}
209215
---@field public below? string
210216
---@field public backgrounds? string[]
211217
---@field public foregrounds? string[]
218+
---@field public custom? table<string, render.md.HeadingCustom>
212219

213220
---@class (exact) render.md.UserPadding
214221
---@field public highlight? string
@@ -438,6 +445,14 @@ M.default_config = {
438445
'RenderMarkdownH5',
439446
'RenderMarkdownH6',
440447
},
448+
-- Define custom heading patterns which allow you to override various properties
449+
-- based on the contents of a heading. Each entry should consist of a string key,
450+
-- which is used mostly as an identifier, and a table value with:
451+
-- 'pattern': Matched against the heading text see :h lua-pattern
452+
-- 'icon': Optional override for the icon
453+
-- 'background': Optional override for the background
454+
-- 'foreground': Optional override for the foreground
455+
custom = {},
441456
},
442457
paragraph = {
443458
-- Turn on / off paragraph rendering

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

+16-3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ function Render:setup()
5252
return false
5353
end
5454

55+
local custom = self:custom()
56+
5557
local icon, icons = nil, self.heading.icons
5658
if type(icons) == 'function' then
5759
icon = icons({ sections = self.node:sections() })
@@ -63,10 +65,10 @@ function Render:setup()
6365
atx = atx,
6466
marker = marker,
6567
level = level,
66-
icon = icon,
68+
icon = custom.icon or icon,
6769
sign = List.cycle(self.heading.signs, level),
68-
foreground = List.clamp(self.heading.foregrounds, level),
69-
background = List.clamp(self.heading.backgrounds, level),
70+
foreground = custom.foreground or List.clamp(self.heading.foregrounds, level),
71+
background = custom.background or List.clamp(self.heading.backgrounds, level),
7072
width = List.clamp(self.heading.width, level) or 'full',
7173
left_margin = List.clamp(self.heading.left_margin, level) or 0,
7274
left_pad = List.clamp(self.heading.left_pad, level) or 0,
@@ -78,6 +80,17 @@ function Render:setup()
7880
return true
7981
end
8082

83+
---@private
84+
---@return render.md.HeadingCustom
85+
function Render:custom()
86+
for _, custom in pairs(self.heading.custom) do
87+
if self.node.text:find(custom.pattern) ~= nil then
88+
return custom
89+
end
90+
end
91+
return {}
92+
end
93+
8194
function Render:render()
8295
if self.heading.sign then
8396
self:sign(self.data.sign, self.data.foreground)

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

+10
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,16 @@ function M.validate()
168168
:list('icons', 'string', 'function')
169169
:one_of('position', { 'overlay', 'inline', 'right' })
170170
:one_or_list_of('width', { 'full', 'block' })
171+
:nested('custom', function(patterns)
172+
patterns
173+
:nested('ALL', function(pattern)
174+
pattern
175+
:type('pattern', 'string')
176+
:type({ 'icon', 'background', 'foreground' }, { 'string', 'nil' })
177+
:check()
178+
end, false)
179+
:check()
180+
end)
171181
:check()
172182
end)
173183
:nested('paragraph', function(paragraph)

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

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
---@field public below string
160160
---@field public backgrounds string[]
161161
---@field public foregrounds string[]
162+
---@field public custom table<string, render.md.HeadingCustom>
162163

163164
---@class (exact) render.md.Padding
164165
---@field public highlight string

Diff for: scripts/update.py

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def is_user(self) -> bool:
2626
def is_optional(self, field: str) -> bool:
2727
class_to_optional: dict[str, list[str]] = {
2828
"Handler": ["extends"],
29+
"HeadingCustom": ["icon", "background", "foreground"],
2930
"UserCode": ["highlight_language"],
3031
"UserCustomCheckbox": ["scope_highlight"],
3132
"UserCheckboxComponent": ["scope_highlight"],

0 commit comments

Comments
 (0)