summaryrefslogtreecommitdiff
path: root/tests/typ/meta
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2024-02-27 11:05:16 +0100
committerGitHub <noreply@github.com>2024-02-27 10:05:16 +0000
commit145723b1ef4fa23f1f6665b8907dfe79d0bf83cf (patch)
tree02a7de661ddd5dafa75dfce3e3c8b45a7333b9dc /tests/typ/meta
parente9ee00a7c0df083663ff5ccca162238b88525e14 (diff)
New context system (#3497)
Diffstat (limited to 'tests/typ/meta')
-rw-r--r--tests/typ/meta/context-compatibility.typ29
-rw-r--r--tests/typ/meta/context.typ181
-rw-r--r--tests/typ/meta/counter.typ18
-rw-r--r--tests/typ/meta/figure-caption.typ2
-rw-r--r--tests/typ/meta/query-before-after.typ7
-rw-r--r--tests/typ/meta/query-figure.typ6
-rw-r--r--tests/typ/meta/query-header.typ20
-rw-r--r--tests/typ/meta/state.typ26
8 files changed, 248 insertions, 41 deletions
diff --git a/tests/typ/meta/context-compatibility.typ b/tests/typ/meta/context-compatibility.typ
new file mode 100644
index 00000000..60124255
--- /dev/null
+++ b/tests/typ/meta/context-compatibility.typ
@@ -0,0 +1,29 @@
+// Test compatibility with the pre-context way of things.
+// Ref: false
+
+---
+#let s = state("x", 0)
+#let compute(expr) = [
+ #s.update(x =>
+ eval(expr.replace("x", str(x)))
+ )
+ New value is #s.display().
+]
+
+#locate(loc => {
+ let elem = query(<here>, loc).first()
+ test(s.at(elem.location()), 13)
+})
+
+#compute("10") \
+#compute("x + 3") \
+*Here.* <here> \
+#compute("x * 2") \
+#compute("x - 5")
+
+---
+#style(styles => measure([it], styles).width < 20pt)
+
+---
+#counter(heading).update(10)
+#counter(heading).display(n => test(n, 10))
diff --git a/tests/typ/meta/context.typ b/tests/typ/meta/context.typ
new file mode 100644
index 00000000..729d9fa2
--- /dev/null
+++ b/tests/typ/meta/context.typ
@@ -0,0 +1,181 @@
+// Test context expressions.
+// Ref: false
+
+---
+// Test that context body is parsed as atomic expression.
+#let c = [#context "hello".]
+#test(c.children.first().func(), (context none).func())
+#test(c.children.last(), [.])
+
+---
+// Test that manual construction is forbidden.
+// Error: 2-25 cannot be constructed manually
+#(context none).func()()
+
+---
+// Test that `here()` yields the context element's location.
+#context test(query(here()).first().func(), (context none).func())
+
+---
+// Test whether context is retained in nested function.
+#let translate(..args) = args.named().at(text.lang)
+#set text(lang: "de")
+#context test(translate(de: "Inhalt", en: "Contents"), "Inhalt")
+
+---
+// Test whether context is retained in built-in callback.
+#set text(lang: "de")
+#context test(
+ ("en", "de", "fr").sorted(key: v => v != text.lang),
+ ("de", "en", "fr"),
+)
+
+---
+// Test `locate` + `here`.
+#context test(here().position().y, 10pt)
+
+---
+// Test `locate`.
+#v(10pt)
+= Introduction <intro>
+#context test(locate(<intro>).position().y, 20pt)
+
+---
+// Error: 10-25 label `<intro>` does not exist in the document
+#context locate(<intro>)
+
+---
+= Introduction <intro>
+= Introduction <intro>
+
+// Error: 10-25 label `<intro>` occurs multiple times in the document
+#context locate(<intro>)
+
+---
+#v(10pt)
+= Introduction <intro>
+#context test(locate(heading).position().y, 20pt)
+
+---
+// Error: 10-25 selector does not match any element
+#context locate(heading)
+
+---
+= Introduction <intro>
+= Introduction <intro>
+
+// Error: 10-25 selector matches multiple elements
+#context locate(heading)
+
+---
+// Test `counter`.
+#let c = counter("heading")
+#c.update(2)
+#c.update(n => n + 2)
+#context test(c.get(), (4,))
+#c.update(n => n - 3)
+#context test(c.at(here()), (1,))
+
+---
+// Test `state.at` outside of context.
+// Error: 2-26 can only be used when context is known
+// Hint: 2-26 try wrapping this in a `context` expression
+// Hint: 2-26 the `context` expression should wrap everything that depends on this function
+#state("key").at(<label>)
+
+---
+// Test `counter.at` outside of context.
+// Error: 2-28 can only be used when context is known
+// Hint: 2-28 try wrapping this in a `context` expression
+// Hint: 2-28 the `context` expression should wrap everything that depends on this function
+#counter("key").at(<label>)
+
+---
+// Test `measure`.
+#let f(lo, hi) = context {
+ let h = measure[Hello].height
+ assert(h > lo)
+ assert(h < hi)
+}
+#text(10pt, f(6pt, 8pt))
+#text(20pt, f(13pt, 14pt))
+
+---
+// Test basic get rule.
+#context test(text.lang, "en")
+#set text(lang: "de")
+#context test(text.lang, "de")
+#text(lang: "es", context test(text.lang, "es"))
+
+---
+// Test folding.
+#set rect(stroke: red)
+#context {
+ test(type(rect.stroke), stroke)
+ test(rect.stroke.paint, red)
+}
+#[
+ #set rect(stroke: 4pt)
+ #context test(rect.stroke, 4pt + red)
+]
+#context test(rect.stroke, stroke(red))
+
+---
+// We have one collision: `figure.caption` could be both the element and a get
+// rule for the `caption` field, which is settable. We always prefer the
+// element. It's unfortunate, but probably nobody writes
+// `set figure(caption: ..)` anyway.
+#test(type(figure.caption), function)
+#context test(type(figure.caption), function)
+
+---
+// Error: 10-31 Assertion failed: "en" != "de"
+#context test(text.lang, "de")
+
+---
+// Error: 15-20 function `text` does not contain field `langs`
+#context text.langs
+
+---
+// Error: 18-22 function `heading` does not contain field `body`
+#context heading.body
+
+---
+// Error: 7-11 can only be used when context is known
+// Hint: 7-11 try wrapping this in a `context` expression
+// Hint: 7-11 the `context` expression should wrap everything that depends on this function
+#text.lang
+
+---
+// Error: 7-12 function `text` does not contain field `langs`
+#text.langs
+
+---
+// Error: 10-14 function `heading` does not contain field `body`
+#heading.body
+
+---
+// Test that show rule establishes context.
+#set heading(numbering: "1.")
+#show heading: it => test(
+ counter(heading).get(),
+ (intro: (1,), back: (2,)).at(str(it.label)),
+)
+
+= Introduction <intro>
+= Background <back>
+
+---
+// Test that show rule on non-locatable element allows `query`.
+// Error: 18-47 Assertion failed: 2 != 3
+#show emph: _ => test(query(heading).len(), 3)
+#show strong: _ => test(query(heading).len(), 2)
+= Introduction
+= Background
+*Hi* _there_
+
+---
+// Test error when captured variable is assigned to.
+#let i = 0
+// Error: 11-12 variables from outside the context expression are read-only and cannot be modified
+#context (i = 1)
diff --git a/tests/typ/meta/counter.typ b/tests/typ/meta/counter.typ
index 6b5797de..6d72f246 100644
--- a/tests/typ/meta/counter.typ
+++ b/tests/typ/meta/counter.typ
@@ -4,21 +4,21 @@
// Count with string key.
#let mine = counter("mine!")
-Final: #locate(loc => mine.final(loc).at(0)) \
+Final: #context mine.final().at(0) \
#mine.step()
-First: #mine.display() \
+First: #context mine.display() \
#mine.update(7)
-#mine.display("1 of 1", both: true) \
+#context mine.display("1 of 1", both: true) \
#mine.step()
#mine.step()
-Second: #mine.display("I")
+Second: #context mine.display("I")
#mine.update(n => n * 2)
#mine.step()
---
// Count labels.
#let label = <heya>
-#let count = counter(label).display()
+#let count = context counter(label).display()
#let elem(it) = [#box(it) #label]
#elem[hey, there!] #count \
@@ -31,17 +31,17 @@ Second: #mine.display("I")
#counter(heading).step()
= Alpha
-In #counter(heading).display()
+In #context counter(heading).display()
== Beta
#set heading(numbering: none)
= Gamma
#heading(numbering: "I.")[Delta]
-At Beta, it was #locate(loc => {
- let it = query(heading, loc).find(it => it.body == [Beta])
+At Beta, it was #context {
+ let it = query(heading).find(it => it.body == [Beta])
numbering(it.numbering, ..counter(heading).at(it.location()))
-})
+}
---
// Count figures.
diff --git a/tests/typ/meta/figure-caption.typ b/tests/typ/meta/figure-caption.typ
index 0188ebca..0cdc2bbb 100644
--- a/tests/typ/meta/figure-caption.typ
+++ b/tests/typ/meta/figure-caption.typ
@@ -45,7 +45,7 @@
#show figure.caption: it => emph[
#it.body
(#it.supplement
- #it.counter.display(it.numbering))
+ #context it.counter.display(it.numbering))
]
#figure(
diff --git a/tests/typ/meta/query-before-after.typ b/tests/typ/meta/query-before-after.typ
index 3ddc9402..5f134093 100644
--- a/tests/typ/meta/query-before-after.typ
+++ b/tests/typ/meta/query-before-after.typ
@@ -57,12 +57,11 @@
#set heading(outlined: true, numbering: "1.")
-// This is purposefully an empty
-#locate(loc => [
+#context [
Non-outlined elements:
- #(query(selector(heading).and(heading.where(outlined: false)), loc)
+ #(query(selector(heading).and(heading.where(outlined: false)))
.map(it => it.body).join(", "))
-])
+]
#heading("A", outlined: false)
#heading("B", outlined: true)
diff --git a/tests/typ/meta/query-figure.typ b/tests/typ/meta/query-figure.typ
index 0540d65a..590c8e87 100644
--- a/tests/typ/meta/query-figure.typ
+++ b/tests/typ/meta/query-figure.typ
@@ -11,8 +11,8 @@
#show figure: set image(width: 80%)
= List of Figures
-#locate(it => {
- let elements = query(selector(figure).after(it), it)
+#context {
+ let elements = query(selector(figure).after(here()))
for it in elements [
Figure
#numbering(it.numbering,
@@ -21,7 +21,7 @@
#box(width: 1fr, repeat[.])
#counter(page).at(it.location()).first() \
]
-})
+}
#figure(
image("/files/glacier.jpg"),
diff --git a/tests/typ/meta/query-header.typ b/tests/typ/meta/query-header.typ
index dd83c128..5cbaa995 100644
--- a/tests/typ/meta/query-header.typ
+++ b/tests/typ/meta/query-header.typ
@@ -4,19 +4,17 @@
#set page(
paper: "a7",
margin: (y: 1cm, x: 0.5cm),
- header: {
+ header: context {
smallcaps[Typst Academy]
h(1fr)
- locate(it => {
- let after = query(selector(heading).after(it), it)
- let before = query(selector(heading).before(it), it)
- let elem = if before.len() != 0 {
- before.last()
- } else if after.len() != 0 {
- after.first()
- }
- emph(elem.body)
- })
+ let after = query(selector(heading).after(here()))
+ let before = query(selector(heading).before(here()))
+ let elem = if before.len() != 0 {
+ before.last()
+ } else if after.len() != 0 {
+ after.first()
+ }
+ emph(elem.body)
}
)
diff --git a/tests/typ/meta/state.typ b/tests/typ/meta/state.typ
index 86dc70a5..3fa8ece7 100644
--- a/tests/typ/meta/state.typ
+++ b/tests/typ/meta/state.typ
@@ -9,20 +9,20 @@
$ 2 + 3 $
#s.update(double)
-Is: #s.display(),
-Was: #locate(location => {
- let it = query(math.equation, location).first()
+Is: #context s.get(),
+Was: #context {
+ let it = query(math.equation).first()
s.at(it.location())
-}).
+}.
---
// Try same key with different initial value.
-#state("key", 2).display()
+#context state("key", 2).get()
#state("key").update(x => x + 1)
-#state("key", 2).display()
-#state("key", 3).display()
+#context state("key", 2).get()
+#context state("key", 3).get()
#state("key").update(x => x + 1)
-#state("key", 2).display()
+#context state("key", 2).get()
---
#set page(width: 200pt)
@@ -30,15 +30,15 @@ Was: #locate(location => {
#let ls = state("lorem", lorem(1000).split("."))
#let loremum(count) = {
- ls.display(list => list.slice(0, count).join(".").trim() + ".")
+ context ls.get().slice(0, count).join(".").trim() + "."
ls.update(list => list.slice(count))
}
#let fs = state("fader", red)
#let trait(title) = block[
- #fs.display(color => text(fill: color)[
+ #context text(fill: fs.get())[
*#title:* #loremum(1)
- ])
+ ]
#fs.update(color => color.lighten(30%))
]
@@ -52,5 +52,5 @@ Was: #locate(location => {
// Warning: layout did not converge within 5 attempts
// Hint: check if any states or queries are updating themselves
#let s = state("s", 1)
-#locate(loc => s.update(s.final(loc) + 1))
-#s.display()
+#context s.update(s.final() + 1)
+#context s.get()