Add max_entries config to plugins (#19)
This commit is contained in:
		 Kangwook Lee (이강욱)
					Kangwook Lee (이강욱)
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							90ecba8261
						
					
				
				
					commit
					0aabb332c9
				
			
							
								
								
									
										3
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -436,6 +436,7 @@ dependencies = [ | ||||
|  "abi_stable", | ||||
|  "anyrun-plugin", | ||||
|  "reqwest", | ||||
|  "ron", | ||||
|  "serde", | ||||
| ] | ||||
|  | ||||
| @@ -1073,6 +1074,8 @@ dependencies = [ | ||||
|  "fuzzy-matcher", | ||||
|  "kidex-common", | ||||
|  "open", | ||||
|  "ron", | ||||
|  "serde", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
|   | ||||
| @@ -5,16 +5,32 @@ use scrubber::DesktopEntry; | ||||
| use serde::Deserialize; | ||||
| use std::{fs, process::Command}; | ||||
|  | ||||
| #[derive(Deserialize, Default)] | ||||
| #[derive(Deserialize)] | ||||
| pub struct Config { | ||||
|     desktop_actions: bool, | ||||
|     max_entries: usize, | ||||
| } | ||||
|  | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             desktop_actions: false, | ||||
|             max_entries: 5, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct State { | ||||
|     config: Config, | ||||
|     entries: Vec<(DesktopEntry, u64)>, | ||||
| } | ||||
|  | ||||
| mod scrubber; | ||||
|  | ||||
| #[handler] | ||||
| pub fn handler(selection: Match, entries: &Vec<(DesktopEntry, u64)>) -> HandleResult { | ||||
|     let entry = entries | ||||
| pub fn handler(selection: Match, state: &State) -> HandleResult { | ||||
|     let entry = state | ||||
|         .entries | ||||
|         .iter() | ||||
|         .find_map(|(entry, id)| { | ||||
|             if *id == selection.id.unwrap() { | ||||
| @@ -33,7 +49,7 @@ pub fn handler(selection: Match, entries: &Vec<(DesktopEntry, u64)>) -> HandleRe | ||||
| } | ||||
|  | ||||
| #[init] | ||||
| pub fn init(config_dir: RString) -> Vec<(DesktopEntry, u64)> { | ||||
| pub fn init(config_dir: RString) -> State { | ||||
|     let config: Config = match fs::read_to_string(format!("{}/applications.ron", config_dir)) { | ||||
|         Ok(content) => ron::from_str(&content).unwrap_or_else(|why| { | ||||
|             eprintln!("Error parsing applications plugin config: {}", why); | ||||
| @@ -45,24 +61,26 @@ pub fn init(config_dir: RString) -> Vec<(DesktopEntry, u64)> { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     scrubber::scrubber(config).unwrap_or_else(|why| { | ||||
|     let entries = scrubber::scrubber(&config).unwrap_or_else(|why| { | ||||
|         eprintln!("Failed to load desktop entries: {}", why); | ||||
|         Vec::new() | ||||
|     }) | ||||
|     }); | ||||
|  | ||||
|     State { config, entries } | ||||
| } | ||||
|  | ||||
| #[get_matches] | ||||
| pub fn get_matches(input: RString, entries: &Vec<(DesktopEntry, u64)>) -> RVec<Match> { | ||||
| pub fn get_matches(input: RString, state: &State) -> RVec<Match> { | ||||
|     let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case(); | ||||
|     let mut entries = entries | ||||
|         .clone() | ||||
|         .into_iter() | ||||
|     let mut entries = state | ||||
|         .entries | ||||
|         .iter() | ||||
|         .filter_map(|(entry, id)| { | ||||
|             let score = matcher.fuzzy_match(&entry.name, &input).unwrap_or(0) | ||||
|                 + matcher.fuzzy_match(&entry.exec, &input).unwrap_or(0); | ||||
|  | ||||
|             if score > 0 { | ||||
|                 Some((entry, id, score)) | ||||
|                 Some((entry, *id, score)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
| @@ -71,14 +89,14 @@ pub fn get_matches(input: RString, entries: &Vec<(DesktopEntry, u64)>) -> RVec<M | ||||
|  | ||||
|     entries.sort_by(|a, b| b.2.cmp(&a.2)); | ||||
|  | ||||
|     entries.truncate(5); | ||||
|     entries.truncate(state.config.max_entries); | ||||
|     entries | ||||
|         .into_iter() | ||||
|         .map(|(entry, id, _)| Match { | ||||
|             title: entry.name.into(), | ||||
|             description: entry.desc.map(|desc| desc.into()).into(), | ||||
|             title: entry.name.clone().into(), | ||||
|             description: entry.desc.clone().map(|desc| desc.into()).into(), | ||||
|             use_pango: false, | ||||
|             icon: ROption::RSome(entry.icon.into()), | ||||
|             icon: ROption::RSome(entry.icon.clone().into()), | ||||
|             id: ROption::RSome(id), | ||||
|         }) | ||||
|         .collect() | ||||
|   | ||||
| @@ -132,7 +132,7 @@ impl DesktopEntry { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn scrubber(config: Config) -> Result<Vec<(DesktopEntry, u64)>, Box<dyn std::error::Error>> { | ||||
| pub fn scrubber(config: &Config) -> Result<Vec<(DesktopEntry, u64)>, Box<dyn std::error::Error>> { | ||||
|     // Create iterator over all the files in the XDG_DATA_DIRS | ||||
|     // XDG compliancy is cool | ||||
|     let mut paths: Vec<Result<fs::DirEntry, io::Error>> = match env::var("XDG_DATA_DIRS") { | ||||
| @@ -186,7 +186,7 @@ pub fn scrubber(config: Config) -> Result<Vec<(DesktopEntry, u64)>, Box<dyn std: | ||||
|                 Ok(entry) => entry, | ||||
|                 Err(_why) => return None, | ||||
|             }; | ||||
|             Some(DesktopEntry::from_dir_entry(entry, &config)) | ||||
|             Some(DesktopEntry::from_dir_entry(entry, config)) | ||||
|         }) | ||||
|         .flatten() | ||||
|         .enumerate() | ||||
|   | ||||
| @@ -13,3 +13,4 @@ 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"] } | ||||
| ron = "0.8.0" | ||||
|   | ||||
| @@ -1,7 +1,24 @@ | ||||
| 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 { | ||||
| @@ -36,7 +53,12 @@ struct Definition { | ||||
| } | ||||
|  | ||||
| #[init] | ||||
| pub fn init(_config_dir: RString) {} | ||||
| 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 { | ||||
| @@ -44,12 +66,12 @@ pub fn handler(_match: Match) -> HandleResult { | ||||
| } | ||||
|  | ||||
| #[get_matches] | ||||
| pub fn get_matches(input: RString) -> RVec<Match> { | ||||
|     if !input.starts_with(":def") { | ||||
| 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 input = &input[4..].trim(); | ||||
|     }; | ||||
|  | ||||
|     let responses: Vec<ApiResponse> = match reqwest::blocking::get(format!( | ||||
|         "https://api.dictionaryapi.dev/api/v2/entries/en/{}", | ||||
| @@ -89,7 +111,7 @@ pub fn get_matches(input: RString) -> RVec<Match> { | ||||
|                 }) | ||||
|                 .collect::<RVec<_>>() | ||||
|         }) | ||||
|         .take(3) | ||||
|         .take(config.max_entries) | ||||
|         .collect() | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -14,3 +14,5 @@ kidex-common = { git = "https://github.com/Kirottu/kidex", features = ["util"] } | ||||
| abi_stable = "0.11.1" | ||||
| fuzzy-matcher = "0.3.7" | ||||
| open = "3.2.0" | ||||
| serde = { version = "1.0.160", features = ["derive"] } | ||||
| ron = "0.8.0" | ||||
|   | ||||
| @@ -2,9 +2,22 @@ use abi_stable::std_types::{ROption, RString, RVec}; | ||||
| use anyrun_plugin::{anyrun_interface::HandleResult, *}; | ||||
| use fuzzy_matcher::FuzzyMatcher; | ||||
| use kidex_common::IndexEntry; | ||||
| use std::{os::unix::prelude::OsStrExt, process::Command}; | ||||
| use serde::Deserialize; | ||||
| use std::{fs, os::unix::prelude::OsStrExt, process::Command}; | ||||
|  | ||||
| #[derive(Deserialize)] | ||||
| struct Config { | ||||
|     max_entries: usize, | ||||
| } | ||||
|  | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self { max_entries: 3 } | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct State { | ||||
|     config: Config, | ||||
|     index: Vec<(usize, IndexEntry)>, | ||||
|     selection: Option<IndexEntry>, | ||||
| } | ||||
| @@ -58,15 +71,21 @@ pub fn handler(selection: Match, state: &mut State) -> HandleResult { | ||||
| } | ||||
|  | ||||
| #[init] | ||||
| pub fn init(_config_dir: RString) -> State { | ||||
| pub fn init(config_dir: RString) -> State { | ||||
|     let config = match fs::read_to_string(format!("{}/kidex.ron", config_dir)) { | ||||
|         Ok(content) => ron::from_str(&content).unwrap_or_default(), | ||||
|         Err(_) => Config::default(), | ||||
|     }; | ||||
|     let index = match kidex_common::util::get_index(None) { | ||||
|         Ok(index) => index.into_iter().enumerate().collect(), | ||||
|         Err(why) => { | ||||
|             println!("Failed to get kidex index: {}", why); | ||||
|             Vec::new() | ||||
|         } | ||||
|     }; | ||||
|     State { | ||||
|         index: match kidex_common::util::get_index(None) { | ||||
|             Ok(index) => index.into_iter().enumerate().collect(), | ||||
|             Err(why) => { | ||||
|                 println!("Failed to get kidex index: {}", why); | ||||
|                 Vec::new() | ||||
|             } | ||||
|         }, | ||||
|         config, | ||||
|         index, | ||||
|         selection: None, | ||||
|     } | ||||
| } | ||||
| @@ -116,7 +135,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec<Match> { | ||||
|  | ||||
|             index.sort_by(|a, b| b.2.cmp(&a.2)); | ||||
|  | ||||
|             index.truncate(3); | ||||
|             index.truncate(state.config.max_entries); | ||||
|             index | ||||
|                 .into_iter() | ||||
|                 .map(|(entry_index, id, _)| Match { | ||||
|   | ||||
| @@ -11,12 +11,14 @@ mod randr; | ||||
| #[derive(Deserialize)] | ||||
| struct Config { | ||||
|     prefix: String, | ||||
|     max_entries: usize, | ||||
| } | ||||
|  | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Config { | ||||
|             prefix: ":dp".to_string(), | ||||
|             max_entries: 5, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -103,11 +105,11 @@ pub fn handler(_match: Match, state: &mut State) -> HandleResult { | ||||
|  | ||||
| #[get_matches] | ||||
| pub fn get_matches(input: RString, state: &State) -> RVec<Match> { | ||||
|     if !input.starts_with(&state.config.prefix) { | ||||
|     let input = if let Some(input) = input.strip_prefix(&state.config.prefix) { | ||||
|         input.trim() | ||||
|     } else { | ||||
|         return RVec::new(); | ||||
|     } | ||||
|  | ||||
|     let input = &input[state.config.prefix.len()..].trim(); | ||||
|     }; | ||||
|  | ||||
|     let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().smart_case(); | ||||
|     let mut vec = match &state.inner { | ||||
| @@ -187,7 +189,7 @@ pub fn get_matches(input: RString, state: &State) -> RVec<Match> { | ||||
|  | ||||
|     vec.sort_by(|a, b| b.1.cmp(&a.1)); | ||||
|  | ||||
|     vec.truncate(5); | ||||
|     vec.truncate(state.config.max_entries); | ||||
|  | ||||
|     vec.into_iter().map(|(_match, _)| _match).collect() | ||||
| } | ||||
|   | ||||
| @@ -16,35 +16,40 @@ struct Symbol { | ||||
| #[derive(Deserialize, Debug)] | ||||
| struct Config { | ||||
|     symbols: HashMap<String, String>, | ||||
|     max_entries: usize, | ||||
| } | ||||
|  | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             symbols: HashMap::new(), | ||||
|             max_entries: 3, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct State { | ||||
|     config: Config, | ||||
|     symbols: Vec<Symbol>, | ||||
| } | ||||
|  | ||||
| #[init] | ||||
| fn init(config_dir: RString) -> Vec<Symbol> { | ||||
| fn init(config_dir: RString) -> State { | ||||
|     // Try to load the config file, if it does not exist only use the static unicode characters | ||||
|     if let Ok(content) = fs::read_to_string(format!("{}/symbols.ron", config_dir)) { | ||||
|         match ron::from_str::<Config>(&content) { | ||||
|             Ok(config) => { | ||||
|                 let symbols = UNICODE_CHARS | ||||
|                     .iter() | ||||
|                     .map(|(name, chr)| (name.to_string(), chr.to_string())) | ||||
|                     .chain(config.symbols.into_iter()) | ||||
|                     .map(|(name, chr)| Symbol { chr, name }) | ||||
|                     .collect(); | ||||
|                 return symbols; | ||||
|             } | ||||
|             Err(why) => { | ||||
|                 println!("Error parsing symbols config file: {}", why); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     let config = if let Ok(content) = fs::read_to_string(format!("{}/symbols.ron", config_dir)) { | ||||
|         ron::from_str(&content).unwrap_or_default() | ||||
|     } else { | ||||
|         Config::default() | ||||
|     }; | ||||
|  | ||||
|     UNICODE_CHARS | ||||
|     let symbols = UNICODE_CHARS | ||||
|         .iter() | ||||
|         .map(|(name, chr)| Symbol { | ||||
|             chr: chr.to_string(), | ||||
|             name: name.to_string(), | ||||
|         }) | ||||
|         .collect() | ||||
|         .map(|(name, chr)| (name.to_string(), chr.to_string())) | ||||
|         .chain(config.symbols.clone().into_iter()) | ||||
|         .map(|(name, chr)| Symbol { chr, name }) | ||||
|         .collect(); | ||||
|  | ||||
|     State { config, symbols } | ||||
| } | ||||
|  | ||||
| #[info] | ||||
| @@ -56,11 +61,11 @@ fn info() -> PluginInfo { | ||||
| } | ||||
|  | ||||
| #[get_matches] | ||||
| fn get_matches(input: RString, symbols: &Vec<Symbol>) -> RVec<Match> { | ||||
| fn get_matches(input: RString, state: &State) -> RVec<Match> { | ||||
|     let matcher = fuzzy_matcher::skim::SkimMatcherV2::default().ignore_case(); | ||||
|     let mut symbols = symbols | ||||
|         .clone() | ||||
|         .into_iter() | ||||
|     let mut symbols = state | ||||
|         .symbols | ||||
|         .iter() | ||||
|         .filter_map(|symbol| { | ||||
|             matcher | ||||
|                 .fuzzy_match(&symbol.name, &input) | ||||
| @@ -71,13 +76,13 @@ fn get_matches(input: RString, symbols: &Vec<Symbol>) -> RVec<Match> { | ||||
|     // Sort the symbol list according to the score | ||||
|     symbols.sort_by(|a, b| b.1.cmp(&a.1)); | ||||
|  | ||||
|     symbols.truncate(3); | ||||
|     symbols.truncate(state.config.max_entries); | ||||
|  | ||||
|     symbols | ||||
|         .into_iter() | ||||
|         .map(|(symbol, _)| Match { | ||||
|             title: symbol.chr.into(), | ||||
|             description: ROption::RSome(symbol.name.into()), | ||||
|             title: symbol.chr.clone().into(), | ||||
|             description: ROption::RSome(symbol.name.clone().into()), | ||||
|             use_pango: false, | ||||
|             icon: ROption::RNone, | ||||
|             id: ROption::RNone, | ||||
|   | ||||
| @@ -8,12 +8,14 @@ use serde::Deserialize; | ||||
| #[derive(Deserialize)] | ||||
| struct Config { | ||||
|     prefix: String, | ||||
|     max_entries: usize, | ||||
| } | ||||
|  | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             prefix: ":".to_string(), | ||||
|             max_entries: 3, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -182,7 +184,7 @@ fn get_matches(input: RString, data: &State) -> RVec<Match> { | ||||
|     matches.sort_by(|a, b| b.2.cmp(&a.2)); | ||||
|  | ||||
|     // We only want 3 matches | ||||
|     matches.truncate(3); | ||||
|     matches.truncate(data.config.max_entries); | ||||
|  | ||||
|     tokio::runtime::Runtime::new().expect("Failed to spawn tokio runtime!").block_on(async move { | ||||
|         // Create the futures for fetching the translation results | ||||
|   | ||||
		Reference in New Issue
	
	Block a user