asklyphe/asklyphe-frontend/src/bangs.rs

114 lines
3.3 KiB
Rust
Raw Normal View History

2025-05-08 15:03:00 +12:00
use tracing::{debug, error};
use once_cell::sync::Lazy;
use std::collections::BTreeMap;
pub static BANG_PREFIX: &str = "!";
pub static BUILTIN_BANGS: Lazy<BTreeMap<&str, (&str, &[&str])>> = 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={}",
}
}
}
2025-05-08 15:46:18 +12:00
#[derive(Debug, Clone)]
struct BangLoc<'a> {
pub url: &'a str,
pub start_idx: usize,
pub end_idx: usize,
}
impl<'a> BangLoc<'_> {
fn init(url: &'a str, start_idx: usize, end_idx: usize) -> BangLoc {
BangLoc {url, start_idx, end_idx}
2025-05-08 15:03:00 +12:00
}
2025-05-08 15:46:18 +12:00
}
pub fn do_bangs_or_whatever(query: &String) -> Option<String> {
// TODO: make this a little more procedural and not as confusing
2025-05-08 15:03:00 +12:00
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() {
2025-05-08 15:46:18 +12:00
true => Some(BangLoc::init(bang_full.1.0, bang_start_idx, bang_end_idx + 1)),
2025-05-08 15:03:00 +12:00
false => None
}
}
None => None,
}
).filter(|i| i.is_some()).map(|bang| bang.unwrap())
.collect::<Vec<_>>().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::<Vec<_>>().first() {
Some(bang) => {
2025-05-08 15:46:18 +12:00
debug!("Initial query: \"{}\"", query);
let query_split = query.split_once(query.get(bang.start_idx..bang.end_idx).unwrap()).unwrap();
debug!("Split query: {:?}", query_split);
let query_trimmed = format!("{}{}", query_split.0, query_split.1);
debug!("Trimmed query: \"{}\"", query_trimmed);
let bang_url_split = bang.url.split_once("{}").unwrap();
debug!("Split bang URL: {:?}", bang_url_split);
let bang_url = format!(
"{}{}{}",
bang_url_split.0,
query_trimmed,
bang_url_split.1
);
debug!("Final URL: \"{}\"", bang_url);
Some(bang_url)
2025-05-08 15:03:00 +12:00
},
None => None
}
}