feat(glossy): add type-checking
- adds type-checking via the valkyrie package - fixes handling of groups parameter on #glossary() - new test for relevant changes
This commit is contained in:
9 files changed
+112
-10
No files matched your search
@@ -168,6 +168,19 @@ Display the glossary using the `glossary()` function:
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note that if you want to display terms without a group, you specify that with an
|
||||||
|
empty string. For example, to show the empty group and then the _Web_ group:
|
||||||
|
|
||||||
|
```typst
|
||||||
|
#glossary(groups: ("", "Web"))
|
||||||
|
```
|
||||||
|
|
||||||
|
Or to just show the empty group (i.e. terms without a group):
|
||||||
|
|
||||||
|
```typst
|
||||||
|
#glossary(groups: (""))
|
||||||
|
```
|
||||||
|
|
||||||
### Customizing Term Display
|
### Customizing Term Display
|
||||||
|
|
||||||
Control how terms appear in the document by providing a custom `show-term` function:
|
Control how terms appear in the document by providing a custom `show-term` function:
|
||||||
|
|||||||
+29
-10
@@ -1,3 +1,7 @@
|
|||||||
|
// TODO: replace with @preview when back online
|
||||||
|
#import "@preview/valkyrie:0.2.1" as z
|
||||||
|
|
||||||
|
#import "./schemas.typ": *
|
||||||
#import "./themes.typ": *
|
#import "./themes.typ": *
|
||||||
#import "./utils.typ": *
|
#import "./utils.typ": *
|
||||||
|
|
||||||
@@ -332,10 +336,15 @@
|
|||||||
show-term: (term-body) => term-body,
|
show-term: (term-body) => term-body,
|
||||||
body
|
body
|
||||||
) = context {
|
) = context {
|
||||||
// Validate entries parameter type
|
// Type checking
|
||||||
if type(entries) != dictionary {
|
let checked-entries = (:)
|
||||||
panic("entries must be a dictionary, instead got: " + repr(entries))
|
for (key, entry) in entries {
|
||||||
|
let checked-key = z.parse(key, z.string(), scope: ("dictionary key",))
|
||||||
|
let checked-entry = z.parse(entry, dict-schema, scope: ("dictionary entry",))
|
||||||
|
checked-entries.insert(checked-key, checked-entry)
|
||||||
}
|
}
|
||||||
|
let checked-show-term = z.parse(show-term, z.function(), scope: ("show-term",))
|
||||||
|
let checked-body = z.parse(body, z.content(), scope: ("body",))
|
||||||
|
|
||||||
// Process and store each glossary entry
|
// Process and store each glossary entry
|
||||||
for (key, entry) in entries {
|
for (key, entry) in entries {
|
||||||
@@ -396,6 +405,12 @@
|
|||||||
ignore-case: false,
|
ignore-case: false,
|
||||||
groups: (),
|
groups: (),
|
||||||
) = context {
|
) = context {
|
||||||
|
// Type checking
|
||||||
|
let checked-title = z.parse(title, z.content(), scope: ("title",))
|
||||||
|
let checked-groups = z.parse(groups, groups-list-schema, scope: ("groups",))
|
||||||
|
let checked-ignore-case = z.parse(ignore-case, z.boolean(), scope: ("ignore-case",))
|
||||||
|
let checked-theme = z.parse(theme, theme-schema, scope: ("theme",))
|
||||||
|
|
||||||
// Collect and organize entries by group
|
// Collect and organize entries by group
|
||||||
let output = (:)
|
let output = (:)
|
||||||
let all_entries = __gloss_entries.final()
|
let all_entries = __gloss_entries.final()
|
||||||
@@ -405,19 +420,23 @@
|
|||||||
let all_groups = all_entries
|
let all_groups = all_entries
|
||||||
.values()
|
.values()
|
||||||
.map(e => e.at("group"))
|
.map(e => e.at("group"))
|
||||||
|
.map(g => { if g == none { "" } else { g } })
|
||||||
.dedup()
|
.dedup()
|
||||||
.sorted()
|
.sorted()
|
||||||
|
|
||||||
let target_groups = if groups.len() == 0 {
|
let target_groups = if checked-groups.len() == 0 {
|
||||||
all_groups
|
all_groups
|
||||||
} else {
|
} else {
|
||||||
// Validate requested groups exist
|
// Validate requested groups exist
|
||||||
for g in groups {
|
for g in checked-groups {
|
||||||
|
if g == none {
|
||||||
|
g = ""
|
||||||
|
}
|
||||||
if g not in all_groups {
|
if g not in all_groups {
|
||||||
panic("Requested group not found: " + g)
|
panic("Requested group, '" + g + "', not found.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groups
|
checked-groups
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process entries group by group
|
// Process entries group by group
|
||||||
@@ -459,15 +478,15 @@
|
|||||||
// Render the glossary using the theme
|
// Render the glossary using the theme
|
||||||
let group_index = 0
|
let group_index = 0
|
||||||
|
|
||||||
(theme.section)(
|
(checked-theme.section)(
|
||||||
title,
|
title,
|
||||||
for (group, entries) in output {
|
for (group, entries) in output {
|
||||||
(theme.group)(
|
(checked-theme.group)(
|
||||||
group,
|
group,
|
||||||
group_index,
|
group_index,
|
||||||
output.len(),
|
output.len(),
|
||||||
for (i, entry) in entries.enumerate() {
|
for (i, entry) in entries.enumerate() {
|
||||||
(theme.entry)(entry, i, entries.len())
|
(checked-theme.entry)(entry, i, entries.len())
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
group_index += 1
|
group_index += 1
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// TODO: change to @preview when online
|
||||||
|
#import "@preview/valkyrie:0.2.1" as z
|
||||||
|
|
||||||
|
#let dict-schema = z.either(
|
||||||
|
z.string(),
|
||||||
|
z.dictionary(
|
||||||
|
(
|
||||||
|
short: z.content(), // this is the only required field
|
||||||
|
plural: z.content(optional: true),
|
||||||
|
long: z.content(optional: true),
|
||||||
|
longplural: z.content(optional: true),
|
||||||
|
description: z.content(optional: true),
|
||||||
|
group: z.content(optional: true),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
#let theme-schema = z.dictionary(
|
||||||
|
(
|
||||||
|
section: z.function(),
|
||||||
|
group: z.function(),
|
||||||
|
entry: z.function(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
#let groups-list-schema = z.array(pre-transform: z.coerce.array)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"zbuffer": {
|
||||||
|
"short": "z-bufer",
|
||||||
|
"long": "the depth buffer"
|
||||||
|
},
|
||||||
|
"pbr": {
|
||||||
|
"short": "PBR",
|
||||||
|
"long": "physically based rendering",
|
||||||
|
"group": "abbreviations"
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 184 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 118 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
@@ -0,0 +1,33 @@
|
|||||||
|
#import "/lib.typ": *
|
||||||
|
|
||||||
|
#show: init-glossary.with(json("abbreviations.json"))
|
||||||
|
|
||||||
|
Reference: @pbr, @zbuffer
|
||||||
|
|
||||||
|
|
||||||
|
#let t(g) = [
|
||||||
|
#line(length: 100%)
|
||||||
|
*TESTING:* `#glossary(groups: ` #repr(g) `)`
|
||||||
|
#glossary(groups: g)
|
||||||
|
]
|
||||||
|
|
||||||
|
#t("abbreviations") // "string" : str
|
||||||
|
#t(("abbreviations")) // ("string") : str
|
||||||
|
#t(("abbreviations",)) // ("string",) : array(str)
|
||||||
|
#t(("abbreviations","abbreviations")) // ("string","string",) : array(str)
|
||||||
|
|
||||||
|
#pagebreak(weak: true)
|
||||||
|
|
||||||
|
#t("") // empty string should be the empty group
|
||||||
|
#t(("")) // empty string should be the empty group
|
||||||
|
#t(("",)) // empty string should be the empty group
|
||||||
|
#t(("","")) // empty string should be the empty group
|
||||||
|
|
||||||
|
#pagebreak(weak: true)
|
||||||
|
|
||||||
|
#t(none) // none should be all groups
|
||||||
|
#t((none)) // none should be all groups
|
||||||
|
|
||||||
|
#pagebreak(weak: true)
|
||||||
|
|
||||||
|
#t(("abbreviations",none)) // try to get both groups
|
||||||
Reference in new issue
Block a user