Skip to content

Commit

Permalink
Validate user config in health check
Browse files Browse the repository at this point in the history
# 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.
  • Loading branch information
MeanderingProgrammer committed May 31, 2024
1 parent d1cd854 commit 6f33a30
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 134 deletions.
3 changes: 3 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ test:
nvim --headless --noplugin -u {{init}} \
-c "PlenaryBustedDirectory tests { minimal_init = '{{init}}', sequential=true }"

health:
nvim -c "checkhealth render-markdown" -- .

demo zoom=default_zoom:
rm -f demo/demo.gif
python demo/record.py \
Expand Down
42 changes: 39 additions & 3 deletions lua/render-markdown/health.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
local M = {}
local md = require('render-markdown')
local state = require('render-markdown.state')

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

---@param t1 table<any, any>
---@param t2 table<any, any>
---@param path string[]
---@return string[]
local function check_keys(t1, t2, path)
local errors = {}
for k, v2 in pairs(t2) do
local v1 = t1[k]
local key_path = vim.list_extend(vim.list_extend({}, path), { k })
local key = vim.fn.join(key_path, ' -> ')
if v1 == nil then
table.insert(errors, string.format('Invalid parameter: %s', key))
elseif type(v1) ~= type(v2) then
table.insert(errors, string.format('Invalid type: %s, expected %s but found %s', key, type(v1), type(v2)))
elseif type(v1) == 'table' and type(v2) == 'table' then
vim.list_extend(errors, check_keys(v1, v2, key_path))
end
end
return errors
end

local M = {}

function M.check()
vim.health.start('Validating treesitter parsers & settings')
validate_treesitter()
vim.health.start('Validating configuration')
local errors = check_keys(md.default_config, state.config, {})
if #errors == 0 then
vim.health.ok('Configuration is valid')
end
for _, message in pairs(errors) do
vim.health.error(message)
end
end

return M
253 changes: 127 additions & 126 deletions lua/render-markdown/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -60,143 +60,144 @@ local M = {}
---@field public table_style? 'full'|'normal'|'none'
---@field public highlights? render.md.UserHighlights

