-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathexam.sty
284 lines (236 loc) · 8.72 KB
/
exam.sty
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{exam}[2021/12/13 v0.1 test]
\newif\ifprint
\printfalse
\DeclareOption{print}{%
\printtrue
}
\DeclareOption{showframe}{%
\RequirePackage{showframe}
}
\ProcessOptions
\IfFontExistsTF{Source Han Serif SC}{
\setCJKmainfont{Source Han Serif SC}
}{}
% \newfontfamily\cmu{CMU Serif}
% \RequirePackage{showframe}
% \ctexset{
% section/format = {\normalsize\raggedright\bfseries}
% }
\RequirePackage{fontawesome5} % 提供大拇指
\RequirePackage{tasks}
\NewTasksEnvironment[label={\faIcon{thumbs-up}}, item-indent=3.5em, label-offset=.5em]{THANKS}[*](4)
\xeCJKsetup{CheckSingle=true}
\RequirePackage{tcolorbox}
\tcbuselibrary{breakable}
\tcbuselibrary{skins}
\tcbset{
width = \linewidth,
fonttitle= \bfseries,
breakable,
enhanced jigsaw
% lines before break=0
}
\RequirePackage{mathtools}
\allowdisplaybreaks[4]
\RequirePackage{unicode-math}
\RequirePackage[mono=false]{libertinus-otf}
% \RequirePackage{fourier-otf}
% \setmainfont{TeX Gyre Pagella}
% \setmathfont{TeX Gyre Pagella Math}
% \setmathfont{NewCMMath-Book.otf}
\setmathfont{latinmodern-math.otf}[range={\lbrace, \rbrace}]
% \setmathfont{TeX Gyre Pagella Math}[range=bb]
\RequirePackage[margin=1.5cm]{geometry}
\RequirePackage[notrig]{physics}
\ExplSyntaxOn
\NewDocumentCommand \DV { } { \derivative }
% \let\dv\relax
% 定义 \dx ...
\clist_new:N \l_cf_diff_clist
\clist_set:Nn \l_cf_diff_clist { x, y, z, t, s, u, r, v }
\cs_set_eq:NN \DeclareDocumentCommand:Nnn \DeclareDocumentCommand
\cs_generate_variant:Nn \DeclareDocumentCommand:Nnn { cnn }
\clist_map_inline:Nn \l_cf_diff_clist
{
\DeclareDocumentCommand:cnn { d #1 } { s }
{
\IfBooleanTF { ##1 }
{ \dd #1 }
{ \dd{#1} }
}
}
\clist_new:N \l_cf_bb_clist
\clist_set:Nn \l_cf_bb_clist { N, Z, Q, J, R, C, K }
\clist_map_inline:Nn \l_cf_bb_clist
{
\DeclareDocumentCommand:cnn { #1 } { } { \symbb{#1} }
}
\ExplSyntaxOff
\RequirePackage{tabularray}
\UseTblrLibrary{amsmath}
\RequirePackage{nicematrix}
\RequirePackage{hyperref}
\ifprint%
\else%
\hypersetup{colorlinks=true, linkcolor=blue}
\fi
% https://tex.stackexchange.com/questions/307412/redefine-pi-to-pi-with-unicode-math
\let\set\qty
\let\emph\textbf
\AtBeginDocument{
\let\ge\geqslant
\let\le\leqslant
\let\hom\symscr
\let\umathpi\pi
\renewcommand\pi{\symup\umathpi}%
}
\def\grad{\symbf{\nabla}}
\let\boldsymbol\symbfit
\newcommand{\limit}[2]{\lim_{#1 \to #2}}
\newcommand{\me}{\symrm{e}}
\newcommand{\mi}{\symrm{i}}
% 可以用 D(){} 来做定界符
\NewDocumentCommand{\MM}{ O{\R} O{n} }{ \ensuremath{\symup{M}_{#2}(#1)} }
\DeclareMathOperator{\diag}{diag}
% \DeclareMathOperator{\deg}{deg}
\DeclareMathOperator{\Image}{Im}
\DeclareMathOperator{\Ker}{Ker}
\DeclareMathOperator{\sgn}{sgn}
% 修改 minipage 的脚注编号为 \arabic
\renewcommand{\thempfootnote}{\arabic{mpfootnote}}
\RequirePackage{amsthm}
\theoremstyle{definition}
\newtheorem*{remark}{注}
\newtheorem{lemma}{引理}
\let\proof\relax
\let\endproof\relax
\newtheorem*{proof}{证明}
% 打印提示和答案列表, 并创建超链接
\newcommand{\printcolor}{\ifprint \else \color{red} \fi}
% 添加红色加粗加星的 \item: \sitem
% 添加 \textbullet 加星的 \item: \hitem
% https://github.com/jbezos/enumitem/issues/33#issuecomment-993449063
\def\hitem{%
\letcs{\originallabel}{labeloriexercise\romannumeral\enit@depth}%
% the same as \@namedef
\csedef{labeloriexercise\romannumeral\enit@depth\expandafter}%
{\noexpand\textbf{\expandonce\textbullet\expandonce\originallabel}}%
\item
\cslet{labeloriexercise\romannumeral\enit@depth}\originallabel
}
\def\sitem{%
\letcs{\originallabel}{labeloriexercise\romannumeral\enit@depth}%
% the same as \@namedef
\csedef{labeloriexercise\romannumeral\enit@depth\expandafter}%
{\noexpand\bfseries\noexpand\printcolor{*\expandonce\originallabel}}%
\item
\cslet{labeloriexercise\romannumeral\enit@depth}\originallabel
}
\RequirePackage{verbatim}
% answerfile
\newwrite\ltxex@ansfile
% hintfile
\newwrite\ltxex@hintfile
\def\ltxex@ansfilename{\jobname.ans}
\def\ltxex@hintfilename{\jobname.hint}
% 遇到 \startexercise 时, 打开文件, 并向 .ans 与 .hint 中写入 answersheet 与 hintsheet 的环境头
\newcommand\startexercise{%
\immediate\openout\ltxex@ansfile=\ltxex@ansfilename
\immediate\write\ltxex@ansfile{\noexpand\begin{answersheet}}
\immediate\openout\ltxex@hintfile=\ltxex@hintfilename
\immediate\write\ltxex@hintfile{\noexpand\begin{hintsheet}}}
% 遇到 \stopexercise 时, 向 .ans 与 .hint 中写入 answersheet 与 hintsheet 的环境尾, 并关闭文件
\newcommand\stopexercise{%
\immediate\write\ltxex@ansfile{\noexpand\end{answersheet}}%
\immediate\closeout\ltxex@ansfile
\immediate\write\ltxex@hintfile{\noexpand\end{hintsheet}}%
\immediate\closeout\ltxex@hintfile}
% 从 .ans 与 .hint 中输出 answer 和 hint
\newcommand\printanswer{%
\InputIfFileExists{\ltxex@ansfilename}%
{\PackageInfo{latexexercise}{answer file `\ltxex@ansfilename' inputed.}}%
{\PackageWarning{latexexercise}%
{answer file `\ltxex@ansfilename' does not exsist.}}}
\newcommand\printhint{%
\InputIfFileExists{\ltxex@hintfilename}%
{\PackageInfo{latexexercise}{hint file `\ltxex@hintfilename' inputed.}}%
{\PackageWarning{latexexercise}%
{hint file `\ltxex@hintfilename' does not exsist.}}}
% 解决对 \item[\ref{}]\label{} 的引用问题
% https://tex.stackexchange.com/a/625985/180617
\NewDocumentCommand{\GetRef}{ m }{\protected@edef\@currentlabel{\getrefnumber{#1}}}%
% 在 answer 环境开始时, 向 .ans 文件中写入 \item[\ref{2:exer}]\label{2:answ}, hint 环境同理
\newenvironment{answer}%
{
\immediate\write\ltxex@ansfile{\noexpand\item[\noexpand\ref{\number\csname c@oriexercisei\endcsname:exer}.] \noexpand\GetRef{\number\csname c@oriexercisei\endcsname:answ}\noexpand\label{\number\csname c@oriexercisei\endcsname:answ}}%
\ltxex@startwriteans%
}%
{\ltxex@endwrite}
\newenvironment{hint}%
{
\immediate\write\ltxex@hintfile{\noexpand\item[\noexpand\ref{\number\csname c@oriexercisei\endcsname:exer}.] \noexpand\GetRef{\number\csname c@oriexercisei\endcsname:hint}\noexpand\label{\number\csname c@oriexercisei\endcsname:hint}}%
\ltxex@startwritehint%
}%
{\ltxex@endwrite}
% 定义 oriexercise, answersheet, hintsheet 以及方法 method
\RequirePackage[shortlabels, inline]{enumitem} % 继承并扩展了enumerate宏包的功能
\setlist[enumerate, 1]{leftmargin=*, label=(\roman*)}
% \setlist[enumerate, 2]{leftmargin=*, label=(\arabic*)}
\newlist{oriexercise}{enumerate}{2}
\setlist[oriexercise, 1]{leftmargin=*, label=\arabic*., widest=000, ref=\arabic*}
\setlist[oriexercise, 2]{leftmargin=*, label=(\arabic*)}
\newlist{answersheet}{enumerate}{2}
\setlist[answersheet, 1]{leftmargin=*, label=\arabic*., widest=000, ref=\arabic*}
\setlist[answersheet, 2]{leftmargin=*, label=(\arabic*)}
\newlist{hintsheet}{enumerate}{2}
\setlist[hintsheet, 1]{leftmargin=*, label=\arabic*., widest=000, ref=\arabic*}
\setlist[hintsheet, 2]{leftmargin=*, label=(\arabic*)}
\newlist{method}{enumerate}{1}
\setlist[method, 1]{leftmargin=0pt, labelindent = *, widest={方法二}, label=(\textbf{方法\chinese*})}
\RequirePackage{letltxmacro}
\LetLtxMacro{\it@m}{\item}
\def\asteriskitem{*}
% https://tex.stackexchange.com/a/328393/180617
\NewDocumentCommand{\new@item}{ o }{
\IfNoValueTF{#1}{\it@m}{\it@m[#1]\phantomsection\protected@edef\@currentlabel{#1}}}
\let\item\new@item
% 在 oriexercise 的基础上定义 exercise 环境, 使得可以输出 [提示][答案], 并带有超链接
\NewDocumentEnvironment{exercise}{ o }{
\RenewDocumentCommand{\item}{ s s o }{
\IfNoValueTF{##3}{\it@m}{\it@m[##3]}%
% 这里注意要判断一下是否在第一层
\ifnum\enit@depth=\@ne
\expandafter\label\expandafter{\number\csname c@oriexercisei\endcsname:exer}
\ifprint \else
\ifcsundef{r@\number\csname c@oriexercisei\endcsname:hint}{[暂无]}{
\hyperref[\number\csname c@oriexercisei\endcsname:hint]{[提示]}}%
\ifcsundef{r@\number\csname c@oriexercisei\endcsname:answ}{[暂无]}{
\hyperref[\number\csname c@oriexercisei\endcsname:answ]{[答案]}}
\fi
\fi
}
\IfValueTF{#1}{%
\begin{oriexercise}[#1]
}{
\begin{oriexercise}
}
}{\end{oriexercise}}
% 下面就是我看不懂的文件写入的控制了
\def\ltxex@startwriteans{%
\begingroup
\@bsphack
\let\do\@makeother \dospecials
\catcode`\^^M\active
\def\verbatim@processline{%
\immediate\write\ltxex@ansfile{\the\verbatim@line}}%
\verbatim@start}
\def\ltxex@startwritehint{%
\begingroup
\@bsphack
\let\do\@makeother \dospecials
\catcode`\^^M\active
\def\verbatim@processline{%
\immediate\write\ltxex@hintfile{\the\verbatim@line}}%
\verbatim@start}
\def\ltxex@endwrite{\@esphack\endgroup}