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 imports = self.imports();
let name = match &source {
match &source {
Value::Func(func) => {
func.scope()
.ok_or("cannot import from user-defined functions")
.at(source_span)?;
func.name().unwrap_or_default().into()
if func.scope().is_none() {
bail!(source_span, "cannot import from user-defined functions");
}
Value::Type(ty) => ty.short_name().into(),
}
Value::Type(_) => {}
other => {
let module = import(vm, other.clone(), source_span, true)?;
let name = module.name().clone();
source = Value::Module(module);
name
source = Value::Module(import(vm, other.clone(), source_span, true)?);
}
}
};
if let Some(new_name) = &new_name {
if let ast::Expr::Ident(ident) = self.source() {
@ -1779,6 +1775,7 @@ impl Eval for ast::ModuleImport<'_> {
None => {
// Only import here if there is no rename.
if new_name.is_none() {
let name: EcoString = source.name().unwrap().into();
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.
pub fn docs(&self) -> Option<&'static str> {
match self {

View File

@ -1195,6 +1195,7 @@ impl<'a> CompletionContext<'a> {
}
/// Add completions for definitions that are available at the cursor.
///
/// Filters the global/math scope with the given filter.
fn scope_completions(&mut self, parens: bool, filter: impl Fn(&Value) -> bool) {
let mut defined = BTreeSet::new();
@ -1203,20 +1204,47 @@ impl<'a> CompletionContext<'a> {
while let Some(node) = &ancestor {
let mut sibling = Some(node.clone());
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() {
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();
}
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) {
let pattern = v.pattern();
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() {
self.completions.push(Completion {
kind: CompletionKind::Constant,
label: name.clone(),
label: name,
apply: None,
detail: None,
});