fix(update): Fix updates from being dropped

Fixes #264
This commit is contained in:
Lewis Russell 2021-11-16 15:56:09 +00:00
parent bfc4543262
commit 3cf3c03cf8
4 changed files with 79 additions and 43 deletions

View File

@ -37,4 +37,39 @@ function M.throttle_leading(ms, fn)
end
end
function M.throttle_by_id(fn)
local scheduled = {}
local running = {}
return function(id, ...)
if scheduled[id] then
return
end
scheduled[id] = true
if running[id] then
return
end
while scheduled[id] do
scheduled[id] = nil
running[id] = true
fn(id, ...)
running[id] = nil
end
end
end
return M

View File

@ -1,6 +1,5 @@
local void = require('plenary.async.async').void
local async_util = require('plenary.async.util')
local scheduler = async_util.scheduler
local scheduler = require('plenary.async.util').scheduler
local gs_cache = require('gitsigns.cache')
local CacheEntry = gs_cache.CacheEntry
@ -12,6 +11,7 @@ local Sign = signs.Sign
local Status = require("gitsigns.status")
local debounce_trailing = require('gitsigns.debounce').debounce_trailing
local throttle_by_id = require('gitsigns.debounce').throttle_by_id
local gs_debug = require("gitsigns.debug")
local dprint = gs_debug.dprint
local dprintf = gs_debug.dprintf
@ -215,6 +215,7 @@ end
local update_cnt = 0
local update0 = function(bufnr, bcache)
local __FUNC__ = 'update'
bcache = bcache or cache[bufnr]
if not bcache then
eprint('Cache for buffer ' .. bufnr .. ' was nil')
@ -266,26 +267,8 @@ end
do
local running = false
local scheduled = {}
M.update = function(bufnr, bcache)
scheduled[bufnr] = true
if not running then
running = true
while scheduled[bufnr] do
scheduled[bufnr] = nil
update0(bufnr, bcache)
end
running = false
else
while running do
async_util.sleep(100)
end
end
end
end
M.update = throttle_by_id(update0)
M.setup = function()
M.update_debounced = debounce_trailing(config.update_debounce, void(M.update))

View File

@ -37,4 +37,39 @@ function M.throttle_leading(ms: number, fn: function): function
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
--- again once the running call has finished.
---
--- fn#1 _/‾\__/‾\_/‾\_____________________________
--- throttled#1 _/‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\/‾‾‾‾‾‾‾‾‾‾\____________
--
--- fn#2 ______/‾\___________/‾\___________________
--- throttled#2 ______/‾‾‾‾‾‾‾‾‾‾\__/‾‾‾‾‾‾‾‾‾‾\__________
---
--
--@param fn (function) Function to throttle
--@returns (function) throttled function.
function M.throttle_by_id(fn: function): function
local scheduled: {any:boolean} = {}
local running: {any:boolean} = {}
return function(id: any, ...)
if scheduled[id] then
-- If fn is already scheduled, then drop
return
end
scheduled[id] = true
if running[id] then
return
end
while scheduled[id] do
scheduled[id] = nil
running[id] = true
fn(id, ...)
running[id] = nil
end
end
end
return M

View File

@ -1,6 +1,5 @@
local void = require('plenary.async.async').void
local async_util = require('plenary.async.util')
local scheduler = async_util.scheduler
local scheduler = require('plenary.async.util').scheduler
local gs_cache = require('gitsigns.cache')
local CacheEntry = gs_cache.CacheEntry
@ -12,6 +11,7 @@ local Sign = signs.Sign
local Status = require("gitsigns.status")
local debounce_trailing = require('gitsigns.debounce').debounce_trailing
local throttle_by_id = require('gitsigns.debounce').throttle_by_id
local gs_debug = require("gitsigns.debug")
local dprint = gs_debug.dprint
local dprintf = gs_debug.dprintf
@ -215,6 +215,7 @@ end
local update_cnt = 0
local update0 = function(bufnr: integer, bcache: CacheEntry)
local __FUNC__ = 'update'
bcache = bcache or cache[bufnr]
if not bcache then
eprint('Cache for buffer '..bufnr..' was nil')
@ -262,30 +263,12 @@ local update0 = function(bufnr: integer, bcache: CacheEntry)
dprintf('updates: %s, jobs: %s', update_cnt, subprocess.job_cnt)
end
-- Ensure updates cannot be interleaved.
-- Since updates are asynchronous we need to make sure an update isn't performed
-- whilst another one is in progress. If this happens then schedule another
-- update after the current one has completed.
do
local running = false
local scheduled: {integer:boolean} = {}
M.update = function(bufnr: integer, bcache: CacheEntry)
scheduled[bufnr] = true
if not running then
running = true
while scheduled[bufnr] do
scheduled[bufnr] = nil
update0(bufnr, bcache)
end
running = false
else
-- Wait until all updates have finished
while running do
async_util.sleep(100)
end
end
end
end
M.update = throttle_by_id(update0) as function(integer, CacheEntry)
M.setup = function()
M.update_debounced = debounce_trailing(config.update_debounce, void(M.update)) as function(integer)