diff --git a/glossy/README.md b/glossy/README.md
index bc23cc3..18c033c 100644
--- a/glossy/README.md
+++ b/glossy/README.md
@@ -128,7 +128,8 @@ And then loaded during initialization as follows:
`init-glossary()` supports the following parameters:
-- `format-term` // TODO: document this
+- `format-term` // Function deciding how to format a term, depending on
+ the 'mode' (short, long, both). See example below.
- `show-term` // Function which can customize display of a term (see example below)
- `term-links: false` // True if you want terms to link to their glossary entry
@@ -141,19 +142,27 @@ In modern web development, languages like @html and @css are essential.
The @tps:pl need to be submitted by Friday.
```
-Available modifiers:
+Available *modes* (they determine which information is printed and are
+mutually exclusive):
-- **cap**: Capitalizes the term
-- **pl**: Uses the plural form
+- auto: (Default) Shows the form depending on the previous usage.
+ The mode when no other mode is appended with a colon.
- **both**: Shows "Long Form (Short Form)"
- **short**: Shows only short form
- **long**: Shows only long form
- **def** or **desc**: Shows the description
+- See [the reference](#reference-for-using-glossary-terms)
+ for a complete overview.
+
+Available *modifiers* (they modify how this information is printed):
+
+- **cap**: Capitalizes the term
+- **pl**: Uses the plural form
- **noref** or **noindex**: Don't show the term in the glossary.
- **a** or **an**: Include the article (`an` is just an alias of `a`, they're
equivalent)
-Modifiers can be combined with colons:
+Modes and modifiers can be combined with colons:
| **Input** | **Output** |
| ------------------- | -------------------------------------------------------------- |
@@ -198,21 +207,71 @@ which would normally render as something like "test procedure specification."
But for some reason you want it to actually say "an annoying report." You can do
that like this:
-| **Input** | **Output** |
-| ------------------------- | -------------------- |
-| `@tps[an annoying report` | "an annoying report" |
+| **Input** | **Output** |
+| -------------------------- | -------------------- |
+| `@tps[an annoying report]` | "an annoying report" |
+| `@tps[]` | #none |
+
+In case you want to reference a term from the Glossary/Index, but don't
+want to display it for whatever reason, the second form can be used.
### First use logic
-Any use of the `short`, `long`, or `both` modifier will not count against the
-term's first use.
+The 'mode' of a glossary term determines which information is printed about this
+term. When using a plain `@term`, possibly with some modifiers, the `auto` mode
+is selected. This mode displays the form depending on the usage counter. On the
+first use (`usage counter == 0`), 'both' forms are printed. On subsequent usage
+(`usage counter > 0`) the 'short' form is printed.
-This is useful, for example, when you want to use a term in a heading or a
-caption. In that case, your term might end up in an `outline()` at the top of
+Not all occurrences of a term are counted towards its usage, this depends on
+the mode of the term. Furthermore, this can be manually controlled by modifiers.
+Both are documented in the [reference tables](#reference-for-using-glossary-terms).
+
+This control over the usage counter is practical, for example, when you want to
+use a term in a heading or a caption.
+In that case, your term might end up in an `outline()` at the top of
your document. Normally you don't want that to count as a term's first real use.
Normally you want that to happen in the body of your document. So, by using
-these modifiers in such situations, you can not only specify exactly how you
-want your term to appear, but also control whether it counts as a "first use".
+the appropriate mode and modifiers in such situations, you can not only specify
+exactly how you want your term to appear, but also control whether it counts
+as a "first use".
+
+### Reference for Using Glossary Terms
+
+A reference about
+- the different 'modes' and how they determine which information is printed about a term
+- the impact of modes on the [usage counter and ensuing first use behaviour](#first-use-logic)
+- how modifiers can change the behaviour with respect to the usage counter
+- how modifiers impact the presentation of the information printed
+
+A glossary term can display different types of information, which is determined
+by the 'mode' in which it is printed. These modes are all mutually exclusive.
+
+| Mode | Utilization | Default first use behaviour | Description |
+| ------------- | ------------------- | --------------------------- | ----------- |
+| `auto` | `@term` | use | The default mode when no 'mode' modifier or supplement is specified. The form depends on the first use counter. |
+| `both` | `:both` | use | Shows both forms of the term, by default ([see `format-term`](#customizing-term-display)) like "Long Form (Short Form)". Falls back to short when long form not available. |
+| `short` | `:short` | no-use | Shows only short form. |
+| `long` | `:long` | no-use | Shows only long form. Falls back to short when long form not available. |
+| `description` | `:def`
`:desc` | no-use | Shows the description (None of the modifiers apply here & no link is created towards the glossary). |
+| `supplement` | `[content]` | no-use | Shows the content given by [the supplement](#overriding-term-text). |
+| `reset` | `:reset` | reset usage counter to 0 | Don't output any content & don't link to the glossary. Typical usage would be after an abstract or even before the start of each chapter, maybe in an injected rule. (This could be made a modifier like `:use` or `:nouse`, but would mostly be utilized as `@term:reset:noindex[]` anyways, thus this is a mode. Write `@term@term:reset` to utilize it as a modifier.) |
+
+Minor modifications to how these different types of information are printed,
+linked or counted towards the usage counter, are controlled by the 'modifiers'.
+They do not influence the default first use behaviour of the mode (unless
+explicitely created for this purpose). Moreover, they neatly compose together
+and with most modes (some exceptions exists, but will print a clear error -
+report a bug if not).
+
+| Modifier | Description |
+| ------------------------------ | ---------------------------------------------------------------------- |
+| `:cap` | Capitalizes the term |
+| `:pl` | Uses the plural form |
+| `:noref`
`:noindex` | Don't show the term in the glossary (i.e. no page will be linked - a link from the term towards the glossary is always provided.). |
+| `:a`
`a:`
`:an`
`an:` | Include the article (`an` is just an alias of `a`, they're equivalent) |
+| `:use`
`:spend` | After this occurrence, the term is 'used', i.e. the usage counter is increased by 1. Write `@term:use:noindex[]` to uniquely control the usage counter without output. |
+| `:nouse`
`:nospend` | After this occurrence, the usage counter remains exactly as the same as before. As if the term is transparent with respect to the usage counter. |
### Generating the Glossary
@@ -244,7 +303,7 @@ Or to just show the empty group (i.e. terms without a group):
### Customizing Term Display
-Control how terms appear in the document by providing a custom `show-term` function:
+Control how terms are styled in the document by providing a custom `show-term` function:
```typst
#let emph-term(term-body) = { emph(term-body) }
@@ -255,6 +314,26 @@ Control how terms appear in the document by providing a custom `show-term` funct
)
```
+Terms can be formatted depending on the 'mode' by providing a custom
+`format-term` function. The mode is one of ("short", "long", "both").
+
+```typst
+// When displaying both, reverse the display order by showing
+// "short (long)" instead of the normal "long (short)"
+#let short-long-term(mode, short-form, long-form) = {
+ if mode == "short" { short-form }
+ else if mode == "long" { long-form }
+ else { // mode assumed to be "both"
+ short-form + " (" + long-form + ")"
+ }
+}
+
+#show: init-glossary.with(
+ myGlossary,
+ format-term: short-long-term
+)
+```
+
### Glossary Themes
#### Included Themes
@@ -300,7 +379,7 @@ Customize glossary appearance by defining a theme with three functions:
columns: (auto, 1fr, auto),
output,
repeat([#h(0.25em) . #h(0.25em)]),
- entry.pages,
+ entry.pages.join(", "),
)
)
}
@@ -313,7 +392,7 @@ Entry fields available to themes:
- `long`: Long form (can be `none`)
- `description`: Term description (can be `none`)
- `label`: Term's dictionary label
-- `pages`: Linked page numbers where term appears
+- `pages`: Array of linked page numbers where term appears
**NOTE:** If the theme does not emit `entry.label`, linking from terms to their
glossary entry will not work.
@@ -321,3 +400,16 @@ glossary entry will not work.
## License
This project is licensed under the MIT License.
+
+## Changelog
+
+### v0.9.0
+- **Breaking**: In themes, entry.pages now returns an array of linked
+ page numbers, instead of opaque content. Use `#entry.pages.join(", ")`
+ in your custom theme to keep the previous behaviour.
+- **Breaking**: The `both` mode (previously called modifier) by default
+ now counts towards the first use of a term.
+- **Breaking**: When multiple conflicting modes are supplied (like 'short'
+ and 'long'), glossy now throws an error (with a clear message).
+- **Breaking**: When an unrecognized modifier is supplied with the term,
+ glossy will now panic instead of ignoring the modifier.
diff --git a/glossy/src/gloss.typ b/glossy/src/gloss.typ
index eed3f34..2429fd4 100644
--- a/glossy/src/gloss.typ
+++ b/glossy/src/gloss.typ
@@ -135,7 +135,8 @@
label(__gloss_label_prefix + key + __gloss_entry_postfix)
}
-// Updates the term usage in the glossary state.
+// Updates the term usage (first use counter & wants to be referenced counter)
+// in the glossary state.
//
// Parameters:
// key (string): The glossary entry key
@@ -143,14 +144,16 @@
// Returns:
// none: Updates state as a side effect
//
-#let __mark_term_used(key, count-as-first-use) = {
- counter(__gloss_label_prefix + key).step()
+#let __mark_term_used(key, count-as-referenced, count-as-first-use) = {
+ if count-as-referenced {
+ counter(__gloss_label_prefix + key).step()
+ }
if count-as-first-use {
counter(__gloss_label_prefix + key + __gloss_first_use_counter_postfix).step()
}
}
-// Queries whether the term is used ANYWHERE
+// Queries whether the term wants to be referenced from ANYWHERE
//
// Parameters:
// key (string): The glossary entry key
@@ -159,7 +162,7 @@
// Returns:
// boolean: If the entry is used above the location in the document
//
-#let __is_term_ever_used(key, location: none) = {
+#let __is_term_ever_referenced(key, location: none) = {
let c = counter(__gloss_label_prefix + key)
c = if location == none {c.final()} else {c.at(location)}
c.at(0) > 0
@@ -183,6 +186,18 @@
c.at(0) > 0
}
+// Reset the first use counter to 0
+//
+// Parameters:
+// key (string): The glossary entry key
+//
+// Returns:
+// none: Updates state as a side effect
+//
+#let __reset_term_first_used(key, location: none) = {
+ counter(__gloss_label_prefix + key + __gloss_first_use_counter_postfix).update(0)
+}
+
// Determine if the glossary contains a visible entry
//
// Parameters:
@@ -207,8 +222,6 @@
// - "long": Show only the long form.
// - "def" or "desc": Show the term's description instead of its name.
// - "a" or "an": Prepend an article, chosen from the entry (short or long form).
-// - "hide" or "hidden": Use term (for the sake of the glossary/index),
-// but don't display it.
// show-term (function): A function that renders the chosen term.
// term-links (boolean): If terms should be clickable links leading to glossary
//
@@ -223,18 +236,68 @@
// content: The fully formatted term, including optional article, capitalization,
// usage tracking metadata, and the chosen form (short, long, or both).
//
-#let __gls(key, modifiers: array, format-term: function, show-term: function, term-links: true, display-text: none) = {
+#let __gls(key, modes-modifiers: array, format-term: function, show-term: function, term-links: true, display-text: none) = {
+ let possible_modes = ("auto", "both", "short", "long", "supplement", "description", "reset")
// ---------------------------------------------------------------------------
- // Check for illegal modifier combinations
+ // Normalize mode & modifier inputs AND check if the modifiers are valid
// ---------------------------------------------------------------------------
- if ("def" in modifiers or "desc" in modifiers) and modifiers.len() > 1 {
- panic("Cannot use 'def'/'desc' with other modifiers.")
+ let modes-modifiers = modes-modifiers.map(it => {
+ if it == "def" or it == "desc" {
+ return "description"
+ } else if it == "a" or it == "an" {
+ return "an"
+ } else if it == "use" or it == "spend" {
+ return "use"
+ } else if it == "nouse" or it == "nospend" {
+ return "no-use"
+ } else if it == "noref" or it == "noindex" {
+ return "noindex"
+ } else if it in ("both", "short", "long", "reset", "cap", "pl") {
+ return it
+ } else if it in ("auto", "description", "supplement") {
+ panic(it, "is a valid mode, but is not used by applying a modifier with this name. Read the documentation.")
+ } else {
+ panic(it, "is not a recognized mode or modifier.")
+ }
+ })
+ if display-text != none and display-text != auto {
+ // A supplement is provided, thus the mode is "supplement"
+ modes-modifiers.push("supplement")
}
- if ("a" in modifiers or "an" in modifiers) and ("pl" in modifiers) {
+
+ // ---------------------------------------------------------------------------
+ // Determine the requested modes (plural) and the modifier array
+ // ---------------------------------------------------------------------------
+ modes-modifiers.push("__MIDDLE_ITEM") // unused modifier
+ let (requested_modes, modifiers) = modes-modifiers.sorted(key: it => {
+ if it in possible_modes {
+ // It is a 'mode'
+ return -1
+ } else if it == "__MIDDLE_ITEM" {
+ return 0
+ } else {
+ // It is a 'modifier'
+ return 1
+ }
+ }).split("__MIDDLE_ITEM")
+
+ // ---------------------------------------------------------------------------
+ // Check for illegal mode and/or modifier combinations
+ // ---------------------------------------------------------------------------
+ if requested_modes.len() > 1 {
+ panic("Cannot mix modes ", requested_modes, ", pick one.")
+ }
+ if "description" in requested_modes and modifiers.len() > 0 {
+ panic("Cannot use mode 'def'/'desc' with other modifiers.")
+ }
+ if "reset" in requested_modes and modifiers.len() > 0 {
+ panic("Cannot use mode 'reset' with other modifiers.")
+ }
+ if "an" in modifiers and "pl" in modifiers {
panic("Cannot use 'a'/'an' and 'pl' together.")
}
- if ("hidden" in modifiers or "hide" in modifiers) and modifiers.len() > 1{
- panic("Cannot use 'hide'/'hidden' with other modifiers.")
+ if "use" in modifiers and "no-use" in modifiers {
+ panic("Cannot use 'use'/'spend' and 'nouse'/'nospend' together.")
}
// ---------------------------------------------------------------------------
@@ -243,24 +306,41 @@
let entry = __get_entry(key)
// ---------------------------------------------------------------------------
- // If "def" or "desc" modifier is present, show the entry's description immediately
+ // Determine the requested mode (singular)
// ---------------------------------------------------------------------------
- if "def" in modifiers or "desc" in modifiers {
+ let requested_mode = if requested_modes.len() == 0 {
+ "auto"
+ } else {
+ requested_modes.at(0)
+ }
+
+ // ---------------------------------------------------------------------------
+ // If mode is "description", show the entry's description immediately
+ // ---------------------------------------------------------------------------
+ if requested_mode == "description" {
if entry.description == none {
panic("Use of 'def'/'desc' requires a description be defined.")
}
return show-term([#entry.description])
}
+ // ---------------------------------------------------------------------------
+ // If mode is "reset", reset the (first) usage counter and return immediately
+ // ---------------------------------------------------------------------------
+ if requested_mode == "reset" {
+ __reset_term_first_used(key)
+ return
+ }
// ---------------------------------------------------------------------------
// Manage term usage counting and determine if it's the first reference
// ---------------------------------------------------------------------------
let is_first_use = not __is_term_first_used(key, location: here())
- let count-as-first-use = ("short" not in modifiers and "long" not in modifiers and "both" not in modifiers)
- let wants_reference = ("noref" not in modifiers and "noindex" not in modifiers)
- if wants_reference {
- __mark_term_used(key, count-as-first-use)
- }
+ let default-count-as-first-use = (requested_mode == "auto" or requested_mode == "both")
+ let force-count-as-first-use = "use" in modifiers
+ let force-skip-as-first-use = "no-use" in modifiers
+ let wants_reference = "noindex" not in modifiers
+ __mark_term_used(key, wants_reference, force-count-as-first-use
+ or (not force-skip-as-first-use and default-count-as-first-use))
// ---------------------------------------------------------------------------
// Helper Functions
@@ -282,7 +362,7 @@
let capitalize_term = (article, term) => {
if "cap" not in modifiers {
(article, term)
- } else if article == "" {
+ } else if article == none {
// No article present, so capitalize the term's first letter.
(article, upper(term.first()) + term.slice(1))
} else {
@@ -292,14 +372,14 @@
}
// get_article(mode): Returns the appropriate article string based on the mode.
- // - If wants_article is false, returns an empty string.
+ // - If wants_article is false, returns none
// - If mode is "short", return the short article.
// - If mode is "long" or "both", return the long article.
// The calling logic ensures that when mode = "long" or "both", a long form exists.
let get_article = (mode) => {
- let wants_article = "a" in modifiers or "an" in modifiers
+ let wants_article = "an" in modifiers
if not wants_article {
- ""
+ none
} else if mode == "short" {
entry.article + " "
} else {
@@ -308,67 +388,38 @@
}
}
- // determine_mode(wants_both, wants_long, wants_short, is_first_use, long_available):
- // Decides which mode ("short", "long", or "both") to use.
- // Preference is given to explicit modifiers. If the requested mode can't be fulfilled due to no long form,
- // fall back to "short".
- // If no explicit mode is given, the default behavior is:
- // - On first use and if a long form exists, "both".
- // - Otherwise, "short".
- let determine_mode = (wants_both, wants_long, wants_short, is_first_use, long_available, wants_hidden) => {
- if wants_hidden {
- // If it's hidden, nothing else matters
- "hidden"
- } else if wants_both {
- // Explicit request for "both":
- // If a long form exists, use "both", otherwise fall back to "short".
- if long_available {
- "both"
- } else {
- "short"
- }
- } else if wants_long {
- // Explicit request for "long":
- // If a long form exists, use "long", otherwise fall back to "short".
- if long_available {
- "long"
- } else {
- "short"
- }
- } else if wants_short {
- // Explicit request for "short":
- // Always "short" regardless of availability.
- "short"
- } else {
- // No explicit mode given:
- // On first use with a long form available, default to "both".
- // Otherwise, use "short".
- if is_first_use and long_available {
- "both"
- } else {
- "short"
- }
- }
- }
-
// ---------------------------------------------------------------------------
// Determine desired options based on modifiers and entry.long availability
// ---------------------------------------------------------------------------
- let wants_both = "both" in modifiers
- let wants_long = "long" in modifiers
- let wants_short = "short" in modifiers
- let wants_hidden = ("hidden" in modifiers or "hide" in modifiers)
- let long_available = entry.long != none
+ // Decide which mode ("short", "long", or "both" or "supplement") to use.
+ // If the requested mode can't be fulfilled due to no long form, fall back to "short".
+ // If no explicit mode is given (i.e. we are in 'auto' mode), the default behavior is:
+ // - On first use and if a long form exists, "both".
+ // - Otherwise, "short".
+ if requested_mode == "auto" {
+ // Set requested_mode to automatically determined mode
+ requested_mode = if is_first_use {
+ "both"
+ } else {
+ "short"
+ }
+ }
- // Determine mode using the helper function
- let mode = determine_mode(wants_both, wants_long, wants_short, is_first_use, long_available, wants_hidden)
+ let long_available = entry.long != none
+ let mode = if (requested_mode == "both" or requested_mode == "long") and not long_available {
+ // The fall back case, because long form is not available, but it is requested
+ "short"
+ } else {
+ // No fall back needed, the requested mode can be fulfilled
+ requested_mode
+ }
// Pluralize (if requested)
let short-form = pluralize_term(entry.short, entry.plural)
let long-form = pluralize_term(entry.long, entry.longplural) // `none` safe here
// Apply format-term() to get the term
- let formatted-term = if display-text != none and display-text != auto {
+ let formatted-term = if mode == "supplement" {
// Display text was overriden by user, just accept it (string or content)
display-text
} else {
@@ -380,7 +431,7 @@
// that with content, thus requiring a string here.
// TODO: consider if we want to capitalize *before* this. First intuition is
// "no".
- panic("Your cutsom format-term() function must return a string.")
+ panic("Your custom format-term() function must return a string.")
}
// Get the article, then capitalize either the article or term (if requested)
@@ -390,7 +441,7 @@
// Construct and return the final output
// ---------------------------------------------------------------------------
context {
- let linked-term = if term-links and query(__entry_label(key)).len() > 0 {
+ let linked-term = if term-links and __has_glossary_entry(key) {
link(__entry_label(key), term)
} else {
term
@@ -403,40 +454,33 @@
}
// Create the output content
- if mode == "hidden" {
- // just put the metadata+label out there
- [#metadata("hidden term")#term-label]
- } else {
- // normal term display (ie not hidden)
- [#article#show-term(linked-term)#metadata(term)#term-label]
- // |^^^^^|^^^^^^^^^ |^^^^^^^^ |^^^^^^^^^^^^
- // \_art.| | |
- // \_ apply user formatting function to the term
- // | |
- // \_ metadata lets us label (ie makes it "labelable")
- // |
- // \_ i.e. <__gloss:key>, etc.
- // for backlink from glossary
- }
+ [#article#show-term(linked-term)#metadata(term)#term-label]
+ // |^^^^^|^^^^^^^^^ |^^^^^^^^ |^^^^^^^^^^
+ // | | | \_ the label for backlink from
+ // | | | glossary i.e. <__gloss:key>, etc.
+ // | | \_ metadata lets us label (ie makes it "labelable")
+ // | \_ apply user formatting function to the term
+ // \_art.
}
}
// Creates page number links back to each usage of a glossary term.
//
-// This function generates a comma-separated list of page numbers, where each
-// number links back to a usage of the term in the document. Duplicate page
-// numbers are removed to avoid redundancy.
+// This function generates an array of page numbers, where each number links
+// back to a usage of the term in the document. Duplicate page numers are
+// removed to avoid redundancy.
//
// Parameters:
// key (string): The glossary entry key
//
// Returns:
-// content: Comma-separated list of linked page numbers
+// array: Linked page numbers
//
-// Example output: "1, 3, 5" where each number links to the term usage on that page
+// Example output after a typical .join(", "):
+// "1, 3, 5" where each number links to the term usage on that page
//
#let __create_backlinks(key) = {
- return context query(__term_label(key)) // find all reference
+ return query(__term_label(key)) // find all reference
.map(meta => { // extract location and page number (or symbol)
let loc = meta.location()
let page = numbering(__default(loc.page-numbering(), "1"), ..counter(page).at(loc))
@@ -444,7 +488,6 @@
})
.dedup(key: ((loc, page)) => page) // deduplicate by page
.map(((loc, page)) => link(loc, page)) // create links
- .join(", ")
}
// Formats a term string based on the specified mode.
@@ -559,7 +602,7 @@
// Now see if this is an actual glossary term key
if __has_entry(key) {
// Found in dictionary, render via __gls()
- __gls(key, modifiers: modifiers.map(lower), format-term: format-term, show-term: show-term, term-links: term-links, display-text: supplement)
+ __gls(key, modes-modifiers: modifiers.map(lower), format-term: format-term, show-term: show-term, term-links: term-links, display-text: supplement)
} else {
// Not one of ours, so just pass it through
r
@@ -592,7 +635,7 @@
// - long: Long form of term (optional)
// - description: Term description (optional)
// - label: Term's dictionary label
-// - pages: Linked page numbers where term appears
+// - pages: Array of linked page numbers where term appears
// - index: Zero-based entry index within group
// - total: Total entries in group
// groups (array): Optional list of groups to include
@@ -622,7 +665,7 @@
let output = (:)
let all_entries = __gloss_entries.final()
let all_used = if not show-all {
- all_entries.keys().filter(key => __is_term_ever_used(key))
+ all_entries.keys().filter(key => __is_term_ever_referenced(key))
} else {
all_entries.keys()
}
diff --git a/glossy/src/themes/academic.typ b/glossy/src/themes/academic.typ
index 975c8ad..8da8513 100644
--- a/glossy/src/themes/academic.typ
+++ b/glossy/src/themes/academic.typ
@@ -40,7 +40,7 @@
columns: (1fr, auto),
gutter: 0.75em,
[#short-display#long-display#description#entry.label],
- text(fill: rgb("#666666"), entry.pages)
+ text(fill: rgb("#666666"), entry.pages.join(", "))
)
}
)
diff --git a/glossy/src/themes/basic.typ b/glossy/src/themes/basic.typ
index b756c27..a36f04d 100644
--- a/glossy/src/themes/basic.typ
+++ b/glossy/src/themes/basic.typ
@@ -36,7 +36,7 @@
// - long: Long form of term (optional)
// - description: Term description (optional)
// - label: Term's dictionary label
- // - pages: Linked page numbers where term appears
+ // - pages: Array of linked page numbers where term appears
// index: Zero-based entry index within group
// total: Total entries in group
entry: (entry, index, total) => {
@@ -62,7 +62,7 @@
left: 1em,
bottom: 0.5em,
block(
- [#term#entry.label#long-form#description #h(1em) (pp. #entry.pages)]
+ [#term#entry.label#long-form#description #h(1em) (pp. #entry.pages.join(", "))]
)
)
)
diff --git a/glossy/src/themes/chicago-index.typ b/glossy/src/themes/chicago-index.typ
index 006c440..bdfb526 100644
--- a/glossy/src/themes/chicago-index.typ
+++ b/glossy/src/themes/chicago-index.typ
@@ -38,7 +38,7 @@
columns: (1fr, auto),
gutter: 1em,
[#short-display#entry.label#long-display#description#entry.label],
- [#entry.pages]
+ [#entry.pages.join(", ")]
)
}
)
diff --git a/glossy/src/themes/compact.typ b/glossy/src/themes/compact.typ
index 86a40e3..238fe94 100644
--- a/glossy/src/themes/compact.typ
+++ b/glossy/src/themes/compact.typ
@@ -44,7 +44,7 @@
// - long: Long form of term (optional)
// - description: Term description (optional)
// - label: Term's dictionary label
- // - pages: Linked page numbers where term appears
+ // - pages: Array of linked page numbers where term appears
// index: Zero-based entry index within group
// total: Total entries in group
entry: (entry, index, total) => {
@@ -83,7 +83,7 @@
text(
size: 0.6em,
fill: gray.darken(20%),
- entry.pages
+ entry.pages.join(", ")
)
)
)
diff --git a/glossy/src/themes/table.typ b/glossy/src/themes/table.typ
index 1dfe1f9..4a9400b 100644
--- a/glossy/src/themes/table.typ
+++ b/glossy/src/themes/table.typ
@@ -27,6 +27,6 @@
},
entry: (entry, index, total) => {
- (entry.short + entry.label, entry.long, entry.description, entry.pages)
+ (entry.short + entry.label, entry.long, entry.description, entry.pages.join(", "))
}
)
diff --git a/glossy/src/themes/twocol.typ b/glossy/src/themes/twocol.typ
index 7183e6e..068446b 100644
--- a/glossy/src/themes/twocol.typ
+++ b/glossy/src/themes/twocol.typ
@@ -36,7 +36,7 @@
// - long: Long form of term (optional)
// - description: Term description (optional)
// - label: Term's dictionary label
- // - pages: Linked page numbers where term appears
+ // - pages: Array of linked page numbers where term appears
// index: Zero-based entry index within group
// total: Total entries in group
entry: (entry, index, total) => {
@@ -65,7 +65,7 @@
[#short-display#entry.label#long-display#description], // Term with label
[#repeat(h(0.25em) + "." + h(0.25em))], // Dotted leader line
[ . ], // A 1em wide dot so we definitely get some break between term and pages
- [#entry.pages] // Page references
+ [#entry.pages.join(", ")] // Page references
)
)
},
diff --git a/glossy/tests/abbreviated-syntax/ref/1.png b/glossy/tests/abbreviated-syntax/ref/1.png
index 7b6a7b4..d1279bd 100644
Binary files a/glossy/tests/abbreviated-syntax/ref/1.png and b/glossy/tests/abbreviated-syntax/ref/1.png differ
diff --git a/glossy/tests/abbreviated-syntax/test.typ b/glossy/tests/abbreviated-syntax/test.typ
index 369ec55..cc1a805 100644
--- a/glossy/tests/abbreviated-syntax/test.typ
+++ b/glossy/tests/abbreviated-syntax/test.typ
@@ -40,18 +40,29 @@ Now make sure I get your @tps:short reports by 2pm!
== Using conflicting modifiers (short, long, both)
-These modifiers are semantically mutually exclusive, by they can be combined
-syntactically. When multiple are used, `glossy` tries to make a smart choice on
-which one to display.
+These modifiers are semantically mutually exclusive. When multiple are used,
+`glossy` throws an error to the compiler, explaining the problem.
+
+#import "/src/gloss.typ": __gls, __default-format-term
+#let manual-gls(key, mods) = __gls(key, modes-modifiers: mods, format-term: __default-format-term, show-term: (body) => [#strong(body)], term-links: false, display-text: none)
+#assert-panic(manual-gls.with("tps", ("short", "long")))
+#let msg-short-long = "panicked with: \"Cannot mix modes \", (\"short\", \"long\"), \", pick one.\""
+#let msg-short-both = "panicked with: \"Cannot mix modes \", (\"short\", \"both\"), \", pick one.\""
+#let msg-long-both = "panicked with: \"Cannot mix modes \", (\"long\", \"both\"), \", pick one.\""
+#let msg-short-long-both = "panicked with: \"Cannot mix modes \", (\"short\", \"long\", \"both\"), \", pick one.\""
#table(
columns: 2,
- table.header([*Input*], [*Output*]),
+ table.header([*Input*], [*Error*]),
- [`@tps:short:long` ], [@tps:short:long],
- [`@tps:short:both` ], [@tps:short:both],
- [`@tps:long:both` ], [@tps:long:both],
- [`@tps:short:long:both`], [@tps:short:long:both],
+ [`@tps:short:long` ], [#assert.eq(catch(manual-gls.with("tps", ("short", "long"))),
+ msg-short-long)#msg-short-long],
+ [`@tps:short:both` ], [#assert.eq(catch(manual-gls.with("tps", ("short", "both"))),
+ msg-short-both)#msg-short-both],
+ [`@tps:long:both` ], [#assert.eq(catch(manual-gls.with("tps", ("long", "both"))),
+ msg-long-both)#msg-long-both],
+ [`@tps:short:long:both`], [#assert.eq(catch(manual-gls.with("tps", ("short", "long", "both"))),
+ msg-short-long-both)#msg-short-long-both],
)
#let my-theme = (
@@ -79,7 +90,7 @@ which one to display.
columns: (auto, 1fr, auto),
output,
repeat([#h(0.25em) . #h(0.25em)]),
- entry.pages,
+ entry.pages.join(", "),
)
)
}
diff --git a/glossy/tests/demo/ref/1.png b/glossy/tests/demo/ref/1.png
index f5208fd..dfa7f93 100644
Binary files a/glossy/tests/demo/ref/1.png and b/glossy/tests/demo/ref/1.png differ
diff --git a/glossy/tests/demo/test.typ b/glossy/tests/demo/test.typ
index 0a422bb..71e1eaf 100644
--- a/glossy/tests/demo/test.typ
+++ b/glossy/tests/demo/test.typ
@@ -78,18 +78,29 @@ Articles are incompatible with the `pl` (plural) modifier.
== Using conflicting modifiers (short, long, both)
-These modifiers are semantically mutually exclusive, by they can be combined
-syntactically. When multiple are used, `glossy` tries to make a smart choice on
-which one to display.
+These modifiers are semantically mutually exclusive. When multiple are used,
+`glossy` throws an error to the compiler, explaining the problem.
+
+#import "/src/gloss.typ": __gls, __default-format-term
+#let manual-gls(key, mods) = __gls(key, modes-modifiers: mods, format-term: __default-format-term, show-term: (body) => [#strong(body)], term-links: false, display-text: none)
+#assert-panic(manual-gls.with("tps", ("short", "long")))
+#let msg-short-long = "panicked with: \"Cannot mix modes \", (\"short\", \"long\"), \", pick one.\""
+#let msg-short-both = "panicked with: \"Cannot mix modes \", (\"short\", \"both\"), \", pick one.\""
+#let msg-long-both = "panicked with: \"Cannot mix modes \", (\"long\", \"both\"), \", pick one.\""
+#let msg-short-long-both = "panicked with: \"Cannot mix modes \", (\"short\", \"long\", \"both\"), \", pick one.\""
#table(
columns: 2,
- table.header([*Input*], [*Output*]),
+ table.header([*Input*], [*Error*]),
- [`@tps:short:long` ], [@tps:short:long],
- [`@tps:short:both` ], [@tps:short:both],
- [`@tps:long:both` ], [@tps:long:both],
- [`@tps:short:long:both`], [@tps:short:long:both],
+ [`@tps:short:long` ], [#assert.eq(catch(manual-gls.with("tps", ("short", "long"))),
+ msg-short-long)#msg-short-long],
+ [`@tps:short:both` ], [#assert.eq(catch(manual-gls.with("tps", ("short", "both"))),
+ msg-short-both)#msg-short-both],
+ [`@tps:long:both` ], [#assert.eq(catch(manual-gls.with("tps", ("long", "both"))),
+ msg-long-both)#msg-long-both],
+ [`@tps:short:long:both`], [#assert.eq(catch(manual-gls.with("tps", ("short", "long", "both"))),
+ msg-short-long-both)#msg-short-long-both],
)
#let my-theme = (
@@ -117,7 +128,7 @@ which one to display.
columns: (auto, 1fr, auto),
output,
repeat([#h(0.25em) . #h(0.25em)]),
- entry.pages,
+ entry.pages.join(", "),
)
)
}
diff --git a/glossy/tests/format-term/test.typ b/glossy/tests/format-term/test.typ
index c38ed49..9de52a5 100644
--- a/glossy/tests/format-term/test.typ
+++ b/glossy/tests/format-term/test.typ
@@ -32,7 +32,7 @@
[@html:short], [@html:long], [@html:both],
[@css:short], [@css:long], [@css:both],
- [@tps:short], [@tps:long], [@tps:both],
+ [@tps:short], [@tps:long], [@tps:both:nouse],
[@concise:short], [@concise:long], [@concise:both],
[@shortonly:short], [@shortonly:long], [@shortonly:both],
@@ -40,7 +40,7 @@
[@html:short:cap], [@html:long:cap], [@html:both:cap],
[@a:css:short], [@a:css:long], [@a:css:both],
- [@tps:short:pl], [@tps:long:pl], [@tps:both:pl],
+ [@tps:short:pl], [@tps:long:pl], [@tps:both:nouse:pl],
[@concise:a:cap:short], [@concise:a:cap:long], [@concise:a:cap:both],
[@an:shortonly:short], [@an:shortonly:long], [@an:shortonly:both],
)
diff --git a/glossy/tests/hidden-terms/test.typ b/glossy/tests/hidden-terms/test.typ
index ffbaf3a..49a4542 100644
--- a/glossy/tests/hidden-terms/test.typ
+++ b/glossy/tests/hidden-terms/test.typ
@@ -24,9 +24,9 @@
= Hiding terms
-Here's a hidden term: @html:hide
+Here's a hidden term: @html[]
-Here's another hidden term: @css:hidden
+Here's another hidden term: @css[]
And here's a shown term: @tps
diff --git a/glossy/tests/override-display/ref/1.png b/glossy/tests/override-display/ref/1.png
index d077037..144db79 100644
Binary files a/glossy/tests/override-display/ref/1.png and b/glossy/tests/override-display/ref/1.png differ
diff --git a/glossy/tests/refs-exhaustive/ref/1.png b/glossy/tests/refs-exhaustive/ref/1.png
index d7e6746..23cd59a 100644
Binary files a/glossy/tests/refs-exhaustive/ref/1.png and b/glossy/tests/refs-exhaustive/ref/1.png differ
diff --git a/glossy/tests/refs-exhaustive/ref/2.png b/glossy/tests/refs-exhaustive/ref/2.png
index 7898d3b..299fe65 100644
Binary files a/glossy/tests/refs-exhaustive/ref/2.png and b/glossy/tests/refs-exhaustive/ref/2.png differ
diff --git a/glossy/tests/refs-exhaustive/ref/3.png b/glossy/tests/refs-exhaustive/ref/3.png
index d7dbaf7..fb83da5 100644
Binary files a/glossy/tests/refs-exhaustive/ref/3.png and b/glossy/tests/refs-exhaustive/ref/3.png differ
diff --git a/glossy/tests/refs-exhaustive/ref/4.png b/glossy/tests/refs-exhaustive/ref/4.png
index 13d9c6e..e4831bb 100644
Binary files a/glossy/tests/refs-exhaustive/ref/4.png and b/glossy/tests/refs-exhaustive/ref/4.png differ
diff --git a/glossy/tests/refs-exhaustive/ref/5.png b/glossy/tests/refs-exhaustive/ref/5.png
index 160a403..03be655 100644
Binary files a/glossy/tests/refs-exhaustive/ref/5.png and b/glossy/tests/refs-exhaustive/ref/5.png differ
diff --git a/glossy/tests/refs-exhaustive/ref/6.png b/glossy/tests/refs-exhaustive/ref/6.png
deleted file mode 100644
index fcbc89b..0000000
Binary files a/glossy/tests/refs-exhaustive/ref/6.png and /dev/null differ
diff --git a/glossy/tests/refs-exhaustive/test.typ b/glossy/tests/refs-exhaustive/test.typ
index ca19418..54cc138 100644
--- a/glossy/tests/refs-exhaustive/test.typ
+++ b/glossy/tests/refs-exhaustive/test.typ
@@ -293,14 +293,25 @@ This document tries all reference forms and modifiers on a large set of terms.
== Conflicting multiple modifiers combined (short, long, both together)
-- @tps:short:long
-- @tps:short:both
-- @tps:long:both
-- @tps:short:long:both
-- @html:both:long:short
-- @doc:long:short
-- @cpu:both:long:short
-- @api:short:long:both
+Assert that a panic occurs.
+#import "/src/gloss.typ": __gls, __default-format-term
+#let manual-gls(key, mods) = __gls(key, modes-modifiers: mods, format-term: __default-format-term, show-term: (body) => [#strong(body)], term-links: false, display-text: none)
+//- @tps:short:long
+#assert-panic(manual-gls.with("tps", ("short", "long")))
+//- @tps:short:both
+#assert-panic(manual-gls.with("tps", ("short", "both")))
+//- @tps:long:both
+#assert-panic(manual-gls.with("tps", ("long", "both")))
+//- @tps:short:long:both
+#assert-panic(manual-gls.with("tps", ("short", "long", "both")))
+//- @html:both:long:short
+#assert-panic(manual-gls.with("html", ("both", "long", "short")))
+//- @doc:long:short
+#assert-panic(manual-gls.with("doc", ("long", "short")))
+//- @cpu:both:long:short
+#assert-panic(manual-gls.with("cpu", ("both", "long", "short")))
+//- @api:short:long:both
+#assert-panic(manual-gls.with("api", ("short", "long", "both")))
== Combining capitalization and plural with short/long/both
diff --git a/glossy/tests/refs-in-captions/ref/1.png b/glossy/tests/refs-in-captions/ref/1.png
index 8b819b6..06290d9 100644
Binary files a/glossy/tests/refs-in-captions/ref/1.png and b/glossy/tests/refs-in-captions/ref/1.png differ
diff --git a/glossy/tests/refs-in-captions/test.typ b/glossy/tests/refs-in-captions/test.typ
index 7f2cc5e..e5ecc84 100644
--- a/glossy/tests/refs-in-captions/test.typ
+++ b/glossy/tests/refs-in-captions/test.typ
@@ -37,7 +37,7 @@
=== `@ShortInHeader:short` = "@ShortInHeader:short"
=== `@LongInHeader:long` = "@LongInHeader:long"
-=== `@BothInHeader:both` = "@BothInHeader:both"
+=== `@BothInHeader:both:nouse` = "@BothInHeader:both:nouse"
=== `@NormalInHeader` = "@NormalInHeader"
#line(length: 100%)
@@ -47,7 +47,7 @@
#figure([], caption: [`@ShortInCaption:short` = "@ShortInCaption:short"])
#figure([], caption: [`@LongInCaption:long` = "@LongInCaption:long"])
-#figure([], caption: [`@BothInCaption:both` = "@BothInCaption:both"])
+#figure([], caption: [`@BothInCaption:both:nospend` = "@BothInCaption:both:nospend"])
#figure([], caption: [`@NormalInCaption` = "@NormalInCaption"])
#line(length: 100%)