Compare commits

...
Author SHA1 Message Date
mewmew b8af7ab776 glossy: fix minor typo in readme 2025-10-26 16:00:21 -06:00
swaits 45112b434f chore(glossy): bump version to 0.8.0 2025-10-26 16:00:20 -06:00
swaits 8a2a2956bc chore: fix path in sync.sh script 2025-10-26 16:00:20 -06:00
swaits 68addf1204 Merge pull request #46 from BurningKarl/reduce-layout-attempts
Fix glossy: avoid duplicate key labels
2025-04-03 15:16:09 -07:00
BurningKarl 797fc68857 fix(glossy): avoid duplicate key labels 2025-04-03 15:16:09 -07:00
swaits 8e8723b8d1 docs(glossy): update README with newest features 2025-04-03 15:06:46 -07:00
swaits 666f26586e Merge pull request #43 from playonverbs/feature/glossy/show-all
Add show-all flag to glossary() and test-case
2025-04-03 14:49:32 -07:00
Niam Patel b899c875c9 Add show-all flag to glossary() and test-case 2025-04-03 08:46:11 -07:00
swaits 3264971bfe Merge pull request #44 from kaerbr/main
docs: fix setting of custom theme in glossary function
2025-04-03 08:39:37 -07:00
Kilian eb382d36cf docs: fix setting of custom theme in glossary function 2025-04-03 08:37:28 -07:00
swaits 4fc05c37a2 feat(glossy): use @term[supplement] to override term display
If you want to completely override how a term is displayed, you can pass
content in via the square brackets on the term's reference.

For example, a term @www which might normally display as "worldwide web
(WWW)" or something similar, could instead display as FOOBAR by using
@www[FOOBAR].
2025-04-03 08:37:28 -07:00
swaits 5957432d5d feat(glossy): adds hide/hidden modifier to suppress term display
There are cases where you might want a term referenced (ie from the
Glossary/Index), but don't want to display it. New modifiers
`hide`||`hidden` do exactly that.
2025-04-03 08:37:28 -07:00
swaits 966a89687a test(glossy): update all tests for Typst 0.13.0 2025-04-03 08:37:28 -07:00
swaits 2b8095d098 fix(glossy): default term-links to false
This parameter (to init-glossary()) enables/disables the terms in the
document linking to their place in the glossary. However, this adds a
crazy amount of extra queries which sometimes hinders Typst's ability to
converge on documents.
2025-04-03 08:37:28 -07:00
swaits c0077ca432 docs(glossy): fix theme parameter typos in README 2025-04-03 08:37:27 -07:00
swaits bc21afc193 chore: merge commit to consolidate upstream merges 2025-04-03 08:17:16 -07:00
37 changed files with 202 additions and 34 deletions

No files matched your search

+23 -4
View File
@@ -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
)
```
@@ -296,7 +315,7 @@ Entry fields available to themes:
- `label`: Term's dictionary label
- `pages`: Linked page numbers where term appears
**NOTE:** If the theme does not emit `entry.label`, linking form terms to their
**NOTE:** If the theme does not emit `entry.label`, linking from terms to their
glossary entry will not work.
## License
+77 -27
View File
@@ -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)
))
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 489 KiB

After

Width:  |  Height:  |  Size: 490 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 884 KiB

After

Width:  |  Height:  |  Size: 882 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

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

Before

Width:  |  Height:  |  Size: 195 KiB

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

+33
View File
@@ -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()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

+33
View File
@@ -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()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 674 KiB

After

Width:  |  Height:  |  Size: 652 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

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

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 651 KiB

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

+1 -1
View File
@@ -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>"]
+1 -1
View File
@@ -4,7 +4,7 @@
RSYNC_OPTS="--archive --delete --itemize-changes --human-readable"
# Set the destination base directory
DEST_DIR="$HOME/Code/forks/typst-packages-fork/packages/preview"
DEST_DIR="$HOME/Code/typst-packages-fork/packages/preview"
# Ensure the destination base directory exists
mkdir -p "$DEST_DIR"