4

In Working with margins egreg proposed the below environment for gathering the maximal width of a description-label. Unfortunately this code only works as long as the environment xdesc is not nested. In case of nesting (see below) the code will return

LaTeX Error: Something's wrong--perhaps a missing \item.

Here is a nestified version of the code:

\documentclass[12pt]{article}
\usepackage[a4paper, margin=2cm]{geometry}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[shortlabels]{enumitem}
\usepackage[spanish]{babel}

\newlength{\xdescwd}
\usepackage{environ}
\makeatletter
\NewEnviron{xdesc}{%
  \vbox{\hbadness=\@M \global\xdescwd=0pt
    \def\item[##1]{%
      \settowidth\@tempdima{\textbf{##1}:}%
      \ifdim\@tempdima>\xdescwd \global\xdescwd=\@tempdima\fi}
  \BODY}
  \begin{description}[leftmargin=\dimexpr\xdescwd+.5em\relax,
    labelindent=0pt,labelsep=.5em,
    labelwidth=\xdescwd,align=left]\BODY\end{description}}
\makeatother

\begin{document}

En un contexto determinado, las palabras poseen, además de su
significado literal, también una dimensión intencional. Un texto es la
manifestación lingüística de la intención del emisor dirigida a un
receptor. Si consideramos, pues, los actos ilocutivos implicados, un
texto cumplirá funciones diferentes.

La función textual es el efecto de los textos en una situación
comunicativa según los objetivos que queremos alcanzar. Un texto puede
desempeñar las siguientes funciones:

\begin{xdesc}
\item[Representativa:] llamada también asertiva, cuando se afirma o se 
    \begin{xdesc}
    \item[Prescriptiva:] cuando se establecen normas. anuncia algo que se
                      considera verdadero.
    \end{xdesc}     
\item[Informativa:] cuando se presenta algo de manera neutra, sin
     énfasis que pueda denotar emotividad, como por ejemplo un titular
     de una noticia.
\item[Prescriptiva:] cuando se establecen normas. En la legislación, por
     ejemplo, se emplean formas modales deónticas (deber + infinitivo)
\item[Persuasiva:] cuando se trata de convencer al interlocutor
\item[Comisiva:] cuando se promete, jura, ofrece, etc.
\item[Fática:] cuando el emisor se centra en el interlocutor y procura
               mantener el contacto con él, como por ejemplo “Oye…”
\item[Expresiva:] cuando el emisor se alegra, agradece, felicita.
\end{xdesc}

\end{document}     

Beyond that even the original code produces a strange duplication of the text of the items above the xdesc-environment.

egreg's two-pass code compiled with pdflatex

Since I really would like to implement the idea of egreg's code in an environment of my own any kind of help would be appreciated.

[Update 2016/12/04] Here is an addition to my original question concerning the answers of egreg and Andrew below:

Unfortunately after further testing in the wild the following problem came up: egreg's xdesc breaks compatibility with the normal enumerate-environment. Within the normal environment it is possible to have \items without any text. But in xdesc a textless item disappears. (The same is true of Andrew's code.) I tried some modifications without success. So I have no clue how to prevent xdesc from eating up textless items. Since I need the functionality of enumerate, any help would be welcome. Here is a MWE:

\documentclass[12pt]{article}
\usepackage[a4paper, margin=2cm]{geometry}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[spanish]{babel}
\usepackage{enumitem}

\newlength{\xdescwd}
\usepackage{environ}
\makeatletter%
\NewEnviron{xdesc}{% I only changed "description" to "enumerate"
               % and did some formatting
              \setbox0=\vbox{%
                             \hbadness=\@M \global\xdescwd=0pt
                             \RenewEnviron{xdesc}{}%
                             \def\item[##1]{%
                             \settowidth\@tempdima{##1}%
                             \ifdim\@tempdima>\xdescwd \global\xdescwd=\@tempdima\fi}
                             \BODY%
                             }%
               \begin{enumerate}[leftmargin=\dimexpr\xdescwd+.5em\relax,
                                labelindent=0pt,labelsep=.5em,
                                labelwidth=\xdescwd,align=left]
               \BODY%
               \end{enumerate}%
               }
\makeatother

\begin{document}
\parindent0pt
Here is what \textbf{enumerate} does:

\begin{enumerate}
\item[(DF)] %llamada también asertiva, cuando se afirma o se

        \begin{enumerate}
        \item[(1)] cuando se establecen normas. anuncia algo que se
                    considera verdadero.
        \item[(1a)] cuando se establecen normas. anuncia algo que se
                    considera verdadero.
        \end{enumerate}
\end{enumerate}

Here is what \textbf{xdesc} does:

\begin{xdesc}
\item[(DF)] %llamada también asertiva, cuando se afirma o se

        \begin{xdesc}
        \item[(1)] cuando se establecen normas. anuncia algo que se
                    considera verdadero.
        \item[(1a)] cuando se establecen normas. anuncia algo que se
                    considera verdadero.
        \end{xdesc}
\end{xdesc}
\end{document}

Here's the output:

output of enumerate and xdesc

[End of Update 2016/12/04]

3
  • Please, when you ask a question, it should be complete. It's obvious that you cannot nest an enumerate environment in xdesc.
    – egreg
    Dec 5, 2016 at 0:03
  • @egreg I did not nest enumerate in xdesc, but xdesc in xdesc. The enumerate-example is only meant as a contrast case to make the difference obvious. (Thanks for the hint to open up a new question in case of need for further clarification.)
    – chandra
    Dec 5, 2016 at 9:42
  • I do not understand why it works, but putting the first token of \BODY in a hbox prevents the code from eating up items without text. Hopefully this doesn't have unwanted side-effects...
    – chandra
    Dec 5, 2016 at 13:59

2 Answers 2

4

This seems to work:

\documentclass[12pt]{article}
\usepackage[a4paper, margin=2cm]{geometry}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[spanish]{babel}
\usepackage{enumitem}

\newlength{\xdescwd}
\usepackage{environ}
\makeatletter
\NewEnviron{xdesc}{%
  \setbox0=\vbox{\hbadness=\@M \global\xdescwd=0pt
    \RenewEnviron{xdesc}{}%
    \def\item[##1]{%
      \settowidth\@tempdima{\textbf{##1}:}%
      \ifdim\@tempdima>\xdescwd \global\xdescwd=\@tempdima\fi}
  \BODY}
  \begin{description}[leftmargin=\dimexpr\xdescwd+.5em\relax,
    labelindent=0pt,labelsep=.5em,
    labelwidth=\xdescwd,align=left]\BODY\end{description}}
\makeatother

\begin{document}

En un contexto determinado, las palabras poseen, además de su
significado literal, también una dimensión intencional. Un texto es la
manifestación lingüística de la intención del emisor dirigida a un
receptor. Si consideramos, pues, los actos ilocutivos implicados, un
texto cumplirá funciones diferentes.

La función textual es el efecto de los textos en una situación
comunicativa según los objetivos que queremos alcanzar. Un texto puede
desempeñar las siguientes funciones:

\begin{xdesc}
\item[Representativa:] llamada también asertiva, cuando se afirma o se 
    \begin{xdesc}
    \item[Prescriptiva:] cuando se establecen normas. anuncia algo que se
                      considera verdadero.
    \item[Prescriptivaaaa:] cuando se establecen normas. anuncia algo que se
                      considera verdadero.
    \end{xdesc}    
\item[Informativa:] cuando se presenta algo de manera neutra, sin
     énfasis que pueda denotar emotividad, como por ejemplo un titular
     de una noticia.
\item[Prescriptiva:] cuando se establecen normas. En la legislación, por
     ejemplo, se emplean formas modales deónticas (deber + infinitivo)
\item[Persuasiva:] cuando se trata de convencer al interlocutor
\item[Comisiva:] cuando se promete, jura, ofrece, etc.
\item[Fática:] cuando el emisor se centra en el interlocutor y procura
               mantener el contacto con él, como por ejemplo “Oye…”
\item[Expresiva:] cuando el emisor se alegra, agradece, felicita.
\end{xdesc}

\end{document}

When the \vbox is being set for measuring, xdesc is redefined to do nothing.

enter image description here

2
  • This is really helpful, thank you very much! I specifically cherish the compactness of the code. Compared to Andrew's code above your code adjusts the labelwidth for each token of a xdesk-environment, what is exactly what I need.
    – chandra
    Dec 3, 2016 at 12:00
  • Please see my follow-up question in the original question above.
    – chandra
    Dec 4, 2016 at 21:00
3

There are really two problems here. First, you need to fix the missing item error and, secondly, I think that you want the maximum label widths for each level of nesting to be different so you need to keep track of the nesting level.

The missing item error I fix by setting \item\setitemwidth the first time \BODY is used and then resetting it to the original \item command directly afterwards.

For the nesting issue, the description environment uses \@listdepth to keep track of this but we cannot use this because we compute the widest labels before we enter the description environment, so I have added a counter xdescdepth to keep track of this. I then store the label widths in widest<xdescepth>.

\documentclass{article}
\usepackage{mathtools}
\usepackage{enumitem}
\usepackage{etoolbox}
\usepackage{environ}

\newdimen\widest
\newcounter{xdescdepth}
\makeatletter
\def\setitemwidth[#1]{% compute maximum width of labels for nesting depth
    \settowidth\@tempdima{\textbf{#1}}%
    \ifdim\@tempdima>\csuse{widest\thexdescdepth}%
       \csdimgdef{widest\thexdescdepth}{\@tempdima}%
    \fi%
}
\let\realitem\item% save the real \item command
\NewEnviron{xdesc}{%
  \addtocounter{xdescdepth}{1}% increment nesting depth
  % initialise label width to 0pt at the start of each nesting level
  \ifcsdef{widest\thexdescdepth}{\relax}%
          {\csdef{widest\thexdescdepth}{0pt}}%
  \let\item\setitemwidth% temporarily override \item
  \setbox0=\vbox{\BODY}% compute label widths without printing anything
  \let\item\realitem% reset \item
  \widest=\dimexpr\csuse{widest\thexdescdepth}\relax%
  \description[
    leftmargin=\dimexpr\widest+0.5em\relax,
    labelindent=0pt,
    labelwidth=\widest
    ]
    \BODY
  \enddescription%
  \addtocounter{xdescdepth}{-1}% decrement nesting depth
}
\makeatother

\begin{document}

  \begin{xdesc}
  \item[Representativa:] llamada también asertiva, cuando se afirma o se
      \begin{xdesc}
      \item[Prescriptiva:] cuando se establecen normas. anuncia algo que se
                        considera verdadero.
      \end{xdesc}
  \item[Informativa:] cuando se presenta algo de manera neutra, sin
       énfasis que pueda denotar emotividad, como por ejemplo un titular
       de una noticia.
  \item[Prescriptiva:] cuando se establecen normas. En la legislación, por
       ejemplo, se emplean formas modales deónticas (deber + infinitivo)
  \item[Persuasiva:] cuando se trata de convencer al interlocutor
  \item[Comisiva:] cuando se promete, jura, ofrece, etc.
      \begin{xdesc}
      \item[Prescrip] cuando se establecen normas. anuncia algo que se
                        considera verdadero.
      \end{xdesc}
  \item[Fática:] cuando el emisor se centra en el interlocutor y procura
                 mantener el contacto con él, como por ejemplo “Oye…”
  \item[Expresiva:] cuando el emisor se alegra, agradece, felicita.
  \end{xdesc}

\end{document}

Here is the output:

enter image description here

1
  • 1
    Thank you very much! Not only for the code but for the great explanation. Compared to egreg's code below your macro adjusts the labelwidth of the itemlabels for all list tokens of the same level. Since this allows a quite consistent layout of a complex list I see this as a feature!
    – chandra
    Dec 3, 2016 at 11:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .