Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-db/src/symbol_index.rs')
-rw-r--r--crates/ide-db/src/symbol_index.rs121
1 files changed, 68 insertions, 53 deletions
diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs
index f5f0f0576f..c2e95ca860 100644
--- a/crates/ide-db/src/symbol_index.rs
+++ b/crates/ide-db/src/symbol_index.rs
@@ -31,9 +31,10 @@ use base_db::{
salsa::{self, ParallelDatabase},
SourceDatabaseExt, SourceRootId, Upcast,
};
-use fst::{self, Streamer};
+use fst::{self, raw::IndexedValue, Automaton, Streamer};
use hir::{
db::HirDatabase,
+ import_map::{AssocSearchMode, SearchMode},
symbols::{FileSymbol, SymbolCollector},
Crate, Module,
};
@@ -43,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,
- limit: usize,
+ only_types: bool,
+ libs: bool,
}
impl Query {
@@ -70,8 +64,8 @@ impl Query {
only_types: false,
libs: false,
mode: SearchMode::Fuzzy,
+ assoc_mode: AssocSearchMode::Include,
case_sensitive: false,
- limit: usize::max_value(),
}
}
@@ -95,12 +89,13 @@ impl Query {
self.mode = SearchMode::Prefix;
}
- pub fn case_sensitive(&mut self) {
- self.case_sensitive = true;
+ /// Specifies whether we want to include associated items in the result.
+ pub fn assoc_search_mode(&mut self, assoc_mode: AssocSearchMode) {
+ self.assoc_mode = assoc_mode;
}
- pub fn limit(&mut self, limit: usize) {
- self.limit = limit
+ pub fn case_sensitive(&mut self) {
+ self.case_sensitive = true;
}
}
@@ -225,7 +220,9 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
indices.iter().flat_map(|indices| indices.iter().cloned()).collect()
};
- query.search(&indices)
+ let mut res = vec![];
+ query.search(&indices, |f| res.push(f.clone()));
+ res
}
#[derive(Default)]
@@ -285,6 +282,7 @@ impl SymbolIndex {
builder.insert(key, value).unwrap();
}
+ // FIXME: fst::Map should ideally have a way to shrink the backing buffer without the unwrap dance
let map = fst::Map::new({
let mut buf = builder.into_inner().unwrap();
buf.shrink_to_fit();
@@ -317,22 +315,54 @@ impl SymbolIndex {
}
impl Query {
- pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<FileSymbol> {
+ pub(crate) fn search<'sym>(
+ self,
+ indices: &'sym [Arc<SymbolIndex>],
+ cb: impl FnMut(&'sym FileSymbol),
+ ) {
let _p = profile::span("symbol_index::Query::search");
let mut op = fst::map::OpBuilder::new();
- for file_symbols in indices.iter() {
- let automaton = fst::automaton::Subsequence::new(&self.lowercased);
- op = op.add(file_symbols.map.search(automaton))
+ match self.mode {
+ SearchMode::Exact => {
+ let automaton = fst::automaton::Str::new(&self.lowercased);
+
+ for index in indices.iter() {
+ op = op.add(index.map.search(&automaton));
+ }
+ self.search_maps(&indices, op.union(), cb)
+ }
+ SearchMode::Fuzzy => {
+ let automaton = fst::automaton::Subsequence::new(&self.lowercased);
+
+ for index in indices.iter() {
+ op = op.add(index.map.search(&automaton));
+ }
+ self.search_maps(&indices, op.union(), cb)
+ }
+ SearchMode::Prefix => {
+ let automaton = fst::automaton::Str::new(&self.lowercased).starts_with();
+
+ for index in indices.iter() {
+ op = op.add(index.map.search(&automaton));
+ }
+ self.search_maps(&indices, op.union(), cb)
+ }
}
- let mut stream = op.union();
- let mut res = Vec::new();
+ }
+
+ fn search_maps<'sym>(
+ &self,
+ indices: &'sym [Arc<SymbolIndex>],
+ mut stream: fst::map::Union<'_>,
+ mut cb: impl FnMut(&'sym FileSymbol),
+ ) {
while let Some((_, indexed_values)) = stream.next() {
- for indexed_value in indexed_values {
- let symbol_index = &indices[indexed_value.index];
- let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value);
+ for &IndexedValue { index, value } in indexed_values {
+ let symbol_index = &indices[index];
+ let (start, end) = SymbolIndex::map_value_to_range(value);
for symbol in &symbol_index.symbols[start..end] {
- if self.only_types
+ let non_type_for_type_only_query = self.only_types
&& !matches!(
symbol.def,
hir::ModuleDef::Adt(..)
@@ -340,38 +370,23 @@ impl Query {
| hir::ModuleDef::BuiltinType(..)
| hir::ModuleDef::TraitAlias(..)
| hir::ModuleDef::Trait(..)
- )
- {
+ );
+ if non_type_for_type_only_query || !self.matches_assoc_mode(symbol.is_assoc) {
continue;
}
- let skip = match self.mode {
- SearchMode::Fuzzy => {
- self.case_sensitive
- && self.query.chars().any(|c| !symbol.name.contains(c))
- }
- SearchMode::Exact => symbol.name != self.query,
- SearchMode::Prefix if self.case_sensitive => {
- !symbol.name.starts_with(&self.query)
- }
- SearchMode::Prefix => symbol
- .name
- .chars()
- .zip(self.lowercased.chars())
- .all(|(n, q)| n.to_lowercase().next() == Some(q)),
- };
-
- if skip {
- continue;
- }
-
- res.push(symbol.clone());
- if res.len() >= self.limit {
- return res;
+ if self.mode.check(&self.query, self.case_sensitive, &symbol.name) {
+ cb(symbol);
}
}
}
}
- res
+ }
+
+ fn matches_assoc_mode(&self, is_trait_assoc_item: bool) -> bool {
+ match (is_trait_assoc_item, self.assoc_mode) {
+ (true, AssocSearchMode::Exclude) | (false, AssocSearchMode::AssocItemsOnly) => false,
+ _ => true,
+ }
}
}