diff options
author | Karl Berry <karl@freefriends.org> | 2023-09-13 20:40:56 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-09-13 20:40:56 +0000 |
commit | 99bdd2e42bf8c8ec861eb8b6a7708f63396c5d8e (patch) | |
tree | 31f555c33bcc0153b169a88c625085b6c39389ee /Master/texmf-dist/source/latex-dev | |
parent | 8f22ac5379816e4b6bdd9e5c9dc981b4223187b4 (diff) |
latex-dev (13sep23)
git-svn-id: svn://tug.org/texlive/trunk@68270 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex-dev')
15 files changed, 2300 insertions, 350 deletions
diff --git a/Master/texmf-dist/source/latex-dev/base/format.ins b/Master/texmf-dist/source/latex-dev/base/format.ins index 74cd78ff4a8..ba0965004d1 100644 --- a/Master/texmf-dist/source/latex-dev/base/format.ins +++ b/Master/texmf-dist/source/latex-dev/base/format.ins @@ -169,6 +169,7 @@ the system are in the document `cfgguide.tex'. \from{ltcmd.dtx}{2ekernel} % L3 layer module (used to be xparse) \from{lthooks.dtx}{2ekernel} % L3 layer module \from{ltcmdhooks.dtx}{2ekernel} % L3 layer module + \from{ltsockets.dtx}{2ekernel} % L3 layer module \from{ltalloc.dtx}{2ekernel} \from{ltcntrl.dtx}{2ekernel} \from{lterror.dtx}{2ekernel} @@ -191,6 +192,7 @@ the system are in the document `cfgguide.tex'. \from{lttextcomp.dtx}{2ekernel} \from{ltpageno.dtx}{2ekernel} \from{ltxref.dtx}{2ekernel} + \from{ltproperties.dtx}{2ekernel} \from{ltmiscen.dtx}{2ekernel} \from{ltmath.dtx}{2ekernel} \from{ltlists.dtx}{2ekernel} diff --git a/Master/texmf-dist/source/latex-dev/base/latexrelease.ins b/Master/texmf-dist/source/latex-dev/base/latexrelease.ins index 61315f8e078..93739630e3e 100644 --- a/Master/texmf-dist/source/latex-dev/base/latexrelease.ins +++ b/Master/texmf-dist/source/latex-dev/base/latexrelease.ins @@ -96,6 +96,7 @@ extension .ins) which are part of the distribution. \from{ltcmd.dtx} {latexrelease}% L3 layer module \from{lthooks.dtx} {latexrelease}% L3 layer module \from{ltcmdhooks.dtx} {latexrelease}% L3 layer module + \from{ltsockets.dtx} {latexrelease}% L3 layer module \from{ltalloc.dtx} {latexrelease}% empty \from{ltcntrl.dtx} {latexrelease}% empty \from{lterror.dtx} {latexrelease}% empty @@ -118,6 +119,7 @@ extension .ins) which are part of the distribution. \from{lttextcomp.dtx} {latexrelease}% \from{ltpageno.dtx} {latexrelease}% empty \from{ltxref.dtx} {latexrelease}% empty + \from{ltproperties.dtx}{latexrelease}% \from{ltmiscen.dtx} {latexrelease}% \from{ltmath.dtx} {latexrelease}% \from{ltlists.dtx} {latexrelease}% empty diff --git a/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx b/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx index d6322ff3ee8..dcb85a1ae8d 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltcmd.dtx @@ -34,8 +34,8 @@ %%% From File: ltcmd.dtx % % \begin{macrocode} -\def\ltcmdversion{v1.1e} -\def\ltcmddate{2023-05-26} +\def\ltcmdversion{v1.2a} +\def\ltcmddate{2023-08-19} % \end{macrocode} % %<*driver> @@ -59,6 +59,8 @@ % \section{Creating document commands} % % \changes{v1.0a}{2020/11/20}{Initial version derived from \texttt{xparse.dtx}} +% \changes{v1.2a}{2023/08/19}{Removed commands that should have remained +% only in \texttt{xparse.dtx}} % % Document commands should be created using the tools provided by this module: % \cs{NewDocumentCommand}, etc.\@, in almost all cases. This allows clean @@ -4263,116 +4265,6 @@ % \end{macro} % \end{macro} % -% \subsection{Access to the argument specification} -% -% \begin{macro}{\@@_get_arg_spec_error:N, \@@_get_arg_spec_error:n} -% \begin{macro}{\@@_get_arg_spec_error_aux:n} -% Provide an informative error when trying to get the argument -% specification of a non-\pkg{xparse} command or environment. -% \begin{macrocode} -\cs_new_protected:Npn \@@_get_arg_spec_error:N #1 - { - \bool_set_false:N \l_@@_environment_bool - \tl_set:Nn \l_@@_fn_tl {#1} - \@@_get_arg_spec_error_aux:n { \cs_if_exist:NTF #1 } - } -\cs_new_protected:Npn \@@_get_arg_spec_error:n #1 - { - \bool_set_true:N \l_@@_environment_bool - \str_set:Nx \l_@@_environment_str {#1} - \@@_get_arg_spec_error_aux:n - { \cs_if_exist:cTF { \l_@@_environment_str } } - } -\cs_new_protected:Npn \@@_get_arg_spec_error_aux:n #1 - { - #1 - { - \msg_error:nnx { cmd } { non-xparse } - { \@@_environment_or_command: } - } - { - \msg_error:nnx { cmd } { unknown } - { \@@_environment_or_command: } - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_get_arg_spec:NTF} -% If the command is not an \pkg{xparse} command, complain. If it is, -% its second \enquote{item} is the argument specification. -% \begin{macrocode} -\cs_new_protected:Npn \@@_get_arg_spec:NTF #1#2#3 - { - \__kernel_cmd_if_xparse:NTF #1 - { - \tl_set:Nx \ArgumentSpecification { \tl_item:Nn #1 { 2 } } - #2 - } - {#3} - } -% \end{macrocode} -% \end{macro} -% -% Rolling forward from 2020-10-01 is tricky because the entire |ltcmd| -% module is new, but the user-level commands have the same name, so only -% these will clash. To work around that, in |latexrelease| mode we will -% (temporarily) disable \cs{__kernel_chk_if_free_cs:N} for this final -% part of the code, then restore at the end. -% \begin{macrocode} -%<latexrelease>\cs_new_eq:NN \@@_chk_if_free_cs:N \__kernel_chk_if_free_cs:N -%<latexrelease>\cs_gset_eq:NN \__kernel_chk_if_free_cs:N \use_none:n -% \end{macrocode} -% -% \begin{variable}{\ArgumentSpecification} -% \begin{macrocode} -\tl_new:N \ArgumentSpecification -% \end{macrocode} -% \end{variable} -% -% \begin{macro}{\@@_get_arg_spec:N} -% \begin{macro}{\@@_get_arg_spec:n} -% Recovering the argument specification is now trivial. -% \begin{macrocode} -\cs_new_protected:Npn \@@_get_arg_spec:N #1 - { - \@@_get_arg_spec:NTF #1 { } - { \@@_get_arg_spec_error:N #1 } - } -\cs_new_protected:Npn \@@_get_arg_spec:n #1 - { - \exp_args:Nc \@@_get_arg_spec:NTF - { environment~ \tl_to_str:n {#1} } - { } - { \@@_get_arg_spec_error:n {#1} } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_show_arg_spec:N} -% \begin{macro}{\@@_show_arg_spec:n} -% Showing the argument specification simply means finding it and then -% calling the \cs{tl_show:N} function. -% \begin{macrocode} -\cs_new_protected:Npn \@@_show_arg_spec:N #1 - { - \@@_get_arg_spec:NTF #1 - { \tl_show:N \ArgumentSpecification } - { \@@_get_arg_spec_error:N #1 } - } -\cs_new_protected:Npn \@@_show_arg_spec:n #1 - { - \exp_args:Nc \@@_get_arg_spec:NTF - { environment~ \tl_to_str:n {#1} } - { \tl_show:N \ArgumentSpecification } - { \@@_get_arg_spec_error:n {#1} } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% % \subsection{Utilities} % % \begin{macro}{\@@_check_definable:nNT, \@@_check_definable_aux:nN} @@ -4817,12 +4709,6 @@ LaTeX~did~not~find~this~argument~and~will~insert~a~default~value~ for~further~processing. } -\msg_new:nnnn { cmd } { non-xparse } - { \str_uppercase:n #1~not~defined~using~xparse. } - { - You~have~asked~for~the~argument~specification~for~the~#1,~ - but~this~was~not~defined~using~xparse. - } \msg_new:nnnn { cmd } { arg-split } { Too~many~'#1'~separators~in~argument. } { @@ -4830,12 +4716,6 @@ at~each~occurrence~of~the~separator~'#1'~into~#2~parts.~ Too~many~separators~were~found. } -\msg_new:nnnn { cmd } { unknown } - { Unknown~document~#1. } - { - You~have~asked~for~the~argument~specification~for~the~#1,~ - but~it~is~not~defined. - } \msg_new:nnnn { cmd } { verbatim-nl } { Verbatim-like~#1~ended~by~end~of~line. } { @@ -5153,31 +5033,6 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\GetDocumentCommandArgSpec} -% \begin{macro}{\GetDocumentEnvironmentArgSpec} -% \begin{macro}{\ShowDocumentCommandArgSpec} -% \begin{macro}{\ShowDocumentEnvironmentArgSpec} -% More simple mappings, with a check that the argument is a single -% control sequence or active character. -% \begin{macrocode} -\cs_new_protected:Npn \GetDocumentCommandArgSpec #1 - { - \@@_check_definable:nNT {#1} \GetDocumentCommandArgSpec - { \@@_get_arg_spec:N #1 } - } -\cs_new_eq:NN \GetDocumentEnvironmentArgSpec \@@_get_arg_spec:n -\cs_new_protected:Npn \ShowDocumentCommandArgSpec #1 - { - \@@_check_definable:nNT {#1} \ShowDocumentCommandArgSpec - { \@@_show_arg_spec:N #1 } - } -\cs_new_eq:NN \ShowDocumentEnvironmentArgSpec \@@_show_arg_spec:n -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% % Finally as promised, restore \cs{__kernel_chk_if_free_cs:N}: % \begin{macrocode} %<latexrelease>\cs_gset_eq:NN \__kernel_chk_if_free_cs:N \@@_chk_if_free_cs:N diff --git a/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx b/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx index 27907af6798..6f885a2c6ce 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltcmdhooks.dtx @@ -14,8 +14,8 @@ % %%% From File: ltcmdhooks.dtx % -\def\ltcmdhooksversion{v1.0h} -\def\ltcmdhooksdate{2023/05/21} +\def\ltcmdhooksversion{v1.0i} +\def\ltcmdhooksdate{2023/06/16} % % % @@ -1641,10 +1641,10 @@ % \subsection{Messages} % % \begin{macrocode} -%<latexrelease>\IncludeInRelease{2021/11/15}{wrong-cmd-hook}% +%<latexrelease>\IncludeInRelease{2023/06/01}{wrong-cmd-hook}% %<latexrelease> {Standardise~generic~hook~names} %<latexrelease>\EndIncludeInRelease -%<latexrelease>\IncludeInRelease{2021/11/15}{wrong-cmd-hook}% +%<latexrelease>\IncludeInRelease{2021/06/01}{wrong-cmd-hook}% %<latexrelease> {Standardise~generic~hook~names} %<latexrelease>\msg_new:nnnn { hooks } { wrong-cmd-hook } %<latexrelease> { diff --git a/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx b/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx index e10a5416e58..ae183bfeb47 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx @@ -32,7 +32,7 @@ % % \begin{macrocode} \providecommand\ltfilehookversion{v1.0o} -\providecommand\ltfilehookdate{2023/04/02} +\providecommand\ltfilehookdate{2023/07/10} % \end{macrocode} % %<*driver> @@ -1043,7 +1043,6 @@ % % \begin{macrocode} %<@@=> -\ExplSyntaxOff % \end{macrocode} % % \subsection{Selecting a file (\cs{set@curr@file})} diff --git a/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx b/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx index 3bac7ea0b22..f079c2cf5b1 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{ltfiles.dtx} - [2023/05/17 v1.2t LaTeX Kernel (File Handling)] + [2023/06/17 v1.2u LaTeX Kernel (File Handling)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltfiles.dtx} @@ -1203,8 +1203,9 @@ % \changes{v1.2d}{2019/10/26}{quote on openin} % \changes{v1.2k}{2021/03/12}{Allow unbalanced conditionals (gh/530)} % \changes{v1.2t}{2023/05/15}{Use \pkg{expl3} file existence test} -% \begin{macro}{\IfFileExists@} +% \begin{macro}{\IfFileExists@@} % \changes{v1.2t}{2023/05/15}{Macro added} +% \changes{v1.2u}{2023/06/16}{Support piped input} % Argument |#1| is |\@curr@file| so catcode 12 string with no quotes. % % The original definition picked up arguments |#2| and |#3| in a @@ -1212,7 +1213,7 @@ % implementation would have been not to pick up the arguments at % all but instead use the usual \cs{@firstoftwo} and % \cs{secondoftwo}. However, that changes how |#| is interpreted -% and so we can't do that nowaways without invalidating a lot of +% and so we can't do that nowadays without invalidating a lot of % code. Therefore the somewhat curious construction near the end. % % Earlier versions used |\openin| here, but this led to two @@ -1224,7 +1225,7 @@ % \begin{macrocode} %</2ekernel> %<*2ekernel|latexrelease> -%<latexrelease>\IncludeInRelease{2023/05/01}% +%<latexrelease>\IncludeInRelease{2023/06/01}% %<latexrelease> {\IfFileExists@}{IfFileExists} \long\def \IfFileExists@#1#2#3{% \edef\@filef@und{\IfFileExists@@{#1}}% @@ -1251,8 +1252,23 @@ \expandafter\def\expandafter\reserved@a \expandafter{\reserved@a{#2}{#3}}% \reserved@a} +% \end{macrocode} +% Pipes are not really files, but at the document level they are supported. +% To quickly trim of any leading spaces, we use a blank test and \cs{use:n} +% rather than \cs{tl_trim_spaces:n} for speed as we don't care about the end +% of the input. +% \begin{macrocode} \ExplSyntaxOn -\cs_new_eq:NN \IfFileExists@@ \file_full_name:n +\cs_new:Npn \IfFileExists@@ #1 + { + \tl_if_blank:nF {#1} + { + \tl_if_head_eq_charcode:oNTF { \use:n #1 } | + {#1} + { \file_full_name:n {#1} } + } + } +\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNTF { o } \ExplSyntaxOff %</2ekernel|latexrelease> %<latexrelease>\EndIncludeInRelease diff --git a/Master/texmf-dist/source/latex-dev/base/lthooks.dtx b/Master/texmf-dist/source/latex-dev/base/lthooks.dtx index 3807d25c44b..e43fa4ef351 100644 --- a/Master/texmf-dist/source/latex-dev/base/lthooks.dtx +++ b/Master/texmf-dist/source/latex-dev/base/lthooks.dtx @@ -31,8 +31,8 @@ %%% From File: lthooks.dtx % % \begin{macrocode} -\def\lthooksversion{v1.1e} -\def\lthooksdate{2023/06/06} +\def\lthooksversion{v1.1f} +\def\lthooksdate{2023/08/11} % \end{macrocode} % %<*driver> @@ -298,10 +298,6 @@ % consumed and any further attempt to add to it will result in % executing the code to be added immediately. % -% The \meta{hook} \emph{cannot} be specified using the dot-syntax. -% A leading |.| is treated literally. See -% section~\ref{sec:default-label} for details. -% % Using \cs{UseOneTimeHook} several times with the same % \Arg{hook} means that it only executes the first time it is used. % For example, if it is used in a command that can be called several times @@ -311,6 +307,11 @@ % Mixing \cs{UseHook} and \cs{UseOneTimeHook} for the same % \Arg{hook} should be avoided, but if this is done then neither will execute % after the first \cs{UseOneTimeHook}. +% +% The \meta{hook} \emph{cannot} be specified using the dot-syntax. +% A leading |.| is treated literally. See +% section~\ref{sec:default-label} for details. +% % \end{function} % % \begin{function}{\UseOneTimeHookWithArguments} @@ -327,6 +328,11 @@ % longer possible to use \cs{AddToHookWithArguments} or similar with % that hook. \cs{AddToHook} continues to work as normal. % Section~\ref{sec:hook-args} explains hooks with arguments. +% +% The \meta{hook} \emph{cannot} be specified using the dot-syntax. +% A leading |.| is treated literally. See +% section~\ref{sec:default-label} for details. +% % \end{function} % % @@ -607,7 +613,10 @@ % \meta{hook} arguments, both in the \LaTeXe{} interface, and the \LaTeX3 % interface described in section~\ref{sec:l3hook-interface}. % -% Note, however, that the replacement of |.| by the \meta{default label} +% Note,\marginpar{\raggedleft\rightskip5pt\itshape \textbf{Important:}\break The dot-syntax +% is \textbf{not} available with +% \cs{UseHook} and some other commands that are typically used within code!} +% however, that the replacement of |.| by the \meta{default label} % takes place when the hook command is executed, so actions that are % somehow executed after the package ends will have the wrong % \meta{default label} if the dot-syntax is used. For that reason, @@ -1997,8 +2006,9 @@ % % \item[\hook{begindocument}] % -% This hook is added to when using \cs{AtBeginDocument} and it is -% executed after the \texttt{.aux} file as be read in and most +% This hook is added to by using \cs{AddToHook}\texttt{\{begindocument\}} +% or by using \cs{AtBeginDocument} and it is +% executed after the \texttt{.aux} file has been read and most % initialization are done, so they can be altered and inspected by % the hook code. It is followed by a small number of further % initializations that shouldn't be altered and are therefore @@ -3534,7 +3544,7 @@ % \changes{v1.1a}{2023/04/06} % {Add \cs{hook_gput_code_with_args:nnn} (hook-args).} % \begin{macrocode} -%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_gput_code_with_args:nnn} +%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_gput_code:nnn} %<latexrelease> {Hooks~with~args} \cs_new_protected:Npn \hook_gput_code:nnn #1 #2 #3 { @@ -4386,7 +4396,7 @@ % \end{macrocode} % % \begin{macrocode} -%<latexrelease>\IncludeInRelease{2023/06/01}{\hook_gremove_code:nn} +%<latexrelease>\IncludeInRelease{2020/10/01}{\hook_gremove_code:nn} %<latexrelease> {Hooks~with~args} %<latexrelease>\cs_new_protected:Npn \@@_gremove_code:nn #1 #2 %<latexrelease> { @@ -5287,6 +5297,10 @@ %<latexrelease> \cs_gset_eq:NN \hook_use:n \@@_use_initialized:n %<latexrelease> \cs_gset_eq:NN \@@_preamble_hook:n \use_none:n %<latexrelease> } +%<@@=> +%<latexrelease>\cs_gset_eq:NN \@expl@@@initialize@all@@ +%<latexrelease> \__hook_initialize_all: +%<@@=hook> %<latexrelease>\EndIncludeInRelease % \end{macrocode} % \end{macro} @@ -7365,7 +7379,7 @@ \NewDocumentCommand \NewMirroredHookPairWithArguments { mmm } { \hook_new_pair_with_args:nnn {#1} {#2} {#3} } %<latexrelease>\EndIncludeInRelease -%<latexrelease>\IncludeInRelease{2023/06/01}{\NewHookWithArguments} +%<latexrelease>\IncludeInRelease{2020/10/01}{\NewHookWithArguments} %<latexrelease> {Hooks~with~args} %<latexrelease>\cs_new_protected:Npn \NewHookWithArguments #1 #2 { } %<latexrelease>\cs_new_protected:Npn \NewReversedHookWithArguments #1 #2 { } diff --git a/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx b/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx index 135cb630096..6d274ed5c33 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx @@ -28,7 +28,7 @@ \ProvidesFile{ltluatex.dtx} %</driver> %<*tex> -[2023/01/19 v1.2b +[2023/08/03 v1.2c %</tex> %<plain> LuaTeX support for plain TeX (core) %<*tex> @@ -1284,6 +1284,7 @@ luatexbase.new_chunkname = new_chunkname % % \begin{macro}{new_luafunction} % \changes{v1.1i}{2018/10/21}{Function added} +% \changes{v1.2c}{2023/07/02}{Ensure existing table entries not overwritten gh/1100} % Much the same as for attribute allocation in Lua. % The optional \meta{name} argument is used in the log if given. % \begin{macrocode} @@ -1291,7 +1292,11 @@ local luafunction_count_name = luafunction_count_name or "e@alloc@luafunction@count" local function new_luafunction(name) tex_setcount("global", luafunction_count_name, - tex_count[luafunction_count_name] + 1) + math.max( + #(lua.get_functions_table()), + tex_count[luafunction_count_name]) + + 1) + lua.get_functions_table()[tex_count[luafunction_count_name]] = false if tex_count[luafunction_count_name] > 65534 then luatexbase_error("No room for a new luafunction register") end @@ -2147,12 +2152,13 @@ luatexbase.uninstall = uninstall % \begin{macro}{mlist_to_hlist} % \changes{v1.1l}{2020/02/02}{|pre/post_mlist_to_hlist| added} % \changes{v1.1y}{2022/08/13}{Use shared\_callback system for pre/post/mlist_to_hlist} +% \changes{v1.2c}{2023/08/03}{Fix callback type of post_mlist_to_hlist_callback} % To emulate these callbacks, the ``real'' |mlist_to_hlist| is replaced by a % wrapper calling the wrappers before and after. % \begin{macrocode} create_callback('pre_mlist_to_hlist_filter', 'list') create_callback('mlist_to_hlist', 'exclusive', node.mlist_to_hlist) -create_callback('post_mlist_to_hlist_filter', 'list') +create_callback('post_mlist_to_hlist_filter', 'reverselist') function shared_callbacks.mlist_to_hlist.handler(head, display_type, need_penalties) local current = call_callback("pre_mlist_to_hlist_filter", head, display_type, need_penalties) if current == false then diff --git a/Master/texmf-dist/source/latex-dev/base/ltmiscen.dtx b/Master/texmf-dist/source/latex-dev/base/ltmiscen.dtx index 801d1e68627..74a9685f1fb 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltmiscen.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltmiscen.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{ltmiscen.dtx} - [2022/11/06 v1.2a LaTeX Kernel (Misc. Environments)] + [2023/09/13 v1.2c LaTeX Kernel (Misc. Environments)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltmiscen.dtx} @@ -194,8 +194,8 @@ % \begin{macrocode} %</2ekernel> %<*2ekernel|latexrelease> -%<latexrelease>\IncludeInRelease{2020/10/01}% -%<latexrelease> {\enddocument}{Use Hooks}% +%<latexrelease>\IncludeInRelease{2023/11/01}% +%<latexrelease> {\enddocument}{check property labels}% \def\enddocument{% % \end{macrocode} % The |\end{document}| hook is executed first. If necessary it can @@ -230,6 +230,10 @@ \let\@setckpt\@gobbletwo \let\@newl@bel\@testdef % \end{macrocode} +% \changes{v1.2b}{2023/09/06}{Test changes of values in \cs{new@label@record}} +% \begin{macrocode} + \let\new@label@record\@kernel@new@label@record@testdef +% \end{macrocode} % \changes{v1.0z}{1995/07/13}{Shorten redefinition of \cs{bibcite} and % \cs{newlabel}} % The previous line is equiv to setting @@ -357,6 +361,67 @@ % \begin{macrocode} %</2ekernel|latexrelease> %<latexrelease>\EndIncludeInRelease +%<latexrelease>\IncludeInRelease{2020/10/01}% +%<latexrelease> {\enddocument}{Use Hooks}% +%<latexrelease>\def\enddocument{% +%<latexrelease> \@kernel@before@enddocument +%<latexrelease> \UseOneTimeHook{enddocument}% +%<latexrelease> \@kernel@after@enddocument +%<latexrelease> \@checkend{document}% +%<latexrelease> \clearpage +%<latexrelease> \UseOneTimeHook{enddocument/afterlastpage}% +%<latexrelease> \@kernel@after@enddocument@afterlastpage +%<latexrelease> \begingroup +%<latexrelease> \if@filesw +%<latexrelease> \immediate\closeout\@mainaux +%<latexrelease> \let\@setckpt\@gobbletwo +%<latexrelease> \let\@newl@bel\@testdef +%<latexrelease> \@tempswafalse +%<latexrelease> \makeatletter \@@input\jobname.aux +%<latexrelease> \fi +%<latexrelease> \UseOneTimeHook{enddocument/afteraux}% +%<latexrelease> \UseOneTimeHook{enddocument/info}% +%<latexrelease> \endgroup +%<latexrelease> \UseOneTimeHook{enddocument/end}% +%<latexrelease> \deadcycles\z@\@@end} +%<latexrelease>\NewHook{enddocument} +%<latexrelease>\NewHook{enddocument/afterlastpage} +%<latexrelease>\NewHook{enddocument/afteraux} +%<latexrelease>\NewHook{enddocument/info} +%<latexrelease>\NewHook{enddocument/end} +%<latexrelease>\AddToHook{enddocument/info}[kernel/filelist]{\@dofilelist} +%<latexrelease>\AddToHook{enddocument/info}[kernel/warnings]{\@enddocument@kernel@warnings} +%<latexrelease>\AddToHook{enddocument/info}[kernel/release]{% +%<latexrelease> \let\show@release@info\wlog +%<latexrelease> \show@release@info{ ***********}% +%<latexrelease> \the\LaTeXReleaseInfo +%<latexrelease> \show@release@info{ ***********}} +%<latexrelease> +%<latexrelease>\DeclareHookRule{enddocument/info}{kernel/release}{before}{kernel/filelist} +%<latexrelease>\DeclareHookRule{enddocument/info}{kernel/filelist}{before}{kernel/warnings} +%<latexrelease>\def\@enddocument@kernel@warnings{% +%<latexrelease> \ifdim \font@submax >\fontsubfuzz\relax +%<latexrelease> \@font@warning{Size substitutions with differences\MessageBreak +%<latexrelease> up to \font@submax\space have occurred.\@gobbletwo}% +%<latexrelease> \fi +%<latexrelease> \@defaultsubs +%<latexrelease> \@refundefined +%<latexrelease> \if@filesw +%<latexrelease> \ifx \@multiplelabels \relax +%<latexrelease> \if@tempswa +%<latexrelease> \@latex@warning@no@line{Label(s) may have changed. +%<latexrelease> Rerun to get cross-references right}% +%<latexrelease> \fi +%<latexrelease> \else +%<latexrelease> \@multiplelabels +%<latexrelease> \fi +%<latexrelease> \ifx \@extra@page@added \relax +%<latexrelease> \@latex@warning@no@line{Temporary extra page added at the end. +%<latexrelease> Rerun to get it removed}% +%<latexrelease> \fi +%<latexrelease> \fi +%<latexrelease>} +%<latexrelease>\EndIncludeInRelease %<latexrelease>\IncludeInRelease{0000/00/00}% %<latexrelease> {\enddocument}{Use Hooks}% %<latexrelease> @@ -496,8 +561,7 @@ \protected\def\protected@file@percent{} % \end{macrocode} % \end{macro} - - +% % \begin{macro}{\add@percent@to@temptokena} % Helper function which is used to inspect a sequence of tokens % (the second argument of \cs{@writefile} and it the last token is @@ -1189,11 +1253,33 @@ % print as the \TeX{}book's space character instead of as blank spaces. % % \begin{macro}{\@vobeyspaces} +% \changes{v1.2b}{2023/06/15}{Support tabs} +% \begin{macro}{\@vobeytabs} +% \changes{v1.2b}{2023/06/14}{Macro added} +% \changes{v1.2c}{2023/09/01}{Provide global definition for active tab} % \begin{macrocode} +%</2ekernel> +%<latexrelease>\IncludeInRelease{2023/11/01}% +%<latexrelease> {\@vobeytabs}{Obeyed tabs}% +%<*2ekernel|latexrelease> {\catcode`\ =\active% -\gdef\@vobeyspaces{\catcode`\ \active\let \@xobeysp}} +\gdef\@vobeyspaces{\catcode`\ \active\let \@xobeysp\@vobeytabs}} +{\catcode`\^^I=\active +\gdef\@vobeytabs{\catcode`\^^I\active\let^^I\@xobeytab}% +\global\let^^I=\space +} +%</2ekernel|latexrelease> +%<latexrelease>\EndIncludeInRelease +%<latexrelease>\IncludeInRelease{0000/00/00}% +%<latexrelease> {\@vobeytabs}{Obeyed tabs}% +%<latexrelease>{\catcode`\ =\active% +%<latexrelease>\gdef\@vobeyspaces{\catcode`\ \active\let \@xobeysp}} +%<latexrelease>\let\@vobeytabs\@undefined +%<latexrelease>\EndIncludeInRelease +%<*2ekernel> % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}{\@xobeysp} % \changes{v1.0z}{1995/07/13}{Use \cs{nobreak}} @@ -1368,44 +1454,8 @@ % \end{macro} % % - -% \begin{macro}{\@setupverbvisiblespace} -% -% In pdf\TeX{} a catcode 12 space will produce the character in -% slot 32 which is assumed to be a visible space character (in a -% typewriter font in OT1 or T1 encoding). In Xe\TeX{} or Lua\TeX{} a -% font in TU encoding is normally used and that has a real space in -% this slot. So what we do in this case is this: we check the -% definition of -% |\verbvisiblespace| and if it is |\asciispace| we assume that the -% char32 can be used (e.g., in pdf\TeX{}). We then redefine -% |\@xobeysp| so that after running |\@vobeyspaces| we get -% characters from slot 32 for each active space. -% -% \changes{v1.1o}{2018/10/11} -% {Provide visible space in \cs{verb*} also for XeTeX and LuaTeX (github/69)} -% \begin{macrocode} -\def\@setupverbvisiblespace{% - \ifx\verbvisiblespace\asciispace - \let\@xobeysp\asciispace - \else -% \end{macrocode} Otherwise we measure the width of a character in -% the mon-spaced current font and place a -% |\verbvisiblespace| into a box of the right width which we are then -% using as the character for a space. By default this will be the space -% character from OT1 cmtt but by changing -% |\verbvisiblespace| one could use, for example, the |\textvisiblespace| -% of the current typewriter font. -% \begin{macrocode} - \setbox\z@\hbox{x}% - \setbox\@verbvisiblespacebox\hbox to\wd\z@{\hss\verbvisiblespace\hss}% - \def\@xobeysp{\leavevmode\copy\@verbvisiblespacebox}% - \fi -} -% \end{macrocode} -% \end{macro} +% ^^A \@setupverbvisiblespace was here % - % \begin{macro}{\@verbvisiblespacebox} % The box to hold the visible space character if it isn't in slot % 32 in the current typewriter font. @@ -1426,6 +1476,8 @@ % check if space is already active---it shouldn't be. % \changes{v1.1o}{2018/10/11} % {Provide visible space in \cs{verb*} also for XeTeX and LuaTeX (github/69)} +% \changes{v1.2b}{2023/06/14} +% {Support visible tabs in \cs{verb*}} % \begin{macrocode} \@namedef{verbatim*}{\@verbatim \@setupverbvisiblespace @@ -1434,8 +1486,6 @@ % \end{macrocode} % \end{environment} % -% -% % \begin{macrocode} %</2ekernel|latexrelease> %<latexrelease>\EndIncludeInRelease @@ -1452,7 +1502,88 @@ %<*2ekernel> % \end{macrocode} % +% \begin{macro}{\@setupverbvisiblespace} % +% In pdf\TeX{} a catcode 12 space will produce the character in +% slot 32 which is assumed to be a visible space character (in a +% typewriter font in OT1 or T1 encoding). In Xe\TeX{} or Lua\TeX{} a +% font in TU encoding is normally used and that has a real space in +% this slot. So what we do in this case is this: we check the +% definition of +% |\verbvisiblespace| and if it is |\asciispace| we assume that the +% char32 can be used (e.g., in pdf\TeX{}). We then redefine +% |\@xobeysp| so that after running |\@vobeyspaces| we get +% characters from slot 32 for each active space. +% +% \changes{v1.1o}{2018/10/11} +% {Provide visible space in \cs{verb*} also for XeTeX and LuaTeX (github/69)} +% \changes{v1.2b}{2023/06/15} +% {Support visible tabs} +% \begin{macrocode} +%</2ekernel> +%<*2ekernel|latexrelease> +%<latexrelease>\IncludeInRelease{2023/11/01}% +%<latexrelease> {\@setupverbvisiblespace}{Setup visible tab for \verb}% +\def\@setupverbvisiblespace{% + \ifx\verbvisiblespace\asciispace + \let\@xobeysp\asciispace + \else +% \end{macrocode} +% Otherwise we measure the width of a character in +% the mono-spaced current font and place a +% |\verbvisiblespace| into a box of the right width which we are then +% using as the character for a space. By default this will be the space +% character from OT1 cmtt but by changing +% |\verbvisiblespace| one could use, for example, the |\textvisiblespace| +% of the current typewriter font. +% \begin{macrocode} + \setbox\z@\hbox{x}% + \setbox\@verbvisiblespacebox\hbox to\wd\z@{\hss\verbvisiblespace\hss}% + \def\@xobeysp{\leavevmode\copy\@verbvisiblespacebox}% + \fi + \@setupverbvisibletab +} +%</2ekernel|latexrelease> +%<latexrelease>\EndIncludeInRelease +%<latexrelease>\IncludeInRelease{2018/12/01}% +%<latexrelease> {\@setupverbvisiblespace}{Setup visible space for \verb}% +%<latexrelease>\def\@setupverbvisiblespace{% +%<latexrelease> \ifx\verbvisiblespace\asciispace +%<latexrelease> \let\@xobeysp\asciispace +%<latexrelease> \else +%<latexrelease> \setbox\z@\hbox{x}% +%<latexrelease> \setbox\@verbvisiblespacebox\hbox to\wd\z@{\hss\verbvisiblespace\hss}% +%<latexrelease> \def\@xobeysp{\leavevmode\copy\@verbvisiblespacebox}% +%<latexrelease> \fi +%<latexrelease>} +%<latexrelease>\EndIncludeInRelease +%<latexrelease>\IncludeInRelease{0000/00/00}% +%<latexrelease> {\@setupverbvisiblespace}{Setup visible space for \verb}% +%<latexrelease>\let\@setupverbvisiblespace\@undefined +%<latexrelease>\EndIncludeInRelease +%<*2ekernel> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@setupverbvisibletab} +% \changes{v1.2q}{2023/06/15} +% {Provide visible tab in \cs{verb*}} +% A redirection: just a simple wrapper. +% \begin{macrocode} +%</2ekernel> +%<latexrelease>\IncludeInRelease{2023/11/01}% +%<latexrelease> {\@setupverbvisibletab}{Setup visible tab for \verb}% +%<*2ekernel|latexrelease> +\def\@setupverbvisibletab{\let\@xobeytab\@xobeysp} +%</2ekernel|latexrelease> +%<latexrelease>\EndIncludeInRelease +%<latexrelease>\IncludeInRelease{0000/00/00}% +%<latexrelease> {\@setupverbvisibletab}{Setup visible tab for \verb}% +%<latexrelease>\let\@setupverbvisibletab\@undefined +%<latexrelease>\EndIncludeInRelease +%<*2ekernel> +% \end{macrocode} +% \end{macro} % % \begin{macro}{\@sverb} % \begin{macro}{\@@sverb} @@ -1464,8 +1595,8 @@ % \begin{macrocode} %</2ekernel> %<*2ekernel|latexrelease> -%<latexrelease>\IncludeInRelease{2020/10/01}% -%<latexrelease> {\@sverb}{Drop spaces before \verb delimiter}% +%<latexrelease>\IncludeInRelease{2023/11/01}% +%<latexrelease> {\@sverb}{Support visible tabs}% % \end{macrocode} % % If the users types \verb=\verb !~! foo= then surprisingly we would @@ -1496,8 +1627,13 @@ % it the definition for the active space character. % \changes{v1.1o}{2018/10/11} % {Provide visible space in \cs{verb*} also for XeTeX and LuaTeX (github/69)} +% \changes{v1.2b}{2023/06/15} +% {Support visible tabs} % \begin{macrocode} - \ifnum\catcode`\ =\active + \ifnum0% + \ifnum\catcode`\ =\active\else 1\fi + \ifnum\catcode`\^^I=\active\else 1\fi + =0 % \else \@setupverbvisiblespace \@vobeyspaces \fi } % \end{macrocode} @@ -1505,6 +1641,19 @@ % \begin{macrocode} %</2ekernel|latexrelease> %<latexrelease>\EndIncludeInRelease +%<latexrelease>\IncludeInRelease{2020/10/01}% +%<latexrelease> {\@sverb}{Drop spaces before \verb delimiter}% +%<latexrelease>\def\@@sverb#1{% +%<latexrelease> \catcode`#1\active +%<latexrelease> \lccode`\~`#1% +%<latexrelease> \gdef\verb@balance@group{\verb@egroup +%<latexrelease> \@latex@error{\noexpand\verb illegal in argument}\@ehc}% +%<latexrelease> \aftergroup\verb@balance@group +%<latexrelease> \lowercase{\let~\verb@egroup}% +%<latexrelease> \ifnum\catcode`\ =\active +%<latexrelease> \else \@setupverbvisiblespace \@vobeyspaces \fi +%<latexrelease>} +%<latexrelease>\EndIncludeInRelease %<latexrelease>\IncludeInRelease{2018/12/01}% %<latexrelease> {\@sverb}{Setup visible space for \verb}% %<latexrelease> diff --git a/Master/texmf-dist/source/latex-dev/base/ltproperties.dtx b/Master/texmf-dist/source/latex-dev/base/ltproperties.dtx new file mode 100644 index 00000000000..71b6e2a14fe --- /dev/null +++ b/Master/texmf-dist/source/latex-dev/base/ltproperties.dtx @@ -0,0 +1,943 @@ +% \iffalse meta-comment +% +%% File: ltproperties.dtx +% +% Copyright (C) 2021-2023 The LaTeX Project +% +% It may be distributed and/or modified under the conditions of the +% LaTeX Project Public License (LPPL), either version 1.3c of this +% license or (at your option) any later version. The latest version +% of this license is in the file +% +% http://www.latex-project.org/lppl.txt +% +% This file is part of the LaTeX base system. (The Work in LPPL) +% and all files in that bundle must be distributed together. +% +% ----------------------------------------------------------------------- +% +% The development version of the bundle can be found at +% +% https://github.com/latex3/latex2e +% +% for those people who are interested. +% \begin{macrocode} +\def\ltpropertiesversion{1.0b} +\def\ltpropertiesdate{2023-09-13} +% \end{macrocode} + +%<*driver> +\documentclass[full]{l3doc} +\EnableCrossrefs +\CodelineIndex +\begin{document} + \DocInput{ltproperties.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% Recording and cross-referencing document properties^^A +% \thanks{This module has version +% \ltpropertiesversion\ dated \ltpropertiesdate, \copyright\ The \LaTeX\ +% Project.} +% } +% +% \author{^^A +% The \LaTeX\ Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \maketitle +% +% \begin{documentation} +% \begin{abstract} +% This code implements command to record and (expandably) reference +% document properties. It extends the standard \cs{label}/\cs{ref}/\cs{pageref} +% commands. +% \end{abstract} +% +% \tableofcontents +% +% \section{Introduction} +% +% The module allows to record the \enquote{current state} of various +% document properties (typically the content of macros and values of counters) +% and to access them in other places through a label. +% The list of properties that can be recorded and retrieved +% are not fix and can be extended by the user. The values of the properties +% are recorded in the \texttt{.aux} file and can be retrieved at the second compilation. +% +% +% The module uses the ideas of properties and labels. A label is +% a document reference point: a name for the user. An property is something +% that \LaTeX{} can track, such as a page number, section number or name. +% The names of labels and properties may be arbitrary. Note that there is +% a single namespace for each. +% +% \section{Design discussion} +% +% The design here largely follows ideas from \pkg{zref}. In particular, there +% are two independent concepts: properties that can be recorded between runs, +% and labels which consist of lists of these properties. The reason for the +% split is that individual labels will want to record some but not all +% properties. For examples, a label concerned with position would track +% the $x$ and $y$ co-ordinates of the current point, but not for example +% the page number. +% +% In the current implementation, properties share a single namespace. This +% allows multiple lists to re-use the same properties, for example page number, +% absolute page number, etc. This does mean that \emph{changing} a standard +% property is an issue. However, some properties have complex definitions +% (again, see \pkg{zref} at present): having them in a single shared space +% avoids the need to copy code. +% +% Labels could be implemented as |prop| data. That is not done at present as +% there is no obvious need to map to or copy the data. As such, faster +% performance is available using a hash table approach as in a \enquote{classical} +% set up. Data written to the |.aux| file uses simple paired \emph{balanced +% text} not keyvals: this avoids any restrictions on names and again offers +% increased performance. +% +% The \pkg{expl3} versions of the label command do not +% use \cs{@bsphack}/\cs{@esphack} to avoid double spaces, +% but the \LaTeXe{} command does as it lives at the document command level. +% +% The reference commands are expandable. +% +% Currently the code has nearly no impact on the main \cs{label} and \cs{ref} commands as +% too many external packages rely on the concrete implementation. +% There is one exception: +% the label names share the same namespace. That means that if both |\label{ABC}| and +% |\RecordProperties{ABC}{page}| are used there is a warning +% \texttt{Label `ABC' multiply defined}. +% +% \section{Handling unknown labels and properties} +% With the standard \cs{label}/\cs{ref} commands the requested label is +% either in the |.aux|-file (and so known) or not. +% In the first case the stored value can be used, +% in the second case the reference commands print two question marks. +% +% With flexible property lists a reference commands asks for the +% value of a specific property stored under a label name +% and we have to consider more variants: +% \begin{itemize} +% \item If the requested property is unknown (not declared) the system +% is not correctly set up and an error is issued. +% \item If the label is unknown, the default of the property is used. +% \item If the label is known, but doesn't provide a value for the +% property then again the default of the property is used. +% \item The command |\property_ref:nnn| allows to give a local default +% which is used instead of the property default in the two cases before. +% \end{itemize} +% +% \section{Rerun messages} +% +% As the reference commands are expandable they can neither issue a message that +% the label or the label-property combination is unknown, nor can they trigger the +% rerun message at the end of the \LaTeX{} run. +% +% Where needed such messages must therefore be triggered manually. For this two commands +% are provided: \cs{property_ref_undefined_warn:} and \cs{property_ref_undefined_warn:nn}. +% See below for a description. +% +% \section{Open points} +% +% \begin{itemize} +% \item The \texttt{xpos} and \texttt{ypos} properties require that the position is +% stored first but there is no (public) engine independent interface yet. Code must +% use \cs{tex_savepos:D}. +% \end{itemize} +% +% \section{Code interfaces} +% +% \begin{function}{\property_new:nnnn,\property_gset:nnnn} +% \begin{syntax} +% \cs{property_new:nnnn} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code} +% \cs{property_gset:nnnn} \Arg{property}\Arg{setpoint} \Arg{default} \Arg{code} +% \end{syntax} +% \LaTeXe-interface: see \cs{NewProperty}, \cs{SetProperty}.\\ +% Sets the \meta{property} to have the \meta{default} specified, and at the +% \meta{setpoint} (either |now| or |shipout|) to write the result of the +% \meta{code} as part of a label. The \meta{code} should be expandable. The expansion +% of \meta{code} (the value of the property) is written to the |.aux| file and read +% back from there at the next compilation. Values should assume that the +% standard \LaTeX{} catcode régime with |@| a letter is active then. +% +% If the property is declared within a package it is suggested +% that its name is build from letters, hyphens and slashes, +% and is always structured as follows:\\ +% \meta{package-name}\texttt{/}\meta{property-name}. +% \end{function} +% +% \begin{function} +% { +% \property_record:nN, +% \property_record:nn, \property_record:nV, \property_record:xx +% } +% \begin{syntax} +% \cs{property_record:nN} \Arg{label} \Arg{clist var} +% \cs{property_record:nn} \Arg{label} \Arg{clist} +% \end{syntax} +% \LaTeXe{}-interface: see \cs{RecordProperties}.\\ +% Writes the list of properties given by the \meta{clist} to the |.aux| +% file with the \meta{label} specified. +% \end{function} +% +% \begin{function}[EXP]{\property_ref:nn,\property_ref:ee} +% \begin{syntax} +% \cs{property_ref:nn} \Arg{label} \Arg{property} +% \end{syntax} +% \LaTeXe{}-interface: see \cs{RefProperty}.\\ +% Expands to the value of the \meta{property} for the \meta{label}, if +% available, and the default value of the property otherwise. +% If \meta{property} has not been declared with |\property_new:nnnn| +% an error is issued. The command raises an internal, expandable, local flag +% if the reference can not be resolved. +% \end{function} +% +% \begin{function}[EXP]{\property_ref:nnn,\property_ref:een} +% \begin{syntax} +% \cs{property_ref:nnn} \Arg{label} \Arg{property} \Arg{local default} +% \end{syntax} +% \LaTeXe{}-interface: see \cs{RefProperty}.\\ +% Expands to the value of the \meta{property} for the \meta{label}, if +% available, and to \meta{local default} otherwise. +% If \meta{property} has not been declared with |\property_new:nnnn| +% an error is issued. The command raises an internal, expandable local flag +% if the reference can not be resolved. +% \end{function} +% +% \begin{function}{\property_ref_undefined_warn:} +% \begin{syntax} +% \cs{property_ref_undefined_warn:} +% \end{syntax} +% \LaTeXe{}-interface: not provided.\\ +% The commands triggers the standard warning +% \\ +% \hspace*{1em}\texttt{LaTeX Warning: There were undefined references.} +% \\ +% at the end of the document if there was a recent +% \cs{property_ref:nn} or \cs{property_ref:nnn} which couldn't be resolved +% and so raised the flag. \enquote{Recent} means in the same group +% or in some outer group! +% \end{function} +% +% \begin{function}{\property_ref_undefined_warn:n,\property_ref_undefined_warn:x} +% \begin{syntax} +% \cs{property_ref_undefined_warn:n} \Arg{label} +% \end{syntax} +% \LaTeXe{}-interface: not provided.\\ +% The commands triggers the standard warning\\ +% \hspace*{1em}\texttt{LaTeX Warning: There were undefined references.} +% \\ +% at the end of the document if \meta{label} is not known. +% At the point where it is called it also issues the warning\\ +% \hspace*{1em}% +% \texttt{Reference~`\meta{label}'~on~page~\meta{page}\space undefined}. +% \end{function} +% +% \begin{function}{\property_ref_undefined_warn:nn,\property_ref_undefined_warn:xx} +% \begin{syntax} +% \cs{property_ref_undefined_warn:nn} \Arg{label} \Arg{property} +% \end{syntax} +% \LaTeXe{}-interface: see \cs{RefUndefinedWarn}.\\ +% The commands triggers the standard warning\\ +% \hspace*{1em}% +% \texttt{LaTeX Warning: There were undefined references.}\\ +% at the end of the document if the reference can not be resolved. +% At the point where it is called it also issues the warning\\ +% \hspace*{1em}% +% \texttt{Reference~`\meta{label}'~on~page~\meta{page}\space undefined}\\ +% if the label +% is unknown, or the more specific\\ +% \hspace*{1em}% +% \texttt{Property `\meta{property}' undefined for reference +% `\meta{label}' on page \meta{page}}\\ +% if the label is known but doesn't provide a value for the requested property. +% \end{function} +% +% \begin{function}[pTF]{\property_if_exist:n,\property_if_exist:e} +% \begin{syntax} +% \cs{property_if_exist_p:n} \Arg{property} +% \cs{property_if_exist:nTF} \Arg{property} \Arg{true code} \Arg{false code} +% \end{syntax} +% \LaTeXe{}-interface: \cs{IfPropertyExistTF}.\\ +% Tests if the \meta{property} has been declared. +% \end{function} +% +% \begin{function}[pTF]{\property_if_recorded:n,\property_if_recorded:e} +% \begin{syntax} +% \cs{property_if_recorded_p:n} \Arg{label} +% \cs{property_if_recorded:nTF} \Arg{label} \Arg{true code} \Arg{false code} +% \end{syntax} +% \LaTeXe{}-interface: \cs{IfLabelExistTF}\\ +% Tests if the \meta{label} is known. This is also true if the label has been +% set with the standard \cs{label} command. +% \end{function} +% +% \begin{function}[pTF]{\property_if_recorded:nn,\property_if_recorded:ee} +% \begin{syntax} +% \cs{property_if_recorded_p:nn} \Arg{label} \Arg{property} +% \cs{property_if_recorded:nnTF} \Arg{label} \Arg{property} \Arg{true code} \Arg{false code} +% \end{syntax} +% \LaTeXe{}-interface: \cs{IfPropertyRecordedTF}.\\ +% Tests if the label \meta{label} is known and if it provides a value of the \meta{property}. +% \end{function} +% +% \section{Auxiliary file interfaces} +% +% \begin{function}{\new@label@record} +% \begin{syntax} +% \cs{new@label@record} \Arg{label} \Arg{data} +% \end{syntax} +% This is a command only for use in the |.aux| file. It loads the key--value +% list of \meta{data} to be available for the \meta{label}. +% \end{function} +% +% \section{\LaTeXe{} interface} +% +% The LaTeXe{} interfaces always expand label and property arguments. +% +% \begin{function}{\NewProperty,\SetProperty} +% \begin{syntax} +% \cs{NewProperty} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code} +% \cs{SetProperty} \Arg{property} \Arg{setpoint} \Arg{default} \Arg{code} +% \end{syntax} +% Sets the \meta{property} to have the \meta{default} specified, and at the +% \meta{setpoint} (either |now| or |shipout|) to write the result of the +% \meta{code} as part of a label. The \meta{code} should be expandable. The expansion +% of \meta{code} (the value of the property) is written to the |.aux| file and read +% back from there at the next compilation (at which point normally +% the standard \LaTeX{} catcode régime with |@| a letter is active). +% +% \end{function} +% +% \begin{function}{\RecordProperties} +% \begin{syntax} +% \cs{RecordProperties} \Arg{label} \Arg{clist} +% \end{syntax} +% Writes the list of properties given by the \meta{clist} to the |.aux| +% file with the \meta{label} specified. Similar to the standard \cs{label} command +% the arguments are expanded. So \meta{clist} can be a macro containing a list +% of properties. Also similar to the standard \cs{label} command, the command is surrounded +% by an \cs{@bsphack}/\cs{@esphack} pair to preserve spacing. +% \end{function} + +% \begin{function}[EXP]{\RefProperty} +% \begin{syntax} +% \cs{RefProperty} \oarg{local default} \Arg{label} \Arg{property} +% \end{syntax} +% Expands to the value of the \meta{property} for the \meta{label}, if +% available, and the default value of the property or -- if given -- +% to \meta{local default} otherwise. +% If \Arg{property} has not been declared an error is issued. +% \end{function} +% +% \begin{function}{\IfPropertyExistTF} +% \begin{syntax} +% \cs{IfPropertyExistTF} \Arg{property} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{property} has been declared. +% \end{function} +% +% \begin{function}{\IfLabelExistTF} +% \begin{syntax} +% \cs{IfLabelExistTF} \Arg{label} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{label} has been recorded. This is also true if a label +% has been set with the standard \cs{label} command. +% \end{function} +% +% \begin{function}{\IfPropertyRecordedTF} +% \begin{syntax} +% \cs{IfPropertyRecordedTF} \Arg{label} \Arg{property} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the label and a value of the \meta{property} for the \meta{label} are both known. +% \end{function} + +% \begin{function}{\RefUndefinedWarn} +% \begin{syntax} +% \cs{RefUndefinedWarn} \Arg{label} \Arg{property} +% \end{syntax} +% This commands triggers the standard warning\\ +% \hspace*{1em}% +% \texttt{LaTeX Warning: There were undefined references.}\\ +% at the end of the document if the reference for \meta{label} and \meta{property} +% can not be resolved. +% At the point where it is called it also issues the warning\\ +% \hspace*{1em}% +% \texttt{Reference `\meta{label}' on page \meta{page} undefined}\\ +% if the label is unknown, or the more specific\\ +% \hspace*{1em}% +% \texttt{Property `\meta{property}' undefined for reference +% `\meta{label}' on page \meta{page}} +% if the label is known but doesn't provide a value for the requested property. +% \end{function} +% +% \section{Pre-declared properties} +% +% \begin{variable}{abspage} +% (shipout) The absolute value of the current page: starts at $1$ and increases +% monotonically at each shipout. +% \end{variable} +% +% \begin{variable}{page} +% (shipout) The current page as given by \cs{thepage}: this may or may not +% be a numerical value, depending on the current style. Contrast with +% \cs{abspage}. You get this value also with the standard \cs{label}/\cs{pageref}. +% \end{variable} +% +% \begin{variable}{pagenum} +% (shipout) The current page as arabic number. This is suitable for integer operations and +% comparisions. +% \end{variable} +% +% \begin{variable}{currentlabel} +% (now) The content of \cs{@currentlabel}. This is the value that +% you get also with the standard \cs{label}/\cs{ref}. +% \end{variable} +% +% \begin{variable}{title} +% (now) The content of \cs{@currentlabelname}. +% This command is filled beside others by the \pkg{nameref} package and some +% classes (e.g.~\pkg{memoir}). +% \end{variable} +% +% \begin{variable}{target} +% (now) The content of \cs{@currentHref}. +% This command is normally filled by for example by +% \pkg{hyperref} and gives the name of the last destination it created. +% \end{variable} +% +% \begin{variable}{counter} +% (now) The content of \cs{@currentcounter}. +% This command contains after a \cs{refstepcounter} the name of the counter. +% \end{variable} +% +% \begin{variable}{xpos,ypos} +% (shipout) This stores the $x$~and $y$ coordinates of a point previously +% stored with \cs{pdfsavepos}/\cs{savepos}. +% E.g.~(if bidi is used it can be necessary to save the position +% before and after the label): +% \begin{verbatim} +% \tex_savepos:D +% \property_record:nn{myposition}{xpos,ypos} +% \tex_savepos:D +% \end{verbatim} +% \end{variable} +% \end{documentation} +% +% \begin{implementation} +% +% \section{The Implementation} +% +% \begin{macrocode} +%<*2ekernel|latexrelease> +% \end{macrocode} +% \begin{macrocode} +\ExplSyntaxOn +% \end{macrocode} +% +% \begin{macrocode} +%<@@=property> +% \end{macrocode} +% +% \begin{macrocode} +%<latexrelease>\NewModuleRelease{2023/11/01}{ltproperties} +%<latexrelease> {Cross-referencing~properties} +% \end{macrocode} +% +% The approach here is based closely on that from \pkg{zref}; separate out +% lists of properties and the properties themselves, so the latter can be +% used multiple times and in varying combinations. +% However, not everything is a straight copy. Firstly, +% we treat lists of properties as simple comma lists: that allows us to have +% either saved or dynamic lists and to avoid another data structure. The cost +% is that errors are detected at point-of-use, but in any real case that should +% be true anyway (and is true for \tn{zref@labelbyprop} already). Secondly, +% we allow properties to have +% arbitrary names, as the code does not require them to tokenize as control +% sequences. +% +% \begin{macro}{\property_new:nnnn, \property_gset:nnnn, \@@_gset:nnnn} +% As properties can be reset, they are not constants. But they also have +% various pieces of required data. So we use the same approach as color and +% make them declarations. Data-wise, we need the detail of the implementation, +% the default and a flag to show if the code works now or at shipout. This +% last entry is done using text so needs a check. We could use a set of +% |prop| here, but as we never need to map or copy the lists, we can gain +% performance using the hash table approach. +% \begin{macrocode} +\cs_new_protected:Npn \property_new:nnnn #1#2#3#4 + { + \cs_if_free:cTF { @@_code_ #1 : } + { + \exp_args:Nx \@@_gset:nnnn { \tl_to_str:n {#1} } + {#2} {#3} {#4} + } + { + \msg_error:nn { property }{ exists }{#1} + } + } +\cs_new_protected:Npn \property_gset:nnnn #1#2#3#4 + { + \@@_gset:xnnn { \tl_to_str:n {#1} } + {#2} {#3} {#4} + } +\cs_new_protected:Npn \@@_gset:nnnn #1#2#3#4 + { + \cs_gset:cpn { @@_code_ #1 : } {#4} + \tl_gclear_new:c { g_@@_default_ #1 _tl } + \tl_gset:cn { g_@@_default_ #1 _tl } {#3} + \bool_if_exist:cF { g_@@_shipout_ #1 _tl } + { \bool_new:c { g_@@_shipout_ #1 _tl } } + \str_case:nnF {#2} + { + { now } { { \bool_gset_false:c { g_@@_shipout_ #1 _tl } } } + { shipout } + { \bool_gset_true:c { g_@@_shipout_ #1 _tl } } + } + { \msg_error:nnnn { property } { unknown-setpoint } {#1} {#2} } + } +\cs_generate_variant:Nn \@@_gset:nnnn {xnnn} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\NewProperty,\SetProperty} +% For consistency we expand the property name, but this doesn't warant a +% variant of the L3-commands. +% \begin{macrocode} +\cs_new_protected:Npn \NewProperty #1#2#3#4 + { + \exp_args:Nx \property_new:nnnn {#1}{#2}{#3}{#4} + } +\cs_new_protected:Npn \SetProperty #1#2#3#4 + { + \exp_args:Nx \property_gset:nnnn {#1}{#2}{#3}{#4} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\property_record:nN} +% \begin{macro} +% { +% \property_record:nn, +% \property_record:nV, +% \property_record:xx, +% \@@_record:nn, +% \@@_record:xn +% } +% \begin{macro}[EXP] +% {\@@_record_value:n, \@@_record_value_aux:n, \@@_record_value_aux:e} +% Writing data when it is labelled means expanding at this stage and possibly +% later too. That is all pretty easy using \pkg{expl3}: we accept a stray +% comma at the end of the list as that is easier to deal with than trying +% to tidy up, and there is no real downside. +% \begin{macrocode} +\cs_new_protected:Npn \property_record:nN #1#2 + { \property_record:nV {#1} #2 } +\cs_new_protected:Npn \property_record:nn #1#2 + { \@@_record:xn { \tl_to_str:n {#1} } {#2} } +\cs_generate_variant:Nn \property_record:nn { nV , xx } +\cs_new_protected:Npn \@@_record:nn #1#2 + { + \legacy_if:nT { @filesw } + { + \iow_shipout_x:Nx \@auxout + { + \token_to_str:N \new@label@record + {#1} + { \clist_map_function:nN {#2} \@@_record_value:n } + } + } + } +\cs_generate_variant:Nn \@@_record:nn { x } +\cs_new:Npn \@@_record_value:n #1 + { \@@_record_value_aux:e { \tl_to_str:n {#1} } } +\cs_new:Npn \@@_record_value_aux:n #1 + { + \cs_if_exist:cTF { @@_code_ #1 : } + { + {#1} + { + \bool_if:cTF { g_@@_shipout_ #1 _tl } + { \exp_not:c } + { \use:c } + { @@_code_ #1 : } + } + } + { \msg_expandable_error:nnn { property } { not-declared } {#1} } + } +\cs_generate_variant:Nn \@@_record_value_aux:n { e } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\RecordProperties} +% \begin{macrocode} +\NewDocumentCommand\RecordProperties { m m } + { + \@bsphack + \property_record:xx {#1}{#2} + \@esphack + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Reference commands} +% +% \begin{variable}{ l_@@_ref_flag } +% A flag that is set if a reference couldn't be resolved. +% \begin{macrocode} +\flag_new:n { l_@@_ref_flag } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[EXP]{\property_ref:nn,\property_ref:ee} +% Search for the label/property combination, and if not found fall back +% to the default of the property. +% \begin{macrocode} +\cs_new:Npn \property_ref:nn #1#2 + { + \@@_ref:een + { \tl_to_str:n {#1} } + { \tl_to_str:n {#2} } + { \tl_use:c { g_@@_default_ #2 _tl } } + } +\cs_generate_variant:Nn \property_ref:nn {ee} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\property_ref:nnn,\property_ref:een, \@@_ref:nnn, \@@_ref:een} +% This allows to set a local default value which overrides the default value +% of the property. +% \begin{macrocode} +\cs_new:Npn \property_ref:nnn #1#2#3 + { + \@@_ref:een + { \tl_to_str:n {#1} } + { \tl_to_str:n {#2} } + {#3} + } +\cs_new:Npn \@@_ref:nnn #1#2#3 + { + \tl_if_exist:cTF { g_@@_label_ #1 _ #2 _tl } + { \tl_use:c { g_@@_label_ #1 _ #2 _tl } } + { + \flag_if_raised:nF + { l_@@_ref_flag } { \flag_raise:n { l_@@_ref_flag } } +% \end{macrocode} +% We test for the default of the property only to check if the property has +% been declared. +% \begin{macrocode} + \tl_if_exist:cTF { g_@@_default_ #2 _tl } + { #3 } + { \msg_expandable_error:nnn { property } { not-declared } {#2} } + } + } +\cs_generate_variant:Nn \@@_ref:nnn { ee } +\cs_generate_variant:Nn \property_ref:nnn {een} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\RefProperty} +% Search for the label/property combination, and if not found fall back +% to the default of the property or the given default. +% \begin{macrocode} +\NewExpandableDocumentCommand \RefProperty { o m m } + { + \IfNoValueTF {#1} + { + \property_ref:ee {#2}{#3} + } + { + \property_ref:een {#2}{#3}{#1} + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\new@label@record} +% \begin{macro}{\@@_data:nnn} +% A standard recursion loop. +% \begin{macrocode} +\cs_new_protected:Npn \new@label@record #1#2 + { + \tl_if_exist:cTF { r@#1 } + { + \gdef \@multiplelabels + { \@latex@warning@no@line { There~were~multiply-defined~labels } } + \@latex@warning@no@line { Label~`#1'~multiply~defined } + } + { + \tl_new:c { r@#1 } + \tl_gset:cn { r@#1 }{#2} + } + \@@_data:nnn {#1} #2 { \q_recursion_tail } { ? } \q_recursion_stop + } +\cs_new_protected:Npn \@@_data:nnn #1#2#3 + { + \quark_if_recursion_tail_stop:n {#2} + \tl_gclear_new:c { g_@@_label_ \tl_to_str:n {#1} _ \tl_to_str:n {#2} _tl } + \tl_gset:cn { g_@@_label_ \tl_to_str:n {#1} _ \tl_to_str:n {#2} _tl } {#3} + \@@_data:nnn {#1} + } +% \end{macrocode} +% +% This command is used in \cs{enddocument} to test if some label values have changed. +% \begin{macrocode} +\cs_new_protected:Npn \@kernel@new@label@record@testdef #1 #2 + { + \tl_if_eq:cnF { r@#1 } {#2} + { \@tempswatrue } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Tests and warnings} +% +% \begin{macro}[pTF]{\property_if_exist:n} +% Tests if property has been declared. +% \begin{macrocode} +\prg_new_conditional:Npnn \property_if_exist:n #1 { p , T , F, TF } + % #1 property + { + \cs_if_exist:cTF { @@_code_ #1 : } + { + \prg_return_true: + } + { + \prg_return_false: + } + } +\prg_generate_conditional_variant:Nnn \property_if_exist:n {e} {TF} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{IfPropertyExistTF} +% \begin{macrocode} +\cs_new_eq:NN \IfPropertyExistTF \property_if_exist:eTF +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\property_if_recorded:n} +% Tests if the label has been set. +% This can then be used to setup e.g.~rerun messages. +% \begin{macrocode} +\prg_new_conditional:Npnn \property_if_recorded:n #1 { p , T , F, TF } + % #1 label + { + \tl_if_exist:cTF { r@#1 } + { + \prg_return_true: + } + { + \prg_return_false: + } + } +\prg_generate_conditional_variant:Nnn \property_if_recorded:n {e} {TF} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\IfLabelExistTF} +% \begin{macrocode} +\cs_new_eq:NN \IfLabelExistTF \property_if_recorded:eTF +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\property_if_recorded:nn} +% tests if the label/property combination has been set +% This can then be used to setup e.g.~rerun messages. +% \begin{macrocode} +\prg_new_conditional:Npnn \property_if_recorded:nn #1#2 { p , T , F, TF } + % #1 label #2 property + { + \tl_if_exist:cTF { g_@@_label_ \tl_to_str:n {#1} _ \tl_to_str:n {#2} _tl } + { + \prg_return_true: + } + { + \prg_return_false: + } + } +\prg_generate_conditional_variant:Nnn \property_if_recorded:nn {ee} {TF} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\IfPropertyRecordedTF} +% \begin{macrocode} +\cs_new_eq:NN \IfPropertyRecordedTF \property_if_recorded:eeTF +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\property_ref_undefined_warn:} +% \cs{G@refundefinedtrue} is defined in \texttt{ltxref} and redefines a warning message. +% \begin{macrocode} +\cs_new_protected:Npn \property_ref_undefined_warn: + { + \flag_if_raised:nT { l_@@_ref_flag } + { + \G@refundefinedtrue + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\property_ref_undefined_warn:n} +% \begin{macrocode} +\cs_new_protected:Npn \property_ref_undefined_warn:n #1 %#1 label + { + \property_if_recorded:nF {#1} + { + \G@refundefinedtrue + \@latex@warning{Reference~`#1'~on~page~\thepage\space undefined}% + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\property_ref_undefined_warn:nn, +% \property_ref_undefined_warn:xx, +% \RefUndefinedWarn} +% \begin{macrocode} +\cs_new_protected:Npn \property_ref_undefined_warn:nn #1#2 %#1 label, #2 property + { + \property_if_recorded:nTF {#1} + { + \property_if_recorded:nnF {#1}{#2} + { + \G@refundefinedtrue + \@latex@warning + { Property~`#2'~undefined~for~reference~`#1'~on~page~\thepage } + } + } + { + \G@refundefinedtrue + \@latex@warning { Reference~`#1'~on~page~\thepage\space undefined }% + } + } +\cs_generate_variant:Nn \property_ref_undefined_warn:nn {xx} +\cs_set_eq:NN \RefUndefinedWarn \property_ref_undefined_warn:xx +% \end{macrocode} +% \end{macro} +% +% \subsection{Predeclared properties} +% +% \begin{variable}{abspage} +% \begin{macrocode} +\property_new:nnnn { abspage } { shipout } + { 0 } { \int_use:N \g_shipout_readonly_int } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{page} +% \begin{macrocode} +\property_new:nnnn { page } { shipout } { 0 } { \thepage } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{pagenum} +% \begin{macrocode} +\property_new:nnnn { pagenum } { shipout } { 0 } { \the \value { page } } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{currentlabel} +% \begin{macrocode} +\property_new:nnnn { currentlabel } { now } { ?? } { \@currentlabel } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{title} +% \begin{macrocode} +\property_new:nnnn { title } { now } + { \exp_not:n { \textbf { ?? } } } { \@currentlabelname } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{target} +% \begin{macrocode} +\property_new:nnnn { target } { now } { } { \@currentHref } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{counter} +% \begin{macrocode} +\property_new:nnnn { counter } { now } { } { \@currentcounter } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{xpos,ypos} +% \begin{macrocode} +\property_new:nnnn { xpos } { shipout } { 0} { \int_use:N \tex_lastxpos:D } +\property_new:nnnn { ypos } { shipout } { 0} { \int_use:N \tex_lastypos:D } +% \end{macrocode} +% \end{variable} +% +% \subsection{Messages} +% \begin{macrocode} +\msg_new:nnnn { property } { exists } + { Property~'#1'~ has~ already~ been~ declared. } + { There~ already~ exists~ a~ property~ declaration~ with~ this~ + name.\\ + Please~ use~ a~ different~ name~ for~ your~ property.} + +\msg_new:nnnn { property } { not-declared } + { Property~'#1'~not~declared. } + { + LaTeX~has~been~asked~to~use~property~'#1',~but~this~ + name~has~not~been~declared. + } +\msg_new:nnnn { property } { unknown-setpoint } + { Unknown~keyword~'#2'~for~setting~property~'#1'. } + { + LaTeX~has~been~asked~to~set~the~property~'#1',~but~the~keyword~ + '#2'~is~not~one~of~the~two~known~values:~'now'~or~'shipout'. + } +% \end{macrocode} +% +% \begin{macrocode} +% +%<latexrelease>\IncludeInRelease{0000/00/00}{ltproperties} +%<latexrelease> {cross-referencing~properties~(undo)}% +%<latexrelease> +%<latexrelease>\let \NewProperty \@undefined +%<latexrelease>\let \SetProperty \@undefined +%<latexrelease> +%<latexrelease>\let \RecordProperties \@undefined +%<latexrelease>\let \RefProperty \@undefined +%<latexrelease>\let \RefUndefinedWarn \@undefined +%<latexrelease> +%<latexrelease>\let \IfPropertyExistTF \@undefined +%<latexrelease>\let \IfLabelExistTF \@undefined +%<latexrelease>\let \IfPropertyRecordedTF \@undefined +%<latexrelease> +%<latexrelease>\let\new@label@record \@undefined +%<latexrelease>\let\@kernel@new@label@record@testdef\@undefined +%<latexrelease>\EndModuleRelease +% \end{macrocode} +% +% \begin{macrocode} +\ExplSyntaxOff +% \end{macrocode} +% +% \begin{macrocode} +%</2ekernel|latexrelease> +% \end{macrocode} +% +% Reset module prefix: +% \begin{macrocode} +%<@@=> +% \end{macrocode} +% +% +% \end{implementation} +% +% \Finale diff --git a/Master/texmf-dist/source/latex-dev/base/ltsockets.dtx b/Master/texmf-dist/source/latex-dev/base/ltsockets.dtx new file mode 100644 index 00000000000..7d2940f454b --- /dev/null +++ b/Master/texmf-dist/source/latex-dev/base/ltsockets.dtx @@ -0,0 +1,1069 @@ +% \iffalse meta-comment +% +% Copyright (C) 2023 +% Frank Mittelbach, The LaTeX Project +% +% This file is part of the LaTeX base system. +% ------------------------------------------- +% +% It may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3c +% of this license or (at your option) any later version. +% The latest version of this license is in +% https://www.latex-project.org/lppl.txt +% and version 1.3c or later is part of all distributions of LaTeX +% version 2008 or later. +% +% This file has the LPPL maintenance status "maintained". +% +% The list of all files belonging to the LaTeX base distribution is +% given in the file `manifest.txt'. See also `legal.txt' for additional +% information. +% +% The list of derived (unpacked) files belonging to the distribution +% and covered by LPPL is defined by the unpacking scripts (with +% extension .ins) which are part of the distribution. +% +% \fi +% +% \iffalse +% +%%% From File: ltsockets.dtx +% +% \begin{macrocode} +\def\ltsocketsversion{0.9a} +\def\ltsocketsdate{2023-08-21} +% \end{macrocode} +% +%<*driver> +\documentclass{l3doc} + + +\providecommand\InternalDetectionOff{} +\providecommand\InternalDetectionOn{} + +\EnableCrossrefs +\CodelineIndex +\begin{document} + \DocInput{ltsockets.dtx} +\end{document} +%</driver> +% +% \fi +% +% +% +% +% \title{\LaTeX{}'s socket management\thanks{This module has version +% \ltsocketsversion\ dated \ltsocketsdate, \copyright\ \LaTeX\ +% Project.}} +% +% \author{Frank Mittelbach} +% +% \maketitle +% +% ^^A this needs some cleanup: +% \long\def\fmi#1{\begin{quote} TODO: \itshape #1\end{quote}} +% +% \providecommand\pkg[1]{\texttt{#1}} +% \providecommand\hook[1]{\texttt{#1}} +% \providecommand\env[1]{\texttt{#1}} +% \providecommand\plug[1]{\texttt{#1}} +% \providecommand\socket[1]{\texttt{#1}} +% +% +% \begin{abstract} +% This code implements sockets which are places in the code into +% which predeclared chunks of code (plugs) can be placed. Both the sockets +% and the plugs are \enquote{named} and each socket is +% assigned exactly one plug at any given time. +% \end{abstract} +% +% \tableofcontents +% +% \section{Introduction} +% +% A \LaTeX{} source file is transformed into a typeset document by +% executing code for each command or environment in the document +% source. Through various steps this code transforms the input and +% eventually generates typeset output appearing in a \enquote{galley} +% from which individual pages are cut off in an asyncronous way. This +% page generating process is normally not directly associated with +% commands in the input\footnote{Excepts for directives such as +% \cs{newpage}.} but is triggered whenever the galley has received +% enough material to form another page (giving current settings). +% +% As part of this transformation input data may get stored in some form +% and later reused, for example, as part of the output routine +% processing. +% +% \section{Configuration of the transformation process} +% +% There are three different major methods offered by \LaTeX{} to +% configure the transformation process: +% \begin{itemize} +% \item through the template mechanism, +% \item through the hook mechanism, or +% \item through sockets and plugs. +% \end{itemize} +% They offer different possibilities (with different features and +% limitations) and are intended for specific use cases, though it is +% possible to combine them. +% +% \subsection{The template mechanism} +% +% The template mechanism is intended for more complex document-level +% elements (e.g., headings such as \verb=\section= or environments like +% \env{itemize}). The template code implements the overall processing +% logic for such an element and offers a set of parameters to influence +% the final result. +% +% The document element is then implemented by (a) selecting a suitable +% template (there may be more than one available for the kind of +% document element) and (b) by setting its parameters to desired +% values. This then forms a so-called instance which is executed when +% the document element is found in the source. +% +% By altering the parameter values (in a document class or in the +% document preamble) or, if more drastic layout changes are desired, by +% selecting a different template and then adjusting its parameters, a +% wide variety of layouts can be realized through simple configuration +% setups without the need to develop new code. +% +% The target audience of this method are therefore document class +% developers or users who wish to alter an existing layout (implemented +% by a document class) in certain (minor) ways. +% +% The template mechanism is currently documented as part of the +% \pkg{xtemplate} package and one more elaborate implementation can be +% found as part of the \texttt{latex-lab} code for lists (to be +% documented further). +% +% \subsection{The hook mechanism} +% +% Hooks are places in the kernel code (or in packages) that offer +% packages the possibility to inject additional code at specific +% points in the processing in a controlled way without the need to +% replace the existing code block (and thereby overwriting +% modifications/extensions made by other packages). The target +% audience is therefore mainly package developers, even though some +% hooks can be useful for document authors. +% +% Obviously, what can reasonably be added into a hook depends on the +% individual hook (hopefully documented as part of the hook +% documentation), but in general the idea behind hooks is that more +% than one package could add code into the hook at the same +% time. Perhaps the most famous hook (that \LaTeX{} had for a very +% long time) is \hook{begindocument} into which many packages add code +% to through \cs{AtBeginDocument}\marg{code} (which is nowadays +% implemented as a shorthand for +% \cs{AddToHook}\texttt{\{\hook{begindocument}\}}\marg{code}). To +% resolve possible conflicts between injections by different packages +% there is a rule mechanism by which code chunks in a hook can be +% ordered in a certain way and by which incompatible packages can be +% detected if a resolution is impossible. +% +% In contrast to template code, there is no standard configuration +% method through parameters for hooks, i.e., the code added to a hook +% \enquote{is} the configuration. If it wants to provide for +% configuration through parameters it has to also provide its own +% method to set such parameters in some way. However, in that case it +% is likely that using a hook is not the right approach and the +% developer better calls a template instance instead which then offers +% configuration through a key/value interface. +% +% In most cases, hooks do not take any arguments as input. Instead, the data +% that they can (and are allowed to) access depends on the surrounding +% context. +% +% For example, the various hooks available during the page shipout +% process in \LaTeX's output routine can (and have to) access the +% accumulated page material stored in a box named +% \verb=\ShipoutBox=. This way, code added to, say, the +% \hook{shipout/before} hook could access the page content, alter it, +% and then write it back into \verb=\ShipoutBox= and any other code +% added to this hook could then operate on the modified content. Of +% course, for such a scheme to work the code prior to executing the hook +% would need to setup up data in appropriate places and the hook +% documentation would need to document what kind of storage can be +% accessed (and possibly altered) by the hook. +% +% There are also hooks that take arguments (typically portions of +% document data) and in that case the hook code can access these +% arguments through \verb=#1=, \verb=#2=, etc. +% +% The hook mechanism is documented in \texttt{lthooks-doc.pdf}. +% +% +% +% \subsection{The socket mechanism} +% +% In some cases there is code that implements a certain programming +% logic (for example, combining footnotes, floats, and the text for the +% current page to be shipped out) and if this logic should change (e.g., +% footnotes to be placed above bottom floats instead of below) then this +% whole code block needs to be replaced with different code. +% +% In theory, this could be implemented with templates, i.e., the code +% simply calls some instance that implements the logic and that instance +% is altered by selecting a different templates and/or adjusting their +% parameters. However, in many cases customization through parameters is +% overkill in such a case (or otherwise awkward, because paramerization +% is better done on a higher level instead of individually for small +% blocks of code) and using the template mechanism just to replace one +% block of code with a different one results in a fairly high +% performance hit. It is therefore usually not a good choice. +% +% In theory, it would also be possible to use a hook, but again that is +% basically a misuse of the concept, because in this use case there should +% never be more than one block of code inside the hook; thus, to alter +% the processing logic one would need to set up rules that replace code +% rather than (as intended) execute all code added to the hook. +% +% +% +% For this reason \LaTeX{} now offers a third mechanism: +% \enquote{sockets} into which one can place exactly one code block +% --- a \enquote{plug}. +% +% In a nutshell: instead of having a fixed code block somewhere as part +% of the code, implementing a certain programming logic there is a +% reference to a named socket at this point. +% This is done by first declaring the named socket with: +% \begin{quote} +% \cs{NewSocket}\marg{socket-name}\marg{number-of-inputs} +% \end{quote} +% This is then referenced at the point where the replaceable code block +% should be executed with: +% \begin{quote} +% \cs{UseSocket}\marg{socket-name} +% \end{quote} +% or, if the socket should take a number of inputs (additional +% arguments beside the name) with +% \begin{quote} +% \cs{UseSocket}\marg{socket-name}\marg{arg\textsubscript{1}}\ldots +% \marg{arg\textsubscript{\meta{number-of-inputs}}} +% \end{quote} +% +% In addition, several code blocks (a.k.a.\ plugs) implementing different logic for this +% socket are set up, each with a declaration of the form: +% \begin{quote} +% \cs{NewSocketPlug}\marg{socket-name}\marg{socket-plug-name}\marg{code} +% \end{quote} +% Finally, +% one of them is assigned to the socket: +% \begin{quote} +% \cs{AssignSocketPlug}\marg{socket-name}\marg{socket-plug-name} +% \end{quote} +% If the programming logic should change, then all that is necessary is +% to make a new assignment with \cs{AssignSocketPlug} to a different +% \marg{socket-plug-name}. This assignment obeys scope so that an +% environment can alter a socket without the need to restore the +% previous setting manually. +% +% If the socket takes inputs, then those need to be provided to +% \cs{UseSocket} and in that case they can be referenced in the \meta{code} +% argument of \cs{NewSocketPlug} with \verb=#1=, \verb=#2=, etc. +% +% In most cases a named socket is used only in a single place, but there +% is, of course, nothing wrong with using it in several places, as long +% as the code in all places is supposed to change in the same way. +% +% +% +% +% +% \subsubsection{Examples} +% +% +% We start by declaring a new socket named \socket{foo} that expects +% two inputs: +%\begin{verbatim} +% \NewSocket{foo}{2} +%\end{verbatim} +% \NewSocket{foo}{2} +% +% Such a declaration has do be unique across the whole \LaTeX{} +% run. Thus, if another package attempts to use the same name +% (regardless of the number of inputs) it will generate an error: +%\begin{verbatim} +% \NewSocket{foo}{2} +% \NewSocket{foo}{1} +% \end{verbatim} +% Both declarations would therefore produce: +% \begin{verbatim} +% ! LaTeX socket Error: Socket 'foo' already declared! +%\end{verbatim} +% +% You also get an error if you attempt to declare some socket plug and +% the socket name is not yet declared, e.g., +%\begin{verbatim} +% \NewSocketPlug{baz}{undeclared}{some code} +%\end{verbatim} +% generates +%\begin{verbatim} +% ! LaTeX socket Error: Socket 'baz' undeclared! +%\end{verbatim} +% +% +% Setting up plugs for the socket is done like this: +%\begin{verbatim} +% \NewSocketPlug{foo}{plug-A} +% {\begin{quote}\itshape foo-A: #1!#2\end{quote}} +% \NewSocketPlug{foo}{plug-B} +% {\begin{quote}\sffamily foo-B: #2\textsuperscript{2}\end{quote}} +%\end{verbatim} +% This will set up the plugs \texttt{plug-A} and \texttt{plug-B} for +% this socket. +% +%\NewSocketPlug{foo}{plug-A}{\begin{quote}\itshape foo-A: #1!#2\end{quote}} +%\NewSocketPlug{foo}{plug-B}{\begin{quote}\sffamily foo-B: #2\textsuperscript{2}\end{quote}} +% +% We still have to assign one or the other to the socket, thus without +% doing that the line +% \begin{verbatim} +% \UseSocket{foo}{hello}{world} +% \end{verbatim} +% produces nothing because the default plug for sockets with 2 inputs +% is \plug{noop} (which grabs the additional arguments and throws them +% away).\footnote{If socket \socket{foo} would have been a socket with one +% input, then the default plug would be \plug{identity}, in which case +% the socket input would remain without braces and gets typeset!} +% +% \UseSocket{foo}{hello}{world} ^^A nothing happens +% +% So let's do the assignment +% \begin{verbatim} +% \AssignSocketPlug{foo}{plug-A} +% \end{verbatim} +% and then +% \begin{verbatim} +% \UseSocket{foo}{hello}{world} +% \end{verbatim} +% will properly typeset +% \AssignSocketPlug{foo}{plug-A}\UseSocket{foo}{hello}{world} +% and after +% \begin{verbatim} +% \AssignSocketPlug{foo}{plug-B} +% \end{verbatim} +% and another call to +% \begin{verbatim} +% \UseSocket{foo}{hello}{world} +% \end{verbatim} +% we get +% \AssignSocketPlug{foo}{plug-B}\UseSocket{foo}{hello}{world} +% +% If we attempt to assign a plug that was not defined, e.g., +% \begin{verbatim} +% \AssignSocketPlug{foo}{plug-C} +% \end{verbatim} +% then we get an error during the assignment +% \begin{verbatim} +% ! LaTeX socket Error: Plug 'plug-C' for socket 'foo' undeclared! +% \end{verbatim} +% and the previous assignment remains in place. +% +% To see what is known about a socket and its plugs you can use +% \cs{ShowSocket} or \cs{LogSocket} which displays information similar +% to this on the terminal or in the transcript file: +% \begin{verbatim} +% Socket foo: +% number of inputs = 2 +% available plugs = noop, plug-A, plug-B +% current plug = plug-B +% definition = \protected\long macro:#1#2->\begin {quote}\sffamily +% foo-B: #2\textsuperscript {2}\end {quote} +% \end{verbatim} +% \LogSocket{foo} +% +% +% \subsubsection{Details and semantics} +% +% In this section we collect some normative statements. +% +% \begin{itemize} +% +% \item +% From a functional point of view sockets are like simple \TeX{} macros, +% i.e., they expect 0 to 9 mandatory arguments (the socket inputs) and get replaced by +% their \enquote{expansion} +% +% \item +% A socket is \enquote{named} and the name consists of ASCII letters +% \texttt{[a-z]}, +% \texttt{[A-Z]}, \texttt{[0-9]}, \texttt{[-/@]} only +% +% \item +% Socket names have to be unique, i.e., there can be only one socket +% named \meta{name}. This is ensured by declaring each socket with +% \cs{NewSocket}. +% +% However, there is no requirement that sockets and +% hook names have to be different. In fact, if a certain action that +% could overwise be specified as hook code has to be executed always +% last (or first) one could ensure this by placing a socket (single +% action) after a hook (or vice versa) and using the same name to +% indicate the relationship, e.g., +%\begin{verbatim} +% \UseHook{foo} % different package can add code here +% \UseSocket{foo} % only one package can assign a plug +%\end{verbatim} +% This avoids the need to order the hook code to ensure that +% something is always last. +% +% \item +% Best practice naming conventions are \ldots\ \emph{to be documented} +% +% \item +% A socket has documented inputs which are +% +% \begin{itemize} +% \item +% the positional arguments (if any) with a description of what +% they contain when used +% +% \item +% implicit data (registers and other 2e/expl3 data stores) that +% the socket is allowed to make use of, with a documented description +% of what they contain (if relevant for the task at hand---no need to +% describe the whole \LaTeX{} universe) +% +% \item +% information about the state of the \TeX{} engine (again when +% relevant), e.g. is called in mmode or vmode or in the output routine or \ldots +% +% \item +% \ldots\ \empty{anything missing?} +% \end{itemize} +% +% +% \item +% A socket has documented results/outputs which can be +% +% \begin{itemize} +% \item +% what kind of data it should write to the current list (if that +% is part of its task) +% +% \item +% what kind of registers and other 2e/expl3 data stores it should +% modify and in what way +% +% \item +% what kind of state changes it should do (if any) +% +% \item +% \emph{\ldots\ anything else?} +% \end{itemize} +% +% \item +% +% At any time a socket has one block of code (a plug \iffalse(\fi:-)\,) +% associated with it. Such code is itself named and the association +% is done by linking the socket name to the code name (putting a +% plug into the socket). +% +% \item +% +% The name of a plug consists of ASCII letters \texttt{[a-z]}, +% \texttt{[A-Z]}, \texttt{[0-9]}, \texttt{[-/@]} only. +% +% \item +% Socket plug names have to be unique within on a per socket basis, +% but it is perfectly allowed (and sensible in some cases) to use +% the same plug name with different sockets (where based on the +% sockets' purposes, different actions may be associated with the plug +% name). For example \plug{noop} is a plug name declared for every +% socket, yet it action \enquote{grab the socket inputs and throw +% them away} obviously differs depending on how many inputs the +% socket has. +% +% \item +% +% When declaring a plug it is stated for which socket it is meant +% (i.e., its code can only be used with that socket). This means +% that the same plug name can be used with different sockets +% referring to different code in each case. +% +% \item +% Configuration of a socket can only be done by +% linking different code to it. Nevertheless the code linked to it can +% provide its own means of configuration (but this is outside of the +% spec). +% +% \item +% Technically execution of a socket (\cs{UseSocket}) involves +% +% \begin{itemize} +% \item +% doing any house keeping (like writing debugging info, \ldots); +% +% \item +% looking up the current code association (what plug is in the socket); +% +% \item +% executing this code which will pick up the mandatory arguments +% (happens at this point, not +% before), i.e., it is like calling a csname defined with +% \begin{verbatim} +% \def\foo#1#2...{...#1...#2...} +% \end{verbatim} +% +% \item +% do some further house keeping (if needed). +% \end{itemize} +% +% \item +% A socket is typically only used in one place in code, but this is not +% a requirement, i.e., if the same operation with the same inputs need +% to be carried out in several places the same named socket can be used. +% +% \end{itemize} +% +% +% +% +% +% \subsubsection{Command syntax} +% +% We give both the \LaTeXe{} and the L3 programming layer command names. +% +% \begin{function}{\NewSocket,\socket_new:nn} +% \begin{syntax} +% \cs{NewSocket} \Arg{socket-name}\Arg{number-of-inputs} +% \cs{socket_new:nn}\Arg{socket-name}\Arg{number-of-inputs} +% \end{syntax} +% Declares a new socket with name \meta{socket-name} having +% \meta{number-of-inputs} inputs. There is automatically a +% plug \plug{noop} declared for it, which does nothing, i.e., it gobbles +% the socket inputs (if any). This is made the default plug except for +% sockets with one input which additionally define the plug +% \plug{identity} and assign that as their default. +% +% This \plug{identity} plug simply returns the socket input without +% its outer braces. +% The use case for this plug are situations like this: +% \begin{quote} +% \cs{UseSocket}\verb={tagsupport/footnote}=\Arg{code} +% \end{quote} +% If tagging is not active and the socket contains the plug \plug{identity} +% then this returns \meta{code} without the outer braces and to +% activate tagging all that is necessary is to change the plug to +% say \plug{tagpdf} so +% that it surrounds \meta{code} by some tagging magic. +% This is the most common use case for sockets with one input, which +% is why they have this special default. +% +% The socket documentation should describe its purpose, its inputs and the +% expected results as discussed above. +% +% The declaration is only allowed at top-level, i.e., not inside a group. +% \end{function} +% +% +% \begin{function}{\NewSocketPlug,\socket_new_plug:nnn,\socket_set_plug:nnn} +% \begin{syntax} +% \cs{NewSocketPlug} \Arg{socket-name}\Arg{socket-plug-name}\Arg{code} +% \cs{socket_new_plug:nnn}\Arg{socket-name}\Arg{socket-plug-name}\Arg{code} +% \cs{socket_set_plug:nnn}\Arg{socket-name}\Arg{socket-plug-name}\Arg{code} +% \end{syntax} +% Declares a new plug for socket \meta{socket-name} that runs +% \meta{code} when executing. It complains if the plug was already +% declared previously. +% +% The form \cs{socket_set_plug:nnn} changes an existing plug. As +% this should normally not be necessary, we currently have only an L3 +% layer name for the few cases it might be useful. +% +% The declarations can be made inside a group and obey scope, i.e., +% they vanish if the group ends. +% \end{function} +% +% +% \begin{function}{\AssignSocketPlug,\socket_assign_plug:nn} +% \begin{syntax} +% \cs{AssignSocketPlug} \Arg{socket-name}\Arg{socket-plug-name} +% \cs{socket_assign_plug:nn}\Arg{socket-name}\Arg{socket-plug-name} +% \end{syntax} +% Assigns the plug \meta{socket-plug-name} to the socket +% \meta{socket-name}. It errors if either socket or plug is not +% defined. +% +% The assignment is local, i.e., it obeys scope. +% \end{function} +% +% +% \begin{function}{\UseSocket,\socket_use:nw,\socket_use:n,\socket_use:nn,\socket_use:nnn,\socket_use:nnnn} +% \begin{syntax} +% \cs{UseSocket} \Arg{socket-name} +% \cs{socket_use:nnn}\Arg{socket-name} \Arg{socket-arg\textsubscript{1}} \Arg{socket-arg\textsubscript{2}} +% \end{syntax} +% Executes the socket \meta{socket-name} by retrieving the +% \meta{code} of the current plug assigned to the socket. This is +% the only command that would appear inside macro code in packages. +% +% For performance reasons there is no explicit check that the socket +% was declared! +% +% The different L3 programming layer commands are really doing the +% same thing: they grab as many arguments as defined as inputs for the socket +% and then pass them to the plug. The different names are only there +% to make the code more readable, i.e., to indicate how many +% arguments are grabbed in total (note that no runtime check is made to +% verify that this is actually true). We only provide them for +% sockets with up to 3 inputs (most likely those with zero or one input would +% have been sufficient). If you happen to have a socket with more +% inputs, use \cs{socket_use:nw}. +% \end{function} +% +% +% \begin{function}{\ShowSocket,\LogSocket,\socket_show:n,\socket_log:n} +% \begin{syntax} +% \cs{ShowSocket} \Arg{socket-name} +% \cs{socket_show:n}\Arg{socket-name} +% \end{syntax} +% Displays information about the socket \meta{socket-name} and its +% state then stops and waits for further instructions --- at the +% moment some what rudimentary. +% +% \cs{LogSocket} and \cs{socket_log:n} only differ in that they don't stop. +% \end{function} +% +% +% \begin{function}{\DebugSocketsOn,\DebugSocketsOff, +% \socket_debug_on:,\socket_debug_off:} +% \begin{syntax} +% \cs{DebugSocketsOn} \ldots\ \cs{DebugSocketsOff} +% \end{syntax} +% Turns debugging of sockets on or off. +% \end{function} +% +% \subsubsection{Rationale for error handling} +% +% The errors during the declarations are produced to help with +% typos---after all, such declarations might be part of a document +% preamble (not that likely, but possible). However, \cs{UseSocket} is +% not doing much checking, e.g., +% \begin{verbatim} +% \UseSocket{mispelled-socket}{hello}{world} +% \end{verbatim} +% will generate a rather low-level error and then typesets +% ``{hello}{world}'' because there is no dedicated runtime check if +% \texttt{mispelled-socket} is a known socket. +% +% The reason is that if the misspelling is in the code, then this is a +% programming error in the package and for speed reasons \LaTeX{} does +% not repeately make runtime checks for coding errors unless they can or +% are likely to be user introduced. +% +% +% \MaybeStop{\setlength\IndexMin{200pt} \PrintIndex } +% +% +% \section{The Implementation} +% +% The implementation of the socket mechanism should be (partially) +% redone and we should probably store the different code chunks in +% a property list so that we can have a decent \cs{ShowSocket} +% command that shows the available alternatives.\fmi{implement?} +% +% \begin{macrocode} +%<*2ekernel|latexrelease> +% \end{macrocode} +% +% \begin{macrocode} +\ExplSyntaxOn +% \end{macrocode} +% +% \begin{macrocode} +%<@@=socket> +% \end{macrocode} +% +% \begin{macrocode} +%<latexrelease>\NewModuleRelease{2023/11/01}{ltsockets} +%<latexrelease> {The~socket~management~system} +% \end{macrocode} +% +% +% +% \subsection{Debugging the socket structures} +% +% Code and commands in this section are not final, it needs more +% experimentation to see what kind of tracing information is going to +% be useful in practice. For now the tracing is mainly meant to be used +% for code testing and not so much for application testing. +% +% It is quite likely that the +% commands and the behavior of the tracing might change in the +% future once we gained some experience with it. +% +% \begin{macro}{\g_@@_debug_bool} +% Holds the current debugging state. +% \begin{macrocode} +\bool_new:N \g_@@_debug_bool +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\socket_debug_on:,\socket_debug_off:} +% \begin{macro}{\@@_debug:n, \@@_debug_term:n} +% \begin{macro}{\@@_debug_gset:} +% Turns debugging on and off by redefining \cs{@@_debug:n} and +% \cs{@@_debug_term:n}. By default they do nothing. +% \begin{macrocode} +\cs_new_eq:NN \@@_debug:n \use_none:n +\cs_new_eq:NN \@@_debug_term:n \use_none:n +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_protected:Npn \socket_debug_on: + { + \bool_gset_true:N \g_@@_debug_bool + \@@_debug_gset: + } +\cs_new_protected:Npn \socket_debug_off: + { + \bool_gset_false:N \g_@@_debug_bool + \@@_debug_gset: + } +\cs_new_protected:Npn \@@_debug_gset: + { + \cs_gset_protected:Npx \@@_debug:n ##1 + { \bool_if:NT \g_@@_debug_bool {##1} } + \cs_gset_protected:Npx \@@_debug_term:n ##1 + { \bool_if:NT \g_@@_debug_bool + { \iow_term:x { ^^J [Sockets]~ ==>~ ##1} } } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsection{The L3 layer commands} +% +% \begin{macro}{\socket_new:nn} +% +% Declaring a socket creates a str to hold the name (a pointer) to the +% code that should be used when the socket is executed, and an integer to +% hold the number of inputs of that socket. Initially, an +% ``empty'' code chunk is created and assigned so the socket +% does nothing by default other than swallowing its inputs (if any). +% \begin{macrocode} +\cs_new_protected:Npn \socket_new:nn #1 #2 { + \str_if_exist:cTF { l_@@_#1_plug_str } + { + \msg_error:nnn { socket } { already-declared } {#1} + } + { +% \end{macrocode} +% We only support declarations on top-level. +% \begin{macrocode} + \int_if_zero:nTF \tex_currentgrouplevel:D + { + \str_new:c { l_@@_#1_plug_str } + \seq_new:c { l_@@_#1_plugs_seq } + \int_const:cn { c_@@_#1_args_int } {#2} + \socket_new_plug:nnn {#1} { noop } {} + \int_compare:nNnTF {#2} = 1 + { + \socket_new_plug:nnn {#1} { identity } {##1} + \socket_assign_plug:nn {#1} { identity } + } + { \socket_assign_plug:nn {#1} { noop } } + \@@_debug_term:n + { Socket~ '#1'~ declared~ with~ #2~ input(s) } + } + { + \msg_error:nn { socket } { not-top-level } + } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\socket_log:n,\socket_show:n} +% Show the current state of the socket --- for now this is just a +% quick draft and should be redone and extended. +% \begin{macrocode} +\cs_new_protected:Npn \socket_log:n #1 { + \typeout{ Socket~ #1:} + \str_if_exist:cTF { l_@@_#1_plug_str } + { + \typeout{ \@spaces number~ of~ inputs~ =~ + \int_use:c { c_@@_#1_args_int } } + \typeout{ \@spaces available~plugs~ =~ + \seq_use:cnnn { l_@@_#1_plugs_seq }{,~}{,~}{,~} } + \typeout{ \@spaces current~ plug~ =~ + \str_use:c { l_@@_#1_plug_str } } + \typeout{ \@spaces definition~ =~ + \cs_meaning:c + { @@_#1_plug_ \str_use:c { l_@@_#1_plug_str } :w } } + \typeout{} + } + { +% \end{macrocode} +% If we are showing a socket it is not an error if it doesn't exist. +% \begin{macrocode} + \typeout { Socket~ is~ not~ declared! } + } +} +% \end{macrocode} +% And here the version that stops: +% \begin{macrocode} +\cs_new_protected:Npn \socket_show:n #1 {\socket_log:n {#1} \errmessage{}} +% \end{macrocode} +% \end{macro} +% +% +% +% +% +% \begin{macro}{\socket_new_plug:nnn,\socket_set_plug:nnn} +% +% Declaring a code for a socket is just making a definition, taking +% the number of arguments from the saved int. +% \begin{macrocode} +\cs_new_protected:Npn \socket_new_plug:nnn #1#2#3 { + \str_if_exist:cTF { l_@@_#1_plug_str } + { + \cs_if_exist:cTF { @@_#1_plug_#2:w } + { + \msg_error:nnnn { socket } { plug-already-declared } {#1} {#2} + } + { + \cs_generate_from_arg_count:cNnn + { @@_#1_plug_#2:w } + \cs_new_protected:Npn + { \int_use:c { c_@@_#1_args_int } } + {#3} +% \end{macrocode} +% This is a new declaration so we add the name to a seq for the +% debugging info. +% \begin{macrocode} + \seq_put_right:cn { l_@@_#1_plugs_seq } {#2} + \@@_debug_term:n + { Plug~ '#2'~ for~ socket~ '#1'~ declared. } + } + } + { + \msg_error:nnn { socket } { undeclared } {#1} + } +} +% \end{macrocode} +% Changing the plug of an existing socket is rather similar, except +% that we don't have to deal with adding it to the debugging +% sequence. +% \begin{macrocode} +\cs_new_protected:Npn \socket_set_plug:nnn #1#2#3 { + \str_if_exist:cTF { l_@@_#1_plug_str } + { + \cs_if_exist:cTF { @@_#1_plug_#2:w } + { + \cs_generate_from_arg_count:cNnn + { @@_#1_plug_#2:w } + \cs_set_protected:Npn + { \int_use:c { c_@@_#1_args_int } } + {#3} + \@@_debug_term:n + { Plug~ '#2'~ for~ socket~ '#1'~ changed. } + } + { + \msg_error:nnnn { socket } { plug-undeclared } {#1} {#2} + } + } + { + \msg_error:nnn { socket } { undeclared } {#1} + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\socket_assign_plug:nn} +% +% Assigning a plug to a socket just changes the name in +% the socket string. The assignment is local to the current group. +% \begin{macrocode} +\cs_new_protected:Npn \socket_assign_plug:nn #1 #2 { + \str_if_exist:cTF { l_@@_#1_plug_str } + { + \cs_if_exist:cTF { @@_#1_plug_#2:w } + { + \@@_debug_term:n + { Replacing~ plug~ '\str_use:c { l_@@_#1_plug_str }'~ + with~ '#2'~ in~ socket~ '#1'. } + \str_set:cn { l_@@_#1_plug_str } {#2} + } + { + \msg_error:nnnn { socket } { plug-undeclared } {#1} {#2} + } + } + { \msg_error:nnn { socket } { undeclared } {#1} } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\socket_use:nw,\socket_use:n,\socket_use:nn,\socket_use:nnn,\socket_use:nnnn} +% +% And using it is more or less a \cs{use:c} so very lightweight. We do not +% add a runtime check for speed reasons! +% +% This command is named +% \cs{socket_use:nw} because we don't know how many inputs the +% socket has until we have looked at the socket name (in argument \verb=#1=). +% But, of course, the developer knows so we also offer a few aliases +% \cs{socket_use:nn}, etc.\ so that one can indicate the correct number of +% arguments (socket inputs plus one) in the L3 layer code. +% +% \begin{macrocode} +\cs_new_protected:Npn \socket_use:nw #1 { + \@@_debug_term:n + { Socket~ '#1'~ containing~ plug~ + '\str_use:c { l_@@_#1_plug_str }'~ used. } + \use:c { @@_#1_plug_ \str_use:c { l_@@_#1_plug_str } :w } +} +% \end{macrocode} +% To make code a bit more readable we also define functions that +% indicate how many arguments are picked up. However, this is just for +% code documentation: internally they all do the same and the number +% of arguments isn't checked by default. +% \begin{macrocode} +\cs_new_eq:NN \socket_use:n \socket_use:nw % socket with no inputs +\cs_new_eq:NN \socket_use:nn \socket_use:nw % socket with one input +\cs_new_eq:NN \socket_use:nnn \socket_use:nw % socket with two inputs +\cs_new_eq:NN \socket_use:nnnn \socket_use:nw % socket with three inputs +% \end{macrocode} +% The above commands could be changed to check how many inputs +% the socket is declared with (for example, when checking is in +% force). +% \fmi{Implement?} +% \end{macro} +% +% +% +% +% +% +% +% \subsection{Error messages} +% + +% +% \begin{macrocode} +\msg_new:nnnn { socket } { already-declared } + { Socket~ '#1'~ already~ declared! } + { A~ socket~ can~ only~ be~ declared~ once.~ The~ name~ '#1'~ is~ + already~ taken.~ Use~ \ShowSocket{#1}~ to~ see~ its~ definition. } + +\msg_new:nnnn { socket } { undeclared } + { Socket~ '#1'~ undeclared! } + { You~ tried~ to~ use~ a~ socket~ that~ was~ not~ declared~ before. } + +\msg_new:nnnn { socket } { not-top-level } + { Sockets~ can~ only~ be~ declared~ at~ top-level! } + { It~ is~ not~ allowed~ to~ declare~ sockets~ inside~ a~ + group.~ Move~ the~ declaration~ to~ the~ top-level. } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnnn { socket } { plug-already-declared } + { Plug~ '#2'~ for~ socket~ '#1'~ already~ declared! } + { You~ can't~ change~ an~ existing~ plug~ with~ \NewSocketPlug~ and~ it~ + is~ normally~ not~ sensible~ to~ do~ so.~ Use~ the~ L3~ programming~ + layer~ function~ \socket_set_plug:nnn~ if~ you~ really~ have~ to. } + +\msg_new:nnnn { socket } { plug-undeclared } + { Plug~ '#2'~ for~ socket~ '#1'~ undeclared! } + { The~ plug~ name~ is~ unknown.~ Is~ the~ name~ misspelled~ or~ did~ you~ + intend~ to~ assign~ it~ to~ a~ different~ socket? } +% \end{macrocode} +% +% \begin{macrocode} +\prop_gput:Nnn \g_msg_module_type_prop { socket } { LaTeX } +% \end{macrocode} +% +% +% +% +% \subsection{The \LaTeXe{} interface commands} +% +% \begin{macro}{\NewSocket,\NewSocketPlug, +% \ShowSocket,\LogSocket, +% \AssignSocketPlug,\UseSocket, +% \DebugSocketsOn,\DebugSocketsOff} +% As we expect that there are existing \LaTeXe{} packages that may +% want to make use of the socket mechanism, we provide 2e names for +% most of the commands. +% \begin{macrocode} +\cs_new_eq:NN \NewSocket \socket_new:nn +\cs_new_eq:NN \ShowSocket \socket_show:n +\cs_new_eq:NN \LogSocket \socket_log:n +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_eq:NN \NewSocketPlug \socket_new_plug:nnn +\cs_new_eq:NN \AssignSocketPlug \socket_assign_plug:nn +\cs_new_eq:NN \UseSocket \socket_use:nw +% \end{macrocode} +% +% \begin{macrocode} +\cs_new_eq:NN \DebugSocketsOn \socket_debug_on: +\cs_new_eq:NN \DebugSocketsOff \socket_debug_off: +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macrocode} +% +%<latexrelease>\IncludeInRelease{0000/00/00}{ltsockets} +%<latexrelease> {The~socket~management~(undo)}% +%<latexrelease> +%<latexrelease>\let \NewSocket \@undefined +%<latexrelease>\let \ShowSocket \@undefined +%<latexrelease>\let \LogSocket \@undefined +%<latexrelease> +%<latexrelease>\let \NewSocketPlug \@undefined +%<latexrelease>\let \AssignSocketPlug \@undefined +%<latexrelease>\let \UseSocket \@undefined +%<latexrelease> +%<latexrelease>\let \DebugSocketsOn \@undefined +%<latexrelease>\let \DebugSocketsOff \@undefined +%<latexrelease> +%<latexrelease>\EndModuleRelease +% \end{macrocode} +% +% \begin{macrocode} +\ExplSyntaxOff +% \end{macrocode} +% +% \begin{macrocode} +%</2ekernel|latexrelease> +% \end{macrocode} +% +% Reset module prefix: +% \begin{macrocode} +%<@@=> +% \end{macrocode} +% +% +% \Finale +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\endinput + + + +^^A Needed for emacs +^^A +^^A Local Variables: +^^A mode: latex +^^A coding: utf-8-unix +^^A End: + + + diff --git a/Master/texmf-dist/source/latex-dev/base/ltspace.dtx b/Master/texmf-dist/source/latex-dev/base/ltspace.dtx index a77314b1bd1..66841cae384 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltspace.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltspace.dtx @@ -32,7 +32,7 @@ %<*driver> % \fi \ProvidesFile{ltspace.dtx} - [2023/05/26 v1.3p LaTeX Kernel (spacing)] + [2023/06/14 v1.3q LaTeX Kernel (spacing)] % \iffalse \documentclass{ltxdoc} \GetFileInfo{ltspace.dtx} @@ -1223,9 +1223,24 @@ % \end{macro} % \end{macro} % +% \begin{macro}{\@xobeytab} +% \changes{v1.3q}{2023/06/14}{Macro added} +% Equivalent to the space case with the default settings. % \begin{macrocode} +%</2ekernel> +%<latexrelease>\IncludeInRelease{2023/11/01}% +%<latexrelease> {\@xobeytab}{Obeyed tabs}% +%<*2ekernel|latexrelease> +\let\@xobeytab\@xobeysp +%</2ekernel|latexrelease> +%<latexrelease>\EndIncludeInRelease +%<latexrelease>\IncludeInRelease{0000/00/00}% +%<latexrelease> {\@xobeytab}{Obeyed tabs}% +%<latexrelease>\let\@xobeytab\@undefined +%<latexrelease>\EndIncludeInRelease +%<*2ekernel> % \end{macrocode} -% +% \end{macro} % % % \begin{macro}{\@} diff --git a/Master/texmf-dist/source/latex-dev/base/ltvers.dtx b/Master/texmf-dist/source/latex-dev/base/ltvers.dtx index 5b124febd9e..5b78c3bc5ed 100644 --- a/Master/texmf-dist/source/latex-dev/base/ltvers.dtx +++ b/Master/texmf-dist/source/latex-dev/base/ltvers.dtx @@ -115,7 +115,7 @@ {2023-11-01} %</2ekernel|latexrelease> %<*2ekernel> -\def\patch@level{-0} +\def\patch@level{-1} % \end{macrocode} % % \begin{macro}{\development@branch@name} diff --git a/Master/texmf-dist/source/latex-dev/firstaid/firstaid.ins b/Master/texmf-dist/source/latex-dev/firstaid/firstaid.ins index cd5ea2006db..b3f30c30daa 100644 --- a/Master/texmf-dist/source/latex-dev/firstaid/firstaid.ins +++ b/Master/texmf-dist/source/latex-dev/firstaid/firstaid.ins @@ -3,7 +3,7 @@ %% driver files from the doc files in this package when run through %% LaTeX or TeX. %% -%% Copyright (C) 2020-2021 +%% Copyright (C) 2020-2023 %% The LaTeX Project and any individual authors listed elsewhere %% in this file. %% @@ -44,7 +44,7 @@ reports for it can be opened at https://latex-project.org/bugs/ (but please observe conditions on bug reports sent to that address!) -Copyright (C) 2020-2021 +Copyright (C) 2020-2023 The LaTeX Project and any individual authors listed elsewhere in this file. @@ -72,7 +72,4 @@ without such generated files. \generate{\file{filehook-ltx.sty} {\from{latex2e-first-aid-for-external-files.dtx}{filehook-ltx}}} -\generate{\file{everysel-ltx.sty} - {\from{latex2e-first-aid-for-external-files.dtx}{everysel-ltx}}} - \endbatchfile diff --git a/Master/texmf-dist/source/latex-dev/firstaid/latex2e-first-aid-for-external-files.dtx b/Master/texmf-dist/source/latex-dev/firstaid/latex2e-first-aid-for-external-files.dtx index 90958ed7776..d1eeaf5ce2a 100644 --- a/Master/texmf-dist/source/latex-dev/firstaid/latex2e-first-aid-for-external-files.dtx +++ b/Master/texmf-dist/source/latex-dev/firstaid/latex2e-first-aid-for-external-files.dtx @@ -111,8 +111,8 @@ % \end{macrocode} % % \begin{macrocode} -\def\LaTeXFirstAidDate{2023/05/20} -\def\LaTeXFirstAidVersion{v1.0z} +\def\LaTeXFirstAidDate{2023/07/18} +\def\LaTeXFirstAidVersion{v1.1a} % \end{macrocode} % % \begin{macrocode} @@ -285,62 +285,10 @@ %</filehook-ltx> % \end{macrocode} % -% -% -% -% \subsection{The \pkg{bidi} package first aid} -% -% The \pkg{bidi} package adds a lot of hooks in various places and -% those added to \cs{document} and \cs{enddocument} are now no -% longer necessary as the kernel already provides the right hooks -% there. -% -% However, we aren't trying to change that but instead only make -% sure that the existing patches still work by adding some first -% aid after \pkg{biditools} has been loaded. -% -% If the package gets updated one can easily take that out simply -% through -%\begin{verbatim} -% \RemoveFromHook{file/biditools.sty/after}[firstaid] -%\end{verbatim} -% This makes it easy to test new bidi code while the first aid code -% is still in the kernel. -% % \begin{macrocode} %<*kernel> % \end{macrocode} % -% Bidi is now ar a new version: patches are no longer needed. -% \begin{macrocode} -%\AddToHook{file/biditools.sty/after}[firstaid]{% -% \FirstAidNeededT{biditools}{sty}% -% {2020/05/13 v2 Programming tools for bidi package}% -% {% -% \end{macrocode} -% \pkg{bidi} adds some code to the beginning of \cs{document} which -% contains \cs{endgroup} and \cs{begingroup} which is no longer -% correct. -% -% Patching \cs{document} using \cs{bidi@patchcmd} doesn't work so -% we take the extra groups out by hand: -% \begin{macrocode} -% \def\firstaid@bidi@document@patch -% \endgroup#1\begingroup#2\firstaid@bidi@document@patch -% {\unexpanded{#1#2}}% -% \edef\document{\expandafter\firstaid@bidi@document@patch\document -% \firstaid@bidi@document@patch}% -% \end{macrocode} -% There are also some patches into \cs{enddocument}, some continue -% to go in but one fails, so we add that now into the right place. -% \begin{macrocode} -% \AddToHook{enddocument/info}% -% {\let\bidi@AfterEndDocumentCheckLabelsRerun\@firstofone -% \bidi@afterenddocumentchecklabelsrerunhook}% -% }% -%} -% \end{macrocode} -% % \subsection{The \pkg{dinbrief} class first aid} % % Again a case of a no longer correct \cs{endgroup} in document. @@ -482,46 +430,6 @@ %</kernel> % \end{macrocode} % -% \subsection{The \pkg{everysel} package first aid} -% -% -% The \cs{selectfont} command got a hook (with the 2021/05 release) which -% was originally provided by the \pkg{everysel} -% package. Now that it is in the kernel this package is no longer -% needed (or only in a simplified manner). -% -% If it is requested we replace it with a simplified package -% (until) it gets updated at which point this line can be removed. -% \changes{v2.2k}{2020/12/04}{Emulate everysel package} -% \begin{macrocode} -%<*kernel> -% this has been updated -%\declare@file@substitution{everysel.sty}{everysel-ltx.sty} -%</kernel> -% \end{macrocode} -% -% -% -% \begin{macrocode} -%<*everysel-ltx> -\ProvidesPackage{everysel-ltx} - [2020/12/04 v1.0a - Emulation of the original everysel^^Jpackage with kernel methods] -% \end{macrocode} -% -% \begin{macrocode} -\newcommand*{\EverySelectfont}[1] - {\AddToHook{selectfont}{#1}} -\newcommand*{\AtNextSelectfont}[1] - {\AddToHookNext{selectfont}{#1}} -% \end{macrocode} -% -% -% \begin{macrocode} -%</everysel-ltx> -% \end{macrocode} -% -% % % \begin{macrocode} %<*kernel> @@ -652,31 +560,6 @@ } % \end{macrocode} % -% -% \subsection{First aid for \pkg{memoir}} -% -% The introduction of \cs{stockheight} and \cs{stockwidth} into the -% kernel requires some first aid. This has to go in \emph{before} -% loading the class, so we cannot check the version string here. -% \begin{macrocode} -\AddToHook{file/memoir.cls/before}[firstaid]{% - \expandafter\def\expandafter\@tempa\string\dimen{}% - \edef\kernel@stockheight{\expandafter\@tempa\meaning\stockheight}% - \edef\kernel@stockwidth{\expandafter\@tempa\meaning\stockwidth}% - \let\stockheight\@undefined - \let\stockwidth\@undefined -} -\AddToHook{file/memoir.cls/after}[firstaid]{% - \dimen\kernel@stockheight=\stockheight - \dimen\kernel@stockwidth=\stockwidth - \dimendef\stockheight=\kernel@stockheight - \dimendef\stockwidth=\kernel@stockwidth -} -% \end{macrocode} -% -% -% -% % \begin{macrocode} %</kernel> % \end{macrocode} |