typst icon indicating copy to clipboard operation
typst copied to clipboard

Feature Request: List of Acronyms

Open JKRhb opened this issue 2 years ago • 11 comments

It would be great if there was a way to use acronyms in Typst similar to the functionality offered by LaTeX packages such as acronym or acro, making it possible to generate a List of Acronyms with only the acronyms that actually been used in the text.

As an advanced feature, these acronyms could also be expanded dynamically in the text, depending on whether they have been used before (i.e., only the first acronym would get printed in its full form, and following occurrences would use the short form).

JKRhb avatar Apr 07 '23 23:04 JKRhb

I have created a function for that maybe it helps.

acronyms.typ

// Dictionary with acronyms
#let acronyms = (
  API: "Application programmable interface",
)

// The state which tracks the used acronyms
#let usedAcronyms = state("usedDic", (_: ""))

// The function which either shows the acronym or the full text for it
#let acro(body) = {
  if(dict.keys().contains(body) == false) {
    return rect(
      fill: red,
      inset: 8pt,
      radius: 4pt,
      [*Warning:\ #body*],
    )
  }
  usedAcronyms.display(usedDic => {
    if(usedDic.keys().contains(body)) {
      return body
    }
    return dict.at(body) + " (" + body + ")"
  });
  usedAcronyms.update(usedDic => {
    usedDic.insert(body, true)
    return usedDic
  })
}

main.typ

#import "acronyms.typ": acro

// Call the function
#acro("API") // --> Application programmable interface (API)

// Second call only the acronym is shown
#acro("API") // --> API

jnlmmln avatar Apr 21 '23 14:04 jnlmmln

Thank you, @jnlmmln, that is a great start! :)

JKRhb avatar Apr 22 '23 10:04 JKRhb

You are welcome, here is also the code I use to show an overview (Glossar):

#import "acronyms.typ": usedAcronyms, acronyms
#locate(loc => usedAcronyms.final(loc)
.pairs()
.filter(x => x.last())
.map(pair => pair.first())
.sorted()
.map(key => grid(
    columns: (1fr, 1fr),
    gutter: 1em,
   strong(key),acronyms.at(key) 
  )).join())

jnlmmln avatar Apr 22 '23 11:04 jnlmmln

I have created a function for that maybe it helps.

acronyms.typ

// Dictionary with acronyms
#let acronyms = (
  API: "Application programmable interface",
)

// The state which tracks the used acronyms
#let usedAcronyms = state("usedDic", (_: ""))

// The function which either shows the acronym or the full text for it
#let acro(body) = {
  if(dict.keys().contains(body) == false) {
    return rect(
      fill: red,
      inset: 8pt,
      radius: 4pt,
      [*Warning:\ #body*],
    )
  }
  usedAcronyms.display(usedDic => {
    if(usedDic.keys().contains(body)) {
      return body
    }
    return dict.at(body) + " (" + body + ")"
  });
  usedAcronyms.update(usedDic => {
    usedDic.insert(body, true)
    return usedDic
  })
}

main.typ

#import "acronyms.typ": acro

// Call the function
#acro("API") // --> Application programmable interface (API)

// Second call only the acronym is shown
#acro("API") // --> API

I tried the code snipped above, but it gives me an error "expected comma" at the position of the underscore in the #let usedAcronyms definition. What am I doing wrong?

mareikep avatar May 10 '23 07:05 mareikep

I tried the code snipped above, but it gives me an error "expected comma" at the position of the underscore in the #let usedAcronyms definition. What am I doing wrong?

Try replacing (_: "") with (:). Moreover, dict needs to be replaced with acronyms in two places for it to work.

Explanation: I think the author didn't know how to create an empty dictionary, so they created one with an unused key like this: (_: ""). However, a lone underscore has since (in the last update) been forbidden as an identifier. The correct way to create an empty dictionary is (:).

laurmaedje avatar May 10 '23 11:05 laurmaedje

I tried the code snipped above, but it gives me an error "expected comma" at the position of the underscore in the #let usedAcronyms definition. What am I doing wrong?

