// glossary figure kind #let __glossary_figure = "glossary_entry" // prefix of label for references query #let __glossary_label_prefix = "glossary:" // global state containing the glossary entry and their location #let __glossary_entries = state("__glossary_entries", (:)) #let __query_labels_with_key(key, before: false) = { if before { query(selector(label(__glossary_label_prefix + key)).before(here(), inclusive: false)) } else { query(selector(label(__glossary_label_prefix + key))) } } // Reference a term #let gls(key, suffix: none, long: none, display: none) = { context { let __glossary_entries = __glossary_entries.final() if key in __glossary_entries { let entry = __glossary_entries.at(key) let gloss = __query_labels_with_key(key, before: true) let is_first = gloss == () let entlong = entry.at("long", default: "") let textLink = if display != none { [#display] } else if (is_first or long == true) and entlong != [] and entlong != "" and long != false { [#entlong#suffix (#entry.short#suffix)] } else { [#entry.short#suffix] } [#link(label(entry.key), textLink)#label(__glossary_label_prefix + entry.key)] } else { text(fill: red, "Glossary entry not found: " + key) } } } // reference to term with pluralisation #let glspl(key) = gls(key, suffix: "s") // show rule to make the references for glossary #let make-glossary(body) = { show ref: r => { if r.element != none and r.element.func() == figure and r.element.kind == __glossary_figure { // call to the general citing function gls(str(r.target), suffix: r.citation.supplement) } else { r } } body } #let __normalize-entry-list(entry_list) = { let new-list = () for entry in entry_list { new-list.push( ( key: entry.key, short: entry.short, long: entry.at("long", default: ""), desc: entry.at("desc", default: ""), group: entry.at("group", default: ""), ), ) } return new-list } #let print-glossary(entry_list, show-all: false, disable-back-references: false, enable-group-pagebreak: false) = { let entries = __normalize-entry-list(entry_list) __glossary_entries.update(x => { for entry in entry_list { x.insert( entry.key, entry, ) } x }) let groups = entries.map(x => x.at("group", default: "")).dedup() // move no group to the front groups.insert(0, "") groups.pop() for group in groups.sorted() { if group != "" [#heading(group, level: 2) ] for entry in entries.sorted(key: x => x.short) { if entry.group == group { [ #show figure.where(kind: __glossary_figure): it => it.caption #figure( supplement: "", kind: __glossary_figure, numbering: none, caption: { context { set align(left) set par(justify: true) let term_references = __query_labels_with_key(entry.key) if term_references.len() != 0 or show-all { let desc = entry.at("desc", default: "") let long = entry.at("long", default: "") let hasLong = long != "" and long != [] let hasDesc = desc != "" and desc != [] { set text(weight: 600) if hasLong { emph(entry.short) + [ -- ] + entry.long } else { emph(entry.short) } } if hasDesc [: #desc ] else [ ] if disable-back-references != true { set text(weight: "bold") box(width: 1fr, repeat[.]) [ ] term_references.map(x => x.location()).sorted(key: x => x.page()).fold( (values: (), pages: ()), ((values, pages), x) => if pages.contains(x.page()) { (values: values, pages: pages) } else { values.push(x) pages.push(x.page()) (values: values, pages: pages) }, ).values.map(x => link(x)[#numbering(x.page-numbering(), ..counter(page).at(x))]).join(", ") } else { h(1fr) } } } }, )[] #label(entry.key) #parbreak() ] } } if enable-group-pagebreak {pagebreak(weak: true)} } };