# Using indentation to automatically begin and end itemize environments

This is a question one might answer with "Why the hell would you want to do it?!", sort of an experiment.

What I am looking for is a way to write lists with many levels of nestings (notes for school) in a "natural" way. Previously, I used an elaborate system of Pandoc, LaTeX and Makefiles to generate notes with occasional LaTeX snippets, however, I would like a more integrated workflow (for example, embedding pseudocode in a codebox environment in a Pandoc/Markdown file is quite challenging, as Markdown was designed with HTML in mind).

If I make + an active character, like

\makeatletter
\mathchardef\@my@mathplus=\mathcode+
\catcode+=\active
\def{+}{\ifmmode\@my@mathplus\else\item\fi}
\mateatother


I can write itemizes like

\begin{itemize}
+ one
+ two
+ three
\end{itemize}


however, I would like to get rid of \begin{itemize} and \end{itemize} and write notes like

+ one
+ subitem one
+ subitem two
+ two
+ three


resulting in the nested list, neatly rendered.

Is there a way to achieve this, or I should consider some kind of pre-procession instead? (Creative and mildly insane answers are appreciated.)

-
+1 for the 'insanity' of the question! :) –  Count Zero Oct 20 '11 at 18:40
Two comments. (1) It's \def+, not \def{+}. (2) It should better be \DeclareRobustCommand+{\ifmmode\@my@mathplus\else\expandafter\item\fi}; apart from robustness, you can write +[label] as you would with \item[label]. Such shortcuts, however, make the document hard to read and unstructured. –  egreg Oct 20 '11 at 20:21
@egreg I didn't really aim for robustness, just a dirty proof of concept. Although thanks for pointing out the mistake with my code (I didn't copy and paste from my text editor but typed it again by hand... my bad). –  Kristóf Marussy Oct 21 '11 at 15:45
ConTeXt can process markdown input directly. –  Martin Schröder Oct 27 '11 at 17:07
@JuanA.Navarro: Start here. –  Martin Schröder Oct 28 '11 at 16:56

Insane answer to an insane question ;)

\documentclass{article}

\def\+{+}

\makeatletter
\catcode\ =12\let\@nl@space= \catcode\ =10
\newcount\@nl@rlevel
\newcount\@nl@llevel
\@nl@llevel=-1

\def\@nl{%
\catcode\ =12
\global\@nl@rlevel=0
\futurelet\@nl@store\@nl@%
}
\def\@nl@gobble#1{\futurelet\@nl@store\@nl@}
\def\@nl@enditemize{
\ifnum\the\@nl@rlevel<\the\@nl@llevel%
\end{itemize}%
\egroup%
\expandafter\@nl@enditemize%
\else%
\ifnum\the\@nl@rlevel=\the\@nl@llevel\else%
\errmessage{Error: inconsistent identation}
\fi%
\fi%
}
\def\@nl@{%
\ifx\@nl@store\@nl@space%
\expandafter\@nl@gobble%
\else%
\catcode\ =10
\ifx\@nl@store+%
\ifnum\the\@nl@rlevel>\the\@nl@llevel%
\bgroup%
\@nl@llevel=\the\@nl@rlevel
\begin{itemize}%
\fi%
\@nl@enditemize%
\item \expandafter\expandafter\expandafter\@gobble%
\else%
\ifx\@nl@store\@nl%
\global\@nl@rlevel=-1\relax\@nl@enditemize\par
\else\space\fi%
\fi%
\fi%
}

\catcode\^^M=\active%
\AtBeginDocument{%
\catcode\^^M=\active%
\let^^M=\@nl%
}%
\catcode\^^M=5
\makeatother

\begin{document}
Some sample text.

+ foo
+ bar
+ a
+ b
+ c. A very long line
split into multiple lines.
+ hehe

Just like nothing happened. Ha!

\+ escaped starting plus

$\lim_{x\to\infty}\frac1x = 0$
\end{document}

-
Surprisingly this really works, and it is yet to explode right into my face, therefore, it is stable enough for my needs. :) –  Kristóf Marussy Oct 21 '11 at 16:01
Okay, it seems to play awfully with Babel (at least with the Hungarian one). Replacing the \AtBeginDocument part with a new environment helps, although. –  Kristóf Marussy Oct 21 '11 at 16:43
You really seem to like @. –  Martin Schröder Oct 27 '11 at 17:05
@MartinSchröder: Better than Knuthian \nlst@re, \nlsp@ce, etc. :) –  Aditya Aug 27 '13 at 5:38

You may need to redefine ^^M to get this feature. That will be somewhat complicated.

As a suggestion, you may use ++ for a subitem, and +++ for a subsubitem. That's much easier:

\documentclass{article}

\makeatletter
\catcode\+\active
\def\itemX{\@ifnextchar+{\subitemX}{\item}}
\def\subitemX#1{\@ifnextchar+{\subsubitemX}{\subitem}}
\def\subsubitemX#1{\subsubitem}
\def+{\ifmmode\string+\else\expandafter\itemX\fi}
\@makeother\+
\makeatother

\newenvironment{easylist}{\trivlist\item
\def\item{\par\noindent\textbullet\enspace}%
\catcode\+\active
}{\endtrivlist}

\begin{document}

\begin{easylist}
+ foo $a+b$
+ foo
++ bar
++ bar
+++ baz
+++ baz
+ foo
\end{easylist}

\end{document}


See also: nicetext package; pandoc tool.

-
Note: After reassigning the category codes of ^^M and space char, there is no essential difficulty to distinguish different level of items through indent. However, it is a bit dangerous to redefine newlines and spaces for normal text. –  Leo Liu Oct 20 '11 at 18:43
Oh, finally I realize that there is a package easylist, which implement what I said. I just reinvent the wheel. –  Leo Liu Oct 21 '11 at 10:29
+1 for "packaged" solution, always preferred. ;-) –  DevSolar Oct 21 '11 at 16:05

