diff --git a/Cargo.lock b/Cargo.lock index 70fa50c..096d960 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] @@ -110,9 +110,9 @@ checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bstr" -version = "1.6.0" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "4c2f7349907b712260e64b0afe2f84692af14a454be26187d9df565c7f69266a" dependencies = [ "memchr", "serde", @@ -165,9 +165,9 @@ checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" [[package]] name = "dashmap" -version = "5.5.1" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", "hashbrown 0.14.0", @@ -176,6 +176,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "env_logger" version = "0.10.0" @@ -191,9 +197,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", @@ -516,9 +522,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" [[package]] name = "miette" @@ -611,6 +617,7 @@ dependencies = [ "log", "miette", "pin-project-lite", + "pretty_assertions", "qp-trie", "ropey", "serde", @@ -686,9 +693,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -696,6 +703,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -759,9 +776,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", @@ -771,9 +788,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", @@ -782,9 +799,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "rle-decode-fast" @@ -810,9 +827,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.8" +version = "0.38.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964" dependencies = [ "bitflags 2.4.0", "errno", @@ -844,18 +861,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.185" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.185" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -1257,9 +1274,9 @@ dependencies = [ [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", @@ -1397,3 +1414,9 @@ name = "xmlparser" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml index dbd06a8..6bfddc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,3 +47,6 @@ lasso = { version = "0.7.2", features = ["multi-threaded"] } intmap = "2.0.0" libflate = "2.0.0" +[dev-dependencies] +pretty_assertions = "1.4.0" + diff --git a/src/index.rs b/src/index.rs index b03a5af..09ded81 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,13 +1,10 @@ -use std::hash::Hash; -use std::marker::PhantomData; -use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::{Arc, OnceLock}; use std::time::Duration; use dashmap::DashSet; use globwalk::FileType; -use lasso::{Spur, ThreadedRodeo}; +use lasso::ThreadedRodeo; use log::{debug, warn}; use miette::{diagnostic, Context, IntoDiagnostic}; use ropey::Rope; @@ -16,13 +13,15 @@ use tower_lsp::lsp_types::*; use tree_sitter::{Query, QueryCursor}; use xmlparser::{Token, Tokenizer}; -use crate::model::{Model, ModelId, ModelIndex}; +use crate::model::{Model, ModelIndex, ModelType}; use crate::record::Record; use crate::utils::{offset_range_to_lsp_range, ByteOffset, CharOffset, RangeExt}; use crate::{format_loc, ImStr}; mod record; pub use record::{RecordId, SymbolMap, SymbolSet}; +mod symbol; +pub use symbol::Symbol; #[derive(Default)] pub struct ModuleIndex { @@ -33,60 +32,10 @@ pub struct ModuleIndex { pub interner: Arc, } -/// Type-safe wrapper around [Spur]. -#[derive(Debug)] -pub struct Symbol { - inner: Spur, - _kind: PhantomData, -} - pub type ModuleName = Symbol; #[derive(Debug)] pub enum Module {} -impl From for Symbol { - #[inline] - fn from(inner: Spur) -> Self { - Symbol { - inner, - _kind: PhantomData, - } - } -} - -impl Clone for Symbol { - #[inline] - fn clone(&self) -> Self { - Symbol { - inner: self.inner.clone(), - _kind: PhantomData, - } - } -} - -impl Copy for Symbol {} -impl Eq for Symbol {} -impl PartialEq for Symbol { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.inner.eq(&other.inner) - } -} - -impl Hash for Symbol { - #[inline] - fn hash(&self, state: &mut H) { - self.inner.hash(state) - } -} - -impl Deref for Symbol { - type Target = Spur; - fn deref(&self) -> &Self::Target { - &self.inner - } -} - enum Output { Records(Vec), Models { path: ImStr, models: Vec }, @@ -206,7 +155,7 @@ impl ModuleIndex { } Output::Models { path, models } => { model_count += models.len(); - self.models.extend_models(path, models).await; + self.models.extend_models(path, &self.interner, models).await; } } } @@ -378,7 +327,7 @@ async fn add_root_py(path: PathBuf) -> miette::Result { } match (inherits.as_slice(), maybe_base) { ([_, ..], None) => out.push(Model { - model: ModelId::Inherit(inherits), + type_: ModelType::Inherit(inherits), range: lsp_range, byte_range: range, }), @@ -386,13 +335,13 @@ async fn add_root_py(path: PathBuf) -> miette::Result { (_, Some(base)) => { if has_primary { out.push(Model { - model: ModelId::Inherit(inherits), + type_: ModelType::Inherit(inherits), range: lsp_range, byte_range: range, }); } else { out.push(Model { - model: ModelId::Base(base.as_ref().into()), + type_: ModelType::Base(base.as_ref().into()), range: lsp_range, byte_range: range, }) diff --git a/src/index/symbol.rs b/src/index/symbol.rs new file mode 100644 index 0000000..40190e4 --- /dev/null +++ b/src/index/symbol.rs @@ -0,0 +1,54 @@ +use std::{hash::Hash, marker::PhantomData, ops::Deref}; + +use lasso::Spur; + +/// Type-safe wrapper around [Spur]. +#[derive(Debug)] +pub struct Symbol { + inner: Spur, + _kind: PhantomData, +} + +// TODO: Remove in favor of strict-type symbols +impl From for Symbol { + #[inline] + fn from(inner: Spur) -> Self { + Symbol { + inner, + _kind: PhantomData, + } + } +} + +impl Clone for Symbol { + #[inline] + fn clone(&self) -> Self { + Symbol { + inner: self.inner, + _kind: PhantomData, + } + } +} + +impl Copy for Symbol {} +impl Eq for Symbol {} +impl PartialEq for Symbol { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.inner.eq(&other.inner) + } +} + +impl Hash for Symbol { + #[inline] + fn hash(&self, state: &mut H) { + self.inner.hash(state) + } +} + +impl Deref for Symbol { + type Target = Spur; + fn deref(&self) -> &Self::Target { + &self.inner + } +} diff --git a/src/main.rs b/src/main.rs index 8dd43f3..f68d1a8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,7 @@ use odoo_lsp::config::{Config, ModuleConfig, ReferencesConfig, SymbolsConfig}; use odoo_lsp::index::{ModuleIndex, ModuleName, RecordId}; use odoo_lsp::model::{FieldKind, ModelLocation}; use odoo_lsp::utils::isolate::Isolate; -use odoo_lsp::{format_loc, unwrap_or_none, utils::*}; +use odoo_lsp::{format_loc, some, utils::*}; mod catch_panic; mod python; @@ -459,7 +459,10 @@ impl LanguageServer for Backend { 'resolve: { match &completion.kind { Some(CompletionItemKind::CLASS) => { - let Some(mut entry) = self.module_index.models.get_mut(completion.label.as_str()) else { + let Some(model) = self.module_index.interner.get(&completion.label) else { + break 'resolve; + }; + let Some(mut entry) = self.module_index.models.get_mut(&model.into()) else { break 'resolve; }; if let Err(err) = entry.resolve_details().await { @@ -475,7 +478,10 @@ impl LanguageServer for Backend { let Some(Value::String(value)) = &completion.data else { break 'resolve; }; - let Some(mut entry) = self.module_index.models.get_mut(value.as_str()) else { + let Some(model) = self.module_index.interner.get(&value) else { + break 'resolve; + }; + let Some(mut entry) = self.module_index.models.get_mut(&model.into()) else { break 'resolve; }; if let Err(err) = entry.resolve_details().await { @@ -549,7 +555,7 @@ impl LanguageServer for Backend { let models = models_by_prefix.iter_prefix(query.as_bytes()).flat_map(|(_, key)| { self.module_index.models.get(key).into_iter().flat_map(|entry| { entry.base.as_ref().map(|loc| SymbolInformation { - name: entry.key().to_string(), + name: self.module_index.interner.resolve(entry.key()).to_string(), kind: SymbolKind::CONSTANT, tags: None, deprecated: None, @@ -571,7 +577,7 @@ impl LanguageServer for Backend { } let interner = &self.module_index.interner; if let Some((module, xml_id_query)) = query.split_once('.') { - let module = unwrap_or_none!(interner.get(&module)).into(); + let module = some!(interner.get(&module)).into(); let records = records_by_prefix .iter_prefix(xml_id_query.as_bytes()) .flat_map(|(_, keys)| { @@ -769,7 +775,10 @@ impl Backend { rope: Rope, items: &mut Vec, ) -> miette::Result<()> { - let Some(mut entry) = self.module_index.models.get_mut(model.as_str()) else { + let Some(model_key) = self.module_index.interner.get(&model) else { + return Ok(()); + }; + let Some(mut entry) = self.module_index.models.get_mut(&model_key.into()) else { return Ok(()); }; let range = char_range_to_lsp_range(range, rope).ok_or_else(|| diagnostic!("range"))?; @@ -808,7 +817,7 @@ impl Backend { .iter_prefix(needle.as_bytes()) .flat_map(|(_, key)| self.module_index.models.get(key)) .map(|entry| { - let label = entry.key().to_string(); + let label = self.module_index.interner.resolve(entry.key()).to_string(); CompletionItem { text_edit: Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit { new_text: label.clone(), @@ -839,14 +848,15 @@ impl Backend { return Ok(None); } } - let record_id = unwrap_or_none!(self.module_index.interner.get(value)); + let record_id = some!(self.module_index.interner.get(value)); return Ok((self.module_index.records.get(&record_id.into())).map(|entry| entry.location.clone().into())); } fn jump_def_model(&self, model: &str) -> miette::Result> { + let model = some!(self.module_index.interner.get(model)); match self .module_index .models - .get(model) + .get(&model.into()) .and_then(|entry| entry.base.as_ref().cloned()) { Some(ModelLocation(base, _)) => Ok(Some(base.into())), @@ -854,10 +864,11 @@ impl Backend { } } async fn jump_def_field_name(&self, field: &str, model: &str) -> miette::Result> { - let mut entry = unwrap_or_none!(self.module_index.models.get_mut(model)); - let field = unwrap_or_none!(self.module_index.interner.get(field)); + let model = self.module_index.interner.get_or_intern(model); + let mut entry = some!(self.module_index.models.get_mut(&model.into())); + let field = some!(self.module_index.interner.get(field)); let fields = self.populate_field_names(&mut entry).await?; - let field = unwrap_or_none!(fields.get(&field.into())); + let field = some!(fields.get(&field.into())); Ok(Some(field.location.clone().into())) } fn model_references(&self, model: &str) -> miette::Result>> { @@ -866,8 +877,9 @@ impl Backend { .records .by_model(model) .map(|record| record.location.clone().into()); + let model = some!(self.module_index.interner.get(model)); let limit = self.references_limit.load(Relaxed); - if let Some(entry) = self.module_index.models.get(model) { + if let Some(entry) = self.module_index.models.get(&model.into()) { let inherit_locations = entry.descendants.iter().map(|loc| loc.0.clone().into()); Ok(Some(inherit_locations.chain(record_locations).take(limit).collect())) } else { @@ -888,7 +900,7 @@ impl Backend { debug!("No current module to resolve the XML ID {inherit_id}"); return Ok(None); }; - let inherit_id = RecordId::from(unwrap_or_none!(interner.get(inherit_id))); + let inherit_id = RecordId::from(some!(interner.get(inherit_id))); let limit = self.references_limit.load(Relaxed); let locations = self .module_index diff --git a/src/model.rs b/src/model.rs index 33f398e..786d608 100644 --- a/src/model.rs +++ b/src/model.rs @@ -3,37 +3,38 @@ use std::ops::Deref; use std::sync::{Arc, OnceLock}; use dashmap::DashMap; -use lasso::Spur; +use lasso::{Spur, ThreadedRodeo}; use miette::{diagnostic, IntoDiagnostic}; use qp_trie::{wrapper::BString, Trie}; use tokio::sync::RwLock; use tower_lsp::lsp_types::Range; use tree_sitter::{Parser, Query, QueryCursor}; -use crate::index::SymbolMap; +use crate::index::{Symbol, SymbolMap}; use crate::str::Text; -use crate::utils::{ByteOffset, Erase, MinLoc}; +use crate::utils::{ByteOffset, ByteRange, Erase, MinLoc}; use crate::ImStr; #[derive(Clone, Debug)] pub struct Model { - pub model: ModelId, + pub type_: ModelType, pub range: Range, - pub byte_range: std::ops::Range, + pub byte_range: ByteRange, } #[derive(Clone, Debug)] -pub enum ModelId { +pub enum ModelType { Base(ImStr), Inherit(Vec), } #[derive(Default)] pub struct ModelIndex { - inner: DashMap, - pub by_prefix: Arc>>, + inner: DashMap, + pub by_prefix: Arc>>, } +pub type ModelName = Symbol; #[derive(Default)] pub struct ModelEntry { pub base: Option, @@ -85,7 +86,7 @@ impl Display for ModelLocation { } impl Deref for ModelIndex { - type Target = DashMap; + type Target = DashMap; fn deref(&self) -> &Self::Target { &self.inner @@ -93,16 +94,17 @@ impl Deref for ModelIndex { } impl ModelIndex { - pub async fn extend_models(&self, path: ImStr, items: I) + pub async fn extend_models(&self, path: ImStr, interner: &ThreadedRodeo, items: I) where I: IntoIterator, { let mut by_prefix = self.by_prefix.write().await; for item in items { - match item.model { - ModelId::Base(base) => { - by_prefix.insert_str(&base, base.clone()); - let mut entry = self.entry(base.clone()).or_default(); + match item.type_ { + ModelType::Base(base) => { + let name = interner.get_or_intern(&base).into(); + by_prefix.insert_str(&base, name); + let mut entry = self.entry(name).or_default(); entry.base = Some(ModelLocation( MinLoc { path: path.clone(), @@ -111,8 +113,9 @@ impl ModelIndex { item.byte_range, )); } - ModelId::Inherit(inherits) => { + ModelType::Inherit(inherits) => { for inherit in inherits { + let inherit = interner.get_or_intern(inherit).into(); self.entry(inherit).or_default().descendants.push(ModelLocation( MinLoc { path: path.clone(), diff --git a/src/python.rs b/src/python.rs index 0e05e3d..12c08ca 100644 --- a/src/python.rs +++ b/src/python.rs @@ -310,7 +310,7 @@ impl Backend { b"One2many" | b"Many2one" | b"Many2many" ); } else if capture.index == 3 { - // @comodel_name + // @relation if is_relational { relation = Some(capture.node.byte_range().contract(1)); } @@ -330,7 +330,9 @@ impl Backend { } } Some(Kwargs::Help) => { - help = Some(parse_help(&capture.node, &contents)); + if matches!(capture.node.kind(), "string" | "concatenated_string") { + help = Some(parse_help(&capture.node, &contents)); + } } None => {} } @@ -394,6 +396,11 @@ impl Backend { #[cfg(test)] mod tests { use super::*; + use pretty_assertions::assert_eq; + + /// Tricky behavior here. The query syntax required to match the trailing comma between + /// named arguments, and this test checks that. Furthermore, @help cannot be matched + /// as a `(string)` since that would reify its shape and refuse subsequent matches. #[test] fn test_model_fields() { let mut parser = Parser::new(); @@ -404,17 +411,29 @@ class Foo(models.Model): bar = fields.Many2one(comodel_name='asd', help='asd') what = fields.What(asd) haha = fields.Many2many('asd') - html = fields.Html(related='asd', foo=123)"#; + html = fields.Html(related='asd', foo=123, help='asdf')"#; let ast = parser.parse(&contents[..], None).unwrap(); let query = model_fields(); let mut cursor = QueryCursor::new(); - for match_ in cursor.matches(query, ast.root_node(), &contents[..]) { - let captures = match_ - .captures - .iter() - .map(|capture| String::from_utf8_lossy(&contents[capture.node.byte_range()])) - .collect::>(); - dbg!(captures); - } + let expected: &[&[&str]] = &[ + &["foo", "fields", "Char", "'asd'", "help", "'asd'"], + &["bar", "fields", "Many2one", "comodel_name", "'asd'", "help", "'asd'"], + &["what", "fields", "What"], + &["haha", "fields", "Many2many", "'asd'"], + &[ + "html", "fields", "Html", "related", "'asd'", "foo", "123", "help", "'asdf'", + ], + ]; + let actual = cursor + .matches(query, ast.root_node(), &contents[..]) + .map(|match_| { + match_ + .captures + .into_iter() + .map(|capture| String::from_utf8_lossy(&contents[capture.node.byte_range()])) + .collect::>() + }) + .collect::>(); + assert_eq!(expected, actual); } } diff --git a/src/queries/model_fields.scm b/src/queries/model_fields.scm index 7c14489..f35c11a 100644 --- a/src/queries/model_fields.scm +++ b/src/queries/model_fields.scm @@ -6,10 +6,7 @@ (call [(identifier) @Type (attribute (identifier) @_fields (identifier) @Type)] - (argument_list - . (string)? @comodel_name - (keyword_argument - (identifier) @_arg - [(string) (concatenated_string)] @value)?)))))) + (argument_list . (string)? @relation + ((keyword_argument (identifier) @_arg (_) @value) ","?)*)))))) (#eq? @_fields "fields") (#match? @Type "^[A-Z]")) \ No newline at end of file diff --git a/src/record.rs b/src/record.rs index aa8b251..273376a 100644 --- a/src/record.rs +++ b/src/record.rs @@ -10,7 +10,7 @@ use crate::utils::{char_to_position, position_to_char, CharOffset}; use crate::ImStr; #[macro_export] -macro_rules! unwrap_or_none { +macro_rules! some { ($opt:expr) => { match $opt { Some(it) => it, @@ -136,7 +136,7 @@ impl Record { _ => {} } } - let id = unwrap_or_none!(id); + let id = some!(id); let end = end.ok_or_else(|| diagnostic!("Unbound range for record"))?; let end = char_to_position(end, rope.clone()).ok_or_else(|| diagnostic!("Failed to parse end location"))?; let range = Range { start, end }; @@ -227,7 +227,7 @@ impl Record { let range = Range { start, end }; Ok(Some(Self { - id: unwrap_or_none!(id), + id: some!(id), deleted: false, model: Some("ir.ui.view".into()), module, diff --git a/src/str.rs b/src/str.rs index bd65752..7fae927 100644 --- a/src/str.rs +++ b/src/str.rs @@ -174,7 +174,7 @@ impl Text { let slice = unsafe { std::str::from_utf8_unchecked(slice) }; Cow::Borrowed(slice) } - TextRepr::Arc(ptr) => Cow::Borrowed(&ptr), + TextRepr::Arc(ptr) => Cow::Borrowed(ptr), TextRepr::Compressed(len, encoded) => { let mut buf = Vec::with_capacity(*len as usize); let mut dec = Decoder::new(&encoded[..]); diff --git a/src/xml.rs b/src/xml.rs index 924d407..59bc7ea 100644 --- a/src/xml.rs +++ b/src/xml.rs @@ -13,7 +13,7 @@ use tower_lsp::lsp_types::*; use xmlparser::{StrSpan, Token, Tokenizer}; use odoo_lsp::record::Record; -use odoo_lsp::{unwrap_or_none, utils::*, ImStr}; +use odoo_lsp::{some, utils::*, ImStr}; enum RefKind { Ref(Spur), @@ -177,10 +177,9 @@ impl Backend { let replace_range = value.range().map_unit(|unit| CharOffset(unit + relative_offset)); match record_field { RefKind::Ref(relation) => { - let Some(model) = model_filter else { return Ok(None) }; - let Some(mut entry) = self.module_index.models.get_mut(model.as_str()) else { - return Ok(None); - }; + let model = some!(model_filter); + let model = some!(self.module_index.interner.get(model)); + let mut entry = some!(self.module_index.models.get_mut(&model.into())); let fields = self.populate_field_names(&mut entry).await?; let Some(Field { kind: FieldKind::Relational(relation), @@ -231,7 +230,7 @@ impl Backend { Some(RefKind::Ref(_)) => self.jump_def_inherit_id(&cursor_value, uri), Some(RefKind::Model) => self.jump_def_model(&cursor_value), Some(RefKind::FieldName) => { - let model = unwrap_or_none!(model); + let model = some!(model); self.jump_def_field_name(&cursor_value, &model).await } Some(RefKind::Id) | None => Ok(None),