LaTeX 3 的最新用户级手册(Ivo Welch 的后续)

LaTeX 3 的最新用户级手册(Ivo Welch 的后续)

这不是重复,而是 Ivo Welch 的问题引发的后续问题是否有针对用户(非专家)的 LaTeX 3 过渡指南?他询问是否有供用户使用的 LaTeX 3 过渡指南。

在 StackExchange 上,我注意到许多答案都包含Hooks与描述新宏的选项和参数的奇怪方式相关的代码。Ivo 的一个答案提到了文档usrguide3。跟进后,我发现interface3lthooks手册都提到了。我已经设法做到了texdoc这些,但对我来说,它们没有提供关于现在可以在 LaTeX 中做什么的集成用户级手册。

作为一名前软件开发人员,我知道首要任务是记录您所做的工作(如果您后来记不清为什么以及如何做,这确实很有帮助)。其次是向潜在用户解释如何利用您的杰出工作。

我强烈地感觉到,文档编制可能比原始工作花费更多的时间,但它非常重要。

我感谢所有为当前文档所付出的辛勤工作,但我希望很快就能开发出一些全面的用户级手册,解释并强调在当前 LaTeX 环境中可以做什么 — — 至少是针对用户(而不一定是包编写者)的usrguide3interfaces3lthooks文档的连接。

答案1

LaTeX3(L3 编程层)接口\cs_new_protected:Npn主要面向软件包编写者和高级用户。而 LaTeX2 接口则\NewDocumentCommand面向普通用户。

对于高级用户(我将其定义为对 TeX 宏扩展有一定了解的用户),interface3是一本全面且优秀的手册,在我看来,它或多或少足够了。

对于普通用户来说,由于目前LaTeX3只有一小部分提供了LaTeX2的接口,因此可供阅读的手册并不多:

  • xparse:对于\NewDocumentCommand,,\NewDocumentEnvironment等等。
  • xfp:对于\inteval\fpeval
  • lthooksltcmdhooksltfilehook:对于\AddToHook,,\RemoveFromHook等等。

甚至 LaTeX3 中的整数步进函数都\int_step_inline还没有提供 LaTeX2 接口,所以对于普通用户我建议使用其他现有的软件包例如pgffor并耐心等待。

PS:另请参阅我打开的一个相关问题这里几天前。


2022-03-19 更新:我写了一篇新functional基于 LaTeX3 编程层 ( expl3) 的软件包。该软件包提供了易于使用的 LaTeX2 接口,可expl3模拟其他编程语言(如Lua或 )中的函数式编程JavaScript。并且该软件包的手册包含的示例比 还多interface3。我认为这个软件包对许多普通用户来说会很方便。

答案2

供参考

通过(非常快速的)原型教程式的实验性试用如下:

快速演示

(它突出显示了令牌是什么)

通过俗话说的粗略计算,我估计需要花费大约 400 小时(对我来说:没有盲打等)。从字数上看,这差不多相当于一本中篇小说(12 号)。

幸运的是,expl3 的结构一致且合乎逻辑。

Expl3-coders:一个“原子”层(每个命令如何工作,+评论,练习),一个“场景”层(解决实际用例),以及也许是众所周知的食谱(项目等)。

我认为用户转换指南应该是最少的,因为 expl3 将是他们将要使用的用户命令的内部内容。

巧合的是,过去一周左右出现了大量解释性问题。

平均能量损失

\documentclass{article}
\usepackage{regexpatch}% also loads xparse
\usepackage{fontspec}
\newfontfamily\testfont{Noto Serif}
%\tracingxpatches

\usepackage{tcolorbox}
\tcbuselibrary{skins,xparse}
\tcbuselibrary{listings}


