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:
Kirottu
2023-04-29 18:18:47 +03:00
parent 3a1648cf37
commit beaf2549ac
13 changed files with 162 additions and 31 deletions

View File

@@ -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 mut entries = entries
.clone()

View 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"] }

View 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, ());

View File

@@ -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 {
Some(index_entry) => {
let path = index_entry.path.to_string_lossy();

View File

@@ -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) {
return RVec::new();
}

View File

@@ -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> {
match rink_core::one_line(ctx, &input) {
fn get_matches(input: RString, _: &()) -> RVec<Match> {
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<Match> {
}
}
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, ());

View File

@@ -33,10 +33,9 @@ fn info() -> PluginInfo {
}
}
fn get_matches(input: RString, config: &mut Config) -> RVec<Match> {
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<Match> {
if input.starts_with(&config.prefix) {
let (_, command) = input.split_once(&config.prefix).unwrap();
if !command.is_empty() {
vec![Match {
title: command.into(),

View File

@@ -12,7 +12,7 @@ fn handler(_match: Match, _lines: &mut Vec<String>) -> HandleResult {
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 mut lines = lines

View File

@@ -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 mut symbols = symbols
.clone()

View File

@@ -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<Match> {
fn get_matches(input: RString, data: &State) -> RVec<Match> {
if !input.starts_with(&data.config.prefix) {
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())
}
plugin!(init, info, get_matches, handler, RuntimeData);
plugin!(init, info, get_matches, handler, State);