How can I create something like #emph, where, when I press on it in the final pdf, it jumps to where it was mentioned first in maybe a #define thing in the pdf?
Kinda like refs, but a little different
== Definition (strict)
A function is called #define[strict], if $epi(f)$ is a strict set
== Example
$f(x) := x^2$ is a #word[strict] function
You can create links with the link function, and generate a label for each definition using the label function:
#let define(it) = [#emph(it)#label("define:" + it.text)]
#let word(it) = link(label("define:" + it.text), emph(it))
#let epi = math.op("epi")
== Definition (strict)
A function is called #define[strict], if $epi(f)$ is a strict set
#pagebreak()
== Example
$f(x) := x^2$ is a #word[strict] function
Ok that works pretty well, but could you also somehow just make a function which creates a label and then just reference it normally?
I tried ti do it myself, but I can’t get around the limit that you can’t label text
Is there something invisible you can reference? That would be extremely helpful
I tried a lot of things, but mainly just figures (I sadly don’t have the code anymore as it was very frustrating), but these had the problem that they caused newlines and when I hid them, the reference didn’t work because it was attached to nothing.
I also prompted ChatGPT and Gemini, but they tried to use metadata(), but this also can’t be referenced.
Basically the only thing I need is either an invisible figure I can reference and then actually use the reference or the ability to reference words.
With a show rule on ref, you can allow references on all kinds of elements, so you can do something like this.
#let define(word) = emph[#word#label(word.text)]
#show ref: it => {
if query(it.target) == ([#str(it.target)],) {
// The only element with the target label is the
// definition text containing the label name, so
// just show and link to that definition.
emph(link(it.target, str(it.target)))
} else {
it
}
}
Then, you can combine the #define[..] function call with normal references like this:
== Definition (strict)
A function is called #define[strict], if $epi(f)$ is a strict set
== Example
$f(x) := x^2$ is a @strict function
Thanks that works great, now how can I add something like an empty reference? I tried to add an input parameter and that worked, but if I understand your logic correctly, it won’t work when every invisible Label has the same invisible character
Inversion condition makes it shorter and easier to read (well, not the ([#str(it.target)],) part):
#show ref: it => {
if query(it.target) != ([#str(it.target)],) { return it }
// The only element with the target label is the
// definition text containing the label name, so
// just show and link to that definition.
emph(link(it.target, str(it.target)))
}
Actually, how could you make this work with stuff with space in them (for example in my case “strict convex”), I tried replacing " " with “-” and then converting it back but I’m not sure how to implement that logic
I see, that is also possible. Here is a more robust (and slightly more complex) way that allows arbitrary content in definitions and automatically attaches usable labels (with hyphens instead of spaces and other non-letter characters):
#let to-label(body) = {
// Convert body to string, replace non-letter characters with
// hyphens, and ensure that it doesn't end with a hyphen.
import "@preview/t4t:0.4.2": get
label(get.text(body)
.replace(regex("[^\p{L}\p{N}\-]+"), "-")
.trim("-", at: end))
}
#let define(word) = emph[#word#to-label(word)]
#show ref: it => {
// Elements that are referencable by default and whose
// reference appearance should not be overridden.
let referencable = (figure, math.equation, heading, footnote)
if it.element == none { return it }
if it.element.func() in referencable { return it }
if it.target != to-label(it.element) { return it }
// If the target element's body matches the label, show the
// reference as the element's body linked to the definition.
emph(link(it.target, it.element))
}
This would allow referencing something like #define[strict convex] with @strict-convex.
Quick note why referencable elements are excluded
To not intefere with standard references, elements which are already referencable are excluded. For example, in the case
the label <Hello> matches the text inside the rectangle, so the figure would have mistakenly been treated as a definition, replacing the “Figure 1” with a copy of the figure itself.
show ref: it => {
if it.element.has("body") and it.element.body == [ ] {
return emph(link(it.target, label-to-string(it.target)), bold: false)
}
let referencable = (figure, math.equation, heading, footnote)
if it.element == none { return it }
if it.element.func() in referencable { return it }
if it.target != to-label(it.element) { return it }
emph(link(it.target, it.element), bold: false)
}
and
#let to-label(body) = {
// Convert body to string, replace non-letter characters with
// hyphens, and ensure that it doesn't end with a hyphen.
import "@preview/t4t:0.4.2": get
label(get.text(body)
.replace(regex("[^\p{L}\p{N}\-]+"), "-")
.trim("-", at: end))
}
#let label-to-string(string) = str(string).replace("-", " ")
#let define(word, hide: false) = {
if hide {
[
#figure(
[ ],
)
#to-label(word)
#v(0fr)
]
// emph[#word#to-label(word)]
} else {
emph[#word#to-label(word)]
}
}