Skip to content

Commit 6f33a30

Browse files
Validate user config in health check
# Details Validate that all parameters provided by the user are valid by comparing keys and value types with the default config. This means the default configuration needs to be made accessible in health check. Change scope of default config to module level. Fix update script tree-sitter query & remove dedent. Add justfile recipe to trigger health check.
1 parent d1cd854 commit 6f33a30

File tree

4 files changed

+172
-134
lines changed

4 files changed

+172
-134
lines changed

Diff for: justfile

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ test:
55
nvim --headless --noplugin -u {{init}} \
66
-c "PlenaryBustedDirectory tests { minimal_init = '{{init}}', sequential=true }"
77

8+
health:
9+
nvim -c "checkhealth render-markdown" -- .
10+
811
demo zoom=default_zoom:
912
rm -f demo/demo.gif
1013
python demo/record.py \

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

+39-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
local M = {}
1+
local md = require('render-markdown')
2+
local state = require('render-markdown.state')
23

3-
function M.check()
4-
vim.health.start('Checking required treesitter parsers & settings')
4+
local function validate_treesitter()
55
local ok, ts = pcall(require, 'nvim-treesitter.parsers')
66
if not ok then
77
vim.health.error('treesitter is not installed')
@@ -25,4 +25,40 @@ function M.check()
2525
end
2626
end
2727

28+
---@param t1 table<any, any>
29+
---@param t2 table<any, any>
30+
---@param path string[]
31+
---@return string[]
32+
local function check_keys(t1, t2, path)
33+
local errors = {}
34+
for k, v2 in pairs(t2) do
35+
local v1 = t1[k]
36+
local key_path = vim.list_extend(vim.list_extend({}, path), { k })
37+
local key = vim.fn.join(key_path, ' -> ')
38+
if v1 == nil then
39+
table.insert(errors, string.format('Invalid parameter: %s', key))
40+
elseif type(v1) ~= type(v2) then
41+
table.insert(errors, string.format('Invalid type: %s, expected %s but found %s', key, type(v1), type(v2)))
42+
elseif type(v1) == 'table' and type(v2) == 'table' then
43+
vim.list_extend(errors, check_keys(v1, v2, key_path))
44+
end
45+
end
46+
return errors
47+
end
48+
49+
local M = {}
50+
51+
function M.check()
52+
vim.health.start('Validating treesitter parsers & settings')
53+
validate_treesitter()
54+
vim.health.start('Validating configuration')
55+
local errors = check_keys(md.default_config, state.config, {})
56+
if #errors == 0 then
57+
vim.health.ok('Configuration is valid')
58+
end
59+
for _, message in pairs(errors) do
60+
vim.health.error(message)
61+
end
62+
end
63+
2864
return M

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

+127-126
Original file line numberDiff line numberDiff line change
@@ -60,143 +60,144 @@ local M = {}
6060
---@field public table_style? 'full'|'normal'|'none'
6161
---@field public highlights? render.md.UserHighlights
6262

