mirror of
https://github.com/SpaceManiac/SpacemanDMM.git
synced 2025-12-23 05:36:47 +00:00
108 lines
3.2 KiB
Rust
108 lines
3.2 KiB
Rust
//! Query parser and evaluator for workspace symbol search.
|
|
|
|
/// A parsed symbol query.
|
|
#[derive(Debug)]
|
|
pub enum Query {
|
|
Anything(String),
|
|
Define(String),
|
|
Type(String),
|
|
Var(String),
|
|
Proc(String),
|
|
}
|
|
|
|
impl Query {
|
|
/// Parse a symbol query.
|
|
pub fn parse(query: &str) -> Option<Query> {
|
|
if !any_alphanumeric(query) {
|
|
return None;
|
|
}
|
|
Some(if query.starts_with("#") {
|
|
Query::Define(query[1..].to_lowercase())
|
|
} else if query.starts_with("var/") {
|
|
let query = &query["var/".len()..];
|
|
if !any_alphanumeric(query) {
|
|
return None;
|
|
}
|
|
Query::Var(query.to_lowercase())
|
|
} else if query.starts_with("proc/") {
|
|
let query = &query["proc/".len()..];
|
|
if !any_alphanumeric(query) {
|
|
return None;
|
|
}
|
|
Query::Proc(query.to_lowercase())
|
|
} else if query.contains("/") {
|
|
Query::Type(query.to_lowercase())
|
|
} else {
|
|
Query::Anything(query.to_lowercase())
|
|
})
|
|
}
|
|
|
|
/// Check whether this query matches the define with the given name.
|
|
pub fn matches_define(&self, name: &str) -> bool {
|
|
match *self {
|
|
Query::Anything(ref q) => starts_with(name, q),
|
|
Query::Define(ref q) => starts_with(name, q),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn matches_type(&self, name: &str, path: &str) -> bool {
|
|
match *self {
|
|
Query::Anything(ref q) => starts_with(name, q),
|
|
Query::Type(ref q) => path.to_lowercase().contains(q),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn matches_on_type(&self, _path: &str) -> bool {
|
|
match *self {
|
|
Query::Anything(_) |
|
|
Query::Proc(_) |
|
|
Query::Var(_) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn matches_var(&self, name: &str) -> bool {
|
|
match *self {
|
|
Query::Anything(ref q) |
|
|
Query::Var(ref q) => starts_with(name, q),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
pub fn matches_proc(&self, name: &str, _kind: ::dm::ast::ProcDeclKind) -> bool {
|
|
match *self {
|
|
Query::Anything(ref q) |
|
|
Query::Proc(ref q) => starts_with(name, q),
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
fn simplify<'a>(s: &'a str) -> impl Iterator<Item=char> + Clone + 'a {
|
|
s.chars().flat_map(|c| c.to_lowercase()).filter(|c| c.is_alphanumeric())
|
|
}
|
|
|
|
// ignore case and underscores
|
|
pub fn starts_with<'a>(fulltext: &'a str, query: &'a str) -> bool {
|
|
let mut query_chars = simplify(query);
|
|
simplify(fulltext).zip(&mut query_chars).all(|(a, b)| a == b) && query_chars.next().is_none()
|
|
}
|
|
|
|
pub fn contains<'a>(fulltext: &'a str, query: &'a str) -> bool {
|
|
let (mut fulltext, query) = (simplify(fulltext), simplify(query));
|
|
loop {
|
|
let mut clone = query.clone();
|
|
if fulltext.clone().zip(&mut clone).all(|(a, b)| a == b) && clone.next().is_none() {
|
|
return true;
|
|
}
|
|
if fulltext.next().is_none() {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn any_alphanumeric(text: &str) -> bool {
|
|
text.chars().flat_map(|c| c.to_lowercase()).any(|c| c.is_alphanumeric())
|
|
}
|