From d8340c7ed36c821c294a35ecc95222c2a0e0df40 Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Tue, 19 Oct 2021 09:18:19 +0200 Subject: [PATCH 1/9] =?UTF-8?q?Mise=20en=20place=20de=20l'architecture=20g?= =?UTF-8?q?=C3=A9n=C3=A9rale=20sans=20code=20sp=C3=A9cifique=20aux=20forma?= =?UTF-8?q?ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++- sample.md | 2 ++ text-crossrefs.lua | 81 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index b4c2037..8ad860b 100644 --- a/README.md +++ b/README.md @@ -67,12 +67,14 @@ If you want to know more about _L'Affaire Lerouge_, see [publication>reception]{ 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{}{}` 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 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[]{}{}` 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. ## Enumerations Rather +Enumerations are only supported for references to page and note numbers. + ## Customization The following metadata fields can be set as strings: @@ -86,6 +88,9 @@ The following metadata fields can be set as strings: * `tcrf-note-prefix`: * “note” prefix; * defaults to `n. `. + * `tcrf-notes-prefix`: + * “notes” prefix; + * defaults to `n. `. * `tcrf-pagenote-separator`: * the separator between the references when `type` is set to `pagenote`; * defaults to `, `. diff --git a/sample.md b/sample.md index 13c7f35..e78a2cf 100644 --- a/sample.md +++ b/sample.md @@ -25,3 +25,5 @@ I want to refer to a note: * 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}. + * What are the notes? → [my-evaluation;format;refer-to-note]{.ref type=note} + * Where are the notes? → [my-evaluation;format]{.ref} diff --git a/text-crossrefs.lua b/text-crossrefs.lua index f4a62f3..ad959b7 100644 --- a/text-crossrefs.lua +++ b/text-crossrefs.lua @@ -1,6 +1,8 @@ -- 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. +-- TODO : créer des commandes latex et context pour les énumérations +-- de notes et de pages sur le modèle de \tcrfpagerangeref -- Begin of initialization @@ -50,6 +52,7 @@ local config = { page_prefix = 'p. ', pages_prefix = 'p. ', note_prefix = 'n. ', + notes_prefix = 'n. ', pagenote_order = 'pagefirst', pagenote_separator = ', ', pagenote_at_end = '', @@ -366,38 +369,53 @@ local function insert_page_target_in_xml(target) end 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 format_prefix(info_type, is_enumeration) + if not is_enumeration then + return config[info_type .. '_prefix'] + elseif RAW_ATTRIBUTE == 'context' or RAW_ATTRIBUTE == 'latex' then + return '' + elseif RAW_ATTRIBUTE == 'opendocument' or RAW_ATTRIBUTE == 'openxml' then + return config[info_type .. 's_prefix'] end end -local function format_pagerange_reference(first, second) +local function format_page_reference(target) + if RAW_ATTRIBUTE == 'context' then + return '\\at[' .. target .. ']' + elseif RAW_ATTRIBUTE == 'latex' then + return '\\pageref{' .. target .. '}' + elseif RAW_ATTRIBUTE == 'opendocument' then + return insert_page_target_in_xml(target) + elseif RAW_ATTRIBUTE == 'openxml' then + return insert_page_target_in_xml(target) + end +end + +local function format_pagerange_reference(first, second, is_prefixed) if RAW_ATTRIBUTE == 'context' or RAW_ATTRIBUTE == 'latex' then - return '\\tcrfpagerangeref{' .. first .. '}{' .. second .. '}' + local bracketed_arg = '' + if is_prefixed then bracketed_arg = 'prefixed' end + -- TODO : implémenter l'argument entre crochets + return '\\tcrfpagerangeref[' .. bracketed_arg .. ']{' .. first .. '}{' .. second .. '}' elseif RAW_ATTRIBUTE == 'opendocument' or RAW_ATTRIBUTE == 'openxml' then - return config.pages_prefix .. insert_page_target_in_xml(first) .. + local to_return = '' + if is_prefixed then to_return = config.pages_prefix end + return to_return .. 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' .. ']' + return '\\in[' .. spans_to_note_labels[target] .. '_note' .. ']' elseif RAW_ATTRIBUTE == 'latex' then - return config.note_prefix .. '\\ref{' .. target .. '}' + return '\\ref{' .. target .. '}' elseif RAW_ATTRIBUTE == 'opendocument' then - return config.note_prefix .. '000' elseif RAW_ATTRIBUTE == 'openxml' then - return config.note_prefix .. + return '' .. ' NOTEREF ' .. target .. '_Note' .. ' \\h ' .. @@ -409,10 +427,12 @@ end local function format_pagenote_reference(target) if config.pagenote_order == 'pagefirst' then - return format_page_reference(target) .. config.pagenote_separator .. + return format_prefix('page', false) .. format_page_reference(target) .. + config.pagenote_separator .. format_prefix('note', false) .. format_note_reference(target) .. config.pagenote_at_end elseif config.pagenote_order == 'notefirst' then - return format_note_reference(target) .. config.pagenote_separator .. + return format_prefix('note', false) .. format_note_reference(target) .. + config.pagenote_separator .. format_prefix('page', false) .. format_page_reference(target) .. config.pagenote_at_end else error('tcrf-pagenote-order must be set either to pagefirst or notefirst.') @@ -421,7 +441,8 @@ 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) + return format_pagerange_reference(target.first, target.second, + not target.is_enumeration) elseif info_type == 'page' then return format_page_reference(target.first) elseif info_type == 'note' then @@ -434,13 +455,31 @@ local function format_reference(target, info_type) end end +local function make_reference_head(info_type, is_enumeration) + if info_type == 'page' or info_type == 'note' then + return format_prefix(info_type, is_enumeration) + else + return '' + end +end + +local function make_reference_body(target, info_type) + +end + +local function make_reference_tail(info_type) + +end + local function make_reference(span) if has_class(span, '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) + local head = make_reference_head(info_type, target.is_enumeration) + local body = make_reference_body(target, info_type) + local tail = make_reference_tail(info_type) + span.content[1] = pandoc.RawInline(RAW_ATTRIBUTE, head .. body .. tail) return span end end From 1c06aceca3bbe91b9c420e1822076f4908d46852 Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Sun, 24 Oct 2021 11:47:24 +0200 Subject: [PATCH 2/9] =?UTF-8?q?Cr=C3=A9ation=20des=20options=20de=20config?= =?UTF-8?q?uration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- text-crossrefs.lua | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ad860b..4ac69b6 100644 --- a/README.md +++ b/README.md @@ -109,10 +109,10 @@ The following metadata fields can be set as strings: * `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`: + * `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`: diff --git a/text-crossrefs.lua b/text-crossrefs.lua index ad959b7..cb708ca 100644 --- a/text-crossrefs.lua +++ b/text-crossrefs.lua @@ -56,6 +56,8 @@ local config = { pagenote_order = 'pagefirst', pagenote_separator = ', ', pagenote_at_end = '', + multiple_delimiter = ', ', + multiple_before_last = ' and ', references_range_separator = '>', range_separator = '-', only_explicit_labels = 'false', From 0bb74650d259304f9fc1179530bc41dd85d8090b Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Sun, 24 Oct 2021 18:45:37 +0200 Subject: [PATCH 3/9] =?UTF-8?q?Enum=C3=A9ration=20fonctionnelle=20pour=20o?= =?UTF-8?q?pendocument=20et=20openxml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- text-crossrefs.lua | 60 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 4ac69b6..c06f5ea 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ The following metadata fields can be set as strings: * the string inserted between to 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; + * the character used to separate the elements of an enumeration in a reference span; can be any character not authorized in an identifier other than space or tab; * defaults to `;`. * `tcrf-multiple-delimiter`: * the string inserted between two elements (but the two last ones) in an enumeration; diff --git a/text-crossrefs.lua b/text-crossrefs.lua index cb708ca..167cdfd 100644 --- a/text-crossrefs.lua +++ b/text-crossrefs.lua @@ -60,6 +60,7 @@ local config = { multiple_before_last = ' and ', references_range_separator = '>', range_separator = '-', + references_enum_separator = ';', only_explicit_labels = 'false', default_info_type = 'page', filelabel_ref_separator = '::' @@ -337,12 +338,21 @@ local function get_second_reference(rawref) if is_reference_valid(ref) then return ref end end +local function is_ref_enumeration(raw_reference) + if string.match(raw_reference, '%' .. config.references_enum_separator) then + return true + else + return false + 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) + analyzed_reference.is_enumeration = is_ref_enumeration(raw_reference) if analyzed_reference.is_external then analyzed_reference.filelabel = get_extfilelabel(raw_reference) end @@ -442,7 +452,7 @@ local function format_pagenote_reference(target) end local function format_reference(target, info_type) - if info_type == 'page' and target.is_range then + if info_type == 'page' and target.is_range then return format_pagerange_reference(target.first, target.second, not target.is_enumeration) elseif info_type == 'page' then @@ -457,20 +467,53 @@ local function format_reference(target, info_type) end end -local function make_reference_head(info_type, is_enumeration) - if info_type == 'page' or info_type == 'note' then +local function make_reference_head(info_type, is_enumeration, is_range) + if (info_type == 'page' or info_type == 'note') and not is_range then return format_prefix(info_type, is_enumeration) else return '' end end -local function make_reference_body(target, info_type) - +local function format_all_items_in_enumeration(enum, info_type) + local reference_body = '' + local enumerated_ref_spans = {} + for ref in string.gmatch(enum, + '[^%' .. config.references_enum_separator .. ']+') do + ref_span = pandoc.Span(ref, {['type'] = info_type}) + table.insert(enumerated_ref_spans, ref_span) + end + for i = 1, #enumerated_ref_spans do + target_in_enum = analyze_reference_span(enumerated_ref_spans[i]) + reference_body = reference_body .. format_reference(target_in_enum, info_type) + if i < #enumerated_ref_spans then + if i < #enumerated_ref_spans-1 then + reference_body = reference_body .. config.multiple_delimiter + else + reference_body = reference_body .. config.multiple_before_last + end + end + end + return reference_body end -local function make_reference_tail(info_type) +local function format_enumeration(target, info_type) + if RAW_ATTRIBUTE == 'context' or RAW_ATTRIBUTE == 'latex' then + -- TODO + return format_enumeration_smart(target.first, info_type) + elseif RAW_ATTRIBUTE == 'opendocument' or RAW_ATTRIBUTE == 'openxml' then + return format_all_items_in_enumeration(target.first, info_type) + end +end +local function make_reference_body(target, info_type) + local reference_body + if target.is_enumeration then + reference_body = format_enumeration(target, info_type) + else + reference_body = format_reference(target, info_type) + end + return reference_body end local function make_reference(span) @@ -478,10 +521,9 @@ local function make_reference(span) local target = analyze_reference_span(span) if not target.is_external then local info_type = span.attributes.type or config.default_info_type - local head = make_reference_head(info_type, target.is_enumeration) + local head = make_reference_head(info_type, target.is_enumeration, target.is_range) local body = make_reference_body(target, info_type) - local tail = make_reference_tail(info_type) - span.content[1] = pandoc.RawInline(RAW_ATTRIBUTE, head .. body .. tail) + span.content[1] = pandoc.RawInline(RAW_ATTRIBUTE, head .. body) return span end end From 666c612a02f495d95eed0d30d2bc061b48bd13ef Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Wed, 19 Oct 2022 20:35:31 +0200 Subject: [PATCH 4/9] Improvement of the documentation and update of the sample --- README.md | 155 ++++++++++++++++++++++++++++++++++++++++-------------- sample.md | 24 +++++---- 2 files changed, 129 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index c06f5ea..eb553f8 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,29 @@ 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 suffixed with `_note`. ## Usage @@ -34,97 +54,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 user’s 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[]{}{}` 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 are only supported for references to page and note numbers. +### 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 `n. `. + * 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 character used to separate the elements of an enumeration in a reference span; can be any character not authorized in an identifier other than space or tab; - * defaults to `;`. + * 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-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 @@ -152,6 +227,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. diff --git a/sample.md b/sample.md index e78a2cf..781f7fb 100644 --- a/sample.md +++ b/sample.md @@ -3,6 +3,8 @@ tcrf-pagenote-separator: '\ (' tcrf-pagenote-at-end: ')' --- +(About the notes, see [toc-notes-begin>toc-notes-end]{.tcrf}.) + Émile Gaboriau published [_L'Affaire Lerouge_ in 1866]{#publication}.[^1] @@ -10,20 +12,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}. - * What are the notes? → [my-evaluation;format;refer-to-note]{.ref type=note} - * Where are the notes? → [my-evaluation;format]{.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} From 0d30b8cc94936f40750bfd04ffc91f22fca3944a Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Wed, 19 Oct 2022 20:36:49 +0200 Subject: [PATCH 5/9] Code refactoring and proper handling of labels on footnotes in ConTeXt --- text-crossrefs.lua | 647 +++++++++++++++++++++++---------------------- 1 file changed, 329 insertions(+), 318 deletions(-) diff --git a/text-crossrefs.lua b/text-crossrefs.lua index 167cdfd..981d129 100644 --- a/text-crossrefs.lua +++ b/text-crossrefs.lua @@ -1,16 +1,11 @@ --- 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. --- TODO : créer des commandes latex et context pour les énumérations --- de notes et de pages sur le modèle de \tcrfpagerangeref +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 RAW_ATTRIBUTE -local IS_LABEL_SET_BY_PANDOC -local LABEL_TEMPLATE -local NOTELABEL_TEMPLATE + +-- Configuration local function define_raw_attribute() if FORMAT == 'native' then @@ -41,38 +36,43 @@ 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. ', - notes_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 = '-', - references_enum_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 ' +} + +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]] = '' .. config[to_format[i]] .. '' @@ -83,11 +83,13 @@ 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 + config[item] = metamap[metakey][1].text 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 @@ -98,65 +100,15 @@ 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 @@ -174,7 +126,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 @@ -187,7 +139,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 @@ -195,12 +148,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) @@ -211,26 +165,12 @@ local function labelize_span(span) end end -local function has_class(elem, class) - if elem.classes then - for i = 1, #elem.classes do - if elem.classes[i] == class then - return true - end - end - return false - else - error('function has_class used on an element of type ' .. - elem.t .. ' that cannot have classes.') - end -end - local current_note_labels = {} local collect_note_labels = { Span = function(span) - if span.identifier ~= '' and - (config.only_explicit_labels == 'false' or has_class(span, 'label')) + if span.identifier ~= '' + and (config.only_explicit_labels == 'false' or span.classes:includes('label')) then table.insert(current_note_labels, span.identifier) end @@ -240,302 +180,373 @@ local collect_note_labels = { local function make_notelabel(pos) local raw_code = '' if pos == 'begin' then - if RAW_ATTRIBUTE == 'openxml' then - raw_code = string.gsub( - '', - '{{label}}', current_note_labels[#current_note_labels]) - end + raw_code = string.gsub( + '', + '{{label}}', current_note_labels[1]) elseif pos == 'end' then - if RAW_ATTRIBUTE == 'context' then - local label = current_note_labels[1] .. '_note' - raw_code = '{' .. label .. '}' - elseif RAW_ATTRIBUTE == 'openxml' then - raw_code = string.gsub('', - '{{label}}', current_note_labels[1]) - end + raw_code = string.gsub('', + '{{label}}', current_note_labels[1]) end return pandoc.RawInline(RAW_ATTRIBUTE, raw_code) end local function labelize_note(note) - local label_begin = make_notelabel('begin') - local label_end = make_notelabel('end') - return { label_begin, note, label_end } + local labelized_note + if RAW_ATTRIBUTE == 'openxml' then + local label_begin = make_notelabel('begin') + local label_end = make_notelabel('end') + labelized_note = { label_begin, note, label_end } + elseif RAW_ATTRIBUTE == 'context' then + labelized_note = pandoc.utils.blocks_to_inlines(note.content) + labelized_note:insert(1, pandoc.RawInline('context', '\\footnote[note:' .. current_note_labels[1] .. ']{')) + labelized_note:insert(pandoc.RawInline('context', '}')) + end + return labelized_note +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 is_ref_enumeration(raw_reference) - if string.match(raw_reference, '%' .. config.references_enum_separator) then - return true - else - return false - 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) - analyzed_reference.is_enumeration = is_ref_enumeration(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_attr_value, 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 + +--- TODO : début de section à revoir + +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 '000' elseif RAW_ATTRIBUTE == 'openxml' then - return '' .. + xml_page_ref = xml_page_ref .. + '' .. ' PAGEREF ' .. target .. ' \\h ' .. '' .. '000' .. '' end + return xml_page_ref end -local function format_prefix(info_type, is_enumeration) - if not is_enumeration then - return config[info_type .. '_prefix'] - elseif RAW_ATTRIBUTE == 'context' or RAW_ATTRIBUTE == 'latex' then - return '' - elseif RAW_ATTRIBUTE == 'opendocument' or RAW_ATTRIBUTE == 'openxml' then - return config[info_type .. 's_prefix'] +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_page_reference(target) - if RAW_ATTRIBUTE == 'context' then - return '\\at[' .. target .. ']' - elseif RAW_ATTRIBUTE == 'latex' then - return '\\pageref{' .. target .. '}' - elseif RAW_ATTRIBUTE == 'opendocument' then - return insert_page_target_in_xml(target) - elseif RAW_ATTRIBUTE == 'openxml' then - return insert_page_target_in_xml(target) - end -end - -local function format_pagerange_reference(first, second, is_prefixed) - if RAW_ATTRIBUTE == 'context' or RAW_ATTRIBUTE == 'latex' then - local bracketed_arg = '' - if is_prefixed then bracketed_arg = 'prefixed' end - -- TODO : implémenter l'argument entre crochets - return '\\tcrfpagerangeref[' .. bracketed_arg .. ']{' .. first .. '}{' .. second .. '}' - elseif RAW_ATTRIBUTE == 'opendocument' or RAW_ATTRIBUTE == 'openxml' then - local to_return = '' - if is_prefixed then to_return = config.pages_prefix end - return to_return .. 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 '\\in[' .. spans_to_note_labels[target] .. '_note' .. ']' - elseif RAW_ATTRIBUTE == 'latex' then - return '\\ref{' .. target .. '}' - elseif RAW_ATTRIBUTE == 'opendocument' then - return '000' + (spans_to_note_labels[target] or '') .. '">000' elseif RAW_ATTRIBUTE == 'openxml' then - return + note_ref_xml = note_ref_xml .. '' .. ' NOTEREF ' .. - target .. '_Note' .. ' \\h ' .. + (spans_to_note_labels[target] or '') .. '_Note' .. ' \\h ' .. '' .. '000' .. '' end + return note_ref_xml end -local function format_pagenote_reference(target) - if config.pagenote_order == 'pagefirst' then - return format_prefix('page', false) .. format_page_reference(target) .. - config.pagenote_separator .. format_prefix('note', false) .. - format_note_reference(target) .. config.pagenote_at_end - elseif config.pagenote_order == 'notefirst' then - return format_prefix('note', false) .. format_note_reference(target) .. - config.pagenote_separator .. format_prefix('page', false) .. - format_page_reference(target) .. config.pagenote_at_end +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 + 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('tcrf-pagenote-order must be set either to pagefirst or notefirst.') + error('“tcrf-pagenote-first-type” must be set either to “page” or “note”.') end + return pagenote_ref_xml 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, - not target.is_enumeration) - 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) - else - error('Invalid value for attribute type in span with class ref: ' .. - info_type) +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_reference_head(info_type, is_enumeration, is_range) - if (info_type == 'page' or info_type == 'note') and not is_range then - return format_prefix(info_type, is_enumeration) - else - return '' +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 format_all_items_in_enumeration(enum, info_type) - local reference_body = '' - local enumerated_ref_spans = {} - for ref in string.gmatch(enum, - '[^%' .. config.references_enum_separator .. ']+') do - ref_span = pandoc.Span(ref, {['type'] = info_type}) - table.insert(enumerated_ref_spans, ref_span) - end - for i = 1, #enumerated_ref_spans do - target_in_enum = analyze_reference_span(enumerated_ref_spans[i]) - reference_body = reference_body .. format_reference(target_in_enum, info_type) - if i < #enumerated_ref_spans then - if i < #enumerated_ref_spans-1 then - reference_body = reference_body .. config.multiple_delimiter +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 - reference_body = reference_body .. config.multiple_before_last + references_xml = references_xml .. config.multiple_before_last end end end - return reference_body + return references_xml end -local function format_enumeration(target, info_type) +--- Fin de section à revoir + +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 - -- TODO - return format_enumeration_smart(target.first, info_type) - elseif RAW_ATTRIBUTE == 'opendocument' or RAW_ATTRIBUTE == 'openxml' then - return format_all_items_in_enumeration(target.first, info_type) - end -end - -local function make_reference_body(target, info_type) - local reference_body - if target.is_enumeration then - reference_body = format_enumeration(target, info_type) + raw_content = make_raw_content_tex(refs, ref_type, is_prefixed) else - reference_body = format_reference(target, info_type) + raw_content = make_raw_content_xml(refs, ref_type, is_prefixed) end - return reference_body + return raw_content end -local function make_reference(span) - if has_class(span, '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 head = make_reference_head(info_type, target.is_enumeration, target.is_range) - local body = make_reference_body(target, info_type) - span.content[1] = pandoc.RawInline(RAW_ATTRIBUTE, head .. body) - return span - end - 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 --- End of references-related code +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 }, { Note = set_notelabels }, { Note = map_spans_to_notelabels }, { Span = labelize_span }, - { Span = make_reference } + { Span = format_enum } } From e9cfad51cda2d7ee0eb11de34d6f7a0aa0f417e5 Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Sat, 29 Oct 2022 18:56:13 +0200 Subject: [PATCH 6/9] ConTeXt: Revert to the strategy of inverting the label and the footnote content Users will be able to use block content in labelized footnotes again. --- README.md | 20 ++++++++++++- text-crossrefs.lua | 72 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index eb553f8..c406a8b 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,25 @@ All references are wrapped in a macro named `\tcrfenum`. It has two optional arg 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 suffixed with `_note`. + * 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 diff --git a/text-crossrefs.lua b/text-crossrefs.lua index 981d129..268b0b5 100644 --- a/text-crossrefs.lua +++ b/text-crossrefs.lua @@ -5,6 +5,46 @@ local REF_TYPE_ATTR = 'reftype' local PREFIXED_ATTR = 'prefixref' local RAW_ATTRIBUTE +-- 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() @@ -178,30 +218,31 @@ 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 - raw_code = string.gsub( - '', - '{{label}}', current_note_labels[1]) + if RAW_ATTRIBUTE == 'openxml' then + raw_code = string.gsub( + '', + '{{label}}', current_note_labels[1]) + end elseif pos == 'end' then - raw_code = string.gsub('', - '{{label}}', current_note_labels[1]) + if RAW_ATTRIBUTE == 'openxml' then + raw_code = string.gsub('', + '{{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 - if RAW_ATTRIBUTE == 'openxml' then - local label_begin = make_notelabel('begin') - local label_end = make_notelabel('end') - labelized_note = { label_begin, note, label_end } - elseif RAW_ATTRIBUTE == 'context' then - labelized_note = pandoc.utils.blocks_to_inlines(note.content) - labelized_note:insert(1, pandoc.RawInline('context', '\\footnote[note:' .. current_note_labels[1] .. ']{')) - labelized_note:insert(pandoc.RawInline('context', '}')) - end - return 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) @@ -545,6 +586,7 @@ end return { { Meta = configure }, + { Meta = tweak_footnote_if_ConTeXt }, { Note = set_notelabels }, { Note = map_spans_to_notelabels }, { Span = labelize_span }, From 80533218166fd4022864abdb019d768f3cc77de7 Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Sat, 29 Oct 2022 19:47:05 +0200 Subject: [PATCH 7/9] Cleaned up the repo and updated the test suite --- Makefile | 23 ++ sample.md | 2 + test.md | 16 -- test/sample-context.native | 386 +++++++++++++++++++++++++++++++ test/sample-latex.native | 386 +++++++++++++++++++++++++++++++ test/sample-opendocument.native | 397 ++++++++++++++++++++++++++++++++ test/test-functions.lua | 36 +++ 7 files changed, 1230 insertions(+), 16 deletions(-) create mode 100644 Makefile delete mode 100644 test.md create mode 100644 test/sample-context.native create mode 100644 test/sample-latex.native create mode 100644 test/sample-opendocument.native create mode 100644 test/test-functions.lua diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d9353c6 --- /dev/null +++ b/Makefile @@ -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 + diff --git a/sample.md b/sample.md index 781f7fb..044150b 100644 --- a/sample.md +++ b/sample.md @@ -1,6 +1,8 @@ --- tcrf-pagenote-separator: '\ (' tcrf-pagenote-at-end: ')' +header-includes: | + \input{tex-aux/tcrfenum} --- (About the notes, see [toc-notes-begin>toc-notes-end]{.tcrf}.) diff --git a/test.md b/test.md deleted file mode 100644 index 8947f69..0000000 --- a/test.md +++ /dev/null @@ -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} diff --git a/test/sample-context.native b/test/sample-context.native new file mode 100644 index 0000000..68cb961 --- /dev/null +++ b/test/sample-context.native @@ -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" , [] , [] ) [] ] +] diff --git a/test/sample-latex.native b/test/sample-latex.native new file mode 100644 index 0000000..c061200 --- /dev/null +++ b/test/sample-latex.native @@ -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" , [] , [] ) [] + ] +] diff --git a/test/sample-opendocument.native b/test/sample-opendocument.native new file mode 100644 index 0000000..d07ef34 --- /dev/null +++ b/test/sample-opendocument.native @@ -0,0 +1,397 @@ +[ Para + [ Str "(About" + , Space + , Str "the" + , Space + , Str "notes," + , Space + , Str "see" + , Space + , Span + ( "" , [ "tcrf" ] , [] ) + [ RawInline + (Format "opendocument") + "pp.\160000\8211000" + ] + , 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.\160000" + ] + , 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.\160000\160(n.\160000)" + ] + , 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.\160000\8211000" + ] + , 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.\160000" + ] + , 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.\160000" + ] + , 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.\160000" + ] + , 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.\160000" + ] + , 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.\160000, 000 and 000" + ] + ] + ] + , [ Plain + [ Str "Where" + , Space + , Str "are" + , Space + , Str "the" + , Space + , Str "notes?" + , Space + , Str "\8594" + , Space + , Span + ( "" , [ "tcrf" ] , [] ) + [ RawInline + (Format "opendocument") + "pp.\160000 and 000" + ] + ] + ] + ] +, Para [ Str "" , Span ( "toc-notes-end" , [] , [] ) [] ] +] diff --git a/test/test-functions.lua b/test/test-functions.lua new file mode 100644 index 0000000..d9d5c9e --- /dev/null +++ b/test/test-functions.lua @@ -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}}') From ef8accbc81cca2e0c256ba044c2358a91bc5b3c7 Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Sat, 5 Nov 2022 18:40:44 +0100 Subject: [PATCH 8/9] Removed obsolete TODO --- text-crossrefs.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/text-crossrefs.lua b/text-crossrefs.lua index 268b0b5..8f8b73b 100644 --- a/text-crossrefs.lua +++ b/text-crossrefs.lua @@ -414,8 +414,6 @@ local function make_raw_content_tex(refs, ref_type, is_prefixed) return texified_references end ---- TODO : début de section à revoir - local function make_prefix_xml(ref_type, is_plural) local prefix = '' if is_plural then @@ -539,8 +537,6 @@ local function make_references_xml(refs, ref_type, is_prefixed) return references_xml end ---- Fin de section à revoir - local function make_raw_content_xml(refs, ref_type, is_prefixed) local is_enumeration = #refs > 1 local global_prefix = '' From bc209420fe6e2b80654de7dfb931bdc1e1165e74 Mon Sep 17 00:00:00 2001 From: Bastien Dumont Date: Sat, 5 Nov 2022 19:35:43 +0100 Subject: [PATCH 9/9] =?UTF-8?q?Impl=C3=A9mentation=20du=20support=20pour?= =?UTF-8?q?=20des=20types=20arbitraires=20pour=20LaTeX=20et=20ConTeXt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- text-crossrefs.lua | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/text-crossrefs.lua b/text-crossrefs.lua index 8f8b73b..d17a15d 100644 --- a/text-crossrefs.lua +++ b/text-crossrefs.lua @@ -3,6 +3,7 @@ local stringify = pandoc.utils.stringify local TEXT_CROSSREF_CLASS = 'tcrf' local REF_TYPE_ATTR = 'reftype' local PREFIXED_ATTR = 'prefixref' +local IS_CONFIG_ARRAY = { ['additional_types'] = true } local RAW_ATTRIBUTE -- ConTeXt-specific tweak in order to add the label to the footnote @@ -94,7 +95,8 @@ local config = { default_reftype = 'page', default_prefixref = 'yes', filelabel_ref_separator = '::', - range_delim_tcrfenum = ' to ' + range_delim_tcrfenum = ' to ', + additional_types = {} } local accepted_types = { @@ -122,8 +124,16 @@ 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].text + 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 @@ -136,6 +146,11 @@ local function configure(metadata) 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 @@ -342,7 +357,7 @@ 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_attr_value, span.content) + error_on_attr(REF_TYPE_ATTR, ref_type, span.content) end return ref_type end