diff --git a/dist/java/src/mp/code/BufferController.java b/dist/java/src/mp/code/BufferController.java index 818bed6..32f2704 100644 --- a/dist/java/src/mp/code/BufferController.java +++ b/dist/java/src/mp/code/BufferController.java @@ -1,5 +1,6 @@ package mp.code; +import mp.code.data.Callback; import mp.code.data.Cursor; import mp.code.data.TextChange; import mp.code.exceptions.ControllerException; @@ -38,6 +39,11 @@ public class BufferController { send(this.ptr, change); } + private static native void callback(long self, Callback cb); + public void callback(Callback cb) { + callback(this.ptr, cb); + } + private static native void free(long self); @Override protected void finalize() { diff --git a/dist/java/src/mp/code/Client.java b/dist/java/src/mp/code/Client.java index 0b1348a..acd65c6 100644 --- a/dist/java/src/mp/code/Client.java +++ b/dist/java/src/mp/code/Client.java @@ -1,6 +1,7 @@ package mp.code; import cz.adamh.utils.NativeUtils; +import mp.code.data.User; import mp.code.exceptions.ConnectionException; import mp.code.exceptions.ConnectionRemoteException; @@ -17,9 +18,9 @@ public class Client { this.ptr = ptr; } - private static native String get_url(long self); - public String getUrl() { - return get_url(this.ptr); + private static native User get_user(long self); + public User getUser() { + return get_user(this.ptr); } private static native Workspace join_workspace(long self, String id) throws ConnectionException; @@ -47,6 +48,11 @@ public class Client { return list_workspaces(this.ptr, owned, invited); } + private static native String[] active_workspaces(long self); + public String[] activeWorkspaces() { + return active_workspaces(this.ptr); + } + private static native boolean leave_workspace(long self, String id); public boolean leaveWorkspace(String id) { return leave_workspace(this.ptr, id); @@ -57,9 +63,9 @@ public class Client { return Optional.ofNullable(get_workspace(this.ptr, workspace)); } - private static native void refresh_native(long self) throws ConnectionRemoteException; + private static native void refresh(long self) throws ConnectionRemoteException; public void refresh() throws ConnectionRemoteException { - refresh_native(this.ptr); + refresh(this.ptr); } private static native void free(long self); diff --git a/dist/java/src/mp/code/CursorController.java b/dist/java/src/mp/code/CursorController.java index fb93983..850fcae 100644 --- a/dist/java/src/mp/code/CursorController.java +++ b/dist/java/src/mp/code/CursorController.java @@ -1,5 +1,6 @@ package mp.code; +import mp.code.data.Callback; import mp.code.data.Cursor; import mp.code.exceptions.ControllerException; @@ -27,6 +28,11 @@ public class CursorController { send(this.ptr, cursor); } + private static native void callback(long self, Callback cb); + public void callback(Callback cb) { + callback(this.ptr, cb); + } + private static native void free(long self); @Override protected void finalize() { diff --git a/dist/java/src/mp/code/data/Callback.java b/dist/java/src/mp/code/data/Callback.java new file mode 100644 index 0000000..c436f67 --- /dev/null +++ b/dist/java/src/mp/code/data/Callback.java @@ -0,0 +1,6 @@ +package mp.code.data; + +@FunctionalInterface +public interface Callback { + void invoke(T controller); +} diff --git a/dist/java/src/mp/code/data/User.java b/dist/java/src/mp/code/data/User.java new file mode 100644 index 0000000..0c672bb --- /dev/null +++ b/dist/java/src/mp/code/data/User.java @@ -0,0 +1,13 @@ +package mp.code.data; + +import java.util.UUID; + +public class User { + public final UUID id; + public final String name; + + public User(UUID id, String name) { + this.id = id; + this.name = name; + } +} diff --git a/src/ffi/java/client.rs b/src/ffi/java/client.rs index 328d509..c0dbd5b 100644 --- a/src/ffi/java/client.rs +++ b/src/ffi/java/client.rs @@ -1,7 +1,7 @@ use jni::{objects::{JClass, JObject, JString, JValueGen}, sys::{jboolean, jint, jlong, jobject, jobjectArray}, JNIEnv}; use crate::{api::Config, client::Client, Workspace}; -use super::{JExceptable, RT}; +use super::{JExceptable, JObjectify, RT}; /// Connect using the given credentials to the default server, and return a [Client] to interact with it. #[no_mangle] @@ -72,6 +72,20 @@ fn connect_internal(mut env: JNIEnv, config: Config) -> jobject { }).jexcept(&mut env).as_raw() } +/// Gets the current [crate::api::User]. +#[no_mangle] +pub extern "system" fn Java_mp_code_Client_get_1user( + mut env: JNIEnv, + _class: JClass, + self_ptr: jlong +) -> jobject { + let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) }; + client.user().clone() + .jobjectify(&mut env) + .jexcept(&mut env) + .as_raw() +} + /// Join a [Workspace] and return a pointer to it. #[no_mangle] pub extern "system" fn Java_mp_code_Client_join_1workspace<'local>( @@ -162,7 +176,26 @@ pub extern "system" fn Java_mp_code_Client_list_1workspaces<'local>( let list = RT .block_on(client.list_workspaces(owned != 0, invited != 0)) .jexcept(&mut env); + env.find_class("java/lang/String") + .and_then(|class| env.new_object_array(list.len() as i32, class, JObject::null())) + .inspect(|arr| { + for (idx, path) in list.iter().enumerate() { + env.new_string(path) + .and_then(|path| env.set_object_array_element(arr, idx as i32, path)) + .jexcept(&mut env) + } + }).jexcept(&mut env).as_raw() +} +/// List available workspaces. +#[no_mangle] +pub extern "system" fn Java_mp_code_Client_active_1workspaces<'local>( + mut env: JNIEnv<'local>, + _class: JClass<'local>, + self_ptr: jlong +) -> jobjectArray { + let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) }; + let list = client.active_workspaces(); env.find_class("java/lang/String") .and_then(|class| env.new_object_array(list.len() as i32, class, JObject::null())) .inspect(|arr| { diff --git a/src/ffi/java/mod.rs b/src/ffi/java/mod.rs index 54cc19a..3bcb617 100644 --- a/src/ffi/java/mod.rs +++ b/src/ffi/java/mod.rs @@ -114,12 +114,29 @@ pub(crate) trait JObjectify<'local> { impl<'local> JObjectify<'local> for uuid::Uuid { type Error = jni::errors::Error; fn jobjectify(self, env: &mut jni::JNIEnv<'local>) -> Result, Self::Error> { - env.find_class("java/util/UUID").and_then(|class| { - let (msb, lsb) = self.as_u64_pair(); - let msb = i64::from_ne_bytes(msb.to_ne_bytes()); - let lsb = i64::from_ne_bytes(lsb.to_ne_bytes()); - env.new_object(&class, "(JJ)V", &[jni::objects::JValueGen::Long(msb), jni::objects::JValueGen::Long(lsb)]) - }) + let class = env.find_class("java/util/UUID")?; + let (msb, lsb) = self.as_u64_pair(); + let msb = i64::from_ne_bytes(msb.to_ne_bytes()); + let lsb = i64::from_ne_bytes(lsb.to_ne_bytes()); + env.new_object(&class, "(JJ)V", &[jni::objects::JValueGen::Long(msb), jni::objects::JValueGen::Long(lsb)]) + } +} + +impl<'local> JObjectify<'local> for crate::api::User { + type Error = jni::errors::Error; + + fn jobjectify(self, env: &mut jni::JNIEnv<'local>) -> Result, Self::Error> { + let id_field = self.id.jobjectify(env)?; + let name_field = env.new_string(self.name)?; + let class = env.find_class("mp/code/data/User")?; + env.new_object( + &class, + "(Ljava/util/UUID;Ljava/lang/String;)V", + &[ + jni::objects::JValueGen::Object(&id_field), + jni::objects::JValueGen::Object(&name_field) + ] + ) } } diff --git a/src/workspace.rs b/src/workspace.rs index a59af0d..1977f63 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -285,7 +285,7 @@ impl Workspace { self.0.filetree.iter() .filter(|f| filter.map_or(true, |flt| { if strict { - f.eq(flt) + f.as_str() == flt } else { f.starts_with(flt) }