Files
anyrun/plugins/dictionary/src/lib.rs
2023-05-01 15:16:11 +03:00

125 lines
3.0 KiB
Rust

use std::fs;
use abi_stable::std_types::{ROption, RString, RVec};
use anyrun_plugin::*;
use serde::Deserialize;
#[derive(Deserialize)]
pub struct Config {
prefix: String,
max_entries: usize,
}
impl Default for Config {
fn default() -> Self {
Self {
prefix: ":def".to_string(),
max_entries: 3,
}
}
}
#[allow(unused)]
#[derive(Deserialize)]
struct ApiResponse {
word: String,
phonetic: Option<String>,
phonetics: Vec<Phonetic>,
origin: Option<String>,
meanings: Vec<Meaning>,
}
#[allow(unused)]
#[derive(Deserialize)]
struct Phonetic {
text: String,
audio: Option<String>,
}
#[derive(Deserialize)]
struct Meaning {
#[serde(rename = "partOfSpeech")]
part_of_speech: String,
definitions: Vec<Definition>,
}
#[allow(unused)]
#[derive(Deserialize)]
struct Definition {
definition: String,
example: Option<String>,
synonyms: Vec<String>,
antonyms: Vec<String>,
}
#[init]
pub fn init(config_dir: RString) -> Config {
match fs::read_to_string(format!("{}/dictionary.ron", config_dir)) {
Ok(content) => ron::from_str(&content).unwrap_or_default(),
Err(_) => Config::default(),
}
}
#[handler]
pub fn handler(_match: Match) -> HandleResult {
HandleResult::Copy(_match.title.into_bytes())
}
#[get_matches]
pub fn get_matches(input: RString, config: &Config) -> RVec<Match> {
let input = if let Some(input) = input.strip_prefix(&config.prefix) {
input.trim()
} else {
return RVec::new();
};
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(config.max_entries)
.collect()
}
#[info]
fn info() -> PluginInfo {
PluginInfo {
name: "Dictionary".into(),
icon: "accessories-dictionary".into(),
}
}