Created
November 20, 2025 16:45
-
-
Save lopesivan/84f1bc6336e9bbbc49ca6860c9b864d9 to your computer and use it in GitHub Desktop.
javadoc com treesitter para C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- 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" }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- 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