mirror of
https://github.com/neovim/neovim.git
synced 2026-08-22 15:21:08 +00:00
Problem: The documentation flow (`gen_vimdoc.py`) has several issues: - it's not very versatile - depends on doxygen - doesn't work well with Lua code as it requires an awkward filter script to convert it into pseudo-C. - The intermediate XML files and filters makes it too much like a rube goldberg machine. Solution: Re-implement the flow using Lua, LPEG and treesitter. - `gen_vimdoc.py` is now replaced with `gen_vimdoc.lua` and replicates a portion of the logic. - `lua2dox.lua` is gone! - No more XML files. - Doxygen is now longer used and instead we now use: - LPEG for comment parsing (see `scripts/luacats_grammar.lua` and `scripts/cdoc_grammar.lua`). - LPEG for C parsing (see `scripts/cdoc_parser.lua`) - Lua patterns for Lua parsing (see `scripts/luacats_parser.lua`). - Treesitter for Markdown parsing (see `scripts/text_utils.lua`). - The generated `runtime/doc/*.mpack` files have been removed. - `scripts/gen_eval_files.lua` now instead uses `scripts/cdoc_parser.lua` directly. - Text wrapping is implemented in `scripts/text_utils.lua` and appears to produce more consistent results (the main contributer to the diff of this change).
118 lines
3.7 KiB
Lua
118 lines
3.7 KiB
Lua
local lpeg = vim.lpeg
|
|
|
|
-- lpeg grammar for building api metadata from a set of header files. It
|
|
-- ignores comments and preprocessor commands and parses a very small subset
|
|
-- of C prototypes with a limited set of types
|
|
local P, R, S = lpeg.P, lpeg.R, lpeg.S
|
|
local C, Ct, Cc, Cg = lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg
|
|
|
|
--- @param pat vim.lpeg.Pattern
|
|
local function rep(pat)
|
|
return pat ^ 0
|
|
end
|
|
|
|
--- @param pat vim.lpeg.Pattern
|
|
local function rep1(pat)
|
|
return pat ^ 1
|
|
end
|
|
|
|
--- @param pat vim.lpeg.Pattern
|
|
local function opt(pat)
|
|
return pat ^ -1
|
|
end
|
|
|
|
local any = P(1) -- (consume one character)
|
|
local letter = R('az', 'AZ') + S('_$')
|
|
local num = R('09')
|
|
local alpha = letter + num
|
|
local nl = P('\r\n') + P('\n')
|
|
local not_nl = any - nl
|
|
local space = S(' \t')
|
|
local ws = space + nl
|
|
local fill = rep(ws)
|
|
local c_comment = P('//') * rep(not_nl)
|
|
local cdoc_comment = P('///') * opt(Ct(Cg(rep(space) * rep(not_nl), 'comment')))
|
|
local c_preproc = P('#') * rep(not_nl)
|
|
local dllexport = P('DLLEXPORT') * rep1(ws)
|
|
|
|
local typed_container = (
|
|
(P('ArrayOf(') + P('DictionaryOf(') + P('Dict('))
|
|
* rep1(any - P(')'))
|
|
* P(')')
|
|
)
|
|
|
|
local c_id = (typed_container + (letter * rep(alpha)))
|
|
local c_void = P('void')
|
|
|
|
local c_param_type = (
|
|
((P('Error') * fill * P('*') * fill) * Cc('error'))
|
|
+ ((P('Arena') * fill * P('*') * fill) * Cc('arena'))
|
|
+ ((P('lua_State') * fill * P('*') * fill) * Cc('lstate'))
|
|
+ C(opt(P('const ')) * c_id * rep1(ws) * rep1(P('*')))
|
|
+ (C(c_id) * rep1(ws))
|
|
)
|
|
|
|
local c_type = (C(c_void) * (ws ^ 1)) + c_param_type
|
|
local c_param = Ct(c_param_type * C(c_id))
|
|
local c_param_list = c_param * (fill * (P(',') * fill * c_param) ^ 0)
|
|
local c_params = Ct(c_void + c_param_list)
|
|
|
|
local impl_line = (any - P('}')) * opt(rep(not_nl)) * nl
|
|
|
|
local ignore_line = rep1(not_nl) * nl
|
|
|
|
local empty_line = Ct(Cc('empty') * nl * nl)
|
|
|
|
local c_proto = Ct(
|
|
Cc('proto')
|
|
* opt(dllexport)
|
|
* opt(Cg(P('static') * fill * Cc(true), 'static'))
|
|
* Cg(c_type, 'return_type')
|
|
* Cg(c_id, 'name')
|
|
* fill
|
|
* (P('(') * fill * Cg(c_params, 'parameters') * fill * P(')'))
|
|
* Cg(Cc(false), 'fast')
|
|
* (fill * Cg((P('FUNC_API_SINCE(') * C(rep1(num))) * P(')'), 'since') ^ -1)
|
|
* (fill * Cg((P('FUNC_API_DEPRECATED_SINCE(') * C(rep1(num))) * P(')'), 'deprecated_since') ^ -1)
|
|
* (fill * Cg((P('FUNC_API_FAST') * Cc(true)), 'fast') ^ -1)
|
|
* (fill * Cg((P('FUNC_API_RET_ALLOC') * Cc(true)), 'ret_alloc') ^ -1)
|
|
* (fill * Cg((P('FUNC_API_NOEXPORT') * Cc(true)), 'noexport') ^ -1)
|
|
* (fill * Cg((P('FUNC_API_REMOTE_ONLY') * Cc(true)), 'remote_only') ^ -1)
|
|
* (fill * Cg((P('FUNC_API_LUA_ONLY') * Cc(true)), 'lua_only') ^ -1)
|
|
* (fill * (Cg(P('FUNC_API_TEXTLOCK_ALLOW_CMDWIN') * Cc(true), 'textlock_allow_cmdwin') + Cg(
|
|
P('FUNC_API_TEXTLOCK') * Cc(true),
|
|
'textlock'
|
|
)) ^ -1)
|
|
* (fill * Cg((P('FUNC_API_REMOTE_IMPL') * Cc(true)), 'remote_impl') ^ -1)
|
|
* (fill * Cg((P('FUNC_API_COMPOSITOR_IMPL') * Cc(true)), 'compositor_impl') ^ -1)
|
|
* (fill * Cg((P('FUNC_API_CLIENT_IMPL') * Cc(true)), 'client_impl') ^ -1)
|
|
* (fill * Cg((P('FUNC_API_CLIENT_IGNORE') * Cc(true)), 'client_ignore') ^ -1)
|
|
* fill
|
|
* (P(';') + (P('{') * nl + (impl_line ^ 0) * P('}')))
|
|
)
|
|
|
|
local c_field = Ct(Cg(c_id, 'type') * ws * Cg(c_id, 'name') * fill * P(';') * fill)
|
|
local c_keyset = Ct(
|
|
P('typedef')
|
|
* ws
|
|
* P('struct')
|
|
* fill
|
|
* P('{')
|
|
* fill
|
|
* Cg(Ct(c_field ^ 1), 'fields')
|
|
* P('}')
|
|
* fill
|
|
* P('Dict')
|
|
* fill
|
|
* P('(')
|
|
* Cg(c_id, 'keyset_name')
|
|
* fill
|
|
* P(')')
|
|
* P(';')
|
|
)
|
|
|
|
local grammar = Ct(
|
|
rep1(empty_line + c_proto + cdoc_comment + c_comment + c_preproc + ws + c_keyset + ignore_line)
|
|
)
|
|
return { grammar = grammar, typed_container = typed_container }
|