diff --git a/build.rs b/build.rs index 2c6bb48..a2e12b6 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,5 @@ use flapigen::{JavaConfig, LanguageConfig}; -use std::{env, path::Path}; +use std::{env, fs, path::Path}; use rifgen::{Generator as RifgenGenerator, TypeCases, Language}; use flapigen::Generator as FlapigenGenerator; @@ -7,15 +7,13 @@ fn main() { let out_dir_var = env::var("OUT_DIR") .expect("no OUT_DIR, but cargo should provide it"); let out_dir = Path::new(&out_dir_var); + let generated_glue_file = out_dir.join("generated_glue.in"); - let mut source_folders = Vec::new(); - source_folders.push(Path::new("src/main/rust/")); + let src_dir = 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, - source_folders) - .generate_interface(&glue_file); + RifgenGenerator::new(TypeCases::CamelCase,Language::Java, vec!(src_dir)) + .generate_interface(&generated_glue_file); let jni_path = Path::new("src") .join("main") @@ -26,7 +24,7 @@ fn main() { .join("jni"); //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!"); let java_gen = FlapigenGenerator::new(LanguageConfig::JavaConfig( @@ -35,14 +33,14 @@ fn main() { "com.codemp.intellij.jni".into() ))).rustfmt_bindings(true); - java_gen.expand( + java_gen.expand_many( "codemp-intellij", - &glue_file, + &[&generated_glue_file, &glue_file], out_dir.join("glue.rs"), ); println!( "cargo:rerun-if-changed={}", - Path::new("src/main").join(&glue_file).display() + Path::new("src/main").join(&generated_glue_file).display() ); -} \ No newline at end of file +} diff --git a/src/main/java/com/codemp/intellij/CodeMP.java b/src/main/java/com/codemp/intellij/CodeMP.java index 0842950..3082c63 100644 --- a/src/main/java/com/codemp/intellij/CodeMP.java +++ b/src/main/java/com/codemp/intellij/CodeMP.java @@ -1,5 +1,9 @@ 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.util.SystemInfo; import cz.adamh.utils.NativeUtils; @@ -20,7 +24,7 @@ public class CodeMP { public static void loadLibrary() { if(!loadedLibrary) { try { - if(SystemInfo.isWindows) //TODO on win for some reason it bundles it twice + if(SystemInfo.isWindows) NativeUtils.loadLibraryFromJar("/natives/codemp_intellij.dll"); else NativeUtils.loadLibraryFromJar("/natives/libcodemp_intellij.so"); } catch(IOException e) { diff --git a/src/main/java/com/codemp/intellij/exceptions/lib/ChannelException.java b/src/main/java/com/codemp/intellij/exceptions/lib/ChannelException.java index 2e30040..07890f3 100644 --- a/src/main/java/com/codemp/intellij/exceptions/lib/ChannelException.java +++ b/src/main/java/com/codemp/intellij/exceptions/lib/ChannelException.java @@ -6,16 +6,4 @@ public class ChannelException extends CodeMPException { public ChannelException(String 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); - } - } } diff --git a/src/main/java/com/codemp/intellij/exceptions/lib/DeadlockedException.java b/src/main/java/com/codemp/intellij/exceptions/lib/DeadlockedException.java new file mode 100644 index 0000000..9637fdb --- /dev/null +++ b/src/main/java/com/codemp/intellij/exceptions/lib/DeadlockedException.java @@ -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); + } +} diff --git a/src/main/java/com/codemp/intellij/task/BufferEventAwaiterTask.java b/src/main/java/com/codemp/intellij/task/BufferEventAwaiterTask.java index e1f3091..c1820d1 100644 --- a/src/main/java/com/codemp/intellij/task/BufferEventAwaiterTask.java +++ b/src/main/java/com/codemp/intellij/task/BufferEventAwaiterTask.java @@ -1,6 +1,7 @@ package com.codemp.intellij.task; import com.codemp.intellij.CodeMP; +import com.codemp.intellij.exceptions.lib.DeadlockedException; import com.codemp.intellij.jni.BufferHandler; import com.codemp.intellij.jni.CodeMPHandler; import com.codemp.intellij.jni.TextChangeWrapper; @@ -67,11 +68,9 @@ public class BufferEventAwaiterTask extends Task.Backgroundable implements Dispo Optional changeOptional; try { changeOptional = handler.tryRecv(); - } catch(Exception e) { + } catch(DeadlockedException e) { CodeMP.LOGGER.error(e.getMessage()); - if(e.getMessage().equals("Error: deadlocked! (safe to retry)")) - continue; - else throw e; + continue; } if(changeOptional.isEmpty()) break; diff --git a/src/main/java/com/codemp/intellij/util/ActionUtil.java b/src/main/java/com/codemp/intellij/util/ActionUtil.java index 914c463..08ee5f3 100644 --- a/src/main/java/com/codemp/intellij/util/ActionUtil.java +++ b/src/main/java/com/codemp/intellij/util/ActionUtil.java @@ -39,7 +39,9 @@ public class ActionUtil { public static void notifyError(AnActionEvent event, String title, Throwable t) { 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()); } } diff --git a/src/main/rust/error.rs b/src/main/rust/error.rs deleted file mode 100644 index c8b3877..0000000 --- a/src/main/rust/error.rs +++ /dev/null @@ -1,30 +0,0 @@ -use codemp::Error; -use codemp::prelude::CodempError; - -pub struct ErrorWrapper(CodempError); - -impl From:: 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() - } - } - } - } -} - diff --git a/src/main/rust/glue.in b/src/main/rust/glue.in new file mode 100644 index 0000000..42997f6 --- /dev/null +++ b/src/main/rust/glue.in @@ -0,0 +1,40 @@ +foreign_typemap!( //thanks @tasn on GitHub for the idea + ($p:r_type) CodempResult => 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 ::jni_invalid_value(); + } + }; + }; + ($p:f_type, unique_prefix="/*codemp::prelude::CodempResult*/") => "/*codemp::prelude::CodempResult*/swig_f_type!(T)" + "swig_foreign_from_i_type!(T, $p)"; +); diff --git a/src/main/rust/lib.rs b/src/main/rust/lib.rs index daff112..97d49f7 100644 --- a/src/main/rust/lib.rs +++ b/src/main/rust/lib.rs @@ -1,16 +1,13 @@ -mod error; - use std::sync::Arc; use codemp::prelude::*; use rifgen::rifgen_attr::{generate_access_methods, generate_interface, generate_interface_doc}; -use crate::error::ErrorWrapper; pub mod glue { //rifgen generated code include!(concat!(env!("OUT_DIR"), "/glue.rs")); } #[generate_interface_doc] -struct CodeMPHandler {} +struct CodeMPHandler; impl CodeMPHandler { #[generate_interface(constructor)] @@ -19,73 +16,61 @@ impl CodeMPHandler { } #[generate_interface] - fn connect(addr: String) -> Result<(), String> { - convert(CODEMP_INSTANCE.connect(&addr)) + fn connect(addr: String) -> CodempResult<()> { + CODEMP_INSTANCE.connect(&addr) } #[generate_interface] - fn join(session: String) -> Result { - convert_cursor(CODEMP_INSTANCE.join(&session)) + fn join(session: String) -> CodempResult { + CODEMP_INSTANCE.join(&session).map(|controller| CursorHandler { cursor: controller }) } #[generate_interface] - fn create(path: String) -> Result<(), String> { - convert(CODEMP_INSTANCE.create(&path, None)) + fn create(path: String) -> CodempResult<()> { + CODEMP_INSTANCE.create(&path, None) } #[generate_interface] - fn create_with_content(path: String, content: String) -> Result<(), String> { - convert(CODEMP_INSTANCE.create(&path, Some(&content))) + fn create_with_content(path: String, content: String) -> CodempResult<()> { + CODEMP_INSTANCE.create(&path, Some(&content)) } #[generate_interface] - fn attach(path: String) -> Result { - convert_buffer(CODEMP_INSTANCE.attach(&path)) + fn attach(path: String) -> CodempResult { + CODEMP_INSTANCE.attach(&path).map(|b| BufferHandler { buffer: b }) } #[generate_interface] - fn detach(path: String) -> Result { - convert(CODEMP_INSTANCE.disconnect_buffer(&path)) + fn detach(path: String) -> CodempResult { + CODEMP_INSTANCE.disconnect_buffer(&path) } #[generate_interface] - fn get_cursor() -> Result { - convert_cursor(CODEMP_INSTANCE.get_cursor()) + fn get_cursor() -> CodempResult { + CODEMP_INSTANCE.get_cursor().map(|c| CursorHandler { cursor: c }) } #[generate_interface] - fn get_buffer(path: String) -> Result { - convert_buffer(CODEMP_INSTANCE.get_buffer(&path)) + fn get_buffer(path: String) -> CodempResult { + CODEMP_INSTANCE.get_buffer(&path).map(|b| BufferHandler { buffer: b }) } #[generate_interface] - fn leave_workspace() -> Result<(), String> { - convert(CODEMP_INSTANCE.leave_workspace()) + fn leave_workspace() -> CodempResult<()> { + CODEMP_INSTANCE.leave_workspace() } #[generate_interface] - fn disconnect_buffer(path: String) -> Result { - convert(CODEMP_INSTANCE.disconnect_buffer(&path)) + fn disconnect_buffer(path: String) -> CodempResult { + CODEMP_INSTANCE.disconnect_buffer(&path) } #[generate_interface] - fn select_buffer() -> Result { - convert(CODEMP_INSTANCE.select_buffer()) + fn select_buffer() -> CodempResult { + CODEMP_INSTANCE.select_buffer() } } -fn convert_buffer(result: Result, CodempError>) -> Result { - convert(result).map(|val| BufferHandler { buffer: val }) -} - -fn convert_cursor(result: Result, CodempError>) -> Result { - convert(result).map(|val| CursorHandler { cursor: val }) -} - -fn convert(result: Result) -> Result { - result.map_err(|err| ErrorWrapper::from(err).get_error_message()) -} - #[generate_interface_doc] #[generate_access_methods] struct CursorEventWrapper { @@ -111,9 +96,9 @@ impl CursorHandler { } #[generate_interface] - fn recv(&self) -> Result { + fn recv(&self) -> CodempResult { 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 { user: event.user, buffer: event.position.as_ref().unwrap().buffer.clone(), @@ -126,12 +111,12 @@ impl CursorHandler { } #[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 { buffer, start: CodempRowCol::wrap(start_row, start_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] - fn try_recv(&self) -> Result, String> { + fn try_recv(&self) -> CodempResult> { match self.buffer.try_recv() { - Err(err) => Err(ErrorWrapper::from(err).get_error_message()), + Err(err) => Err(err), Ok(None) => Ok(None), Ok(Some(change)) => Ok(Some(TextChangeWrapper { start: change.span.start, @@ -174,9 +159,9 @@ impl BufferHandler { } #[generate_interface] - fn recv(&self) -> Result { + fn recv(&self) -> CodempResult { 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 { start: change.span.start, end: change.span.end, @@ -186,8 +171,7 @@ impl BufferHandler { } #[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 }) - .map_err(|err| ErrorWrapper::from(err).get_error_message()) } }