diff options
Diffstat (limited to 'Master')
-rw-r--r-- | Master/texmf-dist/doc/latex/dbshow/dbshow.pdf | bin | 440283 -> 602868 bytes | |||
-rw-r--r-- | Master/texmf-dist/source/latex/dbshow/dbshow.dtx | 3156 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/dbshow/dbshow.sty | 289 |
3 files changed, 2483 insertions, 962 deletions
diff --git a/Master/texmf-dist/doc/latex/dbshow/dbshow.pdf b/Master/texmf-dist/doc/latex/dbshow/dbshow.pdf Binary files differindex 8d7c4d1bc21..7e3d14fb73b 100644 --- a/Master/texmf-dist/doc/latex/dbshow/dbshow.pdf +++ b/Master/texmf-dist/doc/latex/dbshow/dbshow.pdf diff --git a/Master/texmf-dist/source/latex/dbshow/dbshow.dtx b/Master/texmf-dist/source/latex/dbshow/dbshow.dtx index a2af27d9229..9731797f761 100644 --- a/Master/texmf-dist/source/latex/dbshow/dbshow.dtx +++ b/Master/texmf-dist/source/latex/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 } diff --git a/Master/texmf-dist/tex/latex/dbshow/dbshow.sty b/Master/texmf-dist/tex/latex/dbshow/dbshow.sty index 5543a6a09eb..ee3dc831c94 100644 --- a/Master/texmf-dist/tex/latex/dbshow/dbshow.sty +++ b/Master/texmf-dist/tex/latex/dbshow/dbshow.sty @@ -31,15 +31,16 @@ %% -------------------------------------------------------------------------- %% \NeedsTeXFormat{LaTeX2e} -\GetIdInfo$Id: dbshow.dtx 461d9bb 2022-01-14 02:50:24 +0800 Changkai Li <lichangkai225@qq.com> $ +\GetIdInfo$Id: dbshow.dtx 1a507c4 2022-01-17 22:53:24 +0800 Changkai Li <lichangkai225@qq.com> $ {Database to store and display data} \ProvidesExplPackage{\ExplFileName} - {\ExplFileDate}{1.4}{\ExplFileDescription} + {\ExplFileDate}{1.5}{\ExplFileDescription} \__kernel_dependency_version_check:nn { 2021-11-07 } { l3prop } \__kernel_dependency_version_check:nn { 2021-05-17 } { l3str } \__kernel_dependency_version_check:nn { 2021-05-10 } { l3clist } \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 } @@ -65,14 +66,14 @@ Database~'#1'~does~not~exist~\msg_line_context:. } \cs_new:Nn \__dbshow_check_database:n { - \prop_if_exist:cF { g__dbshow_attr_type_prop_#1 } + \prop_if_exist:cF { g__dbshow_attr_type_prop_\tl_to_str:n {#1} } { \msg_fatal:nnn { dbshow } { non-existent-database } {#1} } } \msg_new:nnn { dbshow } { non-existent-attr } { Attribute~'#2'~of~database~'#1'~does~not~exist~\msg_line_context:. } \cs_new:Nn \__dbshow_check_attr:nn { - \prop_if_in:cnF { g__dbshow_attr_type_prop_#1 } {#2} + \prop_if_in:cnF { g__dbshow_attr_type_prop_\tl_to_str:n {#1} } {#2} { \msg_fatal:nnnn { dbshow } { non-existent-attr } {#1} {#2} } } \cs_generate_variant:Nn \__dbshow_check_attr:nn { nV } @@ -80,21 +81,22 @@ Style~'#1'~of~database~'#2'~does~not~exist~\msg_line_context:. } \cs_new:Nn \__dbshow_check_style:nn { - \tl_if_exist:cF { g__dbshow_style_opts_tl_#1_#2 } - { \msg_warning:nnnn { dbshow } { non-existent-style } {#1} {#2} } + \tl_if_exist:cF { g__dbshow_style_opts_tl_\tl_to_str:n {#1}_\tl_to_str:n {#2} } + { \msg_fatal:nnnn { dbshow } { non-existent-style } {#1} {#2} } } \msg_new:nnn { dbshow } { non-existent-cond } { Conditional~'#2'~of~database~'#1'~does~not~exist~\msg_line_context:. } \cs_new:Nn \__dbshow_check_cond:nnn { - \tl_if_exist:cF { g__dbshow_filter_attr_#1_#2 } + \tl_if_exist:cF { g__dbshow_filter_attr_\tl_to_str:n {#1}_\tl_to_str:n {#2} } { \msg_fatal:nnnn { dbshow } { non-existent-cond } {#1} {#2} } } \msg_new:nnn { dbshow } { non-existent-filter } { Filter~'#2'~of~database~'#1'~does~not~exist~and~is~ignored~\msg_line_context:. } \cs_new:Nn \__dbshow_check_filter:nn { - \seq_if_exist:cF { g__dbshow_filter_run_seq_#1_#2 } { + \seq_if_exist:cF + { g__dbshow_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} } @@ -113,10 +115,10 @@ option~'sep'~should~contain~#1~items~but~only~#2~items~was~given,~ sep~=~\{#3\}~\msg_line_context:. } -\cs_new:Nn \__dbshow_sep_error:nnn { - \msg_error:nnnnn { dbshow } { wrong-seperator } {#1} {#2} {#3} +\cs_new:Nn \__dbshow_sep_fatal:nnn { + \msg_fatal:nnnnn { dbshow } { wrong-seperator } {#1} {#2} {#3} } -\cs_generate_variant:Nn \__dbshow_sep_error:nnn { xxx } +\cs_generate_variant:Nn \__dbshow_sep_fatal:nnn { xxx } \msg_new:nnn { dbshow } { unsupported-sort-type } { unsupported~sort~type:~'#1'~\msg_line_context:.~The~type~should~be~one~of~ \{str,~date,~int,~fp\}. @@ -125,7 +127,7 @@ #1\__dbshow_sep#2\__dbshow_sep#3|#4\__dbshow_stop { \__dbshow_check_type:n {#3} \prop_gput:cxx { g__dbshow_attr_type_prop_#1 } {#2} {#3} - \prop_gput:cxx { g__dbshow_default_map_#1 } {#2} {#4} + \prop_gput:cno { g__dbshow_default_map_#1 } {#2} {#4} } \cs_new_protected:Nn \__dbshow_process_attr_type_prop:n { \prop_gclear_new:c { g__dbshow_default_map_#1 } @@ -266,7 +268,7 @@ \regex_match:VVTF #2 #3 {#4} {#5} } \cs_generate_variant:Nn \__dbshow_filter_str:NNNnn { cccnn } -\cs_set_eq:NN \__dbshow_filter_tl:NNNnn \__dbshow_filter_str:NNNnn +\cs_gset_eq:NN \__dbshow_filter_tl:NNNnn \__dbshow_filter_str:NNNnn \cs_generate_variant:Nn \__dbshow_filter_tl:NNNnn { cccnn } \cs_new_protected:Npn \__dbshow_parse_date_cond:NNw #1#2#3|#4\__dbshow_stop { \clist_set_eq:Nc #1 { g__review_points_#3 } @@ -282,8 +284,11 @@ \__dbdate_set:xx { tmp_day1 } { \l__dbshow_filter_tmp_tl } \__dbdate_set:xx { tmp_day2 } {#3} \__dbdate_sub:nnN { tmp_day1 } { tmp_day2 } \l__dbshow_filter_diff_int - \clist_if_in:NxTF \l__dbshow_filter_tmp_clist - { \int_use:N \l__dbshow_filter_diff_int } {#4} {#5} + #5 + \clist_map_inline:Nn \l__dbshow_filter_tmp_clist { + \int_compare:nNnT { \l__dbshow_filter_diff_int } = {##1} + { #4 \clist_map_break: } + } } { \int_zero_new:N \l__dbshow_filter_tmpa_int \int_zero_new:N \l__dbshow_filter_tmpb_int @@ -313,11 +318,12 @@ } } \cs_generate_variant:Nn \__dbshow_filter_date:NNNnn { cccnn } -\cs_set:Nn \__dbshow_filter:nnn { +\cs_new_protected:Nn \__dbshow_filter:nnn { \tl_set_eq:Nc \l__dbshow_attr_tl { g__dbshow_filter_attr_tl_#1_#2 } \cs_set_eq:Nc \dbval { g__dbshow_data_#1_\l__dbshow_attr_tl _#3 } + \tl_set:Nx \l__dbshow_type_tl { \__dbshow_get_type:nV {#1} \l__dbshow_attr_tl } \use:c - { __dbshow_filter_\__dbshow_get_type:nV {#1} \l__dbshow_attr_tl :cccnn } + { __dbshow_filter_\l__dbshow_type_tl :cccnn } { g__dbshow_cond_star_bool_#1_#2 } { g__dbshow_filter_expr_tl_#1_#2 } { dbval } @@ -325,6 +331,8 @@ { \bool_gset_false:c { g__dbshow_filter_bool_#1_#2 } } } \cs_new_protected:Nn \__dbshow_new_conditional:nnnnn { + \__dbshow_check_database:n {#1} + \__dbshow_check_attr:nn {#1} {#3} \tl_gset:cn { g__dbshow_filter_attr_tl_#1_#2 } {#3} \tl_gset:cn { g__dbshow_filter_expr_tl_#1_#2 } {#4} \bool_if_exist:cF { g__dbshow_filter_bool_#1_#2 } @@ -337,49 +345,68 @@ \cs_gset:cn { g__dbshow_filter_hook_#1_#2:n } { \__dbshow_filter:nnn {#1} {#2} {##1} } - \seq_gput_right:cn { g__dbshow_cond_seq_#1 } {#2} + \bool_if_exist:cF { g__dbshow_cond_exist_bool_#1_#2 } + { \bool_set_false:c { g__dbshow_cond_exist_bool_#1_#2 } } + \bool_if:cF { g__dbshow_cond_exist_bool_#1_#2 } + { \seq_gput_right:cn { g__dbshow_cond_seq_#1 } {#2} } } \cs_new_protected:Nn \__dbshow_combine_conditional:nnn { \tl_gset_eq:cN { g__dbshow_filter_bool_tl_#1_#2 } \c_true_bool \seq_gclear_new:c { g__dbshow_filter_run_seq_#1_#2 } - \regex_extract_all:nnN { \w+ } {#3} \l__dbshow_cond_seq + \regex_extract_all:nnN { [^!=&<>()\ ]+ } {#3} \l__dbshow_cond_seq \seq_map_inline:Nn \l__dbshow_cond_seq { \seq_if_in:cnT { g__dbshow_cond_seq_#1 } {##1} { - \seq_gput_right:cn { g__dbshow_filter_run_seq_#1_#2 } + \seq_if_in:cnF { g__dbshow_filter_run_seq_#1_#2 } { g__dbshow_filter_hook_#1_##1:n } + { + \seq_gput_right:cn { g__dbshow_filter_run_seq_#1_#2 } + { g__dbshow_filter_hook_#1_##1:n } + } } } \tl_set:Nn \l__dbshow_cond_expr_tl {#3} \regex_replace_all:nnN - { \w+ } { \c{ g__dbshow_filter_bool_#1_\0 } } + { (\w|-|\d|\_)+ } + { \c{ g__dbshow_filter_bool_#1_\0 } } \l__dbshow_cond_expr_tl \tl_gset_eq:cN { g__dbshow_filter_bool_tl_#1_#2 } \l__dbshow_cond_expr_tl } \cs_generate_variant:Nn \__dbshow_combine_conditional:nnn { nVn } -\NewDocumentEnvironment { dbFilters } { m } { - \seq_gclear_new:c { g__dbshow_cond_seq_#1 } - \DeclareDocumentCommand { \dbNewConditional } { s m m m } { - \__dbshow_new_conditional:nnnnn - {#1} {##2} {##3} {##4} {##1} +\NewDocumentEnvironment { dbFilters } { s m } { + \seq_if_exist:cF { g__dbshow_cond_seq_#2 } + { \seq_new:c { g__dbshow_cond_seq_#2 } } + \DeclareDocumentCommand { \dbNewConditional } { s m m m O{} } { + \__dbshow_new_conditional:nnnnn {#2} {##2} {##3} {##4} {##1} + \IfValueT {#1} { + \dbCombCond{##2}{##2}[##5] + } } \DeclareDocumentCommand { \dbCombineConditionals } { m m O{} } { - \tl_gset:cn { g__dbshow_filter_info_tl_#1_##1 } {##3} - \__dbshow_combine_conditional:nnn {#1} {##1} {##2} + \tl_gset:cn { g__dbshow_filter_info_tl_#2_##1 } {##3} + \__dbshow_combine_conditional:nnn {#2} {##1} {##2} } + \cs_set_eq:NN \dbNewCond \dbNewConditional + \cs_set_eq:NN \dbCombCond \dbCombineConditionals } {} +\DeclareDocumentCommand { \dbNewRawFilter } { s m m m m O{} } { + \seq_if_exist:cF { g__dbshow_cond_seq_#3 } + { \seq_new:c { g__dbshow_cond_seq_#3 } } + \__dbshow_new_conditional:nnnnn {#3} {#2} {#4} {#5} {#1} + \tl_gset:cn { g__dbshow_filter_info_tl_#3_#2 } {#6} + \__dbshow_combine_conditional:nnn {#3} {#2} {#2} +} \NewDocumentCommand { \dbNewReviewPoints } { m m } { \clist_set:cn { g__review_points_#1 } {#2} } -\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_new:Nn \__dbshow_identity:n {#1} +\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 \cs_new_protected:Nn \__dbshow_new_attr_style:nnn { \__dbshow_check_attr:nn {#2} {#3} \keys_define:nn { dbshow/style/#1/#3 } { @@ -391,6 +418,15 @@ g__dbshow_style_attr_after_tl_#1_#2_#3 }, after-code .initial:n = , + code .code:n = { + \bool_gset_false:c { g__dbshow_style_attr_exp_bool_#1_#2_#3 } + \cs_gset:cn { __dbshow_style_attr_code_#1_#2_#3:n } {##1} + }, + code .initial:n = {##1}, + code* .code:n = { + \bool_gset_true:c { g__dbshow_style_attr_exp_bool_#1_#2_#3 } + \cs_gset:cn { __dbshow_style_attr_code_#1_#2_#3:n } {##1} + }, sep .clist_gset:c = { g__dbshow_style_attr_sep_#1_#2_#3 }, @@ -402,15 +438,25 @@ g__dbshow_style_attr_item_after_tl_#1_#2_#3 }, item-after-code .initial:n = , + item-code .code:n = { + \bool_gset_false:c { g__dbshow_style_clist_item_exp_bool_#1_#2_#3 } + \cs_gset:cn { __dbshow_style_clist_item_code_#1_#2_#3:n } {##1} + }, + item-code .initial:n = {##1}, + item-code* .code:n = { + \bool_gset_true:c { g__dbshow_style_clist_item_exp_bool_#1_#2_#3 } + \cs_gset:cn { __dbshow_style_clist_item_code_#1_#2_#3:n } {##1} + }, zfill .bool_gset:c = { - g__dbshow_style_attr_zfill_bool_#1_#2_#3 + g__dbshow_style_date_zfill_bool_#1_#2_#3 }, zfill .initial:n = true, zfill .default:n = true, - wrapper .tl_gset:c = { - g__dbshow_style_attr_wrapper_#1_#2_#3 + format-code .code:n = { + \cs_gset:cn { __dbshow_style_date_format_code_#1_#2_#3:nnn } {##1} + \cs_generate_variant:cn + { __dbshow_style_date_format_code_#1_#2_#3:nnn } { xxx } }, - wrapper .initial:n = { \__dbshow_identity:n }, } \str_case_e:nn { \__dbshow_get_type:nn {#2} {#3} } { { clist } @@ -427,26 +473,34 @@ \str_set:Nx \l__dbshow_raw_filter_str { -raw\int_use:N \g__dbshow_raw_filter_int - } \tl_gset:cV { g__dbshow_filter_#1_#2 } \l__dbshow_raw_filter_str - \__dbshow_combine_conditional:nnn {#2} \l__dbshow_raw_filter_str {##1} + \__dbshow_combine_conditional:nVn {#2} \l__dbshow_raw_filter_str {##1} + }, + filter .tl_gset:c = { g__dbshow_filter_#1_#2 }, + filter .initial:n = -none-, + sort .clist_gset:c = { g__dbshow_sort_clist_#1_#2 }, + before-code .tl_gset:c = { g__dbshow_style_before_tl_#1_#2 }, + before-code .initial:n = , + after-code .tl_gset:c = { g__dbshow_style_after_tl_#1_#2 }, + after-code .initial:n = , + item-before-code .tl_gset:c = { g__dbshow_style_item_before_tl_#1_#2 }, + item-before-code .initial:n = , + item-after-code .tl_gset:c = { g__dbshow_style_item_after_tl_#1_#2 }, + item-after-code .initial:n = , + item-code .code:n = { + \bool_gset_false:c { g__dbshow_style_item_exp_bool_#1_#2 } + \tl_gset:cn { g__dbshow_style_item_tl_#1_#2 } {##1} + }, + item-code .initial:n = , + item-code* .code:n = { + \bool_gset_true:c { g__dbshow_style_item_exp_bool_#1_#2 } + \tl_gset:cn { g__dbshow_style_item_tl_#1_#2 } {##1} }, - filter .tl_gset:c = { g__dbshow_filter_#1_#2 }, - filter .initial:n = -none-, - sort .clist_gset:c = { g__dbshow_sort_clist_#1_#2 }, - before-code .tl_gset:c = { g__dbshow_style_before_tl_#1_#2 }, - before-code .initial:n = , - item-code .tl_gset:c = { g__dbshow_style_database_item_tl_#1_#2 }, - item-code .initial:n = , - after-code .tl_gset:c = { g__dbshow_style_after_tl_#1_#2 }, - after-code .initial:n = , - record-before-code .tl_gset:c = { g__dbshow_style_record_before_tl_#1_#2 }, - record-before-code .initial:n = , - record-after-code .tl_gset:c = { g__dbshow_style_record_after_tl_#1_#2 }, - record-after-code .initial:n = , } \prop_map_inline:cn { g__dbshow_attr_type_prop_#2 } { \__dbshow_new_attr_style:nnn {#1} {#2} {##1} } } \NewDocumentCommand { \dbNewStyle } { o m m +m } { + \__dbshow_check_database:n {#3} \tl_gset:cn { g__dbshow_style_opts_tl_#2_#3 } { #4, } \IfValueT {#1} { \tl_clear_new:N \l__dbshow_style_tmp_tl @@ -497,7 +551,7 @@ { \__dbshow_get_type:nV {#1} \l__dbshow_sort_attr_str } \clist_if_in:nVF { str, int, date, fp } { \l__dbshow_sort_type_tl } { - \msg_error:nnx { dbshow } { unsupported-sort-type } + \msg_fatal:nnx { dbshow } { unsupported-sort-type } { \l__dbshow_sort_type_tl } } \str_if_eq:eeT { \l__dbshow_sort_type_tl } { date } @@ -526,31 +580,33 @@ \__dbshow_sort_single: } } -\cs_new:Nn \__dbshow_clist_wrapper:NNn { - \exp_not:n { { #1#3#2 }, } +\cs_new:Nn \__dbshow_clist_wrapper:NNNNn { + \bool_if:NTF #4 + { \exp_not:n { { #1\exp_args:Nx#3{#5}#2 }, } } + { \exp_not:n { { #1#3{#5}#2 }, } } } -\cs_new:Nn \__dbshow_clist_use:NNNN { +\cs_new:Nn \__dbshow_clist_use:NNNNNN { \int_case:nnF { \clist_count:N #2 } { { 1 } { \clist_use:xx - { \clist_map_tokens:Nn #1 { \__dbshow_clist_wrapper:NNn #3 #4 } } + { \clist_map_tokens:Nn #1 { \__dbshow_clist_wrapper:NNNNn #3#4#5#6 } } { \clist_item:Nn #2 { 1 } } } { 3 } { \clist_use:xxxx - { \clist_map_tokens:Nn #1 { \__dbshow_clist_wrapper:NNn #3 #4 } } + { \clist_map_tokens:Nn #1 { \__dbshow_clist_wrapper:NNNNn #3#4#5#6 } } { \clist_item:Nn #2 { 1 } } { \clist_item:Nn #2 { 2 } } { \clist_item:Nn #2 { 3 } } } } { - \__dbshow_sep_error:xxx + \__dbshow_sep_fatal:xxx { 1~or~3 } { \clist_count:N #2 } { \clist_use:Nn #2 { ,~ } } } } -\cs_generate_variant:Nn \__dbshow_clist_use:NNNN { cccc } +\cs_generate_variant:Nn \__dbshow_clist_use:NNNNNN { cccccc } \cs_new:Nn \__dbshow_date_use:nNN { \int_case:nnF { \clist_count:N #2 } { { 1 } { @@ -571,7 +627,7 @@ { \clist_item:Nn #2 { 4 } } } } { - \__dbshow_sep_error:xxx + \__dbshow_sep_fatal:xxx { 1~or~4 } { \clist_count:N #2 } { \clist_use:Nn #2 { ,~ } } @@ -579,24 +635,39 @@ } \cs_generate_variant:Nn \__dbshow_date_use:nNN { ncc } \cs_new:Nn \__dbshow_use_data:nnnn { + \bool_if:cTF { g__dbshow_style_attr_exp_bool_#4_#1_#2 } { + \protected@edef\@dbshow@tmp{\__dbshow_use_data_raw:nnnn {#1} {#2} {#3} {#4}} + \exp_args:Nno + \use:c { __dbshow_style_attr_code_#4_#1_#2:n } { \@dbshow@tmp } + } { + \use:c { __dbshow_style_attr_code_#4_#1_#2:n } + { \__dbshow_use_data_raw:nnnn {#1} {#2} {#3} {#4} } + } +} +\cs_new:Nn \__dbshow_use_data_raw:nnnn { \str_case_e:nn { \prop_item:cn { g__dbshow_attr_type_prop_#1 } {#2} } { { str } { \str_use:c { g__dbshow_data_#1_#2_#3 } } - { tl } { \tl_use:c { g__dbshow_data_#1_#2_#3 } } + { tl } { \tl_use:c { g__dbshow_data_#1_#2_#3 } } { int } { \int_use:c { g__dbshow_data_#1_#2_#3 } } - { fp } { \fp_use:c { g__dbshow_data_#1_#2_#3 } } + { fp } { \fp_use:c { g__dbshow_data_#1_#2_#3 } } { clist } { - \__dbshow_clist_use:cccc { g__dbshow_data_#1_#2_#3 } + \__dbshow_clist_use:cccccc { g__dbshow_data_#1_#2_#3 } { g__dbshow_style_attr_sep_#4_#1_#2 } { g__dbshow_style_attr_item_before_tl_#4_#1_#2 } - { g__dbshow_style_attr_item_after_tl_#4_#1_#2 } + { g__dbshow_style_attr_item_after_ tl_#4_#1_#2 } + { __dbshow_style_clist_item_code_ #4_#1_#2:n } + { g__dbshow_style_clist_item_exp_bool_#4_#1_#2 } } { date } { - \exp_args:Nnx - \tl_use:c { g__dbshow_style_attr_wrapper_#4_#1_#2 } { + \cs_if_exist_use:cTF { __dbshow_style_date_format_code_#4_#1_#2:xxx } { + { \__dbdate_get_year:n { g__dbshow_data_#1_#2_#3 } } + { \__dbdate_get_month:n { g__dbshow_data_#1_#2_#3 } } + { \__dbdate_get_day:n { g__dbshow_data_#1_#2_#3 } } + } { \__dbshow_date_use:ncc { g__dbshow_data_#1_#2_#3 } { g__dbshow_style_attr_sep_#4_#1_#2 } - { g__dbshow_style_attr_zfill_bool_#4_#1_#2 } + { g__dbshow_style_date_zfill_bool_#4_#1_#2 } } } } @@ -619,28 +690,51 @@ } } \cs_new_protected:Nn \__dbshow_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} } +} +\cs_new_protected:Nn \__dbshow_show_set_if_last:NN { + \prg_set_conditional:Nnn \__dbshow_show_if_last: { T, F, TF } { + \int_compare:nNnTF {#1} = {#2} + { \prg_return_true: } + { \prg_return_false: } + } + \cs_set_eq:NN \dbIfLastT \__dbshow_show_if_last:T + \cs_set_eq:NN \dbIfLastF \__dbshow_show_if_last:F + \cs_set_eq:NN \dbIfLastTF \__dbshow_show_if_last:TF } \cs_new_protected:Nn \__dbshow_show_item:nnN { \int_zero_new:N \l__dbshow_show_int + \int_zero_new:N \l__dbshow_show_count_int + \int_set:Nn \l__dbshow_show_count_int { \clist_count:N #3 } + \tl_clear_new:N \l__dbshow_item_tl \clist_map_inline:Nn #3 { \int_incr:N \l__dbshow_show_int - \__dbshow_show_set_counter:N \l__dbshow_show_int + \__dbshow_show_set_if_last:NN \l__dbshow_show_int \l__dbshow_show_count_int + \__dbshow_show_set_counter:N \l__dbshow_show_int \tl_set:Nn \dbIndex {##1} \cs_set:Npn \dbuse ####1 { \__dbshow_check_attr:nn {#2} {####1} \tl_use:c { g__dbshow_style_attr_before_tl_#1_#2_####1 } \__dbshow_use_data:nnnn {#2} {####1} {##1} {#1} - \tl_use:c { g__dbshow_style_attr_after_tl_#1_#2_####1 } + \tl_use:c { g__dbshow_style_attr_after_ tl_#1_#2_####1 } + } + \bool_if:cTF { g__dbshow_style_item_exp_bool_#1_#2 } { + \protected@edef\@dbshow@tmp{\tl_use:c { g__dbshow_style_item_before_tl_#1_#2 }} + \tl_put_right:No \l__dbshow_item_tl { \@dbshow@tmp } + \protected@edef\@dbshow@tmp{\tl_use:c { g__dbshow_style_item_ tl_#1_#2 }} + \tl_put_right:No \l__dbshow_item_tl { \@dbshow@tmp } + \protected@edef\@dbshow@tmp{\tl_use:c { g__dbshow_style_item_after_ tl_#1_#2 }} + } { + \tl_use:c { g__dbshow_style_item_before_tl_#1_#2 } + \tl_use:c { g__dbshow_style_item_ tl_#1_#2 } + \tl_use:c { g__dbshow_style_item_after_ tl_#1_#2 } } - \tl_use:c { g__dbshow_style_record_before_tl_#1_#2 } - \tl_use:c { g__dbshow_style_database_item_tl_#1_#2 } - \tl_use:c { g__dbshow_style_record_after_tl_#1_#2 } } + \l__dbshow_item_tl } \cs_new_protected:Nn \__dbshow_show_set_cond:N { \prg_set_conditional:Nnn \__dbshow_if_empty: { T, F, TF } { @@ -658,6 +752,7 @@ \__dbshow_show_filter:nnN {#2} {#3} \l__dbshow_show_index_clist \clist_if_empty:cF { g__dbshow_sort_clist_#1_#2 } { \__dbshow_sort:nNn {#2} \l__dbshow_show_index_clist {#1} } + \__dbshow_show_set_cond:N \l__dbshow_show_index_clist \tl_use:c { g__dbshow_style_before_tl_#1_#2 } \__dbshow_show_item:nnN {#1} {#2} \l__dbshow_show_index_clist \tl_use:c { g__dbshow_style_after_tl_#1_#2 } @@ -665,9 +760,25 @@ \cs_generate_variant:Nn \__dbshow_show:nnn { nnv } \NewDocumentCommand { \dbshow } { m m } { \__dbshow_check_database:n {#2} - \__dbshow_check_filter:nv {#2} { g__dbshow_filter_#1_#2 } - \__dbshow_show:nnv {#1} {#2} { g__dbshow_filter_#1_#2 } + \__dbshow_check_style:nn {#1} {#2} + \__dbshow_check_filter:nv {#2} { g__dbshow_filter_#1_#2 } + \__dbshow_show:nnv {#1} {#2} { g__dbshow_filter_#1_#2 } +} +\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. +} +\cs_new:Nn \__dbdate_check_date_sep:nn { + \int_zero_new:N \l__dbdate_sep_int + \tl_map_inline:nn {#1} { + \tl_if_eq:nnT {#2} {##1} { \int_incr:N \l__dbdate_sep_int } + \int_compare:nNnT { \l__dbdate_sep_int } > { 2 } { \tl_map_break: } + } + \int_compare:nNnF { \l__dbdate_sep_int } = { 2 } + { \msg_fatal:nnnn { dbshow } { wrong-date-sep } {#1} {#2} } } +\cs_generate_variant:Nn \__dbdate_check_date_sep:nn { nV } \prg_new_conditional:Nnn \__dbdate_if_leap:n { T, F, TF, p } { \bool_if:nTF { \int_compare_p:nNn { \int_mod:nn {#1} { 400 } } = { 0 } || @@ -752,6 +863,18 @@ \__dbdate_ginit:n {#1} } \cs_generate_variant:Nn \__dbdate_gclear_new:n { x } +\cs_new:Nn \__dbdate_get_year:n { + \int_use:c { __dbdate_year_#1 } +} +\cs_new:Nn \__dbdate_get_month:n { + \int_use:c { __dbdate_month_#1 } +} +\cs_new:Nn \__dbdate_get_day:n { + \int_use:c { __dbdate_day_#1 } +} +\cs_generate_variant:Nn \__dbdate_get_year:n { x } +\cs_generate_variant:Nn \__dbdate_get_month:n { x } +\cs_generate_variant:Nn \__dbdate_get_day:n { x } \cs_new_protected:Nn \__dbdate_set:nnnn { \int_set:cn { __dbdate_year_#1 } {#2} \int_set:cn { __dbdate_month_#1 } {#3} @@ -778,10 +901,12 @@ \cs_gset_eq:NN \dbdatesep \__dbdate_set_sep:n \dbdatesep{/} \cs_new_protected:Nn \__dbdate_set:nn { + \__dbdate_check_date_sep:nV {#2} \g__dbdate_sep_tl \__dbdate_set:w #1\__dbdate_sep#2\__dbdate_stop } \cs_generate_variant:Nn \__dbdate_set:nn { xx } \cs_new_protected:Nn \__dbdate_gset:nn { + \__dbdate_check_date_sep:nV {#2} \g__dbdate_sep_tl \__dbdate_gset:w #1\__dbdate_sep#2\__dbdate_stop } \cs_generate_variant:Nn \__dbdate_gset:nn { xx } |