Time for revenge! I've been fighting with this problem of aligning items according to the longest label automatically for some time now (see first two examples below). The left side of the longest label matches the beginning of the paragraphs (\parindent
). It's not common situation but it looks fine in documents I polish. The authors use it for abbreviations of hypothesis, conditions, properties, theorems, you name it.
The common option is to set up the type of item manually by \begin{itemize}[Example a)]
via the enumerate
package. Or with the help of \leftskip
dimension written directly into an environment.
In production I hadn't used LuaTeX (callback) as I wasn't able to program it. I probably could transform that environment into a table, but I would expect a lot of troubles. I wasn't aware of the environ
package at that time, therefore I used a heavy hammer:
- At a Lua level I select
itemize
environments one by one from a TeX file (regular expressions). - Then I select all the labels from the
\item[label]
commands and create a new TeX file with a series of\measureme{label}
commands (Lua). - I load that file by an external TeX file (
\input
) and find the longest label plus I store that dimension via\message
command in the log file. - I parse that log file by Lua and I add
\leftskip
to thatitemize
environment before the first occurence of\item[]
.
It's rather slow, ineffective, but it works. I care about the first level itemize
, not about higher levels as they are rare in documents I polish (in other words there is no need to add \leftskip
there).
This procedure doesn't handle nested itemize
well, but I could improve it by deleting inner itemize
environments after Step 1 once I handle balanced itemize
selection (e.g. by using LPeg or replacing \begin{itemize}
and \end{itemize}
by a single unused character, e.g. \002
and \003
, I successfully tried that for the first time here). After that step, only \item
s of the actual level of itemize
remain untouched for further analysis. That's my ToDo.
I was thinking if there is an easier way how to handle this alignment. This is my try with the help of environ
package. The idea is to process the content of itemize
twice:
- During the first run the algorithm should measure labels and pick up the longest one (virtual typesetting in a box).
- During the second run the algorithm should use
\leftskip
to alter environment (real typesetting).
I enclose a minimal working example. It would suit me well. It processes the first level of itemize
as shown in the example. But we are getting error messages if we try to process nested environments. Please comment out the first \end{document}
command to see a minimal non-working example (I turned on \nonstopmode
to get some PDF). I was thinking to add \ifnum
and a level of itemize
, but I haven't tried that, yet. We run any LaTeX engine, e.g. lualatex mal-example.tex
.
There might be completely different approach from mine how to handle this sort of alignment. Is there any?
% *latex mal-example.tex
\documentclass[a4paper]{article}
\pagestyle{empty}
\usepackage{environ}
\let\olditemize=\itemize % original \begin{itemize}
\let\endolditemize=\enditemize % original \end{itemize}
\let\olditem=\item % original \item command
\newdimen\measureme % for storing maximum width of item labels
\RenewEnviron{itemize}{% redefinition of itemize environment
\measureme=0mm% set maximum width to zero, initial value
\def\item[##1]{\setbox0=\hbox{##1}% redefinition of \item
\ifdim\wd0>\measureme % getting the maximum value
\global\measureme=\wd0 % store the width maximum
\fi % End of \ifdim...
}% End of redefinition of \item.
\setbox1=\hbox{\BODY}% measure labels virtually
\setbox1=\hbox{\enspace}% measuring space
\advance\measureme by -\wd1\relax % width of space
\let\item=\olditem% Back to common \item.
\begin{olditemize}% common itemize + \leftskip - width of space
\leftskip=\measureme % aproach I use
\BODY % common typesetting of \items...
\end{olditemize}
}% End of redefinition of the itemize environment.
\begin{document}
Text before. Text before. Text before. Text before. Text before. Text before. Text before. Text before. Text before. Text before. Text before. Text before. Text before. Text before.
\begin{itemize}
\item[(malabc)] First item.
\item[(longer one)] Second item.
\item[(3rd)] Third item.
\end{itemize}
Text in the middle. Text in the middle. Text in the middle. Text in the middle. Text in the middle. Text in the middle. Text in the middle.
\begin{itemize}
\item[(cond1)] First item.
\item[(cond11)] Second item.
\item[(cond111)] Third item.
\end{itemize}
\end{document} % to be commented out
Additional text. Additional text. Additional text. Additional text. Additional text. Additional text. Additional text. Additional text. Additional text. Additional text.
\nonstopmode
\begin{itemize}
\item[(a)] First item.
\item[(b)] Second item.
\begin{itemize}
\item[(cba)] First item.
\item[(abc)] Second item.
\item[(cab)] Third item.
\end{itemize}
\item[(c)] Third item.
\end{itemize}
\end{document}