diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,95 @@
+Copyright (c) 2009, Darin Morrison
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+3. Neither the name of the author nor the names of his 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 HOLDER 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.
+
+--------------------------------------------------------------------------------
+
+Portions of this codebase are derived from the 'ansi-wl-pprint'
+package which is copyrighted and licensed as follows:
+
+Copyright 2008, Daan Leijen and Max Bolingbroke. 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.
+
+This software is provided by the copyright holders "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 holders 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.
+
+--------------------------------------------------------------------------------
+
+Portions of this codebase are derived from the 'boxes' package which
+is copyrighted and licensed as follows:
+
+Copyright (c) Brent Yorgey 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of the author 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 AUTHORS ``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 AUTHORS 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/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+
+main = defaultMain
diff --git a/mpppc.cabal b/mpppc.cabal
new file mode 100644
--- /dev/null
+++ b/mpppc.cabal
@@ -0,0 +1,57 @@
+name:                mpppc
+version:             0.1.0
+stability:           experimental
+description:         Multi-dimensional parametric pretty-printer with color
+synopsis:            Multi-dimensional parametric pretty-printer with color
+category:            Text
+license:             GPL
+license-file:        LICENSE
+author:              Max Bolingbroke,
+                     Brent Yorgey,
+                     Darin Morrison
+maintainer:          darinmorrison@gmail.com
+build-type:          Simple
+cabal-version:       >= 1.6
+
+library
+  build-depends:     ansi-terminal >= 0.5   && <= 0.6
+                   , base          >= 3.0   && <= 4.0
+                   , bytestring    >= 0.9.1 && <= 0.9.2
+                   , split         >= 0.1.1 && <= 0.2
+                   , text          >= 0.5   && <= 0.6
+
+  extensions:      BangPatterns
+                   ExistentialQuantification
+                   FlexibleInstances
+                   FunctionalDependencies
+                   MultiParamTypeClasses
+                   OverloadedStrings
+                   ScopedTypeVariables
+
+  exposed-modules: Text.PrettyPrint.MPPPC.OneDim
+                   Text.PrettyPrint.MPPPC.TwoDim
+
+  ghc-options:     -Wall -fwarn-tabs -funbox-strict-fields -O2
+
+  hs-source-dirs:  src
+
+  other-modules:   Text.PrettyPrint.MPPPC.OneDim.Combinators
+                   Text.PrettyPrint.MPPPC.OneDim.Combinators.Align
+                   Text.PrettyPrint.MPPPC.OneDim.Combinators.ANSI
+                   Text.PrettyPrint.MPPPC.OneDim.Combinators.Fill
+                   Text.PrettyPrint.MPPPC.OneDim.Combinators.Layout
+                   Text.PrettyPrint.MPPPC.OneDim.Combinators.Prim
+                   Text.PrettyPrint.MPPPC.OneDim.Combinators.Seq
+                   Text.PrettyPrint.MPPPC.OneDim.Combinators.Tok
+                   Text.PrettyPrint.MPPPC.OneDim.Display
+                   Text.PrettyPrint.MPPPC.OneDim.Pretty
+                   Text.PrettyPrint.MPPPC.OneDim.Render
+                   Text.PrettyPrint.MPPPC.Printable
+                   Text.PrettyPrint.MPPPC.TwoDim.Combinators
+                   Text.PrettyPrint.MPPPC.TwoDim.Combinators.Align
+                   Text.PrettyPrint.MPPPC.TwoDim.Combinators.Flow
+                   Text.PrettyPrint.MPPPC.TwoDim.Combinators.Layout
+                   Text.PrettyPrint.MPPPC.TwoDim.Combinators.Prim
+                   Text.PrettyPrint.MPPPC.TwoDim.Display
+                   Text.PrettyPrint.MPPPC.TwoDim.Pretty
+                   Text.PrettyPrint.MPPPC.TwoDim.Render
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim.hs b/src/Text/PrettyPrint/MPPPC/OneDim.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim.hs
@@ -0,0 +1,13 @@
+module Text.PrettyPrint.MPPPC.OneDim
+  ( module Text.PrettyPrint.MPPPC.OneDim.Combinators
+  , module Text.PrettyPrint.MPPPC.OneDim.Display
+  , module Text.PrettyPrint.MPPPC.OneDim.Pretty
+  , module Text.PrettyPrint.MPPPC.OneDim.Render
+  , module Text.PrettyPrint.MPPPC.Printable )
+  where
+
+import Text.PrettyPrint.MPPPC.OneDim.Combinators
+import Text.PrettyPrint.MPPPC.OneDim.Display
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+import Text.PrettyPrint.MPPPC.OneDim.Render
+import Text.PrettyPrint.MPPPC.Printable
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Combinators.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators.hs
@@ -0,0 +1,17 @@
+module Text.PrettyPrint.MPPPC.OneDim.Combinators
+  ( module Text.PrettyPrint.MPPPC.OneDim.Combinators.Align
+  , module Text.PrettyPrint.MPPPC.OneDim.Combinators.ANSI
+  , module Text.PrettyPrint.MPPPC.OneDim.Combinators.Fill
+  , module Text.PrettyPrint.MPPPC.OneDim.Combinators.Layout
+  , module Text.PrettyPrint.MPPPC.OneDim.Combinators.Prim
+  , module Text.PrettyPrint.MPPPC.OneDim.Combinators.Seq
+  , module Text.PrettyPrint.MPPPC.OneDim.Combinators.Tok )
+  where
+
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Align
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.ANSI
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Fill
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Layout
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Prim
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Seq
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Tok
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/ANSI.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/ANSI.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/ANSI.hs
@@ -0,0 +1,124 @@
+module Text.PrettyPrint.MPPPC.OneDim.Combinators.ANSI where
+
+import System.Console.ANSI
+  ( Color            (..)
+  , ColorIntensity   (..)
+  , ConsoleIntensity (..)
+  , ConsoleLayer     (..)
+  , Underlining      (..) )
+
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+
+-- Colors
+
+black :: Pretty s t -> Pretty s t
+black = Color Foreground Vivid Black
+
+red :: Pretty s t -> Pretty s t
+red = Color Foreground Vivid Red
+
+green :: Pretty s t -> Pretty s t
+green = Color Foreground Vivid Green
+
+yellow :: Pretty s t -> Pretty s t
+yellow = Color Foreground Vivid Yellow
+
+blue :: Pretty s t -> Pretty s t
+blue = Color Foreground Vivid Blue
+
+magenta :: Pretty s t -> Pretty s t
+magenta = Color Foreground Vivid Magenta
+
+cyan :: Pretty s t -> Pretty s t
+cyan = Color Foreground Vivid Cyan
+
+white :: Pretty s t -> Pretty s t
+white = Color Foreground Vivid White
+
+dullBlack :: Pretty s t -> Pretty s t
+dullBlack = Color Foreground Dull Black
+
+dullRed :: Pretty s t -> Pretty s t
+dullRed = Color Foreground Dull Red
+
+dullGreen :: Pretty s t -> Pretty s t
+dullGreen = Color Foreground Dull Green
+
+dullYellow :: Pretty s t -> Pretty s t
+dullYellow = Color Foreground Dull Yellow
+
+dullBlue :: Pretty s t -> Pretty s t
+dullBlue = Color Foreground Dull Blue
+
+dullMagenta :: Pretty s t -> Pretty s t
+dullMagenta = Color Foreground Dull Magenta
+
+dullCyan :: Pretty s t -> Pretty s t
+dullCyan = Color Foreground Dull Cyan
+
+dullWhite :: Pretty s t -> Pretty s t
+dullWhite = Color Foreground Dull White
+
+onBlack :: Pretty s t -> Pretty s t
+onBlack = Color Background Vivid Black
+
+onRed :: Pretty s t -> Pretty s t
+onRed = Color Background Vivid Red
+
+onGreen :: Pretty s t -> Pretty s t
+onGreen = Color Background Vivid Green
+
+onYellow :: Pretty s t -> Pretty s t
+onYellow = Color Background Vivid Yellow
+
+onBlue :: Pretty s t -> Pretty s t
+onBlue = Color Background Vivid Blue
+
+onMagenta :: Pretty s t -> Pretty s t
+onMagenta = Color Background Vivid Magenta
+
+onCyan :: Pretty s t -> Pretty s t
+onCyan = Color Background Vivid Cyan
+
+onWhite :: Pretty s t -> Pretty s t
+onWhite = Color Background Vivid White
+
+onDullBlack :: Pretty s t -> Pretty s t
+onDullBlack = Color Background Dull Black
+
+onDullRed :: Pretty s t -> Pretty s t
+onDullRed = Color Background Dull Red
+
+onDullGreen :: Pretty s t -> Pretty s t
+onDullGreen = Color Background Dull Green
+
+onDullYellow :: Pretty s t -> Pretty s t
+onDullYellow = Color Background Dull Yellow
+
+onDullBlue :: Pretty s t -> Pretty s t
+onDullBlue = Color Background Dull Blue
+
+onDullMagenta :: Pretty s t -> Pretty s t
+onDullMagenta = Color Background Dull Magenta
+
+onDullCyan :: Pretty s t -> Pretty s t
+onDullCyan = Color Background Dull Cyan
+
+onDullWhite :: Pretty s t -> Pretty s t
+onDullWhite = Color Background Dull White
+
+-- Emboldening
+
+bold :: Pretty s t -> Pretty s t
+bold = Intensify BoldIntensity
+
+deBold :: Pretty s t -> Pretty s t
+deBold = Intensify NormalIntensity
+
+-- Underlining
+
+underline :: Pretty s t -> Pretty s t
+underline = Underline SingleUnderline
+
+deUnderline :: Pretty s t -> Pretty s t
+deUnderline = Underline NoUnderline
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Align.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Align.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Align.hs
@@ -0,0 +1,37 @@
+module Text.PrettyPrint.MPPPC.OneDim.Combinators.Align where
+
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Layout
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Seq
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Tok
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+import Text.PrettyPrint.MPPPC.Printable
+
+align :: Pretty s t -> Pretty s t
+align d = column $ \ i -> nesting $ \ j -> nest (i - j) d
+
+encloseSep :: Printable s t
+           =>  Pretty s t
+           ->  Pretty s t
+           ->  Pretty s t
+           -> [Pretty s t]
+           ->  Pretty s t
+encloseSep left right seperator ds =
+  case ds of
+    []  -> left <>      right
+    [d] -> left <> d <> right
+    _   -> align (cat (zipWith (<>) (left : repeat seperator) ds) <> right)
+
+hang :: Int -> Pretty s t -> Pretty s t
+hang n = align . nest n
+
+indent :: Printable s t => Int -> Pretty s t -> Pretty s t
+indent i = hang i . (spaces i <>)
+
+list :: Printable s t => [Pretty s t] -> Pretty s t
+list = encloseSep bracketLeft bracketRight comma
+
+semiBraces :: Printable s t => [Pretty s t] -> Pretty s t
+semiBraces = encloseSep braceLeft braceRight semi
+
+tupled :: Printable s t => [Pretty s t] -> Pretty s t
+tupled = encloseSep parenLeft parenRight comma
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Fill.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Fill.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Fill.hs
@@ -0,0 +1,28 @@
+module Text.PrettyPrint.MPPPC.OneDim.Combinators.Fill where
+
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Layout
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Prim
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Seq
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+import Text.PrettyPrint.MPPPC.Printable
+
+width :: Pretty s t -> (Int -> Pretty s t) -> Pretty s t
+width d f = column (\ i1 -> d <> column (\ i2 -> f (i2 - i1)))
+
+fill :: Printable s t => Int -> Pretty s t -> Pretty s t
+fill f d = width d $ \ w ->
+  if w >= f
+  then empty
+  else spaces (f - w)
+
+fillBreak :: Printable s t => Int -> Pretty s t -> Pretty s t
+fillBreak f x = width x $ \ w ->
+  if w >  f
+  then nest f lineBreak
+  else spaces (f - w)
+
+fillCat :: Printable s t => [Pretty s t] -> Pretty s t
+fillCat = fold (<//>)
+
+fillSep :: Printable s t => [Pretty s t] -> Pretty s t
+fillSep = fold (</>)
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Layout.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Layout.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Layout.hs
@@ -0,0 +1,85 @@
+module Text.PrettyPrint.MPPPC.OneDim.Combinators.Layout where
+
+import Prelude
+  hiding
+    ( length )
+
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Prim
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Tok
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+import Text.PrettyPrint.MPPPC.Printable
+
+infixr 5 </>, <//>, <$>, <$$>
+infixr 6 <>, <+>
+
+(<>) :: Pretty s t -> Pretty s t -> Pretty s t
+(<>)  = beside
+
+(<+>) :: Printable s t => Pretty s t -> Pretty s t -> Pretty s t
+x <+> y = x <> space <> y
+
+(<$$>) :: Pretty s t -> Pretty s t -> Pretty s t
+x <$$> y = x <> lineBreak <> y
+
+(<//>) :: Printable s t => Pretty s t -> Pretty s t -> Pretty s t
+x <//> y = x <> group lineBreak <> y
+
+(<$>) :: Pretty s t -> Pretty s t -> Pretty s t
+x <$> y = x <> line <> y
+
+(</>) :: Printable s t => Pretty s t -> Pretty s t -> Pretty s t
+x </> y = x <> group line <> y
+
+beside :: Pretty s t -> Pretty s t -> Pretty s t
+beside = Cat
+
+cat :: Printable s t => [Pretty s t] -> Pretty s t
+cat = group . vcat
+
+column :: (Int -> Pretty s t) -> Pretty s t
+column = Column
+
+fold :: (Pretty s t -> Pretty s t -> Pretty s t) -> [Pretty s t] -> Pretty s t
+fold _ [] = empty
+fold f ds = foldr1 f ds
+
+group :: Printable s t => Pretty s t -> Pretty s t
+group x = Union (flatten x) x
+
+hcat :: Printable s t => [Pretty s t] -> Pretty s t
+hcat = fold (<>)
+
+hsep :: Printable s t => [Pretty s t] -> Pretty s t
+hsep = fold (<+>)
+
+line :: Pretty s t
+line = Line False
+
+lineBreak :: Pretty s t
+lineBreak = Line True
+
+nest :: Int -> Pretty s t -> Pretty s t
+nest = Nest
+
+nesting :: (Int -> Pretty s t) -> Pretty s t
+nesting = Nesting
+
+punctuate :: Pretty s t -> [Pretty s t] -> [Pretty s t]
+punctuate _ []     = []
+punctuate _ [d]    = [d]
+punctuate p (d:ds) = (d <> p) : punctuate p ds
+
+sep :: Printable s t => [Pretty s t] -> Pretty s t
+sep = group . vsep
+
+softLine :: Printable s t => Pretty s t
+softLine = group line
+
+softBreak :: Printable s t => Pretty s t
+softBreak = group lineBreak
+
+vcat :: [Pretty s t] -> Pretty s t
+vcat = fold (<$$>)
+
+vsep :: [Pretty s t] -> Pretty s t
+vsep = fold (<$>)
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Prim.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Prim.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Prim.hs
@@ -0,0 +1,33 @@
+module Text.PrettyPrint.MPPPC.OneDim.Combinators.Prim where
+
+import Prelude
+  hiding
+    ( length )
+
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+import Text.PrettyPrint.MPPPC.Printable
+
+char :: Printable s t => t -> Pretty s t
+char c
+  | c == tokNewline = Line False
+  | otherwise       = Char c
+
+empty :: Pretty s t
+empty = Empty
+
+flatten :: Printable s t => Pretty s t -> Pretty s t
+flatten (Cat x y)       = Cat (flatten x) (flatten y)
+flatten (Nest i x)      = Nest i (flatten x)
+flatten (Line b)        = if b then Empty else Text 1 (tokSpace `cons` seqEmpty)
+flatten (Union x _)     = flatten x
+flatten (Column f)      = Column  (flatten . f)
+flatten (Nesting f)     = Nesting (flatten . f)
+flatten (Color l i c x) = Color l i c (flatten x)
+flatten (Intensify i x) = Intensify i (flatten x)
+flatten (Underline u x) = Underline u (flatten x)
+flatten other           = other
+
+text :: Printable s t => s -> Pretty s t
+text s
+  | s == seqEmpty = Empty
+  | otherwise     = Text (length s) s
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Seq.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Seq.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Seq.hs
@@ -0,0 +1,35 @@
+module Text.PrettyPrint.MPPPC.OneDim.Combinators.Seq where
+
+import Prelude
+  hiding
+    ( replicate )
+
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Layout
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Prim
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Tok
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+import Text.PrettyPrint.MPPPC.Printable
+
+angles :: Printable s t => Pretty s t -> Pretty s t
+angles = angleLeft `enclose` angleRight
+
+braces :: Printable s t => Pretty s t -> Pretty s t
+braces = braceLeft `enclose` braceRight
+
+brackets :: Printable s t => Pretty s t -> Pretty s t
+brackets = bracketLeft `enclose` bracketRight
+
+enclose :: Printable s t => Pretty s t -> Pretty s t -> Pretty s t -> Pretty s t
+enclose l r x   = l <> x <> r
+
+parens :: Printable s t => Pretty s t -> Pretty s t
+parens = parenLeft `enclose` parenRight
+
+quotesDouble :: Printable s t => Pretty s t -> Pretty s t
+quotesDouble = quoteDouble `enclose` quoteDouble
+
+quotesSingle :: Printable s t => Pretty s t -> Pretty s t
+quotesSingle = quoteSingle `enclose` quoteSingle
+
+spaces :: Printable s t => Int -> Pretty s t
+spaces n = text $ replicate n $ tokSpace `cons` seqEmpty
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Tok.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Tok.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Combinators/Tok.hs
@@ -0,0 +1,60 @@
+module Text.PrettyPrint.MPPPC.OneDim.Combinators.Tok where
+
+import Prelude
+  hiding
+   ( replicate )
+
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+import Text.PrettyPrint.MPPPC.OneDim.Combinators.Prim
+import Text.PrettyPrint.MPPPC.Printable
+
+angleLeft :: Printable s t => Pretty s t
+angleLeft = char tokAngleLeft
+
+angleRight :: Printable s t => Pretty s t
+angleRight = char tokAngleRight
+
+backslash :: Printable s t => Pretty s t
+backslash = char tokBackslash
+
+braceLeft :: Printable s t => Pretty s t
+braceLeft = char tokBraceLeft
+
+braceRight :: Printable s t => Pretty s t
+braceRight = char tokBraceRight
+
+bracketLeft :: Printable s t => Pretty s t
+bracketLeft = char tokBracketLeft
+
+bracketRight :: Printable s t => Pretty s t
+bracketRight = char tokBracketRight
+
+colon :: Printable s t => Pretty s t
+colon = char tokColon
+
+comma :: Printable s t => Pretty s t
+comma = char tokComma
+
+dot :: Printable s t => Pretty s t
+dot = char tokDot
+
+equals :: Printable s t => Pretty s t
+equals = char tokEquals
+
+parenLeft :: Printable s t => Pretty s t
+parenLeft = char tokParenLeft
+
+parenRight :: Printable s t => Pretty s t
+parenRight = char tokParenRight
+
+semi :: Printable s t => Pretty s t
+semi = char tokSemi
+
+space :: Printable s t => Pretty s t
+space = char tokSpace
+
+quoteDouble :: Printable s t => Pretty s t
+quoteDouble = char tokQuoteDouble
+
+quoteSingle :: Printable s t => Pretty s t
+quoteSingle = char tokQuoteSingle
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Display.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Display.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Display.hs
@@ -0,0 +1,33 @@
+module Text.PrettyPrint.MPPPC.OneDim.Display where
+
+import Prelude
+  hiding
+    ( replicate )
+import System.Console.ANSI
+  ( hSetSGR )
+import System.IO
+  ( Handle
+  , stdout )
+
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+import Text.PrettyPrint.MPPPC.OneDim.Render
+import Text.PrettyPrint.MPPPC.Printable
+
+hPutSimplePretty :: forall s t. Printable s t => Handle -> SimplePretty s t -> IO ()
+hPutSimplePretty h = display
+  where
+    display :: SimplePretty s t -> IO ()
+    display (SimpleChar c   x) = hPutTok h c >> display x
+    display (SimpleEmpty     ) = return ()
+    display (SimpleLine i   x) = hPutSeq h l >> display x
+      where
+        l :: s
+        l = tokNewline `cons` replicate i (tokSpace `cons` seqEmpty)
+    display (SimpleText _ s x) = hPutSeq h s >> display x
+    display (SimpleSGR  s   x) = hSetSGR h s >> display x
+
+hPutPretty :: Printable s t => Handle -> Pretty s t -> IO ()
+hPutPretty h = hPutSimplePretty h . renderPretty 0.4 80
+
+putPretty :: Printable s t => Pretty s t -> IO ()
+putPretty = hPutPretty stdout
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Pretty.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Pretty.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Pretty.hs
@@ -0,0 +1,62 @@
+module Text.PrettyPrint.MPPPC.OneDim.Pretty where
+
+import Prelude
+  hiding
+    ( length )
+import Data.String
+import Data.Text
+  hiding
+    ( length )
+
+import Text.PrettyPrint.MPPPC.Printable
+
+import System.Console.ANSI
+  ( Color
+  , ColorIntensity
+  , ConsoleIntensity
+  , ConsoleLayer
+  , SGR
+  , Underlining )
+
+data FormatState
+  =  FormatState
+       { stForeground  :: Maybe (ColorIntensity, Color)
+       , stBackground  :: Maybe (ColorIntensity, Color)
+       , stIntensity   :: Maybe ConsoleIntensity
+       , stUnderlining :: Maybe Underlining }
+
+data Pretty s t
+  = Empty
+  | Printable s t => Char t
+  | Printable s t => Text !Int s
+  | Line Bool
+  | Cat (Pretty s t) (Pretty s t)
+  | Nest Int (Pretty s t)
+  | Union (Pretty s t) (Pretty s t)
+  | Column  (Int -> Pretty s t)
+  | Nesting (Int -> Pretty s t)
+  | Color ConsoleLayer ColorIntensity Color (Pretty s t)
+  | Intensify ConsoleIntensity (Pretty s t)
+  | Underline Underlining (Pretty s t)
+  | RestoreFormat FormatState
+
+data SimplePretty s t
+  = SimpleEmpty
+  | Printable s t => SimpleChar t     (SimplePretty s t)
+  | Printable s t => SimpleText Int s (SimplePretty s t)
+  | SimpleLine Int (SimplePretty s t)
+  | SimpleSGR [SGR] (SimplePretty s t)
+
+instance IsString (Pretty (Seq String Char) (Tok String Char)) where
+  fromString = text . fromString
+    where
+      text s
+        | s == seqEmpty = Empty
+        | otherwise     = Text (length s) s
+
+instance IsString (Pretty (Seq Text   Char) (Tok Text   Char)) where
+  fromString = text . fromString
+    where
+      text s
+        | s == seqEmpty = Empty
+        | otherwise     = Text (length s) s
diff --git a/src/Text/PrettyPrint/MPPPC/OneDim/Render.hs b/src/Text/PrettyPrint/MPPPC/OneDim/Render.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/OneDim/Render.hs
@@ -0,0 +1,110 @@
+module Text.PrettyPrint.MPPPC.OneDim.Render where
+
+import Prelude
+  hiding ( replicate )
+import Data.Maybe
+  ( catMaybes )
+import System.Console.ANSI
+  ( ConsoleLayer (..)
+  , SGR          (..)
+  , setSGRCode )
+
+import Text.PrettyPrint.MPPPC.OneDim.Pretty
+import Text.PrettyPrint.MPPPC.Printable
+
+data Pretties s t
+  = Nil
+  | Cons !Int (Pretty s t) (Pretties s t)
+
+-- FIXME: yuck
+renderPretty :: Float -> Int -> Pretty s t -> SimplePretty s t
+renderPretty rfrac w d = best 0 0 initState (Cons 0 d Nil)
+  where
+    initState = FormatState
+      { stForeground  = Nothing
+      , stBackground  = Nothing
+      , stIntensity   = Nothing
+      , stUnderlining = Nothing }
+    nicest n k x y
+      | width `fits` x                                   = x
+      | otherwise                                        = y
+      where
+        width                       = (w - k) `min` (r - k + n)
+          where
+            r = max 0 $ min w $ round $ fromIntegral w * rfrac
+        fits w' _ | w' < 0          = False
+        fits _   SimpleEmpty        = True
+        fits _  (SimpleLine _ _   ) = True
+        fits w' (SimpleChar _   d') = (w' - 1) `fits` d'
+        fits w' (SimpleText l _ d') = (w' - l) `fits` d'
+        fits w' (SimpleSGR  _   d') =  w'      `fits` d'
+    best _ _ _  Nil            = SimpleEmpty
+    best n k st (Cons i d' ds) = 
+      let best_typical n' !k' ds' = best n' k'                st  ds'
+          ds_restore              = Cons i     (RestoreFormat st) ds
+       in case d' of
+         Cat d1 d2         ->                  best_typical n  k               $ Cons i      d1    (Cons i d2 ds)
+         Char c            -> SimpleChar c   $ best_typical n (k+1)                                           ds
+         Column f          ->                  best_typical n  k               $ Cons i     (f k)             ds
+         Empty             ->                  best_typical n  k                                              ds
+         Line _            -> SimpleLine i   $ best_typical i  i                                              ds
+         Nest j d''        ->                  best_typical n  k               $ Cons (i+j)  d''              ds
+         Nesting f         ->                  best_typical n  k               $ Cons i     (f i)             ds
+         Text l s          -> SimpleText l s $ best_typical n (k+l)                                           ds
+         Union d1 d2       -> nicest n k      (best_typical n  k               $ Cons i      d1               ds)
+                                              (best_typical n  k               $ Cons i      d2               ds)
+         Intensify t d''   -> SimpleSGR [SetConsoleIntensity t] $ best n k st' $ Cons i      d''              ds_restore
+           where
+             st' = st { stIntensity   = Just t }
+         Underline u d''   -> SimpleSGR [SetUnderlining      u] $ best n k st' $ Cons i      d''              ds_restore
+           where
+             st' = st { stUnderlining = Just u }
+         Color l t c d''   -> SimpleSGR [SetColor l t c       ] $ best n k st' $ Cons i      d''              ds_restore
+           where
+             st' = st { stForeground = case l of
+                                         Background -> stForeground st
+                                         Foreground -> Just (t, c)
+                      , stBackground = case l of
+                                         Background -> Just (t, c)
+                                         Foreground -> stBackground st
+                      }
+         RestoreFormat st' -> SimpleSGR sgrs                    $ best n k st'                                ds
+           where
+             sgrs = Reset : catMaybes
+               [ fmap (uncurry $ SetColor Foreground) $ stForeground  st'
+               , fmap (uncurry $ SetColor Background) $ stBackground  st'
+               , fmap SetConsoleIntensity             $ stIntensity   st'
+               , fmap SetUnderlining                  $ stUnderlining st'
+               ]
+
+renderCompact :: Pretty s t -> SimplePretty s t
+renderCompact = scan 0 . (: [])
+  where
+    scan _ []     = SimpleEmpty
+    scan k (d:ds) = case d of
+      Empty           ->                  scan  k                    ds
+      Char c          -> SimpleChar c   $ scan (k + 1)               ds
+      Text l s        -> SimpleText l s $ scan (k + 1)               ds
+      Line _          -> SimpleLine 0   $ scan      0                ds
+      Cat d1 d2       ->                  scan  k      $   d1 : d2 : ds
+      Nest _ d'       ->                  scan  k      $   d' :      ds
+      Union _ d2      ->                  scan  k      $   d2 :      ds
+      Column f        ->                  scan  k      $ f k  :      ds
+      Nesting f       ->                  scan  k      $ f 0  :      ds
+      Color _ _ _ d'  ->                  scan  k      $   d' :      ds
+      Intensify _ d'  ->                  scan  k      $   d' :      ds
+      Underline _ d'  ->                  scan  k      $   d' :      ds
+      RestoreFormat _ ->                  scan  k                    ds
+
+renderSimplePretty :: forall s t. Printable s t => SimplePretty s t -> s
+renderSimplePretty (SimpleChar c   x) = c `cons`   renderSimplePretty x
+renderSimplePretty (SimpleEmpty     ) = seqEmpty
+renderSimplePretty (SimpleLine i   x) = l `append` renderSimplePretty x
+  where
+    l :: s
+    l = tokNewline `cons` replicate i (tokSpace `cons` seqEmpty)
+renderSimplePretty (SimpleText _ s x) = s `append` renderSimplePretty x
+renderSimplePretty (SimpleSGR    s x) = pack (setSGRCode s) `append` renderSimplePretty x
+
+renderSeq :: Printable s t => Pretty s t -> s
+renderSeq = renderSimplePretty . renderPretty 0.4 80
diff --git a/src/Text/PrettyPrint/MPPPC/Printable.hs b/src/Text/PrettyPrint/MPPPC/Printable.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/Printable.hs
@@ -0,0 +1,149 @@
+module Text.PrettyPrint.MPPPC.Printable where
+
+import Control.Arrow
+  ( (***) )
+import qualified Data.ByteString
+  as Word8
+import qualified Data.List
+  as List
+import qualified Data.List.Split
+  as List
+import Data.String
+  ( IsString
+  , fromString )
+import qualified Data.Text
+  as Text
+import qualified Data.Text.Encoding
+  as Text
+import System.IO
+  ( Handle
+  , hPutChar
+  , hPutStr )
+
+newtype Tok s t = Tok { unTok :: t }
+  deriving (Eq, Ord, Show)
+
+newtype Seq s t = Seq { unSeq :: s }
+  deriving (Eq, Ord, Show)
+
+class (Eq s, Eq t, IsString s) => Printable s t | s -> t, t -> s where
+  append          :: s -> s -> s
+  chunk           :: Int -> s -> [s]
+  cons            :: t -> s -> s
+  head            :: s -> t
+  hPutTok         :: Handle -> t -> IO ()
+  hPutSeq         :: Handle -> s -> IO ()
+  length          :: s -> Int
+  pack            :: String -> s
+  isNull          :: s -> Bool
+  replicate       :: Int -> s -> s
+  reverse         :: s -> s
+  singleton       :: t -> s
+  singleton       = (`cons` seqEmpty)
+  seqEmpty        :: s
+  splitAt         :: Int -> s -> (s, s)
+  tail            :: s -> s
+  take            :: Int -> s -> s
+  tokAngleLeft    :: t
+  tokAngleRight   :: t
+  tokBackslash    :: t
+  tokBraceLeft    :: t
+  tokBraceRight   :: t
+  tokBracketLeft  :: t
+  tokBracketRight :: t
+  tokColon        :: t
+  tokComma        :: t
+  tokDot          :: t
+  tokEquals       :: t
+  tokNewline      :: t
+  tokParenLeft    :: t
+  tokParenRight   :: t
+  tokQuoteDouble  :: t
+  tokQuoteSingle  :: t
+  tokSemi         :: t
+  tokSpace        :: t
+  unlines         :: [s] -> s
+  unwords         :: [s] -> s
+  words           :: s -> [s]
+
+instance IsString (Seq String Char) where
+  fromString = Seq . fromString
+
+instance Printable (Seq String Char) (Tok String Char) where
+  append s        =     Seq . (++) (unSeq s)                 . unSeq
+  chunk     n     = map Seq . List.chunk n                   . unSeq
+  cons   t        =     Seq . (unTok t :)                    . unSeq
+  head            =     Tok . List.head                      . unSeq
+  hPutTok h       = hPutChar h                               . unTok
+  hPutSeq h       = hPutStr  h                               . unSeq
+  length          =           List.length                    . unSeq
+  pack            =     Seq . id
+  isNull          =           List.null                      . unSeq
+  replicate n     =     Seq . List.concat . List.replicate n . unSeq
+  reverse         =     Seq . List.reverse                   . unSeq
+  seqEmpty        = Seq ""
+  splitAt   n     = (Seq *** Seq) . List.splitAt n           . unSeq
+  tail            =     Seq . List.tail                      . unSeq
+  take      n     =     Seq . List.take      n               . unSeq
+  tokAngleLeft    = Tok '<'
+  tokAngleRight   = Tok '>'
+  tokBackslash    = Tok '\\'
+  tokBraceLeft    = Tok '{'
+  tokBraceRight   = Tok '}'
+  tokBracketLeft  = Tok '['
+  tokBracketRight = Tok ']'
+  tokColon        = Tok ':'
+  tokComma        = Tok ','
+  tokDot          = Tok '.'
+  tokEquals       = Tok '='
+  tokNewline      = Tok '\n'
+  tokParenLeft    = Tok '('
+  tokParenRight   = Tok ')'
+  tokQuoteDouble  = Tok '"'
+  tokQuoteSingle  = Tok '\''
+  tokSemi         = Tok ';'
+  tokSpace        = Tok ' '
+  unlines         =     Seq . List.unlines                   . map unSeq
+  unwords         =     Seq . List.unwords                   . map unSeq
+  words           = map Seq . List.words                     . unSeq
+
+instance IsString (Seq Text.Text Char) where
+  fromString = Seq . fromString
+
+instance Printable (Seq Text.Text Char) (Tok Text.Text Char) where
+  append s        =     Seq . Text.append (unSeq s)    . unSeq
+  chunk     n     = map Seq . Text.chunksOf  n         . unSeq
+  cons   t        =     Seq . (unTok t `Text.cons`)    . unSeq
+  head            =     Tok . Text.head                . unSeq
+  hPutTok h       =       hPutChar h .                   unTok
+  hPutSeq h       = Word8.hPutStr  h . Text.encodeUtf8 . unSeq
+  length          =           Text.length              . unSeq
+  pack            =     Seq . Text.pack
+  isNull          =           Text.null                . unSeq
+  replicate n     =     Seq . Text.replicate n         . unSeq
+  reverse         =     Seq . Text.reverse             . unSeq
+  seqEmpty        = Seq ""
+  splitAt   n     = (Seq *** Seq) . Text.splitAt n     . unSeq
+  tail            =     Seq . Text.tail                . unSeq
+  take      n     =     Seq . Text.take      n         . unSeq
+  tokAngleLeft    = Tok '<'
+  tokAngleRight   = Tok '>'
+  tokBackslash    = Tok '\\'
+  tokBraceLeft    = Tok '{'
+  tokBraceRight   = Tok '}'
+  tokBracketLeft  = Tok '['
+  tokBracketRight = Tok ']'
+  tokColon        = Tok ':'
+  tokComma        = Tok ','
+  tokDot          = Tok '.'
+  tokEquals       = Tok '='
+  tokNewline      = Tok '\n'
+  tokParenLeft    = Tok '('
+  tokParenRight   = Tok ')'
+  tokQuoteDouble  = Tok '"'
+  tokQuoteSingle  = Tok '\''
+  tokSemi         = Tok ';'
+  tokSpace        = Tok ' '
+  unlines         =     Seq . Text.unlines             . map unSeq
+  unwords         =     Seq . Text.unwords             . map unSeq
+  words           = map Seq . Text.words               . unSeq
diff --git a/src/Text/PrettyPrint/MPPPC/TwoDim.hs b/src/Text/PrettyPrint/MPPPC/TwoDim.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/TwoDim.hs
@@ -0,0 +1,13 @@
+module Text.PrettyPrint.MPPPC.TwoDim
+  ( module Text.PrettyPrint.MPPPC.TwoDim.Combinators
+  , module Text.PrettyPrint.MPPPC.TwoDim.Display
+  , module Text.PrettyPrint.MPPPC.TwoDim.Pretty
+  , module Text.PrettyPrint.MPPPC.TwoDim.Render
+  , module Text.PrettyPrint.MPPPC.Printable )
+  where
+
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators
+import Text.PrettyPrint.MPPPC.TwoDim.Display
+import Text.PrettyPrint.MPPPC.TwoDim.Pretty
+import Text.PrettyPrint.MPPPC.TwoDim.Render
+import Text.PrettyPrint.MPPPC.Printable
diff --git a/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators.hs b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators.hs
@@ -0,0 +1,11 @@
+module Text.PrettyPrint.MPPPC.TwoDim.Combinators
+  ( module Text.PrettyPrint.MPPPC.TwoDim.Combinators.Align
+  , module Text.PrettyPrint.MPPPC.TwoDim.Combinators.Flow
+  , module Text.PrettyPrint.MPPPC.TwoDim.Combinators.Layout
+  , module Text.PrettyPrint.MPPPC.TwoDim.Combinators.Prim )
+  where
+
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators.Align
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators.Flow
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators.Layout
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators.Prim
diff --git a/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Align.hs b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Align.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Align.hs
@@ -0,0 +1,42 @@
+module Text.PrettyPrint.MPPPC.TwoDim.Combinators.Align where
+
+import Text.PrettyPrint.MPPPC.TwoDim.Pretty
+
+align :: Alignment -> Alignment -> Int -> Int -> Pretty s t -> Pretty s t
+align ah av r c = Pretty r c . Sub ah av
+
+alignHoriz :: Alignment -> Int -> Pretty s t -> Pretty s t
+alignHoriz a c b = Pretty (rows b) c $ Sub a AlignFirst b
+
+alignVert :: Alignment -> Int -> Pretty s t -> Pretty s t
+alignVert a r b = Pretty r (cols b) $ Sub AlignFirst a b
+
+bottom :: Alignment
+bottom = AlignLast
+
+centerTopLeft :: Alignment
+centerTopLeft = AlignCenterTopLeft
+
+centerTopRight :: Alignment
+centerTopRight = AlignCenterBotRight
+
+left :: Alignment
+left = AlignFirst
+
+moveDown :: Int -> Pretty s t -> Pretty s t
+moveDown n b = alignVert bottom (rows b + n) b
+
+moveLeft :: Int -> Pretty s t -> Pretty s t
+moveLeft n b = alignHoriz left (cols b + n) b
+
+moveRight :: Int -> Pretty s t -> Pretty s t
+moveRight n b = alignHoriz right (cols b + n) b
+
+moveUp :: Int -> Pretty s t -> Pretty s t
+moveUp n b = alignVert top (rows b + n) b
+
+right :: Alignment
+right = AlignLast
+
+top :: Alignment
+top = AlignFirst
diff --git a/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Flow.hs b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Flow.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Flow.hs
@@ -0,0 +1,87 @@
+module Text.PrettyPrint.MPPPC.TwoDim.Combinators.Flow where
+
+import Prelude
+  hiding
+    ( length
+    , reverse
+    , take
+    , unwords
+    , words )
+import qualified Data.List as List
+  ( foldl'
+  , length
+  , map
+  , reverse )
+import qualified Data.List.Split as List
+  ( chunk )
+
+import Text.PrettyPrint.MPPPC.Printable
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators.Align
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators.Layout
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators.Prim
+import Text.PrettyPrint.MPPPC.TwoDim.Pretty
+
+data Word s t = Printable s t =>
+     Word { wLen    :: Int
+          , getWord :: s
+          }
+
+data Line s t = Printable s t =>
+     Line { lLen     :: Int
+          , getWords :: [Word s t]
+          }
+
+data ParaContent s t = Printable s t =>
+     ParaContent { fullLines :: [Line s t]
+                 , lastLine  ::  Line s t
+                 }
+
+data Para s t = Printable s t =>
+     Para { paraWidth   :: Int
+          , paraContent :: ParaContent s t
+          }
+
+para :: Printable s t => Alignment -> Int -> s -> Pretty s t
+para a n t = (\ ss -> mkParaBox a (List.length ss) ss) $ flow n t
+
+columns :: Printable s t => Alignment -> Int -> Int -> s -> [Pretty s t]
+columns a w h t = map (mkParaBox a h) . List.chunk h $ flow w t
+
+mkParaBox :: Printable s t => Alignment -> Int -> [s] -> Pretty s t
+mkParaBox a n = alignVert top n . vcat a . map text
+
+flow :: forall s t. Printable s t => Int -> s -> [s]
+flow n t = List.map (take n)
+         . getLines
+         $ List.foldl' addWordP (emptyPara n) (List.map mkWord . words $ t)
+
+emptyPara :: Printable s t => Int -> Para s t
+emptyPara pw = Para pw (ParaContent [] (Line 0 []))
+
+getLines :: forall s t. Para s t -> [s]
+getLines (Para _ (ParaContent ls l))
+  | lLen l == 0 = process ls
+  | otherwise   = process (l:ls)
+  where
+    process :: [Line s t] -> [s]
+    process = map (unwords . List.reverse . map getWord . getWords) . List.reverse
+
+mkLine :: Printable s t => [Word s t] -> Line s t
+mkLine ws = Line (sum (map wLen ws) + List.length ws - 1) ws
+
+startLine :: Printable s t => Word s t -> Line s t
+startLine = mkLine . (:[])
+
+mkWord :: Printable s t => s -> Word s t
+mkWord w = Word (length w) w
+
+addWordP :: Para s t -> Word s t -> Para s t
+addWordP (Para pw (ParaContent fl l)) w
+  | wordFits pw w l = Para pw (ParaContent fl (addWordL w l))
+  | otherwise       = Para pw (ParaContent (l:fl) (startLine w))
+
+addWordL :: Word s t -> Line s t -> Line s t
+addWordL w (Line len ws) = Line (len + wLen w + 1) (w:ws)
+
+wordFits :: Int -> Word s t -> Line s t -> Bool
+wordFits pw w l = lLen l == 0 || lLen l + wLen w + 1 <= pw
diff --git a/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Layout.hs b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Layout.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Layout.hs
@@ -0,0 +1,42 @@
+module Text.PrettyPrint.MPPPC.TwoDim.Combinators.Layout where
+
+import Data.List
+  ( intersperse )
+
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators.Align
+import Text.PrettyPrint.MPPPC.TwoDim.Combinators.Prim
+import Text.PrettyPrint.MPPPC.TwoDim.Pretty
+
+(<>) :: Pretty s t -> Pretty s t -> Pretty s t
+l <> r = hcat top [l,r]
+
+(<+>) :: Pretty s t -> Pretty s t -> Pretty s t
+l <+> r = hcat top [l, empty 0 1, r]
+
+(//) :: Pretty s t -> Pretty s t -> Pretty s t
+t // b = vcat left [t,b]
+
+(/+/) :: Pretty s t -> Pretty s t -> Pretty s t
+t /+/ b = vcat left [t, empty 1 0, b]
+
+hcat :: Alignment -> [Pretty s t] -> Pretty s t
+hcat a bs = Pretty h w (Row $ map (alignVert a h) bs)
+  where h = maximum . (0:) . map rows $ bs
+        w = sum . map cols $ bs
+
+hsep :: Int -> Alignment -> [Pretty s t] -> Pretty s t
+hsep sep a bs = punctuateH a (empty 0 sep) bs
+
+vcat :: Alignment -> [Pretty s t] -> Pretty s t
+vcat a bs = Pretty h w (Col $ map (alignHoriz a w) bs)
+  where h = sum . map rows $ bs
+        w = maximum . (0:) . map cols $ bs
+
+vsep :: Int -> Alignment -> [Pretty s t] -> Pretty s t
+vsep sep a = punctuateV a (empty sep 0)
+
+punctuateH :: Alignment -> Pretty s t -> [Pretty s t] -> Pretty s t
+punctuateH a p = hcat a . intersperse p
+
+punctuateV :: Alignment -> Pretty s t -> [Pretty s t] -> Pretty s t
+punctuateV a p = vcat a . intersperse p
diff --git a/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Prim.hs b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Prim.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/TwoDim/Combinators/Prim.hs
@@ -0,0 +1,19 @@
+module Text.PrettyPrint.MPPPC.TwoDim.Combinators.Prim where
+
+import Prelude
+  hiding
+    ( length )
+import Text.PrettyPrint.MPPPC.Printable
+import Text.PrettyPrint.MPPPC.TwoDim.Pretty
+
+empty :: Int -> Int -> Pretty s t
+empty r c = Pretty r c Blank
+
+char :: Printable s t => t -> Pretty s t
+char c = Pretty 1 1 $ Text $ singleton c
+
+null :: Pretty s t
+null = empty 0 0
+
+text :: Printable s t => s -> Pretty s t
+text t = Pretty 1 (length t) (Text t)
diff --git a/src/Text/PrettyPrint/MPPPC/TwoDim/Display.hs b/src/Text/PrettyPrint/MPPPC/TwoDim/Display.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/TwoDim/Display.hs
@@ -0,0 +1,15 @@
+module Text.PrettyPrint.MPPPC.TwoDim.Display where
+
+import System.IO
+  ( Handle
+  , stdout )
+
+import Text.PrettyPrint.MPPPC.TwoDim.Pretty
+import Text.PrettyPrint.MPPPC.TwoDim.Render
+import Text.PrettyPrint.MPPPC.Printable
+
+hPutPretty :: Printable s t => Handle -> Pretty s t -> IO ()
+hPutPretty h = hPutSeq h . renderPretty
+
+putPretty :: Printable s t => Pretty s t -> IO ()
+putPretty = hPutPretty stdout
diff --git a/src/Text/PrettyPrint/MPPPC/TwoDim/Pretty.hs b/src/Text/PrettyPrint/MPPPC/TwoDim/Pretty.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/TwoDim/Pretty.hs
@@ -0,0 +1,22 @@
+module Text.PrettyPrint.MPPPC.TwoDim.Pretty where
+
+import Text.PrettyPrint.MPPPC.Printable
+
+data Alignment
+  = AlignFirst
+  | AlignCenterTopLeft
+  | AlignCenterBotRight
+  | AlignLast
+
+data Content s t
+  = Blank
+  | Printable s t => Text s
+  | Row [Pretty s t]
+  | Col [Pretty s t]
+  | Sub Alignment Alignment (Pretty s t)
+
+data Pretty s t =
+     Pretty { rows    :: Int
+            , cols    :: Int
+            , content :: Content s t
+            }
diff --git a/src/Text/PrettyPrint/MPPPC/TwoDim/Render.hs b/src/Text/PrettyPrint/MPPPC/TwoDim/Render.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/PrettyPrint/MPPPC/TwoDim/Render.hs
@@ -0,0 +1,106 @@
+module Text.PrettyPrint.MPPPC.TwoDim.Render where
+
+import Prelude
+  hiding
+    ( head
+    , length
+    , replicate
+    , reverse
+    , splitAt
+    , tail
+    , unlines )
+import Control.Arrow
+  ( (***)
+  , first )
+import qualified Data.List as List
+  ( length
+  , replicate
+  , reverse
+  , splitAt )
+
+import Text.PrettyPrint.MPPPC.Printable
+import Text.PrettyPrint.MPPPC.TwoDim.Pretty
+
+blanks :: Printable s t => Int -> s
+blanks = flip replicate $ singleton tokSpace
+
+renderPretty :: Printable s t => Pretty s t -> s
+renderPretty = unlines . renderPrettyLines
+
+renderPrettyLines :: Printable s t => Pretty s t -> [s]
+renderPrettyLines (Pretty r c Blank)         = resizePretty r c [singleton tokSpace]
+renderPrettyLines (Pretty r c (Text t))      = resizePretty r c [t]
+renderPrettyLines (Pretty r c (Row bs))      = resizePretty r c
+                                             . merge
+                                             . map (renderPrettyWithRows r)
+                                             $ bs
+  where
+    merge = foldr (zipWith append) (repeat seqEmpty)
+renderPrettyLines (Pretty r c (Col bs))      = resizePretty r c
+                                             . concatMap (renderPrettyWithCols c)
+                                             $ bs
+renderPrettyLines (Pretty r c (Sub ha va b)) = resizePrettyAligned r c ha va
+                                             . renderPrettyLines
+                                             $ b
+
+renderPrettyWithRows :: Printable s t => Int -> Pretty s t -> [s]
+renderPrettyWithRows r b = renderPrettyLines $ b { rows = r }
+
+renderPrettyWithCols :: Printable s t => Int -> Pretty s t -> [s]
+renderPrettyWithCols c b = renderPrettyLines $ b { cols = c }
+
+resizePretty :: Printable s t => Int -> Int -> [s] -> [s]
+resizePretty r c =      takePadList (blanks c)           r
+                 . map (takePad     (singleton tokSpace) c)
+
+resizePrettyAligned :: Printable s t => Int -> Int -> Alignment -> Alignment -> [s] -> [s]
+resizePrettyAligned r c ha va =      takePadAlignList va (blanks c)           r
+                              . map (takePadAlign     ha (singleton tokSpace) c)
+
+takePad :: Printable s t => s -> Int -> s -> s
+takePad _ n _  | n <= 0    = seqEmpty
+takePad b n xs | isNull xs = replicate n b
+takePad b n xs             = head xs `cons` takePad b (n-1) (tail xs)
+
+takePadList :: Printable s t => s -> Int -> [s] -> [s]
+takePadList _ n _  | n <= 0 = []
+takePadList b n []          = List.replicate n b
+takePadList b n (x:xs)      = x : takePadList b (n-1) xs
+
+takePadAlign :: Printable s t => Alignment -> s -> Int -> s -> s
+takePadAlign c b n = glue
+                   . (takePad b (numRev c n) *** takePad b (numFwd c n))
+                   . split
+  where
+    split t                      = first reverse
+                                 . splitAt (numRev c (length t))
+                                 $ t
+    glue                         = uncurry append
+                                 . first reverse
+    numFwd AlignFirst          m =  m
+    numFwd AlignLast           _ =  0
+    numFwd AlignCenterTopLeft  m =  m    `div` 2
+    numFwd AlignCenterBotRight m = (m+1) `div` 2
+    numRev AlignFirst          _ =  0
+    numRev AlignLast           m =  m
+    numRev AlignCenterTopLeft  m = (m+1) `div` 2
+    numRev AlignCenterBotRight m =  m    `div` 2
+
+takePadAlignList :: Printable s t => Alignment -> s -> Int -> [s] -> [s]
+takePadAlignList c b n = glue
+                       . (takePadList b (numRev c n) *** takePadList b (numFwd c n))
+                       . split
+  where
+    split t                      = first List.reverse
+                                 . List.splitAt (numRev c (List.length t))
+                                 $ t
+    glue                         = uncurry (++)
+                                 . first List.reverse
+    numFwd AlignFirst          m =  m
+    numFwd AlignLast           _ =  0
+    numFwd AlignCenterTopLeft  m =  m    `div` 2
+    numFwd AlignCenterBotRight m = (m+1) `div` 2
+    numRev AlignFirst          _ =  0
+    numRev AlignLast           m =  m
+    numRev AlignCenterTopLeft  m = (m+1) `div` 2
+    numRev AlignCenterBotRight m =  m    `div` 2
