Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b399080660
|
||
|
|
68addf1204
|
||
|
|
797fc68857 | ||
|
|
8e8723b8d1
|
||
|
|
666f26586e
|
||
|
|
b899c875c9 | ||
|
|
3264971bfe
|
||
|
|
eb382d36cf | ||
|
|
4fc05c37a2
|
||
|
|
5957432d5d
|
||
|
|
966a89687a
|
||
|
|
2b8095d098
|
||
|
|
c0077ca432
|
||
|
|
bc21afc193
|
No files matched your search
@@ -41,7 +41,7 @@ different goals:
|
||||
### Import the package
|
||||
|
||||
```typst
|
||||
#import "@preview/glossy:0.7.0": *
|
||||
#import "@preview/glossy:0.8.0": *
|
||||
```
|
||||
|
||||
### Defining Glossary Terms
|
||||
@@ -126,6 +126,12 @@ And then loaded during initialization as follows:
|
||||
#show: init-glossary.with(yaml("glossary.yaml"))
|
||||
```
|
||||
|
||||
`init-glossary()` supports the following parameters:
|
||||
|
||||
- `format-term` // TODO: document this
|
||||
- `show-term` // Function which can customize display of a term (see example below)
|
||||
- `link-terms: false` // True if you want terms to link to their glossary entry
|
||||
|
||||
### Using Glossary Terms
|
||||
|
||||
Reference glossary terms using Typst's `@reference` syntax:
|
||||
@@ -184,6 +190,18 @@ For example:
|
||||
Note that the `a`/`an` (article) modifier cannot be combined with the `pl`
|
||||
(plural) modifier.
|
||||
|
||||
### Overriding Term Text
|
||||
|
||||
There may be cases where you want to completely control what `glossy` displays
|
||||
when you reference a term. For example, imagine you want to reference `@tps`
|
||||
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" |
|
||||
|
||||
### First use logic
|
||||
|
||||
Any use of the `short`, `long`, or `both` modifier will not count against the
|
||||
@@ -203,10 +221,11 @@ Display the glossary using the `glossary()` function:
|
||||
```typst
|
||||
#glossary(
|
||||
title: "Web Development Glossary", // Optional: defaults to Glossary theme:
|
||||
my-theme, // Optional: defaults to theme-academic
|
||||
theme: my-theme, // Optional: defaults to theme-academic
|
||||
sort: true, // Optional: whether or not to sort the glossary
|
||||
ignore-case: false, // Optional: ignore case when sorting terms
|
||||
groups: ("Web") // Optional: Filter to specific groups
|
||||
groups: ("Web"), // Optional: Filter to specific groups
|
||||
show-all: false, // Optional; Show all terms even if unreferenced
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#let __gloss_label_prefix = "__gloss:"
|
||||
#let __gloss_first_use_counter_postfix = ":first-use-count"
|
||||
#let __gloss_entry_postfix = ":entry"
|
||||
|
||||
// Normalizes a dictionary entry by ensuring all required and optional keys exist
|
||||
// with appropriate default values.
|
||||
@@ -122,6 +123,18 @@
|
||||
label(__gloss_label_prefix + key)
|
||||
}
|
||||
|
||||
// Creates a label object for the entry in the glossary.
|
||||
//
|
||||
// Parameters:
|
||||
// key (string): The glossary entry key
|
||||
//
|
||||
// Returns:
|
||||
// label: A Typst label object for the term usage
|
||||
//
|
||||
#let __entry_label(key) = {
|
||||
label(__gloss_label_prefix + key + __gloss_entry_postfix)
|
||||
}
|
||||
|
||||
// Updates the term usage in the glossary state.
|
||||
//
|
||||
// Parameters:
|
||||
@@ -179,7 +192,7 @@
|
||||
// boolean: If the term is visible in the glossary (and the label is unique)
|
||||
//
|
||||
#let __has_glossary_entry(key) = {
|
||||
query(<glossary>).len() > 0 and query(selector(label(key)).after(<glossary>)).len() == 1
|
||||
query(__entry_label(key)).len() > 0
|
||||
}
|
||||
|
||||
// Renders a glossary term with various formatting options.
|
||||
@@ -194,6 +207,8 @@
|
||||
// - "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
|
||||
//
|
||||
@@ -208,7 +223,7 @@
|
||||
// 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) = {
|
||||
#let __gls(key, modifiers: array, format-term: function, show-term: function, term-links: true, display-text: none) = {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Check for illegal modifier combinations
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -218,6 +233,9 @@
|
||||
if ("a" in modifiers or "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.")
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Retrieve the glossary entry and its label
|
||||
@@ -297,8 +315,11 @@
|
||||
// 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) => {
|
||||
if wants_both {
|
||||
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 {
|
||||
@@ -336,18 +357,25 @@
|
||||
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
|
||||
|
||||
// Determine mode using the helper function
|
||||
let mode = determine_mode(wants_both, wants_long, wants_short, is_first_use, long_available)
|
||||
let mode = determine_mode(wants_both, wants_long, wants_short, is_first_use, long_available, wants_hidden)
|
||||
|
||||
// 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 = format-term(mode, short-form, long-form)
|
||||
if type(formatted-term) != str {
|
||||
let formatted-term = if display-text != none and display-text != auto {
|
||||
// Display text was overriden by user, just accept it (string or content)
|
||||
display-text
|
||||
} else {
|
||||
// Normal display (ie no override from user)
|
||||
format-term(mode, short-form, long-form)
|
||||
}
|
||||
if "cap" in modifiers and type(formatted-term) != str {
|
||||
// This is because we still need to capitalize the term, and we cannot do
|
||||
// that with content, thus requiring a string here.
|
||||
// TODO: consider if we want to capitalize *before* this. First intuition is
|
||||
@@ -362,25 +390,43 @@
|
||||
// Construct and return the final output
|
||||
// ---------------------------------------------------------------------------
|
||||
context {
|
||||
let linked-term = if term-links and __has_glossary_entry(key) {
|
||||
link(label(key), term)
|
||||
let linked-term = if term-links and query(__entry_label(key)).len() > 0 {
|
||||
link(__entry_label(key), term)
|
||||
} else {
|
||||
term
|
||||
}
|
||||
let term-label = if wants_reference {
|
||||
// Figure out our label (unless not wanted)
|
||||
let term-label = if wants_reference {
|
||||
__term_label(key)
|
||||
} else {
|
||||
[]
|
||||
}
|
||||
[#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
|
||||
|
||||
// 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)
|
||||
|
||||
// create the forward link, if watned
|
||||
let linked-term = if term-links and __has_glossary_entry(key) {
|
||||
link(label(key), term)
|
||||
} else {
|
||||
term
|
||||
}
|
||||
|
||||
// and the final content
|
||||
[#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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,7 +524,7 @@
|
||||
entries,
|
||||
format-term: __default-format-term,
|
||||
show-term: __default-show-term,
|
||||
term-links: true,
|
||||
term-links: false,
|
||||
body
|
||||
) = context {
|
||||
// Type checking
|
||||
@@ -495,15 +541,14 @@
|
||||
// Process and store each glossary entry
|
||||
for (key, entry) in entries {
|
||||
__add_entry(key, __normalize_entry(key, entry))
|
||||
// Create placeholder labels for autocompletion (if not already present)
|
||||
context if not __has_glossary_entry(key) [
|
||||
#metadata(key)#label(key)
|
||||
]
|
||||
// Create placeholder labels for autocompletion
|
||||
[#metadata(key)#label(key)]
|
||||
}
|
||||
|
||||
// Set up reference handling for glossary terms
|
||||
show ref: r => {
|
||||
let (raw_key, ..raw_modifiers) = str(r.target).split(":")
|
||||
let supplement = r.supplement // used for term display overrides
|
||||
|
||||
// Determine if we need to swap the key and first modifier.
|
||||
// Conditions for swapping:
|
||||
@@ -523,7 +568,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)
|
||||
__gls(key, 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
|
||||
@@ -574,6 +619,7 @@
|
||||
sort: true,
|
||||
ignore-case: false,
|
||||
groups: (),
|
||||
show-all: false,
|
||||
) = context {
|
||||
// Type checking
|
||||
let checked-title = z.parse(title, z.content(), scope: ("title",))
|
||||
@@ -584,7 +630,11 @@
|
||||
// Collect and organize entries by group
|
||||
let output = (:)
|
||||
let all_entries = __gloss_entries.final()
|
||||
let all_used = all_entries.keys().filter(key => __is_term_ever_used(key))
|
||||
let all_used = if not show-all {
|
||||
all_entries.keys().filter(key => __is_term_ever_used(key))
|
||||
} else {
|
||||
all_entries.keys()
|
||||
}
|
||||
|
||||
// Determine which groups to process
|
||||
let all_groups = all_entries
|
||||
@@ -621,7 +671,7 @@
|
||||
short: entry.at("short"),
|
||||
long: entry.at("long"),
|
||||
description: entry.at("description"),
|
||||
label: [#metadata(key)#label(key)],
|
||||
label: [#metadata(key)#__entry_label(key)],
|
||||
pages: __create_backlinks(key)
|
||||
))
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 489 KiB After Width: | Height: | Size: 490 KiB |
|
Before Width: | Height: | Size: 884 KiB After Width: | Height: | Size: 882 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.5 MiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
@@ -12,7 +12,7 @@
|
||||
stroke: 1pt,
|
||||
inset: 1em,
|
||||
[
|
||||
#show: init-glossary.with((WWW: "World Wide Web"))
|
||||
#show: init-glossary.with((WWW: "World Wide Web"), term-links: true)
|
||||
|
||||
This should be a link: @WWW
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 132 KiB |
@@ -0,0 +1,33 @@
|
||||
#import "/lib.typ": *
|
||||
|
||||
#let myGlossary = (
|
||||
html: (
|
||||
short: "HTML",
|
||||
long: "Hypertext Markup Language",
|
||||
description: "A standard language for creating web pages",
|
||||
group: "Web"),
|
||||
css: (
|
||||
short: "CSS",
|
||||
long: "Cascading Style Sheets",
|
||||
description: "A language used for describing the presentation of a document",
|
||||
group: "Web"),
|
||||
tps: (
|
||||
short: "TPS",
|
||||
long: "test procedure specification",
|
||||
description: "A document on how to run all the test procedures"),
|
||||
unused: "Unused term, which shouldn't print in the glossary."
|
||||
)
|
||||
|
||||
#show: init-glossary.with(myGlossary)
|
||||
|
||||
#set page(height: auto, width: 6.5in, margin: 1em, numbering: "1")
|
||||
|
||||
= Hiding terms
|
||||
|
||||
Here's a hidden term: @html:hide
|
||||
|
||||
Here's another hidden term: @css:hidden
|
||||
|
||||
And here's a shown term: @tps
|
||||
|
||||
#glossary()
|
||||
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 126 KiB |
@@ -0,0 +1,33 @@
|
||||
#import "/lib.typ": *
|
||||
|
||||
#let myGlossary = (
|
||||
html: (
|
||||
short: "HTML",
|
||||
long: "Hypertext Markup Language",
|
||||
description: "A standard language for creating web pages",
|
||||
group: "Web"),
|
||||
css: (
|
||||
short: "CSS",
|
||||
long: "Cascading Style Sheets",
|
||||
description: "A language used for describing the presentation of a document",
|
||||
group: "Web"),
|
||||
tps: (
|
||||
short: "TPS",
|
||||
long: "test procedure specification",
|
||||
description: "A document on how to run all the test procedures"),
|
||||
unused: "Unused term, which shouldn't print in the glossary."
|
||||
)
|
||||
|
||||
#show: init-glossary.with(myGlossary)
|
||||
|
||||
#set page(height: auto, width: 6.5in, margin: 1em, numbering: "1")
|
||||
|
||||
= Overriding term display
|
||||
|
||||
Here is @html[HTML being overidden].
|
||||
|
||||
Here is @css[] (blank).
|
||||
|
||||
Here is @tps[TPS with #emph("content")]
|
||||
|
||||
#glossary()
|
||||
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 275 KiB |
|
After Width: | Height: | Size: 502 KiB |
|
After Width: | Height: | Size: 534 KiB |
|
After Width: | Height: | Size: 376 KiB |
|
After Width: | Height: | Size: 407 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 674 KiB After Width: | Height: | Size: 652 KiB |
|
After Width: | Height: | Size: 97 KiB |
@@ -0,0 +1,33 @@
|
||||
#import "/lib.typ": *
|
||||
|
||||
#show: init-glossary.with((
|
||||
one: "this is term one",
|
||||
two: "term two also"
|
||||
))
|
||||
|
||||
#set page(
|
||||
margin: 1em,
|
||||
width: 3.5in,
|
||||
height: auto,
|
||||
)
|
||||
#set text(size: 10pt)
|
||||
|
||||
In this document we don't reference our glossary items but expect them to be
|
||||
shown anyway.
|
||||
|
||||
#glossary(show-all: true)
|
||||
|
||||
#glossary(
|
||||
theme: theme-chicago-index,
|
||||
show-all: true
|
||||
)
|
||||
|
||||
#glossary(
|
||||
theme: theme-compact,
|
||||
show-all: true
|
||||
)
|
||||
|
||||
#glossary(
|
||||
theme: theme-table,
|
||||
show-all: true
|
||||
)
|
||||
|
Before Width: | Height: | Size: 259 KiB After Width: | Height: | Size: 259 KiB |
|
Before Width: | Height: | Size: 651 KiB After Width: | Height: | Size: 650 KiB |
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "glossy"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
compiler = "0.13.0"
|
||||
entrypoint = "lib.typ"
|
||||
authors = ["Stephen Waits <steve@waits.net>"]
|
||||
|
||||