Skip to content

Instantly share code, notes, and snippets.

@lopesivan
Created November 20, 2025 16:45
Show Gist options
  • Select an option

  • Save lopesivan/84f1bc6336e9bbbc49ca6860c9b864d9 to your computer and use it in GitHub Desktop.

Select an option

Save lopesivan/84f1bc6336e9bbbc49ca6860c9b864d9 to your computer and use it in GitHub Desktop.
javadoc com treesitter para C
-- after/ftplugin/c.lua
vim.keymap.set("n", "<F2>", function()
require("config.ts_c").insert_doc_for_current_function()
end, { desc = "Inserir Javadoc na função C atual" })
-- lua/config/ts_c.lua
--
local M = {}
local ts = vim.treesitter
local function node_text(node, bufnr)
return vim.treesitter.get_node_text(node, bufnr)
end
local function node_at_cursor(bufnr)
local win = vim.api.nvim_get_current_win()
local row, col = unpack(vim.api.nvim_win_get_cursor(win))
row = row - 1
local parser = ts.get_parser(bufnr, "c")
local tree = parser:parse()[1]
local root = tree:root()
return root:named_descendant_for_range(row, col, row, col)
end
local function ascend_function(node)
while node and node:type() ~= "function_definition" do
node = node:parent()
end
return node
end
--- Retorna informações sobre a função C na qual o cursor está:
--- nome, tipo de retorno, parâmetros e o nó function_definition.
local function get_current_function_info(bufnr)
bufnr = bufnr or vim.api.nvim_get_current_buf()
if vim.bo[bufnr].filetype ~= "c" then
vim.notify("Buffer atual não é C", vim.log.levels.WARN)
return nil
end
local node = node_at_cursor(bufnr)
local fdef = node and ascend_function(node)
if not fdef then
vim.notify("Cursor não está dentro de uma function_definition", vim.log.levels.WARN)
return nil
end
----------------------------------------------------------------
-- 1) Tipo de retorno (tipo base)
----------------------------------------------------------------
local type_node = fdef:field("type")[1]
local return_type = type_node and node_text(type_node, bufnr) or "void"
----------------------------------------------------------------
-- 2) declarator → function_declarator
----------------------------------------------------------------
local decl = fdef:field("declarator")[1]
if not decl then
vim.notify("Sem declarator no function_definition", vim.log.levels.WARN)
return nil
end
----------------------------------------------------------------
-- 2.1) Contar ponteiros no caminho até o function_declarator
-- Ex.: int *f(void);
-- function_definition
-- type: primitive_type(int)
-- declarator: pointer_declarator
-- "*"
-- declarator: function_declarator(...)
----------------------------------------------------------------
do
local walk = decl
local stars = 0
while walk and walk:type() ~= "function_declarator" do
if walk:type() == "pointer_declarator" then
stars = stars + 1
end
walk = walk:field("declarator")[1]
end
if stars > 0 then
-- você pode ajustar o espaço se preferir "int*" em vez de "int *"
return_type = return_type .. " " .. string.rep("*", stars)
end
end
----------------------------------------------------------------
-- 2.2) Agora sim achar o function_declarator (como você já fazia)
----------------------------------------------------------------
local func_decl = decl
while func_decl and func_decl:type() ~= "function_declarator" do
local inner = func_decl:field("declarator")[1]
func_decl = inner
end
if not func_decl then
vim.notify("Sem function_declarator aninhado", vim.log.levels.WARN)
return nil
end
-- 3) Nome da função
local name_node = func_decl:field("declarator")[1]
local func_name = name_node and node_text(name_node, bufnr) or "<anon>"
-- 4) Parâmetros
local params_node = func_decl:field("parameters")[1]
local params = {}
if params_node then
for child in params_node:iter_children() do
if child:type() == "parameter_declaration" then
table.insert(params, node_text(child, bufnr))
end
end
end
return {
name = func_name,
return_type = return_type,
params = params,
node = fdef,
bufnr = bufnr,
}
end
-- Extrai o nome do parâmetro a partir do texto completo "tipo nome"
-- Ex.: "int x" -> "x"
-- "char *msg" -> "msg"
-- "struct foo a" -> "a"
local function extract_param_name(param_text)
-- pega a última "palavra" formada por [a-zA-Z0-9_]
local name = param_text:match("([%w_]+)%s*$")
return name or param_text
end
--- Insere um comentário em estilo Javadoc/Doxygen acima da função C atual.
--- Usa as informações de Tree-sitter (tipo, nome, parâmetros) para gerar o texto.
function M.insert_doc_for_current_function(bufnr)
local info = get_current_function_info(bufnr)
if not info then
return
end
local fdef = info.node
local start_row = fdef:range() -- start_row, start_col, end_row, end_col
local params = info.params or {}
-- Monta a assinatura bonitinha: retorno nome(args...)
local signature = info.return_type .. " " .. info.name .. "(" .. table.concat(params, ", ") .. ")"
local lines = {}
table.insert(lines, "/**")
table.insert(lines, " * @brief Descrição da função " .. info.name .. ".")
table.insert(lines, " *")
table.insert(lines, " * Esta função foi documentada automaticamente por um módulo Lua no Neovim,")
table.insert(lines, " * usando Tree-sitter para extrair o tipo de retorno, nome e parâmetros.")
table.insert(lines, " *")
table.insert(lines, " * Assinatura:")
table.insert(lines, " * " .. signature .. ";")
if #params > 0 then
table.insert(lines, " *")
table.insert(lines, " * Parâmetros:")
for _, p in ipairs(params) do
local pname = extract_param_name(p)
table.insert(lines, " * @param " .. pname .. ": " .. p:match("^(.*)%s+%S+$"))
end
end
table.insert(lines, " *")
table.insert(lines, " * @return " .. info.return_type .. " Valor de retorno da função.")
table.insert(lines, " */")
-- Insere o comentário acima da função
vim.api.nvim_buf_set_lines(info.bufnr, start_row, start_row, false, lines)
vim.notify("Comentário Javadoc inserido para função " .. info.name, vim.log.levels.INFO)
end
return M
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment