% \iffalse meta-comment % % This file should be compiled with $xelatex$. % % Copyright (C) 2018-2024 by F. Pantigny % ------------------------------------------ % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in: % % http://www.latex-project.org/lppl.txt % % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % \fi % \iffalse \def\myfileversion{6.27a} \def\myfiledate{2024/02/19} % % %<*batchfile> \begingroup \input l3docstrip.tex \keepsilent \usedir{tex/latex/nicematrix} \preamble Copyright (C) 2018-2024 by F. Pantigny ----------------------------------- This file may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3 of this license or (at your option) any later version. The latest version of this license is in: http://www.latex-project.org/lppl.txt and version 1.3 or later is part of all distributions of LaTeX version 2005/12/01 or later. \endpreamble \askforoverwritefalse \endgroup % % %<*driver> \documentclass[dvipsnames]{l3doc}% dvipsnames is for xcolor (loaded by Tikz) \VerbatimFootnotes \usepackage[luatex]{geometry} \geometry{left=2.8cm,right=2.8cm,top=2.5cm,bottom=2.5cm,papersize={21cm,29.7cm}} \usepackage{tikz} \usetikzlibrary{fit} \usepackage{nicematrix} \NewDocumentEnvironment {scope} {} {} {} \def\interitem{\vspace{7mm plus 2 mm minus 3mm}} \fvset{formatcom=\color{gray}} \usepackage{upquote} \usepackage{titlesec} \titlespacing*{\section}{0pt}{6.5ex plus 1ex minus .2ex}{4.3ex plus .2ex} \titlespacing*{\subsection}{0pt}{4.5ex plus 1ex minus .2ex}{2ex plus .2ex} \parindent 0pt \skip \footins = 2 \bigskipamount \begin{document} \DocInput{nicematrix-code.dtx} \end{document} % % \fi % \title{The code of the package \pkg{nicematrix}\thanks{This document corresponds to the version~\myfileversion\space of \pkg{nicematrix}, % at the date of~\myfiledate.}} % \author{F. Pantigny \\ \texttt{fpantigny@wanadoo.fr}} % % \hypersetup % { % pdfinfo = % { % Title = The code of the package 'nicematrix' , % Subject = A LaTeX package , % Author = F. Pantigny % } % } % % % \maketitle % % \begin{abstract} % This document is the documented code of the LaTeX package \pkg{nicematrix}. It % is \emph{not} its user's guide. The guide of utilisation is the document % |nicematrix.pdf| (with a French traduction: |nicematrix-french.pdf|). % \end{abstract} % % % \bigskip % By default, the package \pkg{nicematrix} doesn't patch any existing code. % % \smallskip % However, when the option |renew-dots| is used, the commands |\cdots|, % |\ldots|, |\dots|, |\vdots|, |\ddots| and |\iddots| are redefined in the % environments provided by \pkg{nicematrix}. In the same way, if the option % |renew-matrix| is used, the environment |{matrix}| of \pkg{amsmath} is % redefined. % % \smallskip % On the other hand, the environment |{array}| is never redefined. % % \smallskip % Of course, the package \pkg{nicematrix} uses the features of the package % \pkg{array}. It tries to be independent of its implementation. Unfortunately, % it was not possible to be strictly independent. For example, the package % \pkg{nicematrix} relies upon the fact that the package |{array}| uses % |\ialign| to begin the |\halign|. % % % \bigskip % \section{Declaration of the package and packages loaded} % % % The prefix |nicematrix| has been registred for this package. % % See: |http://mirrors.ctan.org/macros/latex/contrib/l3kernel/l3prefixes.pdf| % %<@@=nicematrix> % % \bigskip % First, we load \pkg{pgfcore} and the module \pkg{shapes}. We do so because % it's not possible to use |\usepgfmodule| in |\ExplSyntaxOn|. % \begin{macrocode} \RequirePackage{pgfcore} \usepgfmodule{shapes} % \end{macrocode} % % % We give the traditional declaration of a package written with the L3 % programming layer. % \begin{macrocode} \RequirePackage{l3keys2e} \ProvidesExplPackage {nicematrix} {\myfiledate} {\myfileversion} {Enhanced arrays with the help of PGF/TikZ} % \end{macrocode} % % % \bigskip % The command for the treatment of the options of |\usepackage| is at the end of % this package for technical reasons. % % \bigskip % We load some packages. % \begin{macrocode} \RequirePackage { array } \RequirePackage { amsmath } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_error:n { \msg_error:nn { nicematrix } } \cs_new_protected:Npn \@@_warning:n { \msg_warning:nn { nicematrix } } \cs_new_protected:Npn \@@_error:nn { \msg_error:nnn { nicematrix } } \cs_generate_variant:Nn \@@_error:nn { n e } \cs_new_protected:Npn \@@_error:nnn { \msg_error:nnnn { nicematrix } } \cs_new_protected:Npn \@@_fatal:n { \msg_fatal:nn { nicematrix } } \cs_new_protected:Npn \@@_fatal:nn { \msg_fatal:nnn { nicematrix } } \cs_new_protected:Npn \@@_msg_new:nn { \msg_new:nnn { nicematrix } } % \end{macrocode} % % With Overleaf, by default, a document is compiled in non-stop mode. When there % is an error, there is no way to the user to use the key H in order to have % more information. That's why we decide to put that piece of information (for % the messages with such information) in the main part of the message when the % key |messages-for-Overleaf| is used (at load-time). % \begin{macrocode} \cs_new_protected:Npn \@@_msg_new:nnn #1 #2 #3 { \bool_if:NTF \g_@@_messages_for_Overleaf_bool { \msg_new:nnn { nicematrix } { #1 } { #2 \\ #3 } } { \msg_new:nnnn { nicematrix } { #1 } { #2 } { #3 } } } % \end{macrocode} % % \bigskip % We also create a command which will generate usually an error but only a % warning on Overleaf. The argument is given by curryfication. % \begin{macrocode} \cs_new_protected:Npn \@@_error_or_warning:n { \bool_if:NTF \g_@@_messages_for_Overleaf_bool \@@_warning:n \@@_error:n } % \end{macrocode} % % We try to detect whether the compilation is done on Overleaf. We use % |\c_sys_jobname_str| because, with Overleaf, the value of |\c_sys_jobname_str| % is always ``|output|''. % \begin{macrocode} \bool_new:N \g_@@_messages_for_Overleaf_bool \bool_gset:Nn \g_@@_messages_for_Overleaf_bool { \str_if_eq_p:on \c_sys_jobname_str { _region_ } % for Emacs || \str_if_eq_p:on \c_sys_jobname_str { output } % for Overleaf } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_msg_redirect_name:nn { \msg_redirect_name:nnn { nicematrix } } \cs_new_protected:Npn \@@_gredirect_none:n #1 { \group_begin: \globaldefs = 1 \@@_msg_redirect_name:nn { #1 } { none } \group_end: } \cs_new_protected:Npn \@@_err_gredirect_none:n #1 { \@@_error:n { #1 } \@@_gredirect_none:n { #1 } } \cs_new_protected:Npn \@@_warning_gredirect_none:n #1 { \@@_warning:n { #1 } \@@_gredirect_none:n { #1 } } % \end{macrocode} % % \bigskip % \section{Security test} % % Within the package \pkg{nicematrix}, we will have to test whether a cell of a % |{NiceTabular}| is empty. For the cells of the columns of type |p|, |b|, |m|, % |X| and |V|, we will test whether the cell is syntactically empty (that is to % say that there is only spaces between the ampersands |&|). That test will be % done with the command |\@@_test_if_empty:| by testing if the two first tokens % in the cells are (during the TeX process) are |\ignorespaces| and |\unskip|. % % However, if, one day, there is a changement in the implementation of % \pkg{array}, maybe that this test will be broken (and \pkg{nicematrix} also). % % That's why, by security, we will take a test in a small |{tabular}| composed % in the box |\l_tmpa_box| used as sandbox. % % \begin{macrocode} \@@_msg_new:nn { Internal~error } { Potential~problem~when~using~nicematrix.\\ The~package~nicematrix~have~detected~a~modification~of~the~ standard~environment~{array}~(of~the~package~array).~Maybe~you~will~encounter~ some~slight~problems~when~using~nicematrix.~If~you~don't~want~to~see~ this~message~again,~load~nicematrix~with:~\token_to_str:N \usepackage[no-test-for-array]{nicematrix}. } % \end{macrocode} % % \bigskip % \begin{macrocode} \@@_msg_new:nn { mdwtab~loaded } { The~packages~'mdwtab'~and~'nicematrix'~are~incompatible.~ This~error~is~fatal. } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_security_test:n #1 { \peek_meaning:NTF \ignorespaces { \@@_security_test_i:w } { \@@_error:n { Internal~error } } #1 } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_security_test_i:w \ignorespaces #1 { \peek_meaning:NF \unskip { \@@_error:n { Internal~error } } #1 } % \end{macrocode} % % \bigskip % Here, the box |\l_tmpa_box| will be used as sandbox to take our security test. % This code has been modified in version 6.18 (see question 682891 on TeX % StackExchange). % \begin{macrocode} \hook_gput_code:nnn { begindocument / after } { . } { \IfPackageLoadedTF { mdwtab } { \@@_fatal:n { mdwtab~loaded } } { \bool_if:NF \g_@@_no_test_for_array_bool { \group_begin: \hbox_set:Nn \l_tmpa_box { \begin { tabular } { c > { \@@_security_test:n } c c } text & & text \end { tabular } } \group_end: } } } % \end{macrocode} % % \bigskip % \section{Collecting options} % % The following technic allows to create user commands with the ability to put % an arbitrary number of |[|\textsl{list of (key=val)}|]| after the name of the % command. % % \medskip % \emph{Exemple} :\par\nobreak % % |\@@_collect_options:n { \F } [x=a,y=b] [z=c,t=d] { arg }| % % will be transformed in :\quad |\F{x=a,y=b,z=c,t=d}{arg}| % % \smallskip % Therefore, by writing : |\def\G{\@@_collect_options:n{\F}}|, % % the command |\G| takes in an arbitrary number of optional arguments between % square brackets. % % Be careful: that command is \emph{not} ``fully expandable'' (because of % |\peek_meaning:NTF|). % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_collect_options:n #1 { \peek_meaning:NTF [ { \@@_collect_options:nw { #1 } } { #1 { } } } % \end{macrocode} % % \bigskip % We use |\NewDocumentCommand| in order to be able to allow nested brackets % within the argument between |[| and |]|. % \begin{macrocode} \NewDocumentCommand \@@_collect_options:nw { m r[] } { \@@_collect_options:nn { #1 } { #2 } } \cs_new_protected:Npn \@@_collect_options:nn #1 #2 { \peek_meaning:NTF [ { \@@_collect_options:nnw { #1 } { #2 } } { #1 { #2 } } } \cs_new_protected:Npn \@@_collect_options:nnw #1#2[#3] { \@@_collect_options:nn { #1 } { #2 , #3 } } % \end{macrocode} % % % \bigskip % \section{Technical definitions} % % % The following constants are defined only for efficiency in the tests. % \begin{macrocode} \tl_const:Nn \c_@@_b_tl { b } \tl_const:Nn \c_@@_c_tl { c } \tl_const:Nn \c_@@_l_tl { l } \tl_const:Nn \c_@@_r_tl { r } \tl_const:Nn \c_@@_all_tl { all } \tl_const:Nn \c_@@_dot_tl { . } \tl_const:Nn \c_@@_default_tl { default } \tl_const:Nn \c_@@_star_tl { * } \str_const:Nn \c_@@_r_str { r } \str_const:Nn \c_@@_c_str { c } \str_const:Nn \c_@@_l_str { l } \str_const:Nn \c_@@_R_str { R } \str_const:Nn \c_@@_C_str { C } \str_const:Nn \c_@@_L_str { L } \str_const:Nn \c_@@_j_str { j } \str_const:Nn \c_@@_si_str { si } % \end{macrocode} % % The following token list will be used for definitions of user commands (with % |\NewDocumentCommand|) with an embellishment using an \emph{underscore} (there % may be problems because of the catcode of the underscore). % \begin{macrocode} \tl_new:N \l_@@_argspec_tl % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \seq_set_split:Nnn { N V n } \cs_generate_variant:Nn \str_lowercase:n { V } % \end{macrocode} % % \medskip % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { tikz } { % \end{macrocode} % In some constructions, we will have to use a |{pgfpicture}| which \emph{must} % be replaced by a |{tikzpicture}| if Tikz is loaded. However, this switch % between |{pgfpicture}| and |{tikzpicture}| can't be done dynamically with a % conditional because, when the Tikz library |external| is loaded by the user, % the pair |\tikzpicture|-|\endtikpicture| (or % |\begin{tikzpicture}-\end{tikzpicture}|) must be statically ``visible'' (even % when externalization is not activated). % % That's why we create |\c_@@_pgfortikzpicture_tl| and % |\c_@@_endpgfortikzpicture_tl| which will be used to construct in a % |\AtBeginDocument| the correct version of some commands. The tokens % |\exp_not:N| are mandatory. % \begin{macrocode} \tl_const:Nn \c_@@_pgfortikzpicture_tl { \exp_not:N \tikzpicture } \tl_const:Nn \c_@@_endpgfortikzpicture_tl { \exp_not:N \endtikzpicture } } { \tl_const:Nn \c_@@_pgfortikzpicture_tl { \exp_not:N \pgfpicture } \tl_const:Nn \c_@@_endpgfortikzpicture_tl { \exp_not:N \endpgfpicture } } } % \end{macrocode} % % We test whether the current class is \cls{revtex4-1} (deprecated) or % \cls{revtex4-2} because these classes redefines |\array| (of \pkg{array}) in a % way incompatible with our programmation. At the date May 2023, the current % version \cls{revtex4-2} is 4.2f (compatible with \pkg{booktabs}). % % \begin{macrocode} \IfClassLoadedTF { revtex4-1 } { \bool_const:Nn \c_@@_revtex_bool \c_true_bool } { \IfClassLoadedTF { revtex4-2 } { \bool_const:Nn \c_@@_revtex_bool \c_true_bool } { % \end{macrocode} % Maybe one of the previous classes will be loaded inside another class... We % try to detect that situation. % \begin{macrocode} \cs_if_exist:NT \rvtx@ifformat@geq { \bool_const:Nn \c_@@_revtex_bool \c_true_bool } { \bool_const:Nn \c_@@_revtex_bool \c_false_bool } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_generate_variant:Nn \tl_if_single_token_p:n { V } % \end{macrocode} % % % \bigskip % If the final user uses \pkg{nicematrix}, PGF/Tikz will write instruction % |\pgfsyspdfmark| in the |aux| file. If he changes its mind and no longer loads % \pkg{nicematrix}, an error may occur at the next compilation because of % remanent instructions |\pgfsyspdfmark| in the |aux| file. With the following % code, we try to avoid that situation. % \begin{macrocode} \cs_new_protected:Npn \@@_provide_pgfsyspdfmark: { \iow_now:Nn \@mainaux { \ExplSyntaxOn \cs_if_free:NT \pgfsyspdfmark { \cs_set_eq:NN \pgfsyspdfmark \@gobblethree } \ExplSyntaxOff } \cs_gset_eq:NN \@@_provide_pgfsyspdfmark: \prg_do_nothing: } % \end{macrocode} % % % \bigskip % We define a command |\iddots| similar to |\ddots| ($\ddots$) but with dots % going forward ($\iddots$). We use |\ProvideDocumentCommand| and so, if the % command |\iddots| has already been defined (for example by the package % \pkg{mathdots}), we don't define it again. % % \begin{macrocode} \ProvideDocumentCommand \iddots { } { \mathinner { \tex_mkern:D 1 mu \box_move_up:nn { 1 pt } { \hbox { . } } \tex_mkern:D 2 mu \box_move_up:nn { 4 pt } { \hbox { . } } \tex_mkern:D 2 mu \box_move_up:nn { 7 pt } { \vbox:n { \kern 7 pt \hbox { . } } } \tex_mkern:D 1 mu } } % \end{macrocode} % % This definition is a variant of the standard definition of |\ddots|. % % % \bigskip % In the |aux| file, we will have the references of the PGF/Tikz nodes created % by \pkg{nicematrix}. However, when \pkg{booktabs} is used, some nodes (more % precisely, some |row| nodes) will be defined twice because their position will % be modified. In order to avoid an error message in this case, we will redefine % |\pgfutil@check@rerun| in the |aux| file. % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { booktabs } { \iow_now:Nn \@mainaux \nicematrix@redefine@check@rerun } { } } \cs_set_protected:Npn \nicematrix@redefine@check@rerun { \cs_set_eq:NN \@@_old_pgfutil@check@rerun \pgfutil@check@rerun % \end{macrocode} % The new version of |\pgfutil@check@rerun| will not check the PGF nodes whose % names start with |nm-| (which is the prefix for the nodes created by % \pkg{nicematrix}). % \begin{macrocode} \cs_set_protected:Npn \pgfutil@check@rerun ##1 ##2 { \str_if_eq:eeF { nm- } { \tl_range:nnn { ##1 } 1 3 } { \@@_old_pgfutil@check@rerun { ##1 } { ##2 } } } } % \end{macrocode} % % \bigskip % We have to know whether \pkg{colortbl} is loaded in particular for the % redefinition of |\everycr|. % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { colortbl } { } { % \end{macrocode} % The command |\CT@arc@| is a command of \pkg{colortbl} which sets the color of % the rules in the array. We will use it to store the instruction of color for % the rules even if \pkg{colortbl} is not loaded. % \begin{macrocode} \cs_set_protected:Npn \CT@arc@ { } \cs_set:Npn \arrayrulecolor #1 # { \CT@arc { #1 } } \cs_set:Npn \CT@arc #1 #2 { \dim_compare:nNnT \baselineskip = \c_zero_dim \noalign { \cs_gset_nopar:Npn \CT@arc@ { \color #1 { #2 } } } } % \end{macrocode} % Idem for |\CT@drs@|. % \begin{macrocode} \cs_set:Npn \doublerulesepcolor #1 # { \CT@drs { #1 } } \cs_set:Npn \CT@drs #1 #2 { \dim_compare:nNnT \baselineskip = \c_zero_dim \noalign { \cs_gset:Npn \CT@drsc@ { \color #1 { #2 } } } } \cs_set:Npn \hline { \noalign { \ifnum 0 = `} \fi \cs_set_eq:NN \hskip \vskip \cs_set_eq:NN \vrule \hrule \cs_set_eq:NN \@width \@height { \CT@arc@ \vline } \futurelet \reserved@a \@xhline } } } % \end{macrocode} % % \bigskip % We have to redefine |\cline| for several reasons. The command |\@@_cline| will % be linked to |\cline| in the beginning of |{NiceArrayWithDelims}|. The % following commands must \emph{not} be protected. % \begin{macrocode} \cs_set:Npn \@@_standard_cline #1 { \@@_standard_cline:w #1 \q_stop } \cs_set:Npn \@@_standard_cline:w #1-#2 \q_stop { \int_if_zero:nT \l_@@_first_col_int { \omit & } \int_compare:nNnT { #1 } > \c_one_int { \multispan { \int_eval:n { #1 - 1 } } & } \multispan { \int_eval:n { #2 - #1 + 1 } } { \CT@arc@ \leaders \hrule \@height \arrayrulewidth \hfill % \end{macrocode} % The following |\skip_horizontal:N \c_zero_dim| is to prevent a potential % |\unskip| to delete the |\leaders|\footnote{See question 99041 on TeX % StackExchange.} % \begin{macrocode} \skip_horizontal:N \c_zero_dim } % \end{macrocode} % Our |\everycr| has been modified. In particular, the creation of the |row| % node is in the |\everycr| (maybe we should put it with the incrementation of % |\c@iRow|). Since the following |\cr| correspond to a ``false row'', we have % to nullify |\everycr|. % \begin{macrocode} \everycr { } \cr \noalign { \skip_vertical:N -\arrayrulewidth } } % \end{macrocode} % % \bigskip % The following version of |\cline| spreads the array of a quantity equal % to |\arrayrulewidth| as does |\hline|. It will be loaded excepted if the key % |standard-cline| has been used. % \begin{macrocode} \cs_set:Npn \@@_cline % \end{macrocode} % We have to act in a fully expandable way since there may be |\noalign| (in the % |\multispan|) to detect. That's why we use |\@@_cline_i:en|. % \begin{macrocode} { \@@_cline_i:en \l_@@_first_col_int } % \end{macrocode} % The command |\cline_i:nn| has two arguments. The first is the number of the % current column (it \emph{must} be used in that column). The second is a % standard argument of |\cline| of the form \textsl{i}-\textsl{j} or the form % \textsl{i}. % \begin{macrocode} \cs_set:Npn \@@_cline_i:nn #1 #2 { \@@_cline_i:w #1|#2- \q_stop } \cs_set:Npn \@@_cline_i:w #1|#2-#3 \q_stop { \tl_if_empty:nTF { #3 } { \@@_cline_iii:w #1|#2-#2 \q_stop } { \@@_cline_ii:w #1|#2-#3 \q_stop } } \cs_set:Npn \@@_cline_ii:w #1|#2-#3-\q_stop { \@@_cline_iii:w #1|#2-#3 \q_stop } \cs_set:Npn \@@_cline_iii:w #1|#2-#3 \q_stop { % \end{macrocode} % Now, |#1| is the number of the current column and we have to draw a line from % the column |#2| to the column |#3| (both included). % \begin{macrocode} \int_compare:nNnT { #1 } < { #2 } { \multispan { \int_eval:n { #2 - #1 } } & } \multispan { \int_eval:n { #3 - #2 + 1 } } { \CT@arc@ \leaders \hrule \@height \arrayrulewidth \hfill \skip_horizontal:N \c_zero_dim } % \end{macrocode} % You look whether there is another |\cline| to draw (the final user may put % several |\cline|). % \begin{macrocode} \peek_meaning_remove_ignore_spaces:NTF \cline { & \@@_cline_i:en { \int_eval:n { #3 + 1 } } } { \everycr { } \cr } } \cs_generate_variant:Nn \@@_cline_i:nn { e n } % \end{macrocode} % % % \bigskip % The following command will be nullified in the environment |{NiceTabular}|, % |{NiceTabular*}| and |{NiceTabularX}|. % \begin{macrocode} \cs_set_eq:NN \@@_math_toggle: \c_math_toggle_token % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_set_CT@arc@:n #1 { \tl_if_blank:nF { #1 } { \tl_if_head_eq_meaning:nNTF { #1 } [ { \cs_set:Npn \CT@arc@ { \color #1 } } { \cs_set:Npn \CT@arc@ { \color { #1 } } } } } \cs_generate_variant:Nn \@@_set_CT@arc@:n { o } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_set_CT@drsc@:n #1 { \tl_if_head_eq_meaning:nNTF { #1 } [ { \cs_set:Npn \CT@drsc@ { \color #1 } } { \cs_set:Npn \CT@drsc@ { \color { #1 } } } } \cs_generate_variant:Nn \@@_set_CT@drsc@:n { o } % \end{macrocode} % % \bigskip % The following command must \emph{not} be protected since it will be used to % write instructions in the (internal) |\CodeBefore|. % \begin{macrocode} \cs_new:Npn \@@_exp_color_arg:Nn #1 #2 { \tl_if_head_eq_meaning:nNTF { #2 } [ { #1 #2 } { #1 { #2 } } } \cs_generate_variant:Nn \@@_exp_color_arg:Nn { N o } % \end{macrocode} % % The following command must be protected because of its use of the command |\color|. % \begin{macrocode} \cs_new_protected:Npn \@@_color:n #1 { \tl_if_blank:nF { #1 } { \@@_exp_color_arg:Nn \color { #1 } } } \cs_generate_variant:Nn \@@_color:n { o } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_set_eq:NN \@@_old_pgfpointanchor \pgfpointanchor % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_rescan_for_spanish:N #1 { \tl_set_rescan:Nno #1 { \char_set_catcode_other:N > \char_set_catcode_other:N < } #1 } % \end{macrocode} % % % \bigskip % \section{Parameters} % % \bigskip % The following counter will count the environments |{NiceArray}|. The value of % this counter will be used to prefix the names of the Tikz nodes created in the % array. % \begin{macrocode} \int_new:N \g_@@_env_int % \end{macrocode} % % \bigskip % The following command is only a syntaxic shortcut. It must \emph{not} be % protected (it will be used in names of \textsc{pgf} nodes). % \begin{macrocode} \cs_new:Npn \@@_env: { nm - \int_use:N \g_@@_env_int } % \end{macrocode} % % \bigskip % The command |\NiceMatrixLastEnv| is not used by the package \pkg{nicematrix}. % It's only a facility given to the final user. It gives the number of the last % environment (in fact the number of the current environment but it's meant to % be used after the environment in order to refer to that environment --- and % its nodes --- without having to give it a name). This command \emph{must} be % expandable since it will be used in \pkg{pgf} nodes. % \begin{macrocode} \NewExpandableDocumentCommand \NiceMatrixLastEnv { } { \int_use:N \g_@@_env_int } % \end{macrocode} % % % \bigskip % The following command is only a syntaxic shortcut. The |q| in |qpoint| means % \emph{quick}. % \begin{macrocode} \cs_new_protected:Npn \@@_qpoint:n #1 { \pgfpointanchor { \@@_env: - #1 } { center } } % \end{macrocode} % % \bigskip % If the user uses |{NiceTabular}|, |{NiceTabular*}| or |{NiceTabularX}|, we % will raise the following flag. % \begin{macrocode} \bool_new:N \l_@@_tabular_bool % \end{macrocode} % % \bigskip % |\g_@@_delims_bool| will be true for the environments with delimiters (ex. : % |{pNiceMatrix}|, |{pNiceArray}|, |\pAutoNiceMatrix|, etc.). % \begin{macrocode} \bool_new:N \g_@@_delims_bool \bool_gset_true:N \g_@@_delims_bool % \end{macrocode} % In fact, if there is delimiters in the preamble of |{NiceArray}| (eg: % |[cccc]|), this boolean will be set to false. % % \medskip % The following boolean will be equal to |true| in the environments which have % a preamble (provided by the final user): |{NiceTabular}|, |{NiceArray}|, % |{pNiceArray}|, etc. % \begin{macrocode} \bool_new:N \l_@@_preamble_bool \bool_set_true:N \l_@@_preamble_bool % \end{macrocode} % % \medskip % We need a special treatment for |{NiceMatrix}| when |vlines| is not used, in % order to retrieve |\arraycolsep| on both sides. % \begin{macrocode} \bool_new:N \l_@@_NiceMatrix_without_vlines_bool % \end{macrocode} % % \bigskip % The following counter will count the environments |{NiceMatrixBlock}|. % \begin{macrocode} \int_new:N \g_@@_NiceMatrixBlock_int % \end{macrocode} % % \bigskip % It's possible to put tabular notes (with |\tabularnote|) in the caption if % that caption is composed \emph{above} the tabular. In such case, we will count % in |\g_@@_notes_caption_int| the number of uses of the command % |\tabularnote| \emph{without optional argument} in that caption. % \begin{macrocode} \int_new:N \g_@@_notes_caption_int % \end{macrocode} % % \bigskip % The dimension |\l_@@_columns_width_dim| will be used when the options specify % that all the columns must have the same width (but, if the key |columns-width| % is used with the special value |auto|, the boolean % |\l_@@_auto_columns_width_bool| also will be raised). % \begin{macrocode} \dim_new:N \l_@@_columns_width_dim % \end{macrocode} % % \bigskip % The dimension |\l_@@_col_width_dim| will be available in each cell which % belongs to a column of fixed width: |w{...}{...}|, |W{...}{...}|, |p{...}|, % |m{...}|, |b{...}| but also |X| (when the actual width of that column is known, that % is to say after the first compilation). It's the width of that column. It will % be used by some commands |\Block|. A non positive value means that the column % has no fixed width (it's a column of type |c|, |r|, |l|, etc.). % \begin{macrocode} \dim_new:N \l_@@_col_width_dim \dim_set:Nn \l_@@_col_width_dim { -1 cm } % \end{macrocode} % % % \bigskip % The following counters will be used to count the numbers of rows and columns % of the array. % \begin{macrocode} \int_new:N \g_@@_row_total_int \int_new:N \g_@@_col_total_int % \end{macrocode} % % \bigskip % The following parameter will be used by |\@@_create_row_node:| to avoid to % create the same row-node twice (at the end of the array). % \begin{macrocode} \int_new:N \g_@@_last_row_node_int % \end{macrocode} % % \bigskip % The following counter corresponds to the key |nb-rows| of the command % |\RowStyle|. % \begin{macrocode} \int_new:N \l_@@_key_nb_rows_int % \end{macrocode} % % % \bigskip % The following token list will contain the type of horizontal alignment of the % current cell as provided by the corresponding column. The possible values are % |r|, |l|, |c| and |j|. For example, a column |p[l]{3cm}| will provide the % value |l| for all the cells of the column. % \begin{macrocode} \tl_new:N \l_@@_hpos_cell_tl \tl_set_eq:NN \l_@@_hpos_cell_tl \c_@@_c_tl % \end{macrocode} % % % \bigskip % When there is a mono-column block (created by the command |\Block|), we want % to take into account the width of that block for the width of the column. % That's why we compute the width of that block in the |\g_@@_blocks_wd_dim| % and, after the construction of the box |\l_@@_cell_box|, we change the width % of that box to take into account the length |\g_@@_blocks_wd_dim|. % \begin{macrocode} \dim_new:N \g_@@_blocks_wd_dim % \end{macrocode} % % \bigskip % Idem for the mono-row blocks. % \begin{macrocode} \dim_new:N \g_@@_blocks_ht_dim \dim_new:N \g_@@_blocks_dp_dim % \end{macrocode} % % \bigskip % The following dimension correspond to the key |width| (which may be fixed in % |\NiceMatrixOptions| but also in an environment |{NiceTabular}|). % \begin{macrocode} \dim_new:N \l_@@_width_dim % \end{macrocode} % % \bigskip % The sequence |\g_@@_names_seq| will be the list of all the names of % environments used (via the option |name|) in the document: two environments % must not have the same name. However, it's possible to use the option % |allow-duplicate-names|. % \begin{macrocode} \seq_new:N \g_@@_names_seq % \end{macrocode} % % \bigskip % We want to know whether we are in an environment of \pkg{nicematrix} because we % will raise an error if the user tries to use nested environments. % \begin{macrocode} \bool_new:N \l_@@_in_env_bool % \end{macrocode} % % \bigskip % The following key corresponds to the key |notes/detect_duplicates|. % \begin{macrocode} \bool_new:N \l_@@_notes_detect_duplicates_bool \bool_set_true:N \l_@@_notes_detect_duplicates_bool % \end{macrocode} % % \bigskip % If the user uses |{NiceTabular*}|, the width of the tabular (in the first % argument of the environment |{NiceTabular*}|) will be stored in the following % dimension. % \begin{macrocode} \dim_new:N \l_@@_tabular_width_dim % \end{macrocode} % % \bigskip % The following dimension will be used for the total width of composite rules % (\emph{total} means that the spaces on both sides are included). % \begin{macrocode} \dim_new:N \l_@@_rule_width_dim % \end{macrocode} % % \bigskip % The key |color| in a command of rule such as |\Hline| (or the specifier % ``\verb+|+'' in the preamble of an environment). % \begin{macrocode} \tl_new:N \l_@@_rule_color_tl % \end{macrocode} % % \bigskip % The following boolean will be raised when the command |\rotate| is used. % \begin{macrocode} \bool_new:N \g_@@_rotate_bool % \end{macrocode} % % \bigskip % The following boolean will be raise then the command |\rotate| is used with % the key |c|. % \begin{macrocode} \bool_new:N \g_@@_rotate_c_bool % \end{macrocode} % % \bigskip % In a cell, it will be possible to know whether we are in a cell of a column of % type |X| thanks to that flag. % \begin{macrocode} \bool_new:N \l_@@_X_bool % \end{macrocode} % % \begin{macrocode} \bool_new:N \g_@@_caption_finished_bool % \end{macrocode} % % \bigskip % We will write in |\g_@@_aux_tl| all the instructions that we have to write on % the |aux| file for the current environment. The contain of that token list % will be written on the |aux| file at the end of the environment (in an % instruction |\tl_gset:cn { c_@@_ \int_use:N \g_@@_env_int _ tl }|). % \begin{macrocode} \tl_new:N \g_@@_aux_tl % \end{macrocode} % % During the second run, if informations concerning the current environment has % been found in the |aux| file, the following flag will be raised. % \begin{macrocode} \bool_new:N \g_@@_aux_found_bool % \end{macrocode} % % \bigskip % In particuler, in that |aux| file, there will be, for each environment of % \pkg{nicematrix}, an affectation for the the following sequence that will % contain informations about the size of the array. % \begin{macrocode} \seq_new:N \g_@@_size_seq % \end{macrocode} % % \bigskip % \begin{macrocode} \tl_new:N \g_@@_left_delim_tl \tl_new:N \g_@@_right_delim_tl % \end{macrocode} % % \bigskip % The token list |\g_@@_user_preamble_tl| will contain the preamble provided by % the the final user of \pkg{nicematrix} (eg the preamble of an environment % |{NiceTabular}|). % \begin{macrocode} \tl_new:N \g_@@_user_preamble_tl % \end{macrocode} % The token list |\g_@@_array_preamble_tl| will contain the preamble constructed % by \pkg{nicematrix} for the environment |{array}| (of \pkg{array}). % \begin{macrocode} \tl_new:N \g_@@_array_preamble_tl % \end{macrocode} % For |\multicolumn|. % \begin{macrocode} \tl_new:N \g_@@_preamble_tl % \end{macrocode} % % \bigskip % The following parameter corresponds to the key |columns-type| of the % environments |{NiceMatrix}|, |{pNiceMatrix}|, etc. and also the key % |matrix / columns-type| of |\NiceMatrixOptions|. % \begin{macrocode} \tl_new:N \l_@@_columns_type_tl \str_set:Nn \l_@@_columns_type_tl { c } % \end{macrocode} % % \bigskip % The following parameters correspond to the keys |down|, |up| and |middle| of a % command such as |\Cdots|. Usually, the final user doesn't use that keys % directly because he uses the syntax with the embellishments |_|, |^| and |:|. % \begin{macrocode} \tl_new:N \l_@@_xdots_down_tl \tl_new:N \l_@@_xdots_up_tl \tl_new:N \l_@@_xdots_middle_tl % \end{macrocode} % % \bigskip % We will store in the following sequence informations provided by the % instructions |\rowlistcolors| in the main array (not in the |\CodeBefore|). % \begin{macrocode} \seq_new:N \g_@@_rowlistcolors_seq % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_test_if_math_mode: { \if_mode_math: \else: \@@_fatal:n { Outside~math~mode } \fi: } % \end{macrocode} % % % The list of the columns where vertical lines in sub-matrices (vlism) must be % drawn. Of course, the actual value of this sequence will be known after the % analyse of the preamble of the array. % \begin{macrocode} \seq_new:N \g_@@_cols_vlism_seq % \end{macrocode} % % \bigskip % The following colors will be used to memorize the color of the potential ``first % col'' and the potential ``first row''. % \begin{macrocode} \colorlet { nicematrix-last-col } { . } \colorlet { nicematrix-last-row } { . } % \end{macrocode} % \bigskip % The following string is the name of the current environment or the current % command of \pkg{nicematrix} (despite its name which contains \textsl{env}). % \begin{macrocode} \str_new:N \g_@@_name_env_str % \end{macrocode} % % \bigskip % The following string will contain the word \emph{command} or % \emph{environment} whether we are in a command of \pkg{nicematrix} or in an % environment of \pkg{nicematrix}. The default value is \emph{environment}. % \begin{macrocode} \tl_new:N \g_@@_com_or_env_str \tl_gset:Nn \g_@@_com_or_env_str { environment } % \end{macrocode} % % \bigskip % \begin{macrocode} \bool_new:N \l_@@_bold_row_style_bool % \end{macrocode} % % \bigskip % The following command will be able to reconstruct the full name of the current % command or environment (despite its name which contains \textsl{env}). This % command must \emph{not} be protected since it will be used in error messages % and we have to use |\str_if_eq:VnTF| and not |\tl_if_eq:NnTF| because we need % to be fully expandable). % \begin{macrocode} \cs_new:Npn \@@_full_name_env: { \str_if_eq:VnTF \g_@@_com_or_env_str { command } { command \space \c_backslash_str \g_@@_name_env_str } { environment \space \{ \g_@@_name_env_str \} } } % \end{macrocode} % % % \bigskip % For the key |code| of the command |\SubMatrix| (itself in the main % |\CodeAfter|), we will use the following token list. % \begin{macrocode} \tl_new:N \l_@@_code_tl % \end{macrocode} % % \bigskip % For the key |pgf-node-code|. That code will be used when the nodes of the % cells (that is to say the nodes of the form |i-j|) will be created. % \begin{macrocode} \tl_new:N \l_@@_pgf_node_code_tl % \end{macrocode} % % % \bigskip % The so-called |\CodeBefore| is splitted in two parts because we want to control % the order of execution of some instructions. % \begin{macrocode} \tl_new:N \g_@@_pre_code_before_tl \tl_new:N \g_nicematrix_code_before_tl % \end{macrocode} % The value of the key |code-before| will be added to the left of % |\g_@@_pre_code_before_tl|. Idem for the code between |\CodeBefore| and % |\Body|. % % \bigskip % The so-called |\CodeAfter| is splitted in two parts because we want to control % the order of execution of some instructions. % \begin{macrocode} \tl_new:N \g_@@_pre_code_after_tl \tl_new:N \g_nicematrix_code_after_tl % \end{macrocode} % The |\CodeAfter| provided by the final user (with the key |code-after| or the % keyword |\CodeAfter|) will be stored in the second token list. % % \bigskip % \begin{macrocode} \bool_new:N \l_@@_in_code_after_bool % \end{macrocode} % % \bigskip % The counters |\l_@@_old_iRow_int| and |\l_@@_old_jCol_int| will be used to % save the values of the potential LaTeX counters |iRow| and |jCol|. These LaTeX % counters will be restored at the end of the environment. % \begin{macrocode} \int_new:N \l_@@_old_iRow_int \int_new:N \l_@@_old_jCol_int % \end{macrocode} % The TeX counters |\c@iRow| and |\c@jCol| will be created in the beginning of % |{NiceArrayWithDelims}| (if they don't exist previously). % % \bigskip % The following sequence will contain the names (without backslash) of the % commands created by |custom-line| by the key |command| or |ccommand| (commands % used by the final user in order to draw horizontal rules). % \begin{macrocode} \seq_new:N \l_@@_custom_line_commands_seq % \end{macrocode} % % \bigskip % The following token list corresponds to the key |rules/color| available % in the environments. % \begin{macrocode} \tl_new:N \l_@@_rules_color_tl % \end{macrocode} % % \bigskip % The sum of the weights of all the |X|-columns in the preamble. The weight of a % |X|-column is given as an optional argument between square brackets. The % default value, of course, is $1$. % \begin{macrocode} \int_new:N \g_@@_total_X_weight_int % \end{macrocode} % % If there is at least one |X|-column in the preamble of the array, the % following flag will be raised via the |aux| file. The length % |l_@@_x_columns_dim| will be the width of |X|-columns of weight $1$ (the width % of a column of weigth $n$ will be that dimension multiplied by~$n$). That % value is computed after the construction of the array during the first % compilation in order to be used in the following run. % \begin{macrocode} \bool_new:N \l_@@_X_columns_aux_bool \dim_new:N \l_@@_X_columns_dim % \end{macrocode} % % % \bigskip % This boolean will be used only to detect in an expandable way whether we are % at the beginning of the (potential) column zero, in order to raise an error if % |\Hdotsfor| is used in that column. % \begin{macrocode} \bool_new:N \g_@@_after_col_zero_bool % \end{macrocode} % % \bigskip % A kind of false row will be inserted at the end of the array for the % construction of the |col| nodes (and also to fix the width of the columns when % |columns-width| is used). When this special row will be created, we will raise % the flag |\g_@@_row_of_col_done_bool| in order to avoid some actions set in % the redefinition of |\everycr| when the last |\cr| of the |\halign| will occur % (after that row of |col| nodes). % \begin{macrocode} \bool_new:N \g_@@_row_of_col_done_bool % \end{macrocode} % % % \bigskip % It's possible to use the command |\NotEmpty| to specify explicitely that a % cell must be considered as non empty by \pkg{nicematrix} (the Tikz nodes are % constructed only in the non empty cells). % \begin{macrocode} \bool_new:N \g_@@_not_empty_cell_bool % \end{macrocode} % % \bigskip % |\l_@@_code_before_tl| may contain two types of informations: % \begin{itemize} % \item A |code-before| written in the |aux| file by a previous run. When the % |aux| file is read, this |code-before| is stored in % |\g_@@_code_before_|\textsl{i}|_tl| (where \textsl{i} is the number of the % environment) and, at the beginning of the environment, it will be put in % |\l_@@_code_before_tl|. % \item The final user can explicitly add material in |\l_@@_code_before_tl| by % using the key |code-before| or the keyword |\CodeBefore| (with the keyword % |\Body|). % \end{itemize} % \begin{macrocode} \tl_new:N \l_@@_code_before_tl \bool_new:N \l_@@_code_before_bool % \end{macrocode} % % % \bigskip % The following token list will contain the code inserted in each cell of the % current row (this token list will be cleared at the beginning of each row). % \begin{macrocode} \tl_new:N \g_@@_row_style_tl % \end{macrocode} % % \bigskip % The following dimensions will be used when drawing the dotted lines. % \begin{macrocode} \dim_new:N \l_@@_x_initial_dim \dim_new:N \l_@@_y_initial_dim \dim_new:N \l_@@_x_final_dim \dim_new:N \l_@@_y_final_dim % \end{macrocode} % % \bigskip % The L3 programming layer provides scratch dimensions |\l_tmpa_dim| and % |\l_tmpb_dim|. We creates two more in the same spirit. % \begin{macrocode} \dim_zero_new:N \l_@@_tmpc_dim \dim_zero_new:N \l_@@_tmpd_dim % \end{macrocode} % % \bigskip % Some cells will be declared as ``empty'' (for example a cell with an % instruction |\Cdots|). % \begin{macrocode} \bool_new:N \g_@@_empty_cell_bool % \end{macrocode} % % % \bigskip % The following dimensions will be used internally to compute the width of the % potential ``first column'' and ``last column''. % \begin{macrocode} \dim_new:N \g_@@_width_last_col_dim \dim_new:N \g_@@_width_first_col_dim % \end{macrocode} % % \bigskip % The following sequence will contain the characteristics of the blocks of the % array, specified by the command |\Block|. Each block is represented by 6 % components surrounded by curly braces: % % |{|\textsl{imin}|}{|\textsl{jmin}|}{|\textsl{imax}|}{|\textsl{jmax}|}{|\textsl{options}|}{|\textsl{contents}|}|. % % The variable is global because it will be modified in the cells of the array. % \begin{macrocode} \seq_new:N \g_@@_blocks_seq % \end{macrocode} % We also manage a sequence of the \emph{positions} of the blocks. In that % sequence, each block is represented by only five components: % |{|\textsl{imin}|}{|\textsl{jmin}|}{|\textsl{imax}|}{|\textsl{jmax}|}{|% % \textsl{name}|}|. A block with the key |hvlines| won't appear in that % sequence (otherwise, the lines in that block would not be drawn!). % \begin{macrocode} \seq_new:N \g_@@_pos_of_blocks_seq % \end{macrocode} % In fact, this sequence will also contain the positions of the cells with a % |\diagbox|. The sequence |\g_@@_pos_of_blocks_seq| will be used when we will % draw the rules (which respect the blocks). % % \bigskip % We will also manage a sequence for the positions of the dotted lines. These % dotted lines are created in the array by |\Cdots|, |\Vdots|, |\Ddots|, etc. % However, their positions, that is to say, their extremities, will be % determined only after the construction of the array. In this sequence, each % item contains five components: % |{|\textsl{imin}|}{|\textsl{jmin}|}{|\textsl{imax}|}{|\textsl{jmax}|}{|% % \textsl{name}|}|. % \begin{macrocode} \seq_new:N \g_@@_pos_of_xdots_seq % \end{macrocode} % The sequence |\g_@@_pos_of_xdots_seq| will be used when we will draw the rules % required by the key |hvlines| (these rules won't be drawn within the virtual % blocks corresponding to the dotted lines). % % \medskip % The final user may decide to ``stroke'' a block (using, for example, the key % |draw=red!15| when using the command |\Block|). In that case, the rules % specified, for instance, by |hvlines| must not be drawn around the block. % That's why we keep the information of all that stroken blocks in the following % sequence. % \begin{macrocode} \seq_new:N \g_@@_pos_of_stroken_blocks_seq % \end{macrocode} % % % \medskip % If the user has used the key |corners|, all the cells which are in an (empty) % corner will be stored in the following sequence. % \begin{macrocode} \seq_new:N \l_@@_corners_cells_seq % \end{macrocode} % % \medskip % The list of the names of the potential |\SubMatrix| in the |\CodeAfter| of an % environment. Unfortunately, that list has to be global (we have to use it % inside the group for the options of a given |\SubMatrix|). % \begin{macrocode} \seq_new:N \g_@@_submatrix_names_seq % \end{macrocode} % % \medskip % The following flag will be raised if the key |width| is used in an environment % |{NiceTabular}| (not in a command |\NiceMatrixOptions|). You use it to raise % an error when this key is used while no column |X| is used. % \begin{macrocode} \bool_new:N \l_@@_width_used_bool % \end{macrocode} % % \medskip % The sequence |\g_@@_multicolumn_cells_seq| will contain the list of the cells % of the array where a command |\multicolumn{|$n$|}{...}{...}| with $n>1$ is % issued. In |\g_@@_multicolumn_sizes_seq|, the ``sizes'' (that is to say the % values of $n$) correspondant will be stored. These lists will be used for the % creation of the ``medium nodes'' (if they are created). % \begin{macrocode} \seq_new:N \g_@@_multicolumn_cells_seq \seq_new:N \g_@@_multicolumn_sizes_seq % \end{macrocode} % % \medskip % The following counters will be used when searching the extremities of a dotted % line (we need these counters because of the potential ``open'' lines in the % |\SubMatrix|---the |\SubMatrix| in the |code-before|). % \begin{macrocode} \int_new:N \l_@@_row_min_int \int_new:N \l_@@_row_max_int \int_new:N \l_@@_col_min_int \int_new:N \l_@@_col_max_int % \end{macrocode} % \medskip % The following counters will be used when drawing the rules. % \begin{macrocode} \int_new:N \l_@@_start_int \int_set_eq:NN \l_@@_start_int \c_one_int \int_new:N \l_@@_end_int \int_new:N \l_@@_local_start_int \int_new:N \l_@@_local_end_int % \end{macrocode} % % \medskip % The following sequence will be used when the command |\SubMatrix| is used in % the |\CodeBefore| (and not in the |\CodeAfter|). It will contain the position of % all the sub-matrices specified in the |\CodeBefore|. Each sub-matrix is % represented by an ``object'' of the form |{|$i$|}{|$j$|}{|$k$|}{|$l$|}| % where $i$ and $j$ are the number of row and column of the upper-left cell and % $k$ and $l$ the number of row and column of the lower-right cell. % \begin{macrocode} \seq_new:N \g_@@_submatrix_seq % \end{macrocode} % % \medskip % We are able to determine the number of columns specified in the preamble (for % the environments with explicit preamble of course and without the potential % exterior columns). % \begin{macrocode} \int_new:N \g_@@_static_num_of_col_int % \end{macrocode} % % \medskip % The following parameters correspond to the keys |fill|, |opacity|, |draw|, % |tikz|, |borders|, and |rounded-corners| of the command |\Block|. % \begin{macrocode} \tl_new:N \l_@@_fill_tl \tl_new:N \l_@@_opacity_tl \tl_new:N \l_@@_draw_tl \seq_new:N \l_@@_tikz_seq \clist_new:N \l_@@_borders_clist \dim_new:N \l_@@_rounded_corners_dim % \end{macrocode} % The last parameter has no direct link with the [empty] corners of the array % (which are computed and taken into account by \pkg{nicematrix} when the key % |corners| is used). % % \medskip % The following dimension corresponds to the key |rounded-corners| available in % an individual environment |{NiceTabular}|. When that key is used, a clipping % is applied in the |\CodeBefore| of the environment in order to have rounded % corners for the potential colored panels. % \begin{macrocode} \dim_new:N \l_@@_tab_rounded_corners_dim % \end{macrocode} % % \medskip % The following token list correspond to the key |color| of the command |\Block| % and also the key |color| of the command |\RowStyle|. % \begin{macrocode} \tl_new:N \l_@@_color_tl % \end{macrocode} % % \medskip % In the key |tikz| of a command |\Block| or in the argument of a command % |\TikzEveryCell|, the final user puts a list of tikz keys. But, you have added % another key, named |offset| (which means that an offset will be used for the % frame of the block or the cell). The following parameter corresponds to that key. % \begin{macrocode} \dim_new:N \l_@@_offset_dim % \end{macrocode} % % \medskip % Here is the dimension for the width of the rule when a block (created by % |\Block|) is stroked. % \begin{macrocode} \dim_new:N \l_@@_line_width_dim % \end{macrocode} % % \medskip % The parameters of the horizontal position of the label of a block. If the user % uses the key |c| or |C|, the value is |c|. If the user uses the key |l| or % |L|, the value is |l|. If the user uses the key |r| or |R|, the value is |r|. % If the user has used a capital letter, the boolean % |\l_@@_hpos_of_block_cap_bool| will be raised (in the second pass of the % analyze of the keys of the command |\Block|). % \begin{macrocode} \str_new:N \l_@@_hpos_block_str \str_set:Nn \l_@@_hpos_block_str { c } \bool_new:N \l_@@_hpos_of_block_cap_bool % \end{macrocode} % % \medskip % If the final user has used the special color ``|nocolor|'', the following flag % will be raised. % \begin{macrocode} \bool_new:N \@@_nocolor_used_bool % \end{macrocode} % % \medskip % For the vertical position, the possible values are |c|, |t| and |b|. % \begin{macrocode} \str_new:N \l_@@_vpos_block_str \str_set:Nn \l_@@_vpos_block_str { c } % \end{macrocode} % % % \medskip % Used when the key |draw-first| is used for |\Ddots| or |\Iddots|. % \begin{macrocode} \bool_new:N \l_@@_draw_first_bool % \end{macrocode} % % \medskip % The following flag corresponds to the keys |vlines| and |hlines| of the % command |\Block| (the key |hvlines| is the conjunction of both). % \begin{macrocode} \bool_new:N \l_@@_vlines_block_bool \bool_new:N \l_@@_hlines_block_bool % \end{macrocode} % % % \medskip % The blocks which use the key |-| will store their content in a box. These % boxes are numbered with the following counter. % \begin{macrocode} \int_new:N \g_@@_block_box_int % \end{macrocode} % % \medskip % \begin{macrocode} \dim_new:N \l_@@_submatrix_extra_height_dim \dim_new:N \l_@@_submatrix_left_xshift_dim \dim_new:N \l_@@_submatrix_right_xshift_dim \clist_new:N \l_@@_hlines_clist \clist_new:N \l_@@_vlines_clist \clist_new:N \l_@@_submatrix_hlines_clist \clist_new:N \l_@@_submatrix_vlines_clist % \end{macrocode} % % \medskip % The following key is set when the keys |hvlines| and |hvlines-except-borders| % are used. It's used only to change slightly the clipping path set by the key % |rounded-corners| (for a |{tabular}|). % \begin{macrocode} \bool_new:N \l_@@_hvlines_bool % \end{macrocode} % % % \bigskip % The following flag will be used by (for instance) |\@@_vline_ii:|. % When |\l_@@_dotted_bool| is |true|, a dotted line (with our system) will be drawn. % \begin{macrocode} \bool_new:N \l_@@_dotted_bool % \end{macrocode} % % \bigskip % The following flag will be set to true during the composition of a caption % specified (by the key |caption|). % \begin{macrocode} \bool_new:N \l_@@_in_caption_bool % \end{macrocode} % % % \bigskip % \textbf{Variables for the exterior rows and columns}\par\nobreak % % \medskip % The keys for the exterior rows and columns are |first-row|, |first-col|, % |last-row| and |last-col|. However, internally, these keys are not coded in a % similar way. % % \bigskip % \begin{itemize} % \item \textbf{First row}\par\nobreak % The integer |\l_@@_first_row_int| is the number of the first row of the % array. The default value is $1$, but, if the option |first-row| is used, % the value will be~$0$. % \begin{macrocode} \int_new:N \l_@@_first_row_int \int_set:Nn \l_@@_first_row_int 1 % \end{macrocode} % % \medskip % \item \textbf{First column}\par\nobreak % The integer |\l_@@_first_col_int| is the number of the first column of the % array. The default value is $1$, but, if the option |first-col| is used, % the value will be~$0$. % \begin{macrocode} \int_new:N \l_@@_first_col_int \int_set_eq:NN \l_@@_first_col_int \c_one_int % \end{macrocode} % % \medskip % \item \textbf{Last row}\par\nobreak % The counter |\l_@@_last_row_int| is the number of the potential ``last row'', % as specified by the key |last-row|. A value of $-2$ means that there is no % ``last row''. A value of $-1$ means that there is a ``last row'' but we don't % know the number of that row (the key |last-row| has been used without value % and the actual value has not still been read in the |aux| file). % \begin{macrocode} \int_new:N \l_@@_last_row_int \int_set:Nn \l_@@_last_row_int { -2 } % \end{macrocode} % % \smallskip % If, in an environment like |{pNiceArray}|, the option |last-row| is used % without value, we will globally raise the following flag. It will be used to % know if we have, after the construction of the array, to write in the |aux| % file the number of the ``last row''.\footnote{We can't use % |\l_@@_last_row_int| for this usage because, if \pkg{nicematrix} has read its % value from the |aux| file, the value of the counter won't be $-1$ any longer.} % \begin{macrocode} \bool_new:N \l_@@_last_row_without_value_bool % \end{macrocode} % % \smallskip % Idem for |\l_@@_last_col_without_value_bool| % \begin{macrocode} \bool_new:N \l_@@_last_col_without_value_bool % \end{macrocode} % % \medskip % \item \textbf{Last column}\par\nobreak % % For the potential ``last column'', we use an integer. A value of $-2$ means % that there is no last column. A value of $-1$ means that we are in an % environment without preamble (e.g. |{bNiceMatrix}|) and there is a last column % but we don't know its value because the user has used the option |last-col| % without value. A value of $0$ means that the option |last-col| has been used % in an environment with preamble (like |{pNiceArray}|): in this case, the key % was necessary without argument. The command |\NiceMatrixOptions| also sets % |\l_@@_last_col_int| to~$0$. % \begin{macrocode} \int_new:N \l_@@_last_col_int \int_set:Nn \l_@@_last_col_int { -2 } % \end{macrocode} % % However, we have also a boolean. Consider the following code: % \begin{center} % \begin{BVerbatim} % \begin{pNiceArray}{cc}[last-col] % 1 & 2 \\ % 3 & 4 % \end{pNiceArray} % \end{BVerbatim} % \end{center} % In such a code, the ``last column'' specified by the key |last-col| is not % used. We want to be able to detect such a situation and we create a boolean % for that job. % \begin{macrocode} \bool_new:N \g_@@_last_col_found_bool % \end{macrocode} % This boolean is set to |false| at the end of |\@@_pre_array_ii:|. % % \medskip % In the last column, we will raise the following flag (it will be used by % |\OnlyMainNiceMatrix|). % \begin{macrocode} \bool_new:N \l_@@_in_last_col_bool % \end{macrocode} % \end{itemize} % % \bigskip % \textbf{Some utilities} % % \medskip % \begin{macrocode} \cs_set_protected:Npn \@@_cut_on_hyphen:w #1-#2\q_stop { \cs_set_nopar:Npn \l_tmpa_tl { #1 } \cs_set_nopar:Npn \l_tmpb_tl { #2 } } % \end{macrocode} % % % The following takes as argument the name of a |clist| and which should be a % list of intervals of integers. It \emph{expands} that list, that is to say, % it replaces (by a sort of |mapcan| or |flat_map|) the interval by the explicit % list of the integers. % \begin{macrocode} \cs_new_protected:Npn \@@_expand_clist:N #1 { \clist_if_in:NVF #1 \c_@@_all_tl { \clist_clear:N \l_tmpa_clist \clist_map_inline:Nn #1 { \tl_if_in:nnTF { ##1 } { - } { \@@_cut_on_hyphen:w ##1 \q_stop } { \cs_set_nopar:Npn \l_tmpa_tl { ##1 } \cs_set_nopar:Npn \l_tmpb_tl { ##1 } } \int_step_inline:nnn { \l_tmpa_tl } { \l_tmpb_tl } { \clist_put_right:Nn \l_tmpa_clist { ####1 } } } \tl_set_eq:NN #1 \l_tmpa_clist } } % \end{macrocode} % % \bigskip % The following internal parameters are for: % \begin{itemize} % \item |\Ldots| \emph{with both extremities open} (and hence also |\Hdotsfor| in an % exterior row; % \item |\Vdots| \emph{with both extremities open} (and hence also |\Vdotsfor| in an % exterior column; % \item when the special character ``|:|'' is used in order to put the label of % a so-called ``dotted line'' \emph{on the line}, a margin of % |\c_@@_innersep_middle_dim| will be added around the label. % \end{itemize} % % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \dim_const:Nn \c_@@_shift_Ldots_last_row_dim { 0.5 em } \dim_const:Nn \c_@@_shift_exterior_Vdots_dim { 0.6 em } \dim_const:Nn \c_@@_innersep_middle_dim { 0.17 em } } % \end{macrocode} % % % \bigskip % \section{The command \textbackslash tabularnote} % % \bigskip % Of course, it's possible to use |\tabularnote| in the main tabular. But there % is also the possibility to use that command in the caption of the tabular. And % the caption may be specified by two means: % % \begin{itemize} % \item The caption may of course be provided by the command |\caption| in a % floating environment. Of course, a command |\tabularnote| in that |\caption| % makes sens only if the |\caption| is \emph{before} the |{tabular}|. % \item It's also possible to use |\tabularnote| in the value of the key % |caption| of the |{NiceTabular}| when the key |caption-above| is in force. % However, in that case, one must remind that the caption is composed % \emph{after} the composition of the box which contains the main tabular % (that's mandatory since that caption must be wrapped with a line width equal % to the width ot the tabular). However, we want the labels of the successive % tabular notes in the logical order. That's why: % \begin{itemize} % \item The number of tabular notes present in the caption will be written on % the |aux| file and available in |\g_@@_notes_caption_int|.\footnote{More % precisely, it's the number of tabular notes which do not use the optional % argument of |\tabularnote|.} % \item During the composition of the main tabular, the tabular notes will be % numbered from |\g_@@_notes_caption_int|+1 and the notes will be stored in % |\g_@@_notes_seq|. Each component of |\g_@@_notes_seq| will be a kind of % couple of the form : \texttt{\{\textsl{label}\}\{\textsl{text of the % tabularnote}\}}. The first component is the optional argument (between square % brackets) of the command |\tabularnote| (if the optional argument is not used, % the value will be the special marker expressed by |\c_novalue_tl|). % \item During the composition of the caption (value of |\l_@@_caption_tl|), the % tabular notes will be numbered from $1$ to |\g_@@_notes_caption_int| and the % notes themselves will be stored in |\g_@@_notes_in_caption_seq|. The structure % of the components of that sequence will be the same as for |\g_@@_notes_seq|. % \item After the composition of the main tabular and after the composition of % the caption, the sequences |\g_@@_notes_in_caption_seq| and |\g_@@_notes_seq| % will be merged (in that order) and the notes will be composed. % \end{itemize} % \end{itemize} % % % \bigskip % The LaTeX counter |tabularnote| will be used to count the tabular notes during % the construction of the array (this counter won't be used during the % composition of the notes at the end of the array). You use a LaTeX counter % because we will use |\refstepcounter| in order to have the tabular notes % referenceable. % \begin{macrocode} \newcounter { tabularnote } % \end{macrocode} % % \begin{macrocode} \seq_new:N \g_@@_notes_seq \seq_new:N \g_@@_notes_in_caption_seq % \end{macrocode} % % \bigskip % Before the actual tabular notes, it's possible to put a text % specified by the key |tabularnote| of the environment. The token list % |\g_@@_tabularnote_tl| corresponds to the value of that key. % \begin{macrocode} \tl_new:N \g_@@_tabularnote_tl % \end{macrocode} % % \bigskip % We prepare the tools for the formatting of the references of the footnotes (in % the tabular itself). There may have several references of footnote at the same % point and we have to take into account that point. % \begin{macrocode} \seq_new:N \l_@@_notes_labels_seq \newcounter{nicematrix_draft} \cs_new_protected:Npn \@@_notes_format:n #1 { \setcounter { nicematrix_draft } { #1 } \@@_notes_style:n { nicematrix_draft } } % \end{macrocode} % % \bigskip % The following function can be redefined by using the key |notes/style|. % \begin{macrocode} \cs_new:Npn \@@_notes_style:n #1 { \textit { \alph { #1 } } } % \end{macrocode} % % \bigskip % The following fonction can be redefined by using the key % |notes/label-in-tabular|. % \begin{macrocode} \cs_new:Npn \@@_notes_label_in_tabular:n #1 { \textsuperscript { #1 } } % \end{macrocode} % % \bigskip % The following function can be redefined by using the key |notes/label-in-list|. % \begin{macrocode} \cs_new:Npn \@@_notes_label_in_list:n #1 { \textsuperscript { #1 } } % \end{macrocode} % % \bigskip % We define |\thetabularnote| because it will be used by LaTeX if the user want % to reference a tabular which has been marked by a |\label|. The TeX group is % for the case where the user has put an instruction such as |\color{red}| in % |\@@_notes_style:n|. % \begin{macrocode} \cs_set:Npn \thetabularnote { { \@@_notes_style:n { tabularnote } } } % \end{macrocode} % % \bigskip % The tabular notes will be available for the final user only when % \pkg{enumitem} is loaded. Indeed, the tabular notes will be composed at the end % of the array with a list customized by \pkg{enumitem} (a list |tabularnotes| % in the general case and a list |tabularnotes*| if the key |para| is in force). % However, we can test whether \pkg{enumitem} has been loaded only at the % beginning of the document (we want to allow the user to load \pkg{enumitem} % after \pkg{nicematrix}). % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { enumitem } { % \end{macrocode} % The type of list |tabularnotes| will be used to format the tabular notes at % the end of the array in the general case and |tabularnotes*| will be used if % the key |para| is in force. % \begin{macrocode} \newlist { tabularnotes } { enumerate } { 1 } \setlist [ tabularnotes ] { topsep = 0pt , noitemsep , leftmargin = * , align = left , labelsep = 0pt , label = \@@_notes_label_in_list:n { \@@_notes_style:n { tabularnotesi } } , } \newlist { tabularnotes* } { enumerate* } { 1 } \setlist [ tabularnotes* ] { afterlabel = \nobreak , itemjoin = \quad , label = \@@_notes_label_in_list:n { \@@_notes_style:n { tabularnotes*i } } } % \end{macrocode} % % \bigskip % One must remind that we have allowed a |\tabular| in the caption and % that caption may also be found in the list of tables (|\listoftables|). We % want the command |\tabularnote| be no-op during the composition of that list. % That's why we program |\tabularnote| to be no-op excepted in a floating % environment or in an environment of \pkg{nicematrix}. % \begin{macrocode} \NewDocumentCommand \tabularnote { o m } { \bool_lazy_or:nnT { \cs_if_exist_p:N \@captype } \l_@@_in_env_bool { \bool_lazy_and:nnTF { ! \l_@@_tabular_bool } \l_@@_in_env_bool { \@@_error:n { tabularnote~forbidden } } { \bool_if:NTF \l_@@_in_caption_bool \@@_tabularnote_caption:nn \@@_tabularnote:nn { #1 } { #2 } } } } } { \NewDocumentCommand \tabularnote { o m } { \@@_error_or_warning:n { enumitem~not~loaded } \@@_gredirect_none:n { enumitem~not~loaded } } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_test_first_novalue:nnn #1 #2 #3 { \tl_if_novalue:nT { #1 } { #3 } } % \end{macrocode} % % \bigskip % For the version in normal conditions, that is to say not in the |caption|. % |#1| is the optional argument of |\tabularnote| (maybe equal to the special % marker expressed by |\c_novalue_tl|) and |#2| is the mandatory argument of % |\tabularnote|. % \begin{macrocode} \cs_new_protected:Npn \@@_tabularnote:nn #1 #2 { % \end{macrocode} % You have to see whether the argument of |\tabularnote| has yet been used as % argument of another |\tabularnote| in the same tabular. In that case, there % will be only one note (for both commands |\tabularnote|) at the end of the % tabular. We search the argument of our command |\tabularnote| in % |\g_@@_notes_seq|. The position in the sequence will be stored in % |\l_tmpa_int| (0 if the text is not in the sequence yet). % \begin{macrocode} \int_zero:N \l_tmpa_int \bool_if:NT \l_@@_notes_detect_duplicates_bool { % \end{macrocode} % We recall that each component of |\g_@@_notes_seq| is a kind of couple of the form % \begin{center} % \texttt{\{\textsl{label}\}\{\textsl{text of the tabularnote}\}}. % \end{center} % If the user have used |\tabularnote| without the optional argument, the % \texttt{\textsl{label}} will be the special marker expressed by |\c_novalue_tl|. % % When we will go through the sequence |\g_@@_notes_seq|, we will count in % |\l_tmpb_int| the notes without explicit label in order to have the % ``current'' value of the counter |\c@tabularnote|. % \begin{macrocode} \int_zero:N \l_tmpb_int \seq_map_indexed_inline:Nn \g_@@_notes_seq { \@@_test_first_novalue:nnn ##2 { \int_incr:N \l_tmpb_int } \tl_if_eq:nnT { { #1 } { #2 } } { ##2 } { \tl_if_novalue:nTF { #1 } { \int_set_eq:NN \l_tmpa_int \l_tmpb_int } { \int_set:Nn \l_tmpa_int { ##1 } } \seq_map_break: } } \int_if_zero:nF \l_tmpa_int { \int_add:Nn \l_tmpa_int \g_@@_notes_caption_int } } \int_if_zero:nT \l_tmpa_int { \seq_gput_right:Nn \g_@@_notes_seq { { #1 } { #2 } } \tl_if_novalue:nT { #1 } { \int_gincr:N \c@tabularnote } } \seq_put_right:Nx \l_@@_notes_labels_seq { \tl_if_novalue:nTF { #1 } { \@@_notes_format:n { \int_eval:n { \int_if_zero:nTF \l_tmpa_int \c@tabularnote \l_tmpa_int } } } { #1 } } \peek_meaning:NF \tabularnote { % \end{macrocode} % If the following token is \emph{not} a |\tabularnote|, we have finished the % sequence of successive commands |\tabularnote| and we have to format the % labels of these tabular notes (in the array). We compose those labels in a box % |\l_tmpa_box| because we will do a special construction in order to have this % box in an overlapping position if we are at the end of a cell when % |\l_@@_hpos_cell_tl| is equal to |c| or |r|. % \begin{macrocode} \hbox_set:Nn \l_tmpa_box { % \end{macrocode} % We remind that it is the command |\@@_notes_label_in_tabular:n| that will % put the labels in a |\textsuperscript|. % \begin{macrocode} \@@_notes_label_in_tabular:n { \seq_use:Nnnn \l_@@_notes_labels_seq { , } { , } { , } } } % \end{macrocode} % We want the (last) tabular note referenceable (with the standard command |\label|). % \begin{macrocode} \int_gdecr:N \c@tabularnote \int_set_eq:NN \l_tmpa_int \c@tabularnote \refstepcounter { tabularnote } \int_compare:nNnT \l_tmpa_int = \c@tabularnote { \int_gincr:N \c@tabularnote } \seq_clear:N \l_@@_notes_labels_seq \bool_lazy_or:nnTF { \tl_if_eq_p:NN \l_@@_hpos_cell_tl \c_@@_c_tl } { \tl_if_eq_p:NN \l_@@_hpos_cell_tl \c_@@_r_tl } { \hbox_overlap_right:n { \box_use:N \l_tmpa_box } % \end{macrocode} % If the command |\tabularnote| is used exactly at the end of the cell, the % |\unskip| (inserted by \pkg{array}?) will delete the skip we insert now % and the label of the footnote will be composed in an overlapping position (by % design). % \begin{macrocode} \skip_horizontal:n { \box_wd:N \l_tmpa_box } } { \box_use:N \l_tmpa_box } } } % \end{macrocode} % % \bigskip % Now the version when the command is used in the key |caption|. The main % difficulty is that the argument of the command |\caption| is composed several % times. In order to know the number of commands |\tabularnote| in the caption, % we will consider that there should not be the same tabular note twice in the % caption (in the main tabular, it's possible). Once we have found a tabular % note which has yet been encountered, we consider that you are in a new % composition of the argument of |\caption|. % \begin{macrocode} \cs_new_protected:Npn \@@_tabularnote_caption:nn #1 #2 { \bool_if:NTF \g_@@_caption_finished_bool { \int_compare:nNnT \c@tabularnote = \g_@@_notes_caption_int { \int_gzero:N \c@tabularnote } % \end{macrocode} % Now, we try to detect duplicate notes in the caption. % Be careful! We must put |\tl_if_in:NnF| and not |\tl_if_in:NnT|! % \begin{macrocode} \seq_if_in:NnF \g_@@_notes_in_caption_seq { { #1 } { #2 } } { \@@_error:n { Identical~notes~in~caption } } } { % \end{macrocode} % In the following code, we are in the first composition of the caption or at % the first |\tabularnote| of the second composition. % \begin{macrocode} \seq_if_in:NnTF \g_@@_notes_in_caption_seq { { #1 } { #2 } } { % \end{macrocode} % Now, we know that are in the second composition of the caption since we are % reading a tabular note which has yet been read. Now, the value of % |\g_@@_notes_caption_int| won't change anymore: it's the number of uses % \emph{without optional argument} of the command |\tabularnote| in the caption. % \begin{macrocode} \bool_gset_true:N \g_@@_caption_finished_bool \int_gset_eq:NN \g_@@_notes_caption_int \c@tabularnote \int_gzero:N \c@tabularnote } { \seq_gput_right:Nn \g_@@_notes_in_caption_seq { { #1 } { #2 } } } } % \end{macrocode} % Now, we will compose the label of the footnote (in the caption). Even if we % are not in the first composition, we have to compose that label! % \begin{macrocode} \tl_if_novalue:nT { #1 } { \int_gincr:N \c@tabularnote } \seq_put_right:Nx \l_@@_notes_labels_seq { \tl_if_novalue:nTF { #1 } { \@@_notes_format:n { \int_use:N \c@tabularnote } } { #1 } } \peek_meaning:NF \tabularnote { \@@_notes_label_in_tabular:n { \seq_use:Nnnn \l_@@_notes_labels_seq { , } { , } { , } } \seq_clear:N \l_@@_notes_labels_seq } } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_count_novalue_first:nn #1 #2 { \tl_if_novalue:nT { #1 } { \int_gincr:N \g_@@_notes_caption_int } } % \end{macrocode} % % % \section{Command for creation of rectangle nodes} % % The following command should be used in a |{pgfpicture}|. It creates a % rectangle (empty but with a name). % % |#1| is the name of the node which will be created; % |#2| and |#3| are the coordinates of one of the corner of the rectangle; % |#4| and |#5| are the coordinates of the opposite corner. % \begin{macrocode} \cs_new_protected:Npn \@@_pgf_rect_node:nnnnn #1 #2 #3 #4 #5 { \begin { pgfscope } \pgfset { inner~sep = \c_zero_dim , minimum~size = \c_zero_dim } \pgftransformshift { \pgfpoint { 0.5 * ( #2 + #4 ) } { 0.5 * ( #3 + #5 ) } } \pgfnode { rectangle } { center } { \vbox_to_ht:nn { \dim_abs:n { #5 - #3 } } { \vfill \hbox_to_wd:nn { \dim_abs:n { #4 - #2 } } { } } } { #1 } { } \end { pgfscope } } % \end{macrocode} % % \medskip % The command |\@@_pgf_rect_node:nnn| is a variant of |\@@_pgf_rect_node:nnnnn|: % it takes two \textsc{pgf} points as arguments instead of the four dimensions % which are the coordinates. % \begin{macrocode} \cs_new_protected:Npn \@@_pgf_rect_node:nnn #1 #2 #3 { \begin { pgfscope } \pgfset { inner~sep = \c_zero_dim , minimum~size = \c_zero_dim } \pgftransformshift { \pgfpointscale { 0.5 } { \pgfpointadd { #2 } { #3 } } } \pgfpointdiff { #3 } { #2 } \pgfgetlastxy \l_tmpa_dim \l_tmpb_dim \pgfnode { rectangle } { center } { \vbox_to_ht:nn { \dim_abs:n \l_tmpb_dim } { \vfill \hbox_to_wd:nn { \dim_abs:n \l_tmpa_dim } { } } } { #1 } { } \end { pgfscope } } % \end{macrocode} % % % \bigskip % \section{The options} % % The following parameter corresponds to the keys |caption|, |short-caption| and % |label| of the environment |{NiceTabular}|. % \begin{macrocode} \tl_new:N \l_@@_caption_tl \tl_new:N \l_@@_short_caption_tl \tl_new:N \l_@@_label_tl % \end{macrocode} % % \bigskip % The following parameter corresponds to the key |caption-above| of % |\NiceMatrixOptions|. When this paremeter is |true|, the captions of the % environments |{NiceTabular}|, specified with the key |caption| are put above % the tabular (and below elsewhere). % \begin{macrocode} \bool_new:N \l_@@_caption_above_bool % \end{macrocode} % % \bigskip % By default, the commands |\cellcolor| and |\rowcolor| are available for the % user in the cells of the tabular (the user may use the commands provided by % |\colortbl|). However, if the key |color-inside| is used, these % commands are available. % \begin{macrocode} \bool_new:N \l_@@_color_inside_bool % \end{macrocode} % % \bigskip % By default, the behaviour of |\cline| is changed in the environments of % \pkg{nicematrix}: a |\cline| spreads the array by an amount equal to % |\arrayrulewidth|. It's possible to disable this feature with the key % |\l_@@_standard_line_bool|. % \begin{macrocode} \bool_new:N \l_@@_standard_cline_bool % \end{macrocode} % % \bigskip % The following dimensions correspond to the options |cell-space-top-limit| and co % (these parameters are inspired by the package \pkg{cellspace}). % \begin{macrocode} \dim_new:N \l_@@_cell_space_top_limit_dim \dim_new:N \l_@@_cell_space_bottom_limit_dim % \end{macrocode} % % \bigskip % The following parameter corresponds to the key |xdots/horizontal_labels|. % \begin{macrocode} \bool_new:N \l_@@_xdots_h_labels_bool % \end{macrocode} % \bigskip % The following dimension is the distance between two dots for the dotted lines % (when |line-style| is equal to |standard|, which is the initial value). The % initial value is 0.45~em but it will be changed if the option |small| is used. % \begin{macrocode} \dim_new:N \l_@@_xdots_inter_dim \hook_gput_code:nnn { begindocument } { . } { \dim_set:Nn \l_@@_xdots_inter_dim { 0.45 em } } % \end{macrocode} % The unit is |em| and that's why we fix the dimension after the preamble. % % \bigskip % The following dimension is the distance between a node (in fact an % anchor of that node) and a dotted line (for real dotted lines, the actual % distance may, of course, be a bit larger, depending of the exact position of % the dots). % \begin{macrocode} \dim_new:N \l_@@_xdots_shorten_start_dim \dim_new:N \l_@@_xdots_shorten_end_dim \hook_gput_code:nnn { begindocument } { . } { \dim_set:Nn \l_@@_xdots_shorten_start_dim { 0.3 em } \dim_set:Nn \l_@@_xdots_shorten_end_dim { 0.3 em } } % \end{macrocode} % The unit is |em| and that's why we fix the dimension after the preamble. % % \bigskip % The following dimension is the radius of the dots for the dotted lines (when % |line-style| is equal to |standard|, which is the initial value). The initial % value is 0.53~pt but it will be changed if the option |small| is used. % \begin{macrocode} \dim_new:N \l_@@_xdots_radius_dim \hook_gput_code:nnn { begindocument } { . } { \dim_set:Nn \l_@@_xdots_radius_dim { 0.53 pt } } % \end{macrocode} % The unit is |em| and that's why we fix the dimension after the preamble. % % % \bigskip % The token list |\l_@@_xdots_line_style_tl| corresponds to the option |tikz| of the % commands |\Cdots|, |\Ldots|, etc. and of the options |line-style| for the % environments and |\NiceMatrixOptions|. The constant |\c_@@_standard_tl| will % be used in some tests. % \begin{macrocode} \tl_new:N \l_@@_xdots_line_style_tl \tl_const:Nn \c_@@_standard_tl { standard } \tl_set_eq:NN \l_@@_xdots_line_style_tl \c_@@_standard_tl % \end{macrocode} % % \bigskip % The boolean |\l_@@_light_syntax_bool| corresponds to the option |light-syntax| % and the boolean |\l_@@_light_syntax_expanded_bool| correspond to the the % option |light-syntax-expanded|. % \begin{macrocode} \bool_new:N \l_@@_light_syntax_bool \bool_new:N \l_@@_light_syntax_expanded_bool % \end{macrocode} % % \bigskip % The string |\l_@@_baseline_tl| may contain one of the three values |t|, % |c| or |b| as in the option of the environment |{array}|. However, it may also % contain an integer (which represents the number of the row to which align the % array). % \begin{macrocode} \tl_new:N \l_@@_baseline_tl \tl_set:Nn \l_@@_baseline_tl { c } % \end{macrocode} % % \bigskip % The flag |\l_@@_exterior_arraycolsep_bool| corresponds to the option % |exterior-arraycolsep|. If this option is set, a space equal to |\arraycolsep| % will be put on both sides of an environment |{NiceArray}| (as it is done in % |{array}| of \pkg{array}). % \begin{macrocode} \bool_new:N \l_@@_exterior_arraycolsep_bool % \end{macrocode} % % \bigskip % The flag |\l_@@_parallelize_diags_bool| controls whether the diagonals are % parallelized. The initial value is~|true|. % \begin{macrocode} \bool_new:N \l_@@_parallelize_diags_bool \bool_set_true:N \l_@@_parallelize_diags_bool % \end{macrocode} % % \bigskip % The following parameter correspond to the key |corners|. The elements of that % |clist| must be within |NW|, |SW|, |NE| and |SE|. % \begin{macrocode} \clist_new:N \l_@@_corners_clist % \end{macrocode} % % \bigskip % \begin{macrocode} \dim_new:N \l_@@_notes_above_space_dim \hook_gput_code:nnn { begindocument } { . } { \dim_set:Nn \l_@@_notes_above_space_dim { 1 mm } } % \end{macrocode} % We use a hook only by security in case \cls{revtex4-1} is used (even though it % is obsolete). % % \bigskip % The flag |\l_@@_nullify_dots_bool| corresponds to the option |nullify-dots|. % When the flag is down, the instructions like |\vdots| are inserted within a % |\hphantom| (and so the constructed matrix has exactly the same size as a % matrix constructed with the classical |{matrix}| and |\ldots|, |\vdots|, % etc.). % \begin{macrocode} \bool_new:N \l_@@_nullify_dots_bool % \end{macrocode} % % \medskip % When the key |respect-arraystretch| is used, the following command will be nullified. % \begin{macrocode} \cs_new_protected:Npn \@@_reset_arraystretch: { \cs_set_nopar:Npn \arraystretch { 1 } } % \end{macrocode} % % % \bigskip % The following flag will be used when the current options specify that all the % columns of the array must have the same width equal to the largest width of a % cell of the array (except the cells of the potential exterior columns). % \begin{macrocode} \bool_new:N \l_@@_auto_columns_width_bool % \end{macrocode} % % \bigskip % The following boolean corresponds to the key |create-cell-nodes| of the % keyword |\CodeBefore|. % \begin{macrocode} \bool_new:N \g_@@_recreate_cell_nodes_bool % \end{macrocode} % % \bigskip % The string |\l_@@_name_str| will contain the optional name of the % environment: this name can be used to access to the Tikz nodes created in the % array from outside the environment. % \begin{macrocode} \str_new:N \l_@@_name_str % \end{macrocode} % % \bigskip % The boolean |\l_@@_medium_nodes_bool| will be used to indicate whether the % ``medium nodes'' are created in the array. Idem for the ``large nodes''. % \begin{macrocode} \bool_new:N \l_@@_medium_nodes_bool \bool_new:N \l_@@_large_nodes_bool % \end{macrocode} % % \bigskip % The boolean |\l_@@_except_borders_bool| will be raised when the key % |hvlines-except-borders| will be used (but that key has also other effects). % \begin{macrocode} \bool_new:N \l_@@_except_borders_bool % \end{macrocode} % % % \bigskip % The dimension |\l_@@_left_margin_dim| correspond to the option |left-margin|. % Idem for the right margin. These parameters are involved in the creation of % the ``medium nodes'' but also in the placement of the delimiters and the % drawing of the horizontal dotted lines (|\hdottedline|). % \begin{macrocode} \dim_new:N \l_@@_left_margin_dim \dim_new:N \l_@@_right_margin_dim % \end{macrocode} % % % \bigskip % The dimensions |\l_@@_extra_left_margin_dim| and % |\l_@@_extra_right_margin_dim| correspond to the options |extra-left-margin| % and |extra-right-margin|. % \begin{macrocode} \dim_new:N \l_@@_extra_left_margin_dim \dim_new:N \l_@@_extra_right_margin_dim % \end{macrocode} % % \medskip % The token list |\l_@@_end_of_row_tl| corresponds to the option |end-of-row|. % It specifies the symbol used to mark the ends of rows when the light syntax is % used. % \begin{macrocode} \tl_new:N \l_@@_end_of_row_tl \tl_set:Nn \l_@@_end_of_row_tl { ; } % \end{macrocode} % % \medskip % The following parameter is for the color the dotted lines drawn by |\Cdots|, % |\Ldots|, |\Vdots|, |\Ddots|, |\Iddots| and |\Hdotsfor| but \emph{not} the % dotted lines drawn by |\hdottedline| and ``|:|''. % \begin{macrocode} \tl_new:N \l_@@_xdots_color_tl % \end{macrocode} % % \bigskip % The following token list corresponds to the key |delimiters/color|. % \begin{macrocode} \tl_new:N \l_@@_delimiters_color_tl % \end{macrocode} % % % \bigskip % Sometimes, we want to have several arrays vertically juxtaposed in order to % have an alignment of the columns of these arrays. To acheive this goal, one % may wish to use the same width for all the columns (for example with the % option |columns-width| or the option |auto-columns-width| of the environment % |{NiceMatrixBlock}|). However, even if we use the same type of delimiters, the % width of the delimiters may be different from an array to another because the % width of the delimiter is fonction of its size. That's why we create an option % called |delimiters/max-width| which will give to the delimiters the width of % a delimiter (of the same type) of big size. The following boolean corresponds % to this option. % \begin{macrocode} \bool_new:N \l_@@_delimiters_max_width_bool % \end{macrocode} % % % \bigskip % \begin{macrocode} \keys_define:nn { NiceMatrix / xdots } { shorten-start .code:n = \hook_gput_code:nnn { begindocument } { . } { \dim_set:Nn \l_@@_xdots_shorten_start_dim { #1 } } , shorten-end .code:n = \hook_gput_code:nnn { begindocument } { . } { \dim_set:Nn \l_@@_xdots_shorten_end_dim { #1 } } , shorten-start .value_required:n = true , shorten-end .value_required:n = true , shorten .code:n = \hook_gput_code:nnn { begindocument } { . } { \dim_set:Nn \l_@@_xdots_shorten_start_dim { #1 } \dim_set:Nn \l_@@_xdots_shorten_end_dim { #1 } } , shorten .value_required:n = true , horizontal-labels .bool_set:N = \l_@@_xdots_h_labels_bool , horizontal-labels .default:n = true , line-style .code:n = { \bool_lazy_or:nnTF { \cs_if_exist_p:N \tikzpicture } { \str_if_eq_p:nn { #1 } { standard } } { \tl_set:Nn \l_@@_xdots_line_style_tl { #1 } } { \@@_error:n { bad~option~for~line-style } } } , line-style .value_required:n = true , color .tl_set:N = \l_@@_xdots_color_tl , color .value_required:n = true , radius .code:n = \hook_gput_code:nnn { begindocument } { . } { \dim_set:Nn \l_@@_xdots_radius_dim { #1 } } , radius .value_required:n = true , inter .code:n = \hook_gput_code:nnn { begindocument } { . } { \dim_set:Nn \l_@@_xdots_inter_dim { #1 } } , radius .value_required:n = true , % \end{macrocode} % The options |down|, |up| and |middle| are not documented for the final user % because he should use the syntax with |^|, |_| and |:|. We use % |\tl_put_right:Nn| and not |\tl_set:Nn| (or |.tl_set:N|) because we don't want % a direct use of |up=...| erased by a absent |^{...}|. % \begin{macrocode} down .code:n = \tl_put_right:Nn \l_@@_xdots_down_tl { #1 } , up .code:n = \tl_put_right:Nn \l_@@_xdots_up_tl { #1 } , middle .code:n = \tl_put_right:Nn \l_@@_xdots_middle_tl { #1 } , % \end{macrocode} % The key |draw-first|, which is meant to be used only with |\Ddots| and % |\Iddots|, will be catched when |\Ddots| or |\Iddots| is used (during the % construction of the array and not when we draw the dotted lines). % \begin{macrocode} draw-first .code:n = \prg_do_nothing: , unknown .code:n = \@@_error:n { Unknown~key~for~xdots } } % \end{macrocode} % % % \bigskip % \begin{macrocode} \keys_define:nn { NiceMatrix / rules } { color .tl_set:N = \l_@@_rules_color_tl , color .value_required:n = true , width .dim_set:N = \arrayrulewidth , width .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~rules } } % \end{macrocode} % % % \bigskip % First, we define a set of keys ``|NiceMatrix / Global|'' which will be used % (with the mechanism of |.inherit:n|) by other sets of keys. % % \begin{macrocode} \keys_define:nn { NiceMatrix / Global } { no-cell-nodes .code:n = \cs_set_protected:Npn \@@_node_for_cell: { \box_use_drop:N \l_@@_cell_box } , no-cell-nodes .value_forbidden:n = true , rounded-corners .dim_set:N = \l_@@_tab_rounded_corners_dim , rounded-corners .default:n = 4 pt , custom-line .code:n = \@@_custom_line:n { #1 } , rules .code:n = \keys_set:nn { NiceMatrix / rules } { #1 } , rules .value_required:n = true , standard-cline .bool_set:N = \l_@@_standard_cline_bool , standard-cline .default:n = true , cell-space-top-limit .dim_set:N = \l_@@_cell_space_top_limit_dim , cell-space-top-limit .value_required:n = true , cell-space-bottom-limit .dim_set:N = \l_@@_cell_space_bottom_limit_dim , cell-space-bottom-limit .value_required:n = true , cell-space-limits .meta:n = { cell-space-top-limit = #1 , cell-space-bottom-limit = #1 , } , cell-space-limits .value_required:n = true , xdots .code:n = \keys_set:nn { NiceMatrix / xdots } { #1 } , light-syntax .code:n = \bool_set_true:N \l_@@_light_syntax_bool \bool_set_false:N \l_@@_light_syntax_expanded_bool , light-syntax .value_forbidden:n = true , light-syntax-expanded .code:n = \bool_set_true:N \l_@@_light_syntax_bool \bool_set_true:N \l_@@_light_syntax_expanded_bool , light-syntax-expanded .value_forbidden:n = true , end-of-row .tl_set:N = \l_@@_end_of_row_tl , end-of-row .value_required:n = true , first-col .code:n = \int_zero:N \l_@@_first_col_int , first-row .code:n = \int_zero:N \l_@@_first_row_int , last-row .int_set:N = \l_@@_last_row_int , last-row .default:n = -1 , code-for-first-col .tl_set:N = \l_@@_code_for_first_col_tl , code-for-first-col .value_required:n = true , code-for-last-col .tl_set:N = \l_@@_code_for_last_col_tl , code-for-last-col .value_required:n = true , code-for-first-row .tl_set:N = \l_@@_code_for_first_row_tl , code-for-first-row .value_required:n = true , code-for-last-row .tl_set:N = \l_@@_code_for_last_row_tl , code-for-last-row .value_required:n = true , hlines .clist_set:N = \l_@@_hlines_clist , vlines .clist_set:N = \l_@@_vlines_clist , hlines .default:n = all , vlines .default:n = all , vlines-in-sub-matrix .code:n = { \tl_if_single_token:nTF { #1 } { \tl_if_in:NnTF \c_@@_forbidden_letters_tl { #1 } { \@@_error:nn { Forbidden~letter } { #1 } } % \end{macrocode} % We write directly a command for the automata which reads the preamble provided % by the final user. % \begin{macrocode} { \cs_set_eq:cN { @@ _ #1 } \@@_make_preamble_vlism:n } } { \@@_error:n { One~letter~allowed } } } , vlines-in-sub-matrix .value_required:n = true , hvlines .code:n = { \bool_set_true:N \l_@@_hvlines_bool \tl_set_eq:NN \l_@@_vlines_clist \c_@@_all_tl \tl_set_eq:NN \l_@@_hlines_clist \c_@@_all_tl } , hvlines-except-borders .code:n = { \tl_set_eq:NN \l_@@_vlines_clist \c_@@_all_tl \tl_set_eq:NN \l_@@_hlines_clist \c_@@_all_tl \bool_set_true:N \l_@@_hvlines_bool \bool_set_true:N \l_@@_except_borders_bool } , parallelize-diags .bool_set:N = \l_@@_parallelize_diags_bool , % \end{macrocode} % % \bigskip % With the option |renew-dots|, the command |\cdots|, |\ldots|, |\vdots|, % |\ddots|, etc. are redefined and behave like the commands |\Cdots|, |\Ldots|, % |\Vdots|, |\Ddots|, etc. % \begin{macrocode} renew-dots .bool_set:N = \l_@@_renew_dots_bool , renew-dots .value_forbidden:n = true , nullify-dots .bool_set:N = \l_@@_nullify_dots_bool , create-medium-nodes .bool_set:N = \l_@@_medium_nodes_bool , create-large-nodes .bool_set:N = \l_@@_large_nodes_bool , create-extra-nodes .meta:n = { create-medium-nodes , create-large-nodes } , left-margin .dim_set:N = \l_@@_left_margin_dim , left-margin .default:n = \arraycolsep , right-margin .dim_set:N = \l_@@_right_margin_dim , right-margin .default:n = \arraycolsep , margin .meta:n = { left-margin = #1 , right-margin = #1 } , margin .default:n = \arraycolsep , extra-left-margin .dim_set:N = \l_@@_extra_left_margin_dim , extra-right-margin .dim_set:N = \l_@@_extra_right_margin_dim , extra-margin .meta:n = { extra-left-margin = #1 , extra-right-margin = #1 } , extra-margin .value_required:n = true , respect-arraystretch .code:n = \cs_set_eq:NN \@@_reset_arraystretch: \prg_do_nothing: , respect-arraystretch .value_forbidden:n = true , pgf-node-code .tl_set:N = \l_@@_pgf_node_code_tl , pgf-node-code .value_required:n = true } % \end{macrocode} % % \bigskip % We define a set of keys used by the environments of \pkg{nicematrix} (but not % by the command |\NiceMatrixOptions|). % \begin{macrocode} \keys_define:nn { NiceMatrix / Env } { corners .clist_set:N = \l_@@_corners_clist , corners .default:n = { NW , SW , NE , SE } , code-before .code:n = { \tl_if_empty:nF { #1 } { \tl_gput_left:Nn \g_@@_pre_code_before_tl { #1 } \bool_set_true:N \l_@@_code_before_bool } } , code-before .value_required:n = true , % \end{macrocode} % \bigskip % The options |c|, |t| and |b| of the environment |{NiceArray}| have the same % meaning as the option of the classical environment |{array}|. % \begin{macrocode} c .code:n = \tl_set:Nn \l_@@_baseline_tl c , t .code:n = \tl_set:Nn \l_@@_baseline_tl t , b .code:n = \tl_set:Nn \l_@@_baseline_tl b , baseline .tl_set:N = \l_@@_baseline_tl , baseline .value_required:n = true , columns-width .code:n = \tl_if_eq:nnTF { #1 } { auto } { \bool_set_true:N \l_@@_auto_columns_width_bool } { \dim_set:Nn \l_@@_columns_width_dim { #1 } } , columns-width .value_required:n = true , name .code:n = % \end{macrocode} % We test whether we are in the measuring phase of an environment of % \pkg{amsmath} (always loaded by \pkg{nicematrix}) because we want to avoid a % fallacious message of duplicate name in this case. % \begin{macrocode} \legacy_if:nF { measuring@ } { \str_set:Nx \l_tmpa_str { #1 } \seq_if_in:NVTF \g_@@_names_seq \l_tmpa_str { \@@_error:nn { Duplicate~name } { #1 } } { \seq_gput_left:NV \g_@@_names_seq \l_tmpa_str } \str_set_eq:NN \l_@@_name_str \l_tmpa_str } , name .value_required:n = true , code-after .tl_gset:N = \g_nicematrix_code_after_tl , code-after .value_required:n = true , color-inside .code:n = \bool_set_true:N \l_@@_color_inside_bool \bool_set_true:N \l_@@_code_before_bool , color-inside .value_forbidden:n = true , colortbl-like .meta:n = color-inside } % \end{macrocode} % % \begin{macrocode} \keys_define:nn { NiceMatrix / notes } { para .bool_set:N = \l_@@_notes_para_bool , para .default:n = true , code-before .tl_set:N = \l_@@_notes_code_before_tl , code-before .value_required:n = true , code-after .tl_set:N = \l_@@_notes_code_after_tl , code-after .value_required:n = true , bottomrule .bool_set:N = \l_@@_notes_bottomrule_bool , bottomrule .default:n = true , style .cs_set:Np = \@@_notes_style:n #1 , style .value_required:n = true , label-in-tabular .cs_set:Np = \@@_notes_label_in_tabular:n #1 , label-in-tabular .value_required:n = true , label-in-list .cs_set:Np = \@@_notes_label_in_list:n #1 , label-in-list .value_required:n = true , enumitem-keys .code:n = { \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { enumitem } { \setlist* [ tabularnotes ] { #1 } } { } } } , enumitem-keys .value_required:n = true , enumitem-keys-para .code:n = { \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { enumitem } { \setlist* [ tabularnotes* ] { #1 } } { } } } , enumitem-keys-para .value_required:n = true , detect-duplicates .bool_set:N = \l_@@_notes_detect_duplicates_bool , detect-duplicates .default:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~notes } } % \end{macrocode} % % \begin{macrocode} \keys_define:nn { NiceMatrix / delimiters } { max-width .bool_set:N = \l_@@_delimiters_max_width_bool , max-width .default:n = true , color .tl_set:N = \l_@@_delimiters_color_tl , color .value_required:n = true , } % \end{macrocode} % % \bigskip % We begin the construction of the major sets of keys (used by the different % user commands and environments). % \begin{macrocode} \keys_define:nn { NiceMatrix } { NiceMatrixOptions .inherit:n = { NiceMatrix / Global } , NiceMatrixOptions / xdots .inherit:n = NiceMatrix / xdots , NiceMatrixOptions / rules .inherit:n = NiceMatrix / rules , NiceMatrixOptions / notes .inherit:n = NiceMatrix / notes , NiceMatrixOptions / sub-matrix .inherit:n = NiceMatrix / sub-matrix , SubMatrix / rules .inherit:n = NiceMatrix / rules , CodeAfter / xdots .inherit:n = NiceMatrix / xdots , CodeBefore / sub-matrix .inherit:n = NiceMatrix / sub-matrix , CodeAfter / sub-matrix .inherit:n = NiceMatrix / sub-matrix , NiceMatrix .inherit:n = { NiceMatrix / Global , NiceMatrix / Env , } , NiceMatrix / xdots .inherit:n = NiceMatrix / xdots , NiceMatrix / rules .inherit:n = NiceMatrix / rules , NiceTabular .inherit:n = { NiceMatrix / Global , NiceMatrix / Env } , NiceTabular / xdots .inherit:n = NiceMatrix / xdots , NiceTabular / rules .inherit:n = NiceMatrix / rules , NiceTabular / notes .inherit:n = NiceMatrix / notes , NiceArray .inherit:n = { NiceMatrix / Global , NiceMatrix / Env , } , NiceArray / xdots .inherit:n = NiceMatrix / xdots , NiceArray / rules .inherit:n = NiceMatrix / rules , pNiceArray .inherit:n = { NiceMatrix / Global , NiceMatrix / Env , } , pNiceArray / xdots .inherit:n = NiceMatrix / xdots , pNiceArray / rules .inherit:n = NiceMatrix / rules , } % \end{macrocode} % % % \bigskip % We finalise the definition of the set of keys % ``|NiceMatrix / NiceMatrixOptions|'' with the options specific to % |\NiceMatrixOptions|. % \begin{macrocode} \keys_define:nn { NiceMatrix / NiceMatrixOptions } { delimiters / color .tl_set:N = \l_@@_delimiters_color_tl , delimiters / color .value_required:n = true , delimiters / max-width .bool_set:N = \l_@@_delimiters_max_width_bool , delimiters / max-width .default:n = true , delimiters .code:n = \keys_set:nn { NiceMatrix / delimiters } { #1 } , delimiters .value_required:n = true , width .dim_set:N = \l_@@_width_dim , width .value_required:n = true , last-col .code:n = \tl_if_empty:nF { #1 } { \@@_error:n { last-col~non~empty~for~NiceMatrixOptions } } \int_zero:N \l_@@_last_col_int , small .bool_set:N = \l_@@_small_bool , small .value_forbidden:n = true , % \end{macrocode} % % With the option |renew-matrix|, the environment |{matrix}| of \pkg{amsmath} % and its variants are redefined to behave like the environment |{NiceMatrix}| % and its variants. % \begin{macrocode} renew-matrix .code:n = \@@_renew_matrix: , renew-matrix .value_forbidden:n = true , % \end{macrocode} % % \bigskip % The option |exterior-arraycolsep| will have effect only in |{NiceArray}| for % those who want to have for |{NiceArray}| the same behaviour as |{array}|. % \begin{macrocode} exterior-arraycolsep .bool_set:N = \l_@@_exterior_arraycolsep_bool , % \end{macrocode} % % \bigskip % If the option |columns-width| is used, all the columns will have the same % width. % % In |\NiceMatrixOptions|, the special value |auto| is not available. % \begin{macrocode} columns-width .code:n = \tl_if_eq:nnTF { #1 } { auto } { \@@_error:n { Option~auto~for~columns-width } } { \dim_set:Nn \l_@@_columns_width_dim { #1 } } , % \end{macrocode} % % \bigskip % Usually, an error is raised when the user tries to give the same name to two % distincts environments of \pkg{nicematrix} (these names are global and not % local to the current TeX scope). However, the option |allow-duplicate-names| % disables this feature. % \begin{macrocode} allow-duplicate-names .code:n = \@@_msg_redirect_name:nn { Duplicate~name } { none } , allow-duplicate-names .value_forbidden:n = true , notes .code:n = \keys_set:nn { NiceMatrix / notes } { #1 } , notes .value_required:n = true , sub-matrix .code:n = \keys_set:nn { NiceMatrix / sub-matrix } { #1 } , sub-matrix .value_required:n = true , matrix / columns-type .tl_set:N = \l_@@_columns_type_tl , matrix / columns-type .value_required:n = true , caption-above .bool_set:N = \l_@@_caption_above_bool , caption-above .default:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~NiceMatrixOptions } } % \end{macrocode} % % % % \bigskip % |\NiceMatrixOptions| is the command of the \pkg{nicematrix} package to fix % options at the document level. The scope of these specifications is the % current TeX group. % \begin{macrocode} \NewDocumentCommand \NiceMatrixOptions { m } { \keys_set:nn { NiceMatrix / NiceMatrixOptions } { #1 } } % \end{macrocode} % % % \bigskip % We finalise the definition of the set of keys ``|NiceMatrix / NiceMatrix|''. % That set of keys will be used by |{NiceMatrix}|, |{pNiceMatrix}|, % |{bNiceMatrix}|, etc. % % \begin{macrocode} \keys_define:nn { NiceMatrix / NiceMatrix } { last-col .code:n = \tl_if_empty:nTF { #1 } { \bool_set_true:N \l_@@_last_col_without_value_bool \int_set:Nn \l_@@_last_col_int { -1 } } { \int_set:Nn \l_@@_last_col_int { #1 } } , columns-type .tl_set:N = \l_@@_columns_type_tl , columns-type .value_required:n = true , l .meta:n = { columns-type = l } , r .meta:n = { columns-type = r } , delimiters / color .tl_set:N = \l_@@_delimiters_color_tl , delimiters / color .value_required:n = true , delimiters / max-width .bool_set:N = \l_@@_delimiters_max_width_bool , delimiters / max-width .default:n = true , delimiters .code:n = \keys_set:nn { NiceMatrix / delimiters } { #1 } , delimiters .value_required:n = true , small .bool_set:N = \l_@@_small_bool , small .value_forbidden:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~NiceMatrix } } % \end{macrocode} % % % % \bigskip % We finalise the definition of the set of keys ``|NiceMatrix / NiceArray|'' % with the options specific to |{NiceArray}|. % % \begin{macrocode} \keys_define:nn { NiceMatrix / NiceArray } { % \end{macrocode} % % In the environments |{NiceArray}| and its variants, the option |last-col| must % be used without value because the number of columns of the array is read % from the preamble of the array. % \begin{macrocode} small .bool_set:N = \l_@@_small_bool , small .value_forbidden:n = true , last-col .code:n = \tl_if_empty:nF { #1 } { \@@_error:n { last-col~non~empty~for~NiceArray } } \int_zero:N \l_@@_last_col_int , r .code:n = \@@_error:n { r~or~l~with~preamble } , l .code:n = \@@_error:n { r~or~l~with~preamble } , unknown .code:n = \@@_error:n { Unknown~key~for~NiceArray } } % \end{macrocode} % % % % \begin{macrocode} \keys_define:nn { NiceMatrix / pNiceArray } { first-col .code:n = \int_zero:N \l_@@_first_col_int , last-col .code:n = \tl_if_empty:nF {#1} { \@@_error:n { last-col~non~empty~for~NiceArray } } \int_zero:N \l_@@_last_col_int , first-row .code:n = \int_zero:N \l_@@_first_row_int , delimiters / color .tl_set:N = \l_@@_delimiters_color_tl , delimiters / color .value_required:n = true , delimiters / max-width .bool_set:N = \l_@@_delimiters_max_width_bool , delimiters / max-width .default:n = true , delimiters .code:n = \keys_set:nn { NiceMatrix / delimiters } { #1 } , delimiters .value_required:n = true , small .bool_set:N = \l_@@_small_bool , small .value_forbidden:n = true , r .code:n = \@@_error:n { r~or~l~with~preamble } , l .code:n = \@@_error:n { r~or~l~with~preamble } , unknown .code:n = \@@_error:n { Unknown~key~for~NiceMatrix } } % \end{macrocode} % % \bigskip % We finalise the definition of the set of keys ``|NiceMatrix / NiceTabular|'' % with the options specific to |{NiceTabular}|. % % \begin{macrocode} \keys_define:nn { NiceMatrix / NiceTabular } { % \end{macrocode} % The dimension |width| will be used if at least a column of type |X| is used. % If there is no column of type |X|, an error will be raised. % \begin{macrocode} width .code:n = \dim_set:Nn \l_@@_width_dim { #1 } \bool_set_true:N \l_@@_width_used_bool , width .value_required:n = true , notes .code:n = \keys_set:nn { NiceMatrix / notes } { #1 } , tabularnote .tl_gset:N = \g_@@_tabularnote_tl , tabularnote .value_required:n = true , caption .tl_set:N = \l_@@_caption_tl , caption .value_required:n = true , short-caption .tl_set:N = \l_@@_short_caption_tl , short-caption .value_required:n = true , label .tl_set:N = \l_@@_label_tl , label .value_required:n = true , last-col .code:n = \tl_if_empty:nF {#1} { \@@_error:n { last-col~non~empty~for~NiceArray } } \int_zero:N \l_@@_last_col_int , r .code:n = \@@_error:n { r~or~l~with~preamble } , l .code:n = \@@_error:n { r~or~l~with~preamble } , unknown .code:n = \@@_error:n { Unknown~key~for~NiceTabular } } % \end{macrocode} % % % \bigskip % The |\CodeAfter| (inserted with the key |code-after| or after the keyword % |\CodeAfter|) may always begin with a list of pairs \textsl{key=value} between % square brackets. Here is the corresponding set of keys. % % We \emph{must} put the following instructions \emph{after} the : % % \begin{verbatim} % CodeAfter / sub-matrix .inherit:n = NiceMatrix / sub-matrix % \end{verbatim} % % \begin{macrocode} \keys_define:nn { NiceMatrix / CodeAfter } { delimiters / color .tl_set:N = \l_@@_delimiters_color_tl , delimiters / color .value_required:n = true , rules .code:n = \keys_set:nn { NiceMatrix / rules } { #1 } , rules .value_required:n = true , xdots .code:n = \keys_set:nn { NiceMatrix / xdots } { #1 } , sub-matrix .code:n = \keys_set:nn { NiceMatrix / sub-matrix } { #1 } , sub-matrix .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~CodeAfter } } % \end{macrocode} % % \bigskip % \section{Important code used by \{NiceArrayWithDelims\} } % % The pseudo-environment |\@@_cell_begin:w|--|\@@_cell_end:| will be used to format the % cells of the array. In the code, the affectations are global because this % pseudo-environment will be used in the cells of a |\halign| (via an % environment |{array}|). % % \begin{macrocode} \cs_new_protected:Npn \@@_cell_begin:w { % \end{macrocode} % |\g_@@_cell_after_hook_tl| will be set during the composition of the box % |\l_@@_cell_box| and will be used \emph{after} the composition in order to % modify that box. % \begin{macrocode} \tl_gclear:N \g_@@_cell_after_hook_tl % \end{macrocode} % At the beginning of the cell, we link |\CodeAfter| to a command which do % begin with |\\| (whereas the standard version of |\CodeAfter| does % not). % \begin{macrocode} \cs_set_eq:NN \CodeAfter \@@_CodeAfter_i: % \end{macrocode} % We increment the LaTeX counter |jCol|, which is the counter of the columns. % \begin{macrocode} \int_gincr:N \c@jCol % \end{macrocode} % Now, we increment the counter of the rows. We don't do this incrementation in % the |\everycr| because some packages, like \pkg{arydshln}, create special rows % in the |\halign| that we don't want to take into account. % \begin{macrocode} \int_compare:nNnT \c@jCol = \c_one_int { \int_compare:nNnT \l_@@_first_col_int = \c_one_int \@@_begin_of_row: } % \end{macrocode} % The content of the cell is composed in the box |\l_@@_cell_box|. The % |\hbox_set_end:| corresponding to this |\hbox_set:Nw| is in the % |\@@_cell_end:|. % \begin{macrocode} \hbox_set:Nw \l_@@_cell_box % \end{macrocode} % The following command is nullified in the tabulars. % \begin{macrocode} \@@_tuning_not_tabular_begin: % \end{macrocode} % % \begin{macrocode} \@@_tuning_first_row: \@@_tuning_last_row: \g_@@_row_style_tl } % \end{macrocode} % % The following command will be nullified unless there is a first row. % \begin{macrocode} \cs_new_protected:Npn \@@_tuning_first_row: { \int_if_zero:nT \c@iRow { \int_compare:nNnT \c@jCol > \c_zero_int { \l_@@_code_for_first_row_tl \xglobal \colorlet { nicematrix-first-row } { . } } } } % \end{macrocode} % % The following command will be nullified unless there is a last row and we % know its value (\emph{ie}: |\l_@@_lat_row_int > 0|). % \begin{macrocode} \cs_new_protected:Npn \@@_tuning_last_row: { \int_compare:nNnT \c@iRow = \l_@@_last_row_int { \l_@@_code_for_last_row_tl \xglobal \colorlet { nicematrix-last-row } { . } } } % \end{macrocode} % % A different value will be provided to the following command when the key % |small| is in force. % \begin{macrocode} \cs_set_eq:NN \@@_tuning_key_small: \prg_do_nothing: % \end{macrocode} % % The following commands are nullified in the tabulars. % \begin{macrocode} \cs_set_nopar:Npn \@@_tuning_not_tabular_begin: { \c_math_toggle_token % \end{macrocode} % A special value is provided by the following controls sequence when the key % |small| is in force. % \begin{macrocode} \@@_tuning_key_small: } \cs_set_eq:NN \@@_tuning_not_tabular_end: \c_math_toggle_token % \end{macrocode} % % \interitem % The following macro |\@@_begin_of_row| is usually used in the cell % number~$1$ of the row. However, when the key |first-col| is used, % |\@@_begin_of_row| is executed in the cell number~$0$ of the row. % \begin{macrocode} \cs_new_protected:Npn \@@_begin_of_row: { \int_gincr:N \c@iRow \dim_gset_eq:NN \g_@@_dp_ante_last_row_dim \g_@@_dp_last_row_dim \dim_gset:Nn \g_@@_dp_last_row_dim { \box_dp:N \@arstrutbox } \dim_gset:Nn \g_@@_ht_last_row_dim { \box_ht:N \@arstrutbox } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - row - \int_use:N \c@iRow - base } { \pgfpoint \c_zero_dim { 0.5 \arrayrulewidth } } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - row - \int_use:N \c@iRow - base } { \@@_env: - row - \int_use:N \c@iRow - base } } \endpgfpicture } % \end{macrocode} % Remark: If the key |recreate-cell-nodes| of the |\CodeBefore| is used, then we % will add some lines to that command. % % % \interitem % The following code is used in each cell of the array. It actualises quantities % that, at the end of the array, will give informations about the vertical % dimension of the two first rows and the two last rows. If the user uses the % |last-row|, some lines of code will be dynamically added to this command. % \begin{macrocode} \cs_new_protected:Npn \@@_update_for_first_and_last_row: { \int_if_zero:nTF \c@iRow { \dim_gset:Nn \g_@@_dp_row_zero_dim { \dim_max:nn \g_@@_dp_row_zero_dim { \box_dp:N \l_@@_cell_box } } \dim_gset:Nn \g_@@_ht_row_zero_dim { \dim_max:nn \g_@@_ht_row_zero_dim { \box_ht:N \l_@@_cell_box } } } { \int_compare:nNnT \c@iRow = \c_one_int { \dim_gset:Nn \g_@@_ht_row_one_dim { \dim_max:nn \g_@@_ht_row_one_dim { \box_ht:N \l_@@_cell_box } } } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_rotate_cell_box: { \box_rotate:Nn \l_@@_cell_box { 90 } \bool_if:NTF \g_@@_rotate_c_bool { \hbox_set:Nn \l_@@_cell_box { \c_math_toggle_token \vcenter { \box_use:N \l_@@_cell_box } \c_math_toggle_token } } { \int_compare:nNnT \c@iRow = \l_@@_last_row_int { \vbox_set_top:Nn \l_@@_cell_box { \vbox_to_zero:n { } \skip_vertical:n { - \box_ht:N \@arstrutbox + 0.8 ex } \box_use:N \l_@@_cell_box } } } \bool_gset_false:N \g_@@_rotate_bool \bool_gset_false:N \g_@@_rotate_c_bool } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_adjust_size_box: { \dim_compare:nNnT \g_@@_blocks_wd_dim > \c_zero_dim { \box_set_wd:Nn \l_@@_cell_box { \dim_max:nn { \box_wd:N \l_@@_cell_box } \g_@@_blocks_wd_dim } \dim_gzero:N \g_@@_blocks_wd_dim } \dim_compare:nNnT \g_@@_blocks_dp_dim > \c_zero_dim { \box_set_dp:Nn \l_@@_cell_box { \dim_max:nn { \box_dp:N \l_@@_cell_box } \g_@@_blocks_dp_dim } \dim_gzero:N \g_@@_blocks_dp_dim } \dim_compare:nNnT \g_@@_blocks_ht_dim > \c_zero_dim { \box_set_ht:Nn \l_@@_cell_box { \dim_max:nn { \box_ht:N \l_@@_cell_box } \g_@@_blocks_ht_dim } \dim_gzero:N \g_@@_blocks_ht_dim } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_cell_end: { % \end{macrocode} % The following command is nullified in the tabulars. % \begin{macrocode} \@@_tuning_not_tabular_end: \hbox_set_end: \@@_cell_end_i: } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_cell_end_i: { % \end{macrocode} % The token list |\g_@@_cell_after_hook_tl| is (potentially) set during the % composition of the box |\l_@@_cell_box| and is used now \emph{after} the % composition in order to modify that box. % \begin{macrocode} \g_@@_cell_after_hook_tl \bool_if:NT \g_@@_rotate_bool \@@_rotate_cell_box: \@@_adjust_size_box: % \end{macrocode} % % \begin{macrocode} \box_set_ht:Nn \l_@@_cell_box { \box_ht:N \l_@@_cell_box + \l_@@_cell_space_top_limit_dim } \box_set_dp:Nn \l_@@_cell_box { \box_dp:N \l_@@_cell_box + \l_@@_cell_space_bottom_limit_dim } % \end{macrocode} % % We want to compute in |\g_@@_max_cell_width_dim| the width of the widest cell % of the array (except the cells of the ``first column'' and the ``last % column''). % \begin{macrocode} \@@_update_max_cell_width: % \end{macrocode} % % The following computations are for the ``first row'' and the ``last row''. % \begin{macrocode} \@@_update_for_first_and_last_row: % \end{macrocode} % % \medskip % If the cell is empty, or may be considered as if, we must not create the % \textsc{pgf} node, for two reasons: % \begin{itemize} % \item it's a waste of time since such a node would be rather pointless; % \item we test the existence of these nodes in order to determine whether a % cell is empty when we search the extremities of a dotted line. % \end{itemize} % However, it's very difficult to determine whether a cell is empty. Up to now % we use the following technic: % \begin{itemize} % \item for the columns of type |p|, |m|, |b|, |V| (of \pkg{varwidth}) or |X|, % we test whether the cell is syntactically empty with |\@@_test_if_empty:| and % |\@@_test_if_empty_for_S:| % \item if the width of the box |\l_@@_cell_box| (created with the content of % the cell) is equal to zero, we consider the cell as empty (however, % this is not perfect since the user may have used a |\rlap|, |\llap|, |\clap| % or a |\mathclap| of \pkg{mathtools}). % \item the cells with a command |\Ldots| or |\Cdots|, |\Vdots|, etc., % should also be considered as empty; if |nullify-dots| is in force, there would % be nothing to do (in this case the previous commands only write an instruction % in a kind of |\CodeAfter|); however, if |nullify-dots| is not in force, a % phantom of |\ldots|, |\cdots|, |\vdots| is inserted and its width is not equal % to zero; that's why these commands raise a boolean |\g_@@_empty_cell_bool| and % we begin by testing this boolean. % \end{itemize} % \begin{macrocode} \bool_if:NTF \g_@@_empty_cell_bool { \box_use_drop:N \l_@@_cell_box } { \bool_if:NTF \g_@@_not_empty_cell_bool \@@_node_for_cell: { \dim_compare:nNnTF { \box_wd:N \l_@@_cell_box } > \c_zero_dim \@@_node_for_cell: { \box_use_drop:N \l_@@_cell_box } } } \int_gset:Nn \g_@@_col_total_int { \int_max:nn \g_@@_col_total_int \c@jCol } \bool_gset_false:N \g_@@_empty_cell_bool \bool_gset_false:N \g_@@_not_empty_cell_bool } % \end{macrocode} % % \bigskip % The following command will be nullified in our redefinition of |\multicolumn|. % \begin{macrocode} \cs_new_protected:Npn \@@_update_max_cell_width: { \dim_gset:Nn \g_@@_max_cell_width_dim { \dim_max:nn \g_@@_max_cell_width_dim { \box_wd:N \l_@@_cell_box } } } % \end{macrocode} % % \bigskip % The following variant of |\@@_cell_end:| is only for the columns of type % |w{s}{...}| or |W{s}{...}| (which use the horizontal alignement key |s| of % |\makebox|). % \begin{macrocode} \cs_new_protected:Npn \@@_cell_end_for_w_s: { \@@_math_toggle: \hbox_set_end: \bool_if:NF \g_@@_rotate_bool { \hbox_set:Nn \l_@@_cell_box { \makebox [ \l_@@_col_width_dim ] [ s ] { \hbox_unpack_drop:N \l_@@_cell_box } } } \@@_cell_end_i: } % \end{macrocode} % % \bigskip % \begin{macrocode} \pgfset { nicematrix / cell-node /.style = { inner~sep = \c_zero_dim , minimum~width = \c_zero_dim } } % \end{macrocode} % % \bigskip % The following command creates the \textsc{pgf} name of the node with, of % course, |\l_@@_cell_box| as the content. % \begin{macrocode} \cs_new_protected:Npn \@@_node_for_cell: { \pgfpicture \pgfsetbaseline \c_zero_dim \pgfrememberpicturepositiononpagetrue \pgfset { nicematrix / cell-node } \pgfnode { rectangle } { base } { % \end{macrocode} % The following instruction |\set@color| has been added on 2022/10/06. It's % necessary only with XeLaTeX and not with the other engines (we don't know why). % \begin{macrocode} \set@color \box_use_drop:N \l_@@_cell_box } { \@@_env: - \int_use:N \c@iRow - \int_use:N \c@jCol } { \l_@@_pgf_node_code_tl } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - \int_use:N \c@iRow - \int_use:N \c@jCol } { \@@_env: - \int_use:N \c@iRow - \int_use:N \c@jCol } } \endpgfpicture } % \end{macrocode} % % \medskip % As its name says, the following command is a patch for the command % |\@@_node_for_cell:|. This patch will be appended on the left of % |\@@_node_for_the_cell:| when the construction of the cell nodes (of the form % |(i-j)|) in the |\CodeBefore| is required. % \begin{macrocode} \cs_new_protected:Npn \@@_patch_node_for_cell:n #1 { \cs_new_protected:Npn \@@_patch_node_for_cell: { \hbox_set:Nn \l_@@_cell_box { \box_move_up:nn { \box_ht:N \l_@@_cell_box} \hbox_overlap_left:n { \pgfsys@markposition { \@@_env: - \int_use:N \c@iRow - \int_use:N \c@jCol - NW } % \end{macrocode} % I don't know why the following adjustement is needed when the compilation is % done with XeLaTeX or with the classical way |latex|, |divps|, |ps2pdf| (or % Adobe Distiller). However, it seems to work. % \begin{macrocode} #1 } \box_use:N \l_@@_cell_box \box_move_down:nn { \box_dp:N \l_@@_cell_box } \hbox_overlap_left:n { \pgfsys@markposition { \@@_env: - \int_use:N \c@iRow - \int_use:N \c@jCol - SE } #1 } } } } % \end{macrocode} % % \bigskip % We have no explanation for the different behaviour between the TeX engines... % \begin{macrocode} \bool_lazy_or:nnTF \sys_if_engine_xetex_p: \sys_if_output_dvi_p: { \@@_patch_node_for_cell:n { \skip_horizontal:n { 0.5 \box_wd:N \l_@@_cell_box } } } { \@@_patch_node_for_cell:n { } } % \end{macrocode} % % % \interitem % The second argument of the following command |\@@_instruction_of_type:nnn| % defined below is the type of the instruction (|Cdots|, |Vdots|, |Ddots|, % etc.). The third argument is the list of options. This command writes in the % corresponding |\g_@@_|\textsl{type}|_lines_tl| the instruction which will % actually draw the line after the construction of the matrix. % % \medskip % For example, for the following matrix, % % \smallskip % \begin{BVerbatim}[baseline=c,boxwidth=11cm] % \begin{pNiceMatrix} % 1 & 2 & 3 & 4 \\ % 5 & \Cdots & & 6 \\ % 7 & \Cdots[color=red] % \end{pNiceMatrix} % \end{BVerbatim} % $\begin{pNiceMatrix} % 1 & 2 & 3 & 4 \\ % 5 & \Cdots & & 6 \\ % 7 & \Cdots[color=red] % \end{pNiceMatrix}$ % % \smallskip % the content of |\g_@@_Cdots_lines_tl| will be: % % \smallskip % \begin{scope} % \color{gray} % |\@@_draw_Cdots:nnn {2}{2}{}| % % |\@@_draw_Cdots:nnn {3}{2}{color=red}| % \end{scope} % % % \bigskip % The first argument is a boolean which indicates whether you must put the % instruction on the left or on the right on the list of instructions (with % consequences for the parallelisation of the diagonal lines). % \begin{macrocode} \cs_new_protected:Npn \@@_instruction_of_type:nnn #1 #2 #3 { \bool_if:nTF { #1 } \tl_gput_left:cx \tl_gput_right:cx { g_@@_ #2 _ lines _ tl } { \use:c { @@ _ draw _ #2 : nnn } { \int_use:N \c@iRow } { \int_use:N \c@jCol } { \exp_not:n { #3 } } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_array: { % \begin{macrocode} \dim_set:Nn \col@sep { \bool_if:NTF \l_@@_tabular_bool \tabcolsep \arraycolsep } \dim_compare:nNnTF \l_@@_tabular_width_dim = \c_zero_dim { \cs_set_nopar:Npn \@halignto { } } { \cs_set_nopar:Npx \@halignto { to \dim_use:N \l_@@_tabular_width_dim } } % \end{macrocode} % It \pkg{colortbl} is loaded, |\@tabarray| has been redefined to incorporate % |\CT@start|. % \begin{macrocode} \@tabarray % \end{macrocode} % |\l_@@_baseline_tl| may have the value |t|, |c| or |b|. However, if the value % is |b|, we compose the |\array| (of \pkg{array}) with the option |t| and the % right translation will be done further. Remark that |\str_if_eq:VnTF| is % fully expandable and we need something fully expandable here. % \begin{macrocode} [ \str_if_eq:VnTF \l_@@_baseline_tl c c t ] } % \end{macrocode} % % \medskip % We keep in memory the standard version of |\ialign| because we will redefine % |\ialign| in the environment |{NiceArrayWithDelims}| but restore the standard % version for use in the cells of the array. % \begin{macrocode} \cs_set_eq:NN \@@_old_ialign: \ialign % \end{macrocode} % % % The following command creates a |row| node (and not a row of nodes!). % \begin{macrocode} \cs_new_protected:Npn \@@_create_row_node: { \int_compare:nNnT \c@iRow > \g_@@_last_row_node_int { \int_gset_eq:NN \g_@@_last_row_node_int \c@iRow \@@_create_row_node_i: } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_create_row_node_i: { % \end{macrocode} % The |\hbox:n| (or |\hbox|) is mandatory. % \begin{macrocode} \hbox { \bool_if:NT \l_@@_code_before_bool { \vtop { \skip_vertical:N 0.5\arrayrulewidth \pgfsys@markposition { \@@_env: - row - \int_eval:n { \c@iRow + 1 } } \skip_vertical:N -0.5\arrayrulewidth } } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - row - \int_eval:n { \c@iRow + 1 } } { \pgfpoint \c_zero_dim { - 0.5 \arrayrulewidth } } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - row - \int_eval:n { \c@iRow + 1 } } { \@@_env: - row - \int_eval:n { \c@iRow + 1 } } } \endpgfpicture } } % \end{macrocode} % % % % \bigskip % The following must \emph{not} be protected because it begins with |\noalign|. % \begin{macrocode} \cs_new:Npn \@@_everycr: { \noalign { \@@_everycr_i: } } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_everycr_i: { \int_gzero:N \c@jCol \bool_gset_false:N \g_@@_after_col_zero_bool \bool_if:NF \g_@@_row_of_col_done_bool { \@@_create_row_node: % \end{macrocode} % We don't draw now the rules of the key |hlines| (or |hvlines|) but we reserve the % vertical space for theses rules (the rules will be drawn by \textsc{pgf}). % \begin{macrocode} \tl_if_empty:NF \l_@@_hlines_clist { \tl_if_eq:NNF \l_@@_hlines_clist \c_@@_all_tl { \exp_args:NNe \clist_if_in:NnT \l_@@_hlines_clist { \int_eval:n { \c@iRow + 1 } } } { % \end{macrocode} % The counter |\c@iRow| has the value $-1$ only if there is a ``first % row'' and that we are before that ``first row'', i.e. just before the % beginning of the array. % \begin{macrocode} \int_compare:nNnT \c@iRow > { -1 } { \int_compare:nNnF \c@iRow = \l_@@_last_row_int % \end{macrocode} % The command |\CT@arc@| is a command of \pkg{colortbl} which sets the color of % the rules in the array. The package \pkg{nicematrix} uses it even if % \pkg{colortbl} is not loaded. We use a TeX group in order to limit the scope % of |\CT@arc@|. % \begin{macrocode} { \hrule height \arrayrulewidth width \c_zero_dim } } } } } } % \end{macrocode} % % % % \bigskip % When the key |renew-dots| is used, the following code will be executed. % \begin{macrocode} \cs_set_protected:Npn \@@_renew_dots: { \cs_set_eq:NN \ldots \@@_Ldots \cs_set_eq:NN \cdots \@@_Cdots \cs_set_eq:NN \vdots \@@_Vdots \cs_set_eq:NN \ddots \@@_Ddots \cs_set_eq:NN \iddots \@@_Iddots \cs_set_eq:NN \dots \@@_Ldots \cs_set_eq:NN \hdotsfor \@@_Hdotsfor: } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_test_color_inside: { \bool_if:NF \l_@@_color_inside_bool { % \end{macrocode} % We will issue an error only during the first run. % \begin{macrocode} \bool_if:NF \g_@@_aux_found_bool { \@@_error:n { without~color-inside } } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_redefine_everycr: { \everycr { \@@_everycr: } } \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { colortbl } { \cs_set_protected:Npn \@@_redefine_everycr: { \CT@everycr { \noalign { \cs_gset_eq:NN \CT@row@color \prg_do_nothing: } \@@_everycr: } } } { } } % \end{macrocode} % % If \pkg{booktabs} is loaded, we have to patch the macro |\@BTnormal| which is % a macro of \pkg{booktabs}. The macro |\@BTnormal| draws an horizontal rule but % it occurs after a vertical skip done by a low level TeX command. When this % macro |\@BTnormal| occurs, the |row| node has yet been inserted by % \pkg{nicematrix} \emph{before} the vertical skip (and thus, at a wrong place). % That why we decide to create a new |row| node (for the same row). We patch the % macro |\@BTnormal| to create this |row| node. This new |row| node will % overwrite the previous definition of that |row| node and we have managed to % avoid the error messages of that redefinition % \footnote{cf. |\nicematrix@redefine@check@rerun|}. % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { booktabs } { \cs_new_protected:Npn \@@_patch_booktabs: { \tl_put_left:Nn \@BTnormal \@@_create_row_node_i: } } { \cs_new_protected:Npn \@@_patch_booktabs: { } } } % \end{macrocode} % % \bigskip % The following code |\@@_pre_array_ii:| is used in |{NiceArrayWithDelims}|. It % exists as a standalone macro only for legibility. % \label{prearray} % % \begin{macrocode} \cs_new_protected:Npn \@@_pre_array_ii: { % \end{macrocode} % The number of letters |X| in the preamble of the array. % \begin{macrocode} \int_gzero:N \g_@@_total_X_weight_int % \end{macrocode} % % \begin{macrocode} \@@_expand_clist:N \l_@@_hlines_clist \@@_expand_clist:N \l_@@_vlines_clist \@@_patch_booktabs: \box_clear_new:N \l_@@_cell_box \normalbaselines % \end{macrocode} % If the option |small| is used, we have to do some tuning. In particular, we % change the value of |\arraystretch| (this parameter is used in the % construction of |\@arstrutbox| in the beginning of |{array}|). % \begin{macrocode} \bool_if:NT \l_@@_small_bool { % \end{macrocode} % \begin{macrocode} \cs_set_nopar:Npn \arraystretch { 0.47 } \dim_set:Nn \arraycolsep { 1.45 pt } % \end{macrocode} % By default, |\@@_small_scripstyle:| is null. % \begin{macrocode} \cs_set_eq:NN \@@_tuning_key_small: \scriptstyle } % \end{macrocode} % % \bigskip % \begin{macrocode} \bool_if:NT \g_@@_recreate_cell_nodes_bool { \tl_put_right:Nn \@@_begin_of_row: { \pgfsys@markposition { \@@_env: - row - \int_use:N \c@iRow - base } } } % \end{macrocode} % % \bigskip % The environment |{array}| uses internally the command |\ialign|. We change the % definition of |\ialign| for several reasons. In particular, |\ialign| sets % |\everycr| to |{ }| and we \emph{need} to have to change the value of % |\everycr|. % \begin{macrocode} \cs_set_nopar:Npn \ialign { \@@_redefine_everycr: \tabskip = \c_zero_skip % \end{macrocode} % % The box |\@arstrutbox| is a box constructed in the beginning of the % environment |{array}|. The construction of that box takes into account the % current value of |\arraystretch|\footnote{The option |small| of % \pkg{nicematrix} changes (among others) the value of |\arraystretch|. This is % done, of course, before the call of |{array}|.} and |\extrarowheight| (of % \pkg{array}). That box is inserted (via |\@arstrut|) in the beginning of each % row of the array. That's why we use the dimensions of that box to initialize % the variables which will be the dimensions of the potential first and last row % of the environment. This initialization must be done after the creation of % |\@arstrutbox| and that's why we do it in the |\ialign|. % \begin{macrocode} \dim_gzero_new:N \g_@@_dp_row_zero_dim \dim_gset:Nn \g_@@_dp_row_zero_dim { \box_dp:N \@arstrutbox } \dim_gzero_new:N \g_@@_ht_row_zero_dim \dim_gset:Nn \g_@@_ht_row_zero_dim { \box_ht:N \@arstrutbox } \dim_gzero_new:N \g_@@_ht_row_one_dim \dim_gset:Nn \g_@@_ht_row_one_dim { \box_ht:N \@arstrutbox } \dim_gzero_new:N \g_@@_dp_ante_last_row_dim \dim_gzero_new:N \g_@@_ht_last_row_dim \dim_gset:Nn \g_@@_ht_last_row_dim { \box_ht:N \@arstrutbox } \dim_gzero_new:N \g_@@_dp_last_row_dim \dim_gset:Nn \g_@@_dp_last_row_dim { \box_dp:N \@arstrutbox } % \end{macrocode} % After its first use, the definition of |\ialign| will revert % automatically to its default definition. With this programmation, we will % have, in the cells of the array, a clean version of |\ialign|. % \begin{macrocode} \cs_set_eq:NN \ialign \@@_old_ialign: \halign } % \end{macrocode} % % We keep in memory the old versions or |\ldots|, |\cdots|, etc. only because we % use them inside |\phantom| commands in order that the new commands |\Ldots|, % |\Cdots|, etc. give the same spacing (except when the option |nullify-dots| is % used). % \begin{macrocode} \cs_set_eq:NN \@@_old_ldots \ldots \cs_set_eq:NN \@@_old_cdots \cdots \cs_set_eq:NN \@@_old_vdots \vdots \cs_set_eq:NN \@@_old_ddots \ddots \cs_set_eq:NN \@@_old_iddots \iddots \bool_if:NTF \l_@@_standard_cline_bool { \cs_set_eq:NN \cline \@@_standard_cline } { \cs_set_eq:NN \cline \@@_cline } \cs_set_eq:NN \Ldots \@@_Ldots \cs_set_eq:NN \Cdots \@@_Cdots \cs_set_eq:NN \Vdots \@@_Vdots \cs_set_eq:NN \Ddots \@@_Ddots \cs_set_eq:NN \Iddots \@@_Iddots \cs_set_eq:NN \Hline \@@_Hline: \cs_set_eq:NN \Hspace \@@_Hspace: \cs_set_eq:NN \Hdotsfor \@@_Hdotsfor: \cs_set_eq:NN \Vdotsfor \@@_Vdotsfor: \cs_set_eq:NN \Block \@@_Block: \cs_set_eq:NN \rotate \@@_rotate: \cs_set_eq:NN \OnlyMainNiceMatrix \@@_OnlyMainNiceMatrix:n \cs_set_eq:NN \dotfill \@@_dotfill: \cs_set_eq:NN \CodeAfter \@@_CodeAfter: \cs_set_eq:NN \diagbox \@@_diagbox:nn \cs_set_eq:NN \NotEmpty \@@_NotEmpty: \cs_set_eq:NN \RowStyle \@@_RowStyle:n \seq_map_inline:Nn \l_@@_custom_line_commands_seq { \cs_set_eq:cc { ##1 } { nicematrix - ##1 } } \cs_set_eq:NN \cellcolor \@@_cellcolor_tabular \cs_set_eq:NN \rowcolor \@@_rowcolor_tabular \cs_set_eq:NN \rowcolors \@@_rowcolors_tabular \cs_set_eq:NN \rowlistcolors \@@_rowlistcolors_tabular \int_compare:nNnT \l_@@_first_row_int > \c_zero_int { \cs_set_eq:NN \@@_tuning_first_row: \prg_do_nothing: } \int_compare:nNnT \l_@@_last_row_int < \c_zero_int { \cs_set_eq:NN \@@_tuning_last_row: \prg_do_nothing: } \bool_if:NT \l_@@_renew_dots_bool \@@_renew_dots: % \end{macrocode} % We redefine |\multicolumn| and, since we want |\multicolumn| to be available % in the potential environments |{tabular}| nested in the environments of % \pkg{nicematrix}, we patch |{tabular}| to go back to the original definition. % \begin{macrocode} \cs_set_eq:NN \multicolumn \@@_multicolumn:nnn \hook_gput_code:nnn { env / tabular / begin } { . } { \cs_set_eq:NN \multicolumn \@@_old_multicolumn } \@@_revert_colortbl: % \end{macrocode} % If there is one or several commands |\tabularnote| in the caption specified % by the key |caption| and if that caption has to be composed above the tabular, % we have now that information because it has been written in the |aux| file at % a previous run. We use that information to start counting the tabular notes in % the main array at the right value (we remember that the caption will be % composed \emph{after} the array!). % \begin{macrocode} \tl_if_exist:NT \l_@@_note_in_caption_tl { \tl_if_empty:NF \l_@@_note_in_caption_tl { \int_gset_eq:NN \g_@@_notes_caption_int \l_@@_note_in_caption_tl \int_gset:Nn \c@tabularnote { \l_@@_note_in_caption_tl } } } % \end{macrocode} % % % The sequence |\g_@@_multicolumn_cells_seq| will contain the list of the cells % of the array where a command |\multicolumn{|$n$|}{...}{...}| with $n>1$ is % issued. In |\g_@@_multicolumn_sizes_seq|, the ``sizes'' (that is to say the % values of $n$) correspondant will be stored. These lists will be used for the % creation of the ``medium nodes'' (if they are created). % \begin{macrocode} \seq_gclear:N \g_@@_multicolumn_cells_seq \seq_gclear:N \g_@@_multicolumn_sizes_seq % \end{macrocode} % % The counter |\c@iRow| will be used to count the rows of the array (its % incrementation will be in the first cell of the row). % \begin{macrocode} \int_gset:Nn \c@iRow { \l_@@_first_row_int - 1 } % \end{macrocode} % % At the end of the environment |{array}|, |\c@iRow| will be the total % number de rows. % % |\g_@@_row_total_int| will be the number or rows excepted the last row (if % |\l_@@_last_row_bool| has been raised with the option |last-row|). % \begin{macrocode} \int_gzero_new:N \g_@@_row_total_int % \end{macrocode} % % The counter |\c@jCol| will be used to count the columns of the array. % Since we want to know the total number of columns of the matrix, we also % create a counter |\g_@@_col_total_int|. These counters are updated in the % command |\@@_cell_begin:w| executed at the beginning of each cell. % \begin{macrocode} \int_gzero_new:N \g_@@_col_total_int % \end{macrocode} % % \begin{macrocode} \cs_set_eq:NN \@ifnextchar \new@ifnextchar % \end{macrocode} % % \begin{macrocode} \bool_gset_false:N \g_@@_last_col_found_bool % \end{macrocode} % % \medskip % During the construction of the array, the instructions |\Cdots|, |\Ldots|, % etc. will be written in token lists |\g_@@_Cdots_lines_tl|, etc. which will be % executed after the construction of the array. % \begin{macrocode} \tl_gclear_new:N \g_@@_Cdots_lines_tl \tl_gclear_new:N \g_@@_Ldots_lines_tl \tl_gclear_new:N \g_@@_Vdots_lines_tl \tl_gclear_new:N \g_@@_Ddots_lines_tl \tl_gclear_new:N \g_@@_Iddots_lines_tl \tl_gclear_new:N \g_@@_HVdotsfor_lines_tl % \end{macrocode} % % \medskip % \begin{macrocode} \tl_gclear:N \g_nicematrix_code_before_tl \tl_gclear:N \g_@@_pre_code_before_tl } % \end{macrocode} % This is the end of |\@@_pre_array_ii:|. % % % \bigskip % The command |\@@_pre_array:| will be executed after analyse of the keys of the % environment. % \begin{macrocode} \cs_new_protected:Npn \@@_pre_array: { \cs_if_exist:NT \theiRow { \int_set_eq:NN \l_@@_old_iRow_int \c@iRow } \int_gzero_new:N \c@iRow \cs_if_exist:NT \thejCol { \int_set_eq:NN \l_@@_old_jCol_int \c@jCol } \int_gzero_new:N \c@jCol % \end{macrocode} % % \bigskip % We recall that |\l_@@_last_row_int| and |\l_@@_last_column_int| are \emph{not} % the numbers of the last row and last column of the array. There are only the % values of the keys |last-row| and |last-column| (maybe the user has provided % erroneous values). The meaning of that counters does not change during the % environment of \pkg{nicematrix}. There is only a slight adjustment: if the % user have used one of those keys without value, we provide now the right value % as read on the |aux| file (of course, it's possible only after the first compilation). % \begin{macrocode} \int_compare:nNnT \l_@@_last_row_int = { -1 } { \bool_set_true:N \l_@@_last_row_without_value_bool \bool_if:NT \g_@@_aux_found_bool { \int_set:Nn \l_@@_last_row_int { \seq_item:Nn \g_@@_size_seq 3 } } } \int_compare:nNnT \l_@@_last_col_int = { -1 } { \bool_if:NT \g_@@_aux_found_bool { \int_set:Nn \l_@@_last_col_int { \seq_item:Nn \g_@@_size_seq 6 } } } % \end{macrocode} % % \bigskip % If there is an exterior row, we patch a command used in |\@@_cell_begin:w| in order to % keep track of some dimensions needed to the construction of that ``last row''. % \begin{macrocode} \int_compare:nNnT \l_@@_last_row_int > { -2 } { \tl_put_right:Nn \@@_update_for_first_and_last_row: { \dim_gset:Nn \g_@@_ht_last_row_dim { \dim_max:nn \g_@@_ht_last_row_dim { \box_ht:N \l_@@_cell_box } } \dim_gset:Nn \g_@@_dp_last_row_dim { \dim_max:nn \g_@@_dp_last_row_dim { \box_dp:N \l_@@_cell_box } } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \seq_gclear:N \g_@@_cols_vlism_seq \seq_gclear:N \g_@@_submatrix_seq % \end{macrocode} % % \bigskip % Now the |\CodeBefore|. % \begin{macrocode} \bool_if:NT \l_@@_code_before_bool \@@_exec_code_before: % \end{macrocode} % % \bigskip % The value of |\g_@@_pos_of_blocks_seq| has been written on the |aux| file and % loaded before the (potential) execution of the |\CodeBefore|. Now, we clear % that variable because it will be reconstructed during the creation of the % array. % \begin{macrocode} \seq_gclear:N \g_@@_pos_of_blocks_seq % \end{macrocode} % Idem for other sequences written on the |aux| file. % \begin{macrocode} \seq_gclear_new:N \g_@@_multicolumn_cells_seq \seq_gclear_new:N \g_@@_multicolumn_sizes_seq % \end{macrocode} % % \bigskip % The command |\create_row_node:| will create a row-node (and not a row of % nodes!). However, at the end of the array we construct a ``false row'' (for % the col-nodes) and it interfers with the construction of the last row-node % of the array. We don't want to create such row-node twice (to avaid warnings % or, maybe, errors). That's why the command |\@@_create_row_node:| will use the % following counter to avoid such construction. % \begin{macrocode} \int_gset:Nn \g_@@_last_row_node_int { -2 } % \end{macrocode} % The value $-2$ is important. % % % \interitem % The code in |\@@_pre_array_ii:| is used only here. % \begin{macrocode} \@@_pre_array_ii: % \end{macrocode} % % \medskip % The array will be composed in a box (named |\l_@@_the_array_box|) because we % have to do manipulations concerning the potential exterior rows. % \begin{macrocode} \box_clear_new:N \l_@@_the_array_box % \end{macrocode} % % \medskip % We compute the width of both delimiters. We remind that, when the % environment |{NiceArray}| is used, it's possible to specify the delimiters in % the preamble (eg |[ccc]|). % \begin{macrocode} \dim_zero_new:N \l_@@_left_delim_dim \dim_zero_new:N \l_@@_right_delim_dim \bool_if:NTF \g_@@_delims_bool { % \end{macrocode} % The command |\bBigg@| is a command of \pkg{amsmath}. % \begin{macrocode} \hbox_set:Nn \l_tmpa_box { $ \bBigg@ 5 \g_@@_left_delim_tl $ } \dim_set:Nn \l_@@_left_delim_dim { \box_wd:N \l_tmpa_box } \hbox_set:Nn \l_tmpa_box { $ \bBigg@ 5 \g_@@_right_delim_tl $ } \dim_set:Nn \l_@@_right_delim_dim { \box_wd:N \l_tmpa_box } } { \dim_gset:Nn \l_@@_left_delim_dim { 2 \bool_if:NTF \l_@@_tabular_bool \tabcolsep \arraycolsep } \dim_gset_eq:NN \l_@@_right_delim_dim \l_@@_left_delim_dim } % \end{macrocode} % % \bigskip % Here is the beginning of the box which will contain the array. The % |\hbox_set_end:| corresponding to this |\hbox_set:Nw| will be in the second % part of the environment (and the closing |\c_math_toggle_token| also). % \begin{macrocode} \hbox_set:Nw \l_@@_the_array_box % \end{macrocode} % % \begin{macrocode} \skip_horizontal:N \l_@@_left_margin_dim \skip_horizontal:N \l_@@_extra_left_margin_dim \c_math_toggle_token \bool_if:NTF \l_@@_light_syntax_bool { \use:c { @@-light-syntax } } { \use:c { @@-normal-syntax } } } % \end{macrocode} % % \bigskip % The following command |\@@_CodeBefore_Body:w| will be used when the keyword % |\CodeBefore| is present at the beginning of the environment. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_CodeBefore_Body:w #1 \Body { \tl_set:Nn \l_tmpa_tl { #1 } \int_compare:nNnT { \char_value_catcode:n { 60 } } = { 13 } { \@@_rescan_for_spanish:N \l_tmpa_tl } \tl_gput_left:NV \g_@@_pre_code_before_tl \l_tmpa_tl \bool_set_true:N \l_@@_code_before_bool % \end{macrocode} % We go on with |\@@_pre_array:| which will (among other) execute the % |\CodeBefore| (specified in the key |code-before| or after the keyword % |\CodeBefore|). By definition, the |\CodeBefore| must be executed before the % body of the array... % \begin{macrocode} \@@_pre_array: } % \end{macrocode} % % % % \bigskip % \section{The \textbackslash CodeBefore} % % The following command will be executed if the |\CodeBefore| has to be actually % executed (that commmand will be used only once and is present only for legibility). % \begin{macrocode} \cs_new_protected:Npn \@@_pre_code_before: { % \end{macrocode} % First, we give values to the LaTeX counters |iRow| and |jCol|. We remind that, % in the |\CodeBefore| (and in the |\CodeAfter|) they represent the numbers of % rows and columns of the array (without the potential last row and last % column). The value of |\g_@@_row_total_int| is the number of the last row % (with potentially a last exterior row) and |\g_@@_col_total_int| is the number % of the last column (with potentially a last exterior column). % \begin{macrocode} \int_set:Nn \c@iRow { \seq_item:Nn \g_@@_size_seq 2 } \int_set:Nn \c@jCol { \seq_item:Nn \g_@@_size_seq 5 } \int_set_eq:NN \g_@@_row_total_int { \seq_item:Nn \g_@@_size_seq 3 } \int_set_eq:NN \g_@@_col_total_int { \seq_item:Nn \g_@@_size_seq 6 } % \end{macrocode} % % % Now, we will create all the |col| nodes and |row| nodes with the informations % written in the |aux| file. You use the technique described in the page~1229 of % |pgfmanual.pdf|, version~3.1.4b. % \begin{macrocode} \pgfsys@markposition { \@@_env: - position } \pgfsys@getposition { \@@_env: - position } \@@_picture_position: \pgfpicture \pgf@relevantforpicturesizefalse % \end{macrocode} % First, the recreation of the |row| nodes. % \begin{macrocode} \int_step_inline:nnn \l_@@_first_row_int { \g_@@_row_total_int + 1 } { \pgfsys@getposition { \@@_env: - row - ##1 } \@@_node_position: \pgfcoordinate { \@@_env: - row - ##1 } { \pgfpointdiff \@@_picture_position: \@@_node_position: } } % \end{macrocode} % Now, the recreation of the |col| nodes. % \begin{macrocode} \int_step_inline:nnn \l_@@_first_col_int { \g_@@_col_total_int + 1 } { \pgfsys@getposition { \@@_env: - col - ##1 } \@@_node_position: \pgfcoordinate { \@@_env: - col - ##1 } { \pgfpointdiff \@@_picture_position: \@@_node_position: } } % \end{macrocode} % Now, you recreate the diagonal nodes by using the |row| nodes and the |col| % nodes. % \begin{macrocode} \@@_create_diag_nodes: % \end{macrocode} % % \medskip % Now, the creation of the cell nodes |(i-j)|, and, maybe also the ``medium % nodes'' and the ``large nodes''. % \begin{macrocode} \bool_if:NT \g_@@_recreate_cell_nodes_bool \@@_recreate_cell_nodes: \endpgfpicture % \end{macrocode} % % \medskip % Now, the recreation of the nodes of the blocks \emph{which have a name}. % \begin{macrocode} \@@_create_blocks_nodes: % \end{macrocode} % % \begin{macrocode} \IfPackageLoadedTF { tikz } { \tikzset { every~picture / .style = { overlay , name~prefix = \@@_env: - } } } { } \cs_set_eq:NN \cellcolor \@@_cellcolor \cs_set_eq:NN \rectanglecolor \@@_rectanglecolor \cs_set_eq:NN \roundedrectanglecolor \@@_roundedrectanglecolor \cs_set_eq:NN \rowcolor \@@_rowcolor \cs_set_eq:NN \rowcolors \@@_rowcolors \cs_set_eq:NN \rowlistcolors \@@_rowlistcolors \cs_set_eq:NN \arraycolor \@@_arraycolor \cs_set_eq:NN \columncolor \@@_columncolor \cs_set_eq:NN \chessboardcolors \@@_chessboardcolors \cs_set_eq:NN \SubMatrix \@@_SubMatrix_in_code_before \cs_set_eq:NN \ShowCellNames \@@_ShowCellNames \cs_set_eq:NN \TikzEveryCell \@@_TikzEveryCell } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_exec_code_before: { \seq_gclear_new:N \g_@@_colors_seq % \end{macrocode} % The sequence |\g_@@_colors_seq| will always contain as first element the % special color |nocolor|: when that color is used, no color will be applied in % the corresponding cells by the other coloring commands of \pkg{nicematrix}. % \begin{macrocode} \@@_add_to_colors_seq:nn { { nocolor } } { } \bool_gset_false:N \g_@@_recreate_cell_nodes_bool \group_begin: % \end{macrocode} % % We compose the |\CodeBefore| in math mode in order to nullify the spaces put % by the user between instructions in the |\CodeBefore|. % \begin{macrocode} \bool_if:NT \l_@@_tabular_bool \c_math_toggle_token % \end{macrocode} % % \bigskip % The following code is a security for the case the user has used \pkg{babel} % with the option \pkg{spanish}: in that case, the characters |<| (de code % \textsc{ascci} 60) and |>| are activated and Tikz is not able to solve the % problem (even with the Tikz library \pkg{babel}). % \begin{macrocode} \int_compare:nNnT { \char_value_catcode:n { 60 } } = { 13 } { \@@_rescan_for_spanish:N \l_@@_code_before_tl } % \end{macrocode} % % Here is the |\CodeBefore|. The construction is a bit complicated because % |\g_@@_pre_code_before_tl| may begin with keys between square brackets. Moreover, % after the analyze of those keys, we sometimes have to decide to do \emph{not} % execute the rest of |\g_@@_pre_code_before_tl| (when it is asked for the creation % of cell nodes in the |\CodeBefore|). That's why we use a |\q_stop|: it % will be used to discard the rest of |\g_@@_pre_code_before_tl|. % \begin{macrocode} \exp_last_unbraced:NV \@@_CodeBefore_keys: \g_@@_pre_code_before_tl % \end{macrocode} % Now, all the cells which are specified to be colored by instructions in the % |\CodeBefore| will actually be colored. It's a two-stages mechanism because we % want to draw all the cells with the same color at the same time to absolutely % avoid thin white lines in some \textsc{pdf} viewers. % \begin{macrocode} \@@_actually_color: \l_@@_code_before_tl \q_stop \bool_if:NT \l_@@_tabular_bool \c_math_toggle_token \group_end: \bool_if:NT \g_@@_recreate_cell_nodes_bool { \tl_put_left:Nn \@@_node_for_cell: \@@_patch_node_for_cell: } } % \end{macrocode} % % \bigskip % \begin{macrocode} \keys_define:nn { NiceMatrix / CodeBefore } { create-cell-nodes .bool_gset:N = \g_@@_recreate_cell_nodes_bool , create-cell-nodes .default:n = true , sub-matrix .code:n = \keys_set:nn { NiceMatrix / sub-matrix } { #1 } , sub-matrix .value_required:n = true , delimiters / color .tl_set:N = \l_@@_delimiters_color_tl , delimiters / color .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~CodeBefore } } % \end{macrocode} % % % \begin{macrocode} \NewDocumentCommand \@@_CodeBefore_keys: { O { } } { \keys_set:nn { NiceMatrix / CodeBefore } { #1 } \@@_CodeBefore:w } % \end{macrocode} % % We have extracted the options of the keyword |\CodeBefore| in order to see % whether the key |create-cell-nodes| has been used. Now, you can execute the % rest of the |\CodeBefore|, excepted, of course, if we are in the first % compilation. % \begin{macrocode} \cs_new_protected:Npn \@@_CodeBefore:w #1 \q_stop { \bool_if:NT \g_@@_aux_found_bool { \@@_pre_code_before: #1 } } % \end{macrocode} % % % \bigskip % By default, if the user uses the |\CodeBefore|, only the |col| nodes, |row| % nodes and |diag| nodes are available in that |\CodeBefore|. With the key % |create-cell-nodes|, the cell nodes, that is to say the nodes of the form % |(i-j)| (but not the extra nodes) are also available because those nodes also % are recreated and that recreation is done by the following command. % \begin{macrocode} \cs_new_protected:Npn \@@_recreate_cell_nodes: { \int_step_inline:nnn \l_@@_first_row_int \g_@@_row_total_int { \pgfsys@getposition { \@@_env: - ##1 - base } \@@_node_position: \pgfcoordinate { \@@_env: - row - ##1 - base } { \pgfpointdiff \@@_picture_position: \@@_node_position: } \int_step_inline:nnn \l_@@_first_col_int \g_@@_col_total_int { \cs_if_exist:cT { pgf @ sys @ pdf @ mark @ pos @ \@@_env: - ##1 - ####1 - NW } { \pgfsys@getposition { \@@_env: - ##1 - ####1 - NW } \@@_node_position: \pgfsys@getposition { \@@_env: - ##1 - ####1 - SE } \@@_node_position_i: \@@_pgf_rect_node:nnn { \@@_env: - ##1 - ####1 } { \pgfpointdiff \@@_picture_position: \@@_node_position: } { \pgfpointdiff \@@_picture_position: \@@_node_position_i: } } } } \int_step_inline:nn \c@iRow { \pgfnodealias { \@@_env: - ##1 - last } { \@@_env: - ##1 - \int_use:N \c@jCol } } \int_step_inline:nn \c@jCol { \pgfnodealias { \@@_env: - last - ##1 } { \@@_env: - \int_use:N \c@iRow - ##1 } } \@@_create_extra_nodes: } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_create_blocks_nodes: { \pgfpicture \pgf@relevantforpicturesizefalse \pgfrememberpicturepositiononpagetrue \seq_map_inline:Nn \g_@@_pos_of_blocks_seq { \@@_create_one_block_node:nnnnn ##1 } \endpgfpicture } % \end{macrocode} % % The following command is called |\@@_create_one_block_node:nnnnn| but, in % fact, it creates a node only if the last argument (|#5|) which is the name of % the block, is not empty.\footnote{Moreover, there is also in the list % |\g_@@_pos_of_blocks_seq| the positions of the dotted lines (created by % |\Cdots|, etc.) and, for these entries, there is, of course, no name (the % fifth component is empty).} % \begin{macrocode} \cs_new_protected:Npn \@@_create_one_block_node:nnnnn #1 #2 #3 #4 #5 { \tl_if_empty:nF { #5 } { \@@_qpoint:n { col - #2 } \dim_set_eq:NN \l_tmpa_dim \pgf@x \@@_qpoint:n { #1 } \dim_set_eq:NN \l_tmpb_dim \pgf@y \@@_qpoint:n { col - \int_eval:n { #4 + 1 } } \dim_set_eq:NN \l_@@_tmpc_dim \pgf@x \@@_qpoint:n { \int_eval:n { #3 + 1 } } \dim_set_eq:NN \l_@@_tmpd_dim \pgf@y \@@_pgf_rect_node:nnnnn { \@@_env: - #5 } { \dim_use:N \l_tmpa_dim } { \dim_use:N \l_tmpb_dim } { \dim_use:N \l_@@_tmpc_dim } { \dim_use:N \l_@@_tmpd_dim } } } % \end{macrocode} % % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_patch_for_revtex: { \cs_set_eq:NN \@addamp \@addamp@LaTeX \cs_set_eq:NN \insert@column \insert@column@array \cs_set_eq:NN \@classx \@classx@array \cs_set_eq:NN \@xarraycr \@xarraycr@array \cs_set_eq:NN \@arraycr \@arraycr@array \cs_set_eq:NN \@xargarraycr \@xargarraycr@array \cs_set_eq:NN \array \array@array \cs_set_eq:NN \@array \@array@array \cs_set_eq:NN \@tabular \@tabular@array \cs_set_eq:NN \@mkpream \@mkpream@array \cs_set_eq:NN \endarray \endarray@array \cs_set:Npn \@tabarray { \@ifnextchar [ { \@array } { \@array [ c ] } } \cs_set:Npn \endtabular { \endarray $\egroup} % $ } % \end{macrocode} % % % \bigskip % \section{The environment \{NiceArrayWithDelims\}} % % \begin{macrocode} \NewDocumentEnvironment { NiceArrayWithDelims } { m m O { } m ! O { } t \CodeBefore } { \bool_if:NT \c_@@_revtex_bool \@@_patch_for_revtex: % \end{macrocode} % % \begin{macrocode} \@@_provide_pgfsyspdfmark: \bool_if:NT \g_@@_footnote_bool \savenotes % \end{macrocode} % % The aim of the following |\bgroup| (the corresponding |\egroup| is, of course, % at the end of the environment) is to be able to put an exposant to a matrix in % a mathematical formula. % \begin{macrocode} \bgroup % \end{macrocode} % % \bigskip % \begin{macrocode} \tl_gset:Nn \g_@@_left_delim_tl { #1 } \tl_gset:Nn \g_@@_right_delim_tl { #2 } \tl_gset:Nn \g_@@_user_preamble_tl { #4 } % \end{macrocode} % % % \bigskip % \begin{macrocode} \int_gzero:N \g_@@_block_box_int \dim_zero:N \g_@@_width_last_col_dim \dim_zero:N \g_@@_width_first_col_dim \bool_gset_false:N \g_@@_row_of_col_done_bool \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { NiceArrayWithDelims } } \bool_if:NTF \l_@@_tabular_bool \mode_leave_vertical: \@@_test_if_math_mode: \bool_if:NT \l_@@_in_env_bool { \@@_fatal:n { Yet~in~env } } \bool_set_true:N \l_@@_in_env_bool % \end{macrocode} % The command |\CT@arc@| contains the instruction of color for the rules of the % array\footnote{e.g. |\color[rgb]{0.5,0.5,0}|}. This command is used by |\CT@arc@| but % we use it also for compatibility with \pkg{colortbl}. But we want also to be % able to use color for the rules of the array when \pkg{colortbl} is \emph{not} % loaded. That's why we do the following instruction which is in the patch of % the beginning of arrays done by \pkg{colortbl}. Of course, we restore the % value of |\CT@arc@| at the end of our environment. % \begin{macrocode} \cs_gset_eq:NN \@@_old_CT@arc@ \CT@arc@ % \end{macrocode} % % We deactivate Tikz externalization because we will use \textsc{pgf} pictures % with the options |overlay| and |remember picture| (or equivalent forms). We % deactivate with |\tikzexternaldisable| and not with % |\tikzset{external/export=false}| which is \emph{not} equivalent. % \begin{macrocode} \cs_if_exist:NT \tikz@library@external@loaded { \tikzexternaldisable \cs_if_exist:NT \ifstandalone { \tikzset { external / optimize = false } } } % \end{macrocode} % % We increment the counter |\g_@@_env_int| which counts the environments % of the package. % \begin{macrocode} \int_gincr:N \g_@@_env_int \bool_if:NF \l_@@_block_auto_columns_width_bool { \dim_gzero_new:N \g_@@_max_cell_width_dim } % \end{macrocode} % % % The sequence |\g_@@_blocks_seq| will contain the carateristics of the blocks % (specified by |\Block|) of the array. The sequence |\g_@@_pos_of_blocks_seq| % will contain only the position of the blocks (except the blocks with the key % |hvlines|). % \begin{macrocode} \seq_gclear:N \g_@@_blocks_seq \seq_gclear:N \g_@@_pos_of_blocks_seq % \end{macrocode} % In fact, the sequence |\g_@@_pos_of_blocks_seq| will also contain the % positions of the cells with a |\diagbox| and the |\multicolumn|. % % \begin{macrocode} \seq_gclear:N \g_@@_pos_of_stroken_blocks_seq \seq_gclear:N \g_@@_pos_of_xdots_seq \tl_gclear_new:N \g_@@_code_before_tl \tl_gclear:N \g_@@_row_style_tl % \end{macrocode} % % \bigskip % We load all the informations written in the |aux| file during previous % compilations corresponding to the current environment. % \begin{macrocode} \tl_if_exist:cTF { c_@@ _ \int_use:N \g_@@_env_int _ tl } { \bool_gset_true:N \g_@@_aux_found_bool \use:c { c_@@ _ \int_use:N \g_@@_env_int _ tl } } { \bool_gset_false:N \g_@@_aux_found_bool } % \end{macrocode} % Now, we prepare the token list for the instructions that we will have to write % on the |aux| file at the end of the environment. % \begin{macrocode} \tl_gclear:N \g_@@_aux_tl % \end{macrocode} % % \begin{macrocode} \tl_if_empty:NF \g_@@_code_before_tl { \bool_set_true:N \l_@@_code_before_bool \tl_put_right:NV \l_@@_code_before_tl \g_@@_code_before_tl } \tl_if_empty:NF \g_@@_pre_code_before_tl { \bool_set_true:N \l_@@_code_before_bool } % \end{macrocode} % % The set of keys is not exactly the same for |{NiceArray}| and for the variants % of |{NiceArray}| (|{pNiceArray}|, |{bNiceArray}|, etc.) because, for % |{NiceArray}|, we have the options |t|, |c|, |b| and |baseline|. % \begin{macrocode} \bool_if:NTF \g_@@_delims_bool { \keys_set:nn { NiceMatrix / pNiceArray } } { \keys_set:nn { NiceMatrix / NiceArray } } { #3 , #5 } % \end{macrocode} % % \bigskip % \begin{macrocode} \@@_set_CT@arc@:o \l_@@_rules_color_tl % \end{macrocode} % % \bigskip % The argument |#6| is the last argument of |{NiceArrayWithDelims}|. With that % argument of type ``|t \CodeBefore|'', we test whether there is the keyword % |\CodeBefore| at the beginning of the body of the environment. If that keyword % is present, we have now to extract all the content between that keyword % |\CodeBefore| and the (other) keyword |\Body|. It's the job that will do the % command |\@@_CodeBefore_Body:w|. After that job, the command |\@@_CodeBefore_Body:w| % will go on with |\@@_pre_array:|. % \begin{macrocode} \IfBooleanTF { #6 } \@@_CodeBefore_Body:w \@@_pre_array: } % \end{macrocode} % % Now, the second part of the environment |{NiceArrayWithDelims}|. % \begin{macrocode} { \bool_if:NTF \l_@@_light_syntax_bool { \use:c { end @@-light-syntax } } { \use:c { end @@-normal-syntax } } \c_math_toggle_token \skip_horizontal:N \l_@@_right_margin_dim \skip_horizontal:N \l_@@_extra_right_margin_dim \hbox_set_end: % \end{macrocode} % End of the construction of the array (in the box |\l_@@_the_array_box|). % % \bigskip % If the user has used the key |width| without any column |X|, we raise an error. % \begin{macrocode} \bool_if:NT \l_@@_width_used_bool { \int_if_zero:nT \g_@@_total_X_weight_int { \@@_error_or_warning:n { width~without~X~columns } } } % \end{macrocode} % % \bigskip % Now, if there is at least one |X|-column in the environment, we compute the % width that those columns will have (in the next compilation). In fact, % |l_@@_X_columns_dim| will be the width of a column of weight $1$. For a % |X|-column of weight~$n$, the width will be |\l_@@_X_columns_dim| multiplied % by~$n$. % \begin{macrocode} \int_compare:nNnT \g_@@_total_X_weight_int > \c_zero_int { \tl_gput_right:Nx \g_@@_aux_tl { \bool_set_true:N \l_@@_X_columns_aux_bool \dim_set:Nn \l_@@_X_columns_dim { \dim_compare:nNnTF { \dim_abs:n { \l_@@_width_dim - \box_wd:N \l_@@_the_array_box } } < { 0.001 pt } { \dim_use:N \l_@@_X_columns_dim } { \dim_eval:n { ( \l_@@_width_dim - \box_wd:N \l_@@_the_array_box ) / \int_use:N \g_@@_total_X_weight_int + \l_@@_X_columns_dim } } } } } % \end{macrocode} % % \bigskip % It the user has used the key |last-row| with a value, we control that the % given value is correct (since we have just constructed the array, we know the % actual number of rows of the array). % \begin{macrocode} \int_compare:nNnT \l_@@_last_row_int > { -2 } { \bool_if:NF \l_@@_last_row_without_value_bool { \int_compare:nNnF \l_@@_last_row_int = \c@iRow { \@@_error:n { Wrong~last~row } \int_gset_eq:NN \l_@@_last_row_int \c@iRow } } } % \end{macrocode} % % Now, the definition of |\c@jCol| and |\g_@@_col_total_int| change: |\c@jCol| % will be the number of columns without the ``last column''; % |\g_@@_col_total_int| will be the number of columns with this ``last % column''.\footnote{We remind that the potential ``first column'' (exterior) % has the number~$0$.} % \begin{macrocode} \int_gset_eq:NN \c@jCol \g_@@_col_total_int \bool_if:NTF \g_@@_last_col_found_bool { \int_gdecr:N \c@jCol } { \int_compare:nNnT \l_@@_last_col_int > { -1 } { \@@_error:n { last~col~not~used } } } % \end{macrocode} % % We fix also the value of |\c@iRow| and |\g_@@_row_total_int| with the % same principle. % \begin{macrocode} \int_gset_eq:NN \g_@@_row_total_int \c@iRow \int_compare:nNnT \l_@@_last_row_int > { -1 } { \int_gdecr:N \c@iRow } % \end{macrocode} % % % \bigskip % \textbf{Now, we begin the real construction in the output flow of TeX}. First, we take % into account a potential ``first column'' (we remind that this ``first % column'' has been constructed in an overlapping position and that we have % computed its width in |\g_@@_width_first_col_dim|: see % p.~\pageref{overlap-left}). % \begin{macrocode} \int_if_zero:nT \l_@@_first_col_int { \skip_horizontal:N \g_@@_width_first_col_dim } % \end{macrocode} % % The construction of the real box is different whether we have delimiters to % put. % \begin{macrocode} \bool_if:nTF { ! \g_@@_delims_bool } { \tl_if_eq:NNTF \l_@@_baseline_tl \c_@@_c_tl \@@_use_arraybox_with_notes_c: { \tl_if_eq:NNTF \l_@@_baseline_tl \c_@@_b_tl \@@_use_arraybox_with_notes_b: \@@_use_arraybox_with_notes: } } % \end{macrocode} % % Now, in the case of an environment with delimiters. We compute |\l_tmpa_dim| % which is the total height of the ``first row'' above the array (when the key % |first-row| is used). % \begin{macrocode} { \int_if_zero:nTF \l_@@_first_row_int { \dim_set_eq:NN \l_tmpa_dim \g_@@_dp_row_zero_dim \dim_add:Nn \l_tmpa_dim \g_@@_ht_row_zero_dim } { \dim_zero:N \l_tmpa_dim } % \end{macrocode} % % We compute |\l_tmpb_dim| which is the total height of the ``last row'' % below the array (when the key |last-row| is used). A value of $-2$ for % |\l_@@_last_row_int| means that there is no ``last row''.\footnote{A value of % $-1$ for |\l_@@_last_row_int| means that there is a ``last row'' but the % the user have not set the value with the option |last row| (and we are in the % first compilation).} % \begin{macrocode} \int_compare:nNnTF \l_@@_last_row_int > { -2 } { \dim_set_eq:NN \l_tmpb_dim \g_@@_ht_last_row_dim \dim_add:Nn \l_tmpb_dim \g_@@_dp_last_row_dim } { \dim_zero:N \l_tmpb_dim } % \end{macrocode} % % \begin{macrocode} \hbox_set:Nn \l_tmpa_box { \c_math_toggle_token \@@_color:o \l_@@_delimiters_color_tl \exp_after:wN \left \g_@@_left_delim_tl \vcenter { % \end{macrocode} % We take into account the ``first row'' (we have previously computed its total % height in |\l_tmpa_dim|). The |\hbox:n| (or |\hbox|) is necessary here. % \begin{macrocode} \skip_vertical:n { -\l_tmpa_dim - \arrayrulewidth } \hbox { \bool_if:NTF \l_@@_tabular_bool { \skip_horizontal:N -\tabcolsep } { \skip_horizontal:N -\arraycolsep } \@@_use_arraybox_with_notes_c: \bool_if:NTF \l_@@_tabular_bool { \skip_horizontal:N -\tabcolsep } { \skip_horizontal:N -\arraycolsep } } % \end{macrocode} % We take into account the ``last row'' (we have previously computed its total % height in |\l_tmpb_dim|). % \begin{macrocode} \skip_vertical:N -\l_tmpb_dim \skip_vertical:N \arrayrulewidth } \exp_after:wN \right \g_@@_right_delim_tl \c_math_toggle_token } % \end{macrocode} % Now, the box |\l_tmpa_box| is created with the correct delimiters. % % \smallskip % We will put the box in the TeX flow. However, we have a small work to do % when the option |delimiters/max-width| is used. % \begin{macrocode} \bool_if:NTF \l_@@_delimiters_max_width_bool { \@@_put_box_in_flow_bis:nn \g_@@_left_delim_tl \g_@@_right_delim_tl } \@@_put_box_in_flow: } % \end{macrocode} % % We take into account a potential ``last column'' (this ``last column'' has % been constructed in an overlapping position and we have computed its width in % |\g_@@_width_last_col_dim|: see p.~\pageref{overlap-right}). % \begin{macrocode} \bool_if:NT \g_@@_last_col_found_bool { \skip_horizontal:N \g_@@_width_last_col_dim } \bool_if:NT \l_@@_preamble_bool { \int_compare:nNnT \c@jCol < \g_@@_static_num_of_col_int { \@@_warning_gredirect_none:n { columns~not~used } } } \@@_after_array: % \end{macrocode} % The aim of the following |\egroup| (the corresponding |\bgroup| is, of course, % at the beginning of the environment) is to be able to put an exposant to a matrix in % a mathematical formula. % \begin{macrocode} \egroup % \end{macrocode} % % \bigskip % We write on the |aux| file all the informations corresponding to the % current environment. % \begin{macrocode} \iow_now:Nn \@mainaux { \ExplSyntaxOn } \iow_now:Nn \@mainaux { \char_set_catcode_space:n { 32 } } \iow_now:Nx \@mainaux { \tl_gset:cn { c_@@_ \int_use:N \g_@@_env_int _ tl } { \exp_not:o \g_@@_aux_tl } } \iow_now:Nn \@mainaux { \ExplSyntaxOff } % \end{macrocode} % % \bigskip % \begin{macrocode} \bool_if:NT \g_@@_footnote_bool \endsavenotes } % \end{macrocode} % This is the end of the environment |{NiceArrayWithDelims}|. % % \vspace{1cm} % \section{We construct the preamble of the array} % % \bigskip % The final user provides a preamble, but we must convert that preamble into a % preamble that will be given to |{array}| (of the package \pkg{array}). % % \bigskip % The preamble given by the final user is stored in |\g_@@_user_preamble_tl|. % The modified version will be stored in |\g_@@_array_preamble_tl| also. % \begin{macrocode} \cs_new_protected:Npn \@@_transform_preamble: { \@@_transform_preamble_i: \@@_transform_preamble_ii: } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_transform_preamble_i: { \int_gzero:N \c@jCol % \end{macrocode} % The sequence |\g_@@_cols_vlsim_seq| will contain the numbers of the columns % where you will to have to draw vertical lines in the potential sub-matrices % (hence the name |vlism|). % \begin{macrocode} \seq_gclear:N \g_@@_cols_vlism_seq % \end{macrocode} % |\g_tmpb_bool| will be raised if you have a \verb+|+ at the end of the % preamble provided by the final user. % \begin{macrocode} \bool_gset_false:N \g_tmpb_bool % \end{macrocode} % % The following sequence will store the arguments of the successive |>| in the % preamble. % \begin{macrocode} \tl_gclear_new:N \g_@@_pre_cell_tl % \end{macrocode} % The counter |\l_tmpa_int| will count the number of consecutive occurrences % of the symbol \verb+|+. % \begin{macrocode} \int_zero:N \l_tmpa_int \tl_gclear:N \g_@@_array_preamble_tl \tl_if_eq:NNTF \l_@@_vlines_clist \c_@@_all_tl { \tl_gset:Nn \g_@@_array_preamble_tl { ! { \skip_horizontal:N \arrayrulewidth } } } { \clist_if_in:NnT \l_@@_vlines_clist 1 { \tl_gset:Nn \g_@@_array_preamble_tl { ! { \skip_horizontal:N \arrayrulewidth } } } } % \end{macrocode} % % \bigskip % Now, we actually make the preamble (which will be given to |{array}|). It will % be stored in |\g_@@_array_preamble_tl|. % \begin{macrocode} \exp_last_unbraced:NV \@@_rec_preamble:n \g_@@_user_preamble_tl \stop \int_gset_eq:NN \g_@@_static_num_of_col_int \c@jCol % \end{macrocode} % % \medskip % \begin{macrocode} \@@_replace_columncolor: } % \end{macrocode} % % \bigskip % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { colortbl } { \regex_const:Nn \c_@@_columncolor_regex { \c { columncolor } } \cs_new_protected:Npn \@@_replace_columncolor: { \regex_replace_all:NnN \c_@@_columncolor_regex { \c { @@_columncolor_preamble } } \g_@@_array_preamble_tl } } { \cs_new_protected:Npn \@@_replace_columncolor: { \cs_set_eq:NN \columncolor \@@_columncolor_preamble } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_transform_preamble_ii: { % \end{macrocode} % % \medskip % If there were delimiters at the beginning or at the end of the preamble, the % environment |{NiceArray}| is transformed into an environment |{xNiceMatrix}|. % \begin{macrocode} \tl_if_eq:NNTF \g_@@_left_delim_tl \c_@@_dot_tl { \tl_if_eq:NNF \g_@@_right_delim_tl \c_@@_dot_tl { \bool_gset_true:N \g_@@_delims_bool } } { \bool_gset_true:N \g_@@_delims_bool } % \end{macrocode} % % \medskip % We want to remind whether there is a specifier \verb+|+ at the end of the preamble. % \begin{macrocode} \bool_if:NT \g_tmpb_bool { \bool_set_true:N \l_@@_bar_at_end_of_pream_bool } % \end{macrocode} % % \bigskip % We complete the preamble with the potential ``exterior columns'' (on both sides). % \begin{macrocode} \int_if_zero:nTF \l_@@_first_col_int { \tl_gput_left:No \g_@@_array_preamble_tl \c_@@_preamble_first_col_tl } { \bool_if:NF \g_@@_delims_bool { \bool_if:NF \l_@@_tabular_bool { \tl_if_empty:NT \l_@@_vlines_clist { \bool_if:NF \l_@@_exterior_arraycolsep_bool { \tl_gput_left:Nn \g_@@_array_preamble_tl { @ { } } } } } } } \int_compare:nNnTF \l_@@_last_col_int > { -1 } { \tl_gput_right:No \g_@@_array_preamble_tl \c_@@_preamble_last_col_tl } { \bool_if:NF \g_@@_delims_bool { \bool_if:NF \l_@@_tabular_bool { \tl_if_empty:NT \l_@@_vlines_clist { \bool_if:NF \l_@@_exterior_arraycolsep_bool { \tl_gput_right:Nn \g_@@_array_preamble_tl { @ { } } } } } } } % \end{macrocode} % We add a last column to raise a good error message when the user puts more % columns than allowed by its preamble. However, for technical reasons, it's not % possible to do that in |{NiceTabular*}| (we control that with the value of % |\l_@@_tabular_width_dim|). % \begin{macrocode} \dim_compare:nNnT \l_@@_tabular_width_dim = \c_zero_dim { \tl_gput_right:Nn \g_@@_array_preamble_tl { > { \@@_error_too_much_cols: } l } } } % \end{macrocode} % % \bigskip % The preamble provided by the final user will be read by a finite % automata. The following function |\@@_rec_preamble:n| will read that preamble % (usually letter by letter) in a recursive way (hence the name of that function). % in the preamble. % \begin{macrocode} \cs_new_protected:Npn \@@_rec_preamble:n #1 { % \end{macrocode} % For the majority of the letters, we will trigger the corresponding action by % calling directly a function in the main hashtable of TeX (thanks to the % mechanism |\csname...\endcsname|. Be careful: all these functions take in as % first argument the letter (or token) itself.\footnote{We do that because it's % an easy way to insert the letter at some places in the code that we will add to % |\g_@@_array_preamble_tl|.} % \begin{macrocode} \cs_if_exist:cTF { @@ _ \token_to_str:N #1 } { \use:c { @@ _ \token_to_str:N #1 } { #1 } } { % \end{macrocode} % Now, the columns defined by |\newcolumntype| of \pkg{array}. % \begin{macrocode} \cs_if_exist:cTF { NC @ find @ #1 } { \tl_set_eq:Nc \l_tmpb_tl { NC @ rewrite @ #1 } \exp_last_unbraced:NV \@@_rec_preamble:n \l_tmpb_tl } { \tl_if_eq:nnT { #1 } { S } { \@@_fatal:n { unknown~column~type~S } } { \@@_fatal:nn { unknown~column~type } { #1 } } } } } % \end{macrocode} % % % % \bigskip % For |c|, |l| and |r| % \begin{macrocode} \cs_new:Npn \@@_c #1 { \tl_gput_right:No \g_@@_array_preamble_tl \g_@@_pre_cell_tl \tl_gclear:N \g_@@_pre_cell_tl \tl_gput_right:Nn \g_@@_array_preamble_tl { > \@@_cell_begin:w c < \@@_cell_end: } % \end{macrocode} % % We increment the counter of columns and then we test for the presence of a |<|. % \begin{macrocode} \int_gincr:N \c@jCol \@@_rec_preamble_after_col:n } % \end{macrocode} % \begin{macrocode} \cs_new:Npn \@@_l #1 { \tl_gput_right:No \g_@@_array_preamble_tl \g_@@_pre_cell_tl \tl_gclear:N \g_@@_pre_cell_tl \tl_gput_right:Nn \g_@@_array_preamble_tl { > { \@@_cell_begin:w \tl_set_eq:NN \l_@@_hpos_cell_tl \c_@@_l_tl } l < \@@_cell_end: } \int_gincr:N \c@jCol \@@_rec_preamble_after_col:n } % \end{macrocode} % \begin{macrocode} \cs_new:Npn \@@_r #1 { \tl_gput_right:No \g_@@_array_preamble_tl \g_@@_pre_cell_tl \tl_gclear:N \g_@@_pre_cell_tl \tl_gput_right:Nn \g_@@_array_preamble_tl { > { \@@_cell_begin:w \tl_set_eq:NN \l_@@_hpos_cell_tl \c_@@_r_tl } r < \@@_cell_end: } \int_gincr:N \c@jCol \@@_rec_preamble_after_col:n } % \end{macrocode} % % \medskip % For |!| and |@| % \begin{macrocode} \cs_new:cpn { @@ _ \token_to_str:N ! } #1 #2 { \tl_gput_right:Nn \g_@@_array_preamble_tl { #1 { #2 } } \@@_rec_preamble:n } \cs_set_eq:cc { @@ _ \token_to_str:N @ } { @@ _ \token_to_str:N ! } % \end{macrocode} % % % \medskip % For \verb+|+ % \begin{macrocode} \cs_new:cpn { @@ _ | } #1 { % \end{macrocode} % |\l_tmpa_int| is the number of successive occurrences of \verb+|+ % \begin{macrocode} \int_incr:N \l_tmpa_int \@@_make_preamble_i_i:n } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_i_i:n #1 { \str_if_eq:nnTF { #1 } | { \use:c { @@ _ | } | } { \@@_make_preamble_i_ii:nn { } #1 } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_i_ii:nn #1 #2 { \str_if_eq:nnTF { #2 } [ { \@@_make_preamble_i_ii:nw { #1 } [ } { \@@_make_preamble_i_iii:nn { #2 } { #1 } } } \cs_new_protected:Npn \@@_make_preamble_i_ii:nw #1 [ #2 ] { \@@_make_preamble_i_ii:nn { #1 , #2 } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_i_iii:nn #1 #2 { \@@_compute_rule_width:n { multiplicity = \l_tmpa_int , #2 } \tl_gput_right:Nx \g_@@_array_preamble_tl { % \end{macrocode} % Here, the command |\dim_eval:n| is mandatory. % \begin{macrocode} \exp_not:N ! { \skip_horizontal:n { \dim_eval:n { \l_@@_rule_width_dim } } } } \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_vline:n { position = \int_eval:n { \c@jCol + 1 } , multiplicity = \int_use:N \l_tmpa_int , total-width = \dim_use:N \l_@@_rule_width_dim , #2 } % \end{macrocode} % We don't have provided value for |start| nor for |end|, which means that the % rule will cover (potentially) all the rows of the array. % % \begin{macrocode} } \int_zero:N \l_tmpa_int \str_if_eq:nnT { #1 } { \stop } { \bool_gset_true:N \g_tmpb_bool } \@@_rec_preamble:n #1 } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new:cpn { @@ _ > } #1 #2 { \tl_gput_right:Nn \g_@@_pre_cell_tl { > { #2 } } \@@_rec_preamble:n } % \end{macrocode} % % \begin{macrocode} \bool_new:N \l_@@_bar_at_end_of_pream_bool % \end{macrocode} % % \bigskip % The specifier |p| (and also the specifiers |m|, |b|, |V| and |X|) have an % optional argument between square brackets for a list of % \emph{key}-\emph{value} pairs. Here are the corresponding keys. % \begin{macrocode} \keys_define:nn { WithArrows / p-column } { r .code:n = \str_set_eq:NN \l_@@_hpos_col_str \c_@@_r_str , r .value_forbidden:n = true , c .code:n = \str_set_eq:NN \l_@@_hpos_col_str \c_@@_c_str , c .value_forbidden:n = true , l .code:n = \str_set_eq:NN \l_@@_hpos_col_str \c_@@_l_str , l .value_forbidden:n = true , R .code:n = \IfPackageLoadedTF { ragged2e } { \str_set_eq:NN \l_@@_hpos_col_str \c_@@_R_str } { \@@_error_or_warning:n { ragged2e~not~loaded } \str_set_eq:NN \l_@@_hpos_col_str \c_@@_r_str } , R .value_forbidden:n = true , L .code:n = \IfPackageLoadedTF { ragged2e } { \str_set_eq:NN \l_@@_hpos_col_str \c_@@_L_stsr } { \@@_error_or_warning:n { ragged2e~not~loaded } \str_set_eq:NN \l_@@_hpos_col_str \c_@@_l_str } , L .value_forbidden:n = true , C .code:n = \IfPackageLoadedTF { ragged2e } { \str_set_eq:NN \l_@@_hpos_col_str \c_@@_C_str } { \@@_error_or_warning:n { ragged2e~not~loaded } \str_set_eq:NN \l_@@_hpos_col_str \c_@@_c_str } , C .value_forbidden:n = true , S .code:n = \str_set_eq:NN \l_@@_hpos_col_str \c_@@_si_str , S .value_forbidden:n = true , p .code:n = \str_set:Nn \l_@@_vpos_col_str { p } , p .value_forbidden:n = true , t .meta:n = p , m .code:n = \str_set:Nn \l_@@_vpos_col_str { m } , m .value_forbidden:n = true , b .code:n = \str_set:Nn \l_@@_vpos_col_str { b } , b .value_forbidden:n = true , } % \end{macrocode} % % % \medskip % For |p|, |b| and |m|. % \begin{macrocode} \cs_new:Npn \@@_p #1 { \str_set:Nn \l_@@_vpos_col_str { #1 } % \end{macrocode} % Now, you look for a potential character |[| after the letter of the specifier % (for the options). % \begin{macrocode} \@@_make_preamble_ii_i:n } \cs_set_eq:NN \@@_b \@@_p \cs_set_eq:NN \@@_m \@@_p % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_ii_i:n #1 { \str_if_eq:nnTF { #1 } { [ } { \@@_make_preamble_ii_ii:w [ } { \@@_make_preamble_ii_ii:w [ ] { #1 } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_ii_ii:w [ #1 ] { \@@_make_preamble_ii_iii:nn { #1 } } % \end{macrocode} % % \medskip % |#1| is the optional argument of the specifier (a list of % \emph{key}-\emph{value} pairs). % % |#2| is the mandatory argument of the specifier: the width of the column. % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_ii_iii:nn #1 #2 { % \end{macrocode} % The possible values of |\l_@@_hpos_col_str| are |j| (for \emph{justified} which is % the initial value), |l|, |c|, |r|, |L|, |C| and |R| (when the user has used % the corresponding key in the optional argument of the specifier). % \begin{macrocode} \str_set_eq:NN \l_@@_hpos_col_str \c_@@_j_str \@@_keys_p_column:n { #1 } \@@_make_preamble_ii_iv:nnn { #2 } { minipage } { } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_keys_p_column:n #1 { \keys_set_known:nnN { WithArrows / p-column } { #1 } \l_tmpa_tl } % \end{macrocode} % % \medskip % The first argument is the width of the column. The second is the type of % environment: |minipage| or |varwidth|. The third is some code added at the % beginning of the cell. % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_ii_iv:nnn #1 #2 #3 { \use:e { \@@_make_preamble_ii_v:nnnnnnnn { \str_if_eq:onTF \l_@@_vpos_col_str { p } { t } { b } } { \dim_eval:n { #1 } } { % \end{macrocode} % The parameter |\l_@@_hpos_col_str| (as |\l_@@_vpos_col_str|) exists only % during the construction of the preamble. During the composition of the array % itself, you will have, in each cell, the parameter |\l_@@_hpos_cell_tl| which % will provide the horizontal alignment of the column to which belongs the cell. % \begin{macrocode} \str_if_eq:NNTF \l_@@_hpos_col_str \c_@@_j_str { \tl_clear:N \exp_not:N \l_@@_hpos_cell_tl } { \cs_set_nopar:Npn \exp_not:N \l_@@_hpos_cell_tl { \str_lowercase:V \l_@@_hpos_col_str } } \str_case:on \l_@@_hpos_col_str { c { \exp_not:N \centering } l { \exp_not:N \raggedright } r { \exp_not:N \raggedleft } C { \exp_not:N \Centering } L { \exp_not:N \RaggedRight } R { \exp_not:N \RaggedLeft } } #3 } { \str_if_eq:onT \l_@@_vpos_col_str { m } \@@_center_cell_box: } { \str_if_eq:onT \l_@@_hpos_col_str { si } \siunitx_cell_begin:w } { \str_if_eq:onT \l_@@_hpos_col_str { si } \siunitx_cell_end: } { #2 } { \str_case:onF \l_@@_hpos_col_str { { j } { c } { si } { c } } % \end{macrocode} % We use |\str_lowercase:n| to convert |R| to |r|, etc. % \begin{macrocode} { \str_lowercase:V \l_@@_hpos_col_str } } } % \end{macrocode} % % We increment the counter of columns, and then we test for the presence of a |<|. % \begin{macrocode} \int_gincr:N \c@jCol \@@_rec_preamble_after_col:n } % \end{macrocode} % % \medskip % |#1| is the optional argument of |{minipage}| (or |{varwidth}|): |t| or |b|. % Indeed, for the columns of type |m|, we use the value |b| here because there % is a special post-action in order to center vertically the box (see |#4|). % % |#2| is the width of the |{minipage}| (or |{varwidth}|), that is to say also % the width of the column. % % |#3| is the coding for the horizontal position of the content of the cell % (|\centering|, |\raggedright|, |\raggedleft| or nothing). It's also possible % to put in that |#3| some code to fix the value of |\l_@@_hpos_cell_tl| which % will be available in each cell of the column. % % |#4| is an extra-code which contains |\@@_center_cell_box:| (when the column % is a |m| column) or nothing (in the other cases). % % |#5| is a code put just before the |c| (or |r| or |l|: see |#8|). % % |#6| is a code put just after the |c| (or |r| or |l|: see |#8|). % % |#7| is the type of environment: |minipage| or |varwidth|. % % |#8| is the letter |c| or |r| or |l| which is the basic specificier of column % which is used \emph{in fine}. % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_ii_v:nnnnnnnn #1 #2 #3 #4 #5 #6 #7 #8 { \tl_if_eq:NNTF \l_@@_hpos_col_str \c_@@_si_str { \tl_gput_right:Nn \g_@@_array_preamble_tl { > { \@@_test_if_empty_for_S: } } } { \tl_gput_right:Nn \g_@@_array_preamble_tl { > { \@@_test_if_empty: } } } \tl_gput_right:No \g_@@_array_preamble_tl \g_@@_pre_cell_tl \tl_gclear:N \g_@@_pre_cell_tl \tl_gput_right:Nn \g_@@_array_preamble_tl { > { % \end{macrocode} % The parameter |\l_@@_col_width_dim|, which is the width of the current column, % will be available in each cell of the column. It will be used by the % mono-column blocks. % \begin{macrocode} \dim_set:Nn \l_@@_col_width_dim { #2 } \@@_cell_begin:w % \end{macrocode} % We use the form |\minipage|--|\endminipage| (|\varwidth|--|\endvarwidth|) for % compatibility with \pkg{collcell} (2023-10-31). % \begin{macrocode} \use:c { #7 } [ #1 ] { #2 } % \end{macrocode} % The following lines have been taken from |array.sty|. % \begin{macrocode} \everypar { \vrule height \box_ht:N \@arstrutbox width \c_zero_dim \everypar { } } % \end{macrocode} % Now, the potential code for the horizontal position of the content of the cell % (|\centering|, |\raggedright|, |\RaggedRight|, etc.). % \begin{macrocode} #3 % \end{macrocode} % The following code is to allow something like |\centering| in |\RowStyle|. % \begin{macrocode} \g_@@_row_style_tl \arraybackslash #5 } #8 < { #6 % \end{macrocode} % The following line has been taken from |array.sty|. % \begin{macrocode} \@finalstrut \@arstrutbox \use:c { end #7 } % \end{macrocode} % If the letter in the preamble is |m|, |#4| will be equal to % |\@@_center_cell_box:| (see just below). % \begin{macrocode} #4 \@@_cell_end: } } } % \end{macrocode} % % \bigskip % % \begin{macrocode} \str_new:N \c_@@_ignorespaces_str \str_set:Nx \c_@@_ignorespaces_str { \ignorespaces } \str_remove_all:Nn \c_@@_ignorespaces_str { ~ } % \end{macrocode} % % \bigskip % In order to test whether a cell is empty, we test whether it begins by % |\ignorespaces\unskip|. However, in some circunstancies, for example when % |\collectcell| of \pkg{collcell} is used, the cell does not begin with % |\ignorespaces|. In that case, we consider as not empty... % % First, we test if the next token is |\ignorespaces| and it's not very easy... % \begin{macrocode} \cs_new_protected:Npn \@@_test_if_empty: { \peek_after:Nw \@@_test_if_empty_i: } \cs_new_protected:Npn \@@_test_if_empty_i: { \str_set:Nx \l_tmpa_str { \token_to_meaning:N \l_peek_token } \str_if_eq:NNT \l_tmpa_str \c_@@_ignorespaces_str { \@@_test_if_empty:w } } \cs_new_protected:Npn \@@_test_if_empty:w \ignorespaces { \peek_meaning:NT \unskip { \tl_gput_right:Nn \g_@@_cell_after_hook_tl { \box_set_wd:Nn \l_@@_cell_box \c_zero_dim \skip_horizontal:N \l_@@_col_width_dim } } } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_test_if_empty_for_S: { \peek_meaning:NT \__siunitx_table_skip:n { \tl_gput_right:Nn \g_@@_cell_after_hook_tl { \box_set_wd:Nn \l_@@_cell_box \c_zero_dim } } } % \end{macrocode} % % % \bigskip % The following command will be used in |m|-columns in order to center % vertically the box. In fact, despite its name, the command does not always % center the cell. Indeed, if there is only one row in the cell, it should not % be centered vertically. It's not possible to know the number of rows of the % cell. However, we consider (as in \pkg{array}) that if the height of the cell % is no more that the height of |\@arstrutbox|, there is only one row. % \begin{macrocode} \cs_new_protected:Npn \@@_center_cell_box: { % \end{macrocode} % By putting instructions in |\g_@@_cell_after_hook_tl|, we require a % post-action of the box |\l_@@_cell_box|. % \begin{macrocode} \tl_gput_right:Nn \g_@@_cell_after_hook_tl { \int_compare:nNnT { \box_ht:N \l_@@_cell_box } > % \end{macrocode} % Previously, we had |\@arstrutbox| and not |\strutbox| in the following line % but the code in \pkg{array} has changed in v 2.5g and we follow the change % (see \emph{array: Correctly identify single-line m-cells} in LaTeX~News~36). % \begin{macrocode} { \box_ht:N \strutbox } { \hbox_set:Nn \l_@@_cell_box { \box_move_down:nn { ( \box_ht:N \l_@@_cell_box - \box_ht:N \@arstrutbox + \baselineskip ) / 2 } { \box_use:N \l_@@_cell_box } } } } } % \end{macrocode} % % \medskip % For |V| (similar to the |V| of \pkg{varwidth}). % \begin{macrocode} \cs_new:Npn \@@_V #1 #2 { \str_if_eq:nnTF { #2 } { [ } { \@@_make_preamble_V_i:w [ } { \@@_make_preamble_V_i:w [ ] { #2 } } } \cs_new_protected:Npn \@@_make_preamble_V_i:w [ #1 ] { \@@_make_preamble_V_ii:nn { #1 } } \cs_new_protected:Npn \@@_make_preamble_V_ii:nn #1 #2 { \str_set:Nn \l_@@_vpos_col_str { p } \str_set_eq:NN \l_@@_hpos_col_str \c_@@_j_str \@@_keys_p_column:n { #1 } \IfPackageLoadedTF { varwidth } { \@@_make_preamble_ii_iv:nnn { #2 } { varwidth } { } } { \@@_error_or_warning:n { varwidth~not~loaded } \@@_make_preamble_ii_iv:nnn { #2 } { minipage } { } } } % \end{macrocode} % % \medskip % For |w| and |W| % \begin{macrocode} \cs_new:Npn \@@_w { \@@_make_preamble_w:nnnn { } } \cs_new:Npn \@@_W { \@@_make_preamble_w:nnnn { \@@_special_W: } } % \end{macrocode} % % |#1| is a special argument: empty for |w| and equal to |\@@_special_W:| for |W|; % % |#2| is the type of column (|w| or |W|); % % |#3| is the type of horizontal alignment (|c|, |l|, |r| or |s|); % % |#4| is the width of the column. % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_w:nnnn #1 #2 #3 #4 { \str_if_eq:nnTF { #3 } { s } { \@@_make_preamble_w_i:nnnn { #1 } { #4 } } { \@@_make_preamble_w_ii:nnnn { #1 } { #2 } { #3 } { #4 } } } % \end{macrocode} % % \bigskip % First, the case of an horizontal alignment equal to |s| (for \emph{stretch}). % % |#1| is a special argument: empty for |w| and equal to |\@@_special_W:| for % |W|; % % |#2| is the width of the column. % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_w_i:nnnn #1 #2 { \tl_gput_right:No \g_@@_array_preamble_tl \g_@@_pre_cell_tl \tl_gclear:N \g_@@_pre_cell_tl \tl_gput_right:Nn \g_@@_array_preamble_tl { > { \dim_set:Nn \l_@@_col_width_dim { #2 } \@@_cell_begin:w \tl_set_eq:NN \l_@@_hpos_cell_tl \c_@@_c_tl } c < { \@@_cell_end_for_w_s: #1 \@@_adjust_size_box: \box_use_drop:N \l_@@_cell_box } } \int_gincr:N \c@jCol \@@_rec_preamble_after_col:n } % \end{macrocode} % % \bigskip % Then, the most important version, for the horizontal alignments types of |c|, % |l| and |r| (and not |s|). % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_w_ii:nnnn #1 #2 #3 #4 { \tl_gput_right:No \g_@@_array_preamble_tl \g_@@_pre_cell_tl \tl_gclear:N \g_@@_pre_cell_tl \tl_gput_right:Nn \g_@@_array_preamble_tl { > { % \end{macrocode} % The parameter |\l_@@_col_width_dim|, which is the width of the current column, % will be available in each cell of the column. It will be used by the % mono-column blocks. % \begin{macrocode} \dim_set:Nn \l_@@_col_width_dim { #4 } \hbox_set:Nw \l_@@_cell_box \@@_cell_begin:w \cs_set_nopar:Npn \l_@@_hpos_cell_tl { #3 } } c < { \@@_cell_end: \hbox_set_end: #1 \@@_adjust_size_box: \makebox [ #4 ] [ #3 ] { \box_use_drop:N \l_@@_cell_box } } } % \end{macrocode} % We increment the counter of columns and then we test for the presence of a |<|. % \begin{macrocode} \int_gincr:N \c@jCol \@@_rec_preamble_after_col:n } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_special_W: { \dim_compare:nNnT { \box_wd:N \l_@@_cell_box } > \l_@@_col_width_dim { \@@_warning:n { W~warning } } } % \end{macrocode} % % \medskip % For |S| (of \pkg{siunitx}). % \begin{macrocode} \cs_new:Npn \@@_S #1 #2 { \str_if_eq:nnTF { #2 } { [ } { \@@_make_preamble_S:w [ } { \@@_make_preamble_S:w [ ] { #2 } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_S:w [ #1 ] { \@@_make_preamble_S_i:n { #1 } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_S_i:n #1 { \IfPackageLoadedTF { siunitx } { \tl_gput_right:No \g_@@_array_preamble_tl \g_@@_pre_cell_tl \tl_gclear:N \g_@@_pre_cell_tl \tl_gput_right:Nn \g_@@_array_preamble_tl { > { \@@_cell_begin:w \keys_set:nn { siunitx } { #1 } \siunitx_cell_begin:w } c < { \siunitx_cell_end: \@@_cell_end: } } % \end{macrocode} % We increment the counter of columns and then we test for the presence of a |<|. % \begin{macrocode} \int_gincr:N \c@jCol \@@_rec_preamble_after_col:n } { \@@_fatal:n { siunitx~not~loaded } } } % \end{macrocode} % % % \medskip % For |(|, |[| and |\{|. % \begin{macrocode} \cs_new:cpn { @@ _ \token_to_str:N ( } #1 #2 { \bool_if:NT \l_@@_small_bool { \@@_fatal:n { Delimiter~with~small } } % \end{macrocode} % If we are before the column 1 and not in |{NiceArray}|, we reserve space for % the left delimiter. % \begin{macrocode} \int_if_zero:nTF \c@jCol { \tl_if_eq:NNTF \g_@@_left_delim_tl \c_@@_dot_tl { % \end{macrocode} % In that case, in fact, the first letter of the preamble must be considered as % the left delimiter of the array. % \begin{macrocode} \tl_gset:Nn \g_@@_left_delim_tl { #1 } \tl_gset_eq:NN \g_@@_right_delim_tl \c_@@_dot_tl \@@_rec_preamble:n #2 } { \tl_gput_right:Nn \g_@@_array_preamble_tl { ! { \enskip } } \@@_make_preamble_iv:nn { #1 } { #2 } } } { \@@_make_preamble_iv:nn { #1 } { #2 } } } \cs_set_eq:cc { @@ _ \token_to_str:N [ } { @@ _ \token_to_str:N ( } \cs_set_eq:cc { @@ _ \token_to_str:N \{ } { @@ _ \token_to_str:N ( } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_iv:nn #1 #2 { \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_delimiter:nnn #1 { \int_eval:n { \c@jCol + 1 } } \c_true_bool } \tl_if_in:nnTF { ( [ \{ ) ] \} \left \right } { #2 } { \@@_error:nn { delimiter~after~opening } { #2 } \@@_rec_preamble:n } { \@@_rec_preamble:n #2 } } % \end{macrocode} % % In fact, if would be possible to define |\left| and |\right| as no-op. % \begin{macrocode} \cs_new:cpn { @@ _ \token_to_str:N \left } #1 { \use:c { @@ _ \token_to_str:N ( } } % \end{macrocode} % % \bigskip % For the closing delimiters. We have two arguments for the following command because % we directly read the following letter in the preamble (we have to see whether % we have a opening delimiter following and we also have to see whether we are % at the end of the preamble because, in that case, our letter must be % considered as the right delimiter of the environment if the environment is % |{NiceArray}|). % \begin{macrocode} \cs_new:cpn { @@ _ \token_to_str:N ) } #1 #2 { \bool_if:NT \l_@@_small_bool { \@@_fatal:n { Delimiter~with~small } } \tl_if_in:nnTF { ) ] \} } { #2 } { \@@_make_preamble_v:nnn #1 #2 } { \tl_if_eq:nnTF { \stop } { #2 } { \tl_if_eq:NNTF \g_@@_right_delim_tl \c_@@_dot_tl { \tl_gset:Nn \g_@@_right_delim_tl { #1 } } { \tl_gput_right:Nn \g_@@_array_preamble_tl { ! { \enskip } } \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_delimiter:nnn #1 { \int_use:N \c@jCol } \c_false_bool } \@@_rec_preamble:n #2 } } { \tl_if_in:nnT { ( [ \{ \left } { #2 } { \tl_gput_right:Nn \g_@@_array_preamble_tl { ! { \enskip } } } \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_delimiter:nnn #1 { \int_use:N \c@jCol } \c_false_bool } \@@_rec_preamble:n #2 } } } \cs_set_eq:cc { @@ _ \token_to_str:N ] } { @@ _ \token_to_str:N ) } \cs_set_eq:cc { @@ _ \token_to_str:N \} } { @@ _ \token_to_str:N ) } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_v:nnn #1 #2 #3 { \tl_if_eq:nnTF { \stop } { #3 } { \tl_if_eq:NNTF \g_@@_right_delim_tl \c_@@_dot_tl { \tl_gput_right:Nn \g_@@_array_preamble_tl { ! { \enskip } } \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_delimiter:nnn #1 { \int_use:N \c@jCol } \c_false_bool } \tl_gset:Nn \g_@@_right_delim_tl { #2 } } { \tl_gput_right:Nn \g_@@_array_preamble_tl { ! { \enskip } } \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_delimiter:nnn #1 { \int_use:N \c@jCol } \c_false_bool } \@@_error:nn { double~closing~delimiter } { #2 } } } { \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_delimiter:nnn #1 { \int_use:N \c@jCol } \c_false_bool } \@@_error:nn { double~closing~delimiter } { #2 } \@@_rec_preamble:n #3 } } % \end{macrocode} % % \medskip % \begin{macrocode} \cs_new:cpn { @@ _ \token_to_str:N \right } #1 { \use:c { @@ _ \token_to_str:N ) } } % \end{macrocode} % % % \bigskip % After a specifier of column, we have to test whether there is one or several % |<{..}| because, after those potential |<{...}|, we have to insert % |!{\skip_horizontal:N ...}| when the key |vlines| is used. In fact, we have % also to test whether there is, after the |<{...}|, a |@{...}|. % \begin{macrocode} \cs_new_protected:Npn \@@_rec_preamble_after_col:n #1 { \str_if_eq:nnTF { #1 } { < } \@@_rec_preamble_after_col_i:n { \str_if_eq:nnTF { #1 } { @ } \@@_rec_preamble_after_col_ii:n { \tl_if_eq:NNTF \l_@@_vlines_clist \c_@@_all_tl { \tl_gput_right:Nn \g_@@_array_preamble_tl { ! { \skip_horizontal:N \arrayrulewidth } } } { \exp_args:NNe \clist_if_in:NnT \l_@@_vlines_clist { \int_eval:n { \c@jCol + 1 } } { \tl_gput_right:Nn \g_@@_array_preamble_tl { ! { \skip_horizontal:N \arrayrulewidth } } } } \@@_rec_preamble:n { #1 } } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_rec_preamble_after_col_i:n #1 { \tl_gput_right:Nn \g_@@_array_preamble_tl { < { #1 } } \@@_rec_preamble_after_col:n } % \end{macrocode} % % We have to catch a |@{...}| after a specifier of column because, if we have to % draw a vertical rule, we have to add in that |@{...}| a |\hskip| corresponding % to the width of the vertical rule. % \begin{macrocode} \cs_new_protected:Npn \@@_rec_preamble_after_col_ii:n #1 { \tl_if_eq:NNTF \l_@@_vlines_clist \c_@@_all_tl { \tl_gput_right:Nn \g_@@_array_preamble_tl { @ { #1 \skip_horizontal:N \arrayrulewidth } } } { \exp_args:NNe \clist_if_in:NnTF \l_@@_vlines_clist { \int_eval:n { \c@jCol + 1 } } { \tl_gput_right:Nn \g_@@_array_preamble_tl { @ { #1 \skip_horizontal:N \arrayrulewidth } } } { \tl_gput_right:Nn \g_@@_array_preamble_tl { @ { #1 } } } } \@@_rec_preamble:n } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new:cpn { @@ _ * } #1 #2 #3 { \tl_clear:N \l_tmpa_tl \int_step_inline:nn { #2 } { \tl_put_right:Nn \l_tmpa_tl { #3 } } \exp_last_unbraced:No \@@_rec_preamble:n \l_tmpa_tl } % \end{macrocode} % % \bigskip % The token |\NC@find| is at the head of the definition of the columns type done % by |\newcolumntype|. We wan't that token to be no-op here. % \begin{macrocode} \cs_new:cpn { @@ _ \token_to_str:N \NC@find } #1 { \@@_rec_preamble:n } % \end{macrocode} % % \bigskip % For the case of a letter |X|. This specifier may take in an optional argument % (between square brackets). That's why we test whether there is a |[| after the % letter |X|. % \begin{macrocode} \cs_new:Npn \@@_X #1 #2 { \str_if_eq:nnTF { #2 } { [ } { \@@_make_preamble_X:w [ } { \@@_make_preamble_X:w [ ] #2 } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_X:w [ #1 ] { \@@_make_preamble_X_i:n { #1 } } % \end{macrocode} % |#1| is the optional argument of the |X| specifier (a list of % \emph{key}-\emph{value} pairs). % % \medskip % The following set of keys is for the specifier |X| in the preamble of the % array. Such specifier may have as keys all the keys of % |{ WithArrows / p-column }| but also a key as 1, 2, 3, etc. The following set % of keys will be used to retrieve that value (in the counter |\l_@@_weight_int|). % \begin{macrocode} \keys_define:nn { WithArrows / X-column } { unknown .code:n = \int_set:Nn \l_@@_weight_int { \l_keys_key_str } } % \end{macrocode} % % % \medskip % In the following command, |#1| is the list of the options of the specifier |X|. % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_X_i:n #1 { % \end{macrocode} % The possible values of |\l_@@_hpos_col_str| are |j| (for \emph{justified} which is % the initial value), |l|, |c| and |r| (when the user has used the corresponding % key in the optional argument of the specifier |X|). % \begin{macrocode} \str_set:Nn \l_@@_hpos_col_str { j } % \end{macrocode} % The possible values of |\l_@@_vpos_col_str| are |p| (the initial value), |m| and |b| % (when the user has used the corresponding key in the optional argument of the % specifier |X|). % \begin{macrocode} \str_set:Nn \l_@@_vpos_col_str { p } % \end{macrocode} % % The integer |\l_@@_weight_int| will be the weight of the |X| column (the % initial value is $1$). The user may specify a different value (such as $2$, % $3$, etc.) by putting that value in the optional argument of the specifier. % The weights of the |X| columns are used in the computation of the actual width % of those columns as in \pkg{tabu} (now obsolete) or \pkg{tabularray}. % \begin{macrocode} \int_zero_new:N \l_@@_weight_int \int_set_eq:NN \l_@@_weight_int \c_one_int \@@_keys_p_column:n { #1 } % \end{macrocode} % The unknown keys are put in |\l_tmpa_tl| % \begin{macrocode} \keys_set:no { WithArrows / X-column } \l_tmpa_tl \int_compare:nNnT \l_@@_weight_int < \c_zero_int { \@@_error_or_warning:n { negative~weight } \int_set:Nn \l_@@_weight_int { - \l_@@_weight_int } } \int_gadd:Nn \g_@@_total_X_weight_int \l_@@_weight_int % \end{macrocode} % % We test whether we know the width of the |X|-columns by reading the |aux| file % (after the first compilation, the width of the |X|-columns is computed and % written in the |aux| file). % \begin{macrocode} \bool_if:NTF \l_@@_X_columns_aux_bool { \exp_args:Nne \@@_make_preamble_ii_iv:nnn { \l_@@_weight_int \l_@@_X_columns_dim } { minipage } { \@@_no_update_width: } } { \tl_gput_right:Nn \g_@@_array_preamble_tl { > { \@@_cell_begin:w \bool_set_true:N \l_@@_X_bool % \end{macrocode} % You encounter a problem on 2023-03-04: for an environment with |X| columns, % during the first compilations (which are not the definitive one), sometimes, % some cells are declared empty even if they should not. That's a problem % because user's instructions may use these nodes. That's why we have added the % following |\NotEmpty|. % \begin{macrocode} \NotEmpty % \end{macrocode} % The following code will nullify the box of the cell. % \begin{macrocode} \tl_gput_right:Nn \g_@@_cell_after_hook_tl { \hbox_set:Nn \l_@@_cell_box { } } % \end{macrocode} % We put a |{minipage}| to give to the user the ability to put a command such as % |\centering| in the |\RowStyle|. % \begin{macrocode} \begin { minipage } { 5 cm } \arraybackslash } c < { \end { minipage } \@@_cell_end: } } \int_gincr:N \c@jCol \@@_rec_preamble_after_col:n } } % \end{macrocode} % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_no_update_width: { \tl_gput_right:Nn \g_@@_cell_after_hook_tl { \cs_set_eq:NN \@@_update_max_cell_width: \prg_do_nothing: } } % \end{macrocode} % % \medskip % For the letter set by the user with |vlines-in-sub-matrix| (vlism). % \begin{macrocode} \cs_new_protected:Npn \@@_make_preamble_vlism:n #1 { \seq_gput_right:Nx \g_@@_cols_vlism_seq { \int_eval:n { \c@jCol + 1 } } \tl_gput_right:Nx \g_@@_array_preamble_tl { \exp_not:N ! { \skip_horizontal:N \arrayrulewidth } } \@@_rec_preamble:n } % \end{macrocode} % % \medskip % The token |\stop| is a marker that we have inserted to mark the end of the % preamble (as provided by the final user) that we have inserted in the TeX flow. % \begin{macrocode} \cs_set_eq:cN { @@ _ \token_to_str:N \stop } \use_none:n % \end{macrocode} % % \medskip % The following lines try to catch some errors (when the final user has % forgotten the preamble of its environment). % \begin{macrocode} \cs_new_protected:cpn { @@ _ \token_to_str:N \hline } { \@@_fatal:n { Preamble~forgotten } } \cs_set_eq:cc { @@ _ \token_to_str:N \Hline } { @@ _ \token_to_str:N \hline } \cs_set_eq:cc { @@ _ \token_to_str:N \toprule } { @@ _ \token_to_str:N \hline } \cs_set_eq:cc { @@ _ \token_to_str:N \CodeBefore } { @@ _ \token_to_str:N \hline } % \end{macrocode} % % \bigskip % \section{The redefinition of \textbackslash multicolumn} % % \medskip % The following command must \emph{not} be protected since it begins with % |\multispan| (a TeX primitive). % \begin{macrocode} \cs_new:Npn \@@_multicolumn:nnn #1 #2 #3 { % \end{macrocode} % The following lines are from the definition of |\multicolumn| in \pkg{array} % (and \emph{not} in standard LaTeX). The first line aims to raise an error if % the user has put more that one column specifier in the preamble of % |\multicolumn|. % \begin{macrocode} \multispan { #1 } \cs_set_eq:NN \@@_update_max_cell_width: \prg_do_nothing: % added 2023-10-04 \begingroup \cs_set:Npn \@addamp { \legacy_if:nTF { @firstamp } { \@firstampfalse } { \@preamerr 5 } } % \end{macrocode} % % \medskip % Now, we patch the (small) preamble as we have done with the main preamble of % the array. % \begin{macrocode} \tl_gclear:N \g_@@_preamble_tl \@@_make_m_preamble:n #2 \q_stop % \end{macrocode} % % \medskip % The following lines are an adaptation of the definition of |\multicolumn| in % \pkg{array}. % \begin{macrocode} \exp_args:No \@mkpream \g_@@_preamble_tl \@addtopreamble \@empty \endgroup % \end{macrocode} % % \medskip % Now, we do a treatment specific to \pkg{nicematrix} which has no equivalent % in the original definition of |\multicolumn|. % \begin{macrocode} \int_compare:nNnT { #1 } > \c_one_int { \seq_gput_left:Nx \g_@@_multicolumn_cells_seq { \int_use:N \c@iRow - \int_eval:n { \c@jCol + 1 } } \seq_gput_left:Nn \g_@@_multicolumn_sizes_seq { #1 } \seq_gput_right:Nx \g_@@_pos_of_blocks_seq { { \int_if_zero:nTF \c@jCol { \int_eval:n { \c@iRow + 1 } } { \int_use:N \c@iRow } } { \int_eval:n { \c@jCol + 1 } } { \int_if_zero:nTF \c@jCol { \int_eval:n { \c@iRow + 1 } } { \int_use:N \c@iRow } } { \int_eval:n { \c@jCol + #1 } } { } % for the name of the block } } % \end{macrocode} % % \medskip % The following lines were in the original definition of |\multicolumn|. % \begin{macrocode} \cs_set:Npn \@sharp { #3 } \@arstrut \@preamble \null % \end{macrocode} % % \medskip % We add some lines. % \begin{macrocode} \int_gadd:Nn \c@jCol { #1 - 1 } \int_compare:nNnT \c@jCol > \g_@@_col_total_int { \int_gset_eq:NN \g_@@_col_total_int \c@jCol } \ignorespaces } % \end{macrocode} % % \bigskip % The following commands will patch the (small) preamble of the |\multicolumn|. % All those commands have a |m| in their name to recall that they deal with the % redefinition of |\multicolumn|. % \begin{macrocode} \cs_new_protected:Npn \@@_make_m_preamble:n #1 { \str_case:nnF { #1 } { c { \@@_make_m_preamble_i:n #1 } l { \@@_make_m_preamble_i:n #1 } r { \@@_make_m_preamble_i:n #1 } > { \@@_make_m_preamble_ii:nn #1 } ! { \@@_make_m_preamble_ii:nn #1 } @ { \@@_make_m_preamble_ii:nn #1 } | { \@@_make_m_preamble_iii:n #1 } p { \@@_make_m_preamble_iv:nnn t #1 } m { \@@_make_m_preamble_iv:nnn c #1 } b { \@@_make_m_preamble_iv:nnn b #1 } w { \@@_make_m_preamble_v:nnnn { } #1 } W { \@@_make_m_preamble_v:nnnn { \@@_special_W: } #1 } \q_stop { } } { \cs_if_exist:cTF { NC @ find @ #1 } { \tl_set_eq:Nc \l_tmpa_tl { NC @ rewrite @ #1 } \exp_last_unbraced:No \@@_make_m_preamble:n \l_tmpa_tl } { \tl_if_eq:nnT { #1 } { S } { \@@_fatal:n { unknown~column~type~S } } { \@@_fatal:nn { unknown~column~type } { #1 } } } } } % \end{macrocode} % % \medskip % For |c|, |l| and |r| % \begin{macrocode} \cs_new_protected:Npn \@@_make_m_preamble_i:n #1 { \tl_gput_right:Nn \g_@@_preamble_tl { > { \@@_cell_begin:w \cs_set_nopar:Npn \l_@@_hpos_cell_tl { #1 } } #1 < \@@_cell_end: } % \end{macrocode} % % We test for the presence of a |<|. % \begin{macrocode} \@@_make_m_preamble_x:n } % \end{macrocode} % % \medskip % For |>|, |!| and |@| % \begin{macrocode} \cs_new_protected:Npn \@@_make_m_preamble_ii:nn #1 #2 { \tl_gput_right:Nn \g_@@_preamble_tl { #1 { #2 } } \@@_make_m_preamble:n } % \end{macrocode} % % % \medskip % For \verb+|+ % \begin{macrocode} \cs_new_protected:Npn \@@_make_m_preamble_iii:n #1 { \tl_gput_right:Nn \g_@@_preamble_tl { #1 } \@@_make_m_preamble:n } % \end{macrocode} % % \medskip % For |p|, |m| and |b| % \begin{macrocode} \cs_new_protected:Npn \@@_make_m_preamble_iv:nnn #1 #2 #3 { \tl_gput_right:Nn \g_@@_preamble_tl { > { \@@_cell_begin:w \begin { minipage } [ #1 ] { \dim_eval:n { #3 } } \mode_leave_vertical: \arraybackslash \vrule height \box_ht:N \@arstrutbox depth 0 pt width 0 pt } c < { \vrule height 0 pt depth \box_dp:N \@arstrutbox width 0 pt \end { minipage } \@@_cell_end: } } % \end{macrocode} % We test for the presence of a |<|. % \begin{macrocode} \@@_make_m_preamble_x:n } % \end{macrocode} % % \medskip % For |w| and |W| % \begin{macrocode} \cs_new_protected:Npn \@@_make_m_preamble_v:nnnn #1 #2 #3 #4 { \tl_gput_right:Nn \g_@@_preamble_tl { > { \dim_set:Nn \l_@@_col_width_dim { #4 } \hbox_set:Nw \l_@@_cell_box \@@_cell_begin:w \cs_set_nopar:Npn \l_@@_hpos_cell_tl { #3 } } c < { \@@_cell_end: \hbox_set_end: \bool_if:NT \g_@@_rotate_bool \@@_rotate_cell_box: #1 \@@_adjust_size_box: \makebox [ #4 ] [ #3 ] { \box_use_drop:N \l_@@_cell_box } } } % \end{macrocode} % We test for the presence of a |<|. % \begin{macrocode} \@@_make_m_preamble_x:n } % \end{macrocode} % % % After a specifier of column, we have to test whether there is one or several % |<{..}|. % \begin{macrocode} \cs_new_protected:Npn \@@_make_m_preamble_x:n #1 { \str_if_eq:nnTF { #1 } { < } \@@_make_m_preamble_ix:n { \@@_make_m_preamble:n { #1 } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_make_m_preamble_ix:n #1 { \tl_gput_right:Nn \g_@@_preamble_tl { < { #1 } } \@@_make_m_preamble_x:n } % \end{macrocode} % % % % \bigskip % The command |\@@_put_box_in_flow:| puts the box |\l_tmpa_box| (which contains % the array) in the flow. It is used for the environments with delimiters. % First, we have to modify the height and the depth to take back into account % the potential exterior rows (the total height of the first row has been % computed in |\l_tmpa_dim| and the total height of the potential last row in % |\l_tmpb_dim|). % \begin{macrocode} \cs_new_protected:Npn \@@_put_box_in_flow: { \box_set_ht:Nn \l_tmpa_box { \box_ht:N \l_tmpa_box + \l_tmpa_dim } \box_set_dp:Nn \l_tmpa_box { \box_dp:N \l_tmpa_box + \l_tmpb_dim } \tl_if_eq:NNTF \l_@@_baseline_tl \c_@@_c_tl { \box_use_drop:N \l_tmpa_box } \@@_put_box_in_flow_i: } % \end{macrocode} % % \bigskip % % \medskip % The command |\@@_put_box_in_flow_i:| is used when the value of % |\l_@@_baseline_tl| is different of |c| (which is the initial value and the % most used). % \begin{macrocode} \cs_new_protected:Npn \@@_put_box_in_flow_i: { \pgfpicture \@@_qpoint:n { row - 1 } \dim_gset_eq:NN \g_tmpa_dim \pgf@y \@@_qpoint:n { row - \int_eval:n { \c@iRow + 1 } } \dim_gadd:Nn \g_tmpa_dim \pgf@y \dim_gset:Nn \g_tmpa_dim { 0.5 \g_tmpa_dim } % \end{macrocode} % Now, |\g_tmpa_dim| contains the $y$-value of the center of the array (the % delimiters are centered in relation with this value). % \begin{macrocode} \tl_if_in:NnTF \l_@@_baseline_tl { line- } { \int_set:Nn \l_tmpa_int { \str_range:Nnn \l_@@_baseline_tl 6 { \tl_count:o \l_@@_baseline_tl } } \@@_qpoint:n { row - \int_use:N \l_tmpa_int } } { \tl_if_eq:NnTF \l_@@_baseline_tl { t } { \int_set_eq:NN \l_tmpa_int \c_one_int } { \tl_if_eq:NnTF \l_@@_baseline_tl { b } { \int_set_eq:NN \l_tmpa_int \c@iRow } { \int_set:Nn \l_tmpa_int \l_@@_baseline_tl } } \bool_lazy_or:nnT { \int_compare_p:nNn \l_tmpa_int < \l_@@_first_row_int } { \int_compare_p:nNn \l_tmpa_int > \g_@@_row_total_int } { \@@_error:n { bad~value~for~baseline } \int_set_eq:NN \l_tmpa_int \c_one_int } \@@_qpoint:n { row - \int_use:N \l_tmpa_int - base } % \end{macrocode} % We take into account the position of the mathematical axis. % \begin{macrocode} \dim_gsub:Nn \g_tmpa_dim { \fontdimen22 \textfont2 } } \dim_gsub:Nn \g_tmpa_dim \pgf@y % \end{macrocode} % Now, |\g_tmpa_dim| contains the value of the $y$ translation we have to to. % \begin{macrocode} \endpgfpicture \box_move_up:nn \g_tmpa_dim { \box_use_drop:N \l_tmpa_box } \box_use_drop:N \l_tmpa_box } % \end{macrocode} % % \bigskip % The following command is \emph{always} used by |{NiceArrayWithDelims}| (even % if, in fact, there is no tabular notes: in fact, it's not possible to know % whether there is tabular notes or not before the composition of the blocks). % \begin{macrocode} \cs_new_protected:Npn \@@_use_arraybox_with_notes_c: { % \end{macrocode} % With an environment |{Matrix}|, you want to remove the exterior |\arraycolsep| % but we don't know the number of columns (since there is no preamble) and % that's why we can't put |@{}| at the end of the preamble. That's why we remove % a |\arraycolsep| now. % \begin{macrocode} \bool_if:NT \l_@@_NiceMatrix_without_vlines_bool { \int_compare:nNnT \c@jCol > \c_one_int { \box_set_wd:Nn \l_@@_the_array_box { \box_wd:N \l_@@_the_array_box - \arraycolsep } } } % \end{macrocode} % We need a |{minipage}| because we will insert a LaTeX list for the tabular % notes (that means that a |\vtop{\hsize=...}| is not enough). % \begin{macrocode} \begin { minipage } [ t ] { \box_wd:N \l_@@_the_array_box } \bool_if:NT \l_@@_caption_above_bool { \tl_if_empty:NF \l_@@_caption_tl { % \end{macrocode} % \begin{macrocode} \bool_set_false:N \g_@@_caption_finished_bool \int_gzero:N \c@tabularnote \@@_insert_caption: % \end{macrocode} % If there is one or several commands |\tabularnote| in the caption, we will % write in the |aux| file the number of such tabular notes... but only the % tabular notes for which the command |\tabularnote| has been used without its % optional argument (between square brackets). % \begin{macrocode} \int_compare:nNnT \g_@@_notes_caption_int > \c_zero_int { \tl_gput_right:Nx \g_@@_aux_tl { \tl_set:Nn \exp_not:N \l_@@_note_in_caption_tl { \int_use:N \g_@@_notes_caption_int } } \int_gzero:N \g_@@_notes_caption_int } } } % \end{macrocode} % The |\hbox| avoids that the |pgfpicture| inside |\@@_draw_blocks| adds a extra % vertical space before the notes. % \begin{macrocode} \hbox { \box_use_drop:N \l_@@_the_array_box % \end{macrocode} % We have to draw the blocks right now because there may be tabular notes in % some blocks (which are not mono-column: the blocks which are mono-column % have been composed in boxes yet)... and we have to create (potentially) the % extra nodes before creating the blocks since there are |medium| nodes to create % for the blocks. % \begin{macrocode} \@@_create_extra_nodes: \seq_if_empty:NF \g_@@_blocks_seq \@@_draw_blocks: } % \end{macrocode} % We don't do the following test with |\c@tabularnote| because the value of that % counter is not reliable when the command |\ttabbox| of \pkg{floatrow} is used % (because |\ttabbox| de-activate |\stepcounter| because if compiles several % twice its tabular). % \begin{macrocode} \bool_lazy_any:nT { { ! \seq_if_empty_p:N \g_@@_notes_seq } { ! \seq_if_empty_p:N \g_@@_notes_in_caption_seq } { ! \tl_if_empty_p:o \g_@@_tabularnote_tl } } \@@_insert_tabularnotes: \cs_set_eq:NN \tabularnote \@@_tabularnote_error:n \bool_if:NF \l_@@_caption_above_bool \@@_insert_caption: \end { minipage } } % \end{macrocode} % % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_insert_caption: { \tl_if_empty:NF \l_@@_caption_tl { \cs_if_exist:NTF \@captype { \@@_insert_caption_i: } { \@@_error:n { caption~outside~float } } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_insert_caption_i: { \group_begin: % \end{macrocode} % The flag |\l_@@_in_caption_bool| affects only the behaviour of the command % |\tabularnote| when used in the caption. % \begin{macrocode} \bool_set_true:N \l_@@_in_caption_bool % \end{macrocode} % The package \pkg{floatrow} does a redefinition of |\@makecaption| which will % extract the caption from the tabular. However, the old version of % |\@makecaption| has been stored by \pkg{floatrow} in |\FR@makecaption|. That's % why we restore the old version. % \begin{macrocode} \IfPackageLoadedTF { floatrow } { \cs_set_eq:NN \@makecaption \FR@makecaption } { } \tl_if_empty:NTF \l_@@_short_caption_tl { \caption } { \caption [ \l_@@_short_caption_tl ] } { \l_@@_caption_tl } % \end{macrocode} % In some circonstancies (in particular when the package \pkg{caption} is % loaded), the caption is composed several times. That's why, when the same % tabular note is encountered (in the caption!), we consider that you are in the % second compilation and you can give to |\g_@@_notes_caption_int| its final % value, which is the number of tabular notes in the caption. But sometimes, the % caption is composed only once. In that case, we fix the value of % |\g_@@_caption_finished_bool| now. % \begin{macrocode} \bool_if:NF \g_@@_caption_finished_bool { \bool_gset_true:N \g_@@_caption_finished_bool \int_gset_eq:NN \g_@@_notes_caption_int \c@tabularnote \int_gzero:N \c@tabularnote } \tl_if_empty:NF \l_@@_label_tl { \label { \l_@@_label_tl } } \group_end: } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_tabularnote_error:n #1 { \@@_error_or_warning:n { tabularnote~below~the~tabular } \@@_gredirect_none:n { tabularnote~below~the~tabular } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_insert_tabularnotes: { \seq_gconcat:NNN \g_@@_notes_seq \g_@@_notes_in_caption_seq \g_@@_notes_seq \int_set:Nn \c@tabularnote { \seq_count:N \g_@@_notes_seq } \skip_vertical:N 0.65ex % \end{macrocode} % The TeX group is for potential specifications in the % |\l_@@_notes_code_before_tl|. % \begin{macrocode} \group_begin: \l_@@_notes_code_before_tl \tl_if_empty:NF \g_@@_tabularnote_tl { \g_@@_tabularnote_tl \par \tl_gclear:N \g_@@_tabularnote_tl } % \end{macrocode} % We compose the tabular notes with a list of \pkg{enumitem}. The |\strut| and % the |\unskip| are designed to give the ability to put a |\bottomrule| at the % end of the notes with a good vertical space. % \begin{macrocode} \int_compare:nNnT \c@tabularnote > \c_zero_int { \bool_if:NTF \l_@@_notes_para_bool { \begin { tabularnotes* } \seq_map_inline:Nn \g_@@_notes_seq { \@@_one_tabularnote:nn ##1 } \strut \end { tabularnotes* } % \end{macrocode} % The following |\par| is mandatory for the event that the user has put % |\footnotesize| (for example) in the |notes/code-before|. % \begin{macrocode} \par } { \tabularnotes \seq_map_inline:Nn \g_@@_notes_seq { \@@_one_tabularnote:nn ##1 } \strut \endtabularnotes } } \unskip \group_end: \bool_if:NT \l_@@_notes_bottomrule_bool { \IfPackageLoadedTF { booktabs } { % \end{macrocode} % The two dimensions |\aboverulesep| et |\heavyrulewidth| are parameters defined % by \pkg{booktabs}. % \begin{macrocode} \skip_vertical:N \aboverulesep % \end{macrocode} % |\CT@arc@| is the specification of color defined by \pkg{colortbl} but you use it % even if \pkg{colortbl} is not loaded. % \begin{macrocode} { \CT@arc@ \hrule height \heavyrulewidth } } { \@@_error_or_warning:n { bottomrule~without~booktabs } } } \l_@@_notes_code_after_tl \seq_gclear:N \g_@@_notes_seq \seq_gclear:N \g_@@_notes_in_caption_seq \int_gzero:N \c@tabularnote } % \end{macrocode} % % \medskip % The following command will format (after the main tabular) one tabularnote % (with the command |\item|) . |#1| is the label (when the command % |\tabularnote| has been used with an optional argument between square % brackets) and |#2| is the text of the note. The second argument is provided by % curryfication. % \begin{macrocode} \cs_set_protected:Npn \@@_one_tabularnote:nn #1 { \tl_if_novalue:nTF { #1 } { \item } { \item [ \@@_notes_label_in_list:n { #1 } ] } } % \end{macrocode} % % \medskip % The case of |baseline| equal to |b|. Remember that, when the key |b| is used, % the |{array}| (of \pkg{array}) is constructed with the option |t| (and not % |b|). Now, we do the translation to take into account the option |b|. % \begin{macrocode} \cs_new_protected:Npn \@@_use_arraybox_with_notes_b: { \pgfpicture \@@_qpoint:n { row - 1 } \dim_gset_eq:NN \g_tmpa_dim \pgf@y \@@_qpoint:n { row - \int_use:N \c@iRow - base } \dim_gsub:Nn \g_tmpa_dim \pgf@y \endpgfpicture \dim_gadd:Nn \g_tmpa_dim \arrayrulewidth \int_if_zero:nT \l_@@_first_row_int { \dim_gadd:Nn \g_tmpa_dim \g_@@_ht_row_zero_dim \dim_gadd:Nn \g_tmpa_dim \g_@@_dp_row_zero_dim } \box_move_up:nn \g_tmpa_dim { \hbox { \@@_use_arraybox_with_notes_c: } } } % \end{macrocode} % % \medskip % Now, the general case. % \begin{macrocode} \cs_new_protected:Npn \@@_use_arraybox_with_notes: { % \end{macrocode} % We convert a value of |t| to a value of |1|. % \begin{macrocode} \tl_if_eq:NnT \l_@@_baseline_tl { t } { \cs_set_nopar:Npn \l_@@_baseline_tl { 1 } } % \end{macrocode} % Now, we convert the value of |\l_@@_baseline_tl| (which should represent an % integer) to an integer stored in |\l_tmpa_int|. % \begin{macrocode} \pgfpicture \@@_qpoint:n { row - 1 } \dim_gset_eq:NN \g_tmpa_dim \pgf@y \str_if_in:NnTF \l_@@_baseline_tl { line- } { \int_set:Nn \l_tmpa_int { \str_range:Nnn \l_@@_baseline_tl 6 { \tl_count:o \l_@@_baseline_tl } } \@@_qpoint:n { row - \int_use:N \l_tmpa_int } } { \int_set:Nn \l_tmpa_int \l_@@_baseline_tl \bool_lazy_or:nnT { \int_compare_p:nNn \l_tmpa_int < \l_@@_first_row_int } { \int_compare_p:nNn \l_tmpa_int > \g_@@_row_total_int } { \@@_error:n { bad~value~for~baseline } \int_set:Nn \l_tmpa_int 1 } \@@_qpoint:n { row - \int_use:N \l_tmpa_int - base } } \dim_gsub:Nn \g_tmpa_dim \pgf@y \endpgfpicture \dim_gadd:Nn \g_tmpa_dim \arrayrulewidth \int_if_zero:nT \l_@@_first_row_int { \dim_gadd:Nn \g_tmpa_dim \g_@@_ht_row_zero_dim \dim_gadd:Nn \g_tmpa_dim \g_@@_dp_row_zero_dim } \box_move_up:nn \g_tmpa_dim { \hbox { \@@_use_arraybox_with_notes_c: } } } % \end{macrocode} % % % % \bigskip % The command |\@@_put_box_in_flow_bis:| is used when the option % |delimiters/max-width| is used because, in this case, we have to adjust the % widths of the delimiters. The arguments |#1| and |#2| are the delimiters % specified by the user. % \begin{macrocode} \cs_new_protected:Npn \@@_put_box_in_flow_bis:nn #1 #2 { % \end{macrocode} % We will compute the real width of both delimiters used. % \begin{macrocode} \dim_zero_new:N \l_@@_real_left_delim_dim \dim_zero_new:N \l_@@_real_right_delim_dim \hbox_set:Nn \l_tmpb_box { \c_math_toggle_token \left #1 \vcenter { \vbox_to_ht:nn { \box_ht_plus_dp:N \l_tmpa_box } { } } \right . \c_math_toggle_token } \dim_set:Nn \l_@@_real_left_delim_dim { \box_wd:N \l_tmpb_box - \nulldelimiterspace } \hbox_set:Nn \l_tmpb_box { \c_math_toggle_token \left . \vbox_to_ht:nn { \box_ht_plus_dp:N \l_tmpa_box } { } \right #2 \c_math_toggle_token } \dim_set:Nn \l_@@_real_right_delim_dim { \box_wd:N \l_tmpb_box - \nulldelimiterspace } % \end{macrocode} % % Now, we can put the box in the TeX flow with the horizontal adjustments on % both sides. % \begin{macrocode} \skip_horizontal:N \l_@@_left_delim_dim \skip_horizontal:N -\l_@@_real_left_delim_dim \@@_put_box_in_flow: \skip_horizontal:N \l_@@_right_delim_dim \skip_horizontal:N -\l_@@_real_right_delim_dim } % \end{macrocode} % % \interitem % The construction of the array in the environment |{NiceArrayWithDelims}| is, % in fact, done by the environment |{@@-light-syntax}| or by the environment % |{@@-normal-syntax}| (whether the option |light-syntax| is in force or not). % When the key |light-syntax| is not used, the construction is a standard % environment (and, thus, it's possible to use verbatim in the array). % \begin{macrocode} \NewDocumentEnvironment { @@-normal-syntax } { } % \end{macrocode} % First, we test whether the environment is empty. If it is empty, we raise a % fatal error (it's only a security). In order to detect whether it is empty, we % test whether the next token is |\end| and, if it's the case, we test if this % is the end of the environment (if it is not, an standard error will be raised % by LaTeX for incorrect nested environments). % \begin{macrocode} { \peek_remove_spaces:n { \peek_meaning:NTF \end \@@_analyze_end:Nn { \@@_transform_preamble: % \end{macrocode} % Here is the call to |\array| (we have a dedicated macro |\@@_array:| because % of compatibility with the classes \cls{revtex4-1} and \cls{revtex4-2}). % \begin{macrocode} \exp_args:No \@@_array: \g_@@_array_preamble_tl } } } { \@@_create_col_nodes: \endarray } % \end{macrocode} % % % \bigskip % When the key |light-syntax| is in force, we use an environment which takes its % whole body as an argument (with the specifier |b|). % % \label{code-light-syntax} % \begin{macrocode} \NewDocumentEnvironment { @@-light-syntax } { b } { % \end{macrocode} % First, we test whether the environment is empty. It's only a security. Of % course, this test is more easy than the similar test for the ``normal syntax'' % because we have the whole body of the environment in |#1|. % \begin{macrocode} \tl_if_empty:nT { #1 } { \@@_fatal:n { empty~environment } } \tl_map_inline:nn { #1 } { \str_if_eq:nnT { ##1 } { & } { \@@_fatal:n { ampersand~in~light-syntax } } \str_if_eq:nnT { ##1 } { \\ } { \@@_fatal:n { double-backslash~in~light-syntax } } } % \end{macrocode} % Now, you extract the |\CodeAfter| of the body of the environment. Maybe, there % is no command |\CodeAfter| in the body. That's why you put a marker % |\CodeAfter| after |#1|. If there is yet a |\CodeAfter| in |#1|, this second % (or third...) |\CodeAfter| will be catched in the value of % |\g_nicematrix_code_after_tl|. That doesn't matter because |\CodeAfter| will % be set to \textsl{no-op} before the execution of % |\g_nicematrix_code_after_tl|. % \begin{macrocode} \@@_light_syntax_i:w #1 \CodeAfter \q_stop % \end{macrocode} % The command |\array| is hidden somewhere in |\@@_light_syntax_i:w|. % \begin{macrocode} } % \end{macrocode} % Now, the second part of the environment. We must leave these lines in the % second part (and not put them in the first part even though we caught the % whole body of the environment with an argument of type |b|) in order to have % the columns |S| of \pkg{siunitx} working fine. % \begin{macrocode} { \@@_create_col_nodes: \endarray } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_light_syntax_i:w #1\CodeAfter #2\q_stop { \tl_gput_right:Nn \g_nicematrix_code_after_tl { #2 } % \end{macrocode} % The body of the array, which is stored in the argument |#1|, is now % splitted into items (and \emph{not} tokens). % \begin{macrocode} \seq_clear_new:N \l_@@_rows_seq % \end{macrocode} % We rescan the character of end of line in order to have the correct catcode. % \begin{macrocode} \tl_set_rescan:Nno \l_@@_end_of_row_tl { } \l_@@_end_of_row_tl \bool_if:NTF \l_@@_light_syntax_expanded_bool \seq_set_split:Nee \seq_set_split:NVn \l_@@_rows_seq \l_@@_end_of_row_tl { #1 } % \end{macrocode} % We delete the last row if it is empty. % \begin{macrocode} \seq_pop_right:NN \l_@@_rows_seq \l_tmpa_tl \tl_if_empty:NF \l_tmpa_tl { \seq_put_right:No \l_@@_rows_seq \l_tmpa_tl } % \end{macrocode} % If the environment uses the option |last-row| without value (i.e. without % saying the number of the rows), we have now the opportunity to compute that % value. We do it, and so, if the token list |\l_@@_code_for_last_row_tl| is not % empty, we will use directly where it should be. % \begin{macrocode} \int_compare:nNnT \l_@@_last_row_int = { -1 } { \int_set:Nn \l_@@_last_row_int { \seq_count:N \l_@@_rows_seq } } % \end{macrocode} % % % \bigskip % The new value of the body (that is to say after replacement of the separators % of rows and columns by |\\| and |&|) of the environment will be stored in % |\l_@@_new_body_tl| in order to allow the use of commands such as % |\hline| or |\hdottedline| with the key |light-syntax|). % \begin{macrocode} \tl_build_begin:N \l_@@_new_body_tl \int_zero_new:N \l_@@_nb_cols_int % \end{macrocode} % First, we treat the first row. % \begin{macrocode} \seq_pop_left:NN \l_@@_rows_seq \l_tmpa_tl \@@_line_with_light_syntax:o \l_tmpa_tl % \end{macrocode} % Now, the other rows (with the same treatment, excepted that we have to insert % |\\| between the rows). % \begin{macrocode} \seq_map_inline:Nn \l_@@_rows_seq { \tl_build_put_right:Nn \l_@@_new_body_tl { \\ } \@@_line_with_light_syntax:n { ##1 } } \tl_build_end:N \l_@@_new_body_tl % \end{macrocode} % % \begin{macrocode} \int_compare:nNnT \l_@@_last_col_int = { -1 } { \int_set:Nn \l_@@_last_col_int { \l_@@_nb_cols_int - 1 + \l_@@_first_col_int } } % \end{macrocode} % % Now, we can construct the preamble: if the user has used the key |last-col|, % we have the correct number of columns even though the user has used |last-col| % without value. % \begin{macrocode} \@@_transform_preamble: % \end{macrocode} % \bigskip % % The call to |\array| is in the following command (we have a dedicated macro % |\@@_array:| because of compatibility with the classes \cls{revtex4-1} and % \cls{revtex4-2}). % \begin{macrocode} \exp_args:No \@@_array: \g_@@_array_preamble_tl \l_@@_new_body_tl } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_line_with_light_syntax:n #1 { \seq_clear_new:N \l_@@_cells_seq \seq_set_split:Nnn \l_@@_cells_seq { ~ } { #1 } \int_set:Nn \l_@@_nb_cols_int { \int_max:nn \l_@@_nb_cols_int { \seq_count:N \l_@@_cells_seq } } \seq_pop_left:NN \l_@@_cells_seq \l_tmpa_tl \exp_args:NNo \tl_build_put_right:Nn \l_@@_new_body_tl \l_tmpa_tl \seq_map_inline:Nn \l_@@_cells_seq { \tl_build_put_right:Nn \l_@@_new_body_tl { & ##1 } } } \cs_generate_variant:Nn \@@_line_with_light_syntax:n { o } % \end{macrocode} % % % \bigskip % The following command is used by the code which detects whether the % environment is empty (we raise a fatal error in this case: it's only a % security). When this command is used, |#1| is, in fact, always |\end|. % \begin{macrocode} \cs_new_protected:Npn \@@_analyze_end:Nn #1 #2 { \str_if_eq:onT \g_@@_name_env_str { #2 } { \@@_fatal:n { empty~environment } } % \end{macrocode} % We reput in the stream the |\end{...}| we have extracted and the user will % have an error for incorrect nested environments. % \begin{macrocode} \end { #2 } } % \end{macrocode} % % \bigskip % The command |\@@_create_col_nodes:| will construct a special last row. % That last row is a false row used to create the |col| nodes and to fix the % width of the columns (when the array is constructed with an option which % specifies the width of the columns). % \begin{macrocode} \cs_new:Npn \@@_create_col_nodes: { \crcr \int_if_zero:nT \l_@@_first_col_int { \omit \hbox_overlap_left:n { \bool_if:NT \l_@@_code_before_bool { \pgfsys@markposition { \@@_env: - col - 0 } } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - 0 } \pgfpointorigin \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - col - 0 } { \@@_env: - col - 0 } } \endpgfpicture \skip_horizontal:N 2\col@sep \skip_horizontal:N \g_@@_width_first_col_dim } & } \omit % \end{macrocode} % The following instruction must be put after the instruction |\omit|. % \begin{macrocode} \bool_gset_true:N \g_@@_row_of_col_done_bool % \end{macrocode} % First, we put a |col| node on the left of the first column (of course, we % have to do that \emph{after} the |\omit|). % \begin{macrocode} \int_if_zero:nTF \l_@@_first_col_int { \bool_if:NT \l_@@_code_before_bool { \hbox { \skip_horizontal:N -0.5\arrayrulewidth \pgfsys@markposition { \@@_env: - col - 1 } \skip_horizontal:N 0.5\arrayrulewidth } } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - 1 } { \pgfpoint { - 0.5 \arrayrulewidth } \c_zero_dim } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - col - 1 } { \@@_env: - col - 1 } } \endpgfpicture } { \bool_if:NT \l_@@_code_before_bool { \hbox { \skip_horizontal:N 0.5\arrayrulewidth \pgfsys@markposition { \@@_env: - col - 1 } \skip_horizontal:N -0.5\arrayrulewidth } } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - 1 } { \pgfpoint { 0.5 \arrayrulewidth } \c_zero_dim } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - col - 1 } { \@@_env: - col - 1 } } \endpgfpicture } % \end{macrocode} % We compute in |\g_tmpa_skip| the common width of the columns (it's a skip and % not a dimension). We use a global variable because we are in a cell of an % |\halign| and because we have to use that variable in other cells (of the same % row). The affectation of |\g_tmpa_skip|, like all the affectations, must be % done after the |\omit| of the cell. % % \smallskip % We give a default value for |\g_tmpa_skip| (|0 pt plus 1 fill|) but we will % add some dimensions to it. % \begin{macrocode} \skip_gset:Nn \g_tmpa_skip { 0 pt~plus 1 fill } \bool_if:NF \l_@@_auto_columns_width_bool { \dim_compare:nNnT \l_@@_columns_width_dim > \c_zero_dim } { \bool_lazy_and:nnTF \l_@@_auto_columns_width_bool { \bool_not_p:n \l_@@_block_auto_columns_width_bool } { \skip_gadd:Nn \g_tmpa_skip \g_@@_max_cell_width_dim } { \skip_gadd:Nn \g_tmpa_skip \l_@@_columns_width_dim } \skip_gadd:Nn \g_tmpa_skip { 2 \col@sep } } \skip_horizontal:N \g_tmpa_skip \hbox { \bool_if:NT \l_@@_code_before_bool { \hbox { \skip_horizontal:N -0.5\arrayrulewidth \pgfsys@markposition { \@@_env: - col - 2 } \skip_horizontal:N 0.5\arrayrulewidth } } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - 2 } { \pgfpoint { - 0.5 \arrayrulewidth } \c_zero_dim } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - col - 2 } { \@@_env: - col - 2 } } \endpgfpicture } % \end{macrocode} % We begin a loop over the columns. The integer |\g_tmpa_int| will be the % number of the current column. This integer is used for the Tikz nodes. % \begin{macrocode} \int_gset_eq:NN \g_tmpa_int \c_one_int \bool_if:NTF \g_@@_last_col_found_bool { \prg_replicate:nn { \int_max:nn { \g_@@_col_total_int - 3 } \c_zero_int } } { \prg_replicate:nn { \int_max:nn { \g_@@_col_total_int - 2 } \c_zero_int } } { & \omit \int_gincr:N \g_tmpa_int % \end{macrocode} % The incrementation of the counter |\g_tmpa_int| must be done after the |\omit| % of the cell. % \begin{macrocode} \skip_horizontal:N \g_tmpa_skip \bool_if:NT \l_@@_code_before_bool { \hbox { \skip_horizontal:N -0.5\arrayrulewidth \pgfsys@markposition { \@@_env: - col - \int_eval:n { \g_tmpa_int + 1 } } \skip_horizontal:N 0.5\arrayrulewidth } } % \end{macrocode} % We create the |col| node on the right of the current column. % \begin{macrocode} \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - \int_eval:n { \g_tmpa_int + 1 } } { \pgfpoint { - 0.5 \arrayrulewidth } \c_zero_dim } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - col - \int_eval:n { \g_tmpa_int + 1 } } { \@@_env: - col - \int_eval:n { \g_tmpa_int + 1 } } } \endpgfpicture } % \end{macrocode} % % \bigskip % \begin{macrocode} & \omit % \end{macrocode} % The two following lines have been added on 2021-12-15 to solve a bug % mentionned by Joao Luis Soares by mail. % \begin{macrocode} \int_if_zero:nT \g_@@_col_total_int { \skip_gset:Nn \g_tmpa_skip { 0 pt~plus 1 fill } } \skip_horizontal:N \g_tmpa_skip \int_gincr:N \g_tmpa_int \bool_lazy_any:nF % modified 2023/12/13 { \g_@@_delims_bool \l_@@_tabular_bool { ! \clist_if_empty_p:N \l_@@_vlines_clist } \l_@@_exterior_arraycolsep_bool \l_@@_bar_at_end_of_pream_bool } { \skip_horizontal:N -\col@sep } \bool_if:NT \l_@@_code_before_bool { \hbox { \skip_horizontal:N -0.5\arrayrulewidth % \end{macrocode} % With an environment |{Matrix}|, you want to remove the exterior |\arraycolsep| % but we don't know the number of columns (since there is no preamble) and % that's why we can't put |@{}| at the end of the preamble. That's why we remove % a |\arraycolsep| now. % \begin{macrocode} \bool_if:NT \l_@@_NiceMatrix_without_vlines_bool { \skip_horizontal:N -\arraycolsep } \pgfsys@markposition { \@@_env: - col - \int_eval:n { \g_tmpa_int + 1 } } \skip_horizontal:N 0.5\arrayrulewidth \bool_if:NT \l_@@_NiceMatrix_without_vlines_bool { \skip_horizontal:N \arraycolsep } } } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - \int_eval:n { \g_tmpa_int + 1 } } { \bool_if:NT \l_@@_NiceMatrix_without_vlines_bool { \pgfpoint { - 0.5 \arrayrulewidth - \arraycolsep } \c_zero_dim } { \pgfpoint { - 0.5 \arrayrulewidth } \c_zero_dim } } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - col - \int_eval:n { \g_tmpa_int + 1 } } { \@@_env: - col - \int_eval:n { \g_tmpa_int + 1 } } } \endpgfpicture % \end{macrocode} % % \bigskip % \begin{macrocode} \bool_if:NT \g_@@_last_col_found_bool { \hbox_overlap_right:n { \skip_horizontal:N \g_@@_width_last_col_dim \skip_horizontal:N \col@sep % added 2023-11-05 \bool_if:NT \l_@@_code_before_bool { \pgfsys@markposition { \@@_env: - col - \int_eval:n { \g_@@_col_total_int + 1 } } } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgfcoordinate { \@@_env: - col - \int_eval:n { \g_@@_col_total_int + 1 } } \pgfpointorigin \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - col - \int_eval:n { \g_@@_col_total_int + 1 } } { \@@_env: - col - \int_eval:n { \g_@@_col_total_int + 1 } } } \endpgfpicture } } \cr } % \end{macrocode} % % % \interitem % Here is the preamble for the ``first column'' (if the user uses the key % |first-col|) % \begin{macrocode} \tl_const:Nn \c_@@_preamble_first_col_tl { > { % \end{macrocode} % At the beginning of the cell, we link |\CodeAfter| to a command which do % begins with |\\| (whereas the standard version of |\CodeAfter| begins does % not). % \begin{macrocode} \cs_set_eq:NN \CodeAfter \@@_CodeAfter_i: \bool_gset_true:N \g_@@_after_col_zero_bool \@@_begin_of_row: % \end{macrocode} % The contents of the cell is constructed in the box |\l_@@_cell_box| because we % have to compute some dimensions of this box. % \begin{macrocode} \hbox_set:Nw \l_@@_cell_box \@@_math_toggle: \@@_tuning_key_small: % \end{macrocode} % We insert |\l_@@_code_for_first_col_tl|... but we don't insert it in the % potential ``first row'' and in the potential ``last row''. % \begin{macrocode} \int_compare:nNnT \c@iRow > \c_zero_int { \bool_lazy_or:nnT { \int_compare_p:nNn \l_@@_last_row_int < \c_zero_int } { \int_compare_p:nNn \c@iRow < \l_@@_last_row_int } { \l_@@_code_for_first_col_tl \xglobal \colorlet { nicematrix-first-col } { . } } } } % \end{macrocode} % Be careful: despite this letter |l| the cells of the ``first column'' are % composed in a |R| manner since they are composed in a |\hbox_overlap_left:n|. % \begin{macrocode} l < { \@@_math_toggle: \hbox_set_end: \bool_if:NT \g_@@_rotate_bool \@@_rotate_cell_box: \@@_adjust_size_box: \@@_update_for_first_and_last_row: % \end{macrocode} % We actualise the width of the ``first column'' because we will use this width % after the construction of the array. % \begin{macrocode} \dim_gset:Nn \g_@@_width_first_col_dim { \dim_max:nn \g_@@_width_first_col_dim { \box_wd:N \l_@@_cell_box } } % \end{macrocode} % The content of the cell is inserted in an overlapping position. % \label{overlap-left} % \begin{macrocode} \hbox_overlap_left:n { \dim_compare:nNnTF { \box_wd:N \l_@@_cell_box } > \c_zero_dim \@@_node_for_cell: { \box_use_drop:N \l_@@_cell_box } \skip_horizontal:N \l_@@_left_delim_dim \skip_horizontal:N \l_@@_left_margin_dim \skip_horizontal:N \l_@@_extra_left_margin_dim } \bool_gset_false:N \g_@@_empty_cell_bool \skip_horizontal:N -2\col@sep } } % \end{macrocode} % % % Here is the preamble for the ``last column'' (if the user uses the key % |last-col|). % \begin{macrocode} \tl_const:Nn \c_@@_preamble_last_col_tl { > { \bool_set_true:N \l_@@_in_last_col_bool % \end{macrocode} % At the beginning of the cell, we link |\CodeAfter| to a command which % begins with |\\| (whereas the standard version of |\CodeAfter| begins does % not). % \begin{macrocode} \cs_set_eq:NN \CodeAfter \@@_CodeAfter_i: % \end{macrocode} % With the flag |\g_@@_last_col_found_bool|, we will know that the ``last % column'' is really used. % \begin{macrocode} \bool_gset_true:N \g_@@_last_col_found_bool \int_gincr:N \c@jCol \int_gset_eq:NN \g_@@_col_total_int \c@jCol % \end{macrocode} % The contents of the cell is constructed in the box |\l_tmpa_box| because we % have to compute some dimensions of this box. % \begin{macrocode} \hbox_set:Nw \l_@@_cell_box \@@_math_toggle: \@@_tuning_key_small: % \end{macrocode} % We insert |\l_@@_code_for_last_col_tl|... but we don't insert it in the % potential ``first row'' and in the potential ``last row''. % \begin{macrocode} \int_compare:nNnT \c@iRow > \c_zero_int { \bool_lazy_or:nnT { \int_compare_p:nNn \l_@@_last_row_int < \c_zero_int } { \int_compare_p:nNn \c@iRow < \l_@@_last_row_int } { \l_@@_code_for_last_col_tl \xglobal \colorlet { nicematrix-last-col } { . } } } } l < { \@@_math_toggle: \hbox_set_end: \bool_if:NT \g_@@_rotate_bool \@@_rotate_cell_box: \@@_adjust_size_box: \@@_update_for_first_and_last_row: % \end{macrocode} % We actualise the width of the ``last column'' because we will use this width % after the construction of the array. % \begin{macrocode} \dim_gset:Nn \g_@@_width_last_col_dim { \dim_max:nn \g_@@_width_last_col_dim { \box_wd:N \l_@@_cell_box } } \skip_horizontal:N -2\col@sep % \end{macrocode} % The content of the cell is inserted in an overlapping position. % \label{overlap-right} % \begin{macrocode} \hbox_overlap_right:n { \dim_compare:nNnT { \box_wd:N \l_@@_cell_box } > \c_zero_dim { \skip_horizontal:N \l_@@_right_delim_dim \skip_horizontal:N \l_@@_right_margin_dim \skip_horizontal:N \l_@@_extra_right_margin_dim \@@_node_for_cell: } } \bool_gset_false:N \g_@@_empty_cell_bool } } % \end{macrocode} % % % \interitem % The environment |{NiceArray}| is constructed upon the environment % |{NiceArrayWithDelims}|. % \begin{macrocode} \NewDocumentEnvironment { NiceArray } { } { \bool_gset_false:N \g_@@_delims_bool \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { NiceArray } } % \end{macrocode} % We put . and . for the delimiters but, in fact, that doesn't matter because % these arguments won't be used in |{NiceArrayWithDelims}| (because the flag % |\g_@@_delims_bool| is set to false). % \begin{macrocode} \NiceArrayWithDelims . . } { \endNiceArrayWithDelims } % \end{macrocode} % % % \interitem % We create the variants of the environment |{NiceArrayWithDelims}|. % % \begin{macrocode} \cs_new_protected:Npn \@@_def_env:nnn #1 #2 #3 { \NewDocumentEnvironment { #1 NiceArray } { } { \bool_gset_true:N \g_@@_delims_bool \str_if_empty:NT \g_@@_name_env_str { \str_gset:Nn \g_@@_name_env_str { #1 NiceArray } } \@@_test_if_math_mode: \NiceArrayWithDelims #2 #3 } { \endNiceArrayWithDelims } } % \end{macrocode} % % \begin{macrocode} \@@_def_env:nnn p ( ) \@@_def_env:nnn b [ ] \@@_def_env:nnn B \{ \} \@@_def_env:nnn v | | \@@_def_env:nnn V \| \| % \end{macrocode} % % % \bigskip % \section{The environment \{NiceMatrix\} and its variants} % % % \begin{macrocode} \cs_new_protected:Npn \@@_begin_of_NiceMatrix:nn #1 #2 { \bool_set_false:N \l_@@_preamble_bool \tl_clear:N \l_tmpa_tl \bool_if:NT \l_@@_NiceMatrix_without_vlines_bool { \tl_set:Nn \l_tmpa_tl { @ { } } } \tl_put_right:Nn \l_tmpa_tl { * { \int_case:nnF \l_@@_last_col_int { { -2 } { \c@MaxMatrixCols } { -1 } { \int_eval:n { \c@MaxMatrixCols + 1 } } % \end{macrocode} % The value $0$ can't occur here since we are in a matrix (which is an % environment without preamble). % \begin{macrocode} } { \int_eval:n { \l_@@_last_col_int - 1 } } } { #2 } } \tl_set:Nn \l_tmpb_tl { \use:c { #1 NiceArray } } \exp_args:No \l_tmpb_tl \l_tmpa_tl } % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \@@_begin_of_NiceMatrix:nn { n V } % \end{macrocode} % % \begin{macrocode} \clist_map_inline:nn { p , b , B , v , V } { \NewDocumentEnvironment { #1 NiceMatrix } { ! O { } } { \bool_gset_true:N \g_@@_delims_bool \str_gset:Nn \g_@@_name_env_str { #1 NiceMatrix } % added 2023/10/01 \int_if_zero:nT \l_@@_last_col_int { \bool_set_true:N \l_@@_last_col_without_value_bool \int_set:Nn \l_@@_last_col_int { -1 } } \keys_set:nn { NiceMatrix / NiceMatrix } { ##1 } \@@_begin_of_NiceMatrix:nV { #1 } \l_@@_columns_type_tl } { \use:c { end #1 NiceArray } } } % \end{macrocode} % % \bigskip % We define also an environment |{NiceMatrix}| % \begin{macrocode} \NewDocumentEnvironment { NiceMatrix } { ! O { } } { \str_gset:Nn \g_@@_name_env_str { NiceMatrix } % added 2023/10/01 \int_if_zero:nT \l_@@_last_col_int { \bool_set_true:N \l_@@_last_col_without_value_bool \int_set:Nn \l_@@_last_col_int { -1 } } \keys_set:nn { NiceMatrix / NiceMatrix } { #1 } \bool_lazy_or:nnT { \clist_if_empty_p:N \l_@@_vlines_clist } { \l_@@_except_borders_bool } { \bool_set_true:N \l_@@_NiceMatrix_without_vlines_bool } \@@_begin_of_NiceMatrix:nV { } \l_@@_columns_type_tl } { \endNiceArray } % \end{macrocode} % % \bigskip % The following command will be linked to |\NotEmpty| in the environments of % \pkg{nicematrix}. % \begin{macrocode} \cs_new_protected:Npn \@@_NotEmpty: { \bool_gset_true:N \g_@@_not_empty_cell_bool } % \end{macrocode} % % \bigskip % \section{\{NiceTabular\}, \{NiceTabularX\} and \{NiceTabular*\}} % % \begin{macrocode} \NewDocumentEnvironment { NiceTabular } { O { } m ! O { } } { % \end{macrocode} % If the dimension |\l_@@_width_dim| is equal to $0$~pt, that means that it has % not be set by a previous use of |\NiceMatrixOptions|. % \begin{macrocode} \dim_compare:nNnT \l_@@_width_dim = \c_zero_dim { \dim_set_eq:NN \l_@@_width_dim \linewidth } \str_gset:Nn \g_@@_name_env_str { NiceTabular } \keys_set:nn { NiceMatrix / NiceTabular } { #1 , #3 } \tl_if_empty:NF \l_@@_short_caption_tl { \tl_if_empty:NT \l_@@_caption_tl { \@@_error_or_warning:n { short-caption~without~caption } \tl_set_eq:NN \l_@@_caption_tl \l_@@_short_caption_tl } } \tl_if_empty:NF \l_@@_label_tl { \tl_if_empty:NT \l_@@_caption_tl { \@@_error_or_warning:n { label~without~caption } } } \NewDocumentEnvironment { TabularNote } { b } { \bool_if:NTF \l_@@_in_code_after_bool { \@@_error_or_warning:n { TabularNote~in~CodeAfter } } { \tl_if_empty:NF \g_@@_tabularnote_tl { \tl_gput_right:Nn \g_@@_tabularnote_tl { \par } } \tl_gput_right:Nn \g_@@_tabularnote_tl { ##1 } } } { } \@@_settings_for_tabular: \NiceArray { #2 } } { \endNiceArray } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_settings_for_tabular: { \bool_set_true:N \l_@@_tabular_bool \cs_set_eq:NN \@@_math_toggle: \prg_do_nothing: \cs_set_eq:NN \@@_tuning_not_tabular_begin: \prg_do_nothing: \cs_set_eq:NN \@@_tuning_not_tabular_end: \prg_do_nothing: } % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentEnvironment { NiceTabularX } { m O { } m ! O { } } { \str_gset:Nn \g_@@_name_env_str { NiceTabularX } \dim_zero_new:N \l_@@_width_dim \dim_set:Nn \l_@@_width_dim { #1 } \keys_set:nn { NiceMatrix / NiceTabular } { #2 , #4 } \@@_settings_for_tabular: \NiceArray { #3 } } { \endNiceArray \int_if_zero:nT \g_@@_total_X_weight_int { \@@_error:n { NiceTabularX~without~X } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentEnvironment { NiceTabular* } { m O { } m ! O { } } { \str_gset:Nn \g_@@_name_env_str { NiceTabular* } \dim_set:Nn \l_@@_tabular_width_dim { #1 } \keys_set:nn { NiceMatrix / NiceTabular } { #2 , #4 } \@@_settings_for_tabular: \NiceArray { #3 } } { \endNiceArray } % \end{macrocode} % % % \bigskip % \section{After the construction of the array} % % \bigskip % The following command will be used when the key |rounded-corners| is in force % (this is the key |rounded-corners| for the whole environment and \emph{not} % the key |rounded-corners| of a command |\Block|). % \begin{macrocode} \cs_new_protected:Npn \@@_deal_with_rounded_corners: { \bool_lazy_all:nT { { \int_compare_p:nNn \l_@@_tab_rounded_corners_dim > \c_zero_dim } \l_@@_hvlines_bool { ! \g_@@_delims_bool } { ! \l_@@_except_borders_bool } } { \bool_set_true:N \l_@@_except_borders_bool \clist_if_empty:NF \l_@@_corners_clist { \@@_error:n { hvlines,~rounded-corners~and~corners } } \tl_gput_right:Nn \g_@@_pre_code_after_tl { \@@_stroke_block:nnn { rounded-corners = \dim_use:N \l_@@_tab_rounded_corners_dim , draw = \l_@@_rules_color_tl } { 1-1 } { \int_use:N \c@iRow - \int_use:N \c@jCol } } } } % \end{macrocode} % % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_after_array: { \group_begin: % \end{macrocode} % When the option |last-col| is used in the environments with explicit preambles % (like |{NiceArray}|, |{pNiceArray}|, etc.) a special type of column is used at % the end of the preamble in order to compose the cells in an overlapping % position (with |\hbox_overlap_right:n|) but (if |last-col| has been used), we % don't have the number of that last column. However, we have to know that % number for the color of the potential |\Vdots| drawn in that last column. % That's why we fix the correct value of |\l_@@_last_col_int| in that case. % \begin{macrocode} \bool_if:NT \g_@@_last_col_found_bool { \int_set_eq:NN \l_@@_last_col_int \g_@@_col_total_int } % \end{macrocode} % % If we are in an environment without preamble (like |{NiceMatrix}| or % |{pNiceMatrix}|) and if the option |last-col| has been used without value % we also fix the real value of |\l_@@_last_col_int|. % \begin{macrocode} \bool_if:NT \l_@@_last_col_without_value_bool { \int_set_eq:NN \l_@@_last_col_int \g_@@_col_total_int } % \end{macrocode} % % \medskip % It's also time to give to |\l_@@_last_row_int| its real value. % \begin{macrocode} \bool_if:NT \l_@@_last_row_without_value_bool { \int_set_eq:NN \l_@@_last_row_int \g_@@_row_total_int } % \end{macrocode} % % \medskip % \begin{macrocode} \tl_gput_right:Nx \g_@@_aux_tl { \seq_gset_from_clist:Nn \exp_not:N \g_@@_size_seq { \int_use:N \l_@@_first_row_int , \int_use:N \c@iRow , \int_use:N \g_@@_row_total_int , \int_use:N \l_@@_first_col_int , \int_use:N \c@jCol , \int_use:N \g_@@_col_total_int } } % \end{macrocode} % We write also the potential content of |\g_@@_pos_of_blocks_seq|. It will be % used to recreate the blocks with a name in the |\CodeBefore| and also if the % command |\rowcolors| is used with the key |respect-blocks|). % \begin{macrocode} \seq_if_empty:NF \g_@@_pos_of_blocks_seq { \tl_gput_right:Nx \g_@@_aux_tl { \seq_gset_from_clist:Nn \exp_not:N \g_@@_pos_of_blocks_seq { \seq_use:Nnnn \g_@@_pos_of_blocks_seq , , , } } } \seq_if_empty:NF \g_@@_multicolumn_cells_seq { \tl_gput_right:Nx \g_@@_aux_tl { \seq_gset_from_clist:Nn \exp_not:N \g_@@_multicolumn_cells_seq { \seq_use:Nnnn \g_@@_multicolumn_cells_seq , , , } \seq_gset_from_clist:Nn \exp_not:N \g_@@_multicolumn_sizes_seq { \seq_use:Nnnn \g_@@_multicolumn_sizes_seq , , , } } } % \end{macrocode} % % \medskip % Now, you create the diagonal nodes by using the |row| nodes and the |col| % nodes. % \begin{macrocode} \@@_create_diag_nodes: % \end{macrocode} % % \medskip % We create the aliases using |last| for the nodes of the cells in the last row % and the last column. % \begin{macrocode} \pgfpicture \int_step_inline:nn \c@iRow { \pgfnodealias { \@@_env: - ##1 - last } { \@@_env: - ##1 - \int_use:N \c@jCol } } \int_step_inline:nn \c@jCol { \pgfnodealias { \@@_env: - last - ##1 } { \@@_env: - \int_use:N \c@iRow - ##1 } } \str_if_empty:NF \l_@@_name_str { \int_step_inline:nn \c@iRow { \pgfnodealias { \l_@@_name_str - ##1 - last } { \@@_env: - ##1 - \int_use:N \c@jCol } } \int_step_inline:nn \c@jCol { \pgfnodealias { \l_@@_name_str - last - ##1 } { \@@_env: - \int_use:N \c@iRow - ##1 } } } \endpgfpicture % \end{macrocode} % % By default, the diagonal lines will be parallelized\footnote{It's possible to % use the option |parallelize-diags| to disable this parallelization.}. There % are two types of diagonals lines: the $|\Ddots|$ diagonals and the |\Iddots| % diagonals. We have to count both types in order to know whether a diagonal is % the first of its type in the current |{NiceArray}| environment. % \begin{macrocode} \bool_if:NT \l_@@_parallelize_diags_bool { \int_gzero_new:N \g_@@_ddots_int \int_gzero_new:N \g_@@_iddots_int % \end{macrocode} % % The dimensions |\g_@@_delta_x_one_dim| and |\g_@@_delta_y_one_dim| will % contain the $\Delta_x$ and $\Delta_y$ of the first |\Ddots| diagonal. We have % to store these values in order to draw the others |\Ddots| diagonals parallel % to the first one. Similarly |\g_@@_delta_x_two_dim| and % |\g_@@_delta_y_two_dim| are the $\Delta_x$ and $\Delta_y$ of the first % |\Iddots| diagonal. % \begin{macrocode} \dim_gzero_new:N \g_@@_delta_x_one_dim \dim_gzero_new:N \g_@@_delta_y_one_dim \dim_gzero_new:N \g_@@_delta_x_two_dim \dim_gzero_new:N \g_@@_delta_y_two_dim } % \end{macrocode} % % \begin{macrocode} \int_zero_new:N \l_@@_initial_i_int \int_zero_new:N \l_@@_initial_j_int \int_zero_new:N \l_@@_final_i_int \int_zero_new:N \l_@@_final_j_int \bool_set_false:N \l_@@_initial_open_bool \bool_set_false:N \l_@@_final_open_bool % \end{macrocode} % % If the option |small| is used, the values |\l_@@_xdots_radius_dim| and % |\l_@@_xdots_inter_dim| (used to draw the dotted lines created by % |\hdottedline| and |\vdottedline| and also for all the other dotted lines when % |line-style| is equal to |standard|, which is the initial value) are changed. % \begin{macrocode} \bool_if:NT \l_@@_small_bool { \dim_set:Nn \l_@@_xdots_radius_dim { 0.7 \l_@@_xdots_radius_dim } \dim_set:Nn \l_@@_xdots_inter_dim { 0.55 \l_@@_xdots_inter_dim } % \end{macrocode} % The dimensions |\l_@@_xdots_shorten_start_dim| and % |\l_@@_xdots_shorten_start_dim| correspond to the options % |xdots/shorten-start| and |xdots/shorten-end| available to the user. % \begin{macrocode} \dim_set:Nn \l_@@_xdots_shorten_start_dim { 0.6 \l_@@_xdots_shorten_start_dim } \dim_set:Nn \l_@@_xdots_shorten_end_dim { 0.6 \l_@@_xdots_shorten_end_dim } } % \end{macrocode} % % \bigskip % Now, we actually draw the dotted lines (specified by |\Cdots|, |\Vdots|, % etc.). % \begin{macrocode} \@@_draw_dotted_lines: % \end{macrocode} % % \bigskip % The following computes the ``corners'' (made up of empty cells) but if there % is no corner to compute, it won't do anything. The corners are computed % in |\l_@@_corners_cells_seq| which will contain all the cells which are empty % (and not in a block) considered in the corners of the array. % \begin{macrocode} \@@_compute_corners: % \end{macrocode} % % \bigskip % The sequence |\g_@@_pos_of_blocks_seq| must be ``adjusted'' (for the case % where the user have written something like |\Block{1-*}|). % \begin{macrocode} \@@_adjust_pos_of_blocks_seq: % \end{macrocode} % % \begin{macrocode} \@@_deal_with_rounded_corners: \tl_if_empty:NF \l_@@_hlines_clist \@@_draw_hlines: \tl_if_empty:NF \l_@@_vlines_clist \@@_draw_vlines: % \end{macrocode} % % \bigskip % Now, the pre-code-after and then, the |\CodeAfter|. % \begin{macrocode} \IfPackageLoadedTF { tikz } { \tikzset { every~picture / .style = { overlay , remember~picture , name~prefix = \@@_env: - } } } { } \cs_set_eq:NN \ialign \@@_old_ialign: \cs_set_eq:NN \SubMatrix \@@_SubMatrix \cs_set_eq:NN \UnderBrace \@@_UnderBrace \cs_set_eq:NN \OverBrace \@@_OverBrace \cs_set_eq:NN \ShowCellNames \@@_ShowCellNames \cs_set_eq:NN \TikzEveryCell \@@_TikzEveryCell \cs_set_eq:NN \line \@@_line \g_@@_pre_code_after_tl \tl_gclear:N \g_@@_pre_code_after_tl % \end{macrocode} % When |light-syntax| is used, we insert systematically a |\CodeAfter| in the % flow. Thus, it's possible to have two instructions |\CodeAfter| and the second % may be in |\g_nicematrix_code_after_tl|. That's why we set % |\Code-after| to be \textsl{no-op} now. % \begin{macrocode} \cs_set_eq:NN \CodeAfter \prg_do_nothing: % \end{macrocode} % % We clear the list of the names of the potential |\SubMatrix| that will appear % in the |\CodeAfter| (unfortunately, that list has to be global). % \begin{macrocode} \seq_gclear:N \g_@@_submatrix_names_seq % \end{macrocode} % % \medskip % The following code is a security for the case the user has used \pkg{babel} % with the option \pkg{spanish}: in that case, the characters |>| and |<| are % activated and Tikz is not able to solve the problem (even with the Tikz % library \pkg{babel}). % \begin{macrocode} \int_compare:nNnT { \char_value_catcode:n { 60 } } = { 13 } { \@@_rescan_for_spanish:N \g_nicematrix_code_after_tl } % \end{macrocode} % \medskip % And here's the |\CodeAfter|. Since the |\CodeAfter| may begin with an % ``argument'' between square brackets of the options, we extract and treat that % potential ``argument'' with the command |\@@_CodeAfter_keys:|. % \begin{macrocode} \bool_set_true:N \l_@@_in_code_after_bool \exp_last_unbraced:No \@@_CodeAfter_keys: \g_nicematrix_code_after_tl \scan_stop: \tl_gclear:N \g_nicematrix_code_after_tl \group_end: % \end{macrocode} % % % \medskip % |\g_@@_pre_code_before_tl| is for instructions in the cells of the array such as % |\rowcolor| and |\cellcolor| (when the key |color-inside| is in % force). These instructions will be written on the |aux| file to be added to % the |code-before| in the next run. % \begin{macrocode} \seq_if_empty:NF \g_@@_rowlistcolors_seq { \@@_clear_rowlistcolors_seq: } \tl_if_empty:NF \g_@@_pre_code_before_tl { \tl_gput_right:Nx \g_@@_aux_tl { \tl_gset:Nn \exp_not:N \g_@@_pre_code_before_tl { \exp_not:o \g_@@_pre_code_before_tl } } \tl_gclear:N \g_@@_pre_code_before_tl } \tl_if_empty:NF \g_nicematrix_code_before_tl { \tl_gput_right:Nx \g_@@_aux_tl { \tl_gset:Nn \exp_not:N \g_@@_code_before_tl { \exp_not:o \g_nicematrix_code_before_tl } } \tl_gclear:N \g_nicematrix_code_before_tl } % \end{macrocode} % % \medskip % \begin{macrocode} \str_gclear:N \g_@@_name_env_str \@@_restore_iRow_jCol: % \end{macrocode} % The command |\CT@arc@| contains the instruction of color for the rules of the % array\footnote{e.g. |\color[rgb]{0.5,0.5,0}|}. This command is used by % |\CT@arc@| but we use it also for compatibility with \pkg{colortbl}. But we % want also to be able to use color for the rules of the array when % \pkg{colortbl} is \emph{not} loaded. That's why we do the following % instruction which is in the patch of the end of arrays done by \pkg{colortbl}. % \begin{macrocode} \cs_gset_eq:NN \CT@arc@ \@@_old_CT@arc@ } % \end{macrocode} % % \bigskip % The following command will extract the potential options (between square % brackets) at the beginning of the |\CodeAfter| (that is to say, when % |\CodeAfter| is used, the options of that ``command'' |\CodeAfter|). Idem for % the |\CodeBefore.| % \begin{macrocode} \NewDocumentCommand \@@_CodeAfter_keys: { O { } } { \keys_set:nn { NiceMatrix / CodeAfter } { #1 } } % \end{macrocode} % % % % \bigskip % We remind that the first mandatory argument of the command |\Block| is the % size of the block with the special format $i$|-|$j$. However, the user is % allowed to omit $i$ or $j$ (or both). This will be interpreted as: the last % row (resp. column) of the block will be the last row (resp. column) of the % block (without the potential exterior row---resp. column---of the array). By % convention, this is stored in |\g_@@_pos_of_blocks_seq| (and % |\g_@@_blocks_seq|) as a number of rows (resp. columns) for the block equal to % 100. It's possible, after the construction of the array, to replace these % values by the correct ones (since we know the number of rows and columns of % the array). % \begin{macrocode} \cs_new_protected:Npn \@@_adjust_pos_of_blocks_seq: { \seq_gset_map_x:NNn \g_@@_pos_of_blocks_seq \g_@@_pos_of_blocks_seq { \@@_adjust_pos_of_blocks_seq_i:nnnnn ##1 } } % \end{macrocode} % % The following command must \emph{not} be protected. % \begin{macrocode} \cs_new:Npn \@@_adjust_pos_of_blocks_seq_i:nnnnn #1 #2 #3 #4 #5 { { #1 } { #2 } { \int_compare:nNnTF { #3 } > { 99 } { \int_use:N \c@iRow } { #3 } } { \int_compare:nNnTF { #4 } > { 99 } { \int_use:N \c@jCol } { #4 } } { #5 } } % \end{macrocode} % % \bigskip % We recall that, when externalization is used, |\tikzpicture| and % |\endtikzpicture| (or |\pgfpicture| and |\endpgfpicture|) must be directly % ``visible''. That's why we have to define the adequate version of % |\@@_draw_dotted_lines:| whether Tikz is loaded or not (in that case, only % \textsc{pgf} is loaded). % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \cs_new_protected:Npx \@@_draw_dotted_lines: { \c_@@_pgfortikzpicture_tl \@@_draw_dotted_lines_i: \c_@@_endpgfortikzpicture_tl } } % \end{macrocode} % % The following command \emph{must} be protected because it will appear in the % construction of the command |\@@_draw_dotted_lines:|. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_dotted_lines_i: { \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \g_@@_HVdotsfor_lines_tl \g_@@_Vdots_lines_tl \g_@@_Ddots_lines_tl \g_@@_Iddots_lines_tl \g_@@_Cdots_lines_tl \g_@@_Ldots_lines_tl } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_restore_iRow_jCol: { \cs_if_exist:NT \theiRow { \int_gset_eq:NN \c@iRow \l_@@_old_iRow_int } \cs_if_exist:NT \thejCol { \int_gset_eq:NN \c@jCol \l_@@_old_jCol_int } } % \end{macrocode} % % \bigskip % We define a new \textsc{pgf} shape for the diag nodes because we want to % provide a anchor called |.5| for those nodes. % \begin{macrocode} \pgfdeclareshape { @@_diag_node } { \savedanchor { \five } { \dim_gset_eq:NN \pgf@x \l_tmpa_dim \dim_gset_eq:NN \pgf@y \l_tmpb_dim } \anchor { 5 } { \five } \anchor { center } { \pgfpointorigin } } % \end{macrocode} % % % % \bigskip % The following command creates the diagonal nodes (in fact, if the matrix is % not a square matrix, not all the nodes are on the diagonal). % \begin{macrocode} \cs_new_protected:Npn \@@_create_diag_nodes: { \pgfpicture \pgfrememberpicturepositiononpagetrue \int_step_inline:nn { \int_max:nn \c@iRow \c@jCol } { \@@_qpoint:n { col - \int_min:nn { ##1 } { \c@jCol + 1 } } \dim_set_eq:NN \l_tmpa_dim \pgf@x \@@_qpoint:n { row - \int_min:nn { ##1 } { \c@iRow + 1 } } \dim_set_eq:NN \l_tmpb_dim \pgf@y \@@_qpoint:n { col - \int_min:nn { ##1 + 1 } { \c@jCol + 1 } } \dim_set_eq:NN \l_@@_tmpc_dim \pgf@x \@@_qpoint:n { row - \int_min:nn { ##1 + 1 } { \c@iRow + 1 } } \dim_set_eq:NN \l_@@_tmpd_dim \pgf@y \pgftransformshift { \pgfpoint \l_tmpa_dim \l_tmpb_dim } % \end{macrocode} % Now, |\l_tmpa_dim| and |\l_tmpb_dim| become the width and the height of the % node (of shape |@@_diag_node|) that we will construct. % \begin{macrocode} \dim_set:Nn \l_tmpa_dim { ( \l_@@_tmpc_dim - \l_tmpa_dim ) / 2 } \dim_set:Nn \l_tmpb_dim { ( \l_@@_tmpd_dim - \l_tmpb_dim ) / 2 } \pgfnode { @@_diag_node } { center } { } { \@@_env: - ##1 } { } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - ##1 } { \@@_env: - ##1 } } } % \end{macrocode} % Now, the last node. Of course, that is only a |coordinate| because there is % not |.5| anchor for that node. % \begin{macrocode} \int_set:Nn \l_tmpa_int { \int_max:nn \c@iRow \c@jCol + 1 } \@@_qpoint:n { row - \int_min:nn { \l_tmpa_int } { \c@iRow + 1 } } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint:n { col - \int_min:nn { \l_tmpa_int } { \c@jCol + 1 } } \pgfcoordinate { \@@_env: - \int_use:N \l_tmpa_int } { \pgfpoint \pgf@x \l_tmpa_dim } \pgfnodealias { \@@_env: - last } { \@@_env: - \int_eval:n { \int_max:nn \c@iRow \c@jCol + 1 } } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - \int_use:N \l_tmpa_int } { \@@_env: - \int_use:N \l_tmpa_int } \pgfnodealias { \l_@@_name_str - last } { \@@_env: - last } } \endpgfpicture } % \end{macrocode} % % % \bigskip % \section{We draw the dotted lines} % % A dotted line will be said \emph{open} in one of its extremities when it stops % on the edge of the matrix and \emph{closed} otherwise. In the following % matrix, the dotted line is closed on its left extremity and open on its right. % \[ \begin{pNiceMatrix} % a+b+c & a+b & a\\ % a & \Cdots \\ % a & a+b & a+b+c % \end{pNiceMatrix}\] % % % \bigskip % The command |\@@_find_extremities_of_line:nnnn| takes four arguments: % % \begin{itemize} % \item the first argument is the row of the cell where the command was issued; % \item the second argument is the column of the cell where the command was % issued; % \item the third argument is the $x$-value of the orientation vector of the % line; % \item the fourth argument is the $y$-value of the orientation vector of the % line. % \end{itemize} % % This command computes: % % \begin{itemize} % \item |\l_@@_initial_i_int| and |\l_@@_initial_j_int| which are the % coordinates of one extremity of the line; % \item |\l_@@_final_i_int| and |\l_@@_final_j_int| which are the coordinates of % the other extremity of the line; % \item |\l_@@_initial_open_bool| and |\l_@@_final_open_bool| to indicate % whether the extremities are open or not. % \end{itemize} % % \begin{macrocode} \cs_new_protected:Npn \@@_find_extremities_of_line:nnnn #1 #2 #3 #4 { % \end{macrocode} % First, we declare the current cell as ``dotted'' because we forbide % intersections of dotted lines. % \begin{macrocode} \cs_set:cpn { @@ _ dotted _ #1 - #2 } { } % \end{macrocode} % Initialization of variables. % \begin{macrocode} \int_set:Nn \l_@@_initial_i_int { #1 } \int_set:Nn \l_@@_initial_j_int { #2 } \int_set:Nn \l_@@_final_i_int { #1 } \int_set:Nn \l_@@_final_j_int { #2 } % \end{macrocode} % We will do two loops: one when determinating the initial cell and the other % when determinating the final cell. The boolean |\l_@@_stop_loop_bool| will be % used to control these loops. In the first loop, we search the ``final'' % extremity of the line. % \begin{macrocode} \bool_set_false:N \l_@@_stop_loop_bool \bool_do_until:Nn \l_@@_stop_loop_bool { \int_add:Nn \l_@@_final_i_int { #3 } \int_add:Nn \l_@@_final_j_int { #4 } % \end{macrocode} % We test if we are still in the matrix. % \begin{macrocode} \bool_set_false:N \l_@@_final_open_bool \int_compare:nNnTF \l_@@_final_i_int > \l_@@_row_max_int { \int_compare:nNnTF { #3 } = \c_one_int { \bool_set_true:N \l_@@_final_open_bool } { \int_compare:nNnT \l_@@_final_j_int > \l_@@_col_max_int { \bool_set_true:N \l_@@_final_open_bool } } } { \int_compare:nNnTF \l_@@_final_j_int < \l_@@_col_min_int { \int_compare:nNnT { #4 } = { -1 } { \bool_set_true:N \l_@@_final_open_bool } } { \int_compare:nNnT \l_@@_final_j_int > \l_@@_col_max_int { \int_compare:nNnT { #4 } = \c_one_int { \bool_set_true:N \l_@@_final_open_bool } } } } \bool_if:NTF \l_@@_final_open_bool % \end{macrocode} % If we are outside the matrix, we have found the extremity of the dotted line % and it's an \emph{open} extremity. % \begin{macrocode} { % \end{macrocode} % We do a step backwards. % \begin{macrocode} \int_sub:Nn \l_@@_final_i_int { #3 } \int_sub:Nn \l_@@_final_j_int { #4 } \bool_set_true:N \l_@@_stop_loop_bool } % \end{macrocode} % If we are in the matrix, we test whether the cell is empty. If it's not the % case, we stop the loop because we have found the correct values for % |\l_@@_final_i_int| and |\l_@@_final_j_int|. % \begin{macrocode} { \cs_if_exist:cTF { @@ _ dotted _ \int_use:N \l_@@_final_i_int - \int_use:N \l_@@_final_j_int } { \int_sub:Nn \l_@@_final_i_int { #3 } \int_sub:Nn \l_@@_final_j_int { #4 } \bool_set_true:N \l_@@_final_open_bool \bool_set_true:N \l_@@_stop_loop_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_final_i_int - \int_use:N \l_@@_final_j_int } { \bool_set_true:N \l_@@_stop_loop_bool } % \end{macrocode} % If the case is empty, we declare that the cell as non-empty. Indeed, we will % draw a dotted line and the cell will be on that dotted line. All the cells of % a dotted line have to be marked as ``dotted'' because we don't want % intersections between dotted lines. We recall that the research of the % extremities of the lines are all done in the same TeX group (the group of the % environment), even though, when the extremities are found, each line is % drawn in a TeX group that we will open for the options of the line. % \begin{macrocode} { \cs_set:cpn { @@ _ dotted _ \int_use:N \l_@@_final_i_int - \int_use:N \l_@@_final_j_int } { } } } } } % \end{macrocode} % % \interitem % For |\l_@@_initial_i_int| and |\l_@@_initial_j_int| the programmation is % similar to the previous one. % \begin{macrocode} \bool_set_false:N \l_@@_stop_loop_bool \bool_do_until:Nn \l_@@_stop_loop_bool { \int_sub:Nn \l_@@_initial_i_int { #3 } \int_sub:Nn \l_@@_initial_j_int { #4 } \bool_set_false:N \l_@@_initial_open_bool \int_compare:nNnTF \l_@@_initial_i_int < \l_@@_row_min_int { \int_compare:nNnTF { #3 } = \c_one_int { \bool_set_true:N \l_@@_initial_open_bool } { \int_compare:nNnT \l_@@_initial_j_int = { \l_@@_col_min_int - 1 } { \bool_set_true:N \l_@@_initial_open_bool } } } { \int_compare:nNnTF \l_@@_initial_j_int < \l_@@_col_min_int { \int_compare:nNnT { #4 } = \c_one_int { \bool_set_true:N \l_@@_initial_open_bool } } { \int_compare:nNnT \l_@@_initial_j_int > \l_@@_col_max_int { \int_compare:nNnT { #4 } = { -1 } { \bool_set_true:N \l_@@_initial_open_bool } } } } \bool_if:NTF \l_@@_initial_open_bool { \int_add:Nn \l_@@_initial_i_int { #3 } \int_add:Nn \l_@@_initial_j_int { #4 } \bool_set_true:N \l_@@_stop_loop_bool } { \cs_if_exist:cTF { @@ _ dotted _ \int_use:N \l_@@_initial_i_int - \int_use:N \l_@@_initial_j_int } { \int_add:Nn \l_@@_initial_i_int { #3 } \int_add:Nn \l_@@_initial_j_int { #4 } \bool_set_true:N \l_@@_initial_open_bool \bool_set_true:N \l_@@_stop_loop_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_initial_i_int - \int_use:N \l_@@_initial_j_int } { \bool_set_true:N \l_@@_stop_loop_bool } { \cs_set:cpn { @@ _ dotted _ \int_use:N \l_@@_initial_i_int - \int_use:N \l_@@_initial_j_int } { } } } } } % \end{macrocode} % We remind the rectangle described by all the dotted lines in order to respect % the corresponding virtual ``block'' when drawing the horizontal and vertical % rules. % \begin{macrocode} \seq_gput_right:Nx \g_@@_pos_of_xdots_seq { { \int_use:N \l_@@_initial_i_int } % \end{macrocode} % Be careful: with |\Iddots|, |\l_@@_final_j_int| is inferior to % |\l_@@_initial_j_int|. That's why we use |\int_min:nn| and |\int_max:nn|. % \begin{macrocode} { \int_min:nn \l_@@_initial_j_int \l_@@_final_j_int } { \int_use:N \l_@@_final_i_int } { \int_max:nn \l_@@_initial_j_int \l_@@_final_j_int } { } % for the name of the block } } % \end{macrocode} % % \medskip % If the final user uses the key |xdots/shorten| in |\NiceMatrixOptions| or at the % level of an environment (such as |{pNiceMatrix}|, etc.), only the so called % ``closed extremities'' will be shortened by that key. The following command % will be used \emph{after} the detection of the extremities of a dotted line % (hence at a time when we known wheter the extremities are closed or open) but % before the analyse of the keys of the individual command |\Cdots|, |\Vdots|. % Hence, the keys |shorten|, |shorten-start| and |shorten-end| of that % individual command will be applied. % \begin{macrocode} \cs_new_protected:Npn \@@_open_shorten: { \bool_if:NT \l_@@_initial_open_bool { \dim_zero:N \l_@@_xdots_shorten_start_dim } \bool_if:NT \l_@@_final_open_bool { \dim_zero:N \l_@@_xdots_shorten_end_dim } } % \end{macrocode} % % \medskip % The following commmand (\emph{when it will be written}) will set the four % counters |\l_@@_row_min_int|, |\l_@@_row_max_int|, |\l_@@_col_min_int| and % |\l_@@_col_max_int| to the intersections of the sub-matrices which contains % the cell of row |#1| and column |#2|. As of now, it's only the whole array % (excepted exterior rows and columns). % \begin{macrocode} \cs_new_protected:Npn \@@_adjust_to_submatrix:nn #1 #2 { \int_set:Nn \l_@@_row_min_int 1 \int_set:Nn \l_@@_col_min_int 1 \int_set_eq:NN \l_@@_row_max_int \c@iRow \int_set_eq:NN \l_@@_col_max_int \c@jCol % \end{macrocode} % We do a loop over all the submatrices specified in the |code-before|. We have % stored the position of all those submatrices in |\g_@@_submatrix_seq|. % \begin{macrocode} \seq_map_inline:Nn \g_@@_submatrix_seq { \@@_adjust_to_submatrix:nnnnnn { #1 } { #2 } ##1 } } % \end{macrocode} % % \medskip % |#1| and |#2| are the numbers of row and columns of the cell where the command % of dotted line (ex.: |\Vdots|) has been issued. |#3|, |#4|, |#5| and |#6| are % the specification (in $i$ and $j$) of the submatrix we are analyzing. % \begin{macrocode} \cs_set_protected:Npn \@@_adjust_to_submatrix:nnnnnn #1 #2 #3 #4 #5 #6 { \int_compare:nNnF { #3 } > { #1 } { \int_compare:nNnF { #1 } > { #5 } { \int_compare:nNnF { #4 } > { #2 } { \int_compare:nNnF { #2 } > { #6 } { \int_set:Nn \l_@@_row_min_int { \int_max:nn \l_@@_row_min_int { #3 } } \int_set:Nn \l_@@_col_min_int { \int_max:nn \l_@@_col_min_int { #4 } } \int_set:Nn \l_@@_row_max_int { \int_min:nn \l_@@_row_max_int { #5 } } \int_set:Nn \l_@@_col_max_int { \int_min:nn \l_@@_col_max_int { #6 } } } } } } } % \end{macrocode} % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_set_initial_coords: { \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y } \cs_new_protected:Npn \@@_set_final_coords: { \dim_set_eq:NN \l_@@_x_final_dim \pgf@x \dim_set_eq:NN \l_@@_y_final_dim \pgf@y } \cs_new_protected:Npn \@@_set_initial_coords_from_anchor:n #1 { \pgfpointanchor { \@@_env: - \int_use:N \l_@@_initial_i_int - \int_use:N \l_@@_initial_j_int } { #1 } \@@_set_initial_coords: } \cs_new_protected:Npn \@@_set_final_coords_from_anchor:n #1 { \pgfpointanchor { \@@_env: - \int_use:N \l_@@_final_i_int - \int_use:N \l_@@_final_j_int } { #1 } \@@_set_final_coords: } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_open_x_initial_dim: { \dim_set_eq:NN \l_@@_x_initial_dim \c_max_dim \int_step_inline:nnn \l_@@_first_row_int \g_@@_row_total_int { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - ##1 - \int_use:N \l_@@_initial_j_int } { \pgfpointanchor { \@@_env: - ##1 - \int_use:N \l_@@_initial_j_int } { west } \dim_set:Nn \l_@@_x_initial_dim { \dim_min:nn \l_@@_x_initial_dim \pgf@x } } } % \end{macrocode} % If, in fact, all the cells of the column are empty (no PGF/Tikz nodes in % those cells). % \begin{macrocode} \dim_compare:nNnT \l_@@_x_initial_dim = \c_max_dim { \@@_qpoint:n { col - \int_use:N \l_@@_initial_j_int } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \dim_add:Nn \l_@@_x_initial_dim \col@sep } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_open_x_final_dim: { \dim_set:Nn \l_@@_x_final_dim { - \c_max_dim } \int_step_inline:nnn \l_@@_first_row_int \g_@@_row_total_int { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - ##1 - \int_use:N \l_@@_final_j_int } { \pgfpointanchor { \@@_env: - ##1 - \int_use:N \l_@@_final_j_int } { east } \dim_set:Nn \l_@@_x_final_dim { \dim_max:nn \l_@@_x_final_dim \pgf@x } } } % \end{macrocode} % If, in fact, all the cells of the columns are empty (no PGF/Tikz nodes in % those cells). % \begin{macrocode} \dim_compare:nNnT \l_@@_x_final_dim = { - \c_max_dim } { \@@_qpoint:n { col - \int_eval:n { \l_@@_final_j_int + 1 } } \dim_set_eq:NN \l_@@_x_final_dim \pgf@x \dim_sub:Nn \l_@@_x_final_dim \col@sep } } % \end{macrocode} % % % % \interitem % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Ldots:nnn #1 #2 #3 { \@@_adjust_to_submatrix:nn { #1 } { #2 } \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 0 1 % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \@@_open_shorten: \int_if_zero:nTF { #1 } { \color { nicematrix-first-row } } { % \end{macrocode} % We remind that, when there is a ``last row'' |\l_@@_last_row_int| will always % be (after the construction of the array) the number of that ``last row'' even % if the option |last-row| has been used without value. % \begin{macrocode} \int_compare:nNnT { #1 } = \l_@@_last_row_int { \color { nicematrix-last-row } } } \keys_set:nn { NiceMatrix / xdots } { #3 } \tl_if_empty:oF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Ldots: \group_end: } } % \end{macrocode} % % % \medskip % The command |\@@_actually_draw_Ldots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % % The following function is also used by |\Hdotsfor|. % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Ldots: { \bool_if:NTF \l_@@_initial_open_bool { \@@_open_x_initial_dim: \@@_qpoint:n { row - \int_use:N \l_@@_initial_i_int - base } \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y } { \@@_set_initial_coords_from_anchor:n { base~east } } \bool_if:NTF \l_@@_final_open_bool { \@@_open_x_final_dim: \@@_qpoint:n { row - \int_use:N \l_@@_final_i_int - base } \dim_set_eq:NN \l_@@_y_final_dim \pgf@y } { \@@_set_final_coords_from_anchor:n { base~west } } % \end{macrocode} % Now the case of a |\Hdotsfor| (or when there is only a |\Ldots|) in the ``last % row'' (that case will probably arise when the final user draws an arrow to % indicate the number of columns of the matrix). In the ``first row'', we don't % need any adjustment. % \begin{macrocode} \bool_lazy_all:nTF { \l_@@_initial_open_bool \l_@@_final_open_bool { \int_compare_p:nNn \l_@@_initial_i_int = \l_@@_last_row_int } } { \dim_add:Nn \l_@@_y_initial_dim \c_@@_shift_Ldots_last_row_dim \dim_add:Nn \l_@@_y_final_dim \c_@@_shift_Ldots_last_row_dim } % \end{macrocode} % We raise the line of a quantity equal to the radius of the dots because we % want the dots really ``on'' the line of texte. Of course, maybe we should not % do that when the option |line-style| is used (?). % \begin{macrocode} { \dim_add:Nn \l_@@_y_initial_dim \l_@@_xdots_radius_dim \dim_add:Nn \l_@@_y_final_dim \l_@@_xdots_radius_dim } \@@_draw_line: } % \end{macrocode} % % \interitem % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Cdots:nnn #1 #2 #3 { \@@_adjust_to_submatrix:nn { #1 } { #2 } \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 0 1 % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \@@_open_shorten: \int_if_zero:nTF { #1 } { \color { nicematrix-first-row } } { % \end{macrocode} % We remind that, when there is a ``last row'' |\l_@@_last_row_int| will always % be (after the construction of the array) the number of that ``last row'' even % if the option |last-row| has been used without value. % \begin{macrocode} \int_compare:nNnT { #1 } = \l_@@_last_row_int { \color { nicematrix-last-row } } } \keys_set:nn { NiceMatrix / xdots } { #3 } \tl_if_empty:oF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Cdots: \group_end: } } % \end{macrocode} % % % \medskip % The command |\@@_actually_draw_Cdots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Cdots: { \bool_if:NTF \l_@@_initial_open_bool { \@@_open_x_initial_dim: } { \@@_set_initial_coords_from_anchor:n { mid~east } } \bool_if:NTF \l_@@_final_open_bool { \@@_open_x_final_dim: } { \@@_set_final_coords_from_anchor:n { mid~west } } \bool_lazy_and:nnTF \l_@@_initial_open_bool \l_@@_final_open_bool { \@@_qpoint:n { row - \int_use:N \l_@@_initial_i_int } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint:n { row - \int_eval:n { \l_@@_initial_i_int + 1 } } \dim_set:Nn \l_@@_y_initial_dim { ( \l_tmpa_dim + \pgf@y ) / 2 } \dim_set_eq:NN \l_@@_y_final_dim \l_@@_y_initial_dim } { \bool_if:NT \l_@@_initial_open_bool { \dim_set_eq:NN \l_@@_y_initial_dim \l_@@_y_final_dim } \bool_if:NT \l_@@_final_open_bool { \dim_set_eq:NN \l_@@_y_final_dim \l_@@_y_initial_dim } } \@@_draw_line: } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_open_y_initial_dim: { \dim_set:Nn \l_@@_y_initial_dim { - \c_max_dim } \int_step_inline:nnn \l_@@_first_col_int \g_@@_col_total_int { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_initial_i_int - ##1 } { \pgfpointanchor { \@@_env: - \int_use:N \l_@@_initial_i_int - ##1 } { north } \dim_set:Nn \l_@@_y_initial_dim { \dim_max:nn \l_@@_y_initial_dim \pgf@y } } } \dim_compare:nNnT \l_@@_y_initial_dim = { - \c_max_dim } { \@@_qpoint:n { row - \int_use:N \l_@@_initial_i_int - base } \dim_set:Nn \l_@@_y_initial_dim { \fp_to_dim:n { \pgf@y + ( \box_ht:N \strutbox + \extrarowheight ) * \arraystretch } } } } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_open_y_final_dim: { \dim_set_eq:NN \l_@@_y_final_dim \c_max_dim \int_step_inline:nnn \l_@@_first_col_int \g_@@_col_total_int { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_final_i_int - ##1 } { \pgfpointanchor { \@@_env: - \int_use:N \l_@@_final_i_int - ##1 } { south } \dim_set:Nn \l_@@_y_final_dim { \dim_min:nn \l_@@_y_final_dim \pgf@y } } } \dim_compare:nNnT \l_@@_y_final_dim = \c_max_dim { \@@_qpoint:n { row - \int_use:N \l_@@_final_i_int - base } \dim_set:Nn \l_@@_y_final_dim { \fp_to_dim:n { \pgf@y - ( \box_dp:N \strutbox ) * \arraystretch } } } } % \end{macrocode} % % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Vdots:nnn #1 #2 #3 { \@@_adjust_to_submatrix:nn { #1 } { #2 } \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 1 0 % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \@@_open_shorten: \int_if_zero:nTF { #2 } { \color { nicematrix-first-col } } { \int_compare:nNnT { #2 } = \l_@@_last_col_int { \color { nicematrix-last-col } } } \keys_set:nn { NiceMatrix / xdots } { #3 } \tl_if_empty:oF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Vdots: \group_end: } } % \end{macrocode} % % \bigskip % The command |\@@_actually_draw_Vdots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % % The following function is also used by |\Vdotsfor|. % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Vdots: { % \end{macrocode} % % First, the case of a dotted line open on both sides. % \begin{macrocode} \bool_lazy_and:nnTF \l_@@_initial_open_bool \l_@@_final_open_bool % \end{macrocode} % % We have to determine the $x$-value of the vertical rule that we will have % to draw. % \begin{macrocode} { \@@_open_y_initial_dim: \@@_open_y_final_dim: \int_if_zero:nTF \l_@@_initial_j_int % \end{macrocode} % We have a dotted line open on both sides in the ``first column''. % \begin{macrocode} { \@@_qpoint:n { col - 1 } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \dim_sub:Nn \l_@@_x_initial_dim \l_@@_left_margin_dim \dim_sub:Nn \l_@@_x_initial_dim \l_@@_extra_left_margin_dim \dim_sub:Nn \l_@@_x_initial_dim \c_@@_shift_exterior_Vdots_dim } { \bool_lazy_and:nnTF { \int_compare_p:nNn \l_@@_last_col_int > { -2 } } { \int_compare_p:nNn \l_@@_initial_j_int = \g_@@_col_total_int } % \end{macrocode} % We have a dotted line open on both sides in the ``last column''. % \begin{macrocode} { \@@_qpoint:n { col - \int_use:N \l_@@_initial_j_int } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \dim_add:Nn \l_@@_x_initial_dim \l_@@_right_margin_dim \dim_add:Nn \l_@@_x_initial_dim \l_@@_extra_right_margin_dim \dim_add:Nn \l_@@_x_initial_dim \c_@@_shift_exterior_Vdots_dim } % \end{macrocode} % We have a dotted line open on both sides which is \emph{not} in an exterior column. % \begin{macrocode} { \@@_qpoint:n { col - \int_use:N \l_@@_initial_j_int } \dim_set_eq:NN \l_tmpa_dim \pgf@x \@@_qpoint:n { col - \int_eval:n { \l_@@_initial_j_int + 1 } } \dim_set:Nn \l_@@_x_initial_dim { ( \pgf@x + \l_tmpa_dim ) / 2 } } } } % \end{macrocode} % % Now, the dotted line is \emph{not} open on both sides (maybe open on only one side). % % The boolean |\l_tmpa_bool| will indicate whether the column is of type |l| or % may be considered as if. % \begin{macrocode} { \bool_set_false:N \l_tmpa_bool \bool_if:NF \l_@@_initial_open_bool { \bool_if:NF \l_@@_final_open_bool { \@@_set_initial_coords_from_anchor:n { south~west } \@@_set_final_coords_from_anchor:n { north~west } \bool_set:Nn \l_tmpa_bool { \dim_compare_p:nNn \l_@@_x_initial_dim = \l_@@_x_final_dim } } } % \end{macrocode} % Now, we try to determine whether the column is of type |c| or may be % considered as if. % \begin{macrocode} \bool_if:NTF \l_@@_initial_open_bool { \@@_open_y_initial_dim: \@@_set_final_coords_from_anchor:n { north } \dim_set_eq:NN \l_@@_x_initial_dim \l_@@_x_final_dim } { \@@_set_initial_coords_from_anchor:n { south } \bool_if:NTF \l_@@_final_open_bool \@@_open_y_final_dim: % \end{macrocode} % Now the case where both extremities are closed. The first conditional tests % whether the column is of type |c| or may be considered as if. % \begin{macrocode} { \@@_set_final_coords_from_anchor:n { north } \dim_compare:nNnF \l_@@_x_initial_dim = \l_@@_x_final_dim { \dim_set:Nn \l_@@_x_initial_dim { \bool_if:NTF \l_tmpa_bool \dim_min:nn \dim_max:nn \l_@@_x_initial_dim \l_@@_x_final_dim } } } } } \dim_set_eq:NN \l_@@_x_final_dim \l_@@_x_initial_dim \@@_draw_line: } % \end{macrocode} % % \interitem % For the diagonal lines, the situation is a bit more complicated because, by % default, we parallelize the diagonals lines. The first diagonal line is drawn % and then, all the other diagonal lines are drawn parallel to the first one. % % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Ddots:nnn #1 #2 #3 { \@@_adjust_to_submatrix:nn { #1 } { #2 } \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 1 1 % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \@@_open_shorten: \keys_set:nn { NiceMatrix / xdots } { #3 } \tl_if_empty:oF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Ddots: \group_end: } } % \end{macrocode} % % \bigskip % The command |\@@_actually_draw_Ddots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Ddots: { \bool_if:NTF \l_@@_initial_open_bool { \@@_open_y_initial_dim: \@@_open_x_initial_dim: } { \@@_set_initial_coords_from_anchor:n { south~east } } \bool_if:NTF \l_@@_final_open_bool { \@@_open_x_final_dim: \dim_set_eq:NN \l_@@_x_final_dim \pgf@x } { \@@_set_final_coords_from_anchor:n { north~west } } % \end{macrocode} % We have retrieved the coordinates in the usual way (they are stored in % |\l_@@_x_initial_dim|, etc.). If the parallelization of the diagonals is set, % we will have (maybe) to adjust the fourth coordinate. % \begin{macrocode} \bool_if:NT \l_@@_parallelize_diags_bool { \int_gincr:N \g_@@_ddots_int % \end{macrocode} % We test if the diagonal line is the first one (the counter |\g_@@_ddots_int| % is created for this usage). % \begin{macrocode} \int_compare:nNnTF \g_@@_ddots_int = \c_one_int % \end{macrocode} % If the diagonal line is the first one, we have no adjustment of the line to do % but we store the $\Delta_x$ and the $\Delta_y$ of the line because these % values will be used to draw the others diagonal lines parallels to the first % one. % \begin{macrocode} { \dim_gset:Nn \g_@@_delta_x_one_dim { \l_@@_x_final_dim - \l_@@_x_initial_dim } \dim_gset:Nn \g_@@_delta_y_one_dim { \l_@@_y_final_dim - \l_@@_y_initial_dim } } % \end{macrocode} % If the diagonal line is not the first one, we have to adjust the second % extremity of the line by modifying the coordinate |\l_@@_x_initial_dim|. % \begin{macrocode} { \dim_set:Nn \l_@@_y_final_dim { \l_@@_y_initial_dim + ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn \g_@@_delta_y_one_dim \g_@@_delta_x_one_dim } } } \@@_draw_line: } % \end{macrocode} % % \bigskip % We draw the |\Iddots| diagonals in the same way. % % The first and the second arguments are the coordinates of the cell where the % command has been issued. The third argument is the list of the options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_Iddots:nnn #1 #2 #3 { \@@_adjust_to_submatrix:nn { #1 } { #2 } \cs_if_free:cT { @@ _ dotted _ #1 - #2 } { \@@_find_extremities_of_line:nnnn { #1 } { #2 } 1 { -1 } % \end{macrocode} % The previous command may have changed the current environment by marking some % cells as ``dotted'', but, fortunately, it is outside the group for the options % of the line. % \begin{macrocode} \group_begin: \@@_open_shorten: \keys_set:nn { NiceMatrix / xdots } { #3 } \tl_if_empty:oF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Iddots: \group_end: } } % \end{macrocode} % % \bigskip % The command |\@@_actually_draw_Iddots:| has the following implicit arguments: % \begin{itemize} % \item |\l_@@_initial_i_int| % \item |\l_@@_initial_j_int| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_i_int| % \item |\l_@@_final_j_int| % \item |\l_@@_final_open_bool|. % \end{itemize} % % \begin{macrocode} \cs_new_protected:Npn \@@_actually_draw_Iddots: { \bool_if:NTF \l_@@_initial_open_bool { \@@_open_y_initial_dim: \@@_open_x_initial_dim: } { \@@_set_initial_coords_from_anchor:n { south~west } } \bool_if:NTF \l_@@_final_open_bool { \@@_open_y_final_dim: \@@_open_x_final_dim: } { \@@_set_final_coords_from_anchor:n { north~east } } \bool_if:NT \l_@@_parallelize_diags_bool { \int_gincr:N \g_@@_iddots_int \int_compare:nNnTF \g_@@_iddots_int = \c_one_int { \dim_gset:Nn \g_@@_delta_x_two_dim { \l_@@_x_final_dim - \l_@@_x_initial_dim } \dim_gset:Nn \g_@@_delta_y_two_dim { \l_@@_y_final_dim - \l_@@_y_initial_dim } } { \dim_set:Nn \l_@@_y_final_dim { \l_@@_y_initial_dim + ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn \g_@@_delta_y_two_dim \g_@@_delta_x_two_dim } } } \@@_draw_line: } % \end{macrocode} % % % \bigskip % \section{The actual instructions for drawing the dotted lines with Tikz} % % The command |\@@_draw_line:| should be used in a |{pgfpicture}|. It has six % implicit arguments: % % \begin{itemize} % \item |\l_@@_x_initial_dim| % \item |\l_@@_y_initial_dim| % \item |\l_@@_x_final_dim| % \item |\l_@@_y_final_dim| % \item |\l_@@_initial_open_bool| % \item |\l_@@_final_open_bool| % \end{itemize} % % % \begin{macrocode} \cs_new_protected:Npn \@@_draw_line: { \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \bool_lazy_or:nnTF { \tl_if_eq_p:NN \l_@@_xdots_line_style_tl \c_@@_standard_tl } \l_@@_dotted_bool \@@_draw_standard_dotted_line: \@@_draw_unstandard_dotted_line: } % \end{macrocode} % % \medskip % We have to do a special construction with |\exp_args:No| to be able to put in % the list of options in the correct place in the Tikz instruction. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_unstandard_dotted_line: { \begin { scope } \@@_draw_unstandard_dotted_line:o { \l_@@_xdots_line_style_tl , \l_@@_xdots_color_tl } } % \end{macrocode} % We have used the fact that, in \textsc{pgf}, un color name can be put directly % in a list of options (that's why we have put diredtly |\l_@@_xdots_color_tl|). % % \smallskip % The argument of |\@@_draw_unstandard_dotted_line:n| is, in fact, the list of options. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_unstandard_dotted_line:n #1 { \@@_draw_unstandard_dotted_line:nooo { #1 } \l_@@_xdots_up_tl \l_@@_xdots_down_tl \l_@@_xdots_middle_tl } \cs_generate_variant:Nn \@@_draw_unstandard_dotted_line:n { o } % \end{macrocode} % % % \bigskip % The following Tikz styles are for the three labels (set by the symbols |_|, % |^| and |=|) of a continous line with a non-standard style. % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { tikz } { \tikzset { @@_node_above / .style = { sloped , above } , @@_node_below / .style = { sloped , below } , @@_node_middle / .style = { sloped , inner~sep = \c_@@_innersep_middle_dim } } } { } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_draw_unstandard_dotted_line:nnnn #1 #2 #3 #4 { % \end{macrocode} % We take into account the parameters |xdots/shorten-start| and % |xdots/shorten-end| ``by hand'' because, when we use the key |shorten >| and % |shorten <| of TikZ in the command |\draw|, we don't have the expected output % with |{decorate,decoration=brace}| is used. % % \medskip % The dimension |\l_@@_l_dim| is the length $\ell$ of the line to draw. We use % the floating point reals of the L3 programming layer to compute this length. % \begin{macrocode} \dim_zero_new:N \l_@@_l_dim \dim_set:Nn \l_@@_l_dim { \fp_to_dim:n { sqrt ( ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) ^ 2 + ( \l_@@_y_final_dim - \l_@@_y_initial_dim ) ^ 2 ) } } % \end{macrocode} % It seems that, during the first compilations, the value of |\l_@@_l_dim| may % be erroneous (equal to zero or very large). We must detect these cases % because they would cause errors during the drawing of the dotted line. Maybe % we should also write something in the |aux| file to say that one more % compilation should be done. % \begin{macrocode} \dim_compare:nNnT \l_@@_l_dim < \c_@@_max_l_dim { \dim_compare:nNnT \l_@@_l_dim > { 1 pt } \@@_draw_unstandard_dotted_line_i: } % \end{macrocode} % % If the key |xdots/horizontal-labels| has been used. % \begin{macrocode} \bool_if:NT \l_@@_xdots_h_labels_bool { \tikzset { @@_node_above / .style = { auto = left } , @@_node_below / .style = { auto = right } , @@_node_middle / .style = { inner~sep = \c_@@_innersep_middle_dim } } } \tl_if_empty:nF { #4 } { \tikzset { @@_node_middle / .append~style = { fill = white } } } \draw [ #1 ] ( \l_@@_x_initial_dim , \l_@@_y_initial_dim ) % \end{macrocode} % Be careful: We can't put |\c_math_toggle_token| instead of |$| in the % following lines because we are in the contents of Tikz nodes (and they will be % \emph{rescanned} if the Tikz library \pkg{babel} is loaded). % \begin{macrocode} -- node [ @@_node_middle] { $ \scriptstyle #4 $ } node [ @@_node_below ] { $ \scriptstyle #3 $ } node [ @@_node_above ] { $ \scriptstyle #2 $ } ( \l_@@_x_final_dim , \l_@@_y_final_dim ) ; \end { scope } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_draw_unstandard_dotted_line_i: { \dim_set:Nn \l_tmpa_dim { \l_@@_x_initial_dim + ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn \l_@@_xdots_shorten_start_dim \l_@@_l_dim } \dim_set:Nn \l_tmpb_dim { \l_@@_y_initial_dim + ( \l_@@_y_final_dim - \l_@@_y_initial_dim ) * \dim_ratio:nn \l_@@_xdots_shorten_start_dim \l_@@_l_dim } \dim_set:Nn \l_@@_tmpc_dim { \l_@@_x_final_dim - ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn \l_@@_xdots_shorten_end_dim \l_@@_l_dim } \dim_set:Nn \l_@@_tmpd_dim { \l_@@_y_final_dim - ( \l_@@_y_final_dim - \l_@@_y_initial_dim ) * \dim_ratio:nn \l_@@_xdots_shorten_end_dim \l_@@_l_dim } \dim_set_eq:NN \l_@@_x_initial_dim \l_tmpa_dim \dim_set_eq:NN \l_@@_y_initial_dim \l_tmpb_dim \dim_set_eq:NN \l_@@_x_final_dim \l_@@_tmpc_dim \dim_set_eq:NN \l_@@_y_final_dim \l_@@_tmpd_dim } % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \@@_draw_unstandard_dotted_line:nnnn { n o o o } % \end{macrocode} % % \bigskip % The command |\@@_draw_standard_dotted_line:| draws the line with our system of dots % (which gives a dotted line with real rounded dots). % \begin{macrocode} \cs_new_protected:Npn \@@_draw_standard_dotted_line: { \group_begin: % \end{macrocode} % The dimension |\l_@@_l_dim| is the length $\ell$ of the line to draw. We use % the floating point reals of the L3 programming layer to compute this length. % \begin{macrocode} \dim_zero_new:N \l_@@_l_dim \dim_set:Nn \l_@@_l_dim { \fp_to_dim:n { sqrt ( ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) ^ 2 + ( \l_@@_y_final_dim - \l_@@_y_initial_dim ) ^ 2 ) } } % \end{macrocode} % It seems that, during the first compilations, the value of |\l_@@_l_dim| may % be erroneous (equal to zero or very large). We must detect these cases % because they would cause errors during the drawing of the dotted line. Maybe % we should also write something in the |aux| file to say that one more % compilation should be done. % \begin{macrocode} \dim_compare:nNnT \l_@@_l_dim < \c_@@_max_l_dim { \dim_compare:nNnT \l_@@_l_dim > { 1 pt } \@@_draw_standard_dotted_line_i: } \group_end: % \end{macrocode} % \begin{macrocode} \bool_lazy_all:nF { { \tl_if_empty_p:N \l_@@_xdots_up_tl } { \tl_if_empty_p:N \l_@@_xdots_down_tl } { \tl_if_empty_p:N \l_@@_xdots_middle_tl } } \l_@@_labels_standard_dotted_line: } % \end{macrocode} % % \begin{macrocode} \dim_const:Nn \c_@@_max_l_dim { 50 cm } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_draw_standard_dotted_line_i: { % \end{macrocode} % The number of dots will be |\l_tmpa_int + 1|. % \begin{macrocode} \int_set:Nn \l_tmpa_int { \dim_ratio:nn { \l_@@_l_dim - \l_@@_xdots_shorten_start_dim - \l_@@_xdots_shorten_end_dim } \l_@@_xdots_inter_dim } % \end{macrocode} % % \medskip % The dimensions |\l_tmpa_dim| and |\l_tmpb_dim| are the coordinates of the % vector between two dots in the dotted line. % \begin{macrocode} \dim_set:Nn \l_tmpa_dim { ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn \l_@@_xdots_inter_dim \l_@@_l_dim } \dim_set:Nn \l_tmpb_dim { ( \l_@@_y_final_dim - \l_@@_y_initial_dim ) * \dim_ratio:nn \l_@@_xdots_inter_dim \l_@@_l_dim } % \end{macrocode} % % In the loop over the dots, the dimensions |\l_@@_x_initial_dim| and % |\l_@@_y_initial_dim| will be used for the coordinates of the dots. But, % before the loop, we must move until the first dot. % % \begin{macrocode} \dim_gadd:Nn \l_@@_x_initial_dim { ( \l_@@_x_final_dim - \l_@@_x_initial_dim ) * \dim_ratio:nn { \l_@@_l_dim - \l_@@_xdots_inter_dim * \l_tmpa_int + \l_@@_xdots_shorten_start_dim - \l_@@_xdots_shorten_end_dim } { 2 \l_@@_l_dim } } \dim_gadd:Nn \l_@@_y_initial_dim { ( \l_@@_y_final_dim - \l_@@_y_initial_dim ) * \dim_ratio:nn { \l_@@_l_dim - \l_@@_xdots_inter_dim * \l_tmpa_int + \l_@@_xdots_shorten_start_dim - \l_@@_xdots_shorten_end_dim } { 2 \l_@@_l_dim } } \pgf@relevantforpicturesizefalse \int_step_inline:nnn \c_zero_int \l_tmpa_int { \pgfpathcircle { \pgfpoint \l_@@_x_initial_dim \l_@@_y_initial_dim } { \l_@@_xdots_radius_dim } \dim_add:Nn \l_@@_x_initial_dim \l_tmpa_dim \dim_add:Nn \l_@@_y_initial_dim \l_tmpb_dim } \pgfusepathqfill } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \l_@@_labels_standard_dotted_line: { \pgfscope \pgftransformshift { \pgfpointlineattime { 0.5 } { \pgfpoint \l_@@_x_initial_dim \l_@@_y_initial_dim } { \pgfpoint \l_@@_x_final_dim \l_@@_y_final_dim } } \fp_set:Nn \l_tmpa_fp { atand ( \l_@@_y_final_dim - \l_@@_y_initial_dim , \l_@@_x_final_dim - \l_@@_x_initial_dim ) } \pgftransformrotate { \fp_use:N \l_tmpa_fp } \bool_if:NF \l_@@_xdots_h_labels_bool { \fp_zero:N \l_tmpa_fp } \tl_if_empty:NF \l_@@_xdots_middle_tl { \begin { pgfscope } \pgfset { inner~sep = \c_@@_innersep_middle_dim } \pgfnode { rectangle } { center } { \rotatebox { \fp_eval:n { - \l_tmpa_fp } } { \c_math_toggle_token \scriptstyle \l_@@_xdots_middle_tl \c_math_toggle_token } } { } { \pgfsetfillcolor { white } \pgfusepath { fill } } \end { pgfscope } } \tl_if_empty:NF \l_@@_xdots_up_tl { \pgfnode { rectangle } { south } { \rotatebox { \fp_eval:n { - \l_tmpa_fp } } { \c_math_toggle_token \scriptstyle \l_@@_xdots_up_tl \c_math_toggle_token } } { } { \pgfusepath { } } } \tl_if_empty:NF \l_@@_xdots_down_tl { \pgfnode { rectangle } { north } { \rotatebox { \fp_eval:n { - \l_tmpa_fp } } { \c_math_toggle_token \scriptstyle \l_@@_xdots_down_tl \c_math_toggle_token } } { } { \pgfusepath { } } } \endpgfscope } % \end{macrocode} % % \bigskip % \section{User commands available in the new environments} % % % The commands |\@@_Ldots|, |\@@_Cdots|, |\@@_Vdots|, |\@@_Ddots| and % |\@@_Iddots| will be linked to |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots| and % |\Iddots| in the environments |{NiceArray}| (the other environments of % \pkg{nicematrix} rely upon |{NiceArray}|). % % % \medskip % The syntax of these commands uses the character |_| as embellishment and % thats' why we have to insert a character |_| in the \emph{arg spec} of these % commands. However, we don't know the future catcode of |_| in the main % document (maybe the user will use \pkg{underscore}, and, in that case, the % catcode is $13$ because \pkg{underscore} activates |_|). That's why these % commands will be defined in a |\hook_gput_code:nnn { begindocument } { . }| % and the \emph{arg spec} will be rescanned. % % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \cs_set_nopar:Npn \l_@@_argspec_tl { m E { _ ^ : } { { } { } { } } } \tl_set_rescan:Nno \l_@@_argspec_tl { } \l_@@_argspec_tl \cs_new_protected:Npn \@@_Ldots { \@@_collect_options:n { \@@_Ldots_i } } \exp_args:NNo \NewDocumentCommand \@@_Ldots_i \l_@@_argspec_tl { \int_if_zero:nTF \c@jCol { \@@_error:nn { in~first~col } \Ldots } { \int_compare:nNnTF \c@jCol = \l_@@_last_col_int { \@@_error:nn { in~last~col } \Ldots } { \@@_instruction_of_type:nnn \c_false_bool { Ldots } { #1 , down = #2 , up = #3 , middle = #4 } } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom { \ensuremath { \@@_old_ldots } } } \bool_gset_true:N \g_@@_empty_cell_bool } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_Cdots { \@@_collect_options:n { \@@_Cdots_i } } \exp_args:NNo \NewDocumentCommand \@@_Cdots_i \l_@@_argspec_tl { \int_if_zero:nTF \c@jCol { \@@_error:nn { in~first~col } \Cdots } { \int_compare:nNnTF \c@jCol = \l_@@_last_col_int { \@@_error:nn { in~last~col } \Cdots } { \@@_instruction_of_type:nnn \c_false_bool { Cdots } { #1 , down = #2 , up = #3 , middle = #4 } } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom { \ensuremath { \@@_old_cdots } } } \bool_gset_true:N \g_@@_empty_cell_bool } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_Vdots { \@@_collect_options:n { \@@_Vdots_i } } \exp_args:NNo \NewDocumentCommand \@@_Vdots_i \l_@@_argspec_tl { \int_if_zero:nTF \c@iRow { \@@_error:nn { in~first~row } \Vdots } { \int_compare:nNnTF \c@iRow = \l_@@_last_row_int { \@@_error:nn { in~last~row } \Vdots } { \@@_instruction_of_type:nnn \c_false_bool { Vdots } { #1 , down = #2 , up = #3 , middle = #4 } } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom { \ensuremath { \@@_old_vdots } } } \bool_gset_true:N \g_@@_empty_cell_bool } % \end{macrocode} % % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_Ddots { \@@_collect_options:n { \@@_Ddots_i } } \exp_args:NNo \NewDocumentCommand \@@_Ddots_i \l_@@_argspec_tl { \int_case:nnF \c@iRow { 0 { \@@_error:nn { in~first~row } \Ddots } \l_@@_last_row_int { \@@_error:nn { in~last~row } \Ddots } } { \int_case:nnF \c@jCol { 0 { \@@_error:nn { in~first~col } \Ddots } \l_@@_last_col_int { \@@_error:nn { in~last~col } \Ddots } } { \keys_set_known:nn { NiceMatrix / Ddots } { #1 } \@@_instruction_of_type:nnn \l_@@_draw_first_bool { Ddots } { #1 , down = #2 , up = #3 , middle = #4 } } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom { \ensuremath { \@@_old_ddots } } } \bool_gset_true:N \g_@@_empty_cell_bool } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_Iddots { \@@_collect_options:n { \@@_Iddots_i } } \exp_args:NNo \NewDocumentCommand \@@_Iddots_i \l_@@_argspec_tl { \int_case:nnF \c@iRow { 0 { \@@_error:nn { in~first~row } \Iddots } \l_@@_last_row_int { \@@_error:nn { in~last~row } \Iddots } } { \int_case:nnF \c@jCol { 0 { \@@_error:nn { in~first~col } \Iddots } \l_@@_last_col_int { \@@_error:nn { in~last~col } \Iddots } } { \keys_set_known:nn { NiceMatrix / Ddots } { #1 } \@@_instruction_of_type:nnn \l_@@_draw_first_bool { Iddots } { #1 , down = #2 , up = #3 , middle = #4 } } } \bool_if:NF \l_@@_nullify_dots_bool { \phantom { \ensuremath { \@@_old_iddots } } } \bool_gset_true:N \g_@@_empty_cell_bool } } % \end{macrocode} % End of the |\AddToHook|. % % % \bigskip % Despite its name, the following set of keys will be used for |\Ddots| but also % for |\Iddots|. % \begin{macrocode} \keys_define:nn { NiceMatrix / Ddots } { draw-first .bool_set:N = \l_@@_draw_first_bool , draw-first .default:n = true , draw-first .value_forbidden:n = true } % \end{macrocode} % % \bigskip % The command |\@@_Hspace:| will be linked to |\hspace| in |{NiceArray}|. % \begin{macrocode} \cs_new_protected:Npn \@@_Hspace: { \bool_gset_true:N \g_@@_empty_cell_bool \hspace } % \end{macrocode} % % \bigskip % In the environments of |nicematrix|, the command |\multicolumn| is redefined. % We will patch the environment |{tabular}| to go back to the previous value of % |\multicolumn|. % \begin{macrocode} \cs_set_eq:NN \@@_old_multicolumn \multicolumn % \end{macrocode} % % % % \bigskip % The command |\@@_Hdotsfor| will be linked to |\Hdotsfor| in % |{NiceArrayWithDelims}|. Tikz nodes are created also in the implicit cells of % the |\Hdotsfor| (maybe we should modify that point). % % \medskip % This command must \emph{not} be protected since it begins with |\multicolumn|. % \begin{macrocode} \cs_new:Npn \@@_Hdotsfor: { \bool_lazy_and:nnTF { \int_if_zero_p:n \c@jCol } { \int_if_zero_p:n \l_@@_first_col_int } { \bool_if:NTF \g_@@_after_col_zero_bool { \multicolumn { 1 } { c } { } \@@_Hdotsfor_i } { \@@_fatal:n { Hdotsfor~in~col~0 } } } { \multicolumn { 1 } { c } { } \@@_Hdotsfor_i } } % \end{macrocode} % % % The command |\@@_Hdotsfor_i| is defined with |\NewDocumentCommand| because it % has an optional argument. Note that such a command defined by % |\NewDocumentCommand| is protected and that's why we have put the % |\multicolumn| before (in the definition of |\@@_Hdotsfor:|). % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \cs_set_nopar:Npn \l_@@_argspec_tl { m m O { } E { _ ^ : } { { } { } { } } } \tl_set_rescan:Nno \l_@@_argspec_tl { } \l_@@_argspec_tl % \end{macrocode} % We don't put |!| before the last optionnal argument for homogeneity with % |\Cdots|, etc. which have only one optional argument. % \begin{macrocode} \cs_new_protected:Npn \@@_Hdotsfor_i { \@@_collect_options:n { \@@_Hdotsfor_ii } } \exp_args:NNo \NewDocumentCommand \@@_Hdotsfor_ii \l_@@_argspec_tl { \tl_gput_right:Nx \g_@@_HVdotsfor_lines_tl { \@@_Hdotsfor:nnnn { \int_use:N \c@iRow } { \int_use:N \c@jCol } { #2 } { #1 , #3 , down = \exp_not:n { #4 } , up = \exp_not:n { #5 } , middle = \exp_not:n { #6 } } } \prg_replicate:nn { #2 - 1 } { & \multicolumn { 1 } { c } { } \cs_set_eq:NN \CodeAfter \@@_CodeAfter_i: } } } % \end{macrocode} % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_Hdotsfor:nnnn #1 #2 #3 #4 { \bool_set_false:N \l_@@_initial_open_bool \bool_set_false:N \l_@@_final_open_bool % \end{macrocode} % For the row, it's easy. % \begin{macrocode} \int_set:Nn \l_@@_initial_i_int { #1 } \int_set_eq:NN \l_@@_final_i_int \l_@@_initial_i_int % \end{macrocode} % For the column, it's a bit more complicated. % \begin{macrocode} \int_compare:nNnTF { #2 } = \c_one_int { \int_set_eq:NN \l_@@_initial_j_int \c_one_int \bool_set_true:N \l_@@_initial_open_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_initial_i_int - \int_eval:n { #2 - 1 } } { \int_set:Nn \l_@@_initial_j_int { #2 - 1 } } { \int_set:Nn \l_@@_initial_j_int { #2 } \bool_set_true:N \l_@@_initial_open_bool } } \int_compare:nNnTF { #2 + #3 -1 } = \c@jCol { \int_set:Nn \l_@@_final_j_int { #2 + #3 - 1 } \bool_set_true:N \l_@@_final_open_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_use:N \l_@@_final_i_int - \int_eval:n { #2 + #3 } } { \int_set:Nn \l_@@_final_j_int { #2 + #3 } } { \int_set:Nn \l_@@_final_j_int { #2 + #3 - 1 } \bool_set_true:N \l_@@_final_open_bool } } % \end{macrocode} % % \begin{macrocode} \group_begin: \@@_open_shorten: \int_if_zero:nTF { #1 } { \color { nicematrix-first-row } } { \int_compare:nNnT { #1 } = \g_@@_row_total_int { \color { nicematrix-last-row } } } \keys_set:nn { NiceMatrix / xdots } { #4 } \tl_if_empty:oF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Ldots: \group_end: % \end{macrocode} % % \medskip % We declare all the cells concerned by the |\Hdotsfor| as ``dotted'' (for the % dotted lines created by |\Cdots|, |\Ldots|, etc., this job is done by % |\@@_find_extremities_of_line:nnnn|). This declaration is done by defining a % special control sequence (to nil). % \begin{macrocode} \int_step_inline:nnn { #2 } { #2 + #3 - 1 } { \cs_set:cpn { @@ _ dotted _ #1 - ##1 } { } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \cs_set_nopar:Npn \l_@@_argspec_tl { m m O { } E { _ ^ : } { { } { } { } } } \tl_set_rescan:Nno \l_@@_argspec_tl { } \l_@@_argspec_tl \cs_new_protected:Npn \@@_Vdotsfor: { \@@_collect_options:n { \@@_Vdotsfor_i } } \exp_args:NNo \NewDocumentCommand \@@_Vdotsfor_i \l_@@_argspec_tl { \bool_gset_true:N \g_@@_empty_cell_bool \tl_gput_right:Nx \g_@@_HVdotsfor_lines_tl { \@@_Vdotsfor:nnnn { \int_use:N \c@iRow } { \int_use:N \c@jCol } { #2 } { #1 , #3 , down = \exp_not:n { #4 } , up = \exp_not:n { #5 } , middle = \exp_not:n { #6 } } } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_Vdotsfor:nnnn #1 #2 #3 #4 { \bool_set_false:N \l_@@_initial_open_bool \bool_set_false:N \l_@@_final_open_bool % \end{macrocode} % For the column, it's easy. % \begin{macrocode} \int_set:Nn \l_@@_initial_j_int { #2 } \int_set_eq:NN \l_@@_final_j_int \l_@@_initial_j_int % \end{macrocode} % For the row, it's a bit more complicated. % \begin{macrocode} \int_compare:nNnTF { #1 } = \c_one_int { \int_set_eq:NN \l_@@_initial_i_int \c_one_int \bool_set_true:N \l_@@_initial_open_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_eval:n { #1 - 1 } - \int_use:N \l_@@_initial_j_int } { \int_set:Nn \l_@@_initial_i_int { #1 - 1 } } { \int_set:Nn \l_@@_initial_i_int { #1 } \bool_set_true:N \l_@@_initial_open_bool } } \int_compare:nNnTF { #1 + #3 -1 } = \c@iRow { \int_set:Nn \l_@@_final_i_int { #1 + #3 - 1 } \bool_set_true:N \l_@@_final_open_bool } { \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \int_eval:n { #1 + #3 } - \int_use:N \l_@@_final_j_int } { \int_set:Nn \l_@@_final_i_int { #1 + #3 } } { \int_set:Nn \l_@@_final_i_int { #1 + #3 - 1 } \bool_set_true:N \l_@@_final_open_bool } } % \end{macrocode} % % \begin{macrocode} \group_begin: \@@_open_shorten: \int_if_zero:nTF { #2 } { \color { nicematrix-first-col } } { \int_compare:nNnT { #2 } = \g_@@_col_total_int { \color { nicematrix-last-col } } } \keys_set:nn { NiceMatrix / xdots } { #4 } \tl_if_empty:oF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \@@_actually_draw_Vdots: \group_end: % \end{macrocode} % % \medskip % We declare all the cells concerned by the |\Vdotsfor| as ``dotted'' (for the % dotted lines created by |\Cdots|, |\Ldots|, etc., this job is done by % |\@@_find_extremities_of_line:nnnn|). This declaration is done by defining a % special control sequence (to nil). % \begin{macrocode} \int_step_inline:nnn { #1 } { #1 + #3 - 1 } { \cs_set:cpn { @@ _ dotted _ ##1 - #2 } { } } } % \end{macrocode} % % % \vspace{1cm} % The command |\@@_rotate:| will be linked to |\rotate| in % |{NiceArrayWithDelims}|. % \begin{macrocode} \NewDocumentCommand \@@_rotate: { O { } } { \peek_remove_spaces:n { \bool_gset_true:N \g_@@_rotate_bool \keys_set:nn { NiceMatrix / rotate } { #1 } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \keys_define:nn { NiceMatrix / rotate } { c .code:n = \bool_gset_true:N \g_@@_rotate_c_bool , c .value_forbidden:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~rotate } } % \end{macrocode} % % \bigskip % \section{The command \textbackslash line accessible in code-after} % % In the |\CodeAfter|, the command |\@@_line:nn| will be linked to |\line|. This % command takes two arguments which are the specifications of two cells in the % array (in the format $i$-$j$) and draws a dotted line between these cells. In % fact, if also works with names of blocks. % % \medskip % First, we write a command with the following behaviour: % \begin{itemize} % \item If the argument is of the format $i$-$j$, our command applies % the command |\int_eval:n| to $i$ and~$j$ ; % \item If not (that is to say, when it's a name of a |\Block|), the argument is % left unchanged. % \end{itemize} % This must \emph{not} be protected (and is, of course fully % expandable).\footnote{Indeed, we want that the user may use the command % |\line| in |\CodeAfter| with LaTeX counters in the arguments --- with the % command |\value|.} % \begin{macrocode} \cs_new:Npn \@@_double_int_eval:n #1-#2 \q_stop { \tl_if_empty:nTF { #2 } { #1 } { \@@_double_int_eval_i:n #1-#2 \q_stop } } \cs_new:Npn \@@_double_int_eval_i:n #1-#2- \q_stop { \int_eval:n { #1 } - \int_eval:n { #2 } } % \end{macrocode} % % % \medskip % With the following construction, the command |\@@_double_int_eval:n| is % applied to both arguments before the application of |\@@_line_i:nn| (the % construction uses the fact the |\@@_line_i:nn| is protected and that % |\@@_double_int_eval:n| is fully expandable). % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \cs_set_nopar:Npn \l_@@_argspec_tl { O { } m m ! O { } E { _ ^ : } { { } { } { } } } \tl_set_rescan:Nno \l_@@_argspec_tl { } \l_@@_argspec_tl \exp_args:NNo \NewDocumentCommand \@@_line \l_@@_argspec_tl { \group_begin: \keys_set:nn { NiceMatrix / xdots } { #1 , #4 , down = #5 , up = #6 } \tl_if_empty:oF \l_@@_xdots_color_tl { \color { \l_@@_xdots_color_tl } } \use:e { \@@_line_i:nn { \@@_double_int_eval:n #2 - \q_stop } { \@@_double_int_eval:n #3 - \q_stop } } \group_end: } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_line_i:nn #1 #2 { \bool_set_false:N \l_@@_initial_open_bool \bool_set_false:N \l_@@_final_open_bool \bool_lazy_or:nnTF { \cs_if_free_p:c { pgf @ sh @ ns @ \@@_env: - #1 } } { \cs_if_free_p:c { pgf @ sh @ ns @ \@@_env: - #2 } } { \@@_error:nnn { unknown~cell~for~line~in~CodeAfter } { #1 } { #2 } } % \end{macrocode} % The test of |measuring@| is a security (cf. question 686649 on TeX StackExchange). % \begin{macrocode} { \legacy_if:nF { measuring@ } { \@@_draw_line_ii:nn { #1 } { #2 } } } } % \end{macrocode} % % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \cs_new_protected:Npx \@@_draw_line_ii:nn #1 #2 { % \end{macrocode} % We recall that, when externalization is used, |\tikzpicture| and % |\endtikzpicture| (or |\pgfpicture| and |\endpgfpicture|) must be directly % ``visible'' and that why we do this static construction of the command % |\@@_draw_line_ii:|. % \begin{macrocode} \c_@@_pgfortikzpicture_tl \@@_draw_line_iii:nn { #1 } { #2 } \c_@@_endpgfortikzpicture_tl } } % \end{macrocode} % % \bigskip % The following command \emph{must} be protected (it's used in the % construction of |\@@_draw_line_ii:nn|). % \begin{macrocode} \cs_new_protected:Npn \@@_draw_line_iii:nn #1 #2 { \pgfrememberpicturepositiononpagetrue \pgfpointshapeborder { \@@_env: - #1 } { \@@_qpoint:n { #2 } } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y \pgfpointshapeborder { \@@_env: - #2 } { \@@_qpoint:n { #1 } } \dim_set_eq:NN \l_@@_x_final_dim \pgf@x \dim_set_eq:NN \l_@@_y_final_dim \pgf@y \@@_draw_line: } % \end{macrocode} % % % The commands |\Ldots|, |\Cdots|, |\Vdots|, |\Ddots|, and |\Iddots| don't use % this command because they have to do other settings (for example, the diagonal % lines must be parallelized). % % % % \bigskip % \section{The command \textbackslash RowStyle} % % % |\g_@@_row_style_tl| may contain several instructions of the form: % % \qquad |\@@_if_row_less_than:nn { number } { instructions }| % % \smallskip % Then, |\g_@@_row_style_tl| will be inserted in all the cells of the array (and % also in both components of a |\diagbox| in a cell of in a mono-row block). % % The test |\@@_if_row_less_then:nn| ensures that the instructions are inserted % only if you are in a row which is (still) in the scope of that instructions % (which depends on the value of the key |nb-rows| of |\RowStyle|). % % That test will be active even in an expandable context because % |\@@_if_row_less_then:nn| is \emph{not} protected. % % |#1| is the first row \emph{after} the scope of the instructions in |#2| % \begin{macrocode} \cs_new:Npn \@@_if_row_less_than:nn #1 #2 { \int_compare:nNnT { \c@iRow } < { #1 } { #2 } } % \end{macrocode} % % \bigskip % |\@@_put_in_row_style| will be used several times by |\RowStyle|. % \begin{macrocode} \cs_set_protected:Npn \@@_put_in_row_style:n #1 { \tl_gput_right:Nx \g_@@_row_style_tl { % \end{macrocode} % Be careful, |\exp_not:N \@@_if_row_less_than:nn| can't be replaced by a % protected version of |\@@_if_row_less_than:nn|. % \begin{macrocode} \exp_not:N \@@_if_row_less_than:nn { \int_eval:n { \c@iRow + \l_@@_key_nb_rows_int } } % \end{macrocode} % The |\scan_stop:| is mandatory (for ex. for the case where |\rotate| is used % in the argument of |\RowStyle|). % \begin{macrocode} { \exp_not:n { #1 } \scan_stop: } } } \cs_generate_variant:Nn \@@_put_in_row_style:n { e } % \end{macrocode} % \medskip % \begin{macrocode} \keys_define:nn { NiceMatrix / RowStyle } { cell-space-top-limit .dim_set:N = \l_tmpa_dim , cell-space-top-limit .value_required:n = true , cell-space-bottom-limit .dim_set:N = \l_tmpb_dim , cell-space-bottom-limit .value_required:n = true , cell-space-limits .meta:n = { cell-space-top-limit = #1 , cell-space-bottom-limit = #1 , } , color .tl_set:N = \l_@@_color_tl , color .value_required:n = true , bold .bool_set:N = \l_@@_bold_row_style_bool , bold .default:n = true , nb-rows .code:n = \str_if_eq:nnTF { #1 } { * } { \int_set:Nn \l_@@_key_nb_rows_int { 500 } } { \int_set:Nn \l_@@_key_nb_rows_int { #1 } } , nb-rows .value_required:n = true , rowcolor .tl_set:N = \l_tmpa_tl , rowcolor .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~RowStyle } } % \end{macrocode} % % % \bigskip % \begin{macrocode} \NewDocumentCommand \@@_RowStyle:n { O { } m } { \group_begin: \tl_clear:N \l_tmpa_tl \tl_clear:N \l_@@_color_tl \int_set_eq:NN \l_@@_key_nb_rows_int \c_one_int \dim_zero:N \l_tmpa_dim \dim_zero:N \l_tmpb_dim \keys_set:nn { NiceMatrix / RowStyle } { #1 } % \end{macrocode} % If the key |rowcolor| has been used. % \begin{macrocode} \tl_if_empty:NF \l_tmpa_tl { % \end{macrocode} % First, the end of the current row (we remind that |\RowStyle| applies to the % \emph{end} of the current row). % \begin{macrocode} \tl_gput_right:Nx \g_@@_pre_code_before_tl { % \end{macrocode} % The command |\@@_exp_color_arg:No| is \emph{fully expandable}. % \begin{macrocode} \@@_exp_color_arg:No \@@_rectanglecolor \l_tmpa_tl { \int_use:N \c@iRow - \int_use:N \c@jCol } { \int_use:N \c@iRow - * } } % \end{macrocode} % Then, the other rows (if there is several rows). % \begin{macrocode} \int_compare:nNnT \l_@@_key_nb_rows_int > \c_one_int { \tl_gput_right:Nx \g_@@_pre_code_before_tl { \@@_exp_color_arg:No \@@_rowcolor \l_tmpa_tl { \int_eval:n { \c@iRow + 1 } - \int_eval:n { \c@iRow + \l_@@_key_nb_rows_int - 1 } } } } } \@@_put_in_row_style:n { \exp_not:n { #2 } } % \end{macrocode} % |\l_tmpa_dim| is the value of the key |cell-space-top-limit| of |\RowStyle|. % \begin{macrocode} \dim_compare:nNnT \l_tmpa_dim > \c_zero_dim { \exp_args:Nx \@@_put_in_row_style:n { \tl_gput_right:Nn \exp_not:N \g_@@_cell_after_hook_tl { % \end{macrocode} % It's not possible to chanage the following code by using |\dim_set_eq:NN| % (because of expansion). % \begin{macrocode} \dim_set:Nn \l_@@_cell_space_top_limit_dim { \dim_use:N \l_tmpa_dim } } } } % \end{macrocode} % |\l_tmpb_dim| is the value of the key |cell-space-bottom-limit| of |\RowStyle|. % \begin{macrocode} \dim_compare:nNnT \l_tmpb_dim > \c_zero_dim { \exp_args:Nx \@@_put_in_row_style:n { \tl_gput_right:Nn \exp_not:N \g_@@_cell_after_hook_tl { \dim_set:Nn \l_@@_cell_space_bottom_limit_dim { \dim_use:N \l_tmpb_dim } } } } % \end{macrocode} % |\l_@@_color_tl| is the value of the key |color| of |\RowStyle|. % \begin{macrocode} \tl_if_empty:NF \l_@@_color_tl { \@@_put_in_row_style:e { \mode_leave_vertical: \@@_color:n { \l_@@_color_tl } } } % \end{macrocode} % |\l_@@_bold_row_style_bool| is the value of the key |bold|. % \begin{macrocode} \bool_if:NT \l_@@_bold_row_style_bool { \@@_put_in_row_style:n { \exp_not:n { \if_mode_math: \c_math_toggle_token \bfseries \boldmath \c_math_toggle_token \else: \bfseries \boldmath \fi: } } } \group_end: \g_@@_row_style_tl \ignorespaces } % \end{macrocode} % % % \bigskip % \section{Colors of cells, rows and columns} % % We want to avoid the thin white lines that are shown in some \textsc{pdf} % viewers (eg: with the engine MuPDF used by SumatraPDF). That's why we try to % draw rectangles of the same color in the same instruction |\pgfusepath { fill }| % (and they will be in the same instruction |fill|---coded |f|---in the % resulting \textsc{pdf}). % % The commands |\@@_rowcolor|, |\@@_columncolor|, |\@@_rectanglecolor| and % |\@@_rowlistcolors| don't directly draw the corresponding rectangles. Instead, % they store their instructions color by color: % \begin{itemize} % \item A sequence |\g_@@_colors_seq| will be built containing all the colors % used by at least one of these instructions. Each \emph{color} may be prefixed % by its color model (eg: |[gray]{0.5}|). % \item For the color whose index in |\g_@@_colors_seq| is equal to~$i$, a list of % instructions which use that color will be constructed in the token list % |\g_@@_color_|$i$|_tl|. In that token list, the instructions will be written % using |\@@_cartesian_color:nn| and |\@@_rectanglecolor:nn|. % \end{itemize} % % % \bigskip % |#1| is the color and |#2| is an instruction using that color. Despite its % name, the command |\@@_add_to_colors_seq:nn| doesn't only add a color to % |\g_@@_colors_seq|: it also updates the corresponding token list % |\g_@@_color_|$i$|_tl|. We add in a global way because the final user may use % the instructions such as |\cellcolor| in a loop of \pkg{pgffor} in the % |\CodeBefore| (and we recall that a loop of \pkg{pgffor} is encapsulated in a % group). % \begin{macrocode} \cs_new_protected:Npn \@@_add_to_colors_seq:nn #1 #2 { % \end{macrocode} % Firt, we look for the number of the color and, if it's found, we store it in % |\l_tmpa_int|. If the color is not present in |\l_@@_colors_seq|, % |\l_tmpa_int| will remain equal to $0$. % \begin{macrocode} \int_zero:N \l_tmpa_int % \end{macrocode} % We don't take into account the colors like |myserie!!+| because those colors % are special color from a |\definecolorseries| of \pkg{xcolor}. % \begin{macrocode} \str_if_in:nnF { #1 } { !! } { \seq_map_indexed_inline:Nn \g_@@_colors_seq { \tl_if_eq:nnT { #1 } { ##2 } { \int_set:Nn \l_tmpa_int { ##1 } } } } \int_if_zero:nTF \l_tmpa_int % \end{macrocode} % First, the case where the color is a \emph{new} color (not in the sequence). % \begin{macrocode} { \seq_gput_right:Nn \g_@@_colors_seq { #1 } \tl_gset:cx { g_@@_color _ \seq_count:N \g_@@_colors_seq _ tl } { #2 } } % \end{macrocode} % Now, the case where the color is \emph{not} a new color (the color is in the % sequence at the position |\l_tmpa_int|). % \begin{macrocode} { \tl_gput_right:cx { g_@@_color _ \int_use:N \l_tmpa_int _tl } { #2 } } } % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \@@_add_to_colors_seq:nn { e n } \cs_generate_variant:Nn \@@_add_to_colors_seq:nn { e e } % \end{macrocode} % % \bigskip % The following command must be used within a |\pgfpicture|. % \begin{macrocode} \cs_new_protected:Npn \@@_clip_with_rounded_corners: { \dim_compare:nNnT \l_@@_tab_rounded_corners_dim > \c_zero_dim { % \end{macrocode} % The TeX group is for |\pgfsetcornersarced| (whose scope is the TeX scope). % \begin{macrocode} \group_begin: \pgfsetcornersarced { \pgfpoint { \l_@@_tab_rounded_corners_dim } { \l_@@_tab_rounded_corners_dim } } % \end{macrocode} % Because we want \pkg{nicematrix} compatible with arrays constructed by % \pkg{array}, the nodes for the rows and columns (that is to say the nodes % |row-|\textsl{i} and |col-|\textsl{j}) have not always the expected position, % that is to say, there is sometimes a slight shifting of something such as % |\arrayrulewidth|. Now, for the clipping, we have to change slightly the % position of that clipping whether a rounded rectangle around the array is % required. That's the point which is tested in the following line. % \begin{macrocode} \bool_if:NTF \l_@@_hvlines_bool { \pgfpathrectanglecorners { \pgfpointadd { \@@_qpoint:n { row-1 } } { \pgfpoint { 0.5 \arrayrulewidth } { \c_zero_dim } } } { \pgfpointadd { \@@_qpoint:n { \int_eval:n { \int_max:nn \c@iRow \c@jCol + 1 } } } { \pgfpoint \c_zero_dim { 0.5 \arrayrulewidth } } } } { \pgfpathrectanglecorners { \@@_qpoint:n { row-1 } } { \pgfpointadd { \@@_qpoint:n { \int_eval:n { \int_max:nn \c@iRow \c@jCol + 1 } } } { \pgfpoint \c_zero_dim \arrayrulewidth } } } \pgfusepath { clip } \group_end: % \end{macrocode} % The TeX group was for |\pgfsetcornersarced|. % \begin{macrocode} } } % \end{macrocode} % % \bigskip % The macro |\@@_actually_color:| will actually fill all the rectangles, color by % color (using the sequence |\l_@@_colors_seq| and all the token lists of the % form |\l_@@_color_|$i$|_tl|). % \begin{macrocode} \cs_new_protected:Npn \@@_actually_color: { \pgfpicture \pgf@relevantforpicturesizefalse % \end{macrocode} % If the final user has used the key |rounded-corners| for the environment % |{NiceTabular}|, we will clip to a rectangle with rounded corners before % filling the rectangles. % \begin{macrocode} \@@_clip_with_rounded_corners: \seq_map_indexed_inline:Nn \g_@@_colors_seq { \int_compare:nNnTF { ##1 } = \c_one_int { \cs_set_eq:NN \@@_cartesian_path:n \@@_cartesian_path_nocolor:n \use:c { g_@@_color _ 1 _tl } \cs_set_eq:NN \@@_cartesian_path:n \@@_cartesian_path_normal:n } { \begin { pgfscope } \@@_color_opacity ##2 \use:c { g_@@_color _ ##1 _tl } \tl_gclear:c { g_@@_color _ ##1 _tl } \pgfusepath { fill } \end { pgfscope } } } \endpgfpicture } % \end{macrocode} % % % \bigskip % The following command will extract the potential key |opacity| in its optional % argument (between square brackets) and (of course) then apply the command |\color|. % \begin{macrocode} \cs_new_protected:Npn \@@_color_opacity { \peek_meaning:NTF [ { \@@_color_opacity:w } { \@@_color_opacity:w [ ] } } % \end{macrocode} % % \bigskip % The command |\@@_color_opacity:w| takes in as argument only the optional % argument. One may consider that the second argument (the actual definition of % the color) is provided by curryfication. % \begin{macrocode} \cs_new_protected:Npn \@@_color_opacity:w [ #1 ] { \tl_clear:N \l_tmpa_tl \keys_set_known:nnN { nicematrix / color-opacity } { #1 } \l_tmpb_tl % \end{macrocode} % |\l_tmpa_tl| (if not empty) is now the opacity and |\l_tmpb_tl| (if not empty) is now the colorimetric space. % \begin{macrocode} \tl_if_empty:NF \l_tmpa_tl { \exp_args:No \pgfsetfillopacity \l_tmpa_tl } \tl_if_empty:NTF \l_tmpb_tl { \@declaredcolor } { \use:e { \exp_not:N \@undeclaredcolor [ \l_tmpb_tl ] } } } % \end{macrocode} % % \bigskip % The following set of keys is used by the command |\@@_color_opacity:wn|. % \begin{macrocode} \keys_define:nn { nicematrix / color-opacity } { opacity .tl_set:N = \l_tmpa_tl , opacity .value_required:n = true } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_cartesian_color:nn #1 #2 { \cs_set_nopar:Npn \l_@@_rows_tl { #1 } \cs_set_nopar:Npn \l_@@_cols_tl { #2 } \@@_cartesian_path: } % \end{macrocode} % % \bigskip % Here is an example : |\@@_rowcolor {red!15} {1,3,5-7,10-}| % \begin{macrocode} \NewDocumentCommand \@@_rowcolor { O { } m m } { \tl_if_blank:nF { #2 } { \@@_add_to_colors_seq:en { \tl_if_blank:nF { #1 } { [ #1 ] } { #2 } } { \@@_cartesian_color:nn { #3 } { - } } } } % \end{macrocode} % % \bigskip % Here an example : |\@@_columncolor:nn {red!15} {1,3,5-7,10-}| % \begin{macrocode} \NewDocumentCommand \@@_columncolor { O { } m m } { \tl_if_blank:nF { #2 } { \@@_add_to_colors_seq:en { \tl_if_blank:nF { #1 } { [ #1 ] } { #2 } } { \@@_cartesian_color:nn { - } { #3 } } } } % \end{macrocode} % % \bigskip % Here is an example : |\@@_rectanglecolor{red!15}{2-3}{5-6}| % \begin{macrocode} \NewDocumentCommand \@@_rectanglecolor { O { } m m m } { \tl_if_blank:nF { #2 } { \@@_add_to_colors_seq:en { \tl_if_blank:nF { #1 } { [ #1 ] } { #2 } } { \@@_rectanglecolor:nnn { #3 } { #4 } { \c_zero_dim } } } } % \end{macrocode} % % \bigskip % The last argument is the radius of the corners of the rectangle. % \begin{macrocode} \NewDocumentCommand \@@_roundedrectanglecolor { O { } m m m m } { \tl_if_blank:nF { #2 } { \@@_add_to_colors_seq:en { \tl_if_blank:nF { #1 } { [ #1 ] } { #2 } } { \@@_rectanglecolor:nnn { #3 } { #4 } { #5 } } } } % \end{macrocode} % % \bigskip % The last argument is the radius of the corners of the rectangle. % \begin{macrocode} \cs_new_protected:Npn \@@_rectanglecolor:nnn #1 #2 #3 { \@@_cut_on_hyphen:w #1 \q_stop \tl_clear_new:N \l_@@_tmpc_tl \tl_clear_new:N \l_@@_tmpd_tl \tl_set_eq:NN \l_@@_tmpc_tl \l_tmpa_tl \tl_set_eq:NN \l_@@_tmpd_tl \l_tmpb_tl \@@_cut_on_hyphen:w #2 \q_stop \tl_set:Nx \l_@@_rows_tl { \l_@@_tmpc_tl - \l_tmpa_tl } \tl_set:Nx \l_@@_cols_tl { \l_@@_tmpd_tl - \l_tmpb_tl } % \end{macrocode} % The command |\@@_cartesian_path:n| takes in two implicit arguments: % |\l_@@_cols_tl| and |\l_@@_rows_tl|. % \begin{macrocode} \@@_cartesian_path:n { #3 } } % \end{macrocode} % % % \bigskip % Here is an example : |\@@_cellcolor[rgb]{0.5,0.5,0}{2-3,3-4,4-5,5-6}| % \begin{macrocode} \NewDocumentCommand \@@_cellcolor { O { } m m } { \clist_map_inline:nn { #3 } { \@@_rectanglecolor [ #1 ] { #2 } { ##1 } { ##1 } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentCommand \@@_chessboardcolors { O { } m m } { \int_step_inline:nn \c@iRow { \int_step_inline:nn \c@jCol { \int_if_even:nTF { ####1 + ##1 } { \@@_cellcolor [ #1 ] { #2 } } { \@@_cellcolor [ #1 ] { #3 } } { ##1 - ####1 } } } } % \end{macrocode} % % \bigskip % The command |\@@_arraycolor| (linked to |\arraycolor| at the beginning of % the |\CodeBefore|) will color the whole tabular (excepted the potential % exterior rows and columns) and the cells in the ``corners''. % \begin{macrocode} \NewDocumentCommand \@@_arraycolor { O { } m } { \@@_rectanglecolor [ #1 ] { #2 } { 1 - 1 } { \int_use:N \c@iRow - \int_use:N \c@jCol } } % \end{macrocode} % % \bigskip % \begin{macrocode} \keys_define:nn { NiceMatrix / rowcolors } { respect-blocks .bool_set:N = \l_@@_respect_blocks_bool , respect-blocks .default:n = true , cols .tl_set:N = \l_@@_cols_tl , restart .bool_set:N = \l_@@_rowcolors_restart_bool , restart .default:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~rowcolors } } % \end{macrocode} % % \medskip % The command |\rowcolors| (accessible in the |\CodeBefore|) is inspired by the % command |\rowcolors| of the package \pkg{xcolor} (with the option |table|). % However, the command |\rowcolors| of \pkg{nicematrix} has \emph{not} the % optional argument of the command |\rowcolors| of \pkg{xcolor}. % % Here is an example: |\rowcolors{1}{blue!10}{}[respect-blocks]|. % % In \pkg{nicematrix}, the commmand |\@@_rowcolors| appears as a special case of % |\@@_rowlistcolors|. % % |#1| (optional) is the color space; % |#2| is a list of intervals of rows; % |#3| is the list of colors; % |#4| is for the optional list of pairs \textsl{key=value}. % \begin{macrocode} \NewDocumentCommand \@@_rowlistcolors { O { } m m O { } } { % \end{macrocode} % The group is for the options. |\l_@@_colors_seq| will be the list of colors. % \begin{macrocode} \group_begin: \seq_clear_new:N \l_@@_colors_seq \seq_set_split:Nnn \l_@@_colors_seq { , } { #3 } \tl_clear_new:N \l_@@_cols_tl \cs_set_nopar:Npn \l_@@_cols_tl { - } \keys_set:nn { NiceMatrix / rowcolors } { #4 } % \end{macrocode} % The counter |\l_@@_color_int| will be the rank of the current color in the list of % colors (modulo the length of the list). % \begin{macrocode} \int_zero_new:N \l_@@_color_int \int_set_eq:NN \l_@@_color_int \c_one_int \bool_if:NT \l_@@_respect_blocks_bool { % \end{macrocode} % We don't want to take into account a block which is completely in the ``first % column'' (number~$0$) or in the ``last column'' and that's why we filter % the sequence of the blocks (in a the sequence |\l_tmpa_seq|). % \begin{macrocode} \seq_set_eq:NN \l_tmpb_seq \g_@@_pos_of_blocks_seq \seq_set_filter:NNn \l_tmpa_seq \l_tmpb_seq { \@@_not_in_exterior_p:nnnnn ##1 } } \pgfpicture \pgf@relevantforpicturesizefalse % \end{macrocode} % |#2| is the list of intervals of rows. % \begin{macrocode} \clist_map_inline:nn { #2 } { \cs_set_nopar:Npn \l_tmpa_tl { ##1 } \tl_if_in:NnTF \l_tmpa_tl { - } { \@@_cut_on_hyphen:w ##1 \q_stop } { \tl_set:No \l_tmpb_tl { \int_use:N \c@iRow } } % \end{macrocode} % Now, |l_tmpa_tl| and |l_tmpb_tl| are the first row and the last row of the % interval of rows that we have to treat. The counter |\l_tmpa_int| will be the % index of the loop over the rows. % \begin{macrocode} \int_set:Nn \l_tmpa_int \l_tmpa_tl \int_set:Nn \l_@@_color_int { \bool_if:NTF \l_@@_rowcolors_restart_bool 1 \l_tmpa_tl } \int_zero_new:N \l_@@_tmpc_int \int_set:Nn \l_@@_tmpc_int \l_tmpb_tl \int_do_until:nNnn \l_tmpa_int > \l_@@_tmpc_int { % \end{macrocode} % We will compute in |\l_tmpb_int| the last row of the ``block''. % \begin{macrocode} \int_set_eq:NN \l_tmpb_int \l_tmpa_int % \end{macrocode} % If the key |respect-blocks| is in force, we have to adjust that value (of % course). % \begin{macrocode} \bool_if:NT \l_@@_respect_blocks_bool { \seq_set_filter:NNn \l_tmpb_seq \l_tmpa_seq { \@@_intersect_our_row_p:nnnnn ####1 } \seq_map_inline:Nn \l_tmpb_seq { \@@_rowcolors_i:nnnnn ####1 } % \end{macrocode} % Now, the last row of the block is computed in |\l_tmpb_int|. % \begin{macrocode} } \tl_set:No \l_@@_rows_tl { \int_use:N \l_tmpa_int - \int_use:N \l_tmpb_int } % \end{macrocode} % |\l_@@_tmpc_tl| will be the color that we will use. % \begin{macrocode} \tl_clear_new:N \l_@@_color_tl \tl_set:Nx \l_@@_color_tl { \@@_color_index:n { \int_mod:nn { \l_@@_color_int - 1 } { \seq_count:N \l_@@_colors_seq } + 1 } } \tl_if_empty:NF \l_@@_color_tl { \@@_add_to_colors_seq:ee { \tl_if_blank:nF { #1 } { [ #1 ] } { \l_@@_color_tl } } { \@@_cartesian_color:nn { \l_@@_rows_tl } { \l_@@_cols_tl } } } \int_incr:N \l_@@_color_int \int_set:Nn \l_tmpa_int { \l_tmpb_int + 1 } } } \endpgfpicture \group_end: } % \end{macrocode} % % \medskip % The command |\@@_color_index:n| peeks in |\l_@@_colors_seq| the color at the % index |#1|. However, if that color is the symbol |=|, the previous one is % poken. This macro is recursive. % \begin{macrocode} \cs_new:Npn \@@_color_index:n #1 { \str_if_eq:eeTF { \seq_item:Nn \l_@@_colors_seq { #1 } } { = } { \@@_color_index:n { #1 - 1 } } { \seq_item:Nn \l_@@_colors_seq { #1 } } } % \end{macrocode} % % \bigskip % The command |\rowcolors| (available in the |\CodeBefore|) is a specialisation % of the more general command |\rowlistcolors|. The last argument, which is a % optional argument between square brackets is provided by curryfication. % \begin{macrocode} \NewDocumentCommand \@@_rowcolors { O { } m m m } { \@@_rowlistcolors [ #1 ] { #2 } { { #3 } , { #4 } } } % \end{macrocode} % The braces around |#3| and |#4| are mandatory. % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_rowcolors_i:nnnnn #1 #2 #3 #4 #5 { \int_compare:nNnT { #3 } > \l_tmpb_int { \int_set:Nn \l_tmpb_int { #3 } } } % \end{macrocode} % % % \bigskip % \begin{macrocode} \prg_new_conditional:Nnn \@@_not_in_exterior:nnnnn p { \int_if_zero:nTF { #4 } \prg_return_false: { \int_compare:nNnTF { #2 } > \c@jCol \prg_return_false: \prg_return_true: } } % \end{macrocode} % % \bigskip % The following command return |true| when the block intersects the row % |\l_tmpa_int|. % \begin{macrocode} \prg_new_conditional:Nnn \@@_intersect_our_row:nnnnn p { \int_compare:nNnTF { #1 } > \l_tmpa_int \prg_return_false: { \int_compare:nNnTF \l_tmpa_int > { #3 } \prg_return_false: \prg_return_true: } } % \end{macrocode} % % \bigskip % The following command uses two implicit arguments: |\l_@@_rows_tl| and % |\l_@@_cols_tl| which are specifications for a set of rows and a set of % columns. It creates a path but does \emph{not} fill it. It must be filled by % another command after. The argument is the radius of the corners. We define % below a command |\@@_cartesian_path:| which corresponds to a value $0$~pt for % the radius of the corners. % % This command is, in particular, used in |\@@_rectanglecolor:nnn| (used in % |\@@_rectanglecolor|, itself used in |\@@_cellcolor|). % \begin{macrocode} \cs_new_protected:Npn \@@_cartesian_path_normal:n #1 { \dim_compare:nNnTF { #1 } = \c_zero_dim { \bool_if:NTF \@@_nocolor_used_bool \@@_cartesian_path_normal_ii: { \seq_if_empty:NTF \l_@@_corners_cells_seq { \@@_cartesian_path_normal_i:n { #1 } } \@@_cartesian_path_normal_ii: } } { \@@_cartesian_path_normal_i:n { #1 } } } % \end{macrocode} % % % \bigskip % First, the situation where is a rectangular zone of cells will be colored as a % whole (in the instructions of the resulting \textsc{pdf}). The argument is the % radius of the corners. % \begin{macrocode} \cs_new_protected:Npn \@@_cartesian_path_normal_i:n #1 { \pgfsetcornersarced { \pgfpoint { #1 } { #1 } } % \end{macrocode} % We begin the loop over the columns. % \begin{macrocode} \clist_map_inline:Nn \l_@@_cols_tl { \cs_set_nopar:Npn \l_tmpa_tl { ##1 } \tl_if_in:NnTF \l_tmpa_tl { - } { \@@_cut_on_hyphen:w ##1 \q_stop } { \@@_cut_on_hyphen:w ##1 - ##1 \q_stop } \tl_if_empty:NTF \l_tmpa_tl { \cs_set_nopar:Npn \l_tmpa_tl { 1 } } { \tl_if_eq:NNT \l_tmpa_tl \c_@@_star_tl { \cs_set_nopar:Npn \l_tmpa_tl { 1 } } } \tl_if_empty:NTF \l_tmpb_tl { \tl_set:No \l_tmpb_tl { \int_use:N \c@jCol } } { \tl_if_eq:NNT \l_tmpb_tl \c_@@_star_tl { \tl_set:No \l_tmpb_tl { \int_use:N \c@jCol } } } \int_compare:nNnT \l_tmpb_tl > \g_@@_col_total_int { \tl_set:No \l_tmpb_tl { \int_use:N \g_@@_col_total_int } } % \end{macrocode} % |\l_@@_tmpc_tl| will contain the number of column. % \begin{macrocode} \tl_set_eq:NN \l_@@_tmpc_tl \l_tmpa_tl \@@_qpoint:n { col - \l_tmpa_tl } \int_compare:nNnTF \l_@@_first_col_int = \l_tmpa_tl { \dim_set:Nn \l_@@_tmpc_dim { \pgf@x - 0.5 \arrayrulewidth } } { \dim_set:Nn \l_@@_tmpc_dim { \pgf@x + 0.5 \arrayrulewidth } } \@@_qpoint:n { col - \int_eval:n { \l_tmpb_tl + 1 } } \dim_set:Nn \l_tmpa_dim { \pgf@x + 0.5 \arrayrulewidth } % \end{macrocode} % We begin the loop over the rows. % \begin{macrocode} \clist_map_inline:Nn \l_@@_rows_tl { \cs_set_nopar:Npn \l_tmpa_tl { ####1 } \tl_if_in:NnTF \l_tmpa_tl { - } { \@@_cut_on_hyphen:w ####1 \q_stop } { \@@_cut_on_hyphen:w ####1 - ####1 \q_stop } \tl_if_empty:NTF \l_tmpa_tl { \cs_set_nopar:Npn \l_tmpa_tl { 1 } } { \tl_if_eq:NNT \l_tmpa_tl \c_@@_star_tl { \cs_set_nopar:Npn \l_tmpa_tl { 1 } } } \tl_if_empty:NTF \l_tmpb_tl { \tl_set:No \l_tmpb_tl { \int_use:N \c@iRow } } { \tl_if_eq:NNT \l_tmpb_tl \c_@@_star_tl { \tl_set:No \l_tmpb_tl { \int_use:N \c@iRow } } } \int_compare:nNnT \l_tmpb_tl > \g_@@_row_total_int { \tl_set:No \l_tmpb_tl { \int_use:N \g_@@_row_total_int } } % \end{macrocode} % Now, the numbers of both rows are in |\l_tmpa_tl| and |\l_tmpb_tl|. % \begin{macrocode} \cs_if_exist:cF { @@ _ \l_tmpa_tl _ \l_@@_tmpc_tl _ nocolor } { \@@_qpoint:n { row - \int_eval:n { \l_tmpb_tl + 1 } } \dim_set:Nn \l_tmpb_dim { \pgf@y + 0.5 \arrayrulewidth } \@@_qpoint:n { row - \l_tmpa_tl } \dim_set:Nn \l_@@_tmpd_dim { \pgf@y + 0.5 \arrayrulewidth } \pgfpathrectanglecorners { \pgfpoint \l_@@_tmpc_dim \l_@@_tmpd_dim } { \pgfpoint \l_tmpa_dim \l_tmpb_dim } } } } } % \end{macrocode} % % % Now, the case where the cells will be colored cell by cell (it's mandatory for % example if the key |corners| is used). % \begin{macrocode} \cs_new_protected:Npn \@@_cartesian_path_normal_ii: { \@@_expand_clist:NN \l_@@_cols_tl \c@jCol \@@_expand_clist:NN \l_@@_rows_tl \c@iRow % \end{macrocode} % We begin the loop over the columns. % \begin{macrocode} \clist_map_inline:Nn \l_@@_cols_tl { \@@_qpoint:n { col - ##1 } \int_compare:nNnTF \l_@@_first_col_int = { ##1 } { \dim_set:Nn \l_@@_tmpc_dim { \pgf@x - 0.5 \arrayrulewidth } } { \dim_set:Nn \l_@@_tmpc_dim { \pgf@x + 0.5 \arrayrulewidth } } \@@_qpoint:n { col - \int_eval:n { ##1 + 1 } } \dim_set:Nn \l_tmpa_dim { \pgf@x + 0.5 \arrayrulewidth } % \end{macrocode} % We begin the loop over the rows. % \begin{macrocode} \clist_map_inline:Nn \l_@@_rows_tl { \seq_if_in:NnF \l_@@_corners_cells_seq { ####1 - ##1 } { \@@_qpoint:n { row - \int_eval:n { ####1 + 1 } } \dim_set:Nn \l_tmpb_dim { \pgf@y + 0.5 \arrayrulewidth } \@@_qpoint:n { row - ####1 } \dim_set:Nn \l_@@_tmpd_dim { \pgf@y + 0.5 \arrayrulewidth } \cs_if_exist:cF { @@ _ ####1 _ ##1 _ nocolor } { \pgfpathrectanglecorners { \pgfpoint \l_@@_tmpc_dim \l_@@_tmpd_dim } { \pgfpoint \l_tmpa_dim \l_tmpb_dim } } } } } } % \end{macrocode} % % % % \bigskip % The following command corresponds to a radius of the corners equal to $0$~pt. % This command is used by the commands |\@@_rowcolors|, |\@@_columncolor| and % |\@@_rowcolor:n| (used in |\@@_rowcolor|). % \begin{macrocode} \cs_new_protected:Npn \@@_cartesian_path: { \@@_cartesian_path:n \c_zero_dim } % \end{macrocode} % % % \bigskip % Despite its name, the following command does not create a PGF path. It % declares as colored by the ``empty color'' all the cells in what would be the % path. Hence, the other coloring instructions of \pkg{nicematrix} won't put % color in those cells. % the % \begin{macrocode} \cs_new_protected:Npn \@@_cartesian_path_nocolor:n #1 { \bool_set_true:N \@@_nocolor_used_bool \@@_expand_clist:NN \l_@@_cols_tl \c@jCol \@@_expand_clist:NN \l_@@_rows_tl \c@iRow % \end{macrocode} % We begin the loop over the columns. % \begin{macrocode} \clist_map_inline:Nn \l_@@_rows_tl { \clist_map_inline:Nn \l_@@_cols_tl { \cs_set:cpn { @@ _ ##1 _ ####1 _ nocolor } { } } } } % \end{macrocode} % % % \bigskip % The following command will be used only with |\l_@@_cols_tl| and |\c@jCol| (first % case) or with |\l_@@_rows_tl| and |\c@iRow| (second case). For instance, with % |\l_@@_cols_tl| equal to |2,4-6,8-*| and |\c@jCol| equal to |10|, the clist % |\l_@@_cols_tl| will be replaced by |2,4,5,6,8,9,10|. % \begin{macrocode} \cs_new_protected:Npn \@@_expand_clist:NN #1 #2 { \clist_set_eq:NN \l_tmpa_clist #1 \clist_clear:N #1 \clist_map_inline:Nn \l_tmpa_clist { \cs_set_nopar:Npn \l_tmpa_tl { ##1 } \tl_if_in:NnTF \l_tmpa_tl { - } { \@@_cut_on_hyphen:w ##1 \q_stop } { \@@_cut_on_hyphen:w ##1 - ##1 \q_stop } \bool_lazy_or:nnT { \tl_if_blank_p:o \l_tmpa_tl } { \str_if_eq_p:on \l_tmpa_tl { * } } { \cs_set_nopar:Npn \l_tmpa_tl { 1 } } \bool_lazy_or:nnT { \tl_if_blank_p:o \l_tmpb_tl } { \str_if_eq_p:on \l_tmpb_tl { * } } { \tl_set:No \l_tmpb_tl { \int_use:N #2 } } \int_compare:nNnT \l_tmpb_tl > #2 { \tl_set:No \l_tmpb_tl { \int_use:N #2 } } \int_step_inline:nnn \l_tmpa_tl \l_tmpb_tl { \clist_put_right:Nn #1 { ####1 } } } } % \end{macrocode} % % \bigskip % When the user uses the key |color-inside|, the following command will % be linked to |\cellcolor| in the tabular. % \begin{macrocode} \NewDocumentCommand \@@_cellcolor_tabular { O { } m } { \@@_test_color_inside: \tl_gput_right:Nx \g_@@_pre_code_before_tl { % \end{macrocode} % We must not expand the color (|#2|) because the color may contain the token % |!| which may be activated by some packages (ex.: \pkg{babel} with the option % |french| on latex and pdflatex). % \begin{macrocode} \@@_cellcolor [ #1 ] { \exp_not:n { #2 } } { \int_use:N \c@iRow - \int_use:N \c@jCol } } \ignorespaces } % \end{macrocode} % % \bigskip % When the user uses the key |color-inside|, the following command will % be linked to |\rowcolor| in the tabular. % \begin{macrocode} \NewDocumentCommand \@@_rowcolor_tabular { O { } m } { \@@_test_color_inside: \tl_gput_right:Nx \g_@@_pre_code_before_tl { \@@_rectanglecolor [ #1 ] { \exp_not:n { #2 } } { \int_use:N \c@iRow - \int_use:N \c@jCol } { \int_use:N \c@iRow - \exp_not:n { \int_use:N \c@jCol } } } \ignorespaces } % \end{macrocode} % % \bigskip % When the user uses the key |color-inside|, the following command will % be linked to |\rowcolors| in the tabular. The last argument (an optional % argument between square brackets is taken by curryfication). % \begin{macrocode} \NewDocumentCommand { \@@_rowcolors_tabular } { O { } m m } { \@@_rowlistcolors_tabular [ #1 ] { { #2 } , { #3 } } } % \end{macrocode} % The braces around |#2| and |#3| are mandatory. % % \bigskip % When the user uses the key |color-inside|, the following command will % be linked to |\rowlistcolors| in the tabular. % \begin{macrocode} \NewDocumentCommand { \@@_rowlistcolors_tabular } { O { } m O { } } { \@@_test_color_inside: \peek_remove_spaces:n { \@@_rowlistcolors_tabular:nnn { #1 } { #2 } { #3 } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_rowlistcolors_tabular:nnn #1 #2 #3 { % \end{macrocode} % A use of |\rowlistcolors| in the tabular erases the instructions % |\rowlistcolors| which are in force. However, it's possible to put \emph{several} % instructions |\rowlistcolors| in the same row of a tabular: it may be useful % when those instructions |\rowlistcolors| concerns different columns of the % tabular (thanks to the key |cols| of |\rowlistcolors|). That's why we store % the different instructions |\rowlistcolors| which are in force in a sequence % |\g_@@_rowlistcolors_seq|. Now, we will filter that sequence to keep only the % elements which have been issued on the actual row. We will store the elements % to keep in the |\g_tmpa_seq|. % \begin{macrocode} \seq_gclear:N \g_tmpa_seq \seq_map_inline:Nn \g_@@_rowlistcolors_seq { \@@_rowlistcolors_tabular_i:nnnn ##1 } \seq_gset_eq:NN \g_@@_rowlistcolors_seq \g_tmpa_seq % \end{macrocode} % Now, we add to the sequence |\g_@@_rowlistcolors_seq| (which is the list of % the commands |\rowlistcolors| which are in force) the current instruction % |\rowlistcolors|. % \begin{macrocode} \seq_gput_right:Nx \g_@@_rowlistcolors_seq { { \int_use:N \c@iRow } { \exp_not:n { #1 } } { \exp_not:n { #2 } } { restart , cols = \int_use:N \c@jCol - , \exp_not:n { #3 } } } } % \end{macrocode} % % % \bigskip % The following command will be applied to each component of % |\g_@@_rowlistcolors_seq|. Each component of that sequence is a kind of 4-uple % of the form |{#1}{#2}{#3}{#4}|. % % |#1| is the number of the row where the command |\rowlistcolors| has been % issued. % % |#2| is the colorimetric space (optional argument of the |\rowlistcolors|). % % |#3| is the list of colors (mandatory argument of |\rowlistcolors|). % % |#4| is the list of \textsl{key=value} pairs (last optional argument of % |\rowlistcolors|). % % \begin{macrocode} \cs_new_protected:Npn \@@_rowlistcolors_tabular_i:nnnn #1 #2 #3 #4 { \int_compare:nNnTF { #1 } = \c@iRow % \end{macrocode} % We (temporary) keep in memory in |\g_tmpa_seq| the instructions which will % still be in force after the current instruction (because they have been issued % in the same row of the tabular). % \begin{macrocode} { \seq_gput_right:Nn \g_tmpa_seq { { #1 } { #2 } { #3 } { #4 } } } { \tl_gput_right:Nx \g_@@_pre_code_before_tl { \@@_rowlistcolors [ \exp_not:n { #2 } ] { #1 - \int_eval:n { \c@iRow - 1 } } { \exp_not:n { #3 } } [ \exp_not:n { #4 } ] } } } % \end{macrocode} % % \bigskip % The following command will be used at the end of the tabular, just before the % execution of the |\g_@@_pre_code_before_tl|. It clears the sequence % |\g_@@_rowlistcolors_seq| of all the commands |\rowlistcolors| which are % (still) in force. % \begin{macrocode} \cs_new_protected:Npn \@@_clear_rowlistcolors_seq: { \seq_map_inline:Nn \g_@@_rowlistcolors_seq { \@@_rowlistcolors_tabular_ii:nnnn ##1 } \seq_gclear:N \g_@@_rowlistcolors_seq } % \end{macrocode} % % \medskip % \begin{macrocode} \cs_new_protected:Npn \@@_rowlistcolors_tabular_ii:nnnn #1 #2 #3 #4 { \tl_gput_right:Nn \g_@@_pre_code_before_tl { \@@_rowlistcolors [ #2 ] { #1 } { #3 } [ #4 ] } } % \end{macrocode} % The first mandatory argument of the command |\@@_rowlistcolors| which is % writtent in the pre-|\CodeBefore| is of the form |i|: it means that the % command must be applied to all the rows from the row~$i$ until the end of the % tabular. % % \bigskip % \begin{macrocode} \NewDocumentCommand \@@_columncolor_preamble { O { } m } { % \end{macrocode} % With the following line, we test whether the cell is the first one we % encounter in its column (don't forget that some rows may be incomplete). % \begin{macrocode} \int_compare:nNnT \c@jCol > \g_@@_col_total_int { % \end{macrocode} % You use |gput_left| because we want the specification of colors for the % columns drawn before the specifications of color for the rows (and the cells). % Be careful: maybe this is not effective since we have an analyze of the % instructions in the |\CodeBefore| in order to fill color by color (to avoid % the thin white lines). % \begin{macrocode} \tl_gput_left:Nx \g_@@_pre_code_before_tl { \exp_not:N \columncolor [ #1 ] { \exp_not:n { #2 } } { \int_use:N \c@jCol } } } } % \end{macrocode} % % % \bigskip % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \IfPackageLoadedTF { colortbl } { \cs_set_eq:NN \@@_old_cellcolor \cellcolor \cs_set_eq:NN \@@_old_rowcolor \rowcolor \cs_new_protected:Npn \@@_revert_colortbl: { \hook_gput_code:nnn { env / tabular / begin } { . } { \cs_set_eq:NN \cellcolor \@@_old_cellcolor \cs_set_eq:NN \rowcolor \@@_old_rowcolor } } } { \cs_new_protected:Npn \@@_revert_colortbl: { } } } % \end{macrocode} % % \bigskip % \section{The vertical and horizontal rules} % % % \bigskip % \subsubsection*{OnlyMainNiceMatrix} % % We give to the user the possibility to define new types of columns (with % |\newcolumntype| of \pkg{array}) for special vertical rules (\emph{e.g.} rules % thicker than the standard ones) which will not extend in the potential % exterior rows of the array. % % We provide the command |\OnlyMainNiceMatrix| in that goal. However, that % command must be no-op outside the environments of \pkg{nicematrix} (and so the % user will be allowed to use the same new type of column in the environments % of \pkg{nicematrix} and in the standard environments of \pkg{array}). % % That's why we provide first a global definition of |\OnlyMainNiceMatrix|. % \begin{macrocode} \cs_set_eq:NN \OnlyMainNiceMatrix \use:n % \end{macrocode} % % \medskip % Another definition of |\OnlyMainNiceMatrix| will be linked to the command in % the environments of \pkg{nicematrix}. Here is that definition, called % |\@@_OnlyMainNiceMatrix:n|. % % \begin{macrocode} \cs_new_protected:Npn \@@_OnlyMainNiceMatrix:n #1 { \int_if_zero:nTF \l_@@_first_col_int { \@@_OnlyMainNiceMatrix_i:n { #1 } } { \int_if_zero:nTF \c@jCol { \int_compare:nNnF \c@iRow = { -1 } { \int_compare:nNnF \c@iRow = { \l_@@_last_row_int - 1 } { #1 } } } { \@@_OnlyMainNiceMatrix_i:n { #1 } } } } % \end{macrocode} % This definition may seem complicated but we must remind that the number of row % |\c@iRow| is incremented in the first cell of the row, \emph{after} a % potential vertical rule on the left side of the first cell. % % \smallskip % The command |\@@_OnlyMainNiceMatrix_i:n| is only a short-cut which is used % twice in the above command. This command must \emph{not} be protected. % \begin{macrocode} \cs_new_protected:Npn \@@_OnlyMainNiceMatrix_i:n #1 { \int_if_zero:nF \c@iRow { \int_compare:nNnF \c@iRow = \l_@@_last_row_int { \int_compare:nNnT \c@jCol > \c_zero_int { \bool_if:NF \l_@@_in_last_col_bool { #1 } } } } } % \end{macrocode} % Remember that |\c@iRow| is not always inferior to |\l_@@_last_row_int| because % |\l_@@_last_row_int| may be equal to $-2$ or $-1$ (we can't write % |\int_compare:nNnT \c@iRow < \l_@@_last_row_int|). % % % \bigskip % \subsubsection*{General system for drawing rules} % % When a command, environment or ``subsystem'' of \pkg{nicematrix} wants to draw % a rule, it will write in the internal |\CodeAfter| a command |\@@_vline:n| or % |\@@_hline:n|. Both commands take in as argument a list of \textsl{key=value} % pairs. That list will first be analyzed with the following set of keys. % However, unknown keys will be analyzed further with another set of keys. % % \begin{macrocode} \keys_define:nn { NiceMatrix / Rules } { position .int_set:N = \l_@@_position_int , position .value_required:n = true , start .int_set:N = \l_@@_start_int , end .code:n = \bool_lazy_or:nnTF { \tl_if_empty_p:n { #1 } } { \str_if_eq_p:nn { #1 } { last } } { \int_set_eq:NN \l_@@_end_int \c@jCol } { \int_set:Nn \l_@@_end_int { #1 } } } % \end{macrocode} % % \bigskip % It's possible that the rule won't be drawn continuously from |start| ot |end| % because of the blocks (created with the command |\Block|), the virtual blocks % (created by |\Cdots|, etc.), etc. That's why an analyse is done and the rule % is cut in small rules which will actually be drawn. The small continuous rules % will be drawn by |\@@_vline_ii:| and |\@@_hline_ii:|. Those commands use the % following set of keys. % % \begin{macrocode} \keys_define:nn { NiceMatrix / RulesBis } { multiplicity .int_set:N = \l_@@_multiplicity_int , multiplicity .initial:n = 1 , dotted .bool_set:N = \l_@@_dotted_bool , dotted .initial:n = false , dotted .default:n = true , % \end{macrocode} % We want that, even when the rule has been defined with TikZ by the key |tikz|, % the user has still the possibility to change the color of the rule with the key % |color| (in the command |\Hline|, not in the key |tikz| of the command % |\Hline|). The main use is, when the user has defined its own command % |\MyDashedLine| by |\newcommand{\MyDashedRule}{\Hline[tikz=dashed]}|, to give % the ability to write |\MyDashedRule[color=red]|. % \begin{macrocode} color .code:n = \@@_set_CT@arc@:n { #1 } \tl_set:Nn \l_@@_rule_color_tl { #1 } , color .value_required:n = true , sep-color .code:n = \@@_set_CT@drsc@:n { #1 } , sep-color .value_required:n = true , % \end{macrocode} % If the user uses the key |tikz|, the rule (or more precisely: the different % sub-rules since a rule may be broken by blocks or others) will be drawn with % Tikz. % \begin{macrocode} tikz .code:n = \IfPackageLoadedTF { tikz } { \clist_put_right:Nn \l_@@_tikz_rule_tl { #1 } } { \@@_error:n { tikz~without~tikz } } , tikz .value_required:n = true , total-width .dim_set:N = \l_@@_rule_width_dim , total-width .value_required:n = true , width .meta:n = { total-width = #1 } , unknown .code:n = \@@_error:n { Unknow~key~for~RulesBis } } % \end{macrocode} % % % \subsubsection*{The vertical rules} % % The following command will be executed in the internal |\CodeAfter|. The % argument |#1| is a list of \textsl{key=value} pairs. % \begin{macrocode} \cs_new_protected:Npn \@@_vline:n #1 { % \end{macrocode} % The group is for the options. % \begin{macrocode} \group_begin: \int_set_eq:NN \l_@@_end_int \c@iRow \keys_set_known:nnN { NiceMatrix / Rules } { #1 } \l_@@_other_keys_tl % \end{macrocode} % The following test is for the case where the user does not use all the columns % specified in the preamble of the environment (for instance, a preamble of % \verb+|c|c|c|+ but only two columns used). % \begin{macrocode} \int_compare:nNnT \l_@@_position_int < { \c@jCol + 2 } \@@_vline_i: \group_end: } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_vline_i: { % \end{macrocode} % |\l_tmpa_tl| is the number of row and |\l_tmpb_tl| the number of column. When % we have found a row corresponding to a rule to draw, we note its number in % |\l_@@_tmpc_tl|. % \begin{macrocode} \tl_set:No \l_tmpb_tl { \int_use:N \l_@@_position_int } \int_step_variable:nnNn \l_@@_start_int \l_@@_end_int \l_tmpa_tl { % \end{macrocode} % The boolean |\g_tmpa_bool| indicates whether the small vertical rule will be % drawn. If we find that it is in a block (a real block, created by |\Block| or % a virtual block corresponding to a dotted line, created by |\Cdots|, |\Vdots|, % etc.), we will set |\g_tmpa_bool| to |false| and the small vertical rule won't % be drawn. % \begin{macrocode} \bool_gset_true:N \g_tmpa_bool \seq_map_inline:Nn \g_@@_pos_of_blocks_seq { \@@_test_vline_in_block:nnnnn ##1 } \seq_map_inline:Nn \g_@@_pos_of_xdots_seq { \@@_test_vline_in_block:nnnnn ##1 } \seq_map_inline:Nn \g_@@_pos_of_stroken_blocks_seq { \@@_test_vline_in_stroken_block:nnnn ##1 } \clist_if_empty:NF \l_@@_corners_clist \@@_test_in_corner_v: \bool_if:NTF \g_tmpa_bool { \int_if_zero:nT \l_@@_local_start_int % \end{macrocode} % We keep in memory that we have a rule to draw. |\l_@@_local_start_int| will be % the starting row of the rule that we will have to draw. % \begin{macrocode} { \int_set:Nn \l_@@_local_start_int \l_tmpa_tl } } { \int_compare:nNnT \l_@@_local_start_int > \c_zero_int { \int_set:Nn \l_@@_local_end_int { \l_tmpa_tl - 1 } \@@_vline_ii: \int_zero:N \l_@@_local_start_int } } } \int_compare:nNnT \l_@@_local_start_int > \c_zero_int { \int_set_eq:NN \l_@@_local_end_int \l_@@_end_int \@@_vline_ii: } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_test_in_corner_v: { \int_compare:nNnTF \l_tmpb_tl = { \int_eval:n { \c@jCol + 1 } } { \seq_if_in:NxT \l_@@_corners_cells_seq { \l_tmpa_tl - \int_eval:n { \l_tmpb_tl - 1 } } { \bool_set_false:N \g_tmpa_bool } } { \seq_if_in:NxT \l_@@_corners_cells_seq { \l_tmpa_tl - \l_tmpb_tl } { \int_compare:nNnTF \l_tmpb_tl = \c_one_int { \bool_set_false:N \g_tmpa_bool } { \seq_if_in:NxT \l_@@_corners_cells_seq { \l_tmpa_tl - \int_eval:n { \l_tmpb_tl - 1 } } { \bool_set_false:N \g_tmpa_bool } } } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_vline_ii: { \tl_clear:N \l_@@_tikz_rule_tl \keys_set:nV { NiceMatrix / RulesBis } \l_@@_other_keys_tl \bool_if:NTF \l_@@_dotted_bool \@@_vline_iv: { \tl_if_empty:NTF \l_@@_tikz_rule_tl \@@_vline_iii: \@@_vline_v: } } % \end{macrocode} % % \bigskip % First the case of a standard rule: the user has not used the key |dotted| nor % the key |tikz|. % \begin{macrocode} \cs_new_protected:Npn \@@_vline_iii: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_qpoint:n { row - \int_use:N \l_@@_local_start_int } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint:n { col - \int_use:N \l_@@_position_int } \dim_set:Nn \l_tmpb_dim { \pgf@x - 0.5 \l_@@_rule_width_dim + ( \arrayrulewidth * \l_@@_multiplicity_int + \doublerulesep * ( \l_@@_multiplicity_int - 1 ) ) / 2 } \@@_qpoint:n { row - \int_eval:n { \l_@@_local_end_int + 1 } } \dim_set_eq:NN \l_@@_tmpc_dim \pgf@y \bool_lazy_all:nT { { \int_compare_p:nNn \l_@@_multiplicity_int > \c_one_int } { \cs_if_exist_p:N \CT@drsc@ } { ! \tl_if_blank_p:o \CT@drsc@ } } { \group_begin: \CT@drsc@ \dim_add:Nn \l_tmpa_dim { 0.5 \arrayrulewidth } \dim_sub:Nn \l_@@_tmpc_dim { 0.5 \arrayrulewidth } \dim_set:Nn \l_@@_tmpd_dim { \l_tmpb_dim - ( \doublerulesep + \arrayrulewidth ) * ( \l_@@_multiplicity_int - 1 ) } \pgfpathrectanglecorners { \pgfpoint \l_tmpb_dim \l_tmpa_dim } { \pgfpoint \l_@@_tmpd_dim \l_@@_tmpc_dim } \pgfusepath { fill } \group_end: } \pgfpathmoveto { \pgfpoint \l_tmpb_dim \l_tmpa_dim } \pgfpathlineto { \pgfpoint \l_tmpb_dim \l_@@_tmpc_dim } \prg_replicate:nn { \l_@@_multiplicity_int - 1 } { \dim_sub:Nn \l_tmpb_dim \arrayrulewidth \dim_sub:Nn \l_tmpb_dim \doublerulesep \pgfpathmoveto { \pgfpoint \l_tmpb_dim \l_tmpa_dim } \pgfpathlineto { \pgfpoint \l_tmpb_dim \l_@@_tmpc_dim } } \CT@arc@ \pgfsetlinewidth { 1.1 \arrayrulewidth } \pgfsetrectcap \pgfusepathqstroke \endpgfpicture } % \end{macrocode} % % % \bigskip % The following code is for the case of a dotted rule (with our system of % rounded dots). % \begin{macrocode} \cs_new_protected:Npn \@@_vline_iv: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_qpoint:n { col - \int_use:N \l_@@_position_int } \dim_set:Nn \l_@@_x_initial_dim { \pgf@x - 0.5 \l_@@_rule_width_dim } \dim_set_eq:NN \l_@@_x_final_dim \l_@@_x_initial_dim \@@_qpoint:n { row - \int_use:N \l_@@_local_start_int } \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y \@@_qpoint:n { row - \int_eval:n { \l_@@_local_end_int + 1 } } \dim_set_eq:NN \l_@@_y_final_dim \pgf@y \CT@arc@ \@@_draw_line: \endpgfpicture } % \end{macrocode} % % \bigskip % The following code is for the case when the user uses the key |tikz|. % \begin{macrocode} \cs_new_protected:Npn \@@_vline_v: { \begin {tikzpicture } % added 2023/09/25 % \end{macrocode} % By default, the color defined by |\arrayrulecolor| or by |rules/color| will be % used, but it's still possible to change the color by using the key |color| or, % of course, the key |color| inside the key |tikz| (that is to say the key % |color| provided by \textsc{pgf}. % \begin{macrocode} \CT@arc@ \tl_if_empty:NF \l_@@_rule_color_tl { \tl_put_right:Nx \l_@@_tikz_rule_tl { , color = \l_@@_rule_color_tl } } \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_qpoint:n { row - \int_use:N \l_@@_local_start_int } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint:n { col - \int_use:N \l_@@_position_int } \dim_set:Nn \l_tmpb_dim { \pgf@x - 0.5 \l_@@_rule_width_dim } \@@_qpoint:n { row - \int_eval:n { \l_@@_local_end_int + 1 } } \dim_set_eq:NN \l_@@_tmpc_dim \pgf@y \exp_args:No \tikzset \l_@@_tikz_rule_tl \use:e { \exp_not:N \draw [ \l_@@_tikz_rule_tl ] } ( \l_tmpb_dim , \l_tmpa_dim ) -- ( \l_tmpb_dim , \l_@@_tmpc_dim ) ; \end { tikzpicture } } % \end{macrocode} % % % \bigskip % The command |\@@_draw_vlines:| draws all the vertical rules excepted in the % blocks, in the virtual blocks (determined by a command such as |\Cdots|) and in % the corners (if the key |corners| is used). % \begin{macrocode} \cs_new_protected:Npn \@@_draw_vlines: { \int_step_inline:nnn { \bool_lazy_or:nnTF \g_@@_delims_bool \l_@@_except_borders_bool 2 1 } { \bool_lazy_or:nnTF \g_@@_delims_bool \l_@@_except_borders_bool \c@jCol { \int_eval:n { \c@jCol + 1 } } } { \tl_if_eq:NNF \l_@@_vlines_clist \c_@@_all_tl { \clist_if_in:NnT \l_@@_vlines_clist { ##1 } } { \@@_vline:n { position = ##1 , total-width = \arrayrulewidth } } } } % \end{macrocode} % % % % \subsubsection*{The horizontal rules} % % \bigskip % The following command will be executed in the internal |\CodeAfter|. The % argument |#1| is a list of \textsl{key=value} pairs of the form % |{NiceMatrix/Rules}|. % \begin{macrocode} \cs_new_protected:Npn \@@_hline:n #1 { % \end{macrocode} % The group is for the options. % \begin{macrocode} \group_begin: \int_zero_new:N \l_@@_end_int \int_set_eq:NN \l_@@_end_int \c@jCol \keys_set_known:nnN { NiceMatrix / Rules } { #1 } \l_@@_other_keys_tl \@@_hline_i: \group_end: } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_hline_i: { \int_zero_new:N \l_@@_local_start_int \int_zero_new:N \l_@@_local_end_int % \end{macrocode} % |\l_tmpa_tl| is the number of row and |\l_tmpb_tl| the number of column. When % we have found a column corresponding to a rule to draw, we note its number in % |\l_@@_tmpc_tl|. % \begin{macrocode} \tl_set:No \l_tmpa_tl { \int_use:N \l_@@_position_int } \int_step_variable:nnNn \l_@@_start_int \l_@@_end_int \l_tmpb_tl { % \end{macrocode} % The boolean |\g_tmpa_bool| indicates whether the small horizontal rule will be % drawn. If we find that it is in a block (a real block, created by |\Block| or % a virtual block corresponding to a dotted line, created by |\Cdots|, |\Vdots|, % etc.), we will set |\g_tmpa_bool| to |false| and the small horizontal rule won't % be drawn. % \begin{macrocode} \bool_gset_true:N \g_tmpa_bool \seq_map_inline:Nn \g_@@_pos_of_blocks_seq { \@@_test_hline_in_block:nnnnn ##1 } \seq_map_inline:Nn \g_@@_pos_of_xdots_seq { \@@_test_hline_in_block:nnnnn ##1 } \seq_map_inline:Nn \g_@@_pos_of_stroken_blocks_seq { \@@_test_hline_in_stroken_block:nnnn ##1 } \clist_if_empty:NF \l_@@_corners_clist \@@_test_in_corner_h: \bool_if:NTF \g_tmpa_bool { \int_if_zero:nT \l_@@_local_start_int % \end{macrocode} % We keep in memory that we have a rule to draw. |\l_@@_local_start_int| will be % the starting row of the rule that we will have to draw. % \begin{macrocode} { \int_set:Nn \l_@@_local_start_int \l_tmpb_tl } } { \int_compare:nNnT \l_@@_local_start_int > \c_zero_int { \int_set:Nn \l_@@_local_end_int { \l_tmpb_tl - 1 } \@@_hline_ii: \int_zero:N \l_@@_local_start_int } } } \int_compare:nNnT \l_@@_local_start_int > \c_zero_int { \int_set_eq:NN \l_@@_local_end_int \l_@@_end_int \@@_hline_ii: } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_test_in_corner_h: { \int_compare:nNnTF \l_tmpa_tl = { \int_eval:n { \c@iRow + 1 } } { \seq_if_in:NxT \l_@@_corners_cells_seq { \int_eval:n { \l_tmpa_tl - 1 } - \l_tmpb_tl } { \bool_set_false:N \g_tmpa_bool } } { \seq_if_in:NxT \l_@@_corners_cells_seq { \l_tmpa_tl - \l_tmpb_tl } { \int_compare:nNnTF \l_tmpa_tl = \c_one_int { \bool_set_false:N \g_tmpa_bool } { \seq_if_in:NxT \l_@@_corners_cells_seq { \int_eval:n { \l_tmpa_tl - 1 } - \l_tmpb_tl } { \bool_set_false:N \g_tmpa_bool } } } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_hline_ii: { \tl_clear:N \l_@@_tikz_rule_tl \keys_set:nV { NiceMatrix / RulesBis } \l_@@_other_keys_tl \bool_if:NTF \l_@@_dotted_bool \@@_hline_iv: { \tl_if_empty:NTF \l_@@_tikz_rule_tl \@@_hline_iii: \@@_hline_v: } } % \end{macrocode} % % \bigskip % First the case of a standard rule (without the keys |dotted| and |tikz|). % \begin{macrocode} \cs_new_protected:Npn \@@_hline_iii: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_qpoint:n { col - \int_use:N \l_@@_local_start_int } \dim_set_eq:NN \l_tmpa_dim \pgf@x \@@_qpoint:n { row - \int_use:N \l_@@_position_int } \dim_set:Nn \l_tmpb_dim { \pgf@y - 0.5 \l_@@_rule_width_dim + ( \arrayrulewidth * \l_@@_multiplicity_int + \doublerulesep * ( \l_@@_multiplicity_int - 1 ) ) / 2 } \@@_qpoint:n { col - \int_eval:n { \l_@@_local_end_int + 1 } } \dim_set_eq:NN \l_@@_tmpc_dim \pgf@x \bool_lazy_all:nT { { \int_compare_p:nNn \l_@@_multiplicity_int > \c_one_int } { \cs_if_exist_p:N \CT@drsc@ } { ! \tl_if_blank_p:o \CT@drsc@ } } { \group_begin: \CT@drsc@ \dim_set:Nn \l_@@_tmpd_dim { \l_tmpb_dim - ( \doublerulesep + \arrayrulewidth ) * ( \l_@@_multiplicity_int - 1 ) } \pgfpathrectanglecorners { \pgfpoint \l_tmpa_dim \l_tmpb_dim } { \pgfpoint \l_@@_tmpc_dim \l_@@_tmpd_dim } \pgfusepathqfill \group_end: } \pgfpathmoveto { \pgfpoint \l_tmpa_dim \l_tmpb_dim } \pgfpathlineto { \pgfpoint \l_@@_tmpc_dim \l_tmpb_dim } \prg_replicate:nn { \l_@@_multiplicity_int - 1 } { \dim_sub:Nn \l_tmpb_dim \arrayrulewidth \dim_sub:Nn \l_tmpb_dim \doublerulesep \pgfpathmoveto { \pgfpoint \l_tmpa_dim \l_tmpb_dim } \pgfpathlineto { \pgfpoint \l_@@_tmpc_dim \l_tmpb_dim } } \CT@arc@ \pgfsetlinewidth { 1.1 \arrayrulewidth } \pgfsetrectcap \pgfusepathqstroke \endpgfpicture } % \end{macrocode} % % \bigskip % The following code is for the case of a dotted rule (with our system of % rounded dots). % The aim is that, by standard the dotted line fits between square brackets % (|\hline| doesn't). % % \smallskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix} % 1 & 2 & 3 & 4 \\ % \hline % 1 & 2 & 3 & 4 \\ % \hdottedline % 1 & 2 & 3 & 4 % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix} % 1 & 2 & 3 & 4 \\ % \hline % 1 & 2 & 3 & 4 \\ % \hdottedline % 1 & 2 & 3 & 4 % \end{bNiceMatrix}$ % % \smallskip % But, if the user uses |margin|, the dotted line extends to have the same width % as a |\hline|. % % \smallskip % \begin{BVerbatim}[baseline=c,boxwidth=10cm] % \begin{bNiceMatrix}[margin] % 1 & 2 & 3 & 4 \\ % \hline % 1 & 2 & 3 & 4 \\ % \hdottedline % 1 & 2 & 3 & 4 % \end{bNiceMatrix} % \end{BVerbatim} % $\begin{bNiceMatrix}[margin] % 1 & 2 & 3 & 4 \\ % \hline % 1 & 2 & 3 & 4 \\ % \hdottedline % 1 & 2 & 3 & 4 % \end{bNiceMatrix}$ % % \begin{macrocode} \cs_new_protected:Npn \@@_hline_iv: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_qpoint:n { row - \int_use:N \l_@@_position_int } \dim_set:Nn \l_@@_y_initial_dim { \pgf@y - 0.5 \l_@@_rule_width_dim } \dim_set_eq:NN \l_@@_y_final_dim \l_@@_y_initial_dim \@@_qpoint:n { col - \int_use:N \l_@@_local_start_int } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x \int_compare:nNnT \l_@@_local_start_int = \c_one_int { \dim_sub:Nn \l_@@_x_initial_dim \l_@@_left_margin_dim \bool_if:NF \g_@@_delims_bool { \dim_sub:Nn \l_@@_x_initial_dim \arraycolsep } % \end{macrocode} % For reasons purely aesthetic, we do an adjustment in the case of a rounded % bracket. The correction by |0.5 \l_@@_xdots_inter_dim| is \emph{ad hoc} for a % better result. % \begin{macrocode} \tl_if_eq:NnF \g_@@_left_delim_tl ( { \dim_add:Nn \l_@@_x_initial_dim { 0.5 \l_@@_xdots_inter_dim } } } \@@_qpoint:n { col - \int_eval:n { \l_@@_local_end_int + 1 } } \dim_set_eq:NN \l_@@_x_final_dim \pgf@x \int_compare:nNnT \l_@@_local_end_int = \c@jCol { \dim_add:Nn \l_@@_x_final_dim \l_@@_right_margin_dim \bool_if:NF \g_@@_delims_bool { \dim_add:Nn \l_@@_x_final_dim \arraycolsep } \tl_if_eq:NnF \g_@@_right_delim_tl ) { \dim_gsub:Nn \l_@@_x_final_dim { 0.5 \l_@@_xdots_inter_dim } } } \CT@arc@ \@@_draw_line: \endpgfpicture } % \end{macrocode} % % \bigskip % The following code is for the case when the user uses the key |tikz| (in the % definition of a customized rule by using the key |custom-line|). % \begin{macrocode} \cs_new_protected:Npn \@@_hline_v: { \begin { tikzpicture } % added 2023/09/25 % \end{macrocode} % By default, the color defined by |\arrayrulecolor| or by |rules/color| will be % used, but it's still possible to change the color by using the key |color| or, % of course, the key |color| inside the key |tikz| (that is to say the key % |color| provided by \textsc{pgf}. % \begin{macrocode} \CT@arc@ \tl_if_empty:NF \l_@@_rule_color_tl { \tl_put_right:Nx \l_@@_tikz_rule_tl { , color = \l_@@_rule_color_tl } } \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_qpoint:n { col - \int_use:N \l_@@_local_start_int } \dim_set_eq:NN \l_tmpa_dim \pgf@x \@@_qpoint:n { row - \int_use:N \l_@@_position_int } \dim_set:Nn \l_tmpb_dim { \pgf@y - 0.5 \l_@@_rule_width_dim } \@@_qpoint:n { col - \int_eval:n { \l_@@_local_end_int + 1 } } \dim_set_eq:NN \l_@@_tmpc_dim \pgf@x \exp_args:No \tikzset \l_@@_tikz_rule_tl \use:e { \exp_not:N \draw [ \l_@@_tikz_rule_tl ] } ( \l_tmpa_dim , \l_tmpb_dim ) -- ( \l_@@_tmpc_dim , \l_tmpb_dim ) ; \end { tikzpicture } } % \end{macrocode} % % % \bigskip % The command |\@@_draw_hlines:| draws all the horizontal rules excepted in the % blocks (even the virtual blocks determined by commands such as |\Cdots| and in % the corners --- if the key |corners| is used). % \begin{macrocode} \cs_new_protected:Npn \@@_draw_hlines: { \int_step_inline:nnn { \bool_lazy_or:nnTF \g_@@_delims_bool \l_@@_except_borders_bool 2 1 } { \bool_lazy_or:nnTF \g_@@_delims_bool \l_@@_except_borders_bool \c@iRow { \int_eval:n { \c@iRow + 1 } } } { \tl_if_eq:NNF \l_@@_hlines_clist \c_@@_all_tl { \clist_if_in:NnT \l_@@_hlines_clist { ##1 } } { \@@_hline:n { position = ##1 , total-width = \arrayrulewidth } } } } % \end{macrocode} % % % \medskip % The command |\@@_Hline:| will be linked to |\Hline| in the environments of % \pkg{nicematrix}. % \begin{macrocode} \cs_set:Npn \@@_Hline: { \noalign \bgroup \@@_Hline_i:n { 1 } } % \end{macrocode} % % \medskip % The argument of the command |\@@_Hline_i:n| is the number of successive % |\Hline| found. % \begin{macrocode} \cs_set:Npn \@@_Hline_i:n #1 { \peek_remove_spaces:n { \peek_meaning:NTF \Hline { \@@_Hline_ii:nn { #1 + 1 } } { \@@_Hline_iii:n { #1 } } } } % \end{macrocode} % % \begin{macrocode} \cs_set:Npn \@@_Hline_ii:nn #1 #2 { \@@_Hline_i:n { #1 } } % \end{macrocode} % % \begin{macrocode} \cs_set:Npn \@@_Hline_iii:n #1 { \@@_collect_options:n { \@@_Hline_iv:nn { #1 } } } % \end{macrocode} % % % \begin{macrocode} \cs_set:Npn \@@_Hline_iv:nn #1 #2 { \@@_compute_rule_width:n { multiplicity = #1 , #2 } \skip_vertical:N \l_@@_rule_width_dim \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_hline:n { multiplicity = #1 , position = \int_eval:n { \c@iRow + 1 } , total-width = \dim_use:N \l_@@_rule_width_dim , #2 } } \egroup } % \end{macrocode} % % \subsubsection*{Customized rules defined by the final user} % % The final user can define a customized rule by using the key |custom-line| in % |\NiceMatrixOptions|. That key takes in as value a list of \textsl{key=value} % pairs. % % % % \medskip % The following command will create the customized rule (it is executed when the % final user uses the key |custom-line|, for example in |\NiceMatrixOptions|). % \begin{macrocode} \cs_new_protected:Npn \@@_custom_line:n #1 { \str_clear_new:N \l_@@_command_str \str_clear_new:N \l_@@_ccommand_str \str_clear_new:N \l_@@_letter_str \tl_clear_new:N \l_@@_other_keys_tl \keys_set_known:nnN { NiceMatrix / custom-line } { #1 } \l_@@_other_keys_tl % \end{macrocode} % If the final user only wants to draw horizontal rules, he does not need to % specify a letter (for the vertical rules in the preamble of the array). On the % other hand, if he only wants to draw vertical rules, he does not need to % define a command (which is the tool to draw horizontal rules in the array). Of % course, a definition of custom lines with no letter and no command would be point-less. % % \begin{macrocode} \bool_lazy_all:nTF { { \str_if_empty_p:N \l_@@_letter_str } { \str_if_empty_p:N \l_@@_command_str } { \str_if_empty_p:N \l_@@_ccommand_str } } { \@@_error:n { No~letter~and~no~command } } { \exp_args:No \@@_custom_line_i:n \l_@@_other_keys_tl } } % \end{macrocode} % % % \begin{macrocode} \keys_define:nn { NiceMatrix / custom-line } { letter .str_set:N = \l_@@_letter_str , letter .value_required:n = true , command .str_set:N = \l_@@_command_str , command .value_required:n = true , ccommand .str_set:N = \l_@@_ccommand_str , ccommand .value_required:n = true , } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_custom_line_i:n #1 { % \end{macrocode} % The following flags will be raised when the keys |tikz|, |dotted| and |color| % are used (in the |custom-line|). % \begin{macrocode} \bool_set_false:N \l_@@_tikz_rule_bool \bool_set_false:N \l_@@_dotted_rule_bool \bool_set_false:N \l_@@_color_bool % \end{macrocode} % \begin{macrocode} \keys_set:nn { NiceMatrix / custom-line-bis } { #1 } \bool_if:NT \l_@@_tikz_rule_bool { \IfPackageLoadedTF { tikz } { } { \@@_error:n { tikz~in~custom-line~without~tikz } } \bool_if:NT \l_@@_color_bool { \@@_error:n { color~in~custom-line~with~tikz } } } \bool_if:NT \l_@@_dotted_rule_bool { \int_compare:nNnT \l_@@_multiplicity_int > \c_one_int { \@@_error:n { key~multiplicity~with~dotted } } } \str_if_empty:NF \l_@@_letter_str { \int_compare:nTF { \str_count:N \l_@@_letter_str != 1 } { \@@_error:n { Several~letters } } { \exp_args:NnV \tl_if_in:NnTF \c_@@_forbidden_letters_str \l_@@_letter_str { \@@_error:ne { Forbidden~letter } \l_@@_letter_str } { % \end{macrocode} % During the analyse of the preamble provided by the final user, our automaton, % for the letter corresponding at the custom line, will directly use the % following command that you define in the main hash table of TeX. % \begin{macrocode} \cs_set:cpn { @@ _ \l_@@_letter_str } ##1 { \@@_v_custom_line:n { #1 } } } } } \str_if_empty:NF \l_@@_command_str { \@@_h_custom_line:n { #1 } } \str_if_empty:NF \l_@@_ccommand_str { \@@_c_custom_line:n { #1 } } } % \end{macrocode} % % % \begin{macrocode} \tl_const:Nn \c_@@_forbidden_letters_tl { lcrpmbVX|()[]!@<> } \str_const:Nn \c_@@_forbidden_letters_str { lcrpmbVX|()[]!@<> } % \end{macrocode} % % \medskip % The previous command |\@@_custom_line_i:n| uses the following set of keys. % However, the whole definition of the customized lines (as provided by the % final user as argument of |custom-line|) will also be used further with % other sets of keys (for instance |{NiceMatrix/Rules}|). That's why the % following set of keys has some keys which are no-op. % \begin{macrocode} \keys_define:nn { NiceMatrix / custom-line-bis } { multiplicity .int_set:N = \l_@@_multiplicity_int , multiplicity .initial:n = 1 , multiplicity .value_required:n = true , color .code:n = \bool_set_true:N \l_@@_color_bool , color .value_required:n = true , tikz .code:n = \bool_set_true:N \l_@@_tikz_rule_bool , tikz .value_required:n = true , dotted .code:n = \bool_set_true:N \l_@@_dotted_rule_bool , dotted .value_forbidden:n = true , total-width .code:n = { } , total-width .value_required:n = true , width .code:n = { } , width .value_required:n = true , sep-color .code:n = { } , sep-color .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~custom-line } } % \end{macrocode} % % The following keys will indicate whether the keys |dotted|, |tikz| and |color| % are used in the use of a |custom-line|. % \begin{macrocode} \bool_new:N \l_@@_dotted_rule_bool \bool_new:N \l_@@_tikz_rule_bool \bool_new:N \l_@@_color_bool % \end{macrocode} % % \bigskip % The following keys are used to determine the total width of the line % (including the spaces on both sides of the line). The key |width| is % deprecated and has been replaced by the key |total-width|. % % \begin{macrocode} \keys_define:nn { NiceMatrix / custom-line-width } { multiplicity .int_set:N = \l_@@_multiplicity_int , multiplicity .initial:n = 1 , multiplicity .value_required:n = true , tikz .code:n = \bool_set_true:N \l_@@_tikz_rule_bool , total-width .code:n = \dim_set:Nn \l_@@_rule_width_dim { #1 } \bool_set_true:N \l_@@_total_width_bool , total-width .value_required:n = true , width .meta:n = { total-width = #1 } , dotted .code:n = \bool_set_true:N \l_@@_dotted_rule_bool , } % \end{macrocode} % % \bigskip % The following command will create the command that the final user will use in % its array to draw an horizontal rule (hence the `|h|` in the name) with the % full width of the array. |#1| is the whole set of keys to pass to the command % |\@@_hline:n| (which is in the internal |\CodeAfter|). % \begin{macrocode} \cs_new_protected:Npn \@@_h_custom_line:n #1 { % \end{macrocode} % We use |\cs_set:cpn| and not |\cs_new:cpn| because we want a local definition. % Moreover, the command must \emph{not} be protected since it begins with % |\noalign| (which is in |\Hline|). % \begin{macrocode} \cs_set:cpn { nicematrix - \l_@@_command_str } { \Hline [ #1 ] } \seq_put_left:No \l_@@_custom_line_commands_seq \l_@@_command_str } % \end{macrocode} % % \bigskip % \bigskip % The following command will create the command that the final user will use in % its array to draw an horizontal rule on only some of the columns of the array % (hence the letter |c| as in |\cline|). |#1| is the whole set of keys to pass % to the command |\@@_hline:n| (which is in the internal |\CodeAfter|). % % \begin{macrocode} \cs_new_protected:Npn \@@_c_custom_line:n #1 { % \end{macrocode} % Here, we need an expandable command since it begins with an |\noalign|. % \begin{macrocode} \exp_args:Nc \NewExpandableDocumentCommand { nicematrix - \l_@@_ccommand_str } { O { } m } { \noalign { \@@_compute_rule_width:n { #1 , ##1 } \skip_vertical:n { \l_@@_rule_width_dim } \clist_map_inline:nn { ##2 } { \@@_c_custom_line_i:nn { #1 , ##1 } { ####1 } } } } \seq_put_left:No \l_@@_custom_line_commands_seq \l_@@_ccommand_str } % \end{macrocode} % The first argument is the list of key-value pairs characteristic of the line. % The second argument is the specification of columns for the |\cline| with the % syntax $a$-$b$. % \begin{macrocode} \cs_new_protected:Npn \@@_c_custom_line_i:nn #1 #2 { \str_if_in:nnTF { #2 } { - } { \@@_cut_on_hyphen:w #2 \q_stop } { \@@_cut_on_hyphen:w #2 - #2 \q_stop } \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_hline:n { #1 , start = \l_tmpa_tl , end = \l_tmpb_tl , position = \int_eval:n { \c@iRow + 1 } , total-width = \dim_use:N \l_@@_rule_width_dim } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_compute_rule_width:n #1 { \bool_set_false:N \l_@@_tikz_rule_bool \bool_set_false:N \l_@@_total_width_bool \bool_set_false:N \l_@@_dotted_rule_bool \keys_set_known:nn { NiceMatrix / custom-line-width } { #1 } \bool_if:NF \l_@@_total_width_bool { \bool_if:NTF \l_@@_dotted_rule_bool { \dim_set:Nn \l_@@_rule_width_dim { 2 \l_@@_xdots_radius_dim } } { \bool_if:NF \l_@@_tikz_rule_bool { \dim_set:Nn \l_@@_rule_width_dim { \arrayrulewidth * \l_@@_multiplicity_int + \doublerulesep * ( \l_@@_multiplicity_int - 1 ) } } } } } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_v_custom_line:n #1 { \@@_compute_rule_width:n { #1 } % \end{macrocode} % In the following line, the |\dim_use:N| is mandatory since we do an expansion. % \begin{macrocode} \tl_gput_right:Nx \g_@@_array_preamble_tl { \exp_not:N ! { \skip_horizontal:n { \dim_use:N \l_@@_rule_width_dim } } } \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_vline:n { #1 , position = \int_eval:n { \c@jCol + 1 } , total-width = \dim_use:N \l_@@_rule_width_dim } } \@@_rec_preamble:n } % \end{macrocode} % % \begin{macrocode} \@@_custom_line:n { letter = : , command = hdottedline , ccommand = cdottedline, dotted } % \end{macrocode} % % \subsubsection*{The key hvlines} % % The following command tests whether the current position in the array (given by % |\l_tmpa_tl| for the row and |\l_tmpb_tl| for the column) would provide an % horizontal rule towards the right in the block delimited by the four arguments % |#1|, |#2|, |#3| and |#4|. If this rule would be in the block (it must not be % drawn), the boolean |\l_tmpa_bool| is set to |false|. % \begin{macrocode} \cs_new_protected:Npn \@@_test_hline_in_block:nnnnn #1 #2 #3 #4 #5 { \int_compare:nNnT \l_tmpa_tl > { #1 } { \int_compare:nNnT \l_tmpa_tl < { #3 + 1 } { \int_compare:nNnT \l_tmpb_tl > { #2 - 1 } { \int_compare:nNnT \l_tmpb_tl < { #4 + 1 } { \bool_gset_false:N \g_tmpa_bool } } } } } % \end{macrocode} % % The same for vertical rules. % \begin{macrocode} \cs_new_protected:Npn \@@_test_vline_in_block:nnnnn #1 #2 #3 #4 #5 { \int_compare:nNnT \l_tmpa_tl > { #1 - 1 } { \int_compare:nNnT \l_tmpa_tl < { #3 + 1 } { \int_compare:nNnT \l_tmpb_tl > { #2 } { \int_compare:nNnT \l_tmpb_tl < { #4 + 1 } { \bool_gset_false:N \g_tmpa_bool } } } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_test_hline_in_stroken_block:nnnn #1 #2 #3 #4 { \int_compare:nNnT \l_tmpb_tl > { #2 - 1 } { \int_compare:nNnT \l_tmpb_tl < { #4 + 1 } { \int_compare:nNnTF \l_tmpa_tl = { #1 } { \bool_gset_false:N \g_tmpa_bool } { \int_compare:nNnT \l_tmpa_tl = { #3 + 1 } { \bool_gset_false:N \g_tmpa_bool } } } } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_test_vline_in_stroken_block:nnnn #1 #2 #3 #4 { \int_compare:nNnT \l_tmpa_tl > { #1 - 1 } { \int_compare:nNnT \l_tmpa_tl < { #3 + 1 } { \int_compare:nNnTF \l_tmpb_tl = { #2 } { \bool_gset_false:N \g_tmpa_bool } { \int_compare:nNnT \l_tmpb_tl = { #4 + 1 } { \bool_gset_false:N \g_tmpa_bool } } } } } % \end{macrocode} % % \bigskip % \section{The empty corners} % % When the key |corners| is raised, the rules are not drawn in the corners; they % are not colored and |\TikzEveryCell| does not apply. Of course, we have to % compute the corners before we begin to draw the rules. % % \begin{macrocode} \cs_new_protected:Npn \@@_compute_corners: { % \end{macrocode} % The sequence |\l_@@_corners_cells_seq| will be the sequence of all the % empty cells (and not in a block) considered in the corners of the array. % \begin{macrocode} \seq_clear_new:N \l_@@_corners_cells_seq \clist_map_inline:Nn \l_@@_corners_clist { \str_case:nnF { ##1 } { { NW } { \@@_compute_a_corner:nnnnnn 1 1 1 1 \c@iRow \c@jCol } { NE } { \@@_compute_a_corner:nnnnnn 1 \c@jCol 1 { -1 } \c@iRow 1 } { SW } { \@@_compute_a_corner:nnnnnn \c@iRow 1 { -1 } 1 1 \c@jCol } { SE } { \@@_compute_a_corner:nnnnnn \c@iRow \c@jCol { -1 } { -1 } 1 1 } } { \@@_error:nn { bad~corner } { ##1 } } } % \end{macrocode} % Even if the user has used the key |corners| the list of cells in the corners % may be empty. % \begin{macrocode} \seq_if_empty:NF \l_@@_corners_cells_seq { % \end{macrocode} % You write on the |aux| file the list of the cells which are in the (empty) % corners because you need that information in the |\CodeBefore| since the % commands which color the |rows|, |columns| and |cells| must not color the % cells in the corners. % \begin{macrocode} \tl_gput_right:Nx \g_@@_aux_tl { \seq_set_from_clist:Nn \exp_not:N \l_@@_corners_cells_seq { \seq_use:Nnnn \l_@@_corners_cells_seq , , , } } } } % \end{macrocode} % % % \bigskip % ``Computing a corner'' is determining all the empty cells (which are not in a % block) that belong to that corner. These cells will be added to the sequence % |\l_@@_corners_cells_seq|. % % \medskip % The six arguments of |\@@_compute_a_corner:nnnnnn| are as follow: % \begin{itemize} % \item |#1| and |#2| are the number of row and column of the cell which is % actually in the corner; % \item |#3| and |#4| are the steps in rows and the step in columns when moving % from the corner; % \item |#5| is the number of the final row when scanning the rows from the % corner; % \item |#6| is the number of the final column when scanning the columns from % the corner. % \end{itemize} % \begin{macrocode} \cs_new_protected:Npn \@@_compute_a_corner:nnnnnn #1 #2 #3 #4 #5 #6 { % \end{macrocode} % For the explanations and the name of the variables, we consider that we are % computing the left-upper corner. % % First, we try to determine which is the last empty cell (and not in a block: % we won't add that precision any longer) in the column of number~$1$. The flag % |\l_tmpa_bool| will be raised when a non-empty cell is found. % \begin{macrocode} \bool_set_false:N \l_tmpa_bool \int_zero_new:N \l_@@_last_empty_row_int \int_set:Nn \l_@@_last_empty_row_int { #1 } \int_step_inline:nnnn { #1 } { #3 } { #5 } { \@@_test_if_cell_in_a_block:nn { ##1 } { \int_eval:n { #2 } } \bool_lazy_or:nnTF { \cs_if_exist_p:c { pgf @ sh @ ns @ \@@_env: - ##1 - \int_eval:n { #2 } } } \l_tmpb_bool { \bool_set_true:N \l_tmpa_bool } { \bool_if:NF \l_tmpa_bool { \int_set:Nn \l_@@_last_empty_row_int { ##1 } } } } % \end{macrocode} % Now, you determine the last empty cell in the row of number~$1$. % \begin{macrocode} \bool_set_false:N \l_tmpa_bool \int_zero_new:N \l_@@_last_empty_column_int \int_set:Nn \l_@@_last_empty_column_int { #2 } \int_step_inline:nnnn { #2 } { #4 } { #6 } { \@@_test_if_cell_in_a_block:nn { \int_eval:n { #1 } } { ##1 } \bool_lazy_or:nnTF \l_tmpb_bool { \cs_if_exist_p:c { pgf @ sh @ ns @ \@@_env: - \int_eval:n { #1 } - ##1 } } { \bool_set_true:N \l_tmpa_bool } { \bool_if:NF \l_tmpa_bool { \int_set:Nn \l_@@_last_empty_column_int { ##1 } } } } % \end{macrocode} % Now, we loop over the rows. % \begin{macrocode} \int_step_inline:nnnn { #1 } { #3 } \l_@@_last_empty_row_int { % \end{macrocode} % We treat the row number |##1| with another loop. % \begin{macrocode} \bool_set_false:N \l_tmpa_bool \int_step_inline:nnnn { #2 } { #4 } \l_@@_last_empty_column_int { \@@_test_if_cell_in_a_block:nn { ##1 } { ####1 } \bool_lazy_or:nnTF \l_tmpb_bool { \cs_if_exist_p:c { pgf @ sh @ ns @ \@@_env: - ##1 - ####1 } } { \bool_set_true:N \l_tmpa_bool } { \bool_if:NF \l_tmpa_bool { \int_set:Nn \l_@@_last_empty_column_int { ####1 } \seq_put_right:Nn \l_@@_corners_cells_seq { ##1 - ####1 } } } } } } % \end{macrocode} % % \bigskip % The following macro tests whether a cell is in (at least) one of % the blocks of the array (or in a cell with a |\diagbox|). % % The flag |\l_tmpb_bool| will be raised if the cell |#1|-|#2| is in a block (or % in a cell with a |\diagbox|). % \begin{macrocode} \cs_new_protected:Npn \@@_test_if_cell_in_a_block:nn #1 #2 { \int_set:Nn \l_tmpa_int { #1 } \int_set:Nn \l_tmpb_int { #2 } \bool_set_false:N \l_tmpb_bool \seq_map_inline:Nn \g_@@_pos_of_blocks_seq { \@@_test_if_cell_in_block:nnnnnnn \l_tmpa_int \l_tmpb_int ##1 } } % \end{macrocode} % % % \begin{macrocode} \cs_set_protected:Npn \@@_test_if_cell_in_block:nnnnnnn #1 #2 #3 #4 #5 #6 #7 { \int_compare:nNnF { #3 } > { #1 } { \int_compare:nNnF { #1 } > { #5 } { \int_compare:nNnF { #4 } > { #2 } { \int_compare:nNnF { #2 } > { #6 } { \bool_set_true:N \l_tmpb_bool } } } } } % \end{macrocode} % % % \bigskip % \section{The environment \{NiceMatrixBlock\}} % % The following flag will be raised when all the columns of the environments of % the block must have the same width in ``auto'' mode. % \begin{macrocode} \bool_new:N \l_@@_block_auto_columns_width_bool % \end{macrocode} % % \bigskip % Up to now, there is only one option available for the environment % |{NiceMatrixBlock}|. % \begin{macrocode} \keys_define:nn { NiceMatrix / NiceMatrixBlock } { auto-columns-width .code:n = { \bool_set_true:N \l_@@_block_auto_columns_width_bool \dim_gzero_new:N \g_@@_max_cell_width_dim \bool_set_true:N \l_@@_auto_columns_width_bool } } % \end{macrocode} % % \bigskip % \begin{macrocode} \NewDocumentEnvironment { NiceMatrixBlock } { ! O { } } { \int_gincr:N \g_@@_NiceMatrixBlock_int \dim_zero:N \l_@@_columns_width_dim \keys_set:nn { NiceMatrix / NiceMatrixBlock } { #1 } \bool_if:NT \l_@@_block_auto_columns_width_bool { \cs_if_exist:cT { @@_max_cell_width_ \int_use:N \g_@@_NiceMatrixBlock_int } { % is \exp_args:NNe mandatory? \exp_args:NNe \dim_set:Nn \l_@@_columns_width_dim { \use:c { @@_max_cell_width _ \int_use:N \g_@@_NiceMatrixBlock_int } } } } } % \end{macrocode} % % \medskip % At the end of the environment |{NiceMatrixBlock}|, we write in the main |aux| % file instructions for the column width of all the environments of the block % (that's why we have stored the number of the first environment of the block in % the counter |\l_@@_first_env_block_int|). % \begin{macrocode} { \legacy_if:nTF { measuring@ } % \end{macrocode} % If |{NiceMatrixBlock}| is used in an environment of \pkg{amsmath} such as % |{align}|: cf. question 694957 on TeX StackExchange. The most important line % in that case is the following one. % \begin{macrocode} { \int_gdecr:N \g_@@_NiceMatrixBlock_int } { \bool_if:NT \l_@@_block_auto_columns_width_bool { \iow_shipout:Nn \@mainaux \ExplSyntaxOn \iow_shipout:Nx \@mainaux { \cs_gset:cpn { @@ _ max _ cell _ width _ \int_use:N \g_@@_NiceMatrixBlock_int } % \end{macrocode} % For technical reasons, we have to include the width of a potential rule on the % right side of the cells. % \begin{macrocode} { \dim_eval:n { \g_@@_max_cell_width_dim + \arrayrulewidth } } } \iow_shipout:Nn \@mainaux \ExplSyntaxOff } } \ignorespacesafterend } % \end{macrocode} % % % % \section{The extra nodes} % % First, two variants of the functions |\dim_min:nn| and |\dim_max:nn|. % \begin{macrocode} \cs_generate_variant:Nn \dim_min:nn { v n } \cs_generate_variant:Nn \dim_max:nn { v n } % \end{macrocode} % % % \bigskip % The following command is called in |\@@_use_arraybox_with_notes_c:| just % before the construction of the blocks (if the creation of medium nodes is % required, medium nodes are also created for the blocks and that construction % uses the standard medium nodes). % \begin{macrocode} \cs_new_protected:Npn \@@_create_extra_nodes: { \bool_if:nTF \l_@@_medium_nodes_bool { \bool_if:NTF \l_@@_large_nodes_bool \@@_create_medium_and_large_nodes: \@@_create_medium_nodes: } { \bool_if:NT \l_@@_large_nodes_bool \@@_create_large_nodes: } } % \end{macrocode} % % % \bigskip % We have three macros of creation of nodes: |\@@_create_medium_nodes:|, % |\@@_create_large_nodes:| and |\@@_create_medium_and_large_nodes:|. % % % \bigskip % We have to compute the mathematical coordinates of the ``medium nodes''. These % mathematical coordinates are also used to compute the mathematical coordinates % of the ``large nodes''. That's why we write a command % |\@@_computations_for_medium_nodes:| to do these computations. % % \bigskip % The command |\@@_computations_for_medium_nodes:| must be used in a % |{pgfpicture}|. % % \medskip % For each row $i$, we compute two dimensions % \texttt{l_@@_row_\textsl{i}_min_dim} and \texttt{l_@@_row_\textsl{i}_max_dim}. % The dimension \texttt{l_@@_row_\textsl{i}_min_dim} is the minimal % $y$-value of all the cells of the row~$i$. The dimension % \texttt{l_@@_row_\textsl{i}_max_dim} is the maximal $y$-value of all the cells % of the row~$i$. % % Similarly, for each column $j$, we compute two dimensions % \texttt{l_@@_column_\textsl{j}_min_dim} and % \texttt{l_@@_column_\textsl{j}_max_dim}. The dimension % \texttt{l_@@_column_\textsl{j}_min_dim} is the minimal $x$-value of all the % cells of the column~$j$. The dimension \texttt{l_@@_column_\textsl{j}_max_dim} % is the maximal $x$-value of all the cells of the column~$j$. % % Since these dimensions will be computed as maximum or minimum, we initialize % them to |\c_max_dim| or |-\c_max_dim|. % \begin{macrocode} \cs_new_protected:Npn \@@_computations_for_medium_nodes: { \int_step_variable:nnNn \l_@@_first_row_int \g_@@_row_total_int \@@_i: { \dim_zero_new:c { l_@@_row_\@@_i: _min_dim } \dim_set_eq:cN { l_@@_row_\@@_i: _min_dim } \c_max_dim \dim_zero_new:c { l_@@_row_\@@_i: _max_dim } \dim_set:cn { l_@@_row_\@@_i: _max_dim } { - \c_max_dim } } \int_step_variable:nnNn \l_@@_first_col_int \g_@@_col_total_int \@@_j: { \dim_zero_new:c { l_@@_column_\@@_j: _min_dim } \dim_set_eq:cN { l_@@_column_\@@_j: _min_dim } \c_max_dim \dim_zero_new:c { l_@@_column_\@@_j: _max_dim } \dim_set:cn { l_@@_column_\@@_j: _max_dim } { - \c_max_dim } } % \end{macrocode} % We begin the two nested loops over the rows and the columns of the array. % \begin{macrocode} \int_step_variable:nnNn \l_@@_first_row_int \g_@@_row_total_int \@@_i: { \int_step_variable:nnNn \l_@@_first_col_int \g_@@_col_total_int \@@_j: % \end{macrocode} % If the cell ($i$-$j$) is empty or an implicit cell (that is to say a cell % after implicit ampersands |&|) we don't update the dimensions we want to % compute. % \begin{macrocode} { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - \@@_i: - \@@_j: } % \end{macrocode} % We retrieve the coordinates of the anchor |south west| of the (normal) node of % the cell ($i$-$j$). They will be stored in |\pgf@x| and |\pgf@y|. % \begin{macrocode} { \pgfpointanchor { \@@_env: - \@@_i: - \@@_j: } { south~west } \dim_set:cn { l_@@_row_\@@_i: _min_dim} { \dim_min:vn { l_@@_row _ \@@_i: _min_dim } \pgf@y } \seq_if_in:NxF \g_@@_multicolumn_cells_seq { \@@_i: - \@@_j: } { \dim_set:cn { l_@@_column _ \@@_j: _min_dim} { \dim_min:vn { l_@@_column _ \@@_j: _min_dim } \pgf@x } } % \end{macrocode} % We retrieve the coordinates of the anchor |north east| of the (normal) node of % the cell ($i$-$j$). They will be stored in |\pgf@x| and |\pgf@y|. % \begin{macrocode} \pgfpointanchor { \@@_env: - \@@_i: - \@@_j: } { north~east } \dim_set:cn { l_@@_row _ \@@_i: _ max_dim } { \dim_max:vn { l_@@_row _ \@@_i: _ max_dim } \pgf@y } \seq_if_in:NxF \g_@@_multicolumn_cells_seq { \@@_i: - \@@_j: } { \dim_set:cn { l_@@_column _ \@@_j: _ max_dim } { \dim_max:vn { l_@@_column _ \@@_j: _max_dim } \pgf@x } } } } } % \end{macrocode} % Now, we have to deal with empty rows or empty columns since we don't have % created nodes in such rows and columns. % \begin{macrocode} \int_step_variable:nnNn \l_@@_first_row_int \g_@@_row_total_int \@@_i: { \dim_compare:nNnT { \dim_use:c { l_@@_row _ \@@_i: _ min _ dim } } = \c_max_dim { \@@_qpoint:n { row - \@@_i: - base } \dim_set:cn { l_@@_row _ \@@_i: _ max _ dim } \pgf@y \dim_set:cn { l_@@_row _ \@@_i: _ min _ dim } \pgf@y } } \int_step_variable:nnNn \l_@@_first_col_int \g_@@_col_total_int \@@_j: { \dim_compare:nNnT { \dim_use:c { l_@@_column _ \@@_j: _ min _ dim } } = \c_max_dim { \@@_qpoint:n { col - \@@_j: } \dim_set:cn { l_@@_column _ \@@_j: _ max _ dim } \pgf@y \dim_set:cn { l_@@_column _ \@@_j: _ min _ dim } \pgf@y } } } % \end{macrocode} % % % \bigskip % Here is the command |\@@_create_medium_nodes:|. When this command is used, the % ``medium nodes'' are created. % % \begin{macrocode} \cs_new_protected:Npn \@@_create_medium_nodes: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_computations_for_medium_nodes: % \end{macrocode} % Now, we can create the ``medium nodes''. We use a command |\@@_create_nodes:| % because this command will also be used for the creation of the ``large nodes''. % \begin{macrocode} \cs_set_nopar:Npn \l_@@_suffix_tl { -medium } \@@_create_nodes: \endpgfpicture } % \end{macrocode} % % % \medskip % The command |\@@_create_large_nodes:| must be used when we want to create only % the ``large nodes'' and not the medium ones\footnote{If we want to create % both, we have to use |\@@_create_medium_and_large_nodes:|}. However, the % computation of the mathematical coordinates of the ``large nodes'' needs the % computation of the mathematical coordinates of the ``medium nodes''. Hence, we % use first |\@@_computations_for_medium_nodes:| and then the command % |\@@_computations_for_large_nodes:|. % \begin{macrocode} \cs_new_protected:Npn \@@_create_large_nodes: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_computations_for_medium_nodes: \@@_computations_for_large_nodes: \cs_set_nopar:Npn \l_@@_suffix_tl { - large } \@@_create_nodes: \endpgfpicture } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_create_medium_and_large_nodes: { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_computations_for_medium_nodes: % \end{macrocode} % Now, we can create the ``medium nodes''. We use a command |\@@_create_nodes:| % because this command will also be used for the creation of the ``large nodes''. % \begin{macrocode} \cs_set_nopar:Npn \l_@@_suffix_tl { - medium } \@@_create_nodes: \@@_computations_for_large_nodes: \cs_set_nopar:Npn \l_@@_suffix_tl { - large } \@@_create_nodes: \endpgfpicture } % \end{macrocode} % % % \bigskip % For ``large nodes'', the exterior rows and columns don't interfer. That's why % the loop over the columns will start at 1 and stop at $|\c@jCol|$ (and not % |\g_@@_col_total_int|). Idem for the rows. % \begin{macrocode} \cs_new_protected:Npn \@@_computations_for_large_nodes: { \int_set_eq:NN \l_@@_first_row_int \c_one_int \int_set_eq:NN \l_@@_first_col_int \c_one_int % \end{macrocode} % We have to change the values of all the dimensions % \texttt{l_@@_row_\textsl{i}_min_dim}, \texttt{l_@@_row_\textsl{i}_max_dim}, % \texttt{l_@@_column_\textsl{j}_min_dim} and % \texttt{l_@@_column_\textsl{j}_max_dim}. % \begin{macrocode} \int_step_variable:nNn { \c@iRow - 1 } \@@_i: { \dim_set:cn { l_@@_row _ \@@_i: _ min _ dim } { ( \dim_use:c { l_@@_row _ \@@_i: _ min _ dim } + \dim_use:c { l_@@_row _ \int_eval:n { \@@_i: + 1 } _ max _ dim } ) / 2 } \dim_set_eq:cc { l_@@_row _ \int_eval:n { \@@_i: + 1 } _ max _ dim } { l_@@_row_\@@_i: _min_dim } } \int_step_variable:nNn { \c@jCol - 1 } \@@_j: { \dim_set:cn { l_@@_column _ \@@_j: _ max _ dim } { ( \dim_use:c { l_@@_column _ \@@_j: _ max _ dim } + \dim_use:c { l_@@_column _ \int_eval:n { \@@_j: + 1 } _ min _ dim } ) / 2 } \dim_set_eq:cc { l_@@_column _ \int_eval:n { \@@_j: + 1 } _ min _ dim } { l_@@_column _ \@@_j: _ max _ dim } } % \end{macrocode} % Here, we have to use |\dim_sub:cn| because of the number 1 in the name. % \begin{macrocode} \dim_sub:cn { l_@@_column _ 1 _ min _ dim } \l_@@_left_margin_dim \dim_add:cn { l_@@_column _ \int_use:N \c@jCol _ max _ dim } \l_@@_right_margin_dim } % \end{macrocode} % % % % \bigskip % The command |\@@_create_nodes:| is used twice: for the construction % of the ``medium nodes'' and for the construction of the ``large nodes''. The % nodes are constructed with the value of all the dimensions % \texttt{l_@@_row_\textsl{i}_min_dim}, \texttt{l_@@_row_\textsl{i}_max_dim}, % \texttt{l_@@_column_\textsl{j}_min_dim} and % \texttt{l_@@_column_\textsl{j}_max_dim}. Between the construction of the % ``medium nodes'' and the ``large nodes'', the values of these dimensions are % changed. % % The function also uses |\l_@@_suffix_tl| (|-medium| or |-large|). % \begin{macrocode} \cs_new_protected:Npn \@@_create_nodes: { \int_step_variable:nnNn \l_@@_first_row_int \g_@@_row_total_int \@@_i: { \int_step_variable:nnNn \l_@@_first_col_int \g_@@_col_total_int \@@_j: { % \end{macrocode} % We draw the rectangular node for the cell (|\@@_i|-|\@@_j|). % \begin{macrocode} \@@_pgf_rect_node:nnnnn { \@@_env: - \@@_i: - \@@_j: \l_@@_suffix_tl } { \dim_use:c { l_@@_column_ \@@_j: _min_dim } } { \dim_use:c { l_@@_row_ \@@_i: _min_dim } } { \dim_use:c { l_@@_column_ \@@_j: _max_dim } } { \dim_use:c { l_@@_row_ \@@_i: _max_dim } } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - \@@_i: - \@@_j: \l_@@_suffix_tl } { \@@_env: - \@@_i: - \@@_j: \l_@@_suffix_tl } } } } % \end{macrocode} % Now, we create the nodes for the cells of the |\multicolumn|. We recall that % we have stored in |\g_@@_multicolumn_cells_seq| the list of the cells where a % |\multicolumn{|$n$|}{...}{...}| with $n$>1 was issued and in % |\g_@@_multicolumn_sizes_seq| the correspondant values of $n$. % \begin{macrocode} \seq_map_pairwise_function:NNN \g_@@_multicolumn_cells_seq \g_@@_multicolumn_sizes_seq \@@_node_for_multicolumn:nn } % \end{macrocode} % % % \bigskip % \begin{macrocode} \cs_new_protected:Npn \@@_extract_coords_values: #1 - #2 \q_stop { \cs_set_nopar:Npn \@@_i: { #1 } \cs_set_nopar:Npn \@@_j: { #2 } } % \end{macrocode} % % The command |\@@_node_for_multicolumn:nn| takes two arguments. The first is % the position of the cell where the command |\multicolumn{|$n$|}{...}{...}| was % issued in the format $i$|-|$j$ and the second is the value of~$n$ (the length % of the ``multi-cell''). % \begin{macrocode} \cs_new_protected:Npn \@@_node_for_multicolumn:nn #1 #2 { \@@_extract_coords_values: #1 \q_stop \@@_pgf_rect_node:nnnnn { \@@_env: - \@@_i: - \@@_j: \l_@@_suffix_tl } { \dim_use:c { l_@@_column _ \@@_j: _ min _ dim } } { \dim_use:c { l_@@_row _ \@@_i: _ min _ dim } } { \dim_use:c { l_@@_column _ \int_eval:n { \@@_j: +#2-1 } _ max _ dim } } { \dim_use:c { l_@@_row _ \@@_i: _ max _ dim } } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - \@@_i: - \@@_j: \l_@@_suffix_tl } { \int_use:N \g_@@_env_int - \@@_i: - \@@_j: \l_@@_suffix_tl} } } % \end{macrocode} % % \bigskip % \section{The blocks} % % The code deals with the command |\Block|. This command has no direct link with % the environment |{NiceMatrixBlock}|. % % \bigskip % The options of the command |\Block| will be analyzed first in the cell of the % array (and once again when the block will be put in the array). % Here is the set of keys for the first pass. % \begin{macrocode} \keys_define:nn { NiceMatrix / Block / FirstPass } { l .code:n = \str_set:Nn \l_@@_hpos_block_str l , l .value_forbidden:n = true , r .code:n = \str_set:Nn \l_@@_hpos_block_str r , r .value_forbidden:n = true , c .code:n = \str_set:Nn \l_@@_hpos_block_str c , c .value_forbidden:n = true , L .code:n = \str_set:Nn \l_@@_hpos_block_str l , L .value_forbidden:n = true , R .code:n = \str_set:Nn \l_@@_hpos_block_str r , R .value_forbidden:n = true , C .code:n = \str_set:Nn \l_@@_hpos_block_str c , C .value_forbidden:n = true , t .code:n = \str_set:Nn \l_@@_vpos_block_str t , t .value_forbidden:n = true , T .code:n = \str_set:Nn \l_@@_vpos_block_str T , T .value_forbidden:n = true , b .code:n = \str_set:Nn \l_@@_vpos_block_str b , b .value_forbidden:n = true , B .code:n = \str_set:Nn \l_@@_vpos_block_str B , B .value_forbidden:n = true , color .code:n = \@@_color:n { #1 } \tl_set_rescan:Nnn \l_@@_draw_tl { \char_set_catcode_other:N ! } { #1 } , color .value_required:n = true , respect-arraystretch .code:n = \cs_set_eq:NN \@@_reset_arraystretch: \prg_do_nothing: , respect-arraystretch .value_forbidden:n = true , } % \end{macrocode} % % % The following command |\@@_Block:| will be linked to |\Block| in the % environments of \pkg{nicematrix}. We define it with % |\NewExpandableDocumentCommand| because it has an optional argument between % |<| and |>|. It's mandatory to use an expandable command. % % \begin{macrocode} \cs_new_protected:Npn \@@_Block: { \@@_collect_options:n { \@@_Block_i: } } % \end{macrocode} % % \bigskip % \begin{macrocode} \NewExpandableDocumentCommand \@@_Block_i: { m m D < > { } +m } { % \end{macrocode} % If the first mandatory argument of the command (which is the size of the block % with the syntax $i$|-|$j$) has not been provided by the user, you use |1-1| % (that is to say a block of only one cell). % \begin{macrocode} \peek_remove_spaces:n { \tl_if_blank:nTF { #2 } { \@@_Block_ii:nnnnn \c_one_int \c_one_int } { \int_compare:nNnTF { \char_value_catcode:n { 45 } } = { 13 } \@@_Block_i_czech \@@_Block_i #2 \q_stop } { #1 } { #3 } { #4 } } } % \end{macrocode} % % \medskip % With the following construction, we extract the values of $i$ and $j$ in the % first mandatory argument of the command. % \begin{macrocode} \cs_new:Npn \@@_Block_i #1-#2 \q_stop { \@@_Block_ii:nnnnn { #1 } { #2 } } % \end{macrocode} % % With \pkg{babel} with the key |czech|, the character |-| (hyphen) is active. % That's why we need a special version. Remark that we could not use a % preprocessor in the command |\@@_Block:| to do the job because the command % |\@@_Block:| is defined with the command |\NewExpandableDocumentCommand|. % \begin{macrocode} { \char_set_catcode_active:N - \cs_new:Npn \@@_Block_i_czech #1-#2 \q_stop { \@@_Block_ii:nnnnn { #1 } { #2 } } } % \end{macrocode} % % \medskip % Now, the arguments have been extracted: % |#1| is $i$ (the number of rows of the block), |#2| is $j$ (the number of % columns of the block), |#3| is the list of \textsl{key=values} pairs, |#4| are % the tokens to put before the math mode and before the composition of the block % and |#5| is the label (=content) of the block. % \begin{macrocode} \cs_new_protected:Npn \@@_Block_ii:nnnnn #1 #2 #3 #4 #5 { % \end{macrocode} % % \medskip % We recall that |#1| and |#2| have been extracted from the first mandatory % argument of |\Block| (which is of the syntax $i$|-|$j$). However, the user is % allowed to omit $i$ or $j$ (or both). We detect that situation by replacing a % missing value by 100 (it's a convention: when the block will actually be drawn % these values will be detected and interpreted as \emph{maximal possible % value} according to the actual size of the array). % \begin{macrocode} \bool_lazy_or:nnTF { \tl_if_blank_p:n { #1 } } { \str_if_eq_p:nn { #1 } { * } } { \int_set:Nn \l_tmpa_int { 100 } } { \int_set:Nn \l_tmpa_int { #1 } } \bool_lazy_or:nnTF { \tl_if_blank_p:n { #2 } } { \str_if_eq_p:nn { #2 } { * } } { \int_set:Nn \l_tmpb_int { 100 } } { \int_set:Nn \l_tmpb_int { #2 } } % \end{macrocode} % % \medskip % If the block is mono-column. % \begin{macrocode} \int_compare:nNnTF \l_tmpb_int = \c_one_int { \tl_if_empty:NTF \l_@@_hpos_cell_tl { \str_set_eq:NN \l_@@_hpos_block_str \c_@@_c_str } { \str_set:NV \l_@@_hpos_block_str \l_@@_hpos_cell_tl } } { \str_set_eq:NN \l_@@_hpos_block_str \c_@@_c_str } % \end{macrocode} % The value of |\l_@@_hpos_block_str| may be modified by the keys of the % command |\Block| that we will analyze now. % % \medskip % \begin{macrocode} \keys_set_known:nn { NiceMatrix / Block / FirstPass } { #3 } % \end{macrocode} % % \begin{macrocode} \tl_set:Nx \l_tmpa_tl { { \int_use:N \c@iRow } { \int_use:N \c@jCol } { \int_eval:n { \c@iRow + \l_tmpa_int - 1 } } { \int_eval:n { \c@jCol + \l_tmpb_int - 1 } } } % \end{macrocode} % Now, |\l_tmpa_tl| contains an ``object'' corresponding to the position of the % block with four components, each of them surrounded by curly brackets: % % |{|\textsl{imin}|}{|\textsl{jmin}|}{|\textsl{imax}|}{|\textsl{jmax}|}|. % % % \medskip % If the block is mono-column or mono-row, we have a special treatment. That's % why we have two macros: |\@@_Block_iv:nnnnn| and |\@@_Block_v:nnnnn| (the five % arguments of those macros are provided by curryfication). % \begin{macrocode} \bool_if:nTF { ( \int_compare_p:nNn \l_tmpa_int = \c_one_int || \int_compare_p:nNn \l_tmpb_int = \c_one_int ) && ! \tl_if_empty_p:n { #5 } % \end{macrocode} % For the blocks mono-column, we will compose right now in a box in order to % compute its width and take that width into account for the width of the % column. However, if the column is a |X| column, we should not do that since % the width is determined by another way. This should be the same for the |p|, % |m| and |b| columns and we should modify that point. However, for the |X| % column, it's imperative. Otherwise, the process for the determination of the % widths of the columns will be wrong. % \begin{macrocode} && ! \l_@@_X_bool } { \exp_args:Nee \@@_Block_iv:nnnnn } { \exp_args:Nee \@@_Block_v:nnnnn } { \l_tmpa_int } { \l_tmpb_int } { #3 } { #4 } { #5 } } % \end{macrocode} % % % \bigskip % The following macro is for the case of a |\Block| which is mono-row or % mono-column (or both). In that case, the content of the block is composed % right now in a box (because we have to take into account the dimensions of % that box for the width of the current column or the height and the depth of the % current row). However, that box will be put in the array \emph{after the % construction of the array} (by using \textsc{pgf}) with |\@@_draw_blocks:| and % above all |\@@_Block_v:nnnnnn| which will do the main job. % % |#1| is $i$ (the number of rows of the block), |#2| is $j$ (the number of % columns of the block), |#3| is the list of \textsl{key=values} pairs, |#4| are % the tokens to put before the potential math mode and before the composition of % the block and |#5| is the label (=content) of the block. % \begin{macrocode} \cs_new_protected:Npn \@@_Block_iv:nnnnn #1 #2 #3 #4 #5 { \int_gincr:N \g_@@_block_box_int \cs_set_protected_nopar:Npn \diagbox ##1 ##2 { \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_actually_diagbox:nnnnnn { \int_use:N \c@iRow } { \int_use:N \c@jCol } { \int_eval:n { \c@iRow + #1 - 1 } } { \int_eval:n { \c@jCol + #2 - 1 } } { \g_@@_row_style_tl \exp_not:n { ##1 } } { \g_@@_row_style_tl \exp_not:n { ##2 } } } } \box_gclear_new:c { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } % \end{macrocode} % Now, we will actually compose the content of the |\Block| in a TeX box. % \emph{Be careful}: if after the construction of the box, the boolean % |\g_@@_rotate_bool| is raised (which means that the command |\rotate| was % present in the content of the |\Block|) we will rotate the box but also, % maybe, change the position of the baseline! % \begin{macrocode} \hbox_gset:cn { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } { % \end{macrocode} % For a mono-column block, if the user has specified a color for the column in % the preamble of the array, we want to fix that color in the box we construct. % We do that with |\set@color| and not |\color_ensure_current:| (in order to use % |\color_ensure_current:| safely, you should load \pkg{l3backend} before the % |\documentclass| with |\RequirePackage{expl3}|). % \begin{macrocode} \tl_if_empty:NTF \l_@@_color_tl { \int_compare:nNnT { #2 } = \c_one_int \set@color } { \@@_color:o \l_@@_color_tl } % \end{macrocode} % If the block is mono-row, we use |\g_@@_row_style_tl| even if it has yet been % used in the beginning of the cell where the command |\Block| has been issued % because we want to be able to take into account a potential instruction of % color of the font in |\g_@@_row_style_tl|. % \begin{macrocode} \int_compare:nNnT { #1 } = \c_one_int { \int_if_zero:nTF \c@iRow \l_@@_code_for_first_row_tl { \int_compare:nNnT \c@iRow = \l_@@_last_row_int \l_@@_code_for_last_row_tl } \g_@@_row_style_tl } % \end{macrocode} % The following command will be no-op when |respect-arraystretch| is in force. % \begin{macrocode} \@@_reset_arraystretch: \dim_zero:N \extrarowheight % \end{macrocode} % |#4| is the optional argument of the command |\Block|, provided with the % syntax |<...>|. % \begin{macrocode} #4 % \end{macrocode} % We adjust |\l_@@_hpos_block_str| when |\rotate| has been used (in the cell % where the command |\Block| is used but maybe in |#4|, |\RowStyle|, % |code-for-first-row|, etc.). % \begin{macrocode} \@@_adjust_hpos_rotate: % \end{macrocode} % The boolean |\g_@@_rotate_bool| will be also considered \emph{after the composition % of the box} (in order to rotate the box). % % \medskip % Remind that we are in the command of composition of the box of the block. % Previously, we have only done some tuning. Now, we will actually compose the % content with a |{tabular}|, an |{array}| or a |{minipage}|. % \begin{macrocode} \bool_if:NTF \l_@@_tabular_bool { \bool_lazy_all:nTF { { \int_compare_p:nNn { #2 } = \c_one_int } % \end{macrocode} % Remind that, when the column has not a fixed width, the dimension % |\l_@@_col_width_dim| has the conventional value of $-1$~cm. % \begin{macrocode} { ! \dim_compare_p:nNn \l_@@_col_width_dim < \c_zero_dim } { ! \g_@@_rotate_bool } } % \end{macrocode} % When the block is mono-column in a column with a fixed width (eg |p{3cm}|), we % use a |{minipage}|. % \begin{macrocode} { \use:e { \exp_not:N \begin { minipage }% [ \str_lowercase:V \l_@@_vpos_block_str ] { \l_@@_col_width_dim } \str_case:on \l_@@_hpos_block_str { c \centering r \raggedleft l \raggedright } } #5 \end { minipage } } % \end{macrocode} % In the other cases, we use a |{tabular}|. % \begin{macrocode} { \use:e { \exp_not:N \begin { tabular }% [ \str_lowercase:V \l_@@_vpos_block_str ] { @ { } \l_@@_hpos_block_str @ { } } } #5 \end { tabular } } } % \end{macrocode} % If we are in a mathematical array (|\l_@@_tabular_bool| is |false|). The % composition is always done with an |{array}| (never with a |{minipage}|). % \begin{macrocode} { \c_math_toggle_token \use:e { \exp_not:N \begin { array }% [ \str_lowercase:V \l_@@_vpos_block_str ] { @ { } \l_@@_hpos_block_str @ { } } } #5 \end { array } \c_math_toggle_token } } % \end{macrocode} % The box which will contain the content of the block has now been composed. % % \bigskip % If there were |\rotate| (which raises |\g_@@_rotate_bool|) in the content of % the |\Block|, we do a rotation of the box (and we also adjust the % baseline the rotated box). % \begin{macrocode} \bool_if:NT \g_@@_rotate_bool \@@_rotate_box_of_block: % \end{macrocode} % % If we are in a mono-column block, we take into account the width of that block % for the width of the column. % \begin{macrocode} \int_compare:nNnT { #2 } = \c_one_int { \dim_gset:Nn \g_@@_blocks_wd_dim { \dim_max:nn \g_@@_blocks_wd_dim { \box_wd:c { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } } } } % \end{macrocode} % If we are in a mono-row block and if that block has no vertical option for the % position\footnote{If the block has a key of a vertical position, that means % that it has to be put in a vertical space determined by the \emph{others} % cells of the row. Therefore there is no point creating space here. Moreover, % that would lead to problems when a multi-row block with a position key such as % |b| or |B|.}, we take into account the height and the depth of that block for the % height and the depth of the row. % \begin{macrocode} \str_if_eq:VnT \l_@@_vpos_block_str { c } { \int_compare:nNnT { #1 } = \c_one_int { \dim_gset:Nn \g_@@_blocks_ht_dim { \dim_max:nn \g_@@_blocks_ht_dim { \box_ht:c { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } } } \dim_gset:Nn \g_@@_blocks_dp_dim { \dim_max:nn \g_@@_blocks_dp_dim { \box_dp:c { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } } } } } \seq_gput_right:Nx \g_@@_blocks_seq { \l_tmpa_tl % \end{macrocode} % In the list of options |#3|, maybe there is a key for the horizontal alignment % (|l|, |r| or |c|). In that case, that key has been read and stored in % |\l_@@_hpos_block_str|. However, maybe there were no key of the horizontal % alignment and that's why we put a key corresponding to the value of % |\l_@@_hpos_block_str|, which is fixed by the type of current column. % \begin{macrocode} { \exp_not:n { #3 } , \l_@@_hpos_block_str , % \end{macrocode} % Now, we put a key for the vertical alignment. % \begin{macrocode} \bool_if:NT \g_@@_rotate_bool { \bool_if:NTF \g_@@_rotate_c_bool { v-center } { \int_compare:nNnT \c@iRow = \l_@@_last_row_int T } } } { \box_use_drop:c { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } } } \bool_set_false:N \g_@@_rotate_c_bool } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new:Npn \@@_adjust_hpos_rotate: { \bool_if:NT \g_@@_rotate_bool { \str_set:Nx \l_@@_hpos_block_str { \bool_if:NTF \g_@@_rotate_c_bool { c } { \str_case:onF \l_@@_vpos_block_str { b l B l t r T r } { \int_compare:nNnTF \c@iRow = \l_@@_last_row_int r l } } } } } % \end{macrocode} % % \bigskip % Despite its name the following command rotates the box of the block \emph{but % also does vertical adjustement of the baseline of the block}. % \begin{macrocode} \cs_new_protected:Npn \@@_rotate_box_of_block: { \box_grotate:cn { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } { 90 } \int_compare:nNnT \c@iRow = \l_@@_last_row_int { \vbox_gset_top:cn { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } { \skip_vertical:n { 0.8 ex } \box_use:c { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } } } \bool_if:NT \g_@@_rotate_c_bool { \hbox_gset:cn { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } { \c_math_toggle_token \vcenter { \box_use:c { g_@@_ block _ box _ \int_use:N \g_@@_block_box_int _ box } } \c_math_toggle_token } } } % \end{macrocode} % % \bigskip % The following macro is for the standard case, where the block is not mono-row % and not mono-column. In that case, the content of the block is \emph{not} % composed right now in a box. The composition in a box will be done further, % just after the construction of the array (cf. |\@@_draw_blocks:| and % above all |\@@_Block_v:nnnnnn|). % % |#1| is $i$ (the number of rows of the block), |#2| is $j$ (the number of % columns of the block), |#3| is the list of \textsl{key=values} pairs, |#4| are % the tokens to put before the math mode and before the composition of the block % and |#5| is the label (=content) of the block. % \begin{macrocode} \cs_new_protected:Npn \@@_Block_v:nnnnn #1 #2 #3 #4 #5 { \seq_gput_right:Nx \g_@@_blocks_seq { \l_tmpa_tl { \exp_not:n { #3 } } { \bool_if:NTF \l_@@_tabular_bool { \group_begin: % \end{macrocode} % The following command will be no-op when |respect-arraystretch| is in force. % \begin{macrocode} \@@_reset_arraystretch: \exp_not:n { \dim_zero:N \extrarowheight #4 % \end{macrocode} % If the box is rotated (the key |\rotate| may be in the previous |#4|), the % tabular used for the content of the cell will be constructed with a format % |c|. In the other cases, the tabular will be constructed with a format equal % to the key of position of the box. In other words: the alignment internal to % the tabular is the same as the external alignment of the tabular (that is to % say the position of the block in its zone of merged cells). % \begin{macrocode} \use:e { \exp_not:N \begin { tabular } [ \l_@@_vpos_block_str ] { @ { } \l_@@_hpos_block_str @ { } } } #5 \end { tabular } } \group_end: } % \end{macrocode} % When we are \emph{not} in an environments |{NiceTabular}| (or similar). % \begin{macrocode} { \group_begin: % \end{macrocode} % The following will be no-op when |respect-arraystretch| is in force. % \begin{macrocode} \@@_reset_arraystretch: \exp_not:n { \dim_zero:N \extrarowheight #4 \c_math_toggle_token \use:e { \exp_not:N \begin { array } [ \l_@@_vpos_block_str ] { @ { } \l_@@_hpos_block_str @ { } } } #5 \end { array } \c_math_toggle_token } \group_end: } } } } % \end{macrocode} % % \bigskip % We recall that the options of the command |\Block| are analyzed twice: first % in the cell of the array and once again when the block will be put in the % array \emph{after the construction of the array} (by using \textsc{pgf}). % % \medskip % \begin{macrocode} \keys_define:nn { NiceMatrix / Block / SecondPass } { tikz .code:n = \IfPackageLoadedTF { tikz } { \seq_put_right:Nn \l_@@_tikz_seq { { #1 } } } { \@@_error:n { tikz~key~without~tikz } } , tikz .value_required:n = true , fill .code:n = \tl_set_rescan:Nnn \l_@@_fill_tl { \char_set_catcode_other:N ! } { #1 } , fill .value_required:n = true , opacity .tl_set:N = \l_@@_opacity_tl , opacity .value_required:n = true , draw .code:n = \tl_set_rescan:Nnn \l_@@_draw_tl { \char_set_catcode_other:N ! } { #1 } , draw .default:n = default , rounded-corners .dim_set:N = \l_@@_rounded_corners_dim , rounded-corners .default:n = 4 pt , color .code:n = \@@_color:n { #1 } \tl_set_rescan:Nnn \l_@@_draw_tl { \char_set_catcode_other:N ! } { #1 } , borders .clist_set:N = \l_@@_borders_clist , borders .value_required:n = true , hvlines .meta:n = { vlines , hlines } , vlines .bool_set:N = \l_@@_vlines_block_bool, vlines .default:n = true , hlines .bool_set:N = \l_@@_hlines_block_bool, hlines .default:n = true , line-width .dim_set:N = \l_@@_line_width_dim , line-width .value_required:n = true , % \end{macrocode} % Some keys have not a property |.value_required:n| (or similar) because they % are in |FirstPass|. % \begin{macrocode} l .code:n = \str_set:Nn \l_@@_hpos_block_str l , r .code:n = \str_set:Nn \l_@@_hpos_block_str r , c .code:n = \str_set:Nn \l_@@_hpos_block_str c , L .code:n = \str_set:Nn \l_@@_hpos_block_str l \bool_set_true:N \l_@@_hpos_of_block_cap_bool , R .code:n = \str_set:Nn \l_@@_hpos_block_str r \bool_set_true:N \l_@@_hpos_of_block_cap_bool , C .code:n = \str_set:Nn \l_@@_hpos_block_str c \bool_set_true:N \l_@@_hpos_of_block_cap_bool , t .code:n = \str_set:Nn \l_@@_vpos_block_str t , T .code:n = \str_set:Nn \l_@@_vpos_block_str T , b .code:n = \str_set:Nn \l_@@_vpos_block_str b , B .code:n = \str_set:Nn \l_@@_vpos_block_str B , v-center .code:n = \str_set:Nn \l_@@_vpos_block_str { c } , v-center .value_forbidden:n = true , name .tl_set:N = \l_@@_block_name_str , name .value_required:n = true , name .initial:n = , respect-arraystretch .code:n = \cs_set_eq:NN \@@_reset_arraystretch: \prg_do_nothing: , respect-arraystretch .value_forbidden:n = true , transparent .bool_set:N = \l_@@_transparent_bool , transparent .default:n = true , transparent .initial:n = false , unknown .code:n = \@@_error:n { Unknown~key~for~Block } } % \end{macrocode} % % \bigskip % The command |\@@_draw_blocks:| will draw all the blocks. This command is used % after the construction of the array. We have to revert to a clean version of % |\ialign| because there may be tabulars in the |\Block| instructions that will % be composed now. % \begin{macrocode} \cs_new_protected:Npn \@@_draw_blocks: { \cs_set_eq:NN \ialign \@@_old_ialign: \seq_map_inline:Nn \g_@@_blocks_seq { \@@_Block_iv:nnnnnn ##1 } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_Block_iv:nnnnnn #1 #2 #3 #4 #5 #6 { % \end{macrocode} % The integer |\l_@@_last_row_int| will be the last row of the block and % |\l_@@_last_col_int| its last column. % \begin{macrocode} \int_zero_new:N \l_@@_last_row_int \int_zero_new:N \l_@@_last_col_int % \end{macrocode} % % We remind that the first mandatory argument of the command |\Block| is the % size of the block with the special format $i$|-|$j$. However, the user is % allowed to omit $i$ or $j$ (or both). This will be interpreted as: the last % row (resp. column) of the block will be the last row (resp. column) of the % block (without the potential exterior row---resp. column---of the array). By % convention, this is stored in |\g_@@_blocks_seq| as a number of rows (resp. % columns) for the block equal to 100. That's what we detect now. % \begin{macrocode} \int_compare:nNnTF { #3 } > { 99 } { \int_set_eq:NN \l_@@_last_row_int \c@iRow } { \int_set:Nn \l_@@_last_row_int { #3 } } \int_compare:nNnTF { #4 } > { 99 } { \int_set_eq:NN \l_@@_last_col_int \c@jCol } { \int_set:Nn \l_@@_last_col_int { #4 } } \int_compare:nNnTF \l_@@_last_col_int > \g_@@_col_total_int { \bool_lazy_and:nnTF \l_@@_preamble_bool { \int_compare_p:n { \l_@@_last_col_int <= \g_@@_static_num_of_col_int } } { \msg_error:nnnn { nicematrix } { Block~too~large~2 } { #1 } { #2 } \@@_msg_redirect_name:nn { Block~too~large~2 } { none } \@@_msg_redirect_name:nn { columns~not~used } { none } } { \msg_error:nnnn { nicematrix } { Block~too~large~1 } { #1 } { #2 } } } { \int_compare:nNnTF \l_@@_last_row_int > \g_@@_row_total_int { \msg_error:nnnn { nicematrix } { Block~too~large~1 } { #1 } { #2 } } { \@@_Block_v:nnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { #6 } } } } % \end{macrocode} % % % \medskip % The following command |\@@_Block_v:nnnnnn| will actually draw the block. % |#1| is the first row of the block; % |#2| is the first column of the block; % |#3| is the last row of the block; % |#4| is the last column of the block; % |#5| is a list of \textsl{key=value} options; % |#6| is the label % \begin{macrocode} \cs_new_protected:Npn \@@_Block_v:nnnnnn #1 #2 #3 #4 #5 #6 { % \end{macrocode} % The group is for the keys. % \begin{macrocode} \group_begin: \int_compare:nNnT { #1 } = { #3 } { \str_set:Nn \l_@@_vpos_block_str { t } } \keys_set:nn { NiceMatrix / Block / SecondPass } { #5 } % \end{macrocode} % % \begin{macrocode} \bool_if:NT \l_@@_vlines_block_bool { \tl_gput_right:Nx \g_nicematrix_code_after_tl { \@@_vlines_block:nnn { \exp_not:n { #5 } } { #1 - #2 } { \int_use:N \l_@@_last_row_int - \int_use:N \l_@@_last_col_int } } } \bool_if:NT \l_@@_hlines_block_bool { \tl_gput_right:Nx \g_nicematrix_code_after_tl { \@@_hlines_block:nnn { \exp_not:n { #5 } } { #1 - #2 } { \int_use:N \l_@@_last_row_int - \int_use:N \l_@@_last_col_int } } } \bool_if:NF \l_@@_transparent_bool { \bool_lazy_and:nnF \l_@@_vlines_block_bool \l_@@_hlines_block_bool { % \end{macrocode} % The sequence of the positions of the blocks (excepted the blocks with the key % |hvlines|) will be used when drawing the rules (in fact, there is also the % |\multicolumn| and the |\diagbox| in that sequence). % \begin{macrocode} \seq_gput_left:Nx \g_@@_pos_of_blocks_seq { { #1 } { #2 } { #3 } { #4 } { \l_@@_block_name_str } } } } % \end{macrocode} % % \bigskip % \begin{macrocode} \tl_if_empty:NF \l_@@_draw_tl { \bool_lazy_or:nnT \l_@@_hlines_block_bool \l_@@_vlines_block_bool { \@@_error:n { hlines~with~color } } } % \end{macrocode} % \bigskip % \begin{macrocode} \tl_if_empty:NF \l_@@_draw_tl { \tl_gput_right:Nx \g_nicematrix_code_after_tl { \@@_stroke_block:nnn { \exp_not:n { #5 } } % #5 are the options { #1 - #2 } { \int_use:N \l_@@_last_row_int - \int_use:N \l_@@_last_col_int } } \seq_gput_right:Nn \g_@@_pos_of_stroken_blocks_seq { { #1 } { #2 } { #3 } { #4 } } } % \end{macrocode} % % \begin{macrocode} \clist_if_empty:NF \l_@@_borders_clist { \tl_gput_right:Nx \g_nicematrix_code_after_tl { \@@_stroke_borders_block:nnn { \exp_not:n { #5 } } { #1 - #2 } { \int_use:N \l_@@_last_row_int - \int_use:N \l_@@_last_col_int } } } % \end{macrocode} % % \begin{macrocode} \tl_if_empty:NF \l_@@_fill_tl { \tl_if_empty:NF \l_@@_opacity_tl { \tl_if_head_eq_meaning:nNTF \l_@@_fill_tl [ { \tl_set:Nx \l_@@_fill_tl { [ opacity = \l_@@_opacity_tl , \tl_tail:o \l_@@_fill_tl } } { \tl_set:Nx \l_@@_fill_tl { [ opacity = \l_@@_opacity_tl ] { \l_@@_fill_tl } } } } \tl_gput_right:Nx \g_@@_pre_code_before_tl { \exp_not:N \roundedrectanglecolor \exp_args:No \tl_if_head_eq_meaning:nNTF \l_@@_fill_tl [ { \l_@@_fill_tl } { { \l_@@_fill_tl } } { #1 - #2 } { \int_use:N \l_@@_last_row_int - \int_use:N \l_@@_last_col_int } { \dim_use:N \l_@@_rounded_corners_dim } } } % \end{macrocode} % % \begin{macrocode} \seq_if_empty:NF \l_@@_tikz_seq { \tl_gput_right:Nx \g_nicematrix_code_before_tl { \@@_block_tikz:nnnnn { #1 } { #2 } { \int_use:N \l_@@_last_row_int } { \int_use:N \l_@@_last_col_int } { \seq_use:Nn \l_@@_tikz_seq { , } } } } % \end{macrocode} % % \medskip % \begin{macrocode} \cs_set_protected_nopar:Npn \diagbox ##1 ##2 { \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_actually_diagbox:nnnnnn { #1 } { #2 } { \int_use:N \l_@@_last_row_int } { \int_use:N \l_@@_last_col_int } { \exp_not:n { ##1 } } { \exp_not:n { ##2 } } } } % \end{macrocode} % % \medskip % \begin{macrocode} \hbox_set:Nn \l_@@_cell_box { \set@color #6 } \bool_if:NT \g_@@_rotate_bool \@@_rotate_cell_box: % \end{macrocode} % % \bigskip % Let's consider the following |{NiceTabular}|. Because of the instruction % |!{\hspace{1cm}}| in the preamble which increases the space between the % columns (by adding, in fact, that space to the previous column, that is to say % the second column of the tabular), we will create \emph{two} nodes relative to % the block: the node |1-1-block| and the node |1-1-block-short|. % % \begin{Verbatim} % \begin{NiceTabular}{cc!{\hspace{1cm}}c} % \Block{2-2}{our block} & & one \\ % & & two \\ % three & four & five \\ % six & seven & eight \\ % \end{NiceTabular} % \end{Verbatim} % % \tikzset{highlight/.style={rectangle, % fill=red!15, % blend mode = multiply, % rounded corners = 0pt, % inner sep=0pt, % fit = #1}} % % \begin{tabular}{c@{\hspace{1cm}}c} % We highlight the node |1-1-block| % & % We highlight the node |1-1-block-short| \\[2mm] % \begin{NiceTabular}{cc!{\hspace{1cm}}c} % \Block{2-2}{our block} & & one \\ % & & two \\ % three & four & five \\ % six & seven & eight \\ % \CodeAfter % \tikz \node [highlight = (1-1-block)] { } ; % \end{NiceTabular} % & % \begin{NiceTabular}{cc!{\hspace{1cm}}c} % \Block{2-2}{our block} & & one \\ % & & two \\ % three & four & five \\ % six & seven & eight \\ % \CodeAfter % \tikz \node [highlight = (1-1-block-short)] { } ; % \end{NiceTabular} % \end{tabular} % % % \bigskip % The construction of the node corresponding to the merged cells. % \begin{macrocode} \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \@@_qpoint:n { row - #1 } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint:n { col - #2 } \dim_set_eq:NN \l_tmpb_dim \pgf@x \@@_qpoint:n { row - \int_eval:n { \l_@@_last_row_int + 1 } } \dim_set_eq:NN \l_@@_tmpc_dim \pgf@y \@@_qpoint:n { col - \int_eval:n { \l_@@_last_col_int + 1 } } \dim_set_eq:NN \l_@@_tmpd_dim \pgf@x % \end{macrocode} % % We construct the node for the block with the name |(#1-#2-block)|. % % The function |\@@_pgf_rect_node:nnnnn| takes in as arguments the name of the node % and the four coordinates of two opposite corner points of the rectangle. % \begin{macrocode} \@@_pgf_rect_node:nnnnn { \@@_env: - #1 - #2 - block } \l_tmpb_dim \l_tmpa_dim \l_@@_tmpd_dim \l_@@_tmpc_dim \str_if_empty:NF \l_@@_block_name_str { \pgfnodealias { \@@_env: - \l_@@_block_name_str } { \@@_env: - #1 - #2 - block } \str_if_empty:NF \l_@@_name_str { \pgfnodealias { \l_@@_name_str - \l_@@_block_name_str } { \@@_env: - #1 - #2 - block } } } % \end{macrocode} % % \medskip % Now, we create the ``short node'' which, in general, will be used to put the % label (that is to say the content of the node). However, if one the keys |L|, |C| or % |R| is used (that information is provided by the boolean % |\l_@@_hpos_of_block_cap_bool|), we don't need to create that node since the % normal node is used to put the label. % % \begin{macrocode} \bool_if:NF \l_@@_hpos_of_block_cap_bool { \dim_set_eq:NN \l_tmpb_dim \c_max_dim % \end{macrocode} % The short node is constructed by taking into account the \emph{contents} of % the columns involved in at least one cell of the block. That's why we have to % do a loop over the rows of the array. % \begin{macrocode} \int_step_inline:nnn \l_@@_first_row_int \g_@@_row_total_int { % \end{macrocode} % We recall that, when a cell is empty, no (normal) node is created in that % cell. That's why we test the existence of the node before using it. % \begin{macrocode} \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - ##1 - #2 } { \seq_if_in:NnF \g_@@_multicolumn_cells_seq { ##1 - #2 } { \pgfpointanchor { \@@_env: - ##1 - #2 } { west } \dim_set:Nn \l_tmpb_dim { \dim_min:nn \l_tmpb_dim \pgf@x } } } } % \end{macrocode} % If all the cells of the column were empty, |\l_tmpb_dim| has still the same % value |\c_max_dim|. In that case, you use for |\l_tmpb_dim| the value of the % position of the vertical rule. % \begin{macrocode} \dim_compare:nNnT \l_tmpb_dim = \c_max_dim { \@@_qpoint:n { col - #2 } \dim_set_eq:NN \l_tmpb_dim \pgf@x } \dim_set:Nn \l_@@_tmpd_dim { - \c_max_dim } \int_step_inline:nnn \l_@@_first_row_int \g_@@_row_total_int { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - ##1 - \int_use:N \l_@@_last_col_int } { \seq_if_in:NnF \g_@@_multicolumn_cells_seq { ##1 - #2 } { \pgfpointanchor { \@@_env: - ##1 - \int_use:N \l_@@_last_col_int } { east } \dim_set:Nn \l_@@_tmpd_dim { \dim_max:nn \l_@@_tmpd_dim \pgf@x } } } } \dim_compare:nNnT \l_@@_tmpd_dim = { - \c_max_dim } { \@@_qpoint:n { col - \int_eval:n { \l_@@_last_col_int + 1 } } \dim_set_eq:NN \l_@@_tmpd_dim \pgf@x } \@@_pgf_rect_node:nnnnn { \@@_env: - #1 - #2 - block - short } \l_tmpb_dim \l_tmpa_dim \l_@@_tmpd_dim \l_@@_tmpc_dim } % \end{macrocode} % % \medskip % If the creation of the ``medium nodes'' is required, we create a ``medium % node'' for the block. The function |\@@_pgf_rect_node:nnn| takes in as % arguments the name of the node and two \textsc{pgf} points. % \begin{macrocode} \bool_if:NT \l_@@_medium_nodes_bool { \@@_pgf_rect_node:nnn { \@@_env: - #1 - #2 - block - medium } { \pgfpointanchor { \@@_env: - #1 - #2 - medium } { north~west } } { \pgfpointanchor { \@@_env: - \int_use:N \l_@@_last_row_int - \int_use:N \l_@@_last_col_int - medium } { south~east } } } % \end{macrocode} % % % \medskip % Now, we will put the label of the block. % \begin{macrocode} \bool_lazy_any:nTF { { \str_if_eq_p:on \l_@@_vpos_block_str { c } } { \str_if_eq_p:on \l_@@_vpos_block_str { T } } { \str_if_eq_p:on \l_@@_vpos_block_str { B } } } % \end{macrocode} % \medskip % \begin{macrocode} { % \end{macrocode} % If we are in the first column, we must put the block as if it was with the key~|r|. % \begin{macrocode} \int_if_zero:nT { #2 } { \str_set_eq:NN \l_@@_hpos_block_str \c_@@_r_str } % \end{macrocode} % If we are in the last column, we must put the block as if it was with the key~|l|. % \begin{macrocode} \bool_if:nT \g_@@_last_col_found_bool { \int_compare:nNnT { #2 } = \g_@@_col_total_int { \str_set_eq:NN \l_@@_hpos_block_str \c_@@_l_str } } % \end{macrocode} % |\l_tmpa_tl| will contain the anchor of the \textsc{pgf} node which will be used. % \begin{macrocode} \tl_set:Nx \l_tmpa_tl { \str_case:on \l_@@_vpos_block_str { c { \str_case:on \l_@@_hpos_block_str { c { center } l { west } r { east } } } T { \str_case:on \l_@@_hpos_block_str { c { north } l { north~west } r { north~east } } } B { \str_case:on \l_@@_hpos_block_str { c { south} l { south~west } r { south~east } } } } } % \end{macrocode} % \begin{macrocode} \pgftransformshift { \pgfpointanchor { \@@_env: - #1 - #2 - block \bool_if:NF \l_@@_hpos_of_block_cap_bool { - short } } { \l_tmpa_tl } } \pgfset { inner~xsep = \c_zero_dim , inner~ysep = \c_zero_dim } \pgfnode { rectangle } { \l_tmpa_tl } { \box_use_drop:N \l_@@_cell_box } { } { } } % \end{macrocode} % End of the case when |\l_@@_vpos_block_str| is equal to |c|, |T| or |B|. % Now, the other cases. % \begin{macrocode} { % \end{macrocode} % % \begin{macrocode} \pgfextracty \l_tmpa_dim { \@@_qpoint:n { row - \str_if_eq:onTF \l_@@_vpos_block_str { b } { #3 } { #1 } - base } } \dim_sub:Nn \l_tmpa_dim { 0.5 \arrayrulewidth } % added 2023-02-21 % \end{macrocode} % We retrieve (in |\pgf@x|) the $x$-value of the center of the block. % \begin{macrocode} \pgfpointanchor { \@@_env: - #1 - #2 - block \bool_if:NF \l_@@_hpos_of_block_cap_bool { - short } } { \str_case:on \l_@@_hpos_block_str { c { center } l { west } r { east } } } % \end{macrocode} % We put the label of the block which has been composed in |\l_@@_cell_box|. % \begin{macrocode} \pgftransformshift { \pgfpoint \pgf@x \l_tmpa_dim } \pgfset { inner~sep = \c_zero_dim } \pgfnode { rectangle } { \str_case:on \l_@@_hpos_block_str { c { base } l { base~west } r { base~east } } } { \box_use_drop:N \l_@@_cell_box } { } { } } % \end{macrocode} % % \begin{macrocode} \endpgfpicture \group_end: } % \end{macrocode} % % % % \bigskip % The first argument of |\@@_stroke_block:nnn| is a list of options for the % rectangle that you will stroke. The second argument is the upper-left cell of % the block (with, as usual, the syntax $i$|-|$j$) and the third is the last % cell of the block (with the same syntax). % \begin{macrocode} \cs_new_protected:Npn \@@_stroke_block:nnn #1 #2 #3 { \group_begin: \tl_clear:N \l_@@_draw_tl \dim_set_eq:NN \l_@@_line_width_dim \arrayrulewidth \keys_set_known:nn { NiceMatrix / BlockStroke } { #1 } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \tl_if_empty:NF \l_@@_draw_tl { % \end{macrocode} % If the user has used the key |color| of the command |\Block| without value, % the color fixed by |\arrayrulecolor| is used. % \begin{macrocode} \tl_if_eq:NNTF \l_@@_draw_tl \c_@@_default_tl { \CT@arc@ } { \@@_color:o \l_@@_draw_tl } } \pgfsetcornersarced { \pgfpoint { \l_@@_rounded_corners_dim } { \l_@@_rounded_corners_dim } } \@@_cut_on_hyphen:w #2 \q_stop \int_compare:nNnF \l_tmpa_tl > \c@iRow { \int_compare:nNnF \l_tmpb_tl > \c@jCol { \@@_qpoint:n { row - \l_tmpa_tl } \dim_set_eq:NN \l_tmpb_dim \pgf@y \@@_qpoint:n { col - \l_tmpb_tl } \dim_set_eq:NN \l_@@_tmpc_dim \pgf@x \@@_cut_on_hyphen:w #3 \q_stop \int_compare:nNnT \l_tmpa_tl > \c@iRow { \tl_set:No \l_tmpa_tl { \int_use:N \c@iRow } } \int_compare:nNnT \l_tmpb_tl > \c@jCol { \tl_set:No \l_tmpb_tl { \int_use:N \c@jCol } } \@@_qpoint:n { row - \int_eval:n { \l_tmpa_tl + 1 } } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint:n { col - \int_eval:n { \l_tmpb_tl + 1 } } \dim_set_eq:NN \l_@@_tmpd_dim \pgf@x \pgfsetlinewidth { 1.1 \l_@@_line_width_dim } \pgfpathrectanglecorners { \pgfpoint \l_@@_tmpc_dim \l_tmpb_dim } { \pgfpoint \l_@@_tmpd_dim \l_tmpa_dim } \dim_compare:nNnTF \l_@@_rounded_corners_dim = \c_zero_dim { \pgfusepathqstroke } { \pgfusepath { stroke } } } } \endpgfpicture \group_end: } % \end{macrocode} % % Here is the set of keys for the command |\@@_stroke_block:nnn|. % \begin{macrocode} \keys_define:nn { NiceMatrix / BlockStroke } { color .tl_set:N = \l_@@_draw_tl , draw .code:n = \exp_args:Ne \tl_if_empty:nF { #1 } { \tl_set:Nn \l_@@_draw_tl { #1 } } , draw .default:n = default , line-width .dim_set:N = \l_@@_line_width_dim , rounded-corners .dim_set:N = \l_@@_rounded_corners_dim , rounded-corners .default:n = 4 pt } % \end{macrocode} % % % \bigskip % The first argument of |\@@_vlines_block:nnn| is a list of options for the % rules that we will draw. The second argument is the upper-left cell of the % block (with, as usual, the syntax $i$|-|$j$) and the third is the last cell of % the block (with the same syntax). % \begin{macrocode} \cs_new_protected:Npn \@@_vlines_block:nnn #1 #2 #3 { \dim_set_eq:NN \l_@@_line_width_dim \arrayrulewidth \keys_set_known:nn { NiceMatrix / BlockBorders } { #1 } \@@_cut_on_hyphen:w #2 \q_stop \tl_set_eq:NN \l_@@_tmpc_tl \l_tmpa_tl \tl_set_eq:NN \l_@@_tmpd_tl \l_tmpb_tl \@@_cut_on_hyphen:w #3 \q_stop \tl_set:Nx \l_tmpa_tl { \int_eval:n { \l_tmpa_tl + 1 } } \tl_set:Nx \l_tmpb_tl { \int_eval:n { \l_tmpb_tl + 1 } } \int_step_inline:nnn \l_@@_tmpd_tl \l_tmpb_tl { \use:e { \@@_vline:n { position = ##1 , start = \l_@@_tmpc_tl , end = \int_eval:n { \l_tmpa_tl - 1 } , total-width = \dim_use:N \l_@@_line_width_dim } } } } \cs_new_protected:Npn \@@_hlines_block:nnn #1 #2 #3 { \dim_set_eq:NN \l_@@_line_width_dim \arrayrulewidth \keys_set_known:nn { NiceMatrix / BlockBorders } { #1 } \@@_cut_on_hyphen:w #2 \q_stop \tl_set_eq:NN \l_@@_tmpc_tl \l_tmpa_tl \tl_set_eq:NN \l_@@_tmpd_tl \l_tmpb_tl \@@_cut_on_hyphen:w #3 \q_stop \tl_set:Nx \l_tmpa_tl { \int_eval:n { \l_tmpa_tl + 1 } } \tl_set:Nx \l_tmpb_tl { \int_eval:n { \l_tmpb_tl + 1 } } \int_step_inline:nnn \l_@@_tmpc_tl \l_tmpa_tl { \use:e { \@@_hline:n { position = ##1 , start = \l_@@_tmpd_tl , end = \int_eval:n { \l_tmpb_tl - 1 } , total-width = \dim_use:N \l_@@_line_width_dim } } } } % \end{macrocode} % % \bigskip % The first argument of |\@@_stroke_borders_block:nnn| is a list of options for % the borders that you will stroke. The second argument is the upper-left cell % of the block (with, as usual, the syntax $i$|-|$j$) and the third is the last % cell of the block (with the same syntax). % \begin{macrocode} \cs_new_protected:Npn \@@_stroke_borders_block:nnn #1 #2 #3 { \dim_set_eq:NN \l_@@_line_width_dim \arrayrulewidth \keys_set_known:nn { NiceMatrix / BlockBorders } { #1 } \dim_compare:nNnTF \l_@@_rounded_corners_dim > \c_zero_dim { \@@_error:n { borders~forbidden } } { \tl_clear_new:N \l_@@_borders_tikz_tl \keys_set:nV { NiceMatrix / OnlyForTikzInBorders } \l_@@_borders_clist \@@_cut_on_hyphen:w #2 \q_stop \tl_set_eq:NN \l_@@_tmpc_tl \l_tmpa_tl \tl_set_eq:NN \l_@@_tmpd_tl \l_tmpb_tl \@@_cut_on_hyphen:w #3 \q_stop \tl_set:Nx \l_tmpa_tl { \int_eval:n { \l_tmpa_tl + 1 } } \tl_set:Nx \l_tmpb_tl { \int_eval:n { \l_tmpb_tl + 1 } } \@@_stroke_borders_block_i: } } % \end{macrocode} % % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \cs_new_protected:Npx \@@_stroke_borders_block_i: { \c_@@_pgfortikzpicture_tl \@@_stroke_borders_block_ii: \c_@@_endpgfortikzpicture_tl } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_stroke_borders_block_ii: { \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \CT@arc@ \pgfsetlinewidth { 1.1 \l_@@_line_width_dim } \clist_if_in:NnT \l_@@_borders_clist { right } { \@@_stroke_vertical:n \l_tmpb_tl } \clist_if_in:NnT \l_@@_borders_clist { left } { \@@_stroke_vertical:n \l_@@_tmpd_tl } \clist_if_in:NnT \l_@@_borders_clist { bottom } { \@@_stroke_horizontal:n \l_tmpa_tl } \clist_if_in:NnT \l_@@_borders_clist { top } { \@@_stroke_horizontal:n \l_@@_tmpc_tl } } % \end{macrocode} % % \begin{macrocode} \keys_define:nn { NiceMatrix / OnlyForTikzInBorders } { tikz .code:n = \cs_if_exist:NTF \tikzpicture { \tl_set:Nn \l_@@_borders_tikz_tl { #1 } } { \@@_error:n { tikz~in~borders~without~tikz } } , tikz .value_required:n = true , top .code:n = , bottom .code:n = , left .code:n = , right .code:n = , unknown .code:n = \@@_error:n { bad~border } } % \end{macrocode} % % % \medskip % The following command is used to stroke the left border and the right border. % The argument |#1| is the number of column (in the sense of the |col| node). % \begin{macrocode} \cs_new_protected:Npn \@@_stroke_vertical:n #1 { \@@_qpoint:n \l_@@_tmpc_tl \dim_set:Nn \l_tmpb_dim { \pgf@y + 0.5 \l_@@_line_width_dim } \@@_qpoint:n \l_tmpa_tl \dim_set:Nn \l_@@_tmpc_dim { \pgf@y + 0.5 \l_@@_line_width_dim } \@@_qpoint:n { #1 } \tl_if_empty:NTF \l_@@_borders_tikz_tl { \pgfpathmoveto { \pgfpoint \pgf@x \l_tmpb_dim } \pgfpathlineto { \pgfpoint \pgf@x \l_@@_tmpc_dim } \pgfusepathqstroke } { \use:e { \exp_not:N \draw [ \l_@@_borders_tikz_tl ] } ( \pgf@x , \l_tmpb_dim ) -- ( \pgf@x , \l_@@_tmpc_dim ) ; } } % \end{macrocode} % % \medskip % The following command is used to stroke the top border and the bottom border. % The argument |#1| is the number of row (in the sense of the |row| node). % \begin{macrocode} \cs_new_protected:Npn \@@_stroke_horizontal:n #1 { \@@_qpoint:n \l_@@_tmpd_tl \clist_if_in:NnTF \l_@@_borders_clist { left } { \dim_set:Nn \l_tmpa_dim { \pgf@x - 0.5 \l_@@_line_width_dim } } { \dim_set:Nn \l_tmpa_dim { \pgf@x + 0.5 \l_@@_line_width_dim } } \@@_qpoint:n \l_tmpb_tl \dim_set:Nn \l_tmpb_dim { \pgf@x + 0.5 \l_@@_line_width_dim } \@@_qpoint:n { #1 } \tl_if_empty:NTF \l_@@_borders_tikz_tl { \pgfpathmoveto { \pgfpoint \l_tmpa_dim \pgf@y } \pgfpathlineto { \pgfpoint \l_tmpb_dim \pgf@y } \pgfusepathqstroke } { \use:e { \exp_not:N \draw [ \l_@@_borders_tikz_tl ] } ( \l_tmpa_dim , \pgf@y ) -- ( \l_tmpb_dim , \pgf@y ) ; } } % \end{macrocode} % % \bigskip % Here is the set of keys for the command |\@@_stroke_borders_block:nnn|. % \begin{macrocode} \keys_define:nn { NiceMatrix / BlockBorders } { borders .clist_set:N = \l_@@_borders_clist , rounded-corners .dim_set:N = \l_@@_rounded_corners_dim , rounded-corners .default:n = 4 pt , line-width .dim_set:N = \l_@@_line_width_dim } % \end{macrocode} % % \bigskip % The following command will be used if the key |tikz| has been used for the % command |\Block|. The arguments |#1| and |#2| are the coordinates of the first % cell and |#3| and |#4| the coordinates of the last cell of the block. |#5| is % a comma-separated list of the Tikz keys used with the path. However, among % those keys, you have added in \pkg{nicematrix} a special key |offset| (an % offset for the rectangle of the block). That's why we have to extract that key % first. % \begin{macrocode} \cs_new_protected:Npn \@@_block_tikz:nnnnn #1 #2 #3 #4 #5 { \begin { tikzpicture } \@@_clip_with_rounded_corners: \clist_map_inline:nn { #5 } { \keys_set_known:nnN { NiceMatrix / SpecialOffset } { ##1 } \l_tmpa_tl \use:e { \exp_not:N \path [ \l_tmpa_tl ] } ( [ xshift = \dim_use:N \l_@@_offset_dim , yshift = - \dim_use:N \l_@@_offset_dim ] #1 -| #2 ) rectangle ( [ xshift = - \dim_use:N \l_@@_offset_dim , yshift = \dim_use:N \l_@@_offset_dim ] \int_eval:n { #3 + 1 } -| \int_eval:n { #4 + 1 } ) ; } \end { tikzpicture } } \cs_generate_variant:Nn \@@_block_tikz:nnnnn { n n n n V } % \end{macrocode} % % \medskip % \begin{macrocode} \keys_define:nn { NiceMatrix / SpecialOffset } { offset .dim_set:N = \l_@@_offset_dim } % \end{macrocode} % % % \section{How to draw the dotted lines transparently} % \begin{macrocode} \cs_set_protected:Npn \@@_renew_matrix: { \RenewDocumentEnvironment { pmatrix } { } { \pNiceMatrix } { \endpNiceMatrix } \RenewDocumentEnvironment { vmatrix } { } { \vNiceMatrix } { \endvNiceMatrix } \RenewDocumentEnvironment { Vmatrix } { } { \VNiceMatrix } { \endVNiceMatrix } \RenewDocumentEnvironment { bmatrix } { } { \bNiceMatrix } { \endbNiceMatrix } \RenewDocumentEnvironment { Bmatrix } { } { \BNiceMatrix } { \endBNiceMatrix } } % \end{macrocode} % % % \bigskip % \section{Automatic arrays} % % % % We will extract some keys and pass the other keys to the environment % |{NiceArrayWithDelims}|. % \begin{macrocode} \keys_define:nn { NiceMatrix / Auto } { columns-type .tl_set:N = \l_@@_columns_type_tl , columns-type .value_required:n = true , l .meta:n = { columns-type = l } , r .meta:n = { columns-type = r } , c .meta:n = { columns-type = c } , delimiters / color .tl_set:N = \l_@@_delimiters_color_tl , delimiters / color .value_required:n = true , delimiters / max-width .bool_set:N = \l_@@_delimiters_max_width_bool , delimiters / max-width .default:n = true , delimiters .code:n = \keys_set:nn { NiceMatrix / delimiters } { #1 } , delimiters .value_required:n = true , rounded-corners .dim_set:N = \l_@@_tab_rounded_corners_dim , rounded-corners .default:n = 4 pt } % \end{macrocode} % % \begin{macrocode} \NewDocumentCommand \AutoNiceMatrixWithDelims { m m O { } > { \SplitArgument { 1 } { - } } m O { } m ! O { } } { \@@_auto_nice_matrix:nnnnnn { #1 } { #2 } #4 { #6 } { #3 , #5 , #7 } } % \end{macrocode} % % % \begin{macrocode} \cs_new_protected:Npn \@@_auto_nice_matrix:nnnnnn #1 #2 #3 #4 #5 #6 { % \end{macrocode} % The group is for the protection of the keys. % \begin{macrocode} \group_begin: \keys_set_known:nnN { NiceMatrix / Auto } { #6 } \l_tmpa_tl \use:e { \exp_not:N \begin { NiceArrayWithDelims } { #1 } { #2 } { * { #4 } { \exp_not:o \l_@@_columns_type_tl } } [ \exp_not:o \l_tmpa_tl ] } \int_if_zero:nT \l_@@_first_row_int { \int_if_zero:nT \l_@@_first_col_int { & } \prg_replicate:nn { #4 - 1 } { & } \int_compare:nNnT \l_@@_last_col_int > { -1 } { & } \\ } \prg_replicate:nn { #3 } { \int_if_zero:nT \l_@@_first_col_int { & } % \end{macrocode} % We put |{ }| before |#6| to avoid a hasty expansion of a potential % |\arabic{iRow}| at the beginning of the row which would result in an incorrect % value of that |iRow| (since |iRow| is incremented in the first cell of the row % of the |\halign|). % \begin{macrocode} \prg_replicate:nn { #4 - 1 } { { } #5 & } #5 \int_compare:nNnT \l_@@_last_col_int > { -1 } { & } \\ } \int_compare:nNnT \l_@@_last_row_int > { -2 } { \int_if_zero:nT \l_@@_first_col_int { & } \prg_replicate:nn { #4 - 1 } { & } \int_compare:nNnT \l_@@_last_col_int > { -1 } { & } \\ } \end { NiceArrayWithDelims } \group_end: } % \end{macrocode} % % \begin{macrocode} \cs_set_protected:Npn \@@_define_com:nnn #1 #2 #3 { \cs_set_protected:cpn { #1 AutoNiceMatrix } { \bool_gset_true:N \g_@@_delims_bool \str_gset:Nx \g_@@_name_env_str { #1 AutoNiceMatrix } \AutoNiceMatrixWithDelims { #2 } { #3 } } } % \end{macrocode} % % \begin{macrocode} \@@_define_com:nnn p ( ) \@@_define_com:nnn b [ ] \@@_define_com:nnn v | | \@@_define_com:nnn V \| \| \@@_define_com:nnn B \{ \} % \end{macrocode} % % \bigskip % We define also a command |\AutoNiceMatrix| similar to the environment |{NiceMatrix}|. % \begin{macrocode} \NewDocumentCommand \AutoNiceMatrix { O { } m O { } m ! O { } } { \group_begin: \bool_gset_false:N \g_@@_delims_bool \AutoNiceMatrixWithDelims . . { #2 } { #4 } [ #1 , #3 , #5 ] \group_end: } % \end{macrocode} % % % \bigskip % \section{The redefinition of the command \textbackslash dotfill } % % \begin{macrocode} \cs_set_eq:NN \@@_old_dotfill \dotfill \cs_new_protected:Npn \@@_dotfill: { % \end{macrocode} % First, we insert |\@@_dotfill| (which is the saved version of |\dotfill|) in % case of use of |\dotfill| ``internally'' in the cell (e.g. |\hbox to 1cm {\dotfill}|). % \begin{macrocode} \@@_old_dotfill \tl_gput_right:Nn \g_@@_cell_after_hook_tl \@@_dotfill_i: } % \end{macrocode} % Now, if the box if not empty (unfornately, we can't actually test whether the % box is empty and that's why we only consider it's width), we insert % |\@@_dotfill| (which is the saved version of |\dotfill|) in the cell of the % array, and it will extend, since it is no longer in |\l_@@_cell_box|. % \begin{macrocode} \cs_new_protected:Npn \@@_dotfill_i: { \dim_compare:nNnT { \box_wd:N \l_@@_cell_box } = \c_zero_dim \@@_old_dotfill } % \end{macrocode} % % \bigskip % \section{The command \textbackslash diagbox} % % The command |\diagbox| will be linked to |\diagbox:nn| in the environments of % \pkg{nicematrix}. However, there are also redefinitions of |\diagbox| in other % circonstancies. % % \begin{macrocode} \cs_new_protected:Npn \@@_diagbox:nn #1 #2 { \tl_gput_right:Nx \g_@@_pre_code_after_tl { \@@_actually_diagbox:nnnnnn { \int_use:N \c@iRow } { \int_use:N \c@jCol } { \int_use:N \c@iRow } { \int_use:N \c@jCol } % \end{macrocode} % |\g_@@_row_style_tl| contains several instructions of the form: % % \qquad |\@@_if_row_less_than:nn { number } { instructions }| % % The command |\@@_if_row_less:nn| is fully expandable and, thus, the % instructions will be inserted in the |\g_@@_pre_code_after_tl| only if % |\diagbox| is used in a row which is the scope of that chunck of instructions. % \begin{macrocode} { \g_@@_row_style_tl \exp_not:n { #1 } } { \g_@@_row_style_tl \exp_not:n { #2 } } } % \end{macrocode} % We put the cell with |\diagbox| in the sequence |\g_@@_pos_of_blocks_seq| % because a cell with |\diagbox| must be considered as non empty by the key % |corners|. % \begin{macrocode} \seq_gput_right:Nx \g_@@_pos_of_blocks_seq { { \int_use:N \c@iRow } { \int_use:N \c@jCol } { \int_use:N \c@iRow } { \int_use:N \c@jCol } % \end{macrocode} % The last argument is for the name of the block. % \begin{macrocode} { } } } % \end{macrocode} % % \medskip % The command |\diagbox| is also redefined locally when we draw a block. % % \medskip % The first four arguments of |\@@_actually_diagbox:nnnnnn| correspond to the % rectangle (=block) to slash (we recall that it's possible to use |\diagbox| in % a |\Block|). The other two are the elements to draw below and above the % diagonal line. % \begin{macrocode} \cs_new_protected:Npn \@@_actually_diagbox:nnnnnn #1 #2 #3 #4 #5 #6 { \pgfpicture \pgf@relevantforpicturesizefalse \pgfrememberpicturepositiononpagetrue \@@_qpoint:n { row - #1 } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint:n { col - #2 } \dim_set_eq:NN \l_tmpb_dim \pgf@x \pgfpathmoveto { \pgfpoint \l_tmpb_dim \l_tmpa_dim } \@@_qpoint:n { row - \int_eval:n { #3 + 1 } } \dim_set_eq:NN \l_@@_tmpc_dim \pgf@y \@@_qpoint:n { col - \int_eval:n { #4 + 1 } } \dim_set_eq:NN \l_@@_tmpd_dim \pgf@x \pgfpathlineto { \pgfpoint \l_@@_tmpd_dim \l_@@_tmpc_dim } { % \end{macrocode} % The command |\CT@arc@| is a command of \pkg{colortbl} which sets the color of % the rules in the array. The package \pkg{nicematrix} uses it even if \pkg{colortbl} is not % loaded. % \begin{macrocode} \CT@arc@ \pgfsetroundcap \pgfusepathqstroke } \pgfset { inner~sep = 1 pt } \pgfscope \pgftransformshift { \pgfpoint \l_tmpb_dim \l_@@_tmpc_dim } \pgfnode { rectangle } { south~west } { \begin { minipage } { 20 cm } \@@_math_toggle: #5 \@@_math_toggle: \end { minipage } } { } { } \endpgfscope \pgftransformshift { \pgfpoint \l_@@_tmpd_dim \l_tmpa_dim } \pgfnode { rectangle } { north~east } { \begin { minipage } { 20 cm } \raggedleft \@@_math_toggle: #6 \@@_math_toggle: \end { minipage } } { } { } \endpgfpicture } % \end{macrocode} % % % % % \bigskip % \section{The keyword \textbackslash CodeAfter} % % % % \medskip % In fact, in this subsection, we define the user command |\CodeAfter| for the % case of the ``normal syntax''. For the case of ``light-syntax'', see the % definition of the environment |{@@-light-syntax}| on % p.~\pageref{code-light-syntax}. % % % \medskip % In the environments of \pkg{nicematrix}, |\CodeAfter| will be linked to % |\@@_CodeAfter:|. That macro must \emph{not} be protected since it begins with % |\omit|. % \begin{macrocode} \cs_new:Npn \@@_CodeAfter: { \omit \@@_CodeAfter_ii:n } % \end{macrocode} % % \medskip % However, in each cell of the environment, the command |\CodeAfter| will be % linked to the following command |\@@_CodeAfter_ii:n| which begins % with |\\|. % % \begin{macrocode} \cs_new_protected:Npn \@@_CodeAfter_i: { \\ \omit \@@_CodeAfter_ii:n } % \end{macrocode} % % \smallskip % We have to catch everything until the end of the current environment (of % \pkg{nicematrix}). First, we go until the next command |\end|. % \begin{macrocode} \cs_new_protected:Npn \@@_CodeAfter_ii:n #1 \end { \tl_gput_right:Nn \g_nicematrix_code_after_tl { #1 } \@@_CodeAfter_iv:n } % \end{macrocode} % % We catch the argument of the command |\end| (in |#1|). % \begin{macrocode} \cs_new_protected:Npn \@@_CodeAfter_iv:n #1 { % \end{macrocode} % If this is really the end of the current environment (of \pkg{nicematrix}), we % put back the command |\end| and its argument in the TeX flow. % \begin{macrocode} \str_if_eq:eeTF \@currenvir { #1 } { \end { #1 } } % \end{macrocode} % If this is not the |\end| we are looking for, we put those tokens in % |\g_nicematrix_code_after_tl| and we go on searching for the next command % |\end| with a recursive call to the command |\@@_CodeAfter:n|. % \begin{macrocode} { \tl_gput_right:Nn \g_nicematrix_code_after_tl { \end { #1 } } \@@_CodeAfter_ii:n } } % \end{macrocode} % % % % \section{The delimiters in the preamble} % % The command |\@@_delimiter:nnn| will be used to draw delimiters inside the % matrix when delimiters are specified in the preamble of the array. It does % \emph{not} concern the exterior delimiters added by |{NiceArrayWithDelims}| % (and |{pNiceArray}|, |{pNiceMatrix}|, etc.). % % A delimiter in the preamble of the array will write an instruction % |\@@_delimiter:nnn| in the |\g_@@_pre_code_after_tl| (and also % potentially add instructions in the preamble provided to |\array| in order to % add space between columns). % % \smallskip % The first argument is the type of delimiter (|(|, |[|, |\{|, |)|, |]| or % |\}|). The second argument is the number of colummn. The third argument is a % boolean equal to |\c_true_bool| (resp. |\c_false_true|) when the delimiter % must be put on the left (resp. right) side. % % \begin{macrocode} \cs_new_protected:Npn \@@_delimiter:nnn #1 #2 #3 { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse % \end{macrocode} % % \medskip % |\l_@@_y_initial_dim| and |\l_@@_y_final_dim| will be the $y$-values of the % extremities of the delimiter we will have to construct. % \begin{macrocode} \@@_qpoint:n { row - 1 } \dim_set_eq:NN \l_@@_y_initial_dim \pgf@y \@@_qpoint:n { row - \int_eval:n { \c@iRow + 1 } } \dim_set_eq:NN \l_@@_y_final_dim \pgf@y % \end{macrocode} % % \medskip % We will compute in |\l_tmpa_dim| the $x$-value where we will have to put our % delimiter (on the left side or on the right side). % \begin{macrocode} \bool_if:nTF { #3 } { \dim_set_eq:NN \l_tmpa_dim \c_max_dim } { \dim_set:Nn \l_tmpa_dim { - \c_max_dim } } \int_step_inline:nnn \l_@@_first_row_int \g_@@_row_total_int { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - ##1 - #2 } { \pgfpointanchor { \@@_env: - ##1 - #2 } { \bool_if:nTF { #3 } { west } { east } } \dim_set:Nn \l_tmpa_dim { \bool_if:nTF { #3 } \dim_min:nn \dim_max:nn \l_tmpa_dim \pgf@x } } } % \end{macrocode} % % % Now we can put the delimiter with a node of \textsc{pgf}. % \begin{macrocode} \pgfset { inner~sep = \c_zero_dim } \dim_zero:N \nulldelimiterspace \pgftransformshift { \pgfpoint { \l_tmpa_dim } { ( \l_@@_y_initial_dim + \l_@@_y_final_dim + \arrayrulewidth ) / 2 } } \pgfnode { rectangle } { \bool_if:nTF { #3 } { east } { west } } { % \end{macrocode} % Here is the content of the \textsc{pgf} node, that is to say the delimiter, % constructed with its right size. % \begin{macrocode} \nullfont \c_math_toggle_token \@@_color:o \l_@@_delimiters_color_tl \bool_if:nTF { #3 } { \left #1 } { \left . } \vcenter { \nullfont \hrule \@height \dim_eval:n { \l_@@_y_initial_dim - \l_@@_y_final_dim } \@depth \c_zero_dim \@width \c_zero_dim } \bool_if:nTF { #3 } { \right . } { \right #1 } \c_math_toggle_token } { } { } \endpgfpicture } % \end{macrocode} % % \section{The command \textbackslash SubMatrix} % % % \begin{macrocode} \keys_define:nn { NiceMatrix / sub-matrix } { extra-height .dim_set:N = \l_@@_submatrix_extra_height_dim , extra-height .value_required:n = true , left-xshift .dim_set:N = \l_@@_submatrix_left_xshift_dim , left-xshift .value_required:n = true , right-xshift .dim_set:N = \l_@@_submatrix_right_xshift_dim , right-xshift .value_required:n = true , xshift .meta:n = { left-xshift = #1, right-xshift = #1 } , xshift .value_required:n = true , delimiters / color .tl_set:N = \l_@@_delimiters_color_tl , delimiters / color .value_required:n = true , slim .bool_set:N = \l_@@_submatrix_slim_bool , slim .default:n = true , hlines .clist_set:N = \l_@@_submatrix_hlines_clist , hlines .default:n = all , vlines .clist_set:N = \l_@@_submatrix_vlines_clist , vlines .default:n = all , hvlines .meta:n = { hlines, vlines } , hvlines .value_forbidden:n = true } \keys_define:nn { NiceMatrix } { SubMatrix .inherit:n = NiceMatrix / sub-matrix , NiceArray / sub-matrix .inherit:n = NiceMatrix / sub-matrix , pNiceArray / sub-matrix .inherit:n = NiceMatrix / sub-matrix , NiceMatrixOptions / sub-matrix .inherit:n = NiceMatrix / sub-matrix , } % \end{macrocode} % % \medskip % The following keys set is for the command |\SubMatrix| itself (not the tuning % of |\SubMatrix| that can be done elsewhere). % \begin{macrocode} \keys_define:nn { NiceMatrix / SubMatrix } { delimiters / color .tl_set:N = \l_@@_delimiters_color_tl , delimiters / color .value_required:n = true , hlines .clist_set:N = \l_@@_submatrix_hlines_clist , hlines .default:n = all , vlines .clist_set:N = \l_@@_submatrix_vlines_clist , vlines .default:n = all , hvlines .meta:n = { hlines, vlines } , hvlines .value_forbidden:n = true , name .code:n = \tl_if_empty:nTF { #1 } { \@@_error:n { Invalid~name } } { \regex_match:nnTF { \A[A-Za-z][A-Za-z0-9]*\Z } { #1 } { \seq_if_in:NnTF \g_@@_submatrix_names_seq { #1 } { \@@_error:nn { Duplicate~name~for~SubMatrix } { #1 } } { \str_set:Nn \l_@@_submatrix_name_str { #1 } \seq_gput_right:Nn \g_@@_submatrix_names_seq { #1 } } } { \@@_error:n { Invalid~name } } } , name .value_required:n = true , rules .code:n = \keys_set:nn { NiceMatrix / rules } { #1 } , rules .value_required:n = true , code .tl_set:N = \l_@@_code_tl , code .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~SubMatrix } } % \end{macrocode} % % % % \bigskip % \begin{macrocode} \NewDocumentCommand \@@_SubMatrix_in_code_before { m m m m ! O { } } { \peek_remove_spaces:n { \tl_gput_right:Nx \g_@@_pre_code_after_tl { \SubMatrix { #1 } { #2 } { #3 } { #4 } [ delimiters / color = \l_@@_delimiters_color_tl , hlines = \l_@@_submatrix_hlines_clist , vlines = \l_@@_submatrix_vlines_clist , extra-height = \dim_use:N \l_@@_submatrix_extra_height_dim , left-xshift = \dim_use:N \l_@@_submatrix_left_xshift_dim , right-xshift = \dim_use:N \l_@@_submatrix_right_xshift_dim , slim = \bool_to_str:N \l_@@_submatrix_slim_bool , #5 ] } \@@_SubMatrix_in_code_before_i { #2 } { #3 } } } % \end{macrocode} % % \begin{macrocode} \NewDocumentCommand \@@_SubMatrix_in_code_before_i { > { \SplitArgument { 1 } { - } } m > { \SplitArgument { 1 } { - } } m } { \@@_SubMatrix_in_code_before_i:nnnn #1 #2 } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_SubMatrix_in_code_before_i:nnnn #1 #2 #3 #4 { \seq_gput_right:Nx \g_@@_submatrix_seq { % \end{macrocode} % We use |\str_if_eq:nnTF| because it is fully expandable. % \begin{macrocode} { \str_if_eq:nnTF { #1 } { last } { \int_use:N \c@iRow } { #1 } } { \str_if_eq:nnTF { #2 } { last } { \int_use:N \c@jCol } { #2 } } { \str_if_eq:nnTF { #3 } { last } { \int_use:N \c@iRow } { #3 } } { \str_if_eq:nnTF { #4 } { last } { \int_use:N \c@jCol } { #4 } } } } % \end{macrocode} % % % \bigskip % In the pre-code-after and in the |\CodeAfter| the following command % |\@@_SubMatrix| will be linked to |\SubMatrix|. % \begin{itemize} % \item |#1| is the left delimiter; % \item |#2| is the upper-left cell of the matrix with the format $i$-$j$; % \item |#3| is the lower-right cell of the matrix with the format $i$-$j$; % \item |#4| is the right delimiter; % \item |#5| is the list of options of the command; % \item |#6| is the potential subscript; % \item |#7| is the potential superscript. % \end{itemize} % For explanations about the construction with rescanning of the preamble, see % the documentation for the user command |\Cdots|. % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \cs_set_nopar:Npn \l_@@_argspec_tl { m m m m O { } E { _ ^ } { { } { } } } \tl_set_rescan:Nno \l_@@_argspec_tl { } \l_@@_argspec_tl \exp_args:NNo \NewDocumentCommand \@@_SubMatrix \l_@@_argspec_tl { \peek_remove_spaces:n { \@@_sub_matrix:nnnnnnn { #1 } { #2 } { #3 } { #4 } { #5 } { #6 } { #7 } } } } % \end{macrocode} % % \medskip % The following macro will compute |\l_@@_first_i_tl|, |\l_@@_first_j_tl|, % |\l_@@_last_i_tl| and |\l_@@_last_j_tl| from the arguments of the command as % provided by the user (for example |2-3| and |5-last|). % \begin{macrocode} \NewDocumentCommand \@@_compute_i_j:nn { > { \SplitArgument { 1 } { - } } m > { \SplitArgument { 1 } { - } } m } { \@@_compute_i_j:nnnn #1 #2 } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_compute_i_j:nnnn #1 #2 #3 #4 { \cs_set_nopar:Npn \l_@@_first_i_tl { #1 } \cs_set_nopar:Npn \l_@@_first_j_tl { #2 } \cs_set_nopar:Npn \l_@@_last_i_tl { #3 } \cs_set_nopar:Npn \l_@@_last_j_tl { #4 } \tl_if_eq:NnT \l_@@_first_i_tl { last } { \tl_set:NV \l_@@_first_i_tl \c@iRow } \tl_if_eq:NnT \l_@@_first_j_tl { last } { \tl_set:NV \l_@@_first_j_tl \c@jCol } \tl_if_eq:NnT \l_@@_last_i_tl { last } { \tl_set:NV \l_@@_last_i_tl \c@iRow } \tl_if_eq:NnT \l_@@_last_j_tl { last } { \tl_set:NV \l_@@_last_j_tl \c@jCol } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \@@_sub_matrix:nnnnnnn #1 #2 #3 #4 #5 #6 #7 { \group_begin: % \end{macrocode} % The four following token lists correspond to the position of the |\SubMatrix|. % \begin{macrocode} \@@_compute_i_j:nn { #2 } { #3 } \int_compare:nNnT \l_@@_first_i_tl = \l_@@_last_i_tl { \cs_set_nopar:Npn \arraystretch { 1 } } \bool_lazy_or:nnTF { \int_compare_p:nNn \l_@@_last_i_tl > \g_@@_row_total_int } { \int_compare_p:nNn \l_@@_last_j_tl > \g_@@_col_total_int } { \@@_error:nn { Construct~too~large } { \SubMatrix } } { \str_clear_new:N \l_@@_submatrix_name_str \keys_set:nn { NiceMatrix / SubMatrix } { #5 } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \pgfset { inner~sep = \c_zero_dim } \dim_set_eq:NN \l_@@_x_initial_dim \c_max_dim \dim_set:Nn \l_@@_x_final_dim { - \c_max_dim } % \end{macrocode} % The last value of |\int_step_inline:nnn| is provided by currifycation. % \begin{macrocode} \bool_if:NTF \l_@@_submatrix_slim_bool { \int_step_inline:nnn \l_@@_first_i_tl \l_@@_last_i_tl } { \int_step_inline:nnn \l_@@_first_row_int \g_@@_row_total_int } { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - ##1 - \l_@@_first_j_tl } { \pgfpointanchor { \@@_env: - ##1 - \l_@@_first_j_tl } { west } \dim_set:Nn \l_@@_x_initial_dim { \dim_min:nn \l_@@_x_initial_dim \pgf@x } } \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - ##1 - \l_@@_last_j_tl } { \pgfpointanchor { \@@_env: - ##1 - \l_@@_last_j_tl } { east } \dim_set:Nn \l_@@_x_final_dim { \dim_max:nn \l_@@_x_final_dim \pgf@x } } } \dim_compare:nNnTF \l_@@_x_initial_dim = \c_max_dim { \@@_error:nn { Impossible~delimiter } { left } } { \dim_compare:nNnTF \l_@@_x_final_dim = { - \c_max_dim } { \@@_error:nn { Impossible~delimiter } { right } } { \@@_sub_matrix_i:nnnn { #1 } { #4 } { #6 } { #7 } } } \endpgfpicture } \group_end: } % \end{macrocode} % % \bigskip % |#1| is the left delimiter, |#2| is the right one, |#3| is the subscript and % |#4| is the superscript. % \begin{macrocode} \cs_new_protected:Npn \@@_sub_matrix_i:nnnn #1 #2 #3 #4 { \@@_qpoint:n { row - \l_@@_first_i_tl - base } \dim_set:Nn \l_@@_y_initial_dim { \fp_to_dim:n { \pgf@y + ( \box_ht:N \strutbox + \extrarowheight ) * \arraystretch } } \@@_qpoint:n { row - \l_@@_last_i_tl - base } \dim_set:Nn \l_@@_y_final_dim { \fp_to_dim:n { \pgf@y - ( \box_dp:N \strutbox ) * \arraystretch } } \int_step_inline:nnn \l_@@_first_col_int \g_@@_col_total_int { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - \l_@@_first_i_tl - ##1 } { \pgfpointanchor { \@@_env: - \l_@@_first_i_tl - ##1 } { north } \dim_set:Nn \l_@@_y_initial_dim { \dim_max:nn \l_@@_y_initial_dim \pgf@y } } \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - \l_@@_last_i_tl - ##1 } { \pgfpointanchor { \@@_env: - \l_@@_last_i_tl - ##1 } { south } \dim_set:Nn \l_@@_y_final_dim { \dim_min:nn \l_@@_y_final_dim \pgf@y } } } \dim_set:Nn \l_tmpa_dim { \l_@@_y_initial_dim - \l_@@_y_final_dim + \l_@@_submatrix_extra_height_dim - \arrayrulewidth } \dim_zero:N \nulldelimiterspace % \end{macrocode} % % \bigskip % We will draw the rules in the |\SubMatrix|. % \begin{macrocode} \group_begin: \pgfsetlinewidth { 1.1 \arrayrulewidth } \@@_set_CT@arc@:o \l_@@_rules_color_tl \CT@arc@ % \end{macrocode} % Now, we draw the potential vertical rules specified in the preamble of the % environments with the letter fixed with the key |vlines-in-sub-matrix|. The % list of the columns where there is such rule to draw is in |\g_@@_cols_vlism_seq|. % \begin{macrocode} \seq_map_inline:Nn \g_@@_cols_vlism_seq { \int_compare:nNnT \l_@@_first_j_tl < { ##1 } { \int_compare:nNnT { ##1 } < { \int_eval:n { \l_@@_last_j_tl + 1 } } { % \end{macrocode} % First, we extract the value of the abscissa of the rule we have to draw. % \begin{macrocode} \@@_qpoint:n { col - ##1 } \pgfpathmoveto { \pgfpoint \pgf@x \l_@@_y_initial_dim } \pgfpathlineto { \pgfpoint \pgf@x \l_@@_y_final_dim } \pgfusepathqstroke } } } % \end{macrocode} % % \medskip % Now, we draw the vertical rules specified in the key |vlines| of |\SubMatrix|. % The last argument of |\int_step_inline:nn| or |\clist_map_inline:Nn| is given % by curryfication. % \begin{macrocode} \tl_if_eq:NNTF \l_@@_submatrix_vlines_clist \c_@@_all_tl { \int_step_inline:nn { \l_@@_last_j_tl - \l_@@_first_j_tl } } { \clist_map_inline:Nn \l_@@_submatrix_vlines_clist } { \bool_lazy_and:nnTF { \int_compare_p:nNn { ##1 } > \c_zero_int } { \int_compare_p:nNn { ##1 } < { \l_@@_last_j_tl - \l_@@_first_j_tl + 1 } } { \@@_qpoint:n { col - \int_eval:n { ##1 + \l_@@_first_j_tl } } \pgfpathmoveto { \pgfpoint \pgf@x \l_@@_y_initial_dim } \pgfpathlineto { \pgfpoint \pgf@x \l_@@_y_final_dim } \pgfusepathqstroke } { \@@_error:nnn { Wrong~line~in~SubMatrix } { vertical } { ##1 } } } % \end{macrocode} % % \medskip % Now, we draw the horizontal rules specified in the key |hlines| of % |\SubMatrix|. % The last argument of |\int_step_inline:nn| or |\clist_map_inline:Nn| is given % by curryfication. % \begin{macrocode} \tl_if_eq:NNTF \l_@@_submatrix_hlines_clist \c_@@_all_tl { \int_step_inline:nn { \l_@@_last_i_tl - \l_@@_first_i_tl } } { \clist_map_inline:Nn \l_@@_submatrix_hlines_clist } { \bool_lazy_and:nnTF { \int_compare_p:nNn { ##1 } > \c_zero_int } { \int_compare_p:nNn { ##1 } < { \l_@@_last_i_tl - \l_@@_first_i_tl + 1 } } { \@@_qpoint:n { row - \int_eval:n { ##1 + \l_@@_first_i_tl } } % \end{macrocode} % We use a group to protect |\l_tmpa_dim| and |\l_tmpb_dim|. % \begin{macrocode} \group_begin: % \end{macrocode} % We compute in |\l_tmpa_dim| the $x$-value of the left end of the rule. % \begin{macrocode} \dim_set:Nn \l_tmpa_dim { \l_@@_x_initial_dim - \l_@@_submatrix_left_xshift_dim } \str_case:nn { #1 } { ( { \dim_sub:Nn \l_tmpa_dim { 0.9 mm } } [ { \dim_sub:Nn \l_tmpa_dim { 0.2 mm } } \{ { \dim_sub:Nn \l_tmpa_dim { 0.9 mm } } } \pgfpathmoveto { \pgfpoint \l_tmpa_dim \pgf@y } % \end{macrocode} % We compute in |\l_tmpb_dim| the $x$-value of the right end of the rule. % \begin{macrocode} \dim_set:Nn \l_tmpb_dim { \l_@@_x_final_dim + \l_@@_submatrix_right_xshift_dim } \str_case:nn { #2 } { ) { \dim_add:Nn \l_tmpb_dim { 0.9 mm } } ] { \dim_add:Nn \l_tmpb_dim { 0.2 mm } } \} { \dim_add:Nn \l_tmpb_dim { 0.9 mm } } } \pgfpathlineto { \pgfpoint \l_tmpb_dim \pgf@y } \pgfusepathqstroke \group_end: } { \@@_error:nnn { Wrong~line~in~SubMatrix } { horizontal } { ##1 } } } % \end{macrocode} % % \medskip % If the key |name| has been used for the command |\SubMatrix|, we create a PGF % node with that name for the submatrix (this node does not encompass the % delimiters that we will put after). % \begin{macrocode} \str_if_empty:NF \l_@@_submatrix_name_str { \@@_pgf_rect_node:nnnnn \l_@@_submatrix_name_str \l_@@_x_initial_dim \l_@@_y_initial_dim \l_@@_x_final_dim \l_@@_y_final_dim } \group_end: % \end{macrocode} % The group was for |\CT@arc@| (the color of the rules). % % \medskip % Now, we deal with the left delimiter. Of course, the environment % |{pgfscope}| is for the |\pgftransformshift|. % \begin{macrocode} \begin { pgfscope } \pgftransformshift { \pgfpoint { \l_@@_x_initial_dim - \l_@@_submatrix_left_xshift_dim } { ( \l_@@_y_initial_dim + \l_@@_y_final_dim ) / 2 } } \str_if_empty:NTF \l_@@_submatrix_name_str { \@@_node_left:nn #1 { } } { \@@_node_left:nn #1 { \@@_env: - \l_@@_submatrix_name_str - left } } \end { pgfscope } % \end{macrocode} % % \medskip % Now, we deal with the right delimiter. % \begin{macrocode} \pgftransformshift { \pgfpoint { \l_@@_x_final_dim + \l_@@_submatrix_right_xshift_dim } { ( \l_@@_y_initial_dim + \l_@@_y_final_dim ) / 2 } } \str_if_empty:NTF \l_@@_submatrix_name_str { \@@_node_right:nnnn #2 { } { #3 } { #4 } } { \@@_node_right:nnnn #2 { \@@_env: - \l_@@_submatrix_name_str - right } { #3 } { #4 } } % \end{macrocode} % % \begin{macrocode} \cs_set_eq:NN \pgfpointanchor \@@_pgfpointanchor:n \flag_clear_new:n { nicematrix } \l_@@_code_tl } % \end{macrocode} % % \bigskip % In the key |code| of the command |\SubMatrix| there may be Tikz instructions. % We want that, in these instructions, the $i$ and $j$ in specifications of % nodes of the forms $i$|-|$j$, |row-|$i$, |col-|$j$ and $i$\verb+-|+$j$ refer % to the number of row and columm \emph{relative} of the current |\SubMatrix|. % That's why we will patch (locally in the |\SubMatrix|) the command % |\pgfpointanchor|. % \begin{macrocode} \cs_set_eq:NN \@@_old_pgfpointanchor \pgfpointanchor % \end{macrocode} % % \bigskip % The following command will be linked to |\pgfpointanchor| just before the % execution of the option |code| of the command |\SubMatrix|. In this command, % we catch the argument |#1| of |\pgfpointanchor| and we apply to it the command % |\@@_pgfpointanchor_i:nn| before passing it to the original |\pgfpointanchor|. % We have to act in an expandable way because the command |\pgfpointanchor| is % used in names of Tikz nodes which are computed in an expandable way. % \begin{macrocode} \cs_new_protected:Npn \@@_pgfpointanchor:n #1 { \use:e { \exp_not:N \@@_old_pgfpointanchor { \@@_pgfpointanchor_i:nn #1 } } } % \end{macrocode} % % \bigskip % In fact, the argument of |\pgfpointanchor| is always of the form % |\a_command { name_of_node }| where ``|name_of_node|'' is the name of the Tikz % node without the potential prefix and suffix. That's why we catch two % arguments and work only on the second by trying (first) to extract an hyphen |-|. % \begin{macrocode} \cs_new:Npn \@@_pgfpointanchor_i:nn #1 #2 { #1 { \@@_pgfpointanchor_ii:w #2 - \q_stop } } % \end{macrocode} % % \bigskip % Since |\seq_if_in:NnTF| and |\clist_if_in:NnTF| are not expandable, we will % use the following token list and |\str_case:nVTF| to test whether we have an % integer or not. % \begin{macrocode} \tl_const:Nn \c_@@_integers_alist_tl { { 1 } { } { 2 } { } { 3 } { } { 4 } { } { 5 } { } { 6 } { } { 7 } { } { 8 } { } { 9 } { } { 10 } { } { 11 } { } { 12 } { } { 13 } { } { 14 } { } { 15 } { } { 16 } { } { 17 } { } { 18 } { } { 19 } { } { 20 } { } } % \end{macrocode} % % \bigskip % \begin{macrocode} \cs_new:Npn \@@_pgfpointanchor_ii:w #1-#2\q_stop { % \end{macrocode} % If there is no hyphen, that means that the node is of the form of a single % number (ex.: |5| or |11|). In that case, we are in an analysis which result % from a specification of node of the form $i$\verb+-|+$j$. In that case, the % $i$ of the number of row arrives first (and alone) in a |\pgfpointanchor| and, % the, the $j$ arrives (alone) in the following |\pgfpointanchor|. In order to % know whether we have a number of row or a number of column, we keep track of % the number of such treatments by the expandable flag called |nicematrix|. % \begin{macrocode} \tl_if_empty:nTF { #2 } { \str_case:nVTF { #1 } \c_@@_integers_alist_tl { \flag_raise:n { nicematrix } \int_if_even:nTF { \flag_height:n { nicematrix } } { \int_eval:n { #1 + \l_@@_first_i_tl - 1 } } { \int_eval:n { #1 + \l_@@_first_j_tl - 1 } } } { #1 } } % \end{macrocode} % If there is an hyphen, we have to see whether we have a node of the form % $i$|-|$j$, |row-|$i$ or |col-|$j$. % \begin{macrocode} { \@@_pgfpointanchor_iii:w { #1 } #2 } } % \end{macrocode} % % \bigskip % There was an hyphen in the name of the node and that's why we have to retrieve % the extra hyphen we have put (cf. |\@@_pgfpointanchor_i:nn|). % \begin{macrocode} \cs_new:Npn \@@_pgfpointanchor_iii:w #1 #2 - { \str_case:nnF { #1 } { { row } { row - \int_eval:n { #2 + \l_@@_first_i_tl - 1 } } { col } { col - \int_eval:n { #2 + \l_@@_first_j_tl - 1 } } } % \end{macrocode} % Now the case of a node of the form $i$|-|$j$. % \begin{macrocode} { \int_eval:n { #1 + \l_@@_first_i_tl - 1 } - \int_eval:n { #2 + \l_@@_first_j_tl - 1 } } } % \end{macrocode} % % \medskip % The command |\@@_node_left:nn| puts the left delimiter with the correct size. % The argument |#1| is the delimiter to put. The argument |#2| is the name we % will give to this PGF node (if the key |name| has been used in |\SubMatrix|). % \begin{macrocode} \cs_new_protected:Npn \@@_node_left:nn #1 #2 { \pgfnode { rectangle } { east } { \nullfont \c_math_toggle_token \@@_color:o \l_@@_delimiters_color_tl \left #1 \vcenter { \nullfont \hrule \@height \l_tmpa_dim \@depth \c_zero_dim \@width \c_zero_dim } \right . \c_math_toggle_token } { #2 } { } } % \end{macrocode} % % \medskip % The command |\@@_node_right:nn| puts the right delimiter with the correct size. % The argument |#1| is the delimiter to put. The argument |#2| is the name we % will give to this PGF node (if the key |name| has been used in |\SubMatrix|). % The argument |#3| is the subscript and |#4| is the superscript. % \begin{macrocode} \cs_new_protected:Npn \@@_node_right:nnnn #1 #2 #3 #4 { \pgfnode { rectangle } { west } { \nullfont \c_math_toggle_token \@@_color:o \l_@@_delimiters_color_tl \left . \vcenter { \nullfont \hrule \@height \l_tmpa_dim \@depth \c_zero_dim \@width \c_zero_dim } \right #1 \tl_if_empty:nF { #3 } { _ { \smash { #3 } } } ^ { \smash { #4 } } \c_math_toggle_token } { #2 } { } } % \end{macrocode} % % % \bigskip % \section{Les commandes \textbackslash UnderBrace et \textbackslash % OverBrace} % % The following commands will be linked to |\UnderBrace| and |\OverBrace| in the % |\CodeAfter|. % % \begin{macrocode} \NewDocumentCommand \@@_UnderBrace { O { } m m m O { } } { \peek_remove_spaces:n { \@@_brace:nnnnn { #2 } { #3 } { #4 } { #1 , #5 } { under } } } % \end{macrocode} % % \begin{macrocode} \NewDocumentCommand \@@_OverBrace { O { } m m m O { } } { \peek_remove_spaces:n { \@@_brace:nnnnn { #2 } { #3 } { #4 } { #1 , #5 } { over } } } % \end{macrocode} % % \medskip % \begin{macrocode} \keys_define:nn { NiceMatrix / Brace } { left-shorten .bool_set:N = \l_@@_brace_left_shorten_bool , left-shorten .default:n = true , right-shorten .bool_set:N = \l_@@_brace_right_shorten_bool , shorten .meta:n = { left-shorten , right-shorten } , right-shorten .default:n = true , yshift .dim_set:N = \l_@@_brace_yshift_dim , yshift .value_required:n = true , yshift .initial:n = \c_zero_dim , color .tl_set:N = \l_tmpa_tl , color .value_required:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~Brace } } % \end{macrocode} % % \medskip % |#1| is the first cell of the rectangle (with the syntax $i$\verb+-|+$j$; % |#2| is the last cell of the rectangle; % |#3| is the label of the text; % |#4| is the optional argument (a list of \textsl{key}-\textsl{value} pairs); % |#5| is equal to |under| or |over|. % \begin{macrocode} \cs_new_protected:Npn \@@_brace:nnnnn #1 #2 #3 #4 #5 { \group_begin: % \end{macrocode} % The four following token lists correspond to the position of the sub-matrix to % which a brace will be attached. % \begin{macrocode} \@@_compute_i_j:nn { #1 } { #2 } \bool_lazy_or:nnTF { \int_compare_p:nNn \l_@@_last_i_tl > \g_@@_row_total_int } { \int_compare_p:nNn \l_@@_last_j_tl > \g_@@_col_total_int } { \str_if_eq:nnTF { #5 } { under } { \@@_error:nn { Construct~too~large } { \UnderBrace } } { \@@_error:nn { Construct~too~large } { \OverBrace } } } { \tl_clear:N \l_tmpa_tl \keys_set:nn { NiceMatrix / Brace } { #4 } \tl_if_empty:NF \l_tmpa_tl { \color { \l_tmpa_tl } } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \bool_if:NT \l_@@_brace_left_shorten_bool { \dim_set_eq:NN \l_@@_x_initial_dim \c_max_dim \int_step_inline:nnn \l_@@_first_i_tl \l_@@_last_i_tl { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - ##1 - \l_@@_first_j_tl } { \pgfpointanchor { \@@_env: - ##1 - \l_@@_first_j_tl } { west } \dim_set:Nn \l_@@_x_initial_dim { \dim_min:nn \l_@@_x_initial_dim \pgf@x } } } } \bool_lazy_or:nnT { \bool_not_p:n \l_@@_brace_left_shorten_bool } { \dim_compare_p:nNn \l_@@_x_initial_dim = \c_max_dim } { \@@_qpoint:n { col - \l_@@_first_j_tl } \dim_set_eq:NN \l_@@_x_initial_dim \pgf@x } \bool_if:NT \l_@@_brace_right_shorten_bool { \dim_set:Nn \l_@@_x_final_dim { - \c_max_dim } \int_step_inline:nnn \l_@@_first_i_tl \l_@@_last_i_tl { \cs_if_exist:cT { pgf @ sh @ ns @ \@@_env: - ##1 - \l_@@_last_j_tl } { \pgfpointanchor { \@@_env: - ##1 - \l_@@_last_j_tl } { east } \dim_set:Nn \l_@@_x_final_dim { \dim_max:nn \l_@@_x_final_dim \pgf@x } } } } \bool_lazy_or:nnT { \bool_not_p:n \l_@@_brace_right_shorten_bool } { \dim_compare_p:nNn \l_@@_x_final_dim = { - \c_max_dim } } { \@@_qpoint:n { col - \int_eval:n { \l_@@_last_j_tl + 1 } } \dim_set_eq:NN \l_@@_x_final_dim \pgf@x } \pgfset { inner~sep = \c_zero_dim } \str_if_eq:nnTF { #5 } { under } { \@@_underbrace_i:n { #3 } } { \@@_overbrace_i:n { #3 } } \endpgfpicture } \group_end: } % \end{macrocode} % % \medskip % The argument is the text to put above the brace. % \begin{macrocode} \cs_new_protected:Npn \@@_overbrace_i:n #1 { \@@_qpoint:n { row - \l_@@_first_i_tl } \pgftransformshift { \pgfpoint { ( \l_@@_x_initial_dim + \l_@@_x_final_dim) / 2 } { \pgf@y + \l_@@_brace_yshift_dim - 3 pt} } \pgfnode { rectangle } { south } { \vtop { \group_begin: \everycr { } \halign { \hfil ## \hfil \crcr \@@_math_toggle: #1 \@@_math_toggle: \cr \noalign { \skip_vertical:n { 3 pt } \nointerlineskip } \c_math_toggle_token \overbrace { \hbox_to_wd:nn { \l_@@_x_final_dim - \l_@@_x_initial_dim } { } } \c_math_toggle_token \cr } \group_end: } } { } { } } % \end{macrocode} % % % \medskip % The argument is the text to put under the brace. % \begin{macrocode} \cs_new_protected:Npn \@@_underbrace_i:n #1 { \@@_qpoint:n { row - \int_eval:n { \l_@@_last_i_tl + 1 } } \pgftransformshift { \pgfpoint { ( \l_@@_x_initial_dim + \l_@@_x_final_dim) / 2 } { \pgf@y - \l_@@_brace_yshift_dim + 3 pt } } \pgfnode { rectangle } { north } { \group_begin: \everycr { } \vbox { \halign { \hfil ## \hfil \crcr \c_math_toggle_token \underbrace { \hbox_to_wd:nn { \l_@@_x_final_dim - \l_@@_x_initial_dim } { } } \c_math_toggle_token \cr \noalign { \skip_vertical:n { 3 pt } \nointerlineskip } \@@_math_toggle: #1 \@@_math_toggle: \cr } } \group_end: } { } { } } % \end{macrocode} % % \bigskip % \section{The command TikzEveryCell} % % \begin{macrocode} \bool_new:N \l_@@_not_empty_bool \bool_new:N \l_@@_empty_bool \keys_define:nn { NiceMatrix / TikzEveryCell } { not-empty .code:n = \bool_lazy_or:nnTF \l_@@_in_code_after_bool \g_@@_recreate_cell_nodes_bool { \bool_set_true:N \l_@@_not_empty_bool } { \@@_error:n { detection~of~empty~cells } } , not-empty .value_forbidden:n = true , empty .code:n = \bool_lazy_or:nnTF \l_@@_in_code_after_bool \g_@@_recreate_cell_nodes_bool { \bool_set_true:N \l_@@_empty_bool } { \@@_error:n { detection~of~empty~cells } } , empty .value_forbidden:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~TikzEveryCell } } \NewDocumentCommand { \@@_TikzEveryCell } { O { } m } { \IfPackageLoadedTF { tikz } { \group_begin: \keys_set:nn { NiceMatrix / TikzEveryCell } { #1 } % \end{macrocode} % The inner pair of braces in the following line is mandatory because, the last % argument of |\@@_tikz:nnnnn| is \emph{a list of lists} of TikZ keys. % \begin{macrocode} \tl_set:Nn \l_tmpa_tl { { #2 } } \seq_map_inline:Nn \g_@@_pos_of_blocks_seq { \@@_for_a_block:nnnnn ##1 } \@@_all_the_cells: \group_end: } { \@@_error:n { TikzEveryCell~without~tikz } } } \tl_new:N \@@_i_tl \tl_new:N \@@_j_tl \cs_new_protected:Nn \@@_all_the_cells: { \int_step_variable:nNn { \int_use:c { c@iRow } } \@@_i_tl { \int_step_variable:nNn { \int_use:c { c@jCol } } \@@_j_tl { \cs_if_exist:cF { cell - \@@_i_tl - \@@_j_tl } { \exp_args:NNe \seq_if_in:NnF \l_@@_corners_cells_seq { \@@_i_tl - \@@_j_tl } { \bool_set_false:N \l_tmpa_bool \cs_if_exist:cTF { pgf @ sh @ ns @ \@@_env: - \@@_i_tl - \@@_j_tl } { \bool_if:NF \l_@@_empty_bool { \bool_set_true:N \l_tmpa_bool } } { \bool_if:NF \l_@@_not_empty_bool { \bool_set_true:N \l_tmpa_bool } } \bool_if:NT \l_tmpa_bool { \@@_block_tikz:nnnnV \@@_i_tl \@@_j_tl \@@_i_tl \@@_j_tl \l_tmpa_tl } } } } } } \cs_new_protected:Nn \@@_for_a_block:nnnnn { \bool_if:NF \l_@@_empty_bool { \@@_block_tikz:nnnnV { #1 } { #2 } { #3 } { #4 } \l_tmpa_tl } \@@_mark_cells_of_block:nnnn { #1 } { #2 } { #3 } { #4 } } \cs_new_protected:Nn \@@_mark_cells_of_block:nnnn { \int_step_inline:nnn { #1 } { #3 } { \int_step_inline:nnn { #2 } { #4 } { \cs_set:cpn { cell - ##1 - ####1 } { } } } } % \end{macrocode} % % % \bigskip % \section{The command \textbackslash ShowCellNames} % % \begin{macrocode} \NewDocumentCommand \@@_ShowCellNames_CodeBefore { } { \dim_zero_new:N \g_@@_tmpc_dim \dim_zero_new:N \g_@@_tmpd_dim \dim_zero_new:N \g_@@_tmpe_dim \int_step_inline:nn \c@iRow { \begin { pgfpicture } \@@_qpoint:n { row - ##1 } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint:n { row - \int_eval:n { ##1 + 1 } } \dim_gset:Nn \g_tmpa_dim { ( \l_tmpa_dim + \pgf@y ) / 2 } \dim_gset:Nn \g_tmpb_dim { \l_tmpa_dim - \pgf@y } \bool_if:NTF \l_@@_in_code_after_bool \end { pgfpicture } \int_step_inline:nn \c@jCol { \hbox_set:Nn \l_tmpa_box { \normalfont \Large \color { red ! 50 } ##1 - ####1 } \begin { pgfpicture } \@@_qpoint:n { col - ####1 } \dim_gset_eq:NN \g_@@_tmpc_dim \pgf@x \@@_qpoint:n { col - \int_eval:n { ####1 + 1 } } \dim_gset:Nn \g_@@_tmpd_dim { \pgf@x - \g_@@_tmpc_dim } \dim_gset_eq:NN \g_@@_tmpe_dim \pgf@x \endpgfpicture \end { pgfpicture } \fp_set:Nn \l_tmpa_fp { \fp_min:nn { \fp_min:nn { \dim_ratio:nn { \g_@@_tmpd_dim } { \box_wd:N \l_tmpa_box } } { \dim_ratio:nn { \g_tmpb_dim } { \box_ht_plus_dp:N \l_tmpa_box } } } { 1.0 } } \box_scale:Nnn \l_tmpa_box { \fp_use:N \l_tmpa_fp } { \fp_use:N \l_tmpa_fp } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \pgftransformshift { \pgfpoint { 0.5 * ( \g_@@_tmpc_dim + \g_@@_tmpe_dim ) } { \dim_use:N \g_tmpa_dim } } \pgfnode { rectangle } { center } { \box_use:N \l_tmpa_box } { } { } \endpgfpicture } } } % \end{macrocode} % % \begin{macrocode} \NewDocumentCommand \@@_ShowCellNames { } { \bool_if:NT \l_@@_in_code_after_bool { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \pgfpathrectanglecorners { \@@_qpoint:n { 1 } } { \@@_qpoint:n { \int_eval:n { \int_max:nn \c@iRow \c@jCol + 1 } } } \pgfsetfillopacity { 0.75 } \pgfsetfillcolor { white } \pgfusepathqfill \endpgfpicture } \dim_zero_new:N \g_@@_tmpc_dim \dim_zero_new:N \g_@@_tmpd_dim \dim_zero_new:N \g_@@_tmpe_dim \int_step_inline:nn \c@iRow { \bool_if:NTF \l_@@_in_code_after_bool { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse } { \begin { pgfpicture } } \@@_qpoint:n { row - ##1 } \dim_set_eq:NN \l_tmpa_dim \pgf@y \@@_qpoint:n { row - \int_eval:n { ##1 + 1 } } \dim_gset:Nn \g_tmpa_dim { ( \l_tmpa_dim + \pgf@y ) / 2 } \dim_gset:Nn \g_tmpb_dim { \l_tmpa_dim - \pgf@y } \bool_if:NTF \l_@@_in_code_after_bool { \endpgfpicture } { \end { pgfpicture } } \int_step_inline:nn \c@jCol { \hbox_set:Nn \l_tmpa_box { \normalfont \Large \sffamily \bfseries \bool_if:NTF \l_@@_in_code_after_bool { \color { red } } { \color { red ! 50 } } ##1 - ####1 } \bool_if:NTF \l_@@_in_code_after_bool { \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse } { \begin { pgfpicture } } \@@_qpoint:n { col - ####1 } \dim_gset_eq:NN \g_@@_tmpc_dim \pgf@x \@@_qpoint:n { col - \int_eval:n { ####1 + 1 } } \dim_gset:Nn \g_@@_tmpd_dim { \pgf@x - \g_@@_tmpc_dim } \dim_gset_eq:NN \g_@@_tmpe_dim \pgf@x \bool_if:NTF \l_@@_in_code_after_bool { \endpgfpicture } { \end { pgfpicture } } \fp_set:Nn \l_tmpa_fp { \fp_min:nn { \fp_min:nn { \dim_ratio:nn \g_@@_tmpd_dim { \box_wd:N \l_tmpa_box } } { \dim_ratio:nn \g_tmpb_dim { \box_ht_plus_dp:N \l_tmpa_box } } } { 1.0 } } \box_scale:Nnn \l_tmpa_box { \fp_use:N \l_tmpa_fp } { \fp_use:N \l_tmpa_fp } \pgfpicture \pgfrememberpicturepositiononpagetrue \pgf@relevantforpicturesizefalse \pgftransformshift { \pgfpoint { 0.5 * ( \g_@@_tmpc_dim + \g_@@_tmpe_dim ) } { \dim_use:N \g_tmpa_dim } } \pgfnode { rectangle } { center } { \box_use:N \l_tmpa_box } { } { } \endpgfpicture } } } % \end{macrocode} % % \bigskip % \section{We process the options at package loading} % % % We process the options when the package is loaded (with |\usepackage|) but we % recommend to use |\NiceMatrixOptions| instead. % % We must process these options after the definition of the environment % |{NiceMatrix}| because the option |renew-matrix| executes the code % |\cs_set_eq:NN \env@matrix \NiceMatrix|. % % Of course, the command |\NiceMatrix| must be defined before such an % instruction is executed. % % % \medskip % The boolean |\g_@@_footnotehyper_bool| will indicate if the option % |footnotehyper| is used. % \begin{macrocode} \bool_new:N \g_@@_footnotehyper_bool % \end{macrocode} % % \medskip % The boolean |\g_@@_footnote_bool| will indicate if the option |footnote| is % used, but quicky, it will also be set to |true| if the option |footnotehyper| % is used. % \begin{macrocode} \bool_new:N \g_@@_footnote_bool % \end{macrocode} % % \begin{macrocode} \msg_new:nnnn { nicematrix } { Unknown~key~for~package } { The~key~'\l_keys_key_str'~is~unknown. \\ That~key~will~be~ignored. \\ For~a~list~of~the~available~keys,~type~H~. } { The~available~keys~are~(in~alphabetic~order):~ footnote,~ footnotehyper,~ messages-for-Overleaf,~ no-test-for-array,~ renew-dots,~and~ renew-matrix. } % \end{macrocode} % % % \begin{macrocode} \keys_define:nn { NiceMatrix / Package } { renew-dots .bool_set:N = \l_@@_renew_dots_bool , renew-dots .value_forbidden:n = true , renew-matrix .code:n = \@@_renew_matrix: , renew-matrix .value_forbidden:n = true , messages-for-Overleaf .bool_set:N = \g_@@_messages_for_Overleaf_bool , footnote .bool_set:N = \g_@@_footnote_bool , footnotehyper .bool_set:N = \g_@@_footnotehyper_bool , no-test-for-array .bool_set:N = \g_@@_no_test_for_array_bool , no-test-for-array .default:n = true , unknown .code:n = \@@_error:n { Unknown~key~for~package } } \ProcessKeysOptions { NiceMatrix / Package } % \end{macrocode} % % \bigskip % \begin{macrocode} \@@_msg_new:nn { footnote~with~footnotehyper~package } { You~can't~use~the~option~'footnote'~because~the~package~ footnotehyper~has~already~been~loaded.~ If~you~want,~you~can~use~the~option~'footnotehyper'~and~the~footnotes~ within~the~environments~of~nicematrix~will~be~extracted~with~the~tools~ of~the~package~footnotehyper.\\ The~package~footnote~won't~be~loaded. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { footnotehyper~with~footnote~package } { You~can't~use~the~option~'footnotehyper'~because~the~package~ footnote~has~already~been~loaded.~ If~you~want,~you~can~use~the~option~'footnote'~and~the~footnotes~ within~the~environments~of~nicematrix~will~be~extracted~with~the~tools~ of~the~package~footnote.\\ The~package~footnotehyper~won't~be~loaded. } % \end{macrocode} % % \medskip % \begin{macrocode} \bool_if:NT \g_@@_footnote_bool { % \end{macrocode} % The class \cls{beamer} has its own system to extract footnotes and that's why % we have nothing to do if \cls{beamer} is used. % \begin{macrocode} \IfClassLoadedTF { beamer } { \bool_set_false:N \g_@@_footnote_bool } { \IfPackageLoadedTF { footnotehyper } { \@@_error:n { footnote~with~footnotehyper~package } } { \usepackage { footnote } } } } % \end{macrocode} % % \begin{macrocode} \bool_if:NT \g_@@_footnotehyper_bool { % \end{macrocode} % The class \cls{beamer} has its own system to extract footnotes and that's why % we have nothing to do if \cls{beamer} is used. % \begin{macrocode} \IfClassLoadedTF { beamer } { \bool_set_false:N \g_@@_footnote_bool } { \IfPackageLoadedTF { footnote } { \@@_error:n { footnotehyper~with~footnote~package } } { \usepackage { footnotehyper } } } \bool_set_true:N \g_@@_footnote_bool } % \end{macrocode} % The flag |\g_@@_footnote_bool| is raised and so, we will only have to test % |\g_@@_footnote_bool| in order to know if we have to insert an environment % |{savenotes}|. % % \bigskip % \section{About the package underscore} % % If the user loads the package \pkg{underscore}, it must be loaded % \emph{before} the package \pkg{nicematrix}. If it is loaded after, we raise an % error. % % \begin{macrocode} \bool_new:N \l_@@_underscore_loaded_bool \IfPackageLoadedTF { underscore } { \bool_set_true:N \l_@@_underscore_loaded_bool } { } % \end{macrocode} % % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \bool_if:NF \l_@@_underscore_loaded_bool { \IfPackageLoadedTF { underscore } { \@@_error:n { underscore~after~nicematrix } } { } } } % \end{macrocode} % % \bigskip % \section{Error messages of the package} % % \begin{macrocode} \bool_if:NTF \g_@@_messages_for_Overleaf_bool { \str_const:Nn \c_@@_available_keys_str { } } { \str_const:Nn \c_@@_available_keys_str { For~a~list~of~the~available~keys,~type~H~. } } % \end{macrocode} % % \begin{macrocode} \seq_new:N \g_@@_types_of_matrix_seq \seq_gset_from_clist:Nn \g_@@_types_of_matrix_seq { NiceMatrix , pNiceMatrix , bNiceMatrix , vNiceMatrix, BNiceMatrix, VNiceMatrix } \seq_gset_map_x:NNn \g_@@_types_of_matrix_seq \g_@@_types_of_matrix_seq { \tl_to_str:n { #1 } } % \end{macrocode} % % \bigskip % If the user uses too much columns, the command |\@@_error_too_much_cols:| is % triggered. This command raises an error but also tries to give the best % information to the user in the error message. The command |\seq_if_in:NoTF| is % not expandable and that's why we can't put it in the error message itself. We % have to do the test before the |\@@_fatal:n|. % \begin{macrocode} \cs_new_protected:Npn \@@_error_too_much_cols: { \seq_if_in:NoTF \g_@@_types_of_matrix_seq \g_@@_name_env_str { \int_compare:nNnTF \l_@@_last_col_int = { -2 } { \@@_fatal:n { too~much~cols~for~matrix } } { \int_compare:nNnTF \l_@@_last_col_int = { -1 } { \@@_fatal:n { too~much~cols~for~matrix } } { \bool_if:NF \l_@@_last_col_without_value_bool { \@@_fatal:n { too~much~cols~for~matrix~with~last~col } } } } } { \@@_fatal:nn { too~much~cols~for~array } } } % \end{macrocode} % % % The following command must \emph{not} be protected since it's used in an error message. % \begin{macrocode} \cs_new:Npn \@@_message_hdotsfor: { \tl_if_empty:oF \g_@@_HVdotsfor_lines_tl { ~Maybe~your~use~of~\token_to_str:N \Hdotsfor\ is~incorrect.} } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { hvlines,~rounded-corners~and~corners } { Incompatible~options.\\ You~should~not~use~'hvlines',~'rounded-corners'~and~'corners'~at~this~time.\\ The~output~will~not~be~reliable. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { negative~weight } { Negative~weight.\\ The~weight~of~the~'X'~columns~must~be~positive~and~you~have~used~ the~value~'\int_use:N \l_@@_weight_int'.\\ The~absolute~value~will~be~used. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { last~col~not~used } { Column~not~used.\\ The~key~'last-col'~is~in~force~but~you~have~not~used~that~last~column~ in~your~\@@_full_name_env:.~However,~you~can~go~on. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { too~much~cols~for~matrix~with~last~col } { Too~much~columns.\\ In~the~row~\int_eval:n { \c@iRow },~ you~try~to~use~more~columns~ than~allowed~by~your~\@@_full_name_env:.\@@_message_hdotsfor:\ The~maximal~number~of~columns~is~\int_eval:n { \l_@@_last_col_int - 1 }~ (plus~the~exterior~columns).~This~error~is~fatal. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { too~much~cols~for~matrix } { Too~much~columns.\\ In~the~row~\int_eval:n { \c@iRow },~ you~try~to~use~more~columns~than~allowed~by~your~ \@@_full_name_env:.\@@_message_hdotsfor:\ Recall~that~the~maximal~ number~of~columns~for~a~matrix~(excepted~the~potential~exterior~ columns)~is~fixed~by~the~LaTeX~counter~'MaxMatrixCols'.~ Its~current~value~is~\int_use:N \c@MaxMatrixCols\ (use~ \token_to_str:N \setcounter\ to~change~that~value).~ This~error~is~fatal. } % \end{macrocode} % % \medskip % \begin{macrocode} \@@_msg_new:nn { too~much~cols~for~array } { Too~much~columns.\\ In~the~row~\int_eval:n { \c@iRow },~ ~you~try~to~use~more~columns~than~allowed~by~your~ \@@_full_name_env:.\@@_message_hdotsfor:\ The~maximal~number~of~columns~is~ \int_use:N \g_@@_static_num_of_col_int\ ~(plus~the~potential~exterior~ones). This~error~is~fatal. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { columns~not~used } { Columns~not~used.\\ The~preamble~of~your~\@@_full_name_env:\ announces~\int_use:N \g_@@_static_num_of_col_int\ columns~but~you~use~only~\int_use:N \c@jCol.\\ The~columns~you~did~not~used~won't~be~created.\\ You~won't~have~similar~error~till~the~end~of~the~document. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { in~first~col } { Erroneous~use.\\ You~can't~use~the~command~#1 in~the~first~column~(number~0)~of~the~array.\\ That~command~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { in~last~col } { Erroneous~use.\\ You~can't~use~the~command~#1 in~the~last~column~(exterior)~of~the~array.\\ That~command~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { in~first~row } { Erroneous~use.\\ You~can't~use~the~command~#1 in~the~first~row~(number~0)~of~the~array.\\ That~command~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { in~last~row } { You~can't~use~the~command~#1 in~the~last~row~(exterior)~of~the~array.\\ That~command~will~be~ignored. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { caption~outside~float } { Key~caption~forbidden.\\ You~can't~use~the~key~'caption'~because~you~are~not~in~a~floating~ environment.~This~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { short-caption~without~caption } { You~should~not~use~the~key~'short-caption'~without~'caption'.~ However,~your~'short-caption'~will~be~used~as~'caption'. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { double~closing~delimiter } { Double~delimiter.\\ You~can't~put~a~second~closing~delimiter~"#1"~just~after~a~first~closing~ delimiter.~This~delimiter~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { delimiter~after~opening } { Double~delimiter.\\ You~can't~put~a~second~delimiter~"#1"~just~after~a~first~opening~ delimiter.~That~delimiter~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { bad~option~for~line-style } { Bad~line~style.\\ Since~you~haven't~loaded~Tikz,~the~only~value~you~can~give~to~'line-style'~ is~'standard'.~That~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Identical~notes~in~caption } { Identical~tabular~notes.\\ You~can't~put~several~notes~with~the~same~content~in~ \token_to_str:N \caption\ (but~you~can~in~the~main~tabular).\\ If~you~go~on,~the~output~will~probably~be~erroneous. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { tabularnote~below~the~tabular } { \token_to_str:N \tabularnote\ forbidden\\ You~can't~use~\token_to_str:N \tabularnote\ in~the~caption~ of~your~tabular~because~the~caption~will~be~composed~below~ the~tabular.~If~you~want~the~caption~above~the~tabular~use~the~ key~'caption-above'~in~\token_to_str:N \NiceMatrixOptions.\\ Your~\token_to_str:N \tabularnote\ will~be~discarded~and~ no~similar~error~will~raised~in~this~document. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Unknown~key~for~rules } { Unknown~key.\\ There~is~only~two~keys~available~here:~width~and~color.\\ Your~key~'\l_keys_key_str'~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Unknown~key~for~TikzEveryCell } { Unknown~key.\\ There~is~only~two~keys~available~here:~ 'empty'~and~'not-empty'.\\ Your~key~'\l_keys_key_str'~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Unknown~key~for~rotate } { Unknown~key.\\ The~only~key~available~here~is~'c'.\\ Your~key~'\l_keys_key_str'~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~custom-line } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown~in~a~'custom-line'.~ It~you~go~on,~you~will~probably~have~other~errors. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ ccommand,~ color,~ command,~ dotted,~ letter,~ multiplicity,~ sep-color,~ tikz,~and~total-width. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~xdots } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown~for~a~command~for~drawing~dotted~rules.\\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ 'color',~ 'horizontal-labels',~ 'inter',~ 'line-style',~ 'radius',~ 'shorten',~ 'shorten-end'~and~'shorten-start'. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { Unknown~key~for~rowcolors } { Unknown~key.\\ As~for~now,~there~is~only~two~keys~available~here:~'cols'~and~'respect-blocks'~ (and~you~try~to~use~'\l_keys_key_str')\\ That~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { label~without~caption } { You~can't~use~the~key~'label'~in~your~'{NiceTabular}'~because~ you~have~not~used~the~key~'caption'.~The~key~'label'~will~be~ignored. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { W~warning } { Line~\msg_line_number:.~The~cell~is~too~wide~for~your~column~'W'~ (row~\int_use:N \c@iRow). } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Construct~too~large } { Construct~too~large.\\ Your~command~\token_to_str:N #1 can't~be~drawn~because~your~matrix~is~too~small.\\ That~command~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { underscore~after~nicematrix } { Problem~with~'underscore'.\\ The~package~'underscore'~should~be~loaded~before~'nicematrix'.~ You~can~go~on~but~you~won't~be~able~to~write~something~such~as:\\ '\token_to_str:N \Cdots\token_to_str:N _{n~\token_to_str:N \text{~times}}'. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { ampersand~in~light-syntax } { Ampersand~forbidden.\\ You~can't~use~an~ampersand~(\token_to_str:N &)~to~separate~columns~because~ ~the~key~'light-syntax'~is~in~force.~This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { double-backslash~in~light-syntax } { Double~backslash~forbidden.\\ You~can't~use~\token_to_str:N \\~to~separate~rows~because~the~key~'light-syntax'~ is~in~force.~You~must~use~the~character~'\l_@@_end_of_row_tl'~ (set~by~the~key~'end-of-row').~This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { hlines~with~color } { Incompatible~keys.\\ You~can't~use~the~keys~'hlines',~'vlines'~or~'hvlines'~for~a~ '\token_to_str:N \Block'~when~the~key~'color'~or~'draw'~is~used.\\ Maybe~it~will~possible~in~future~version.\\ Your~key~will~be~discarded. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { bad~value~for~baseline } { Bad~value~for~baseline.\\ The~value~given~to~'baseline'~(\int_use:N \l_tmpa_int)~is~not~ valid.~The~value~must~be~between~\int_use:N \l_@@_first_row_int\ and~ \int_use:N \g_@@_row_total_int\ or~equal~to~'t',~'c'~or~'b'~or~of~ the~form~'line-i'.\\ A~value~of~1~will~be~used. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { detection~of~empty~cells } { Problem~with~'not-empty'\\ For~technical~reasons,~you~must~activate~ 'create-cell-nodes'~in~\token_to_str:N \CodeBefore\ in~order~to~use~the~key~'\l_keys_key_str'.\\ That~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { siunitx~not~loaded } { siunitx~not~loaded\\ You~can't~use~the~columns~'S'~because~'siunitx'~is~not~loaded.\\ That~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { ragged2e~not~loaded } { You~have~to~load~'ragged2e'~in~order~to~use~the~key~'\l_keys_key_str'~in~ your~column~'\l_@@_vpos_col_str'~(or~'X').~The~key~'\str_lowercase:V \l_keys_key_str'~will~be~used~instead. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Invalid~name } { Invalid~name.\\ You~can't~give~the~name~'\l_keys_value_tl'~to~a~\token_to_str:N \SubMatrix\ of~your~\@@_full_name_env:.\\ A~name~must~be~accepted~by~the~regular~expression~[A-Za-z][A-Za-z0-9]*.\\ This~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Wrong~line~in~SubMatrix } { Wrong~line.\\ You~try~to~draw~a~#1~line~of~number~'#2'~in~a~ \token_to_str:N \SubMatrix\ of~your~\@@_full_name_env:\ but~that~ number~is~not~valid.~It~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Impossible~delimiter } { Impossible~delimiter.\\ It's~impossible~to~draw~the~#1~delimiter~of~your~ \token_to_str:N \SubMatrix\ because~all~the~cells~are~empty~ in~that~column. \bool_if:NT \l_@@_submatrix_slim_bool { ~Maybe~you~should~try~without~the~key~'slim'. } \\ This~\token_to_str:N \SubMatrix\ will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { width~without~X~columns } { You~have~used~the~key~'width'~but~you~have~put~no~'X'~column.~ That~key~will~be~ignored. } { This~message~is~the~message~'width~without~X~columns'~ of~the~module~'nicematrix'.~ The~experimented~users~can~disable~that~message~with~ \token_to_str:N \msg_redirect_name:nnn.\\ } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { key~multiplicity~with~dotted } { Incompatible~keys. \\ You~have~used~the~key~'multiplicity'~with~the~key~'dotted'~ in~a~'custom-line'.~They~are~incompatible. \\ The~key~'multiplicity'~will~be~discarded. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { empty~environment } { Empty~environment.\\ Your~\@@_full_name_env:\ is~empty.~This~error~is~fatal. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { No~letter~and~no~command } { Erroneous~use.\\ Your~use~of~'custom-line'~is~no-op~since~you~don't~have~used~the~ key~'letter'~(for~a~letter~for~vertical~rules)~nor~the~keys~'command'~or~ ~'ccommand'~(to~draw~horizontal~rules).\\ However,~you~can~go~on. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Forbidden~letter } { Forbidden~letter.\\ You~can't~use~the~letter~'#1'~for~a~customized~line.\\ It~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Several~letters } { Wrong~name.\\ You~must~use~only~one~letter~as~value~for~the~key~'letter'~(and~you~ have~used~'\l_@@_letter_str').\\ It~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Delimiter~with~small } { Delimiter~forbidden.\\ You~can't~put~a~delimiter~in~the~preamble~of~your~\@@_full_name_env:\ because~the~key~'small'~is~in~force.\\ This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { unknown~cell~for~line~in~CodeAfter } { Unknown~cell.\\ Your~command~\token_to_str:N\line\{#1\}\{#2\}~in~ the~\token_to_str:N \CodeAfter\ of~your~\@@_full_name_env:\ can't~be~executed~because~a~cell~doesn't~exist.\\ This~command~\token_to_str:N \line\ will~be~ignored. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nnn { Duplicate~name~for~SubMatrix } { Duplicate~name.\\ The~name~'#1'~is~already~used~for~a~\token_to_str:N \SubMatrix\ in~this~\@@_full_name_env:.\\ This~key~will~be~ignored.\\ \bool_if:NF \g_@@_messages_for_Overleaf_bool { For~a~list~of~the~names~already~used,~type~H~. } } { The~names~already~defined~in~this~\@@_full_name_env:\ are:~ \seq_use:Nnnn \g_@@_submatrix_names_seq { ~and~ } { ,~ } { ~and~ }. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { r~or~l~with~preamble } { Erroneous~use.\\ You~can't~use~the~key~'\l_keys_key_str'~in~your~\@@_full_name_env:.~ You~must~specify~the~alignment~of~your~columns~with~the~preamble~of~ your~\@@_full_name_env:.\\ This~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Hdotsfor~in~col~0 } { Erroneous~use.\\ You~can't~use~\token_to_str:N \Hdotsfor\ in~an~exterior~column~of~ the~array.~This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { bad~corner } { Bad~corner.\\ #1~is~an~incorrect~specification~for~a~corner~(in~the~key~ 'corners').~The~available~values~are:~NW,~SW,~NE~and~SE.\\ This~specification~of~corner~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { bad~border } { Bad~border.\\ \l_keys_key_str\space~is~an~incorrect~specification~for~a~border~ (in~the~key~'borders'~of~the~command~\token_to_str:N \Block).~ The~available~values~are:~left,~right,~top~and~bottom~(and~you~can~ also~use~the~key~'tikz' \IfPackageLoadedTF { tikz } { } {~if~you~load~the~LaTeX~package~'tikz'}).\\ This~specification~of~border~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { TikzEveryCell~without~tikz } { TikZ~not~loaded.\\ You~can't~use~\token_to_str:N \TikzEveryCell\ because~you~have~not~loaded~tikz.~ This~command~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { tikz~key~without~tikz } { TikZ~not~loaded.\\ You~can't~use~the~key~'tikz'~for~the~command~'\token_to_str:N \Block'~because~you~have~not~loaded~tikz.~ This~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { last-col~non~empty~for~NiceArray } { Erroneous~use.\\ In~the~\@@_full_name_env:,~you~must~use~the~key~ 'last-col'~without~value.\\ However,~you~can~go~on~for~this~time~ (the~value~'\l_keys_value_tl'~will~be~ignored). } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { last-col~non~empty~for~NiceMatrixOptions } { Erroneous~use.\\ In~\token_to_str:N \NiceMatrixOptions,~you~must~use~the~key~ 'last-col'~without~value.\\ However,~you~can~go~on~for~this~time~ (the~value~'\l_keys_value_tl'~will~be~ignored). } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { Block~too~large~1 } { Block~too~large.\\ You~try~to~draw~a~block~in~the~cell~#1-#2~of~your~matrix~but~the~matrix~is~ too~small~for~that~block. \\ This~block~and~maybe~others~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Block~too~large~2 } { Block~too~large.\\ The~preamble~of~your~\@@_full_name_env:\ announces~\int_use:N \g_@@_static_num_of_col_int\ columns~but~you~use~only~\int_use:N \c@jCol\ and~that's~why~a~block~ specified~in~the~cell~#1-#2~can't~be~drawn.~You~should~add~some~ampersands~ (&)~at~the~end~of~the~first~row~of~your~\@@_full_name_env:.\\ This~block~and~maybe~others~will~be~ignored. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { unknown~column~type } { Bad~column~type.\\ The~column~type~'#1'~in~your~\@@_full_name_env:\ is~unknown. \\ This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { unknown~column~type~S } { Bad~column~type.\\ The~column~type~'S'~in~your~\@@_full_name_env:\ is~unknown. \\ If~you~want~to~use~the~column~type~'S'~of~siunitx,~you~should~ load~that~package. \\ This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { tabularnote~forbidden } { Forbidden~command.\\ You~can't~use~the~command~\token_to_str:N\tabularnote\ ~here.~This~command~is~available~only~in~ \{NiceTabular\},~\{NiceTabular*\}~and~\{NiceTabularX\}~or~in~ the~argument~of~a~command~\token_to_str:N \caption\ included~ in~an~environment~{table}. \\ This~command~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { borders~forbidden } { Forbidden~key.\\ You~can't~use~the~key~'borders'~of~the~command~\token_to_str:N \Block\ because~the~option~'rounded-corners'~ is~in~force~with~a~non-zero~value.\\ This~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { bottomrule~without~booktabs } { booktabs~not~loaded.\\ You~can't~use~the~key~'tabular/bottomrule'~because~you~haven't~ loaded~'booktabs'.\\ This~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { enumitem~not~loaded } { enumitem~not~loaded.\\ You~can't~use~the~command~\token_to_str:N\tabularnote\ ~because~you~haven't~loaded~'enumitem'.\\ All~the~commands~\token_to_str:N\tabularnote\ will~be~ ignored~in~the~document. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { tikz~without~tikz } { Tikz~not~loaded.\\ You~can't~use~the~key~'tikz'~here~because~Tikz~is~not~ loaded.~If~you~go~on,~that~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { tikz~in~custom-line~without~tikz } { Tikz~not~loaded.\\ You~have~used~the~key~'tikz'~in~the~definition~of~a~ customized~line~(with~'custom-line')~but~tikz~is~not~loaded.~ You~can~go~on~but~you~will~have~another~error~if~you~actually~ use~that~custom~line. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { tikz~in~borders~without~tikz } { Tikz~not~loaded.\\ You~have~used~the~key~'tikz'~in~a~key~'borders'~(of~a~ command~'\token_to_str:N\Block')~but~tikz~is~not~loaded.~ That~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { without~color-inside } { If~order~to~use~\token_to_str:N \cellcolor,~\token_to_str:N \rowcolor,~ \token_to_str:N \rowcolors\ or~\token_to_str:N \rowlistcolors\ outside~\token_to_str:N \CodeBefore,~you~ should~have~used~the~key~'color-inside'~in~your~\@@_full_name_env:.\\ You~can~go~on~but~you~may~need~more~compilations. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { color~in~custom-line~with~tikz } { Erroneous~use.\\ In~a~'custom-line',~you~have~used~both~'tikz'~and~'color',~ which~is~forbidden~(you~should~use~'color'~inside~the~key~'tikz').~ The~key~'color'~will~be~discarded. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Wrong~last~row } { Wrong~number.\\ You~have~used~'last-row=\int_use:N \l_@@_last_row_int'~but~your~ \@@_full_name_env:\ seems~to~have~\int_use:N \c@iRow \ rows.~ If~you~go~on,~the~value~of~\int_use:N \c@iRow \ will~be~used~for~ last~row.~You~can~avoid~this~problem~by~using~'last-row'~ without~value~(more~compilations~might~be~necessary). } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nn { Yet~in~env } { Nested~environments.\\ Environments~of~nicematrix~can't~be~nested.\\ This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Outside~math~mode } { Outside~math~mode.\\ The~\@@_full_name_env:\ can~be~used~only~in~math~mode~ (and~not~in~\token_to_str:N \vcenter).\\ This~error~is~fatal. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { One~letter~allowed } { Bad~name.\\ The~value~of~key~'\l_keys_key_str'~must~be~of~length~1.\\ It~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { TabularNote~in~CodeAfter } { Environment~{TabularNote}~forbidden.\\ You~must~use~{TabularNote}~at~the~end~of~your~{NiceTabular}~ but~*before*~the~\token_to_str:N \CodeAfter.\\ This~environment~{TabularNote}~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { varwidth~not~loaded } { varwidth~not~loaded.\\ You~can't~use~the~column~type~'V'~because~'varwidth'~is~not~ loaded.\\ Your~column~will~behave~like~'p'. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknow~key~for~RulesBis } { Unkown~key.\\ Your~key~'\l_keys_key_str'~is~unknown~for~a~rule.\\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ color,~ dotted,~ multiplicity,~ sep-color,~ tikz,~and~total-width. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~Block } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown~for~the~command~\token_to_str:N \Block.\\ It~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~b,~B,~borders,~c,~draw,~fill,~ hlines,~hvlines,~l,~line-width,~name,~opacity,~rounded-corners,~r,~ respect-arraystretch,~t,~T,~tikz,~transparent~and~vlines. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~Brace } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown~for~the~commands~\token_to_str:N \UnderBrace\ and~\token_to_str:N \OverBrace.\\ It~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~color,~left-shorten,~ right-shorten,~shorten~(which~fixes~both~left-shorten~and~ right-shorten)~and~yshift. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~CodeAfter } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown.\\ It~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ delimiters/color,~ rules~(with~the~subkeys~'color'~and~'width'),~ sub-matrix~(several~subkeys)~ and~xdots~(several~subkeys).~ The~latter~is~for~the~command~\token_to_str:N \line. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~CodeBefore } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown.\\ It~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ create-cell-nodes,~ delimiters/color~and~ sub-matrix~(several~subkeys). } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~SubMatrix } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown.\\ That~key~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ 'delimiters/color',~ 'extra-height',~ 'hlines',~ 'hvlines',~ 'left-xshift',~ 'name',~ 'right-xshift',~ 'rules'~(with~the~subkeys~'color'~and~'width'),~ 'slim',~ 'vlines'~and~'xshift'~(which~sets~both~'left-xshift'~ and~'right-xshift').\\ } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~notes } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown.\\ That~key~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ bottomrule,~ code-after,~ code-before,~ detect-duplicates,~ enumitem-keys,~ enumitem-keys-para,~ para,~ label-in-list,~ label-in-tabular~and~ style. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~RowStyle } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown~for~the~command~ \token_to_str:N \RowStyle. \\ That~key~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ 'bold',~ 'cell-space-top-limit',~ 'cell-space-bottom-limit',~ 'cell-space-limits',~ 'color',~ 'nb-rows'~and~ 'rowcolor'. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~NiceMatrixOptions } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown~for~the~command~ \token_to_str:N \NiceMatrixOptions. \\ That~key~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ allow-duplicate-names,~ caption-above,~ cell-space-bottom-limit,~ cell-space-limits,~ cell-space-top-limit,~ code-for-first-col,~ code-for-first-row,~ code-for-last-col,~ code-for-last-row,~ corners,~ custom-key,~ create-extra-nodes,~ create-medium-nodes,~ create-large-nodes,~ delimiters~(several~subkeys),~ end-of-row,~ first-col,~ first-row,~ hlines,~ hvlines,~ hvlines-except-borders,~ last-col,~ last-row,~ left-margin,~ light-syntax,~ light-syntax-expanded,~ matrix/columns-type,~ no-cell-nodes,~ notes~(several~subkeys),~ nullify-dots,~ pgf-node-code,~ renew-dots,~ renew-matrix,~ respect-arraystretch,~ rounded-corners,~ right-margin,~ rules~(with~the~subkeys~'color'~and~'width'),~ small,~ sub-matrix~(several~subkeys),~ vlines,~ xdots~(several~subkeys). } % \end{macrocode} % % For `|{NiceArray}|`, the set of keys is the same as for |{NiceMatrix}| % excepted that there is no |l| and |r|. % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~NiceArray } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown~for~the~environment~ \{NiceArray\}. \\ That~key~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ b,~ baseline,~ c,~ cell-space-bottom-limit,~ cell-space-limits,~ cell-space-top-limit,~ code-after,~ code-for-first-col,~ code-for-first-row,~ code-for-last-col,~ code-for-last-row,~ color-inside,~ columns-width,~ corners,~ create-extra-nodes,~ create-medium-nodes,~ create-large-nodes,~ extra-left-margin,~ extra-right-margin,~ first-col,~ first-row,~ hlines,~ hvlines,~ hvlines-except-borders,~ last-col,~ last-row,~ left-margin,~ light-syntax,~ light-syntax-expanded,~ name,~ no-cell-nodes,~ nullify-dots,~ pgf-node-code,~ renew-dots,~ respect-arraystretch,~ right-margin,~ rounded-corners,~ rules~(with~the~subkeys~'color'~and~'width'),~ small,~ t,~ vlines,~ xdots/color,~ xdots/shorten-start,~ xdots/shorten-end,~ xdots/shorten~and~ xdots/line-style. } % \end{macrocode} % % \medskip % This error message is used for the set of keys |NiceMatrix/NiceMatrix| and % |NiceMatrix/pNiceArray| (but not by |NiceMatrix/NiceArray| because, for this % set of keys, there is no |l| and |r|). % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~NiceMatrix } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown~for~the~ \@@_full_name_env:. \\ That~key~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ b,~ baseline,~ c,~ cell-space-bottom-limit,~ cell-space-limits,~ cell-space-top-limit,~ code-after,~ code-for-first-col,~ code-for-first-row,~ code-for-last-col,~ code-for-last-row,~ color-inside,~ columns-type,~ columns-width,~ corners,~ create-extra-nodes,~ create-medium-nodes,~ create-large-nodes,~ extra-left-margin,~ extra-right-margin,~ first-col,~ first-row,~ hlines,~ hvlines,~ hvlines-except-borders,~ l,~ last-col,~ last-row,~ left-margin,~ light-syntax,~ light-syntax-expanded,~ name,~ no-cell-nodes,~ nullify-dots,~ pgf-node-code,~ r,~ renew-dots,~ respect-arraystretch,~ right-margin,~ rounded-corners,~ rules~(with~the~subkeys~'color'~and~'width'),~ small,~ t,~ vlines,~ xdots/color,~ xdots/shorten-start,~ xdots/shorten-end,~ xdots/shorten~and~ xdots/line-style. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nnn { Unknown~key~for~NiceTabular } { Unknown~key.\\ The~key~'\l_keys_key_str'~is~unknown~for~the~environment~ \{NiceTabular\}. \\ That~key~will~be~ignored. \\ \c_@@_available_keys_str } { The~available~keys~are~(in~alphabetic~order):~ b,~ baseline,~ c,~ caption,~ cell-space-bottom-limit,~ cell-space-limits,~ cell-space-top-limit,~ code-after,~ code-for-first-col,~ code-for-first-row,~ code-for-last-col,~ code-for-last-row,~ color-inside,~ columns-width,~ corners,~ custom-line,~ create-extra-nodes,~ create-medium-nodes,~ create-large-nodes,~ extra-left-margin,~ extra-right-margin,~ first-col,~ first-row,~ hlines,~ hvlines,~ hvlines-except-borders,~ label,~ last-col,~ last-row,~ left-margin,~ light-syntax,~ light-syntax-expanded,~ name,~ no-cell-nodes,~ notes~(several~subkeys),~ nullify-dots,~ pgf-node-code,~ renew-dots,~ respect-arraystretch,~ right-margin,~ rounded-corners,~ rules~(with~the~subkeys~'color'~and~'width'),~ short-caption,~ t,~ tabularnote,~ vlines,~ xdots/color,~ xdots/shorten-start,~ xdots/shorten-end,~ xdots/shorten~and~ xdots/line-style. } % \end{macrocode} % % % \begin{macrocode} \@@_msg_new:nnn { Duplicate~name } { Duplicate~name.\\ The~name~'\l_keys_value_tl'~is~already~used~and~you~shouldn't~use~ the~same~environment~name~twice.~You~can~go~on,~but,~ maybe,~you~will~have~incorrect~results~especially~ if~you~use~'columns-width=auto'.~If~you~don't~want~to~see~this~ message~again,~use~the~key~'allow-duplicate-names'~in~ '\token_to_str:N \NiceMatrixOptions'.\\ \bool_if:NF \g_@@_messages_for_Overleaf_bool { For~a~list~of~the~names~already~used,~type~H~. } } { The~names~already~defined~in~this~document~are:~ \seq_use:Nnnn \g_@@_names_seq { ~and~ } { ,~ } { ~and~ }. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Option~auto~for~columns-width } { Erroneous~use.\\ You~can't~give~the~value~'auto'~to~the~key~'columns-width'~here.~ That~key~will~be~ignored. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { NiceTabularX~without~X } { NiceTabularX~without~X.\\ You~should~not~use~{NiceTabularX}~without~X~columns.\\ However,~you~can~go~on. } % \end{macrocode} % % \begin{macrocode} \@@_msg_new:nn { Preamble~forgotten } { Preamble~forgotten.\\ You~have~probably~forgotten~the~preamble~of~your~ \@@_full_name_env:. \\ This~error~is~fatal. } % \end{macrocode} % % \newpage % \tableofcontents % % \endinput % Local Variables: % TeX-fold-mode: t % TeX-fold-preserve-comments: nil % fill-column: 80 % End: