diff --git a/glossy/README.md b/glossy/README.md index 5a04649..a9bdc91 100644 --- a/glossy/README.md +++ b/glossy/README.md @@ -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 Control how terms appear in the document by providing a custom `show-term` function: diff --git a/glossy/src/gloss.typ b/glossy/src/gloss.typ index 3956ff3..2c2e2e7 100644 --- a/glossy/src/gloss.typ +++ b/glossy/src/gloss.typ @@ -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 "./utils.typ": * @@ -332,10 +336,15 @@ show-term: (term-body) => term-body, body ) = context { - // Validate entries parameter type - if type(entries) != dictionary { - panic("entries must be a dictionary, instead got: " + repr(entries)) + // Type checking + let checked-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 for (key, entry) in entries { @@ -396,6 +405,12 @@ ignore-case: false, groups: (), ) = 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 let output = (:) let all_entries = __gloss_entries.final() @@ -405,19 +420,23 @@ let all_groups = all_entries .values() .map(e => e.at("group")) + .map(g => { if g == none { "" } else { g } }) .dedup() .sorted() - let target_groups = if groups.len() == 0 { + let target_groups = if checked-groups.len() == 0 { all_groups } else { // Validate requested groups exist - for g in groups { + for g in checked-groups { + if g == none { + g = "" + } 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 @@ -459,15 +478,15 @@ // Render the glossary using the theme let group_index = 0 - (theme.section)( + (checked-theme.section)( title, for (group, entries) in output { - (theme.group)( + (checked-theme.group)( group, group_index, output.len(), for (i, entry) in entries.enumerate() { - (theme.entry)(entry, i, entries.len()) + (checked-theme.entry)(entry, i, entries.len()) } ) group_index += 1 diff --git a/glossy/src/schemas.typ b/glossy/src/schemas.typ new file mode 100644 index 0000000..949de09 --- /dev/null +++ b/glossy/src/schemas.typ @@ -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) diff --git a/glossy/tests/group-specified/abbreviations.json b/glossy/tests/group-specified/abbreviations.json new file mode 100644 index 0000000..ff4594f --- /dev/null +++ b/glossy/tests/group-specified/abbreviations.json @@ -0,0 +1,11 @@ +{ + "zbuffer": { + "short": "z-bufer", + "long": "the depth buffer" + }, + "pbr": { + "short": "PBR", + "long": "physically based rendering", + "group": "abbreviations" + } +} diff --git a/glossy/tests/group-specified/ref/1.png b/glossy/tests/group-specified/ref/1.png new file mode 100644 index 0000000..7db97d3 Binary files /dev/null and b/glossy/tests/group-specified/ref/1.png differ diff --git a/glossy/tests/group-specified/ref/2.png b/glossy/tests/group-specified/ref/2.png new file mode 100644 index 0000000..22f8771 Binary files /dev/null and b/glossy/tests/group-specified/ref/2.png differ diff --git a/glossy/tests/group-specified/ref/3.png b/glossy/tests/group-specified/ref/3.png new file mode 100644 index 0000000..e2ba743 Binary files /dev/null and b/glossy/tests/group-specified/ref/3.png differ diff --git a/glossy/tests/group-specified/ref/4.png b/glossy/tests/group-specified/ref/4.png new file mode 100644 index 0000000..d903658 Binary files /dev/null and b/glossy/tests/group-specified/ref/4.png differ diff --git a/glossy/tests/group-specified/test.typ b/glossy/tests/group-specified/test.typ new file mode 100644 index 0000000..58720ae --- /dev/null +++ b/glossy/tests/group-specified/test.typ @@ -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