use tracing::{debug, error}; use once_cell::sync::Lazy; use std::collections::BTreeMap; pub static BANG_PREFIX: &str = "!"; pub static BUILTIN_BANGS: Lazy> = Lazy::new(|| { let mut bangs = BTreeMap::new(); bangs.insert("Google", ("https://google.com/search?q={}", &["g", "google"] as &[&str])); bangs.insert("DuckDuckGo", ("https://duckduckgo.com/?q={}", &["d", "ddg", "duckduckgo"] as &[&str])); bangs.insert("Wikipedia", ("https://wikipedia.org/w/index.php?search={}", &["w", "wiki", "wikipedia"] as &[&str])); bangs }); enum Bangs { Google, DuckDuckGo, Wikipedia, } impl Bangs { pub fn get_suffix(self) -> &'static [&'static str] { match self { Bangs::Google => &["g", "google"], Bangs::DuckDuckGo => &["d", "ddg", "duckduckgo"], Bangs::Wikipedia => &["w", "wiki", "wikipedia"], } } pub fn get_url_format(self) -> &'static str { match self { Bangs::Google => "https://google.com/search?q={}", Bangs::DuckDuckGo => "https://duckduckgo.com/?q={}", Bangs::Wikipedia => "https://wikipedia.org/w/index.php?search={}", } } } pub fn do_bangs_or_whatever(query: &String) -> Option { #[derive(Debug, Clone)] struct Bang<'a> { pub name: &'a str, pub start_idx: usize, pub end_idx: usize, } impl<'a> Bang<'_> { fn init(name: &'a str, start_idx: usize, end_idx: usize) -> Bang { Bang {name, start_idx, end_idx} } } error!("Hello, World!, you searched \"{}\"", query); return match query.match_indices(BANG_PREFIX).map(|idx| { let bang_start_idx = idx.0; match bang_start_idx == 0 || query.chars().nth(bang_start_idx - 1).unwrap().is_ascii_whitespace() { true => match query.get(bang_start_idx + 1 .. query.len()) { Some(rest) => { debug!("rest is {}", rest); match BUILTIN_BANGS.iter().map( |bang_full| match bang_full.1.1.iter() .filter(|short| rest.starts_with(**short)) .max_by(|a, b| a.len().cmp(&b.len())) { Some(bang_text) => { let bang_end_idx = bang_start_idx + 1 + bang_text.len(); match query.chars().nth(bang_end_idx).unwrap_or(' ').is_ascii_whitespace() { true => Some(Bang::init(bang_full.1.0, bang_start_idx, bang_end_idx)), false => None } } None => None, } ).filter(|i| i.is_some()).map(|bang| bang.unwrap()) .collect::>().last() { Some(bang) => { debug!("got:'{:?}'", bang); Some(bang.clone()) }, None => None } }, None => None } false => None } }).filter(|bang| bang.is_some()).map(|bang| bang.unwrap()).collect::>().first() { Some(bang) => { let query_trimmed = format!( "{}{}", query.get(0..bang.start_idx).unwrap(), if bang.end_idx == query.len() { "" } else { query.get(bang.end_idx..query.len()).unwrap() }); debug!("Old query: \"{}\"", query); debug!("New query: \"{}\"", query_trimmed); None }, None => None } }