Skip to content

Commit

Permalink
feat: goto-definitions for mapped access
Browse files Browse the repository at this point in the history
  • Loading branch information
Desdaemon committed Dec 2, 2023
1 parent 9d0429d commit 8c6ef47
Show file tree
Hide file tree
Showing 8 changed files with 408 additions and 298 deletions.
13 changes: 5 additions & 8 deletions src/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use tree_sitter::{Node, QueryCursor};

use odoo_lsp::{
index::interner,
model::{FieldKind, ModelName},
model::ModelName,
utils::{ByteRange, Erase, PreTravel, RangeExt},
ImStr,
};
Expand Down Expand Up @@ -323,13 +323,10 @@ impl Backend {
};
let ident = String::from_utf8_lossy(ident);
let ident = interner.get_or_intern(ident.as_ref());
let entry = self.populate_field_names(model, &[])?;
let entry = block_on(entry);
let field = entry.fields.as_ref()?.get(&ident.into())?;
match field.kind {
FieldKind::Relational(model) => Some(Type::Model(interner.resolve(&model).into())),
FieldKind::Value => None,
}
block_on(self.index.models.populate_field_names(model, &[])?);
let relation =
block_on(self.index.models.normalize_field_relation(ident.into(), model.into()))?;
Some(Type::Model(interner.resolve(&relation).into()))
}
_ => None,
}
Expand Down
8 changes: 4 additions & 4 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ impl Backend {
}
let model_key = interner().get_or_intern(&model);
let range = char_range_to_lsp_range(range, rope).ok_or_else(|| diagnostic!("range"))?;
let Some(entry) = self.populate_field_names(model_key.into(), &[]) else {
let Some(entry) = self.index.models.populate_field_names(model_key.into(), &[]) else {
return Ok(());
};
let entry = entry.await;
Expand Down Expand Up @@ -373,7 +373,7 @@ impl Backend {
pub async fn jump_def_field_name(&self, field: &str, model: &str) -> miette::Result<Option<Location>> {
let model_key = interner().get_or_intern(model);
let field = some!(interner().get(field));
let entry = some!(self.populate_field_names(model_key.into(), &[])).await;
let entry = some!(self.index.models.populate_field_names(model_key.into(), &[])).await;
let field = some!(entry.fields.as_ref()).get(&field.into());
Ok(Some(some!(field).location.clone().into()))
}
Expand All @@ -391,7 +391,7 @@ impl Backend {
) -> miette::Result<Option<Hover>> {
let model_key = interner().get_or_intern(model);
let field = some!(interner().get(name));
let fields = some!(self.populate_field_names(model_key.into(), &[])).await;
let fields = some!(self.index.models.populate_field_names(model_key.into(), &[])).await;
let field = some!(fields.fields.as_ref()).get(&field.into());
Ok(Some(Hover {
range,
Expand Down Expand Up @@ -526,7 +526,7 @@ impl Backend {
let type_ = interner().resolve(&field.type_);
if signature {
match &field.kind {
FieldKind::Value => {
FieldKind::Value | FieldKind::Related(_) => {
out = format!(concat!("```python\n", "{} = fields.{}(…)\n", "```\n\n"), name, type_)
}
FieldKind::Relational(relation) => {
Expand Down
4 changes: 4 additions & 0 deletions src/index/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ impl<K, T> SymbolMap<K, T> {
pub fn get(&self, key: &Symbol<K>) -> Option<&T> {
self.0.get(key.into_usize() as u64)
}
#[inline]
pub fn get_mut(&mut self, key: &Symbol<K>) -> Option<&mut T> {
self.0.get_mut(key.into_usize() as u64)
}
pub fn keys(&self) -> impl Iterator<Item = Symbol<K>> + '_ {
self.0
.iter()
Expand Down
7 changes: 7 additions & 0 deletions src/index/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ impl<T> From<Spur> for Symbol<T> {
}
}

impl<T> From<Symbol<T>> for Spur {
#[inline]
fn from(value: Symbol<T>) -> Self {
value.inner
}
}

impl<T> Clone for Symbol<T> {
#[inline]
fn clone(&self) -> Self {
Expand Down
29 changes: 19 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use tower_lsp::{LanguageServer, LspService, Server};

use odoo_lsp::config::Config;
use odoo_lsp::index::{interner, Interner};
use odoo_lsp::model::FieldKind;
use odoo_lsp::{format_loc, some, utils::*};

mod analyze;
Expand Down Expand Up @@ -462,7 +461,7 @@ impl LanguageServer for Backend {
}))
}
Some(CompletionItemKind::FIELD) => {
// NOTE: This was injected by complete().
// NOTE: This was injected by complete_field_name().
let Some(Value::String(value)) = &completion.data else {
break 'resolve;
};
Expand All @@ -473,22 +472,32 @@ impl LanguageServer for Backend {
let Some(model) = interner().get(value) else {
break 'resolve;
};
let Some(entry) = self.index.models.get(&model.into()) else {
let Some(mut entry) = self
.index
.models
.try_get_mut(&model.into())
.expect(format_loc!("deadlock"))
else {
break 'resolve;
};
let Some(fields) = &mut entry.fields else {
break 'resolve;
};
let Some(fields) = &entry.fields else { break 'resolve };
if let Some(field) = fields.get(&field.into()) {
let type_ = interner().resolve(&field.type_);
completion.detail = match field.kind {
FieldKind::Value => Some(format!("{type_}(…)")),
FieldKind::Relational(relation) => {
let field_entry = fields.get(&field.into()).cloned();
drop(entry);
if let Some(field_entry) = field_entry {
let type_ = interner().resolve(&field_entry.type_);
completion.detail = match self.index.models.normalize_field_relation(field.into(), model).await
{
None => Some(format!("{type_}(…)")),
Some(relation) => {
let relation = interner().resolve(&relation);
Some(format!("{type_}(\"{relation}\", …)"))
}
};
completion.documentation = Some(Documentation::MarkupContent(MarkupContent {
kind: MarkupKind::Markdown,
value: self.field_docstring(field_name, field, false),
value: self.field_docstring(field_name, &field_entry, false),
}))
}
}
Expand Down
Loading

0 comments on commit 8c6ef47

Please sign in to comment.