Sophanatprime / cus

CusTeX
8 stars 4 forks source link

`\section` 中有 cs 时的 `\tableofcontents` 出现报错 #17

Closed xkwxdyy closed 1 month ago

xkwxdyy commented 1 month ago

场景

下面可能不是一个最 minimal 的 MWE,但可以复现问题

% !TeX program = xelatex
\documentclass{ctexbook}
\usepackage{cus}
\ExplSyntaxOn
\NewDocumentCommand { \whudefineconstant } { m }
  {
    \keys_set:nn { whu/constant } {#1}
  }

\cs_new_protected:Nn \__whu_define_constant_family:n
  {
    \keys_define:nn { whu/constant }
      {
        #1/中文正文 .code:n =
          { \__whu_set_constant:nnn {#1} { \l_keys_key_str } {##1} }
      , #1/中文目录 .code:n =
          { \__whu_set_constant:nnn {#1} { \l_keys_key_str } {##1} }
      , #1/英文正文 .code:n =
          { \__whu_set_constant:nnn {#1} { \l_keys_key_str } {##1} }
      , #1/英文目录 .code:n =
          { \__whu_set_constant:nnn {#1} { \l_keys_key_str } {##1} }
      , #1         .code:n = 
          {
            \keys_set:nn { whu/constant/#1 } { ##1 }
            \bool_lazy_and:nnT
              { \__whu_constant_if_exist_p:nn {#1} {中文正文} }
              { ! \__whu_constant_if_exist_p:nn {#1} {中文目录} }
              {
                \__whu_set_constant:nnn {#1} {中文目录}
                  { \__whu_use_constant:nn {#1} {中文正文} }
              }
            \bool_lazy_and:nnT
              { \__whu_constant_if_exist_p:nn {#1} {英文正文} }
              { ! \__whu_constant_if_exist_p:nn {#1} {英文目录} }
              {
                \__whu_set_constant:nnn {#1} {英文目录}
                  { \__whu_use_constant:nn {#1} {英文正文} }
              }
          }
      }
  }

\__whu_define_constant_family:n {致谢}
\cs_new_protected:Nn \__whu_set_constant:nnn
  {
    \tl_const:cn { c__whu_constant_ #1/#2 _tl } {#3}
  }
\cs_new_protected:Nn \__whu_use_constant:nn
  {
    \tl_use:c { c__whu_constant_ #1/#2 _tl }
  }
\cs_new_protected:Nn \__whu_get_constant_csname:nn
  {
    c__whu_constant_ #1/#2 _tl
  }
\prg_new_conditional:Nnn \__whu_constant_if_exist:nn { p , T , F , TF }
  {
    \tl_if_exist:cTF { \__whu_get_constant_csname:nn {#1} {#2} }
      \prg_return_true:
      \prg_return_false:
  }
\ExplSyntaxOff
\enablecombinedlist

\begin{document}
\whudefineconstant{
  致谢={
    中文正文=致\quad 谢
  }
}

\tableofcontents

\ExplSyntaxOn
\section{
  \__whu_use_constant:nn{致谢}{中文正文}
}
\ExplSyntaxOff
\end{document}

使用 xelatex 编译后报错

! Missing $ inserted.
<inserted text> 
                $
l.73 

? 

尝试

  1. 去掉 \tableofcontents 后不报错
  2. 不去掉 \tableofcontents,但是\section的参数改为正常文本,不报错
xkwxdyy commented 1 month ago

测试期间发现了一个警告

Package hyperref: Token not allowed in a PDF string (Unicode):
(hyperref)  removing `\__whu_use_constant:nn'.

猜测会不会是展开的太晚了?

Sophanatprime commented 1 month ago

在写入目录文件、标签、书签等时,\protected 的宏不会被展开。\__whu_use_constant:nn 不能定义成 \protected。 而且在读入目录文件时,不会开启 LaTeX3 语法环境,所以展开之后的内容不能有以 LaTeX3 命名规范命名(包含 _ : 等)的命令。

xkwxdyy commented 1 month ago

在写入目录文件、标签、书签等时,\protected 的宏不会被展开。\__whu_use_constant:nn 不能定义成 \protected

原来如此,感谢提醒。

而且在读入目录文件时,不会开启 LaTeX3 语法环境,所以展开之后的内容不能有以 LaTeX3 命名规范命名(包含 _ : 等)的命令。

请问我这个需求怎么办,能用别的方式解决吗?

xkwxdyy commented 1 month ago

或者把 _ 换成 @

Sophanatprime commented 1 month ago

请问我这个需求怎么办,能用别的方式解决吗?

\tl_use:N 是可展的,用 \cs_new:Npn \__whu_use_constant:nn 就可以了,写入目录文件时它会自己展开。

xkwxdyy commented 1 month ago

\tl_use:N 是可展的,用 \cs_new:Npn \__whu_use_constant:nn 就可以了,写入目录文件时它会自己展开。

我可能没表述清楚,我看到您这句话

而且在读入目录文件时,不会开启 LaTeX3 语法环境,所以展开之后的内容不能有以 LaTeX3 命名规范命名(包含 _ ``: 等)的命令。

的时候,我以为是除了 protected 的另外一个问题,我以为除了改成 \cs_new:Npn \__whu_use_constant:nn外 展开的内容里面不能出现 _, 所以我本来打算把 c__whu_constant_ #1/#2 _tl 改成 c@@whu@constant@ #1/#2 @tl 的。

但测试下来改成 \cs_new:Npn \__whu_use_constant:nn 之后 c__whu_constant_ #1/#2 _tlc@@whu@constant@ #1/#2 @tl 都可以行得通,但是 c__whu_constant_ #1/#2 _tl 里面不是也有 _ 吗?这和您上面那个

不能有以 LaTeX3 命名规范命名(包含 _ ``: 等)的命令。

之间好像不太一样?(抱歉,我有点不太懂太深的展开原理)

Sophanatprime commented 1 month ago

一个命令能否展开、会不会展开、怎么展开和它所处的上下文有关。 interface3.pdf 里标记 ⋆ 的是可以用于 ef 参数,标记 ✩ 可以用于 e 参数,用在这些参数中它们被完全展开。 写入目录文件、标签、书签等,和用在 e 参数中类似,不过用 \DeclareRobustCommand 定义的命令也不会展开,所以 \textbf 这些可以安全的写入目录文件。

\protected 命令不会在 e 参数中展开,但出现在控制序列的名称中会展开(所以 \__whu_get_constant_csname:nn 能生效)。 所以使用 \cs_new:Npn \__whu_use_constant:nn 会在 e 参数中展开为 \tl_use:c { c__whu_constant_ #1/#2 _tl }\tl_use:c 还可以展开,但它先把后面那个变成一个控制序列,变成了 \tl_use:N <...>\tl_use:N 还可以展开,它的作用是展开为那个 tl 的内容,而这个 tl 的内容并没有 LaTeX3 名称的命令,所以能够正确读取。

xkwxdyy commented 1 month ago

一个命令能否展开、会不会展开、怎么展开和它所处的上下文有关。 interface3.pdf 里标记 ⋆ 的是可以用于 ef 参数,标记 ✩ 可以用于 e 参数,用在这些参数中它们被完全展开。 写入目录文件、标签、书签等,和用在 e 参数中类似,不过用 \DeclareRobustCommand 定义的命令也不会展开,所以 \textbf 这些可以安全的写入目录文件。

\protected 命令不会在 e 参数中展开,但出现在控制序列的名称中会展开(所以 \__whu_get_constant_csname:nn 能生效)。 所以使用 \cs_new:Npn \__whu_use_constant:nn 会在 e 参数中展开为 \tl_use:c { c__whu_constant_ #1/#2 _tl }\tl_use:c 还可以展开,但它先把后面那个变成一个控制序列,变成了 \tl_use:N <...>\tl_use:N 还可以展开,它的作用是展开为那个 tl 的内容,而这个 tl 的内容并没有 LaTeX3 名称的命令,所以能够正确读取。

非常感谢!