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.

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.)

share|improve this question
4  
+1 for the 'insanity' of the question! :) –  Count Zero Oct 20 '11 at 18:40
5  
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
2  
@JuanA.Navarro: Start here. –  Martin Schröder Oct 28 '11 at 16:56

5 Answers 5

up vote 21 down vote accepted

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%
    \global\advance\@nl@rlevel by 1
    \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}
share|improve this answer
2  
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
4  
You really seem to like @. –  Martin Schröder Oct 27 '11 at 17:05
1  
@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}%
  \def\subitem{\par\noindent\quad\textasteriskcentered\enspace\ignorespaces}%
  \def\subsubitem{\par\noindent\qquad-\enspace\ignorespaces}%
  \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.

share|improve this answer
1  
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
1  
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\narrower{\advance\leftskip by\parindent
\advance\rightskip by\parindent}
\def\wider{\advance\leftskip by-\parindent
\advance\rightskip by-\parindent}


\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!

share|improve this answer
    
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

enter image description here

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()}}

\unexpanded\def\readtranslatedfile#1%
  {\enableinputtranslation
   \readfile{#1}\donothing\donothing
   \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).

enter image description here

share|improve this answer

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.

share|improve this answer
3  
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

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.