diff options
author | Norbert Preining <norbert@preining.info> | 2023-01-31 03:01:43 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2023-01-31 03:01:43 +0000 |
commit | 7c33483242d8e20f8f809e76ec9a3406db2dbfab (patch) | |
tree | a6b1f262cb5d0ec3041fddac57b41ed134c1e9ed /macros | |
parent | 326add29024271cbd541ac55448e616e833ae5fa (diff) |
CTAN sync 202301310301
Diffstat (limited to 'macros')
39 files changed, 1423 insertions, 348 deletions
diff --git a/macros/latex/contrib/eolang/eolang.dtx b/macros/latex/contrib/eolang/eolang.dtx index d65c2092bd..f49cc47530 100644 --- a/macros/latex/contrib/eolang/eolang.dtx +++ b/macros/latex/contrib/eolang/eolang.dtx @@ -50,7 +50,7 @@ %<package>\NeedsTeXFormat{LaTeX2e} %<package>\ProvidesPackage{eolang} %<*package> -[2023-01-22 0.10.0 Formulas and Graphs for EO Programming Language] +[2023-01-30 0.11.0 Formulas and Graphs for EO Programming Language] %</package> %<*driver> \documentclass{ltxdoc} @@ -96,8 +96,7 @@ % and later formalized by \citet{kudasov2021}. Here is how you render % a simple expression: % \begin{docshot} -% \documentclass{article} -% \pagestyle{empty} +% \documentclass{minimal} % \usepackage{eolang} % \begin{document} % \begin{phiquation*} @@ -826,7 +825,7 @@ $tex =~ s/([^\\{a-z0-9]|^)Q(?![a-z0-9])/\1\\Phi{}/g; $tex =~ s/([^\\{a-z0-9]|^)D>/\1\\Delta{}..>/g; $tex =~ s/([^\\{a-z0-9]|^)L>/\1\\lambda{}..>/g; $tex =~ s/"([^"]+)"/|"\1"|/g; -$tex =~ s/(^|(?<=[\s)(\]\[,.>\/]))([a-z][a-z0-9]+)(?=[\s)(\]\[,.-]|$)/|\2|/g; +$tex =~ s/(^|(?<=[\s)(\]\[,.>\/]))([a-zA-Z][a-z0-9]+)(?=[\s)(\]\[,.-]|$)/|\2|/g; $tex =~ s/([^^_]|^)([0-9]+|\*)\/(\\?[a-z]+|\|[a-z]+\|) (->|\.\.>|~>|:=|!->)/\1\\alpha_{\2}\\vert{}\3\\space{}\4/xg; $tex =~ s/([^^_]|^)([0-9]+|\*) @@ -863,8 +862,8 @@ if ($macro ne 'phiq') { } $tex =~ s/\$/\\xi{}/g; $tex =~ s/(?<!\{)\^/\\rho{}/g; -$tex =~ s/\[\[/\\llbracket\\mathrel{}/g; -$tex =~ s/\]\]/\\mathrel{}\\rrbracket{}/g; +$tex =~ s/\[\[/\\llbracket\\mathbin{}/g; +$tex =~ s/\]\]/\\mathbin{}\\rrbracket{}/g; $tex =~ s/([\s,>(])([0-9A-F]{2}(?:-[0-9A-F]{2})+| [0-9]+(?:\.[0-9]+)?)(?!\{)/\1|\2|/xg; $tex =~ s/TRUE/|TRUE|/g; @@ -872,12 +871,12 @@ $tex =~ s/FALSE/|FALSE|/g; $tex =~ s/\?/\\varnothing{}/g; $tex =~ s/@/\\varphi{}/g; $tex =~ s/-([a-z]+)>/\\mathrel{\\phiSlot{\1}}/g; -$tex =~ s/!->/\\mathrel{\\phiConst}/g; -$tex =~ s/->/\\mathrel{\\mapsto}/g; -$tex =~ s/~>/\\mathrel{\\phiWave}/g; +$tex =~ s/!->/\\mathbin{\\phiConst}/g; +$tex =~ s/->/\\mathbin{\\mapsto}/g; +$tex =~ s/~>/\\mathbin{\\phiWave}/g; $tex =~ s/:=/\\mathrel{\\vDash}/g; $tex =~ s/==/\\mathrel{\\equiv}/g; -$tex =~ s/\.\.>/\\mathrel{\\phiDotted}/g; +$tex =~ s/\.\.>/\\mathbin{\\phiDotted}/g; $tex =~ s/<</\\langle/g; $tex =~ s/>>/\\rangle/g; $tex =~ s/\|{2,}/|/g; diff --git a/macros/latex/contrib/eolang/eolang.pdf b/macros/latex/contrib/eolang/eolang.pdf Binary files differindex 5f74ed44f4..c97623759b 100644 --- a/macros/latex/contrib/eolang/eolang.pdf +++ b/macros/latex/contrib/eolang/eolang.pdf diff --git a/macros/latex/contrib/naive-ebnf/naive-ebnf.dtx b/macros/latex/contrib/naive-ebnf/naive-ebnf.dtx index 6213cf6d52..cdd047a30f 100644 --- a/macros/latex/contrib/naive-ebnf/naive-ebnf.dtx +++ b/macros/latex/contrib/naive-ebnf/naive-ebnf.dtx @@ -50,7 +50,7 @@ %<package>\NeedsTeXFormat{LaTeX2e} %<package>\ProvidesPackage{naive-ebnf} %<*package> -[2023-01-29 0.0.2 EBNF in Plain Text] +[2023-01-30 0.0.3 EBNF in Plain Text] %</package> %<*driver> \documentclass{ltxdoc} @@ -81,7 +81,7 @@ % % \section{Introduction} % -% This package helps render a +% This package helps render an % \href{https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form}{Extended Backus-Naur Form} % using plain text notation: % \begin{docshot} @@ -97,6 +97,8 @@ % \end{document} % \end{docshot} +% \DescribeMacro{ebnf} +% The |ebnf| environment \emph{doesn't} add any formatting to the paragraph, but only replaces the plain text symbols, such as ``|:=|'' and ``|<Var>|'' with proper \LaTeX{} commands. % The following syntax is understood inside the |ebnf| environment: % \begin{itemize} % \item |:=| separates the left-hand side from the right-hand side of the production rule; @@ -133,6 +135,19 @@ % with \terminal{)}. % \end{document} % \end{docshot} +% It's possible to use them in math-mode too, for example: +% \docshotOptions{firstline=6,lastline=8} +% \begin{docshot} +% \documentclass{article} +% \pagestyle{empty} +% \usepackage[paperwidth=3in]{geometry} +% \usepackage{naive-ebnf} +% \begin{document} +% If $\terminal{(} f_1 \nonterminal{Var} +% \terminal{)}$ is always true, then +% $f_1$ is a tautology. +% \end{document} +% \end{docshot} % \section{Package Options} @@ -187,12 +202,15 @@ % \begin{macro}{\terminal} % \changes{0.0.2}{2023/01/29}{New command \texttt{\char`\\terminal} added, to enable rendering terminal symbols outside of the \texttt{ebnf} environment.} +% \changes{0.0.3}{2023/01/30}{Quotes fixed in both text and math modes.} % Then, we a command to render a single terminal: % \begin{macrocode} \makeatletter -\newcommand\terminal[1]{% +\newcommand\terminal[1]{{% \relax\ifmmode\else\ttfamily\fi% - \ebnf@color{gray}{"}#1\ebnf@color{gray}{"}} + \ebnf@color{gray}{\relax\ifmmode\textsf{``}\else{\sffamily``}\fi}% + #1% + \ebnf@color{gray}{\relax\ifmmode\textsf{''}\else{\sffamily''}\fi}}} \makeatother % \end{macrocode} % \end{macro} @@ -202,8 +220,10 @@ % Then, we a command to render a single non-terminal: % \begin{macrocode} \makeatletter -\newcommand\nonterminal[1] - {\(\ebnf@color{gray}{\langle}\textsf{#1}\ebnf@color{gray}{\rangle}\)} +\newcommand\nonterminal[1]{% + \ebnf@color{gray}{\relax\ifmmode\langle\else\(\langle\)\fi}% + \relax\ifmmode\textsf{#1}\else{\sffamily#1}\fi% + \ebnf@color{gray}{\relax\ifmmode\rangle\else\(\rangle\)\fi}} \makeatother % \end{macrocode} % \end{macro} diff --git a/macros/latex/contrib/naive-ebnf/naive-ebnf.pdf b/macros/latex/contrib/naive-ebnf/naive-ebnf.pdf Binary files differindex fdf6d14f90..cfb0270b4c 100644 --- a/macros/latex/contrib/naive-ebnf/naive-ebnf.pdf +++ b/macros/latex/contrib/naive-ebnf/naive-ebnf.pdf diff --git a/macros/latex/contrib/pseudo/LICENSE b/macros/latex/contrib/pseudo/LICENSE index f0b6409bee..b0f5b7852d 100644 --- a/macros/latex/contrib/pseudo/LICENSE +++ b/macros/latex/contrib/pseudo/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019-2022 Magnus Lie Hetland +Copyright (c) 2019-2023 Magnus Lie Hetland Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/macros/latex/contrib/pseudo/Makefile b/macros/latex/contrib/pseudo/Makefile index b8b64dcd5e..309974597c 100644 --- a/macros/latex/contrib/pseudo/Makefile +++ b/macros/latex/contrib/pseudo/Makefile @@ -2,7 +2,7 @@ TARGETS=doc/pseudo.pdf doc/fig/readmefig.svg LATEX=latexmk -norc -pdf -auxdir=build -outdir=build FIGS=build/hilitefig.pdf build/pausefig.pdf build/kwfig.pdf -TESTS=build/pseudotest.pdf +TESTS=build/pseudotest.pdf build/beamertest.pdf all: $(TARGETS) @@ -27,6 +27,9 @@ build/kwfig.pdf: doc/fig/kwfig.tex pseudo.sty build/pseudotest.pdf: test/pseudotest.tex pseudo.sty $(LATEX) $< +build/beamertest.pdf: test/beamertest.tex pseudo.sty + $(LATEX) $< + pseudo.sty: VERSION LICENSE doc/pseudo.tex cat LICENSE | sed -e "s/^/% /" | sed -e "s/^% \$$/%/" > pseudo.sty echo "%" >> pseudo.sty diff --git a/macros/latex/contrib/pseudo/VERSION b/macros/latex/contrib/pseudo/VERSION index 6085e94650..23aa839063 100644 --- a/macros/latex/contrib/pseudo/VERSION +++ b/macros/latex/contrib/pseudo/VERSION @@ -1 +1 @@ -1.2.1 +1.2.2 diff --git a/macros/latex/contrib/pseudo/doc/pseudo.pdf b/macros/latex/contrib/pseudo/doc/pseudo.pdf Binary files differindex 920266e118..30721c9667 100644 --- a/macros/latex/contrib/pseudo/doc/pseudo.pdf +++ b/macros/latex/contrib/pseudo/doc/pseudo.pdf diff --git a/macros/latex/contrib/pseudo/doc/pseudo.tex b/macros/latex/contrib/pseudo/doc/pseudo.tex index 21e640267c..562de5f6fa 100644 --- a/macros/latex/contrib/pseudo/doc/pseudo.tex +++ b/macros/latex/contrib/pseudo/doc/pseudo.tex @@ -1,4 +1,22 @@ -\documentclass[a4paper]{article} +\documentclass[a4paper]{book} + +% Using geometry.sty to have equal margins, despite twoside option. It will +% normally change the margins quite a bit; the following produces something +% close to normal LaTeX layout -- it just increases \topmargin by 2pt: +\usepackage[textwidth=345pt,textheight=598pt,centering]{geometry} +\usepackage{fancyhdr} +\pagestyle{fancy} + +\renewcommand{\chaptermark}[1]{\markboth{#1}{}} +\renewcommand{\sectionmark}[1]{\markright{\thesection\enskip#1}} +\fancyhf{} +\fancyhead[LE,RO]{\thepage} +\fancyhead[LO]{\nouppercase{\textit{\rightmark}}} +\fancyhead[RE]{\nouppercase{\textit{\leftmark}}} +% \def\headrulewidth{0pt} + +\usepackage{abspos} +\usepackage{xcoffins} \usepackage[inline]{enumitem} @@ -7,6 +25,8 @@ label=\mbox{\rm($\roman*$)}, } +\usepackage[prefix=s]{xcolor-solarized} + \usepackage{tabularx} \usepackage{tabto} @@ -137,6 +157,11 @@ \codefont{ \l_tmpa_tl } } +% https://tex.stackexchange.com/a/44362/18003 +\DeclareTextFontCommand \hyphencodefont { + \ttfamily \hyphenchar \font=45 \relax +} + \ExplSyntaxOff \makeatother @@ -147,7 +172,9 @@ \NewDocumentCommand \shortcutted { m m } {% If some package defines \cs{#1} before \pkg{pseudo} is loaded, \pkg{pseudo} - will not overwrite it. The command will still be available, as \cs{#2}.% + will not overwrite it. The command will still be available, as \cs{#2}. To + get the shorter version, simply use \code{\cs{let}\cs{#1}\cs{#2}}, possibly + as part of the \refk{init} hook.% } \NewDocumentCommand \pseudoshortcutted { m } {% @@ -293,6 +320,49 @@ #1 } +\tcbset{ + infobox/.style = { + pseudo/filled, + colback = black!4, + colbacktitle = black!4, + % coltitle = black!65, + top = 9pt, + bottom = 8pt, + right= 10pt, + left= 9pt, + }, + admonition/.style = { + infobox, + borderline west = {2.5pt}{0pt}{black!25}, + leftrule = 2.5pt, % spacing + before title = {}, + after title = {}, + attach title to upper, + beforeafter skip balanced = 6.0pt plus 3.0pt minus 1.5pt, + }, + sidebar/.style = { + infobox, + float, + colback = white, + colbacktitle = white, + boxrule = \lightrulewidth, + borderline = {\lightrulewidth}{0pt}{black}, + toptitle = 8pt, + top = 5pt, + fonttitle = \centering\bfseries\large, + } +} + +\DeclareTColorBox {note} { } { + admonition, + % title = {Note:\enskip} +} + +\DeclareTColorBox {sidebar} { m } { + sidebar, + title = {#1}, +} + \def\refc{\refCom*} \def\refe{\refEnv*} \def\refk{\refKey*} @@ -360,9 +430,8 @@ } -\NewDocumentCommand \Abstract { } { - \begin{abstract} +\NewDocumentCommand \Abstract { } { \ior_open:Nn \g_tmpa_ior {README.md} @@ -394,15 +463,13 @@ \regex_replace_all:nnN {` ( \w+ ) `} - { \c{code} \cB{ \1 \cE} } \g_tmpa_tl + { \c{hyphencodefont} \cB{ \1 \cE} } \g_tmpa_tl + % { \c{code} \cB{ \1 \cE} } \g_tmpa_tl - \noindent \tl_use:N \g_tmpa_tl \ior_close:N \g_tmpa_ior - \end{abstract} - } \ExplSyntaxOff @@ -428,7 +495,7 @@ % \NoIndentAfterEnv{source} \newtcbtheorem[ - number within = section, + number within = chapter, crefname = {Algorithm}{algorithms} ]% {algorithm}{Algorithm}{pseudo/ruled}{alg} @@ -443,11 +510,78 @@ \usepackage{ellipsis} \begin{document} -\maketitle -\Abstract -\section{Introduction} +\makeatletter +{\colorlet{scol}{black!15}% +\def\ssep{\hspace{.5em}\color{scol}}% +\absput[scale=4.5]{ + \tcbox[ + pseudo/boxruled, + before upper={}, % bc/o restricted horizontal mode + after upper={}, % -- " -- + title={pseudo \pseudoversion}] + {% + \begin{pseudo}[hsep=.5em, label=\color{sred}\arabic*] + \rlap{straight-}\phantom{pseudocode}\ssep\code{\bslash\bslash+}\\ + \phantom{pseudocode}\llap{forward}\ssep\code{\bslash\bslash-}\\ + pseudocode\ssep\code{\bslash\bslash} + \end{pseudo}% + } +}} +\makeatother + +\pagenumbering{roman} +\pagestyle{empty} +\pagecolor{black!4} +\null +\clearpage +\null\vfill +{\small +\makeatletter +\noindent +Copyright\enskip\copyright\enskip\@author\enskip2019--\the\year +\makeatother + +\medskip\noindent +\Abstract} +\clearpage +\nopagecolor + +\pagenumbering{arabic} + +\begin{titlepage} +\makeatletter +\null +\begin{center} + +\null +\vfill + +\Huge +\@title + +\vspace{\baselineskip} + +\LARGE +\@author + +\vspace{\baselineskip} + +\LARGE +\@date + +\vfill + +\end{center} +\makeatother +\end{titlepage} + +\tableofcontents + +\pagestyle{fancy} + +\chapter{Introduction} The \pkg{pseudo} package lets you typeset pseudocode in a straightforward and not all too opinionated manner. You don't need to use separate commands for @@ -505,7 +639,7 @@ The running time is quadratic in the number of bits in the input. \end{algorithm} } -\subsection*{Microtutorial: How to produce \cref{alg:euclid}} +\section*{Microtutorial: How to produce \cref{alg:euclid}} The pseudocode in \cref{alg:euclid} is typeset in the same way as on \vpageref{p:intro-euclid}. The line numbers are styled using the \refk{label} @@ -521,12 +655,13 @@ command and its relatives (as well as most other functionality) are discussed in \cref{sec:overview}, with individual definitions given in \cref{sec:reference}.\footnote{The actual implementations, with explanations, are found in \cref{sec:impl}.} The input and output descriptions are aligned -using \cs{tab} from the \pkg{tabto} package (cf.\@ \cref{sec:tabstops}). +using \cs{tab} from the \pkg{tabto} package (cf.\@ +\cref{sec:tabstops}). \begin{texexp}[listing] % In document preamble: % \usepackage{tabto} -% \TabPositions{1.5cm} +% \TabPositions{1.5cm} % Adjust as needed! \begin{algorithm}{Euclid's algorithm, \pr{Euclid}(a, b)}{euclid} @@ -547,7 +682,15 @@ The running time is quadratic in the number of bits in the input. \end{algorithm} \end{texexp} -\subsection*{Alternatives} +\begin{note} +With a different font, ``\textb{Output:}''\ may take up more space, and +\cs{tabto} might just introduce a line break. If so, simply increase the +argument to \cs{TabPositions}. To produce an indent right after a line break +(\cs{\bslash})---e.g., if you want multiline input/output---use +\cs{null}\cs{tab}. +\end{note} + +\section*{Alternatives} There are many ways of typesetting code and pseudocode in \LaTeX, so if you're unhappy with \pkg{pseudo}, you have several alternatives to choose from. I @@ -598,7 +741,7 @@ There are also code-typesetting packages like \pkg[https://ctan.org/tex-archive/macros/latex/contrib/listings]{listings} and \pkg{minted}, of course. -\subsection*{Using older \TeX\ distributions} +\section*{Using older \TeX\ distributions} The imlementation of \pkg{pseudo} uses some functionality that isn't available in older \TeX\ distributions, in particular, older versions of \pkg{xparse} and @@ -610,20 +753,24 @@ else (e.g., when submitting to some publisher with a custom setup), feel free to \href{https://github.com/mlhetland/pseudo.sty/pulls}{provide a pull request} with a fix. One thing to look out for is that older versions of \pkg{xparse} parse arguments differently, so things like -\begin{texexp}[listing] -foo\\<1> -bar\\[hl] -\end{texexp} +\code{\cs{\bslash}[hl]} +% \begin{texexp}[listing] +% foo\\<1> +% bar\\[hl] +% \end{texexp} would work, but separating the arguments with spaces, as in -\begin{texexp}[listing] -foo\\ <1> -bar\\ [hl] -\end{texexp} +% \begin{texexp}[listing] +% foo\\ <1> +% bar\\ [hl] +% \end{texexp} +\code*{\cs{\bslash} [hl]} will \emph{not} work, though this works with more recent versions (as seen -from some of my examples, later). For more advice on working around an older -distribution, see also \cref{sec:older}. +from some of my examples, later). +\begin{note} +For more advice on working around an older distribution, see \cref{sec:older}. +\end{note} -\section{Overview} +\chapter{Pseudocode} \label{sec:overview} The main component of the \pkg{pseudo} package is the \refe{pseudo} @@ -643,16 +790,8 @@ repeat the following while $a\neq b$ \\+ \end{pseudo} \end{texexp} +% \medskip \noindent -Spacing is handled similarly to in \LaTeX\ lists, with \cs{topsep} and -\cs{parskip} added before and after, as well as \cs{partopsep} whenever the -environment starts a new paragraph. The left margin (how much the pseudocode -is indented wrt.\ the surrounding text) is set by the \refk{left-margin} key -(initially \code{0pt}).\footnote{If \refe{pseudo} occurs in a box such as -\code{fbox}, or a \pkg[https://ctan.org/pkg/pgf]{tikz} node, this spacing is -dropped. See also the \refk{compact} key for overriding this behavior.} - -\medskip\noindent There are also some styling commands for special elements of the pseudocode: \begin{texexp} @@ -670,6 +809,18 @@ the more convenient short forms (\refc{kw}, \refc{cn}, etc.)\@ are prone to name collisions, and are only defined if the names are not already in use when \pkg{pseudo} is imported. +Spacing is handled similarly to in \LaTeX\ lists, with \cs{topsep} and +\cs{parskip} added before and after, as well as \cs{partopsep} whenever the +environment starts a new paragraph. The left margin (how much the pseudocode +is indented wrt.\ the surrounding text) is set by the \refk{left-margin} key +(initially \code{0pt}). + +\begin{note} +If \refe{pseudo} occurs in a box such as \code{fbox}, or +a \pkg[https://ctan.org/pkg/pgf]{tikz} node, this spacing is dropped. See also +the \refk{compact} key for overriding this behavior. +\end{note} + The \refk{indent-length} option, which determines the length of each indentation step, is initially set via the secondary \refk{indent-text} key, so that the any code after \code{\cs{kw}\braces{else}} aligns with the @@ -767,11 +918,13 @@ You can also configure the quotes and comment markers: \kw{print} \st{Hello, world!} \quad \ct{Greeting} \end{pseudo} \end{texexp} -% + +\begin{note} Note that \cs{stfont} and friends may either be font-switching commands like \cs{itshape} or formatting commands like \cs{textit}, though the latter are generally preferable when available. They need not be restricted to actual fonts, but may include color commands, for example. +\end{note} You can also set the font for the entire code lines, using the \refk{font} option. The command you provide there should just switch the font (i.e., not @@ -824,17 +977,39 @@ The code is normally typeset in a two-column \code{tabular} (whose preamble, and thus number of columns, is configurable via the option \refk{preamble}), but the first column is handled by an automatic \refk{prefix} inserted before each line, containing the numbering and column separator (\code{\&}). You -disable the prefix for the following line by using \code{\refc{\bslash}*}: +disable the prefix for the following line by using \code{\refc{\bslash}*}. If +you add the \code{\&} manually, you get an (appropriately indented) unnumbered +line: \begin{texexp} \begin{pseudo} - this line has an automatic prefix \\+* -& this line does not \\+ + this line has an automatic prefix \\+*& + this line does not \\+ but this one does \end{pseudo} \end{texexp} \noindent +The \code{\cs{\bslash}*\&} combo can also be used for manual line breaking in +multiline pseudocode steps: + +\begin{texexp} +\begin{pseudo}[indent-mark] +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam +nonumy \\*& eirmod tempor invidunt ut labore et dolore magna +aliquyam erat. \\+ +At vero eos et accusam et justo duo dolores et ea rebum. Stet +clita \\*& kasd gubergren, no sea takimata sanctus est Lorem ipsum +dolor. +\end{pseudo} +\end{texexp} + +\begin{note} +Automatic line wrapping is a bit trickier. See \cref{sec:multiline} for a +discussion. +\end{note} + +\noindent This star also works after \code{\cs{begin}\braces{pseudo}}. Note that in order to prevent your code from ending up in the numbering column, you must insert a column separator manually. A version of the \refc{pr} command, called @@ -852,14 +1027,57 @@ if $b \== 0$ \\+ \end{pseudo} \end{texexp} -\noindent -As can be seen in this example, \cs{==} (or \refc{eqs}) is a notational -convenience defined by \pkg{pseudo}, along with interval dots \cs{..}\@ (or -\refc{dts}) and the alternative range operator \refc{rng}: +\begin{note} +The \refc{hd} command is less capable than \refc{pr} and \refc{fn} in its +argument parsing: the parenthetical arguments are mandatory, and they are +terminated at the first closing parenthesis, regardless of nesting. If you want +to include parentheses in the arguments, you need to wrap them in braces, e.g., +\code{\cs{hd}\braces{Traverse}(\braces{G=(V, E), s})}. +\end{note} + +Another style is to include the header as a statement, just as any other, +perhaps with an introductory keyword. The following example, for example, is +based on one in the \pkg{algxpar} documentation (using \refe{pseudo*} to +suppress line numbering, along with a couple of config keys): + +{\def\bf{\fontseries{bx}\selectfont} +\begin{texexp} +\begin{pseudo*}[font=\bf, indent-length=1.5em] +function \pr{Max}(a, b) \\+ + if $a > b$ then \\+ + return $a$ \\- + else \\+ + return $b$ \\- + end if \\- +end function +\end{pseudo*} +\end{texexp}} + +As can be seen in the earlier \pr{Euclid} example, \cs{==} (or \refc{eqs}) is +a notational convenience defined by \pkg{pseudo}, along with interval dots +\cs{..}\@ (or \refc{dts}) and the alternative range operator \refc{rng}: \begin{texexp} Do you prefer $A[1 \.. n]$ or $A[1 \rng n]$? \end{texexp} +\begin{sidebar}{Shortcuts for \cs{rng}} +The \refc{..} command is actually implemented by hijacking the \cs{.} command, +and isn't easily redefined directly. Instead, if you want \code{1\refc{..}n} to +produce $1\rng n$, you can redefine \refc{dts}, using +\code{\cs{let}\refc{dts}\refc{rng}}. + +Another option is to introduce some other shortcut, such as \cs{:}, for example: +\begin{texexp} +\let\:\rng +$A[1\:n]$ +\end{texexp} +Note that \cs{:} is an existing spacing command that produces a medium space. If +\cs{:} is redefined, this spacing command is still available as \cs{>}. However, +if you use packages that rely on \cs{:}, such a redefinition might cause +trouble. One solution is to keep the redefinition local, e.g., using +\code{\refc{pseudoset}\braces{\refk{init}=\cs{let}\cs{:}\refc{rng}}}. +\end{sidebar} + \noindent Other special symbols may be found in other packages. For example, if you want to use $\coloneqq$ for assignment, you can use \cs{coloneqq} from @@ -904,11 +1122,11 @@ We're using something custom! \label{custom-line} \end{texexp} \noindent -Note that if I refer to the labeled line with \cs{ref}, I'll just end up with -\ref{custom-line}, which is probably what I'd want in this case. If you want a -custom reference format as well, you can set that with the \refk{ref} key, in -the same way as with \refk{label}. If you use the key without arguments, it'll -use the same format as the one provided to \refk{label}: +Note that if you refer to the labeled line with \cs{ref}, you'll just end up +with \ref{custom-line}, which is probably what you'd want in this case. If you +want a custom reference format as well, you can set that with the \refk{ref} +key, in the same way as with \refk{label}. If you use the key without arguments, +it'll use the same format as the one provided to \refk{label}: \begin{texexp} \pseudoset{label=(\textit{\roman*}), label-align=l, ref} @@ -938,7 +1156,7 @@ I'm not highlighted \\[hl] But I am! \end{pseudo*} \end{texexp} -} +}% % Initially, the \refc{pseudohl} command that is inserted is simply a \cs{rowcolor} that uses \refk{hl-color}, but you're free to redefine this @@ -950,11 +1168,17 @@ pseudocode aligned with the surrounding text. However, when using row highlighting (e.g., because you are stepping through the code in some presentation), that alignment may be less of an issue---and you'd rather widen the highlight a bit. The horizontal padding on each side is controlled by the -\refk{hpad} key.\footnote{In fact, if you use \refk{hl} without \refk{hpad}, -you'll get a warning. You can turn this warning off using \refk{hl-warn}, or by, -e.g., setting \refk{hpad} to \code{0pt}.} You can either specify a length, or -just turn on the default, by not supplying an argument. There's a similar -option, \refk{hsep}, which controls the separation between the two columns. +\refk{hpad} key. + +\begin{note} +If you use \refk{hl} without \refk{hpad}, you'll get a warning. You can turn +this warning off using \refk{hl-warn} or by setting \refk{hpad} to \code{0pt}. +\end{note} + +\noindent +You can either specify a length, or just turn on the default, by not supplying +an argument. There's a similar option, \refk{hsep}, which controls the +separation between the two columns. \begin{texexp} \begin{pseudo}[hpad, hsep=1em, indent-length=1em] @@ -974,9 +1198,20 @@ is simply ignored. What is more, the row separator \emph{itself} takes an overlay specification as a shortcut for the one on \refk{hl}, so \code{\refc{\bslash}<1,2-4>} is -equivalent to \code{\refc{\bslash}[\refk{hl}<1,2-4>]}. Just like with the -optional arguments, space before the overlay specification is ignored, so -you're free to put the specification in front of the line in question: +equivalent to \code{\refc{\bslash}[\refk{hl}<1,2-4>]}. + +\begin{note} +Actually, explicitly using \code{\refk{hl}<1,2-4>} wouldn't work! The problem is +that the key--value lists are split at commas before individual keys (including +overlay specifications) are parsed. And unlike values, using braces to +``protect'' the keys isn't entirely straightforward. The solution is instead to +use the key multiple times, as in +\code{\refc{\bslash}[\refk{hl}<1>, \refk{hl}<2-4>]}. +\end{note} + +Just like with the optional arguments, space before the overlay specification is +ignored, so you're free to put the specification in front of the line in +question: \medskip @@ -1018,7 +1253,7 @@ purpose (equivalent to \code*{\refk{eol-append} = \cs{pause}}): \includegraphics[page=1]{pausefig.pdf}\hfill \includegraphics[page=2]{pausefig.pdf}\hfill \includegraphics[page=3]{pausefig.pdf}\hfill -\includegraphics[page=4]{pausefig.pdf} +\includegraphics[page=4]{pausefig.pdf}\qquad\null \vspace{-4pt} @@ -1038,6 +1273,15 @@ The \refk{eol} value is only inserted wherever \refc{\bslash} starts a new line (i.e., not at the end of the environment), so in this case only three \cs{pause} commands are inserted. +\begin{note} + The last \refc{\bslash} looks for an immediately following + \code{\cs{end}\braces{pseudo}}, after skipping any non-paragraph whitespace, + so if you insert anything between the the \refc{\bslash} and + \code{\cs{end}\braces{pseudo}}, even if it's just an empty line (i.e., a + \cs{par}), you'll end up with an extra (empty) line in the result. Note, + however, that the last \refc{\bslash} is entirely optional! +\end{note} + The previously discussed configuration keys are described in more detail in \cref{sec:reference}. You can create your own presets or \emph{styles} using \refc{pseudodefinestyle}. This command takes two arguments; the first is the @@ -1059,9 +1303,21 @@ unnumbered version of the \refe{pseudo} environment: \end{texexp} } -\section{Boxes and floats} +\chapter{Boxes and floats} \label{sec:floats} +\begin{sidebar}{The short story} +First import \pkg{tcolorbox}, with +libraries \code{skins} and \code{theorems} (see nearby sidebar), and then put +the following in your preamble: +\begin{texexp}[listing] +\newtcbtheorem{algorithm}{Algorithm}{pseudo/ruled, float}{alg} +\end{texexp} +You now have an \code{algorithm} float with the \code{pseudo/ruled} style. The +environment takes two arguments: the title and a label name, which can be left +empty. +\end{sidebar} + There are (at least) two different ways of viewing a block of pseudocode: as an inline element, like equations, or as a float, like figures and tables. For example, \citet{Cormen:2009} place their pseudocode inline, and refer to the @@ -1082,23 +1338,27 @@ you could do a quick \href{https://ctan.org}{\textsc{ctan}} search for the \pkg[https://ctan.org/tex-archive/macros/latex/contrib/float]{float} package, will give you many options, with varying functionality.} You could also use the float environments supplied with packages such as \pkg{algorithms}, -\pkg{algorithmicx} and \pkg{algorithm2e}.\footnote{The definition of \refc{==} -doesn't properly carry over into floats. It's properly redefined inside -\refe{pseudo}, so you probably won't notice, but if you wish to use the symbol -outside the \refe{pseudo} environment, but in a float (e.g., inside -\cs{caption}), you'll need to either call \refc{RestorePseudoEq} to -re-establish \pkg{pseudo}'s redefinition of \cs{=} or simply use \refc{eqs} -instead of \refc{==}.} +\pkg{algorithmicx} and \pkg{algorithm2e}. + +\begin{note} +The definition of \refc{==} doesn't properly carry over into floats. It's +properly redefined inside \refe{pseudo}, so you probably won't notice, but if +you wish to use the symbol outside the \refe{pseudo} environment, but in a float +(e.g., inside \cs{caption}), you'll need to either call \refc{RestorePseudoEq} +to re-establish \pkg{pseudo}'s redefinition of \cs{=} or simply use \refc{eqs} +instead of \refc{==}. +\end{note} +\noindent The \pkg{pseudo} package does provide some specialized setup, however, using \pkg{tcolorbox}. This also lets you typeset non-float pseudocode with a colored background, for example, like \citeauthor{Cormen:2022} do in the most recent version of their textbook~\citep{Cormen:2022}. - -\medskip\noindent -\textb{Note:} For performance reasons, \pkg{pseudo} does \emph{not} -automatically import \pkg{tcolorbox}; if you want to use the float -functionality, you will need to import \pkg{tcolorbox} yourself: +% +\begin{sidebar}{Importing \pkg{tcolorbox}} +For performance reasons, \pkg{pseudo} does \emph{not} automatically import +\pkg{tcolorbox}; if you want to use the box functionality, you will need to +import it yourself: \begin{texexp}[listing] \usepackage{pseudo} % ... @@ -1108,7 +1368,8 @@ functionality, you will need to import \pkg{tcolorbox} yourself: It does not matter whether you import \pkg{tcolorbox} before or after \pkg{pseudo}, but make sure you also import the two libraries \code{skins} and \code{theorems}, as in the example above. - +\end{sidebar} +% The styles defined by \pkg{pseudo} are versions of the commonly used \emph{boxed} and \emph{ruled} styles, as found in, e.g., \pkg[https://ctan.org/tex-archive/macros/latex/contrib/float]{float}, as well as @@ -1191,7 +1452,7 @@ effect.} % Actual definition in preamble (so crefname works) \begin{texexp}[listing] \newtcbtheorem[ - number within = section, + number within = chapter, crefname = {Algorithm}{algorithms} ]% {algorithm}{Algorithm}{pseudo/ruled, float}{alg} @@ -1344,8 +1605,19 @@ The running time of the algorithm is quadratic. \end{texexp} } +\begin{sidebar}{Why only styles?} +Currently, \pkg{pseudo} defines only \pkg{tcolorbox} \emph{styles}, and not any +actual boxes or theorem-style environments. While this may change in the future, +it has a couple of advantages. First, the style definitions aren't dependent on +\pkg{tcolorbox} being imported, making it entirely optional. Second, when +defining the box or theorem environment, you can easily configure the counter +style, counter level, etc., through the normal \pkg{tcolorbox} mechanisms. +Similar customization mechanisms would have to be defined, anyway, and there is +no real point in aliasing them, rather than simply using the originals. +\end{sidebar} -\section{Reference} + +\chapter{Reference} \label{sec:reference} This section gives an overview of all the moving parts of the package. A @@ -1356,7 +1628,7 @@ at the point where \pkg{pseudo} is imported. Several commands (such as, e.g., \refk{prefix}). When the behavior of such commands is described, the description references their initial behavior. -\subsection{Line structure} +\section{Line structure} \label{sec:linestructure} Each line of a \refe{pseudo} environment is (initially) structured as follows: @@ -1483,7 +1755,7 @@ appropriate options (e.g., \refk{prefix} and \refk{setup}). not insert \refk{eol} and does not start a new line). \end{description} -\subsection{Command and key reference} +\section{Command and key reference} \label{sec:cmdandkeyref} In addition to descriptions of the various commands and options/keys (in @@ -2027,7 +2299,21 @@ We're not in math mode, but the argument of \Ln[A] is. The \refk{hd-space} key can be used to configure \refc{hd} so it sets the \refk{extra-space} key. Note that the signature arguments are mandatory; in order to function properly, \cs{hd} must be \emph{expandable}, and therefore - cannot end with an optional argument, the way \refc{pr} does. + cannot end with an optional argument, the way \refc{pr} does. Also, it is + not able to determine nesting levels of parentheses, so the arguments are + terminated upon encountering the first closing parentheses. If you want to + use parentheses in the arguments themselves, you must wrap them in braces, + or thing will get wonky: + +\begin{texexp} +\begin{pseudo}* +\hd{Foo}(G=(V, E), w, s) \\* +\hd{Foo}({G=(V, E), w, s}) \\ +lorem ipsum dolor sit amet, consetetur +\end{pseudo} +\end{texexp} + + \noindent \pseudoshortcutted{hd} \end{docCommand} @@ -2137,7 +2423,7 @@ $\textit{foo-bar:baz}$ \refk{indent-text} is used to calculate one the indent length instead. \end{docKey} -\begin{docKey}{indent-level}{\,=\,\meta{length}}{no default, initially \code{0}} +\begin{docKey}{indent-level}{\,=\,\meta{level}}{no default, initially \code{0}} Sets the current indentation level. This is most usefully set on \refe{pseudo} environment, in concert with \refk{start}:\footnote{The \cs{strut} here is just to even out spacing above and below the text, @@ -2242,6 +2528,22 @@ indent-mark-width=.4pt} the \refKey*{indent-length} key. \end{docKey} +\begin{docKey}{init}{\,=\,\meta{commands}}{\initiallyempty} + Used to set the initialization hook, which is inserted at the beginning of + the \refe{pseudo} environment (right before the actual tabular environment + begins, as defined by \refk{begin-tabular}). See also \refk{init-append} and + \refk{init-prepend}. +\end{docKey} + +\begin{docKey}{init-append}{\,=\,\meta{commands}}{no default} + Locally appends \meta{commands} to \refk{init}. +\end{docKey} + +\begin{docKey}{init-prepend}{\,=\,\meta{commands}}{no default} + Similar to \refk{init-append}, except that \meta{commands} are added to + the \emph{beginning} of \refk{init}. +\end{docKey} + \begin{docKey}{kw}{}{\novaluekey} Sets \refk{font} to \refc{kwfont}. \end{docKey} @@ -2315,21 +2617,23 @@ vs.\ font or theme, e.g., with the \pkg{beamer} command \code{\cs{usefonttheme}\braces{serif}}, you may not have any issues to begin with.} though only once, as it's suppressed after the first occurrence, so the - fact that the font selection doesn't work on the last line isn't reported. Note, - however, that the current implementation of \refc{kwfont} actually - \emph{piggybacks} on this warning to determine if the non-extended bold is - available. This means that if you've tried (and failed) to use - \code{\cs{fontseries}\braces{b}} \emph{before} the fist use of \refc{kwfont}, - the fallback (i.e., extended bold) won't be triggered. - - Also note that \refk{indent-text} (which will tend to be the first - occurrence use of \refc{kwfont}) won't be evaluated (to determine - \refk{indent-length}) until you actually start a \refe{pseudo} - environment, so if you're \emph{aware} that you don't have non-extended - bold available, and you set \code*{\refk{kwfont} = \cs{bfseries}}, for - example, there will be no attempt to use the non-extended version, and you - won't get the font warning that the default implementation produces in - that case. + fact that the font selection doesn't work on the last line isn't reported. + + \begin{note} + The current implementation of \refc{kwfont} actually \emph{piggybacks} on + this warning to determine if the non-extended bold is available. This means + that if you've tried (and failed) to use \code{\cs{fontseries}\braces{b}} + \emph{before} the fist use of \refc{kwfont}, the fallback (i.e., extended + bold) won't be triggered. + \end{note} + + Note that \refk{indent-text} (which will tend to be the first occurrence use + of \refc{kwfont}) won't be evaluated (to determine \refk{indent-length}) + until you actually start a \refe{pseudo} environment, so if you're + \emph{aware} that you don't have non-extended bold available, and you set + \code*{\refk{kwfont} = \cs{bfseries}}, for example, there will be no attempt + to use the non-extended version, and you won't get the font warning that the + default implementation produces in that case. \end{docCommand} \begin{docKey}{label}{\,=\,\meta{commands}}{% @@ -2348,10 +2652,11 @@ print \st{Hello, label!} \label{li:label} \\ goto \tn{\ref{li:label}} \end{pseudo} \end{texexp} - \noindent - Note that \cs{label} should be used in the actual code line, as here, and - not in the number cell (which is generally not explicitly written, - anyway). + + \begin{note} + Make sure to use \cs{label} in the actual code line, as here, and not in the + number cell (which is generally not explicitly written, anyway). + \end{note} As can be seen from the example, \cs{ref} is unaffected by \refKey*{label}, and in many cases that's what you want---as apposed to, @@ -2398,10 +2703,10 @@ I'm a livin' in a box \\ I'm a livin' in a cardboard box \end{pseudo*}} \end{texexp} -Note that as opposed to \refk{topsep} and \refk{partopsep}, we are \emph{not} -working with one of the built-in list spacing commands; \cs{leftmargin} has no -effect on this key (which is why the hyphenated naming style of other keys such -as \refk{label-align} or \refk{indent-text} is also adopted for +As opposed to with \refk{topsep} and \refk{partopsep}, we are \emph{not} working +with one of the built-in list spacing commands; \cs{leftmargin} has no effect on +this key (which is why the hyphenated naming style of other keys such as +\refk{label-align} or \refk{indent-text} is also adopted for \refk{left-margin}). % See also \refk{compact}. @@ -2680,8 +2985,8 @@ dolor sit amet. environment (so that units like \code{em} and \code{ex} adapt to the current font). If no \refk{indent-mark} is set, the \cs{pseudoindent} command then inserts a horizontal space of length - $\cs{pseudoindentlength}\times\textit{current indent level}$. Otherwise, - one \refk{indent-mark} and a horizontal space of length + $\cs{pseudoindentlength}\times\mkern-1.8mu\textit{current indent level}$. + Otherwise, one \refk{indent-mark} and a horizontal space of length \cs{pseudoindentlength} is inserted for each level of indentation up to the current indentation level. (This horizontal space is measured from the left edge of the \refk{indent-mark}.) @@ -2892,21 +3197,13 @@ See also \refk{indent-level}. \medskip \noindent - If \pkg{beamer} is \emph{not} used, the key is simply ignored. Note that - because of current limitations on how keys are handled, - % Cf. https://github.com/latex3/latex3/issues/67 - unknown keys cannot have defaults, and so there is no way to insert a - marker for when no value is provided, which could be used to determine - whether to use - \code*{\refc{pseudoset}\braces{\meta{name} = \meta{value}}} - or simply - \code*{\refc{pseudoset}\braces{\meta{name}}}. Instead, if an empty value - is provided to the unknown key, that is treated in the same way as when - the key is used - without a value, resulting in - \code*{\refc{pseudoset}\braces{\meta{name}}} - rather than - \code*{\refc{pseudoset}\braces{\meta{name} = }}. + If \pkg{beamer} is \emph{not} used, the key is simply ignored. + + \begin{note} + Currently, using commas in the \meta{overlay specification} doesn't + work. As a workaround, you can use the key multiple times. That is, rather + than \code{\refk{dim}<1,3>}, use \code{\refk{dim}<1>, \refk{dim}<3>}. + \end{note} If an unknown key does \emph{not} take the form of a key with an overlay specification, a second special case is also handled: If we're processing @@ -2915,13 +3212,29 @@ See also \refk{indent-level}. implicit key is \refk{extra-space}. This means that you can specify extra space in the ordinary way, with \code{\cs{\bslash}[1.5ex]}, etc. \end{docKey} - -\section{But how do I\,\dots} +\begin{sidebar}{Unknown Keys and Defaults} +Because of current limitations on how keys are handled, +% \footnote{\url{https://github.com/latex3/latex3/issues/67}.} +unknown keys cannot have defaults, and so there is no way to insert a +marker for when no value is provided, which could be used to determine +whether to use +\code*{\refc{pseudoset}\braces{\meta{name} = \meta{value}}} +or simply +\code*{\refc{pseudoset}\braces{\meta{name}}}. Instead, if an empty value +is provided to the unknown key, that is treated in the same way as when +the key is used +without a value, resulting in +\code*{\refc{pseudoset}\braces{\meta{name}}} +rather than +\code*{\refc{pseudoset}\braces{\meta{name} = }}. +\end{sidebar} + +\chapter{But how do I\,\dots} Some functionality is not built in, but is still fairly easy to achieve. Some streamlining may be added in future versions. -\subsection{\dots\,prevent paragraph indentation after \code{pseudo}?} +\section{\dots\,prevent paragraph indentation after \code{pseudo}?} If you want to keep the pseudocode as part of a surrounding paragraph, you could have it not start its own, i.e., not have an empty line before it. This @@ -2961,7 +3274,7 @@ indentation after \emph{all} instances of \refe{pseudo}, you could use the If you wish to override this, and indent a given paragraph after all, you can simply use the \cs{indent} command. -\subsection{\dots\,get log-like functions?} +\section{\dots\,get log-like functions?} There's no built-in command for math-roman function names, as used in $\log$ and $\sin$, etc. (other than just setting \refk{fnfont}, if you want it @@ -2982,7 +3295,7 @@ if $\MyFunc x \== 1$ \\+ The spacing is then correct whether you enclose the arguments in parentheses or not. -\subsection{\dots\,unbold punctuation?} +\section{\dots\,unbold punctuation?} If you use the \refk{kw} key, all pseudocode not in math mode will end up using the keyword font (\refc{kwfont}), which initially is bold. Though some @@ -3037,13 +3350,15 @@ only do it locally, at the very least): \end{pseudo*} \end{texexp} -\subsection{\dots\,use \codefont{tabularx}?} +\section{\dots\,use \codefont{tabularx}?} \label{sec:tabularx} You can use other tabular packages such as \pkg{tabularx} via \refk{begin-tabular} and \refk{end-tabular}. Let's say, for example, that you wish to extend the \refe{pseudo} environment to fill out the entire line, and -set up a new column for comments. You could achieve that as follows: +set up a new column for comments. You could achieve that as +follows:\footnote{For an explanation of the use of \code{[t]}, see the +documentation of the \refk{pos} option.} \label{p:fullwidth} \begin{texexp} @@ -3078,10 +3393,10 @@ column.\footnote{You can also, of course, just use \refc{eqs} instead.} See the \pkg{tabularx} documentation (page~4) for an explanation of why we can't use \code{\cs{begin}\braces{tabularx}} and \code{\cs{end}\braces{tabularx}}. -Also note that because \pkg{tabularx} passes its contents as the argument to a -macro, the parsing \pkg{pseudo} uses to determine if \refc{\bslash} is at the -end of the last line doesn't work; if you add \refc{\bslash} at the end here, -you'll introduce an empty line. +Also, because \pkg{tabularx} passes its contents as the argument to a macro, the +parsing \pkg{pseudo} uses to determine if \refc{\bslash} is at the end of the +last line doesn't work; if you add \refc{\bslash} at the end here, you'll +introduce an empty line. \makeatletter For simplicity, I've used \code{@\braces{}} to remove space on either side. @@ -3092,7 +3407,7 @@ to use \cs{pseudolabelalign}, rather than \code{r}. \makeatother -\subsection{\dots\,get tab stops?} +\section{\dots\,get tab stops?} \label{sec:tabstops} Some packages, such as \pkg{clrscode3e}, use an actual \code{tabbing} @@ -3166,6 +3481,11 @@ preamble, or you can do it as part of the box setup, e.g.,. using \cs{newtcbtheorem} (or, as in the following simplified example, just supply it directly as an option to the box environment). +If you'd rather not separate the elements of, say, your input description by +paragraphs, you could of course use line breaks (\cs{\bslash}); however, +\cs{tab} won't work on its own at the beginning of the next line. To fix this, +simply add \cs{null} before it (i.e., use \cs{null}\cs{tab}). + \begin{texexp} % In document preamble: % \usepackage{tabto} @@ -3181,7 +3501,7 @@ just supply it directly as an option to the box environment). \tab No negative cycle in $G$ is reachable from $s$ \textbf{Result} - \tab An matrix $D$ of distances between the vertices in $V$ + \tab An array $d$ of distances from $s$ \begin{pseudo} \dots @@ -3190,7 +3510,7 @@ just supply it directly as an option to the box environment). \end{texexp} -\subsection{\dots\,use horizontal lines?} +\section{\dots\,use horizontal lines?} \label{sec:horizontallines} Many opt for a table-like appearance when typesetting algorithms, with @@ -3202,6 +3522,7 @@ tools such as \pkg{booktabs}, making sure to suppress the \pkg{pseudo} \refk{prefix} using the star flag (\code{*}): \begin{texexp} +% In document preamble: % \usepackage{booktabs} \begin{pseudo}* \toprule @@ -3226,7 +3547,7 @@ Rather than \code{\cs{\bslash}[bol=\cs{midrule}]}, you could also have used that the paragraph break between \refc{\bslash} and its argument has been commented out.) -\subsection{\dots\,handle object attributes?} +\section{\dots\,handle object attributes?} In the \pkg{clrscode3e} package, you'll find an assortment of commands for handling object attributes such as $A.\id{length}$. The manual says (here with @@ -3260,7 +3581,7 @@ perhaps using \pkg{microtype}), you may of course do so, but \pkg{pseudo} does not (at present) include any special attribute lookup commands that do it for you. -\subsection{\dots\,indicate blocks with braces or the like?} +\section{\dots\,indicate blocks with braces or the like?} Some packages (such as \pkg{algorithm2e}) have support for using vertical lines to indicate the block structure; @@ -3348,7 +3669,7 @@ course. This could be done by some hook triggered by the \code{-} flags in \refc{\bslash}. If it turns out there's a demand for something like that, I might add it in a future version. -\subsection{\dots\,use \pkg{pseudo} with older \TeX\ distributions?} +\section{\dots\,use \pkg{pseudo} with older \TeX\ distributions?} \label{sec:older} As mentioned in the introduction, I've tried to make \pkg{pseudo} work with at @@ -3408,7 +3729,7 @@ Of course, you won't have access to other functionality (such as of that should be possible to emulate by hand (possibly peeking at the implementation in \cref{sec:impl}). -\subsection{\dots\,use a header with no arguments?} +\section{\dots\,use a header with no arguments?} Normally, \refc{hd} has a mandatory set of arguments; at the very least, you'll need to supply the parentheses: @@ -3434,7 +3755,7 @@ arguments. If you'd like, though, you can just use \cs{multicolumn} yourself \end{pseudo} \end{texexp} -\subsection{\dots\,place algorithm boxes side by side?} +\section{\dots\,place algorithm boxes side by side?} In the simplest case, maybe you just want to place two of them side by side in the text (i.e., not as floats). Let's say you've defined an environment as @@ -3502,25 +3823,30 @@ package): \end{figure} \end{texexp} -\subsection{\dots\,have steps span multiple lines?} +\section{\dots\,have steps span multiple lines?} +\label{sec:multiline} First of all, you can do this by just breaking your lines manually, keeping any additional lines belonging to the same step unnumbered, by using the starred -version of \refc{\bslash} (and skipping the number column with \code{\&}): -adding unnumbered lines: +version of \refc{\bslash} and skipping the number column with \code{\&}, adding +unnumbered lines: \begin{texexp} \begin{pseudo}[line-height=1.1] - This step is broken\,\dots \\* -& \dots\,into multiple lines \\ + This step is broken\,\dots \\*& + \dots\,into multiple lines \\ This one is not \end{pseudo} \end{texexp} -If you want the line breaking to be automated, you can use a \code{p} column, -specified in \refk{preamble} (perhaps defining a style using -\refc{pseudodefinestyle}), adapted from the default:\footnote{The default is +If you want the line breaking to be automated, \emph{and you don't need +indentation}, you can use a \code{p} column, specified in \refk{preamble} +(perhaps defining a style using \refc{pseudodefinestyle}), adapted from the +default, as in the following. +\begin{note} +The default is found on p.~\pageref{p:preamble}. However, in the source code there, whitespace -is insignificant. If writing your own preamble, you should avoid spurious -whitespace inside \code{>\braces{\dots}} and \code{<\braces{\dots}}.} +is insignificant. In writing your own preamble, you should avoid spurious +whitespace inside \code{>\braces{\dots}} and \code{<\braces{\dots}}. +\end{note} \begin{texexp} \begin{pseudo}[preamble = { >{\pseudohpad} \pseudolabelalign @@ -3539,13 +3865,14 @@ dolor sit amet. \noindent In addition to introducing the \code{p} column, I've added \cs{raggedright} to -the setup (with \refk{setup-append}, with \cs{RestorePseudoBackslash} to restore -\refc{\bslash}, because \cs{raggedright} redefines it). +the setup (using \refk{setup-append}, with \cs{RestorePseudoBackslash} to +restore \refc{\bslash}, because \cs{raggedright} redefines it). One disadvantage of the \code{p} column is that you need to know its exact width. A better solution is probably to replace the default \code{tabular} with a \code{tabularx}, as discussed in \cref{sec:tabularx}, and use an \code{X} -column, i.e.: +column, i.e.:\footnote{For an explanation of the use of \code{[t]}, see the +documentation of the \refk{pos} option.} \begin{texexp}[listing] begin-tabular = \tabularx{\linewidth}[t]{ >{\pseudohpad} \pseudolabelalign @@ -3555,8 +3882,15 @@ column, i.e.: setup-append = \RestorePseudoEq, \end{texexp} +\noindent +The main problem with this setup is that the automatic line wrapping doesn't +take indentation into account, i.e., only the first line is indented! While +there are ways of dealing with this,\footnote{Cf.\ +\url{https://github.com/mlhetland/pseudo.sty/issues/16}.} the simplest solution +(at least for now) is probably to break lines manually, using +\code{\cs{\bslash}*\&}. -\subsection{\dots\,get the old spacing?} +\section{\dots\,get the old spacing?} The current version of the \refe{pseudo} environment ensures the spacing above and below is adjusted, so the baselines of the previous and following lines are @@ -3568,7 +3902,7 @@ follows: \end{texexp} -\subsection{\dots\,configure my \code{tcolorbox}es?} +\section{\dots\,configure my \code{tcolorbox}es?} \label{sec:boxconfig} If you use the \pkg{pseudo} styles for \code{tcolorbox}es (see @@ -3578,9 +3912,7 @@ system, not that of \pkg{pseudo}, so it's worth consulting the \pkg{tcolorbox} documentation (and, perhaps, the source of the \pkg{pseudo} box styles, in \cref{sec:floatsrc}). In the following, I go through some examples of things you might want to adjust. First, let's define a rather unstyled environment which we -can modify locally.\footnote{If you want the styling to apply to the environment -in general, simply insert it as the third argument. See the \pkg{tcolorbox} -documentation for more about \cs{newtcbtheorem}.} +can modify locally. % Duplicated: \newtcbtheorem{example}{Example}{}{} @@ -3588,6 +3920,12 @@ documentation for more about \cs{newtcbtheorem}.} \newtcbtheorem{example}{Example}{}{} \end{texexp} +\begin{note} +If you want the styling to apply to the environment in general, simply insert it +as the third argument. See the \pkg{tcolorbox} documentation for more about +\cs{newtcbtheorem}. +\end{note} + \paragraph{A different separator.} By default, the \pkg{pseudo} box styles use an \cs{enskip} to separate the label part from the description, but you might want to use something else, such as a colon or a period. You can get this by @@ -3601,14 +3939,9 @@ using the \code*{separator sign} key: \paragraph{A different parskip.} You might want more or less spacing between the paragraphs of any plain text outside your pseudocode. You do this by setting \cs{parskip}, which is normally set as part of the \code*{before upper} key in -the \code{pseudo/\dots} styles (see p.~\ref{p:before-upper}). Rather than +the \code{pseudo/} styles (see p.~\pageref{p:before-upper}). Rather than overwrite the \code*{before upper} code, you can use the hook \refk{pseudo/init} (set as part of the \pkg{tcolorbox} configuration, not using \cs{pseudoset}):% -\footnote{It is possible to use the \pkg{tcolorbox} key \code*{before upper app} -(together with the \pkg{tcolorbox} library \code{hooks}) instead of -\refk{pseudo/init}. However, the compatibility code (\cref{sec:compat}) appends -some spacing to this setup hook, and this may be messed up by inserting more -code after it. In this case, \refk{pseudo/init} is safer.} \begin{texexp} \begin{example}[pseudo/boxed, pseudo/init = \parskip\baselineskip]{\dots}{} @@ -3617,6 +3950,14 @@ code after it. In this case, \refk{pseudo/init} is safer.} is bigger! \end{example} \end{texexp} +\begin{note} +It is possible to use the \pkg{tcolorbox} key \code*{before upper app} +(together with the \pkg{tcolorbox} library \code{hooks}) instead of +\refk{pseudo/init}. However, the compatibility code (\cref{sec:compat}) appends +some spacing to this setup hook, and this may be messed up by inserting more +code after it. In this case, \refk{pseudo/init} is safer. +\end{note} + You \emph{could} set \cs{topsep} and \cs{partopsep} in the same manner, but unless you want to change the settings for lists (such as \code{itemize} and \code{enumerate}), you could also just set those for pseudocode specifically, @@ -3635,9 +3976,12 @@ adjust the line widths. \end{example} \end{texexp} The problem with the other ruled or boxed styles is that they use the -\code{empty} skin, which removes the box drawing.\footnote{The reason they don't -just set the appropriate line widths to zero is that this generally still -results in visible hairlines in many PDF viewers.} +\code{empty} skin, which removes the box drawing. +\begin{note} +The reason they don't just set the appropriate line widths to zero is that this +generally still results in visible hairlines in many PDF viewers. +\end{note} +\noindent They then instead rely on various \code{borderline} commands. These are cumulative, so if you want to replace some of them, you first need to clear the deck with \code*{no borderline}, and then re-do them all. For example, maybe you @@ -3680,7 +4024,7 @@ If you want to style the top and bottom line separately, just use \code*{borderline north} and \code*{borderline south} separately, rather than the collective \code*{borderline horizontal}. -\section{Implementation} +\chapter{Implementation} \label{sec:impl} \lstdefinestyle{tcblatex}{language={[LaTeX]TeX}, @@ -3757,7 +4101,7 @@ As part of the initial setup, we also record whether we're part of a \end{source} We're now ready to begin the actual implementation. -\subsection{Variable declarations} +\section{Variable declarations} Many variables are created as needed by various \code{set} commands, but some are declared initially. First, we create a plain-vanilla \LaTeX\ counter for @@ -3799,7 +4143,7 @@ to know if that's the command we're in: \bool_new:N \l_@@_in_eol_bool \end{source} -\subsection{Utilities} +\section{Utilities} \paragraph{Variants.} First, let's just generate a couple of expansion variants we'll need of some standard commands. (I'm using the @@ -4011,7 +4355,7 @@ the original name to the meaning it had when we entered the scope. In saving a macro, we also supply a name for the original, which may then be used to refer to it until it's restored. \begin{source} -\cs_new:Npn \@@_gsave_as:NN #1 #2 { +\cs_new:Npn \@@_cs_gsave_as:NN #1 #2 { \cs_gset_eq:NN #2 #1 \group_insert_after:N \cs_gset_eq:NN \group_insert_after:N #1 @@ -4019,7 +4363,22 @@ used to refer to it until it's restored. } \end{source} % -\subsection{Styles} +\paragraph{Skipping paragraphs.} Ignoring space is easy enough, but skipping +\cs{par} tokens takes a bit more work. We'll be using this as part of the +end-of-line handling, when we're checking if the next ``real'' token is +\cs{end}. The argument is the code to execute after skipping (and removing) +whitespace and \cs{par} tokens. +\begin{source} +\cs_new:Npn \@@_skip_pars:n #1 { + \peek_meaning_remove_ignore_spaces:NTF \par { + \@@_skip_pars:n { #1 } + } { + #1 + } +} +\end{source} +% +\section{Styles} The first text styling commands are only straight-up shortcuts for normal font commands: @@ -4030,9 +4389,13 @@ commands: \@@_new_cmd:Nnn \cn { m } { \textnormal {\cnfont { #1 } } } \@@_new_cmd:Nnn \id { m } { \textnormal {\idfont { #1 } } } \end{source} -(As a side-effect, we've now also defined \cs{pseudonf} and \cs{pseudotn}, -which we don't really need.) -% +\begin{note} +As a side-effect, we've now also defined \cs{pseudonf} and \cs{pseudotn}, which +we don't really need, as we might as well use \cs{normalfont} and +\cs{textnormal} directly. +\end{note} + +\noindent While we're at it, we'll define the initial value for \refc{kwfont}, which is generally non-extended bold, if that's available, but extended bold otherwise: \begin{source} @@ -4047,7 +4410,7 @@ generally non-extended bold, if that's available, but extended bold otherwise: \group_begin: \cs_if_exist:NT \@defaultsubs { - \@@_gsave_as:NN \@defaultsubs \@@_defaultsubs + \@@_cs_gsave_as:NN \@defaultsubs \@@_defaultsubs \cs_gset_eq:NN \@defaultsubs \relax } @@ -4167,7 +4530,7 @@ provided: \@@_new_dec:nn { String } { st } \end{source} % -\subsection{Notation} +\section{Notation} Here we'll define a couple of symbols that are useful for pseudocode but that are not necessarily entirely standard mathematical notation. First, the double @@ -4255,7 +4618,7 @@ command of \pkg[https://www.cs.dartmouth.edu/~thc/]{clrscode4e}. } \end{source} -\subsection{Options} +\section{Options} \label{sec:options} Much of the behavior of \pkg{pseudo} may be configured through various options, @@ -4287,6 +4650,14 @@ typesetting the pseudocode. \begin{source} \keys_define:nn { pseudo } { + init .tl_set:N = \l_@@_init_tl, + init-append .code:n = { + \tl_put_right:Nn \l_@@_init_tl {#1} + }, + init-prepend .code:n = { + \tl_put_left:Nn \l_@@_init_tl {#1} + }, + font .tl_set:N = \pseudofont, font .initial:n = \normalfont, @@ -4372,7 +4743,6 @@ magnitude. }, hl .value_forbidden:n = true, - bol .tl_set:N = \l_@@_bol_tl, bol-append .code:n = { \tl_put_right:Nn \l_@@_bol_tl {#1} @@ -4720,7 +5090,7 @@ supply a command for setting them. \cs_new:Npn \@@_set:n #1 { \keys_set:nn { pseudo } { #1 } } \end{source} % -\subsection{The row separator} +\section{The row separator} Much of the work of the \refe{pseudo} environment is performed by the row separator, that is, the \refc{\bslash} command; whatever part of the line @@ -4761,8 +5131,8 @@ and clamp the indent level to non-negative values: % \paragraph{The actual row separator.} The command consists of a few interacting macros. The implementation of \refc{\bslash} is -\verb|@@_eol:|, but that is just a thin wrapper that counts pluses and -minuses, before handing the control over to \verb|@@_eol_tail|. This is where +\verb|\@@_eol:|, but that is just a thin wrapper that counts pluses and +minuses, before handing the control over to \verb|\@@_eol_tail|. This is where the remaining argument parsing takes place, and the \cs{tabularnewline} is inserted, after which control is passed to \verb|\@@_bol:| in order to begin a new line---unless we're at the end of the environment. @@ -4801,16 +5171,26 @@ but then we'd have a conditional at the beginning of the next line, which would mess up \cs{bottomrule} or the like. We need to keep \verb|\@@_bol:| alone at the start of the line.) We call \cs{tabularnewline} either way, in particular for it to use any extra space provided to \refk{extra-space}. + +It seems providing a zero-length extra space in \cs{tabularnewline} can cause +trouble,\footnote{Cf.\ \url{https://github.com/mlhetland/pseudo.sty/issues/21}} +so we treat that as a special case. \begin{source} - \tl_set:Nx \l_tmpa_tl { - \exp_not:N \tabularnewline [ \l_@@_extra_space_tl ] - } - \peek_meaning_ignore_spaces:NTF \end { - \l_tmpa_tl + \dim_compare:nNnTF \l_@@_extra_space_tl = { 0pt } { + \tl_set_eq:NN \l_tmpa_tl \tabularnewline } { - \pseudoeol - \l_tmpa_tl - \@@_bol: + \tl_set:Nx \l_tmpa_tl { + \exp_not:N \tabularnewline [ \l_@@_extra_space_tl ] + } + } + \@@_skip_pars:n { + \peek_meaning_ignore_spaces:NTF \end { + \l_tmpa_tl + } { + \pseudoeol + \l_tmpa_tl + \@@_bol: + } } } \end{source} @@ -4837,7 +5217,7 @@ The \verb|\@@_bol:| command (currently) just inserts the \refk{prefix}: } \end{source} % -\subsection{Various user commands} +\section{Various user commands} A few user-level wrappers around internal commands. First, a couple primarily for use in the \refk{preamble}, together with \refc{pseudosavelabel} and @@ -4884,7 +5264,7 @@ for setting multiple keys at some later point: \end{source} % % Not allowed to use \code in header, here: -\subsection{The \codefont{pseudo} environment} +\section{The \codefont{pseudo} environment} While this is the main attraction, it's essentially just an augmented \code{tabular} environment, which does a bit of setup initially, using the @@ -4895,8 +5275,8 @@ various macros already described. \group_begin: - \@@_gsave_as:NN \\ \c_@@_saved_cr_cs - \@@_gsave_as:NN \= \c_@@_saved_eq_cs + \@@_cs_gsave_as:NN \\ \c_@@_saved_cr_cs + \@@_cs_gsave_as:NN \= \c_@@_saved_eq_cs % \RestorePseudoBackslash is inside the tabular \RestorePseudoEq @@ -4941,7 +5321,11 @@ various macros already described. \stepcounter{pseudoenv} \setcounter{pseudoline}{\l_@@_start_tl} \addtocounter{pseudoline}{-1} - +\end{source} +Before starting the actual tabular environment, we insert any user-configured +initialization. +\begin{source} + \tl_use:N \l_@@_init_tl \tl_use:N \l_@@_begin_tabular_tl \end{source} We use \cs{noalign} to be able to place these definitions inside the tabular, @@ -5034,7 +5418,7 @@ The starred version of the environment is just a wrapper that uses the custom } \end{source} -\subsection{Boxes and floats} +\section{Boxes and floats} \label{sec:floatsrc} Some spacing and width values are taken from \pkg{booktabs}, to partly emulate @@ -5411,7 +5795,9 @@ preamble, and only if \pkg{tcolorbox} has actually been loaded at that point. \cs_new:Npn \@@_vmaj:n #1 { \@@_vmaj_aux:w #1 \q_stop } \cs_new:Npn \@@_vmaj_aux:w #1 . #2 \q_stop { #1 } - \tl_set:Nx \l_tmpa_tl { \exp_args:No \@@_vmaj:n \tcb@version } + \tl_set:Nx \l_tmpa_tl { + \exp_args:No \@@_vmaj:n \tcb@version + } \int_compare:nNnT \l_tmpa_tl < 5 { diff --git a/macros/latex/contrib/pseudo/pseudo.sty b/macros/latex/contrib/pseudo/pseudo.sty index 2634ab7d38..6fd03eca74 100644 --- a/macros/latex/contrib/pseudo/pseudo.sty +++ b/macros/latex/contrib/pseudo/pseudo.sty @@ -1,6 +1,6 @@ % MIT License % -% Copyright (c) 2019-2022 Magnus Lie Hetland +% Copyright (c) 2019-2023 Magnus Lie Hetland % % Permission is hereby granted, free of charge, to any person obtaining a copy % of this software and associated documentation files (the "Software"), to deal @@ -20,8 +20,8 @@ % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE % SOFTWARE. % -\def \pseudoversion {1.2.1} -\def \pseudodate {2022/08/23} +\def \pseudoversion {1.2.2} +\def \pseudodate {2023/01/30} \RequirePackage{expl3} \ProvidesExplPackage {pseudo} @@ -143,12 +143,19 @@ \DeclareDocumentCommand \pseudosavelabel { } { \__pseudo_save_label: } -\cs_new:Npn \__pseudo_gsave_as:NN #1 #2 { +\cs_new:Npn \__pseudo_cs_gsave_as:NN #1 #2 { \cs_gset_eq:NN #2 #1 \group_insert_after:N \cs_gset_eq:NN \group_insert_after:N #1 \group_insert_after:N #2 } +\cs_new:Npn \__pseudo_skip_pars:n #1 { + \peek_meaning_remove_ignore_spaces:NTF \par { + \__pseudo_skip_pars:n { #1 } + } { + #1 + } +} \__pseudo_new_cmd:Nnn \nf { } { \normalfont } \__pseudo_new_cmd:Nnn \tn { m } { \textnormal { #1 } } \__pseudo_new_cmd:Nnn \kw { m } { \textnormal {\kwfont { #1 } } } @@ -157,7 +164,7 @@ \cs_new:Npn \__pseudo_b_or_bx: { \group_begin: \cs_if_exist:NT \@defaultsubs { - \__pseudo_gsave_as:NN \@defaultsubs \__pseudo_defaultsubs + \__pseudo_cs_gsave_as:NN \@defaultsubs \__pseudo_defaultsubs \cs_gset_eq:NN \@defaultsubs \relax } \cs_gset:Nn \__pseudo_b_or_bx: { \fontseries{b}\selectfont } @@ -274,6 +281,13 @@ } \ProcessKeysOptions{ pseudo/package } \keys_define:nn { pseudo } { + init .tl_set:N = \l__pseudo_init_tl, + init-append .code:n = { + \tl_put_right:Nn \l__pseudo_init_tl {#1} + }, + init-prepend .code:n = { + \tl_put_left:Nn \l__pseudo_init_tl {#1} + }, font .tl_set:N = \pseudofont, font .initial:n = \normalfont, hpad .meta:n = { @@ -551,15 +565,21 @@ } \NewDocumentCommand \__pseudo_eol_tail { s d<> +O{ } } { \__pseudo_eol_handle_args:nnn{#1}{#2}{#3} - \tl_set:Nx \l_tmpa_tl { - \exp_not:N \tabularnewline [ \l__pseudo_extra_space_tl ] - } - \peek_meaning_ignore_spaces:NTF \end { - \l_tmpa_tl + \dim_compare:nNnTF \l__pseudo_extra_space_tl = { 0pt } { + \tl_set_eq:NN \l_tmpa_tl \tabularnewline } { - \pseudoeol - \l_tmpa_tl - \__pseudo_bol: + \tl_set:Nx \l_tmpa_tl { + \exp_not:N \tabularnewline [ \l__pseudo_extra_space_tl ] + } + } + \__pseudo_skip_pars:n { + \peek_meaning_ignore_spaces:NTF \end { + \l_tmpa_tl + } { + \pseudoeol + \l_tmpa_tl + \__pseudo_bol: + } } } \cs_new:Npn \__pseudo_eol: { @@ -598,8 +618,8 @@ } \NewDocumentEnvironment { pseudo } { +o s d<> +O{ } } { \group_begin: - \__pseudo_gsave_as:NN \\ \c__pseudo_saved_cr_cs - \__pseudo_gsave_as:NN \= \c__pseudo_saved_eq_cs + \__pseudo_cs_gsave_as:NN \\ \c__pseudo_saved_cr_cs + \__pseudo_cs_gsave_as:NN \= \c__pseudo_saved_eq_cs \RestorePseudoEq \int_set:Nn \g__pseudo_last_saved_line_int {\arabic{pseudoline}} \__pseudo_star_setup: @@ -630,6 +650,7 @@ \stepcounter{pseudoenv} \setcounter{pseudoline}{\l__pseudo_start_tl} \addtocounter{pseudoline}{-1} + \tl_use:N \l__pseudo_init_tl \tl_use:N \l__pseudo_begin_tabular_tl \tex_noalign:D { \RestorePseudoBackslash @@ -855,7 +876,9 @@ filled/.style = { \@ifpackageloaded { tcolorbox } { \cs_new:Npn \__pseudo_vmaj:n #1 { \__pseudo_vmaj_aux:w #1 \q_stop } \cs_new:Npn \__pseudo_vmaj_aux:w #1 . #2 \q_stop { #1 } - \tl_set:Nx \l_tmpa_tl { \exp_args:No \__pseudo_vmaj:n \tcb@version } + \tl_set:Nx \l_tmpa_tl { + \exp_args:No \__pseudo_vmaj:n \tcb@version + } \int_compare:nNnT \l_tmpa_tl < 5 { \tcbuselibrary { hooks } \tcbset { diff --git a/macros/latex/contrib/pseudo/test/overlaytest.tex b/macros/latex/contrib/pseudo/test/beamertest.tex index 44bdb77c7a..babf88a6f4 100644 --- a/macros/latex/contrib/pseudo/test/overlaytest.tex +++ b/macros/latex/contrib/pseudo/test/beamertest.tex @@ -2,6 +2,7 @@ \usepackage{pseudo} \begin{document} + \begin{frame} \begin{pseudo} foo \\[dim<2->] @@ -9,4 +10,13 @@ baz \end{pseudo} \end{frame} + +% https://github.com/mlhetland/pseudo.sty/issues/21 +\begin{frame} +\begin{pseudo}[pause]* +\hd{A}(x) \\ +B \\ +\end{pseudo} +\end{frame} + \end{document} diff --git a/macros/latex/contrib/tagpdf/README.md b/macros/latex/contrib/tagpdf/README.md index 654c5ec695..e6db86a9e4 100644 --- a/macros/latex/contrib/tagpdf/README.md +++ b/macros/latex/contrib/tagpdf/README.md @@ -1,6 +1,6 @@ #tagpdf — A package to create tagged pdf -Packageversion: 0.98b -Packagedate: 2023/01/24 +Packageversion: 0.98c +Packagedate: 2023/01/30 Author: Ulrike Fischer ## License diff --git a/macros/latex/contrib/tagpdf/tagpdf-backend.dtx b/macros/latex/contrib/tagpdf/tagpdf-backend.dtx index 0028f72397..0a2c4f693f 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-backend.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-backend.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-backend.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -47,13 +47,13 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{implementation} % \begin{macrocode} %<@@=tag> %<*luatex> -\ProvidesExplFile {tagpdf-luatex.def} {2023-01-24} {0.98b} +\ProvidesExplFile {tagpdf-luatex.def} {2023-01-30} {0.98c} {tagpdf~driver~for~luatex} % \end{macrocode} % \section{Loading the lua} @@ -158,8 +158,8 @@ local ProvidesLuaModule = { name = "tagpdf", - version = "0.98b", --TAGVERSION - date = "2023-01-24", --TAGDATE + version = "0.98c", --TAGVERSION + date = "2023-01-30", --TAGDATE description = "tagpdf lua code", license = "The LATEX Project Public License 1.3c" } diff --git a/macros/latex/contrib/tagpdf/tagpdf-checks.dtx b/macros/latex/contrib/tagpdf/tagpdf-checks.dtx index fae3e853d3..a20017a77c 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-checks.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-checks.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-checks.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -48,7 +48,7 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{documentation} % \section{Commands} @@ -295,7 +295,7 @@ % \begin{macrocode} %<@@=tag> %<*header> -\ProvidesExplPackage {tagpdf-checks-code} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-checks-code} {2023-01-30} {0.98c} {part of tagpdf - code related to checks, conditionals, debugging and messages} %</header> % \end{macrocode} diff --git a/macros/latex/contrib/tagpdf/tagpdf-code.pdf b/macros/latex/contrib/tagpdf/tagpdf-code.pdf Binary files differindex 5b954258dd..c8c3c146cb 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-code.pdf +++ b/macros/latex/contrib/tagpdf/tagpdf-code.pdf diff --git a/macros/latex/contrib/tagpdf/tagpdf-data.dtx b/macros/latex/contrib/tagpdf/tagpdf-data.dtx index 93bf80667b..a62f6d3cdb 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-data.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-data.dtx @@ -47,7 +47,7 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{documentation} % This files contains a various data files which are read in @@ -60,7 +60,7 @@ % It lists the new tag, the rolemap and the namespace of the rolemap. % \begin{macrocode} %<*ns-latex> -%% \ProvidesExplFile {tagpdf-ns-latex.def} {2023-01-24} {0.98b} +%% \ProvidesExplFile {tagpdf-ns-latex.def} {2023-01-30} {0.98c} %% {latex} {https://www.latex-project.org/ns/dflt/2022}{} title, Title, pdf2, part, Title, pdf2, @@ -86,7 +86,7 @@ footnotelabel,Lbl, pdf2, % It is bound to change % \begin{macrocode} %<*ns-latex-book> -%% \ProvidesExplFile {tagpdf-ns-latex-book.def} {2023-01-24} {0.98b} +%% \ProvidesExplFile {tagpdf-ns-latex-book.def} {2023-01-30} {0.98c} %% {latex-book} {https://www.latex-project.org/ns/book/2022}{} chapter, H1,pdf2, section, H2,pdf2, @@ -102,7 +102,7 @@ subparagraph, H6,pdf2, % It is bound to change a lot! % \begin{macrocode} %<*ns-latex-inline> -%% \ProvidesExplFile {tagpdf-ns-latex-inline.def} {2023-01-24} {0.98b} +%% \ProvidesExplFile {tagpdf-ns-latex-inline.def} {2023-01-30} {0.98c} %% {latex-inline} {https://www.latex-project.org/ns/inline/2022}{} chapter, Span, pdf2, section, Span, pdf2, @@ -116,7 +116,7 @@ P, Span, pdf2, % \section{The pdf namespace data} % \begin{macrocode} %<*ns-pdf> -%% \ProvidesExplFile {tagpdf-ns-pdf.def} {2023-01-24} {0.98b} +%% \ProvidesExplFile {tagpdf-ns-pdf.def} {2023-01-30} {0.98c} %% {pdf} {http://iso.org/pdf/ssn}{} StructTreeRoot,StructTreeRoot,pdf,D, Document,Document,pdf,D, @@ -184,7 +184,7 @@ Strong,Span,pdf,I, % \section{The pdf 2.0 namespace data} % \begin{macrocode} %<*ns-pdf2> -%% \ProvidesExplFile {tagpdf-ns-pdf2.def} {2023-01-24} {0.98b} +%% \ProvidesExplFile {tagpdf-ns-pdf2.def} {2023-01-30} {0.98c} %% {pdf2} {http://iso.org/pdf2/ssn}{} Document,Document,pdf2,D, Part,Part,pdf2,G, @@ -240,7 +240,7 @@ Strong,Strong,pdf2,I, % \section{The mathml namespace data} % \begin{macrocode} %<*ns-mathml> -%% \ProvidesExplFile {tagpdf-ns-mathml.def} {2023-01-24} {0.98b} +%% \ProvidesExplFile {tagpdf-ns-mathml.def} {2023-01-30} {0.98c} % {mathml}{http://www.w3.org/1998/Math/MathML}{} abs,,, and,,, @@ -475,7 +475,7 @@ xor,,, % This will perhaps change in future. % \begin{macrocode} %<*parent-child> -%% \ProvidesExplFile {tagpdf-parent-child.csv} {2023-01-24} {0.98b} +%% \ProvidesExplFile {tagpdf-parent-child.csv} {2023-01-30} {0.98c} ,,,StructTreeRoot,Document,Art,Part,Div,Sect,BlockQuote,NonStruct,TOC,TOCI,Index,Private,Quote,Note,Reference,BibEntry,P,Hn,H,Lbl,Code,Span,Link,Annot,Form,Ruby,RB,RT,RP,Warichu,WT,WP,L,LI,LBody,Table,TR,TH,TD,THead,TBody,TFoot,Caption,Figure,Formula,MC Document,both,document level,1,0..n,∅,‡,‡,∅,0..n,‡,∅,∅,∅,0..n,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅ Art,1.7,grouping,∅,0..n,∅,‡,‡,0..n,0..n,‡,∅,∅,∅,0..n,∅,0..n,∅,∅,∅,0..1,0..1,∅,∅,∅,0..n,0..n,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,0..n,∅,∅,0..n,0..n,∅,∅,∅,0..n,0..n,∅,∅ @@ -530,7 +530,7 @@ MC,both,---,∅,∅,∅,∅,∅,∅,0..n,‡,∅,∅,∅,0..n,0..n,0..n,0..n,0.. % This will perhaps change in future. % \begin{macrocode} %<*parent-child-2> -%% \ProvidesExplFile {tagpdf-parent-child-2.csv} {2023-01-24} {0.98b} +%% \ProvidesExplFile {tagpdf-parent-child-2.csv} {2023-01-30} {0.98c} ,,,StructTreeRoot,Document,DocumentFragment,Art,Part,Div,Sect,Aside,BlockQuote,NonStruct,TOC,TOCI,Index,Private,Title,Sub,Quote,Note,Reference,BibEntry,P,Hn,H,Lbl,Code,Em,Strong,Span,Link,Annot,Form,Ruby,RB,RT,RP,Warichu,WT,WP,FENote,L,LI,LBody,Table,TR,TH,TD,THead,TBody,TFoot,Caption,Figure,Formula,math,mathml,Artifact,MC Document,both,document level,1,0..n,0..n,∅,‡,‡,∅,0..n,0..n,‡,∅,∅,∅,0..n,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,0..n,∅ DocumentFragment,2.0,document level,∅,0..n,0..n,0..n,‡,‡,0..n,0..n,0..n,‡,∅,∅,∅,0..n,∅,∅,∅,∅*,∅,∅,∅,∅,∅,∅,∅*,∅,∅,∅,∅*,∅*,∅,∅,∅,∅,∅,∅,∅,∅,∅*,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅,∅*,∅,∅,∅,∅,0..n,∅ diff --git a/macros/latex/contrib/tagpdf/tagpdf-mc-generic.dtx b/macros/latex/contrib/tagpdf/tagpdf-mc-generic.dtx index fd3409c73b..1d04a19368 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-mc-generic.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-mc-generic.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-mc-generic.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{documentation} % \end{documentation} @@ -55,11 +55,11 @@ % \begin{macrocode} %<@@=tag> %<*generic> -\ProvidesExplPackage {tagpdf-mc-code-generic} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-mc-code-generic} {2023-01-30} {0.98c} {part of tagpdf - code related to marking chunks - generic mode} %</generic> %<*debug> -\ProvidesExplPackage {tagpdf-debug-generic} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-debug-generic} {2023-01-30} {0.98c} {part of tagpdf - debugging code related to marking chunks - generic mode} %</debug> % \end{macrocode} diff --git a/macros/latex/contrib/tagpdf/tagpdf-mc-luacode.dtx b/macros/latex/contrib/tagpdf/tagpdf-mc-luacode.dtx index de5fe42739..066d2e2243 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-mc-luacode.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-mc-luacode.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-mc-luacode.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{implementation} % The code is splitted into three parts: code shared by all engines, @@ -86,7 +86,7 @@ % \begin{macrocode} %<@@=tag> %<*luamode> -\ProvidesExplPackage {tagpdf-mc-code-lua} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-mc-code-lua} {2023-01-30} {0.98c} {tagpdf - mc code only for the luamode } %</luamode> % \end{macrocode} diff --git a/macros/latex/contrib/tagpdf/tagpdf-mc-shared.dtx b/macros/latex/contrib/tagpdf/tagpdf-mc-shared.dtx index e693242d1b..88c5937f57 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-mc-shared.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-mc-shared.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-mc-shared.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{documentation} % \section{Public Commands} @@ -174,7 +174,7 @@ % \begin{macrocode} %<@@=tag> %<*header> -\ProvidesExplPackage {tagpdf-mc-code-shared} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-mc-code-shared} {2023-01-30} {0.98c} {part of tagpdf - code related to marking chunks - code shared by generic and luamode } %</header> diff --git a/macros/latex/contrib/tagpdf/tagpdf-roles.dtx b/macros/latex/contrib/tagpdf/tagpdf-roles.dtx index 60ba857294..8948b89055 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-roles.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-roles.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-roles.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{documentation} % \begin{function} @@ -85,12 +85,20 @@ % Namespaces are mostly a PDF 2.0 property, but it doesn't harm to % set them also in a PDF 1.7 or earlier. % \end{function} +% +% \begin{function}[TF]{\tag_check_child:nn} +% \begin{syntax} +% \cs{tag_check_child:nn}\Arg{tag}\Arg{namespace} \Arg{true code} \Arg{false code} +% \end{syntax} +% This checks if the tag \meta{tag} from the name space \meta{namespace} +% can be used at the current position. In tagpdf-base it is always true. +% \end{function} % \end{documentation} % \begin{implementation} % \begin{macrocode} %<@@=tag> %<*header> -\ProvidesExplPackage {tagpdf-roles-code} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-roles-code} {2023-01-30} {0.98c} {part of tagpdf - code related to roles and structure names} %</header> % \end{macrocode} @@ -522,14 +530,14 @@ % \begin{macrocode} \tl_if_empty:nF { #2 } { - \prop_get:cnN { g__tag_role_NS_#4_prop } {#3}\l_@@_tmpa_tl + \prop_get:cnN { g_@@_role_NS_#4_prop } {#3}\l_@@_tmpa_tl \quark_if_no_value:NTF \l_@@_tmpa_tl { - \prop_gput:cnx { g__tag_role_NS_#2_prop } {#1} + \prop_gput:cnx { g_@@_role_NS_#2_prop } {#1} {{\tl_to_str:n{#3}}{\tl_to_str:n{#4}}} } { - \prop_gput:cno { g__tag_role_NS_#2_prop } {#1}{\l_@@_tmpa_tl} + \prop_gput:cno { g_@@_role_NS_#2_prop } {#1}{\l_@@_tmpa_tl} } } } @@ -642,7 +650,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_role_read_namespace:n #1 %name of namespace { - \prop_if_exist:cF {g__tag_role_NS_#1_prop} + \prop_if_exist:cF {g_@@_role_NS_#1_prop} { \msg_warning:nnn {tag}{namespace-unknown}{#1} } \file_if_exist:nTF { tagpdf-ns-#1.def} { @@ -1155,6 +1163,30 @@ } \cs_generate_variant:Nn\@@_check_parent_child:nnN {VVN} \cs_generate_variant:Nn\@@_check_parent_child:nnnnN {VVVVN,nVnVN,VVnnN} +%</package> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF]{\tag_check_child:nn} +% \begin{macrocode} +%<base>\prg_new_protected_conditional:Npnn \tag_check_child:nn #1 #2 {T,F,TF}{\prg_return_true:} +%<*package> +\prg_set_protected_conditional:Npnn \tag_check_child:nn #1 #2 {T,F,TF} + { + \seq_get:NN\g_@@_struct_stack_seq\l_@@_tmpa_tl + \@@_struct_get_tag_info:eNN + {\l_@@_tmpa_tl} + \l_@@_get_parent_tmpa_tl + \l_@@_get_parent_tmpb_tl + \@@_check_parent_child:VVnnN + \l_@@_get_parent_tmpa_tl + \l_@@_get_parent_tmpb_tl + {#1}{#2} + \l_@@_parent_child_check_tl + \int_compare:nNnTF { \l_@@_parent_child_check_tl } < {0} + {\prg_return_false:} + {\prg_return_true:} + } % \end{macrocode} % \end{macro} % @@ -1199,7 +1231,7 @@ { \cs_new_protected:Npn \@@_role_remap_inline: { - \prop_get:cVNT { g__tag_role_NS_latex-inline_prop }\l_@@_role_remap_tag_tl\l_@@_tmpa_tl + \prop_get:cVNT { g_@@_role_NS_latex-inline_prop }\l_@@_role_remap_tag_tl\l_@@_tmpa_tl { \tl_set:Nx\l_@@_role_remap_tag_tl { @@ -1219,7 +1251,7 @@ { \cs_new_protected:Npn \@@_role_remap_inline: { - \prop_get:cVNT { g__tag_role_NS_latex-inline_prop }\l_@@_role_remap_tag_tl\l_@@_tmpa_tl + \prop_get:cVNT { g_@@_role_NS_latex-inline_prop }\l_@@_role_remap_tag_tl\l_@@_tmpa_tl { \tl_set:Nn\l_@@_role_remap_NS_tl {latex-inline} } diff --git a/macros/latex/contrib/tagpdf/tagpdf-space.dtx b/macros/latex/contrib/tagpdf/tagpdf-space.dtx index f450520a48..5e21bb0f6a 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-space.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-space.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-space.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{documentation} % \begin{function}{interwordspace (setup-key)} @@ -64,7 +64,7 @@ % \begin{macrocode} %<@@=tag> %<*header> -\ProvidesExplPackage {tagpdf-space-code} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-space-code} {2023-01-30} {0.98c} {part of tagpdf - code related to real space chars} %</header> % \end{macrocode} diff --git a/macros/latex/contrib/tagpdf/tagpdf-struct.dtx b/macros/latex/contrib/tagpdf/tagpdf-struct.dtx index 2e83d51280..229989dad1 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-struct.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-struct.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-struct.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{documentation} % \section{Public Commands} @@ -242,7 +242,7 @@ % \begin{macrocode} %<@@=tag> %<*header> -\ProvidesExplPackage {tagpdf-struct-code} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-struct-code} {2023-01-30} {0.98c} {part of tagpdf - code related to storing structure} %</header> % \end{macrocode} @@ -1510,7 +1510,7 @@ % \section{Attributes and attribute classes} % \begin{macrocode} %<*header> -\ProvidesExplPackage {tagpdf-attr-code} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-attr-code} {2023-01-30} {0.98c} {part of tagpdf - code related to attributes and attribute classes} %</header> % \end{macrocode} @@ -1577,7 +1577,7 @@ { attribute-class .code:n = { - \clist_set:No \l_@@_tmpa_clist { #1 } + \clist_set:Nx \l_@@_tmpa_clist { #1 } \seq_set_from_clist:NN \l_@@_tmpb_seq \l_@@_tmpa_clist % \end{macrocode} % we convert the names into pdf names with slash @@ -1618,50 +1618,53 @@ { attribute .code:n = % A property (attribute, value currently a dictionary) { - \clist_set:No \l_@@_tmpa_clist { #1 } - \seq_set_from_clist:NN \l_@@_tmpb_seq \l_@@_tmpa_clist + \clist_set:Nx \l_@@_tmpa_clist { #1 } + \clist_if_empty:NF \l_@@_tmpa_clist + { + \seq_set_from_clist:NN \l_@@_tmpb_seq \l_@@_tmpa_clist % \end{macrocode} % we convert the names into pdf names with slash % \begin{macrocode} - \seq_set_map_x:NNn \l_@@_tmpa_seq \l_@@_tmpb_seq - { - \pdf_name_from_unicode_e:n {##1} - } - \tl_set:Nx \l_@@_attr_value_tl - { - \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{[}%] - } - \seq_map_inline:Nn \l_@@_tmpa_seq - { - \prop_if_in:NnF \g_@@_attr_entries_prop {##1} + \seq_set_map_x:NNn \l_@@_tmpa_seq \l_@@_tmpb_seq + { + \pdf_name_from_unicode_e:n {##1} + } + \tl_set:Nx \l_@@_attr_value_tl { - \msg_error:nnn { tag } { attr-unknown } { ##1 } + \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{[}%] } - \prop_if_in:NnF \g_@@_attr_objref_prop {##1} - {%\prop_show:N \g_@@_attr_entries_prop - \pdf_object_unnamed_write:nx - { dict } + \seq_map_inline:Nn \l_@@_tmpa_seq + { + \prop_if_in:NnF \g_@@_attr_entries_prop {##1} { - \prop_item:Nn\g_@@_attr_entries_prop {##1} + \msg_error:nnn { tag } { attr-unknown } { ##1 } } - \prop_gput:Nnx \g_@@_attr_objref_prop {##1} {\pdf_object_ref_last:} + \prop_if_in:NnF \g_@@_attr_objref_prop {##1} + {%\prop_show:N \g_@@_attr_entries_prop + \pdf_object_unnamed_write:nx + { dict } + { + \prop_item:Nn\g_@@_attr_entries_prop {##1} + } + \prop_gput:Nnx \g_@@_attr_objref_prop {##1} {\pdf_object_ref_last:} + } + \tl_put_right:Nx \l_@@_attr_value_tl + { + \c_space_tl + \prop_item:Nn \g_@@_attr_objref_prop {##1} + } + % \tl_show:N \l_@@_attr_value_tl } \tl_put_right:Nx \l_@@_attr_value_tl - { - \c_space_tl - \prop_item:Nn \g_@@_attr_objref_prop {##1} + { %[ + \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{]}% } - % \tl_show:N \l_@@_attr_value_tl - } - \tl_put_right:Nx \l_@@_attr_value_tl - { %[ - \int_compare:nT { \seq_count:N \l_@@_tmpa_seq > 1 }{]}% - } - % \tl_show:N \l_@@_attr_value_tl - \@@_prop_gput:cnx - { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop } - { A } - { \l_@@_attr_value_tl } + % \tl_show:N \l_@@_attr_value_tl + \@@_prop_gput:cnx + { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop } + { A } + { \l_@@_attr_value_tl } + } }, } %</package> diff --git a/macros/latex/contrib/tagpdf/tagpdf-tree.dtx b/macros/latex/contrib/tagpdf/tagpdf-tree.dtx index 2a02a7c5df..507681afa6 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-tree.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-tree.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-tree.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -47,13 +47,13 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{implementation} % \begin{macrocode} %<@@=tag> %<*header> -\ProvidesExplPackage {tagpdf-tree-code} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-tree-code} {2023-01-30} {0.98c} {part of tagpdf - code related to writing trees and dictionaries to the pdf} %</header> % \end{macrocode} diff --git a/macros/latex/contrib/tagpdf/tagpdf-user.dtx b/macros/latex/contrib/tagpdf/tagpdf-user.dtx index 309b62a6c1..980641b6b7 100644 --- a/macros/latex/contrib/tagpdf/tagpdf-user.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf-user.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf-user.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Version 0.98b, released 2023-01-24} +% \date{Version 0.98c, released 2023-01-30} % \maketitle % \begin{documentation} % \section{Setup commands} @@ -246,7 +246,7 @@ % \begin{macrocode} %<@@=tag> %<*header> -\ProvidesExplPackage {tagpdf-user} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-user} {2023-01-30} {0.98c} {tagpdf - user commands} %</header> % \end{macrocode} diff --git a/macros/latex/contrib/tagpdf/tagpdf.dtx b/macros/latex/contrib/tagpdf/tagpdf.dtx index c264123ebc..61222d151a 100644 --- a/macros/latex/contrib/tagpdf/tagpdf.dtx +++ b/macros/latex/contrib/tagpdf/tagpdf.dtx @@ -2,7 +2,7 @@ % %% File: tagpdf.dtx % -% Copyright (C) 2019-2022 Ulrike Fischer +% Copyright (C) 2019-2023 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -92,7 +92,7 @@ % \begin{macrocode} %<@@=tag> %<*package> -\ProvidesExplPackage {tagpdf} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf} {2023-01-30} {0.98c} { A package to experiment with pdf tagging } \bool_if:nF @@ -118,7 +118,7 @@ % \end{macrocode} %<*debug> % \begin{macrocode} -\ProvidesExplPackage {tagpdf-debug} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-debug} {2023-01-30} {0.98c} { debug code for tagpdf } \@ifpackageloaded{tagpdf}{}{\PackageWarning{tagpdf-debug}{tagpdf~not~loaded,~quitting}\endinput} % \end{macrocode} @@ -159,7 +159,7 @@ % \end{macrocode} % \begin{macrocode} %<*base> -\ProvidesExplPackage {tagpdf-base} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdf-base} {2023-01-30} {0.98c} {part of tagpdf - provide base, no-op versions of the user commands } %</base> % \end{macrocode} diff --git a/macros/latex/contrib/tagpdf/tagpdf.ins b/macros/latex/contrib/tagpdf/tagpdf.ins index d494018825..d17e709b25 100644 --- a/macros/latex/contrib/tagpdf/tagpdf.ins +++ b/macros/latex/contrib/tagpdf/tagpdf.ins @@ -79,6 +79,7 @@ and all files in that bundle must be distributed together. \from{tagpdf-struct.dtx}{base} \from{tagpdf-checks.dtx}{base} \from{tagpdf-user.dtx}{base} + \from{tagpdf-roles.dtx}{base} } } diff --git a/macros/latex/contrib/tagpdf/tagpdf.pdf b/macros/latex/contrib/tagpdf/tagpdf.pdf Binary files differindex a77e88d3c5..3edd2185eb 100644 --- a/macros/latex/contrib/tagpdf/tagpdf.pdf +++ b/macros/latex/contrib/tagpdf/tagpdf.pdf diff --git a/macros/latex/contrib/tagpdf/tagpdf.tex b/macros/latex/contrib/tagpdf/tagpdf.tex index e36b3e9197..299763001c 100644 --- a/macros/latex/contrib/tagpdf/tagpdf.tex +++ b/macros/latex/contrib/tagpdf/tagpdf.tex @@ -15,8 +15,8 @@ } \makeatletter -\def\UlrikeFischer@package@version{0.98b} -\def\UlrikeFischer@package@date{2023-01-24} +\def\UlrikeFischer@package@version{0.98c} +\def\UlrikeFischer@package@date{2023-01-30} \makeatother \documentclass[DIV=12,parskip=half-,bibliography=totoc,a4paper]{article} diff --git a/macros/latex/contrib/tagpdf/tagpdfdocu-patches.sty b/macros/latex/contrib/tagpdf/tagpdfdocu-patches.sty index 3ad0e3de74..dc1c94b911 100644 --- a/macros/latex/contrib/tagpdf/tagpdfdocu-patches.sty +++ b/macros/latex/contrib/tagpdf/tagpdfdocu-patches.sty @@ -1,5 +1,5 @@ %\RequirePackage[enable-debug]{expl3}[2018/06/14] -\ProvidesExplPackage {tagpdfdocu-patches} {2023-01-24} {0.98b} +\ProvidesExplPackage {tagpdfdocu-patches} {2023-01-30} {0.98c} {patches/commands for the tagpdf documentation} \RequirePackage{etoolbox,xpatch} diff --git a/macros/latex/contrib/tramlines/README b/macros/latex/contrib/tramlines/README index e3dfeb4ebe..b252d9323a 100644 --- a/macros/latex/contrib/tramlines/README +++ b/macros/latex/contrib/tramlines/README @@ -1,6 +1,6 @@ tramlines - make tramlines -version: 1.0.0 +version: 1.1.0 This package automatically creates tramlines (lines above and below a title used by lawyers in the UK and the Commonwealth). @@ -12,4 +12,7 @@ For suggestions, feature requests, and bug reports, please use the project's GitHub site: https://github.com/ezgranet/tramlines Version history: +29/01/2023: Updates to float composition and fixed bug with global commands. Thanks to GitHub user niruvt + + 27/01/2023: package creation
\ No newline at end of file diff --git a/macros/latex/contrib/tramlines/tramlines-documentation.pdf b/macros/latex/contrib/tramlines/tramlines-documentation.pdf Binary files differindex 79938ccd51..e9d9c9d6d9 100644 --- a/macros/latex/contrib/tramlines/tramlines-documentation.pdf +++ b/macros/latex/contrib/tramlines/tramlines-documentation.pdf diff --git a/macros/latex/contrib/tramlines/tramlines-documentation.tex b/macros/latex/contrib/tramlines/tramlines-documentation.tex index 5b9c304601..f39e7ba70c 100644 --- a/macros/latex/contrib/tramlines/tramlines-documentation.tex +++ b/macros/latex/contrib/tramlines/tramlines-documentation.tex @@ -74,11 +74,11 @@ breaklines, firstnumber=last ] {latex} -\def\tramlinesversionnumber{1.0.0} -\ProvidesPackage{textcsc} -[2023/01/27\tramlinesversionnumber\ - Command for caps-to-small-caps-text] -% This work may be distributed and/or modified under the +\def\tramlinesversionnumber{1.1.0} +\ProvidesPackage{tramlines} +[2023/01/29\tramlinesversionnumber\ + Tramlines] + % This work 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 @@ -104,28 +104,32 @@ firstnumber=last % tramlines %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% -\setlength\doublerulesep{1pt}% <-- set distance between double rule - +\newcommand{\tramlinesep}{2pt} \newcommand{\tramlines}[1]{\normalsize -\begin{table*}[ht] +\smallskip +\begin{center} +\begin{minipage}{\textwidth} \centering +{%notglobal +\setlength\doublerulesep{\tramlinesep}% <-- set distance between double rule \begin{tabular}[t]{l c c } \toprule\toprule & #1 & \\ \bottomrule\bottomrule -\end{tabular} -\end{table*} +\end{tabular}} +\end{minipage} +\end{center} + +\smallskip } %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% % all done %%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%% -\end{minted} +%%%%%%%%%%%%%%%%%%%%%%%%%%%\end{minted} -\section{Version History} -\subsection{\texttt{1.0.0}} +\subsection*{\texttt{1.0.0}} \ttfamily 27 January 2023: Package creation diff --git a/macros/latex/contrib/tramlines/tramlines.sty b/macros/latex/contrib/tramlines/tramlines.sty index 4bfa700fb1..f3288a8d1f 100644 --- a/macros/latex/contrib/tramlines/tramlines.sty +++ b/macros/latex/contrib/tramlines/tramlines.sty @@ -1,7 +1,7 @@ -\def\tramlinesversionnumber{1.0.0} -\ProvidesPackage{textcsc} -[2023/01/27\tramlinesversionnumber\ - Command for caps-to-small-caps-text] +\def\tramlinesversionnumber{1.1.0} +\ProvidesPackage{tramlines} +[2023/01/29\tramlinesversionnumber\ + Tramlines] % This work 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. @@ -28,17 +28,23 @@ % tramlines %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%% -\setlength\doublerulesep{1pt}% <-- set distance between double rule - +\newcommand{\tramlinesep}{2pt} \newcommand{\tramlines}[1]{\normalsize -\begin{table*}[ht] +\smallskip +\begin{center} +\begin{minipage}{\textwidth} \centering +{%notglobal +\setlength\doublerulesep{\tramlinesep}% <-- set distance between double rule \begin{tabular}[t]{l c c } \toprule\toprule & #1 & \\ \bottomrule\bottomrule -\end{tabular} -\end{table*} +\end{tabular}} +\end{minipage} +\end{center} + +\smallskip } %%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/macros/luatex/generic/lparse/README.md b/macros/luatex/generic/lparse/README.md new file mode 100644 index 0000000000..f6210b4923 --- /dev/null +++ b/macros/luatex/generic/lparse/README.md @@ -0,0 +1,34 @@ +# lparse + +Parse and scan macro arguments in `Lua` with `LuaTeX` using a `xparse` +like argument specification. + +The name lparse is derived from xparse. The x has been replaced by l +because this package only works with LuaTeX. l stands for Lua. Just as +with xparse, it is possible to use a special syntax consisting of single +letters to express the arguments of a macro. However, lparse is able to +read arguments regardless of the macro systemd used - whether LaTeX or +ConTeXt or even plain TeX. Of course, LuaTeX must always be used as the +engine. + +## Current version + +2023/01/29 v0.1.0 + +## License + +Copyright (C) 2023 by Josef Friedrich <josef@friedrich.rocks> +------------------------------------------------------------------------ +This work may be distributed and/or modified under the conditions of +the LaTeX Project Public License, either version 1.3 of this license +or (at your option) any later version. The latest version of this +license is in: + + http://www.latex-project.org/lppl.txt + +and version 1.3 or later is part of all distributions of LaTeX +version 2005/12/01 or later. + +## Maintainer + +Josef Friedrich <josef@friedrich.rocks> diff --git a/macros/luatex/generic/lparse/lparse-doc.tex b/macros/luatex/generic/lparse/lparse-doc.tex new file mode 100644 index 0000000000..35c618f277 --- /dev/null +++ b/macros/luatex/generic/lparse/lparse-doc.tex @@ -0,0 +1,205 @@ +\documentclass{ltxdoc} + +\EnableCrossrefs +\CodelineIndex +\RecordChanges + +\usepackage{mdframed} +\usepackage{minted} +\usepackage{multicol} +\usepackage{luacode} +\usepackage{syntax} + +\usemintedstyle{friendly} +\BeforeBeginEnvironment{minted}{\begin{mdframed}} +\AfterEndEnvironment{minted}{\end{mdframed}} +\setminted{ + breaklines=true, + fontsize=\footnotesize, + style=manni, +} +\def\lua#1{\mintinline{lua}|#1|} +\def\latex#1{\mintinline{latex}|#1|} + +\NewDocumentCommand { \InputLatex } { O{} m } { + \begin{mdframed} + \inputminted[linenos=false,#1]{latex}{examples/#2} + \end{mdframed} +} + +\NewDocumentCommand { \InputLua } { O{} m } { + \begin{mdframed} + \inputminted[linenos=false,#1]{lua}{examples/#2} + \end{mdframed} +} + +\begin{document} + +\providecommand*{\url}{\texttt} + +\title{The \textsf{lparse} package} +\author{% + Josef Friedrich\\% + \url{josef@friedrich.rocks}\\% + \href{https://github.com/Josef-Friedrich/lparse} + {github.com/Josef-Friedrich/lparse}% +} +\date{0.1.0 from 2023/01/29} + +\maketitle + +\InputLatex[firstline=5,lastline=14]{title-page.tex} + +\newpage + +\tableofcontents + +\newpage + +% \section{Einführung} +\section{Introduction} + +% Der Name |lparse| ist von |xparse| abgeleitet. +The name |lparse| is derived from |xparse|. +% +% Das |x| wurde durch |l| ersetzt, da dieses Packet nur zusammen mit +% Lua\TeX{} funktioniert. +The |x| has been replaced by |l| because this package only works with Lua\TeX{}. +% +% |l| steht für \emph{Lua} +|l| stands for \emph{Lua}. +% +% Ebenso wie bei dem Paket |xparse| ist es möglich, die Argumente eines +% Makros mit Hilfe einer speziellen Syntax bestehend aus einzelnen +% Buchstaben zu beschreiben. +Just as with |xparse|, it is possible to use a special syntax consisting +of single letters to express the arguments of a macro. +% +% |lparse| ist jedoch im Stande unabhängig von der verwendeten +% Makrosammlung - ob LaTeX oder ConTeXt oder sogar Plain TeX - Argumente +% einzulesen. +However, |lparse| is able to read arguments regardless of the macro +systemd used - whether \LaTeX{} or Con\TeX{}t or even plain \TeX. +% +% Als Engine musst natürlich immer LuaTeX verwendet werden. +Of course, Lua\TeX{} must always be used as the engine. + +\subsection{Similar projects} + +% Für ConTeXt gibt es einen ähnlichen Argumenten scanner. +For Con\TeX{}t there is a similar argument scanner (see Con\TeX{}t Lua +Document +\href{http://www.pragma-ade.nl/general/manuals/cld-mkiv.pdf}{cld-mkiv}). +% +% Dieser Scanner ist in folgenden Dateien implementiert +This scanner is implemented in the following files: +\href{https://github.com/contextgarden/context/blob/main/tex/context/base/mkiv/toks-scn.lua}{toks-scn.lua} +\href{https://github.com/contextgarden/context/blob/main/tex/context/base/mkiv/toks-aux.lua}{toks-aux.lua} +\href{https://github.com/contextgarden/context/blob/main/tex/context/base/mkiv/toks-ini.lua}{toks-ini.lua} +% Con\TeX{}t scanner verwendet offenbar die Token Bibliothek des LuaTeX Nachfolgeprojekts luametaTeX +% +Con\TeX{}t scanner apparently uses the token library of the LuaTeX +successor project luameta\TeX: +\href{https://github.com/contextgarden/context/blob/main/source/luametatex/source/lua/lmttokenlib.c}{lmttokenlib.c} + +\section{Description of the argument specification} +% +% Folgende Listen, die die Argumenttypen beschreiben, entstammen den +% Handbücher usrguide bzw. xparse. +The following lists, which describe the individual argument types, are +taken from the manuals +\href{http://mirrors.ctan.org/macros/latex/base/usrguide.pdf}{usrguide} +and +\href{http://mirrors.ctan.org/macros/latex/contrib/l3packages/xparse.pdf}{xparse}. +% +% Die Beschreibungstexte der einzelnen Argumententypen wurden nur leicht angepasst. +The descriptive texts of the individual argument types have only been +slightly adjusted. +% +% Die noch nicht unterstützen Argumentypen sind eingeklammert. +The argument types that are not yet supported are bracketed. + +% /usr/local/texlive/texmf-dist/source/latex/l3packages/xparse/xparse.dtx +\begin{itemize} + \item[m] A standard mandatory argument, which can either be a single + token alone or multiple tokens surrounded by curly braces |{}|. + Regardless of the input, the argument will be passed to the + internal code without the outer braces. This is the \pkg{xparse} + type specifier for a normal \TeX{} argument. + \item[r] Given as \texttt{r}\meta{token1}\meta{token2}, this denotes a + \enquote{required} delimited argument, where the delimiters are + \meta{token1} and \meta{token2}. If the opening delimiter + \meta{token1} is missing, |nil| will be + returned after a suitable error. + \item[R] Given as \texttt{R}\meta{token1}\meta{token2}\marg{default}, + this is a \enquote{required} delimited argument as for~\texttt{r}, + but it has a user-definable recovery \meta{default} instead of + |nil|. + \item[v] Reads an argument \enquote{verbatim}, between the following + character and its next occurrence. + \item[(b)] Not implemented! Only suitable in the argument specification of an + environment, it denotes the body of the environment, between + |\begin|\marg{environment} and |\end|\marg{environment}. +\end{itemize} +The types which define optional arguments are: +\begin{itemize} + \item[o] A standard \LaTeX{} optional argument, surrounded with square + brackets, which will supply + |nil| if not given (as described later). + \item[d] Given as \texttt{d}\meta{token1}\meta{token2}, an optional + argument which is delimited by \meta{token1} and \meta{token2}. + As with \texttt{o}, if no + value is given |nil| is returned. + \item[O] Given as \texttt{O}\marg{default}, is like \texttt{o}, but + returns \meta{default} if no value is given. + \item[D] Given as \texttt{D}\meta{token1}\meta{token2}\marg{default}, + it is as for \texttt{d}, but returns \meta{default} if no value is given. + Internally, the \texttt{o}, \texttt{d} and \texttt{O} types are + short-cuts to an appropriated-constructed \texttt{D} type argument. + \item[s] An optional star, which will result in a value + |true| if a star is present and |false| + otherwise (as described later). + \item[t] An optional \meta{token}, which will result in a value + |true| if \meta{token} is present and |false| + otherwise. Given as \texttt{t}\meta{token}. + \item[(e)] Not implemented! Given as \texttt{e}\marg{tokens}, a set of optional + \emph{embellishments}, each of which requires a \emph{value}. + If an embellishment is not present, |-NoValue-| is returned. Each + embellishment gives one argument, ordered as for the list of + \meta{tokens} in the argument specification. All \meta{tokens} + must be distinct. \emph{This is an experimental type}. + \item[(E)] Not implemented! As for \texttt{e} but returns one or more \meta{defaults} + if values are not given: \texttt{E}\marg{tokens}\marg{defaults}. +\end{itemize} + +\clearpage + +\section{Implementation} + +%% +% +%% + +\subsection{lparse.lua} + +\inputminted[linenos=true]{lua}{lparse.lua} + +%% +% +%% + +\clearpage + +\subsection{lparse.tex} + +\inputminted[linenos=true]{latex}{lparse.tex} + +\clearpage + +\subsection{lparse.sty} + +\inputminted[linenos=true]{latex}{lparse.sty} + +\pagebreak +\PrintIndex +\end{document} diff --git a/macros/luatex/generic/lparse/lparse.lua b/macros/luatex/generic/lparse/lparse.lua new file mode 100644 index 0000000000..755cf2883f --- /dev/null +++ b/macros/luatex/generic/lparse/lparse.lua @@ -0,0 +1,302 @@ +-- lparse.lua +-- Copyright 2023 Josef Friedrich +-- +-- This work 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 +-- http://www.latex-project.org/lppl.txt +-- and version 1.3c or later is part of all distributions of LaTeX +-- version 2008/05/04 or later. +-- +-- This work has the LPPL maintenance status `maintained'. +-- +-- The Current Maintainer of this work is Josef Friedrich. +-- +-- This work consists of the files lparse.lua, lparse.tex, +-- and lparse.sty. +--- +if lpeg == nil then + lpeg = require('lpeg') +end + +--- +---@param spec string +---@return Argument[] +local function parse_spec(spec) + local V = lpeg.V + local P = lpeg.P + local Set = lpeg.S + local Range = lpeg.R + local CaptureFolding = lpeg.Cf + local CaptureTable = lpeg.Ct + local Cc = lpeg.Cc + local CaptureSimple = lpeg.C + + local function add_result(result, value) + if not result then + result = {} + end + table.insert(result, value) + return result + end + + local function collect_delims(a, b) + return { init_delim = a, end_delim = b } + end + + local function collect_token(a) + return { token = a } + end + + local function set_default(a) + return { default = a } + end + + local function combine(...) + local args = { ... } + + local output = {} + + for _, arg in ipairs(args) do + if type(arg) ~= 'table' then + arg = {} + end + + for key, value in pairs(arg) do + output[key] = value + end + + end + + return output + end + + local function ArgumentType(letter) + local function get_type(l) + return { argument_type = l } + end + return CaptureSimple(P(letter)) / get_type + end + + local T = ArgumentType + + local pattern = P({ + 'init', + init = V('whitespace') ^ 0 * + CaptureFolding(CaptureTable('') * V('list'), add_result), + + list = (V('arg') * V('whitespace') ^ 1) ^ 0 * V('arg') ^ -1, + + arg = V('m') + V('r') + V('R') + V('v') + V('o') + V('d') + V('O') + + V('D') + V('s') + V('t'), + + m = T('m') / combine, + + r = T('r') * V('delimiters') / combine, + + R = T('R') * V('delimiters') * V('default') / combine, + + v = T('v') * Cc({ verbatim = true }) / combine, + + o = T('o') * Cc({ optional = true }) / combine, + + d = T('d') * V('delimiters') * Cc({ optional = true }) / combine, + + O = T('O') * V('default') * Cc({ optional = true }) / combine, + + D = T('D') * V('delimiters') * V('default') * + Cc({ optional = true }) / combine, + + s = T('s') * Cc({ star = true }) / combine, + + t = T('t') * V('token') / combine, + + token = V('delimiter') / collect_token, + + delimiter = CaptureSimple(Range('!~')), + + delimiters = V('delimiter') * V('delimiter') / collect_delims, + + whitespace = Set(' \t\n\r'), + + default = P('{') * CaptureSimple((1 - P('}')) ^ 0) * P('}') / + set_default, + }) + + return pattern:match(spec) + +end + +--- +---Scan for an optional argument. +--- +---@param init_delim? string # The character that marks the beginning of an optional argument (by default `[`). +---@param end_delim? string # The character that marks the end of an optional argument (by default `]`). +--- +---@return string|nil # The string that was enclosed by the delimiters. The delimiters themselves are not returned. +local function scan_delimited(init_delim, end_delim) + if init_delim == nil then + init_delim = '[' + end + if end_delim == nil then + end_delim = ']' + end + + --- + ---@param t Token + --- + ---@return string + local function convert_token_to_string(t) + if t.index ~= nil then + return utf8.char(t.index) + else + return '\\' .. t.csname + end + end + + local delimiter_stack = 0 + + local function get_next_char() + local t = token.get_next() + local char = convert_token_to_string(t) + if char == init_delim then + delimiter_stack = delimiter_stack + 1 + end + + if char == end_delim then + delimiter_stack = delimiter_stack - 1 + end + return char, t + end + + local char, t = get_next_char() + + if t.cmdname == 'spacer' then + char, t = get_next_char() + end + + if char == init_delim then + local output = {} + + char, t = get_next_char() + + -- “while” better than “repeat ... until”: The end_delimiter is + -- included in the result output. + while not (char == end_delim and delimiter_stack == 0) do + table.insert(output, char) + char, t = get_next_char() + end + return table.concat(output, '') + else + token.put_next(t) + end +end + +---@class Argument +---@field argument_type? string +---@field optional? boolean +---@field init_delim? string +---@field end_delim? string +---@field dest? string +---@field star? boolean +---@field default? string +---@field verbatim? boolean +---@field token? string + +---@class Parser +---@field args Argument[] +---@field result any[] +local Parser = {} +---@private +Parser.__index = Parser + +function Parser:new(spec) + local parser = {} + setmetatable(parser, Parser) + parser.spec = spec + parser.args = parse_spec(spec) + parser.result = parser:parse(parser.args) + return parser +end + +---@return any[] +function Parser:parse() + local result = {} + local index = 1 + for _, arg in pairs(self.args) do + if arg.star then + -- s + result[index] = token.scan_keyword('*') + elseif arg.token then + -- t + result[index] = token.scan_keyword(arg.token) + elseif arg.optional then + -- o d O D + local oarg = scan_delimited(arg.init_delim, arg.end_delim) + if arg.default and oarg == nil then + oarg = arg.default + end + result[index] = oarg + elseif arg.init_delim and arg.end_delim then + -- r R + local oarg = scan_delimited(arg.init_delim, arg.end_delim) + if arg.default and oarg == nil then + oarg = arg.default + end + if oarg == nil then + tex.error('Missing required argument') + end + result[index] = oarg + else + -- m v + local marg = token.scan_argument(arg.verbatim ~= true) + if marg == nil then + tex.error('Missing required argument') + end + result[index] = marg + end + index = index + 1 + end + return result +end + +---@private +function Parser:set_result(...) + self.result = { ... } +end + +function Parser:assert(...) + local arguments = { ... } + for index, arg in ipairs(arguments) do + assert(self.result[index] == arg, string.format( + 'Argument at index %d doesn’t match: “%s” != “%s”', + index, self.result[index], arg)) + end +end + +--- +---@return string|boolean|nil ... +function Parser:export() + -- #self.arg: to get all elements of the result table, also elements + -- with nil values. + return table.unpack(self.result, 1, #self.args) +end + +function Parser:debug() + for index = 1, #self.args do + print(index, self.result[index]) + end +end + +---@return Parser +local function create_parser(spec) + return Parser:new(spec) +end + +local function scan(spec) + local parser = create_parser(spec) + return parser:export() +end + +return { Parser = create_parser, scan = scan, parse_spec = parse_spec } diff --git a/macros/luatex/generic/lparse/lparse.pdf b/macros/luatex/generic/lparse/lparse.pdf Binary files differnew file mode 100644 index 0000000000..c1afc32823 --- /dev/null +++ b/macros/luatex/generic/lparse/lparse.pdf diff --git a/macros/luatex/generic/lparse/lparse.sty b/macros/luatex/generic/lparse/lparse.sty new file mode 100644 index 0000000000..9d4fb2412f --- /dev/null +++ b/macros/luatex/generic/lparse/lparse.sty @@ -0,0 +1,22 @@ +%% lparse.sty +%% Copyright 2023 Josef Friedrich +% +% This work 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 +% http://www.latex-project.org/lppl.txt +% and version 1.3c or later is part of all distributions of LaTeX +% version 2008/05/04 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Josef Friedrich. +% +% This work consists of the files lparse.lua, lparse.tex, +% and lparse.sty. + +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{lparse}[2023/01/29 v0.1.0 Parse and scan macro arguments in Lua on LuaTeX using a xparse like argument specification] + +\input lparse.tex diff --git a/macros/luatex/generic/lparse/lparse.tex b/macros/luatex/generic/lparse/lparse.tex new file mode 100644 index 0000000000..7393d581e5 --- /dev/null +++ b/macros/luatex/generic/lparse/lparse.tex @@ -0,0 +1,22 @@ +%% lparse.tex +%% Copyright 2023 Josef Friedrich +% +% This work 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 +% http://www.latex-project.org/lppl.txt +% and version 1.3c or later is part of all distributions of LaTeX +% version 2008/05/04 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Josef Friedrich. +% +% This work consists of the files lparse.lua, lparse.tex, +% and lparse.sty. + +\directlua +{ + lparse = require('lparse') +} |