Environment with a switch
You can use environ
for manipulating the environment's contents more easily.
\documentclass{article}
\usepackage{xparse,environ}
\ExplSyntaxOn
\NewEnviron{xdesc}
{
\begin{description}
\cp_xdesc_main:NV \xdescitemshow \BODY
\end{description}
}
\NewEnviron{xdesc*}
{
\begin{description}
\cp_xdesc_main:NV \xdescitemhide \BODY
\end{description}
}
\cs_new_protected:Nn \cp_xdesc_main:Nn
{
\seq_set_split:Nnn \l_cp_xdesc_items_in_seq { \item } { #2 }
\seq_pop_left:NN \l_cp_xdesc_items_in_seq \l_tmpa_tl
\seq_clear:N \l_cp_xdesc_items_out_seq
\seq_map_inline:Nn \l_cp_xdesc_items_in_seq
{
\seq_put_right:Nn \l_cp_xdesc_items_out_seq { #1 ##1 \endxdescitem }
}
\seq_use:Nn \l_cp_xdesc_items_out_seq { }
}
\cs_generate_variant:Nn \cp_xdesc_main:Nn { NV }
\NewDocumentCommand{\xdescitemshow}{sO{}+u{\endxdescitem}}
{
\item[#2] #3
}
\NewDocumentCommand{\xdescitemhide}{sO{}+u{\endxdescitem}}
{
\item[#2] \IfBooleanT{#1}{#3}
}
\ExplSyntaxOff
\begin{document}
\section{Show}
\begin{xdesc}
\item[ABC] 12345
\item[CDEF] 098765
\item*[xxxx] yyyyy
\end{xdesc}
\section{Hide}
\begin{xdesc*}
\item[ABC] 12345
\item[CDEF] 098765
\item*[xxxx] yyyyy
\end{xdesc*}
\end{document}
The idea is to collect the contents and splitting it at \item
; the first item will be empty and we throw it away. Then we process each item by adding in front of it either \xdescitemshow
or \xdescitemhide
and ending them with the sentinel \endxdescitem
; the two commands process their arguments inserting \item
, collecting the optional argument (and possibly the *
), then printing or discarding the following text up to \endxdescitem
.
Update March 2019
With new features of expl3
(\seq_map_variable:NNn
) and xparse
(the implementation of features alike to environ
), the code can be simplified.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{xdesc}{+b}
{
\begin{description}
\cp_xdesc_main:Nn \xdescitemshow { #1 }
\end{description}
}{}
\NewDocumentEnvironment{xdesc*}{+b}
{
\begin{description}
\cp_xdesc_main:Nn \xdescitemhide { #1 }
\end{description}
}{}
\seq_new:N \l_cp_xdesc_items_seq
\tl_new:N \l__cp_xdesc_temp_tl
\cs_new_protected:Nn \cp_xdesc_main:Nn
{
% split the input at \item
\seq_set_split:Nnn \l_cp_xdesc_items_seq { \item } { #2 }
% throw away the first element, that's empty
\seq_pop_left:NN \l_cp_xdesc_items_seq \l_tmpa_tl
%
\seq_map_variable:NNn \l_cp_xdesc_items_seq \l__cp_xdesc_temp_tl
{
\exp_last_unbraced:NV #1 \l__cp_xdesc_temp_tl \stopxdescitem
}
}
\NewDocumentCommand{\xdescitemshow}{sO{}+u{\stopxdescitem}}
{
\item[#2] #3
}
\NewDocumentCommand{\xdescitemhide}{sO{}+u{\stopxdescitem}}
{
\item[#2] \IfBooleanT{#1}{#3}
}
\NewDocumentCommand{\stopxdescitem}{}{} % for safety
\ExplSyntaxOff
\begin{document}
\section{Show}
\begin{xdesc}
\item[ABC] 12345
\item[CDEF] 098765
\item*[xxxx] yyyyy
\end{xdesc}
\section{Hide}
\begin{xdesc*}
\item[ABC] 12345
\item[CDEF] 098765
\item*[xxxx] yyyyy
\end{xdesc*}
\end{document}
I don't know of a package that does this. If you are prepared to enclose the "item text" in braces so that for each item you type something like:
\Item[ABC]{12345}
then this is relatively straightforward to do using the xparse package. All that you need to do is define an \Item
command that takes three arguments:
- an optional
*
- an optional label for the
\item
command, and, - the "item text"
The \Item
command then processes the input using the tools described in the (see the xparse](https://www.ctan.org/pkg/xparse) manual and then does the appropriate things.
For example, you get the output
using the code:
\documentclass{scrreprt}
\usepackage{enumerate}
\usepackage{xparse}
\newif\ifMySwitch% a "switch" for turning othe item text on/off
\NewDocumentCommand\Item{ som }{% *[label]{text}
\IfBooleanTF{#1}{ \IfNoValueTF{#2}{\item #3}{\item[#2]#3} }
{\IfNoValueTF{#2}{\item}{\item[#2]}\ifMySwitch #3\fi}
}
\begin{document}
Switched on: \MySwitchtrue
\begin{description}
\Item[ABC]{12345}
\Item[CDEF]{098765}
\Item*[xxxx]{yyyyy}
\end{description}
Switched off \MySwitchfalse
\begin{description}
\Item[ABC]{12345}
\Item[CDEF]{098765}
\Item*[xxxx]{yyyyy}
\end{description}
\end{document}
If you are not happy enclosing the "item text" in braces this is slightly trickier. The easiest way out that I see is to assume that the "item text" contains at most one paragraph, which seems reasonable to me, and then require that every item ends with a blank line. In particular, the very last item needs a blank line before the \end{Description}
.
If you assume this then you can essentially repeat the code above but now the item command delegates everything to a \greedyItem
command that reads in everything up to the end of the next paragraph as the item text. For LaTeX the "end of the next paragraph" means the next \par
, which is why \par
appears after the #3
in the definition of \greedyItem
. The following code achieves this:
\documentclass{scrreprt}
\usepackage{enumitem}
\newlist{Description}{description}{3}% a new description environment
\setlist[Description]{before=\let\item\Item}% in which the switch is automatic
\let\realItem=\item% save the "real" item for future use
\usepackage{xparse}
\newif\ifMySwitch% switch on/switch off
\def\greedyItem[#1][#2]#3\par{% #3 = until end of paragraph
\IfBooleanTF{#1}{ \IfNoValueTF{#2}{\realItem #3}{\realItem[#2]#3} }%
{\IfNoValueTF{#2}{\realItem}{\realItem[#2]}\ifMySwitch #3\fi}%
}
\NewDocumentCommand\Item{ so }{\greedyItem[#1][#2]}
\begin{document}
Switched on: \MySwitchtrue
\begin{Description}
\item[ABC]12345
\item[CDEF]098765
\item*[xxxx]yyyyy
\end{Description}
Switched off \MySwitchfalse
\begin{Description}
\item[ABC]12345
\item[CDEF]098765
\item*[xxxx]yyyyy
\end{Description}
\end{document}
Btw, I have switched to using the enumitem package, which I prefer, and added a few bells and whistles to hide the code inside a new Description
environment, which is the just the usual description
environment with your switch automatically incorporated. The output is the same as before.