From a9d17bf6300ce7f9b88b01baa61883e7168cd1f6 Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 15 Oct 2024 19:31:21 +0200 Subject: [PATCH 01/19] chore: added explicit target to names, consistency --- src/client.rs | 4 ++-- src/workspace.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/client.rs b/src/client.rs index 7cba102..90ba517 100644 --- a/src/client.rs +++ b/src/client.rs @@ -153,7 +153,7 @@ impl Client { } /// Join and return a [`Workspace`]. - pub async fn join_workspace(&self, workspace: impl AsRef) -> ConnectionResult { + pub async fn attach_workspace(&self, workspace: impl AsRef) -> ConnectionResult { let token = self .0 .session @@ -203,7 +203,7 @@ impl Client { } /// Get the currently logged in user. - pub fn user(&self) -> &User { + pub fn my_user(&self) -> &User { &self.0.user } } diff --git a/src/workspace.rs b/src/workspace.rs index fe14388..94c8d37 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -140,7 +140,7 @@ impl Workspace { } /// Create a new buffer in the current workspace. - pub async fn create(&self, path: &str) -> RemoteResult<()> { + pub async fn create_buffer(&self, path: &str) -> RemoteResult<()> { let mut workspace_client = self.0.services.ws(); workspace_client .create_buffer(tonic::Request::new(BufferNode { @@ -158,7 +158,7 @@ impl Workspace { } /// Attach to a buffer and return a handle to it. - pub async fn attach(&self, path: &str) -> ConnectionResult { + pub async fn attach_buffer(&self, path: &str) -> ConnectionResult { let mut worskspace_client = self.0.services.ws(); let request = tonic::Request::new(BufferNode { path: path.to_string(), @@ -190,7 +190,7 @@ impl Workspace { /// If this method returns `false` you have a dangling ref, maybe just waiting for garbage /// collection or maybe preventing the controller from being dropped completely #[allow(clippy::redundant_pattern_matching)] // all cases are clearer this way - pub fn detach(&self, path: &str) -> bool { + pub fn detach_buffer(&self, path: &str) -> bool { match self.0.buffers.remove(path) { None => true, // noop: we werent attached in the first place Some((_name, controller)) => match Arc::into_inner(controller.0) { @@ -256,8 +256,8 @@ impl Workspace { } /// Delete a buffer. - pub async fn delete(&self, path: &str) -> RemoteResult<()> { - self.detach(path); // just in case + pub async fn delete_buffer(&self, path: &str) -> RemoteResult<()> { + self.detach_buffer(path); // just in case let mut workspace_client = self.0.services.ws(); workspace_client @@ -285,13 +285,13 @@ impl Workspace { /// Return a handle to the [buffer::Controller] with the given path, if present. // #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120 - pub fn buffer_by_name(&self, path: &str) -> Option { + pub fn get_buffer(&self, path: &str) -> Option { self.0.buffers.get(path).map(|x| x.clone()) } /// Get a list of all the currently attached buffers. // #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120 - pub fn buffer_list(&self) -> Vec { + pub fn active_buffers(&self) -> Vec { self.0 .buffers .iter() From 14e10e1f7bb148381d0554edd4e207f9a3c8efba Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 15 Oct 2024 21:46:22 +0200 Subject: [PATCH 02/19] chore: update glues --- src/ffi/java/client.rs | 4 ++-- src/ffi/java/workspace.rs | 14 +++++++------- src/ffi/js/client.rs | 6 +++--- src/ffi/js/workspace.rs | 36 ++++++++++++++++++------------------ src/ffi/lua/client.rs | 11 ++++++----- src/ffi/lua/workspace.rs | 25 ++++++++++++------------- src/ffi/python/client.rs | 10 +++++----- src/ffi/python/workspace.rs | 28 ++++++++++++++-------------- 8 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/ffi/java/client.rs b/src/ffi/java/client.rs index ff14472..d092999 100644 --- a/src/ffi/java/client.rs +++ b/src/ffi/java/client.rs @@ -20,8 +20,8 @@ fn get_user(client: &mut Client) -> crate::api::User { /// Join a [Workspace] and return a pointer to it. #[jni(package = "mp.code", class = "Client")] -fn join_workspace(client: &mut Client, workspace: String) -> Result { - super::tokio().block_on(client.join_workspace(workspace)) +fn attach_workspace(client: &mut Client, workspace: String) -> Result { + super::tokio().block_on(client.attach_workspace(workspace)) } /// Create a workspace on server, if allowed to. diff --git a/src/ffi/java/workspace.rs b/src/ffi/java/workspace.rs index acdc36f..9b5343e 100644 --- a/src/ffi/java/workspace.rs +++ b/src/ffi/java/workspace.rs @@ -22,7 +22,7 @@ fn get_cursor(workspace: &mut Workspace) -> crate::cursor::Controller { /// Get a buffer controller by name and returns a pointer to it. #[jni(package = "mp.code", class = "Workspace")] fn get_buffer(workspace: &mut Workspace, path: String) -> Option { - workspace.buffer_by_name(&path) + workspace.get_buffer(&path) } /// Get the filetree. @@ -34,7 +34,7 @@ fn get_file_tree(workspace: &mut Workspace, filter: Option, strict: bool /// Gets a list of the active buffers. #[jni(package = "mp.code", class = "Workspace")] fn active_buffers(workspace: &mut Workspace) -> Vec { - workspace.buffer_list() + workspace.active_buffers() } /// Gets a list of the active buffers. @@ -46,7 +46,7 @@ fn user_list(workspace: &mut Workspace) -> Vec { /// Create a new buffer. #[jni(package = "mp.code", class = "Workspace")] fn create_buffer(workspace: &mut Workspace, path: String) -> Result<(), RemoteError> { - super::tokio().block_on(workspace.create(&path)) + super::tokio().block_on(workspace.create_buffer(&path)) } /// Attach to a buffer and return a pointer to its [crate::buffer::Controller]. @@ -55,13 +55,13 @@ fn attach_to_buffer( workspace: &mut Workspace, path: String, ) -> Result { - super::tokio().block_on(workspace.attach(&path)) + super::tokio().block_on(workspace.attach_buffer(&path)) } /// Detach from a buffer. #[jni(package = "mp.code", class = "Workspace")] -fn detach_from_buffer(workspace: &mut Workspace, path: String) -> bool { - workspace.detach(&path) +fn detach_buffer(workspace: &mut Workspace, path: String) -> bool { + workspace.detach_buffer(&path) } /// Update the local buffer list. @@ -88,7 +88,7 @@ fn list_buffer_users( /// Delete a buffer. #[jni(package = "mp.code", class = "Workspace")] fn delete_buffer(workspace: &mut Workspace, path: String) -> Result<(), RemoteError> { - super::tokio().block_on(workspace.delete(&path)) + super::tokio().block_on(workspace.delete_buffer(&path)) } /// Block and receive a workspace event. diff --git a/src/ffi/js/client.rs b/src/ffi/js/client.rs index 8f63862..8089bc7 100644 --- a/src/ffi/js/client.rs +++ b/src/ffi/js/client.rs @@ -66,10 +66,10 @@ impl Client { Ok(self.invite_to_workspace(workspace, user).await?) } - #[napi(js_name = "join_workspace")] + #[napi(js_name = "attach_workspace")] /// join workspace with given id (will start its cursor controller) - pub async fn js_join_workspace(&self, workspace: String) -> napi::Result { - Ok(self.join_workspace(workspace).await?) + pub async fn js_attach_workspace(&self, workspace: String) -> napi::Result { + Ok(self.attach_workspace(workspace).await?) } #[napi(js_name = "leave_workspace")] diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index bacde0e..0358e2b 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -54,9 +54,9 @@ impl Workspace { } /// List all currently active buffers - #[napi(js_name = "buffer_list")] - pub fn js_buffer_list(&self) -> Vec { - self.buffer_list() + #[napi(js_name = "active_buffers")] + pub fn js_active_buffers(&self) -> Vec { + self.active_buffers() } /// Get workspace's Cursor Controller @@ -66,27 +66,27 @@ impl Workspace { } /// Get a buffer controller by its name (path) - #[napi(js_name = "buffer_by_name")] - pub fn js_buffer_by_name(&self, path: String) -> Option { - self.buffer_by_name(&path) + #[napi(js_name = "get_buffer")] + pub fn js_get_buffer(&self, path: String) -> Option { + self.get_buffer(&path) } /// Create a new buffer in the current workspace - #[napi(js_name = "create")] - pub async fn js_create(&self, path: String) -> napi::Result<()> { - Ok(self.create(&path).await?) + #[napi(js_name = "create_buffer")] + pub async fn js_create_buffer(&self, path: String) -> napi::Result<()> { + Ok(self.create_buffer(&path).await?) } /// Attach to a workspace buffer, starting a BufferController - #[napi(js_name = "attach")] - pub async fn js_attach(&self, path: String) -> napi::Result { - Ok(self.attach(&path).await?) + #[napi(js_name = "attach_buffer")] + pub async fn js_attach_buffer(&self, path: String) -> napi::Result { + Ok(self.attach_buffer(&path).await?) } /// Delete a buffer from workspace - #[napi(js_name = "delete")] - pub async fn js_delete(&self, path: String) -> napi::Result<()> { - Ok(self.delete(&path).await?) + #[napi(js_name = "delete_buffer")] + pub async fn js_delete_buffer(&self, path: String) -> napi::Result<()> { + Ok(self.delete_buffer(&path).await?) } #[napi(js_name = "recv")] @@ -128,9 +128,9 @@ impl Workspace { /// Detach from an active buffer, stopping its underlying worker /// this method returns true if no reference or last reference was held, false if there are still /// dangling references to clear - #[napi(js_name = "detach")] - pub async fn js_detach(&self, path: String) -> bool { - self.detach(&path) + #[napi(js_name = "detach_buffer")] + pub async fn js_detach_buffer(&self, path: String) -> bool { + self.detach_buffer(&path) } /// Re-fetch remote buffer list diff --git a/src/ffi/lua/client.rs b/src/ffi/lua/client.rs index 6198671..520eaec 100644 --- a/src/ffi/lua/client.rs +++ b/src/ffi/lua/client.rs @@ -7,9 +7,6 @@ use super::ext::from_lua_serde; impl LuaUserData for CodempClient { fn add_fields>(fields: &mut F) { - fields.add_field_method_get("id", |_, this| Ok(this.user().id.to_string())); - fields.add_field_method_get("username", |_, this| Ok(this.user().name.clone())); - fields.add_field_method_get("active_workspaces", |_, this| Ok(this.active_workspaces())); } fn add_methods>(methods: &mut M) { @@ -17,14 +14,18 @@ impl LuaUserData for CodempClient { Ok(format!("{:?}", this)) }); + fields.add_method("user", |_, this| Ok(this.user().id.to_string())); + fields.add_method("username", |_, this| Ok(this.my_user().name.clone())); + fields.add_method("active_workspaces", |_, this| Ok(this.active_workspaces())); + methods.add_method( "refresh", |_, this, ()| a_sync! { this => this.refresh().await? }, ); methods.add_method( - "join_workspace", - |_, this, (ws,): (String,)| a_sync! { this => this.join_workspace(ws).await? }, + "attach_workspace", + |_, this, (ws,): (String,)| a_sync! { this => this.attach_workspace(ws).await? }, ); methods.add_method( diff --git a/src/ffi/lua/workspace.rs b/src/ffi/lua/workspace.rs index 3be3ec3..56769c7 100644 --- a/src/ffi/lua/workspace.rs +++ b/src/ffi/lua/workspace.rs @@ -3,7 +3,6 @@ use mlua::prelude::*; use mlua_codemp_patch as mlua; use super::ext::a_sync::a_sync; -use super::ext::from_lua_serde; impl LuaUserData for CodempWorkspace { fn add_methods>(methods: &mut M) { @@ -11,26 +10,26 @@ impl LuaUserData for CodempWorkspace { Ok(format!("{:?}", this)) }); methods.add_method( - "create", - |_, this, (name,): (String,)| a_sync! { this => this.create(&name).await? }, + "create_buffer", + |_, this, (name,): (String,)| a_sync! { this => this.create_buffer(&name).await? }, ); methods.add_method( - "attach", - |_, this, (name,): (String,)| a_sync! { this => this.attach(&name).await? }, + "attach_buffer", + |_, this, (name,): (String,)| a_sync! { this => this.attach_buffer(&name).await? }, ); - methods.add_method("detach", |_, this, (name,): (String,)| { - Ok(this.detach(&name)) + methods.add_method("detach_buffer", |_, this, (name,): (String,)| { + Ok(this.detach_buffer(&name)) }); methods.add_method( - "delete", - |_, this, (name,): (String,)| a_sync! { this => this.delete(&name).await? }, + "delete_buffer", + |_, this, (name,): (String,)| a_sync! { this => this.delete_buffer(&name).await? }, ); methods.add_method("get_buffer", |_, this, (name,): (String,)| { - Ok(this.buffer_by_name(&name)) + Ok(this.get_buffer(&name)) }); methods.add_method( @@ -49,6 +48,9 @@ impl LuaUserData for CodempWorkspace { }, ); + fields.add_method("id", |_, this, ()| Ok(this.id())); + fields.add_method("cursor", |_, this, ()| Ok(this.cursor())); + fields.add_method("active_buffers", |_, this, ()| Ok(this.active_buffers())); methods.add_method("user_list", |_, this, ()| Ok(this.user_list())); methods.add_method("recv", |_, this, ()| a_sync! { this => this.recv().await? }); @@ -70,9 +72,6 @@ impl LuaUserData for CodempWorkspace { } fn add_fields>(fields: &mut F) { - fields.add_field_method_get("name", |_, this| Ok(this.id())); - fields.add_field_method_get("cursor", |_, this| Ok(this.cursor())); - fields.add_field_method_get("active_buffers", |_, this| Ok(this.buffer_list())); // fields.add_field_method_get("users", |_, this| Ok(this.0.users())); // TODO } } diff --git a/src/ffi/python/client.rs b/src/ffi/python/client.rs index ffeb3a6..4d12726 100644 --- a/src/ffi/python/client.rs +++ b/src/ffi/python/client.rs @@ -14,11 +14,11 @@ impl Client { // super::tokio().block_on(Client::connect(host, username, password)) // } - #[pyo3(name = "join_workspace")] - fn pyjoin_workspace(&self, py: Python<'_>, workspace: String) -> PyResult { + #[pyo3(name = "attach_workspace")] + fn pyattach_workspace(&self, py: Python<'_>, workspace: String) -> PyResult { tracing::info!("attempting to join the workspace {}", workspace); let this = self.clone(); - a_sync_allow_threads!(py, this.join_workspace(workspace).await) + a_sync_allow_threads!(py, this.attach_workspace(workspace).await) // let this = self.clone(); // Ok(super::Promise(Some(tokio().spawn(async move { // Ok(this @@ -84,12 +84,12 @@ impl Client { #[pyo3(name = "user_id")] fn pyuser_id(&self) -> String { - self.user().id.to_string() + self.my_user().id.to_string() } #[pyo3(name = "user_name")] fn pyuser_name(&self) -> String { - self.user().name.clone() + self.my_user().name.clone() } #[pyo3(name = "refresh")] diff --git a/src/ffi/python/workspace.rs b/src/ffi/python/workspace.rs index 3ceeebc..96e287c 100644 --- a/src/ffi/python/workspace.rs +++ b/src/ffi/python/workspace.rs @@ -11,20 +11,20 @@ use super::Promise; #[pymethods] impl Workspace { // join a workspace - #[pyo3(name = "create")] - fn pycreate(&self, py: Python, path: String) -> PyResult { + #[pyo3(name = "create_buffer")] + fn pycreate_buffer(&self, py: Python, path: String) -> PyResult { let this = self.clone(); - a_sync_allow_threads!(py, this.create(path.as_str()).await) + a_sync_allow_threads!(py, this.create_buffer(path.as_str()).await) } - #[pyo3(name = "attach")] - fn pyattach(&self, py: Python, path: String) -> PyResult { + #[pyo3(name = "attach_buffer")] + fn pyattach_buffer(&self, py: Python, path: String) -> PyResult { let this = self.clone(); - a_sync_allow_threads!(py, this.attach(path.as_str()).await) + a_sync_allow_threads!(py, this.attach_buffer(path.as_str()).await) } - #[pyo3(name = "detach")] - fn pydetach(&self, path: String) -> bool { + #[pyo3(name = "detach_buffer")] + fn pydetach_buffer(&self, path: String) -> bool { self.detach(path.as_str()) } @@ -47,10 +47,10 @@ impl Workspace { a_sync_allow_threads!(py, this.list_buffer_users(path.as_str()).await) } - #[pyo3(name = "delete")] - fn pydelete(&self, py: Python, path: String) -> PyResult { + #[pyo3(name = "delete_buffer")] + fn pydelete_buffer(&self, py: Python, path: String) -> PyResult { let this = self.clone(); - a_sync_allow_threads!(py, this.delete(path.as_str()).await) + a_sync_allow_threads!(py, this.delete_buffer(path.as_str()).await) } #[pyo3(name = "id")] @@ -68,9 +68,9 @@ impl Workspace { self.buffer_by_name(path.as_str()) } - #[pyo3(name = "buffer_list")] - fn pybuffer_list(&self) -> Vec { - self.buffer_list() + #[pyo3(name = "active_buffers")] + fn pyactive_buffers(&self) -> Vec { + self.active_buffers() } #[pyo3(name = "filetree")] From a44edee07b697b24ddb1fbb17ecba8adbf8cffb0 Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 15 Oct 2024 22:19:38 +0200 Subject: [PATCH 03/19] feat: user_list returns Vec returning a String was weird! --- src/ffi/java/workspace.rs | 4 ++-- src/ffi/js/workspace.rs | 6 ++++-- src/ffi/python/workspace.rs | 2 +- src/workspace.rs | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/ffi/java/workspace.rs b/src/ffi/java/workspace.rs index 9b5343e..9dcdc5b 100644 --- a/src/ffi/java/workspace.rs +++ b/src/ffi/java/workspace.rs @@ -1,5 +1,5 @@ use crate::{ - api::controller::AsyncReceiver, + api::{controller::AsyncReceiver, User}, errors::{ConnectionError, ControllerError, RemoteError}, ffi::java::null_check, Workspace, @@ -39,7 +39,7 @@ fn active_buffers(workspace: &mut Workspace) -> Vec { /// Gets a list of the active buffers. #[jni(package = "mp.code", class = "Workspace")] -fn user_list(workspace: &mut Workspace) -> Vec { +fn user_list(workspace: &mut Workspace) -> Vec { workspace.user_list() } diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index 0358e2b..e0386fe 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -8,6 +8,8 @@ use napi::threadsafe_function::{ }; use napi_derive::napi; +use super::client::JsUser; + #[napi(object, js_name = "Event")] pub struct JsEvent { pub r#type: String, @@ -49,8 +51,8 @@ impl Workspace { /// List all user names currently in this workspace #[napi(js_name = "user_list")] - pub fn js_user_list(&self) -> Vec { - self.user_list() + pub fn js_user_list(&self) -> Vec { + self.user_list().into_iter().map(JsUser::from).collect() } /// List all currently active buffers diff --git a/src/ffi/python/workspace.rs b/src/ffi/python/workspace.rs index 96e287c..a5c1256 100644 --- a/src/ffi/python/workspace.rs +++ b/src/ffi/python/workspace.rs @@ -80,7 +80,7 @@ impl Workspace { } #[pyo3(name = "user_list")] - fn pyuser_list(&self) -> Vec { + fn pyuser_list(&self) -> Vec { self.user_list() } diff --git a/src/workspace.rs b/src/workspace.rs index 94c8d37..8d04910 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -300,11 +300,11 @@ impl Workspace { } /// Get all names of users currently in this workspace - pub fn user_list(&self) -> Vec { + pub fn user_list(&self) -> Vec { self.0 .users .iter() - .map(|elem| elem.value().name.clone()) + .map(|elem| elem.value().clone()) .collect() } From a721e17024d96f0164e4423fdba296dbfe80b749 Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 15 Oct 2024 22:20:03 +0200 Subject: [PATCH 04/19] fix(py): unify current_user --- src/ffi/python/client.rs | 12 ++++-------- src/ffi/python/workspace.rs | 9 +++++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/ffi/python/client.rs b/src/ffi/python/client.rs index 4d12726..7d63406 100644 --- a/src/ffi/python/client.rs +++ b/src/ffi/python/client.rs @@ -1,5 +1,6 @@ use super::a_sync_allow_threads; use super::Client; +use crate::api::User; use crate::workspace::Workspace; use pyo3::prelude::*; @@ -82,14 +83,9 @@ impl Client { self.active_workspaces() } - #[pyo3(name = "user_id")] - fn pyuser_id(&self) -> String { - self.my_user().id.to_string() - } - - #[pyo3(name = "user_name")] - fn pyuser_name(&self) -> String { - self.my_user().name.clone() + #[pyo3(name = "current_user")] + fn pycurrent_user(&self) -> User { + self.current_user().clone() } #[pyo3(name = "refresh")] diff --git a/src/ffi/python/workspace.rs b/src/ffi/python/workspace.rs index a5c1256..ed914f5 100644 --- a/src/ffi/python/workspace.rs +++ b/src/ffi/python/workspace.rs @@ -1,4 +1,5 @@ use crate::api::controller::AsyncReceiver; +use crate::api::User; use crate::buffer::Controller as BufferController; use crate::cursor::Controller as CursorController; use crate::workspace::Workspace; @@ -25,7 +26,7 @@ impl Workspace { #[pyo3(name = "detach_buffer")] fn pydetach_buffer(&self, path: String) -> bool { - self.detach(path.as_str()) + self.detach_buffer(path.as_str()) } #[pyo3(name = "fetch_buffers")] @@ -63,9 +64,9 @@ impl Workspace { self.cursor() } - #[pyo3(name = "buffer_by_name")] - fn pybuffer_by_name(&self, path: String) -> Option { - self.buffer_by_name(path.as_str()) + #[pyo3(name = "get_buffer")] + fn pyget_buffer(&self, path: String) -> Option { + self.get_buffer(path.as_str()) } #[pyo3(name = "active_buffers")] From c63a3ec73a97adef1da4bc9ccc623caa037b780a Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 15 Oct 2024 22:20:23 +0200 Subject: [PATCH 05/19] feat(lua): use serde for IntoLua too so now it creates a table on the fly and the thing that lua receives behaves like you would expect instead of being weird! --- src/ffi/lua/buffer.rs | 36 ++---------------------------------- src/ffi/lua/client.rs | 22 ++++------------------ src/ffi/lua/cursor.rs | 34 ++-------------------------------- src/ffi/lua/ext/mod.rs | 10 ++++++++-- src/ffi/lua/workspace.rs | 34 +++++----------------------------- 5 files changed, 21 insertions(+), 115 deletions(-) diff --git a/src/ffi/lua/buffer.rs b/src/ffi/lua/buffer.rs index 5bc0813..2392734 100644 --- a/src/ffi/lua/buffer.rs +++ b/src/ffi/lua/buffer.rs @@ -3,7 +3,8 @@ use mlua::prelude::*; use mlua_codemp_patch as mlua; use super::ext::a_sync::a_sync; -use super::ext::from_lua_serde; + +super::ext::impl_lua_serde! { CodempTextChange CodempBufferUpdate } impl LuaUserData for CodempBufferController { fn add_methods>(methods: &mut M) { @@ -38,36 +39,3 @@ impl LuaUserData for CodempBufferController { }); } } - -from_lua_serde! { CodempTextChange } -impl LuaUserData for CodempTextChange { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("content", |_, this| Ok(this.content.clone())); - fields.add_field_method_get("start", |_, this| Ok(this.start)); - fields.add_field_method_get("end", |_, this| Ok(this.end)); - // add a 'finish' accessor too because in Lua 'end' is reserved - fields.add_field_method_get("finish", |_, this| Ok(this.end)); - } - - fn add_methods>(methods: &mut M) { - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - Ok(format!("{:?}", this)) - }); - methods.add_method("apply", |_, this, (txt,): (String,)| Ok(this.apply(&txt))); - } -} - -from_lua_serde! { CodempBufferUpdate } -impl LuaUserData for CodempBufferUpdate { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("hash", |_, this| Ok(this.hash)); - fields.add_field_method_get("version", |_, this| Ok(this.version.clone())); - fields.add_field_method_get("change", |_, this| Ok(this.change.clone())); - } - - fn add_methods>(methods: &mut M) { - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - Ok(format!("{:?}", this)) - }); - } -} diff --git a/src/ffi/lua/client.rs b/src/ffi/lua/client.rs index 520eaec..cb54eff 100644 --- a/src/ffi/lua/client.rs +++ b/src/ffi/lua/client.rs @@ -3,20 +3,17 @@ use mlua::prelude::*; use mlua_codemp_patch as mlua; use super::ext::a_sync::a_sync; -use super::ext::from_lua_serde; + +super::ext::impl_lua_serde! { CodempConfig CodempUser } impl LuaUserData for CodempClient { - fn add_fields>(fields: &mut F) { - } - fn add_methods>(methods: &mut M) { methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { Ok(format!("{:?}", this)) }); - fields.add_method("user", |_, this| Ok(this.user().id.to_string())); - fields.add_method("username", |_, this| Ok(this.my_user().name.clone())); - fields.add_method("active_workspaces", |_, this| Ok(this.active_workspaces())); + methods.add_method("current_user", |_, this, ()| Ok(this.current_user().clone())); + methods.add_method("active_workspaces", |_, this, ()| Ok(this.active_workspaces())); methods.add_method( "refresh", @@ -55,14 +52,3 @@ impl LuaUserData for CodempClient { }); } } - -from_lua_serde! { CodempConfig } -impl LuaUserData for CodempConfig { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("username", |_, this| Ok(this.username.clone())); - fields.add_field_method_get("password", |_, this| Ok(this.password.clone())); - fields.add_field_method_get("host", |_, this| Ok(this.host.clone())); - fields.add_field_method_get("port", |_, this| Ok(this.port)); - fields.add_field_method_get("tls", |_, this| Ok(this.tls)); - } -} diff --git a/src/ffi/lua/cursor.rs b/src/ffi/lua/cursor.rs index 86a3a33..5a7c220 100644 --- a/src/ffi/lua/cursor.rs +++ b/src/ffi/lua/cursor.rs @@ -3,7 +3,8 @@ use mlua::prelude::*; use mlua_codemp_patch as mlua; use super::ext::a_sync::a_sync; -use super::ext::from_lua_serde; + +super::ext::impl_lua_serde! { CodempCursor CodempSelection } impl LuaUserData for CodempCursorController { fn add_methods>(methods: &mut M) { @@ -29,34 +30,3 @@ impl LuaUserData for CodempCursorController { }); } } - -from_lua_serde! { CodempCursor } -impl LuaUserData for CodempCursor { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("user", |_, this| Ok(this.user.clone())); - fields.add_field_method_get("sel", |_, this| Ok(this.sel.clone())); - } - - fn add_methods>(methods: &mut M) { - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - Ok(format!("{:?}", this)) - }); - } -} - -from_lua_serde! { CodempSelection } -impl LuaUserData for CodempSelection { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("buffer", |_, this| Ok(this.buffer.clone())); - fields.add_field_method_get("start_row", |_, this| Ok(this.start_row)); - fields.add_field_method_get("start_col", |_, this| Ok(this.start_col)); - fields.add_field_method_get("end_row", |_, this| Ok(this.end_row)); - fields.add_field_method_get("end_col", |_, this| Ok(this.end_col)); - } - - fn add_methods>(methods: &mut M) { - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - Ok(format!("{:?}", this)) - }); - } -} diff --git a/src/ffi/lua/ext/mod.rs b/src/ffi/lua/ext/mod.rs index 1cb07c6..a209c0a 100644 --- a/src/ffi/lua/ext/mod.rs +++ b/src/ffi/lua/ext/mod.rs @@ -5,7 +5,7 @@ pub mod log; pub(crate) use a_sync::tokio; pub(crate) use callback::callback; -macro_rules! from_lua_serde { +macro_rules! impl_lua_serde { ($($t:ty)*) => { $( impl FromLua for $t { @@ -13,8 +13,14 @@ macro_rules! from_lua_serde { lua.from_value(value) } } + + impl IntoLua for $t { + fn into_lua(self, lua: &Lua) -> LuaResult { + lua.to_value(&self) + } + } )* }; } -pub(crate) use from_lua_serde; +pub(crate) use impl_lua_serde; diff --git a/src/ffi/lua/workspace.rs b/src/ffi/lua/workspace.rs index 56769c7..dd80f05 100644 --- a/src/ffi/lua/workspace.rs +++ b/src/ffi/lua/workspace.rs @@ -4,6 +4,8 @@ use mlua_codemp_patch as mlua; use super::ext::a_sync::a_sync; +super::ext::impl_lua_serde! { CodempEvent } + impl LuaUserData for CodempWorkspace { fn add_methods>(methods: &mut M) { methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { @@ -48,9 +50,9 @@ impl LuaUserData for CodempWorkspace { }, ); - fields.add_method("id", |_, this, ()| Ok(this.id())); - fields.add_method("cursor", |_, this, ()| Ok(this.cursor())); - fields.add_method("active_buffers", |_, this, ()| Ok(this.active_buffers())); + methods.add_method("id", |_, this, ()| Ok(this.id())); + methods.add_method("cursor", |_, this, ()| Ok(this.cursor())); + methods.add_method("active_buffers", |_, this, ()| Ok(this.active_buffers())); methods.add_method("user_list", |_, this, ()| Ok(this.user_list())); methods.add_method("recv", |_, this, ()| a_sync! { this => this.recv().await? }); @@ -70,30 +72,4 @@ impl LuaUserData for CodempWorkspace { methods.add_method("clear_callback", |_, this, ()| Ok(this.clear_callback())); } - - fn add_fields>(fields: &mut F) { - // fields.add_field_method_get("users", |_, this| Ok(this.0.users())); // TODO - } -} - -from_lua_serde! { CodempEvent } -impl LuaUserData for CodempEvent { - fn add_methods>(methods: &mut M) { - methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| { - Ok(format!("{:?}", this)) - }); - } - - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("type", |_, this| match this { - CodempEvent::FileTreeUpdated(_) => Ok("filetree"), - CodempEvent::UserJoin(_) => Ok("join"), - CodempEvent::UserLeave(_) => Ok("leave"), - }); - fields.add_field_method_get("value", |_, this| match this { - CodempEvent::FileTreeUpdated(x) - | CodempEvent::UserJoin(x) - | CodempEvent::UserLeave(x) => Ok(x.clone()), - }); - } } From 9a4225cf0d56008415fa263bdf156de2fd01e57e Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 15 Oct 2024 22:21:08 +0200 Subject: [PATCH 06/19] chore(js): camelCase --- src/ffi/js/buffer.rs | 6 +++--- src/ffi/js/client.rs | 22 +++++++++++----------- src/ffi/js/cursor.rs | 4 ++-- src/ffi/js/workspace.rs | 24 ++++++++++++------------ 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/ffi/js/buffer.rs b/src/ffi/js/buffer.rs index fc9b961..739659c 100644 --- a/src/ffi/js/buffer.rs +++ b/src/ffi/js/buffer.rs @@ -32,13 +32,13 @@ impl BufferController { } /// Remove registered buffer callback - #[napi(js_name = "clear_callback")] + #[napi(js_name = "clearCallback")] pub fn js_clear_callback(&self) { self.clear_callback(); } /// Get buffer path - #[napi(js_name = "get_path")] + #[napi(js_name = "path")] pub fn js_path(&self) -> &str { self.path() } @@ -50,7 +50,7 @@ impl BufferController { } /// Return next buffer event if present - #[napi(js_name = "try_recv")] + #[napi(js_name = "tryRecv")] pub async fn js_try_recv(&self) -> napi::Result> { Ok(self.try_recv().await?) } diff --git a/src/ffi/js/client.rs b/src/ffi/js/client.rs index 8089bc7..fc92560 100644 --- a/src/ffi/js/client.rs +++ b/src/ffi/js/client.rs @@ -34,19 +34,19 @@ pub async fn connect(config: crate::api::Config) -> napi::Result #[napi] impl Client { - #[napi(js_name = "create_workspace")] + #[napi(js_name = "createWorkspace")] /// create workspace with given id, if able to pub async fn js_create_workspace(&self, workspace: String) -> napi::Result<()> { Ok(self.create_workspace(workspace).await?) } - #[napi(js_name = "delete_workspace")] + #[napi(js_name = "deleteWorkspace")] /// delete workspace with given id, if able to pub async fn js_delete_workspace(&self, workspace: String) -> napi::Result<()> { Ok(self.delete_workspace(workspace).await?) } - #[napi(js_name = "list_workspaces")] + #[napi(js_name = "listWorkspaces")] /// list available workspaces pub async fn js_list_workspaces( &self, @@ -56,7 +56,7 @@ impl Client { Ok(self.list_workspaces(owned, invited).await?) } - #[napi(js_name = "invite_to_workspace")] + #[napi(js_name = "inviteToWorkspace")] /// invite user to given workspace, if able to pub async fn js_invite_to_workspace( &self, @@ -66,31 +66,31 @@ impl Client { Ok(self.invite_to_workspace(workspace, user).await?) } - #[napi(js_name = "attach_workspace")] + #[napi(js_name = "attachWorkspace")] /// join workspace with given id (will start its cursor controller) pub async fn js_attach_workspace(&self, workspace: String) -> napi::Result { Ok(self.attach_workspace(workspace).await?) } - #[napi(js_name = "leave_workspace")] + #[napi(js_name = "leaveWorkspace")] /// leave workspace and disconnect, returns true if workspace was active pub async fn js_leave_workspace(&self, workspace: String) -> bool { self.leave_workspace(&workspace) } - #[napi(js_name = "get_workspace")] + #[napi(js_name = "getWorkspace")] /// get workspace with given id, if it exists pub fn js_get_workspace(&self, workspace: String) -> Option { self.get_workspace(&workspace) } - #[napi(js_name = "user")] + #[napi(js_name = "currentUser")] /// return current sessions's user id - pub fn js_user(&self) -> JsUser { - self.user().clone().into() + pub fn js_current_user(&self) -> JsUser { + self.current_user().clone().into() } - #[napi(js_name = "active_workspaces")] + #[napi(js_name = "activeWorkspaces")] /// get list of all active workspaces pub fn js_active_workspaces(&self) -> Vec { self.active_workspaces() diff --git a/src/ffi/js/cursor.rs b/src/ffi/js/cursor.rs index 4759dcc..eb173ad 100644 --- a/src/ffi/js/cursor.rs +++ b/src/ffi/js/cursor.rs @@ -32,7 +32,7 @@ impl CursorController { } /// Clear the registered callback - #[napi(js_name = "clear_callback")] + #[napi(js_name = "clearCallback")] pub fn js_clear_callback(&self) { self.clear_callback(); } @@ -44,7 +44,7 @@ impl CursorController { } /// Get next cursor event if available without blocking - #[napi(js_name = "try_recv")] + #[napi(js_name = "tryRecv")] pub async fn js_try_recv(&self) -> napi::Result> { Ok(self.try_recv().await?.map(crate::api::Cursor::from)) } diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index e0386fe..c24658b 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -50,13 +50,13 @@ impl Workspace { } /// List all user names currently in this workspace - #[napi(js_name = "user_list")] + #[napi(js_name = "userList")] pub fn js_user_list(&self) -> Vec { self.user_list().into_iter().map(JsUser::from).collect() } /// List all currently active buffers - #[napi(js_name = "active_buffers")] + #[napi(js_name = "activeBuffers")] pub fn js_active_buffers(&self) -> Vec { self.active_buffers() } @@ -68,25 +68,25 @@ impl Workspace { } /// Get a buffer controller by its name (path) - #[napi(js_name = "get_buffer")] + #[napi(js_name = "getBuffer")] pub fn js_get_buffer(&self, path: String) -> Option { self.get_buffer(&path) } /// Create a new buffer in the current workspace - #[napi(js_name = "create_buffer")] + #[napi(js_name = "createBuffer")] pub async fn js_create_buffer(&self, path: String) -> napi::Result<()> { Ok(self.create_buffer(&path).await?) } /// Attach to a workspace buffer, starting a BufferController - #[napi(js_name = "attach_buffer")] + #[napi(js_name = "attachBuffer")] pub async fn js_attach_buffer(&self, path: String) -> napi::Result { Ok(self.attach_buffer(&path).await?) } /// Delete a buffer from workspace - #[napi(js_name = "delete_buffer")] + #[napi(js_name = "deleteBuffer")] pub async fn js_delete_buffer(&self, path: String) -> napi::Result<()> { Ok(self.delete_buffer(&path).await?) } @@ -96,7 +96,7 @@ impl Workspace { Ok(JsEvent::from(self.recv().await?)) } - #[napi(js_name = "try_recv")] + #[napi(js_name = "tryRecv")] pub async fn js_try_recv(&self) -> napi::Result> { Ok(self.try_recv().await?.map(JsEvent::from)) } @@ -107,7 +107,7 @@ impl Workspace { Ok(()) } - #[napi(js_name = "clear_callback")] + #[napi(js_name = "clearCallback")] pub fn js_clear_callback(&self) -> napi::Result<()> { self.clear_callback(); Ok(()) @@ -130,24 +130,24 @@ impl Workspace { /// Detach from an active buffer, stopping its underlying worker /// this method returns true if no reference or last reference was held, false if there are still /// dangling references to clear - #[napi(js_name = "detach_buffer")] + #[napi(js_name = "detachBuffer")] pub async fn js_detach_buffer(&self, path: String) -> bool { self.detach_buffer(&path) } /// Re-fetch remote buffer list - #[napi(js_name = "fetch_buffers")] + #[napi(js_name = "fetchBuffers")] pub async fn js_fetch_buffers(&self) -> napi::Result<()> { Ok(self.fetch_buffers().await?) } /// Re-fetch the list of all users in the workspace. - #[napi(js_name = "fetch_users")] + #[napi(js_name = "fetchUsers")] pub async fn js_fetch_users(&self) -> napi::Result<()> { Ok(self.fetch_users().await?) } /// List users attached to a specific buffer - #[napi(js_name = "list_buffer_users")] + #[napi(js_name = "listBufferUsers")] pub async fn js_list_buffer_users( &self, path: String, From 3bf620d41a303c9d33ba68f567433d24979f5af6 Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 15 Oct 2024 22:21:19 +0200 Subject: [PATCH 07/19] chore: my_user -> current_user --- src/client.rs | 2 +- src/ffi/java/client.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/client.rs b/src/client.rs index 90ba517..b7e7138 100644 --- a/src/client.rs +++ b/src/client.rs @@ -203,7 +203,7 @@ impl Client { } /// Get the currently logged in user. - pub fn my_user(&self) -> &User { + pub fn current_user(&self) -> &User { &self.0.user } } diff --git a/src/ffi/java/client.rs b/src/ffi/java/client.rs index d092999..a65d883 100644 --- a/src/ffi/java/client.rs +++ b/src/ffi/java/client.rs @@ -7,15 +7,15 @@ use crate::{ use jni_toolbox::jni; /// Connect using the given credentials to the default server, and return a [Client] to interact with it. -#[jni(package = "mp.code", class = "Client", ptr)] +#[jni(package = "mp.code", class = "Client")] fn connect(config: Config) -> Result { super::tokio().block_on(Client::connect(config)) } /// Gets the current [crate::api::User]. -#[jni(package = "mp.code", class = "Client", ptr)] -fn get_user(client: &mut Client) -> crate::api::User { - client.user().clone() +#[jni(package = "mp.code", class = "Client")] +fn current_user(client: &mut Client) -> crate::api::User { + client.current_user().clone() } /// Join a [Workspace] and return a pointer to it. From 96a8b1a88fb9e33f11adde952773a915639b2951 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Tue, 15 Oct 2024 22:36:43 +0200 Subject: [PATCH 08/19] chore: public workspace event type --- dist/java/src/mp/code/Workspace.java | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/dist/java/src/mp/code/Workspace.java b/dist/java/src/mp/code/Workspace.java index 10ae3b1..2d82192 100644 --- a/dist/java/src/mp/code/Workspace.java +++ b/dist/java/src/mp/code/Workspace.java @@ -4,6 +4,7 @@ import java.util.Optional; import java.util.UUID; import java.util.function.Consumer; +import lombok.Getter; import mp.code.exceptions.ConnectionException; import mp.code.exceptions.ConnectionRemoteException; import mp.code.exceptions.ControllerException; @@ -232,7 +233,8 @@ public final class Workspace { * Represents a workspace-wide event. */ public static final class Event { - private final Type type; + /** The type of the event. */ + public final @Getter Type type; private final String argument; Event(Type type, String argument) { @@ -270,9 +272,24 @@ public final class Workspace { } else return Optional.empty(); } - enum Type { + /** + * The type of workspace event. + */ + public enum Type { + /** + * Somebody joined a workspace. + * @see #getUserJoined() to get the name + */ USER_JOIN, + /** + * Somebody left a workspace + * @see #getUserLeft() to get the name + */ USER_LEAVE, + /** + * The filetree was updated. + * @see #getChangedBuffer() to see the buffer that changed + */ FILE_TREE_UPDATED } } From 6f04c3877968a1e9fd933777b25e6f6b015b3ef2 Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 15 Oct 2024 23:01:49 +0200 Subject: [PATCH 09/19] chore: last consistency fixes in glues Co-authored-by: zaaarf --- dist/java/src/mp/code/Client.java | 12 ++++---- dist/java/src/mp/code/Workspace.java | 30 +++++++++---------- dist/lua/annotations.lua | 44 ++++++++++++++++++++-------- dist/py/src/codemp/codemp.pyi | 25 ++++++++++------ src/api/event.rs | 1 + src/ffi/java/workspace.rs | 10 +++---- 6 files changed, 75 insertions(+), 47 deletions(-) diff --git a/dist/java/src/mp/code/Client.java b/dist/java/src/mp/code/Client.java index 12bd9c3..1146973 100644 --- a/dist/java/src/mp/code/Client.java +++ b/dist/java/src/mp/code/Client.java @@ -34,17 +34,17 @@ public final class Client { */ public static native Client connect(Config config) throws ConnectionException; - private static native User get_user(long self); + private static native User current_user(long self); /** * Gets information about the current user. * @return a {@link User} object representing the user */ - public User getUser() { - return get_user(this.ptr); + public User currentUser() { + return current_user(this.ptr); } - private static native Workspace join_workspace(long self, String workspaceId) throws ConnectionException; + private static native Workspace attach_workspace(long self, String workspaceId) throws ConnectionException; /** * Joins a {@link Workspace} and returns it. @@ -52,8 +52,8 @@ public final class Client { * @return the relevant {@link Workspace} * @throws ConnectionException if an error occurs in communicating with the server */ - public Workspace joinWorkspace(String workspaceId) throws ConnectionException { - return join_workspace(this.ptr, workspaceId); + public Workspace attachWorkspace(String workspaceId) throws ConnectionException { + return attach_workspace(this.ptr, workspaceId); } private static native void create_workspace(long self, String workspaceId) throws ConnectionRemoteException; diff --git a/dist/java/src/mp/code/Workspace.java b/dist/java/src/mp/code/Workspace.java index 2d82192..1324f6a 100644 --- a/dist/java/src/mp/code/Workspace.java +++ b/dist/java/src/mp/code/Workspace.java @@ -25,24 +25,24 @@ public final class Workspace { Extensions.CLEANER.register(this, () -> free(ptr)); } - private static native String get_workspace_id(long self); + private static native String id(long self); /** * Gets the unique identifier of the current workspace. * @return the identifier */ - public String getWorkspaceId() { - return get_workspace_id(this.ptr); + public String id() { + return id(this.ptr); } - private static native CursorController get_cursor(long self); + private static native CursorController cursor(long self); /** * Gets the {@link CursorController} for the current workspace. * @return the {@link CursorController} */ - public CursorController getCursor() { - return get_cursor(this.ptr); + public CursorController cursor() { + return cursor(this.ptr); } private static native BufferController get_buffer(long self, String path); @@ -57,7 +57,7 @@ public final class Workspace { return Optional.ofNullable(get_buffer(this.ptr, path)); } - private static native String[] get_file_tree(long self, String filter, boolean strict); + private static native String[] filetree(long self, String filter, boolean strict); /** * Gets the file tree for this workspace, optionally filtering it. @@ -66,8 +66,8 @@ public final class Workspace { * @return an array containing file tree as flat paths */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - public String[] getFileTree(Optional filter, boolean strict) { - return get_file_tree(this.ptr, filter.orElse(null), strict); + public String[] filetree(Optional filter, boolean strict) { + return filetree(this.ptr, filter.orElse(null), strict); } private static native String[] active_buffers(long self); @@ -102,7 +102,7 @@ public final class Workspace { create_buffer(this.ptr, path); } - private static native BufferController attach_to_buffer(long self, String path) throws ConnectionException; + private static native BufferController attach_buffer(long self, String path) throws ConnectionException; /** * Attaches to an existing buffer with the given path, if present. @@ -110,19 +110,19 @@ public final class Workspace { * @return the {@link BufferController} associated with that path * @throws ConnectionException if an error occurs in communicating with the server, or if the buffer did not exist */ - public BufferController attachToBuffer(String path) throws ConnectionException { - return attach_to_buffer(ptr, path); + public BufferController attachBuffer(String path) throws ConnectionException { + return attach_buffer(ptr, path); } - private static native boolean detach_from_buffer(long self, String path); + private static native boolean detach_buffer(long self, String path); /** * Detaches from a given buffer. * @param path the path of the buffer to detach from * @return a boolean, true only if there are still dangling references preventing controller from stopping */ - public boolean detachFromBuffer(String path) { - return detach_from_buffer(this.ptr, path); + public boolean detachBuffer(String path) { + return detach_buffer(this.ptr, path); } private static native void fetch_buffers(long self) throws ConnectionRemoteException; diff --git a/dist/lua/annotations.lua b/dist/lua/annotations.lua index 71b5ea3..9a411ba 100644 --- a/dist/lua/annotations.lua +++ b/dist/lua/annotations.lua @@ -162,12 +162,17 @@ function MaybeBufferUpdatePromise:and_then(cb) end ---@class (exact) Client ----@field id string uuid of local user ----@field username string name of local user ----@field active_workspaces string[] array of all currently active workspace names ---the effective local client, handling connecting to codemp server local Client = {} +---@return User +---current logged in user for this client +function Client:current_user() end + +---@return string[] +---array of all currently active workspace names +function Client:active_workspaces() end + ---@return NilPromise ---@async ---@nodiscard @@ -179,7 +184,7 @@ function Client:refresh() end ---@async ---@nodiscard ---join requested workspace if possible and subscribe to event bus -function Client:join_workspace(ws) end +function Client:attach_workspace(ws) end ---@param ws string workspace id to create ---@return NilPromise @@ -222,26 +227,41 @@ function Client:get_workspace(ws) end +---@class User +---@field id string user uuid +---@field name string user display name + + + ---@class (exact) Workspace ----@field name string workspace name ----@field cursor CursorController workspace cursor controller ----@field active_buffers string[] array of all currently active buffer names ---a joined codemp workspace local Workspace = {} +---@return string +---workspace id +function Workspace:id() end + +---@return string[] +---array of all currently active buffer names +function Workspace:active_buffers() end + +---@return CursorController +---reference to workspace's CursorController +function Workspace:cursor() end + ---@param path string relative path ("name") of new buffer ---@return NilPromise ---@async ---@nodiscard ---create a new empty buffer -function Workspace:create(path) end +function Workspace:create_buffer(path) end ---@param path string relative path ("name") of buffer to delete ---@return NilPromise ---@async ---@nodiscard ---delete buffer from workspace -function Workspace:delete(path) end +function Workspace:delete_buffer(path) end ---@param path string relative path ("name") of buffer to get ---@return BufferController? @@ -253,12 +273,12 @@ function Workspace:get_buffer(path) end ---@async ---@nodiscard ---attach to a remote buffer, synching content and changes and returning its controller -function Workspace:attach(path) end +function Workspace:attach_buffer(path) end ---@param path string relative path ("name") of buffer to detach from ---@return boolean success ---detach from an active buffer, closing all streams. returns false if there are still dangling references -function Workspace:detach(path) end +function Workspace:detach_buffer(path) end ---@param filter? string apply a filter to the return elements ---@param strict? boolean whether to strictly match or just check whether it starts with it @@ -266,7 +286,7 @@ function Workspace:detach(path) end ---return the list of available buffers in this workspace, as relative paths from workspace root function Workspace:filetree(filter, strict) end ----@return string[] +---@return User[] ---return all names of users currently in this workspace function Workspace:user_list() end diff --git a/dist/py/src/codemp/codemp.pyi b/dist/py/src/codemp/codemp.pyi index 25b1ba8..438bdbe 100644 --- a/dist/py/src/codemp/codemp.pyi +++ b/dist/py/src/codemp/codemp.pyi @@ -7,6 +7,13 @@ class Driver: """ def stop(self) -> None: ... +class User: + """ + A remote user, with uuid and username + """ + id: str + name: str + class Config: """ Configuration data structure for codemp clients @@ -40,7 +47,7 @@ class Client: Handle to the actual client that manages the session. It manages the connection to a server and joining/creating new workspaces """ - def join_workspace(self, workspace: str) -> Promise[Workspace]: ... + def attach_workspace(self, workspace: str) -> Promise[Workspace]: ... def create_workspace(self, workspace: str) -> Promise[None]: ... def delete_workspace(self, workspace: str) -> Promise[None]: ... def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ... @@ -48,8 +55,7 @@ class Client: def leave_workspace(self, workspace: str) -> bool: ... def get_workspace(self, id: str) -> Workspace: ... def active_workspaces(self) -> list[str]: ... - def user_id(self) -> str: ... - def user_name(self) -> str: ... + def current_user(self) -> User: ... def refresh(self) -> Promise[None]: ... class Event: @@ -60,17 +66,18 @@ class Workspace: Handle to a workspace inside codemp. It manages buffers. A cursor is tied to the single workspace. """ - def create(self, path: str) -> Promise[None]: ... - def attach(self, path: str) -> Promise[BufferController]: ... - def detach(self, path: str) -> bool: ... + def create_buffer(self, path: str) -> Promise[None]: ... + def attach_buffer(self, path: str) -> Promise[BufferController]: ... + def detach_buffer(self, path: str) -> bool: ... def fetch_buffers(self) -> Promise[None]: ... def fetch_users(self) -> Promise[None]: ... def list_buffer_users(self, path: str) -> Promise[list[str]]: ... - def delete(self, path: str) -> Promise[None]: ... + def delete_buffer(self, path: str) -> Promise[None]: ... def id(self) -> str: ... def cursor(self) -> CursorController: ... - def buffer_by_name(self, path: str) -> Optional[BufferController]: ... - def buffer_list(self) -> list[str]: ... + def get_buffer(self, path: str) -> Optional[BufferController]: ... + def user_list(self) -> list[User]: ... + def active_buffers(self) -> list[str]: ... def filetree(self, filter: Optional[str], strict: bool) -> list[str]: ... def recv(self) -> Promise[Event]: ... def try_recv(self) -> Promise[Optional[Event]]: ... diff --git a/src/api/event.rs b/src/api/event.rs index c4c73c5..81df033 100644 --- a/src/api/event.rs +++ b/src/api/event.rs @@ -6,6 +6,7 @@ use codemp_proto::workspace::workspace_event::Event as WorkspaceEventInner; #[derive(Debug, Clone)] #[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serialize", serde(tag = "type"))] pub enum Event { /// Fired when the file tree changes. /// Contains the modified buffer path (deleted, created or renamed). diff --git a/src/ffi/java/workspace.rs b/src/ffi/java/workspace.rs index 9dcdc5b..4cca434 100644 --- a/src/ffi/java/workspace.rs +++ b/src/ffi/java/workspace.rs @@ -9,13 +9,13 @@ use jni_toolbox::jni; /// Get the workspace id. #[jni(package = "mp.code", class = "Workspace")] -fn get_workspace_id(workspace: &mut Workspace) -> String { +fn id(workspace: &mut Workspace) -> String { workspace.id() } /// Get a cursor controller by name and returns a pointer to it. #[jni(package = "mp.code", class = "Workspace")] -fn get_cursor(workspace: &mut Workspace) -> crate::cursor::Controller { +fn cursor(workspace: &mut Workspace) -> crate::cursor::Controller { workspace.cursor() } @@ -27,7 +27,7 @@ fn get_buffer(workspace: &mut Workspace, path: String) -> Option, strict: bool) -> Vec { +fn filetree(workspace: &mut Workspace, filter: Option, strict: bool) -> Vec { workspace.filetree(filter.as_deref(), strict) } @@ -49,9 +49,9 @@ fn create_buffer(workspace: &mut Workspace, path: String) -> Result<(), RemoteEr super::tokio().block_on(workspace.create_buffer(&path)) } -/// Attach to a buffer and return a pointer to its [crate::buffer::Controller]. +/// Attach to a buffer and return a pointer to its [`crate::buffer::Controller`]. #[jni(package = "mp.code", class = "Workspace")] -fn attach_to_buffer( +fn attach_buffer( workspace: &mut Workspace, path: String, ) -> Result { From e5fd0ca76aa0bada561e3372311523cf8989a5eb Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 16 Oct 2024 00:42:55 +0200 Subject: [PATCH 10/19] chore: split list_workspaces, renamed filetree, refactored fetch_users and fetch_buffers Co-authored-by: alemi --- dist/java/src/mp/code/Client.java | 21 +++++++--- dist/java/src/mp/code/Workspace.java | 41 +++++++++---------- dist/lua/annotations.lua | 33 +++++++++++++--- dist/py/src/codemp/codemp.pyi | 11 +++--- src/api/mod.rs | 8 ++-- src/buffer/worker.rs | 11 ++++-- src/client.rs | 31 +++++++++------ src/ffi/java/buffer.rs | 5 +-- src/ffi/java/client.rs | 16 ++++---- src/ffi/java/cursor.rs | 5 +-- src/ffi/java/workspace.rs | 16 ++++---- src/ffi/js/client.rs | 18 +++++---- src/ffi/js/workspace.rs | 25 +++++++----- src/ffi/lua/client.rs | 18 +++++++-- src/ffi/lua/ext/callback.rs | 1 + src/ffi/lua/workspace.rs | 15 ++++--- src/ffi/mod.rs | 52 ++++++++++++------------ src/ffi/python/client.rs | 20 +++++----- src/ffi/python/workspace.rs | 14 +++---- src/prelude.rs | 2 +- src/workspace.rs | 59 +++++++++++++--------------- 21 files changed, 239 insertions(+), 183 deletions(-) diff --git a/dist/java/src/mp/code/Client.java b/dist/java/src/mp/code/Client.java index 1146973..f7d56f5 100644 --- a/dist/java/src/mp/code/Client.java +++ b/dist/java/src/mp/code/Client.java @@ -91,17 +91,26 @@ public final class Client { invite_to_workspace(this.ptr, workspaceId, user); } - private static native String[] list_workspaces(long self, boolean owned, boolean invited) throws ConnectionRemoteException; + private static native String[] fetch_owned_workspaces(long self) throws ConnectionRemoteException; /** - * Lists available workspaces according to certain filters. - * @param owned if owned workspaces should be included - * @param invited if workspaces the user is invited to should be included + * Lists workspaces owned by the current user. * @return an array of workspace IDs * @throws ConnectionRemoteException if an error occurs in communicating with the server */ - public String[] listWorkspaces(boolean owned, boolean invited) throws ConnectionRemoteException { - return list_workspaces(this.ptr, owned, invited); + public String[] fetchOwnedWorkspaces() throws ConnectionRemoteException { + return fetch_owned_workspaces(this.ptr); + } + + private static native String[] fetch_joined_workspaces(long self) throws ConnectionRemoteException; + + /** + * Lists workspaces the current user has joined. + * @return an array of workspace IDs + * @throws ConnectionRemoteException if an error occurs in communicating with the server + */ + public String[] fetchJoinedWorkspaces() throws ConnectionRemoteException { + return fetch_joined_workspaces(this.ptr); } private static native String[] active_workspaces(long self); diff --git a/dist/java/src/mp/code/Workspace.java b/dist/java/src/mp/code/Workspace.java index 1324f6a..b359516 100644 --- a/dist/java/src/mp/code/Workspace.java +++ b/dist/java/src/mp/code/Workspace.java @@ -1,10 +1,10 @@ package mp.code; import java.util.Optional; -import java.util.UUID; import java.util.function.Consumer; import lombok.Getter; +import mp.code.data.User; import mp.code.exceptions.ConnectionException; import mp.code.exceptions.ConnectionRemoteException; import mp.code.exceptions.ControllerException; @@ -57,17 +57,16 @@ public final class Workspace { return Optional.ofNullable(get_buffer(this.ptr, path)); } - private static native String[] filetree(long self, String filter, boolean strict); + private static native String[] search_buffers(long self, String filter); /** - * Gets the file tree for this workspace, optionally filtering it. - * @param filter applies an optional filter to the outputs - * @param strict whether it should be a strict match (equals) or not (startsWith) + * Searches for buffers matching the filter in this workspace. + * @param filter the filter to apply * @return an array containing file tree as flat paths */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - public String[] filetree(Optional filter, boolean strict) { - return filetree(this.ptr, filter.orElse(null), strict); + public String[] searchBuffers(Optional filter) { + return search_buffers(this.ptr, filter.orElse(null)); } private static native String[] active_buffers(long self); @@ -125,37 +124,39 @@ public final class Workspace { return detach_buffer(this.ptr, path); } - private static native void fetch_buffers(long self) throws ConnectionRemoteException; + private static native String[] fetch_buffers(long self) throws ConnectionRemoteException; /** - * Updates the local list of buffers. + * Updates and fetches the local list of buffers. + * @return the updated list * @throws ConnectionRemoteException if an error occurs in communicating with the server */ - public void fetchBuffers() throws ConnectionRemoteException { - fetch_buffers(this.ptr); + public String[] fetchBuffers() throws ConnectionRemoteException { + return fetch_buffers(this.ptr); } - private static native void fetch_users(long self) throws ConnectionRemoteException; + private static native User[] fetch_users(long self) throws ConnectionRemoteException; /** - * Updates the local list of users. + * Updates and fetches the local list of users. + * @return the updated list * @throws ConnectionRemoteException if an error occurs in communicating with the server */ - public void fetchUsers() throws ConnectionRemoteException { - fetch_buffers(this.ptr); + public User[] fetchUsers() throws ConnectionRemoteException { + return fetch_users(this.ptr); } - private static native UUID[] list_buffer_users(long self, String path) throws ConnectionRemoteException; + private static native User[] fetch_buffer_users(long self, String path) throws ConnectionRemoteException; /** - * Lists the user attached to a certain buffer. + * Fetches the users attached to a certain buffer. * The user must be attached to the buffer to perform this operation. * @param path the path of the buffer to search - * @return an array of user {@link UUID UUIDs} + * @return an array of {@link User}s * @throws ConnectionRemoteException if an error occurs in communicating with the server, or the user wasn't attached */ - public UUID[] listBufferUsers(String path) throws ConnectionRemoteException { - return list_buffer_users(this.ptr, path); + public User[] fetchBufferUsers(String path) throws ConnectionRemoteException { + return fetch_buffer_users(this.ptr, path); } private static native void delete_buffer(long self, String path) throws ConnectionRemoteException; diff --git a/dist/lua/annotations.lua b/dist/lua/annotations.lua index 9a411ba..16b8a4f 100644 --- a/dist/lua/annotations.lua +++ b/dist/lua/annotations.lua @@ -158,6 +158,17 @@ function MaybeBufferUpdatePromise:cancel() end ---invoke callback asynchronously as soon as promise is ready function MaybeBufferUpdatePromise:and_then(cb) end +---@class (exact) UserListPromise : Promise +local UserListPromise = {} +--- block until promise is ready and return value +--- @return User[] +function UserListPromise:await() end +--- cancel promise execution +function UserListPromise:cancel() end +---@param cb fun(x: User[]) callback to invoke +---invoke callback asynchronously as soon as promise is ready +function UserListPromise:and_then(cb) end + -- [[ END ASYNC STUFF ]] @@ -212,13 +223,17 @@ function Client:delete_workspace(ws) end ---grant user acccess to workspace function Client:invite_to_workspace(ws, user) end ----@param owned boolean? list owned workspaces, default true ----@param invited boolean? list invited workspaces, default true ---@return StringArrayPromise ---@async ---@nodiscard ----grant user acccess to workspace -function Client:list_workspaces(owned, invited) end +---fetch and list owned workspaces +function Client:fetch_owned_workspaces() end + +---@return StringArrayPromise +---@async +---@nodiscard +---fetch and list joined workspaces +function Client:fetch_joined_workspaces() end ---@param ws string workspace id to get ---@return Workspace? @@ -281,10 +296,9 @@ function Workspace:attach_buffer(path) end function Workspace:detach_buffer(path) end ---@param filter? string apply a filter to the return elements ----@param strict? boolean whether to strictly match or just check whether it starts with it ---@return string[] ---return the list of available buffers in this workspace, as relative paths from workspace root -function Workspace:filetree(filter, strict) end +function Workspace:search_buffers(filter) end ---@return User[] ---return all names of users currently in this workspace @@ -302,6 +316,13 @@ function Workspace:fetch_buffers(path) end ---force refresh users list from workspace function Workspace:fetch_users(path) end +---@param path string the buffer to look in +---@return UserListPromise +---@async +---@nodiscard +---fetch the list of users in the given buffer +function Workspace:fetch_buffer_users(path) end + ---@class (exact) WorkspaceEvent ---@field type string ---@field value string diff --git a/dist/py/src/codemp/codemp.pyi b/dist/py/src/codemp/codemp.pyi index 438bdbe..9d32002 100644 --- a/dist/py/src/codemp/codemp.pyi +++ b/dist/py/src/codemp/codemp.pyi @@ -51,7 +51,8 @@ class Client: def create_workspace(self, workspace: str) -> Promise[None]: ... def delete_workspace(self, workspace: str) -> Promise[None]: ... def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ... - def list_workspaces(self, owned: bool, invited: bool) -> Promise[list[str]]: ... + def fetch_owned_workspaces(self) -> Promise[list[str]]: ... + def fetch_joined_workspaces(self) -> Promise[list[str]]: ... def leave_workspace(self, workspace: str) -> bool: ... def get_workspace(self, id: str) -> Workspace: ... def active_workspaces(self) -> list[str]: ... @@ -69,16 +70,16 @@ class Workspace: def create_buffer(self, path: str) -> Promise[None]: ... def attach_buffer(self, path: str) -> Promise[BufferController]: ... def detach_buffer(self, path: str) -> bool: ... - def fetch_buffers(self) -> Promise[None]: ... - def fetch_users(self) -> Promise[None]: ... - def list_buffer_users(self, path: str) -> Promise[list[str]]: ... + def fetch_buffers(self) -> Promise[list[str]]: ... + def fetch_users(self) -> Promise[list[User]]: ... + def fetch_buffer_users(self, path: str) -> Promise[list[User]]: ... def delete_buffer(self, path: str) -> Promise[None]: ... def id(self) -> str: ... def cursor(self) -> CursorController: ... def get_buffer(self, path: str) -> Optional[BufferController]: ... def user_list(self) -> list[User]: ... def active_buffers(self) -> list[str]: ... - def filetree(self, filter: Optional[str], strict: bool) -> list[str]: ... + def search_buffers(self, filter: Optional[str]) -> list[str]: ... def recv(self) -> Promise[Event]: ... def try_recv(self) -> Promise[Optional[Event]]: ... def poll(self) -> Promise[None]: ... diff --git a/src/api/mod.rs b/src/api/mod.rs index 158a4d0..9e27c22 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -19,11 +19,9 @@ pub mod event; /// data structure for remote users pub mod user; -pub use change::BufferUpdate; -pub use change::TextChange; +pub use change::{BufferUpdate, TextChange}; pub use config::Config; -pub use controller::Controller; -pub use cursor::Cursor; -pub use cursor::Selection; +pub use controller::{AsyncReceiver, AsyncSender, Controller}; +pub use cursor::{Cursor, Selection}; pub use event::Event; pub use user::User; diff --git a/src/buffer/worker.rs b/src/buffer/worker.rs index 19b25d7..8b7bc72 100644 --- a/src/buffer/worker.rs +++ b/src/buffer/worker.rs @@ -170,8 +170,11 @@ impl BufferWorker { // in case we have a "replace" span if change.is_delete() { - self.branch - .delete_without_content(&mut self.oplog, self.agent_id, clip_start..clip_end); + self.branch.delete_without_content( + &mut self.oplog, + self.agent_id, + clip_start..clip_end, + ); } if change.is_insert() { @@ -247,7 +250,9 @@ impl BufferWorker { { tracing::warn!( "Insert span ({}, {}) differs from effective content len ({})", - dtop.start(), dtop.end(), dtop.content_as_str().unwrap_or_default().len() + dtop.start(), + dtop.end(), + dtop.content_as_str().unwrap_or_default().len() ); } crate::api::BufferUpdate { diff --git a/src/client.rs b/src/client.rs index b7e7138..17ddcbb 100644 --- a/src/client.rs +++ b/src/client.rs @@ -130,9 +130,18 @@ impl Client { Ok(()) } - /// List all available workspaces, also filtering between those owned and those invited to. - pub async fn list_workspaces(&self, owned: bool, invited: bool) -> RemoteResult> { - let mut workspaces = self + /// Fetch the names of all workspaces owned by the current user. + pub async fn fetch_owned_workspaces(&self) -> RemoteResult> { + self.fetch_workspaces(true).await + } + + /// Fetch the names of all workspaces the current user has joined. + pub async fn fetch_joined_workspaces(&self) -> RemoteResult> { + self.fetch_workspaces(false).await + } + + async fn fetch_workspaces(&self, owned: bool) -> RemoteResult> { + let workspaces = self .0 .session .clone() @@ -140,20 +149,18 @@ impl Client { .await? .into_inner(); - let mut out = Vec::new(); - if owned { - out.append(&mut workspaces.owned) + Ok(workspaces.owned) + } else { + Ok(workspaces.invited) } - if invited { - out.append(&mut workspaces.invited) - } - - Ok(out) } /// Join and return a [`Workspace`]. - pub async fn attach_workspace(&self, workspace: impl AsRef) -> ConnectionResult { + pub async fn attach_workspace( + &self, + workspace: impl AsRef, + ) -> ConnectionResult { let token = self .0 .session diff --git a/src/ffi/java/buffer.rs b/src/ffi/java/buffer.rs index 5f06f8e..edd7b9a 100644 --- a/src/ffi/java/buffer.rs +++ b/src/ffi/java/buffer.rs @@ -2,10 +2,7 @@ use jni::{objects::JObject, JNIEnv}; use jni_toolbox::jni; use crate::{ - api::{ - controller::{AsyncReceiver, AsyncSender}, - BufferUpdate, TextChange, - }, + api::{AsyncReceiver, AsyncSender, BufferUpdate, TextChange}, errors::ControllerError, }; diff --git a/src/ffi/java/client.rs b/src/ffi/java/client.rs index a65d883..230b26a 100644 --- a/src/ffi/java/client.rs +++ b/src/ffi/java/client.rs @@ -46,14 +46,16 @@ fn invite_to_workspace( super::tokio().block_on(client.invite_to_workspace(workspace, user)) } -/// List available workspaces. +/// List owned workspaces. #[jni(package = "mp.code", class = "Client")] -fn list_workspaces( - client: &mut Client, - owned: bool, - invited: bool, -) -> Result, RemoteError> { - super::tokio().block_on(client.list_workspaces(owned, invited)) +fn fetch_owned_workspaces(client: &mut Client) -> Result, RemoteError> { + super::tokio().block_on(client.fetch_owned_workspaces()) +} + +/// List joined workspaces. +#[jni(package = "mp.code", class = "Client")] +fn fetch_joined_workspaces(client: &mut Client) -> Result, RemoteError> { + super::tokio().block_on(client.fetch_joined_workspaces()) } /// List available workspaces. diff --git a/src/ffi/java/cursor.rs b/src/ffi/java/cursor.rs index e08a788..4457ddc 100644 --- a/src/ffi/java/cursor.rs +++ b/src/ffi/java/cursor.rs @@ -1,8 +1,5 @@ use crate::{ - api::{ - controller::{AsyncReceiver, AsyncSender}, - Cursor, Selection, - }, + api::{AsyncReceiver, AsyncSender, Cursor, Selection}, errors::ControllerError, }; use jni::{objects::JObject, JNIEnv}; diff --git a/src/ffi/java/workspace.rs b/src/ffi/java/workspace.rs index 4cca434..3548a92 100644 --- a/src/ffi/java/workspace.rs +++ b/src/ffi/java/workspace.rs @@ -25,10 +25,10 @@ fn get_buffer(workspace: &mut Workspace, path: String) -> Option, strict: bool) -> Vec { - workspace.filetree(filter.as_deref(), strict) +fn search_buffers(workspace: &mut Workspace, filter: Option) -> Vec { + workspace.search_buffers(filter.as_deref()) } /// Gets a list of the active buffers. @@ -66,23 +66,23 @@ fn detach_buffer(workspace: &mut Workspace, path: String) -> bool { /// Update the local buffer list. #[jni(package = "mp.code", class = "Workspace")] -fn fetch_buffers(workspace: &mut Workspace) -> Result<(), RemoteError> { +fn fetch_buffers(workspace: &mut Workspace) -> Result, RemoteError> { super::tokio().block_on(workspace.fetch_buffers()) } /// Update the local user list. #[jni(package = "mp.code", class = "Workspace")] -fn fetch_users(workspace: &mut Workspace) -> Result<(), RemoteError> { +fn fetch_users(workspace: &mut Workspace) -> Result, RemoteError> { super::tokio().block_on(workspace.fetch_users()) } -/// List users attached to a buffer. +/// Fetch users attached to a buffer. #[jni(package = "mp.code", class = "Workspace")] -fn list_buffer_users( +fn fetch_buffer_users( workspace: &mut Workspace, path: String, ) -> Result, RemoteError> { - super::tokio().block_on(workspace.list_buffer_users(&path)) + super::tokio().block_on(workspace.fetch_buffer_users(&path)) } /// Delete a buffer. diff --git a/src/ffi/js/client.rs b/src/ffi/js/client.rs index fc92560..b6034f6 100644 --- a/src/ffi/js/client.rs +++ b/src/ffi/js/client.rs @@ -46,14 +46,16 @@ impl Client { Ok(self.delete_workspace(workspace).await?) } - #[napi(js_name = "listWorkspaces")] - /// list available workspaces - pub async fn js_list_workspaces( - &self, - owned: bool, - invited: bool, - ) -> napi::Result> { - Ok(self.list_workspaces(owned, invited).await?) + #[napi(js_name = "fetchOwnedWorkspaces")] + /// fetch owned workspaces + pub async fn js_fetch_owned_workspaces(&self) -> napi::Result> { + Ok(self.fetch_owned_workspaces().await?) + } + + #[napi(js_name = "fetchJoinedWorkspaces")] + /// fetch joined workspaces + pub async fn js_fetch_joined_workspaces(&self) -> napi::Result> { + Ok(self.fetch_joined_workspaces().await?) } #[napi(js_name = "inviteToWorkspace")] diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index c24658b..70b4c7d 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -44,9 +44,9 @@ impl Workspace { } /// List all available buffers in this workspace - #[napi(js_name = "filetree")] - pub fn js_filetree(&self, filter: Option<&str>, strict: bool) -> Vec { - self.filetree(filter, strict) + #[napi(js_name = "search_buffers")] + pub fn js_search_buffers(&self, filter: Option<&str>) -> Vec { + self.search_buffers(filter) } /// List all user names currently in this workspace @@ -121,7 +121,7 @@ impl Workspace { })?; self.callback(move |controller: Workspace| { tsfn.call(controller.clone(), ThreadsafeFunctionCallMode::Blocking); //check this with tracing also we could use Ok(event) to get the error - // If it blocks the main thread too many time we have to change this + // If it blocks the main thread too many time we have to change this }); Ok(()) @@ -137,23 +137,28 @@ impl Workspace { /// Re-fetch remote buffer list #[napi(js_name = "fetchBuffers")] - pub async fn js_fetch_buffers(&self) -> napi::Result<()> { + pub async fn js_fetch_buffers(&self) -> napi::Result> { Ok(self.fetch_buffers().await?) } /// Re-fetch the list of all users in the workspace. #[napi(js_name = "fetchUsers")] - pub async fn js_fetch_users(&self) -> napi::Result<()> { - Ok(self.fetch_users().await?) + pub async fn js_fetch_users(&self) -> napi::Result> { + Ok(self + .fetch_users() + .await? + .into_iter() + .map(JsUser::from) + .collect()) } /// List users attached to a specific buffer - #[napi(js_name = "listBufferUsers")] - pub async fn js_list_buffer_users( + #[napi(js_name = "fetchBufferUsers")] + pub async fn js_fetch_buffer_users( &self, path: String, ) -> napi::Result> { Ok(self - .list_buffer_users(&path) + .fetch_buffer_users(&path) .await? .into_iter() .map(super::client::JsUser::from) diff --git a/src/ffi/lua/client.rs b/src/ffi/lua/client.rs index cb54eff..4a8f4d2 100644 --- a/src/ffi/lua/client.rs +++ b/src/ffi/lua/client.rs @@ -12,8 +12,12 @@ impl LuaUserData for CodempClient { Ok(format!("{:?}", this)) }); - methods.add_method("current_user", |_, this, ()| Ok(this.current_user().clone())); - methods.add_method("active_workspaces", |_, this, ()| Ok(this.active_workspaces())); + methods.add_method("current_user", |_, this, ()| { + Ok(this.current_user().clone()) + }); + methods.add_method("active_workspaces", |_, this, ()| { + Ok(this.active_workspaces()) + }); methods.add_method( "refresh", @@ -39,8 +43,14 @@ impl LuaUserData for CodempClient { a_sync! { this => this.invite_to_workspace(ws, user).await? } ); - methods.add_method("list_workspaces", |_, this, (owned,invited):(Option,Option)| - a_sync! { this => this.list_workspaces(owned.unwrap_or(true), invited.unwrap_or(true)).await? } + methods.add_method( + "fetch_owned_workspaces", + |_, this, ()| a_sync! { this => this.fetch_owned_workspaces().await? }, + ); + + methods.add_method( + "fetch_joined_workspaces", + |_, this, ()| a_sync! { this => this.fetch_joined_workspaces().await? }, ); methods.add_method("leave_workspace", |_, this, (ws,): (String,)| { diff --git a/src/ffi/lua/ext/callback.rs b/src/ffi/lua/ext/callback.rs index 7c5f360..54d8e03 100644 --- a/src/ffi/lua/ext/callback.rs +++ b/src/ffi/lua/ext/callback.rs @@ -101,6 +101,7 @@ macro_rules! callback_args { callback_args! { Str: String, VecStr: Vec, + VecUser: Vec, Client: CodempClient, CursorController: CodempCursorController, BufferController: CodempBufferController, diff --git a/src/ffi/lua/workspace.rs b/src/ffi/lua/workspace.rs index dd80f05..2094f75 100644 --- a/src/ffi/lua/workspace.rs +++ b/src/ffi/lua/workspace.rs @@ -43,12 +43,15 @@ impl LuaUserData for CodempWorkspace { |_, this, ()| a_sync! { this => this.fetch_users().await? }, ); - methods.add_method( - "filetree", - |_, this, (filter, strict): (Option, Option)| { - Ok(this.filetree(filter.as_deref(), strict.unwrap_or(false))) - }, - ); + methods.add_method("search_buffers", |_, this, (filter,): (Option,)| { + Ok(this.search_buffers(filter.as_deref())) + }); + + methods.add_method("fetch_buffer_users", |_, this, (path,): (String,)| { + a_sync! { + this => this.fetch_buffer_users(&path).await? + } + }); methods.add_method("id", |_, this, ()| Ok(this.id())); methods.add_method("cursor", |_, this, ()| Ok(this.cursor())); diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 1ddd89a..686045b 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -5,26 +5,26 @@ //! ```no_run //! # async { //! use codemp::api::controller::{AsyncReceiver, AsyncSender}; // needed for send/recv trait methods -//! +//! //! // connect first, api.code.mp is managed by hexed.technology //! let client = codemp::Client::connect(codemp::api::Config::new( //! "mail@example.net", "dont-use-this-password" //! )).await?; -//! +//! //! // create and join a workspace //! client.create_workspace("some-workspace").await?; //! let workspace = client.join_workspace("some-workspace").await?; -//! +//! //! // create a new buffer in this workspace and attach to it //! workspace.create("/my/file.txt").await?; //! let buffer = workspace.attach("/my/file.txt").await?; -//! +//! //! // write `hello!` at the beginning of this buffer //! buffer.send(codemp::api::TextChange { //! start: 0, end: 0, //! content: "hello!".to_string(), //! })?; -//! +//! //! // wait for cursor movements //! loop { //! let event = workspace.cursor().recv().await?; @@ -42,26 +42,26 @@ //! //! ```js //! import * as codemp from 'codemp'; -//! +//! //! // connect first, api.code.mp is managed by hexed.technology //! let client = await codemp.connect({ //! username: "mail@example.net", password: "dont-use-this-password" //! }); -//! +//! //! // create and join a workspace //! await client.create_workspace("some-workspace"); //! let workspace = await client.join_workspace("some-workspace"); -//! +//! //! // create a new buffer in this workspace and attach to it //! await workspace.create("/my/file.txt"); //! let buffer = await workspace.attach("/my/file.txt"); -//! +//! //! // write `hello!` at the beginning of this buffer //! await buffer.send({ //! start: 0, end: 0, //! content: "hello!", //! }); -//! +//! //! // wait for cursor movements //! while (true) { //! let event = await workspace.cursor().recv(); @@ -78,26 +78,26 @@ //! //! ```py //! import codemp -//! +//! //! # connect first, api.code.mp is managed by hexed.technology //! config = codemp.get_default_config() //! config.username = "mail@example.net" //! config.password = "dont-use-this-password" //! client = codemp.connect(config).wait() -//! +//! //! # create and join a workspace //! client.create_workspace("some-workspace").wait() //! workspace = client.join_workspace("some-workspace").wait() -//! +//! //! # create a new buffer in this workspace and attach to it //! workspace.create("/my/file.txt").wait() //! buffer = workspace.attach("/my/file.txt").wait() -//! +//! //! # write `hello!` at the beginning of this buffer //! buffer.send( //! 0, 0, "hello!" //! ).wait() -//! +//! //! # wait for cursor movements //! while true: //! event = workspace.cursor().recv().wait() @@ -124,26 +124,26 @@ //! //! ```lua //! CODEMP = require('codemp') -//! +//! //! -- connect first, api.code.mp is managed by hexed.technology //! local client = CODEMP.connect({ //! username = "mail@example.net", password = "dont-use-this-password" //! }):await() -//! +//! //! -- create and join a workspace //! client:create_workspace("my-workspace"):await() //! local workspace = client:join_workspace("my-workspace"):await() -//! +//! //! -- create a new buffer in this workspace and attach to it //! workspace:create_buffer("/my/file.txt"):await() //! local buffer = workspace:attach_buffer("/my/file.txt"):await() -//! +//! //! -- write `hello!` at the beginning of this buffer //! buffer:send({ -//! start = 0, finish = 0, +//! start = 0, finish = 0, //! content = "hello!" //! }):await() -//! +//! //! -- wait for cursor movements //! while true do //! local event = workspace.cursor:recv():await() @@ -162,26 +162,26 @@ //! //! ```java //! import mp.code.*; -//! +//! //! // connect first, api.code.mp is managed by hexed.technology //! Client client = Client.connect( //! new data.Config("mail@example.net", "dont-use-this-password") //! ); -//! +//! //! // create and join a workspace //! client.createWorkspace("some-workspace"); //! Workspace workspace = client.joinWorkspace("some-workspace"); -//! +//! //! // create a new buffer in this workspace and attach to it //! workspace.createBuffer("/my/file.txt"); //! BufferController buffer = workspace.attachToBuffer("/my/file.txt"); -//! +//! //! // write `hello!` at the beginning of this buffer //! buffer.send(new data.TextChange( //! 0, 0, "hello!", //! java.util.OptionalLong.empty() // optional, used for error detection //! )); -//! +//! //! // wait for cursor movements //! while (true) { //! data.Cursor event = workspace.getCursor().recv(); diff --git a/src/ffi/python/client.rs b/src/ffi/python/client.rs index 7d63406..46bc033 100644 --- a/src/ffi/python/client.rs +++ b/src/ffi/python/client.rs @@ -55,16 +55,18 @@ impl Client { a_sync_allow_threads!(py, this.invite_to_workspace(workspace, user).await) } - #[pyo3(name = "list_workspaces")] - fn pylist_workspaces( - &self, - py: Python<'_>, - owned: bool, - invited: bool, - ) -> PyResult { - tracing::info!("attempting to list workspaces"); + #[pyo3(name = "fetch_owned_workspaces")] + fn pyfetch_owned_workspaces(&self, py: Python<'_>) -> PyResult { + tracing::info!("attempting to fetch owned workspaces"); let this = self.clone(); - a_sync_allow_threads!(py, this.list_workspaces(owned, invited).await) + a_sync_allow_threads!(py, this.fetch_owned_workspaces().await) + } + + #[pyo3(name = "fetch_joined_workspaces")] + fn pyfetch_joined_workspaces(&self, py: Python<'_>) -> PyResult { + tracing::info!("attempting to fetch joined workspaces"); + let this = self.clone(); + a_sync_allow_threads!(py, this.fetch_joined_workspaces().await) } #[pyo3(name = "leave_workspace")] diff --git a/src/ffi/python/workspace.rs b/src/ffi/python/workspace.rs index ed914f5..8d3c525 100644 --- a/src/ffi/python/workspace.rs +++ b/src/ffi/python/workspace.rs @@ -41,11 +41,11 @@ impl Workspace { a_sync_allow_threads!(py, this.fetch_users().await) } - #[pyo3(name = "list_buffer_users")] - fn pylist_buffer_users(&self, py: Python, path: String) -> PyResult { + #[pyo3(name = "fetch_buffer_users")] + fn pyfetch_buffer_users(&self, py: Python, path: String) -> PyResult { // crate::Result> let this = self.clone(); - a_sync_allow_threads!(py, this.list_buffer_users(path.as_str()).await) + a_sync_allow_threads!(py, this.fetch_buffer_users(path.as_str()).await) } #[pyo3(name = "delete_buffer")] @@ -74,10 +74,10 @@ impl Workspace { self.active_buffers() } - #[pyo3(name = "filetree")] - #[pyo3(signature = (filter=None, strict=false))] - fn pyfiletree(&self, filter: Option<&str>, strict: bool) -> Vec { - self.filetree(filter, strict) + #[pyo3(name = "search_buffers")] + #[pyo3(signature = (filter=None))] + fn pysearch_buffers(&self, filter: Option<&str>) -> Vec { + self.search_buffers(filter) } #[pyo3(name = "user_list")] diff --git a/src/prelude.rs b/src/prelude.rs index 71bb813..5f96584 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -2,7 +2,7 @@ //! All-in-one renamed imports with `use codemp::prelude::*`. pub use crate::api::{ - controller::AsyncReceiver as CodempAsyncReceiver, controller::AsyncSender as CodempAsyncSender, + AsyncReceiver as CodempAsyncReceiver, AsyncSender as CodempAsyncSender, BufferUpdate as CodempBufferUpdate, Config as CodempConfig, Controller as CodempController, Cursor as CodempCursor, Event as CodempEvent, Selection as CodempSelection, TextChange as CodempTextChange, User as CodempUser, diff --git a/src/workspace.rs b/src/workspace.rs index 8d04910..f8054fc 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -26,7 +26,7 @@ use codemp_proto::{ }; use dashmap::{DashMap, DashSet}; -use std::{collections::BTreeSet, sync::Arc}; +use std::sync::Arc; use tokio::sync::{mpsc, mpsc::error::TryRecvError}; use tonic::Streaming; use uuid::Uuid; @@ -201,45 +201,48 @@ impl Workspace { } /// Re-fetch the list of available buffers in the workspace. - pub async fn fetch_buffers(&self) -> RemoteResult<()> { + pub async fn fetch_buffers(&self) -> RemoteResult> { let mut workspace_client = self.0.services.ws(); - let buffers = workspace_client + let resp = workspace_client .list_buffers(tonic::Request::new(Empty {})) .await? - .into_inner() - .buffers; + .into_inner(); + + let mut out = Vec::new(); self.0.filetree.clear(); - for b in buffers { - self.0.filetree.insert(b.path); + for b in resp.buffers { + self.0.filetree.insert(b.path.clone()); + out.push(b.path); } - Ok(()) + Ok(out) } /// Re-fetch the list of all users in the workspace. - pub async fn fetch_users(&self) -> RemoteResult<()> { + pub async fn fetch_users(&self) -> RemoteResult> { let mut workspace_client = self.0.services.ws(); - let users = BTreeSet::from_iter( - workspace_client - .list_users(tonic::Request::new(Empty {})) - .await? - .into_inner() - .users - .into_iter() - .map(User::from), - ); + let users = workspace_client + .list_users(tonic::Request::new(Empty {})) + .await? + .into_inner() + .users + .into_iter() + .map(User::from); + + let mut result = Vec::new(); self.0.users.clear(); for u in users { - self.0.users.insert(u.id, u); + self.0.users.insert(u.id, u.clone()); + result.push(u); } - Ok(()) + Ok(result) } - /// Get a list of the [User]s attached to a specific buffer. - pub async fn list_buffer_users(&self, path: &str) -> RemoteResult> { + /// Fetch a list of the [User]s attached to a specific buffer. + pub async fn fetch_buffer_users(&self, path: &str) -> RemoteResult> { let mut workspace_client = self.0.services.ws(); let buffer_users = workspace_client .list_buffer_users(tonic::Request::new(BufferNode { @@ -311,20 +314,12 @@ impl Workspace { /// Get the filetree as it is currently cached. /// A filter may be applied, and it may be strict (equality check) or not (starts_with check). // #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120 - pub fn filetree(&self, filter: Option<&str>, strict: bool) -> Vec { + pub fn search_buffers(&self, filter: Option<&str>) -> Vec { let mut tree = self .0 .filetree .iter() - .filter(|f| { - filter.map_or(true, |flt| { - if strict { - f.as_str() == flt - } else { - f.starts_with(flt) - } - }) - }) + .filter(|f| filter.map_or(true, |flt| f.starts_with(flt))) .map(|f| f.clone()) .collect::>(); tree.sort(); From 4363bdfa7ef972f8f0e8faf86b0f57a050f34ec8 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 16 Oct 2024 00:43:19 +0200 Subject: [PATCH 11/19] chore: dep version bump --- Cargo.lock | 327 ++++++++++++++++++++++++++++------------------------- 1 file changed, 173 insertions(+), 154 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb7e87a..777cfca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -49,9 +49,9 @@ checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -60,24 +60,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -88,15 +88,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -114,16 +114,16 @@ dependencies = [ "rustversion", "serde", "sync_wrapper 1.0.1", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -134,7 +134,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", ] @@ -190,15 +190,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.1.20" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bcde016d64c21da4be18b655631e5ab6d3107607e71a73a9f53eb48aae23fb" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "shlex", ] @@ -343,7 +343,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -440,36 +440,36 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-task", @@ -490,9 +490,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -512,7 +512,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.5.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -531,6 +531,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "heck" version = "0.5.0" @@ -579,9 +585,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -597,9 +603,9 @@ checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -631,9 +637,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", @@ -644,7 +650,6 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] @@ -684,12 +689,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -749,9 +754,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jni-toolbox" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeae2881d819e208fcfceea81eb5a8ca6c131c6fb1605dfe2f3a31dea061ec7c" +checksum = "cce03cf89bc32b81de142a323a71e9903ee88127a0e04bbd7f215ab74ab6b10a" dependencies = [ "jni", "jni-toolbox-macro", @@ -760,20 +765,20 @@ dependencies = [ [[package]] name = "jni-toolbox-macro" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e480850db18f0cc95120e7bf86af772c31b3c0f0dd3d3600682d8bd8399f4ae" +checksum = "609491ce00edcf12946945a514d033bf6e8bfbab02c6a25a46ed8cd4749707da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -796,9 +801,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libloading" @@ -935,7 +940,7 @@ checksum = "13e6f40fa1fd8426285688f4a37b56beac69284743d057ee6db352b543f4b621" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -946,9 +951,9 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "napi" -version = "2.16.10" +version = "2.16.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04409e8c2d61995696e44d2181b79b68c1dd41f7e24a17cde60bbd9f54ddddef" +checksum = "3a84fdaf64da2b2d86b1be5db1b81963353bf00f7bef4b9e2668bbe6f72e8eb3" dependencies = [ "bitflags", "chrono", @@ -979,7 +984,7 @@ dependencies = [ "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -994,7 +999,7 @@ dependencies = [ "quote", "regex", "semver", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1048,18 +1053,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl-probe" @@ -1118,27 +1123,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.5.0", + "indexmap 2.6.0", ] [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1155,15 +1160,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "ppv-lite86" @@ -1181,7 +1186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1196,18 +1201,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", "prost-derive", @@ -1215,9 +1220,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", "heck", @@ -1230,37 +1235,37 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.77", + "syn 2.0.79", "tempfile", ] [[package]] name = "prost-derive" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "prost-types" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" dependencies = [ "prost", ] [[package]] name = "pyo3" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225" +checksum = "3d922163ba1f79c04bc49073ba7b32fd5a8d3b76a87c955921234b8e77333c51" dependencies = [ "cfg-if", "indoc", @@ -1276,9 +1281,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3" +checksum = "bc38c5feeb496c8321091edf3d63e9a6829eab4b863b4a6a65f26f3e9cc6b179" dependencies = [ "once_cell", "target-lexicon", @@ -1286,9 +1291,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c" +checksum = "94845622d88ae274d2729fcefc850e63d7a3ddff5e3ce11bd88486db9f1d357d" dependencies = [ "libc", "pyo3-build-config", @@ -1296,27 +1301,27 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28" +checksum = "e655aad15e09b94ffdb3ce3d217acf652e26bbc37697ef012f5e5e348c716e5e" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "pyo3-macros-backend" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1" +checksum = "ae1e3f09eecd94618f60a455a23def79f79eba4dc561a97324bf9ac8c6df30ce" dependencies = [ "heck", "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1360,18 +1365,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", @@ -1381,9 +1386,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", @@ -1392,9 +1397,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ring" @@ -1447,9 +1452,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "log", "once_cell", @@ -1462,9 +1467,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -1475,19 +1480,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -1502,9 +1506,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -1523,9 +1527,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ "windows-sys 0.59.0", ] @@ -1551,9 +1555,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -1592,7 +1596,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1701,9 +1705,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -1730,9 +1734,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -1743,22 +1747,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1795,7 +1799,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1845,16 +1849,16 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "toml_datetime", "winnow", ] [[package]] name = "tonic" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", @@ -1877,7 +1881,7 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-stream", - "tower", + "tower 0.4.13", "tower-layer", "tower-service", "tracing", @@ -1885,15 +1889,16 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" dependencies = [ "prettyplease", "proc-macro2", "prost-build", + "prost-types", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1916,6 +1921,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -1947,7 +1966,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2080,9 +2099,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -2091,24 +2110,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2116,22 +2135,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "winapi" @@ -2354,7 +2373,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] From e1e09cb20e4e876a62364b882481244a7a0b4502 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 16 Oct 2024 00:51:52 +0200 Subject: [PATCH 12/19] fix: doctests --- src/ffi/mod.rs | 26 +++++++++++++------------- src/lib.rs | 10 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 686045b..0de8500 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -13,11 +13,11 @@ //! //! // create and join a workspace //! client.create_workspace("some-workspace").await?; -//! let workspace = client.join_workspace("some-workspace").await?; +//! let workspace = client.attach_workspace("some-workspace").await?; //! //! // create a new buffer in this workspace and attach to it -//! workspace.create("/my/file.txt").await?; -//! let buffer = workspace.attach("/my/file.txt").await?; +//! workspace.create_buffer("/my/file.txt").await?; +//! let buffer = workspace.attach_buffer("/my/file.txt").await?; //! //! // write `hello!` at the beginning of this buffer //! buffer.send(codemp::api::TextChange { @@ -49,12 +49,12 @@ //! }); //! //! // create and join a workspace -//! await client.create_workspace("some-workspace"); -//! let workspace = await client.join_workspace("some-workspace"); +//! await client.createWorkspace("some-workspace"); +//! let workspace = await client.attachWorkspace("some-workspace"); //! //! // create a new buffer in this workspace and attach to it -//! await workspace.create("/my/file.txt"); -//! let buffer = await workspace.attach("/my/file.txt"); +//! await workspace.createBuffer("/my/file.txt"); +//! let buffer = await workspace.attachBuffer("/my/file.txt"); //! //! // write `hello!` at the beginning of this buffer //! await buffer.send({ @@ -87,11 +87,11 @@ //! //! # create and join a workspace //! client.create_workspace("some-workspace").wait() -//! workspace = client.join_workspace("some-workspace").wait() +//! workspace = client.attach_workspace("some-workspace").wait() //! //! # create a new buffer in this workspace and attach to it //! workspace.create("/my/file.txt").wait() -//! buffer = workspace.attach("/my/file.txt").wait() +//! buffer = workspace.attach_buffer("/my/file.txt").wait() //! //! # write `hello!` at the beginning of this buffer //! buffer.send( @@ -132,7 +132,7 @@ //! //! -- create and join a workspace //! client:create_workspace("my-workspace"):await() -//! local workspace = client:join_workspace("my-workspace"):await() +//! local workspace = client:attach_workspace("my-workspace"):await() //! //! -- create a new buffer in this workspace and attach to it //! workspace:create_buffer("/my/file.txt"):await() @@ -170,11 +170,11 @@ //! //! // create and join a workspace //! client.createWorkspace("some-workspace"); -//! Workspace workspace = client.joinWorkspace("some-workspace"); +//! Workspace workspace = client.attachWorkspace("some-workspace"); //! //! // create a new buffer in this workspace and attach to it //! workspace.createBuffer("/my/file.txt"); -//! BufferController buffer = workspace.attachToBuffer("/my/file.txt"); +//! BufferController buffer = workspace.attachBuffer("/my/file.txt"); //! //! // write `hello!` at the beginning of this buffer //! buffer.send(new data.TextChange( @@ -184,7 +184,7 @@ //! //! // wait for cursor movements //! while (true) { -//! data.Cursor event = workspace.getCursor().recv(); +//! data.Cursor event = workspace.cursor().recv(); //! System.out.printf("user %s moved on buffer %s\n", event.user, event.buffer); //! } //! ``` diff --git a/src/lib.rs b/src/lib.rs index 8ddf2c8..304e7c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,13 +32,13 @@ //! ``` //! //! A [`Client`] can acquire a [`Workspace`] handle by joining an existing one it can access with -//! [`Client::join_workspace`] or create a new one with [`Client::create_workspace`]. +//! [`Client::attach_workspace`] or create a new one with [`Client::create_workspace`]. //! //! ```no_run //! # async { //! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap(); //! client.create_workspace("my-workspace").await.expect("failed to create workspace!"); -//! let workspace = client.join_workspace("my-workspace").await.expect("failed to attach!"); +//! let workspace = client.attach_workspace("my-workspace").await.expect("failed to attach!"); //! # }; //! ``` //! @@ -49,7 +49,7 @@ //! # async { //! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap(); //! # client.create_workspace("").await.unwrap(); -//! # let workspace = client.join_workspace("").await.unwrap(); +//! # let workspace = client.attach_workspace("").await.unwrap(); //! use codemp::api::controller::{AsyncSender, AsyncReceiver}; // needed to access trait methods //! let cursor = workspace.cursor(); //! let event = cursor.recv().await.expect("disconnected while waiting for event!"); @@ -65,9 +65,9 @@ //! # async { //! # let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap(); //! # client.create_workspace("").await.unwrap(); -//! # let workspace = client.join_workspace("").await.unwrap(); +//! # let workspace = client.attach_workspace("").await.unwrap(); //! # use codemp::api::controller::{AsyncSender, AsyncReceiver}; -//! let buffer = workspace.attach("/some/file.txt").await.expect("failed to attach"); +//! let buffer = workspace.attach_buffer("/some/file.txt").await.expect("failed to attach"); //! buffer.content(); // force-sync //! if let Some(mut update) = buffer.try_recv().await.unwrap() { //! println!( From 332621705852c30265f34a56543be4e5022ddd88 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 16 Oct 2024 02:46:20 +0200 Subject: [PATCH 13/19] feat(python): better struct access Co-authored-by: alemi --- Cargo.lock | 7 + Cargo.toml | 2 +- dist/java/src/mp/code/data/TextChange.java | 1 - dist/py/src/codemp/codemp.pyi | 2 +- src/api/user.rs | 2 + src/ffi/mod.rs | 15 ++- src/ffi/python/mod.rs | 144 ++++++++++++++++++--- 7 files changed, 144 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 777cfca..cbb8786 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -703,6 +703,12 @@ version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +[[package]] +name = "inventory" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" + [[package]] name = "itertools" version = "0.13.0" @@ -1269,6 +1275,7 @@ checksum = "3d922163ba1f79c04bc49073ba7b32fd5a8d3b76a87c955921234b8e77333c51" dependencies = [ "cfg-if", "indoc", + "inventory", "libc", "memoffset", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index f867898..5c3f4d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ napi = { version = "2.16", features = ["full"], optional = true } napi-derive = { version="2.16", optional = true} # glue (python) -pyo3 = { version = "0.22", features = ["extension-module"], optional = true} +pyo3 = { version = "0.22", features = ["extension-module", "multiple-pymethods"], optional = true} # extra async-trait = { version = "0.1", optional = true } diff --git a/dist/java/src/mp/code/data/TextChange.java b/dist/java/src/mp/code/data/TextChange.java index 3c0a0f9..bcd72c2 100644 --- a/dist/java/src/mp/code/data/TextChange.java +++ b/dist/java/src/mp/code/data/TextChange.java @@ -13,7 +13,6 @@ import java.util.OptionalLong; @ToString @EqualsAndHashCode @RequiredArgsConstructor -@SuppressWarnings("OptionalUsedAsFieldOrParameterType") public class TextChange { /** * The starting position of the change. diff --git a/dist/py/src/codemp/codemp.pyi b/dist/py/src/codemp/codemp.pyi index 9d32002..e4cfa2e 100644 --- a/dist/py/src/codemp/codemp.pyi +++ b/dist/py/src/codemp/codemp.pyi @@ -24,7 +24,7 @@ class Config: port: Optional[int] tls: Optional[bool] - def __new__(cls, *, username: str, password: str, **kwargs) -> Config: ... + def __new__(cls, username: str, password: str, **kwargs) -> Config: ... def init() -> Driver: ... def set_logger(logger_cb: Callable[[str], None], debug: bool) -> bool: ... diff --git a/src/api/user.rs b/src/api/user.rs index 2b610f9..47d133c 100644 --- a/src/api/user.rs +++ b/src/api/user.rs @@ -6,11 +6,13 @@ use uuid::Uuid; /// Represents a service user #[derive(Debug, Clone)] +#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct User { /// User unique identifier, should never change. pub id: Uuid, /// User name, can change but should be unique. + #[pyo3(get, set)] pub name: String, } diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 0de8500..5c5346d 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -80,10 +80,9 @@ //! import codemp //! //! # connect first, api.code.mp is managed by hexed.technology -//! config = codemp.get_default_config() -//! config.username = "mail@example.net" -//! config.password = "dont-use-this-password" -//! client = codemp.connect(config).wait() +//! client = codemp.connect( +//! codemp.Config('mail@example.net', 'dont-use-this-password') +//! ).wait() //! //! # create and join a workspace //! client.create_workspace("some-workspace").wait() @@ -94,14 +93,16 @@ //! buffer = workspace.attach_buffer("/my/file.txt").wait() //! //! # write `hello!` at the beginning of this buffer -//! buffer.send( -//! 0, 0, "hello!" -//! ).wait() +//! buffer.send(codemp.TextChange( +//! start=0, end=0, +//! content="hello!" +//! )).wait() //! //! # wait for cursor movements //! while true: //! event = workspace.cursor().recv().wait() //! print(f"user {event.user} moved on buffer {event.buffer}") +//! //! ``` //! //! ## Lua diff --git a/src/ffi/python/mod.rs b/src/ffi/python/mod.rs index bbeb91b..75e7695 100644 --- a/src/ffi/python/mod.rs +++ b/src/ffi/python/mod.rs @@ -3,14 +3,14 @@ pub mod controllers; pub mod workspace; use crate::{ - api::{Config, Cursor, TextChange}, + api::{BufferUpdate, Config, Cursor, Selection, TextChange, User}, buffer::Controller as BufferController, cursor::Controller as CursorController, Client, Workspace, }; -use pyo3::prelude::*; use pyo3::{ + prelude::*, exceptions::{PyConnectionError, PyRuntimeError, PySystemError}, types::PyDict, }; @@ -153,19 +153,28 @@ fn init() -> PyResult { Ok(Driver(Some(rt_stop_tx))) } -#[pyfunction] -fn get_default_config() -> crate::api::Config { - let mut conf = crate::api::Config::new("".to_string(), "".to_string()); - conf.host = Some(conf.host().to_string()); - conf.port = Some(conf.port()); - conf.tls = Some(false); - conf +#[pymethods] +impl User { + #[getter] + fn get_id(&self) -> pyo3::PyResult { + Ok(self.id.to_string()) + } + + #[setter] + fn set_id(&mut self, value: String) -> pyo3::PyResult<()> { + self.id = value.parse().map_err(|x: ::Err| pyo3::exceptions::PyRuntimeError::new_err(x.to_string()))?; + Ok(()) + } + + fn __str__(&self) -> String { + format!("{self:?}") + } } #[pymethods] impl Config { #[new] - #[pyo3(signature = (*, username, password, **kwds))] + #[pyo3(signature = (username, password, **kwds))] pub fn pynew( username: String, password: String, @@ -176,7 +185,7 @@ impl Config { let port = kwgs.get_item("port")?.and_then(|e| e.extract().ok()); let tls = kwgs.get_item("tls")?.and_then(|e| e.extract().ok()); - Ok(Config { + Ok(Self { username, password, host, @@ -184,9 +193,109 @@ impl Config { tls, }) } else { - Ok(Config::new(username, password)) + Ok(Self::new(username, password)) } } + + fn __str__(&self) -> String { + format!("{self:?}") + } +} + +#[pymethods] +impl Cursor { + fn __str__(&self) -> String { + format!("{self:?}") + } +} + +#[pymethods] +impl Selection { + #[new] + #[pyo3(signature = (**kwds))] + pub fn py_new(kwds: Option<&Bound<'_, PyDict>>) -> PyResult { + if let Some(kwds) = kwds { + let start_row = if let Some(e) = kwds.get_item("start_row")? { + e.extract()? + } else { + 0 + }; + + let start_col = if let Some(e) = kwds.get_item("start_col")? { + e.extract()? + } else { + 0 + }; + + let end_row = if let Some(e) = kwds.get_item("end_row")? { + e.extract()? + } else { + 0 + }; + + let end_col = if let Some(e) = kwds.get_item("end_col")? { + e.extract()? + } else { + 0 + }; + + let buffer = if let Some(e) = kwds.get_item("buffer")? { + e.extract()? + } else { + String::default() + }; + + Ok(Self { start_row, start_col, end_row, end_col, buffer }) + } else { + Ok(Self::default()) + } + } + + fn __str__(&self) -> String { + format!("{self:?}") + } +} + +#[pymethods] +impl BufferUpdate { + fn __str__(&self) -> String { + format!("{self:?}") + } +} + +#[pymethods] +impl TextChange { + #[new] + #[pyo3(signature = (**kwds))] + pub fn py_new(kwds: Option<&Bound<'_, PyDict>>) -> PyResult { + if let Some(kwds) = kwds { + let start = if let Some(e) = kwds.get_item("start")? { + e.extract()? + } else { + 0 + }; + + let end = if let Some(e) = kwds.get_item("end")? { + e.extract()? + } else { + 0 + }; + + let content = if let Some(e) = kwds.get_item("content")? { + e.extract()? + } else { + String::default() + }; + + Ok(Self { start, end, content }) + } else { + Ok(Self::default()) + } + } + + fn __str__(&self) -> String { + format!("{self:?}") + } } #[pyfunction] @@ -254,27 +363,24 @@ impl From for PyErr { } } -impl IntoPy for crate::api::User { - fn into_py(self, py: Python<'_>) -> PyObject { - self.id.to_string().into_py(py) - } -} - #[pymodule] fn codemp(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(version, m)?)?; m.add_function(wrap_pyfunction!(init, m)?)?; - m.add_function(wrap_pyfunction!(get_default_config, m)?)?; m.add_function(wrap_pyfunction!(connect, m)?)?; m.add_function(wrap_pyfunction!(set_logger, m)?)?; m.add_class::()?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; m.add_class::()?; + m.add_class::()?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; From 4b5ed06bb722b9e7466d881e46a480155baf46d7 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 16 Oct 2024 03:11:40 +0200 Subject: [PATCH 14/19] chore: renamed TextChange and Event fields Co-authored-by: alemi --- dist/java/src/mp/code/data/TextChange.java | 10 +-- dist/lua/annotations.lua | 4 +- dist/py/src/codemp/codemp.pyi | 96 ++++++++++------------ src/api/change.rs | 33 ++++---- src/api/event.rs | 18 ++-- src/buffer/worker.rs | 12 +-- src/ffi/java/mod.rs | 18 ++-- src/ffi/js/workspace.rs | 6 +- src/ffi/mod.rs | 8 +- src/ffi/python/controllers.rs | 25 +----- src/ffi/python/mod.rs | 28 +++++-- 11 files changed, 124 insertions(+), 134 deletions(-) diff --git a/dist/java/src/mp/code/data/TextChange.java b/dist/java/src/mp/code/data/TextChange.java index bcd72c2..023869f 100644 --- a/dist/java/src/mp/code/data/TextChange.java +++ b/dist/java/src/mp/code/data/TextChange.java @@ -18,13 +18,13 @@ public class TextChange { * The starting position of the change. * If negative, it is clamped to 0. */ - public final long start; + public final long startIdx; /** * The ending position of the change. * If negative, it is clamped to 0. */ - public final long end; + public final long endIdx; /** * The content of the change. @@ -39,7 +39,7 @@ public class TextChange { * @return true if this change represents a deletion */ public boolean isDelete() { - return this.start < this.end; + return this.startIdx < this.endIdx; } /** @@ -66,14 +66,14 @@ public class TextChange { * @return the mutated string */ public String apply(String input) { - long preIndex = Math.min(this.start, input.length()); + long preIndex = Math.min(this.startIdx, input.length()); String pre = ""; try { pre = input.substring(0, (int) preIndex); } catch(IndexOutOfBoundsException ignored) {} String post = ""; try { - post = input.substring((int) this.end); + post = input.substring((int) this.endIdx); } catch(IndexOutOfBoundsException ignored) {} return pre + this.content + post; } diff --git a/dist/lua/annotations.lua b/dist/lua/annotations.lua index 16b8a4f..df02187 100644 --- a/dist/lua/annotations.lua +++ b/dist/lua/annotations.lua @@ -361,8 +361,8 @@ local BufferController = {} ---@class TextChange ---@field content string text content of change ----@field start integer start index of change ----@field finish integer end index of change +---@field start_idx integer start index of change +---@field end_idx integer end index of change local TextChange = {} ---@class (exact) BufferUpdate diff --git a/dist/py/src/codemp/codemp.pyi b/dist/py/src/codemp/codemp.pyi index e4cfa2e..5b09cb5 100644 --- a/dist/py/src/codemp/codemp.pyi +++ b/dist/py/src/codemp/codemp.pyi @@ -39,25 +39,25 @@ class Promise[T]: It can either be used directly or you can wrap it inside a future python side. """ - def wait(self) -> T: ... - def is_done(self) -> bool: ... + def wait(self) -> T: ... + def is_done(self) -> bool: ... class Client: """ Handle to the actual client that manages the session. It manages the connection to a server and joining/creating new workspaces """ - def attach_workspace(self, workspace: str) -> Promise[Workspace]: ... - def create_workspace(self, workspace: str) -> Promise[None]: ... - def delete_workspace(self, workspace: str) -> Promise[None]: ... + def attach_workspace(self, workspace: str) -> Promise[Workspace]: ... + def create_workspace(self, workspace: str) -> Promise[None]: ... + def delete_workspace(self, workspace: str) -> Promise[None]: ... def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ... - def fetch_owned_workspaces(self) -> Promise[list[str]]: ... - def fetch_joined_workspaces(self) -> Promise[list[str]]: ... - def leave_workspace(self, workspace: str) -> bool: ... - def get_workspace(self, id: str) -> Workspace: ... - def active_workspaces(self) -> list[str]: ... - def current_user(self) -> User: ... - def refresh(self) -> Promise[None]: ... + def fetch_owned_workspaces(self) -> Promise[list[str]]: ... + def fetch_joined_workspaces(self) -> Promise[list[str]]: ... + def leave_workspace(self, workspace: str) -> bool: ... + def get_workspace(self, id: str) -> Workspace: ... + def active_workspaces(self) -> list[str]: ... + def current_user(self) -> User: ... + def refresh(self) -> Promise[None]: ... class Event: pass @@ -67,23 +67,23 @@ class Workspace: Handle to a workspace inside codemp. It manages buffers. A cursor is tied to the single workspace. """ - def create_buffer(self, path: str) -> Promise[None]: ... - def attach_buffer(self, path: str) -> Promise[BufferController]: ... - def detach_buffer(self, path: str) -> bool: ... - def fetch_buffers(self) -> Promise[list[str]]: ... - def fetch_users(self) -> Promise[list[User]]: ... - def fetch_buffer_users(self, path: str) -> Promise[list[User]]: ... - def delete_buffer(self, path: str) -> Promise[None]: ... - def id(self) -> str: ... - def cursor(self) -> CursorController: ... - def get_buffer(self, path: str) -> Optional[BufferController]: ... - def user_list(self) -> list[User]: ... - def active_buffers(self) -> list[str]: ... + def create_buffer(self, path: str) -> Promise[None]: ... + def attach_buffer(self, path: str) -> Promise[BufferController]: ... + def detach_buffer(self, path: str) -> bool: ... + def fetch_buffers(self) -> Promise[list[str]]: ... + def fetch_users(self) -> Promise[list[User]]: ... + def fetch_buffer_users(self, path: str) -> Promise[list[User]]: ... + def delete_buffer(self, path: str) -> Promise[None]: ... + def id(self) -> str: ... + def cursor(self) -> CursorController: ... + def get_buffer(self, path: str) -> Optional[BufferController]: ... + def user_list(self) -> list[User]: ... + def active_buffers(self) -> list[str]: ... def search_buffers(self, filter: Optional[str]) -> list[str]: ... - def recv(self) -> Promise[Event]: ... - def try_recv(self) -> Promise[Optional[Event]]: ... - def poll(self) -> Promise[None]: ... - def clear_callback(self) -> None: ... + def recv(self) -> Promise[Event]: ... + def try_recv(self) -> Promise[Optional[Event]]: ... + def poll(self) -> Promise[None]: ... + def clear_callback(self) -> None: ... def callback(self, cb: Callable[[Workspace], None]) -> None: ... class TextChange: @@ -95,10 +95,10 @@ class TextChange: end: int content: str - def is_delete(self) -> bool: ... - def is_insert(self) -> bool: ... - def is_empty(self) -> bool: ... - def apply(self, txt: str) -> str: ... + def is_delete(self) -> bool: ... + def is_insert(self) -> bool: ... + def is_empty(self) -> bool: ... + def apply(self, txt: str) -> str: ... class BufferUpdate: """ @@ -114,19 +114,16 @@ class BufferController: Handle to the controller for a specific buffer, which manages the back and forth of operations to and from other peers. """ - def path(self) -> str: ... - def content(self) -> Promise[str]: ... - def ack(self, v: list[int]) -> None: ... - def send(self, - start: int, - end: int, - txt: str) -> Promise[None]: ... - def try_recv(self) -> Promise[Optional[TextChange]]: ... - def recv(self) -> Promise[TextChange]: ... - def poll(self) -> Promise[None]: ... + def path(self) -> str: ... + def content(self) -> Promise[str]: ... + def ack(self, v: list[int]) -> None: ... + def send(self, op: TextChange) -> None: ... + def try_recv(self) -> Promise[Optional[TextChange]]: ... + def recv(self) -> Promise[TextChange]: ... + def poll(self) -> Promise[None]: ... def callback(self, cb: Callable[[BufferController], None]) -> None: ... - def clear_callback(self) -> None: ... + def clear_callback(self) -> None: ... @@ -151,14 +148,11 @@ class CursorController: Handle to the controller for a workspace, which manages the back and forth of cursor movements to and from other peers """ - def send(self, - path: str, - start: Tuple[int, int], - end: Tuple[int, int]) -> Promise[None]: ... - def try_recv(self) -> Promise[Optional[Cursor]]: ... - def recv(self) -> Promise[Cursor]: ... - def poll(self) -> Promise[None]: ... + def send(self, pos: Selection) -> None: ... + def try_recv(self) -> Promise[Optional[Cursor]]: ... + def recv(self) -> Promise[Cursor]: ... + def poll(self) -> Promise[None]: ... def callback(self, cb: Callable[[CursorController], None]) -> None: ... - def clear_callback(self) -> None: ... + def clear_callback(self) -> None: ... diff --git a/src/api/change.rs b/src/api/change.rs index 6270e37..b52cc5c 100644 --- a/src/api/change.rs +++ b/src/api/change.rs @@ -55,10 +55,9 @@ pub struct BufferUpdate { #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct TextChange { /// Range start of text change, as char indexes in buffer previous state. - pub start: u32, + pub start_idx: u32, /// Range end of text change, as char indexes in buffer previous state. - #[cfg_attr(feature = "serialize", serde(alias = "finish"))] // Lua uses `end` as keyword - pub end: u32, + pub end_idx: u32, /// New content of text inside span. pub content: String, } @@ -66,7 +65,7 @@ pub struct TextChange { impl TextChange { /// Returns the [`std::ops::Range`] representing this change's span. pub fn span(&self) -> std::ops::Range { - self.start as usize..self.end as usize + self.start_idx as usize..self.end_idx as usize } } @@ -76,7 +75,7 @@ impl TextChange { /// /// Note that this is is **not** mutually exclusive with [TextChange::is_insert]. pub fn is_delete(&self) -> bool { - self.start < self.end + self.start_idx < self.end_idx } /// Returns true if this [`TextChange`] adds new text. @@ -93,9 +92,9 @@ impl TextChange { /// Applies this text change to given text, returning a new string. pub fn apply(&self, txt: &str) -> String { - let pre_index = std::cmp::min(self.start as usize, txt.len()); + let pre_index = std::cmp::min(self.start_idx as usize, txt.len()); let pre = txt.get(..pre_index).unwrap_or("").to_string(); - let post = txt.get(self.end as usize..).unwrap_or("").to_string(); + let post = txt.get(self.end_idx as usize..).unwrap_or("").to_string(); format!("{}{}{}", pre, self.content, post) } } @@ -105,8 +104,8 @@ mod tests { #[test] fn textchange_apply_works_for_insertions() { let change = super::TextChange { - start: 5, - end: 5, + start_idx: 5, + end_idx: 5, content: " cruel".to_string(), }; let result = change.apply("hello world!"); @@ -116,8 +115,8 @@ mod tests { #[test] fn textchange_apply_works_for_deletions() { let change = super::TextChange { - start: 5, - end: 11, + start_idx: 5, + end_idx: 11, content: "".to_string(), }; let result = change.apply("hello cruel world!"); @@ -127,8 +126,8 @@ mod tests { #[test] fn textchange_apply_works_for_replacements() { let change = super::TextChange { - start: 5, - end: 11, + start_idx: 5, + end_idx: 11, content: " not very pleasant".to_string(), }; let result = change.apply("hello cruel world!"); @@ -138,8 +137,8 @@ mod tests { #[test] fn textchange_apply_never_panics() { let change = super::TextChange { - start: 100, - end: 110, + start_idx: 100, + end_idx: 110, content: "a very long string \n which totally matters".to_string(), }; let result = change.apply("a short text"); @@ -152,8 +151,8 @@ mod tests { #[test] fn empty_textchange_doesnt_alter_buffer() { let change = super::TextChange { - start: 42, - end: 42, + start_idx: 42, + end_idx: 42, content: "".to_string(), }; let result = change.apply("some important text"); diff --git a/src/api/event.rs b/src/api/event.rs index 81df033..8754778 100644 --- a/src/api/event.rs +++ b/src/api/event.rs @@ -1,5 +1,7 @@ //! # Event //! Real time notification of changes in a workspace, to either users or buffers. +#![allow(non_upper_case_globals, non_camel_case_types)] // pyo3 fix your shit + use codemp_proto::workspace::workspace_event::Event as WorkspaceEventInner; /// Event in a [crate::Workspace]. @@ -10,21 +12,21 @@ use codemp_proto::workspace::workspace_event::Event as WorkspaceEventInner; pub enum Event { /// Fired when the file tree changes. /// Contains the modified buffer path (deleted, created or renamed). - FileTreeUpdated(String), + FileTreeUpdated { path: String }, /// Fired when an user joins the current workspace. - UserJoin(String), + UserJoin { name: String }, /// Fired when an user leaves the current workspace. - UserLeave(String), + UserLeave { name: String }, } impl From for Event { fn from(event: WorkspaceEventInner) -> Self { match event { - WorkspaceEventInner::Join(e) => Self::UserJoin(e.user.name), - WorkspaceEventInner::Leave(e) => Self::UserLeave(e.user.name), - WorkspaceEventInner::Create(e) => Self::FileTreeUpdated(e.path), - WorkspaceEventInner::Delete(e) => Self::FileTreeUpdated(e.path), - WorkspaceEventInner::Rename(e) => Self::FileTreeUpdated(e.after), + WorkspaceEventInner::Join(e) => Self::UserJoin { name: e.user.name }, + WorkspaceEventInner::Leave(e) => Self::UserLeave { name: e.user.name }, + WorkspaceEventInner::Create(e) => Self::FileTreeUpdated { path: e.path }, + WorkspaceEventInner::Delete(e) => Self::FileTreeUpdated { path: e.path }, + WorkspaceEventInner::Rename(e) => Self::FileTreeUpdated { path: e.after }, } } } diff --git a/src/buffer/worker.rs b/src/buffer/worker.rs index 8b7bc72..21a4746 100644 --- a/src/buffer/worker.rs +++ b/src/buffer/worker.rs @@ -160,8 +160,8 @@ impl BufferWorker { async fn handle_editor_change(&mut self, change: TextChange, tx: &mpsc::Sender) { let last_ver = self.oplog.local_version(); // clip to buffer extents - let clip_start = change.start as usize; - let mut clip_end = change.end as usize; + let clip_start = change.start_idx as usize; + let mut clip_end = change.end_idx as usize; let b_len = self.branch.len(); if clip_end > b_len { tracing::warn!("clipping TextChange end span from {clip_end} to {b_len}"); @@ -262,8 +262,8 @@ impl BufferWorker { .map(|x| i64::from_ne_bytes(x.to_ne_bytes())) .collect(), // TODO this is wasteful change: crate::api::TextChange { - start: dtop.start() as u32, - end: dtop.start() as u32, + start_idx: dtop.start() as u32, + end_idx: dtop.start() as u32, content: dtop.content_as_str().unwrap_or_default().to_string(), }, } @@ -276,8 +276,8 @@ impl BufferWorker { .map(|x| i64::from_ne_bytes(x.to_ne_bytes())) .collect(), // TODO this is wasteful change: crate::api::TextChange { - start: dtop.start() as u32, - end: dtop.end() as u32, + start_idx: dtop.start() as u32, + end_idx: dtop.end() as u32, content: dtop.content_as_str().unwrap_or_default().to_string(), }, }, diff --git a/src/ffi/java/mod.rs b/src/ffi/java/mod.rs index 51bd3a5..80ac028 100644 --- a/src/ffi/java/mod.rs +++ b/src/ffi/java/mod.rs @@ -170,9 +170,9 @@ impl<'j> jni_toolbox::IntoJavaObject<'j> for crate::api::Event { env: &mut jni::JNIEnv<'j>, ) -> Result, jni::errors::Error> { let (ordinal, arg) = match self { - crate::api::Event::UserJoin(arg) => (0, env.new_string(arg)?), - crate::api::Event::UserLeave(arg) => (1, env.new_string(arg)?), - crate::api::Event::FileTreeUpdated(arg) => (2, env.new_string(arg)?), + crate::api::Event::UserJoin { name: arg } => (0, env.new_string(arg)?), + crate::api::Event::UserLeave { name: arg } => (1, env.new_string(arg)?), + crate::api::Event::FileTreeUpdated { path: arg } => (2, env.new_string(arg)?), }; let type_class = env.find_class("mp/code/Workspace$Event$Type")?; @@ -242,8 +242,8 @@ impl<'j> jni_toolbox::IntoJavaObject<'j> for crate::api::TextChange { class, "(JJLjava/lang/String;)V", &[ - jni::objects::JValueGen::Long(self.start.into()), - jni::objects::JValueGen::Long(self.end.into()), + jni::objects::JValueGen::Long(self.start_idx.into()), + jni::objects::JValueGen::Long(self.end_idx.into()), jni::objects::JValueGen::Object(&content), ], ) @@ -438,11 +438,11 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::TextChange { change: Self::From, ) -> Result { let start = env - .get_field(&change, "start", "J")? + .get_field(&change, "startIdx", "J")? .j()? .clamp(0, u32::MAX.into()) as u32; let end = env - .get_field(&change, "end", "J")? + .get_field(&change, "endIdx", "J")? .j()? .clamp(0, u32::MAX.into()) as u32; @@ -457,8 +457,8 @@ impl<'j> jni_toolbox::FromJava<'j> for crate::api::TextChange { }; Ok(Self { - start, - end, + start_idx: start, + end_idx: end, content, }) } diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index 70b4c7d..f2e2487 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -19,15 +19,15 @@ pub struct JsEvent { impl From for JsEvent { fn from(value: crate::api::Event) -> Self { match value { - crate::api::Event::FileTreeUpdated(value) => Self { + crate::api::Event::FileTreeUpdated { path: value } => Self { r#type: "filetree".into(), value, }, - crate::api::Event::UserJoin(value) => Self { + crate::api::Event::UserJoin { name: value } => Self { r#type: "join".into(), value, }, - crate::api::Event::UserLeave(value) => Self { + crate::api::Event::UserLeave { name: value } => Self { r#type: "leave".into(), value, }, diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 5c5346d..2fd6fb1 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -21,7 +21,7 @@ //! //! // write `hello!` at the beginning of this buffer //! buffer.send(codemp::api::TextChange { -//! start: 0, end: 0, +//! start_idx: 0, end_idx: 0, //! content: "hello!".to_string(), //! })?; //! @@ -58,7 +58,7 @@ //! //! // write `hello!` at the beginning of this buffer //! await buffer.send({ -//! start: 0, end: 0, +//! start_idx: 0, end_idx: 0, //! content: "hello!", //! }); //! @@ -94,7 +94,7 @@ //! //! # write `hello!` at the beginning of this buffer //! buffer.send(codemp.TextChange( -//! start=0, end=0, +//! start_idx=0, end_idx=0, //! content="hello!" //! )).wait() //! @@ -141,7 +141,7 @@ //! //! -- write `hello!` at the beginning of this buffer //! buffer:send({ -//! start = 0, finish = 0, +//! start_idx = 0, end_idx = 0, //! content = "hello!" //! }):await() //! diff --git a/src/ffi/python/controllers.rs b/src/ffi/python/controllers.rs index 9d9d5f3..01b2cc5 100644 --- a/src/ffi/python/controllers.rs +++ b/src/ffi/python/controllers.rs @@ -13,22 +13,8 @@ use super::Promise; #[pymethods] impl CursorController { #[pyo3(name = "send")] - fn pysend( - &self, - _py: Python, - path: String, - start: (i32, i32), - end: (i32, i32), - ) -> PyResult<()> { - let pos = Selection { - start_row: start.0, - start_col: start.1, - end_row: end.0, - end_col: end.1, - buffer: path, - }; - let this = self.clone(); - this.send(pos)?; + fn pysend(&self, _py: Python, pos: Selection) -> PyResult<()> { + self.send(pos)?; Ok(()) } @@ -86,12 +72,7 @@ impl BufferController { } #[pyo3(name = "send")] - fn pysend(&self, _py: Python, start: u32, end: u32, txt: String) -> PyResult<()> { - let op = TextChange { - start, - end, - content: txt, - }; + fn pysend(&self, _py: Python, op: TextChange) -> PyResult<()> { let this = self.clone(); this.send(op)?; Ok(()) diff --git a/src/ffi/python/mod.rs b/src/ffi/python/mod.rs index 75e7695..e620b39 100644 --- a/src/ffi/python/mod.rs +++ b/src/ffi/python/mod.rs @@ -10,8 +10,8 @@ use crate::{ }; use pyo3::{ - prelude::*, exceptions::{PyConnectionError, PyRuntimeError, PySystemError}, + prelude::*, types::PyDict, }; @@ -162,7 +162,11 @@ impl User { #[setter] fn set_id(&mut self, value: String) -> pyo3::PyResult<()> { - self.id = value.parse().map_err(|x: ::Err| pyo3::exceptions::PyRuntimeError::new_err(x.to_string()))?; + self.id = value + .parse() + .map_err(|x: ::Err| { + pyo3::exceptions::PyRuntimeError::new_err(x.to_string()) + })?; Ok(()) } @@ -220,7 +224,7 @@ impl Selection { } else { 0 }; - + let start_col = if let Some(e) = kwds.get_item("start_col")? { e.extract()? } else { @@ -245,7 +249,13 @@ impl Selection { String::default() }; - Ok(Self { start_row, start_col, end_row, end_col, buffer }) + Ok(Self { + start_row, + start_col, + end_row, + end_col, + buffer, + }) } else { Ok(Self::default()) } @@ -269,13 +279,13 @@ impl TextChange { #[pyo3(signature = (**kwds))] pub fn py_new(kwds: Option<&Bound<'_, PyDict>>) -> PyResult { if let Some(kwds) = kwds { - let start = if let Some(e) = kwds.get_item("start")? { + let start_idx = if let Some(e) = kwds.get_item("start")? { e.extract()? } else { 0 }; - let end = if let Some(e) = kwds.get_item("end")? { + let end_idx = if let Some(e) = kwds.get_item("end")? { e.extract()? } else { 0 @@ -287,7 +297,11 @@ impl TextChange { String::default() }; - Ok(Self { start, end, content }) + Ok(Self { + start_idx, + end_idx, + content, + }) } else { Ok(Self::default()) } From 8b2a2f2e2e78025a0e160ca29a65bde54325a09f Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 16 Oct 2024 03:15:09 +0200 Subject: [PATCH 15/19] fix: feature gate pyo3 reference --- src/api/user.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/user.rs b/src/api/user.rs index 47d133c..c6a6a05 100644 --- a/src/api/user.rs +++ b/src/api/user.rs @@ -12,7 +12,7 @@ pub struct User { /// User unique identifier, should never change. pub id: Uuid, /// User name, can change but should be unique. - #[pyo3(get, set)] + #[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3(get, set))] pub name: String, } From 7cc8e88402c790587163c2e2616b0af61265b254 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 16 Oct 2024 03:47:07 +0200 Subject: [PATCH 16/19] fix(py): explicit getter/setter for user name --- src/api/user.rs | 1 - src/ffi/python/mod.rs | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/api/user.rs b/src/api/user.rs index c6a6a05..28297fd 100644 --- a/src/api/user.rs +++ b/src/api/user.rs @@ -12,7 +12,6 @@ pub struct User { /// User unique identifier, should never change. pub id: Uuid, /// User name, can change but should be unique. - #[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3(get, set))] pub name: String, } diff --git a/src/ffi/python/mod.rs b/src/ffi/python/mod.rs index e620b39..aaab6a9 100644 --- a/src/ffi/python/mod.rs +++ b/src/ffi/python/mod.rs @@ -170,6 +170,17 @@ impl User { Ok(()) } + #[getter] + fn get_name(&self) -> pyo3::PyResult { + Ok(self.name.clone()) + } + + #[setter] + fn set_name(&mut self, value: String) -> pyo3::PyResult<()> { + self.name = value; + Ok(()) + } + fn __str__(&self) -> String { format!("{self:?}") } From a73a61a8412b90d9db356fc527d19aca021822c9 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 16 Oct 2024 04:00:05 +0200 Subject: [PATCH 17/19] docs: fix doctests --- src/api/change.rs | 8 ++++---- src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/change.rs b/src/api/change.rs index b52cc5c..60d28f2 100644 --- a/src/api/change.rs +++ b/src/api/change.rs @@ -31,18 +31,18 @@ pub struct BufferUpdate { /// ### Examples /// To insert 'a' after 4th character we should send: /// ``` -/// codemp::api::TextChange { start: 4, end: 4, content: "a".into() }; +/// codemp::api::TextChange { start_idx: 4, end_idx: 4, content: "a".into() }; /// ``` /// /// To delete the fourth character we should send: /// ``` -/// codemp::api::TextChange { start: 3, end: 4, content: "".into() }; +/// codemp::api::TextChange { start_idx: 3, end_idx: 4, content: "".into() }; /// ``` /// /// ``` /// let change = codemp::api::TextChange { -/// start: 6, -/// end: 11, +/// start_idx: 6, +/// end_idx: 11, /// content: "mom".to_string() /// }; /// let before = "hello world!"; diff --git a/src/lib.rs b/src/lib.rs index 304e7c5..3179b7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,7 @@ //! if let Some(mut update) = buffer.try_recv().await.unwrap() { //! println!( //! "content: {}, span: {}-{}", -//! update.change.content, update.change.start, update.change.end +//! update.change.content, update.change.start_idx, update.change.end_idx //! ); //! buffer.ack(update.version); //! } // if None, no changes are currently available From 3d1284045911e6514590eb98ebaf8a950c2d9b95 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Wed, 16 Oct 2024 15:52:35 +0200 Subject: [PATCH 18/19] fix(js): camelCase searchBuffers Co-authored-by: frelodev <74790175+frelodev@users.noreply.github.com> --- src/ffi/js/workspace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ffi/js/workspace.rs b/src/ffi/js/workspace.rs index f2e2487..d1ba78d 100644 --- a/src/ffi/js/workspace.rs +++ b/src/ffi/js/workspace.rs @@ -44,7 +44,7 @@ impl Workspace { } /// List all available buffers in this workspace - #[napi(js_name = "search_buffers")] + #[napi(js_name = "searchBuffers")] pub fn js_search_buffers(&self, filter: Option<&str>) -> Vec { self.search_buffers(filter) } From 22cec4ab561c8cbe81931dd0589483e70df7ffd8 Mon Sep 17 00:00:00 2001 From: cschen Date: Wed, 16 Oct 2024 16:46:41 +0200 Subject: [PATCH 19/19] reverted the change to accept only keywords arguments and have user and password as mandatory. --- src/ffi/python/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ffi/python/mod.rs b/src/ffi/python/mod.rs index aaab6a9..a0f7b8e 100644 --- a/src/ffi/python/mod.rs +++ b/src/ffi/python/mod.rs @@ -174,7 +174,7 @@ impl User { fn get_name(&self) -> pyo3::PyResult { Ok(self.name.clone()) } - + #[setter] fn set_name(&mut self, value: String) -> pyo3::PyResult<()> { self.name = value; @@ -189,7 +189,7 @@ impl User { #[pymethods] impl Config { #[new] - #[pyo3(signature = (username, password, **kwds))] + #[pyo3(signature = (*, username, password, **kwds))] pub fn pynew( username: String, password: String,