refactor(glossy): Sanitize modes & modifiers

The list of modes & modifiers is now normalized (i.e. multiple equal
names are mapped to the same internal name, e.g. 'def' and 'desc' are
mapped to 'description').
Some sanitization is applied (not yet rigorously).

The internals are now splitted in a list of modes and a list of
modifiers.

These two actions already simplify a lot of logic (no multiple checks
for 'def' and 'desc' for example).
This commit is contained in:
swaits authored and swaits committed 2025-10-26 16:00:23 -06:00
1 parent c8f2c0d975
commit 8e3ede34dc
1 file changed
+70 -20
+70 -20
View File
@@ -224,17 +224,60 @@
// content: The fully formatted term, including optional article, capitalization, // content: The fully formatted term, including optional article, capitalization,
// usage tracking metadata, and the chosen form (short, long, or both). // 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", "description", "supplement")
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Check for illegal modifier combinations // Normalize mode & modifier inputs AND first sanitization
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
if ("def" in modifiers or "desc" in modifiers) and modifiers.len() > 1 { let modes-modifiers = modes-modifiers.map(it => {
panic("Cannot use 'def'/'desc' with other modifiers.") 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 ("auto", "supplement", "__MIDDLE_ITEM") {
// Already internally used, don't make user input confuse us
panic(it, "should not be used as a modifier")
} else {
return it
}
})
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 "description" in requested_modes and modifiers.len() > 0 {
panic("Cannot use mode 'def'/'desc' with other modifiers.")
}
if "an" in modifiers and "pl" in modifiers {
panic("Cannot use 'a'/'an' and 'pl' together.") panic("Cannot use 'a'/'an' and 'pl' together.")
} }
if ("use" in modifiers or "spend" in modifiers) and ("nouse" in modifiers or "nospend" in modifiers) { if "use" in modifiers and "no-use" in modifiers {
panic("Cannot use 'use'/'spend' and 'nouse'/'nospend' together.") panic("Cannot use 'use'/'spend' and 'nouse'/'nospend' together.")
} }
@@ -244,9 +287,18 @@
let entry = __get_entry(key) 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 { if entry.description == none {
panic("Use of 'def'/'desc' requires a description be defined.") panic("Use of 'def'/'desc' requires a description be defined.")
} }
@@ -257,12 +309,10 @@
// Manage term usage counting and determine if it's the first reference // 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 is_first_use = not __is_term_first_used(key, location: here())
let default-count-as-first-use = ("short" not in modifiers // mode is not short let default-count-as-first-use = (requested_mode == "auto" or requested_mode == "both")
and "long" not in modifiers // mode is not long let force-count-as-first-use = "use" in modifiers
and (display-text == none or display-text == auto)) // mode is not supplement let force-skip-as-first-use = "no-use" in modifiers
let force-count-as-first-use = ("use" in modifiers or "spend" in modifiers) let wants_reference = "noindex" not in modifiers
let force-skip-as-first-use = ("nouse" in modifiers or "nospend" in modifiers)
let wants_reference = ("noref" not in modifiers and "noindex" not in modifiers)
__mark_term_used(key, wants_reference, force-count-as-first-use __mark_term_used(key, wants_reference, force-count-as-first-use
or (not force-skip-as-first-use and default-count-as-first-use)) or (not force-skip-as-first-use and default-count-as-first-use))
@@ -301,7 +351,7 @@
// - If mode is "long" or "both", return the long 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. // The calling logic ensures that when mode = "long" or "both", a long form exists.
let get_article = (mode) => { let get_article = (mode) => {
let wants_article = "a" in modifiers or "an" in modifiers let wants_article = "an" in modifiers
if not wants_article { if not wants_article {
none none
} else if mode == "short" { } else if mode == "short" {
@@ -355,9 +405,9 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Determine desired options based on modifiers and entry.long availability // Determine desired options based on modifiers and entry.long availability
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
let wants_both = "both" in modifiers let wants_both = "both" in requested_modes
let wants_long = "long" in modifiers let wants_long = "long" in requested_modes
let wants_short = "short" in modifiers let wants_short = "short" in requested_modes
let long_available = entry.long != none let long_available = entry.long != none
// Determine mode using the helper function // Determine mode using the helper function
@@ -368,7 +418,7 @@
let long-form = pluralize_term(entry.long, entry.longplural) // `none` safe here let long-form = pluralize_term(entry.long, entry.longplural) // `none` safe here
// Apply format-term() to get the term // Apply format-term() to get the term
let formatted-term = if display-text != none and display-text != auto { let formatted-term = if requested_mode == "supplement" {
// Display text was overriden by user, just accept it (string or content) // Display text was overriden by user, just accept it (string or content)
display-text display-text
} else { } else {
@@ -551,7 +601,7 @@
// Now see if this is an actual glossary term key // Now see if this is an actual glossary term key
if __has_entry(key) { if __has_entry(key) {
// Found in dictionary, render via __gls() // 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 { } else {
// Not one of ours, so just pass it through // Not one of ours, so just pass it through
r r