Implémentation des énumérations et compatibilité avec tcrfenum.tex

This commit is contained in:
Bastien Dumont 2022-11-05 19:59:24 +01:00
commit e868420bf6
9 changed files with 1771 additions and 292 deletions

23
Makefile Normal file
View File

@ -0,0 +1,23 @@
.PHONY: test-all test-internal
SHELL=/bin/bash
return_statement_line_number := $(shell grep -nE '^return' text-crossrefs.lua | cut -d ':' -f 1)
line_before_return := $(shell echo $$(($(return_statement_line_number) - 1)))
test-all: test-internal test-context test-latex test-opendocument
test-internal: text-crossrefs.lua
-rm --interactive=never test/tmp.lua
sed -n 1,$(line_before_return)p text-crossrefs.lua > test/tmp.lua
cat test/test-functions.lua >> test/tmp.lua
chmod -w test/tmp.lua
pandoc -L test/tmp.lua <<< ''
@echo -e '==========================\nAll internal tests passed.\n==========================\n'
rm --interactive=never test/tmp.lua
test-%: text-crossrefs.lua sample.md
TESTED_FORMAT=$* pandoc -t native -L text-crossrefs.lua sample.md > test/tmp-$*.native
diff test/tmp-$*.native test/sample-$*.native
@echo -e '\n===============\ntest passed.\n===============\n'
rm test/tmp-$*.native

178
README.md
View File

