27 Star 115 Fork 32

xkwxdyy/exam-zh

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
exam-zh-math.sty 15.15 KB
一键复制 编辑 原始数据 按行查看 历史
kangweixia_xdyy 提交于 2024-03-23 16:08 . 修改版本号
%
% Copyright (c) 2024 Kangwei Xia
% Released under the LaTeX Project Public License v1.3c License.
% Repository: https://gitee.com/xkwxdyy/exam-zh
%
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expl3}
\ProvidesExplPackage {exam-zh-math} {2024-03-23} {v0.2.3}
{exam-zh math module}
\RequirePackage { tabularray }
\RequirePackage { varwidth }
\RequirePackage { graphicx }
\RequirePackage { filehook }
\file_if_exist:nT { wrapstuff.sty }
{
\RequirePackage { wrapstuff }
\AtEndOfPackageFile* { exam-zh-choices }
{
\AddToHook { env / choices / before }
{ \wrapstuffclear }
}
}
\keys_define:nn { exam-zh }
{ calculations .meta:nn = { exam-zh / calculations } {#1} }
%% calculations 环境 %%
% 图片相对于 label 的方位
\str_new:N \l__examzh_calculations_figure_position_str
% coffin type 的对齐方式
\str_new:N \l__examzh_calculations_coffin_align_str
\keys_define:nn { exam-zh / calculations }
{
% calculations 环境的 label 从几开始(但是其实是 index + seq 函数的 ##1 才是最终的 index)
index .int_set:N = \l__examzh_calculations_label_index_shift_int,
% 每行多少个(等价于有多少列)
columns .int_set:N = \l__examzh_calculations_column_int,
% 图片相对于文字的位置(上下左右)
fig-pos .choices:nn =
{ top, above, bottom, below, left, right, left-top }
{ \str_set:Nx \l__examzh_calculations_figure_position_str { \l_keys_choice_tl } },
% 环境上方的额外距离
top-sep .skip_set:N = \l__examzh_calculations_top_sep_skip,
% 环境下方的额外距离
bottom-sep .skip_set:N = \l__examzh_calculations_bottom_sep_skip,
% 两列之间的水平间距
hsep .skip_set:N = \l__examzh_calculations_hsep_skip,
% 两行之间的垂直间距
vsep .skip_set:N = \l__examzh_calculations_vsep_skip,
% 整体的偏移量
xshift .dim_set:N = \l__examzh_calculations_xshift_dim,
hshift .dim_set:N = \l__examzh_calculations_xshift_dim,
yshift .dim_set:N = \l__examzh_calculations_yshift_dim,
vshift .dim_set:N = \l__examzh_calculations_yshift_dim,
% label 的偏移量
label-xshift .dim_set:N = \l__examzh_calculations_label_xshift_dim,
label-hshift .dim_set:N = \l__examzh_calculations_label_xshift_dim,
label-yshift .dim_set:N = \l__examzh_calculations_label_yshift_dim,
label-vshift .dim_set:N = \l__examzh_calculations_label_yshift_dim,
% 对齐方式
align .choices:nn =
{ t, m, b }
{ \str_set:Nx \l__examzh_calculations_coffin_align_str { \l_keys_choice_tl } }
}
\keys_set:nn { exam-zh / calculations }
{
index = 0,
columns = 2,
fig-pos = left-top,
xshift = 2em,
hsep = 2em,
vsep = 0pt,
label-xshift = 0pt,
align = t,
top-sep = 1ex plus .5ex minus .5ex,
bottom-sep = 0pt,
}
% item 的 index 指标(即第几个 item)
\int_new:N \l__examzh_calculations_item_index_int
% 将拼接后的 coffin 存到 seq 里
\seq_new:N \l__examzh_calculations_store_seq
% 上面的 seq 的 item 数
\int_new:N \l__examzh_calculations_store_seq_item_int
% 最终放在 tblr 里的内容
\tl_new:N \l__examzh_calculations_tblr_content_tl
% #1: 设置 calculations
% #2: 设置里面的 tblr
\NewDocumentEnvironment { calculations } { O{ } +O{ } }
{
\group_begin:
\RenewDocumentCommand \item { O{ } }
{ \__examzh_calculations_item:n {##1} }
\int_set:Nn \l__examzh_calculations_item_index_int {0}
\seq_clear:N \l__examzh_calculations_store_seq
\tl_clear:N \l__examzh_calculations_tblr_content_tl
\keys_set:nn { exam-zh / calculations } {#1}
}
{
% 结束收集
\unskip
\end{varwidth}
% \end{minipage}
\hcoffin_set_end:
% 拼接 label 和 figure
\__examzh_calculations_coffin_join:
% 输出
\__examzh_calculations_coffin_typeset:n {#2}
% \par \int_use:N \l__examzh_calculations_item_index_int
\group_end:
}
% 拼接 label 和 figure
\cs_new:Npn \__examzh_calculations_coffin_join:
{
\int_step_inline:nn { \l__examzh_calculations_item_index_int }
{
\__examzh_calculations_coffin_join_position_set:n {##1}
\seq_gput_right:Nn \l__examzh_calculations_store_seq
{
\__examzh_calculations_coffin_align_set:n {##1}
\kern\l__examzh_calculations_hsep_skip
}
}
}
\cs_new:Npn \__examzh_calculations_coffin_align_set:n #1
{
\str_case:Vn \l__examzh_calculations_coffin_align_str
{
{t} { \__examzh_calculations_coffin_align_set_t:n {#1} }
{m} { \__examzh_calculations_coffin_align_set_m:n {#1} }
{b} { \__examzh_calculations_coffin_align_set_b:n {#1} }
}
}
\cs_new:Npn \__examzh_calculations_coffin_align_set_t:n #1
{
\coffin_typeset:cnnnn
{ l__examzh_calculations_figure_ \int_to_roman:n { #1 } _coffin }
{ l } { t } % align = t
{ \l__examzh_calculations_xshift_dim } { \l__examzh_calculations_yshift_dim + 1em }
}
\cs_new:Npn \__examzh_calculations_coffin_align_set_m:n #1
{
\coffin_typeset:cnnnn
{ l__examzh_calculations_figure_ \int_to_roman:n { #1 } _coffin }
{ l } { vc } % align = m
{ \l__examzh_calculations_xshift_dim } { \l__examzh_calculations_yshift_dim }
}
\cs_new:Npn \__examzh_calculations_coffin_align_set_b:n #1
{
\coffin_typeset:cnnnn
{ l__examzh_calculations_figure_ \int_to_roman:n { #1 } _coffin }
{ l } { b } % align = b
{ \l__examzh_calculations_xshift_dim } { \l__examzh_calculations_yshift_dim }
}
\cs_new:Npn \__examzh_calculations_coffin_join_position_set:n #1
{
\use:c { __examzh_calculations_coffin_join_position_set_ \l__examzh_calculations_figure_position_str :n } {#1}
}
\cs_new:cpn { __examzh_calculations_coffin_join_position_set_left-top :n } #1
{
\coffin_join:cnncnnnn
{ l__examzh_calculations_figure_ \int_to_roman:n {#1} _ coffin }
{ l } { t }
{ l__examzh_calculations_label_ \int_to_roman:n {#1} _ coffin }
{ r } { b }
{ \l__examzh_calculations_label_xshift_dim }
{ \l__examzh_calculations_label_yshift_dim -10.6pt}
}
\cs_new:Npn \__examzh_calculations_coffin_join_position_set_top:n #1
{
\coffin_join:cnncnnnn
{ l__examzh_calculations_figure_ \int_to_roman:n {#1} _ coffin }
{ hc } { b }
{ l__examzh_calculations_label_ \int_to_roman:n {#1} _ coffin }
{ hc } { t }
{ \l__examzh_calculations_label_xshift_dim }
{ \l__examzh_calculations_label_yshift_dim - 6pt }
}
\cs_set_eq:NN
\__examzh_calculations_coffin_join_position_set_above:n
\__examzh_calculations_coffin_join_position_set_top:n
\cs_new:Npn \__examzh_calculations_coffin_join_position_set_bottom:n #1
{
\coffin_join:cnncnnnn
{ l__examzh_calculations_figure_ \int_to_roman:n {#1} _ coffin }
{ hc } { t }
{ l__examzh_calculations_label_ \int_to_roman:n {#1} _ coffin }
{ hc } { b }
{ \l__examzh_calculations_label_xshift_dim }
{ \l__examzh_calculations_label_yshift_dim + 6pt }
}
\cs_set_eq:NN
\__examzh_calculations_coffin_join_position_set_below:n
\__examzh_calculations_coffin_join_position_set_bottom:n
\cs_new:Npn \__examzh_calculations_coffin_join_position_set_left:n #1
{
\coffin_join:cnncnnnn
{ l__examzh_calculations_figure_ \int_to_roman:n {#1} _ coffin }
{ l } { vc }
{ l__examzh_calculations_label_ \int_to_roman:n {#1} _ coffin }
{ r } { vc }
{ \l__examzh_calculations_label_xshift_dim - 6pt }
{ \l__examzh_calculations_label_yshift_dim }
}
\cs_new:Npn \__examzh_calculations_coffin_join_position_set_right:n #1
{
\coffin_join:cnncnnnn
{ l__examzh_calculations_figure_ \int_to_roman:n {#1} _ coffin }
{ r } { vc }
{ l__examzh_calculations_label_ \int_to_roman:n {#1} _ coffin }
{ l } { vc }
{ \l__examzh_calculations_label_xshift_dim + 2pt }
{ \l__examzh_calculations_label_yshift_dim }
}
\cs_new:Npn \__examzh_calculations_coffin_typeset:n #1
{
\__examzh_calculations_coffin_typeset_count:
\seq_map_indexed_inline:Nn \l__examzh_calculations_store_seq
% ##1: index
% ##2: content
{
\int_compare:nNnTF { \int_mod:nn {##1} { \l__examzh_calculations_column_int } } = {0}
{
\tl_gput_right:Nn \l__examzh_calculations_tblr_content_tl
{ ##2 \\[\l__examzh_calculations_vsep_skip] }
}
{
\tl_gput_right:Nn \l__examzh_calculations_tblr_content_tl
{ ##2 & }
}
}
% 如果 seq 的 item 比 column 多且不整除 column 的话,要补 &
\int_compare:nNnT { \l__examzh_calculations_store_seq_item_int } > { \l__examzh_calculations_column_int }
{
\int_compare:nNnF { \l__examzh_calculations_item_num_mod_column_left_int } = { 0 }
{
\tl_gput_right:Nx \l__examzh_calculations_tblr_content_tl
{
\prg_replicate:nn { \l__examzh_calculations_item_num_mod_column_left_int -1 } {&}
}
% \int_use:N \l__examzh_calculations_item_num_mod_column_left_int
}
}
\par
\vspace*{ \l__examzh_calculations_top_sep_skip }
\noindent
% \centering
% \SetTblrInner
% {
% rowsep = 4pt,
% % colsep = 0pt
% }
\begin{tblr}
[ expand = \l__examzh_calculations_tblr_content_tl ]
{
width = \linewidth,
columns =
{
l,
leftsep = 0em,
rightsep = 0pt,
},
rows =
{
m,
ht=\baselineskip,
abovesep = 0pt,
belowsep = 0pt,
},
stretch=0,
#1
}
\l__examzh_calculations_tblr_content_tl
\end{tblr}
\vspace*{ \l__examzh_calculations_bottom_sep_skip }
\par
}
\int_new:N \l__examzh_calculations_item_num_mod_column_left_int
\cs_new:Npn \__examzh_calculations_coffin_typeset_count:
{
% 计算 seq 有多少项
\int_set:Nn \l__examzh_calculations_store_seq_item_int
{ \seq_count:N \l__examzh_calculations_store_seq }
% seq 项数小于 column 的话,column 设置为 seq 项数
\int_compare:nNnTF { \l__examzh_calculations_store_seq_item_int } < { \l__examzh_calculations_column_int }
{ \int_set_eq:NN \l__examzh_calculations_column_int \l__examzh_calculations_store_seq_item_int }
{
% 计算 \l__examzh_calculations_store_seq_item_int mod \l__examzh_calculations_column_int 的余数,用于补 &
\int_set:Nn \l__examzh_calculations_item_num_mod_column_left_int { \int_mod:nn { \l__examzh_calculations_store_seq_item_int } { \l__examzh_calculations_column_int } }
}
}
\cs_new:Npn \__examzh_calculations_item:n #1
{
% 增加指标(g 是关键)
\int_gincr:N \l__examzh_calculations_item_index_int
% 新建 coffin
\__examzh_calculations_item_new_coffin:
% 储存 label(一直出不来的原因是因为没改成 gset)
\hcoffin_gset:cn
{ l__examzh_calculations_label_ \int_to_roman:n { \l__examzh_calculations_item_index_int } _coffin }
{
% 加上 index 键值设置的偏移量才是最终的 index
% (\int_eval:n { \l__examzh_calculations_item_index_int + \l__examzh_calculations_label_index_shift_int - 1} )
% 如果 \item 的[] 中没内容,则需要把 label 升高
% \tl_if_blank:nTF {#1}
% {
% \box_move_up:nn { 2.7pt } { \hbox{\__examzh_calculations_the_label:} }
% \space
% #1
% }
% {
% \__examzh_calculations_the_label: #1
% }
% \IfBooleanTF{#1}{#1 yes}{#1 no}
% \IfNoValueTF{#1}
% {
% \dim_set:Nn \l__examzh_calculations_label_yshift_dim { 4pt }
% }{#1 yes}
}
% 储存 figure
\int_compare:nNnF { \l__examzh_calculations_item_index_int } = {1}
{
\unskip
\end{varwidth}
% \end{minipage}
% 结束上一个 item 的收集
\hcoffin_set_end:
}
% 收集
\hcoffin_set:cw { l__examzh_calculations_figure_ \int_to_roman:n { \l__examzh_calculations_item_index_int } _coffin }
% \begin{varwidth}{\hsize}
% 根据 columns 个数设置宽度
\__examzh_calculations_item_varwidth_width_set:
\begin{varwidth}{\l__examzh_calculations_item_varwidth_width_dim}
% \begin{minipage}{8cm}
\ignorespaces
\makebox[0em]{\rule{0pt}{\baselineskip}}
\__examzh_calculations_the_label:
}
\dim_new:N \l__examzh_calculations_item_varwidth_width_dim
\cs_new:Npn \__examzh_calculations_item_varwidth_width_set:
{
\int_case:nnF { \l__examzh_calculations_column_int }
{
{1} { \dim_set:Nn \l__examzh_calculations_item_varwidth_width_dim {0.8 \textwidth} }
{2} { \dim_set:Nn \l__examzh_calculations_item_varwidth_width_dim {0.3 \textwidth} }
{3} { \dim_set:Nn \l__examzh_calculations_item_varwidth_width_dim {0.3 \textwidth} }
{4} { \dim_set:Nn \l__examzh_calculations_item_varwidth_width_dim {0.2 \textwidth} }
}
{ \dim_set:Nn \l__examzh_calculations_item_varwidth_width_dim { \hsize } }
}
% 新建 coffin
\cs_new:Npn \__examzh_calculations_item_new_coffin:
{
% 放图片的 coffin
\coffin_if_exist:cF { l__examzh_calculations_figure_ \int_to_roman:n { \l__examzh_calculations_item_index_int } _coffin }
{ \coffin_new:c { l__examzh_calculations_figure_ \int_to_roman:n { \l__examzh_calculations_item_index_int } _coffin } }
% 放 label 的 coffin
\coffin_if_exist:cF { l__examzh_calculations_label_ \int_to_roman:n { \l__examzh_calculations_item_index_int } _coffin }
{ \coffin_new:c { l__examzh_calculations_label_ \int_to_roman:n { \l__examzh_calculations_item_index_int } _coffin } }
}
\tl_new:N \l__examzh_calculations_counters_commands_set_tl
\keys_define:nn { exam-zh / calculations }
{
label .tl_set:N = \l__examzh_calculations_label_tl
}
\keys_set:nn { exam-zh / calculations }
{
label = \arabic*
}
\cs_new:Npn \__examzh_calculations_the_label:
{
\group_begin:
% 定义计数器相关的命令函数
\l__examzh_calculations_counters_commands_set_tl
% 输出处理后的 label
\l__examzh_calculations_label_tl
\group_end:
}
\NewDocumentCommand \AddCalculationsCounter { m m }
{
% 生成用户层命令
\tl_put_right:Nn \l__examzh_calculations_counters_commands_set_tl
{ \__examzh_process_counter:NNn #1 #2 { calculations } }
% 把核心函数存起来
\cs_set_eq:cN { __examzh_calculations_save_ \cs_to_str:N #1 : } #2
\cs_set_eq:cN { __examzh_calculations_save_ \cs_to_str:N #2 : } #2
}
\AddCalculationsCounter \arabic \@arabic
\AddCalculationsCounter \alph \@alph
\AddCalculationsCounter \Alph \@Alph
\AddCalculationsCounter \roman \@roman
\AddCalculationsCounter \Roman \@Roman
\cs_new:Npn \__examzh_calculations_process_counter_aux:Nn #1#2
{
\tl_if_eq:nnTF {#2} { * }
{
% \Alph*
\use:c { __examzh_calculations_save_ \cs_to_str:N #1 : }
{ \int_eval:n { \l__examzh_calculations_item_index_int + \l__examzh_calculations_label_index_shift_int } }
}
{
% \Alph{...}
\use:c { __examzh_calculations_save_ \cs_to_str:N #1 : }
{#2}
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
TeX/LaTeX
1
https://gitee.com/xkwxdyy/exam-zh.git
git@gitee.com:xkwxdyy/exam-zh.git
xkwxdyy
exam-zh
exam-zh
main

搜索帮助

23e8dbc6 1850385 7e0993f3 1850385