From 24ec1e3bb55573a6fa9b10a1b16d23e93959feec Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 12 Sep 2023 10:41:16 +0100 Subject: [PATCH] fix(blame): do not run concurrent processes Fixes #877 --- lua/gitsigns/current_line_blame.lua | 77 ++++++++++++++++------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/lua/gitsigns/current_line_blame.lua b/lua/gitsigns/current_line_blame.lua index 617cd825..6f9797a8 100644 --- a/lua/gitsigns/current_line_blame.lua +++ b/lua/gitsigns/current_line_blame.lua @@ -2,20 +2,16 @@ local async = require('gitsigns.async') local cache = require('gitsigns.cache').cache local config = require('gitsigns.config').config local util = require('gitsigns.util') -local uv = vim.loop local api = vim.api local current_buf = api.nvim_get_current_buf +local debounce = require('gitsigns.debounce') local namespace = api.nvim_create_namespace('gitsigns_blame') -local timer = assert(uv.new_timer()) - local M = {} -local wait_timer = async.wrap(uv.timer_start, 4) - --- @param bufnr integer --- @param row integer --- @param opts? table @@ -143,10 +139,7 @@ end --- @param blame_info Gitsigns.BlameInfo --- @param opts Gitsigns.CurrentLineBlameOpts local function handle_blame_info(bufnr, lnum, blame_info, opts) - local bcache = cache[bufnr] - if not bcache then - return - end + local bcache = assert(cache[bufnr]) local virt_text ---@type {[1]: string, [2]: string}[] local clb_formatter = blame_info.author == 'Not Committed Yet' and config.current_line_blame_formatter_nc @@ -178,15 +171,35 @@ local function handle_blame_info(bufnr, lnum, blame_info, opts) end end +--- @param winid integer --- @return integer lnum -local function get_lnum() - return api.nvim_win_get_cursor(0)[1] +local function get_lnum(winid) + return api.nvim_win_get_cursor(winid)[1] end --- Update function, must be called in async context -local function update0() - local bufnr = current_buf() - local lnum = get_lnum() +--- @param winid integer +--- @param lnum integer +--- @return boolean +local function foldclosed(winid, lnum) + ---@return boolean + return api.nvim_win_call(winid, function() + return vim.fn.foldclosed(lnum) ~= -1 + end) +end + +-- local function fold_closed(winid + +--- Update function, must be called in async context +--- @param bufnr integer +local function update0(bufnr) + async.scheduler_if_buf_valid(bufnr) + + local winid = vim.fn.bufwinid(bufnr) + if winid == -1 then + return + end + + local lnum = get_lnum(winid) local old_lnum = get_extmark(bufnr) if old_lnum and lnum == old_lnum and BlameCache:get(bufnr, lnum) then @@ -209,32 +222,20 @@ local function update0() end -- Can't show extmarks on folded lines so skip - if vim.fn.foldclosed(lnum) ~= -1 then + if foldclosed(winid, lnum) then return end - local opts = config.current_line_blame_opts - - -- Note because the same timer is re-used, this call has a debouncing effect. - wait_timer(timer, opts.delay, 0) - async.scheduler() - local bcache = cache[bufnr] if not bcache or not bcache.git_obj.object_name then return end + local opts = config.current_line_blame_opts + local blame_info = run_blame(bufnr, lnum, opts) async.scheduler_if_buf_valid(bufnr) - local lnum1 = get_lnum() - if bufnr == current_buf() and lnum ~= lnum1 then - -- Cursor has moved during events; abort and tr-trigger another update - -- since it's likely blame jobs where skipped - update0() - return - end - vim.b[bufnr].gitsigns_blame_line_dict = blame_info if blame_info then @@ -242,11 +243,17 @@ local function update0() end end -local update = async.void(update0) +local update = async.void(debounce.throttle_by_id(update0)) + +--- @type fun(bufnr: integer) +local update_debounced function M.setup() local group = api.nvim_create_augroup('gitsigns_blame', {}) + local opts = config.current_line_blame_opts + update_debounced = debounce.debounce_trailing(opts.delay, update) + for k, _ in pairs(cache) do reset(k) end @@ -254,7 +261,9 @@ function M.setup() if config.current_line_blame then api.nvim_create_autocmd({ 'FocusGained', 'BufEnter', 'CursorMoved', 'CursorMovedI' }, { group = group, - callback = update, + callback = function(args) + update_debounced(args.buf) + end }) api.nvim_create_autocmd({ 'InsertEnter', 'FocusLost', 'BufLeave' }, { @@ -266,7 +275,9 @@ function M.setup() -- Call via vim.schedule to avoid the debounce timer killing the async -- coroutine - vim.schedule(update) + vim.schedule(function() + update_debounced(api.nvim_get_current_buf()) + end) end end