mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Spans for cross-file go-to-definition (#4539)
This commit is contained in:
parent
02d0128dde
commit
7437352638
@ -52,7 +52,6 @@ pub fn analyze_expr(
|
|||||||
pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> {
|
pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> {
|
||||||
// Use span in the node for resolving imports with relative paths.
|
// Use span in the node for resolving imports with relative paths.
|
||||||
let source_span = source.span();
|
let source_span = source.span();
|
||||||
|
|
||||||
let (source, _) = analyze_expr(world, source).into_iter().next()?;
|
let (source, _) = analyze_expr(world, source).into_iter().next()?;
|
||||||
if source.scope().is_some() {
|
if source.scope().is_some() {
|
||||||
return Some(source);
|
return Some(source);
|
||||||
@ -76,6 +75,7 @@ pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option<Value> {
|
|||||||
Scopes::new(Some(world.library())),
|
Scopes::new(Some(world.library())),
|
||||||
Span::detached(),
|
Span::detached(),
|
||||||
);
|
);
|
||||||
|
|
||||||
typst::eval::import(&mut vm, source, source_span, true)
|
typst::eval::import(&mut vm, source, source_span, true)
|
||||||
.ok()
|
.ok()
|
||||||
.map(Value::Module)
|
.map(Value::Module)
|
||||||
|
@ -378,12 +378,12 @@ fn field_access_completions(
|
|||||||
value: &Value,
|
value: &Value,
|
||||||
styles: &Option<Styles>,
|
styles: &Option<Styles>,
|
||||||
) {
|
) {
|
||||||
for (name, value) in value.ty().scope().iter() {
|
for (name, value, _) in value.ty().scope().iter() {
|
||||||
ctx.value_completion(Some(name.clone()), value, true, None);
|
ctx.value_completion(Some(name.clone()), value, true, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(scope) = value.scope() {
|
if let Some(scope) = value.scope() {
|
||||||
for (name, value) in scope.iter() {
|
for (name, value, _) in scope.iter() {
|
||||||
ctx.value_completion(Some(name.clone()), value, true, None);
|
ctx.value_completion(Some(name.clone()), value, true, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -549,7 +549,7 @@ fn import_item_completions<'a>(
|
|||||||
ctx.snippet_completion("*", "*", "Import everything.");
|
ctx.snippet_completion("*", "*", "Import everything.");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, value) in scope.iter() {
|
for (name, value, _) in scope.iter() {
|
||||||
if existing.iter().all(|item| item.original_name().as_str() != name) {
|
if existing.iter().all(|item| item.original_name().as_str() != name) {
|
||||||
ctx.value_completion(Some(name.clone()), value, false, None);
|
ctx.value_completion(Some(name.clone()), value, false, None);
|
||||||
}
|
}
|
||||||
@ -1337,7 +1337,7 @@ impl<'a> CompletionContext<'a> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let scope = if in_math { self.math } else { self.global };
|
let scope = if in_math { self.math } else { self.global };
|
||||||
for (name, value) in scope.iter() {
|
for (name, value, _) in scope.iter() {
|
||||||
if filter(value) && !defined.contains(name) {
|
if filter(value) && !defined.contains(name) {
|
||||||
self.value_completion(Some(name.clone()), value, parens, None);
|
self.value_completion(Some(name.clone()), value, parens, None);
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,7 @@ pub fn definition(
|
|||||||
let root = LinkedNode::new(source.root());
|
let root = LinkedNode::new(source.root());
|
||||||
let leaf = root.leaf_at(cursor, side)?;
|
let leaf = root.leaf_at(cursor, side)?;
|
||||||
|
|
||||||
let target = deref_target(leaf.clone())?;
|
let mut use_site = match deref_target(leaf.clone())? {
|
||||||
|
|
||||||
let mut use_site = match target {
|
|
||||||
DerefTarget::VarAccess(node) | DerefTarget::Callee(node) => node,
|
DerefTarget::VarAccess(node) | DerefTarget::Callee(node) => node,
|
||||||
DerefTarget::IncludePath(path) | DerefTarget::ImportPath(path) => {
|
DerefTarget::IncludePath(path) | DerefTarget::ImportPath(path) => {
|
||||||
let import_item =
|
let import_item =
|
||||||
@ -82,10 +80,10 @@ pub fn definition(
|
|||||||
.then_some(site.span())
|
.then_some(site.span())
|
||||||
.unwrap_or_else(Span::detached),
|
.unwrap_or_else(Span::detached),
|
||||||
)),
|
)),
|
||||||
NamedItem::Import(name, span, value) => Some(Definition::item(
|
NamedItem::Import(name, name_span, value) => Some(Definition::item(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
Span::detached(),
|
Span::detached(),
|
||||||
span,
|
name_span,
|
||||||
value.cloned(),
|
value.cloned(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
@ -99,14 +97,14 @@ pub fn definition(
|
|||||||
| Some(SyntaxKind::MathFrac)
|
| Some(SyntaxKind::MathFrac)
|
||||||
| Some(SyntaxKind::MathAttach)
|
| Some(SyntaxKind::MathAttach)
|
||||||
);
|
);
|
||||||
let library = world.library();
|
|
||||||
|
|
||||||
|
let library = world.library();
|
||||||
let scope = if in_math { library.math.scope() } else { library.global.scope() };
|
let scope = if in_math { library.math.scope() } else { library.global.scope() };
|
||||||
for (item_name, value) in scope.iter() {
|
for (item_name, value, span) in scope.iter() {
|
||||||
if *item_name == name {
|
if *item_name == name {
|
||||||
return Some(Definition::item(
|
return Some(Definition::item(
|
||||||
name,
|
name,
|
||||||
Span::detached(),
|
span,
|
||||||
Span::detached(),
|
Span::detached(),
|
||||||
Some(value.clone()),
|
Some(value.clone()),
|
||||||
));
|
));
|
||||||
|
@ -77,12 +77,8 @@ pub fn named_items<T>(
|
|||||||
// ```
|
// ```
|
||||||
Some(ast::Imports::Wildcard) => {
|
Some(ast::Imports::Wildcard) => {
|
||||||
if let Some(scope) = source.and_then(|(value, _)| value.scope()) {
|
if let Some(scope) = source.and_then(|(value, _)| value.scope()) {
|
||||||
for (name, value) in scope.iter() {
|
for (name, value, span) in scope.iter() {
|
||||||
let item = NamedItem::Import(
|
let item = NamedItem::Import(name, span, Some(value));
|
||||||
name,
|
|
||||||
Span::detached(),
|
|
||||||
Some(value),
|
|
||||||
);
|
|
||||||
if let Some(res) = recv(item) {
|
if let Some(res) = recv(item) {
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
@ -94,9 +90,17 @@ pub fn named_items<T>(
|
|||||||
// ```
|
// ```
|
||||||
Some(ast::Imports::Items(items)) => {
|
Some(ast::Imports::Items(items)) => {
|
||||||
for item in items.iter() {
|
for item in items.iter() {
|
||||||
let name = item.bound_name();
|
let original = item.original_name();
|
||||||
|
let bound = item.bound_name();
|
||||||
|
let scope = source.and_then(|(value, _)| value.scope());
|
||||||
|
let span = scope
|
||||||
|
.and_then(|s| s.get_span(&original))
|
||||||
|
.unwrap_or(Span::detached())
|
||||||
|
.or(bound.span());
|
||||||
|
|
||||||
|
let value = scope.and_then(|s| s.get(&original));
|
||||||
if let Some(res) =
|
if let Some(res) =
|
||||||
recv(NamedItem::Import(name.get(), name.span(), None))
|
recv(NamedItem::Import(bound.get(), span, value))
|
||||||
{
|
{
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ fn closure_tooltip(leaf: &LinkedNode) -> Option<Tooltip> {
|
|||||||
|
|
||||||
let captures = visitor.finish();
|
let captures = visitor.finish();
|
||||||
let mut names: Vec<_> =
|
let mut names: Vec<_> =
|
||||||
captures.iter().map(|(name, _)| eco_format!("`{name}`")).collect();
|
captures.iter().map(|(name, ..)| eco_format!("`{name}`")).collect();
|
||||||
if names.is_empty() {
|
if names.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,15 @@ impl Span {
|
|||||||
self.0.get() & ((1 << Self::BITS) - 1)
|
self.0.get() & ((1 << Self::BITS) - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return `other` if `self` is detached and `self` otherwise.
|
||||||
|
pub fn or(self, other: Self) -> Self {
|
||||||
|
if self.is_detached() {
|
||||||
|
other
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve a file location relative to this span's source.
|
/// Resolve a file location relative to this span's source.
|
||||||
pub fn resolve_path(self, path: &str) -> Result<FileId, EcoString> {
|
pub fn resolve_path(self, path: &str) -> Result<FileId, EcoString> {
|
||||||
let Some(file) = self.id() else {
|
let Some(file) = self.id() else {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use comemo::{Tracked, TrackedMut};
|
use comemo::{Tracked, TrackedMut};
|
||||||
use ecow::{eco_format, EcoVec};
|
use ecow::{eco_format, EcoString, EcoVec};
|
||||||
|
|
||||||
use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint};
|
use crate::diag::{bail, error, At, HintedStrResult, SourceResult, Trace, Tracepoint};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
@ -410,9 +410,11 @@ impl<'a> CapturesVisitor<'a> {
|
|||||||
// Identifiers that shouldn't count as captures because they
|
// Identifiers that shouldn't count as captures because they
|
||||||
// actually bind a new name are handled below (individually through
|
// actually bind a new name are handled below (individually through
|
||||||
// the expressions that contain them).
|
// the expressions that contain them).
|
||||||
Some(ast::Expr::Ident(ident)) => self.capture(&ident, Scopes::get),
|
Some(ast::Expr::Ident(ident)) => {
|
||||||
|
self.capture(ident.get(), ident.span(), Scopes::get)
|
||||||
|
}
|
||||||
Some(ast::Expr::MathIdent(ident)) => {
|
Some(ast::Expr::MathIdent(ident)) => {
|
||||||
self.capture(&ident, Scopes::get_in_math)
|
self.capture(ident.get(), ident.span(), Scopes::get_in_math)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code and content blocks create a scope.
|
// Code and content blocks create a scope.
|
||||||
@ -520,13 +522,14 @@ impl<'a> CapturesVisitor<'a> {
|
|||||||
|
|
||||||
/// Bind a new internal variable.
|
/// Bind a new internal variable.
|
||||||
fn bind(&mut self, ident: ast::Ident) {
|
fn bind(&mut self, ident: ast::Ident) {
|
||||||
self.internal.top.define(ident.get().clone(), Value::None);
|
self.internal.top.define_ident(ident, Value::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Capture a variable if it isn't internal.
|
/// Capture a variable if it isn't internal.
|
||||||
fn capture(
|
fn capture(
|
||||||
&mut self,
|
&mut self,
|
||||||
ident: &str,
|
ident: &EcoString,
|
||||||
|
span: Span,
|
||||||
getter: impl FnOnce(&'a Scopes<'a>, &str) -> HintedStrResult<&'a Value>,
|
getter: impl FnOnce(&'a Scopes<'a>, &str) -> HintedStrResult<&'a Value>,
|
||||||
) {
|
) {
|
||||||
if self.internal.get(ident).is_err() {
|
if self.internal.get(ident).is_err() {
|
||||||
@ -538,7 +541,12 @@ impl<'a> CapturesVisitor<'a> {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.captures.define_captured(ident, value.clone(), self.capturer);
|
self.captures.define_captured(
|
||||||
|
ident.clone(),
|
||||||
|
value.clone(),
|
||||||
|
self.capturer,
|
||||||
|
span,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -561,7 +569,7 @@ mod tests {
|
|||||||
visitor.visit(&root);
|
visitor.visit(&root);
|
||||||
|
|
||||||
let captures = visitor.finish();
|
let captures = visitor.finish();
|
||||||
let mut names: Vec<_> = captures.iter().map(|(k, _)| k).collect();
|
let mut names: Vec<_> = captures.iter().map(|(k, ..)| k).collect();
|
||||||
names.sort();
|
names.sort();
|
||||||
|
|
||||||
assert_eq!(names, result);
|
assert_eq!(names, result);
|
||||||
|
@ -31,7 +31,7 @@ impl Eval for ast::ModuleImport<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
||||||
if ident.as_str() == new_name.as_str() {
|
if ident.as_str() == new_name.as_str() {
|
||||||
// Warn on `import x as x`
|
// Warn on `import x as x`
|
||||||
@ -43,7 +43,7 @@ impl Eval for ast::ModuleImport<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Define renamed module on the scope.
|
// Define renamed module on the scope.
|
||||||
vm.scopes.top.define(new_name.as_str(), source.clone());
|
vm.scopes.top.define_ident(new_name, source.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let scope = source.scope().unwrap();
|
let scope = source.scope().unwrap();
|
||||||
@ -56,8 +56,8 @@ impl Eval for ast::ModuleImport<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(ast::Imports::Wildcard) => {
|
Some(ast::Imports::Wildcard) => {
|
||||||
for (var, value) in scope.iter() {
|
for (var, value, span) in scope.iter() {
|
||||||
vm.scopes.top.define(var.clone(), value.clone());
|
vm.scopes.top.define_spanned(var.clone(), value.clone(), span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(ast::Imports::Items(items)) => {
|
Some(ast::Imports::Items(items)) => {
|
||||||
|
@ -47,7 +47,7 @@ impl<'a> Vm<'a> {
|
|||||||
if self.inspected == Some(var.span()) {
|
if self.inspected == Some(var.span()) {
|
||||||
self.trace(value.clone());
|
self.trace(value.clone());
|
||||||
}
|
}
|
||||||
self.scopes.top.define(var.get().clone(), value);
|
self.scopes.top.define_ident(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trace a value.
|
/// Trace a value.
|
||||||
|
@ -261,7 +261,7 @@ pub struct ToDict(Dict);
|
|||||||
|
|
||||||
cast! {
|
cast! {
|
||||||
ToDict,
|
ToDict,
|
||||||
v: Module => Self(v.scope().iter().map(|(k, v)| (Str::from(k.clone()), v.clone())).collect()),
|
v: Module => Self(v.scope().iter().map(|(k, v, _)| (Str::from(k.clone()), v.clone())).collect()),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Dict {
|
impl Debug for Dict {
|
||||||
|
@ -290,7 +290,7 @@ pub fn eval(
|
|||||||
let dict = scope;
|
let dict = scope;
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
for (key, value) in dict {
|
for (key, value) in dict {
|
||||||
scope.define(key, value);
|
scope.define_spanned(key, value, span);
|
||||||
}
|
}
|
||||||
crate::eval::eval_string(engine.world, &text, span, mode, scope)
|
crate::eval::eval_string(engine.world, &text, span, mode, scope)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ use crate::foundations::{
|
|||||||
Element, Func, IntoValue, Module, NativeElement, NativeFunc, NativeFuncData,
|
Element, Func, IntoValue, Module, NativeElement, NativeFunc, NativeFuncData,
|
||||||
NativeType, Type, Value,
|
NativeType, Type, Value,
|
||||||
};
|
};
|
||||||
|
use crate::syntax::ast::{self, AstNode};
|
||||||
|
use crate::syntax::Span;
|
||||||
use crate::util::Static;
|
use crate::util::Static;
|
||||||
use crate::Library;
|
use crate::Library;
|
||||||
|
|
||||||
@ -129,6 +131,23 @@ impl Scope {
|
|||||||
/// Bind a value to a name.
|
/// Bind a value to a name.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn define(&mut self, name: impl Into<EcoString>, value: impl IntoValue) {
|
pub fn define(&mut self, name: impl Into<EcoString>, value: impl IntoValue) {
|
||||||
|
self.define_spanned(name, value, Span::detached())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bind a value to a name defined by an identifier.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn define_ident(&mut self, ident: ast::Ident, value: impl IntoValue) {
|
||||||
|
self.define_spanned(ident.get().clone(), value, ident.span())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bind a value to a name.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn define_spanned(
|
||||||
|
&mut self,
|
||||||
|
name: impl Into<EcoString>,
|
||||||
|
value: impl IntoValue,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
@ -136,8 +155,24 @@ impl Scope {
|
|||||||
panic!("duplicate definition: {name}");
|
panic!("duplicate definition: {name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.map
|
self.map.insert(
|
||||||
.insert(name, Slot::new(value.into_value(), Kind::Normal, self.category));
|
name,
|
||||||
|
Slot::new(value.into_value(), span, Kind::Normal, self.category),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Define a captured, immutable binding.
|
||||||
|
pub fn define_captured(
|
||||||
|
&mut self,
|
||||||
|
name: EcoString,
|
||||||
|
value: Value,
|
||||||
|
capturer: Capturer,
|
||||||
|
span: Span,
|
||||||
|
) {
|
||||||
|
self.map.insert(
|
||||||
|
name,
|
||||||
|
Slot::new(value.into_value(), span, Kind::Captured(capturer), self.category),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define a native function through a Rust type that shadows the function.
|
/// Define a native function through a Rust type that shadows the function.
|
||||||
@ -168,19 +203,6 @@ impl Scope {
|
|||||||
self.define(module.name().clone(), module);
|
self.define(module.name().clone(), module);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define a captured, immutable binding.
|
|
||||||
pub fn define_captured(
|
|
||||||
&mut self,
|
|
||||||
var: impl Into<EcoString>,
|
|
||||||
value: impl IntoValue,
|
|
||||||
capturer: Capturer,
|
|
||||||
) {
|
|
||||||
self.map.insert(
|
|
||||||
var.into(),
|
|
||||||
Slot::new(value.into_value(), Kind::Captured(capturer), self.category),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to access a variable immutably.
|
/// Try to access a variable immutably.
|
||||||
pub fn get(&self, var: &str) -> Option<&Value> {
|
pub fn get(&self, var: &str) -> Option<&Value> {
|
||||||
self.map.get(var).map(Slot::read)
|
self.map.get(var).map(Slot::read)
|
||||||
@ -194,14 +216,19 @@ impl Scope {
|
|||||||
.map(|res| res.map_err(HintedString::from))
|
.map(|res| res.map_err(HintedString::from))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the span of a definition.
|
||||||
|
pub fn get_span(&self, var: &str) -> Option<Span> {
|
||||||
|
Some(self.map.get(var)?.span)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the category of a definition.
|
/// Get the category of a definition.
|
||||||
pub fn get_category(&self, var: &str) -> Option<Category> {
|
pub fn get_category(&self, var: &str) -> Option<Category> {
|
||||||
self.map.get(var)?.category
|
self.map.get(var)?.category
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over all definitions.
|
/// Iterate over all definitions.
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (&EcoString, &Value)> {
|
pub fn iter(&self) -> impl Iterator<Item = (&EcoString, &Value, Span)> {
|
||||||
self.map.iter().map(|(k, v)| (k, v.read()))
|
self.map.iter().map(|(k, v)| (k, v.read(), v.span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,6 +268,8 @@ struct Slot {
|
|||||||
value: Value,
|
value: Value,
|
||||||
/// The kind of slot, determines how the value can be accessed.
|
/// The kind of slot, determines how the value can be accessed.
|
||||||
kind: Kind,
|
kind: Kind,
|
||||||
|
/// A span associated with the stored value.
|
||||||
|
span: Span,
|
||||||
/// The category of the slot.
|
/// The category of the slot.
|
||||||
category: Option<Category>,
|
category: Option<Category>,
|
||||||
}
|
}
|
||||||
@ -265,8 +294,8 @@ pub enum Capturer {
|
|||||||
|
|
||||||
impl Slot {
|
impl Slot {
|
||||||
/// Create a new slot.
|
/// Create a new slot.
|
||||||
fn new(value: Value, kind: Kind, category: Option<Category>) -> Self {
|
fn new(value: Value, span: Span, kind: Kind, category: Option<Category>) -> Self {
|
||||||
Self { value, kind, category }
|
Self { value, span, kind, category }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the value.
|
/// Read the value.
|
||||||
|
@ -48,8 +48,8 @@ static GROUPS: Lazy<Vec<GroupData>> = Lazy::new(|| {
|
|||||||
.module()
|
.module()
|
||||||
.scope()
|
.scope()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, v)| matches!(v, Value::Func(_)))
|
.filter(|(_, v, _)| matches!(v, Value::Func(_)))
|
||||||
.map(|(k, _)| k.clone())
|
.map(|(k, _, _)| k.clone())
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -253,7 +253,7 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel {
|
|||||||
|
|
||||||
// Add values and types.
|
// Add values and types.
|
||||||
let scope = module.scope();
|
let scope = module.scope();
|
||||||
for (name, value) in scope.iter() {
|
for (name, value, _) in scope.iter() {
|
||||||
if scope.get_category(name) != Some(category) {
|
if scope.get_category(name) != Some(category) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -467,7 +467,7 @@ fn casts(
|
|||||||
fn scope_models(resolver: &dyn Resolver, name: &str, scope: &Scope) -> Vec<FuncModel> {
|
fn scope_models(resolver: &dyn Resolver, name: &str, scope: &Scope) -> Vec<FuncModel> {
|
||||||
scope
|
scope
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(_, value)| {
|
.filter_map(|(_, value, _)| {
|
||||||
let Value::Func(func) = value else { return None };
|
let Value::Func(func) = value else { return None };
|
||||||
Some(func_model(resolver, func, &[name], true))
|
Some(func_model(resolver, func, &[name], true))
|
||||||
})
|
})
|
||||||
@ -653,7 +653,7 @@ fn symbols_page(resolver: &dyn Resolver, parent: &str, group: &GroupData) -> Pag
|
|||||||
/// Produce a symbol list's model.
|
/// Produce a symbol list's model.
|
||||||
fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel {
|
fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel {
|
||||||
let mut list = vec![];
|
let mut list = vec![];
|
||||||
for (name, value) in group.module().scope().iter() {
|
for (name, value, _) in group.module().scope().iter() {
|
||||||
let Value::Symbol(symbol) = value else { continue };
|
let Value::Symbol(symbol) = value else { continue };
|
||||||
let complete = |variant: &str| {
|
let complete = |variant: &str| {
|
||||||
if variant.is_empty() {
|
if variant.is_empty() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user