mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Select items by import paths (#5518)
This commit is contained in:
parent
ec1e8f9e8d
commit
e8bbf3794f
@ -89,15 +89,21 @@ 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 original = item.original_name();
|
|
||||||
let bound = item.bound_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));
|
let (span, value) = item.path().iter().fold(
|
||||||
|
(bound.span(), source.map(|(value, _)| value)),
|
||||||
|
|(span, value), path_ident| {
|
||||||
|
let scope = value.and_then(|v| v.scope());
|
||||||
|
let span = scope
|
||||||
|
.and_then(|s| s.get_span(&path_ident))
|
||||||
|
.unwrap_or(Span::detached())
|
||||||
|
.or(span);
|
||||||
|
let value = scope.and_then(|s| s.get(&path_ident));
|
||||||
|
(span, value)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(res) =
|
if let Some(res) =
|
||||||
recv(NamedItem::Import(bound.get(), span, value))
|
recv(NamedItem::Import(bound.get(), span, value))
|
||||||
{
|
{
|
||||||
@ -269,16 +275,18 @@ mod tests {
|
|||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
use typst::foundations::Value;
|
||||||
use typst::syntax::{LinkedNode, Side};
|
use typst::syntax::{LinkedNode, Side};
|
||||||
|
|
||||||
use super::named_items;
|
use super::named_items;
|
||||||
use crate::tests::{FilePos, WorldLike};
|
use crate::tests::{FilePos, TestWorld, WorldLike};
|
||||||
|
|
||||||
type Response = Vec<EcoString>;
|
type Response = Vec<(EcoString, Option<Value>)>;
|
||||||
|
|
||||||
trait ResponseExt {
|
trait ResponseExt {
|
||||||
fn must_include<'a>(&self, includes: impl IntoIterator<Item = &'a str>) -> &Self;
|
fn must_include<'a>(&self, includes: impl IntoIterator<Item = &'a str>) -> &Self;
|
||||||
fn must_exclude<'a>(&self, excludes: impl IntoIterator<Item = &'a str>) -> &Self;
|
fn must_exclude<'a>(&self, excludes: impl IntoIterator<Item = &'a str>) -> &Self;
|
||||||
|
fn must_include_value(&self, name_value: (&str, Option<&Value>)) -> &Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseExt for Response {
|
impl ResponseExt for Response {
|
||||||
@ -286,7 +294,7 @@ mod tests {
|
|||||||
fn must_include<'a>(&self, includes: impl IntoIterator<Item = &'a str>) -> &Self {
|
fn must_include<'a>(&self, includes: impl IntoIterator<Item = &'a str>) -> &Self {
|
||||||
for item in includes {
|
for item in includes {
|
||||||
assert!(
|
assert!(
|
||||||
self.iter().any(|v| v == item),
|
self.iter().any(|v| v.0 == item),
|
||||||
"{item:?} was not contained in {self:?}",
|
"{item:?} was not contained in {self:?}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -297,12 +305,21 @@ mod tests {
|
|||||||
fn must_exclude<'a>(&self, excludes: impl IntoIterator<Item = &'a str>) -> &Self {
|
fn must_exclude<'a>(&self, excludes: impl IntoIterator<Item = &'a str>) -> &Self {
|
||||||
for item in excludes {
|
for item in excludes {
|
||||||
assert!(
|
assert!(
|
||||||
!self.iter().any(|v| v == item),
|
!self.iter().any(|v| v.0 == item),
|
||||||
"{item:?} was wrongly contained in {self:?}",
|
"{item:?} was wrongly contained in {self:?}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn must_include_value(&self, name_value: (&str, Option<&Value>)) -> &Self {
|
||||||
|
assert!(
|
||||||
|
self.iter().any(|v| (v.0.as_str(), v.1.as_ref()) == name_value),
|
||||||
|
"{name_value:?} was not contained in {self:?}",
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
@ -314,7 +331,7 @@ mod tests {
|
|||||||
let leaf = node.leaf_at(cursor, Side::After).unwrap();
|
let leaf = node.leaf_at(cursor, Side::After).unwrap();
|
||||||
let mut items = vec![];
|
let mut items = vec![];
|
||||||
named_items(world, leaf, |s| {
|
named_items(world, leaf, |s| {
|
||||||
items.push(s.name().clone());
|
items.push((s.name().clone(), s.value().clone()));
|
||||||
None::<()>
|
None::<()>
|
||||||
});
|
});
|
||||||
items
|
items
|
||||||
@ -340,5 +357,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_named_items_import() {
|
fn test_named_items_import() {
|
||||||
test("#import \"foo.typ\": a; #(a);", 2).must_include(["a"]);
|
test("#import \"foo.typ\": a; #(a);", 2).must_include(["a"]);
|
||||||
|
|
||||||
|
let world = TestWorld::new("#import \"foo.typ\": a.b; #(b);")
|
||||||
|
.with_source("foo.typ", "#import \"a.typ\"")
|
||||||
|
.with_source("a.typ", "#let b = 1;");
|
||||||
|
test(&world, 2).must_include_value(("b", Some(&Value::Int(1))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user