63-
---@param opts? render.md.UserConfig
64-
function M.setup(opts)
65-
---@type render.md.Config
66-
local default_config = {
67-
-- Configure whether Markdown should be rendered by default or not
68-
start_enabled = true,
69-
-- Maximum file size (in MB) that this plugin will attempt to render
70-
-- Any file larger than this will effectively be ignored
71-
max_file_size = 1.5,
72-
-- Capture groups that get pulled from markdown
73-
markdown_query = [[
74-
(atx_heading [
75-
(atx_h1_marker)
76-
(atx_h2_marker)
77-
(atx_h3_marker)
78-
(atx_h4_marker)
79-
(atx_h5_marker)
80-
(atx_h6_marker)
81-
] @heading)
63+
---@type render.md.Config
64+
M.default_config = {
65+
-- Configure whether Markdown should be rendered by default or not
66+
start_enabled = true,
67+
-- Maximum file size (in MB) that this plugin will attempt to render
68+
-- Any file larger than this will effectively be ignored
69+
max_file_size = 1.5,
70+
-- Capture groups that get pulled from markdown
71+
markdown_query = [[
72+
(atx_heading [
73+
(atx_h1_marker)
74+
(atx_h2_marker)
75+
(atx_h3_marker)
76+
(atx_h4_marker)
77+
(atx_h5_marker)
78+
(atx_h6_marker)
79+
] @heading)
8280
83-
(thematic_break) @dash
81+
(thematic_break) @dash
8482
85-
(fenced_code_block) @code
83+
(fenced_code_block) @code
8684
87-
[
88-
(list_marker_plus)
89-
(list_marker_minus)
90-
(list_marker_star)
91-
] @list_marker
85+
[
86+
(list_marker_plus)
87+
(list_marker_minus)
88+
(list_marker_star)
89+
] @list_marker
9290
93-
(task_list_marker_unchecked) @checkbox_unchecked
94-
(task_list_marker_checked) @checkbox_checked
91+
(task_list_marker_unchecked) @checkbox_unchecked
92+
(task_list_marker_checked) @checkbox_checked
9593
96-
(block_quote (block_quote_marker) @quote_marker)
97-
(block_quote (paragraph (inline (block_continuation) @quote_marker)))
94+
(block_quote (block_quote_marker) @quote_marker)
95+
(block_quote (paragraph (inline (block_continuation) @quote_marker)))
9896
99-
(pipe_table) @table
100-
(pipe_table_header) @table_head
101-
(pipe_table_delimiter_row) @table_delim
102-
(pipe_table_row) @table_row
103-
]],
104-
-- Capture groups that get pulled from inline markdown
105-
inline_query = [[
106-
(code_span) @code
97+
(pipe_table) @table
98+
(pipe_table_header) @table_head
99+
(pipe_table_delimiter_row) @table_delim
100+
(pipe_table_row) @table_row
101+
]],
102+
-- Capture groups that get pulled from inline markdown
103+
inline_query = [[
104+
(code_span) @code
107105
108-
(shortcut_link) @callout
109-
]],
110-
-- The level of logs to write to file: vim.fn.stdpath('state') .. '/render-markdown.log'
111-
-- Only intended to be used for plugin development / debugging
112-
log_level = 'error',
113-
-- Filetypes this plugin will run on
114-
file_types = { 'markdown' },
115-
-- Vim modes that will show a rendered view of the markdown file
116-
-- All other modes will be uneffected by this plugin
117-
render_modes = { 'n', 'c' },
118-
-- Characters that will replace the # at the start of headings
119-
headings = { '󰲡 ', '󰲣 ', '󰲥 ', '󰲧 ', '󰲩 ', '󰲫 ' },
120-
-- Character to use for the horizontal break
121-
dash = '',
122-
-- Character to use for the bullet points in lists
123-
bullets = { '', '', '', '' },
124-
checkbox = {
125-
-- Character that will replace the [ ] in unchecked checkboxes
126-
unchecked = '󰄱 ',
127-
-- Character that will replace the [x] in checked checkboxes
128-
checked = '',
106+
(shortcut_link) @callout
107+
]],
108+
-- The level of logs to write to file: vim.fn.stdpath('state') .. '/render-markdown.log'
109+
-- Only intended to be used for plugin development / debugging
110+
log_level = 'error',
111+
-- Filetypes this plugin will run on
112+
file_types = { 'markdown' },
113+
-- Vim modes that will show a rendered view of the markdown file
114+
-- All other modes will be uneffected by this plugin
115+
render_modes = { 'n', 'c' },
116+
-- Characters that will replace the # at the start of headings
117+
headings = { '󰲡 ', '󰲣 ', '󰲥 ', '󰲧 ', '󰲩 ', '󰲫 ' },
118+
-- Character to use for the horizontal break
119+
dash = '',
120+
-- Character to use for the bullet points in lists
121+
bullets = { '', '', '', '' },
122+
checkbox = {
123+
-- Character that will replace the [ ] in unchecked checkboxes
124+
unchecked = '󰄱 ',
125+
-- Character that will replace the [x] in checked checkboxes
126+
checked = '',
127+
},
128+
-- Character that will replace the > at the start of block quotes
129+
quote = '',
130+
-- Symbol / text to use for different callouts
131+
callout = {
132+
note = ' Note',
133+
tip = ' Tip',
134+
important = '󰅾 Important',
135+
warning = ' Warning',
136+
caution = '󰳦 Caution',
137+
},
138+
-- See :h 'conceallevel' for more information about meaning of values
139+
conceal = {
140+
-- conceallevel used for buffer when not being rendered, get user setting
141+
default = vim.opt.conceallevel:get(),
142+
-- conceallevel used for buffer when being rendered
143+
rendered = 3,
144+
},
145+
-- Determines how tables are rendered
146+
-- full: adds a line above and below tables + normal behavior
147+
-- normal: renders the rows of tables
148+
-- none: disables rendering, use this if you prefer having cell highlights
149+
table_style = 'full',
150+
-- Define the highlight groups to use when rendering various components
151+
highlights = {
152+
heading = {
153+
-- Background of heading line
154+
backgrounds = { 'DiffAdd', 'DiffChange', 'DiffDelete' },
155+
-- Foreground of heading character only
156+
foregrounds = {
157+
'markdownH1',
158+
'markdownH2',
159+
'markdownH3',
160+
'markdownH4',
161+
'markdownH5',
162+
'markdownH6',
163+
},
129164
},
130-
-- Character that will replace the > at the start of block quotes
131-
quote = '',
132-
-- Symbol / text to use for different callouts
133-
callout = {
134-
note = ' Note',
135-
tip = ' Tip',
136-
important = '󰅾 Important',
137-
warning = ' Warning',
138-
caution = '󰳦 Caution',
165+
-- Horizontal break
166+
dash = 'LineNr',
167+
-- Code blocks
168+
code = 'ColorColumn',
169+
-- Bullet points in list
170+
bullet = 'Normal',
171+
checkbox = {
172+
-- Unchecked checkboxes
173+
unchecked = '@markup.list.unchecked',
174+
-- Checked checkboxes
175+
checked = '@markup.heading',
139176
},
140-
-- See :h 'conceallevel' for more information about meaning of values
141-
conceal = {
142-
-- conceallevel used for buffer when not being rendered, get user setting
143-
default = vim.opt.conceallevel:get(),
144-
-- conceallevel used for buffer when being rendered
145-
rendered = 3,
177+
table = {
178+
-- Header of a markdown table
179+
head = '@markup.heading',
180+
-- Non header rows in a markdown table
181+
row = 'Normal',
146182
},
147-
-- Determines how tables are rendered
148-
-- full: adds a line above and below tables + normal behavior
149-
-- normal: renders the rows of tables
150-
-- none: disables rendering, use this if you prefer having cell highlights
151-
table_style = 'full',
152-
-- Define the highlight groups to use when rendering various components
153-
highlights = {
154-
heading = {
155-
-- Background of heading line
156-
backgrounds = { 'DiffAdd', 'DiffChange', 'DiffDelete' },
157-
-- Foreground of heading character only
158-
foregrounds = {
159-
'markdownH1',
160-
'markdownH2',
161-
'markdownH3',
162-
'markdownH4',
163-
'markdownH5',
164-
'markdownH6',
165-
},
166-
},
167-
-- Horizontal break
168-
dash = 'LineNr',
169-
-- Code blocks
170-
code = 'ColorColumn',
171-
-- Bullet points in list
172-
bullet = 'Normal',
173-
checkbox = {
174-
-- Unchecked checkboxes
175-
unchecked = '@markup.list.unchecked',
176-
-- Checked checkboxes
177-
checked = '@markup.heading',
178-
},
179-
table = {
180-
-- Header of a markdown table
181-
head = '@markup.heading',
182-
-- Non header rows in a markdown table
183-
row = 'Normal',
184-
},
185-
-- LaTeX blocks
186-
latex = '@markup.math',
187-
-- Quote character in a block quote
188-
quote = '@markup.quote',
189-
-- Highlights to use for different callouts
190-
callout = {
191-
note = 'DiagnosticInfo',
192-
tip = 'DiagnosticOk',
193-
important = 'DiagnosticHint',
194-
warning = 'DiagnosticWarn',
195-
caution = 'DiagnosticError',
196-
},
183+
-- LaTeX blocks
184+
latex = '@markup.math',
185+
-- Quote character in a block quote
186+
quote = '@markup.quote',
187+
-- Highlights to use for different callouts
188+
callout = {
189+
note = 'DiagnosticInfo',
190+
tip = 'DiagnosticOk',
191+
important = 'DiagnosticHint',
192+
warning = 'DiagnosticWarn',
193+
caution = 'DiagnosticError',
197194
},
198-
}
199-
state.config = vim.tbl_deep_extend('force', default_config, opts or {})
195+
},
196+
}
197+
198+
---@param opts? render.md.UserConfig
199+
function M.setup(opts)
200+
state.config = vim.tbl_deep_extend('force', M.default_config, opts or {})
200201
state.enabled = state.config.start_enabled
201202
state.markdown_query = vim.treesitter.query.parse('markdown', state.config.markdown_query)
202203
state.inline_query = vim.treesitter.query.parse('markdown_inline', state.config.inline_query)

Diff for: scripts/update.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from pathlib import Path
2-
from textwrap import dedent
32

43
from tree_sitter_languages import get_language, get_parser
54

@@ -30,8 +29,7 @@ def update_types(init_file: Path) -> None:
3029

3130
def update_readme(init_file: Path) -> None:
3231
default_config = get_default_config(init_file)
33-
new_config = " require('render-markdown').setup(" + default_config + ")"
34-
new_config = dedent(new_config)
32+
new_config = "require('render-markdown').setup(" + default_config + ")"
3533

3634
readme_file = Path("README.md")
3735
current_config = get_readme_config(readme_file)
@@ -48,9 +46,9 @@ def get_comments(file: Path) -> list[str]:
4846

4947
def get_default_config(file: Path) -> str:
5048
query = """
51-
(local_variable_declaration(
49+
(variable_assignment(
5250
(variable_list(
53-
variable name: (identifier) @name
51+
variable field: (identifier) @name
5452
(#eq? @name "default_config")
5553
))
5654
(expression_list value: (table)) @value

0 commit comments

Comments
 (0)