Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

How can I create a list in which a rule is automatically inserted between each pair of items?

share|improve this question
add comment

2 Answers 2

up vote 3 down vote accepted

An alternate method that you can use is to redefine \item. This is not necessarily a better solution in this case, but you don't need to rely on the internals of other packages. I use a modified version of the rule that @Werner defined in his solution, but that can be adjusted as desired.

Here I use etoolbox to handle the condition that we do not want to apply the rule above the very first \item. I prefer this method of handling conditions, but any other method for conditional typesetting / build can be used as well.

First step is to save the original definition of item

\let\OriginalItem\item% 

Now using this we can define our own version of item:

\newcommand{\ItemWithRuleAbove}{%
    \iftoggle{IsFirstItem}{}{\WernersHRule}% only add \hrule if not first item
    \OriginalItem%
    \togglefalse{IsFirstItem}%
}%

where:

  1. if this is not the first item, we add the rule,
  2. apply the original definition of item, and
  3. toggle the IsFirstItem so that we know for next time that a rule is to be applied.

Using this definition we can create our own MyEnuterate environment that has this behaviour (assuming you don't want this all the time):

\newenvironment{MyEnumerate}{%
    \toggletrue{IsFirstItem}%
    \let\item\ItemWithRuleAbove%
    \begin{enumerate}%
}{%
    \end{enumerate}%
}%

within this environment we redefine \item to use \ItemWithRuleAbove as opposed to the original \item. At the beginning of this environment we toggle IsFirstItem to true so that it is initialized for this instance of MyEnumerate.

enter image description here

Code:

Enumerated content copied directly from @Werner's solution:

\documentclass{article}
\usepackage{etoolbox}

\newtoggle{IsFirstItem}% so we don't add rule above first item
\toggletrue{IsFirstItem}% personal preference: initialize variables explicetly at time of defintion

\newcommand*{\WernersHRule}{% Slightly Modified
   \par\kern\dimexpr.7\itemsep-\parskip-.6\baselineskip\relax%
   \hrulefill%
   \par\kern\dimexpr.3\itemsep-.3\parskip-.6\baselineskip\relax%
}%


\let\OriginalItem\item% store existing definition of \item
\newcommand{\ItemWithRuleAbove}{%
    \iftoggle{IsFirstItem}{}{\WernersHRule}% only add \hrule if not first item
    \OriginalItem%
    \togglefalse{IsFirstItem}%
}%

\newenvironment{MyEnumerate}{%
    \toggletrue{IsFirstItem}%
    \let\item\ItemWithRuleAbove%
    \begin{enumerate}%
}{%
    \end{enumerate}%
}%


\begin{document}
\begin{minipage}{.45\linewidth}
\begin{MyEnumerate}
  \item An item with descender p
  \item An item without descenders
  \item abcdefghijklmnopqrstuvwxyz
\end{MyEnumerate}
\end{minipage}
%
\begin{minipage}{.45\linewidth}
\begin{enumerate}
  \item An item with descender p
  \item An item without descenders
  \item abcdefghijklmnopqrstuvwxyz
\end{enumerate}
\end{minipage}
\end{document}
share|improve this answer
add comment

The standard list structures (itemize and enumerate) is made up as a \list. At the start of this \list, a condition \@newlist is set to true (via \global\@newlisttrue). This separates the first item from the rest in terms of the vertical space inserted. Here's an extract from the conditioning within \@item in latex.ltx:

\if@newlist
  \if@nobreak
    \@nbitem
  \else
    \addpenalty\@beginparpenalty
    \addvspace\@topsep
    \addvspace{-\parskip}%
  \fi
\else
  \addpenalty\@itempenalty
  \addvspace\itemsep
\fi

So, based on this, \itemsep is only inserted if we're not \@newlist.

Using etoolbox one can now patch \@item and modify \addvspace\itemsep to insert a "decoration":

enter image description here

\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/xpatch
\begin{document}
\noindent%
\begin{minipage}{.45\linewidth}
\begin{enumerate}
  \item An item with descender p
  \item An item without descenders
  \item abcdefghijklmnopqrstuvwxyz
\end{enumerate}
\end{minipage}
%
\makeatletter
\patchcmd{\@item}
  {\addvspace\itemsep}
  {\par\kern\dimexpr.7\itemsep-.7\parskip-.7\baselineskip\relax%
   \hrulefill%
   \par\kern\dimexpr.3\itemsep-.3\parskip-.3\baselineskip\relax}
  {}{}%
\makeatother
%
\begin{minipage}{.45\linewidth}
\begin{enumerate}
  \item An item with descender p
  \item An item without descenders
  \item abcdefghijklmnopqrstuvwxyz
\end{enumerate}
\end{minipage}
\end{document}

On the left is a regular list, while the right shows the same list with the modified \itemsep.

If you want the \hrulefill to stretch the entire \textwidth (rather than \linewidth), you can use

\makeatletter
\patchcmd{\@item}
  {\addvspace\itemsep}
  {\par\kern\dimexpr.7\itemsep-.7\parskip-.7\baselineskip\relax%
   \hspace*{\dimexpr-\itemindent-\labelwidth-\labelsep}\hrulefill%
   \par\kern\dimexpr.3\itemsep-.3\parskip-.3\baselineskip\relax}
  {}{}%
\makeatother

which corrects for the \itemindent, \labelwidth and \labelsep inserted in the list.

The choice of a 70%/30% skip across the horizontal rule is somewhat arbitrary, but based on the definition of \strutbox. Together, they make up the entire \itemsep.

share|improve this answer
2  
nice approach. But I would keep the \addvspace. After all, if the previous item ended in a vertical skip for some reason you want the maxium of both skips not the addition. So perhaps start the patch code with \addvspace\itemsep\vskip-\itemsep followed by your code. Also using \kernmeans you are dropping stretch and shrink and "perhaps" one would like to retain that at least above the rule. –  Frank Mittelbach Feb 11 '12 at 17:43
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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