Added dictionary plugin and switched from a Mutex
to an RwLock
in the anyrun_plugin
crate
This change means that `get_matches` no longer has access to a mutable version of the state of the plugin. A redesign is needed to allow for this if needed.
This commit is contained in:
16
Cargo.lock
generated
16
Cargo.lock
generated
@@ -420,6 +420,16 @@ dependencies = [
|
|||||||
"syn 1.0.107",
|
"syn 1.0.107",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dictionary"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"abi_stable",
|
||||||
|
"anyrun-plugin",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "doc-comment"
|
name = "doc-comment"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@@ -1528,11 +1538,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.13"
|
version = "0.11.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
|
checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.13.1",
|
"base64 0.21.0",
|
||||||
"bytes",
|
"bytes",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
@@ -11,4 +11,5 @@ members = [
|
|||||||
"plugins/translate",
|
"plugins/translate",
|
||||||
"plugins/randr",
|
"plugins/randr",
|
||||||
"plugins/stdin",
|
"plugins/stdin",
|
||||||
|
"plugins/dictionary",
|
||||||
]
|
]
|
@@ -32,8 +32,8 @@ macro_rules! plugin {
|
|||||||
> = ::std::sync::Mutex::new(None);
|
> = ::std::sync::Mutex::new(None);
|
||||||
static ANYRUN_INTERNAL_ID_COUNTER: ::std::sync::atomic::AtomicU64 =
|
static ANYRUN_INTERNAL_ID_COUNTER: ::std::sync::atomic::AtomicU64 =
|
||||||
::std::sync::atomic::AtomicU64::new(0);
|
::std::sync::atomic::AtomicU64::new(0);
|
||||||
static ANYRUN_INTERNAL_DATA: ::std::sync::Mutex<Option<$type>> =
|
static ANYRUN_INTERNAL_DATA: ::std::sync::RwLock<Option<$type>> =
|
||||||
::std::sync::Mutex::new(None);
|
::std::sync::RwLock::new(None);
|
||||||
|
|
||||||
#[::abi_stable::export_root_module]
|
#[::abi_stable::export_root_module]
|
||||||
fn anyrun_internal_init_root_module() -> ::anyrun_plugin::anyrun_interface::PluginRef {
|
fn anyrun_internal_init_root_module() -> ::anyrun_plugin::anyrun_interface::PluginRef {
|
||||||
@@ -51,7 +51,7 @@ macro_rules! plugin {
|
|||||||
#[::abi_stable::sabi_extern_fn]
|
#[::abi_stable::sabi_extern_fn]
|
||||||
fn anyrun_internal_init(config_dir: ::abi_stable::std_types::RString) {
|
fn anyrun_internal_init(config_dir: ::abi_stable::std_types::RString) {
|
||||||
::std::thread::spawn(|| {
|
::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);
|
.store(current_id + 1, ::std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
let handle = ::std::thread::spawn(move || {
|
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)
|
$get_matches(input, data)
|
||||||
} else {
|
} else {
|
||||||
::abi_stable::std_types::RVec::new()
|
::abi_stable::std_types::RVec::new()
|
||||||
@@ -108,7 +108,7 @@ macro_rules! plugin {
|
|||||||
) -> ::anyrun_plugin::anyrun_interface::HandleResult {
|
) -> ::anyrun_plugin::anyrun_interface::HandleResult {
|
||||||
$handler(
|
$handler(
|
||||||
selection,
|
selection,
|
||||||
ANYRUN_INTERNAL_DATA.lock().unwrap().as_mut().unwrap(),
|
ANYRUN_INTERNAL_DATA.write().unwrap().as_mut().unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -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<Match> {
|
pub fn get_matches(input: RString, entries: &Vec<(DesktopEntry, u64)>) -> RVec<Match> {
|
||||||
let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case();
|
let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case();
|
||||||
let mut entries = entries
|
let mut entries = entries
|
||||||
.clone()
|
.clone()
|
||||||
|
15
plugins/dictionary/Cargo.toml
Normal file
15
plugins/dictionary/Cargo.toml
Normal file
@@ -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"] }
|
97
plugins/dictionary/src/lib.rs
Normal file
97
plugins/dictionary/src/lib.rs
Normal file
@@ -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<String>,
|
||||||
|
phonetics: Vec<Phonetic>,
|
||||||
|
origin: Option<String>,
|
||||||
|
meanings: Vec<Meaning>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Phonetic {
|
||||||
|
text: String,
|
||||||
|
audio: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Meaning {
|
||||||
|
#[serde(rename = "partOfSpeech")]
|
||||||
|
part_of_speech: String,
|
||||||
|
definitions: Vec<Definition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Definition {
|
||||||
|
definition: String,
|
||||||
|
example: Option<String>,
|
||||||
|
synonyms: Vec<String>,
|
||||||
|
antonyms: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Match> {
|
||||||
|
if !input.starts_with(":def") {
|
||||||
|
return RVec::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = &input[4..].trim();
|
||||||
|
|
||||||
|
let responses: Vec<ApiResponse> = 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::<RVec<_>>()
|
||||||
|
})
|
||||||
|
.collect::<RVec<_>>()
|
||||||
|
})
|
||||||
|
.take(3)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn info() -> PluginInfo {
|
||||||
|
PluginInfo {
|
||||||
|
name: "Dictionary".into(),
|
||||||
|
icon: "accessories-dictionary".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin!(init, info, get_matches, handler, ());
|
@@ -69,7 +69,7 @@ pub fn init(_config_dir: RString) -> State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_matches(input: RString, state: &mut State) -> RVec<Match> {
|
pub fn get_matches(input: RString, state: &State) -> RVec<Match> {
|
||||||
match &state.selection {
|
match &state.selection {
|
||||||
Some(index_entry) => {
|
Some(index_entry) => {
|
||||||
let path = index_entry.path.to_string_lossy();
|
let path = index_entry.path.to_string_lossy();
|
||||||
|
@@ -98,7 +98,7 @@ pub fn handler(_match: Match, state: &mut State) -> HandleResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_matches(input: RString, state: &mut State) -> RVec<Match> {
|
pub fn get_matches(input: RString, state: &State) -> RVec<Match> {
|
||||||
if !input.starts_with(&state.config.prefix) {
|
if !input.starts_with(&state.config.prefix) {
|
||||||
return RVec::new();
|
return RVec::new();
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,15 @@
|
|||||||
use abi_stable::std_types::{ROption, RString, RVec};
|
use abi_stable::std_types::{ROption, RString, RVec};
|
||||||
use anyrun_plugin::{anyrun_interface::HandleResult, plugin, Match, PluginInfo};
|
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 {
|
fn init(_config_dir: RString) {
|
||||||
let mut ctx = rink_core::Context::new();
|
// 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 units = gnu_units::parse_str(rink_core::DEFAULT_FILE.unwrap());
|
||||||
let dates = date::parse_datefile(rink_core::DATES_FILE);
|
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.load_dates(dates);
|
||||||
|
|
||||||
ctx
|
ctx*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn info() -> PluginInfo {
|
fn info() -> PluginInfo {
|
||||||
@@ -38,8 +44,11 @@ fn info() -> PluginInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matches(input: RString, ctx: &mut rink_core::Context) -> RVec<Match> {
|
fn get_matches(input: RString, _: &()) -> RVec<Match> {
|
||||||
match rink_core::one_line(ctx, &input) {
|
match rink_core::one_line(
|
||||||
|
&mut rink_core::simple_context().expect("Failed to create rink context"),
|
||||||
|
&input,
|
||||||
|
) {
|
||||||
Ok(result) => vec![Match {
|
Ok(result) => vec![Match {
|
||||||
title: result.into(),
|
title: result.into(),
|
||||||
description: ROption::RNone,
|
description: ROption::RNone,
|
||||||
@@ -52,8 +61,8 @@ fn get_matches(input: RString, ctx: &mut rink_core::Context) -> RVec<Match> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handler(selection: Match, _: &mut rink_core::Context) -> HandleResult {
|
fn handler(selection: Match, _: &mut ()) -> HandleResult {
|
||||||
HandleResult::Copy(selection.title.into_bytes())
|
HandleResult::Copy(selection.title.into_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin!(init, info, get_matches, handler, rink_core::Context);
|
plugin!(init, info, get_matches, handler, ());
|
||||||
|
@@ -33,10 +33,9 @@ fn info() -> PluginInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matches(input: RString, config: &mut Config) -> RVec<Match> {
|
fn get_matches(input: RString, config: &Config) -> RVec<Match> {
|
||||||
let prefix_with_delim = format!("{}", config.prefix);
|
if input.starts_with(&config.prefix) {
|
||||||
if input.starts_with(&prefix_with_delim) {
|
let (_, command) = input.split_once(&config.prefix).unwrap();
|
||||||
let (_, command) = input.split_once(&prefix_with_delim).unwrap();
|
|
||||||
if !command.is_empty() {
|
if !command.is_empty() {
|
||||||
vec![Match {
|
vec![Match {
|
||||||
title: command.into(),
|
title: command.into(),
|
||||||
|
@@ -12,7 +12,7 @@ fn handler(_match: Match, _lines: &mut Vec<String>) -> HandleResult {
|
|||||||
HandleResult::Stdout(_match.title.into_bytes())
|
HandleResult::Stdout(_match.title.into_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matches(input: RString, lines: &mut Vec<String>) -> RVec<Match> {
|
fn get_matches(input: RString, lines: &Vec<String>) -> RVec<Match> {
|
||||||
let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case();
|
let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case();
|
||||||
|
|
||||||
let mut lines = lines
|
let mut lines = lines
|
||||||
|
@@ -53,7 +53,7 @@ fn info() -> PluginInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matches(input: RString, symbols: &mut Vec<Symbol>) -> RVec<Match> {
|
fn get_matches(input: RString, symbols: &Vec<Symbol>) -> RVec<Match> {
|
||||||
let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().ignore_case();
|
let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().ignore_case();
|
||||||
let mut symbols = symbols
|
let mut symbols = symbols
|
||||||
.clone()
|
.clone()
|
||||||
|
@@ -18,13 +18,13 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RuntimeData {
|
struct State {
|
||||||
config: Config,
|
config: Config,
|
||||||
langs: Vec<(&'static str, &'static str)>,
|
langs: Vec<(&'static str, &'static str)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(config_dir: RString) -> RuntimeData {
|
fn init(config_dir: RString) -> State {
|
||||||
RuntimeData {
|
State {
|
||||||
config: match fs::read_to_string(format!("{}/translate.ron", config_dir)) {
|
config: match fs::read_to_string(format!("{}/translate.ron", config_dir)) {
|
||||||
Ok(content) => ron::from_str(&content).unwrap_or_default(),
|
Ok(content) => ron::from_str(&content).unwrap_or_default(),
|
||||||
Err(_) => Config::default(),
|
Err(_) => Config::default(),
|
||||||
@@ -145,7 +145,7 @@ fn info() -> PluginInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matches(input: RString, data: &mut RuntimeData) -> RVec<Match> {
|
fn get_matches(input: RString, data: &State) -> RVec<Match> {
|
||||||
if !input.starts_with(&data.config.prefix) {
|
if !input.starts_with(&data.config.prefix) {
|
||||||
return RVec::new();
|
return RVec::new();
|
||||||
}
|
}
|
||||||
@@ -227,8 +227,8 @@ fn get_matches(input: RString, data: &mut RuntimeData) -> RVec<Match> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handler(selection: Match, _data: &mut RuntimeData) -> HandleResult {
|
fn handler(selection: Match, _data: &mut State) -> HandleResult {
|
||||||
HandleResult::Copy(selection.title.into_bytes())
|
HandleResult::Copy(selection.title.into_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin!(init, info, get_matches, handler, RuntimeData);
|
plugin!(init, info, get_matches, handler, State);
|
||||||
|
Reference in New Issue
Block a user