Skip to content

Commit 2994b6b

Browse files
committed
ref: manage memory usage
1 parent 004d33c commit 2994b6b

File tree

10 files changed

+84
-62
lines changed

10 files changed

+84
-62
lines changed

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@
4848
"odoo-lsp.symbols.limit": {
4949
"type": "number",
5050
"default": 80,
51-
"description": "Maximum amount of workspace symbols to view at once."
51+
"description": "Maximum amount of workspace symbols to retrieve at once."
52+
},
53+
"odoo-lsp.references.limit": {
54+
"type": "number",
55+
"default": 80,
56+
"description": "Maximum amount of model/record references to retrieve at once."
5257
},
5358
"odoo-lsp.module.roots": {
5459
"type": "array",

src/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use serde::Deserialize;
44
pub struct Config {
55
pub module: Option<ModuleConfig>,
66
pub symbols: Option<SymbolsConfig>,
7+
pub references: Option<ReferencesConfig>,
78
}
89

910
#[derive(Deserialize, Debug, Clone)]
@@ -15,3 +16,8 @@ pub struct ModuleConfig {
1516
pub struct SymbolsConfig {
1617
pub limit: Option<u32>,
1718
}
19+
20+
#[derive(Deserialize, Debug, Clone)]
21+
pub struct ReferencesConfig {
22+
pub limit: Option<u32>,
23+
}

src/index.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,7 @@ impl ModuleIndex {
146146
}
147147
Output::Models { path, models } => {
148148
model_count += models.len();
149-
let uri = match format!("file://{path}").parse() {
150-
Ok(uri) => uri,
151-
Err(err) => {
152-
debug!("{err}");
153-
continue;
154-
}
155-
};
156-
self.models.extend_models(&uri, models).await;
149+
self.models.extend_models(path, models).await;
157150
}
158151
}
159152
}
@@ -185,7 +178,7 @@ impl ModuleIndex {
185178
}
186179

187180
async fn add_root_xml(path: PathBuf, module_name: ImStr) -> miette::Result<Output> {
188-
let uri: Url = format!("file://{}", path.to_string_lossy()).parse().into_diagnostic()?;
181+
let path_uri = ImStr::from(path.to_string_lossy().as_ref());
189182
let file = tokio::fs::read(&path)
190183
.await
191184
.into_diagnostic()
@@ -201,7 +194,7 @@ async fn add_root_xml(path: PathBuf, module_name: ImStr) -> miette::Result<Outpu
201194
let record = Record::from_reader(
202195
CharOffset(span.start()),
203196
module_name.clone(),
204-
uri.clone(),
197+
path_uri.clone(),
205198
&mut reader,
206199
rope.clone(),
207200
)?;
@@ -210,7 +203,7 @@ async fn add_root_xml(path: PathBuf, module_name: ImStr) -> miette::Result<Outpu
210203
let template = Record::template(
211204
CharOffset(span.start()),
212205
module_name.clone(),
213-
uri.clone(),
206+
path_uri.clone(),
214207
&mut reader,
215208
rope.clone(),
216209
)?;
@@ -281,11 +274,11 @@ async fn add_root_py(path: PathBuf, _: ImStr) -> miette::Result<Output> {
281274
.ok_or_else(|| diagnostic!("model range"))?;
282275
match (inherits.as_slice(), maybe_base) {
283276
([single], Some(base)) if base.as_ref() == single => out.push(Model {
284-
model: ModelId::Inherit(inherits.into_boxed_slice()),
277+
model: ModelId::Inherit(inherits),
285278
range,
286279
}),
287280
(_, None) if !inherits.is_empty() => out.push(Model {
288-
model: ModelId::Inherit(inherits.into_boxed_slice()),
281+
model: ModelId::Inherit(inherits),
289282
range,
290283
}),
291284
(_, Some(base)) => out.push(Model {

src/index/record.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl RecordIndex {
5656
.or_insert_with(DashSet::default)
5757
.insert(qualified_id.clone());
5858
}
59-
self.inner.insert(qualified_id.into(), record);
59+
self.inner.insert(qualified_id, record);
6060
}
6161
pub async fn extend_records(&self, prefix: Option<&mut PrefixTrie>, records: impl IntoIterator<Item = Record>) {
6262
if let Some(prefix) = prefix {

src/main.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use tower_lsp::lsp_types::*;
1818
use tower_lsp::{Client, LanguageServer, LspService, Server};
1919
use tree_sitter::{Parser, Tree};
2020

21-
use odoo_lsp::config::{Config, ModuleConfig, SymbolsConfig};
21+
use odoo_lsp::config::{Config, ModuleConfig, ReferencesConfig, SymbolsConfig};
2222
use odoo_lsp::index::ModuleIndex;
2323
use odoo_lsp::model::ModelLocation;
2424
use odoo_lsp::utils::isolate::Isolate;
@@ -38,6 +38,7 @@ pub struct Backend {
3838
capabilities: Capabilities,
3939
root_setup: AtomicBool,
4040
symbols_limit: AtomicUsize,
41+
references_limit: AtomicUsize,
4142
isolate: Isolate,
4243
}
4344

@@ -137,6 +138,7 @@ impl LanguageServer for Backend {
137138
capabilities: _,
138139
root_setup: _,
139140
symbols_limit: _,
141+
references_limit: _,
140142
isolate: _,
141143
} = self;
142144
document_map.remove(path);
@@ -172,7 +174,7 @@ impl LanguageServer for Backend {
172174
}
173175

174176
for root in self.roots.iter() {
175-
match self.module_index.add_root(&root.as_str(), progress.clone()).await {
177+
match self.module_index.add_root(root.as_str(), progress.clone()).await {
176178
Ok(Some(results)) => {
177179
info!(
178180
"{} | {} modules | {} records | {} models | {:.2}s",
@@ -750,17 +752,18 @@ impl Backend {
750752
}
751753
}
752754
fn model_references(&self, model: &str) -> miette::Result<Option<Vec<Location>>> {
753-
let mut locations = match self.module_index.models.get(model) {
754-
Some(entry) => entry.1.iter().map(|loc| loc.0.clone().into()).collect::<Vec<_>>(),
755-
None => vec![],
756-
};
757-
locations.extend(
758-
self.module_index
759-
.records
760-
.by_model(model)
761-
.map(|record| record.location.clone().into()),
762-
);
763-
Ok(Some(locations))
755+
let record_locations = self
756+
.module_index
757+
.records
758+
.by_model(model)
759+
.map(|record| record.location.clone().into());
760+
let limit = self.references_limit.load(Relaxed);
761+
if let Some(entry) = self.module_index.models.get(model) {
762+
let inherit_locations = entry.1.iter().map(|loc| loc.0.clone().into());
763+
Ok(Some(inherit_locations.chain(record_locations).take(limit).collect()))
764+
} else {
765+
Ok(Some(record_locations.take(limit).collect()))
766+
}
764767
}
765768
fn record_references(
766769
&self,
@@ -775,17 +778,22 @@ impl Backend {
775778
debug!("No current module to resolve the XML ID {inherit_id}");
776779
return Ok(None);
777780
};
781+
let limit = self.references_limit.load(Relaxed);
778782
let locations = self
779783
.module_index
780784
.records
781785
.by_inherit_id(&inherit_id)
782-
.map(|record| record.location.clone().into());
786+
.map(|record| record.location.clone().into())
787+
.take(limit);
783788
Ok(Some(locations.collect()))
784789
}
785790
async fn on_change_config(&self, config: Config) {
786791
if let Some(SymbolsConfig { limit: Some(limit) }) = config.symbols {
787792
self.symbols_limit.store(limit as usize, Relaxed);
788793
}
794+
if let Some(ReferencesConfig { limit: Some(limit) }) = config.references {
795+
self.references_limit.store(limit as usize, Relaxed);
796+
}
789797
let Some(ModuleConfig { roots: Some(roots), .. }) = config.module else {
790798
return;
791799
};
@@ -830,6 +838,7 @@ async fn main() {
830838
root_setup: Default::default(),
831839
ast_map: DashMap::new(),
832840
symbols_limit: AtomicUsize::new(100),
841+
references_limit: AtomicUsize::new(100),
833842
isolate: Isolate::new(),
834843
})
835844
.finish();

src/model.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use std::{fmt::Display, ops::Deref, sync::Arc};
33
use dashmap::DashMap;
44
use qp_trie::{wrapper::BString, Trie};
55
use tokio::sync::RwLock;
6-
use tower_lsp::lsp_types::{Location, Range, Url};
6+
use tower_lsp::lsp_types::Range;
77

8-
use crate::utils::ImStr;
8+
use crate::utils::{ImStr, MinLoc};
99

1010
#[derive(Clone, Debug)]
1111
pub struct Model {
@@ -16,7 +16,7 @@ pub struct Model {
1616
#[derive(Clone, Debug)]
1717
pub enum ModelId {
1818
Base(ImStr),
19-
Inherit(Box<[ImStr]>),
19+
Inherit(Vec<ImStr>),
2020
}
2121

2222
#[derive(Default, Clone)]
@@ -26,24 +26,21 @@ pub struct ModelIndex {
2626
}
2727

2828
#[derive(Clone)]
29-
pub struct ModelLocation(pub Location);
29+
pub struct ModelLocation(pub MinLoc);
3030

3131
impl Display for ModelLocation {
3232
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3333
if self.0.range.start.line == self.0.range.end.line {
3434
write!(
3535
f,
3636
"{} [{}:{}..{}]",
37-
self.0.uri.path(),
38-
self.0.range.start.line,
39-
self.0.range.start.character,
40-
self.0.range.end.character,
37+
self.0.path, self.0.range.start.line, self.0.range.start.character, self.0.range.end.character,
4138
)
4239
} else {
4340
write!(
4441
f,
4542
"{} [{}:{}..{}:{}]",
46-
self.0.uri.path(),
43+
self.0.path,
4744
self.0.range.start.line,
4845
self.0.range.start.character,
4946
self.0.range.end.line,
@@ -62,7 +59,7 @@ impl Deref for ModelIndex {
6259
}
6360

6461
impl ModelIndex {
65-
pub async fn extend_models<I>(&self, uri: &Url, items: I)
62+
pub async fn extend_models<I>(&self, path: ImStr, items: I)
6663
where
6764
I: IntoIterator<Item = Model>,
6865
{
@@ -71,8 +68,8 @@ impl ModelIndex {
7168
match item.model {
7269
ModelId::Base(base) => {
7370
by_prefix.insert_str(&base, base.clone());
74-
let mut location = Some(ModelLocation(Location {
75-
uri: uri.clone(),
71+
let mut location = Some(ModelLocation(MinLoc {
72+
path: path.clone(),
7673
range: item.range,
7774
}));
7875
core::mem::swap(&mut self.entry(base.clone()).or_default().0, &mut location);
@@ -83,8 +80,8 @@ impl ModelIndex {
8380
}
8481
ModelId::Inherit(inherits) => {
8582
for inherit in inherits.iter() {
86-
self.entry(inherit.clone()).or_default().1.push(ModelLocation(Location {
87-
uri: uri.clone(),
83+
self.entry(inherit.clone()).or_default().1.push(ModelLocation(MinLoc {
84+
path: path.clone(),
8885
range: item.range,
8986
}))
9087
}

src/record.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use ropey::Rope;
33
use tower_lsp::lsp_types::*;
44
use xmlparser::{ElementEnd, Token, Tokenizer};
55

6-
use crate::utils::ImStr;
76
use crate::utils::{char_to_position, position_to_char, CharOffset};
7+
use crate::utils::{ImStr, MinLoc};
88

99
macro_rules! unwrap_or_none {
1010
($opt:expr) => {
@@ -23,7 +23,7 @@ pub struct Record {
2323
pub model: Option<ImStr>,
2424
/// (inherit_module?, xml_id)
2525
pub inherit_id: Option<(Option<ImStr>, ImStr)>,
26-
pub location: Location,
26+
pub location: MinLoc,
2727
}
2828

2929
impl Record {
@@ -33,7 +33,7 @@ impl Record {
3333
pub fn from_reader(
3434
offset: CharOffset,
3535
module: ImStr,
36-
uri: Url,
36+
path: ImStr,
3737
reader: &mut Tokenizer,
3838
rope: Rope,
3939
) -> miette::Result<Option<Self>> {
@@ -144,13 +144,13 @@ impl Record {
144144
module,
145145
model,
146146
inherit_id,
147-
location: Location { uri, range },
147+
location: MinLoc { path, range },
148148
}))
149149
}
150150
pub fn template(
151151
offset: CharOffset,
152152
module: ImStr,
153-
uri: Url,
153+
path: ImStr,
154154
reader: &mut Tokenizer,
155155
rope: Rope,
156156
) -> miette::Result<Option<Self>> {
@@ -231,7 +231,7 @@ impl Record {
231231
model: Some("ir.ui.view".into()),
232232
module,
233233
inherit_id,
234-
location: Location { uri, range },
234+
location: MinLoc { path, range },
235235
}))
236236
}
237237
}
@@ -252,17 +252,11 @@ mod tests {
252252
_ = reader.next();
253253
let rope = Rope::from_str(&document);
254254
let Record {
255-
location: Location { range, .. },
255+
location: MinLoc { range, .. },
256256
..
257-
} = Record::from_reader(
258-
CharOffset(0),
259-
"foo".into(),
260-
"/foo".parse().unwrap(),
261-
&mut reader,
262-
rope.clone(),
263-
)
264-
.unwrap()
265-
.unwrap();
257+
} = Record::from_reader(CharOffset(0), "foo".into(), "/foo".into(), &mut reader, rope.clone())
258+
.unwrap()
259+
.unwrap();
266260
let range = lsp_range_to_char_range(range, rope).unwrap();
267261
assert_eq!(&document[range.map_unit(|unit| unit.0)], fragment);
268262
}

src/utils.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,22 @@ pub use str::ImStr;
1414

1515
pub type PrefixTrie = qp_trie::Trie<BString, DashSet<ImStr>>;
1616

17+
/// A more economical version of [Location].
18+
#[derive(Clone, Debug)]
19+
pub struct MinLoc {
20+
pub path: ImStr,
21+
pub range: Range,
22+
}
23+
24+
impl From<MinLoc> for Location {
25+
fn from(value: MinLoc) -> Self {
26+
Location {
27+
uri: format!("file://{}", value.path).parse().unwrap(),
28+
range: value.range,
29+
}
30+
}
31+
}
32+
1733
pub fn offset_to_position(offset: usize, rope: Rope) -> Option<Position> {
1834
let line = rope.try_char_to_line(offset).ok()?;
1935
let first_char_of_line = rope.try_line_to_char(line).ok()?;

src/utils/str.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl Deref for ImStr {
1818
#[inline]
1919
fn deref(&self) -> &Self::Target {
2020
match &self.0 {
21-
Repr::Arc(inner) => &inner,
21+
Repr::Arc(inner) => inner,
2222
Repr::Inline(len, bytes) => {
2323
let slice = &bytes[..(*len as usize)];
2424
unsafe { std::str::from_utf8_unchecked(slice) }
@@ -116,6 +116,7 @@ impl std::hash::Hash for ImStr {
116116
}
117117

118118
impl ImStr {
119+
#[inline]
119120
pub fn as_str(&self) -> &str {
120121
self.deref()
121122
}

0 commit comments

Comments
 (0)