I’ve been trying to add a little abbreviations feature to my Julia/Typst documents. My idea was to use percentage-fenced abbreviations which can easily be replaced using regex #show methods. My problem is that sometimes I want to show the code that generated a piece of content, some text or maybe a table. But the #show method will replace these strings in the raw code blocks as well. Can I restrict the #show method somehow so it doesn’t apply when we’re in a raw block?
#let ABBREVIATIONS = (
"O2": ([O#sub([2])], "Oxygen"),
)
#show regex("%.*?%"): word => {
let inner = word.text.slice(1, -1)
assert(inner in ABBREVIATIONS.keys(), message: "The abbreviation " + inner + " is not in the global abbreviation dictionary.")
ABBREVIATIONS.at(inner).at(0)
}
// this could be a code block that was rendered
```julia
println("%O2% is an example for an abbreviation")
```
// and this would be the output, both contain the string pattern
// but I only want to replace it below
%O2% is an example for an abbreviation
You can use a state to keep track of when you are in a raw element:
#let ABBREVIATIONS = (
"O2": ([O#sub([2])], "Oxygen"),
)
#let in-raw = state("in-raw", false)
#show raw: it => {
in-raw.update(true)
it
in-raw.update(false)
}
#show regex("%.*?%"): word => context {
if in-raw.get() {
return word
}
let inner = word.text.slice(1, -1)
assert(inner in ABBREVIATIONS.keys(), message: "The abbreviation " + inner + " is not in the global abbreviation dictionary.")
ABBREVIATIONS.at(inner).at(0)
}
```julia
println("%O2% is an example for an abbreviation")
```
%O2% is an example for an abbreviation
Nice, that seems to work well, thank you! And the #show raw method won’t interact with other show methods that might be defined for it, right? Like in a theme I’m applying.
It shouldn’t cause unwanted interactions… It’s just adding a state-update element before each raw element, and another state-update after it. The raw element is still there untouched.
I guess things could break if a piece of code introspects content and expects something specific before or after the raw element, but this would be unusual (and the kind of things that one should expect to break easily).
A good thing to do for increased robustness is to use a more unique state name: there might be another piece of code that also manipulates an "in-raw" state. So you might want to call your state "__julius-in-raw" or whatever (this should be less of an issue in the future).
Another approach is to check for some value on the style chain that you know is different inside of raw elements. For example the font:
#show regex("%.*?%"): word => {
if text.font == "dejavu sans mono" { // default raw font
return word
}
let inner = word.text.slice(1, -1)
assert(inner in ABBREVIATIONS.keys(), message: "The abbreviation " + inner + " is not in the global abbreviation dictionary.")
ABBREVIATIONS.at(inner).at(0)
}
It’s a bit of a hack: it would also affect non-raw text that uses this font for some reason.
I was thinking of the good ol’ wj hack, though here I had to also insert a wj check:
#let ABBREVIATIONS = (
"O2": ([O#sub([2])], "Oxygen"),
)
#show raw: it => {
show regex("%.*?%"): word => word.text.clusters().intersperse(sym.wj).join()
it
}
#show regex("%.*?%"): word => {
if word.text.find(sym.wj) != none { return word }
let inner = word.text.slice(1, -1)
assert(
inner in ABBREVIATIONS.keys(),
message: "The abbreviation " + inner + " is not in the global abbreviation dictionary."
)
ABBREVIATIONS.at(inner).at(0)
}
```julia
println("%O2% is an example for an abbreviation")
```
%O2% is an example for an abbreviation
Also no context.
I guess I can inline the symbol:
#show raw: it => {
show regex("%.*?%"): word => word.text.clusters().intersperse(sym.wj).join()
it
}
#show regex("%[^" + sym.wj + "]*?%"): word => {
let inner = word.text.slice(1, -1)
assert(
inner in ABBREVIATIONS.keys(),
message: "The abbreviation " + inner + " is not in the global abbreviation dictionary."
)
ABBREVIATIONS.at(inner).at(0)
}
Well, it’s literally old, which might explain it. You didn’t have context at the time, only locate(loc => {}), I think. It was used for substitutions that should only apply to one place: raw or normal.
I assume so too. Typst needs some extra operations for resolving context. But it has 2 text show rules, which probably will cancel the extra mini gain. But realistically, don’t sweat it until compilation becomes slow. The show rules will probably slow down compilation on very big documents because they will have to be applied to a ton of text elements. Profiling is the way.