├── img
└── fig-1.png
├── expected
├── demo.docx
├── refnos.docx
├── table.md
├── table.tex
├── demo.md
├── demo.tex
├── refnos.md
└── refnos.tex
├── samples
├── table.md
├── demo.md
└── refnos.md
├── test_output.sh
├── LICENSE
├── README.md
└── refnos.lua
/img/fig-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tstenner/luarefnos/HEAD/img/fig-1.png
--------------------------------------------------------------------------------
/expected/demo.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tstenner/luarefnos/HEAD/expected/demo.docx
--------------------------------------------------------------------------------
/expected/refnos.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tstenner/luarefnos/HEAD/expected/refnos.docx
--------------------------------------------------------------------------------
/expected/table.md:
--------------------------------------------------------------------------------
1 | Revision Date Change Description
2 | ---------- ------------ --------------------
3 | 0.5 2022-07-05 Initial Draft
4 |
--------------------------------------------------------------------------------
/samples/table.md:
--------------------------------------------------------------------------------
1 | Revision Date Change Description
2 | ---------- ------------ --------------------
3 | 0.5 2022-07-05 Initial Draft
4 |
--------------------------------------------------------------------------------
/expected/table.tex:
--------------------------------------------------------------------------------
1 | \begin{longtable}[]{@{}ccl@{}}
2 | \toprule\noalign{}
3 | Revision & Date & Change Description \\
4 | \midrule\noalign{}
5 | \endhead
6 | \bottomrule\noalign{}
7 | \endlastfoot
8 | 0.5 & 2022-07-05 & Initial Draft \\
9 | \end{longtable}
10 |
--------------------------------------------------------------------------------
/test_output.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 |
3 | set -e
4 |
5 | for f in samples/*; do
6 | for outfmt in md tex; do
7 | pandoc -L refnos.lua $f -o expected/$(basename ${f%%.*}).$outfmt
8 | done
9 | done
10 | discrepancies="$(git diff -- expected)"
11 | echo $discrepancies
12 | if [[ "$discrepancies" != "" ]]; then
13 | echo "Expected output doesn't match actual output!"
14 | echo $discrepandies
15 | exit 1
16 | fi
17 |
--------------------------------------------------------------------------------
/samples/demo.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Pandoc-fignos Demo
3 | lang: de
4 | luarefnos:
5 | strs:
6 | de:
7 | tab: {ref: 'Tabelle', plural: 'Tabellen'}
8 | tbl: {ref: 'Tableu', plural: 'Tableus'}
9 | fig: {ref: 'Plot', abbrev: 'Plot'}
10 | ...
11 |
12 | {#fig:1 width=1in}
13 |
14 | {#fig:2 width=1in}
15 |
16 | Wir verweisen auf @fig:1 und [@fig:1; die @fig:2 mit Postfix; fehlenden @fig:3].
17 |
18 | Foo Bar
19 | --- ---
20 | 1 2
21 |
22 | Table: Caption {#tbl:foobar}
23 |
24 | Note that @tbl:foobar has a special namespace name.
25 |
--------------------------------------------------------------------------------
/expected/demo.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Plot 1: Plot eins
4 |
5 |
6 |
7 |
8 | Plot 2: Plot zwei
9 |
10 |
11 | Wir verweisen auf Plot [1](#fig:1) und Plots [1](#fig:1), die
12 | [2](#fig:2) mit Postfix & fehlenden **fig:3?**.
13 |
14 | Foo Bar
15 | ----- -----
16 | 1 2
17 |
18 | : [Tableu 1: ]{#tbl:foobar}Caption
19 |
20 | Note that Tableu [1](#tbl:foobar) has a special namespace name.
21 |
--------------------------------------------------------------------------------
/expected/demo.tex:
--------------------------------------------------------------------------------
1 | \begin{figure}
2 | \centering
3 | \includegraphics[width=1in,height=\textheight]{img/fig-1.png}
4 | \caption{Plot 1: Plot eins}\label{fig:1}
5 | \end{figure}
6 |
7 | \begin{figure}
8 | \centering
9 | \includegraphics[width=1in,height=\textheight]{img/fig-1.png}
10 | \caption{Plot 2: Plot zwei}\label{fig:2}
11 | \end{figure}
12 |
13 | Wir verweisen auf Plot \ref{fig:1} und Plots \ref{fig:1}, die
14 | \ref{fig:2} mit Postfix \& fehlenden \ref{fig:3}.
15 |
16 | \begin{longtable}[]{@{}ll@{}}
17 | \caption{Caption}\label{tbl:foobar}\tabularnewline
18 | \toprule\noalign{}
19 | Foo & Bar \\
20 | \midrule\noalign{}
21 | \endfirsthead
22 | \toprule\noalign{}
23 | Foo & Bar \\
24 | \midrule\noalign{}
25 | \endhead
26 | \bottomrule\noalign{}
27 | \endlastfoot
28 | 1 & 2 \\
29 | \end{longtable}
30 |
31 | Note that Tableu \ref{tbl:foobar} has a special namespace name.
32 |
--------------------------------------------------------------------------------
/samples/refnos.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Pandoc-fignos Demo
3 | test: bar
4 | ...
5 |
6 | # Chapter 1
7 |
8 | In-text references to @fig:1 [B] and @tab:foobar results in
9 | **Figure 1B and Table 1**.
10 |
11 | Multi-reference to [@fig:1 (A); the cool part of @fig:1; @fig:three]
12 | and [@tab:foobar (very cool); *especially* @tab:foobar] is rendered as
13 | **Figures 1 (A), the cool part of 1 & 2 and Tables 1 (verycool) & *especially* 1**
14 |
15 | {#fig:1 width=1in}
16 |
17 | {#fig: width=1in}
18 |
19 | {#fig:three width=1in}
20 |
21 | Plot [-@fig:three] is given above, without adding the "Figure" prefix.
22 |
23 | As seen in @tab:foobar, commas are handled properly.
24 |
25 | ## Equations {#equationchapter}
26 |
27 | Equations, such as [@eq:pythagoras; @eq:einstein (however short it is)], have to be put into a span with an id:
28 |
29 | [$$a^2 + b^2 = c^2$$]{#eq:pythagoras}
30 |
31 | They can also be inline: [$$e=mc^2$$]{#eq:einstein}.
32 |
33 | Most people prefer @eq:pythagoras, but know [@eq:einstein].
34 |
35 | ## Tables
36 |
37 | Foo Bar
38 | --- ---
39 | 1 2
40 |
41 | Table: Caption {#tab:foobar width=1em attr2=foo}
42 |
43 | # Another chapter
44 |
45 | References to @sec:equationchapter and the unnamed @sec:another-chapter
46 |
47 | Text at end.
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 2-Clause License
2 |
3 | Copyright (c) 2021, Tristan Stenner
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 |
--------------------------------------------------------------------------------
/expected/refnos.md:
--------------------------------------------------------------------------------
1 | # Chapter 1
2 |
3 | In-text references to Figure [1](#fig:1)B and Table [1](#tab:foobar)
4 | results in **Figure 1B and Table 1**.
5 |
6 | Multi-reference to Figures [1](#fig:1) (A), the cool part of
7 | [1](#fig:1) & [3](#fig:three) and Tables [1](#tab:foobar) (very
8 | cool) & *especially* [1](#tab:foobar) is rendered as **Figures 1 (A),
9 | the cool part of 1 & 2 and Tables 1 (verycool) & *especially* 1**
10 |
11 |
12 |
13 | Figure 1: The number one.
14 |
15 |
16 |
17 |
19 | Figure 2: The unlabeled number two.
20 |
21 |
22 |
23 |
24 | Figure 3: The number three.
25 |
26 |
27 | Plot [3](#fig:three) is given above, without adding the "Figure" prefix.
28 |
29 | As seen in Table [1](#tab:foobar), commas are handled properly.
30 |
31 | ## Equations {#equationchapter}
32 |
33 | Equations, such as Equations [1](#eq:pythagoras) & [2](#eq:einstein)
34 | (however short it is), have to be put into a span with an id:
35 |
36 | [$$a^2 + b^2 = c^2$$ (1)]{#eq:pythagoras}
37 |
38 | They can also be inline: [$$e=mc^2$$ (2)]{#eq:einstein}.
39 |
40 | Most people prefer Equation [1](#eq:pythagoras), but know
41 | Equation [2](#eq:einstein).
42 |
43 | ## Tables
44 |
45 | Foo Bar
46 | ----- -----
47 | 1 2
48 |
49 | : [Table 1: ]{#tab:foobar}Caption
50 |
51 | # Another chapter
52 |
53 | References to Section [1.1](#equationchapter) and the unnamed
54 | Section [2](#another-chapter)
55 |
56 | Text at end.
57 |
--------------------------------------------------------------------------------
/expected/refnos.tex:
--------------------------------------------------------------------------------
1 | \section{Chapter 1}\label{chapter-1}
2 |
3 | In-text references to Figure \ref{fig:1}B and Table \ref{tab:foobar}
4 | results in \textbf{Figure 1B and Table 1}.
5 |
6 | Multi-reference to Figures \ref{fig:1} (A), the cool part of
7 | \ref{fig:1} \& \ref{fig:three} and Tables \ref{tab:foobar} (very
8 | cool) \& \emph{especially} \ref{tab:foobar} is rendered as
9 | \textbf{Figures 1 (A), the cool part of 1 \& 2 and Tables 1 (verycool)
10 | \& \emph{especially} 1}
11 |
12 | \begin{figure}
13 | \centering
14 | \includegraphics[width=1in,height=\textheight]{img/fig-1.png}
15 | \caption{Figure 1: The number one.}\label{fig:1}
16 | \end{figure}
17 |
18 | \begin{figure}
19 | \centering
20 | \includegraphics[width=1in,height=\textheight]{img/fig-1.png}
21 | \caption{Figure 2: The unlabeled number two.}\label{fig:}
22 | \end{figure}
23 |
24 | \begin{figure}
25 | \centering
26 | \includegraphics[width=1in,height=\textheight]{img/fig-1.png}
27 | \caption{Figure 3: The number three.}\label{fig:three}
28 | \end{figure}
29 |
30 | Plot \ref{fig:three} is given above, without adding the ``Figure''
31 | prefix.
32 |
33 | As seen in Table \ref{tab:foobar}, commas are handled properly.
34 |
35 | \subsection{Equations}\label{equationchapter}
36 |
37 | Equations, such as Equations \ref{eq:pythagoras} \& \ref{eq:einstein}
38 | (however short it is), have to be put into a span with an id:
39 |
40 | \phantomsection\label{eq:pythagoras}{\[a^2 + b^2 = c^2\]}
41 |
42 | They can also be inline: \phantomsection\label{eq:einstein}{\[e=mc^2\]}.
43 |
44 | Most people prefer Equation \ref{eq:pythagoras}, but know
45 | Equation \ref{eq:einstein}.
46 |
47 | \subsection{Tables}\label{tables}
48 |
49 | \begin{longtable}[]{@{}ll@{}}
50 | \caption{Caption}\label{tab:foobar}\tabularnewline
51 | \toprule\noalign{}
52 | Foo & Bar \\
53 | \midrule\noalign{}
54 | \endfirsthead
55 | \toprule\noalign{}
56 | Foo & Bar \\
57 | \midrule\noalign{}
58 | \endhead
59 | \bottomrule\noalign{}
60 | \endlastfoot
61 | 1 & 2 \\
62 | \end{longtable}
63 |
64 | \section{Another chapter}\label{another-chapter}
65 |
66 | References to Section \ref{equationchapter} and the unnamed
67 | Section \ref{another-chapter}
68 |
69 | Text at end.
70 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # luarefnos
2 |
3 | Pure lua implementation of table, figure, section and equation
4 | cross-references.
5 |
6 | ## Sample usage
7 |
8 | ``` markdown
9 | # Chapter 1
10 |
11 | In-text references to @fig:1 [B] and @tab:foobar.
12 |
13 | Multi-reference to [@fig:1 (A); the cool part of @fig:1; @fig:three]
14 | and [@tab:foobar (very cool); *especially* @tab:foobar].
15 |
16 | {#fig:1 width=1in}
17 |
18 | {#fig: width=1in}
19 |
20 | {#fig:three width=1in}
21 |
22 | Plot [-@fig:three] is given above, without adding the "Figure" prefix.
23 |
24 | As seen in @tab:foobar, commas are handled properly.
25 |
26 | ## Equations {#equationchapter}
27 |
28 | Equations, such as @eq:pythagoras, have to be put into a span with an id:
29 |
30 | [$$a^2 + b^2 = c^2$$]{#eq:pythagoras}
31 |
32 | ## Tables
33 |
34 | Foo Bar
35 | --- ---
36 | 1 2
37 |
38 | Table: With caption string {#tab:foobar border=1 attr2=foo}
39 | ```
40 |
41 | ## Sample output
42 |
43 | ### Chapter 1
44 |
45 | In-text references to Figure [1](#fig:1)B and Table [1](#tab:foobar).
46 |
47 | Multi-reference to Figures [1](#fig:1) (A), the cool part of [1](#fig:1)
48 | & [3](#fig:three) and Tables [1](#tab:foobar) (very cool) & *especially*
49 | [1](#tab:foobar).
50 |
51 |
52 |
Figure 1: The number one.
53 |
54 |
55 |
56 |
Figure 2: The unlabeled number two.
57 |
58 |
59 |
60 |
Figure 3: The number three.
61 |
62 |
63 | Plot [3](#fig:three) is given above, without adding the “Figure” prefix.
64 |
65 | As seen in Table [1](#tab:foobar), commas are handled properly.
66 |
67 | #### Equations
68 |
69 | Equations, such as Equation [1](#eq:pythagoras), have to be put into a
70 | span with an id:
71 |
72 |
73 | *a*2 + *b*2 = *c*2
74 |
75 |
76 | #### Tables
77 |
78 | | Foo | Bar |
79 | |:----|:----|
80 | | 1 | 2 |
81 |
82 | Table 1:With caption string
83 |
84 | # What about pandoc-xnos
85 |
86 | | Feature | luarefnos | pandoc-xnos |
87 | |:-----------------------|:---------:|:-------------------:|
88 | | Figure references | ✔ | ✔ |
89 | | Subfigures | (✗) | ✔ |
90 | | Table references | ✔ | ✔ |
91 | | Equation references | ✔ | ✔ |
92 | | Section references | (✔) | ✔ |
93 | | Clever references | ✗ | ✔ |
94 | | Customization | ✗ | ✔ |
95 | | Maturity | 👶 | ✔ |
96 | | Corner cases | Many | Probably none |
97 | | Installation | One file | Python + 3 packages |
98 | | Native docx references | ✔ | ✗ |
99 |
100 | # Usage
101 |
102 | Before anything can be referenced, it has to have an ID.
103 |
104 | ## Figures
105 |
106 | The native attribute syntax is reused:
107 |
108 | ``` markdown
109 | {#fig:example}
110 | ```
111 |
112 | ## Tables
113 |
114 | A (not yet) native attribute block is at the end of the caption is
115 | applied to the table:
116 |
117 | ``` markdown
118 | Col A Col B
119 | ----- -----
120 | 1 2
121 |
122 | : A table caption {#tab:example}
123 | ```
124 |
125 | ## Equations
126 |
127 | Display math in a span with an ID is counted:
128 |
129 | ``` markdown
130 | [$$a^2 + b^2 = c^2$$]{#eq:pythagoras}
131 | ```
132 |
133 | ## Sections
134 |
135 | Section IDs are re-used, the `sec:` is added automatically!
136 |
137 | ``` markdown
138 | # Section A
139 |
140 | The section below has the number @sec:someotherid
141 |
142 | # Section B {#someotherid}
143 | ```
144 |
145 | ## Referencing
146 |
147 | Citations with a namespace (e.g. `sec:`, `fig:` etc.) are replaced with
148 | the reference:
149 |
150 | ``` markdown
151 | We reference @tab:example and @fig:example.
152 | ```
153 |
--------------------------------------------------------------------------------
/refnos.lua:
--------------------------------------------------------------------------------
1 | local pandoc = require 'pandoc'
2 | ---@type table
3 | local Counter = {} -- counter for each namespace
4 | ---@type table
5 | local Targets = {} -- maps reference IDs to reference numbers, e.g. {@fig:A=1, @fig:B=2, @tab:A=1}
6 | ---@type table>
7 | local Cap = {} -- localized caption strings
8 |
9 |
10 | local debugmsg = function(logstr) end
11 | -- local debugmsg = print
12 | local warnmsg = print
13 |
14 | --- returns the namespace portion from an id (i.e. 'fig' in 'fig:foobar') or nil
15 | local function getnamespace(id)
16 | if id == nil then return nil end
17 | local colonidx = id:find(':')
18 | if colonidx ~= nil then
19 | return id:sub(1, colonidx - 1)
20 | else
21 | return nil
22 | end
23 | end
24 |
25 | --- to be overridden for some formats; escapes the reference ID if needed
26 | ---@param id string
27 | local function EscapeId(id)
28 | return id
29 | end
30 |
31 | local function Link(text, id)
32 | return pandoc.Link(text, '#' .. id)
33 | end
34 |
35 | --- increments the counter for a namespace, saves and returns the index of refid
36 | ---@param namespace string
37 | ---@param refid string
38 | ---@return integer
39 | local function storeRef(namespace, refid)
40 | local refno = (Counter[namespace] or 0) + 1
41 |
42 | debugmsg(' Adding ref to ' .. namespace .. ' -> ' .. refid .. '(#' .. refno .. ')')
43 | Counter[namespace] = refno
44 | if refid ~= nil then Targets[refid] = refno end
45 | return refno
46 | end
47 |
48 | local function getRefLink(namespace, refid)
49 | local t = Targets[refid]
50 | if refid:sub(1,4) == 'sec:' then
51 | refid = refid:sub(5)
52 | end
53 | if t == nil then
54 | warnmsg('Missing reference: (' .. namespace .. '): ' .. refid)
55 | return pandoc.Strong(refid .. '?')
56 | else
57 | return Link(tostring(t), EscapeId(refid))
58 | end
59 | end
60 |
61 | --- prepends "Figure XY: " to an image caption
62 | local function InsertNumInImgCaption(caption, namespace, refno, identifier)
63 | if caption.long ~= nil then
64 | caption = caption.long[1].content
65 | end
66 | caption:insert(1, pandoc.Str(Cap[namespace].ref .. ' ' .. refno .. ': '))
67 | end
68 |
69 | --- prepends "Table XY: " to a table caption
70 | function InsertNumInTabCaption(caption, namespace, refno, identifier)
71 | caption.long[1].content:insert(1, pandoc.Str(Cap[namespace].ref .. ' ' .. refno .. ': '))
72 | end
73 |
74 | --- appends "(XY)" to a span containing an equation
75 | function InsertNumInEqCaption(caption, namespace, refno, identifier)
76 | caption.content:insert(pandoc.Str(' (' .. refno .. ')'))
77 | end
78 |
79 | --- formats and returns a reference, optionally with prefix (Table XY)
80 | function InsertRef(id, namespace, withprefix)
81 | local reflink = getRefLink(namespace, id)
82 | if withprefix then
83 | return {pandoc.Str(Cap[namespace].ref .. ' '), reflink}
84 | end
85 | return {reflink}
86 | end
87 |
88 | --- format specific overrides, e.g. for native reference handling
89 | if FORMAT == 'latex' then
90 | local function label(id)
91 | return pandoc.RawInline('latex', '\\label{' .. EscapeId(id) .. '}')
92 | end
93 |
94 | function InsertNumInTabCaption(caption, namespace, refno, identifier)
95 | -- no longer needed since pandoc 3
96 | -- caption.long[1].content:insert(label(identifier))
97 | end
98 |
99 | --- replaces the markdown equation with a native latex equation + prepended \\label
100 | function InsertNumInEqCaption(span, namespace, refno, identifier)
101 | local eq = span.content[1]
102 | local el = label(identifier)
103 | el.text = '$$' .. el.text .. eq.text .. '$$'
104 | return el
105 | end
106 |
107 | function getRefLink(namespace, refid)
108 | if refid:sub(1,4) == 'sec:' then
109 | refid = refid:sub(5)
110 | end
111 | return pandoc.RawInline('latex', '\\ref{' .. refid ..'}')
112 | end
113 |
114 | elseif FORMAT == 'docx' then
115 | function EscapeId(id)
116 | if id:sub(1,4) == 'sec:' then
117 | return id:sub(5)
118 | end
119 | return 'refnos_' .. id
120 | end
121 | local function DocxFieldFunction(instr, text, hlink)
122 | local xml = '' .. text .. ''
123 | if hlink ~= nil then
124 | -- return '' .. xml .. ''
125 | xml = ''.. xml ..''
126 | end
127 | return pandoc.RawInline('openxml', xml)
128 | end
129 |
130 | function InsertRef(id, namespace, withprefix)
131 | local t = Targets[id]
132 | if t == nil then
133 | warnmsg(' Missing reference: ' .. namespace .. ' -> ' .. id)
134 | return {pandoc.Strong(id .. '??')}
135 | end
136 | id = EscapeId(id)
137 |
138 | -- not yet usable
139 | if namespace == 'sec' then
140 | local field = DocxFieldFunction(' REF ' .. id .. ' \\w \\h ', t)
141 | if withprefix then
142 | return {pandoc.Str(Cap.sec.ref), field}
143 | else
144 | return {field}
145 | end
146 | end
147 |
148 | -- full fldChar XML:
149 | -- local xml = '' ..
150 | -- ' REF ' .. EscapeId(id) .. ' \\h' ..
151 | -- ''..
152 | -- '' t .. '' ..
153 | -- ''
154 | -- local xml = ''..prefix .. ' ' .. t .. ''
155 | if withprefix then
156 | return {DocxFieldFunction(' REF ' .. id .. ' \\h', Cap[namespace].ref .. ' ' .. t)}
157 | end
158 |
159 | return {DocxFieldFunction(' SEQ ' .. Cap[namespace].ref .. ' ' .. id .. ' \\c', t, nil)}
160 | end
161 |
162 | function InsertNumInCaption(caption, namespace, refno, identifier)
163 | -- generate hopefully unique bookmark ID
164 | local span = pandoc.Span(Cap[namespace].ref .. ' ')
165 | span.attr.identifier = EscapeId(identifier)
166 | span.content:insert(DocxFieldFunction(' SEQ ' .. Cap[namespace].ref .. ' \\* ARABIC ', refno))
167 | -- span.content:insert(pandoc.Str(': '))
168 | caption:insert(1, span)
169 | caption:insert(2, pandoc.Str(': '))
170 | end
171 | function InsertNumInTabCaption(caption, namespace, refno, identifier)
172 | InsertNumInCaption(caption.long[1].content, namespace, refno, identifier)
173 | end
174 | function InsertNumInImgCaption(caption, namespace, refno, identifier)
175 | if caption.long ~= nil then
176 | caption = caption.long[1].content
177 | end
178 |
179 | InsertNumInCaption(caption, namespace, refno, identifier)
180 | end
181 | function InsertNumInEqCaption(eq_span, namespace, refno, identifier)
182 | local span = pandoc.Span(DocxFieldFunction(' SEQ ' .. Cap[namespace].ref .. ' \\* ARABIC ', refno))
183 | span.attr.identifier = EscapeId(identifier)
184 |
185 | local txt = eq_span.content
186 | txt:insert(pandoc.Str(' ('))
187 | txt:insert(pandoc.Span(span))
188 | txt:insert(pandoc.Str(')'))
189 | end
190 |
191 | elseif FORMAT == 'markdown' then
192 | function InsertNumInTabCaption(caption, namespace, refno, identifier)
193 | local span = pandoc.Span(Cap[namespace].ref .. ' ' .. refno .. ': ')
194 | span.attr.identifier = EscapeId(identifier)
195 | caption.long[1].content:insert(1, span)
196 | end
197 | end
198 |
199 | -- parses and removes an ID and attributes like
200 | -- This is a caption {#id attr1=val1 foobar=baz}
201 | -- into "This is a caption", {attr1="val1", foobar="baz"}
202 | function GetAttrsFromCaption(e)
203 | if e.caption == nil or #e.caption.long == 0 then return e, nil end
204 |
205 | local cap = e.caption.long[1]
206 | local attrstr = (' '..pandoc.utils.stringify(cap)):match(' ({.*})$')
207 | if attrstr == nil then return e, nil end
208 |
209 | -- reuse pandocs span attribute parser
210 | local attrs = pandoc.read('[text]' .. attrstr).blocks[1].content[1].attr
211 |
212 | -- remove string from caption, starting at the end
213 | local i = #cap.content
214 | while i > 1 do
215 | local el = cap.content:remove(i)
216 | if el.tag == 'Str' and el.text:sub(1, 1) == '{' then break end
217 | i = i - 1
218 | end
219 | -- also remove preceding space
220 | if #cap.content > 0 and cap.content[#cap.content].t == 'Space' then
221 | cap.content:remove(#cap.content)
222 | end
223 |
224 | -- remove strings from caption
225 | while i <= #cap.content do cap.content:remove(#cap.content) end
226 |
227 | return e, attrs
228 | end
229 |
230 | --- Parse ID, class and attributes in the caption
231 | -- Markdown has no native syntax for table attributes (unlike images), so
232 | -- this function parses an attribute string at the end of the caption
233 | local function MoveCaptionAttrsToTable(tab)
234 | local tbl, attr = GetAttrsFromCaption(tab)
235 | if attr ~= nil then
236 | tbl.attr.identifier = attr.identifier
237 | tbl.attr.classes:extend(attr.classes)
238 | for k, v in pairs(attr.attributes) do tbl.attr.attributes[k] = v end
239 | debugmsg('Extracted table id ' .. attr.identifier)
240 | return tbl
241 | end
242 | end
243 |
244 | local function HandleTable(tbl)
245 | local id = tbl.attr.identifier
246 | if id ~= '' then
247 | local ns = getnamespace(id)
248 | local refno = storeRef(ns, tbl.attr.identifier)
249 | InsertNumInTabCaption(tbl.caption, ns, refno, tbl.attr.identifier)
250 | return tbl
251 | end
252 | end
253 |
254 | local function HandleFigure(fig)
255 | local id = fig.identifier
256 | if id:sub(1, 4) == 'fig:' then
257 | local figno = storeRef('fig', id)
258 | if fig.caption ~= nil and fig.caption.long ~= nil then
259 | InsertNumInImgCaption(fig.caption, 'fig', figno, id)
260 | return fig
261 | end
262 | end
263 | end
264 |
265 | local function HandleImage(img)
266 | local id = img.identifier
267 | if id:sub(1, 4) == 'fig:' then
268 | local figno = storeRef('fig', id)
269 |
270 | if img.caption ~= nil then
271 | InsertNumInImgCaption(img.caption, 'fig', figno, id)
272 | return img
273 | end
274 | end
275 | end
276 |
277 | local function HandleEquationInSpan(sp)
278 | if sp.content[1].t ~= 'Math' or sp.content[1].mathtype ~= 'DisplayMath' then
279 | return
280 | end
281 | local id = sp.attr.identifier
282 | local ns = getnamespace(id)
283 | if ns ~= nil then
284 | local refno = storeRef(ns, id)
285 | InsertNumInEqCaption(sp, ns, refno, id)
286 | return sp
287 | end
288 | end
289 |
290 | CurChapter = {0, 0, 0, 0, 0, 0, 0, 0, 0}
291 | local function HandleHeader(h)
292 | CurChapter[h.level] = CurChapter[h.level] + 1
293 | for i = h.level + 1, 9 do
294 | CurChapter[i] = 0
295 | end
296 | local chapterNumber = CurChapter[1]
297 | for i = 2, #CurChapter do
298 | if CurChapter[i] == 0 then break end
299 | chapterNumber = chapterNumber .. '.' .. CurChapter[i]
300 | end
301 | if h.identifier then
302 | Targets['sec:' .. h.identifier] = chapterNumber
303 | end
304 | end
305 |
306 | local function HandleCitation(c)
307 | local namespace = getnamespace(c.citations[1].id)
308 | if namespace == nil then return end
309 |
310 | local res = pandoc.List()
311 | -- special case: AuthorInText, e.g. "As seen in @tab:foobar, …"
312 | if #c.citations == 1 and c.citations[1].mode == pandoc.AuthorInText then
313 | local ct = c.citations[1]
314 | res:extend(InsertRef(ct.id, namespace, true))
315 | res:extend(ct.suffix)
316 | return res
317 | end
318 |
319 | if c.citations[1].mode ~= pandoc.SuppressAuthor then
320 | if #c.citations == 1 then
321 | res:insert(pandoc.Str(Cap[namespace].ref .. ' '))
322 | else
323 | res:insert(pandoc.Str(Cap[namespace].plural .. ' '))
324 | end
325 | end
326 |
327 | for i, ct in ipairs(c.citations) do
328 | if namespace ~= getnamespace(ct.id) then
329 | warnmsg('Found mixed references in citation' .. c.content)
330 | res:insert(pandoc.Strong('… unprocessed citations'))
331 | return res
332 | end
333 |
334 | if i == 1 then
335 | -- nothing to do
336 | elseif i == #c.citations then
337 | res:insert(pandoc.Str(' & '))
338 | else
339 | res:insert(pandoc.Str(', '))
340 | end
341 | if #ct.prefix > 0 then
342 | res:extend(ct.prefix)
343 | res:insert(pandoc.Space())
344 | end
345 | res:extend(InsertRef(ct.id, namespace, false))
346 | res:extend(ct.suffix)
347 | end
348 | return res
349 | end
350 |
351 | local function MetaToStr(m)
352 | if m == nil then
353 | return nil
354 | elseif type(m) == 'string' then
355 | return m
356 | elseif m.t == 'MetaInlines' or m.t == 'Str' then
357 | return pandoc.utils.stringify(m)
358 | elseif m.t == 'MetaString' then
359 | return m.str
360 | elseif type(m) == 'table' then
361 | return MetaToStr(m[1])
362 | else
363 | warnmsg('unhandled type ' .. type(m))
364 | warnmsg(m.t)
365 | return nil
366 | end
367 | end
368 |
369 | function SetStrings(opts, lang)
370 | local Localized = {
371 | de = {
372 | tab = {ref = 'Tabelle', plural = 'Tabellen', abbrev = 'Tab.'},
373 | fig = {ref = 'Abbildung', plural = 'Abbildungen', abbrev = 'Abb.'},
374 | eq = {ref = 'Gleichung', plural = 'Gleichungen', abbrev = 'Gl.'},
375 | sec = {ref = 'Abschnitt', plural = 'Abschnitte', abbrev = 'Abs.'}
376 | },
377 | en = {
378 | tab = {ref = 'Table', plural = 'Tables', abbrev = 'Tab.'},
379 | fig = {ref = 'Figure', plural = 'Figures', abbrev = 'Fig.'},
380 | eq = {ref = 'Equation', plural = 'Equations', abbrev = 'Eq.'},
381 | sec = {ref = 'Section', plural = 'Sections', abbrev = 'Sec.'}
382 | }
383 | }
384 |
385 | if opts.strs == nil or type(opts.strs) ~= 'table' then opts.strs = Localized end
386 | if opts.strs[lang] == nil then lang = 'en' end
387 |
388 | for namespace, strs in pairs(opts.strs[lang]) do
389 | for k, v in pairs(strs) do
390 | if k ~= 'ref' and k~='plural' and k~='abbrev' then
391 | warnmsg('Unknown key luarefnos.'..lang..'.'..namespace..'.'..k)
392 | end
393 | strs[k] = MetaToStr(v)
394 | end
395 |
396 | if strs.ref == nil then
397 | warnmsg('Missing "ref" in luarefnos.'..lang..'.'..namespace)
398 | strs.ref = '???'
399 | end
400 | if strs.plural == nil then
401 | strs.plural = strs.ref .. 's'
402 | end
403 | if strs.abbrev == nil then
404 | strs.abbrev = strs.ref:sub(1,3)
405 | end
406 | end
407 | Cap = opts.strs[lang]
408 | end
409 |
410 | function Init(m)
411 | local opts = m.luarefnos
412 | -- if opts == nil then return end
413 |
414 | local lang = MetaToStr(m.lang) or 'en'
415 |
416 | SetStrings(m.luarefnos or {}, lang)
417 | end
418 |
419 | return {{Meta = Init},
420 | {Table = MoveCaptionAttrsToTable},
421 | {
422 | Header = HandleHeader,
423 | Table = HandleTable,
424 | Image = HandleImage,
425 | Figure = HandleFigure,
426 | Span = HandleEquationInSpan
427 | },
428 | {Cite = HandleCitation}}
429 |
--------------------------------------------------------------------------------