Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fa2ca99be
|
||
|
|
c47839fe8d
|
||
|
|
cfcdc7e2f4 | ||
|
|
db8d7c9c91 | ||
|
|
a869d3ab6b
|
||
|
|
f8085fc768
|
||
|
|
e262a2eafe
|
||
|
|
022892df88
|
||
|
|
6d83a858c8
|
||
|
|
bacb6cebd1
|
||
|
|
279217dfd2
|
||
|
|
8b98b9e89f
|
||
|
|
9972b93b52
|
||
|
|
ae6405c288
|
||
|
|
a6572d07ff
|
||
|
|
8e3ede34dc
|
||
|
|
c8f2c0d975
|
||
|
|
a2947f2b7b
|
||
|
|
f745af74cc
|
||
|
|
9de06d3781
|
||
|
|
4f26f9a194
|
||
|
|
2e9b81dff4
|
||
|
|
3b7a1404ea
|
||
|
|
b250c35f78
|
||
|
|
552858d813
|
||
|
|
03e8e62c70
|
||
|
|
f7727f5abd
|
||
|
|
f3cc41360c | ||
|
|
68945132fb
|
||
|
|
93af7fa6b4
|
||
|
|
0bd35b1984 | ||
|
|
392e8a8122
|
||
|
|
b8af7ab776 | ||
|
|
ca57b15ccf | ||
|
|
3e0d7a9812
|
No files matched your search
@@ -0,0 +1,6 @@
|
||||
STOP! This repository is being migrated.
|
||||
|
||||
All packages have moved to:
|
||||
https://github.com/swaits-typst-packages
|
||||
|
||||
Do NOT create new issues or PRs here.
|
||||
@@ -1,27 +0,0 @@
|
||||
image: alpine/edge
|
||||
packages:
|
||||
- git
|
||||
|
||||
secrets:
|
||||
- 88cce185-d2ec-4573-9546-e33f36f79bbf
|
||||
|
||||
environment:
|
||||
# repo and user names on both sr.ht and github
|
||||
REPO: typst-collection
|
||||
USER: swaits
|
||||
|
||||
tasks:
|
||||
- fetch-all-branches: |
|
||||
cd "$HOME/$REPO"
|
||||
git fetch origin '+refs/heads/*:refs/heads/*' '+refs/tags/*:refs/tags/*' --prune
|
||||
|
||||
- get-github-public-key: |
|
||||
ssh-keyscan -t rsa github.com >> "$HOME/.ssh/known_hosts"
|
||||
|
||||
- add-github-remote: |
|
||||
cd "$HOME/$REPO"
|
||||
git remote add github "git@github.com:$USER/$REPO.git"
|
||||
|
||||
- mirror-to-github: |
|
||||
cd "$HOME/$REPO"
|
||||
git push --mirror github
|
||||
@@ -0,0 +1,9 @@
|
||||
Migration started: 2025-10-26 21:22
|
||||
|
||||
This repository is being split into individual package repositories.
|
||||
During this transition:
|
||||
- No new issues or PRs should be created
|
||||
- Existing issues are being triaged and moved
|
||||
- The repository will be archived once migration is complete
|
||||
|
||||
New organization: https://github.com/swaits-typst-packages
|
||||
@@ -1,3 +1,54 @@
|
||||
# 🚨 REPOSITORY MOVING - DO NOT CREATE NEW ISSUES OR PRS HERE 🚨
|
||||
|
||||
<div align="center">
|
||||
|
||||
## ⛔ THIS REPOSITORY IS BEING MIGRATED ⛔
|
||||
|
||||
### **ALL PACKAGES ARE MOVING TO:** [github.com/swaits-typst-packages](https://github.com/swaits-typst-packages)
|
||||
|
||||
**DO NOT:**
|
||||
- ❌ Create new issues here
|
||||
- ❌ Submit new pull requests here
|
||||
- ❌ Start new work based on this repo
|
||||
|
||||
**INSTEAD:**
|
||||
- ✅ Go to the new organization: [swaits-typst-packages](https://github.com/swaits-typst-packages)
|
||||
- ✅ Find your specific package repository there
|
||||
- ✅ Create issues/PRs in the individual package repos
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
## 📦 New Repository Locations
|
||||
|
||||
| If you're looking for... | Go to... |
|
||||
|--------------------------|----------|
|
||||
| **codly-languages** | ➡️ [github.com/swaits-typst-packages/codly-languages](https://github.com/swaits-typst-packages/codly-languages) |
|
||||
| **easy-typography** | ➡️ [github.com/swaits-typst-packages/easy-typography](https://github.com/swaits-typst-packages/easy-typography) |
|
||||
| **finely-crafted-cv** | ➡️ [github.com/swaits-typst-packages/finely-crafted-cv](https://github.com/swaits-typst-packages/finely-crafted-cv) |
|
||||
| **glossy** | ➡️ [github.com/swaits-typst-packages/glossy](https://github.com/swaits-typst-packages/glossy) |
|
||||
| **pro-letter** | ➡️ [github.com/swaits-typst-packages/pro-letter](https://github.com/swaits-typst-packages/pro-letter) |
|
||||
| **rfc-vibe** | ➡️ [github.com/swaits-typst-packages/rfc-vibe](https://github.com/swaits-typst-packages/rfc-vibe) |
|
||||
| **run-liners** | ➡️ [github.com/swaits-typst-packages/run-liners](https://github.com/swaits-typst-packages/run-liners) |
|
||||
| **swank-tex** | ➡️ [github.com/swaits-typst-packages/swank-tex](https://github.com/swaits-typst-packages/swank-tex) |
|
||||
| **tasteful-pairings** | ➡️ [github.com/swaits-typst-packages/tasteful-pairings](https://github.com/swaits-typst-packages/tasteful-pairings) |
|
||||
|
||||
## ⏳ Migration In Progress
|
||||
|
||||
We are currently:
|
||||
1. Moving existing issues to the appropriate new repositories
|
||||
2. Redirecting pull requests to the new locations
|
||||
3. Setting up the new package infrastructure
|
||||
|
||||
**Expected completion: [Coming Soon]**
|
||||
|
||||
---
|
||||
|
||||
|
||||
<details>
|
||||
<summary>📜 Original README (click to expand)</summary>
|
||||
|
||||
# `typst-collection`
|
||||
|
||||
A collection of `typst` templates and packages by [swaits](https://swaits.com/about).
|
||||
@@ -35,3 +86,5 @@ links below to their main page.
|
||||
## License
|
||||
|
||||
All content licensed under the [MIT license](LICENSE).
|
||||
|
||||
</details>
|
||||
@@ -0,0 +1,37 @@
|
||||
# `typst-collection`
|
||||
|
||||
A collection of `typst` templates and packages by [swaits](https://swaits.com/about).
|
||||
|
||||
Everything in this collection is available for use at the [`typst`
|
||||
universe](https://typst.app/universe/). For details on each, please visit the
|
||||
links below to their main page.
|
||||
|
||||
## Packages
|
||||
|
||||
- [**codly-languages**](https://typst.app/universe/package/codly-languages): A
|
||||
set of language configurations for use with
|
||||
[codly](https://typst.app/universe/package/codly).
|
||||
- [easy-typography](https://typst.app/universe/package/easy-typography): Sets up
|
||||
sensible typography defaults.
|
||||
- [**glossy**](https://typst.app/universe/package/glossy): A very simple
|
||||
glossary system with easily customizable output.
|
||||
- [**rfc-vibe**](https://typst.app/universe/package/rfc-vibe): Bring RFC language
|
||||
into everyday docs.
|
||||
- [**run-liners**](https://typst.app/universe/package/run-liners): Functions to
|
||||
create various run-in lists.
|
||||
- [**swank-tex**](https://typst.app/universe/package/swank-tex): Render those
|
||||
funky logos for TeX, LaTeX, and friends.
|
||||
- [**tasteful-pairings**](https://typst.app/universe/package/tasteful-pairings):
|
||||
A carefully curated collection of font pairings focusing on readability and
|
||||
typographic harmony.
|
||||
|
||||
## Templates
|
||||
|
||||
- [**finely-crafted-cv**](https://typst.app/universe/package/finely-crafted-cv):
|
||||
A modern résumé/curriculum vitæ template with high attention to detail.
|
||||
- [**pro-letter**](https://typst.app/universe/package/pro-letter): A formal
|
||||
business letter template.
|
||||
|
||||
## License
|
||||
|
||||
All content licensed under the [MIT license](LICENSE).
|
||||
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SRC_REPO_ROOT="$(pwd)"
|
||||
DEST_PARENT="../swaits-typst-collection" # change if you like
|
||||
|
||||
DIRS=(
|
||||
codly-languages
|
||||
)
|
||||
|
||||
command -v git-filter-repo >/dev/null || {
|
||||
echo "git-filter-repo is required. Install via 'uv tool install git-filter-repo' (or pipx/pip)."
|
||||
exit 1
|
||||
}
|
||||
|
||||
mkdir -p "$DEST_PARENT"
|
||||
|
||||
for d in "${DIRS[@]}"; do
|
||||
[ -d "$d" ] || {
|
||||
echo "Skip: '$d' not found in $(pwd)"
|
||||
continue
|
||||
}
|
||||
|
||||
TARGET="$DEST_PARENT/$d"
|
||||
echo
|
||||
echo "==> Splitting '$d' → '$TARGET'"
|
||||
|
||||
rm -rf "$TARGET"
|
||||
git clone --no-local --branch main --origin origin "$SRC_REPO_ROOT" "$TARGET"
|
||||
|
||||
(
|
||||
cd "$TARGET"
|
||||
|
||||
git filter-repo --force \
|
||||
--path "$d/" \
|
||||
--path-rename "$d/:"
|
||||
|
||||
# ---- Tag rename: '<dir>-X.Y.Z' -> 'vX.Y.Z' (annotated, with message) ----
|
||||
# Peel old tags to the commit/object they point to to avoid nested tags.
|
||||
while IFS= read -r oldtag; do
|
||||
# only proceed if the (filtered) repo still has this tag
|
||||
git rev-parse -q --verify "refs/tags/$oldtag" >/dev/null || continue
|
||||
|
||||
peeled=$(git rev-parse -q --verify "${oldtag}^{}" || true)
|
||||
[ -z "$peeled" ] && continue
|
||||
|
||||
ver="${oldtag#${d}-}"
|
||||
newtag="v${ver}"
|
||||
|
||||
if git rev-parse -q --verify "refs/tags/$newtag" >/dev/null; then
|
||||
echo "Tag exists, deleting old: $oldtag"
|
||||
git tag -d "$oldtag" >/dev/null
|
||||
else
|
||||
# annotated tag with message equal to tag name (avoids interactive prompt)
|
||||
git -c advice.nestedTag=false tag -a "$newtag" -m "$newtag" "$peeled"
|
||||
git tag -d "$oldtag" >/dev/null
|
||||
echo "Renamed: $oldtag -> $newtag (at $peeled)"
|
||||
fi
|
||||
done < <(git tag -l "${d}-*")
|
||||
|
||||
# standalone: drop the monorepo remote that filter-repo rewired
|
||||
git remote remove origin || true
|
||||
|
||||
echo "Done: $TARGET"
|
||||
)
|
||||
done
|
||||
|
||||
echo
|
||||
echo "All splits complete under: $DEST_PARENT"
|
||||
@@ -6,5 +6,5 @@ authors = ["Stephen Waits <steve@waits.net>"]
|
||||
license = "MIT"
|
||||
description = "A set of language configurations for use with codly"
|
||||
keywords = ["code", "languages", "template", "raw"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
repository = "https://git.swaits.com/swaits/typst-collection"
|
||||
exclude = ["thumbnail.png", "tests"]
|
||||
@@ -6,5 +6,5 @@ authors = ["Stephen Waits <steve@waits.net>"]
|
||||
license = "MIT"
|
||||
description = "Sets up sensible typography defaults."
|
||||
keywords = ["easy", "typography", "defaults"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
repository = "https://git.swaits.com/swaits/typst-collection"
|
||||
exclude = ["thumbnail.png", "tests"]
|
||||
@@ -12,6 +12,7 @@
|
||||
body-size: BODY_SIZE,
|
||||
icon-contact-header: none,
|
||||
keywords: "",
|
||||
show_last_updated: true,
|
||||
thumbnail: none, // check out https://qrframe.kylezhe.ng/ for QR code generation
|
||||
body
|
||||
) = {
|
||||
@@ -47,7 +48,7 @@
|
||||
columns: (1fr, 1fr, 1fr),
|
||||
align: (left, center, right + horizon),
|
||||
// left column
|
||||
[Last updated: #date],
|
||||
if show_last_updated [Last updated: #date],
|
||||
// center column
|
||||
if multi_page { counter(page).display(both: true, "1 of 1") },
|
||||
// right column
|
||||
|
||||
@@ -8,7 +8,7 @@ description = "A modern résumé/curriculum vitæ template with high attention t
|
||||
categories = ["cv"]
|
||||
disciplines = ["business", "communication"]
|
||||
keywords = ["resume", "curriculum", "vitae", "cv"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
repository = "https://git.swaits.com/swaits/typst-collection"
|
||||
exclude = ["thumbnail.png", "tests"]
|
||||
|
||||
[template]
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
tests/**/out/
|
||||
build/
|
||||
tests/**/diff/
|
||||
tests/**/out/
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Stephen Waits <steve@waits.net>
|
||||
Copyright (c) 2025 Stephen Waits <steve@waits.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -41,7 +41,7 @@ different goals:
|
||||
### Import the package
|
||||
|
||||
```typst
|
||||
#import "@preview/glossy:0.8.0": *
|
||||
#import "@preview/glossy:0.9.0": *
|
||||
```
|
||||
|
||||
### Defining Glossary Terms
|
||||
@@ -128,9 +128,10 @@ 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)
|
||||
- `link-terms: false` // True if you want terms to link to their glossary entry
|
||||
- `term-links: false` // True if you want terms to link to their glossary entry
|
||||
|
||||
### Using Glossary Terms
|
||||
|
||||
@@ -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** |
|
||||
| ------------------- | -------------------------------------------------------------- |
|
||||
@@ -199,20 +208,70 @@ 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" |
|
||||
| -------------------------- | -------------------- |
|
||||
| `@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,11 +392,24 @@ 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 form terms to their
|
||||
**NOTE:** If the theme does not emit `entry.label`, linking from terms to their
|
||||
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.
|
||||
@@ -1,6 +0,0 @@
|
||||
watchexec \
|
||||
--watch . \
|
||||
--clear \
|
||||
--ignore 'tests/**/diff/**' \
|
||||
--ignore 'tests/**/out/**' \
|
||||
"typst-test r"
|
||||
@@ -0,0 +1,151 @@
|
||||
# Global settings
|
||||
set shell := ["bash", "-eu", "-o", "pipefail", "-c"]
|
||||
set unstable := true
|
||||
|
||||
# Tooling knobs (overridable via env)
|
||||
TT := env_var_or_default("TT", "tt")
|
||||
TT_JOBS := env_var_or_default("TT_JOBS", "4")
|
||||
TYPST := env_var_or_default("TYPST", "typst")
|
||||
TYPSTYLE := env_var_or_default("TYPSTYLE", "typstyle")
|
||||
|
||||
# Paths
|
||||
THUMB_SRC := "tests/demo/test.typ"
|
||||
THUMB_OUT := "thumbnail.png"
|
||||
THEME_SRC := "tests/theme-gallery/test.typ"
|
||||
THEME_OUT := "themeshots.png"
|
||||
DEMO_SRC := "tests/demo/test.typ"
|
||||
DEMO_OUT := "build/demo.pdf"
|
||||
|
||||
# Aliases
|
||||
alias c := check
|
||||
alias f := fmt
|
||||
alias t := test
|
||||
alias w := watch
|
||||
|
||||
# Default entrypoint
|
||||
[default]
|
||||
help:
|
||||
@just --list --unsorted
|
||||
|
||||
# ---------------------------- CI / quality ----------------------------
|
||||
|
||||
# Format all Typst files
|
||||
[group('ci')]
|
||||
fmt:
|
||||
rg --files -g '*.typ' | xargs -r {{TYPSTYLE}} --inplace
|
||||
|
||||
# Check formatting without modifying files
|
||||
[group('ci')]
|
||||
fmt-check:
|
||||
rg --files -g '*.typ' | xargs -r {{TYPSTYLE}} --check
|
||||
|
||||
# Run all quality checks
|
||||
[group('ci')]
|
||||
check: fmt-check test
|
||||
|
||||
# Run tests with optional arguments
|
||||
[group('ci')]
|
||||
test *args:
|
||||
{{TT}} run --jobs {{TT_JOBS}} {{args}}
|
||||
|
||||
# Accept test outputs as new references
|
||||
[group('ci')]
|
||||
accept *args:
|
||||
{{TT}} accept {{args}}
|
||||
|
||||
# ---------------------------- Dev UX ----------------------------
|
||||
|
||||
# Watch for changes and run tests automatically
|
||||
[group('dev')]
|
||||
watch *args:
|
||||
watchexec \
|
||||
--watch . \
|
||||
--clear \
|
||||
--delay-run 5s \
|
||||
--ignore 'tests/**/diff/**' \
|
||||
--ignore 'tests/**/out/**' \
|
||||
--ignore 'tests/**/ref/**' \
|
||||
"{{TT}} run --jobs {{TT_JOBS}} {{args}}"
|
||||
|
||||
# ---------------------------- Artifacts ----------------------------
|
||||
|
||||
# Build demo.typ -> demo.pdf
|
||||
[group('artifacts')]
|
||||
demo:
|
||||
mkdir -p "$(dirname {{DEMO_OUT}})"
|
||||
{{TYPST}} compile --root . {{DEMO_SRC}} {{DEMO_OUT}}
|
||||
@echo "Wrote {{DEMO_OUT}}"
|
||||
|
||||
# Build all preview images
|
||||
# Build all preview images
|
||||
[group('artifacts')]
|
||||
images:
|
||||
{{TT}} run theme-gallery && cp tests/theme-gallery/out/*.png {{THEME_OUT}}
|
||||
{{TT}} run demo && cp tests/demo/out/*.png {{THUMB_OUT}}
|
||||
|
||||
# ---------------------------- Housekeeping ----------------------------
|
||||
|
||||
# Remove all generated test files and build artifacts
|
||||
[group('housekeeping')]
|
||||
clean:
|
||||
rg --files tests -g '**/diff/**' -g '**/out/**' 2>/dev/null \
|
||||
| xargs -r dirname \
|
||||
| sort -u \
|
||||
| xargs -r bash -c 'for d; do echo "Removing files under: $d"; rm -rf -- "$d"/*; done' _ \
|
||||
|| true
|
||||
rm -rf build
|
||||
|
||||
# ---------------------------- Release tooling ----------------------------
|
||||
|
||||
# Bump version by level (major|minor|patch) or to explicit version
|
||||
[group('release')]
|
||||
[script("python3")]
|
||||
bump version_or_level:
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
arg = "{{version_or_level}}".strip()
|
||||
if not arg:
|
||||
raise SystemExit("Usage: just bump <major|minor|patch|x.y.z>")
|
||||
|
||||
# If it's a level keyword, calculate the new version
|
||||
if arg.lower() in {"major", "minor", "patch"}:
|
||||
level = arg.lower()
|
||||
data = Path("typst.toml").read_text()
|
||||
m = re.search(r'^version\s*=\s*"([^"]+)"', data, re.MULTILINE)
|
||||
if not m:
|
||||
raise SystemExit("Could not find current version in typst.toml")
|
||||
|
||||
major, minor, patch = map(int, m.group(1).split("."))
|
||||
old_version = m.group(1)
|
||||
|
||||
if level == "major":
|
||||
major, minor, patch = major + 1, 0, 0
|
||||
elif level == "minor":
|
||||
major, minor, patch = major, minor + 1, 0
|
||||
else:
|
||||
patch += 1
|
||||
|
||||
version = f"{major}.{minor}.{patch}"
|
||||
print(f"Bumping {level} version: {old_version} → {version}")
|
||||
else:
|
||||
# It's an explicit version
|
||||
version = arg
|
||||
print(f"Setting version to {version}")
|
||||
|
||||
# Update files
|
||||
def update(path: Path, pattern: re.Pattern):
|
||||
text = path.read_text()
|
||||
new_text, count = pattern.subn(lambda m: m.group(1) + version + m.group(3), text, count=1)
|
||||
if count == 0:
|
||||
raise SystemExit(f"Failed to update {path}")
|
||||
path.write_text(new_text)
|
||||
|
||||
update(Path("typst.toml"), re.compile(r'^(version\s*=\s*")([^"]+)(")', re.MULTILINE))
|
||||
update(Path("README.md"), re.compile(r'(#import "@preview/glossy:)([^"]+)(": \*)'))
|
||||
print(f"Updated typst.toml and README.md")
|
||||
|
||||
|
||||
# Run full pre-submission checks
|
||||
[group('release')]
|
||||
pre-submit: clean images check
|
||||
@@ -1,2 +1,2 @@
|
||||
#import "src/gloss.typ": init-glossary, glossary
|
||||
#import "src/gloss.typ": glossary, init-glossary
|
||||
#import "src/themes.typ": *
|
||||
@@ -59,7 +59,7 @@
|
||||
longplural: entry.at("longplural", default: __pluralize(long)),
|
||||
longarticle: entry.at("longarticle", default: __determine_article(long)),
|
||||
description: entry.at("description", default: none),
|
||||
group: entry.at("group", default: "")
|
||||
group: entry.at("group", default: ""),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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,18 @@
|
||||
// Returns:
|
||||
// none: Updates state as a side effect
|
||||
//
|
||||
#let __mark_term_used(key, count-as-first-use) = {
|
||||
#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()
|
||||
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 +164,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
|
||||
@@ -178,11 +183,27 @@
|
||||
// boolean: If the entry is used above the location in the document
|
||||
//
|
||||
#let __is_term_first_used(key, location: none) = {
|
||||
let c = counter(__gloss_label_prefix + key + __gloss_first_use_counter_postfix)
|
||||
let c = counter(
|
||||
__gloss_label_prefix + key + __gloss_first_use_counter_postfix,
|
||||
)
|
||||
c = if location == none { c.final() } else { c.at(location) }
|
||||
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 +228,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 +242,88 @@
|
||||
// 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 ("a" in modifiers or "an" in modifiers) and ("pl" in modifiers) {
|
||||
})
|
||||
if display-text != none and display-text != auto {
|
||||
// A supplement is provided, thus the mode is "supplement"
|
||||
modes-modifiers.push("supplement")
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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 +332,47 @@
|
||||
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 +394,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 +404,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 get_article = mode => {
|
||||
let wants_article = "an" in modifiers
|
||||
if not wants_article {
|
||||
""
|
||||
none
|
||||
} else if mode == "short" {
|
||||
entry.article + " "
|
||||
} else {
|
||||
@@ -308,67 +420,41 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 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 +466,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 +476,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,57 +489,44 @@
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
// |^^^^^|^^^^^^^^^ |^^^^^^^^ |^^^^^^^^^^
|
||||
// | | | \_ 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
|
||||
.map(meta => { // extract location and page number (or symbol)
|
||||
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))
|
||||
let page = numbering(
|
||||
__default(loc.page-numbering(), "1"),
|
||||
..counter(page).at(loc),
|
||||
)
|
||||
(loc, page)
|
||||
})
|
||||
.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.
|
||||
@@ -525,17 +598,23 @@
|
||||
format-term: __default-format-term,
|
||||
show-term: __default-show-term,
|
||||
term-links: false,
|
||||
body
|
||||
body,
|
||||
) = context {
|
||||
// Type checking
|
||||
let checked-entries = (:)
|
||||
for (key, entry) in entries {
|
||||
let checked-key = z.parse(key, z.string(), scope: ("dictionary key",))
|
||||
let checked-entry = z.parse(entry, dict-schema, scope: ("dictionary entry",))
|
||||
let checked-entry = z.parse(entry, dict-schema, scope: (
|
||||
"dictionary entry",
|
||||
))
|
||||
checked-entries.insert(checked-key, checked-entry)
|
||||
}
|
||||
let checked-format-term = z.parse(show-term, z.function(), scope: ("format-term",))
|
||||
let checked-show-term = z.parse(show-term, z.function(), scope: ("show-term",))
|
||||
let checked-format-term = z.parse(show-term, z.function(), scope: (
|
||||
"format-term",
|
||||
))
|
||||
let checked-show-term = z.parse(show-term, z.function(), scope: (
|
||||
"show-term",
|
||||
))
|
||||
let checked-body = z.parse(body, z.content(), scope: ("body",))
|
||||
|
||||
// Process and store each glossary entry
|
||||
@@ -556,7 +635,12 @@
|
||||
// - That "key" does not correspond to an actual entry,
|
||||
// - There is at least one modifier,
|
||||
// - The first modifier corresponds to an existing entry key.
|
||||
let can_swap = (lower(raw_key) == "a" or lower(raw_key) == "an") and not __has_entry(raw_key) and raw_modifiers.len() > 0 and __has_entry(raw_modifiers.first())
|
||||
let can_swap = (
|
||||
(lower(raw_key) == "a" or lower(raw_key) == "an")
|
||||
and not __has_entry(raw_key)
|
||||
and raw_modifiers.len() > 0
|
||||
and __has_entry(raw_modifiers.first())
|
||||
)
|
||||
|
||||
// If we can swap, use the first modifier as the key and insert "a" as the first modifier.
|
||||
let (key, modifiers) = if can_swap {
|
||||
@@ -568,7 +652,14 @@
|
||||
// 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
|
||||
@@ -601,7 +692,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
|
||||
@@ -624,14 +715,16 @@
|
||||
// Type checking
|
||||
let checked-title = z.parse(title, z.content(), scope: ("title",))
|
||||
let checked-groups = z.parse(groups, groups-list-schema, scope: ("groups",))
|
||||
let checked-ignore-case = z.parse(ignore-case, z.boolean(), scope: ("ignore-case",))
|
||||
let checked-ignore-case = z.parse(ignore-case, z.boolean(), scope: (
|
||||
"ignore-case",
|
||||
))
|
||||
let checked-theme = z.parse(theme, theme-schema, scope: ("theme",))
|
||||
|
||||
// Collect and organize entries by group
|
||||
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()
|
||||
}
|
||||
@@ -672,7 +765,7 @@
|
||||
long: entry.at("long"),
|
||||
description: entry.at("description"),
|
||||
label: [#metadata(key)#__entry_label(key)],
|
||||
pages: __create_backlinks(key)
|
||||
pages: __create_backlinks(key),
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -685,7 +778,9 @@
|
||||
let sorted_entries = if sort {
|
||||
current_entries
|
||||
// 1. create array of tuples with (lower [if ignore-case], entry)
|
||||
.map(e => { if ignore-case { (lower(e.short), e) } else { (e.short, e) } })
|
||||
.map(e => {
|
||||
if ignore-case { (lower(e.short), e) } else { (e.short, e) }
|
||||
})
|
||||
// 2. sort the tuples (by first element then second)
|
||||
.sorted() // NOTE: sorted() is NOT language-aware
|
||||
// 3. strip away the tuple's first element, leaving an array of entries
|
||||
@@ -713,10 +808,10 @@
|
||||
output.len(),
|
||||
for (i, entry) in entries.enumerate() {
|
||||
(checked-theme.entry)(entry, i, entries.len())
|
||||
}
|
||||
},
|
||||
)
|
||||
group_index += 1
|
||||
}
|
||||
},
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -10,8 +10,8 @@
|
||||
longplural: z.content(optional: true),
|
||||
description: z.content(optional: true),
|
||||
group: z.content(optional: true),
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
#let theme-schema = z.dictionary(
|
||||
@@ -19,7 +19,7 @@
|
||||
section: z.function(),
|
||||
group: z.function(),
|
||||
entry: z.function(),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
#let groups-list-schema = z.array(pre-transform: z.coerce.array)
|
||||
@@ -5,7 +5,6 @@
|
||||
v(1em)
|
||||
body
|
||||
},
|
||||
|
||||
group: (name, index, total, body) => {
|
||||
if name != "" and total > 1 {
|
||||
v(1.5em)
|
||||
@@ -16,7 +15,6 @@
|
||||
}
|
||||
body
|
||||
},
|
||||
|
||||
entry: (entry, index, total) => {
|
||||
let short-display = text(weight: "bold", entry.short)
|
||||
let long-display = if entry.long == none {
|
||||
@@ -40,10 +38,10 @@
|
||||
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(", ")),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -15,7 +15,6 @@
|
||||
heading(level: 1, title)
|
||||
body
|
||||
},
|
||||
|
||||
// Renders a group of related glossary terms
|
||||
// Parameters:
|
||||
// name: Group name (empty string for ungrouped terms)
|
||||
@@ -28,7 +27,6 @@
|
||||
}
|
||||
body
|
||||
},
|
||||
|
||||
// Renders a single glossary entry with term, definition, and page references
|
||||
// Parameters:
|
||||
// entry: Dictionary containing term data:
|
||||
@@ -36,7 +34,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,9 +60,9 @@
|
||||
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(", "))],
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -5,7 +5,6 @@
|
||||
heading(level: 1, smallcaps(title))
|
||||
body
|
||||
},
|
||||
|
||||
group: (name, index, total, body) => {
|
||||
if name != "" and total > 1 {
|
||||
v(1em)
|
||||
@@ -14,7 +13,6 @@
|
||||
}
|
||||
body
|
||||
},
|
||||
|
||||
entry: (entry, index, total) => {
|
||||
let short-display = text(weight: "regular", entry.short)
|
||||
let long-display = if entry.long == none {
|
||||
@@ -38,10 +36,10 @@
|
||||
columns: (1fr, auto),
|
||||
gutter: 1em,
|
||||
[#short-display#entry.label#long-display#description#entry.label],
|
||||
[#entry.pages]
|
||||
)
|
||||
}
|
||||
[#entry.pages.join(", ")],
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -17,7 +17,6 @@
|
||||
heading(level: 1, outlined: false, text(weight: "bold", size: 1.1em, title))
|
||||
body
|
||||
},
|
||||
|
||||
// Renders a group of related glossary terms
|
||||
// Parameters:
|
||||
// name: Group name (empty string for ungrouped terms)
|
||||
@@ -30,13 +29,12 @@
|
||||
spacing: 0.5em,
|
||||
pad(
|
||||
top: 0.5em,
|
||||
text(weight: "bold", size: 0.9em, name)
|
||||
)
|
||||
text(weight: "bold", size: 0.9em, name),
|
||||
),
|
||||
)
|
||||
}
|
||||
body
|
||||
},
|
||||
|
||||
// Renders a single glossary entry with term, definition, and page references
|
||||
// Parameters:
|
||||
// entry: Dictionary containing term data:
|
||||
@@ -44,7 +42,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) => {
|
||||
@@ -53,7 +51,7 @@
|
||||
size: 0.65em,
|
||||
weight: "medium",
|
||||
fill: gray.darken(60%),
|
||||
entry.short
|
||||
entry.short,
|
||||
)
|
||||
|
||||
let long-form = if entry.long == none {
|
||||
@@ -83,9 +81,9 @@
|
||||
text(
|
||||
size: 0.6em,
|
||||
fill: gray.darken(20%),
|
||||
entry.pages
|
||||
)
|
||||
)
|
||||
entry.pages.join(", "),
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -4,13 +4,13 @@
|
||||
heading(level: 1, title)
|
||||
body
|
||||
},
|
||||
|
||||
group: (name, index, total, body) => {
|
||||
if name != "" and total > 1 {
|
||||
heading(level: 2, name)
|
||||
}
|
||||
|
||||
table(columns: 4,
|
||||
table(
|
||||
columns: 4,
|
||||
stroke: none,
|
||||
inset: (x, y) => {
|
||||
if (x == 0) {
|
||||
@@ -22,11 +22,15 @@
|
||||
}
|
||||
},
|
||||
table.header([*Abbreviation*], [*Full Name*], [*Description*], [*Pages*]),
|
||||
..body
|
||||
..body,
|
||||
)
|
||||
},
|
||||
|
||||
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(", "),
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -15,7 +15,6 @@
|
||||
heading(level: 1, title)
|
||||
columns(2, body)
|
||||
},
|
||||
|
||||
// Renders a group of related glossary terms
|
||||
// Parameters:
|
||||
// name: Group name (empty string for ungrouped terms)
|
||||
@@ -28,7 +27,6 @@
|
||||
}
|
||||
body
|
||||
},
|
||||
|
||||
// Renders a single glossary entry with term, definition, and page references
|
||||
// Parameters:
|
||||
// entry: Dictionary containing term data:
|
||||
@@ -36,7 +34,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,11 +60,15 @@
|
||||
grid(
|
||||
columns: (auto, 1fr, 1em, auto),
|
||||
align: (left, center, center, right),
|
||||
[#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
|
||||
)
|
||||
[#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.join(", ")],
|
||||
// Page references
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
|
||||
// Helper functions for checking endings
|
||||
let ends_with = (suffix) => lower(word).ends-with(suffix)
|
||||
let ends_with_any = (suffixes) => suffixes.any((suffix) => ends_with(suffix))
|
||||
let ends_with = suffix => lower(word).ends-with(suffix)
|
||||
let ends_with_any = suffixes => suffixes.any(suffix => ends_with(suffix))
|
||||
|
||||
// Map of irregular plurals for common words
|
||||
let irregulars = (
|
||||
@@ -80,7 +80,18 @@
|
||||
// Irregular suffixes
|
||||
let f_to_ves = ("leaf", "loaf", "calf", "half", "wolf", "thief")
|
||||
let fe_to_ves = ("wife", "knife", "life")
|
||||
let o_to_os = ("photo", "piano", "halo", "radio", "video", "studio", "solo", "taco", "memo", "zero")
|
||||
let o_to_os = (
|
||||
"photo",
|
||||
"piano",
|
||||
"halo",
|
||||
"radio",
|
||||
"video",
|
||||
"studio",
|
||||
"solo",
|
||||
"taco",
|
||||
"memo",
|
||||
"zero",
|
||||
)
|
||||
|
||||
// Convenience
|
||||
let w = lower(word)
|
||||
|
||||
|
Before Width: | Height: | Size: 490 KiB After Width: | Height: | Size: 104 KiB |
@@ -6,10 +6,11 @@
|
||||
tps: (
|
||||
short: "TPS",
|
||||
long: "test procedure specification",
|
||||
description: "A document on how to run all the test procedures"),
|
||||
description: "A document on how to run all the test procedures",
|
||||
),
|
||||
)
|
||||
|
||||
#show: init-glossary.with(myGlossary, show-term: (body) => [#emph(body)])
|
||||
#show: init-glossary.with(myGlossary, show-term: body => [#emph(body)])
|
||||
|
||||
#set heading(numbering: "1.1")
|
||||
#set page(numbering: "1")
|
||||
@@ -40,18 +41,51 @@ 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": __default-format-term, __gls
|
||||
#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 = (
|
||||
@@ -77,12 +111,10 @@ which one to display.
|
||||
block(
|
||||
grid(
|
||||
columns: (auto, 1fr, auto),
|
||||
output,
|
||||
repeat([#h(0.25em) . #h(0.25em)]),
|
||||
entry.pages,
|
||||
output, repeat([#h(0.25em) . #h(0.25em)]), entry.pages.join(", "),
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
#glossary(theme: my-theme)
|
||||
|
Before Width: | Height: | Size: 882 KiB After Width: | Height: | Size: 187 KiB |
@@ -7,20 +7,23 @@
|
||||
short: "HTML",
|
||||
long: "Hypertext Markup Language",
|
||||
description: "A standard language for creating web pages",
|
||||
group: "Web"),
|
||||
group: "Web",
|
||||
),
|
||||
css: (
|
||||
short: "CSS",
|
||||
long: "Cascading Style Sheets",
|
||||
description: "A language used for describing the presentation of a document",
|
||||
group: "Web"),
|
||||
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."
|
||||
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, show-term: (body) => [#emph(body)])
|
||||
#show: init-glossary.with(myGlossary, show-term: body => [#emph(body)])
|
||||
|
||||
#set heading(numbering: "1.1")
|
||||
#set page(height: auto, width: 6.5in, margin: 1em, numbering: "1")
|
||||
@@ -78,18 +81,51 @@ 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": __default-format-term, __gls
|
||||
#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 = (
|
||||
@@ -115,14 +151,20 @@ which one to display.
|
||||
block(
|
||||
grid(
|
||||
columns: (auto, 1fr, auto),
|
||||
output,
|
||||
repeat([#h(0.25em) . #h(0.25em)]),
|
||||
entry.pages,
|
||||
output, repeat([#h(0.25em) . #h(0.25em)]), entry.pages.join(", "),
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
#glossary(theme: my-theme)
|
||||
#glossary(title: "Glossary with just empty group", groups: ("",), theme: theme-basic)
|
||||
#glossary(title: "Glossary with just Web group", groups: ("Web",), theme: theme-compact)
|
||||
#glossary(
|
||||
title: "Glossary with just empty group",
|
||||
groups: ("",),
|
||||
theme: theme-basic,
|
||||
)
|
||||
#glossary(
|
||||
title: "Glossary with just Web group",
|
||||
groups: ("Web",),
|
||||
theme: theme-compact,
|
||||
)
|
||||
@@ -54,7 +54,6 @@
|
||||
("usage", "a"),
|
||||
("user", "a"),
|
||||
("utensil", "a"),
|
||||
|
||||
// Acronym tests
|
||||
("ASCII", "an"),
|
||||
("CFO", "a"),
|
||||
@@ -80,9 +79,7 @@
|
||||
("WWW", "a"),
|
||||
("X.Y.Z.", "an"),
|
||||
("YAML", "a"),
|
||||
|
||||
// Extra tests (courtesy of LLM)
|
||||
|
||||
// Common English words starting with vowels
|
||||
("idea", "an"),
|
||||
("island", "an"),
|
||||
@@ -94,7 +91,6 @@
|
||||
("octopus", "an"),
|
||||
("atom", "an"),
|
||||
("item", "an"),
|
||||
|
||||
// Words starting with vowel but "yoo" sound (thus 'a')
|
||||
("universe", "a"),
|
||||
("unicycle", "a"),
|
||||
@@ -106,7 +102,6 @@
|
||||
("useful", "a"),
|
||||
("utility", "a"),
|
||||
("utopia", "a"),
|
||||
|
||||
// More common vowel words with a/an
|
||||
("umbrella", "an"), // repeated but reaffirming
|
||||
("eggplant", "an"),
|
||||
@@ -118,7 +113,6 @@
|
||||
("aroma", "an"),
|
||||
("ear", "an"),
|
||||
("ocean", "an"),
|
||||
|
||||
// Words starting with 'h' but pronounced, so 'a'
|
||||
("house", "a"), // repeated for emphasis
|
||||
("hammer", "a"),
|
||||
@@ -130,14 +124,12 @@
|
||||
("holiday", "a"),
|
||||
("harmony", "a"),
|
||||
("hover", "a"),
|
||||
|
||||
// More silent 'h' words (already in set, but variations)
|
||||
("honorific", "an"),
|
||||
("honorarium", "an"),
|
||||
("honesties", "an"),
|
||||
("hourly", "an"),
|
||||
("heirloom", "an"),
|
||||
|
||||
// Words starting with 'e' + 'u' combo with "yoo" sound
|
||||
("Europe", "a"), // repeated
|
||||
("European", "a"), // repeated
|
||||
@@ -149,7 +141,6 @@
|
||||
("euthanasia", "a"),
|
||||
("eugenics", "a"),
|
||||
("Eurasia", "a"),
|
||||
|
||||
// Common consonant-start words
|
||||
("book", "a"),
|
||||
("pen", "a"),
|
||||
@@ -161,7 +152,6 @@
|
||||
("river", "a"),
|
||||
("mountain", "a"),
|
||||
("cloud", "a"),
|
||||
|
||||
// More vowel-start words
|
||||
("ostrich", "an"),
|
||||
("amphibian", "an"),
|
||||
@@ -173,7 +163,6 @@
|
||||
("aisle", "an"),
|
||||
("oracle", "an"),
|
||||
("overcoat", "an"),
|
||||
|
||||
// More acronym/initialism tests:
|
||||
("ATM", "an"), // A = 'ay'
|
||||
("EPA", "an"), // E = 'ee'
|
||||
@@ -185,7 +174,6 @@
|
||||
("OSHA", "an"), // O = 'oh'
|
||||
("RAM", "an"), // R = 'ar'
|
||||
("SMS", "an"), // repeated, S = 'ess'
|
||||
|
||||
// Acronyms starting with consonant sound letters
|
||||
("GIF", "a"), // G = 'jee', repeated
|
||||
("CFO", "a"), // C = 'see', repeated (consonant sound 's')
|
||||
@@ -197,7 +185,6 @@
|
||||
("UPS", "a"), // U = 'yoo' sound, hence 'a'
|
||||
("VIP", "a"), // V = 'vee' starts with 'v' consonant sound
|
||||
("WIPO", "a"), // W = 'double-u' starts with 'd' consonant sound
|
||||
|
||||
// More tricky 'u' words with 'yoo' sound for 'a'
|
||||
("unify", "a"),
|
||||
("unilateral", "a"),
|
||||
@@ -209,7 +196,6 @@
|
||||
("ugly", "an"), // repeated, 'uh-glee'
|
||||
("upper", "an"), // 'uh-pur' (vowel sound but actually 'uh' sound = 'an'? Actually "upper" starts with a simple vowel sound 'uh', so should it be 'an'? It's commonly "an upper hand".
|
||||
("update", "an"), // 'up-date' starts with 'uh' vowel sound → 'an update' normally. Actually we say "an update" commonly. Correcting to 'an':
|
||||
|
||||
// Words starting with 'u' that actually take "an"
|
||||
// (because they start with a vowel sound 'uh'):
|
||||
("under", "an"),
|
||||
@@ -225,7 +211,6 @@
|
||||
("universal", "a"),
|
||||
("umbrella", "an"), // repeated
|
||||
("upset", "an"), // 'uh-pset' vowel start
|
||||
|
||||
// More vowel words to ensure coverage:
|
||||
("animal", "an"),
|
||||
("image", "an"),
|
||||
@@ -240,7 +225,6 @@
|
||||
("item", "an"), // repeated
|
||||
("isotope", "an"),
|
||||
("opera", "an"),
|
||||
|
||||
// Words starting with vowels but pronounced with consonant sound 'y' → 'a'
|
||||
("euphemistic", "a"), // repeated
|
||||
("euphoric", "a"),
|
||||
@@ -252,7 +236,6 @@
|
||||
("eureka", "a"), // repeated
|
||||
("euphonious", "a"),
|
||||
("Eurasia", "a"),
|
||||
|
||||
// Common consonant-start words:
|
||||
("milk", "a"),
|
||||
("road", "a"),
|
||||
@@ -264,7 +247,6 @@
|
||||
("knife", "a"), // 'knife' actually starts with /n/ sound because 'k' is silent. "a knife" or "an knife"? It's "a knife" (starts with 'n' consonant sound?), actually 'kn' in 'knife' is silent, so 'knife' is pronounced 'nife' with a consonant sound 'n', so "a knife" is correct.
|
||||
("glass", "a"),
|
||||
("window", "a"),
|
||||
|
||||
// Final checks with tricky silent letters:
|
||||
("gnome", "a"), // 'g' silent, pronounced 'nome' with 'n' consonant sound → 'a gnome'
|
||||
("gnat", "a"), // 'nat' consonant sound → 'a gnat'
|
||||
@@ -280,7 +262,14 @@
|
||||
#for (word, article) in tests {
|
||||
let chosen = __determine_article(word)
|
||||
if chosen != article {
|
||||
panic("bad choice! word: " + word + ", article: " + article + ", chosen: " + chosen)
|
||||
panic(
|
||||
"bad choice! word: "
|
||||
+ word
|
||||
+ ", article: "
|
||||
+ article
|
||||
+ ", chosen: "
|
||||
+ chosen,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,20 +5,24 @@
|
||||
short: "HTML",
|
||||
long: "Hypertext Markup Language",
|
||||
description: "A standard language for creating web pages",
|
||||
group: "Web"),
|
||||
group: "Web",
|
||||
),
|
||||
css: (
|
||||
short: "CSS",
|
||||
long: "Cascading Style Sheets",
|
||||
description: "A language used for describing the presentation of a document",
|
||||
group: "Web"),
|
||||
group: "Web",
|
||||
),
|
||||
tps: (
|
||||
short: "TPS",
|
||||
long: "test procedure specification",
|
||||
description: "A document on how to run all the test procedures"),
|
||||
description: "A document on how to run all the test procedures",
|
||||
),
|
||||
concise: "Concise syntax!",
|
||||
shortonly: (
|
||||
short: "shortonly!!!"),
|
||||
unused: "Unused term, which shouldn't print in the glossary."
|
||||
short: "shortonly!!!",
|
||||
),
|
||||
unused: "Unused term, which shouldn't print in the glossary.",
|
||||
)
|
||||
|
||||
#set page(width: 6.5in, height: auto, margin: 1em)
|
||||
@@ -26,13 +30,11 @@
|
||||
#let test-content = {
|
||||
table(
|
||||
columns: 3,
|
||||
table.header(
|
||||
[`short`], [`long`], [`both`],
|
||||
),
|
||||
table.header([`short`], [`long`], [`both`]),
|
||||
|
||||
[@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 +42,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],
|
||||
)
|
||||
@@ -79,7 +81,7 @@
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
#let format-uppercase-short(mode, short-form, long-form) = {
|
||||
let short-up = upper(short-form);
|
||||
let short-up = upper(short-form)
|
||||
if mode == "short" {
|
||||
short-up
|
||||
} else if mode == "long" {
|
||||
@@ -108,8 +110,8 @@
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
#let format-conditional-separator(mode, short-form, long-form) = {
|
||||
let separator = if short-form.len() > 4 { " / " } else { ", " };
|
||||
let has_long = long-form != none and long-form != "";
|
||||
let separator = if short-form.len() > 4 { " / " } else { ", " }
|
||||
let has_long = long-form != none and long-form != ""
|
||||
|
||||
if mode == "short" {
|
||||
short-form
|
||||
@@ -124,7 +126,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
#init-glossary(myGlossary, format-term: format-conditional-separator)[#test-content]
|
||||
#init-glossary(
|
||||
myGlossary,
|
||||
format-term: format-conditional-separator,
|
||||
)[#test-content]
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// 1. Braces and Labels
|
||||
@@ -145,7 +150,9 @@
|
||||
// 2. Mode-Based Prefix
|
||||
// Idea: Add a prefix indicating the mode, and then show the term(s).
|
||||
#let format-mode-prefix(mode, short-form, long-form) = {
|
||||
let prefix = if mode == "short" { "S:" } else if mode == "long" { "L:" } else { "B:" };
|
||||
let prefix = if mode == "short" { "S:" } else if mode == "long" {
|
||||
"L:"
|
||||
} else { "B:" }
|
||||
if mode == "short" {
|
||||
prefix + short-form
|
||||
} else if mode == "long" {
|
||||
@@ -161,7 +168,7 @@
|
||||
// 3. Conditional Fallback for Missing Long
|
||||
// Idea: If no long-form is provided, use the short-form in all cases.
|
||||
#let format-fallback-long(mode, short-form, long-form) = {
|
||||
let has_long = long-form != none and long-form != "";
|
||||
let has_long = long-form != none and long-form != ""
|
||||
if mode == "short" {
|
||||
short-form
|
||||
} else if mode == "long" {
|
||||
@@ -193,7 +200,9 @@
|
||||
// Idea: In both mode, append the length of each string.
|
||||
#let format-length-info(mode, short-form, long-form) = {
|
||||
let s_len = str(short-form.len())
|
||||
let l_len = if long-form != none and long-form != "" { str(long-form.len()) } else { "0" }
|
||||
let l_len = if long-form != none and long-form != "" {
|
||||
str(long-form.len())
|
||||
} else { "0" }
|
||||
|
||||
if mode == "short" {
|
||||
short-form + " [len:" + s_len + "]"
|
||||
|
||||
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 99 KiB |
@@ -1,5 +1,5 @@
|
||||
#import "/lib.typ": *
|
||||
#import "@preview/glossarium:0.5.3": *
|
||||
#import "@preview/glossarium:0.5.9": *
|
||||
|
||||
#set page(height: auto, width: 4.5in)
|
||||
#show link: set text(fill: red)
|
||||
@@ -19,7 +19,7 @@
|
||||
This should be a link, too: @WWW
|
||||
|
||||
#glossary()
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -41,5 +41,5 @@
|
||||
This should be a link, too: @ML
|
||||
|
||||
#print-glossary(entry-list)
|
||||
]
|
||||
],
|
||||
)
|
||||
@@ -12,21 +12,21 @@ Reference: @pbr, @zbuffer
|
||||
]
|
||||
|
||||
#t("abbreviations") // "string" : str
|
||||
#t(("abbreviations")) // ("string") : str
|
||||
#t("abbreviations") // ("string") : str
|
||||
#t(("abbreviations",)) // ("string",) : array(str)
|
||||
#t(("abbreviations", "abbreviations")) // ("string","string",) : array(str)
|
||||
|
||||
#pagebreak(weak: true)
|
||||
|
||||
#t("") // empty string should be the empty group
|
||||
#t(("")) // empty string should be the empty group
|
||||
#t("") // empty string should be the empty group
|
||||
#t(("",)) // empty string should be the empty group
|
||||
#t(("", "")) // empty string should be the empty group
|
||||
|
||||
#pagebreak(weak: true)
|
||||
|
||||
#t(none) // none should be all groups
|
||||
#t((none)) // none should be all groups
|
||||
#t(none) // none should be all groups
|
||||
|
||||
#pagebreak(weak: true)
|
||||
|
||||
|
||||
@@ -5,17 +5,20 @@
|
||||
short: "HTML",
|
||||
long: "Hypertext Markup Language",
|
||||
description: "A standard language for creating web pages",
|
||||
group: "Web"),
|
||||
group: "Web",
|
||||
),
|
||||
css: (
|
||||
short: "CSS",
|
||||
long: "Cascading Style Sheets",
|
||||
description: "A language used for describing the presentation of a document",
|
||||
group: "Web"),
|
||||
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."
|
||||
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)
|
||||
@@ -24,9 +27,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
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 27 KiB |
@@ -5,17 +5,20 @@
|
||||
short: "HTML",
|
||||
long: "Hypertext Markup Language",
|
||||
description: "A standard language for creating web pages",
|
||||
group: "Web"),
|
||||
group: "Web",
|
||||
),
|
||||
css: (
|
||||
short: "CSS",
|
||||
long: "Cascading Style Sheets",
|
||||
description: "A language used for describing the presentation of a document",
|
||||
group: "Web"),
|
||||
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."
|
||||
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)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
tps: (
|
||||
short: "TPS",
|
||||
long: "test procedure specification",
|
||||
description: "A document on how to run all the test procedures"
|
||||
description: "A document on how to run all the test procedures",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
+ ". Expected: "
|
||||
+ (if expected == none { "none" } else { str(expected) })
|
||||
+ ", got: "
|
||||
+ (if result == none { "none" } else { str(result) })
|
||||
+ (if result == none { "none" } else { str(result) }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 502 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 534 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 376 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 407 KiB After Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 78 KiB |
@@ -37,43 +37,37 @@
|
||||
short: "HTML",
|
||||
long: "Hypertext Markup Language",
|
||||
description: "A standard language for creating web pages",
|
||||
group: "Web"
|
||||
group: "Web",
|
||||
),
|
||||
|
||||
css: (
|
||||
short: "CSS",
|
||||
long: "Cascading Style Sheets",
|
||||
description: "A language used for describing the presentation of documents",
|
||||
group: "Web"
|
||||
group: "Web",
|
||||
),
|
||||
|
||||
// Term with no description
|
||||
js: (
|
||||
short: "JS",
|
||||
long: "JavaScript",
|
||||
group: "Web"
|
||||
group: "Web",
|
||||
),
|
||||
|
||||
// Term with only a short field
|
||||
tcp: (
|
||||
short: "TCP",
|
||||
group: "Networking"
|
||||
group: "Networking",
|
||||
),
|
||||
|
||||
// Term with only a long field
|
||||
// should panic!
|
||||
//udp: (
|
||||
// long: "User Datagram Protocol",
|
||||
// group: "Networking"
|
||||
//),
|
||||
|
||||
// Term with short and description, but no long
|
||||
ip: (
|
||||
short: "IP",
|
||||
description: "A unique identifier for a host or network interface",
|
||||
group: "Networking"
|
||||
group: "Networking",
|
||||
),
|
||||
|
||||
// Term with custom articles and everything defined
|
||||
api: (
|
||||
short: "API",
|
||||
@@ -81,35 +75,30 @@
|
||||
description: "A set of protocols and tools for building software",
|
||||
article: "an", // custom article for short form
|
||||
longarticle: "an", // custom article for long form
|
||||
group: "Software"
|
||||
group: "Software",
|
||||
),
|
||||
|
||||
// Term starting with a vowel, no custom article, to test default a/an logic
|
||||
xml: (
|
||||
short: "XML",
|
||||
long: "Extensible Markup Language",
|
||||
description: "A markup language defining rules for encoding documents",
|
||||
group: "Data"
|
||||
group: "Data",
|
||||
),
|
||||
|
||||
// Term starting with a consonant, no custom article
|
||||
cpu: (
|
||||
short: "CPU",
|
||||
long: "Central Processing Unit",
|
||||
description: "The primary component of a computer that performs calculations",
|
||||
group: "Hardware"
|
||||
group: "Hardware",
|
||||
),
|
||||
|
||||
// Term without any fields (just a string), should be handled gracefully
|
||||
bare: "A bare term with no fields",
|
||||
|
||||
// Term with only description
|
||||
// should panic!
|
||||
//desconly: (
|
||||
// description: "Just a description, no short or long",
|
||||
// group: "Misc"
|
||||
//),
|
||||
|
||||
// Term with article fields but missing short and long (should test fallback)
|
||||
// should panic!
|
||||
//articonly: (
|
||||
@@ -118,51 +107,46 @@
|
||||
// description: "Has only articles and a description",
|
||||
// group: "Misc"
|
||||
//),
|
||||
|
||||
// Term with uppercase key
|
||||
SSL: (
|
||||
short: "SSL",
|
||||
long: "Secure Sockets Layer",
|
||||
description: "A protocol for encrypting information over the internet",
|
||||
group: "Security"
|
||||
group: "Security",
|
||||
),
|
||||
|
||||
// Term that will not be referenced
|
||||
unusedterm: (
|
||||
short: "UNUSED",
|
||||
long: "Unused Term",
|
||||
description: "Should not appear since it's never referenced"
|
||||
description: "Should not appear since it's never referenced",
|
||||
),
|
||||
|
||||
// Term that tests pluralization with custom fields maybe
|
||||
doc: (
|
||||
short: "doc",
|
||||
long: "document",
|
||||
description: "A single piece of written matter",
|
||||
group: "Misc"
|
||||
group: "Misc",
|
||||
),
|
||||
|
||||
// Terms that might require checking conflicting modifiers
|
||||
tps: (
|
||||
short: "TPS",
|
||||
long: "test procedure specification",
|
||||
description: "A document describing test procedures",
|
||||
group: "Testing"
|
||||
group: "Testing",
|
||||
),
|
||||
|
||||
// Term that might appear multiple times
|
||||
http: (
|
||||
short: "HTTP",
|
||||
long: "Hypertext Transfer Protocol",
|
||||
description: "A protocol for distributed, collaborative, hypermedia information systems",
|
||||
group: "Web"
|
||||
)
|
||||
group: "Web",
|
||||
),
|
||||
)
|
||||
|
||||
// Initialize the glossary with a custom show-term callback
|
||||
#show: init-glossary.with(
|
||||
exhaustiveGlossary,
|
||||
show-term: (body) => [#strong(body)]
|
||||
show-term: body => [#strong(body)],
|
||||
)
|
||||
|
||||
#set heading(numbering: "1.1")
|
||||
@@ -293,14 +277,32 @@ 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": __default-format-term, __gls
|
||||
#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
|
||||
|
||||
@@ -349,7 +351,7 @@ This document tries all reference forms and modifiers on a large set of terms.
|
||||
[`@api:cap` ], [@api:cap], ["capitalize"],
|
||||
[`@api:pl` ], [@api:pl], ["plural"],
|
||||
[`@api:long:cap`], [@api:long:cap], ["long + cap"],
|
||||
[`@api:both:pl` ], [@api:both:pl], ["both + pl"]
|
||||
[`@api:both:pl` ], [@api:both:pl], ["both + pl"],
|
||||
)
|
||||
|
||||
== Multiple glossaries with themes and group filtering
|
||||
@@ -366,7 +368,11 @@ This document tries all reference forms and modifiers on a large set of terms.
|
||||
|
||||
== Networking Only
|
||||
|
||||
#glossary(title: "Networking Terms", groups: ("Networking",), theme: theme-basic)
|
||||
#glossary(
|
||||
title: "Networking Terms",
|
||||
groups: ("Networking",),
|
||||
theme: theme-basic,
|
||||
)
|
||||
|
||||
== Misc and Data
|
||||
|
||||
@@ -374,17 +380,29 @@ This document tries all reference forms and modifiers on a large set of terms.
|
||||
|
||||
== Just Testing terms
|
||||
|
||||
#glossary(title: "Testing Terms", groups: ("Testing",), theme: theme-chicago-index)
|
||||
#glossary(
|
||||
title: "Testing Terms",
|
||||
groups: ("Testing",),
|
||||
theme: theme-chicago-index,
|
||||
)
|
||||
|
||||
== Hardware group
|
||||
|
||||
#glossary(title: "Hardware Terms", groups: ("Hardware",), theme: theme-chicago-index)
|
||||
#glossary(
|
||||
title: "Hardware Terms",
|
||||
groups: ("Hardware",),
|
||||
theme: theme-chicago-index,
|
||||
)
|
||||
|
||||
== Unreferenced entries
|
||||
|
||||
#glossary(title: "Unreferenced (Should Contain Unused?)", groups: ("Security",), theme: theme-chicago-index)
|
||||
#glossary(
|
||||
title: "Unreferenced (Should Contain Unused?)",
|
||||
groups: ("Security",),
|
||||
theme: theme-chicago-index,
|
||||
)
|
||||
|
||||
== Empty group glossary
|
||||
#glossary(title: "Empty Group Glossary", groups: (""), theme: theme-basic)
|
||||
#glossary(title: "Empty Group Glossary", groups: "", theme: theme-basic)
|
||||
|
||||
= End of Brutal Test
|
||||
|
Before Width: | Height: | Size: 652 KiB After Width: | Height: | Size: 135 KiB |
@@ -25,7 +25,7 @@
|
||||
#outline(title: "List of Figures", target: figure.where(kind: image))
|
||||
#block(
|
||||
height: 7em,
|
||||
glossary(title: "List of Abbreviations", theme: theme-twocol)
|
||||
glossary(title: "List of Abbreviations", theme: theme-twocol),
|
||||
)
|
||||
|
||||
#line(length: 100%)
|
||||
@@ -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,10 @@
|
||||
|
||||
#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%)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#show: init-glossary.with((
|
||||
one: "this is term one",
|
||||
two: "term two also"
|
||||
two: "term two also",
|
||||
))
|
||||
|
||||
#set page(
|
||||
@@ -19,15 +19,15 @@ shown anyway.
|
||||
|
||||
#glossary(
|
||||
theme: theme-chicago-index,
|
||||
show-all: true
|
||||
show-all: true,
|
||||
)
|
||||
|
||||
#glossary(
|
||||
theme: theme-compact,
|
||||
show-all: true
|
||||
show-all: true,
|
||||
)
|
||||
|
||||
#glossary(
|
||||
theme: theme-table,
|
||||
show-all: true
|
||||
show-all: true,
|
||||
)
|
||||
@@ -22,11 +22,11 @@
|
||||
tps: (
|
||||
short: "TPS",
|
||||
long: "test procedure specification",
|
||||
description: "A document on how to run all the test procedures"
|
||||
description: "A document on how to run all the test procedures",
|
||||
),
|
||||
)
|
||||
|
||||
#show: init-glossary.with(myGlossary, show-term: (body) => [#emph(body)])
|
||||
#show: init-glossary.with(myGlossary, show-term: body => [#emph(body)])
|
||||
|
||||
#set page(numbering: "1")
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
),
|
||||
iphone: (
|
||||
short: "iPhone",
|
||||
description: "Revolutionized phones."
|
||||
description: "Revolutionized phones.",
|
||||
),
|
||||
css: (
|
||||
short: "CSS",
|
||||
@@ -21,11 +21,11 @@
|
||||
tps: (
|
||||
short: "TPS",
|
||||
long: "test procedure specification",
|
||||
description: "A document on how to run all the test procedures"
|
||||
description: "A document on how to run all the test procedures",
|
||||
),
|
||||
)
|
||||
|
||||
#show: init-glossary.with(myGlossary, show-term: (body) => [#emph(body)])
|
||||
#show: init-glossary.with(myGlossary, show-term: body => [#emph(body)])
|
||||
|
||||
#set page(
|
||||
margin: 1cm,
|
||||
@@ -50,6 +50,6 @@
|
||||
inset: 1em,
|
||||
stroke: 1pt + gray,
|
||||
height: if theme.first() == "theme-twocol" { 1.5in } else { auto },
|
||||
glossary(title: raw(theme.first()), theme: theme.last(), ignore-case: true)
|
||||
glossary(title: raw(theme.first()), theme: theme.last(), ignore-case: true),
|
||||
)
|
||||
}
|
||||
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 650 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 906 KiB |
@@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "glossy"
|
||||
version = "0.8.0"
|
||||
compiler = "0.13.0"
|
||||
version = "0.9.0"
|
||||
compiler = "0.14.0"
|
||||
entrypoint = "lib.typ"
|
||||
authors = ["Stephen Waits <steve@waits.net>"]
|
||||
license = "MIT"
|
||||
description = "A very simple glossary system with easily customizable output."
|
||||
categories = ["model"]
|
||||
keywords = ["glossary", "index", "dictionary", "gloss"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
exclude = ["thumbnail.png", "themeshots.png", "tests", "bin"]
|
||||
repository = "https://git.swaits.com/swaits/typst-collection"
|
||||
exclude = ["justfile", "thumbnail.png", "themeshots.png", "tests", "bin"]
|
||||
@@ -8,7 +8,7 @@ description = "A formal business letter template."
|
||||
categories = ["office"]
|
||||
disciplines = ["business", "communication"]
|
||||
keywords = ["professional", "business", "letter", "correspondence"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
repository = "https://git.swaits.com/swaits/typst-collection"
|
||||
|
||||
[template]
|
||||
path = "template"
|
||||
|
||||
@@ -7,5 +7,5 @@ license = "MIT"
|
||||
description = "Bring RFC language into everyday docs"
|
||||
categories = ["utility"]
|
||||
keywords = ["rfc", "keywords", "rfc2119", "rfc8174", "bcp14"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
repository = "https://git.swaits.com/swaits/typst-collection"
|
||||
exclude = ["thumbnail.png", "tests"]
|
||||
@@ -7,5 +7,5 @@ license = "MIT"
|
||||
description = "Functions to create various run-in lists."
|
||||
categories = ["model"]
|
||||
keywords = ["run-in", "enum", "list", "terms"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
repository = "https://git.swaits.com/swaits/typst-collection"
|
||||
exclude = ["thumbnail.png", "tests", "bin", "docs/manual.pdf"]
|
||||
@@ -7,5 +7,5 @@ license = "MIT"
|
||||
description = "Render those funky logos for TeX, LaTeX, and friends."
|
||||
categories = ["utility"]
|
||||
keywords = ["tex", "latex", "luatex", "xetex", "lualatex", "xelatex", "logo"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
repository = "https://git.swaits.com/swaits/typst-collection"
|
||||
exclude = ["thumbnail.png", "tests"]
|
||||
@@ -6,5 +6,5 @@ authors = ["Stephen Waits <steve@waits.net>"]
|
||||
license = "MIT"
|
||||
description = "A carefully curated collection of font pairings."
|
||||
keywords = ["font", "pairing", "typography"]
|
||||
repository = "https://github.com/swaits/typst-collection"
|
||||
repository = "https://git.swaits.com/swaits/typst-collection"
|
||||
exclude = ["thumbnail.png", "tests"]
|
||||