Merge pull request #55 from th1j5/main

Formalize & document glossy behaviour, simplify internals and add some features
This commit is contained in:
swaits committed 2025-10-26 16:00:23 -06:00
commit 279217dfd2
24 files changed
+329 -161

No files matched your search

+109 -17
View File
@@ -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` <br> `: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` <br> `: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`<br>`a:`<br>`:an`<br>`an:` | Include the article (`an` is just an alias of `a`, they're equivalent) |
| `:use` <br> `: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` <br> `: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.
+146 -103
View File
@@ -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()
}
+1 -1
View File
@@ -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(", "))
)
}
)
+2 -2
View File
@@ -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(", "))]
)
)
)
+1 -1
View File
@@ -38,7 +38,7 @@
columns: (1fr, auto),
gutter: 1em,
[#short-display#entry.label#long-display#description#entry.label],
[#entry.pages]
[#entry.pages.join(", ")]
)
}
)
+2 -2
View File
@@ -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(", ")
)
)
)
+1 -1
View File
@@ -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(", "))
}
)
+2 -2
View File
@@ -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
)
)
},
Binary file not shown.

Before

Width:  |  Height:  |  Size: 490 KiB

After

Width:  |  Height:  |  Size: 104 KiB

+20 -9
View File
@@ -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(", "),
)
)
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 882 KiB

After

Width:  |  Height:  |  Size: 187 KiB

+20 -9
View File
@@ -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(", "),
)
)
}
+2 -2
View File
@@ -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],
)
+2 -2
View File
@@ -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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 KiB

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 534 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 376 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

+19 -8
View File
@@ -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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 KiB

After

Width:  |  Height:  |  Size: 135 KiB

+2 -2
View File
@@ -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%)