summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2025-06-24 18:14:09 +0200
committerLaurenz <laurmaedje@gmail.com>2025-06-24 18:14:09 +0200
commitcd7233c7761a685f06a6cd45daef192ab3423fa1 (patch)
treed8d9bb6be68aac4bd7756eadbdcf41c87a6cb87f
parent9e3c1199edddc0422d34a266681d2efe1babd0c1 (diff)
Support `in` operator on strings and modulesin-operator-for-modules
-rw-r--r--crates/typst-library/src/foundations/module.rs19
-rw-r--r--crates/typst-library/src/foundations/ops.rs1
-rw-r--r--docs/reference/groups.yml6
-rw-r--r--tests/suite/scripting/ops.typ2
4 files changed, 19 insertions, 9 deletions
diff --git a/crates/typst-library/src/foundations/module.rs b/crates/typst-library/src/foundations/module.rs
index 55d8bab6..14eefca3 100644
--- a/crates/typst-library/src/foundations/module.rs
+++ b/crates/typst-library/src/foundations/module.rs
@@ -19,11 +19,8 @@ use crate::foundations::{repr, ty, Content, Scope, Value};
///
/// You can access definitions from the module using [field access
/// notation]($scripting/#fields) and interact with it using the [import and
-/// include syntaxes]($scripting/#modules). Alternatively, it is possible to
-/// convert a module to a dictionary, and therefore access its contents
-/// dynamically, using the [dictionary constructor]($dictionary/#constructor).
+/// include syntaxes]($scripting/#modules).
///
-/// # Example
/// ```example
/// <<< #import "utils.typ"
/// <<< #utils.add(2, 5)
@@ -34,6 +31,20 @@ use crate::foundations::{repr, ty, Content, Scope, Value};
/// >>>
/// >>> #(-3)
/// ```
+///
+/// You can check whether a definition is present in a module using the `{in}`
+/// operator, with a string on the left-hand side. This can be useful to
+/// [conditionally access]($category/foundations/std/#conditional-access)
+/// definitions in a module.
+///
+/// ```example
+/// #("table" in std) \
+/// #("nope" in std)
+/// ```
+///
+/// Alternatively, it is possible to convert a module to a dictionary, and
+/// therefore access its contents dynamically, using the [dictionary
+/// constructor]($dictionary/#constructor).
#[ty(cast)]
#[derive(Clone, Hash)]
#[allow(clippy::derived_hash_with_manual_eq)]
diff --git a/crates/typst-library/src/foundations/ops.rs b/crates/typst-library/src/foundations/ops.rs
index 6c240844..3c6a5e6c 100644
--- a/crates/typst-library/src/foundations/ops.rs
+++ b/crates/typst-library/src/foundations/ops.rs
@@ -558,6 +558,7 @@ pub fn contains(lhs: &Value, rhs: &Value) -> Option<bool> {
(Str(a), Str(b)) => Some(b.as_str().contains(a.as_str())),
(Dyn(a), Str(b)) => a.downcast::<Regex>().map(|regex| regex.is_match(b)),
(Str(a), Dict(b)) => Some(b.contains(a)),
+ (Str(a), Module(b)) => Some(b.scope().get(a).is_some()),
(a, Array(b)) => Some(b.contains(a.clone())),
_ => Option::None,
diff --git a/docs/reference/groups.yml b/docs/reference/groups.yml
index c7e3d996..e01d99dc 100644
--- a/docs/reference/groups.yml
+++ b/docs/reference/groups.yml
@@ -181,11 +181,7 @@
[`sys.version`]($category/foundations/sys) can also be very useful.
```typ
- #let tiling = if "tiling" in dictionary(std) {
- tiling
- } else {
- pattern
- }
+ #let tiling = if "tiling" in std { tiling } else { pattern }
...
```
diff --git a/tests/suite/scripting/ops.typ b/tests/suite/scripting/ops.typ
index d17c0117..561682f0 100644
--- a/tests/suite/scripting/ops.typ
+++ b/tests/suite/scripting/ops.typ
@@ -264,6 +264,8 @@
#test("Hey" not in "abheyCd", true)
#test("a" not
/* fun comment? */ in "abc", false)
+#test("sys" in std, true)
+#test("system" in std, false)
--- ops-not-trailing ---
// Error: 10 expected keyword `in`