mirror of
https://github.com/lewis6991/gitsigns.nvim
synced 2025-02-20 22:47:23 +00:00
fix(attach): check cache status between async calls
This commit is contained in:
parent
bf6b0bbc52
commit
3885901f24
@ -362,7 +362,7 @@ local attach_throttled = throttle_by_id(function(cbuf, ctx, aucmd)
|
||||
})
|
||||
|
||||
-- Initial update
|
||||
manager.update(cbuf, cache[cbuf])
|
||||
manager.update(cbuf)
|
||||
end)
|
||||
|
||||
--- Detach Gitsigns from all buffers it is attached to.
|
||||
|
@ -41,10 +41,6 @@ function CacheEntry:get_compare_rev(base)
|
||||
return string.format(':%d', stage)
|
||||
end
|
||||
|
||||
function CacheEntry:get_staged_compare_rev()
|
||||
return self.commit and string.format('%s^', self.commit) or 'HEAD'
|
||||
end
|
||||
|
||||
function CacheEntry:get_rev_bufname(rev)
|
||||
rev = rev or self:get_compare_rev()
|
||||
return string.format('gitsigns://%s/%s:%s', self.git_obj.repo.gitdir, rev, self.git_obj.relpath)
|
||||
|
@ -7,39 +7,31 @@ local M = {}
|
||||
--- @generic F: function
|
||||
--- @param ms number Timeout in ms
|
||||
--- @param fn F Function to debounce
|
||||
--- @param hash? integer|fun(...): any Function that determines id from arguments to fn
|
||||
--- @return F Debounced function.
|
||||
function M.debounce_trailing(ms, fn)
|
||||
local timer = assert(uv.new_timer())
|
||||
function M.debounce_trailing(ms, fn, hash)
|
||||
local running = {} --- @type table<any,uv.uv_timer_t>
|
||||
if type(hash) == 'number' then
|
||||
local hash_i = hash
|
||||
hash = function(...)
|
||||
return select(hash_i, ...)
|
||||
end
|
||||
end
|
||||
return function(...)
|
||||
local id = hash and hash(...) or true
|
||||
if running[id] == nil then
|
||||
running[id] = assert(uv.new_timer())
|
||||
end
|
||||
local timer = running[id]
|
||||
local argv = { ... }
|
||||
timer:start(ms, 0, function()
|
||||
timer:stop()
|
||||
fn(unpack(argv))
|
||||
running[id] = nil
|
||||
fn(unpack(argv, 1, table.maxn(argv)))
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
--- Throttles a function on the leading edge.
|
||||
---
|
||||
--- @generic F: function
|
||||
--- @param ms number Timeout in ms
|
||||
--- @param fn F Function to throttle
|
||||
--- @return F throttled function.
|
||||
function M.throttle_leading(ms, fn)
|
||||
local timer = assert(uv.new_timer())
|
||||
local running = false
|
||||
return function(...)
|
||||
if not running then
|
||||
timer:start(ms, 0, function()
|
||||
running = false
|
||||
timer:stop()
|
||||
end)
|
||||
running = true
|
||||
fn(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Throttles a function using the first argument as an ID
|
||||
---
|
||||
--- If function is already running then the function will be scheduled to run
|
||||
|
@ -12,7 +12,6 @@ local throttle_by_id = require('gitsigns.debounce').throttle_by_id
|
||||
local log = require('gitsigns.debug.log')
|
||||
local dprint = log.dprint
|
||||
local dprintf = log.dprintf
|
||||
local eprint = log.eprint
|
||||
|
||||
local subprocess = require('gitsigns.subprocess')
|
||||
local util = require('gitsigns.util')
|
||||
@ -63,12 +62,13 @@ end
|
||||
--- @param top integer
|
||||
--- @param bot integer
|
||||
--- @param clear boolean
|
||||
--- @param untracked boolean
|
||||
local function apply_win_signs(bufnr, top, bot, clear, untracked)
|
||||
local function apply_win_signs(bufnr, top, bot, clear)
|
||||
local bcache = cache[bufnr]
|
||||
if not bcache then
|
||||
return
|
||||
end
|
||||
|
||||
local untracked = bcache.git_obj.object_name == nil
|
||||
apply_win_signs0(bufnr, signs_normal, bcache.hunks, top, bot, clear, untracked)
|
||||
if signs_staged then
|
||||
apply_win_signs0(bufnr, signs_staged, bcache.hunks_staged, top, bot, clear, false)
|
||||
@ -106,7 +106,7 @@ function M.on_lines(buf, first, last_orig, last_new)
|
||||
end
|
||||
end
|
||||
|
||||
M.update_debounced(buf, cache[buf])
|
||||
M.update_debounced(buf)
|
||||
end
|
||||
|
||||
local ns = api.nvim_create_namespace('gitsigns')
|
||||
@ -394,6 +394,24 @@ local function update_show_deleted(bufnr)
|
||||
end
|
||||
end
|
||||
|
||||
--- @param bufnr? integer
|
||||
--- @param cb function
|
||||
M.buf_check = async.wrap(function(bufnr, cb)
|
||||
vim.schedule(function()
|
||||
if bufnr then
|
||||
if not api.nvim_buf_is_valid(bufnr) then
|
||||
dprint('Buffer not valid, aborting')
|
||||
return
|
||||
end
|
||||
if not cache[bufnr] then
|
||||
dprint('Has detached, aborting')
|
||||
return
|
||||
end
|
||||
end
|
||||
cb()
|
||||
end)
|
||||
end, 2)
|
||||
|
||||
local update_cnt = 0
|
||||
|
||||
--- Ensure updates cannot be interleaved.
|
||||
@ -401,38 +419,36 @@ local update_cnt = 0
|
||||
--- whilst another one is in progress. If this happens then schedule another
|
||||
--- update after the current one has completed.
|
||||
--- @param bufnr integer
|
||||
--- @param bcache? Gitsigns.CacheEntry
|
||||
M.update = throttle_by_id(function(bufnr, bcache)
|
||||
M.update = throttle_by_id(function(bufnr)
|
||||
local __FUNC__ = 'update'
|
||||
bcache = bcache or cache[bufnr]
|
||||
if not bcache then
|
||||
eprint('Cache for buffer ' .. bufnr .. ' was nil')
|
||||
return
|
||||
end
|
||||
M.buf_check(bufnr)
|
||||
local bcache = cache[bufnr]
|
||||
local old_hunks, old_hunks_staged = bcache.hunks, bcache.hunks_staged
|
||||
bcache.hunks, bcache.hunks_staged = nil, nil
|
||||
|
||||
async.scheduler_if_buf_valid(bufnr)
|
||||
local buftext = util.buf_lines(bufnr)
|
||||
local git_obj = bcache.git_obj
|
||||
|
||||
if not bcache.compare_text or config._refresh_staged_on_update then
|
||||
bcache.compare_text = git_obj:get_show_text(bcache:get_compare_rev())
|
||||
async.scheduler_if_buf_valid(bufnr)
|
||||
M.buf_check(bufnr)
|
||||
end
|
||||
|
||||
local buftext = util.buf_lines(bufnr)
|
||||
|
||||
bcache.hunks = run_diff(bcache.compare_text, buftext)
|
||||
M.buf_check(bufnr)
|
||||
|
||||
if config._signs_staged_enable then
|
||||
if not bcache.compare_text_head or config._refresh_staged_on_update then
|
||||
bcache.compare_text_head = git_obj:get_show_text(bcache:get_staged_compare_rev())
|
||||
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)
|
||||
end
|
||||
local hunks_head = run_diff(bcache.compare_text_head, buftext)
|
||||
M.buf_check(bufnr)
|
||||
bcache.hunks_staged = gs_hunks.filter_common(hunks_head, bcache.hunks)
|
||||
end
|
||||
|
||||
async.scheduler_if_buf_valid(bufnr)
|
||||
|
||||
-- Note the decoration provider may have invalidated bcache.hunks at this
|
||||
-- point
|
||||
if
|
||||
@ -442,7 +458,7 @@ M.update = throttle_by_id(function(bufnr, bcache)
|
||||
then
|
||||
-- Apply signs to the window. Other signs will be added by the decoration
|
||||
-- provider as they are drawn.
|
||||
apply_win_signs(bufnr, vim.fn.line('w0'), vim.fn.line('w$'), true, git_obj.object_name == nil)
|
||||
apply_win_signs(bufnr, vim.fn.line('w0'), vim.fn.line('w$'), true)
|
||||
|
||||
update_show_deleted(bufnr)
|
||||
bcache.force_next_update = false
|
||||
@ -497,9 +513,7 @@ local function on_win(_cb, _winid, bufnr, topline, botline_guess)
|
||||
end
|
||||
local botline = math.min(botline_guess, api.nvim_buf_line_count(bufnr))
|
||||
|
||||
local untracked = bcache.git_obj.object_name == nil
|
||||
|
||||
apply_win_signs(bufnr, topline + 1, botline + 1, false, untracked)
|
||||
apply_win_signs(bufnr, topline + 1, botline + 1, false)
|
||||
|
||||
if not (config.word_diff and config.diff_opts.internal) then
|
||||
return false
|
||||
|
@ -9,28 +9,13 @@ local util = require('gitsigns.util')
|
||||
local cache = require('gitsigns.cache').cache
|
||||
local config = require('gitsigns.config').config
|
||||
local debounce_trailing = require('gitsigns.debounce').debounce_trailing
|
||||
local manager = require('gitsigns.manager')
|
||||
|
||||
local buf_check = manager.buf_check
|
||||
|
||||
local dprint = log.dprint
|
||||
local dprintf = log.dprintf
|
||||
|
||||
--- @param bufnr? integer
|
||||
--- @param cb function
|
||||
local buf_check = async.wrap(function(bufnr, cb)
|
||||
vim.schedule(function()
|
||||
if bufnr then
|
||||
if not api.nvim_buf_is_valid(bufnr) then
|
||||
dprint('Buffer not valid, aborting')
|
||||
return
|
||||
end
|
||||
if not cache[bufnr] then
|
||||
dprint('Has detached, aborting')
|
||||
return
|
||||
end
|
||||
end
|
||||
cb()
|
||||
end)
|
||||
end, 2)
|
||||
|
||||
--- @param bufnr integer
|
||||
--- @param old_relpath string
|
||||
local function handle_moved(bufnr, old_relpath)
|
||||
@ -74,7 +59,9 @@ local function handle_moved(bufnr, old_relpath)
|
||||
dprintf('%s buffer %d from %s to %s', msg, bufnr, old_name, bcache.file)
|
||||
end
|
||||
|
||||
local watch_gitdir_handler = async.void(function(bufnr)
|
||||
--- @param bufnr integer
|
||||
local handler = debounce_trailing(200, async.void(function(bufnr)
|
||||
local __FUNC__ = 'watcher_handler'
|
||||
buf_check(bufnr)
|
||||
|
||||
local git_obj = cache[bufnr].git_obj
|
||||
@ -100,8 +87,8 @@ local watch_gitdir_handler = async.void(function(bufnr)
|
||||
|
||||
cache[bufnr]:invalidate()
|
||||
|
||||
require('gitsigns.manager').update(bufnr, cache[bufnr])
|
||||
end)
|
||||
require('gitsigns.manager').update(bufnr)
|
||||
end), 1)
|
||||
|
||||
-- vim.inspect but on one line
|
||||
--- @param x any
|
||||
@ -112,14 +99,15 @@ end
|
||||
|
||||
local M = {}
|
||||
|
||||
local WATCH_IGNORE = {
|
||||
ORIG_HEAD = true,
|
||||
FETCH_HEAD = true
|
||||
}
|
||||
|
||||
--- @param bufnr integer
|
||||
--- @param gitdir string
|
||||
--- @return uv.uv_fs_event_t
|
||||
function M.watch_gitdir(bufnr, gitdir)
|
||||
-- Setup debounce as we create the luv object so the debounce is independent
|
||||
-- to each watcher
|
||||
local watch_gitdir_handler_db = debounce_trailing(200, watch_gitdir_handler)
|
||||
|
||||
dprintf('Watching git dir')
|
||||
local w = assert(uv.new_fs_event())
|
||||
w:start(gitdir, {}, function(err, filename, events)
|
||||
@ -134,14 +122,14 @@ function M.watch_gitdir(bufnr, gitdir)
|
||||
-- The luv docs say filename is passed as a string but it has been observed
|
||||
-- to sometimes be nil.
|
||||
-- https://github.com/lewis6991/gitsigns.nvim/issues/848
|
||||
if filename == nil or vim.endswith(filename, '.lock') then
|
||||
if filename == nil or WATCH_IGNORE[filename] or vim.endswith(filename, '.lock') then
|
||||
dprintf('%s (ignoring)', info)
|
||||
return
|
||||
end
|
||||
|
||||
dprint(info)
|
||||
|
||||
watch_gitdir_handler_db(bufnr)
|
||||
handler(bufnr)
|
||||
end)
|
||||
return w
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user