123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- local cdoc_grammar = require('scripts.cdoc_grammar')
- local c_grammar = require('src.nvim.generators.c_grammar')
- --- @class nvim.cdoc.parser.param
- --- @field name string
- --- @field type string
- --- @field desc string
- --- @class nvim.cdoc.parser.return
- --- @field name string
- --- @field type string
- --- @field desc string
- --- @class nvim.cdoc.parser.note
- --- @field desc string
- --- @class nvim.cdoc.parser.brief
- --- @field kind 'brief'
- --- @field desc string
- --- @class nvim.cdoc.parser.fun
- --- @field name string
- --- @field params nvim.cdoc.parser.param[]
- --- @field returns nvim.cdoc.parser.return[]
- --- @field desc string
- --- @field deprecated? true
- --- @field since? string
- --- @field attrs? string[]
- --- @field nodoc? true
- --- @field notes? nvim.cdoc.parser.note[]
- --- @field see? nvim.cdoc.parser.note[]
- --- @class nvim.cdoc.parser.State
- --- @field doc_lines? string[]
- --- @field cur_obj? nvim.cdoc.parser.obj
- --- @field last_doc_item? nvim.cdoc.parser.param|nvim.cdoc.parser.return|nvim.cdoc.parser.note
- --- @field last_doc_item_indent? integer
- --- @alias nvim.cdoc.parser.obj
- --- | nvim.cdoc.parser.fun
- --- | nvim.cdoc.parser.brief
- --- If we collected any `---` lines. Add them to the existing (or new) object
- --- Used for function/class descriptions and multiline param descriptions.
- --- @param state nvim.cdoc.parser.State
- local function add_doc_lines_to_obj(state)
- if state.doc_lines then
- state.cur_obj = state.cur_obj or {}
- local cur_obj = assert(state.cur_obj)
- local txt = table.concat(state.doc_lines, '\n')
- if cur_obj.desc then
- cur_obj.desc = cur_obj.desc .. '\n' .. txt
- else
- cur_obj.desc = txt
- end
- state.doc_lines = nil
- end
- end
- --- @param line string
- --- @param state nvim.cdoc.parser.State
- local function process_doc_line(line, state)
- line = line:gsub('^%s+@', '@')
- local parsed = cdoc_grammar:match(line)
- if not parsed then
- if line:match('^ ') then
- line = line:sub(2)
- end
- if state.last_doc_item then
- if not state.last_doc_item_indent then
- state.last_doc_item_indent = #line:match('^%s*') + 1
- end
- state.last_doc_item.desc = (state.last_doc_item.desc or '')
- .. '\n'
- .. line:sub(state.last_doc_item_indent or 1)
- else
- state.doc_lines = state.doc_lines or {}
- table.insert(state.doc_lines, line)
- end
- return
- end
- state.last_doc_item_indent = nil
- state.last_doc_item = nil
- local kind = parsed.kind
- state.cur_obj = state.cur_obj or {}
- local cur_obj = assert(state.cur_obj)
- if kind == 'brief' then
- state.cur_obj = {
- kind = 'brief',
- desc = parsed.desc,
- }
- elseif kind == 'param' then
- state.last_doc_item_indent = nil
- cur_obj.params = cur_obj.params or {}
- state.last_doc_item = {
- name = parsed.name,
- desc = parsed.desc,
- }
- table.insert(cur_obj.params, state.last_doc_item)
- elseif kind == 'return' then
- cur_obj.returns = { {
- desc = parsed.desc,
- } }
- state.last_doc_item_indent = nil
- state.last_doc_item = cur_obj.returns[1]
- elseif kind == 'deprecated' then
- cur_obj.deprecated = true
- elseif kind == 'nodoc' then
- cur_obj.nodoc = true
- elseif kind == 'since' then
- cur_obj.since = parsed.desc
- elseif kind == 'see' then
- cur_obj.see = cur_obj.see or {}
- table.insert(cur_obj.see, { desc = parsed.desc })
- elseif kind == 'note' then
- state.last_doc_item_indent = nil
- state.last_doc_item = {
- desc = parsed.desc,
- }
- cur_obj.notes = cur_obj.notes or {}
- table.insert(cur_obj.notes, state.last_doc_item)
- else
- error('Unhandled' .. vim.inspect(parsed))
- end
- end
- --- @param item table
- --- @param state nvim.cdoc.parser.State
- local function process_proto(item, state)
- state.cur_obj = state.cur_obj or {}
- local cur_obj = assert(state.cur_obj)
- cur_obj.name = item.name
- cur_obj.params = cur_obj.params or {}
- for _, p in ipairs(item.parameters) do
- local param = { name = p[2], type = p[1] }
- local added = false
- for _, cp in ipairs(cur_obj.params) do
- if cp.name == param.name then
- cp.type = param.type
- added = true
- break
- end
- end
- if not added then
- table.insert(cur_obj.params, param)
- end
- end
- cur_obj.returns = cur_obj.returns or { {} }
- cur_obj.returns[1].type = item.return_type
- for _, a in ipairs({
- 'fast',
- 'remote_only',
- 'lua_only',
- 'textlock',
- 'textlock_allow_cmdwin',
- }) do
- if item[a] then
- cur_obj.attrs = cur_obj.attrs or {}
- table.insert(cur_obj.attrs, a)
- end
- end
- cur_obj.deprecated_since = item.deprecated_since
- -- Remove some arguments
- for i = #cur_obj.params, 1, -1 do
- local p = cur_obj.params[i]
- if p.name == 'channel_id' or vim.tbl_contains({ 'lstate', 'arena', 'error' }, p.type) then
- table.remove(cur_obj.params, i)
- end
- end
- end
- local M = {}
- --- @param filename string
- --- @return {} classes
- --- @return nvim.cdoc.parser.fun[] funs
- --- @return string[] briefs
- function M.parse(filename)
- local funs = {} --- @type nvim.cdoc.parser.fun[]
- local briefs = {} --- @type string[]
- local state = {} --- @type nvim.cdoc.parser.State
- local txt = assert(io.open(filename, 'r')):read('*all')
- local parsed = c_grammar.grammar:match(txt)
- for _, item in ipairs(parsed) do
- if item.comment then
- process_doc_line(item.comment, state)
- else
- add_doc_lines_to_obj(state)
- if item[1] == 'proto' then
- process_proto(item, state)
- table.insert(funs, state.cur_obj)
- end
- local cur_obj = state.cur_obj
- if cur_obj and not item.static then
- if cur_obj.kind == 'brief' then
- table.insert(briefs, cur_obj.desc)
- end
- end
- state = {}
- end
- end
- return {}, funs, briefs
- end
- -- M.parse('src/nvim/api/vim.c')
- return M
|