summaryrefslogtreecommitdiff
path: root/macros/latex-dev/base/ltmarks.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex-dev/base/ltmarks.dtx')
-rw-r--r--macros/latex-dev/base/ltmarks.dtx159
1 files changed, 135 insertions, 24 deletions
diff --git a/macros/latex-dev/base/ltmarks.dtx b/macros/latex-dev/base/ltmarks.dtx
index dcfa2fcb27..a9f3bb0184 100644
--- a/macros/latex-dev/base/ltmarks.dtx
+++ b/macros/latex-dev/base/ltmarks.dtx
@@ -17,21 +17,12 @@
%<*driver>
% \fi
\ProvidesFile{ltmarks.dtx}
- [2024/02/11 v1.0e LaTeX Kernel (Marks)]
+ [2024/05/31 v1.0g LaTeX Kernel (Marks)]
% \iffalse
%
\documentclass{l3doc}
\GetFileInfo{ltmarks.dtx}
-%\usepackage{ltmarks}
-
-% Fixing footnotes in functions and variables: this should be in l3doc!
-
-\newcommand\fixfootnote[2]{\footnotemark
- \AddToHookNext{env/#1/after}{\footnotetext{#2}}}
-\AddToHook{env/function/begin}{\def\footnote{\fixfootnote{function}}}
-\AddToHook{env/variable/begin}{\def\footnote{\fixfootnote{variable}}}
-
\EnableCrossrefs
\CodelineIndex
\begin{document}
@@ -293,6 +284,11 @@
% The \meta{pos\textsubscript{\itshape i}} argument can be either
% \texttt{top}, \texttt{first}, or \texttt{last}.
%
+% Important to note is that the comparison is not with respect to
+% the textual content of the marks but whether or not they
+% originated from the same \cs{InsertMark} command (or the L3 layer
+% version \cs{mark_insert:nn}).
+%
% If you wish to compare marks across different regions or across
% different classes, you have to do it using the generic test only
% available in the L3 programming layer or do it manually, i.e.,
@@ -809,6 +805,32 @@
\tl_new:c { g_@@_last-column_top_ #1 _tl }
\tl_new:c { g_@@_last-column_first_ #1 _tl }
\tl_new:c { g_@@_last-column_last_ #1 _tl }
+% \end{macrocode}
+% All marks will have an identication at the beginning of the form
+% \cs{@@_id:n}\texttt\{\meta{number}\texttt\} and therefore the
+% initial empty values should have that too, so that data extraction
+% is going to be uniform.
+% \changes{v1.0g}{2024/05/31}{Initialize all marks with an id, use 0
+% when a new class is made (gh/1359)}
+% \begin{macrocode}
+ \tl_set:cn { g_@@_page_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_page_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_page_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-page_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-page_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-page_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_column_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_column_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_column_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-column_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-column_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_previous-column_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_first-column_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_first-column_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_first-column_last_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_last-column_top_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_last-column_first_ #1 _tl }{ \@@_id:n{0} }
+ \tl_set:cn { g_@@_last-column_last_ #1 _tl }{ \@@_id:n{0} }
}
% \end{macrocode}
% \end{macro}
@@ -1408,7 +1430,18 @@
% \begin{macrocode}
\@kernel@before@insertmark
\hook_use:n { insertmark }
- \unrestored@protected@xdef \g_@@_tmp_tl {#2}
+ \unrestored@protected@xdef \g_@@_tmp_tl
+ {
+% \end{macrocode}
+% To ensure that marks are unique we insert a hidden sequence
+% marker at the beginning of the content of the mark containing the
+% sequence number of the mark.
+% \changes{v1.0f}{2024/05/30}{Use sequence marker to make all marks
+% unique on nearby regions (gh/1359)}
+% \begin{macrocode}
+ \@@_id:n{ \int_use:N\g_@@_int }
+ #2
+ }
%<*trace>
\@@_debug:n{ \iow_term:x { Marks:~ set~#1~<-~
'\tl_to_str:V \g_@@_tmp_tl' ~ \msg_line_context: } }
@@ -1421,9 +1454,11 @@
% becomes empty, but not immediately; otherwise we just put
% \cs{g_@@_tmp_tl} in.
% \begin{macrocode}
- \tl_if_empty:NTF \g_@@_tmp_tl
- { \exp_not:n { \prg_do_nothing: } }
- { \exp_not:o { \g_@@_tmp_tl } }
+% this is no longer needed with 1.0f
+% \tl_if_empty:NTF \g_@@_tmp_tl
+% { \exp_not:n { \prg_do_nothing: } }
+% { \exp_not:o { \g_@@_tmp_tl } }
+ \exp_not:o { \g_@@_tmp_tl }
}
\group_end:
% \end{macrocode}
@@ -1445,15 +1480,43 @@
% \end{macro}
%
%
+% \begin{macro}{\@@_id:n}
+% A hidden marker is placed into every mark added by
+% \cs{mark_insert:nn}. It will will not show up in the output but
+% its argument (a counter value that is incremented) makes all
+% marks unique so the test for \enquote{equal} is not fooled by two
+% different marks having the same mark text.
+% \changes{v1.0f}{2024/05/30}{Use sequence marker to make all marks
+% unique on nearby regions (gh/1359)}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_id:n #1 { }
+% \end{macrocode}
+% \end{macro}
+%
+%
% \begin{macro}[int]{\@kernel@before@insertmark}
% \begin{macro}{insertmark}
% By default \cs{label}, \cs{index}, and \cs{glossary} do nothing
% when the mark is inserted.
% \begin{macrocode}
+\int_new:N \g_@@_int
\cs_new:Npn \@kernel@before@insertmark {
\cs_set_eq:NN \label \scan_stop:
\cs_set_eq:NN \index \scan_stop:
\cs_set_eq:NN \glossary \scan_stop:
+% \end{macrocode}
+% We count each mark and use that to place a hidden marker in front
+% of the mark text. To ensure that there is no overflow (very
+% unlikely but you never know) we restart every 100000 marks. Thus,
+% if somebody puts more than that number of marks on a single page
+% you could construct a scenario in which that approach fails.
+% \changes{v1.0f}{2024/05/30}{Use sequence marker to make all marks
+% unique on nearby regions (gh/1359)}
+% \begin{macrocode}
+ \int_compare:nNnTF \g_@@_int < {99999}
+ { \int_gincr:N \g_@@_int }
+ { \int_gzero:N \g_@@_int }
+
}
% \end{macrocode}
% The public hook to augment the setup.
@@ -1473,10 +1536,20 @@
%
% If used with an unknown class or region they generate an error
% (fairly low-level because we are in an expandable context).
+%
+% Each mark starts with an id and while the id does not print it is
+% nevertheless better to remove it when returning the mark, so that
+% downstream manipulation of the data doesn't have to deal with it.
+% \changes{v1.0g}{2024/05/31}{Remove the id when returning the mark value (gh/1359)}
% \begin{macrocode}
-\cs_new:Npn \mark_use_first:nn #1#2 { \exp_not:v { g_@@_#1_first_#2_tl } }
-\cs_new:Npn \mark_use_last:nn #1#2 { \exp_not:v { g_@@_#1_last_#2_tl } }
-\cs_new:Npn \mark_use_top:nn #1#2 { \exp_not:v { g_@@_#1_top_#2_tl } }
+\cs_new:Npn \mark_use_first:nn #1#2 { \@@_use:v { g_@@_#1_first_#2_tl } }
+\cs_new:Npn \mark_use_last:nn #1#2 { \@@_use:v { g_@@_#1_last_#2_tl } }
+\cs_new:Npn \mark_use_top:nn #1#2 { \@@_use:v { g_@@_#1_top_#2_tl } }
+% \end{macrocode}
+% This is what the \cs{use_none:nn} accomplishes.
+% \begin{macrocode}
+\cs_new:Npn \@@_use:n #1 { \exp_not:o { \use_none:nn #1 } }
+\cs_generate_variant:Nn \@@_use:n { v }
% \end{macrocode}
% \end{macro}
%
@@ -1854,6 +1927,12 @@
% \begin{macrocode}
\seq_map_inline:Nn \g_@@_classes_seq
{
+% \end{macrocode}
+% The \texttt{previous-page} updates need to come before the
+% updates for \texttt{page} region because otherwise the values
+% to copy are already overwritten.
+% necessary values.
+% \begin{macrocode}
\tl_gset_eq:cc { g_@@_previous-page_top_ ##1 _tl }
{ g_@@_page_top_ ##1 _tl }
\tl_gset_eq:cc { g_@@_previous-page_first_ ##1 _tl }
@@ -1861,16 +1940,48 @@
\tl_gset_eq:cc { g_@@_previous-page_last_ ##1 _tl }
{ g_@@_page_last_ ##1 _tl }
% \end{macrocode}
-% The \texttt{page} updates need to come after the corresponding
-% updates for \texttt{previous-page} otherwise we loose the
-% necessary value.
+% To update the \texttt{top} we only have to copy what is in
+% \texttt{first-column}:
% \begin{macrocode}
\tl_gset_eq:cc { g_@@_page_top_ ##1 _tl }
{ g_@@_first-column_top_ ##1 _tl }
- \tl_gset_eq:cc { g_@@_ page_first_ ##1 _tl }
- { g_@@_first-column_first_ ##1 _tl }
- \tl_gset_eq:cc { g_@@_page_last_ ##1 _tl }
- { g_@@_last-column_last_ ##1 _tl }
+
+% \end{macrocode}
+% Updating the \texttt{first} mark for the \texttt{page} region is
+% more complicated. We first have to find out of there is any mark
+% in the first column (this can be done by comparing the \texttt{top} and
+% the \texttt{first} mark of of that region).
+% \changes{v1.0f}{2024/05/30}{Correct logic for first mark in page
+% region if first column contains no marks (gh/1359)}
+% \begin{macrocode}
+ \tl_if_eq:ccTF { g__@@_first-column_top_ ##1 _tl }
+ { g__@@_first-column_first_ ##1 _tl }
+ {
+% \end{macrocode}
+% If there is no mark in the first column we copy the first mark of
+% the last column. If that doesn't contain a mark we still get the
+% right result because the first mark is then equal to the top mark.
+% \begin{macrocode}
+ \tl_gset_eq:cc { g_@@_page_first_ ##1 _tl }
+ { g_@@_last-column_first_ ##1 _tl }
+ }
+ {
+% \end{macrocode}
+% On the other hand, if there is a mark in the first column we copy
+% over the \texttt{first} mark from that column.
+% \begin{macrocode}
+ \tl_gset_eq:cc { g_@@_page_first_ ##1 _tl }
+ { g_@@_first-column_first_ ##1 _tl }
+ }
+% \end{macrocode}
+% The logic for the \texttt{last} page mark is again simple, we can
+% just copy the value in the \texttt{last} mark of the last column.
+% If that column doesn't contain any marks, then the value in
+% \texttt{last} will be automatically the same as the \texttt{last}
+% from the first column.
+% \begin{macrocode}
+ \tl_gset_eq:cc { g_@@_page_last_ ##1 _tl }
+ { g_@@_last-column_last_ ##1 _tl }
}
}
%<*trace>