Typst-Snippets/in-dexter.typ

93 lines
3.0 KiB
Plaintext

// Copyright 2023 Rolf Bremer, Jutta Klebe
// Use of this code is governed by the License in the LICENSE.txt file.
// For a 'how to use this package', see the accompanying .md, .pdf + .typ documents.
// Index Entry; used to mark an entry in the document to be included in the Index.
// An optional initial may be provided.
#let index(
content,
initial: none
) = locate(loc => [#metadata((initial: initial, content: content, location: loc.position()))<jkrb_index>])
// Create the index page.
#let make-index(title: none, outlined: false) = {
// This function combines the text(s) of a content.
let content-text(content) = {
let ct = ""
if content.has("text") {
ct = content.text
}
else {
for cc in content.children {
if cc.has("text") {
ct += cc.text
}
}
}
return ct
}
locate(loc => {
let elements = query(<jkrb_index>, loc)
let pages = (:)
let words = (:)
for el in elements {
let ct = content-text(el.value.content)
// Have we already know that entry text? If not,
// add it to our list of entry words
if pages.keys().contains(ct) != true {
pages.insert(ct, ())
}
// Add the new page entry to the list.
let ent = (page: el.value.location.page)
if not pages.at(ct).contains(ent){
pages.at(ct).push(ent)
}
}
for el in elements {
let ct = content-text(el.value.content)
if words.keys().contains(ct) != true {
words.insert(ct, ())
words.at(ct) = (content: el.value.content, initial: el.value.initial, pages: pages.at(ct))
}
}
// Sort the entries.
let initial-sorted(ct) = {
let char = words.at(ct).initial
if char == none {
char = content-text(words.at(ct).content)
}
return char
}
let sortedkeys = words.keys().sorted(key: initial-sorted)
// Output.
let register = ""
if title != none { heading(outlined: outlined, numbering: none, title) }
for sk in sortedkeys [
// Use class specific formatting for the page numbers.
#let formattedPageNumbers = words.at(sk).pages.map(en => {
link((page: en.page, x:0pt, y:0pt))[#strong[#en.page]]
})
#let firstCharacter = content-text(words.at(sk).content).first()
#if (words.at(sk).initial != none) {
firstCharacter = words.at(sk).initial
}
#if firstCharacter != register {
heading(level: 2, numbering: none, outlined: false, firstCharacter)
register = firstCharacter
}
#words.at(sk).content
#box(width: 1fr)
#formattedPageNumbers.join(", ")
]
})
}