Prepare for scope-limited footnote numbering

This commit is contained in:
jfbu
2021-02-06 10:45:50 +01:00
parent 9c823478e0
commit 628c58abef
4 changed files with 48 additions and 33 deletions

View File

@@ -176,7 +176,7 @@
\@footnotemark \@footnotemark
% Sphinx addition: store internal hyperref anchor reference to allow % Sphinx addition: store internal hyperref anchor reference to allow
% multiple clickable reference to same numbered footnote % multiple clickable reference to same numbered footnote
\expandafter\xdef\csname FNH@!#1\endcsname{\Hy@footnote@currentHref}% \expandafter\xdef\csname FNH!\number\value{sphinxscope}!#1\endcsname{\Hy@footnote@currentHref}%
\def\FNH@endfntext@fntext{\@footnotetext}% \def\FNH@endfntext@fntext{\@footnotetext}%
\FNH@startfntext \FNH@startfntext
}% }%
@@ -329,35 +329,34 @@
% \sphinxfootnotemark: usable in section titles and silently removed from TOCs. % \sphinxfootnotemark: usable in section titles and silently removed from TOCs.
\def\sphinxfootnotemark [#1]% \def\sphinxfootnotemark [#1]%
{\ifx\thepage\relax\else\sphinxfootref{#1}\fi}% {\ifx\thepage\relax\else\sphinxfootref{#1}\fi}%
% \sphinxfootref: inspired by \footref from footmisc package as % \sphinxfootref:
% re-defined by hyperref, but with an extra FNH@! branch:
% - \spx@opt@BeforeFootnote is from BeforeFootnote sphinxsetup option % - \spx@opt@BeforeFootnote is from BeforeFootnote sphinxsetup option
% - \ref{fn:#1} branch: % - \ref branch:
% the latex.py writer inserts at start of footnotetext contents % the latex.py writer inserts at start of footnotetext contents
% \phantomsection\label{fn:<num>}, so we can use \ref which % \phantomsection\label{<scope>.<num>}, so we can use \ref which
% hyperref converts into an hyperlink. This is basically the % hyperref converts into an hyperlink. <scope> is the number of
% idea of the \footref macro from package footmisc. % the scope and <num> the number of the footnote, local to scope.
% - FNH@! branch: % - FNH! branch:
% explicitly numbered footnotes in latex.py output always use first % explicitly numbered footnotes in latex.py output always use first
% the footnote environment, then \sphinxfootnotemark. We patched % the footnote environment, then \sphinxfootnotemark. We patched
% \FNH@footnoteenv@i to define the \FNH@!<number> macro as storage % \FNH@footnoteenv@i to define the \FNH!<scope>!<number> macro as storage
% for the internal hyperref target id for the hyperref anchor. So % for the internal hyperref target id for the hyperref anchor. So
% we can then create an hyperlink from any \sphinxfootnotemark with % we can then create an hyperlink from any \sphinxfootnotemark with
% this <number> as argument. % this <number> as argument and taking into account current <scope>.
\protected\def\sphinxfootref#1{% \protected\def\sphinxfootref#1{% #1 always explicit number in Sphinx usage
\spx@opt@BeforeFootnote \spx@opt@BeforeFootnote
\ifcsname FNH@!#1\endcsname \ifcsname FNH!\number\value{sphinxscope}!#1\endcsname
\def\@thefnmark{#1}% \gdef\@thefnmark{#1}% \@thefnmark always redefined globally by latex
\let\spx@saved@makefnmark\@makefnmark \let\spx@saved@makefnmark\@makefnmark
\def\@makefnmark{% \edef\@makefnmark{% we pre-expand the sphinxscope value, to be safe
\hyper@linkstart{link}{\@nameuse{FNH@!#1}}% \noexpand\hyper@linkstart{link}{\@nameuse{FNH!\number\value{sphinxscope}!#1}}%
\spx@saved@makefnmark \noexpand\spx@saved@makefnmark
\hyper@linkend \noexpand\hyper@linkend
}% }%
\H@@footnotemark \H@@footnotemark
\let\@makefnmark\spx@saved@makefnmark \let\@makefnmark\spx@saved@makefnmark
\else \else
\def\@thefnmark{\ref{fn:#1}}% #1 = number \xdef\@thefnmark{\noexpand\ref{\number\value{sphinxscope}.#1}}% #1 = number
\H@@footnotemark \H@@footnotemark
\fi \fi
}% }%

View File

@@ -844,6 +844,8 @@
%% FOOTNOTES %% FOOTNOTES
% %
% Support scopes for footnote numbering
\newcounter{sphinxscope}
% Support large numbered footnotes in minipage % Support large numbered footnotes in minipage
% But now obsolete due to systematic use of \savenotes/\spewnotes % But now obsolete due to systematic use of \savenotes/\spewnotes
% when minipages are in use in the various macro definitions next. % when minipages are in use in the various macro definitions next.

View File

@@ -1738,7 +1738,7 @@ class LaTeXTranslator(SphinxTranslator):
def visit_footnotetext(self, node: Element) -> None: def visit_footnotetext(self, node: Element) -> None:
label = cast(nodes.label, node[0]) label = cast(nodes.label, node[0])
self.body.append('%%\n\\begin{footnotetext}[%s]' self.body.append('%%\n\\begin{footnotetext}[%s]'
'\\phantomsection\\label{fn:%s}%%\n' '\\phantomsection\\label{\\number\\value{sphinxscope}.%s}%%\n'
'\\sphinxAtStartFootnote\n' % (label.astext(), label.astext())) '\\sphinxAtStartFootnote\n' % (label.astext(), label.astext()))
def depart_footnotetext(self, node: Element) -> None: def depart_footnotetext(self, node: Element) -> None:

View File

@@ -732,10 +732,12 @@ def test_footnote(app, status, warning):
assert '\\sphinxcite{footnote:bar}' in result assert '\\sphinxcite{footnote:bar}' in result
assert ('\\bibitem[bar]{footnote:bar}\n\\sphinxAtStartPar\ncite\n') in result assert ('\\bibitem[bar]{footnote:bar}\n\\sphinxAtStartPar\ncite\n') in result
assert '\\sphinxcaption{Table caption \\sphinxfootnotemark[4]' in result assert '\\sphinxcaption{Table caption \\sphinxfootnotemark[4]' in result
assert ('\\hline%\n\\begin{footnotetext}[4]\\phantomsection\\label{fn:4}%\n' assert ('\\hline%\n\\begin{footnotetext}[4]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.4}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'footnote in table caption\n%\n\\end{footnotetext}\\ignorespaces %\n' 'footnote in table caption\n%\n\\end{footnotetext}\\ignorespaces %\n'
'\\begin{footnotetext}[5]\\phantomsection\\label{fn:5}%\n' '\\begin{footnotetext}[5]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.5}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'footnote in table header\n%\n\\end{footnotetext}\\ignorespaces ' 'footnote in table header\n%\n\\end{footnotetext}\\ignorespaces '
'\n\\sphinxAtStartPar\n' '\n\\sphinxAtStartPar\n'
@@ -762,22 +764,26 @@ def test_reference_in_caption_and_codeblock_in_footnote(app, status, warning):
assert '\\subsubsection*{The rubric title with a reference to {[}AuthorYear{]}}' in result assert '\\subsubsection*{The rubric title with a reference to {[}AuthorYear{]}}' in result
assert ('\\chapter{The section with a reference to \\sphinxfootnotemark[5]}\n' assert ('\\chapter{The section with a reference to \\sphinxfootnotemark[5]}\n'
'\\label{\\detokenize{index:the-section-with-a-reference-to}}' '\\label{\\detokenize{index:the-section-with-a-reference-to}}'
'%\n\\begin{footnotetext}[5]\\phantomsection\\label{fn:5}%\n' '%\n\\begin{footnotetext}[5]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.5}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Footnote in section\n%\n\\end{footnotetext}') in result 'Footnote in section\n%\n\\end{footnotetext}') in result
assert ('\\caption{This is the figure caption with a footnote to ' assert ('\\caption{This is the figure caption with a footnote to '
'\\sphinxfootnotemark[7].}\\label{\\detokenize{index:id29}}\\end{figure}\n' '\\sphinxfootnotemark[7].}\\label{\\detokenize{index:id29}}\\end{figure}\n'
'%\n\\begin{footnotetext}[7]\\phantomsection\\label{fn:7}%\n' '%\n\\begin{footnotetext}[7]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.7}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Footnote in caption\n%\n\\end{footnotetext}') in result 'Footnote in caption\n%\n\\end{footnotetext}') in result
assert ('\\sphinxcaption{footnote \\sphinxfootnotemark[8] in ' assert ('\\sphinxcaption{footnote \\sphinxfootnotemark[8] in '
'caption of normal table}\\label{\\detokenize{index:id30}}') in result 'caption of normal table}\\label{\\detokenize{index:id30}}') in result
assert ('\\caption{footnote \\sphinxfootnotemark[9] ' assert ('\\caption{footnote \\sphinxfootnotemark[9] '
'in caption \\sphinxfootnotemark[10] of longtable\\strut}') in result 'in caption \\sphinxfootnotemark[10] of longtable\\strut}') in result
assert ('\\endlastfoot\n%\n\\begin{footnotetext}[9]\\phantomsection\\label{fn:9}%\n' assert ('\\endlastfoot\n%\n\\begin{footnotetext}[9]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.9}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Foot note in longtable\n%\n\\end{footnotetext}\\ignorespaces %\n' 'Foot note in longtable\n%\n\\end{footnotetext}\\ignorespaces %\n'
'\\begin{footnotetext}[10]\\phantomsection\\label{fn:10}%\n' '\\begin{footnotetext}[10]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.10}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Second footnote in caption of longtable\n') in result 'Second footnote in caption of longtable\n') in result
assert ('This is a reference to the code\\sphinxhyphen{}block in the footnote:\n' assert ('This is a reference to the code\\sphinxhyphen{}block in the footnote:\n'
@@ -818,7 +824,8 @@ def test_latex_show_urls_is_inline(app, status, warning):
assert '\\sphinxhref{http://sphinx-doc.org/}{Sphinx} (http://sphinx\\sphinxhyphen{}doc.org/)' in result assert '\\sphinxhref{http://sphinx-doc.org/}{Sphinx} (http://sphinx\\sphinxhyphen{}doc.org/)' in result
assert ('Third footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n' assert ('Third footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n'
'Third \\sphinxfootnotemark[4]\n%\n\\end{footnote}%\n' 'Third \\sphinxfootnotemark[4]\n%\n\\end{footnote}%\n'
'\\begin{footnotetext}[4]\\phantomsection\\label{fn:4}%\n' '\\begin{footnotetext}[4]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.4}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Footnote inside footnote\n%\n\\end{footnotetext}\\ignorespaces') in result 'Footnote inside footnote\n%\n\\end{footnotetext}\\ignorespaces') in result
assert ('\\sphinxhref{http://sphinx-doc.org/~test/}{URL including tilde} ' assert ('\\sphinxhref{http://sphinx-doc.org/~test/}{URL including tilde} '
@@ -827,7 +834,8 @@ def test_latex_show_urls_is_inline(app, status, warning):
'(http://sphinx\\sphinxhyphen{}doc.org/)}] ' '(http://sphinx\\sphinxhyphen{}doc.org/)}] '
'\\leavevmode\n\\sphinxAtStartPar\nDescription' in result) '\\leavevmode\n\\sphinxAtStartPar\nDescription' in result)
assert ('\\item[{Footnote in term \\sphinxfootnotemark[6]}] ' assert ('\\item[{Footnote in term \\sphinxfootnotemark[6]}] '
'\\leavevmode%\n\\begin{footnotetext}[6]\\phantomsection\\label{fn:6}%\n' '\\leavevmode%\n\\begin{footnotetext}[6]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.6}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Footnote in term\n%\n\\end{footnotetext}\\ignorespaces ' 'Footnote in term\n%\n\\end{footnotetext}\\ignorespaces '
'\n\\sphinxAtStartPar\nDescription') in result '\n\\sphinxAtStartPar\nDescription') in result
@@ -869,7 +877,8 @@ def test_latex_show_urls_is_footnote(app, status, warning):
'\\sphinxnolinkurl{http://sphinx-doc.org/}\n%\n\\end{footnote}') in result '\\sphinxnolinkurl{http://sphinx-doc.org/}\n%\n\\end{footnote}') in result
assert ('Third footnote: %\n\\begin{footnote}[6]\\sphinxAtStartFootnote\n' assert ('Third footnote: %\n\\begin{footnote}[6]\\sphinxAtStartFootnote\n'
'Third \\sphinxfootnotemark[7]\n%\n\\end{footnote}%\n' 'Third \\sphinxfootnotemark[7]\n%\n\\end{footnote}%\n'
'\\begin{footnotetext}[7]\\phantomsection\\label{fn:7}%\n' '\\begin{footnotetext}[7]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.7}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Footnote inside footnote\n%\n' 'Footnote inside footnote\n%\n'
'\\end{footnotetext}\\ignorespaces') in result '\\end{footnotetext}\\ignorespaces') in result
@@ -878,18 +887,21 @@ def test_latex_show_urls_is_footnote(app, status, warning):
'\\sphinxnolinkurl{http://sphinx-doc.org/~test/}\n%\n\\end{footnote}') in result '\\sphinxnolinkurl{http://sphinx-doc.org/~test/}\n%\n\\end{footnote}') in result
assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}' assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}'
'{URL in term}\\sphinxfootnotemark[9]}] ' '{URL in term}\\sphinxfootnotemark[9]}] '
'\\leavevmode%\n\\begin{footnotetext}[9]\\phantomsection\\label{fn:9}%\n' '\\leavevmode%\n\\begin{footnotetext}[9]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.9}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'\\sphinxnolinkurl{http://sphinx-doc.org/}\n%\n' '\\sphinxnolinkurl{http://sphinx-doc.org/}\n%\n'
'\\end{footnotetext}\\ignorespaces \n\\sphinxAtStartPar\nDescription') in result '\\end{footnotetext}\\ignorespaces \n\\sphinxAtStartPar\nDescription') in result
assert ('\\item[{Footnote in term \\sphinxfootnotemark[11]}] ' assert ('\\item[{Footnote in term \\sphinxfootnotemark[11]}] '
'\\leavevmode%\n\\begin{footnotetext}[11]\\phantomsection\\label{fn:11}%\n' '\\leavevmode%\n\\begin{footnotetext}[11]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.11}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Footnote in term\n%\n\\end{footnotetext}\\ignorespaces ' 'Footnote in term\n%\n\\end{footnotetext}\\ignorespaces '
'\n\\sphinxAtStartPar\nDescription') in result '\n\\sphinxAtStartPar\nDescription') in result
assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}{Term in deflist}' assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}{Term in deflist}'
'\\sphinxfootnotemark[10]}] ' '\\sphinxfootnotemark[10]}] '
'\\leavevmode%\n\\begin{footnotetext}[10]\\phantomsection\\label{fn:10}%\n' '\\leavevmode%\n\\begin{footnotetext}[10]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.10}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'\\sphinxnolinkurl{http://sphinx-doc.org/}\n%\n' '\\sphinxnolinkurl{http://sphinx-doc.org/}\n%\n'
'\\end{footnotetext}\\ignorespaces \n\\sphinxAtStartPar\nDescription') in result '\\end{footnotetext}\\ignorespaces \n\\sphinxAtStartPar\nDescription') in result
@@ -926,14 +938,16 @@ def test_latex_show_urls_is_no(app, status, warning):
assert '\\sphinxhref{http://sphinx-doc.org/}{Sphinx}' in result assert '\\sphinxhref{http://sphinx-doc.org/}{Sphinx}' in result
assert ('Third footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n' assert ('Third footnote: %\n\\begin{footnote}[3]\\sphinxAtStartFootnote\n'
'Third \\sphinxfootnotemark[4]\n%\n\\end{footnote}%\n' 'Third \\sphinxfootnotemark[4]\n%\n\\end{footnote}%\n'
'\\begin{footnotetext}[4]\\phantomsection\\label{fn:4}%\n' '\\begin{footnotetext}[4]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.4}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Footnote inside footnote\n%\n\\end{footnotetext}\\ignorespaces') in result 'Footnote inside footnote\n%\n\\end{footnotetext}\\ignorespaces') in result
assert '\\sphinxhref{http://sphinx-doc.org/~test/}{URL including tilde}' in result assert '\\sphinxhref{http://sphinx-doc.org/~test/}{URL including tilde}' in result
assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}{URL in term}}] ' assert ('\\item[{\\sphinxhref{http://sphinx-doc.org/}{URL in term}}] '
'\\leavevmode\n\\sphinxAtStartPar\nDescription') in result '\\leavevmode\n\\sphinxAtStartPar\nDescription') in result
assert ('\\item[{Footnote in term \\sphinxfootnotemark[6]}] ' assert ('\\item[{Footnote in term \\sphinxfootnotemark[6]}] '
'\\leavevmode%\n\\begin{footnotetext}[6]\\phantomsection\\label{fn:6}%\n' '\\leavevmode%\n\\begin{footnotetext}[6]'
'\\phantomsection\\label{\\number\\value{sphinxscope}.6}%\n'
'\\sphinxAtStartFootnote\n' '\\sphinxAtStartFootnote\n'
'Footnote in term\n%\n\\end{footnotetext}\\ignorespaces ' 'Footnote in term\n%\n\\end{footnotetext}\\ignorespaces '
'\n\\sphinxAtStartPar\nDescription') in result '\n\\sphinxAtStartPar\nDescription') in result