Files
rust/crates/ra_analysis/src/symbol_index.rs

120 lines
3.4 KiB
Rust
Raw Normal View History

use std::{
hash::{Hash, Hasher},
sync::Arc,
};
use fst::{self, Streamer};
2018-11-28 02:22:25 +03:00
use ra_editor::{self, FileSymbol};
2018-09-16 12:54:24 +03:00
use ra_syntax::{
2018-11-07 18:32:33 +03:00
SourceFileNode,
2018-08-13 15:10:20 +03:00
SyntaxKind::{self, *},
};
use ra_db::{SyntaxDatabase, SourceRootId};
2018-09-03 19:46:30 +03:00
use rayon::prelude::*;
2018-11-28 02:22:25 +03:00
use crate::{
Cancelable,
FileId, Query,
};
salsa::query_group! {
pub(crate) trait SymbolsDatabase: SyntaxDatabase {
fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> {
type FileSymbolsQuery;
}
fn library_symbols(id: SourceRootId) -> Arc<SymbolIndex> {
type LibrarySymbolsQuery;
storage input;
}
}
}
fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> {
db.check_canceled()?;
2018-11-28 02:25:03 +03:00
let syntax = db.source_file(file_id);
2018-11-28 02:22:25 +03:00
Ok(Arc::new(SymbolIndex::for_file(file_id, syntax)))
}
2018-08-13 15:10:20 +03:00
#[derive(Default, Debug)]
2018-09-03 19:46:30 +03:00
pub(crate) struct SymbolIndex {
2018-09-02 23:36:23 +03:00
symbols: Vec<(FileId, FileSymbol)>,
2018-08-13 15:10:20 +03:00
map: fst::Map,
}
2018-10-07 13:18:25 +03:00
impl PartialEq for SymbolIndex {
fn eq(&self, other: &SymbolIndex) -> bool {
self.symbols == other.symbols
}
}
impl Eq for SymbolIndex {}
2018-10-07 13:18:25 +03:00
2018-09-15 23:42:01 +03:00
impl Hash for SymbolIndex {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.symbols.hash(hasher)
}
}
2018-09-03 19:46:30 +03:00
impl SymbolIndex {
2018-11-07 18:32:33 +03:00
pub(crate) fn for_files(
files: impl ParallelIterator<Item = (FileId, SourceFileNode)>,
) -> SymbolIndex {
2018-09-03 19:46:30 +03:00
let mut symbols = files
.flat_map(|(file_id, file)| {
2018-11-28 02:22:25 +03:00
ra_editor::file_symbols(&file)
2018-09-03 19:46:30 +03:00
.into_iter()
.map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol)))
2018-09-03 19:46:30 +03:00
.collect::<Vec<_>>()
})
2018-08-13 15:10:20 +03:00
.collect::<Vec<_>>();
2018-09-03 19:46:30 +03:00
symbols.par_sort_by(|s1, s2| s1.0.cmp(&s2.0));
2018-08-13 15:10:20 +03:00
symbols.dedup_by(|s1, s2| s1.0 == s2.0);
2018-09-02 23:36:23 +03:00
let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) =
2018-09-03 19:46:30 +03:00
symbols.into_iter().unzip();
let map = fst::Map::from_iter(names.into_iter().zip(0u64..)).unwrap();
2018-09-03 19:46:30 +03:00
SymbolIndex { symbols, map }
}
2018-11-07 18:32:33 +03:00
pub(crate) fn for_file(file_id: FileId, file: SourceFileNode) -> SymbolIndex {
2018-10-24 16:13:17 +03:00
SymbolIndex::for_files(rayon::iter::once((file_id, file)))
2018-08-13 15:10:20 +03:00
}
}
impl Query {
2018-10-31 23:41:43 +03:00
pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<(FileId, FileSymbol)> {
2018-09-02 20:08:58 +03:00
let mut op = fst::map::OpBuilder::new();
2018-09-02 23:36:23 +03:00
for file_symbols in indices.iter() {
2018-09-02 20:08:58 +03:00
let automaton = fst::automaton::Subsequence::new(&self.lowercased);
op = op.add(file_symbols.map.search(automaton))
2018-08-13 15:10:20 +03:00
}
2018-09-02 20:08:58 +03:00
let mut stream = op.union();
2018-08-13 16:07:05 +03:00
let mut res = Vec::new();
2018-09-02 20:08:58 +03:00
while let Some((_, indexed_values)) = stream.next() {
2018-10-20 22:02:41 +03:00
if res.len() >= self.limit {
2018-08-13 17:19:27 +03:00
break;
}
2018-09-02 20:08:58 +03:00
for indexed_value in indexed_values {
2018-09-02 23:36:23 +03:00
let file_symbols = &indices[indexed_value.index];
2018-09-02 20:08:58 +03:00
let idx = indexed_value.value as usize;
2018-09-02 23:36:23 +03:00
let (file_id, symbol) = &file_symbols.symbols[idx];
2018-09-02 20:08:58 +03:00
if self.only_types && !is_type(symbol.kind) {
continue;
}
if self.exact && symbol.name != self.query {
continue;
}
res.push((*file_id, symbol.clone()));
2018-08-13 16:07:05 +03:00
}
}
2018-08-13 17:19:27 +03:00
res
2018-08-13 15:10:20 +03:00
}
}
2018-09-02 20:08:58 +03:00
fn is_type(kind: SyntaxKind) -> bool {
match kind {
STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_DEF => true,
_ => false,
}
}