mirror of
https://github.com/hexedtech/codemp-nvim.git
synced 2024-11-22 15:34:53 +01:00
feat: lua impl for cursors, tweaks to bindings
This commit is contained in:
parent
480becf588
commit
23b4adafcb
3 changed files with 148 additions and 18 deletions
|
@ -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
111
src/codemp.lua
Normal 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
|
51
src/lib.rs
51
src/lib.rs
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue