Skip to content

Commit a565bca

Browse files
committed
feat: goto definitions for python fields
1 parent 3dd6a23 commit a565bca

File tree

7 files changed

+43
-43
lines changed

7 files changed

+43
-43
lines changed

Cargo.lock

Lines changed: 0 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ qp-trie = "0.8.1"
4646
lasso = { version = "0.7.2", features = ["multi-threaded"] }
4747
intmap = "2.0.0"
4848
libflate = "2.0.0"
49-
async-recursion = "1.0.4"
5049

5150
[dev-dependencies]
5251
pretty_assertions = "1.4.0"

examples/two/test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ class Moo(models.Model):
2323

2424
what = fields.Many2one(comodel_name='bar')
2525
def foo(self):
26-
self.env['moo']
26+
self.env['moo'].what
2727
request.render('generic_tax_report')

src/analyze.rs

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{borrow::Borrow, collections::HashMap, sync::OnceLock};
22

3-
use async_recursion::async_recursion;
3+
use futures::executor::block_on;
44
use log::debug;
55
use tree_sitter::{Node, Query, QueryCursor};
66

@@ -82,7 +82,7 @@ fn field_completion() -> &'static Query {
8282
}
8383

8484
impl Backend {
85-
pub async fn model_of_range(
85+
pub fn model_of_range(
8686
&self,
8787
node: Node<'_>,
8888
range: ByteRange,
@@ -149,15 +149,15 @@ impl Backend {
149149
let rhs = child.named_child(1)?;
150150
if lhs.kind() == "identifier" {
151151
let lhs = String::from_utf8_lossy(&contents[lhs.byte_range()]);
152-
let type_ = self.type_of(rhs, &scope, contents).await?;
152+
let type_ = self.type_of(rhs, &scope, contents)?;
153153
scope.insert(lhs.into_owned(), type_);
154154
}
155155
}
156156
"for_statement" => {
157157
let iteratee = child.named_child(0)?;
158158
let src = child.named_child(1)?;
159159
if iteratee.kind() == "identifier" {
160-
let type_ = self.type_of(src, &scope, contents).await?;
160+
let type_ = self.type_of(src, &scope, contents)?;
161161
if let Some(next) = children.peek().cloned() {
162162
stack.push(next);
163163
}
@@ -186,7 +186,7 @@ impl Backend {
186186
// Phase 3: Determine type of cursor expression using recursive ascent
187187
let mut descendant = Some(target?.descendant_for_byte_range(range.start.0, range.end.0)?);
188188
while let Some(descendant_) = descendant {
189-
match self.type_of(descendant_, &scope, contents).await {
189+
match self.type_of(descendant_, &scope, contents) {
190190
Some(Type::Model(model)) => {
191191
return interner().get(model).map(Into::into);
192192
}
@@ -204,9 +204,8 @@ impl Backend {
204204
}
205205
None
206206
}
207-
#[async_recursion(?Send)]
208-
async fn type_of(&self, mut node: Node<'async_recursion>, scope: &Scope, contents: &[u8]) -> Option<Type> {
209-
debug!("type_of {}", String::from_utf8_lossy(&contents[node.byte_range()]));
207+
fn type_of(&self, mut node: Node, scope: &Scope, contents: &[u8]) -> Option<Type> {
208+
// debug!("type_of {}", String::from_utf8_lossy(&contents[node.byte_range()]));
210209
// What creates local scope, but doesn't contribute to method scope?
211210
// 1. For-statements: only within the block
212211
// 2. List comprehension: only within the object
@@ -230,23 +229,22 @@ impl Backend {
230229
// 1. foo.bar;
231230
// foo: Model('t) => bar: Model('t).field('bar')
232231
let interner = interner();
233-
match normalize(&mut node).kind() {
232+
let kind = normalize(&mut node).kind();
233+
match kind {
234234
"subscript" => {
235235
let rhs = node.named_child(1)?;
236+
let rhs_range = rhs.byte_range().contract(1);
236237
if rhs.kind() != "string" {
237238
return None;
238239
}
239-
let obj_ty = self.type_of(node.child(0)?, scope, contents).await?;
240-
matches!(obj_ty, Type::Env).then(|| {
241-
Type::Model(
242-
String::from_utf8_lossy(&contents[rhs.byte_range().contract(1)])
243-
.as_ref()
244-
.into(),
245-
)
246-
})
240+
let lhs = node.named_child(0)?;
241+
let obj_ty = self.type_of(lhs, scope, contents)?;
242+
matches!(obj_ty, Type::Env)
243+
.then(|| Type::Model(String::from_utf8_lossy(&contents[rhs_range]).as_ref().into()))
247244
}
248245
"attribute" => {
249-
let lhs = self.type_of(node.named_child(0)?, scope, contents).await?;
246+
let lhs = node.named_child(0)?;
247+
let lhs = self.type_of(lhs, scope, contents)?;
250248
let rhs = node.named_child(1)?;
251249
match &contents[rhs.byte_range()] {
252250
b"env" if matches!(lhs, Type::Model(..) | Type::Record(..)) => Some(Type::Env),
@@ -276,7 +274,7 @@ impl Backend {
276274
let ident = String::from_utf8_lossy(ident);
277275
let ident = interner.get_or_intern(ident.as_ref());
278276
let mut entry = self.index.models.get_mut(&model.into())?;
279-
let fields = self.populate_field_names(&mut entry).await;
277+
let fields = block_on(self.populate_field_names(&mut entry));
280278
let field = fields.ok()?.get(&ident.into())?;
281279
match field.kind {
282280
FieldKind::Relational(model) => Some(Type::Model(interner.resolve(&model).into())),
@@ -292,11 +290,11 @@ impl Backend {
292290
}
293291
"assignment" => {
294292
let rhs = node.named_child(1)?;
295-
self.type_of(rhs, scope, contents).await
293+
self.type_of(rhs, scope, contents)
296294
}
297295
"call" => {
298296
let func = node.named_child(0)?;
299-
let func = self.type_of(func, scope, contents).await?;
297+
let func = self.type_of(func, scope, contents)?;
300298
match func {
301299
Type::RefFn => {
302300
// (call (_) @func (argument_list . (string) @xml_id))

src/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize};
55

66
use catch_panic::CatchPanic;
77
use dashmap::{DashMap, DashSet};
8+
use futures::executor::block_on;
89
use globwalk::FileType;
910
use lasso::{Key, Spur};
1011
use log::{debug, error, info};
@@ -350,6 +351,7 @@ impl LanguageServer for Backend {
350351
} else if ext == "py" {
351352
location = self
352353
.python_jump_def(params, document.value().clone())
354+
.await
353355
.map_err(|err| error!("Error retrieving references:\n{err}"))
354356
.ok()
355357
.flatten();
@@ -867,11 +869,11 @@ impl Backend {
867869
None => Ok(None),
868870
}
869871
}
870-
async fn jump_def_field_name(&self, field: &str, model: &str) -> miette::Result<Option<Location>> {
872+
fn jump_def_field_name(&self, field: &str, model: &str) -> miette::Result<Option<Location>> {
871873
let model = interner().get_or_intern(model);
872874
let mut entry = some!(self.index.models.get_mut(&model.into()));
873875
let field = some!(interner().get(field));
874-
let fields = self.populate_field_names(&mut entry).await?;
876+
let fields = block_on(self.populate_field_names(&mut entry))?;
875877
let field = some!(fields.get(&field.into()));
876878
Ok(Some(field.location.clone().into()))
877879
}

src/python.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,12 @@ impl Backend {
170170
break 'match_;
171171
};
172172
let lhs = some!(capture.node.prev_named_sibling());
173-
let model = some!(
174-
self.model_of_range(ast.root_node(), lhs.byte_range().map_unit(ByteOffset), None, &bytes)
175-
.await
176-
);
173+
let model = some!(self.model_of_range(
174+
ast.root_node(),
175+
lhs.byte_range().map_unit(ByteOffset),
176+
None,
177+
&bytes
178+
));
177179
let model = interner().resolve(&model);
178180
let needle = Cow::from(slice.byte_slice(..offset - range.start));
179181
let range = range.map_unit(|unit| CharOffset(rope.byte_to_char(unit)));
@@ -189,7 +191,7 @@ impl Backend {
189191
}
190192
Ok(None)
191193
}
192-
pub fn python_jump_def(&self, params: GotoDefinitionParams, rope: Rope) -> miette::Result<Option<Location>> {
194+
pub async fn python_jump_def(&self, params: GotoDefinitionParams, rope: Rope) -> miette::Result<Option<Location>> {
193195
let uri = &params.text_document_position_params.text_document.uri;
194196
let ast = self
195197
.ast_map
@@ -232,6 +234,17 @@ impl Backend {
232234
let slice = Cow::from(slice);
233235
return self.jump_def_model(&slice);
234236
}
237+
} else if capture.index == 10 {
238+
// @access
239+
let range = capture.node.byte_range();
240+
if range.contains(&offset) || range.end == offset {
241+
let lhs = some!(capture.node.prev_named_sibling());
242+
let lhs = lhs.byte_range().map_unit(ByteOffset);
243+
let model = some!(self.model_of_range(ast.root_node(), lhs, None, &bytes));
244+
let field = String::from_utf8_lossy(&bytes[range]);
245+
let model = interner().resolve(&model);
246+
return self.jump_def_field_name(&field, model);
247+
}
235248
}
236249
}
237250
}

src/xml.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ impl Backend {
237237
Some(RefKind::Model) => self.jump_def_model(&cursor_value),
238238
Some(RefKind::FieldName) => {
239239
let model = some!(model_filter);
240-
self.jump_def_field_name(&cursor_value, &model).await
240+
self.jump_def_field_name(&cursor_value, &model)
241241
}
242242
Some(RefKind::Id) | None => Ok(None),
243243
}

0 commit comments

Comments
 (0)