From d2e8a979fa6502477c28602591a5592be4ce0a5a Mon Sep 17 00:00:00 2001 From: Rodolpho Lima Date: Wed, 12 Nov 2025 19:38:14 +0100 Subject: [PATCH 1/5] [IMP] list namespace dirs on hover Instead of displaying the "See also" link, we now list the namespace directories when hovering over a namespace symbol. We also make sure that the documentation section appears before the useful links/directories list section. --- server/src/features/features_utils.rs | 54 ++++++++++++++-------- server/tests/test_get_symbol.rs | 66 +++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 19 deletions(-) diff --git a/server/src/features/features_utils.rs b/server/src/features/features_utils.rs index fe59572c..1aa1eb29 100644 --- a/server/src/features/features_utils.rs +++ b/server/src/features/features_utils.rs @@ -4,10 +4,9 @@ use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::core::file_mgr::FileMgr; use crate::core::odoo::SyncOdoo; use crate::core::symbols::function_symbol::Argument; -use crate::utils::{compare_semver, PathSanitizer}; +use crate::utils::compare_semver; use std::cmp::Ordering; use std::collections::HashMap; -use std::path::PathBuf; use std::rc::Weak; use std::{cell::RefCell, rc::Rc}; @@ -507,12 +506,12 @@ impl FeaturesUtils { let from_modules = info_pieces.iter().filter_map(|info| info.from_module.clone().map(|module_rc| module_rc.borrow().name().clone())).unique().collect::>(); // BLOCK 1: (type) **name** -> inferred_type block += FeaturesUtils::build_block_1(session, id.type_, &id.name, sym_type_tag, &inferred_types).as_str(); - // BLOCK 2: useful links - block += inferred_types.iter().map(|typ| FeaturesUtils::get_useful_link(session, &typ.eval_ptr)).collect::().as_str(); - // BLOCK 3: documentation + // BLOCK 2: documentation if let Some(documentation_block) = FeaturesUtils::get_documentation_block(session, &from_modules, &inferred_types){ block = block + " \n*** \n" + &documentation_block; } + // BLOCK 3: useful links or directory paths + block += inferred_types.iter().map(|typ| FeaturesUtils::get_location_info(session, &typ.eval_ptr)).collect::().as_str(); blocks.push(block); } blocks.iter().join(" \n*** \n") @@ -674,24 +673,41 @@ impl FeaturesUtils { } - /// Finds and returns useful links for an evaluation - fn get_useful_link(_session: &mut SessionInfo, typ: &EvaluationSymbolPtr) -> String { + /// Finds and returns useful links or directory locations for an evaluation + fn get_location_info(_session: &mut SessionInfo, typ: &EvaluationSymbolPtr) -> String { // Possibly add more links in the future let Some(typ) = typ.upgrade_weak() else { return S!("") }; - let paths = &typ.borrow().paths(); - if paths.len() == 1 { //we won't put a link to a namespace - let type_ref = typ.borrow(); - let base_path = match type_ref.typ() { - SymType::PACKAGE(_) => PathBuf::from(paths.first().unwrap().clone()).join(format!("__init__.py{}", type_ref.as_package().i_ext())).sanitize(), - _ => paths.first().unwrap().clone() - }; - let path = FileMgr::pathname2uri(&base_path); - let range = if type_ref.is_file_content() { type_ref.range().start().to_u32() } else { 0 }; - format!(" \n*** \nSee also: [{}]({}#{}){}", type_ref.name().as_str(), path.as_str(), range, " \n") - } else { - S!("") + let symbol = &*typ.borrow(); + let lb = FeaturesUtils::get_line_break(_session); + match symbol { + Symbol::Namespace(ns) => { + // List namespace directories + let paths = ns.paths(); + let name = &ns.name; + match paths.len() { + 0 => S!(""), + 1 => format!(" \n*** \n`{name}` namespace directory: `{}`{lb}", paths[0]), + _ => { + let path_list = paths.iter().map(|p| format!("- `{p}`")).join(lb); + format!(" \n*** \n`{name}` namespace directories:{lb}{path_list}{lb}") + } + } + } + Symbol::Package(_) + | Symbol::File(_) + | Symbol::XmlFileSymbol(_) + | Symbol::CsvFileSymbol(_) => { + // Get useful link + let uri = FileMgr::pathname2uri(&symbol.get_symbol_first_path()); + let range = if symbol.is_file_content() { symbol.range().start().to_u32() } else { 0 }; + format!( " \n*** \nSee also: [{}]({}#{}){lb}", symbol.name(), uri.as_str(), range) + } + Symbol::Compiled(c) => { + format!(" \n*** \n`{}` is a binary at `{}`{lb}", c.name, c.path) + } + _ => S!(""), } } diff --git a/server/tests/test_get_symbol.rs b/server/tests/test_get_symbol.rs index 49d6de1d..519a85ec 100644 --- a/server/tests/test_get_symbol.rs +++ b/server/tests/test_get_symbol.rs @@ -150,6 +150,72 @@ fn test_hover_on_model_field_and_method() { ); } +#[test] +fn test_hover_on_namespace_and_module() { + // Setup server and session with test addons + let (mut odoo, config) = setup::setup::setup_server(true); + let test_addons_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests").join("data").join("addons"); + let test_file = test_addons_path.join("module_1").join("models").join("base_test_models.py").sanitize(); + + // Ensure the test file exists + assert!(PathBuf::from(&test_file).exists(), "Test file does not exist: {}", test_file); + let mut session = setup::setup::create_init_session(&mut odoo, config); + + // Get file symbol and file info + let file_mgr = session.sync_odoo.get_file_mgr(); + let file_info = file_mgr.borrow().get_file_info(&test_file).unwrap(); + let Some(file_symbol) = SyncOdoo::get_symbol_of_opened_file( + &mut session, + &PathBuf::from(&test_file) + ) else { + panic!("Failed to get file symbol"); + }; + + // Test hover on namespace: "odoo.addons" in line 2: from odoo.addons.module_1.constants import ... + // Position: line 1 (0-indexed), character at "addons" (~10-16) + let hover_namespace = test_utils::get_hover_markdown(&mut session, &file_symbol, &file_info, 1, 12).unwrap_or_default(); + + // Should show namespace symbol type + assert!( + hover_namespace.contains("(namespace)"), + "Hover on namespace should show '(namespace)' type. Got: {}", hover_namespace + ); + + // Should show "addons" as the name + assert!( + hover_namespace.contains("addons"), + "Hover on namespace should show namespace name. Got: {}", hover_namespace + ); + + // Should list directories instead of "See also" link + assert!( + hover_namespace.contains("directories:"), + "Hover on namespace should list directories. Got: {}", hover_namespace + ); + + // Should NOT contain "See also:" link + assert!( + !hover_namespace.contains("See also:"), + "Hover on namespace should NOT show 'See also' link. Got: {}", hover_namespace + ); + + // Test hover on Odoo module: "module_1" in line 2: from odoo.addons.module_1.constants import ... + // Position: line 1 (0-indexed), character at "module_1" (~17-24) + let hover_module = test_utils::get_hover_markdown(&mut session, &file_symbol, &file_info, 1, 20).unwrap_or_default(); + + // Should show package type, module name and "Module" inferred type + assert!( + hover_module.contains("(package) module_1: Module"), + "Hover on Odoo module should show package type, module_1 as name and 'Module' inferred type. Got: {}", hover_module + ); + + // Module should show "See also" link + assert!( + hover_module.contains("See also:"), + "Hover on Odoo module should show 'See also' link. Got: {}", hover_module + ); +} + #[test] fn test_definition() { // Setup server and session with test addons From 2a68db2e15361b9887a9643a18fe62a662d82cf9 Mon Sep 17 00:00:00 2001 From: Rodolpho Lima Date: Fri, 14 Nov 2025 14:29:43 +0100 Subject: [PATCH 2/5] [REF] remove paths from RootSymbol The `paths` field in `RootSymbol` has no purpose and is always an empty vector. --- server/src/core/symbols/root_symbol.rs | 2 -- server/src/core/symbols/symbol.rs | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/server/src/core/symbols/root_symbol.rs b/server/src/core/symbols/root_symbol.rs index f7824c61..d65bc444 100644 --- a/server/src/core/symbols/root_symbol.rs +++ b/server/src/core/symbols/root_symbol.rs @@ -7,7 +7,6 @@ use super::symbol::Symbol; pub struct RootSymbol { pub name: OYarn, pub entry_point: Option>>, - pub paths: Vec, pub weak_self: Option>>, pub parent: Option>>, pub module_symbols: HashMap>>, @@ -18,7 +17,6 @@ impl RootSymbol { pub fn new() -> Self { Self { name: oyarn!("Root"), - paths: vec![], weak_self: None, entry_point: None, parent: None, diff --git a/server/src/core/symbols/symbol.rs b/server/src/core/symbols/symbol.rs index c6445d2d..5050de58 100644 --- a/server/src/core/symbols/symbol.rs +++ b/server/src/core/symbols/symbol.rs @@ -844,7 +844,7 @@ impl Symbol { pub fn paths(&self) -> Vec { match self { - Symbol::Root(r) => r.paths.clone(), + Symbol::Root(_) => vec![], Symbol::Namespace(n) => n.paths(), Symbol::DiskDir(d) => vec![d.path.clone()], Symbol::Package(p) => p.paths(), @@ -859,7 +859,7 @@ impl Symbol { } pub fn add_path(&mut self, path: String) { match self { - Symbol::Root(r) => r.paths.push(path), + Symbol::Root(_) => {}, Symbol::Namespace(n) => { n.directories.push(NamespaceDirectory { path: path, module_symbols: HashMap::new() }); }, From cebf89c270d1e1f653bf573508eb815e7e0e3ad5 Mon Sep 17 00:00:00 2001 From: Rodolpho Lima Date: Tue, 18 Nov 2025 17:22:20 +0100 Subject: [PATCH 3/5] [REF] move add_path to NamespaceSymbol Among all symbol variants, adding a path is only relevant for `NamespaceSymbol`. Therefore this commits moved the `add_path` method from the generic `Symbol` enum to the specific `NamespaceSymbol` struct. --- server/src/core/odoo.rs | 4 ++-- server/src/core/symbols/namespace_symbol.rs | 4 ++++ server/src/core/symbols/symbol.rs | 19 +------------------ 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/server/src/core/odoo.rs b/server/src/core/odoo.rs index 7d870824..408a6355 100644 --- a/server/src/core/odoo.rs +++ b/server/src/core/odoo.rs @@ -443,7 +443,7 @@ impl SyncOdoo { let addon_symbol = addon_symbol[0].clone(); if odoo_addon_path.exists() { if session.sync_odoo.load_odoo_addons { - addon_symbol.borrow_mut().add_path( + addon_symbol.borrow_mut().as_namespace_mut().add_path( odoo_addon_path.sanitize() ); EntryPointMgr::add_entry_to_addons(session, odoo_addon_path.sanitize(), @@ -457,7 +457,7 @@ impl SyncOdoo { for addon in session.sync_odoo.config.addons_paths.clone().iter() { let addon_path = PathBuf::from(addon); if addon_path.exists() { - addon_symbol.borrow_mut().add_path( + addon_symbol.borrow_mut().as_namespace_mut().add_path( addon_path.sanitize() ); EntryPointMgr::add_entry_to_addons(session, addon.clone(), diff --git a/server/src/core/symbols/namespace_symbol.rs b/server/src/core/symbols/namespace_symbol.rs index 82d8a3ca..9582361d 100644 --- a/server/src/core/symbols/namespace_symbol.rs +++ b/server/src/core/symbols/namespace_symbol.rs @@ -71,6 +71,10 @@ impl NamespaceSymbol { self.directories.iter().map(|x| {x.path.clone()}).collect() } + pub fn add_path(&mut self, path: String) { + self.directories.push(NamespaceDirectory { path, module_symbols: HashMap::new() }); + } + pub fn get_dependencies(&self, step: usize, level: usize) -> Option<&PtrWeakHashSet>>> { self.dependencies.get(step)?.get(level)?.as_ref() diff --git a/server/src/core/symbols/symbol.rs b/server/src/core/symbols/symbol.rs index 5050de58..2434f33d 100644 --- a/server/src/core/symbols/symbol.rs +++ b/server/src/core/symbols/symbol.rs @@ -33,7 +33,7 @@ use super::compiled_symbol::CompiledSymbol; use super::csv_file_symbol::CsvFileSymbol; use super::disk_dir_symbol::DiskDirSymbol; use super::file_symbol::FileSymbol; -use super::namespace_symbol::{NamespaceDirectory, NamespaceSymbol}; +use super::namespace_symbol::NamespaceSymbol; use super::package_symbol::{PackageSymbol, PythonPackageSymbol}; use super::symbol_mgr::{ContentSymbols, SymbolMgr}; use super::variable_symbol::VariableSymbol; @@ -857,23 +857,6 @@ impl Symbol { Symbol::CsvFileSymbol(c) => vec![c.path.clone()], } } - pub fn add_path(&mut self, path: String) { - match self { - Symbol::Root(_) => {}, - Symbol::Namespace(n) => { - n.directories.push(NamespaceDirectory { path: path, module_symbols: HashMap::new() }); - }, - Symbol::DiskDir(_) => {}, - Symbol::Package(_) => {}, - Symbol::File(_) => {}, - Symbol::Compiled(_) => {}, - Symbol::Class(_) => {}, - Symbol::Function(_) => {}, - Symbol::Variable(_) => {}, - Symbol::XmlFileSymbol(_) => {}, - Symbol::CsvFileSymbol(_) => {}, - } - } pub fn get_symbol_first_path(&self) -> String{ match self{ From 0b7874cbd143129172153f5cd47fbb5a193272d6 Mon Sep 17 00:00:00 2001 From: Rodolpho Lima Date: Fri, 14 Nov 2025 16:08:25 +0100 Subject: [PATCH 4/5] [REF] path method in PackageSymbol Package symbols only have a single path. Before this commit, the `PackageSymbol::paths` method always returned a single-element Vec. This commit renames it to `path` (singular) and makes it return the single path instead. --- server/src/core/symbols/package_symbol.rs | 6 +++--- server/src/core/symbols/symbol.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/src/core/symbols/package_symbol.rs b/server/src/core/symbols/package_symbol.rs index 8a1798b8..4baea689 100644 --- a/server/src/core/symbols/package_symbol.rs +++ b/server/src/core/symbols/package_symbol.rs @@ -82,10 +82,10 @@ impl PackageSymbol { PackageSymbol::PythonPackage(p) => p.module_symbols.insert(file.borrow().name().clone(), file.clone()), }; } - pub fn paths(&self) -> Vec { + pub fn path(&self) -> &String { match self { - PackageSymbol::Module(m) => vec![m.path.clone()], - PackageSymbol::PythonPackage(p) => vec![p.path.clone()], + PackageSymbol::Module(m) => &m.path, + PackageSymbol::PythonPackage(p) => &p.path, } } pub fn is_external(&self) -> bool { diff --git a/server/src/core/symbols/symbol.rs b/server/src/core/symbols/symbol.rs index 2434f33d..bfc4a227 100644 --- a/server/src/core/symbols/symbol.rs +++ b/server/src/core/symbols/symbol.rs @@ -847,7 +847,7 @@ impl Symbol { Symbol::Root(_) => vec![], Symbol::Namespace(n) => n.paths(), Symbol::DiskDir(d) => vec![d.path.clone()], - Symbol::Package(p) => p.paths(), + Symbol::Package(p) => vec![p.path().clone()], Symbol::File(f) => vec![f.path.clone()], Symbol::Compiled(c) => vec![c.path.clone()], Symbol::Class(_) => vec![], @@ -860,7 +860,7 @@ impl Symbol { pub fn get_symbol_first_path(&self) -> String{ match self{ - Symbol::Package(p) => PathBuf::from(p.paths()[0].clone()).join("__init__.py").sanitize() + p.i_ext().as_str(), + Symbol::Package(p) => PathBuf::from(p.path().clone()).join("__init__.py").sanitize() + p.i_ext().as_str(), Symbol::File(f) => f.path.clone(), Symbol::DiskDir(_) => panic!("invalid symbol type to extract path"), Symbol::Root(_) => panic!("invalid symbol type to extract path"), From 77d6151086c642470df272624b722d5a9b7e0ed0 Mon Sep 17 00:00:00 2001 From: Rodolpho Lima Date: Fri, 21 Nov 2025 13:08:10 +0100 Subject: [PATCH 5/5] [REF] symbol path handling with SymbolPath enum This commit replaces the Vec return type in Symbol::paths() (now renamed to path) with a new SymbolPath enum that explicitly represents three cases: Single path, Multiple paths, or None. The purpose of this change is to force the caller handle the different cases explicitly, rather than doing [0] on the vector previously returned by paths(). This commit also renames get_symbol_first_path() to get_file_path() for clarity, as it only applies to file types (File, Package, XMLFile and CSVFile) and specifically returns the actual file path including __init__.py for packages. --- server/src/core/csv_arch_builder.rs | 2 +- server/src/core/entry_point.rs | 2 +- server/src/core/import_resolver.rs | 28 ++-- server/src/core/odoo.rs | 26 ++-- server/src/core/python_arch_builder.rs | 16 +- server/src/core/python_arch_builder_hooks.rs | 6 +- server/src/core/python_arch_eval.rs | 9 +- server/src/core/python_arch_eval_hooks.rs | 32 ++-- server/src/core/python_validator.rs | 13 +- server/src/core/symbols/module_symbol.rs | 6 +- server/src/core/symbols/namespace_symbol.rs | 12 +- server/src/core/symbols/symbol.rs | 71 ++++++--- server/src/core/xml_validation.rs | 2 +- server/src/features/definition.rs | 150 ++++++++----------- server/src/features/features_utils.rs | 2 +- server/src/features/references.rs | 38 ++--- server/src/features/workspace_symbols.rs | 23 ++- server/tests/test_get_symbol.rs | 4 +- 18 files changed, 229 insertions(+), 213 deletions(-) diff --git a/server/src/core/csv_arch_builder.rs b/server/src/core/csv_arch_builder.rs index 3b144528..3e8562a2 100644 --- a/server/src/core/csv_arch_builder.rs +++ b/server/src/core/csv_arch_builder.rs @@ -21,7 +21,7 @@ impl CsvArchBuilder { pub fn load_csv(&mut self, session: &mut SessionInfo, csv_symbol: Rc>, content: &String) -> Vec { let diagnostics = vec![]; csv_symbol.borrow_mut().set_build_status(BuildSteps::ARCH, BuildStatus::IN_PROGRESS); - let model_name_pb = PathBuf::from(&csv_symbol.borrow().paths()[0]); + let model_name_pb = PathBuf::from(&csv_symbol.borrow().path().to_single_string()); let model_name = Sy!(model_name_pb.file_stem().unwrap().to_str().unwrap().to_string()); let csv_module = csv_symbol.borrow().find_module(); let Some(csv_module) = &csv_module else { diff --git a/server/src/core/entry_point.rs b/server/src/core/entry_point.rs index 05625579..0b2b574c 100644 --- a/server/src/core/entry_point.rs +++ b/server/src/core/entry_point.rs @@ -203,7 +203,7 @@ impl EntryPointMgr { } else { // There was an __init__.py, that was renamed or deleted. // Another notification will come for the deletion of the file, so we just warn here. - warn_or_panic!("Trying to create a custom entrypoint on a namespace symbol: {:?}", new_sym.borrow().paths()); + warn_or_panic!("Trying to create a custom entrypoint on a namespace symbol: {:?}", new_sym.borrow().path().to_multiple_vec()); } return false; } diff --git a/server/src/core/import_resolver.rs b/server/src/core/import_resolver.rs index 6aad4290..8ec7f2ef 100644 --- a/server/src/core/import_resolver.rs +++ b/server/src/core/import_resolver.rs @@ -57,6 +57,9 @@ fn resolve_import_stmt_hook(alias: &Alias, from_symbol: &Option>, from_stmt:Option, name: &str, asname: Option, level: u32, diagnostics: &mut Option<&mut Vec>) -> Vec { + if source_file_symbol.borrow().path().to_vec().len() > 1 { + panic!("Importing from a multi-path namespace symbol is not supported in manual_import"); + } let name_aliases = vec![Alias { name: Identifier { id: Name::new(name), range: TextRange::new(TextSize::new(0), TextSize::new(0)), node_index: AtomicNodeIndex::default() }, asname: match asname { @@ -82,7 +85,8 @@ pub fn resolve_from_stmt(session: &mut SessionInfo, source_file_symbol: &Rc = vec![name_split.last().unwrap().clone()]; let (mut next_symbol, mut fallback_sym) = _get_or_create_symbol( session, @@ -223,7 +228,7 @@ pub fn resolve_import_stmt(session: &mut SessionInfo, source_file_symbol: &Rc>, name: &OYarn) -> Option>> { - let paths = (*odoo_addons).borrow().paths().clone(); + let paths = (*odoo_addons).borrow().path().to_vec(); for path in paths.iter() { let full_path = Path::new(path.as_str()).join(name.as_str()); if !is_dir_cs(full_path.sanitize()) { @@ -243,7 +248,7 @@ fn _resolve_packages(from_file: &Symbol, level: u32, from_stmt: Option<&Identifi let mut first_part_tree: Vec = vec![]; if level > 0 { let mut lvl = level; - if lvl > Path::new(&from_file.paths()[0]).components().count() as u32 { + if lvl > Path::new(&from_file.path().to_single_string()).components().count() as u32 { panic!("Level is too high!") } if matches!(from_file.typ(), SymType::PACKAGE(_)) { @@ -390,7 +395,7 @@ fn _resolve_new_symbol(session: &mut SessionInfo, parent: Rc>, n if (*parent).borrow().typ() == SymType::COMPILED { return Ok((*parent).borrow_mut().add_new_compiled(session, &sym_name, &S!(""))); } - let paths = (*parent).borrow().paths().clone(); + let paths = (*parent).borrow().path().to_vec(); for path in paths.iter() { let mut full_path = Path::new(path.as_str()).join(name.to_string()); for stub in session.sync_odoo.stubs_dirs.iter() { @@ -477,7 +482,7 @@ pub fn get_all_valid_names(session: &mut SessionInfo, source_file_symbol: &Rc { - for path in symbol.borrow().paths().iter() { + SymType::NAMESPACE => { + for path in symbol.borrow().path().to_multiple_vec().iter() { res.extend(valid_name_from_disk(path, start_filter)); } }, + SymType::DISK_DIR => { + res.extend(valid_name_from_disk(&symbol.borrow().path().to_single_string(), start_filter)); + } SymType::PACKAGE(_) => { - for path in symbol.borrow().paths().iter() { - res.extend(valid_name_from_disk(path, start_filter)); - } + res.extend(valid_name_from_disk(&symbol.borrow().path().to_single_string(), start_filter)); if only_on_disk { return res; } diff --git a/server/src/core/odoo.rs b/server/src/core/odoo.rs index 408a6355..94a8a4b8 100644 --- a/server/src/core/odoo.rs +++ b/server/src/core/odoo.rs @@ -1,6 +1,7 @@ use crate::core::diagnostics::{create_diagnostic, DiagnosticCode}; use crate::core::entry_point::EntryPointType; use crate::core::file_mgr::AstType; +use crate::core::symbols::symbol::SymbolPath; use crate::core::xml_data::OdooData; use crate::core::xml_validation::XmlValidator; use crate::features::document_symbols::DocumentSymbolFeature; @@ -472,8 +473,10 @@ impl SyncOdoo { fn build_modules(session: &mut SessionInfo) { { let addons_symbol = session.sync_odoo.get_symbol(session.sync_odoo.config.odoo_path.as_ref().unwrap(), &tree(vec!["odoo", "addons"], vec![]), u32::MAX)[0].clone(); - let addons_path = addons_symbol.borrow().paths().clone(); - for addon_path in addons_path.iter() { + let SymbolPath::Multiple(addons_paths) = addons_symbol.borrow().path() else { + panic!("Odoo addons symbol paths should be a namespace"); + }; + for addon_path in addons_paths.iter() { info!("searching modules in {}", addon_path); if PathBuf::from(addon_path).exists() { //browse all dir in path @@ -760,7 +763,7 @@ impl SyncOdoo { pub fn add_to_rebuild_arch(&mut self, symbol: Rc>) { if DEBUG_THREADS { - trace!("ADDED TO ARCH - {}", symbol.borrow().paths().first().unwrap_or(&symbol.borrow().name().to_string())); + trace!("ADDED TO ARCH - {} - {:?}", symbol.borrow().name(), symbol.borrow().path()); } if symbol.borrow().build_status(BuildSteps::ARCH) != BuildStatus::IN_PROGRESS { let sym_clone = symbol.clone(); @@ -774,7 +777,7 @@ impl SyncOdoo { pub fn add_to_rebuild_arch_eval(&mut self, symbol: Rc>) { if DEBUG_THREADS { - trace!("ADDED TO EVAL - {}", symbol.borrow().paths().first().unwrap_or(&symbol.borrow().name().to_string())); + trace!("ADDED TO EVAL - {} - {:?}", symbol.borrow().name(), symbol.borrow().path()); } if symbol.borrow().build_status(BuildSteps::ARCH_EVAL) != BuildStatus::IN_PROGRESS { let sym_clone = symbol.clone(); @@ -787,7 +790,7 @@ impl SyncOdoo { pub fn add_to_validations(&mut self, symbol: Rc>) { if DEBUG_THREADS { - trace!("ADDED TO VALIDATION - {}", symbol.borrow().paths().first().unwrap_or(&symbol.borrow().name().to_string())); + trace!("ADDED TO VALIDATION - {} - {:?}", symbol.borrow().name(), symbol.borrow().path()); } if symbol.borrow().build_status(BuildSteps::VALIDATION) != BuildStatus::IN_PROGRESS { symbol.borrow_mut().set_build_status(BuildSteps::VALIDATION, BuildStatus::PENDING); @@ -809,10 +812,10 @@ impl SyncOdoo { } if DEBUG_REBUILD_NOW { if symbol.borrow().build_status(step) == BuildStatus::INVALID { - panic!("Trying to build an invalid symbol: {}", symbol.borrow().paths().first().unwrap_or(&symbol.borrow().name().to_string())); + panic!("Trying to build an invalid symbol: {} - {:?}", symbol.borrow().name(), symbol.borrow().path()); } if symbol.borrow().build_status(step) == BuildStatus::IN_PROGRESS && !session.sync_odoo.is_in_rebuild(&symbol, step) { - error!("Trying to build a symbol that is NOT in the queue: {}", symbol.borrow().paths().first().unwrap_or(&symbol.borrow().name().to_string())); + error!("Trying to build a symbol that is NOT in the queue: {} - {:?}", symbol.borrow().name(), symbol.borrow().path()); } } if symbol.borrow().build_status(step) == BuildStatus::PENDING && symbol.borrow().previous_step_done(step) { @@ -826,7 +829,7 @@ impl SyncOdoo { } else if step == BuildSteps::ARCH_EVAL { if DEBUG_REBUILD_NOW { if symbol.borrow().build_status(BuildSteps::ARCH) != BuildStatus::DONE { - panic!("An evaluation has been requested on a non-arched symbol: {}", symbol.borrow().paths().first().unwrap_or(&symbol.borrow().name().to_string())); + panic!("An evaluation has been requested on a non-arched symbol: {} - {:?}", symbol.borrow().name(), symbol.borrow().path()); } } let mut builder = PythonArchEval::new(entry_point, symbol.clone()); @@ -835,7 +838,7 @@ impl SyncOdoo { } else if step == BuildSteps::VALIDATION { if DEBUG_REBUILD_NOW { if symbol.borrow().build_status(BuildSteps::ARCH) != BuildStatus::DONE || symbol.borrow().build_status(BuildSteps::ARCH_EVAL) != BuildStatus::DONE { - panic!("An evaluation has been requested on a non-arched symbol: {}", symbol.borrow().paths().first().unwrap_or(&symbol.borrow().name().to_string())); + panic!("An evaluation has been requested on a non-arched symbol: {} - {:?}", symbol.borrow().name(), symbol.borrow().path()); } } let mut validator = PythonValidator::new(entry_point, symbol.clone()); @@ -951,7 +954,10 @@ impl SyncOdoo { let mut to_del = Vec::from_iter(path_symbol.borrow().all_module_symbol().map(|x| x.clone())); let mut index = 0; while index < to_del.len() { - FileMgr::delete_path(session, &to_del[index].borrow().paths()[0]); + match to_del[index].borrow().path() { + SymbolPath::Single(p) => FileMgr::delete_path(session, &p), + SymbolPath::Multiple(_) | SymbolPath::None => {} + } let mut to_del_child = Vec::from_iter(to_del[index].borrow().all_module_symbol().map(|x| x.clone())); to_del.append(&mut to_del_child); index += 1; diff --git a/server/src/core/python_arch_builder.rs b/server/src/core/python_arch_builder.rs index 98e9bc46..0302c2c4 100644 --- a/server/src/core/python_arch_builder.rs +++ b/server/src/core/python_arch_builder.rs @@ -68,10 +68,10 @@ impl PythonArchBuilder { self.current_step = if self.file_mode {BuildSteps::ARCH} else {BuildSteps::VALIDATION}; } if DEBUG_STEPS && (!DEBUG_STEPS_ONLY_INTERNAL || !symbol.borrow().is_external()) { - trace!("building {} - {}", self.file.borrow().paths().first().unwrap_or(&S!("No path found")), symbol.borrow().name()); + trace!("building {} - {}", self.file.borrow().path().to_single_string(), symbol.borrow().name()); } symbol.borrow_mut().set_build_status(BuildSteps::ARCH, BuildStatus::IN_PROGRESS); - let path = self.file.borrow().get_symbol_first_path(); + let path = self.file.borrow().get_file_path(); if self.file_mode { let in_workspace = (self.file.borrow().parent().is_some() && self.file.borrow().parent().as_ref().unwrap().upgrade().is_some() && @@ -194,24 +194,24 @@ impl PythonArchBuilder { if value.is_some() { let (nf, parse_error) = self.extract_all_symbol_eval_values(&value.as_ref()); if parse_error { - warn!("error during parsing __all__ import in file {}", (*import_result.symbol).borrow().paths()[0] ) + warn!("error during parsing __all__ import in file {}", (*import_result.symbol).borrow().path().to_single_string()) } name_filter = nf; all_name_allowed = false; } else { - warn!("invalid __all__ import in file {} - no value found", (*import_result.symbol).borrow().paths()[0]) + warn!("invalid __all__ import in file {} - no value found", (*import_result.symbol).borrow().path().to_single_string()) } } else { - warn!("invalid __all__ import in file {} - multiple evaluation found", (*import_result.symbol).borrow().paths()[0]) + warn!("invalid __all__ import in file {} - multiple evaluation found", (*import_result.symbol).borrow().path().to_single_string()) } } else { - warn!("invalid __all__ import in file {} - localizedSymbol not found", (*import_result.symbol).borrow().paths()[0]) + warn!("invalid __all__ import in file {} - localizedSymbol not found", (*import_result.symbol).borrow().path().to_single_string()) } } else { - warn!("invalid __all__ import in file {} - expired symbol", (*import_result.symbol).borrow().paths()[0]) + warn!("invalid __all__ import in file {} - expired symbol", (*import_result.symbol).borrow().path().to_single_string()) } } else { - warn!("invalid __all__ import in file {} - no symbol found", (*import_result.symbol).borrow().paths()[0]) + warn!("invalid __all__ import in file {} - no symbol found", (*import_result.symbol).borrow().path().to_single_string()) } } let mut dep_to_add = vec![]; diff --git a/server/src/core/python_arch_builder_hooks.rs b/server/src/core/python_arch_builder_hooks.rs index 77a95304..7f98fd6c 100644 --- a/server/src/core/python_arch_builder_hooks.rs +++ b/server/src/core/python_arch_builder_hooks.rs @@ -177,7 +177,7 @@ impl PythonArchBuilderHooks { let name = symbol.borrow().name().clone(); if name == "release" { if symbol.borrow().get_main_entry_tree(session) == (vec![Sy!("odoo"), Sy!("release")], vec![]) { - let (maj, min, mic) = SyncOdoo::read_version(session, PathBuf::from(symbol.borrow().paths()[0].clone())); + let (maj, min, mic) = SyncOdoo::read_version(session, PathBuf::from(symbol.borrow().path().to_single_string())); if maj != session.sync_odoo.version_major || min != session.sync_odoo.version_minor || mic != session.sync_odoo.version_micro { session.sync_odoo.need_rebuild = true; } @@ -185,7 +185,7 @@ impl PythonArchBuilderHooks { } else if name == "init" { if compare_semver(session.sync_odoo.full_version.as_str(), "18.1") != Ordering::Less { if symbol.borrow().get_main_entry_tree(session) == (vec![Sy!("odoo"), Sy!("init")], vec![]) { - let odoo_namespace = session.sync_odoo.get_symbol(symbol.borrow().paths()[0].as_str(), &(vec![Sy!("odoo")], vec![]), u32::MAX); + let odoo_namespace = session.sync_odoo.get_symbol(&symbol.borrow().path().to_single_string(), &(vec![Sy!("odoo")], vec![]), u32::MAX); if let Some(odoo_namespace) = odoo_namespace.get(0) { // create _ and Command as ext_symbols let owner = symbol.clone(); @@ -199,7 +199,7 @@ impl PythonArchBuilderHooks { } else if name == "werkzeug" { if symbol.borrow().get_main_entry_tree(session) == (vec![Sy!("odoo"), Sy!("_monkeypatches"), Sy!("werkzeug")], vec![]) { //doing this patch like this imply that an odoo project will make these functions available for all entrypoints, but heh - let werkzeug_url = session.sync_odoo.get_symbol(symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![]), u32::MAX); + let werkzeug_url = session.sync_odoo.get_symbol(&symbol.borrow().path().to_single_string(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![]), u32::MAX); if let Some(werkzeug_url) = werkzeug_url.first() { let url_join = werkzeug_url.borrow().get_symbol(&(vec![], vec![Sy!("url_join")]), u32::MAX); if url_join.is_empty() { //else, installed version is already patched diff --git a/server/src/core/python_arch_eval.rs b/server/src/core/python_arch_eval.rs index b1e35339..551a3918 100644 --- a/server/src/core/python_arch_eval.rs +++ b/server/src/core/python_arch_eval.rs @@ -72,13 +72,10 @@ impl PythonArchEval { self.current_step = if self.file_mode {BuildSteps::ARCH_EVAL} else {BuildSteps::VALIDATION}; } if DEBUG_STEPS && (!DEBUG_STEPS_ONLY_INTERNAL || !symbol.borrow().is_external()) { - trace!("evaluating {} - {}", self.file.borrow().paths().first().unwrap_or(&S!("No path found")), symbol.borrow().name()); + trace!("evaluating {} - {}", self.file.borrow().path().to_single_string(), symbol.borrow().name()); } symbol.borrow_mut().set_build_status(BuildSteps::ARCH_EVAL, BuildStatus::IN_PROGRESS); - if self.file.borrow().paths().len() != 1 { - panic!("Trying to eval_arch a symbol without any path") - } - let path = self.file.borrow().get_symbol_first_path(); + let path = self.file.borrow().get_file_path(); let Some(file_info_rc) = session.sync_odoo.get_file_mgr().borrow().get_file_info(&path).clone() else { warn!("File info not found for {}", path); return; @@ -515,7 +512,7 @@ impl PythonArchEval { if let Some(sym) = evaluation.symbol.get_symbol_as_weak(session, &mut None, &mut self.diagnostics, None).weak.upgrade() { if Rc::ptr_eq(&sym, &variable_rc){ // TODO: investigate deps, and fix cyclic evals - let file_path = parent.borrow().get_file().and_then(|file| file.upgrade()).and_then(|file| file.borrow().paths().first().cloned()); + let file_path = parent.borrow().get_file().and_then(|file| file.upgrade()).and_then(|file| Some(file.borrow().path().to_single_string())); warn!("Found cyclic evaluation symbol: {}, parent: {}, file: {}", var_name, parent.borrow().name(), file_path.unwrap_or(S!("N/A"))); evaluations.remove(ix); continue; diff --git a/server/src/core/python_arch_eval_hooks.rs b/server/src/core/python_arch_eval_hooks.rs index 44c69c38..0cde19b4 100644 --- a/server/src/core/python_arch_eval_hooks.rs +++ b/server/src/core/python_arch_eval_hooks.rs @@ -258,7 +258,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v trees: vec![(Sy!("18.1"), Sy!("999.0"), (vec![Sy!("odoo"), Sy!("init")], vec![Sy!("_")]))], if_exist_only: true, func: |odoo: &mut SessionInfo, _entry: &Rc>, _file_symbol: Rc>, symbol: Rc>| { - let odoo_underscore = odoo.sync_odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("odoo")], vec![Sy!("_")]), u32::MAX); + let odoo_underscore = odoo.sync_odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("odoo")], vec![Sy!("_")]), u32::MAX); if let Some(eval_1) = odoo_underscore.first() { eval_1.borrow_mut().set_evaluations(vec![Evaluation::eval_from_symbol(&Rc::downgrade(&symbol), Some(false))]); } @@ -267,7 +267,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v trees: vec![(Sy!("18.1"), Sy!("999.0"), (vec![Sy!("odoo"), Sy!("init")], vec![Sy!("SUPERUSER_ID")]))], if_exist_only: true, func: |odoo: &mut SessionInfo, _entry: &Rc>, _file_symbol: Rc>, symbol: Rc>| { - let odoo_superuser_id = odoo.sync_odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("odoo")], vec![Sy!("SUPERUSER_ID")]), u32::MAX); + let odoo_superuser_id = odoo.sync_odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("odoo")], vec![Sy!("SUPERUSER_ID")]), u32::MAX); if let Some(eval_1) = odoo_superuser_id.first() { eval_1.borrow_mut().set_evaluations(vec![Evaluation::eval_from_symbol(&Rc::downgrade(&symbol), Some(false))]); } @@ -276,7 +276,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v trees: vec![(Sy!("18.1"), Sy!("999.0"), (vec![Sy!("odoo"), Sy!("init")], vec![Sy!("_lt")]))], if_exist_only: true, func: |odoo: &mut SessionInfo, _entry: &Rc>, _file_symbol: Rc>, symbol: Rc>| { - let odoo_lt = odoo.sync_odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("odoo")], vec![Sy!("_lt")]), u32::MAX); + let odoo_lt = odoo.sync_odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("odoo")], vec![Sy!("_lt")]), u32::MAX); if let Some(eval_1) = odoo_lt.first() { eval_1.borrow_mut().set_evaluations(vec![Evaluation::eval_from_symbol(&Rc::downgrade(&symbol), Some(false))]); } @@ -285,7 +285,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v trees: vec![(Sy!("18.1"), Sy!("999.0"), (vec![Sy!("odoo"), Sy!("init")], vec![Sy!("Command")]))], if_exist_only: true, func: |odoo: &mut SessionInfo, _entry: &Rc>, _file_symbol: Rc>, symbol: Rc>| { - let odoo_command = odoo.sync_odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("odoo")], vec![Sy!("Command")]), u32::MAX); + let odoo_command = odoo.sync_odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("odoo")], vec![Sy!("Command")]), u32::MAX); if let Some(eval_1) = odoo_command.first() { eval_1.borrow_mut().set_evaluations(vec![Evaluation::eval_from_symbol(&Rc::downgrade(&symbol), Some(false))]); } @@ -294,9 +294,9 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v trees: vec![(Sy!("15.0"), Sy!("999.0"), (vec![Sy!("odoo"), Sy!("addons"), Sy!("base"), Sy!("models"), Sy!("ir_rule")], vec![Sy!("IrRule"), Sy!("global")]))], if_exist_only: true, func: |odoo: &mut SessionInfo, _entry: &Rc>, _file_symbol: Rc>, symbol: Rc>| { - let mut boolean_field = odoo.sync_odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("odoo"), Sy!("fields")], vec![Sy!("Boolean")]), u32::MAX); + let mut boolean_field = odoo.sync_odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("odoo"), Sy!("fields")], vec![Sy!("Boolean")]), u32::MAX); if compare_semver(odoo.sync_odoo.full_version.as_str(), "18.1") >= Ordering::Equal { - boolean_field = odoo.sync_odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("odoo"), Sy!("orm"), Sy!("fields_misc")], vec![Sy!("Boolean")]), u32::MAX); + boolean_field = odoo.sync_odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("odoo"), Sy!("orm"), Sy!("fields_misc")], vec![Sy!("Boolean")]), u32::MAX); } if let Some(boolean) = boolean_field.first() { let mut eval = Evaluation::eval_from_symbol(&Rc::downgrade(&boolean), Some(true)); @@ -311,7 +311,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v func: |session: &mut SessionInfo, _entry: &Rc>, _file_symbol: Rc>, symbol: Rc>| { let odoo = &mut session.sync_odoo; let url_decode = symbol.borrow().get_symbol(&(vec![], vec![Sy!("url_decode")]), u32::MAX); - let werkzeug_url_decode = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_decode")]), u32::MAX); + let werkzeug_url_decode = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_decode")]), u32::MAX); if let Some(werkzeug_url_decode) = werkzeug_url_decode.first() { if werkzeug_url_decode.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url_decode.first() { @@ -322,7 +322,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v } } let url_encode = symbol.borrow().get_symbol(&(vec![], vec![Sy!("url_encode")]), u32::MAX); - let werkzeug_url_encode = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_encode")]), u32::MAX); + let werkzeug_url_encode = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_encode")]), u32::MAX); if let Some(werkzeug_url_encode) = werkzeug_url_encode.first() { if werkzeug_url_encode.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url_encode.first() { @@ -333,7 +333,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v } } let url_join = symbol.borrow().get_symbol(&(vec![], vec![Sy!("url_join")]), u32::MAX); - let werkzeug_url_join = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_join")]), u32::MAX); + let werkzeug_url_join = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_join")]), u32::MAX); if let Some(werkzeug_url_join) = werkzeug_url_join.first() { if werkzeug_url_join.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url_join.first() { @@ -344,7 +344,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v } } let url_parse = symbol.borrow().get_symbol(&(vec![], vec![Sy!("url_parse")]), u32::MAX); - let werkzeug_url_parse = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_parse")]), u32::MAX); + let werkzeug_url_parse = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_parse")]), u32::MAX); if let Some(werkzeug_url_parse) = werkzeug_url_parse.first() { if werkzeug_url_parse.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url_parse.first() { @@ -355,7 +355,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v } } let url_quote = symbol.borrow().get_symbol(&(vec![], vec![Sy!("url_quote")]), u32::MAX); - let werkzeug_url_quote = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_quote")]), u32::MAX); + let werkzeug_url_quote = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_quote")]), u32::MAX); if let Some(werkzeug_url_quote) = werkzeug_url_quote.first() { if werkzeug_url_quote.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url_quote.first() { @@ -366,7 +366,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v } } let url_unquote = symbol.borrow().get_symbol(&(vec![], vec![Sy!("url_unquote")]), u32::MAX); - let werkzeug_url_unquote = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_unquote")]), u32::MAX); + let werkzeug_url_unquote = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_unquote")]), u32::MAX); if let Some(werkzeug_url_unquote) = werkzeug_url_unquote.first() { if werkzeug_url_unquote.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url_unquote.first() { @@ -377,7 +377,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v } } let url_quote_plus = symbol.borrow().get_symbol(&(vec![], vec![Sy!("url_quote_plus")]), u32::MAX); - let werkzeug_url_quote_plus = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_quote_plus")]), u32::MAX); + let werkzeug_url_quote_plus = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_quote_plus")]), u32::MAX); if let Some(werkzeug_url_quote_plus) = werkzeug_url_quote_plus.first() { if werkzeug_url_quote_plus.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url_quote_plus.first() { @@ -388,7 +388,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v } } let url_unquote_plus = symbol.borrow().get_symbol(&(vec![], vec![Sy!("url_unquote_plus")]), u32::MAX); - let werkzeug_url_unquote_plus = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_unquote_plus")]), u32::MAX); + let werkzeug_url_unquote_plus = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_unquote_plus")]), u32::MAX); if let Some(werkzeug_url_unquote_plus) = werkzeug_url_unquote_plus.first() { if werkzeug_url_unquote_plus.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url_unquote_plus.first() { @@ -399,7 +399,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v } } let url_unparse = symbol.borrow().get_symbol(&(vec![], vec![Sy!("url_unparse")]), u32::MAX); - let werkzeug_url_unparse = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_unparse")]), u32::MAX); + let werkzeug_url_unparse = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("url_unparse")]), u32::MAX); if let Some(werkzeug_url_unparse) = werkzeug_url_unparse.first() { if werkzeug_url_unparse.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url_unparse.first() { @@ -410,7 +410,7 @@ static arch_eval_file_hooks: Lazy> = Lazy::new(|| {v } } let url = symbol.borrow().get_symbol(&(vec![], vec![Sy!("URL")]), u32::MAX); - let werkzeug_url_syms = odoo.get_symbol(_file_symbol.borrow().paths()[0].as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("URL")]), u32::MAX); + let werkzeug_url_syms = odoo.get_symbol(_file_symbol.borrow().path().to_single_string().as_str(), &(vec![Sy!("werkzeug"), Sy!("urls")], vec![Sy!("URL")]), u32::MAX); if let Some(werkzeug_url) = werkzeug_url_syms.first() { if werkzeug_url.borrow().typ() == SymType::VARIABLE { //if not variable, no need to patch it if let Some(eval_1) = url.first() { diff --git a/server/src/core/python_validator.rs b/server/src/core/python_validator.rs index 80373bf0..acb50b6f 100644 --- a/server/src/core/python_validator.rs +++ b/server/src/core/python_validator.rs @@ -51,17 +51,14 @@ impl PythonValidator { fn get_file_info(&mut self, session: &mut SessionInfo) -> Option>> { let file_symbol = self.file.borrow(); - let mut path = file_symbol.paths()[0].clone(); - if matches!(file_symbol.typ(), SymType::PACKAGE(_)) { - path = PathBuf::from(path).join("__init__.py").sanitize() + file_symbol.as_package().i_ext().as_str(); - } + let path = file_symbol.get_file_path(); let file_info_rc = session.sync_odoo.get_file_mgr().borrow().get_file_info(&path); let file_info_rc = match file_info_rc { Some(f) => f, None => { - let (updated, symbol) = session.sync_odoo.get_file_mgr().borrow_mut().update_file_info(session, &file_symbol.paths()[0], None, Some(-100), true); + let (updated, symbol) = session.sync_odoo.get_file_mgr().borrow_mut().update_file_info(session, &file_symbol.path().to_single_string(), None, Some(-100), true); if !updated { - warn!("File info not found for validating symbol: {} at path {}", self.sym_stack[0].borrow().name(), file_symbol.paths()[0]); + warn!("File info not found for validating symbol: {} at path {}", self.sym_stack[0].borrow().name(), file_symbol.path().to_single_string()); return None; } symbol @@ -95,7 +92,7 @@ impl PythonValidator { return; } if DEBUG_STEPS && (!DEBUG_STEPS_ONLY_INTERNAL || !self.sym_stack[0].borrow().is_external()) { - trace!("Validating {}", self.sym_stack[0].borrow().paths().first().unwrap_or(&S!("No path found"))); + trace!("Validating {}", self.sym_stack[0].borrow().path().to_single_string()); } self.sym_stack[0].borrow_mut().set_build_status(BuildSteps::VALIDATION, BuildStatus::IN_PROGRESS); file_info_rc.borrow_mut().replace_diagnostics(BuildSteps::VALIDATION, vec![]); @@ -187,7 +184,7 @@ impl PythonValidator { if !symbol.is_external() { return } - FileMgr::delete_path(session, &symbol.paths()[0].to_string()); + FileMgr::delete_path(session, &symbol.path().to_single_string()); } else { self.file_info.as_ref().unwrap().borrow_mut().publish_diagnostics(session); } diff --git a/server/src/core/symbols/module_symbol.rs b/server/src/core/symbols/module_symbol.rs index fc27e0d6..a4eaa906 100644 --- a/server/src/core/symbols/module_symbol.rs +++ b/server/src/core/symbols/module_symbol.rs @@ -343,7 +343,7 @@ impl ModuleSymbol { let data_paths = symbol.borrow().as_module_package().data.clone(); for (data_url, data_range) in data_paths.iter() { //check if the file exists - let path = PathBuf::from(symbol.borrow().paths()[0].clone()).join(data_url); + let path = PathBuf::from(symbol.borrow().path().to_single_string()).join(data_url); if !path.exists() { symbol.borrow_mut().as_module_package_mut().not_found_data.insert(path.sanitize(), BuildSteps::ARCH); symbol.borrow().get_entry().unwrap().borrow_mut().not_found_symbols.insert(symbol.clone()); @@ -370,7 +370,7 @@ impl ModuleSymbol { let mut diagnostics = vec![]; for (data_url, data_range) in data_paths.iter() { // validate csv file names, check that their models exist - let path = PathBuf::from(symbol.borrow().paths()[0].clone()).join(data_url); + let path = PathBuf::from(symbol.borrow().path().to_single_string()).join(data_url); if path.extension().unwrap_or_default() != "csv" || !path.exists(){ continue; } @@ -401,7 +401,7 @@ impl ModuleSymbol { let data_paths = symbol.borrow().as_module_package().data.clone(); for (data_url, _data_range) in data_paths.iter() { //load data from file - let path = PathBuf::from(symbol.borrow().paths()[0].clone()).join(data_url); + let path = PathBuf::from(symbol.borrow().path().to_single_string()).join(data_url); let (_, file_info) = session.sync_odoo.get_file_mgr().borrow_mut().update_file_info(session, &path.sanitize(), None, None, false); //create ast if not in cache let mut file_info = file_info.borrow_mut(); let file_name = path.file_name().unwrap().to_str().unwrap().to_string(); diff --git a/server/src/core/symbols/namespace_symbol.rs b/server/src/core/symbols/namespace_symbol.rs index 9582361d..262680da 100644 --- a/server/src/core/symbols/namespace_symbol.rs +++ b/server/src/core/symbols/namespace_symbol.rs @@ -2,7 +2,7 @@ use weak_table::PtrWeakHashSet; use std::{cell::RefCell, collections::HashMap, path::PathBuf, rc::{Rc, Weak}}; -use crate::constants::OYarn; +use crate::{constants::OYarn, core::symbols::symbol::SymbolPath}; use super::symbol::Symbol; @@ -53,15 +53,21 @@ impl NamespaceSymbol { let mut best_index: i32 = -1; let mut best_length: i32 = -1; let mut index = 0; + let path = match file.borrow().path() { + SymbolPath::Single(p) => p, + SymbolPath::Multiple(paths) => paths[0].clone(), + SymbolPath::None => panic!("Trying to add a file with no path to namespace {}", self.name), + }; + let path_buf = PathBuf::from(&path); while index < self.directories.len() { - if PathBuf::from(&file.borrow().paths()[0]).starts_with(&self.directories[index].path) && self.directories[index].path.len() as i32 > best_length { + if path_buf.starts_with(&self.directories[index].path) && self.directories[index].path.len() as i32 > best_length { best_index = index as i32; best_length = self.directories[index].path.len() as i32; } index += 1; } if best_index == -1 { - panic!("Not valid path found to add the file ({}) to namespace {} with directories {:?}", file.borrow().paths()[0], self.name, self.directories); + panic!("Not valid path found to add the file ({}) to namespace {} with directories {:?}", path, self.name, self.directories); } else { self.directories[best_index as usize].module_symbols.insert(file.borrow().name().clone(), file.clone()); } diff --git a/server/src/core/symbols/symbol.rs b/server/src/core/symbols/symbol.rs index bfc4a227..b0719e5c 100644 --- a/server/src/core/symbols/symbol.rs +++ b/server/src/core/symbols/symbol.rs @@ -54,6 +54,13 @@ pub enum Symbol { CsvFileSymbol(CsvFileSymbol), } +#[derive(Debug)] +pub enum SymbolPath { + Single(String), + Multiple(Vec), + None, +} + impl Symbol { /// Checks if weak references of symbol are equal /// Attempts to upgrade both (false upon failure) and does pointer equality @@ -842,23 +849,21 @@ impl Symbol { } } - pub fn paths(&self) -> Vec { + pub fn path(&self) -> SymbolPath { match self { - Symbol::Root(_) => vec![], - Symbol::Namespace(n) => n.paths(), - Symbol::DiskDir(d) => vec![d.path.clone()], - Symbol::Package(p) => vec![p.path().clone()], - Symbol::File(f) => vec![f.path.clone()], - Symbol::Compiled(c) => vec![c.path.clone()], - Symbol::Class(_) => vec![], - Symbol::Function(_) => vec![], - Symbol::Variable(_) => vec![], - Symbol::XmlFileSymbol(x) => vec![x.path.clone()], - Symbol::CsvFileSymbol(c) => vec![c.path.clone()], + Self::Root(_) => SymbolPath::None, + Self::Namespace(n) => SymbolPath::Multiple(n.paths()), + Self::DiskDir(d) => SymbolPath::Single(d.path.clone()), + Self::Package(p) => SymbolPath::Single(p.path().clone()), + Self::File(f) => SymbolPath::Single(f.path.clone()), + Self::Compiled(c) => SymbolPath::Single(c.path.clone()), + Self::XmlFileSymbol(x) => SymbolPath::Single(x.path.clone()), + Self::CsvFileSymbol(c) => SymbolPath::Single(c.path.clone()), + Self::Class(_) | Self::Function(_) | Self::Variable(_) => SymbolPath::None, } } - pub fn get_symbol_first_path(&self) -> String{ + pub fn get_file_path(&self) -> String{ match self{ Symbol::Package(p) => PathBuf::from(p.path().clone()).join("__init__.py").sanitize() + p.i_ext().as_str(), Symbol::File(f) => f.path.clone(), @@ -1779,7 +1784,7 @@ impl Symbol { } vec_to_unload.pop_front(); if DEBUG_MEMORY && (sym_ref.typ() == SymType::FILE || matches!(sym_ref.typ(), SymType::PACKAGE(_))) { - info!("Unloading symbol {:?} at {:?}", sym_ref.name(), sym_ref.paths()); + info!("Unloading symbol {:?} at {:?}", sym_ref.name(), sym_ref.path()); } let module = sym_ref.find_module(); //unload symbol @@ -1795,12 +1800,12 @@ impl Symbol { match ref_to_unload.borrow().typ() { SymType::PACKAGE(PackageType::PYTHON_PACKAGE) => { if ref_to_unload.borrow().as_python_package().self_import { - session.sync_odoo.must_reload_paths.push((Rc::downgrade(&parent), ref_to_unload.borrow().paths().first().unwrap().clone())); + session.sync_odoo.must_reload_paths.push((Rc::downgrade(&parent), ref_to_unload.borrow().path().to_single_string())); } }, SymType::FILE => { if ref_to_unload.borrow().as_file().self_import { - session.sync_odoo.must_reload_paths.push((Rc::downgrade(&parent), ref_to_unload.borrow().paths().first().unwrap().clone())); + session.sync_odoo.must_reload_paths.push((Rc::downgrade(&parent), ref_to_unload.borrow().path().to_single_string())); } } _ => {} @@ -2034,7 +2039,7 @@ impl Symbol { Symbol::DiskDir(d) => { d.module_symbols.remove(symbol.borrow().name()); }, Symbol::Package(PackageSymbol::Module(m)) => { if symbol.borrow().typ() == SymType::XML_FILE || symbol.borrow().typ() == SymType::CSV_FILE { - m.data_symbols.remove(symbol.borrow().paths()[0].as_str()); + m.data_symbols.remove(&symbol.borrow().path().to_single_string()); } else { m.module_symbols.remove(symbol.borrow().name()); } @@ -3174,3 +3179,35 @@ impl Symbol { res }*/ } + +impl SymbolPath { + pub fn is_single(&self) -> bool { + matches!(self, Self::Single(_)) + } + + pub fn is_multiple(&self) -> bool { + matches!(self, Self::Multiple(_)) + } + + pub fn to_single_string(self) -> String { + match self { + Self::Single(s) => s, + _ => panic!("Not a Single"), + } + } + + pub fn to_multiple_vec(self) -> Vec { + match self { + Self::Multiple(v) => v, + _ => panic!("Not a Multiple"), + } + } + + pub fn to_vec(self) -> Vec { + match self { + Self::Single(s) => vec![s], + Self::Multiple(v) => v, + Self::None => vec![], + } + } +} diff --git a/server/src/core/xml_validation.rs b/server/src/core/xml_validation.rs index 31610ad9..ddb22fd8 100644 --- a/server/src/core/xml_validation.rs +++ b/server/src/core/xml_validation.rs @@ -24,7 +24,7 @@ impl XmlValidator { fn get_file_info(&mut self, odoo: &mut SyncOdoo) -> Rc> { let file_symbol = self.xml_symbol.borrow(); - let path = file_symbol.paths()[0].clone(); + let path = file_symbol.path().to_single_string(); let file_info_rc = odoo.get_file_mgr().borrow().get_file_info(&path).expect("File not found in cache").clone(); file_info_rc } diff --git a/server/src/features/definition.rs b/server/src/features/definition.rs index 6b6b8ea8..7f3243eb 100644 --- a/server/src/features/definition.rs +++ b/server/src/features/definition.rs @@ -38,10 +38,10 @@ impl DefinitionFeature { ); string_domain_fields.iter().for_each(|(field, field_range)|{ if let Some(file_sym) = field.borrow().get_file().and_then(|file_sym_weak| file_sym_weak.upgrade()){ - let path = file_sym.borrow().paths()[0].clone(); + let path = file_sym.borrow().path().to_single_string(); let range = session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &path, &field.borrow().range()); links.push(LocationLink{ - origin_selection_range: Some(session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, file_symbol.borrow().paths().first().as_ref().unwrap(), &field_range)), + origin_selection_range: Some(session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &file_symbol.borrow().path().to_single_string(), &field_range)), target_uri: FileMgr::pathname2uri(&path), target_selection_range: range, target_range: range, @@ -77,11 +77,11 @@ impl DefinitionFeature { } } if let Some(model_file_sym) = class_symbol.get_file().and_then(|model_file_sym_weak| model_file_sym_weak.upgrade()){ - let path = model_file_sym.borrow().get_symbol_first_path(); + let path = model_file_sym.borrow().get_file_path(); let range = session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &path, &class_symbol.range()); model_found = true; links.push(LocationLink{ - origin_selection_range: eval.range.map(|r| session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, file_symbol.borrow().paths().first().as_ref().unwrap(), &r)), + origin_selection_range: eval.range.map(|r| session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &file_symbol.borrow().path().to_single_string(), &r)), target_uri: FileMgr::pathname2uri(&path), target_selection_range: range, target_range: range, @@ -108,7 +108,7 @@ impl DefinitionFeature { let Some(module) = session.sync_odoo.modules.get(&oyarn!("{}", value)).and_then(|m| m.upgrade()) else { return false; }; - let path = PathBuf::from(module.borrow().paths()[0].clone()).join("__manifest__.py").sanitize(); + let path = PathBuf::from(module.borrow().path().to_single_string()).join("__manifest__.py").sanitize(); links.push(LocationLink{ origin_selection_range: None, target_uri: FileMgr::pathname2uri(&path), @@ -134,11 +134,11 @@ impl DefinitionFeature { let file = xml_id.get_file_symbol(); if let Some(file) = file { if let Some(file) = file.upgrade() { - let range = session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, &file.borrow().paths()[0], &xml_id.get_range()); + let range = session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, &file.borrow().path().to_single_string(), &xml_id.get_range()); xml_found = true; links.push(LocationLink { - origin_selection_range: eval.range.map(|r| session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, file_symbol.borrow().paths().first().as_ref().unwrap(), &r)), - target_uri: FileMgr::pathname2uri(&file.borrow().paths()[0]), + origin_selection_range: eval.range.map(|r| session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &file_symbol.borrow().path().to_single_string(), &r)), + target_uri: FileMgr::pathname2uri(&&file.borrow().path().to_single_string()), target_range: range, target_selection_range: range }); } @@ -163,10 +163,10 @@ impl DefinitionFeature { ); method_symbols.iter().for_each(|field|{ if let Some(file_sym) = field.borrow().get_file().and_then(|file_sym_weak| file_sym_weak.upgrade()){ - let path = file_sym.borrow().paths()[0].clone(); + let path = file_sym.borrow().path().to_single_string(); let range = session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &path, &field.borrow().range()); links.push(LocationLink{ - origin_selection_range: eval.range.map(|r| session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, file_symbol.borrow().paths().first().as_ref().unwrap(), &r)), + origin_selection_range: eval.range.map(|r| session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &file_symbol.borrow().path().to_single_string(), &r)), target_uri: FileMgr::pathname2uri(&path), target_selection_range: range, target_range: range, @@ -195,26 +195,21 @@ impl DefinitionFeature { }).collect::>(); for symbol in symbols { if let Some(file) = symbol.borrow().get_file() { - for path in file.upgrade().unwrap().borrow().paths().iter() { - let full_path = match file.upgrade().unwrap().borrow().typ() { - SymType::PACKAGE(_) => PathBuf::from(path).join(format!("__init__.py{}", file.upgrade().unwrap().borrow().as_package().i_ext())).sanitize(), - _ => path.clone() - }; - let range = if symbol.borrow().has_range() { - if symbol.borrow().range().contains(TextSize::new(offset as u32)) { - continue; //skip if we are already on the definition - } - session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &full_path, &symbol.borrow().range()) - } else { - Range::default() - }; - links.push(LocationLink{ - origin_selection_range: None, - target_uri: FileMgr::pathname2uri(&full_path), - target_selection_range: range, - target_range: range, - }); - } + let full_path = file.upgrade().unwrap().borrow().get_file_path(); + let range = if symbol.borrow().has_range() { + if symbol.borrow().range().contains(TextSize::new(offset as u32)) { + continue; //skip if we are already on the definition + } + session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &full_path, &symbol.borrow().range()) + } else { + Range::default() + }; + links.push(LocationLink{ + origin_selection_range: None, + target_uri: FileMgr::pathname2uri(&full_path), + target_selection_range: range, + target_range: range, + }); } } } @@ -287,23 +282,18 @@ impl DefinitionFeature { } continue; } - for path in file.upgrade().unwrap().borrow().paths().iter() { - let full_path = match file.upgrade().unwrap().borrow().typ() { - SymType::PACKAGE(_) => PathBuf::from(path).join(format!("__init__.py{}", file.upgrade().unwrap().borrow().as_package().i_ext())).sanitize(), - _ => path.clone() - }; - let range = if symbol.borrow().has_range() { - session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &full_path, &symbol.borrow().range()) - } else { - Range::default() - }; - links.push(LocationLink{ - origin_selection_range: None, - target_uri: FileMgr::pathname2uri(&full_path), - target_selection_range: range, - target_range: range, - }); - } + let full_path = file.upgrade().unwrap().borrow().get_file_path(); + let range = if symbol.borrow().has_range() { + session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &full_path, &symbol.borrow().range()) + } else { + Range::default() + }; + links.push(LocationLink{ + origin_selection_range: None, + target_uri: FileMgr::pathname2uri(&full_path), + target_selection_range: range, + target_range: range, + }); } index += 1; } @@ -330,18 +320,36 @@ impl DefinitionFeature { match xml_result { crate::features::xml_ast_utils::XmlAstResult::SYMBOL(s) => { if let Some(file) = s.borrow().get_file() { - for path in file.upgrade().unwrap().borrow().paths().iter() { - let full_path = match file.upgrade().unwrap().borrow().typ() { - SymType::PACKAGE(_) => PathBuf::from(path).join(format!("__init__.py{}", file.upgrade().unwrap().borrow().as_package().i_ext())).sanitize(), - _ => path.clone() - }; - let range = if s.borrow().has_range() { - session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &full_path, &s.borrow().range()) - } else { - Range::default() + let full_path = file.upgrade().unwrap().borrow().get_file_path(); + let range = if s.borrow().has_range() { + session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &full_path, &s.borrow().range()) + } else { + Range::default() + }; + let link_range = if link_range.is_some() { + Some(session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, &file_symbol.borrow().path().to_single_string(), link_range.as_ref().unwrap())) + } else { + None + }; + links.push(LocationLink{ + origin_selection_range: link_range, + target_uri: FileMgr::pathname2uri(&full_path), + target_range: range, + target_selection_range: range + }); + } + }, + XmlAstResult::XML_DATA(xml_file_symbol, range) => { + let file = xml_file_symbol.borrow().get_file(); //in case of XML_DATA coming from a python class + if let Some(file) = file { + if let Some(file) = file.upgrade() { + let full_path = file.borrow().get_file_path(); + let range = match file.borrow().typ() { + SymType::PACKAGE(_) | SymType::FILE | SymType::NAMESPACE | SymType::DISK_DIR => Range::default(), + _ => session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, &full_path, &range), }; let link_range = if link_range.is_some() { - Some(session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, file_symbol.borrow().paths().first().as_ref().unwrap(), link_range.as_ref().unwrap())) + Some(session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, &file_symbol.borrow().path().to_single_string(), link_range.as_ref().unwrap())) } else { None }; @@ -353,34 +361,6 @@ impl DefinitionFeature { }); } } - }, - XmlAstResult::XML_DATA(xml_file_symbol, range) => { - let file = xml_file_symbol.borrow().get_file(); //in case of XML_DATA coming from a python class - if let Some(file) = file { - if let Some(file) = file.upgrade() { - for path in file.borrow().paths().iter() { - let full_path = match file.borrow().typ() { - SymType::PACKAGE(_) => PathBuf::from(path).join(format!("__init__.py{}", file.borrow().as_package().i_ext())).sanitize(), - _ => path.clone() - }; - let range = match file.borrow().typ() { - SymType::PACKAGE(_) | SymType::FILE | SymType::NAMESPACE | SymType::DISK_DIR => Range::default(), - _ => session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, &full_path, &range), - }; - let link_range = if link_range.is_some() { - Some(session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, file_symbol.borrow().paths().first().as_ref().unwrap(), link_range.as_ref().unwrap())) - } else { - None - }; - links.push(LocationLink{ - origin_selection_range: link_range, - target_uri: FileMgr::pathname2uri(&full_path), - target_range: range, - target_selection_range: range - }); - } - } - } } } } diff --git a/server/src/features/features_utils.rs b/server/src/features/features_utils.rs index 1aa1eb29..42865c25 100644 --- a/server/src/features/features_utils.rs +++ b/server/src/features/features_utils.rs @@ -700,7 +700,7 @@ impl FeaturesUtils { | Symbol::XmlFileSymbol(_) | Symbol::CsvFileSymbol(_) => { // Get useful link - let uri = FileMgr::pathname2uri(&symbol.get_symbol_first_path()); + let uri = FileMgr::pathname2uri(&symbol.get_file_path()); let range = if symbol.is_file_content() { symbol.range().start().to_u32() } else { 0 }; format!( " \n*** \nSee also: [{}]({}#{}){lb}", symbol.name(), uri.as_str(), range) } diff --git a/server/src/features/references.rs b/server/src/features/references.rs index e568e660..530e5175 100644 --- a/server/src/features/references.rs +++ b/server/src/features/references.rs @@ -1,8 +1,8 @@ -use std::{cell::RefCell, path::PathBuf, rc::Rc}; +use std::{cell::RefCell, rc::Rc}; use lsp_types::{Location, Range}; -use crate::{constants::SymType, core::{file_mgr::{FileInfo, FileMgr}, symbols::symbol::Symbol}, features::xml_ast_utils::{XmlAstResult, XmlAstUtils}, threads::SessionInfo, utils::PathSanitizer}; +use crate::{constants::SymType, core::{file_mgr::{FileInfo, FileMgr}, symbols::symbol::Symbol}, features::xml_ast_utils::{XmlAstResult, XmlAstUtils}, threads::SessionInfo}; @@ -31,31 +31,21 @@ impl ReferenceFeature { match xml_result { crate::features::xml_ast_utils::XmlAstResult::SYMBOL(s) => { if let Some(file) = s.borrow().get_file() { - for path in file.upgrade().unwrap().borrow().paths().iter() { - let full_path = match file.upgrade().unwrap().borrow().typ() { - SymType::PACKAGE(_) => PathBuf::from(path).join(format!("__init__.py{}", file.upgrade().unwrap().borrow().as_package().i_ext())).sanitize(), - _ => path.clone() - }; - let range = match s.borrow().typ() { - SymType::PACKAGE(_) | SymType::FILE | SymType::NAMESPACE | SymType::DISK_DIR => Range::default(), - _ => session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &full_path, &s.borrow().range()), - }; - links.push(Location{uri: FileMgr::pathname2uri(&full_path), range}); - } - } - }, - XmlAstResult::XML_DATA(xml_file_symbol, range) => { - for path in xml_file_symbol.borrow().paths().iter() { - let full_path = match xml_file_symbol.borrow().typ() { - SymType::PACKAGE(_) => PathBuf::from(path).join(format!("__init__.py{}", xml_file_symbol.borrow().as_package().i_ext())).sanitize(), - _ => path.clone() - }; - let range = match xml_file_symbol.borrow().typ() { + let full_path = file.upgrade().unwrap().borrow().get_file_path(); + let range = match s.borrow().typ() { SymType::PACKAGE(_) | SymType::FILE | SymType::NAMESPACE | SymType::DISK_DIR => Range::default(), - _ => session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, &full_path, &range), + _ => session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &full_path, &s.borrow().range()), }; - links.push(Location{uri: FileMgr::pathname2uri(&full_path), range: range}); + links.push(Location{uri: FileMgr::pathname2uri(&full_path), range}); } + }, + XmlAstResult::XML_DATA(xml_file_symbol, range) => { + let full_path = xml_file_symbol.borrow().get_file_path(); + let range = match xml_file_symbol.borrow().typ() { + SymType::PACKAGE(_) | SymType::FILE | SymType::NAMESPACE | SymType::DISK_DIR => Range::default(), + _ => session.sync_odoo.get_file_mgr().borrow().std_range_to_range(session, &full_path, &range), + }; + links.push(Location{uri: FileMgr::pathname2uri(&full_path), range: range}); } } } diff --git a/server/src/features/workspace_symbols.rs b/server/src/features/workspace_symbols.rs index 7006c08a..a15cfcb9 100644 --- a/server/src/features/workspace_symbols.rs +++ b/server/src/features/workspace_symbols.rs @@ -4,7 +4,7 @@ use lsp_server::{ErrorCode, ResponseError}; use lsp_types::{Location, WorkspaceLocation, WorkspaceSymbol, WorkspaceSymbolResponse}; use ruff_text_size::{TextRange, TextSize}; -use crate::{S, constants::{PackageType, SymType}, core::{entry_point::EntryPointType, file_mgr::FileMgr, symbols::symbol::Symbol}, threads::SessionInfo, utils::string_fuzzy_contains}; +use crate::{S, constants::{PackageType, SymType}, core::{entry_point::EntryPointType, file_mgr::FileMgr, symbols::symbol::{Symbol, SymbolPath}}, threads::SessionInfo, utils::string_fuzzy_contains}; pub struct WorkspaceSymbolFeature; @@ -58,13 +58,11 @@ impl WorkspaceSymbolFeature { Some(p) => Some(p.clone()), None => None, }; - let path = symbol_borrowed.paths(); - let path = if path.len() == 1 { - Some(&path[0]) - } else if path.len() == 0{ - parent_path - } else { - None + let paths = symbol_borrowed.path(); + let path = match paths { + SymbolPath::Single(ref p) => Some(p), + SymbolPath::None => parent_path, + SymbolPath::Multiple(_) => None, }; if path.is_some() && symbol_borrowed.has_range() { //Test if symbol should be returned @@ -89,11 +87,10 @@ impl WorkspaceSymbolFeature { for data in xml_data { let xml_file_symbol = data.get_xml_file_symbol(); if let Some(xml_file_symbol) = xml_file_symbol { - if let Some(path) = xml_file_symbol.borrow().paths().get(0) { - let range = data.get_range(); - let text_range = TextRange::new(TextSize::new(range.start as u32), TextSize::new(range.end as u32)); - WorkspaceSymbolFeature::add_symbol_to_results(session, &xml_file_symbol.borrow(), &xml_name, path, Some(symbol_borrowed.name().to_string()), Some(&text_range), can_resolve_location_range, results); - } + let path = xml_file_symbol.borrow().path().to_single_string(); + let range = data.get_range(); + let text_range = TextRange::new(TextSize::new(range.start as u32), TextSize::new(range.end as u32)); + WorkspaceSymbolFeature::add_symbol_to_results(session, &xml_file_symbol.borrow(), &xml_name, &path, Some(symbol_borrowed.name().to_string()), Some(&text_range), can_resolve_location_range, results); } } } diff --git a/server/tests/test_get_symbol.rs b/server/tests/test_get_symbol.rs index 519a85ec..50e5744d 100644 --- a/server/tests/test_get_symbol.rs +++ b/server/tests/test_get_symbol.rs @@ -295,7 +295,7 @@ fn test_definition() { let country_id_field_sym = session.sync_odoo.get_symbol(odoo_path, &(vec![Sy!("odoo"), Sy!("addons"), Sy!("base"), Sy!("models"), Sy!("res_partner")], vec![Sy!(partner_class_name), Sy!("country_id")]), u32::MAX); assert_eq!(country_id_field_sym.len(), 1, "Expected 1 location for country_id"); let country_id_field_sym = country_id_field_sym[0].clone(); - let country_id_file = country_id_field_sym.borrow().get_file().unwrap().upgrade().unwrap().borrow().paths()[0].clone(); + let country_id_file = country_id_field_sym.borrow().get_file().unwrap().upgrade().unwrap().borrow().path().to_single_string(); assert_eq!(country_id_locs[0].target_uri.to_file_path().unwrap().sanitize(), country_id_file); // check that one of the country_id_locs is the same as the country_id field symbol assert!(country_id_locs.iter().any(|loc| loc.target_range == file_mgr.borrow().text_range_to_range(&mut session, &country_id_file, country_id_field_sym.borrow().range())), "Expected country_id to be at the same location as the field"); @@ -305,7 +305,7 @@ fn test_definition() { let phone_code_field_sym = session.sync_odoo.get_symbol(odoo_path, &(vec![Sy!("odoo"), Sy!("addons"), Sy!("base"), Sy!("models"), Sy!("res_country")], vec![Sy!(country_class_name), Sy!("phone_code")]), u32::MAX); assert_eq!(phone_code_field_sym.len(), 1, "Expected 1 location for phone_code"); let phone_code_field_sym = phone_code_field_sym[0].clone(); - let phone_code_file = phone_code_field_sym.borrow().get_file().unwrap().upgrade().unwrap().borrow().paths()[0].clone(); + let phone_code_file = phone_code_field_sym.borrow().get_file().unwrap().upgrade().unwrap().borrow().path().to_single_string(); assert_eq!(phone_code_locs[0].target_uri.to_file_path().unwrap().sanitize(), phone_code_file); // check that one of the phone_code_locs is the same as the phone_code field assert!(phone_code_locs.iter().any(|loc| loc.target_range == file_mgr.borrow().text_range_to_range(&mut session, &phone_code_file, phone_code_field_sym.borrow().range())), "Expected phone_code to be at the same location as the field");