经过几天的尝试,我基本上完成了 的新版本multifootnote
。但是,查看日志文件时,我注意到其中有几行类似这样的内容(使用 pdflatex):
pdfTeX warning (ext4): destination with the same identifier (name{...}) has been already used, duplicate ignored
pdfTeX warning (dest): name{...} has been referenced but does not exist, replaced by a fixed one
或(使用 lualatex)
warning (pdf backend): ignoring duplicate destination with the name '...'
warning (pdf backend): unreferenced destination with name '...'
或(使用 xelatex)
xdvipdfmx:warning: Object @... already defined.
考虑到生成的 PDF 看起来不错,我需要担心这些警告吗?由于我不熟悉超链接的工作原理,所以我不太清楚如何解决此类问题。
下面是 MWE。
\documentclass{article}
\usepackage[paperwidth=5cm,paperheight=5cm]{geometry}
% \usepackage{multifootnote}
\usepackage[backref]{multifootnote}
% \usepackage[manual]{multifootnote}
% \usepackage[manual,backref]{multifootnote}
% \usepackage{hyperref}
\begin{document}
% First approach
Lorem ipsum\footnotenumber[fn1] dolor\footnotenumber[fn2] sit amet\footnotenumber[fn3], \clearpage
consectetur\footnotenumber[fn4] adipiscing elit\footnotenumber[fn5].
\multifootnote[fn1,fn2,fn5]{This is a footnote for demonstration.}
\multifootnote[fn1,fn3,fn4]{This is another footnote for demonstration.}
\clearpage
% Second approach
Lorem ipsum\footnotetag{fntag1,fntag2} dolor\footnotetag{fntag1} sit amet\footnotetag{fntag2}, \clearpage
consectetur\footnotetag{fntag2} adipiscing elit\footnotetag{fntag1}.
\multifootnote[fntag1]{This is a footnote for demonstration.}
\multifootnote[fntag2]{This is another footnote for demonstration.}
\clearpage
SOME TEXT
\end{document}
以下是 的当前版本multifootnote.sty
。
\NeedsTeXFormat{LaTeX2e}[2022-06-01]
\ProvidesExplPackage
{multifootnote}
{2024/03/23*} {}
{Multiple numbers for the same footnote}
\msg_new:nnn { multifootnote }
{ non-compatible-package }
{ "multifootnote" ~ is ~ not ~ compatible ~ with ~ the ~ package ~ "#1". }
\hook_gput_code:nnn { begindocument/before } { multifootnote }
{
\@ifpackageloaded { footnotebackref }
{
\msg_warning:nnn { multifootnote } { non-compatible-package } { footnotebackref }
} {}
}
\dim_new:N \l_multifootnote_space_after_comma_dim
\dim_set:Nn \l_multifootnote_space_after_comma_dim { 0.2ex }
\bool_new:N \l__multifootnote_left_indent_bool
\bool_set_false:N \l__multifootnote_left_indent_bool
\dim_new:N \l__multifootnote_left_indent_dim
\keys_define:nn { multifootnote }
{
, backref .bool_set:N = \l__multifootnote_backref_bool
, backref .initial:n = { false }
, left-align .bool_set:N = \l__multifootnote_left_align_bool
, left-align .initial:n = { false }
, left~align .bool_set:N = \l__multifootnote_left_align_bool
, left align .bool_set:N = \l__multifootnote_left_align_bool
, left-indent .code:n = {
\bool_set_true:N \l__multifootnote_left_indent_bool
\dim_set:Nn \l__multifootnote_left_indent_dim { #1 }
}
, left-indent .default:n = { 1.5em }
, left~indent .code:n = {
\bool_set_true:N \l__multifootnote_left_indent_bool
\dim_set:Nn \l__multifootnote_left_indent_dim { #1 }
}
, left~indent .default:n = { 1.5em }
, left indent .code:n = {
\bool_set_true:N \l__multifootnote_left_indent_bool
\dim_set:Nn \l__multifootnote_left_indent_dim { #1 }
}
, left indent .default:n = { 1.5em }
, manual .bool_set:N = \l__multifootnote_manual_mode_bool
, manual .initial:n = { false }
, manual-mode .bool_set:N = \l__multifootnote_manual_mode_bool
, manual~mode .bool_set:N = \l__multifootnote_manual_mode_bool
, manual mode .bool_set:N = \l__multifootnote_manual_mode_bool
, unknown .code:n = {}
}
\ProcessKeyOptions [ multifootnote ]
\bool_if:NT \l__multifootnote_backref_bool
{
\RequirePackage { hyperref }
}
\RequirePackage { refcount }
\cs_new_protected:Nn \multifootnote_make_footnote_left_align:n
{
\renewcommand { \@makefntext } [1]
{
\skip_horizontal:n { #1 }
\tl_if_blank:eF { \text_expand:n { \@thefnmark } }
{
\@makefnmark
\nobreakspace
}
##1
}
}
\bool_if:NT \l__multifootnote_left_align_bool
{
\multifootnote_make_footnote_left_align:n { 0pt }
}
\bool_if:NT \l__multifootnote_left_indent_bool
{
\multifootnote_make_footnote_left_align:n { \l__multifootnote_left_indent_dim }
}
\tl_new:N \l__multifootnote_tmp_tl
\seq_new:N \l__multifootnote_tmp_seq
\clist_new:N \l__multifootnote_tmp_clist
% get the total page number
\hook_gput_code:nnn { enddocument } { multifootnote }
{
\label{multifootnote_last-page}
}
\int_new:N \g_multifootnote_total_page_int
\hook_gput_code:nnn { begindocument } { multifootnote }
{
\int_gset:Nn \g_multifootnote_total_page_int { \getpagerefnumber{multifootnote_last-page} }
}
% First approach
\NewDocumentCommand \multifootnotemarkmanual { O{} }
{
\footnotemark
\group_begin:
\tl_if_blank:nF { #1 }
{
\addtocounter { footnote } { -1 }
\refstepcounter { footnote }
\label { multifootnote-mark-#1 }
\@ifpackageloaded { hyperref }
{
\cs_gset_eq:NN \@currentHref \Hy@footnote@currentHref
} {}
\label { multifootnote-#1 }
}
\group_end:
}
\NewCommandCopy \footnotenumbermanual \multifootnotemarkmanual
\NewDocumentCommand \multifootnotetextmanual { O{} m }
{
\group_begin:
\tl_if_blank:nTF { #1 }
{
\footnotetext { #2 }
}
{
\clist_clear:N \l_tmpa_clist
\clist_clear:N \l_tmpb_clist
\clist_map_inline:nn { #1 }
{
\@ifpackageloaded { hyperref }
{
\bool_if:NTF \l__multifootnote_backref_bool
{
\clist_put_right:Nn \l_tmpa_clist
{ \hyperref[multifootnote-mark-##1]{ \ref*{ multifootnote-##1 } } }
}
{
\clist_put_right:Nn \l_tmpa_clist
{ \ref*{ multifootnote-##1 } }
}
\clist_put_right:Nn \l_tmpb_clist
{ \Hy@raisedlink { \hypertarget { \getrefbykeydefault{multifootnote-##1}{anchor}{Doc-Start} } {} } }
}
{
\clist_put_right:Nn \l_tmpa_clist
{ \ref { multifootnote-##1 } }
}
}
\def \thefootnote { \clist_use:Nn \l_tmpa_clist { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } } }
\@ifpackageloaded { hyperref }
{
\xdef \Hy@footnote@currentHref { x\Hy@footnote@currentHref }
} {}
\footnotetext { \clist_use:Nn \l_tmpb_clist {} \ignorespaces #2 }
}
\group_end:
}
\seq_new:N \g__multifootnote_mark_internal_seq
\cs_new:Nn \__multifootnote_process_per_page_mark:nnnN
% #1 = labels
% #2 = footnote text
% #3 = actual page number
% #4 = a macro to store the result
{
\tl_gclear:N #4
\clist_clear:N \l_tmpa_clist
\clist_map_inline:nn { #1 }
{
% only keep those labels that appear on the current page
\str_if_eq:eeT { #3 } { \getpagerefnumber{multifootnote-mark-##1} }
{
\clist_put_right:Nn \l_tmpa_clist { ##1 }
}
}
\clist_if_empty:NF \l_tmpa_clist
{
\tl_gput_right:No #4 { \exp_after:wN { \l_tmpa_clist } }
\tl_gput_right:Nn #4 { { #2 } }
}
}
\hook_gput_code:nnn { begindocument } { multifootnote/mark }
{
\int_step_inline:nn { \int_eval:n { \g_multifootnote_total_page_int } }
{
% generate the per page mark-footnotetext sequences
% \tl_show:n { g__multifootnote_mark_internal_page_ #1 _seq }
\seq_new:c { g__multifootnote_mark_internal_page_ #1 _seq }
\seq_new:c { g__multifootnote_mark_internal_page_ #1 _recorded_seq }
% leave only those labels appeared on the current page
\seq_clear:N \l__multifootnote_tmp_seq
\seq_map_inline:cn { g__multifootnote_mark_internal_seq }
{
% \tl_show:n { TEST:~##1 }
\__multifootnote_process_per_page_mark:nnnN ##1 { #1 } \l__multifootnote_tmp_tl
\tl_if_empty:NF \l__multifootnote_tmp_tl
{
\seq_put_right:No \l__multifootnote_tmp_seq { \l__multifootnote_tmp_tl }
}
}
\seq_gset_eq:cN { g__multifootnote_mark_internal_page_ #1 _seq } \l__multifootnote_tmp_seq
% \seq_show:c { g__multifootnote_mark_internal_page_ #1 _seq }
}
}
\NewDocumentCommand \multifootnotemark { O{} }
{
% print the footnote mark
\footnotemark
\group_begin:
\tl_if_blank:nF { #1 }
{
\addtocounter { footnote } { -1 }
\refstepcounter { footnote }
\label { multifootnote-mark-#1 }
\@ifpackageloaded { hyperref }
{
\cs_gset_eq:NN \@currentHref \Hy@footnote@currentHref
} {}
\label { multifootnote-#1 }
}
\group_end:
% print the corresponding footnote text
\tl_if_blank:nF { #1 }
{
\tl_set:Ne \l__multifootnote_tmp_tl { \getpagerefnumber{multifootnote-mark-#1} }
% \tl_show:N \l__multifootnote_tmp_tl
% \seq_show:c { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _seq }
\seq_map_inline:cn { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _seq }
{
% \tl_show:n { TEST:~ { #1 } ##1 }
\seq_if_in:cnF { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _recorded_seq } { ##1 }
{
% \tl_show:n { TEST:~ { #1 } ##1 }
\__multifootnote_print_footnotetext:nnnnn { #1 } ##1
{
% record the current item
\seq_gput_right:cn { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _recorded_seq } { ##1 }
% \seq_show:c { g__multifootnote_mark_internal_page_ \l__multifootnote_tmp_tl _recorded_seq }
} {}
{} {} % the two extra empty groups are added for safety
}
}
}
}
\cs_new:Nn \__multifootnote_print_footnotetext:nnnnn
% #1 = a given label
% #2 = labels
% #3 = footnote text
% #4 = code when the footnote text is indeed printed
% #5 = fallback code when the footnote text does not get printed
{
% \tl_show:n { TEST:~ { #1 } { #2 } { #3 } }
% \clist_if_in:nnTF { #2 } { #1 } { \tl_show:n { TEST:~ {#1}~is~in~{#2}. } } { \tl_show:n { TEST:~ {#1}~is~NOT~in~{#2}. } }
\clist_if_in:nnTF { #2 } { #1 }
{
\clist_clear:N \l_tmpa_clist
\clist_clear:N \l_tmpb_clist
% \clist_show:n { #2 }
\clist_map_inline:nn { #2 }
{
\@ifpackageloaded { hyperref }
{
\bool_if:NTF \l__multifootnote_backref_bool
{
\clist_put_right:Nn \l_tmpa_clist
{ \hyperref[multifootnote-mark-##1]{ \ref*{ multifootnote-##1 } } }
}
{
\clist_put_right:Nn \l_tmpa_clist
{ \ref*{ multifootnote-##1 } }
}
\clist_put_right:Nn \l_tmpb_clist
{ \Hy@raisedlink { \hypertarget { \getrefbykeydefault{multifootnote-##1}{anchor}{Doc-Start} } {} } }
}
{
\clist_put_right:Nn \l_tmpa_clist
{ \ref { multifootnote-##1 } }
}
}
% \clist_show:N \l_tmpa_clist
\group_begin:
\def \thefootnote { \clist_use:Nn \l_tmpa_clist { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } } }
\@ifpackageloaded { hyperref }
{
\xdef \Hy@footnote@currentHref { x\Hy@footnote@currentHref }
} {}
\footnotetext { \clist_use:Nn \l_tmpb_clist {} \ignorespaces #3 }
\group_end:
#4
}
{
#5
}
}
\NewCommandCopy \footnotenumber \multifootnotemark
\NewDocumentCommand \multifootnotetext { O{} m }
{
\tl_if_blank:nTF { #1 }
{
\footnotetext { #2 }
}
{
\iow_now:cn { @auxout }
{
\@multifootnote@add@to@mark@text@list { #1 } { #2 }
}
}
}
\NewDocumentCommand \@multifootnote@add@to@mark@text@list { m m }
{
\seq_gput_right:Nn \g__multifootnote_mark_internal_seq { { #1 } { #2 } }
}
% Second approach
\int_new:N \g__multifootnote_tag_footnotemark_counter_int
\NewDocumentCommand \multifootnotetagmanual { m }
{
\footnotemark
\@ifpackageloaded { hyperref }
{
\int_gdecr:N \g__multifootnote_tag_footnotemark_counter_int
\addtocounter { footnote } { -1 }
\refstepcounter { footnote }
\label { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } }
\cs_gset_eq:NN \@currentHref \Hy@footnote@currentHref
\label { multifootnote-tag-footnote- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } }
\clist_map_inline:nn { #1 }
{
% generate hypertargets for footnote marks so that they can jump correctly to the corresponding footnotes
\clist_if_exist:cF { multifootnote-tag-hypertarget- ##1 }
{ \clist_new:c { multifootnote-tag-hypertarget- ##1 } }
\clist_put_right:ce { multifootnote-tag-hypertarget- ##1 }
{ \exp_not:N \Hy@raisedlink { \exp_not:N \hypertarget { \exp_not:N \getrefbykeydefault{ multifootnote-tag-footnote- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } }{anchor}{Doc-Start} } {} } }
}
} {}
\clist_map_inline:nn { #1 }
{
% generate list of marks in the footnote
\bool_if:NTF \l__multifootnote_backref_bool
{
\cs_if_exist:cTF { multifootnote-tag-list- ##1 }
{
\tl_gput_right:ce { multifootnote-tag-list- ##1 } { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } \ref { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } }
}
{
\cs_gset:cpx { multifootnote-tag-list- ##1 } { \ref { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } }
}
}
{
\cs_if_exist:cTF { multifootnote-tag-list- ##1 }
{
\tl_gput_right:ce { multifootnote-tag-list- ##1 } { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } \thefootnote }
}
{
\cs_gset:cpx { multifootnote-tag-list- ##1 } { \thefootnote }
}
}
}
}
\NewCommandCopy \footnotetagmanual \multifootnotetagmanual
\NewDocumentCommand \multifootnotetagtextmanual { O{} m }
{
\group_begin:
\tl_if_blank:nTF { #1 }
{
\def \thefootnote { }
}
{
\def \thefootnote { \use:c { multifootnote-tag-list- #1 } }
}
\@ifpackageloaded { hyperref }
{
\xdef \Hy@footnote@currentHref { x\Hy@footnote@currentHref }
\footnotetext { \clist_use:cn { multifootnote-tag-hypertarget- #1 } {} \ignorespaces #2 }
}
{
\footnotetext { #2 }
}
\group_end:
}
\prop_new:N \g__multifootnote_tag_internal_prop
% \hook_gput_code:nnn { begindocument } { multifootnote/tag }
% { % declare the clists to be used
% \prop_map_inline:Nn \g__multifootnote_tag_internal_prop
% {
% % \clist_new:c { g__multifootnote_tag_ #1 _clist }
% \int_step_inline:nn { \int_eval:n { \g_multifootnote_total_page_int } }
% {
% \clist_new:c { g__multifootnote_tag_ #1 _page_ ##1 _clist }
% \clist_new:c { g__multifootnote_tag_page_ ##1 _recorded_clist }
% }
% }
% }
\NewDocumentCommand \multifootnotetag { m }
{
\footnotemark
\int_gdecr:N \g__multifootnote_tag_footnotemark_counter_int
\addtocounter { footnote } { -1 }
\refstepcounter { footnote }
\label { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } }
% add the current label number to the clist of the given tag on the current page
\clist_map_inline:nn { #1 }
{
\iow_now:ce { @auxout }
{
\@multifootnote@add@to@tag@label@list
{ ##1 }
{ \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } }
{ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } }
}
}
\@ifpackageloaded { hyperref }
{
\cs_gset_eq:NN \@currentHref \Hy@footnote@currentHref
\label { multifootnote-tag-footnote- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } }
} {}
\clist_map_inline:nn { #1 }
{
\clist_if_exist:cF { g__multifootnote_tag_page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _recorded_clist }
{
\clist_new:c { g__multifootnote_tag_page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _recorded_clist }
}
\clist_if_in:cnF { g__multifootnote_tag_page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _recorded_clist } { ##1 }
{
\clist_gput_right:cn { g__multifootnote_tag_page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _recorded_clist } { ##1 }
\group_begin:
% \clist_show:c { g__multifootnote_tag_ ##1 _page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _clist }
\clist_if_exist:cT { g__multifootnote_tag_ ##1 _page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _clist }
{ % skip the following code on the first run
\clist_clear:N \l__multifootnote_tmp_clist
\clist_map_inline:cn { g__multifootnote_tag_ ##1 _page_ \getpagerefnumber { multifootnote-tag-mark- \int_eval:n { \g__multifootnote_tag_footnotemark_counter_int } } _clist }
{
\clist_put_right:Nn \l__multifootnote_tmp_clist
{
% \tl_show:n { ####1 }
\ref { multifootnote-tag-mark- ####1 }
}
}
% \clist_show:N \l__multifootnote_tmp_clist
\def \thefootnote { \clist_use:Nn \l__multifootnote_tmp_clist { , \skip_horizontal:n { \l_multifootnote_space_after_comma_dim } } }
\footnotetext { \prop_item:Nn \g__multifootnote_tag_internal_prop { ##1 } }
}
\group_end:
}
}
}
\NewCommandCopy \footnotetag \multifootnotetag
\NewDocumentCommand \@multifootnote@add@to@tag@label@list { m m m }
% #1 = tag
% #2 = label number
% #3 = page number
{
\clist_if_exist:cF { g__multifootnote_tag_ #1 _page_ #3 _clist }
{
\clist_new:c { g__multifootnote_tag_ #1 _page_ #3 _clist }
}
\clist_gput_right:cn { g__multifootnote_tag_ #1 _page_ #3 _clist } { #2 }
% \clist_show:c { g__multifootnote_tag_ #1 _page_ #3 _clist }
}
\NewDocumentCommand \multifootnotetagtext { O{} m }
{
\tl_if_blank:nTF { #1 }
{
\footnotetext { #2 }
}
{
\iow_now:cn { @auxout }
{
\@multifootnote@add@to@tag@text@list { #1 } { #2 }
}
}
}
\NewDocumentCommand \@multifootnote@add@to@tag@text@list { m m }
{
\prop_gput:Nnn \g__multifootnote_tag_internal_prop { #1 } { #2 }
}
% The combined interface for producing footnote text
\NewDocumentCommand \multifootnotemanual { O{} m }
{
\str_if_in:nnTF { #1 } { , }
{
\multifootnotetextmanual [ #1 ] { #2 }
}
{
\multifootnotetagtextmanual [ #1 ] { #2 }
}
}
\NewDocumentCommand \multifootnote { O{} m }
{
\str_if_in:nnTF { #1 } { , }
{
\multifootnotetext [ #1 ] { #2 }
}
{
\multifootnotetagtext [ #1 ] { #2 }
}
}
\bool_if:NT \l__multifootnote_manual_mode_bool
{
\RenewCommandCopy \multifootnotemark \multifootnotemarkmanual
\RenewCommandCopy \multifootnotetext \multifootnotetextmanual
\RenewCommandCopy \multifootnotetag \multifootnotetagmanual
\RenewCommandCopy \multifootnotetagtext \multifootnotetagtextmanual
\RenewCommandCopy \multifootnote \multifootnotemanual
\RenewCommandCopy \footnotenumber \footnotenumbermanual
\RenewCommandCopy \footnotetag \footnotetagmanual
}
\endinput
%%
%% End of file `multifootnote.sty'.
答案1
是的,你需要担心。
这些消息意味着超链接将是错误的,例如指向错误的目标(如果有两个同名的目的地,则使用第一个)或转到文档的开头(如果目的地缺少 Doc-Start 作为后备)。
我无法调试你的所有代码,但这样的事情必然会带来问题:
\documentclass{article}
\usepackage{hyperref}
\begin{document}
[test]
\refstepcounter{footnote}\label{A}
[text text]
\addtocounter{footnote}{-1}
\refstepcounter{footnote}\label{B}
\end{document}
日志将会抱怨重复的目的地,如果你查看辅助文件,你会看到两个标签都指向同一个位置footnote.0
:
\newlabel{A}{{1}{1}{}{footnote.0}{}}
\newlabel{B}{{1}{1}{}{footnote.0}{}}
如果你重置了计数器,你就不能再使用\refstepcounter
它来重置它,而是必须自己处理引用和目标。例如
\documentclass{article}
\usepackage{hyperref}
\begin{document}
[test]
\refstepcounter{footnote}\label{A}
[text text]
\addtocounter{footnote}{-1}\stepcounter{footnote}
\MakeLinkTarget[multifootnote]{}%
\ExpandArgs{c}\def{@currentlabel}{\thefootnote}\label{B}
\end{document}
然后您将获得独特的目的地并且两个标签都可以起作用。
\newlabel{A}{{1}{1}{}{footnote.0}{}}
\newlabel{B}{{1}{1}{}{multifootnote*.1}{}}