Skip to content

Commit 7b8110b

Browse files
Fix a variety of health check configuration edge cases by using vim.validate
1 parent 0dfd020 commit 7b8110b

File tree

1 file changed

+147
-17
lines changed

1 file changed

+147
-17
lines changed

lua/render-markdown/health.lua

Lines changed: 147 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function M.check()
3535
end
3636

3737
vim.health.start('markdown.nvim [configuration]')
38-
local errors = M.check_keys(md.default_config, state.config, {})
38+
local errors = M.check_config(state.config)
3939
if #errors == 0 then
4040
vim.health.ok('valid')
4141
end
@@ -69,27 +69,157 @@ function M.check_executable(name, advice)
6969
end
7070
end
7171

72-
---@param t1 table<any, any>
73-
---@param t2 table<any, any>
74-
---@param path string[]
72+
---@param config render.md.Config
7573
---@return string[]
76-
function M.check_keys(t1, t2, path)
74+
function M.check_config(config)
7775
local errors = {}
78-
for k, v2 in pairs(t2) do
79-
local v1 = t1[k]
80-
local key_path = vim.list_extend(vim.list_extend({}, path), { k })
81-
local key = vim.fn.join(key_path, '.')
82-
if v1 == nil then
83-
table.insert(errors, string.format('Invalid key: %s', key))
84-
elseif type(v1) ~= type(v2) then
85-
table.insert(errors, string.format('Invalid type: %s, expected %s, found %s', key, type(v1), type(v2)))
86-
elseif type(v1) == 'table' and type(v2) == 'table' then
87-
-- Some tables are meant to have unrestricted keys
88-
if not vim.tbl_contains({ 'win_options', 'custom', 'custom_handlers' }, k) then
89-
vim.list_extend(errors, M.check_keys(v1, v2, key_path))
76+
77+
---@param value string
78+
---@param valid_values string[]
79+
---@return vim.validate.Spec
80+
local function one_of(value, valid_values)
81+
return {
82+
value,
83+
function(v)
84+
return vim.tbl_contains(valid_values, v)
85+
end,
86+
'one of ' .. vim.inspect(valid_values),
87+
}
88+
end
89+
90+
---@param path string?
91+
---@param opts table<string, vim.validate.Spec>
92+
local function append_errors(path, opts)
93+
local ok, err = pcall(vim.validate, opts)
94+
if not ok then
95+
if path == nil then
96+
table.insert(errors, err)
97+
else
98+
table.insert(errors, path .. '.' .. err)
9099
end
91100
end
92101
end
102+
103+
---@param path string
104+
---@param values string[]
105+
local function all_strings(path, values)
106+
for i, value in ipairs(values) do
107+
append_errors(path, {
108+
[tostring(i)] = { value, 'string' },
109+
})
110+
end
111+
end
112+
113+
append_errors(nil, {
114+
start_enabled = { config.start_enabled, 'boolean' },
115+
latex_enabled = { config.latex_enabled, 'boolean' },
116+
max_file_size = { config.max_file_size, 'number' },
117+
markdown_query = { config.markdown_query, 'string' },
118+
markdown_quote_query = { config.markdown_quote_query, 'string' },
119+
inline_query = { config.inline_query, 'string' },
120+
latex_converter = { config.latex_converter, 'string' },
121+
log_level = one_of(config.log_level, { 'debug', 'error' }),
122+
file_types = { config.file_types, 'table' },
123+
render_modes = { config.render_modes, 'table' },
124+
headings = { config.headings, 'table' },
125+
dash = { config.dash, 'string' },
126+
bullets = { config.bullets, 'table' },
127+
checkbox = { config.checkbox, 'table' },
128+
quote = { config.quote, 'string' },
129+
callout = { config.callout, 'table' },
130+
win_options = { config.win_options, 'table' },
131+
code_style = one_of(config.code_style, { 'full', 'normal', 'none' }),
132+
table_style = one_of(config.table_style, { 'full', 'normal', 'none' }),
133+
cell_style = one_of(config.cell_style, { 'overlay', 'raw' }),
134+
custom_handlers = { config.custom_handlers, 'table' },
135+
highlights = { config.highlights, 'table' },
136+
})
137+
138+
all_strings('file_types', config.file_types)
139+
all_strings('render_modes', config.render_modes)
140+
all_strings('headings', config.headings)
141+
all_strings('bullets', config.bullets)
142+
143+
append_errors('checkbox', {
144+
unchecked = { config.checkbox.unchecked, 'string' },
145+
checked = { config.checkbox.checked, 'string' },
146+
custom = { config.checkbox.custom, 'table' },
147+
})
148+
for name, component in pairs(config.checkbox.custom) do
149+
append_errors('checkbox.custom.' .. name, {
150+
raw = { component.raw, 'string' },
151+
rendered = { component.rendered, 'string' },
152+
highlight = { component.highlight, 'string' },
153+
})
154+
end
155+
156+
append_errors('callout', {
157+
note = { config.callout.note, 'string' },
158+
tip = { config.callout.tip, 'string' },
159+
important = { config.callout.important, 'string' },
160+
warning = { config.callout.warning, 'string' },
161+
caution = { config.callout.caution, 'string' },
162+
custom = { config.callout.custom, 'table' },
163+
})
164+
for name, component in pairs(config.callout.custom) do
165+
append_errors('callout.custom.' .. name, {
166+
raw = { component.raw, 'string' },
167+
rendered = { component.rendered, 'string' },
168+
highlight = { component.highlight, 'string' },
169+
})
170+
end
171+
172+
for name, win_option in pairs(config.win_options) do
173+
append_errors('win_options.' .. name, {
174+
default = { win_option.default, { 'number', 'string' } },
175+
rendered = { win_option.rendered, { 'number', 'string' } },
176+
})
177+
end
178+
179+
for name, handler in pairs(config.custom_handlers) do
180+
append_errors('custom_handlers.' .. name, {
181+
render = { handler.render, 'function' },
182+
extends = { handler.extends, 'boolean', true },
183+
})
184+
end
185+
186+
append_errors('highlights', {
187+
heading = { config.highlights.heading, 'table' },
188+
dash = { config.highlights.dash, 'string' },
189+
code = { config.highlights.code, 'string' },
190+
bullet = { config.highlights.bullet, 'string' },
191+
checkbox = { config.highlights.checkbox, 'table' },
192+
table = { config.highlights.table, 'table' },
193+
latex = { config.highlights.latex, 'string' },
194+
quote = { config.highlights.quote, 'string' },
195+
callout = { config.highlights.callout, 'table' },
196+
})
197+
198+
append_errors('highlights.heading', {
199+
backgrounds = { config.highlights.heading.backgrounds, 'table' },
200+
foregrounds = { config.highlights.heading.foregrounds, 'table' },
201+
})
202+
all_strings('highlights.heading.backgrounds', config.highlights.heading.backgrounds)
203+
all_strings('highlights.heading.foregrounds', config.highlights.heading.foregrounds)
204+
205+
append_errors('highlights.checkbox', {
206+
unchecked = { config.highlights.checkbox.unchecked, 'string' },
207+
checked = { config.highlights.checkbox.checked, 'string' },
208+
})
209+
210+
append_errors('highlights.table', {
211+
head = { config.highlights.table.head, 'string' },
212+
row = { config.highlights.table.row, 'string' },
213+
})
214+
215+
append_errors('highlights.callout', {
216+
note = { config.highlights.callout.note, 'string' },
217+
tip = { config.highlights.callout.tip, 'string' },
218+
important = { config.highlights.callout.important, 'string' },
219+
warning = { config.highlights.callout.warning, 'string' },
220+
caution = { config.highlights.callout.caution, 'string' },
221+
})
222+
93223
return errors
94224
end
95225

0 commit comments

Comments
 (0)