mirror of
https://github.com/hexedtech/codemp-nvim.git
synced 2024-11-22 15:34:53 +01:00
feat: global state, fixed thread kink
This commit is contained in:
parent
6b0cf072e8
commit
44d9f9766b
7 changed files with 146 additions and 88 deletions
|
@ -1,4 +1,6 @@
|
||||||
local function register_controller_handler(workspace, target, controller, handler, delay)
|
local state = require('codemp.state')
|
||||||
|
|
||||||
|
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 success, event = pcall(controller.try_recv, controller)
|
local success, event = pcall(controller.try_recv, controller)
|
||||||
|
@ -20,10 +22,15 @@ local function register_controller_handler(workspace, target, controller, handle
|
||||||
-- completely useless. We can circumvent this by requiring codemp again in the new
|
-- 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
|
-- thread and requesting a new reference to the same controller from che global instance
|
||||||
-- NOTE variables prefixed with underscore live in another Lua runtime
|
-- NOTE variables prefixed with underscore live in another Lua runtime
|
||||||
vim.loop.new_thread({}, function(_async, _workspace, _target, _delay)
|
vim.loop.new_thread({}, function(_async, _target, _delay, _ws, _id)
|
||||||
local _codemp = require("codemp.loader").load() -- TODO maybe make a native.load() idk
|
local _codemp = require("codemp.loader").load() -- TODO maybe make a native.load() idk
|
||||||
local _ws = _codemp.get_workspace(_workspace)
|
local _client = _codemp.get_client(_id)
|
||||||
local _controller = _target ~= nil and _ws:get_buffer(_target) or _ws.cursor
|
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
|
while true do
|
||||||
local success, _ = pcall(_controller.poll, _controller)
|
local success, _ = pcall(_controller.poll, _controller)
|
||||||
if success then
|
if success then
|
||||||
|
@ -38,7 +45,7 @@ local function register_controller_handler(workspace, target, controller, handle
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end, async, workspace, target, delay)
|
end, async, target, delay, state.workspace, state.client.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
local native = require('codemp.loader').load()
|
|
||||||
|
|
||||||
local utils = require('codemp.utils')
|
local utils = require('codemp.utils')
|
||||||
local async = require('codemp.async')
|
local async = require('codemp.async')
|
||||||
|
local state = require('codemp.state')
|
||||||
|
|
||||||
local id_buffer_map = {}
|
local id_buffer_map = {}
|
||||||
local buffer_id_map = {}
|
local buffer_id_map = {}
|
||||||
local ticks = {}
|
local ticks = {}
|
||||||
|
|
||||||
local function create(workspace, name, content)
|
local function create(name, content)
|
||||||
native.get_workspace(workspace):create_buffer(name, content)
|
state.client:get_workspace(state.workspace):create_buffer(name, content)
|
||||||
print(" ++ created buffer '" .. name .. "' on " .. workspace)
|
print(" ++ created buffer '" .. name .. "' on " .. state.workspace)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function attach(workspace, name, force)
|
local function attach(name, force)
|
||||||
local buffer = nil
|
local buffer = nil
|
||||||
if force then
|
if force then
|
||||||
buffer = vim.api.nvim_get_current_buf()
|
buffer = vim.api.nvim_get_current_buf()
|
||||||
|
@ -24,7 +23,7 @@ local function attach(workspace, name, force)
|
||||||
vim.api.nvim_buf_set_name(buffer, "codemp::" .. name)
|
vim.api.nvim_buf_set_name(buffer, "codemp::" .. name)
|
||||||
vim.api.nvim_set_current_buf(buffer)
|
vim.api.nvim_set_current_buf(buffer)
|
||||||
end
|
end
|
||||||
local controller = native.get_workspace(workspace):attach_buffer(name)
|
local controller = state.client:get_workspace(state.workspace):attach_buffer(name)
|
||||||
|
|
||||||
-- TODO map name to uuid
|
-- TODO map name to uuid
|
||||||
|
|
||||||
|
@ -55,7 +54,7 @@ local function attach(workspace, name, force)
|
||||||
-- vim.loop.sleep(200) -- moved inside poller thread to at least not block ui
|
-- vim.loop.sleep(200) -- moved inside poller thread to at least not block ui
|
||||||
|
|
||||||
-- hook clientbound callbacks
|
-- hook clientbound callbacks
|
||||||
async.handler(workspace, name, controller, function(event)
|
async.handler(name, controller, function(event)
|
||||||
ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer)
|
ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer)
|
||||||
local before = utils.buffer.get_content(buffer)
|
local before = utils.buffer.get_content(buffer)
|
||||||
local after = event:apply(before)
|
local after = event:apply(before)
|
||||||
|
@ -67,21 +66,21 @@ local function attach(workspace, name, force)
|
||||||
print(" ++ attached to buffer " .. name)
|
print(" ++ attached to buffer " .. name)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function detach(workspace, name)
|
local function detach(name)
|
||||||
local buffer = buffer_id_map[name]
|
local buffer = buffer_id_map[name]
|
||||||
id_buffer_map[buffer] = nil
|
id_buffer_map[buffer] = nil
|
||||||
buffer_id_map[name] = nil
|
buffer_id_map[name] = nil
|
||||||
native.get_workspace(workspace):disconnect_buffer(name)
|
state.client:get_workspace(state.workspace):disconnect_buffer(name)
|
||||||
vim.api.nvim_buf_delete(buffer, {})
|
vim.api.nvim_buf_delete(buffer, {})
|
||||||
|
|
||||||
print(" -- detached from buffer " .. name)
|
print(" -- detached from buffer " .. name)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function sync(workspace)
|
local function sync()
|
||||||
local buffer = vim.api.nvim_get_current_buf()
|
local buffer = vim.api.nvim_get_current_buf()
|
||||||
local name = id_buffer_map[buffer]
|
local name = id_buffer_map[buffer]
|
||||||
if name ~= nil then
|
if name ~= nil then
|
||||||
local controller = native.get_workspace(workspace):get_buffer(name)
|
local controller = state.client:get_workspace(state.workspace):get_buffer(name)
|
||||||
ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer)
|
ticks[buffer] = vim.api.nvim_buf_get_changedtick(buffer)
|
||||||
utils.buffer.set_content(buffer, controller.content)
|
utils.buffer.set_content(buffer, controller.content)
|
||||||
print(" :: synched buffer " .. name)
|
print(" :: synched buffer " .. name)
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
local native = require('codemp.loader').load()
|
|
||||||
|
|
||||||
local workspace = nil
|
|
||||||
|
|
||||||
|
|
||||||
local function login(username, password, ws)
|
|
||||||
native.login(username, password, ws)
|
|
||||||
print(" ++ logged in as '" .. username .. "' on " .. ws)
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
login = login,
|
|
||||||
workspace = workspace,
|
|
||||||
}
|
|
130
src/command.lua
130
src/command.lua
|
@ -1,7 +1,6 @@
|
||||||
local client = require('codemp.client')
|
local state = require('codemp.state')
|
||||||
local buffers = require('codemp.buffers')
|
local buffers = require('codemp.buffers')
|
||||||
local workspace = require('codemp.workspace')
|
local workspace = require('codemp.workspace')
|
||||||
local utils = require('codemp.utils')
|
|
||||||
|
|
||||||
local native = require('codemp.loader').load()
|
local native = require('codemp.loader').load()
|
||||||
|
|
||||||
|
@ -15,48 +14,75 @@ local function filter(needle, haystack)
|
||||||
return hints
|
return hints
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- always available
|
||||||
|
local base_actions = {
|
||||||
|
connect = function(host)
|
||||||
|
if host == nil then host = 'http://codemp.alemi.dev:50053' end
|
||||||
|
local user = vim.fn.input("username > ", "user-" .. vim.fn.rand() % 1024)
|
||||||
|
local password = vim.fn.input("password > ", "lmaodefaultpassword")
|
||||||
|
state.client = native.connect(host, user, password)
|
||||||
|
print(" ++ connected to " .. host .. " as " .. user)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- only available if state.client is not nil
|
||||||
|
local connected_actions = {
|
||||||
|
id = function()
|
||||||
|
print(" ::codemp#" .. state.client.id)
|
||||||
|
end,
|
||||||
|
|
||||||
|
join = function(ws)
|
||||||
|
if ws == nil then error("missing workspace name") end
|
||||||
|
state.workspace = ws
|
||||||
|
workspace.join(ws)
|
||||||
|
print(" >< joined workspace " .. ws)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- only available if state.workspace is not nil
|
||||||
|
local joined_actions = {
|
||||||
|
create = function(path)
|
||||||
|
if path == nil then error("missing buffer name") end
|
||||||
|
buffers.create(path)
|
||||||
|
end,
|
||||||
|
|
||||||
|
buffers = function()
|
||||||
|
workspace.open_buffer_tree()
|
||||||
|
end,
|
||||||
|
|
||||||
|
sync = function()
|
||||||
|
buffers.sync()
|
||||||
|
end,
|
||||||
|
|
||||||
|
attach = function(path, bang)
|
||||||
|
if path == nil then error("missing buffer name") end
|
||||||
|
buffers.attach(path, bang)
|
||||||
|
end,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
vim.api.nvim_create_user_command(
|
vim.api.nvim_create_user_command(
|
||||||
"MP",
|
"MP",
|
||||||
function (args)
|
function (args)
|
||||||
if args.fargs[1] == "login" then
|
local action = args.fargs[1]
|
||||||
if #args.fargs < 2 then error("missing workspace name") end
|
local fn = nil
|
||||||
local user = vim.fn.input("username > ", "user-" .. vim.fn.rand() % 1024)
|
|
||||||
local password = vim.fn.input("password > ", "lmaodefaultpassword")
|
if base_actions[action] ~= nil then
|
||||||
client.login(user, password, args.fargs[2])
|
fn = base_actions[action]
|
||||||
elseif args.fargs[1] == "create" then
|
|
||||||
if #args.fargs < 2 then error("missing buffer name") end
|
|
||||||
if client.workspace == nil then error("connect to a workspace first") end
|
|
||||||
buffers.create(client.workspace, args.fargs[2])
|
|
||||||
elseif args.fargs[1] == "join" then
|
|
||||||
if #args.fargs < 2 then error("missing workspace name") end
|
|
||||||
client.workspace = args.fargs[2]
|
|
||||||
workspace.join(client.workspace)
|
|
||||||
elseif args.fargs[1] == "attach" then
|
|
||||||
if #args.fargs < 2 then error("missing buffer name") end
|
|
||||||
if client.workspace == nil then error("connect to a workspace first") end
|
|
||||||
buffers.attach(client.workspace, args.fargs[2], args.bang)
|
|
||||||
elseif args.fargs[1] == "sync" then
|
|
||||||
if client.workspace == nil then error("connect to a workspace first") end
|
|
||||||
buffers.sync(client.workspace)
|
|
||||||
elseif args.fargs[1] == "buffers" then
|
|
||||||
if client.workspace == nil then error("connect to a workspace first") end
|
|
||||||
workspace.open_buffer_tree(client.workspace)
|
|
||||||
elseif args.fargs[1] == "id" then
|
|
||||||
print(" ::codemp#" .. native.id())
|
|
||||||
-- elseif args.fargs[1] == "users" then
|
|
||||||
-- if client.workspace == nil then error("connect to a workspace first") end
|
|
||||||
-- workspace.users(client.workspace)
|
|
||||||
-- elseif args.fargs[1] == "detach" then
|
|
||||||
-- if #args.fargs < 2 then error("missing buffer name") end
|
|
||||||
-- if client.workspace == nil then error("connect to a workspace first") end
|
|
||||||
-- buffers.detach(client.workspace, args.fargs[2])
|
|
||||||
-- elseif args.fargs[1] == "leave" then
|
|
||||||
-- if client.workspace == nil then error("connect to a workspace first") end
|
|
||||||
-- workspace.leave()
|
|
||||||
-- client.workspace = nil
|
|
||||||
end
|
end
|
||||||
if args.bang then
|
|
||||||
print("pls stop shouting :'c")
|
if state.client ~= nil and connected_actions[action] ~= nil then
|
||||||
|
fn = connected_actions[action]
|
||||||
|
end
|
||||||
|
|
||||||
|
if state.workspace ~= nil and joined_actions[action] ~= nil then
|
||||||
|
fn = joined_actions[action]
|
||||||
|
end
|
||||||
|
|
||||||
|
if fn ~= nil then
|
||||||
|
fn(args.fargs[2], args.bang)
|
||||||
|
else
|
||||||
|
print(" ?? invalid command")
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
{
|
{
|
||||||
|
@ -69,11 +95,29 @@ vim.api.nvim_create_user_command(
|
||||||
if stage == 1 then
|
if stage == 1 then
|
||||||
return { "MP" }
|
return { "MP" }
|
||||||
elseif stage == 2 then
|
elseif stage == 2 then
|
||||||
return filter(lead, {'login', 'create', 'join', 'attach', 'sync', 'buffers', 'users', 'detach', 'leave'})
|
local suggestions = {}
|
||||||
|
local n = 0
|
||||||
|
for sugg, _ in pairs(base_actions) do
|
||||||
|
n = n + 1
|
||||||
|
suggestions[n] = sugg
|
||||||
|
end
|
||||||
|
if state.client ~= nil then
|
||||||
|
for sugg, _ in pairs(connected_actions) do
|
||||||
|
n = n + 1
|
||||||
|
suggestions[n] = sugg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if state.workspace ~= nil then
|
||||||
|
for sugg, _ in pairs(joined_actions) do
|
||||||
|
n = n + 1
|
||||||
|
suggestions[n] = sugg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return filter(lead, suggestions)
|
||||||
elseif stage == 3 then
|
elseif stage == 3 then
|
||||||
if args[#args-1] == 'attach' or args[#args-1] == 'detach' then
|
if args[#args-1] == 'attach' or args[#args-1] == 'detach' then
|
||||||
if client.workspace ~= nil then
|
if state.client ~= nil and state.workspace ~= nil then
|
||||||
local ws = native.get_workspace(client.workspace)
|
local ws = state.client:get_workspace(state.workspace)
|
||||||
if ws ~= nil then
|
if ws ~= nil then
|
||||||
return filter(lead, ws.filetree)
|
return filter(lead, ws.filetree)
|
||||||
end
|
end
|
||||||
|
|
17
src/init.lua
17
src/init.lua
|
@ -24,6 +24,21 @@ end
|
||||||
-- end
|
-- 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')
|
||||||
|
native.runtime_drive_forever() -- spawn thread to drive tokio runtime
|
||||||
|
|
||||||
|
vim.api.nvim_create_autocmd(
|
||||||
|
{"ExitPre"},
|
||||||
|
{
|
||||||
|
callback = function (ev)
|
||||||
|
if state.client ~= nil then
|
||||||
|
print(" xx disconnecting codemp client")
|
||||||
|
native.close_client(state.client.id)
|
||||||
|
state.client = nil
|
||||||
|
end
|
||||||
|
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 (:
|
||||||
|
@ -41,7 +56,7 @@ require('codemp.command')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
native = native,
|
native = native,
|
||||||
client = require('codemp.client'),
|
state = require('codemp.state'),
|
||||||
buffers = require('codemp.buffers'),
|
buffers = require('codemp.buffers'),
|
||||||
workspace = require('codemp.workspace'),
|
workspace = require('codemp.workspace'),
|
||||||
utils = require('codemp.utils'),
|
utils = require('codemp.utils'),
|
||||||
|
|
7
src/state.lua
Normal file
7
src/state.lua
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
local workspace = nil
|
||||||
|
local client = nil
|
||||||
|
|
||||||
|
return {
|
||||||
|
workspace = workspace,
|
||||||
|
client = client,
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ 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 async = require('codemp.async')
|
||||||
|
local state = require('codemp.state')
|
||||||
|
|
||||||
local user_hl = {}
|
local user_hl = {}
|
||||||
local user_buffer = {}
|
local user_buffer = {}
|
||||||
|
@ -17,12 +18,12 @@ local available_colors = { -- TODO these are definitely not portable!
|
||||||
"CmpItemKindInterface",
|
"CmpItemKindInterface",
|
||||||
}
|
}
|
||||||
|
|
||||||
local function register_cursor_callback(controller, workspace, buffer)
|
local function register_cursor_callback(controller)
|
||||||
vim.api.nvim_create_autocmd({"CursorMoved", "CursorMovedI", "ModeChanged"}, {
|
vim.api.nvim_create_autocmd({"CursorMoved", "CursorMovedI", "ModeChanged"}, {
|
||||||
group = vim.api.nvim_create_augroup("codemp-workspace-" .. workspace, { clear = true }),
|
group = vim.api.nvim_create_augroup("codemp-workspace-" .. state.workspace, { clear = true }),
|
||||||
callback = function (_)
|
callback = function (_)
|
||||||
local cur = utils.cursor.position()
|
local cur = utils.cursor.position()
|
||||||
local buf = buffer or vim.api.nvim_get_current_buf()
|
local buf = vim.api.nvim_get_current_buf()
|
||||||
if buffers.map[buf] ~= nil then
|
if buffers.map[buf] ~= nil then
|
||||||
controller:send(buffers.map[buf], cur[1][1], cur[1][2], cur[2][1], cur[2][2])
|
controller:send(buffers.map[buf], cur[1][1], cur[1][2], cur[2][1], cur[2][2])
|
||||||
end
|
end
|
||||||
|
@ -30,8 +31,8 @@ local function register_cursor_callback(controller, workspace, buffer)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
local function register_cursor_handler(controller, workspace)
|
local function register_cursor_handler(controller)
|
||||||
async.handler(workspace, nil, controller, function(event)
|
async.handler(nil, controller, function(event)
|
||||||
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),
|
||||||
|
@ -54,10 +55,9 @@ local function register_cursor_handler(controller, workspace)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function join(workspace)
|
local function join(workspace)
|
||||||
local controller = native.join_workspace(workspace)
|
local controller = state.client:join_workspace(workspace)
|
||||||
register_cursor_callback(controller, workspace)
|
register_cursor_callback(controller)
|
||||||
register_cursor_handler(controller, workspace)
|
register_cursor_handler(controller)
|
||||||
print(" ++ joined workspace " .. workspace)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function leave()
|
local function leave()
|
||||||
|
@ -65,15 +65,15 @@ local function leave()
|
||||||
print(" -- left workspace")
|
print(" -- left workspace")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function open_buffer_tree(workspace)
|
local function open_buffer_tree()
|
||||||
local tree = native.get_workspace(workspace).filetree
|
local tree = state.client:get_workspace(state.workspace).filetree
|
||||||
if tree_buf == nil then
|
if tree_buf == nil then
|
||||||
tree_buf = vim.api.nvim_create_buf(false, true)
|
tree_buf = vim.api.nvim_create_buf(false, true)
|
||||||
vim.api.nvim_buf_set_name(tree_buf, "codemp::" .. workspace)
|
vim.api.nvim_buf_set_name(tree_buf, "codemp::" .. state.workspace)
|
||||||
vim.api.nvim_set_option_value('buftype', 'nofile', { buf = tree_buf })
|
vim.api.nvim_set_option_value('buftype', 'nofile', { buf = tree_buf })
|
||||||
end
|
end
|
||||||
vim.api.nvim_set_option_value('modifiable', true, { buf = tree_buf })
|
vim.api.nvim_set_option_value('modifiable', true, { buf = tree_buf })
|
||||||
utils.buffer.set_content(tree_buf, "codemp::" .. workspace .. "\n\n- " .. vim.fn.join(tree, "\n- "))
|
utils.buffer.set_content(tree_buf, "codemp::" .. state.workspace .. "\n\n- " .. vim.fn.join(tree, "\n- "))
|
||||||
vim.api.nvim_set_option_value('modifiable', false, { buf = tree_buf })
|
vim.api.nvim_set_option_value('modifiable', false, { buf = tree_buf })
|
||||||
vim.api.nvim_open_win(tree_buf, true, {
|
vim.api.nvim_open_win(tree_buf, true, {
|
||||||
win = 0,
|
win = 0,
|
||||||
|
|
Loading…
Reference in a new issue