Skip to content

Commit

Permalink
perf: better throttle
Browse files Browse the repository at this point in the history
  • Loading branch information
folke committed May 30, 2024
1 parent d80e978 commit c10d53d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 46 deletions.
72 changes: 52 additions & 20 deletions lua/trouble/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -105,31 +105,63 @@ function M.camel(str)
end, parts))
end

function M.debounce(ms, fn)
local timer = vim.loop.new_timer()
return function(...)
local argv = { ... }
timer:start(ms, 0, function()
timer:stop()
vim.schedule_wrap(fn)(unpack(argv))
-- throttle with trailing execution
---@generic T: fun()
---@param fn T
---@param opts? {ms:number, is_running?:fun():boolean}
---@return T
function M.throttle(fn, opts)
opts = opts or {}
opts.ms = opts.ms or 20
local timer = assert(vim.loop.new_timer())
local check = assert(vim.loop.new_check())
local last = 0
local args = {} ---@type any[]
local executing = false
local trailing = false

local throttle = {}

check:start(function()
if not throttle.is_running() and not timer:is_active() and trailing then
trailing = false
throttle.schedule()
end
end)

function throttle.is_running()
return executing or (opts.is_running and opts.is_running())
end

function throttle.run()
executing = true
last = vim.loop.now()
vim.schedule(function()
local ok, err = pcall(fn, vim.F.unpack_len(args))
executing = false
if not ok then
vim.schedule(function()
error(err)
end)
end
end)
end
end

function M.throttle(ms, fn)
local timer = vim.loop.new_timer()
local running = false
return function(...)
if not running then
local argv = { ... }
local argc = select("#", ...)
function throttle.schedule()
local now = vim.loop.now()
local delay = opts.ms - (now - last)
timer:start(math.max(0, delay), 0, throttle.run)
end

timer:start(ms, 0, function()
running = false
pcall(vim.schedule_wrap(fn), unpack(argv, 1, argc))
end)
running = true
return function(...)
args = vim.F.pack_len(...)
if timer:is_active() then
return
elseif throttle.is_running() then
trailing = true
return
end
throttle.schedule()
end
end

Expand Down
42 changes: 16 additions & 26 deletions lua/trouble/view/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ local Sort = require("trouble.sort")
local Source = require("trouble.source")
local Spec = require("trouble.spec")
local Tree = require("trouble.tree")
local Util = require("trouble.util")
local Window = require("trouble.view.window")

---@class trouble.View
Expand All @@ -20,23 +21,6 @@ local Window = require("trouble.view.window")
local M = {}
M.__index = M

--- @generic F: function
--- @param f F
--- @param opts? {ms: number, leading: boolean, trailing: boolean}
--- @return F
local function throttle(f, opts)
local fn = f
local ms = opts and opts.ms or 100
local timer = vim.loop.new_timer()
return function(...)
local argv = { ... }
timer:start(ms, 0, function()
timer:stop()
vim.schedule_wrap(fn)(unpack(argv))
end)
end
end

---@param opts trouble.Mode
function M.new(opts)
local self = setmetatable({}, M)
Expand All @@ -52,18 +36,22 @@ function M.new(opts)
self.win = Window.new(opts.win)
self.opts.win = self.win.opts
self.items = {}
self.fetching = 0
self.nodes = {}
self._main = {}
self.cache = Cache.new("view")
self.renderer = Render.new({
padding = vim.tbl_get(self.opts.win, "padding", "left"),

self.opts.render.padding = self.opts.render.padding or vim.tbl_get(self.opts.win, "padding", "left")

self.renderer = Render.new(self.opts.render)
self.refresh = Util.throttle(self.refresh, {
ms = 200,
is_running = function()
return self.fetching > 0
end,
})
local function wrap(name)
return throttle(self[name], { ms = 20, leading = true })
end
self.refresh = wrap("refresh")
self.update = wrap("update")
self.render = wrap("render")
self.update = Util.throttle(self.update, { ms = 10 })
self.render = Util.throttle(self.render, { ms = 10 })

if self.opts.auto_open then
self:listen()
Expand All @@ -78,7 +66,7 @@ function M:on_mount()
Preview.close()
end)

local preview = throttle(self.preview, { ms = 100 })
local preview = Util.throttle(self.preview, { ms = 100 })
self.win:on("CursorMoved", function()
if self.opts.auto_preview then
local loc = self:at()
Expand Down Expand Up @@ -271,6 +259,7 @@ function M:refresh()
end
self.cache:clear()
for s, section in ipairs(self.sections) do
self.fetching = self.fetching + 1
Source.get(section.source, function(items)
self.items[s] = Filter.filter(items, section.filter, self)
self.items[s] = Sort.sort(self.items[s], section.sort, self)
Expand All @@ -279,6 +268,7 @@ function M:refresh()
end
-- self.items[s] = vim.list_slice(self.items[s], 1, 10)
self.nodes[s] = Tree.build(self.items[s], section)
self.fetching = self.fetching - 1
self:update()
end, { filter = section.filter, view = self })
end
Expand Down

0 comments on commit c10d53d

Please sign in to comment.