From ea59bbae964229c3eaf974afabf0a2df297e167f Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Thu, 12 Mar 2026 20:19:18 -0400 Subject: [PATCH] fix(init): preserve cursor column and position in mutation functions (#152) Problem: `toggle_complete()`, `toggle_priority()`, `adjust_priority()`, `toggle_status()`, and `move_task()` captured only the row from `nvim_win_get_cursor` and restored the cursor to column 0 after re-render. Additionally, `toggle_complete()` followed the toggled task to its new sorted position at the bottom of the category, which is disorienting when working through a list of tasks. Solution: Capture both row and column from the cursor, and restore the column in all five functions. For `toggle_complete()`, instead of chasing the task ID after render, clamp the cursor to the original row (or total lines if shorter) and advance to the nearest task line, similar to the `]t` motion in `textobj.lua`. --- lua/pending/init.lua | 45 +++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/lua/pending/init.lua b/lua/pending/init.lua index fe8fd6f..e21320d 100644 --- a/lua/pending/init.lua +++ b/lua/pending/init.lua @@ -544,7 +544,8 @@ function M.toggle_complete() if not require_saved() then return end - local row = vim.api.nvim_win_get_cursor(0)[1] + local cursor = vim.api.nvim_win_get_cursor(0) + local row, col = cursor[1], cursor[2] local meta = buffer.meta() if not meta[row] or meta[row].type ~= 'task' then return @@ -578,11 +579,25 @@ function M.toggle_complete() end _save_and_notify() buffer.render(bufnr) - for lnum, m in ipairs(buffer.meta()) do - if m.id == id then - vim.api.nvim_win_set_cursor(0, { lnum, 0 }) - break + local new_meta = buffer.meta() + local total = #new_meta + local target = math.min(row, total) + if new_meta[target] and new_meta[target].type == 'task' then + vim.api.nvim_win_set_cursor(0, { target, col }) + else + for r = target, total do + if new_meta[r] and new_meta[r].type == 'task' then + vim.api.nvim_win_set_cursor(0, { r, col }) + return + end end + for r = target, 1, -1 do + if new_meta[r] and new_meta[r].type == 'task' then + vim.api.nvim_win_set_cursor(0, { r, col }) + return + end + end + vim.api.nvim_win_set_cursor(0, { target, col }) end end @@ -654,7 +669,8 @@ function M.toggle_priority() if not require_saved() then return end - local row = vim.api.nvim_win_get_cursor(0)[1] + local cursor = vim.api.nvim_win_get_cursor(0) + local row, col = cursor[1], cursor[2] local meta = buffer.meta() if not meta[row] or meta[row].type ~= 'task' then return @@ -675,7 +691,7 @@ function M.toggle_priority() buffer.render(bufnr) for lnum, m in ipairs(buffer.meta()) do if m.id == id then - vim.api.nvim_win_set_cursor(0, { lnum, 0 }) + vim.api.nvim_win_set_cursor(0, { lnum, col }) break end end @@ -691,7 +707,8 @@ local function adjust_priority(delta) if not require_saved() then return end - local row = vim.api.nvim_win_get_cursor(0)[1] + local cursor = vim.api.nvim_win_get_cursor(0) + local row, col = cursor[1], cursor[2] local meta = buffer.meta() if not meta[row] or meta[row].type ~= 'task' then return @@ -715,7 +732,7 @@ local function adjust_priority(delta) buffer.render(bufnr) for lnum, m in ipairs(buffer.meta()) do if m.id == id then - vim.api.nvim_win_set_cursor(0, { lnum, 0 }) + vim.api.nvim_win_set_cursor(0, { lnum, col }) break end end @@ -829,7 +846,8 @@ function M.toggle_status(target_status) if not require_saved() then return end - local row = vim.api.nvim_win_get_cursor(0)[1] + local cursor = vim.api.nvim_win_get_cursor(0) + local row, col = cursor[1], cursor[2] local meta = buffer.meta() if not meta[row] or meta[row].type ~= 'task' then return @@ -852,7 +870,7 @@ function M.toggle_status(target_status) buffer.render(bufnr) for lnum, m in ipairs(buffer.meta()) do if m.id == id then - vim.api.nvim_win_set_cursor(0, { lnum, 0 }) + vim.api.nvim_win_set_cursor(0, { lnum, col }) break end end @@ -868,7 +886,8 @@ function M.move_task(direction) if not require_saved() then return end - local row = vim.api.nvim_win_get_cursor(0)[1] + local cursor = vim.api.nvim_win_get_cursor(0) + local row, col = cursor[1], cursor[2] local meta = buffer.meta() if not meta[row] or meta[row].type ~= 'task' then return @@ -943,7 +962,7 @@ function M.move_task(direction) for lnum, m in ipairs(buffer.meta()) do if m.id == id then - vim.api.nvim_win_set_cursor(0, { lnum, 0 }) + vim.api.nvim_win_set_cursor(0, { lnum, col }) break end end