diff options
| author | Laurenz <laurmaedje@gmail.com> | 2025-01-29 15:20:30 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-29 14:20:30 +0000 |
| commit | 1b2719c94c6422112508cfad24bdd9504541c363 (patch) | |
| tree | f58682b5203b3448a560b2efd3f50c4c7d79372b /crates/typst-ide | |
| parent | 9665eecdb62ee94cd9fcf4dfc61e2c70ba9391fb (diff) | |
Resolve bound name of bare import statically (#5773)
Diffstat (limited to 'crates/typst-ide')
| -rw-r--r-- | crates/typst-ide/src/matchers.rs | 88 |
1 files changed, 49 insertions, 39 deletions
diff --git a/crates/typst-ide/src/matchers.rs b/crates/typst-ide/src/matchers.rs index b92cbf55..ef8288f2 100644 --- a/crates/typst-ide/src/matchers.rs +++ b/crates/typst-ide/src/matchers.rs @@ -1,7 +1,7 @@ use ecow::EcoString; use typst::foundations::{Module, Value}; use typst::syntax::ast::AstNode; -use typst::syntax::{ast, LinkedNode, Span, SyntaxKind, SyntaxNode}; +use typst::syntax::{ast, LinkedNode, Span, SyntaxKind}; use crate::{analyze_import, IdeWorld}; @@ -30,38 +30,38 @@ pub fn named_items<T>( if let Some(v) = node.cast::<ast::ModuleImport>() { let imports = v.imports(); - let source = node - .children() - .find(|child| child.is::<ast::Expr>()) - .and_then(|source: LinkedNode| { - Some((analyze_import(world, &source)?, source)) - }); - let source = source.as_ref(); + let source = v.source(); + + let source_value = node + .find(source.span()) + .and_then(|source| analyze_import(world, &source)); + let source_value = source_value.as_ref(); + + let module = source_value.and_then(|value| match value { + Value::Module(module) => Some(module), + _ => None, + }); + + let name_and_span = match (imports, v.new_name()) { + // ```plain + // import "foo" as name + // import "foo" as name: .. + // ``` + (_, Some(name)) => Some((name.get().clone(), name.span())), + // ```plain + // import "foo" + // ``` + (None, None) => v.bare_name().ok().map(|name| (name, source.span())), + // ```plain + // import "foo": .. + // ``` + (Some(..), None) => None, + }; // Seeing the module itself. - if let Some((value, source)) = source { - let site = match (imports, v.new_name()) { - // ```plain - // import "foo" as name; - // import "foo" as name: ..; - // ``` - (_, Some(name)) => Some(name.to_untyped()), - // ```plain - // import "foo"; - // ``` - (None, None) => Some(source.get()), - // ```plain - // import "foo": ..; - // ``` - (Some(..), None) => None, - }; - - if let Some((site, value)) = - site.zip(value.clone().cast::<Module>().ok()) - { - if let Some(res) = recv(NamedItem::Module(&value, site)) { - return Some(res); - } + if let Some((name, span)) = name_and_span { + if let Some(res) = recv(NamedItem::Module(&name, span, module)) { + return Some(res); } } @@ -75,7 +75,7 @@ pub fn named_items<T>( // import "foo": *; // ``` Some(ast::Imports::Wildcard) => { - if let Some(scope) = source.and_then(|(value, _)| value.scope()) { + if let Some(scope) = source_value.and_then(Value::scope) { for (name, value, span) in scope.iter() { let item = NamedItem::Import(name, span, Some(value)); if let Some(res) = recv(item) { @@ -92,7 +92,7 @@ pub fn named_items<T>( let bound = item.bound_name(); let (span, value) = item.path().iter().fold( - (bound.span(), source.map(|(value, _)| value)), + (bound.span(), source_value), |(span, value), path_ident| { let scope = value.and_then(|v| v.scope()); let span = scope @@ -175,8 +175,8 @@ pub enum NamedItem<'a> { Var(ast::Ident<'a>), /// A function item. Fn(ast::Ident<'a>), - /// A (imported) module item. - Module(&'a Module, &'a SyntaxNode), + /// A (imported) module. + Module(&'a EcoString, Span, Option<&'a Module>), /// An imported item. Import(&'a EcoString, Span, Option<&'a Value>), } @@ -186,7 +186,7 @@ impl<'a> NamedItem<'a> { match self { NamedItem::Var(ident) => ident.get(), NamedItem::Fn(ident) => ident.get(), - NamedItem::Module(value, _) => value.name(), + NamedItem::Module(name, _, _) => name, NamedItem::Import(name, _, _) => name, } } @@ -194,7 +194,7 @@ impl<'a> NamedItem<'a> { pub(crate) fn value(&self) -> Option<Value> { match self { NamedItem::Var(..) | NamedItem::Fn(..) => None, - NamedItem::Module(value, _) => Some(Value::Module((*value).clone())), + NamedItem::Module(_, _, value) => value.cloned().map(Value::Module), NamedItem::Import(_, _, value) => value.cloned(), } } @@ -202,7 +202,7 @@ impl<'a> NamedItem<'a> { pub(crate) fn span(&self) -> Span { match *self { NamedItem::Var(name) | NamedItem::Fn(name) => name.span(), - NamedItem::Module(_, site) => site.span(), + NamedItem::Module(_, span, _) => span, NamedItem::Import(_, span, _) => span, } } @@ -356,7 +356,17 @@ mod tests { #[test] fn test_named_items_import() { - test("#import \"foo.typ\": a; #(a);", 2).must_include(["a"]); + test("#import \"foo.typ\"", 2).must_include(["foo"]); + test("#import \"foo.typ\" as bar", 2) + .must_include(["bar"]) + .must_exclude(["foo"]); + } + + #[test] + fn test_named_items_import_items() { + test("#import \"foo.typ\": a; #(a);", 2) + .must_include(["a"]) + .must_exclude(["foo"]); let world = TestWorld::new("#import \"foo.typ\": a.b; #(b);") .with_source("foo.typ", "#import \"a.typ\"") |
