text-crossrefs: Typst + testing, coding and documentation improvements

This commit is contained in:
Bastien Dumont
2025-12-21 16:59:06 +01:00
parent 078b6ae71e
commit af22b6e167
15 changed files with 3236 additions and 207 deletions

View File

@ -1,4 +1,8 @@
# text-crossrefs: cross-references to arbitrary portions of text in Pandoc
---
title: "text-crossrefs: cross-references to arbitrary portions of text in Pandoc"
author: "Bastien Dumont (`bastien.dumont [at] posteo.net`)"
date: 2025/12/21
---
This filter extends Pandoc's cross-referencing abilities
with references to any portion of text
@ -11,16 +15,17 @@ It currently supports the following output formats:
* latex
* odt
* opendocument
* typst
## Format-specific preliminary notices
# Format-specific preliminary notices
### DOCX and ODT/Opendocument
## DOCX and ODT/Opendocument
When opening for the first time a file produced by Pandoc with _text-crossrefs_,
you should have to refresh the fields in order to get the correct values.
In LibreOffice, press `F9`; in Word, a dialog box should appear when the file opens.
### ConTeXt specifically
## ConTeXt specifically
Your template should include the following directive before `\starttext`
(as in the default template for ConTeXt):
@ -31,7 +36,7 @@ $header-includes$
$endfor$
```
### All TeX-based formats
## All TeX-based formats
All references are wrapped in a macro named `\crossrefenum`.
It has two optional arguments:
@ -41,17 +46,19 @@ the second indicates whether the prefix (e.g. “p. ”) should be printed or
The default values for these arguments should match
those of `tcrf-default-reftype` and `tcrf-default-prefixref`
(resp. `page` and `yes`, i.e. `withprefix`).
The mandatory argument of `\crossrefenum` is a group enclosing one or more groups.
Each of them contain a reference (either a single reference or a range).
The mandatory argument of `\crossrefenum` is a list of references (possibly ranges).
Here are some valid invocations:
* `\crossrefenum[note][withprefix]{{lblone}{lbltwo}{lblthree}}`
* `\crossrefenum[page][noprefix]{{lblone}{lbltwo}{lblthree}}`
* `\crossrefenum[noprefix]{{lblone}{lbltwo}{lblthree}}` (the first argument defaults to `page`)
* `\crossrefenum{{lblone}{lbltwo}{lblthree}}` (the second argument defaults to `withprefix`)
* `\crossrefenum{{only-one}}` (even if the enumeration is limited to one item, it must be in a group)
* `\crossrefenum{{lblone to lbltwo}{lblthree}}` (the first reference points to a range)
* `\crossrefenum[note][withprefix]{lblone, lbltwo, lblthree}`
* `\crossrefenum[page][noprefix]{lblone, lbltwo, lblthree}`
* `\crossrefenum[noprefix]{lblone, lbltwo, lblthree}` (the first argument defaults to `page`)
* `\crossrefenum{lblone, lbltwo, lblthree}` (the second argument defaults to `withprefix`)
* `\crossrefenum{only-one}`
* `\crossrefenum{lblone to lbltwo, lblthree}` (the first reference points to a range)
> **For users from before December 2025**: the formatting
> of the main argument of `\crossrefenum` [changed](#breaking-comma-crfnm).
It is up to you to define `\crossrefenum` in your preamble.
If your target format is LaTeX, it should be possible to define it as a wrapper
@ -91,9 +98,53 @@ Here are some hints about the implementation of the `\crossrefenum` macro:
```
## Usage
## Typst {#typst}
### Basics
You can either get an equivalent of `\crossrefenum` in Typst,
the implementation of which is to be provided in your document,
or simply output consecutive `#ref` commands.
The advantage of the first approach is that a `#crossrefenum` command
could handle a list of references intelligently
(e.g. printing “pp. 13 and 5” instead of “pp. 1, 2, 3, 5 and 5”;
see [my implementation in TeX](https://ctan.org/pkg/crossrefenum) for more examples).
The main drawback is that is has still to be implemented in Typst to date (14 December 2025),
which is why `text-crossrefs` uses the second approach by default.
The `#crossrefenum` command has the following parameters:
> ```
> crossrefenum(
> form: str,
> prefixed: bool,
> array dictionary label,
> ) -> content
> ```
>
> **form**: `"normal"`, `"page"`, `"pagenote"`, or an [accepted type](#tex-options)
>
> **prefixed**: whether to print the prefix (e.g. “p. ”)
>
> **main argument**: a label, a range, or an array of labels and ranges;
> ranges are dictionaries of the form `(beg: <label1>, end: <label2>)`
>
> To see examples, please convert `sample.md` to Typst using this filter.
See the [Typst-specific options](#typst-options) to know how to switch to `#crossrefenum`.
If you keep the defaults (outputting `#ref` commands),
you may wish to set some [formatting options](#docx-odt-options)
and to add a show rule for `#ref` to prevent it from typesetting prefixes (e.g. “p. ”)
in addition to those that `text-crossrefs` already inserts.
In the default mode, you can also (ab)use the `note` reference type to refer to
a heading, figure or equation by its number, for the `note` reference type
is mapped to the `normal` form in Typst, which is common to all these elements:
for instance, `[my-lbl]{.tcrf reftype=note}` will be translated as
`#ref(<my-lbl>, form: "normal")`, which may be printed as “Section 2”
if `my-lbl` is a label attached to a section heading.
# Usage
## Basics
Mark the span of text you want to refer to later
with an identifier composed of alphanumeric characters, periods, colons, underscores or hyphens:
@ -114,22 +165,23 @@ according to the value of the `reftype` attribute (defaults to `page`).
For instance, this:
``` markdown
See [publication]{.tcrf} for the publication date. I gave my
opinion in [my-evaluation]{.tcrf reftype=note}, [my-evaluation]{.tcrf}.
See [publication]{.tcrf} for the publication date.
I gave my opinion in [my-evaluation]{.tcrf reftype=note},
[my-evaluation]{.tcrf}.
```
will render in ConTeXt or LaTeX output:
will be rendered in ConTeXt or LaTeX output as:
``` tex
See \crossrefenum{{publication}} for the publication date. I expressed
my thoughts about it in \crossrefenum[note]{{my-evaluation}},
\crossrefenum{{my-evaluation}}.
See \crossrefenum{{publication}} for the publication date.
I expressed my thoughts about it in
\crossrefenum[note]{my-evaluation}, \crossrefenum{my-evaluation}.
```
If you want to give a reference by note _and_ page number like in the example above,
you can also use the following shorthand:
```md
``` markdown
[my-evaluation]{.tcrf reftype=pagenote}
```
@ -139,17 +191,19 @@ To suppress the prefixes (e.g. “p. ”), you can set the `prefixref` attribu
It can be useful, for instance, for small manually formatted indexes[^comma-syntax]:
``` markdown
Gaboriau: [publication, my-evaluation, reception]{.tcrf prefixref=no}
Gaboriau:
[publication, my-evaluation, reception]{.tcrf prefixref=no}
```
[^comma-syntax]: About the comma-delimited syntax used in this example, see [the section on enumerations below](#enums).
### Controlling where the label is placed
## Controlling where the label is placed
By default, labels are placed at the beginning of the spans.
You can change this via the attribute `refanchor`, which can be set to:
By default, most of Pandoc's writers place the labels
at the beginning of the span they identify (the Typst writer is an exception).
You can control the placement via the attribute `refanchor`, which can be set to:
* `beg` (default);
* `beg`;
* `end`;
* `both`.
@ -163,12 +217,13 @@ A typical use case is:
See [mylbl-beg>mylbl-end]{.tcrf}.
```
### Page ranges
## Page ranges
You can refer to a page range like this:
``` markdown
If you want to know more about _L'Affaire Lerouge_, see [publication>reception]{.tcrf}.
If you want to know more about _L'Affaire Lerouge_,
see [publication>reception]{.tcrf}.
```
The separator (here `>`) can be set to any string of characters
@ -185,10 +240,10 @@ The syntax of a range is[^customize-range-tex]:
[^customize-range-tex]: Note that [it can be customized](#tex-options).
In DOCX and ODT/Opendocument output,
In DOCX and ODT/Opendocument output and in the default Typst output,
a range will be printed as a range even if the numbers are identical.
### Enumerations {#enums}
## Enumerations {#enums}
You can enumerate several references as a comma-delimited list, for instance:
@ -202,12 +257,18 @@ In TeX-based output formats, they will be wrapped in `\crossrefenum` like this
and should be collapsed by the macro when it is desirable:
``` tex
\crossrefenum{{ref-one}{ref-two to ref-three}{ref-four}}
\crossrefenum{ref-one, ref-two to ref-three, ref-four}
```
## Customization
# Customization
### Common options {#common-opts}
Most of the customization variables expect a string.
In this case, they must not contain Markdown markup
and all breakable spaces must be replaced with the HTML entity `&#x20;`:
otherwise, only the first word is taken into account and leading and trailing spaces are ignored.
See `sample-with-options.md` for examples.
## Common options {#common-opts}
The following metadata fields can be set:
@ -227,7 +288,7 @@ The following metadata fields can be set:
* default value for the `reftype` attribute;
* defaults to `page`.
### Options specific to DOCX, ODT/Opendocument and (by default) Typst {#docx-odt-options}
## Options specific to DOCX, ODT/Opendocument and (by default) Typst {#docx-odt-options}
Here are some metadata fields for the `docx`, `odt` and `opendocument` formats.
They are also used for `typst` unless [`tcrf-typst-crossrefenum` is set to `true`](#typst-options)
@ -274,7 +335,7 @@ They are also used for `typst` unless [`tcrf-typst-crossrefenum` is set to `true
* the string inserted between the two last elements in an enumeration;
* defaults to `and` surrounded with spaces.
### Options specific to the formats based on TeX {#tex-options}
## Options specific to the formats based on TeX {#tex-options}
Since TeX is extensible, you may wish to support types
other than `page`, `note` and `pagenote` for ConTeXt and LaTeX output.
@ -295,7 +356,18 @@ In addition, the following metadata field can be used to control the rendering o
* the delimiter between the labels of a range in the TeX output file;
* defaults to `to` surrounded with spaces.
## Compatibility with other filters
## Options specific to Typst {#typst-options}
If the metadata field `tcrf-typst-crossrefenum` is set to `true` (defaults to `false`),
`text-crossrefs` will output `#crossrefenum` commands
modeled after the `\crossrefenum` macro for TeX-based formats (see [above](#typst)).
The implementation of this command must be provided by the user.
In this case, the metadata fields [specific to TeX](#tex-options) will be taken into account.
Otherwise, `text-crossrefs` will only output native `#ref` commands.
In this case, the metadata fields [specific to DOCX and ODT](#docx-odt-options) will be used.
# Compatibility with other filters
_text-crossrefs_ must be run after all filters that may create, delete or move footnotes, such as citeproc.
@ -328,3 +400,16 @@ not that:
Until December 2025, `yes`, `no`, `true` and `false` as metadata values
had to be put within double quotes. Now, they must not be quoted at all,
which is a more standard way to handle boolean values in YAML.
From December 2025, `text-crossrefs` formats
[the main argument of `\crossrefenum`]{#breaking-comma-crfnm}
as a comma-delimited list, not as a list of groups.
This is in line the new, more readable formatting implemented in the version 1.2
of [the _crossrefenum_ TeX package](https://ctan.org/pkg/crossrefenum).
# License
Copyright 20242025 Bastien Dumont (bastien.dumont [at] posteo.net).
The program and all related files, including the present documentation,
are under the MIT License: see LICENSE for more details.