chore: split list_workspaces, renamed filetree, refactored fetch_users and fetch_buffers

Co-authored-by: alemi <me@alemi.dev>
This commit is contained in:
zaaarf 2024-10-16 00:42:55 +02:00
parent 6f04c38779
commit e5fd0ca76a
No known key found for this signature in database
GPG key ID: 102E445F4C3F829B
21 changed files with 239 additions and 183 deletions

View file

@ -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);

View file

@ -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<String> filter, boolean strict) {
return filetree(this.ptr, filter.orElse(null), strict);
public String[] searchBuffers(Optional<String> 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;

View file

@ -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

View file

@ -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]: ...

View file

@ -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;

View file

@ -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 {

View file

@ -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<Vec<String>> {
let mut workspaces = self
/// Fetch the names of all workspaces owned by the current user.
pub async fn fetch_owned_workspaces(&self) -> RemoteResult<Vec<String>> {
self.fetch_workspaces(true).await
}
/// Fetch the names of all workspaces the current user has joined.
pub async fn fetch_joined_workspaces(&self) -> RemoteResult<Vec<String>> {
self.fetch_workspaces(false).await
}
async fn fetch_workspaces(&self, owned: bool) -> RemoteResult<Vec<String>> {
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<str>) -> ConnectionResult<Workspace> {
pub async fn attach_workspace(
&self,
workspace: impl AsRef<str>,
) -> ConnectionResult<Workspace> {
let token = self
.0
.session

View file

@ -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,
};

View file

@ -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<Vec<String>, RemoteError> {
super::tokio().block_on(client.list_workspaces(owned, invited))
fn fetch_owned_workspaces(client: &mut Client) -> Result<Vec<String>, 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<Vec<String>, RemoteError> {
super::tokio().block_on(client.fetch_joined_workspaces())
}
/// List available workspaces.

View file

@ -1,8 +1,5 @@
use crate::{
api::{
controller::{AsyncReceiver, AsyncSender},
Cursor, Selection,
},
api::{AsyncReceiver, AsyncSender, Cursor, Selection},
errors::ControllerError,
};
use jni::{objects::JObject, JNIEnv};

View file

@ -25,10 +25,10 @@ fn get_buffer(workspace: &mut Workspace, path: String) -> Option<crate::buffer::
workspace.get_buffer(&path)
}
/// Get the filetree.
/// Searches for buffers matching the filter.
#[jni(package = "mp.code", class = "Workspace")]
fn filetree(workspace: &mut Workspace, filter: Option<String>, strict: bool) -> Vec<String> {
workspace.filetree(filter.as_deref(), strict)
fn search_buffers(workspace: &mut Workspace, filter: Option<String>) -> Vec<String> {
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<Vec<String>, 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<Vec<User>, 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<Vec<crate::api::User>, RemoteError> {
super::tokio().block_on(workspace.list_buffer_users(&path))
super::tokio().block_on(workspace.fetch_buffer_users(&path))
}
/// Delete a buffer.

View file

@ -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<Vec<String>> {
Ok(self.list_workspaces(owned, invited).await?)
#[napi(js_name = "fetchOwnedWorkspaces")]
/// fetch owned workspaces
pub async fn js_fetch_owned_workspaces(&self) -> napi::Result<Vec<String>> {
Ok(self.fetch_owned_workspaces().await?)
}
#[napi(js_name = "fetchJoinedWorkspaces")]
/// fetch joined workspaces
pub async fn js_fetch_joined_workspaces(&self) -> napi::Result<Vec<String>> {
Ok(self.fetch_joined_workspaces().await?)
}
#[napi(js_name = "inviteToWorkspace")]

View file

@ -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<String> {
self.filetree(filter, strict)
#[napi(js_name = "search_buffers")]
pub fn js_search_buffers(&self, filter: Option<&str>) -> Vec<String> {
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<Vec<String>> {
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<Vec<JsUser>> {
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<Vec<crate::ffi::js::client::JsUser>> {
Ok(self
.list_buffer_users(&path)
.fetch_buffer_users(&path)
.await?
.into_iter()
.map(super::client::JsUser::from)

View file

@ -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<bool>,Option<bool>)|
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,)| {

View file

@ -101,6 +101,7 @@ macro_rules! callback_args {
callback_args! {
Str: String,
VecStr: Vec<String>,
VecUser: Vec<CodempUser>,
Client: CodempClient,
CursorController: CodempCursorController,
BufferController: CodempBufferController,

View file

@ -43,12 +43,15 @@ impl LuaUserData for CodempWorkspace {
|_, this, ()| a_sync! { this => this.fetch_users().await? },
);
methods.add_method(
"filetree",
|_, this, (filter, strict): (Option<String>, Option<bool>)| {
Ok(this.filetree(filter.as_deref(), strict.unwrap_or(false)))
},
);
methods.add_method("search_buffers", |_, this, (filter,): (Option<String>,)| {
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()));

View file

@ -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();

View file

@ -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<super::Promise> {
tracing::info!("attempting to list workspaces");
#[pyo3(name = "fetch_owned_workspaces")]
fn pyfetch_owned_workspaces(&self, py: Python<'_>) -> PyResult<super::Promise> {
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<super::Promise> {
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")]

View file

@ -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<Promise> {
#[pyo3(name = "fetch_buffer_users")]
fn pyfetch_buffer_users(&self, py: Python, path: String) -> PyResult<Promise> {
// crate::Result<Vec<crate::api::User>>
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<String> {
self.filetree(filter, strict)
#[pyo3(name = "search_buffers")]
#[pyo3(signature = (filter=None))]
fn pysearch_buffers(&self, filter: Option<&str>) -> Vec<String> {
self.search_buffers(filter)
}
#[pyo3(name = "user_list")]

View file

@ -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,

View file

@ -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<Vec<String>> {
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<Vec<User>> {
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<Vec<User>> {
/// Fetch a list of the [User]s attached to a specific buffer.
pub async fn fetch_buffer_users(&self, path: &str) -> RemoteResult<Vec<User>> {
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<String> {
pub fn search_buffers(&self, filter: Option<&str>) -> Vec<String> {
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::<Vec<String>>();
tree.sort();