CTeX-org / forum

A temporarily alternate forum of `bbs.ctex.org`
https://t.me/chinesetex
Apache License 2.0
210 stars 16 forks source link

命令可选参数键值的值为 LaTeX3 的 cs 的可行性 #311

Open xkwxdyy opened 3 months ago

xkwxdyy commented 3 months ago

检查清单

操作系统

mac os 14

TeX 发行版

TeXLive 2024

描述问题

原始场景

开发 whuthesis 论文模板。因为涉及到本硕博多个版本,想考虑先做一个框架出来,然后利用键值设置不同的版本。

比如封面就可以拆成一个个组件(类似于 xtemplate?)或者叫模块,然后控制这些模块的内容以及之间的距离。

在做封面的时候,为了防止标题的不同高度造成的排版偏差,考虑用 tikz 的 node 来将一些模块固定,比如 logo 等。也就是整个封面会在 tikzpicture 的环境下进行。

遇到问题

在考虑模块的之间的距离的时候,比如 top-head 表示 head 模块(包含 clc,UDC 等)到 text area 的顶部的距离 由于是通过键值控制的,键值 top-head 对应的 dim 在定义时(由于是用 clist 批量处理,所以这里采用了 map_line_function,就需要定义一个函数),用 tl 的 replace 函数,把 - 替换为 _ 再 new,也就是 top-head 对应的为 \l__whu_top_head_tl. 比如

