summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/dbshow/dbshow.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/dbshow/dbshow.dtx')
-rw-r--r--macros/latex/contrib/dbshow/dbshow.dtx3156
1 files changed, 2276 insertions, 880 deletions
diff --git a/macros/latex/contrib/dbshow/dbshow.dtx b/macros/latex/contrib/dbshow/dbshow.dtx
index a2af27d922..9731797f76 100644
--- a/macros/latex/contrib/dbshow/dbshow.dtx
+++ b/macros/latex/contrib/dbshow/dbshow.dtx
@@ -143,10 +143,10 @@ Copyright and License
\fi
%</internal>
%<package>\NeedsTeXFormat{LaTeX2e}
-%<+package|config>\GetIdInfo$Id: dbshow.dtx 461d9bb 2022-01-14 02:50:24 +0800 Changkai Li <lichangkai225@qq.com> $
+%<+package|config>\GetIdInfo$Id: dbshow.dtx 1a507c4 2022-01-17 22:53:24 +0800 Changkai Li <lichangkai225@qq.com> $
%<package> {Database to store and display data}
%<package>\ProvidesExplPackage{\ExplFileName}
-%<package|config> {\ExplFileDate}{1.4}{\ExplFileDescription}
+%<package|config> {\ExplFileDate}{1.5}{\ExplFileDescription}
%<*driver>
\documentclass[full]{l3doc}
\usepackage[scheme=plain, fontset=ubuntu]{ctex}
@@ -161,6 +161,9 @@ Copyright and License
\usepackage{xcolor}
\usepackage{tabularray}
\usepackage{zhnumber}
+\usepackage{tcolorbox}
+\tcbuselibrary{skins, minted, breakable, xparse}
+\usepackage{accsupp}
\geometry{
left=4.5cm,
@@ -197,8 +200,6 @@ Copyright and License
\addcontentsline{toc}{part}{Change~History}
}
-\let\subsubitem\subitem
-
\DoNotIndex{\begin, \end}
\setlength{\parskip}{\medskipamount}
@@ -217,6 +218,56 @@ Copyright and License
\par\textbf{\textsf{NOTE:~}}#1\par
} {}
+\definecolor {exambg} {RGB} {248, 241, 224} % 示例背景
+\definecolor {examno} {RGB} {176, 101, 90} % 示例行号
+\definecolor {examnobg} {RGB} {241, 225, 208} % 示例行号背景
+\definecolor {examframe} {RGB} {156, 129, 110} % 示例边框(标题背景)
+\definecolor {option} {HTML} {009933} % 选项
+\definecolor {cs} {HTML} {FF6600} % 命令
+\definecolor {env} {HTML} {C81531} % 环境
+\definecolor {link} {HTML} {33539E} % 链接
+
+% \definecolor {exambg} {RGB} {241, 225, 208} % 示例背景
+% \definecolor {examno} {HTML} {F3AA20} % 示例行号
+% \definecolor {examnobg} {HTML} {8B4C70} % 示例行号背景
+% \definecolor {examframe} {HTML} {58094F} % 示例边框(标题背景)
+% \definecolor {option} {HTML} {8B4C70} % 选项
+% \definecolor {cs} {HTML} {F3AA20} % 命令
+% \definecolor {cs} {HTML} {F9A911} % 命令
+% \definecolor {env} {HTML} {669933} % 环境
+\hypersetup{linkcolor=link}
+\tcbset{
+ exam-base/.style={
+ listing engine=minted, listing and text,
+ minted style=emacs, breakable,
+ minted options={fontsize=\small,breaklines,linenos,numbersep=3mm},
+ colback=exambg, colframe=examframe,
+ left=5mm, enhanced,
+ fonttitle=\small\sffamily\bfseries, fontlower=\small,
+ overlay={
+ \begin{tcbclipinterior}
+ \fill[examnobg]
+ (frame.south west) rectangle ([xshift=5mm]frame.north west);
+ \end{tcbclipinterior}
+ }
+ }
+}
+\DeclareTCBListing[auto counter]{example}{ O{} D(){} m }{%
+ exam-base, title={示例 \thetcbcounter:#3}, label={cn-#2}, #1
+}
+\DeclareTCBListing[auto counter]{example*}{ O{} D(){} m }{%
+ exam-base, title={Example \thetcbcounter: #3}, label={en-#2}, #1
+}
+\renewcommand{\theFancyVerbLine}{%
+ \ttfamily\textcolor{examno}{%
+ \scriptsize\oldstylenums{%
+ \protect\BeginAccSupp{ActualText={}}%
+ \arabic{FancyVerbLine}%
+ \protect\EndAccSupp{}%
+ }%
+ }%
+}
+
\ExplSyntaxOn
\makeatletter
@@ -274,7 +325,7 @@ Copyright and License
\int_compare:nNnT { \str_count:n {#1} } = { 3 } { \phantom{0} }
\c_space_tl
}
-\cs_set_eq:NN \dbshowdocver \dbshowdoc_print_version:n
+\cs_gset_eq:NN \dbshowdocver \dbshowdoc_print_version:n
% #1 ver #2 date #3 type #4 desc
\cs_new_protected:Nn \dbshowdoc_changes_what:nnnn {
@@ -336,13 +387,26 @@ Copyright and License
\end{itemize}
} {}
-\cs_new_protected:Nn \dbshowdoc_function_begin:N {
+\cs_gset_protected:Npn \__codedoc_typeset_function_block:nN #1#2 {
+ \__codedoc_function_index:x
+ { #1 \bool_if:NT #2 { \tl_to_str:n {TF} } }
+ \__codedoc_function_label:xN {#1} #2
+ \color{cs}\bfseries #1
+ \bool_if:NT #2 { \__codedoc_typeset_TF: }
+ \__codedoc_typeset_expandability:
+ \seq_if_empty:NF \g__codedoc_variants_seq
+ { \__codedoc_typeset_variant_list:nN {#1} #2 }
+ \\
+}
+\cs_new_protected:Nn \dbshowdoc_function_begin:Nn {
\cs_set_eq:NN \__codedoc_tmp_cs:nN \__codedoc_typeset_function_block:nN
\cs_set_protected:Npn \__codedoc_typeset_function_block:nN ##1##2 {
\__codedoc_function_label:xN {##1} ##2
\hbox_set:Nn \l_tmpa_box {##1}
- \int_compare:nTF { \str_count:n {##1} <= 22 }
+ \group_begin: \color{#2}\bfseries
+ \int_compare:nTF { \str_count:n {##1} <= 20 }
{##1} { \adjustbox{width=.7\marginparwidth, height=\box_ht:N \l_tmpa_box}{##1} }
+ \group_end:
#1{##1}
\__codedoc_typeset_expandability: \\
}
@@ -352,7 +416,7 @@ Copyright and License
}
\DeclareDocumentEnvironment { option } { O{} +v }
{
- \dbshowdoc_function_begin:N \SpecialOptionIndex
+ \dbshowdoc_function_begin:Nn \SpecialOptionIndex { option }
\__codedoc_function:nnw {#1} {#2}
}
{
@@ -361,7 +425,7 @@ Copyright and License
}
\DeclareDocumentEnvironment { environment } { O{} +v }
{
- \dbshowdoc_function_begin:N \SpecialEnvIndex
+ \dbshowdoc_function_begin:Nn \SpecialEnvIndex { env }
\__codedoc_function:nnw {#1} {#2}
}
{
@@ -369,8 +433,81 @@ Copyright and License
\dbshowdoc_function_end:
}
+\makeatletter
+\cs_gset_protected:Npn \__codedoc_cmd:nn #1#2
+ {
+ \bool_set_false:N \l__codedoc_cmd_noindex_bool
+ \bool_set_true:N \l__codedoc_cmd_replace_bool
+ \tl_set:Nn \l__codedoc_cmd_index_tl { \q_no_value }
+ \tl_set:Nn \l__codedoc_cmd_module_tl { \q_no_value }
+ \keys_set:nn { l3doc/cmd } {#1}
+ \tl_set:Nn \l__codedoc_cmd_tl {#2}
+ \bool_if:NT \l__codedoc_cmd_replace_bool
+ {
+ \tl_set_rescan:Nnn \l__codedoc_tmpb_tl { } { _ }
+ \tl_replace_all:Non \l__codedoc_cmd_tl \l__codedoc_tmpb_tl { _ }
+ \__codedoc_replace_at_at:N \l__codedoc_cmd_tl
+ \tl_replace_all:Nno \l__codedoc_cmd_tl { _ } \l__codedoc_tmpb_tl
+ }
+ \mode_if_math:T { \mbox }
+ {
+ \bool_if:NT \l__codedoc_allow_indexing_bool { \__codedoc_target: }
+ \verbatim@font
+ \__codedoc_if_almost_str:VT \l__codedoc_cmd_tl
+ {
+ \__kernel_tl_set:Nx \l__codedoc_cmd_tl { \tl_to_str:N \l__codedoc_cmd_tl }
+ \bool_if:NT \g__codedoc_cs_break_bool
+ {
+ \regex_replace_all:nnN
+ { ([^\\\_]\_*) \_ ([^\_]) }
+ { \1 \c{BreakableUnderscore} \2 }
+ \l__codedoc_cmd_tl
+ }
+ }
+ \tl_replace_all:Nnn \l__codedoc_cmd_tl { ~ } { \@xobeysp }
+ \textbf{\l__codedoc_cmd_tl}
+ \@
+ }
+ \bool_if:NT \l__codedoc_allow_indexing_bool
+ {
+ \bool_if:NF \l__codedoc_cmd_noindex_bool
+ {
+ \quark_if_no_value:NF \l__codedoc_cmd_index_tl
+ {
+ \__kernel_tl_set:Nx \l__codedoc_cmd_tl
+ { \c_backslash_str \exp_not:o { \l__codedoc_cmd_index_tl } }
+ }
+ \exp_args:No \__codedoc_key_get:n { \l__codedoc_cmd_tl }
+ \quark_if_no_value:NF \l__codedoc_cmd_module_tl
+ {
+ \__kernel_tl_set:Nx \l__codedoc_index_module_tl
+ { \tl_to_str:N \l__codedoc_cmd_module_tl }
+ }
+ \__codedoc_special_index_module:ooonN
+ { \l__codedoc_index_key_tl }
+ { \l__codedoc_index_macro_tl }
+ { \l__codedoc_index_module_tl }
+ { usage }
+ \l__codedoc_index_internal_bool
+ }
+ }
+ }
+\cs_generate_variant:Nn \__codedoc_cmd:nn { no }
+\makeatother
+
+% #1 color #2 opt #3 content
+\cs_new_protected:Nn \dbshowdoc_cmd:nnn {
+ \__codedoc_get_hyper_target:xN {#3} \l_tmpa_tl
+ \hyperref[\l_tmpa_tl]{\textcolor{#1}{\__codedoc_cmd:no {#2} {#3}}}
+}
\DeclareDocumentCommand \opt { O{} m }
- { \__codedoc_cmd:no {#1} {#2} }
+ { \dbshowdoc_cmd:nnn { option } {#1} {#2} }
+\DeclareDocumentCommand \nopt { O{} m }
+ { \textcolor{option}{\textbf{#2}} }
+\DeclareDocumentCommand \env { O{} m }
+ { \dbshowdoc_cmd:nnn { env } {#1} {#2} }
+\DeclareDocumentCommand \cs { O{} m }
+ { \dbshowdoc_cmd:nnn { cs } {#1} { \c_backslash_str #2 } }
\NewDocumentCommand \linktarget { m m m } {%
\hyperlink{#1}{#3}%
@@ -385,6 +522,19 @@ Copyright and License
{ \GetIdInfo $Id$ }
{ \fileinfo }
}
+
+\DeclareDocumentCommand \inidef { s d() s o } {
+ \group_begin:
+ \hfill\normalfont(
+ initially~
+ \IfBooleanTF {#1} {empty}
+ { \IfValueTF {#2} { \texttt{#2} } { unset } }
+ ,~
+ \IfBooleanTF {#3} {default empty}
+ { \IfValueTF {#4} { default~\texttt{#4} } { no~default } }
+ )
+ \group_end:
+}
\ExplSyntaxOff
\begin{document}
@@ -402,7 +552,7 @@ Copyright and License
%</driver>
% \fi
%
-% \CheckSum{882}
+% \CheckSum{0}
% \GetFileId{dbshow.sty}
%
% \ExplSyntaxOn
@@ -428,15 +578,11 @@ Copyright and License
% \begin{documentation}
%
% \section{引言}
+%
% 编写本宏包的动机来源于当前没有一个很好的错题本宏包,可以方便的根据各种条件对错
% 题进行筛选、排序,然后以自定义的样式展示出来。\pkg{dbshow} 宏包实现了四个核心
% 功能:数据存储和使用、数据筛选、数据排序、数据展示。
%
-% 数据只需要存储一次,就可以通过预定义的筛选、排序条件和样式展示部分或全部的数据。
-% 如上所述,本宏包其实实现了一个非常简单的数据库,复习错题的功能只是其中一个应用,
-% 和其他数据库宏包比如 \pkg{datatool} 相比,\pkg{dbshow} 更专注于非图表类型的数
-% 据展示。
-%
% \changes{1.4}{2022-01-10}{Add check}{version of \pkg{l3kernel}}
% \pkg{dbshow} 依赖版本日期至少为 |2022-11-07| 的 \pkg{l3kernel}。
%
@@ -473,19 +619,8 @@ Copyright and License
% 除了日期类型,所有类型都是 \pkg{expl3} 的内置类型。\pkg{dbshow} 构建了一个简单
% 的 |date| 类型,支持转换成整数以及带样式的打印。
%
-% \subsection{与 \pkg{datatool} 的区别}
-%
% \changes{1.2}{2022-01-07}{Add doc}{add comparison to \pkg{datatool}}
-%
-% 从核心功能上看,\pkg{dbshow} 和 \pkg{datatool} 实现了相同的功能。区别在于
-% \pkg{dbshow} 基于 \pkg{expl3} 实现,支持字符串的正则匹配,还支持多级排序。使用
-% 方式上更倾向于样式与内容分离,所有的样式都可以通过选项提前定义好并且可以复用。
-% \pkg{dbshow} 并没有实现从外部文件读取数据以及将数据持久化的功能,我认为这些应
-% 该是更专业的外部程序的工作而不应该在 \LaTeX 中设计这些功能。因此,\pkg{dbshow}
-% 只提供了一个运行时的临时数据库,足够轻便且满足大部分正常需求。如果你想删除或修
-% 改数据库中某一条记录,请去对应的位置删除或修改掉对应的 \env{dbitem} 环境,而不
-% 是让宏包提供一个输出某一行记录的命令。某种意义上记录数据库的 \TeX 源文件本身就
-% 是数据的一种持久化。
+% \changes{1.3}{2022-01-07}{Remove doc}{remove comparison to \pkg{datatool}}
%
% \section{接口文档}
%
@@ -531,18 +666,6 @@ Copyright and License
% 每个数据库都有一个默认的属性 |id| 用来存储数据的索引。
% \end{note}
%
-% 下面是定义一个错题数据库的示例,|question| 和 |answer| 属性用来存储问题和答
-% 案,|date| 属性存储日期,|info| 属性存储额外信息,|labels| 存储题目标签。
-% \begin{verbatim}
-% \dbNewDatabase{ques}{
-% question = tl,
-% answer = tl,
-% date = date,
-% info = tl,
-% labels = clist
-% }
-% \end{verbatim}
-%
% \begin{function}[added=2022-01-05]{\dbshow}
% \begin{syntax}
% \cs{dbshow} \marg{style} \marg{database}
@@ -561,7 +684,7 @@ Copyright and License
%
% \subsection{\cs{dbNewStyle} 和样式选项}
%
-% \begin{function}[added=2022-01-05]{\dbNewStyle}
+% \begin{function}[added=2022-01-05, updated=2022-01-15]{\dbNewStyle}
% \begin{syntax}
% \cs{dbNewStyle} \oarg{base styles} \marg{style} \marg{database} \marg{opts}
% \end{syntax}
@@ -574,222 +697,343 @@ Copyright and License
%
% \begin{option}[added=2022-01-05]{filter}
% \begin{syntax}
-% filter = <filter>
+% \opt{filter} = <filter> \inidef(-none-)
% \end{syntax}
%
-% 为当前样式设置由 \cs{dbCombineFilters} 所定义的过滤器
+% 为当前样式设置由 \cs{dbCombineFilters} 所定义的过滤器。示例 \ref{cn-filter}
+% 演示了如何定义条件,将条件组合成过滤器以及使用过滤器。
% \end{option}
%
+% \iffalse
+%<*verb>
+% \fi
+\DeleteShortVerb{\|}
+\begin{example}(filter){使用过滤器筛选数据}
+ \dbNewDatabase{filter-db}{name=str, count=int}
+ \begin{dbFilters}{filter-db}
+ \dbNewCond {cond1}{count}{\dbval > 3}
+ \dbNewCond*{cond2}{name} {\d+}
+ \dbCombCond{filter-and}{cond1 && cond2}
+ \dbCombCond{filter-or} {cond1 || cond2}
+ \end{dbFilters}
+ \dbitemkv{filter-db}{name=123, count=4}
+ \dbitemkv{filter-db}{name=ab3, count=2}
+ \dbitemkv{filter-db}{name=bag, count=5}
+ \dbNewStyle{filter-and-style}{filter-db}{
+ filter = filter-and,
+ before-code = \par Filter And\par,
+ item-code = {\dbuse{name}: \dbuse{count}\quad},
+ }
+ \dbNewStyle{filter-or-style}{filter-db}{
+ filter = filter-or,
+ before-code = \par Filter Or\par,
+ item-code = {\dbuse{name}: \dbuse{count}\quad},
+ }
+ \dbshow{filter-and-style}{filter-db}
+ \dbshow{filter-or-style} {filter-db}
+\end{example}
+\MakeShortVerb{\|}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.1}{2022-01-06}{Add option}{\opt{raw-filter}}
% \begin{option}[added=2022-01-06]{raw-filter}
% \begin{syntax}
-% raw-filter = <conditional expression>
+% \opt{raw-filter} = <conditional expression> \inidef
% \end{syntax}
%
% 使用条件表达式设置匿名过滤器,这里的条件指通过 \cs{dbNewConditional} 定义的
-% 条件。下面代码中两个示例的过滤器具有相同的功能。
+% 条件。示例 \ref{cn-raw-filter} 使用 \opt{raw-filter} 选项,直接组合筛选条
+% 件,达到与示例 \ref{cn-filter} 相同的效果。
% \end{option}
%
-% \changes{1.1}{2022-01-06}{Add option}{\opt{raw-filter}}
-%
-% \begin{verbatim}
-% % method 1
-% \begin{dbFilters}{db}
-% \dbNewConditional{cond1}{int-attr}{\rval > 1}
-% \dbNewConditional*{cond2}{str-attr}{\d+}
-% \end{dbFilters}
-% \dbNewStyle{style}{db}{raw-filter={cond1 && cond2}}
-% % method 2
-% \begin{dbFilters}{db}
-% \dbNewConditional{cond1}{int-attr}{\rval > 1}
-% \dbNewConditional*{cond2}{str-attr}{\d+}
-% \dbCombineFilters{filter}{cond1 && cond2}
-% \end{dbFilters}
-% \dbNewStyle{style}{db}{filter=filter}
-% \end{verbatim}
+% \DeleteShortVerb{\|}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(raw-filter){使用匿名过滤器筛选数据}
+ \dbNewDatabase{filter-db}{name=str, count=int}
+ \begin{dbFilters}{filter-db}
+ \dbNewCond {cond1}{count}{\dbval > 3}
+ \dbNewCond*{cond2}{name} {\d+}
+ \end{dbFilters}
+ \dbitemkv{filter-db}{name=123, count=4}
+ \dbitemkv{filter-db}{name=ab3, count=2}
+ \dbitemkv{filter-db}{name=bag, count=5}
+ \dbNewStyle{filter-and-style}{filter-db}{
+ raw-filter = {cond1 && cond2},
+ before-code = \par Filter And\par,
+ item-code = {\dbuse{name}: \dbuse{count}\quad},
+ }
+ \dbNewStyle{filter-or-style}{filter-db}{
+ raw-filter = {cond1 || cond2},
+ before-code = \par Filter Or\par,
+ item-code = {\dbuse{name}: \dbuse{count}\quad},
+ }
+ \dbshow{filter-and-style}{filter-db}
+ \dbshow{filter-or-style} {filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+% \MakeShortVerb{\|}
%
% \changes{1.2}{2022-01-08}{Fix bug}{string sorting bug}
% \begin{option}[added=2022-01-05]{sort}
% \begin{syntax}
-% sort = \{ <attr spec1>, <attr spec2>, \ldots{} \}
+% \opt{sort} = \{ <attr spec1>, <attr spec2>, \ldots{} \} \inidef
% \end{syntax}
%
-% 为当前样式设置排序规则。支持根据 |str|,|date|,|int|,|fp| 类型的数据进行排
-% 序,支持多级排序。\meta{attr} 表示增序,\meta{attr}* 表示降序。下面例子中,
-% 使用 |sort-style| 展示数据时的顺序为先按 |level| 降序,|level| 相同的再按出
-% 生日期 |birth| 增序,以此类推。
+% 为当前样式设置排序规则。支持对 |str|,|date|,|int|,|fp| 类型的数据进行排
+% 序,支持多级排序。\meta{attr} 表示增序,\meta{attr}\texttt{*} 表示降序。示
+% 例 \ref{cn-sort} 的排序规则为先按 |count| 降序排序,|count| 相同的再按
+% |name| 增序排序。
% \end{option}
%
-% \begin{verbatim}
-% \dbNewDatabase{sort-example}{
-% name = str,
-% birth = date,
-% level = int,
-% weight = fp,
-% }
-% \dbNewStyle{sort-style}{sort-example}{
-% sort = { level*, birth, name, weight }
-% }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(sort){多级排序}
+ \dbNewDatabase{sort-db}{name=str, count=int}
+ \dbNewStyle{sort-style}{sort-db}{
+ sort = {count*, name},
+ item-code = {\dbuse{name}: \dbuse{count}\quad}
+ }
+ \dbitemkv{sort-db}{name=bag, count=1}
+ \dbitemkv{sort-db}{name=box, count=1}
+ \dbitemkv{sort-db}{name=tag, count=2}
+ \dbitemkv{sort-db}{name=pen, count=3}
+ \dbshow{sort-style}{sort-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
%
-% \begin{option}[added=2022-01-05, rEXP]{item-code}
+% \begin{option}[added=2022-01-05, rEXP]{before-code}
% \begin{syntax}
-% item-code = <code>
+% \opt{before-code} = <before code> \inidef*
% \end{syntax}
%
-% 该选项用来设置展示数据库中每条记录的代码。你可以使用 \cs{dbuse} 来展示属性的
-% 值。
+% 该选项用来设置在展示整个数据库之\zhbefore 需要执行的代码(见示例
+% \ref{cn-db-wrap})。
% \end{option}
%
-% \changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
-% \begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+% \begin{option}[added=2022-01-05, rEXP]{after-code}
% \begin{syntax}
-% <attr>/sep = <separator> \\
-% <attr>/sep = \{ \\
-% ~~\meta{separator between two}, \\
-% ~~\meta{separator between more than two}, \\
-% ~~\meta{separator between final two} \\
-% \} \\
-% <attr>/sep = \{ \\
-% ~~\meta{separator before year}, \\
-% ~~\meta{separator between year and month}, \\
-% ~~\meta{separator between month and day}, \\
-% ~~\meta{separator after day} \\
-% \} \\
+% \opt{after-code} = <after code> \inidef*
% \end{syntax}
%
-% 该选项只适用于类型为 |clist| 或 |date| 的属性,用来设置列表间元素的间隔。参
-% 数为一个 \meta{separator} 时,所有元素间的分隔符被设置为 \meta{separator}。
-% \meta{separator before year} 和 \meta{separator after day} 被设置为空。
+% 该选项用来设置在展示整个数据库之\zhafter 需要执行的代码(见示例
+% \ref{cn-db-wrap})。
% \end{option}
%
-% 参数为3个元素的逗号分隔的列表时,此选项用来设置列表元素的分隔符,分别用来设
-% 置只有两个元素时的分隔符 \meta{separator between two},超过两个元素时的分隔
-% 符 \meta{separator between more than two},和最后两个元素之间的分隔符
-% \meta{separator between final two}。对于类型为 |clist| 的属性,设置此选项时
-% 如果参数列表数量不是1或者3会触发报错。
-%
-% \begin{verbatim}
-% % clist-attr is an attribute of database db
-% % suppose the val of clist-attr is { 1, 2, 3 }
-% \dbNewStyle{clist-sep}{db}{
-% clist-attr/sep = { ,~ }, % print 1, 2, 3
-% clist-attr/sep = { {,~}, {,~}, {and~} } % print 1, 2 and 3
-% }
-% \end{verbatim}
-%
-% 参数为4个元素的逗号分隔的列表时,此选项用来设置日期的分隔符,分别用来设
-% 置 \meta{year} 之前的分隔符 \meta{separator before year} ,\meta{year} 和
-% \meta{month} 之间的分隔符 \meta{separator between year and month} ,
-% \meta{month} 和 \meta{day} 之间的分隔符,以及 \meta{day} 之后的分隔符。对于
-% 类型为 |date| 的属性,设置此选项时如果参数列表数量不是1或者4会触发报错。
-%
-% \begin{verbatim}
-% % date-attr is an attribute of database db
-% % suppose the val of date-attr is 2022/01/01
-% \dbNewStyle{date-sep}{db}{
-% date-attr/sep = -, % print 2022-01-01
-% date-attr/sep = { |, -, -, | } % print |2022-01-01|
-% }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(db-wrap){设置展示数据库前后的代码}
+ \dbNewDatabase{wrap-db}{text=tl}
+ \dbNewStyle{wrap-style}{wrap-db}{
+ before-code = \textit{before code}\quad,
+ after-code = \textit{after code},
+ item-code = \dbarabic.~\dbuse{text}\quad
+ }
+ \dbitemkv{wrap-db}{text=text1}
+ \dbitemkv{wrap-db}{text=text2}
+ \dbitemkv{wrap-db}{text=text3}
+ \dbshow{wrap-style}{wrap-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
%
-% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
-% \begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+% \begin{option}[added=2022-01-05, rEXP]{item-code}
% \begin{syntax}
-% <attr>/zfill = <\TTF>
+% \opt{item-code} = <item code> \inidef
% \end{syntax}
%
-% 该选项只适用于类型为 |date| 的属性。控制输出月份和天时是否补零。
+% 该选项用来设置展示数据库中每条记录的代码。你可以使用 \cs{dbuse}\marg{attr}
+% 来指代属性 \meta{attr} 的值。示例 \ref{cn-item-code} 演示了如何展示一个首
+% 字母缩写词表。
% \end{option}
%
-% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbdatesep}}
-% \begin{function}[added=2022-01-13, EXP]{\dbdatesep}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(item-code){展示数据库条目}
+ \dbNewDatabase{item-db}{acronym=str, desc=tl}
+ \dbNewStyle{item-style}{item-db}{
+ before-code = {\dbIfEmptyF{\begin{description}}},
+ after-code = {\dbIfEmptyF{\end{description}}},
+ item-code = {\item[\dbuse{acronym}] \dbuse{desc}},
+ sort = acronym,
+ }
+ \dbitemkv{item-db}{acronym=PM, desc={Prime Minister}}
+ \dbitemkv{item-db}{acronym=CBD, desc={Central Business District}}
+ \dbitemkv{item-db}{acronym=DL, desc={Deep Learning}}
+ \dbshow{item-style}{item-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-17}{Add option}{\opt{item-code*}}
+% \begin{option}[added=2022-01-17, rEXP]{item-code*}
% \begin{syntax}
-% \cs{dbdatesep} \marg{separator}
+% \opt{item-code*} = <item code> \inidef
% \end{syntax}
%
-% 设置内部解析日期时的间隔符,默认为 |/|,即存储数据的格式为 |yyyy/mm/dd|。
-% \end{function}
+% 使用该选项设置的代码在被插入到最终执行代码序列之前会先通过
+% \cs{protected@edef} 完全展开。示例 \ref{cn-item-exp} 展示了如何通过该选项
+% 使用表格来展示数据。
+% \end{option}
%
-% \subsubsection{装饰器}
-%
-% 下面这些选项在不同层次上装饰原有的展示代码,有些其实不必通过选项的形式来装饰,
-% 但这样做的好处是可以进一步使样式与内容分离。下面的例子中,\meta{style1} 和
-% \meta{style2} 是相同的样式,都用 * 将 \meta{attr1} 包裹住了,但是如果你还想定
-% 义一个样式用 = 将 \meta{attr1} 包裹住,如果用 \meta{style1} 的方式,那就可能
-% 需要重复大片代码,用 \meta{style2} 的方式则可以很轻松的继承 \meta{style1} 中的
-% 代码。
-%
-% \begin{verbatim}
-% \dbNewStyle{style1}{db}{
-% item-code = {%
-% *\rvuse{attr1}*\rvuse{attr2}
-% % more code
-% }
-% }
-% \dbNewStyle{base-style}{db}{
-% item-code = {%
-% \rvuse{attr1}\rvuse{attr2}
-% % more code
-% }
-% }
-% \dbNewStyle[base-style]{style2}{db}{
-% attr1/before-code = { * },
-% attr1/after-code = { * },
-% }
-% \dbNewStyle[base-style]{style3}{db}{
-% attr1/before-code = { = },
-% attr1/after-code = { = },
-% }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example}(item-exp){用表格展示数据}
+ \dbNewDatabase{tab-db}{name=str, count=int}
+ \dbNewStyle{tab-style}{tab-db}{
+ before-code = {%
+ \begin{tabular}{ll}
+ name & count \\
+ },
+ after-code = \end{tabular},
+ item-code* = {%
+ \textcolor{red}{\dbuse{name}} & \dbuse{count} \\
+ },
+ }
+ \dbitemkv{tab-db}{name=bag, count=100}
+ \dbitemkv{tab-db}{name=pig, count=20}
+ \dbshow{tab-style}{tab-db}
+\end{example}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
%
-% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/wrapper}}
-% \begin{option}[added=2022-01-08, rEXP]{<attr>/wrapper}
+% \changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
+% \opt{record-after-code}}
+% \changes{1.5}{2022-01-14}{Update options}{Rename \opt{record-before-code}
+% and \opt{record-after-code} to \opt{item-before-code} and
+% \opt{item-after-code}}
+% \begin{option}[added=2022-01-08, updated=2022-01-14, rEXP]{item-before-code}
% \begin{syntax}
-% <attr>/wrapper = <control sequence>
+% \opt{item-before-code} = <before code> \inidef*
% \end{syntax}
%
-% 该选项只适用于类型为 |date| 的属性。\meta{control sequence} 只接收一个参数即
-% 日期,如果设置了此选项,则最后输出的日期为
-% \meta{control sequence}\marg{date}。
+% 在 \meta{item code} 之\zhbefore 执行的代码(见示例 \ref{cn-item-wrapper})。
% \end{option}
%
-% \begin{option}[added=2022-01-05, rEXP]{before-code}
+% \begin{option}[added=2022-01-08, updated=2022-01-14, rEXP]{item-after-code}
% \begin{syntax}
-% before-code = <code>
+% \opt{item-after-code} = <after code> \inidef*
% \end{syntax}
%
-% 该选项用来设置在展示整个数据库之\zhbefore 需要执行的代码。
+% 在 \meta{item code} 之\zhafter 执行的代码(见示例 \ref{cn-item-wrapper})。
% \end{option}
%
-% \begin{option}[added=2022-01-05, rEXP]{after-code}
-% \begin{syntax}
-% after-code = <code>
-% \end{syntax}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(item-wrapper){设置展示条目之前和之后的代码}
+ \dbNewDatabase{item-wrap-db}{text=tl, hint=tl}
+ \dbNewStyle{item-wrap-style}{item-wrap-db}{
+ item-before-code = \begingroup\ttfamily<,
+ item-after-code = >\endgroup,
+ item-code = \dbuse{text}~(\dbuse{hint}),
+ }
+ \dbitemkv{item-wrap-db}{text=example, hint={this is an example}}
+ \dbshow{item-wrap-style}{item-wrap-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
%
-% 该选项用来设置在展示整个数据库之\zhafter 需要执行的代码。
-% \end{option}
+% \subsubsection{属性选项}
%
-% \changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
-% \opt{record-after-code}}
-% \begin{option}[added=2022-01-05, rEXP]{record-before-code}
+% \changes{1.5}{2022-01-14}{Remove option}{\opt{<attr>/wrapper}}
+%
+% \changes{1.5}{2022-01-14}{Add options}{\opt{<attr>/code},
+% \opt{<attr>/code*}}
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/code}
% \begin{syntax}
-% record-before-code = <code>
+% \nopt{<attr>/code} = <code> \inidef(\#1)
% \end{syntax}
%
-% 该选项用来设置在展示当前记录之\zhbefore 需要执行的代码。
+% 设置 \meta{attr} 的样式代码。在 \meta{code} 中用 |#1| 指代属性的值。示例
+% \ref{cn-attr-code} 将数量超过10个的物品打印为红色,少于10个的则打印为青色。
% \end{option}
%
-% \begin{option}[added=2022-01-05, rEXP]{record-after-code}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(attr-code){设置单个属性样式}
+ \dbNewDatabase{attr-code-db}{name=str, count=int}
+ \begin{dbFilters}{attr-code-db}
+ \dbNewCond{large}{count}{\dbval >= 10}
+ \end{dbFilters}
+ \dbNewStyle{base-style}{attr-code-db}{
+ item-code = \dbuse{name}:~\dbuse{count}\quad,
+ }
+ \dbNewStyle[base-style]{large-style}{attr-code-db}{
+ raw-filter = large,
+ name/code = \textcolor{red}{#1},
+ }
+ \dbNewStyle[base-style]{small-style}{attr-code-db}{
+ raw-filter = !large,
+ name/code = \textcolor{teal}{#1},
+ }
+ \dbitemkv{attr-code-db}{name=bag, count=1}
+ \dbitemkv{attr-code-db}{name=pen, count=12}
+ \dbitemkv{attr-code-db}{name=pig, count=5}
+ \dbitemkv{attr-code-db}{name=egg, count=50}
+ \dbshow{large-style}{attr-code-db}
+ \dbshow{small-style}{attr-code-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/code*}
% \begin{syntax}
-% record-after-code = <code>
+% \nopt{<attr>/code*} = <code> \inidef
% \end{syntax}
%
-% 该选项用来设置在展示当前记录之\zhafter 需要执行的代码。
+% 设置 \meta{attr} 的样式代码。在 \meta{code} 中用 |#1| 指代\textbf{展开}的
+% 属性的值。这对某些需要以特定格式解析参数的命令比较有用。
% \end{option}
%
+% 示例 \ref{cn-exp-code} 中 \pkg{zhnumber} 宏包的 \cs{zhdate} 命令接收
+% |yyyy/mm/dd| 格式的时期并输出中文日期,本宏包默认的日期输出格式是
+% |yyyy/mm/dd|,因此可以通过 \opt{date/code*} 选项,将日期完全展开后然后传递
+% 给 \cs{zhdate} 命令,如果不展开,\cs{zhdate} 接收到的是若干个用来展示日期
+% 的控制序列,而不是 |yyyy/mm/dd| 格式的时期,进而触发报错。
+%
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example}(exp-code){中文日期}
+ % \usepackage{zhnumber}
+ \dbNewDatabase{exp-db}{date=date, event=tl}
+ \dbNewStyle{exp-style}{exp-db}{
+ item-code = \par\makebox[4cm][l]{\dbuse{date}}\dbuse{event},
+ date/code* = \zhdate{#1},
+ }
+ \dbitemkv{exp-db}{date=2020/12/31, event=eat}
+ \dbitemkv{exp-db}{date=2021/01/01, event=sleep}
+ \dbshow{exp-style}{exp-db}
+\end{example}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
+%
% \begin{option}[added=2022-01-05, rEXP]{<attr>/before-code}
% \begin{syntax}
-% <attr>/before-code = <code>
+% \nopt{<attr>/before-code} = <before code> \inidef*
% \end{syntax}
%
% 该选项用来设置展示数据库中属性 \meta{attr} 对应数据之\zhbefore 需要执行的代
@@ -798,16 +1042,60 @@ Copyright and License
%
% \begin{option}[added=2022-01-05, rEXP]{<attr>/after-code}
% \begin{syntax}
-% <attr>/after-code = <code>
+% \nopt{<attr>/after-code} = <after code> \inidef*
% \end{syntax}
%
% 该选项用来设置展示数据库中属性 \meta{attr} 对应数据之\zhafter 需要执行的代码。
% \cs{dbuse} 会在展示属性数据\zhafter 执行此代码。
% \end{option}
%
+% 属性样式代码的执行顺序为:
+% \begin{enumerate}[nolistsep]
+% \item \opt{<attr>/before-code}
+% \item \opt{<attr>/code} or \opt{<attr>/code*}
+% \item \opt{<attr>/after-code}
+% \end{enumerate}
+%
+% \changes{1.5}{2022-01-16}{Add options}{\opt{<attr>/item-code},
+% \opt{<attr>/item-code*}}
+% \begin{option}[added=2022-01-16, rEXP]{<attr>/item-code}
+% \begin{syntax}
+% \nopt{<attr>/item-code} = <item code> \inidef(\#1)
+% \end{syntax}
+%
+% 设置列表元素的样式代码。在 \meta{item code} 中用 |#1| 指代列表元素的值。示例
+% \ref{cn-clist-code} 演示了如何为列表元素设置额外的样式。
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(clist-code){设置列表元素样式代码}
+ \dbNewDatabase{clist-db}{name=str, label=clist}
+ \dbNewStyle{clist-style}{clist-db}{
+ item-code = \par\dbuse{name}:~\dbuse{label},
+ label/item-code = (\textcolor{red}{\textit{#1}}),
+ }
+ \dbitemkv{clist-db}{name=pig, label={animal, meat}}
+ \dbitemkv{clist-db}{name=Alex, label={person, male}}
+ \dbshow{clist-style}{clist-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \begin{option}[added=2022-01-16, rEXP]{<attr>/item-code*}
+% \begin{syntax}
+% \nopt{<attr>/item-code*} = <item code> \inidef
+% \end{syntax}
+%
+% 设置列表元素的样式代码。在 \meta{item code} 中用 |#1| 指代\textbf{展开}的列
+% 表元素的值。
+% \end{option}
+%
% \begin{option}[added=2022-01-05, rEXP]{<attr>/item-before-code}
% \begin{syntax}
-% <attr>/item-before-code = <code>
+% \nopt{<attr>/item-before-code} = <code> \inidef*
% \end{syntax}
%
% 该选项只适用于类型为 |clist| 的属性,用来设置展示列表每个元素\zhbefore 需要
@@ -816,65 +1104,291 @@ Copyright and License
%
% \begin{option}[added=2022-01-05, rEXP]{<attr>/item-after-code}
% \begin{syntax}
-% <attr>/item-after-code = <code>
+% \nopt{<attr>/item-after-code} = <code> \inidef*
% \end{syntax}
%
% 该选项只适用于类型为 |clist| 的属性,用来设置展示列表每个元素\zhafter 需要执
% 行的代码。
% \end{option}
%
-% \subsection{使用 \cs{dbNewReviewPoints} 定义复习点}
+% 列表元素样式代码的执行顺序为:
+% \begin{enumerate}[nolistsep]
+% \item \opt{<attr>/item-before-code}
+% \item \opt{<attr>/item-code} or \opt{<attr>/item-code*}
+% \item \opt{<attr>/item-after-code}
+% \end{enumerate}
+%
+% \def\sepini{%
+% \begingroup\normalfont%
+% \hfill%
+% (initially \texttt{\{,\char`~\}} for \texttt{clist}%
+% and \texttt{/} for \texttt{date}, no default)%
+% \endgroup%
+% }
+% \changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
+% \begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+% \begin{syntax}
+% \nopt{<attr>/sep} = <separator> \sepini\\
+% \nopt{<attr>/sep} = \{ \\
+% ~~\meta{separator between two}, \\
+% ~~\meta{separator between more than two}, \\
+% ~~\meta{separator between final two} \\
+% \} \\
+% \nopt{<attr>/sep} = \{ \\
+% ~~\meta{separator before year}, \\
+% ~~\meta{separator between year and month}, \\
+% ~~\meta{separator between month and day}, \\
+% ~~\meta{separator after day} \\
+% \} \\
+% \end{syntax}
+%
+% 该选项只适用于类型为 |clist| 或 |date| 的属性,用来设置列表间元素的间隔。参
+% 数为一个 \meta{separator} 时,所有元素间的分隔符被设置为 \meta{separator}。
+% \meta{separator before year} 和 \meta{separator after day} 被设置为空。
+% \end{option}
+%
+% 参数为3个元素的逗号分隔的列表时,此选项用来设置列表元素的分隔符,分别用来设
+% 置只有两个元素时的分隔符 \meta{separator between two},超过两个元素时的分隔
+% 符 \meta{separator between more than two},和最后两个元素之间的分隔符
+% \meta{separator between final two}。对于类型为 |clist| 的属性,设置此选项时
+% 如果参数列表数量不是1或者3会触发报错。示例 \ref{cn-clist-sep} 展示了如何设
+% 置列表元素间隔。
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(clist-sep){设置列表元素间隔}
+ \dbNewDatabase{clist-db}{label=clist}
+ \dbNewStyle{clist-base}{clist-db}{
+ before-code = {\dbIfEmptyF{\begin{enumerate}}},
+ after-code = {\dbIfEmptyF{\end{enumerate}}},
+ item-code = \item \dbuse{label},
+ }
+ \dbNewStyle[clist-base]{clist-style1}{clist-db}{
+ label/sep = {{,~}}
+ }
+ \dbNewStyle[clist-base]{clist-style2}{clist-db}{
+ label/sep = {{,~}, {,~}, ~and~}
+ }
+ \dbitemkv{clist-db}{label={a, b, c}}
+ \dbitemkv{clist-db}{label={1, 2, 3}}
+ \dbshow{clist-style1}{clist-db}
+ \dbshow{clist-style2}{clist-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% 参数为4个元素的逗号分隔的列表时,此选项用来设置日期的分隔符,分别用来设
+% 置 \meta{year} 之前的分隔符 \meta{separator before year} ,\meta{year} 和
+% \meta{month} 之间的分隔符 \meta{separator between year and month} ,
+% \meta{month} 和 \meta{day} 之间的分隔符,以及 \meta{day} 之后的分隔符。对于
+% 类型为 |date| 的属性,设置此选项时如果参数列表数量不是1或者4会触发报错。示例
+% \ref{cn-date-sep} 展示了如何自定义日期间隔符。
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(date-sep){设置日期间隔符}
+ \dbNewDatabase{date-db}{date=date}
+ \dbNewStyle{date-style1}{date-db}{
+ item-code = \dbuse{date}\quad,
+ date/sep = -,
+ }
+ \dbNewStyle{date-style2}{date-db}{
+ item-code = \dbuse{date}\quad,
+ date/sep = {\$, +, !, \$},
+ }
+ \dbitemkv{date-db}{date=2020/01/02}
+ \dbitemkv{date-db}{date=2022/07/12}
+ \dbshow{date-style1}{date-db}
+ \dbshow{date-style2}{date-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-14}{Add option}{\opt{<attr>/format-code}}
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/format-code}
+% \begin{syntax}
+% \nopt{<attr>/format-code} = <format code> \inidef
+% \end{syntax}
+%
+% 该选项用来更精细地控制日期的输出格式。在 \meta{format code}中,|#1| 代表年份,
+% |#2| 代表月份,|#3| 代表天。示例 \ref{cn-date-code} 演示了如何使用该选项。
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(date-code){任意日期格式}
+ \dbNewDatabase{date-db}{date=date}
+ \dbNewStyle{date-style}{date-db}{
+ item-code = \dbuse{date},
+ date/format-code = {日:#3\quad 月:#2\quad 年:#1}
+ }
+ \dbitemkv{date-db}{date=2022/01/01}
+ \dbshow{date-style}{date-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
+% \begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+% \begin{syntax}
+% \nopt{<attr>/zfill} = <\TTF> \inidef(true)[true]
+% \end{syntax}
+%
+% 该选项只适用于类型为 |date| 的属性。控制输出月份和天时是否补零。示例
+% \ref{cn-date-zfill} 展示了补零和不补零的日期。
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(date-zfill){月份和天补零}
+ \dbNewDatabase{date-db}{date=date}
+ \dbNewStyle {zfill-style}{date-db}{
+ item-code = \dbuse{date},
+ }
+ \dbNewStyle{nofill-style}{date-db}{
+ item-code = \dbuse{date},
+ date/zfill = false,
+ }
+ \dbitemkv{date-db}{date=2022/01/01}
+ \dbshow {zfill-style}{date-db}
+ \dbshow{nofill-style}{date-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbdatesep}}
+% \begin{function}[added=2022-01-13]{\dbdatesep}
+% \begin{syntax}
+% \cs{dbdatesep} \marg{separator}
+% \end{syntax}
+%
+% 设置内部解析日期时的分隔符,默认为 |/|,即存储数据的格式为 |yyyy/mm/dd|。
+% 示例 \ref{cn-inner-date-sep} 演示了使用两种格式存储数据,但实际上分隔符并
+% 没有被存储,而是被内部用来解析年、月和日然后存储为三个整数。
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(inner-date-sep){设置日期解析格式}
+ \dbNewDatabase{inner-date-db}{date=date}
+ \dbNewStyle{inner-date-style}{inner-date-db}{
+ item-code = \dbuse{date}\quad,
+ }
+ \dbitemkv{inner-date-db}{date=2020/01/20}
+ \dbdatesep{-}
+ \dbitemkv{inner-date-db}{date=2022-01-10}
+ \dbshow{inner-date-style}{inner-date-db}
+\end{example}
+\dbdatesep{/}
+% \iffalse
+%</verb>
+% \fi
+% \subsection{过滤器}
+%
+% 过滤器是一些条件的组合,只有满足过滤器指定条件的数据才会被展现出来。
%
% \begin{function}[added=2022-01-05]{\dbNewReviewPoints}
% \begin{syntax}
% \cs{dbNewReviewPoints} \marg{name} \marg{points}
% \end{syntax}
%
-% 定义名为 \meta{name} 的复习点。这是专门为错题本或复习所定制的功能,
-% \meta{points}是一系列整数,现在假设每道错题你都将写错时的日期记录在了 |date|
-% 属性中,并且你希望每隔2,5,15天复习一次。下面的代码给出了一个实现示例。
+% 定义名为 \meta{name} 的复习间隔列表。\meta{points} 是一系列整数或整数表达
+% 式,用于设置日期的过滤器。示例 \ref{cn-review-points} 中,预定义了一个复习
+% 间隔列表 |review| 和一个时间锚点 |2022/02/06|,筛选时,将当前条目的日期与
+% 描点相比较,计算得到时间间隔 $\meta{interval} = \meta{date anchor} -
+% \meta{date cmp}$,只有当 \meta{interval} 的值在 \meta{points} 中时,条件才
+% 成立。
% \end{function}
%
-% \begin{verbatim}
-% \dbNewReviewPoints{review-point}{2, 5, 15} % 定义复习点
-% \begin{dbFilters}
-% \dbNewConditional{cond1}{date}{review-point|\Today} % 定义复习条件
-% \dbCombineConditionals{filter1}{cond1} % 定义过滤器
-% \end{dbFilters}
-% \dbNewStyle{review-style}{ques}{filter=filter1} % 定义展示样式
-% \end{verbatim}
-%
-% \subsection{在 \env{dbFilters} 环境中定义过滤器}
+% \iffalse
+%<*verb>
+% \fi
+\DeleteShortVerb{\|}
+\begin{example}(review-points){按时间间隔筛选}
+ \dbNewDatabase{filter-db}{date=date}
+ \dbNewReviewPoints{review}{2, 5}
+ \dbNewRawFilter*{review-filter}{filter-db}{date}{review|2022/02/06}
+ \dbNewStyle{filter-style}{filter-db}{
+ item-code = \dbuse{date}\quad,
+ filter = review-filter,
+ }
+ \dbitemkv{filter-db}{date=2022/01/30}
+ \dbitemkv{filter-db}{date=2022/02/01}
+ \dbitemkv{filter-db}{date=2022/02/04}
+ \dbshow{filter-style}{filter-db}
+\end{example}
+\MakeShortVerb{\|}
+% \iffalse
+%</verb>
+% \fi
%
-% \begin{environment}[added=2022-01-05]{dbFilters}
+% \changes{1.5}{2022-01-16}{Update env}{add starred version of \env{dbFilters}}
+% \begin{environment}[added=2022-01-05, updated=2022-01-16]{dbFilters}
% \begin{syntax}
-% |\begin{dbFilters}|\marg{database} \\
+% |\begin|\{\env{dbFilters}\} \marg{database} \\
+% ~~\meta{code}
+% |\end|\{\env{dbFilters}\} \\
+% |\begin|\{\env{dbFilters}\} * \marg{database} \\
% ~~\meta{code}
-% |\end{dbFilters}| \\
+% |\end|\{\env{dbFilters}\} \\
% \end{syntax}
%
% \env{dbFilters}用来定义过滤器,此环境中定义了 \cs{dbNewConditional} 命令用来
-% 定义条件和 \cs{dbCombineConditionals} 命令用来组合条件定义过滤器。过滤器独立
-% 于每个 \meta{database},这意味着你可以在不同数据库中定义名称相同的过滤条件和
-% 过滤器。
+% 定义条件和 \cs{dbCombineConditionals} 命令用来组合条件定义过滤器。星号版本在
+% 定义条件的同时会定义一个与条件同名且只使用这个条件的过滤器。示例
+% \ref{cn-star-filter} 中定义 |greater| 条件的同时也定义了一个同名的过滤器,你
+% 可以直接在 \opt{filter} 中使用这个过滤器。过滤器独立于每个 \meta{database},
+% 这意味着你可以在不同数据库中定义名称相同的过滤条件和过滤器。
% \end{environment}
%
-% \begin{function}[added=2022-01-05, updated=2022-01-08]{\dbNewConditional, \dbNewConditional*}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(star-filter){定义与条件同名的过滤器}
+ \dbNewDatabase{filter-db}{count=int}
+ \begin{dbFilters}*{filter-db}
+ \dbNewCond{greater}{count}{\dbval > 3}
+ \end{dbFilters}
+ \dbNewStyle{filter-style}{filter-db}{
+ filter = greater,
+ item-code = \dbuse{count}\quad,
+ }
+ \dbitemkv{filter-db}{count=2}
+ \dbitemkv{filter-db}{count=5}
+ \dbshow{filter-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-15}{Add macros}{\cs{dbNewCond}, \cs{dbCombCond}}
+% \begin{function}[added=2022-01-05, updated=2022-01-16]{\dbNewConditional,
+% \dbNewCond, \dbNewConditional*, \dbNewCond*}
% \begin{syntax}
-% \cs{dbNewConditional} \marg{name} \marg{attr} \marg{cond spec} \\
-% \cs{dbNewConditional}* \marg{name} \marg{attr} \marg{cond spec} \\[2pt]
-% \cs{dbNewConditional} \marg{name} \marg{int/fp attr} \marg{expr} \\
-% \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr} \\
-% \cs{dbNewConditional} \marg{name} \marg{str/tl attr} \marg{regex expr} \\
-% \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \\
-% \cs{dbNewConditional} \marg{name} \marg{clist attr} \marg{val list} \\
-% \cs{dbNewConditional}* \marg{name} \marg{clist attr} \marg{val list} \\
-% \cs{dbNewConditional} \marg{name} \marg{date attr} \marg{expr}
-% \cs{dbNewConditional}* \marg{name} \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \\
+% \cs{dbNewConditional} \marg{name} \marg{attr} \marg{cond spec} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{attr} \marg{cond spec} \oarg{filter info} \\[2pt]
+% \cs{dbNewConditional} \marg{name} \marg{int/fp attr} \marg{expr} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr} \oarg{filter info}
+% \cs{dbNewConditional} \marg{name} \marg{str/tl attr} \marg{regex expr} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \oarg{filter info}
+% \cs{dbNewConditional} \marg{name} \marg{clist attr} \marg{val list} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{clist attr} \marg{val list} \oarg{filter info}
+% \cs{dbNewConditional} \marg{name} \marg{date attr} \marg{date expr} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \oarg{filter info}
% \end{syntax}
%
% \cs{dbNewConditional} 用来定义名为 \meta{name} 的条件,\meta{attr} 指定条件
% 所绑定的属性,在 \meta{cond spec} 中可以用 \cs{dbval} 指代属性的值。
+% \cs{dbNewCond} 是 \cs{dbNewConditional} 的别名。
% \end{function}
%
% \changes{1.3}{2022-01-10}{Update doc}{truncated division}
@@ -885,30 +1399,155 @@ Copyright and License
% \end{note}
%
% 对于类型为 |str| 和 |tl| 的属性,\meta{regex} 为正则表达式,
-% \cs{dbNewConditional} 表示部分匹配,\cs{dbNewConditional*} 表示整体匹配。
+% \cs{dbNewConditional} 表示部分匹配,\cs{dbNewConditional*} 表示整体匹配。该
+% 选项依赖于 \pkg{l3regex}。示例 \ref{cn-filter-str} 演示了部分匹配和全部匹
+% 配的区别,|part| 过滤器匹配所有含数字的 |name|,而 |all| 过滤器匹配全部为
+% 数字的 |name|。
%
-% \begin{verbatim}
-% \dbNewConditional {cond1}{str-attr}{abc} % 匹配 abc, abcd, 1abc, =abc= 等
-% \dbNewConditional*{cond2}{str-attr}{abc} % 只匹配 abc
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(filter-str){匹配字符串}
+ \dbNewDatabase{filter-db}{name=str}
+ \begin{dbFilters}*{filter-db}
+ \dbNewCond{part}{name}{\d+}
+ \dbNewCond*{all}{name}{\d+}
+ \end{dbFilters}
+ \dbNewStyle{part-style}{filter-db}{
+ before-code = Match part:~,
+ item-code = \dbuse{name}\quad,
+ filter = part,
+ }
+ \dbNewStyle{all-style}{filter-db}{
+ before-code = Match all:~,
+ item-code = \dbuse{name}\quad,
+ filter = all,
+ }
+ \dbitemkv{filter-db}{name=123}
+ \dbitemkv{filter-db}{name=int12}
+ \dbitemkv{filter-db}{name=variable}
+ \dbshow{part-style}{filter-db}
+ \dbshow {all-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
%
% 对于类型为 |clist| 的属性,使用 \cs{dbNewConditional} 定义的条件只要
% \meta{val list} 中的任意一个元素在属性值(列表)中则条件成立;使用
% \cs{dbNewConditional*} 定义的条件只有 \meta{val list} 中每一个值都在属性值
-% (列表)中条件才成立。
+% (列表)中条件才成立。示例 \ref{cn-filter-clist} 中过滤器 |or| 匹配含有
+% hard \textbf{或者} red 的标签,而过滤器 |and| 匹配含有 hard \textbf{并且}
+% 含有 red 的标签。
%
-% \begin{verbatim}
-% \dbNewConditional {cond1}{clist-attr}{a, b, c} % a, b, d 满足条件
-% \dbNewConditional*{cond2}{clist-attr}{a, b, c} % a, b, d 不满足条件
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(filter-clist){筛选列表}
+ \dbNewDatabase{filter-db}{label=clist}
+ \begin{dbFilters}*{filter-db}
+ \dbNewCond {or}{label}{hard, red}
+ \dbNewCond*{and}{label}{hard, red}
+ \end{dbFilters}
+ \def\emph#1{\textit{\textbf{#1}}}
+ \dbNewStyle{base-style}{filter-db}{
+ before-code = {
+ \begin{minipage}[t]{.3\textwidth}
+ All items
+ },
+ after-code = {\end{minipage}},
+ item-code = \par\dbarabic.~\dbuse{label},
+ }
+ \dbNewStyle[base-style] {or-style}{filter-db}{
+ before-code = {
+ \begin{minipage}[t]{.3\textwidth}
+ Match \emph{any} of hard \emph{or} red
+ },
+ filter = or,
+ }
+ \dbNewStyle[base-style]{and-style}{filter-db}{
+ before-code = {
+ \begin{minipage}[t]{.3\textwidth}
+ Match \emph{all} of hard \emph{and} red
+ },
+ filter = and,
+ }
+ \dbitemkv{filter-db}{label={hard, red}}
+ \dbitemkv{filter-db}{label={hard, blue}}
+ \dbitemkv{filter-db}{label={easy, blue}}
+ \dbitemkv{filter-db}{label={easy, red}}
+ \dbitemkv{filter-db}{label={hard, red, flat}}
+ \dbshow {base-style}{filter-db}
+ \dbshow {or-style}{filter-db}
+ \dbshow {and-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
%
% \changes{1.3}{2022-01-08}{Update logic}{swap definition of starred and
% unstarred conditionals of date}
% 对于类型为 |date| 的属性,\cs{dbNewConditional} 定义的条件后续处理中会将
-% \meta{expr} 中的所有日期转换成相对\textit{1971年1月1日}的一个整数值,然后将
-% 处理后的表达式传递给 \cs{int_compare:nTF} 做进一步处理;
-% \cs{dbNewConditional*} 使用复习点来定义过滤条件,\meta{review points} 是
-% \cs{dbNewReviewPoints} 定义的复习点,\meta{date} 是用来比较的日期。
+% \meta{expr} 中的所有日期转换成相对1971年1月1日的一个整数值,然后将处理后的
+% 表达式传递给 \cs{int_compare:nTF} 做进一步处理。示例 \ref{cn-filter-date}
+% 展示了如何使用该选项。
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(filter-date){根据日期表达式过滤}
+ \dbNewDatabase{filter-db}{date=date}
+ \dbNewRawFilter{date-filter}{filter-db}{date}{\dbval >= 2022/02/01}
+ \dbNewStyle{filter-style}{filter-db}{
+ item-code = \dbuse{date}\quad,
+ filter = date-filter,
+ }
+ \dbitemkv{filter-db}{date=2022/01/30}
+ \dbitemkv{filter-db}{date=2022/02/01}
+ \dbitemkv{filter-db}{date=2022/02/04}
+ \dbshow{filter-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% 对于类型为 |date| 的属性,\cs{dbNewConditional*} 使用复习点来定义过滤条件,
+% \meta{review points} 是 \cs{dbNewReviewPoints} 定义的复习点,\meta{date}
+% 是用来比较的日期(见示例 \ref{cn-review-points})。
+%
+% \changes{1.5}{2022-01-16}{Add macro}{\cs{dbNewRawFilter}}
+% \begin{function}[added=2022-01-16]{\dbNewRawFilter}
+% \begin{syntax}
+% \cs{dbNewRawFilter} \marg{name} \marg{database} \marg{attr} \marg{cond spec} \oarg{filter info}
+% \cs{dbNewRawFilter}* \marg{name} \marg{database} \marg{attr} \marg{cond spec} \oarg{filter info}
+% 等同于
+% |\begin|\{\env{dbFilters}\}*\phantom{\marg{name}}\marg{database}
+% ~~\cs{dbNewCond} \marg{name} \phantom{\marg{database}} \marg{attr} \marg{cond spec} \oarg{filter info}
+% ~~\cs{dbNewCond}* \marg{name} \phantom{\marg{database}} \marg{attr} \marg{cond spec} \oarg{filter info}
+% |\end|\{\env{dbFilters}\}
+% \end{syntax}
+%
+% 该命令用来快捷地定义单个过滤器。示例 \ref{cn-new-raw-filter} 展示了如何使
+% 用该命令,它和示例 \ref{cn-star-filter} 本质上是相同的。
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(new-raw-filter){定义与条件同名的过滤器}
+ \dbNewDatabase{filter-db}{count=int}
+ \dbNewRawFilter{greater}{filter-db}{count}{\dbval > 3}
+ \dbNewStyle{filter-style}{filter-db}{
+ filter = greater,
+ item-code = \dbuse{count}\quad,
+ }
+ \dbitemkv{filter-db}{count=2}
+ \dbitemkv{filter-db}{count=5}
+ \dbshow{filter-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
%
% \begin{function}[added=2022-01-05]{\dbCombineConditionals}
% \begin{syntax}
@@ -916,37 +1555,60 @@ Copyright and License
% \end{syntax}
%
% \cs{dbCombineConditionals} 定义名为 \marg{name} 的过滤器,并将
-% \cs{dbNewConditional} 定义的条件组合起来,比如
-% \verb=\dbCombineConditionals{filter}{(cond1 && cond2) || !cond3}=。
-% \meta{cond combination} 中可以使用的关系操作符为 \verb=&&, ||, !=。
-% 可以将 \opt{filter} 选项设置为 \meta{name} 来应用过滤器。\meta{info} 为过滤
-% 器的相关信息,在展示数据库的时候可以用 \cs{dbFilterInfo} 指代。
+% \cs{dbNewConditional} 定义的条件组合起来。\meta{cond combination} 中可以使
+% 用的关系操作符为 \verb=&&, ||, !=。可以将 \opt{filter} 选项设置为
+% \meta{name} 来应用过滤器。\meta{info} 为过滤器的相关信息,在展示数据库的时
+% 候可以用 \cs{dbFilterInfo} 指代。使用示例见示例 \ref{cn-filter}.
% \end{function}
%
-% \subsection{使用 \env{dbitem} 环境存储数据}
+% \subsection{存储和使用数据}
%
% \changes{1.4}{2022-01-13}{Update env}{dbitem}
% \begin{environment}[added=2022-01-05, updated=2022-01-13]{dbitem}
% \begin{syntax}
-% |\begin{dbitem}| \marg{database} \oarg{attr-val list}
+% |\begin|\marg{\env{dbitem}} \marg{database} \oarg{attr-val list}
% ~~\meta{code} \\
-% |\end{dbitem}|
+% |\end|\marg{\env{dbitem}}
% \end{syntax}
%
% \env{dbitem} 环境用来存储数据。有两种存储数据的方法,较短的数据可以在选项列
% 表中通过键值对设置值,较长的数据可以在 \meta{code} 中使用 \cs{dbsave} 存储。
% \meta{attr} = \meta{val} 等同于 \cs{dbsave}\marg{attr}\marg{val},
-% \meta{attr}* = \meta{val} 等同于 \cs{dbsave*}\marg{attr}\marg{val},数据在
-% |e| 或者 |x| 类型的参数中不可展开。\cs{dbsave}会覆盖选项中设置的值。没有设
-% 置的值将会被设置为全局默认值,下面给出一个存储示例。
+% \meta{attr}\texttt{*} = \meta{val} 等同于 \cs{dbsave*}\marg{attr}
+% \marg{val},数据在 |e| 或者 |x| 类型的参数中不可展开。\cs{dbsave}会覆盖选
+% 项中设置的值。没有设置的值将会被设置为全局默认值。示例 \ref{cn-dbitem} 展
+% 示了如何存储数据。
% \end{environment}
%
-% \begin{verbatim}
-% \begin{dbitem}[date = 2022-01-01, info = 测试]
-% \dbsave{question}{这是一个测试问题}
-% \dbsave{answer} {这是一个测试答案}
-% \end{dbitem}
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example}(dbitem){存储数据}
+ \dbNewDatabase{ques-db}{date=date, ques=tl, ans=tl}
+ \dbNewStyle{ques-style}{ques-db}{
+ item-code = {%
+ \par\dbuse{date}
+ \par\dbarabic.~\dbuse{ques}
+ \par\textbf{答案:}~\dbuse{ans}
+ },
+ item-after-code = \medskip,
+ date/code* = \zhdate{#1},
+ }
+ \begin{dbitem}{ques-db}[date=2022/01/01]
+ \dbsave{ques}{地球到月亮的距离}
+ \dbsave{ans} {384,401公里}
+ \end{dbitem}
+ \begin{dbitem}{ques-db}[date=2022/01/02]
+ \dbsave{ques}{鲁迅的本名}
+ \dbsave{ans} {周树人}
+ \end{dbitem}
+ \dbshow{ques-style}{ques-db}
+\end{example}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
%
% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbitemkv}}
% \begin{function}[added=2022-01-13]{\dbitemkv}
@@ -957,8 +1619,6 @@ Copyright and License
% 只使用 \meta{attr-val list} 来存储数据。
% \end{function}
%
-% \subsection{\cs{dbsave} 和 \cs{dbuse}}
-%
% \changes{1.3}{2022-01-08}{Add macro}{\cs{dbsave*}}
% \begin{function}[added=2022-01-05, updated=2022-01-08]{\dbsave, \dbsave*}
% \begin{syntax}
@@ -976,8 +1636,8 @@ Copyright and License
% \cs{dbuse} \marg{attr}
% \end{syntax}
%
-% \cs{dbuse} 用来展示数据,只能在 \opt{item-code} 选项中使用。\cs{dbuse} 是可
-% 展开的。
+% \cs{dbuse} 用来展示数据,只能在 \opt{item-code}, \opt{item-before-code},
+% \opt{item-after-code} 选项中使用。\cs{dbuse} 是可展开的。
% \end{function}
%
% \subsection{条件判别式}
@@ -985,20 +1645,69 @@ Copyright and License
% \begin{function}[added=2022-01-05, EXP]{\dbIfEmptyT, \dbIfEmptyF, \dbIfEmptyTF}
% \begin{syntax}
% \cs{dbIfEmptyTF} \marg{true code} \marg{false code} \\
-% \cs{dbIfEmptyT} \marg{true code} \\
+% \cs{dbIfEmptyT} \marg{true code} \\
% \cs{dbIfEmptyF} \marg{false code}
% \end{syntax}
%
-% 该判别式用来判断当前数据库是否为空。下面的示例展示了如何预防空的列表环境。
+% 该判别式用来判断当前数据库是否为空。示例 \ref{cn-empty-db} 演示了如何使用
+% 该判别式来预防空的列表环境。
% \end{function}
%
-% \begin{verbatim}
-% \dbNewStyle{style-cond1}{database-test}{
-% before-code = {\dbIfEmptyF{\begin{enumerate}}},
-% after-code = {\dbIfEmptyF{\end{enumerate}}},
-% item-code = {\item \dbuse{attr-test}}
-% }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(empty-db){预防空列表环境}
+ \dbNewDatabase{test-db}{text=tl}
+ \dbNewRawFilter{alph}{test-db}{text}{\d}
+ \dbNewStyle{base-style}{test-db}{
+ before-code = \dbIfEmptyTF{Empty db}{\begin{enumerate}},
+ after-code = \dbIfEmptyF{\end{enumerate}}\medskip,
+ item-code = \item \dbuse{text},
+ }
+ \dbNewStyle[base-style]{empty-style}{test-db}{
+ raw-filter=!alph
+ }
+ \dbitemkv{test-db}{text={$1 + 1 = 2$.}}
+ \dbitemkv{test-db}{text={I have 2 pens.}}
+ \dbshow {base-style}{test-db}
+ \dbshow{empty-style}{test-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-17}{Add macros}{\cs{dbIfLastT}, \cs{dbIfLastF},
+% \cs{dbIfLastTF}}
+% \begin{function}[added=2022-01-17, EXP]{\dbIfLastT, \dbIfLastF, \dbIfLastTF}
+% \begin{syntax}
+% \cs{dbIfLastTF} \marg{true code} \marg{false code}
+% \cs{dbIfLastT} \marg{true code}
+% \cs{dbIfLastF} \marg{false code}
+% \end{syntax}
+%
+% 该判别式用来判断当前是否为数据库要展示的最后一条数据。示例
+% \ref{cn-last} 演示了如何设置条目之间的间隔。
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(last){设置条目之间的间隔}
+ \dbNewDatabase{last-db}{text=tl}
+ \dbNewStyle{last-style}{last-db}{
+ item-code = {%
+ \par\dbuse{text}\par%
+ \dbIfLastF{\textcolor{red}{\hrulefill separator\hrulefill}}%
+ },
+ }
+ \dbitemkv{last-db}{text=This is the first paragraph.}
+ \dbitemkv{last-db}{text=This is the second paragraph.}
+ \dbitemkv{last-db}{text=This is the last paragraph.}
+ \dbshow{last-style}{last-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
%
% \changes{1.2}{2022-01-08}{Remove macros}{\cs{dbItemIfEmpty(TF)}, \cs{dbClistItemIfEmpty(TF)}}
%
@@ -1010,26 +1719,49 @@ Copyright and License
% \dbIntMin, \dbIntMod, \dbFpSign,
% }
% \begin{syntax}
-% \cs{dbIntAbs} \Arg{intexpr}
-% \cs{dbIntSign} \Arg{intexpr}
-% \cs{dbIntDivRound} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbIntDivTruncate} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbIntMax} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbIntMin} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbIntMod} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbFpSign} \Arg{fpexpr}
-% \end{syntax}
-% \cs{dbIntAbs} 等同于 \cs{int_abs:n} \\
-% \cs{dbIntSign} 等同于 \cs{int_sign:n} \\
-% \cs{dbIntDivRound} 等同于 \cs{int_div_round:nn} \\
-% \cs{dbIntDivTruncate} 等同于 \cs{int_div_truncate:nn} \\
-% \cs{dbIntMax} 等同于 \cs{int_max:nn} \\
-% \cs{dbIntMin} 等同于 \cs{int_min:nn} \\
-% \cs{dbIntMod} 等同于 \cs{int_mod:nn} \\
-% \cs{dbFpSign} 等同于 \cs{fp_sign:n} \\
-% 详细的文档见 \pkg{interface3} \\
+% \cs{dbIntAbs} \Arg{intexpr}
+% \cs{dbIntSign} \Arg{intexpr}
+% \cs{dbIntDivRound} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbIntDivTruncate} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbIntMax} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbIntMin} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbIntMod} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbFpSign} \Arg{fpexpr}
+% \end{syntax}
+% \begin{tblr}{ll}
+% \cs{dbIntAbs} & 等同于 \cs{int_abs:n} \\
+% \cs{dbIntSign} & 等同于 \cs{int_sign:n} \\
+% \cs{dbIntDivRound} & 等同于 \cs{int_div_round:nn} \\
+% \cs{dbIntDivTruncate} & 等同于 \cs{int_div_truncate:nn} \\
+% \cs{dbIntMax} & 等同于 \cs{int_max:nn} \\
+% \cs{dbIntMin} & 等同于 \cs{int_min:nn} \\
+% \cs{dbIntMod} & 等同于 \cs{int_mod:nn} \\
+% \cs{dbFpSign} & 等同于 \cs{fp_sign:n} \\
+% \end{tblr}
+%
+% 详细的文档见 \pkg{interface3}。示例 \ref{cn-expr-db} 展示了如何筛选3的倍数。
% \end{function}
%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(expr-db){筛选3的倍数}
+ \dbNewDatabase{expr-db}{n=int}
+ \dbNewRawFilter{mod}{expr-db}{n}{\dbIntMod{\dbval}{3} = 0}
+ \dbNewStyle{expr-style}{expr-db}{
+ item-code = \dbuse{n}\quad,
+ filter = mod,
+ }
+ \dbitemkv{expr-db}{n=2}
+ \dbitemkv{expr-db}{n=3}
+ \dbitemkv{expr-db}{n=6}
+ \dbitemkv{expr-db}{n=7}
+ \dbshow{expr-style}{expr-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
% \subsection{特殊命令}
%
% \pkg{dbshow} 定义了一些特殊的命令,会根据语境展开为不同的内容。
@@ -1040,27 +1772,64 @@ Copyright and License
% }
% \changes{1.1}{2022-01-06}{Fix bug}{\cs{dbIndex} not defined}
% \begin{function}[added=2022-01-05, EXP]{
-% \dbval, \dbDatabase, \dbFilterName, \dbFilterInfo,
+% \dbval, \dbtoday, \dbDatabase, \dbFilterName, \dbFilterInfo,
% \dbIndex, \dbarabic, \dbalph, \dbAlph, \dbroman, \dbRoman
% }
% \begin{tblr}{ll}
-% \cs{dbval} & 当前属性的值 \\
-% \cs{dbDatabase} & 数据库名称 \\
+% \cs{dbval} & 当前属性的值 \\
+% \cs{dbtoday} & 当天的日期 \\
+% \cs{dbDatabase} & 数据库名称 \\
% \cs{dbFilterName} & 当前样式过滤器的名称 \\
% \cs{dbFilterInfo} & 当前样式过滤器的相关信息 \\
-% \cs{dbIndex} & 数据索引,等同于 \cs{dbuse}|{id}| \\
-% \cs{dbarabic} & 用数字表示的查询集数据计数 \\
-% \cs{dbalph} & 用小写字母表示的查询集数据计数 \\
-% \cs{dbAlph} & 用大写字母表示的查询集数据计数 \\
-% \cs{dbroman} & 用小写罗马字母表示的查询集数据计数 \\
-% \cs{dbroman} & 用大写罗马字母表示的查询集数据计数 \\
-% \end{tblr}
+% \cs{dbIndex} & 数据索引,等同于 \cs{dbuse}\marg{id} \\
+% \cs{dbarabic} & 用数字表示的查询集数据计数 \\
+% \cs{dbalph} & 用小写字母表示的查询集数据计数 \\
+% \cs{dbAlph} & 用大写字母表示的查询集数据计数 \\
+% \cs{dbroman} & 用小写罗马字母表示的查询集数据计数 \\
+% \cs{dbroman} & 用大写罗马字母表示的查询集数据计数 \\
+% \end{tblr}
+%
+% \cs{dbtoday} 使用 \cs{dbdatesep} 确定的分隔符来展示日期。见示例
+% \ref{cn-spespecial-cs}.
% \end{function}
%
-% \section{错题本示例}
-% 见第 \ref{sec:example} 节。
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example}(special-cs){特殊命令}
+ \dbNewDatabase{special-db}{name=str}
+ \dbNewRawFilter*{number}{special-db}{name}{\d+}[name that is a number]
+ \dbNewStyle{special-style}{special-db}{
+ before-code = {
+ Date: \dbtoday \\
+ Database: \dbDatabase
+ Filter: \dbFilterName \\
+ Filter info: \dbFilterInfo \par
+ \begin{tabular}{@{}lllllll}
+ Index & arabic & alph & Alph & roman & Roman & value \\
+ },
+ after-code = \end{tabular},
+ item-code* = {%
+ \dbIndex & \dbarabic & \dbalph & \dbAlph &
+ \dbroman & \dbRoman & \dbuse{name} \\
+ },
+ sort = name,
+ filter = number,
+ }
+ \dbitemkv{special-db}{name=test}
+ \dbitemkv{special-db}{name=12}
+ \dbitemkv{special-db}{name=int2}
+ \dbitemkv{special-db}{name=99}
+ \dbshow{special-style}{special-db}
+\end{example}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
%
% \changes{1.1}{2022-01-07}{Update doc}{improve example}
+% \changes{1.5}{2022-01-17}{Remove doc}{Remove big example}
%
% \title{
% Package \pkg{dbshow} \fileversion%
@@ -1085,7 +1854,7 @@ Copyright and License
% certain times or questions having not been reviewed for certain days. So this
% package provides a database to do such thing.
%
-% The package provides four core functions: data storage and display, data
+% The package provides four core functions: data storage, data
% filtering, data sorting and data display. All data is saved once and then you
% can display these data with custom filters, orders and styles.
%
@@ -1129,23 +1898,8 @@ Copyright and License
% by \pkg{dbshow} itself and supports converting to integer and printing with
% style.
%
-% \subsection{Comparison to \pkg{datatool}}
-%
% \changes{1.2}{2022-01-07}{Add doc}{add comparison to \pkg{datatool}}
-%
-% \pkg{dbshow} and \pkg{datatool} implement the same core functions. But
-% \pkg{dbshow} is based on \pkg{expl3} and it supports string regex and
-% multi-level sorting. \pkg{dbshow} tries to divide style from the contents
-% (data in database): all styles are predefined and can be reused conveniently
-% so that there can be only codes to save data and one-line code to show the
-% database inside the \env{document} environment. You can hide the details in
-% the preamble and focus on the data you want to display. \pkg{dbshow} provides
-% a simple temporary runtime database, which means it can not input and output
-% data from/to extern files (they should be responsible by some professional
-% programming languages). When you need to delete or revise a record, just go to
-% where it is recorded in the source code rather than use a macro to manipulate
-% data after they are saved. In a sense, \TeX~file is also a kind of data
-% persistence.
+% \changes{1.3}{2022-01-07}{Remove doc}{remove comparison to \pkg{datatool}}
%
% \section{Interfaces}
%
@@ -1186,17 +1940,6 @@ Copyright and License
% Every database has a default attribute |id| to store the index of the item.
% \end{note}
%
-% The example below define a database named |ques|.
-% \begin{verbatim}
-% \dbNewDatabase{ques}{
-% question = tl, % store question
-% answer = tl, % store corresponding answer
-% date = date, % store the date when you were wrong
-% info = tl, % store extra info
-% labels = clist % store question labels
-% }
-% \end{verbatim}
-%
% \begin{function}[added=2022-01-05]{\dbshow}
% \begin{syntax}
% \cs{dbshow} \marg{style} \marg{database}
@@ -1216,7 +1959,7 @@ Copyright and License
%
% \subsection{\cs{dbNewStyle} and Style Options}
%
-% \begin{function}[added=2022-01-05]{\dbNewStyle}
+% \begin{function}[added=2022-01-05, updated=2022-01-15]{\dbNewStyle}
% \begin{syntax}
% \cs{dbNewStyle} \oarg{base styles} \marg{style} \marg{database} \marg{opts}
% \end{syntax}
@@ -1230,253 +1973,412 @@ Copyright and License
%
% \begin{option}[added=2022-01-05]{filter}
% \begin{syntax}
-% filter = <filter>
+% \opt{filter} = <filter> \inidef(-none-)
% \end{syntax}
%
-% Set the \meta{filter} defined by \cs{dbCombineFilters}.
+% Set the \meta{filter} defined by \cs{dbCombineFilters}. Example
+% \ref{en-filter} shows how to define conditionals and combine them into
+% a filter.
% \end{option}
%
+% \DeleteShortVerb{\|}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(filter){Filter Items}
+ \dbNewDatabase{filter-db}{name=str, count=int}
+ \begin{dbFilters}{filter-db}
+ \dbNewCond {cond1}{count}{\dbval > 3}
+ \dbNewCond*{cond2}{name} {\d+}
+ \dbCombCond{filter-and}{cond1 && cond2}
+ \dbCombCond{filter-or} {cond1 || cond2}
+ \end{dbFilters}
+ \dbitemkv{filter-db}{name=123, count=4}
+ \dbitemkv{filter-db}{name=ab3, count=2}
+ \dbitemkv{filter-db}{name=bag, count=5}
+ \dbNewStyle{filter-and-style}{filter-db}{
+ filter = filter-and,
+ before-code = \par Filter And\par,
+ item-code = {\dbuse{name}: \dbuse{count}\quad},
+ }
+ \dbNewStyle{filter-or-style}{filter-db}{
+ filter = filter-or,
+ before-code = \par Filter Or\par,
+ item-code = {\dbuse{name}: \dbuse{count}\quad},
+ }
+ \dbshow{filter-and-style}{filter-db}
+ \dbshow{filter-or-style} {filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+% \MakeShortVerb{\|}
+%
% \changes{1.1}{2022-01-06}{Add option}{\opt{raw-filter}}
% \begin{option}[added=2022-01-06]{raw-filter}
% \begin{syntax}
-% raw-filter = <conditional expression>
+% \opt{raw-filter} = <conditional expression> \inidef
% \end{syntax}
%
-% Set anonymous with conditionals defined by \cs{dbNewConditional}. Two
-% filters shows in the code below have the same meaning.
+% Set anonymous filter with conditionals defined by \cs{dbNewConditional}.
+% Example \ref{en-raw-filter} shows how to simplify the code of example
+% \ref{en-filter} with \opt{raw-filter} option.
% \end{option}
%
-% \begin{verbatim}
-% % method 1
-% \begin{dbFilters}{db}
-% \dbNewConditional{cond1}{int-attr}{\rval > 1}
-% \dbNewConditional*{cond2}{str-attr}{\d+}
-% \end{dbFilters}
-% \dbNewStyle{style}{db}{raw-filter={cond1 && cond2}}
-% % method 2
-% \begin{dbFilters}{db}
-% \dbNewConditional{cond1}{int-attr}{\rval > 1}
-% \dbNewConditional*{cond2}{str-attr}{\d+}
-% \dbCombineFilters{filter}{cond1 && cond2}
-% \end{dbFilters}
-% \dbNewStyle{style}{db}{filter=filter}
-% \end{verbatim}
+% \DeleteShortVerb{\|}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(raw-filter){Using Anonymous Filter}
+ \dbNewDatabase{filter-db}{name=str, count=int}
+ \begin{dbFilters}{filter-db}
+ \dbNewCond {cond1}{count}{\dbval > 3}
+ \dbNewCond*{cond2}{name} {\d+}
+ \end{dbFilters}
+ \dbitemkv{filter-db}{name=123, count=4}
+ \dbitemkv{filter-db}{name=ab3, count=2}
+ \dbitemkv{filter-db}{name=bag, count=5}
+ \dbNewStyle{filter-and-style}{filter-db}{
+ raw-filter = {cond1 && cond2},
+ before-code = \par Filter And\par,
+ item-code = {\dbuse{name}: \dbuse{count}\quad},
+ }
+ \dbNewStyle{filter-or-style}{filter-db}{
+ raw-filter = {cond1 || cond2},
+ before-code = \par Filter Or\par,
+ item-code = {\dbuse{name}: \dbuse{count}\quad},
+ }
+ \dbshow{filter-and-style}{filter-db}
+ \dbshow{filter-or-style} {filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+% \MakeShortVerb{\|}
%
% \changes{1.2}{2022-01-08}{Fix bug}{string sorting bug}
% \begin{option}[added=2022-01-05]{sort}
% \begin{syntax}
-% sort = \{ <attr spec1>, <attr spec2>, \ldots{} \}
+% \opt{sort} = \{ <attr spec1>, <attr spec2>, \ldots{} \} \inidef
% \end{syntax}
%
% Set sorting rules. Attributes of type |str, date, int, fp| is supported to
-% sort. Multi-level sort is allowed. \meta{attr} represents for ascending
-% order, and \meta{attr}* represents for descending order. The example below
-% use four fields to determine the order of the records. It sorts on |level|
-% in descending order first and if two |levels| are same then sorts on |birth|
-% in ascending order and so on.
+% sort. Multi-level sort is allowed. \meta{attr} represents for ascending
+% order, and \meta{attr}\texttt{*} represents for descending order. Example
+% \ref{en-sort} shows how to sort items by |count| in descending order and
+% for the same |count|, sort by |name| in ascending order.
% \end{option}
%
-% \begin{verbatim}
-% \dbNewDatabase{sort-example}{
-% name = str,
-% birth = date,
-% level = int,
-% weight = fp,
-% }
-% \dbNewStyle{sort-style}{sort-example}{
-% sort = { level*, birth, name, weight }
-% }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(sort){Multi-level Sorting}
+ \dbNewDatabase{sort-db}{name=str, count=int}
+ \dbNewStyle{sort-style}{sort-db}{
+ sort = {count*, name},
+ item-code = {\dbuse{name}: \dbuse{count}\quad}
+ }
+ \dbitemkv{sort-db}{name=bag, count=1}
+ \dbitemkv{sort-db}{name=box, count=1}
+ \dbitemkv{sort-db}{name=tag, count=2}
+ \dbitemkv{sort-db}{name=pen, count=3}
+ \dbshow{sort-style}{sort-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
%
-% \begin{option}[added=2022-01-05, rEXP]{item-code}
+% \begin{option}[added=2022-01-05, rEXP]{before-code}
% \begin{syntax}
-% item-code = <code>
+% \opt{before-code} = <before code> \inidef*
% \end{syntax}
%
-% Set the code that show a single record. You can use \cs{dbuse} to display
-% certian attribute.
+% Set the \meta{code} that is executed \enbefore displaying the database.
+% See Example \ref{en-db-wrap}.
% \end{option}
%
-% \changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
-% \begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+% \begin{option}[added=2022-01-05, rEXP]{after-code}
% \begin{syntax}
-% <attr>/sep = <separator> \\
-% <attr>/sep = \{ \\
-% ~~\meta{separator between two}, \\
-% ~~\meta{separator between more than two}, \\
-% ~~\meta{separator between final two} \\
-% \} \\
-% <attr>/sep = \{ \\
-% ~~\meta{separator before year}, \\
-% ~~\meta{separator between year and month}, \\
-% ~~\meta{separator between month and day}, \\
-% ~~\meta{separator after day} \\
-% \} \\
+% \opt{after-code} = <after code> \inidef*
% \end{syntax}
%
-% Only for attributes of type |clist| or |date|. Set the separator between
-% items. If the argument is an one-item comma list, all separators are set to
-% \meta{separator} but \meta{separator before year} and \meta{separator after
-% day} is set empty.
+% Set the \meta{code} that is executed \enafter displaying the database.
+% See Example \ref{en-db-wrap}.
% \end{option}
%
-% If the argument is a comma list of 3 items, it is used to set the separator
-% between items of the comma list. Following documentation is quoted from
-% \pkg{interface3}:
-% \begin{quote}
-% If the comma list has more than two items, the \meta{separator between
-% more than two} is placed between each pair of items except the last, for
-% which the \meta{separator between final two} is used. If the comma list
-% has exactly two items, then they are placed in the input stream separated
-% by the \meta{separator between two}. If the comma list has a single item,
-% it is placed in the input stream, and a comma list with no items produces
-% no output.
-% \end{quote}
-% For attributes of type |clist|, incorrect number (numbers exclude 1 and 3)
-% of items of the argument will raise an error.
-%
-% \begin{verbatim}
-% % clist-attr is an attribute of database db
-% % suppose the val of clist-attr is { 1, 2, 3 }
-% \dbNewStyle{clist-sep}{db}{
-% clist-attr/sep = { ,~ }, % print 1, 2, 3
-% clist-attr/sep = { {,~}, {,~}, {and~} } % print 1, 2 and 3
-% }
-% \end{verbatim}
-%
-% If the argument is a comma list of 4 items, it is used to set the separators
-% of the date. For attributes of type |date|, incorrect number (numbers
-% exclude 1 and 4) will raise an error.
-%
-% \begin{verbatim}
-% % date-attr is an attribute of database db
-% % suppose the val of date-attr is 2022/01/01
-% \dbNewStyle{date-sep}{db}{
-% date-attr/sep = -, % print 2022-01-01
-% date-attr/sep = { |, -, -, | } % print |2022-01-01|
-% }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(db-wrap){Set the Before and After Code of the Database}
+ \dbNewDatabase{wrap-db}{text=tl}
+ \dbNewStyle{wrap-style}{wrap-db}{
+ before-code = \textit{before code}\quad,
+ after-code = \textit{after code},
+ item-code = \dbarabic.~\dbuse{text}\quad
+ }
+ \dbitemkv{wrap-db}{text=text1}
+ \dbitemkv{wrap-db}{text=text2}
+ \dbitemkv{wrap-db}{text=text3}
+ \dbshow{wrap-style}{wrap-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
%
-% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
-% \begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+% \begin{option}[added=2022-01-05, rEXP]{item-code}
% \begin{syntax}
-% <attr>/zfill = <\TTF>
+% \opt{item-code} = <item code> \inidef
% \end{syntax}
%
-% Only for attributes of type |date|. Control whether to fill zero on the left
-% of the month or day.
+% Set the code that display a record. You can use \cs{dbuse} to denote the
+% value of attribute. Example \ref{en-item-code} shows how to display an
+% acronym glossary table.
% \end{option}
%
-% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbdatesep}}
-% \begin{function}[added=2022-01-13, EXP]{\dbdatesep}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(item-code){Display Database Items}
+ \dbNewDatabase{item-db}{acronym=str, desc=tl}
+ \dbNewStyle{item-style}{item-db}{
+ before-code = {\dbIfEmptyF{\begin{description}}},
+ after-code = {\dbIfEmptyF{\end{description}}},
+ item-code = {\item[\dbuse{acronym}] \dbuse{desc}},
+ sort = acronym,
+ }
+ \dbitemkv{item-db}{acronym=PM, desc={Prime Minister}}
+ \dbitemkv{item-db}{acronym=CBD, desc={Central Business District}}
+ \dbitemkv{item-db}{acronym=DL, desc={Deep Learning}}
+ \dbshow{item-style}{item-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-17}{Add option}{\opt{item-code*}}
+% \begin{option}[added=2022-01-17, rEXP]{item-code*}
% \begin{syntax}
-% \cs{dbdatesep} \marg{separator}
+% \opt{item-code*} = <item code> \inidef
% \end{syntax}
%
-% Set the separator for internal date parsing. The default value is |/|,
-% i.e. the date must be store in the format of |yyyy/mm/dd|.
-% \end{function}
+% The \meta{item code} will be expanded through \cs{protected@edef} before
+% it is used. \ref{en-item-exp} shows how to display data with table using
+% the expanded code.
+% \end{option}
%
-% \subsubsection{Decorators}
-%
-% The options below serves as decorators. In some cases, decorator can also be
-% encoded directly into |item-code| or some other places, which is convenient
-% sometimes. The benefit of defining decorators with options is that styles step
-% further to be divided with contents. In the examples below, \meta{style1} and
-% \meta{style2} is the same style, which wrap \meta{attr1} with *. When you want
-% another style which wrap \meta{attr1} with =, if you choose the way of
-% \meta{style1}, \meta{item code} are repeated, otherwise if you choose the way
-% of \meta{style2}, \meta{item code} is inherited and you only need define the
-% decorators.
-%
-% \begin{verbatim}
-% \dbNewStyle{style1}{db}{
-% item-code = {%
-% *\rvuse{attr1}*\rvuse{attr2}
-% % more code
-% }
-% }
-% \dbNewStyle{base-style}{db}{
-% item-code = {%
-% \rvuse{attr1}\rvuse{attr2}
-% % more code
-% }
-% }
-% \dbNewStyle[base-style]{style2}{db}{
-% attr1/before-code = { * },
-% attr1/after-code = { * },
-% }
-% \dbNewStyle[base-style]{style3}{db}{
-% attr1/before-code = { = },
-% attr1/after-code = { = },
-% }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(item-exp){Display Data with Table}
+ \dbNewDatabase{tab-db}{name=str, count=int}
+ \dbNewStyle{tab-style}{tab-db}{
+ before-code = {%
+ \begin{tabular}{ll}
+ name & count \\
+ },
+ after-code = \end{tabular},
+ item-code* = {%
+ \textcolor{red}{\dbuse{name}} & \dbuse{count} \\
+ },
+ }
+ \dbitemkv{tab-db}{name=bag, count=100}
+ \dbitemkv{tab-db}{name=pig, count=20}
+ \dbshow{tab-style}{tab-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
%
-% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/wrapper}}
-% \begin{option}[added=2022-01-08, rEXP]{<attr>/wrapper}
+% \changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
+% \opt{record-after-code}}
+% \changes{1.5}{2022-01-14}{Update options}{Rename \opt{record-before-code}
+% and \opt{record-after-code} to \opt{item-before-code} and
+% \opt{item-after-code}}
+% \begin{option}[added=2022-01-08, updated=2022-01-14, rEXP]{item-before-code}
% \begin{syntax}
-% <attr>/wrapper = <control sequence>
+% \opt{item-before-code} = <before code> \inidef*
% \end{syntax}
%
-% Only for attributes of type |date|. Output of \cs{dbuse}\marg{date attr}
-% will be \meta{control sequence}\marg{date}.
+% Set the \meta{code} that is executed \enbefore displaying a item. See
+% Example \ref{en-item-wrapper}.
% \end{option}
%
-% \begin{option}[added=2022-01-05, rEXP]{before-code}
+% \begin{option}[added=2022-01-08, updated=2022-01-14, rEXP]{item-after-code}
% \begin{syntax}
-% before-code = <code>
+% \opt{item-after-code} = <after code> \inidef*
% \end{syntax}
%
-% Set the \meta{code} that is executed \enbefore displaying the database.
+% Set the \meta{code} that is executed \enafter displaying the item. See
+% Example \ref{en-item-wrapper}.
% \end{option}
%
-% \begin{option}[added=2022-01-05, rEXP]{after-code}
-% \begin{syntax}
-% after-code = <code>
-% \end{syntax}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(item-wrapper){Set the Before and After Code of the Item}
+ \dbNewDatabase{item-wrap-db}{text=tl}
+ \dbNewStyle{item-wrap-style}{item-wrap-db}{
+ item-before-code = \begingroup\ttfamily<,
+ item-after-code = >\endgroup,
+ item-code = \dbuse{text},
+ }
+ \dbitemkv{item-wrap-db}{text=example}
+ \dbshow{item-wrap-style}{item-wrap-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
%
-% Set the \meta{code} that is executed \enafter displaying the database.
-% \end{option}
+% \subsubsection{Attribute Options}
%
-% \changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
-% \opt{record-after-code}}
-% \begin{option}[added=2022-01-05, rEXP]{record-before-code}
+% \changes{1.5}{2022-01-14}{Remove option}{\opt{<attr>/wrapper}}
+%
+% \changes{1.5}{2022-01-14}{Add options}{\opt{<attr>/code},
+% \opt{<attr>/code*}}
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/code}
% \begin{syntax}
-% record-before-code = <code>
+% \nopt{<attr>/code} = <code> \inidef(\#1)
% \end{syntax}
%
-% Set the \meta{code} that is executed \enbefore displaying a record.
+% Set the style code of \meta{attr}. In \meta{code}, |#1| is replaced with the
+% value of \meta{attr}. Example \ref{en-attr-code} prints |name| whose |count|
+% is less than 10 in teal color, otherwise in red color.
% \end{option}
%
-% \begin{option}[added=2022-01-05, rEXP]{record-after-code}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(attr-code){Set Style Code of Attribute}
+ \dbNewDatabase{attr-code-db}{name=str, count=int}
+ \begin{dbFilters}{attr-code-db}
+ \dbNewCond{large}{count}{\dbval >= 10}
+ \end{dbFilters}
+ \dbNewStyle{base-style}{attr-code-db}{
+ item-code = \dbuse{name}:~\dbuse{count}\quad,
+ }
+ \dbNewStyle[base-style]{large-style}{attr-code-db}{
+ raw-filter = large,
+ name/code = \textcolor{red}{#1},
+ }
+ \dbNewStyle[base-style]{small-style}{attr-code-db}{
+ raw-filter = !large,
+ name/code = \textcolor{teal}{#1},
+ }
+ \dbitemkv{attr-code-db}{name=bag, count=1}
+ \dbitemkv{attr-code-db}{name=pen, count=12}
+ \dbitemkv{attr-code-db}{name=pig, count=5}
+ \dbitemkv{attr-code-db}{name=egg, count=50}
+ \dbshow{large-style}{attr-code-db}
+ \dbshow{small-style}{attr-code-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/code*}
% \begin{syntax}
-% record-after-code = <code>
+% \nopt{<attr>/code*} = <code> \inidef
% \end{syntax}
%
-% Set the \meta{code} that is executed \enafter displaying the record.
+% Set the style code of \meta{attr}. In \meta{code}, |#1| is replaced with the
+% \textbf{expanded} value of \meta{attr}. This is useful to commands that
+% require special format of the arguments.
% \end{option}
%
+% Example \ref{en-exp-code} shows how to print Chinese date with \cs{zhdate}
+% of package \pkg{zhnumber}. \cs{zhdate} require argument to be the date of
+% |yyyy/mm/dd|, which is the default date format of \pkg{dbshow}. But we need
+% to expand the date through \opt{date/code*} first because \cs{zhdate} cannot
+% parse the token list other than |yyyy/mm/dd|.
+%
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(exp-code){Show Chinese Date}
+ % \usepackage{zhnumber}
+ \dbNewDatabase{exp-db}{date=date, event=tl}
+ \dbNewStyle{exp-style}{exp-db}{
+ item-code = \par\makebox[4cm][l]{\dbuse{date}}\dbuse{event},
+ date/code* = \zhdate{#1},
+ }
+ \dbitemkv{exp-db}{date=2020/12/31, event=eat}
+ \dbitemkv{exp-db}{date=2021/01/01, event=sleep}
+ \dbshow{exp-style}{exp-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
+%
% \begin{option}[added=2022-01-05, rEXP]{<attr>/before-code}
% \begin{syntax}
-% <attr>/before-code = <code>
+% \nopt{<attr>/before-code} = <before code> \inidef*
% \end{syntax}
%
% Set the \meta{code} that is executed by \cs{dbuse} \enbefore displaying
-% certain attribute.
+% the value of attribute.
% \end{option}
%
% \begin{option}[added=2022-01-05, rEXP]{<attr>/after-code}
% \begin{syntax}
-% <attr>/after-code = <code>
+% \nopt{<attr>/after-code} = <after code> \inidef*
% \end{syntax}
%
% Set the \meta{code} that is executed by \cs{dbuse} \enafter displaying
-% certain attribute.
+% the value of attribute.
+% \end{option}
+%
+% The style code execution order of attribute is:
+% \begin{enumerate}[nolistsep]
+% \item \opt{<attr>/before-code}
+% \item \opt{<attr>/code} or \opt{<attr>/code*}
+% \item \opt{<attr>/after-code}
+% \end{enumerate}
+%
+% \changes{1.5}{2022-01-16}{Add options}{\opt{<attr>/item-code},
+% \opt{<attr>/item-code*}}
+% \begin{option}[added=2022-01-16, rEXP]{<attr>/item-code}
+% \begin{syntax}
+% \nopt{<attr>/item-code} = <item code> \inidef(\#1)
+% \end{syntax}
+%
+% Set the style code of \meta{attr}. In \meta{item code}, |#1| is replaced
+% with the item of the comma list. Example \ref{en-clist-code} shows how to
+% set the style code of the item of the comma list.
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(clist-code){Set the Style Code of Clist Item}
+ \dbNewDatabase{clist-db}{name=str, label=clist}
+ \dbNewStyle{clist-style}{clist-db}{
+ item-code = \par\dbuse{name}:~\dbuse{label},
+ label/item-code = (\textcolor{red}{\textit{#1}}),
+ }
+ \dbitemkv{clist-db}{name=pig, label={animal, meat}}
+ \dbitemkv{clist-db}{name=Alex, label={person, male}}
+ \dbshow{clist-style}{clist-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \begin{option}[added=2022-01-16, rEXP]{<attr>/item-code*}
+% \begin{syntax}
+% \nopt{<attr>/item-code*} = <item code> \inidef
+% \end{syntax}
+%
+% Set the style code of \meta{attr}. In \meta{item code}, |#1| is replaced
+% with the \textbf{expanded} item of the comma list.
% \end{option}
%
% \begin{option}[added=2022-01-05, rEXP]{<attr>/item-before-code}
% \begin{syntax}
-% <attr>/item-before-code = <code>
+% \nopt{<attr>/item-before-code} = <before code> \inidef*
% \end{syntax}
%
% Only for attributes of type |clist|. Set the \meta{code} that is excuted
@@ -1485,63 +2387,297 @@ Copyright and License
%
% \begin{option}[added=2022-01-05, rEXP]{<attr>/item-after-code}
% \begin{syntax}
-% <attr>/item-after-code = <code>
+% \nopt{<attr>/item-after-code} = <after code> \inidef*
% \end{syntax}
%
% Only for attributes of type |clist|. Set the \meta{code} that is excuted
% \enafter displaying the item of the comma list.
% \end{option}
%
-% \subsection{Use \cs{dbNewReviewPoints} to Define Review Points}
+% The style code execution order of comma list item is:
+% \begin{enumerate}[nolistsep]
+% \item \opt{<attr>/item-before-code}
+% \item \opt{<attr>/item-code} or \opt{<attr>/item-code*}
+% \item \opt{<attr>/item-after-code}
+% \end{enumerate}
+%
+% \changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
+% \begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+% \begin{syntax}
+% \nopt{<attr>/sep} = <separator> \sepini\\
+% \nopt{<attr>/sep} = \{ \\
+% ~~\meta{separator between two}, \\
+% ~~\meta{separator between more than two}, \\
+% ~~\meta{separator between final two} \\
+% \} \\
+% \nopt{<attr>/sep} = \{ \\
+% ~~\meta{separator before year}, \\
+% ~~\meta{separator between year and month}, \\
+% ~~\meta{separator between month and day}, \\
+% ~~\meta{separator after day} \\
+% \} \\
+% \end{syntax}
+%
+% Only for attributes of type |clist| or |date|. Set the separator between
+% items. If the argument is an one-item comma list, all separators are set to
+% \meta{separator} but \meta{separator before year} and \meta{separator after
+% day} is set empty.
+% \end{option}
+%
+% If the argument is a comma list of 3 items, it is used to set the separator
+% between items of the comma list. Following documentation is quoted from
+% \pkg{interface3}:
+% \begin{quote}
+% If the comma list has more than two items, the \meta{separator between
+% more than two} is placed between each pair of items except the last, for
+% which the \meta{separator between final two} is used. If the comma list
+% has exactly two items, then they are placed in the input stream separated
+% by the \meta{separator between two}. If the comma list has a single item,
+% it is placed in the input stream, and a comma list with no items produces
+% no output.
+% \end{quote}
+% For attributes of type |clist|, incorrect number (numbers exclude 1 and 3)
+% of items of the argument will raise an error. Example \ref{en-clist-sep}
+% shows how to use this option to customize the separators between comma
+% list items.
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(clist-sep){Set Separator Between Items of Comma List}
+ \dbNewDatabase{clist-db}{label=clist}
+ \dbNewStyle{clist-base}{clist-db}{
+ before-code = {\dbIfEmptyF{\begin{enumerate}}},
+ after-code = {\dbIfEmptyF{\end{enumerate}}},
+ item-code = \item \dbuse{label},
+ }
+ \dbNewStyle[clist-base]{clist-style1}{clist-db}{
+ label/sep = {{,~}}
+ }
+ \dbNewStyle[clist-base]{clist-style2}{clist-db}{
+ label/sep = {{,~}, {,~}, ~and~}
+ }
+ \dbitemkv{clist-db}{label={a, b, c}}
+ \dbitemkv{clist-db}{label={1, 2, 3}}
+ \dbshow{clist-style1}{clist-db}
+ \dbshow{clist-style2}{clist-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% If the argument is a comma list of 4 items, it is used to set the separators
+% of the date. For attributes of type |date|, incorrect number (numbers
+% exclude 1 and 4) will raise an error. Example \ref{en-date-sep} shows how
+% to customize the date separators.
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(date-sep){Set Date Separators}
+ \dbNewDatabase{date-db}{date=date}
+ \dbNewStyle{date-style1}{date-db}{
+ item-code = \dbuse{date}\quad,
+ date/sep = -,
+ }
+ \dbNewStyle{date-style2}{date-db}{
+ item-code = \dbuse{date}\quad,
+ date/sep = {\$, +, !, \$},
+ }
+ \dbitemkv{date-db}{date=2020/01/02}
+ \dbitemkv{date-db}{date=2022/07/12}
+ \dbshow{date-style1}{date-db}
+ \dbshow{date-style2}{date-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-14}{Add option}{\opt{<attr>/format-code}}
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/format-code}
+% \begin{syntax}
+% \nopt{<attr>/format-code} = <format code> \inidef
+% \end{syntax}
+%
+% Use this option to get fine-grained control over date formatting. In
+% \meta{format code}, |#1| represents for the \meta{year}, |#2| represents for
+% the \meta{month} and |#3| represents for the \meta{day}. Example
+% \ref{en-date-code} shows how to format the date with this option.
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(date-code){Date Formatting}
+ \dbNewDatabase{date-db}{date=date}
+ \dbNewStyle{date-style}{date-db}{
+ item-code = \dbuse{date},
+ date/format-code = {日:#3\quad 月:#2\quad 年:#1}
+ }
+ \dbitemkv{date-db}{date=2022/01/01}
+ \dbshow{date-style}{date-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
+% \begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+% \begin{syntax}
+% \nopt{<attr>/zfill} = <\TTF> \inidef(true)[true]
+% \end{syntax}
+%
+% Only for attributes of type |date|. Control whether to fill zero on the left
+% of the month or day. Example \ref{en-date-zfill} shows the differences.
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(date-zfill){Control the Leading Zero of the Date}
+ \dbNewDatabase{date-db}{date=date}
+ \dbNewStyle {zfill-style}{date-db}{
+ item-code = \dbuse{date},
+ }
+ \dbNewStyle{nofill-style}{date-db}{
+ item-code = \dbuse{date},
+ date/zfill = false,
+ }
+ \dbitemkv{date-db}{date=2022/01/01}
+ \dbshow {zfill-style}{date-db}
+ \dbshow{nofill-style}{date-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbdatesep}}
+% \begin{function}[added=2022-01-13]{\dbdatesep}
+% \begin{syntax}
+% \cs{dbdatesep} \marg{separator}
+% \end{syntax}
+%
+% Set the separator for internal date parsing. The default value is |/|,
+% i.e. the date must be store in the format of |yyyy/mm/dd|. Example
+% \ref{en-inner-date-sep} shows how to store dates with two formats.
+% However, the separators are not really stored but used to parse the year,
+% month and day, which will be stored internally as three integers.
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(inner-date-sep){Set Date Parsing Format}
+ \dbNewDatabase{inner-date-db}{date=date}
+ \dbNewStyle{inner-date-style}{inner-date-db}{
+ item-code = \dbuse{date}\quad,
+ }
+ \dbitemkv{inner-date-db}{date=2020/01/20}
+ \dbdatesep{-}
+ \dbitemkv{inner-date-db}{date=2022-01-10}
+ \dbshow{inner-date-style}{inner-date-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \subsection{Data Filters}
+%
+% Filter is a combination of conditionals that is used to filter the data you
+% want to display.
%
% \begin{function}[added=2022-01-05]{\dbNewReviewPoints}
% \begin{syntax}
% \cs{dbNewReviewPoints} \marg{name} \marg{points}
% \end{syntax}
%
-% Define the new \meta{points} that is specially designed for reviewing
-% something. \meta{points} is a list of integers. Suppose you record the date
-% when you did not answer correctly and you plan to review every 2, 5 and 15
-% days. The following code give what you want.
+% Define \meta{points} to filter dates by intervals. something. \meta{points}
+% is a list of \meta{intexpr}. In example \ref{en-review-points}, a \meta{date
+% anchor} and a list of \meta{points} is defined. During the filtering process,
+% \meta{interval} is calculated by $\meta{interval} = \meta{date anchor} -
+% \meta{date cmp}$, \meta{date cmp} is the \meta{date} of current item. Then
+% each \meta{intexpr} in \meta{points} is compared with \meta{interval} to
+% test if they are equal.
% \end{function}
%
-% \begin{verbatim}
-% \dbNewReviewPoints{review-point}{2, 5, 15} % define points
-% \begin{dbFilters}
-% \dbNewConditional{cond1}{date}{review-point|\Today} % define conditional
-% \dbCombineConditionals{filter1}{cond1} % define filter
-% \end{dbFilters}
-% \dbNewStyle{review-style}{ques}{filter=filter1} % define style
-% \end{verbatim}
-%
-% \subsection{Define Filters inside \env{dbFilters} Environment}
+% \iffalse
+%<*verb>
+% \fi
+\DeleteShortVerb{\|}
+\dbdatesep{/}
+\begin{example*}(review-points){Filter with Review Points}
+ \dbNewDatabase{filter-db}{date=date}
+ \dbNewReviewPoints{review}{2, 5}
+ \dbNewRawFilter*{review-filter}{filter-db}{date}{review|2022/02/06}
+ \dbNewStyle{filter-style}{filter-db}{
+ item-code = \dbuse{date}\quad,
+ filter = review-filter,
+ }
+ \dbitemkv{filter-db}{date=2022/01/30}
+ \dbitemkv{filter-db}{date=2022/02/01}
+ \dbitemkv{filter-db}{date=2022/02/04}
+ \dbshow{filter-style}{filter-db}
+\end{example*}
+\MakeShortVerb{\|}
+% \iffalse
+%</verb>
+% \fi
%
-% \begin{environment}[added=2022-01-05]{dbFilters}
+% \changes{1.5}{2022-01-16}{Update env}{add starred version of \env{dbFilters}}
+% \begin{environment}[added=2022-01-05, updated=2022-01-16]{dbFilters}
% \begin{syntax}
-% |\begin{dbFilters}|\marg{database} \\
+% |\begin|\{\env{dbFilters}\} \marg{database} \\
+% ~~\meta{code}
+% |\end|\{\env{dbFilters}\} \\
+% |\begin|\{\env{dbFilters}\} * \marg{database} \\
% ~~\meta{code}
-% |\end{dbFilters}| \\
+% |\end|\{\env{dbFilters}\} \\
% \end{syntax}
%
% Filters are defined inside \env{dbFilters} environment, inside which,
% \cs{dbNewConditional} is defined to declare conditionals and
-% \cs{dbCombineConditionals} is defined to combine conditionals. Filters are
-% independent in different databases, which means the same name of filters is
-% allowed in different databases.
+% \cs{dbCombineConditionals} is defined to combine conditionals. Starred
+% version will define a filter of the same name of conditional as soon as you
+% define it. In example \ref{en-star-filter}, line 3 define the conditional
+% and the filter named |greater| so that you can use it in option \opt{option}.
+% Filters are independent in different databases, which means the same name of
+% filters is allowed in different databases.
% \end{environment}
%
-% \begin{function}[added=2022-01-05, updated=2022-01-08]{\dbNewConditional, \dbNewConditional*}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(star-filter){Define Conditional and Filter at Same Time}
+ \dbNewDatabase{filter-db}{count=int}
+ \begin{dbFilters}*{filter-db}
+ \dbNewCond{greater}{count}{\dbval > 3}
+ \end{dbFilters}
+ \dbNewStyle{filter-style}{filter-db}{
+ filter = greater,
+ item-code = \dbuse{count}\quad,
+ }
+ \dbitemkv{filter-db}{count=2}
+ \dbitemkv{filter-db}{count=5}
+ \dbshow{filter-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-15}{Add macros}{\cs{dbNewCond}, \cs{dbCombCond}}
+% \begin{function}[added=2022-01-05, updated=2022-01-16]{\dbNewConditional,
+% \dbNewCond, \dbNewConditional*, \dbNewCond*}
% \begin{syntax}
-% \cs{dbNewConditional} \marg{name} \marg{attr} \marg{cond spec} \\
-% \cs{dbNewConditional}* \marg{name} \marg{attr} \marg{cond spec} \\[2pt]
-% \cs{dbNewConditional} \marg{name} \marg{int/fp attr} \marg{expr} \\
-% \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr} \\
-% \cs{dbNewConditional} \marg{name} \marg{str/tl attr} \marg{regex expr} \\
-% \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \\
-% \cs{dbNewConditional} \marg{name} \marg{clist attr} \marg{val list} \\
-% \cs{dbNewConditional}* \marg{name} \marg{clist attr} \marg{val list} \\
-% \cs{dbNewConditional} \marg{name} \marg{date attr} \marg{expr}
-% \cs{dbNewConditional}* \marg{name} \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \\
+% \cs{dbNewConditional} \marg{name} \marg{attr} \marg{cond spec} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{attr} \marg{cond spec} \oarg{filter info} \\[2pt]
+% \cs{dbNewConditional} \marg{name} \marg{int/fp attr} \marg{expr} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr} \oarg{filter info}
+% \cs{dbNewConditional} \marg{name} \marg{str/tl attr} \marg{regex expr} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \oarg{filter info}
+% \cs{dbNewConditional} \marg{name} \marg{clist attr} \marg{val list} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{clist attr} \marg{val list} \oarg{filter info}
+% \cs{dbNewConditional} \marg{name} \marg{date attr} \marg{date expr} \oarg{filter info}
+% \cs{dbNewConditional}* \marg{name} \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \oarg{filter info}
% \end{syntax}
%
% Define the conditional named \meta{name} that binds to \meta{attr}. \cs{dbval}
@@ -1557,53 +2693,176 @@ Copyright and License
% \end{note}
%
% For attribute of type |str| and |tl|, unstarred form matches any part while
-% starred form matches the whole part with the \meta{regex expr}.
+% starred form matches the whole part with the \meta{regex expr}, which is
+% shown in example \ref{en-filter-str}: filter |part| match |name|s that
+% contain numbers and filter |all| match |name|s that is composed of digits.
%
-% \begin{verbatim}
-% \dbNewConditional {cond1}{str-attr}{abc} % match abc, abcd, 1abc, =abc=, etc
-% \dbNewConditional*{cond2}{str-attr}{abc} % only match abc
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(filter-str){Match Strings}
+ \dbNewDatabase{filter-db}{name=str}
+ \begin{dbFilters}*{filter-db}
+ \dbNewCond{part}{name}{\d+}
+ \dbNewCond*{all}{name}{\d+}
+ \end{dbFilters}
+ \dbNewStyle{part-style}{filter-db}{
+ before-code = Match part:~,
+ item-code = \dbuse{name}\quad,
+ filter = part,
+ }
+ \dbNewStyle{all-style}{filter-db}{
+ before-code = Match all:~,
+ item-code = \dbuse{name}\quad,
+ filter = all,
+ }
+ \dbitemkv{filter-db}{name=123}
+ \dbitemkv{filter-db}{name=int12}
+ \dbitemkv{filter-db}{name=variable}
+ \dbshow{part-style}{filter-db}
+ \dbshow {all-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
%
% For attributes of type |clist|, the conditional defined by unstarred form is
% true if any item of \meta{val list} is in the comma list. While the
% conditional defined by starred form is true only if every item of \meta{val
-% list} is in the comma list. As is showed below, for |cond1|, |a| is in
-% |{a, b, d}| so |cond1| is true. While |c| is not in |{a, b, d}| so |cond2|
-% is false.
+% list} is in the comma list. In example \ref{en-filter-clist}, filter |or|
+% match labels that contain hard \textbf{or} red, and filter |and| match
+% labels that contain hard \textbf{and} red.
%
-% \begin{verbatim}
-% \dbNewConditional {cond1}{clist-attr}{a, b, c} % {a, b, d} -> true
-% \dbNewConditional*{cond2}{clist-attr}{a, b, c} % {a, b, d} -> false
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(filter-clist){Filter Lists}
+ \dbNewDatabase{filter-db}{label=clist}
+ \begin{dbFilters}*{filter-db}
+ \dbNewCond {or}{label}{hard, red}
+ \dbNewCond*{and}{label}{hard, red}
+ \end{dbFilters}
+ \def\emph#1{\textit{\textbf{#1}}}
+ \dbNewStyle{base-style}{filter-db}{
+ before-code = {
+ \begin{minipage}[t]{.3\textwidth}
+ All items
+ },
+ after-code = {\end{minipage}},
+ item-code = \par\dbarabic.~\dbuse{label},
+ }
+ \dbNewStyle[base-style] {or-style}{filter-db}{
+ before-code = {
+ \begin{minipage}[t]{.3\textwidth}
+ Match \emph{any} of hard \emph{or} red
+ },
+ filter = or,
+ }
+ \dbNewStyle[base-style]{and-style}{filter-db}{
+ before-code = {
+ \begin{minipage}[t]{.3\textwidth}
+ Match \emph{all} of hard \emph{and} red
+ },
+ filter = and,
+ }
+ \dbitemkv{filter-db}{label={hard, red}}
+ \dbitemkv{filter-db}{label={hard, blue}}
+ \dbitemkv{filter-db}{label={easy, blue}}
+ \dbitemkv{filter-db}{label={easy, red}}
+ \dbitemkv{filter-db}{label={hard, red, flat}}
+ \dbshow {base-style}{filter-db}
+ \dbshow {or-style}{filter-db}
+ \dbshow {and-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
%
% \changes{1.3}{2022-01-08}{Update logic}{swap definition of starred and
% unstarred conditionals of date}
% For attributes of type |date|, unstarred form replace each date with a
-% integer representing for the days between \meta{date} and
-% \textit{1971/01/01}, and the result is passed to \cs{int_compare:nTF}.
+% integer representing for the days between \meta{date} and 1971/01/01, and
+% the result is passed to \cs{int_compare:nTF}. Example \ref{en-filter-date}
+% shows how to use the \meta{date expr} to filter the data.
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(filter-date){Filter with Date Expression}
+ \dbNewDatabase{filter-db}{date=date}
+ \dbNewRawFilter{date-filter}{filter-db}{date}{\dbval >= 2022/02/01}
+ \dbNewStyle{filter-style}{filter-db}{
+ item-code = \dbuse{date}\quad,
+ filter = date-filter,
+ }
+ \dbitemkv{filter-db}{date=2022/01/30}
+ \dbitemkv{filter-db}{date=2022/02/01}
+ \dbitemkv{filter-db}{date=2022/02/04}
+ \dbshow{filter-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
% Starred form defines the conditional with review points defined by
-% \cs{dbNewRdbNewReviewPoints} and \meta{date} is the date to be compared.
+% \cs{dbNewReviewPoints} and \meta{date} is the date to be compared (see
+% example \ref{en-review-points}).
+%
+% \changes{1.5}{2022-01-16}{Add macro}{\cs{dbNewRawFilter}}
+% \begin{function}[added=2022-01-16]{\dbNewRawFilter}
+% \begin{syntax}
+% \cs{dbNewRawFilter} \marg{name} \marg{database} \marg{attr} \marg{cond spec} \oarg{filter info}
+% \cs{dbNewRawFilter}* \marg{name} \marg{database} \marg{attr} \marg{cond spec} \oarg{filter info}
+% \textnormal{\textit{Equal to}}
+% |\begin|\{\env{dbFilters}\}*\phantom{\marg{name}}\marg{database}
+% ~~\cs{dbNewCond} \marg{name} \phantom{\marg{database}} \marg{attr} \marg{cond spec} \oarg{filter info}
+% ~~\cs{dbNewCond}* \marg{name} \phantom{\marg{database}} \marg{attr} \marg{cond spec} \oarg{filter info}
+% |\end|\{\env{dbFilters}\}
+% \end{syntax}
+%
+% Use this command to quickly define a \meta{filter} that has the same name
+% with the \meta{conditional}. Example \ref{en-new-raw-filter} is actually the
+% same with example \ref{en-star-filter}, but it is more concise.
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(new-raw-filter){Define Conditional and Filter at Same Time}
+ \dbNewDatabase{filter-db}{count=int}
+ \dbNewRawFilter{greater}{filter-db}{count}{\dbval > 3}
+ \dbNewStyle{filter-style}{filter-db}{
+ filter = greater,
+ item-code = \dbuse{count}\quad,
+ }
+ \dbitemkv{filter-db}{count=2}
+ \dbitemkv{filter-db}{count=5}
+ \dbshow{filter-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
%
% \begin{function}[added=2022-01-05]{\dbCombineConditionals}
% \begin{syntax}
% \cs{dbCombineConditionals} \marg{name} \marg{cond combination} \oarg{info}
% \end{syntax}
%
-% Define the filter \meta{name}, which combine the conditionals and store the
-% extra \meta{info} into \cs{dbFilterInfo}. So you can write something as\\
-% \verb=\dbCombineConditionals{filter}{(cond1 && cond2) || !cond3}=.\\
-% Supported operators are \verb=&&, ||, !=. You can set the option \opt{filter}
-% to \meta{name} to apply the filter when you display the database.
+% Define the filter \meta{name}, which combine the conditionals and store
+% the extra \meta{info} into \cs{dbFilterInfo}. Supported operators are
+% \verb=&&, ||, !=. You can set the option \opt{filter} to \meta{name} to
+% apply the filter when you display the database. See example
+% \ref{en-filter}.
% \end{function}
%
-% \subsection{Store Data with \env{dbitem} Environment}
+% \subsection{Store and Use Data}
%
% \changes{1.4}{2022-01-13}{Update env}{dbitem}
% \begin{environment}[added=2022-01-05, updated=2022-01-13]{dbitem}
% \begin{syntax}
-% |\begin{dbitem}| \marg{database} \oarg{attr-val list}
+% |\begin|\marg{\env{dbitem}} \marg{database} \oarg{attr-val list}
% ~~\meta{code} \\
-% |\end{dbitem}|
+% |\end|\marg{\env{dbitem}}
% \end{syntax}
%
% The data are stored with \env{dbitem} environment in two ways. Short data
@@ -1612,15 +2871,37 @@ Copyright and License
% \meta{attr} = \meta{val} is equal to \cs{dbsave}\marg{attr}\marg{val}, and
% \meta{attr} = \meta{val} is equal to \cs{dbsave*}\marg{attr}\marg{val},
% in which case, data will not be expanded in an |e| or |x|-type argument.
-% An example code is showned below.
+% Example \ref{en-dbitem} shows how to store data with \env{dbitem}.
% \end{environment}
%
-% \begin{verbatim}
-% \begin{dbitem}[date=2022-01-01, info=test]
-% \dbsave{question}{This is a test question.}
-% \dbsave{answer} {This is a test answer.}
-% \end{dbitem}
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(dbitem){Store Date}
+ \dbNewDatabase{ques-db}{date=date, ques=tl, ans=tl}
+ \dbNewStyle{ques-style}{ques-db}{
+ item-code = {%
+ \par\dbuse{date}
+ \par\dbarabic.~\dbuse{ques}
+ \par\textbf{Answer:}~\dbuse{ans}
+ },
+ item-after-code = \medskip,
+ }
+ \begin{dbitem}{ques-db}[date=2022/01/01]
+ \dbsave{ques}{Distance from earth to moon?}
+ \dbsave{ans} {384,401 kilometers.}
+ \end{dbitem}
+ \begin{dbitem}{ques-db}[date=2022/01/02]
+ \dbsave{ques}{The number of English letters?}
+ \dbsave{ans} {26.}
+ \end{dbitem}
+ \dbshow{ques-style}{ques-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
%
% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbitemkv}}
% \begin{function}[added=2022-01-13]{\dbitemkv}
@@ -1653,7 +2934,8 @@ Copyright and License
% \end{syntax}
%
% Display the value of \meta{attr} of current record. \cs{dbuse} is
-% \textbf{expandable} and can be only used inside the option \opt{item-code}.
+% \textbf{expandable} and can be only used inside the option \opt{item-code},
+% \opt{item-before-code}, \opt{item-after-code}.
% \end{function}
%
% \subsection{Conditionals}
@@ -1661,21 +2943,71 @@ Copyright and License
% \begin{function}[added=2022-01-05, EXP]{\dbIfEmptyT, \dbIfEmptyF, \dbIfEmptyTF}
% \begin{syntax}
% \cs{dbIfEmptyTF} \marg{true code} \marg{false code} \\
-% \cs{dbIfEmptyT} \marg{true code} \\
+% \cs{dbIfEmptyT} \marg{true code} \\
% \cs{dbIfEmptyF} \marg{false code}
% \end{syntax}
%
-% Test if the database is empty. The example below shows how to avoid an empty
-% list environment.
+% Test if the database is empty. Example \ref{en-empty-db} shows how to
+% avoid an empty list environment.
% \end{function}
%
-% \begin{verbatim}
-% \dbNewStyle{style-cond1}{database-test}{
-% before-code = {\dbIfEmptyF{\begin{enumerate}}},
-% after-code = {\dbIfEmptyF{\end{enumerate}}},
-% item-code = {\item \dbuse{attr-test}}
-% }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(empty-db){Avoid Empty List Environment}
+ \dbNewDatabase{test-db}{text=tl}
+ \dbNewRawFilter{alph}{test-db}{text}{\d}
+ \dbNewStyle{base-style}{test-db}{
+ before-code = \dbIfEmptyTF{Empty db}{\begin{enumerate}},
+ after-code = \dbIfEmptyF{\end{enumerate}}\medskip,
+ item-code = \item \dbuse{text},
+ }
+ \dbNewStyle[base-style]{empty-style}{test-db}{
+ raw-filter=!alph
+ }
+ \dbitemkv{test-db}{text={$1 + 1 = 2$.}}
+ \dbitemkv{test-db}{text={I have 2 pens.}}
+ \dbshow {base-style}{test-db}
+ \dbshow{empty-style}{test-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-17}{Add macros}{\cs{dbIfLastT}, \cs{dbIfLastF},
+% \cs{dbIfLastTF}}
+% \begin{function}[added=2022-01-17, EXP]{\dbIfLastT, \dbIfLastF, \dbIfLastTF}
+% \begin{syntax}
+% \cs{dbIfLastTF} \marg{true code} \marg{false code}
+% \cs{dbIfLastT} \marg{true code}
+% \cs{dbIfLastF} \marg{false code}
+% \end{syntax}
+%
+% Test if the current item is the last item to display. Example \ref{en-last}
+% shows how to set the separator between items.
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(last){Separator between Items}
+ \dbNewDatabase{last-db}{text=tl}
+ \dbNewStyle{last-style}{last-db}{
+ item-code = {%
+ \par\dbuse{text}\par%
+ \dbIfLastF{\textcolor{red}{\hrulefill separator\hrulefill}}%
+ },
+ }
+ \dbitemkv{last-db}{text=This is the first paragraph.}
+ \dbitemkv{last-db}{text=This is the second paragraph.}
+ \dbitemkv{last-db}{text=This is the last paragraph.}
+ \dbshow{last-style}{last-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
%
% \changes{1.2}{2022-01-08}{Remove macros}{\cs{dbItemIfEmpty(TF)}, \cs{dbClistItemIfEmpty(TF)}}
%
@@ -1687,26 +3019,50 @@ Copyright and License
% \dbIntMin, \dbIntMod, \dbFpSign,
% }
% \begin{syntax}
-% \cs{dbIntAbs} \Arg{intexpr}
-% \cs{dbIntSign} \Arg{intexpr}
-% \cs{dbIntDivRound} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbIntDivTruncate} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbIntMax} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbIntMin} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbIntMod} \Arg{intexpr_1} \marg{intexpr_2}
-% \cs{dbFpSign} \Arg{fpexpr}
-% \end{syntax}
-% \cs{dbIntAbs} is identical to \cs{int_abs:n} \\
-% \cs{dbIntSign} is identical to \cs{int_sign:n} \\
-% \cs{dbIntDivRound} is identical to \cs{int_div_round:nn} \\
-% \cs{dbIntDivTruncate} is identical to \cs{int_div_truncate:nn} \\
-% \cs{dbIntMax} is identical to \cs{int_max:nn} \\
-% \cs{dbIntMin} is identical to \cs{int_min:nn} \\
-% \cs{dbIntMod} is identical to \cs{int_mod:nn} \\
-% \cs{dbFpSign} is identical to \cs{fp_sign:n} \\
-% Detailed documentation see \pkg{interface3} \\
+% \cs{dbIntAbs} \Arg{intexpr}
+% \cs{dbIntSign} \Arg{intexpr}
+% \cs{dbIntDivRound} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbIntDivTruncate} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbIntMax} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbIntMin} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbIntMod} \Arg{intexpr_1} \Arg{intexpr_2}
+% \cs{dbFpSign} \Arg{fpexpr}
+% \end{syntax}
+% \begin{tblr}{ll}
+% \cs{dbIntAbs} & is equal to \cs{int_abs:n} \\
+% \cs{dbIntSign} & is equal to \cs{int_sign:n} \\
+% \cs{dbIntDivRound} & is equal to \cs{int_div_round:nn} \\
+% \cs{dbIntDivTruncate} & is equal to \cs{int_div_truncate:nn} \\
+% \cs{dbIntMax} & is equal to \cs{int_max:nn} \\
+% \cs{dbIntMin} & is equal to \cs{int_min:nn} \\
+% \cs{dbIntMod} & is equal to \cs{int_mod:nn} \\
+% \cs{dbFpSign} & is equal to \cs{fp_sign:n} \\
+% \end{tblr}
+%
+% See detailed documentation of \pkg{interface3}. Example \ref{en-expr-db}
+% shows how to filter multiples of 3.
% \end{function}
%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(expr-db){Filter Multiples of 3}
+ \dbNewDatabase{expr-db}{n=int}
+ \dbNewRawFilter{mod}{expr-db}{n}{\dbIntMod{\dbval}{3} = 0}
+ \dbNewStyle{expr-style}{expr-db}{
+ item-code = \dbuse{n}\quad,
+ filter = mod,
+ }
+ \dbitemkv{expr-db}{n=2}
+ \dbitemkv{expr-db}{n=3}
+ \dbitemkv{expr-db}{n=6}
+ \dbitemkv{expr-db}{n=7}
+ \dbshow{expr-style}{expr-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
% \subsection{Special Macros}
%
% Some special macros are defined to expand to different contents according to context.
@@ -1721,208 +3077,60 @@ Copyright and License
% \dbIndex, \dbarabic, \dbalph, \dbAlph, \dbroman, \dbRoman
% }
% \begin{tblr}{ll}
-% \cs{dbval} & Attribute value, only according in \cs{dbNewConditional}. \\
-% \cs{dbDatabase} & Database name. \\
+% \cs{dbval} & Attribute value, only accessible in \cs{dbNewConditional}. \\
+% \cs{dbtoday} & Date of today. \\
+% \cs{dbDatabase} & Database name. \\
% \cs{dbFilterName} & Filter name. \\
% \cs{dbFilterInfo} & Filter information. \\
-% \cs{dbIndex} & Record index, identical to \cs{dbuse}|{id}| \\
-% \cs{dbarabic} & Show the counter of query set as digits. \\
-% \cs{dbalph} & Show the counter of query set as lowercase letters. \\
-% \cs{dbAlph} & Show the counter of query set as uppercase letters. \\
-% \cs{dbroman} & Show the counter of query set as lowercase roman numerals. \\
-% \cs{dbroman} & Show the counter of query set as uppercase roman numerals. \\
-% \end{tblr}
+% \cs{dbIndex} & Record index, identical to \cs{dbuse}\marg{id} \\
+% \cs{dbarabic} & Show the counter of query set as digits. \\
+% \cs{dbalph} & Show the counter of query set as lowercase letters. \\
+% \cs{dbAlph} & Show the counter of query set as uppercase letters. \\
+% \cs{dbroman} & Show the counter of query set as lowercase roman numerals. \\
+% \cs{dbroman} & Show the counter of query set as uppercase roman numerals. \\
+% \end{tblr}
+%
+% \cs{dbtoday} show the current date with the separator defined by
+% \cs{dbdatesep}. See example~\ref{en-special-cs}.
% \end{function}
%
-% \section{Example of Flaw Sweeper Template}
-% \label{sec:example}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(special-cs){Special Commands}
+ \dbNewDatabase{special-db}{name=str}
+ \dbNewRawFilter*{number}{special-db}{name}{\d+}[name that is a number]
+ \dbNewStyle{special-style}{special-db}{
+ before-code = {
+ Date: \dbtoday \\
+ Database: \dbDatabase
+ Filter: \dbFilterName \\
+ Filter info: \dbFilterInfo \par
+ \begin{tabular}{@{}lllllll}
+ Index & arabic & alph & Alph & roman & Roman & value \\
+ },
+ after-code = \end{tabular},
+ item-code* = {%
+ \dbIndex & \dbarabic & \dbalph & \dbAlph &
+ \dbroman & \dbRoman & \dbuse{name} \\
+ },
+ sort = name,
+ filter = number,
+ }
+ \dbitemkv{special-db}{name=test}
+ \dbitemkv{special-db}{name=12}
+ \dbitemkv{special-db}{name=int2}
+ \dbitemkv{special-db}{name=99}
+ \dbshow{special-style}{special-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
%
% \changes{1.1}{2022-01-07}{Update doc}{improve example}
-%
-% \begin{verbatim}
-% \documentclass{article}
-% \usepackage{amsmath, physics}
-% \usepackage{geometry}
-% \usepackage{dbshow}
-% \usepackage{tikz}
-% \usepackage{tcolorbox}
-% \tcbuselibrary{skins}
-% \usetikzlibrary{shadings}
-% \usepackage[hidelinks]{hyperref}
-%
-% \geometry{
-% margin=2cm
-% }
-%
-% % #1 link node #2 target node #3 text to show
-% \NewDocumentCommand \linktarget { m m m } {%
-% \hyperlink{#1}{#3}%
-% \raisebox{1em}{\hypertarget{#2}{}}%
-% }
-%
-% % question box
-% \tcbset{
-% base/.style={
-% empty,
-% frame engine=path,
-% colframe=yellow!10,
-% coltitle=red!70,
-% fonttitle=\bfseries\sffamily,
-% sharp corners,
-% left=4pt,
-% right=4pt,
-% drop fuzzy shadow,
-% drop fuzzy shadow,
-% borderline west={3pt}{-3pt}{red!80},
-% }
-% }
-%
-% \newtcolorbox{mybox}[1]{%
-% base, title = {#1}
-% }
-%
-% \dbNewReviewPoints{review}{1, 3, 7, 15, 30, 60}
-%
-% \dbNewDatabase{ques-book}{
-% ques = tl,
-% answer = tl,
-% count = int|1,
-% labels = clist,
-% date = date,
-% }
-%
-% \begin{dbFilters}{ques-book}
-% \dbNewConditional{hard}{labels}{hard}
-% \dbNewConditional{bad}{count}{\dbval > 1}
-% \dbNewConditional*{review}{date}{review|2022/01/07}
-% \dbNewConditional{after}{date}{\dbval > 2022/01/02}
-% \end{dbFilters}
-%
-% % show all questions with hyperlink to answers
-% \dbNewStyle{ques}{ques-book}{
-% before-code = {\section{Questions}},
-% item-code = {
-% \begin{mybox}{%
-% \linktarget{answer_\dbIndex}{ques_\dbIndex}{%
-% Question \dbarabic%
-% \hspace{2em}\dbuse{date}%
-% \hspace{2em}\dbuse{labels}%
-% \hfill\dbuse{count}%
-% }%
-% }
-% \dbuse{ques}%
-% \end{mybox}
-% },
-% labels/sep = /,
-% }
-%
-% % show all questions and answers with hyperlink to questions
-% \dbNewStyle{answer}{ques-book}{
-% before-code = {\section{Questions and Answers}},
-% item-code = {
-% \begin{mybox}{%
-% \linktarget{ques_\dbIndex}{answer_\dbIndex}{%
-% Question \dbarabic%
-% \hspace{2em}\dbuse{date}%
-% \hspace{2em}\dbuse{labels}%
-% \hfill\dbuse{count}%
-% }%
-% }
-% \dbuse{ques}\tcbsubtitle{Answer}\dbuse{answer}%
-% \end{mybox}
-% },
-% labels/sep = /,
-% }
-%
-% % show all hard questions with hyperlink to answers
-% \dbNewStyle{hard}{ques-book}{
-% before-code = {\section{Hard Questions}},
-% item-code = {
-% \begin{mybox}{%
-% \hyperlink{answer_\dbIndex}{%
-% Question \dbarabic%
-% \hspace{2em}\dbuse{date}%
-% \hspace{2em}\dbuse{labels}%
-% \hfill\dbuse{count}%
-% }%
-% }
-% \dbuse{ques}%
-% \end{mybox}
-% },
-% raw-filter = hard,
-% labels/sep = /,
-% }
-%
-% % show all hard questions that have been answered incorrectly for more than
-% % one time with hyperlink to answers
-% \dbNewStyle[hard]{bad}{ques-book}{
-% before-code = {\section{Bad Questions}},
-% raw-filter = {bad && hard},
-% }
-% % show all questions that plan to be reviewed on 2022/01/07 with hyperlink to
-% % answers
-% \dbNewStyle[hard]{review}{ques-book}{
-% before-code = {\section{Questions to be Reviewed}},
-% raw-filter = {review},
-% }
-% % show all questions that is record after 2022/01/02 with hyperlink to answers
-% \dbNewStyle[hard]{after}{ques-book}{
-% before-code = {\section{Questions after 2022/01/02}},
-% raw-filter = {after},
-% }
-%
-% \AtEndDocument{
-% \dbshow{review}{ques-book}
-% \dbshow{hard}{ques-book}
-% \dbshow{bad}{ques-book}
-% \dbshow{after}{ques-book}
-% \dbshow{ques}{ques-book}
-% \dbshow{answer}{ques-book}
-% }
-%
-% \begin{document}
-%
-% \begin{dbitem}{ques-book}[
-% date=2022/01/01,
-% labels={math, equation, easy},
-% count=2
-% ]
-% \dbsave{ques}{%
-% Solve the linear equation: $x + 16 = 31$.
-% }
-% \dbsave{answer}{%
-% $x = 31 - 16 = 15$
-% }
-% \end{dbitem}
-%
-% \begin{dbitem}{ques-book}[
-% date=2022/01/01,
-% labels={math, equation, hard},
-% count=3
-% ]
-% \dbsave{ques}{%
-% Solve the linear equation: $2y = 16$.
-% }
-% \dbsave{answer}{%
-% $y = 16 / 2 = 8$
-% }
-% \end{dbitem}
-%
-% \begin{dbitem}{ques-book}[
-% date=2022/01/04,
-% labels={math, integral, hard},
-% count=1
-% ]
-% \dbsave{ques}{%
-% Find the indefinite integral: $\int 2x \dd x$.
-% }
-% \dbsave{answer}{%
-% $\int 2x \dd x = x^2$
-% }
-% \end{dbitem}
-%
-% \end{document}
-% \end{verbatim}
+% \changes{1.5}{2022-01-17}{Remove doc}{Remove big example}
%
% \end{documentation}
%
@@ -1962,6 +3170,7 @@ Copyright and License
% \begin{macrocode}
\cs_generate_variant:Nn \msg_warning:nnnn { nnnx }
\cs_generate_variant:Nn \keys_set:nn { nv }
+\cs_generate_variant:Nn \tl_put_right:Nn { Nv }
\cs_generate_variant:Nn \clist_use:nn { xx }
\cs_generate_variant:Nn \clist_use:nnnn { xxxx }
\cs_generate_variant:Nn \clist_map_inline:nn { Vn }
@@ -2014,6 +3223,8 @@ Copyright and License
}
% \end{macrocode}
%
+% \changes{1.5}{2022-01-15}{Update check code}{transform arguments to string
+% before check}
% \begin{macro}{\@@_check_database:n}
% Check if the database is valid.
% \begin{arguments}
@@ -2021,7 +3232,7 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\cs_new:Nn \@@_check_database:n {
- \prop_if_exist:cF { g_@@_attr_type_prop_#1 }
+ \prop_if_exist:cF { g_@@_attr_type_prop_\tl_to_str:n {#1} }
{ \msg_fatal:nnn { dbshow } { non-existent-database } {#1} }
}
% \end{macrocode}
@@ -2045,7 +3256,7 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\cs_new:Nn \@@_check_attr:nn {
- \prop_if_in:cnF { g_@@_attr_type_prop_#1 } {#2}
+ \prop_if_in:cnF { g_@@_attr_type_prop_\tl_to_str:n {#1} } {#2}
{ \msg_fatal:nnnn { dbshow } { non-existent-attr } {#1} {#2} }
}
\cs_generate_variant:Nn \@@_check_attr:nn { nV }
@@ -2070,8 +3281,8 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\cs_new:Nn \@@_check_style:nn {
- \tl_if_exist:cF { g_@@_style_opts_tl_#1_#2 }
- { \msg_warning:nnnn { dbshow } { non-existent-style } {#1} {#2} }
+ \tl_if_exist:cF { g_@@_style_opts_tl_\tl_to_str:n {#1}_\tl_to_str:n {#2} }
+ { \msg_fatal:nnnn { dbshow } { non-existent-style } {#1} {#2} }
}
% \end{macrocode}
% \end{macro}
@@ -2094,7 +3305,7 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\cs_new:Nn \@@_check_cond:nnn {
- \tl_if_exist:cF { g_@@_filter_attr_#1_#2 }
+ \tl_if_exist:cF { g_@@_filter_attr_\tl_to_str:n {#1}_\tl_to_str:n {#2} }
{ \msg_fatal:nnnn { dbshow } { non-existent-cond } {#1} {#2} }
}
% \end{macrocode}
@@ -2118,7 +3329,8 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\cs_new:Nn \@@_check_filter:nn {
- \seq_if_exist:cF { g_@@_filter_run_seq_#1_#2 } {
+ \seq_if_exist:cF
+ { g_@@_filter_run_seq_\tl_to_str:n {#1}_\tl_to_str:n {#2} } {
\str_if_eq:eeF {#2} { -none- } {
\msg_warning:nnnx { dbshow } { non-existent-filter } {#1} {#2}
}
@@ -2163,7 +3375,7 @@ Copyright and License
}
% \end{macrocode}
%
-% \begin{macro}{\@@_sep_error:nnn, \@@_sep_error:xxx}
+% \begin{macro}{\@@_sep_fatal:nnn, \@@_sep_fatal:xxx}
% Check the value of \opt{<attr>/sep} is valid.
% \begin{arguments}
% \item \meta{valid count}
@@ -2171,10 +3383,10 @@ Copyright and License
% \item \meta{value}
% \end{arguments}
% \begin{macrocode}
-\cs_new:Nn \@@_sep_error:nnn {
- \msg_error:nnnnn { dbshow } { wrong-seperator } {#1} {#2} {#3}
+\cs_new:Nn \@@_sep_fatal:nnn {
+ \msg_fatal:nnnnn { dbshow } { wrong-seperator } {#1} {#2} {#3}
}
-\cs_generate_variant:Nn \@@_sep_error:nnn { xxx }
+\cs_generate_variant:Nn \@@_sep_fatal:nnn { xxx }
% \end{macrocode}
% \end{macro}
%
@@ -2190,9 +3402,11 @@ Copyright and License
%
% \subsection{Create Database}
%
+% \changes{1.5}{2022-01-15}{Fix bug}{can not use \cs{dbdatesep} midway}
% \begin{macro}{\@@_process_default_value:w}
% Create map from \meta{attr} to \meta{type} and map from \meta{attr} to
-% \meta{default value}.
+% \meta{default value}. Note that only one expansion is needed to get the
+% correct default value from \cs{l_@@_tmp_default}.
% \begin{arguments}
% \item \meta{database}
% \item \meta{attr}
@@ -2204,7 +3418,7 @@ Copyright and License
#1\@@_sep#2\@@_sep#3|#4\@@_stop {
\@@_check_type:n {#3}
\prop_gput:cxx { g_@@_attr_type_prop_#1 } {#2} {#3}
- \prop_gput:cxx { g_@@_default_map_#1 } {#2} {#4}
+ \prop_gput:cno { g_@@_default_map_#1 } {#2} {#4}
}
% \end{macrocode}
% \end{macro}
@@ -2617,7 +3831,7 @@ Copyright and License
% \begin{macro}{\@@_filter_tl:NNNnn, \@@_filter_tl:cccnn}
% Filter token list with regex expression. It is the same with string.
% \begin{macrocode}
-\cs_set_eq:NN \@@_filter_tl:NNNnn \@@_filter_str:NNNnn
+\cs_gset_eq:NN \@@_filter_tl:NNNnn \@@_filter_str:NNNnn
\cs_generate_variant:Nn \@@_filter_tl:NNNnn { cccnn }
% \end{macrocode}
% \end{macro}
@@ -2662,8 +3876,11 @@ Copyright and License
\__dbdate_set:xx { tmp_day1 } { \l_@@_filter_tmp_tl }
\__dbdate_set:xx { tmp_day2 } {#3}
\__dbdate_sub:nnN { tmp_day1 } { tmp_day2 } \l_@@_filter_diff_int
- \clist_if_in:NxTF \l_@@_filter_tmp_clist
- { \int_use:N \l_@@_filter_diff_int } {#4} {#5}
+ #5
+ \clist_map_inline:Nn \l_@@_filter_tmp_clist {
+ \int_compare:nNnT { \l_@@_filter_diff_int } = {##1}
+ { #4 \clist_map_break: }
+ }
} {
% \end{macrocode}
% For unstarred \meta{conditional} which parses \meta{expr}. We first replace
@@ -2711,11 +3928,12 @@ Copyright and License
% \item \meta{index}
% \end{arguments}
% \begin{macrocode}
-\cs_set:Nn \@@_filter:nnn {
+\cs_new_protected:Nn \@@_filter:nnn {
\tl_set_eq:Nc \l_@@_attr_tl { g_@@_filter_attr_tl_#1_#2 }
\cs_set_eq:Nc \dbval { g_@@_data_#1_\l_@@_attr_tl _#3 }
+ \tl_set:Nx \l_@@_type_tl { \@@_get_type:nV {#1} \l_@@_attr_tl }
\use:c
- { @@_filter_\@@_get_type:nV {#1} \l_@@_attr_tl :cccnn }
+ { @@_filter_\l_@@_type_tl :cccnn }
{ g_@@_cond_star_bool_#1_#2 }
{ g_@@_filter_expr_tl_#1_#2 }
{ dbval }
@@ -2739,6 +3957,8 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\cs_new_protected:Nn \@@_new_conditional:nnnnn {
+ \@@_check_database:n {#1}
+ \@@_check_attr:nn {#1} {#3}
\tl_gset:cn { g_@@_filter_attr_tl_#1_#2 } {#3}
\tl_gset:cn { g_@@_filter_expr_tl_#1_#2 } {#4}
\bool_if_exist:cF { g_@@_filter_bool_#1_#2 }
@@ -2757,7 +3977,10 @@ Copyright and License
\cs_gset:cn { g_@@_filter_hook_#1_#2:n } {
\@@_filter:nnn {#1} {#2} {##1}
}
- \seq_gput_right:cn { g_@@_cond_seq_#1 } {#2}
+ \bool_if_exist:cF { g_@@_cond_exist_bool_#1_#2 }
+ { \bool_set_false:c { g_@@_cond_exist_bool_#1_#2 } }
+ \bool_if:cF { g_@@_cond_exist_bool_#1_#2 }
+ { \seq_gput_right:cn { g_@@_cond_seq_#1 } {#2} }
}
% \end{macrocode}
% \end{macro}
@@ -2778,7 +4001,7 @@ Copyright and License
\cs_new_protected:Nn \@@_combine_conditional:nnn {
\tl_gset_eq:cN { g_@@_filter_bool_tl_#1_#2 } \c_true_bool
\seq_gclear_new:c { g_@@_filter_run_seq_#1_#2 }
- \regex_extract_all:nnN { \w+ } {#3} \l_@@_cond_seq
+ \regex_extract_all:nnN { [^!=&<>()\ ]+ } {#3} \l_@@_cond_seq
% \end{macrocode}
% \begin{arguments}[2]
% \item \meta{conditional}
@@ -2786,13 +4009,18 @@ Copyright and License
% \begin{macrocode}
\seq_map_inline:Nn \l_@@_cond_seq {
\seq_if_in:cnT { g_@@_cond_seq_#1 } {##1} {
- \seq_gput_right:cn { g_@@_filter_run_seq_#1_#2 }
+ \seq_if_in:cnF { g_@@_filter_run_seq_#1_#2 }
{ g_@@_filter_hook_#1_##1:n }
+ {
+ \seq_gput_right:cn { g_@@_filter_run_seq_#1_#2 }
+ { g_@@_filter_hook_#1_##1:n }
+ }
}
}
\tl_set:Nn \l_@@_cond_expr_tl {#3}
\regex_replace_all:nnN
- { \w+ } { \c{ g_@@_filter_bool_#1_\0 } }
+ { (\w|-|\d|\_)+ }
+ { \c{ g_@@_filter_bool_#1_\0 } }
\l_@@_cond_expr_tl
\tl_gset_eq:cN
{ g_@@_filter_bool_tl_#1_#2 } \l_@@_cond_expr_tl
@@ -2801,25 +4029,30 @@ Copyright and License
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{dbFilters, \dbNewConditional, \dbCombineConditionals}
+% \begin{macro}{dbFilters, \dbNewConditional, \dbNewCond,
+% \dbCombineConditionals, \dbCombCond}
% Environment to define conditionals and filters.
% \begin{arguments}
% \item \meta{database}
% \end{arguments}
% \begin{macrocode}
-\NewDocumentEnvironment { dbFilters } { m } {
- \seq_gclear_new:c { g_@@_cond_seq_#1 }
+\NewDocumentEnvironment { dbFilters } { s m } {
+ \seq_if_exist:cF { g_@@_cond_seq_#2 }
+ { \seq_new:c { g_@@_cond_seq_#2 } }
% \end{macrocode}
% \begin{arguments}[2]
% \item \meta{star}
-% \item \meta{conditional}
+% \item \meta{filter/conditional}
% \item \meta{attr}
% \item \meta{expr}
+% \item \meta{filter info}
% \end{arguments}
% \begin{macrocode}
- \DeclareDocumentCommand { \dbNewConditional } { s m m m } {
- \@@_new_conditional:nnnnn
- {#1} {##2} {##3} {##4} {##1}
+ \DeclareDocumentCommand { \dbNewConditional } { s m m m O{} } {
+ \@@_new_conditional:nnnnn {#2} {##2} {##3} {##4} {##1}
+ \IfValueT {#1} {
+ \dbCombCond{##2}{##2}[##5]
+ }
}
% \end{macrocode}
% \begin{arguments}[2]
@@ -2829,13 +4062,36 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\DeclareDocumentCommand { \dbCombineConditionals } { m m O{} } {
- \tl_gset:cn { g_@@_filter_info_tl_#1_##1 } {##3}
- \@@_combine_conditional:nnn {#1} {##1} {##2}
+ \tl_gset:cn { g_@@_filter_info_tl_#2_##1 } {##3}
+ \@@_combine_conditional:nnn {#2} {##1} {##2}
}
+ \cs_set_eq:NN \dbNewCond \dbNewConditional
+ \cs_set_eq:NN \dbCombCond \dbCombineConditionals
} {}
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\dbNewRawFilter, \dbNewRawFilter*}
+% Define filter with single conditional.
+% \begin{arguments}
+% \item \meta{star}
+% \item \meta{filter and conditional name}
+% \item \meta{database}
+% \item \meta{attr}
+% \item \meta{expr}
+% \item \meta{filter info}
+% \end{arguments}
+% \begin{macrocode}
+\DeclareDocumentCommand { \dbNewRawFilter } { s m m m m O{} } {
+ \seq_if_exist:cF { g_@@_cond_seq_#3 }
+ { \seq_new:c { g_@@_cond_seq_#3 } }
+ \@@_new_conditional:nnnnn {#3} {#2} {#4} {#5} {#1}
+ \tl_gset:cn { g_@@_filter_info_tl_#3_#2 } {#6}
+ \@@_combine_conditional:nnn {#3} {#2} {#2}
+}
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\dbNewReviewPoints}
% User interface to define \meta{review points}.
% \begin{arguments}
@@ -2853,26 +4109,19 @@ Copyright and License
% \dbIntMax, \dbIntMin, \dbIntMod, \dbFpSign}
% Function aliases to support more operations of integer and floating points.
% \begin{macrocode}
-\cs_set_eq:NN \dbIntAbs \int_abs:n
-\cs_set_eq:NN \dbIntSign \int_sign:n
-\cs_set_eq:NN \dbIntDivRound \int_div_round:nn
-\cs_set_eq:NN \dbIntDivTruncate \int_div_truncate:nn
-\cs_set_eq:NN \dbIntMax \int_max:nn
-\cs_set_eq:NN \dbIntMin \int_min:nn
-\cs_set_eq:NN \dbIntMod \int_mod:nn
-\cs_set_eq:NN \dbFpSign \fp_sign:n
+\cs_gset_eq:NN \dbIntAbs \int_abs:n
+\cs_gset_eq:NN \dbIntSign \int_sign:n
+\cs_gset_eq:NN \dbIntDivRound \int_div_round:nn
+\cs_gset_eq:NN \dbIntDivTruncate \int_div_truncate:nn
+\cs_gset_eq:NN \dbIntMax \int_max:nn
+\cs_gset_eq:NN \dbIntMin \int_min:nn
+\cs_gset_eq:NN \dbIntMod \int_mod:nn
+\cs_gset_eq:NN \dbFpSign \fp_sign:n
% \end{macrocode}
% \end{macro}
%
% \subsection{Style and Options}
%
-% \begin{macro}{\@@_identity:n}
-% Does nothing and keep things unchanged.
-% \begin{macrocode}
-\cs_new:Nn \@@_identity:n {#1}
-% \end{macrocode}
-% \end{macro}
-%
% \begin{macro}{\@@_new_attr_style:nnn}
% Define style keys for each attribute.
% \begin{arguments}
@@ -2892,6 +4141,15 @@ Copyright and License
g_@@_style_attr_after_tl_#1_#2_#3
},
after-code .initial:n = ,
+ code .code:n = {
+ \bool_gset_false:c { g_@@_style_attr_exp_bool_#1_#2_#3 }
+ \cs_gset:cn { @@_style_attr_code_#1_#2_#3:n } {##1}
+ },
+ code .initial:n = {##1},
+ code* .code:n = {
+ \bool_gset_true:c { g_@@_style_attr_exp_bool_#1_#2_#3 }
+ \cs_gset:cn { @@_style_attr_code_#1_#2_#3:n } {##1}
+ },
% \end{macrocode}
% For comma list and date.
% \begin{macrocode}
@@ -2909,18 +4167,28 @@ Copyright and License
g_@@_style_attr_item_after_tl_#1_#2_#3
},
item-after-code .initial:n = ,
+ item-code .code:n = {
+ \bool_gset_false:c { g_@@_style_clist_item_exp_bool_#1_#2_#3 }
+ \cs_gset:cn { @@_style_clist_item_code_#1_#2_#3:n } {##1}
+ },
+ item-code .initial:n = {##1},
+ item-code* .code:n = {
+ \bool_gset_true:c { g_@@_style_clist_item_exp_bool_#1_#2_#3 }
+ \cs_gset:cn { @@_style_clist_item_code_#1_#2_#3:n } {##1}
+ },
% \end{macrocode}
% Only for date.
% \begin{macrocode}
zfill .bool_gset:c = {
- g_@@_style_attr_zfill_bool_#1_#2_#3
+ g_@@_style_date_zfill_bool_#1_#2_#3
},
zfill .initial:n = true,
zfill .default:n = true,
- wrapper .tl_gset:c = {
- g_@@_style_attr_wrapper_#1_#2_#3
+ format-code .code:n = {
+ \cs_gset:cn { @@_style_date_format_code_#1_#2_#3:nnn } {##1}
+ \cs_generate_variant:cn
+ { @@_style_date_format_code_#1_#2_#3:nnn } { xxx }
},
- wrapper .initial:n = { \@@_identity:n },
}
\str_case_e:nn { \@@_get_type:nn {#2} {#3} } {
{ clist }
@@ -2947,21 +4215,28 @@ Copyright and License
\str_set:Nx \l_@@_raw_filter_str
{ -raw\int_use:N \g_@@_raw_filter_int - }
\tl_gset:cV { g_@@_filter_#1_#2 } \l_@@_raw_filter_str
- \@@_combine_conditional:nnn {#2} \l_@@_raw_filter_str {##1}
+ \@@_combine_conditional:nVn {#2} \l_@@_raw_filter_str {##1}
+ },
+ filter .tl_gset:c = { g_@@_filter_#1_#2 },
+ filter .initial:n = -none-,
+ sort .clist_gset:c = { g_@@_sort_clist_#1_#2 },
+ before-code .tl_gset:c = { g_@@_style_before_tl_#1_#2 },
+ before-code .initial:n = ,
+ after-code .tl_gset:c = { g_@@_style_after_tl_#1_#2 },
+ after-code .initial:n = ,
+ item-before-code .tl_gset:c = { g_@@_style_item_before_tl_#1_#2 },
+ item-before-code .initial:n = ,
+ item-after-code .tl_gset:c = { g_@@_style_item_after_tl_#1_#2 },
+ item-after-code .initial:n = ,
+ item-code .code:n = {
+ \bool_gset_false:c { g_@@_style_item_exp_bool_#1_#2 }
+ \tl_gset:cn { g_@@_style_item_tl_#1_#2 } {##1}
+ },
+ item-code .initial:n = ,
+ item-code* .code:n = {
+ \bool_gset_true:c { g_@@_style_item_exp_bool_#1_#2 }
+ \tl_gset:cn { g_@@_style_item_tl_#1_#2 } {##1}
},
- filter .tl_gset:c = { g_@@_filter_#1_#2 },
- filter .initial:n = -none-,
- sort .clist_gset:c = { g_@@_sort_clist_#1_#2 },
- before-code .tl_gset:c = { g_@@_style_before_tl_#1_#2 },
- before-code .initial:n = ,
- item-code .tl_gset:c = { g_@@_style_database_item_tl_#1_#2 },
- item-code .initial:n = ,
- after-code .tl_gset:c = { g_@@_style_after_tl_#1_#2 },
- after-code .initial:n = ,
- record-before-code .tl_gset:c = { g_@@_style_record_before_tl_#1_#2 },
- record-before-code .initial:n = ,
- record-after-code .tl_gset:c = { g_@@_style_record_after_tl_#1_#2 },
- record-after-code .initial:n = ,
}
\prop_map_inline:cn { g_@@_attr_type_prop_#2 }
{ \@@_new_attr_style:nnn {#1} {#2} {##1} }
@@ -2969,6 +4244,8 @@ Copyright and License
% \end{macrocode}
% \end{macro}
%
+% \changes{1.5}{2022-01-15}{Add check}{check if database is valid in
+% \cs{dbNewStyle}}
% \begin{macro}{\dbNewStyle}
% Set style options based on \meta{base style}.
% \begin{arguments}
@@ -2979,6 +4256,7 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\NewDocumentCommand { \dbNewStyle } { o m m +m } {
+ \@@_check_database:n {#3}
\tl_gset:cn { g_@@_style_opts_tl_#2_#3 } { #4, }
\IfValueT {#1} {
\tl_clear_new:N \l_@@_style_tmp_tl
@@ -3070,7 +4348,7 @@ Copyright and License
{ \@@_get_type:nV {#1} \l_@@_sort_attr_str }
\clist_if_in:nVF
{ str, int, date, fp } { \l_@@_sort_type_tl } {
- \msg_error:nnx { dbshow } { unsupported-sort-type }
+ \msg_fatal:nnx { dbshow } { unsupported-sort-type }
{ \l_@@_sort_type_tl }
}
\str_if_eq:eeT { \l_@@_sort_type_tl } { date }
@@ -3110,51 +4388,57 @@ Copyright and License
%
% \subsection{Display Data}
%
-% \begin{macro}{\@@_clist_wrapper:NNn}
+% \begin{macro}{\@@_clist_wrapper:NNNNn}
% Wrap the clist item with \meta{before code} and \meta{after code}.
% \begin{arguments}
% \item \meta{before code tl}
% \item \meta{after code tl}
+% \item \meta{item code cs}
+% \item \meta{exp boolean var}
% \item \meta{item}
% \end{arguments}
% \begin{macrocode}
-\cs_new:Nn \@@_clist_wrapper:NNn {
- \exp_not:n { { #1#3#2 }, }
+\cs_new:Nn \@@_clist_wrapper:NNNNn {
+ \bool_if:NTF #4
+ { \exp_not:n { { #1\exp_args:Nx#3{#5}#2 }, } }
+ { \exp_not:n { { #1#3{#5}#2 }, } }
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_clist_use:NNNN, \@@_clist_use:cccc}
+% \begin{macro}{\@@_clist_use:NNNNNN, \@@_clist_use:cccccc}
% Display a comma list.
% \begin{arguments}
% \item \meta{data clist}
% \item \meta{separator clist}
% \item \meta{before code tl}
% \item \meta{after code tl}
+% \item \meta{item code cs}
+% \item \meta{exp boolean var}
% \end{arguments}
% \begin{macrocode}
-\cs_new:Nn \@@_clist_use:NNNN {
+\cs_new:Nn \@@_clist_use:NNNNNN {
\int_case:nnF { \clist_count:N #2 } {
{ 1 } {
\clist_use:xx
- { \clist_map_tokens:Nn #1 { \@@_clist_wrapper:NNn #3 #4 } }
+ { \clist_map_tokens:Nn #1 { \@@_clist_wrapper:NNNNn #3#4#5#6 } }
{ \clist_item:Nn #2 { 1 } }
}
{ 3 } {
\clist_use:xxxx
- { \clist_map_tokens:Nn #1 { \@@_clist_wrapper:NNn #3 #4 } }
+ { \clist_map_tokens:Nn #1 { \@@_clist_wrapper:NNNNn #3#4#5#6 } }
{ \clist_item:Nn #2 { 1 } }
{ \clist_item:Nn #2 { 2 } }
{ \clist_item:Nn #2 { 3 } }
}
} {
- \@@_sep_error:xxx
+ \@@_sep_fatal:xxx
{ 1~or~3 }
{ \clist_count:N #2 }
{ \clist_use:Nn #2 { ,~ } }
}
}
-\cs_generate_variant:Nn \@@_clist_use:NNNN { cccc }
+\cs_generate_variant:Nn \@@_clist_use:NNNNNN { cccccc }
% \end{macrocode}
% \end{macro}
%
@@ -3186,7 +4470,7 @@ Copyright and License
{ \clist_item:Nn #2 { 4 } }
}
} {
- \@@_sep_error:xxx
+ \@@_sep_fatal:xxx
{ 1~or~4 }
{ \clist_count:N #2 }
{ \clist_use:Nn #2 { ,~ } }
@@ -3196,8 +4480,9 @@ Copyright and License
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_use_data:nnnn}
-% Display Data.
+% \begin{macro}{\@@_use_data:nnnn, \@@_use_data_raw:nnnn}
+% Display Data. \cs{@@_use_data:nnnn} wrap the \meta{attr} data and
+% \cs{@@_use_data_raw:nnnn} display the underlying data.
% \begin{arguments}
% \item \meta{database}
% \item \meta{attr}
@@ -3205,26 +4490,40 @@ Copyright and License
% \item \meta{style}
% \end{arguments}
% \begin{macrocode}
-% #1 database #2 attr #3 index #4 style
\cs_new:Nn \@@_use_data:nnnn {
+ \bool_if:cTF { g_@@_style_attr_exp_bool_#4_#1_#2 } {
+ \protected@edef\@dbshow@tmp{\@@_use_data_raw:nnnn {#1} {#2} {#3} {#4}}
+ \exp_args:Nno
+ \use:c { @@_style_attr_code_#4_#1_#2:n } { \@dbshow@tmp }
+ } {
+ \use:c { @@_style_attr_code_#4_#1_#2:n }
+ { \@@_use_data_raw:nnnn {#1} {#2} {#3} {#4} }
+ }
+}
+\cs_new:Nn \@@_use_data_raw:nnnn {
\str_case_e:nn
{ \prop_item:cn { g_@@_attr_type_prop_#1 } {#2} } {
{ str } { \str_use:c { g_@@_data_#1_#2_#3 } }
- { tl } { \tl_use:c { g_@@_data_#1_#2_#3 } }
+ { tl } { \tl_use:c { g_@@_data_#1_#2_#3 } }
{ int } { \int_use:c { g_@@_data_#1_#2_#3 } }
- { fp } { \fp_use:c { g_@@_data_#1_#2_#3 } }
+ { fp } { \fp_use:c { g_@@_data_#1_#2_#3 } }
{ clist } {
- \@@_clist_use:cccc { g_@@_data_#1_#2_#3 }
+ \@@_clist_use:cccccc { g_@@_data_#1_#2_#3 }
{ g_@@_style_attr_sep_#4_#1_#2 }
{ g_@@_style_attr_item_before_tl_#4_#1_#2 }
- { g_@@_style_attr_item_after_tl_#4_#1_#2 }
+ { g_@@_style_attr_item_after_ tl_#4_#1_#2 }
+ { @@_style_clist_item_code_ #4_#1_#2:n }
+ { g_@@_style_clist_item_exp_bool_#4_#1_#2 }
}
{ date } {
- \exp_args:Nnx
- \tl_use:c { g_@@_style_attr_wrapper_#4_#1_#2 } {
+ \cs_if_exist_use:cTF { @@_style_date_format_code_#4_#1_#2:xxx } {
+ { \__dbdate_get_year:n { g_@@_data_#1_#2_#3 } }
+ { \__dbdate_get_month:n { g_@@_data_#1_#2_#3 } }
+ { \__dbdate_get_day:n { g_@@_data_#1_#2_#3 } }
+ } {
\@@_date_use:ncc { g_@@_data_#1_#2_#3 }
{ g_@@_style_attr_sep_#4_#1_#2 }
- { g_@@_style_attr_zfill_bool_#4_#1_#2 }
+ { g_@@_style_date_zfill_bool_#4_#1_#2 }
}
}
}
@@ -3247,7 +4546,7 @@ Copyright and License
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_show_filter:nn}
+% \begin{macro}{\@@_show_filter:nnN}
% Filter records by executing the hook function in the running sequence and
% then testing the result boolean.
% \begin{arguments}
@@ -3289,11 +4588,31 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\cs_new_protected:Nn \@@_show_set_counter:N {
- \tl_set:Nx \dbalph { \int_to_alph:n {#1} }
- \tl_set:Nx \dbAlph { \int_to_Alph:n {#1} }
+ \tl_set:Nx \dbalph { \int_to_alph:n {#1} }
+ \tl_set:Nx \dbAlph { \int_to_Alph:n {#1} }
\tl_set:Nx \dbarabic { \int_to_arabic:n {#1} }
- \tl_set:Nx \dbRoman { \int_to_Roman:n {#1} }
- \tl_set:Nx \dbroman { \int_to_roman:n {#1} }
+ \tl_set:Nx \dbRoman { \int_to_Roman:n {#1} }
+ \tl_set:Nx \dbroman { \int_to_roman:n {#1} }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_show_set_if_last:NN, \dbIfLastT, \dbIfLastF, \dbIfLastTF}
+% Define conditional to check if the current item is the last item.
+% \begin{arguments}
+% \item \meta{current index}
+% \item \meta{count}
+% \end{arguments}
+% \begin{macrocode}
+\cs_new_protected:Nn \@@_show_set_if_last:NN {
+ \prg_set_conditional:Nnn \@@_show_if_last: { T, F, TF } {
+ \int_compare:nNnTF {#1} = {#2}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ \cs_set_eq:NN \dbIfLastT \@@_show_if_last:T
+ \cs_set_eq:NN \dbIfLastF \@@_show_if_last:F
+ \cs_set_eq:NN \dbIfLastTF \@@_show_if_last:TF
}
% \end{macrocode}
% \end{macro}
@@ -3308,6 +4627,9 @@ Copyright and License
% \begin{macrocode}
\cs_new_protected:Nn \@@_show_item:nnN {
\int_zero_new:N \l_@@_show_int
+ \int_zero_new:N \l_@@_show_count_int
+ \int_set:Nn \l_@@_show_count_int { \clist_count:N #3 }
+ \tl_clear_new:N \l_@@_item_tl
% \end{macrocode}
% \begin{arguments}[2]
% \item \meta{index}
@@ -3315,7 +4637,8 @@ Copyright and License
% \begin{macrocode}
\clist_map_inline:Nn #3 {
\int_incr:N \l_@@_show_int
- \@@_show_set_counter:N \l_@@_show_int
+ \@@_show_set_if_last:NN \l_@@_show_int \l_@@_show_count_int
+ \@@_show_set_counter:N \l_@@_show_int
\tl_set:Nn \dbIndex {##1}
% \end{macrocode}
% \begin{arguments}[3]
@@ -3326,12 +4649,21 @@ Copyright and License
\@@_check_attr:nn {#2} {####1}
\tl_use:c { g_@@_style_attr_before_tl_#1_#2_####1 }
\@@_use_data:nnnn {#2} {####1} {##1} {#1}
- \tl_use:c { g_@@_style_attr_after_tl_#1_#2_####1 }
+ \tl_use:c { g_@@_style_attr_after_ tl_#1_#2_####1 }
+ }
+ \bool_if:cTF { g_@@_style_item_exp_bool_#1_#2 } {
+ \protected@edef\@dbshow@tmp{\tl_use:c { g_@@_style_item_before_tl_#1_#2 }}
+ \tl_put_right:No \l_@@_item_tl { \@dbshow@tmp }
+ \protected@edef\@dbshow@tmp{\tl_use:c { g_@@_style_item_ tl_#1_#2 }}
+ \tl_put_right:No \l_@@_item_tl { \@dbshow@tmp }
+ \protected@edef\@dbshow@tmp{\tl_use:c { g_@@_style_item_after_ tl_#1_#2 }}
+ } {
+ \tl_use:c { g_@@_style_item_before_tl_#1_#2 }
+ \tl_use:c { g_@@_style_item_ tl_#1_#2 }
+ \tl_use:c { g_@@_style_item_after_ tl_#1_#2 }
}
- \tl_use:c { g_@@_style_record_before_tl_#1_#2 }
- \tl_use:c { g_@@_style_database_item_tl_#1_#2 }
- \tl_use:c { g_@@_style_record_after_tl_#1_#2 }
}
+ \l_@@_item_tl
}
% \end{macrocode}
% \end{macro}
@@ -3355,8 +4687,14 @@ Copyright and License
% \end{macrocode}
% \end{macro}
%
+% \changes{1.5}{2022-01-15}{Fix bug}{\cs{dbIfEmptyF} undefined}
% \begin{macro}{\@@_show:nnn, \@@_show:nnv}
% First filter records and sort them if needed and display at last.
+% \begin{arguments}
+% \item \meta{style}
+% \item \meta{database}
+% \item \meta{filter}
+% \end{arguments}
% \begin{macrocode}
\cs_new_protected:Nn \@@_show:nnn {
\@@_show_set_macro:nn {#2} {#3}
@@ -3364,6 +4702,7 @@ Copyright and License
\@@_show_filter:nnN {#2} {#3} \l_@@_show_index_clist
\clist_if_empty:cF { g_@@_sort_clist_#1_#2 }
{ \@@_sort:nNn {#2} \l_@@_show_index_clist {#1} }
+ \@@_show_set_cond:N \l_@@_show_index_clist
\tl_use:c { g_@@_style_before_tl_#1_#2 }
\@@_show_item:nnN {#1} {#2} \l_@@_show_index_clist
\tl_use:c { g_@@_style_after_tl_#1_#2 }
@@ -3381,8 +4720,9 @@ Copyright and License
% \begin{macrocode}
\NewDocumentCommand { \dbshow } { m m } {
\@@_check_database:n {#2}
- \@@_check_filter:nv {#2} { g_@@_filter_#1_#2 }
- \@@_show:nnv {#1} {#2} { g_@@_filter_#1_#2 }
+ \@@_check_style:nn {#1} {#2}
+ \@@_check_filter:nv {#2} { g_@@_filter_#1_#2 }
+ \@@_show:nnv {#1} {#2} { g_@@_filter_#1_#2 }
}
% \end{macrocode}
% \end{macro}
@@ -3393,6 +4733,38 @@ Copyright and License
%<@@=dbdate>
% \end{macrocode}
%
+% \begin{arguments}
+% \item \meta{date}
+% \item \meta{date sep}
+% \end{arguments}
+% \begin{macrocode}
+\msg_new:nnn { dbshow } { wrong-date-sep } {
+ can~not~parse~the~date~'#1'~with~the~global~date~separator~'#2'~
+ \msg_line_context:.~Please~set~the~correct~date~separator~with~
+ \dbdatesep.
+}
+% \end{macrocode}
+%
+% \begin{macro}{\@@_check_date_sep:nn, \@@_check_date_sep:Vn}
+% Check if the global date separator is valid.
+% \begin{arguments}
+% \item \meta{date}
+% \item \meta{date sep}
+% \end{arguments}
+% \begin{macrocode}
+\cs_new:Nn \@@_check_date_sep:nn {
+ \int_zero_new:N \l_@@_sep_int
+ \tl_map_inline:nn {#1} {
+ \tl_if_eq:nnT {#2} {##1} { \int_incr:N \l_@@_sep_int }
+ \int_compare:nNnT { \l_@@_sep_int } > { 2 } { \tl_map_break: }
+ }
+ \int_compare:nNnF { \l_@@_sep_int } = { 2 }
+ { \msg_fatal:nnnn { dbshow } { wrong-date-sep } {#1} {#2} }
+}
+\cs_generate_variant:Nn \@@_check_date_sep:nn { nV }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[pTF]{\@@_if_leap:n}
% Check if the year is leap.
% \begin{arguments}
@@ -3563,6 +4935,28 @@ Copyright and License
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@@_get_year:n, \@@_get_year:x, \@@_get_month:n,
+% \@@_get_month:x, \@@_get_day:n, \@@_get_day:x}
+% Extract year, month or day from \meta{date var}.
+% \begin{arguments}
+% \item \meta{date var}
+% \end{arguments}
+% \begin{macrocode}
+\cs_new:Nn \@@_get_year:n {
+ \int_use:c { @@_year_#1 }
+}
+\cs_new:Nn \@@_get_month:n {
+ \int_use:c { @@_month_#1 }
+}
+\cs_new:Nn \@@_get_day:n {
+ \int_use:c { @@_day_#1 }
+}
+\cs_generate_variant:Nn \@@_get_year:n { x }
+\cs_generate_variant:Nn \@@_get_month:n { x }
+\cs_generate_variant:Nn \@@_get_day:n { x }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\@@_set:nnnn, \@@_gset:nnnn}
% Set the value of \meta{date var}.
% \begin{arguments}
@@ -3626,10 +5020,12 @@ Copyright and License
% \end{arguments}
% \begin{macrocode}
\cs_new_protected:Nn \@@_set:nn {
+ \@@_check_date_sep:nV {#2} \g_@@_sep_tl
\@@_set:w #1\@@_sep#2\@@_stop
}
\cs_generate_variant:Nn \@@_set:nn { xx }
\cs_new_protected:Nn \@@_gset:nn {
+ \@@_check_date_sep:nV {#2} \g_@@_sep_tl
\@@_gset:w #1\@@_sep#2\@@_stop
}
\cs_generate_variant:Nn \@@_gset:nn { xx }