@ -11,9 +11,47 @@ currently supports the following target formats:
* odt
* opendocument
It doesn't permit to refer to references in other files: if you want to do this, use text-extrefs.
It does not permit to refer to references in other files: if you want to do this, use text-extrefs.
N.-B.: When opening for the first time a DOCX or ODT/Opendocument file produced by Pandoc with text-crossrefs, you probably will 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.
## Format-specific preliminary notices
### DOCX and ODT/Opendocument
When opening for the first time a file produced by Pandoc with text-crossrefs, you probably will 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.
### TeX-based formats
All references are wrapped in a macro named `\tcrfenum`. It has two optional arguments: the first one is the reference type, the second specifies whether the prefix (e.g. “p. ”) should be printed or not (can be set to `withprefix`, `noprefix`, `yes` or `no`). 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 `\tcrfenum` is a group containing a list of groups. Each of them contain a reference (either a single reference or a range). Here are some valid invocations:
* \tcrfenum\[note\]\[withprefix\]{{lblone}{lbltwo}{lblthree}}
* \tcrfenum\[page\]\[noprefix\]{{lblone}{lbltwo}{lblthree}}
* \tcrfenum\[noprefix\]{{lblone}{lbltwo}{lblthree}} (the first argument defaults to `page`)
* \tcrfenum{{lblone}{lbltwo}{lblthree}} (the second argument defaults to `withprefix`)
* \tcrfenum{{only-one}} (even if the enumeration is limited to one item, it must be inside its own group)
* \tcrfenum{{lblone to lbltwo}{lblthree}} (the first reference points to a range)
It is up to you to define `\tcrfenum` in your preamble. If your target format is LaTeX, it should be possible to define it as a wrapper for the `\zcref` macro provided by [the zref-clever package](https://ctan.org/pkg/zref-clever). Alternatively, you can use [my implementation](TODO), which supports ConTeXt, LaTeX and other formats. Here are some hints about the implementation:
* [The `\tcrfenum` macro is supposed to output the numbers along with the prefixes and delimiters (e.g. “p. ” and “–”)]{#prefixes-tex};
* In ConTeXt, there is no way to retrieve the note number from a `\reference` or a `\pagereference` contained in the note as is customary in LaTeX. to work around this, footnotes are labelled automatically with the first identifier attached to a span in the note prefixed with `note:`. Contrary to the ConTeXt syntax, this label is placed _after_ the footnote content, which implies redefining the `\footnote` macro. If your template includes the `header-includes` metadata variable like in the default template, this redefinition will happen automatically. Otherwise, you can copy-paste the following code in your preamble:
``` {=tex}
\catcode`\@=11
\let\origfootnote\footnote
\def\footnote#1#2{
\def\tcrf@secondArg{#2}%
\ifx\tcrf@secondArg\tcrf@bracket
\def\tcrf@todo{\tcrf@footnote@withlabel{#1}#2} %
\else
\def\tcrf@todo{\origfootnote{#1}#2}%
\fi
\tcrf@todo
}
\def\tcrf@bracket{[}
\def\tcrf@footnote@withlabel#1[#2]{\origfootnote[#2]{#1}}
\catcode`\@=13
```
## Usage
@ -34,92 +72,152 @@ identifier composed of alphanumeric characters, periods, colons, underscores and
You can refer to it using another span with class `ref` containing
the target's identifier. If the targetted span is part of a
footnote, you can refer to it either by page or by note number according to
the value of the `type` attribute (defaults to `page`). For instance, this:
the value of the `reftype` attribute (defaults to `page`). For instance, this:
``` markdown
See [publication]{.ref} for the publication date. I gave my
opinion in [my-evaluation]{.ref type=note}, [my-evaluation]{.ref}.
See [publication]{.tcrf} for the publication date. I gave my
opinion in [my-evaluation]{.tcrf reftype=note}, [my-evaluation]{.tcrf}.
```
will render in LaTeX output:
will render in ConTeXt or LaTeX output:
``` tex
See p. \pageref{publication} for the publication date. I expressed
my thoughts about it in \ref{my-evaluation},
p. \pageref{my-evaluation}.
See \tcrfenum{{publication}} for the publication date. I expressed
my thoughts about it in \tcrfenum[note]{{my-evaluation}},
\tcrfenum{{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
[my-evaluation]{.ref type=pagenote}
[my-evaluation]{.tcrf reftype=pagenote}
```
You can refer to headers as well using either explicit or automatically generated identifiers (see Pandoc users guide).
To suppress the prefixes (e.g. “p. ”), you can set the `prefixref` attribute to `no` (defaults to `yes`). It can be useful, for instance, for small manually formatted indexes[^1]:
``` markdown
Gaboriau: [publication, my-evaluation, reception]{.tcrf prefixref=no}
```
[^1]: About the comma-delimited syntax used in this example, see [the section on enumerations below](#enums).
### 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]{.ref}.
If you want to know more about _L'Affaire Lerouge_, see [publication>reception]{.tcrf}.
```
The separator (here `>`) can be set to any string composed of characters other than alphanumeric, period, colon, underscore, hyphen and space.
In LaTeX and ConTeXt output, the page range will be printed as a simple page reference if the page numbers are identical. You can provide your own definition of the macro `\tcrfpagerangeref{<label1>}{<label2>}` in the preamble. In DOCX and ODT/Opendocument output, the same result can be achieved in a word processor by the means of automatic search and replace with regular expressions.
In LaTeX and ConTeXt output, the above-mentionned `\tcrfenum` macro should be defined so that the range is printed as a simple page reference if the page numbers are identical. The syntax of a range is:
## Enumerations
``` tex
\tcrfenum{{publication to reception}}
```
Rather
In DOCX and ODT/Opendocument output, the same result can be achieved in a word processor by automatically searching and replacing duplicates with regular expressions and/or macros.
### Enumerations {#enums}
You can enumerate several references as a comma-delimited list, for instance:
``` markdown
[ref-one, ref-two>ref-three, ref-four]{.tcrf}
```
In DOCX and ODT/Opendocument output, all these references will be printed, potentially resulting in unnecessary repetitions.
In TeX-based output formats, they will be wrapped in `\tcrfenum` like this:
``` tex
\tcrfenum{{ref-one}{ref-two to ref-three}{ref-four}}
```
## Customization
### Common options
The following metadata fields can be set as strings:
* `tcrf-references-enum-separator`:
* the string between two references in an enumeration in a reference span; can be composed of any characters not authorized in an identifier;
* defaults to `, ` (with a space after the comma).
* `tcrf-references-range-separator`:
* the string used to separate two references in a reference span; can be composed of any characters not authorized in an identifier;
* defaults to `>`.
* `tcrf-only-explicit-labels`:
* set it to `true` if you want that _tcrf_ handle only spans with class `label`;
* defaults to `false`.
* `tcrf-default-prefixref`:
* default value for the `prefixref` attribute;
* defaults to `yes`.
* `tcrf-default-reftype`:
* default value for the `reftype` attribute;
* defaults to `page`.
* `tcrf-filelabel-ref-separator`:
* only useful in conjunction with the text-exrefs filter;
* separator between external files' labels and references;
* defaults to `::`.
### Options specific to DOCX and ODT/Opendocument
Here are some metadata fields only useful in conjunction with `docx`, `odt` and `opendocument` formats (see [above](#prefixes-tex) why they are ignored with `context` and `latex`):
* `tcrf-page-prefix`:
* “page” prefix;
* defaults to `p. `.
* `tcrf-pages-prefix`:
* “pages” prefix;
* defaults to `p. `.
* defaults to `pp. `.
* `tcrf-note-prefix`:
* “note” prefix;
* defaults to `n. `.
* `tcrf-notes-prefix`:
* “notes” prefix;
* defaults to `nn. `.
* `tcrf-pagenote-separator`:
* the separator between the references when `type` is set to `pagenote`;
* the separator between the references when `reftype` is set to `pagenote`;
* defaults to `, `.
* `tcrf-pagenote-at-end`:
* the string printed at the end of a pagenote reference;
* defaults to an empty string, can be used to achieve something like *n. 3 (p. 5)*.
* `tcrf-pagenote-order`:
* the order in which the references to note and page are printed;
* defaults to `pagefirst`, can be set to `notefirst`.
* `tcrf-references-range-separator`:
* the string used to separate two references in a reference span; can be composed of any character not authorized in an identifier other than space or tab;
* defaults to `>`.
* defaults to the empty string, can be used to achieve something like *n. 3 (p. 5)*.
* `tcrf-pagenote-factorize-first-prefix-in-enum`:
* defines if the prefixes of the type printed first in a reference to page and note should be repeated (e.g. “p. 6, n. 1 and p. 9, n. 3”) or expressed globally at the beginning of the enumeration (e.g. “pp. 6, n. 1 and 9, n. 3”);
* defaults to `no`, can be set to `yes`.
* `tcrf-pagenote-first-type`:
* the information that is printed first in references to page and note;
* defaults to `page`, can be set to `note`.
* `tcrf-range-separator`:
* the string inserted between to page numbers in a range;
* defaults to `-`.
* the string inserted between the page numbers in a range;
* defaults to ``.
* `tcrf-references-enum-separator`:
* the string used to separate the elements of an enumeration in a reference span; can be composed of any character not authorized in an identifier other than space or tab;
* defaults to `;`.
* `tcrf-enum-separator`:
* the string used to separate the elements of an enumeration in a reference span;
* defaults to a comma followed by a space.
* `tcrf-multiple-delimiter`:
* the string inserted between two elements (but the two last ones) in an enumeration;
* defaults to a comma followed by a space.
* `tcrf-before-last-in-enum`:
* `tcrf-multiple-before-last`:
* the string inserted between the two last elements in an enumeration;
* defaults to `and` surrounded with spaces.
* `tcrf-only-explicit-labels`:
* set it to `true` if you want that _tcrf_ handle only spans with class `label`;
* defaults to `false`.
* `tcrf-default-info-type`:
* default value for the `type` attribute (`note`, `page` or `pagenote`);
* defaults to `page`.
* `tcrf-filelabel-ref-separator`:
* only useful in conjunction with the text-exrefs filter;
* separator between external files' labels and references;
* defaults to `::`.
### Options specific to the formats based on TeX
Since TeX is extensible, you may wish to support types other than `page`, `note` and `pagenote` for ConTeXt and LaTeX output. `tcrf-additional-types` can be provided with a list of supplementary accepted types, e.g.:
``` yaml
tcrf-additional-types:
- line
- figure
```
In addition, the following metadata field can be used to control the rendering of ranges of labels in `\tcrfenum`:
* `tcrf-range-delim-tcrfenum`:
* the delimiter between the labels of a range in the list of references passed to `\tcrfenum`;
* defaults to ` to ` (mind the spaces).
## Compatibility with other filters
@ -147,6 +245,6 @@ not that:
[@Jones1973, p. 5-70[]{#ref-to-jones}; @Doe2004]
```
You can set classes and attributes to your spans other than those defined by text-crossrefs (for instance `[some text]{#to-be-referred-to .highlighted color=red}` or `[reference]{.ref color=red}`). No span is removed.
You can set classes and attributes to your spans other than those defined by text-crossrefs (for instance `[some text]{#to-be-referred-to .highlighted color=red}` or `[reference]{.tcrf color=red}`). No span is removed.
Text-crossrefs is fully compatible with text-extrefs. Whenever possible, when a metadata is not set for text-extrefs, its value is taken from its text-crossrefs equivalent, so that you don't need to duplicate similar variables.

View File

@ -1,8 +1,12 @@
---
tcrf-pagenote-separator: '\ ('
tcrf-pagenote-at-end: ')'
header-includes: |
\input{tex-aux/tcrfenum}
---
(About the notes, see [toc-notes-begin>toc-notes-end]{.tcrf}.)
Émile Gaboriau published [_L'Affaire Lerouge_ in
1866]{#publication}.[^1]
@ -10,18 +14,22 @@ tcrf-pagenote-at-end: ')'
[It was very popular.]{#reception}
See [publication]{.ref} for the publication date. I expressed
my thoughts about it in [my-evaluation]{.ref type=pagenote}.
See [publication]{.tcrf} for the publication date. I expressed
my thoughts about it in [my-evaluation]{.tcrf reftype=pagenote}.
If you want to know more about _L'Affaire Lerouge_, see [publication>reception]{.ref}.
If you want to know more about _L'Affaire Lerouge_, see [publication>reception]{.tcrf}.
Here are some precisions.[^2]
[^2]: [Whatever format]{#format} you choose, you can [refer to a note]{#refer-to-note} by the identifier of [any of its spans. You can even [nest spans]{#nested-spans}!]{#which-identifier}
I want to refer to a note:
[I want to refer to a note]{#toc-notes-begin}:
* How can I refer to a note by its number? → See [refer-to-note]{.ref}.
* What formats are supported? → See [format]{.ref}.
* What if the note contains multiple spans with identifiers? → See [which-identifier]{.ref}.
* What happens if a span in contained in a span? → See [nested-spans]{.ref}.
* How can I refer to a note by its number? → See [refer-to-note]{.tcrf}.
* What formats are supported? → See [format]{.tcrf}.
* What if the note contains multiple spans with identifiers? → See [which-identifier]{.tcrf}.
* What happens if a span in contained in a span? → See [nested-spans]{.tcrf}.
* What are the notes? → [my-evaluation, format, refer-to-note]{.tcrf reftype=note}
* Where are the notes? → [my-evaluation, format]{.tcrf}
[]{#toc-notes-end}

16
test.md
View File

@ -1,16 +0,0 @@
---
tcrf-pagenote-separator: '\ ('
tcrf-pagenote-at-end: ')'
---
Émile Gaboriau published [_L'Affaire Lerouge_ in
1866]{#publication}.[^1]
[^1]: It is a very [fine piece of literature]{#my-evaluation}.
[It was very popular.]{#reception}
See [publication]{.ref} for the publication date. I expressed
my thoughts about it [my-evaluation]{.ref type=pagenote}.
Page range: [publication>reception]{.ref}

386
test/sample-context.native Normal file
View File

@ -0,0 +1,386 @@
[ Para
[ Str "(About"
, Space
, Str "the"
, Space
, Str "notes,"
, Space
, Str "see"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "context")
"\\tcrfenum{{toc-notes-begin to toc-notes-end}}"
]
, Str ".)"
]
, Para
[ Str "\201mile"
, Space
, Str "Gaboriau"
, Space
, Str "published"
, Space
, Str ""
, Span
( "publication" , [] , [] )
[ Emph [ Str "L\8217Affaire" , Space , Str "Lerouge" ]
, Space
, Str "in"
, SoftBreak
, Str "1866"
]
, Str "."
, RawInline (Format "context") ""
, Note
[ Para
[ Str "It"
, Space
, Str "is"
, Space
, Str "a"
, Space
, Str "very"
, Space
, Str ""
, Span
( "my-evaluation" , [] , [] )
[ Str "fine"
, Space
, Str "piece"
, Space
, Str "of"
, Space
, Str "literature"
]
, Str "."
]
]
, RawInline (Format "context") "[note:my-evaluation]"
]
, Para
[ Str ""
, Span
( "reception" , [] , [] )
[ Str "It"
, Space
, Str "was"
, Space
, Str "very"
, Space
, Str "popular."
]
]
, Para
[ Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline (Format "context") "\\tcrfenum{{publication}}" ]
, Space
, Str "for"
, Space
, Str "the"
, Space
, Str "publication"
, Space
, Str "date."
, Space
, Str "I"
, Space
, Str "expressed"
, SoftBreak
, Str "my"
, Space
, Str "thoughts"
, Space
, Str "about"
, Space
, Str "it"
, Space
, Str "in"
, Space
, Span
( "" , [ "tcrf" ] , [ ( "reftype" , "pagenote" ) ] )
[ RawInline
(Format "context") "\\tcrfenum[pagenote]{{my-evaluation}}"
]
, Str "."
]
, Para
[ Str "If"
, Space
, Str "you"
, Space
, Str "want"
, Space
, Str "to"
, Space
, Str "know"
, Space
, Str "more"
, Space
, Str "about"
, Space
, Emph [ Str "L\8217Affaire" , Space , Str "Lerouge" ]
, Str ","
, Space
, Str "see"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "context") "\\tcrfenum{{publication to reception}}"
]
, Str "."
]
, Para
[ Str "Here"
, Space
, Str "are"
, Space
, Str "some"
, Space
, Str "precisions."
, RawInline (Format "context") ""
, Note
[ Para
[ Str ""
, Span
( "format" , [] , [] )
[ Str "Whatever" , Space , Str "format" ]
, Space
, Str "you"
, Space
, Str "choose,"
, Space
, Str "you"
, Space
, Str "can"
, Space
, Str ""
, Span
( "refer-to-note" , [] , [] )
[ Str "refer"
, Space
, Str "to"
, Space
, Str "a"
, Space
, Str "note"
]
, Space
, Str "by"
, Space
, Str "the"
, Space
, Str "identifier"
, Space
, Str "of"
, Space
, Str ""
, Span
( "which-identifier" , [] , [] )
[ Str "any"
, Space
, Str "of"
, Space
, Str "its"
, Space
, Str "spans."
, Space
, Str "You"
, Space
, Str "can"
, Space
, Str "even"
, Space
, Str ""
, Span
( "nested-spans" , [] , [] )
[ Str "nest" , Space , Str "spans" ]
, Str "!"
]
]
]
, RawInline (Format "context") "[note:format]"
]
, Para
[ Str ""
, Span
( "toc-notes-begin" , [] , [] )
[ Str "I"
, Space
, Str "want"
, Space
, Str "to"
, Space
, Str "refer"
, Space
, Str "to"
, Space
, Str "a"
, Space
, Str "note"
]
, Str ":"
]
, BulletList
[ [ Plain
[ Str "How"
, Space
, Str "can"
, Space
, Str "I"
, Space
, Str "refer"
, Space
, Str "to"
, Space
, Str "a"
, Space
, Str "note"
, Space
, Str "by"
, Space
, Str "its"
, Space
, Str "number?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "context") "\\tcrfenum{{refer-to-note}}"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "formats"
, Space
, Str "are"
, Space
, Str "supported?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline (Format "context") "\\tcrfenum{{format}}" ]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "if"
, Space
, Str "the"
, Space
, Str "note"
, Space
, Str "contains"
, Space
, Str "multiple"
, Space
, Str "spans"
, Space
, Str "with"
, Space
, Str "identifiers?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "context") "\\tcrfenum{{which-identifier}}"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "happens"
, Space
, Str "if"
, Space
, Str "a"
, Space
, Str "span"
, Space
, Str "in"
, Space
, Str "contained"
, Space
, Str "in"
, Space
, Str "a"
, Space
, Str "span?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "context") "\\tcrfenum{{nested-spans}}"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "are"
, Space
, Str "the"
, Space
, Str "notes?"
, Space
, Str "\8594"
, Space
, Span
( "" , [ "tcrf" ] , [ ( "reftype" , "note" ) ] )
[ RawInline
(Format "context")
"\\tcrfenum[note]{{my-evaluation}{format}{refer-to-note}}"
]
]
]
, [ Plain
[ Str "Where"
, Space
, Str "are"
, Space
, Str "the"
, Space
, Str "notes?"
, Space
, Str "\8594"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "context")
"\\tcrfenum{{my-evaluation}{format}}"
]
]
]
]
, Para [ Str "" , Span ( "toc-notes-end" , [] , [] ) [] ]
]

386
test/sample-latex.native Normal file
View File

@ -0,0 +1,386 @@
[ Para
[ Str "(About"
, Space
, Str "the"
, Space
, Str "notes,"
, Space
, Str "see"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "latex")
"\\tcrfenum{{toc-notes-begin to toc-notes-end}}"
]
, Str ".)"
]
, Para
[ Str "\201mile"
, Space
, Str "Gaboriau"
, Space
, Str "published"
, Space
, RawInline (Format "latex") "\\label{publication}"
, Span
( "publication" , [] , [] )
[ Emph [ Str "L\8217Affaire" , Space , Str "Lerouge" ]
, Space
, Str "in"
, SoftBreak
, Str "1866"
]
, Str "."
, RawInline (Format "latex") ""
, Note
[ Para
[ Str "It"
, Space
, Str "is"
, Space
, Str "a"
, Space
, Str "very"
, Space
, RawInline (Format "latex") "\\label{my-evaluation}"
, Span
( "my-evaluation" , [] , [] )
[ Str "fine"
, Space
, Str "piece"
, Space
, Str "of"
, Space
, Str "literature"
]
, Str "."
]
]
, RawInline (Format "latex") ""
]
, Para
[ RawInline (Format "latex") "\\label{reception}"
, Span
( "reception" , [] , [] )
[ Str "It"
, Space
, Str "was"
, Space
, Str "very"
, Space
, Str "popular."
]
]
, Para
[ Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline (Format "latex") "\\tcrfenum{{publication}}" ]
, Space
, Str "for"
, Space
, Str "the"
, Space
, Str "publication"
, Space
, Str "date."
, Space
, Str "I"
, Space
, Str "expressed"
, SoftBreak
, Str "my"
, Space
, Str "thoughts"
, Space
, Str "about"
, Space
, Str "it"
, Space
, Str "in"
, Space
, Span
( "" , [ "tcrf" ] , [ ( "reftype" , "pagenote" ) ] )
[ RawInline
(Format "latex") "\\tcrfenum[pagenote]{{my-evaluation}}"
]
, Str "."
]
, Para
[ Str "If"
, Space
, Str "you"
, Space
, Str "want"
, Space
, Str "to"
, Space
, Str "know"
, Space
, Str "more"
, Space
, Str "about"
, Space
, Emph [ Str "L\8217Affaire" , Space , Str "Lerouge" ]
, Str ","
, Space
, Str "see"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "latex") "\\tcrfenum{{publication to reception}}"
]
, Str "."
]
, Para
[ Str "Here"
, Space
, Str "are"
, Space
, Str "some"
, Space
, Str "precisions."
, RawInline (Format "latex") ""
, Note
[ Para
[ RawInline (Format "latex") "\\label{format}"
, Span
( "format" , [] , [] )
[ Str "Whatever" , Space , Str "format" ]
, Space
, Str "you"
, Space
, Str "choose,"
, Space
, Str "you"
, Space
, Str "can"
, Space
, RawInline (Format "latex") "\\label{refer-to-note}"
, Span
( "refer-to-note" , [] , [] )
[ Str "refer"
, Space
, Str "to"
, Space
, Str "a"
, Space
, Str "note"
]
, Space
, Str "by"
, Space
, Str "the"
, Space
, Str "identifier"
, Space
, Str "of"
, Space
, RawInline (Format "latex") "\\label{which-identifier}"
, Span
( "which-identifier" , [] , [] )
[ Str "any"
, Space
, Str "of"
, Space
, Str "its"
, Space
, Str "spans."
, Space
, Str "You"
, Space
, Str "can"
, Space
, Str "even"
, Space
, RawInline (Format "latex") "\\label{nested-spans}"
, Span
( "nested-spans" , [] , [] )
[ Str "nest" , Space , Str "spans" ]
, Str "!"
]
]
]
, RawInline (Format "latex") ""
]
, Para
[ RawInline (Format "latex") "\\label{toc-notes-begin}"
, Span
( "toc-notes-begin" , [] , [] )
[ Str "I"
, Space
, Str "want"
, Space
, Str "to"
, Space
, Str "refer"
, Space
, Str "to"
, Space
, Str "a"
, Space
, Str "note"
]
, Str ":"
]
, BulletList
[ [ Plain
[ Str "How"
, Space
, Str "can"
, Space
, Str "I"
, Space
, Str "refer"
, Space
, Str "to"
, Space
, Str "a"
, Space
, Str "note"
, Space
, Str "by"
, Space
, Str "its"
, Space
, Str "number?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline (Format "latex") "\\tcrfenum{{refer-to-note}}"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "formats"
, Space
, Str "are"
, Space
, Str "supported?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline (Format "latex") "\\tcrfenum{{format}}" ]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "if"
, Space
, Str "the"
, Space
, Str "note"
, Space
, Str "contains"
, Space
, Str "multiple"
, Space
, Str "spans"
, Space
, Str "with"
, Space
, Str "identifiers?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "latex") "\\tcrfenum{{which-identifier}}"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "happens"
, Space
, Str "if"
, Space
, Str "a"
, Space
, Str "span"
, Space
, Str "in"
, Space
, Str "contained"
, Space
, Str "in"
, Space
, Str "a"
, Space
, Str "span?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline (Format "latex") "\\tcrfenum{{nested-spans}}"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "are"
, Space
, Str "the"
, Space
, Str "notes?"
, Space
, Str "\8594"
, Space
, Span
( "" , [ "tcrf" ] , [ ( "reftype" , "note" ) ] )
[ RawInline
(Format "latex")
"\\tcrfenum[note]{{my-evaluation}{format}{refer-to-note}}"
]
]
]
, [ Plain
[ Str "Where"
, Space
, Str "are"
, Space
, Str "the"
, Space
, Str "notes?"
, Space
, Str "\8594"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "latex") "\\tcrfenum{{my-evaluation}{format}}"
]
]
]
]
, Para
[ RawInline (Format "latex") "\\label{toc-notes-end}"
, Span ( "toc-notes-end" , [] , [] ) []
]
]

View File

@ -0,0 +1,397 @@
[ Para
[ Str "(About"
, Space
, Str "the"
, Space
, Str "notes,"
, Space
, Str "see"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "opendocument")
"pp.\160<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"toc-notes-begin\">000</text:bookmark-ref>\8211<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"toc-notes-end\">000</text:bookmark-ref>"
]
, Str ".)"
]
, Para
[ Str "\201mile"
, Space
, Str "Gaboriau"
, Space
, Str "published"
, Space
, Str ""
, Span
( "publication" , [] , [] )
[ Emph [ Str "L\8217Affaire" , Space , Str "Lerouge" ]
, Space
, Str "in"
, SoftBreak
, Str "1866"
]
, Str "."
, RawInline (Format "opendocument") ""
, Note
[ Para
[ Str "It"
, Space
, Str "is"
, Space
, Str "a"
, Space
, Str "very"
, Space
, Str ""
, Span
( "my-evaluation" , [] , [] )
[ Str "fine"
, Space
, Str "piece"
, Space
, Str "of"
, Space
, Str "literature"
]
, Str "."
]
]
, RawInline (Format "opendocument") ""
]
, Para
[ Str ""
, Span
( "reception" , [] , [] )
[ Str "It"
, Space
, Str "was"
, Space
, Str "very"
, Space
, Str "popular."
]
]
, Para
[ Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "opendocument")
"p.\160<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"publication\">000</text:bookmark-ref>"
]
, Space
, Str "for"
, Space
, Str "the"
, Space
, Str "publication"
, Space
, Str "date."
, Space
, Str "I"
, Space
, Str "expressed"
, SoftBreak
, Str "my"
, Space
, Str "thoughts"
, Space
, Str "about"
, Space
, Str "it"
, Space
, Str "in"
, Space
, Span
( "" , [ "tcrf" ] , [ ( "reftype" , "pagenote" ) ] )
[ RawInline
(Format "opendocument")
"p.\160<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"my-evaluation\">000</text:bookmark-ref>\160(n.\160<text:note-ref text:note-class=\"footnote\" text:reference-format=\"text\" text:ref-name=\"ftn0\">000</text:note-ref>)"
]
, Str "."
]
, Para
[ Str "If"
, Space
, Str "you"
, Space
, Str "want"
, Space
, Str "to"
, Space
, Str "know"
, Space
, Str "more"
, Space
, Str "about"
, Space
, Emph [ Str "L\8217Affaire" , Space , Str "Lerouge" ]
, Str ","
, Space
, Str "see"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "opendocument")
"pp.\160<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"publication\">000</text:bookmark-ref>\8211<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"reception\">000</text:bookmark-ref>"
]
, Str "."
]
, Para
[ Str "Here"
, Space
, Str "are"
, Space
, Str "some"
, Space
, Str "precisions."
, RawInline (Format "opendocument") ""
, Note
[ Para
[ Str ""
, Span
( "format" , [] , [] )
[ Str "Whatever" , Space , Str "format" ]
, Space
, Str "you"
, Space
, Str "choose,"
, Space
, Str "you"
, Space
, Str "can"
, Space
, Str ""
, Span
( "refer-to-note" , [] , [] )
[ Str "refer"
, Space
, Str "to"
, Space
, Str "a"
, Space
, Str "note"
]
, Space
, Str "by"
, Space
, Str "the"
, Space
, Str "identifier"
, Space
, Str "of"
, Space
, Str ""
, Span
( "which-identifier" , [] , [] )
[ Str "any"
, Space
, Str "of"
, Space
, Str "its"
, Space
, Str "spans."
, Space
, Str "You"
, Space
, Str "can"
, Space
, Str "even"
, Space
, Str ""
, Span
( "nested-spans" , [] , [] )
[ Str "nest" , Space , Str "spans" ]
, Str "!"
]
]
]
, RawInline (Format "opendocument") ""
]
, Para
[ Str ""
, Span
( "toc-notes-begin" , [] , [] )
[ Str "I"
, Space
, Str "want"
, Space
, Str "to"
, Space
, Str "refer"
, Space
, Str "to"
, Space
, Str "a"
, Space
, Str "note"
]
, Str ":"
]
, BulletList
[ [ Plain
[ Str "How"
, Space
, Str "can"
, Space
, Str "I"
, Space
, Str "refer"
, Space
, Str "to"
, Space
, Str "a"
, Space
, Str "note"
, Space
, Str "by"
, Space
, Str "its"
, Space
, Str "number?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "opendocument")
"p.\160<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"refer-to-note\">000</text:bookmark-ref>"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "formats"
, Space
, Str "are"
, Space
, Str "supported?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "opendocument")
"p.\160<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"format\">000</text:bookmark-ref>"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "if"
, Space
, Str "the"
, Space
, Str "note"
, Space
, Str "contains"
, Space
, Str "multiple"
, Space
, Str "spans"
, Space
, Str "with"
, Space
, Str "identifiers?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "opendocument")
"p.\160<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"which-identifier\">000</text:bookmark-ref>"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "happens"
, Space
, Str "if"
, Space
, Str "a"
, Space
, Str "span"
, Space
, Str "in"
, Space
, Str "contained"
, Space
, Str "in"
, Space
, Str "a"
, Space
, Str "span?"
, Space
, Str "\8594"
, Space
, Str "See"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "opendocument")
"p.\160<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"nested-spans\">000</text:bookmark-ref>"
]
, Str "."
]
]
, [ Plain
[ Str "What"
, Space
, Str "are"
, Space
, Str "the"
, Space
, Str "notes?"
, Space
, Str "\8594"
, Space
, Span
( "" , [ "tcrf" ] , [ ( "reftype" , "note" ) ] )
[ RawInline
(Format "opendocument")
"nn.\160<text:note-ref text:note-class=\"footnote\" text:reference-format=\"text\" text:ref-name=\"ftn0\">000</text:note-ref>, <text:note-ref text:note-class=\"footnote\" text:reference-format=\"text\" text:ref-name=\"ftn1\">000</text:note-ref> and <text:note-ref text:note-class=\"footnote\" text:reference-format=\"text\" text:ref-name=\"ftn1\">000</text:note-ref>"
]
]
]
, [ Plain
[ Str "Where"
, Space
, Str "are"
, Space
, Str "the"
, Space
, Str "notes?"
, Space
, Str "\8594"
, Space
, Span
( "" , [ "tcrf" ] , [] )
[ RawInline
(Format "opendocument")
"pp.\160<text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"my-evaluation\">000</text:bookmark-ref> and <text:bookmark-ref text:reference-format=\"page\" text:ref-name=\"format\">000</text:bookmark-ref>"
]
]
]
]
, Para [ Str "" , Span ( "toc-notes-end" , [] , [] ) [] ]
]

