diff options
Diffstat (limited to 'macros')
45 files changed, 7022 insertions, 1688 deletions
diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/README.md b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/README.md index f53446ab8c..2643816c1f 100644 --- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/README.md +++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/README.md @@ -59,7 +59,7 @@ To install a stable version of this theme, please refer to update instructions of your TeX distribution. Trigon has been on [CTAN](https://ctan.org/pkg/beamertheme-trigon) since March 2021. For users of typical TeX distributions (TexLive, MacTeX, MikTeX), simply updating your -package list should install trigon on your system. +package list should install Trigon on your system. If you want to use the cutting-edge development version of Trigon, you can install it manually by following these steps: @@ -77,7 +77,7 @@ install it manually by following these steps: ### Overleaf -Since October 2021, [TexLive 2011 is availabe on +Since October 2021, [TexLive 2021 is available on Overleaf](https://www.overleaf.com/blog/tex-live-2021-now-available). Trigon is therefore automatically supported for new documents. If you want to switch older documents to use the Trigon theme, you need to [select TexLive 2021 or higher as @@ -85,7 +85,7 @@ your TeX Live version](https://www.overleaf.com/blog/new-feature-select-your-tex-live-compiler-version) (this may cause issues with other packages used in your presentation). -In addition to that, a template project was created and is publicly availabe in +In addition to that, a template project was created and is publicly available in the [Overleaf Gallery][overleaf-gallery] to bootstrap your presentation. ## Usage diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/demo/trigon_demo.pdf b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/demo/trigon_demo.pdf Binary files differindex 157574bf15..0b5b1c54dd 100644 --- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/demo/trigon_demo.pdf +++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/demo/trigon_demo.pdf diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/docs/trigontheme.pdf b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/docs/trigontheme.pdf Binary files differindex f70379b53a..44f97f0726 100644 --- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/docs/trigontheme.pdf +++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/docs/trigontheme.pdf diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamercolorthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamercolorthemetrigon.dtx index 9e5780a7e7..e45237be4d 100644 --- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamercolorthemetrigon.dtx +++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamercolorthemetrigon.dtx @@ -13,7 +13,7 @@ % \iffalse %<*package> \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{beamercolorthemetrigon}[2022/03/10 v0.6.3 Trigon color theme] +\ProvidesPackage{beamercolorthemetrigon}[2022/03/19 v0.6.4 Trigon color theme] %</package> % \fi % \CheckSum{0} diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerfontthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerfontthemetrigon.dtx index 0d2d1b15ba..d3c8c302d5 100644 --- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerfontthemetrigon.dtx +++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerfontthemetrigon.dtx @@ -13,7 +13,7 @@ % \iffalse %<*package> \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{beamerfontthemetrigon}[2022/03/10 v0.6.3 Trigon font theme] +\ProvidesPackage{beamerfontthemetrigon}[2022/03/19 v0.6.4 Trigon font theme] %</package> % \fi % \CheckSum{0} diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerinnerthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerinnerthemetrigon.dtx index 5726c1a543..a0adf0a1c4 100644 --- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerinnerthemetrigon.dtx +++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerinnerthemetrigon.dtx @@ -13,7 +13,7 @@ % \iffalse %<*package> \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{beamerinnerthemetrigon}[2022/03/10 v0.6.3 Trigon inner theme] +\ProvidesPackage{beamerinnerthemetrigon}[2022/03/19 v0.6.4 Trigon inner theme] %</package> % \fi % \CheckSum{0} @@ -51,9 +51,9 @@ % |\includegraphics|, so it accepts the same options. % \begin{macrocode} \def\logbig{} -\newcommand\biglogo[2][width=0.28\textwidth]{ - \ifx#2\@empty\else - \def\logbig{\includegraphics[#1]{#2}} +\newcommand*\biglogo[2][width=0.28\textwidth]{ + \ifx{#2}\@empty\else + \edef\logbig{\includegraphics[#1]{#2}} \fi } % \end{macrocode} diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerouterthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerouterthemetrigon.dtx index de5dc23c16..29eaa37c40 100644 --- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerouterthemetrigon.dtx +++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerouterthemetrigon.dtx @@ -13,7 +13,7 @@ % \iffalse %<*package> \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{beamerouterthemetrigon}[2022/03/10 v0.6.3 Trigon outer theme] +\ProvidesPackage{beamerouterthemetrigon}[2022/03/19 v0.6.4 Trigon outer theme] %</package> % \fi % \CheckSum{0} @@ -41,10 +41,10 @@ % |\includegraphics|, so it accepts the same options. % \begin{macrocode} \def\logsmall{} -\newcommand\smalllogo[2][width=20pt]{ - \ifx#2\@empty\else - \def\logsmall{\includegraphics[#1]{#2}} - \fi +\newcommand*\smalllogo[2][width=20pt]{ +\ifx{#2}\@empty\else + \edef\logsmall{\includegraphics[#1]{#2}} +\fi } % \end{macrocode} % diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerthemetrigon.dtx index f2c56ad5ea..71fd1a5978 100644 --- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerthemetrigon.dtx +++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerthemetrigon.dtx @@ -13,7 +13,7 @@ % \iffalse %<*package> \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{beamerthemetrigon}[2022/03/10 v0.6.3 Trigon Beamer theme] +\ProvidesPackage{beamerthemetrigon}[2022/03/19 v0.6.4 Trigon Beamer theme] %</package> % \fi % \CheckSum{0} diff --git a/macros/latex/contrib/functional/README.txt b/macros/latex/contrib/functional/README.txt index fcb1672c0c..58c2081c9a 100644 --- a/macros/latex/contrib/functional/README.txt +++ b/macros/latex/contrib/functional/README.txt @@ -1,4 +1,4 @@ -Functional: LaTeX2 functional interfaces to LaTeX3 programming layer +Functional: LaTeX2 functional interfaces for LaTeX3 programming layer Copyright : 2022 (c) Jianrui Lyu <tolvjr@163.com> Repository: https://github.com/lvjr/functional Repository: https://bitbucket.org/lvjr/functional diff --git a/macros/latex/contrib/functional/functional.pdf b/macros/latex/contrib/functional/functional.pdf Binary files differindex f9f553a0da..e4f7ca1b8f 100644 --- a/macros/latex/contrib/functional/functional.pdf +++ b/macros/latex/contrib/functional/functional.pdf diff --git a/macros/latex/contrib/functional/functional.sty b/macros/latex/contrib/functional/functional.sty index 95e5ada3dc..dcc863b3c5 100644 --- a/macros/latex/contrib/functional/functional.sty +++ b/macros/latex/contrib/functional/functional.sty @@ -1,22 +1,24 @@ %%% -*- coding: utf-8 -*- %% ---------------------------------------------------------------------------- -%% Functional: LaTeX2 functional interfaces to LaTeX3 programming layer +%% Functional: LaTeX2 functional interfaces for LaTeX3 programming layer %% Copyright : 2022 (c) Jianrui Lyu <tolvjr@163.com> %% Repository: https://github.com/lvjr/functional +%% Repository: https://bitbucket.org/lvjr/functional %% License : The LaTeX Project Public License 1.3c %% ---------------------------------------------------------------------------- %%% -------------------------------------------------------- -%%> \section{Interfaces for Function Definitions (l3basics)} +%%> \section{Interfaces for Functional Programming (Prg)} %%% -------------------------------------------------------- \NeedsTeXFormat{LaTeX2e}[2018-04-01] \RequirePackage{expl3} -\ProvidesExplPackage{functional}{2022-03-10}{2022A} - {^^JLaTeX2 functional interfaces to LaTeX3 programming layer} +\ProvidesExplPackage{functional}{2022-03-19}{2022B} + {^^JLaTeX2 functional interfaces for LaTeX3 programming layer} \cs_generate_variant:Nn \iow_log:n { V } +\cs_generate_variant:Nn \tl_log:n { e } \cs_generate_variant:Nn \tl_set:Nn { Ne } \tl_new:N \gResultTl @@ -51,16 +53,6 @@ \tl_const:Nn \c__fun_parameter_called_vii_tl { {#7} } \tl_const:Nn \c__fun_parameter_called_viii_tl { {#8} } \tl_const:Nn \c__fun_parameter_called_ix_tl { {#9} } -\tl_new:N \l__fun_argument_tl -\tl_new:N \l__fun_argument_i_tl -\tl_new:N \l__fun_argument_ii_tl -\tl_new:N \l__fun_argument_iii_tl -\tl_new:N \l__fun_argument_iv_tl -\tl_new:N \l__fun_argument_v_tl -\tl_new:N \l__fun_argument_vi_tl -\tl_new:N \l__fun_argument_vii_tl -\tl_new:N \l__fun_argument_viii_tl -\tl_new:N \l__fun_argument_ix_tl %% #1: function name; #2: argument specification; #3 function body \cs_new_protected:Npn \__fun_new_function:Nnn #1 #2 #3 @@ -113,13 +105,18 @@ \cs_set_eq:NN \PrgNewConditional \__fun_new_conditional:Nnn +\int_new:N \g__fun_nesting_level_int + %% #1: function name; #2: argument specifications; #3 parameters tl defined %% Some times we need to create a function without arguments \cs_new_protected:Npn \__fun_new_with_arg_:Nnn #1 #2 #3 { \cs_new_protected:Npn #1 #3 { + \int_gincr:N \g__fun_nesting_level_int \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_:Nnn { NnV } @@ -129,8 +126,11 @@ { \cs_new_protected:Npn #1 #3 { - \tl_set:Nn \l__fun_argument_i_tl { ##1 } + \int_gincr:N \g__fun_nesting_level_int + \__fun_one_argument_gset:nn { 1 } { ##1 } \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_i:Nnn { NnV } @@ -140,9 +140,12 @@ { \cs_new_protected:Npn #1 #3 { - \tl_set:Nn \l__fun_argument_i_tl { ##1 } - \tl_set:Nn \l__fun_argument_ii_tl { ##2 } + \int_gincr:N \g__fun_nesting_level_int + \__fun_one_argument_gset:nn { 1 } { ##1 } + \__fun_one_argument_gset:nn { 2 } { ##2 } \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_ii:Nnn { NnV } @@ -152,10 +155,13 @@ { \cs_new_protected:Npn #1 #3 { - \tl_set:Nn \l__fun_argument_i_tl { ##1 } - \tl_set:Nn \l__fun_argument_ii_tl { ##2 } - \tl_set:Nn \l__fun_argument_iii_tl { ##3 } + \int_gincr:N \g__fun_nesting_level_int + \__fun_one_argument_gset:nn { 1 } { ##1 } + \__fun_one_argument_gset:nn { 2 } { ##2 } + \__fun_one_argument_gset:nn { 3 } { ##3 } \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_iii:Nnn { NnV } @@ -165,11 +171,14 @@ { \cs_new_protected:Npn #1 #3 { - \tl_set:Nn \l__fun_argument_i_tl { ##1 } - \tl_set:Nn \l__fun_argument_ii_tl { ##2 } - \tl_set:Nn \l__fun_argument_iii_tl { ##3 } - \tl_set:Nn \l__fun_argument_iv_tl { ##4 } + \int_gincr:N \g__fun_nesting_level_int + \__fun_one_argument_gset:nn { 1 } { ##1 } + \__fun_one_argument_gset:nn { 2 } { ##2 } + \__fun_one_argument_gset:nn { 3 } { ##3 } + \__fun_one_argument_gset:nn { 4 } { ##4 } \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_iv:Nnn { NnV } @@ -179,12 +188,15 @@ { \cs_new_protected:Npn #1 #3 { - \tl_set:Nn \l__fun_argument_i_tl { ##1 } - \tl_set:Nn \l__fun_argument_ii_tl { ##2 } - \tl_set:Nn \l__fun_argument_iii_tl { ##3 } - \tl_set:Nn \l__fun_argument_iv_tl { ##4 } - \tl_set:Nn \l__fun_argument_v_tl { ##5 } + \int_gincr:N \g__fun_nesting_level_int + \__fun_one_argument_gset:nn { 1 } { ##1 } + \__fun_one_argument_gset:nn { 2 } { ##2 } + \__fun_one_argument_gset:nn { 3 } { ##3 } + \__fun_one_argument_gset:nn { 4 } { ##4 } + \__fun_one_argument_gset:nn { 5 } { ##5 } \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_v:Nnn { NnV } @@ -194,13 +206,16 @@ { \cs_new_protected:Npn #1 #3 { - \tl_set:Nn \l__fun_argument_i_tl { ##1 } - \tl_set:Nn \l__fun_argument_ii_tl { ##2 } - \tl_set:Nn \l__fun_argument_iii_tl { ##3 } - \tl_set:Nn \l__fun_argument_iv_tl { ##4 } - \tl_set:Nn \l__fun_argument_v_tl { ##5 } - \tl_set:Nn \l__fun_argument_vi_tl { ##6 } + \int_gincr:N \g__fun_nesting_level_int + \__fun_one_argument_gset:nn { 1 } { ##1 } + \__fun_one_argument_gset:nn { 2 } { ##2 } + \__fun_one_argument_gset:nn { 3 } { ##3 } + \__fun_one_argument_gset:nn { 4 } { ##4 } + \__fun_one_argument_gset:nn { 5 } { ##5 } + \__fun_one_argument_gset:nn { 6 } { ##6 } \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_vi:Nnn { NnV } @@ -210,14 +225,17 @@ { \cs_new_protected:Npn #1 #3 { - \tl_set:Nn \l__fun_argument_i_tl { ##1 } - \tl_set:Nn \l__fun_argument_ii_tl { ##2 } - \tl_set:Nn \l__fun_argument_iii_tl { ##3 } - \tl_set:Nn \l__fun_argument_iv_tl { ##4 } - \tl_set:Nn \l__fun_argument_v_tl { ##5 } - \tl_set:Nn \l__fun_argument_vi_tl { ##6 } - \tl_set:Nn \l__fun_argument_vii_tl { ##7 } + \int_gincr:N \g__fun_nesting_level_int + \__fun_one_argument_gset:nn { 1 } { ##1 } + \__fun_one_argument_gset:nn { 2 } { ##2 } + \__fun_one_argument_gset:nn { 3 } { ##3 } + \__fun_one_argument_gset:nn { 4 } { ##4 } + \__fun_one_argument_gset:nn { 5 } { ##5 } + \__fun_one_argument_gset:nn { 6 } { ##6 } + \__fun_one_argument_gset:nn { 7 } { ##7 } \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_vii:Nnn { NnV } @@ -227,15 +245,18 @@ { \cs_new_protected:Npn #1 #3 { - \tl_set:Nn \l__fun_argument_i_tl { ##1 } - \tl_set:Nn \l__fun_argument_ii_tl { ##2 } - \tl_set:Nn \l__fun_argument_iii_tl { ##3 } - \tl_set:Nn \l__fun_argument_iv_tl { ##4 } - \tl_set:Nn \l__fun_argument_v_tl { ##5 } - \tl_set:Nn \l__fun_argument_vi_tl { ##6 } - \tl_set:Nn \l__fun_argument_vii_tl { ##7 } - \tl_set:Nn \l__fun_argument_viii_tl { ##8 } + \int_gincr:N \g__fun_nesting_level_int + \__fun_one_argument_gset:nn { 1 } { ##1 } + \__fun_one_argument_gset:nn { 2 } { ##2 } + \__fun_one_argument_gset:nn { 3 } { ##3 } + \__fun_one_argument_gset:nn { 4 } { ##4 } + \__fun_one_argument_gset:nn { 5 } { ##5 } + \__fun_one_argument_gset:nn { 6 } { ##6 } + \__fun_one_argument_gset:nn { 7 } { ##7 } + \__fun_one_argument_gset:nn { 8 } { ##8 } \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_viii:Nnn { NnV } @@ -245,39 +266,39 @@ { \cs_new_protected:Npn #1 #3 { - \tl_set:Nn \l__fun_argument_i_tl { ##1 } - \tl_set:Nn \l__fun_argument_ii_tl { ##2 } - \tl_set:Nn \l__fun_argument_iii_tl { ##3 } - \tl_set:Nn \l__fun_argument_iv_tl { ##4 } - \tl_set:Nn \l__fun_argument_v_tl { ##5 } - \tl_set:Nn \l__fun_argument_vi_tl { ##6 } - \tl_set:Nn \l__fun_argument_vii_tl { ##7 } - \tl_set:Nn \l__fun_argument_viii_tl { ##8 } - \tl_set:Nn \l__fun_argument_ix_tl { ##9 } + \int_gincr:N \g__fun_nesting_level_int + \__fun_one_argument_gset:nn { 1 } { ##1 } + \__fun_one_argument_gset:nn { 2 } { ##2 } + \__fun_one_argument_gset:nn { 3 } { ##3 } + \__fun_one_argument_gset:nn { 4 } { ##4 } + \__fun_one_argument_gset:nn { 5 } { ##5 } + \__fun_one_argument_gset:nn { 6 } { ##6 } + \__fun_one_argument_gset:nn { 7 } { ##7 } + \__fun_one_argument_gset:nn { 8 } { ##8 } + \__fun_one_argument_gset:nn { 9 } { ##9 } \__fun_evaluate:Nn #1 {#2} + \int_gdecr:N \g__fun_nesting_level_int + \__fun_return_result: } } \cs_generate_variant:Nn \__fun_new_with_arg_ix:Nnn { NnV } -\int_new:N \g__fun_nesting_level_int -\int_new:N \l__fun_argtype_number_int \tl_new:N \l__fun_argtype_tl \tl_const:Nn \c__fun_argtype_m_tl { m } \tl_const:Nn \c__fun_argtype_M_tl { M } \tl_const:Nn \c__fun_argtype_n_tl { n } \tl_const:Nn \c__fun_argtype_N_tl { N } +\tl_new:N \l__fun_argument_tl %% #1: function name; #2: argument specifications \cs_new_protected:Npn \__fun_evaluate:Nn #1 #2 { - \int_zero:N \l__fun_argtype_number_int - \int_gincr:N \g__fun_nesting_level_int + \__fun_argtype_index_gzero: \__fun_arguments_gclear: \tl_map_variable:nNn { #2 } \l__fun_argtype_tl % spaces are ignored { - \int_incr:N \l__fun_argtype_number_int - \tl_set_eq:Nc \l__fun_argument_tl - { l__fun_argument_ \int_to_roman:n { \l__fun_argtype_number_int } _tl } + \__fun_argtype_index_gincr: + \__fun_one_argument_get:eN { \__fun_argtype_index_use: } \l__fun_argument_tl \tl_case:Nn \l__fun_argtype_tl { \c__fun_argtype_m_tl @@ -300,19 +321,14 @@ } \__fun_arguments_log:N #1 \__fun_arguments_called:c { __fun_defined_ \cs_to_str:N #1 : w } - \int_gdecr:N \g__fun_nesting_level_int - \__fun_return_result: } -\cs_set_eq:NN \__fun_cs_temp:w \scan_stop: - \cs_new_protected:Npn \__fun_evaluate_and_put_argument:N #1 { - \cs_set_eq:Nc \__fun_cs_temp:w + \cs_if_exist:cTF { __fun_defined_ \exp_last_unbraced:Ne \cs_to_str:N { \tl_head:N #1 } : w } - \cs_if_exist:NTF \__fun_cs_temp:w { #1 \__fun_arguments_gput:e { { \exp_not:V \gResultTl } } @@ -322,6 +338,57 @@ } } +%% #1: argument number; #2: token lists +\cs_new_protected:Npn \__fun_one_argument_gset:nn #1 #2 + { + \tl_gset:cn + { g__fun_one_argument_ \int_use:N \g__fun_nesting_level_int _#1_tl } { #2 } + %\__fun_one_argument_log:nn { #1 } { set } + } + +%% #1: argument number; #2: variable of token lists +\cs_new_protected:Npn \__fun_one_argument_get:nN #1 #2 + { + \tl_set_eq:Nc + #2 { g__fun_one_argument_ \int_use:N \g__fun_nesting_level_int _ #1 _tl } + %\__fun_one_argument_log:nn { #1 } { get } + } +\cs_generate_variant:Nn \__fun_one_argument_get:nN { eN } + +%% #1: argument number; #2: get or set +\cs_new_protected:Npn \__fun_one_argument_log:nn #1 #2 + { + \tl_log:e + { + #2 ~ level _ \int_use:N \g__fun_nesting_level_int _ arg _ #1 ~ = ~ + \exp_not:v + { g__fun_one_argument_ \int_use:N \g__fun_nesting_level_int _#1_tl } + } + } + +\int_new:c { g__fun_argtype_index_ 1 _int } +\int_new:c { g__fun_argtype_index_ 2 _int } +\int_new:c { g__fun_argtype_index_ 3 _int } +\int_new:c { g__fun_argtype_index_ 4 _int } +\int_new:c { g__fun_argtype_index_ 5 _int } + +\cs_new_protected:Npn \__fun_argtype_index_gzero: + { + \int_gzero_new:c + { g__fun_argtype_index_ \int_use:N \g__fun_nesting_level_int _int } + } + +\cs_new_protected:Npn \__fun_argtype_index_gincr: + { + \int_gincr:c + { g__fun_argtype_index_ \int_use:N \g__fun_nesting_level_int _int } + } + +\cs_new:Npn \__fun_argtype_index_use: + { + \int_use:c { g__fun_argtype_index_ \int_use:N \g__fun_nesting_level_int _int } + } + \cs_new_protected:Npn \__fun_arguments_called:N #1 { \exp_last_unbraced:Nv @@ -350,6 +417,12 @@ } \cs_generate_variant:Nn \__fun_arguments_gput:n { e } +\cs_set_eq:NN \Break \prg_break: +\cs_set_eq:NN \PrgBreak \prg_break: + +\cs_set_eq:NN \BreakDo \prg_break:n +\cs_set_eq:NN \PrgBreakDo \prg_break:n + \cs_new_protected:Npn \__fun_put_result:n #1 { \tl_gput_right:Nn \gResultTl { #1 } @@ -361,27 +434,6 @@ \__fun_put_result:n { #1 } } -\PrgNewFunction \Name { m } - { - \exp_args:Nc \__fun_put_result:n { #1 } - } -\cs_set_eq:NN \UseName \Name - -\PrgNewFunction \Expand { m } - { - \__fun_put_result:e { #1 } - } -\cs_set_eq:NN \UseExpand \Expand - -\PrgNewFunction \Value { M } - { - \__fun_put_result:V #1 - } -\cs_set_eq:NN \UseValue \Value - -\cs_set_eq:NN \ExpNot \exp_not:n -\cs_set_eq:NN \ExpValue \exp_not:V - \cs_new_protected:Npn \__fun_return_result: { \int_compare:nNnT { \g__fun_nesting_level_int } = { 0 } @@ -484,28 +536,50 @@ \Functional { scoping = false, tracing = false } -\PrgNewFunction \UseOne { n } +\cs_new_protected:Npn \__fun_ignore_spaces_on: { - \Result { #1 } + \ExplSyntaxOn + \char_set_catcode_math_subscript:N \_ + \char_set_catcode_other:N \: } +\cs_set_eq:NN \IgnoreSpacesOn \__fun_ignore_spaces_on: +\cs_set_eq:NN \IgnoreSpacesOff \ExplSyntaxOff -\PrgNewFunction \GobbleOne { n } +%%% -------------------------------------------------------- +%%> \section{Interfaces for Argument Using (Use)} +%%% -------------------------------------------------------- + +\PrgNewFunction \Name { m } { - \Result { } + \exp_args:Nc \__fun_put_result:n { #1 } } +\cs_set_eq:NN \UseName \Name -\PrgNewFunction \UseGobble { n n } +\PrgNewFunction \Value { M } { - \UseOne { #1 } + \__fun_put_result:V #1 } +\cs_set_eq:NN \UseValue \Value -\PrgNewFunction \GobbleUse { n n } +\PrgNewFunction \Expand { m } { - \UseOne { #2 } + \__fun_put_result:e { #1 } } +\cs_set_eq:NN \UseExpand \Expand + +\cs_set_eq:NN \ExpNot \exp_not:n +\cs_set_eq:NN \ExpValue \exp_not:V + +\PrgNewFunction \UseOne { n } { \Result { #1 } } + +\PrgNewFunction \GobbleOne { n } { \Result { } } + +\PrgNewFunction \UseGobble { n n } { \UseOne { #1 } } + +\PrgNewFunction \GobbleUse { n n } { \UseOne { #2 } } %%% -------------------------------------------------------- -%%> \section{Interfaces for Control Structures (l3prg)} +%%> \section{Interfaces for Control Structures (Bool)} %%% -------------------------------------------------------- \bool_const:Nn \cTrueBool { \c_true_bool } @@ -519,8 +593,14 @@ \bool_new:N \gTmpiBool \bool_new:N \gTmpjBool \bool_new:N \gTmpkBool \bool_new:N \g@Funx@Bool \bool_new:N \g@Funy@Bool \bool_new:N \g@Funz@Bool -\cs_set_eq:NN \BoolNew \bool_new:N -\cs_set_eq:NN \BoolLog \bool_log:N +\PrgNewFunction \BoolNew { M } { \bool_new:N #1 } + +\PrgNewFunction \BoolConst { M m } { \bool_const:Nn #1 { #2 } } + +\PrgNewFunction \BoolSet { M m } { + \__fun_do_assignment:Nnn #1 + { \bool_gset:Nn #1 { #2 } } { \bool_set:Nn #1 { #2 } } +} \PrgNewFunction \BoolSetTrue { M } { @@ -532,15 +612,59 @@ \__fun_do_assignment:Nnn #1 { \bool_gset_false:N #1 } { \bool_set_false:N #1 } } -\PrgNewConditional \BoolIf { N } +\PrgNewFunction \BoolSetEq { M M } { - \Result { #1 } + \__fun_do_assignment:Nnn #1 + { \bool_gset_eq:NN #1 #2 } { \bool_set_eq:NN #1 #2 } + } + +\PrgNewFunction \BoolLog { m } { \bool_log:n { #1 } } + +\PrgNewFunction \BoolVarLog { M } { \bool_log:N #1 } + +\PrgNewFunction \BoolShow { m } { \bool_show:n { #1 } } + +\PrgNewFunction \BoolVarShow { M } { \bool_show:N #1 } + +\PrgNewConditional \BoolIfExist { M } + { + \bool_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \BoolVarIf { M } { \Result { #1 } } + +\PrgNewConditional \BoolVarNot { M } + { + \bool_if:NTF #1 + { \Result { \cFalseBool } } { \Result { \cTrueBool } } + } + +\PrgNewConditional \BoolVarAnd { M M } + { + \bool_lazy_and:nnTF {#1} {#2} + { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \BoolVarOr { M M } + { + \bool_lazy_or:nnTF {#1} {#2} + { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \BoolVarXor { M M } + { + \bool_xor:nnTF {#1} {#2} + { \Result { \cTrueBool } } { \Result { \cFalseBool } } } %%% -------------------------------------------------------- -%%> \section{Interfaces for Token Lists (l3tl)} +%%> \section{Interfaces for Token Lists (Tl)} %%% -------------------------------------------------------- +\tl_set_eq:NN \cEmptyTl \c_empty_tl +\tl_set_eq:NN \cSpaceTl \c_space_tl +\tl_set_eq:NN \cNoValueTl \c_novalue_tl + \tl_new:N \lTmpaTl \tl_new:N \lTmpbTl \tl_new:N \lTmpcTl \tl_new:N \lTmpiTl \tl_new:N \lTmpjTl \tl_new:N \lTmpkTl \tl_new:N \l@Funx@Tl \tl_new:N \l@Funy@Tl \tl_new:N \l@Funz@Tl @@ -549,17 +673,48 @@ \tl_new:N \gTmpiTl \tl_new:N \gTmpjTl \tl_new:N \gTmpkTl \tl_new:N \g@Funx@Tl \tl_new:N \g@Funy@Tl \tl_new:N \g@Funz@Tl -\cs_set_eq:NN \TlNew \tl_new:N -\cs_set_eq:NN \TlLog \tl_log:N +\PrgNewFunction \TlNew { M } { \tl_new:N #1 } + +\PrgNewFunction \TlLog { m } { \tl_log:n { #1 } } + +\PrgNewFunction \TlVarLog { M } { \tl_log:N #1 } + +\PrgNewFunction \TlShow { m } { \tl_show:n { #1 } } + +\PrgNewFunction \TlVarShow { M } { \tl_show:N #1 } + +\PrgNewFunction \TlUse { M } { \Result { \Value #1 } } + +\PrgNewFunction \TlToStr { m } { \Expand { \tl_to_str:n { #1 } } } + +\PrgNewFunction \TlVarToStr { M } { \Expand { \tl_to_str:N #1 } } + +\PrgNewFunction \TlConst { M m } { \tl_const:Nn #1 { #2 } } + +\PrgNewFunction \TlSet { M m } + { + \__fun_do_assignment:Nnn #1 { \tl_gset:Nn #1 {#2} } { \tl_set:Nn #1 {#2} } + } + +\PrgNewFunction \TlSetEq { M M } + { + \__fun_do_assignment:Nnn #1 { \tl_gset_eq:NN #1 #2 } { \tl_set_eq:NN #1 #2 } + } + +\PrgNewFunction \TlConcat { M M M } + { + \__fun_do_assignment:Nnn #1 + { \tl_gconcat:NNN #1 #2 #3 } { \tl_concat:NNN #1 #2 #3 } + } \PrgNewFunction \TlClear { M } { \__fun_do_assignment:Nnn #1 { \tl_gclear:N #1 } { \tl_clear:N #1 } } -\PrgNewFunction \TlSet { M m } +\PrgNewFunction \TlClearNew { M } { - \__fun_do_assignment:Nnn #1 { \tl_gset:Nn #1 {#2} } { \tl_set:Nn #1 {#2} } + \__fun_do_assignment:Nnn #1 { \tl_gclear_new:N #1 } { \tl_clear_new:N #1 } } \PrgNewFunction \TlPutLeft { M m } @@ -574,29 +729,339 @@ { \tl_gput_right:Nn #1 {#2} } { \tl_put_right:Nn #1 {#2} } } -\PrgNewFunction \TlUse { M } +\PrgNewFunction \TlReplaceOnce { M m m } { - \Result { \Value #1 } + \__fun_do_assignment:Nnn #1 + { \tl_greplace_once:Nnn #1 {#2} {#3} } { \tl_replace_once:Nnn #1 {#2} {#3} } } -\PrgNewConditional \TlIfEmpty { N } +\PrgNewFunction \TlReplaceAll { M m m } { - \tl_if_empty:NTF #1 - { \Result { \cTrueBool } } - { \Result { \cFalseBool } } + \__fun_do_assignment:Nnn #1 + { \tl_greplace_all:Nnn #1 {#2} {#3} } { \tl_replace_all:Nnn #1 {#2} {#3} } + } + +\PrgNewFunction \TlRemoveOnce { M m } + { + \__fun_do_assignment:Nnn #1 + { \tl_gremove_once:Nn #1 {#2} } { \tl_remove_once:Nn #1 {#2} } + } + +\PrgNewFunction \TlRemoveAll { M m } + { + \__fun_do_assignment:Nnn #1 + { \tl_gremove_all:Nn #1 {#2} } { \tl_remove_all:Nn #1 {#2} } + } + +\PrgNewFunction \TlTrimSpaces { m } { \Expand { \tl_trim_spaces:n { #1 } } } + +\PrgNewFunction \TlVarTrimSpaces { M } + { + \__fun_do_assignment:Nnn #1 { \tl_gtrim_spaces:N #1 } { \tl_trim_spaces:N #1 } + } + +\PrgNewFunction \TlCount { m } { \Expand { \tl_count:n { #1 } } } + +\PrgNewFunction \TlVarCount { M } { \Expand { \tl_count:N #1 } } + +\PrgNewFunction \TlHead { m } { \Expand { \tl_head:n { #1 } } } + +\PrgNewFunction \TlVarHead { M } { \Expand { \tl_head:N #1 } } + +\PrgNewFunction \TlTail { m } { \Expand { \tl_tail:n { #1 } } } + +\PrgNewFunction \TlVarTail { M } { \Expand { \tl_tail:N #1 } } + +\PrgNewFunction \TlItem { m m } { \Expand { \tl_item:nn {#1} {#2} } } + +\PrgNewFunction \TlVarItem { M m } { \Expand { \tl_item:Nn #1 {#2} } } + +\PrgNewFunction \TlRandItem { m } { \Expand { \tl_rand_item:n {#1} } } + +\PrgNewFunction \TlVarRandItem { M } { \Expand { \tl_rand_item:N #1 } } + +\PrgNewFunction \TlVarCase { M m } { \tl_case:Nn {#1} {#2} } +\PrgNewFunction \TlVarCaseT { M m n } { \tl_case:NnT {#1} {#2} {#3} } +\PrgNewFunction \TlVarCaseF { M m n } { \tl_case:NnF {#1} {#2} {#3} } +\PrgNewFunction \TlVarCaseTF { M m n n } { \tl_case:NnTF {#1} {#2} {#3} {#4} } + +\PrgNewFunction \TlMapInline { m n } + { + \tl_map_inline:nn {#1} {#2} + } + +\PrgNewFunction \TlVarMapInline { M n } + { + \tl_map_inline:Nn #1 {#2} + } + +\PrgNewFunction \TlMapVariable { m M n } + { + \tl_map_variable:nNn {#1} #2 {#3} + } + +\PrgNewFunction \TlVarMapVariable { M M n } + { + \tl_map_variable:NNn #1 #2 {#3} + } + +\PrgNewConditional \TlIfExist { M } + { + \tl_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \TlIfEmpty { m } + { + \tl_if_empty:nTF {#1} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \TlVarIfEmpty { M } + { + \tl_if_empty:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \TlIfBlank { m } + { + \tl_if_blank:nTF {#1} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \TlIfEq { m m } + { + \tl_if_eq:nnTF {#1} {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \TlVarIfEq { M M } + { + \tl_if_eq:NNTF #1 #2 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \TlIfIn { m m } + { + \tl_if_in:nnTF {#1} {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \TlVarIfIn { M m } + { + \tl_if_in:NnTF #1 {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \TlIfSingle { m } + { + \tl_if_single:nTF {#1} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \TlVarIfSingle { M } + { + \tl_if_single:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +%%% -------------------------------------------------------- +%%> \section{Interfaces for Strings (Str)} +%%% -------------------------------------------------------- + +\str_set_eq:NN \cAmpersandStr \c_ampersand_str +\str_set_eq:NN \cAttignStr \c_atsign_str +\str_set_eq:NN \cBackslashStr \c_backslash_str +\str_set_eq:NN \cLeftBraceStr \c_left_brace_str +\str_set_eq:NN \cRightBraceStr \c_right_brace_str +\str_set_eq:NN \cCircumflexStr \c_circumflex_str +\str_set_eq:NN \cColonStr \c_colon_str +\str_set_eq:NN \cDollarStr \c_dollar_str +\str_set_eq:NN \cHashStr \c_hash_str +\str_set_eq:NN \cPercentStr \c_percent_str +\str_set_eq:NN \cTildeStr \c_tilde_str +\str_set_eq:NN \cUnderscoreStr \c_underscore_str +\str_set_eq:NN \cZeroStr \c_zero_str + +\str_new:N \lTmpaStr \str_new:N \lTmpbStr \str_new:N \lTmpcStr +\str_new:N \lTmpiStr \str_new:N \lTmpjStr \str_new:N \lTmpkStr +\str_new:N \l@Funx@Str \str_new:N \l@Funy@Str \str_new:N \l@Funz@Str + +\str_new:N \gTmpaStr \str_new:N \gTmpbStr \str_new:N \gTmpcStr +\str_new:N \gTmpiStr \str_new:N \gTmpjStr \str_new:N \gTmpkStr +\str_new:N \g@Funx@Str \str_new:N \g@Funy@Str \str_new:N \g@Funz@Str + +\PrgNewFunction \StrNew { M } { \str_new:N #1 } + +\PrgNewFunction \StrLog { m } { \str_log:n { #1 } } + +\PrgNewFunction \StrVarLog { M } { \str_log:N #1 } + +\PrgNewFunction \StrShow { m } { \str_show:n { #1 } } + +\PrgNewFunction \StrVarShow { M } { \str_show:N #1 } + +\PrgNewFunction \StrUse { M } { \Result { \Value #1 } } + +\PrgNewFunction \StrConst { M m } { \str_const:Nn #1 {#2} } + +\PrgNewFunction \StrSet { M m } + { + \__fun_do_assignment:Nnn #1 { \str_gset:Nn #1 {#2} } { \str_set:Nn #1 {#2} } + } + +\PrgNewFunction \StrSetEq { M M } + { + \__fun_do_assignment:Nnn #1 { \str_gset_eq:NN #1 #2 } { \str_set_eq:NN #1 #2 } + } + +\PrgNewFunction \StrConcat { M M M } + { + \__fun_do_assignment:Nnn #1 + { \str_gconcat:NNN #1 #2 #3 } { \str_concat:NNN #1 #2 #3 } + } + +\PrgNewFunction \StrClear { M } + { + \__fun_do_assignment:Nnn #1 { \str_gclear:N #1 } { \str_clear:N #1 } + } + +\PrgNewFunction \StrClearNew { M } + { + \__fun_do_assignment:Nnn #1 { \str_gclear_new:N #1 } { \str_clear_new:N #1 } + } + +\PrgNewFunction \StrPutLeft { M m } + { + \__fun_do_assignment:Nnn #1 + { \str_gput_left:Nn #1 {#2} } { \str_put_left:Nn #1 {#2} } + } + +\PrgNewFunction \StrPutRight { M m } + { + \__fun_do_assignment:Nnn #1 + { \str_gput_right:Nn #1 {#2} } { \str_put_right:Nn #1 {#2} } + } + +\PrgNewFunction \StrReplaceOnce { M m m } + { + \__fun_do_assignment:Nnn #1 + { \str_greplace_once:Nnn #1 {#2} {#3} } { \str_replace_once:Nnn #1 {#2} {#3} } + } + +\PrgNewFunction \StrReplaceAll { M m m } + { + \__fun_do_assignment:Nnn #1 + { \str_greplace_all:Nnn #1 {#2} {#3} } { \str_replace_all:Nnn #1 {#2} {#3} } + } + +\PrgNewFunction \StrRemoveOnce { M m } + { + \__fun_do_assignment:Nnn #1 + { \str_gremove_once:Nn #1 {#2} } { \str_remove_once:Nn #1 {#2} } } -\PrgNewConditional \TlIfEq { N N } +\PrgNewFunction \StrRemoveAll { M m } { - \tl_if_eq:NNTF #1 #2 + \__fun_do_assignment:Nnn #1 + { \str_gremove_all:Nn #1 {#2} } { \str_remove_all:Nn #1 {#2} } + } + +%% Avoid naming confict with xstring package +\cs_if_exist:NF \StrCount + { \PrgNewFunction \StrCount { m } { \Expand { \str_count:n { #1 } } } } + +%% Provide another name for \StrCount function +\PrgNewFunction \StrSize { m } { \Expand { \str_count:n { #1 } } } + +\PrgNewFunction \StrVarCount { M } { \Expand { \str_count:N #1 } } + +\PrgNewFunction \StrHead { m } { \Expand { \str_head:n { #1 } } } + +\PrgNewFunction \StrVarHead { M } { \Expand { \str_head:N #1 } } + +\PrgNewFunction \StrTail { m } { \Expand { \str_tail:n { #1 } } } + +\PrgNewFunction \StrVarTail { M } { \Expand { \str_tail:N #1 } } + +\PrgNewFunction \StrItem { m m } { \Expand { \str_item:nn {#1} {#2} } } + +\PrgNewFunction \StrVarItem { M m } { \Expand { \str_item:Nn #1 {#2} } } + +\PrgNewFunction \StrCase { m m } { \str_case:nn {#1} {#2} } +\PrgNewFunction \StrCaseT { m m n } { \str_case:nnT {#1} {#2} {#3} } +\PrgNewFunction \StrCaseF { m m n } { \str_case:nnF {#1} {#2} {#3} } +\PrgNewFunction \StrCaseTF { m m n n } { \str_case:nnTF {#1} {#2} {#3} {#4} } + +\PrgNewFunction \StrMapInline { m n } + { + \str_map_inline:nn {#1} {#2} + } + +\PrgNewFunction \StrVarMapInline { M n } + { + \str_map_inline:Nn #1 {#2} + } + +\PrgNewFunction \StrMapVariable { m M n } + { + \str_map_variable:nNn {#1} #2 {#3} + } + +\PrgNewFunction \StrVarMapVariable { M M n } + { + \str_map_variable:NNn #1 #2 {#3} + } + +\PrgNewConditional \StrIfExist { M } + { + \str_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \StrVarIfEmpty { M } + { + \str_if_empty:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \StrIfEq { m m } + { + \str_if_eq:nnTF {#1} {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \StrVarIfEq { M M } + { + \str_if_eq:NNTF #1 #2 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \StrIfIn { m m } + { + \str_if_in:nnTF {#1} {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \StrVarIfIn { M m } + { + \str_if_in:NnTF #1 {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +%% Avoid naming confict with xstring package +\cs_if_exist:NF \StrCompare + { + \PrgNewConditional \StrCompare { m N m } + { + \str_compare:nNnTF {#1} #2 {#3} + { \Result { \cTrueBool } } + { \Result { \cFalseBool } } + } + } + +%% Provide another name for \StrCompare function +\PrgNewConditional \StrIfCompare { m N m } + { + \str_compare:nNnTF {#1} #2 {#3} { \Result { \cTrueBool } } { \Result { \cFalseBool } } } %%% -------------------------------------------------------- -%%> \section{Interfaces for Integers (l3int)} +%%> \section{Interfaces for Integers (Int)} %%% -------------------------------------------------------- +\cs_set_eq:NN \cZeroInt \c_zero_int +\cs_set_eq:NN \cOneInt \c_one_int +\cs_set_eq:NN \cMaxInt \c_max_int +\cs_set_eq:NN \cMaxRegisterInt \c_max_register_int +\cs_set_eq:NN \cMaxCharInt \c_max_char_in + \int_new:N \lTmpaInt \int_new:N \lTmpbInt \int_new:N \lTmpcInt \int_new:N \lTmpiInt \int_new:N \lTmpjInt \int_new:N \lTmpkInt \int_new:N \l@Funx@Int \int_new:N \l@Funy@Int \int_new:N \l@Funz@Int @@ -605,14 +1070,85 @@ \int_new:N \gTmpiInt \int_new:N \gTmpjInt \int_new:N \gTmpkInt \int_new:N \g@Funx@Int \int_new:N \g@Funy@Int \int_new:N \g@Funz@Int -\cs_set_eq:NN \IntNew \int_new:N -\cs_set_eq:NN \IntLog \int_log:N +\PrgNewFunction \IntEval { m } + { + \Result { \Expand { \int_eval:n { #1 } } } + } + +\PrgNewFunction \IntMathAdd { m m } + { + \int_set:Nn \l@Funx@Int { \int_eval:n { (#1) + (#2) } } + \Result { \Value \l@Funx@Int } + } + +\PrgNewFunction \IntMathSub { m m } + { + \int_set:Nn \l@Funx@Int { \int_eval:n { (#1) - (#2) } } + \Result { \Value \l@Funx@Int } + } + +\PrgNewFunction \IntMathMult { m m } + { + \int_set:Nn \l@Funx@Int { \int_eval:n { (#1) * (#2) } } + \Result { \Value \l@Funx@Int } + } + +\PrgNewFunction \IntMathDiv { m m } + { + \Expand { \int_div_round:nn { #1 } { #2 } } + } + +\PrgNewFunction \IntMathDivTruncate { m m } + { + \Expand { \int_div_truncate:nn { #1 } { #2 } } + } + +\PrgNewFunction \IntMathSign { m } { \Expand { \int_sign:n { #1 } } } + +\PrgNewFunction \IntMathAbs { m } { \Expand { \int_abs:n { #1 } } } + +\PrgNewFunction \IntMathMax { m m } { \Expand { \int_max:nn { #1 } { #2 } } } + +\PrgNewFunction \IntMathMin { m m } { \Expand { \int_min:nn { #1 } { #2 } } } + +\PrgNewFunction \IntMathMod { m m } { \Expand { \int_mod:nn { #1 } { #2 } } } + +\PrgNewFunction \IntMathRand { m m } { \Expand { \int_rand:nn { #1 } { #2 } } } + +\PrgNewFunction \IntNew { M } { \int_new:N #1 } + +\PrgNewFunction \IntConst { M m } { \int_const:Nn #1 { #2 } } + +\PrgNewFunction \IntLog { m } { \int_log:n { #1 } } + +\PrgNewFunction \IntVarLog { M } { \int_log:N #1 } + +\PrgNewFunction \IntShow { m } { \int_show:n { #1 } } + +\PrgNewFunction \IntVarShow { M } { \int_show:N #1 } + +\PrgNewFunction \IntUse { M } { \Result { \Value #1 } } + +\PrgNewFunction \IntSet { M m } + { + \__fun_do_assignment:Nnn #1 { \int_gset:Nn #1 {#2} } { \int_set:Nn #1 {#2} } + } \PrgNewFunction \IntZero { M } { \__fun_do_assignment:Nnn #1 { \int_gzero:N #1 } { \int_zero:N #1 } } +\PrgNewFunction \IntZeroNew { M } + { + \__fun_do_assignment:Nnn #1 { \int_gzero_new:N #1 } { \int_zero_new:N #1 } + } + +\PrgNewFunction \IntSetEq { M M } + { + \__fun_do_assignment:Nnn #1 { \int_gset_eq:NN #1 #2 } { \int_set_eq:NN #1 #2 } + } + \PrgNewFunction \IntIncr { M } { \__fun_do_assignment:Nnn #1 { \int_gincr:N #1 } { \int_incr:N #1 } @@ -623,11 +1159,6 @@ \__fun_do_assignment:Nnn #1 { \int_gdecr:N #1 } { \int_decr:N #1 } } -\PrgNewFunction \IntSet { M m } - { - \__fun_do_assignment:Nnn #1 { \int_gset:Nn #1 {#2} } { \int_set:Nn #1 {#2} } - } - \PrgNewFunction \IntAdd { M m } { \__fun_do_assignment:Nnn #1 { \int_gadd:Nn #1 {#2} } { \int_add:Nn #1 {#2} } @@ -638,49 +1169,524 @@ \__fun_do_assignment:Nnn #1 { \int_gsub:Nn #1 {#2} } { \int_sub:Nn #1 {#2} } } -\PrgNewFunction \IntUse { M } +\PrgNewFunction \IntStepInline { m m m n } { - \Result { \Value #1 } + \int_step_inline:nnnn { #1 } { #2 } { #3 } { #4 } } -\PrgNewFunction \IntEval { m } +\PrgNewFunction \IntStepVariable { m m m M n } { - \Result { \Expand { \int_eval:n { #1 } } } + \int_step_variable:nnnNn { #1 } { #2 } { #3 } #4 { #5 } } -\PrgNewFunction \IntMathAdd { m m } +\PrgNewConditional \IntIfExist { M } { - \int_set:Nn \l@Funx@Int { \int_eval:n { #1 + #2 } } - \Result { \Value \l@Funx@Int } + \int_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } } -\PrgNewFunction \IntMathSub { m m } +\PrgNewConditional \IntIfOdd { m } { - \int_set:Nn \l@Funx@Int { \int_eval:n { #1 - #2 } } - \Result { \Value \l@Funx@Int } + \int_if_odd:nTF { #1 } { \Result { \cTrueBool } } { \Result { \cFalseBool } } } -\PrgNewFunction \IntMathMult { m m } +\PrgNewConditional \IntIfEven { m } { - \int_set:Nn \l@Funx@Int { \int_eval:n { #1 * #2 } } - \Result { \Value \l@Funx@Int } + \int_if_even:nTF { #1 } { \Result { \cTrueBool } } { \Result { \cFalseBool } } } -\PrgNewFunction \IntMathDiv { m m } +\PrgNewConditional \IntCompare { m N m } { - \int_set:Nn \l@Funx@Int { \int_eval:n { #1 / #2 } } - \Result { \Value \l@Funx@Int } + \int_compare:nNnTF {#1} #2 {#3} + { \Result { \cTrueBool } } + { \Result { \cFalseBool } } } -\PrgNewFunction \IntStepVariable { m m m M n } +\PrgNewFunction \IntCase { m m } { \int_case:nn {#1} {#2} } +\PrgNewFunction \IntCaseT { m m n } { \int_case:nnT {#1} {#2} {#3} } +\PrgNewFunction \IntCaseF { m m n } { \int_case:nnF {#1} {#2} {#3} } +\PrgNewFunction \IntCaseTF { m m n n } { \int_case:nnTF {#1} {#2} {#3} {#4} } + +%%% -------------------------------------------------------- +%%> \section{Interfaces for Floating Point Numbers (Fp)} +%%% -------------------------------------------------------- + +\fp_set_eq:NN \cZeroFp \c_zero_fp +\fp_set_eq:NN \cMinusZeroFp \c_minus_zero_fp +\fp_set_eq:NN \cOneFp \c_one_fp +\fp_set_eq:NN \cInfFp \c_inf_fp +\fp_set_eq:NN \cMinusInfFp \c_minus_inf_fp +\fp_set_eq:NN \cEFp \c_e_fp +\fp_set_eq:NN \cPiFp \c_pi_fp +\fp_set_eq:NN \cOneDegreeFp \c_one_degree_fp + +\fp_new:N \lTmpaFp \fp_new:N \lTmpbFp \fp_new:N \lTmpcFp +\fp_new:N \lTmpiFp \fp_new:N \lTmpjFp \fp_new:N \lTmpkFp +\fp_new:N \l@Funx@Fp \fp_new:N \l@Funy@Fp \fp_new:N \l@Funz@Fp + +\fp_new:N \gTmpaFp \fp_new:N \gTmpbFp \fp_new:N \gTmpcFp +\fp_new:N \gTmpiFp \fp_new:N \gTmpjFp \fp_new:N \gTmpkFp +\fp_new:N \g@Funx@Fp \fp_new:N \g@Funy@Fp \fp_new:N \g@Funz@Fp + +\PrgNewFunction \FpEval { m } { - \int_step_variable:nnnNn { #1 } { #2 } { #3 } #4 { #5 } + \Result { \Expand { \fp_eval:n { #1 } } } } -\PrgNewConditional \IntCompare { m N m } +\PrgNewFunction \FpMathAdd { m m } { - \int_compare:nNnTF {#1} #2 {#3} + \fp_set:Nn \l@Funx@Fp { \fp_eval:n { (#1) + (#2) } } + \Result { \FpUse \l@Funx@Fp } + } + +\PrgNewFunction \FpMathSub { m m } + { + \fp_set:Nn \l@Funx@Fp { \fp_eval:n { (#1) - (#2) } } + \Result { \FpUse \l@Funx@Fp } + } + +\PrgNewFunction \FpMathMult { m m } + { + \fp_set:Nn \l@Funx@Fp { \fp_eval:n { (#1) * (#2) } } + \Result { \FpUse \l@Funx@Fp } + } + +\PrgNewFunction \FpMathDiv { m m } + { + \fp_set:Nn \l@Funx@Fp { \fp_eval:n { (#1) / (#2) } } + \Result { \FpUse \l@Funx@Fp } + } + +\PrgNewFunction \FpMathSign { m } + { + \Result { \Expand { \fp_sign:n { #1 } } } + } + +\PrgNewFunction \FpMathAbs { m } + { + \Result { \Expand { \fp_abs:n { #1 } } } + } + +\PrgNewFunction \FpMathMax { m m } + { + \Result { \Expand { \fp_max:nn { #1 } { #2 } } } + } + +\PrgNewFunction \FpMathMin { m m } + { + \Result { \Expand { \fp_min:nn { #1 } { #2 } } } + } + +\PrgNewFunction \FpNew { M } { \fp_new:N #1 } + +\PrgNewFunction \FpConst { M m } { \fp_const:Nn #1 {#2} } + +\PrgNewFunction \FpUse { M } { \Result { \Expand { \fp_use:N #1 } } } + +\PrgNewFunction \FpLog { m } { \fp_log:n { #1 } } + +\PrgNewFunction \FpVarLog { M } { \fp_log:N #1 } + +\PrgNewFunction \FpShow { m } { \fp_show:n { #1 } } + +\PrgNewFunction \FpVarShow { M } { \fp_show:N #1 } + +\PrgNewFunction \FpSet { M m } + { + \__fun_do_assignment:Nnn #1 { \fp_gset:Nn #1 {#2} } { \fp_set:Nn #1 {#2} } + } + +\PrgNewFunction \FpSetEq { M M } + { + \__fun_do_assignment:Nnn #1 { \fp_gset_eq:NN #1 #2 } { \fp_set_eq:NN #1 #2 } + } + +\PrgNewFunction \FpZero { M } + { + \__fun_do_assignment:Nnn #1 { \fp_gzero:N #1 } { \fp_zero:N #1 } + } + +\PrgNewFunction \FpZeroNew { M } + { + \__fun_do_assignment:Nnn #1 { \fp_gzero_new:N #1 } { \fp_zero_new:N #1 } + } + +\PrgNewFunction \FpAdd { M m } + { + \__fun_do_assignment:Nnn #1 { \fp_gadd:Nn #1 {#2} } { \fp_add:Nn #1 {#2} } + } + +\PrgNewFunction \FpSub { M m } + { + \__fun_do_assignment:Nnn #1 { \fp_gsub:Nn #1 {#2} } { \fp_sub:Nn #1 {#2} } + } + +\PrgNewFunction \FpStepInline { m m m n } + { + \fp_step_inline:nnnn { #1 } { #2 } { #3 } { #4 } + } + +\PrgNewFunction \FpStepVariable { m m m M n } + { + \fp_step_variable:nnnNn { #1 } { #2 } { #3 } #4 { #5 } + } + +\PrgNewConditional \FpIfExist { M } + { + \fp_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \FpCompare { m N m } + { + \fp_compare:nNnTF {#1} #2 {#3} { \Result { \cTrueBool } } { \Result { \cFalseBool } } } +%%% -------------------------------------------------------- +%%> \section{Interfaces for Dimensions (Dim)} +%%% -------------------------------------------------------- + +\cs_set_eq:NN \cMaxDim \c_max_dim +\cs_set_eq:NN \cZeroDim \c_zero_dim + +\dim_new:N \lTmpaDim \dim_new:N \lTmpbDim \dim_new:N \lTmpcDim +\dim_new:N \lTmpiDim \dim_new:N \lTmpjDim \dim_new:N \lTmpkDim +\dim_new:N \l@Funx@Dim \dim_new:N \l@Funy@Dim \dim_new:N \l@Funz@Dim + +\dim_new:N \gTmpaDim \dim_new:N \gTmpbDim \dim_new:N \gTmpcDim +\dim_new:N \gTmpiDim \dim_new:N \gTmpjDim \dim_new:N \gTmpkDim +\dim_new:N \g@Funx@Dim \dim_new:N \g@Funy@Dim \dim_new:N \g@Funz@Dim + +\PrgNewFunction \DimEval { m } + { + \Result { \Expand { \dim_eval:n { #1 } } } + } + +\PrgNewFunction \DimMathAdd { m m } + { + \dim_set:Nn \l@Funx@Dim { \dim_eval:n { (#1) + (#2) } } + \Result { \Value \l@Funx@Dim } + } + +\PrgNewFunction \DimMathSub { m m } + { + \dim_set:Nn \l@Funx@Dim { \dim_eval:n { (#1) - (#2) } } + \Result { \Value \l@Funx@Dim } + } + +\PrgNewFunction \DimMathSign { m } + { + \Result { \Expand { \dim_sign:n { #1 } } } + } + +\PrgNewFunction \DimMathAbs { m } + { + \Result { \Expand { \dim_abs:n { #1 } } } + } + +\PrgNewFunction \DimMathMax { m m } + { + \Result { \Expand { \dim_max:nn { #1 } { #2 } } } + } + +\PrgNewFunction \DimMathMin { m m } + { + \Result { \Expand { \dim_min:nn { #1 } { #2 } } } + } + +\PrgNewFunction \DimMathRatio { m m } + { + \Result { \Expand { \dim_ratio:nn { #1 } { #2 } } } + } + +\PrgNewFunction \DimNew { M } { \dim_new:N #1 } + +\PrgNewFunction \DimConst { M m } { \dim_const:Nn #1 {#2} } + +\PrgNewFunction \DimUse { M } { \Result { \Value #1 } } + +\PrgNewFunction \DimLog { m } { \dim_log:n { #1 } } + +\PrgNewFunction \DimVarLog { M } { \dim_log:N #1 } + +\PrgNewFunction \DimShow { m } { \dim_show:n { #1 } } + +\PrgNewFunction \DimVarShow { M } { \dim_show:N #1 } + +\PrgNewFunction \DimSet { M m } + { + \__fun_do_assignment:Nnn #1 { \dim_gset:Nn #1 {#2} } { \dim_set:Nn #1 {#2} } + } + +\PrgNewFunction \DimSetEq { M M } + { + \__fun_do_assignment:Nnn #1 { \dim_gset_eq:NN #1 #2 } { \dim_set_eq:NN #1 #2 } + } + +\PrgNewFunction \DimZero { M } + { + \__fun_do_assignment:Nnn #1 { \dim_gzero:N #1 } { \dim_zero:N #1 } + } + +\PrgNewFunction \DimZeroNew { M } + { + \__fun_do_assignment:Nnn #1 { \dim_gzero_new:N #1 } { \dim_zero_new:N #1 } + } + +\PrgNewFunction \DimAdd { M m } + { + \__fun_do_assignment:Nnn #1 { \dim_gadd:Nn #1 {#2} } { \dim_add:Nn #1 {#2} } + } + +\PrgNewFunction \DimSub { M m } + { + \__fun_do_assignment:Nnn #1 { \dim_gsub:Nn #1 {#2} } { \dim_sub:Nn #1 {#2} } + } + +\PrgNewFunction \DimStepInline { m m m n } + { + \dim_step_inline:nnnn { #1 } { #2 } { #3 } { #4 } + } + +\PrgNewFunction \DimStepVariable { m m m M n } + { + \dim_step_variable:nnnNn { #1 } { #2 } { #3 } #4 { #5 } + } + +\PrgNewConditional \DimIfExist { M } + { + \dim_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \DimCompare { m N m } + { + \dim_compare:nNnTF {#1} #2 {#3} + { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewFunction \DimCase { m m } { \dim_case:nn {#1} {#2} } +\PrgNewFunction \DimCaseT { m m n } { \dim_case:nnT {#1} {#2} {#3} } +\PrgNewFunction \DimCaseF { m m n } { \dim_case:nnF {#1} {#2} {#3} } +\PrgNewFunction \DimCaseTF { m m n n } { \dim_case:nnTF {#1} {#2} {#3} {#4} } + +%%% -------------------------------------------------------- +%%> \section{Interfaces for Sorting Functions (Sort)} +%%% -------------------------------------------------------- + +\cs_set_eq:NN \SortReturnSame \sort_return_same: +\cs_set_eq:NN \SortReturnSwapped \sort_return_swapped: + +%%% -------------------------------------------------------- +%%> \section{Interfaces for Comma Separated Lists (Clist)} +%%% -------------------------------------------------------- + +\clist_new:N \lTmpaClist \clist_new:N \lTmpbClist \clist_new:N \lTmpcClist +\clist_new:N \lTmpiClist \clist_new:N \lTmpjClist \clist_new:N \lTmpkClist +\clist_new:N \l@Funx@Clist \clist_new:N \l@Funy@Clist \clist_new:N \l@Funz@Clist + +\clist_new:N \gTmpaClist \clist_new:N \gTmpbClist \clist_new:N \gTmpcClist +\clist_new:N \gTmpiClist \clist_new:N \gTmpjClist \clist_new:N \gTmpkClist +\clist_new:N \g@Funx@Clist \clist_new:N \g@Funy@Clist \clist_new:N \g@Funz@Clist + +\clist_set_eq:NN \cEmptyClist \c_empty_clist + +\PrgNewFunction \ClistNew { M } { \clist_new:N #1 } + +\PrgNewFunction \ClistLog { m } { \clist_log:n { #1 } } + +\PrgNewFunction \ClistVarLog { M } { \clist_log:N #1 } + +\PrgNewFunction \ClistShow { m } { \clist_show:n { #1 } } + +\PrgNewFunction \ClistVarShow { M } { \clist_show:N #1 } + +\PrgNewFunction \ClistVarJoin { M m } + { + \Expand { \clist_use:Nn #1 { #2 } } + } + +\PrgNewFunction \ClistVarJoinExtended { M m m m } + { + \Expand { \clist_use:Nnnn #1 { #2 } { #3 } { #4 } } + } + +\PrgNewFunction \ClistJoin { m m } + { + \Expand { \clist_use:nn { #1 } { #2 } } + } + +\PrgNewFunction \ClistJoinExtended { m m m m } + { + \Expand { \clist_use:nnnn { #1 } { #2 } { #3 } { #4 } } + } + +\PrgNewFunction \ClistConst { M m } { \clist_const:Nn #1 { #2 } } + +\PrgNewFunction \ClistSet { M m } + { + \__fun_do_assignment:Nnn #1 + { \clist_gset:Nn #1 {#2} } { \clist_set:Nn #1 {#2} } + } + +\PrgNewFunction \ClistSetEq { M M } + { + \__fun_do_assignment:Nnn #1 + { \clist_gset_eq:NN #1 #2 } { \clist_set_eq:NN #1 #2 } + } + +\PrgNewFunction \ClistSetFromSeq { M M } + { + \__fun_do_assignment:Nnn #1 + { \clist_gset_from_seq:NN #1 #2 } { \clist_set_from_seq:NN #1 #2 } + } + +\PrgNewFunction \ClistConcat { M M M } + { + \__fun_do_assignment:Nnn #1 + { \clist_gconcat:NNN #1 #2 #3 } { \clist_concat:NNN #1 #2 #3 } + } + +\PrgNewFunction \ClistClear { M } + { + \__fun_do_assignment:Nnn #1 { \clist_gclear:N #1 } { \clist_clear:N #1 } + } + +\PrgNewFunction \ClistClearNew { M } + { + \__fun_do_assignment:Nnn #1 { \clist_gclear_new:N #1 } { \clist_clear_new:N #1 } + } + +\PrgNewFunction \ClistPutLeft { M m } + { + \__fun_do_assignment:Nnn #1 + { \clist_gput_left:Nn #1 {#2} } { \clist_put_left:Nn #1 {#2} } + } + +\PrgNewFunction \ClistPutRight { M m } + { + \__fun_do_assignment:Nnn #1 + { \clist_gput_right:Nn #1 {#2} } { \clist_put_right:Nn #1 {#2} } + } + +\PrgNewFunction \ClistRemoveDuplicates { M } + { + \__fun_do_assignment:Nnn #1 + { \clist_gremove_duplicates:N #1 } { \clist_remove_duplicates:N #1 } + } + +\PrgNewFunction \ClistRemoveAll { M m } + { + \__fun_do_assignment:Nnn #1 + { \clist_gremove_all:Nn #1 {#2} } { \clist_remove_all:Nn #1 {#2} } + } + +\PrgNewFunction \ClistReverse { M } + { + \__fun_do_assignment:Nnn #1 { \clist_greverse:N #1 } { \clist_reverse:N #1 } + } + +\PrgNewFunction \ClistSort { M m } + { + \__fun_do_assignment:Nnn #1 + { \clist_gsort:Nn #1 {#2} } { \clist_sort:Nn #1 {#2} } + } + +\PrgNewFunction \ClistCount { m } + { + \Result { \Expand { \clist_count:n { #1 } } } + } + +\PrgNewFunction \ClistVarCount { m } + { + \Result { \Expand { \clist_count:N #1 } } + } + +\PrgNewFunction \ClistGet { M M } { \clist_get:NN #1 #2 } +\PrgNewFunction \ClistGetT { M M n } { \clist_get:NNT #1 #2 {#3} } +\PrgNewFunction \ClistGetF { M M n } { \clist_get:NNF #1 #2 {#3} } +\PrgNewFunction \ClistGetTF { M M n n } { \clist_get:NNTF #1 #2 {#3} {#4} } + +\PrgNewFunction \ClistPop { M M } + { + \__fun_do_assignment:Nnn #1 + { \clist_gpop:NN #1 #2 } { \clist_pop:NN #1 #2 } + } +\PrgNewFunction \ClistPopT { M M n } + { + \__fun_do_assignment:Nnn #1 + { \clist_gpop:NNT #1 #2 {#3} } { \clist_pop:NNT #1 #2 {#3} } + } +\PrgNewFunction \ClistPopF { M M n } + { + \__fun_do_assignment:Nnn #1 + { \clist_gpop:NNF #1 #2 {#3} } { \clist_pop:NNF #1 #2 {#3} } + } +\PrgNewFunction \ClistPopTF { M M n n } + { + \__fun_do_assignment:Nnn #1 + { \clist_gpop:NNTF #1 #2 {#3} {#4} } { \clist_pop:NNTF #1 #2 {#3} {#4} } + } + +\PrgNewFunction \ClistPush { M m } + { + \__fun_do_assignment:Nnn #1 + { \clist_gpush:Nn #1 {#2} } { \clist_push:Nn #1 {#2} } + } + +\PrgNewFunction \ClistItem { m m } { \Expand { \clist_item:nn {#1} {#2} } } + +\PrgNewFunction \ClistVarItem { M m } { \Expand { \clist_item:Nn #1 {#2} } } + +\PrgNewFunction \ClistRandItem { m } { \Expand { \clist_rand_item:n {#1} } } + +\PrgNewFunction \ClistVarRandItem { M } { \Expand { \clist_rand_item:N #1 } } + +\PrgNewFunction \ClistMapInline { m n } + { + \clist_map_inline:nn {#1} {#2} + } + +\PrgNewFunction \ClistVarMapInline { M n } + { + \clist_map_inline:Nn #1 {#2} + } + +\PrgNewFunction \ClistMapVariable { m M n } + { + \clist_map_variable:nNn {#1} #2 {#3} + } + +\PrgNewFunction \ClistVarMapVariable { M M n } + { + \clist_map_variable:NNn #1 #2 {#3} + } + +\cs_set_eq:NN \ClistMapBreak \clist_map_break: + +\PrgNewConditional \ClistIfExist { M } + { + \clist_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \ClistIfEmpty { m } + { + \clist_if_empty:nTF {#1} { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \ClistVarIfEmpty { m } + { + \clist_if_empty:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \ClistIfIn { m m } + { + \clist_if_in:nnTF {#1} {#2} + { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + +\PrgNewConditional \ClistVarIfIn { M m } + { + \clist_if_in:NnTF #1 {#2} + { \Result { \cTrueBool } } { \Result { \cFalseBool } } + } + diff --git a/macros/latex/contrib/functional/functional.tex b/macros/latex/contrib/functional/functional.tex index 18dfa30662..b3eb028adc 100644 --- a/macros/latex/contrib/functional/functional.tex +++ b/macros/latex/contrib/functional/functional.tex @@ -1,9 +1,9 @@ -% -*- coding: utf-8 -*- - +% -*- coding: utf-8 -*- +% !TEX program = lualatex \documentclass[oneside]{book} \usepackage[a4paper,margin=2.5cm]{geometry} -\newcommand*{\myversion}{2022A} +\newcommand*{\myversion}{2022B} \newcommand*{\mydate}{Version \myversion\ (\the\year-\mylpad\month-\mylpad\day)} \newcommand*{\mylpad}[1]{\ifnum#1<10 0\the#1\else\the#1\fi} @@ -18,6 +18,8 @@ \NewCodeHighEnv{code}{style/main=gray9,style/code=gray9} \NewCodeHighEnv{demo}{style/main=gray9,style/code=gray9,demo} +\usepackage{enumitem} + \NewDocumentCommand\MySubScript{m}{$_{#1}$} \ExplSyntaxOn @@ -34,13 +36,13 @@ } \ExplSyntaxOff -\NewDocumentEnvironment{variable}{m}{ +\NewDocumentEnvironment{variable}{om}{ \vspace{5pt} \begin{minipage}{\linewidth} \hrule\vspace{4pt}\obeylines% \begingroup \ttfamily\bfseries\color{azure3} - \PrintVarList{#1} + \PrintVarList{#2} \endgroup \par\vspace{4pt}\hrule \end{minipage}\par\nopagebreak\vspace{4pt} @@ -48,7 +50,7 @@ \vspace{5pt}% } -\NewDocumentEnvironment{function}{m}{ +\NewDocumentEnvironment{function}{om}{ \vspace{5pt}% }{\vspace{5pt}} @@ -74,6 +76,9 @@ \texttt{\{}\textsl{$\langle$\ignorespaces\lTmpaTl\unskip$\rangle$}\texttt{\}}% } +\NewDocumentCommand\nan{}{\texttt{NaN}} +\NewDocumentCommand\enquote{m}{``#1''} + \let\tn=\cs \RenewDocumentCommand\emph{m}{% @@ -92,7 +97,7 @@ \begin{document} -\title{\sffamily LaTeX2 \textcolor{green3}{Functional} Interfaces to LaTeX3 Programming Layer} +\title{\sffamily LaTeX2 \textcolor{green3}{Functional} Interfaces for LaTeX3 Programming Layer} \author{Jianrui Lyu (tolvjr@163.com)\\\url{https://github.com/lvjr/functional}} \date{\mydate\vspace{1cm}\\\myabstract\vspace{10cm}} @@ -120,44 +125,48 @@ Note that many paragraphs in this manual are copied from the documentation of \t We will compare our first example with a similar \verb!Lua! example: -\begin{code} --- lua code -- -function MathSquare (arg) - local lTmpaInt = arg * arg - return lTmpaInt -end -print(MathSquare(5)) -print(MathSquare(MathSquare(5))) -\end{code} - +\begin{minipage}{0.55\textwidth} \begin{codehigh} %% function code -\ExplSyntaxOn +\IgnoreSpacesOn \PrgNewFunction \MathSquare { m } { - \IntSet \lTmpaInt { \IntEval { #1 * #1 } } + \IntSet \lTmpaInt { \IntEval {#1 * #1} } \Result { \Value \lTmpaInt } } -\ExplSyntaxOff +\IgnoreSpacesOff \MathSquare{5} \MathSquare{\MathSquare{5}} \end{codehigh} +\end{minipage}% +\begin{minipage}{0.45\textwidth} +\begin{code} +-- define a function -- +function MathSquare (arg) + local lTmpaInt = arg * arg + return lTmpaInt +end +-- use the function -- +print(MathSquare(5)) +print(MathSquare(MathSquare(5))) +\end{code} +\end{minipage} -%\ExplSyntaxOn +%\IgnoreSpacesOn %\PrgNewFunction \MathSquare { m }{ % \IntSet \lTmpaInt { \IntEval { #1 * #1 } } % \Result { \Value \lTmpaInt } %} -%\ExplSyntaxOff +%\IgnoreSpacesOff %\MathSquare{5} %\MathSquare{\MathSquare{5}} -%\ExplSyntaxOn +%\IgnoreSpacesOn %\PrgNewFunction \MathCubic { m } % { % \IntSet \lTmpaInt { \IntEval { #1 * #1 * #1 } } % \Result { \Value \lTmpaInt } % } -%\ExplSyntaxOff +%\IgnoreSpacesOff %\MathCubic{2} %\MathCubic{\MathCubic{2}} @@ -176,38 +185,42 @@ with \cs{Result} command. And \verb!functional! package is responsible for inserting result tokens to the input stream at the appropriate time. To remove space tokens inside function code in defining functions, -you'd better put function definitions inside \verb!\ExplSyntaxOn! and -\verb!\ExplSyntaxOff! block. Within this block, \verb!~! is used to input a space. +you'd better put function definitions inside \verb!\IgnoreSpacesOn! and +\verb!\IgnoreSpacesOff! block. Within this block, \verb!~! is used to input a space. At the end of this section, we will compare our factorial example with a similar \verb!Lua! example: -\begin{code} --- lua code -- -function Factorial (n) - if n == 0 then - return 1 - else - return n * Factorial(n-1) - end -end -print(Factorial(4)) -\end{code} - +\begin{minipage}{0.69\textwidth} \begin{codehigh} -\ExplSyntaxOn -\PrgNewFunction \Factorial { m } { +\IgnoreSpacesOn +\PrgNewFunction \Fact { m } { \IntCompareTF {#1} = {0} { \Result {1} }{ - \Result { \IntMathMult {#1} { \Factorial { \IntMathSub{#1}{1} } } } + \Result {\IntMathMult{#1}{\Fact{\IntMathSub{#1}{1}}}} } } -\ExplSyntaxOff -\Factorial{4} +\IgnoreSpacesOff +\Fact{4} \end{codehigh} +\end{minipage}% +\begin{minipage}{0.31\textwidth} +\begin{code} +-- define a function -- +function Fact (n) + if n == 0 then + return 1 + else + return n * Fact(n-1) + end +end +-- use the function -- +print(Fact(4)) +\end{code} +\end{minipage} -%\ExplSyntaxOn +%\IgnoreSpacesOn %\PrgNewFunction \Factorial { m } { % \IntCompareTF {#1} = {0} { % \Result {1} @@ -215,7 +228,7 @@ print(Factorial(4)) % \Result { \IntMathMult {#1} { \Factorial { \IntMathSub{#1}{1} } } } % } %} -%\ExplSyntaxOff +%\IgnoreSpacesOff %\Factorial{0} %\Factorial{4} @@ -223,47 +236,50 @@ print(Factorial(4)) In \verb!Lua! language, a function or a condition expression makes a block, and the values of local variables will be reset after a block. -For example - -\begin{code} --- lua code -- -local a = 1 -print(a) ---- 1 -function SomeFun() - local a = 2 - print(a) ---- 2 - if 1 > 0 then - local a = 3 - print(a) ---- 3 - end - print(a) ---- 2 -end -SomeFun() -print(a) ---- 1 -\end{code} - In \verb!functional! package, a condition expression is in fact a function, and you can make every function become a group by setting \verb!\Functional{scoping=true}!. For example +\begin{minipage}{0.58\textwidth} \begin{codehigh} \Functional{scoping=true} -\ExplSyntaxOn +\IgnoreSpacesOn \IntSet \lTmpaInt {1} -\IntLog \lTmpaInt % ---- 1 +\IntLogVar \lTmpaInt % ---- 1 \PrgNewFunction \SomeFun { } { \IntSet \lTmpaInt {2} - \IntLog \lTmpaInt % ---- 2 + \IntLogVar \lTmpaInt % ---- 2 \IntCompareTF {1} > {0} { \IntSet \lTmpaInt {3} - \IntLog \lTmpaInt % ---- 3 + \IntLogVar \lTmpaInt % ---- 3 }{ } - \IntLog \lTmpaInt % ---- 2 + \IntLogVar \lTmpaInt % ---- 2 } \SomeFun -\IntLog \lTmpaInt % ---- 1 -\ExplSyntaxOff +\IntLogVar \lTmpaInt % ---- 1 +\IgnoreSpacesOff \end{codehigh} +\end{minipage}% +\begin{minipage}{0.42\textwidth} +\begin{code} +-- lua code -- +-- begin example -- +local a = 1 +print(a) ---- 1 +function SomeFun() + local a = 2 + print(a) ---- 2 + if 1 > 0 then + local a = 3 + print(a) ---- 3 + end + print(a) ---- 2 +end +SomeFun() +print(a) ---- 1 +-- end example -- +\end{code} +\end{minipage} Same as \verb!expl3!, the names of local variables \emph{must} start with \verb!l!, while names of global variables \emph{must} start with \verb!g!. @@ -275,22 +291,46 @@ by checking leading letters of their names. So for integer variables, you can wr The previous example will produce different result if we change variable from \verb!\lTmpaInt! to \verb!\gTmpaInt!. +\begin{minipage}{0.58\textwidth} \begin{codehigh} \Functional{scoping=true} +\IgnoreSpacesOn \IntSet \gTmpaInt {1} -\IntLog \gTmpaInt % ---- 1 +\IntLogVar \gTmpaInt % ---- 1 \PrgNewFunction \SomeFun { } { \IntSet \gTmpaInt {2} - \IntLog \gTmpaInt % ---- 2 + \IntLogVar \gTmpaInt % ---- 2 \IntCompareTF {1} > {0} { \IntSet \gTmpaInt {3} - \IntLog \gTmpaInt % ---- 3 + \IntLogVar \gTmpaInt % ---- 3 }{ } - \IntLog \gTmpaInt % ---- 3 + \IntLogVar \gTmpaInt % ---- 3 } \SomeFun -\IntLog \gTmpaInt % ---- 3 +\IntLogVar \gTmpaInt % ---- 3 +\IgnoreSpacesOff \end{codehigh} +\end{minipage}% +\begin{minipage}{0.42\textwidth} +\begin{code} +-- lua code -- +-- begin example -- +a = 1 +print(a) ---- 1 +function SomeFun() + a = 2 + print(a) ---- 2 + if 1 > 0 then + a = 3 + print(a) ---- 3 + end + print(a) ---- 3 +end +SomeFun() +print(a) ---- 3 +-- end example -- +\end{code} +\end{minipage} As you can see, the values of global variables will never be reset after a group. @@ -326,9 +366,9 @@ For example, the tracing log of the first example in this chapter will be the fo [I] \Result{25} [O] 25 [O] 25 - [I] \IntSet\lTmpaInt {25} - [O] - [I] \Value\lTmpaInt + [I] \IntSet{\lTmpaInt }{25} + [O] + [I] \Value{\lTmpaInt } [O] 25 [I] \Result{25} [O] 25 @@ -340,9 +380,9 @@ For example, the tracing log of the first example in this chapter will be the fo [I] \Result{625} [O] 625 [O] 625 - [I] \IntSet\lTmpaInt {625} - [O] - [I] \Value\lTmpaInt + [I] \IntSet{\lTmpaInt }{625} + [O] + [I] \Value{\lTmpaInt } [O] 625 [I] \Result{625} [O] 625 @@ -354,16 +394,22 @@ For example, the tracing log of the first example in this chapter will be the fo Within \verb!expl3!, there are eight commands for defining new functions, which is good for power users. +\begin{minipage}{0.5\textwidth} \begin{code}[language=latex/latex3] \cs_new:Npn \cs_new_nopar:Npn \cs_new_protected:Npn \cs_new_protected_nopar:Npn +\end{code} +\end{minipage}% +\begin{minipage}{0.5\textwidth} +\begin{code}[language=latex/latex3] \cs_new:Nn \cs_new_nopar:Nn \cs_new_protected:Nn \cs_new_protected_nopar:Nn \end{code} +\end{minipage} Within \verb!functional! package, there is only one command (\cs{PrgNewFunction}) for defining new functions, which is good for normal users. @@ -377,6 +423,7 @@ Since \verb!functional! package gets the results of functions by evaluation Within \verb!expl3!, there are several expansion variants for arguments, and many expansion functions for expanding them, which are necessary for power users. +\begin{minipage}{0.5\textwidth} \begin{code}[language=latex/latex3] \module_foo:c \module_bar:e @@ -386,7 +433,8 @@ and many expansion functions for expanding them, which are necessary for power u \module_bar:V \module_bar:v \end{code} - +\end{minipage}% +\begin{minipage}{0.5\textwidth} \begin{code}[language=latex/latex3] \exp_args:Nc \exp_args:Ne @@ -396,6 +444,7 @@ and many expansion functions for expanding them, which are necessary for power u \exp_args:NV \exp_args:Nv \end{code} +\end{minipage} Within \verb!functional! package, there are only three variants (\verb!c!, \verb!e!, \verb!V!) are provided, and these variants are defined @@ -426,7 +475,7 @@ simply composing \cs{Name} and \cs{Value} functions: \Value{\Name{lTmpaInt}} \end{demohigh} -\chapter{Basic Definitions (\texttt{l3basics})} +\chapter{Functional Progarmming (\texttt{Prg})} \section{Defining Functions and Conditionals} @@ -470,6 +519,8 @@ will be created at the same time. \verb!\FooIfBarTF! function has two extra argu which are \Arg{true code} and \Arg{false code}.\par \end{function} +\section{Collecting Returned Values} + \begin{function}{\Result} \begin{syntax} \cs{Result} \Arg{tokens} @@ -478,7 +529,9 @@ Appends \meta{tokens} to \verb!\gResultTl!, which holds the returned value of cu This function is normally used in the \meta{code} of \cs{PrgNewFunction} and \cs{PrgNewConditional}. \end{function} -\section{Expanding and Using Tokens} +\chapter{Argument Using (\texttt{Use})} + +\section{Expanding Tokens} \begin{function}{\Name} \begin{syntax} @@ -538,6 +591,8 @@ Recovers the content of the \meta{variable}, then prevents expansion of this material inside the argument of \cs{Expand} function. \end{function} +\section{Using Tokens} + \begin{function}{\UseOne,\GobbleOne} \begin{syntax} \cs{UseOne} \Arg{argument} @@ -578,9 +633,18 @@ For example \end{demohigh} \end{function} -\chapter{Control Structures (\texttt{l3prg})} +\chapter{Control Structures (\texttt{Bool})} + +\section{Constant and Scratch Booleans} -\section{Scratch Variables of Booleans} +\begin{variable}{\cTrueBool,\cFalseBool} +Constants that represent \verb|true| and \verb|false|, respectively. Used to +implement predicates. For example +\begin{demohigh} +\BoolVarIfTF \cTrueBool {\Result{True!}} {\Result{False!}} +\BoolVarIfTF \cFalseBool {\Result{True!}} {\Result{False!}} +\end{demohigh} +\end{variable} \begin{variable}{\lTmpaBool,\lTmpbBool,\lTmpcBool,\lTmpiBool,\lTmpjBool,\lTmpkBool} Scratch booleans for local assignment. These are never used by @@ -596,10 +660,7 @@ function. However, they may be overwritten by other code and so should only be used for short-term storage. \end{variable} -%\BoolIfTF\cTrueBool{\Result{true}}{\Result{false}} -%\BoolIfTF\cFalseBool{\Result{true}}{\Result{false}} - -\section{Public Functions for Booleans} +\section{Creating and Setting Booleans} \begin{function}{\BoolNew} \begin{syntax} @@ -610,6 +671,33 @@ name is already taken. The declaration is global. The \meta{boolean} is initially \texttt{false}. \end{function} +\begin{function}{\BoolConst} +\begin{syntax} +\cs{BoolConst} \meta{boolean} \Arg{boolexpr} +\end{syntax} +Creates a new constant \meta{boolean} or raises an error if the name +is already taken. The value of the \meta{boolean} is set globally to +the result of evaluating the \meta{boolexpr}. +For example +\begin{codehigh} +\BoolConst \cFooSomeBool {\IntCompare{3}>{2}} +\BoolVarLog \cFooSomeBool +\end{codehigh} +\end{function} + +\begin{function}{\BoolSet} +\begin{syntax} +\cs{BoolSet} \meta{boolean} \Arg{boolexpr} +\end{syntax} +Evaluates the \meta{boolean expression} and sets the \meta{boolean} variable to +the logical truth of this evaluation. +For example +\begin{codehigh} +\BoolSet \lTmpaBool {\IntCompare{3}<{2}} +\BoolVarLog \lTmpaBool +\end{codehigh} +\end{function} + \begin{function}{\BoolSetTrue} \begin{syntax} \cs{BoolSetTrue} \meta{boolean} @@ -624,24 +712,165 @@ Sets \meta{boolean} logically \texttt{true}. Sets \meta{boolean} logically \texttt{false}. \end{function} -\begin{function}{\BoolIf,\BoolIfTF} +\begin{function}{\BoolSetEq} +\begin{syntax} +\cs{BoolSetEq} \meta{boolean_1} \meta{boolean_2} +\end{syntax} +Sets \meta{boolean_1} to the current value of \meta{boolean_2}. +For example +\begin{codehigh} +\BoolSetTrue \lTmpaBool +\BoolSetEq \lTmpbBool \lTmpaBool +\BoolVarLog \lTmpbBool +\end{codehigh} +\end{function} + +\section{Viewing Booleans} + +\begin{function}{\BoolLog} +\begin{syntax} +\cs{BoolLog} \Arg{boolean expression} +\end{syntax} +Writes the logical truth of the \meta{boolean expression} in the log file. +\end{function} + +\begin{function}{\BoolVarLog} +\begin{syntax} +\cs{BoolVarLog} \meta{boolean} +\end{syntax} +Writes the logical truth of the \meta{boolean} in the log file. +\end{function} + +\begin{function}{\BoolShow} +\begin{syntax} +\cs{BoolShow} \Arg{boolean expression} +\end{syntax} +Displays the logical truth of the \meta{boolean expression} on the terminal. +\end{function} + +\begin{function}{\BoolVarShow} +\begin{syntax} +\cs{BoolVarShow} \meta{boolean} +\end{syntax} +Displays the logical truth of the \meta{boolean} on the terminal. +\end{function} + +\section{Booleans and Conditionals} + +\begin{function}{\BoolIfExist,\BoolIfExistTF} +\begin{syntax} +\cs{BoolIfExist} \meta{boolean} +\cs{BoolIfExistTF} \meta{boolean} \Arg{true code} \Arg{false code} +\end{syntax} +Tests whether the \meta{boolean} is currently defined. This does not +check that the \meta{boolean} really is a boolean variable. +For example +\begin{demohigh} +\BoolIfExistTF \lTmpaBool {\Result{Yes}} {\Result{No}} +\BoolIfExistTF \lFooUndefinedBool {\Result{Yes}} {\Result{No}} +\end{demohigh} +\end{function} + +\begin{function}{\BoolVarIf,\BoolVarIfTF} \begin{syntax} -\cs{BoolIf} \meta{boolean} -\cs{BoolIfTF} \meta{boolean} \Arg{true code} \Arg{false code} +\cs{BoolVarIf} \meta{boolean} +\cs{BoolVarIfTF} \meta{boolean} \Arg{true code} \Arg{false code} \end{syntax} Tests the current truth of \meta{boolean}, and continues evaluation based on this result. For example \begin{demohigh} -\BoolSetTrue\lTmpaBool -\BoolIfTF\lTmpaBool{\Result{True!}}{\Result{False!}} -\BoolSetFalse\lTmpaBool -\BoolIfTF\lTmpaBool{\Result{True!}}{\Result{False!}} +\BoolSetTrue \lTmpaBool +\BoolVarIfTF \lTmpaBool {\Result{True!}} {\Result{False!}} +\BoolSetFalse \lTmpaBool +\BoolVarIfTF \lTmpaBool {\Result{True!}} {\Result{False!}} +\end{demohigh} +\end{function} + +\begin{function}{\BoolVarNot,\BoolVarNotTF} +\begin{syntax} +\cs{BoolVarNot} \meta{boolean} +\cs{BoolVarNotTF} \meta{boolean} \Arg{true code} \Arg{false code} +\end{syntax} +Evaluates \meta{true code} if \meta{boolean} is \verb!false!, +and \meta{false code} If \meta{boolean} is \verb!true!. +For example +\begin{demohigh} +\BoolVarNotTF {\IntCompare{3}>{2}} {\Result{Yes}} {\Result{No}} \end{demohigh} \end{function} -\chapter{Token Lists (\texttt{l3tl})} +\begin{function}{\BoolVarAnd,\BoolVarAndTF} +\begin{syntax} +\cs{BoolVarAnd} \meta{boolean_1} \meta{boolean_2} +\cs{BoolVarAndTF} \meta{boolean_1} \meta{boolean_2} \Arg{true code} \Arg{false code} +\end{syntax} +Implements the \enquote{And} operation between two booleans, +hence is \texttt{true} if both are \texttt{true}. +%Contrarily to the infix operator \verb|&&|, +The \meta{boolean_2} is only evaluated if it is needed to determine the result of +\cs{BoolVarAnd}. +For example +\begin{demohigh} +\BoolVarAndTF {\IntCompare{3}>{2}} {\IntCompare{3}>{4}} {\Result{Yes}} {\Result{No}} +\end{demohigh} +\end{function} + +\begin{function}{\BoolVarOr,\BoolVarOrTF} +\begin{syntax} +\cs{BoolVarOr} \meta{boolean_1} \meta{boolean_2} +\cs{BoolVarOrTF} \meta{boolean_1} \meta{boolean_2} \Arg{true code} \Arg{false code} +\end{syntax} +Implements the \enquote{Or} operation between two booleans, +hence is \texttt{true} if either one is \texttt{true}. +%Contrarily to the infix operator \verb"||", +The \meta{boolean_2} is only evaluated if it is needed to determine the result of +\cs{BoolVarOr}. +For example +\begin{demohigh} +\BoolVarOrTF {\IntCompare{3}>{2}} {\IntCompare{3}>{4}} {\Result{Yes}} {\Result{No}} +\end{demohigh} +\end{function} + +\begin{function}{\BoolVarXor,\BoolVarXorTF} +\begin{syntax} +\cs{BoolVarXor} \meta{boolean_1} \meta{boolean_2} +\cs{BoolVarXorTF} \meta{boolean_1} \meta{boolean_2} \Arg{true code} \Arg{false code} +\end{syntax} +Implements an \enquote{exclusive or} operation between two booleans. +For example +\begin{demohigh} +\BoolVarXorTF {\IntCompare{3}>{2}} {\IntCompare{3}>{4}} {\Result{Yes}} {\Result{No}} +\end{demohigh} +\end{function} -\section{Scratch Variables of Token Lists} +\chapter{Token Lists (\texttt{Tl})} + +\section{Constant and Scratch Token Lists} + +\begin{variable}{\cSpaceTl} +An explicit space character contained in a token list% +%(compare this with \cs{c_space_token}) +. For use where an explicit space is required. +\end{variable} + +\begin{variable}{\cEmptyTl} +Constant that is always empty. +\end{variable} + +%\begin{variable}{\cNoValueTl} +%A marker for the absence of an argument. This constant \verb|tl| can safely +%be typeset (\emph{cf.}~\cs{qNil}), with the result being \verb|-NoValue-|. +%It is important to note that \cs{cNoValueTl} is constructed such that it +%will \emph{not} match the simple text input \verb|-NoValue-|, \emph{i.e.} +%that +%\begin{demohigh} +%\TlIfEqTF {\TlUse\cNoValueTl} {-NoValue-} {Result{Yes}} {\Result{No}} +%\end{demohigh} +%The \cs{cNoValueTl} marker is intended for +%use in creating document-level interfaces, where it serves as an indicator +%that an (optional) argument was omitted. In particular, it is distinct +%from a simple empty \verb|tl|. +%\end{variable} \begin{variable}{\lTmpaTl,\lTmpbTl,\lTmpcTl,\lTmpiTl,\lTmpjTl,\lTmpkTl} Scratch token lists for local assignment. These are never used by @@ -657,17 +886,26 @@ function. However, they may be overwritten by other code and so should only be used for short-term storage. \end{variable} -\section{Public Functions for Token Lists} +\section{Creating and Using Token Lists} \begin{function}{\TlNew} \begin{syntax} -\cs{TlNew} \meta{tl~var} +\cs{TlNew} \meta{tl var} \end{syntax} -Creates a new \meta{tl~var} or raises an error if the +Creates a new \meta{tl var} or raises an error if the name is already taken. The declaration is global. The \meta{tl~var} is initially empty. \end{function} +\begin{function}{\TlConst} +\begin{syntax} +\cs{TlConst} \meta{tl var} \Arg{token list} +\end{syntax} +Creates a new constant \meta{tl var} or raises an error +if the name is already taken. The value of the +\meta{tl var} is set globally to the \meta{token list}. +\end{function} + \begin{function}{\TlUse} \begin{syntax} \cs{TlUse} \meta{tl~var} @@ -678,6 +916,97 @@ does not exist or if it is invalid. Note that it is possible to use a \meta{tl~var} directly without an accessor function. \end{function} +\begin{function}{\TlToStr} +\begin{syntax} +\cs{TlToStr} \Arg{token list} +\end{syntax} +Converts the \meta{token list} to a \meta{string}, returning the +resulting character tokens. A \meta{string} +is a series of tokens with category code $12$ (other) with the exception +of spaces, which retain category code $10$ (space). +%This function requires only a single expansion. +%Its argument \emph{must} be braced. +%\begin{texnote} +%This is the \eTeX{} primitive \tn{detokenize}. +%Converting a \meta{token list} to a \meta{string} yields a +%concatenation of the string representations of every token in the +%\meta{token list}. +%The string representation of a control sequence is +%\begin{itemize} +%\item an escape character, whose character code is given by the +%internal parameter \tn{escapechar}, absent if the +%\tn{escapechar} is negative or greater than the largest +%character code; +%\item the control sequence name, as defined by \cs{cs_to_str:N}; +%\item a space, unless the control sequence name is a single +%character whose category at the time of expansion of +%\cs{tl_to_str:n} is not \enquote{letter}. +%\end{itemize} +%The string representation of an explicit character token is that +%character, doubled in the case of (explicit) macro parameter +%characters (normally \verb|#|). +%In particular, the string representation of a token list may +%depend on the category codes in effect when it is evaluated, and +%the value of the \tn{escapechar}: for instance |\tl_to_str:n {\a}| +%normally produces the three character \enquote{backslash}, +%\enquote{lower-case a}, \enquote{space}, but it may also produce a +%single \enquote{lower-case a} if the escape character is negative +%and \texttt{a} is currently not a letter. +%\end{texnote} +\end{function} + +\begin{function}{\TlVarToStr} +\begin{syntax} +\cs{TlVarToStr} \meta{tl var} +\end{syntax} +Converts the content of the \meta{tl var} to a string, returning the +resulting character tokens. A \meta{string} +is a series of tokens with category code $12$ (other) with the exception +of spaces, which retain category code $10$ (space). +\end{function} + +\section{Viewing Token Lists} + +\begin{function}{\TlLog} +\begin{syntax} +\cs{TlLog} \Arg{token list} +\end{syntax} +Writes the \meta{token list} in the log file. See also +\cs{TlShow} which displays the result in the terminal. +\end{function} + +\begin{function}{\TlVarLog} +\begin{syntax} +\cs{TlVarLog} \meta{tl var} +\end{syntax} +Writes the content of the \meta{tl var} in the log file. See also +\cs{TlVarShow} which displays the result in the terminal. +\end{function} + +\begin{function}{\TlShow} +\begin{syntax} +\cs{TlShow} \Arg{token list} +\end{syntax} +Displays the \meta{token list} on the terminal. +%\begin{texnote} +%This is similar to the \eTeX{} primitive \tn{showtokens}, wrapped +%to a fixed number of characters per line. +%\end{texnote} +\end{function} + +\begin{function}{\TlVarShow} +\begin{syntax} +\cs{TlVarShow} \meta{tl var} +\end{syntax} +Displays the content of the \meta{tl var} on the terminal. +\begin{texnote} +This is similar to the \TeX{} primitive \tn{show}, wrapped to a +fixed number of characters per line. +\end{texnote} +\end{function} + +\section{Setting Token List Variables} + \begin{function}{\TlSet} \begin{syntax} \cs{TlSet} \meta{tl~var} \Arg{tokens} @@ -685,24 +1014,50 @@ a \meta{tl~var} directly without an accessor function. Sets \meta{tl~var} to contain \meta{tokens}, removing any previous content from the variable. For example \begin{demohigh} -\TlSet\lTmpiTl{\IntMathMult{4}{5}} -\TlUse\lTmpiTl +\TlSet \lTmpiTl {\IntMathMult{4}{5}} +\TlUse \lTmpiTl \end{demohigh} \end{function} +\begin{function}{\TlSetEq} +\begin{syntax} +\cs{TlSetEq} \meta{tl var_1} \meta{tl var_2} +\end{syntax} +Sets the content of \meta{tl var_1} equal to that of +\meta{tl var_2}. +\end{function} + \begin{function}{\TlClear} \begin{syntax} \cs{TlClear} \meta{tl~var} \end{syntax} Clears all entries from the \meta{tl~var}. For example \begin{demohigh} -\TlSet\lTmpjTl{One} -\TlClear\lTmpjTl -\TlSet\lTmpjTl{Two} -\TlUse\lTmpjTl +\TlSet \lTmpjTl {One} +\TlClear \lTmpjTl +\TlSet \lTmpjTl {Two} +\TlUse \lTmpjTl \end{demohigh} \end{function} +\begin{function}{\TlClearNew} +\begin{syntax} +\cs{TlClearNew} \meta{tl var} +\end{syntax} +Ensures that the \meta{tl var} exists globally by applying +\cs{TlNew} if necessary, then applies \cs{TlClear} to leave +the \meta{tl var} empty. +\end{function} + +\begin{function}{\TlConcat} +\begin{syntax} +\cs{TlConcat} \meta{tl var_1} \meta{tl var_2} \meta{tl var_3} +\end{syntax} +Concatenates the content of \meta{tl var_2} and \meta{tl var_3} +together and saves the result in \meta{tl var_1}. The \meta{tl var_2} +is placed at the left side of the new token list. +\end{function} + \begin{function}{\TlPutLeft} \begin{syntax} \cs{TlPutLeft} \meta{tl~var} \Arg{tokens} @@ -710,9 +1065,9 @@ Clears all entries from the \meta{tl~var}. For example Appends \meta{tokens} to the left side of the current content of \meta{tl~var}. For example \begin{demohigh} -\TlSet\lTmpkTl{Functional} -\TlPutLeft\lTmpkTl{Hello} -\TlUse\lTmpkTl +\TlSet \lTmpkTl {Functional} +\TlPutLeft \lTmpkTl {Hello} +\TlUse \lTmpkTl \end{demohigh} \end{function} @@ -723,49 +1078,1233 @@ Appends \meta{tokens} to the left side of the current content of Appends \meta{tokens} to the right side of the current content of \meta{tl~var}. For example \begin{demohigh} -\TlSet\lTmpkTl{Functional} -\TlPutRight\lTmpkTl{World} -\TlUse\lTmpkTl +\TlSet \lTmpkTl {Functional} +\TlPutRight \lTmpkTl {World} +\TlUse \lTmpkTl +\end{demohigh} +\end{function} + +\section{Replacing Tokens} + +Within token lists, replacement takes place at the top level: there is +no recursion into brace groups (more precisely, within a group defined by +a categroy code $1$/$2$ pair). + +\begin{function}{\TlReplaceOnce} +\begin{syntax} +\cs{TlReplaceOnce} \meta{tl var} \Arg{old tokens} \Arg{new tokens} +\end{syntax} +Replaces the first (leftmost) occurrence of \meta{old tokens} in the +\meta{tl var} with \meta{new tokens}. \meta{Old tokens} +cannot contain \verb|{|, \verb|}| or \verb|#| +(more precisely, explicit character tokens with category code $1$ +(begin-group) or $2$ (end-group), and tokens with category code $6$). +\end{function} + +\begin{function}{\TlReplaceAll} +\begin{syntax} +\cs{TlReplaceAll} \meta{tl var} \Arg{old tokens} \Arg{new tokens} +\end{syntax} +Replaces all occurrences of \meta{old tokens} in the +\meta{tl var} with \meta{new tokens}. \meta{Old tokens} +cannot contain \verb|{|, \verb|}| or \verb|#| +(more precisely, explicit character tokens with category code $1$ +(begin-group) or $2$ (end-group), and tokens with category code $6$). +As this function +operates from left to right, the pattern \meta{old tokens} +may remain after the replacement (see \cs{TlRemoveAll} +for an example). +\end{function} + +\begin{function}{\TlRemoveOnce} +\begin{syntax} +\cs{TlRemoveOnce} \meta{tl var} \Arg{tokens} +\end{syntax} +Removes the first (leftmost) occurrence of \meta{tokens} from the +\meta{tl var}. \meta{Tokens} cannot contain \verb|{|, \verb|}| or \verb|#| +(more precisely, explicit character tokens with category code $1$ +(begin-group) or $2$ (end-group), and tokens with category code $6$). +\end{function} + +\begin{function}{\TlRemoveAll} +\begin{syntax} +\cs{TlRemoveAll} \meta{tl var} \Arg{tokens} +\end{syntax} +Removes all occurrences of \meta{tokens} from the +\meta{tl var}. \meta{Tokens} cannot contain \verb|{|, \verb|}| or \verb|#| +(more precisely, explicit character tokens with category code $1$ +(begin-group) or $2$ (end-group), and tokens with category code $6$). +As this function +operates from left to right, the pattern \meta{tokens} +may remain after the removal, for instance, +\begin{demohigh} +\TlSet \lTmpaTl {abbccd} +\TlRemoveAll \lTmpaTl {bc} +\TlUse \lTmpaTl \end{demohigh} \end{function} +\begin{function}{\TlTrimSpaces} +\begin{syntax} +\cs{TlTrimSpaces} \Arg{token list} +\end{syntax} +Removes any leading and trailing explicit space characters +(explicit tokens with character code $32$ and category code $10$) +from the \meta{token list} and returns the result. +%\begin{texnote} +%The result is returned within \tn{unexpanded}, which means that the token +%list does not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\begin{function}{\TlVarTrimSpaces} +\begin{syntax} +\cs{TlVarTrimSpaces} \meta{tl var} +\end{syntax} +Sets the \meta{tl var} to contain the result of removing any leading +and trailing explicit space characters (explicit tokens with +character code $32$ and category code $10$) from its contents. +\end{function} + +\section{Working with the Content of Token Lists} + +\begin{function}{\TlCount} +\begin{syntax} +\cs{TlCount} \Arg{tokens} +\end{syntax} +Counts the number of \meta{items} in \meta{tokens} and returns this information. +Unbraced tokens count as one element as do each token group (\verb|{|$\cdots$\verb|}|). +This process ignores any unprotected spaces within \meta{tokens}. %See also \cs{TlVarCount}. +%This function requires three expansions, giving an \meta{integer denotation}. +\end{function} + +\begin{function}{\TlVarCount} +\begin{syntax} +\cs{TlVarCount} \meta{tl var} +\end{syntax} +Counts the number of \meta{items} in the \meta{tl var} and returns this information. +Unbraced tokens count as one element as do each token group (\verb|{|$\cdots$\verb|}|). +This process ignores any unprotected spaces within the \meta{tl var}. %See also \cs{TlCount}. +%This function requires three expansions, giving an \meta{integer denotation}. +\end{function} + +\begin{function}{\TlHead} +\begin{syntax} +\cs{TlHead} \Arg{token list} +\end{syntax} +Returns the first \meta{item} in the \meta{token list}, +discarding the rest of the \meta{token list}. +All leading explicit space characters +(explicit tokens with character code $32$ and category code $10$) +are discarded; for example +\begin{demohigh} +\fbox {1\TlHead{ abc }2} +\fbox {1\TlHead{ abc }2} +\end{demohigh} +If the \enquote{head} is a brace group, rather than a single token, +the braces are removed, and so +\begin{codehigh} +\TlHead { { ab} c } +\end{codehigh} +yields \verb*| ab|. +A blank \meta{token list} (see \cs{TlIfBlank}) results in +\cs{TlHead} returning nothing. +%\begin{texnote} +%The result is returned within \cs{exp_not:n}, which means that the token +%list does not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\begin{function}{\TlVarHead} +\begin{syntax} +\cs{TlVarHead} \meta{tl var} +\end{syntax} +Returns the first \meta{item} in the \meta{tl var}, +discarding the rest of the \meta{tl var}. +All leading explicit space characters +(explicit tokens with character code $32$ and category code $10$) +are discarded. +\end{function} + +\begin{function}{\TlTail} +\begin{syntax} +\cs{TlTail} \Arg{token list} +\end{syntax} +Discards all leading explicit space characters +(explicit tokens with character code $32$ and category code $10$) +and the first \meta{item} in the \meta{token list}, and returns the +remaining tokens. Thus for example +\begin{codehigh} +\TlTail { a {bc} d } +\end{codehigh} +and +\begin{codehigh} +\TlTail { a {bc} d } +\end{codehigh} +both return \verb*| {bc} d |. A blank \meta{token list} (see \cs{TlIfBlank}) +results in \cs{TlTail} returning nothing. +%\begin{texnote} +%The result is returned within \cs{exp_not:n}, which means that the +%token list does not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\begin{function}{\TlVarTail} +\begin{syntax} +\cs{TlVarTail} \meta{tl var} +\end{syntax} +Discards all leading explicit space characters +(explicit tokens with character code $32$ and category code $10$) +and the first \meta{item} in the \meta{tl var}, and returns the +remaining tokens. +\end{function} + +\begin{function}{\TlItem,\TlVarItem} +\begin{syntax} +\cs{TlItem} \Arg{token list} \Arg{integer expression} +\cs{TlVarItem} \meta{tl var} \Arg{integer expression} +\end{syntax} +Indexing items in the \meta{token list} from $1$ on the left, this +function evaluates the \meta{integer expression} and returns the +appropriate item from the \meta{token list}. +If the \meta{integer expression} is negative, indexing occurs from +the right of the token list, starting at $-1$ for the right-most item. +If the index is out of bounds, then the function returns nothing. +%\begin{texnote} +%The result is returned within the \tn{unexpanded} +%primitive (\cs{exp_not:n}), which means that the \meta{item} +%does not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\begin{function}{\TlRandItem,\TlVarRandItem} +\begin{syntax} +\cs{TlRandItem} \Arg{token list} +\cs{TlVarRandItem} \meta{tl var} +\end{syntax} +Selects and returns a pseudo-random item of the \meta{token list}. +If the \meta{token list} is blank, the result is empty. +%This is not available in older versions of \XeTeX{}. +%\begin{texnote} +%The result is returned within the \tn{unexpanded} +%primitive (\cs{exp_not:n}), which means that the \meta{item} +%does not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\section{Mapping over Token Lists} + +All mappings are done at the current group level, \emph{i.e.} any +local assignments made by the \meta{function} or \meta{code} discussed +below remain in effect after the loop. + +%\begin{function}{\TlMapFunction} +%\begin{syntax} +%\cs{TlMapFunction} \Arg{token list} \meta{function} +%\end{syntax} +%Applies \meta{function} to every \meta{item} in the \meta{token list}, +%The \meta{function} receives one argument for each iteration. +%This may be a number of tokens if the \meta{item} was stored within +%braces. Hence the \meta{function} should anticipate receiving +%\texttt{n}-type arguments. +%\end{function} +% +%\begin{function}{\TlVarMapFunction} +%\begin{syntax} +%\cs{TlVarMapFunction} \meta{tl var} \meta{function} +%\end{syntax} +%Applies \meta{function} to every \meta{item} in the \meta{tl var}. +%The \meta{function} receives one argument for each iteration. +%This may be a number of tokens if the \meta{item} was stored within +%braces. Hence the \meta{function} should anticipate receiving +%\texttt{n}-type arguments. +%\end{function} + +\begin{function}{\TlMapInline} +\begin{syntax} +\cs{TlMapInline} \Arg{token list} \Arg{inline function} +\end{syntax} +Applies the \meta{inline function} to every \meta{item} stored within the +\meta{token list}. The \meta{inline function} should consist of code which +receives the \meta{item} as \verb|#1|. +\end{function} + +\begin{function}{\TlVarMapInline} +\begin{syntax} +\cs{TlVarMapInline} \meta{tl var} \Arg{inline function} +\end{syntax} +Applies the \meta{inline function} to every \meta{item} stored within the +\meta{tl var}. The \meta{inline function} should consist of code which +receives the \meta{item} as \verb|#1|. +\end{function} + +%\begin{function}{\TlMapTokens,\TlVarMapTokens} +%\begin{syntax} +%\cs{TlMapTokens} \Arg{tokens} \Arg{code} +%\cs{TlVarMapTokens} \meta{tl var} \Arg{code} +%\end{syntax} +%Analogue of \cs{tl_map_function:NN} which maps several tokens +%instead of a single function. The \meta{code} receives each \meta{item} in +%the \meta{tl var} or in \meta{tokens} as a trailing brace group. For +%instance, +%\begin{verbatim} +%\tl_map_tokens:Nn \l_my_tl { \prg_replicate:nn { 2 } } +%\end{verbatim} +%expands to twice each \meta{item} in the \meta{tl var}: for each \meta{item} in +%\cs{l_my_tl} the function \cs{prg_replicate:nn} receives |2| and +%\meta{item} as its two arguments. The function +%\cs{tl_map_inline:Nn} is typically faster but is not expandable. +%\end{function} + +\begin{function}{\TlMapVariable} +\begin{syntax} +\cs{TlMapVariable} \Arg{token list} \meta{variable} \Arg{code} +\end{syntax} +Stores each \meta{item} of the \meta{token list} in turn in the +(token list) \meta{variable} and applies the \meta{code}. The +\meta{code} will usually make use of the \meta{variable}, but this +is not enforced. The assignments to the \meta{variable} are local. +Its value after the loop is the last \meta{item} in the +\meta{tl var}, or its original value if the \meta{tl var} is blank. +\end{function} + +\begin{function}{\TlVarMapVariable} +\begin{syntax} +\cs{TlVarMapVariable} \meta{tl var} \meta{variable} \Arg{code} +\end{syntax} +Stores each \meta{item} of the \meta{tl var} in turn in the (token +list) \meta{variable} and applies the \meta{code}. The \meta{code} +will usually make use of the \meta{variable}, but this is not +enforced. The assignments to the \meta{variable} are local. Its +value after the loop is the last \meta{item} in the \meta{tl var}, +or its original value if the \meta{tl var} is blank. +\end{function} + +%\begin{function}{\TlMapBreak} +%\begin{syntax} +%\cs{TlMapBreak} +%\end{syntax} +%Used to terminate a tl map function before all +%entries in the \meta{token list variable} have been processed. This +%normally takes place within a conditional statement, for example +%\begin{verbatim} +%\tl_map_inline:Nn \l_my_tl +%{ +%\str_if_eq:nnT { #1 } { bingo } { \tl_map_break: } +%Do something useful +%} +%\end{verbatim} +%See also \cs{tl_map_break:n}. +%Use outside of a tl map scenario leads to low +%level \TeX{} errors. +%\begin{texnote} +%When the mapping is broken, additional tokens may be inserted +%before the \meta{tokens} are +%inserted into the input stream. +%This depends on the design of the mapping function. +%\end{texnote} +%\end{function} +% +%\begin{function}{\TlMapBreakDo} +%\begin{syntax} +%\cs{TlMapBreakDo} \Arg{code} +%\end{syntax} +%Used to terminate a tl map function before all +%entries in the \meta{token list variable} have been processed, inserting +%the \meta{code} after the mapping has ended. This +%normally takes place within a conditional statement, for example +%\begin{verbatim} +%\tl_map_inline:Nn \l_my_tl +%{ +%\str_if_eq:nnT { #1 } { bingo } +%{ \tl_map_break:n { <code> } } +%Do something useful +%} +%\end{verbatim} +%Use outside of a tl map scenario leads to low +%level \TeX{} errors. +%\begin{texnote} +%When the mapping is broken, additional tokens may be inserted +%before the \meta{code} is +%inserted into the input stream. +%This depends on the design of the mapping function. +%\end{texnote} +%\end{function} + +\section{Token List Conditionals} + +\begin{function}{\TlIfExist,\TlIfExistTF} +\begin{syntax} +\cs{TlIfExist} \meta{tl var} +\cs{TlIfExistTF} \meta{tl var} \Arg{true code} \Arg{false code} +\end{syntax} +Tests whether the \meta{tl var} is currently defined. This does not +check that the \meta{tl var} really is a token list variable. +\end{function} + \begin{function}{\TlIfEmpty,\TlIfEmptyTF} \begin{syntax} -\cs{TlIfEmpty} \meta{tl~var} -\cs{TlIfEmptyTF} \meta{tl~var} \Arg{true code} \Arg{false code} +\cs{TlIfEmpty} \Arg{token list} +\cs{TlIfEmptyTF} \Arg{token list} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the \meta{token list} is entirely empty +(\emph{i.e.}~contains no tokens at all). For example +\begin{demohigh} +\TlIfEmptyTF {abc} {\Result{Empty}} {\Result{NonEmpty}} +\TlIfEmptyTF {} {\Result{Empty}} {\Result{NonEmpty}} +\end{demohigh} +\end{function} + +\begin{function}{\TlVarIfEmpty,\TlVarIfEmptyTF} +\begin{syntax} +\cs{TlVarIfEmpty} \meta{tl~var} +\cs{TlVarIfEmptyTF} \meta{tl~var} \Arg{true code} \Arg{false code} \end{syntax} Tests if the \meta{token list variable} is entirely empty (\emph{i.e.}~contains no tokens at all). For example \begin{demohigh} -\TlSet\lTmpaTl{abc} -\TlIfEmptyTF\lTmpaTl{\Result{Empty}}{\Result{NonEmpty}} -\TlClear\lTmpaTl -\TlIfEmptyTF\lTmpaTl{\Result{Empty}}{\Result{NonEmpty}} +\TlSet \lTmpaTl {abc} +\TlVarIfEmptyTF \lTmpaTl {\Result{Empty}} {\Result{NonEmpty}} +\TlClear \lTmpaTl +\TlVarIfEmptyTF \lTmpaTl {\Result{Empty}} {\Result{NonEmpty}} \end{demohigh} \end{function} +\begin{function}{\TlIfBlank} +\begin{syntax} +\cs{TlIfBlank} \Arg{token list} +\cs{TlIfBlankTF} \Arg{token list} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the \meta{token list} consists only of blank spaces +(\emph{i.e.} contains no item). The test is \texttt{true} if +\meta{token list} is zero or more explicit space characters +(explicit tokens with character code $32$ and category code $10$), +and is \texttt{false} otherwise. +\end{function} + \begin{function}{\TlIfEq,\TlIfEqTF} \begin{syntax} -\cs{TlIfEq} \meta{tl~var_1} \meta{tl~var_2} -\cs{TlIfEqTF} \meta{tl~var_1} \meta{tl~var_2} \Arg{true code} \Arg{false code} +\cs{TlIfEq} \Arg{token list_1} \Arg{token list_2} +\cs{TlIfEqTF} \Arg{token list_1} \Arg{token list_2} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if \meta{token list_1} and \meta{token list_2} contain the +same list of tokens, both in respect of character codes and category +codes. See \cs{StrIfEq} if category codes are not important. +For example +\begin{demohigh} +\TlIfEqTF {abc} {abc} {\Result{Yes}} {\Result{No}} +\TlIfEqTF {abc} {xyz} {\Result{Yes}} {\Result{No}} +\end{demohigh} +%\begin{demohigh} +%\TlSet\lTmpaTl{abc} +%\TlSet\lTmpbTl{abc} +%\TlSet\lTmpcTl{xyz} +%\TlIfEqTF{\TlUse\lTmpaTl}{\TlUse\lTmpbTl}{\Result{Yes}}{\Result{No}} +%\TlIfEqTF{\TlUse\lTmpaTl}{\TlUse\lTmpcTl}{\Result{Yes}}{\Result{No}} +%\end{demohigh} +\end{function} + +\begin{function}{\TlVarIfEq,\TlVarIfEqTF} +\begin{syntax} +\cs{TlVarIfEq} \meta{tl var_1} \meta{tl var_2} +\cs{TlVarIfEqTF} \meta{tl var_1} \meta{tl var_2} \Arg{true code} \Arg{false code} \end{syntax} Compares the content of two \meta{token list variables} and is logically \texttt{true} if the two contain the same list of tokens (\emph{i.e.}~identical in both the list of characters they contain and the category codes of those characters). For example \begin{demohigh} -\TlSet\lTmpaTl{abc} -\TlSet\lTmpbTl{abc} -\TlSet\lTmpcTl{xyz} -\TlIfEqTF\lTmpaTl\lTmpbTl{\Result{Yes}}{\Result{No}} -\TlIfEqTF\lTmpaTl\lTmpcTl{\Result{Yes}}{\Result{No}} +\TlSet \lTmpaTl {abc} +\TlSet \lTmpbTl {abc} +\TlSet \lTmpcTl {xyz} +\TlVarIfEqTF \lTmpaTl \lTmpbTl {\Result{Yes}} {\Result{No}} +\TlVarIfEqTF \lTmpaTl \lTmpcTl {\Result{Yes}} {\Result{No}} +\end{demohigh} +See also \cs{StrVarIfEq} for a comparison that ignores category codes. +\end{function} + +\begin{function}{\TlIfIn,\TlIfInTF} +\begin{syntax} +\cs{TlIfIn} \Arg{token list_1} \Arg{token list_2} +\cs{TlIfInTF} \Arg{token list_1} \Arg{token list_2} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if \meta{token list_2} is found inside \meta{token list_1}. +The \meta{token list_2} cannot contain the tokens \verb|{|, \verb|}| or \verb|#| +(more precisely, explicit character tokens with category code $1$ +(begin-group) or $2$ (end-group), and tokens with category code $6$). +The search does \emph{not} enter brace (category code $1$/$2$) groups. +\end{function} + +\begin{function}{\TlVarIfIn,\TlVarIfInTF} +\begin{syntax} +\cs{TlVarIfIn} \meta{tl var} \Arg{token list} +\cs{TlVarIfInTF} \meta{tl var} \Arg{token list} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the \meta{token list} is found in the content of the +\meta{tl var}. The \meta{token list} cannot contain +the tokens \verb|{|, \verb|}| or \verb|#| +(more precisely, explicit character tokens with category code $1$ +(begin-group) or $2$ (end-group), and tokens with category code $6$). +\end{function} + +\begin{function}{\TlIfSingle,\TlIfSingleTF} +\begin{syntax} +\cs{TlIfSingle} \Arg{token list} +\cs{TlIfSingleTF} \Arg{token list} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the \meta{token list} has exactly one \meta{item}, \emph{i.e.} is +a single normal token (neither an explicit space character nor a +begin-group character) or a single brace group, surrounded by +optional spaces on both sides. In other words, such a token list has +token count $1$ according to \cs{TlCount}. +\end{function} + +\begin{function}{\TlVarIfSingle,\TlVarIfSingleTF} +\begin{syntax} +\cs{TlVarIfSingle} \meta{tl var} +\cs{TlVarIfSingleTF} \meta{tl var} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the content of the \meta{tl var} consists of a single \meta{item}, +\emph{i.e.} is a single normal token (neither an explicit space +character nor a begin-group character) or a single brace group, +surrounded by optional spaces on both sides. In other words, such a +token list has token count $1$ according to \cs{TlVarCount}. +\end{function} + +\section{Token List Case Functions} + +\begin{function}{\TlVarCase} +\begin{syntax} +\cs{TlVarCase} \meta{test token list variable} +~ ~ \verb"{" +~ ~ ~ ~ \meta{token list variable case_1} \Arg{code case_1} +~ ~ ~ ~ \meta{token list variable case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \meta{token list variable case_n} \Arg{code case_n} +~ ~ \verb"}" +\end{syntax} +This function compares the \meta{test token list variable} in turn +with each of the \meta{token list variable cases}. If the two +are equal (as described for \cs{TlVarIfEq}) +then the associated \meta{code} is left in the input +stream and other cases are discarded. The function +does nothing if there is no match. +\end{function} + +\begin{function}{\TlVarCaseT} +\begin{syntax} +\cs{TlVarCaseT} \meta{test token list variable} +~ ~ \verb"{" +~ ~ ~ ~ \meta{token list variable case_1} \Arg{code case_1} +~ ~ ~ ~ \meta{token list variable case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \meta{token list variable case_n} \Arg{code case_n} +~ ~ \verb"}" +~ ~ \Arg{true code} +\end{syntax} +This function compares the \meta{test token list variable} in turn +with each of the \meta{token list variable cases}. If the two +are equal (as described for \cs{TlVarIfEq}) +then the associated \meta{code} is left in the input +stream and other cases are discarded. If any of the +cases are matched, the \meta{true code} is also inserted into the +input stream (after the code for the appropriate case). +\end{function} + +\begin{function}{\TlVarCaseF} +\begin{syntax} +\cs{TlVarCaseF} \meta{test token list variable} +~ ~ \verb"{" +~ ~ ~ ~ \meta{token list variable case_1} \Arg{code case_1} +~ ~ ~ ~ \meta{token list variable case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \meta{token list variable case_n} \Arg{code case_n} +~ ~ \verb"}" +~ ~ \Arg{false code} +\end{syntax} +This function compares the \meta{test token list variable} in turn +with each of the \meta{token list variable cases}. If the two +are equal (as described for \cs{TlVarIfEq}) +then the associated \meta{code} is left in the input +stream and other cases are discarded. If none +match then the \meta{false code} is inserted into the input stream + (after the code for the appropriate case). +\end{function} + +\begin{function}{\TlVarCaseTF} +\begin{syntax} +\cs{TlVarCaseTF} \meta{test token list variable} +~ ~ \verb"{" +~ ~ ~ ~ \meta{token list variable case_1} \Arg{code case_1} +~ ~ ~ ~ \meta{token list variable case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \meta{token list variable case_n} \Arg{code case_n} +~ ~ \verb"}" +~ ~ \Arg{true code} +~ ~ \Arg{false code} +\end{syntax} +This function compares the \meta{test token list variable} in turn +with each of the \meta{token list variable cases}. If the two +are equal (as described for \cs{TlVarIfEq}) +then the associated \meta{code} is left in the input +stream and other cases are discarded. If any of the +cases are matched, the \meta{true code} is also inserted into the +input stream (after the code for the appropriate case), while if none +match then the \meta{false code} is inserted. The function +\cs{TlVarCase}, which does nothing if there is no match, is also +available. +\end{function} + +\chapter{Strings (\texttt{Str})} + +\section{Constant and Scratch Strings} + +\begin{variable}{\cAmpersandStr,\cAtsignStr,\cBackslashStr,\cLeftBraceStr,\cRightBraceStr, +\cCircumflexStr,\cColonStr,\cDollarStr,\cHashStr,\cPercentStr,\cTildeStr,\cUnderscoreStr,\cZeroStr} +Constant strings, containing a single character token, with category code $12$. +\end{variable} + +\begin{variable}{\lTmpaStr,\lTmpbStr,\lTmpcStr,\lTmpiStr,\lTmpjStr,\lTmpkStr} +Scratch strings for local assignment. These are never used by +the \verb!functional! package, and so are safe for use with any +function. However, they may be overwritten by other +code and so should only be used for short-term storage. +\end{variable} + +\begin{variable}{\gTmpaStr,\gTmpbStr,\gTmpcStr,\gTmpiStr,\gTmpjStr,\gTmpkStr} +Scratch strings for global assignment. These are never used by +the \verb!functional! package, and so are safe for use with any +function. However, they may be overwritten by other +code and so should only be used for short-term storage. +\end{variable} + +\section{Creating and Using Strings} + +\begin{function}{\StrNew} +\begin{syntax} +\cs{StrNew} \meta{str var} +\end{syntax} +Creates a new \meta{str var} or raises an error if the name is +already taken. The declaration is global. The \meta{str var} is +initially empty. +\end{function} + +\begin{function}{\StrConst} +\begin{syntax} +\cs{StrConst} \meta{str var} \Arg{token list} +\end{syntax} +Creates a new constant \meta{str var} or raises an error if the name +is already taken. The value of the \meta{str var} is set +globally to the \meta{token list}, converted to a string. +\end{function} + +\begin{function}{\StrUse} +\begin{syntax} +\cs{StrUse} \meta{str var} +\end{syntax} +Recovers the content of a \meta{str var} and returns the value. +An error is raised if the variable +does not exist or if it is invalid. Note that it is possible to use +a \meta{str} directly without an accessor function. +\end{function} + +\section{Viewing Strings} + +\begin{function}{\StrLog} +\begin{syntax} +\cs{StrLog} \Arg{token list} +\end{syntax} +Writes \meta{token list} in the log file. +\end{function} + +\begin{function}{\StrVarLog} +\begin{syntax} +\cs{StrVarLog} \meta{str var} +\end{syntax} +Writes the content of the \meta{str var} in the log file. +For example +\begin{codehigh} +\StrSet \lTmpiStr {1234\abcd5678} +\StrVarLog \lTmpiStr +\end{codehigh} +\end{function} + +\begin{function}{\StrShow} +\begin{syntax} +\cs{StrShow} \Arg{token list} +\end{syntax} +Displays \meta{token list} on the terminal. +\end{function} + +\begin{function}{\StrVarShow} +\begin{syntax} +\cs{StrVarShow} \meta{str var} +\end{syntax} +Displays the content of the \meta{str var} on the terminal. +\end{function} + +\section{Setting String Variables} + +\begin{function}{\StrSet} +\begin{syntax} +\cs{StrSet} \meta{str var} \Arg{token list} +\end{syntax} +Converts the \meta{token list} to a \meta{string}, and stores the +result in \meta{str var}. For example +\begin{demohigh} +\StrSet \lTmpiStr {\IntMathMult{4}{5}} +\StrUse \lTmpiStr +\end{demohigh} +\end{function} + +\begin{function}{\StrSetEq} +\begin{syntax} +\cs{StrSetEq} \meta{str var_1} \meta{str var_2} +\end{syntax} +Sets the content of \meta{str var_1} equal to that of +\meta{str var_2}. +\end{function} + +\begin{function}{\StrClear} +\begin{syntax} +\cs{StrClear} \meta{str var} +\end{syntax} +Clears the content of the \meta{str var}. For example +\begin{demohigh} +\StrSet \lTmpjStr {One} +\StrClear \lTmpjStr +\StrSet \lTmpjStr {Two} +\StrUse \lTmpjStr +\end{demohigh} +\end{function} + +\begin{function}{\StrClearNew} +\begin{syntax} +\cs{StrClearNew} \meta{str var} +\end{syntax} +Ensures that the \meta{str var} exists globally by applying +\cs{StrNew} if necessary, then applies \cs{StrClear} to leave +the \meta{str var} empty. +\end{function} + +\begin{function}{\StrConcat} +\begin{syntax} +\cs{StrConcat} \meta{str var_1} \meta{str var_2} \meta{str var_3} +\end{syntax} +Concatenates the content of \meta{str var_2} and \meta{str var_3} +together and saves the result in \meta{str var_1}. The \meta{str var_2} +is placed at the left side of the new string variable. +The \meta{str var_2} and \meta{str var_3} must indeed be strings, as +this function does not convert their contents to a string. +\end{function} + +\begin{function}{\StrPutLeft} +\begin{syntax} +\cs{StrPutLeft} \meta{str var} \Arg{token list} +\end{syntax} +Converts the \meta{token list} to a \meta{string}, and prepends the +result to \meta{str var}. The current contents of the \meta{str +var} are not automatically converted to a string. For example +\begin{demohigh} +\StrSet \lTmpkStr {Functional} +\StrPutLeft \lTmpkStr {Hello} +\StrUse \lTmpkStr +\end{demohigh} +\end{function} + +\begin{function}{\StrPutRight} +\begin{syntax} +\cs{StrPutRight} \meta{str var} \Arg{token list} +\end{syntax} +Converts the \meta{token list} to a \meta{string}, and appends the +result to \meta{str var}. The current contents of the \meta{str +var} are not automatically converted to a string. For example +\begin{demohigh} +\StrSet \lTmpkStr {Functional} +\StrPutRight \lTmpkStr {World} +\StrUse \lTmpkStr +\end{demohigh} +\end{function} + +\section{Modifying String Variables} + +\begin{function}{\StrReplaceOnce} +\begin{syntax} +\cs{StrReplaceOnce} \meta{str var} \Arg{old} \Arg{new} +\end{syntax} +Converts the \meta{old} and \meta{new} token lists to strings, then +replaces the first (leftmost) occurrence of \meta{old string} in the +\meta{str var} with \meta{new string}. +\end{function} + +\begin{function}{\StrReplaceAll} +\begin{syntax} +\cs{StrReplaceAll} \meta{str var} \Arg{old} \Arg{new} +\end{syntax} +Converts the \meta{old} and \meta{new} token lists to strings, then +replaces all occurrences of \meta{old string} in the +\meta{str var} with \meta{new string}. +As this function +operates from left to right, the pattern \meta{old string} +may remain after the replacement. +\end{function} + +\begin{function}{\StrRemoveOnce} +\begin{syntax} +\cs{StrRemoveOnce} \meta{str var} \Arg{token list} +\end{syntax} +Converts the \meta{token list} to a \meta{string} then +removes the first (leftmost) occurrence of \meta{string} from the +\meta{str var}. +\end{function} + +\begin{function}{\StrRemoveAll} +\begin{syntax} +\cs{StrRemoveAll} \meta{str var} \Arg{token list} +\end{syntax} +Converts the \meta{token list} to a \meta{string} then +removes all occurrences of \meta{string} from the \meta{str var}. +As this function operates from left to right, +the pattern \meta{string} may remain after the removal, for instance, +\begin{demohigh} +\StrSet \lTmpaStr {abbccd} +\StrRemoveAll \lTmpaStr {bc} +\TlUse \lTmpaStr +\end{demohigh} +\end{function} + +\section{Working with the Content of Strings} + +\begin{function}{\StrCount} +\begin{syntax} +\cs{StrCount} \Arg{token list} +\end{syntax} +Returns the number of characters in the string representation of \meta{token list}, +as an integer denotation. All characters including spaces are counted. +\par +Due to naming conflict, you need to use \cs{StrSize} instead of \cs{StrCount} +if you want to use \verb!functional! package together with \verb!xstring! package. +\end{function} + +\begin{function}{\StVarCount} +\begin{syntax} +\cs{StrVarCount} \meta{tl var} +\end{syntax} +Returns the number of characters in the string representation of the \meta{tl var}, +as an integer denotation. All characters including spaces are counted. +\end{function} + +\begin{function}{\StrHead} +\begin{syntax} +\cs{StrHead} \Arg{token list} +\end{syntax} +Converts the \meta{token list} into a \meta{string}. +The first character in the \meta{string} is then returned, +with category code \enquote{other}. If the first character is a space, +it returns a space token with category code $10$ (blank space). +If the \meta{string} is empty, then nothing is returned. +\end{function} + +\begin{function}{\StrVarHead} +\begin{syntax} +\cs{StrVarHead} \meta{tl var} +\end{syntax} +Converts the \meta{tl var} into a \meta{string}. +The first character in the \meta{string} is then returned, +with category code \enquote{other}. If the first character is a space, +it returns a space token with category code $10$ (blank space). +If the \meta{string} is empty, then nothing is returned. +\end{function} + +\begin{function}{\StrTail} +\begin{syntax} +\cs{StrTail} \Arg{token list} +\end{syntax} +Converts the \meta{token list} to a \meta{string}, removes the first +character, and returns the remaining characters (if any) +with category codes $12$ and $10$ (for spaces). +If the first character is a space, it only trims that space. +If the \meta{token list} is empty, +then nothing is left on the input stream. +\end{function} + +\begin{function}{\StrVarTail} +\begin{syntax} +\cs{StrVarTail} \meta{tl var} +\end{syntax} +Converts the \meta{tl var} to a \meta{string}, removes the first +character, and returns the remaining characters (if any) +with category codes $12$ and $10$ (for spaces). +If the first character is a space, it only trims that space. +If the \meta{token list} is empty, +then nothing is left on the input stream. +\end{function} + +\begin{function}{\StrItem} +\begin{syntax} +\cs{StrItem} \Arg{token list} \Arg{integer expression} +\end{syntax} +Converts the \meta{token list} to a \meta{string}, +and returns the character in position \meta{integer expression} of +the \meta{string}, starting at $1$ for the first (left-most) +character. All characters including spaces are taken into account. +If the \meta{integer expression} is negative, +characters are counted from the end of the \meta{string}. Hence, +$-1$ is the right-most character, \emph{etc.} +\end{function} + +\begin{function}{\StrVarItem} +\begin{syntax} +\cs{StrVarItem} \meta{tl var} \Arg{integer expression} +\end{syntax} +Converts the \meta{tl var} to a \meta{string}, +and returns the character in position \meta{integer expression} of +the \meta{string}, starting at $1$ for the first (left-most) +character. All characters including spaces are taken into account. +If the \meta{integer expression} is negative, +characters are counted from the end of the \meta{string}. Hence, +$-1$ is the right-most character, \emph{etc.} +\end{function} + +\section{Mapping over Strings} + +All mappings are done at the current group level, \emph{i.e.} any +local assignments made by the \meta{function} or \meta{code} discussed +below remain in effect after the loop. + +%\begin{function}{\StrMapFunction,\StrVarMapFunction} +%\begin{syntax} +%\cs{StrMapFunction} \Arg{token list} \meta{function} +%\cs{StrVarMapFunction} \meta{str var} \meta{function} +%\end{syntax} +%Converts the \meta{token list} to a \meta{string} then +%applies \meta{function} to every \meta{character} in the +%\meta{string} including spaces. +%\end{function} + +\begin{function}{\StrMapInline,\StrVarMapInline} +\begin{syntax} +\cs{StrMapInline} \Arg{token list} \Arg{inline function} +\cs{StrVarMapInline} \meta{str var} \Arg{inline function} +\end{syntax} +Converts the \meta{token list} to a \meta{string} then +applies the \meta{inline function} to every \meta{character} in the +\meta{str var} including spaces. +The \meta{inline function} should consist of code which +receives the \meta{character} as \verb|#1|. +\end{function} + +%\begin{function}{\StrMapTokens, \StrVarMapTokens} +%\begin{syntax} +%\cs{StrMapTokens} \Arg{token list} \Arg{code} +%\cs{StrVarMapTokens} \meta{str var} \Arg{code} +%\end{syntax} +%Converts the \meta{token list} to a \meta{string} then applies +%\meta{code} to every \meta{character} in the \meta{string} including spaces. +%The \meta{code} receives each character as a trailing brace group. +%This is equivalent to \cs{StrMapFunction} if the +%\meta{code} consists of a single function. +%\end{function} + +\begin{function}{\StrMapVariable,\StrMapVariable} +\begin{syntax} +\cs{StrMapVariable} \Arg{token list} \meta{variable} \Arg{code} +\cs{StrVarMapVariable} \meta{str var} \meta{variable} \Arg{code} +\end{syntax} +Converts the \meta{token list} to a \meta{string} then stores each +\meta{character} in the \meta{string} (including spaces) in turn in +the (string or token list) \meta{variable} and applies the +\meta{code}. The \meta{code} will usually make use of the +\meta{variable}, but this is not enforced. The assignments to the +\meta{variable} are local. Its value after the loop is the last +\meta{character} in the \meta{string}, or its original value if the +\meta{string} is empty. +\end{function} + +%\begin{function}{\StrMapBreak} +%\begin{syntax} +%\cs{StrMapBreak} +%\end{syntax} +%Used to terminate a string map function before all +%characters in the \meta{string} have been processed. This +%normally takes place within a conditional statement, for example +%\begin{verbatim} +%\str_map_inline:Nn \l_my_str +%{ +%\str_if_eq:nnT { #1 } { bingo } { \str_map_break: } +%Do something useful +%} +%\end{verbatim} +%See also \cs{StrMapBreakDo}. +%Use outside of a string map scenario leads to low +%level \TeX{} errors. +%\begin{texnote} +%When the mapping is broken, additional tokens may be inserted +%before continuing with the +%code that follows the loop. +%This depends on the design of the mapping function. +%\end{texnote} +%\end{function} +% +%\begin{function}{\StrMapBreakDo} +%\begin{syntax} +%\cs{StrMapBreakDo} \Arg{code} +%\end{syntax} +%Used to terminate a string map function before all +%characters in the \meta{string} have been processed, inserting +%the \meta{code} after the mapping has ended. This +%normally takes place within a conditional statement, for example +%\begin{verbatim} +%\str_map_inline:Nn \l_my_str +%{ +%\str_if_eq:nnT { #1 } { bingo } +%{ \str_map_break:n { <code> } } +%Do something useful +%} +%\end{verbatim} +%Use outside of a string map scenario leads to low +%level \TeX{} errors. +%\begin{texnote} +%When the mapping is broken, additional tokens may be inserted +%before the \meta{code} is +%inserted into the input stream. +%This depends on the design of the mapping function. +%\end{texnote} +%\end{function} + +\section{String Conditionals} + +\begin{function}{\StrIfExist,\StrIfExistTF} +\begin{syntax} +\cs{StrIfExist} \meta{str var} +\cs{StrIfExistTF} \meta{str var} \Arg{true code} \Arg{false code} +\end{syntax} +Tests whether the \meta{str var} is currently defined. This does not +check that the \meta{str var} really is a string. +\end{function} + +\begin{function}{\StrVarIfEmpty,\StrVarIfEmptyTF} +\begin{syntax} +\cs{StrVarIfEmpty} \meta{str var} +\cs{StrVarIfEmptyTF} \meta{str var} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the \meta{string variable} is entirely empty +(\emph{i.e.} contains no characters at all). For example +\begin{demohigh} +\StrSet \lTmpaStr {abc} +\StrVarIfEmptyTF \lTmpaStr {\Result{Empty}} {\Result{NonEmpty}} +\StrClear \lTmpaStr +\StrVarIfEmptyTF \lTmpaStr {\Result{Empty}} {\Result{NonEmpty}} \end{demohigh} -%See also \cs{StrIfEqTF} for a comparison that ignores category codes. \end{function} -\chapter{Integers (\texttt{l3int})} +\begin{function}{\StrIfEq,\StrIfEqTF} +\begin{syntax} +\cs{StrIfEq} \Arg{tl_1} \Arg{tl_2} +\cs{StrIfEqTF} \Arg{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code} +\end{syntax} +Compares the two \meta{token lists} on a character by character +basis (namely after converting them to strings), +and is \texttt{true} if the two \meta{strings} contain the same +characters in the same order. +%Thus for example +%\begin{codehigh} +%\StrIfEq{abc}{\TlToStr{abc}} +%\end{codehigh} +%is logically \texttt{true}. +See \cs{TlIfEq} to compare +tokens (including their category codes) rather than characters. +For example +\begin{demohigh} +\StrIfEqTF {abc} {abc} {\Result{Yes}} {\Result{No}} +\StrIfEqTF {abc} {xyz} {\Result{Yes}} {\Result{No}} +\end{demohigh} +%\begin{demohigh} +%\StrSet\lTmpaStr{abc} +%\StrSet\lTmpbStr{abc} +%\StrSet\lTmpcStr{xyz} +%\StrIfEqTF{\lTmpaStr}{\lTmpbStr}{\Result{Yes}}{\Result{No}} +%\StrIfEqTF{\lTmpaStr}{\lTmpcStr}{\Result{Yes}}{\Result{No}} +%\StrIfEqTF{\StrUse\lTmpaStr}{\StrUse\lTmpbStr}{\Result{Yes}}{\Result{No}} +%\StrIfEqTF{\StrUse\lTmpaStr}{\StrUse\lTmpcStr}{\Result{Yes}}{\Result{No}} +%\end{demohigh} +\end{function} -\section{Scratch Variables of Integers} +\begin{function}{\StrVarIfEq,\StrVarIfEqTF} +\begin{syntax} +\cs{StrVarIfEq} \meta{str var_1} \meta{str var_2} +\cs{StrVarIfEqTF} \meta{str var_1} \meta{str var_2} \Arg{true code} \Arg{false code} +\end{syntax} +Compares the content of two \meta{str variables} and +is logically \texttt{true} if the two contain the same characters +in the same order. See \cs{TlVarIfEq} to compare tokens +(including their category codes) rather than characters. +\begin{demohigh} +\StrSet \lTmpaStr {abc} +\StrSet \lTmpbStr {abc} +\StrSet \lTmpcStr {xyz} +\StrVarIfEqTF \lTmpaStr \lTmpbStr {\Result{Yes}} {\Result{No}} +\StrVarIfEqTF \lTmpaStr \lTmpcStr {\Result{Yes}} {\Result{No}} +\end{demohigh} +\end{function} + +\begin{function}{\StrIfIn,\StrIfInTF} +\begin{syntax} +\cs{StrIfInTF} \Arg{tl_1} \Arg{tl_2} +\cs{StrIfInTF} \Arg{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code} +\end{syntax} +Converts both \meta{token lists} to \meta{strings} and +tests whether \meta{string_2} is found inside \meta{string_1}. +\end{function} + +\begin{function}{\StrVarIfIn,\StrVarIfInTF} +\begin{syntax} +\cs{StrVarIfInTF} \meta{str var} \Arg{token list} +\cs{StrVarIfInTF} \meta{str var} \Arg{token list} \Arg{true code} \Arg{false code} +\end{syntax} +Converts the \meta{token list} to a \meta{string} and +tests if that \meta{string} is found in the content of the +\meta{str var}. +\end{function} + +\begin{function}{\StrCompare,\StrCompareTF} +\begin{syntax} +\cs{StrCompare} \Arg{tl_1} \meta{relation} \Arg{tl_2} +\cs{StrCompareTF} \Arg{tl_1} \meta{relation} \Arg{tl_2} \Arg{true code} \Arg{false code} +\end{syntax} +Compares the two \meta{token lists} on a character by character +basis (namely after converting them to strings) in a lexicographic +order according to the character codes of the characters. The +\meta{relation} can be \verb|<|, \verb|=|, or \verb|>| and the test is +\texttt{true} under the following conditions: +\begin{itemize}[nosep] +\item for \verb|<|, if the first string is earlier than the second in lexicographic order; +\item for \verb|=|, if the two strings have exactly the same characters; +\item for \verb|>|, if the first string is later than the second in lexicographic order. +\end{itemize} +For example: +\begin{demohigh} +\StrCompareTF {ab} < {abc} {\Result{Yes}} {\Result{No}} +\StrCompareTF {ab} < {aa} {\Result{Yes}} {\Result{No}} +\end{demohigh} +%\begin{texnote} +%This is a wrapper around the \TeX{} primitive +%\cs{(pdf)strcmp}. It is meant for programming +%and not for sorting textual contents, as it simply considers +%character codes and not more elaborate considerations of grapheme +%clusters, locale, etc. +%\end{texnote} +\par +Due to naming conflict, you need to use \cs{StrIfCompare}/\cs{StrIfCompareTF} as a replacement +if you want to use \verb!functional! package together with \verb!xstring! package. +\end{function} + +\section{String Case Functions} + +\begin{function}{\StrCase} +\begin{syntax} +\cs{StrCase} \Arg{test string} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{string case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{string case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \Arg{string case_n} \Arg{code case_n} +~ ~ \verb|}| +\end{syntax} +Compares the \meta{test string} in turn with each +of the \meta{string cases} (all token lists are converted to strings). +If the two are equal (as described for +\cs{StrIfEq}) then the associated \meta{code} is left in the +input stream and other cases are discarded. +\end{function} + +\begin{function}{\StrCaseT} +\begin{syntax} +\cs{StrCaseT} \Arg{test string} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{string case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{string case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \Arg{string case_n} \Arg{code case_n} +~ ~ \verb|}| +~ ~ \Arg{true code} +\end{syntax} +Compares the \meta{test string} in turn with each +of the \meta{string cases} (all token lists are converted to strings). +If the two are equal (as described for +\cs{StrIfEq}) then the associated \meta{code} is left in the +input stream and other cases are discarded. If any of the +cases are matched, the \meta{true code} is also inserted into the +input stream (after the code for the appropriate case). +\end{function} + +\begin{function}{\StrCaseF} +\begin{syntax} +\cs{StrCaseF} \Arg{test string} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{string case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{string case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \Arg{string case_n} \Arg{code case_n} +~ ~ \verb|}| +~ ~ \Arg{false code} +\end{syntax} +Compares the \meta{test string} in turn with each +of the \meta{string cases} (all token lists are converted to strings). +If the two are equal (as described for +\cs{StrIfEq}) then the associated \meta{code} is left in the +input stream and other cases are discarded. If none +match then the \meta{false code} is inserted. +\end{function} + +\begin{function}{\StrCaseTF} +\begin{syntax} +\cs{StrCaseTF} \Arg{test string} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{string case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{string case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \Arg{string case_n} \Arg{code case_n} +~ ~ \verb|}| +~ ~ \Arg{true code} +~ ~ \Arg{false code} +\end{syntax} +Compares the \meta{test string} in turn with each +of the \meta{string cases} (all token lists are converted to strings). +If the two are equal (as described for +\cs{StrIfEq}) then the associated \meta{code} is left in the +input stream and other cases are discarded. If any of the +cases are matched, the \meta{true code} is also inserted into the +input stream (after the code for the appropriate case), while if none +match then the \meta{false code} is inserted. +\end{function} + +\chapter{Integers (\texttt{Int})} + +\section{Constant and Scratch Integers} + +\begin{variable}{\cZeroInt,\cOneInt} +Integer values used with primitive tests and assignments: their +self-terminating nature makes these more convenient and faster than +literal numbers. +\end{variable} + +\begin{variable}{\cMaxInt} +The maximum value that can be stored as an integer. +\end{variable} + +\begin{variable}{\cMaxRegisterInt} +Maximum number of registers. +\end{variable} + +\begin{variable}{\cMaxCharInt} +Maximum character code completely supported by the engine. +\end{variable} \begin{variable}{\lTmpaInt,\lTmpbInt,\lTmpcInt,\lTmpiInt,\lTmpjInt,\lTmpkInt} Scratch integer for local assignment. These are never used by @@ -781,7 +2320,7 @@ function. However, they may be overwritten by other code and so should only be used for short-term storage. \end{variable} -\section{Public Functions for Integers} +\section{Integer Expressions} \begin{function}{\IntEval} \begin{syntax} @@ -793,7 +2332,7 @@ explicit sequence of decimal digits not starting with~\texttt{0}, for negative results \texttt{-}~followed by such a sequence, and \texttt{0}~for zero. For example \begin{demohigh} -\IntEval{(1+4)*(2-3)/5} +\IntEval {(1+4)*(2-3)/5} \end{demohigh} \end{function} @@ -804,7 +2343,7 @@ for negative results \texttt{-}~followed by such a sequence, and Adds \Arg{integer expression_1} and \Arg{integer expression_2}, and returns the result. For example \begin{demohigh} -\IntMathAdd{7}{3} +\IntMathAdd {7} {3} \end{demohigh} \end{function} @@ -812,10 +2351,10 @@ and returns the result. For example \begin{syntax} \cs{IntMathSub} \Arg{integer expression_1} \Arg{integer expression_2} \end{syntax} -Subtracts \Arg{integer expression_1} from \Arg{integer expression_2}, +Subtracts \Arg{integer expression_2} from \Arg{integer expression_1}, and returns the result. For example \begin{demohigh} -\IntMathSub{7}{3} +\IntMathSub {7} {3} \end{demohigh} \end{function} @@ -826,7 +2365,7 @@ and returns the result. For example Multiplies \Arg{integer expression_1} by \Arg{integer expression_2}, and returns the result. For example \begin{demohigh} -\IntMathMult{7}{3} +\IntMathMult {7} {3} \end{demohigh} \end{function} @@ -834,13 +2373,85 @@ and returns the result. For example \begin{syntax} \cs{IntMathDiv} \Arg{integer expression_1} \Arg{integer expression_2} \end{syntax} -Divides \Arg{integer expression_1} by \Arg{integer expression_2}, -and returns the result. For example +Evaluates the two \meta{integer expressions} as described earlier, +then divides the first value by the second, and rounds the result +to the closest integer. Ties are rounded away from zero. Note that +this is identical to using \verb|/| directly in an \meta{integer expression}. +The result is returned as an \meta{integer denotation}. +For example +\begin{demohigh} +\IntMathDiv {8} {3} +\end{demohigh} +\end{function} + +\begin{function}{\IntMathDivTrancate} +\begin{syntax} +\cs{IntMathDivTrancate} \Arg{integer expression_1} \Arg{integer expression_2} +\end{syntax} +Evaluates the two \meta{integer expressions} as described earlier, +then divides the first value by the second, and rounds the result towards zero. +Note that division using \verb|/| rounds to the closest integer instead. +The result is returned as an \meta{integer denotation}. +For example \begin{demohigh} -\IntMathDiv{7}{3} +\IntMathDivTruncate {8} {3} \end{demohigh} \end{function} +\begin{function}{\IntMathSign} +\begin{syntax} +\cs{IntMathSign} \Arg{intexpr} +\end{syntax} +Evaluates the \meta{integer expression} then leaves $1$ or $0$ or +$-1$ in the input stream according to the sign of the result. +\end{function} + +\begin{function}{\IntMathAbs} +\begin{syntax} +\cs{IntMathAbs} \Arg{integer expression} +\end{syntax} +Evaluates the \meta{integer expression} as described for +\cs{IntEval} and leaves the absolute value of the result in +the input stream as an \meta{integer denotation} after two +expansions. +\end{function} + +\begin{function}{\IntMathMax,\IntMathMin} +\begin{syntax} +\cs{IntMathMax} \Arg{intexpr_1} \Arg{intexpr_2} +\cs{IntMathMin} \Arg{intexpr_1} \Arg{intexpr_2} +\end{syntax} +Evaluates the \meta{integer expressions} as described for +\cs{IntEval} and leaves either the larger or smaller value +in the input stream as an \meta{integer denotation} after two +expansions. +\end{function} + +\begin{function}{\IntMathMod} +\begin{syntax} +\cs{IntMathMod} \Arg{intexpr_1} \Arg{intexpr_2} +\end{syntax} +Evaluates the two \meta{integer expressions} as described earlier, +then calculates the integer remainder of dividing the first +expression by the second. This is obtained by subtracting +\cs{IntMathDivTruncate} \Arg{intexpr_1} \Arg{intexpr_2} times +\meta{intexpr_2} from \meta{intexpr_1}. Thus, the result has the +same sign as \meta{intexpr_1} and its absolute value is strictly +less than that of \meta{intexpr_2}. The result is left in the input +stream as an \meta{integer denotation} after two expansions. +\end{function} + +\begin{function}{\IntMathRand} +\begin{syntax} +\cs{IntMathRand} \Arg{intexpr_1} \Arg{intexpr_2} +\end{syntax} +Evaluates the two \meta{integer expressions} and produces a +pseudo-random number between the two (with bounds included). +%This is not available in older versions of \XeTeX{}. +\end{function} + +\section{Creating and Using Integers} + \begin{function}{\IntNew} \begin{syntax} \cs{IntNew} \meta{integer} @@ -850,21 +2461,57 @@ already taken. The declaration is global. The \meta{integer} is initially equal to $0$. \end{function} +\begin{function}{\IntConst} +\begin{syntax} +\cs{IntConst} \meta{integer} \Arg{integer expression} +\end{syntax} +Creates a new constant \meta{integer} or raises an error if the name +is already taken. The value of the \meta{integer} is set +globally to the \meta{integer expression}. +\end{function} + \begin{function}{\IntUse} \begin{syntax} \cs{IntUse} \meta{integer} \end{syntax} Recovers the content of an \meta{integer} and returns the value. -An error is raised if the variable does -not exist or if it is invalid. Can be omitted in places where an -\meta{integer} is required (such as in the first and third arguments -of \cs{IntCompareTF}).% -%\begin{texnote} -%\cs{IntUse} is the \TeX{} primitive \tn{the}: this is one of -%several \verb!functional! names for this primitive. -%\end{texnote} +An error is raised if the variable does not exist or if it is invalid. +\end{function} + +\section{Viewing Integers} + +\begin{function}{\IntLog} +\begin{syntax} +\cs{IntLog} \Arg{integer expression} +\end{syntax} +Writes the result of evaluating the \meta{integer expression} +in the log file. +\end{function} + +\begin{function}{\IntVarLog} +\begin{syntax} +\cs{IntVarLog} \meta{integer} +\end{syntax} +Writes the value of the \meta{integer} in the log file. +\end{function} + +\begin{function}{\IntShow} +\begin{syntax} +\cs{IntShow} \Arg{integer expression} +\end{syntax} +Displays the result of evaluating the \meta{integer expression} +on the terminal. +\end{function} + +\begin{function}{\IntVarShow} +\begin{syntax} +\cs{IntVarShow} \meta{integer} +\end{syntax} +Displays the value of the \meta{integer} on the terminal. \end{function} +\section{Setting Integer Variables} + \begin{function}{\IntSet} \begin{syntax} \cs{IntSet} \meta{integer} \Arg{integer expression} @@ -873,23 +2520,40 @@ Sets \meta{integer} to the value of \meta{integer expression}, which must evaluate to an integer (as described for \cs{IntEval}). For example \begin{demohigh} -\IntSet\lTmpaInt{3+5} -\IntUse\lTmpaInt +\IntSet \lTmpaInt {3+5} +\IntUse \lTmpaInt \end{demohigh} \end{function} +\begin{function}{\IntSetEq} +\begin{syntax} +\cs{IntSetEq} \meta{integer_1} \meta{integer_2} +\end{syntax} +Sets the content of \meta{integer_1} equal to that of +\meta{integer_2}. +\end{function} + \begin{function}{\IntZero} \begin{syntax} \cs{IntZero} \meta{integer} \end{syntax} Sets \meta{integer} to $0$. For example \begin{demohigh} -\IntSet\lTmpaInt{5} -\IntZero\lTmpaInt -\IntUse\lTmpaInt +\IntSet \lTmpaInt {5} +\IntZero \lTmpaInt +\IntUse \lTmpaInt \end{demohigh} \end{function} +\begin{function}{\IntZeroNew} +\begin{syntax} +\cs{IntZeroNew} \meta{integer} +\end{syntax} +Ensures that the \meta{integer} exists globally by applying +\cs{IntNew} if necessary, then applies \cs{IntZero} to leave +the \meta{integer} set to zero. +\end{function} + \begin{function}{\IntIncr} \begin{syntax} \cs{IntIncr} \meta{integer} @@ -897,9 +2561,9 @@ Sets \meta{integer} to $0$. For example Increases the value stored in \meta{integer} by $1$. For example \begin{demohigh} -\IntSet\lTmpaInt{5} -\IntIncr\lTmpaInt -\IntUse\lTmpaInt +\IntSet \lTmpaInt {5} +\IntIncr \lTmpaInt +\IntUse \lTmpaInt \end{demohigh} \end{function} @@ -910,9 +2574,9 @@ For example Decreases the value stored in \meta{integer} by $1$. For example \begin{demohigh} -\IntSet\lTmpaInt{5} -\IntDecr\lTmpaInt -\IntUse\lTmpaInt +\IntSet \lTmpaInt {5} +\IntDecr \lTmpaInt +\IntUse \lTmpaInt \end{demohigh} \end{function} @@ -923,9 +2587,9 @@ For example Adds the result of the \meta{integer expression} to the current content of the \meta{integer}. For example \begin{demohigh} -\IntSet\lTmpaInt{5} -\IntAdd\lTmpaInt{2} -\IntUse\lTmpaInt +\IntSet \lTmpaInt {5} +\IntAdd \lTmpaInt {2} +\IntUse \lTmpaInt \end{demohigh} \end{function} @@ -936,32 +2600,119 @@ content of the \meta{integer}. For example Subtracts the result of the \meta{integer expression} from the current content of the \meta{integer}. For example \begin{demohigh} -\IntSet\lTmpaInt{5} -\IntSub\lTmpaInt{3} -\IntUse\lTmpaInt +\IntSet \lTmpaInt {5} +\IntSub \lTmpaInt {3} +\IntUse \lTmpaInt \end{demohigh} \end{function} +\section{Integer Step Functions} + +%\begin{function}{\IntStepFunction} +%\begin{syntax} +%\cs{IntStepFunction} \Arg{initial value} \Arg{step} \Arg{final value} \meta{function} +%\end{syntax} +%This function first evaluates the \meta{initial value}, \meta{step} +%and \meta{final value}, all of which should be integer expressions. +%The \meta{function} is then placed in front of each \meta{value} +%from the \meta{initial value} to the \meta{final value} in turn +%(using \meta{step} between each \meta{value}). The \meta{step} must +%be non-zero. If the \meta{step} is positive, the loop stops when +%the \meta{value} becomes larger than the \meta{final value}. If the +%\meta{step} is negative, the loop stops when the \meta{value} +%becomes smaller than the \meta{final value}. The \meta{function} +%should absorb one numerical argument. For example +%\begin{verbatim} +%\cs_set:Npn \my_func:n #1 { [I~saw~#1] \quad } +%\int_step_function:nnnN { 1 } { 1 } { 5 } \my_func:n +%\end{verbatim} +%would print +%\begin{quote} +%[I saw 1] \quad +%[I saw 2] \quad +%[I saw 3] \quad +%[I saw 4] \quad +%[I saw 5] \quad +%\end{quote} +%\end{function} + +\begin{function}{\IntStepInline} +\begin{syntax} +\cs{IntStepInline} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code} +\end{syntax} +This function first evaluates the \meta{initial value}, \meta{step} +and \meta{final value}, all of which should be integer expressions. +Then for each \meta{value} from the \meta{initial value} to the +\meta{final value} in turn (using \meta{step} between each +\meta{value}), the \meta{code} is inserted into the input stream +with \verb|#1| replaced by the current \meta{value}. Thus the +\meta{code} should define a function of one argument~(\verb|#1|). +For example +\begin{codehigh} +\IgnoreSpacesOn +\TlClear \lTmpaTl +\IntStepInline {1} {3} {30} { + \TlPutRight \lTmpaTl {[#1]} +} +\Result {\Value\lTmpaTl} +\IgnoreSpacesOff +\end{codehigh} +produces [1][4][7][10][13][16][19][22][25][28]. +\end{function} + \begin{function}{\IntStepVariable} \begin{syntax} -\cs{IntStepVariable} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl~var} \Arg{code} +\cs{IntStepVariable} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl var} \Arg{code} \end{syntax} This function first evaluates the \meta{initial value}, \meta{step} and \meta{final value}, all of which should be integer expressions. Then for each \meta{value} from the \meta{initial value} to the \meta{final value} in turn (using \meta{step} between each \meta{value}), the \meta{code} is evaluated, -with the \meta{tl~var} defined as the current \meta{value}. Thus +with the \meta{tl~var} defined as the current \meta{value}. Thus the \meta{code} should make use of the \meta{tl~var}. -For example -\begin{demohigh} -\TlClear\lTmpaTl -\IntStepVariable{1}{3}{30}\lTmpiTl{ - \TlPutRight\lTmpaTl{\Value\lTmpiTl} - \TlPutRight\lTmpaTl{ } -} -\Result{\Value\lTmpaTl} -\end{demohigh} +%For example +%\begin{demohigh} +%\IgnoreSpacesOn +%\TlClear\lTmpaTl +%\IntStepVariable{1}{3}{30}\lTmpiTl{ +% \TlPutRight\lTmpaTl{\Value\lTmpiTl} +% \TlPutRight\lTmpaTl{~} +%} +%\Result{\Value\lTmpaTl} +%\IgnoreSpacesOff +%\end{demohigh} +\end{function} + +\section{Integer Conditionals} + +\begin{function}{\IntIfExist, \IntIfExistTF} +\begin{syntax} +\cs{IntIfExist} \meta{integer} +\cs{IntIfExistTF} \meta{integer} \Arg{true code} \Arg{false code} +\end{syntax} +Tests whether the \meta{integer} is currently defined. This does not +check that the \meta{integer} really is an integer variable. +\end{function} + +\begin{function}{\IntIfOdd,\IntIfOddTF} +\begin{syntax} +\cs{IntIfOdd} \Arg{integer expression} +\cs{IntIfOddTF} \Arg{integer expression} \Arg{true code} \Arg{false code} +\end{syntax} +This function first evaluates the \meta{integer expression} +as described for \cs{IntEval}. +It then evaluates if this is odd or even, as appropriate. +\end{function} + +\begin{function}{\IntIfEven,\IntIfEvenTF} +\begin{syntax} +\cs{IntIfEven} \Arg{integer expression} +\cs{IntIfEvenTF} \Arg{integer expression} \Arg{true code} \Arg{false code} +\end{syntax} +This function first evaluates the \meta{integer expression} +as described for \cs{IntEval}. +It then evaluates if this is even or odd, as appropriate. \end{function} \begin{function}{\IntCompare,\IntCompareTF} @@ -979,11 +2730,1632 @@ Less than & \texttt{<} \\ \end{tabular}\par} For example \begin{demohigh} -\IntCompareTF{2}>{1}{\Result{Greater}}{\Result{Less}} -\IntCompareTF{2}>{3}{\Result{Greater}}{\Result{Less}} +\IntCompareTF {2} > {1} {\Result{Greater}} {\Result{Less}} +\IntCompareTF {2} > {3} {\Result{Greater}} {\Result{Less}} +\end{demohigh} +\end{function} + +\section{Integer Case Functions} + +\begin{function}{\IntCase} +\begin{syntax} +\cs{IntCase} \Arg{test integer expression} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{intexpr case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{intexpr case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \Arg{intexpr case_n} \Arg{code case_n} +~ ~ \verb|}| +\end{syntax} +This function evaluates the \meta{test integer expression} and +compares this in turn to each of the +\meta{integer expression cases}. If the two are equal then the +associated \meta{code} is left in the input stream +and other cases are discarded. +\end{function} + +\begin{function}{\IntCaseT} +\begin{syntax} +\cs{IntCaseT} \Arg{test integer expression} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{intexpr case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{intexpr case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \Arg{intexpr case_n} \Arg{code case_n} +~ ~ \verb|}| +~ ~ \Arg{true code} +\end{syntax} +This function evaluates the \meta{test integer expression} and +compares this in turn to each of the +\meta{integer expression cases}. If the two are equal then the +associated \meta{code} is left in the input stream +and other cases are discarded. If any of the +cases are matched, the \meta{true code} is also inserted into the +input stream (after the code for the appropriate case). +\end{function} + +\begin{function}{\IntCaseF} +\begin{syntax} +\cs{IntCaseF} \Arg{test integer expression} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{intexpr case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{intexpr case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \Arg{intexpr case_n} \Arg{code case_n} +~ ~ \verb|}| +~ ~ \Arg{false code} +\end{syntax} +This function evaluates the \meta{test integer expression} and +compares this in turn to each of the +\meta{integer expression cases}. If the two are equal then the +associated \meta{code} is left in the input stream +and other cases are discarded. If none +match then the \meta{false code} is into the input stream +(after the code for the appropriate case). +For example +\begin{demohigh} +\IgnoreSpacesOn +\IntCaseF { 2 * 5 } + { + { 5 } { Small } + { 4 + 6 } { Medium } + { -2 * 10 } { Negative } + } + { No idea! } +\IgnoreSpacesOff +\end{demohigh} +\end{function} + +\begin{function}{\IntCaseTF} +\begin{syntax} +\cs{IntCaseTF} \Arg{test integer expression} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{intexpr case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{intexpr case_2} \Arg{code case_2} +~ ~ ~ ~ $\cdots$ +~ ~ ~ ~ \Arg{intexpr case_n} \Arg{code case_n} +~ ~ \verb|}| +~ ~ \Arg{true code} +~ ~ \Arg{false code} +\end{syntax} +This function evaluates the \meta{test integer expression} and +compares this in turn to each of the +\meta{integer expression cases}. If the two are equal then the +associated \meta{code} is left in the input stream +and other cases are discarded. If any of the +cases are matched, the \meta{true code} is also inserted into the +input stream (after the code for the appropriate case), while if none +match then the \meta{false code} is inserted. +\end{function} + +\chapter{Floating Point Numbers (\texttt{Fp})} + +\section{Constant and Scratch Floating Points} + +\begin{variable}{\cZeroFp, \cMinusZeroFp} +Zero, with either sign. +\end{variable} + +\begin{variable}{\cOneFp} +One as an \texttt{fp}: useful for comparisons in some places. +\end{variable} + +\begin{variable}{\cInfFp,\cMinusInfFp} +Infinity, with either sign. These can be input directly in a +floating point expression as \texttt{inf} and \texttt{-inf}. +\end{variable} + +\begin{variable}{\cEFp} +The value of the base of the natural logarithm, $\mathrm{e} = \exp(1)$. +\end{variable} + +\begin{variable}{\cPiFp} +The value of $\pi$. This can be input directly in a floating point +expression as \texttt{pi}. +\end{variable} + +\begin{variable}{\cOneDegreeFp} +The value of $1^{\circ}$ in radians. Multiply an angle given in +degrees by this value to obtain a result in radians. Note that +trigonometric functions expecting an argument in radians or in +degrees are both available. Within floating point expressions, this +can be accessed as \texttt{deg}. +\end{variable} + +\begin{variable}{\lTmpaFp,\lTmpbFp,\lTmpcFp,\lTmpiFp,\lTmpjFp,\lTmpkFp} +Scratch floating point numbers for local assignment. These are never used by +the \verb!functional! package, and so are safe for use with any +function. However, they may be overwritten by other +code and so should only be used for short-term storage. +\end{variable} + +\begin{variable}{\gTmpaFp,\gTmpbFp,\gTmpcFp,\gTmpiFp,\gTmpjFp,\gTmpkFp} +Scratch floating point numbers for global assignment. These are never used by +the \verb!functional! package, and so are safe for use with any +function. However, they may be overwritten by other +code and so should only be used for short-term storage. +\end{variable} + +\section{Floating Point Expressions} + +\begin{function}{\FpEval} +\begin{syntax} +\cs{FpEval} \Arg{floating point expression} +\end{syntax} +Evaluates the \meta{floating point expression} and returns the +result as a decimal number with no +exponent. Leading or trailing zeros may be inserted to compensate +for the exponent. Non-significant trailing zeros are trimmed, and +integers are expressed without a decimal separator. The values +$\pm\infty$ and \nan{} trigger an \enquote{invalid operation} +exception. +For a tuple, each item is converted using \cs{FpEval} and they are combined as +\verb|(|\meta{fp_1}\verb*|, |\meta{fp_2}\verb*|, |\ldots{}\meta{fp_n}\verb|)| +if $n>1$ and \verb|(|\meta{fp_1}\verb|,)| or \verb|()| for fewer items. +%This function is identical to \cs{fp_to_decimal:n}. +For example +\begin{demohigh} +\FpEval {(1.2+3.4)*(5.6-7.8)/9} +\end{demohigh} +\end{function} + +\begin{function}{\FpMathAdd} +\begin{syntax} +\cs{FpMathAdd} \Arg{fpexpr_1} \Arg{fpexpr_2} +\end{syntax} +Adds \Arg{fpexpr_1} and \Arg{fpexpr_2}, +and returns the result. For example +\begin{demohigh} +\FpMathAdd {2.8} {3.7} +\FpMathAdd {3.8-1} {2.7+1} +\end{demohigh} +\end{function} + +\begin{function}{\FpMathSub} +\begin{syntax} +\cs{FpMathSub} \Arg{fpexpr_1} \Arg{fpexpr_2} +\end{syntax} +Subtracts \Arg{fpexpr_2} from \Arg{fpexpr_1}, +and returns the result. For example +\begin{demohigh} +\FpMathSub {2.8} {3.7} +\FpMathSub {3.8-1} {2.7+1} +\end{demohigh} +\end{function} + +\begin{function}{\FpMathMult} +\begin{syntax} +\cs{FpMathMult} \Arg{fpexpr_1} \Arg{fpexpr_2} +\end{syntax} +Multiplies \Arg{fpexpr_1} by \Arg{fpexpr_2}, +and returns the result. For example +\begin{demohigh} +\FpMathMult {2.8} {3.7} +\FpMathMult {3.8-1} {2.7+1} +\end{demohigh} +\end{function} + +\begin{function}{\FpMathDiv} +\begin{syntax} +\cs{FpMathDiv} \Arg{fpexpr_1} \Arg{fpexpr_2} +\end{syntax} +Divides \Arg{fpexpr_1} by \Arg{fpexpr_2}, +and returns the result. For example +\begin{demohigh} +\FpMathDiv {2.8} {3.7} +\FpMathDiv {3.8-1} {2.7+1} +\end{demohigh} +\end{function} + +\begin{function}{\FpMathSign} +\begin{syntax} +\cs{FpMathSign} \Arg{fpexpr} +\end{syntax} +Evaluates the \meta{fpexpr} and returns the value +using \cs{FpEval}\verb|{sign(|\meta{result}\verb|)}|: $+1$ for positive +numbers and for $+\infty$, $-1$ for negative numbers and for +$-\infty$, $\pm 0$ for $\pm 0$. If the operand is a tuple or is +\nan{}, then \enquote{invalid operation} occurs and the result +is $0$. For example +\begin{demohigh} +\FpMathSign {3.5} +\FpMathSign {-2.7} \end{demohigh} \end{function} +\begin{function}{\FpMathAbs} +\begin{syntax} +\cs{FpMathAbs} \Arg{floating point expression} +\end{syntax} +Evaluates the \meta{floating point expression} as described for +\cs{FpEval} and returns the absolute value. +If the argument is $\pm\infty$, \nan{} or a tuple, +\enquote{invalid operation} occurs. Within floating point +expressions, \verb|abs()| can be used; it accepts $\pm\infty$ and \nan{} +as arguments. +\end{function} + +\begin{function}{\FpMathMax,\FpMathMin} +\begin{syntax} +\cs{FpMathMax} \Arg{fp expression_1} \Arg{fp expression_2} +\cs{FpMathMin} \Arg{fp expression_1} \Arg{fp expression_2} +\end{syntax} +Evaluates the \meta{floating point expressions} as described for \cs{FpEval} +and returns the resulting larger (\texttt{max}) or smaller (\texttt{min}) value. +If the argument is a tuple, \enquote{invalid operation} occurs, +but no other case raises exceptions. Within floating point expressions, +\verb|max()| and \verb|min()| can be used. +\end{function} + +\section{Creating and Using Floating Points} + +\begin{function}{\FpNew} +\begin{syntax} +\cs{FpNew} \meta{fp var} +\end{syntax} +Creates a new \meta{fp var} or raises an error if the name is +already taken. The declaration is global. The \meta{fp~var} is +initially $+0$. +\end{function} + +\begin{function}{\FpConst} +\begin{syntax} +\cs{FpConst} \meta{fp var} \Arg{floating point expression} +\end{syntax} +Creates a new constant \meta{fp var} or raises an error if the name +is already taken. The \meta{fp var} is set globally equal to +the result of evaluating the \meta{floating point expression}. +For example +\begin{demohigh} +\FpConst \cMyPiFp {3.1415926} +\FpUse \cMyPiFp +\end{demohigh} +\end{function} + +\begin{function}{\FpUse} +\begin{syntax} +\cs{FpUse} \meta{fp var} +\end{syntax} +Recovers the value of the \meta{fp var} and returns the value as a +decimal number with no exponent. +%Leading or trailing zeros may be inserted to compensate for the +%exponent. Non-significant trailing zeros are trimmed. Integers are +%expressed without a decimal separator. The values $\pm\infty$ +%and \nan{} trigger an \enquote{invalid operation} exception. +%For a tuple, each item is converted using \cs{fp_to_decimal:n} and they are combined as +%|(|\meta{fp_1}\verb*|, |\meta{fp_2}\verb*|, |\ldots{}\meta{fp_n}|)| +%if $n>1$ and |(|\meta{fp_1}|,)| or |()| for fewer items. +%This function is identical to \cs{fp_to_decimal:N}. +\end{function} + +\section{Viewing Floating Points} + +\begin{function}{\FpLog} +\begin{syntax} +\cs{FpLog} \Arg{floating point expression} +\end{syntax} +Evaluates the \meta{floating point expression} and writes the +result in the log file. +\end{function} + +\begin{function}{\FpVarLog} +\begin{syntax} +\cs{FpVarLog} \meta{fp var} +\end{syntax} +Writes the value of \meta{fp var} in the log file. +\end{function} + +\begin{function}{\FpShow} +\begin{syntax} +\cs{FpShow} \Arg{floating point expression} +\end{syntax} +Evaluates the \meta{floating point expression} and displays the +result in the terminal. +\end{function} + +\begin{function}{\FpVarShow} +\begin{syntax} +\cs{FpVarShow} \meta{fp var} +\end{syntax} +Displays the value of \meta{fp var} in the terminal. +\end{function} + +\section{Setting Floating Point Variables} + +\begin{function}{\FpSet} +\begin{syntax} +\cs{FpSet} \meta{fp var} \Arg{floating point expression} +\end{syntax} +Sets \meta{fp var} equal to the result of computing the +\meta{floating point expression}. For example +\begin{demohigh} +\FpSet \lTmpaFp {4/7} +\FpUse \lTmpaFp +\end{demohigh} +\end{function} + +\begin{function}{\FpSetEq} +\begin{syntax} +\cs{FpSetEq} \meta{fp var_1} \meta{fp var_2} +\end{syntax} +Sets the floating point variable \meta{fp var_1} equal to the current +value of \meta{fp var_2}. +\end{function} + +\begin{function}{\FpZero} +\begin{syntax} +\cs{FpZero} \meta{fp var} +\end{syntax} +Sets the \meta{fp var} to $+0$. For example +\begin{demohigh} +\FpSet \lTmpaFp {5.3} +\FpZero \lTmpaFp +\FpUse \lTmpaFp +\end{demohigh} +\end{function} + +\begin{function}{\FpZeroNew} +\begin{syntax} +\cs{FpZeroNew} \meta{fp var} +\end{syntax} +Ensures that the \meta{fp var} exists globally +by applying \cs{FpNew} if necessary, then applies +\cs{FpZero} to leave the \meta{fp var} set to $+0$. +\end{function} + +\begin{function}{\FpAdd} +\begin{syntax} +\cs{FpAdd} \meta{fp var} \Arg{floating point expression} +\end{syntax} +Adds the result of computing the \meta{floating point expression} to +the \meta{fp var}. +This also applies if \meta{fp var} and \meta{floating point +expression} evaluate to tuples of the same size. For example +\begin{demohigh} +\FpSet \lTmpaFp {5.3} +\FpAdd \lTmpaFp {2.11} +\FpUse \lTmpaFp +\end{demohigh} +\end{function} + +\begin{function}{\FpSub} +\begin{syntax} +\cs{FpSub} \meta{fp var} \Arg{floating point expression} +\end{syntax} +Subtracts the result of computing the \meta{floating point +expression} from the \meta{fp var}. +This also applies if \meta{fp var} and \meta{floating point +expression} evaluate to tuples of the same size. For example +\begin{demohigh} +\FpSet \lTmpaFp {5.3} +\FpSub \lTmpaFp {2.11} +\FpUse \lTmpaFp +\end{demohigh} +\end{function} + +\section{Floating Point Step Functions} + +%\begin{function}{\FpStepFunction} +%\begin{syntax} +%\cs{FpStepFunction} \Arg{initial value} \Arg{step} \Arg{final value} \meta{function} +%\end{syntax} +%This function first evaluates the \meta{initial value}, \meta{step} +%and \meta{final value}, each of which should be a floating point +%expression evaluating to a floating point number, not a tuple. +%The \meta{function} is then placed in front of each \meta{value} +%from the \meta{initial value} to the \meta{final value} in turn +%(using \meta{step} between each \meta{value}). The \meta{step} must +%be non-zero. If the \meta{step} is positive, the loop stops when +%the \meta{value} becomes larger than the \meta{final value}. If the +%\meta{step} is negative, the loop stops when the \meta{value} +%becomes smaller than the \meta{final value}. The \meta{function} +%should absorb one numerical argument. For example +%\begin{verbatim} +%\cs_set:Npn \my_func:n #1 { [I saw #1] \quad } +%\fp_step_function:nnnN { 1.0 } { 0.1 } { 1.5 } \my_func:n +%\end{verbatim} +%would print +%\begin{quote} +%[I saw 1.0] \quad +%[I saw 1.1] \quad +%[I saw 1.2] \quad +%[I saw 1.3] \quad +%[I saw 1.4] \quad +%[I saw 1.5] \quad +%\end{quote} +%\begin{texnote} +%Due to rounding, it may happen that adding the \meta{step} to the +%\meta{value} does not change the \meta{value}; such cases give an +%error, as they would otherwise lead to an infinite loop. +%\end{texnote} +%\end{function} + +\begin{function}{\FpStepInline} +\begin{syntax} +\cs{FpStepInline} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code} +\end{syntax} +This function first evaluates the \meta{initial value}, \meta{step} +and \meta{final value}, all of which should be floating point +expressions evaluating to a floating point number, not a tuple. +Then for each \meta{value} from the \meta{initial value} to the +\meta{final value} in turn (using \meta{step} between each +\meta{value}), the \meta{code} is inserted into the input stream +with \verb|#1| replaced by the current \meta{value}. Thus the +\meta{code} should define a function of one argument (\verb|#1|). +For example +\begin{codehigh} +\IgnoreSpacesOn +\TlClear \lTmpaTl +\FpStepInline {1} {0.1} {1.5} { + \TlPutRight \lTmpaTl {[#1]} +} +\Result {\Value\lTmpaTl} +\IgnoreSpacesOff +\end{codehigh} +produces [1][1.1][1.2][1.3][1.4][1.5]. +\end{function} + +\begin{function}{\FpStepVariable} +\begin{syntax} +\cs{FpStepVariable} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl var} \Arg{code} +\end{syntax} +This function first evaluates the \meta{initial value}, \meta{step} +and \meta{final value}, all of which should be floating point +expressions evaluating to a floating point number, not a tuple. +Then for each \meta{value} from the \meta{initial value} to the +\meta{final value} in turn (using \meta{step} between each +\meta{value}), the \meta{code} is inserted into the input stream, +with the \meta{tl var} defined as the current \meta{value}. Thus +the \meta{code} should make use of the \meta{tl var}. +%For example +%\begin{demohigh} +%\IgnoreSpacesOn +%\TlClear\lTmpaTl +%\FpStepVariable{1}{0.1}{1.5}\lTmpiTl{ +% \TlPutRight\lTmpaTl{\Value\lTmpiTl} +% \TlPutRight\lTmpaTl{~} +%} +%\Result{\Value\lTmpaTl} +%\IgnoreSpacesOff +%\end{demohigh} +\end{function} + +\section{Float Point Conditionals} + +\begin{function}{\FpIfExist,\FpIfExistTF} +\begin{syntax} +\cs{FpIfExist} \meta{fp var} +\cs{FpIfExistTF} \meta{fp var} \Arg{true code} \Arg{false code} +\end{syntax} +Tests whether the \meta{fp var} is currently defined. This does not +check that the \meta{fp var} really is a floating point variable. +For example +\begin{demohigh} +\FpIfExistTF \lTmpaFp {\Result{Yes}} {\Result{No}} +\FpIfExistTF \lMyUndefinedFp {\Result{Yes}} {\Result{No}} +\end{demohigh} +\end{function} + +\begin{function}{\FpCompare,\FpCompareTF} +\begin{syntax} +\cs{FpCompare} \Arg{fpexpr_1} \meta{relation} \Arg{fpexpr_2} +\cs{FpCompareTF} \Arg{fpexpr_1} \meta{relation} \Arg{fpexpr_2} \Arg{true code} \Arg{false code} +\end{syntax} +Compares the \meta{fpexpr_1} and the \meta{fpexpr_2}, and returns +\texttt{true} if the \meta{relation} is obeyed. For example +\begin{demohigh} +\FpCompareTF {1} > {0.9999} {\Result{Greater}} {\Result{Less}} +\FpCompareTF {1} > {1.0001} {\Result{Greater}} {\Result{Less}} +\end{demohigh} +Two floating points +$x$ and $y$ may obey four mutually exclusive relations: +$x<y$, $x=y$, $x>y$, or $x?y$ (\enquote{not ordered}). The last +case occurs exactly if one or both operands is \nan{} or is a tuple, +unless they are equal tuples. Note that a \nan{} is distinct from +any value, even another \nan{}, hence $x=x$ is not true for +a \nan{}. To test if a value is \nan{}, compare it to an arbitrary +number with the \enquote{not ordered} relation.\par +%\begin{demohigh} +%\FpCompareTF{0/0}?{0}{\Result{Is~a~Nan}}{\Result{Isn't~a~NaN}} +%\end{demohigh} +Tuples are equal if they have the same number of items and items +compare equal (in particular there must be no \nan{}). +At present any other comparison with tuples yields \verb|?| (not ordered). +This is experimental. +\end{function} + +\chapter{Dimensions (\texttt{Dim})} + +\section{Constant and Scratch Dimensions} + +\begin{variable}{\cMaxDim} +The maximum value that can be stored as a dimension. This can also +be used as a component of a skip. +\end{variable} + +\begin{variable}{\cZeroDim} +A zero length as a dimension. This can also be used as a component +of a skip. +\end{variable} + +\begin{variable}{\lTmpaDim,\lTmpbDim,\lTmpcDim,\lTmpiDim,\lTmpjDim,\lTmpkDim} +Scratch dimensions for local assignment. These are never used by +the \verb!functional! package, and so are safe for use with any +function. However, they may be overwritten by other +code and so should only be used for short-term storage. +\end{variable} + +\begin{variable}{\gTmpaDim,\gTmpbDim,\gTmpcDim,\gTmpiDim,\gTmpjDim,\gTmpkDim} +Scratch dimensions for global assignment. These are never used by +the \verb!functional! package, and so are safe for use with any +function. However, they may be overwritten by other +code and so should only be used for short-term storage. +\end{variable} + +\section{Dimension Expressions} + +\begin{function}{\DimEval} +\begin{syntax} +\cs{DimEval} \Arg{dimension expression} +\end{syntax} +Evaluates the \meta{dimension expression}, expanding any +dimensions and token list variables within the \meta{expression} +to their content (without requiring \cs{DimUse}/\cs{TlUse}) +and applying the standard mathematical rules. The result of the +calculation is returned as a \meta{dimension denotation}. +%This is expressed in points (\texttt{pt}), and requires suitable +%termination if used in a \TeX{}-style assignment as it is \emph{not} +%an \meta{internal dimension}. +For example +\begin{demohigh} +\DimEval {(1.2pt+3.4pt)/9} +\end{demohigh} +%\DimEval{(1.2pt+3.4pt)*(5.6-7.8)/9} +\end{function} + +\begin{function}{\DimMathAdd} +\begin{syntax} +\cs{DimMathAdd} \Arg{dimexpr_1} \Arg{dimexpr_2} +\end{syntax} +Adds \Arg{dimexpr_1} and \Arg{dimexpr_2}, +and returns the result. For example +\begin{demohigh} +\DimMathAdd {2.8pt} {3.7pt} +\DimMathAdd {3.8pt-1pt} {2.7pt+1pt} +\end{demohigh} +\end{function} + +\begin{function}{\DimMathSub} +\begin{syntax} +\cs{DimMathSub} \Arg{dimexpr_1} \Arg{dimexpr_2} +\end{syntax} +Subtracts \Arg{dimexpr_2} from \Arg{dimexpr_1}, +and returns the result. For example +\begin{demohigh} +\DimMathSub {2.8pt} {3.7pt} +\DimMathSub {3.8pt-1pt} {2.7pt+1pt} +\end{demohigh} +\end{function} + +\begin{function}{\DimMathRatio} +\begin{syntax} +\cs{DimMathRatio} \Arg{dimexpr_1} \Arg{dimexpr_2} +\end{syntax} +Parses the two \meta{dimension expressions}, +then calculates the ratio of the two and returns it. +The result is a ratio expression +between two integers, with all distances converted to scaled points. +For example +\begin{demohigh} +\DimMathRatio {5pt} {10pt} +\end{demohigh} +The returned value is suitable for use inside a \meta{dimension expression} +such as +\begin{codehigh} +\DimSet \lTmpaDim {10pt*\DimMathRatio{5pt}{10pt}} +\end{codehigh} +\end{function} + +\begin{function}{\DimMathSign} +\begin{syntax} +\cs{DimMathSign} \Arg{dimexpr} +\end{syntax} +Evaluates the \meta{dimexpr} then returns $1$ or $0$ or $-1$ +according to the sign of the result. For example +\begin{demohigh} +\DimMathSign {3.5pt} +\DimMathSign {-2.7pt} +\end{demohigh} +\end{function} + +\begin{function}{\DimMathAbs} +\begin{syntax} +\cs{DimMathAbs} \Arg{dimexpr} +\end{syntax} +Converts the \meta{dimexpr} to its absolute value, +returning the result as a \meta{dimension denotation}. +For example +\begin{demohigh} +\DimMathAbs {3.5pt} +\DimMathAbs {-2.7pt} +\end{demohigh} +\end{function} + +\begin{function}{\DimMathMax,\DimMathMin} +\begin{syntax} +\cs{DimMathMax} \Arg{dimexpr_1} \Arg{dimexpr_2} +\cs{DimMathMin} \Arg{dimexpr_1} \Arg{dimexpr_2} +\end{syntax} +Evaluates the two \meta{dimension expressions} and returns either the +maximum or minimum value as appropriate as a \meta{dimension denotation}. +For example +\begin{demohigh} +\DimMathMax {3.5pt} {-2.7pt} +\DimMathMin {3.5pt} {-2.7pt} +\end{demohigh} +\end{function} + +\section{Creating and Using Dimensions} + +\begin{function}{\DimNew} +\begin{syntax} +\cs{DimNew} \meta{dimension} +\end{syntax} +Creates a new \meta{dimension} or raises an error if the name is +already taken. The declaration is global. The \meta{dimension} +is initially equal to $0$\,pt. +\end{function} + +\begin{function}{\DimConst} +\begin{syntax} +\cs{DimConst} \meta{dimension} \Arg{dimension expression} +\end{syntax} +Creates a new constant \meta{dimension} or raises an error if the +name is already taken. The value of the \meta{dimension} is set +globally to the \meta{dimension expression}. For example +\begin{demohigh} +\DimConst \cFooSomeDim {1cm} +\DimUse \cFooSomeDim +\end{demohigh} +\end{function} + +\begin{function}{\DimUse} +\begin{syntax} +\cs{DimUse} \meta{dimension} +\end{syntax} +Recovers the content of a \meta{dimension} and returns the value. +An error is raised if the variable does not exist or if it is invalid. +\end{function} + +\section{Viewing Dimensions} + +\begin{function}{\DimLog} +\begin{syntax} +\cs{DimLog} \Arg{dimension expression} +\end{syntax} +Writes the result of evaluating the \meta{dimension expression} +in the log file. For example +\begin{codehigh} +\DimLog {\lFooSomeDim+1cm} +\end{codehigh} +\end{function} + +\begin{function}{\DimVarLog} +\begin{syntax} +\cs{DimVarLog} \meta{dimension} +\end{syntax} +Writes the value of the \meta{dimension} in the log file. For example +\begin{codehigh} +\DimVarLog \lFooSomeDim +\end{codehigh} +\end{function} + +\begin{function}{\DimShow} +\begin{syntax} +\cs{DimShow} \Arg{dimension expression} +\end{syntax} +Displays the result of evaluating the \meta{dimension expression} +on the terminal. For example +\begin{codehigh} +\DimShow {\lFooSomeDim+1cm} +\end{codehigh} +\end{function} + +\begin{function}{\DimVarShow} +\begin{syntax} +\cs{DimVarShow} \meta{dimension} +\end{syntax} +Displays the value of the \meta{dimension} on the terminal. For example +\begin{codehigh} +\DimVarShow \lFooSomeDim +\end{codehigh} +\end{function} + +\section{Setting Dimension Variables} + +\begin{function}{\DimSet} +\begin{syntax} +\cs{DimSet} \meta{dimension} \Arg{dimension expression} +\end{syntax} +Sets \meta{dimension} to the value of \meta{dimension expression}, which +must evaluate to a length with units. +\end{function} + +\begin{function}{\DimSetEq} +\begin{syntax} +\cs{DimSetEq} \meta{dimension_1} \meta{dimension_2} +\end{syntax} +Sets the content of \meta{dimension_1} equal to that of +\meta{dimension_2}. For example +\begin{demohigh} +\DimSet \lTmpaDim {10pt} +\DimSetEq \lTmpbDim \lTmpaDim +\DimUse \lTmpbDim +\end{demohigh} +\end{function} + +\begin{function}{\DimZero} +\begin{syntax} +\cs{DimZero} \meta{dimension} +\end{syntax} +Sets \meta{dimension} to $0$\,pt. For example +\begin{demohigh} +\DimSet \lTmpaDim {1em} +\DimZero \lTmpaDim +\DimUse \lTmpaDim +\end{demohigh} +\end{function} + +\begin{function}{\DimZeroNew} +\begin{syntax} +\cs{DimZeroNew} \meta{dimension} +\end{syntax} +Ensures that the \meta{dimension} exists globally by applying +\cs{DimNew} if necessary, then applies +\cs{DimZero} to set the \meta{dimension} to zero. For example +\begin{demohigh} +\DimZeroNew \lFooSomeDim +\DimUse \lFooSomeDim +\end{demohigh} +\end{function} + +\begin{function}{\DimAdd} +\begin{syntax} +\cs{DimAdd} \meta{dimension} \Arg{dimension expression} +\end{syntax} +Adds the result of the \meta{dimension expression} to the current +content of the \meta{dimension}. For example +\begin{demohigh} +\DimSet \lTmpaDim {5.3pt} +\DimAdd \lTmpaDim {2.11pt} +\DimUse \lTmpaDim +\end{demohigh} +\end{function} + +\begin{function}{\DimSub} +\begin{syntax} +\cs{DimSub} \meta{dimension} \Arg{dimension expression} +\end{syntax} +Subtracts the result of the \meta{dimension expression} from the +current content of the \meta{dimension}. For example +\begin{demohigh} +\DimSet \lTmpaDim {5.3pt} +\DimSub \lTmpaDim {2.11pt} +\DimUse \lTmpaDim +\end{demohigh} +\end{function} + +\section{Dimension Step Functions} + +%\begin{function}{\DimStepFunction} +%\begin{syntax} +%\cs{DimStepFunction} \Arg{initial value} \Arg{step} \Arg{final value} \meta{function} +%\end{syntax} +%This function first evaluates the \meta{initial value}, \meta{step} +%and \meta{final value}, all of which should be dimension expressions. +%The \meta{function} is then placed in front of each \meta{value} +%from the \meta{initial value} to the \meta{final value} in turn +%(using \meta{step} between each \meta{value}). The \meta{step} must +%be non-zero. If the \meta{step} is positive, the loop stops when +%the \meta{value} becomes larger than the \meta{final value}. If the +%\meta{step} is negative, the loop stops when the \meta{value} +%becomes smaller than the \meta{final value}. The \meta{function} +%should absorb one argument. +%\end{function} + +\begin{function}{\DimStepInline} +\begin{syntax} +\cs{DimStepInline} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code} +\end{syntax} +This function first evaluates the \meta{initial value}, \meta{step} +and \meta{final value}, all of which should be dimension expressions. +Then for each \meta{value} from the \meta{initial value} to the +\meta{final value} in turn (using \meta{step} between each +\meta{value}), the \meta{code} is inserted into the input stream +with \verb|#1| replaced by the current \meta{value}. Thus the +\meta{code} should define a function of one argument (\verb|#1|). +For example +\begin{codehigh} +\IgnoreSpacesOn +\TlClear \lTmpaTl +\DimStepInline {1pt} {0.1pt} {1.5pt} { + \TlPutRight \lTmpaTl {[#1]} +} +\Result {\Value\lTmpaTl} +\IgnoreSpacesOff +\end{codehigh} +produces [1.0pt][1.1pt][1.20001pt][1.30002pt][1.40002pt]. +\end{function} + +\begin{function}{\DimStepVariable} +\begin{syntax} +\cs{DimStepVariable} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl var} \Arg{code} +\end{syntax} +This function first evaluates the \meta{initial value}, \meta{step} +and \meta{final value}, all of which should be dimension expressions. +Then for each \meta{value} from the \meta{initial value} to the +\meta{final value} in turn (using \meta{step} between each +\meta{value}), the \meta{code} is inserted into the input stream, +with the \meta{tl var} defined as the current \meta{value}. Thus +the \meta{code} should make use of the \meta{tl var}. +%For example +%\begin{demohigh} +%\IgnoreSpacesOn +%\TlClear\lTmpaTl +%\DimStepVariable{1pt}{0.1pt}{1.5pt}\lTmpiTl{ +% \TlPutRight\lTmpaTl{\Value\lTmpiTl} +% \TlPutRight\lTmpaTl{~} +%} +%\Result{\Value\lTmpaTl} +%\IgnoreSpacesOff +%\end{demohigh} +\end{function} + +\section{Dimension Conditionals} + +\begin{function}{\DimIfExist,\DimIfExistTF} +\begin{syntax} +\cs{DimIfExist} \meta{dimension} +\cs{DimIfExistTF} \meta{dimension} \Arg{true code} \Arg{false code} +\end{syntax} +Tests whether the \meta{dimension} is currently defined. This does +not check that the \meta{dimension} really is a dimension variable. +For example +\begin{demohigh} +\DimIfExistTF \lTmpaDim {\Result{Yes}} {\Result{No}} +\DimIfExistTF \lFooUndefinedDim {\Result{Yes}} {\Result{No}} +\end{demohigh} +\end{function} + +\begin{function}{\DimCompare,\DimCompareTF} +\begin{syntax} +\cs{DimCompare} \Arg{dimexpr_1} \meta{relation} \Arg{dimexpr_2} +\cs{DimCompareTF} \Arg{dimexpr_1} \meta{relation} \Arg{dimexpr_2} \Arg{true code} \Arg{false code} +\end{syntax} +This function first evaluates each of the \meta{dimension expressions} +as described for \cs{DimEval}. The two results are then +compared using the \meta{relation}:\par +{\centering +\begin{tabular}{ll} +Equal & \verb|=| \\ +Greater than & \verb|>| \\ +Less than & \verb|<| \\ +\end{tabular}\par} +For example +\begin{demohigh} +\DimCompareTF {1pt} > {0.9999pt} {\Result{Greater}} {\Result{Less}} +\DimCompareTF {1pt} > {1.0001pt} {\Result{Greater}} {\Result{Less}} +\end{demohigh} +\end{function} + +\section{Dimension Case Functions} + +\begin{function}{\DimCase} +\begin{syntax} +\cs{DimCase} \Arg{test dimension expression} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{dimexpr case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{dimexpr case_2} \Arg{code case_2} +~ ~ ~ ~ \ldots +~ ~ ~ ~ \Arg{dimexpr case_n} \Arg{code case_n} +~ ~ \verb|}| +\end{syntax} +This function evaluates the \meta{test dimension expression} and +compares this in turn to each of the +\meta{dimension expression cases}. If the two are equal then the +associated \meta{code} is left in the input stream +and other cases are discarded. +\end{function} + +\begin{function}{\DimCaseT} +\begin{syntax} +\cs{DimCaseT} \Arg{test dimension expression} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{dimexpr case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{dimexpr case_2} \Arg{code case_2} +~ ~ ~ ~ \ldots +~ ~ ~ ~ \Arg{dimexpr case_n} \Arg{code case_n} +~ ~ \verb|}| +~ ~ \Arg{true code} +\end{syntax} +This function evaluates the \meta{test dimension expression} and +compares this in turn to each of the +\meta{dimension expression cases}. If the two are equal then the +associated \meta{code} is left in the input stream +and other cases are discarded. If any of the +cases are matched, the \meta{true code} is also inserted into the +input stream (after the code for the appropriate case). +\end{function} + +\begin{function}{\DimCaseF} +\begin{syntax} +\cs{DimCaseF} \Arg{test dimension expression} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{dimexpr case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{dimexpr case_2} \Arg{code case_2} +~ ~ ~ ~ \ldots +~ ~ ~ ~ \Arg{dimexpr case_n} \Arg{code case_n} +~ ~ \verb|}| +~ ~ \Arg{false code} +\end{syntax} +This function evaluates the \meta{test dimension expression} and +compares this in turn to each of the +\meta{dimension expression cases}. If the two are equal then the +associated \meta{code} is left in the input stream +and other cases are discarded. If none of the cases +match then the \meta{false code} is inserted. +For example +\begin{demohigh} +\IgnoreSpacesOn +\DimSet \lTmpaDim {5pt} +\DimCaseF {2\lTmpaDim} { + {5pt} {\Result{Small}} + {4pt+6pt} {\Result{Medium}} + {-10pt} {\Result{Negative}} +}{ + \Result {No Match} +} +\IgnoreSpacesOff +\end{demohigh} +\end{function} + +\begin{function}{\DimCaseTF} +\begin{syntax} +\cs{DimCaseTF} \Arg{test dimension expression} +~ ~ \verb|{| +~ ~ ~ ~ \Arg{dimexpr case_1} \Arg{code case_1} +~ ~ ~ ~ \Arg{dimexpr case_2} \Arg{code case_2} +~ ~ ~ ~ \ldots +~ ~ ~ ~ \Arg{dimexpr case_n} \Arg{code case_n} +~ ~ \verb|}| +~ ~ \Arg{true code} +~ ~ \Arg{false code} +\end{syntax} +This function evaluates the \meta{test dimension expression} and +compares this in turn to each of the +\meta{dimension expression cases}. If the two are equal then the +associated \meta{code} is left in the input stream +and other cases are discarded. If any of the +cases are matched, the \meta{true code} is also inserted into the +input stream (after the code for the appropriate case), while if none +match then the \meta{false code} is inserted. +%For example +%\begin{demohigh} +%\IgnoreSpacesOn +%\DimSet\lTmpaDim{5pt} +%\DimCaseTF{2\lTmpaDim}{ +% {5pt} {\Result{Small}} +% {4pt+6pt} {\Result{Medium}} +% {-10pt} {\Result{Negative}} +%}{ +% \Result{[Some Match]} +%}{ +% \Result{[No Match]} +%} +%\IgnoreSpacesOff +%\end{demohigh} +\end{function} + +\chapter{Comma Separated Lists (\texttt{Clist})} + +\section{Constant and Scratch Comma Lists} + +\begin{variable}{\cEmptyClist} +Constant that is always empty. +\end{variable} + +\begin{variable}{\lTmpaClist,\lTmpbClist,\lTmpcClist,\lTmpiClist,\lTmpjClist,\lTmpkClist} +Scratch comma lists for local assignment. These are never used by +the \verb!functional! package, and so are safe for use with any +function. However, they may be overwritten by other +code and so should only be used for short-term storage. +\end{variable} + +\begin{variable}{\gTmpaClist,\gTmpbClist,\gTmpcClist,\gTmpiClist,\gTmpjClist,\gTmpkClist} +Scratch comma lists for global assignment. These are never used by +the \verb!functional! package, and so are safe for use with any +function. However, they may be overwritten by other +code and so should only be used for short-term storage. +\end{variable} + +\section{Creating and Using Comma Lists} + +\begin{function}{\ClistNew} +\begin{syntax} +\cs{ClistNew} \meta{comma list} +\end{syntax} +Creates a new \meta{comma list} or raises an error if the name is +already taken. The declaration is global. The \meta{comma list} +initially contains no items. +\end{function} + +\begin{function}{\ClistConst} +\begin{syntax} +\cs{ClistConst} \meta{clist var} \Arg{comma list} +\end{syntax} +Creates a new constant \meta{clist var} or raises an error +if the name is already taken. The value of the +\meta{clist var} is set globally to the +\meta{comma list}. +\end{function} + +\begin{function}{\ClistVarJoin} +\begin{syntax} +\cs{ClistVarJoin} \meta{clist var} \Arg{separator} +\end{syntax} +Returns the contents of the \meta{clist var}, +with the \meta{separator} between the items. +%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. +%An error is raised if the variable does not exist or if it is invalid. +For example, +\begin{demohigh} +\ClistSet \lTmpaClist { a , b , , c , {de} , f } +\ClistVarJoin \lTmpaClist { and } +\end{demohigh} +%\begin{texnote} +%The result is returned within the \tn{unexpanded} +%primitive (\cs{exp_not:n}), which means that the \meta{items} +%do not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\begin{function}{\ClistVarJoinExtended} +\begin{syntax} +\cs{ClistVarJoinExtended} \meta{clist var} \Arg{separator between two} \Arg{separator between more than two} \Arg{separator between final two} +\end{syntax} +Returns the contents of the \meta{clist var}, +with the appropriate \meta{separator} between the items. Namely, 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 joined with +the \meta{separator between two} and returns. +%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. +%An error is raised if the variable does not exist or if it is invalid. +For example, +\begin{demohigh} +\ClistSet \lTmpaClist { a , b , , c , {de} , f } +\ClistVarJoinExtended \lTmpaClist { and } {, } {, and } +\end{demohigh} +The first separator argument is not used in this case +because the comma list has more than $2$ items. +%\begin{texnote} +%The result is returned within the \tn{unexpanded} +%primitive (\cs{exp_not:n}), which means that the \meta{items} +%do not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\begin{function}{\ClistJoin,\ClistJoinExtended} +\begin{syntax} +\cs{ClistJoin} \meta{comma list} \Arg{separator} +\cs{ClistJoinExtended} \meta{comma list} \Arg{separator between two} \Arg{separator between more than two} \Arg{separator between final two} +\end{syntax} +Returns the contents of the \meta{comma list}, +with the appropriate \meta{separator} between the items. As for +\cs{ClistSet}, blank items are omitted, spaces are removed from +both sides of each item, then a set of braces is removed if the +resulting space-trimmed item is braced. The \meta{separators} are +then inserted in the same way as for \cs{ClistVarJoin} and +\cs{ClistVarJoinExtended}, respectively. +%\begin{texnote} +%The result is returned within the \tn{unexpanded} +%primitive (\cs{exp_not:n}), which means that the \meta{items} +%do not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\section{Viewing Comma Lists} + +\begin{function}{\ClistLog} +\begin{syntax} +\cs{ClistLog} \Arg{tokens} +\end{syntax} +Writes the entries in the comma list in the log file. See also +\cs{ClistShow} which displays the result in the terminal. +\end{function} + +\begin{function}{\ClistVarLog} +\begin{syntax} +\cs{ClistVarLog} \meta{comma list} +\end{syntax} +Writes the entries in the \meta{comma list} in the log file. See +also \cs{ClistVarShow} which displays the result in the terminal. +\end{function} + +\begin{function}{\ClistShow} +\begin{syntax} +\cs{ClistShow} \Arg{tokens} +\end{syntax} +Displays the entries in the comma list in the terminal. +\end{function} + +\begin{function}{\ClistVarShow} +\begin{syntax} +\cs{ClistVarShow} \meta{comma list} +\end{syntax} +Displays the entries in the \meta{comma list} in the terminal. +\end{function} + +\section{Setting Comma Lists} + +\begin{function}{\ClistSet} +\begin{syntax} +\cs{ClistSet} \meta{comma list} \verb|{|\meta{item_1},\ldots{},\meta{item_n}\verb|}| +\end{syntax} +Sets \meta{comma list} to contain the \meta{items}, +removing any previous content from the variable. +Blank items are omitted, spaces are removed from both sides of each +item, then a set of braces is removed if the resulting space-trimmed +item is braced. +To store some \meta{tokens} as a single \meta{item} even if the +\meta{tokens} contain commas or spaces, add a set of braces: +\cs{ClistSet} \meta{comma list} \verb|{| \Arg{tokens} \verb|}|. +\end{function} + +\begin{function}{\ClistSetEq} +\begin{syntax} +\cs{ClistSetEq} \meta{comma list_1} \meta{comma list_2} +\end{syntax} +Sets the content of \meta{comma list_1} equal to that of +\meta{comma list_2}. To set a token list variable equal to a comma +list variable, use \cs{TlSetEq}. Conversely, setting a comma +list variable to a token list is unadvisable unless one checks +space-trimming and related issues. +\end{function} + +%\begin{function}{\ClistSetFromSeq} +%\begin{syntax} +%\cs{ClistSetFromSeq} \meta{comma list} \meta{sequence} +%\end{syntax} +%Converts the data in the \meta{sequence} into a \meta{comma list}: +%the original \meta{sequence} is unchanged. +%Items which contain either spaces or commas are surrounded by braces. +%\end{function} + +\begin{function}{\ClistClear} +\begin{syntax} +\cs{ClistClear} \meta{comma list} +\end{syntax} +Clears all items from the \meta{comma list}. +\end{function} + +\begin{function}{\ClistClearNew} +\begin{syntax} +\cs{ClistClearNew} \meta{comma list} +\end{syntax} +Ensures that the \meta{comma list} exists globally by applying +\cs{ClistNew} if necessary, then applies \cs{ClistClear} to leave +the list empty. +\end{function} + +\begin{function}{\ClistConcat} +\begin{syntax} +\cs{ClistConcat} \meta{comma list_1} \meta{comma list_2} \meta{comma list_3} +\end{syntax} +Concatenates the content of \meta{comma list_2} and \meta{comma list_3} +together and saves the result in \meta{comma list_1}. The items in +\meta{comma list_2} are placed at the left side of the new comma list. +\end{function} + +\begin{function}{\ClistPutLeft} +\begin{syntax} +\cs{ClistPutLeft} \meta{comma list} \verb|{|\meta{item_1},\ldots{},\meta{item_n}\verb|}| +\end{syntax} +Appends the \meta{items} to the left of the \meta{comma list}. +Blank items are omitted, spaces are removed from both sides of each +item, then a set of braces is removed if the resulting space-trimmed +item is braced. +To append some \meta{tokens} as a single \meta{item} even if the +\meta{tokens} contain commas or spaces, add a set of braces: +\cs{ClistPutLeft} \meta{comma list} \verb|{| \Arg{tokens} \verb|}|. +\end{function} + +\begin{function}{\ClistPutRight} +\begin{syntax} +\cs{ClistPutRight} \meta{comma list} \verb|{|\meta{item_1},\ldots{},\meta{item_n}\verb|}| +\end{syntax} +Appends the \meta{items} to the right of the \meta{comma list}. +Blank items are omitted, spaces are removed from both sides of each +item, then a set of braces is removed if the resulting space-trimmed +item is braced. +To append some \meta{tokens} as a single \meta{item} even if the +\meta{tokens} contain commas or spaces, add a set of braces: +\cs{ClistPutRight} \meta{comma list} \verb|{| \Arg{tokens} \verb|}|. +\end{function} + +\section{Modifying Comma Lists} + +While comma lists are normally used as ordered lists, it may be +necessary to modify the content. The functions here may be used +to update comma lists, while retaining the order of the unaffected +entries. + +\begin{function}{\ClistRemoveDuplicates} +\begin{syntax} +\cs{ClistRemoveDuplicates} \meta{comma list} +\end{syntax} +Removes duplicate items from the \meta{comma list}, leaving the +left most copy of each item in the \meta{comma list}. The \meta{item} +comparison takes place on a token basis, as for \cs{TlIfEqTF}. +\begin{texnote} +This function iterates through every item in the \meta{comma list} and +does a comparison with the \meta{items} already checked. It is therefore +relatively slow with large comma lists. +Furthermore, it may fail if any of the items in the +\meta{comma list} contains \verb|{|, \verb|}|, or \verb|#| +(assuming the usual \TeX{} category codes apply). +\end{texnote} +\end{function} + +\begin{function}{\ClistRemoveAll} +\begin{syntax} +\cs{ClistRemoveAll} \meta{comma list} \Arg{item} +\end{syntax} +Removes every occurrence of \meta{item} from the \meta{comma list}. +The \meta{item} comparison takes place on a token basis, as for +\cs{TlIfEqTF}. +\begin{texnote} +The function may fail if the \meta{item} contains \verb|{|, \verb|}|, or \verb|#| +(assuming the usual \TeX{} category codes apply). +\end{texnote} +\end{function} + +\begin{function}{\ClistReverse} +\begin{syntax} +\cs{ClistReverse} \meta{comma list} +\end{syntax} +Reverses the order of items stored in the \meta{comma list}. +\end{function} + +%\begin{function}{\ClistSort} +%\begin{syntax} +%\cs{ClistSort} \meta{clist var} \Arg{comparison code} +%\end{syntax} +%Sorts the items in the \meta{clist var} according to the +%\meta{comparison code}, and assigns the result to +%\meta{clist var}. The details of sorting comparison are +%described in Section \ref{sec:l3sort:mech}. +%\end{function} + +\section{Working with the Contents of Comma Lists} + +\begin{function}{\ClistCount,\ClistVarCount} +\begin{syntax} +\cs{ClistCount} \Arg{comma list} +\cs{ClistVarCount} \meta{comma list} +\end{syntax} +Returns the number of items in the \meta{comma list} +as an \meta{integer denotation}. The total number of items +in a \meta{comma list} includes those which are duplicates, +\emph{i.e.} every item in a \meta{comma list} is counted. +\end{function} + +\begin{function}{\ClistItem} +\begin{syntax} +\cs{ClistItem} \Arg{comma list} \Arg{integer expression} +\end{syntax} +Indexing items in the \meta{comma list} from $1$ at the top (left), this +function evaluates the \meta{integer expression} and returns the +appropriate item from the comma list. If the +\meta{integer expression} is negative, indexing occurs from the +bottom (right) of the comma list. When the \meta{integer expression} +is larger than the number of items in the \meta{comma list} (as +calculated by \cs{ClistCount}) then the function returns nothing. +%\begin{texnote} +%The result is returned within the \tn{unexpanded} +%primitive (\cs{exp_not:n}), which means that the \meta{item} +%does not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\begin{function}{\ClistVarItem} +\begin{syntax} +\cs{ClistVarItem} \meta{comma list} \Arg{integer expression} +\end{syntax} +Indexing items in the \meta{comma list} from $1$ at the top (left), this +function evaluates the \meta{integer expression} and returns the +appropriate item from the comma list. If the +\meta{integer expression} is negative, indexing occurs from the +bottom (right) of the comma list. When the \meta{integer expression} +is larger than the number of items in the \meta{comma list} (as +calculated by \cs{ClistVarCount}) then the function returns nothing. +%\begin{texnote} +%The result is returned within the \tn{unexpanded} +%primitive (\cs{exp_not:n}), which means that the \meta{item} +%does not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\begin{function}{\ClistRandItem,\ClistVarRandItem} +\begin{syntax} +\cs{ClistRandItem} \Arg{comma list} +\cs{ClistVarRandItem} \meta{clist var} +\end{syntax} +Selects a pseudo-random item of the \meta{comma list}. +If the \meta{comma list} has no item, the result is empty. +%\begin{texnote} +%The result is returned within the \tn{unexpanded} +%primitive (\cs{exp_not:n}), which means that the \meta{item} +%does not expand further when appearing in an \texttt{x}-type +%or \texttt{e}-type argument expansion. +%\end{texnote} +\end{function} + +\section{Comma Lists as Stacks} + +Comma lists can be used as stacks, where data is pushed to and popped +from the top of the comma list. (The left of a comma list is the top, for +performance reasons.) The stack functions for comma lists are not +intended to be mixed with the general ordered data functions detailed +in the previous section: a comma list should either be used as an +ordered data type or as a stack, but not in both ways. + +\begin{function}{\ClistGet,\ClistGetTF} +\begin{syntax} +\cs{ClistGet} \meta{comma list} \meta{token list variable} +\cs{ClistGetT} \meta{comma list} \meta{token list variable} \meta{true code} +\cs{ClistGetF} \meta{comma list} \meta{token list variable} \meta{false code} +\cs{ClistGetTF} \meta{comma list} \meta{token list variable} \meta{true code} \meta{false code} +\end{syntax} +Stores the left-most item from a \meta{comma list} in the +\meta{token list variable} without removing it from the +\meta{comma list}. The \meta{token list variable} is assigned locally. +%In the non-branching version, if the \meta{comma list} is empty the +%\meta{token list variable} is set to the marker value \cs{qNoValue}. +\end{function} + +\begin{function}{\ClistPop,\ClistPopT,\ClistPopF,\ClistPopTF} +\begin{syntax} +\cs{ClistPop} \meta{comma list} \meta{token list variable} +\cs{ClistPopT} \meta{comma list} \meta{token list variable} \Arg{true code} +\cs{ClistPopF} \meta{comma list} \meta{token list variable} \Arg{false code} +\cs{ClistPopTF} \meta{comma list} \meta{token list variable} \Arg{true code} \Arg{false code} +\end{syntax} +Pops the left-most item from a \meta{comma list} into the +\meta{token list variable}, \emph{i.e.} removes the item from the +comma list and stores it in the \meta{token list variable}. +The assignment of the \meta{token list variable} is local. +If the \meta{comma list} is empty, +the value of the \meta{token list variable} is +not defined in this case and should not be relied upon. +\end{function} + +\begin{function}{\ClistPush} +\begin{syntax} +\cs{ClistPush} \meta{comma list} \Arg{items} +\end{syntax} +Adds the \Arg{items} to the top of the \meta{comma list}. +Spaces are removed from both sides of each item as for any +\texttt{n}-type comma list. +\end{function} + +\section{Mapping over Comma Lists} + +%The functions described in this section apply a specified function +%to each item of a comma list. +%All mappings are done at the current group level, \emph{i.e.} any +%local assignments made by the \meta{function} or \meta{code} discussed +%below remain in effect after the loop. + +When the comma list is given explicitly, %as an \texttt{n}-type argument, +spaces are trimmed around each item. +If the result of trimming spaces is empty, the item is ignored. +Otherwise, if the item is surrounded by braces, one set is removed, +and the result is passed to the mapped function. Thus, if the +comma list that is being mapped is \verb*|{a , {{b} }, ,{}, {c},}| +then the arguments passed to the mapped function are +`\verb*|a|', `\verb*|{b} |', an empty argument, and `\verb*|c|'. + +When the comma list is given as a variable, spaces +have already been trimmed on input, and items are simply stripped +of one set of braces if any. This case is more efficient than using +explicit comma lists. + +%\begin{function}{\ClistMapFunction,\ClistVarMapFunction} +%\begin{syntax} +%\cs{ClistMapFunction} \Arg{comma list} \meta{function} +%\cs{ClistVarMapFunction} \meta{comma list} \meta{function} +%\end{syntax} +%Applies \meta{function} to every \meta{item} stored in the +%\meta{comma list}. The \meta{function} receives one argument for +%each iteration. The \meta{items} are returned from left to right. +%The function \cs{ClistMapInline} is in general more efficient +%than \cs{ClistMapFunction}. +%\end{function} + +\begin{function}{\ClistMapInline,\ClistVarMapInline} +\begin{syntax} +\cs{ClistMapInline} \Arg{comma list} \Arg{inline function} +\cs{ClistVarMapInline} \meta{comma list} \Arg{inline function} +\end{syntax} +Applies \meta{inline function} to every \meta{item} stored +within the \meta{comma list}. The \meta{inline function} should +consist of code which receives the \meta{item} as \verb|#1|. +The \meta{items} are returned from left to right. +For example +\begin{codehigh} +\IgnoreSpacesOn +\TlClear \lTmpaTl +\ClistMapInline {one,two,three} { + \TlPutRight \lTmpaTl {(#1)} +} +\Result {\TlUse\lTmpaTl} +\IgnoreSpacesOff +\end{codehigh} +produces (one)(two)(three). +\end{function} + +\begin{function}{\ClistMapVariable,\ClistVarMapVariable} +\begin{syntax} +\cs{ClistMapVariable} \Arg{comma list} \meta{variable} \Arg{code} +\cs{ClistVarMapVariable} \meta{comma list} \meta{variable} \Arg{code} +\end{syntax} +Stores each \meta{item} of the \meta{comma list} in turn in the +(token list) \meta{variable} and applies the \meta{code}. The +\meta{code} will usually make use of the \meta{variable}, but this +is not enforced. The assignments to the \meta{variable} are local. +Its value after the loop is the last \meta{item} in the \meta{comma +list}, or its original value if there were no \meta{item}. The +\meta{items} are returned from left to right. +\end{function} + +%\begin{function}{\ClistMapTokens,\ClistVarMapTokens} +%\begin{syntax} +%\cs{ClistMapTokens} \Arg{comma list} \Arg{code} +%\cs{ClistVarMapTokens} \meta{clist var} \Arg{code} +%\end{syntax} +%Calls \meta{code} \Arg{item} for every \meta{item} stored in the +%\meta{comma list}. The \meta{code} receives each \meta{item} as a +%trailing brace group. If the \meta{code} consists of a single +%function this is equivalent to \cs{ClistMapFunction} or \cs{ClistVarMapFunction}. +%\end{function} + +%\begin{function}{\ClistMapBreak} +%\begin{syntax} +%\cs{ClistMapBreak} +%\end{syntax} +%Used to terminate a clist map function before all +%entries in the \meta{comma list} have been processed. This +%normally takes place within a conditional statement, for example +%\begin{verbatim} +%\clist_map_inline:Nn \l_my_clist +%{ +%\str_if_eq:nnTF { #1 } { bingo } +%{ \clist_map_break: } +%{ +%Do something useful +%} +%} +%\end{verbatim} +%Use outside of a clist map scenario leads to low +%level \TeX{} errors. +%\begin{texnote} +%When the mapping is broken, additional tokens may be inserted +%before further items are taken +%from the input stream. This depends on the design of the mapping +%function. +%\end{texnote} +%\end{function} +% +%\begin{function}{\ClistMapBreakDo} +%\begin{syntax} +%\cs{ClistMapBreakDo} \Arg{code} +%\end{syntax} +%Used to terminate a clist map function before all +%entries in the \meta{comma list} have been processed, inserting +%the \meta{code} after the mapping has ended. This +%normally takes place within a conditional statement, for example +%\begin{verbatim} +%\clist_map_inline:Nn \l_my_clist +%{ +%\str_if_eq:nnTF { #1 } { bingo } +%{ \clist_map_break:n { <code> } } +%{ +%Do something useful +%} +%} +%\end{verbatim} +%Use outside of a clist map scenario leads to low +%level \TeX{} errors. +%\begin{texnote} +%When the mapping is broken, additional tokens may be inserted +%before the \meta{code} is +%inserted into the input stream. +%This depends on the design of the mapping function. +%\end{texnote} +%\end{function} + +\section{Comma List Conditionals} + +\begin{function}{\ClistIfExist,\ClistIfExistTF} +\begin{syntax} +\cs{ClistIfExist} \meta{comma list} +\cs{ClistIfExistTF} \meta{comma list} \Arg{true code} \Arg{false code} +\end{syntax} +Tests whether the \meta{comma list} is currently defined. This does +not check that the \meta{comma list} really is a comma list. +\end{function} + +\begin{function}{\ClistIfEmpty,\ClistIfEmptyTF} +\begin{syntax} +\cs{ClistIfEmpty} \Arg{comma list} +\cs{ClistIfEmptyTF} \Arg{comma list} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the \meta{comma list} is empty (containing no items). +The rules for space trimming are as for other \texttt{n}-type +comma-list functions, hence the comma list \verb|{ , ,, }| (without +outer braces) is empty, while \verb|{ ,{},}| (without outer braces) +contains one element, which happens to be empty: the comma-list +is not empty. +\end{function} + +\begin{function}{\ClistVarIfEmpty,\ClistVarIfEmptyTF} +\begin{syntax} +\cs{ClistVarIfEmpty} \meta{comma list} +\cs{ClistVarIfEmptyTF} \meta{comma list} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the \meta{comma list} is empty (containing no items). +\end{function} + +\begin{function}{\ClistIfIn,\ClistIfInTF} +\begin{syntax} +\cs{ClistIfIn} \Arg{comma list} \Arg{item} +\cs{ClistIfInTF} \Arg{comma list} \Arg{item} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the \meta{item} is present in the \meta{comma list}. +In the case of an \texttt{n}-type \meta{comma list}, the usual rules +of space trimming and brace stripping apply. For example +\begin{demohigh} +\ClistIfInTF { a , {b} , {b} , c } {b} {Yes} {No} +\end{demohigh} +%\begin{texnote} +%The function may fail if the \meta{item} contains \verb|{|, \verb|}|, or \verb|#| +%(assuming the usual \TeX{} category codes apply). +%\end{texnote} +\end{function} + +\begin{function}{\ClistVarIfIn,\ClistVarIfInTF} +\begin{syntax} +\cs{ClistVarIfIn} \meta{comma list} \Arg{item} +\cs{ClistVarIfInTF} \meta{comma list} \Arg{item} \Arg{true code} \Arg{false code} +\end{syntax} +Tests if the \meta{item} is present in the \meta{comma list}. +In the case of an \texttt{n}-type \meta{comma list}, the usual rules +of space trimming and brace stripping apply. +%\begin{texnote} +%The function may fail if the \meta{item} contains \verb|{|, \verb|}|, or \verb|#| +%(assuming the usual \TeX{} category codes apply). +%\end{texnote} +\end{function} + \chapter{The Source Code} %\CodeHigh{lite} @@ -991,4 +4363,3 @@ For example \dochighinput[language=latex/latex3]{functional.sty} \end{document} - diff --git a/macros/latex/contrib/thuthesis/CHANGELOG.md b/macros/latex/contrib/thuthesis/CHANGELOG.md index d68be6a460..086fa411a5 100644 --- a/macros/latex/contrib/thuthesis/CHANGELOG.md +++ b/macros/latex/contrib/thuthesis/CHANGELOG.md @@ -6,67 +6,110 @@ ## [Unreleased] +## [v7.2.4] - 2022-03-19 + +### Added + +- 增加警告提醒本科生将附录置于声明后([#682](https://github.com/tuna/thuthesis/issues/682))。 +- 增加警告提醒本科生将插图索引和表格索引置于正文后。 +- 本科生的 `\listoffiguresandtables` 改为分开的插图索引和表格索引。 + +### Changed + +- 本科生的“答辩委员会名单”、“指导教师/小组学术评语”和“答辩委员会决议书”改为不输出内容([#688](https://github.com/tuna/thuthesis/issues/688))。 +- 研究生和博后不再默认载入 `bibunits`([#710](https://github.com/tuna/thuthesis/issues/710))。 +- 参考文献表中预印本的文献类型标识改为“A”。 +- 允许多行页眉([#735](https://github.com/tuna/thuthesis/issues/735))。 + +### Fixed + +- 修复本科生“使用授权说明”中“日期”后缺失的冒号([#679](https://github.com/tuna/thuthesis/issues/679))。 +- 修复 `TikZ` 的 `external` 库与 `pdfpages` 的兼容性问题([#693](https://github.com/tuna/thuthesis/issues/693))。 +- 参考文献表中专利文献使用 `address`/`lcoation` 输出专利国别。 +- 修正一章内脚注数量超过 10 个时的报错问题,改为警告([#742](https://github.com/tuna/thuthesis/issues/742))。 + +### Removed + +- 去掉了 `siunitx` 的 `inter-unit-product` 设置。 + ## [v7.2.3] - 2021-05-31 + ### Changed -- 中文模板的公式编号改为中文括号(#297)。 + +- 中文模板的公式编号改为中文括号([#287](https://github.com/tuna/thuthesis/issues/287))。 ### Fixed -- 修正硕士论文书脊的字号(#647)。 -- 修正本科生附录(调研和翻译)的目录在 TeX Live 2019 前无法生成的问题(#659)。 -- 修正本科生主要符号表的标题(#661)。 + +- 修正硕士论文书脊的字号([#647](https://github.com/tuna/thuthesis/issues/647))。 +- 修正本科生附录(调研和翻译)的目录在 TeX Live 2019 前无法生成的问题([#659](https://github.com/tuna/thuthesis/issues/659))。 +- 修正本科生主要符号表的标题([#661](https://github.com/tuna/thuthesis/issues/661))。 ## [v7.2.2] - 2021-04-03 + ### Changed -- 修改授权说明的内容和格式,同 2020 年 12 月版 Word 模板一致(#625)。 -- 参考文献的页码前与冒号之间加上空格,同步 2021 年 3 月版《指南》的格式修改(#629)。 + +- 修改授权说明的内容和格式,同 2020 年 12 月版 Word 模板一致([#625](https://github.com/tuna/thuthesis/issues/625))。 +- 参考文献的页码前与冒号之间加上空格,同步 2021 年 3 月版《指南》的格式修改([#629](https://github.com/tuna/thuthesis/issues/629))。 - 著者-出版年制参考文献表的著者姓名与年份之间改为逗号。 ### Fixed -- 修正图表等浮动体与文字之间的距离(#614、#617)。 -- 修正表格、算法等浮动体的行距(#619)。 -- 修正了上标式引用后与中文之间多余的空格(#624)。 -- 修正了参考文献的姓名或年份中含有中括号时的引用错误(#630)。 + +- 修正图表等浮动体与文字之间的距离([#614](https://github.com/tuna/thuthesis/issues/614)、[#617](https://github.com/tuna/thuthesis/issues/617))。 +- 修正表格、算法等浮动体的行距([#619](https://github.com/tuna/thuthesis/issues/619))。 +- 修正了上标式引用后与中文之间多余的空格([#624](https://github.com/tuna/thuthesis/issues/624))。 +- 修正了参考文献的姓名或年份中含有中括号时的引用错误([#630](https://github.com/tuna/thuthesis/issues/630))。 ## [v7.2.1] - 2021-03-21 + ### Added + - 在文档中添加更多关于数学公式样式的说明。 ### Changed + - 允许控制研究生的声明页是否添加页眉页脚。 ### Fixed -- 调整文字与图表等浮动体之间的距离(#614)。 + +- 调整文字与图表等浮动体之间的距离([#614](https://github.com/tuna/thuthesis/issues/614))。 - 修复一些字体选择相关的问题。 ## [v7.2.0] - 2021-03-12 + ### Added + - 新增英文版写作指南要求的格式。 -- 新增选题报告的格式(#579)。 +- 新增选题报告的格式([#579](https://github.com/tuna/thuthesis/issues/579))。 - 新增 `figure-number-sepatator` 等选项设置图表编号的连接符。 - 新增数学符号字体风格选项 `math-style`。 - 新增选项控制数学字体风格的细节:`uppercase-greek`、`less-than-or-equal`、`integral`、`integral-limits`、`partial` 和 `math-ellipsis`。 - 新增数学字体试验性选项 `math-font = newtx`。 ### Changed -- 研究生的声明页默认加上页眉和页码,不受 `page-style` 的控制(#574)。 -- 取消图表标题的悬挂缩进(#589)。 + +- 研究生的声明页默认加上页眉和页码,不受 `page-style` 的控制([#574](https://github.com/tuna/thuthesis/issues/574))。 +- 取消图表标题的悬挂缩进([#589](https://github.com/tuna/thuthesis/issues/589))。 - 英文封面的联合导师改为“Co-supervisor”。 - 联合导师的 key 改为 `co-supervisor`,同英文版模板一致。 ### Fixed -- 修正 `longtable` 宏包的配置(#584)。 -- 修正本科生的“目录”、“声明”和“致谢”等标题中的空白(#591)。 + +- 修正 `longtable` 宏包的配置([#584](https://github.com/tuna/thuthesis/issues/584))。 +- 修正本科生的“目录”、“声明”和“致谢”等标题中的空白([#591](https://github.com/tuna/thuthesis/issues/591))。 - 修正参考文献的格式,取消页码与前面冒号之间的空格。 - 修正中文封面的字距。 ## [v7.1.0] - 2020-10-14 + ### Changed + - 更新摘要的标题格式(研究生 2020-09-18 版)。 - 更新目录的格式(研究生 2020-09-18 版)。 - 图表浮动体的位置参数默认为 `h`。 - 更新示例文档。 ### Fixed + - 修正 “keywords” 的拼写。 - 修正授权使用说明的内容。 - 修正授伪粗字体的粗度。 @@ -78,17 +121,21 @@ - 修正脚注的行距和缩进距离。 ## [v7.0.0] - 2020-09-09 + ### Changed + - 更新 2020 年版目录、插图和附表清单的格式。 - 更新 2020 年版使用授权说明的内容。 - 更新 2020 年版参考文献表的格式。 ### Added + - 新增 2020 年版“答辩委员会名单”页。 - 新增 biblatex 支持。 - 新增本科生外文系格式的支持。 ### Fixed + - 修正本科生密级的字体。 - 修正表格的默认字号。 - 修正参考文献表的行距和段前段后间距。 @@ -97,72 +144,88 @@ - 修正封面的语言切换。 ## [v6.1.3] - 2020-07-09 + ### Added + - 新增选项 `statement-page-style = empty / plain` 同时控制声明的页眉和页脚。 ### Fixed + - `\record` 命令中,如果 `output` 配置为 `print`,则强制进行 `\cleardoublepage`,保证记录表独立成页。 -- 修正了在导言区设置论文主要语言无效的问题(#560)。 +- 修正了在导言区设置论文主要语言无效的问题([#560](https://github.com/tuna/thuthesis/issues/560))。 - 修正了研究生插入扫描版声明页时的页眉。 ### Deprecated + - 选项 `statement-page-number` 已过时。 ## [v6.1.2] - 2020-06-14 + ### Changed + - `\statement` 和 `\copyrightpage` 命令都会在 PDF 中生成相应位置的书签。 - `\statement` 命令编译生成声明页默认不含页码。 - `\statement[xxx.pdf]` 插入扫描页时在页脚生成页码,以解决打印版与电子版页码不一致的情况。 - 使用 `l3build` 编译的版本,在提交到 CTAN 时提供 TDS 结构,以解决编译时 `tsinghua-name-bachelor.pdf` 找不到的问题。 ### Added + - 添加 `\record` 命令用于本科生插入综合论文训练记录表,同时在 PDF 中生成对应书签。 - 添加选项 `statement-page-number` 控制编译声明页时是否含页码。 ### Fixed + - 修正示例代码中关于 `\statement` 的 typo。 ## [v6.1.1] - 2020-06-12 + ### Changed + - 书脊中的西文不再需要调整高度。 - 修改预生成的隶书版本本科生封面学校名称的文件名为 `tsinghua-name-bachelor.pdf`,不再尝试使用系统字体生成。 - 将论文示例的文件名更改为 `thuthesis-example.tex / pdf`,以符合 CTAN 的要求。 ### Added -- 添加选项 `include-spine`,允许在正文中插入书脊页(#551)。 + +- 添加选项 `include-spine`,允许在正文中插入书脊页([#551](https://github.com/tuna/thuthesis/issues/551))。 - 添加选项 `spine-title`、`spine-author` 控制书脊的内容。 - 添加选项 `spine-font` 控制书脊的字号。 -- 添加选项 `output` 选择输出格式为打印版或用于提交的电子版(#553)。 +- 添加选项 `output` 选择输出格式为打印版或用于提交的电子版([#553](https://github.com/tuna/thuthesis/issues/553))。 ### Fixed + - 修正书脊的格式。 - 修复文档中 Changelog 的格式问题。 ## [v6.1.0] - 2020-06-08 + ### Changed + - 在 `translation` 环境中使用 `\bibliography` 改为生成参考文献, - 对应的原文索引改为 `translation-index` 环境(#529)。 + 对应的原文索引改为 `translation-index` 环境([#529](https://github.com/tuna/thuthesis/issues/529))。 - 附录的图、表不再加入索引。 - 使用 `threeparttable` 示例表内脚注。 -- 本科生的目录章标题的西文字母和数字默认使用 Arial(#542)。 +- 本科生的目录章标题的西文字母和数字默认使用 Arial([#542](https://github.com/tuna/thuthesis/issues/542))。 - GitHub repo 所有者更改为清华大学 TUNA 协会。 -- 接管 `ctex` 的 `fontset` 选项,允许更灵活的字体配置(#498)。 +- 接管 `ctex` 的 `fontset` 选项,允许更灵活的字体配置([#498](https://github.com/tuna/thuthesis/issues/498))。 ### Fixed -- 本科生附录的调研报告使用英文(#479)。 + +- 本科生附录的调研报告使用英文([#479](https://github.com/tuna/thuthesis/issues/479))。 - 修正本科生附录的 `algorithm` 和 `listings` 环境的编号格式。 -- 研究生的“使用授权说明”增加一空白页(#504)。 -- 修正 publication 列表行距问题(#507)。 +- 研究生的“使用授权说明”增加一空白页([#504](https://github.com/tuna/thuthesis/issues/504))。 +- 修正 publication 列表行距问题([#507](https://github.com/tuna/thuthesis/issues/507))。 - 修正研究生目录的行距。 -- 调整本科生封面有辅导教师、联合指导教师时的格式(#522, #537)。 -- 修正本科生封面日期的字体(#532)。 +- 调整本科生封面有辅导教师、联合指导教师时的格式([#522](https://github.com/tuna/thuthesis/issues/522), [#537](https://github.com/tuna/thuthesis/issues/537))。 +- 修正本科生封面日期的字体([#532](https://github.com/tuna/thuthesis/issues/532))。 - 设置三线表横线的默认粗度。 - 修正文档中关于本科生学科(专业)名称的说明。 - 允许用户使用文档类选项 `openright`。 -- 修正本科生的“单设一页”格式(#545)。 +- 修正本科生的“单设一页”格式([#545](https://github.com/tuna/thuthesis/issues/545))。 - 研究生的正文(main matter)起始于奇数页。 ### Added + - 允许使用边注。 - 新增 `amsthm` 支持。 - 支持单个关键词设置样式。 @@ -170,37 +233,47 @@ - 添加选项 `toc-chapter-style` 控制本科生的目录章标题的西文字体。 ## [v6.0.2] - 2020-02-23 + ### Fixed -- 修复图表公式目录内容缺失(#467)。 + +- 修复图表公式目录内容缺失([#467](https://github.com/tuna/thuthesis/issues/467))。 - 修复 Github Actions 执行 l3build check 问题。 - 文本模式使用 `\checkmark`。 ### Added + - 补充 PDF 元信息:文档标题,语言。 ### Changed + - 补充“著者-出版年”引用命令使用方法。 - 使用 `xeCJKfntef` 替换 `CJKfntef`。 ## [v6.0.1] - 2020-02-03 + ### Changed + - 更新文档。 - 更新 bib 测试用例。 ### Fixed -- 修复 PDF 目录层级问题(#457)。 -- 修复 PDF 中章节连接问题(#453)。 + +- 修复 PDF 目录层级问题([#457](https://github.com/tuna/thuthesis/issues/457))。 +- 修复 PDF 中章节连接问题([#453](https://github.com/tuna/thuthesis/issues/453))。 ## [v6.0.0] - 2020-01-06 + ### Added + - 新增 `survey`(调研阅读报告)和 `translation`(书面翻译)环境用于本科生的附录, - 其中的参考文献引用独立于论文正文(#343)。 + 其中的参考文献引用独立于论文正文([#343](https://github.com/tuna/thuthesis/issues/343))。 - 新增论文语言选项。 - 增加 `l3build` 测试。 ### Changed + - 重新设计 `\thusetup` 的接口。 -- 指导教师的姓名和职称用英文逗号分开(#424)。 +- 指导教师的姓名和职称用英文逗号分开([#424](https://github.com/tuna/thuthesis/issues/424))。 - 重新设计封面(题名页)。 - `\makecover` 拆分为 `\maketitle`、`\copyrightpage`。 - 中英文摘分别用 `abstract`、`abstract*` 环境生成。 @@ -212,26 +285,34 @@ - 整理 Makefile,便于日常使用。 ## Removed + - 移除 `secret` 选项。 - 移除 `translationbib` 环境。 - 移除 `tocarialchapter`、`tocarialchapterentry` 和 `tocarialchapterpage` 选项。 - 只保留 xelatex 编译方式。 ### Fixed + - 修正本科生的文献引用样式。 - 修正本科生目录章标题的字体。 - 处理 `hyperref` 与 `unicode-math` 的兼容性问题。 ## [v5.5.2] - 2019-04-21 + ### Changed + - 使用 XITS 数学字体。 ## [v5.5.1] - 2019-04-16 + ### Changed + - `\thu@textcircled`: 修复 minipage 中 footnote 编号问题。 ## [v5.5.0] - 2019-03-15 + ### Changed + - 增加选项使用英文模板。 - 使用 `unicode-math` 处理数学字体。 - Windows 的中文字体开启伪粗。 @@ -242,11 +323,15 @@ - 增加 `nomencl` 宏包的支持。 ## [v5.4.5] - 2018-05-17 + ### Changed + - `\normalsize`: 调整公式和正文间距。 ## [v5.4.4] - 2018-04-22 + ### Changed + - 删除 `arialtitle`,所有论文格式都一样。 - 让目录中的引用不影响正文中引用序号。 - 参考文献列表的页码使用 hyphen 取代 en dash。 @@ -254,40 +339,56 @@ - 允许连续两个文献引用使用连接号。 ## [v5.4.2] - 2017-12-18 + ### Changed + - 删除 `\pozhehao`。 - 使用 degree 取代 type 选项。 ## [v5.4.1] - 2017-12-04 + ### Changed + - bst 在 ctan 上不分路径,故加前缀。 ## [v5.4.0] - 2017-12-3 + ### Changed + - 基于 `natbib` 的环境调整距离兼容性更好。 - `\bibliographystyle{<newbib>}` will cause `\bibstyle@newbib` to be called on THE NEXT LATEX RUN (via the aux file). ## [v5.3.2] - 2017-05-01 + ### Changed + - 定理环境格式设置(环境标题和环境正文字体设置)统一放置到 .cfg 文件中。 ## [v5.3.1] - 2016-03-20 + ### Changed + - 使用 CTeX 默认中文字体配置,支持不同引擎。 - `ctex` 默认加载 `CJKspace`。 - 几乎没人主动安装 Arial 字体。 ## [v5.3.0] - 2016-03-11 + ### Changed + - 更新到研究生院 2016.3 指南。 ## [v5.2.3] - 2016-02-13 + ### Changed + - `\thu@def@fontsize`: 改写字体定义命令。 - 安全注释本科公式部分。 ## [v5.2.2] - 2016-02-01 + ### Changed + - 不希望 `newtx` 修改 `\@makefnmark`。 - 利用 `environ` 的 `\Collect@Body`。 - 目录中标题和页码都是链接。 @@ -297,26 +398,34 @@ - 用 `environ` 封装的 `\Collect@Body`。 ## [v5.2.1] - 2016-01-14 + ### Changed + - 使用 `newtx` 替换 `txfonts`。 - 使用 `newtx` 字体。 - `denotation`: 利用 `enumitem` 改造环境定义,更直观。 - `acknowledgement`: 用 `acknowledgement` 替换 `ack`。 ## [v5.2.0] - 2016-01-11 + ### Changed + - `\title`: 增加 `\title` 排版翻译标题。 - `translationbib`: 增加翻译文献环境 `translationbib`。 - `\publicationskip`: 增加 `\publicationskip`。 ## [v5.1.0] - 2015-12-27 + ### Changed + - `\thusetup`: 通过 `\thusetup` 统一设置封面信息。 - `\thu@first@titlepage`: 利用 `CJKfilltwosides` 优化封面排版。 - `\thu@first@titlepage`: 修改联合指导教师显示问题。 ## [v5.0.0] - 2015-12-21 + ### Changed + - 使用 `kvoptions` 简化选项 type。 - norggedbottom 选项修改为 raggedbottom。 - 删除 `paralist` 选项。 @@ -324,25 +433,29 @@ - 不再将页面尺寸写入 dvi,因为已不支持 dvips, 而该方案会使得在使用 tikzexternalize 时外部 PDF 图片 BBox 不对。 - 用 `geometry` 简化设置。 - `\ps@thu@headings`: 利用 `fancyhdr` 设置页眉页脚。 -- 修正定理字样为黑体(#104)。 +- 修正定理字样为黑体([#104](https://github.com/tuna/thuthesis/issues/104))。 - 本科附录图表编号用-不用.(如图A-1,表A-2)。 - 用 `\ctexset` 来设置,替换复杂的 `\@startsection`。 -- 修正章节间距问题(#57)。 +- 修正章节间距问题([#57](https://github.com/tuna/thuthesis/issues/57))。 - 硕士博士论文目录只出现到第 3 级标题即可。其他未明确要求。 -- `\tableofcontents`: 修正学位论文中目录里节前缩进(#103)。 -- `\makecover`: 使用 `pdfpages` 宏包支持本硕博论文授权说明扫描版(#36)。 -- `acknowledgement`: 使用 pdfpages 宏包支持本硕博论文声明扫描版(#36)。 +- `\tableofcontents`: 修正学位论文中目录里节前缩进([#103](https://github.com/tuna/thuthesis/issues/103))。 +- `\makecover`: 使用 `pdfpages` 宏包支持本硕博论文授权说明扫描版([#36](https://github.com/tuna/thuthesis/issues/36))。 +- `acknowledgement`: 使用 pdfpages 宏包支持本硕博论文声明扫描版([#36](https://github.com/tuna/thuthesis/issues/36))。 - `\inlinecite`: 用 `\inlinecite` 替换 `\onlinecite`。为保证兼 容性,`\onlinecite` 会保留。 -- `achievements`: 博士后就不提在学期间了,不合适(#100)。 -- `achievements`: 让简历部分更符合格式指南和示例文件(#122)。 +- `achievements`: 博士后就不提在学期间了,不合适([#100](https://github.com/tuna/thuthesis/issues/100))。 +- `achievements`: 让简历部分更符合格式指南和示例文件([#122](https://github.com/tuna/thuthesis/issues/122))。 - `\shuji`: 扩展 `\shuji[<标题>][<作者>]`。 ## [v4.8.1] - 2014-12-09 + ### Changed + - 按照 CTAN 的要求整理一下文件。 ## [v4.8] - 2014-11-25 + ### Changed + - no need to load `indentfirst` directly since we use `ctex`. - 内部调用 `ctex` 宏包,自动检测编译引擎。 - dvips method is deprecated. We ask their users to load it manually. @@ -355,7 +468,9 @@ - 在 CJK 模式下用 `CJKspace` 保留中英文间空格。 ## [v4.7] - 2012-06-12 + ### Changed + - 去掉 `hypernat` 依赖,`hyperref` 和 `natbib` 可以很好配合了。 - 修改本科生页脚间距与样例基本一致。 - `\ps@thu@headings`: 本科页码用小五号字。 @@ -368,7 +483,9 @@ - `\thu@makeabstract`: Bachelor sample uses Keywords w/o space `-_-` ## [v4.6] - 2011-10-22 + ### Changed + - 增加博士后文档部分。 - 使用手册更新。 - 增加 postdoctor 选项。 @@ -379,7 +496,9 @@ - `resume`: 支持可选参数,自己定义简历章节标题。 ## [v4.5.2] - 2010-09-19 + ### Changed + - 研究生页面边距由 3.2cm 改为 3cm。 - 本科论文日期具体到日。 - `\makecover`: 本科封面和授权说明之间不要空白页。 @@ -387,28 +506,38 @@ - `acknowledgement`: 研究生论文的致谢和声明终于分开了。 ## [v4.5.1] - 2009-01-06 + ### Changed + - 太好了,不用处理 `longtable` 的 `\caption` 了。 - `\listoftables*`: 更优雅的插图/表格索引,避免跟 `caption` 包冲 突。`\thu@listof` 相应修改。 ## [v4.5] - 2009-01-04 + ### Changed + - 加入 XeTeX 支持,需要 `xeCJK`。 - 彻底转向 UTF-8,并支持 XeLaTeX。 - 增加 xetex, pdftex 选项。 - `\shuji`: 简化代码,同时支持 XeLaTeX。 ## [v4.4.4] - 2008-06-12 + ### Changed + - 修复了一个从 v4.3 升级到 v4.4 过程中的丢失公式索引的 bug,原修改代码保留备忘。 ## [v4.4.3] - 2008-06-09 + ### Changed + - `\thu@first@titlepage`: 修改本科生论文封面格式以符合新样例。 - `\thu@first@titlepage`: 修改本科生论文封面日期格式以符合新样例。 ## [v4.4.2] - 2008-06-07 + ### Changed + - 本科生格式终于也开始用空格作为关键字分隔符了。 - 本科生签名之间距离改为 `\hskip1em`。 - `\thu@authorization@mk`: 修改本科生的授权部分,按照 2008 年的新样例。 @@ -416,7 +545,9 @@ - `\thu@makeabstract`: Bachelor English abstract format requires indent and no hang-indent. ## [v4.4] - 2008-06-18 + ### Changed + - 修复网址断字。 - `\backmatter`: 本科正文后的页码延续前面的阿拉伯数字,不再用罗马数 字。 - `\backmatter`: 本科取消了所有页眉。 @@ -430,23 +561,31 @@ - `\tableofcontents`: 本科章目录项一直用黑体(Arial)。 ## [v4.3] - 2008-03-11 + ### Changed + - 子图引用时加括号。 ## [v4.2] - 2008-03-07 + ### Changed + - `\eqref` 加括号。 - 调整证明环境的编号和结尾的方块。 - `\thu@doctor@engcover`: 博士英文封面补充联合导师。 ## [v4.0] - 2007-11-08 + ### Changed + - `\tableofcontents`: 本科研究生目录字号行距都不同。 - **内部**密级前面终究还是不要五角星了。 - `\thu@authorization@mk`: 研究生的授权部分调整了一下,不知道老师为什么总爱修改 那些无关紧要的格式,郁闷。感谢 PMHT@newsmth 的认真比对。 ## [v3.1] - 2007-10-09 + ### Changed + - 本科的目录又不要 arial 字体了。 - replace `mathptmx` with `txfonts`. - 英文摘要标题要搞特殊化。 @@ -460,7 +599,9 @@ - `\thu@makeabstract`: 研究生关键词不再沉底。 ## [v3.0] - 2007-05-13 + ### Changed + - 不用专门为本科论文生成“**提交**”版本了。 - 没有了综合论文训练页面,很多本科论文专用命令就消失了。 - 删除 submit 选项。 @@ -473,7 +614,9 @@ - `acknowledgement`: 本科论文声明部分图片扫描取消。 ## [v2.6.4] - 2006-10-23 + ### Changed + - 增加 `neverdecrease` 选项。 - `\thu@makeabstract`: **Keywords** but not **Key words**. - `\listoftables*`: 增加 `\listoffigures*`,`\listoftables*`。 @@ -481,12 +624,16 @@ - 调整参考文献标签宽度,使得条目增多时仍能对齐。 ## [v2.6.3] - 2006-07-01 + ### Changed + - `\thu@makeabstract`: 为本科正确设置目录及以后的页码。 - `acknowledgement`: 重画双虚线,自适应页面宽度。 ## [v2.6.2] - 2006-06-20 + ### Changed + - 改正 groupmembers 的拼写错误。 - 去掉 `paralist` 的 `newitem` 和 `newenum` 选项,因为默认是打开的。 - `\thu@def@fontsize`: 引入此命令重新定义字号。 @@ -500,11 +647,15 @@ - `\equcaption`: 此命令配合 `amsmath` 命令基本可以满足所有 公式需要。 ## [v2.6.1] - 2006-06-16 + ### Changed + - 取消 `thubib.bst` 中 inbook 类 volume 后的页 码。 ## [v2.6] - 2006-06-09 + ### Changed + - 增加 dvipdfm 选项。 - 增加 `longtable`。 - 去除 hyperref 选项,等待全局传递。 @@ -513,7 +664,9 @@ - `\thu@first@titlepage`: 本科生题目加长,最多 24 个字。 ## [v2.5.3] - 2006-06-08 + ### Changed + - submit 选项的一个笔误。 - `\backmatter`: 第一章永远右开。 - 不管 caption 出现在什么位置,`\aboveskip` 总是出现在标题和浮动体之间的距离。 @@ -522,7 +675,9 @@ - `\equcaption`: 取消 `\equcaption` 的参数 ## [v2.5.2] - 2006-06-01 + ### Changed + - 更改默认列表距离。 - 上一个版本忘了把研究生的公式编号排除。 - `\thu@chapter*`: 定义自己的 `\thu@chapter*`。 @@ -534,7 +689,9 @@ - `resume`: 研究生的个人介绍要右开。 ## [v2.5.1] - 2006-05-28 + ### Changed + - 如果选项设置了 dvips,但是用 PDFLaTeX 编译,报错。 - 根据教务处的新要求调整附录部分。 - 参考文献中杂志文章如果没有卷号,那么页码直接跟在 年份后面,并用句点分割。在 `thubib.bst` 中增加 output.year 函数。 @@ -560,7 +717,9 @@ - `resume`: 教务处和研究生院非要搞的不一样! ## [v2.5] - 2006-05-20 + ### Changed + - 对本科论文进行大幅度的重写,因为教务处修改了格式要求。 - 重新整理代码,使其布局更易读。 - 增加本科论文的提交选项 submit。 @@ -583,16 +742,22 @@ - 不用 `\CJKcaption`,在导言区直接引入配置文件。 ## [v2.4.2] - 2006-04-18 + ### Changed + - 去掉参考文献第二个作者后面烦人的逗号。 ## [v2.4.1] - 2006-04-17 + ### Changed + - 2.4 忘了把关键词的 tabular 改成 thu@tabular。 - 参考文献最后一个作者前是逗号而不是 and。 ## [v2.4] - 2006-04-15 + ### Changed + - Fill more pdf info. with `\hypersetup`. - 自动隐藏密级为内部时后面的五角星。 - 增加“注释(Remark)”环境。 @@ -616,7 +781,9 @@ - 参考文献间距调小一点,label 长度增加一点,以便让超过 100 的参考文献更好地对齐。 ## [v2.3] - 2006-04-09 + ### Changed + - Fix a great bug: `\PassOptionsToClass` and `\LoadClass` rather than `\PassOptionToPackage` and `\LoadPackage`. - Reorganize the codes in cover, make the pagestyle more readable. - Add gbk2uni into the document. @@ -629,14 +796,18 @@ - Change the brace in the cover. ## [v2.2] - 2006-03-26 + ### Changed + - Adjust margins. How bad it is to simulate MS WORD!. - Add bachelor training overview details supporting. - CJK support in preamble. - Adjust hyperref to avoid boxes around links. ## [v2.1] - 2006-03-03 + ### Changed + - Add support to bachelor thesis. - Remove `fancyhdr` and `geometry`. - Redefine footnote marks. @@ -651,11 +822,15 @@ - `\makecover`: 分成几个小模块来搞,不然这个 macro 太大了,看不过来。 ## [v2.0e] - 2005-12-18 + ### Changed + - `denotation`: 主要符号表定义为一个 list,用起来方便。 ## [v2.0] - 2005-12-20 + ### Changed + - `\ps@thu@headings`: 以前的太乱了,重新整理过清晰多了。 - `\tableofcontents`: 附录的目录项需要调整一下。以及公式编号方式等等。 - 增加了封面密级,增加博士封面支持 @@ -664,38 +839,53 @@ - `resume`: 最后决定将 resume 定义为环境。这样与前面的主要符号 表、致谢等对应。 ## [v1.5] - 2005-12-16 + ### Changed + - `acknowledgement`: 在那些不显示编号的章节前面先执行一次 `\cleardoublepage`,使新开章节的页码到达正确的状态。否则会因为 `\addcontentsline` 在 chapter 之前而导致目录页码错误。 - `resume`: 增加个人简历章节的命令,去掉主文件中需要重新 定义 `\cleardoublepage` 和自己写 `\markboth`,`\addcontentsline` 的部分。 ## [v1.4rc1] - 2005-12-14 + ### Changed + - I do not know why `\thu@authorizationaddon` does not work now for v1.3, while it's fine in v1.2. Temporarily, I remove the directive :(. There might be better solution. Other changes: add `config` option to subfig to be compatible with subfigure. add `courier` package for tt font. - I have to put all chinese chars into cfg, otherwise they would not appear. ## [v1.4] - 2005-12-05 + ### Changed + - Fix the problem of **chinese**, which is because both CJK and everysel redefine the `\selectfont`. So, a not so good workaround is to merge them up. Add `shuji.tex` example. Add `\pozhehao` command. ## [v1.3] - 2005-11-14 + ### Changed + - Replace `subfigure` with `subfig`, replace `caption2` with `caption`, add details about using figure are in the example. ## [v1.2] - 2005-11-04 + ### Changed + - Remove `fancyref`; Remove `ucite` and implement `\onlinecite`; use package `arial` or `helvet` selectively. ## [v1.1] - 2005-11-03 + ### Changed + - Initial version, migrate from the old ``Bao--Pan'' version. Make the template a class instead of package. ## [v1.0] - 2005-07-06 + ### Changed + - Please refer to ``Bao--Pan'' version. -[Unreleased]: https://github.com/tuna/thuthesis/compare/v7.2.3...HEAD +[Unreleased]: https://github.com/tuna/thuthesis/compare/v7.2.4...HEAD +[v7.2.4]: https://github.com/tuna/thuthesis/compare/v7.2.3...v7.2.4 [v7.2.3]: https://github.com/tuna/thuthesis/compare/v7.2.2...v7.2.3 [v7.2.2]: https://github.com/tuna/thuthesis/compare/v7.2.1...v7.2.2 [v7.2.1]: https://github.com/tuna/thuthesis/compare/v7.2.0...v7.2.1 diff --git a/macros/latex/contrib/thuthesis/README.md b/macros/latex/contrib/thuthesis/README.md index 455b858f95..c84c7f409f 100644 --- a/macros/latex/contrib/thuthesis/README.md +++ b/macros/latex/contrib/thuthesis/README.md @@ -15,10 +15,6 @@ Scroll down for the English version of README. **由于模板升级频繁,在开始使用和提问前,请确保您已经认真完整地阅读了使用说明文档和示例代码。** -**由于模板升级频繁,在开始使用和提问前,请确保您已经认真完整地阅读了使用说明文档和示例代码。** - -**由于模板升级频繁,在开始使用和提问前,请确保您已经认真完整地阅读了使用说明文档和示例代码。** - ## 下载 推荐下载**发布版**模板,里面包括具体使用说明以及示例文档: @@ -37,6 +33,8 @@ Scroll down for the English version of README. * [Overleaf](https://www.overleaf.com/latex/templates/thuthesis-tsinghua-university-thesis-latex-template/wddqnwbyhtnk):Overleaf 的模板。 * 开发版:[GitHub](https://github.com/tuna/thuthesis) +**任何在其他途径分发的 ThuThesis(包含其变体或衍生物)均不是官方版本,请谨慎使用。** + ## 更新日志 每个版本的详细更新日志,请见 [CHANGELOG.md](CHANGELOG.md)。使用文档中也包含了这一内容。 @@ -107,6 +105,8 @@ Developer versions contain only source code but no pre-compiled `cls` file and d * [Overleaf Template](https://www.overleaf.com/latex/templates/thuthesis-tsinghua-university-thesis-latex-template/wddqnwbyhtnk) * Developer versions: [GitHub](https://github.com/tuna/thuthesis) +**ThuThesis (including its variants / derivatives) distributed in any other way is NOT an official version. Use at your own risk.** + ## Changelog See [CHANGELOG.md](CHANGELOG.md) for detailed changes in each release. They are also included in the usage documentation. diff --git a/macros/latex/contrib/thuthesis/data/appendix-translation.tex b/macros/latex/contrib/thuthesis/data/appendix-translation.tex index 812cfcc767..0ca7d15264 100644 --- a/macros/latex/contrib/thuthesis/data/appendix-translation.tex +++ b/macros/latex/contrib/thuthesis/data/appendix-translation.tex @@ -62,6 +62,13 @@ 文献引用示例\cite{abrahams99tex}。 +\appendix + +\section{附录} + +附录的内容。 + + % 书面翻译的参考文献 \bibliographystyle{unsrtnat} \bibliography{ref/appendix} diff --git a/macros/latex/contrib/thuthesis/data/chap04.tex b/macros/latex/contrib/thuthesis/data/chap04.tex index a7fcc1439f..b07ce4dc96 100644 --- a/macros/latex/contrib/thuthesis/data/chap04.tex +++ b/macros/latex/contrib/thuthesis/data/chap04.tex @@ -47,7 +47,7 @@ \thusetup{ cite-style = author-year, } -\begin{tabular}{l@{\quad$\Rightarrow$\quad}l} +\begin{tabular}{l@{\space$\Rightarrow$\space}l} \verb|\cite{zhangkun1994}| & \cite{zhangkun1994} \\ \verb|\citet{zhangkun1994}| & \citet{zhangkun1994} \\ \verb|\citep{zhangkun1994}| & \citep{zhangkun1994} \\ diff --git a/macros/latex/contrib/thuthesis/ref/appendix.bib b/macros/latex/contrib/thuthesis/ref/appendix.bib index 1e4cc0daef..0f9ae22352 100644 --- a/macros/latex/contrib/thuthesis/ref/appendix.bib +++ b/macros/latex/contrib/thuthesis/ref/appendix.bib @@ -5,7 +5,7 @@ year = 1990, } -@incollection{salomon1995advanced, +@book{salomon1995advanced, author = {David Salomon}, title = {The advanced {\TeX}book}, address = {New York}, diff --git a/macros/latex/contrib/thuthesis/ref/refs.bib b/macros/latex/contrib/thuthesis/ref/refs.bib index 7c397888d5..6b51f03003 100644 --- a/macros/latex/contrib/thuthesis/ref/refs.bib +++ b/macros/latex/contrib/thuthesis/ref/refs.bib @@ -41,7 +41,9 @@ @patent{jiangxizhou1980, author = {姜锡洲}, - title = {一种温热外敷药制备方案: 中国, 88105607.3}, + title = {一种温热外敷药制备方案}, + address = {中国}, + number = {88105607.3}, date = {1980-07-26}, key = {jiang1 xi1 zhou1}, } diff --git a/macros/latex/contrib/thuthesis/spine.pdf b/macros/latex/contrib/thuthesis/spine.pdf Binary files differindex 63eef753e0..6f9d37e2ed 100644 --- a/macros/latex/contrib/thuthesis/spine.pdf +++ b/macros/latex/contrib/thuthesis/spine.pdf diff --git a/macros/latex/contrib/thuthesis/thusetup.tex b/macros/latex/contrib/thuthesis/thusetup.tex index dc74d148bd..718667f969 100644 --- a/macros/latex/contrib/thuthesis/thusetup.tex +++ b/macros/latex/contrib/thuthesis/thusetup.tex @@ -156,10 +156,10 @@ % \bibliographystyle{thuthesis-bachelor} % 参考文献使用 BibLaTeX 宏包 -% \usepackage[backend=biber,style=thuthesis-numeric]{biblatex} -% \usepackage[backend=biber,style=thuthesis-author-year]{biblatex} -% \usepackage[backend=biber,style=apa]{biblatex} -% \usepackage[backend=biber,style=mla-new]{biblatex} +% \usepackage[style=thuthesis-numeric]{biblatex} +% \usepackage[style=thuthesis-author-year]{biblatex} +% \usepackage[style=apa]{biblatex} +% \usepackage[style=mla-new]{biblatex} % 声明 BibLaTeX 的数据库 % \addbibresource{ref/refs.bib} diff --git a/macros/latex/contrib/thuthesis/thuthesis-author-year.bbx b/macros/latex/contrib/thuthesis/thuthesis-author-year.bbx index 47ec9ea815..026e280cb1 100644 --- a/macros/latex/contrib/thuthesis/thuthesis-author-year.bbx +++ b/macros/latex/contrib/thuthesis/thuthesis-author-year.bbx @@ -6,7 +6,6 @@ \ExecuteBibliographyOptions{ gbnamefmt = lowercase, gbpub = false, - gbalign = left, } \defbibenvironment{bibliography} @@ -18,3 +17,33 @@ \setlength{\parsep}{\bibparsep}}} {\endlist} {\item} + +% +% 重设专利title的输出,将文献类型标识符输出出去 +% +\renewbibmacro*{patenttitle}{%原输出来自biblatex.def文件 + \ifboolexpr{% + test{\iffieldundef{title}}% + and% + test{\iffieldundef{subtitle}}% + }% + {}% + {\printtext[title]{\bibtitlefont% + \printfield[titlecase]{title}% + \ifboolexpr{test {\iffieldundef{subtitle}}} + {}{\setunit{\subtitlepunct}% + \printfield[titlecase]{subtitle}}% + \iffieldundef{titleaddon}{} + {\setunit{\subtitlepunct}\printfield{titleaddon}}% + % \setunit{\subtitlepunct}\printfield{number}%写专利号 + \setunit{\subtitlepunct}% + \iflistundef{location}{} + {\printlist{location}\setunit{\addcomma\space}}% 专利国别 + \printfield{number}%写专利号 + \iftoggle{bbx:gbtype}{\printfield[gbtypeflag]{usera}}{}% + %\iffieldundef{booktitle}{\newunit}{}%当title是析出时,不要标点 + %\newunit + }% +}% +\clearlist{location}\clearlist{address}% +} diff --git a/macros/latex/contrib/thuthesis/thuthesis-author-year.bst b/macros/latex/contrib/thuthesis/thuthesis-author-year.bst index d25269b8e3..514368e842 100644 --- a/macros/latex/contrib/thuthesis/thuthesis-author-year.bst +++ b/macros/latex/contrib/thuthesis/thuthesis-author-year.bst @@ -4,11 +4,11 @@ %% %% The original source files were: %% -%% gbt7714.dtx (with options: `2015,thu,authoryear') +%% gbt7714.dtx (with options: `2015,thu,author-year') %% ------------------------------------------------------------------- %% GB/T 7714—2015 BibTeX Style -%% https://github.com/CTeX-org/gbt7714-bibtex-style -%% Version: 2021/04/03 v2.1.1 +%% https://github.com/zepinglee/gbt7714-bibtex-style +%% Version: 2021/12/08 v2.1.3 %% ------------------------------------------------------------------- %% Copyright (C) 2016—2021 by Zeping Lee <zepinglee AT gmail.com> %% ------------------------------------------------------------------- @@ -29,9 +29,11 @@ INTEGERS { terms.in.macro year.after.author period.after.author + italic.book.title sentence.case.title link.title title.in.journal + show.patent.country show.mark space.before.mark show.medium.type @@ -43,12 +45,14 @@ INTEGERS { show.missing.address.publisher space.before.pages only.start.page + wave.dash.in.pages show.urldate show.url show.doi show.preprint show.note show.english.translation + end.with.period lang.zh.order lang.ja.order lang.en.order @@ -66,9 +70,11 @@ FUNCTION {load.config} #0 'terms.in.macro := #1 'year.after.author := #0 'period.after.author := + #0 'italic.book.title := #1 'sentence.case.title := #0 'link.title := #1 'title.in.journal := + #1 'show.patent.country := #1 'show.mark := #0 'space.before.mark := #1 'show.medium.type := @@ -80,12 +86,14 @@ FUNCTION {load.config} #0 'show.missing.address.publisher := #1 'space.before.pages := #0 'only.start.page := + #0 'wave.dash.in.pages := #1 'show.urldate := #1 'show.url := #1 'show.doi := - #0 'show.preprint := + #1 'show.preprint := #0 'show.note := #0 'show.english.translation := + #1 'end.with.period := #1 'lang.zh.order := #2 'lang.ja.order := #3 'lang.en.order := @@ -341,7 +349,10 @@ FUNCTION {output.check} } FUNCTION {fin.entry} -{ add.period$ +{ end.with.period + 'add.period$ + 'skip$ + if$ write$ show.english.translation entry.lang lang.zh = and { ")" @@ -428,10 +439,18 @@ FUNCTION {field.or.null} if$ } -FUNCTION {italicize} +FUNCTION {emphasize} { duplicate$ empty$ { pop$ "" } - { "\textit{" swap$ * "}" * } + { "\emph{" swap$ * "}" * } + if$ +} + +FUNCTION {format.btitle} +{ italic.book.title + entry.lang lang.en = and + 'emphasize + 'skip$ if$ } @@ -566,7 +585,7 @@ FUNCTION {format.name} { bbl.et.al } { t get.str.lang 'name.lang := name.lang lang.en = - { t #1 "{vv~}{ll}{~f{~}}" format.name$ + { t #1 "{vv~}{ll}{ f{~}}" format.name$ uppercase.name { "u" change.case$ } 'skip$ @@ -756,7 +775,7 @@ FUNCTION {add.link} { url empty$ not { "\href{" url * "}{" * swap$ * "}" * } { doi empty$ not - { "\href{http://dx.doi.org/" doi * "}{" * swap$ * "}" * } + { "\href{https://doi.org/" doi * "}{" * swap$ * "}" * } 'skip$ if$ } @@ -772,7 +791,25 @@ FUNCTION {format.title} 'skip$ if$ entry.numbered number empty$ not and - { bbl.colon * number * } + { bbl.colon * + type$ "patent" = show.patent.country and + { address empty$ not + { address * ", " * } + { location empty$ not + { location * ", " * } + { entry.lang lang.zh = + { "中国" * ", " * } + 'skip$ + if$ + } + if$ + } + if$ + } + 'skip$ + if$ + number * + } 'skip$ if$ link.title @@ -917,6 +954,7 @@ FUNCTION {format.series.vol.num.title} } { format.title.vol.num } if$ + format.btitle link.title 'add.link 'skip$ @@ -948,6 +986,7 @@ FUNCTION {format.series.vol.num.booktitle} } { format.booktitle.vol.num } if$ + format.btitle in.booktitle { duplicate$ empty$ not entry.lang lang.en = and { "In: " swap$ * } @@ -989,16 +1028,15 @@ FUNCTION {abbreviate} if$ } -FUNCTION {format.journal} -{ "" - short.journal +FUNCTION {get.journal.title} +{ short.journal { shortjournal empty$ not - { shortjournal * } + { shortjournal } { journal empty$ not - { journal * abbreviate } + { journal abbreviate } { journaltitle empty$ not - { journaltitle * abbreviate } - 'skip$ + { journaltitle abbreviate } + { "" } if$ } if$ @@ -1006,18 +1044,33 @@ FUNCTION {format.journal} if$ } { journal empty$ not - { journal * } + { journal } { journaltitle empty$ not - { journaltitle * } - 'skip$ + { journaltitle } + { shortjournal empty$ not + { shortjournal } + { "" } + if$ + } if$ } if$ } if$ +} + +FUNCTION {check.arxiv.preprint} +{ #1 #5 substring$ "l" change.case$ "arxiv" = + { #1 } + { #0 } + if$ +} + +FUNCTION {format.journal} +{ get.journal.title duplicate$ empty$ not { italic.journal entry.lang lang.en = and - 'italicize + 'emphasize 'skip$ if$ } @@ -1092,7 +1145,7 @@ FUNCTION {format.edition} { edition change.sentence.case 's := s "Revised" = s "Revised edition" = or { "Rev. ed." } - { s " ed." *} + { s " ed." * } if$ } { edition } @@ -1282,11 +1335,16 @@ FUNCTION {format.periodical.year} } FUNCTION {format.date} -{ type$ "patent" = type$ "newspaper" = or - date empty$ not and - { date } - { year field.or.null - extra.label * +{ date empty$ not + { type$ "patent" = type$ "newspaper" = or + { date } + { format.year } + if$ + } + { year empty$ not + { format.year } + { "" } + if$ } if$ } @@ -1299,9 +1357,9 @@ FUNCTION {format.editdate} } FUNCTION {format.urldate} -{ urldate empty$ not - show.urldate show.url and is.pure.electronic or and - url empty$ not and +{ show.urldate show.url and entry.url empty$ not and + is.pure.electronic or + urldate empty$ not and { "\allowbreak[" urldate * "]" * } { "" } if$ @@ -1312,7 +1370,10 @@ FUNCTION {hyphenate} "" { t empty$ not } { t #1 #1 substring$ "-" = - { "-" * + { wave.dash.in.pages + { "~" * } + { "-" * } + if$ { t #1 #1 substring$ "-" = } { t #2 global.max$ substring$ 't := } while$ @@ -1432,12 +1493,9 @@ FUNCTION {check.url} if$ } -FUNCTION {format.url} -{ entry.url -} - FUNCTION {output.url} -{ entry.url empty$ not +{ show.url is.pure.electronic or + entry.url empty$ not and { new.block entry.url output } @@ -1538,9 +1596,9 @@ FUNCTION {check.electronic} } FUNCTION {format.eprint} -{ eprinttype empty$ not - { eprinttype } - { archivePrefix empty$ not +{ archivePrefix empty$ not + { archivePrefix } + { eprinttype empty$ not { archivePrefix } { "" } if$ @@ -1731,7 +1789,7 @@ FUNCTION {periodical} fin.entry } -FUNCTION {article} +FUNCTION {journal.article} { output.bibitem output.translation format.authors output @@ -1865,7 +1923,7 @@ FUNCTION {preprint} new.block title.in.journal { format.series.vol.num.title "title" output.check - "Z" set.entry.mark + "A" set.entry.mark format.mark "" output.after new.block } @@ -1875,13 +1933,18 @@ FUNCTION {preprint} new.sentence format.edition output new.block - output.eprint year.after.author not - { format.year "year" output.check } + { date empty$ + { format.date output } + 'skip$ + if$ + } 'skip$ if$ format.pages bbl.pages.colon output.after + format.editdate "" output.after format.urldate "" output.after + output.eprint output.url new.block format.note output @@ -1889,13 +1952,19 @@ FUNCTION {preprint} } FUNCTION {misc} -{ journal empty$ not - 'article - { booktitle empty$ not +{ get.journal.title + duplicate$ empty$ not + { check.arxiv.preprint + 'preprint + 'journal.article + if$ + } + { pop$ + booktitle empty$ not 'incollection { publisher empty$ not 'monograph - { eprint empty$ not show.preprint and + { eprint empty$ not archivePrefix empty$ not or 'preprint { entry.is.electronic 'electronic @@ -1920,6 +1989,8 @@ FUNCTION {archive} misc } +FUNCTION {article} { misc } + FUNCTION {book} { monograph } FUNCTION {booklet} { book } @@ -1948,6 +2019,8 @@ FUNCTION {inproceedings} FUNCTION {conference} { inproceedings } +FUNCTION {legislation} { archive } + FUNCTION {map} { "CM" set.entry.mark misc @@ -2407,25 +2480,42 @@ FUNCTION {presort} 'sort.key$ := } -STRINGS { longest.label last.label next.extra } +STRINGS { longest.label last.label next.extra last.extra.label } -INTEGERS { longest.label.width last.extra.num number.label } +INTEGERS { longest.label.width number.label } FUNCTION {initialize.longest.label} { "" 'longest.label := #0 int.to.chr$ 'last.label := "" 'next.extra := #0 'longest.label.width := - #0 'last.extra.num := #0 'number.label := + "" 'last.extra.label := } FUNCTION {forward.pass} -{ last.label short.label = - { last.extra.num #1 + 'last.extra.num := - last.extra.num int.to.chr$ 'extra.label := +{ + last.label short.label = + { "" 'extra.label := + last.extra.label text.length$ 'charptr := + { last.extra.label charptr #1 substring$ "z" = + charptr #0 > and + } + { "a" extra.label * 'extra.label := + charptr #1 - 'charptr := + } + while$ + charptr #0 > + { last.extra.label charptr #1 substring$ chr.to.int$ #1 + int.to.chr$ + extra.label * 'extra.label := + last.extra.label #1 charptr #1 - substring$ + extra.label * 'extra.label := + } + { "a" extra.label * 'extra.label := } + if$ + extra.label 'last.extra.label := } - { "a" chr.to.int$ 'last.extra.num := + { "a" 'last.extra.label := "" 'extra.label := short.label 'last.label := } @@ -2434,7 +2524,8 @@ FUNCTION {forward.pass} } FUNCTION {reverse.pass} -{ next.extra "b" = +{ + next.extra "b" = { "a" 'extra.label := } 'skip$ if$ diff --git a/macros/latex/contrib/thuthesis/thuthesis-bachelor.bst b/macros/latex/contrib/thuthesis/thuthesis-bachelor.bst index 5c08210cb3..78c81e628b 100644 --- a/macros/latex/contrib/thuthesis/thuthesis-bachelor.bst +++ b/macros/latex/contrib/thuthesis/thuthesis-bachelor.bst @@ -4,11 +4,11 @@ %% %% The original source files were: %% -%% gbt7714.dtx (with options: `2015,numerical,noslsn') +%% gbt7714.dtx (with options: `2015,numerical') %% ------------------------------------------------------------------- %% GB/T 7714—2015 BibTeX Style -%% https://github.com/CTeX-org/gbt7714-bibtex-style -%% Version: 2021/04/03 v2.1.1 +%% https://github.com/zepinglee/gbt7714-bibtex-style +%% Version: 2021/12/08 v2.1.3 %% ------------------------------------------------------------------- %% Copyright (C) 2016—2021 by Zeping Lee <zepinglee AT gmail.com> %% ------------------------------------------------------------------- @@ -29,9 +29,11 @@ INTEGERS { terms.in.macro year.after.author period.after.author + italic.book.title sentence.case.title link.title title.in.journal + show.patent.country show.mark space.before.mark show.medium.type @@ -43,12 +45,14 @@ INTEGERS { show.missing.address.publisher space.before.pages only.start.page + wave.dash.in.pages show.urldate show.url show.doi show.preprint show.note show.english.translation + end.with.period } FUNCTION {load.config} @@ -61,9 +65,11 @@ FUNCTION {load.config} #0 'terms.in.macro := #0 'year.after.author := #1 'period.after.author := + #0 'italic.book.title := #1 'sentence.case.title := #0 'link.title := #1 'title.in.journal := + #0 'show.patent.country := #1 'show.mark := #0 'space.before.mark := #1 'show.medium.type := @@ -75,12 +81,14 @@ FUNCTION {load.config} #0 'show.missing.address.publisher := #1 'space.before.pages := #0 'only.start.page := + #0 'wave.dash.in.pages := #1 'show.urldate := #1 'show.url := #1 'show.doi := - #0 'show.preprint := + #1 'show.preprint := #0 'show.note := #0 'show.english.translation := + #1 'end.with.period := } ENTRY @@ -331,7 +339,10 @@ FUNCTION {output.check} } FUNCTION {fin.entry} -{ add.period$ +{ end.with.period + 'add.period$ + 'skip$ + if$ write$ show.english.translation entry.lang lang.zh = and { ")" @@ -418,10 +429,18 @@ FUNCTION {field.or.null} if$ } -FUNCTION {italicize} +FUNCTION {emphasize} { duplicate$ empty$ { pop$ "" } - { "\textit{" swap$ * "}" * } + { "\emph{" swap$ * "}" * } + if$ +} + +FUNCTION {format.btitle} +{ italic.book.title + entry.lang lang.en = and + 'emphasize + 'skip$ if$ } @@ -556,7 +575,7 @@ FUNCTION {format.name} { bbl.et.al } { t get.str.lang 'name.lang := name.lang lang.en = - { t #1 "{vv~}{ll}{~f{~}}" format.name$ + { t #1 "{vv~}{ll}{ f{~}}" format.name$ uppercase.name { "u" change.case$ } 'skip$ @@ -746,7 +765,7 @@ FUNCTION {add.link} { url empty$ not { "\href{" url * "}{" * swap$ * "}" * } { doi empty$ not - { "\href{http://dx.doi.org/" doi * "}{" * swap$ * "}" * } + { "\href{https://doi.org/" doi * "}{" * swap$ * "}" * } 'skip$ if$ } @@ -762,7 +781,25 @@ FUNCTION {format.title} 'skip$ if$ entry.numbered number empty$ not and - { bbl.colon * number * } + { bbl.colon * + type$ "patent" = show.patent.country and + { address empty$ not + { address * ", " * } + { location empty$ not + { location * ", " * } + { entry.lang lang.zh = + { "中国" * ", " * } + 'skip$ + if$ + } + if$ + } + if$ + } + 'skip$ + if$ + number * + } 'skip$ if$ link.title @@ -907,6 +944,7 @@ FUNCTION {format.series.vol.num.title} } { format.title.vol.num } if$ + format.btitle link.title 'add.link 'skip$ @@ -938,6 +976,7 @@ FUNCTION {format.series.vol.num.booktitle} } { format.booktitle.vol.num } if$ + format.btitle in.booktitle { duplicate$ empty$ not entry.lang lang.en = and { "In: " swap$ * } @@ -979,16 +1018,15 @@ FUNCTION {abbreviate} if$ } -FUNCTION {format.journal} -{ "" - short.journal +FUNCTION {get.journal.title} +{ short.journal { shortjournal empty$ not - { shortjournal * } + { shortjournal } { journal empty$ not - { journal * abbreviate } + { journal abbreviate } { journaltitle empty$ not - { journaltitle * abbreviate } - 'skip$ + { journaltitle abbreviate } + { "" } if$ } if$ @@ -996,18 +1034,33 @@ FUNCTION {format.journal} if$ } { journal empty$ not - { journal * } + { journal } { journaltitle empty$ not - { journaltitle * } - 'skip$ + { journaltitle } + { shortjournal empty$ not + { shortjournal } + { "" } + if$ + } if$ } if$ } if$ +} + +FUNCTION {check.arxiv.preprint} +{ #1 #5 substring$ "l" change.case$ "arxiv" = + { #1 } + { #0 } + if$ +} + +FUNCTION {format.journal} +{ get.journal.title duplicate$ empty$ not { italic.journal entry.lang lang.en = and - 'italicize + 'emphasize 'skip$ if$ } @@ -1082,7 +1135,7 @@ FUNCTION {format.edition} { edition change.sentence.case 's := s "Revised" = s "Revised edition" = or { "Rev. ed." } - { s " ed." *} + { s " ed." * } if$ } { edition } @@ -1272,11 +1325,16 @@ FUNCTION {format.periodical.year} } FUNCTION {format.date} -{ type$ "patent" = type$ "newspaper" = or - date empty$ not and - { date } - { year field.or.null - extra.label * +{ date empty$ not + { type$ "patent" = type$ "newspaper" = or + { date } + { format.year } + if$ + } + { year empty$ not + { format.year } + { "" } + if$ } if$ } @@ -1289,9 +1347,9 @@ FUNCTION {format.editdate} } FUNCTION {format.urldate} -{ urldate empty$ not - show.urldate show.url and is.pure.electronic or and - url empty$ not and +{ show.urldate show.url and entry.url empty$ not and + is.pure.electronic or + urldate empty$ not and { "\allowbreak[" urldate * "]" * } { "" } if$ @@ -1302,7 +1360,10 @@ FUNCTION {hyphenate} "" { t empty$ not } { t #1 #1 substring$ "-" = - { "-" * + { wave.dash.in.pages + { "~" * } + { "-" * } + if$ { t #1 #1 substring$ "-" = } { t #2 global.max$ substring$ 't := } while$ @@ -1422,12 +1483,9 @@ FUNCTION {check.url} if$ } -FUNCTION {format.url} -{ entry.url -} - FUNCTION {output.url} -{ entry.url empty$ not +{ show.url is.pure.electronic or + entry.url empty$ not and { new.block entry.url output } @@ -1528,9 +1586,9 @@ FUNCTION {check.electronic} } FUNCTION {format.eprint} -{ eprinttype empty$ not - { eprinttype } - { archivePrefix empty$ not +{ archivePrefix empty$ not + { archivePrefix } + { eprinttype empty$ not { archivePrefix } { "" } if$ @@ -1721,7 +1779,7 @@ FUNCTION {periodical} fin.entry } -FUNCTION {article} +FUNCTION {journal.article} { output.bibitem output.translation format.authors output @@ -1855,7 +1913,7 @@ FUNCTION {preprint} new.block title.in.journal { format.series.vol.num.title "title" output.check - "Z" set.entry.mark + "A" set.entry.mark format.mark "" output.after new.block } @@ -1865,13 +1923,18 @@ FUNCTION {preprint} new.sentence format.edition output new.block - output.eprint year.after.author not - { format.year "year" output.check } + { date empty$ + { format.date output } + 'skip$ + if$ + } 'skip$ if$ format.pages bbl.pages.colon output.after + format.editdate "" output.after format.urldate "" output.after + output.eprint output.url new.block format.note output @@ -1879,13 +1942,19 @@ FUNCTION {preprint} } FUNCTION {misc} -{ journal empty$ not - 'article - { booktitle empty$ not +{ get.journal.title + duplicate$ empty$ not + { check.arxiv.preprint + 'preprint + 'journal.article + if$ + } + { pop$ + booktitle empty$ not 'incollection { publisher empty$ not 'monograph - { eprint empty$ not show.preprint and + { eprint empty$ not archivePrefix empty$ not or 'preprint { entry.is.electronic 'electronic @@ -1910,6 +1979,8 @@ FUNCTION {archive} misc } +FUNCTION {article} { misc } + FUNCTION {book} { monograph } FUNCTION {booklet} { book } @@ -1938,6 +2009,8 @@ FUNCTION {inproceedings} FUNCTION {conference} { inproceedings } +FUNCTION {legislation} { archive } + FUNCTION {map} { "CM" set.entry.mark misc @@ -2248,44 +2321,26 @@ FUNCTION {presort} 'sort.key$ := } -STRINGS { longest.label last.label next.extra } +STRINGS { longest.label last.label next.extra last.extra.label } -INTEGERS { longest.label.width last.extra.num number.label } +INTEGERS { longest.label.width number.label } FUNCTION {initialize.longest.label} { "" 'longest.label := #0 int.to.chr$ 'last.label := "" 'next.extra := #0 'longest.label.width := - #0 'last.extra.num := #0 'number.label := + "" 'last.extra.label := } FUNCTION {forward.pass} -{ last.label short.label = - { last.extra.num #1 + 'last.extra.num := - last.extra.num int.to.chr$ 'extra.label := - } - { "a" chr.to.int$ 'last.extra.num := - "" 'extra.label := - short.label 'last.label := - } - if$ +{ number.label #1 + 'number.label := } FUNCTION {reverse.pass} -{ next.extra "b" = - { "a" 'extra.label := } - 'skip$ - if$ - extra.label 'next.extra := - extra.label - duplicate$ empty$ - 'skip$ - { "{\natexlab{" swap$ * "}}" * } - if$ - 'extra.label := +{ label extra.label * 'label := } diff --git a/macros/latex/contrib/thuthesis/thuthesis-example.pdf b/macros/latex/contrib/thuthesis/thuthesis-example.pdf Binary files differindex a881f81a4a..b25df293c9 100644 --- a/macros/latex/contrib/thuthesis/thuthesis-example.pdf +++ b/macros/latex/contrib/thuthesis/thuthesis-example.pdf diff --git a/macros/latex/contrib/thuthesis/thuthesis-example.tex b/macros/latex/contrib/thuthesis/thuthesis-example.tex index 7e6f698ca2..39edf3af3e 100644 --- a/macros/latex/contrib/thuthesis/thuthesis-example.tex +++ b/macros/latex/contrib/thuthesis/thuthesis-example.tex @@ -24,6 +24,7 @@ \maketitle % 学位论文指导小组、公开评阅人和答辩委员会名单 +% 本科生不需要 \input{data/committee} % 使用授权的说明 @@ -39,9 +40,9 @@ % 插图和附表清单 % 本科生的插图索引和表格索引需要移至正文之后、参考文献前 -\listoffiguresandtables % 插图和附表清单 -% \listoffigures % 插图清单 -% \listoftables % 附表清单 +% \listoffiguresandtables % 插图和附表清单(仅限研究生) +\listoffigures % 插图清单 +\listoftables % 附表清单 % 符号对照表 \input{data/denotation} @@ -63,6 +64,7 @@ % \printbibliography % 参考文献使用 BibLaTeX 编译 % 附录 +% 本科生需要将附录放到声明之后,个人简历之前 \appendix % \input{data/appendix-survey} % 本科生:外文资料的调研阅读报告 % \input{data/appendix-translation} % 本科生:外文资料的书面翻译 @@ -82,12 +84,15 @@ % \statement[file=scan-statement.pdf, page-style=plain] % 个人简历、在学期间完成的相关学术成果 +% 本科生可以附个人简历,也可以不附个人简历 \input{data/resume} % 指导教师/指导小组学术评语 +% 本科生不需要 \input{data/comments} % 答辩委员会决议书 +% 本科生不需要 \input{data/resolution} % 本科生的综合论文训练记录表(扫描版) diff --git a/macros/latex/contrib/thuthesis/thuthesis-numeric.bbx b/macros/latex/contrib/thuthesis/thuthesis-numeric.bbx index f0d6234eff..fb7dcdff68 100644 --- a/macros/latex/contrib/thuthesis/thuthesis-numeric.bbx +++ b/macros/latex/contrib/thuthesis/thuthesis-numeric.bbx @@ -25,3 +25,33 @@ \renewcommand*{\makelabel}[1]{\hss##1}} {\endlist} {\item} + +% +% 重设专利title的输出,将文献类型标识符输出出去 +% +\renewbibmacro*{patenttitle}{%原输出来自biblatex.def文件 + \ifboolexpr{% + test{\iffieldundef{title}}% + and% + test{\iffieldundef{subtitle}}% + }% + {}% + {\printtext[title]{\bibtitlefont% + \printfield[titlecase]{title}% + \ifboolexpr{test {\iffieldundef{subtitle}}} + {}{\setunit{\subtitlepunct}% + \printfield[titlecase]{subtitle}}% + \iffieldundef{titleaddon}{} + {\setunit{\subtitlepunct}\printfield{titleaddon}}% + % \setunit{\subtitlepunct}\printfield{number}%写专利号 + \setunit{\subtitlepunct}% + \iflistundef{location}{} + {\printlist{location}\setunit{\addcomma\space}}% 专利国别 + \printfield{number}%写专利号 + \iftoggle{bbx:gbtype}{\printfield[gbtypeflag]{usera}}{}% + %\iffieldundef{booktitle}{\newunit}{}%当title是析出时,不要标点 + %\newunit + }% +}% +\clearlist{location}\clearlist{address}% +} diff --git a/macros/latex/contrib/thuthesis/thuthesis-numeric.bst b/macros/latex/contrib/thuthesis/thuthesis-numeric.bst index 9f57d5ed57..0b41d73140 100644 --- a/macros/latex/contrib/thuthesis/thuthesis-numeric.bst +++ b/macros/latex/contrib/thuthesis/thuthesis-numeric.bst @@ -7,8 +7,8 @@ %% gbt7714.dtx (with options: `2015,thu,numerical') %% ------------------------------------------------------------------- %% GB/T 7714—2015 BibTeX Style -%% https://github.com/CTeX-org/gbt7714-bibtex-style -%% Version: 2021/04/03 v2.1.1 +%% https://github.com/zepinglee/gbt7714-bibtex-style +%% Version: 2021/12/08 v2.1.3 %% ------------------------------------------------------------------- %% Copyright (C) 2016—2021 by Zeping Lee <zepinglee AT gmail.com> %% ------------------------------------------------------------------- @@ -29,9 +29,11 @@ INTEGERS { terms.in.macro year.after.author period.after.author + italic.book.title sentence.case.title link.title title.in.journal + show.patent.country show.mark space.before.mark show.medium.type @@ -43,12 +45,14 @@ INTEGERS { show.missing.address.publisher space.before.pages only.start.page + wave.dash.in.pages show.urldate show.url show.doi show.preprint show.note show.english.translation + end.with.period } FUNCTION {load.config} @@ -61,9 +65,11 @@ FUNCTION {load.config} #0 'terms.in.macro := #0 'year.after.author := #1 'period.after.author := + #0 'italic.book.title := #1 'sentence.case.title := #0 'link.title := #1 'title.in.journal := + #1 'show.patent.country := #1 'show.mark := #0 'space.before.mark := #1 'show.medium.type := @@ -75,12 +81,14 @@ FUNCTION {load.config} #0 'show.missing.address.publisher := #1 'space.before.pages := #0 'only.start.page := + #0 'wave.dash.in.pages := #1 'show.urldate := #1 'show.url := #1 'show.doi := - #0 'show.preprint := + #1 'show.preprint := #0 'show.note := #0 'show.english.translation := + #1 'end.with.period := } ENTRY @@ -331,7 +339,10 @@ FUNCTION {output.check} } FUNCTION {fin.entry} -{ add.period$ +{ end.with.period + 'add.period$ + 'skip$ + if$ write$ show.english.translation entry.lang lang.zh = and { ")" @@ -418,10 +429,18 @@ FUNCTION {field.or.null} if$ } -FUNCTION {italicize} +FUNCTION {emphasize} { duplicate$ empty$ { pop$ "" } - { "\textit{" swap$ * "}" * } + { "\emph{" swap$ * "}" * } + if$ +} + +FUNCTION {format.btitle} +{ italic.book.title + entry.lang lang.en = and + 'emphasize + 'skip$ if$ } @@ -556,7 +575,7 @@ FUNCTION {format.name} { bbl.et.al } { t get.str.lang 'name.lang := name.lang lang.en = - { t #1 "{vv~}{ll}{~f{~}}" format.name$ + { t #1 "{vv~}{ll}{ f{~}}" format.name$ uppercase.name { "u" change.case$ } 'skip$ @@ -746,7 +765,7 @@ FUNCTION {add.link} { url empty$ not { "\href{" url * "}{" * swap$ * "}" * } { doi empty$ not - { "\href{http://dx.doi.org/" doi * "}{" * swap$ * "}" * } + { "\href{https://doi.org/" doi * "}{" * swap$ * "}" * } 'skip$ if$ } @@ -762,7 +781,25 @@ FUNCTION {format.title} 'skip$ if$ entry.numbered number empty$ not and - { bbl.colon * number * } + { bbl.colon * + type$ "patent" = show.patent.country and + { address empty$ not + { address * ", " * } + { location empty$ not + { location * ", " * } + { entry.lang lang.zh = + { "中国" * ", " * } + 'skip$ + if$ + } + if$ + } + if$ + } + 'skip$ + if$ + number * + } 'skip$ if$ link.title @@ -907,6 +944,7 @@ FUNCTION {format.series.vol.num.title} } { format.title.vol.num } if$ + format.btitle link.title 'add.link 'skip$ @@ -938,6 +976,7 @@ FUNCTION {format.series.vol.num.booktitle} } { format.booktitle.vol.num } if$ + format.btitle in.booktitle { duplicate$ empty$ not entry.lang lang.en = and { "In: " swap$ * } @@ -979,16 +1018,15 @@ FUNCTION {abbreviate} if$ } -FUNCTION {format.journal} -{ "" - short.journal +FUNCTION {get.journal.title} +{ short.journal { shortjournal empty$ not - { shortjournal * } + { shortjournal } { journal empty$ not - { journal * abbreviate } + { journal abbreviate } { journaltitle empty$ not - { journaltitle * abbreviate } - 'skip$ + { journaltitle abbreviate } + { "" } if$ } if$ @@ -996,18 +1034,33 @@ FUNCTION {format.journal} if$ } { journal empty$ not - { journal * } + { journal } { journaltitle empty$ not - { journaltitle * } - 'skip$ + { journaltitle } + { shortjournal empty$ not + { shortjournal } + { "" } + if$ + } if$ } if$ } if$ +} + +FUNCTION {check.arxiv.preprint} +{ #1 #5 substring$ "l" change.case$ "arxiv" = + { #1 } + { #0 } + if$ +} + +FUNCTION {format.journal} +{ get.journal.title duplicate$ empty$ not { italic.journal entry.lang lang.en = and - 'italicize + 'emphasize 'skip$ if$ } @@ -1082,7 +1135,7 @@ FUNCTION {format.edition} { edition change.sentence.case 's := s "Revised" = s "Revised edition" = or { "Rev. ed." } - { s " ed." *} + { s " ed." * } if$ } { edition } @@ -1272,11 +1325,16 @@ FUNCTION {format.periodical.year} } FUNCTION {format.date} -{ type$ "patent" = type$ "newspaper" = or - date empty$ not and - { date } - { year field.or.null - extra.label * +{ date empty$ not + { type$ "patent" = type$ "newspaper" = or + { date } + { format.year } + if$ + } + { year empty$ not + { format.year } + { "" } + if$ } if$ } @@ -1289,9 +1347,9 @@ FUNCTION {format.editdate} } FUNCTION {format.urldate} -{ urldate empty$ not - show.urldate show.url and is.pure.electronic or and - url empty$ not and +{ show.urldate show.url and entry.url empty$ not and + is.pure.electronic or + urldate empty$ not and { "\allowbreak[" urldate * "]" * } { "" } if$ @@ -1302,7 +1360,10 @@ FUNCTION {hyphenate} "" { t empty$ not } { t #1 #1 substring$ "-" = - { "-" * + { wave.dash.in.pages + { "~" * } + { "-" * } + if$ { t #1 #1 substring$ "-" = } { t #2 global.max$ substring$ 't := } while$ @@ -1422,12 +1483,9 @@ FUNCTION {check.url} if$ } -FUNCTION {format.url} -{ entry.url -} - FUNCTION {output.url} -{ entry.url empty$ not +{ show.url is.pure.electronic or + entry.url empty$ not and { new.block entry.url output } @@ -1528,9 +1586,9 @@ FUNCTION {check.electronic} } FUNCTION {format.eprint} -{ eprinttype empty$ not - { eprinttype } - { archivePrefix empty$ not +{ archivePrefix empty$ not + { archivePrefix } + { eprinttype empty$ not { archivePrefix } { "" } if$ @@ -1721,7 +1779,7 @@ FUNCTION {periodical} fin.entry } -FUNCTION {article} +FUNCTION {journal.article} { output.bibitem output.translation format.authors output @@ -1855,7 +1913,7 @@ FUNCTION {preprint} new.block title.in.journal { format.series.vol.num.title "title" output.check - "Z" set.entry.mark + "A" set.entry.mark format.mark "" output.after new.block } @@ -1865,13 +1923,18 @@ FUNCTION {preprint} new.sentence format.edition output new.block - output.eprint year.after.author not - { format.year "year" output.check } + { date empty$ + { format.date output } + 'skip$ + if$ + } 'skip$ if$ format.pages bbl.pages.colon output.after + format.editdate "" output.after format.urldate "" output.after + output.eprint output.url new.block format.note output @@ -1879,13 +1942,19 @@ FUNCTION {preprint} } FUNCTION {misc} -{ journal empty$ not - 'article - { booktitle empty$ not +{ get.journal.title + duplicate$ empty$ not + { check.arxiv.preprint + 'preprint + 'journal.article + if$ + } + { pop$ + booktitle empty$ not 'incollection { publisher empty$ not 'monograph - { eprint empty$ not show.preprint and + { eprint empty$ not archivePrefix empty$ not or 'preprint { entry.is.electronic 'electronic @@ -1910,6 +1979,8 @@ FUNCTION {archive} misc } +FUNCTION {article} { misc } + FUNCTION {book} { monograph } FUNCTION {booklet} { book } @@ -1938,6 +2009,8 @@ FUNCTION {inproceedings} FUNCTION {conference} { inproceedings } +FUNCTION {legislation} { archive } + FUNCTION {map} { "CM" set.entry.mark misc @@ -2248,44 +2321,26 @@ FUNCTION {presort} 'sort.key$ := } -STRINGS { longest.label last.label next.extra } +STRINGS { longest.label last.label next.extra last.extra.label } -INTEGERS { longest.label.width last.extra.num number.label } +INTEGERS { longest.label.width number.label } FUNCTION {initialize.longest.label} { "" 'longest.label := #0 int.to.chr$ 'last.label := "" 'next.extra := #0 'longest.label.width := - #0 'last.extra.num := #0 'number.label := + "" 'last.extra.label := } FUNCTION {forward.pass} -{ last.label short.label = - { last.extra.num #1 + 'last.extra.num := - last.extra.num int.to.chr$ 'extra.label := - } - { "a" chr.to.int$ 'last.extra.num := - "" 'extra.label := - short.label 'last.label := - } - if$ +{ number.label #1 + 'number.label := } FUNCTION {reverse.pass} -{ next.extra "b" = - { "a" 'extra.label := } - 'skip$ - if$ - extra.label 'next.extra := - extra.label - duplicate$ empty$ - 'skip$ - { "{\natexlab{" swap$ * "}}" * } - if$ - 'extra.label := +{ label extra.label * 'label := } diff --git a/macros/latex/contrib/thuthesis/thuthesis.dtx b/macros/latex/contrib/thuthesis/thuthesis.dtx index 3233b5e580..f2a48c8a13 100644 --- a/macros/latex/contrib/thuthesis/thuthesis.dtx +++ b/macros/latex/contrib/thuthesis/thuthesis.dtx @@ -14,7 +14,7 @@ % % \iffalse %<*driver> -\ProvidesFile{thuthesis.dtx}[2021/05/31 7.2.3 Tsinghua University Thesis Template] +\ProvidesFile{thuthesis.dtx}[2022/03/19 7.2.4 Tsinghua University Thesis Template] \documentclass{ltxdoc} \usepackage{dtx-style} @@ -74,10 +74,10 @@ % \item 本模板为作者根据 % 清华大学研究生院颁发的《 % \href{http://yjsy.cic.tsinghua.edu.cn/docinfo/board/boarddetail.jsp?columnId=001050603&parentColumnId=0010506&itemSeq=5365}{% -% 研究生学位论文写作指南}》(限校内网络访问)、 +% 研究生学位论文写作指南}》(2021年6月版本,限校内网络访问)、 % 英文版《Guide to Thesis Writing for Graduate Students》、 % 清华大学教务处颁发的《 -% \href{https://lib.tsinghua.edu.cn/dra/news/annoucement/7963}{% +% \href{https://lib.tsinghua.edu.cn/info/1073/1978.htm}{% % 综合论文训练写作指南}》、 % 外文系的《英语专业本科生综合论文训练》和 % 清华大学《 @@ -260,7 +260,7 @@ % \end{shell} % % 在调用 \XeLaTeX 时,如果设置了 \option{include-spine} 选项, -% 则需要在文件名前加上 \texttt{-shell-scape} 的命令行选项。 +% 则需要在文件名前加上 \texttt{-shell-escape} 的命令行选项。 % % 下面的命令用来生成用户手册: % \begin{shell} @@ -852,10 +852,10 @@ % 可能会造成正文和公式中的数字字体不一致,需要谨慎使用。 % % 以上字体都是 OpenType 格式的字体,需要配合 -% \href{http://mirrors.ctan.org/macros/latex/contrib/unicode-math/unicode-math.pdf}{\pkg{unicode-math}} +% \href{http://mirrors.ctan.org/macros/unicodetex/latex/unicode-math/unicode-math.pdf}{\pkg{unicode-math}} % 宏包使用。 % 全部数学符号的命令参考 -% \href{http://mirrors.ctan.org/macros/latex/contrib/unicode-math/unimath-symbols.pdf}{\pkg{unimath-symbols}}。 +% \href{http://mirrors.ctan.org/macros/unicodetex/latex/unicode-math/unimath-symbols.pdf}{\pkg{unimath-symbols}}。 % 注意,\pkg{unicode-math} 宏包与 \pkg{amsfonts}、\pkg{amssymb}、\pkg{bm}、 % \pkg{mathrsfs}、\pkg{upgreek} 等宏包\emph{不}兼容。 % 模板作了处理,用户可以直接使用这些宏包的命令,如 \cs{bm}、\cs{mathscr}、 @@ -1009,7 +1009,7 @@ % \end{latex} % 另一种方式是使用 biblatex,应在导言区设置 % \begin{latex} -% \usepackage[backend=biber,style=thuthesis-author-year]{biblatex} +% \usepackage[style=thuthesis-author-year]{biblatex} % \addbibresource{ref/refs.bib} % \end{latex} % 这里的样式由 \href{https://ctan.org/pkg/biblatex-gb7714-2015}{biblatex-gb7714-2015} 进行了少量改编, @@ -1082,12 +1082,12 @@ % 研究生不存在空白页的问题,在编译生成声明时默认加页眉页脚(\option{plain}), % 而插入扫描版时不再重复(\option{empty})。 % -% 声明的页眉页脚也可以通过 \option{pagestyle} 参数手动控制, +% 声明的页眉页脚也可以通过 \option{page-style} 参数手动控制, % 比如编译生成时固定不加页眉页脚: % \begin{latex} -% \statement[page-style=plain] +% \statement[page-style=empty] % \end{latex} -% 插入扫面版声明补上页眉页脚: +% 插入扫描版声明补上页眉页脚: % \begin{latex} % \statement[file=scan-statement.pdf, page-style=plain] % \end{latex} @@ -1250,7 +1250,7 @@ % \begin{macrocode} %<cls>\NeedsTeXFormat{LaTeX2e}[2017/04/15] %<cls>\ProvidesClass{thuthesis} -%<cls>[2021/05/31 7.2.3 Tsinghua University Thesis Template] +%<cls>[2022/03/19 7.2.4 Tsinghua University Thesis Template] % \end{macrocode} % % 报错 @@ -1306,7 +1306,7 @@ %<*cls> \hyphenation{Thu-Thesis} \def\thuthesis{ThuThesis} -\def\version{7.2.3} +\def\version{7.2.4} \RequirePackage{kvdefinekeys} \RequirePackage{kvsetkeys} \RequirePackage{kvoptions} @@ -1731,9 +1731,20 @@ % \end{macrocode} % % \pkg{pdfpages} 宏包便于我们插入扫描后的授权说明和声明页 PDF 文档。 +% +% 由于 \pkg{pdfpages} 跟 \pkg{TikZ} 的 \pkg{external} 库冲突, +% 需要在导言区的结尾进行处理,见 +% \href{https://github.com/tuna/thuthesis/issues/693}{\#693}。 % \begin{macrocode} \RequirePackage{pdfpages} \includepdfset{fitpaper=true} +\AtEndPreamble{ + \ifx\tikzifexternalizing\@undefined\else + \tikzifexternalizing{ + \renewcommand*\includepdf[2][]{} + }{} + \fi +} % \end{macrocode} % % 更好的列表环境。 @@ -1784,9 +1795,11 @@ } } \AtEndOfPackageFile*{natbib}{ - \@ifpackageloaded{apacite}{}{ - \RequirePackage{bibunits} - } + \ifthu@degree@bachelor + \@ifpackageloaded{apacite}{}{ + \RequirePackage{bibunits} + } + \fi } % \end{macrocode} % @@ -1829,16 +1842,6 @@ \thu@package@conflict{newtxmath}{upgreek} % \end{macrocode} % -% \pkg{mathtools} 需要在 \pkg{unicode-math} 前载入, -% 参考 \url{https://tex.stackexchange.com/q/521394/82731}。 -% \begin{macrocode} -\AtBeginOfPackageFile*{mathtools}{ - \@ifpackageloaded{unicode-math}{ - \thu@error{The "mathtools" package should be loaded before setting "math-font"} - }{} -}% -% \end{macrocode} -% % \pkg{amsthm} 需要在 \pkg{newtx} 前载入,参考 \pkg{newtx} 的文档。 % \begin{macrocode} \AtBeginOfPackageFile*{amsthm}{ @@ -1858,7 +1861,12 @@ % 本科生《写作指南》: % 页边距:上:3.8 厘米,下:3.2 厘米,左右:3 厘米,装订线:左 0.2 厘米。 % 本科生 Word 模板: -% 页眉距边界:1.5 厘米,页脚距边界:1.75 厘米。 +% 无页眉,页脚距边界:1.75 厘米。 +% +% \pkg{fancyhdr} 的页眉是沿底部对齐的,所以只需设置 \cs{headsep}, +% \cs{headheight} 可以适当增加高度允许多行页眉。 +% 研究生:\cs{headsep} = $\SI{3}{cm} - \SI{2.2}{cm} - \SI{10.5}{bp} \times 1.3 +% \approx \SI{0.3}{cm}$。 % % \begin{macrocode} \geometry{ @@ -1873,8 +1881,8 @@ bottom = 3.2cm, left = 3.2cm, right = 3cm, - headheight = 0.5cm, - headsep = 1.8cm, + headheight = 1.9cm, + headsep = 1.9cm, footskip = 1.45cm, }% \ifthu@output@print @@ -1890,7 +1898,7 @@ \else \geometry{ margin = 3cm, - headheight = 0.5cm, + headheight = 2.7cm, headsep = 0.3cm, footskip = 0.8cm, }% @@ -2837,10 +2845,12 @@ \thu@set@stix@names \setmathfont{\thu@font@name@stix@math}[ Extension = .otf, + Scale = MatchLowercase, StylisticSet = \thu@xits@integral@stylistic@set, ]% \setmathfont{\thu@font@name@stix@math}[ Extension = .otf, + Scale = MatchLowercase, StylisticSet = 1, range = {scr,bfscr}, ]% @@ -3079,6 +3089,7 @@ \@mainmattertrue \pagenumbering{arabic}% } +\newif\ifthu@backmatter \renewcommand\backmatter{% \if@openright \cleardoublepage @@ -3086,6 +3097,7 @@ \clearpage \fi \@mainmatterfalse + \thu@backmattertrue \thusetup{toc-depth = 0}% } % \end{macrocode} @@ -3256,7 +3268,7 @@ % \begin{macrocode} \newcommand\thu@circled[1]{% \ifnum#1 >10\relax - \thu@error{% + \thu@warning{% Too many footnotes in this page. Keep footnote less than 10% }% @@ -3366,8 +3378,8 @@ % % 图表浮动体的默认位置设为 |h|。 % \begin{macrocode} -\def\fps@figure{h} -\def\fps@table{h} +\def\fps@figure{htbp} +\def\fps@table{htbp} % \end{macrocode} % % 设置浮动对象和文字之间的距离 @@ -4826,41 +4838,43 @@ % 学位论文指导小组、公开评阅人和答辩委员会名单。 % \begin{macrocode} \def\thu@committee@name{学位论文指导小组、公开评阅人和答辩委员会名单} -\newenvironment{committee}[1][]{% - \cleardoublepage - \let\thu@committee@file\@empty - \kv@define@key{thu@committee}{name}{\let\thu@committee@name\kv@value}% - \kv@define@key{thu@committee}{file}{\let\thu@committee@file\kv@value}% - \kv@set@family@handler{thu@committee}{% - \ifx\kv@value\relax - \let\thu@committee@file\kv@key +\NewEnviron{committee}[1][]{% + \ifthu@degree@graduate + \cleardoublepage + \let\thu@committee@file\@empty + \kv@define@key{thu@committee}{name}{\let\thu@committee@name\kv@value}% + \kv@define@key{thu@committee}{file}{\let\thu@committee@file\kv@value}% + \kv@set@family@handler{thu@committee}{% + \ifx\kv@value\relax + \let\thu@committee@file\kv@key + \else + \kv@handled@false + \fi + }% + \kvsetkeys{thu@committee}{#1}% + \ifx\thu@committee@file\@empty + \begingroup + \ifthu@main@language@english + \ctexset{chapter/format=\centering\sffamily\fontsize{16bp}{20bp}\selectfont} + \fi + \thu@chapter*[]{\thu@committee@name}% + \endgroup \else - \kv@handled@false + \thu@pdfbookmark{0}{\thu@committee@name}% + \includepdf{\thu@committee@file}% \fi - }% - \kvsetkeys{thu@committee}{#1}% - \ifx\thu@committee@file\@empty - \begingroup - \ifthu@main@language@english - \ctexset{chapter/format=\centering\sffamily\fontsize{16bp}{20bp}\selectfont} - \fi - \thu@chapter*[]{\thu@committee@name}% - \endgroup - \else - \thu@pdfbookmark{0}{\thu@committee@name}% - \includepdf{\thu@committee@file}% + \thispagestyle{empty}% + \ctexset{ + section = { + format += {\centering}, + numbering = false, + afterindent = false, + }, + }% + \thusetup{language=chinese} + \BODY\clearpage + \thu@reset@main@language \fi - \thispagestyle{empty}% - \ctexset{ - section = { - format += {\centering}, - numbering = false, - afterindent = false, - }, - }% - \thusetup{language=chinese} -}{% - \thu@reset@main@language } % \end{macrocode} % \end{environment} @@ -4966,7 +4980,7 @@ \centering 签\quad 名:\thu@underline[6em]{}% 导师签名:\thu@underline[6em]{}% - 日\quad 期\thu@underline[6em]{}% + 日\quad 期:\thu@underline[6em]{}% \par \endgroup } @@ -5175,8 +5189,10 @@ Use "page-style" option of \protect\statement command instead% }% } +\newif\ifthu@statement@exists \newcommand\statement[1][]{% \@mainmatterfalse + \thu@statement@existstrue \ifthu@degree@bachelor \cleardoublepage \def\thu@statement@name{声\hspace{2em}明}% @@ -5269,6 +5285,11 @@ % 插图清单。 % \begin{macrocode} \renewcommand\listoffigures{% + \ifthu@degree@bachelor + \ifthu@backmatter\else + \thu@warning{The list of figures should be placed in back matter}% + \fi + \fi \thu@listof{figure}% } \titlecontents{figure} @@ -5284,6 +5305,11 @@ % 附表清单。 % \begin{macrocode} \renewcommand\listoftables{% + \ifthu@degree@bachelor + \ifthu@backmatter\else + \thu@warning{The list of tables should be placed in back matter}% + \fi + \fi \thu@listof{table}% } \titlecontents{table} @@ -5298,11 +5324,17 @@ % 将插图和附表合在一起列出“插图和附表清单”。 % \begin{macrocode} \newcommand\listoffiguresandtables{% - \thu@chapter*{\thu@list@figure@table@name}% - \@starttoc{lof}% - \par - \null\par - \@starttoc{lot}% + \ifthu@degree@bachelor + \thu@warning{The list of figures and tables are for graduates only}% + \listoffigures + \listoftables + \else + \thu@chapter*{\thu@list@figure@table@name}% + \@starttoc{lof}% + \par + \null\par + \@starttoc{lot}% + \fi } % \end{macrocode} % \end{macro} @@ -5794,6 +5826,11 @@ % \begin{macrocode} \g@addto@macro\appendix{% \@mainmattertrue + \ifthu@degree@bachelor + \ifthu@statement@exists\else + \thu@warning{The appendices should be placed after statement}% + \fi + \fi } % \end{macrocode} % @@ -5865,6 +5902,7 @@ \thu@print@contents{survey}{l}{1}{2}{}% \vskip 20bp% }% + \let\appendix\thu@appendix@appendix \renewcommand\bibname{参考文献}% \let\bibsection\thu@appendix@bibsection \renewcommand\@bibunitname{\jobname-survey}% @@ -5907,6 +5945,7 @@ \thu@print@contents{translation}{l}{1}{2}{}% \vskip 20bp% }% + \let\appendix\thu@appendix@appendix \def\bibsection{% \begingroup \ctexset{section/numbering=false}% @@ -5969,6 +6008,16 @@ } % \end{macrocode} % +% 书面翻译的附录。 +% \begin{macrocode} +\newcommand\thu@appendix@appendix{% + \def\theHsection{\Hy@AlphNoErr{section}}% + \setcounter{section}{0}% + \setcounter{subsection}{0}% + \renewcommand\thesection{\thechapter.\@Alph\c@section}% +}% +% \end{macrocode} +% % 调研阅读报告的参考文献(或书面翻译对应的外文资料的原文索引)标题用宋体小四号字,段前 20pt,段后 6pt,行距 20pt。 % \begin{macrocode} \newcommand\thu@appendix@bibsection{% @@ -6061,19 +6110,21 @@ % \subsection{指导教师/小组学术评语} % \begin{environment}{comments} % \begin{macrocode} -\newenvironment{comments}[1][]{% - \@mainmatterfalse - \kv@define@key{thu@comments}{name}{\let\thu@comments@name\kv@value}% - \kv@set@family@handler{thu@comments}{% - \ifx\kv@value\relax - \let\thu@comments@name\kv@key - \else - \kv@handled@false - \fi - }% - \kvsetkeys{thu@comments}{#1}% - \chapter{\thu@comments@name}% -}{% +\NewEnviron{comments}[1][]{% + \ifthu@degree@graduate + \@mainmatterfalse + \kv@define@key{thu@comments}{name}{\let\thu@comments@name\kv@value}% + \kv@set@family@handler{thu@comments}{% + \ifx\kv@value\relax + \let\thu@comments@name\kv@key + \else + \kv@handled@false + \fi + }% + \kvsetkeys{thu@comments}{#1}% + \chapter{\thu@comments@name}% + \BODY\clearpage + \fi } % \end{macrocode} % \end{environment} @@ -6081,10 +6132,13 @@ % \subsection{答辩委员会决议书} % \begin{environment}{resolution} % \begin{macrocode} -\newenvironment{resolution}{% - \@mainmatterfalse - \chapter{\thu@resolution@name}% -}{} +\NewEnviron{resolution}{% + \ifthu@degree@graduate + \@mainmatterfalse + \chapter{\thu@resolution@name}% + \BODY\clearpage + \fi +} % \end{macrocode} % \end{environment} % @@ -6150,6 +6204,7 @@ \pdfstringdefDisableCommands{ \let\\\relax \let\quad\relax + \let\qquad\relax \let\hspace\@gobble }% % \end{macrocode} @@ -6195,6 +6250,20 @@ } % \end{macrocode} % +% \subsubsection{\pkg{mathtools} 宏包} +% +% \pkg{mathtools} 会修改 \pkg{unicode-math} 的 \cs{underbrace} 和 \cs{overbrace}, +% 需要还原为 \cs{LaTeXunderbrace} 和 \cs{LaTeXoverbrace}, +% 参考 \url{https://tex.stackexchange.com/q/521394/82731}。 +% \begin{macrocode} +\AtEndOfPackageFile*{mathtools}{ + \@ifpackageloaded{unicode-math}{ + \let\underbrace\LaTeXunderbrace + \let\overbrace\LaTeXoverbrace + }{} +} +% \end{macrocode} +% % \subsubsection{\pkg{nomencl} 宏包} % % \begin{macrocode} @@ -6209,11 +6278,6 @@ % % \begin{macrocode} \AtEndOfPackageFile*{siunitx}{% - \sisetup{ - group-minimum-digits = 4, - separate-uncertainty = true, - inter-unit-product = \ensuremath{{}\cdot{}}, - } \newcommand\thu@set@siunitx@language{% \ifthu@language@chinese \sisetup{ @@ -6526,7 +6590,12 @@ \RequirePackage{enumitem} \RequirePackage{etoolbox} \RequirePackage{metalogo} + +% Pretending the `amssymb` has been loaded. +% This should be removed after `markdown` v2.13.0. +\expandafter\def\csname ver@amssymb.sty\endcsname{0000/00/00} \RequirePackage[tightLists=false]{markdown} +\expandafter\let\csname ver@amssymb.sty\endcsname\relax \markdownSetup{ renderers = { diff --git a/macros/latex/contrib/thuthesis/thuthesis.pdf b/macros/latex/contrib/thuthesis/thuthesis.pdf Binary files differindex 6925a82705..ad3acc14f2 100644 --- a/macros/latex/contrib/thuthesis/thuthesis.pdf +++ b/macros/latex/contrib/thuthesis/thuthesis.pdf diff --git a/macros/luatex/generic/lua-widow-control/README.md b/macros/luatex/generic/lua-widow-control/README.md index 920873c5b0..e6e9ce0b29 100644 --- a/macros/luatex/generic/lua-widow-control/README.md +++ b/macros/luatex/generic/lua-widow-control/README.md @@ -7,7 +7,7 @@ lua-widow-control ================= -Lua-widow-control is a Plain TeX/LaTeX/ConTeXt/OpTeX package that removes widows and orphans without any user intervention. Using the power of LuaTeX, it does so _without_ stretching any glue or shortening any pages or columns. Instead, lua-widow-control automatically lengthens a paragraph on a page or column where a widow or orphan would otherwise occur. +Lua-widow-control is a Plain TeX/LaTeX/ConTeXt/OpTeX package that removes widows and orphans without any user intervention. Using the power of LuaTeX, it does so _without_ stretching any glue or shortening any pages or columns. Instead, lua-widow-control automatically lengthens a paragraph on a page or column where a widow or orphan would otherwise occur. Please see the [**full documentation**](https://github.com/gucci-on-fleek/lua-widow-control/releases/latest/download/lua-widow-control.pdf) for more. @@ -38,14 +38,14 @@ To load the package, add the relevant line to your preamble: Contributing ------------ -Please see [`contributing.md`](https://github.com/gucci-on-fleek/lua-widow-control/blob/master/.github/contributing.md). +Please see [`CONTRIBUTING.md`](https://github.com/gucci-on-fleek/lua-widow-control/blob/master/CONTRIBUTING.md). Licence ------- Lua-widow-control is licensed under the [_Mozilla Public License_, version 2.0](https://www.mozilla.org/en-US/MPL/2.0/) or greater. The documentation is additionally licensed under [CC-BY-SA, version 4.0](https://creativecommons.org/licenses/by-sa/4.0/legalcode) or greater. -Please note that a compiled document is absolutely **not** considered to be an "Executable Form" as defined by the MPL. The use of lua-widow-control in a document does not place **any** obligations on the document's author or distributors. The MPL and CC-BY-SA licenses **only** apply to you if you distribute the lua-widow-control source code or documentation. +Please note that a compiled document is absolutely **not** considered to be an "Executable Form" as defined by the MPL. The use of lua-widow-control in a document does not place **any** obligations on the document's author or distributors. The MPL and CC-BY-SA licenses **only** apply to you if you distribute the lua-widow-control source code or documentation. --- -_v2.0.0 (2022-03-07)_ <!--%%version %%dashdate--> +_v2.0.1 (2022-03-18)_ <!--%%version %%dashdate--> diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty b/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty index 783db59ed2..e8b2eefb0a 100644 --- a/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty +++ b/macros/luatex/generic/lua-widow-control/lua-widow-control-2022-02-22.sty @@ -38,7 +38,7 @@ % Here, we enable font expansion/contraction. It isn't strictly necessary for % \lwc/'s functionality; however, it is required for the -% lengthened paragraphs to not have terrible spacing. +% lengthened paragraphs to not have terrible spacing. \RequirePackage{etoolbox} \AtEndPreamble{ \@ifpackageloaded{microtype}{}{ % Only load if not already loaded diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.lua b/macros/luatex/generic/lua-widow-control/lua-widow-control.lua index 5801feef12..be9cab16cb 100644 --- a/macros/luatex/generic/lua-widow-control/lua-widow-control.lua +++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.lua @@ -107,8 +107,8 @@ elseif plain or latex or optex then debug_print("Plain/LaTeX") luatexbase.provides_module { name = lwc.name, - date = "2022/03/07", --%%slashdate - version = "2.0.0", --%%version + date = "2022/03/18", --%%slashdate + version = "2.0.1", --%%version description = [[ This module provides a LuaTeX-based solution to prevent @@ -182,7 +182,7 @@ local function register_callback(t) with \LuaTeX{}base, \ConTeXt{} leaves some \LuaTeX{} callbacks unregistered and unfrozen. Because of this, we need to register some callbacks at the engine level. This is fragile though, because a future \ConTeXt{} update - may decide to register one of these functions, in which case + may decide to register one of these functions, in which case \lwc/ will crash with a cryptic error message. ]] return { @@ -225,7 +225,7 @@ end function lwc.paragraph_cost(demerits, lines) - return demerits / (2 * math.sqrt(lines)) + return demerits / math.sqrt(lines) end @@ -299,14 +299,17 @@ function lwc.save_paragraphs(head) return head end + +local last_paragraph = 0 --- Tags the beginning and the end of each paragraph as it is added to the page. --- --- We add an attribute to the first and last node of each paragraph. The ID is --- some arbitrary number for \lwc/, and the value corresponds to the --- paragraphs index, which is negated for the end of the paragraph. function lwc.mark_paragraphs(head) - set_attribute(head, attribute, #paragraphs) - set_attribute(last(head), attribute, -1 * #paragraphs) + set_attribute(head, attribute, #paragraphs + (100 * pagenum())) + set_attribute(last(head), attribute, -1 * (#paragraphs + (100 * pagenum()))) + last_paragraph = #paragraphs return head end @@ -326,7 +329,7 @@ local function safe_last(head) if ids[id] then warning [[Circular node list detected! -This should never happen. I'll try and +This should never happen. I'll try and recover, but your output may be corrupted. (Internal Error)]] prev.next = nil @@ -385,7 +388,7 @@ function lwc.remove_widows(head) #paragraphs >= 1 then else paragraphs = {} - return head + return head_save end info("Widow/orphan detected. Attempting to remove.") @@ -398,7 +401,9 @@ function lwc.remove_widows(head) -- We find the current "best" replacement, then free the unused ones for i, paragraph in pairs(paragraphs) do - if paragraph.cost < best_cost and i <= #paragraphs - 1 then + if paragraph.cost < best_cost and + i ~= last_paragraph + then -- Clear the old best paragraph flush_list(paragraphs[paragraph_index].node) paragraphs[paragraph_index].node = nil @@ -421,7 +426,9 @@ function lwc.remove_widows(head) ")" ) - if best_cost > tex.getcount(max_cost) then + if best_cost > tex.getcount(max_cost) or + paragraph_index == last_paragraph + then -- If the best replacement is too bad, we can't do anything warning("Widow/Orphan NOT removed on page " .. pagenum()) paragraphs = {} @@ -488,7 +495,7 @@ function lwc.remove_widows(head) debug_print("remove_widows", "found " .. value) -- Insert the start of the replacement paragraph - if value == paragraph_index then + if value == paragraph_index + (100 * pagenum()) then debug_print("remove_widows", "replacement start") safe_last(target_node) -- Remove any loops @@ -497,7 +504,7 @@ function lwc.remove_widows(head) end -- Insert the end of the replacement paragraph - if value == -1 * paragraph_index then + if value == -1 * (paragraph_index + (100 * pagenum())) then debug_print("remove_widows", "replacement end") safe_last(target_node).next = head.next break diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.opm b/macros/luatex/generic/lua-widow-control/lua-widow-control.opm index 992d817a5c..8980ca6007 100644 --- a/macros/luatex/generic/lua-widow-control/lua-widow-control.opm +++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.opm @@ -3,11 +3,12 @@ % SPDX-License-Identifier: MPL-2.0+ % SPDX-FileCopyrightText: 2022 Max Chernoff -\_codedecl\lwcenable{lua-widow-control <v2.0.0>} %%version +\_codedecl\lwcenable{lua-widow-control <v2.0.1>} %%version \_clubpenalty=1 \_widowpenalty=1 \_displaywidowpenalty=1 +\_brokenpenalty=1 \_newdimen\lwcemergencystretch \lwcemergencystretch=3em diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf b/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf Binary files differindex 9243a3a07c..106f106a08 100644 --- a/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf +++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.pdf diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.sty b/macros/luatex/generic/lua-widow-control/lua-widow-control.sty index 56462e40d8..fc80a58cfb 100644 --- a/macros/luatex/generic/lua-widow-control/lua-widow-control.sty +++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.sty @@ -5,7 +5,7 @@ % Formats built after 2015 include \LuaTeX{}Base, so this is the absolute % minimum version that we will run under. -\NeedsTeXFormat{LaTeX2e}[2015/01/01] +\NeedsTeXFormat{LaTeX2e}[2015/01/01] % For _really_ old formats \providecommand\DeclareRelease[3]{} @@ -13,7 +13,7 @@ \DeclareRelease{}{0000-00-00}{lua-widow-control-2022-02-22.sty} \DeclareRelease{v1.1.6}{2022-02-22}{lua-widow-control-2022-02-22.sty} -\DeclareCurrentRelease{v2.0.0}{2022-03-07} %%version %%dashdate +\DeclareCurrentRelease{v2.0.1}{2022-03-18} %%version %%dashdate % If this version of LaTeX doesn't support command hooks, then we load % the last v1.1.X version of the package. @@ -23,8 +23,8 @@ \ProvidesExplPackage {lua-widow-control} - {2022/03/07} %%slashdate - {v2.0.0} %%version + {2022/03/18} %%slashdate + {v2.0.1} %%version {Use Lua to remove widows and orphans} % Unconditional Package Loads @@ -44,15 +44,15 @@ \msg_new:nnn { \c__lwc_name_str } { patch-failed } - { + { Patching~ \c_backslash_str #1~ failed. \\ - Please~ ensure~ that~ \c_backslash_str #1~ exists. + Please~ ensure~ that~ \c_backslash_str #1~ exists. } \msg_new:nnn { \c__lwc_name_str } { old-format-patch } - { + { Patching~ not~ supported~ with~ old~ LaTeX. \\ Please~ use~ a~ LaTeX~ format~ >=~ 2021/06/01. } @@ -60,9 +60,9 @@ \msg_new:nnn { \c__lwc_name_str } { old-command } - { + { \c_backslash_str #1~ has~ been~ REMOVED! \\ - Please~ use~ \c_backslash_str setuplwc \c_left_brace_str #2 + Please~ use~ \c_backslash_str setuplwc \c_left_brace_str #2 \c_right_brace_str\ instead. } @@ -91,6 +91,10 @@ orphanpenalty .value_required:n = true, orphanpenalty .initial:n = 1, + brokenpenalty .int_gset:N = \tex_brokenpenalty:D, + brokenpenalty .value_required:n = true, + brokenpenalty .initial:x = 1, + microtype .bool_gset:N = \g__lwc_use_microtype_bool, microtype .value_required:n = true, microtype .initial:n = true, @@ -194,16 +198,16 @@ debug / false .code:n = \lua_now:n { lwc.debug = false }, strict .meta:n = { emergencystretch = 0pt, - max-cost = 2500, - nobreak = warn, + max-cost = 5000, + nobreak = warn, }, strict .value_forbidden:n = true, default .meta:n = { emergencystretch = 3em, max-cost = \c_max_int, - nobreak = keep, + nobreak = keep, }, - default .value_forbidden:n = true, + default .value_forbidden:n = true, } % Add the user interface for the keys diff --git a/macros/luatex/generic/lua-widow-control/lua-widow-control.tex b/macros/luatex/generic/lua-widow-control/lua-widow-control.tex index 7a75e52132..6d4f0722e3 100644 --- a/macros/luatex/generic/lua-widow-control/lua-widow-control.tex +++ b/macros/luatex/generic/lua-widow-control/lua-widow-control.tex @@ -3,7 +3,7 @@ % SPDX-License-Identifier: MPL-2.0+ % SPDX-FileCopyrightText: 2022 Max Chernoff -\wlog{lua-widow-control v2.0.0} %%version +\wlog{lua-widow-control v2.0.1} %%version \ifx\directlua\undefined \errmessage{% @@ -17,6 +17,7 @@ \clubpenalty=1 \widowpenalty=1 \displaywidowpenalty=1 +\brokenpenalty=1 \newdimen\lwcemergencystretch \lwcemergencystretch=3em @@ -28,7 +29,7 @@ % Here, we enable font expansion/contraction. It isn't strictly necessary for % \lwc/'s functionality; however, it is required for the -% lengthened paragraphs to not have terrible spacing. +% lengthened paragraphs to not have terrible spacing. \expandglyphsinfont\the\font 20 20 5 \adjustspacing=2 diff --git a/macros/luatex/generic/lua-widow-control/lwc-documentation.mkxl b/macros/luatex/generic/lua-widow-control/lwc-documentation.mkxl index 4edaa10694..8a0a0fe382 100644 --- a/macros/luatex/generic/lua-widow-control/lwc-documentation.mkxl +++ b/macros/luatex/generic/lua-widow-control/lwc-documentation.mkxl @@ -117,7 +117,7 @@ setbounds currentpicture to boundingbox OverlayBox; align=flushleft, ]{% {\ssa\bf Warning} - + #1 }} \blank[line] @@ -139,6 +139,7 @@ setbounds currentpicture to boundingbox OverlayBox; ] \define[1]\meta{\m{\langle}\italic{#1}\m{\rangle}} +\define[1]\githubissue{\goto{(Issue~\##1)}[url(https://github.com/gucci-on-fleek/lua-widow-control/issues/#1)]} %%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%% Section Commands %%%%% @@ -146,6 +147,8 @@ setbounds currentpicture to boundingbox OverlayBox; \definecharacterkerning[titlekern][factor=0.2] +\protected\def\interwordspace{\scaledfontdimen2\font} + % Section \startsetups[style:section] \setcharacterkerning[titlekern] @@ -202,7 +205,7 @@ setbounds currentpicture to boundingbox OverlayBox; \else \box0 \fi - + \goodbreak \stoptexdefinition @@ -295,7 +298,7 @@ interfaces.implement { \dontleavehmode \blackrule[depth=-0.25\baselineskip, height=\dimexpr0.25\baselineskip + 0.4pt, width=8em] \par - + \doifdocumentvariable{ctan}{ \strippedurl{\documentvariable{ctan}} } @@ -306,7 +309,7 @@ interfaces.implement { \noindentation \stopalignment -\stopsetups +\stopsetups \startsetups[document:start] \setup[titleblock] diff --git a/macros/luatex/generic/lua-widow-control/lwc-documentation.tex b/macros/luatex/generic/lua-widow-control/lwc-documentation.tex index 1194acb44f..6e9eaacc66 100644 --- a/macros/luatex/generic/lua-widow-control/lwc-documentation.tex +++ b/macros/luatex/generic/lua-widow-control/lwc-documentation.tex @@ -29,21 +29,20 @@ \def\titlecite[#1]{\cite[title][#1]\cite[#1]} -\usemodule[vim] -\definevimtyping[TEX][syntax=tex, lines=split, escape=comment, directory=tmp] -\definevimtyping[LUA][syntax=lua, lines=split, escape=comment, directory=tmp] +\definetype[inlineTEX][option=tex, escape={$,$}, lines=hyphenated] +\definetype[inlineLUA][option=lua, escape={$,$}, lines=hyphenated] \input lwc-sample \startdocument[ title=lua-widow-control, author=Max Chernoff, - version=2.0.0, %%version + version=2.0.1, %%version github=https://github.com/gucci-on-fleek/lua-widow-control, ctan=https://www.ctan.org/pkg/lua-widow-control, ] -\Lwc/ is a Plain~\TeX/\LaTeX/\ConTeXt{}/Op\TeX{} package that removes \waos/ without any user intervention. Using the power of \LuaTeX{}, it does so \emph{without} stretching any glue or shortening any pages or columns. Instead, \lwc/ automatically lengthens a paragraph on a page or column where a \woo/ would otherwise occur. +\Lwc/ is a Plain~\TeX/\LaTeX/\ConTeXt{}/Op\TeX{} package that removes \waos/ without any user intervention. Using the power of \LuaTeX{}, it does so \emph{without} stretching any glue or shortening any pages or columns. Instead, \lwc/ automatically lengthens a paragraph on a page or column where a \woo/ would otherwise occur. \section{Quick Start} Ensure that your \TeX~Live/Mik\TeX{} distribution is up-to-date. Then, \LaTeX{} users just need to place \inlineTEX{\usepackage{lua-widow-control}} in the preamble of your document. For more details, see the \goto{Usage sections}[sec:usage]. @@ -65,6 +64,9 @@ Widows occur when when the majority of a paragraph is on one page or column, but \subsection{Orphans} Orphans are when the first line of a paragraph occurs on the page or column before the remainder of they paragraph. They are not nearly as distracting for the reader, but they are still not ideal. Visually, \waos/ are about equally disruptive; however, orphans tend not to decrease the legibility of a text as much as widows do, so they tend to be ignored more often. +\subsection{Broken Hyphens} +\q{Broken} hyphens occur whenever a page break occurs part way through a hyphenated word. These really have nothing to do with \waos/; however, \TeX{} treats broken hyphens exactly the same as it does \waos/. In addition, breaking a word across two pages is at almost as bad for the reader as \waos/; therefore, \lwc/ treats broken hyphens exactly the same way as it treats \waos/. + \startplacefigure[location={here, top, bottom}, title={A visual comparison of \waos/.}, reference=tab:widow] \getbuffer[widow-orphan] \stopplacefigure @@ -81,7 +83,7 @@ However, some objects have penalties attached. These penalties make \TeX{} treat One important note: once \TeX{} begins breaking a page, it never goes back and modifies any content on the page. Page breaking is a localized algorithm, without any backtracking. \subsection{Behavior} -Of course, this algorithm doesn't allow us to intuitively understand how \TeX{} deals with \waos/. +Of course, this algorithm doesn't allow us to intuitively understand how \TeX{} deals with \waos/. Due to the penalties attached to \waos/, \TeX{} treats them as if they are longer than they actually are. Widows and orphans with small penalties attached---like \LaTeX's default values of 150---are only treated as slightly taller than 1 line, while \waos/ with large penalties---values near 10\,000---are treated as if they are 2 lines tall. Because potential \wao/ lines are broken as if they are taller than they actually are, \TeX{} will tend to group them together on the same pages. @@ -92,16 +94,17 @@ There have been a few previous attempts to improve upon \TeX's previously-discus \titlecite[tugboat-strategies] and \titlecite[tugboat-widows] both begin with comprehensive discussions of the methods of preventing \waos/. They both agree that \waos/ are bad and ought to be avoided; however, they each differ in solutions. \italic{Strategies}\cite[tugboat-strategies] proposes an output routine that reduces the length of facing pages by 1~line when necessary to remove \waos/ while \italic{Managing}\cite[tugboat-widows] proposes that the author manually rewrites or adjusts the \tex{looseness} when needed. -\titlecite[widow-assist] contains a file \type{widow-assist.lua} that automatically detects which paragraphs can be safely shortened or lengthened by 1 line. \titlecite[widows-and-orphans] alerts the author to the pages that contain widows or orphans. Combined, these packages make it very simple for the author to quickly remove \waos/ by adjusting the \tex{looseness} values; however, it still requires the author to make manual source changes after each revision. +\titlecite[widow-assist] contains a file \type{widow-assist.lua} that automatically detects which paragraphs can be safely shortened or lengthened by 1 line. \titlecite[widows-and-orphans] alerts the author to the pages that contain widows or orphans. Combined, these packages make it very simple for the author to quickly remove \waos/ by adjusting the \tex{looseness} values; however, it still requires the author to make manual source changes after each revision. \Lwc/ is essentially just a combination of \type{widow-assist.lua}\cite[widow-assist] and \sans{widows-and-orphans}:\cite[widows-and-orphans] when the \openalty/ shows that a \woo/ occurred, Lua is used to find a stretchable paragraph. What \lwc/ adds on top of these packages is automation: \lwc/ eliminates the requirement for any manual adjustments. +\startpostponing \startTEXpage[ align=normal, width=100cm, autowidth=force, offset=5pt, - pagestate=start + pagestate=start, ] \veryraggedcenter \setupTABLE[row][first][style=\ssbf, align=middle] @@ -116,7 +119,7 @@ There have been a few previous attempts to improve upon \TeX's previously-discus \NC \typesetbuffer[shorten][frame=on,page=1] \NC \typesetbuffer[stretch][frame=on,page=1] \NC \typesetbuffer[lwc][frame=on,page=1] - \NC\NR + \NC\NR \NC \typesetbuffer[ignore][frame=on,page=2] \NC \typesetbuffer[shorten][frame=on,page=2] @@ -124,15 +127,16 @@ There have been a few previous attempts to improve upon \TeX's previously-discus \NC \typesetbuffer[lwc][frame=on,page=2] \NC\NR - \NC \processTEXbuffer[ignore-code] - \NC \processTEXbuffer[shorten-code] - \NC \processTEXbuffer[stretch-code] - \NC \processTEXbuffer[lwc-code] + \NC \typebuffer[ignore-code][option=TEX] + \NC \typebuffer[shorten-code][option=TEX] + \NC \typebuffer[stretch-code][option=TEX] + \NC \typebuffer[lwc-code][option=TEX] \NC\NR \stopTABLE \placefloatcaption[table][reference=tab:demo, title={A visual comparison of various automated widow handling techniques.}] \stopTEXpage +\stoppostponing \section[sec:demo]{Demonstration} @@ -145,21 +149,21 @@ As you can see, the last line of the page is on a separate page from the rest of This page did not leave any widows, but it did shorten the previous page by 1~line. Sometimes this is acceptable, but usually it looks bad because each page will have different text-block heights. This can make the pages look quite uneven, especially when typesetting with columns or in a book with facing pages. \subsection{Stretch} -This page also has no widows and it has a flushed bottom margin. However, the space between each paragraph had to be stretched. +This page also has no widows and it has a flushed bottom margin. However, the space between each paragraph had to be stretched. -If this page had many equations, headings, and other elements with natural space between them, the stretched out space would be much less noticeable. \TeX{} was designed for mathematical typesetting, so it makes sense that this is its default behavior. However, in a page with mostly text, these paragraph gaps can look unsightly. +If this page had many equations, headings, and other elements with natural space between them, the stretched out space would be much less noticeable. \TeX{} was designed for mathematical typesetting, so it makes sense that this is its default behavior. However, in a page with mostly text, these paragraph gaps can look unsightly. In addition, this method is incompatible with typesetting on a grid since all glue stretch must be quantized to the height of a line. \subsection{\lwc/} -\Lwc/ has none of these issues: it eliminates the widows in a document while keeping a flushed bottom margin and constant paragraph spacing. +\Lwc/ has none of these issues: it eliminates the widows in a document while keeping a flushed bottom margin and constant paragraph spacing. To do so, \lwc/ lengthened the second paragraph by one line. If you look closely, you can see that this stretched the interword spaces. This stretching is noticeable when typesetting in a narrow text block, but it becomes nearly imperceptible with larger widths. \Lwc/ automatically finds the \q{best} paragraph to stretch, so the increase in interword spaces should almost always be minimal. \section{Installation} -Most up-to-date \TeX~Live and Mik\TeX{} systems should already have \lwc/ installed. However, a manual installation may occasionally be required. +Most up-to-date \TeX~Live and Mik\TeX{} systems should already have \lwc/ installed. However, a manual installation may occasionally be required. \subsection{\TeX~Live} Run \type{tlmgr install lua-widow-control} in a terminal, or install using the \q{\TeX~Live Manager} \acronym{GUI}. @@ -231,11 +235,11 @@ Please note that when running in legacy mode, you cannot use the key--value inte \subsection{Overview} -\LaTeX{} users can set the options either when loading the package (\tex{usepackage[\meta{options}]\{lua-widow-control\}}) or at any point using \tex{lwcsetup\{\meta{options}\}}. +\LaTeX{} users can set the options either when loading the package (\inlineTEX{\usepackage[$\meta{options}$]{lua-widow-control}}) or at any point using \inlineTEX{\lwcsetup{$\meta{options}$}}. -\ConTeXt{} users should always use the \tex{setuplwc[\meta{options}]} command. +\ConTeXt{} users should always use the \inlineTEX{\setuplwc[$\meta{options}$]} command. -Plain~\TeX{} and Op\TeX{} are a little different. Some options have commands provided (i.e., \tex{lwcemergencystretch=\meta{dimension}}), while others must be set manually (i.e., \tex{directlua\{lwc.debug = true\}}). +Plain~\TeX{} and Op\TeX{} are a little different. Some options have commands provided (i.e., \inlineTEX{\lwcemergencystretch = $\meta{dimension}$}), while others must be set manually (i.e., \inlineTEX{\directlua{lwc.debug = true}}). Also, please note that not all commands are provided for all formats. @@ -271,7 +275,7 @@ Also, please note that not all commands are provided for all formats. \subsection{Strict Mode} -By default, \lwc/ takes all possible measures to remove \waos/. This normally works out pretty well; however, sometimes these measures may be a little more aggressive than certain users want. +By default, \lwc/ takes all possible measures to remove \waos/. This normally works out pretty well; however, sometimes these measures may be a little more aggressive than certain users want. \Lwc/ offers a \q{strict} mode that will only make modification to the page that are near-imperceptible to remove \waos/. @@ -281,28 +285,28 @@ By default, \lwc/ takes all possible measures to remove \waos/. This normally wo \NC\NR \stopTABLE -Internally, this sets {\tt emergencystretch = 0pt}, {\tt max-cost = 2500}, and {\tt nobreak = warn}. +Internally, this sets {\tt emergencystretch = 0pt}, {\tt max-cost = 5000}, and {\tt nobreak = warn}. \subsection{\estretch/} -You can configure the \estretch/ used when stretching a paragraph. The default value is 3~em. +You can configure the \estretch/ used when stretching a paragraph. The default value is 3~em. \Lwc/ will only use the \estretch/ when it cannot lengthen a paragraph in any other way, so it is fairly safe to set this to a large value. \TeX{} still accumulates badness when \estretch/ is used, so it's pretty rare that a paragraph that requires any \estretch/ will actually be used on the page. \startTABLE \NC \plainop/ - \NC\tex{lwcemergencystretch=\meta{dimension}} + \NC\inlineTEX{\lwcemergencystretch = $\meta{dimension}$} \NC\NR \NC \LaTeX{} - \NC\tex{lwcsetup\{emergencystretch = \meta{dimension}\}} + \NC\inlineTEX{\lwcsetup{emergencystretch = $\meta{dimension}$}} \NC\NR \NC \ConTeXt{} - \NC\tex{setuplwc[emergencystretch = \meta{dimension}]} + \NC\inlineTEX{\setuplwc[emergencystretch = $\meta{dimension}$]} \NC\NR \stopTABLE \subsection{Selectively Disabling} -Sometimes, you may want to disable \lwc/ for certain commands where stretching is undesirable. For example, you typically wouldn't want section headings to be stretched. +Sometimes, you may want to disable \lwc/ for certain commands where stretching is undesirable. For example, you typically wouldn't want section headings to be stretched. You could just disable then reenable \lwc/ every time that you use the command; however, \lwc/ provides a convenience macro that will do this automatically for you. @@ -310,33 +314,36 @@ You could just disable then reenable \lwc/ every time that you use the command; \startTABLE \NC Plain \TeX{} - \NC \tex{lwcdisablecmd\{\meta{\backslash macro}\}} + \NC \inlineTEX{\lwcdisablecmd{$\meta{\backslash macro}$}} \NC\NR \NC \LaTeX{} - \NC \tex{lwcsetup\{disablecmds = \{\meta{\backslash macroone}, \meta{\backslash macrotwo}\}\}} + \NC \inlineTEX{\lwcsetup{disablecmds = {$\meta{\backslash macroone}$, $\meta{\backslash macrotwo}$}}} \NC\NR \NC \ConTeXt{} - \NC \tex{prependtoks\backslash lwc@patch@pre\backslash to\backslash everybefore\meta{hook}} - \NC\NR\NC\NC \tex{prependtoks\backslash lwc@patch@post\backslash to\backslash everyafter\meta{hook}} + \NC \inlineTEX{\prependtoks\lwc$\hskip-0.5em\relax$@patch@pre\to\everybefore$\hskip-0.5em\relax\meta{hook}$} + \NC\NR\NC\NC \inlineTEX{\prependtoks\lwc$\hskip-0.5em\relax$@patch@pre\to\everyafter$\hskip-0.5em\relax\meta{hook}$} \NC\NR \stopTABLE \subsection{Widow and Orphan Penalties} -You can also manually adjust the penalties that \TeX{} assigns to \waos/. Usually, the defaults are fine, but advanced users may want to change them. +You can also manually adjust the penalties that \TeX{} assigns to widows, orphans, and broken hyphens. Usually, the defaults are fine, but advanced users may want to change them. \startTABLE \NC \plainop/ - \NC\tex{widowpenalty=\meta{integer}} - \NC\NR\NC\NC\tex{clubpenalty=\meta{integer}} + \NC\inlineTEX{\widowpenalty = $\meta{integer}$} + \NC\NR\NC\NC\inlineTEX{\clubpenalty = $\meta{integer}$} + \NC\NR\NC\NC\inlineTEX{\brokenpenalty = $\meta{integer}$} \NC\NR \NC \LaTeX{} - \NC\tex{lwcsetup\{widowpenalty = \meta{integer}\}} - \NC\NR\NC\NC\tex{lwcsetup\{orphanpenalty = \meta{integer}\}} + \NC\inlineTEX{\lwcsetup{widowpenalty = $\meta{integer}$}} + \NC\NR\NC\NC\inlineTEX{\lwcsetup{orphanpenalty = $\meta{integer}$}} + \NC\NR\NC\NC\inlineTEX{\lwcsetup{brokenpenalty = $\meta{integer}$}} \NC\NR \NC \ConTeXt{} - \NC\tex{setuplwc[widowpenalty = \meta{integer}]} - \NC\NR\NC\NC\tex{setuplwc[orphanpenalty = \meta{integer}]} + \NC\inlineTEX{\setuplwc[widowpenalty = $\meta{integer}$]} + \NC\NR\NC\NC\inlineTEX{\setuplwc[orphanpenalty = $\meta{integer}$]} + \NC\NR\NC\NC\inlineTEX{\setuplwc[brokenpenalty = $\meta{integer}$]} \NC\NR \stopTABLE @@ -354,13 +361,13 @@ When \lwc/ encounters an orphan, it removes it by removing the orphaned line to \startTABLE \NC \plainop/ - \NC\tex{directlua\{lwc.nobreak_behaviour = "\meta{value}"\}} + \NC\inlineTEX{\directlua{lwc.nobreak_behaviour = "$\meta{value}$"}} \NC\NR \NC \LaTeX{} - \NC\tex{lwcsetup\{nobreak = \meta{value}\}} + \NC\inlineTEX{\lwcsetup{nobreak = $\meta{value}$}} \NC\NR \NC \ConTeXt{} - \NC\tex{setuplwc[nobreak = \meta{value}]} + \NC\inlineTEX{\setuplwc[nobreak = $\meta{value}$]} \NC\NR \stopTABLE @@ -375,20 +382,20 @@ The value \type{warn} causes \lwc/ to give up on the page and do nothing, leavin When \TeX{} breaks a paragraph, it scores it by the number of \q{demerits}. The demerits for a paragraph is the sum of the squared badnesses for each line, plus any \q{additional demerits} added for any other reason. The badness for a line is proportional the cube of the glue stretch ratio, so demerits grow with the sixth power of glue stretch. To choose the \q{best} paragraph on the page, \lwc/ uses a \q{cost function} $C$ that is initially defined as \startformula - C = \frac{d}{2\sqrt{l}} -\stopformula where $d$ is the total demerits of the paragraph, and $l$ is the number of lines in the paragraph. + C = \frac{d}{\sqrt{l}} +\stopformula where $d$ is the total demerits of the paragraph, and $l$ is the number of lines in the paragraph. By default, \lwc/ just selects the paragraph on the page with the lowest cost; however, you can configure it to only select paragraphs below a selected cost. If there aren't any paragraphs below the set threshold, then \lwc/ won't remove the \woo/ and will instead issue a warning. \startTABLE \NC \plainop/ - \NC\tex{lwcmaxcost=\meta{integer}} + \NC\inlineTEX{\lwcmaxcost = $\meta{integer}$} \NC\NR \NC \LaTeX{} - \NC\tex{lwcsetup\{max-cost = \meta{integer}\}} + \NC\inlineTEX{\lwcsetup{max-cost = $\meta{integer}$}} \NC\NR \NC \ConTeXt{} - \NC\tex{setuplwc[maxcost = \meta{integer}]} + \NC\inlineTEX{\setuplwc[maxcost = $\meta{integer}$]} \NC\NR \stopTABLE @@ -419,17 +426,19 @@ Since \TeX{} implements column breaking and page breaking through the same inter \section[sec:issues]{Known Issues} \startitemize - \item \Lwc/ will rarely fail to correctly move the last line on an expanded page to the next page in documents with \emph{very} small paper sizes. + \item \Lwc/ will rarely fail to correctly move the last line on an expanded page to the next page in documents with \emph{very} small paper sizes. \githubissue{19} \item When a 3-line paragraph is at the end of a page forming a widow, \lwc/ will remove the widow; however, it will leave an orphan. This issue is inherent to any process that removes widows through paragraph expansion and is thus unavoidable. Orphans are better than widows, so this is still an improvement. \item Sometimes a \woo/ cannot be eliminated because no paragraph has enough \q{stretch}. This can \emph{sometimes} be remediated by increasing \lwc/'s \estretch/; however, some pages just don't have enough \q{stretchy} paragraphs. Long paragraphs with short words tend to be \q{stretchier} than short paragraphs with long words since these long paragraphs will have more interword glue. Narrow columns also stretch easier than wide columns since you need to expand a paragraph by less to make a new line. - \item When running under \LuaMetaTeX, the log may be filled with lines like \q{\tt luatex warning > tex: left parfill skip is gone}. This is harmless and can be ignored. % I have no idea how to fix this. The LMTX manual has "\parfillleftskip" in the indices, but that's all that I can find about it. + \item When running under \LuaMetaTeX, the log may be filled with lines like \q{\tt luatex warning > tex: left parfill skip is gone}. This is harmless and can be ignored. \githubissue{7} % I have no idea how to fix this. The LMTX manual has "\parfillleftskip" in the indices, but that's all that I can find about it. + + \item \Lwc/ will rarely raise a \q{\tt Circular node list detected!} warning. This occurs when the replacement paragraph node list loops back on itself. This is usually harmless, but can rarely cause the entire compile to completely fail. \githubissue{9} - \item \Lwc/ will rarely raise a \q{\tt Circular node list detected!} warning. This occurs when the replacement paragraph node list loops back on itself. This is usually harmless, but can rarely cause the entire compile to completely fail. + \item \TeX{} may warn you about over or underfull vboxes on pages where \lwc/ removed a \woo/. This is a false alarm and can be ignored. \githubissue{8} - \item \TeX{} may warn you about over or underfull vboxes on pages where \lwc/ removed a \woo/. This is a false alarm and can be ignored. + \item If there is a footnote on the last line of the page with a \woo/, \lwc/ will sometimes move the \q{footnote mark} but not the \q{footnote text}, thus breaking up a footnote. \githubissue{26} \stopitemize \section{The Algorithm} @@ -473,11 +482,13 @@ Please note that a compiled document is \bold{not} considered to be an \q{Execut ] \section[sec:implementation]{Implementation} +\usemodule[scite] \setupbodyfont[10pt] \setuphead[subsection][ alternative=normal, style=\ssita, - before={\blank[big, preference]}, + page=yes, + continue=yes, ] \subsection{lua-widow-control.lua} @@ -492,7 +503,6 @@ Please note that a compiled document is \bold{not} considered to be an \q{Execut \typeTEXfile{../source/lua-widow-control.sty} -\def\module{\tex{module}} \subsection{t-lua-widow-control.mkxl/mkiv} \typeTEXfile{../source/t-lua-widow-control.mkxl} diff --git a/macros/luatex/generic/lua-widow-control/lwc-sample.tex b/macros/luatex/generic/lua-widow-control/lwc-sample.tex index 0ba9f17f76..8df05999a5 100644 --- a/macros/luatex/generic/lua-widow-control/lwc-sample.tex +++ b/macros/luatex/generic/lua-widow-control/lwc-sample.tex @@ -37,10 +37,10 @@ \setuplanguage[en][spacing=packed] \starttext - \Lwc/ can remove most widows and orphans from a document, \emph{without} stretching any glue or shortening any pages. - + \Lwc/ can remove most widows and orphans from a document, \emph{without} stretching any glue or shortening any pages. + It does so by automatically lengthening a paragraph on a page where a widow or orphan would otherwise occur. While \TeX{} breaks paragraphs into their natural length, \lwc/ is breaking the paragraph 1~line longer than its natural length. \TeX{}'s paragraph is output to the page, but \lwc/'s paragraph is just stored for later. When a widow or orphan occurs, \lwc/ can take over. It selects the previously-saved paragraph with the least badness; then, it replaces \TeX{}'s paragraph with its saved paragraph. This increases the text block height of the page by 1~line. - + Now, the last line of the current page can be pushed to the top of the next page. This removes the widow or the orphan without creating any additional work. \stoptext \stopbuffer diff --git a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkiv b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkiv index e24f972d57..716e45dcf5 100644 --- a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkiv +++ b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkiv @@ -1,10 +1,10 @@ %D \module %D [ file=t-lua-widow-control, -%D version=2.0.0, %%version +%D version=2.0.1, %%version %D title=lua-widow-control, %D subtitle=\ConTeXt module for lua-widow-control, %D author=Max Chernoff, -%D date=2022-03-07, %%dashdate +%D date=2022-03-18, %%dashdate %D copyright=Max Chernoff, %D license=MPL-2.0+, %D url=https://github.com/gucci-on-fleek/lua-widow-control] @@ -52,6 +52,7 @@ \clubpenalty=\lwcparameter{orphanpenalty} \widowpenalty=\lwcparameter{widowpenalty} \displaywidowpenalty=\lwcparameter{widowpenalty} + \brokenpenalty=\lwcparameter{brokenpenalty} \stopsetups \setups[*default] @@ -67,6 +68,7 @@ debug=\v!stop, orphanpenalty=1, widowpenalty=1, + brokenpenalty=1, nobreak=keep, maxcost=2147483647, ] @@ -74,7 +76,7 @@ % Here, we enable font expansion/contraction. It isn't strictly necessary for % \lwc/'s functionality; however, it is required for the -% lengthened paragraphs to not have terrible spacing. +% lengthened paragraphs to not have terrible spacing. \definefontfeature[default][default][expansion=quality] \setupalign[hz] diff --git a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl index e24f972d57..716e45dcf5 100644 --- a/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl +++ b/macros/luatex/generic/lua-widow-control/t-lua-widow-control.mkxl @@ -1,10 +1,10 @@ %D \module %D [ file=t-lua-widow-control, -%D version=2.0.0, %%version +%D version=2.0.1, %%version %D title=lua-widow-control, %D subtitle=\ConTeXt module for lua-widow-control, %D author=Max Chernoff, -%D date=2022-03-07, %%dashdate +%D date=2022-03-18, %%dashdate %D copyright=Max Chernoff, %D license=MPL-2.0+, %D url=https://github.com/gucci-on-fleek/lua-widow-control] @@ -52,6 +52,7 @@ \clubpenalty=\lwcparameter{orphanpenalty} \widowpenalty=\lwcparameter{widowpenalty} \displaywidowpenalty=\lwcparameter{widowpenalty} + \brokenpenalty=\lwcparameter{brokenpenalty} \stopsetups \setups[*default] @@ -67,6 +68,7 @@ debug=\v!stop, orphanpenalty=1, widowpenalty=1, + brokenpenalty=1, nobreak=keep, maxcost=2147483647, ] @@ -74,7 +76,7 @@ % Here, we enable font expansion/contraction. It isn't strictly necessary for % \lwc/'s functionality; however, it is required for the -% lengthened paragraphs to not have terrible spacing. +% lengthened paragraphs to not have terrible spacing. \definefontfeature[default][default][expansion=quality] \setupalign[hz] diff --git a/macros/unicodetex/latex/njuthesis/README.md b/macros/unicodetex/latex/njuthesis/README.md index b9411c04fb..80509ca1ce 100644 --- a/macros/unicodetex/latex/njuthesis/README.md +++ b/macros/unicodetex/latex/njuthesis/README.md @@ -11,7 +11,7 @@ Usage A minimal example of this document class should look like -``` +```LaTeX \documentclass{njuthesis} \njusetup{} \begin{document} diff --git a/macros/unicodetex/latex/njuthesis/njuthesis.dtx b/macros/unicodetex/latex/njuthesis/njuthesis.dtx index d08fbc07f1..ff8521dd9d 100644 --- a/macros/unicodetex/latex/njuthesis/njuthesis.dtx +++ b/macros/unicodetex/latex/njuthesis/njuthesis.dtx @@ -20,6 +20,8 @@ % This work consists of the files njuthesis.dtx, % and the derived files njuthesis.ins, % njuthesis.cls, +% njuthesis-undergraduate.def, +% njuthesis-graduate.def, % njuthesis.pdf, % and README.md. % @@ -71,10 +73,12 @@ To produce the documentation run the original source files ending with \generate{ \usedir{tex/latex/njuthesis} - \file{\jobname.cls} {\from{\jobname.dtx}{class}} + \file{\jobname.cls} {\from{\jobname.dtx}{class}} + \file{\jobname-undergraduate.def} {\from{\jobname.dtx}{definition-ug}} + \file{\jobname-graduate.def} {\from{\jobname.dtx}{definition-g}} %<*internal> \usedir{source/latex/njuthesis} - \file{\jobname.ins} {\from{\jobname.dtx}{install}} + \file{\jobname.ins} {\from{\jobname.dtx}{install}} %</internal> } @@ -87,6 +91,8 @@ To produce the documentation run the original source files ending with \Msg{* The recommended directory is TDS:tex/latex/njuthesis *} \Msg{* *} \Msg{* njuthesis.cls *} +\Msg{* njuthesis-graduate.def *} +\Msg{* njuthesis-undergraduate.def *} \Msg{* njuthesis.ins *} \Msg{* *} \Msg{* To produce the documentation, run the file njuthesis.dtx *} @@ -104,22 +110,30 @@ To produce the documentation run the original source files ending with %</internal> % %<class>\NeedsTeXFormat{LaTeX2e} -%<class>\RequirePackage{expl3} -%<class>\GetIdInfo $Id: njuthesis.dtx 0.15.0 2022-02-20 10:30:00 +0800 NJU LUG <git+nju-lug-email-3104-issue-@yaoge123.cn>$ +%<*!(driver|install)> +%<+!driver>\GetIdInfo $Id: njuthesis.dtx 0.16.0 2022-03-19 12:00:00 +0800 NJU LUG <git+nju-lug-email-3104-issue-@yaoge123.cn>$ %<class> {Thesis template for Nanjing University} %<class>\ProvidesExplClass{njuthesis} -%<class> {\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +%<definition-ug> {Undergraduate definition file for njuthesis} +%<definition-ug>\ProvidesExplFile{njuthesis-undergraduate.def} +%<definition-g> {Graduate definition file for njuthesis} +%<definition-g>\ProvidesExplFile{njuthesis-graduate.def} +%<!driver> {\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +%</!(driver|install)> % %<*driver> \ProvidesFile{njuthesis.dtx} -\documentclass{ctxdoc} +\documentclass[fontset=fandol]{ctxdoc} \usepackage{listings,njuvisual,tabularray} \usepackage[firstpage=true]{background} \backgroundsetup{contents={\njuemblem[white!85!gray]{22cm}{!}},scale=1,angle=0,hshift=-4cm} \colorlet{at@guard}{njuviolet} \definecolor{olgreen}{HTML}{138a07} +\definecolor{agrd}{HTML}{2E3191} \newcommand\olbutton[1]{\textcolor{olgreen}{\bfseries #1}} -\newcommand\grd[1]{\textcolor{at@guard}{\sffamily #1}} +\newcommand\agrd[1]{\textcolor{agrd}{\sffamily 〈#1〉}} +\newcommand\bgrd[1]{\textcolor{at@guard}{\sffamily #1}} +\newcommand\tikzlogo{Ti\emph{k}Z} \hypersetup{% pdftitle = {The njuthesis class - LaTeX thesis template for Nanjing University}, citecolor = njublue, @@ -183,7 +197,7 @@ To produce the documentation run the original source files ending with % 南京大学 Linux 用户组 % \thanks{E-mail: \href{mailto:git+nju-lug-email-3104-issue-@yaoge123.cn}{git+nju-lug-email-3104-issue-@yaoge123.cn}}} % -% \date{v0.15.0 \quad 2022-02-20} +% \date{v0.16.0 \quad 2022-03-19} % % \changes{v0.1}{2021/09/04}{开始开发。} % \changes{v0.2}{2021/09/07}{初步搭建了可用的模板。} @@ -206,6 +220,7 @@ To produce the documentation run the original source files ending with % \changes{v0.13}{2021/12/12}{优化了编译速度。} % \changes{v0.13}{2021/12/15}{适配2022届本科生毕业毕业论文(设计)规范。} % \changes{v0.14}{2022/01/13}{将本模板内嵌入南大 \hologo{TeX} 网站。} +% \changes{v0.16}{2022/03/01}{分离本科生和研究生模板配置。} % % % \maketitle @@ -327,7 +342,7 @@ To produce the documentation run the original source files ending with % \end{itemize} % % -% \subsection{君 \hologo{LaTeX} 本当上手} +% \subsection{快速上手} % % \hologo{LaTeX} 并不是一种零门槛的语言,亦不是南京大学学生的必备技能。有同学听 % 到“\emph{给毕业论文交差也得写代码}”这种事情就头疼,实在是我们不愿意见到而必须 @@ -413,29 +428,33 @@ To produce the documentation run the original source files ending with % % \subsubsection{文件构成} % -% 本模板由数量众多的文件组成,\emph{所有可能遇到的}文件如表 \ref{tab:njuthesisfiles} 所示。 -% 其中标注为黄色的内容仅供开发使用,并不会在发行版中出现。 +% 本模板由数量众多的文件组成,\emph{所有可能遇到的}文件如表 \ref{tab:njuthesis-files} 所示。 % % \begin{table}[ht] -% \caption{\cls{njuthesis}文件构成} -% \label{tab:njuthesisfiles} % \centering -% \begin{tabular}{lp{18em}} +% \begin{talltblr}[ +% caption = {\cls{njuthesis}文件构成}, +% label = {tab:njuthesis-files}, +% note{a} = {仅供开发使用,并不会在发布版本中出现。} +% ] {ll} % \toprule -% 名称 & 说明 \\ +% 名称 & 说明 \\ % \midrule -% \file{.vscode} & Visual Studio Code 配置文件 \\ -% \file{latexmkrc} & latexmk 配置文件 \\ -% \file{LICENSE} & 许可证 \\ -% \file{njuthesis.cls} & 模板文档类 \\ -% \color{njuyellow}\file{njuthesis.dtx} & 文档类源代码 \\ -% \color{njuyellow}\file{njuthesis.ins} & 文档类安装脚本 \\ -% \file{njuthesis.pdf} & 用户手册(本文档) \\ -% \file{njuthesis-sample.bib} & 示例参考文献列表 \\ -% \file{njuthesis-sample.tex} & 示例文档,不妨以此为基础撰写论文 \\ -% \file{README.md} & 自述文件 \\ +% \file{.vscode} & Visual Studio Code 配置文件 \\ +% \file{CHANGELOG.md} & 修订记录 \\ +% \file{latexmkrc} & \pkg{latexmk} 配置文件 \\ +% \file{LICENSE} & 许可证 \\ +% \file{njuthesis.cls} & 模板文档类 \\ +% \file{njuthesis.dtx}\TblrNote{a} & 文档类源代码 \\ +% \file{njuthesis.ins}\TblrNote{a} & 文档类安装脚本 \\ +% \file{njuthesis.pdf} & 用户手册(本文档) \\ +% \file{njuthesis-sample.bib} & 示例参考文献列表 \\ +% \file{njuthesis-sample.tex} & 示例文档,不妨以此为基础撰写论文 \\ +% \file{njuthesis-graduate.def} & 研究生参数配置文件 \\ +% \file{njuthesis-undergraduate.def} & 本科生参数配置文件 \\ +% \file{README.md} & 自述文件 \\ % \bottomrule -% \end{tabular} +% \end{talltblr} % \end{table} % % @@ -505,7 +524,7 @@ To produce the documentation run the original source files ending with % \hologo{TeX} & Windows & macOS & Linux \\ % \midrule % \hologo{TeX}\,Live & $\bullet$ & & $\bullet$ \\ -% mac\hologo{TeX} & & $\bullet$ & \\ +% Mac\hologo{TeX} & & $\bullet$ & \\ % \hologo{MiKTeX} & $\bullet$ & $\bullet$ & $\bullet$ \\ % \bottomrule % \end{tabular} @@ -555,14 +574,15 @@ To produce the documentation run the original source files ending with % 下命令顺序进行编译,以生成内容正确的 \file{njuthesis-sample.pdf}。输出的 PDF % 文档位于同一目录下。该目录下同时会生成若干中间文件。 % -% 编译命令具体为引擎名称加主文件名,在编译 \file{.tex} 文件时,文件扩展名可以省略 -% 不写。现阶段 \cls{njuthesis} 仅支持 \hologo{XeLaTeX} 与 \hologo{LuaLaTeX}。请 -% 注意,几种命令的输出文件基本相同,可以任取一种;但如果您不清楚这两种编译引擎的 +% 编译命令具体为引擎名称加主文件名,在编译 \file{.tex} 文件时, +% 文件扩展名可以省略不写。现阶段 \cls{njuthesis} 仅支持 \hologo{XeTeX} +% 与 \hologo{LuaTeX} 引擎,以及 \hologo{biber} 文献工具。请注意, +% 几种命令的输出文件基本相同,可以任取一种;但如果您不清楚这两种编译引擎的 % 区别,或者对多步编译感到困惑,我们建议优先使用 |latexmk -xelatex|。 % % % \subparagraph{使用 \hologo{XeLaTeX}} -% 标准的 \hologo{XeLaTeX} 引擎四步编译方法。 +% 标准的 \hologo{XeTeX} 引擎四步编译方法。 % % \begin{shellexample}[morekeywords={xelatex,biber}] % xelatex njuthesis-sample @@ -573,7 +593,7 @@ To produce the documentation run the original source files ending with % % % \subparagraph{使用 \hologo{LuaLaTeX}} -% 标准的 \hologo{LuaLaTeX} 引擎四步编译方法。 +% 标准的 \hologo{LuaTeX} 引擎四步编译方法。 % % \begin{shellexample}[morekeywords={lualatex,biber}] % lualatex njuthesis-sample @@ -594,7 +614,9 @@ To produce the documentation run the original source files ending with % \begin{shellexample}[morekeywords={latexmk}] % latexmk njuthesis-sample % \end{shellexample} -% 直接运行会调用 \hologo{pdfLaTeX} 引擎导致报错。如需指定编译引擎,可以加入 |-xelatex| 或 |-lualatex| 参数,例如指定 \hologo{XeLaTeX} 的命令为 +% 直接运行会调用 \hologo{pdfLaTeX} 引擎导致报错。 +% 如需指定编译引擎,可以加入 |-xelatex| 或 |-lualatex| 参数。 +% 例如,指定 \hologo{XeLaTeX} 的命令为 % \begin{shellexample}[morekeywords={latexmk},emph={-xelatex}] % latexmk -xelatex njuthesis-sample % \end{shellexample} @@ -750,14 +772,28 @@ To produce the documentation run the original source files ending with % \end{itemize} % 草稿模式有助于提升编译速度以及检查格式问题,建议在定稿前始终开启。 % -% 启用这一选项也会改变特定宏包的行为,譬如在草稿模式下 \pkg{listings} 宏包的代码环境不会显示内容,具体效果需要参照各个宏包的说明文档。如需抵消草稿模式的影响,请使用 \opt{final} 选项载入相关宏包。 +% 启用这一选项也会改变特定宏包的行为,譬如在草稿模式下 \pkg{listings} +% 宏包的代码环境不会显示内容,具体效果需要参照各个宏包的说明文档。 +% 如需抵消草稿模式的影响,请使用 \opt{final} 选项载入相关宏包。 % % -% \subsubsection{指定字体} +% \subsubsection{配置文件} % -% 学校论文格式要求使用的字体一般已经预装在各个操作系统,本模板针对不同平台进行了自动检测适配,可以开箱即用。 +% \begin{function}[added=2022-02-23]{config} +% \begin{syntax} +% config = \Arg{文件} +% \end{syntax} +% 配置文件路径。 +% \end{function} % -% 如果希望更改本模板使用的字体,请填写以下两个选项以覆盖操作系统检测得到的设置。 +% 本选项可用于载入额外的用户配置文件。该文件支持 \hologo{LaTeX3} 语法。 +% +% +% \subsubsection{指定字体} +% +% 学校论文格式要求使用的字体一般已经预装在各个操作系统, +% 本模板针对不同平台进行了自动检测适配,可以开箱即用。 +% 如果希望更改本模板使用的字体,请填写以下两个选项以覆盖默认设置。 % % \begin{function}[added=2021-09-07,updated=2021-12-18]{cjk-font,latin-font} % \begin{syntax} @@ -1049,8 +1085,6 @@ To produce the documentation run the original source files ending with % \cs{mainmatter} 标志着正文的开始,使用阿拉伯数字重新进行页码编号,并设置页眉格式。 % \end{function} % -% 在页面布局方面,页面编号居中位于页脚,本科生无页眉,研究生页眉包括章名(奇数页)和节名(偶数页)。 -% % \begin{function}{\chapter,\section,\subsection,\subsubsection} % \begin{syntax} % \tn{chapter}\oarg{短描述}\marg{完整的章标题} @@ -1058,12 +1092,68 @@ To produce the documentation run the original source files ending with % \tn{subsection}\oarg{短描述}\marg{完整的节标题} % \tn{subsection}\oarg{短描述}\marg{完整的节标题} % \end{syntax} -% \pkg{ctex} 宏集提供了其中用于处理长标题的可选参数。对于过长的标题,目录中会使用其短描述。 +% 对于过长的标题,目录和页眉中会使用其短描述。 % \end{function} % % +% \subsubsection{页面} +% +% 在本模板预定义的页面样式中:本科生使用 \opt{plain} 样式,无页眉, +% 页面编号使用五号罗马体,居中位于页脚;研究生使用 \opt{headings} 样式, +% 页眉使用五号楷体,包括章名(奇数页右侧)和节名(偶数页左侧), +% 页面编号使用五号罗马体,居中位于页脚。在单面模式下,页眉会同时显示章节名。 +% +% 考虑到各个院系对于页眉内容的规定并不一致,本模板提供了若干个自定义选项。 +% +% \begin{function}{style/header/format,style/footer/format, +% style/header,style/header*,style/footer,style/footer*} +% \begin{syntax} +% header/format = \Arg{格式} +% footer/format = \Arg{格式} +% header = \{\Arg{位置}\Arg{内容},\Arg{位置}\Arg{内容},...\} +% header* = \{\Arg{位置}\Arg{内容},\Arg{位置}\Arg{内容},...\} +% footer = \{\Arg{位置}\Arg{内容},\Arg{位置}\Arg{内容},...\} +% footer* = \{\Arg{位置}\Arg{内容},\Arg{位置}\Arg{内容},...\} +% \end{syntax} +% 页眉页脚的格式与内容设置。带有星号的设置项供单面模式下使用。 +% \end{function} +% +% 页眉页脚的内容设置是一个逗号分隔的列表,实际上是 \cs{fancyhead} 和 +% \cs{fancyfoot} 命令的选项。前一个花括号内为大写字母指定的位置选项, +% 可使用左(\opt{L})、中(\opt{C})、右(\opt{R})。 +% 双面模式下可额外指定出现在奇数页(\opt{O})还是偶数页(\opt{E})。 +% 详细说明请参考 \pkg{fancyhdr} 的手册。 +% +% 接下来展示了一个手动设置页眉内容的例子。这里我们清空了页脚, +% 并将页眉格式设置成五号黑体,奇数页左侧为节名,右侧为页码, +% 偶数页左侧为页码,右侧为章名。 +% \begin{latexexample}[moretexcs={\njusetup,\sffamily},emph={[2]style}] +% \njusetup { +% style = { +% header/format = \small \sffamily, +% header = { +% { OR } { \thepage }, { OL } { \rightmark }, +% { EL } { \thepage }, { ER } { \leftmark } +% }, +% footer = {}, +% } +% } +% \end{latexexample} +% +% % \subsubsection{文字} % +% \begin{function}{\songti,\heiti,\kaishu,\fangsong,\zihao} +% \begin{syntax} +% \tn{zihao}\Arg{字号} +% \end{syntax} +% 字形与字号设置。 +% \end{function} +% +% 本模板继承 \pkg{ctex} 宏集提供的字形字号设置,以备不时之需。换句话说, +% 除非你有十足的把握,认为某处字体产生了偏差\footnote{在此情况下也应当直接到 +% GitHub 反馈},否则无需动用这些命令处理样式问题。 +% % \begin{function}[added=2021-09-22]{\njuline} % \begin{syntax} % \tn{njuline}\Arg{文字} @@ -1191,11 +1281,7 @@ To produce the documentation run the original source files ending with % % \subsubsection{数学} % -% 符号表可以参考 \url{https://www.caam.rice.edu/~heinken/latex/symbols.pdf}。 -% -% 单位请参考相关国家标准\footnote{GB 3100-1993, GB/T 3101-1993, GB/T 3102-1993},使用 \pkg{siunitx} 宏包。\pkg{siunitx} 是一个更新频繁的包,可能会引发兼容性问题。 -% -% 行内公式形如|$\mathrm{e}^{(a+2b)x}$|。 +% 行内公式形如 |$\mathrm{e}^{(a+2b)x}$|。 % % 带有编号的行间公式 \env{equation}。 % \begin{latexexample}[emph={[1]equation}] @@ -1204,7 +1290,20 @@ To produce the documentation run the original source files ending with % \end{equation} % \end{latexexample} % -% 如不需要编号,可以用 \env{equation*} 或者 |\[|\meta{公式}|\]|,请不要使用可能引发问题的 |$$|\meta{公式}|$$|\footnote{\url{https://tex.stackexchange.com/questions/503/why-is-preferable-to}}。 +% 如不需要编号,可以用 \env{equation*} 或者 |\[|\meta{公式}|\]|, +% 请不要使用可能引发问题的 |$$|\meta{公式}|$$|\footnote{\url{https://tex.stackexchange.com/questions/503/why-is-preferable-to}}。 +% +% +% \paragraph{符号和单位} +% +% 模板使用 \pkg{unicode-math} 配置数学字体,可以替代传统方案下的 \pkg{bm}、 +% \pkg{mathrsfs} 等宏包\footnote{\url{https://tex.stackexchange.com/questions/528831/why-doesnt-the-bm-package-work-with-the-unicode-math-package}}。 +% 相应地,也需要使用新方案提供的命令。例如,加粗数学符号的命令可以使用 +% \tn{symbf}。更多细节请查阅 \pkg{unicode-math} 手册。 +% +% 符号表可以参考 \url{https://www.caam.rice.edu/~heinken/latex/symbols.pdf}。 +% +% 单位请参考相关国家标准\footnote{GB 3100-1993, GB/T 3101-1993, GB/T 3102-1993},使用 \pkg{siunitx} 宏包。\pkg{siunitx} 是一个更新频繁的包,可能会引发兼容性问题。 % % % \paragraph{定理环境} @@ -1229,13 +1328,11 @@ To produce the documentation run the original source files ending with % \end{table} % % 使用示例如下。 -% \begin{latexexample} +% \begin{latexexample}[emph={[1]proof,definition}] % \begin{proof} % 证明我是我 % \end{proof} -% \end{latexexample} -% 普通环境。 -% \begin{latexexample} +% % \begin{definition}[他人] % 定义他人即地狱 % \end{definition} @@ -1462,16 +1559,20 @@ To produce the documentation run the original source files ending with % % 参考文献数据源理应是通过文献管理软件导出的,而不是逐条手动填写的。 % -% \subparagraph{使用EndNote} +% \subparagraph{使用 EndNote} % % 南京大学信息化建设管理服务中心已购买 \href{https://itsc.nju.edu.cn/EndNote/list.htm}{EndNote} 供全校师生免费使用,最新版为 EndNote 20。 % +% \subparagraph{使用 JabRef} % -% \subparagraph{使用Zotero} +% \href{https://www.jabref.org/}{jabRef} 是一款开源、跨平台的文献管理软件。 +% JabRef 提供了对 \hologo{BibTeX} 和 \pkg{biblatex} 的原生支持, +% 能够直接管理 \file{.bib} 文件, 还可以向 TeXstudio 等外部软件推送引用命令。 % -% \href{https://www.zotero.org/}{Zotero}是一款免费的文献管理软件,支持所有桌面平台。 +% \subparagraph{使用 Zotero} % -% 在保持 Zotero 程序运行的情况下,点击浏览器工具栏的 Zotero Connector 插件即可自动从网页抓取参考文件信息。Zotero 可以通过\href{https://github.com/l0o0/jasminum}{jasminum插件}支持中文参考文献的识别。在选中希望使用的文献后右键导出文献条目即可生成 \file{.bib} 文件。 +% \href{https://www.zotero.org/}{Zotero} 也是一款开源、跨平台的文献管理软件。 +% Zotero 更为通用,其功能可以通过 \href{https://github.com/l0o0/jasminum}{Jasminum}、\href{https://github.com/retorquere/zotero-better-bibtex}{Better BibTeX}、\href{https://github.com/bwiernik/zotero-shortdoi}{DOI Manager} 等第三方插件,以及 Zotero Connector 浏览器插件进行增强。 % % % \subsection{特殊页面} @@ -1492,23 +1593,18 @@ To produce the documentation run the original source files ending with % % \paragraph{封面图片} % -% \begin{function}[added=2021-12-23]{style/emblem-img} +% \begin{function}[added=2021-12-23,updated=2022-02-22]{ +% style/emblem-img,style/name-img} % \begin{syntax} % emblem-img = \Arg{文件} -% \end{syntax} -% 校徽图片文件。 -% \end{function} -% -% \begin{function}[added=2021-12-23]{style/name-img} -% \begin{syntax} % name-img = \Arg{文件} % \end{syntax} -% 校名图片文件。 +% 校名、校徽图片文件路径。 % \end{function} % -% 通过以上两个选项可以使用外置的校徽和校名图片。本模板封面中校徽及校名的绘制 -% 默认依赖 \pkg{njuvisual} 宏包提供的 \pkg{tikz} 矢量曲线,耗时较长, -% 在替换为外置图片后可节省约1秒的编译时长。 +% 通过以上选项可以使用外置的校徽和校名图片,两个选项\emph{任一留空}则不会生效。 +% 本模板封面中校徽及校名的绘制默认依赖 \pkg{njuvisual} 宏包提供的 \tikzlogo +% 矢量曲线,耗时较长,在替换为外置图片后可节省约1秒的编译时长。 % % % \subsubsection{摘要页} @@ -1660,6 +1756,54 @@ To produce the documentation run the original source files ending with % 本宏包的详细使用方法请参考其使用手册。 % % +% \section{宏包依赖} +% +% 在任何情况下,本模板都会\emph{显式}调用以下宏包(或文档类): +% \begin{itemize} +% \item \pkg{xtemplate} 和 \pkg{l3keys2e},用于扩展 \hologo{LaTeX3} 编程环境。 +% 它们属于 \pkg{l3packages} 宏集。 +% \item \cls{ctexbook},提供中文排版的通用框架。属于 C\hologo{TeX} +% 宏集 \cite{CTeX}。 +% \item \pkg{mathtools},增强数学功能。 +% \item \pkg{unicode-math},负责处理 Unicode 编码的 OpenType 数学字体。 +% \item \pkg{geometry},用于调整页面尺寸。 +% \item \pkg{setspace},调整行距。 +% \item \pkg{fancyhdr},处理页眉页脚。 +% \item \pkg{footmisc},处理脚注。 +% \item \pkg{ntheorem},提供增强版的定理类环境。 +% \item \pkg{enumitem},调整列表环境。 +% \item \pkg{graphicx},提供图形插入的接口。 +% \item \pkg{booktabs},绘制三线表。 +% \item \pkg{caption},用于设置题注。 +% \item \pkg{hyperref},提供交叉引用、超链接、电子书签等功能。 +% \item \pkg{cleveref},用于自动生成引用标签。 +% \item \pkg{biblatex},提供参考文献解决方案。 +% \end{itemize} +% +% 以下宏包可能被隐式载入: +% \begin{itemize} +% \item \pkg{xcolor},提供色彩支持。 +% \item \pkg{amsmath},对 \LaTeX{} 的数学排版功能进行了 +% 全面扩展。属于 \hologo{AmSLaTeX} 套件。 +% \item \pkg{biblatex-gb7714-2015},用于生成国标下的参考文献样式。 +% \item \pkg{xits},提供数学字体。 +% \end{itemize} +% +% 在开启某些选项时,本模板也会调用以下宏包: +% \begin{itemize} +% \item \pkg{fandol}、\pkg{tex-gyre} 和 \pkg{tex-gyre-math},提供自由字体。 +% \item \pkg{emptypage},在双面模式下清空空白页的页眉、页脚和页码。 +% \item \pkg{njuvisual},用于绘制封面的校名校徽。 +% \item \pkg{xeCJKfntef} 或 \pkg{lua-ul},用于在对应引擎下绘制下划线。 +% \end{itemize} +% +% 下列宏包会与本模板产生冲突,或者不能发挥预期作用: +% \begin{itemize} +% \item \pkg{natbib} 和 \pkg{gbt7714} 等 \hologo{BibTeX} 相关的参考文献宏包。 +% \item \pkg{bm} 等使用传统数学字体配置方案的宏包。 +% \end{itemize} +% +% % \begin{thebibliography}{99} % % \newcommand\urlprefix{\newline\hspace*{\fill}} @@ -1743,6 +1887,14 @@ To produce the documentation run the original source files ending with % \urlprefix\url{https://ctan.org/pkg/biblatex-gb7714-2015} % \urlprefix\CTANurl[文档:]{biblatex-contrib/biblatex-gb7714-2015/biblatex-gb7714-2015.pdf} % +% \bibitem{CTeX} +% \textsc{CTEX.ORG}. +% \newblock \textit{\CTeX{} 宏集手册} [EB/OL]. +% \newblock version 2.5.8, +% \newblock (2021-12-12) +% \urlprefix\url{https://ctan.org/pkg/ctex} +% \urlprefix\CTANurl[文档及源代码:]{language/chinese/ctex/ctex.pdf} +% % \bibitem{latexmk} % \textsc{Collins J}. % \newblock \textit{Fully automated \hologo{LaTeX} document generation} [EB/OL]. @@ -1872,15 +2024,15 @@ To produce the documentation run the original source files ending with % 本模板使用 \hologo{LaTeX3} 语法编写,依赖 \pkg{expl3} 环境, % 并需调用 \pkg{l3packages} 中的相关宏包。 % -% 以下代码中有一些形如 \textsf{\color{guard@series!!}〈*class〉} -% 的标记,这是 \pkg{DocStrip} 中的“guard”,用来选择性地提取文件。 +% 以下代码中有一些形如 \agrd{*class} 的标记, +% 这是 \pkg{DocStrip} 中的“guard”,用来选择性地提取文件。 % “|*|”和“|/|”分别表示该部分的开始和结束。不含 % “|*|”和“|/|”的 guard 出现在行号右侧,它们用来确定 % 单独一行代码的归属。这些 guard 的颜色深浅不一,用以明确嵌套关系。 % -% 另有若干包含 \grd{@@} 的 guard,用以表示名空间(模块)。 +% 另有若干包含 \bgrd{@@} 的 guard,用以表示名空间(模块)。 % 在删除注释生成格式文件时,源代码变量名称中的 |@@| 会被等号后的字段替换, -% 譬如在本模板中 \grd{〈@@=nju〉}。 +% 譬如在本模板主体部分中 \bgrd{〈@@=nju〉}。 % % % \subsection{准备} @@ -1898,17 +2050,15 @@ To produce the documentation run the original source files ending with \msg_new:nnn { njuthesis } { l3-too-old } { Package~ "#1"~ is~ too~ old. \\ - Please~ update~ an~ up-to-date~ version~ of~ - the~ bundles "l3kernel"~ and~ "l3packages"~ - using~ your~ TeX~ package~ manager~ or~ from~ \\ - CTAN. + Please~ update~ an~ up-to-date~ version~ of~ the~ + bundles~ "l3kernel"~ and~ "l3packages"~ using~ + your~ TeX~ package~ manager~ or~ from~ CTAN. } \clist_map_inline:nn { xtemplate, l3keys2e } { \@ifpackagelater {#1} { 2020/10/01 } { } { \msg_error:nnn { njuthesis } { l3-too-old } {#1} } } - % \end{macrocode} % % 目前 \cls{njuthesis} 仅支持 \hologo{XeTeX} 和 \hologo{LuaTeX}。 @@ -1921,14 +2071,10 @@ To produce the documentation run the original source files ending with You~ must~ change~ your~ typesetting~ engine~ to~ "xelatex"~ or~ "lualatex". } -\sys_if_engine_xetex:F - { - \sys_if_engine_luatex:F - { - \msg_fatal:nnx { njuthesis } { unsupported-engine } - { \c_sys_engine_str } - } - } +\bool_lazy_or:nnF + { \sys_if_engine_xetex_p: } + { \sys_if_engine_luatex_p: } + { \msg_fatal:nnx { njuthesis } { unsupported-engine } { \c_sys_engine_str } } % \end{macrocode} % % @@ -1949,13 +2095,13 @@ To produce the documentation run the original source files ending with % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_@@_info_degree_int, -% \l_@@_info_diploma_int,\l_@@_info_type_int} +% \begin{variable}{\g_@@_info_degree_int, +% \l_@@_info_diploma_int,\g_@@_info_type_int} % 用于存储学位类型的变量。 % \begin{macrocode} -\int_new:N \l_@@_info_degree_int +\int_new:N \g_@@_info_degree_int \int_new:N \l_@@_info_diploma_int -\int_new:N \l_@@_info_type_int +\int_new:N \g_@@_info_type_int % \end{macrocode} % \end{variable} % @@ -1992,22 +2138,30 @@ To produce the documentation run the original source files ending with % \end{macrocode} % \end{variable} % -% \begin{variable}{\g_@@_load_sys_font_bool} -% 定义用于判断是否需要载入系统预装字体的变量。 +% \begin{variable}{\g_@@_latin_font_tl,\g_@@_cjk_font_tl} +% 用于存储所使用字体名称的全局变量。 % \begin{macrocode} -\bool_new:N \g_@@_load_sys_font_bool +\tl_new:N \g_@@_latin_font_tl +\tl_new:N \g_@@_cjk_font_tl % \end{macrocode} % \end{variable} % -% \begin{variable}{\g_@@_latin_font_tl,\g_@@_cjk_font_tl} -% 用于存储所使用字体名称的全局变量 +% \begin{variable}{\g_@@_config_tl} +% 保存配置文件名称。默认为空。 % \begin{macrocode} -\tl_new:N \g_@@_latin_font_tl -\tl_new:N \g_@@_cjk_font_tl +\tl_new:N \g_@@_config_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_theorem_type_clist} +% 定理类型。 +% \begin{macrocode} +\clist_new:N \g_@@_theorem_type_clist % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_@@_info_sm_date_tl,\l_@@_info_sm_date_en_tl,\l_@@_info_df_date_tl} +% \begin{variable}{\l_@@_info_sm_date_tl,\l_@@_info_sm_date_en_tl, +% \l_@@_info_df_date_tl} % 用于存储格式化后的论文提交日期和答辩日期的变量。 % \begin{macrocode} \tl_new:N \l_@@_info_sm_date_tl @@ -2074,7 +2228,8 @@ To produce the documentation run the original source files ending with % \end{macro} % % \begin{macro}{\@@_vskip:N} -% 类似于 \hologo{LaTeX2e} 中的 \tn{vspace*},从上一个页面元素底部开始生成 |skip|。 +% 类似于 \hologo{LaTeX2e} 中的 \tn{vspace*}, +% 从上一个页面元素底部开始生成 |skip|。 % \begin{macrocode} \cs_new_protected:Npn \@@_vskip:N #1 { @@ -2099,6 +2254,17 @@ To produce the documentation run the original source files ending with % \end{macrocode} % \end{macro} % +% \begin{macro}{\@@_add_theorem_type:nnn} +% 添加已知的定理环境类型。 +% \begin{macrocode} +\cs_new_protected:Npn \@@_add_theorem_type:nnn #1#2#3 + { + \clist_gput_right:Nn \g_@@_theorem_type_clist { #1 } + \@@_define_name:nnn { #1 } { #2 } { #3 } + } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_name:n,\@@_info:n} % 根据变量名调用名称和内容信息。 % \begin{macrocode} @@ -2124,7 +2290,7 @@ To produce the documentation run the original source files ending with % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_spread_box:nnn} +% \begin{macro}{\@@_spread_box:nnn,\@@_spread_box:nnV,\@@_spread_box:nnx} % 分散对齐的水平盒子。 % \begin{arguments} % \item 宽度,|dim| 型变量 @@ -2132,13 +2298,14 @@ To produce the documentation run the original source files ending with % \item 内容,不可带有格式 % \end{arguments} % \begin{macrocode} -\cs_generate_variant:Nn \tl_map_inline:nn { xn } \cs_new_protected:Npn \@@_spread_box:nnn #1#2#3 { \mode_leave_vertical: \hbox_to_wd:nn { #1 } - { #2 \tl_map_inline:xn { #3 } { ##1 \hfil } \unskip } + { #2 \tl_map_inline:nn { #3 } { ##1 \hfil } \unskip } } +\cs_generate_variant:Nn \@@_spread_box:nnn { nnV } +\cs_generate_variant:Nn \@@_spread_box:nnn { nnx } % \end{macrocode} % \end{macro} % @@ -2299,6 +2466,286 @@ To produce the documentation run the original source files ending with % \end{macrocode} % \end{macro} % +% \subsubsection{封面相关} +% \changes{v0.16}{2022/03/10}{将封面和摘要内部函数定义移动到前部。} +% +% \begin{macro}{\@@_split_title:n,\@@_split_title:V} +% 分割标题。 +% \begin{macrocode} +\cs_new_protected:Npn \@@_split_title:n #1 + { + \tl_if_in:nnTF { #1 } { \\ } + { +% \end{macrocode} +% 从 |\\| 进行分割,存入 |clist|。 +% \begin{macrocode} + \seq_set_split:Nnn \l_@@_tmp_seq { \\ } { #1 } + \clist_set_from_seq:NN \l_@@_tmp_clist \l_@@_tmp_seq + } + { +% \end{macrocode} +% 如果没找到换行符,则手动从固定宽度的位置进行分割。 +% \begin{macrocode} + \@@_put_inempty_seg:nnn { #1 } { 1 } { 15 } + \@@_put_inempty_seg:nnn { #1 } { 16 } { 15 } + \@@_put_inempty_seg:nnn { #1 } { 31 } { 15 } + } + } +\cs_generate_variant:Nn \@@_split_title:n { V } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_multiline_title:nnn} +% 生成多行标题。 +% \begin{arguments} +% \item 内容格式 +% \item 名称盒子宽度,|dim| 型变量 +% \item 内容盒子宽度,|dim| 型变量 +% \end{arguments} +% \begin{macrocode} +\cs_new_protected:Npn \@@_multiline_title:nnn #1#2#3 + { + \@@_split_title:V \l_@@_info_title_tl + \@@_spread_box:nnV { #2 } { \kaishu } \c_@@_name_title_tl + \@@_hskip: + \clist_map_inline:Nn \l_@@_tmp_clist + { \@@_ulined_center_box:nn { #3 } { #1 ##1 } \@@_vskip: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_cover_entry:nnn} +% 生成单项信息条目。 +% \begin{arguments} +% \item 条目名称 +% \item 名称盒子宽度,|dim| 型变量 +% \item 内容盒子宽度,|dim| 型变量 +% \end{arguments} +% \begin{macrocode} +\cs_new_protected:Npn \@@_cover_entry:nnn #1#2#3 + { + \@@_spread_box:nnx { #2 } { \kaishu } { \@@_name:n { #1 } } + \@@_hskip: + \@@_ulined_center_box:nn { #3 } { \@@_info:n { #1 } } + \@@_vskip: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_cover_bientry:nnnn} +% 生成两项信息条目,仅用于本科生封面。 +% \begin{arguments} +% \item 左侧条目名称 +% \item 右侧条目名称 +% \item 名称盒子宽度,|dim| 型变量 +% \item 内容盒子宽度,|dim| 型变量 +% \end{arguments} +% \begin{macrocode} +\cs_new_protected:Npn \@@_cover_bientry:nnnn #1#2#3#4 + { + \@@_spread_box:nnx { #3 } { \kaishu } { \@@_name:n { #1 } } + \@@_hskip: + \@@_ulined_center_box:nn { #4 } { \@@_info:n { #1 } } + \skip_horizontal:n { 0.5 em } + \@@_spread_box:nnx { #3 } { \kaishu } { \@@_name:n { #2 } } + \@@_hskip: + \@@_ulined_center_box:nn { #4 } { \@@_info:n { #2 } } + \@@_vskip: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_cover_supv_entry:nnn} +% 生成两项导师信息条目,仅用于本科生封面。 +% \begin{arguments} +% \item 条目名称 +% \item 长内容盒子宽度,|dim| 型变量 +% \item 短内容盒子宽度,|dim| 型变量 +% \end{arguments} +% \begin{macrocode} +\cs_new_protected:Npn \@@_cover_supv_entry:nnn #1#2#3 + { + \@@_spread_box:nnx { #2 } { \kaishu } { \@@_name:n { #1 } } + \@@_hskip: + \@@_ulined_center_box:nn { #3 } + { \clist_item:cn { l_@@_info_ #1 _clist } { 1 } } + \skip_horizontal:n { 0.5 em } + \@@_spread_box:nnV { #2 } { \kaishu } \c_@@_name_supv_ttl_tl + \@@_hskip: + \@@_ulined_center_box:nn { #3 } + { \clist_item:cn { l_@@_info_ #1 _clist } { 2 } } + \@@_vskip: + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{摘要相关} +% +% \begin{macro}{\@@_abs_bookmark:nn,\@@_abs_bookmark:Vn} +% \changes{v0.14}{2021/12/21}{将摘要插入目录。} +% 生成摘要的目录条目。 +% \begin{macrocode} +\cs_new_protected:Npn \@@_abs_bookmark:nn #1#2 + { + \phantomsection + \bool_if:NTF \g_@@_abs_in_toc_bool + { \@@_add_tocline:n { #1 } } + { \pdfbookmark [0] { #1 } { #2 } } + \@@_chapter_header:n { #1 } + } +\cs_generate_variant:Nn \@@_abs_bookmark:nn { Vn } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_abs_title:n,\@@_abs_title:V} +% 摘要标题双层下划线格式。 +% \begin{arguments} +% \item 宽度,|dim| 型变量 +% \end{arguments} +% \begin{macrocode} +\cs_new_protected:Npn \@@_abs_title:n #1 + { + \@@_get_text_width:Nn \l_@@_tmp_dim {#1} + \@@_uuline:n { \l_@@_tmp_dim } #1 + } +\cs_generate_variant:Nn \@@_abs_title:n { V } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{页面对象} +% \changes{v0.15}{2022/01/24}{使用 \pkg{xtemplate} 重构封面。} +% +% 本模板使用 \pkg{xtemplate} 提供的面向对象方法简化封面和摘要的绘制过程。 +% +% 以下分别从页面元素(element)和页面整体(page)的层次进行了抽象。当我们把页面部件考虑为一个对象时,它天然地只具备有限数量的属性:内容、格式、边距、对齐方式等。而具体的页面是这些对象的实例的集合,附加边距、行距等属性,创建页面只需传入一个列表调用各个 Instance 即可。通过 \pkg{xtemplate} 提供的功能,我们可以根据这些属性创建模板(template),进而能大量构建具有\emph{相似行为}的实例(instance)。这种做法能充分分离内容和样式,极大优化代码的可读性。 +% +% 声明对象类型。此类对象不需要参数。 +% \begin{macrocode} +\DeclareObjectType { nju } { \c_zero_int } +% \end{macrocode} +% +% 定义元素模板。 +% \begin{macrocode} +%<@@=njuelem> +% \end{macrocode} +% +% 声明页面元素模板接口。 +% 元素是一个页面的基本组成单位,包括文段、图片等等。一个抽象的元素应当具备以下属性: +% \begin{description} +% \item[\opt{content}] 内容,即剥离样式的元素本身 +% \item[\opt{format}] 格式,例如字号、字体 +% \item[\opt{bottom-skip}] 下间距,即与下一个元素的距离 +% \item[\opt{align}] 对齐方式,包括左对齐、右对齐、居中、正常段落 +% \end{description} +% \begin{macrocode} +\DeclareTemplateInterface { nju } { element } { \c_zero_int } + { + content : tokenlist = \c_empty_tl, + format : tokenlist = \c_empty_tl, + bottom-skip : skip = \c_zero_skip, + align : choice { l, r, c, n } = c + } +% \end{macrocode} +% +% 声明页面元素模板代码。涉及的变量将被自动创建。 +% \begin{macrocode} +\DeclareTemplateCode { nju } { element } { \c_zero_int } + { + content = \l_@@_content_tl, + format = \l_@@_format_tl, + bottom-skip = \l_@@_bottom_skip, + align = + { + l = + { \tl_set_eq:NN \l_@@_begin_align_tl \flushleft + \tl_set_eq:NN \l_@@_end_align_tl \endflushleft }, + r = + { \tl_set_eq:NN \l_@@_begin_align_tl \flushright + \tl_set_eq:NN \l_@@_end_align_tl \endflushright }, + c = + { \tl_set_eq:NN \l_@@_begin_align_tl \center + \tl_set_eq:NN \l_@@_end_align_tl \endcenter }, + n = + { \tl_clear:N \l_@@_begin_align_tl + \tl_clear:N \l_@@_end_align_tl } + } + } + { + \AssignTemplateKeys + \group_begin: + \l_@@_begin_align_tl + \l_@@_format_tl + \l_@@_content_tl \par + \l_@@_end_align_tl + \group_end: + \__nju_vskip:N \l_@@_bottom_skip + } +% \end{macrocode} +% +% 定义页面模板。 +% \begin{macrocode} +%<@@=njupage> +% \end{macrocode} +% +% 声明页面模板接口。 +% 页面是元素的集合。一个抽象的页面应当具备以下属性: +% \begin{description} +% \item[\opt{element}] 包含的元素,这里使用的是名称列表 +% \item[\opt{prefix}] 元素名称前缀 +% \item[\opt{format}] 格式,例如行距 +% \item[\opt{top-skip}] 上间距,即与页面顶部的距离 +% \item[\opt{bottom-skip}] 下间距,即与页面底部的距离 +% \end{description} +% \begin{macrocode} +\DeclareTemplateInterface { nju } { page } { \c_zero_int } + { + element : commalist = \c_empty_clist, + prefix : tokenlist = \c_empty_tl, + format : tokenlist = \c_empty_tl, + top-skip : skip = \c_zero_skip, + bottom-skip : skip = \c_zero_skip + } +% \end{macrocode} +% +% 声明页面模板代码。 +% \begin{macrocode} +\DeclareTemplateCode { nju } { page } { \c_zero_int } + { + element = \l_@@_element_clist, + prefix = \l_@@_prefix_tl, + format = \l_@@_format_tl, + top-skip = \l_@@_top_skip, + bottom-skip = \l_@@_bottom_skip + } + { + \AssignTemplateKeys + \newpage + \__nju_vskip:N \l_@@_top_skip + \group_begin: + \l_@@_format_tl + \clist_map_inline:Nn \l_@@_element_clist + { \UseInstance { nju } { \l_@@_prefix_tl ##1 } } + \group_end: + \__nju_vskip:N \l_@@_bottom_skip + } +%<@@=nju> +% \end{macrocode} +% +% \begin{macro}{\@@_declare_element:nn,\@@_declare_page:nn} +% 封装 \pkg{xtemplate} 提供的函数,简化创建实例的过程。 +% \begin{arguments} +% \item 实例名称 +% \item 参数列表 +% \end{arguments} +% \begin{macrocode} +\cs_new_protected:Npn \@@_declare_element:nn #1#2 + { \DeclareInstance { nju } {#1} { element } {#2} } +\cs_new_protected:Npn \@@_declare_page:nn #1#2 + { \DeclareInstance { nju } {#1} { page } {#2} } +% \end{macrocode} +% \end{macro} +% % % \subsection{模板选项} % \changes{v0.11}{2021/11/15}{进行了效率优化。} @@ -2312,20 +2759,7 @@ To produce the documentation run the original source files ending with % 学位类型,默认为本科。 % \begin{macrocode} degree .choices:nn = { ug, mg, mf, phd } - { - \int_set_eq:NN \l_@@_info_degree_int \l_keys_choice_int - \tl_set:Nn \l_@@_info_degree_tl - { - \clist_item:Nn \c_@@_name_degree_clist - { \l_@@_info_degree_int } - } -% \end{macrocode} -% 进行学位的判断。 -% \begin{macrocode} - \int_compare:nTF { \l_@@_info_degree_int == 1 } - { \tl_set:Nn \l_@@_info_diploma_tl { ug } } - { \tl_set:Nn \l_@@_info_diploma_tl { g } } - }, + { \int_gset_eq:NN \g_@@_info_degree_int \l_keys_choice_int }, degree .initial:n = ug, % \end{macrocode} % \end{macro} @@ -2334,13 +2768,7 @@ To produce the documentation run the original source files ending with % 论文类型,默认为毕业论文。 % \begin{macrocode} type .choices:nn = { thesis, design } - { - \int_set_eq:NN \l_@@_info_type_int \l_keys_choice_int - \tl_set:Nn \l_@@_info_type_tl - { \clist_item:Nn \c_@@_name_type_clist { \l_@@_info_type_int } } - \tl_put_left:Nn \l_@@_info_type_tl - { \tl_use:c { c_@@_name_ \l_@@_info_diploma_tl _tl } } - }, + { \int_gset_eq:NN \g_@@_info_type_int \l_keys_choice_int }, type .initial:n = thesis, % \end{macrocode} % \end{macro} @@ -2386,7 +2814,7 @@ To produce the documentation run the original source files ending with % % \begin{macro}{latin-font,cjk-font} % \changes{v0.14}{2021/12/12}{简化字体选项名称。} -% 定义字体选项。 +% 字体选项。 % \begin{macrocode} latin-font .choices:nn = { gyre, mac, win, none } @@ -2394,6 +2822,14 @@ To produce the documentation run the original source files ending with cjk-font .choices:nn = { fandol, founder, mac, noto, source, win, none } { \tl_set_eq:NN \g_@@_cjk_font_tl \l_keys_choice_tl }, +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{config} +% \changes{v0.16}{2022/02/23}{新增 \opt{config} 选项。} +% 配置文件路径。 +% \begin{macrocode} + config .tl_set:N = \g_@@_config_clist } % \end{macrocode} % \end{macro} @@ -2427,180 +2863,6 @@ To produce the documentation run the original source files ending with % \end{macro} % % -% \subsection{配置常量} -% TODO: 分离为单独文件 -% 通用默认名称。注意空格是忽略掉的。 -% \begin{macrocode} -\clist_map_inline:nn - { - { acknowledgement } { 致\hspace{2em}谢 }, - { id } { 学号 }, - { notation } { 符号表 }, - { orig_date } { 日期 }, - { paperlist } { 发表文章目录 }, - { pdf_creator } { LaTeX~ with~ njuthesis~ class }, - { preface } { 前\hspace{2em}言 }, - { supv_ii } { 第二导师 }, - { supv_ttl } { 职称 } - } - { \@@_define_name:nn #1 } -% \end{macrocode} -% -% 定义同时使用到中英文名称的常量。 -% \begin{macrocode} -\clist_map_inline:nn - { - { abstract } { 摘要 } { ABSTRACT }, - { appendix } { 附录 } { appendix }, - { dept } { 院系 } { DEPARTMENT }, - { figure } { 图 } { figure }, - { keywords } { 关键词: } { Keywords:~ }, - { lang } { 中文 } { 英文 }, - { nju } { 南京大学 } { Nanjing~ University }, - { table } { 表 } { table } - } - { \@@_define_name:nnn #1 } -% \end{macrocode} -% -% 针对学位的特定名称。需要放在 \cs{ProcessKeysOptions} 导入设置选项后,以使用学位信息。 -% \begin{macrocode} -\int_compare:nTF { \l_@@_info_degree_int == 1 } - { -% \end{macrocode} -% 本科默认名称。 -% \begin{macrocode} - \clist_map_inline:nn - { - { author_full } { 本科生姓名 }, - { grade } { 年级 }, - { orig_decl } { 本科毕业论文(设计)诚信承诺书 }, - { orig_sign } { 作者签名 }, - { sm_date } { 提交日期 }, - { supv } { 导师 }, - { title } { 题目 }, - { type } { 本科生毕业论文(设计、作品) }, - { ug } { 本科 } - } - { \@@_define_name:nn #1 } - \clist_map_inline:nn - { - { author } { 学生姓名 } { UNDERGRADUATE }, - { major } { 专业 } { SPECIALIZATION }, - { supv_full } { 指导教师(姓名、职称) } { MENTOR } - } - { \@@_define_name:nnn #1 } -% \end{macrocode} -% -% \begin{variable}{\c_@@_orig_decl_text_tl} -% 学位论文诚信承诺书。 -% \begin{macrocode} - \tl_const:Nn \c_@@_orig_decl_text_tl - { - 本人郑重承诺:所呈交的毕业论文(设计)(题目:)是在指导教师的指导下 - 严格按照学校和院系有关规定由本人独立完成的。本毕业论文(设计)中引用 - 他人观点及参考资源的内容均已标注引用,如出现侵犯他人知识产权的行为, - 由本人承担相应法律责任。本人承诺不存在抄袭、伪造、篡改、代写、买卖毕 - 业论文(设计)等违纪行为。 - } - } -% \end{macrocode} -% \end{variable} -% -% 研究生默认名称。 -% \begin{macrocode} - { - \clist_map_inline:nn - { - { abstract_r } { 摘要首页用纸 }, - { author_r } { 生姓名 }, - { chairman } { 答辩委员会主席: }, - { clc } { 分类号 }, - { confer } { 学位授予单位和日期 }, - { df_date } { 论文答辩日期 }, - { degree } { 申请学位级别 }, - { apply } - { (申请 \l_@@_info_degree_tl 学位) }, - { field } { 研究方向 }, - { g } { 研究生 }, - { grade } { 级 }, - { major_s } { 专业 }, - { major_nl } { 专业名称 }, - { orig_decl } { 学位论文原创性声明 }, - { orig_sign } { 研究生签名 }, - { reviewer } { 评阅人: }, - { seclv } { 密级 }, - { sign } { (签字) }, - { sm_date } { 论文提交日期 }, - { supv } { 导师 }, - { supv_r } { (姓名、职称) }, - { supv_info } { 指导教师姓名、职务、 - 职称、学位、单位名称及地址 }, - { title } { 论文题目 }, - { title_nl } { (题名和副题名) }, - { title_s } { 题目 }, - { udc } { U D C } - } - { \@@_define_name:nn #1 } - \clist_map_inline:nn - { - { author } { 作者姓名 } { POSTGRADUATE }, - { major } { 专业方向 } { SPECIALIZATION }, - { supv_full } { 指导教师 } { MENTOR } - } - { \@@_define_name:nnn #1 } -% \end{macrocode} -% -% \begin{variable}{\c_@@_cover_en_text_tl} -% 英文封面字样。 -% \begin{macrocode} - \tl_const:Nn \c_@@_cover_en_text_tl - { - A~ dissertation~ submitted~ to \\ - the~ graduate~ school~ of~ Nanjing~ University \\ - in~ partial~ fulfilment~ of~ the~ requirements~ for~ the~ degree~ of - } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_@@_orig_decl_text_tl} -% 学位论文原创性声明。 -% \begin{macrocode} - \tl_const:Nn \c_@@_orig_decl_text_tl - { - 本人郑重声明,所提交的学位论文是本人在导师指导下独立进行科学研究工作 - 所取得的成果。除本论文中已经注明引用的内容外,本论文不包含其他个人或 - 集体已经发表或撰写过的研究成果,也不包含为获得南京大学或其他教育机构 - 的学位证书而使用过的材料。对本文的研究做出重要贡献的个人和集体,均已 - 在论文的致谢部分明确标明。本人郑重申明愿承担本声明的法律责任。 - } - } -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_@@_theorem_type_clist} -% 默认定理类型。 -% \begin{macrocode} -\clist_const:Nn \c_@@_theorem_type_clist - { axiom, corollary, definition, example, lemma, theorem } -% \end{macrocode} -% \end{variable} -% -% 默认定理头名称。 -% \begin{macrocode} -\clist_map_inline:nn - { - { axiom } { 公理 } { Axiom }, - { corollary } { 推论 } { Corollary }, - { definition } { 定义 } { Definition }, - { example } { 例 } { Example }, - { lemma } { 引理 } { Lemma }, - { proof } { 证明 } { Proof }, - { theorem } { 定理 } { Theorem } - } - { \@@_define_name:nnn #1 } -% \end{macrocode} -% -% % \subsection{载入宏包} % % \changes{v0.12}{2021/12/07}{重新组织宏包载入顺序。} @@ -2610,7 +2872,7 @@ To produce the documentation run the original source files ending with { a4paper, UTF8, - scheme=chinese, + scheme = chinese, % \end{macrocode} % 传入单双面模式选项。 % \begin{macrocode} @@ -2620,18 +2882,18 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \bool_if:NT \g_@@_draft_bool { draft, } % \end{macrocode} -% 关于行距,\hologo{LaTeX} 默认1.2行距,word 默认行距是1.3,要求1.5倍 word 行距,故 -% $1.5\times\frac{1.3}{1.2} = 1.625$ +% 关于行距,\hologo{LaTeX} 默认1.2行距,MS Word 默认行距是1.3,要求1.5倍 +% Word 行距,故 $1.5\times\frac{1.3}{1.2} = 1.625$ % \begin{macrocode} - linespread=1.625, + linespread = 1.625, % \end{macrocode} % 默认不载入任何字体,供本模板自行设置。 % \begin{macrocode} - fontset=none, + fontset = none, % \end{macrocode} % 正文字体设置为小四号。 % \begin{macrocode} - zihao=-4 + zihao = -4 } { ctexbook } % \end{macrocode} @@ -2667,21 +2929,20 @@ To produce the documentation run the original source files ending with fancyhdr, setspace, % \end{macrocode} -% 南京大学视觉形象化标准宏包 \pkg{njuvisual} 用于绘制学校 logo。 -% \begin{macrocode} - njuvisual, -% \end{macrocode} -% \changes{v0.13}{2021/12/13}{使用 \pkg{ntheorem} 创建定理环境,删除 \pkg{amsthm} 和 \pkg{thmtools}。} -% 数学,\pkg{amsmath} 必须在 \pkg{unicode-math} 前加载。 -% \pkg{unicode-math} 指定了 \hologo{XeTeX} 和 \hologo{LuaTeX} 下所使用的数学字体。 -% 用于配置数学环境的 \pkg{mathtools} 会与 \pkg{unicode-math} 发生冲突,此处手动消除其警告。 +% \changes{v0.13}{2021/12/13}{使用 \pkg{ntheorem} 创建定理环境,删除 +% \pkg{amsthm} 和 \pkg{thmtools}。} +% \changes{v0.16}{2022/03/19}{不显式载入 \pkg{amsmath}。} +% 数学相关的宏包。其中,\pkg{amsmath} 必须在 \pkg{unicode-math} 前加载。 +% \pkg{unicode-math} 指定了 \hologo{XeTeX} 和 \hologo{LuaTeX} 下所使用的 +% 数学字体。用于配置数学环境的 \pkg{mathtools} 会与 \pkg{unicode-math} +% 发生冲突,需要手动消除其警告。 % \begin{macrocode} - amsmath, mathtools, unicode-math, ntheorem, % \end{macrocode} -% \changes{v0.14}{2021/12/21}{移除内置的 \pkg{multirow}、\pkg{subcaption} 和 \pkg{wrapfig}。} +% \changes{v0.14}{2021/12/21}{移除内置的 \pkg{multirow}、\pkg{subcaption} +% 和 \pkg{wrapfig}。} % 图片与表格。 % \begin{macrocode} booktabs, @@ -2731,7 +2992,7 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \msg_new:nnn { njuthesis } { package-too-old } { - Package~ "#1"~ is~ too~ old. \\ + Package~ "#1"~ is~ too~ old.\\ The~ njuthesis~ class~ only~ supports~ "#1"~ with~ a~ version higher~ than~ v#2.\\ Please~ update~ an~ up-to-date~ version~ of~ it~ @@ -2745,13 +3006,43 @@ To produce the documentation run the original source files ending with % \end{macrocode} % \end{macro} % -% 检查绘制下划线所需的 \pkg{luatexja} 包版本。该宏包在2021-09-18的更新解决了下划线中断问题,然而在2021-10-24的更新才提供了正确的内嵌日期。 +% 检查绘制下划线所需的 \pkg{luatexja} 包版本。该宏包在 2021-09-18 的更新 +% 解决了下划线中断问题,然而在 2021-10-24 的更新才提供了正确的内嵌日期。 % \begin{macrocode} \sys_if_engine_luatex:T { \@@_check_package:nnn { luatexja } { 2021/10/24 } { 20211024.0 } } % \end{macrocode} % % +% \subsection{配置文件} +% +% \cls{njuthesis} 包含\emph{本科生}和\emph{研究生}两套区别较大的模板配置。 +% 出于定义的简洁起见,本模板将其拆分为两个单独的参数配置文件, +% 编译过程中将会根据设置的学位信息,载入相应默认配置。 +% 注意,尽管在手册的实现细节部分封面、摘要、常量等位于靠后部分, +% 拆分后实际上是在此处载入运行的,务必要注意逻辑顺序。 +% +% 下文中,本科生模板配置对应 \agrd{definition-ug},用于生成 +% \file{njuthesis-undergraduate.def};研究生模板配置对应 +% \agrd{definition-g},用于生成 \file{njuthesis-graduate.def}。 +% \begin{macrocode} +\int_compare:nTF { \g_@@_info_degree_int == 1 } + { \file_input:n { njuthesis-undergraduate.def } } + { \file_input:n { njuthesis- graduate.def } } +% \end{macrocode} +% +% 载入用户设置,可用于对模板做额外修改。 +% \begin{macrocode} +\msg_new:nnn { njuthesis } { load-config } + { I~ am~ loading~ config~ file~ "#1". } +\clist_if_empty:NF \g_@@_config_clist + { + \msg_info:nnx { njuthesis } { load-config } { \g_@@_config_tl } + \clist_map_inline:Nn \g_@@_config_clist { \file_input:n { #1 } } + } +% \end{macrocode} +% +% % \subsection{个人信息} % \changes{v0.11}{2021/10/01}{将个人信息变量名改为小写字母加连字符的形式。} % \changes{v0.15}{2022/01/22}{将个人信息设置移到载入宏包后。} @@ -2858,8 +3149,31 @@ To produce the documentation run the original source files ending with % \end{macrocode} % \end{macro} % +% \changes{v0.16}{2022/03/06}{正确处理学位和类型信息。} +% 设置学位信息。该设置需要放在 \cs{ProcessKeysOptions} +% 命令以及载入配置文件中的常量信息后进行。 +% \begin{macrocode} +\tl_set:Nx \l_@@_info_degree_tl + { + \clist_item:Nn \c_@@_name_degree_clist + { \g_@@_info_degree_int } + } +\int_compare:nTF { \g_@@_info_degree_int == 1 } + { \tl_set:Nn \l_@@_info_diploma_tl { ug } } + { \tl_set:Nn \l_@@_info_diploma_tl { g } } +% \end{macrocode} +% +% 设置类型信息。 +% \begin{macrocode} +\tl_set:Nx \l_@@_info_type_tl + { \clist_item:Nn \c_@@_name_type_clist { \g_@@_info_type_int } } +\tl_put_left:Nx \l_@@_info_type_tl + { \tl_use:c { c_@@_name_ \l_@@_info_diploma_tl _tl } } +% \end{macrocode} +% % \changes{v0.15}{2022/01/22}{正确处理双导师信息。} -% 在导言区录入用户信息后进行变量设置。此处使用到了 \pkg{ctex} 提供的命令,应当位于载入文档类之后。 +% 在导言区录入用户信息后进行变量设置。此处使用到了 \pkg{ctex} 提供的命令, +% 应当位于载入文档类之后。 % \begin{macrocode} \ctex_at_end_preamble:n { @@ -2894,7 +3208,7 @@ To produce the documentation run the original source files ending with % \end{macrocode} % 英文提交日期以及答辩日期仅用于研究生封面。 % \begin{macrocode} - \int_compare:nF { \l_@@_info_degree_int == 1 } + \int_compare:nF { \g_@@_info_degree_int == 1 } { \tl_set:Nn \l_@@_info_sm_date_en_tl { @@ -2920,29 +3234,32 @@ To produce the documentation run the original source files ending with % 判断用户是否自定义了中英文字体。如果其中任意一种未被定义, % 则使用系统预装字体覆盖字体选项。 % \begin{macrocode} -\tl_if_empty:NTF \g_@@_latin_font_tl - { \bool_gset_true:N \g_@@_load_sys_font_bool } - { - \tl_if_empty:NT \g_@@_cjk_font_tl - { \bool_gset_true:N \g_@@_load_sys_font_bool } - } +\bool_lazy_or:nnT + { \tl_if_empty_p:N \g_@@_latin_font_tl } + { \tl_if_empty_p:N \g_@@_cjk_font_tl } % \end{macrocode} -% -% 进行系统检测。 +% 进行操作系统检测。 % 检测 Windows 的命令由 \pkg{l3kernel} 提供, % 检测 macOS 的命令由 \pkg{ctex} 提供, % 这两种情况外的系统被判断为 Linux,一律使用自由字体。 % \begin{macrocode} -\bool_if:NT \g_@@_load_sys_font_bool { \sys_if_platform_windows:TF - { \tl_set:Nn \g_@@_latin_font_tl { win } - \tl_set:Nn \g_@@_cjk_font_tl { win } } - { \ctex_if_platform_macos:TF - { \tl_set:Nn \g_@@_latin_font_tl { mac } - \tl_set:Nn \g_@@_cjk_font_tl { mac } } - { \tl_set:Nn \g_@@_latin_font_tl { gyre } - \tl_set:Nn \g_@@_cjk_font_tl { fandol } } } + { + \tl_set:Nn \g_@@_latin_font_tl { win } + \tl_set:Nn \g_@@_cjk_font_tl { win } + } + { + \ctex_if_platform_macos:TF + { + \tl_set:Nn \g_@@_latin_font_tl { mac } + \tl_set:Nn \g_@@_cjk_font_tl { mac } + } + { + \tl_set:Nn \g_@@_latin_font_tl { gyre } + \tl_set:Nn \g_@@_cjk_font_tl { fandol } + } + } } % \end{macrocode} % @@ -2956,9 +3273,10 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \cs_new_protected:Npn \@@_load_latin_font_win: { - \setmainfont{Times~New~Roman} - \setsansfont{Arial} - \setmonofont{Courier~New}[Scale=MatchLowercase] + \setmainfont { Times~New~Roman } + \setsansfont { Arial } + \setmonofont { Courier~New } + [ Scale = MatchLowercase ] } % \end{macrocode} % \end{macro} @@ -2968,9 +3286,10 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \cs_new_protected:Npn \@@_load_latin_font_mac: { - \setmainfont{Times~New~Roman} - \setsansfont{Arial} - \setmonofont{Menlo}[Scale=MatchLowercase] + \setmainfont { Times~New~Roman } + \setsansfont { Arial } + \setmonofont { Menlo } + [ Scale = MatchLowercase ] } % \end{macrocode} % \end{macro} @@ -2980,26 +3299,32 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \cs_new_protected:Npn \@@_load_latin_font_gyre: { - \setmainfont{texgyretermes}[ - Extension=.otf, - UprightFont=*-regular, - BoldFont=*-bold, - ItalicFont=*-italic, - BoldItalicFont=*-bolditalic] - \setsansfont{texgyreheros}[ - Extension=.otf, - UprightFont=*-regular, - BoldFont=*-bold, - ItalicFont=*-italic, - BoldItalicFont=*-bolditalic] - \setmonofont{texgyrecursor}[ - Extension=.otf, - UprightFont=*-regular, - BoldFont=*-bold, - ItalicFont=*-italic, - BoldItalicFont=*-bolditalic, - Scale=MatchLowercase, - Ligatures=CommonOff] + \setmainfont { texgyretermes } + [ + Extension = .otf, + UprightFont = *-regular, + BoldFont = *-bold, + ItalicFont = *-italic, + BoldItalicFont = *-bolditalic + ] + \setsansfont { texgyreheros } + [ + Extension = .otf, + UprightFont = *-regular, + BoldFont = *-bold, + ItalicFont = *-italic, + BoldItalicFont = *-bolditalic + ] + \setmonofont { texgyrecursor } + [ + Extension = .otf, + UprightFont = *-regular, + BoldFont = *-bold, + ItalicFont = *-italic, + BoldItalicFont = *-bolditalic, + Scale = MatchLowercase, + Ligatures = CommonOff + ] } % \end{macrocode} % \end{macro} @@ -3007,10 +3332,10 @@ To produce the documentation run the original source files ending with % % \subsubsection{定义中文字库} % -% \begin{macro}{\@@_diable_no_script_msg:} -% 移除 |does not contain script "CJK"| 警告。 +% \begin{macro}{\@@_hide_no_script_msg:} +% 隐藏 |does not contain script "CJK"| 警告。 % \begin{macrocode} -\cs_new_protected:Npn \@@_diable_no_script_msg: +\cs_new_protected:Npn \@@_hide_no_script_msg: { \msg_redirect_name:nnn { fontspec } { no-script } { info } } % \end{macrocode} % \end{macro} @@ -3039,7 +3364,7 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \cs_new_protected:Npn \@@_load_cjk_font_mac: { - \@@_diable_no_script_msg: + \@@_hide_no_script_msg: \setCJKmainfont{Songti~SC~Light}[ BoldFont=Songti~SC~Bold, ItalicFont=Kaiti~SC, @@ -3060,25 +3385,37 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \cs_new_protected:Npn \@@_load_cjk_font_fandol: { - \@@_diable_no_script_msg: - \setCJKmainfont{FandolSong-Regular}[ - Extension=.otf, - BoldFont=FandolSong-Bold, - ItalicFont=FandolKai-Regular] - \setCJKsansfont{FandolHei-Regular}[ - Extension=.otf, - BoldFont=FandolHei-Bold] - \setCJKmonofont{FandolFang-Regular}[Extension=.otf] - \setCJKfamilyfont{zhsong}{FandolSong-Regular}[ - Extension=.otf, - BoldFont=FandolSong-Bold] - \setCJKfamilyfont{zhhei}{FandolHei-Regular}[ - Extension=.otf, - BoldFont=FandolHei-Bold] - \setCJKfamilyfont{zhfs}{FandolFang-Regular}[Extension=.otf] - \setCJKfamilyfont{zhkai}{FandolKai-Regular}[ - Extension=.otf, - AutoFakeBold=2.17] + \@@_hide_no_script_msg: + \setCJKmainfont { FandolSong-Regular } + [ + Extension = .otf, + BoldFont = FandolSong-Bold, + ItalicFont = FandolKai-Regular + ] + \setCJKsansfont { FandolHei-Regular } + [ + Extension = .otf, + BoldFont = FandolHei-Bold + ] + \setCJKmonofont { FandolFang-Regular } + [ Extension = .otf ] + \setCJKfamilyfont { zhsong } { FandolSong-Regular } + [ + Extension = .otf, + BoldFont = FandolSong-Bold + ] + \setCJKfamilyfont { zhhei } { FandolHei-Regular } + [ + Extension = .otf, + BoldFont = FandolHei-Bold + ] + \setCJKfamilyfont { zhfs } { FandolFang-Regular } + [ Extension = .otf ] + \setCJKfamilyfont { zhkai } { FandolKai-Regular } + [ + Extension = .otf, + AutoFakeBold = 2.17 + ] } % \end{macrocode} % \end{macro} @@ -3103,9 +3440,9 @@ To produce the documentation run the original source files ending with \setCJKfamilyfont { zhsong } { FZShuSong-Z01 } [ BoldFont = FZXiaoBiaoSong-B05 ] \setCJKfamilyfont { zhhei } { FZHei-B01 } - [AutoFakeBold=2.17] + [ AutoFakeBold = 2.17 ] \setCJKfamilyfont { zhkai } { FZKai-Z03 } - [AutoFakeBold=2.17] + [ AutoFakeBold = 2.17 ] \setCJKfamilyfont { zhfs } { FZFangSong-Z02 } \defaultCJKfontfeatures{} } @@ -3212,7 +3549,7 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \@@_load_math_font: % \end{macrocode} -% 自行定义 C\hologo{TeX} 中的四类字体命令。 +% 自行定义 \pkg{ctex} 中的四类字体命令。 % \begin{macrocode} \NewDocumentCommand \songti { } { \CJKfamily { zhsong } } \NewDocumentCommand \heiti { } { \CJKfamily { zhhei } } @@ -3249,16 +3586,110 @@ To produce the documentation run the original source files ending with % 草稿模式下显示页面文字范围边界以及页眉、页脚线。 % \begin{macrocode} \bool_if:NT \g_@@_draft_bool { \geometry { showframe } } +%</class> % \end{macrocode} % % % \subsubsection{页眉页脚} % -% \begin{macro}{\@@_fancy_head:nn} -% 页眉样式,设置为小号字体、楷书。这里对 \pkg{fancyhdr} 的命令进行了包装。 +% \begin{variable}{\c_@@_pagestyle_tl} +% 针对不同学位类型的默认页面样式设置。 +% \begin{macrocode} +%<definition-ug>\tl_const:Nn \c_@@_pagestyle_tl { plain } +%<definition-g>\tl_const:Nn \c_@@_pagestyle_tl { headings } +% \end{macrocode} +% \end{variable} +% +% 提供设置页眉页脚的用户接口。在 \cs{fancyhead} 的可选参数中, +% \opt{E} 和 \opt{O} 分别表示在偶数页(even)和奇数页(odd), +% 而 \opt{L}、\opt{R} 和 \opt{C} 则分别表示左(left)、右 +% (right)和中间(center)。按照通常的排版规则,在双面模式下, +% 偶数页的中间页眉文字在左,奇数页则在右。单面模式下,左右页眉都要显示。 +% \begin{macrocode} +%<*class> +\keys_define:nn { nju / style } + { +% \end{macrocode} +% \begin{macro}{style/header/format} +% \changes{v0.16}{2022/03/18}{可手动指定页眉样式。} +% 页眉格式。 +% \begin{macrocode} + header/format .tl_gset:N = \g_@@_header_format_tl, + header/format .initial:n = \small \kaishu, +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{style/header,style/header*} +% \changes{v0.16}{2022/03/18}{可手动指定页眉内容。} +% 页眉内容,分别对应双面模式和单面模式。 +% 为了便于指定复杂的页眉样式,这里用 |clist| 存储位置和内容信息。 +% \begin{macrocode} + header .clist_gset:N = \g_@@_header_twoside_clist, + header* .clist_gset:N = \g_@@_header_oneside_clist, + header .initial:n = + { + { EL } { \leftmark }, { OR } { \rightmark } + }, + header* .initial:n = + { + { L } { \leftmark }, { R } { \rightmark } + }, +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{style/footer/format} +% \changes{v0.16}{2022/03/19}{可手动指定页脚样式。} +% 页脚格式。 +% \begin{macrocode} + footer/format .tl_gset:N = \g_@@_footer_format_tl, + footer/format .initial:n = \small \rmfamily, +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{style/footer,style/footer*} +% \changes{v0.16}{2022/03/18}{可手动指定页脚内容。} +% 页脚内容,同页眉。 +% \begin{macrocode} + footer .clist_gset:N = \g_@@_footer_twoside_clist, + footer* .clist_gset:N = \g_@@_footer_oneside_clist, + footer .initial:n = { { C } { \thepage } }, + footer* .initial:n = { { C } { \thepage } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_@@_header_clist,\g_@@_footer_clist} +% 设置页眉页脚。 +% \begin{macrocode} +\clist_new:N \g_@@_header_clist +\clist_new:N \g_@@_footer_clist +% \end{macrocode} +% \end{macro} +% +% 在导言区末尾确定页眉页脚内容。 % \begin{macrocode} -\cs_new_protected:Npn \@@_fancy_head:nn #1#2 - { \fancyhead [#1] { \small \kaishu \nouppercase {#2} } } +\ctex_at_end_preamble:n + { + \bool_if:NTF \g_@@_twoside_bool + { + \clist_set_eq:NN \g_@@_header_clist \g_@@_header_twoside_clist + \clist_set_eq:NN \g_@@_footer_clist \g_@@_footer_twoside_clist + } + { + \clist_set_eq:NN \g_@@_header_clist \g_@@_header_oneside_clist + \clist_set_eq:NN \g_@@_footer_clist \g_@@_footer_oneside_clist + } + } +% \end{macrocode} +% +% \begin{macro}{\@@_header:nn,\@@_footer:nn} +% 对 \pkg{fancyhdr} 的命令进行包装,便于设置页眉页脚。 +% \begin{macrocode} +\cs_new_protected:Npn \@@_header:nn #1#2 + { \fancyhead [#1] { \g_@@_header_format_tl #2 } } +\cs_new_protected:Npn \@@_footer:nn #1#2 + { \fancyfoot [#1] { \g_@@_footer_format_tl #2 } } % \end{macrocode} % \end{macro} % @@ -3269,45 +3700,40 @@ To produce the documentation run the original source files ending with \fancypagestyle { plain } { \fancyhf { } - \fancyfoot [ C ] { \zihao { 5 } \rmfamily \thepage } + \clist_map_inline:Nn \g_@@_footer_clist { \@@_footer:nn ##1 } \tl_set:Nn \headrulewidth { \c_zero_dim } \tl_set:Nn \footrulewidth { \c_zero_dim } } % \end{macrocode} % -% \begin{macro}{\@@_set_heading_g:} % \changes{v0.15}{2022/01/17}{修复单页模式的页眉问题。} -% 以 \opt{plain} 样式为基础,单独设置研究生模板的页眉内容。在 \cs{fancyhead} 的 -% 可选参数中,\opt{E} 和 \opt{O} 分别表示在偶数页(even)和奇数页(odd), 而 -% \opt{L}、\opt{R} 和 \opt{C} 则分别表示左(left)、右(right)和中间(center) -% 。按照通常的排版规则,在双面模式下,偶数页的中间页眉文字在左,奇数页则在右。 -% 单面模式下,左右页眉都要显示。 +% 以 \opt{plain} 样式为基础的 \opt{headings} 样式,用于研究生模板。 % \begin{macrocode} -\cs_new_protected:Npn \@@_set_heading_g: +\fancypagestyle { headings } { - \bool_if:NTF \g_@@_twoside_bool + \fancyhf { } + \clist_if_empty:NTF \g_@@_header_clist { - \@@_fancy_head:nn { EL } { \leftmark } - \@@_fancy_head:nn { OR } { \rightmark } + \tl_set:Nn \headrulewidth { \c_zero_dim } } { - \@@_fancy_head:nn { L } { \leftmark } - \@@_fancy_head:nn { R } { \rightmark } + \tl_set:Nn \headrulewidth { 0.4 pt } + \dim_set:Nn \headheight { 20 pt } + \clist_map_inline:Nn \g_@@_header_clist + { \@@_header:nn ##1 } } - \tl_set:Nn \headrulewidth { 0.4 pt } - \dim_set:Nn \headheight { 20 pt } + \clist_map_inline:Nn \g_@@_footer_clist { \@@_footer:nn ##1 } + \tl_set:Nn \footrulewidth { \c_zero_dim } } % \end{macrocode} -% \end{macro} % % \begin{macro}{\frontmatter} -% 重定义 \cs{frontmatter},清空页眉页脚以及页码设置。 -% 此命令仅为解决原 \cls{book} 类中默认使用小写罗马字母序号的冲突,并不建议使用。 +% 重定义 \cs{frontmatter},设置前言区默认的页眉页脚以及页码样式。 % \begin{macrocode} \RenewDocumentCommand \frontmatter { } { \cleardoublepage - \pagestyle { empty } + \exp_args:NV \pagestyle \c_@@_pagestyle_tl \pagenumbering { Roman } } % \end{macrocode} @@ -3316,21 +3742,29 @@ To produce the documentation run the original source files ending with % \begin{macro}{\mainmatter} % \changes{v0.12}{2021/12/03}{修复了摘要页字体格式泄漏到正文的问题。} % \changes{v0.12}{2021/12/03}{修复了页眉上长标题重叠的问题。} -% 重定义 \cs{mainmatter},在论文主体部分载入页眉页脚设置,使用阿拉伯数字重新进行 -% 页码编号。 +% 重定义 \cs{mainmatter},在论文主体部分载入页面样式设置, +% 使用阿拉伯数字重新进行页码编号。 % \begin{macrocode} \RenewDocumentCommand \mainmatter { } { \cleardoublepage - \pagestyle { plain } - \int_compare:nF { \l_@@_info_degree_int == 1 } - { \@@_set_heading_g: } + \exp_args:NV \pagestyle \c_@@_pagestyle_tl \pagenumbering { arabic } \normalfont \normalsize } % \end{macrocode} % \end{macro} % +% \changes{v0.16}{2022/03/18}{研究生模板的目录、摘要等页面也显示页眉。} +% 在文档起始位置设置默认页面样式。 +% \begin{macrocode} +\AtBeginEnvironment { document } + { + \exp_args:NV \pagestyle \c_@@_pagestyle_tl + \pagenumbering { Roman } + } +% \end{macrocode} +% % % \subsection{章节标题格式} % @@ -3379,7 +3813,7 @@ To produce the documentation run the original source files ending with % \begin{macro}{\njuchapter} % 封装无编号章环境,供用户在正文中使用。 % \begin{macrocode} -\NewDocumentCommand \njuchapter { m } { \@@_chapter:V { #1 } } +\NewDocumentCommand \njuchapter { m } { \@@_chapter:n { #1 } } % \end{macrocode} % \end{macro} % @@ -3587,7 +4021,7 @@ To produce the documentation run the original source files ending with % 如果需要在每章后附上一个参考文献表,即对 \pkg{biblatex} 传入了 % |refsection = chapter| 选项,则默认为 |section| 级别。 % \begin{macrocode} - \defbibheading { njubibintoc } [ \bibname ] { \@@_chapter:V { ##1 } } + \defbibheading { njubibintoc } [ \bibname ] { \@@_chapter:n { ##1 } } \tl_if_eq:NnTF \blx@refsecreset@level { 2 } { \DeclarePrintbibliographyDefaults { heading = subbibintoc } } { \DeclarePrintbibliographyDefaults { heading = njubibintoc } } @@ -3641,7 +4075,7 @@ To produce the documentation run the original source files ending with } % \end{macrocode} % -% \begin{macro}{\@@_cref_name:n,} +% \begin{macro}{\@@_cref_name:n,\@@_cref_name:V} % 用于修改 \pkg{cleverref} 的标签名称的辅助函数。 % \begin{macrocode} \cs_new_protected:Npn \@@_cref_name:n #1 @@ -3652,6 +4086,7 @@ To produce the documentation run the original source files ending with { \@@_name:n { ##1 } } { \@@_name:n { ##1 _en } } } } +\cs_generate_variant:Nn \@@_cref_name:n { V } % \end{macrocode} % \end{macro} % @@ -3668,7 +4103,7 @@ To produce the documentation run the original source files ending with % 修改 \pkg{cleverref} 的标签名称。 % \begin{macrocode} \@@_cref_name:n { figure, table, appendix, proof } -\exp_args:NV \@@_cref_name:n \c_@@_theorem_type_clist +\@@_cref_name:V \g_@@_theorem_type_clist % \end{macrocode} % % @@ -3679,6 +4114,12 @@ To produce the documentation run the original source files ending with \DeclareGraphicsExtensions { .pdf, .eps, .jpg, .png } % \end{macrocode} % +% \changes{v0.16}{2022/03/11}{表格内字体设为五号。} +% 表格默认居中,字号设置为五号。^^A https://www.zhihu.com/question/366803177/answer/977853129 +% \begin{macrocode} +\BeforeBeginEnvironment { tabular } { \centering \zihao {5} } +% \end{macrocode} +% % \changes{v0.12}{2021/12/06}{删除了可能导致冲突的 \pkg{floatrow}。} % 图表标题样式。文字设置为五号宋体,标签设置为粗体,间隔一个全角空格。 % \begin{macrocode} @@ -3728,311 +4169,29 @@ To produce the documentation run the original source files ending with \newtheorem* { proof } { \c_@@_name_proof_tl } % \end{macrocode} % -% 定义普通定理环境。 +% 定义普通定理环境,需要排除 \env{proof}。 % \begin{macrocode} -\@@_new_theorem:N \c_@@_theorem_type_clist +\group_begin: + \clist_remove_all:Nn \g_@@_theorem_type_clist { proof } + \@@_new_theorem:N \g_@@_theorem_type_clist +\group_end: +%</class> % \end{macrocode} % % % \subsection{封面} % -% \subsubsection{内部命令} -% -% \begin{macro}{\@@_split_title:n} -% 分割标题。 -% \begin{macrocode} -\cs_new_protected:Npn \@@_split_title:n #1 - { - \tl_if_in:VnTF { #1 } { \\ } - { -% \end{macrocode} -% 从 |\\| 进行分割,存入 |clist|。 -% \begin{macrocode} - \seq_set_split:NnV \l_@@_tmp_seq { \\ } { #1 } - \clist_set_from_seq:NN \l_@@_tmp_clist \l_@@_tmp_seq - } - { -% \end{macrocode} -% 如果没找到换行符,则手动从固定宽度的位置进行分割。 -% \begin{macrocode} - \@@_put_inempty_seg:nnn { #1 } { 1 } { 15 } - \@@_put_inempty_seg:nnn { #1 } { 16 } { 15 } - \@@_put_inempty_seg:nnn { #1 } { 31 } { 15 } - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_multiline_title:nnn} -% 生成多行标题。 -% \begin{arguments} -% \item 内容格式 -% \item 名称盒子宽度,|dim| 型变量 -% \item 内容盒子宽度,|dim| 型变量 -% \end{arguments} -% \begin{macrocode} -\cs_new_protected:Npn \@@_multiline_title:nnn #1#2#3 - { - \@@_split_title:n { \l_@@_info_title_tl } - \@@_spread_box:nnn { #2 } { \kaishu } { \c_@@_name_title_tl } - \@@_hskip: - \clist_map_inline:Nn \l_@@_tmp_clist - { \@@_ulined_center_box:nn { #3 } { #1 ##1 } \@@_vskip: } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_cover_entry:nnn} -% 生成单项信息条目。 -% \begin{arguments} -% \item 条目名称 -% \item 名称盒子宽度,|dim| 型变量 -% \item 内容盒子宽度,|dim| 型变量 -% \end{arguments} -% \begin{macrocode} -\cs_new_protected:Npn \@@_cover_entry:nnn #1#2#3 - { - \@@_spread_box:nnn { #2 } { \kaishu } { \@@_name:n { #1 } } - \@@_hskip: - \@@_ulined_center_box:nn { #3 } { \@@_info:n { #1 } } - \@@_vskip: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_cover_bientry:nnnn} -% 生成两项信息条目,仅用于本科生封面。 -% \begin{arguments} -% \item 左侧条目名称 -% \item 右侧条目名称 -% \item 名称盒子宽度,|dim| 型变量 -% \item 内容盒子宽度,|dim| 型变量 -% \end{arguments} -% \begin{macrocode} -\cs_new_protected:Npn \@@_cover_bientry:nnnn #1#2#3#4 - { - \@@_spread_box:nnn { #3 } { \kaishu } { \@@_name:n { #1 } } - \@@_hskip: - \@@_ulined_center_box:nn { #4 } { \@@_info:n { #1 } } - \skip_horizontal:n { 0.5 em } - \@@_spread_box:nnn { #3 } { \kaishu } { \@@_name:n { #2 } } - \@@_hskip: - \@@_ulined_center_box:nn { #4 } { \@@_info:n { #2 } } - \@@_vskip: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_cover_supv_entry:nnn} -% 生成两项导师信息条目,仅用于本科生封面。 -% \begin{arguments} -% \item 条目名称 -% \item 长内容盒子宽度,|dim| 型变量 -% \item 短内容盒子宽度,|dim| 型变量 -% \end{arguments} -% \begin{macrocode} -\cs_new_protected:Npn \@@_cover_supv_entry:nnn #1#2#3 - { - \@@_spread_box:nnn { #2 } { \kaishu } { \@@_name:n { #1 } } - \@@_hskip: - \@@_ulined_center_box:nn { #3 } - { \clist_item:cn { l_@@_info_ #1 _clist } { 1 } } - \skip_horizontal:n { 0.5 em } - \@@_spread_box:nnn { #2 } { \kaishu } { \c_@@_name_supv_ttl_tl } - \@@_hskip: - \@@_ulined_center_box:nn { #3 } - { \clist_item:cn { l_@@_info_ #1 _clist } { 2 } } - \@@_vskip: - } -% \end{macrocode} -% \end{macro} -% -% -% \subsubsection{定义对象} -% \changes{v0.15}{2022/01/24}{使用 \pkg{xtemplate} 重构封面。} -% -% 本模板使用 \pkg{xtemplate} 提供的面向对象方法简化封面和摘要的绘制过程。 -% -% 以下分别从页面元素(element)和页面整体(page)的层次进行了抽象。当我们把页面部件考虑为一个对象时,它天然地只具备有限数量的属性:内容、格式、边距、对齐方式等。而具体的页面是这些对象的实例的集合,附加边距、行距等属性,创建页面只需传入一个列表调用各个 Instance 即可。通过 \pkg{xtemplate} 提供的功能,我们可以根据这些属性创建模板(template),进而能大量构建具有\emph{相似行为}的实例(instance)。这种做法能充分分离内容和样式,极大优化代码的可读性。 -% -% 声明对象类型。此类对象不需要参数。 -% \begin{macrocode} -\DeclareObjectType { nju } { \c_zero_int } -% \end{macrocode} -% -% 定义元素模板。 -% \begin{macrocode} -%<@@=njuelem> -% \end{macrocode} -% -% 声明页面元素模板接口。 -% 元素是一个页面的基本组成单位,包括文段、图片等等。一个抽象的元素应当具备以下属性: -% \begin{description} -% \item[\opt{content}] 内容,即剥离样式的元素本身 -% \item[\opt{format}] 格式,例如字号、字体 -% \item[\opt{bottom-skip}] 下间距,即与下一个元素的距离 -% \item[\opt{align}] 对齐方式,包括左对齐、右对齐、居中、正常段落 -% \end{description} -% \begin{macrocode} -\DeclareTemplateInterface { nju } { element } { \c_zero_int } - { - content : tokenlist = \c_empty_tl, - format : tokenlist = \c_empty_tl, - bottom-skip : skip = \c_zero_skip, - align : choice { l, r, c, n } = c - } -% \end{macrocode} -% -% 声明页面元素模板代码。涉及的变量将被自动创建。 -% \begin{macrocode} -\DeclareTemplateCode { nju } { element } { \c_zero_int } - { - content = \l_@@_content_tl, - format = \l_@@_format_tl, - bottom-skip = \l_@@_bottom_skip, - align = - { - l = - { \tl_set_eq:NN \l_@@_begin_align_tl \flushleft - \tl_set_eq:NN \l_@@_end_align_tl \endflushleft }, - r = - { \tl_set_eq:NN \l_@@_begin_align_tl \flushright - \tl_set_eq:NN \l_@@_end_align_tl \endflushright }, - c = - { \tl_set_eq:NN \l_@@_begin_align_tl \center - \tl_set_eq:NN \l_@@_end_align_tl \endcenter }, - n = - { \tl_clear:N \l_@@_begin_align_tl - \tl_clear:N \l_@@_end_align_tl } - } - } - { - \AssignTemplateKeys - \group_begin: - \l_@@_begin_align_tl - \l_@@_format_tl - \l_@@_content_tl \par - \l_@@_end_align_tl - \group_end: - \__nju_vskip:N \l_@@_bottom_skip - } -% \end{macrocode} -% -% 定义页面模板。 -% \begin{macrocode} -%<@@=njupage> -% \end{macrocode} -% -% 声明页面模板接口。 -% 页面是元素的集合。一个抽象的页面应当具备以下属性: -% \begin{description} -% \item[\opt{element}] 包含的元素,这里使用的是名称列表 -% \item[\opt{prefix}] 元素名称前缀 -% \item[\opt{format}] 格式,例如行距 -% \item[\opt{top-skip}] 上间距,即与页面顶部的距离 -% \item[\opt{bottom-skip}] 下间距,即与页面底部的距离 -% \end{description} -% \begin{macrocode} -\DeclareTemplateInterface { nju } { page } { \c_zero_int } - { - element : commalist = \c_empty_clist, - prefix : tokenlist = \c_empty_tl, - format : tokenlist = \c_empty_tl, - top-skip : skip = \c_zero_skip, - bottom-skip : skip = \c_zero_skip - } -% \end{macrocode} -% -% 声明页面模板代码。 -% \begin{macrocode} -\DeclareTemplateCode { nju } { page } { \c_zero_int } - { - element = \l_@@_element_clist, - prefix = \l_@@_prefix_tl, - format = \l_@@_format_tl, - top-skip = \l_@@_top_skip, - bottom-skip = \l_@@_bottom_skip - } - { - \AssignTemplateKeys - \newpage - \__nju_vskip:N \l_@@_top_skip - \group_begin: - \l_@@_format_tl - \clist_map_inline:Nn \l_@@_element_clist - { \UseInstance { nju } { \l_@@_prefix_tl ##1 } } - \group_end: - \__nju_vskip:N \l_@@_bottom_skip - } -%<@@=nju> -% \end{macrocode} -% -% \begin{macro}{\@@_declare_element:nn,\@@_declare_page:nn} -% 封装 \pkg{xtemplate} 提供的函数,简化创建实例的过程。 -% \begin{arguments} -% \item 实例名称 -% \item 参数列表 -% \end{arguments} -% \begin{macrocode} -\cs_new_protected:Npn \@@_declare_element:nn #1#2 - { \DeclareInstance { nju } {#1} { element } {#2} } -\cs_new_protected:Npn \@@_declare_page:nn #1#2 - { \DeclareInstance { nju } {#1} { page } {#2} } -% \end{macrocode} -% \end{macro} -% % % \subsubsection{绘制部件} % -% \begin{macrocode} -\keys_define:nn { nju / style } - { -% \end{macrocode} -% \begin{macro}{style/emblem-img} -% \changes{v0.14}{2021/12/23}{提供选择外置校徽图片的接口。} -% 校徽图片路径。 -% \begin{macrocode} - emblem-img .tl_set:N = \l_@@_emblem_img_tl, -% \end{macrocode} -% \end{macro} -% \begin{macro}{style/name-img} -% \changes{v0.14}{2021/12/23}{提供选择外置校名图片的接口。} -% 校名图片路径。 -% \begin{macrocode} - name-img .tl_set:N = \l_@@_name_img_tl - } -% \end{macrocode} -% \end{macro} -% -% 根据导言区载入的用户设置进行一些处理。 -% \begin{macrocode} -\ctex_at_end_preamble:n - { -% \end{macrocode} -% \begin{macro}{\njuemblem,\njuname} -% 如果用户在定义了图片的路径,则覆盖 \pkg{njuvisual} 提供的绘制命令。 -% \begin{macrocode} - \tl_if_empty:NF \l_@@_emblem_img_tl - { - \RenewDocumentCommand \njuemblem { o m m } - { \includegraphics [ width = #2, height = #3 ] - { \l_@@_emblem_img_tl } } - } - \tl_if_empty:NF \l_@@_name_img_tl - { - \RenewDocumentCommand \njuname { o m m } - { \includegraphics [ width = #2, height = #3 ] - { \l_@@_name_img_tl } } - } - } -% \end{macrocode} -% \end{macro} +% \changes{v0.16}{2022/03/01}{将封面部件分离到 \file{.def} 文件。} % % \paragraph{本科生} % % \begin{macro}{cover/ug/emblem-img} % 本科生封面校徽图片实例。 % \begin{macrocode} +%<*definition-ug> \@@_declare_element:nn { cover / ug / emblem-img } { content = \njuemblem [ black ] { ! } { 3.35 cm }, @@ -4059,7 +4218,7 @@ To produce the documentation run the original source files ending with \@@_declare_element:nn { cover / ug / title } { content = - \@@_spread_box:nnn { 9 em } { \bf } { \l_@@_info_type_tl }, + \@@_spread_box:nnV { 9 em } { \bf } \l_@@_info_type_tl, format = \zihao { -1 }, bottom-skip = 0 pt plus 1.5 fill } @@ -4101,6 +4260,7 @@ To produce the documentation run the original source files ending with \@@_cover_entry:nnn { sm_date } { #1 } { #2 } \end{minipage} } +%</definition-ug> % \end{macrocode} % \end{macro} % @@ -4111,6 +4271,7 @@ To produce the documentation run the original source files ending with % \begin{macro}{cover/g/emblem-img} % 研究生封面校徽图片实例。 % \begin{macrocode} +%<*definition-g> \@@_declare_element:nn { cover / g / emblem-img } { content = \njuemblem [ black ] { ! } { 1.9 cm }, @@ -4124,7 +4285,7 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \@@_declare_element:nn { cover / g / name-img } { - content = \njuname [ black ] { 4.4 cm } { ! }, + content = \njuname [ black ] { 4.4 cm } { ! }, bottom-skip = 2 cm } % \end{macrocode} @@ -4136,7 +4297,7 @@ To produce the documentation run the original source files ending with \@@_declare_element:nn { cover / g / type } { content = - \@@_spread_box:nnn { 9 em } { } { \l_@@_info_type_tl }, + \@@_spread_box:nnV { 9 em } { } \l_@@_info_type_tl, format = \zihao { -1 } \bfseries, bottom-skip = 1 cm } @@ -4211,13 +4372,13 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \cs_new_protected:Npn \@@_cover_back_g: { - \@@_spread_box:nnn { 6.2 em } { \kaishu } { \c_@@_name_id_tl } + \@@_spread_box:nnV { 6.2 em } { \kaishu } \c_@@_name_id_tl { : \@@_quad: } \l_@@_info_id_tl \@@_vskip: - \@@_spread_box:nnn { 6.2 em } { \kaishu } { \c_@@_name_df_date_tl } + \@@_spread_box:nnV { 6.2 em } { \kaishu } \c_@@_name_df_date_tl { : \@@_quad: } \l_@@_info_df_date_tl \@@_vskip: - \@@_spread_box:nnn { 6.2 em } { \kaishu } { \c_@@_name_supv_full_tl } + \@@_spread_box:nnV { 6.2 em } { \kaishu } \c_@@_name_supv_full_tl { : \@@_quad: } \skip_horizontal:n { 8 em } \c_@@_name_sign_tl } % \end{macrocode} @@ -4264,7 +4425,7 @@ To produce the documentation run the original source files ending with content = \c_@@_cover_en_text_tl \@@_vskip: \textsc { \clist_item:Nn \c_@@_name_degree_en_clist - { \l_@@_info_degree_int } } + { \g_@@_info_degree_int } } \@@_vskip: { in } \@@_vskip: \l_@@_info_major_en_tl, bottom-skip = 2 cm @@ -4315,7 +4476,7 @@ To produce the documentation run the original source files ending with \@@_declare_element:nn { cover / nl / name } { content = - \@@_spread_box:nnn { 6 em } { } { \c_@@_name_title_tl }, + \@@_spread_box:nnV { 6 em } { } \c_@@_name_title_tl, format = \zihao { -0 }, bottom-skip = 0 pt plus 1.2 fil } @@ -4374,11 +4535,11 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \cs_new_protected:Npn \@@_cover_top_nl: { - \@@_spread_box:nnn { 3.2 em } { } { \c_@@_name_clc_tl } \@@_hskip: + \@@_spread_box:nnV { 3.2 em } { } \c_@@_name_clc_tl \@@_hskip: \@@_ulined_center_box:nn { 9 em } { \l_@@_info_clc_tl } \hfill - \@@_spread_box:nnn { 3.2 em } { } { \c_@@_name_seclv_tl } \@@_hskip: + \@@_spread_box:nnV { 3.2 em } { } \c_@@_name_seclv_tl \@@_hskip: \@@_ulined_center_box:nn { 9 em } { \l_@@_info_seclv_tl } \\ - \@@_spread_box:nnn { 3.2 em } { } { \c_@@_name_udc_tl } \@@_hskip: + V { 3.2 em } { } { \c_@@_name_udc_tl } \@@_hskip: \@@_ulined_center_box:nn { 9 em } { \l_@@_info_udc_tl } \hfill \null } % \end{macrocode} @@ -4389,10 +4550,10 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \cs_new_protected:Npn \@@_cover_title_nl: { - \@@_split_title:n { \l_@@_info_title_tl } + \@@_split_title:V \l_@@_info_title_tl \@@_multiline_box:nnnn { \l_@@_tmp_int } \l_@@_tmp_clist { 3 } { 15 em } \skip_vertical:n { - 0.5 cm } - { \zihao { 4 } \c_@@_name_title_nl_tl } + { \zihao { 4 } \c_@@_name_title_b_tl } \skip_vertical:N \c_zero_skip \@@_ulined_center_box:nn { 4.5 em } { \l__nju_info_author_tl } \skip_vertical:n { - 0.5 cm } @@ -4414,7 +4575,7 @@ To produce the documentation run the original source files ending with \@@_ulined_center_box:nn { \textwidth } { \@@_info:n { supv_ttl } \@@_quad: \@@_info:n { supv_cont } } \\ \@@_uline_bientry:Nnnn \l_@@_tmp_dim { degree } { degree } { } - \@@_uline_bientry:Nnnn \l_@@_tmp_dim { major_nl } { major } { } \\ + \@@_uline_bientry:Nnnn \l_@@_tmp_dim { major_b } { major } { } \\ \@@_uline_bientry:Nnnn \l_@@_tmp_dim { sm_date } { sm_date } { } \@@_uline_bientry:Nnnn \l_@@_tmp_dim { df_date } { df_date } { } \\ \@@_full_uline:Nn \l_@@_tmp_dim { \c_@@_name_confer_tl } @@ -4434,6 +4595,7 @@ To produce the documentation run the original source files ending with \@@_multiline_box:nnnn { \l_@@_tmp_int } { \l_@@_info_reviewer_clist } { 4 } { 9 em } } +%</definition-g> % \end{macrocode} % \end{macro} % @@ -4449,18 +4611,21 @@ To produce the documentation run the original source files ending with % \begin{macro}{cover-ug-default} % 默认本科生封面实例。 % \begin{macrocode} +%<*definition-ug> \@@_declare_page:nn { cover-ug-default } { element = { emblem-img, name-img, title, info }, prefix = cover / ug /, bottom-skip = 0.5 cm plus 1.5 fill } +%</definition-ug> % \end{macrocode} % \end{macro} % % \begin{macro}{cover-g-front-default} % 默认研究生普通封面正面实例。 % \begin{macrocode} +%<*definition-g> \@@_declare_page:nn { cover-g-front-default } { element = { emblem-img, name-img, type, degree, info, date }, @@ -4505,24 +4670,19 @@ To produce the documentation run the original source files ending with prefix = cover / nl /, format = \kaishu } +%</definition-g> % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_make_cover_ug:} -% 生成本科生封面。 -% \begin{macrocode} -\cs_new_protected:Npn \@@_make_cover_ug: - { \UseInstance { nju } { cover-ug-default } } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_make_cover_g:} -% 生成研究生的普通封面。 +% \begin{macro}{\@@_make_cover:} +% 生成本科生或研究生的普通封面。 % \begin{macrocode} -\cs_new_protected:Npn \@@_make_cover_g: +%<*(definition-ug|definition-g)> +\cs_new_protected:Npn \@@_make_cover: { - \clist_map_inline:nn { front, back, en } - { \UseInstance { nju } { cover-g- ##1 -default } } +%<definition-ug> \UseInstance { nju } { cover-ug-default } +%<definition-g> \clist_map_inline:nn { front, back, en } +%<definition-g> { \UseInstance { nju } { cover-g- ##1 -default } } } % \end{macrocode} % \end{macro} @@ -4530,8 +4690,8 @@ To produce the documentation run the original source files ending with % \begin{macro}{\@@_make_cover_nl:} % 生成研究生的国家图书馆封面。 % \begin{macrocode} -\cs_new_protected:Npn \@@_make_cover_nl: - { \UseInstance { nju } { cover-nl-default } } +%<definition-g>\cs_new_protected:Npn \@@_make_cover_nl: +%<definition-g> { \UseInstance { nju } { cover-nl-default } } % \end{macrocode} % \end{macro} % @@ -4541,25 +4701,89 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \cs_new_protected:Npn \@@_make_orig_decl: { - \chapter* { \c_@@_name_nju_tl \c_@@_name_orig_decl_tl } + \chapter* { \c_@@_name_orig_decl_tl } \thispagestyle { empty } \c_@@_orig_decl_text_tl \vfil \begin{flushright} - \clist_set:Nn \l_@@_tmp_clist { orig_sign, id, orig_date } - \int_compare:nF { \l_@@_info_degree_int == 1 } - { \clist_remove_all:Nn \l_@@_tmp_clist { id } } - \clist_map_inline:Nn \l_@@_tmp_clist +%<definition-ug> \clist_map_inline:nn { orig_sign, id, orig_date } +%<definition-g> \clist_map_inline:nn { orig_sign, orig_date } { \@@_vskip: \@@_name:n { ##1 } : \@@_uline:n { 7 em } } \end{flushright} \vfil } +%</(definition-ug|definition-g)> % \end{macrocode} % \end{macro} % % % \subsubsection{用户接口} % +% \begin{macro}{\@@_new_img_cmd:nn,\@@_new_img_cmd:nV} +% 用于定义插入图片命令的辅助函数。 +% \begin{macrocode} +%<*class> +\cs_new_protected:Npn \@@_new_img_cmd:nn #1#2 + { + \exp_args:Nc \NewDocumentCommand { #1 } { o m m } + { \includegraphics [ width = ##2, height = ##3 ] { #2 } } + } +\cs_generate_variant:Nn \@@_new_img_cmd:nn { nV } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\keys_define:nn { nju / style } + { +% \end{macrocode} +% \begin{macro}{style/emblem-img,\njuemblem} +% \changes{v0.14}{2021/12/23}{提供选择外置校徽图片的接口。} +% 校徽图片路径。 +% \begin{macrocode} + emblem-img .code:n = + { \@@_new_img_cmd:nV { njuemblem } \l_keys_value_tl }, +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{style/name-img,\njuname} +% \changes{v0.14}{2021/12/23}{提供选择外置校名图片的接口。} +% 校名图片路径。 +% \begin{macrocode} + name-img .code:n = + { \@@_new_img_cmd:nV { njuname } \l_keys_value_tl } + } +% \end{macrocode} +% \end{macro} +% +% \changes{v0.16}{2022/02/22}{不再默认载入 \pkg{njuvisual}。} +% 检查 \cs{njuemblem} 和 \cs{njuname} 命令是否有定义。 +% \begin{macrocode} +\msg_new:nnn { njuthesis } { missing-image } + { + Local~ images~ not~ designated.\\ + It~ seems~ that~ you~ haven't~ fill~ in~ both~ + "style/emblem-img"~ and~ "style/name-img",~ + therefore~ I~ am~ using~ package~ "njuvisual"~ + instead,~ which~ may~ slow~ down~ the~ compilation. + } +\ctex_at_end_preamble:n + { +% \end{macrocode} +% 如果校名、校徽图片其中之一的路径未被定义, +% 则全盘使用 \pkg{njuvisual} 提供的绘制命令。 +% \begin{macrocode} + \bool_lazy_and:nnF + { \cs_if_exist_p:N \njuemblem } + { \cs_if_exist_p:N \njuname } + { + \cs_undefine:N \njuemblem + \cs_undefine:N \njuname + \msg_warning:nn { njuthesis } { missing-image } + \RequirePackage { njuvisual } + } + } +% \end{macrocode} +% % \begin{macro}{\maketitle} % \changes{v0.12}{2021/12/01}{仅会生成国家图书馆封面或者普通封面之一。} % \changes{v0.13}{2021/12/12}{重新绘制封面。} @@ -4579,7 +4803,7 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \bool_if:NTF \g_@@_nlcover_bool { \@@_make_cover_nl: } - { \use:c { @@_make_cover_ \l_@@_info_diploma_tl : } } + { \@@_make_cover: } % \end{macrocode} % 如果在选择了 \opt{decl-page},就生成本科生的诚信承诺书或研究生的原创性声明。 % \begin{macrocode} @@ -4593,90 +4817,79 @@ To produce the documentation run the original source files ending with % 在标题页后使用大写罗马字母页码,恢复正常字体设置。 % \begin{macrocode} \cleardoublepage - \pagestyle { plain } + \exp_args:NV \pagestyle \c_@@_pagestyle_tl \pagenumbering { Roman } - \normalfont \normalsize } +%</class> % \end{macrocode} % \end{macro} % % % \subsection{摘要页} % -% \subsubsection{内部命令} +% \subsubsection{绘制部件} +% \changes{v0.16}{2022/03/02}{将摘要部件分离到 \file{.def} 文件。} +% \changes{v0.16}{2022/03/02}{使用 \pkg{xtemplate} 重构摘要。} % +% \begin{macro}{abstract/title} +% 中文摘要标题实例。 % \begin{macrocode} -\keys_define:nn { nju / style } +%<*(definition-ug|definition-g)> +\@@_declare_element:nn { abstract / title } { -% \end{macrocode} -% \begin{macro}{style/abstract-in-toc} -% \changes{v0.15}{2022/02/04}{可选择摘要是否出现在目录中。} -% 是否将摘要添加到目录。 -% \begin{macrocode} - abstract-in-toc .bool_gset:N = \g_@@_abs_in_toc_bool, - abstract-in-toc .initial:n = true + content = \@@_abs_title:V \c_@@_name_abstract_title_tl, + format = \bfseries \kaishu \zihao { -2 }, + bottom-skip = 1.2 cm } % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_abs_bookmark:nn} -% \changes{v0.14}{2021/12/21}{将摘要插入目录。} -% 生成摘要的目录条目。 +% \begin{macro}{abstract/info} +% 中文摘要信息栏实例。 % \begin{macrocode} -\cs_new_protected:Npn \@@_abs_bookmark:nn #1#2 +\@@_declare_element:nn { abstract / info } { - \phantomsection - \bool_if:NTF \g_@@_abs_in_toc_bool - { \@@_add_tocline:n { #1 } } - { \pdfbookmark [0] { #1 } { #2 } } +%<definition-ug> content = \@@_abs_info_ug:nn { } { : }, +%<definition-g> content = \@@_abs_info_g:n { : }, +%<definition-ug> format = \zihao { -4 } \kaishu, +%<definition-g> format = \zihao { 4 } \kaishu, + align = l, + bottom-skip = 1 cm } -\cs_generate_variant:Nn \@@_abs_bookmark:nn { Vn } % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_abs_title_uuline:n} -% 摘要标题双层下划线格式。 -% \begin{arguments} -% \item 宽度,|dim| 型变量 -% \end{arguments} +% \begin{macro}{abstract/en/title} +% 英文摘要标题实例。 % \begin{macrocode} -\cs_new_protected:Npn \@@_abs_title_uuline:n #1 - { \bf \kaishu \zihao { -2 } \@@_uuline:n { #1 } } +\@@_declare_element:nn { abstract / en / title } + { + content = \@@_abs_title:V \c_@@_name_abstract_title_en_tl, + format = \bfseries \kaishu \zihao { -2 }, + bottom-skip = 1.2 cm + } % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_abs_info_style:n,\@@_abs_info_style_en:n} -% 摘要信息栏通用格式,设置为无缩进、四号或者小四号、楷书。 -% \begin{arguments} -% \item 字号 -% \end{arguments} +% \begin{macro}{abstract/en/info} +% 英文摘要信息栏实例。 % \begin{macrocode} -\cs_new_protected:Npn \@@_abs_info_style:n #1 - { \noindent \zihao{ #1 } \kaishu } -\cs_new_protected:Npn \@@_abs_info_style_en: #1 - { \zihao{ #1 } } -% \end{macrocode} -% \end{macro} -% -% -% \subsubsection{绘制部件} -% -% \paragraph{本科生} -% -% \begin{macro}{\@@_abs_title_ug:n} -% 绘制本科生摘要标题。 -% \begin{arguments} -% \item 语言,空置为中文,|_en| 为英文 -% \end{arguments} -% \begin{macrocode} -\cs_new_protected:Npn \@@_abs_title_ug:n #1 +\@@_declare_element:nn { abstract / en / info } { - \clist_map_inline:nn { nju, type, lang #1, abstract } - { \@@_name:n { ##1 } } +%<definition-ug> content = \@@_abs_info_ug:nn { _en } { :~ }, +%<definition-g> content = \@@_abs_info_en_g:n { :~ }, +%<definition-ug> format = \zihao { -4 }, +%<definition-g> format = \zihao { 4 }, + align = l, + bottom-skip = 1 cm } +%</(definition-ug|definition-g)> % \end{macrocode} % \end{macro} % +% \paragraph{本科生} +% \changes{v0.13}{2021/12/12}{使用 \hologo{LaTeX3} 语法重构本科生摘要。} +% % \begin{macro}{\@@_abs_info_ug:nn} % 绘制本科生摘要信息栏。 % \begin{arguments} @@ -4685,6 +4898,7 @@ To produce the documentation run the original source files ending with % \end{arguments} % 本科生摘要页面不含下划线,因而不用确定文本宽度,绘制命令较为简单。 % \begin{macrocode} +%<*definition-ug> \cs_new_protected:Npn \@@_abs_info_ug:nn #1#2 { % \end{macrocode} @@ -4692,12 +4906,12 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \tl_if_blank:eTF { #1 } { \c_@@_name_title_tl } - { \clist_item:Nn \c_@@_name_type_en_clist { \l_@@_info_type_int } } + { \clist_item:Nn \c_@@_name_type_en_clist { \g_@@_info_type_int } } #2 \tl_use:c { l_@@_info_title #1 _tl } \\ % \end{macrocode} % 由于作者姓名使用的字样发生了变动,这里进行替换以便嵌入循环。 % \begin{macrocode} - \tl_set_eq:NN \c_@@_name_author_tl \c_@@_name_author_full_tl + \tl_set_eq:NN \c_@@_name_author_tl \c_@@_name_author_a_tl % \end{macrocode} % 使用循环输出院系、专业、作者、导师信息。 % \begin{macrocode} @@ -4705,91 +4919,82 @@ To produce the documentation run the original source files ending with { \@@_name:n { ##1 #1 } #2 \@@_info:n { ##1 #1 } \\ } \@@_name:n { abstract #1 } #2 } +%</definition-ug> % \end{macrocode} % \end{macro} % % \paragraph{研究生} +% \changes{v0.13}{2021/12/12}{使用 \hologo{LaTeX3} 语法重构研究生摘要。} % -% \begin{macro}{\@@_abs_title_g:n} -% 绘制研究生摘要标题。 +% \begin{macro}{\@@_abs_info_g:n} +% 绘制研究生中文摘要信息栏。 % \begin{arguments} -% \item 语言,空置为中文,|_en| 为英文 +% \item 分隔符 % \end{arguments} +% 研究生中文摘要页包括下划线以及若干特殊的对齐方式,实现方式较为繁琐。使用 \cs{@@_full_uline:NV} 确定内容宽度后,调用 \cs{@@_uline:n} 或 \cs{@@_ulined_center_box:nn} 命令以绘制横穿页面的下划线。前两行为标题。 % \begin{macrocode} -\cs_new_protected:Npn \@@_abs_title_g:n #1 +%<*definition-g> +\cs_new_protected:Npn \@@_abs_info_g:n #1 { - \@@_name:n { nju } \@@_info:n { type } - \@@_name:n { lang #1 } \@@_name:n { abstract_r } + \@@_full_uline:NV \l_@@_tmp_dim + { + \clist_item:Nn \c_@@_name_type_clist { \g_@@_info_type_int } + \c_@@_name_title_a_tl #1 + } + \@@_ulined_center_box:nn { \l_@@_tmp_dim } + { \tl_range:Nnn \l_@@_info_title_tl { 1 } { 20 } } \\ + \@@_uline:n { \textwidth } \@@_qquad: + \tl_range:Nnn \l_@@_info_title_tl { 21 } { -1 } \\ +% \end{macrocode} +% 专业、年级、姓名。 +% \begin{macrocode} + \@@_full_uline:NV \l_@@_tmp_dim + { + \@@_ulined_center_box:nn { 11 em } { \l_@@_info_major_tl } + \c_@@_name_major_a_tl + \@@_ulined_center_box:nn { 4 em } { \l_@@_info_grade_tl } + \c_@@_name_grade_tl \c_@@_name_author_a_tl #1 + } + \@@_ulined_center_box:nn { \l_@@_tmp_dim } + { \l_@@_info_author_tl } \\ +% \end{macrocode} +% 导师姓名、职称。 +% \begin{macrocode} + \@@_full_uline:NV \l_@@_tmp_dim + { \c_@@_name_supv_a_tl #1 } + \@@_ulined_center_box:nn { \l_@@_tmp_dim } + { \l_@@_info_supv_full_tl } } % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_abs_info_g:nn} -% 绘制研究生摘要信息栏。 +% \begin{macro}{\@@_abs_info_en_g:n} +% 绘制研究生英文摘要信息栏。 % \begin{arguments} -% \item 语言,空置为中文,|_en| 为英文 % \item 分隔符 -% 研究生摘要页包括下划线以及若干特殊的对齐方式,实现方式较为繁琐。 % \end{arguments} +% 前两行为标题。 % \begin{macrocode} -\cs_new_protected:Npn \@@_abs_info_g:nn #1#2 +\cs_new_protected:Npn \@@_abs_info_en_g:n #1 { - \tl_if_blank:eTF { #1 } - { -% \end{macrocode} -% 中文摘要环境,使用 \cs{@@_full_uline:NV} 确定内容宽度后,调用 \cs{@@_uline:n} 或 \cs{@@_ulined_center_box:nn} 命令以绘制横穿页面的下划线。前两行为标题。 -% \begin{macrocode} - \@@_full_uline:NV \l_@@_tmp_dim - { - \clist_item:Nn \c_@@_name_type_clist { \l_@@_info_type_int } - \c_@@_name_title_s_tl #2 - } - \@@_ulined_center_box:nn { \l_@@_tmp_dim } - { \tl_range:Nnn \l_@@_info_title_tl { 1 } { 20 } } \\ - \@@_uline:n { \textwidth } \@@_qquad: - \tl_range:Nnn \l_@@_info_title_tl { 21 } { -1 } \\ -% \end{macrocode} -% 专业、年级、姓名。 -% \begin{macrocode} - \@@_full_uline:NV \l_@@_tmp_dim - { - \@@_ulined_center_box:nn { 11 em } { \l_@@_info_major_tl } - \c_@@_name_major_s_tl - \@@_ulined_center_box:nn { 4 em } { \l_@@_info_grade_tl } - \c_@@_name_grade_tl - \tl_item:nn { \l_@@_info_degree_tl } { 1 } - \c_@@_name_author_r_tl #2 - } - \@@_ulined_center_box:nn { \l_@@_tmp_dim } - { \l_@@_info_author_tl } \\ + \@@_full_uline:NV \l_@@_tmp_dim + { \clist_item:Nn \c_@@_name_type_en_clist + { \g_@@_info_type_int } #1 } + \@@_ulined_center_box:nn { \l_@@_tmp_dim } + { \tl_range:Nnn \l_@@_info_title_en_tl { 1 } { 40 } } \\ + \@@_uline:n { \textwidth } \@@_qquad: + \tl_range:Nnn \l_@@_info_title_en_tl { 41 } { -1 } % \end{macrocode} -% 导师姓名、职称。 +% 使用循环输出专业、姓名、导师。注意这里将 |\\| 放置在前部, +% 以避免末尾生成多余的换行符产生 |Underfull \vbox| 信息。 % \begin{macrocode} - \@@_full_uline:NV \l_@@_tmp_dim - { \c_@@_name_supv_full_tl \c_@@_name_supv_r_tl #2 } - \@@_ulined_center_box:nn { \l_@@_tmp_dim } - { \l_@@_info_supv_full_tl } - } -% \end{macrocode} -% 英文摘要环境。前两行为标题。 -% \begin{macrocode} - { - \@@_full_uline:NV \l_@@_tmp_dim - { \clist_item:cn { c_@@_name_type #1 _clist } - { \l_@@_info_type_int } # 2 } - \@@_ulined_center_box:nn { \l_@@_tmp_dim } - { \tl_range:Nnn \l_@@_info_title_en_tl { 1 } { 40 } } \\ - \@@_uline:n { \textwidth } \@@_qquad: - \tl_range:Nnn \l_@@_info_title_en_tl { 41 } { -1 } -% \end{macrocode} -% 使用循环输出专业、姓名、导师。注意这里将 |\\| 放置在前部,以避免末尾生成多余的换行符产生 |Underfull \vbox| 信息。 -% \begin{macrocode} - \clist_map_inline:nn { major, author, supv_full } - { \\ - \@@_uline_entry:Nnnn \l_@@_tmp_dim { ##1 _en } { ##1 _en } { #2 } - } + \clist_map_inline:nn { major, author, supv_full } + { \\ + \@@_uline_entry:Nnnn \l_@@_tmp_dim + { ##1 _en } { ##1 _en } { #1 } } } +%</definition-g> % \end{macrocode} % \end{macro} % @@ -4803,11 +5008,11 @@ To produce the documentation run the original source files ending with % \item 关键词分隔符 % \end{arguments} % \begin{macrocode} +%<*class> \cs_new_protected:Npn \@@_print_keywords:nn #1#2 { - \exp_args:NNc - \tl_set_eq:NN \l_@@_tmp_tl { c_@@_name_keywords #1 _tl } - \@@_get_text_width:Nn \l_@@_tmp_dim { \l_@@_tmp_tl } + \tl_set:Nv \l_@@_tmp_tl { c_@@_name_keywords #1 _tl } + \@@_get_text_width:NV \l_@@_tmp_dim \l_@@_tmp_tl % \end{macrocode} % 关键词列表的悬挂缩进样式由 \tn{list} 环境产生。 % \begin{macrocode} @@ -4827,59 +5032,49 @@ To produce the documentation run the original source files ending with \clist_use:cn { l_@@_info_keywords #1 _clist } { #2 } \endlist } +%</class> % \end{macrocode} % \end{macro} % % % \subsubsection{绘制摘要} % -% \begin{macro}{\@@_make_abs_ug:nn} -% \changes{v0.13}{2021/12/12}{使用 \hologo{LaTeX3} 语法重构本科生摘要。} -% \begin{arguments} -% \item 语言,空置为中文,|_en| 为英文 -% \item 关键词分隔符 -% \end{arguments} -% 生成本科生摘要。 +% \begin{macro}{\@@_make_abstract:,\@@_make_abstract_en:} +% 绘制摘要页面。 % \begin{macrocode} -\cs_new_protected:Npn \@@_make_abs_ug:nn #1#2 +%<*(definition-ug|definition-g)> +\cs_new_protected:Npn \@@_make_abstract: { - \begin{center} - \@@_abs_title_uuline:n { 22 em } - \@@_abs_title_ug:n { #1 } - \end{center} - \group_begin: - \@@_abs_info_style:n { -4 } - \@@_abs_info_ug:nn { #1 } { #2 } - \group_end: \@@_vskip: + \UseInstance { nju } { abstract / title } + \UseInstance { nju } { abstract / info } + } +\cs_new_protected:Npn \@@_make_abstract_en: + { + \UseInstance { nju } { abstract / en / title } + \UseInstance { nju } { abstract / en / info } } +%</(definition-ug|definition-g)> % \end{macrocode} % \end{macro} % -% \begin{macro}{\@@_make_abs_g:nn} -% \changes{v0.13}{2021/12/12}{使用 \hologo{LaTeX3} 语法重构研究生摘要。} -% \begin{arguments} -% \item 语言,空置为中文,|_en| 为英文 -% \item 关键词分隔符 -% \end{arguments} -% 生成研究生摘要。 +% +% \subsubsection{用户接口} +% % \begin{macrocode} -\cs_new_protected:Npn \@@_make_abs_g:nn #1#2 +%<*class> +\keys_define:nn { nju / style } { - \begin{center} - \@@_abs_title_uuline:n { 19 em } - \@@_abs_title_g:n { #1 } - \end{center} - \group_begin: - \@@_abs_info_style:n { 4 } - \@@_abs_info_g:nn { #1 } { #2 } - \group_end: \@@_vskip: +% \end{macrocode} +% \begin{macro}{style/abstract-in-toc} +% \changes{v0.15}{2022/02/04}{可选择摘要是否出现在目录中。} +% 是否将摘要添加到目录。 +% \begin{macrocode} + abstract-in-toc .bool_gset:N = \g_@@_abs_in_toc_bool, + abstract-in-toc .initial:n = true } % \end{macrocode} % \end{macro} % -% -% \subsubsection{用户接口} -% % \begin{environment}{abstract} % \changes{v0.13}{2021/12/12}{重新绘制摘要。} % 中文摘要环境。 @@ -4888,9 +5083,8 @@ To produce the documentation run the original source files ending with { \cleardoublepage \thispagestyle { plain } - \@@_abs_bookmark:Vn - { \c_@@_name_lang_tl \c_@@_name_abstract_tl } { abstract } - \use:c { @@_make_abs_ \l_@@_info_diploma_tl :nn } { } { : } + \@@_abs_bookmark:Vn \c_@@_name_abstract_a_tl { abstract } + \@@_make_abstract: \group_begin: \kaishu \zihao { -4 } #1 } { \@@_print_keywords:nn { } { ; } \group_end: } @@ -4904,9 +5098,9 @@ To produce the documentation run the original source files ending with { \cleardoublepage \thispagestyle { plain } - \@@_abs_bookmark:Vn { \c_@@_name_abstract_en_tl } { abstract-en } - \use:c { @@_make_abs_ \l_@@_info_diploma_tl :nn } { _en } { :~ } - \group_begin: \zihao{ -4 } #1 + \@@_abs_bookmark:Vn \c_@@_name_abstract_a_en_tl { abstract-en } + \@@_make_abstract_en: + \group_begin: \zihao { -4 } #1 } { \@@_print_keywords:nn { _en } { ;~ } \group_end: } % \end{macrocode} @@ -4920,9 +5114,9 @@ To produce the documentation run the original source files ending with % 单独制作的前言致谢页。 % \begin{macrocode} \NewDocumentEnvironment { preface } { +b } - { \@@_chapter:V { \c_@@_name_preface_tl } #1 } { } + { \@@_chapter:V \c_@@_name_preface_tl #1 } { } \NewDocumentEnvironment { acknowledgement } { +b } - { \@@_chapter:V { \c_@@_name_acknowledgement_tl } #1 } { } + { \@@_chapter:V \c_@@_name_acknowledgement_tl #1 } { } % \end{macrocode} % \end{environment} % \end{environment} @@ -5014,7 +5208,7 @@ To produce the documentation run the original source files ending with % \begin{macrocode} \NewDocumentEnvironment { notation } { O { 10 em } O { 5 em } } { - \@@_chapter:V { \c_@@_name_notation_tl } + \@@_chapter:V \c_@@_name_notation_tl \@@_make_notation:nn { #1 } { #2 } } { \endlist } @@ -5034,5 +5228,201 @@ To produce the documentation run the original source files ending with % \end{macrocode} % \end{environment} % +% +% \subsection{配置常量} +% \changes{v0.16}{2022/02/23}{将名称常量分离到 \file{.def} 文件。} +% +% 本节内容用于生成名称常量的默认定义,分为本科生和研究生模板两种。 +% +% 由于同一名称在不同位置具有不同变体,本模板使用字母后缀名进行了区分, +% 并在易混淆处添加了注释。 +% +% 通用默认名称。注意空格是忽略掉的。 +% \begin{macrocode} +%<*(definition-ug|definition-g)> +\clist_map_inline:nn + { + { acknowledgement } { 致\hspace{2em}谢 }, + { id } { 学号 }, + { notation } { 符号表 }, + { orig_date } { 日期 }, + { paperlist } { 发表文章目录 }, + { pdf_creator } { LaTeX~ with~ njuthesis~ class }, + { preface } { 前\hspace{2em}言 }, + { supv_ii } { 第二导师 }, + { supv_ttl } { 职称 } + } + { \@@_define_name:nn #1 } +% \end{macrocode} +% +% 定义同时使用到中英文名称的常量。 +% \begin{macrocode} +\clist_map_inline:nn + { + { abstract } { 摘要 } { ABSTRACT }, + % 用于书签的摘要名称字样 + { abstract_a } { 中文摘要 } { ABSTRACT }, + { appendix } { 附录 } { appendix }, + { dept } { 院系 } { DEPARTMENT }, + { figure } { 图 } { figure }, + { keywords } { 关键词: } { Keywords:~ }, + { lang } { 中文 } { 英文 }, + { nju } { 南京大学 } { Nanjing~ University }, + { table } { 表 } { table } + } + { \@@_define_name:nnn #1 } +%</(definition-ug|definition-g)> +% \end{macrocode} +% +% 本科生模板默认名称。 +% \begin{macrocode} +%<*definition-ug> +\clist_map_inline:nn + { + % 用于摘要的作者名称字样 + { author_a } { 本科生姓名 }, + { grade } { 年级 }, + { orig_decl } + { \c_@@_name_nju_tl 本科毕业论文(设计)诚信承诺书 }, + { orig_sign } { 作者签名 }, + { sm_date } { 提交日期 }, + { supv } { 导师 }, + { title } { 题目 }, + { type } { 本科生毕业论文(设计、作品) }, + { ug } { 本科生 } + } + { \@@_define_name:nn #1 } +\clist_map_inline:nn + { + { abstract_title } + { + \c_@@_name_nju_tl \c_@@_name_type_tl + \c_@@_name_lang_tl \c_@@_name_abstract_tl + } + { + \c_@@_name_nju_tl \c_@@_name_type_tl + \c_@@_name_lang_en_tl \c_@@_name_abstract_tl + }, + { author } { 学生姓名 } { UNDERGRADUATE }, + { major } { 专业 } { SPECIALIZATION }, + { supv_full } { 指导教师(姓名、职称) } { MENTOR } + } + { \@@_define_name:nnn #1 } +% \end{macrocode} +% +% \begin{variable}{\c_@@_orig_decl_text_tl} +% 学位论文诚信承诺书。 +% \begin{macrocode} +\tl_const:Nn \c_@@_orig_decl_text_tl + { + 本人郑重承诺:所呈交的毕业论文(设计)(题目:)是在指导教师的指导下 + 严格按照学校和院系有关规定由本人独立完成的。本毕业论文(设计)中引用 + 他人观点及参考资源的内容均已标注引用,如出现侵犯他人知识产权的行为, + 由本人承担相应法律责任。本人承诺不存在抄袭、伪造、篡改、代写、买卖毕 + 业论文(设计)等违纪行为。 + } +%</definition-ug> +% \end{macrocode} +% \end{variable} +% +% 研究生模板默认名称。 +% \begin{macrocode} +%<*definition-g> +\clist_map_inline:nn + { + % 用于摘要的作者名称字样 + { author_a } + { \tl_item:Nn \l_@@_info_degree_tl { 1 } 士生姓名 }, + { chairman } { 答辩委员会主席: }, + { clc } { 分类号 }, + { confer } { 学位授予单位和日期 }, + { df_date } { 论文答辩日期 }, + { degree } { 申请学位级别 }, + { apply } + { (申请 \l_@@_info_degree_tl 学位) }, + { field } { 研究方向 }, + { g } { 研究生 }, + { grade } { 级 }, + % 用于摘要的专业名称字样 + { major_a } { 专业 }, + % 用于国家图书馆封面的专业名称字样 + { major_b } { 专业名称 }, + { orig_decl } + { \c_@@_name_nju_tl 学位论文原创性声明 }, + { orig_sign } { 研究生签名 }, + { reviewer } { 评阅人: }, + { seclv } { 密级 }, + { sign } { (签字) }, + { sm_date } { 论文提交日期 }, + { supv } { 导师 }, + % 用于摘要的导师名称字样 + { supv_a } { 指导教师(姓名、职称) }, + { supv_info } + { 指导教师姓名、职务、职称、学位、单位名称及地址 }, + % 用于普通封面的标题名称字样 + { title } { 论文题目 }, + % 用于摘要的标题名称字样 + { title_a } { 题目 }, + % 用于国家图书馆封面的标题名称字样 + { title_b } { (题名和副题名) }, + { udc } { U D C } + } + { \@@_define_name:nn #1 } +\clist_map_inline:nn + { + { abstract_title } + { 南京大学 \l_@@_info_type_tl 中文摘要首页用纸 } + { 南京大学 \l_@@_info_type_tl 英文摘要首页用纸 }, + { author } { 作者姓名 } { POSTGRADUATE }, + { major } { 专业方向 } { SPECIALIZATION }, + { supv_full } { 指导教师 } { MENTOR } + } + { \@@_define_name:nnn #1 } +% \end{macrocode} +% +% \begin{variable}{\c_@@_cover_en_text_tl} +% 英文封面字样。 +% \begin{macrocode} +\tl_const:Nn \c_@@_cover_en_text_tl + { + A~ dissertation~ submitted~ to \\ + the~ graduate~ school~ of~ Nanjing~ University \\ + in~ partial~ fulfilment~ of~ the~ requirements~ for~ the~ degree~ of + } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_@@_orig_decl_text_tl} +% 学位论文原创性声明。 +% \begin{macrocode} +\tl_const:Nn \c_@@_orig_decl_text_tl + { + 本人郑重声明,所提交的学位论文是本人在导师指导下独立进行科学研究工作 + 所取得的成果。除本论文中已经注明引用的内容外,本论文不包含其他个人或 + 集体已经发表或撰写过的研究成果,也不包含为获得南京大学或其他教育机构 + 的学位证书而使用过的材料。对本文的研究做出重要贡献的个人和集体,均已 + 在论文的致谢部分明确标明。本人郑重申明愿承担本声明的法律责任。 + } +%</definition-g> +% \end{macrocode} +% \end{variable} +% +% 默认定理类型和头名称。 +% \begin{macrocode} +%<*(definition-ug|definition-g)> +\clist_map_inline:nn + { + { axiom } { 公理 } { Axiom }, + { corollary } { 推论 } { Corollary }, + { definition } { 定义 } { Definition }, + { example } { 例 } { Example }, + { lemma } { 引理 } { Lemma }, + { proof } { 证明 } { Proof }, + { theorem } { 定理 } { Theorem } + } + { \@@_add_theorem_type:nnn #1 } +%</(definition-ug|definition-g)> +% \end{macrocode} +% % \end{implementation} % diff --git a/macros/unicodetex/latex/njuthesis/njuthesis.ins b/macros/unicodetex/latex/njuthesis/njuthesis.ins index f64208f6f9..1d947d360e 100644 --- a/macros/unicodetex/latex/njuthesis/njuthesis.ins +++ b/macros/unicodetex/latex/njuthesis/njuthesis.ins @@ -50,7 +50,9 @@ To produce the documentation run the original source files ending with \generate{ \usedir{tex/latex/njuthesis} - \file{\jobname.cls} {\from{\jobname.dtx}{class}} + \file{\jobname.cls} {\from{\jobname.dtx}{class}} + \file{\jobname-undergraduate.def} {\from{\jobname.dtx}{definition-ug}} + \file{\jobname-graduate.def} {\from{\jobname.dtx}{definition-g}} } \obeyspaces @@ -62,6 +64,8 @@ To produce the documentation run the original source files ending with \Msg{* The recommended directory is TDS:tex/latex/njuthesis *} \Msg{* *} \Msg{* njuthesis.cls *} +\Msg{* njuthesis-graduate.def *} +\Msg{* njuthesis-undergraduate.def *} \Msg{* njuthesis.ins *} \Msg{* *} \Msg{* To produce the documentation, run the file njuthesis.dtx *} diff --git a/macros/unicodetex/latex/njuthesis/njuthesis.pdf b/macros/unicodetex/latex/njuthesis/njuthesis.pdf Binary files differindex 6d15a76a77..1430d0d6ab 100644 --- a/macros/unicodetex/latex/njuthesis/njuthesis.pdf +++ b/macros/unicodetex/latex/njuthesis/njuthesis.pdf |