Scope completions for imports

This commit is contained in:
Laurenz 2023-09-23 01:35:03 +02:00
parent 71a21b7ec1
commit 72f4c543cc
3 changed files with 51 additions and 16 deletions

View File

@ -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);
} }
} }

View File

@ -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 {

View File

@ -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,
}); });