From 5ae49d3c49790e1390a9bba790980e516974f8bd Mon Sep 17 00:00:00 2001 From: alemi Date: Thu, 26 Sep 2024 05:40:58 +0200 Subject: [PATCH] feat: improved async poller for events now, when :abort() is available, it properly cancels promises so that we dont get dangling references --- lua/codemp/utils.lua | 44 ++++++++++++++++++++++++++++++++-------- lua/codemp/workspace.lua | 28 +++++++++++++++++++++---- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/lua/codemp/utils.lua b/lua/codemp/utils.lua index 827b1d0..78afccb 100644 --- a/lua/codemp/utils.lua +++ b/lua/codemp/utils.lua @@ -29,18 +29,44 @@ local function color(name) } end +---@class AsyncPoller +---@field promise WorkspaceEventPromise | nil +---@field timer luv.Timer +---@field generator fun(): WorkspaceEventPromise +---@field callback fun(e: WorkspaceEvent) +---@field stop fun(self: AsyncPoller) + +---@return AsyncPoller local function async_poller(generator, callback) - local promise = nil - local timer = vim.loop.new_timer() - timer:start(500, 500, function() - if promise == nil then promise = generator() end - if promise.ready then - local res = promise:await() - vim.schedule(function() callback(res) end) - promise = nil + ---@type AsyncPoller + local poller = { + promise = nil, + generator = generator, + callback = callback, + timer = vim.uv.new_timer(), + stop = function (this) + print("stopping async poller") + if this.promise ~= nil then + -- TODO the :abort() change still hasnt been merged, so check for its presence! + if this.promise.abort ~= nil then + this.promise:abort() + end + end + this.timer:stop() + this.timer:close() + end + } + poller.timer:start(500, 500, function() + print("ticking poller") + if poller.promise == nil then poller.promise = poller.generator() end + if poller.promise.ready then + print("spawning callback") + local res = poller.promise:await() + vim.schedule(function() poller.callback(res) end) + poller.promise = nil end end) - + return poller end ---@param first integer diff --git a/lua/codemp/workspace.lua b/lua/codemp/workspace.lua index 12ded21..6bc626e 100644 --- a/lua/codemp/workspace.lua +++ b/lua/codemp/workspace.lua @@ -150,6 +150,8 @@ local function register_cursor_handler(controller) controller:callback(function (_controller) async:send() end) end +local events_poller = nil + ---@param workspace string workspace name to join ---join a workspace and register event handlers local function join(workspace) @@ -169,8 +171,14 @@ local function join(workspace) } end require('codemp.window').update() - utils.poller( - function() return ws:event() end, + local ws_name = ws.name + events_poller = utils.poller( + function() + if CODEMP.client == nil then return nil end + local wspace = CODEMP.client:get_workspace(ws_name) + if wspace == nil then return nil end + return wspace:event() + end, function(event) if event.type == "leave" then if buffers.users[event.value] ~= nil then @@ -198,9 +206,21 @@ local function join(workspace) end local function leave() - CODEMP.client:leave_workspace(CODEMP.workspace.name) - print(" -- left workspace") + local name = CODEMP.workspace.name CODEMP.workspace = nil + if events_poller ~= nil then + events_poller:stop() + events_poller = nil + end + if not CODEMP.client:leave_workspace(name) then + collectgarbage("collect") + -- TODO codemp disconnects when all references to its objects are dropped. since it + -- hands out Arc<> of things, all references still not garbage collected in Lua will + -- prevent it from disconnecting. while running a full cycle may be a bit slow, this + -- only happens when manually requested, and it's not like the extra garbage collection + -- is an effort for nothing... still it would be more elegant to not need this!! + end + print(" -- left workspace " .. name) require('codemp.window').update() end