This is a bit different rather use two commands, one to narrow the paragraph and another to widen it. I have used \i, \w. The first one to make the paragraph narrower (i.e indent but lose the dotless i and the second the \w for wider.

\documentclass{article}
\usepackage{lipsum}
\parskip12pt

\def\w{\wider}
\def\i{\narrower}

\begin{document}
\lipsum[1]
\i \lipsum[2]
\i \lipsum[2]
\i \lipsum[3]
\w \lipsum[4]
\w \lipsum[5]
\w \lipsum[6]
\end{document}


Advantages, never type more than is necessary! Style to suit!

-
The command \i is already defined. \expandafter\detokenize\expandafter{\i} –  Marco Daniel Oct 20 '11 at 19:10
@MarcoDaniel ... I know that is why I mentioned you lose the dotless i, you don't need a dotless i do you? –  Yiannis Lazarides Oct 20 '11 at 19:14
I didn't read this ;-(. Sorry. Nobody need this ;-) but I thought it is important to mention this. –  Marco Daniel Oct 20 '11 at 19:15
@MarcoDaniel No problem, you only need it if you type turkish texts, I picked it for its mnemonics i.e, indent, then the indentation level stays until you change it. –  Yiannis Lazarides Oct 20 '11 at 19:24

All of the solutions suggested here rely on catcode trickery. LuaTeX provides a sane way to do such input translation. The solution below translates the + at the beginning of line to \firstlevel and ++ at the beginning of line to \secondlevel. So, first lets define the \firstlevel and \secondlevel macros (in ConTeXt)

\define\firstlevel
{\endgraf
\blank
\noindentation
\hangindent=1em
\hangafter\plusone
\dontleavehmode\hbox to 1em {\symbol[1]}}

\define\secondlevel
{\endgraf
\blank[none]
\noindentation
\hangindent=2em
\hangafter\plusone
\null \quad \hbox to 1em {\symbol[2]}}


ConTeXt already have a module m-translate that allows you to translate the input while the file is being read and before the text is passed on to TeX. So, you can do:

\usemodule[translate]
\translateinput[++][\string\secondlevel]
\translateinput[+][\string\firstlevel]

\starttext

+ One
+ Two
+ Three

\enableinputtranslation

+ One, a really long line \input ward
++ Two
+ Three

\stoptext


which gives

The only trouble is that this translates all the + to \firstlevel. The m-translate module does not provide an interface to only match the character at the beginning of the line, but it is a short module, so we can override how the match is done.

In the following code, I have simply copied the m-translate module and changed the translators.translate() function.

\startluacode
local translators = { }

moduledata.translators = translators

local compiled, list = nil, nil

function translators.register(from,to)
local l = lpeg.P(from)/to
if not list then
list = l
else
list = list + l
end
compiled = nil
end

function translators.translate(s)
if list then
if not compiled then
compiled = lpeg.Cs((list)^0*(lpeg.P(1))^0)
end
return compiled:match(s)
else
return s
end
end

local textlineactions = resolvers.openers.helpers.textlineactions

utilities.sequencers.appendaction(textlineactions,"after","moduledata.translators.translate")

function translators.enable()
utilities.sequencers.enableaction(textlineactions,"moduledata.translators.translate")
end

function translators.disable()
utilities.sequencers.disableaction(textlineactions,"moduledata.translators.translate")
end

function translators.reset(s)
translators.enable()
list, compiled = nil, nil
end

translators.disable()
\stopluacode

\unprotect

\unexpanded\def\translateinput
{\dodoubleargument\module_translate_input}

\def\module_translate_input[#1][#2]%
{\ctxlua{moduledata.translators.register(\!!bs#1\!!es,\!!bs#2\!!es)}}

\unexpanded\def\resetinputtranslation
{\ctxlua{moduledata.translators.reset()}}

\unexpanded\def\enableinputtranslation
{\ctxlua{moduledata.translators.enable()}}

\unexpanded\def\disableinputtranslation
{\ctxlua{moduledata.translators.disable()}}

{\enableinputtranslation
\disableinputtranslation}

\protect

\define\firstlevel
{\endgraf
\blank
\noindentation
\hangindent=1em
\hangafter\plusone
\dontleavehmode\hbox to 1em {\symbol[1]}}

\define\secondlevel
{\endgraf
\blank[none]
\noindentation
\hangindent=2em
\hangafter\plusone
\null \quad \hbox to 1em {\symbol[2]}}

\translateinput[++][\string\secondlevel]
\translateinput[+][\string\firstlevel]

\starttext

+ One
+ Two
+ Three

\enableinputtranslation

+ One, a really long line \input ward
++ Two and math $a + b$ works
+ Three

\stoptext


which gives (notice that the + in the math mode has not changed).

-

I had trouble using the previous solutions with beamerposter, so I came up with another. It's a bit of a kludge, but it works for me, and preserves the bullet styles of the beamerposter:

\newcommand{\point}[1]{
\begin{itemize}
\item{#1}
\end{itemize}
}
\newcommand{\subpoint}[1]{
\begin{itemize}
\item[]
\begin{itemize}
\item{#1}
\end{itemize}
\end{itemize}
}
`

Perhaps someone with better code-fu can make this work with active characters instead of my clumsy environment-based way of doing this.

-
Welcome to TeX.SX! I think you misread the question, it is about indention in the source. –  mafp Aug 26 '13 at 22:13
Thanks! As I said, I'm not familiar enough with LaTeX to use the catcode to achieve the desired input syntax. I was just offering part of a solution (how to make a bullet point of arbitrary depth with a single command instead of a nested list). –  user2719544 Aug 27 '13 at 15:13