1

I would like to combine this question with this one.

The goal is to build a list of notation with the following properties

  1. the symbol is on the left in a column with fixed width
  2. the description is in a second column
  3. if the symbol is too long, it extends into the second column with an additional , (comma+space)
  4. at the end of the item (last line of the paragraph) it should be possible to add the page reference (one or more), on the right and the space should be filled with dots
  5. there should be some dot before the page reference
4

The final version can be found below, at the end of this answer. I'm leaving essentially one intermediate version with screenshots and explanations of what I did to overcome its weaknesses, because it's probably useful from a learning perspective.

Starting from egreg's solution to this question and this inspired from David Carlisle's answer to that question, you can do:

\documentclass{article}
\usepackage{enumitem}

\usepackage{lipsum}

\newlength{\commalabelwd}
\newcommand{\commalabel}[2]{%
  \settowidth\commalabelwd{\normalfont\itshape#2,\hspace{\labelsep}}%
  \normalfont\itshape#2\ifdim#1<\commalabelwd,\fi\hfill
}

\newcommand{\mindotfill}[1][1cm]{%
  \nolinebreak
  {\def\hfill{\hskip #1plus 1fill\relax}%
   \dotfill
  }%
}

\newlength{\glossaryrmarg}
\setlength{\glossaryrmarg}{2em}

\newcommand*{\glosspagenum}[1]{%
  \unskip
  \begingroup
    \normalfont\normalcolor\mindotfill
    % Set \parfillskip *locally*. The locality of this change is useful
    % in case the next paragraph doesn't end with \glosspagenum.
    \parfillskip=-\glossaryrmarg\relax
    \hbox to \glossaryrmarg{%
      \hfil #1%
      \kern-1pt\kern1pt}% Avoid protrusion into the right margin (see below)
    \par
  \endgroup
}

\begin{document}
\noindent
\hrulefill  % Show a full \linewidth (equal to \textwidth in this case)

% The final version below will show how to make our own environement    
\begin{description}[
  labelwidth=\dimexpr2cm-\labelsep,
  leftmargin=2cm,
  before={\renewcommand\makelabel[1]{\commalabel{2cm}{##1}}},
  rightmargin=\glossaryrmarg
]
\item[Short] \lipsum[1][1-2]\glosspagenum{3}

\item[Longer] \lipsum[1][1-3]\glosspagenum{23}

\item[Longerr] \lipsum[1][1-4] abc def ghi jkl\glosspagenum{12}

\item[Longerrr] \lipsum[1][1-5]\glosspagenum{221}

\item[Longerrrr] \lipsum[1][1-2]\glosspagenum{245}

\item[Longerrrrr] \lipsum[1][1-2]\glosspagenum{23}

\item[Longerrrrrr] \lipsum[1][1-2]\glosspagenum{23}

\item[Longerrrrrrr] \lipsum[1][1-2]\glosspagenum{23}

\item[Longerrrrrrrrrrrrr] \lipsum[1][1-2]\glosspagenum{23}
\end{description}

\end{document}

Screenshot

You can verify that the \mindotfill is working as expected by suppressing the l in abc def ghi jkl; you'll then get:

One term

The \mindotfill ensures there is 1 cm or more of dots before the page number (1cm is the default value of \mindotfill's argument, you can of course change it and/or specify it explicitly in the definition of \glosspagenum).

In what precedes, the page number, reference or whatever it is called, is typeset in a box of width \glossaryrmarg. If you have large references and don't increase this length, you'll rightfully obtain overfull \hbox warnings. In case you prefer long references to protrude to the left into the item description, you can get rid of the fixed-width box by redefining \glosspagenum this way (we still put the reference #1 inside an \mbox to make sure it doesn't get broken across lines, but this box has the reference's natural width). Here is how to do so:

\newcommand*{\glosspagenum}[1]{%
  \unskip
  \begingroup
    \normalfont\normalcolor\mindotfill
    % Set \parfillskip *locally*. The locality of this change is useful
    % in case the next paragraph doesn't end with \glosspagenum.
    \parfillskip=-\glossaryrmarg\relax
    \kern.5em
    % Prevent line break and protrusion of reference into the right margin
    \mbox{#1\kern-1pt\kern1pt}%
    \par
  \endgroup
}

Unboxed reference screenshot

Final version

The last change is probably an improvement, however there is still a little problem due to the fact that our \mindotfill is based on \dotfill, which uses \cleaders, which are not of the aligned kind. This implies that dots placed by such leaders (\cleaders or \xleaders) are unlikely to be vertically aligned, unless by sheer luck—it's easy to notice if you change our \mindotfill so as to increase the space between two consecutive dots, for instance by copying there the replacement text of \dotfill before changing it.

This annoyance does not happen for dots in the table of contents. This is because the \@dottedtocline macro uses aligned leaders produced via \leaders inside a suitably left-aligned enclosing box. So, let's modify our \mindotfill macro to use aligned leaders this time, and while we are at it, to give the same spacing between dots as in the table of contents. Let's also test the case where an item has no reference (i.e., doesn't end with a call to \glosspagenum) or is made of several paragraphs.

Finally, we can use enumitem's \newlist and \setlist macros to define our own environment which we'll call myglossary. This ensures that all parameters we pass to enumitem for this type of glossary are set in one well-defined place, which facilitates code reuse and implementation changes. Note that this requires us to use eight hash signs (#) in a row instead of two, presumably due to the number of \def (or \newcommand, etc.) calls done within each other when using \setlist. In other words, this:

\begin{document}

(...)

\begin{description}[<options>,
                    before={\renewcommand\makelabel[1]{\commalabel{2cm}{##1}}}]
(...)
\end{description}

becomes this:

\newlist{myglossary}{description}{1}
\setlist[myglossary]{<options>,
                     before={\renewcommand\makelabel[1]{\commalabel{2cm}{########1}}}}

\begin{document}

(...)

\begin{myglossary}
(...)
\end{myglossary}

There will remain one slightly subtle trick that we'll explain below: the \kern-1pt\kern1pt used inside \mbox in the definition of \glosspagenum. Here is the code:

\documentclass{article}
\usepackage{enumitem}

\usepackage{lipsum}

\newlength{\commalabelwd}
\newcommand{\commalabel}[2]{%
  \settowidth\commalabelwd{\normalfont\itshape#2,\hspace{\labelsep}}%
  \normalfont\itshape#2\ifdim#1<\commalabelwd,\fi\hfill
}

\makeatletter
\newcommand*{\mindotfill}[1][1cm]{%
  \nolinebreak
  \leavevmode \leaders         % aligned leaders (unlike those in \dotfill)
  % Same spacing between dots as in the table of contents
  \hbox{$\m@th \mkern\@dotsep mu\hbox{.}\mkern \@dotsep mu$}%
  \hskip #1plus 1fill \kern 0pt % at least #1 worth of dots
}
\makeatother

\newlength{\glossaryrmarg}
\setlength{\glossaryrmarg}{2em} % width of the right-most column

\newcommand*{\glosspagenum}[1]{%
  \unskip
  \begingroup
    \normalfont\normalcolor\mindotfill
    % Set \parfillskip *locally*. The locality of this change is useful
    % in case the next paragraph doesn't end with \glosspagenum.
    \parfillskip=-\glossaryrmarg\relax
    \kern.1em
    % Prevent line break and protrusion of reference into the right margin
    \mbox{#1\kern-1pt\kern1pt}%
    \par
  \endgroup
}

% Our 'myglossary' environment
\newlist{myglossary}{description}{1}
\setlist[myglossary]{
  labelwidth=\dimexpr2cm-\labelsep,
  leftmargin=2cm,
  rightmargin=\glossaryrmarg,
  before={\renewcommand\makelabel[1]{\commalabel{2cm}{########1}}}
}

\begin{document}
\noindent
\hrulefill  % Show a full \linewidth (equal to \textwidth in this case)

\begin{myglossary}
\item[Short] \lipsum[1][1-2]\glosspagenum{3}

\item[Longer] \lipsum[1][1-3]\glosspagenum{23}

\item[Longerr] \lipsum[1][1-4] abc def ghi jk\glosspagenum{12}

\item[Longerrr] \lipsum[1][1-5]\glosspagenum{221}

\item[Longerrrr] \lipsum[1][1-2]\glosspagenum{789 245}

\item[Longerrrrr] \lipsum[1][1-2]   % this skip will be discarded
\glosspagenum{Extremely long reference}

\item[Longerrrrrr] \lipsum[1][1-2]\glosspagenum{7}

\item[Longerrrrrrr] \lipsum[1][1] This paragraph doesn't end with
  \verb|\glosspagenum|. Foo bar baz.

\item[Longerrrrrrrrrrrrr] \lipsum[1][1-2]\par \lipsum[1][3-4]
  \glosspagenum{Final reference}
\end{myglossary}

\end{document}

Final screenshot

Explanation of the \kern-1pt\kern1pt trick

Decimal digits (0, 1, 2, 3, ..., 9) typically have the same width in common fonts. When using aligned leaders as in the table of contents and in our final version here, this implies that when you have two page numbers containing the same number of digits, the last dot printed on their left (and others before) will be vertically aligned. For instance, pages 4 and 7 on the one hand, pages 21 and 85 on the other hand, compare nicely when you look at the dots printed before them, because 4 has the same width as 7 in typical fonts, and 21 the same as 85. But one typographical feature of modern TeX engines goes against this nice machinery: character protrusion.

Due to their particular shape, some characters may be allowed to protrude a tiny bit into the right margin, so that our poor {eye, brain} system thinks they are better aligned this way with other characters that are also flush to the right margin. This is a kind of illusion. pdfTeX has been capable of doing this for many years. But the consequence of such a behavior in what we described concerning dots alignment ruins it all, because if \mbox{#1} is shifted even a tiny bit to the right because of the particular shape of the last digit in #1, there will be more space available on its left, which leaves room for possibly more dots (at most one more, unless dots are crazily close to each other). That would look weird: one more dot would fit before a reference that wouldn't fit before another reference, with both references having the same number of digits. By using \mbox{#1\kern-1pt\kern1pt} instead of \mbox{#1} in \@dottedtocline and \glosspagenum, we prevent the TeX engine from realizing that the rightmost visible thing in the \mbox is the last digit of #1; then all such boxes are very precisely flush to the right margin, which preserves the desired property loosely described as “same-width references have the same dots on their left.”

Explanation of the \kern 0pt in \mindotfill

The reason for using \kern 0pt in \mindotfill is the same as for \dotfill: see this question (my answer here).

  • there is a small problem: the reference can be wider that the right column (e.g. "123,124" or +12-15", or a ref to another notes "ST 12") I think the toc manage this problem; that is the right margin is fine, but then the box for the reference is of variable length and aligner on the right. – PeptideChain May 18 at 20:21
  • We can fix it if you tell precisely how you want it to behave, but the way I implemented it is very close to toc. In toc, the page number is typeset inside an \hbox of width \@pnumwidth, which is 1.55em in the article class. Here, this role is fulfilled by \glossaryrmarg, you can of course increase it, but we could also get rid of the box if desired (large reference texts would then protrude into the description...). – frougon May 18 at 20:28
  • 1
    1) I added an alternative implementation of \glosspagenum that doesn't put the reference inside a box. But it does protrude into the description if the reference is too long, because the excess width has to go somewhere. 2) You're mistaken about the #3 of \@dottedtocline. That parameter is not for the page number, but for the section/subsection/etc. number on the left of a title, for a numbered line (one that has \numberline). AFAIK, the part on the right (page number) behaves as the implementation in my full example. But the \@pnumwidth is probably large enough by default... – frougon May 18 at 20:45
  • 1
    I modified the alternative \glosspagenum because it wasn't quite satisfactory when the reference contains valid breakpoints (such as interword spaces). I also added a small kern (0.5em) so that the dots aren't stuck to the reference in this implementation. – frougon May 18 at 21:20
  • 1
    Thanks for your comments. I added an explanation of the \kern-1pt\kern1pt trick (plus small code improvements: see the edit history of the answer). – frougon May 19 at 10:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.