% You'll get 39 warnings if you run this document % in pdf, because of the $\diamond$ I inserted in % the toc and which hyperref doesn't like. Don't % worry, it'll work fine anyway. \documentclass[a4paper]{article} \usepackage[T1]{fontenc} \usepackage[textwidth=16cm,textheight=26cm]{geometry} \usepackage{xcolor} \usepackage{fancyvrb} \usepackage{easylist} \usepackage[pdfborder={0 0 0}]{hyperref} \let\ref\autoref \title{\Example{12}{\bfseries The \texttt{easylist} package for numbered items}} \author{Paul Isambert\\ \texttt{zappathustra@free.fr}\\ \texttt{http://paulisambert.free.fr}} % Some shorthands \newcommand{\deepred}{red!80!black} \newcommand{\vs}{\vspace{1ex}} \newcommand{\n}{\emph{n}} \newcommand{\Arg}[1]{\texttt{\emph{<#1>}}} \newcommand{\param}[2]{\noindent\textcolor{\deepred}{\textbullet\ \texttt{#1=\Arg{#2}}}} \newcommand{\style}[1]{\noindent\textcolor{\deepred}{\textbullet\ \texttt{#1}}} % Colors \definecolor{Exemple}{rgb}{1,1,.8} \definecolor{Frame}{rgb}{1,.3,.3} % To put the name of the parameters is % a colored box in the margin. \newif\ifMargin \def\NewLine{% \ifMargin% \\% \else% , % \fi} \newlength{\marginlength} \newcommand{\Note}[2][X]{% \if#1X% \settowidth{\marginlength}{\texttt{#2}}% \else% \settowidth{\marginlength}{\texttt{#1}}% \fi% \Margintrue% \marginpar{% \fboxrule1pt\vspace{-2.2ex}\raggedleft% \fcolorbox{black}{gray!50!white!90!red}{% \parbox{\marginlength}{\raggedleft\ttfamily #2}}} \Marginfalse% \phantomsection% \addcontentsline{toc}{subsubsection}{$\diamond$ \texttt{#2}}} \reversemarginpar % To create the boxes for code and examples. \newcommand{\Code}[2]{% \vs\begin{center}% \noindent\fboxrule1pt \fcolorbox{Frame}{Exemple}{% \begin{minipage}{#1cm}% \ttfamily% \noindent$\backslash$begin\{easylist\}\\% #2% $\backslash$end\{easylist\}% \end{minipage}}% \end{center}% } \newcommand{\Example}[2]{% \vs\begin{center}% \noindent\fboxrule1pt% \fcolorbox{Frame}{Exemple}{% \begin{minipage}{#1cm}% #2% \end{minipage}}% \end{center}} % To change how sections look. % The redefinition of \section % comes after \tableofcontents, % otherwise it messes with it. \let\NormalFont\normalfont \let\ssubsection\subsection \renewcommand{\subsection}[1]{% \let\normalfont\sffamily% \ssubsection{#1}% \let\normalfont\NormalFont} \let\ssubsubsection\subsubsection \renewcommand{\subsubsection}[1]{% \let\normalfont\sffamily% \ssubsubsection{#1}% \let\normalfont\NormalFont} % To handle code implementation. % \VI skips a line while \VI doesn't % (useful when commenting inside a def). \DefineShortVerb{\+} \fvset{numbers=left,tabsize=2} \newcounter{easylistFirstLine} \newcounter{easylistSecondLine} \makeatletter \def\VI{\@ifstar{\VIstar}{\VInostar}} \makeatother \def\VIstar#1.{% \addtocounter{easylistFirstLine}{1} \setcounter{easylistSecondLine}{\theeasylistFirstLine} \addtocounter{easylistSecondLine}{#1} \addtocounter{easylistSecondLine}{-1} {\color{\deepred}% \VerbatimInput[firstline=\theeasylistFirstLine,lastline=\theeasylistSecondLine]{easylist.sty}} \setcounter{easylistFirstLine}{\theeasylistSecondLine}} \def\VInostar#1.{% \addtocounter{easylistFirstLine}{2} \setcounter{easylistSecondLine}{\theeasylistFirstLine} \addtocounter{easylistSecondLine}{#1} \addtocounter{easylistSecondLine}{-1} {\color{\deepred}% \VerbatimInput[firstline=\theeasylistFirstLine,lastline=\theeasylistSecondLine]{easylist.sty}} \setcounter{easylistFirstLine}{\theeasylistSecondLine}} \begin{document} \maketitle \begin{abstract}This package is designed for typesetting lists of numbered items (like Wittgenstein's \textit{Tractatus} or---more likely---the outline of a work yet to be done) with a single active character acting as the only command. Various options are available to achieve greater control over the general appearance of the list.\end{abstract} \setcounter{tocdepth}{5} \Example{14}{\tableofcontents} \let\ssection\section \renewcommand{\section}[1]{% \let\normalfont\sffamily% \ssection{#1}% \let\normalfont\NormalFont} \section{Choosing the symbol} Here's what the \LaTeX\ code with +easylist+ in its default usage looks like: \Code{12}{% \S\ First proposition.\\ \S\S\ Interesting comment.\\ \S\S\S\ A note on the comment.\\ \S\S\S\ Another note.\\ \S\S\S\S\ By the way...\\ \S\S\S\S\S\ This is a subsub...-proposition.\\ \S\ Let's start something new...\\} \vs \noindent And it yields: \Activate\Example{8}{ \begin{easylist} § First proposition. §§ Interesting comment. §§§ A note on the comment. §§§ Another note. §§§§ By the way... §§§§§ This is a subsub...-proposition. § Let's start something new... \end{easylist}}\Deactivate \vs \noindent (No, the pinky box \emph{isn't} part of the package.) Now, the section sign \S\ might not be readily accessible on some (most?) keyboards (although it is accessible and useless on French ones). So you can choose another one instead by setting an option when calling the package (\S\ is default): \Example{8}{\ttfamily$\backslash$usepackage[pilcrow]\{easylist\} \rmfamily to use \textparagraph\\ \ttfamily$\backslash$usepackage[at]\{easylist\} \rmfamily to use \ttfamily @\\ \ttfamily$\backslash$usepackage[sharp]\{easylist\} \rmfamily to use \ttfamily \#\\ \ttfamily$\backslash$usepackage[ampersand]\{easylist\} \rmfamily to use \ttfamily \&} \vs The selected character is made active between +\begin{easylist}+ and +\end{easylist}+ and then returns to its initial value. So when using +#+ for instance, just make sure to define new commands outside the +easylist+, or use the +\Activate+ and +\Deactivate+ commands in your list; as you might have guessed, they make the symbol respectively active and back to its original category. (Ending a list and then beginning a new one will not be noticeable in the final product, so you can interrupt your list to create a new command.) In what follows, I will be using \S, but everything applies to other symbols too.\footnote{You might not be happy with the symbols and maybe you'd like to use another one, or simply have your favorite symbol as default to avoid remembering such a cumbersome name as `pilcrow'. Here's a simple hack that does the job: select the entire code of the package, and replace all occurrences of \S\ with your symbol. Make sure you won't use it in the list for other purposes, though.} \section{Usage} First of all, you have to decide how many counters you need. By default, +easylist+ creates 10 counters, but you might want more, so just specify a number as an option when calling the package: +\usepackage[50]{easylist}+ will create 50 counters. Who knows? this might be useful. You can create as many counters as \TeX\ allows you to. If you exceed its limit, it'll say it. You can also specify a number below 10, if you want less counters to be created. The example above says it all, so let's repeat it: \Code{8}{ \S\ First proposition.\\ \S\S\ Interesting comment.\\ \S\S\S\ A note on the comment.\\ \S\S\S\ Another note.\\ \S\S\S\S\ By the way...\\ \S\S\S\S\S\ This is a subsub...-proposition.\\ \S\ Let's start something new...\\} \vs \noindent Your list must be enclosed between +\begin{easylist}+ and +\end{easylist}+, which is welcome since a character is made active and active characters are notoriously dangerous. As you might have guessed, one \S\ creates a proposition of the first level, two \S's make a proposition of the second level, and so on down to the fifth level. If you concatenate more \S's than available, you'll get an error message telling you to ask for more and the problematic line will begin with \fbox{!!!} instead of numbers. Every sequence of \S's must terminate with a space, otherwise numbers won't be printed. Two things are worth mentioning. First, note that \S\ automatically creates a new line, so typing your propositions in a row will not affect the result. Hence \Example{15}{\ttfamily$\backslash$begin\{easylist\} \S\ First proposition. \S\S\ Interesting comment. $\backslash$end\{easylist\}} \vs \noindent still yields \Activate\Example{8}{ \NewList\begin{easylist} § First proposition. §§ Interesting comment. \end{easylist}}\Deactivate \vs Second, when skipping one or more level(s), that(those) level(s) will be numbered 0 (except otherwise specified---see below), as in: \Code{8}{\S\ First proposition.\\ \S\S\S\ A sub-comment to the first proposition.\\} \vs \noindent which yields: \Activate\Example{8}{\NewList \begin{easylist} § First proposition. §§§ A sub-comment to the first proposition. \end{easylist}}\Deactivate \vs That's it. The following sections deal with labelling and referring and layout options, but for basic purpose you don't need more than that. Predefined style, available with +\begin{easylist}[+\Arg{Style}+]+, are treated in section \ref{style}. \section{Referring to an item} You can use \LaTeX's +\label+, +\ref+ and +\pageref+ to refer to an item. The +\label+ can appear anywhere in the text of the item (affecting only +\pageref+) but if you put it after the row of \S's, make sure there's a space in between, otherwise \S\ won't fire, as mentionned above. The output of +\ref+ is the counters of the item referred to with their original denotation and punctuation but not their original +Style+ or +CtrCom+ (see below), that is they adopt style where +\ref+ is called. Only counters that have not been hidden will appear. \section{Options} Several parameters are available to achieve a finer control over the final output. The general command is +\ListProperties(key=value,key=value...)+, where +key+ is a parameter. +ListProperties+ affects all \emph{subsequent} items and all subsequent lists, wherever it is issued. If you want to set the parameters back to default, use +\NewList+, which can also have an argument (between parentheses like +\ListProperties+) and will then function as +\ListProperties+ if you want to specify again a parameter. Note that you don't need to put all your parameters in the same +\ListProperties+: several +\ListProperties(key=value...)+ have the same effect as a big +\ListProperties+ with all parameters at once. By definition, this is not the case for +\NewList+---which, by the way, I'm using in all examples here, although I show +\ListProperties+ just to make you believe in the illusion of a stand-alone list... \texttt{Parameter\n} affects the \n th counter (e.g. 5 in 14.5.22 is the second counter) or the item of the \n th level (e.g. 14.5.22 is a counter of the third level). I think there isn't much room for ambiguity, and at least the context will make clear what I'm talking about---and if you're still uncertain, well, just try the parameter! If a value contains a comma or a closing parenthesis, you should enclose it between braces or +easylist+ will take them to be delimiters. For instance, if you want a closing parenthesis to be +FinalMark+ (see below), say +\ListProperties(FinalMark={)})+. And if you want to put a framebox anywhere, say for instance +\ListProperties(Style2**={\framebox(5,5){}})+. \subsection{Parameters affecting the \n th counter in an item number} \vs \param{Start\n}{Number} \Note[Start\n*]{Start\n\NewLine Start\n*} makes the \n th counter start at \Arg{Number}, if and only if it immediately precedes an item containing that counter, otherwise it is useless. \param{Start\n*}{Counter} makes the \n th counter dependent on \Arg{Counter}, where \Arg{Counter} is an external counter, like +\thesection+. The counter cannot be controlled anymore and stubbornly follows \Arg{Counter}. To make it back to normal, say \texttt{Start\n*=NA}, which is of course default. \Activate \Example{9}{ \ttfamily $\backslash$begin\{easylist\}\\% $\backslash$ListProperties(Start1*=$\backslash$thesection,Start2=17)\\% \S\ First proposition.\\% \S\S\ Numbering doesn't work.\\% $\backslash$ListProperties(Start2=17)\\% \S\S\ This is better.\\% \S\ Hey, I can't move on!\\% \S\ I must be stuck to an external counter!\\% $\backslash$ListProperties(Start1*=NA)\\% \S\ Okay, it works again.\\% $\backslash$end\{easylist\} \vs\rmfamily \begin{easylist} \ListProperties(Start1*=\thesection,Start2=17) § First proposition. §§ Numbering doesn't work. \ListProperties(Start2=17) §§ This is better. § Hey, I can't move on! § I must be stuck to an external counter! \ListProperties(Start1*=NA) § Okay, it works again. \end{easylist}}\Deactivate \vs \param{Mark}{Punctuation} \Note[FinalMark\n]{Mark\NewLine Mark\n\NewLine FinalMark\NewLine FinalMark\n} sets the punctuation of all counters to \Arg{Punctuation}. \param{Mark\n}{Punctuation} sets the punctuation of the \n th counter to \Arg{Punctuation}. \param{FinalMark}{Punctation} sets the punctuation of the final counter, if specified, for all items. To unspecify it without using +\NewList+, say \texttt{FinalMark\n=NA}. \param{FinalMark\n}{Punctuation} sets the punctuation of the last (i.e. the \n th) counter of the \n th item. To unspecify it without using +\NewList+, say \texttt{FinalMark\n=NA}. The difference between \texttt{Mark(\n)} and \texttt{FinalMark(\n)} is that the latter supersedes the former at the end of the counters numbering an item. In case \texttt{FinalMark(\n)} is set to \texttt{NA}, then \texttt{Mark(\n)} is used in all positions. The default punctuation mark is a full stop, and +FinalMark+ is unspecified (so all item numbers end with a full stop by default). In the following example, note that \texttt{=} followed by nothing is understood as a normal value, albeit empty, and that specifying \texttt{FinalMark3} \emph{after} \texttt{FinalMark} makes the former win. If \texttt{FinalMark3} had appeared \emph{before} \texttt{FinalMark}, then its value would have been superseded. It works the same for all the parameters that follow. There's a final caveat: if you want fixed spaces as marks, you shouldn't use \LaTeX's +\hspace+ but \TeX's original +\hskip+. The former makes it all wrong, and I don't really know why (it doesn't stand being the replacement text of a macro defined with +\edef+ or +\xdef+). You may not be used to +\hskip+, but it's very simple. Instead of +\hspace{1cm}+, for instance, say +\hskip 1cm+. \Activate \Example{9.1}{% \texttt{$\backslash$ListProperties(Mark=.,FinalMark=,FinalMark3=\{)\})} \vs \begin{easylist} \NewList(Mark=.,FinalMark=,FinalMark3={)}) § The world is all that exists... §§ ... said Ludwig to Lizzie... §§§ ... but she wasn't listening. \end{easylist}} \Deactivate \vs \param{Numbers}{Number denotation} \Note[Numbers\n]{Numbers\NewLine Numbers\n} sets the way all counters are printed. \param{Numbers\n}{Number denotation} sets the way the \n th counter is printed. Here are the admissible values: \Example{8}{% \texttt{r} for lower case roman numerals;\\ \texttt{R} for upper case roman numerals;\\ \texttt{l} for lower case letters;\\ \texttt{L} for upper case letters;\\ \texttt{z} for Zapf's Dingbats;\\ \texttt{a} for arabic numbers, which are the default value.} Note that if you choose letters for a given counter, it should not exceed 26, or \TeX\ will complain---and you'll have no number at all. Since I think that using letters with more than, say, 10 items, is ill-advised, I didn't overcome that limitation. \Activate \Example{13.1}{% \ttfamily$\backslash$ListProperties(Numbers2=R,Numbers3=L,Numbers4=r,Numbers5=l,Numbers6=z) \vs\rmfamily \begin{easylist}\NewList(Numbers2=R,Numbers3=L,Numbers4=r,Numbers5=l,Numbers6=z) § I... §§ ... really... §§§ ... like... §§§§ ... numbers... §§§§§ ... however... §§§§§§ ... they are printed. \end{easylist}} \Deactivate \subsection{Parameters affecting numbers and items of the \n th level} \param{Hide}{Number} \Note[Hide\n]{Hide\NewLine Hide\n} hides the first \Arg{Number} counters for all items. It isn't very useful unless you want all counters to be hidden for all items, that is you want lists of unnumbered items, in which case you may say +Hide=100+ (or +Hide=10000+ if you have more than 100 counters!). \param{Hide\n}{Number} hides the first \Arg{Number} counters for items of the \n th level. This is more useful. If $\Arg{Number}>\n$, then nothing is printed. Note that if you refer to an item with hidden numbers, those will not appear when referring to the item with +\ref+. See the example below. \Activate \Example{13.1}{% \ttfamily$\backslash$ListProperties(Hide2=1,Hide3=2,Progressive*=.5cm,Numbers3=l,\\% Numbers4=r,FinalMark3=\{)\}) \vs\rmfamily \begin{easylist} \NewList(Hide2=1,Hide3=2,Progressive*=.5cm,Numbers3=l,Numbers4=r,FinalMark3={)}) § Now, what's the difference with \texttt{enumerate}? asks Leslie. §§ Frankly, I don't know, Don answers. §§§ Should have made it proprietary.\label{example} §§§§ And suddenly all counters reappear... This is ugly! they both exclaim, but they cannot help noticing that referring to the previous item with $\backslash$\texttt{ref} yields \ref{example}. \end{easylist}} \Deactivate \vs \param{Style}{Format} \Note[Style\n**]{Style\NewLine Style\n\NewLine Style*\NewLine Style\n*\NewLine Style**\NewLine Style\n**} sets the style of counters and text for all items. \param{Style\n}{Format} sets the style of counters and text for items of the \n th level. \param{Style*}{Format} sets the style of all counters. \param{Style\n*}{Format} sets the style of the counters of items belonging to the \n th level. \param{Style**}{Format} sets the style of all item texts. \param{Style\n**}{Format} sets the style of the texts of items belonging to the \n th level. Since numbers and texts are enclosed in groups, \Arg{Format} can safely be a command such as +\bfseries+ or +\itshape+, etc., or even +\color{green}+ of the +xcolor+ package. The no-star version interacts freely with the other two (up to (L\kern-.36em\raisebox{.5ex}{\scriptsize A}\kern-.10em)\kern-.15em\TeX's font limitations). Those parameters are actually placeholders in front of the counter or the text of the item (or both in case of +Style+), so you can use them to add nice symbols, for instance. The default style is the style of your document. \Activate\Example{10}{% \ttfamily$\backslash$ListProperties(Style=$\backslash$color\{blue\},Style1*=$\backslash$bfseries,\\% Style2*=$\backslash$itshape,Style1**=$\backslash$scshape\$$\backslash$bullet\$ ,\\ Style1**=\$$\backslash$diamond\$ ,Style3**=\$$\backslash$Rightarrow\$ ,Hide3=3) \vs\rmfamily \begin{easylist} \NewList(Style=\color{blue},Style1*=\bfseries,Style2*=\itshape,Style1**=\scshape$\bullet$ ,Style2**=$\diamond$ ,Style3**=$\Rightarrow$ ,Hide3=3) § A fundamental proposition. §§ An essential comment. §§§ First... §§§ Then... §§§ And we should not forget... \end{easylist}}\Deactivate \vs \param{CtrCom}{Command} \Note[CtrCom\n]{CtrCom\NewLine CtrCom\n} makes \Arg{Command} into a command whose argument is the counters of all items. \param{CtrCom\n}{Command} makes \Arg{Command} into a command whose argument is the counters of items of the \n th level. Note that \Arg{Command} can only be a command taking one token (i.e. possibly a group) as its last argument. Only the bare command must be issued when specifying the parameter. In the following example, +CtrCom=\colorbox{pink}+ thus means +CtrCom=\colorbox{pink}{COUNTERS}+. \Activate\Example{10}{% \ttfamily $\backslash$ListProperties(CtrCom=$\backslash$fbox,CtrCom3=$\backslash$colorbox\{pink\}) \vs\rmfamily\fboxrule.4pt \begin{easylist} \NewList(CtrCom=\fbox,CtrCom3=\colorbox{pink}) § A box is a box is a box... §§ ... said Gertie to Jim... §§§ ... who was looking for Leopold. \end{easylist}}\Deactivate \vs \param{Hang}{Boolean} \Note[Hang\n]{Hang\NewLine Hang\n} lets all item texts hang from their counters if \Arg{Boolean} is +true+. \param{Hang\n}{Boolean} let all item texts of level \n\ hang from their counters if \Arg{Boolean} is +true+. If you don't want texts to hang, set \Arg{Boolean} to +false+, or +F+, or +RDNZL+ or even +True+ for that matter, i.e. anything but +true+. By default, no text hangs from its counter. If you specify +Margin+ or +Progressive+ (see below), the counter will be at the specified distance and the text of the item will be at that distance plus the width of the counter. If you specify +Indent+ (see below again), the first paragraph won't be indented. \Activate \Example{10}{% \texttt{$\backslash$ListProperties(Margin1=1cm,Hang1=true,Indent1=.5cm)}\vs \begin{easylist} \NewList(Margin1=1cm,Hang1=true,Indent1=.5cm) § I'm a nice item with a margin of 1cm for my counter and, well, 1cm plus something else for me. Here I have an indent because I'm a brave new paragraph. \end{easylist} \vs\texttt{$\backslash$ListProperties(Hang1=false)}\vs \begin{easylist} \ListProperties(Hang1=false) § Hey! I'm not hanging anymore! I just have a 1cm margin! And I'm already indented! \end{easylist}} \Deactivate \vs \param{Align}{keyword or dimension} \Note[Align\n]{Align\NewLine Align\n} aligns all item texts at the same level for all levels. \param{Align\n}{keyword or dimension} aligns all item texts of the \n th level. This needs an explanation. Item numbers don't have the same width, even if they belong to the same counter. For instance, the first item of the first level has +1+ as its number, while the 33rd one of the same level has +33+, and obviously +33+ is a wider expression than +1+. So the corresponding item texts won't start at the same horizontal distance, i.e. they wont be aligned. And if texts hang from their counters, the entire left margin will be unaligned, which might be pretty ugly. This parameter is meant to avoid such a situation. If \Arg{keyword} is +move+, then the item number will be moved to the left if it is too large (as in the +enumerate+ environment). If \Arg{keyword} is +fixed+, the +FinalSpace+ (see below), i.e. the space between the item number and the item text, will be shrinked (or stretched) accordingly (as in a table of contents). If it is reduced to nothing and the counter is still too wide, then the counter will spread on the text and you'll get a warning; then you should increase +FinalSpace+ so the \emph{first} counter will be larger and the problematic one will have more room. In both cases, the reference width is the width of the first item counter (of the adequate level, of course) that +easylist+ meets \emph{after} the parameter is set. It is very likely to be +1+, thus a narrow counter. Finally, if you use a \Arg{dimension} instead of a keyword, it has the same effect as +fixed+, except that the reference width is not the width of the first counter of that level but the specified dimension. +FinalSpace+ then becomes useless. Set \Arg{keyword} to anything but +fixed+ and +move+ to turn off this parameter, which by default is not in use. Note that items belonging to different levels aren't aligned with one another. \Activate \Example{9}{% {\ttfamily$\backslash$ListProperties(Hang=true,Margin=1cm,\\FinalSpace=2em)} \vs \begin{easylist} \NewList(Hang=true,Margin=1cm,FinalSpace=2em) § Here is the first item of my very uninteresting yet very convenient list. \ListProperties(Start1=1000) § Here's the 1000th one which obviously isn't aligned with what precedes, although both are on the same level. \end{easylist} \vs {\ttfamily$\backslash$ListProperties(Hang=true,Margin=1cm,\\Align=fixed,FinalSpace=2em)} \vs \begin{easylist} \NewList(Hang=true,Margin=1cm,Align=fixed,FinalSpace=2em) § Here is the first item of my very uninteresting yet very convenient list. \ListProperties(Start1=1000) § Here's the 1000th one which obviously \emph{is} aligned with what precedes. Fortunately, \texttt{FinalSpace} was wide enough. \end{easylist} \vs {\ttfamily$\backslash$ListProperties(Hang=true,Margin=1cm,\\Align=move,FinalSpace=2em)} \vs \begin{easylist} \NewList(Hang=true,Margin=1cm,Align=move,FinalSpace=2em) § Here is the first item of my very uninteresting yet very convenient list. \ListProperties(Start1=1000) § Here's the 1000th one which is also aligned with what precedes, but it would have run out of the box if \texttt{Margin} hadn't been taken care of. \end{easylist} \vs {\ttfamily$\backslash$ListProperties(Hang=true,Margin=1cm,Align=2cm)} \vs \begin{easylist} \NewList(Hang=true,Margin=1cm,Align=2cm) § Hey, my counter is 2cm wide. \ListProperties(Start1=1000) § Mine too. \end{easylist}} \Deactivate \vs \noindent\textsc{A note on dimensions:} the following parameters take \Arg{Dimensions} as values. However, those dimensions should be specified explicitely (e.g. +\ListProperties(Margin=2cm)+) or with a command (e.g. +\newcommand{\mydimension}{2cm}+ and then +\ListProperties(Margin=\mydimension)+), but you should not directly use real \TeX\ dimensions defined with +\newdimen+ (or \LaTeX's +\newlength+), etc. In case you want such dimensions here, you have to prefix them with +\the+. So if you have defined a dimension +\mydimen+, +ListProperties(Margin=\the\mydimen)+ is ok, but not \texttt{$\backslash$ListProperties(Margin=$\backslash$mydi\-men)}. This may sound paradoxical, and indeed it is, but +easylist+ runs some tests on the parameters before \TeX\ gets crazy (you want to avoid 10 error messages when you have 10 counters), and in order to test a dimension, it has to be readable, hence +\the+. \vs \param{Margin}{Dimension} \Note[Margin\n]{Margin\NewLine Margin\n} sets the distance from the left margin at which all items should start. \param{Margin\n}{Dimension} sets the distance from the left margin at which items of the \n th level should start. A negative value doesn't move the left margin to the left, but indents the right margin. \Activate \Example{10}{% \ttfamily$\backslash$ListProperties(Margin2=3ex,Margin3=6ex,Margin4=9ex,\\Margin5=12ex) \vs\rmfamily \begin{easylist} \NewList(Margin2=3ex,Margin3=6ex,Margin4=9ex,Margin5=12ex) § First proposition. §§ Interesting comment. §§§ A note on the comment. §§§ Another note. This is fascinating. We can start a new paragraph at any level and it remains where it should be. §§§§ By the way... §§§§§ This is a subsub...-proposition. § Let's start something new... \end{easylist}}\Deactivate \vs \hangafter0\hangindent=1ex \param{Progressive}{Dimension} \Note[Progressive*]{Progressive\NewLine Progressive*} sets the margin of all items to a distance depending on their level. Namely, items of the \n th level have a margin of $\n\times\Arg{Dimension}$. \hangafter0\hangindent=1ex \param{Progressive*}{Dimension} does the same, except that items of the \n th level have a margin of $\n\times\Arg{Dimension}-\Arg{Dimension}$. This means that items of the first level will be at the current margin and that the progressive indentation will start at the second item. Thus the previous example could have been typeset with: \Activate \Example{10}{% \ttfamily$\backslash$ListProperties(Progressive*=3ex) \vs\rmfamily \begin{easylist} \NewList(Progressive*=3ex) § First proposition. §§ Interesting comment. §§§ A note on the comment. §§§ Another note. This is fascinating. We can start a new paragraph at any level and it remains where it should be. §§§§ By the way... §§§§§ This is a subsub...-proposition. § Let's start something new... \end{easylist}}\Deactivate \vs You can still specify +Margin+ (\emph{after} +Progressive+) if you want some items to be at a specified distance. \vs \param{Space}{Dimension} \Note[Space\n*]{Space\NewLine Space\n\NewLine Space*\NewLine Space\n*} sets the vertical space between items of a different level. \param{Space\n}{Dimension} sets the vertical space between items of the \n th level and previous items belonging to another level. \param{Space*}{Dimension} sets the vertical space between items of the same level. \param{Space\n*}{Dimension} sets the vertical space between items of the \n th level and previous items belonging to the same level. This space is added to the normal space between two lines. You can use a negative value if you want to compact your list. \Activate \Example{8}{% \ttfamily$\backslash$ListProperties(Space2=1cm,Space2*=.5cm) \vs\rmfamily \begin{easylist} \NewList(Space2=1cm,Space2*=.5cm) § Innocent item. §§ What a space! It must be \texttt{Space2}! §§ This one is less impressive. It must be \texttt{Space2*}. \end{easylist}} \Deactivate \vs \param{Indent}{Dimension} \Note[Indent\n]{Indent\NewLine Indent\n} sets the indentation of all paragraphs. \param{Indent\n}{Dimension} sets the indentation of paragraphs belonging to items of the \n th level. \Activate \Example{8}{% \ttfamily$\backslash$ListProperties(Indent2=2cm,Margin2=1cm) \vs\rmfamily \begin{easylist} \NewList(Indent2=2cm,Margin2=1cm) § Here is an unaffected item. §§ Here is a paragraph. Its text is totally silly. But it exhibits a nice indentation. Here's a new paragraph, under the same number. Its text is still silly, but it still has a nice indentation too. \end{easylist} } \Deactivate \vs \param{FinalSpace}{Dimension} \Note[FinalSpace\n]{FinalSpace\NewLine FinalSpace\n} sets the distance between the item number (more precisely, the last mark) and the text for all items. Default is +.3em+. \param{FinalSpace\n}{Dimension} sets the distance between the item number (more precisely, the last mark) and the text for items of the \n th level. This may not be very useful, except when adjusting it to meet the requirements of alignment. In case you set the +Align+ parameter to +fixed+, +FinalSpace+ may be shrinked or stretched. \Activate \Example{8}{% \ttfamily$\backslash$ListProperties(FinalSpace2=1cm) \vs\rmfamily \begin{easylist} \NewList(FinalSpace2=1cm) § The following item wants to be seen. §§ Yes I do. \end{easylist}} \Deactivate \section{Predefined styles}\label{style} You can load some predefined styles with +\begin{easylist}[+\Arg{Style}+]+. They simply issue +\NewList+ with some special values. You can still add +\ListProperties+ to modify them further, and you can still interrupt your list and start it again later, and you don't have to specify +\begin{easylist}[+\Arg{Style}+]+: +\begin{easylist}+ is enough, since it will inherit the properties of the previous one (if it hasn't been +\NewList+'ed, of course). \vs \style{tractatus} is an imitation of Wittgenstein's \emph{Tractatus Logico-Philosophicus}. It's quite simple: +Mark1+ is turned to a dot, and all other marks are turned off. \Activate \Example{8}{% \begin{easylist}[tractatus] § The world is all that exists. §§ If something doesn't exist, it doesn't belong to the world. §§§ Of something that doesn't exist, we should not speak. § I won't speak of things that don't exist. §§ Although they have some appeal to me. §§§§§§ I really can't resist. \end{easylist}} \Deactivate \vs \style{checklist} has no numbers, only check boxes, items are indented according to their levels, and the style of the first level is +\bfseries+. \Activate \Example{8}{% {\begin{center}\large\bfseries Things to do\end{center}} \fboxrule=.4pt% \begin{easylist}[checklist] § Finish the \texttt{easylist} package §§ Find new predefined styles §§ Comment the code §§§ Avoid being verbose and making dumb jokes to hide weaknesses § Tidy up the room \end{easylist}} \Deactivate \vs\style{booktoc} roughly emulates a table of contents according to the +book+ class (without page numbers, of course). Items of the first level are formatted like parts, and so on. Items of the seventh level and higher are not formatted at all. \Activate \Example{15}{% \begin{easylist}[booktoc] § My part §§ My chapter §§§ My wonderful section §§§§ My tremendous subsection §§§§§ My very exciting subsubsection §§§§§§ My delicate paragraph §§§§§§§ My secret subparagraph where everything is unveiled and which goes to the end of the line to show its hanging from the counter §§ My second chapter \end{easylist}} \Deactivate \vs\style{articletoc} does the same for the +article+ class. Items of the first level are sections, etc. Items of the fifth level and higher are not formatted. \Activate \Example{15}{% \begin{easylist}[articletoc] § A very interesting section §§ A subsection that will explain great theories §§§ Here we find a proof §§§§ And a corollary here §§§§§ This paragraph seems really cool \end{easylist}} \Deactivate \vs\style{enumerate} mimicks the +enumerate+ environment as defined in the \LaTeX\ base and +article+ class. Items of the fifth level and higher aren't formatted. \Activate \Example{10}{% \begin{easylist}[enumerate] § I have somehing to say... §§ But I don't know if I can... §§§ This is \texttt{enumerate} made easy... §§§§ Oh yeah, you can spot some differences too, maybe in the separation between items... \end{easylist} \emph{(Two hours later)} \begin{easylist} \ListProperties(Start1=200) § Now that we've come thus far, let's study alignment of items in this emulated \texttt{enumerate} environment. \end{easylist}} \Deactivate \vs\style{itemize} does the same for the +itemize+ environment. \Activate \Example{10}{% \begin{easylist}[itemize] § Hey, this is a bullet. §§ And this is a dash. §§§ Here we have an \texttt{$\backslash$ast} (don't forget the \texttt{\$}'s!). §§§§ And finally a \texttt{$\backslash$cdot}, in case you didn't know. \end{easylist}} \Deactivate \section{Trouble with boxes} Active characters, as is well known, are nasty beings, and it's hard to keep them activated all the way down. That's why the +easylist+ environment in its present state won't work in boxes. That is \Example{8}{\ttfamily $\backslash$fbox\{\%\\ $\backslash$begin\{easylist\}\\ \S\ First proposition.\\ $\backslash$end\{easylist\}\}} \vs \noindent will print: \Example{8}{\fboxrule.4pt\fbox{\begin{easylist}§ First proposition.\end{easylist}}} \vs \noindent where § is the normal value of \S\ (in T1 font encoding). Lists in boxes aren't that common (except for this document), but such a limitation is always annoying. The solution is to make active the character you've chosen to create items just before the box and then turn it back to its initial value. For that purpose, +easylist+ has the two commands +\Activate+ and +\Deactivate+. So here's what you'll do: \Example{8}{\ttfamily $\backslash$Activate\\ $\backslash$fbox\{\%\\ $\backslash$begin\{easylist\}\\ \S\ First proposition.\\ $\backslash$end\{easylist\}\}\\ $\backslash$Deactivate} \vs \noindent and you'll get: \Activate\Example{8}{\NewList\fboxrule.4pt\fbox{\begin{easylist}§ First proposition.\end{easylist}}}\Deactivate \vs Unfortunately, this has to be issued for every box. That is, the following code won't work (even if you surround your command definition with +\Activate+ and +\Deactivate+---I told you that active characters were nasty): \Example{10}{\ttfamily $\backslash$newcommand\{$\backslash$myfbox\}[1]\{$\backslash$Activate$\backslash$fbox\{\#1\}$\backslash$Deactivate\}\\ $\backslash$myfbox\{\%\\ $\backslash$begin\{easylist\}\\ \S\ First proposition.\\ $\backslash$end\{easylist\}\} } \vs Finally, for some boxes, as for instance the +\fbox+ above, a +\NewList+ should be issued at the beginning of the list. Don't ask me why. Instead, avoid +\fbox+es. \section{An example} Now, it so happened that French writer Jacques Roubaud published a book named \textbf{La Dissolution} just as I released the first version of this package (although the book was written in 2000). He uses MS word and has some troubles with the numbered items of which his text is made. I don't know if he knows \TeX\ (he's a retired professional mathematician, so who knows?), but anyway here's an excerpt from the book as a tribute to that coincidence. It's in French. \Example{15.6}{\ttfamily $\backslash$NewList(Style*=$\backslash$footnotesize,Style3=$\backslash$color\{red\},Style4=$\backslash$color\{blue!60!black\})\\ $\backslash$ListProperties(Style5=$\backslash$color\{green!60!black\},Style6=$\backslash$color\{violet\})\\ $\backslash$ListProperties(Style7=$\backslash$color\{yellow!50!brown\},Style8=$\backslash$color\{gray\})\\ $\backslash$ListProperties(Start1=70,Start2=6,Progressive*=2em,Mark= )} \hfil\Activate\fbox{\parbox{11cm}{% \begin{easylist} \NewList(Style*=\footnotesize,Style3=\color{red},Style4=\color{blue!60!black}) \ListProperties(Style5=\color{green!60!black},Style6=\color{violet}) \ListProperties(Style7=\color{yellow!50!brown},Style8=\color{gray}) \ListProperties(Start1=70,Start2=6,Start3=12,Progressive*=2em,Mark= ) §§ Après une heure environ de lecture de choses à lire et de lecture de paysage §§§ m'amenant à découvrir que le Châlons traversé par le train ne se nommait plus, comme dans mon souvenir d'écolier, -sur Marne, mais -en Champagne, réforme onomastique récente qui m'avait jusqu'alors échappé, et avait vraisemblablement obligé les autorités municipales à un intense ``lobbying'' §§§§ il y aura bientôt un Villefranche-en-Beaujolais-nouveau, si Mâcon laisse faire §§§§ je vérifie, à tout hasard, que Reims n'est pas devenu Reims-en-Champagne §§§§§ aucune ville X n'a choisi de se renommer ``X en Champagne Pouilleuse'' §§§§§§ laquelle a été baptisée, pendant que je ne regardais pas, ``Champagne crayeuse'' §§§§§§§ rebaptême qui a vraisemblablement obligé les autorités de quelques groupements d'autorités municipales à un intense ``lobbying'' §§§§§§§§ les progrès du P.C. sont globaux comme l'économie du même adjectif \end{easylist} \hfill (\copyright\ \'Editions Nous)}} \Deactivate \section{Implementation} I'm not used to \textsf{DocStrip} so I input the code by hand with the +fancyvrb+ package. Gaps in line numbering correspond to blank lines in the package. Besides, I'm pretty talkative, so I put the code in red. It will be easier to skip comments. \subsection{Declarations and options} \setcounter{easylistFirstLine}{15} After some commented-out information, here are the usual declarations: \VI2. To process options, we already need conditionals and counts. The first four conditionals and the first count will be used in options, while the remaining conditional and counts are used in the following tests. We also define a convenient shorthand. \VI12. The +\el@NumberCheck+ test is a basic token-by-token test that checks whether a sequence is made of numbers, which unfortunately have no category code of their own. The command takes the next character, compares it to 0, then 1, up to 9, etc. until it matches; if it doesn't the sequence is not a number and +\DubiousFiguretrue+ is output. First, +\el@NumberCheck+ looks whether the next character is +?+, the terminator, in which case the control counter is set to 0, +\e@synext+ (called at the end of the command to create recursion) is deactivated and the command comes to an end. So we can write +\el@NumberCheck 2563?+ and +2563+ will be tested. \VI4. \noindent Then, if the argument is not +?+, but the control counter has reached 10, then the argument is not a number (all figures have been exhausted). The counter is set to 0, the sequence is said doubtful and the rest of it is discarded: \VI*5. \noindent If all figures have not been tried, the argument is compared to the present one, which is the value of the control counter. If it matches, the counter is reset and the command proceeds to the next character. If not, the counter is stepped and the command is called on the same argument: \VI*10. Now we can declare options. When it comes to choosing the symbol, they simply makes some conditional true. The conditional will be used at the end of the package, when we define the environment. \VI4. The remaining (undeclared) option is checked and if it's a valid number (if it passes the test above), then +\el@CounterTotal+, which tells the entire package how many counters, parameters, etc., must be created, is set to its value: \VI*10. We need two more counters for the rest of the package (well, for now): \VI4. \subsection{Basic recursive definitions} Since the number of counters depends on +\el@CounterTotal+, I can't create them in advance, so I designed recursive commands whose purpose is to create other commands in a given amount. The general trick is quite basic: simply use +\easynext+ at the end of the command, which is +\let+ to the command itself if the desired quantity (specified by +\el@CounterTotal+) has not been reached yet, and to +\relax+ otherwise. First, +\Generic@Counter+ creates as many counters as needed. They are named +List1+, +List2+, +List3+, etc., and they are respectively the first, second, third, etc. counter of the final output. It's so simple that we don't need +\easynext+ to create tail recursion. We simply +\expandafter+ the command itself at the end of the conditional, so it jumps the +\fi+. \VI10. +\Generic@Def+ creates the commands that define parameters of the counters, that is +Margin+, +Style+, and so on, once again according to +\el@CounterTotal+. Basically, +\Generic@Def[A]{B}{C}+ will create commands +\B1A+, +\B2A+, +\B3A+, etc., with the definition +C+. The optional argument is needed to handle stars as in +\Start1*+, +\Style2*+, +\Style2**+, etc. (Yes, it would have been much simpler and somewhat more coherent to define and use +\Style**2+ instead of +\Style2**+, for instance. But +\Style**2+ does not please my eye.) Of course, +\Style2**+ is not a valid \TeX\ command, since it does not contain only category 11 characters (i.e. letters), but +\cscommand Style2**\endcsname+ is and I use it throughout the package. First, we check whether there still needs commands. If not, i.e. if the control counter is higher than the number of required levels, then the control counter is reset and the command does not reiterate: \VI4. \noindent If there still needs commands, then one is created whose name depends on the value of the control counter. The +\def+ is global (+\gdef+) because the +easylist+ environment is made of concatenated groups; hence, if +\ListProperties+ is called between +\begin{easylist}+ and +\end{easylist}+, the parameters so defined would be stuck to their groups. Moreover, the +\gdef+ is prefixed with +\expandafter+, otherwise it would try to define +\csname+, which would be a very bad idea. Globality and delay of +\def+ are pervasive in this package. \VI*2. \noindent Once the command is created, the control counter is stepped and the command reiterates: \VI*4. Now we create the default values of the parameters. These are important even if they're empty, because in what follows we'll look for invalid parameters as undefined commands. The command +\el@PreviousItem+ is used for the +Space+ parameter. It records the level of the previous item, and since the first list has no previous item, it is set to 0. +NA+ is the value of a parameter which has to be discarded. \VI18. The +Progressive(*)+ parameter is different, since it creates a different definition for each command (namely the +Margin+ command), so it can't use +\el@GenericDef+. It sets the +Margin+ of each item to $\n\times\Arg{Dimension}$ where \Arg{Dimension} is the argument of the command and \n\ is the level of the item. The starred version simply substracts one argument (which is a dimension) to each +Margin+, which is thus set to $\n\times\Arg{Dimension}-\Arg{Dimension}$, and so items of the first level stay at the current margin. First we need a new conditional and a new dimension: \VI2. +Progressive+ calls +\el@ProgressiveMargin+ and +Progressive*+ calls +\el@ProgressiveMargin*+. It's the same command, but with a different value for the conditional. \VI4. +\el@ProgressiveM@rgin+ does the real job. First, as usual, it checks whether there are enough commands, in which case it resets and stops: \VI4. \noindent If a command must be created, it sets the dimension to the value of the argument and multiply it by the level of that command: \VI*3. \noindent Then, if in the starred version, it substracts one argument to the dimension: \VI*3. \noindent The +Margin+ of the level is set to the value of the dimension. The definition is global for the same reason as above and immediate (+\xdef+) because the value of the dimension is changed at each iteration of +\el@ProgressiveM@rgin+, so we want to store it beforehand. Finally, the dimension is stringed with +\the+ because we want to be able to test it (dimensions are unanalyzable tokens). Actually, it has already been tested when the user called the +Progressive+ parameter. But since it becomes the value of the +Margin+s, and since these are tested after each +\ListProperties+, we want it to be so. \VI*2. \noindent Finally, we step the control counter and reiterate: \VI*4. \subsection{Parameters} In the first (nonrecursive) version of this package, I used the +keyval+ package to set the parameters. But I was not able to use +keyval+ pairs into recursive definitions, so I had to create such pairs myself. This proved rather easy, albeit fastidious and ugly---because the package has to check parameters to process them. I'm nonetheless very happy with that because I was able to taylor more precise tests. +\ListProperties(Arg)+ calls +\el@ListProperties+ on `+A=A,Arg,Z=Z,+' with `+A=A+' to avoid troubles in case of an empty +\ListProperties()+ and `+Z=Z+' as a terminator. Once parameters have been set, it runs some tests on the testable arguments, described below. The values of +Style+ or +Mark+ cannot be tested, of course, because they're so diverse. \VI11. +\NewList+ calls +\el@NewList+ and then +\ListProperties+ if the next character is an opening parenthesis. \VI4. +\el@NewList+ simply sets all parameters back to default and reset all counters. +\el@ResetCounters+ (which needs setting +\el@ControlCounter+ to +0+) is described in section \ref{reset}. Don't worry for +\el@Control+-+Counter+ set to +0+, the tests below bring it back to +1+, its default value. \VI21. Finally, we need keywords to identify parameters without numbers, like +Style+, and some values: \VI25. Here are some shorthands. +^^J+ is the character creating a new line and +==>+ is simply a useless decoration. \VI5. And here comes the ugly definition. Most of the conditionals aren't indented because they amount to exclusive cases, and it's ugly enough. The command takes two parameters delimited by +=+ and a comma at the end (i.e. +Parameter=Value,+), does a lot of testing and if everything is ok assigns +Value+ to +\Parameter+. Roughly speaking. First we reset all conditionals and names issued by tests (see below): \VI9. \noindent Then we set the default value of tail recursion and store the names of the parameter and the value: \VI*3. \noindent If the parameter is equal to +Z+, we redefine tail recursion as +\relax+ so the process comes to an end. If the parameter is +A+, we simply go on, since +A+ is just a placeholder. \VI*3. \noindent Now we use the keywords to catch +Margin+, +Style+, etc., which are not treated like +Margin2+, +Style5+, etc. If the parameter is +Margin+, for instance, we check whether the value is a correct dimension (tests are described in the next section), and in case it is, we launch +\el@GenericDef{Margin}{#2}+, which defines +\Margin1+, +\Margin2+, etc., with the value as their definition. \VI*7. \noindent +Progressive(*)+, +Indent+, +Space(*)+ and +FinalSpace+ behave like +Margin+ and test dimensions: \VI*42. \noindent +Hide+ tests whether its argument is a number. (If you don't understand +\el@Error+, see above, where it's been defined.) \VI*7. \noindent For +Numbers+, we check that the value is a correct number denotation, namely +a+, +r+, +R+, +l+, +L+ and +z+ (which will be turned into commands later on). \VI*8. \noindent For +Align+ and +Hang+, we test whether the value is some keyword, and in the case of +Align+, if it is not a keyword, we test whether it's a dimension. \VI*27. \noindent +Start(*)+ is not allowed without specifying a number, so an error is issued if it appears without one: \VI*6. \noindent Finally, with +(Final)Mark+, +Style(*(*))+, and +CtrCommand+, there's not much we can test, so we just launch a generic definition and hope. \VI*12. \noindent Now, if the parameter is not a keyword, it is either something like +Style2+ or an error from the user. The former is treated below. In the latter case, we put the parameter to the test and issue some error message accordingly: whether it has a wrong name, or a number higher than the amount of counters asked for, or both, or none. We can do that because we define and use parameters as commands with +\csname Parameter\endcsname+. Using +\csname Command\endcsname+ is equivalent to +\relax+ if no such command has been defined (unlike +\Command+ which yields an error message). That's the reason why all parameters have to be defined, albeit sometimes vacuously, as have been done above. So we see whether +\csname Parameter\endcsname+ is equal to +\relax+, and if it is, we test it to see what's wrong: \VI*2. \noindent If it has a wrong name and a wrong number, we say: \VI*4. \noindent If only the name is wrong: \VI*3. \noindent If only the number is wrong: \VI*5. \noindent And finally if none are wrong, as in the case of +Style**2+, which the test cannot detect: \VI*6. \noindent If nothing is wrong, we simply define the parameter as a command with the value as its definition: \VI*2. \noindent And we uglily close that ugly definition and call +\el@CommaKiller+: \VI*2. +\el@CommaKiller+ simply gobbles stray commas to avoid trouble with +\ListProperties(Hide=5,)+, or +\ListProperties(Hide=5,,,,,,,,,Margin=2cm)+ for that matter. If the next character is a comma, it calls +\el@Comm@Killer+, which takes an argument, namely the comma, and does nothing with it but calls +\el@CommaKiller+ again, thus proceeding to the next character. If the latter is not a comma, +\easynext@Properties+ is called, which has been defined as +\el@ListProperties+ or as +\relax+, depending on remaining arguments in +\ListProperties+. \VI2. \subsection{Parametric tests} Here are the tests used on parameter names and values in +\ListProperties+ and +\el@ListProperties+ (hence the bad pun that titles this section). One of them, namely +\el@NumberCheck+, has been defined at the beginning of the package because we needed it to test options. First, we need some conditionals (+\ifDubiousFigure+ was defined with +\el@NumberCheck+) and temporary names: \VI9. First, +\el@DubiousParameter+ is called when +\el@ListProperties+ finds an undefined parameter. I use it simply to give more detailed error messages; I could have let +easylist+ always prompt the same error message, but using packages with this kind of parameters, I sometime get lost with their names. So I think details are welcome in error messages, even if it's not much. Anyway, +\el@DubiousParameter+ scans strings token by token until it meets a +?+. A parameter name is made of letters, numbers, and stars. This test looks for them and lumps them together. For instance, when it meets a letter, it stores it in +\el@Parameter+, which is defined as +\el@P@rameter+ plus the letter, where +\el@P@rameter+ has been +\let+ to +\el@Parameter+ beforehand (watch the +@+'s!), i.e. with its previous value. So first, we +\let+ temporary names and numbers. In case this is the first iteration, they are just empty. We also reset a conditional. \VI4. \noindent In case we meet the terminator, we call the two tests that'll try the parameter and its number (described below). Otherwise, we define +\easynext+ to be the command itself, so it will iterate until the question mark: \VI*4. \noindent Now we look for letters, i.e. characters of category code 11. If we find one, we store it in +\el@Parameter+: \VI*2. \noindent If the character is not a letter, we already test what we have collected as letters. We don't wait for the end of the sequence, otherwise +Sty7le+, for instance, would be analyzed as +Style+ and +7+ and we'd be forced to say that it is wrong but we don't know why. So it just makes error messages a little more efficient: +Sty+ is analyzed and rejected, and then when +Sty+ and +le+ are concatenated, although they will pass the test, the wrong analysis cannot be undone. \VI*2. \noindent Now we look for stars and collect them into the parameter name, just like letters: \VI*2. \noindent Finally, we analyse everyhing else, i.e. characters of category code 12 (or worse!) except stars. When we find such a character, we test whether it's a number: \VI*2. \noindent If it's not, we can already say the parameter name is wrong, since it should contain only letters, stars, and numbers. \VI*2. \noindent If the character is a number, we collect it in +\el@ParameterNumber+, to be tested later. \VI*2. \noindent And we close and call +\easynext+: \VI*4. Now we test what we have gathered. The following two tests output values to conditionals, which are then used at the end of +\el@ListProperties+ (see above), namely whether the parameter has a bad name or a bad number or both or none. The name of the parameter is simply compared to keywords with +\el@ParameterTest+, and if it matches with none, we fire the proper conditional. If the name matches +Progressive(*)+, we turn down bad numbers, otherwise +easylist+ will see `good name, bad number', and say `you don't have so many counters', while actually the problem is that this parameter don't take a number. So +easylist+ will see `good name, good number', say `something's wrong but I don't know what' and politely suggest that maybe you put a number to +Progressive+. (Sorry for the unindented conditionals.) \VI24. Now we test numbers. If there is none, everything's ok, but if there's one and it's larger than the total number of counters (stored in +el@CounterTotal+), then the conditional is launched. \VI7. \subsection{Non-parametric tests} Now we test the values of the parameters (hence, once again, the bad title) before \TeX\ gets crazy. Indeed, if the user say, for instance, +Margin=2+, we want to disable +2+ (which is not a dimension) before \TeX\ tries to put it where it belongs and starts complaining that there lacks a legal unit of measure. Those tests are used in +\ListProperties+ and +\el@ListProperties+ above. \subsubsection{Dimensions} So, first, we devise a test for dimensions. It's a token-by-token test, and that's the reason why dimensions defined with \TeX's +\newdimen+ or \LaTeX's +\newlength+ should be prefixed with +\the+ (they're unreadable otherwise). A dimension is made of at most one plus or minus sign at the beginning, numbers separated by at most one dot or comma for decimals, and two letters which form the unit's name. That's the basis on which we can build our test. First, we define default tail: \VI2. \noindent Then we look for the plus or minus sign. It's ok if we have never encountered one before, in which case the dimension is wrong and we let the test gobble the rest of the sequence. \VI*15. \noindent If the character is not a plus minus sign, then none can appear later: the signs are always at the beginning of a dimension. Thus, as soon as we meet a character which is not a plus or minus sign, we do as if we had encountered one, i.e. with set the corresponding conditional to true. \VI*2. \noindent Then, if we meet the terminator, it means that the dimension is wrong, since dimensions end with letters (the unit) and if letters are met, another test is launched which goes to the end of the sequence (and the terminator). So +\el@UnitSearch+ should never see +?+ with a valid dimension. (We use +\DubiousFiguretrue+, although we're testing dimensions, because that single conditional is enough. We don't need one for numbers, one for units, etc. As long as something is wrong, the dimension is wrong, and I think the user can find out what, contrary to the parametric tests above that were more detailed.) \VI*3. \noindent Next, if we meet a point or a comma, it's ok unless we already met once, in which case the dimension is wrong, and we simply gobble the rest of the sequence: \VI*16. \noindent If we find a letter, we quit +\el@UnitSearch+ for another test. \VI*3. \noindent Now, if the character is none of the above, then its category code is 12. So we test whether it's a number: \VI*2. \noindent If it's not, that doesn't mean that the dimension is wrong. Indeed, if it is a \TeX\ or \LaTeX\ dimension as defined above, then its prefixing with +\the+ turned it into a readable sequence of characters, but they all have category code 12, even letters. So the unit (which is always +pt+) can't be detected by +\ifcat#1a+ above, for the +p+ is not of the same category anymore. So we run a special test: \VI*2. \noindent And we close. The rest is up to the tests that have been called. \VI*7. Before testing units, we need keywords, namely their names. I hope I didn't miss one\footnote{Actually, I missed those same dimensions prefixed with \texttt{true} (see the \emph{\TeX book}, chapter 10), but since there might be any number of spaces, including zero, between \texttt{true} and the unit, it's hard to test. And I think \texttt{true} is hardly used---and one can still define the appropriate dimension beforehand. What, me, reluctant?}: \VI11. Now we simply compare what we've found to those keywords. +\el@UnitCheck+ takes the rest of the sequence (from the first letter found with +\el@UnitSearch+) as its argument. In case nothing matches, then the dimension is wrong (when fed with two commands, +\ifx+ tests whether they have the same expansion). \VI14. Here's the little test for the case letters have turned to category 12. In that case, the unit is +pt+ (dimensions always use +pt+, even if you define them with another unit). The conditional +\if+ compares character codes, not category codes, so it works fine here. If the first character is +p+ and the second is +t+, then we have a valid unit and we can turn off +\ifDubiousFigure+ (which was turned on by +\el@NumberCheck+ in +\el@UnitSearch+ above). \VI6. Now, those tests work fine when we have something like +Margin=2cm+. +\el@ListProperties+ identifies the keyword and runs the test on +2cm+ accordingly. But if we have +Margin3=2cm+, we can't do that: +Margin3+ is not identified, we simply know that it's been already defined and thus it's a valid parameter. But apart from that, we don't know anything---actually, +\el@ListProperties+ doesn't even know it's a +Margin+; it just defines it because its name is ok. So we have to test those parameters after they've been redefined by +\el@ListProperties+. However, we don't know which parameters have been specified, so we must test them all. But we don't know in advance how many of them there are: it depends on the number of counters that the user has asked for. So we need a recursive test, just like we had a recursive definition. That's the meaning of all those +\el@Generic...+ tests appended at the end of +\ListProperties+ above. Here's the generic version of +\el@UnitSearch+. First, we do some cleaning: \VI3. \noindent Then, if the control counter is higher than +\el@Counter++Total+, then we have tested all parameters and we stop: \VI*3. \noindent Otherwise, we take the value of the parameter of the level we're in (according to the control counter). The name of the parameter is made out of the two arguments, the first of which is optional since it is used for stars. So +\el@GenericUnitSearch[*]{Space}+ will test +Space1*+, +Space2*+, etc.: \VI*2. \noindent Then we launch +\el@UnitSearch+. In case we have a invalid dimension, we issue an error message and redefine the command to its default value (unfortunately not its previous value in case the user had already specified one), which is +.3em+ for +FinalSpace+ and +0cm+ for anything else. \VI*17. \noindent Finally, we set the stage for a new iteration: \VI*4. \subsubsection{Number denotation} Here's a test to check that the value of +Numbers+ is valid. Well, it's quite simple, it just compares letters: \VI9. The generic version is exactly the same thing as +\el@GenericUnitSearch+ above, so I don't comment it. It's even simpler since we don't need an argument: only one parameter uses this test. \VI18. \subsubsection{Numbers} Finally we devise a generic version of +\el@NumberCheck+ (defined at the beginning of the package). It concerns +Hide+ and +Start(*)+. The beginning is as usual: \VI4. \noindent We store the value of the parameter, make sure it's not +NA+ (the unspecified value of +Start(*)+), and run +\el@NumberCheck+: \VI*5. \noindent If something's wrong, we issue the appropriate message depending on the name of the parameter and the presence or absence of a star, redefine the command, and close as usual: \VI*22. \subsection{Creating items}\label{reset} Now we can start typesetting items. First of all, we want counters to be properly reset when higher ones are stepped. So +\el@ResetCounters+ sets a scratch counter to the control counter, steps it (because we're interested in those counters that are below the current one) and launch the real job. \VI4. First, if we have done all counters, we stop. \VI4. Otherwise, we set the counters under investigation to 0, conditionally reset its +Start+ value to +NA+ and reiterate. Resetting +Start+ just forces the user to define this parameter before an item containing that counter, which is just security. But we don't want this to happen with an intermediate counter. Indeed, setting for instance the first counter to +10+ just before an item of the \emph{second} level needs to reset the second counter, except when that counter has also just been specified with +Start2+. Now, when building an item's number, +\el@CounterLevel+ represents its level (in our example, it's +2+) and +\el@ControlCounter+ represents the counter we're currently working with (here, +1+). So the conditional does the job: it resets the second counter but not its +Start+ value, in case there is one. \VI*8. We need some simple definitions, including a font definition for Zapf's Dingbats. \VI3. Now, here's the command that handles numbers and their punctuation. It defines +\el@ItemCounter+, to be inserted in the final product. The commands before match the +Numbers+ parameter with \LaTeX\ commands. \VI7. \noindent The definition is twofold: it prints the first numbers, and then the last one, i.e. the \n th one in an item of the \n th level. There are few differences. So, in case we're one of the first counters, i.e. in case +\el@ControlCounter+ is lower than +\el@CounterLevel+ (which basically records how many \S's we've seen), and if +Start*+ for this counter is unspecified (equal to +NA+) but +Start+ is not, then we turn that counter to the value of +Start+, set it back to +NA+ (because we don't want the counter to be stuck to that value), and reset lower counters. Indeed, if you say +\ListProperties(Start1=5)+ and then type \S\S, chances are you want the second counter to start at 1, don't you? \VI*8. \noindent And if +Start*+ is \emph{not} unspecified, first we check if the value has changed: indeed, since +Start*+ is meant to follow an external counter, changing its value will affect lower counters. For instance, if the first counter follows sections, every new section increases it by one and we want the second, third, etc., counters to be reset as with any incrementing of a higher counter. So if the current value of a counter is not equal to the value of its +Start*+ parameter fully expanded, we launch +\el@ResetCounters+. In any case, we set the counter to +Start*+. \VI*8. \noindent Now, if the current counter is higher than +Hide+ for the current level, we print it or rather store it in +\el@ItemCounter+, which before all stores itself, i.e. previous values of itself, so when we reiterate we retrieve everything from the previous iteration. \VI*2. \noindent We store the counter value in a group, because if its +Numbers+ parameter is +z+, we change the font, and we don't want that to spread. \VI*4. \noindent Finally, we put the punctuation mark, close the +\el@ItemCounter+ and the conditional and set the stage for tail recursion: \VI*4. Now, if we're concerned with the last counter of the item, first we increment it and reset all counters below: \VI*3. \noindent Then, as before, we check +Start+ and +Start*+ and act accordingly, except that we don't have to check whether +Start*+ has changed, because counters are reset anyway. \VI*9. \noindent We build +\el@ItemCounter+ just the same except that if +FinalMark+ is specified, we put it instead of +Mark+. \VI*12. \noindent And we stop the iteration and close: \VI*4. Now, for the final big definition, we need two boxes, two dimensions, and a definition which is an imitation of \LaTeX's +\@sptoken+ to define a space, except that I enclosed it in a group here (since +\:+ already exists). It makes +\el@Space+ a space. \VI5. First, we turn +#+ into a normal character because we'll need it in the error message, then we check whether +\elNextToken+, which has been stored by \S\ (see the definition of the +easylist+ environment below), and which represents the next character after the current \S, is a space, in which case we must proceed. We reset +\el@LeftMove+ (see below) and then close a group. Indeed, a group is open after each item number so that the text can have +Style**+ command like +\color{red}+ without affecting the rest of the text. +\begin{easylist}+ has a corresponding +\begingroup+ and +\end{easylist}+ a +\endgroup+. \VI5. \noindent Now, if +\el@CounterLevel+, which is incremented each time a \S\ is followed by another \S\ and which records the level of the item we're building, is higher than the total number of counters asked for, we issue an error message (with the proper symbol, hence the ugly conditional) and replace the item number by boxed exclamation marks. (+^^b6+ is \S\ and +^^a7+ is \textparagraph; this denotation makes the package compatible with Lua\TeX, and it is due to \'Elie Roux.) \VI*7. \noindent If everything's okay, we create a paragraph and add +Space+ or +Space*+ depending on the level of the previous item, which was stored in +\el@PreviousItem+ (+0+ means that there was no previous item). \VI*10. \noindent Then we launch +\el@PrintCounters+ to create +\el@ItemCounter+, and set the working margin to the value of +Margin+ for the current level. \VI*2. \noindent Now we build a box with the counter in full regalia, i.e. nested in its +CtrCom+, accompanied by its +Style(*)+ and with the +FinalSpace+ added at the end of it if not all counters were hidden (since if there's no counter, you don't want a space). The inner pair of braces creates a group that will prevent +Style(*)+ values like +\color{blue}+ from spreading to the text item. \VI*8. \noindent Now we have to checked the +Align+ parameter. If it is +false+, we do nothing, of course. If it is set to +fixed+, we store the width of the box we've just built, and it will serve as our reference width for this level. We turn +Align+ to +alreadyfixed+ for items to come. \VI*5. \noindent If +Align+ is +alreadyfixed+, we rebuild the box, this time setting its width to the reference width and replacing +FinalSpace+ with a glue. \VI*7. \noindent We copy that new box into +\el@ControlBox+ to get the \emph{real} width of the counter, compare it to the desired value, and if it is larger, we issue a warning (but use the box anyway): \VI*9. \noindent If +Align+ is +move+, we store the width of the box once again and set +Align+ to +alreadymoved+. \VI*4. \noindent And if +Align+ is +alreadymoved+, we set a dimension to the width of the current box minus the desired width, i.e. we determine the extra space, which we'll remove when we insert the box. \VI*3. \noindent Finally, if +Align+ is none of the above, it should be a dimension. But we have to be sure of this, so we run +\el@UnitSearch+, and if it's ok, we rebuild the box with the dimension, which we store, and turn +Align+ to +alreadyfixed+. We measure the width one again an issue an warning if the box is overfull. \VI*33. \noindent Now we have to deal with the +Hang+ parameter. If it is on, in case we're in a +alreadymoved+ situation, we add the reference width to the working margin and substract it from +\parindent+; in any other case, we do the same with the current width of the box (which is the same of the desired width if +Align+ is +alreadyfixed+). The net effect of this is to leave room for the item number in the left margin and to move the first line (with +\parindent+) on the left by its width. \VI*8. \noindent If +Hang+ is turned off, we simply set +\parindent+ to value specified by the user: \VI*3. \noindent Finally, we set the left margin, and with +\hangafter0+ we tell \TeX\ to start indenting from the first line on. Then we add the negative space (set to 0pt if +Align+ is not +alreadymoved+) and release the box. The +\if@afterindent+ conditional is set to +true+ to prevent \LaTeX\ from removing indentation after section titles. \VI*3. \noindent We're done with the counter and we must now set the stage for the item text. First, we open a group for the reason above, set +\@currentlabel+ (used by \LaTeX\ to know what should be +\label+'ed with +\label+) to +\el@ItemCounter+ and clear the latter (since it recusively defines itself, see above). \VI*3. \noindent We shape the paragraphs to come by setting +\parindent+ to the value issued by the user (since the first paragraph has already begun with the printing of the counter, hanging items won't be affected) and by repeating the margin with +\everypar+ (since +\hangafter+ and +\hangindent+ are reset after each paragraph). And, of course, we issue the +Style(**)+ of this level. \VI*4. \noindent Finally, we set some values, simply increment the level counter if there was no space after all, close by ignoring spaces so that the distance from the counter to the text will be rigidly fixed by +FinalSpace+, and restore +#+. \VI*7. Here are the predefined styles. There's nothing much to comment. +\elPredefinedStyle+ is called by +\begin{easylist}+ and does nothing if nothing follows. \VI48. Finally, we define the environment. First we turn off +@+ and store the category codes of the symbols to be made active. I could have simply said for instance +\catcode`#=6+ but who knows, catcodes might have been changed by a previous package. +\edef\AtCatcode{\number\catcode`@\relax}+ is useless since we just said +\makeatletter+, but it's for the sake of symmetry. \VI7. Then we make them active to allow a definition that will make them, say, active. \VI5. Now, according to the option loaded with the package, we create the proper environment. For instance, if +@+ was chosen, we make it active in the environment and defines it as follows: it stores the next item in +\elNextToken+ and calls +\elCreateItem+, which will act accordingly. \VI4. \noindent Next +\easylist+ opens a group to match those created by items and launch +\elPredefinedStyles+, while +\endeasylist+ closes a group and add a +\par+ that will ensure that the last item of an +easylist+ is properly formatted. \VI*2. \noindent Finally we define +\Activate+ and +\Deactivate+, which are straightforward. +\AtCatcode+ is +\xdef+'ed because we want the current value category code of +@+, and +\Activate+ might be issued in a group, so we want +\AtCatcode+ to be global. \VI*4. \noindent And we do the same for the other symbols: \VI*47. At last, we restore the original catcodes and say goodbye. \VI5. \end{document}