feat: lua impl for cursors, tweaks to bindings

This commit is contained in:
əlemi 2023-08-21 04:07:25 +02:00
parent 480becf588
commit 23b4adafcb
3 changed files with 148 additions and 18 deletions

View file

@ -7,7 +7,7 @@ edition = "2021"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", tag = "v0.4.2", features = ["global", "sync"] } codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", tag = "v0.4.4", features = ["global", "sync"] }
mlua = { version = "0.9.0", features = ["send", "module", "luajit"] } mlua = { version = "0.9.0", features = ["module", "luajit"] }
thiserror = "1.0.47" thiserror = "1.0.47"
derive_more = "0.99.17" derive_more = "0.99.17"

111
src/codemp.lua Normal file
View file

@ -0,0 +1,111 @@
local codemp = require("libcodemp_nvim")
local function register_async_waker(target, cb)
local async = vim.loop.new_async(cb)
vim.loop.new_thread(function(_async, _target)
local _codemp = require("libcodemp_nvim")
local _cntrl
if _target ~= nil then
_cntrl = _codemp.get_buffer(_target)
else
_cntrl = _codemp.get_cursor()
end
while true do
_cntrl:poll()
_async:send()
end
end, async, target)
end
local function order_tuples(x) -- TODO send help...
if x[1][1] < x[2][1] then
return { { x[1][1], x[1][2] }, { x[2][1], x[2][2] } }
elseif x[1][1] > x[2][1] then
return { { x[2][1], x[2][2] }, { x[1][1], x[1][2] } }
elseif x[1][2] < x[2][2] then
return { { x[1][1], x[1][2] }, { x[2][1], x[2][2] } }
else
return { { x[2][1], x[2][2] }, { x[1][1], x[1][2] } }
end
end
local function cursor_position()
local mode = vim.api.nvim_get_mode().mode
if mode == "v" or mode == "V" then
local _, ls, cs = unpack(vim.fn.getpos('v'))
local _, le, ce = unpack(vim.fn.getpos('.'))
return order_tuples({ { ls-1, cs-1 }, { le-1, ce } })
else
local win = vim.api.nvim_get_current_win()
local cur = vim.api.nvim_win_get_cursor(win)
return order_tuples({ { cur[1]-1, cur[2] }, { cur[1]-1, cur[2]+1 } })
end
end
local function multiline_highlight(buf, ns, group, start, fini)
for i=start[1],fini[1] do
if i == start[1] and i == fini[1] then
vim.api.nvim_buf_add_highlight(buf, ns, group, i, start[2], fini[2])
elseif i == start[1] then
vim.api.nvim_buf_add_highlight(buf, ns, group, i, start[2], -1)
elseif i == fini[1] then
vim.api.nvim_buf_add_highlight(buf, ns, group, i, 0, fini[2])
else
vim.api.nvim_buf_add_highlight(buf, ns, group, i, 0, -1)
end
end
end
vim.api.nvim_create_user_command(
"Connect",
function (args)
codemp.connect(#args.args > 0 and args.args or nil)
print(" ++ connected")
end,
{ nargs = "?" }
)
vim.api.nvim_create_user_command(
"Join",
function (args)
local controller = codemp.join(args.args)
-- hook serverbound callbacks
local group = vim.api.nvim_create_augroup("codemp-workspace", { clear = true })
vim.api.nvim_create_autocmd({"CursorMoved", "CursorMovedI"}, {
group = group,
callback = function (_)
local cur = cursor_position()
controller:send("", cur[1][1], cur[1][2], cur[2][1], cur[2][2])
end
})
-- hook clientbound callbacks
local ns = vim.api.nvim_create_namespace("codemp-cursors")
local buffer = vim.api.nvim_get_current_buf()
register_async_waker(nil, function()
while true do
local event = controller:recv()
if event == nil then break end
vim.schedule(function()
vim.api.nvim_buf_clear_namespace(buffer, ns, 0, -1)
multiline_highlight(buffer, ns, "ErrorMsg", event.start, event.finish)
end)
end
end)
print(" ++ joined workspace " .. args.args)
end,
{ nargs = 1 }
)
vim.api.nvim_create_user_command(
"Attach",
function (args)
codemp.connect(#args.args > 0 and args.args or nil)
print(" ++ connected")
end,
{ nargs = 1 }
)
return codemp

View file

@ -16,11 +16,11 @@ impl From::<LuaCodempError> for LuaError {
fn cursor_to_table(lua: &Lua, cur: CodempCursorEvent) -> LuaResult<LuaTable> { fn cursor_to_table(lua: &Lua, cur: CodempCursorEvent) -> LuaResult<LuaTable> {
let pos = cur.position.unwrap_or_default(); let pos = cur.position.unwrap_or_default();
let start = lua.create_table()?; let start = lua.create_table()?;
start.set(0, pos.start().row)?; start.set(1, pos.start().row)?;
start.set(1, pos.start().col)?; start.set(2, pos.start().col)?;
let end = lua.create_table()?; let end = lua.create_table()?;
end.set(0, pos.end().row)?; end.set(1, pos.end().row)?;
end.set(1, pos.end().col)?; end.set(2, pos.end().col)?;
let out = lua.create_table()?; let out = lua.create_table()?;
out.set("user", cur.user)?; out.set("user", cur.user)?;
out.set("buffer", pos.buffer)?; out.set("buffer", pos.buffer)?;
@ -51,7 +51,13 @@ fn connect(_: &Lua, (host,): (Option<String>,)) -> LuaResult<()> {
Ok(()) Ok(())
} }
fn get_cursor(_: &Lua, _args: ()) -> LuaResult<LuaCursorController> {
Ok(
CODEMP_INSTANCE.get_cursor()
.map_err(LuaCodempError::from)?
.into()
)
}
/// join a remote workspace and start processing cursor events /// join a remote workspace and start processing cursor events
fn join(_: &Lua, (session,): (String,)) -> LuaResult<LuaCursorController> { fn join(_: &Lua, (session,): (String,)) -> LuaResult<LuaCursorController> {
@ -60,17 +66,24 @@ fn join(_: &Lua, (session,): (String,)) -> LuaResult<LuaCursorController> {
Ok(LuaCursorController(controller)) Ok(LuaCursorController(controller))
} }
#[derive(derive_more::From)] #[derive(Debug, derive_more::From)]
struct LuaCursorController(Arc<CodempCursorController>); struct LuaCursorController(Arc<CodempCursorController>);
impl LuaUserData for LuaCursorController { impl LuaUserData for LuaCursorController {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method_mut("send", |_, this, (usr, sr, sc, er, ec):(String, i32, i32, i32, i32)| { methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(format!("{:?}", this)));
methods.add_method("send", |_, this, (usr, sr, sc, er, ec):(String, i32, i32, i32, i32)| {
Ok(this.0.send(make_cursor(usr, sr, sc, er, ec)).map_err(LuaCodempError::from)?) Ok(this.0.send(make_cursor(usr, sr, sc, er, ec)).map_err(LuaCodempError::from)?)
}); });
methods.add_method_mut("recv", |lua, this, ()| { methods.add_method("recv", |lua, this, ()| {
let event = this.0.blocking_recv(CODEMP_INSTANCE.rt()) match this.0.try_recv() .map_err(LuaCodempError::from)? {
Some(x) => Ok(Some(cursor_to_table(lua, x)?)),
None => Ok(None),
}
});
methods.add_method("poll", |_, this, ()| {
CODEMP_INSTANCE.rt().block_on(this.0.poll())
.map_err(LuaCodempError::from)?; .map_err(LuaCodempError::from)?;
cursor_to_table(lua, event) Ok(())
}); });
} }
} }
@ -132,26 +145,27 @@ fn attach(_: &Lua, (path,): (String,)) -> LuaResult<LuaBufferController> {
Ok(LuaBufferController(controller)) Ok(LuaBufferController(controller))
} }
#[derive(derive_more::From)] #[derive(Debug, derive_more::From)]
struct LuaBufferController(Arc<CodempBufferController>); struct LuaBufferController(Arc<CodempBufferController>);
impl LuaUserData for LuaBufferController { impl LuaUserData for LuaBufferController {
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method_mut("delta", |_, this, (start, txt, end):(usize, String, usize)| { methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(format!("{:?}", this)));
methods.add_method("delta", |_, this, (start, txt, end):(usize, String, usize)| {
match this.0.delta(start, &txt, end) { match this.0.delta(start, &txt, end) {
Some(op) => Ok(this.0.send(op).map_err(LuaCodempError::from)?), Some(op) => Ok(this.0.send(op).map_err(LuaCodempError::from)?),
None => Ok(()), None => Ok(()),
} }
}); });
methods.add_method_mut("replace", |_, this, txt:String| { methods.add_method("replace", |_, this, txt:String| {
match this.0.replace(&txt) { match this.0.replace(&txt) {
Some(op) => Ok(this.0.send(op).map_err(LuaCodempError::from)?), Some(op) => Ok(this.0.send(op).map_err(LuaCodempError::from)?),
None => Ok(()), None => Ok(()),
} }
}); });
methods.add_method_mut("insert", |_, this, (txt, pos):(String, u64)| { methods.add_method("insert", |_, this, (txt, pos):(String, u64)| {
Ok(this.0.send(this.0.insert(&txt, pos)).map_err(LuaCodempError::from)?) Ok(this.0.send(this.0.insert(&txt, pos)).map_err(LuaCodempError::from)?)
}); });
methods.add_method_mut("recv", |_, this, ()| { methods.add_method("recv", |_, this, ()| {
let change = this.0.blocking_recv(CODEMP_INSTANCE.rt()) let change = this.0.blocking_recv(CODEMP_INSTANCE.rt())
.map_err(LuaCodempError::from)?; .map_err(LuaCodempError::from)?;
Ok(LuaTextChange(change)) Ok(LuaTextChange(change))
@ -163,7 +177,7 @@ impl LuaUserData for LuaBufferController {
} }
} }
#[derive(derive_more::From)] #[derive(Debug, derive_more::From)]
struct LuaTextChange(CodempTextChange); struct LuaTextChange(CodempTextChange);
impl LuaUserData for LuaTextChange { impl LuaUserData for LuaTextChange {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
@ -171,6 +185,10 @@ impl LuaUserData for LuaTextChange {
fields.add_field_method_get("start", |_, this| Ok(this.0.span.start)); fields.add_field_method_get("start", |_, this| Ok(this.0.span.start));
fields.add_field_method_get("finish", |_, this| Ok(this.0.span.end)); fields.add_field_method_get("finish", |_, this| Ok(this.0.span.end));
} }
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| Ok(format!("{:?}", this)));
}
} }
@ -182,5 +200,6 @@ fn libcodemp_nvim(lua: &Lua) -> LuaResult<LuaTable> {
exports.set("join", lua.create_function(join)?)?; exports.set("join", lua.create_function(join)?)?;
exports.set("create", lua.create_function(create)?)?; exports.set("create", lua.create_function(create)?)?;
exports.set("attach", lua.create_function(attach)?)?; exports.set("attach", lua.create_function(attach)?)?;
exports.set("get_cursor", lua.create_function(get_cursor)?)?;
Ok(exports) Ok(exports)
} }