diff --git a/src/async.lua b/src/async.lua deleted file mode 100644 index 7069523..0000000 --- a/src/async.lua +++ /dev/null @@ -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, -} diff --git a/src/buffers.lua b/src/buffers.lua index 0f1e3ba..8659b34 100644 --- a/src/buffers.lua +++ b/src/buffers.lua @@ -1,5 +1,4 @@ local utils = require('codemp.utils') -local async = require('codemp.async') local state = require('codemp.state') local id_buffer_map = {} @@ -63,21 +62,32 @@ local function attach(name, current, content) end, }) - -- hook clientbound callbacks - async.handler(name, controller, function(event) - ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer) - -- print(" ~~ applying change ~~ " .. event.first .. ".." .. event.last .. "::[" .. event.content .. "]") - utils.buffer.set_content(buffer, event.content, event.first, event.last) - if event.hash ~= nil then - if utils.hash(utils.buffer.get_content(buffer)) ~= event.hash then - -- OUT OF SYNC! - -- TODO this may be destructive! we should probably prompt the user before doing this - print(" /!\\ out of sync, resynching...") - utils.buffer.set_content(buffer, controller:content()) - return + 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 buffer async handler: " .. tostring(event)) + break + end + if event == nil then break end + ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer) + -- print(" ~~ applying change ~~ " .. event.first .. ".." .. event.last .. "::[" .. event.content .. "]") + utils.buffer.set_content(buffer, event.content, event.first, event.last) + if event.hash ~= nil then + if utils.hash(utils.buffer.get_content(buffer)) ~= event.hash then + -- OUT OF SYNC! + -- TODO this may be destructive! we should probably prompt the user before doing this + print(" /!\\ out of sync, resynching...") + utils.buffer.set_content(buffer, controller:content()) + return + end end end - end, 20) -- wait 20ms before polling again because it overwhelms libuv? + 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) return controller diff --git a/src/init.lua b/src/init.lua index 6750b08..8fb287c 100644 --- a/src/init.lua +++ b/src/init.lua @@ -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 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( {"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') return { @@ -61,5 +52,5 @@ return { workspace = require('codemp.workspace'), window = require('codemp.window'), utils = require('codemp.utils'), - async = require('codemp.async'), + rt = rt, } diff --git a/src/workspace.lua b/src/workspace.lua index e2cf3eb..2cfa531 100644 --- a/src/workspace.lua +++ b/src/workspace.lua @@ -2,7 +2,6 @@ local native = require('codemp.loader').load() local utils = require('codemp.utils') local buffers = require('codemp.buffers') -local async = require('codemp.async') local state = require('codemp.state') local window = require('codemp.window') @@ -33,51 +32,45 @@ local function register_cursor_callback(controller) end local function register_cursor_handler(controller) - async.handler(nil, controller, function(event) - if user_hl[event.user] == nil then - user_hl[event.user] = { - ns = vim.api.nvim_create_namespace("codemp-cursor-" .. event.user), - hi = available_colors[ math.random( #available_colors ) ], - } + 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 + user_hl[event.user] = { + ns = vim.api.nvim_create_namespace("codemp-cursor-" .. event.user), + hi = available_colors[ math.random( #available_colors ) ], + } + end + user_buffer[event.user] = event.buffer + local buffer = buffers.map_rev[event.buffer] + if buffer ~= nil then + vim.api.nvim_buf_clear_namespace(buffer, user_hl[event.user].ns, 0, -1) + utils.multiline_highlight( + buffer, + user_hl[event.user].ns, + user_hl[event.user].hi, + event.start, + event.finish + ) + end end - user_buffer[event.user] = event.buffer - local buffer = buffers.map_rev[event.buffer] - if buffer ~= nil then - vim.api.nvim_buf_clear_namespace(buffer, user_hl[event.user].ns, 0, -1) - utils.multiline_highlight( - buffer, - user_hl[event.user].ns, - user_hl[event.user].hi, - event.start, - event.finish - ) - end - end, 20) + end)) + controller:callback(function (_controller) async:send() end) end local function join(workspace) - local controller = state.client:join_workspace(workspace) - register_cursor_callback(controller) - register_cursor_handler(controller) - - -- 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) + local ws = state.client:join_workspace(workspace) + register_cursor_callback(ws.cursor) + register_cursor_handler(ws.cursor) + -- ws:callback(function (_ev) + -- vim.schedule(function() window.update() end) + -- end) window.update() end