---@param opts? render.md.UserConfig
function M.setup(opts)
---@type render.md.Config
local default_config = {
-- Configure whether Markdown should be rendered by default or not
start_enabled = true,
-- Maximum file size (in MB) that this plugin will attempt to render
-- Any file larger than this will effectively be ignored
max_file_size = 1.5,
-- Capture groups that get pulled from markdown
markdown_query = [[
(atx_heading [
(atx_h1_marker)
(atx_h2_marker)
(atx_h3_marker)
(atx_h4_marker)
(atx_h5_marker)
(atx_h6_marker)
] @heading)
---@type render.md.Config
M.default_config = {
-- Configure whether Markdown should be rendered by default or not
start_enabled = true,
-- Maximum file size (in MB) that this plugin will attempt to render
-- Any file larger than this will effectively be ignored
max_file_size = 1.5,
-- Capture groups that get pulled from markdown
markdown_query = [[
(atx_heading [
(atx_h1_marker)
(atx_h2_marker)
(atx_h3_marker)
(atx_h4_marker)
(atx_h5_marker)
(atx_h6_marker)
] @heading)
(thematic_break) @dash
(thematic_break) @dash
(fenced_code_block) @code
(fenced_code_block) @code
[
(list_marker_plus)
(list_marker_minus)
(list_marker_star)
] @list_marker
[
(list_marker_plus)
(list_marker_minus)
(list_marker_star)
] @list_marker
(task_list_marker_unchecked) @checkbox_unchecked
(task_list_marker_checked) @checkbox_checked
(task_list_marker_unchecked) @checkbox_unchecked
(task_list_marker_checked) @checkbox_checked
(block_quote (block_quote_marker) @quote_marker)
(block_quote (paragraph (inline (block_continuation) @quote_marker)))
(block_quote (block_quote_marker) @quote_marker)
(block_quote (paragraph (inline (block_continuation) @quote_marker)))
(pipe_table) @table
(pipe_table_header) @table_head
(pipe_table_delimiter_row) @table_delim
(pipe_table_row) @table_row
]],
-- Capture groups that get pulled from inline markdown
inline_query = [[
(code_span) @code
(pipe_table) @table
(pipe_table_header) @table_head
(pipe_table_delimiter_row) @table_delim
(pipe_table_row) @table_row
]],
-- Capture groups that get pulled from inline markdown
inline_query = [[
(code_span) @code
(shortcut_link) @callout
]],
-- The level of logs to write to file: vim.fn.stdpath('state') .. '/render-markdown.log'
-- Only intended to be used for plugin development / debugging
log_level = 'error',
-- Filetypes this plugin will run on
file_types = { 'markdown' },
-- Vim modes that will show a rendered view of the markdown file
-- All other modes will be uneffected by this plugin
render_modes = { 'n', 'c' },
-- Characters that will replace the # at the start of headings
headings = { '󰲡 ', '󰲣 ', '󰲥 ', '󰲧 ', '󰲩 ', '󰲫 ' },
-- Character to use for the horizontal break
dash = '',
-- Character to use for the bullet points in lists
bullets = { '', '', '', '' },
checkbox = {
-- Character that will replace the [ ] in unchecked checkboxes
unchecked = '󰄱 ',
-- Character that will replace the [x] in checked checkboxes
checked = '',
(shortcut_link) @callout
]],
-- The level of logs to write to file: vim.fn.stdpath('state') .. '/render-markdown.log'
-- Only intended to be used for plugin development / debugging
log_level = 'error',
-- Filetypes this plugin will run on
file_types = { 'markdown' },
-- Vim modes that will show a rendered view of the markdown file
-- All other modes will be uneffected by this plugin
render_modes = { 'n', 'c' },
-- Characters that will replace the # at the start of headings
headings = { '󰲡 ', '󰲣 ', '󰲥 ', '󰲧 ', '󰲩 ', '󰲫 ' },
-- Character to use for the horizontal break
dash = '',
-- Character to use for the bullet points in lists
bullets = { '', '', '', '' },
checkbox = {
-- Character that will replace the [ ] in unchecked checkboxes
unchecked = '󰄱 ',
-- Character that will replace the [x] in checked checkboxes
checked = '',
},
-- Character that will replace the > at the start of block quotes
quote = '',
-- Symbol / text to use for different callouts
callout = {
note = ' Note',
tip = ' Tip',
important = '󰅾 Important',
warning = ' Warning',
caution = '󰳦 Caution',
},
-- See :h 'conceallevel' for more information about meaning of values
conceal = {
-- conceallevel used for buffer when not being rendered, get user setting
default = vim.opt.conceallevel:get(),
-- conceallevel used for buffer when being rendered
rendered = 3,
},
-- Determines how tables are rendered
-- full: adds a line above and below tables + normal behavior
-- normal: renders the rows of tables
-- none: disables rendering, use this if you prefer having cell highlights
table_style = 'full',
-- Define the highlight groups to use when rendering various components
highlights = {
heading = {
-- Background of heading line
backgrounds = { 'DiffAdd', 'DiffChange', 'DiffDelete' },
-- Foreground of heading character only
foregrounds = {
'markdownH1',
'markdownH2',
'markdownH3',
'markdownH4',
'markdownH5',
'markdownH6',
},
},
-- Character that will replace the > at the start of block quotes
quote = '',
-- Symbol / text to use for different callouts
callout = {
note = ' Note',
tip = ' Tip',
important = '󰅾 Important',
warning = ' Warning',
caution = '󰳦 Caution',
-- Horizontal break
dash = 'LineNr',
-- Code blocks
code = 'ColorColumn',
-- Bullet points in list
bullet = 'Normal',
checkbox = {
-- Unchecked checkboxes
unchecked = '@markup.list.unchecked',
-- Checked checkboxes
checked = '@markup.heading',
},
-- See :h 'conceallevel' for more information about meaning of values
conceal = {
-- conceallevel used for buffer when not being rendered, get user setting
default = vim.opt.conceallevel:get(),
-- conceallevel used for buffer when being rendered
rendered = 3,
table = {
-- Header of a markdown table
head = '@markup.heading',
-- Non header rows in a markdown table
row = 'Normal',
},
-- Determines how tables are rendered
-- full: adds a line above and below tables + normal behavior
-- normal: renders the rows of tables
-- none: disables rendering, use this if you prefer having cell highlights
table_style = 'full',
-- Define the highlight groups to use when rendering various components
highlights = {
heading = {
-- Background of heading line
backgrounds = { 'DiffAdd', 'DiffChange', 'DiffDelete' },
-- Foreground of heading character only
foregrounds = {
'markdownH1',
'markdownH2',
'markdownH3',
'markdownH4',
'markdownH5',
'markdownH6',
},
},
-- Horizontal break
dash = 'LineNr',
-- Code blocks
code = 'ColorColumn',
-- Bullet points in list
bullet = 'Normal',
checkbox = {
-- Unchecked checkboxes
unchecked = '@markup.list.unchecked',
-- Checked checkboxes
checked = '@markup.heading',
},
table = {
-- Header of a markdown table
head = '@markup.heading',
-- Non header rows in a markdown table
row = 'Normal',
},
-- LaTeX blocks
latex = '@markup.math',
-- Quote character in a block quote
quote = '@markup.quote',
-- Highlights to use for different callouts
callout = {
note = 'DiagnosticInfo',
tip = 'DiagnosticOk',
important = 'DiagnosticHint',
warning = 'DiagnosticWarn',
caution = 'DiagnosticError',
},
-- LaTeX blocks
latex = '@markup.math',
-- Quote character in a block quote
quote = '@markup.quote',
-- Highlights to use for different callouts
callout = {
note = 'DiagnosticInfo',
tip = 'DiagnosticOk',
important = 'DiagnosticHint',
warning = 'DiagnosticWarn',
caution = 'DiagnosticError',
},
}
state.config = vim.tbl_deep_extend('force', default_config, opts or {})
},
}

---@param opts? render.md.UserConfig
function M.setup(opts)
state.config = vim.tbl_deep_extend('force', M.default_config, opts or {})
state.enabled = state.config.start_enabled
state.markdown_query = vim.treesitter.query.parse('markdown', state.config.markdown_query)
state.inline_query = vim.treesitter.query.parse('markdown_inline', state.config.inline_query)
Expand Down
8 changes: 3 additions & 5 deletions scripts/update.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from pathlib import Path
from textwrap import dedent

from tree_sitter_languages import get_language, get_parser

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

def update_readme(init_file: Path) -> None:
default_config = get_default_config(init_file)
new_config = " require('render-markdown').setup(" + default_config + ")"
new_config = dedent(new_config)
new_config = "require('render-markdown').setup(" + default_config + ")"

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

def get_default_config(file: Path) -> str:
query = """
(local_variable_declaration(
(variable_assignment(
(variable_list(
variable name: (identifier) @name
variable field: (identifier) @name
(#eq? @name "default_config")
))
(expression_list value: (table)) @value
Expand Down

0 comments on commit 6f33a30

Please sign in to comment.