% \iffalse meta-comment % % Copyright (C) 2025 by Julien Labbé % % This file may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this license or % (at your option) any later version. The latest version of this license is in % the file https://www.latex-project.org/lppl.txt % % \fi % % \iffalse % %\NeedsTeXFormat{LaTeX2e} %\ProvidesExplPackage{bracealign}{2025/04/17}{v1.0}{Align underbraces and overbraces} % %<*driver> \documentclass[nohyperref]{ltxdoc} \usepackage{bracealign-doc} %^^A defined at end of this file, with guard \usepackage{bracealign} \usepackage{mathtools} \EnableCrossrefs \PageIndex % \CodelineIndex \RecordChanges % \OnlyDescription \begin{document} \DocInput{bracealign.dtx} \PrintIndex \PrintChanges \end{document} % % \fi % % \changes{v1.0}{2025/04/17}{Initial version.} % % \GetFileInfo{\jobname.sty} % % \title{The \pkg{bracealign} package\thanks{This document corresponds to % \pkg{bracealign}~\fileversion, dated \filedate.}} % \author{Julien Labb\'e \\ {\small \url{https://github.com/julienlabbe/latex-packages}}} % % \maketitle % % \begin{abstract} % A \LaTeX{} package to align braces under and over math expressions. A new % environment called \refEnv{bracealign} is provided, inside which braces and % brackets drawn with the commands \cs{underbrace}, \cs{overbrace}, % \cs{underbracket}, \cs{overbracket}, \cs{underparen} or \cs{overparen} are % vertically aligned. The package also allows adding support for new commands. % % \bigskip % % Example: % \iffalse %<*example> % \fi \begin{dispExample} \[ \rho c \frac{\partial T}{\partial t} = \begin{bracealign} \underbrace{ \begin{bracealign} \underbrace{ - \lambda \frac{\partial^2 T}{\partial x^2} }_{\text{diffusion}} - \underbrace{ \mu (T^4 - {T_0}^4) }_{\substack{\text{radiative loss}}} \end{bracealign} }_{\text{heat transferts}} + \underbrace{ \sum_{i=1}^{n} \dot{q}_i }_{\substack{\text{heat}\\{\text{sources}}}} \end{bracealign} \] \end{dispExample} % \iffalse % % \fi % % \end{abstract} % % \clearpage % % \tableofcontents{} % % \clearpage % % \section{Introduction} % % The \pkg{bracealign} package provides the environment \refEnv{bracealign} % inside which brace-like commands are vertically aligned. Supported brace-like % commands are: % \begin{center} % \begin{tabular}{lll} % \cs{underbrace} & % \cs{underbracket} & % \cs{underparen} \\ % \cs{overbrace} & % \cs{overbracket} & % \cs{overparen} % \end{tabular} % \end{center} % \cs{underbrace} and \cs{overbrace} are standard \LaTeX{} commands. % The commands \cs{underbracket} and \cs{overbracket} are defined, for example, % by the packages: \pkg{unicode-math}, \pkg{mathtools}, \pkg{stix2} or % \pkg{libertinus}; the commands \cs{underparen} and \cs{overparen} by: % \pkg{unicode-math}, \pkg{stix2} or \pkg{libertinus}. The support for new % commands can be added by the user. % % Inside the \refEnv{bracealign} environment, the content of brace-like commands % is grabbed and appended inside all same braces with a \cs{vphantom} macro to % generate the braces alignment. Note that this prohibits the use of optional % arguments for the commands (see \emph{Known issue}, section~\ref{sec:issue-command-with-optionnal-arguments}, page~\pageref{sec:issue-command-with-optionnal-arguments}). % % \medskip % % This package originates in an answer on the TeX -- LaTeX Stack % Exchange network\footnote{\url{https://tex.stackexchange.com/a/740290}.}. % % \section{User interface} % \label{sec:user-interface} % % \newcommand{\smallcontent}{\textcolor{cyan}{\rule[-3pt]{1cm}{6pt}}} % \newcommand{\medcontent} {\textcolor{cyan}{\rule[-6pt]{1.2cm}{12pt}}} % \newcommand{\bigcontent} {\textcolor{cyan}{\rule[-12pt]{2cm}{24pt}}} % \newcommand{\hugecontent} {\textcolor{cyan}{\rule[-18pt]{2.5cm}{36pt}}} % % The examples given in this section use the following commands: % \iffalse %<*example> % \fi \begin{dispListing} \newcommand{\smallcontent}{\textcolor{cyan}{\rule[-3pt]{1cm}{6pt}}} \newcommand{\medcontent} {\textcolor{cyan}{\rule[-6pt]{1.2cm}{12pt}}} \newcommand{\bigcontent} {\textcolor{cyan}{\rule[-12pt]{2cm}{24pt}}} \newcommand{\hugecontent} {\textcolor{cyan}{\rule[-18pt]{2.5cm}{36pt}}} \end{dispListing} % \iffalse % % \fi % \noindent The \pkg{xcolor} package is also required (for the command % \cs{textcolor}), as loading the \pkg{amsmath} package (for the command % \cs{text}) and a package that defines \cs{underbracket} (such as % \pkg{mathtools}). % % \subsection{Environment} % % \begin{docEnvironment}{bracealign}{ \oarg{options list} } % Vertically aligns the brace-like commands in \meta{environment content}. % Each command is aligned separately (note that commands that uses % internally a brace-like command are also aligned). \refEnv{bracealign} % environments can be nested. % % The keys described in section~\ref{sec:keys}, can be used in \meta{options list} to % activate, or deactivate, the alignment of each braces. % %\clearpage % % \noindent\vspace{-\baselineskip} % % \marginpar{\hfill % \parbox[t]{0.88\linewidth}{\vspace*{1cm}\raggedright % Separate alignment of brace-like commands % } % } % \iffalse %<*example> % \fi \begin{dispExample} \[ \begin{bracealign} \underbrace{\medcontent}_{1} ~+~ \underbracket{\smallcontent}_{A} ~=~ \underbrace{\hugecontent}_{2} ~+~ \underbracket{\bigcontent}_{B} ~+~ \underbrace{\smallcontent}_{3} \end{bracealign} \] \end{dispExample} % \iffalse % % \fi % % \vfill % % \marginpar{\hfill % \parbox[t]{0.88\linewidth}{\vspace*{1cm}\raggedright % Nested \refEnv*{bracealign} environments % } % } % \iffalse %<*example> % \fi \begin{dispExample} \[ \begin{bracealign} \underbrace{ \begin{bracealign} \underbrace{\medcontent}_{1} ~+~ \underbrace{\smallcontent}_{2} \end{bracealign} }_{\text{nested}} ~=~ \underbrace{\hugecontent}_{3} ~+~ \underbrace{\bigcontent}_{4} ~+~ \underbrace{\smallcontent}_{5} \end{bracealign} \] \end{dispExample} % \iffalse % % \fi % %\vfill % % \marginpar{\hfill % \parbox[t]{0.88\linewidth}{\vspace*{1cm}\raggedright % Using internally a brace-like command % % \bigskip % % \itshape\footnotesize Note: the {\normalfont \cs{ubrace}} command has been % suggested by Enrico Gregorio to fix the syntax and spacing issues of % \cs{underbrace} (see {\normalfont % \url{https://tex.stackexchange.com/a/728627/}}). % } % } % \iffalse %<*example> % \fi \begin{dispExample} \newcommand{\ubrace}[2]{{\underbrace{#1}_{#2}}} \[ \begin{bracealign} \ubrace{\medcontent}{1} ~+~ \underbrace{\smallcontent}_{A} ~=~ \ubrace{\hugecontent}{2} ~+~ \underbrace{\bigcontent}_{B} ~+~ \ubrace{\smallcontent}{3} \end{bracealign} \] \end{dispExample} % \iffalse % % \fi % % \clearpage % % \end{docEnvironment} % % \subsection{Command} % %\begin{docCommand}{bracealignsetup}{ \marg{options list} } % Sets options for every \refEnv{bracealign} environments. All keys described % in the section~\ref{sec:keys} can be used in \meta{options list}. % % This is equivalent to \cs{SetKeys} |[bracealign]| \marg{options list}. % % \iffalse %<*example> % \fi \begin{dispExample} \bracealignsetup{underbracket=false} \[ \begin{bracealign} \underbrace{\medcontent}_{1} ~+~ \underbracket{\smallcontent}_{A} ~=~ \underbrace{\hugecontent}_{2} ~+~ \underbracket{\bigcontent}_{B} ~+~ \underbrace{\smallcontent}_{3} \end{bracealign} \] \end{dispExample} % \iffalse % % \fi % \end{docCommand} % % \subsection{Keys} % \label{sec:keys} % % \begin{docKeys}[ % doc keypath = bracealign, % doc parameter = {=true\textbar{}false} % ] % { % { % doc name = {overbrace}, % doc description = {default |true|, initially |true|}, % }, % { % doc name = {nooverbrace}, % doc description = {default |true|, inverse of |overbrace|}, % }, % } % \end{docKeys} % \begin{docKeys}[ % doc keypath = bracealign, % doc parameter = {=true\textbar{}false} % ] % { % { % doc name = {underbrace}, % doc description = {default |true|, initially |true|}, % }, % { % doc name = {nounderbrace}, % doc description = {default |true|, inverse of |underbrace|}, % }, % } % \end{docKeys} % \begin{docKeys}[ % doc keypath = bracealign, % doc parameter = {=true\textbar{}false} % ] % { % { % doc name = {overbracket}, % doc description = {default |true|, initially |true|}, % }, % { % doc name = {nooverbracket}, % doc description = {default |true|, inverse of |overbracket|}, % }, % } % \end{docKeys} % \begin{docKeys}[ % doc keypath = bracealign, % doc parameter = {=true\textbar{}false} % ] % { % { % doc name = {underbracket}, % doc description = {default |true|, initially |true|}, % }, % { % doc name = {nounderbracket}, % doc description = {default |true|, inverse of |underbracket|}, % }, % } % \end{docKeys} % \begin{docKeys}[ % doc keypath = bracealign, % doc parameter = {=true\textbar{}false} % ] % { % { % doc name = {overparen}, % doc description = {default |true|, initially |true|}, % }, % { % doc name = {nooverparen}, % doc description = {default |true|, inverse of |overparen|}, % }, % } % \end{docKeys} % \begin{docKeys}[ % doc keypath = bracealign, % doc parameter = {=true\textbar{}false} % ] % { % { % doc name = {underparen}, % doc description = {default |true|, initially |true|}, % }, % { % doc name = {nounderparen}, % doc description = {default |true|, inverse of |underparen|}, % }, % } % Activates, or deactivates, the alignment of the corresponding brace-like % command. These boolean keys are defined when the package \pkg{bracealign} % is loaded, whether the commands are defined or not (as they can be defined % later). % % \iffalse %<*example> % \fi \begin{dispExample} \[ \begin{bracealign}[underbrace=false] \underbrace{\medcontent}_{1} ~+~ \underbracket{\smallcontent}_{A} ~=~ \underbrace{\hugecontent}_{2} ~+~ \underbracket{\bigcontent}_{B} ~+~ \underbrace{\smallcontent}_{3} \end{bracealign} \] \end{dispExample} % \iffalse % % \fi % \end{docKeys} % % \begin{docKeys}[ % doc keypath = bracealign, % ] % { % { % doc name = {add-brace}, % doc parameter = {=\textbackslash\meta{command} } % }, % { % doc name = {add-braces}, % doc parameter = {=\marg{commands list}} % } % } % \refKey{/bracealign/add-brace} adds the support for the new brace-like % command % |\|\meta{command}. This also defines the keys \meta{command} % and |no|\meta{command} to activate or deactivate the alignment of % |\|\meta{command} braces. % % \refKey{/bracealign/add-braces} adds the support for multiple brace-like % commands, given as a comma separated list of commands. % % \iffalse %<*example> % \fi \begin{dispExample} \newcommand*{\mybrace}[1]{\mathop{\overleftrightarrow{#1}}\limits} \bracealignsetup{add-brace=\mybrace} \[ \begin{bracealign} \mybrace{ \begin{bracealign}[mybrace=false] \mybrace{\medcontent}^{1} ~+~ \mybrace{\smallcontent}^{2} \end{bracealign} }^{\text{nested}} ~=~ \mybrace{\hugecontent}^{3} ~+~ \mybrace{\bigcontent}^{4} ~+~ \mybrace{\smallcontent}^{5} \end{bracealign} \] \end{dispExample} % \iffalse % % \fi % \end{docKeys} % % \begin{docKey}[bracealign][before lower=\bigskip\par]{default-braces} % {=\marg{commands list}} % {no default, initially |\{\cs{underbrace}, \cs{overbrace},\par % \cs{underbracket}, \cs{overbracket},\par \cs{underparen}, \cs{overparen}\}|} % Sets the list of brace-like commands that must be supported by % \refEnv{bracealign}. At the beginning of the document (through the % |begindocument| hook) the existence of each command is tested and, if the test % sucesses, the command is passed to \refKey{/bracealign/add-brace}. % \end{docKey} % % \section{Complements} % % \subsection{Known issue: Commands with optional arguments} % \label{sec:issue-command-with-optionnal-arguments} % % The brace-like commands are expected to have only one mandatory argument (this % argument is grabbed and used to align the braces). In particular, if a command % handles optional arguments (such as the commands % \cs{underbracket} and \cs{overbracket} as defined by the \pkg{mathtools} % package), these optional arguments can't be used inside the % \refEnv{bracealign} environment. % % \subsection{Changelog} % % \begin{description} % \item[v1.0] Initial version. % \end{description} % % \MaybeStop{} % % \section{Implementation} % %\iffalse %<*package> %\fi % \setlength{\parindent}{0em} % \setlength{\parskip}{\smallskipamount} % % \iffalse ^^A Not in doc to get the right line numbering % Internal prefix for \pkg{DocStrip}. % \begin{macrocode} %<@@=bracealign> % \end{macrocode} % \fi % % \subsection{Adding brace command} % % The sequence that store the brace-like commands. % \begin{macrocode} \seq_new:N \l_bracealign_brace_seq % \end{macrocode} % % \begin{macro}{\bracealign_add_brace:n} % \begin{macro}{\bracealign_add_brace:e} % \begin{macro}{\bracealign_add_brace:N} % Add the brace command |#1|. % \begin{macrocode} \msg_new:nnn { bracealign } { already-added-brace } { Brace~command~\token_to_str:c #1~has~already~been~added.~Skipped. } \cs_new:Nn \bracealign_add_brace:n { \seq_if_in:NnTF \l_bracealign_brace_seq { #1 } { \msg_warning:nnn { bracealign } { already-added-brace } { #1 } } { \seq_put_right:Nn \l_bracealign_brace_seq { #1 } % \end{macrocode} % % Backup the standard command. % \begin{macrocode} \cs_set_eq:cc { @@_#1_std_cmd:n } { #1 } % \end{macrocode} % % Define switches, if needed (for commands initially in % \cs{l@@_default_brace_clist}, the switches are defined when the % package is loaded, but the commands are added through the hook % |begindocument|). % \begin{macrocode} \bool_if_exist:cF { l@@_#1_bool } { \@@_define_switches:e { #1 } } % \end{macrocode} % % These token lists store the content of braces. % \begin{macrocode} \tl_new:c { g@@_#1_strutcontent_tl } \tl_new:c { l@@_#1_strutcontent_tl } \tl_new:c { l@@_#1_strutcontent_surround_tl } % \end{macrocode} % % Command wrapper to collect the braces content. % \begin{macrocode} \cs_new:cn { @@_#1_collect_strutcontent:n } { \tl_gput_right:cn { g@@_#1_strutcontent_tl } { ##1 } \use:c { @@_#1_std_cmd:n } { } } % \end{macrocode} % % Command wrapper to use the braces content in \cs{vphantom}. % \begin{macrocode} \cs_new:cn { @@_#1_use_strutcontent:n } { \use:c { @@_#1_std_cmd:n } { \vphantom { \tl_use:c { l@@_#1_strutcontent_tl } } ##1 } } } } \cs_generate_variant:Nn \bracealign_add_brace:n { e } \cs_new:Nn \bracealign_add_brace:N { \bracealign_add_brace:e { \cs_to_str:N #1 } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % Keys \refKey{/bracealign/add-brace} and \refKey{/bracealign/add-braces} % (wrapper to \cs{bracealign_add_brace:N}). % \begin{macrocode} \keys_define:nn { bracealign } { add-brace .code:n = { \bracealign_add_brace:N #1 }, add-braces .code:n = { \clist_map_function:nN { #1 } \bracealign_add_brace:N }, } % \end{macrocode} % % \begin{macro}{\@@_define_switches:n} % \begin{macro}{\@@_define_switches:e} % \begin{macro}{\@@_define_switches:N} % Define the switches for the brace command |#1|. % \begin{macrocode} \cs_new:Nn \@@_define_switches:n { \bool_new:c { l@@_#1_bool } \bool_set_true:c { l@@_#1_bool } \keys_define:nn { bracealign } { #1 .bool_set:c = { l@@_#1_bool }, no#1 .bool_set_inverse:c = { l@@_#1_bool }, } } \cs_generate_variant:Nn \@@_define_switches:n { e } \cs_new:Nn \@@_define_switches:N { \@@_define_switches:e { \cs_to_str:N #1 } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Alteration of brace command} % % These three commands are used for each brace. |#1| is the brace name. % % \begin{macro}{\@@_initialize:n} % Sets the brace command to collect its content in |\g@@_#1_strutcontent_tl|. % \begin{macrocode} \cs_new:Nn \@@_initialize:n { \tl_set_eq:cc { l@@_#1_strutcontent_surround_tl } { g@@_#1_strutcontent_tl } \tl_clear:c { g@@_#1_strutcontent_tl } \cs_set_eq:cc { #1 } { @@_#1_collect_strutcontent:n } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_use_strutcontent:n} % Set the brace command to use the all braces contents as strut (using % \cs{vphantom}). % \begin{macrocode} \cs_new:Nn \@@_use_strutcontent:n { \tl_set_eq:cc { l@@_#1_strutcontent_tl } { g@@_#1_strutcontent_tl } \cs_set_eq:cc { #1 } { @@_#1_use_strutcontent:n } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_finalize:n} % Restore |\g@@_#1_strutcontent_tl| for the surrounding group. % \begin{macrocode} \cs_new:Nn \@@_finalize:n { \tl_set_eq:cc { g@@_#1_strutcontent_tl } { l@@_#1_strutcontent_surround_tl } } % \end{macrocode} % \end{macro} % % \subsection{Main command} % % Sequence of active braces. % \begin{macrocode} \seq_new:N \l@@_active_brace_seq % \end{macrocode} % % \begin{macro}{\@@_update_active_braces:} % Update the sequence of active brace commands. % \begin{macrocode} \cs_new:Nn \@@_update_active_braces: { % \end{macrocode} % Restore standard brace commands (in the case the command is set is the % surrounding group, and unset in the current one). % \begin{macrocode} \seq_map_inline:Nn \l@@_active_brace_seq { \cs_set_eq:cc { ##1 } { @@_##1_std_cmd:n } } % \end{macrocode} % Set \cs{l@@_active_brace_seq}. % \begin{macrocode} \seq_clear:N \l@@_active_brace_seq \seq_map_inline:Nn \l_bracealign_brace_seq { \bool_if:cT { l@@_##1_bool } { \seq_put_right:Nn \l@@_active_brace_seq { ##1 } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\bracealign_bracealign:n} % Align braces in |#1|. % \begin{macrocode} \cs_new:Nn \bracealign_bracealign:n { % \end{macrocode} % % List active brace commands. % \begin{macrocode} \@@_update_active_braces: % \end{macrocode} % % Set the braces to collect their contents. % \begin{macrocode} \seq_map_inline:Nn \l@@_active_brace_seq { \@@_initialize:n { ##1 } } % \end{macrocode} % % Expand |#1| in an unused box. % \begin{macrocode} \hbox_set:Nn \l_tmpa_box { $ #1 $ } % \end{macrocode} % % Set the braces to automatically use a strut, and align. % \begin{macrocode} \seq_map_inline:Nn \l@@_active_brace_seq { \@@_use_strutcontent:n { ##1 } } % \end{macrocode} % % Typeset |#1|. % \begin{macrocode} #1 % \end{macrocode} % % Finalize. % \begin{macrocode} \seq_map_inline:Nn \l@@_active_brace_seq { \@@_finalize:n { ##1 } } } % \end{macrocode} % \end{macro} % % \subsection{User interface} % % \begin{macro}{\bracealignsetup} % Set \pkg{bracealign} keys. % \begin{macrocode} \NewDocumentCommand { \bracealignsetup } { m } { \keys_set:nn { bracealign } { #1 } } % \end{macrocode} % \end{macro} % % \begin{environment}{bracealign} % Main environment. % \begin{macrocode} \NewDocumentEnvironment { bracealign } { O{} b } { \bracealignsetup{ #1 } \bracealign_bracealign:n { #2 } } { } % \end{macrocode} % \end{environment} % % \subsection{Default braces} % % The |clist| that stores the default brace commands. % \begin{macrocode} \clist_new:N \l@@_default_brace_clist \keys_define:nn { bracealign } { default-braces .clist_set:N = \l@@_default_brace_clist, default-braces .initial:n = { \underbrace, \overbrace, \underbracket, \overbracket, \underparen, \overparen }, } % \end{macrocode} % % Define the switches for the commands initially in % \cs{l@@_default_brace_clist} to make them available in the preamble % (these commands are added through the hook |begindocument|). % \begin{macrocode} \clist_map_inline:Nn \l@@_default_brace_clist { \@@_define_switches:N #1 } % \end{macrocode} % % \subsection{Hook: \texttt{begindocument}} % % All these packages define brace commands. Wait for their commands definition. % \begin{macrocode} \clist_map_inline:nn { mathtools, unicode-math-luatex, unicode-math-xetex, libertinus, libertinust1math, stix2-type1, stix2 } { \hook_gset_rule:nnnn { begindocument } { . } { after } { #1 } } % \end{macrocode} % % Add braces in \cs{l@@_default_brace_clist}. % \begin{macrocode} \hook_gput_code:nnn { begindocument } { . } { \clist_map_inline:Nn \l@@_default_brace_clist { \cs_if_exist:NT #1 { \bracealign_add_brace:N #1 } } } % \end{macrocode} % %\iffalse % ^^A End of package implementation. %\fi % % \iffalse % ^^A The following is not for doc % %<*docstyle> % % \section*{bracealign-doc package} % % The following define some styles used for documentation and should not be % included in the documentation itself. % % \subsection*{Packages} % % \begin{macrocode} \RequirePackage{xcolor} \RequirePackage{metalogo} \PassOptionsToPackage{hyperref}{xcolor} \RequirePackage[many]{tcolorbox} \tcbuselibrary{listings} \tcbuselibrary{documentation} \hypersetup{hidelinks} % \end{macrocode} % % \subsection*{Colors} % % \begin{macrocode} \definecolor{bracealign_lavender}{rgb}{0.92,0.92,1} \definecolor{bracealign_darkblue}{rgb}{0.1,0.2,0.5} \definecolor{bracealign_darkgreen}{rgb}{0,0.39,0} \definecolor{bracealign_beige}{rgb}{.96,.96,.86} \colorlet{bracealign_commands}{bracealign_darkblue} \colorlet{bracealign_keys}{bracealign_darkgreen} \colorlet{bracealign_lengths}{violet} \colorlet{bracealign_options}{Definition} % from tcolorbox documentation % \end{macrocode} % % \subsection*{listings styles} % % \begin{macrocode} \lstdefinestyle{lstbracealigndoc}{% language = [LaTeX]TeX, alsoletter = {_,:},% for expl3 columns = fullflexible, keepspaces = true, keywordstyle = {\bfseries\color{bracealign_darkblue}}, texcsstyle = *{\bfseries\color{bracealign_darkblue}}, commentstyle = {\color{gray}}, identifierstyle = {\color{bracealign_darkgreen}}, morekeywords = {},% keywordsprefix needs a morekeywords before keywordsprefix = {\\}, % \end{macrocode} % For literate, the extra braces around the replacement text avoid the error: "Argument of |lst@FillFixed@| has an extra \}." % \begin{macrocode} literate = *{\$}{{\textcolor{red}{\$}}}{1} {\&}{{\textcolor{red}{\&}}}{1} {\}}{{\textcolor{darkgray}{\}}}}{1} {\{}{{\textcolor{darkgray}{\{}}}{1} {\\\\}{{\textcolor{red}{\textbackslash\textbackslash}}}{2} % \begin{macrocode} % One \% and four spaces to remove extra lines added by \cs{macrocode} % \end{macrocode} {\%\ \ \ \ }{}0, basicstyle = \ttfamily\footnotesize, frame = none, framesep = 0pt, aboveskip = 0pt, belowskip = 0pt, } \lstdefinestyle{lstbracealigncode}{% style = lstbracealigndoc, backgroundcolor = \color{bracealign_beige}, breakindent = 1cm, numbers = left, numberstyle = \scriptsize\ttfamily\color{gray}, aboveskip = \smallskipamount, belowskip = \smallskipamount, } % \end{macrocode} % % \subsection*{tcolorbox} % % \begin{macrocode} \tcbset{% copied and adapted from tcolorbox.doc.s_main.sty documentation listing style=lstbracealigndoc,% doc keypath=bracealign, size=small,% % verbatim ignore percent, %% styles docexample/.style={% bicolor jigsaw, before skip balanced=\medskipamount, after skip balanced=\medskipamount, fonttitle=\bfseries, fontlower=\normalfont, halign lower=center, colframe=bracealign_darkblue, colback=bracealign_lavender, colbacklower=white, drop fuzzy shadow, }, color key=bracealign_keys, color command=bracealign_commands, color length=bracealign_lengths, doc head key={fontlower=\footnotesize, collower=darkgray}, before doc body={\parskip=\smallskipamount}, } % \end{macrocode} % % Inline code % % \begin{macrocode} \DeclareTotalTCBox{\code}{ v } { verbatim, colframe=bracealign_beige, colback=bracealign_beige, sharp corners, size=tight, left=2pt, right=2pt, } {% \strut\lstinline[basicstyle=\ttfamily\small\color{bracealign_darkblue}]!#1!% } % \end{macrocode} % % \subsection*{Index} % % To deal with DocStrip @@ prefix, use '=' as index actual, in place of '@'. % \begin{macrocode} \begin{filecontents*}{\jobname.mst} actual '=' \end{filecontents*} % \begin{macrocode} \tcbset{% index actual={=}, index colorize=true, index gather all, index format=pgfsection, } % \end{macrocode} % Redefine \cs{tcb@doc@index@pgfsection} to add prologue (adapted from % tcbdocumentation.code.tex). % \begin{macrocode} \def\tcb@doc@index@pgfsection{% \def\index@prologue{% \section*{\kvtcb@text@index}\addcontentsline{toc}{section}{\kvtcb@text@index} {\small% Entries listed in the categories ``commands" and ``internal macros" also include references to package implementation. } \bigskip\par\noindent% }% \tcb@doc@index@pgf@% } % \end{macrocode} % Unset |\lst@UM| before indexing, to deal with comma (avoid |\unhbox \voidb@x % \kern \z@| in index file, see: \url{https://tex.stackexchange.com/a/510108}). % \begin{macrocode} \newcommand{\indexmacro}[1]{% \begingroup \let\lst@UM\@empty% \index{{Commands!#1=\tcbIndexPrintComC {#1}}}% \endgroup } \newcommand{\indexmacrointernal}[1]{% \begingroup \let\lst@UM\@empty% \index{{Internal macros!#1=\tcbIndexPrintComC {#1}}}% \endgroup } \newcommand{\indexlength}[1]{% \begingroup \let\lst@UM\@empty% \index{{Lengths!#1=\tcbIndexPrintLenC {#1}}}% \endgroup } % \end{macrocode} % % \subsection*{Redefinition of macrocode environment} % % \begin{macrocode} \let\macrocode\relax \lstnewenvironment{macrocode}{% \lstset{% name=macrocode, firstnumber=auto, style=lstbracealigncode, showlines=false, keepspaces=true, % \end{macrocode} % Commands identification and indexing % % Note: index works badly with inherited styles. It seems that "texcs" and % "index" keys should be set together. % \begin{macrocode} texcs = [2]{% commands bracealignsetup ,bracealign_add_brace:e ,bracealign_add_brace:n ,bracealign_add_brace:N ,bracealign_bracealign:n }, index = [2][texcs2],% indexstyle = [2]\indexmacro,% texcs = [3]{% lengths }, index = [3][texcs3],% indexstyle = [3]\indexlength,% % \end{macrocode} % Internal macros identification and indexing % \begin{macrocode} texcs = [4]{% internal macros (@@@@ → @@ with DocStrip) @@@@_define_switches:e ,@@@@_define_switches:n ,@@@@_define_switches:N ,@@@@_finalize:n ,@@@@_initialize:n ,@@@@_update_active_braces: ,@@@@_use_strutcontent:n ,l@@@@_active_brace_seq ,l@@@@_default_brace_clist ,l@@@@_overbrace_bool ,l@@@@_overbracket_bool ,l@@@@_overparen_bool ,l@@@@_underbrace_bool ,l@@@@_underbracket_bool ,l@@@@_underparen_bool }, index = [4][texcs4],% indexstyle = [4]\indexmacrointernal,% % \end{macrocode} % Keys identification and indexing ^^A works badly if keys have spaces % \begin{macrocode} morekeywords = [2]{% bracealign/add-brace ,bracealign/add-braces ,bracealign/default-braces ,bracealign/nooverbrace ,bracealign/nooverbracket ,bracealign/nooverparen ,bracealign/nounderbrace ,bracealign/nounderbracket ,bracealign/nounderparen ,bracealign/overbrace ,bracealign/overbracket ,bracealign/overparen ,bracealign/underbrace ,bracealign/underbracket ,bracealign/underparen }, index = [3][keywords2],% indexstyle = [3]\lstindexmacro,% } % \end{macrocode} % Save and restore the line number (not done by environments defined with % |\lstnewenvironment|, see \url{https://tex.stackexchange.com/a/95048}): % \begin{macrocode} \csname\@lst @SetFirstNumber\endcsname }{% \csname \@lst @SaveFirstNumber\endcsname } % \end{macrocode} % % \subsection*{Redefinition of macro environment} % % \begin{macrocode} \DeclareDocumentEnvironment{macro}{m}{% % \end{macrocode} % Extraction of macro name. Save/restore current \cs{escapechar} in \cs{count@}. % \begin{macrocode} \count@\escapechar \escapechar=-1 \edef\macroname{\string#1} \escapechar\count@ \marginpar{% \parbox{0.88\linewidth}{% \scriptsize\flushright\ifcsdef{r@com:\macroname}{\refCom*{\macroname}}{\cs{\macroname}}% }% } }{% end of macro environment } % \end{macrocode} % % \subsection*{Documentation styles} % % \subsubsection*{Tool for references} % % \begin{macrocode} \def\refDoc#1{\tcb@ref@doc{#1}} % \end{macrocode} % % \subsubsection*{Package name} % % \begin{macrocode} \newcommand{\pkg}[1]{\textsf{#1}} % \end{macrocode} % % % \subsubsection*{Redefinition of the \cs{cs} command} % % To handle |expl3| syntax. % % \begin{macrocode} \ExplSyntaxOn \cs_new_protected:Nn \bracealigndoc_cs:n { \str_set:Nn \l_tmpa_str { #1 } \exp_args:Ne \texttt{ \c_backslash_str \str_use:N \l_tmpa_str } } \cs_generate_variant:Nn \bracealigndoc_cs:n { e } \RenewDocumentCommand{\cs}{ m }{\bracealigndoc_cs:e { #1} } \ExplSyntaxOff % \end{macrocode} % % \subsubsection*{Package options} % % Definition of docOption environment to document package options, like keys. % \begin{macrocode} \newrobustcmd{\tcbIndexPrintOptionCA}[1]{% adapted from \tcbIndexPrintKeyCA \tcb@Index@Print@CA{#1}{bracealign_options}{package option}% } \newrobustcmd{\tcbIndexPrintOptionC}[1]{% adapted from \tcbIndexPrintKeyCA \tcb@Index@Print@C{#1}{bracealign_options}% } \DeclareDocumentEnvironment{docOption}{ O{} m }{% \begin{docKey*}[] [doc name={#2}, doc label={opt:#2}, color key=bracealign_options, #1] {#2}{}{}% \kvtcb@index@command{% \kvtcb@doc@sortindex\idx@actual\tcbIndexPrintOptionCA{#2}% }% \kvtcb@index@command{% {Package options}\idx@level\kvtcb@doc@sortindex\idx@actual% \tcbIndexPrintOptionC{#2}% }% }{% \end{docKey*}% } \def\refOpt{\refDoc{key:opt}} % \end{macrocode} % % % % \fi %^^A end of \iffalse % % \Finale % \endinput