tcolorbox documentation: documenting dynamic keypaths
tcolorbox
assumes the value of first optional argument of docKey
environment (also the value of key /tcb/doc keypath
) is fully expandable and uses it in printing, label name, and index name. Since \meta{...}
is not fully expandable, errors are raised.
In the following example, I split the role of doc keypath
into four:
- printed key name
- label name, can be set by
doc keypath label
- printed index name, can be set by
doc keypath index
- sorted index name, can be set by
doc keypath sort index
.
Modified doc keypath
will set all four of them, and a new key doc formatted keypath
sets both the first and the third.
Usage:
\begin{docKey}
[keypath][doc formatted keypath=\meta{keypath}]
{my key}
{=value}
{}
\end{docKey}
See \refKey{/keypath/my key}.
Full example:
\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{documentation}
\makeindex
\makeatletter
\newif\iftcb@doc@formatted@keypath
\tcbset{
doc keypath/.style={%
doc@keypath={#1},
doc keypath label={#1},
doc keypath index={#1},doc keypath sort index={#1},
},
doc@keypath/.store in=\kvtcb@doc@keypath,
doc formatted keypath/.code=%
\tcb@doc@formatted@keypathtrue
\pgfkeysalso{doc@keypath=#1,doc keypath index=#1},
% doc keypath name/.store in=\kvtcb@doc@keypath,
doc keypath label/.store in=\kvtcb@doc@keypath@label,
doc keypath index/.store in=\kvtcb@doc@keypath@index,
doc keypath sort index/.store in=\kvtcb@doc@keypath@sortindex,
}
\ExplSyntaxOn
\cs_set_nopar:Npn \__tcobox_print_key:
{
\textcolor{\kvtcb@col@key}{\tcb@doc@bfseries\ttfamily
\tl_if_empty:NF \kvtcb@doc@keypath
{
\iftcb@doc@formatted@keypath
/\kvtcb@doc@keypath/
\else
/\__tcobox_sanitize_tl:V\kvtcb@doc@keypath/
\fi
}
\__tcobox_sanitize_tl:V\kvtcb@doc@name}
}
\cs_set_nopar:Npn \__tcobox_index_key:
{
\iftcb@doc@toindex
\kvtcb@index@command{\kvtcb@doc@sortindex\idx@actual\tcbIndexPrintKeyCA{\kvtcb@doc@index}}
\tl_if_empty:NTF \kvtcb@doc@keypath@index
{
\kvtcb@index@command{\kvtcb@text@keys\idx@level\kvtcb@doc@sortindex\idx@actual\tcbIndexPrintKeyC{\kvtcb@doc@index}}
}
{
\kvtcb@index@command{\kvtcb@text@keys\idx@level\kvtcb@doc@keypath@sortindex\idx@actual\tcbIndexPrintKeyC{/\kvtcb@doc@keypath@index/}
\idx@level\kvtcb@doc@sortindex\idx@actual\tcbIndexPrintKeyC{\kvtcb@doc@index}}
}
\fi
}
\cs_set:Npn \__tcobox_doc_head_key:
{
\__tcobox_print_key:
\__tcobox_index_key:
\tl_if_empty:NTF \kvtcb@doc@keypath@label
{
\seq_if_in:NVF \g__tcobox_label_seq \kvtcb@doc@label
{
\protected@edef\@currentlabel{\kvtcb@doc@name}
\label{key:\kvtcb@doc@label}
\seq_gput_left:NV \g__tcobox_label_seq \kvtcb@doc@label
}
}
{
\tl_set:Nx \l_tmpa_tl {/\kvtcb@doc@keypath@label/\kvtcb@doc@label}
\seq_if_in:NVF \g__tcobox_label_seq \l_tmpa_tl
{
\protected@edef\@currentlabel{/\kvtcb@doc@keypath/\kvtcb@doc@name}
\label{key:/\kvtcb@doc@keypath@label/\kvtcb@doc@label}
\seq_gput_left:NV \g__tcobox_label_seq \l_tmpa_tl
}
}
{\ttfamily\kvtcb@doc@parameter}
\tcb@doc@do@description
}
\ExplSyntaxOff
\makeatother
\begin{document}
\begin{docKey}
[keypath][doc formatted keypath=\meta{keypath}]
{my key}
{=value}
{}
The \texttt{keypath} part of the key path is dynamic. Using \meta{keypath} breaks.
Putting both in the mandatory argument as \verb|{\meta{keypath}/my key}| also breaks.
What is the best alternative?
\end{docKey}
See \refKey{/keypath/my key}.
\printindex
\end{document}
Thanks for the detailed answers, @Marijn & @mushimushiZ! I am studying them for ideas and techniques.
As for this specific problem, it turns out that it is possible to do with the options provided by tcolorbox itself, via the doc label
key, if the macros are kept to the key itself (and not in the optional path argument):
\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{documentation}
\makeindex
\begin{document}
\begin{docKey}
[mypackage]
[doc label=keypath/mykey]
{\meta{keypath}/my key}
{=value}
{}
The \texttt{keypath} part of the key path is dynamic and corresponds to ...
\end{docKey}
Can be referenced: \refKey{/mypackage/keypath/mykey}
\printindex
\end{document}
The issue is that both the optional and the mandatory argument are used to create a label for referencing with \refKey
, i.e., \refKey{/mypackage/keypath/my key}
. In the value of a label commands such as \meta
are not allowed.
You can modify the definition of docKey
slightly to circumvent the issue, by defining the label to be just the name without the optional prefix. One way of doing that is to copy the definition from the tcolorbox
source and use \RenewDocumentEnvironment
to make the changes.
MWE:
\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{documentation}
\makeatletter
\RenewDocumentEnvironment{docKey}{ O{} +O{} m m +m }{\tcbset{#2,doc description={#5}}%
\begin{tcb@manual@entry}%
\begin{tcb@doc@head}{doc@head@key}%
\ifblank{#1}{%
\tcb@Print@Key{#3}\tcb@index@Key{#3}\protected@edef\@currentlabel{#3}\label{key:#3}{\ttfamily #4}%
}{%
\tcb@Print@Key{/#1/#3}%
% CHANGE OF LABEL IN FOLLOWING LINE %
\tcb@index@KeyPath{#1}{#3}\protected@edef\@currentlabel{/#1/#3}\label{key:#3}{\ttfamily #4}%
}%
\tcb@doc@do@description%
\end{tcb@doc@head}\nobreak\tcbset{before upper=}\kvtcb@doc@body@key@before\ignorespaces}%
{\ifvmode\else\unskip\fi\kvtcb@doc@body@key@after\end{tcb@manual@entry}}
\makeatother
\begin{document}
\begin{docKey}
[mypackage/\meta{keypath}]
{my key}
{=value}
{}
The \texttt{keypath} part of the key path is dynamic. Using \meta{keypath} breaks.
Putting both in the mandatory argument as \verb|{\meta{keypath}/my key}| also breaks.
What is the best alternative?
\end{docKey}
See \refKey{my key}.
\end{document}
Result:
Remark: maybe \textit{<keypath>}
is nicer than \meta{keypath}
: