semi ok
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
local M = {}
|
||||
|
||||
-- C/kernel-doc style: /** ... @param: ... Return: ... */
|
||||
local function generate_c_doc(bufnr, row, line)
|
||||
-- strip static/inline/extern prefixes
|
||||
local stripped = line:gsub("^%s*static%s+", ""):gsub("^%s*inline%s+", ""):gsub("^%s*extern%s+", "")
|
||||
|
||||
-- match: type *func_name(params) or type* func_name(params)
|
||||
local ret, name, params = stripped:match("^%s*([%w_]+%s*%**)%s*([%w_]+)%s*%((.*)%)%s*{?%s*$")
|
||||
if not name then
|
||||
return nil, "No C function signature found on current line"
|
||||
end
|
||||
|
||||
local doc = { "/**", " * " .. name .. "() - " }
|
||||
|
||||
-- parse parameters
|
||||
if params and params:match("%S") and not params:match("^%s*void%s*$") then
|
||||
for param in params:gmatch("([^,]+)") do
|
||||
local pname = param:match("([%w_]+)%s*$")
|
||||
or param:match("%*%s*([%w_]+)")
|
||||
or param:match("([%w_]+)%s*%[")
|
||||
if pname then
|
||||
table.insert(doc, " * @" .. pname .. ": ")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(doc, " *")
|
||||
|
||||
-- add Return: if not void
|
||||
ret = ret and ret:gsub("%s+", " "):gsub("^%s*", ""):gsub("%s*$", "") or ""
|
||||
if ret ~= "void" and ret ~= "" then
|
||||
table.insert(doc, " * Return: ")
|
||||
end
|
||||
|
||||
table.insert(doc, " */")
|
||||
return doc, nil
|
||||
end
|
||||
|
||||
-- Go style: // FunctionName does something.
|
||||
local function generate_go_doc(bufnr, row, line)
|
||||
-- match: func (receiver) name(params) return or func name(params) return
|
||||
local name, params, ret
|
||||
|
||||
-- method with receiver: func (r *Receiver) Name(params) return
|
||||
name, params, ret = line:match("^%s*func%s+%([^)]+%)%s+([%w_]+)%s*%((.-)%)%s*(.-)%s*{?%s*$")
|
||||
|
||||
-- regular function: func Name(params) return
|
||||
if not name then
|
||||
name, params, ret = line:match("^%s*func%s+([%w_]+)%s*%((.-)%)%s*(.-)%s*{?%s*$")
|
||||
end
|
||||
|
||||
if not name then
|
||||
return nil, "No Go function signature found on current line"
|
||||
end
|
||||
|
||||
local doc = { "// " .. name .. " " }
|
||||
|
||||
-- add parameter hints if present
|
||||
if params and params:match("%S") then
|
||||
local param_names = {}
|
||||
for param in params:gmatch("([^,]+)") do
|
||||
-- Go params: name type or name, name2 type
|
||||
local pname = param:match("^%s*([%w_]+)")
|
||||
if pname then
|
||||
table.insert(param_names, pname)
|
||||
end
|
||||
end
|
||||
if #param_names > 0 then
|
||||
table.insert(doc, "//")
|
||||
table.insert(doc, "// Parameters:")
|
||||
for _, pname in ipairs(param_names) do
|
||||
table.insert(doc, "// - " .. pname .. ": ")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- add return hint if present
|
||||
ret = ret and ret:gsub("^%s*", ""):gsub("%s*$", "") or ""
|
||||
if ret ~= "" and ret ~= "error" then
|
||||
table.insert(doc, "//")
|
||||
table.insert(doc, "// Returns: ")
|
||||
end
|
||||
|
||||
return doc, nil
|
||||
end
|
||||
|
||||
-- Rust style: /// Description
|
||||
local function generate_rust_doc(bufnr, row, line)
|
||||
-- match: fn name(params) -> return or pub fn name...
|
||||
local name, params, ret = line:match("^%s*pub%s+fn%s+([%w_]+)%s*%((.-)%)%s*%->%s*(.-)%s*{?%s*$")
|
||||
if not name then
|
||||
name, params, ret = line:match("^%s*fn%s+([%w_]+)%s*%((.-)%)%s*%->%s*(.-)%s*{?%s*$")
|
||||
end
|
||||
if not name then
|
||||
name, params = line:match("^%s*pub%s+fn%s+([%w_]+)%s*%((.-)%)%s*{?%s*$")
|
||||
end
|
||||
if not name then
|
||||
name, params = line:match("^%s*fn%s+([%w_]+)%s*%((.-)%)%s*{?%s*$")
|
||||
end
|
||||
|
||||
if not name then
|
||||
return nil, "No Rust function signature found on current line"
|
||||
end
|
||||
|
||||
local doc = { "/// " }
|
||||
|
||||
-- add parameter hints if present
|
||||
if params and params:match("%S") then
|
||||
local param_names = {}
|
||||
for param in params:gmatch("([^,]+)") do
|
||||
local pname = param:match("^%s*([%w_]+)%s*:")
|
||||
if pname and pname ~= "self" and pname ~= "&self" and pname ~= "&mut" then
|
||||
table.insert(param_names, pname)
|
||||
end
|
||||
end
|
||||
if #param_names > 0 then
|
||||
table.insert(doc, "///")
|
||||
table.insert(doc, "/// # Arguments")
|
||||
table.insert(doc, "///")
|
||||
for _, pname in ipairs(param_names) do
|
||||
table.insert(doc, "/// * `" .. pname .. "` - ")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- add return hint if present
|
||||
ret = ret and ret:gsub("^%s*", ""):gsub("%s*$", "") or ""
|
||||
if ret ~= "" then
|
||||
table.insert(doc, "///")
|
||||
table.insert(doc, "/// # Returns")
|
||||
table.insert(doc, "///")
|
||||
table.insert(doc, "/// ")
|
||||
end
|
||||
|
||||
return doc, nil
|
||||
end
|
||||
|
||||
-- Python style: """docstring"""
|
||||
local function generate_python_doc(bufnr, row, line)
|
||||
local name, params = line:match("^%s*def%s+([%w_]+)%s*%((.-)%)%s*:?%s*$")
|
||||
if not name then
|
||||
name, params = line:match("^%s*async%s+def%s+([%w_]+)%s*%((.-)%)%s*:?%s*$")
|
||||
end
|
||||
|
||||
if not name then
|
||||
return nil, "No Python function signature found on current line"
|
||||
end
|
||||
|
||||
local indent = line:match("^(%s*)") or ""
|
||||
local doc = { indent .. ' """' }
|
||||
|
||||
-- parse parameters
|
||||
if params and params:match("%S") then
|
||||
local param_names = {}
|
||||
for param in params:gmatch("([^,]+)") do
|
||||
local pname = param:match("^%s*([%w_]+)")
|
||||
if pname and pname ~= "self" and pname ~= "cls" then
|
||||
table.insert(param_names, pname)
|
||||
end
|
||||
end
|
||||
if #param_names > 0 then
|
||||
table.insert(doc, indent .. "")
|
||||
table.insert(doc, indent .. " Args:")
|
||||
for _, pname in ipairs(param_names) do
|
||||
table.insert(doc, indent .. " " .. pname .. ": ")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(doc, indent .. "")
|
||||
table.insert(doc, indent .. " Returns:")
|
||||
table.insert(doc, indent .. " ")
|
||||
table.insert(doc, indent .. ' """')
|
||||
|
||||
return doc, nil
|
||||
end
|
||||
|
||||
-- filetype to generator mapping
|
||||
local generators = {
|
||||
c = generate_c_doc,
|
||||
cpp = generate_c_doc,
|
||||
h = generate_c_doc,
|
||||
go = generate_go_doc,
|
||||
rust = generate_rust_doc,
|
||||
python = generate_python_doc,
|
||||
}
|
||||
|
||||
function M.generate_doc()
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local line = vim.api.nvim_buf_get_lines(bufnr, row - 1, row, false)[1]
|
||||
local ft = vim.bo[bufnr].filetype
|
||||
|
||||
local generator = generators[ft]
|
||||
if not generator then
|
||||
vim.notify("No doc generator for filetype: " .. ft, vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
local doc, err = generator(bufnr, row, line)
|
||||
if err then
|
||||
vim.notify(err, vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
vim.api.nvim_buf_set_lines(bufnr, row - 1, row - 1, false, doc)
|
||||
|
||||
-- position cursor at first empty description spot
|
||||
local cursor_row = row
|
||||
local cursor_col = #doc[1]
|
||||
for i, docline in ipairs(doc) do
|
||||
if docline:match("%s$") or docline:match(":%s*$") or docline:match("%-%s*$") then
|
||||
cursor_row = row + i - 1
|
||||
cursor_col = #docline
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_win_set_cursor(0, { cursor_row, cursor_col })
|
||||
vim.cmd("startinsert!")
|
||||
end
|
||||
|
||||
vim.keymap.set("n", "<leader>dg", M.generate_doc)
|
||||
Reference in New Issue
Block a user