From bdf800aa5a74b10f816992d38294dedff5f03e8b Mon Sep 17 00:00:00 2001 From: alemi Date: Sun, 4 Feb 2024 00:56:20 +0100 Subject: [PATCH 1/3] chore: simplify and adapt lib to workspace model very lazy port, if it works i'll make it better later:tm: --- Cargo.toml | 4 +- src/codemp.lua | 54 +++++++++++-------- src/lib.rs | 140 +++++++++++++++++++++---------------------------- 3 files changed, 93 insertions(+), 105 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e839143..b800c3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,11 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", tag = "v0.5.1", features = ["global", "sync"] } mlua = { version = "0.9.0", features = ["module", "luajit"] } +codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", rev = "5cc0bd3a869d83f7decc8ce1185eebb38771621a", features = ["global", "sync"] } thiserror = "1.0.47" derive_more = "0.99.17" tracing-subscriber = "0.3.17" tracing = "0.1.37" +lazy_static = "1.4.0" +tokio = { version = "1.35.1", features = ["rt"] } diff --git a/src/codemp.lua b/src/codemp.lua index 6c6193e..ef85b87 100644 --- a/src/codemp.lua +++ b/src/codemp.lua @@ -1,4 +1,5 @@ local codemp = require("libcodemp_nvim") +local active_workspace = nil local codemp_changed_tick = {} @@ -19,9 +20,10 @@ local function register_controller_handler(target, controller, handler, delay) -- 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) + vim.loop.new_thread({}, function(_async, _workspace, _target, _delay) local _codemp = require("libcodemp_nvim") - local _controller = _target ~= nil and _codemp.get_buffer(_target) or _codemp.get_cursor() + local _ws = _codemp.get_workspace(_workspace) + local _controller = _target ~= nil and _ws:get_buffer(_target) or _ws:get_cursor() while true do local success, _ = pcall(_controller.poll, _controller) if success then @@ -35,7 +37,7 @@ local function register_controller_handler(target, controller, handler, delay) print(" -- stopping " .. my_name .. " controller poller") end end - end, async, target, delay) + end, async, active_workspace, target, delay) end local function split_without_trim(str, sep) @@ -146,19 +148,20 @@ local available_colors = { -- TODO these are definitely not portable! "CmpItemKindInterface", } -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( +-- "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) + local controller = codemp.join_workspace(args.args) + active_workspace = args.args -- hook serverbound callbacks vim.api.nvim_create_autocmd({"CursorMoved", "CursorMovedI", "ModeChanged"}, { @@ -207,7 +210,7 @@ vim.api.nvim_create_user_command( content = buffer_get_content(buf) -- TODO send content! end - codemp.create(args.args, content) + codemp.get_workspace(active_workspace):create_buffer(args.args, content) print(" ++ created buffer " .. args.args) end, @@ -228,7 +231,7 @@ vim.api.nvim_create_user_command( vim.api.nvim_buf_set_name(buffer, "codemp::" .. args.args) vim.api.nvim_set_current_buf(buffer) end - local controller = codemp.attach(args.args) + local controller = codemp.get_workspace(active_workspace):attach_buffer(args.args) -- TODO map name to uuid @@ -242,13 +245,18 @@ vim.api.nvim_create_user_command( on_bytes = function(_, buf, tick, start_row, start_col, start_offset, old_end_row, old_end_col, old_end_byte_len, new_end_row, new_end_col, new_byte_len) if tick <= codemp_changed_tick[buf] then return end if buffer_mappings[buf] == nil then return true end -- unregister callback handler - local content = "" - if old_end_row < new_end_row and new_byte_len == 1 then - content = "\n" - else - content = table.concat(vim.api.nvim_buf_get_text(buf, start_row, start_col, start_row + new_end_row, start_col + new_byte_len, {}), '\n') - end - controller:send(start_offset, start_offset + old_end_byte_len, content) + controller:replace(buffer_get_content(buf)) + -- local content = "" + -- if old_end_row < new_end_row and new_byte_len == 1 then + -- content = "\n" + -- else + -- print(string.format("%s %s %s %s", start_row, start_col, start_row + new_end_row, start_col + new_end_col)) + -- content = table.concat(vim.api.nvim_buf_get_text(buf, start_row - 1, start_col, start_row + new_end_row - 1, start_col + new_end_col, {}), '\n') + -- end + -- if old_end_row < new_end_row then + -- start_offset = start_offset - 1 + -- end + -- controller:send(start_offset, start_offset + old_end_byte_len, content) end, }) @@ -278,7 +286,7 @@ vim.api.nvim_create_user_command( local buffer = vim.api.nvim_get_current_buf() local name = buffer_mappings[buffer] if name ~= nil then - local controller = codemp.get_buffer(name) + local controller = codemp.get_workspace(active_workspace):get_buffer(name) codemp_changed_tick[buffer] = vim.api.nvim_buf_get_changedtick(buffer) buffer_set_content(buffer, controller.content) print(" :: synched buffer " .. name) @@ -297,7 +305,7 @@ vim.api.nvim_create_user_command( local name = buffer_mappings[buffer] buffer_mappings[buffer] = nil buffer_mappings_reverse[name] = nil - codemp.disconnect_buffer(name) + codemp.get_workspace(active_workspace):disconnect_buffer(name) vim.api.nvim_buf_delete(buffer, {}) print(" -- detached from buffer " .. name) end, diff --git a/src/lib.rs b/src/lib.rs index ad514fb..aa89763 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,19 @@ use std::io::Write; -use std::sync::{Arc, Mutex, mpsc}; +use std::sync::{mpsc, Arc, Mutex}; use codemp::prelude::*; use codemp::woot::crdt::Op; use mlua::prelude::*; +use tokio::runtime::Runtime; +use tokio::sync::RwLock; + +lazy_static::lazy_static!{ + // TODO use a runtime::Builder::new_current_thread() runtime to not behave like malware + static ref RT : Runtime = Runtime::new().expect("could not instantiate tokio runtime"); + static ref CODEMP : RwLock = RwLock::new(RT.block_on(CodempClient::new( + &std::env::var("CODEMP_BASE_HOST").unwrap_or("http://codemp.alemi.dev:50051".to_string()) + )).expect("could not connect to codemp servers")); +} #[derive(Debug, thiserror::Error, derive_more::From, derive_more::Display)] @@ -18,53 +28,58 @@ impl From:: for LuaError { // TODO put friendlier constructor directly in lib? fn make_cursor(buffer: String, start_row: i32, start_col: i32, end_row: i32, end_col: i32) -> CodempCursorPosition { CodempCursorPosition { - buffer, - start: Some(CodempRowCol { - row: start_row, col: start_col, - }), - end: Some(CodempRowCol { - row: end_row, col: end_col, - }), + buffer, start: CodempRowCol { row: start_row, col: start_col}, end: CodempRowCol { row: end_row, col: end_col }, } } +fn id(_: &Lua, (): ()) -> LuaResult { + Ok(CODEMP.blocking_read().user_id().to_string()) +} + + +/// join a remote workspace and start processing cursor events +fn join_workspace(_: &Lua, (session,): (String,)) -> LuaResult { + let ws = RT.block_on(async { CODEMP.write().await.join_workspace(&session).await }) + .map_err(LuaCodempError::from)?; + let cursor = ws.blocking_read().cursor().clone(); + Ok(LuaCursorController(cursor)) +} + +fn get_workspace(_: &Lua, (session,): (String,)) -> LuaResult> { + Ok(CODEMP.blocking_read().workspaces.get(&session).cloned().map(LuaWorkspace)) +} + #[derive(Debug, derive_more::From)] struct LuaOp(Op); impl LuaUserData for LuaOp { } -/// connect to remote server -fn connect(_: &Lua, (host,): (Option,)) -> LuaResult<()> { - let addr = host.unwrap_or("http://127.0.0.1:50051".into()); - CODEMP_INSTANCE.connect(&addr) - .map_err(LuaCodempError::from)?; - Ok(()) -} +#[derive(derive_more::From)] +struct LuaWorkspace(Arc>); +impl LuaUserData for LuaWorkspace { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_method("create_buffer", |_, this, (name,):(String,)| { + Ok(RT.block_on(async { this.0.write().await.create(&name).await }).map_err(LuaCodempError::from)?) + }); -fn get_cursor(_: &Lua, _args: ()) -> LuaResult { - Ok( - CODEMP_INSTANCE.get_cursor() - .map_err(LuaCodempError::from)? - .into() - ) -} + methods.add_method("attach_buffer", |_, this, (name,):(String,)| { + Ok(LuaBufferController(RT.block_on(async { this.0.write().await.attach(&name).await }).map_err(LuaCodempError::from)?)) + }); -fn get_buffer(_: &Lua, (path,): (String,)) -> LuaResult { - Ok( - CODEMP_INSTANCE.get_buffer(&path) - .map_err(LuaCodempError::from)? - .into() - ) + // TODO disconnect_buffer + // TODO leave_workspace:w + + methods.add_method("get_buffer", |_, this, (name,):(String,)| Ok(RT.block_on(async { this.0.read().await.buffer_by_name(&name) }).map(|x| LuaBufferController(x)))); + } + + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("cursor", |_, this| Ok(LuaCursorController(RT.block_on(async { this.0.read().await.cursor() })))); + fields.add_field_method_get("filetree", |_, this| Ok(RT.block_on(async { this.0.read().await.filetree() }))); + // methods.add_method("users", |_, this| Ok(this.0.users())); // TODO + } } -/// join a remote workspace and start processing cursor events -fn join(_: &Lua, (session,): (String,)) -> LuaResult { - let controller = CODEMP_INSTANCE.join(&session) - .map_err(LuaCodempError::from)?; - Ok(LuaCursorController(controller)) -} - #[derive(Debug, derive_more::From)] struct LuaCursorController(Arc); impl LuaUserData for LuaCursorController { @@ -80,7 +95,7 @@ impl LuaUserData for LuaCursorController { } }); methods.add_method("poll", |_, this, ()| { - CODEMP_INSTANCE.rt().block_on(this.0.poll()) + RT.block_on(this.0.poll()) .map_err(LuaCodempError::from)?; Ok(()) }); @@ -91,9 +106,9 @@ impl LuaUserData for LuaCursorController { struct LuaCursorEvent(CodempCursorEvent); impl LuaUserData for LuaCursorEvent { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("user", |_, this| Ok(this.0.user.clone())); + fields.add_field_method_get("user", |_, this| Ok(this.0.user.id.clone())); fields.add_field_method_get("position", |_, this| - Ok(this.0.position.as_ref().map(|x| LuaCursorPosition(x.clone()))) + Ok(LuaCursorPosition(this.0.position.clone())) ); } } @@ -103,29 +118,12 @@ struct LuaCursorPosition(CodempCursorPosition); impl LuaUserData for LuaCursorPosition { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { fields.add_field_method_get("buffer", |_, this| Ok(this.0.buffer.clone())); - fields.add_field_method_get("start", |_, this| Ok(LuaRowCol(this.0.start()))); - fields.add_field_method_get("finish", |_, this| Ok(LuaRowCol(this.0.end()))); + fields.add_field_method_get("start", |_, this| Ok(LuaRowCol(this.0.start.clone()))); + fields.add_field_method_get("finish", |_, this| Ok(LuaRowCol(this.0.end.clone()))); } } - -/// create a new buffer in current workspace -fn create(_: &Lua, (path, content): (String, Option)) -> LuaResult<()> { - CODEMP_INSTANCE.create(&path, content.as_deref()) - .map_err(LuaCodempError::from)?; - Ok(()) -} - - - -/// attach to remote buffer and start processing buffer events -fn attach(_: &Lua, (path,): (String,)) -> LuaResult { - let controller = CODEMP_INSTANCE.attach(&path) - .map_err(LuaCodempError::from)?; - Ok(LuaBufferController(controller)) -} - #[derive(Debug, derive_more::From)] struct LuaBufferController(Arc); impl LuaUserData for LuaBufferController { @@ -149,7 +147,7 @@ impl LuaUserData for LuaBufferController { } }); methods.add_method("poll", |_, this, ()| { - CODEMP_INSTANCE.rt().block_on(this.0.poll()) + RT.block_on(this.0.poll()) .map_err(LuaCodempError::from)?; Ok(()) }); @@ -221,18 +219,6 @@ impl Write for LuaLoggerProducer { 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,)) -> LuaResult { let (tx, rx) = mpsc::channel(); let level = if debug.unwrap_or(false) { tracing::Level::DEBUG } else {tracing::Level::INFO }; @@ -254,25 +240,17 @@ fn setup_tracing(_: &Lua, (debug,): (Option,)) -> LuaResult { Ok(LuaLogger(Arc::new(Mutex::new(rx)))) } - - // define module and exports #[mlua::lua_module] fn libcodemp_nvim(lua: &Lua) -> LuaResult { let exports = lua.create_table()?; // core proto functions - exports.set("connect", lua.create_function(connect)?)?; - exports.set("join", lua.create_function(join)?)?; - exports.set("create", lua.create_function(create)?)?; - exports.set("attach", lua.create_function(attach)?)?; + exports.set("join_workspace", lua.create_function(join_workspace)?)?; // state helpers - exports.set("get_cursor", lua.create_function(get_cursor)?)?; - 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)?)?; + exports.set("get_workspace", lua.create_function(get_workspace)?)?; // debug + exports.set("id", lua.create_function(id)?)?; exports.set("setup_tracing", lua.create_function(setup_tracing)?)?; Ok(exports) From ef12f3d588aed03f45bc21aa5ff3ca88f698d4fc Mon Sep 17 00:00:00 2001 From: alemi Date: Sun, 4 Feb 2024 02:11:54 +0100 Subject: [PATCH 2/3] feat: disgusting global state but maybe works?? not really because lib still lacks a way to get the first token but ignore that, the rest may just work as it did before --- src/lib.rs | 58 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index aa89763..5a9644a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,12 +9,35 @@ use tokio::sync::RwLock; lazy_static::lazy_static!{ // TODO use a runtime::Builder::new_current_thread() runtime to not behave like malware - static ref RT : Runtime = Runtime::new().expect("could not instantiate tokio runtime"); - static ref CODEMP : RwLock = RwLock::new(RT.block_on(CodempClient::new( - &std::env::var("CODEMP_BASE_HOST").unwrap_or("http://codemp.alemi.dev:50051".to_string()) - )).expect("could not connect to codemp servers")); + static ref STATE : GlobalState = GlobalState::default(); } +struct GlobalState { + client: std::sync::RwLock, + runtime: Runtime, +} + +impl Default for GlobalState { + fn default() -> Self { + let rt = Runtime::new().expect("could not create tokio runtime"); + let client = rt.block_on(CodempClient::new("http://codemp.alemi.dev:50053")).expect("could not connect to codemp servers"); + GlobalState { client: std::sync::RwLock::new(client), runtime: rt } + } +} + +impl GlobalState { + fn client(&self) -> std::sync::RwLockReadGuard { + self.client.read().unwrap() + } + + fn client_mut(&self) -> std::sync::RwLockWriteGuard { + self.client.write().unwrap() + } + + fn rt(&self) -> &Runtime { + &self.runtime + } +} #[derive(Debug, thiserror::Error, derive_more::From, derive_more::Display)] struct LuaCodempError(CodempError); @@ -33,20 +56,21 @@ fn make_cursor(buffer: String, start_row: i32, start_col: i32, end_row: i32, end } fn id(_: &Lua, (): ()) -> LuaResult { - Ok(CODEMP.blocking_read().user_id().to_string()) + Ok(STATE.client().user_id().to_string()) } /// join a remote workspace and start processing cursor events fn join_workspace(_: &Lua, (session,): (String,)) -> LuaResult { - let ws = RT.block_on(async { CODEMP.write().await.join_workspace(&session).await }) + tracing::info!("joining workspace {}", session); + let ws = STATE.rt().block_on(async { STATE.client_mut().join_workspace(&session).await }) .map_err(LuaCodempError::from)?; - let cursor = ws.blocking_read().cursor().clone(); - Ok(LuaCursorController(cursor)) + let cursor = STATE.rt().block_on(async { ws.read().await.cursor() }); + Ok(cursor.into()) } fn get_workspace(_: &Lua, (session,): (String,)) -> LuaResult> { - Ok(CODEMP.blocking_read().workspaces.get(&session).cloned().map(LuaWorkspace)) + Ok(STATE.client().workspaces.get(&session).cloned().map(LuaWorkspace)) } #[derive(Debug, derive_more::From)] @@ -58,22 +82,22 @@ struct LuaWorkspace(Arc>); impl LuaUserData for LuaWorkspace { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_method("create_buffer", |_, this, (name,):(String,)| { - Ok(RT.block_on(async { this.0.write().await.create(&name).await }).map_err(LuaCodempError::from)?) + Ok(STATE.rt().block_on(async { this.0.write().await.create(&name).await }).map_err(LuaCodempError::from)?) }); methods.add_method("attach_buffer", |_, this, (name,):(String,)| { - Ok(LuaBufferController(RT.block_on(async { this.0.write().await.attach(&name).await }).map_err(LuaCodempError::from)?)) + Ok(LuaBufferController(STATE.rt().block_on(async { this.0.write().await.attach(&name).await }).map_err(LuaCodempError::from)?)) }); // TODO disconnect_buffer // TODO leave_workspace:w - methods.add_method("get_buffer", |_, this, (name,):(String,)| Ok(RT.block_on(async { this.0.read().await.buffer_by_name(&name) }).map(|x| LuaBufferController(x)))); + methods.add_method("get_buffer", |_, this, (name,):(String,)| Ok(STATE.rt().block_on(async { this.0.read().await.buffer_by_name(&name) }).map(LuaBufferController))); } fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("cursor", |_, this| Ok(LuaCursorController(RT.block_on(async { this.0.read().await.cursor() })))); - fields.add_field_method_get("filetree", |_, this| Ok(RT.block_on(async { this.0.read().await.filetree() }))); + fields.add_field_method_get("cursor", |_, this| Ok(LuaCursorController(STATE.rt().block_on(async { this.0.read().await.cursor() })))); + fields.add_field_method_get("filetree", |_, this| Ok(STATE.rt().block_on(async { this.0.read().await.filetree() }))); // methods.add_method("users", |_, this| Ok(this.0.users())); // TODO } } @@ -95,7 +119,7 @@ impl LuaUserData for LuaCursorController { } }); methods.add_method("poll", |_, this, ()| { - RT.block_on(this.0.poll()) + STATE.rt().block_on(this.0.poll()) .map_err(LuaCodempError::from)?; Ok(()) }); @@ -147,7 +171,7 @@ impl LuaUserData for LuaBufferController { } }); methods.add_method("poll", |_, this, ()| { - RT.block_on(this.0.poll()) + STATE.rt().block_on(this.0.poll()) .map_err(LuaCodempError::from)?; Ok(()) }); @@ -255,3 +279,5 @@ fn libcodemp_nvim(lua: &Lua) -> LuaResult { Ok(exports) } + + From 1bd160782298fa5fca0cf9e3cc3aee65d485c70c Mon Sep 17 00:00:00 2001 From: alemi Date: Fri, 9 Feb 2024 01:34:04 +0100 Subject: [PATCH 3/3] feat: updated to codemp v0.6 --- Cargo.toml | 4 ++-- src/codemp.lua | 20 ++++++++++++++++---- src/lib.rs | 27 ++++++++++++++++----------- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b800c3a..b3c8bcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -mlua = { version = "0.9.0", features = ["module", "luajit"] } -codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", rev = "5cc0bd3a869d83f7decc8ce1185eebb38771621a", features = ["global", "sync"] } +codemp = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp.git", tag = "v0.6.0", features = ["global", "sync"] } +mlua = { version = "0.9.0", features = ["module", "luajit", "send"] } thiserror = "1.0.47" derive_more = "0.99.17" tracing-subscriber = "0.3.17" diff --git a/src/codemp.lua b/src/codemp.lua index ef85b87..d4d6855 100644 --- a/src/codemp.lua +++ b/src/codemp.lua @@ -23,7 +23,7 @@ local function register_controller_handler(target, controller, handler, delay) vim.loop.new_thread({}, function(_async, _workspace, _target, _delay) local _codemp = require("libcodemp_nvim") local _ws = _codemp.get_workspace(_workspace) - local _controller = _target ~= nil and _ws:get_buffer(_target) or _ws:get_cursor() + local _controller = _target ~= nil and _ws:get_buffer(_target) or _ws.cursor while true do local success, _ = pcall(_controller.poll, _controller) if success then @@ -35,6 +35,7 @@ local function register_controller_handler(target, controller, handler, delay) my_name = "buffer(" .. _target .. ")" end print(" -- stopping " .. my_name .. " controller poller") + break end end end, async, active_workspace, target, delay) @@ -157,6 +158,15 @@ local available_colors = { -- TODO these are definitely not portable! -- { nargs = "?" } -- ) +vim.api.nvim_create_user_command( + "Login", + function (args) + codemp.login(args.fargs[1], args.fargs[2], args.fargs[3]) + print(" ++ logged in " .. args.args) + end, + { nargs = "+" } +) + vim.api.nvim_create_user_command( "Join", function (args) @@ -245,7 +255,9 @@ vim.api.nvim_create_user_command( on_bytes = function(_, buf, tick, start_row, start_col, start_offset, old_end_row, old_end_col, old_end_byte_len, new_end_row, new_end_col, new_byte_len) if tick <= codemp_changed_tick[buf] then return end if buffer_mappings[buf] == nil then return true end -- unregister callback handler - controller:replace(buffer_get_content(buf)) + local text = buffer_get_content(buf) + print(string.format("CRDT content: %s", controller.content)) + controller:send(0, #controller.content, text) -- local content = "" -- if old_end_row < new_end_row and new_byte_len == 1 then -- content = "\n" @@ -268,7 +280,7 @@ vim.api.nvim_create_user_command( -- hook clientbound callbacks register_controller_handler(args.args, controller, function(event) - codemp_changed_tick[buffer] = vim.api.nvim_buf_get_changedtick(buffer) + codemp_changed_tick[buffer] = vim.api.nvim_buf_get_changedtick(buffer) + 1 local before = buffer_get_content(buffer) local after = event:apply(before) buffer_set_content(buffer, after) @@ -287,7 +299,7 @@ vim.api.nvim_create_user_command( local name = buffer_mappings[buffer] if name ~= nil then local controller = codemp.get_workspace(active_workspace):get_buffer(name) - codemp_changed_tick[buffer] = vim.api.nvim_buf_get_changedtick(buffer) + codemp_changed_tick[buffer] = vim.api.nvim_buf_get_changedtick(buffer) + 1 buffer_set_content(buffer, controller.content) print(" :: synched buffer " .. name) else diff --git a/src/lib.rs b/src/lib.rs index 5a9644a..a17aa94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,10 +2,10 @@ use std::io::Write; use std::sync::{mpsc, Arc, Mutex}; use codemp::prelude::*; +use codemp::proto::files::BufferNode; use codemp::woot::crdt::Op; use mlua::prelude::*; use tokio::runtime::Runtime; -use tokio::sync::RwLock; lazy_static::lazy_static!{ // TODO use a runtime::Builder::new_current_thread() runtime to not behave like malware @@ -51,7 +51,7 @@ impl From:: for LuaError { // TODO put friendlier constructor directly in lib? fn make_cursor(buffer: String, start_row: i32, start_col: i32, end_row: i32, end_col: i32) -> CodempCursorPosition { CodempCursorPosition { - buffer, start: CodempRowCol { row: start_row, col: start_col}, end: CodempRowCol { row: end_row, col: end_col }, + buffer: BufferNode::from(buffer), start: CodempRowCol { row: start_row, col: start_col}, end: CodempRowCol { row: end_row, col: end_col }, } } @@ -65,12 +65,16 @@ fn join_workspace(_: &Lua, (session,): (String,)) -> LuaResult LuaResult<()> { + Ok(STATE.rt().block_on(STATE.client().login(username, password, Some(workspace_id))).map_err(LuaCodempError::from)?) +} + fn get_workspace(_: &Lua, (session,): (String,)) -> LuaResult> { - Ok(STATE.client().workspaces.get(&session).cloned().map(LuaWorkspace)) + Ok(STATE.client().get_workspace(&session).map(LuaWorkspace)) } #[derive(Debug, derive_more::From)] @@ -78,26 +82,26 @@ struct LuaOp(Op); impl LuaUserData for LuaOp { } #[derive(derive_more::From)] -struct LuaWorkspace(Arc>); +struct LuaWorkspace(Arc); impl LuaUserData for LuaWorkspace { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { methods.add_method("create_buffer", |_, this, (name,):(String,)| { - Ok(STATE.rt().block_on(async { this.0.write().await.create(&name).await }).map_err(LuaCodempError::from)?) + Ok(STATE.rt().block_on(async { this.0.create(&name).await }).map_err(LuaCodempError::from)?) }); methods.add_method("attach_buffer", |_, this, (name,):(String,)| { - Ok(LuaBufferController(STATE.rt().block_on(async { this.0.write().await.attach(&name).await }).map_err(LuaCodempError::from)?)) + Ok(LuaBufferController(STATE.rt().block_on(async { this.0.attach(&name).await }).map_err(LuaCodempError::from)?)) }); // TODO disconnect_buffer // TODO leave_workspace:w - methods.add_method("get_buffer", |_, this, (name,):(String,)| Ok(STATE.rt().block_on(async { this.0.read().await.buffer_by_name(&name) }).map(LuaBufferController))); + methods.add_method("get_buffer", |_, this, (name,):(String,)| Ok(this.0.buffer_by_name(&name).map(LuaBufferController))); } fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("cursor", |_, this| Ok(LuaCursorController(STATE.rt().block_on(async { this.0.read().await.cursor() })))); - fields.add_field_method_get("filetree", |_, this| Ok(STATE.rt().block_on(async { this.0.read().await.filetree() }))); + fields.add_field_method_get("cursor", |_, this| Ok(LuaCursorController(this.0.cursor()))); + fields.add_field_method_get("filetree", |_, this| Ok(this.0.filetree())); // methods.add_method("users", |_, this| Ok(this.0.users())); // TODO } } @@ -141,7 +145,7 @@ impl LuaUserData for LuaCursorEvent { struct LuaCursorPosition(CodempCursorPosition); impl LuaUserData for LuaCursorPosition { fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("buffer", |_, this| Ok(this.0.buffer.clone())); + fields.add_field_method_get("buffer", |_, this| Ok(this.0.buffer.path.clone())); fields.add_field_method_get("start", |_, this| Ok(LuaRowCol(this.0.start.clone()))); fields.add_field_method_get("finish", |_, this| Ok(LuaRowCol(this.0.end.clone()))); } @@ -270,6 +274,7 @@ fn libcodemp_nvim(lua: &Lua) -> LuaResult { let exports = lua.create_table()?; // core proto functions + exports.set("login", lua.create_function(login)?)?; exports.set("join_workspace", lua.create_function(join_workspace)?)?; // state helpers exports.set("get_workspace", lua.create_function(get_workspace)?)?;