T-F-S / tcolorbox

A LaTeX package to create highly customizable colored boxes.
http://www.ctan.org/pkg/tcolorbox
LaTeX Project Public License v1.3c
213 stars 15 forks source link

[FR] Compacter way to document commands accepting optional stars #258

Open muzimuzhi opened 7 months ago

muzimuzhi commented 7 months ago

Currently a tcolorbox command accepting an optional star as first argument is always documented in two entries, e.g., \docValue and \docValue*, and in the starred entry/form, the star is colored as if it's mandatory since the star * is passed to doc name. This also holds for index entries, see https://github.com/T-F-S/tcolorbox/issues/193#issuecomment-1430751043.

image

I think the advantage of passing * to doc name, rather than to doc parameter is that so the starred form also has its own label (hence can be referred by \refCom{docValue*}) and index entries.

The example below defines a new option /tcb/label starred commands which will create labels for starred form(s) if doc parameter starts with \sarg(s). This way, \sarg can be used in doc parameter and \refCom{<doc name>*} is still usable.

If it's strongly needed (which is contrary to my preference), index entries for starred form(s) can be automatically created similarly.

\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{documentation}

\hypersetup{colorlinks}

\makeindex

\makeatletter
\ExplSyntaxOn

% define new boolean option "/tcb/label starred commands"
% live with both "nn" and "Nn" forms of "\__tcobox_new_bool_key:<arg-spec>",
%   see https://github.com/T-F-S/tcolorbox/issues/257
\cs_if_exist:NTF \__tcobox_new_bool_key:Nn
  { \__tcobox_new_bool_key:Nn }
  { \__tcobox_new_bool_key:nn }
  \l__tcobox_doc_label_starred_tool { label~starred~commands }

% init new option
\tcbset{label~starred~commands=false}

% patch \__tcobox_doc_head_command: to create labels for starred forms
\cs_gset_protected:Npn \__tcobox_doc_head_command:
  {
    \__tcobox_print_command:
    \__tcobox_index_command:
    % this is slightly quicker than no-arg form, which needs to get value of
    % \kvtcb@doc@label twice
    \__tcobox_label_command:o { \kvtcb@doc@label }
    \bool_if:NT \l__tcobox_doc_label_starred_tool
      {
        \group_begin:
        % change \kvtcb@doc@label and \kvtcb@doc@parameter locally
        % note that \__tcobox_label_command:nn works globally
        \bool_while_do:nn
          { \tl_if_head_eq_meaning_p:oN { \kvtcb@doc@parameter } \sarg }
          {
            % just in case "*" has catcode other than 12 (other)
            \tl_put_right:No \kvtcb@doc@label { \tl_to_str:n {*} }
            % result of \tl_tail:N is returend within \exp_not:n, hence no fear
            % of over-expansion
            \tl_set:Ne \kvtcb@doc@parameter { \tl_tail:N \kvtcb@doc@parameter }
            % create label using current value of \kvtcb@doc@label
            \__tcobox_label_command:o { \kvtcb@doc@label }
          }
        \group_end:
      }
    {\ttfamily\kvtcb@doc@parameter}
    \tcb@doc@do@description
  }

% may be useful in other \__tcobox_doc_head_<type>: too
% #1 = doc name, usually the value of \kvtcb@doc@label
\cs_new_protected:Npn \__tcobox_label_command:n #1
  {
    \seq_if_in:NnF \g__tcobox_label_seq { #1 }
      {
        \protected@edef \@currentlabel { \exp_not:N \tcb@cs {#1} }
        \label{com:#1}
        \seq_gput_left:Nn \g__tcobox_label_seq {#1}
      }
  }

\cs_generate_variant:Nn \__tcobox_label_command:n { o }
\prg_generate_conditional_variant:Nnn \tl_if_head_eq_meaning:nN { o } { p }

\ExplSyntaxOff
\makeatother

\begin{document}

\subsection*{Before}
\begin{docCommands}[doc parameter=\oarg{options}\marg{name}]
  {
    { doc name    = docAuxCommand },
    { doc name    = docAuxCommand* }
  }
  \refCom{docAuxCommand} and starred \refCom{docAuxCommand*}.
\end{docCommands}

\subsection*{After}
\begin{docCommand}[label starred commands]
    {myCmdS}{\sarg\oarg{options}\marg{name}}
  \refCom{myCmdS} and starred \refCom{myCmdS*}
\end{docCommand}

\begin{docCommand}[label starred commands]
    {myCmdSS}{\sarg\sarg\oarg{options}\marg{name}}
  Multiple leading \docAuxCommand*{sarg} are supported.

  \refCom{myCmdSS}, starred \refCom{myCmdSS*}, and doubly starred \refCom{myCmdSS**}
\end{docCommand}

\begin{docCommands}[label starred commands, doc name=myCmdXS]
  {
    { doc parameter = \marg{name} },
    { doc parameter = \sarg\marg{name} }
  }
  Documented in multiple entries are supported, and labels are created only once.

  \refCom{myCmdXS} and starred \refCom{myCmdXS*}
\end{docCommands}

\printindex
\end{document}
image image
T-F-S commented 7 months ago

Hm... I am not so sure about this change. I will think about it with more time.