mirror of
https://github.com/hexedtech/codemp-intellij.git
synced 2024-11-21 22:54:48 +01:00
feat: added custom exceptions, glue code refactor
This commit is contained in:
parent
2ffcd42b65
commit
5741e28a09
9 changed files with 103 additions and 109 deletions
22
build.rs
22
build.rs
|
@ -1,5 +1,5 @@
|
||||||
use flapigen::{JavaConfig, LanguageConfig};
|
use flapigen::{JavaConfig, LanguageConfig};
|
||||||
use std::{env, path::Path};
|
use std::{env, fs, path::Path};
|
||||||
use rifgen::{Generator as RifgenGenerator, TypeCases, Language};
|
use rifgen::{Generator as RifgenGenerator, TypeCases, Language};
|
||||||
use flapigen::Generator as FlapigenGenerator;
|
use flapigen::Generator as FlapigenGenerator;
|
||||||
|
|
||||||
|
@ -7,15 +7,13 @@ fn main() {
|
||||||
let out_dir_var = env::var("OUT_DIR")
|
let out_dir_var = env::var("OUT_DIR")
|
||||||
.expect("no OUT_DIR, but cargo should provide it");
|
.expect("no OUT_DIR, but cargo should provide it");
|
||||||
let out_dir = Path::new(&out_dir_var);
|
let out_dir = Path::new(&out_dir_var);
|
||||||
|
let generated_glue_file = out_dir.join("generated_glue.in");
|
||||||
|
|
||||||
let mut source_folders = Vec::new();
|
let src_dir = Path::new("src/main/rust/");
|
||||||
source_folders.push(Path::new("src/main/rust/"));
|
let glue_file = src_dir.join("glue.in");
|
||||||
|
|
||||||
let glue_file = out_dir.join("glue.in");
|
RifgenGenerator::new(TypeCases::CamelCase,Language::Java, vec!(src_dir))
|
||||||
RifgenGenerator::new(TypeCases::CamelCase,
|
.generate_interface(&generated_glue_file);
|
||||||
Language::Java,
|
|
||||||
source_folders)
|
|
||||||
.generate_interface(&glue_file);
|
|
||||||
|
|
||||||
let jni_path = Path::new("src")
|
let jni_path = Path::new("src")
|
||||||
.join("main")
|
.join("main")
|
||||||
|
@ -26,7 +24,7 @@ fn main() {
|
||||||
.join("jni");
|
.join("jni");
|
||||||
|
|
||||||
//create folder if it doesn't exist
|
//create folder if it doesn't exist
|
||||||
std::fs::create_dir_all(&jni_path)
|
fs::create_dir_all(&jni_path)
|
||||||
.expect("An error occurred while creating the JNI folder!");
|
.expect("An error occurred while creating the JNI folder!");
|
||||||
|
|
||||||
let java_gen = FlapigenGenerator::new(LanguageConfig::JavaConfig(
|
let java_gen = FlapigenGenerator::new(LanguageConfig::JavaConfig(
|
||||||
|
@ -35,14 +33,14 @@ fn main() {
|
||||||
"com.codemp.intellij.jni".into()
|
"com.codemp.intellij.jni".into()
|
||||||
))).rustfmt_bindings(true);
|
))).rustfmt_bindings(true);
|
||||||
|
|
||||||
java_gen.expand(
|
java_gen.expand_many(
|
||||||
"codemp-intellij",
|
"codemp-intellij",
|
||||||
&glue_file,
|
&[&generated_glue_file, &glue_file],
|
||||||
out_dir.join("glue.rs"),
|
out_dir.join("glue.rs"),
|
||||||
);
|
);
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"cargo:rerun-if-changed={}",
|
"cargo:rerun-if-changed={}",
|
||||||
Path::new("src/main").join(&glue_file).display()
|
Path::new("src/main").join(&generated_glue_file).display()
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
package com.codemp.intellij;
|
package com.codemp.intellij;
|
||||||
|
|
||||||
|
import com.codemp.intellij.exceptions.lib.ChannelException;
|
||||||
|
import com.codemp.intellij.exceptions.lib.DeadlockedException;
|
||||||
|
import com.codemp.intellij.exceptions.lib.InvalidStateException;
|
||||||
|
import com.codemp.intellij.exceptions.lib.TransportException;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.util.SystemInfo;
|
import com.intellij.openapi.util.SystemInfo;
|
||||||
import cz.adamh.utils.NativeUtils;
|
import cz.adamh.utils.NativeUtils;
|
||||||
|
@ -20,7 +24,7 @@ public class CodeMP {
|
||||||
public static void loadLibrary() {
|
public static void loadLibrary() {
|
||||||
if(!loadedLibrary) {
|
if(!loadedLibrary) {
|
||||||
try {
|
try {
|
||||||
if(SystemInfo.isWindows) //TODO on win for some reason it bundles it twice
|
if(SystemInfo.isWindows)
|
||||||
NativeUtils.loadLibraryFromJar("/natives/codemp_intellij.dll");
|
NativeUtils.loadLibraryFromJar("/natives/codemp_intellij.dll");
|
||||||
else NativeUtils.loadLibraryFromJar("/natives/libcodemp_intellij.so");
|
else NativeUtils.loadLibraryFromJar("/natives/libcodemp_intellij.so");
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
|
|
|
@ -6,16 +6,4 @@ public class ChannelException extends CodeMPException {
|
||||||
public ChannelException(String input) {
|
public ChannelException(String input) {
|
||||||
super(input);
|
super(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Send extends ChannelException {
|
|
||||||
public Send(String input) {
|
|
||||||
super(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Read extends ChannelException {
|
|
||||||
public Read(String input) {
|
|
||||||
super(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.codemp.intellij.exceptions.lib;
|
||||||
|
|
||||||
|
import com.codemp.intellij.exceptions.CodeMPException;
|
||||||
|
|
||||||
|
public class DeadlockedException extends CodeMPException {
|
||||||
|
public DeadlockedException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package com.codemp.intellij.task;
|
package com.codemp.intellij.task;
|
||||||
|
|
||||||
import com.codemp.intellij.CodeMP;
|
import com.codemp.intellij.CodeMP;
|
||||||
|
import com.codemp.intellij.exceptions.lib.DeadlockedException;
|
||||||
import com.codemp.intellij.jni.BufferHandler;
|
import com.codemp.intellij.jni.BufferHandler;
|
||||||
import com.codemp.intellij.jni.CodeMPHandler;
|
import com.codemp.intellij.jni.CodeMPHandler;
|
||||||
import com.codemp.intellij.jni.TextChangeWrapper;
|
import com.codemp.intellij.jni.TextChangeWrapper;
|
||||||
|
@ -67,11 +68,9 @@ public class BufferEventAwaiterTask extends Task.Backgroundable implements Dispo
|
||||||
Optional<TextChangeWrapper> changeOptional;
|
Optional<TextChangeWrapper> changeOptional;
|
||||||
try {
|
try {
|
||||||
changeOptional = handler.tryRecv();
|
changeOptional = handler.tryRecv();
|
||||||
} catch(Exception e) {
|
} catch(DeadlockedException e) {
|
||||||
CodeMP.LOGGER.error(e.getMessage());
|
CodeMP.LOGGER.error(e.getMessage());
|
||||||
if(e.getMessage().equals("Error: deadlocked! (safe to retry)"))
|
|
||||||
continue;
|
continue;
|
||||||
else throw e;
|
|
||||||
}
|
}
|
||||||
if(changeOptional.isEmpty())
|
if(changeOptional.isEmpty())
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -39,7 +39,9 @@ public class ActionUtil {
|
||||||
|
|
||||||
public static void notifyError(AnActionEvent event, String title, Throwable t) {
|
public static void notifyError(AnActionEvent event, String title, Throwable t) {
|
||||||
Notifications.Bus.notify(new Notification(
|
Notifications.Bus.notify(new Notification(
|
||||||
"CodeMP", title, t.getMessage(), NotificationType.ERROR
|
"CodeMP", title,
|
||||||
|
String.format("%s: %s", t.getClass().getCanonicalName(), t.getMessage()),
|
||||||
|
NotificationType.ERROR
|
||||||
), event.getProject());
|
), event.getProject());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
use codemp::Error;
|
|
||||||
use codemp::prelude::CodempError;
|
|
||||||
|
|
||||||
pub struct ErrorWrapper(CodempError);
|
|
||||||
|
|
||||||
impl From::<CodempError> for ErrorWrapper {
|
|
||||||
fn from(value: CodempError) -> Self {
|
|
||||||
ErrorWrapper(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ErrorWrapper {
|
|
||||||
pub fn get_error_message(&self) -> String {
|
|
||||||
match &self.0 {
|
|
||||||
CodempError::Transport { status, message } =>
|
|
||||||
format!("Error {}: {}", status, message),
|
|
||||||
CodempError::InvalidState { msg } => msg.to_string(),
|
|
||||||
CodempError::Filler { message } => message.to_string(),
|
|
||||||
Error::Deadlocked => { "Error: deadlocked! (safe to retry)".to_string() }
|
|
||||||
CodempError::Channel { send } => {
|
|
||||||
if *send {
|
|
||||||
"Error while sending message on channel: the channel was closed!".to_string()
|
|
||||||
} else {
|
|
||||||
"Error while reading message from channel: the channel was closed!".to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
40
src/main/rust/glue.in
Normal file
40
src/main/rust/glue.in
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
foreign_typemap!( //thanks @tasn on GitHub for the idea
|
||||||
|
($p:r_type) <T> CodempResult<T> => swig_i_type!(T) {
|
||||||
|
$out = match $p {
|
||||||
|
Ok(x) => {
|
||||||
|
swig_from_rust_to_i_type!(T, x, ret)
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
let (msg, exception_class) = match err {
|
||||||
|
CodempError::Filler { message } => (
|
||||||
|
message,
|
||||||
|
swig_jni_find_class!(CODEMP_EXCEPTION, "com/codemp/intellij/exceptions/CodeMPException")
|
||||||
|
),
|
||||||
|
CodempError::Transport { status, message } => (
|
||||||
|
format!("Status {}: {}", status, message),
|
||||||
|
swig_jni_find_class!(TRANSPORT_EXCEPTION, "com/codemp/intellij/exceptions/lib/TransportException")
|
||||||
|
),
|
||||||
|
CodempError::InvalidState { msg } => (
|
||||||
|
msg, swig_jni_find_class!(INVALID_STATE_EXCEPTION, "com/codemp/intellij/exceptions/lib/InvalidStateException")
|
||||||
|
),
|
||||||
|
CodempError::Deadlocked => (
|
||||||
|
"WOOT deadlocked (safe to retry)!".to_string(),
|
||||||
|
swig_jni_find_class!(DEADLOCKED_EXCEPTION, "com/codemp/intellij/exceptions/lib/DeadlockedException")
|
||||||
|
),
|
||||||
|
CodempError::Channel { send } => {
|
||||||
|
let verb = if send { "sending" } else { "reading" };
|
||||||
|
(
|
||||||
|
format!("Error while {} message on channel: the channel was closed!", verb),
|
||||||
|
swig_jni_find_class!(CHANNEL_EXCEPTION, "com/codemp/intellij/exceptions/lib/ChannelException")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
jni_throw(env, exception_class, &msg);
|
||||||
|
return <swig_i_type!(T)>::jni_invalid_value();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
($p:f_type, unique_prefix="/*codemp::prelude::CodempResult<swig_subst_type!(T)>*/") => "/*codemp::prelude::CodempResult<swig_subst_type!(T)>*/swig_f_type!(T)"
|
||||||
|
"swig_foreign_from_i_type!(T, $p)";
|
||||||
|
);
|
|
@ -1,16 +1,13 @@
|
||||||
mod error;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use codemp::prelude::*;
|
use codemp::prelude::*;
|
||||||
use rifgen::rifgen_attr::{generate_access_methods, generate_interface, generate_interface_doc};
|
use rifgen::rifgen_attr::{generate_access_methods, generate_interface, generate_interface_doc};
|
||||||
use crate::error::ErrorWrapper;
|
|
||||||
|
|
||||||
pub mod glue { //rifgen generated code
|
pub mod glue { //rifgen generated code
|
||||||
include!(concat!(env!("OUT_DIR"), "/glue.rs"));
|
include!(concat!(env!("OUT_DIR"), "/glue.rs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface_doc]
|
#[generate_interface_doc]
|
||||||
struct CodeMPHandler {}
|
struct CodeMPHandler;
|
||||||
|
|
||||||
impl CodeMPHandler {
|
impl CodeMPHandler {
|
||||||
#[generate_interface(constructor)]
|
#[generate_interface(constructor)]
|
||||||
|
@ -19,73 +16,61 @@ impl CodeMPHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn connect(addr: String) -> Result<(), String> {
|
fn connect(addr: String) -> CodempResult<()> {
|
||||||
convert(CODEMP_INSTANCE.connect(&addr))
|
CODEMP_INSTANCE.connect(&addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn join(session: String) -> Result<CursorHandler, String> {
|
fn join(session: String) -> CodempResult<CursorHandler> {
|
||||||
convert_cursor(CODEMP_INSTANCE.join(&session))
|
CODEMP_INSTANCE.join(&session).map(|controller| CursorHandler { cursor: controller })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn create(path: String) -> Result<(), String> {
|
fn create(path: String) -> CodempResult<()> {
|
||||||
convert(CODEMP_INSTANCE.create(&path, None))
|
CODEMP_INSTANCE.create(&path, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn create_with_content(path: String, content: String) -> Result<(), String> {
|
fn create_with_content(path: String, content: String) -> CodempResult<()> {
|
||||||
convert(CODEMP_INSTANCE.create(&path, Some(&content)))
|
CODEMP_INSTANCE.create(&path, Some(&content))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn attach(path: String) -> Result<BufferHandler, String> {
|
fn attach(path: String) -> CodempResult<BufferHandler> {
|
||||||
convert_buffer(CODEMP_INSTANCE.attach(&path))
|
CODEMP_INSTANCE.attach(&path).map(|b| BufferHandler { buffer: b })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn detach(path: String) -> Result<bool, String> {
|
fn detach(path: String) -> CodempResult<bool> {
|
||||||
convert(CODEMP_INSTANCE.disconnect_buffer(&path))
|
CODEMP_INSTANCE.disconnect_buffer(&path)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn get_cursor() -> Result<CursorHandler, String> {
|
fn get_cursor() -> CodempResult<CursorHandler> {
|
||||||
convert_cursor(CODEMP_INSTANCE.get_cursor())
|
CODEMP_INSTANCE.get_cursor().map(|c| CursorHandler { cursor: c })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn get_buffer(path: String) -> Result<BufferHandler, String> {
|
fn get_buffer(path: String) -> CodempResult<BufferHandler> {
|
||||||
convert_buffer(CODEMP_INSTANCE.get_buffer(&path))
|
CODEMP_INSTANCE.get_buffer(&path).map(|b| BufferHandler { buffer: b })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn leave_workspace() -> Result<(), String> {
|
fn leave_workspace() -> CodempResult<()> {
|
||||||
convert(CODEMP_INSTANCE.leave_workspace())
|
CODEMP_INSTANCE.leave_workspace()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn disconnect_buffer(path: String) -> Result<bool, String> {
|
fn disconnect_buffer(path: String) -> CodempResult<bool> {
|
||||||
convert(CODEMP_INSTANCE.disconnect_buffer(&path))
|
CODEMP_INSTANCE.disconnect_buffer(&path)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn select_buffer() -> Result<String, String> {
|
fn select_buffer() -> CodempResult<String> {
|
||||||
convert(CODEMP_INSTANCE.select_buffer())
|
CODEMP_INSTANCE.select_buffer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_buffer(result: Result<Arc<CodempBufferController>, CodempError>) -> Result<BufferHandler, String> {
|
|
||||||
convert(result).map(|val| BufferHandler { buffer: val })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_cursor(result: Result<Arc<CodempCursorController>, CodempError>) -> Result<CursorHandler, String> {
|
|
||||||
convert(result).map(|val| CursorHandler { cursor: val })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert<T>(result: Result<T, CodempError>) -> Result<T, String> {
|
|
||||||
result.map_err(|err| ErrorWrapper::from(err).get_error_message())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[generate_interface_doc]
|
#[generate_interface_doc]
|
||||||
#[generate_access_methods]
|
#[generate_access_methods]
|
||||||
struct CursorEventWrapper {
|
struct CursorEventWrapper {
|
||||||
|
@ -111,9 +96,9 @@ impl CursorHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn recv(&self) -> Result<CursorEventWrapper, String> {
|
fn recv(&self) -> CodempResult<CursorEventWrapper> {
|
||||||
match self.cursor.blocking_recv(CODEMP_INSTANCE.rt()) {
|
match self.cursor.blocking_recv(CODEMP_INSTANCE.rt()) {
|
||||||
Err(err) => Err(ErrorWrapper::from(err).get_error_message()),
|
Err(err) => Err(err),
|
||||||
Ok(event) => Ok(CursorEventWrapper {
|
Ok(event) => Ok(CursorEventWrapper {
|
||||||
user: event.user,
|
user: event.user,
|
||||||
buffer: event.position.as_ref().unwrap().buffer.clone(),
|
buffer: event.position.as_ref().unwrap().buffer.clone(),
|
||||||
|
@ -126,12 +111,12 @@ impl CursorHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn send(&self, buffer: String, start_row: i32, start_col: i32, end_row: i32, end_col: i32) -> Result<(), String> {
|
fn send(&self, buffer: String, start_row: i32, start_col: i32, end_row: i32, end_col: i32) -> CodempResult<()> {
|
||||||
self.cursor.send(CodempCursorPosition {
|
self.cursor.send(CodempCursorPosition {
|
||||||
buffer,
|
buffer,
|
||||||
start: CodempRowCol::wrap(start_row, start_col),
|
start: CodempRowCol::wrap(start_row, start_col),
|
||||||
end: CodempRowCol::wrap(end_row, end_col)
|
end: CodempRowCol::wrap(end_row, end_col)
|
||||||
}).map_err(|err| ErrorWrapper::from(err).get_error_message())
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,9 +146,9 @@ impl BufferHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn try_recv(&self) -> Result<Option<TextChangeWrapper>, String> {
|
fn try_recv(&self) -> CodempResult<Option<TextChangeWrapper>> {
|
||||||
match self.buffer.try_recv() {
|
match self.buffer.try_recv() {
|
||||||
Err(err) => Err(ErrorWrapper::from(err).get_error_message()),
|
Err(err) => Err(err),
|
||||||
Ok(None) => Ok(None),
|
Ok(None) => Ok(None),
|
||||||
Ok(Some(change)) => Ok(Some(TextChangeWrapper {
|
Ok(Some(change)) => Ok(Some(TextChangeWrapper {
|
||||||
start: change.span.start,
|
start: change.span.start,
|
||||||
|
@ -174,9 +159,9 @@ impl BufferHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn recv(&self) -> Result<TextChangeWrapper, String> {
|
fn recv(&self) -> CodempResult<TextChangeWrapper> {
|
||||||
match self.buffer.blocking_recv(CODEMP_INSTANCE.rt()) {
|
match self.buffer.blocking_recv(CODEMP_INSTANCE.rt()) {
|
||||||
Err(err) => Err(ErrorWrapper::from(err).get_error_message()),
|
Err(err) => Err(err),
|
||||||
Ok(change) => Ok(TextChangeWrapper {
|
Ok(change) => Ok(TextChangeWrapper {
|
||||||
start: change.span.start,
|
start: change.span.start,
|
||||||
end: change.span.end,
|
end: change.span.end,
|
||||||
|
@ -186,8 +171,7 @@ impl BufferHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_interface]
|
#[generate_interface]
|
||||||
fn send(&self, start_offset: usize, end_offset: usize, content: String) -> Result<(), String> {
|
fn send(&self, start_offset: usize, end_offset: usize, content: String) -> CodempResult<()> {
|
||||||
self.buffer.send(CodempTextChange { span: start_offset..end_offset, content })
|
self.buffer.send(CodempTextChange { span: start_offset..end_offset, content })
|
||||||
.map_err(|err| ErrorWrapper::from(err).get_error_message())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue