mirror of
https://github.com/hexedtech/codemp.git
synced 2024-11-24 16:14:48 +01:00
feat: recv, buffer_list, tweaks, gradle
This commit is contained in:
parent
84996489e1
commit
6212718e99
13 changed files with 266 additions and 84 deletions
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -18,3 +18,14 @@ java/*.iml
|
||||||
java/.idea/
|
java/.idea/
|
||||||
java/*.h
|
java/*.h
|
||||||
java/**/*.class
|
java/**/*.class
|
||||||
|
java/build/
|
||||||
|
java/.classpath
|
||||||
|
java/.gradle/
|
||||||
|
java/.project
|
||||||
|
java/.settings/
|
||||||
|
java/bin/
|
||||||
|
|
||||||
|
# intellij insists on creating the wrapper every time even if it's not strictly necessary
|
||||||
|
java/gradle/
|
||||||
|
java/gradlew
|
||||||
|
java/gradlew.bat
|
||||||
|
|
49
java/build.gradle
Normal file
49
java/build.gradle
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id 'maven-publish'
|
||||||
|
id 'com.github.johnrengelman.shadow' version '8.1.1'
|
||||||
|
id 'com.palantir.git-version' version '3.1.0'
|
||||||
|
}
|
||||||
|
|
||||||
|
group = 'mp.code'
|
||||||
|
version = versionDetails().lastTag
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url 'https://jitpack.io' }
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main.java.srcDirs = ['src/']
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'com.github.adamheinrich:native-utils:master-SNAPSHOT'
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowJar {
|
||||||
|
archiveClassifier.set('')
|
||||||
|
dependencies {
|
||||||
|
include(dependency('com.github.adamheinrich:native-utils:master-SNAPSHOT'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def rustDir = projectDir.toPath()
|
||||||
|
.parent
|
||||||
|
.resolve('target')
|
||||||
|
.resolve('release')
|
||||||
|
.toFile()
|
||||||
|
processResources {
|
||||||
|
from(rustDir) {
|
||||||
|
include('*.dll')
|
||||||
|
include('*.so')
|
||||||
|
into('natives/')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('cargoBuild', Exec) {
|
||||||
|
workingDir '.'
|
||||||
|
commandLine 'cargo', 'build', '--release', '--features=java'
|
||||||
|
}
|
||||||
|
|
||||||
|
build.dependsOn cargoBuild
|
1
java/settings.gradle
Normal file
1
java/settings.gradle
Normal file
|
@ -0,0 +1 @@
|
||||||
|
rootProject.name = 'codemp'
|
|
@ -1,8 +1,11 @@
|
||||||
package mp.code;
|
package mp.code;
|
||||||
|
|
||||||
|
import mp.code.data.Cursor;
|
||||||
import mp.code.data.TextChange;
|
import mp.code.data.TextChange;
|
||||||
import mp.code.exceptions.CodeMPException;
|
import mp.code.exceptions.CodeMPException;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class BufferController {
|
public class BufferController {
|
||||||
private final long ptr;
|
private final long ptr;
|
||||||
|
|
||||||
|
@ -21,8 +24,13 @@ public class BufferController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native TextChange try_recv(long self) throws CodeMPException;
|
private static native TextChange try_recv(long self) throws CodeMPException;
|
||||||
public TextChange tryRecv() throws CodeMPException {
|
public Optional<TextChange> tryRecv() throws CodeMPException {
|
||||||
return try_recv(this.ptr);
|
return Optional.ofNullable(try_recv(this.ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native Cursor recv(long self) throws CodeMPException;
|
||||||
|
public Cursor recv() throws CodeMPException {
|
||||||
|
return recv(this.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void send(long self, TextChange change) throws CodeMPException;
|
private static native void send(long self, TextChange change) throws CodeMPException;
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
package mp.code;
|
package mp.code;
|
||||||
|
|
||||||
|
import cz.adamh.utils.NativeUtils;
|
||||||
import mp.code.exceptions.CodeMPException;
|
import mp.code.exceptions.CodeMPException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class Client {
|
public class Client {
|
||||||
private final long ptr;
|
private final long ptr;
|
||||||
private final String url;
|
|
||||||
|
|
||||||
public static native long setup_tracing(String path);
|
public static native Client connect(String url) throws CodeMPException;
|
||||||
|
Client(long ptr) {
|
||||||
private static native long connect(String url) throws CodeMPException;
|
this.ptr = ptr;
|
||||||
public Client(String url) throws CodeMPException {
|
|
||||||
this.ptr = connect(url);
|
|
||||||
this.url = url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static native String get_url(long self);
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return this.url;
|
return get_url(this.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void login(long self, String username, String password, String workspace) throws CodeMPException;
|
private static native void login(long self, String username, String password, String workspace) throws CodeMPException;
|
||||||
|
@ -25,19 +24,14 @@ public class Client {
|
||||||
login(this.ptr, username, password, workspace);
|
login(this.ptr, username, password, workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long join_workspace(long self, String id) throws CodeMPException;
|
private static native Workspace join_workspace(long self, String id) throws CodeMPException;
|
||||||
public Workspace joinWorkspace(String id) throws CodeMPException {
|
public Workspace joinWorkspace(String id) throws CodeMPException {
|
||||||
return new Workspace(join_workspace(this.ptr, id));
|
return join_workspace(this.ptr, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long get_workspace(long self);
|
private static native Workspace get_workspace(long self);
|
||||||
public Optional<Workspace> getWorkspace() {
|
public Optional<Workspace> getWorkspace() {
|
||||||
long ptr = get_workspace(this.ptr);
|
return Optional.ofNullable(get_workspace(this.ptr));
|
||||||
if(ptr == 0) { // TODO it would be better to init in rust directly
|
|
||||||
return Optional.empty();
|
|
||||||
} else {
|
|
||||||
return Optional.of(new Workspace(ptr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void free(long self);
|
private static native void free(long self);
|
||||||
|
@ -46,5 +40,17 @@ public class Client {
|
||||||
protected void finalize() {
|
protected void finalize() {
|
||||||
free(this.ptr);
|
free(this.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static native void setup_tracing(String path);
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
if(System.getProperty("os.name").startsWith("Windows"))
|
||||||
|
NativeUtils.loadLibraryFromJar("/natives/codemp_intellij.dll");
|
||||||
|
else NativeUtils.loadLibraryFromJar("/natives/libcodemp_intellij.so");
|
||||||
|
setup_tracing(System.getenv().get("CODEMP_TRACING_LOG"));
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ package mp.code;
|
||||||
import mp.code.data.Cursor;
|
import mp.code.data.Cursor;
|
||||||
import mp.code.exceptions.CodeMPException;
|
import mp.code.exceptions.CodeMPException;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class CursorController {
|
public class CursorController {
|
||||||
private final long ptr;
|
private final long ptr;
|
||||||
|
|
||||||
|
@ -11,8 +13,13 @@ public class CursorController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native Cursor try_recv(long self) throws CodeMPException;
|
private static native Cursor try_recv(long self) throws CodeMPException;
|
||||||
public Cursor tryRecv() throws CodeMPException {
|
public Optional<Cursor> tryRecv() throws CodeMPException {
|
||||||
return try_recv(this.ptr);
|
return Optional.ofNullable(try_recv(this.ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native Cursor recv(long self) throws CodeMPException;
|
||||||
|
public Cursor recv() throws CodeMPException {
|
||||||
|
return recv(this.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void send(long self, Cursor cursor) throws CodeMPException;
|
private static native void send(long self, Cursor cursor) throws CodeMPException;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package mp.code;
|
package mp.code;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import mp.code.exceptions.CodeMPException;
|
import mp.code.exceptions.CodeMPException;
|
||||||
|
|
||||||
public class Workspace {
|
public class Workspace {
|
||||||
|
@ -14,14 +16,14 @@ public class Workspace {
|
||||||
return get_workspace_id(this.ptr);
|
return get_workspace_id(this.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long get_cursor(long self);
|
private static native CursorController get_cursor(long self);
|
||||||
public CursorController getCursor() {
|
public CursorController getCursor() {
|
||||||
return new CursorController(get_cursor(this.ptr));
|
return get_cursor(this.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long get_buffer(long self, String path);
|
private static native BufferController get_buffer(long self, String path);
|
||||||
public BufferController getBuffer(String path) {
|
public Optional<BufferController> getBuffer(String path) {
|
||||||
return new BufferController(get_buffer(this.ptr, path));
|
return Optional.ofNullable(get_buffer(this.ptr, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native String[] get_file_tree(long self);
|
private static native String[] get_file_tree(long self);
|
||||||
|
@ -34,9 +36,9 @@ public class Workspace {
|
||||||
return new BufferController(create_buffer(path));
|
return new BufferController(create_buffer(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long attach_to_buffer(long self) throws CodeMPException;
|
private static native BufferController attach_to_buffer(long self, String path) throws CodeMPException;
|
||||||
public BufferController attachToBuffer() throws CodeMPException {
|
public BufferController attachToBuffer(String path) throws CodeMPException {
|
||||||
return new BufferController(attach_to_buffer(ptr));
|
return attach_to_buffer(ptr, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void fetch_buffers(long self) throws CodeMPException;
|
private static native void fetch_buffers(long self) throws CodeMPException;
|
||||||
|
@ -60,8 +62,8 @@ public class Workspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native BufferController select_buffer(long self, long timeout) throws CodeMPException;
|
private static native BufferController select_buffer(long self, long timeout) throws CodeMPException;
|
||||||
public BufferController selectBuffer(long timeout) throws CodeMPException {
|
public Optional<BufferController> selectBuffer(long timeout) throws CodeMPException {
|
||||||
return select_buffer(this.ptr, timeout);
|
return Optional.ofNullable(select_buffer(this.ptr, timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void free(long self);
|
private static native void free(long self);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::{Error, api::Controller};
|
use crate::{Error, api::Controller};
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
/// invoke .poll() on all given buffer controllers and wait, returning the first one ready
|
/// invoke .poll() on all given buffer controllers and wait, returning the first one ready
|
||||||
|
@ -13,15 +12,16 @@ use tokio::sync::mpsc;
|
||||||
///
|
///
|
||||||
/// returns an error if all buffers returned errors while polling.
|
/// returns an error if all buffers returned errors while polling.
|
||||||
pub async fn select_buffer(
|
pub async fn select_buffer(
|
||||||
buffers: &[Arc<crate::buffer::Controller>],
|
buffers: &[crate::buffer::Controller],
|
||||||
timeout: Option<std::time::Duration>,
|
timeout: Option<std::time::Duration>,
|
||||||
) -> crate::Result<Option<Arc<crate::buffer::Controller>>> {
|
runtime: &tokio::runtime::Runtime
|
||||||
|
) -> crate::Result<Option<crate::buffer::Controller>> {
|
||||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||||
let mut tasks = Vec::new();
|
let mut tasks = Vec::new();
|
||||||
for buffer in buffers {
|
for buffer in buffers {
|
||||||
let _tx = tx.clone();
|
let _tx = tx.clone();
|
||||||
let _buffer = buffer.clone();
|
let _buffer = buffer.clone();
|
||||||
tasks.push(tokio::spawn(async move {
|
tasks.push(runtime.spawn(async move {
|
||||||
match _buffer.poll().await {
|
match _buffer.poll().await {
|
||||||
Ok(()) => _tx.send(Ok(Some(_buffer))),
|
Ok(()) => _tx.send(Ok(Some(_buffer))),
|
||||||
Err(_) => _tx.send(Err(Error::Channel { send: true })),
|
Err(_) => _tx.send(Err(Error::Channel { send: true })),
|
||||||
|
@ -30,7 +30,7 @@ pub async fn select_buffer(
|
||||||
}
|
}
|
||||||
if let Some(d) = timeout {
|
if let Some(d) = timeout {
|
||||||
let _tx = tx.clone();
|
let _tx = tx.clone();
|
||||||
tasks.push(tokio::spawn(async move {
|
tasks.push(runtime.spawn(async move {
|
||||||
tokio::time::sleep(d).await;
|
tokio::time::sleep(d).await;
|
||||||
_tx.send(Ok(None))
|
_tx.send(Ok(None))
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -2,7 +2,7 @@ use jni::{objects::{JClass, JObject, JValueGen}, sys::{jlong, jobject, jstring},
|
||||||
|
|
||||||
use crate::api::Controller;
|
use crate::api::Controller;
|
||||||
|
|
||||||
use super::util::JExceptable;
|
use super::{util::JExceptable, RT};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "system" fn Java_mp_code_BufferController_get_1name(
|
pub extern "system" fn Java_mp_code_BufferController_get_1name(
|
||||||
|
@ -37,7 +37,23 @@ pub extern "system" fn Java_mp_code_BufferController_try_1recv(
|
||||||
self_ptr: jlong,
|
self_ptr: jlong,
|
||||||
) -> jobject {
|
) -> jobject {
|
||||||
let controller = unsafe { Box::leak(Box::from_raw(self_ptr as *mut crate::buffer::Controller)) };
|
let controller = unsafe { Box::leak(Box::from_raw(self_ptr as *mut crate::buffer::Controller)) };
|
||||||
match controller.try_recv().jexcept(&mut env) {
|
let change = controller.try_recv().jexcept(&mut env);
|
||||||
|
recv_jni(&mut env, change)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_mp_code_BufferController_recv(
|
||||||
|
mut env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
self_ptr: jlong,
|
||||||
|
) -> jobject {
|
||||||
|
let controller = unsafe { Box::leak(Box::from_raw(self_ptr as *mut crate::buffer::Controller)) };
|
||||||
|
let change = RT.block_on(controller.recv()).map(Some).jexcept(&mut env);
|
||||||
|
recv_jni(&mut env, change)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recv_jni(env: &mut JNIEnv, change: Option<crate::api::TextChange>) -> jobject {
|
||||||
|
match change {
|
||||||
None => JObject::null().as_raw(),
|
None => JObject::null().as_raw(),
|
||||||
Some(event) => {
|
Some(event) => {
|
||||||
let class = env.find_class("mp/code/data/TextChange").expect("Couldn't find class!");
|
let class = env.find_class("mp/code/data/TextChange").expect("Couldn't find class!");
|
||||||
|
@ -52,6 +68,7 @@ pub extern "system" fn Java_mp_code_BufferController_try_1recv(
|
||||||
).expect("failed creating object").into_raw()
|
).expect("failed creating object").into_raw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use jni::{objects::{JClass, JString}, sys::jlong, JNIEnv};
|
use jni::{objects::{JClass, JObject, JString, JValueGen}, sys::{jlong, jobject}, JNIEnv};
|
||||||
use crate::{client::Client, Workspace};
|
use crate::{client::Client, Workspace};
|
||||||
|
|
||||||
use super::{util::JExceptable, RT};
|
use super::{util::JExceptable, RT};
|
||||||
|
@ -9,48 +9,21 @@ pub extern "system" fn Java_mp_code_Client_free(_env: JNIEnv, _class: JClass, in
|
||||||
let _ = unsafe { Box::from_raw(input as *mut Client) };
|
let _ = unsafe { Box::from_raw(input as *mut Client) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up tracing subscriber
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "system" fn Java_mp_code_Client_setup_1tracing<'local>(
|
|
||||||
mut env: JNIEnv,
|
|
||||||
_class: JClass<'local>,
|
|
||||||
path: JString<'local>
|
|
||||||
) {
|
|
||||||
let path: Option<String> = if path.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(env.get_string(&path).expect("Couldn't get java string!").into())
|
|
||||||
};
|
|
||||||
|
|
||||||
super::setup_logger(true, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Connects to a given URL and returns a [Client] to interact with that server.
|
/// Connects to a given URL and returns a [Client] to interact with that server.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "system" fn Java_mp_code_Client_connect<'local>(
|
pub extern "system" fn Java_mp_code_Client_connect<'local>(
|
||||||
mut env: JNIEnv,
|
mut env: JNIEnv,
|
||||||
_class: JClass<'local>,
|
_class: JClass<'local>,
|
||||||
input: JString<'local>
|
input: JString<'local>
|
||||||
) -> jlong {
|
) -> jobject {
|
||||||
let url: String = env.get_string(&input).expect("Couldn't get java string!").into();
|
let url: String = env.get_string(&input).expect("Couldn't get java string!").into();
|
||||||
RT.block_on(crate::Client::new(&url))
|
RT.block_on(crate::Client::new(&url))
|
||||||
.map(|client| Box::into_raw(Box::new(client)) as jlong)
|
.map(|client| Box::into_raw(Box::new(client)) as jlong)
|
||||||
.jexcept(&mut env)
|
.map(|ptr| {
|
||||||
}
|
let class = env.find_class("mp/code/Client").expect("Failed to find class");
|
||||||
|
env.new_object(class, "(J)V", &[JValueGen::Long(ptr)])
|
||||||
/// Gets a [Workspace] by name and returns a pointer to it.
|
.expect("Failed to initialise object")
|
||||||
#[no_mangle]
|
}).jexcept(&mut env).as_raw()
|
||||||
pub extern "system" fn Java_mp_code_Client_get_1workspace<'local>(
|
|
||||||
env: JNIEnv<'local>,
|
|
||||||
_class: JClass<'local>,
|
|
||||||
self_ptr: jlong,
|
|
||||||
input: JString<'local>
|
|
||||||
) -> jlong {
|
|
||||||
let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) };
|
|
||||||
let workspace_id = unsafe { env.get_string_unchecked(&input).expect("Couldn't get java string!") };
|
|
||||||
client.get_workspace(workspace_id.to_str().expect("Not UTF-8"))
|
|
||||||
.map(|workspace| Box::into_raw(Box::new(workspace)) as jlong)
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Logs in to a specific [Workspace].
|
/// Logs in to a specific [Workspace].
|
||||||
|
@ -78,13 +51,17 @@ pub extern "system" fn Java_mp_code_Client_join_1workspace<'local>(
|
||||||
_class: JClass<'local>,
|
_class: JClass<'local>,
|
||||||
self_ptr: jlong,
|
self_ptr: jlong,
|
||||||
input: JString<'local>
|
input: JString<'local>
|
||||||
) -> jlong {
|
) -> jobject {
|
||||||
let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) };
|
let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) };
|
||||||
let workspace_id = unsafe { env.get_string_unchecked(&input).expect("Couldn't get java string!") };
|
let workspace_id = unsafe { env.get_string_unchecked(&input).expect("Couldn't get java string!") };
|
||||||
RT.block_on(client.join_workspace(workspace_id.to_str().expect("Not UTF-8")))
|
RT.block_on(client.join_workspace(workspace_id.to_str().expect("Not UTF-8")))
|
||||||
.map(|workspace| spawn_updater(workspace.clone()))
|
.map(|workspace| spawn_updater(workspace.clone()))
|
||||||
.map(|workspace| Box::into_raw(Box::new(workspace)) as jlong)
|
.map(|workspace| Box::into_raw(Box::new(workspace)) as jlong)
|
||||||
.jexcept(&mut env)
|
.map(|ptr| {
|
||||||
|
let class = env.find_class("mp/code/Workspace").expect("Failed to find class");
|
||||||
|
env.new_object(class, "(J)V", &[JValueGen::Long(ptr)])
|
||||||
|
.expect("Failed to initialise object")
|
||||||
|
}).jexcept(&mut env).as_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this stays until we get rid of the arc then i'll have to find a better way
|
// TODO: this stays until we get rid of the arc then i'll have to find a better way
|
||||||
|
@ -99,3 +76,37 @@ fn spawn_updater(workspace: Workspace) -> Workspace {
|
||||||
});
|
});
|
||||||
workspace
|
workspace
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a [Workspace] by name and returns a pointer to it.
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_mp_code_Client_get_1workspace<'local>(
|
||||||
|
mut env: JNIEnv<'local>,
|
||||||
|
_class: JClass<'local>,
|
||||||
|
self_ptr: jlong,
|
||||||
|
input: JString<'local>
|
||||||
|
) -> jobject {
|
||||||
|
let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) };
|
||||||
|
let workspace_id = unsafe { env.get_string_unchecked(&input).expect("Couldn't get java string!") };
|
||||||
|
client.get_workspace(workspace_id.to_str().expect("Not UTF-8"))
|
||||||
|
.map(|workspace| Box::into_raw(Box::new(workspace)) as jlong)
|
||||||
|
.map(|ptr| {
|
||||||
|
let class = env.find_class("mp/code/Workspace").expect("Failed to find class");
|
||||||
|
env.new_object(class, "(J)V", &[JValueGen::Long(ptr)])
|
||||||
|
.expect("Failed to initialise object")
|
||||||
|
}).unwrap_or(JObject::null()).as_raw()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets up the tracing subscriber.
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_mp_code_Client_setup_1tracing<'local>(
|
||||||
|
mut env: JNIEnv,
|
||||||
|
_class: JClass<'local>,
|
||||||
|
path: JString<'local>
|
||||||
|
) {
|
||||||
|
super::setup_logger(
|
||||||
|
true,
|
||||||
|
Some(path)
|
||||||
|
.filter(|p| p.is_null())
|
||||||
|
.map(|p| env.get_string(&p).expect("couldn't get java string").into())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use jni::{objects::{JClass, JObject, JString, JValueGen}, sys::{jlong, jobject}, JNIEnv};
|
use jni::{objects::{JClass, JObject, JString, JValueGen}, sys::{jlong, jobject}, JNIEnv};
|
||||||
use crate::{api::Controller, ffi::java::util::JExceptable};
|
use crate::{api::Controller, ffi::java::util::JExceptable};
|
||||||
|
|
||||||
|
use super::RT;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "system" fn Java_mp_code_CursorController_try_1recv(
|
pub extern "system" fn Java_mp_code_CursorController_try_1recv(
|
||||||
mut env: JNIEnv,
|
mut env: JNIEnv,
|
||||||
|
@ -8,7 +10,23 @@ pub extern "system" fn Java_mp_code_CursorController_try_1recv(
|
||||||
self_ptr: jlong,
|
self_ptr: jlong,
|
||||||
) -> jobject {
|
) -> jobject {
|
||||||
let controller = unsafe { Box::leak(Box::from_raw(self_ptr as *mut crate::cursor::Controller)) };
|
let controller = unsafe { Box::leak(Box::from_raw(self_ptr as *mut crate::cursor::Controller)) };
|
||||||
match controller.try_recv().jexcept(&mut env) {
|
let cursor = controller.try_recv().jexcept(&mut env);
|
||||||
|
jni_recv(&mut env, cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_mp_code_CursorController_recv(
|
||||||
|
mut env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
self_ptr: jlong,
|
||||||
|
) -> jobject {
|
||||||
|
let controller = unsafe { Box::leak(Box::from_raw(self_ptr as *mut crate::cursor::Controller)) };
|
||||||
|
let cursor = RT.block_on(controller.recv()).map(Some).jexcept(&mut env);
|
||||||
|
jni_recv(&mut env, cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jni_recv(env: &mut JNIEnv, cursor: Option<crate::api::Cursor>) -> jobject {
|
||||||
|
match cursor {
|
||||||
None => JObject::null().as_raw(),
|
None => JObject::null().as_raw(),
|
||||||
Some(event) => {
|
Some(event) => {
|
||||||
let class = env.find_class("mp/code/data/Cursor").expect("Couldn't find class!");
|
let class = env.find_class("mp/code/data/Cursor").expect("Couldn't find class!");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use jni::{objects::{JClass, JObject, JString}, sys::{jlong, jobjectArray, jstring}, JNIEnv};
|
use jni::{objects::{JClass, JObject, JString, JValueGen}, sys::{jlong, jobject, jobjectArray, jstring}, JNIEnv};
|
||||||
use crate::Workspace;
|
use crate::Workspace;
|
||||||
|
|
||||||
use super::{util::JExceptable, RT};
|
use super::{util::JExceptable, RT};
|
||||||
|
@ -25,25 +25,35 @@ pub extern "system" fn Java_mp_code_Workspace_get_1workspace_1id<'local>(
|
||||||
/// Gets a cursor controller by name and returns a pointer to it.
|
/// Gets a cursor controller by name and returns a pointer to it.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "system" fn Java_mp_code_Workspace_get_1cursor<'local>(
|
pub extern "system" fn Java_mp_code_Workspace_get_1cursor<'local>(
|
||||||
_env: JNIEnv<'local>,
|
mut env: JNIEnv<'local>,
|
||||||
_class: JClass<'local>,
|
_class: JClass<'local>,
|
||||||
self_ptr: jlong
|
self_ptr: jlong
|
||||||
) -> jlong {
|
) -> jobject {
|
||||||
let workspace = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Workspace)) };
|
let workspace = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Workspace)) };
|
||||||
Box::into_raw(Box::new(workspace.cursor())) as jlong
|
let class = env.find_class("mp/code/CursorController").expect("Failed to find class");
|
||||||
|
env.new_object(class, "(J)V", &[JValueGen::Long(Box::into_raw(Box::new(workspace.cursor())) as jlong)])
|
||||||
|
.expect("Failed to initialise object")
|
||||||
|
.as_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a buffer controller by name and returns a pointer to it.
|
/// Gets a buffer controller by name and returns a pointer to it.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "system" fn Java_mp_code_Workspace_get_1buffer<'local>(
|
pub extern "system" fn Java_mp_code_Workspace_get_1buffer<'local>(
|
||||||
env: JNIEnv<'local>,
|
mut env: JNIEnv<'local>,
|
||||||
_class: JClass<'local>,
|
_class: JClass<'local>,
|
||||||
self_ptr: jlong,
|
self_ptr: jlong,
|
||||||
input: JString<'local>
|
input: JString<'local>
|
||||||
) -> jlong {
|
) -> jobject {
|
||||||
let workspace = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Workspace)) };
|
let workspace = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Workspace)) };
|
||||||
let path = unsafe { env.get_string_unchecked(&input).expect("Couldn't get java string!") };
|
let path = unsafe { env.get_string_unchecked(&input).expect("Couldn't get java string!") };
|
||||||
Box::into_raw(Box::new(workspace.buffer_by_name(path.to_str().expect("Not UTF-8")))) as jlong
|
if let Some(buf) = workspace.buffer_by_name(path.to_str().expect("Not UTF-8!")) {
|
||||||
|
let class = env.find_class("mp/code/BufferController").expect("Failed to find class");
|
||||||
|
env.new_object(class, "(J)V", &[JValueGen::Long(Box::into_raw(Box::new(buf)) as jlong)])
|
||||||
|
.expect("Failed to initialise object")
|
||||||
|
.as_raw()
|
||||||
|
} else {
|
||||||
|
JObject::null().as_raw()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new buffer.
|
/// Creates a new buffer.
|
||||||
|
@ -87,12 +97,16 @@ pub extern "system" fn Java_mp_code_Workspace_attach_1to_1buffer<'local>(
|
||||||
_class: JClass<'local>,
|
_class: JClass<'local>,
|
||||||
self_ptr: jlong,
|
self_ptr: jlong,
|
||||||
input: JString<'local>
|
input: JString<'local>
|
||||||
) -> jlong {
|
) -> jobject {
|
||||||
let workspace = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Workspace)) };
|
let workspace = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Workspace)) };
|
||||||
let path = unsafe { env.get_string_unchecked(&input).expect("Couldn't get java string!") };
|
let path = unsafe { env.get_string_unchecked(&input).expect("Couldn't get java string!") };
|
||||||
RT.block_on(workspace.attach(path.to_str().expect("Not UTF-8!")))
|
RT.block_on(workspace.attach(path.to_str().expect("Not UTF-8!")))
|
||||||
.map(|buffer| Box::into_raw(Box::new(buffer)) as jlong)
|
.map(|buffer| Box::into_raw(Box::new(buffer)) as jlong)
|
||||||
.jexcept(&mut env)
|
.map(|ptr| {
|
||||||
|
let class = env.find_class("mp/code/BufferController").expect("Failed to find class");
|
||||||
|
env.new_object(class, "(J)V", &[JValueGen::Long(ptr)])
|
||||||
|
.expect("Failed to initialise object")
|
||||||
|
}).jexcept(&mut env).as_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the local buffer list.
|
/// Updates the local buffer list.
|
||||||
|
@ -155,3 +169,36 @@ pub extern "system" fn Java_mp_code_Workspace_delete_1buffer<'local>(
|
||||||
let workspace = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Workspace)) };
|
let workspace = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Workspace)) };
|
||||||
RT.block_on(workspace.delete(buffer.to_str().expect("Not UTF-8!"))).jexcept(&mut env);
|
RT.block_on(workspace.delete(buffer.to_str().expect("Not UTF-8!"))).jexcept(&mut env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Polls a list of buffers, returning the first ready one.
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_mp_code_Workspace_select_1buffer(
|
||||||
|
mut env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
self_ptr: jlong,
|
||||||
|
timeout: jlong
|
||||||
|
) -> jobject {
|
||||||
|
let workspace = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Workspace)) };
|
||||||
|
let buffers = workspace.buffer_list();
|
||||||
|
let mut controllers = Vec::default();
|
||||||
|
for buffer in buffers {
|
||||||
|
if let Some(controller) = workspace.buffer_by_name(&buffer) {
|
||||||
|
controllers.push(controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let active = RT.block_on(crate::buffer::tools::select_buffer(
|
||||||
|
&controllers,
|
||||||
|
Some(std::time::Duration::from_millis(timeout as u64)),
|
||||||
|
&RT,
|
||||||
|
)).jexcept(&mut env);
|
||||||
|
|
||||||
|
if let Some(buf) = active {
|
||||||
|
let class = env.find_class("mp/code/BufferController").expect("Failed to find class");
|
||||||
|
env.new_object(class, "(J)V", &[JValueGen::Long(Box::into_raw(Box::new(buf)) as jlong)])
|
||||||
|
.expect("Failed to initialise object")
|
||||||
|
.as_raw()
|
||||||
|
} else {
|
||||||
|
JObject::null().as_raw()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -241,6 +241,11 @@ impl Workspace {
|
||||||
self.0.buffers.get(path).map(|x| x.clone())
|
self.0.buffers.get(path).map(|x| x.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get a list of all the currently attached to buffers
|
||||||
|
pub fn buffer_list(&self) -> Vec<String> {
|
||||||
|
self.0.buffers.iter().map(|elem| elem.key().clone()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// get the currently cached "filetree"
|
/// get the currently cached "filetree"
|
||||||
pub fn filetree(&self) -> Vec<String> {
|
pub fn filetree(&self) -> Vec<String> {
|
||||||
self.0.filetree.iter().map(|f| f.clone()).collect()
|
self.0.filetree.iter().map(|f| f.clone()).collect()
|
||||||
|
|
Loading…
Reference in a new issue