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/*.h
|
||||
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;
|
||||
|
||||
import mp.code.data.Cursor;
|
||||
import mp.code.data.TextChange;
|
||||
import mp.code.exceptions.CodeMPException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class BufferController {
|
||||
private final long ptr;
|
||||
|
||||
|
@ -21,8 +24,13 @@ public class BufferController {
|
|||
}
|
||||
|
||||
private static native TextChange try_recv(long self) throws CodeMPException;
|
||||
public TextChange tryRecv() throws CodeMPException {
|
||||
return try_recv(this.ptr);
|
||||
public Optional<TextChange> tryRecv() throws CodeMPException {
|
||||
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;
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
package mp.code;
|
||||
|
||||
import cz.adamh.utils.NativeUtils;
|
||||
import mp.code.exceptions.CodeMPException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Client {
|
||||
private final long ptr;
|
||||
private final String url;
|
||||
|
||||
public static native long setup_tracing(String path);
|
||||
|
||||
private static native long connect(String url) throws CodeMPException;
|
||||
public Client(String url) throws CodeMPException {
|
||||
this.ptr = connect(url);
|
||||
this.url = url;
|
||||
public static native Client connect(String url) throws CodeMPException;
|
||||
Client(long ptr) {
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
private static native String get_url(long self);
|
||||
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;
|
||||
|
@ -25,19 +24,14 @@ public class Client {
|
|||
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 {
|
||||
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() {
|
||||
long ptr = 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));
|
||||
}
|
||||
return Optional.ofNullable(get_workspace(this.ptr));
|
||||
}
|
||||
|
||||
private static native void free(long self);
|
||||
|
@ -46,5 +40,17 @@ public class Client {
|
|||
protected void finalize() {
|
||||
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.exceptions.CodeMPException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class CursorController {
|
||||
private final long ptr;
|
||||
|
||||
|
@ -11,8 +13,13 @@ public class CursorController {
|
|||
}
|
||||
|
||||
private static native Cursor try_recv(long self) throws CodeMPException;
|
||||
public Cursor tryRecv() throws CodeMPException {
|
||||
return try_recv(this.ptr);
|
||||
public Optional<Cursor> tryRecv() throws CodeMPException {
|
||||
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;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package mp.code;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import mp.code.exceptions.CodeMPException;
|
||||
|
||||
public class Workspace {
|
||||
|
@ -14,14 +16,14 @@ public class Workspace {
|
|||
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() {
|
||||
return new CursorController(get_cursor(this.ptr));
|
||||
return get_cursor(this.ptr);
|
||||
}
|
||||
|
||||
private static native long get_buffer(long self, String path);
|
||||
public BufferController getBuffer(String path) {
|
||||
return new BufferController(get_buffer(this.ptr, path));
|
||||
private static native BufferController get_buffer(long self, String path);
|
||||
public Optional<BufferController> getBuffer(String path) {
|
||||
return Optional.ofNullable(get_buffer(this.ptr, path));
|
||||
}
|
||||
|
||||
private static native String[] get_file_tree(long self);
|
||||
|
@ -34,9 +36,9 @@ public class Workspace {
|
|||
return new BufferController(create_buffer(path));
|
||||
}
|
||||
|
||||
private static native long attach_to_buffer(long self) throws CodeMPException;
|
||||
public BufferController attachToBuffer() throws CodeMPException {
|
||||
return new BufferController(attach_to_buffer(ptr));
|
||||
private static native BufferController attach_to_buffer(long self, String path) throws CodeMPException;
|
||||
public BufferController attachToBuffer(String path) throws CodeMPException {
|
||||
return attach_to_buffer(ptr, path);
|
||||
}
|
||||
|
||||
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;
|
||||
public BufferController selectBuffer(long timeout) throws CodeMPException {
|
||||
return select_buffer(this.ptr, timeout);
|
||||
public Optional<BufferController> selectBuffer(long timeout) throws CodeMPException {
|
||||
return Optional.ofNullable(select_buffer(this.ptr, timeout));
|
||||
}
|
||||
|
||||
private static native void free(long self);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::{Error, api::Controller};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
/// 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.
|
||||
pub async fn select_buffer(
|
||||
buffers: &[Arc<crate::buffer::Controller>],
|
||||
buffers: &[crate::buffer::Controller],
|
||||
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 mut tasks = Vec::new();
|
||||
for buffer in buffers {
|
||||
let _tx = tx.clone();
|
||||
let _buffer = buffer.clone();
|
||||
tasks.push(tokio::spawn(async move {
|
||||
tasks.push(runtime.spawn(async move {
|
||||
match _buffer.poll().await {
|
||||
Ok(()) => _tx.send(Ok(Some(_buffer))),
|
||||
Err(_) => _tx.send(Err(Error::Channel { send: true })),
|
||||
|
@ -30,7 +30,7 @@ pub async fn select_buffer(
|
|||
}
|
||||
if let Some(d) = timeout {
|
||||
let _tx = tx.clone();
|
||||
tasks.push(tokio::spawn(async move {
|
||||
tasks.push(runtime.spawn(async move {
|
||||
tokio::time::sleep(d).await;
|
||||
_tx.send(Ok(None))
|
||||
}));
|
||||
|
|
|
@ -2,7 +2,7 @@ use jni::{objects::{JClass, JObject, JValueGen}, sys::{jlong, jobject, jstring},
|
|||
|
||||
use crate::api::Controller;
|
||||
|
||||
use super::util::JExceptable;
|
||||
use super::{util::JExceptable, RT};
|
||||
|
||||
#[no_mangle]
|
||||
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,
|
||||
) -> jobject {
|
||||
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(),
|
||||
Some(event) => {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[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 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) };
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[no_mangle]
|
||||
pub extern "system" fn Java_mp_code_Client_connect<'local>(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass<'local>,
|
||||
input: JString<'local>
|
||||
) -> jlong {
|
||||
) -> jobject {
|
||||
let url: String = env.get_string(&input).expect("Couldn't get java string!").into();
|
||||
RT.block_on(crate::Client::new(&url))
|
||||
.map(|client| Box::into_raw(Box::new(client)) as jlong)
|
||||
.jexcept(&mut env)
|
||||
}
|
||||
|
||||
/// Gets a [Workspace] by name and returns a pointer to it.
|
||||
#[no_mangle]
|
||||
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()
|
||||
.map(|ptr| {
|
||||
let class = env.find_class("mp/code/Client").expect("Failed to find class");
|
||||
env.new_object(class, "(J)V", &[JValueGen::Long(ptr)])
|
||||
.expect("Failed to initialise object")
|
||||
}).jexcept(&mut env).as_raw()
|
||||
}
|
||||
|
||||
/// Logs in to a specific [Workspace].
|
||||
|
@ -78,13 +51,17 @@ pub extern "system" fn Java_mp_code_Client_join_1workspace<'local>(
|
|||
_class: JClass<'local>,
|
||||
self_ptr: jlong,
|
||||
input: JString<'local>
|
||||
) -> jlong {
|
||||
) -> 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!") };
|
||||
RT.block_on(client.join_workspace(workspace_id.to_str().expect("Not UTF-8")))
|
||||
.map(|workspace| spawn_updater(workspace.clone()))
|
||||
.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
|
||||
|
@ -99,3 +76,37 @@ fn spawn_updater(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 crate::{api::Controller, ffi::java::util::JExceptable};
|
||||
|
||||
use super::RT;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "system" fn Java_mp_code_CursorController_try_1recv(
|
||||
mut env: JNIEnv,
|
||||
|
@ -8,7 +10,23 @@ pub extern "system" fn Java_mp_code_CursorController_try_1recv(
|
|||
self_ptr: jlong,
|
||||
) -> jobject {
|
||||
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(),
|
||||
Some(event) => {
|
||||
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 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.
|
||||
#[no_mangle]
|
||||
pub extern "system" fn Java_mp_code_Workspace_get_1cursor<'local>(
|
||||
_env: JNIEnv<'local>,
|
||||
mut env: JNIEnv<'local>,
|
||||
_class: JClass<'local>,
|
||||
self_ptr: jlong
|
||||
) -> jlong {
|
||||
) -> jobject {
|
||||
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.
|
||||
#[no_mangle]
|
||||
pub extern "system" fn Java_mp_code_Workspace_get_1buffer<'local>(
|
||||
env: JNIEnv<'local>,
|
||||
mut env: JNIEnv<'local>,
|
||||
_class: JClass<'local>,
|
||||
self_ptr: jlong,
|
||||
input: JString<'local>
|
||||
) -> jlong {
|
||||
) -> jobject {
|
||||
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!") };
|
||||
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.
|
||||
|
@ -87,12 +97,16 @@ pub extern "system" fn Java_mp_code_Workspace_attach_1to_1buffer<'local>(
|
|||
_class: JClass<'local>,
|
||||
self_ptr: jlong,
|
||||
input: JString<'local>
|
||||
) -> jlong {
|
||||
) -> jobject {
|
||||
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!") };
|
||||
RT.block_on(workspace.attach(path.to_str().expect("Not UTF-8!")))
|
||||
.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.
|
||||
|
@ -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)) };
|
||||
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())
|
||||
}
|
||||
|
||||
/// 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"
|
||||
pub fn filetree(&self) -> Vec<String> {
|
||||
self.0.filetree.iter().map(|f| f.clone()).collect()
|
||||
|
|
Loading…
Reference in a new issue