Deduplicate some code
This commit is contained in:
parent
2666349392
commit
d60638e5e6
@ -83,29 +83,42 @@ impl ImportMap {
|
||||
.iter()
|
||||
// We've only collected items, whose name cannot be tuple field so unwrapping is fine.
|
||||
.flat_map(|(&item, (info, _))| {
|
||||
info.iter().enumerate().map(move |(idx, info)| {
|
||||
(item, info.name.as_str().unwrap().to_ascii_lowercase(), idx as u32)
|
||||
})
|
||||
info.iter()
|
||||
.enumerate()
|
||||
.map(move |(idx, info)| (item, info.name.to_smol_str(), idx as u32))
|
||||
})
|
||||
.collect();
|
||||
importables.sort_by(|(_, lhs_name, _), (_, rhs_name, _)| lhs_name.cmp(rhs_name));
|
||||
importables.sort_by(|(_, l_info, _), (_, r_info, _)| {
|
||||
let lhs_chars = l_info.chars().map(|c| c.to_ascii_lowercase());
|
||||
let rhs_chars = r_info.chars().map(|c| c.to_ascii_lowercase());
|
||||
lhs_chars.cmp(rhs_chars)
|
||||
});
|
||||
importables.dedup();
|
||||
|
||||
// Build the FST, taking care not to insert duplicate values.
|
||||
let mut builder = fst::MapBuilder::memory();
|
||||
let iter = importables
|
||||
let mut iter = importables
|
||||
.iter()
|
||||
.enumerate()
|
||||
.dedup_by(|(_, (_, lhs, _)), (_, (_, rhs, _))| lhs == rhs);
|
||||
for (start_idx, (_, name, _)) in iter {
|
||||
let _ = builder.insert(name, start_idx as u64);
|
||||
.dedup_by(|&(_, (_, lhs, _)), &(_, (_, rhs, _))| lhs.eq_ignore_ascii_case(rhs));
|
||||
|
||||
let mut insert = |name: &str, start, end| {
|
||||
builder.insert(name.to_ascii_lowercase(), ((start as u64) << 32) | end as u64).unwrap()
|
||||
};
|
||||
|
||||
if let Some((mut last, (_, name, _))) = iter.next() {
|
||||
debug_assert_eq!(last, 0);
|
||||
let mut last_name = name;
|
||||
for (next, (_, next_name, _)) in iter {
|
||||
insert(last_name, last, next);
|
||||
last = next;
|
||||
last_name = next_name;
|
||||
}
|
||||
insert(last_name, last, importables.len());
|
||||
}
|
||||
|
||||
Arc::new(ImportMap {
|
||||
item_to_info_map: map,
|
||||
fst: builder.into_map(),
|
||||
importables: importables.into_iter().map(|(item, _, idx)| (item, idx)).collect(),
|
||||
})
|
||||
let importables = importables.into_iter().map(|(item, _, idx)| (item, idx)).collect();
|
||||
Arc::new(ImportMap { item_to_info_map: map, fst: builder.into_map(), importables })
|
||||
}
|
||||
|
||||
pub fn import_info_for(&self, item: ItemInNs) -> Option<&[ImportInfo]> {
|
||||
@ -266,8 +279,8 @@ impl fmt::Debug for ImportMap {
|
||||
}
|
||||
|
||||
/// A way to match import map contents against the search query.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum SearchMode {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum SearchMode {
|
||||
/// Import map entry should strictly match the query string.
|
||||
Exact,
|
||||
/// Import map entry should contain all letters from the query string,
|
||||
@ -277,6 +290,42 @@ enum SearchMode {
|
||||
Prefix,
|
||||
}
|
||||
|
||||
impl SearchMode {
|
||||
pub fn check(self, query: &str, case_sensitive: bool, candidate: &str) -> bool {
|
||||
match self {
|
||||
SearchMode::Exact if case_sensitive => candidate == query,
|
||||
SearchMode::Exact => candidate.eq_ignore_ascii_case(&query),
|
||||
SearchMode::Prefix => {
|
||||
query.len() <= candidate.len() && {
|
||||
let prefix = &candidate[..query.len() as usize];
|
||||
if case_sensitive {
|
||||
prefix == query
|
||||
} else {
|
||||
prefix.eq_ignore_ascii_case(&query)
|
||||
}
|
||||
}
|
||||
}
|
||||
SearchMode::Fuzzy => {
|
||||
let mut name = candidate;
|
||||
query.chars().all(|query_char| {
|
||||
let m = if case_sensitive {
|
||||
name.match_indices(query_char).next()
|
||||
} else {
|
||||
name.match_indices([query_char, query_char.to_ascii_uppercase()]).next()
|
||||
};
|
||||
match m {
|
||||
Some((index, _)) => {
|
||||
name = &name[index + 1..];
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Three possible ways to search for the name in associated and/or other items.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AssocSearchMode {
|
||||
@ -392,67 +441,28 @@ fn search_maps(
|
||||
query: &Query,
|
||||
) -> FxHashSet<ItemInNs> {
|
||||
let mut res = FxHashSet::default();
|
||||
while let Some((key, indexed_values)) = stream.next() {
|
||||
while let Some((_, indexed_values)) = stream.next() {
|
||||
for &IndexedValue { index: import_map_idx, value } in indexed_values {
|
||||
let import_map = &import_maps[import_map_idx];
|
||||
let importables = &import_map.importables[value as usize..];
|
||||
let end = (value & 0xFFFF_FFFF) as usize;
|
||||
let start = (value >> 32) as usize;
|
||||
let ImportMap { item_to_info_map, importables, .. } = &*import_maps[import_map_idx];
|
||||
let importables = &importables[start as usize..end];
|
||||
|
||||
let iter = importables
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|(item, info_idx)| {
|
||||
let (import_infos, assoc_mode) = &import_map.item_to_info_map[&item];
|
||||
(item, &import_infos[info_idx as usize], *assoc_mode)
|
||||
.filter_map(|(item, info_idx)| {
|
||||
let (import_infos, assoc_mode) = &item_to_info_map[&item];
|
||||
query
|
||||
.matches_assoc_mode(*assoc_mode)
|
||||
.then(|| (item, &import_infos[info_idx as usize]))
|
||||
})
|
||||
// we put all entries with the same lowercased name in a row, so stop once we find a
|
||||
// different name in the importables
|
||||
// FIXME: Consider putting a range into the value: u64 as (u32, u32)?
|
||||
.take_while(|&(_, info, _)| {
|
||||
info.name.to_smol_str().as_bytes().eq_ignore_ascii_case(&key)
|
||||
})
|
||||
.filter(|&(_, info, assoc_mode)| {
|
||||
if !query.matches_assoc_mode(assoc_mode) {
|
||||
return false;
|
||||
}
|
||||
if !query.case_sensitive {
|
||||
return true;
|
||||
}
|
||||
let name = info.name.to_smol_str();
|
||||
// FIXME: Deduplicate this from ide-db
|
||||
match query.search_mode {
|
||||
SearchMode::Exact => !query.case_sensitive || name == query.query,
|
||||
SearchMode::Prefix => {
|
||||
query.query.len() <= name.len() && {
|
||||
let prefix = &name[..query.query.len() as usize];
|
||||
if query.case_sensitive {
|
||||
prefix == query.query
|
||||
} else {
|
||||
prefix.eq_ignore_ascii_case(&query.query)
|
||||
}
|
||||
}
|
||||
}
|
||||
SearchMode::Fuzzy => {
|
||||
let mut name = &*name;
|
||||
query.query.chars().all(|query_char| {
|
||||
let m = if query.case_sensitive {
|
||||
name.match_indices(query_char).next()
|
||||
} else {
|
||||
name.match_indices([
|
||||
query_char,
|
||||
query_char.to_ascii_uppercase(),
|
||||
])
|
||||
.next()
|
||||
};
|
||||
match m {
|
||||
Some((index, _)) => {
|
||||
name = &name[index + 1..];
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
.filter(|&(_, info)| {
|
||||
query.search_mode.check(
|
||||
&query.query,
|
||||
query.case_sensitive,
|
||||
&info.name.to_smol_str(),
|
||||
)
|
||||
});
|
||||
res.extend(iter.map(TupleExt::head));
|
||||
}
|
||||
|
@ -18,11 +18,11 @@ use crate::{Module, ModuleDef, Semantics};
|
||||
/// possible.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FileSymbol {
|
||||
// even though name can be derived from the def, we store it for efficiency
|
||||
pub name: SmolStr,
|
||||
pub def: ModuleDef,
|
||||
pub loc: DeclarationLocation,
|
||||
pub container_name: Option<SmolStr>,
|
||||
/// Whether this symbol is a doc alias for the original symbol.
|
||||
pub is_alias: bool,
|
||||
pub is_assoc: bool,
|
||||
}
|
||||
@ -166,8 +166,6 @@ impl<'a> SymbolCollector<'a> {
|
||||
// FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily
|
||||
// for now.
|
||||
for id in scope.imports() {
|
||||
let loc = id.import.lookup(self.db.upcast());
|
||||
loc.id.item_tree(self.db.upcast());
|
||||
let source = id.import.child_source(self.db.upcast());
|
||||
let Some(use_tree_src) = source.value.get(id.idx) else { continue };
|
||||
let Some(rename) = use_tree_src.rename() else { continue };
|
||||
|
@ -34,7 +34,7 @@ use base_db::{
|
||||
use fst::{self, raw::IndexedValue, Automaton, Streamer};
|
||||
use hir::{
|
||||
db::HirDatabase,
|
||||
import_map::AssocSearchMode,
|
||||
import_map::{AssocSearchMode, SearchMode},
|
||||
symbols::{FileSymbol, SymbolCollector},
|
||||
Crate, Module,
|
||||
};
|
||||
@ -44,22 +44,15 @@ use triomphe::Arc;
|
||||
|
||||
use crate::RootDatabase;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum SearchMode {
|
||||
Fuzzy,
|
||||
Exact,
|
||||
Prefix,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Query {
|
||||
query: String,
|
||||
lowercased: String,
|
||||
only_types: bool,
|
||||
libs: bool,
|
||||
mode: SearchMode,
|
||||
assoc_mode: AssocSearchMode,
|
||||
case_sensitive: bool,
|
||||
only_types: bool,
|
||||
libs: bool,
|
||||
}
|
||||
|
||||
impl Query {
|
||||
@ -381,43 +374,7 @@ impl Query {
|
||||
if non_type_for_type_only_query || !self.matches_assoc_mode(symbol.is_assoc) {
|
||||
continue;
|
||||
}
|
||||
// FIXME: Deduplicate this from hir-def
|
||||
let matches = match self.mode {
|
||||
SearchMode::Exact if self.case_sensitive => symbol.name == self.query,
|
||||
SearchMode::Exact => symbol.name.eq_ignore_ascii_case(&self.query),
|
||||
SearchMode::Prefix => {
|
||||
self.query.len() <= symbol.name.len() && {
|
||||
let prefix = &symbol.name[..self.query.len() as usize];
|
||||
if self.case_sensitive {
|
||||
prefix == self.query
|
||||
} else {
|
||||
prefix.eq_ignore_ascii_case(&self.query)
|
||||
}
|
||||
}
|
||||
}
|
||||
SearchMode::Fuzzy => {
|
||||
let mut name = &*symbol.name;
|
||||
self.query.chars().all(|query_char| {
|
||||
let m = if self.case_sensitive {
|
||||
name.match_indices(query_char).next()
|
||||
} else {
|
||||
name.match_indices([
|
||||
query_char,
|
||||
query_char.to_ascii_uppercase(),
|
||||
])
|
||||
.next()
|
||||
};
|
||||
match m {
|
||||
Some((index, _)) => {
|
||||
name = &name[index + 1..];
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
if matches {
|
||||
if self.mode.check(&self.query, self.case_sensitive, &symbol.name) {
|
||||
cb(symbol);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user