36
test/test-functions.lua Normal file
View File

@ -0,0 +1,36 @@
local refs
refs = parse_references_enum('mylabel')
assert(#refs == 1)
assert(refs[1].anchor == 'mylabel')
assert(not refs[1].end_of_range)
assert(make_raw_content_tex(refs, 'page', true)
== '\\tcrfenum{{mylabel}}')
assert(make_raw_content_tex(refs, 'page', false)
== '\\tcrfenum[noprefix]{{mylabel}}')
assert(make_raw_content_tex(refs, 'note', true)
== '\\tcrfenum[note]{{mylabel}}')
assert(make_raw_content_tex(refs, 'note', false)
== '\\tcrfenum[note][noprefix]{{mylabel}}')
refs = parse_references_enum('rangebeg>rangeend')
assert(#refs == 1)
assert(refs[1].anchor == 'rangebeg')
assert(refs[1].end_of_range == 'rangeend')
assert(make_raw_content_tex(refs, 'page', true)
== '\\tcrfenum{{rangebeg to rangeend}}')
refs = parse_references_enum('first, second')
assert(#refs == 2)
assert(refs[1].anchor == 'first')
assert(refs[2].anchor == 'second')
assert(make_raw_content_tex(refs, 'page', true)
== '\\tcrfenum{{first}{second}}')
refs = parse_references_enum('first, rangebeg>rangeend')
assert(#refs == 2)
assert(refs[1].anchor == 'first')
assert(refs[2].anchor == 'rangebeg')
assert(refs[2].end_of_range == 'rangeend')
assert(make_raw_content_tex(refs, 'page', true)
== '\\tcrfenum{{first}{rangebeg to rangeend}}')

View File

@ -1,14 +1,52 @@
-- TODO : permettre la citation de références multiples avec un seul préfixe
-- [ref-one, ref-two>ref-four, ref-three]{.ref} → pp. 1, 3-6 et 12
-- Compléter README et test une fois que ce sera fait.
local stringify = pandoc.utils.stringify
-- Begin of initialization
local IDENTIFIER_PATTERN = '[%w_.:-]+'
local TEXT_CROSSREF_CLASS = 'tcrf'
local REF_TYPE_ATTR = 'reftype'
local PREFIXED_ATTR = 'prefixref'
local IS_CONFIG_ARRAY = { ['additional_types'] = true }
local RAW_ATTRIBUTE
local IS_LABEL_SET_BY_PANDOC
local LABEL_TEMPLATE
local NOTELABEL_TEMPLATE
-- ConTeXt-specific tweak in order to add the label to the footnote
--[[
Placing the label in square brackets immediatly after \footnote
in the regular way would require unpacking the content
of the Note and wrapping them with the RawInlines
'\footnote[note:' .. label .. ']{' and '}'.
However, Notes have the strange property of being Inlines
that contain Blocks, so this would result in Blocks being
brought into the content of the object that contains the Note,
which would be invalid.
That's why we place the label at the end of the \footnote
and redefine the macro so that it takes it into account.
]]--
local function tweak_footnote_if_ConTeXt(metadata)
if RAW_ATTRIBUTE == 'context' then
local footnote_redefinition = [[
\catcode`\@=11
\let\origfootnote\footnote
\def\footnote#1#2{
\def\tcrf@secondArg{#2}%
\def\tcrf@bracket{[}%
\ifx\tcrf@secondArg\tcrf@bracket
\def\tcrf@todo{\tcrf@footnote@withlabel{#1}#2} %
\else
\def\tcrf@todo{\origfootnote{#1}#2}%
\fi
\tcrf@todo
}
\def\tcrf@footnote@withlabel#1[#2]{\origfootnote[#2]{#1}}
\catcode`\@=13
]]
if not metadata['header-includes'] then
metadata['header-includes'] = pandoc.MetaBlocks(pandoc.RawBlock('context', ''))
end
metadata['header-includes']:insert(pandoc.RawBlock('context', footnote_redefinition))
end
return metadata
end
-- Configuration
local function define_raw_attribute()
if FORMAT == 'native' then
@ -39,34 +77,44 @@ local function define_label_template()
end
end
define_raw_attribute()
define_label_template()
-- End of initialization
-- Configuration
local config = {
page_prefix = 'p. ',
pages_prefix = 'p. ',
pages_prefix = 'pp. ',
note_prefix = 'n. ',
pagenote_order = 'pagefirst',
notes_prefix = 'nn. ',
pagenote_first_type = 'page',
pagenote_separator = ', ',
pagenote_at_end = '',
pagenote_factorize_first_prefix_in_enum = 'no',
multiple_delimiter = ', ',
multiple_before_last = ' and ',
references_range_separator = '>',
range_separator = '-',
range_separator = '',
references_enum_separator = ', ',
only_explicit_labels = 'false',
default_info_type = 'page',
filelabel_ref_separator = '::'
default_reftype = 'page',
default_prefixref = 'yes',
filelabel_ref_separator = '::',
range_delim_tcrfenum = ' to ',
additional_types = {}
}
local accepted_types = {
page = true,
note = true,
pagenote = true
}
local function format_config_to_openxml()
to_format = { 'page_prefix',
local to_format = { 'page_prefix',
'pages_prefix',
'note_prefix',
'notes_prefix',
'pagenote_separator',
'pagenote_at_end',
'range_separator' }
'range_separator',
'multiple_delimiter',
'multiple_before_last' }
for i = 1, #to_format do
config[to_format[i]] = '<w:r><w:t xml:space="preserve">' ..
config[to_format[i]] .. '</w:t></w:r>'
@ -76,81 +124,46 @@ end
local function set_configuration_item_from_metadata(item, metamap)
metakey = 'tcrf-' .. string.gsub(item, '_', '-')
if metamap[metakey] then
-- The metadata values are Str in MetaInlines.
config[item] = metamap[metakey][1].c
if IS_CONFIG_ARRAY[item] then
-- The metadata values is a list of MetaInlines,
-- each of them contains a single Str.
for _, value_metalist in ipairs(metamap[metakey]) do
table.insert(config[item], value_metalist[1].text)
end
else
-- The metadata value is a single Str in a MetaInlines.
config[item] = metamap[metakey][1].text
end
end
end
local function configure(metadata)
define_raw_attribute()
define_label_template()
for item, _ in pairs(config) do
set_configuration_item_from_metadata(item, metadata)
end
if RAW_ATTRIBUTE == 'openxml' then
format_config_to_openxml()
end
if RAW_ATTRIBUTE == 'context' or RAW_ATTRIBUTE == 'latex' then
for _, additional_type in ipairs(config.additional_types) do
accepted_types[additional_type] = true
end
end
end
-- End of configuration
-- Extensions for the output document's format
local function define_tex_macros(document)
if RAW_ATTRIBUTE == 'context' then
local footnote_redefinition = '\\let\\oldfootnote\\footnote\n' ..
'\\define[2]\\footnote{\\oldfootnote[#2]{#1}%\n' ..
'\\expandafter\\edef\\csname #2pagenumber\\endcsname{\\userpage}}\n'
local predefined_strings =
'\\define\\tcrfpage{' .. config.page_prefix .. '}\n' ..
'\\define\\tcrfpages{' .. config.pages_prefix .. '}\n' ..
'\\define\\tcrfrangesep{' .. config.range_separator .. '}\n'
local range_ref = '\\ifdefined\\tcrfpagerangeref\\else\n' ..
'\\define[2]\\tcrfpagerangeref{' ..
'\\if' ..
'\\csname #1pagenumber\\endcsname' ..
'\\csname #2pagenumber\\endcsname\n' ..
'\\tcrfpage\\at[#1]\n' ..
'\\else\n' ..
'\\tcrfpages\\at[#1]\\tcrfrangesep\\at[#2]\\fi}\n' ..
'\\fi\n'
local macros_block = pandoc.RawBlock('context',
footnote_redefinition ..
predefined_strings ..
range_ref)
table.insert(document.blocks, 1, macros_block)
elseif RAW_ATTRIBUTE == 'latex' then
local predefined_strings =
'\\newcommand*{\\tcrfpage}{' .. config.page_prefix .. '}\n' ..
'\\newcommand*{\\tcrfpages}{' .. config.pages_prefix .. '}\n' ..
'\\newcommand*{\\tcrfrangesep}{' .. config.range_separator .. '}\n'
local label_redefinition = '\\let\\oldlabel\\label\n' ..
'\\renewcommand*{\\label}[1]{\\oldlabel{#1}%\n' ..
'\\expandafter\\xdef\\csname #1pagenumber\\endcsname{\\thepage}}\n'
local range_ref = '\\ifdefined\\tcrfpagerangeref\\else\n' ..
'\\newcommand*{\\tcrfpagerangeref}[2]{%\n' ..
'\\if' ..
'\\csname #1pagenumber\\endcsname' ..
'\\csname #2pagenumber\\endcsname\n' ..
'\\tcrfpage\\pageref{#1}\n' ..
'\\else\n' ..
'\\tcrfpages\\pageref{#1}\\tcrfrangesep\\pageref{#2}\\fi}\n' ..
'\\fi\n'
local macros_block = pandoc.RawBlock('latex',
predefined_strings ..
label_redefinition ..
range_ref)
table.insert(document.blocks, 1, macros_block)
end
return document
end
-- End of the extensions for the output document's format
-- Identifiers
-- Preprocessing of identifiers on notes
-- Necessary for those output format where a note can be referred to
-- only via an identifier directly attached to it, not to its content
local spans_to_note_labels = {}
local current_odt_note_index = 0
local is_first_span_in_note = true
local current_note_label
local text_to_note_labels = {}
local function map_span_to_label(span)
if RAW_ATTRIBUTE == 'opendocument' then
@ -168,7 +181,7 @@ local function map_spans_to_labels(container)
for i = 1, #container.content do
-- The tests must be separate in order to support spans inside spans.
if container.content[i].t == 'Span'
and container.content[i].identifier ~= ''
and container.content[i].identifier
then
map_span_to_label(container.content[i])
end
@ -181,7 +194,8 @@ end
local function map_spans_to_notelabels(note)
if RAW_ATTRIBUTE == 'context'
or RAW_ATTRIBUTE == 'opendocument'
or RAW_ATTRIBUTE == 'openxml' then
or RAW_ATTRIBUTE == 'openxml'
then
is_first_span_in_note = true
map_spans_to_labels(note)
current_odt_note_index = current_odt_note_index + 1
@ -189,12 +203,13 @@ local function map_spans_to_notelabels(note)
end
local function make_label(label)
if IS_LABEL_SET_BY_PANDOC then
return pandoc.Str('')
else
label_rawcode = string.gsub(LABEL_TEMPLATE, '{{label}}', label)
return pandoc.RawInline(RAW_ATTRIBUTE, label_rawcode)
-- pandoc.Null() cannot be used here because it is a Block element.
local label_pandoc_object = pandoc.Str('')
if not IS_LABEL_SET_BY_PANDOC then
local label_rawcode = string.gsub(LABEL_TEMPLATE, '{{label}}', label)
label_pandoc_object = pandoc.RawInline(RAW_ATTRIBUTE, label_rawcode)
end
return label_pandoc_object
end
local function labelize_span(span)
@ -209,8 +224,8 @@ local current_note_labels = {}
local collect_note_labels = {
Span = function(span)
if span.identifier ~= '' and
(config.only_explicit_labels == 'false' or span.classes:includes('label'))
if span.identifier ~= ''
and (config.only_explicit_labels == 'false' or span.classes:includes('label'))
then
table.insert(current_note_labels, span.identifier)
end
@ -218,227 +233,373 @@ local collect_note_labels = {
}
local function make_notelabel(pos)
-- About the strategy followed with ConTeXt,
-- see above tweak_footnote_if_ConTeXt.
local raw_code = ''
if pos == 'begin' then
if RAW_ATTRIBUTE == 'openxml' then
raw_code = string.gsub(
'<w:bookmarkStart w:id="{{label}}_Note" w:name="{{label}}_Note"/>',
'{{label}}', current_note_labels[#current_note_labels])
'{{label}}', current_note_labels[1])
end
elseif pos == 'end' then
if RAW_ATTRIBUTE == 'context' then
local label = current_note_labels[1] .. '_note'
raw_code = '{' .. label .. '}'
elseif RAW_ATTRIBUTE == 'openxml' then
if RAW_ATTRIBUTE == 'openxml' then
raw_code = string.gsub('<w:bookmarkEnd w:id="{{label}}_Note"/>',
'{{label}}', current_note_labels[1])
elseif RAW_ATTRIBUTE == 'context' then
raw_code = '[note:' .. current_note_labels[1] .. ']'
end
end
return pandoc.RawInline(RAW_ATTRIBUTE, raw_code)
end
local function labelize_note(note)
local labelized_note
local label_begin = make_notelabel('begin')
local label_end = make_notelabel('end')
return { label_begin, note, label_end }
end
local function map_text_to_note_labels(current_note_labels)
local note_label = 'note:' .. current_note_labels[1]
for _, text_label in ipairs(current_note_labels) do
text_to_note_labels[text_label] = note_label
end
end
function set_notelabels(note)
current_note_labels = {}
pandoc.walk_inline(note, collect_note_labels)
if #current_note_labels > 0 then
map_text_to_note_labels(current_note_labels)
return labelize_note(note)
end
end
-- End of identifiers-related code
-- End of preprocessing of identifiers on notes
-- References
-- Gathering of data from the references span
local function is_reference_valid(ref)
if string.find(ref, '^[' .. IDENTIFIER_PATTERN .. ']') then
error('text-crossrefs.lua: Invalid character in reference: ' .. ref ..
'\nIdentifier and reference names can only contain' ..
' alphanumerical characters, periods, underscores and hyphens.\n')
else
return true
end
local function new_ref(anchor, end_of_range)
-- A ref is a string-indexed table containing an "anchor" field
-- and an optionnal "end_of_range" field.
-- When "end_of_range" is non-nil, the ref is a range.
local ref = {}
ref.anchor = anchor
ref.end_of_range = end_of_range
return ref
end
local function is_ref_external(rawref)
if string.find(rawref, config.filelabel_ref_separator, 1, true) then
local function is_ref_external(raw_references)
if string.find(raw_references, config.filelabel_ref_separator, 1, true) then
return true
else
return false
end
end
local function is_ref_range(rawref)
if string.find(rawref, config.references_range_separator, 1, true) then
return true
else
return false
local function parse_possible_range(reference)
-- If reference is a string representing a range,
-- returns the strings representing the boundaries of the range.
-- Else, returns the string.
local range_first, range_second = nil
local delim_beg, delim_end = string.find(reference,
config.references_range_separator,
1, true)
if delim_beg then
range_first = string.sub(reference, 1, delim_beg - 1)
range_second = string.sub(reference, delim_end + 1)
end
return (range_first or reference), range_second
end
function get_first_reference_end_index(range_separator_index)
if range_separator_index then
return range_separator_index - 1
end
end
local function get_first_reference(rawref)
local _, file_ref_separator_index =
string.find(rawref, config.filelabel_ref_separator, 1, true)
local range_separator_index, _ =
string.find(rawref, config.references_range_separator, 1, true)
local ref = string.sub(rawref,
(file_ref_separator_index or 0) + 1,
get_first_reference_end_index(range_separator_index))
if is_reference_valid(ref) then return ref end
end
local function get_second_reference(rawref)
local second_ref_begin_index
local _, file_ref_separator_index =
string.find(rawref, config.filelabel_ref_separator, 1, true)
if file_ref_separator_index then
_, file_ref_separator_index =
string.find(rawref,
config.filelabel_ref_separator,
config.file_ref_separator_index + 1,
true)
second_ref_begin_index = file_ref_separator_index + 1
else
local _, range_separator_index, _ =
string.find(rawref, config.references_range_separator, 1, true)
second_ref_begin_index = range_separator_index + 1
end
local ref = string.sub(rawref, second_ref_begin_index)
if is_reference_valid(ref) then return ref end
end
local function analyze_reference_span(reference_span)
if #reference_span.content == 1 and reference_span.content[1].t == 'Str' then
raw_reference = reference_span.content[1].c
analyzed_reference = {}
analyzed_reference.is_external = is_ref_external(raw_reference)
analyzed_reference.is_range = is_ref_range(raw_reference)
if analyzed_reference.is_external then
analyzed_reference.filelabel = get_extfilelabel(raw_reference)
local function parse_next_reference(raw_references, beg_of_search)
-- Returns the ref corresponding to the next reference string
-- and the index which the parsing should be resumed at.
local current_ref = false
local next_ref_beg = nil
if beg_of_search < #raw_references then
-- The delimiter can be composed of more than one character.
local delim_beg, delim_end = string.find(raw_references,
config.references_enum_separator,
beg_of_search, true)
if delim_beg then
reference = string.sub(raw_references, beg_of_search, delim_beg - 1)
next_ref_beg = delim_end + 1
else
reference = string.sub(raw_references, beg_of_search)
next_ref_beg = #raw_references
end
analyzed_reference.first = get_first_reference(raw_reference)
if analyzed_reference.is_range then
analyzed_reference.second = get_second_reference(raw_reference)
end
return analyzed_reference
else
error('The content of a span with class ref must be a plain string.')
current_ref = new_ref(parse_possible_range(reference))
end
return current_ref, next_ref_beg
end
local function insert_page_target_in_xml(target)
local function parse_references_enum(raw_references)
-- raw_refs is a string consisting of a list of single references or ranges.
-- Returns an array of refs produced by "new_ref" above.
local parsed_refs = {}
local current_ref, next_ref_beg = parse_next_reference(raw_references, 1)
while current_ref do
table.insert(parsed_refs, current_ref)
current_ref, next_ref_beg =
parse_next_reference(raw_references, next_ref_beg)
end
return parsed_refs
end
local function error_on_attr(attr_key, attr_value, span_content)
error('Invalid value "' .. attr_value .. '" for attribute "' .. attr_key ..
'" in the span with class "' .. TEXT_CROSSREF_CLASS ..
'" whose content is "' .. stringify(span_content) .. '".')
end
local function get_ref_type(span)
local ref_type = span.attributes[REF_TYPE_ATTR] or config.default_reftype
if not accepted_types[ref_type] then
error_on_attr(REF_TYPE_ATTR, ref_type, span.content)
end
return ref_type
end
local function if_prefixed(span)
local prefixed_attr_value = span.attributes[PREFIXED_ATTR] or config.default_prefixref
if prefixed_attr_value ~= 'yes' and prefixed_attr_value ~= 'no' then
error_on_attr(PREFIXED_ATTR, prefixed_attr_value, span.content)
end
local is_prefixed = true
if prefixed_attr_value == 'no' then is_prefixed = false end
return is_prefixed
end
-- End of gathering of data from the references span
-- Formatting references as raw inlines.
local function make_tcrfenum_first_arg(ref_type)
local ref_type_is_explicit = ref_type ~= config.default_reftype
local tcrfenum_first_arg = ''
if ref_type_is_explicit then
tcrfenum_first_arg = '[' .. ref_type .. ']'
end
return tcrfenum_first_arg
end
local function make_tcrfenum_second_arg(is_prefixed)
local is_prefixed_is_explicit = is_prefixed ~= (config.default_prefixref == 'yes')
local tcrfenum_second_arg = ''
local is_prefixed_string = ''
if is_prefixed_is_explicit then
if is_prefixed then
is_prefixed_string = 'withprefix'
else
is_prefixed_string = 'noprefix'
end
tcrfenum_second_arg = '[' .. is_prefixed_string .. ']'
end
return tcrfenum_second_arg
end
local function make_tcrfenum_references_list(refs, ref_type)
local tcrfenum_references_list = ''
for i = 1, #refs do
local ref = refs[i]
local anchor = ref.anchor
if FORMAT == 'context'
and (ref_type == 'note' or ref_type == 'pagenote')
then
anchor = text_to_note_labels[anchor]
end
local texified_ref = '{' .. anchor
if ref.end_of_range then
texified_ref = texified_ref .. config.range_delim_tcrfenum .. ref.end_of_range
end
texified_ref = texified_ref .. '}'
tcrfenum_references_list = tcrfenum_references_list .. texified_ref
end
return tcrfenum_references_list
end
local function make_raw_content_tex(refs, ref_type, is_prefixed)
local texified_references = ''
texified_references = '\\tcrfenum'
.. make_tcrfenum_first_arg(ref_type)
.. make_tcrfenum_second_arg(is_prefixed)
.. '{' .. make_tcrfenum_references_list(refs, ref_type) .. '}'
return texified_references
end
local function make_prefix_xml(ref_type, is_plural)
local prefix = ''
if is_plural then
prefix = config[ref_type .. 's_prefix']
else
prefix = config[ref_type .. '_prefix']
end
return prefix
end
local function make_page_reference_xml(target, is_prefixed)
local xml_page_ref = ''
if is_prefixed then
xml_page_ref = make_prefix_xml('page', false)
end
if RAW_ATTRIBUTE == 'opendocument' then
return '<text:bookmark-ref ' ..
xml_page_ref = xml_page_ref ..
'<text:bookmark-ref ' ..
' text:reference-format="page" text:ref-name="' ..
target .. '">000</text:bookmark-ref>'
elseif RAW_ATTRIBUTE == 'openxml' then
return '<w:r><w:fldChar w:fldCharType="begin" w:dirty="true"/></w:r>' ..
xml_page_ref = xml_page_ref ..
'<w:r><w:fldChar w:fldCharType="begin" w:dirty="true"/></w:r>' ..
'<w:r><w:instrText xml:space="preserve"> PAGEREF ' ..
target .. ' \\h </w:instrText></w:r>' ..
'<w:r><w:fldChar w:fldCharType="separate"/></w:r>' ..
'<w:r><w:t>000</w:t></w:r>' ..
'<w:r><w:fldChar w:fldCharType="end"/></w:r>'
end
return xml_page_ref
end
local function format_page_reference(target)
if RAW_ATTRIBUTE == 'context' then
return config.page_prefix .. '\\at[' .. target .. ']'
elseif RAW_ATTRIBUTE == 'latex' then
return config.page_prefix .. '\\pageref{' .. target .. '}'
elseif RAW_ATTRIBUTE == 'opendocument' then
return config.page_prefix .. insert_page_target_in_xml(target)
elseif RAW_ATTRIBUTE == 'openxml' then
return config.page_prefix .. insert_page_target_in_xml(target)
local function make_pagerange_reference_xml(first, second, is_prefixed)
local prefix = ''
if is_prefixed then prefix = make_prefix_xml('page', true) end
return prefix .. make_page_reference_xml(first, false) ..
config.range_separator .. make_page_reference_xml(second, false)
end
local function make_note_reference_xml(target, is_prefixed)
local note_ref_xml = ''
if is_prefixed then
note_ref_xml = make_prefix_xml('note', false)
end
end
local function format_pagerange_reference(first, second)
if RAW_ATTRIBUTE == 'context' or RAW_ATTRIBUTE == 'latex' then
return '\\tcrfpagerangeref{' .. first .. '}{' .. second .. '}'
elseif RAW_ATTRIBUTE == 'opendocument' or RAW_ATTRIBUTE == 'openxml' then
return config.pages_prefix .. insert_page_target_in_xml(first) ..
config.range_separator .. insert_page_target_in_xml(second)
end
end
local function format_note_reference(target)
if RAW_ATTRIBUTE == 'context' then
return config.note_prefix .. '\\in[' .. spans_to_note_labels[target] .. '_note' .. ']'
elseif RAW_ATTRIBUTE == 'latex' then
return config.note_prefix .. '\\ref{' .. target .. '}'
elseif RAW_ATTRIBUTE == 'opendocument' then
return config.note_prefix .. '<text:note-ref text:note-class="footnote"' ..
if RAW_ATTRIBUTE == 'opendocument' then
note_ref_xml = note_ref_xml ..
'<text:note-ref text:note-class="footnote"' ..
' text:reference-format="text" text:ref-name="' ..
spans_to_note_labels[target] .. '">000</text:note-ref>'
(spans_to_note_labels[target] or '') .. '">000</text:note-ref>'
elseif RAW_ATTRIBUTE == 'openxml' then
return config.note_prefix ..
note_ref_xml = note_ref_xml ..
'<w:r><w:fldChar w:fldCharType="begin" w:dirty="true"/></w:r>' ..
'<w:r><w:instrText xml:space="preserve"> NOTEREF ' ..
target .. '_Note' .. ' \\h </w:instrText></w:r>' ..
(spans_to_note_labels[target] or '') .. '_Note' .. ' \\h </w:instrText></w:r>' ..
'<w:r><w:fldChar w:fldCharType="separate"/></w:r>' ..
'<w:r><w:t>000</w:t></w:r>' ..
'<w:r><w:fldChar w:fldCharType="end"/></w:r>'
end
return note_ref_xml
end
local function format_pagenote_reference(target)
if config.pagenote_order == 'pagefirst' then
return format_page_reference(target) .. config.pagenote_separator ..
format_note_reference(target) .. config.pagenote_at_end
elseif config.pagenote_order == 'notefirst' then
return format_note_reference(target) .. config.pagenote_separator ..
format_page_reference(target) .. config.pagenote_at_end
else
error('tcrf-pagenote-order must be set either to pagefirst or notefirst.')
local function make_pagenote_reference_xml(target, is_prefixed)
local pagenote_ref_xml = ''
if is_prefixed then
pagenote_ref_xml = make_prefix_xml(config.pagenote_first_type, false)
end
end
local function format_reference(target, info_type)
if info_type == 'page' and target.is_range then
return format_pagerange_reference(target.first, target.second)
elseif info_type == 'page' then
return format_page_reference(target.first)
elseif info_type == 'note' then
return format_note_reference(target.first)
elseif info_type == 'pagenote' then
return format_pagenote_reference(target.first)
if config.pagenote_first_type == 'page' then
pagenote_ref_xml = pagenote_ref_xml ..
make_page_reference_xml(target, false) ..
config.pagenote_separator .. make_note_reference_xml(target, true) ..
config.pagenote_at_end
elseif config.pagenote_first_type == 'note' then
pagenote_ref_xml = pagenote_ref_xml ..
make_note_reference_xml(target, false) ..
config.pagenote_separator .. make_page_reference_xml(target, true) ..
config.pagenote_at_end
else
error('Invalid value for attribute type in span with class ref: ' ..
info_type)
error('“tcrf-pagenote-first-type” must be set either to “page” or “note”.')
end
return pagenote_ref_xml
end
local function make_reference(span)
if span.classes:includes('ref') then
local target = analyze_reference_span(span)
if not target.is_external then
local info_type = span.attributes.type or config.default_info_type
local formatted_reference = format_reference(target, info_type)
span.content[1] = pandoc.RawInline(RAW_ATTRIBUTE, formatted_reference)
return span
local function make_reference_xml(ref, ref_type, is_prefixed)
local reference_xml = ''
if ref_type == 'page' and ref.end_of_range then
reference_xml =
make_pagerange_reference_xml(ref.anchor, ref.end_of_range, is_prefixed)
elseif ref_type == 'page' then
reference_xml = make_page_reference_xml(ref.anchor, is_prefixed)
elseif ref_type == 'note' then
reference_xml = make_note_reference_xml(ref.anchor, is_prefixed)
elseif ref_type == 'pagenote' then
reference_xml = make_pagenote_reference_xml(ref.anchor, is_prefixed)
end
return reference_xml
end
local function make_global_prefix_xml(ref_type)
local global_prefix_xml = ''
local prefix_type = ref_type
if ref_type == 'pagenote' then
prefix_type = config.pagenote_first_type
end
global_prefix_xml = make_prefix_xml(prefix_type, true)
return global_prefix_xml
end
local function make_references_xml(refs, ref_type, is_prefixed)
local references_xml = ''
for i = 1, #refs do
references_xml = references_xml ..
make_reference_xml(refs[i], ref_type, is_prefixed)
if i < #refs then
if i < #refs - 1 then
references_xml = references_xml .. config.multiple_delimiter
else
references_xml = references_xml .. config.multiple_before_last
end
end
end
return references_xml
end
-- End of references-related code
local function make_raw_content_xml(refs, ref_type, is_prefixed)
local is_enumeration = #refs > 1
local global_prefix = ''
if is_enumeration and is_prefixed
and (ref_type ~= 'pagenote'
or pagenote_factorize_first_prefix_in_enum == 'yes')
then
global_prefix = make_global_prefix_xml(ref_type)
is_prefixed = false
end
local references_raw_xml = make_references_xml(refs, ref_type, is_prefixed)
return global_prefix .. references_raw_xml
end
local function make_raw_content(refs, ref_type, is_prefixed)
local raw_content = ''
if RAW_ATTRIBUTE == 'context' or RAW_ATTRIBUTE == 'latex' then
raw_content = make_raw_content_tex(refs, ref_type, is_prefixed)
else
raw_content = make_raw_content_xml(refs, ref_type, is_prefixed)
end
return raw_content
end
local function format_references(refs, ref_type, is_prefixed)
local raw_content = make_raw_content(refs, ref_type, is_prefixed)
return pandoc.RawInline(RAW_ATTRIBUTE, raw_content)
end
local function format_enum(span)
-- A reference is a Str contained in a span representing a label or a range of labels.
-- A ref is a ref object produced by the function "new_ref" defined above.
if span.classes:includes(TEXT_CROSSREF_CLASS)
and not(is_ref_external(stringify(span.content)))
then
local refs = parse_references_enum(stringify(span.content))
local ref_type = get_ref_type(span)
local is_prefixed = if_prefixed(span)
span.content = format_references(refs, ref_type, is_prefixed)
end
return span
end
return {
{ Meta = configure },
{ Pandoc = define_tex_macros },
{ Meta = tweak_footnote_if_ConTeXt },
{ Note = set_notelabels },
{ Note = map_spans_to_notelabels },
{ Span = labelize_span },
{ Span = make_reference }
{ Span = format_enum }
}