Try replacing (_: "") with (:). Moreover, dict needs to be replaced with acronyms in two places for it to work.

Explanation: I think the author didn't know how to create an empty dictionary, so they created one with an unused key like this: (_: ""). However, a lone underscore has since (in the last update) been forbidden as an identifier. The correct way to create an empty dictionary is (:).

Thank you for the explanation. I wasn't familiar with the empty dictionary initialization here, so I had just replaced it by an empty list (not sure why we need a dictionary here anyway). The other errors were more obvious to fix. However, I have a working example now and a similar one for glossary entries, which came out nicely. Next step would be to a) add the page numbers where the glossary/acronym entry was used in the overview and b) have a nice overlay similar to the one, that typst shows for citations (which is really cool)

Any suggestions are highly appreciated :)

mareikep avatar May 10 '23 12:05 mareikep

I wasn't familiar with the empty dictionary initialization here, so I had just replaced it by an empty list (not sure why we need a dictionary here anyway).

That works too. Maybe the original author wanted to use a set-like structure for better performance. Shouldn't matter too much until the list of acronyms gets huge.

add the page numbers where the glossary/acronym entry was used in the overview

That's gonna be a bit trickier. Your best bet is probably to attach a bunch of generated labels to the entries and query for them.

have a nice overlay similar to the one, that typst shows for citations (which is really cool)

What do you mean with "overlay"?

laurmaedje avatar May 10 '23 13:05 laurmaedje

I wasn't familiar with the empty dictionary initialization here, so I had just replaced it by an empty list (not sure why we need a dictionary here anyway).

That works too. Maybe the original author wanted to use a set-like structure for better performance. Shouldn't matter too much until the list of acronyms gets huge.

good point. Currently there are not too many glossary or acronym entries in my document. But I might consider changing it back to dict once that happens.

add the page numbers where the glossary/acronym entry was used in the overview

That's gonna be a bit trickier. Your best bet is probably to attach a bunch of generated labels to the entries and query for them.

Good lord. Might give it a try when I really feel like it..

have a nice overlay similar to the one, that typst shows for citations (which is really cool)

What do you mean with "overlay"?

When you use cite (or @), typst seems to automatically create a ref to the respective entry in the bibliography list. In my compiled pdf, when I hover over the citation, it shows that it is a link and offers to jump there (Go to page XY), but also displays a preview of the page to jump to. Not sure if this is a typst thing or a feature of my document viewer I just happen to have discovered ;)

mareikep avatar May 10 '23 13:05 mareikep

displays a preview of the page to jump to

That's a feature of your PDF viewer! When you create a link that should happen automatically.

laurmaedje avatar May 10 '23 13:05 laurmaedje

In case someone needs more than just printing the short form from the second #acro usage ongoing: based on the snippet from jnlmmln I've created another acronym snippet with some more acro-like features (#acs, #acl, #acp, #acsp, #aclp). Still far from perfect, but usable.

Ciolv avatar May 16 '23 06:05 Ciolv

I just though I would provide what I am currently using, a simple function that takes a string or content, and collects the capital letters in a parenthesis, underlining them:

// Uppercase letters in `input` (string or content) are underlined, and put into a parenthesis in the end.
#let acronym(input, make_lower: true) = {
  set underline(evade: false)

  let input_string = if type(input) == "string" {
     input} else {input.text
  }
  let capitals = ()

  for letter in input_string {
  if letter.contains(regex("[A-Z]")) {
    capitals.push(letter)
    if make_lower {
      underline(lower(letter))
    } else {underline(letter)}
  } else {letter}
  }
  [ (#capitals.join())]
}

The following input: #acronym[Integrated Development Environment] generates image

KronosTheLate avatar May 26 '23 12:05 KronosTheLate

Now there is a package that is managing this. It is not the only one but the one I use as I consider it the best. https://github.com/typst/packages/tree/main/packages/preview/glossarium

dscso avatar Nov 04 '23 11:11 dscso

I'll close this as something that we'll continue to leave to packages.

laurmaedje avatar Apr 10 '24 12:04 laurmaedje