mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Scope completions for imports
This commit is contained in:
parent
71a21b7ec1
commit
72f4c543cc
@ -1743,21 +1743,17 @@ impl Eval for ast::ModuleImport<'_> {
|
|||||||
let new_name = self.new_name();
|
let new_name = self.new_name();
|
||||||
let imports = self.imports();
|
let imports = self.imports();
|
||||||
|
|
||||||
let name = match &source {
|
match &source {
|
||||||
Value::Func(func) => {
|
Value::Func(func) => {
|
||||||
func.scope()
|
if func.scope().is_none() {
|
||||||
.ok_or("cannot import from user-defined functions")
|
bail!(source_span, "cannot import from user-defined functions");
|
||||||
.at(source_span)?;
|
|
||||||
func.name().unwrap_or_default().into()
|
|
||||||
}
|
}
|
||||||
Value::Type(ty) => ty.short_name().into(),
|
}
|
||||||
|
Value::Type(_) => {}
|
||||||
other => {
|
other => {
|
||||||
let module = import(vm, other.clone(), source_span, true)?;
|
source = Value::Module(import(vm, other.clone(), source_span, true)?);
|
||||||
let name = module.name().clone();
|
}
|
||||||
source = Value::Module(module);
|
|
||||||
name
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(new_name) = &new_name {
|
if let Some(new_name) = &new_name {
|
||||||
if let ast::Expr::Ident(ident) = self.source() {
|
if let ast::Expr::Ident(ident) = self.source() {
|
||||||
@ -1779,6 +1775,7 @@ impl Eval for ast::ModuleImport<'_> {
|
|||||||
None => {
|
None => {
|
||||||
// Only import here if there is no rename.
|
// Only import here if there is no rename.
|
||||||
if new_name.is_none() {
|
if new_name.is_none() {
|
||||||
|
let name: EcoString = source.name().unwrap().into();
|
||||||
vm.scopes.top.define(name, source);
|
vm.scopes.top.define(name, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,16 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The name, if this is a function, type, or module.
|
||||||
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Self::Func(func) => func.name(),
|
||||||
|
Self::Type(ty) => Some(ty.short_name()),
|
||||||
|
Self::Module(module) => Some(module.name()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Try to extract documentation for the value.
|
/// Try to extract documentation for the value.
|
||||||
pub fn docs(&self) -> Option<&'static str> {
|
pub fn docs(&self) -> Option<&'static str> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -1195,6 +1195,7 @@ impl<'a> CompletionContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add completions for definitions that are available at the cursor.
|
/// Add completions for definitions that are available at the cursor.
|
||||||
|
///
|
||||||
/// Filters the global/math scope with the given filter.
|
/// Filters the global/math scope with the given filter.
|
||||||
fn scope_completions(&mut self, parens: bool, filter: impl Fn(&Value) -> bool) {
|
fn scope_completions(&mut self, parens: bool, filter: impl Fn(&Value) -> bool) {
|
||||||
let mut defined = BTreeSet::new();
|
let mut defined = BTreeSet::new();
|
||||||
@ -1203,20 +1204,47 @@ impl<'a> CompletionContext<'a> {
|
|||||||
while let Some(node) = &ancestor {
|
while let Some(node) = &ancestor {
|
||||||
let mut sibling = Some(node.clone());
|
let mut sibling = Some(node.clone());
|
||||||
while let Some(node) = &sibling {
|
while let Some(node) = &sibling {
|
||||||
if let Some(v) = node.get().cast::<ast::LetBinding>() {
|
if let Some(v) = node.cast::<ast::LetBinding>() {
|
||||||
for ident in v.kind().idents() {
|
for ident in v.kind().idents() {
|
||||||
defined.insert(ident.get());
|
defined.insert(ident.get().clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(v) = node.cast::<ast::ModuleImport>() {
|
||||||
|
let imports = v.imports();
|
||||||
|
match imports {
|
||||||
|
None | Some(ast::Imports::Wildcard) => {
|
||||||
|
if let Some(value) = node
|
||||||
|
.children()
|
||||||
|
.find(|child| child.is::<ast::Expr>())
|
||||||
|
.and_then(|source| analyze_import(self.world, &source))
|
||||||
|
{
|
||||||
|
if imports.is_none() {
|
||||||
|
defined.extend(value.name().map(Into::into));
|
||||||
|
} else if let Some(scope) = value.scope() {
|
||||||
|
for (name, _) in scope.iter() {
|
||||||
|
defined.insert(name.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(ast::Imports::Items(items)) => {
|
||||||
|
for item in items.iter() {
|
||||||
|
defined.insert(item.bound_name().get().clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sibling = node.prev_sibling();
|
sibling = node.prev_sibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(parent) = node.parent() {
|
if let Some(parent) = node.parent() {
|
||||||
if let Some(v) = parent.get().cast::<ast::ForLoop>() {
|
if let Some(v) = parent.cast::<ast::ForLoop>() {
|
||||||
if node.prev_sibling_kind() != Some(SyntaxKind::In) {
|
if node.prev_sibling_kind() != Some(SyntaxKind::In) {
|
||||||
let pattern = v.pattern();
|
let pattern = v.pattern();
|
||||||
for ident in pattern.idents() {
|
for ident in pattern.idents() {
|
||||||
defined.insert(ident.get());
|
defined.insert(ident.get().clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1247,7 +1275,7 @@ impl<'a> CompletionContext<'a> {
|
|||||||
if !name.is_empty() {
|
if !name.is_empty() {
|
||||||
self.completions.push(Completion {
|
self.completions.push(Completion {
|
||||||
kind: CompletionKind::Constant,
|
kind: CompletionKind::Constant,
|
||||||
label: name.clone(),
|
label: name,
|
||||||
apply: None,
|
apply: None,
|
||||||
detail: None,
|
detail: None,
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user