From 6e05045fb1a4845fe44f5c54aafe024444c422ba Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Sun, 10 Dec 2023 09:28:46 -0500 Subject: [PATCH] fix(manager): manager.update() never resolve when buf_check() fails Problem: If `buf_check(...)` fails (mostly when cache is outdated), it would abort updating gitsigns, but this actually leads to the coroutine never resolving and stuck forever. It is because the asynchronous callback `cb()` is never called. As a result, gitsigns might be stuck forever and fail to update silently (see #924), and manual reattach or refresh also doesn't work, because of the unresolved coroutine that is recognized to be "still running", i.e., any subsequent calls to "throttled" `manager.update()` will not be executed. Solution: Make `buf_check()` always yield a value (true/false) to ensure that `manager.update()` will resolve and finish its execution after all. --- lua/gitsigns/manager.lua | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lua/gitsigns/manager.lua b/lua/gitsigns/manager.lua index 12912b667..b5531b978 100644 --- a/lua/gitsigns/manager.lua +++ b/lua/gitsigns/manager.lua @@ -430,24 +430,24 @@ end --- @param bufnr? integer --- @param check_compare_text? boolean ---- @param cb function +--- @param cb fun(boolean) M.buf_check = async.wrap(function(bufnr, check_compare_text, cb) vim.schedule(function() if bufnr then if not api.nvim_buf_is_valid(bufnr) then dprint('Buffer not valid, aborting') - return + return cb(false) end if not cache[bufnr] then dprint('Has detached, aborting') - return + return cb(false) end if check_compare_text and not cache[bufnr].compare_text then dprint('compare_text was invalid, aborting') - return + return cb(false) end end - cb() + cb(true) end) end, 3) @@ -460,7 +460,9 @@ local update_cnt = 0 --- @param bufnr integer M.update = throttle_by_id(function(bufnr) local __FUNC__ = 'update' - M.buf_check(bufnr) + if not M.buf_check(bufnr) then + return + end local bcache = cache[bufnr] local old_hunks, old_hunks_staged = bcache.hunks, bcache.hunks_staged bcache.hunks, bcache.hunks_staged = nil, nil @@ -473,22 +475,30 @@ M.update = throttle_by_id(function(bufnr) if not bcache.compare_text or config._refresh_staged_on_update or file_mode then bcache.compare_text = git_obj:get_show_text(compare_rev) - M.buf_check(bufnr, true) + if not M.buf_check(bufnr, true) then + return + end end local buftext = util.buf_lines(bufnr) bcache.hunks = run_diff(bcache.compare_text, buftext) - M.buf_check(bufnr) + if not M.buf_check(bufnr) then + return + end if config._signs_staged_enable and not file_mode then if not bcache.compare_text_head or config._refresh_staged_on_update then local staged_compare_rev = bcache.commit and string.format('%s^', bcache.commit) or 'HEAD' bcache.compare_text_head = git_obj:get_show_text(staged_compare_rev) - M.buf_check(bufnr, true) + if not M.buf_check(bufnr, true) then + return + end end local hunks_head = run_diff(bcache.compare_text_head, buftext) - M.buf_check(bufnr) + if not M.buf_check(bufnr) then + return + end bcache.hunks_staged = gs_hunks.filter_common(hunks_head, bcache.hunks) end