\cs_new:Npn \__whu_cover_new_width_en:n #1 
  {
    \tl_set:Nn \l__whu_tpma_tl { #1 }
    \tl_replace_once:Nnn \l__whu_tpma_tl { - } { _ } 
    \dim_new:c { g__whu_cover_en_ \l__whu_tpma_tl _width_dim }
    \keys_define:nn { whu/cover/en/width }
      {
        #1 .code:n =
          { \dim_gset:cn { g__whu_cover_en_ \l__whu_tpma_tl _width_dim } { ##1 } }
      }
  }

然后使用的时候,其实借鉴了muzi 在 #309 里的操作,定义一个 use 的 cs

\cs_new:Npn \__whu_cover_use_width:nn #1#2
  {
    \tl_set:Nn \l__whu_tpma_tl { #2 }
    \tl_replace_once:Nnn \l__whu_tpma_tl { - } { _ } 
    \dim_use:c { g__whu_cover_ #1 _ \l__whu_tpma_tl _width_dim }
  }

然后比如设置加载 logo 的图片,就使用:

\includegraphics[width = \__whu_cover_use_width:nn{zh}{logo}]{logo.png}

来使用。但是编译后报错,见下面的 MWE

最小工作示例(MWE)

\documentclass{article}
% \usepackage{tikz}
\usepackage{graphicx}

\begin{document}

\ExplSyntaxOn
\dim_new:c { l_test_xdyy_dim }
\dim_set:cn { l_test_xdyy_dim } { 2pt }
\cs_new:Npn \__test:n #1
  {
    \tl_set:Nn \l_tmpa_tl { #1 }
    \tl_replace_once:Nnn \l_tmpa_tl { - } { _ } 
    \dim_use:c { l_ \l_tmpa_tl _dim }
  }
% \tikz \draw [ line~width = \dim_use:c { l_test-xdyy_dim } ] (0,0) -- (1,0);  % works
% \tikz \draw [ line~width = \__test:n { test-xdyy } ] (0,0) -- (1,0);  % fails
\includegraphics[width = \__test:n{test-xdyy}]{example-image-a}
% \__test:n{test-xdyy}
\ExplSyntaxOff

\end{document}

使用 pdflatex 编译后报错

! Missing number, treated as zero.
<to be read again> 
                   \__kernel_tl_set:Nx 
l.18 ...h = \__test:n{test-xdyy}]{example-image-a}

? 

在 tikz 中的键值也是如此

\documentclass{article}
\usepackage{tikz}

\begin{document}

\ExplSyntaxOn
\dim_new:N \l_test_xdyy_dim
\dim_set:Nn \l_test_xdyy_dim { 2pt }
\cs_new:Npn \__test:n #1
  {
    \tl_set:Nn \l_tmpa_tl { #1 }
    \tl_replace_once:Nnn \l_tmpa_tl { - } { _ } 
    \dim_use:c { l_ \l_tmpa_tl _dim }
  }
% \tikz \draw [ line~width = \dim_use:c { l_ test_xdyy _dim } ] (0,0) -- (1,0);  % works
\tikz \draw [ line~width = \__test:n { test-xdyy } ] (0,0) -- (1,0);  % fails
\ExplSyntaxOff

\end{document}

用 pdflatex 编译后,日志文件输出:

! You can't use `\relax' after \the.
<recently read> \l__dim 

l.16 ...w [ line~width = \__test:n { test-xdyy } ]
                                                   (0,0) -- (1,0);  % fails
? 

链接

No response

其他信息

尝试把上面的 cs 的 new 改为 protected:

\documentclass{article}
\usepackage{tikz}

\begin{document}

\ExplSyntaxOn
\dim_new:N \l_test_xdyy_dim
\dim_set:Nn \l_test_xdyy_dim { 2pt }
\cs_new_protected:Npn \__test:n #1
  {
    \tl_set:Nn \l_tmpa_tl { #1 }
    \tl_replace_once:Nnn \l_tmpa_tl { - } { _ } 
    \dim_use:c { l_ \l_tmpa_tl _dim }
  }
% \tikz \draw [ line~width = \dim_use:c { l_ test_xdyy _dim } ] (0,0) -- (1,0);  % works
\tikz \draw [ line~width = \__test:n { test-xdyy } ] (0,0) -- (1,0);  % fails
\ExplSyntaxOff

\end{document}

使用 PDFLaTeX 编译后报错:

! Missing \endcsname inserted.
<to be read again> 
                   \__kernel_tl_set:Nx 
l.16 ...w [ line~width = \__test:n { test-xdyy } ]
                                                   (0,0) -- (1,0);  % fails
? 

不知道如何才能实现这种在键值中使用 cs。

(我后面发现其实没必要替换,dim new 的时候反正都是 c 展开,可以直接用 -,然后使用的时候用 [ line~width = \dim_use:c { l_ test_xdyy _dim } ] 这样是不会报错的。但是考虑到这个需求应用范围比较广,以及 whuthesis 开发过程中可能还是会碰到这个问题,所以就来请教一下,还是想知道解决办法。)

附件

No response

muzimuzhi commented 3 months ago

取决于每个键是如何定义、值是如何存储和使用的,有的键接受的值要能展开到字面量/literal value(借用通用变成语言里的概念)。

比如 \includegraphics[width = \__test:n{test-xdyy}]{example-image-a} 里,width 的值需要展开到类似 1pt 这样的 dimension denotation(也就是说,对于 width=<dimen><dimen> 要能 \setlength\mylen{<dimen>}),而你的 \__test:n 的实现是不可展开的(所有 \tl_set:Nn 这样的赋值都不可展开)。

几种解决方案


texdoc interface3 里的函数,都用星星标记了它们的可展开性。 image

PS: texdoc interface3 里的函数依然都是宏,所以没有返回值,只有 texdoc texbytopic chap. 1 "The Structure of the TeX Processor" 里提到的步骤。

muzimuzhi commented 3 months ago

可以用 unravel 宏包逐步地查看一个命令是怎么展开和执行的,这比传统的\tracingall...\tracingnone 或其他单一的 \tracingxxx primitive,要更直观一些。

\documentclass{article}
\usepackage{unravel}

\begin{document}
\unravel{<command(s)>}
\end{document}

在命令行编译,然后就能在命令行「步进」查看了。

xkwxdyy commented 3 months ago

谢谢 muzi,我试一下。