diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2009, Nicolas Pouillard
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of the copyright holders nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Language/LaTeX.hs b/Language/LaTeX.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX.hs
@@ -0,0 +1,124 @@
+module Language.LaTeX
+  (
+   -- * Types
+   Document
+  ,LineNumber
+  ,CharNumber
+  ,Loc
+  ,Note
+  ,Named
+  ,DocumentClassKind
+  ,DocumentClss
+  ,Star
+  ,Coord
+  ,Percentage
+  ,TexUnit
+  ,LatexLength
+  ,RowSpec
+  ,LocSpec
+  ,Pos
+  ,LatexPaperSize
+  ,Row
+  ,PackageName
+  ,Key
+  ,SaveBin
+  ,LatexState
+  ,TexDecl
+  ,LatexItem
+  ,ParItem
+  ,MathDecl
+  ,AnyItem
+  ,MathItem
+  ,ListItem
+  ,PreambleItem
+  ,DocumentClass
+  ,LatexM
+  ,Encoding
+  -- * Internal types
+  ,Arg
+  ,MathDcl
+  ,AnyItm
+  ,PreambleItm
+  ,TexDcl
+  ,LatexItm
+  ,ParItm
+  ,MathItm
+  ,ListItm
+  -- * Writer type aliases
+  ,TexDeclW
+  ,LatexItemW
+  ,ParItemW
+  ,MathDeclW
+  ,MathItemW
+  ,PreambleItemW
+  -- * Utils
+  ,module Language.LaTeX.Builder.MonoidUtils
+  ,(!$), ($?), (!$?), tell, Writer
+  ,(★)
+  ,Monoid(..)
+  ,printLatexDocument
+  ,ViewOpts(..)
+  ,quickView
+  ,myViewOpts
+  ,testViewOpts
+  ,showLaTeX
+  ,runLatexM
+  )
+where
+import Data.Monoid (Monoid(..))
+import Data.List (intercalate)
+import Language.LaTeX.Types
+import Language.LaTeX.Printer (showLaTeX)
+import Language.LaTeX.Builder.MonoidUtils
+import Language.LaTeX.Builder ((!$), ($?), (!$?), (★))
+import Control.Monad (when)
+import Control.Monad.Writer (Writer, tell)
+import System.Cmd (system)
+import System.FilePath
+import System.Directory (createDirectoryIfMissing)
+import System.Exit
+import qualified System.IO.UTF8 as U
+-- import Codec.Binary.UTF8.String (encodeString)
+
+data ViewOpts = ViewOpts { basedir   :: FilePath
+                         , pdflatex  :: String
+                         , pdfviewer :: String
+                         , inputdirs :: [FilePath]
+                         , showoutput :: Bool }
+
+myViewOpts, testViewOpts :: ViewOpts
+myViewOpts = ViewOpts { basedir   = ""
+                      , pdflatex  = "texi2pdf"
+                      , pdfviewer = "open"
+                      , inputdirs = []
+                      , showoutput = True }
+
+testViewOpts = myViewOpts { basedir = "tests" }
+
+{-
+-- | The computation 'writeBinaryFile' @file str@ function writes the string @str@,
+-- to the file @file@.
+writeBinaryFile :: FilePath -> String -> IO ()
+writeBinaryFile f txt = withBinaryFile f WriteMode (\ hdl -> hPutStr hdl txt)
+-}
+
+quickView :: ViewOpts -> FilePath -> LatexM Document -> IO ()
+quickView vo basename doc =
+     do createDirectoryIfMissing False (basedir vo)
+        when (showoutput vo) $ putStrLn s
+        -- writeBinaryFile (basedir vo </> tex) s
+        U.writeFile (basedir vo </> tex) s
+        exitWith =<< system cmd
+  -- where s = encodeString . either error id $ showLaTeX doc
+  where s = either error id $ showLaTeX doc
+        pdf = basename <.> "pdf"
+        tex = basename <.> "tex"
+        inputdirsStr = intercalate ":" $ inputdirs vo
+        texinputs = "TEXINPUTS=" ++ inputdirsStr
+        bstinputs = "BSTINPUTS=" ++ inputdirsStr
+        cmd = unwords ["cd", basedir vo, "&&"
+                      , texinputs, bstinputs, pdflatex vo, tex, "&&"
+                      , pdfviewer vo, pdf]
+
+printLatexDocument :: LatexM Document -> IO ()
+printLatexDocument = putStr . either error id . showLaTeX
diff --git a/Language/LaTeX/Builder.hs b/Language/LaTeX/Builder.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder.hs
@@ -0,0 +1,1141 @@
+module Language.LaTeX.Builder
+  ( (!$), (!$?), ($?), HaveC(..), HaveL(..), HaveR(..),
+Spaces(..),
+-- * Injecting declarations
+decl, decls, parDecls, parDecl,
+-- * Others
+_AA, _AE, _H, _Huge, _L, _LARGE, _LaTeX,
+_Large, _O, _OE, _P, _S, _TeX, _l, XChar, a4paper, aa,
+acute, addvspace, ae, allTexDecls, appendix,
+article, author, authors,
+bf, bfseries, bigskip,
+bibliography, bibliographystyle, book, boxedminipage,
+caption, caption', cedil, cell, cells, center, chapter, chapter',
+check, circ, cite, cite', cleardoublepage, clearpage, cline,
+comment, compressSpaces, copyright, corrspace, dag, dash1,
+dash2, dash3, date, ddag,
+description, displaymath,
+document, documentclass, dot, dotfill, dquote, em, emph, enumerate,
+fbox, figure, flushleft, footnote,
+footnotesize, framebox, fussy, grave, group, hat, hchar,
+hfill, hline, hr, href, hrulefill, space, hspace, hspace', hspaces,
+hstring, huge, hyphen, hyphenation, hyphenationPar, i, institute, it, item,
+item', itemize, itshape, j, label,
+large, ldots, letter, linebreak, linebr,
+lq, ldq, makebox, maketitle,
+math, mbox, mdseries, medskip,
+minipage, nbsp, negthinspace, newline, rawNewline,
+newpage, nocite, noindent, nolinebreak, nopagebreak, normalfont,
+normalmarginpar, normalsize, num, o, oe, overbar, overdot, pagebreak,
+pageref, pagestyle, para, paragraph, paragraph', parbox, part, part', person, phantom, pounds,
+protect, protector, quotation, quote, raisebox, raisebox',
+rat, ref, report, reversemarginpar, ring, rm, rmfamily, rq, rdq,
+rtext, rule, rule', samepage, savebox, sbox, sc, scriptsize, scshape, section,
+section', sep, setlength, addtolength, settowidth, sf, sffamily, sl, sloppy, sloppypar,
+slshape, small, smallskip, spaceProtector, ss, subparagraph,
+subparagraph', subsection, subsection',
+subsubsection, subsubsection', subtitle, table,
+tableofcontents, tabular, textbf, textdegree,
+textit, textmd, textnormal, textrm, textsc, textsf,
+textsl, texttt, textup, textsuperscript, textsubscript, textunderscore,
+thinspace, thispagestyle, tieafter, tilde,
+tiny, title, titlepage, tt, ttchar, ttfamily, uml,
+underbar, unwords, upshape, usebox, verb, verse, vfill, vline,
+vphantom, vspace, vspace', (★), vbox, vtop, hbox, here, top, bot, bottom, page, normal,
+centered, flushLeft, flushRight, stretch,
+-- * Input Encodings (inputenc package)
+utf8,latin1,inputenc,fromEncoding,
+  )
+  where
+
+
+
+import Prelude hiding (sqrt, min, max, lcm, gcd, log, mod, tanh, cosh, tan, sinh,
+                       sin, cos, succ, sum, pi, mapM, unwords)
+import Data.List hiding (sum, and, group, unwords)
+import qualified Data.List as L
+import Data.Ratio
+import Data.Monoid
+import Data.Char
+import Data.Maybe
+import Data.Foldable (foldMap)
+import Data.Traversable
+import Data.String (IsString(..))
+import Control.Applicative hiding (optional)
+import Control.Monad hiding (mapM)
+import Control.Monad.Error (throwError)
+import Control.Monad.Writer (Writer, execWriter, tell)
+import Control.Arrow
+
+import Language.LaTeX.Types
+import Language.LaTeX.Builder.Internal
+import qualified Language.LaTeX.Length as L
+import Language.LaTeX.Builder.MonoidUtils
+
+
+{-
+import Prelude (writeFile, id, Monad(..), fst)
+import Language.Haskell.TH
+-}
+
+
+-- references: http://dmr.ath.cx/notes/tex.html
+
+(★) :: Star
+(★) = Star
+
+group :: LatexItem -> LatexItem
+group = liftM TexGroup
+
+infixr 0 !$
+infixr 0 $?
+infixr 0 !$?
+
+(!$) :: Monoid b => (a -> b) -> a -> Writer b ()
+(!$) f x = tell $ f x
+
+($?) :: (a -> b) -> Writer a () -> b
+($?) f m = f $ execWriter m
+
+-- NOTE: This combinator seems pretty promising...
+(!$?) :: Monoid b => (a -> b) -> Writer a () -> Writer b ()
+(!$?) f m = tell $ f $ execWriter m
+
+math :: MathItem -> LatexItem
+math = latexCast . mathItem
+
+displaymath :: MathItem -> ParItem
+displaymath = parCast . mathItem
+
+decls :: [TexDecl] -> LatexItem -> LatexItem
+decls ds x = group (rawDecls ds ⊕ x)
+
+decl :: TexDecl -> LatexItem -> LatexItem
+decl = decls . pure
+
+parDecls :: [TexDecl] -> ParItem
+parDecls = para . rawDecls
+
+parDecl :: TexDecl -> ParItem
+parDecl = parDecls . pure
+
+document :: DocumentClass -> PreambleItem -> ParItem -> LatexM Document
+document = liftM3 Document
+
+dash1, dash2, dash3, nbsp :: LatexItem
+dash1 = rawTex "{-}"
+dash2 = rawTex "{--}"
+dash3 = rawTex "{---}"
+
+nbsp = rawTex "{~}"
+-- Do we want to treat '\160' as an nbsp too?
+
+-- | 'sep' is like '{}' in LaTeX, it allows to force letters to be treaten separately,
+-- for instance to separate the two 'f's in shelfful.
+sep :: LatexItem
+sep = group ø
+
+{- GHC bug with OverloadedStrings
+f "" = 1
+f ('a':_) = 2
+f _ = 3
+-}
+
+newtype Spaces = Spaces { countSpaces :: Int }
+
+hspaces :: Spaces -> LatexItem
+hspaces = mbox . hspace . L.em . (1%2 *) . fromIntegral . countSpaces
+
+compressSpaces :: String -> [Either Char Spaces]
+compressSpaces [] = []
+compressSpaces (' ':xs)
+  = uncurry (:) . (Right . Spaces . (+1) . length *** compressSpaces) . span (==' ') $ xs
+compressSpaces (x:xs) = Left x : compressSpaces xs
+
+type XChar = Char -> LatexItem
+
+spaceProtector :: XChar -> String -> LatexItem
+spaceProtector xchar = foldMap (either xchar hspaces) . compressSpaces
+
+protector :: XChar -> String -> LatexItem
+protector = spaceProtector . nlchar
+
+protect :: String -> LatexItem
+protect = protector hchar
+
+-- Turns @'\n'@ into 'newline' and others with the given translator.
+nlchar :: XChar -> XChar
+nlchar _      '\n'  = rawNewline ø
+nlchar xchar  ch    = xchar ch
+
+hchar :: XChar
+hchar = rawTex . rawhchar
+
+ttchar :: XChar
+ttchar ch | isAscii ch &&
+            isPrint ch &&
+            not (isAlphaNum ch)  = rawTex $ "{\\char `\\" ++ ch : "}"
+          | isAscii ch &&
+            not (isPrint ch)     = verb . show $ ch
+          | otherwise            = rawTex [ch]
+
+verb :: String -> LatexItem
+verb = texttt . protector ttchar
+
+-- A comment put in the generated LaTeX document
+comment :: String -> LatexItem
+comment s = latexNote (MkKey "comment") (stringNote s) ø
+
+href :: LatexItem -> LatexItem -> LatexItem
+href x y = latexCmdArgs "href" [mandatory x,mandatory y]
+
+person :: String -> String -> LatexItem
+person name email = href (hstring ("mailto:"++email)) (hstring name)
+
+-- simulate the <hr> html tag
+hr :: LatexItem
+hr = group $ noindent ⊕ rule L.linewidth (L.pt 1.5)
+
+hstring :: String -> LatexItem
+hstring = fromString
+
+
+tableofcontents :: ParItem
+tableofcontents = parCmdArgs "tableofcontents" []
+
+maketitle :: ParItem
+maketitle = parCmdArgs "maketitle" []
+
+-- par = texCmdNoArg "par"
+noindent :: LatexItem
+noindent = texCmdNoArg "noindent"
+
+-- Marginal Notes
+
+reversemarginpar :: TexDecl
+reversemarginpar = texDecl "reversemarginpar"
+normalmarginpar :: TexDecl
+normalmarginpar = texDecl "normalmarginpar"
+
+-- The tabbing Environment
+
+-- TODO
+
+-- Spaces
+
+-- robust
+-- http://www.personal.ceu.hu/tex/spacebox.htm#hspace
+hspace' :: Star -> LatexLength -> LatexItem
+hspace' s = latexCmdAnyArg (starize "hspace" s) . texLength
+
+-- robust
+-- http://www.personal.ceu.hu/tex/spacebox.htm#hspace
+hspace :: LatexLength -> LatexItem
+hspace = hspace' ø
+
+-- fragile
+-- they says that's a command however putting braces around disable
+-- its effect. We expose it as a ParItem since this is its main usage.
+-- http://www.personal.ceu.hu/tex/spacebox.htm#vspace
+vspace' :: Star -> LatexLength -> ParItem
+vspace' s = parCmdArg (starize "vspace" s) . texLength
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/spacebox.htm#vspace
+vspace :: LatexLength -> ParItem
+vspace = vspace' ø
+
+-- http://www.personal.ceu.hu/tex/spacebox.htm#vfill
+vfill :: ParItem
+vfill = parCmdArgs "vfill" [] -- = vspace fill
+
+-- http://www.personal.ceu.hu/tex/spacebox.htm#hfill
+hfill :: LatexItem
+hfill = texCmdNoArg "hfill" -- = hspace fill
+
+dotfill :: LatexItem
+dotfill = texCmdNoArg "dotfill"
+
+hrulefill :: LatexItem
+hrulefill = texCmdNoArg "hrulefill"
+
+thinspace :: LatexItem
+thinspace = texCmdNoArg "thinspace"
+
+negthinspace :: LatexItem
+negthinspace = texCmdNoArg "!"
+
+-- The italic correction space (\/ in LaTeX)
+corrspace :: LatexItem
+corrspace = texCmdNoArg "/"
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/spacebox.htm#bskip
+bigskip :: ParItem
+bigskip = parCmdArgs "bigskip" [] -- = vspace bigskipamount
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/spacebox.htm#bskip
+medskip :: ParItem
+medskip = parCmdArgs "medskip" [] -- = vspace medskipamount
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/spacebox.htm#bskip
+smallskip :: ParItem
+smallskip = parCmdArgs "smallskip" [] -- = vspace smallskipamount
+
+-- http://www.personal.ceu.hu/tex/spacebox.htm#addvspace
+addvspace :: LatexLength -> ParItem
+addvspace = parCmdArg "addvspace" . texLength
+
+unwords :: [LatexItem] -> LatexItem
+unwords = mconcat . intersperse space
+
+-- TODO
+-- unlines:
+-- * does it makes sense?
+-- * given that newline can be forbidden at some places is it safe?
+-- * Why not just a minipage ? . mconcat
+
+-- Fonts
+-- some ref used: http://www.cl.cam.ac.uk/~rf10/pstex/latexcommands.htm
+
+-- Font sizes
+
+-- those could be seen as taking an argument
+tiny, scriptsize, footnotesize, small, normalsize, large,
+  _LARGE, _Large, huge, _Huge, mdseries, bfseries,
+  itshape, slshape, scshape, upshape,
+  rmfamily, sffamily, ttfamily, normalfont :: TexDecl
+tiny         = texDecl "tiny"
+scriptsize   = texDecl "scriptsize"
+footnotesize = texDecl "footnotesize"
+small        = texDecl "small"
+normalsize   = texDecl "normalsize"
+large        = texDecl "large"
+_LARGE       = texDecl "LARGE"
+_Large       = texDecl "Large"
+huge         = texDecl "huge"
+_Huge        = texDecl "Huge"
+
+bfseries = texDecl "bfseries"
+mdseries = texDecl "mdseries"
+rmfamily = texDecl "rmfamily"
+sffamily = texDecl "sffamily"
+ttfamily = texDecl "ttfamily"
+upshape = texDecl "upshape"
+itshape = texDecl "itshape"
+slshape = texDecl "slshape"
+scshape = texDecl "scshape"
+normalfont = texDecl "normalfont"
+
+emph, textrm, textsf, texttt, textmd, textbf,
+  textup, textit, textsl, textsc, textnormal,
+  textsuperscript, textsubscript :: LatexItem -> LatexItem
+-- textXYZ commands should work in math too (use a typeclass)
+emph = latexCmdArg "emph"
+textrm = latexCmdArg "textrm"
+textsf = latexCmdArg "textsf"
+texttt = latexCmdArg "texttt"
+textmd = latexCmdArg "textmd"
+textbf = latexCmdArg "textbf"
+textup = latexCmdArg "textup"
+textit = latexCmdArg "textit"
+textsl = latexCmdArg "textsl"
+textsc = latexCmdArg "textsc"
+textnormal = latexCmdArg "textnormal"
+
+-- http://en.wikibooks.org/wiki/LaTeX/Formatting#Text_mode_superscript_and_subscript
+textsuperscript = latexCmdArg "textsuperscript"
+
+-- http://en.wikibooks.org/wiki/LaTeX/Formatting#Text_mode_superscript_and_subscript
+-- fixltxe2 is not the only package providing textsubscript
+textsubscript x = latexCmdArgs "textsubscript" [packageDependency (pkgName "fixltxe2")
+                                               ,mandatory x]
+
+-- Litteral underscore in text mode
+textunderscore :: LatexItem
+textunderscore = texCmdNoArg "textunderscore"
+
+-- Line and page breaking
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/breaking.htm#linebreak
+linebreak :: Maybe Int -> TexDecl
+linebreak = (texDecl' "linebreak" =<<) . check0to4 "linebreak"
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/breaking.htm#nolinebreak
+nolinebreak :: Maybe Int -> TexDecl
+nolinebreak = (texDecl' "nolinebreak" =<<) . check0to4 "nolinebreak"
+
+-- http://www.personal.ceu.hu/tex/breaking.htm#linebr
+linebr :: Star -> Maybe LatexLength -> LatexItem
+linebr s extraSpace =
+  latexCmdAnyArgs "\\" [starToArg s
+                       ,maybe noArg optTexLength extraSpace
+                       ,rawArg "%\n"]
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/breaking.htm#newline
+rawNewline :: Maybe LatexLength -> LatexItem
+rawNewline mlen =
+  latexCmdAnyArgs "newline" [maybe noArg optTexLength mlen
+                            ,rawArg "%\n"]
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/breaking.htm#newline
+-- see rawNewline for a more permissive dangerous version of newline
+newline :: Maybe LatexLength -> ParItem
+newline = para . rawNewline
+
+-- robust
+-- http://www.personal.ceu.hu/tex/breaking.htm#hyph
+hyphen :: LatexItem
+hyphen = rawTex "{\\-}" -- TODO: check if {...} does not cause trouble here
+                        -- otherwise this may be considered a legit
+                        -- ``concatenation effect''.
+
+-- robust
+-- http://www.personal.ceu.hu/tex/breaking.htm#hyphw
+hyphenation :: [String] -> PreambleItem
+hyphenation = preambleCmdArg "hyphenation" . rawAnyTex . L.unwords -- rawAnyTex is a bit rough here
+
+hyphenationPar :: [String] -> ParItem
+hyphenationPar = parCmdArg "hyphenation" . rawAnyTex . L.unwords -- rawAnyTex is a bit rough here
+
+sloppy, fussy :: TexDecl
+sloppy = texDecl "sloppy"
+fussy = texDecl "fussy"
+
+
+sloppypar :: ParItem -> ParItem
+sloppypar = parEnvironmentPar "sloppypar" []
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/breaking.htm#pagebreak
+pagebreak :: Maybe Int -> TexDecl
+pagebreak = (texDecl' "pagebreak" =<<) . check0to4 "pagebreak"
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/breaking.htm#nopagebreak
+nopagebreak :: Maybe Int -> TexDecl
+nopagebreak = (texDecl' "nopagebreak" =<<) . check0to4 "nopagebreak"
+
+-- fragile
+samepage :: TexDecl
+samepage = texDecl "samepage"
+
+-- robust
+-- http://www.personal.ceu.hu/tex/breaking.htm#newpage
+newpage :: ParItem
+newpage = parCmdArgs "newpage" []
+
+-- robust
+-- http://www.personal.ceu.hu/tex/breaking.htm#clrpage
+clearpage :: ParItem
+clearpage = parCmdArgs "clearpage" []
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/breaking.htm#clrdblpage
+cleardoublepage :: ParItem
+cleardoublepage = parCmdArgs "cleardoublepage" []
+
+--- Boxes
+
+-- TeX level
+-- http://dmr.ath.cx/notes/tex.html#entry25
+hbox :: LatexItem -> LatexItem
+hbox = latexCmdArg "hbox"
+
+-- TeX level
+-- http://dmr.ath.cx/notes/tex.html#entry25
+vbox :: ParItem -> LatexItem
+vbox = latexParModeArgs "vbox" []
+
+-- TeX level
+-- http://dmr.ath.cx/notes/tex.html#entry25
+vtop :: ParItem -> LatexItem
+vtop = latexParModeArgs "vtop" []
+
+-- TODO
+-- vbox_to :: LatexLength -> ParItem -> LatexItem
+-- vbox_to width = latexParModeArgs "vbox" [to $ texLength width]
+
+{-
+class Mbox a where
+  -- robust
+  mbox :: LatexItem -> a
+
+  -- fragile
+  makebox :: LatexLength -> LatexLength -> LatexItem -> a
+
+instance Mbox MathItem where
+  mbox = MathToLR Nothing Nothing
+  makebox = mmakebox
+
+instance Mbox LatexItem where
+  mbox = id
+
+instance Mbox ParItem where
+-}
+
+-- robust
+-- http://www.personal.ceu.hu/tex/spacebox.htm#makebox
+mbox :: LatexItem -> LatexItem
+mbox = latexCmdArg "mbox"
+
+posArg :: Pos -> Arg AnyItem
+posArg = optional . rawAnyTex . pure . charPos
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/spacebox.htm#makebox
+makebox :: LatexLength -> Pos -> LatexItem -> LatexItem
+makebox width pos txt =
+  latexCmdAnyArgs "makebox" [optTexLength width
+                            ,posArg pos
+                            ,mandatoryLatexItem txt]
+
+-- robust
+fbox :: LatexItem -> LatexItem
+fbox = latexCmdArg "fbox"
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/spacebox.htm#framebox
+framebox :: LatexLength -> Pos -> LatexItem -> LatexItem
+framebox width pos txt = latexCmdAnyArgs "framebox" [optTexLength width
+                                                    ,posArg pos
+                                                    ,mandatoryLatexItem txt]
+
+phantom :: LatexItem -> LatexItem
+phantom = latexCmdArg "phantom"
+
+vphantom :: LatexItem -> LatexItem
+vphantom = latexCmdArg "vphantom"
+
+-- robust
+sbox :: SaveBin -> LatexItem -> LatexItem
+sbox bin txt = latexCmdAnyArgs "sbox" [mandatory $ latexSaveBin bin, mandatoryLatexItem txt]
+
+-- fragile
+savebox :: SaveBin -> Maybe LatexLength -> Maybe (Either () ()) -> LatexItem -> LatexItem
+savebox bin width dir txt =
+  latexCmdAnyArgs "savebox" [mandatory $ latexSaveBin bin
+                            ,maybe noArg optTexLength width
+                            ,maybe noArg (optionalLatexItem . either ll rr) dir
+                            ,mandatoryLatexItem txt]
+  where ll _ = rawTex "l"
+        rr _ = rawTex "r"
+
+-- robust
+usebox :: SaveBin -> LatexItem
+usebox bin = latexCmdAnyArgs "usebox" [mandatory $ latexSaveBin bin]
+
+-- vertical position for parbox and minipage
+data VPos = Normal
+          | Top
+          | Bot
+
+vposArg :: VPos -> Arg AnyItem
+vposArg Normal = noArg
+vposArg Top    = optional . rawAnyTex $ "t"
+vposArg Bot    = optional . rawAnyTex $ "b"
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/spacebox.htm#parbox
+parbox :: VPos -> LatexLength -> LatexItem -> LatexItem
+parbox pos width txt =
+  latexCmdAnyArgs "parbox" [vposArg pos, mandatory $ texLength width, mandatoryLatexItem txt]
+
+minipage :: VPos -> LatexLength -> ParItem -> LatexItem
+minipage pos width = latexEnvironmentPar "minipage" [vposArg pos, mandatory $ texLength width]
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/spacebox.htm#rule
+rule :: LatexLength -> LatexLength -> LatexItem
+rule width height = latexCmdAnyArgs "rule" [mandatory $ texLength width
+                                           ,mandatory $ texLength height]
+
+-- fragile
+rule' :: LatexLength -> LatexLength -> LatexLength -> LatexItem
+rule' raise_len width height = latexCmdAnyArgs "rule" [optTexLength raise_len
+                                                      ,mandatory $ texLength width
+                                                      ,mandatory $ texLength height]
+
+-- fragile
+-- http://www.personal.ceu.hu/tex/spacebox.htm#raisebox
+raisebox :: LatexLength -> LatexItem -> LatexItem
+raisebox raise_len txt =
+  latexCmdAnyArgs "raisebox" [mandatory $ texLength raise_len
+                             ,mandatoryLatexItem txt]
+
+-- fragile
+raisebox' :: LatexLength -> LatexLength -> LatexLength -> LatexItem -> LatexItem
+raisebox' raise_len height depth txt =
+  latexCmdAnyArgs "raisebox" [mandatory $ texLength raise_len
+                             ,optTexLength height
+                             ,optTexLength depth
+                             ,mandatoryLatexItem txt]
+
+footnote :: LatexItem -> LatexItem
+footnote = latexCmdArg "footnote"
+
+caption :: LatexItem -> LatexItem
+caption txt = latexCmdArgs "caption" [mandatory txt]
+caption' :: String -> LatexItem -> LatexItem
+caption' lstentry txt = latexCmdArgs "caption" [optional $ checkentry lstentry, mandatory txt]
+  where checkentry x
+          | all isAlphaNum x = rawTex x
+          | otherwise        = throwError "caption': restriction to alphanumeric characters for the lstentry"
+
+label :: Key -> LatexItem
+label = latexCmdAnyArg "label" . latexKey
+ref :: Key -> LatexItem
+ref = latexCmdAnyArg "ref" . latexKey
+pageref :: Key -> LatexItem
+pageref = latexCmdAnyArg "pageref" . latexKey
+
+-- fragile
+cite :: [Key] -> LatexItem
+cite = latexCmdAnyArgs "cite" . pure . latexKeysArg
+cite' :: LatexItem -> [Key] -> LatexItem
+cite' txt keys = latexCmdAnyArgs "cite" [optionalLatexItem txt, latexKeysArg keys]
+
+-- fragile
+nocite :: [Key] -> LatexItem
+nocite = latexCmdAnyArgs "nocite" . pure . latexKeysArg
+
+-- sectioning
+
+part, chapter, section, subsection,  subsubsection, paragraph,
+  subparagraph :: LatexItem -> ParItem
+part', chapter', section', subsection', subsubsection', paragraph',
+  subparagraph' :: Star -> Maybe LatexItem -> LatexItem -> ParItem
+
+(part,          part')          = sectioning "part"
+(chapter,       chapter')       = sectioning "chapter"
+(section,       section')       = sectioning "section"
+(subsection,    subsection')    = sectioning "subsection"
+(subsubsection, subsubsection') = sectioning "subsubsection"
+(paragraph,     paragraph')     = sectioning "paragraph"
+(subparagraph , subparagraph')  = sectioning "subparagraph"
+
+-- | Don't confuse 'paragraph' with 'para', 'para' is to make a paragraph,
+-- 'paragraph' is to name a set of paragraphs.
+para :: LatexItem -> ParItem
+para = parCast . latexItem
+
+bibliography :: LatexItem -> ParItem
+bibliography = parCmdArg "bibliography" . latexItem
+bibliographystyle :: LatexItem -> ParItem
+bibliographystyle = parCmdArg "bibliographystyle" . latexItem
+thispagestyle :: LatexItem -> ParItem
+thispagestyle = parCmdArg "thispagestyle" . latexItem
+pagestyle :: LatexItem -> ParItem
+pagestyle = parCmdArg "pagestyle" . latexItem
+
+appendix :: ParItem
+appendix = parCmdArgs "appendix" []
+
+-- http://www.personal.ceu.hu/tex/length.htm
+setlength :: LatexLength -> LatexLength -> ParItem
+setlength lengthName newLength
+  | isJust (lengthCst lengthName)
+      = throwError "setlength: the first argument should be a length name not a constant"
+  | otherwise
+      = parCmdArgs "setlength" [mandatory (texLength lengthName)
+                               ,mandatory (texLength newLength)]
+
+-- http://www.personal.ceu.hu/tex/length.htm
+addtolength :: LatexLength -> LatexLength -> ParItem
+addtolength lengthName newLength
+  | isJust (lengthCst lengthName)
+      = throwError "addtolength: the first argument should be a length name not a constant"
+  | otherwise
+      = parCmdArgs "addtolength" [mandatory (texLength lengthName)
+                                 ,mandatory (texLength newLength)]
+
+-- http://www.personal.ceu.hu/tex/length.htm
+settowidth :: LatexLength -> LatexItem -> ParItem
+settowidth lengthName text
+  | isJust (lengthCst lengthName)
+      = throwError "settowidth: the first argument should be a length name not a constant"
+  | otherwise
+      = parCmdArgs "settowidth" [mandatory (texLength lengthName)
+                                ,mandatoryLatexItem text]
+
+item :: ParItem -> ListItem
+item = liftM $ ListItm []
+
+item' :: LatexItem -> ParItem -> ListItem
+item' a = liftM2 ListItm (pure . optional <$> a)
+
+itemize :: Maybe LatexItem -> [ListItem] -> ParItem
+itemize = listLikeEnv "itemize" . pure . maybe noArg optional
+
+-- enumerate counters are enumi, enumii, enumiii, enumiv
+enumerate :: Maybe LatexItem -> [ListItem] -> ParItem
+enumerate = listLikeEnv "enumerate" . pure . maybe noArg optional
+
+description :: Maybe LatexItem -> [ListItem] -> ParItem
+description = listLikeEnv "description" . pure . maybe noArg optional
+
+figure, table :: Star -> [LocSpec] -> ParItem -> ParItem
+figure = figureLike "figure"
+table  = figureLike "table"
+
+-- Accents
+
+-- | Add a cedila to a letter (\c{...} in LaTeX)
+cedil :: LatexItem -> LatexItem
+cedil = latexCmdArg "c"
+
+grave :: LatexItem -> LatexItem
+grave = latexCmdArg "`"
+
+acute :: LatexItem -> LatexItem
+acute = latexCmdArg "'"
+
+uml :: LatexItem -> LatexItem
+uml = latexCmdArg "\""
+
+circ :: LatexItem -> LatexItem
+circ = latexCmdArg "^"
+
+-- alias of 'circ'
+hat :: LatexItem -> LatexItem
+hat = latexCmdArg "^"
+
+check :: LatexItem -> LatexItem
+check = latexCmdArg "v"
+
+i :: LatexItem
+i = texCmdNoArg "i"
+
+j :: LatexItem
+j = texCmdNoArg "j"
+
+tilde :: LatexItem -> LatexItem
+tilde = latexCmdArg "~"
+
+dot :: LatexItem -> LatexItem
+dot = latexCmdArg "d"
+
+ring :: LatexItem -> LatexItem
+ring = latexCmdArg "r"
+
+-- TODO find a name
+_H :: LatexItem -> LatexItem
+_H = latexCmdArg "H"
+
+-- Produces a dot accent over the following (\.{x} in LaTeX)
+overdot :: LatexItem -> LatexItem
+overdot = latexCmdArg "."
+
+-- Produces a macron (overbar) accent over the following
+overbar :: LatexItem -> LatexItem
+overbar = latexCmdArg "="
+
+-- Produces a macron (overbar) accent over the following
+underbar :: LatexItem -> LatexItem
+underbar = latexCmdArg "b"
+
+-- Produces a tie-after accent, as in `oo[' (\t in LaTeX).
+tieafter :: LatexItem -> LatexItem
+tieafter = latexCmdArg "t"
+
+-- Some non-English characters
+
+-- The 'å' letter (like @ring "a"@)
+aa :: LatexItem
+aa = texCmdNoArg "aa"
+
+-- The 'Å' letter (like @ring "A"@)
+_AA :: LatexItem
+_AA = texCmdNoArg "AA"
+
+-- The 'æ' letter
+ae :: LatexItem
+ae = texCmdNoArg "ae"
+
+-- The 'Æ' letter
+_AE :: LatexItem
+_AE = texCmdNoArg "AE"
+
+-- The 'œ' letter
+oe :: LatexItem
+oe = texCmdNoArg "oe"
+
+-- The 'Œ' letter
+_OE :: LatexItem
+_OE = texCmdNoArg "OE"
+
+-- The 'ß' letter
+ss :: LatexItem
+ss = texCmdNoArg "ss"
+
+-- The '/l' letter
+_l :: LatexItem
+_l = texCmdNoArg "l"
+
+-- The '/L' letter
+_L :: LatexItem
+_L = texCmdNoArg "L"
+
+-- The 'ø' letter
+o :: LatexItem
+o = texCmdNoArg "o"
+
+-- The 'Ø' letter
+_O :: LatexItem
+_O = texCmdNoArg "O"
+
+-- Text symbols
+
+-- | The copyright symbol, ©.
+copyright :: LatexItem
+copyright = texCmdNoArg "copyright"
+
+-- | The dagger symbol (in text).
+dag :: LatexItem
+dag = texCmdNoArg "dag"
+
+-- | The double dagger symbol (in text).
+ddag :: LatexItem
+ddag = texCmdNoArg "ddag"
+
+-- | The LaTeX logo.
+_LaTeX :: LatexItem
+_LaTeX = texCmdNoArg "LaTeX"
+
+-- | The TeX logo.
+_TeX :: LatexItem
+_TeX = texCmdNoArg "TeX"
+
+-- | An ellipsis (three dots at the baseline): `...'. This command also works in math mode.
+ldots :: LatexItem
+ldots = texCmdNoArg "ldots"
+
+-- | Left (opening) quote: `.
+lq :: LatexItem
+lq = texCmdNoArg "lq"
+
+-- | Right (closing) quote: '.
+rq :: LatexItem
+rq = texCmdNoArg "rq"
+
+-- | Left (opening) double quotes: ``.
+ldq :: LatexItem
+ldq = rawTex "{``}"
+
+-- | Right (opening) double quotes: ''.
+rdq :: LatexItem
+rdq = rawTex "{''}"
+
+-- | Double quote a LaTeX item.
+dquote :: LatexItem -> LatexItem
+dquote x = ldq ⊕ x ⊕ rdq
+
+-- | Paragraph sign (pilcrow).
+_P :: LatexItem
+_P = texCmdNoArg "P"
+
+-- | English pounds sterling.
+pounds :: LatexItem
+pounds = texCmdNoArg "pounds"
+
+-- | Section symbol.
+_S :: LatexItem
+_S = texCmdNoArg "S"
+
+textdegree :: LatexItem
+textdegree = latexCmdArgs "textdegree" [packageDependency (pkgName "textcomp"), mandatory ø]
+
+-- check options
+titlepage, flushleft, center, boxedminipage, quotation, verse :: ParItem -> ParItem
+titlepage = parEnvironmentPar "titlepage" []
+flushleft = parEnvironmentPar "flushleft" []
+center = parEnvironmentPar "center" []
+boxedminipage = parEnvironmentPar "boxedminipage" []
+quotation = parEnvironmentPar "quotation" []
+verse = parEnvironmentPar "verse" []
+
+quote :: LatexItem -> ParItem
+quote = liftM $ ParEnv "quote" [] . LatexItm
+
+-- The array and tablular Environments
+
+tabular :: [RowSpec LatexItem] -> [Row LatexItem] -> ParItem
+tabular = tabularLike Tabular
+
+cells :: [a] -> Row a
+cells = Cells
+
+cell :: a -> Row a
+cell = Cells . pure
+
+hline :: Row a
+hline = Hline
+cline :: Int -> Int -> Row a
+cline = Cline
+
+-- this is more the '|' than the \vline of LaTeX,
+-- one may want to support both using a HaveVline type class.
+vline :: RowSpec a
+vline = Rvline
+
+rtext :: a -> RowSpec a
+rtext = Rtext
+
+class HaveC a where c :: a
+class HaveL a where l :: a
+class HaveR a where r :: a
+
+instance HaveC (RowSpec a) where c = Rc
+instance HaveL (RowSpec a) where l = Rl
+instance HaveR (RowSpec a) where r = Rr
+
+class HaveTop a where top :: a
+instance HaveTop LocSpec where top = Lt
+instance HaveTop VPos    where top = Top
+
+class HaveBot a where bot :: a
+instance HaveBot LocSpec where bot = Lb
+instance HaveBot VPos    where bot = Bot
+
+class HaveNormal a where normal :: a
+instance HaveNormal VPos where normal = Normal
+
+bottom :: HaveBot a => a
+bottom = bot
+
+here, page :: LocSpec
+here = Lh
+page = Lp
+
+centered, flushLeft, flushRight, stretch :: Pos
+centered = Centered
+flushLeft = FlushLeft
+flushRight = FlushRight
+stretch = Stretch
+
+
+-- eqnarraystar = 
+
+a4paper :: LatexPaperSize
+a4paper = A4paper
+
+documentclass ::  DocumentClassKind -> [AnyItem] ->
+                  DocumentClass
+documentclass dc = (DocClass dc <$>) . mapM anyItmM
+
+article ::  Maybe LatexLength -> Maybe LatexPaperSize ->
+            [AnyItem] -> DocumentClass
+article msize mpaper args =
+  documentclass Article $  maybeToList (latexPaper <$> mpaper) ++
+                           maybeToList (texLength <$> msize) ++
+                           args
+
+-- TODO improve options
+letter :: [AnyItem] -> DocumentClass
+letter = documentclass Letter
+
+book ::  Maybe LatexLength -> Maybe LatexPaperSize ->
+         [AnyItem] -> DocumentClass
+book msize mpaper args =
+  documentclass Book $  maybeToList (latexPaper <$> mpaper) ++
+                        maybeToList (texLength <$> msize) ++
+                        args
+
+-- TODO improve options
+report :: [AnyItem] -> DocumentClass
+report = documentclass Report
+
+{-
+$(
+ let
+  mathCmdsArg, allTexDecls, mathDecls :: [String]
+  mathCmds :: [(String, String)]
+
+  mathCmds =
+    [("lbrace", "{")
+    ,("rbrace", "}")
+    ,("space", " ")
+    ,("at", "@")
+    ,("in_", "in")
+    ,("forall_", "forall")
+    ,("thinspace", ",")
+    ,("negthinspace", "!")
+    ,("mediumspace", ":")
+    ,("thickspace", ";")
+    ,("msup", "sup")
+    ] ++ map (id &&& id)
+    [-- Greek letters
+    "alpha","beta","chi","delta","Delta","epsilon","varepsilon","eta","gamma"
+    ,"Gamma","iota","kappa","lambda","Lambda","mu","nu","omega","Omega","phi"
+    ,"varphi","Phi","pi","Pi","psi","rho","sigma","Sigma","tau","theta"
+    ,"vartheta","Theta","upsilon","xi","Xi","zeta"
+
+    -- Operation symbols
+    ,"backslash","times","divide","circ","oplus","otimes","sum","prod","wedge"
+    ,"bigwedge","vee","bigvee","cup","bigcup","cap","bigcap"
+
+    -- Relation symbols
+    ,"ne","le","leq","ge","geq","prec","succ","notin","subset","supset"
+    ,"subseteq","supseteq","equiv","cong","approx","propto"
+
+    -- Logical symbols
+    ,"neg","implies","iff","exists","bot","top","vdash","models"
+
+    -- Grouping brackets
+    ,"langle","rangle"
+
+    -- Miscellaneous symbols
+    ,"int","oint","partial","nabla","pm","emptyset","infty","aleph","ldots"
+    ,"cdots","vdots","ddots","quad","diamond","square","lfloor","rfloor","lceiling","rceiling"
+
+    -- Standard functions
+    ,"sin","cos","tan","csc","sec","cot","sinh","cosh","tanh","log"
+    ,"ln","det","dim","lim","mod","gcd","lcm","liminf","inf","limsup"
+    ,"max","min","Pr"
+
+    -- Arrows
+    ,"uparrow","downarrow","rightarrow","to","leftarrow"
+    ,"leftrightarrow","Rightarrow","Leftarrow","Leftrightarrow"
+    ]
+
+  mathCmdsArg =
+    [-- Font commands
+    "mathbf","mathbb","mathcal","mathtt","mathfrak"
+    -------
+    ,"pmod"
+    -- Putting one thing above another
+    ,"tilde", "hat", "check", "breve", "acute", "grave", "bar", "vec"
+    , "dot", "ddot", "overbrace", "underbrace"
+    ,"overline","underline","widehat","widetilde","imath","jmath"
+    ]
+
+  typeStyles :: [String]
+  typeStyles = ["em","bf","sf","sl","sc","it","tt"]
+
+  allTexDecls = typeStyles
+
+  mathDecls = ["displaystyle", "textstyle", "scriptstyle", "scriptscriptstyle"
+              ,"mit","cal"
+              ]
+
+  lowerName :: String -> Name
+  lowerName name | isLower (head name) = mkName name
+                | otherwise           = mkName $ '_':name
+
+  mkMathCmd (name, cmd) =
+    let lname = lowerName name
+    in
+    [sigD lname [t| MathItem |]
+    , valD (varP lname) (normalB [| mathCmd $(stringE cmd) |]) []
+    ]
+
+  mkMathCmdArg name =
+    let lname = lowerName name in
+    [sigD lname [t| MathItem -> MathItem |]
+    , valD (varP lname) (normalB [| mathCmdArg $(stringE name) |]) []
+    ]
+
+  mkTexDecl name =
+    let lname = lowerName name in
+    [sigD lname [t| LatexItem |]
+    , valD (varP lname) (normalB [| texDecl $(stringE name) [] |]) []
+    ]
+
+  mkMathDecl name =
+    let lname = lowerName name in
+    [sigD lname [t| MathItem |]
+     , valD (varP lname) (normalB [| mathDecl $(stringE name) [] |]) []
+    ]
+
+  mkList name ty names =
+    [sigD name ty
+    ,valD (varP name) (normalB (listE $ map (varE . lowerName) names)) []]
+
+  d = sequence $ concat $ concat
+      [ map mkMathCmd mathCmds
+      , map mkMathCmdArg mathCmdsArg
+      , map mkTexDecl allTexDecls
+      , map mkMathDecl mathDecls
+      , [mkList (mkName "mathItems") [t| [MathItem] |] $ (map fst mathCmds ++ mathDecls)]
+      , [mkList (mkName "mathCmdsArg") [t| [MathItem -> MathItem] |] mathCmdsArg]
+      , [mkList (mkName "allTexDecls") [t| [LatexItem] |] allTexDecls]
+      ]
+  in do dd <- d
+        runIO $ writeFile "/tmp/a.hs" $ pprint dd
+        return []
+ )
+ -}
+
+{- This chunk was generated by the previous TH splice.
+   The lists of all commands are manually maintained though. -}
+author, title, subtitle, date, institute :: LatexItem -> PreambleItem
+title = preambleCmdArg "title" . latexItem
+subtitle = preambleCmdArg "subtitle" . latexItem
+date = preambleCmdArg "date" . latexItem
+author = preambleCmdArg "author" . latexItem
+-- Institute is defined in beamer but not in article.
+-- Should we move these definitions into sub modules?
+-- For instance Language.LaTeX.Article.date
+institute = preambleCmdArg "institute" . latexItem
+
+authors :: [LatexItem] -> PreambleItem
+authors = author . mconcat . intersperse (rawTex " & ")
+
+utf8 :: Encoding
+utf8 = rawEncoding "utf8"
+
+latin1 :: Encoding
+latin1 = rawEncoding "latin1"
+
+inputenc :: Encoding -> PreambleItem
+inputenc (Encoding enc)
+  = usepackage [latexItem $ fromString enc] (pkgName "inputenc")
+
+{-# DEPRECATED em "Use emph instead" #-}
+em :: TexDecl
+em = texDecl "em"
+{-# DEPRECATED rm "Use textrm or rmfamily instead" #-}
+rm :: TexDecl
+rm = texDecl "rm"
+{-# DEPRECATED bf "Use textbf or bfseries instead" #-}
+bf :: TexDecl
+bf = texDecl "bf"
+{-# DEPRECATED sf "Use textsf or sffamily instead" #-}
+sf :: TexDecl
+sf = texDecl "sf"
+{-# DEPRECATED sl "Use textsl or slshape instead" #-}
+sl :: TexDecl
+sl = texDecl "sl"
+{-# DEPRECATED sc "Use textsc or scshape instead" #-}
+sc :: TexDecl
+sc = texDecl "sc"
+{-# DEPRECATED it "Use textit or itshape instead" #-}
+it :: TexDecl
+it = texDecl "it"
+{-# DEPRECATED tt "Use texttt or ttfamily instead" #-}
+tt :: TexDecl
+tt = texDecl "tt"
+-- \up ?
+
+allTexDecls :: [TexDecl]
+allTexDecls = [rm, em, bf, sf, sl, sc, it, tt
+              ,rmfamily, bfseries, sffamily, slshape
+              ,scshape, itshape, ttfamily, upshape, normalfont
+              ,reversemarginpar,normalmarginpar
+              ,sloppy, fussy,samepage
+              ,tiny, scriptsize, footnotesize, small, normalsize, large
+              ,_LARGE, _Large, huge, _Huge]
+
+-- Local definitions
+
+check0to4 :: String -> Maybe Int -> LatexM [Arg AnyItem]
+check0to4 _ Nothing  = return []
+check0to4 s (Just n)
+  | n >= 0 && n <= 4 = return [optional $ num n]
+  | otherwise        = throwError $ s ++ ": option must be between 0 and 4 not " ++ show i
diff --git a/Language/LaTeX/Builder/Babel.hs b/Language/LaTeX/Builder/Babel.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder/Babel.hs
@@ -0,0 +1,44 @@
+-- TODO add more langs
+module Language.LaTeX.Builder.Babel
+   (Lang, BabelOpt
+   ,useBabel
+   ,langName
+   ,otherlanguage
+   -- langs
+   ,francais
+   ,french
+   -- last resort
+   ,customLang
+   ,customBabelOpt
+   ,pkg
+   ) where
+
+import Data.String
+import Language.LaTeX.Types
+import qualified Language.LaTeX.Builder.Internal as BI
+
+newtype BabelOpt = BabelOpt { babelOpt :: AnyItem }
+
+newtype Lang = Lang { langName :: String }
+  deriving (Show, Eq)
+
+francais, french :: Lang
+francais = Lang "francais"
+french   = Lang "french"
+
+customLang :: String -> Lang
+customLang = Lang
+
+customBabelOpt :: AnyItem -> BabelOpt
+customBabelOpt = BabelOpt
+
+pkg :: PackageName
+pkg = BI.pkgName "babel"
+
+useBabel :: Lang -> [BabelOpt] -> PreambleItem
+useBabel lang opts = BI.usepackage (BI.latexItem (fromString (langName lang))
+                                   : map babelOpt opts) pkg
+
+-- | Switch locally to another language
+otherlanguage :: Lang -> ParItem -> ParItem
+otherlanguage lang = BI.parEnvironmentPar "otherlanguage" [BI.mandatoryLatexItem (fromString (langName lang))]
diff --git a/Language/LaTeX/Builder/Beamer.hs b/Language/LaTeX/Builder/Beamer.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder/Beamer.hs
@@ -0,0 +1,433 @@
+{-# LANGUAGE QuasiQuotes #-}
+module Language.LaTeX.Builder.Beamer
+
+where
+
+import Language.LaTeX.Builder.MonoidUtils
+import Language.LaTeX.Types
+import qualified Language.LaTeX.Builder.Internal as BI
+import qualified Language.LaTeX.Builder as B
+import Language.LaTeX.Builder.QQ
+import Control.Applicative
+import Data.List (intersperse)
+import Data.Maybe
+import Data.Monoid
+
+{-
+pkg :: PackageName
+pkg = B.pkgName "beamer"
+-}
+
+data DocClassOption = Compress
+                    | T
+                    | Red
+                    | Handout
+                    | RawDocClassOption String
+
+compress, t, red, handout :: DocClassOption
+compress = Compress
+t = T
+red = Red
+handout = Handout
+
+rawDocClassOption :: String -> DocClassOption
+rawDocClassOption = RawDocClassOption
+
+showDocClassOption :: DocClassOption -> String
+showDocClassOption Compress  = "compress"
+showDocClassOption T         = "t"
+showDocClassOption Red       = "red"
+showDocClassOption Handout   = "handout"
+showDocClassOption (RawDocClassOption x) = x
+
+documentclasskind :: DocumentClassKind
+documentclasskind =  OtherDocumentClassKind "beamer"
+
+beamer :: Maybe LatexLength -> [DocClassOption] -> [AnyItem] -> DocumentClass
+beamer msize opts
+  = B.documentclass documentclasskind
+  . (maybeToList (BI.texLength <$> msize) ++)
+  . (map (BI.rawAnyTex . showDocClassOption) opts ++)
+
+type TargetName = String
+type Label = String
+
+labelArg :: Label -> Arg AnyItem
+labelArg = BI.mandatoryLatexItem . BI.rawTex
+
+targetArg :: TargetName -> Arg AnyItem
+targetArg = BI.mandatoryLatexItem . BI.rawTex
+
+data FrameOpt = Label Label
+              | Fragile
+              | OtherOption String String
+  deriving (Eq,Ord)
+
+data OverlayInt = OvInt Int
+                | OvPlus
+                | OvPlusOffset Int
+                | OvDot
+  deriving (Eq,Ord)
+
+-- | Only overlay actions are not supported currently.
+data Overlay = OvSingle OverlayInt
+             | OvFromTo OverlayInt OverlayInt
+             | OvFrom OverlayInt
+  deriving (Eq,Ord)
+
+type Overlays = [Overlay]
+
+type BeamerOpt = (String, String)
+
+texFrameOpt :: FrameOpt -> BeamerOpt
+texFrameOpt (Label lbl)        = ("label",lbl)
+texFrameOpt Fragile            = ("fragile","")
+texFrameOpt (OtherOption a b)  = (a,b)
+
+texFrameOpts :: [FrameOpt] -> Arg AnyItem
+texFrameOpts = beamerOpts . map texFrameOpt
+
+showOvInt :: OverlayInt -> ShowS
+showOvInt (OvInt i)           = shows i
+showOvInt OvPlus              = ('+':)
+showOvInt OvDot               = ('.':)
+showOvInt (OvPlusOffset off)  = ('+':) . ('(':) . shows off . (')':)
+
+showOverlay :: Overlay -> ShowS
+showOverlay (OvSingle i)    = showOvInt i
+showOverlay (OvFromTo i j)  = showOvInt i . ('-':) . showOvInt j
+showOverlay (OvFrom i)      = showOvInt i . ('-':)
+
+showOverlays :: Overlays -> Maybe String
+showOverlays []   = Nothing
+showOverlays ovs  = Just . ('<':) . (++">") . showsOv ovs $ []
+   where
+     showsOv :: Overlays -> ShowS
+     showsOv = mconcat . intersperse (',':) . map showOverlay
+
+texOverlaysOpt :: Overlays -> Maybe LatexItem
+texOverlaysOpt = fmap BI.rawTex . showOverlays
+
+texOverlaysArg :: Overlays -> Arg a
+texOverlaysArg = maybe BI.noArg BI.rawArg . showOverlays
+
+texOverlaysOptArg :: Overlays -> Arg AnyItem
+texOverlaysOptArg = maybe BI.noArg (BI.optionalLatexItem . BI.rawTex) . showOverlays
+
+label :: Label -> FrameOpt
+label = Label
+
+-- more options to add ?
+frame :: Overlays -> Overlays -> [FrameOpt] -> LatexItem -> LatexItem -> ParItem  -> ParItem
+frame ov mov fopts title subtitle =
+  {- recent beamer versions
+  BI.parEnvironmentPar "frame" $ [ texOverlaysArg ov
+                                 , maybe BI.noArg BI.optional $ texOverlaysOpt mov
+                                 , texFrameOpts fopts
+                                 , BI.mandatory title
+                                 , BI.mandatory subtitle ]
+  -}
+  BI.parEnvironmentPar "frame" [ texOverlaysArg ov
+                               , texOverlaysOptArg mov
+                               , texFrameOpts fopts
+                               ] . (mapNonEmpty frametitle title ⊕)
+                                 . (mapNonEmpty framesubtitle subtitle ⊕)
+
+frameO :: Overlays -> ParItem  -> ParItem
+frameO overlays = BI.parEnvironmentPar "frame" [texOverlaysOptArg overlays]
+
+example :: ParItem -> ParItem
+example = BI.parEnvironmentPar "example" []
+
+theorem :: ParItem -> ParItem
+theorem = BI.parEnvironmentPar "theorem" []
+
+block :: LatexItem -> ParItem -> ParItem
+block title = BI.parEnvironmentPar "block" [BI.mandatoryLatexItem title]
+
+slide :: LatexItem -> ParItem -> ParItem
+slide tit = frame [] [] [] tit ø
+
+slideO :: LatexItem -> Overlays -> ParItem -> ParItem
+slideO tit ovs body = frameO ovs (frametitle tit ⊕ body)
+
+frametitle :: LatexItem -> ParItem
+frametitle = BI.parCmdArg "frametitle" . BI.latexItem
+
+framesubtitle :: LatexItem -> ParItem
+framesubtitle = BI.parCmdArg "framesubtitle" . BI.latexItem
+
+-- | All overlays counting from the given argument (like in @<1->@).
+ovFrom :: OverlayInt -> Overlay
+ovFrom = OvFrom
+
+-- | All overlays between the given arguments (like in @<1-3>@).
+ovFromTo :: OverlayInt -> OverlayInt -> Overlay
+ovFromTo = OvFromTo
+
+-- | The single overlay (like in @<1>@).
+ovSingle :: OverlayInt -> Overlay
+ovSingle = OvSingle
+
+-- | Lift a strictly positive 'Int' to an 'OverlayInt'
+ovInt :: Int -> OverlayInt
+ovInt i | i > 0      = OvInt i
+        | otherwise  = error "ovInt: strictly positive Int expected"
+
+{- | The '+' incremental overlay specification (like in @<+->@).
+
+     Beamer User Guide at 8.6.4 Incremental Specifications -}
+ovPlus :: OverlayInt
+ovPlus = OvPlus
+
+{- | The '.' incremental overlay specification (like in @<.->@).
+
+     Beamer User Guide at 8.6.4 Incremental Specifications -}
+ovDot :: OverlayInt
+ovDot = OvDot
+
+-- | Handy shortcut for @[ovFrom ovPlus]@ aka @<+->@.
+ovIncr :: Overlays
+ovIncr = [ovFrom ovPlus]
+
+-- | Handy lifting for a list of strictly positive integers.
+ovInts :: [Int] -> Overlays
+ovInts = map (ovSingle . ovInt)
+
+alert :: LatexItem -> LatexItem
+alert = BI.latexCmdArg "alert"
+
+-- A shortcut for @itemize . texOverlaysOpt@
+itemize :: Overlays -> [ListItem] -> ParItem
+itemize = B.itemize . texOverlaysOpt
+-- A shortcut for @enumerate . texOverlaysOpt@
+enumerate :: Overlays -> [ListItem] -> ParItem
+enumerate = B.enumerate . texOverlaysOpt
+-- A shortcut for @description . texOverlaysOpt@
+description :: Overlays -> [ListItem] -> ParItem
+description = B.description . texOverlaysOpt
+
+-- AtBeginSubsection, AtBeginSection
+
+pause :: LatexItem
+pause = BI.texCmdNoArg "pause"
+
+pause' :: Maybe Int -> LatexItem
+pause' = BI.latexCmdArgs "pause" . maybeToList . fmap (BI.optional . BI.rawTex . show)
+
+only :: Overlays -> LatexItem -> LatexItem
+only ov arg = BI.latexCmdArgs "only" [texOverlaysArg ov, BI.mandatory arg]
+
+uncover :: Overlays -> LatexItem -> LatexItem
+uncover ov arg = BI.latexCmdArgs "uncover" [texOverlaysArg ov, BI.mandatory arg]
+
+visible :: Overlays -> LatexItem -> LatexItem
+visible ov arg = BI.latexCmdArgs "visible" [texOverlaysArg ov, BI.mandatory arg]
+
+invisible :: Overlays -> LatexItem -> LatexItem
+invisible ov arg = BI.latexCmdArgs "invisible" [texOverlaysArg ov, BI.mandatory arg]
+
+alt :: Overlays -> LatexItem -> LatexItem -> LatexItem
+alt ov arg1 arg2 = BI.latexCmdArgs "alt" [texOverlaysArg ov, BI.mandatory arg1, BI.mandatory arg2]
+
+temporal :: Overlays -> LatexItem -> LatexItem -> LatexItem -> LatexItem
+temporal ov arg1 arg2 arg3
+  = BI.latexCmdArgs "temporal"  [  texOverlaysArg ov
+                                ,  BI.mandatory arg1
+                                ,  BI.mandatory arg2
+                                ,  BI.mandatory arg3
+                                ]
+
+visibleenv :: Overlays -> ParItem -> ParItem
+visibleenv ov = BI.parEnvironmentPar "visibleenv" [texOverlaysArg ov]
+
+invisibleenv :: Overlays -> ParItem -> ParItem
+invisibleenv ov = BI.parEnvironmentPar "invisibleenv" [texOverlaysArg ov]
+
+uncoverenv :: Overlays -> ParItem -> ParItem
+uncoverenv ov = BI.parEnvironmentPar "uncoverenv" [texOverlaysArg ov]
+
+onlyenv :: Overlays -> ParItem -> ParItem
+onlyenv ov = BI.parEnvironmentPar "onlyenv" [texOverlaysArg ov]
+
+altenv :: Overlays   -- ^ overlay specification
+       -> LatexItem  -- ^ begin text
+       -> LatexItem  -- ^ end   text
+       -> LatexItem  -- ^ alternate begin text
+       -> LatexItem  -- ^ alternate end text
+       -> ParItem    -- ^ environment contents
+       -> ParItem
+altenv ov b e ab ae =
+  BI.parEnvironmentPar "altenv"  [  texOverlaysArg ov
+                                 ,  BI.mandatoryLatexItem b
+                                 ,  BI.mandatoryLatexItem e
+                                 ,  BI.mandatoryLatexItem ab
+                                 ,  BI.mandatoryLatexItem ae
+                                 ]
+
+beamerOpts :: [BeamerOpt] -> Arg AnyItem
+beamerOpts = BI.namedOpts . map f
+  where f (x,y) = Named x $ BI.rawAnyTex y
+
+beamerPreambleCmdArgs :: String -> [BeamerOpt] -> LatexItem -> PreambleItem
+beamerPreambleCmdArgs name opts arg = BI.preambleCmdArgs name [beamerOpts opts, BI.mandatoryLatexItem arg]
+
+usetheme, usefonttheme, useinnertheme, useoutertheme,
+  usecolortheme :: [BeamerOpt] -> LatexItem -> PreambleItem
+
+usetheme       = beamerPreambleCmdArgs "usetheme"
+usefonttheme   = beamerPreambleCmdArgs "usefonttheme"
+useinnertheme  = beamerPreambleCmdArgs "useinnertheme"
+useoutertheme  = beamerPreambleCmdArgs "useoutertheme"
+usecolortheme  = beamerPreambleCmdArgs "usecolortheme"
+
+{- | Draws a button with the given button text .
+
+  Example: @hyperlink [] "somewhere" (beamerbutton "Go somewhere")@
+
+  p97 beamer userguide
+-}
+beamerbutton :: LatexItem -> LatexItem
+beamerbutton = BI.latexCmdArg "beamerbutton"
+
+{- | Draws a button with the given button text. Before the text, a small symbol (usually a
+     right-pointing arrow) is inserted that indicates that pressing this button will jump
+     to another *area* of the presentation.
+
+  Example: @hyperlink [] "detour" (beamergotobutton "Go to detour")@
+
+  p98 beamer userguide
+-}
+beamergotobutton :: LatexItem -> LatexItem
+beamergotobutton = BI.latexCmdArg "beamergotobutton"
+
+{- | The symbol drawn for this button is usually a double right arrow. Use this button if
+     pressing it will skip over a well-defined part of your talk.
+
+  p98 beamer userguide
+-}
+beamerskipbutton :: LatexItem -> LatexItem
+beamerskipbutton = BI.latexCmdArg "beamerskipbutton"
+
+{- | The symbol drawn for this button is usually a left-pointing arrow. Use this button
+     if pressing it will return from a detour.
+
+  p98 beamer userguide
+-}
+beamerreturnbutton :: LatexItem -> LatexItem
+beamerreturnbutton = BI.latexCmdArg "beamerreturnbutton"
+
+{- |
+  Only one overlay specification may be given. The link text is typeset in the
+  usual way. If you click anywhere on this text, you will jump to the slide on
+  which the \hypertarget command was used with the parameter target name . If an
+  overlay specification is present, the hyperlink (including the link text) is
+  completely suppressed on the non-specified slides.
+
+  p99 beamer userguide
+-}
+hyperlink :: Overlays -> TargetName -> LatexItem -> Overlays -> LatexItem
+hyperlink ov1 target linkText ov2 =
+  BI.latexCmdAnyArgs "hyperlink"  [  texOverlaysArg ov1
+                                  ,  targetArg target
+                                  ,  BI.mandatoryLatexItem linkText
+                                  ,  texOverlaysArg ov2
+                                  ]
+
+againframe :: Overlays -> Overlays -> [FrameOpt] -> Label -> ParItem
+againframe ov1 ov2 fopts lbl =
+  BI.parCmdArgs "againframe" [ texOverlaysArg ov1
+                             , texOverlaysArg ov2
+                             , texFrameOpts fopts
+                             , labelArg lbl
+                             ]
+
+
+-- | Disable those litte icons at the bottom right of your presentation.
+beamertemplatenavigationsymbolsempty :: PreambleItem
+beamertemplatenavigationsymbolsempty = BI.preambleCmdArgs "beamertemplatenavigationsymbolsempty" []
+
+type TexDimension = LatexLength
+
+data BeamerSize
+  = TextMarginLeft TexDimension
+    -- ^ sets a new left margin. This excludes the left sidebar. Thus,
+    -- it is the distance between the right edge of the left sidebar and the left edge of the text.
+  | TextMarginRight TexDimension
+    -- ^ sets a new right margin.
+  | SidebarWidthLeft TexDimension
+    -- ^ sets the size of the left sidebar. Currently, this command
+    -- should be given before a shading is installed for the sidebar canvas.
+  | SidebarWidthRight TexDimension
+    -- ^ sets the size of the right sidebar.
+  | DescriptionWidth TexDimension
+    -- ^ sets the default width of description labels, see Beamer User Guide Section 11.1.
+  | DescriptionWidthOf LatexItem
+    -- ^ sets the default width of description labels to the width of the
+    -- text, see Section 11.1.
+  | MiniFrameSize TexDimension
+    -- ^ sets the size of mini frames in a navigation bar. When two
+    -- mini frame icons are shown alongside each other, their left end points are
+    -- 'TexDimension' far apart.
+  | MiniFrameOffset TexDimension
+    -- ^ set an additional vertical offset that is added to the mini
+    -- frame size when arranging mini frames vertically.
+
+texBeamerSizeArg :: BeamerSize -> Arg AnyItem
+texBeamerSizeArg bs = BI.namedArgs . pure $ case bs of
+  TextMarginLeft dim     -> n "text margin left"     $ BI.texLength dim
+  TextMarginRight dim    -> n "text margin right"    $ BI.texLength dim
+  SidebarWidthLeft dim   -> n "sidebar width left"   $ BI.texLength dim
+  SidebarWidthRight dim  -> n "sidebar width right"  $ BI.texLength dim
+  DescriptionWidth dim   -> n "description width"    $ BI.texLength dim
+  DescriptionWidthOf txt -> n "description width of" $ BI.latexItem txt
+  MiniFrameSize dim      -> n "mini frame size"      $ BI.texLength dim
+  MiniFrameOffset dim    -> n "mini frame offset"    $ BI.texLength dim
+  where n = Named
+
+setbeamersize :: BeamerSize -> PreambleItem
+setbeamersize = BI.preambleCmdArgs "setbeamersize" . pure . texBeamerSizeArg
+
+appendix :: ParItem
+appendix = BI.parCmdArgs "appendix" []
+
+-- \setbeamercolor*{titlelike}{parent=structure}
+
+data Footline = Footline { authorPercent    :: Percentage
+                         , titlePercent     :: Percentage
+                         , datePercent      :: Maybe Percentage
+                         , showTotalFrames  :: Bool }
+
+defaultFootline :: Footline
+defaultFootline = Footline { authorPercent    = 34
+                           , titlePercent     = 36
+                           , datePercent      = Nothing
+                           , showTotalFrames  = True }
+
+footline :: Footline -> PreambleItem
+footline Footline{authorPercent=authorp,titlePercent=titlep,datePercent=maydatep,showTotalFrames=stf} =
+  let datep = fromMaybe (100 - authorp - titlep) maydatep
+      f (Percentage p) = BI.rawPreamble $ show p
+      maytotalframes = if stf then [qp| / \inserttotalframenumber|] else ø
+  in
+  [qp|
+     |  \defbeamertemplate*{footline}{infolines theme without institution}
+     |  {
+     |    \leavevmode%
+     |    \hbox{%
+     |      \begin{beamercolorbox}[wd=.|] ⊕ f authorp ⊕ [qp|\paperwidth,ht=2.25ex,dp=1.125ex,center]{author in head/foot}%
+     |        \usebeamerfont{author in head/foot}
+     |        \insertshortauthor
+     |      \end{beamercolorbox}%
+     |      \begin{beamercolorbox}[wd=.|] ⊕ f titlep ⊕ [qp|\paperwidth,ht=2.25ex,dp=1.125ex,center]{title in head/foot}%
+     |        \usebeamerfont{title in head/foot}
+     |        \insertshorttitle
+     |      \end{beamercolorbox}%
+     |      \begin{beamercolorbox}[wd=.|] ⊕ f datep ⊕ [qp|\paperwidth,ht=2.25ex,dp=1.125ex,right]{date  in head/foot}%
+     |        \usebeamerfont{date in head/foot}
+     |        \insertshortdate{}\hspace*{2em}
+     |        \insertframenumber{}|] ⊕ maytotalframes ⊕ [qp|\hspace*{2ex}
+     |      \end{beamercolorbox}}%
+     |    \vskip0pt%
+     |  }
+     |]
diff --git a/Language/LaTeX/Builder/Color.hs b/Language/LaTeX/Builder/Color.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder/Color.hs
@@ -0,0 +1,128 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Language.LaTeX.Builder.Color
+  (
+  -- * The type of colors
+   Color
+  -- * Coloring commands
+  ,pagecolor
+  ,color
+  ,textcolor
+  ,colorbox
+  ,fcolorbox
+  ,preamblecolor
+  ,normalcolor
+  -- * Making colors
+  ,named, rgb, cmyk, gray, html, rgb256
+  -- * Predefined colors
+  ,red, green, blue, black, white, cyan, magenta, yellow, orange
+  -- * Package name
+  ,pkg)
+where
+
+import Data.String
+import Data.Word
+import Language.LaTeX.Types
+import qualified Language.LaTeX.Builder.Internal as BI
+import Control.Monad.Error (throwError)
+
+-- Some HTML docs at http://en.wikibooks.org/wiki/LaTeX/Colors
+
+data Color = BaseColor String
+           | NamedColor String
+           | RGB Rational Rational Rational
+           | RGB256 Word8 Word8 Word8
+           | HTML String
+           | CMYK Rational Rational Rational Rational
+           | Gray Rational
+
+colorArgs :: Color -> [Arg AnyItem]
+colorArgs = (BI.packageDependency pkg:) . f
+  where f (BaseColor n)  = [man n]
+        f (NamedColor n) = [opt "named", man n]
+        f (RGB r g b)    = model "rgb" (checkRatios [r,g,b])
+        f (RGB256 r g b) = model "RGB" [r,g,b]
+        f (CMYK c m y k) = model "cmyk" (checkRatios [c,m,y,k])
+        f (Gray g)       = model "gray" (checkRatios [g])
+        f (HTML s)       = [opt "HTML", man . checkHTML $ s]
+        opt = BI.optionalLatexItem . fromString
+        man = BI.mandatoryLatexItem . fromString
+        model name cs    = [opt name,
+                            BI.mandatoryList . map BI.num $ cs]
+        check msg p x | p x       = x
+                      | otherwise = error msg
+        checkHTML = check "Not a HTML color (6 hex digits)" (\s -> length s == 6 && all (`elem` (['0'..'9']++['a'..'F']++['A'..'F'])) s)
+        checkRatios = check "Not a rational number between 0 and 1" (all checkRatio)
+        checkRatio x = x >= 0 && x <= 1
+
+red, green, blue, black, white, cyan, magenta, yellow :: Color
+[red, green, blue, black, white, cyan, magenta, yellow] =
+   map BaseColor ["red", "green", "blue", "black", "white", "cyan", "magenta", "yellow"]
+
+orange :: Color
+orange = rgb 1 0.5 0
+
+pkg :: PackageName
+pkg = BI.pkgName "color"
+
+named :: String -> Color
+named = NamedColor
+
+rgb :: Rational -> Rational -> Rational -> Color
+rgb = RGB
+
+cmyk :: Rational -> Rational -> Rational -> Rational -> Color
+cmyk = CMYK
+
+gray :: Rational -> Color
+gray = Gray
+
+rgb256 :: Word8 -> Word8 -> Word8 -> Color
+rgb256 = RGB256
+
+html :: String -> Color
+html = HTML
+
+-- | 'pagecolor' sets the background colour for the current and following pages
+pagecolor :: Color -> ParItem
+pagecolor = BI.parCmdArgs "pagecolor" . colorArgs
+
+-- | 'color' is a declaration to switch to setting text in the given colour
+color :: Color -> TexDecl
+color = BI.texDecl' "color" . colorArgs
+
+-- | 'textcolor' sets the text of its argument in the given colour
+textcolor :: Color -> LatexItem -> LatexItem
+textcolor c x = BI.latexCmdAnyArgs "textcolor" (colorArgs c ++ [BI.mandatoryLatexItem x])
+
+-- | 'colorbox' sets its argument in a box with the given colour as background
+colorbox :: Color -> LatexItem -> LatexItem
+colorbox c x = BI.latexCmdAnyArgs "colorbox" (colorArgs c ++ [BI.mandatoryLatexItem x])
+
+-- | @fcolorbox c1 c2 text@ is like 'colorbox', with a frame of @c1@ around a box
+--   of background colour @c2@.
+--   For example, @fcolorbox red green "Text"@ sets `Text' in the current text colour
+--   on a green background with a red frame.
+--
+--   The two specifications must either both be defined ones, or both use the same
+--   model, which is given only once, this limitation only make sense in LaTeX
+--   parlance but is helpful here to understand why this function can fail.
+fcolorbox :: Color -> Color -> LatexItem -> LatexItem
+fcolorbox c1 c2 x =
+  let args =
+       case (colorArgs c1, colorArgs c2) of
+         ([p, m1, a1], [_, m2, a2]) | m1 == m2 -> [p, m1, a1, a2]
+         ([p, a1], [_, a2]) -> [p, a1, a2]
+         _ -> [BI.mandatory (AnyItem $ throwError "fcolorbox: arguments must be either of the same model,\
+                                       \ or be defined colors.")]
+  in
+  BI.latexCmdAnyArgs "fcolorbox" (args ++ [BI.mandatoryLatexItem x])
+
+-- | Like 'color' but usable in the preamble.
+preamblecolor :: Color -> PreambleItem
+preamblecolor = BI.preambleCmdArgs "color" . colorArgs
+
+-- | 'normalcolor' switches to the colour that was active at the end of the preamble.
+--   Thus placing a 'color' declaration in the preamble can change the standard colour
+--   for the whole document. This is the equivalent to 'normalfont' for font selection.
+normalcolor :: TexDecl
+normalcolor = BI.texDecl' "normalcolor" [BI.packageDependency pkg]
diff --git a/Language/LaTeX/Builder/Graphics.hs b/Language/LaTeX/Builder/Graphics.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder/Graphics.hs
@@ -0,0 +1,176 @@
+module Language.LaTeX.Builder.Graphics
+  (
+  -- * The main command
+  includegraphics
+  -- * The options
+  ,IncludeGraphicsOpts(..)
+  -- * The locations
+  ,Loc, c, center, t, top, l, left, r, right, b, bottom, ba, baseline, tr, topRight
+  ,tl, topLeft, bl, bottomLeft, br, bottomRight, baselineLeft, baselineRight
+  -- * The package name
+  , pkg)
+where
+
+import Language.LaTeX.Types hiding (Loc)
+import qualified Language.LaTeX.Builder.Internal as BI
+import Language.LaTeX.Builder.MonoidUtils ((⊕))
+import Control.Arrow ((***))
+import Data.Maybe
+import Data.String
+
+data Loc = C   -- ^ Center
+         | T   -- ^ Top
+         | L   -- ^ Left
+         | R   -- ^ Right
+         | B   -- ^ Bottom
+         | Ba  -- ^ Baseline
+         | TR  -- ^ Top right
+         | TL  -- ^ Top left
+         | BL  -- ^ Bottom left (default)
+         | BR  -- ^ Bottom right
+         | BaL -- ^ Baseline left
+         | BaR -- ^ Baseline right
+  deriving (Eq)
+
+c, center, t, top, l, left, r, right, b, bottom, ba, baseline, tr, topRight,
+  tl, topLeft, bl, bottomLeft, br, bottomRight, baselineLeft, baselineRight :: Loc
+c = C
+center = C
+t = T
+top = T
+l = L
+left = L
+r = R
+right = R
+b = B
+bottom = B
+ba = Ba
+baseline = Ba
+tr = TR
+topRight = TR
+tl = TL
+topLeft = TL
+bl = BL
+bottomLeft = BL
+br = BR
+bottomRight = BR
+baselineLeft = BaL
+baselineRight = BaR
+
+showGrLoc :: Loc -> String
+showGrLoc loc = case loc of
+  C -> "c"
+  T -> "t"
+  L -> "l"
+  R -> "r"
+  B -> "b"
+  Ba -> "B"
+  TR -> "tr"
+  TL -> "tl"
+  BL -> "bl"
+  BR -> "br"
+  BaL -> "Bl"
+  BaR -> "Br"
+
+data IncludeGraphicsOpts = IncludeGraphicsOpts
+  { scale  :: Rational
+    -- ^ the number by which the figure size should be magnified over its natural size
+  , width  :: Maybe LatexLength
+    -- ^ specifies the width to which the figure should be scaled to; if height not given,
+    -- it is scaled with the same factor as the width
+  , height :: Maybe LatexLength
+    -- ^ specifies the height to which the figure should be scaled to; if width is not given,
+    -- it is scaled with the same factor as the height
+  , totalheight :: Maybe LatexLength
+    -- ^ like height but specifies the height plus depth of the figure; should always be used
+    -- in place of height if the figure has been otated
+  , keepaspectratio :: Bool
+    -- ^ if both height and width are specified, this flag ensures that the original height/width
+    -- ratio remains unchanged; the figure will not exceed either of the given dimensions
+  , angle :: Rational
+    -- ^ the angle by which the figure is to be rotated counterclockwise, in degrees; any height
+    -- or width specifications coming before this key are also rotated, so that the height becomes
+    -- the width, while the width becomes either the height (positive angle) or depth (negative angle)
+  , origin :: Loc
+    -- ^ determines the point about which the rotation occurs; default is bl for bottom left
+    -- corner; also possible are c for center, t for top, r for right, and B for baseline;
+    -- any sensible combination, such as tr, is allowed
+  , draft :: Bool
+    -- ^ like the draft package option but applied to the one graphics file; the figure is not
+    -- imported, but rather a framed box of the correct size is printed containing the name of
+    -- the file
+  , clip :: Bool
+    -- ^ suppresses the printing of any graphic outside the bounding box
+  , bb :: Maybe (Coord, Coord)
+    -- ^ ((llx, lly) (urx, ury)); enters the coordinates of the bounding box manually,
+    -- if they are missing or incorrect in the graphics file, or to be deliberately altered;
+    -- the specifications are four lengths separated by blanks; units may be given, but if
+    -- omitted, big points (bp) are assumed
+  , viewport :: Maybe (Coord, Coord)
+    -- ^ ((llx, lly), (urx, ury)); specifies the bounding box but relative to the lower left
+    -- corner of the existing one; useful for correcting the bounding box, or (with clip) to
+    -- select only a portion of the whole figure
+  , trim :: Maybe (Coord, Coord)
+    -- ^ ((dllx, dlly), (durx, dury)); reduces the existing bounding box by the amounts specified
+  , hiresbb :: Bool
+    -- ^ like the hiresbb package option but applied to the one graphics file; reads bounding box
+    -- information from the %%HiResBoundingBox line in the graphics file. 
+  }
+
+pkg :: PackageName
+pkg = PkgName "graphicx"
+
+-- | @includegraphics fopts fp@
+-- The @fopts@ function will receive the defaults options and should modify options
+-- to suit your needs.
+--
+-- This function is generally used like this:
+-- @
+-- includegraphics (\\o -> o{ \<opt\> = \<exp\> ... }) fp
+-- @
+includegraphics :: (IncludeGraphicsOpts -> IncludeGraphicsOpts) -> FilePath -> ParItem
+includegraphics f fp =
+   BI.parCmdArgs "includegraphics" $ opt ++ [BI.packageDependency pkg, BI.mandatoryLatexItem $ fromString fp]
+  where opts = includeGraphicsOpts $ f defaultOpts
+        opt | null opts = []
+            | otherwise = [BI.namedOpts opts]
+
+defaultOpts :: IncludeGraphicsOpts
+defaultOpts = IncludeGraphicsOpts
+  { scale = 1
+  , width = Nothing
+  , height = Nothing
+  , totalheight = Nothing
+  , keepaspectratio = False
+  , angle = 0
+  , origin = baselineLeft
+  , draft = False
+  , clip = False
+  , bb = Nothing
+  , viewport = Nothing
+  , trim = Nothing
+  , hiresbb = False -- I think that's the default.
+  }
+
+includeGraphicsOpts :: IncludeGraphicsOpts -> [Named AnyItem]
+includeGraphicsOpts o =
+  catMaybes [ f "scale" scale BI.rat
+            , f "width" width (BI.texLength . fromJust)
+            , f "height" height (BI.texLength . fromJust)
+            , f "totalheight" totalheight (BI.texLength . fromJust)
+            , f "keepaspectratio" keepaspectratio BI.bool
+            , f "angle" angle BI.rat
+            , f "origin" origin (BI.rawAnyTex . showGrLoc)
+            , f "draft" draft BI.bool
+            , f "clip" clip BI.bool
+            , f "bb" bb maybeCoords
+            , f "viewport" viewport maybeCoords
+            , f "trim" trim maybeCoords
+            , f "hiresbb" hiresbb BI.bool
+            ]
+  where f :: Eq a => String -> (IncludeGraphicsOpts -> a) -> (a -> AnyItem) -> Maybe (Named AnyItem)
+        f name proj toAnyItem
+            | proj defaultOpts == proj o = Nothing
+            | otherwise                  = Just (Named name (toAnyItem $ proj o))
+        maybeCoords = g . (BI.coord *** BI.coord) . fromJust
+        g (x, y) = BI.latexItem $ BI.latexCast x ⊕ BI.rawTex " " ⊕ BI.latexCast y
diff --git a/Language/LaTeX/Builder/Internal.hs b/Language/LaTeX/Builder/Internal.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder/Internal.hs
@@ -0,0 +1,355 @@
+module Language.LaTeX.Builder.Internal where
+
+import Prelude hiding (sqrt, min, max, lcm, gcd, log, mod, tanh, cosh, tan, sinh,
+                       sin, cos, succ, sum, pi, mapM)
+import qualified Data.List as L
+import Data.Maybe
+import Data.Monoid
+import Data.Traversable (sequenceA, mapM)
+import Control.Applicative hiding (optional)
+import Control.Monad hiding (mapM)
+import Control.Monad.Error (throwError)
+
+import Language.LaTeX.Types
+import Language.LaTeX.Builder.MonoidUtils
+
+
+{- TODO:
+    - robust/fragile/moving
+    - tracking savebin in the monad?
+    - generating a doc with examples:
+         [...("sum", [| sum⊕sub(i⊕eq⊕0)⊕sup infty⊕i⊕sup 2 |])...]
+    - pictures
+    - choose between optFoo and optionalFoo
+ -}
+
+noArg :: Arg a
+noArg = NoArg
+
+starArg :: Arg a
+starArg = StarArg
+
+starToArg :: Star -> Arg a
+starToArg Star   = starArg
+starToArg NoStar = noArg
+
+mandatory, optional :: a -> Arg a
+mandatory = Mandatory . pure
+optional = Optional . pure
+
+mandatoryLatexItem, optionalLatexItem :: LatexItem -> Arg AnyItem
+mandatoryLatexItem = mandatory . latexItem
+optionalLatexItem = optional . latexItem
+
+coordinates :: a -> a -> Arg a
+coordinates = Coordinates
+
+mandatoryList :: [a] -> Arg a
+mandatoryList = Mandatory
+
+optionals :: [a] -> Arg a
+optionals [] = NoArg
+optionals xs = Optional xs
+
+named :: String -> a -> Named a
+named = Named
+
+namedOpts :: [Named a] -> Arg a
+namedOpts [] = NoArg
+namedOpts xs = NamedOpts xs
+
+namedArgs :: [Named a] -> Arg a
+namedArgs = NamedArgs
+
+optionalLatexItems :: [LatexItem] -> Arg AnyItem
+optionalLatexItems = optionals . map latexItem
+
+usepackage :: [AnyItem] -> PackageName -> PreambleItem
+usepackage opts pkg =
+  preambleCmdArgs "usepackage"
+    [providePackage pkg, optionals opts, mandatory (packageName pkg)]
+
+nilNote :: Note
+nilNote = stringNote ""
+
+stringNote :: String -> Note
+stringNote = TextNote
+
+intNote :: Int -> Note
+intNote = IntNote
+
+locNote :: Loc -> Note
+locNote = LocNote
+
+-- Note that @rawArg ø@ reduces to ø.
+rawArg :: String -> Arg m
+rawArg "" = NoArg
+rawArg x  = RawArg x
+
+-- Note that @liftArg ø@ reduces to ø.
+liftArg :: (Eq m, Monoid m) => m -> Arg m
+liftArg x | x == ø    = NoArg
+          | otherwise = LiftArg x
+
+rawDecls :: [TexDecl] -> LatexItem
+rawDecls = mapNonEmpty $ fmap TexDecls . sequenceA
+
+texDecl :: String -> TexDecl
+texDecl s = pure $ TexDcl s []
+
+texDecl' :: String -> [Arg AnyItem] -> TexDecl
+texDecl' s opts = TexDcl s <$> mapM (mapM anyItmM) opts
+
+texDeclOpt :: String -> AnyItem -> TexDecl
+texDeclOpt s opt = texDecl' s [optional opt]
+
+parNote :: Key -> Note -> ParItem -> ParItem
+parNote k = fmap . ParNote k
+
+parCmdArgs :: String -> [Arg AnyItem] -> ParItem
+parCmdArgs x ys = ParCmdArgs x <$> mapM (mapM anyItmM) ys
+
+parCmdArg :: String -> AnyItem -> ParItem
+parCmdArg x y = parCmdArgs x [mandatory y]
+
+latexNote :: Key -> Note -> LatexItem -> LatexItem
+latexNote k = fmap . LatexNote k
+
+latexCmdArgs :: String -> [Arg LatexItem] -> LatexItem
+latexCmdArgs x ys = LatexCmdArgs x <$> mapM sequenceA ys
+
+latexCmdAnyArgs :: String -> [Arg AnyItem] -> LatexItem
+latexCmdAnyArgs x ys = LatexCmdAnyArgs x <$> mapM (mapM anyItmM) ys
+
+latexCmdArg :: String -> LatexItem -> LatexItem
+latexCmdArg x y = latexCmdArgs x [mandatory y]
+
+latexCmdAnyArg :: String -> AnyItem -> LatexItem
+latexCmdAnyArg x y = latexCmdAnyArgs x [mandatory y]
+
+preambleNote :: Key -> Note -> PreambleItem -> PreambleItem
+preambleNote k = fmap . PreambleNote k
+
+preambleCmdArgs :: String -> [Arg AnyItem] -> PreambleItem
+preambleCmdArgs x ys = PreambleCmdArgs x <$> mapM (mapM anyItmM) ys
+
+preambleCmdArg :: String -> AnyItem -> PreambleItem
+preambleCmdArg x y = preambleCmdArgs x [mandatory y]
+
+preambleEnv :: String -> [Arg AnyItem] -> AnyItem -> PreambleItem
+preambleEnv x ys = liftM2 (PreambleEnv x) (mapM (mapM anyItmM) ys) . anyItmM
+
+rawPreamble :: String -> PreambleItem
+rawPreamble = mapNonEmpty $ pure . RawPreamble
+
+texLength :: LatexLength -> AnyItem
+texLength = AnyItem . pure . Length
+
+mandatoryTexLength :: LatexLength -> Arg AnyItem
+mandatoryTexLength = mandatory . texLength
+
+optTexLength :: LatexLength -> Arg AnyItem
+optTexLength = optional . texLength
+
+latexItem :: LatexItem -> AnyItem
+latexItem = AnyItem . fmap LatexItm
+
+mathItem :: MathItem -> AnyItem
+mathItem = AnyItem . fmap MathItm . mathItmM
+
+parItem :: ParItem -> AnyItem
+parItem = AnyItem . fmap ParItm
+
+preambleItem :: PreambleItem -> AnyItem
+preambleItem = AnyItem . fmap PreambleItm
+
+packageName :: PackageName -> AnyItem
+packageName = AnyItem . pure . PackageName
+
+locSpecs :: [LocSpec] -> AnyItem
+locSpecs = AnyItem . pure . LocSpecs
+
+rawEncoding :: String -> Encoding
+rawEncoding = Encoding
+
+pkgName :: String -> PackageName
+pkgName = PkgName
+
+packageDependency :: PackageName -> Arg a
+packageDependency = PackageAction . PackageDependency
+
+-- This phantom argument states that the given package
+-- is considered provided from now on.
+-- This especially make sense when building the usepackage
+-- command.
+providePackage :: PackageName -> Arg a
+providePackage = PackageAction . ProvidePackage
+
+showPaper :: LatexPaperSize -> String
+showPaper A4paper = "a4paper"
+showPaper (OtherPaperSize s) = s
+
+latexPaper :: LatexPaperSize -> AnyItem
+latexPaper = rawAnyTex . showPaper
+
+otherDocumentClassKind :: String -> DocumentClassKind
+otherDocumentClassKind = OtherDocumentClassKind
+
+bool :: Bool -> AnyItem
+bool True  = rawAnyTex "true"
+bool False = rawAnyTex "false"
+
+coord :: Coord -> AnyItem
+coord = AnyItem . pure . Coord
+
+latexSaveBin :: SaveBin -> AnyItem
+latexSaveBin = AnyItem . pure . SaveBin
+
+latexCast :: AnyItem -> LatexItem
+latexCast = fmap cast . anyItmM
+  where cast (LatexItm x) = x
+        cast x            = LatexCast x
+
+mathCast :: AnyItem -> MathItem
+mathCast = MathItem . fmap cast . anyItmM
+  where cast (MathItm x) = x
+        cast x           = MathCast x
+
+parCast :: AnyItem -> ParItem
+parCast = fmap cast . anyItmM
+  where cast (ParItm x) = x
+        cast x          = ParCast x
+
+preambleCast :: AnyItem -> PreambleItem
+preambleCast = fmap cast . anyItmM
+  where cast (PreambleItm x) = x
+        cast x               = PreambleCast x
+
+latexEnvironmentAny :: String -> [Arg AnyItem] -> AnyItem -> LatexItem
+latexEnvironmentAny x ys = liftM2 (Environment x) (mapM (mapM anyItmM) ys) . anyItmM
+
+latexEnvironment :: String -> [Arg AnyItem] -> LatexItem -> LatexItem
+latexEnvironment x ys = latexEnvironmentAny x ys . latexItem
+
+latexEnvironmentPar :: String -> [Arg AnyItem] -> ParItem -> LatexItem
+latexEnvironmentPar x ys = latexEnvironmentAny x ys . parItem
+
+latexParModeArgs :: String -> [Arg AnyItem] -> ParItem -> LatexItem
+latexParModeArgs x ys z = latexCmdAnyArgs x (ys ++ [mandatory (parItem z)])
+
+parEnv :: String -> [Arg AnyItem] -> AnyItem -> ParItem
+parEnv x ys = liftM2 (ParEnv x) (mapM (mapM anyItmM) ys) . anyItmM
+
+parEnvironmentPar :: String -> [Arg AnyItem] -> ParItem -> ParItem
+parEnvironmentPar x ys = parEnv x ys . parItem
+
+figureLike :: String -> Star -> [LocSpec] -> ParItem -> ParItem
+figureLike name star locs
+  = parEnvironmentPar (starize name star)
+      [optional . locSpecs $ locs] -- liftM $ FigureLike (starize x s) y
+
+listLikeEnv :: String -> [Arg LatexItem] -> [ListItem] -> ParItem
+listLikeEnv name opts items =
+  parEnvironmentPar name ((map.fmap) latexItem opts)
+                         (mconcat <$> mapM (fmap mkItem) items)
+  where mkItem (ListItm opts' contents) = ParCmdArgs "item" ((map.fmap) LatexItm opts') ⊕ contents
+
+rawTex :: String -> LatexItem
+rawTex = mapNonEmpty $ pure . RawTex
+
+rawAnyTex :: String -> AnyItem
+rawAnyTex = latexItem . rawTex
+
+rawMath :: String -> MathItem
+rawMath = MathItem . pure . RawMath
+
+rawMathChar :: Char -> MathItem
+rawMathChar = rawMath . ('{':) . (:"}")
+
+texCmdNoArg :: String -> LatexItem
+texCmdNoArg = pure . TexCmdNoArg
+
+latexKey :: Key -> AnyItem
+latexKey = AnyItem . pure . Key
+
+latexKeys :: [Key] -> [AnyItem]
+latexKeys = map latexKey
+
+latexKeysArg :: [Key] -> Arg AnyItem
+latexKeysArg = mandatoryList . latexKeys
+
+latexKeyArg :: Key -> Arg AnyItem
+latexKeyArg = mandatory . latexKey
+
+normSpaces :: String -> String
+normSpaces = unlines . map (L.unwords . words) . lines
+
+num :: Real a => a -> AnyItem
+num = texLength . fromRational . toRational
+
+rat :: Rational -> AnyItem
+rat = texLength . fromRational
+
+space :: LatexItem
+space = rawTex "{ }"
+
+starize :: String -> Star -> String
+starize s NoStar = s
+starize s Star   = s ++ "*"
+
+-- TODO: make a safe version using a monad
+-- http://www.personal.ceu.hu/tex/spacebox.htm#newsavebox
+-- fragile
+unsafeNewsavebox :: Int -> (SaveBin, LatexItem)
+unsafeNewsavebox n =
+  let bin = UnsafeMakeSaveBin n
+  in (bin, latexCmdAnyArg "newsavebox" $ latexSaveBin bin)
+
+-- sectioning
+
+-- Sectioning commands arguments are 'moving'.
+sectioning :: String -> (LatexItem -> ParItem,
+                         Star -> Maybe LatexItem -> LatexItem -> ParItem)
+sectioning name = (sect, sect')
+  where sect = sect' ø Nothing
+        sect' s opt arg = parCmdArgs (starize name s)
+                                     (maybeToList (fmap (optional . latexItem) opt) ++
+                                      [mandatory (latexItem arg)])
+
+-- The array and tablular Environments
+
+tabularLike :: ([RowSpec a] -> [Row a] -> b) -> [RowSpec (LatexM a)] -> [Row (LatexM a)] -> LatexM b
+tabularLike f specs rows = do
+  spcs <- mapM sequenceA specs
+  f spcs <$> (checkRows spcs =<< mapM sequenceA rows)
+
+checkRows :: [RowSpec a] -> [Row a] -> LatexM [Row a]
+checkRows specs = mapM checkRow
+  where checkRow (Cells cs)
+          | cols /= length cs    = err "wrong number of cells" cols "different from" (length cs)
+          | otherwise            = pure $ Cells cs
+        checkRow Hline           = pure Hline
+        checkRow (Cline c1 c2)
+          | c1 > cols = err "cline: start column too high" c1 ">" cols
+          | c1 < 0    = throwError "tabular: cline: negative start column"
+          | c2 > cols = err "cline: end column too high" c2 ">" cols
+          | c2 < 0    = throwError "tabular: cline: negative end column"
+          | otherwise = pure $ Cline c1 c2
+        cols = length $ filter isCol specs
+        isCol Rc = True
+        isCol Rl = True
+        isCol Rr = True
+        isCol Rvline = False
+        isCol (Rtext _) = False
+        err msg x op y = throwError $ L.unwords ["tabular:", msg, '(' : show x, op, show y ++ ")"]
+
+-- `{' `}' are like bgroup plus egroup except that `{' and `}' are
+-- syntactically forced to be balanced.
+-- begingroup and endgroup only save the scopes of definitions.
+-- bgroup and egroup save the scopes as well but also resolve the springs
+-- independently.
+bgroup, egroup, begingroup, endgroup :: TexDecl
+bgroup      = texDecl "bgroup"
+egroup      = texDecl "egroup"
+begingroup  = texDecl "begingroup"
+endgroup    = texDecl "endgroup"
diff --git a/Language/LaTeX/Builder/Math.hs b/Language/LaTeX/Builder/Math.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder/Math.hs
@@ -0,0 +1,877 @@
+module Language.LaTeX.Builder.Math
+
+  -- NOTE: do not forget to update allMathItems, allMathDecls
+  (amsmath,
+   charToMath, stringToMath, mchar, mstring, mathlift, protect, protector, verb,
+   _Delta, _Gamma, _Lambda, _Leftarrow, _Leftrightarrow, _Omega, _Phi, _Pi, _Pr,
+   _Rightarrow, _Sigma, _Theta, _Xi, acute, aleph, alpha, approx, array, at,
+   backslash, bar, beta, between, bigcap, bigcup, bigvee, bigwedge, bmod, bot,
+   braces, brackets, breve, bullet, cal, cap, cdots, cdotp, check, chi, circ, cong, cos, cosh,
+   cot, csc, cup, ddot, ddots, delta, det, diamond, dim, displaystyle, div, divide,
+   dot, downarrow, emptyset, epsilon, eq, neq, equiv, eta, exists, forall_, frac,
+   gamma, gcd, ge, geq, grave, group, hat, iff, imath, implies, in_, inf,
+   infty, int, iota, jmath, kappa, lambda, langle, lbrace, lceil, lcm,
+   ldots, ldotp, le, leftarrow, leftrightarrow, leq, lfloor, lim, liminf, limsup, ln,
+   log, lparen, mathBinOp, longleftarrow, longrightarrow, longleftrightarrow,
+   mathBinOps, mathCmd, mathCmdArg, mathCmdArgs, mathCmdMathArg, mathCmdMathArgs, mathCmdsArg,
+   mathDecl, mathGroup, allMathItems, allMathDecls, rawDecls, decl, decls,
+   mathbb, mathbf, mathnormal, mathrm, mathsf, mathit, mathscr,
+   mathcal, mathfrak, mathtt, max, mbox, min, mit, mleft, mediumspace,
+   negthinspace, mod, models, mrat, mright, msup, thickspace,
+   thinspace, mu, nabla, ne, neg, notin, nu, oint, omega, omicron, oplus, otimes,
+   overbrace, overline, parenChar, parens, partial, phi, pi, pm, pmod, prec,
+   prod, propto, psi, quad, rangle, rbrace, rceil,
+   rfloor, rho, rightarrow, rparen, scriptscriptstyle, scriptstyle, sec, sigma, sin, sinh,
+   space, sqrt, sqrt', square, stackrel, sub, subset, subseteq, succ, sum, sup,
+   supset, supseteq, tan, tanh, tau, text, textstyle, theta, tilde, times, to, top,
+   underbrace, underline, uparrow, upsilon, varepsilon, varphi, vartheta, vdash,
+   vdots, vec, vee, wedge, widehat, widetilde, xi, zeta,
+   a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,
+   _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P,
+   _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z,
+   _Downarrow, _Uparrow,
+   vartriangleright,phantom,
+
+   -- reexports
+   cells, cell, vline, hline, cline
+  ) where
+
+import Prelude hiding (sqrt, min, max, lcm, gcd, log, mod, tanh, cosh, tan, sinh,
+                       sin, cos, succ, sum, pi, mapM, div)
+import Data.Char
+import Data.Maybe (fromMaybe)
+import Data.Foldable (foldMap)
+import Data.Traversable (sequenceA, mapM)
+import Data.String
+import qualified Data.IntMap as IntMap
+import Control.Arrow
+import Control.Applicative
+import Control.Monad hiding (mapM)
+import Control.Monad.Error (throwError)
+
+import Language.LaTeX.Types
+import Language.LaTeX.Builder.MonoidUtils
+import Language.LaTeX.Builder (XChar, cell, cells, vline, hline, cline)
+import Language.LaTeX.Builder.Internal (rawMath, rawMathChar)
+import qualified Language.LaTeX.Builder as B
+import qualified Language.LaTeX.Builder.Internal as B
+
+liftMath :: (MathItm -> MathItm) -> MathItem -> MathItem
+liftMath fun = MathItem . liftM fun . mathItmM
+
+liftMath2 :: (MathItm -> MathItm -> MathItm) -> MathItem -> MathItem -> MathItem
+liftMath2 fun (MathItem aa) (MathItem bb) = MathItem (liftM2 fun aa bb)
+
+group :: MathItem -> MathItem
+group = liftMath MathGroup
+
+-- | Same as 'group'
+mathGroup :: MathItem -> MathItem
+mathGroup = group
+
+mathCmdArgs :: String -> [Arg AnyItem] -> MathItem
+mathCmdArgs name args = MathItem $ MathCmdArgs name <$> mapM (mapM anyItmM) args
+
+mathCmdMathArgs :: String -> [Arg MathItem] -> MathItem
+mathCmdMathArgs name = mathCmdArgs name . (map . fmap) B.mathItem
+
+mathCmdArg :: String -> AnyItem -> MathItem
+mathCmdArg m1 m2 = mathCmdArgs m1 [B.mandatory m2]
+
+mathCmdMathArg :: String -> MathItem -> MathItem
+mathCmdMathArg name = mathCmdMathArgs name . pure . B.mandatory
+
+mathDecl :: String -> MathDecl
+mathDecl = pure . MathDcl
+
+rawDecls :: [MathDecl] -> MathItem
+rawDecls = MathItem . fmap MathDecls . sequenceA
+
+decls :: [MathDecl] -> MathItem -> MathItem
+decls ds itm = group (rawDecls ds ⊕ itm)
+
+decl :: MathDecl -> MathItem -> MathItem
+decl dcl = decls [dcl]
+
+mathCmd :: String -> MathItem
+mathCmd = MathItem . pure . (`MathCmdArgs` [])
+
+mathBinOp :: String -> MathItem -> MathItem -> MathItem
+mathBinOp = liftMath2 . MathBinOp
+
+mrat :: Rational -> MathItem
+mrat = fromRational
+
+sub, sup :: MathItem -> MathItem
+sub = (rawMath "_" ⊕) . mathGroup
+sup = (rawMath "^" ⊕) . mathGroup
+
+frac, stackrel :: MathItem -> MathItem -> MathItem
+frac m1 m2 = mathCmdMathArgs "frac" [B.mandatory m1,B.mandatory m2]
+stackrel m1 m2 = mathCmdMathArgs "stackrel" [B.mandatory m1,B.mandatory m2]
+
+sqrt :: MathItem -> MathItem
+sqrt = mathCmdMathArg "sqrt"
+
+sqrt' :: MathItem -> MathItem -> MathItem
+sqrt' n1 m1 = mathCmdMathArgs "sqrt" [B.optional n1, B.mandatory m1]
+
+phantom :: MathItem -> MathItem
+phantom = mathCmdMathArg "phantom"
+
+mleft, mright :: Char -> MathItem
+mleft m1  = MathItem $ RawMath . ("\\left"  ⊕) <$> parenChar m1
+mright m1 = MathItem $ RawMath . ("\\right" ⊕) <$> parenChar m1
+
+between :: Char -> Char -> MathItem -> MathItem
+between opening closing m1 = mleft opening ⊕ m1 ⊕ mright closing
+
+parens, braces, brackets :: MathItem -> MathItem
+parens   = between '(' ')'
+braces   = between '{' '}'
+brackets = between '[' ']'
+
+parenChar :: Char -> LatexM String
+parenChar m1 | m1 `elem` "([.])" = return [m1]
+             | m1 == '{'         = return "\\{"
+             | m1 == '}'         = return "\\}"
+             | otherwise         = throwError $ "invalid parenthesis-like: " ++ show m1
+
+-- NOTE: This command is defined in the amsmath package. It does conflict with
+-- some other packages/classes like the JFP class.
+-- Maybe this should be move to a Amsmath module
+text :: LatexItem -> MathItem
+text arg = mathCmdArgs "text" [B.packageDependency amsmath, B.mandatoryLatexItem arg]
+
+mbox :: LatexItem -> MathItem
+mbox arg = mathCmdArgs "mbox" [B.mandatoryLatexItem arg]
+
+array :: [RowSpec MathItem] -> [Row MathItem] -> MathItem
+array spec items = MathItem $ B.tabularLike MathArray (map (fmap mathItmM) spec)
+                                                      (map (fmap mathItmM) items)
+
+-- TODO equation
+
+{- This chunk was extracted from Language.LaTeX.Builder -}
+lbrace :: MathItem
+lbrace = mathCmd "{"
+rbrace :: MathItem
+rbrace = mathCmd "}"
+lparen :: MathItem
+lparen = rawMathChar '('
+rparen :: MathItem
+rparen = rawMathChar ')'
+space :: MathItem
+space = mathCmd " "
+at :: MathItem
+at = mathCmd "@"
+in_ :: MathItem
+in_ = mathCmd "in"
+forall_ :: MathItem
+forall_ = mathCmd "forall"
+thinspace :: MathItem
+thinspace = mathCmd ","
+negthinspace :: MathItem
+negthinspace = mathCmd "!"
+
+-- \: or \> in LaTeX
+mediumspace :: MathItem
+mediumspace = mathCmd ":"
+thickspace :: MathItem
+thickspace = mathCmd ";"
+msup :: MathItem
+msup = mathCmd "sup"
+alpha :: MathItem
+alpha = mathCmd "alpha"
+beta :: MathItem
+beta = mathCmd "beta"
+chi :: MathItem
+chi = mathCmd "chi"
+-- Chi? (don't forget the charToMath table)
+delta :: MathItem
+delta = mathCmd "delta"
+_Delta :: MathItem
+_Delta = mathCmd "Delta"
+epsilon :: MathItem
+epsilon = mathCmd "epsilon"
+varepsilon :: MathItem
+varepsilon = mathCmd "varepsilon"
+eta :: MathItem
+eta = mathCmd "eta"
+gamma :: MathItem
+gamma = mathCmd "gamma"
+_Gamma :: MathItem
+_Gamma = mathCmd "Gamma"
+iota :: MathItem
+iota = mathCmd "iota"
+kappa :: MathItem
+kappa = mathCmd "kappa"
+lambda :: MathItem
+lambda = mathCmd "lambda"
+_Lambda :: MathItem
+_Lambda = mathCmd "Lambda"
+mu :: MathItem
+mu = mathCmd "mu"
+nu :: MathItem
+nu = mathCmd "nu"
+omega :: MathItem
+omega = mathCmd "omega"
+_Omega :: MathItem
+_Omega = mathCmd "Omega"
+-- | In LaTeX math mode omicron is just 'o',
+--   it is exported as omicron here as well just
+--   for convinience.
+omicron :: MathItem
+omicron = mathCmd "o"
+phi :: MathItem
+phi = mathCmd "phi"
+varphi :: MathItem
+varphi = mathCmd "varphi"
+_Phi :: MathItem
+_Phi = mathCmd "Phi"
+pi :: MathItem
+pi = mathCmd "pi"
+_Pi :: MathItem
+_Pi = mathCmd "Pi"
+psi :: MathItem
+psi = mathCmd "psi"
+rho :: MathItem
+rho = mathCmd "rho"
+sigma :: MathItem
+sigma = mathCmd "sigma"
+_Sigma :: MathItem
+_Sigma = mathCmd "Sigma"
+tau :: MathItem
+tau = mathCmd "tau"
+theta :: MathItem
+theta = mathCmd "theta"
+vartheta :: MathItem
+vartheta = mathCmd "vartheta"
+_Theta :: MathItem
+_Theta = mathCmd "Theta"
+upsilon :: MathItem
+upsilon = mathCmd "upsilon"
+xi :: MathItem
+xi = mathCmd "xi"
+_Xi :: MathItem
+_Xi = mathCmd "Xi"
+zeta :: MathItem
+zeta = mathCmd "zeta"
+backslash :: MathItem
+backslash = mathCmd "backslash"
+times :: MathItem
+times = mathCmd "times"
+div :: MathItem
+div = mathCmd "div"
+circ :: MathItem
+circ = mathCmd "circ"
+oplus :: MathItem
+oplus = mathCmd "oplus"
+otimes :: MathItem
+otimes = mathCmd "otimes"
+sum :: MathItem
+sum = mathCmd "sum"
+prod :: MathItem
+prod = mathCmd "prod"
+wedge :: MathItem
+wedge = mathCmd "wedge"
+bigwedge :: MathItem
+bigwedge = mathCmd "bigwedge"
+vee :: MathItem
+vee = mathCmd "vee"
+bigvee :: MathItem
+bigvee = mathCmd "bigvee"
+cup :: MathItem
+cup = mathCmd "cup"
+bigcup :: MathItem
+bigcup = mathCmd "bigcup"
+cap :: MathItem
+cap = mathCmd "cap"
+bigcap :: MathItem
+bigcap = mathCmd "bigcap"
+ne :: MathItem
+ne = mathCmd "ne"
+le :: MathItem
+le = mathCmd "le"
+leq :: MathItem
+leq = mathCmd "leq"
+ge :: MathItem
+ge = mathCmd "ge"
+geq :: MathItem
+geq = mathCmd "geq"
+prec :: MathItem
+prec = mathCmd "prec"
+succ :: MathItem
+succ = mathCmd "succ"
+notin :: MathItem
+notin = mathCmd "notin"
+subset :: MathItem
+subset = mathCmd "subset"
+supset :: MathItem
+supset = mathCmd "supset"
+subseteq :: MathItem
+subseteq = mathCmd "subseteq"
+supseteq :: MathItem
+supseteq = mathCmd "supseteq"
+equiv :: MathItem
+equiv = mathCmd "equiv"
+cong :: MathItem
+cong = mathCmd "cong"
+approx :: MathItem
+approx = mathCmd "approx"
+propto :: MathItem
+propto = mathCmd "propto"
+neg :: MathItem
+neg = mathCmd "neg"
+implies :: MathItem
+implies = mathCmd "implies"
+iff :: MathItem
+iff = mathCmd "iff"
+exists :: MathItem
+exists = mathCmd "exists"
+bullet :: MathItem
+bullet = mathCmd "bullet"
+bot :: MathItem
+bot = mathCmd "bot"
+top :: MathItem
+top = mathCmd "top"
+vdash :: MathItem
+vdash = mathCmd "vdash"
+models :: MathItem
+models = mathCmd "models"
+langle :: MathItem
+langle = mathCmd "langle"
+rangle :: MathItem
+rangle = mathCmd "rangle"
+int :: MathItem
+int = mathCmd "int"
+oint :: MathItem
+oint = mathCmd "oint"
+partial :: MathItem
+partial = mathCmd "partial"
+nabla :: MathItem
+nabla = mathCmd "nabla"
+pm :: MathItem
+pm = mathCmd "pm"
+emptyset :: MathItem
+emptyset = mathCmd "emptyset"
+infty :: MathItem
+infty = mathCmd "infty"
+aleph :: MathItem
+aleph = mathCmd "aleph"
+ldots :: MathItem
+ldots = mathCmd "ldots"
+cdots :: MathItem
+cdots = mathCmd "cdots"
+vdots :: MathItem
+vdots = mathCmd "vdots"
+ddots :: MathItem
+ddots = mathCmd "ddots"
+cdotp :: MathItem
+cdotp = mathCmd "cdotp"
+ldotp :: MathItem
+ldotp = mathCmd "ldotp"
+quad :: MathItem
+quad = mathCmd "quad"
+diamond :: MathItem
+diamond = mathCmd "diamond"
+square :: MathItem
+square = mathCmd "square"
+lfloor :: MathItem
+lfloor = mathCmd "lfloor"
+rfloor :: MathItem
+rfloor = mathCmd "rfloor"
+lceil :: MathItem
+lceil = mathCmd "lceil"
+rceil :: MathItem
+rceil = mathCmd "rceil"
+sin :: MathItem
+sin = mathCmd "sin"
+cos :: MathItem
+cos = mathCmd "cos"
+tan :: MathItem
+tan = mathCmd "tan"
+csc :: MathItem
+csc = mathCmd "csc"
+sec :: MathItem
+sec = mathCmd "sec"
+cot :: MathItem
+cot = mathCmd "cot"
+sinh :: MathItem
+sinh = mathCmd "sinh"
+cosh :: MathItem
+cosh = mathCmd "cosh"
+tanh :: MathItem
+tanh = mathCmd "tanh"
+log :: MathItem
+log = mathCmd "log"
+ln :: MathItem
+ln = mathCmd "ln"
+det :: MathItem
+det = mathCmd "det"
+dim :: MathItem
+dim = mathCmd "dim"
+lim :: MathItem
+lim = mathCmd "lim"
+mod :: MathItem
+mod = mathCmd "mod"
+gcd :: MathItem
+gcd = mathCmd "gcd"
+lcm :: MathItem
+lcm = mathCmd "lcm"
+liminf :: MathItem
+liminf = mathCmd "liminf"
+inf :: MathItem
+inf = mathCmd "inf"
+limsup :: MathItem
+limsup = mathCmd "limsup"
+max :: MathItem
+max = mathCmd "max"
+min :: MathItem
+min = mathCmd "min"
+_Pr :: MathItem
+_Pr = mathCmd "Pr"
+uparrow :: MathItem
+uparrow = mathCmd "uparrow"
+downarrow :: MathItem
+downarrow = mathCmd "downarrow"
+_Uparrow :: MathItem
+_Uparrow = mathCmd "Uparrow"
+_Downarrow :: MathItem
+_Downarrow = mathCmd "Downarrow"
+rightarrow :: MathItem
+rightarrow = mathCmd "rightarrow"
+longrightarrow :: MathItem
+longrightarrow = mathCmd "longrightarrow"
+to :: MathItem
+to = mathCmd "to"
+leftarrow :: MathItem
+leftarrow = mathCmd "leftarrow"
+longleftarrow :: MathItem
+longleftarrow = mathCmd "longleftarrow"
+leftrightarrow :: MathItem
+leftrightarrow = mathCmd "leftrightarrow"
+longleftrightarrow :: MathItem
+longleftrightarrow = mathCmd "longleftrightarrow"
+_Rightarrow :: MathItem
+_Rightarrow = mathCmd "Rightarrow"
+_Leftarrow :: MathItem
+_Leftarrow = mathCmd "Leftarrow"
+_Leftrightarrow :: MathItem
+_Leftrightarrow = mathCmd "Leftrightarrow"
+-- https://secure.wikimedia.org/wikibooks/en/wiki/LaTeX/Mathematics#Formatting_mathematics_symbols
+-- they are said to depend on amsfonts, maybe one should force it
+mathnormal, mathrm, mathit, mathbf, mathsf, mathtt, mathbb, mathcal, mathfrak, mathscr :: MathItem -> MathItem
+mathnormal = mathCmdMathArg "mathnormal"
+mathrm = mathCmdMathArg "mathrm"
+mathit = mathCmdMathArg "mathit"
+mathbf = mathCmdMathArg "mathbf"
+mathsf = mathCmdMathArg "mathsf"
+mathtt = mathCmdMathArg "mathtt"
+mathcal = mathCmdMathArg "mathcal"
+mathfrak = mathCmdMathArg "mathfrak"
+mathbb = mathCmdMathArg "mathbb"
+mathscr = mathCmdMathArg "mathscr"
+pmod :: MathItem -> MathItem
+pmod = mathCmdMathArg "pmod"
+tilde :: MathItem -> MathItem
+tilde = mathCmdMathArg "tilde"
+hat :: MathItem -> MathItem
+hat = mathCmdMathArg "hat"
+check :: MathItem -> MathItem
+check = mathCmdMathArg "check"
+breve :: MathItem -> MathItem
+breve = mathCmdMathArg "breve"
+acute :: MathItem -> MathItem
+acute = mathCmdMathArg "acute"
+grave :: MathItem -> MathItem
+grave = mathCmdMathArg "grave"
+bar :: MathItem -> MathItem
+bar = mathCmdMathArg "bar"
+vec :: MathItem -> MathItem
+vec = mathCmdMathArg "vec"
+dot :: MathItem -> MathItem
+dot = mathCmdMathArg "dot"
+ddot :: MathItem -> MathItem
+ddot = mathCmdMathArg "ddot"
+overbrace :: MathItem -> MathItem
+overbrace = mathCmdMathArg "overbrace"
+underbrace :: MathItem -> MathItem
+underbrace = mathCmdMathArg "underbrace"
+overline :: MathItem -> MathItem
+overline = mathCmdMathArg "overline"
+underline :: MathItem -> MathItem
+underline = mathCmdMathArg "underline"
+widehat :: MathItem -> MathItem
+widehat = mathCmdMathArg "widehat"
+widetilde :: MathItem -> MathItem
+widetilde = mathCmdMathArg "widetilde"
+imath :: MathItem -> MathItem
+imath = mathCmdMathArg "imath"
+jmath :: MathItem -> MathItem
+jmath = mathCmdMathArg "jmath"
+displaystyle :: MathDecl
+displaystyle = mathDecl "displaystyle"
+textstyle :: MathDecl
+textstyle = mathDecl "textstyle"
+scriptstyle :: MathDecl
+scriptstyle = mathDecl "scriptstyle"
+scriptscriptstyle :: MathDecl
+scriptscriptstyle = mathDecl "scriptscriptstyle"
+mit :: MathDecl
+mit = mathDecl "mit"
+cal :: MathDecl
+cal = mathDecl "cal"
+eq :: MathItem
+eq = rawMathChar '='
+neq :: MathItem
+neq = mathCmd "neq"
+a :: MathItem
+a = rawMathChar 'a'
+b :: MathItem
+b = rawMathChar 'b'
+c :: MathItem
+c = rawMathChar 'c'
+d :: MathItem
+d = rawMathChar 'd'
+e :: MathItem
+e = rawMathChar 'e'
+f :: MathItem
+f = rawMathChar 'f'
+g :: MathItem
+g = rawMathChar 'g'
+h :: MathItem
+h = rawMathChar 'h'
+i :: MathItem
+i = rawMathChar 'i'
+j :: MathItem
+j = rawMathChar 'j'
+k :: MathItem
+k = rawMathChar 'k'
+l :: MathItem
+l = rawMathChar 'l'
+m :: MathItem
+m = rawMathChar 'm'
+n :: MathItem
+n = rawMathChar 'n'
+o :: MathItem
+o = rawMathChar 'o'
+p :: MathItem
+p = rawMathChar 'p'
+q :: MathItem
+q = rawMathChar 'q'
+r :: MathItem
+r = rawMathChar 'r'
+s :: MathItem
+s = rawMathChar 's'
+t :: MathItem
+t = rawMathChar 't'
+u :: MathItem
+u = rawMathChar 'u'
+v :: MathItem
+v = rawMathChar 'v'
+w :: MathItem
+w = rawMathChar 'w'
+x :: MathItem
+x = rawMathChar 'x'
+y :: MathItem
+y = rawMathChar 'y'
+z :: MathItem
+z = rawMathChar 'z'
+_A :: MathItem
+_A = rawMathChar 'A'
+_B :: MathItem
+_B = rawMathChar 'B'
+_C :: MathItem
+_C = rawMathChar 'C'
+_D :: MathItem
+_D = rawMathChar 'D'
+_E :: MathItem
+_E = rawMathChar 'E'
+_F :: MathItem
+_F = rawMathChar 'F'
+_G :: MathItem
+_G = rawMathChar 'G'
+_H :: MathItem
+_H = rawMathChar 'H'
+_I :: MathItem
+_I = rawMathChar 'I'
+_J :: MathItem
+_J = rawMathChar 'J'
+_K :: MathItem
+_K = rawMathChar 'K'
+_L :: MathItem
+_L = rawMathChar 'L'
+_M :: MathItem
+_M = rawMathChar 'M'
+_N :: MathItem
+_N = rawMathChar 'N'
+_O :: MathItem
+_O = rawMathChar 'O'
+_P :: MathItem
+_P = rawMathChar 'P'
+_Q :: MathItem
+_Q = rawMathChar 'Q'
+_R :: MathItem
+_R = rawMathChar 'R'
+_S :: MathItem
+_S = rawMathChar 'S'
+_T :: MathItem
+_T = rawMathChar 'T'
+_U :: MathItem
+_U = rawMathChar 'U'
+_V :: MathItem
+_V = rawMathChar 'V'
+_W :: MathItem
+_W = rawMathChar 'W'
+_X :: MathItem
+_X = rawMathChar 'X'
+_Y :: MathItem
+_Y = rawMathChar 'Y'
+_Z :: MathItem
+_Z = rawMathChar 'Z'
+
+vartriangleright :: MathItem
+vartriangleright = mathCmd "vartriangleright"
+
+bmod :: MathItem -> MathItem -> MathItem
+bmod = mathBinOp "bmod"
+
+mathlift :: (LatexItem -> LatexItem) -> MathItem -> MathItem
+mathlift fun = text . fun . B.math
+{-# DEPRECATED mathlift "The use of M.text should be done with care (mbox is an alternative)" #-}
+
+divide :: MathItem
+divide = mathCmd "div"
+{-# DEPRECATED divide "Use div instead" #-}
+
+allMathDecls :: [MathDecl]
+allMathDecls = [displaystyle, textstyle, scriptstyle, scriptscriptstyle, mit, cal]
+
+allMathItems :: [MathItem]
+allMathItems =
+  [lbrace, rbrace, space, at, in_, forall_, thinspace, negthinspace, mediumspace,
+   thickspace, msup, alpha, beta, chi, delta, _Delta, epsilon, varepsilon, eta,
+   gamma, _Gamma, iota, kappa, lambda, _Lambda, mu, nu, omega, _Omega, phi, varphi,
+   _Phi, pi, _Pi, psi, rho, sigma, _Sigma, tau, theta, vartheta, _Theta, upsilon,
+   xi, _Xi, zeta, backslash, times, div, circ, oplus, otimes, sum, prod, wedge,
+   bigwedge, vee, bigvee, cup, bigcup, cap, bigcap, ne, le, leq, ge, geq, prec, succ,
+   notin, subset, supset, subseteq, supseteq, equiv, cong, approx, propto, neg, implies,
+   iff, exists, bullet, bot, top, vdash, models, langle, rangle, int, oint, partial, nabla, pm,
+   emptyset, infty, aleph, ldots, cdots, vdots, ddots, quad, diamond, square, lfloor,
+   rfloor, lceil, rceil, sin, cos, tan, csc, sec, cot, sinh, cosh, tanh, log, ln,
+   det, dim, lim, mod, gcd, lcm, liminf, inf, limsup, max, min, _Pr, uparrow, downarrow,
+   rightarrow, to, leftarrow, leftrightarrow, _Rightarrow, _Leftarrow, _Leftrightarrow
+  ,longrightarrow,longrightarrow,longleftrightarrow
+  ,vartriangleright, cdotp, ldotp, _Downarrow, _Uparrow
+  -- maually added
+  ,eq,neq
+  ,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
+  ,_A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P
+  ,_Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z
+  ,lparen,rparen
+  ]
+
+mathCmdsArg :: [MathItem -> MathItem]
+mathCmdsArg = [mathbf, mathbb, mathcal, mathtt, mathfrak, pmod, tilde, hat, check,
+                breve, acute, grave, bar, vec, dot, ddot, overbrace, underbrace, overline,
+                underline, widehat, widetilde, imath, jmath
+                -- maually added
+               ,negate
+               , sqrt, phantom
+               ]
+
+mathBinOps :: [MathItem -> MathItem -> MathItem]
+mathBinOps = [(+),(-),(*),bmod]
+
+amsmath :: PackageName
+amsmath = PkgName "amsmath"
+
+protector :: XChar -> String -> LatexItem
+protector = B.protector . mchar
+
+protect :: String -> LatexItem
+protect = protector B.hchar
+
+verb :: String -> LatexItem
+verb = protector B.ttchar
+
+{- NOT USED
+mchar :: XChar
+mchar '\\' = "\\textbackslash{}"
+mchar '~'  = "\\text{\\~{}}"
+mchar '^'  = "\\^{}"
+mchar ':'  = ":"
+mchar '_'  = "\\_"
+mchar x | x `elem` "#&{}$%"  = ['\\',x]
+        | x `elem` "]["      = ['{', x, '}'] -- to avoid mess up optional args
+        | otherwise          = [x]
+-}
+
+type MXChar = Char -> MathItem
+
+-- This char translator transformer only take care of math specific characters.
+-- For instance 'a' will be displayed in text mode.
+mchar :: XChar -> XChar
+mchar xchar ch = maybe (xchar ch) B.math m'
+  where m' | isAscii ch && (isAlphaNum ch || isSpace ch) = Nothing
+           | otherwise                   = charToMath ch
+
+-- find a better name and export
+mchar' :: XChar -> MXChar
+mchar' xchar ch = fromMaybe (mbox (xchar ch)) (charToMath ch)
+
+stringToMath :: String -> MathItem
+stringToMath = foldMap $ mchar' B.hchar
+
+mstring :: String -> LatexItem
+mstring = B.math . stringToMath
+
+instance IsString MathItem where
+  fromString = stringToMath
+
+charToMath :: Char -> Maybe MathItem
+charToMath ch
+   | isAscii ch && (isAlphaNum ch || isSpace ch) = Just $ rawMathChar ch
+   | otherwise = IntMap.lookup (fromEnum ch) mapping
+  where
+    mapping = IntMap.fromList $ map (first fromEnum)
+      [ ('α', alpha)
+      , ('β', beta)
+      , ('χ', chi)
+      , ('δ', delta)
+      , ('Δ', _Delta)
+      , ('ε', epsilon)
+      --, ('', varepsilon)
+      , ('η', eta)
+      , ('γ', gamma)
+      , ('Γ', _Gamma)
+      , ('ι', iota)
+      , ('κ', kappa)
+      , ('λ', lambda)
+      , ('Λ', _Lambda)
+      , ('μ', mu) -- '\956' mu
+      , ('µ', mu) -- '\181' micro sign, is there a specific latex macro for it?
+      , ('ν', nu)
+      , ('ω', omega)
+      , ('Ω', _Omega)
+      , ('ο', omicron)
+      , ('φ', phi)
+      --, ('', varphi)
+      , ('Φ', _Phi)
+      , ('π', pi)
+      , ('Π', _Pi)
+      , ('ψ', psi)
+      , ('ρ', rho)
+      , ('σ', sigma)
+      , ('Σ', _Sigma)
+      , ('τ', tau)
+      , ('θ', theta)
+      --, ('', vartheta)
+      , ('Θ', _Theta)
+      --, ('', upsilon)
+      , ('ξ', xi)
+      --, ('', _Xi)
+      , ('ζ', zeta)
+      , ('×', times)
+      , ('÷', div)
+      , ('·', cdotp)
+      , ('∘', circ)
+      , ('⊕', oplus)
+      , ('⊗', otimes)
+      , ('∧', wedge)
+      --, ('', bigwedge)
+      , ('∨', vee)
+      --, ('', bigvee)
+      , ('∪', cup)
+      --, ('', bigcup)
+      --, ('', cap)
+      --, ('', bigcap)
+      , ('≠', ne)
+      --, ('', le)
+      , ('≤', leq)
+      --, ('', ge)
+      , ('≥', geq)
+      , ('∈', in_)
+      , ('∉', notin)
+      , ('⊂', subset)
+      , ('⊃', supset)
+      , ('⊆', subseteq)
+      , ('⊇', supseteq)
+      , ('≡', equiv)
+      , ('=', eq)
+      , ('≠', neq)
+      --, ('', cong)
+      , ('≈', approx)
+      --, ('', propto)
+      , ('¬', neg)
+      --, ('', iff)
+      , ('∀', forall_)
+      , ('∃', exists)
+      , ('⊥', bot)
+      , ('⊤', top)
+      , ('⊢', vdash)
+      , ('⊩', models)
+      , ('⟨', langle)
+      , ('⟩', rangle)
+      , ('●', bullet)
+      {-
+      , ('', int)
+      , ('', oint)
+      , ('', partial)
+      , ('', nabla)
+      , ('', pm)
+      -}
+      , ('ø', emptyset)
+      , ('∞', infty)
+      , ('…', ldots)
+      , ('⋯', cdots)
+      , ('⋮', vdots)
+      {-
+      , ('', aleph)
+      , ('', ddots)
+      , ('', quad)
+      , ('', diamond)
+      , ('', square)
+      -}
+      , ('⌈', lceil)
+      , ('⌉', rceil)
+      , ('⌊', lfloor)
+      , ('⌋', rfloor)
+      , ('↑', uparrow)
+      {-
+      , ('', downarrow)
+prec
+succ
+      -}
+      , ('→', rightarrow)
+      --, ('', to)
+      , ('←', leftarrow)
+      , ('↔', leftrightarrow)
+      , ('⇒', _Rightarrow)
+      , ('⇐', _Leftarrow)
+      , ('⇔', _Leftrightarrow)
+      , ('⟶', longrightarrow)
+      , ('⟵', longleftarrow)
+      , ('▹', vartriangleright)
+      -- black board
+      , ('ℕ', mathbb _N)
+      , ('ℍ', mathbb _H)
+      , ('ℙ', mathbb _P)
+      , ('ℝ', mathbb _R)
+      , ('ⅅ', mathbb _D)
+      , ('ℚ', mathbb _Q)
+      , ('ℤ', mathbb _Z)
+      --fail/TODO: find the correct definitions
+      --, ('ℽ', mathbb gamma)
+      --, ('ℾ', mathbb _Gamma)
+      --, ('ℿ', mathbb _Pi)
+      --, ('⅀', mathbb _Sigma)
+
+      -- mathcal
+      , ('℘', mathcal _P)
+      , ('ℒ', mathcal _L)
+      , ('ℛ', mathcal _R)
+      , ('𝒩', mathcal _N)
+
+      ]
diff --git a/Language/LaTeX/Builder/MonoidUtils.hs b/Language/LaTeX/Builder/MonoidUtils.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder/MonoidUtils.hs
@@ -0,0 +1,24 @@
+module Language.LaTeX.Builder.MonoidUtils (ø, (⊕), (<>), (<||>), (<&&>), mapNonEmpty) where
+
+import Data.Monoid
+import Data.Monoid.Unicode ((⊕))
+
+infixr 5 <>
+(<>) :: Monoid m => m -> m -> m
+(<>) = mappend
+
+ø :: Monoid m => m
+ø = mempty
+
+(<||>) :: (Monoid a, Eq a) => a -> a -> a
+a <||> b | a == ø     = b
+         | otherwise  = a
+
+(<&&>) :: (Monoid a, Eq a, Monoid b) => a -> b -> b
+a <&&> b | a == ø     = ø
+         | otherwise  = b
+
+mapNonEmpty :: (Eq a, Monoid a, Monoid b) => (a -> b) -> a -> b
+mapNonEmpty f x | x == ø     = ø
+                | otherwise  = f x
+
diff --git a/Language/LaTeX/Builder/QQ.hs b/Language/LaTeX/Builder/QQ.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder/QQ.hs
@@ -0,0 +1,96 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Language.LaTeX.Builder.QQ
+  (-- * Quasi Quoters
+   frQQ,frQQFile,str,strFile,istr,tex,texFile,texm,texmFile,qm,qmFile,qp,qpFile,
+   keys,keysFile,
+   -- * Building new Quasi Quoters
+   mkQQ, mkQQnoIndent, mkQQgen, mkQQFile, indent, noIndent,
+   stripIndentQQ,
+   -- * Misc functions used by the frquotes expander of «...»
+   frTop, frAntiq,
+  ) where
+
+import Data.List
+import Data.Char
+import Data.Functor
+import Language.Haskell.TH (Q, Exp, Name, appE, varE, stringE, litP, stringL, valD,
+                            varP, sigD, mkName, normalB, conE)
+import Language.Haskell.TH.Quote
+import Language.Haskell.TH.Syntax (Lift(..))
+import Language.LaTeX.Types (Key(..))
+import Language.LaTeX.Builder.Internal (rawTex, rawPreamble, rawMath)
+import Language.LaTeX.Builder.Math (mstring)
+import Language.LaTeX.Builder (hstring)
+
+frTop :: a -> a
+frTop = id
+
+frAntiq :: a -> a
+frAntiq = id
+
+frQQ,frQQFile,str,strFile,istr,tex,texFile,qm,qmFile,qp,qpFile,
+  keys, keysFile :: QuasiQuoter
+
+quasiQuoter :: String -> QuasiQuoter
+quasiQuoter qqName =
+  QuasiQuoter (err "expressions") (err "patterns")
+-- if GHC7
+              (err "types") (err "declarations")
+-- endif
+  where err kind _ = fail $ qqName ++ ": not available in " ++ kind
+
+stripIndentQQ :: String -> Q String
+stripIndentQQ = fmap unlines' . skipFirst (mapM dropBar . dropLastWhen null . map (dropWhile isSpace)) . lines
+  where unlines'   = intercalate "\n"
+        skipFirst _ []     = return []
+        skipFirst f (x:xs) = (x :) <$> f xs
+        dropLastWhen _ [] = []
+        dropLastWhen p (x:xs) | null xs && p x = []
+                              | otherwise      = x:dropLastWhen p xs
+        dropBar ('|':xs) = return xs
+        dropBar []       = fail "stripIndentQQ: syntax error '|' expected after spaces (unexpected empty string)"
+        dropBar (c:_)    = fail $ "stripIndentQQ: syntax error '|' expected after spaces (unexpected "++show c++")"
+
+str = (quasiQuoter "str"){ quoteExp = stringE
+                         , quotePat = litP . stringL }
+strFile = quoteFile str
+
+mkQQgen :: (String -> Q Exp) -> String -> Name -> QuasiQuoter
+mkQQgen pre qqName qqFun = (quasiQuoter qqName){ quoteExp = appE (varE qqFun) . pre }
+
+mkQQ :: String -> Name -> QuasiQuoter
+mkQQ = mkQQgen indent
+
+mkQQnoIndent :: String -> Name -> QuasiQuoter
+mkQQnoIndent = mkQQgen lift
+
+mkQQFile :: (String -> Q Exp) -> String -> Name -> (QuasiQuoter, QuasiQuoter)
+mkQQFile pre qqName qqFun = (mkQQgen pre qqName qqFun , quoteFile (mkQQgen lift qqName qqFun))
+
+indent, noIndent :: String -> Q Exp
+indent = (lift =<<) . stripIndentQQ
+noIndent = lift
+
+-- istr ≡ mkQQ "istr" 'id
+istr = (quasiQuoter "istr"){ quoteExp = (stringE =<<) . stripIndentQQ }
+-- istrFile makes no sense, use strFile instead
+
+-- | Quasiquoter for raw TeX in math mode
+texm, texmFile :: QuasiQuoter
+
+(frQQ, frQQFile) = mkQQFile noIndent "frQQ" 'hstring
+(tex,  texFile)  = mkQQFile indent   "tex"  'rawTex
+(texm, texmFile) = mkQQFile indent   "texm" 'rawMath
+(qm,   qmFile)   = mkQQFile indent   "qm"   'mstring
+(qp,   qpFile)   = mkQQFile indent   "qp"   'rawPreamble
+
+keys = (quasiQuoter "keys"){ quoteDec = fs } where
+  fs = sequence . concatMap f . words
+  clean = filter isAlphaNum
+  f x = [sigD n [t|Key|]
+        ,valD (varP n)
+              (normalB (appE (conE 'MkKey) $ stringE x))
+              []
+        ]
+        where n = mkName (clean x)
+keysFile  = quoteFile keys
diff --git a/Language/LaTeX/Builder/Rotating.hs b/Language/LaTeX/Builder/Rotating.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Builder/Rotating.hs
@@ -0,0 +1,10 @@
+module Language.LaTeX.Builder.Rotating (pkg, turn) where
+
+import Language.LaTeX.Types
+import qualified Language.LaTeX.Builder.Internal as BI
+
+pkg :: PackageName
+pkg = BI.pkgName "rotating"
+
+turn :: Int -> LatexItem -> LatexItem
+turn i = BI.latexEnvironment "turn" [BI.packageDependency pkg, BI.mandatory (BI.num i)]
diff --git a/Language/LaTeX/Checker.hs b/Language/LaTeX/Checker.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Checker.hs
@@ -0,0 +1,20 @@
+module Language.LaTeX.Checker where
+
+import Data.Set (Set)
+import qualified Data.Set as Set
+import Data.Generics.Uniplate.Data (universeBi)
+import Language.LaTeX.Types
+
+providedPackages :: PreambleItm -> Set PackageName
+providedPackages x = Set.fromList [ pkg | ProvidePackage pkg <- universeBi x ]
+
+neededPackages :: Document -> Set PackageName
+neededPackages x = Set.fromList [ pkg | PackageDependency pkg <- universeBi x ]
+
+checkDocument :: Document -> Maybe ErrorMessage
+checkDocument doc
+  | not . null $ missingPkgs = Just ("Missing packages: " ++ show missingPkgs)
+  | otherwise                = Nothing
+ where providedPkgs = providedPackages . documentPreamble $ doc
+       neededPkgs   = neededPackages doc
+       missingPkgs  = map getPkgName . Set.toList $ neededPkgs `Set.difference` providedPkgs
diff --git a/Language/LaTeX/Length.hs b/Language/LaTeX/Length.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Length.hs
@@ -0,0 +1,117 @@
+module Language.LaTeX.Length
+  (
+  -- Units
+    inch, pt, em, cm, mm, ex, pc, sp, bp, dd, cc, mu
+  -- Dynamic Length
+  , stretch
+  -- Predefined lengths
+  , parindent, textwidth, linewidth, textheight, parsep, parskip, baselineskip
+  , baselinestrech, fill, columnsep, columnseprule, mathindent, oddsidemargin
+  , evensidemargin, marginparwidth, marginparsep, marginparpush, topmargin
+  , headheight, headsep, topskip, footheight, footskip, topsep, partopsep, itemsep
+  , itemindent, labelsep, labelwidth, leftmargin, rightmargin, listparindent, jot
+  , abovedisplayskip, belowdisplayskip, abovedisplayshortskip
+  , belowdisplayshortskip, floatsep, textfloatsep, intextsep, dblfloatsep
+  , dbltextfloatsep, textfraction, floatpagefraction, dbltopfaction
+  , dblfloatpagefraction, arraycolsep, tabcolsep, arrayrulewidth, doublerulesep
+  , arraystretch, bigskipamount, medskipamount, smallskipamount, fboxrule, fboxsep
+  )
+  where
+
+import Language.LaTeX.Types
+
+inch, pt, em, cm, mm, ex, pc, sp, bp, dd, cc, mu :: Rational -> LatexLength
+pt = withUnit Pt
+em = withUnit Em
+cm = withUnit Cm
+mm = withUnit Mm
+ex = withUnit Ex
+pc = withUnit Pc
+
+-- | Since 'in' is a keyword in Haskell, this one is called 'inch'.
+inch = withUnit In
+sp = withUnit Sp
+bp = withUnit Bp
+dd = withUnit Dd
+cc = withUnit Cc
+mu = withUnit Mu
+
+-- | Internal function to make LatexLength commands
+lengthCmd :: String -> LatexLength
+lengthCmd = LengthCmd
+
+-- | Internal function to make LatexLength commands
+withUnit :: TexUnit -> Rational -> LatexLength
+withUnit unit = LengthCst (Just unit)
+
+-- robust
+stretch :: Rational -> LatexLength
+stretch = LengthCmdRatArg "stretch"
+
+parindent, textwidth, linewidth, textheight, parsep, parskip, baselineskip, baselinestrech,
+  fill, columnsep, columnseprule, mathindent, oddsidemargin, evensidemargin, marginparwidth,
+  marginparsep, marginparpush, topmargin, headheight, headsep, topskip, footheight, footskip,
+  topsep, partopsep, itemsep, itemindent, labelsep, labelwidth, leftmargin, rightmargin,
+  listparindent, jot, abovedisplayskip, belowdisplayskip, abovedisplayshortskip,
+  belowdisplayshortskip, floatsep, textfloatsep, intextsep, dblfloatsep, dbltextfloatsep,
+  textfraction, floatpagefraction, dbltopfaction, dblfloatpagefraction, arraycolsep,
+  tabcolsep, arrayrulewidth, doublerulesep, arraystretch, bigskipamount, medskipamount,
+  smallskipamount, fboxrule, fboxsep :: LatexLength
+
+parindent = lengthCmd "parindent"
+textwidth = lengthCmd "textwidth"
+linewidth = lengthCmd "linewidth"
+textheight = lengthCmd "textheight"
+parsep = lengthCmd "parsep"
+parskip = lengthCmd "parskip"
+baselineskip = lengthCmd "baselineskip"
+baselinestrech = lengthCmd "baselinestrech"
+fill = lengthCmd "fill"
+columnsep = lengthCmd "columnsep"
+columnseprule = lengthCmd "columnseprule"
+mathindent = lengthCmd "mathindent"
+oddsidemargin = lengthCmd "oddsidemargin"
+evensidemargin = lengthCmd "evensidemargin"
+marginparwidth = lengthCmd "marginparwidth"
+marginparsep = lengthCmd "marginparsep"
+marginparpush = lengthCmd "marginparpush"
+topmargin = lengthCmd "topmargin"
+headheight = lengthCmd "headheight"
+headsep = lengthCmd "headsep"
+topskip = lengthCmd "topskip"
+footheight = lengthCmd "footheight"
+footskip = lengthCmd "footskip"
+topsep = lengthCmd "topsep"
+partopsep = lengthCmd "partopsep"
+itemsep = lengthCmd "itemsep"
+itemindent = lengthCmd "itemindent"
+labelsep = lengthCmd "labelsep"
+labelwidth = lengthCmd "labelwidth"
+leftmargin = lengthCmd "leftmargin"
+rightmargin = lengthCmd "rightmargin"
+listparindent = lengthCmd "listparindent"
+jot = lengthCmd "jot"
+abovedisplayskip = lengthCmd "abovedisplayskip"
+belowdisplayskip = lengthCmd "belowdisplayskip"
+abovedisplayshortskip = lengthCmd "abovedisplayshortskip"
+belowdisplayshortskip = lengthCmd "belowdisplayshortskip"
+floatsep = lengthCmd "floatsep"
+textfloatsep = lengthCmd "textfloatsep"
+intextsep = lengthCmd "intextsep"
+dblfloatsep = lengthCmd "dblfloatsep"
+dbltextfloatsep = lengthCmd "dbltextfloatsep"
+textfraction = lengthCmd "textfraction"
+floatpagefraction = lengthCmd "floatpagefraction"
+dbltopfaction = lengthCmd "dbltopfaction"
+dblfloatpagefraction = lengthCmd "dblfloatpagefraction"
+arraycolsep = lengthCmd "arraycolsep"
+tabcolsep = lengthCmd "tabcolsep"
+arrayrulewidth = lengthCmd "arrayrulewidth"
+doublerulesep = lengthCmd "doublerulesep"
+arraystretch = lengthCmd "arraystretch"
+bigskipamount = lengthCmd "bigskipamount"
+medskipamount = lengthCmd "medskipamount"
+smallskipamount = lengthCmd "smallskipamount"
+fboxrule = lengthCmd "fboxrule"
+fboxsep = lengthCmd "fboxsep"
+
diff --git a/Language/LaTeX/Printer.hs b/Language/LaTeX/Printer.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Printer.hs
@@ -0,0 +1,245 @@
+module Language.LaTeX.Printer where
+
+import Data.Monoid
+import Data.List (intersperse)
+import Data.Ratio (numerator, denominator)
+import Data.Foldable (foldMap)
+import Data.Char
+import GHC.Float (formatRealFloat, FFFormat(FFFixed))
+
+import Language.LaTeX.Types
+import Language.LaTeX.Checker (checkDocument)
+import Language.LaTeX.Builder.MonoidUtils
+
+optionals :: [a] -> Arg a
+optionals [] = NoArg
+optionals xs = Optional xs
+
+text :: String -> ShowS
+text = showString
+
+between :: String -> String -> ShowS -> ShowS
+between opening closing x = text opening ⊕ x ⊕ text closing
+
+
+braces, brackets, parens :: ShowS -> ShowS
+braces   = between "{" "}"
+brackets = between "[" "]"
+parens   = between "(" ")"
+
+
+nl, nl2, irrNl, backslash, sp :: ShowS
+backslash = text "\\"
+nl = text "\n"
+nl2 = nl ⊕ nl
+sp = text " "
+irrNl = text "%\n"
+
+($$) :: ShowS -> ShowS -> ShowS
+($$) x y = x ⊕ nl ⊕ y
+
+($$$) :: ShowS -> ShowS -> ShowS
+($$$) x y = x ⊕ nl2 ⊕ y
+
+vcat, vcat2 :: [ShowS] -> ShowS
+vcat  = mconcat . intersperse nl
+vcat2 = mconcat . intersperse nl2
+
+ppNamed :: Named ShowS -> ShowS
+ppNamed (Named name val)
+  | null name = val
+  | otherwise = text name ⊕ text "=" ⊕ val
+
+commas :: [ShowS] -> ShowS
+commas = mconcat . intersperse (text ",")
+
+ppArg :: Arg ShowS -> ShowS
+ppArg NoArg             = id
+ppArg StarArg           = text "*"
+ppArg (Optional [])     = error "ppArg: impossible: Optional []"
+ppArg (NamedOpts [])    = error "ppArg: impossible: NamedOpts []"
+ppArg (Mandatory xs)    = braces   . commas $ xs
+ppArg (Optional xs)     = brackets . commas $ xs
+ppArg (NamedArgs xs)    = braces   . commas . map ppNamed $ xs
+ppArg (NamedOpts xs)    = brackets . commas . map ppNamed $ xs
+ppArg (Coordinates x y) = parens (x ⊕ text " " ⊕ y)
+ppArg (LiftArg x)       = x
+ppArg (RawArg x)        = text x
+ppArg (PackageAction _) = id
+
+ppEnv :: String -> [Arg ShowS] -> ShowS -> ShowS
+ppEnv envName args contents =
+  backslash ⊕ begin ⊕ braces envNameS ⊕ mconcat (map ppArg args)
+ $$
+  contents
+ $$
+  backslash ⊕ end ⊕ braces envNameS
+
+  where envNameS = text envName
+        begin    = text "begin"
+        end      = text "end"
+
+-- these are not wrapped by braces
+ppCmdArgs :: String -> [Arg ShowS] -> ShowS
+ppCmdArgs cmdName args = backslash ⊕ text cmdName ⊕ mconcat (map ppArg args)
+
+ppDecl :: String -> ShowS -> ShowS
+ppDecl declName declArgs = backslash ⊕ text declName ⊕ declArgs ⊕ text " " -- or {}
+
+ppTexDecl :: TexDcl -> ShowS
+ppTexDecl (TexDcl declName declArgs) = ppDecl declName (foldMap (ppArg . fmap ppAny) declArgs)
+
+ppMathDecl :: MathDcl -> ShowS
+ppMathDecl (MathDcl declName) = ppDecl declName ø
+
+pp :: LatexItm -> ShowS
+pp (LatexCmdArgs cmdName args) = ppCmdArgs cmdName $ map (fmap pp) args
+pp (LatexCmdAnyArgs cmdName args) = ppCmdArgs cmdName $ map (fmap ppAny) args
+pp (TexDecls decls) = foldMap ppTexDecl decls
+pp (TexCmdNoArg cmdName) = braces $ ppCmdArgs cmdName []
+pp (TexCmdArg cmdName contents)
+ = braces (backslash ⊕ text cmdName ⊕ text " " ⊕ pp contents)
+pp (Environment envName args contents) = ppEnv envName (map (fmap ppAny) args) $ ppAny contents
+pp (RawTex s) = text s
+-- One produces $...$ since \(...\) is ``fragile''
+pp (LatexCast (MathItm m)) = text "$ " ⊕ ppMath m ⊕ text " $"
+pp (LatexCast x) = ppAny x
+pp (TexGroup t) = braces $ pp t
+pp LatexEmpty = ø
+pp (LatexAppend x y) = pp x ⊕ pp y
+pp (LatexNote key note t) = ppNote key note pp t
+
+ppParMode :: ParItm -> ShowS
+ppParMode (ParCast (MathItm m)) = text "\\[ " ⊕ ppMath m ⊕ text " \\]"
+ppParMode (ParCast t) = ppAny t
+ppParMode (ParCmdArgs cmdName args) = ppCmdArgs cmdName $ map (fmap ppAny) args
+ppParMode (RawParMode x) = text x
+ppParMode (ParGroup p) = braces $ ppParMode p
+ppParMode (ParEnv envName args contents)
+  = ppEnv envName (map (fmap ppAny) args) $ ppAny contents
+ppParMode (Tabular specs rows) =
+  ppEnv "tabular" [Mandatory . (:[]) . mconcat $ map (ppRowSpec . fmap pp) specs] (ppRows pp rows)
+ppParMode (ParConcat contents) = vcat2 $ map ppParMode contents
+ppParMode (ParNote key note t) = ppNote key note ppParMode t
+
+ppMath :: MathItm -> ShowS
+ppMath (MathDecls decls) = foldMap ppMathDecl decls
+ppMath (MathCmdArgs cmdName args) = ppCmdArgs cmdName $ map (fmap ppAny) args
+ppMath (RawMath s) = text s
+ppMath (MathCast x) = ppAny x
+ppMath (MathRat r) | denominator r == 1 = shows (numerator r)
+                     | otherwise          = shows (numerator r) ⊕ text " / " ⊕ shows (denominator r)
+ppMath (MathArray specs rows) = 
+  ppEnv "array" [Mandatory . (:[]) . mconcat $ map (ppRowSpec . fmap ppMath) specs] (ppRows ppMath rows)
+ppMath (MathGroup m) = braces $ ppMath m
+ppMath (MathConcat ms) = mconcat $ map ppMath ms
+ppMath (MathUnOp op m) = text op ⊕ sp ⊕ ppMath m
+ppMath (MathBinOp op l r) = parens (ppMath l ⊕ sp ⊕ text op ⊕ sp ⊕ ppMath r)
+ppMath (MathNote key note m) = ppNote key note ppMath m
+
+ppAny :: AnyItm -> ShowS
+ppAny (PreambleItm x) = ppPreamble x
+ppAny (LatexItm    x) = pp x
+ppAny (MathItm     x) = ppMath x
+ppAny (ParItm      x) = ppParMode x
+ppAny (LocSpecs locs) = text . map locSpecChar $ locs
+ppAny (Key key)       = text . getKey $ key
+ppAny (Length len)    = ppTexLength len
+ppAny (Coord (MkCoord x y)) = ppTexLength x ⊕ text " " ⊕ ppTexLength y
+ppAny (SaveBin bin) = text $ "\\hlatexSaveBin" ++ (map enc . show $ unsafeGetSaveBin bin)
+  where enc i = chr (ord 'a' + digitToInt i) -- hackish but numbers are prohibited
+ppAny (PackageName pkg) = text $ getPkgName pkg
+
+ppRowSpec :: RowSpec ShowS -> ShowS
+ppRowSpec Rc        = text "c"
+ppRowSpec Rl        = text "l"
+ppRowSpec Rr        = text "r"
+ppRowSpec Rvline    = text "|"
+ppRowSpec (Rtext x) = text "@" ⊕ braces x
+
+
+ppRows :: (a -> ShowS) -> [Row a] -> ShowS
+ppRows _ []
+  = ø
+ppRows ppCell (Cells cells : rows)
+  = (mconcat . intersperse (text " & ") . map ppCell $ cells)
+ ⊕ (if null rows then ø else backslash ⊕ backslash $$ ppRows ppCell rows)
+ppRows ppCell (Hline : rows)
+  = backslash ⊕ text "hline " ⊕ ppRows ppCell rows
+ppRows ppCell (Cline c1 c2 : rows)
+  -- No braces here around the \cline, intentionally
+  = ppCmdArgs "cline" [Mandatory . (:[]) . text $ show c1 ++ "-" ++ show c2] ⊕ ppRows ppCell rows
+
+unitName :: TexUnit -> String
+unitName u =
+  case u of
+    Cm -> "cm"
+    Mm -> "mm"
+    Em -> "em"
+    Ex -> "ex"
+    Pt -> "pt"
+    Pc -> "pc"
+    In -> "in"
+    Sp -> "sp"
+    Bp -> "bp"
+    Dd -> "dd"
+    Cc -> "cc"
+    Mu -> "mu"
+
+ppTexLength :: LatexLength -> ShowS
+ppTexLength s =
+  case s of
+    LengthCmd cmd          -> ppCmdArgs cmd []
+    LengthCmdRatArg  cmd r -> braces $ ppCmdArgs cmd [Mandatory . (:[]) $ showr r]
+    LengthScaledBy _ (LengthScaledBy _ _) ->
+      error "broken invariant: nested LengthScaledBy"
+    LengthScaledBy r l     -> showr r ⊕ ppTexLength l
+    LengthCst munit r      -> showr r ⊕ foldMap (text . unitName) munit
+  where showr r | denominator r == 1 = shows $ numerator r
+                | otherwise          = text $ formatRealFloat FFFixed (Just 2) (fromRational r :: Double)
+
+ppPreamble :: PreambleItm -> ShowS
+ppPreamble (PreambleCmdArgs cmdName args) = ppCmdArgs cmdName $ map (fmap ppAny) args
+ppPreamble (PreambleEnv envName args contents) = ppEnv envName (map (fmap ppAny) args) (ppAny contents)
+ppPreamble (PreambleCast x) = ppAny x
+ppPreamble (PreambleConcat ps) = vcat $ map ppPreamble ps
+ppPreamble (RawPreamble raw) = text raw
+ppPreamble (PreambleNote key note p) = ppNote key note ppPreamble p
+
+ppNote :: Key -> Note -> (a -> ShowS) -> a -> ShowS
+ppNote (MkKey key) note ppElt elt = irrNl ⊕ comment (key ⊕ ": " ⊕ showNote note) ⊕ ppElt elt ⊕ irrNl
+  where showNote (TextNote s) = s
+        showNote (IntNote  i) = show i
+        showNote (LocNote  loc) = showLoc loc
+        comment = mconcat . map (text . ('%':) . (⊕ "\n") . stripRight) . lines
+        stripRight = reverse . dropWhile isSpace . reverse
+
+showLoc :: Loc -> String
+showLoc (Loc fp line char) = unwords [fp, ":", show line, ":", show char]
+
+showDocClassKind :: DocumentClassKind -> String
+showDocClassKind Article = "article"
+showDocClassKind Book    = "book"
+showDocClassKind Report  = "report"
+showDocClassKind Letter  = "letter"
+showDocClassKind (OtherDocumentClassKind x) = x
+
+preambOfDocClass :: DocumentClss -> PreambleItm
+preambOfDocClass (DocClass kind opts) =
+  PreambleCmdArgs "documentclass"
+    [optionals opts, Mandatory . (:[]) . LatexItm . RawTex $ showDocClassKind kind]
+
+ppDocument :: Document -> ShowS
+ppDocument (Document docClass preamb doc) =
+  ppPreamble (preambOfDocClass docClass) $$$
+  ppPreamble preamb $$$
+  ppEnv "document" [] (nl ⊕ ppParMode doc ⊕ nl) ⊕ nl
+
+showsLaTeX :: LatexM Document -> Either ErrorMessage ShowS
+showsLaTeX mdoc = do
+  doc <- runLatexM mdoc
+  maybe (return ()) Left $ checkDocument doc
+  return . ppDocument $ doc
+
+showLaTeX :: LatexM Document -> Either ErrorMessage String
+showLaTeX = fmap ($"") . showsLaTeX
diff --git a/Language/LaTeX/Slicer.hs b/Language/LaTeX/Slicer.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Slicer.hs
@@ -0,0 +1,46 @@
+module Language.LaTeX.Slicer
+  (marknote, mark, marker, (^$), slice)
+where
+
+import Data.Monoid
+import Control.Monad.Writer
+import Language.LaTeX.Types
+import Language.LaTeX.Builder.MonoidUtils
+import qualified Language.LaTeX.Builder.Internal as BI
+import qualified Data.Generics.Uniplate.Data as U
+
+marknote :: ParItm
+marknote = ParNote (MkKey "slicemark") BI.nilNote ø
+
+mark :: ParItemW
+mark = tell $ return marknote
+
+marker :: Writer ParItem a -> Writer ParItem a
+marker f = do mark
+              x <- f
+              mark
+              return x
+
+infixr 0 ^$
+(^$) :: (b -> Writer ParItem a) -> b -> Writer ParItem a
+f ^$ x = marker (f x)
+
+slice :: Functor f => f ParItm -> f ParItm
+slice = fmap $ mconcat . mconcat . comb [maySlice1, maySlice2, id] . uncatParItm
+  where notMark = (/= marknote)
+
+        -- Is there a mark in a subterm?
+        isMarked = any (== marknote) . U.universe
+
+        -- slicing strategy (1): drop until the mark,
+        --                       drop the mark,
+        --                       take until the next mark
+        maySlice1 = takeWhile notMark . drop 1 . dropWhile notMark
+
+        -- slicing strategy (2):
+        -- keep only items which contains a mark as a subterm
+        maySlice2 = filter isMarked
+
+        -- Combine multiple strategies:
+        --   takes the result of the first succeeding strategy
+        comb fs xs = take 1 . filter (not . null) . map ($xs) $ fs
diff --git a/Language/LaTeX/Types.hs b/Language/LaTeX/Types.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Types.hs
@@ -0,0 +1,523 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving, TemplateHaskell,
+             DeriveDataTypeable, PatternGuards #-}
+
+-- Those extensions are required by the Uniplate instances.
+--{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
+module Language.LaTeX.Types where
+
+import Prelude hiding (and, foldr, foldl, foldr1, foldl1, elem, concatMap, concat)
+import Data.Monoid (Monoid(..))
+import Data.List (intercalate)
+import Data.Ratio ((%))
+import Data.Traversable
+import Data.Foldable
+import Data.String (IsString(..))
+-- import Data.Generics.PlateTypeable
+import Data.Data
+import Data.DeriveTH
+import Control.Applicative
+import Control.Arrow (second)
+import Control.Monad.Writer (Writer)
+import Control.Monad.Trans ()
+import Control.Monad.Error
+
+data Document = Document { documentClass     :: DocumentClss
+                         , documentPreamble  :: PreambleItm
+                         , documentBody      :: ParItm }
+  deriving (Show, Eq, Typeable, Data)
+
+type LineNumber = Int
+type CharNumber = Int
+
+data Loc = Loc { locFile :: FilePath
+               , locLine :: LineNumber
+               , locChar :: CharNumber
+               }
+   deriving (Show, Eq, Typeable, Data)
+
+data Note = TextNote String
+          | IntNote Int
+          | LocNote Loc
+   deriving (Show, Eq, Typeable, Data)
+
+data DocumentClassKind  = Article
+                        | Book
+                        | Report
+                        | Letter
+                        | OtherDocumentClassKind String
+  deriving (Show, Eq, Typeable, Data)
+
+data DocumentClss
+  = DocClass  {  docClassKind     :: DocumentClassKind
+              ,  docClassOptions  :: [AnyItm]
+              }
+  deriving (Show, Eq, Typeable, Data)
+
+data AnyItm = PreambleItm PreambleItm
+            | LatexItm    LatexItm
+            | MathItm     MathItm
+            | ParItm      ParItm
+            | LocSpecs    [LocSpec]
+            | Key         Key
+            | PackageName PackageName
+            | Coord       Coord
+            | Length      LatexLength
+            | SaveBin     SaveBin
+  deriving (Show, Eq, Typeable, Data)
+
+data PreambleItm = PreambleCmdArgs String [Arg AnyItm]
+                 | PreambleEnv String [Arg AnyItm] AnyItm
+                 | PreambleCast AnyItm
+                 | PreambleConcat [PreambleItm]
+                 | RawPreamble String
+                 | PreambleNote Key Note PreambleItm
+  deriving (Show, Eq, Typeable, Data)
+
+instance Monoid PreambleItm where
+  mempty  = PreambleConcat []
+  PreambleConcat xs `mappend` PreambleConcat ys = PreambleConcat (xs ++ ys)
+  PreambleConcat xs `mappend` y                 = PreambleConcat (xs ++ [y])
+  x                 `mappend` PreambleConcat ys = PreambleConcat (x : ys)
+  x                 `mappend` y                 = PreambleConcat [x, y]
+
+data TexDcl = TexDcl { texDeclName :: String
+                     , texDeclArgs :: [Arg AnyItm]
+                     }
+  deriving (Show, Eq, Typeable, Data)
+
+-- This is the subset of tex strings that fits in the LR mode.
+-- The distinction between the paragraph and the LR mode is always
+-- made explicit using the Para constructor.
+--
+-- Modes: http://www.personal.ceu.hu/tex/modes.htm
+data LatexItm
+           = LatexCmdArgs String [Arg LatexItm]
+           | LatexCmdAnyArgs String [Arg AnyItm]
+           | TexDecls [TexDcl]
+           | TexCmdNoArg String
+           | TexCmdArg String LatexItm
+           | Environment String [Arg AnyItm] AnyItm
+           | RawTex String
+           | LatexCast AnyItm -- a cast from math induce $...$
+           | TexGroup LatexItm
+           | LatexEmpty
+           | LatexAppend LatexItm LatexItm
+           | LatexNote Key Note LatexItm
+  deriving (Show, Eq, Typeable, Data)
+
+appendAny :: AnyItm -> AnyItm -> Maybe AnyItm
+appendAny (PreambleItm x) (PreambleItm y) = Just $ PreambleItm (x `mappend` y)
+appendAny (LatexItm x)    (LatexItm y)    = Just $ LatexItm (x `mappend` y)
+appendAny (MathItm x)     (MathItm y)     = Just $ MathItm (x `mappend` y)
+appendAny (ParItm x)      (ParItm y)      = Just $ ParItm (x `mappend` y)
+appendAny (LocSpecs x)    (LocSpecs y)    = Just $ LocSpecs (x `mappend` y)
+-- this lengthy matching is to get a warning when we extend the AnyItm type
+appendAny PreambleItm{} _ = Nothing
+appendAny LatexItm{}    _ = Nothing
+appendAny MathItm{}     _ = Nothing
+appendAny ParItm{}      _ = Nothing
+appendAny LocSpecs{}    _ = Nothing
+appendAny Key{}         _ = Nothing
+appendAny PackageName{} _ = Nothing
+appendAny Coord{}       _ = Nothing
+appendAny Length{}      _ = Nothing
+appendAny SaveBin{}     _ = Nothing
+
+instance Monoid LatexItm where
+  mempty  = LatexEmpty -- LatexConcat []
+  RawTex xs       `mappend` RawTex ys = RawTex (xs ++ ys)
+  LatexCast x     `mappend` LatexCast y | Just z <- appendAny x y = LatexCast z
+  LatexEmpty      `mappend` x = x
+  x               `mappend` LatexEmpty = x
+  LatexAppend x y `mappend` z = x `mappend` (y `mappend` z) -- TODO complexity issue?
+  x `mappend` LatexAppend y z =
+    case x `mappend` y of
+      LatexAppend x' y' -> x' `LatexAppend` (y' `mappend` z) -- TODO complexity issue?
+      xy                -> xy `mappend` z
+  x               `mappend` y = x `LatexAppend` y
+
+{-
+  LatexConcat xs `mappend` LatexConcat ys = LatexConcat (xs ++ ys)
+  LatexConcat xs `mappend` y              = LatexConcat (xs ++ [y])
+  x              `mappend` LatexConcat ys = LatexConcat (x : ys)
+  x              `mappend` y              = LatexConcat [x, y]
+-}
+
+instance IsString LatexItm where
+  fromString s
+    | null s    = mempty
+    | otherwise = f s
+    where f = RawTex . concatMap rawhchar . intercalate "\n" . filter (not . null) . lines
+
+data Named a = Named String a
+  deriving (Show, Eq, Typeable, Data)
+
+data PackageAction = PackageDependency PackageName
+                   | ProvidePackage    PackageName
+  deriving (Show, Eq, Typeable, Data)
+
+data Arg a = NoArg
+           | StarArg             -- `*'
+           | Mandatory [a]       -- surrounded by `{' `}', separated by `,'
+           | Optional [a]        -- surrounded by `[' `]', separated by `,' or empty if null
+           | NamedArgs [Named a] -- surrounded by `{' `}', separated by `=` and `,'
+           | NamedOpts [Named a] -- surrounded by `[' `]', separated by `=' and `,' or empty if null
+           | Coordinates a a     -- surrounded by `(' `)', separated by ` '
+           | RawArg String
+           | LiftArg a
+           | PackageAction PackageAction
+  deriving (Show, Eq, Typeable, Data)
+
+data Star = Star | NoStar
+  deriving (Show, Eq, Typeable, Data)
+
+instance Monoid Star where
+  mempty = NoStar
+  NoStar `mappend` x      = x
+  x      `mappend` _      = x
+
+data Coord = MkCoord LatexLength LatexLength
+  deriving (Show, Eq, Typeable, Data)
+
+newtype Percentage = Percentage { percentage :: Int } deriving (Eq,Show,Ord,Num)
+
+data ParItm  = ParCmdArgs String [Arg AnyItm]
+             | ParEnv String [Arg AnyItm] AnyItm
+             | Tabular [RowSpec LatexItm] [Row LatexItm]
+             | RawParMode String
+             | ParCast AnyItm -- a cast from Math induce \[...\]
+             | ParGroup ParItm -- check validity of this
+             | ParConcat [ParItm]
+             | ParNote Key Note ParItm
+  deriving (Show, Eq, Typeable, Data)
+
+instance Monoid ParItm where
+  mempty  = ParConcat []
+  ParConcat xs `mappend` ParConcat ys = ParConcat (xs ++ ys)
+  ParConcat xs `mappend` y            = ParConcat (xs ++ [y])
+  x            `mappend` ParConcat ys = ParConcat (x : ys)
+  x            `mappend` y            = ParConcat [x, y]
+
+unParNote :: ParItm -> Maybe (Key, Note, ParItm)
+unParNote (ParNote k n p) = Just (k, n, p)
+unParNote _               = Nothing
+
+uncatParItm :: ParItm -> [ParItm]
+uncatParItm (ParConcat pars) = pars
+uncatParItm par              = [par]
+
+newtype MathDcl = MathDcl String
+  deriving (Show, Eq, Typeable, Data)
+
+data MathItm   = MathDecls [MathDcl]
+               | MathCmdArgs String [Arg AnyItm]
+               | MathArray [RowSpec MathItm] [Row MathItm]
+               | RawMath String
+               | MathCast AnyItm
+               | MathRat Rational
+               | MathGroup MathItm
+               | MathConcat [MathItm]
+               | MathBinOp String MathItm MathItm
+               | MathUnOp String MathItm
+               | MathNote Key Note MathItm
+  deriving (Show, Eq, Typeable, Data)
+
+instance Monoid MathItm where
+  mempty  = MathConcat []
+  MathConcat xs `mappend` MathConcat ys = MathConcat (xs ++ ys)
+  MathConcat xs `mappend` y              = MathConcat (xs ++ [y])
+  x              `mappend` MathConcat ys = MathConcat (x : ys)
+  x              `mappend` y              = MathConcat [x, y]
+
+instance Num MathItm where
+  (+) = MathBinOp "+"
+  (*) = MathBinOp "*"
+  (-) = MathBinOp "-"
+  negate = MathUnOp "-"
+  abs x = MathCmdArgs "abs" [Mandatory [MathItm x]] -- TODO check
+  signum = error "MathItm.signum is undefined"
+  fromInteger = MathRat . (%1)
+
+instance Fractional MathItm where
+  (/) = MathBinOp "/"
+  fromRational = MathRat
+
+{-
+instance Real MathItm where
+  toRational = error "MathItm.toRational is undefined"
+
+instance Integral MathItm where
+  mod = MathBinOp "bmod"
+  -- TODO quot, rem
+-}
+
+data TexUnit
+  = Sp -- ^ Scalled point (1pt = 65536sp)
+  | Pt -- ^ Point unit size (1pt = 0.351mm)
+  | Bp -- ^ Big point (1in = 72bp), also PostScript point
+  | Dd -- ^ Didôt point (1dd = 0.376mm)
+  | Em -- ^ One em is about the width of the letter M in the current font
+  | Ex -- ^ One ex is about the hoigh of the letter x in the current font
+  | Cm -- ^ Centimeter unit size
+  | Mm -- ^ Milimeter unit size (1mm = 2.845pt)
+  | In -- ^ Inch unit size (1in = 72.27pt)
+  | Pc -- ^ Picas (1pc = 12pt)
+  | Cc -- ^ Cicero (1dd = 12dd = 4.531mm)
+  | Mu -- ^ Math unit (18mu = 1em)
+  deriving (Eq, Ord, Enum, Show, Typeable, Data)
+
+data LatexLength = LengthScaledBy Rational LatexLength
+                 | LengthCmdRatArg String Rational
+                 | LengthCmd String
+                 | LengthCst (Maybe TexUnit) Rational
+  deriving (Show, Eq, Typeable, Data)
+
+lengthCst :: LatexLength -> Maybe (Maybe TexUnit, Rational)
+lengthCst (LengthScaledBy rat len) = second (rat *) <$> lengthCst len
+lengthCst (LengthCmdRatArg _ _)    = Nothing
+lengthCst (LengthCmd _)            = Nothing
+lengthCst (LengthCst mtu rat)      = Just (mtu, rat)
+
+safeLengthOp :: String -> (Rational -> Rational -> Rational) -> LatexLength -> LatexLength -> LatexLength
+safeLengthOp _ op (LengthCst Nothing     rx) (LengthCst munit ry)
+  = LengthCst munit (op rx ry)
+safeLengthOp _ op (LengthCst (Just unit) rx) (LengthCst Nothing ry)
+  = LengthCst (Just unit) (op rx ry)
+safeLengthOp op _ x y
+  = error $ "LatexLength." ++ op
+         ++ ": undefined on non constants terms (" ++ show x ++ op ++ show y ++ ")"
+
+scaleBy :: Rational -> LatexLength -> LatexLength
+scaleBy rx (LengthScaledBy ry l)   = LengthScaledBy (rx * ry) l
+scaleBy rx (LengthCst munit ry)    = LengthCst munit (rx * ry)
+scaleBy rx (LengthCmd cmd)         = LengthScaledBy rx (LengthCmd cmd)
+scaleBy rx (LengthCmdRatArg cmd r) = LengthScaledBy rx (LengthCmdRatArg cmd r)
+
+instance Num LatexLength where
+  LengthCst Nothing x * y = scaleBy x y
+  x * LengthCst Nothing y = scaleBy y x
+  x * y                   = safeLengthOp "*" (*) x y
+
+  (+) = safeLengthOp "+" (+)
+  (-) = safeLengthOp "-" (-)
+  negate x = LengthCst Nothing (-1) * x
+  abs = error "LatexLength.abs is undefined"
+  signum = error "LatexLength.signum is undefined"
+  fromInteger = LengthCst Nothing . (%1)
+
+instance Monoid LatexLength where
+  mempty = 0
+  mappend = (+)
+
+instance Fractional LatexLength where
+  x / LengthCst Nothing ry = scaleBy (1/ry) x
+  x / y                    = safeLengthOp "/" (/) x y
+  fromRational = LengthCst Nothing
+
+-- p{wd}, and *{num}{cols} are explicitly
+-- not supported, it seems much more natural and
+-- simple to obtain the same goals using standard
+-- programming uppon the rows and cells.
+data RowSpec a = Rc --- ^ Centered
+               | Rl --- ^ Left
+               | Rr --- ^ Right
+               | Rvline --- ^ A vertical line
+               | Rtext a --- ^ A fixed text column (@-expression in LaTeX parlance)
+  deriving (Show, Eq, Typeable, Data)
+
+{-
+instance Functor RowSpec where
+  _ `fmap` Rc         = Rc
+  _ `fmap` Rl         = Rl
+  _ `fmap` Rr         = Rr
+  _ `fmap` Rvline     = Rvline
+  f `fmap` (Rtext x)  = Rtext $ f x
+
+instance Foldable RowSpec where
+  foldr _ z Rc        = z
+  foldr _ z Rl        = z
+  foldr _ z Rr        = z
+  foldr _ z Rvline    = z
+  foldr f z (Rtext x) = f x z
+
+instance Traversable RowSpec where
+  sequenceA Rc        = pure Rc
+  sequenceA Rl        = pure Rl
+  sequenceA Rr        = pure Rr
+  sequenceA Rvline    = pure Rvline
+  sequenceA (Rtext x) = Rtext <$> x
+-}
+
+data LocSpec = Lh --- ^ Here
+             | Lt --- ^ Top
+             | Lb --- ^ Bottom
+             | Lp --- ^ Page of floats: on a sperate page containing no text,
+                  ---   only figures and tables.
+  deriving (Show, Eq, Typeable, Data)
+
+locSpecChar :: LocSpec -> Char
+locSpecChar Lh = 'h'
+locSpecChar Lt = 't'
+locSpecChar Lb = 'b'
+locSpecChar Lp = 'p'
+
+data Pos = Centered   -- ^ Centered (default).
+         | FlushLeft  -- ^ Flush left
+         | FlushRight -- ^ Flush right
+         | Stretch -- ^ Stretch (justify) across entire width; text must contain
+                   -- stretchable space for this to work.
+
+charPos :: Pos -> Char
+charPos Centered   = 'c'
+charPos FlushLeft  = 'l'
+charPos FlushRight = 'r'
+charPos Stretch    = 's'
+
+-- TODO: add more paper sizes
+data LatexPaperSize = A4paper | OtherPaperSize String
+  deriving (Show, Eq, Typeable, Data)
+
+{- NOTE: their is no handling of the \multicolumn command at the moment -}
+data Row cell = Cells [cell]
+              | Hline
+              | Cline Int Int
+  deriving (Show, Eq, Typeable, Data)
+
+{-
+instance Functor Row where
+  f `fmap` Cells cs  = Cells (fmap f cs)
+  _ `fmap` Hline     = Hline
+  _ `fmap` Cline i j = Cline i j
+
+instance Foldable Row where
+  foldr f z (Cells cs)  = foldr f z cs
+  foldr _ z Hline       = z
+  foldr _ z (Cline _ _) = z
+
+instance Traversable Row where
+  sequenceA (Cells cs)  = Cells <$> sequenceA cs
+  sequenceA Hline       = pure Hline
+  sequenceA (Cline i j) = pure $ Cline i j
+-}
+
+data ListItm = ListItm { itemOptions :: [Arg LatexItm], itemContents :: ParItm }
+
+newtype PackageName = PkgName { getPkgName :: String }
+  deriving (Ord, Eq, Show, Typeable, Data)
+
+newtype Key = MkKey { getKey :: String }
+  deriving (Eq, Show, Typeable, Data)
+
+newtype SaveBin = UnsafeMakeSaveBin { unsafeGetSaveBin :: Int }
+  deriving (Eq, Show, Typeable, Data)
+
+data LatexState = LS { freshSaveBin :: SaveBin }
+
+instance (Error a, Eq a, Show a, Num b) => Num (Either a b) where
+  fromInteger = pure . fromInteger
+  (+)         = liftM2 (+)
+  (-)         = liftM2 (-)
+  (*)         = liftM2 (*)
+  negate      = liftM negate
+  abs         = liftM abs
+  signum      = liftM signum
+
+instance (Error a, Eq a, Show a, Fractional b) => Fractional (Either a b) where
+  (/) = liftM2 (/)
+  fromRational = pure . fromRational
+
+type ErrorMessage = String
+
+newtype LatexM a = LatexM { runLatexM :: Either ErrorMessage a }
+  deriving (Functor, Applicative, Monad, MonadPlus,
+            MonadError ErrorMessage, Show, Eq, Num, Fractional,
+            Typeable, Data)
+
+instance Monoid a => Monoid (LatexM a) where
+  mempty = pure mempty
+  mappend = liftM2 mappend
+  mconcat = liftM mconcat . sequenceA
+
+instance IsString a => IsString (LatexM a) where fromString = pure . fromString
+
+type TexDecl   = LatexM TexDcl
+type LatexItem = LatexM LatexItm
+type ParItem   = LatexM ParItm
+type MathDecl  = LatexM MathDcl
+newtype AnyItem   = AnyItem { anyItmM :: LatexM AnyItm }
+  deriving (Eq, Show, Typeable, Data)
+newtype MathItem  = MathItem { mathItmM :: LatexM MathItm }
+  deriving (Monoid, Eq, Show, Num, Fractional, Typeable, Data)
+
+type ListItem  = LatexM ListItm
+type PreambleItem = LatexM PreambleItm
+type DocumentClass = LatexM DocumentClss
+
+type TexDeclW      = Writer TexDecl ()
+type LatexItemW    = Writer LatexItem ()
+type ParItemW      = Writer ParItem ()
+type MathDeclW     = Writer MathDecl ()
+type MathItemW     = Writer MathItem ()
+type PreambleItemW = Writer PreambleItem ()
+
+-- TODO: Maybe one should handle quotes in a less LaTeX
+-- way: provide a replacement for ``...'' and escape `'"
+--
+-- NOTE: Don't confuse this function with ttchar
+-- NOTE: this raw Tex is ugly
+rawhchar :: Char -> String
+rawhchar '\\'  = "\\textbackslash{}"
+rawhchar '<'   = "\\textless{}"
+rawhchar '>'   = "\\textgreater{}"
+rawhchar '|'   = "\\textbar{}"
+rawhchar x
+  | x `elem` "~^_#&{}$%" = ['\\',x,'{','}']
+  | x `elem` ":]["       = ['{', x, '}'] -- '[' and ']' are escaped to avoid mess up optional args
+  | otherwise            = [x]
+
+-- | Type for encodings used in commands like.
+-- @\usepackage[utf8]{inputenc}@, that we can
+-- express as 'useInputenc' 'utf8'.
+newtype Encoding = Encoding { fromEncoding :: String }
+  deriving (Eq,Ord,Show)
+
+-- instance (Integral a, Typeable a, Typeable b, PlateAll a b) => PlateAll (Ratio a) b where
+--   plateAll r = plate (%) |+ numerator r |+ denominator r
+
+$(derive makeFunctor     ''Named)
+$(derive makeFoldable    ''Named)
+$(derive makeTraversable ''Named)
+$(derive makeFunctor     ''Arg)
+$(derive makeFoldable    ''Arg)
+$(derive makeTraversable ''Arg)
+$(derive makeFunctor     ''RowSpec)
+$(derive makeFoldable    ''RowSpec)
+$(derive makeTraversable ''RowSpec)
+$(derive makeFunctor     ''Row)
+$(derive makeFoldable    ''Row)
+$(derive makeTraversable ''Row)
+
+{-
+$(derive makeUniplateTypeable ''SaveBin)
+$(derive makeUniplateTypeable ''PackageName)
+$(derive makeUniplateTypeable ''Loc)
+$(derive makeUniplateTypeable ''Note)
+$(derive makeUniplateTypeable ''Arg)
+$(derive makeUniplateTypeable ''Key)
+$(derive makeUniplateTypeable ''Row)
+$(derive makeUniplateTypeable ''RowSpec)
+$(derive makeUniplateTypeable ''LocSpec)
+$(derive makeUniplateTypeable ''LatexLength)
+$(derive makeUniplateTypeable ''Coord)
+$(derive makeUniplateTypeable ''DocumentClassKind)
+
+$(derive makeUniplateTypeable ''TexDcl)
+$(derive makeUniplateTypeable ''MathItm)
+$(derive makeUniplateTypeable ''MathDcl)
+$(derive makeUniplateTypeable ''ParItm)
+$(derive makeUniplateTypeable ''TexUnit)
+$(derive makeUniplateTypeable ''LatexItm)
+$(derive makeUniplateTypeable ''DocumentClass)
+$(derive makeUniplateTypeable ''PreambleItm)
+$(derive makeUniplateTypeable ''Document)
+-}
diff --git a/Language/LaTeX/Unicode.hs b/Language/LaTeX/Unicode.hs
new file mode 100644
--- /dev/null
+++ b/Language/LaTeX/Unicode.hs
@@ -0,0 +1,183 @@
+{-# LANGUAGE FlexibleInstances #-}
+module Language.LaTeX.Unicode where
+
+import Language.LaTeX.Types
+import qualified Language.LaTeX.Builder as B
+import qualified Language.LaTeX.Builder.Math as M
+
+{-
+      α = alpha)
+      β = beta)
+      χ = chi)
+      δ = delta)
+      Δ = _Delta)
+      ε = epsilon)
+    --  = varepsilon)
+      η = eta)
+      γ = gamma)
+      Γ = _Gamma)
+      ι = iota)
+      κ = kappa)
+      λ = lambda)
+      Λ = _Lambda)
+      μ = mu)
+      ν = nu)
+      ω = omega)
+      Ω = _Omega)
+      ο = omicron)
+      φ = phi)
+    --  = varphi)
+      Φ = _Phi)
+      π = pi)
+      Π = _Pi)
+      ψ = psi)
+      ρ = rho)
+      σ = sigma)
+      Σ = _Sigma)
+      τ = tau)
+      θ = theta)
+    --  = vartheta)
+      Θ = _Theta)
+    --  = upsilon)
+      ξ = xi)
+    --  = _Xi)
+      ζ = zeta)
+-}
+
+class Greek a where
+    -- varepsilon
+    -- varphi
+    -- vartheta
+    -- upsilon
+    -- _Xi
+  α  :: a
+  β  :: a
+  χ  :: a
+  δ  :: a
+  _Δ :: a
+  ε  :: a
+  η  :: a
+  γ  :: a
+  _Γ :: a
+  ι  :: a
+  κ  :: a
+  λ  :: a
+  _Λ :: a
+  μ  :: a
+  ν  :: a
+  ω  :: a
+  _Ω :: a
+  ο  :: a
+  φ  :: a
+  _Φ :: a
+  π  :: a
+  _Π :: a
+  ψ  :: a
+  ρ  :: a
+  σ  :: a
+  _Σ :: a
+  τ  :: a
+  θ  :: a
+  _Θ :: a
+  ξ  :: a
+  ζ  :: a
+
+instance Greek MathItem where
+  α  = M.alpha
+  β  = M.beta
+  χ  = M.chi
+  δ  = M.delta
+  _Δ = M._Delta
+  ε  = M.epsilon
+  η  = M.eta
+  γ  = M.gamma
+  _Γ = M._Gamma
+  ι  = M.iota
+  κ  = M.kappa
+  λ  = M.lambda
+  _Λ = M._Lambda
+  μ  = M.mu
+  ν  = M.nu
+  ω  = M.omega
+  _Ω = M._Omega
+  ο  = M.omicron
+  φ  = M.phi
+  _Φ = M._Phi
+  π  = M.pi
+  _Π = M._Pi
+  ψ  = M.psi
+  ρ  = M.rho
+  σ  = M.sigma
+  _Σ = M._Sigma
+  τ  = M.tau
+  θ  = M.theta
+  _Θ = M._Theta
+  ξ  = M.xi
+  ζ  = M.zeta
+
+{-
+  α  = α
+  β  = β
+  χ  = χ
+  δ  = δ
+  _Δ = _Δ
+  ε  = ε
+  η  = η
+  γ  = γ
+  _Γ = _Γ
+  ι  = ι
+  κ  = κ
+  λ  = λ
+  _Λ = _Λ
+  μ  = μ
+  ν  = ν
+  ω  = ω
+  _Ω = _Ω
+  ο  = ο
+  φ  = φ
+  _Φ = _Φ
+  π  = π
+  _Π = _Π
+  ψ  = ψ
+  ρ  = ρ
+  σ  = σ
+  _Σ = _Σ
+  τ  = τ
+  θ  = θ
+  _Θ = _Θ
+  ξ  = ξ
+  ζ  = ζ
+-}
+
+instance Greek (LatexM LatexItm) where
+  α = B.math M.alpha
+  β = B.math M.beta
+  χ = B.math M.chi
+  δ = B.math M.delta
+  _Δ = B.math M._Delta
+  ε = B.math M.epsilon
+  η = B.math M.eta
+  γ = B.math M.gamma
+  _Γ = B.math M._Gamma
+  ι = B.math M.iota
+  κ = B.math M.kappa
+  λ = B.math M.lambda
+  _Λ = B.math M._Lambda
+  μ = B.math M.mu
+  ν = B.math M.nu
+  ω = B.math M.omega
+  _Ω = B.math M._Omega
+  ο = B.math M.omicron
+  φ = B.math M.phi
+  _Φ = B.math M._Phi
+  π = B.math M.pi
+  _Π = B.math M._Pi
+  ψ = B.math M.psi
+  ρ = B.math M.rho
+  σ = B.math M.sigma
+  _Σ = B.math M._Sigma
+  τ = B.math M.tau
+  θ = B.math M.theta
+  _Θ = B.math M._Theta
+  ξ = B.math M.xi
+  ζ = B.math M.zeta
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/doc/user_guide.hs b/doc/user_guide.hs
new file mode 100644
--- /dev/null
+++ b/doc/user_guide.hs
@@ -0,0 +1,440 @@
+{-# LANGUAGE QuasiQuotes, OverloadedStrings, NoMonomorphismRestriction, UnicodeSyntax #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures -F -pgmF frquotes #-}
+import Language.LaTeX
+import qualified Language.LaTeX.Length as L
+import qualified Language.LaTeX.Builder as B
+import qualified Language.LaTeX.Builder.Color as C
+import qualified Language.LaTeX.Builder.Math as M
+import Language.LaTeX.Builder.QQ hiding (tex)
+import Control.Monad.Writer
+
+{- OUTLINE (to put up to date)
+
+Conventions DONE
+
+Monoidal structure PLANNED
+
+Injecting strings
+ IsString
+ hstring
+ reduce hstring "" => mempty
+
+Sectioning
+
+List like env
+ how to put a paritem between items
+
+Declarations
+ decls are side effects and {} are scopes
+ in hlatex all declarations are explicitely scoped (effects don't pass through <>)
+ unsafe injection is still available though
+
+Tabulars
+ why lists
+ format spec
+ how put hline
+ missing features
+
+Paragraphs
+ why strong paragraph distintinction
+ no longer double endline meaning
+ don't confuse para and paragraph
+
+Math mode
+ no strings
+ no chars (M.a, M.b...)
+ still low level (sum has only one arg)
+ still the same meaning for <>
+    Ligatures
+ num class
+
+Verbatim mode
+ why not using the latex verbatim mode
+ protect
+   special characters
+   Ligatures
+   Work with fixed width fonts
+
+Figures
+
+Bibliography, glossary and index
+
+Making new commands
+ TODO: wrap these functions to
+           L.L.Builder.Internal
+
+Raw LaTeX
+
+Pictures
+
+Size units and predefs dimensions
+ normalisation, symbolic eval
+ num class
+
+The latexm monad
+ what for
+ how hidden
+ a monad transformer would allow
+   custom initial monad, more state,
+   more control...
+
+The Writer monad
+ how to use it
+
+French quotes
+ fq is a lexical syntax extension enabling lightweight interpolated literal piece of text. Once desugared this extension relies on the quasi-quoting system provided by GHC.
+
+Misc
+ savebins
+
+Packages
+ automatic tracking
+
+ graphicx
+ listings equivalent
+
+ adding new packages
+-}
+
+latex = B._LaTeX
+tex = B._TeX
+hlatex = B.textsc "HLaTeX" -- TODO make a proper symol and provide it in L.L.Builder
+haskell = B.textsc "Haskell"
+ast = B.textsc "AST"
+ghc = B.textsc "GHC"
+math = «mathematics»
+mathmode = «math-mode»
+frquotes = B.texttt "frquotes"
+ltxcode = B.texttt . B.protect
+hcode = B.texttt . B.protect
+ltxenv = B.texttt . B.protect
+ascii = B.textsc "ASCII"
+
+put :: ParItem -> ParItemW
+put = tell
+
+p = put . B.para
+section = put . B.section
+subsection = put . B.subsection
+paragraph = put . B.paragraph
+em = B.emph
+
+todo = p . C.textcolor C.red
+
+main = quickView myViewOpts { basedir = "examples"
+                            , pdflatex = "pdflatex"
+                            , pdfviewer = "evince" }
+                 "user_guide" doc
+
+doc = B.document (B.book (Just (L.pt 11)) (Just B.a4paper) []) preamb body
+
+preamb = ø
+     -- ⊕ B.usepackage [B.optional "francais"] (B.pkgName "babel")
+
+body = execWriter $ do
+  put B.tableofcontents
+
+  section «Introduction»
+
+  p «{hlatex} is a library to generate {latex} documents using the {haskell}
+    programming language. This library focus on providing a safe set of functions
+    and constants that will build a kind of {ast} (abstract syntax tree). This {ast}
+    could be subsequently checked and pretty-printed into a final {latex} document,
+    ready to feed the {latex} processor.»
+
+  p «The main {latex} advantage is to enable nice typesetting of documents
+    without giving up on a human readable/writable text format. However the success
+    of {latex} is greatly due to its extensibility. By being a programming language,
+    various extensions for all kind of needs appeared as packages. These packages
+    provide highlevel typesetting facilities but are themself just using a more
+    primitive set of typesetting facilities, and so do not extend the internals of
+    the system.»
+
+  p «However as a programming language {latex} has a lot to envy to other
+    languages. {tex} ---the underlying system of {latex}--- as a programming
+    language, is a system based on macro expansion, lexical conventions are changing
+    (dependent of the evaluation), there is no support for data structures, a poor
+    support for control structuros, and no type system.»
+
+  p «Hopefully from the point of view of a {latex} generator like {hlatex}, there
+    is no need for these programming features. Indeed {hlatex} focus on producing
+    {latex} documents without macros definitions. Since {haskell} functions
+    superseed {latex} macros, they could be used in replacement, the produced
+    {latex} document will be as if the expansion of these new macros was already
+    done.»
+
+  paragraph «Safety»
+
+  p «By imposing this restriction ({latex} without macros), {hlatex} turns the
+    hard problem of generating correct {latex} into a reasonable one. Indeed safety
+    is one of the main goal of this library. Providing safety on the generator side
+    has two big advantages. One of them is to avoid the need of looking at the
+    generated {latex}, indeed if errors are not reported on the generator but on the
+    generatad {latex}, one would have to look at the generatad {latex} and infer
+    where is the error in the generator.»
+
+  p «In {hlatex}, errors are classified in two categories. One category of errors
+    are caught by the {haskell} type system like the usage of {math} symbols only in
+    the {mathmode}, or the distinctions of inline commands like {ltxcode "\\textbf"}
+    or {ltxcode "\\hspace»"}, block commands like {ltxenv "itemize"}, dimensions
+    like constants in different units, or commands like {ltxcode "\\textwidth"}, and
+    others distinctions made using types. All others detected errors are caught
+    dynamically before generating the {latex} document, this emcompass for example
+    veriications of the numbers of columns in the {ltxenv "tabular"} or
+    {ltxenv "array"} environment, and a lot more as the library is being improved.»
+  -- TODO cross-references and citations, math mode nestings like a_{b}_{c}...
+
+  section «Design principles»
+
+  subsection «Naming conventions»
+
+  p «{hlatex} tries to stay close to the {latex} concepts and command names. This
+    decision should help to find the right function given a {latex} name, however
+    this is not always possible since some commands are not valid {haskell}
+    identifiers. {latex} names starting with a capital letter will have a leading
+    underscore character, for example {ltxcode "\\Rightarrow"} is called
+    {hcode "_Rightarrow"}. More precisely since {hlatex} is a {haskell} library,
+    function names are not floating around but are packaged in modules, then
+    the complete name of {ltxcode "\\Rightarrow"} is
+    {hcode "Language.LaTeX.Builder.Math._Rightarrow"}, of course no one wants to
+    use it fully qualified. Instead one commonly use {haskell}
+    {em «qualified imports»}, importing {hcode "Language.LaTeX.Builder.Math"} as
+    simply {hcode "M"}, leading to {hcode "M._Rightarrow"} in a {hlatex} document.
+    Likewise the {hcode "Language.LaTeX.Builder"} module is commonly imported as
+    {hcode "B"}.»
+
+  p «However some {latex} commands are far from being valid identifiers like
+    {math} spacing commands ({ltxcode "\\!"}, {ltxcode "\\,"}, or {ltxcode "\\;"})
+    or accents in text mode ({ltxcode "\\'"}, {ltxcode "\\`"}, or {ltxcode "\\."}).
+    In these cases, plain names have be chosen like {hcode "M.negthinspace"} or
+    {hcode "B.acute"}. These names are chosen according there semantics and not
+    according their symbol, so we use `acute' instead of `single quote' and
+    `thinspace' instead of `comma'.»
+
+  subsection «Commands with optional arguments»
+
+  p «OUTDATED TODO Since {haskell} does not support optional arguments, and that we do not want
+    to add extra burden on the document writer we have choosen to expose two
+    variants of some commands. Therefore {ltxcode "\\newline"} is exposed as
+    {hcode "B.newline"} and to give the optional size argument one use the
+    {hcode "B.newline'"} function as in {hcode "B.newline' (B.pt 42)"}.»
+{-Another
+    example is sectionning. Each sectionning command (like {ltxcode "\\chapter"} or
+    {ltxcode "\\section"}) have an unnumbered version (like {ltxcode "\\chapter*"} or
+    {ltxcode "\\section*"}), and can also take an optional argument that is the
+    title that will appear in table of contents. So the {hcode "B.chapter"} function
+    only take the chapter title whereas the {hcode "B.chapter'"} function takes
+    three arguments the first select the normal or the starred version, the second
+    is the table of contents version as a {hcode "Maybe"} type and the third is the
+    actual title.»
+-}
+
+  section «Monoidal structure»
+
+  subsection «FIXME» -- rappel
+
+  p «A monoid is a very simple algebraic structure. To be a monoid one needs a
+    set---that will be represented with a {haskell} type---; an associative
+    composition operator---called {hcode "mappend"} in {haskell} and abbreviated by
+    the {hcode "⊕"} infix operator here; and a neutral element---called
+    {hcode "mempty"} and abbreviated using unicode empty set symbol { {-TODO use ø-}B.math M.emptyset }.
+    The neutral element is a left and right unit for the composition operator.»
+
+  p «In computer systems a lot of structures are monoid instances. Like lists
+    with the empty list and concatenation, integers with zero and addition,
+    functions with identity and composition and a lot more.»
+
+  p «The point of using this kind of abstraction instead of their concrete
+    representations is to share generic functions over them. For instance composing
+    a list of values can be done with the {hcode "mconcat"} function, another
+    variants are included in the {hcode "Data.Foldable"} module like the
+    {hcode "fold"} and {hcode "foldMap"} functions.»
+    -- also add mapNonEmpty when I would have found another name.
+
+{-
+  p «»
+  p «»
+  p «»
+  p «»
+  p «»
+-}
+
+  section «Injecting strings»
+
+  p «While the main job of {hlatex} is to give access to {latex} commands in
+    {haskell}, generating documents using {haskell} needs also to cope with
+    80% of the contents, namely the text.»
+
+  p «Plain text can be converted to {latex} using the {hcode "hstring"} function.»
+
+  subsection «The {hcode "hstring"} function»
+
+  p «This function convert an {haskell} string to a piece of {latex}. While the
+    semantics of this function is obvious for characters like `a' or `X', what
+    the result for blanks, special characters and unicode characters.»
+
+{-
+  p «The semantics is clear, {hcode "hstring"} converts each character to a
+    {}»
+  -}
+
+  todo «note that {hcode "hstring \"\""} reduces to {hcode "ø"}»
+
+  subsection «The IsString class»
+
+  section «Lexical extensions and preprocessing»
+
+  subsection «Activating the extensions»
+
+  let pragmaOpts = "{-# OPTIONS_GHC -F -pgmF frquotes #-}"
+      pragmaLang = "{-# LANGUAGE QuasiQuotes, UnicodeSyntax #-}"
+
+  p «Using the following {ghc} pragma {hcode pragmaOpts}, and since this
+    extension relies on quasi-quoting one also needs this pragma
+    {hcode pragmaLang}.»
+
+  subsection «French Quotes Extension»
+
+  p «{frquotes} is a lexical syntax extension enabling lightweight interpolated  
+    literal piece of text. Once desugared this extension relies on the  
+    quasi-quoting system provided by {ghc}.»
+
+  -- TODO
+  p «TO BE UPDATED.
+    Currently the French Quotes extension only desugar to litteral strings
+    and monoid compositions. French Quotes are introduced using `{«}' and
+    closed using `{»}'. Interpolation (injection of {haskell} code inside the
+    quotes) is done using braces (`«{»' and `«}»'). These interpolated holes
+    can contains an {haskell} expression including nested French Quotes,
+    string, comments, braces, etc. The French Quotes characters can be used
+    inside French Quotes but must be balanced.»
+
+  subsection «Unicode Syntax Extension»
+
+  p «This syntax extension allows to use `ø' and `⊕' in {haskell}
+     code instead {hcode "mempty"} and {hcode "`mappend`"} respectively.
+     For example one can write {hcode "ø ⊕ x ⊕ ø"} instead of
+     {hcode "mempty `mappend` x `mappend` mempty"}.»
+  -- TODO
+
+  section «Sectioning»
+
+  p «In {latex} sectioning is done by inserting separators commands. In {hlatex}
+    all these commands are exported in a straightforward way. Most of these commands
+    appears in two variants, for instance {ltxcode "\\section"} can be produced
+    by {hcode "section"} and just waits for a {hcode "LatexItem"} as title,
+    and {hcode "section'"} waits for two extra arguments the first is either
+    {hcode "ø"} ({hcode "mempty"} in {ascii}) or {hcode "(★)"} ({hcode "star"} in {ascii})
+    and the second is optional and represents the text to be used in the table of contents.»
+
+  section «List like environment»
+  todo "how to put a paritem between items"
+
+  section «Declarations»
+
+  p «In {latex} declarations are side effects.  For instance {ltxcode "\\small"}
+    changes the current size of text to make it smaller, it is an effect on
+    the size.  However the scope of declarations can be delimited using braces
+    ({"{"} and {"}"}).»
+
+-- "toto " ⊕ "\small" ⊕ " tata"
+-- toto ⊕ {\small ⊕ tata} ⊕ tutu
+
+  p «In {hlatex} all declarations are explicitely scoped.
+    In other words the effects of declarations do not pass through concatenation
+    ({hcode "⊕"}) of {latex} pieces.
+    They are represented in {hlatex} with types {hcode "TexDecl"} and
+    {hcode "MathDecl"} for the math mode.
+    The unsafe injection from declarations to pieces of {latex} is still
+    available though.»
+
+  section «Tabulars»
+  todo «
+     why lists
+     format spec
+     how put hline
+     missing features
+     »
+
+  section «Paragraphs»
+  todo «why strong paragraph distintinction
+     no longer double endline meaning
+     don't confuse para and paragraph
+     »
+
+  section «Math mode»
+  subsection «No plain strings»
+
+
+
+  -- p (math "1" ⊕ "+" ⊕ "2")
+
+  {-
+  (&) fct arg = fct ⊕ M.parens arg 
+  f arg = M.f & arg
+
+  f M.x
+  M.«1 + f({arg}) + Σ^i_(0..n)»
+  -}
+
+  subsection «No plain chars»
+  todo "=> (M.a, M.b...), in fact yes as unicode support"
+  todo "still low level (sum has only one arg)"
+  todo "still the same meaning for ⊕ Ligatures"
+  todo "num class"
+
+  section «Verbatim mode»
+
+  subsection «Why not using the {latex} verbatim mode?»
+
+  p «{latex} verbatim mode is a hack.  It is a kind of global side-effect that
+    changes the meaning of letters to turn off their original meaning and
+    produce fixed width characters.  In result the verbatim mode interacts badly
+    with other fancy environments.»
+
+  p «In {haskell} this task is much simpler, indeed we do have literal strings.
+    There is no need to change some existing meaning.  We just need a function
+    from {hcode "String"} to {hcode "LatexItem"}.»
+  subsection «The protect function»
+  todo «special characters
+     Ligatures
+     Work with fixed width fonts»
+  todo "verb, M.verb, UTF8..."
+
+  section «Figures»
+
+  section «Bibliography, glossary and index»
+
+  section «Making new commands»
+  todo "L.L.Builder.Internal"
+
+  section «Injecting Raw LaTeX»
+
+  section «Pictures»
+
+  section «Size units and pre-defineds dimensions»
+  todo "normalisation, symbolic eval, num class"
+
+  section «The LatexM monad»
+  subsection «What for?»
+  subsection «How hidden is it?»
+  todo «
+     a monad transformer would allow
+       custom initial monad, more state,
+       more control...
+    »
+
+  section «Using the Writer monad»
+
+  section «Misc»
+  subsection «Save bins»
+
+  section «Packages»
+  subsection «Automatic tracking»
+
+  subsection «graphics»
+  subsection «Listings equivalent»
+
+  subsection «Adding new packages»
+
+-- end
diff --git a/hlatex.cabal b/hlatex.cabal
new file mode 100644
--- /dev/null
+++ b/hlatex.cabal
@@ -0,0 +1,54 @@
+name:            hlatex
+cabal-version:   >= 1.8
+version:         0.1
+license:         BSD3
+license-File:    LICENSE
+copyright:       (c) Nicolas Pouillard
+author:          Nicolas Pouillard
+maintainer:      Nicolas Pouillard <nicolas.pouillard@gmail.com>
+category:        Text
+synopsis:        A library to build valid LaTeX files
+description:     ...
+stability:       Provisional
+build-type:      Simple
+
+flag build_doc
+    Default: False
+
+library
+    build-depends:
+                 base>=3.0&&<5, containers>=0.1, process, filepath, directory,
+                 template-haskell >= 2.5,
+                 transformers>=0.2.1&&<1, mtl>2.0, base-unicode-symbols,
+                 uniplate>=1.4&&<1.7, derive, utf8-string
+    exposed-modules:
+                 Language.LaTeX,
+                 Language.LaTeX.Types,
+                 Language.LaTeX.Length,
+                 Language.LaTeX.Builder,
+                 Language.LaTeX.Builder.Internal,
+                 Language.LaTeX.Builder.MonoidUtils,
+                 Language.LaTeX.Builder.Math,
+                 Language.LaTeX.Builder.Graphics,
+                 Language.LaTeX.Builder.Color,
+                 Language.LaTeX.Builder.Rotating,
+                 Language.LaTeX.Builder.QQ,
+                 Language.LaTeX.Builder.Beamer,
+                 Language.LaTeX.Builder.Babel,
+                 Language.LaTeX.Printer,
+                 Language.LaTeX.Slicer,
+                 Language.LaTeX.Checker,
+                 Language.LaTeX.Unicode
+    ghc-options: -Wall
+
+executable generate_hlatex_user_guide
+    Build-depends: base>=3.0, containers>=0.1, frquotes,
+                   transformers, mtl>2.0, base-unicode-symbols
+    main-is: doc/user_guide.hs
+    ghc-options: -Wall
+  if !flag(build_doc)
+    Buildable: False
+
+source-repository head
+  type:     git
+  location: https://github.com/np/hlatex.git
