feat: catch worker error, add disconnect and detach

This commit is contained in:
əlemi 2023-11-23 15:10:30 +01:00
parent 0a990c733c
commit 2393a2ceb5
2 changed files with 65 additions and 8 deletions

View file

@ -5,9 +5,13 @@ local codemp_changed_tick = 0 -- TODO this doesn't work when events are coalesce
local function register_controller_handler(target, controller, handler, delay) local function register_controller_handler(target, controller, handler, delay)
local async = vim.loop.new_async(function() local async = vim.loop.new_async(function()
while true do while true do
local event = controller:try_recv() local success, event = pcall(controller.try_recv, controller)
if event == nil then break end if success then
vim.schedule(function() handler(event) end) if event == nil then break end
vim.schedule(function() handler(event) end)
else
print("error receiving: deadlocked?")
end
end end
end) end)
-- TODO controller can't be passed to the uvloop new_thread: when sent to the new -- TODO controller can't be passed to the uvloop new_thread: when sent to the new
@ -20,8 +24,16 @@ local function register_controller_handler(target, controller, handler, delay)
local _codemp = require("libcodemp_nvim") local _codemp = require("libcodemp_nvim")
local _controller = _target ~= nil and _codemp.get_buffer(_target) or _codemp.get_cursor() local _controller = _target ~= nil and _codemp.get_buffer(_target) or _codemp.get_cursor()
while true do while true do
_controller:poll() local success, _ = pcall(_controller.poll, _controller)
_async:send() if success then
_async:send()
else
local my_name = "cursor"
if _target ~= nil then
my_name = "buffer(" .. _target .. ")"
end
print(" -- stopping " .. my_name .. " controller poller")
end
end end
end, async, target, delay) end, async, target, delay)
end end
@ -204,18 +216,24 @@ vim.api.nvim_create_user_command(
vim.api.nvim_create_user_command( vim.api.nvim_create_user_command(
"Attach", "Attach",
function (args) function (args)
local buffer = vim.api.nvim_create_buf(true, true)
vim.api.nvim_buf_set_option(buffer, 'fileformat', 'unix')
vim.api.nvim_buf_set_option(buffer, 'filetype', 'codemp')
vim.api.nvim_buf_set_name(buffer, "codemp::" .. args.args)
vim.api.nvim_set_current_buf(buffer)
local controller = codemp.attach(args.args) local controller = codemp.attach(args.args)
-- TODO map name to uuid -- TODO map name to uuid
local buffer = vim.api.nvim_get_current_buf()
buffer_mappings[buffer] = args.args buffer_mappings[buffer] = args.args
buffer_mappings_reverse[args.args] = buffer buffer_mappings_reverse[args.args] = buffer
-- hook serverbound callbacks -- hook serverbound callbacks
-- TODO breaks when deleting whole lines at buffer end
vim.api.nvim_buf_attach(buffer, false, { vim.api.nvim_buf_attach(buffer, false, {
on_lines = function (_, buf, tick, firstline, lastline, new_lastline, old_byte_size) on_lines = function (_, buf, tick, firstline, lastline, new_lastline, old_byte_size)
if tick <= codemp_changed_tick then return end if tick <= codemp_changed_tick then return end
if buffer_mappings[buf] == nil then return true end -- exit worker
local start = vim.api.nvim_buf_get_offset(buf, firstline) local start = vim.api.nvim_buf_get_offset(buf, firstline)
local content = table.concat(vim.api.nvim_buf_get_lines(buf, firstline, new_lastline, false), '\n') local content = table.concat(vim.api.nvim_buf_get_lines(buf, firstline, new_lastline, false), '\n')
if start == -1 then start = 0 end if start == -1 then start = 0 end
@ -234,13 +252,37 @@ vim.api.nvim_create_user_command(
register_controller_handler(args.args, controller, function(event) register_controller_handler(args.args, controller, function(event)
codemp_changed_tick = vim.api.nvim_buf_get_changedtick(buffer) + 1 codemp_changed_tick = vim.api.nvim_buf_get_changedtick(buffer) + 1
buffer_replace_content(buffer, event.first, event.last, event.content) buffer_replace_content(buffer, event.first, event.last, event.content)
end, 200) -- delay by 200 ms as ugly fix end, 500) -- delay by 200 ms as ugly fix
print(" ++ joined workspace " .. args.args) print(" ++ attached to buffer " .. args.args)
end, end,
{ nargs = 1 } { nargs = 1 }
) )
vim.api.nvim_create_user_command(
"Detach",
function (args)
local buffer = buffer_mappings_reverse[args.args]
if buffer == nil then buffer = vim.api.nvim_get_current_buf() end
local name = buffer_mappings[buffer]
buffer_mappings[buffer] = nil
buffer_mappings_reverse[name] = nil
codemp.disconnect_buffer(name)
vim.api.nvim_buf_delete(buffer, {})
print(" -- detached from buffer " .. name)
end,
{ nargs = '?' }
)
vim.api.nvim_create_user_command(
"Leave",
function (_)
codemp.leave_workspace()
print(" -- left workspace")
end,
{}
)
-- TODO nvim docs say that we should stop all threads before exiting nvim -- TODO nvim docs say that we should stop all threads before exiting nvim
-- but we like to live dangerously (: -- but we like to live dangerously (:
vim.loop.new_thread({}, function() vim.loop.new_thread({}, function()

View file

@ -223,6 +223,18 @@ impl Write for LuaLoggerProducer {
fn flush(&mut self) -> std::io::Result<()> { Ok(()) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) }
} }
fn disconnect_buffer(_: &Lua, (path,): (String,)) -> LuaResult<()> {
CODEMP_INSTANCE.disconnect_buffer(&path)
.map_err(LuaCodempError::from)?;
Ok(())
}
fn leave_workspace(_: &Lua, (): ()) -> LuaResult<()> {
CODEMP_INSTANCE.leave_workspace()
.map_err(LuaCodempError::from)?;
Ok(())
}
fn setup_tracing(_: &Lua, (debug,): (Option<bool>,)) -> LuaResult<LuaLogger> { fn setup_tracing(_: &Lua, (debug,): (Option<bool>,)) -> LuaResult<LuaLogger> {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let level = if debug.unwrap_or(false) { tracing::Level::DEBUG } else {tracing::Level::INFO }; let level = if debug.unwrap_or(false) { tracing::Level::DEBUG } else {tracing::Level::INFO };
@ -259,6 +271,9 @@ fn libcodemp_nvim(lua: &Lua) -> LuaResult<LuaTable> {
// state helpers // state helpers
exports.set("get_cursor", lua.create_function(get_cursor)?)?; exports.set("get_cursor", lua.create_function(get_cursor)?)?;
exports.set("get_buffer", lua.create_function(get_buffer)?)?; exports.set("get_buffer", lua.create_function(get_buffer)?)?;
// cleanup
exports.set("disconnect_buffer", lua.create_function(disconnect_buffer)?)?;
exports.set("leave_workspace", lua.create_function(leave_workspace)?)?;
// debug // debug
exports.set("setup_tracing", lua.create_function(setup_tracing)?)?; exports.set("setup_tracing", lua.create_function(setup_tracing)?)?;