mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge #1200
1200: Allows searching for case-equivalent symbols (fixes #1151) r=matklad a=jrvidal I couldn't find a nice, functional way of calculating the ranges in one pass so I resorted to a plain old `for` loop. Co-authored-by: Roberto Vidal <vidal.roberto.j@gmail.com>
This commit is contained in:
commit
6009af9b7c
1 changed files with 69 additions and 17 deletions
|
@ -20,7 +20,6 @@
|
||||||
//! file in the current workspace, and run a query against the union of all
|
//! file in the current workspace, and run a query against the union of all
|
||||||
//! those FSTs.
|
//! those FSTs.
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
mem,
|
mem,
|
||||||
|
@ -137,13 +136,32 @@ impl Hash for SymbolIndex {
|
||||||
|
|
||||||
impl SymbolIndex {
|
impl SymbolIndex {
|
||||||
fn new(mut symbols: Vec<FileSymbol>) -> SymbolIndex {
|
fn new(mut symbols: Vec<FileSymbol>) -> SymbolIndex {
|
||||||
fn cmp(s1: &FileSymbol, s2: &FileSymbol) -> Ordering {
|
fn cmp_key<'a>(s1: &'a FileSymbol) -> impl Ord + 'a {
|
||||||
unicase::Ascii::new(s1.name.as_str()).cmp(&unicase::Ascii::new(s2.name.as_str()))
|
unicase::Ascii::new(s1.name.as_str())
|
||||||
}
|
}
|
||||||
symbols.par_sort_by(cmp);
|
|
||||||
symbols.dedup_by(|s1, s2| cmp(s1, s2) == Ordering::Equal);
|
symbols.par_sort_by(|s1, s2| cmp_key(s1).cmp(&cmp_key(s2)));
|
||||||
let names = symbols.iter().map(|it| it.name.as_str().to_lowercase());
|
|
||||||
let map = fst::Map::from_iter(names.zip(0u64..)).unwrap();
|
let mut builder = fst::MapBuilder::memory();
|
||||||
|
|
||||||
|
let mut last_batch_start = 0;
|
||||||
|
|
||||||
|
for idx in 0..symbols.len() {
|
||||||
|
if symbols.get(last_batch_start).map(cmp_key) == symbols.get(idx + 1).map(cmp_key) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let start = last_batch_start;
|
||||||
|
let end = idx + 1;
|
||||||
|
last_batch_start = end;
|
||||||
|
|
||||||
|
let key = symbols[start].name.as_str().to_lowercase();
|
||||||
|
let value = SymbolIndex::range_to_map_value(start, end);
|
||||||
|
|
||||||
|
builder.insert(key, value).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let map = fst::Map::from_bytes(builder.into_inner().unwrap()).unwrap();
|
||||||
SymbolIndex { symbols, map }
|
SymbolIndex { symbols, map }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +181,19 @@ impl SymbolIndex {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
SymbolIndex::new(symbols)
|
SymbolIndex::new(symbols)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn range_to_map_value(start: usize, end: usize) -> u64 {
|
||||||
|
debug_assert![start <= (std::u32::MAX as usize)];
|
||||||
|
debug_assert![end <= (std::u32::MAX as usize)];
|
||||||
|
|
||||||
|
((start as u64) << 32) | end as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_value_to_range(value: u64) -> (usize, usize) {
|
||||||
|
let end = value as u32 as usize;
|
||||||
|
let start = (value >> 32) as usize;
|
||||||
|
(start, end)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Query {
|
impl Query {
|
||||||
|
@ -179,10 +210,10 @@ impl Query {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for indexed_value in indexed_values {
|
for indexed_value in indexed_values {
|
||||||
let file_symbols = &indices[indexed_value.index];
|
let symbol_index = &indices[indexed_value.index];
|
||||||
let idx = indexed_value.value as usize;
|
let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value);
|
||||||
|
|
||||||
let symbol = &file_symbols.symbols[idx];
|
for symbol in &symbol_index.symbols[start..end] {
|
||||||
if self.only_types && !is_type(symbol.ptr.kind()) {
|
if self.only_types && !is_type(symbol.ptr.kind()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -192,6 +223,7 @@ impl Query {
|
||||||
res.push(symbol.clone());
|
res.push(symbol.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,7 +305,10 @@ fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ra_syntax::SmolStr;
|
use ra_syntax::{
|
||||||
|
SmolStr,
|
||||||
|
SyntaxKind::{FN_DEF, STRUCT_DEF}
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
display::NavigationTarget,
|
display::NavigationTarget,
|
||||||
mock_analysis::single_file,
|
mock_analysis::single_file,
|
||||||
|
@ -323,6 +358,23 @@ mod foo {
|
||||||
assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
|
assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_world_symbols_are_case_sensitive() {
|
||||||
|
let code = r#"
|
||||||
|
fn foo() {}
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let symbols = get_symbols_matching(code, "Foo");
|
||||||
|
|
||||||
|
let fn_match = symbols.iter().find(|s| s.name() == "foo").map(|s| s.kind());
|
||||||
|
let struct_match = symbols.iter().find(|s| s.name() == "Foo").map(|s| s.kind());
|
||||||
|
|
||||||
|
assert_eq!(fn_match, Some(FN_DEF));
|
||||||
|
assert_eq!(struct_match, Some(STRUCT_DEF));
|
||||||
|
}
|
||||||
|
|
||||||
fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
|
fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
|
||||||
let (analysis, _) = single_file(text);
|
let (analysis, _) = single_file(text);
|
||||||
analysis.symbol_search(Query::new(query.into())).unwrap()
|
analysis.symbol_search(Query::new(query.into())).unwrap()
|
||||||
|
|
Loading…
Reference in a new issue