branch todos

This commit is contained in:
Kacper Marzecki 2026-08-04 18:57:16 +02:00
parent 8b32f22c49
commit b8e0dee953
2 changed files with 224 additions and 0 deletions

View File

@ -143,6 +143,225 @@ end
-- Keybind for inserting TODO comment -- Keybind for inserting TODO comment
vim.api.nvim_set_keymap("n", "<leader>t", "<cmd>lua insert_todo_comment()<CR>", { noremap = true, silent = true }) vim.api.nvim_set_keymap("n", "<leader>t", "<cmd>lua insert_todo_comment()<CR>", { noremap = true, silent = true })
local function git_output(args)
local output = vim.fn.system(args)
if vim.v.shell_error ~= 0 then
return nil
end
return vim.split(output, "\n", { trimempty = true })
end
local function branch_todos_base()
if vim.g.branch_todos_base then
return vim.g.branch_todos_base
end
for _, ref in ipairs({ "origin/main", "origin/master", "main", "master" }) do
if git_output({ "git", "rev-parse", "--verify", ref }) then
return ref
end
end
end
local function branch_todos_entries()
local base = branch_todos_base()
if not base then
return { "No git base found. Set vim.g.branch_todos_base." }
end
local merge_base = git_output({ "git", "merge-base", base, "HEAD" })
if not merge_base or not merge_base[1] then
return { "Could not find merge-base against " .. base .. "." }
end
local lines = git_output({ "git", "diff", "--unified=0", merge_base[1] })
if not lines then
return { "Could not read git diff against " .. base .. "." }
end
local added_lines = {}
local file
local new_line
local todo_keywords = { "TODO", "FIXME", "HACK", "XXX", "BUG", "BUGS" }
for _, line in ipairs(lines) do
local diff_file = line:match("^%+%+%+ b/(.+)$")
if diff_file then
file = diff_file
new_line = nil
else
local hunk_start = line:match("^@@ %-%d+,?%d* %+(%d+),?%d* @@")
if hunk_start then
new_line = tonumber(hunk_start)
elseif new_line and line:sub(1, 1) == "+" and not line:match("^%+%+%+") then
local text = line:sub(2)
if file then
table.insert(added_lines, { file = file, line = new_line, text = text })
end
new_line = new_line + 1
elseif new_line and line:sub(1, 1) ~= "-" then
new_line = new_line + 1
end
end
end
local function has_todo_keyword(text)
local upper_text = text:upper()
for _, keyword in ipairs(todo_keywords) do
local start = 1
while true do
local match_start, match_end = upper_text:find(keyword, start, true)
if not match_start then
break
end
local before = match_start > 1 and upper_text:sub(match_start - 1, match_start - 1) or ""
local after = match_end < #upper_text and upper_text:sub(match_end + 1, match_end + 1) or ""
if not before:match("[%w_]") and not after:match("[%w_]") then
return true
end
start = match_end + 1
end
end
return false
end
local function list_depth_delta(text)
local _, opens = text:gsub("%[", "")
local _, closes = text:gsub("%]", "")
return opens - closes
end
local entries = {}
local index = 1
while index <= #added_lines do
local item = added_lines[index]
if has_todo_keyword(item.text) then
table.insert(entries, string.format("%s:%d", item.file, item.line))
table.insert(entries, item.text)
if item.text:lower():match('todo:%s*"""') and not item.text:match('""".*"""') then
index = index + 1
while index <= #added_lines do
local next_item = added_lines[index]
if next_item.file ~= item.file then
break
end
table.insert(entries, next_item.text)
if next_item.text:find('"""', 1, true) then
break
end
index = index + 1
end
elseif item.text:match("[=:]%s*%[") and list_depth_delta(item.text) > 0 then
local depth = list_depth_delta(item.text)
index = index + 1
while index <= #added_lines do
local next_item = added_lines[index]
if next_item.file ~= item.file then
break
end
table.insert(entries, next_item.text)
depth = depth + list_depth_delta(next_item.text)
if depth <= 0 then
break
end
index = index + 1
end
elseif item.text:match("^%s*#") then
index = index + 1
while index <= #added_lines do
local next_item = added_lines[index]
if next_item.file ~= item.file or not next_item.text:match("^%s*#") then
break
end
table.insert(entries, next_item.text)
index = index + 1
end
index = index - 1
end
table.insert(entries, "")
end
index = index + 1
end
if #entries == 0 then
return { "No TODOs added on this branch against " .. base .. "." }
end
return entries
end
local function jump_to_branch_todo()
local line = vim.api.nvim_get_current_line()
local file, linenum = line:match("([^:%s]+):(%d+)")
if not file then
local cursor = vim.api.nvim_win_get_cursor(0)
for row = cursor[1] - 1, 1, -1 do
local previous_line = vim.api.nvim_buf_get_lines(0, row - 1, row, false)[1] or ""
file, linenum = previous_line:match("([^:%s]+):(%d+)")
if file then
break
end
end
end
if file and linenum then
local current_win = vim.api.nvim_get_current_win()
vim.cmd("wincmd h")
if current_win == vim.api.nvim_get_current_win() then
vim.api.nvim_set_current_win(current_win)
end
vim.cmd("edit " .. vim.fn.fnameescape(file))
vim.api.nvim_win_set_cursor(0, { tonumber(linenum), 0 })
if vim.api.nvim_win_is_valid(current_win) and current_win ~= vim.api.nvim_get_current_win() then
vim.api.nvim_set_current_win(current_win)
end
end
end
local function refresh_branch_todos(buf)
local cursor = vim.api.nvim_win_get_cursor(0)
vim.bo[buf].modifiable = true
vim.api.nvim_buf_set_lines(buf, 0, -1, false, branch_todos_entries())
vim.bo[buf].modifiable = false
local line_count = vim.api.nvim_buf_line_count(buf)
vim.api.nvim_win_set_cursor(0, { math.min(cursor[1], line_count), cursor[2] })
end
local function open_branch_todos()
local name = "branch-todos"
local buf = vim.fn.bufnr(name)
if buf == -1 then
buf = vim.api.nvim_create_buf(true, false)
vim.api.nvim_buf_set_name(buf, name)
end
vim.api.nvim_set_current_buf(buf)
vim.bo[buf].buftype = "nofile"
vim.bo[buf].bufhidden = "hide"
vim.bo[buf].swapfile = false
vim.bo[buf].filetype = "branch-todos"
refresh_branch_todos(buf)
vim.keymap.set("n", "<CR>", jump_to_branch_todo, { buffer = buf, desc = "Jump to branch TODO" })
vim.keymap.set("n", "r", function()
refresh_branch_todos(buf)
end, { buffer = buf, desc = "Refresh branch TODOs" })
vim.keymap.set("n", "q", "<cmd>bdelete<CR>", { buffer = buf, desc = "Close branch TODOs" })
end
vim.api.nvim_create_user_command("BranchTodos", open_branch_todos, {})
vim.keymap.set("n", "<leader>xb", open_branch_todos, { desc = "Branch TODOs" })
-- floating NOTES -- floating NOTES
function open_notes() function open_notes()
local notes_file = vim.env.HOME .. "/git/notes/todo.md" -- Path to your notes file local notes_file = vim.env.HOME .. "/git/notes/todo.md" -- Path to your notes file

View File

@ -130,6 +130,11 @@ vim.api.nvim_create_autocmd("FileType", {
return return
end end
local rg = vim.system({ "rg", "-q", "--glob", "*.ex", "use ExOf", root }):wait()
if rg.code ~= 0 then
return
end
vim.lsp.start({ vim.lsp.start({
name = "exofx-lsp", name = "exofx-lsp",
cmd_env = { MIX_ENV = "test" }, cmd_env = { MIX_ENV = "test" },