feat: implemented callback api

it works well!!?! when it doesnt crash... but its also pretty clean
maybe its our fault? could be worth investigating more lua ffi
This commit is contained in:
əlemi 2024-08-16 03:49:24 +02:00
parent 36f997b42e
commit 3e9647ab39
Signed by: alemi
GPG key ID: A4895B84D311642C
4 changed files with 63 additions and 123 deletions

View file

@ -1,54 +0,0 @@
local state = require('codemp.state')
local function register_controller_handler(target, controller, handler, delay)
local async = vim.loop.new_async(function()
while true do
local success, event = pcall(controller.try_recv, controller)
if success then
if event == nil then break end
vim.schedule(function()
local ok, res = pcall(handler, event)
if not ok then
print(" !! error running callback handler: " .. res)
end
end)
else
print("error receiving: " .. tostring(event))
break
end
end
end)
-- TODO controller can't be passed to the uvloop new_thread: when sent to the new
-- Lua runtime it "loses" its methods defined with mlua, making the userdata object
-- completely useless. We can circumvent this by requiring codemp again in the new
-- thread and requesting a new reference to the same controller from che global instance
-- NOTE variables prefixed with underscore live in another Lua runtime
vim.loop.new_thread({}, function(_async, _target, _delay, _ws, _id)
local _codemp = require("codemp.loader").load() -- TODO maybe make a native.load() idk
local _client = _codemp.get_client(_id)
if _client == nil then error("cant find client " .. _id .. " from thread") end
local _workspace = _client:get_workspace(_ws)
if _workspace == nil then error("cant find workspace " .. _ws .. " from thread") end
local _controller = _target ~= nil and _workspace:get_buffer(_target) or _workspace.cursor
if _controller == nil then error("cant find controller " .. _target .. " from thread") end
if _controller.poll == nil then error("controller has nil poll field???") end
while true do
local success, _ = pcall(_controller.poll, _controller)
if success then
_async:send()
if _delay ~= nil then vim.loop.sleep(_delay) end
else
local my_name = "cursor"
if _target ~= nil then
my_name = "buffer(" .. _target .. ")"
end
print(" -- stopping " .. my_name .. " controller poller")
break
end
end
end, async, target, delay, state.workspace, state.client.id)
end
return {
handler = register_controller_handler,
}

View file

@ -1,5 +1,4 @@
local utils = require('codemp.utils') local utils = require('codemp.utils')
local async = require('codemp.async')
local state = require('codemp.state') local state = require('codemp.state')
local id_buffer_map = {} local id_buffer_map = {}
@ -63,8 +62,14 @@ local function attach(name, current, content)
end, end,
}) })
-- hook clientbound callbacks local async = vim.loop.new_async(vim.schedule_wrap(function ()
async.handler(name, controller, function(event) while true do
local success, event = pcall(controller.try_recv, controller)
if not success then
print("error in buffer async handler: " .. tostring(event))
break
end
if event == nil then break end
ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer) ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer)
-- print(" ~~ applying change ~~ " .. event.first .. ".." .. event.last .. "::[" .. event.content .. "]") -- print(" ~~ applying change ~~ " .. event.first .. ".." .. event.last .. "::[" .. event.content .. "]")
utils.buffer.set_content(buffer, event.content, event.first, event.last) utils.buffer.set_content(buffer, event.content, event.first, event.last)
@ -77,7 +82,12 @@ local function attach(name, current, content)
return return
end end
end end
end, 20) -- wait 20ms before polling again because it overwhelms libuv? end
end))
controller:callback(function (_controller) async:send() end)
vim.schedule(function ()
async:send() -- run once to try_recv anything we synched in the meantime
end)
print(" ++ attached to buffer " .. name) print(" ++ attached to buffer " .. name)
return controller return controller

View file

@ -25,7 +25,10 @@ end
local native = require('codemp.loader').load() -- make sure we can load the native library correctly, otherwise no point going forward local native = require('codemp.loader').load() -- make sure we can load the native library correctly, otherwise no point going forward
local state = require('codemp.state') local state = require('codemp.state')
native.runtime_drive_forever() -- spawn thread to drive tokio runtime local rt = native.runtime_drive_forever() -- spawn thread to drive tokio runtime
-- native.logger(function (msg)
-- vim.schedule(function () print(msg) end)
-- end, true)
vim.api.nvim_create_autocmd( vim.api.nvim_create_autocmd(
{"ExitPre"}, {"ExitPre"},
@ -40,18 +43,6 @@ vim.api.nvim_create_autocmd(
} }
) )
-- TODO nvim docs say that we should stop all threads before exiting nvim
-- but we like to live dangerously (:
vim.loop.new_thread({}, function()
vim.loop.sleep(1000) -- allow user to setup their own logger options
local _codemp = require('codemp.loader').load()
_codemp.setup_logger()
local logger = _codemp.get_logger()
while true do
print(logger:recv())
end
end)
require('codemp.command') require('codemp.command')
return { return {
@ -61,5 +52,5 @@ return {
workspace = require('codemp.workspace'), workspace = require('codemp.workspace'),
window = require('codemp.window'), window = require('codemp.window'),
utils = require('codemp.utils'), utils = require('codemp.utils'),
async = require('codemp.async'), rt = rt,
} }

View file

@ -2,7 +2,6 @@ local native = require('codemp.loader').load()
local utils = require('codemp.utils') local utils = require('codemp.utils')
local buffers = require('codemp.buffers') local buffers = require('codemp.buffers')
local async = require('codemp.async')
local state = require('codemp.state') local state = require('codemp.state')
local window = require('codemp.window') local window = require('codemp.window')
@ -33,7 +32,14 @@ local function register_cursor_callback(controller)
end end
local function register_cursor_handler(controller) local function register_cursor_handler(controller)
async.handler(nil, controller, function(event) local async = vim.loop.new_async(vim.schedule_wrap(function ()
while true do
local success, event = pcall(controller.try_recv, controller)
if not success then
print("error in cursor callback: " .. tostring(event))
break
end
if event == nil then break end
if user_hl[event.user] == nil then if user_hl[event.user] == nil then
user_hl[event.user] = { user_hl[event.user] = {
ns = vim.api.nvim_create_namespace("codemp-cursor-" .. event.user), ns = vim.api.nvim_create_namespace("codemp-cursor-" .. event.user),
@ -52,32 +58,19 @@ local function register_cursor_handler(controller)
event.finish event.finish
) )
end end
end, 20) end
end))
controller:callback(function (_controller) async:send() end)
end end
local function join(workspace) local function join(workspace)
local controller = state.client:join_workspace(workspace) local ws = state.client:join_workspace(workspace)
register_cursor_callback(controller) register_cursor_callback(ws.cursor)
register_cursor_handler(controller) register_cursor_handler(ws.cursor)
-- TODO nvim docs say that we should stop all threads before exiting nvim
-- but we like to live dangerously (:
local refresher = vim.loop.new_async(function () vim.schedule(function() window.update() end) end)
vim.loop.new_thread({}, function(_id, _ws, _refresher)
local _codemp = require('codemp.loader').load()
local _workspace = _codemp.get_client(_id):get_workspace(_ws)
while true do
local success, res = pcall(_workspace.event, _workspace)
if success then
print("workspace event!")
_refresher:send()
else
print("error waiting for workspace event: " .. res)
break
end
end
end, state.client.id, state.workspace, refresher)
-- ws:callback(function (_ev)
-- vim.schedule(function() window.update() end)
-- end)
window.update() window.update()
end end