100 如何更合理地为文档类设计用户接口?

发布于 2023-02-17 15:23:19

用 latex3 给用户设计接口的时候总是遇到一类问题,就是要根据键值来重设某些命令,但这项工作在用户调用接口之前就完成了,这样的话这个接口就无效了。下面给出一个关于脚注样式的mwe。

% test.cls
\NeedsTeXFormat {LaTeX2e}
\ProvidesExplClass {test} {2023/02/17} {0.1} {Just a test}
\RequirePackage {l3keys2e}
%%
\LoadClass{article}
%%
\cs_new:Npn \__symbol:n #1 {\tex_char:D #1 \scan_stop:}
\tl_new:N \g__fn_num_style_tl
\tl_new:N \g__fn_num_XITS_tl
\tl_new:N \g__fn_num_plain_tl
\tl_gset:Nn \g__fn_num_XITS_tl {XITS}
\tl_gset:Nn \g__fn_num_plain_tl {plain}
%%
\keys_define:nn {test/style} {
  footnote-num .choice:,
  footnote-num .value_required:n = true,
  footnote-num .choices:nn =
    {XITS, plain}
    {\tl_gset:NV \g__fn_num_style_tl \l_keys_choice_tl},
  footnote-num .initial:n = {XITS}
}
%%
%% 这个函数是带圈数字支持
\cs_new:Npn \__select_fn_num:n #1 {
  \int_compare:nTF {#1>=21}
    {
      \int_compare:nTF {#1>=47}
        {\__symbol:n {\int_eval:n {"24B6-47+#1}}}
        {\__symbol:n {\int_eval:n {"24D0-21+#1}}}
    }
    {\__symbol:n {\int_eval:n {"2460-1+#1}}}
}
\cs_new:Npn \__plain_fn_num:n #1 {\int_use:N #1}
%%
\cs_new:Npn \__fn_num_:N #1 {
  \tl_case:Nn \g__fn_num_style_tl {
    \g__fn_num_XITS_tl  {\__select_fn_num:n {#1}}
    \g__fn_num_plain_tl {\__plain_fn_num:n  {#1}}
  }
}
%% 以下是脚注调整
\tl_set:Nn \thefootnote {\__fn_num_:N \c@footnote}
\tl_if_eq:NnF \g__fn_num_style_tl {plain} {
  \tl_new:N  \g__makefnmark_tl
  \tl_gset:Nn \g__makefnmark_tl {\hbox{\normalfont\@thefnmark\space}}
  \cs_set:Npn \@makefntext #1 {
    \noindent\hb@xt@2em{\hss\g__makefnmark_tl}#1
  }
}
%%
\NewDocumentCommand \testsetup {m} {
  \keys_set:nn {test} {#1}
}
%%
\endinput
%%
%%
%% 需要 xelatex,需要 XITS 字体
\documentclass{test}
\usepackage{fontspec}
\setmainfont{XITS}
%%
%% 这个接口没法回头再去设置脚注编号样式,除非用钩子把第 43-49 行代码移到 \testsetup 之后
\testsetup {
  style/footnote-num = plain
}
%%
\begin{document}
test\footnote{test}
\end{document}

如上所见,对于带圈数字,我想让编号和正文一样;而对于 plain 样式,脚注编号应位于左上角,但上面的效果还是和正文一样。

这类问题和命令作用顺序有关,可以通过钩子把脚注调整代码移到接口命令之后来解决。但是当代码多了,钩子也多了,就会很乱。这类问题有没有更合适的解决方法呢?

查看更多

关注者
0
被浏览
1k
 個亼滴兲箜
個亼滴兲箜 2023-02-17
这家伙很懒,什么也没写!

我会交换一下 \tl_if_eq:Nn\cs_set:Npn \@makefntext 的顺序

% test.cls
\NeedsTeXFormat {LaTeX2e}
\ProvidesExplClass {test} {2023/02/17} {0.1} {Just a test}
\RequirePackage {l3keys2e}
%%
\LoadClass{article}
%%
\cs_new:Npn \__symbol:n #1 {\tex_char:D #1 \scan_stop:}
\tl_new:N \g__fn_num_style_tl
\tl_new:N \g__fn_num_XITS_tl
\tl_new:N \g__fn_num_plain_tl
\tl_gset:Nn \g__fn_num_XITS_tl {XITS}
\tl_gset:Nn \g__fn_num_plain_tl {plain}
%%
\keys_define:nn {test/style} {
  footnote-num .choice:,
  footnote-num .value_required:n = true,
  footnote-num .choices:nn =
    {XITS, plain}
    {\tl_gset:NV \g__fn_num_style_tl \l_keys_choice_tl},
  footnote-num .initial:n = {XITS}
}
%%
%% 这个函数是带圈数字支持
\cs_new:Npn \__select_fn_num:n #1 {
  \int_compare:nTF {#1>=21}
    {
      \int_compare:nTF {#1>=47}
        {\__symbol:n {\int_eval:n {"24B6-47+#1}}}
        {\__symbol:n {\int_eval:n {"24D0-21+#1}}}
    }
    {\__symbol:n {\int_eval:n {"2460-1+#1}}}
}
\cs_new:Npn \__plain_fn_num:n #1 {\int_use:N #1}
%%
\cs_new:Npn \__fn_num_:N #1 {
  \tl_case:Nn \g__fn_num_style_tl {
    \g__fn_num_XITS_tl  {\__select_fn_num:n {#1}}
    \g__fn_num_plain_tl {\__plain_fn_num:n  {#1}}
  }
}
%% 以下是脚注调整
\tl_set:Nn \thefootnote {\__fn_num_:N \c@footnote}
\tl_new:N  \g__makefnmark_tl
\tl_gset:Nn \g__makefnmark_tl {\hbox{\normalfont\@thefnmark\space}}
\cs_set_eq:NN \__old_@makefntext:n \@makefntext
\cs_set:Npn \@makefntext #1
  {
    \tl_if_eq:NnTF \g__fn_num_style_tl {plain}
    { \__old_@makefntext:n {#1} }
    { \noindent\hb@xt@2em{\hss\g__makefnmark_tl}#1 }
  }
%%
\NewDocumentCommand \testsetup {m} {
  \keys_set:nn {test} {#1}
}
%%
\endinput

另外借个楼,看有没有人感兴趣。我写毕业论文的时候也用到了带圈数字的功能,觉得这个功能完全可以模块化成单独宏包,然后就写了个自用的小包包,哈哈~ circlenum.sty

1 个回答

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览