diff --git a/pylight/benches/search.rs b/pylight/benches/search.rs index 87a2294..12c33e6 100644 --- a/pylight/benches/search.rs +++ b/pylight/benches/search.rs @@ -1,6 +1,5 @@ use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use pylight::{SearchEngine, Symbol, SymbolKind}; -use std::path::PathBuf; use std::sync::Arc; fn generate_symbols(count: usize) -> Vec> { @@ -11,7 +10,7 @@ fn generate_symbols(count: usize) -> Vec> { symbols.push(Arc::new(Symbol::new( format!("function_{i}"), SymbolKind::Function, - PathBuf::from(format!("file{}.py", i % 10)), + format!("file{}.py", i % 10), i, 0, ))); @@ -19,7 +18,7 @@ fn generate_symbols(count: usize) -> Vec> { symbols.push(Arc::new(Symbol::new( format!("Class_{i}"), SymbolKind::Class, - PathBuf::from(format!("file{}.py", i % 10)), + format!("file{}.py", i % 10), i, 0, ))); @@ -28,7 +27,7 @@ fn generate_symbols(count: usize) -> Vec> { Symbol::new( format!("method_{i}"), SymbolKind::Method, - PathBuf::from(format!("file{}.py", i % 10)), + format!("file{}.py", i % 10), i, 4, ) diff --git a/pylight/src/bin/pylight.rs b/pylight/src/bin/pylight.rs index 19f970b..2b65ce3 100644 --- a/pylight/src/bin/pylight.rs +++ b/pylight/src/bin/pylight.rs @@ -103,7 +103,7 @@ fn run_standalone( "{:2}. {} ({}:{})", i + 1, result.symbol.name, - result.symbol.file_path.display(), + result.symbol.file_path.as_ref(), result.symbol.line ); } diff --git a/pylight/src/index/mod.rs b/pylight/src/index/mod.rs index 9855583..1b5fdbd 100644 --- a/pylight/src/index/mod.rs +++ b/pylight/src/index/mod.rs @@ -4,4 +4,4 @@ pub mod files; pub mod symbol_index; pub mod updater; -pub use symbol_index::{FileMetadata, SymbolIndex}; +pub use symbol_index::SymbolIndex; diff --git a/pylight/src/index/symbol_index.rs b/pylight/src/index/symbol_index.rs index cc37a54..73e93fd 100644 --- a/pylight/src/index/symbol_index.rs +++ b/pylight/src/index/symbol_index.rs @@ -1,6 +1,7 @@ //! Symbol index implementation use crate::parser::{create_parser, ParserBackend}; +use crate::string_cache::StringCache; use crate::{Result, Symbol}; use parking_lot::RwLock; use rayon::prelude::*; @@ -13,14 +14,8 @@ use super::files; pub struct SymbolIndex { symbols: Arc>>>>, all_symbols: Arc>>>, - file_metadata: Arc>>, parser_backend: ParserBackend, -} - -#[derive(Debug, Clone)] -pub struct FileMetadata { - pub last_modified: std::time::SystemTime, - pub symbol_count: usize, + string_cache: StringCache, } impl SymbolIndex { @@ -28,8 +23,8 @@ impl SymbolIndex { Self { symbols: Arc::new(RwLock::new(HashMap::new())), all_symbols: Arc::new(RwLock::new(Vec::new())), - file_metadata: Arc::new(RwLock::new(HashMap::new())), parser_backend, + string_cache: StringCache::new(), } } @@ -44,28 +39,22 @@ impl SymbolIndex { let mut file_symbols = self.symbols.write(); let mut all = self.all_symbols.write(); - let mut metadata = self.file_metadata.write(); // Remove old symbols for this file if any if let Some(_old_symbols) = file_symbols.get(&canonical_path) { - all.retain(|s| s.file_path != canonical_path); + all.retain(|s| s.file_path.as_ref() != canonical_path.to_string_lossy().as_ref()); } - // Update metadata - if let Ok(file_metadata) = std::fs::metadata(&canonical_path) { - if let Ok(modified) = file_metadata.modified() { - metadata.insert( - canonical_path.clone(), - FileMetadata { - last_modified: modified, - symbol_count: symbols.len(), - }, - ); - } - } - - // Convert symbols to Arc - let arc_symbols: Vec> = symbols.into_iter().map(Arc::new).collect(); + // Convert symbols to Arc and intern strings + let arc_symbols: Vec> = symbols + .into_iter() + .map(|mut symbol| { + // Intern file_path and module_path + symbol.file_path = self.string_cache.intern(symbol.file_path.as_ref()); + symbol.module_path = self.string_cache.intern(symbol.module_path.as_ref()); + Arc::new(symbol) + }) + .collect(); // Add new symbols all.extend(arc_symbols.clone()); @@ -80,11 +69,9 @@ impl SymbolIndex { let mut file_symbols = self.symbols.write(); let mut all = self.all_symbols.write(); - let mut metadata = self.file_metadata.write(); file_symbols.remove(&canonical_path); - all.retain(|s| s.file_path != canonical_path); - metadata.remove(&canonical_path); + all.retain(|s| s.file_path.as_ref() != canonical_path.to_string_lossy().as_ref()); Ok(()) } @@ -110,7 +97,6 @@ impl SymbolIndex { pub fn clear(&self) { self.symbols.write().clear(); self.all_symbols.write().clear(); - self.file_metadata.write().clear(); } /// Get the total number of indexed files @@ -124,12 +110,6 @@ impl SymbolIndex { self.symbols.read().contains_key(&canonical_path) } - /// Get metadata for a file - pub fn get_file_metadata(&self, path: &Path) -> Option { - let canonical_path = path.canonicalize().unwrap_or_else(|_| path.to_path_buf()); - self.file_metadata.read().get(&canonical_path).cloned() - } - /// Update specific files without full re-index pub fn update_files_batch( &self, @@ -137,7 +117,6 @@ impl SymbolIndex { ) -> Result<(usize, usize)> { let mut file_symbols = self.symbols.write(); let mut all = self.all_symbols.write(); - let mut metadata = self.file_metadata.write(); let mut updated_files = 0; let mut total_symbols = 0; @@ -145,24 +124,19 @@ impl SymbolIndex { for (path, symbols) in updates { // Remove old symbols for this file if any if file_symbols.contains_key(&path) { - all.retain(|s| s.file_path != path); + all.retain(|s| s.file_path.as_ref() != path.to_string_lossy().as_ref()); } - // Update metadata - if let Ok(file_metadata) = std::fs::metadata(&path) { - if let Ok(modified) = file_metadata.modified() { - metadata.insert( - path.clone(), - FileMetadata { - last_modified: modified, - symbol_count: symbols.len(), - }, - ); - } - } - - // Convert symbols to Arc - let arc_symbols: Vec> = symbols.into_iter().map(Arc::new).collect(); + // Convert symbols to Arc and intern strings + let arc_symbols: Vec> = symbols + .into_iter() + .map(|mut symbol| { + // Intern file_path and module_path + symbol.file_path = self.string_cache.intern(symbol.file_path.as_ref()); + symbol.module_path = self.string_cache.intern(symbol.module_path.as_ref()); + Arc::new(symbol) + }) + .collect(); total_symbols += arc_symbols.len(); // Add new symbols @@ -179,45 +153,36 @@ impl SymbolIndex { // Acquire all locks in a consistent order to avoid deadlocks let mut symbols = self.symbols.write(); let mut all_symbols = self.all_symbols.write(); - let mut metadata = self.file_metadata.write(); let new_symbols = new_index.symbols.read(); let new_all = new_index.all_symbols.read(); - let new_metadata = new_index.file_metadata.read(); // Swap the contents *symbols = new_symbols.clone(); *all_symbols = new_all.clone(); - *metadata = new_metadata.clone(); } /// Add multiple files in a single batch operation to minimize lock contention pub fn add_files_batch(&self, files: Vec<(PathBuf, Vec)>) -> Result<()> { let mut file_symbols = self.symbols.write(); let mut all = self.all_symbols.write(); - let mut metadata = self.file_metadata.write(); for (path, symbols) in files { // Remove old symbols for this file if any if file_symbols.contains_key(&path) { - all.retain(|s| s.file_path != path); - } - - // Update metadata - if let Ok(file_metadata) = std::fs::metadata(&path) { - if let Ok(modified) = file_metadata.modified() { - metadata.insert( - path.clone(), - FileMetadata { - last_modified: modified, - symbol_count: symbols.len(), - }, - ); - } + all.retain(|s| s.file_path.as_ref() != path.to_string_lossy().as_ref()); } - // Convert symbols to Arc - let arc_symbols: Vec> = symbols.into_iter().map(Arc::new).collect(); + // Convert symbols to Arc and intern strings + let arc_symbols: Vec> = symbols + .into_iter() + .map(|mut symbol| { + // Intern file_path and module_path + symbol.file_path = self.string_cache.intern(symbol.file_path.as_ref()); + symbol.module_path = self.string_cache.intern(symbol.module_path.as_ref()); + Arc::new(symbol) + }) + .collect(); // Add new symbols all.extend(arc_symbols.clone()); diff --git a/pylight/src/lib.rs b/pylight/src/lib.rs index fbedb18..6592460 100644 --- a/pylight/src/lib.rs +++ b/pylight/src/lib.rs @@ -9,6 +9,7 @@ pub mod index; pub mod lsp; pub mod parser; pub mod search; +pub mod string_cache; pub mod symbols; pub mod watcher; diff --git a/pylight/src/lsp/handlers.rs b/pylight/src/lsp/handlers.rs index 4e6b2b3..b0e095d 100644 --- a/pylight/src/lsp/handlers.rs +++ b/pylight/src/lsp/handlers.rs @@ -53,7 +53,7 @@ pub fn handle_workspace_symbol( .take(200) // Limit results .filter_map(|result| { let symbol = &result.symbol; - let uri = url::Url::from_file_path(&symbol.file_path).ok()?; + let uri = url::Url::from_file_path(symbol.file_path.as_ref()).ok()?; #[allow(deprecated)] Some(SymbolInformation { diff --git a/pylight/src/parser/extractor.rs b/pylight/src/parser/extractor.rs index 9f9f8d1..5aad586 100644 --- a/pylight/src/parser/extractor.rs +++ b/pylight/src/parser/extractor.rs @@ -72,7 +72,13 @@ impl<'a> SymbolExtractor<'a> { _ => SymbolKind::Function, }; - let mut symbol = Symbol::new(name.clone(), kind, self.path.clone(), line, column); + let mut symbol = Symbol::new( + name.clone(), + kind, + self.path.to_string_lossy().into_owned(), + line, + column, + ); // Set container name if we're inside another context if !self.context_stack.is_empty() { @@ -131,7 +137,13 @@ impl<'a> SymbolExtractor<'a> { SymbolKind::Class }; - let mut symbol = Symbol::new(name.clone(), kind, self.path.clone(), line, column); + let mut symbol = Symbol::new( + name.clone(), + kind, + self.path.to_string_lossy().into_owned(), + line, + column, + ); // Set container name if we're inside another context if !self.context_stack.is_empty() { diff --git a/pylight/src/parser/ruff.rs b/pylight/src/parser/ruff.rs index c1b7551..33ee097 100644 --- a/pylight/src/parser/ruff.rs +++ b/pylight/src/parser/ruff.rs @@ -7,7 +7,7 @@ use ruff_python_ast::{ }; use ruff_python_parser::{parse, Mode}; use ruff_source_file::{LineIndex, SourceCode}; -use std::path::{Path, PathBuf}; +use std::path::Path; use super::r#trait::Parser; @@ -33,7 +33,7 @@ enum Context { struct SymbolExtractor<'a> { symbols: &'a mut Vec, - file_path: PathBuf, + file_path: String, context_stack: Vec, source_code: SourceCode<'a, 'a>, } @@ -41,7 +41,7 @@ struct SymbolExtractor<'a> { impl<'a> SymbolExtractor<'a> { fn new( symbols: &'a mut Vec, - file_path: PathBuf, + file_path: String, source: &'a str, line_index: &'a LineIndex, ) -> Self { @@ -118,8 +118,7 @@ impl<'a> Visitor<'a> for SymbolExtractor<'a> { let (line, column) = self.get_line_column(func_def.name.range.start().to_u32()); // Get module name from file path - let module_path = self - .file_path + let module_path = std::path::Path::new(&self.file_path) .file_stem() .and_then(|s| s.to_str()) .unwrap_or("unknown") @@ -148,8 +147,7 @@ impl<'a> Visitor<'a> for SymbolExtractor<'a> { let (line, column) = self.get_line_column(class_def.name.range.start().to_u32()); // Get module name from file path - let module_path = self - .file_path + let module_path = std::path::Path::new(&self.file_path) .file_stem() .and_then(|s| s.to_str()) .unwrap_or("unknown") @@ -183,8 +181,12 @@ impl Parser for RuffParser { .map_err(|e| Error::Parse(format!("Ruff parse error: {e:?}")))?; let mut symbols = Vec::new(); - let mut extractor = - SymbolExtractor::new(&mut symbols, file_path.to_path_buf(), source, &line_index); + let mut extractor = SymbolExtractor::new( + &mut symbols, + file_path.to_string_lossy().into_owned(), + source, + &line_index, + ); match parsed.syntax() { Mod::Module(module) => { diff --git a/pylight/src/parser/tests.rs b/pylight/src/parser/tests.rs index 607d0de..71d2b52 100644 --- a/pylight/src/parser/tests.rs +++ b/pylight/src/parser/tests.rs @@ -142,8 +142,7 @@ class MyClass: assert_eq!(symbols[0].line, 1); assert_eq!( symbols[0].column, 4, - "Function name should start at column 4 (0-based) for parser {:?}", - backend + "Function name should start at column 4 (0-based) for parser {backend:?}" ); // Test class column position @@ -154,8 +153,7 @@ class MyClass: assert_eq!(symbols[0].line, 1); assert_eq!( symbols[0].column, 6, - "Class name should start at column 6 (0-based) for parser {:?}", - backend + "Class name should start at column 6 (0-based) for parser {backend:?}" ); // Test indented method column position @@ -165,8 +163,7 @@ class MyClass: assert_eq!(method.line, 2); assert_eq!( method.column, 8, - "Method name should start at column 8 (0-based) for parser {:?}", - backend + "Method name should start at column 8 (0-based) for parser {backend:?}" ); } } diff --git a/pylight/src/search.rs b/pylight/src/search.rs index 3125207..9e9ccef 100644 --- a/pylight/src/search.rs +++ b/pylight/src/search.rs @@ -117,7 +117,6 @@ impl Default for SearchEngine { mod tests { use super::*; use crate::symbols::SymbolKind; - use std::path::PathBuf; #[test] fn test_search_engine_creation() { @@ -133,14 +132,14 @@ mod tests { Arc::new(Symbol::new( "test_function".to_string(), SymbolKind::Function, - PathBuf::from("test.py"), + "test.py".to_string(), 1, 0, )), Arc::new(Symbol::new( "another_function".to_string(), SymbolKind::Function, - PathBuf::from("test.py"), + "test.py".to_string(), 2, 0, )), diff --git a/pylight/src/string_cache.rs b/pylight/src/string_cache.rs new file mode 100644 index 0000000..ee96c0b --- /dev/null +++ b/pylight/src/string_cache.rs @@ -0,0 +1,79 @@ +//! Simple string cache for deduplicating file paths and module paths + +use parking_lot::RwLock; +use std::collections::HashMap; +use std::sync::Arc; + +/// A thread-safe string cache that deduplicates strings using Arc +#[derive(Clone, Default)] +pub struct StringCache { + cache: Arc>>>, +} + +impl StringCache { + pub fn new() -> Self { + Self { + cache: Arc::new(RwLock::new(HashMap::new())), + } + } + + /// Get or insert a string into the cache, returning an Arc + pub fn intern(&self, s: impl Into) -> Arc { + let s = s.into(); + + // Fast path: check if already cached + { + let cache = self.cache.read(); + if let Some(cached) = cache.get(&s) { + return Arc::clone(cached); + } + } + + // Slow path: insert into cache + let mut cache = self.cache.write(); + cache + .entry(s.clone()) + .or_insert_with(|| Arc::from(s.as_str())) + .clone() + } + + /// Get the number of unique strings in the cache + #[allow(dead_code)] + pub fn len(&self) -> usize { + self.cache.read().len() + } + + /// Check if the cache is empty + #[allow(dead_code)] + pub fn is_empty(&self) -> bool { + self.cache.read().is_empty() + } + + /// Clear the cache + #[allow(dead_code)] + pub fn clear(&self) { + self.cache.write().clear(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_string_cache() { + let cache = StringCache::new(); + + let s1 = cache.intern("hello"); + let s2 = cache.intern("hello"); + let s3 = cache.intern("world"); + + // Same string should return same Arc + assert!(Arc::ptr_eq(&s1, &s2)); + + // Different strings should not + assert!(!Arc::ptr_eq(&s1, &s3)); + + assert_eq!(cache.len(), 2); + } +} diff --git a/pylight/src/symbols.rs b/pylight/src/symbols.rs index e639fd8..f195fd4 100644 --- a/pylight/src/symbols.rs +++ b/pylight/src/symbols.rs @@ -1,7 +1,7 @@ //! Symbol definitions and types use serde::{Deserialize, Serialize}; -use std::path::PathBuf; +use std::sync::Arc; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum SymbolKind { @@ -12,33 +12,81 @@ pub enum SymbolKind { NestedClass, } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Symbol { pub name: String, pub kind: SymbolKind, - pub file_path: PathBuf, + pub file_path: Arc, pub line: usize, pub column: usize, pub container_name: Option, - pub module_path: String, + pub module_path: Arc, +} + +// Custom Serialize/Deserialize to handle Arc +impl Serialize for Symbol { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut state = serializer.serialize_struct("Symbol", 7)?; + state.serialize_field("name", &self.name)?; + state.serialize_field("kind", &self.kind)?; + state.serialize_field("file_path", &self.file_path.as_ref())?; + state.serialize_field("line", &self.line)?; + state.serialize_field("column", &self.column)?; + state.serialize_field("container_name", &self.container_name)?; + state.serialize_field("module_path", &self.module_path.as_ref())?; + state.end() + } +} + +impl<'de> Deserialize<'de> for Symbol { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + struct SymbolData { + name: String, + kind: SymbolKind, + file_path: String, + line: usize, + column: usize, + container_name: Option, + module_path: String, + } + + let data = SymbolData::deserialize(deserializer)?; + Ok(Symbol { + name: data.name, + kind: data.kind, + file_path: Arc::from(data.file_path.as_str()), + line: data.line, + column: data.column, + container_name: data.container_name, + module_path: Arc::from(data.module_path.as_str()), + }) + } } impl Symbol { pub fn new( name: String, kind: SymbolKind, - file_path: PathBuf, + file_path: String, line: usize, column: usize, ) -> Self { Self { name, kind, - file_path, + file_path: Arc::from(file_path), line, column, container_name: None, - module_path: String::new(), + module_path: Arc::from(""), } } @@ -48,7 +96,7 @@ impl Symbol { } pub fn with_module(mut self, module: String) -> Self { - self.module_path = module; + self.module_path = Arc::from(module.as_str()); self } } diff --git a/pylight/tests/integration/test_index.rs b/pylight/tests/integration/test_index.rs index 10fa9ff..5351f8b 100644 --- a/pylight/tests/integration/test_index.rs +++ b/pylight/tests/integration/test_index.rs @@ -10,11 +10,17 @@ fn test_index_add_file() { Symbol::new( "func1".to_string(), SymbolKind::Function, - path.clone(), + path.to_string_lossy().into_owned(), 1, 0, ), - Symbol::new("Class1".to_string(), SymbolKind::Class, path.clone(), 10, 0), + Symbol::new( + "Class1".to_string(), + SymbolKind::Class, + path.to_string_lossy().into_owned(), + 10, + 0, + ), ]; index.add_file(path.clone(), symbols.clone()).unwrap(); @@ -35,7 +41,7 @@ fn test_index_update_file() { let symbols_v1 = vec![Symbol::new( "old_func".to_string(), SymbolKind::Function, - path.clone(), + path.to_string_lossy().into_owned(), 1, 0, )]; @@ -46,14 +52,14 @@ fn test_index_update_file() { Symbol::new( "new_func".to_string(), SymbolKind::Function, - path.clone(), + path.to_string_lossy().into_owned(), 1, 0, ), Symbol::new( "NewClass".to_string(), SymbolKind::Class, - path.clone(), + path.to_string_lossy().into_owned(), 10, 0, ), @@ -80,14 +86,14 @@ fn test_index_remove_file() { let symbols1 = vec![Symbol::new( "func1".to_string(), SymbolKind::Function, - path1.clone(), + path1.to_string_lossy().into_owned(), 1, 0, )]; let symbols2 = vec![Symbol::new( "func2".to_string(), SymbolKind::Function, - path2.clone(), + path2.to_string_lossy().into_owned(), 1, 0, )]; @@ -115,12 +121,12 @@ fn test_index_clear() { let symbols = vec![Symbol::new( "func1".to_string(), SymbolKind::Function, - path.clone(), + path.to_string_lossy().into_owned(), 1, 0, )]; - index.add_file(path, symbols).unwrap(); + index.add_file(path.clone(), symbols).unwrap(); assert_eq!(index.get_all_symbols().len(), 1); index.clear(); diff --git a/pylight/tests/integration/test_lsp.rs b/pylight/tests/integration/test_lsp.rs index 9905b87..b463ed8 100644 --- a/pylight/tests/integration/test_lsp.rs +++ b/pylight/tests/integration/test_lsp.rs @@ -17,14 +17,14 @@ fn test_lsp_handler() { Symbol::new( "test_function".to_string(), SymbolKind::Function, - PathBuf::from("/test/file.py"), + "/test/file.py".to_string(), 10, 0, ), Symbol::new( "TestClass".to_string(), SymbolKind::Class, - PathBuf::from("/test/file.py"), + "/test/file.py".to_string(), 20, 0, ), @@ -70,14 +70,14 @@ fn test_empty_query_returns_symbols() { Symbol::new( "function1".to_string(), SymbolKind::Function, - PathBuf::from("/test/file.py"), + "/test/file.py".to_string(), 10, 0, ), Symbol::new( "function2".to_string(), SymbolKind::Function, - PathBuf::from("/test/file.py"), + "/test/file.py".to_string(), 20, 0, ), diff --git a/pylight/tests/integration/test_search.rs b/pylight/tests/integration/test_search.rs index 04e0c8e..e4247f4 100644 --- a/pylight/tests/integration/test_search.rs +++ b/pylight/tests/integration/test_search.rs @@ -1,5 +1,4 @@ use pylight::{SearchEngine, Symbol, SymbolKind}; -use std::path::PathBuf; use std::sync::Arc; fn create_test_symbols() -> Vec> { @@ -7,35 +6,35 @@ fn create_test_symbols() -> Vec> { Arc::new(Symbol::new( "test_function".to_string(), SymbolKind::Function, - PathBuf::from("test.py"), + "test.py".to_string(), 1, 0, )), Arc::new(Symbol::new( "TestClass".to_string(), SymbolKind::Class, - PathBuf::from("test.py"), + "test.py".to_string(), 10, 0, )), Arc::new(Symbol::new( "another_test_func".to_string(), SymbolKind::Function, - PathBuf::from("test.py"), + "test.py".to_string(), 20, 0, )), Arc::new(Symbol::new( "helper_function".to_string(), SymbolKind::Function, - PathBuf::from("helper.py"), + "helper.py".to_string(), 5, 0, )), Arc::new(Symbol::new( "HelperClass".to_string(), SymbolKind::Class, - PathBuf::from("helper.py"), + "helper.py".to_string(), 15, 0, )), @@ -43,7 +42,7 @@ fn create_test_symbols() -> Vec> { Symbol::new( "test_method".to_string(), SymbolKind::Method, - PathBuf::from("test.py"), + "test.py".to_string(), 12, 4, ) @@ -86,28 +85,28 @@ fn test_exact_match_ranks_first() { Arc::new(Symbol::new( "test".to_string(), // Exact match SymbolKind::Function, - PathBuf::from("exact.py"), + "exact.py".to_string(), 1, 0, )), Arc::new(Symbol::new( "test_something".to_string(), // Prefix match SymbolKind::Function, - PathBuf::from("prefix.py"), + "prefix.py".to_string(), 1, 0, )), Arc::new(Symbol::new( "another_test".to_string(), // Suffix match SymbolKind::Function, - PathBuf::from("suffix.py"), + "suffix.py".to_string(), 1, 0, )), Arc::new(Symbol::new( "TestClass".to_string(), // Different case SymbolKind::Class, - PathBuf::from("class.py"), + "class.py".to_string(), 1, 0, )), @@ -198,14 +197,14 @@ fn test_case_insensitive_exact_match() { Arc::new(Symbol::new( "TestFunction".to_string(), SymbolKind::Function, - PathBuf::from("test.py"), + "test.py".to_string(), 1, 0, )), Arc::new(Symbol::new( "test_helper".to_string(), SymbolKind::Function, - PathBuf::from("test.py"), + "test.py".to_string(), 10, 0, )),