\DeclareTCBListing{mybox}{ s O{} m }{%
colback=red!3!white,
colframe=red!75!blue,
fonttitle=\sffamily\bfseries,
bicolor,
colbacklower=yellow!20,
segmentation style={double=white,draw=blue,
double distance=1pt,solid},
listing options={style=tcblatex,numbers=left,numberstyle=\small\color{blue!75!black},numbersep=5pt},%IfBooleanTF={#1}
%{listing side text}
%{text side listing},
title=\getegcounter\ -- #3,#2}



\ExplSyntaxOn

%\int_new:N \ic_eg_count
%\newcounter{egcounter}[section]
\newcounter{ic_eg_count}[section]
%\newcommand\getegcounter{\refstepcounter{egcounter}[\thesection.\theegcounter]}


\cs_new:Nn \ic_get_egnum: {
%\refstepcounter{egcounter}[\thesection.\theegcounter]
\refstepcounter{ic_eg_count}[\thesection.\theic_eg_count]
}

\cs_set_eq:NN \getegcounter \ic_get_egnum:


\int_new:N \g_commcount_int
\NewDocumentCommand { \comm } {  } {
    \textsc{Commentary:} ~
    \int_gset:Nn \g_commcount_int { 0 }
}
\NewDocumentCommand { \cc } {  } {
    \par\noindent
    ( \int_gincr:N \g_commcount_int
    {
        \sffamily
        \int_use:N \g_commcount_int
        }
    ) ~
}
\NewDocumentCommand { \nocomm } {  } {
    -- ~
}
\NewDocumentCommand { \res } {  } {
    \par\textsc{Result:} ~
}



%\newcommand{\dobb}[1]{\renewcommand\ProcessedArgument{\fbox{\textcolor{blue}{\textbf{#1}}}}}


\cs_new:Npn \ic_do_bluebold: #1  {
\renewcommand\ProcessedArgument{\fbox{\textcolor{blue}{\textbf{#1}}}}
%\cs_gset:Nn \ic_processed_arg:n { \fbox{\textcolor{blue}{\textbf{#1}}} }
%\exp_args:NNo \cs_gset_eq:NN \ProcessedArgument \ic_processed_arg:n
}


\NewDocumentCommand { \dca } { s o >{\ic_do_bluebold:}m v } {
    #4 ~ : ~ 
    \IfBooleanTF {#1} {star} {no star}
    ;~ \IfNoValueTF {#2} {no opt = #2} {OArg = #2}
    ;~ MArg = #3.
%   \par \#3 ~ after ~ pre-processing = #3
}

\NewDocumentEnvironment { codeillus } { +b } {
    \begin{quotation}
    \marginpar{\getegcounter}
    \ttfamily
    #1
    \end{quotation}
}{}

%\newcommand\icmarker{ \% <------}
\cs_new:Nn \ic_marker: {  \% ~ <------ }
\tl_new:N \l_ic_parm_tl
\NewDocumentCommand { \vv } { m O{\ic_marker:} } {
    \tl_set:Nn \l_ic_parm_tl { #1 }
    {
    \bfseries
    \color{blue}
%  \detokenize { #1 }
  \tl_to_str:N \l_ic_parm_tl
    } ~~~ #2
}

\ExplSyntaxOff




\begin{document}

\section{Basics}

%===================== 
\begin{codeillus}
\vv{\ExplSyntaxOn}

Some code.

Some code.

Some code.

\vv{\ExplSyntaxOff}

\end{codeillus}


%===================== 
\begin{codeillus}
Some code.

\vv{\group_begin:}

Some code.

\vv{\group_end:}

Some code.
\end{codeillus}



%===================== 
\begin{mybox}{Grouping}
\ExplSyntaxOn
Text ~ text ~
\group_begin:
\color{red}
\large
text ~ text ~
\group_end:
text ~ text.
\ExplSyntaxOff
\end{mybox}
\bigskip




%===================== 
\begin{mybox}{Defining a function}
\ExplSyntaxOn
\cs_new:Npn \ic_funca:n #1 { {\color{blue} \bfseries #1 } }

Text ~ \ic_funca:n { ~ This ~ is ~ blue ~ bold. } ~ Text.
\ExplSyntaxOff
\end{mybox}
\bigskip



%===================== 
\begin{mybox}{Defining a user command}
\ExplSyntaxOn
\NewDocumentCommand { \mycmdb } { m } {
\cs_new:Npn \ic_funcb:n ##1 { {\color{blue} \bfseries ##1 } }
 \ic_funcb:n { #1 }
 }
\ExplSyntaxOff
Text \mycmdb{This is blue bold.} Text.
\end{mybox}
\bigskip


%===================== 
\begin{mybox}{Using a token list}
\ExplSyntaxOn
\tl_new:N \l_myicc_tl
\NewDocumentCommand { \mycmdc } { m } {
\tl_set:Nn \l_myicc_tl { #1 }
\cs_new:Npn \ic_funcc:N ##1 { {\color{blue} \bfseries ##1 } }
 \ic_funcc:N \l_myicc_tl
 }
\ExplSyntaxOff
Text \mycmdc{This is blue bold.} Text.
\end{mybox}
\bigskip



%===================== 
\begin{mybox}{Appending to a token list}
\ExplSyntaxOn
\tl_new:N \l_myicd_tl
\NewDocumentCommand { \mycmdd } { m } {
\tl_set:Nn \l_myicd_tl { #1 }
\tl_put_right:Nn \l_myicd_tl { $\leftarrow$ ! ! }
\tl_put_left:Nn \l_myicd_tl { ! ! $\rightarrow$ }
\cs_new:Npn \ic_funcd:N ##1 { {\color{blue} \bfseries ##1 } }
 \ic_funcd:N \l_myicd_tl
 }
\ExplSyntaxOff
Text \mycmdd{This is blue bold.} Text.
\end{mybox}
\bigskip


%===================== 
\begin{mybox}{Modifying a token list (\texttt{\textbackslash tl\_replace})} 
\ExplSyntaxOn
\tl_new:N \l_myice_tl
\NewDocumentCommand { \mycmde } { m } {
\tl_set:Nn \l_myice_tl { #1 }
\tl_replace_all:Nnn \l_myice_tl { blue } { not ~ red }
\tl_replace_all:Nnn \l_myice_tl { bold } { italic }
\cs_new:Npn \ic_funce:N ##1 { {\color{blue} \bfseries ##1 } }
 \ic_funce:N \l_myice_tl
 }
\ExplSyntaxOff
Text \mycmde{This is blue bold.} Text.
\end{mybox}
\bigskip

%===================== 
\begin{mybox}{Modifying a token list (\texttt{\textbackslash regex\_replace})} 
\ExplSyntaxOn
\tl_new:N \l_myicez_tl
\NewDocumentCommand { \mycmdez } { m } {
\tl_set:Nn \l_myicez_tl { #1 }
\regex_replace_all:nnN 
{ (\c{color} \cB\{ [^\cE\}]* \cE\}) } 
{ not \  } 
\l_myicez_tl
\regex_replace_all:nnN 
{ \c{textbf}(.+)(bold) } 
{ is\ \c{textsc}\1 small\ caps } 
\l_myicez_tl
\tl_use:N \l_myicez_tl
 }
\ExplSyntaxOff
Text \mycmdez{This is {\color{blue}blue} and \textbf{bold}.} Text.
\end{mybox}
\bigskip




%===================== 
\begin{mybox}{Copying a control sequence}
\ExplSyntaxOn
\cs_new:Npn \ic_funcf:N #1 { {\color{blue} \bfseries #1 } }
\cs_new_eq:NN \mybbcmd \ic_funcf:N
\ExplSyntaxOff
Text \mybbcmd{This is blue bold.} Text.
\end{mybox}
\bigskip




%===================== 
\begin{mybox}{Looping}
\ExplSyntaxOn
\cs_set:Npn \ic_funcg:n #1 { \symbol{#1} }
\cs_set:Nn \ic_funcgb:  {
\int_step_function:nnnN { 97 } { 1 } { 122 } \ic_funcg:n
\ 
}
\cs_new_eq:NN \myloopcmd \ic_funcgb:
\ExplSyntaxOff
Text \myloopcmd Text.
\end{mybox}
\bigskip

\comm
\cc Open the expl3 environment.
\cc Define a 1-parameter function, g, that will print a glyph, given the glyph's slot number, in the current font using the symbol command.
\cc Define a no-parameter function, gb, that will
\cc step through values 97 to 122 (inclusive) and pass each value to the g function.
\cc Add a space (replacing the one gobbled after the command in the user code).
\cc \nocomm
\cc Create a user-command, \textbackslash myloopcmd, that will call the gb function.
\cc Close the expl3 environment.
\cc Use the user-command
\res The letters a..z are printed, followed by a space.
%\begin{quotation}
%>>\myloopcmd<<
%\end{quotation}



%===================== 
\begin{mybox}{Mapping function}
\ExplSyntaxOn
\cs_set:Npn \ic_funch:n #1 { \fbox{#1}. }
\tl_new:N \l_myich_tl
\NewDocumentCommand { \mycmdh } { m } {
\tl_set:Nn \l_myich_tl { #1 }
\tl_map_function:NN \l_myich_tl \ic_funch:n
\par tl ~ = ~ >> \tl_use:N \l_myich_tl << 
}
\ExplSyntaxOff
Text \mycmdh{abc{de}fgh} Text.
\end{mybox}
\bigskip


%===================== 
\begin{mybox}{Mapping inline function}
\ExplSyntaxOn
\cs_set:Npn \ic_funci:n #1 { \fbox{#1}. }
\tl_new:N \l_myici_tl
\NewDocumentCommand { \mycmdi } { m } {
\tl_set:Nn \l_myici_tl { #1 }
\tl_map_inline:Nn \l_myici_tl { \ic_funci:n {##1} }
\par tl ~ = ~ >> \tl_use:N \l_myici_tl << 
}
\ExplSyntaxOff
Text \mycmdi{abc{de}fgh} Text.
\end{mybox}
\bigskip


%===================== 
\begin{mybox}{Contents of a token list (1)}
\ExplSyntaxOn
\tl_new:N \l_myicj_tl
\NewDocumentCommand { \mycmdj } { m } {
\tl_set:Nn \l_myicj_tl { #1 }
\par (a) ~ \tl_count:N \l_myicj_tl  \ token ~ groups.
\par (b) ~ \tl_count_tokens:n { \l_myicj_tl } ~ token \int_compare:nNnTF {\tl_count_tokens:n { \l_myicj_tl }} = { 1 } { } { s }.
\par (c) ~ \exp_args:No \tl_count_tokens:n { \l_myicj_tl } ~ tokens: ~
{ \color{blue} \tl_to_str:N \l_myicj_tl }.
}
\ExplSyntaxOff
\mycmdj{abc{de}fgh}
\end{mybox}
\bigskip




%===================== 
\begin{mybox}{Contents of a token list (2)}
\ExplSyntaxOn
\tl_new:N \l_myick_tl
\NewDocumentCommand { \mycmdk } { m } {
\tl_set:Nn \l_myick_tl { #1 }
\par head: ~ \tl_head:N \l_myick_tl  
\par tail: ~ \tl_tail:N \l_myick_tl  
\par reverse: ~ \tl_reverse:N \l_myick_tl   \tl_use:N \l_myick_tl ~<~ \tl_to_str:N \l_myick_tl
\par 5th ~ item : ~ \tl_item:Nn \l_myick_tl { 5 }
\par reverse: ~ \tl_reverse:N \l_myick_tl   \tl_use:N \l_myick_tl ~<~ \tl_to_str:N \l_myick_tl
\par reverse ~ items: ~ \exp_args:No \tl_reverse_items:n { \l_myick_tl } ~<~ \tl_to_str:N \l_myick_tl
\par 5th ~ item : ~ \tl_item:Nn \l_myick_tl { 5 }
}
\ExplSyntaxOff
\mycmdk{abc{de}fgh}
\end{mybox}
\bigskip





%===================== 
\begin{mybox}{Tokens}
\ExplSyntaxOn
\tl_new:N \l_myiclz_tl
\cs_set:Npn \ic_funcl:n #1 { 
\tl_set:Nn \l_myiclz_tl { #1 }
\fbox{ \strut \tl_to_str:N \l_myiclz_tl } $^ \exp_args:No \tl_count_tokens:n { \l_myiclz_tl }$
\int_compare:nNnT 
{ \exp_args:No \tl_count_tokens:n { \l_myiclz_tl } }
> 
{ 1 }
 { >> \mycmdl{#1} << }
}
\tl_new:N \l_myicl_tl
\NewDocumentCommand { \mycmdl } { m } {
\tl_set:Nn \l_myicl_tl { #1 }
\tl_map_function:NN \l_myicl_tl \ic_funcl:n
}
\ExplSyntaxOff
 \mycmdl{abc{d\textit{e}}fgh}
\end{mybox}
\bigskip

%\tl_item:Nn






*=====



\section{regexpatch}


\begin{mybox}{testca}
\newcommand{\testca}{\textit{label}}
Before: \testca
\par \regexpatchcmd{\testca}{\c{textit}}{\c{textbf}}{S}{F}
\par \xpatchcmd{\testca}{label}{babble}{S}{F}
\par After: \testca
\end{mybox}
\bigskip


%\xshowcmd*\ph
%\makeatletter
%\makeatother

%\tracingxpatches
\begin{mybox}{ph: Too many brace levels}
\newcommand{\ph}[1]{
\textbf{\textsc{{\color{blue}#1}}}\ \ }
Before: {\testfont\ph{Snail in the Bottle}}
\regexpatchcmd{\ph}{\c{color}\cB\{blue\cE\}}{red}{}{F}
\par After: {\testfont\ph{Snail in the Bottle}}
\end{mybox}
\bigskip

\tracingxpatches[0]
\begin{mybox}{ph2: Two levels of braces}
\newcommand{\phb}[1]{\textsc{{\color{blue}#1}}\ \ }
Before: {\testfont\phb{Snail in the Bottle}}
\regexpatchcmd{\phb}{\c{color}\cB\{blue\cE\}}{red}{}{F}
\par After: {\testfont\phb{Snail in the Bottle}}
\end{mybox}
\bigskip

\begin{mybox}{ph3: Entire \textbackslash color command replaced}
\newcommand{\phc}[1]{{
\bfseries\scshape\color{blue}#1\ \ }}
Before: {\testfont\phc{Snail in the Bottle}}
\regexpatchcmd{\phc}{\c{color}\cB\{blue\cE\}} {\c{color}\cB\{red\cE\}}{}{F}
\par After: {\testfont\phc{Snail in the Bottle}}
\end{mybox}
\bigskip

\begin{mybox}{ph4: Text replaced: `blue' > `red'}
\newcommand{\phd}[1]{{
\bfseries\scshape\color{blue}#1\ \ }}
Before: {\testfont\phd{Snail in the Bottle}}
\xpatchcmd{\phd}{blue}{red}{}{F}
\par After: {\testfont\phd{Snail in the Bottle}}
\end{mybox}
\bigskip



\begin{mybox}{ph5: Text (`blue') replaced by a macro (`\textbackslash mycolour')}
\newcommand{\mycolour}{green}
\newcommand{\phe}[1]{{
\bfseries\scshape\color{blue}#1\ \ }}
Before: {\testfont\phe{Snail in the Bottle}}
\regexpatchcmd{\phe}{blue}{\c{mycolour}}{}{F}
\par After: {\testfont\phe{Snail in the Bottle}}
\end{mybox}
\bigskip


\begin{mybox}{ph6: Multi-level grouping without braces\footnote{\sffamily\color{blue!5} ``patchable'' = it can be reconstructed from its decomposition under the current category code egime. -- Manual, \S 7.1 (2018/05/02)}} 
\newcommand{\mycolour}{brown}
\newcommand{\phf}[1]{\begingroup
\bfseries\begingroup\scshape\begingroup\color{blue}#1\endgroup\ smallcaps\endgroup \ bold\endgroup\ normal \ \ }
Before: {\testfont\phf{Snail in the Bottle}}
\regexpatchcmd{\phf}{blue}{\c{mycolour}}{}{F}
\par After: {\testfont\phf{Snail in the Bottle}}
\end{mybox}
\bigskip

\dca{x}{\dca{x}}

\dca*{y}{\dca*{y}}

\dca[abc]{z}{\dca[abc]{z}}

\dca[xyz]{zz}{\dca[xyz]{zz}}

\dca*[xyzz]{zzz}{\dca*[xyzz]{zzz}}


\begin{mybox}{ph4a: Text replaced: `blue' > `red'}
\newcommand{\phda}[2]{{
\bfseries\scshape\color{blue}#1\normalcolor\ in the \color{blue}#2}}
Before: {\testfont\phda{Snail}{Bottle}}
\xpatchcmd{\phda}{blue}{red}{}{F}
\par After: {\testfont\phda{Snail}{Bottle}}
\end{mybox}
\bigskip

\begin{mybox}{ph4b: Text replaced: all `blue' > `red'}
\newcommand{\phdb}[2]{{
\bfseries\scshape\color{blue}#1\normalcolor\ in the \color{blue}#2}}
Before: {\testfont\phdb{Snail}{Bottle}}
\xpatchcmd*{\phdb}{blue}{red}{}{F}
\par After: {\testfont\phdb{Snail}{Bottle}}
\end{mybox}
\bigskip





\end{document}

相关内容