diff --git a/Cargo.lock b/Cargo.lock index b30db4e..641899f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -420,6 +420,16 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "dictionary" +version = "0.1.0" +dependencies = [ + "abi_stable", + "anyrun-plugin", + "reqwest", + "serde", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -1528,11 +1538,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.13" +version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" +checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", "bytes", "encoding_rs", "futures-core", diff --git a/Cargo.toml b/Cargo.toml index 5599cef..67b2293 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ members = [ "plugins/translate", "plugins/randr", "plugins/stdin", + "plugins/dictionary", ] \ No newline at end of file diff --git a/anyrun-plugin/src/lib.rs b/anyrun-plugin/src/lib.rs index 846741e..f121b3c 100644 --- a/anyrun-plugin/src/lib.rs +++ b/anyrun-plugin/src/lib.rs @@ -32,8 +32,8 @@ macro_rules! plugin { > = ::std::sync::Mutex::new(None); static ANYRUN_INTERNAL_ID_COUNTER: ::std::sync::atomic::AtomicU64 = ::std::sync::atomic::AtomicU64::new(0); - static ANYRUN_INTERNAL_DATA: ::std::sync::Mutex> = - ::std::sync::Mutex::new(None); + static ANYRUN_INTERNAL_DATA: ::std::sync::RwLock> = + ::std::sync::RwLock::new(None); #[::abi_stable::export_root_module] fn anyrun_internal_init_root_module() -> ::anyrun_plugin::anyrun_interface::PluginRef { @@ -51,7 +51,7 @@ macro_rules! plugin { #[::abi_stable::sabi_extern_fn] fn anyrun_internal_init(config_dir: ::abi_stable::std_types::RString) { ::std::thread::spawn(|| { - *ANYRUN_INTERNAL_DATA.lock().unwrap() = Some($init(config_dir)); + *ANYRUN_INTERNAL_DATA.write().unwrap() = Some($init(config_dir)); }); } @@ -68,7 +68,7 @@ macro_rules! plugin { .store(current_id + 1, ::std::sync::atomic::Ordering::Relaxed); let handle = ::std::thread::spawn(move || { - if let Some(data) = ANYRUN_INTERNAL_DATA.lock().unwrap().as_mut() { + if let Some(data) = ANYRUN_INTERNAL_DATA.read().unwrap().as_ref() { $get_matches(input, data) } else { ::abi_stable::std_types::RVec::new() @@ -108,7 +108,7 @@ macro_rules! plugin { ) -> ::anyrun_plugin::anyrun_interface::HandleResult { $handler( selection, - ANYRUN_INTERNAL_DATA.lock().unwrap().as_mut().unwrap(), + ANYRUN_INTERNAL_DATA.write().unwrap().as_mut().unwrap(), ) } }; diff --git a/plugins/applications/src/lib.rs b/plugins/applications/src/lib.rs index 1c235b7..45a3f4f 100644 --- a/plugins/applications/src/lib.rs +++ b/plugins/applications/src/lib.rs @@ -49,7 +49,7 @@ pub fn init(config_dir: RString) -> Vec<(DesktopEntry, u64)> { }) } -pub fn get_matches(input: RString, entries: &mut Vec<(DesktopEntry, u64)>) -> RVec { +pub fn get_matches(input: RString, entries: &Vec<(DesktopEntry, u64)>) -> RVec { let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case(); let mut entries = entries .clone() diff --git a/plugins/dictionary/Cargo.toml b/plugins/dictionary/Cargo.toml new file mode 100644 index 0000000..45cb1b0 --- /dev/null +++ b/plugins/dictionary/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "dictionary" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyrun-plugin = { path = "../../anyrun-plugin" } +abi_stable = "0.11.1" +reqwest = { version = "0.11.16", default-features = false, features = ["blocking", "json", "rustls-tls"] } +serde = { version = "1.0.160", features = ["derive"] } diff --git a/plugins/dictionary/src/lib.rs b/plugins/dictionary/src/lib.rs new file mode 100644 index 0000000..4d3058f --- /dev/null +++ b/plugins/dictionary/src/lib.rs @@ -0,0 +1,97 @@ +use abi_stable::std_types::{ROption, RString, RVec}; +use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct ApiResponse { + word: String, + phonetic: Option, + phonetics: Vec, + origin: Option, + meanings: Vec, +} + +#[derive(Deserialize)] +struct Phonetic { + text: String, + audio: Option, +} + +#[derive(Deserialize)] +struct Meaning { + #[serde(rename = "partOfSpeech")] + part_of_speech: String, + definitions: Vec, +} + +#[derive(Deserialize)] +struct Definition { + definition: String, + example: Option, + synonyms: Vec, + antonyms: Vec, +} + +pub fn init(_config_dir: RString) {} + +pub fn handler(_match: Match, _: &mut ()) -> HandleResult { + HandleResult::Copy(_match.title.into_bytes()) +} + +pub fn get_matches(input: RString, _: &()) -> RVec { + if !input.starts_with(":def") { + return RVec::new(); + } + + let input = &input[4..].trim(); + + let responses: Vec = match reqwest::blocking::get(format!( + "https://api.dictionaryapi.dev/api/v2/entries/en/{}", + input + )) { + Ok(response) => match response.json() { + Ok(response) => response, + Err(why) => { + eprintln!("Error deserializing response: {}", why); + return RVec::new(); + } + }, + Err(why) => { + eprintln!("Error fetching dictionary result: {}", why); + return RVec::new(); + } + }; + + responses + .into_iter() + .flat_map(|response| { + response + .meanings + .into_iter() + .flat_map(|meaning| { + meaning + .definitions + .into_iter() + .map(|definition| Match { + title: definition.definition.into(), + description: ROption::RSome(meaning.part_of_speech.clone().into()), + use_pango: false, + icon: ROption::RSome("accessories-dictionary".into()), + id: ROption::RNone, + }) + .collect::>() + }) + .collect::>() + }) + .take(3) + .collect() +} + +fn info() -> PluginInfo { + PluginInfo { + name: "Dictionary".into(), + icon: "accessories-dictionary".into(), + } +} + +plugin!(init, info, get_matches, handler, ()); diff --git a/plugins/kidex/src/lib.rs b/plugins/kidex/src/lib.rs index ae236f4..bcbb593 100644 --- a/plugins/kidex/src/lib.rs +++ b/plugins/kidex/src/lib.rs @@ -69,7 +69,7 @@ pub fn init(_config_dir: RString) -> State { } } -pub fn get_matches(input: RString, state: &mut State) -> RVec { +pub fn get_matches(input: RString, state: &State) -> RVec { match &state.selection { Some(index_entry) => { let path = index_entry.path.to_string_lossy(); diff --git a/plugins/randr/src/lib.rs b/plugins/randr/src/lib.rs index 508e558..046a7ef 100644 --- a/plugins/randr/src/lib.rs +++ b/plugins/randr/src/lib.rs @@ -98,7 +98,7 @@ pub fn handler(_match: Match, state: &mut State) -> HandleResult { } } -pub fn get_matches(input: RString, state: &mut State) -> RVec { +pub fn get_matches(input: RString, state: &State) -> RVec { if !input.starts_with(&state.config.prefix) { return RVec::new(); } diff --git a/plugins/rink/src/lib.rs b/plugins/rink/src/lib.rs index 9ab92f9..9cfde1c 100644 --- a/plugins/rink/src/lib.rs +++ b/plugins/rink/src/lib.rs @@ -1,9 +1,15 @@ use abi_stable::std_types::{ROption, RString, RVec}; use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo}; -use rink_core::{ast, date, gnu_units, CURRENCY_FILE}; -fn init(_config_dir: RString) -> rink_core::Context { - let mut ctx = rink_core::Context::new(); +fn init(_config_dir: RString) { + // Currently broken due to limitations with the declarative macro anyrun_plugin crate. + // For any plugin that does something relatively time intensive like fetching something + // from the internet, the internal Mutex would block making requests way too long when typed rapidly. + + // TODO: Redesign the anyrun_plugin crate to allow for both mutable and non mutable borrows of the + // shared data for functions + + /*let mut ctx = rink_core::Context::new(); let units = gnu_units::parse_str(rink_core::DEFAULT_FILE.unwrap()); let dates = date::parse_datefile(rink_core::DATES_FILE); @@ -28,7 +34,7 @@ fn init(_config_dir: RString) -> rink_core::Context { }); ctx.load_dates(dates); - ctx + ctx*/ } fn info() -> PluginInfo { @@ -38,8 +44,11 @@ fn info() -> PluginInfo { } } -fn get_matches(input: RString, ctx: &mut rink_core::Context) -> RVec { - match rink_core::one_line(ctx, &input) { +fn get_matches(input: RString, _: &()) -> RVec { + match rink_core::one_line( + &mut rink_core::simple_context().expect("Failed to create rink context"), + &input, + ) { Ok(result) => vec![Match { title: result.into(), description: ROption::RNone, @@ -52,8 +61,8 @@ fn get_matches(input: RString, ctx: &mut rink_core::Context) -> RVec { } } -fn handler(selection: Match, _: &mut rink_core::Context) -> HandleResult { +fn handler(selection: Match, _: &mut ()) -> HandleResult { HandleResult::Copy(selection.title.into_bytes()) } -plugin!(init, info, get_matches, handler, rink_core::Context); +plugin!(init, info, get_matches, handler, ()); diff --git a/plugins/shell/src/lib.rs b/plugins/shell/src/lib.rs index c8943c7..6c63cd1 100644 --- a/plugins/shell/src/lib.rs +++ b/plugins/shell/src/lib.rs @@ -33,10 +33,9 @@ fn info() -> PluginInfo { } } -fn get_matches(input: RString, config: &mut Config) -> RVec { - let prefix_with_delim = format!("{}", config.prefix); - if input.starts_with(&prefix_with_delim) { - let (_, command) = input.split_once(&prefix_with_delim).unwrap(); +fn get_matches(input: RString, config: &Config) -> RVec { + if input.starts_with(&config.prefix) { + let (_, command) = input.split_once(&config.prefix).unwrap(); if !command.is_empty() { vec![Match { title: command.into(), diff --git a/plugins/stdin/src/lib.rs b/plugins/stdin/src/lib.rs index 2e048de..53229c8 100644 --- a/plugins/stdin/src/lib.rs +++ b/plugins/stdin/src/lib.rs @@ -12,7 +12,7 @@ fn handler(_match: Match, _lines: &mut Vec) -> HandleResult { HandleResult::Stdout(_match.title.into_bytes()) } -fn get_matches(input: RString, lines: &mut Vec) -> RVec { +fn get_matches(input: RString, lines: &Vec) -> RVec { let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case(); let mut lines = lines diff --git a/plugins/symbols/src/lib.rs b/plugins/symbols/src/lib.rs index c0b8e81..7052668 100644 --- a/plugins/symbols/src/lib.rs +++ b/plugins/symbols/src/lib.rs @@ -53,7 +53,7 @@ fn info() -> PluginInfo { } } -fn get_matches(input: RString, symbols: &mut Vec) -> RVec { +fn get_matches(input: RString, symbols: &Vec) -> RVec { let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().ignore_case(); let mut symbols = symbols .clone() diff --git a/plugins/translate/src/lib.rs b/plugins/translate/src/lib.rs index 2403489..0d0f8d3 100644 --- a/plugins/translate/src/lib.rs +++ b/plugins/translate/src/lib.rs @@ -18,13 +18,13 @@ impl Default for Config { } } -struct RuntimeData { +struct State { config: Config, langs: Vec<(&'static str, &'static str)>, } -fn init(config_dir: RString) -> RuntimeData { - RuntimeData { +fn init(config_dir: RString) -> State { + State { config: match fs::read_to_string(format!("{}/translate.ron", config_dir)) { Ok(content) => ron::from_str(&content).unwrap_or_default(), Err(_) => Config::default(), @@ -145,7 +145,7 @@ fn info() -> PluginInfo { } } -fn get_matches(input: RString, data: &mut RuntimeData) -> RVec { +fn get_matches(input: RString, data: &State) -> RVec { if !input.starts_with(&data.config.prefix) { return RVec::new(); } @@ -227,8 +227,8 @@ fn get_matches(input: RString, data: &mut RuntimeData) -> RVec { }) } -fn handler(selection: Match, _data: &mut RuntimeData) -> HandleResult { +fn handler(selection: Match, _data: &mut State) -> HandleResult { HandleResult::Copy(selection.title.into_bytes()) } -plugin!(init, info, get_matches, handler, RuntimeData); +plugin!(init, info, get_matches, handler, State);