diff options
author | Karl Berry <karl@freefriends.org> | 2023-09-03 20:12:19 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-09-03 20:12:19 +0000 |
commit | e4b80747d242b22d1bc0bba31c6bb1dd04745bbe (patch) | |
tree | 07f54ed039600e096423f07d04f1d759269c47aa /Master/texmf-dist | |
parent | 801622890e90b6fc84d2b628538accdbdfcad12b (diff) |
updatemarks (3sep23)
git-svn-id: svn://tug.org/texlive/trunk@68163 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
-rw-r--r-- | Master/texmf-dist/doc/latex/updatemarks/README.md | 13 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/updatemarks/updatemarks.pdf | bin | 0 -> 459124 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/updatemarks/updatemarks.tex | 322 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/updatemarks/updatemarks.sty | 503 |
4 files changed, 838 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/latex/updatemarks/README.md b/Master/texmf-dist/doc/latex/updatemarks/README.md new file mode 100644 index 00000000000..eb3a99d23cb --- /dev/null +++ b/Master/texmf-dist/doc/latex/updatemarks/README.md @@ -0,0 +1,13 @@ +# updatemarks +A LaTeX package is used to update marks in boxes. + +You can use `\usepackage[minipage,multicol,tcolorbox]{updatemarks}` in the preamble +of your document so that marks in these environments can be found by LaTeX. +You are able to use `\ExtractMarks` or `\ExtractSplitMarks` to save marks and +use `\UpdateMarks` to reinsert marks. Read the documentation for more details. + +# Copyright and License + +Copyright 2023 Wenjian Chern + +LICENSE: [LPPL 1.3c](http://www.latex-project.org/lppl.txt) diff --git a/Master/texmf-dist/doc/latex/updatemarks/updatemarks.pdf b/Master/texmf-dist/doc/latex/updatemarks/updatemarks.pdf Binary files differnew file mode 100644 index 00000000000..f6e45818968 --- /dev/null +++ b/Master/texmf-dist/doc/latex/updatemarks/updatemarks.pdf diff --git a/Master/texmf-dist/doc/latex/updatemarks/updatemarks.tex b/Master/texmf-dist/doc/latex/updatemarks/updatemarks.tex new file mode 100644 index 00000000000..2de3b6bded3 --- /dev/null +++ b/Master/texmf-dist/doc/latex/updatemarks/updatemarks.tex @@ -0,0 +1,322 @@ +\documentclass{l3doc} +\usepackage{updatemarks} +\usepackage[a4paper,top=2cm,bottom=2.5cm,left=5cm,right=2cm]{geometry} + +\title{Update marks in box\thanks{Issues: \url{https://github.com/Sophanatprime/updatemarks/issues}}} +\author{WenJian Chern\thanks{Email: longaster@163.com}} +\date{\today\qquad v0.2b} + +\begin{document} + +\maketitle + +\begin{abstract} +There are some cases where one may put title in box and still want its +\cs{markboth} working. This brings the \pkg{updatemarks} package. +The \pkg{updatemarks} package provides interface to extract marks where are in a +inner box and then can put the first and last marks back to outer. +It can automatically update marks where are in \env{minipage}, +\textit{boxed multicols} and \env{tcolorbox} environments. +\end{abstract} + + +\tableofcontents + + +\section{Usage of the package} + +You simply insert \verb|\usepackage{updatemarks}| or +\verb|\usepackage|\oarg{options}\verb|{updatemarks}| in the preamble of your document. + +There are three package options \texttt{minipage}, +\texttt{multicol}(an optional \texttt s) and +\texttt{tcolorbox}, which are used to enable the function of automatical updating marks +in \env{minipage}, \env{multicols} and +\env{tcolorbox} (both \env{tcolorbox} environment and \tn{tcbox} command), respectively. + +No automatical updatings are enable, by default. + +If your {\LaTeX} version is 2022-06-01 or newer, you can use +\cs{SetKeys}\texttt{[updatemarks]}\marg{options} to enable or disable +automatical updating locally. + +Such as, +\begin{verbatim} + \SetKeys[updatemarks]{minipage=false, tcolorbox=true, multicol} +\end{verbatim} +so marks in \env{minipage} would not update, +whereas \env{tcolorbox} and \env{multicols} do. + +The total empty mark will not be extracted and updated. +But \verb|\markboth{}{}| and \verb|\InsertMark{}| do will be extracted and updated, +because they are not total empty internally. + +However, the updating is not once for all. +For example, if you are using \env{minipage} in \tn{makebox}, even if you enable +the automatical updating, the marks still can not be found by \LaTeX. +But, if you put \env{minipage} in \env{tcolorbox} or the other way round, +\LaTeX\ still can get correct marks. + +The point is, updating marks is done inner to outer and level by level, +if any level is not updated, you will lost all marks in inner boxes. +Furthermore, whether marks are updated or not {\TeX} is only influenced by box level +instead of group level, so if you try to limit marks in a certain position, you should +use a box. + +The extracting and updating would not remove these marks, they still be there, you +can find them by your own method as well. + + +\section{\env{minipage}} + +You can enable automatically extracting and updating marks where are in \env{minipage} +to its nearest outer box level, +by using \texttt{minipage} package option or set \texttt{minipage} key to true. + +\pkg{updatemarks} patches the \tn{endminipage}, if you enable the function, +marks in any other environments that use \env{minipage} will be updated, +including \env{varwidth} of \pkg{varwidth} package, etc. + + +\section{\pkg{multicol} and \pkg{adjmulticol}} + +If \env{multicols} or \env{adjmulticols} or their starred versions are put in a box +--- so called \emph{boxed multicols}, you are able to eanble automatically extracting +and updating marks into the box (not outer of the box, because it only ). +If you need to update marks in this box, you have to do it manually. +Of cause, if the box is \env{minipage} or \env{tcolorbox} or another \env{multicols} +or any other supported environments or commands, then no more things to do. + +All \env{multicols} and \env{adjmulticols} and their starred versions share the +same option \texttt{multicol}(an optional \texttt s). + +For \emph{non boxed multicols}, i.e, not in any other box except +the main vertical list, the \tn{topmark} (and \tn{topmarks}) at first and last page +are not correct. Multiple contiguous forced break or \tn{clearpage} may cause the +wrong marks. + +If your {\LaTeX} version is 2022-06-01 or newer, +you can get more accurate mark values by using \cs{TopMark}, \cs{FirstMark} +and \cs{LastMark} in head and foot, but only the +\texttt{previous-page} region and \texttt{page} region are supported for now. +Still, Multiple contiguous forced break or \tn{clearpage} may cause the wrong marks. + + +\section{\pkg{tcolorbox}} + +The \pkg{updatemarks} package can also update marks in \env{tcolorbox} environments +(both breakable and unbreakable) and \tn{tcbox} commands. + +You are allowed to use \verb|updatemarks=true| or \verb|updatemarks| in \tn{tcbset} +or as environment and command option to enable the function, and +\verb|updatemarks=false| to disable. + + +\section{Set automatical updating list} + +\pkg{updatemarks} can automatically detect mark classes allocated by \tn{newmarks} +and \cs{NewMarkClass} in preamble. But if you allocate mark class after preamble +(which I strongly recommend you do not), +\pkg{updatemarks} also provides interfaces to enable you add these mark class to +automatical updating list. If you are not using these two commands, then nothing need +to be done. + + +\enlargethispage{20pt} + +\begin{function}{\AddToUpdateMarksList,\SetUpdateMarksList,\RemoveFromUpdateMarksList} + \begin{syntax} + \verb|\AddToUpdateMarksList| \marg{number list} + \verb|\SetUpdateMarksList| \marg{number list} + \verb|\RemoveFromUpdateMarksList| \marg{number list} + \end{syntax} +You can use these functions to globally add items to, set items, and remove items from +the list of mark classes which need to be automatically updated. + +The \meta{number} is the first argument of \tn{newmarks}, or literally, a number. +Specially, for those mark classes declared by \cs{NewMarkClass}, you are able to use +\oarg{class} or \cs{MarkClass}\marg{class}. Such as +\begin{verbatim} + \RemoveFromUpdateMarksList { [2e-right], 4, \MarkClass{my-class} } +\end{verbatim} +\end{function} + + +\begin{function}{\AddAllocatedToUpdateMarksList} + \begin{syntax} + \verb|\AddAllocatedToUpdateMarksList| + \end{syntax} +The function add all mark classes allocated by \tn{newmarks} and \cs{NewMarkClass} +to automatical updating list. +\end{function} + + +\section{Generic interfaces of extracting and updating} + +If you need to extract and update marks manually, \cs{ExtractMarks}, +\cs{ExtractSplitMarks} and \cs{UpdateMarks} will help you. + +\begin{function}{\ExtractMarks} + \begin{syntax} + \verb|\ExtractMarks| \marg{box number} + \verb|\ExtractMarks| \oarg{number list} \marg{box number} + \verb|\ExtractMarks| * \marg{text} + \verb|\ExtractMarks| * \oarg{number list} \marg{text} + \end{syntax} +Save first marks and last marks of specified mark classes +which are directly presented in \meta{box number} or \meta{text} +if these marks is not total empty. +Marks in deeper boxes will not be detected, unless they are moved out. + +If \meta{number list} is presented, the mark classes are these numbers, otherwise +they are the automatical updating list. + +The \meta{box number} is the first argument of \tn{newbox} or \tn{newsavebox}, etc., +and have saved contents by using \env{lrbox} or \tn{sbox} or similar. + +The \meta{text} is typeset material and \emph{will be executed}. + +If the \meta{box number} is a vbox and contains forced page break, then all marks after +the first forced page break will not be detected. +\end{function} + +\begin{function}{\ExtractSplitMarks} + \begin{syntax} + \verb|\ExtractSplitMarks| + \verb|\ExtractSplitMarks| \oarg{number list} + \end{syntax} +This command is used after a \tn{vsplit}, and save +first marks and last marks of specified mark classes which are directly +presented in being split part if these marks is not total empty. +Marks in deeper boxes will not be detected, unless they are moved out. + +If \meta{number list} is presented, the mark classes are these numbers, otherwise +they are the automatical updating list. +\end{function} + +\begin{function}{\UpdateMarks} + \begin{syntax} + \verb|\UpdateMarks| + \verb|\UpdateMarks| \oarg{number list} + \end{syntax} +Reinserting saved first marks and last marks of specified mark classes +(if have been saved) into the current box, +or if not in a box then the main vertical list. + +If \meta{number list} is presented, the mark classes are these numbers, otherwise +they are the automatical updating list. +\end{function} + + +\section{Disable patches or write your own patches} + +By default, \pkg{updatemarks} use its own patches to support \env{minipage}, +\env{multicols} and \env{tcolorbox}, however, you can write your own patches and +remove the patches will be done by \pkg{updatemarks}. + +To the patches for \env{minipage}, you can define \tn{updatemarks@minipage@patch} +before \pkg{updatemarks} is loaded, then \pkg{updatemarks} will use your patches. +Specially, if you set \tn{updatemarks@minipage@patch} to empty, then no patches will +be done for \cs{endminipage}. + +The patches for \pkg{multicol}, \pkg{adjmulticol} and \pkg{tcolorbox}, +are \tn{updatemarks@multicol@patch}, \tn{updatemarks@adjmulticol@patch}, +\tn{updatemarks@tcolorbox@patch} and \linebreak\tn{updatemarks@multicolnewmark@patch}, +\tn{updatemarks@adjmulticolnewmark@patch} for new mark mechanism, +you are able set them in preamble before or after \pkg{updatemarks} is loaded. + + +\section{Programming interfaces} + +This section describes the interfaces of \LaTeX3. + +\begin{function}{\updatemarks_extract:nN,\updatemarks_extract_split:N} + \begin{syntax} + \verb|\updatemarks_extract:nN| \marg{box material} \meta{seq var} + \verb|\updatemarks_extract_split:N| \meta{seq var} + \end{syntax} +These two functions have the same functions of +\cs{ExtractMarks} and \cs{ExtractSplitMarks}. + +\meta{box material} is content to build a box. +Such as unpacked box using \cs{hbox_unpack:N} or \cs{vbox_unpack:N} or text. + +\meta{seq var} is the number sequence of mark classes which are need to be extracted. + +They only save the marks whose positions are first or last. +\end{function} + +\begin{function}{\updatemarks_update:N} + \begin{syntax} + \verb|\updatemarks_update:N| \meta{seq var} + \end{syntax} +This function has the same function of \cs{UpdateMarks}. + +\meta{seq var} is the number sequence of mark classes which are need to be +reinserted into the current box or the main vertical list. + +It only reinserts marks whose positions are first or last. +\end{function} + +\begin{function}{\updatemarks_save:Nnn} + \begin{syntax} + \verb|\updatemarks_save:Nnn| \meta{seq var} \marg{position} \marg{value code} + \end{syntax} +Saving marks at \meta{position} of specified mark classes \meta{seq var}, +whose values are expanding \meta{value code} \emph{once}. +The \meta{value code} receives each item in the \meta{seq var} +as a trailing brace group. +\end{function} + +\begin{function}{\updatemarks_save_x:Nnn} + \begin{syntax} + \verb|\updatemarks_save_x:Nnn| \meta{seq var} \marg{position} \marg{value code} + \end{syntax} +Saving marks at \meta{position} of specified mark classes \meta{seq var}, +whose values are fully expanding \meta{value code}. +The \meta{value code} receives each item in the \meta{seq var} +as a trailing brace group. +\end{function} + +\begin{function}{\updatemarks_alias:Nnn} + \begin{syntax} + \verb|\updatemarks_alias:Nnn| \meta{seq var} \marg{alias position} \marg{source position} + \end{syntax} +Setting marks at \meta{alias position} are equal to \meta{source position} +of specified mark classes \meta{seq var}. +\end{function} + +\begin{function}{\updatemarks_remove:Nn} + \begin{syntax} + \verb|\updatemarks_remove:Nn| \meta{seq var} \marg{position} + \end{syntax} +Remove marks at \meta{position} of specified mark classes \meta{seq var}. +\end{function} + +\begin{function}[EXP]{\updatemarks_value:nn} + \begin{syntax} + \verb|\updatemarks_value:nn| \marg{position} \marg{mark class} + \end{syntax} +Return the value of \meta{mark class} at \meta{position}. +If it has not been saved, then return to total empty. + +\begin{texnote} + The result is returned within the \tn{unexpanded} primitive (\cs{exp_not:n}). +\end{texnote} +\end{function} + +\begin{function}{\g_updatemarks_max_int} +Readonly interger, its value is the maximum mark class number allocated. +\end{function} + +\begin{function}{\g_updatemarks_seq} +The number sequence which holds the mark classes needed to be automatical updated. +\end{function} + +\begin{function}{\g_updatemarks_classes_seq} +Readonly number sequence which holds the mark classes allocated by +\cs{NewMarkClass}. If \cs{NewMarkClass} is undefined, then it's empty. +\end{function} + + +\end{document}
\ No newline at end of file diff --git a/Master/texmf-dist/tex/latex/updatemarks/updatemarks.sty b/Master/texmf-dist/tex/latex/updatemarks/updatemarks.sty new file mode 100644 index 00000000000..ab5acb8aa3a --- /dev/null +++ b/Master/texmf-dist/tex/latex/updatemarks/updatemarks.sty @@ -0,0 +1,503 @@ +% updatemarks.sty +% Copyright 2023 Wenjian Chern. +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Wenjian Chern. +% +% This work consists of the files updatemarks.sty and updatemarks.tex +% +\NeedsTeXFormat{LaTeX2e} +\@ifundefined{ProvidesExplPackage}{\RequirePackage{expl3}}{} +\@ifundefined{NewDocumentCommand}{\RequirePackage{xparse}}{} +\ProvidesExplPackage{updatemarks}{2023/09/03}{0.2b}{extract and update marks from box} +\RequirePackage{etoolbox} + +\seq_new:N \g__updatemarks_seq +\box_new:N \l__updatemarks_r_box +\cs_new_eq:NN \l__updatemarks_s_box \l_tmpa_box % this box is used for locally split +\tex_countdef:D \g_updatemarks_max_int 256 \exp_stop_f: +\tl_new:N \l__updatemarks_tl + + +%% basicly copy from \__mark_update_structure:nn of LaTeX kernel +\cs_new_protected:Npn \__updatemarks_extract:nnn #1#2#3 % box, map of number, code + { + \group_begin: + \dim_set_eq:NN \tex_splitmaxdepth:D \c_max_dim + \int_set_eq:NN \tex_vbadness:D \c_max_int + \dim_set_eq:NN \tex_vfuzz:D \c_max_dim + \vbox_set_to_ht:Nnw \l__updatemarks_r_box { -.5 \c_max_dim } + #1 \tex_unskip:D + \box_set_to_last:N \l__updatemarks_r_box + \int_compare:nNnT { \tex_lastnodetype:D } < { 0 } + { + \box_if_vertical:NT \l__updatemarks_r_box + { + \vbox_set_to_ht:Nnn \l__updatemarks_r_box { -.5 \c_max_dim } + { \vbox_unpack:N \l__updatemarks_r_box \tex_kern:D \c_zero_dim } + \int_compare:nNnT { \tex_badness:D } > { 0 } + { \vbox_unpack:N \l__updatemarks_r_box } + } + } + \tex_kern:D \c_zero_dim + \vbox_set_end: + \int_compare:nNnTF { \tex_badness:D } > { 0 } + { + \vbox_set_split_to_ht:NNn \l__updatemarks_s_box \l__updatemarks_r_box \c_max_dim + \__updatemarks_extract_split:nn {#2} {#3} + } + { + \msg_error:nn { updatemarks } { infinite-shrinkage } + #2 + { + \cs_undefine:N \l_updatemarks_first_tl + \cs_undefine:N \l_updatemarks_last_tl + #3 + } + } + \group_end: + } +\cs_new_protected:Npn \__updatemarks_extract_split:nn #1#2 % map of number, code + { + #1 + { + \tl_set:No \l_updatemarks_last_tl { \tex_splitbotmarks:D ##1 } + \tl_if_empty:NTF \l_updatemarks_last_tl + { + \cs_undefine:N \l_updatemarks_first_tl + \cs_undefine:N \l_updatemarks_last_tl + } + { \tl_set:No \l_updatemarks_first_tl { \tex_splitfirstmarks:D ##1 } } + #2 + } + } +\cs_new_protected:Npn \__updatemarks_extract_num:n #1 % number + { + \tl_if_exist:NT \l_updatemarks_last_tl + { + \tl_if_exist:cF { g__updatemarks_first-#1_tl } + { \tl_gset_eq:cN { g__updatemarks_first-#1_tl } \l_updatemarks_first_tl } + \tl_gset_eq:cN { g__updatemarks_last-#1_tl } \l_updatemarks_last_tl + } + } +\cs_new_protected:Npn \updatemarks_extract:nN #1#2 % box material, seq + { + \__updatemarks_extract:nnn {#1} + { \seq_map_inline:Nn #2 } + { \__updatemarks_extract_num:n {##1} } + } +\cs_new_protected:Npn \updatemarks_extract_split:N #1 % seq + { + \__updatemarks_extract_split:nn + { \seq_map_inline:Nn #1 } + { \__updatemarks_extract_num:n {##1} } + } + + +\cs_new_protected:Npn \updatemarks_save:Nnn #1#2#3 % seq, pos, value + { + \seq_map_inline:Nn #1 + { \tl_gset:co { g__updatemarks_#2-##1_tl } { #3 {##1} } } + } +\cs_new_protected:Npn \updatemarks_save_x:Nnn #1#2#3 % seq, pos, value + { + \seq_map_inline:Nn #1 + { \tl_gset:cx { g__updatemarks_#2-##1_tl } { #3 {##1} } } + } +\cs_new_protected:Npn \updatemarks_alias:Nnn #1#2#3 % seq, pos1, pos2 + { + \seq_map_inline:Nn #1 + { \tl_gset_eq:cc { g__updatemarks_#2-##1_tl } { g__updatemarks_#3-##1_tl } } + } +\cs_new_protected:Npn \updatemarks_remove:Nn #1#2 % seq, pos + { \seq_map_inline:Nn #1 { \cs_undefine:c { g__updatemarks_#2-##1_tl } } } +\cs_new:Npn \updatemarks_value:nn #1#2 % pos, number + { + \tl_if_exist:cTF { g__updatemarks_#1- \int_eval:n {#2} _tl } + { \exp_not:v { g__updatemarks_#1- \int_eval:n {#2} _tl } } { } + } + + +\cs_new_protected:Npn \updatemarks_update:N #1 % seq + { + \seq_if_empty:NF #1 + { + \seq_map_inline:Nn #1 + { + \tl_if_exist:cT { g__updatemarks_last-##1_tl } + { + \tl_if_exist:cT { g__updatemarks_first-##1_tl } + { \tex_marks:D ##1 { \exp_not:v { g__updatemarks_first-##1_tl } } } + \tex_marks:D ##1 { \exp_not:v { g__updatemarks_last-##1_tl } } + } + \cs_undefine:c { g__updatemarks_first-##1_tl } + \cs_undefine:c { g__updatemarks_last-##1_tl } + } + \if@nobreak\ifvmode\nobreak\fi\fi + } + } +% do not check if it is <= \g_updatemarks_max_int +\cs_new_protected:Npn \__updatemarks_gput:Nn #1#2 + { + \group_begin: + \cs_set_eq:NN \MarkClass \__updatemarks_class_num:n + \cs_set_eq:NN \MaxClass \g_updatemarks_max_int + \clist_map_inline:nn {#2} + { \seq_gput_right:Nx #1 { \int_eval:n { \__updatemarks_maybe_class:n {##1} } } } + \seq_gremove_duplicates:N #1 + \group_end: + } + +\cs_new:Npn \__updatemarks_class_num:n #1 { \cs:w c__mark_class_ #1 _mark \cs_end: } +\cs_new:Npn \__updatemarks_maybe_class:n #1 + { + \tl_if_head_eq_meaning:nNTF {#1} [ % ] + { \__updatemarks_maybe_class_aux:w #1 } {#1} + } +\cs_new:Npn \__updatemarks_maybe_class_aux:w [#1] + { + \cs_if_exist_use:cF { c__mark_class_ #1 _mark } + { 0 \msg_expandable_error:nnn { updatemarks } { unknown-class } {#1} } + } + + + +\seq_new:N \g_updatemarks_seq +\NewDocumentCommand \ExtractMarks { s o +m } + { + \tl_if_novalue:nTF {#2} + { + \updatemarks_extract:nN + { + \bool_if:nTF {#1} { #3 } + { + \if_hbox:N #3 \hbox_unpack:N #3 \scan_stop: \fi: + \if_vbox:N #3 \vbox_unpack:N #3 \scan_stop: \fi: + } + } + \g_updatemarks_seq + } + { + \seq_gclear:N \g__updatemarks_seq + \__updatemarks_gput:Nn \g__updatemarks_seq {#2} + \updatemarks_extract:nN + { + \bool_if:nTF {#1} { #3 } + { + \if_hbox:N #3 \hbox_unpack:N #3 \scan_stop: \fi: + \if_vbox:N #3 \vbox_unpack:N #3 \scan_stop: \fi: + } + } + \g__updatemarks_seq + } + } +\NewDocumentCommand \ExtractSplitMarks { o } + { + \tl_if_novalue:nTF {#1} + { \updatemarks_extract_split:N \g_updatemarks_seq } + { + \seq_gclear:N \g__updatemarks_seq + \__updatemarks_gput:Nn \g__updatemarks_seq {#1} + \updatemarks_extract_split:N \g__updatemarks_seq + } + } +\NewDocumentCommand \UpdateMarks { o } + { + \tl_if_novalue:nTF {#1} + { \updatemarks_update:N \g_updatemarks_seq } + { + \seq_gclear:N \g__updatemarks_seq + \__updatemarks_gput:Nn \g__updatemarks_seq {#1} + \updatemarks_update:N \g__updatemarks_seq + } + } +\cs_new_protected:Npn \AddToUpdateMarksList + { \__updatemarks_gput:Nn \g_updatemarks_seq } +\cs_new_protected:Npn \SetUpdateMarksList + { + \seq_gclear:N \g_updatemarks_seq + \AddToUpdateMarksList + } +\cs_new_protected:Npn \RemoveFromUpdateMarksList #1 + { + \__updatemarks_gput:Nn \g__updatemarks_seq {#1} + % to support old expl3, do not use \seq_map_tokens:Nn + \seq_map_inline:Nn \g__updatemarks_seq + { \seq_gremove_all:Nn \g_updatemarks_seq {##1} } + } +\cs_new_protected:Npn \AddAllocatedToUpdateMarksList + { + \int_step_inline:nnn { 0 } { \g_updatemarks_max_int } + { \seq_gput_right:Nn \g_updatemarks_seq {##1} } + \seq_gremove_duplicates:N \g_updatemarks_seq + } + +\cs_new_protected:Npn \__updatemarks_get_all_classes: + { + \seq_map_inline:Nn \g__mark_classes_seq + { + \seq_gput_right:Nx \g_updatemarks_classes_seq + { \int_value:w \__updatemarks_class_num:n {##1} } + } + } +\seq_new:N \g_updatemarks_classes_seq +\cs_if_exist:NTF \g__mark_classes_seq + { + \hook_gput_code:nnn { begindocument/end } { updatemarks } + { + \__updatemarks_get_all_classes: + \AddAllocatedToUpdateMarksList + } + } + { + \AtBeginDocument + { + \int_step_inline:nnn { 0 } { \g_updatemarks_max_int } + { \seq_gput_right:Nn \g_updatemarks_seq {#1} } + } + } + +\msg_new:nnn { updatemarks } { unknown-class } { Unknown~mark~class~`#1'. } +\msg_new:nnn { updatemarks } { infinite-shrinkage } + { Infinite~shrinkage~found~when~extracting~marks. } + + +\cs_new_protected:Npn \savemarks@of #1 #2 #3 + { + \bool_if:cT { l__updatemarks_#1_bool } + { \updatemarks_save:Nnn \g_updatemarks_seq {#2} {#3} } + } +\cs_new_protected:Npn \removemarks@of #1 #2 + { + \bool_if:cT { l__updatemarks_#1_bool } + { \updatemarks_remove:Nn \g_updatemarks_seq {#2} } + } +\cs_new_protected:Npn \updatemarks@of #1 + { + \bool_if:cT { l__updatemarks_#1_bool } + { \updatemarks_update:N \g_updatemarks_seq } + } +\cs_new_protected:Npn \extractmarks@of #1 #2 + { + \bool_if:cT { l__updatemarks_#1_bool } + { \updatemarks_extract:nN { #2 } \g_updatemarks_seq } + } +\cs_new_protected:Npn \extractsplitmarks@of #1 + { + \bool_if:cT { l__updatemarks_#1_bool } + { \updatemarks_extract_split:N \g_updatemarks_seq } + } +% \let\updatemarks@@imakebox\@imakebox +% % savebox and makebox +% \cs_if_exist:NF \updatemarks@makebox@patch +% { +% \patchcmd \@imakebox { \hb@xt@ } { \extractmarks@of{makebox}\hb@xt@ } +% { } { \ERROR } +% \patchcmd \@imakebox { \@end@tempboxa } { \updatemarks@of{makebox}\@end@tempboxa } +% { } { \ERROR } +% } +\let\updatemarks@endminipage\endminipage +% minipage +\cs_if_exist_use:NF \updatemarks@minipage@patch + { + \patchcmd \endminipage + { \color@endgroup\egroup } + { \color@endgroup\egroup\extractmarks@of{minipage}{\unvcopy\@tempboxa} } + { } { \ERROR } + \apptocmd \endminipage { \updatemarks@of{minipage} } { } { \ERROR } + } +% tcolorbox +\providecommand \updatemarks@tcolorbox@patch + { + \tcbset{updatemarks/.is~choice, + updatemarks/true/.code=\bool_set_true:N \l__updatemarks_tcolorbox_bool, + updatemarks/false/.code=\bool_set_false:N \l__updatemarks_tcolorbox_bool, + updatemarks/.default=true} + \patchcmd \tcbox@inner@hbox { \tcbdimto } + { \extractmarks@of{tcolorbox}{\unhcopy\tcb@upperbox}\tcbdimto } + { } { \ERROR } + \let\endtcb@lrbox=\updatemarks@endminipage + \patchcmd \endtcb@lrbox + { \color@endgroup\egroup } + { \color@endgroup\egroup\extractmarks@of{tcolorbox}{\unvcopy\@tempboxa} } + { } { \ERROR } + \let\endtcb@savebox=\endtcb@lrbox + \patchcmd \tcb@drawing@env@end { \csname } + { \updatemarks@of{tcolorbox}\csname } { } { \ERROR } + % breakable library + \ifdefined \tcb@vsplit@upper + \apptocmd \tcb@vsplit@upper { \extractsplitmarks@of{tcolorbox} } { } { \ERROR } + \apptocmd \tcb@vsplit@lower { \extractsplitmarks@of{tcolorbox} } { } { \ERROR } + \patchcmd \tcb@split@start { \iftcb@final@box } + { \iftcb@final@box + \extractmarks@of{tcolorbox}{\unvcopy\tcb@upperbox\unvcopy\tcb@lowerbox} } + { } { \ERROR } + \patchcmd \tcb@split@start + { \tcb@comp@h@page\tcb@check@for@final@box\iftcb@final@box } + { \tcb@comp@h@page\tcb@check@for@final@box\iftcb@final@box + \extractmarks@of{tcolorbox}{\unvcopy\tcb@upperbox\unvcopy\tcb@lowerbox}} + { } { \ERROR } + \patchcmd \tcb@split@USL { \iftcb@final@box } + { \iftcb@final@box + \extractmarks@of{tcolorbox}{\unvcopy\tcb@totalupperbox + \iftcb@lowerspace\unvcopy\tcb@totallowerbox\fi } + } + { } { \ERROR } + \patchcmd \tcb@split@SL@displayed { \iftcb@final@box } + { \iftcb@final@box + \extractmarks@of{tcolorbox}{\unvcopy\tcb@totallowerbox} } + { } { \ERROR } + \patchcmd \tcb@split@L { \iftcb@final@box } + { \iftcb@final@box + \extractmarks@of{tcolorbox}{\unvcopy\tcb@totallowerbox} } + { } { \ERROR } + \fi + } +% multicol +\providecommand \updatemarks@multicol@patch + { + %% the patch is used to extract marks + \tl_set:No \set@keptmarks + { \set@keptmarks \extractsplitmarks@of{multicol} } + + %% the patch is used for boxmulticols + \patchcmd \endmulticols { \page@sofar } + { \updatemarks@of{multicol}\page@sofar } + { } { \ERROR } + + %% the patch is used for middle page to remove unnecessary extract + \patchcmd \multi@column@out { \let\topmark\kept@topmark } + { + \let\topmark\kept@topmark + \removemarks@of{multicol}{first} + \removemarks@of{multicol}{last} + } + { } { \ERROR } + + %% the patch is used for final page + \patchcmd \balance@columns@out { \page@sofar } + { \updatemarks@of{multicol}\page@sofar } + { } { \ERROR } + + %% these patches are used to update marks after forced break + \patchcmd \balance@columns@out { \unvbox\colbreak@box } + { \extractmarks@of{multicol}{\unvcopy\colbreak@box}\unvbox\colbreak@box } + { } { \ERROR } + \patchcmd \balance@columns@out { \unvbox\@cclv } + { \extractmarks@of{multicol}{\unvcopy\@cclv}\unvbox\@cclv } + { } { \ERROR } + \patchcmd \balance@columns { \get@keptmarks\mult@box } + { \if@boxedmulticols\get@keptmarks\mult@box\fi } + { } { } + + % patches of new mark mechanism + \updatemarks@multicolnewmark@patch + } +\providecommand \updatemarks@adjmulticol@patch + { + \patchcmd \adjmc@process@ne@column { \unvbox } + { \extractmarks@of{multicol}{\unvcopy\mult@box}\unvbox } + { } { \ERROR } + \updatemarks@adjmulticolnewmark@patch + } +\providecommand \updatemarks@paracol@patch + { + \updatemarks@paracolnewmark@patch + } + +\AtBeginDocument{ + \@ifpackageloaded{tcolorbox}{\updatemarks@tcolorbox@patch}{} + \@ifpackageloaded{multicol}{\updatemarks@multicol@patch}{} + \@ifpackageloaded{adjmulticol}{\updatemarks@adjmulticol@patch}{} + \@ifpackageloaded{paracol}{\updatemarks@paracol@patch}{} +} + + +\keys_define:nn { updatemarks } + { +% makebox .bool_set:N = \l__updatemarks_makebox_bool , + minipage .bool_set:N = \l__updatemarks_minipage_bool , + tcolorbox .bool_set:N = \l__updatemarks_tcolorbox_bool , + multicol .bool_set:N = \l__updatemarks_multicol_bool , + multicols .bool_set:N = \l__updatemarks_multicol_bool , + paracol .bool_set:N = \l__updatemarks_paracol_bool , + } + +\cs_if_exist:NTF \ProcessKeyOptions + { \ProcessKeyOptions [ updatemarks ] } + { + \RequirePackage{l3keys2e} + \ProcessKeysOptions { updatemarks } + } + +\cs_if_free:NT \mark_new_class:n + { + \providecommand \updatemarks@multicolnewmark@patch { } + \providecommand \updatemarks@adjmulticolnewmark@patch { } + \providecommand \updatemarks@paracolnewmark@patch { } + \endinput + } + +\tl_const:Nn \updatemarks@multicol@firstpage + { + \bool_if:NT \l__updatemarks_multicol_bool + { + \seq_map_inline:Nn \g_updatemarks_seq + { + \tl_set:Nx \l__updatemarks_tl { \updatemarks_value:nn { top } {#1} } + \tl_if_empty:NT \l__updatemarks_tl + { \tl_gset:co { g__updatemarks_top-#1_tl } { \tex_topmarks:D #1 } } + } + } + } +\tl_const:Nn \updatemarks@multicol@middlepage + { + \__mark_update_structure_alias:nn { previous-page } { page } + \seq_map_inline:Nn \g__mark_classes_seq + { + \tl_gset_eq:cc { g__mark_page_top_#1_tl } { g__mark_page_last_#1_tl } + + \tl_set:Nx \l__updatemarks_tl + { \updatemarks_value:nn { first } { \__updatemarks_class_num:n {#1} } } + \tl_if_empty:NTF \l__updatemarks_tl + { \tl_gset_eq:cc { g__mark_page_first_#1_tl } { g__mark_page_last_#1_tl } } + { \tl_gset_eq:cN { g__mark_page_first_#1_tl } \l__updatemarks_tl } + + \tl_set:Nx \l__updatemarks_tl + { \updatemarks_value:nn { last } { \__updatemarks_class_num:n {#1} } } + \tl_if_empty:NF \l__updatemarks_tl + { \tl_gset_eq:cN { g__mark_page_last_#1_tl } \l__updatemarks_tl } + } + \updatemarks_remove:Nn \g_updatemarks_seq { top } + \updatemarks_remove:Nn \g_updatemarks_seq { first } + \updatemarks_remove:Nn \g_updatemarks_seq { last } + } + +\providecommand \updatemarks@multicolnewmark@patch + { + \patchcmd \prep@keptmarks { \fi } + { \updatemarks@multicol@firstpage\fi } + { } { \ERROR } + \patchcmd \multi@column@out + { + \removemarks@of{multicol}{first} + \removemarks@of{multicol}{last} + } + { } + { } { \ERROR } + \patchcmd \multi@column@out { \@makecol } + { \@makecol\updatemarks@multicol@middlepage } + { } { \ERROR } + } + +\providecommand \updatemarks@adjmulticolnewmark@patch { } +\providecommand \updatemarks@paracolnewmark@patch { }
\ No newline at end of file |