diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,35 @@
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+
+## [Unreleased]
+
+
+## [0.9.0.0] - 2020-04-10
+
+### Added
+
+- Add `Text.Layout.Table.Cell.Formatted`. A `Cell` instance is provided that
+  enables formatting text correctly with inline text formatting commands.
+- Add helpers to generate tables for Pandoc in the module
+  `Text.Layout.Table.Pandoc`.
+- Add `Cell` type class: This enables using different input string types.
+- Add `StringBuilder` type class. This enables generating output in different
+  ways.
+- Add test case for left-biased trim.
+
+### Changed
+
+- Change input type of a lot of functions to use the `Cell` type class. This
+  might break some code but will require only a type annotation to fix.
+- Rework and simplify formatting functions with `Cell` and `StringBuilder`. This
+  includes improvements in test coverage.
+- Reorganize module structure:
+    * Modules of types used for specification do now start with
+      `Text.Layout.Table.Spec.`.
+    * Move a lot of the code in `Text.Layout.Table` into sub-modules.
+
+### Fixed
+
+- Fix an error with text justification for lines that contain only one word and
+  add a test case. (#6)
+- Fix an error where cut marks where applied wrongly on the right side.
+
diff --git a/src/Test.hs b/src/Test.hs
--- a/src/Test.hs
+++ b/src/Test.hs
@@ -1,7 +1,5 @@
 module Main where
 
-import Control.Monad
-
 import Text.Layout.Table
 
 main :: IO ()
diff --git a/src/Text/Layout/Table.hs b/src/Text/Layout/Table.hs
--- a/src/Text/Layout/Table.hs
+++ b/src/Text/Layout/Table.hs
@@ -62,7 +62,7 @@
       -- ** Headers
     , HeaderColSpec
     , headerColumn
-    , Header
+    , HeaderSpec
     , fullH
     , titlesH
 
@@ -111,25 +111,31 @@
 -- TODO AlignSpec:   multiple alignment points - useful?
 -- TODO RowGroup:    optional: vertical group labels
 -- TODO RowGroup:    optional: provide extra layout for a RowGroup
--- TODO ColModInfo:  provide a special version of ensureWidthOfCMI to force header visibility
 -- TODO ColSpec:     add some kind of combinator to construct ColSpec values (e.g. via Monoid, see optparse-applicative)
 
-import qualified Control.Arrow                                   as A
 import           Data.List
-import           Data.Maybe
-import           Data.Semigroup
 import           Data.Default.Class
-import           Data.Default.Instances.Base                          ()
+import           Data.Default.Instances.Base                 ()
 
+import           Text.Layout.Table.Cell
 import           Text.Layout.Table.Justify
-import           Text.Layout.Table.Style
-import           Text.Layout.Table.Position.Internal
-import           Text.Layout.Table.Primitives.AlignSpec.Internal
+import           Text.Layout.Table.Primitives.AlignInfo
 import           Text.Layout.Table.Primitives.Basic
-import           Text.Layout.Table.Primitives.Column
-import           Text.Layout.Table.Primitives.LenSpec.Internal
-import           Text.Layout.Table.Primitives.Occurence
-import           Text.Layout.Table.Internal
+import           Text.Layout.Table.Primitives.ColumnModifier
+import           Text.Layout.Table.Primitives.Header
+import           Text.Layout.Table.Primitives.Table
+import           Text.Layout.Table.Spec.AlignSpec
+import           Text.Layout.Table.Spec.ColSpec
+import           Text.Layout.Table.Spec.CutMark
+import           Text.Layout.Table.Spec.HeaderColSpec
+import           Text.Layout.Table.Spec.HeaderSpec
+import           Text.Layout.Table.Spec.LenSpec
+import           Text.Layout.Table.Spec.OccSpec
+import           Text.Layout.Table.Spec.Position
+import           Text.Layout.Table.Spec.RowGroup
+import           Text.Layout.Table.Spec.Util
+import           Text.Layout.Table.StringBuilder
+import           Text.Layout.Table.Style
 import           Text.Layout.Table.Vertical
 
 -------------------------------------------------------------------------------
@@ -154,301 +160,20 @@
 fixedLeftCol i = fixedCol i left
 
 -------------------------------------------------------------------------------
--- Single-cell layout functions.
--------------------------------------------------------------------------------
-
--- | Assume the given length is greater or equal than the length of the 'String'
--- passed. Pads the given 'String' accordingly using the position specification.
---
--- >>> pad left 10 "foo"
--- "foo       "
---
-pad :: Position o -> Int -> String -> String
-pad p = case p of
-    Start  -> fillRight
-    Center -> fillCenter
-    End    -> fillLeft
-
--- | If the given text is too long, the 'String' will be shortened according to
--- the position specification. Adds cut marks to indicate that the column has
--- been trimmed in length, otherwise it behaves like 'pad'.
---
--- >>> trimOrPad left (singleCutMark "..") 10 "A longer text."
--- "A longer.."
---
-trimOrPad :: Position o -> CutMark -> Int -> String -> String
-trimOrPad p = case p of
-    Start  -> fitRightWith
-    Center -> fitCenterWith
-    End    -> fitLeftWith
-
--- | Align a 'String' by first locating the position to align with and then
--- padding on both sides. If no such position is found, it will align it such
--- that it gets aligned before that position.
---
--- >>> let { os = predOccSpec (== '.') ; ai = deriveAlignInfo os "iiii.fff" } in align os ai <$> ["1.5", "30", ".25"]
--- ["   1.5  ","  30    ","    .25 "]
---
--- This function assumes that the given 'String' fits the 'AlignInfo'. Thus:
---
--- > ai <> deriveAlignInfo s = ai
---
-align :: OccSpec -> AlignInfo -> String -> String
-align oS (AlignInfo l r) s = case splitAtOcc oS s of
-    (ls, rs) -> fillLeft l ls ++ case rs of
-        -- No alignment character found.
-        [] -> spaces r
-        _  -> fillRight r rs
-
--- | Aligns a 'String' using a fixed width, fitting it to the width by either
--- filling or cutting while respecting the alignment.
-alignFixed :: Position o -> CutMark -> Int -> OccSpec -> AlignInfo -> String -> String
-alignFixed _ cms 0 _  _                  _               = ""
-alignFixed _ cms 1 _  _                  s@(_ : (_ : _)) = applyMarkLeftWith cms " "
-alignFixed p cms i oS ai@(AlignInfo l r) s               =
-    let n = l + r - i
-    in case splitAtOcc oS s of
-        (ls, rs) -> case p of
-            Start  ->
-                let remRight = r - n
-                in if remRight < 0
-                   then fitRight (l + remRight) $ fillLeft l ls
-                   else fitRight (l + remRight) $ fillLeft l ls ++ rs
-            End    ->
-                let remLeft = l - n
-                in if remLeft < 0
-                   then fitLeft (r + remLeft) $ fillRight r rs
-                   else fitLeft (r + remLeft) $ ls ++ fillRight r rs
-            Center ->
-                {-
-                   This is really complicated, maybe there can be found
-                   something better.
-                  
-                   First case l > r:
-                  
-                         l
-                   |<----'----->|
-                   |<-----------x----->|
-                                |--.-->|
-                                    r
-                        c1 = (l + r) div 2
-                        |
-                   |<---'--->|<---.--->|
-                             .    |
-                             .    c2 = c1 + (l + r) mod 2
-                             .
-                             .  d2 = d1 + i mod 2
-                             .  |
-                       |<-.->|<-'-->|
-                          |
-                          d1 = i div 2
-                  
-                       |<----.----->|
-                             i
-                                 
-                   needed length on the left side:
-                       l - c1 + d1
-                  
-                   needed length on the right side:
-                       d2 - (l - c1)
-                  
-                   Second case l < r:
-                   
-                  
-                       l
-                   |<--'-->|
-                   |<------x---------->|
-                           |<----.---->|
-                                 r
-                        c1 = (l + r) div 2
-                        |
-                   |<---'--->|<---.--->|
-                             .    |
-                             .    c2 = c1 + (l + r) mod 2
-                             .
-                             .  d2 = d1 + i mod 2
-                             .  |
-                       |<-.->|<-'-->|
-                          |
-                          d1 = i div 2
-                  
-                       |<----.----->|
-                             i
-                                 
-                   needed length on the left side:
-                       d1 - (r - c2)
-                  
-                   needed length on the right side:
-                       (c1 - l) + d2
-                -}
-                let (c, remC)        = (l + r) `divMod` 2
-                    (d, remD)        = i `divMod` 2
-                    d2               = d + remD
-                    c2               = c + remC
-                    -- Note: widthL and widthR can be negative if there is no
-                    -- width left and we need to further trim into the other
-                    -- side.
-                    (widthL, widthR) = if l > c
-                                       then (l - c2 + d, d2 - (l - c2))
-                                       else (d - (r - c), (c2 - l) + d2)
-                    lenL             = length ls
-                    lenR             = length rs
-
-                    toCutLfromR      = negate $ min 0 widthL
-                    toCutRfromL      = max 0 $ negate widthR
-                    (markL, funL)    = if lenL > widthL
-                                       then ( applyMarkLeft
-                                            , take (widthL - toCutRfromL) . drop (lenL - widthL)
-                                            )
-                                       else ( id
-                                            , fillLeft (widthL - toCutRfromL) . take (lenL - toCutRfromL)
-                                            )
-                    (markR, funR)    = if lenR > widthR
-                                       then (applyMarkRight, take widthR)
-                                       else (id            , fillRight widthR)
-                in markL $ markR $ funL ls ++ drop toCutLfromR (funR rs)
-  where
-    fitRight       = fitRightWith cms
-    fitLeft        = fitLeftWith cms
-    applyMarkRight = applyMarkRightWith cms
-    applyMarkLeft  = applyMarkLeftWith cms
-
--- | Specifies how a column should be modified. Values of this type are derived
--- in a traversal over the input columns by using 'deriveColModInfos'. Finally,
--- 'columnModifier' will interpret them and apply the appropriate modification
--- function to the cells of the column.
-data ColModInfo
-    = FillAligned OccSpec AlignInfo
-    | FillTo Int
-    | FitTo Int (Maybe (OccSpec, AlignInfo))
-
--- | Private show function.
-showCMI :: ColModInfo -> String
-showCMI cmi = case cmi of
-    FillAligned oS ai -> "FillAligned .. " ++ showAI ai
-    FillTo i          -> "FillTo " ++ show i
-    FitTo i _         -> "FitTo " ++ show i ++ ".."
-
--- | Get the exact width of a 'ColModInfo' after applying it with
--- 'columnModifier'.
-widthCMI :: ColModInfo -> Int
-widthCMI cmi = case cmi of
-    FillAligned _ ai -> widthAI ai
-    FillTo maxLen    -> maxLen
-    FitTo lim _      -> lim
-
--- | Remove alignment from a 'ColModInfo'. This is used to change alignment of
--- headers while using the combined width information.
-unalignedCMI :: ColModInfo -> ColModInfo
-unalignedCMI cmi = case cmi of
-    FillAligned _ ai -> FillTo $ widthAI ai
-    FitTo i _        -> FitTo i Nothing
-    _                -> cmi
-
--- | Ensures that the modification provides a minimum width but only if it is
--- not limited.
-ensureWidthCMI :: Int -> Position H -> ColModInfo -> ColModInfo
-ensureWidthCMI w pos cmi = case cmi of
-    FillAligned oS ai@(AlignInfo lw rw) ->
-        let neededW = w - widthAI ai
-        in if neededW <= 0
-           then cmi
-           else FillAligned oS $ case pos of
-               Start  -> AlignInfo lw (rw + neededW)
-               End    -> AlignInfo (lw + neededW) rw
-               Center -> let (q, r) = neededW `divMod` 2 
-                            in AlignInfo (q + lw) (q + rw + r)
-    FillTo maxLen                     -> FillTo (max maxLen w)
-    _                                 -> cmi
-
--- | Ensures that the given 'String' will fit into the modified columns.
-ensureWidthOfCMI :: String -> Position H -> ColModInfo -> ColModInfo
-ensureWidthOfCMI = ensureWidthCMI . length
-
--- | Generates a function which modifies a given cell according to
--- 'Text.Layout.Table.Position.Position', 'CutMark' and 'ColModInfo'. This is
--- used to modify a single cell of column to bring all cells of column to the
--- same width.
-columnModifier :: Position H -> CutMark -> ColModInfo -> (String -> String)
-columnModifier pos cms lenInfo = case lenInfo of
-    FillAligned oS ai -> align oS ai
-    FillTo maxLen     -> pad pos maxLen
-    FitTo lim mT      ->
-        maybe (trimOrPad pos cms lim) (uncurry $ alignFixed pos cms lim) mT
-
--- TODO factor out
--- | Specifies the length before and after an alignment position (including the
--- alignment character).
-data AlignInfo = AlignInfo Int Int
-
--- | Private show function.
-showAI :: AlignInfo -> String
-showAI (AlignInfo l r) = "AlignInfo " ++ show l ++ " " ++ show r
-
--- | The column width when using the 'AlignInfo'.
-widthAI :: AlignInfo -> Int
-widthAI (AlignInfo l r) = l + r
-
--- | Produce an 'AlignInfo' that is wide enough to hold inputs of both given
--- 'AlignInfo's.
-instance Semigroup AlignInfo where
-    AlignInfo ll lr <> AlignInfo rl rr = AlignInfo (max ll rl) (max lr rr)
-
-instance Monoid AlignInfo where
-    mempty = AlignInfo 0 0
-
--- | Derive the 'ColModInfo' by using layout specifications and the actual cells
--- of a column.
-deriveColModInfos :: [(LenSpec, AlignSpec)] -> [Row String] -> [ColModInfo]
-deriveColModInfos specs = zipWith ($) (fmap fSel specs) . transpose
-  where
-    fSel (lenSpec, alignSpec) = case alignSpec of
-        NoAlign     -> let fitTo i             = const $ FitTo i Nothing
-                           expandUntil f i max = if f (max <= i)
-                                                 then FillTo max
-                                                 else fitTo i max
-                           fun                 = case lenSpec of
-                               Expand        -> FillTo
-                               Fixed i       -> fitTo i
-                               ExpandUntil i -> expandUntil id i
-                               FixedUntil i  -> expandUntil not i
-                       in fun . maximum . map length
-        AlignOcc oS -> let fitToAligned i     = FitTo i . Just . (,) oS
-                           fillAligned        = FillAligned oS
-                           expandUntil f i ai = if f (widthAI ai <= i)
-                                                then fillAligned ai
-                                                else fitToAligned i ai
-                           fun                = case lenSpec of
-                               Expand        -> fillAligned
-                               Fixed i       -> fitToAligned i
-                               ExpandUntil i -> expandUntil id i
-                               FixedUntil i  -> expandUntil not i
-                        in fun . foldMap (deriveAlignInfo oS)
-
--- | Generate the 'AlignInfo' of a cell by using the 'OccSpec'.
-deriveAlignInfo :: OccSpec -> String -> AlignInfo
-deriveAlignInfo occSpec s =
-    AlignInfo <$> length . fst <*> length . snd $ splitAtOcc occSpec s
-
--------------------------------------------------------------------------------
 -- Basic layout
 -------------------------------------------------------------------------------
 
 -- | Modifies cells according to the column specification.
-grid :: [ColSpec] -> [Row String] -> [Row String]
-grid specs tab = zipWith ($) cmfs <$> tab
-  where
-    -- | The column modification function for each column.
-    cmfs  = zipWith (uncurry columnModifier) (map (position A.&&& cutMark) specs) cmis
-    cmis  = deriveColModInfos (map (lenSpec A.&&& alignSpec) specs) tab
+grid :: Cell a => [ColSpec] -> [Row a] -> [Row String]
+grid specs tab = zipWith ($) (deriveColMods specs tab) <$> tab
 
 -- | Behaves like 'grid' but produces lines by joining with whitespace.
-gridLines :: [ColSpec] -> [Row String] -> [String]
+gridLines :: Cell a => [ColSpec] -> [Row a] -> [String]
 gridLines specs = fmap unwords . grid specs
 
 -- | Behaves like 'gridLines' but produces a string by joining with the newline
 -- character.
-gridString :: [ColSpec] -> [Row String] -> String
+gridString :: Cell a => [ColSpec] -> [Row a] -> String
 gridString specs = concatLines . gridLines specs
 
 -------------------------------------------------------------------------------
@@ -472,38 +197,22 @@
 
 -- | Create a 'RowGroup' by aligning the columns vertically. The position is
 -- specified for each column.
-colsG :: [Position V] -> [Col String] -> RowGroup
+colsG :: Monoid a => [Position V] -> [Col a] -> RowGroup a
 colsG ps = rowsG . colsAsRows ps
 
 -- | Create a 'RowGroup' by aligning the columns vertically. Each column uses
 -- the same vertical positioning.
-colsAllG :: Position V -> [Col String] -> RowGroup
+colsAllG :: Monoid a => Position V -> [Col a] -> RowGroup a
 colsAllG p = rowsG . colsAsRowsAll p
 
--- | Specifies a header.
-data Header
-    = Header [HeaderColSpec] [String]
-    | NoHeader
-
--- | By the default the header is not shown.
-instance Default Header where
-    def = NoHeader
-
--- | Specify a header column for every title.
-fullH :: [HeaderColSpec] -> [String] -> Header
-fullH = Header
-
--- | Use titles with the default header column specification.
-titlesH :: [String] -> Header
-titlesH = fullH $ repeat def
-
 -- | Layouts a pretty table with an optional header. Note that providing fewer
 -- layout specifications than columns or vice versa will result in not showing
 -- the redundant ones.
-tableLines :: [ColSpec]  -- ^ Layout specification of columns
+tableLines :: Cell a
+           => [ColSpec]  -- ^ Layout specification of columns
            -> TableStyle -- ^ Visual table style
-           -> Header     -- ^ Optional header details
-           -> [RowGroup] -- ^ Rows which form a cell together
+           -> HeaderSpec -- ^ Optional header details
+           -> [RowGroup a] -- ^ Rows which form a cell together
            -> [String]
 tableLines specs TableStyle { .. } header rowGroups =
     topLine : addHeaderLines (rowGroupLines ++ [bottomLine])
@@ -511,20 +220,9 @@
     -- Helpers for horizontal lines that will put layout characters arround and
     -- in between a row of the pre-formatted grid.
 
-    -- | Draw a horizontal line that will use the delimiters around 'cols'
-    -- appropriately and visually separate by 'hSpace'.
-    hLineDetail hSpace delimL delimM delimR cols
-                  = intercalate [hSpace] $ [delimL] : intersperse [delimM] cols ++ [[delimR]]
-
-    -- | A simplified version of 'hLineDetail' that will use the same delimiter
-    -- for everything.
-    hLine hSpace delim
-                  = hLineDetail hSpace delim delim delim
-
     -- | Generate columns filled with 'sym'.
     fakeColumns sym
-                  = map (`replicate` sym) colWidths
-
+                  = map (`replicateCharB` sym) colWidths
 
     -- Horizontal seperator lines that occur in a table.
     topLine       = hLineDetail realTopH realTopL realTopC realTopR $ fakeColumns realTopH
@@ -533,29 +231,28 @@
     headerSepLine = hLineDetail headerSepH headerSepLC headerSepC headerSepRC $ fakeColumns headerSepH
 
     -- Vertical content lines
-    rowGroupLines = intercalate [groupSepLine] $ map (map (hLine ' ' groupV) . applyRowMods . rows) rowGroups
+    rowGroupLines =
+        intercalate [groupSepLine] $ map (map (hLineContent groupV) . applyRowMods . rows) rowGroups
 
     -- Optional values for the header
     (addHeaderLines, fitHeaderIntoCMIs, realTopH, realTopL, realTopC, realTopR)
                   = case header of
-        Header headerColSpecs hTitles
-                 ->
-            let headerLine    = hLine ' ' headerV (zipWith ($) headerRowMods hTitles)
-                headerRowMods = zipWith3 (\(HeaderColSpec pos optCutMark) cutMark ->
-                                              columnModifier pos $ fromMaybe cutMark optCutMark
-                                         )
+        HeaderHS headerColSpecs hTitles
+               ->
+            let headerLine    = hLineContent headerV (zipWith ($) headerRowMods hTitles)
+                headerRowMods = zipWith3 headerCellModifier
                                          headerColSpecs
                                          cMSs
-                                         (map unalignedCMI cMIs)
+                                         cMIs
             in
             ( (headerLine :) . (headerSepLine :)
-            , zipWith ($) $ zipWith ($) (map ensureWidthOfCMI hTitles) posSpecs
+            , fitTitlesCMI hTitles posSpecs
             , headerTopH
             , headerTopL
             , headerTopC
             , headerTopR
             )
-        NoHeader ->
+        NoneHS ->
             ( id
             , id
             , groupTopH
@@ -568,15 +265,15 @@
     posSpecs      = map position specs
     applyRowMods  = map (zipWith ($) rowMods)
     rowMods       = zipWith3 columnModifier posSpecs cMSs cMIs
-    cMIs          = fitHeaderIntoCMIs $ deriveColModInfos (map (lenSpec A.&&& alignSpec) specs)
-                                        $ concatMap rows rowGroups
+    cMIs          = fitHeaderIntoCMIs $ deriveColModInfos' specs $ concatMap rows rowGroups
     colWidths     = map widthCMI cMIs
 
 -- | Does the same as 'tableLines', but concatenates lines.
-tableString :: [ColSpec]  -- ^ Layout specification of columns
+tableString :: Cell a
+            => [ColSpec]  -- ^ Layout specification of columns
             -> TableStyle -- ^ Visual table style
-            -> Header     -- ^ Optional header details
-            -> [RowGroup] -- ^ Rows which form a cell together
+            -> HeaderSpec -- ^ Optional header details
+            -> [RowGroup a] -- ^ Rows which form a cell together
             -> String
 tableString specs style header rowGroups = concatLines $ tableLines specs style header rowGroups
 
diff --git a/src/Text/Layout/Table/Cell.hs b/src/Text/Layout/Table/Cell.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Cell.hs
@@ -0,0 +1,259 @@
+{-# LANGUAGE FlexibleInstances #-}
+module Text.Layout.Table.Cell where
+
+import Text.Layout.Table.Primitives.AlignInfo
+import Text.Layout.Table.Spec.CutMark
+import Text.Layout.Table.Spec.OccSpec
+import Text.Layout.Table.Spec.Position
+import Text.Layout.Table.StringBuilder
+
+-- | Types that can be shortened, measured for visible characters, and turned
+-- into a 'StringBuilder'.
+class Cell a where
+    -- Preprocessing functions:
+
+    -- | Drop a number of characters from the left side. Treats negative numbers
+    -- as zero.
+    dropLeft :: Int -> a -> a
+    dropLeft n = dropBoth n 0
+
+    -- | Drop a number of characters from the right side. Treats negative
+    -- numbers as zero.
+    dropRight :: Int -> a -> a
+    dropRight = dropBoth 0
+
+    -- | Drop characters from both sides. Treats negative numbers as zero.
+    dropBoth :: Int -> Int -> a -> a
+    dropBoth l r = dropRight r . dropLeft l
+
+    -- | Returns the length of the visible characters as displayed on the
+    -- output medium.
+    visibleLength :: a -> Int
+
+    -- | Measure the preceeding and following characters for a position where
+    -- the predicate matches.
+    measureAlignment :: (Char -> Bool) -> a -> AlignInfo
+
+    -- | Insert the contents into a 'StringBuilder'.
+    buildCell :: StringBuilder b => a -> b
+
+    {-# MINIMAL visibleLength, measureAlignment, buildCell, (dropBoth | (dropLeft, dropRight))  #-}
+
+instance Cell String where
+    dropLeft = drop
+    dropRight n = reverse . drop n . reverse
+    visibleLength = length
+    measureAlignment p xs = case break p xs of
+        (ls, rs) -> AlignInfo (length ls) $ case rs of
+            []      -> Nothing
+            _ : rs' -> Just $ length rs'
+
+    buildCell = stringB
+
+remSpacesB :: (Cell a, StringBuilder b) => Int -> a -> b
+remSpacesB n c = remSpacesB' n $ visibleLength c
+
+remSpacesB' :: StringBuilder b => Int -> Int -> b
+remSpacesB' n k = spacesB $ n - k
+
+-- | Fill the right side with spaces if necessary.
+fillRight :: (Cell a, StringBuilder b) => Int -> a -> b
+fillRight n c = buildCell c <> remSpacesB n c
+
+-- | Fill both sides with spaces if necessary.
+fillCenter :: (Cell a, StringBuilder b) => Int -> a -> b
+fillCenter n c = spacesB q <> buildCell c <> spacesB (q + r)
+  where
+    missing = n - visibleLength c
+    (q, r)  = missing `divMod` 2
+
+-- | Fill the left side with spaces if necessary.
+fillLeft :: (Cell a, StringBuilder b) => Int -> a -> b
+fillLeft n c = remSpacesB n c <> buildCell c
+
+-- | Assume the given length is greater or equal than the length of the cell
+-- passed. Pads the given cell accordingly using the position specification.
+--
+-- >>> pad left 10 "foo" :: String
+-- "foo       "
+--
+pad :: (Cell a, StringBuilder b) => Position o -> Int -> a -> b
+pad p = case p of
+    Start  -> fillRight
+    Center -> fillCenter
+    End    -> fillLeft
+
+-- | If the given text is too long, the 'String' will be shortened according to
+-- the position specification. Adds cut marks to indicate that the column has
+-- been trimmed in length, otherwise it behaves like 'pad'.
+--
+-- >>> trimOrPad left (singleCutMark "..") 10 "A longer text." :: String
+-- "A longer.."
+--
+trimOrPad :: (Cell a, StringBuilder b) => Position o -> CutMark -> Int -> a -> b
+trimOrPad p cm n c = case compare (visibleLength c) n of
+    LT -> pad p n c
+    EQ -> buildCell c
+    GT -> trim p cm n c
+
+-- | Trim a cell based on the position. Preconditions that require to be met
+-- (otherwise the function will produce garbage):
+-- prop> visibleLength c > n
+trim :: (Cell a, StringBuilder b) => Position o -> CutMark -> Int -> a -> b
+trim p cm n c = case p of
+    Start  -> buildCell (dropRight (cutLen + rightLen) c) <> buildCell (rightMark cm)
+    Center -> case cutLen `divMod` 2 of
+        (0, 1) -> buildCell (leftMark cm) <> buildCell (dropLeft (1 + leftLen) c)
+        (q, r) -> if n > leftLen + rightLen
+                  then buildCell (leftMark cm) <> buildCell (dropBoth (leftLen + q + r) (rightLen + q) c)
+                       <> buildCell (rightMark cm)
+                  else case n `divMod` 2 of
+                      (qn, rn) -> buildCell (take qn $ leftMark cm)
+                                  <> buildCell (drop (rightLen - qn - rn) $ rightMark cm)
+    End    -> buildCell (leftMark cm) <> buildCell (dropLeft (leftLen + cutLen) c)
+  where
+    leftLen = length $ leftMark cm
+    rightLen = length $ rightMark cm
+
+    cutLen = visibleLength c - n
+
+-- | Align a cell by first locating the position to align with and then padding
+-- on both sides. If no such position is found, it will align it such that it
+-- gets aligned before that position.
+--
+-- >>> let { os = predOccSpec (== '.') ; ai = deriveAlignInfo os "iiii.fff" }
+-- >>> in align os ai <$> ["1.5", "30", ".25"] :: [String]
+-- ["   1.5  ","  30    ","    .25 "]
+--
+-- This function assumes that the given 'String' fits the 'AlignInfo'. Thus:
+--
+-- prop> ai <> deriveAlignInfo s = ai
+--
+align :: (Cell a, StringBuilder b) => OccSpec -> AlignInfo -> a -> b
+align oS (AlignInfo ln optRN) c = case measureAlignment (predicate oS) c of
+    AlignInfo lk optRK -> remSpacesB' ln lk <> buildCell c <> remSpacesB' (maybe 0 succ optRN) (maybe 0 succ optRK)
+
+data CutAction
+    = FillCA Int
+    | CutCA Int
+    | NoneCA
+    deriving (Eq, Show)
+
+surplusSpace :: CutAction -> Int
+surplusSpace ca = case ca of
+    CutCA n  -> negate n
+    FillCA n -> n
+    _        -> 0
+
+determineCutAction :: Int -> Int -> CutAction
+determineCutAction requiredW actualW = case compare requiredW actualW of
+    LT -> CutCA $ actualW - requiredW
+    EQ -> NoneCA
+    GT -> FillCA $ requiredW - actualW
+
+data CutInfo
+    -- | Apply a cut action to each side.
+    = SidesCI CutAction CutAction
+    -- | Apply a mark to a whitespace string pointing to the left.
+    | MarkLeftCI
+    -- | Apply a mark to a whitespace string pointing to the right.
+    | MarkRightCI
+    deriving (Eq, Show)
+
+-- | Compares the view range, that represents the visible part, with the cell
+-- range, which is the position of the cell relative to the alignment, and
+-- determines the actions that should be performed.
+determineCuts :: Int -> Int -> Int -> Int -> CutInfo
+determineCuts vl vr cl cr
+    | vr <= cl  = MarkRightCI
+    | cr <= vl  = MarkLeftCI
+    | otherwise = SidesCI (determineCutAction cl vl) (determineCutAction vr cr)
+
+-- | If the amount to be cut is bigger than the cell length then any missing
+-- amount is taken away from any remaining padding.
+spacesAfterCut :: StringBuilder b => CutAction -> Int -> Int -> b
+spacesAfterCut ca cellLen cutAmount = spacesB $ s + min r 0
+  where
+    s = surplusSpace ca
+    r = cellLen - cutAmount
+
+applyCutInfo
+    :: (Cell a, StringBuilder b)
+    => CutInfo
+    -> CutMark
+    -> Int
+    -> Int
+    -> a
+    -> b
+applyCutInfo ci cm availSpace cellLen c = case ci of
+    -- The cuts might interfere with each other. Properly distribute available
+    -- length between both cut marks.
+    SidesCI (CutCA lCut) (CutCA rCut) ->
+        let (q, r) = availSpace `divMod` 2
+        in applyLeftMark q
+           <> buildCell (dropBoth (lCut + leftLen) (rCut + rightLen) c)
+           <> applyRightMark (q + r)
+    -- The left cut might need some of the right padding.
+    SidesCI (CutCA lCut) rCA          ->
+        applyLeftMark availSpace
+        <> buildCell (dropLeft (lCut + leftLen) c)
+        <> spacesAfterCut rCA cellLen (lCut + leftLen)
+    -- The right cut might need some of the left padding.
+    SidesCI lCA (CutCA rCut)          ->
+        spacesAfterCut lCA cellLen (rCut + rightLen)
+        <> buildCell (dropRight (rCut + rightLen) c)
+        <> applyRightMark availSpace
+    -- Filtered out all cuts at this point.
+    SidesCI lCA rCA                   ->
+        let spacesB' = spacesB . surplusSpace
+        in spacesB' lCA <> buildCell c <> spacesB' rCA
+    MarkRightCI                       ->
+        spacesB (max 0 $ availSpace - leftLen) <> applyRightMark availSpace
+    MarkLeftCI                        ->
+        applyLeftMark availSpace <> spacesB (max 0 $ availSpace - rightLen)
+  where
+    leftLen = length $ leftMark cm
+    rightLen = length $ rightMark cm
+
+    applyLeftMark k  = buildCell $ take k $ leftMark cm
+    applyRightMark k = buildCell $ drop (rightLen - k) $ rightMark cm
+
+-- | Given a position, the available width, and the length of an alignment
+-- (left and right side, separator is implied) compute a range for the view.
+-- The lower bound is inclusive and the upper bound exclusive.
+viewRange :: Position o -> Int -> Int -> Int -> (Int, Int)
+viewRange p availSpace l r = case p of
+    Start  -> (0, availSpace)
+    Center -> let (cq, cr) = (l + r + 1 - availSpace) `divMod` 2
+                  start    = cq + cr
+              in (start, start + availSpace)
+    End    -> let end = l + r + 1
+              in (end - availSpace, end)
+
+-- | Given the maximum left alignment and the alignment of the cell create a
+-- range that describes the position of the cell. The lower bound is inclusive
+-- and the upper bound exclusive.
+cellRange :: Int -> AlignInfo -> (Int, Int)
+cellRange lMax cellAlignInfo@(AlignInfo l _) = (cl, cl + widthAI cellAlignInfo)
+  where
+    cl = lMax - l
+
+-- | Aligns a cell using a fixed width, fitting it to the width by either
+-- filling or cutting while respecting the alignment.
+alignFixed
+    :: (Cell a, StringBuilder b)
+    => Position o
+    -> CutMark
+    -> Int
+    -> OccSpec
+    -> AlignInfo
+    -> a
+    -> b
+alignFixed p cm n oS (AlignInfo lMax optRMax) c = case optRMax of
+    Nothing   -> trimOrPad p cm n c
+    Just rMax -> let (vl, vr)            = viewRange p n lMax rMax
+                     (cl, cr)            = cellRange lMax $ measureAlignment (predicate oS) c
+                     cutInfo             = determineCuts vl vr cl cr
+                     cellLen             = cr - cl
+                 in applyCutInfo cutInfo cm n cellLen c
+
diff --git a/src/Text/Layout/Table/Cell/Formatted.hs b/src/Text/Layout/Table/Cell/Formatted.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Cell/Formatted.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE DeriveFunctor #-}
+-- | Provides formatting to an instance of 'Cell'. For example, in a unix
+-- terminal one could use the following:
+--
+-- >>> buildCell (formatted "\ESC[31m" "Hello World!" "\ESC[0m") :: String
+-- Hello World!
+--
+-- The text then appears in dull red.
+module Text.Layout.Table.Cell.Formatted
+    ( Formatted
+    , formatted
+    , plain
+    ) where
+
+import Data.String
+
+import Text.Layout.Table.Cell
+import Text.Layout.Table.StringBuilder
+
+data Formatted a
+    = Formatted
+    { prefix :: String
+    , content :: a
+    , suffix :: String
+    } deriving Functor
+
+-- | Create a value from content that is kept plain without any formatting.
+plain :: a -> Formatted a
+plain x = Formatted "" x ""
+
+-- | Create a formatted value with formatting directives that are applied to
+-- the whole value. The actual formatting has to be done by the backend.
+formatted
+    :: String -- ^ Prefix text directives for formatting.
+    -> a -- ^ The content to be formatted.
+    -> String -- ^ Suffix text directives for formatting.
+    -> Formatted a
+formatted = Formatted
+
+instance IsString a => IsString (Formatted a) where
+    fromString = plain . fromString
+
+instance Cell a => Cell (Formatted a) where
+    dropLeft i = fmap $ dropLeft i
+    dropRight i = fmap $ dropRight i
+    dropBoth l r = fmap $ dropBoth l r
+    visibleLength = visibleLength . content
+    measureAlignment p = measureAlignment p . content
+
+    -- | Surrounds the content with the directives.
+    buildCell h = stringB (prefix h) <> buildCell (content h) <> stringB (suffix h)
diff --git a/src/Text/Layout/Table/Internal.hs b/src/Text/Layout/Table/Internal.hs
deleted file mode 100644
--- a/src/Text/Layout/Table/Internal.hs
+++ /dev/null
@@ -1,40 +0,0 @@
-module Text.Layout.Table.Internal where
-
-import Data.Default.Class
-import Data.Default.Instances.Base
-
-import Text.Layout.Table.Position
-import Text.Layout.Table.Primitives.Basic
-
--- | Groups rows together which should not be visually seperated from each other.
-newtype RowGroup
-    = RowGroup
-    { rows :: [[String]]
-    }
-
--- | Group the given rows together.
-rowsG :: [Row String] -> RowGroup
-rowsG = RowGroup
-
--- | Make a group of a single row.
-rowG :: Row String -> RowGroup
-rowG = RowGroup . (: [])
-
--- | Specifies how a header is rendered.
-data HeaderColSpec = HeaderColSpec (Position H) (Maybe CutMark)
-
--- | Smart constructor for 'HeaderColSpec'. By omitting the cut mark it will use
--- the one specified in the 'Text.Layout.Primitives.Column.ColSpec' like the
--- other cells in that column.
-headerColumn :: Position H -> Maybe CutMark -> HeaderColSpec
-headerColumn = HeaderColSpec
-
--- | Header columns are usually centered.
-instance Default HeaderColSpec where
-    def = headerColumn center def
-
--- | An alias for lists, conceptually for values with a horizontal arrangement.
-type Row a = [a]
-
--- | An alias for lists, conceptually for values with a vertical arrangement.
-type Col a = [a]
diff --git a/src/Text/Layout/Table/Justify.hs b/src/Text/Layout/Table/Justify.hs
--- a/src/Text/Layout/Table/Justify.hs
+++ b/src/Text/Layout/Table/Justify.hs
@@ -1,10 +1,13 @@
 -- | Produce justified text, which is spread over multiple rows. For a simple
 -- cut, 'chunksOf' from the `split` package is best suited.
 {-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE RecordWildCards #-}
 module Text.Layout.Table.Justify
     ( -- * Text justification
       justify
     , justifyText
+    , fitWords
+    , concatPadLine
 
       -- * Helpers
     , dimorphicSummands
@@ -12,13 +15,7 @@
     , mixedDimorphicSummandsBy
     ) where
 
-import Control.Arrow
-import Data.List
-
-import Text.Layout.Table.Internal
 import Text.Layout.Table.Primitives.Basic
-import Text.Layout.Table.Position.Internal
-import Text.Layout.Table.Vertical
 
 -- | Uses 'words' to split the text into words and justifies it with 'justify'.
 --
@@ -32,23 +29,69 @@
 -- Every line, except the last one, gets equally filled with spaces between the
 -- words as far as possible.
 justify :: Int -> [String] -> [String]
-justify width = mapInit pad (\(_, _, line) -> unwords line) . gather 0 0 []
+justify width = mapInit (concatPadLine width) (unwords . lineWords) . fitWords width
+
+-- | Intermediate representation for a line of words.
+data Line
+    = Line
+    { lineLength :: Int -- ^ The length of the current line with a single space as separator between the words.
+    , lineWordCount :: Int -- ^ The number of words on the current line.
+    , lineWords :: [String] -- ^ The actual words of the line.
+    } deriving Show
+
+-- | Join the words on a line together by filling it with spaces in between.
+concatPadLine
+    :: Int -- ^ The maximum length for lines.
+    -> Line -- ^ The 'Line'.
+    -> String -- The padded and concatenated line.
+concatPadLine width Line {..} = case lineWords of
+    [word] -> word
+    _      -> unwords $ if lineLength < width
+                        then let fillAmount = width - lineLength
+                                 gapCount   = pred lineWordCount
+                                 spaceSeps  = mixedDimorphicSpaces fillAmount gapCount ++ [""]
+                             in zipWith (++) lineWords spaceSeps
+                        else lineWords
+
+-- | Fit as much words on a line as possible. Produce a list of the length of
+-- the line with one space between the words, the word count and the words.
+--
+-- Cutting below word boundaries is not yet supported.
+fitWords
+    :: Int -- ^ The number of characters available per line.
+    -> [String] -- ^ The words to join with whitespaces.
+    -> [Line] -- ^ The list of line information.
+fitWords width = --gather 0 0 []
+    finishFitState . foldr fitStep (FitState 0 0 [] [])
   where
-    pad (len, wCount, line) = unwords $ if len < width
-                                        then zipWith (++) line $ mixedDimorphicSpaces (width - len) (pred wCount) ++ [""]
-                                        else line
+    fitStep word s@FitState {..} =
+        let wLen       = length word
+            newLineLen = fitStateLineLen + 1 + wLen
+            reinit f   = FitState wLen 1 [word] $ f fitStateLines
+        in if | null fitStateWords  -> reinit id
+              | newLineLen <= width -> FitState newLineLen (succ fitStateWordCount) (word : fitStateWords) fitStateLines
+              | otherwise           -> reinit (finishLine s :)
 
-    gather lineLen wCount line ws = case ws of  
-        []      | null line -> []
-                | otherwise -> [(lineLen, wCount, reverse line)]
-        w : ws'             ->
-            let wLen   = length w
-                newLineLen = lineLen + 1 + wLen
-                reinit = gather wLen 1 [w] ws'
-            in if | null line           -> reinit
-                  | newLineLen <= width -> gather newLineLen (succ wCount) (w : line) ws'
-                  | otherwise           -> (lineLen, wCount, reverse line) : reinit
+-- | State used while fitting words on a line.
+data FitState
+    = FitState
+    { fitStateLineLen :: Int
+    , fitStateWordCount :: Int
+    , fitStateWords :: [String]
+    , fitStateLines :: [Line]
+    }
 
+-- | Completes the current line.
+finishLine :: FitState -> Line
+finishLine FitState {..} = Line fitStateLineLen fitStateWordCount $ reverse fitStateWords
+
+finishFitState :: FitState -> [Line]
+finishFitState s@FitState {..} = finishLines fitStateLines
+  where
+    finishLines = case fitStateWordCount of
+        0 -> id
+        _ -> (finishLine s :)
+
 -- | Map inits with the first function and the last one with the last function.
 mapInit :: (a -> b) -> (a -> b) -> [a] -> [b]
 mapInit _ _ []       = []
@@ -56,9 +99,6 @@
   where
     go y []        = [g y]
     go y (y' : ys) = f y : go y' ys
-
-dimorphicSpaces :: Int -> Int -> [String]
-dimorphicSpaces = dimorphicSummandsBy spaces
 
 -- | Spread out spaces with different widths more evenly (in comparison to
 -- 'dimorphicSpaces').
diff --git a/src/Text/Layout/Table/Pandoc.hs b/src/Text/Layout/Table/Pandoc.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Pandoc.hs
@@ -0,0 +1,51 @@
+-- | Render tables that can be used in <https://pandoc.org/ Pandoc>. In
+-- particular, this supports the
+-- <https://pandoc.org/MANUAL.html#tables pipe_tables> extension.
+module Text.Layout.Table.Pandoc where
+
+import Data.List
+
+import Text.Layout.Table.Primitives.ColumnModifier
+import Text.Layout.Table.Primitives.Header
+import Text.Layout.Table.Spec.ColSpec
+import Text.Layout.Table.Spec.HeaderSpec
+import Text.Layout.Table.Spec.Position
+import Text.Layout.Table.Spec.Util
+
+-- | Generate a table that is readable but also serves as input to pandoc.
+--
+-- >>> mapM_ putStrLn $ pandocPipeTableLines [def, numCol] (titlesH ["text", "numeric value"]) [["a", "1.5"], ["b", "6.60000"]]
+-- |text|numberic value|
+-- |:---|-------------:|
+-- |a   |       1.5    |
+-- |b   |       6.60000|
+pandocPipeTableLines
+    :: [ColSpec]
+    -> HeaderSpec
+    -> [Row String]
+    -> [String]
+pandocPipeTableLines specs h tab =
+    fmap (intercalate "|" . ("" :) . (++ [""])) $ consHeaderRow . (vSeparators :) $ zipWith ($) cmfs <$> tab
+  where
+    cmfs = zipWith (\spec cmi -> columnModifier (position spec) (cutMark spec) cmi) specs cmis
+    cmis = zipWith (ensureWidthCMI 2) posSpecs $ fitHeaderIntoCMIs $ deriveColModInfos' specs tab
+
+    posSpecs = fmap position specs
+
+    (fitHeaderIntoCMIs, consHeaderRow) = case h of
+        NoneHS                      -> (id, id)
+        HeaderHS headerSpecs titles ->
+            ( fitTitlesCMI titles posSpecs
+            , (zipWith4 headerCellModifier headerSpecs (cutMark <$> specs) cmis titles :)
+            )
+
+    vSeparators = zipWith (\pos cmi -> applyPandocPositionMarker pos $ replicate (widthCMI cmi) '-') posSpecs cmis
+
+applyPandocPositionMarker :: Position H -> String -> String
+applyPandocPositionMarker p = case p of
+    Start  -> markLeft
+    Center -> markRight . markLeft
+    End    -> markRight
+  where
+    markLeft = (':' :) . drop 1
+    markRight = reverse . (':' :) . drop 1 .  reverse
diff --git a/src/Text/Layout/Table/Position.hs b/src/Text/Layout/Table/Position.hs
deleted file mode 100644
--- a/src/Text/Layout/Table/Position.hs
+++ /dev/null
@@ -1,13 +0,0 @@
-{-# LANGUAGE PatternSynonyms #-}
-module Text.Layout.Table.Position
-    ( Position
-    , H
-    , V
-    , left
-    , right
-    , center
-    , top
-    , bottom
-    ) where
-
-import Text.Layout.Table.Position.Internal
diff --git a/src/Text/Layout/Table/Position/Internal.hs b/src/Text/Layout/Table/Position/Internal.hs
deleted file mode 100644
--- a/src/Text/Layout/Table/Position/Internal.hs
+++ /dev/null
@@ -1,48 +0,0 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE EmptyDataDecls #-}
-module Text.Layout.Table.Position.Internal where
-
-import Data.Default.Class
-
--- | Specifies a position relative from a beginning.
-data Position orientation
-    = Start
-    | Center
-    | End
-    deriving Eq
-
-instance Show (Position H) where
-    show p = case p of
-        Start  -> "left"
-        Center -> "center"
-        End    -> "right"
-
-instance Show (Position V) where
-    show p = case p of
-        Start  -> "top"
-        Center -> "center"
-        End    -> "bottom"
-
-instance Default (Position orientation) where
-    def = Start
-
--- | Horizontal orientation.
-data H
-
--- | Vertical orientation.
-data V
-
-left :: Position H
-left = Start
-
-right :: Position H
-right = End
-
-center :: Position orientation
-center = Center
-
-top :: Position V
-top = Start
-
-bottom :: Position V
-bottom = End
diff --git a/src/Text/Layout/Table/Primitives/AlignInfo.hs b/src/Text/Layout/Table/Primitives/AlignInfo.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Primitives/AlignInfo.hs
@@ -0,0 +1,24 @@
+module Text.Layout.Table.Primitives.AlignInfo where
+
+import Data.Foldable (asum)
+
+-- | Specifies the length before and after an alignment position (excluding the
+-- alignment character).
+data AlignInfo = AlignInfo Int (Maybe Int)
+
+-- | Private show function.
+showAI :: AlignInfo -> String
+showAI (AlignInfo l optR) = "AlignInfo " ++ show l ++ " " ++ showsPrec 11 optR ""
+
+-- | The column width when using the 'AlignInfo'.
+widthAI :: AlignInfo -> Int
+widthAI (AlignInfo l optR) = l + maybe 0 succ optR
+
+-- | Produce an 'AlignInfo' that is wide enough to hold inputs of both given
+-- 'AlignInfo's.
+instance Semigroup AlignInfo where
+    AlignInfo ll lOptR <> AlignInfo rl rOptR =
+        AlignInfo (max ll rl) (asum [max <$> lOptR <*> rOptR, lOptR, rOptR])
+
+instance Monoid AlignInfo where
+    mempty = AlignInfo 0 Nothing
diff --git a/src/Text/Layout/Table/Primitives/AlignSpec.hs b/src/Text/Layout/Table/Primitives/AlignSpec.hs
deleted file mode 100644
--- a/src/Text/Layout/Table/Primitives/AlignSpec.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Text.Layout.Table.Primitives.AlignSpec
-    ( AlignSpec
-    , noAlign
-    , occSpecAlign
-    , predAlign
-    , charAlign
-    ) where
-
-import Text.Layout.Table.Primitives.AlignSpec.Internal
diff --git a/src/Text/Layout/Table/Primitives/AlignSpec/Internal.hs b/src/Text/Layout/Table/Primitives/AlignSpec/Internal.hs
deleted file mode 100644
--- a/src/Text/Layout/Table/Primitives/AlignSpec/Internal.hs
+++ /dev/null
@@ -1,36 +0,0 @@
-module Text.Layout.Table.Primitives.AlignSpec.Internal
-    ( AlignSpec(..)
-    , noAlign
-    , occSpecAlign
-    , predAlign
-    , charAlign
-    ) where
-
-import Data.Default.Class
-
-import Text.Layout.Table.Primitives.Occurence
-
--- | Determines whether a column will align at a specific letter.
-data AlignSpec
-    = AlignOcc OccSpec
-    | NoAlign
-
--- | No alignment is the default.
-instance Default AlignSpec where
-    def = noAlign
-
--- | Don't align text.
-noAlign :: AlignSpec
-noAlign = NoAlign
-
--- | Construct an 'AlignSpec' by giving an occurence specification.
-occSpecAlign :: OccSpec -> AlignSpec
-occSpecAlign = AlignOcc
-
--- | Align at the first match of a predicate.
-predAlign :: (Char -> Bool) -> AlignSpec
-predAlign = occSpecAlign . predOccSpec
-
--- | Align text at the first occurence of a given 'Char'.
-charAlign :: Char -> AlignSpec
-charAlign = predAlign . (==)
diff --git a/src/Text/Layout/Table/Primitives/Basic.hs b/src/Text/Layout/Table/Primitives/Basic.hs
--- a/src/Text/Layout/Table/Primitives/Basic.hs
+++ b/src/Text/Layout/Table/Primitives/Basic.hs
@@ -1,14 +1,8 @@
 -- | This module contains primitive modifiers for lists and 'String's to be
 -- filled or fitted to a specific length.
 module Text.Layout.Table.Primitives.Basic
-    ( -- * Cut marks
-      CutMark
-    , doubleCutMark
-    , singleCutMark
-    , noCutMark
-
-      -- * String-related tools
-    , spaces
+    ( -- * String-related tools
+      spaces
     , concatLines
 
       -- ** Filling
@@ -32,39 +26,12 @@
     , fillEnd
     , fillBoth'
     , fillBoth
-    )
-    where
+    ) where
 
--- TODO rename cut marks (they are too long)
+import Text.Layout.Table.Spec.CutMark
 
-import Data.Default.Class
 import Data.List
 
--- | Specifies how the place looks where a 'String' has been cut. Note that the
--- cut mark may be cut itself to fit into a column.
-data CutMark
-    = CutMark
-    { leftMark  :: String
-    , rightMark :: String
-    }
-
--- | A single ellipsis unicode character is used to show cut marks.
-instance Default CutMark where
-    def = singleCutMark "…"
-
--- | Specify two different cut marks, one for cuts on the left and one for cuts
--- on the right.
-doubleCutMark :: String -> String -> CutMark
-doubleCutMark l r = CutMark l (reverse r)
-
--- | Use the cut mark on both sides by reversing it on the other.
-singleCutMark :: String -> CutMark
-singleCutMark l = doubleCutMark l (reverse l)
-
--- | Don't show any cut mark when text is cut.
-noCutMark :: CutMark
-noCutMark = singleCutMark ""
-
 spaces :: Int -> String
 spaces = flip replicate ' '
 
@@ -144,11 +111,11 @@
 
 -- | Applies a 'CutMark' to the left of a 'String', while preserving the length.
 applyMarkLeftWith :: CutMark -> String -> String
-applyMarkLeftWith cms = applyMarkLeftBy leftMark cms
+applyMarkLeftWith = applyMarkLeftBy leftMark
 
 -- | Applies a 'CutMark' to the right of a 'String', while preserving the length.
 applyMarkRightWith :: CutMark -> String -> String
-applyMarkRightWith cms = reverse . applyMarkLeftBy rightMark cms . reverse
+applyMarkRightWith cms = reverse . applyMarkLeftBy (reverse . rightMark) cms . reverse
 
 applyMarkLeftBy :: (a -> String) -> a -> String -> String
 applyMarkLeftBy f v = zipWith ($) $ map const (f v) ++ repeat id
diff --git a/src/Text/Layout/Table/Primitives/Column.hs b/src/Text/Layout/Table/Primitives/Column.hs
deleted file mode 100644
--- a/src/Text/Layout/Table/Primitives/Column.hs
+++ /dev/null
@@ -1,32 +0,0 @@
-module Text.Layout.Table.Primitives.Column
-    ( ColSpec
-    , lenSpec
-    , position
-    , alignSpec
-    , cutMark
-    , column
-    ) where
-
-import Data.Default.Class
-
-import Text.Layout.Table.Position
-import Text.Layout.Table.Primitives.AlignSpec
-import Text.Layout.Table.Primitives.Basic
-import Text.Layout.Table.Primitives.LenSpec
-
-
--- | Specifies the layout of a column.
-data ColSpec
-    = ColSpec
-    { lenSpec     :: LenSpec
-    , position    :: Position H
-    , alignSpec   :: AlignSpec
-    , cutMark     :: CutMark
-    }
-
-instance Default ColSpec where
-    def = column def def def def
-
--- | Smart constructor to specify a column.
-column :: LenSpec -> Position H -> AlignSpec -> CutMark -> ColSpec
-column = ColSpec
diff --git a/src/Text/Layout/Table/Primitives/ColumnModifier.hs b/src/Text/Layout/Table/Primitives/ColumnModifier.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Primitives/ColumnModifier.hs
@@ -0,0 +1,141 @@
+module Text.Layout.Table.Primitives.ColumnModifier where
+
+import Control.Arrow ((&&&))
+import Data.List
+
+import Text.Layout.Table.Cell
+import Text.Layout.Table.Primitives.AlignInfo
+import Text.Layout.Table.Spec.AlignSpec
+import Text.Layout.Table.Spec.ColSpec
+import Text.Layout.Table.Spec.CutMark
+import Text.Layout.Table.Spec.LenSpec
+import Text.Layout.Table.Spec.OccSpec
+import Text.Layout.Table.Spec.Position
+import Text.Layout.Table.Spec.Util
+import Text.Layout.Table.StringBuilder
+
+-- | Specifies how a column should be modified. Values of this type are derived
+-- in a traversal over the input columns by using 'deriveColModInfos'. Finally,
+-- 'columnModifier' will interpret them and apply the appropriate modification
+-- function to the cells of the column.
+data ColModInfo
+    = FillAligned OccSpec AlignInfo
+    | FillTo Int
+    | FitTo Int (Maybe (OccSpec, AlignInfo))
+
+-- | Private show function.
+showCMI :: ColModInfo -> String
+showCMI cmi = case cmi of
+    FillAligned _ ai -> "FillAligned .. " ++ showAI ai
+    FillTo i         -> "FillTo " ++ show i
+    FitTo i _        -> "FitTo " ++ show i ++ ".."
+
+-- | Get the exact width of a 'ColModInfo' after applying it with
+-- 'columnModifier'.
+widthCMI :: ColModInfo -> Int
+widthCMI cmi = case cmi of
+    FillAligned _ ai -> widthAI ai
+    FillTo maxLen    -> maxLen
+    FitTo lim _      -> lim
+
+-- | Remove alignment from a 'ColModInfo'. This is used to change alignment of
+-- headers while using the combined width information.
+unalignedCMI :: ColModInfo -> ColModInfo
+unalignedCMI cmi = case cmi of
+    FillAligned _ ai -> FillTo $ widthAI ai
+    FitTo i _        -> FitTo i Nothing
+    _                -> cmi
+
+-- | Ensures that the modification provides a minimum width but only if it is
+-- not limited.
+ensureWidthCMI :: Int -> Position H -> ColModInfo -> ColModInfo
+ensureWidthCMI w pos cmi = case cmi of
+    FillAligned oS ai@(AlignInfo lw optRW)
+                  ->
+        let neededW = w - widthAI ai
+        in if neededW <= 0
+           then cmi
+           else FillAligned oS $ case pos of
+               Start  -> case optRW of
+                   Just rw -> AlignInfo lw $ Just (rw + neededW)
+                   Nothing -> AlignInfo (lw + neededW) optRW
+               End    -> AlignInfo (lw + neededW) optRW
+               Center -> case optRW of
+                   Just _  -> let (q, r) = w `divMod` 2 
+                              -- Calculate a new distribution.
+                              in AlignInfo q $ Just (q + r)
+                   Nothing -> AlignInfo (lw + neededW) optRW
+    FillTo maxLen -> FillTo (max maxLen w)
+    _             -> cmi
+
+-- | Ensures that the given 'String' will fit into the modified columns.
+ensureWidthOfCMI :: String -> Position H -> ColModInfo -> ColModInfo
+ensureWidthOfCMI = ensureWidthCMI . visibleLength
+
+-- | Fit titles of a header column into the derived 'ColModInfo'.
+fitTitlesCMI :: [String] -> [Position H] -> [ColModInfo] -> [ColModInfo]
+fitTitlesCMI = zipWith3 ensureWidthOfCMI
+
+-- | Generates a function which modifies a given cell according to
+-- 'Text.Layout.Table.Position.Position', 'CutMark' and 'ColModInfo'. This is
+-- used to modify a single cell of a column to bring all cells of a column to
+-- the same width.
+columnModifier
+    :: (Cell a, StringBuilder b)
+    => Position H
+    -> CutMark
+    -> ColModInfo
+    -> (a -> b)
+columnModifier pos cms colModInfo = case colModInfo of
+    FillAligned oS ai -> align oS ai
+    FillTo maxLen     -> pad pos maxLen
+    FitTo lim mT      ->
+        maybe (trimOrPad pos cms lim) (uncurry $ alignFixed pos cms lim) mT
+
+-- | Derive the 'ColModInfo' by using layout specifications and the actual cells
+-- of a column. This function only needs to know about 'LenSpec' and 'AlignInfo'.
+deriveColModInfos :: Cell a => [(LenSpec, AlignSpec)] -> [Row a] -> [ColModInfo]
+deriveColModInfos specs = zipWith ($) (fmap fSel specs) . transpose
+  where
+    fSel (lenS, alignS) = case alignS of
+        NoAlign     -> let fitTo i              = const $ FitTo i Nothing
+                           expandUntil' f i max' = if f (max' <= i)
+                                                   then FillTo max'
+                                                   else fitTo i max'
+                           fun                  = case lenS of
+                               Expand        -> FillTo
+                               Fixed i       -> fitTo i
+                               ExpandUntil i -> expandUntil' id i
+                               FixedUntil i  -> expandUntil' not i
+                       in fun . maximum . map visibleLength
+        AlignOcc oS -> let fitToAligned i      = FitTo i . Just . (,) oS
+                           fillAligned         = FillAligned oS
+                           expandUntil' f i ai = if f (widthAI ai <= i)
+                                                then fillAligned ai
+                                                else fitToAligned i ai
+                           fun                = case lenS of
+                               Expand        -> fillAligned
+                               Fixed i       -> fitToAligned i
+                               ExpandUntil i -> expandUntil' id i
+                               FixedUntil i  -> expandUntil' not i
+                        in fun . foldMap (deriveAlignInfo oS)
+
+deriveColModInfos' :: Cell a => [ColSpec] -> [Row a] -> [ColModInfo]
+deriveColModInfos' = deriveColModInfos . fmap (lenSpec &&& alignSpec)
+
+-- | Derive the 'ColModInfo' and generate functions without any intermediate
+-- steps.
+deriveColMods
+    :: (Cell a, StringBuilder b)
+    => [ColSpec]
+    -> [Row a]
+    -> [a -> b]
+deriveColMods specs tab =
+    zipWith (uncurry columnModifier) (map (position &&& cutMark) specs) cmis
+  where
+    cmis = deriveColModInfos' specs tab
+
+-- | Generate the 'AlignInfo' of a cell by using the 'OccSpec'.
+deriveAlignInfo :: Cell a => OccSpec -> a -> AlignInfo
+deriveAlignInfo occSpec = measureAlignment (predicate occSpec)
+
diff --git a/src/Text/Layout/Table/Primitives/Header.hs b/src/Text/Layout/Table/Primitives/Header.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Primitives/Header.hs
@@ -0,0 +1,13 @@
+module Text.Layout.Table.Primitives.Header where
+
+import Data.Maybe
+
+import Text.Layout.Table.Primitives.ColumnModifier
+import Text.Layout.Table.Spec.CutMark
+import Text.Layout.Table.Spec.HeaderColSpec
+
+-- | Combine a 'HeaderColSpec' and existing 'ColModInfo's to format header cells.
+headerCellModifier :: HeaderColSpec -> CutMark -> ColModInfo -> (String -> String)
+headerCellModifier (HeaderColSpec pos optCutMark) cutMark cmi =
+    columnModifier pos (fromMaybe cutMark optCutMark) (unalignedCMI cmi)
+
diff --git a/src/Text/Layout/Table/Primitives/LenSpec.hs b/src/Text/Layout/Table/Primitives/LenSpec.hs
deleted file mode 100644
--- a/src/Text/Layout/Table/Primitives/LenSpec.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-module Text.Layout.Table.Primitives.LenSpec
-    ( LenSpec
-    , expand
-    , fixed
-    , expandUntil
-    , fixedUntil
-    ) where
-
-import Text.Layout.Table.Primitives.LenSpec.Internal
diff --git a/src/Text/Layout/Table/Primitives/LenSpec/Internal.hs b/src/Text/Layout/Table/Primitives/LenSpec/Internal.hs
deleted file mode 100644
--- a/src/Text/Layout/Table/Primitives/LenSpec/Internal.hs
+++ /dev/null
@@ -1,35 +0,0 @@
-module Text.Layout.Table.Primitives.LenSpec.Internal
-    ( LenSpec (..)
-    , expand
-    , fixed
-    , expandUntil
-    , fixedUntil
-    ) where
-
-import Data.Default.Class
-
--- | Determines how long a column will be.
-data LenSpec
-    = Expand
-    | Fixed Int
-    | ExpandUntil Int
-    | FixedUntil Int
-
-instance Default LenSpec where
-    def = expand
-
--- | Allows columns to use as much space as needed.
-expand :: LenSpec
-expand = Expand
-
--- | Fixes column length to a specific width.
-fixed :: Int -> LenSpec
-fixed = Fixed
-
--- | The column will expand as long as it is smaller as the given width.
-expandUntil :: Int -> LenSpec
-expandUntil = ExpandUntil
-
--- | The column will be at least as wide as the given width.
-fixedUntil :: Int -> LenSpec
-fixedUntil = FixedUntil
diff --git a/src/Text/Layout/Table/Primitives/Occurence.hs b/src/Text/Layout/Table/Primitives/Occurence.hs
deleted file mode 100644
--- a/src/Text/Layout/Table/Primitives/Occurence.hs
+++ /dev/null
@@ -1,26 +0,0 @@
-module Text.Layout.Table.Primitives.Occurence
-    ( OccSpec
-    , predOccSpec
-    , splitAtOcc
-    ) where
-
-import Control.Arrow
-
--- | Specifies an occurence of a letter.
-data OccSpec = OccSpec (Char -> Bool) Int
-
--- | Construct an occurence specification by using a predicate.
-predOccSpec :: (Char -> Bool) -> OccSpec
-predOccSpec p = OccSpec p 0
-
--- | Use an occurence specification to split a 'String'.
-splitAtOcc :: OccSpec -> String -> (String, String)
-splitAtOcc (OccSpec p occ) = first reverse . go 0 []
-  where
-    go n ls xs = case xs of
-        []      -> (ls, [])
-        x : xs' -> if p x
-                   then if n == occ
-                        then (ls, xs)
-                        else go (succ n) (x : ls) xs'
-                   else go n (x : ls) xs'
diff --git a/src/Text/Layout/Table/Primitives/Table.hs b/src/Text/Layout/Table/Primitives/Table.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Primitives/Table.hs
@@ -0,0 +1,40 @@
+-- | This module provides primitives for generating tables. Tables are generated
+-- line by line thus the functions in this module produce
+module Text.Layout.Table.Primitives.Table where
+
+import           Data.List
+
+import           Text.Layout.Table.StringBuilder
+import           Text.Layout.Table.Spec.Util
+
+
+-- | Draw a horizontal line that will use the delimiters around the
+-- appropriately and visually separate by 'hSpace'.
+hLineDetail
+    :: StringBuilder b
+    => Char -- ^ The space character that is used as padding.
+    -> Char -- ^ The delimiter that is used on the left side.
+    -> Char -- ^ The delimiter that is used in between cells.
+    -> Char -- ^ The delimiter that is sued on the right side.
+    -> Row b -- ^ A row of builders.
+    -> b -- ^ The formatted line as a 'StringBuilder'.
+hLineDetail hSpace delimL delimM delimR cells =
+    mconcat $ intersperse (charB hSpace) $ charB delimL : intersperse (charB delimM) cells ++ [charB delimR]
+
+-- | A simplified version of 'hLineDetail' that will use the same delimiter
+-- for everything.
+hLine
+    :: StringBuilder b
+    => Char -- ^ The space character that is used as padding.
+    -> Char -- ^ The delimiter that is used for everything.
+    -> Row b -- ^ A row of builders.
+    -> b -- ^ The formatted line as a 'StringBuilder'.
+hLine hSpace delim = hLineDetail hSpace delim delim delim
+
+-- | Render a line with actual content.
+hLineContent
+    :: StringBuilder b
+    => Char -- ^ The delimiter that is used for everything.
+    -> Row b -- ^ A row of builders.
+    -> b
+hLineContent = hLine ' '
diff --git a/src/Text/Layout/Table/Spec/AlignSpec.hs b/src/Text/Layout/Table/Spec/AlignSpec.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/AlignSpec.hs
@@ -0,0 +1,36 @@
+module Text.Layout.Table.Spec.AlignSpec
+    ( AlignSpec(..)
+    , noAlign
+    , occSpecAlign
+    , predAlign
+    , charAlign
+    ) where
+
+import Data.Default.Class
+
+import Text.Layout.Table.Spec.OccSpec
+
+-- | Determines whether a column will align at a specific letter.
+data AlignSpec
+    = AlignOcc OccSpec
+    | NoAlign
+
+-- | No alignment is the default.
+instance Default AlignSpec where
+    def = noAlign
+
+-- | Don't align text.
+noAlign :: AlignSpec
+noAlign = NoAlign
+
+-- | Construct an 'AlignSpec' by giving an occurence specification.
+occSpecAlign :: OccSpec -> AlignSpec
+occSpecAlign = AlignOcc
+
+-- | Align at the first match of a predicate.
+predAlign :: (Char -> Bool) -> AlignSpec
+predAlign = occSpecAlign . predOccSpec
+
+-- | Align text at the first occurence of a given 'Char'.
+charAlign :: Char -> AlignSpec
+charAlign = predAlign . (==)
diff --git a/src/Text/Layout/Table/Spec/ColSpec.hs b/src/Text/Layout/Table/Spec/ColSpec.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/ColSpec.hs
@@ -0,0 +1,33 @@
+module Text.Layout.Table.Spec.ColSpec
+    ( ColSpec
+    , lenSpec
+    , position
+    , alignSpec
+    , cutMark
+    , column
+    ) where
+
+import Data.Default.Class
+
+import Text.Layout.Table.Primitives.Basic ()
+import Text.Layout.Table.Spec.CutMark
+import Text.Layout.Table.Spec.AlignSpec
+import Text.Layout.Table.Spec.LenSpec
+import Text.Layout.Table.Spec.Position
+
+
+-- | Specifies the layout of a column.
+data ColSpec
+    = ColSpec
+    { lenSpec     :: LenSpec
+    , position    :: Position H
+    , alignSpec   :: AlignSpec
+    , cutMark     :: CutMark
+    }
+
+instance Default ColSpec where
+    def = column def def def def
+
+-- | Smart constructor to specify a column.
+column :: LenSpec -> Position H -> AlignSpec -> CutMark -> ColSpec
+column = ColSpec
diff --git a/src/Text/Layout/Table/Spec/CutMark.hs b/src/Text/Layout/Table/Spec/CutMark.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/CutMark.hs
@@ -0,0 +1,37 @@
+-- TODO rename cut marks (they are too long)
+module Text.Layout.Table.Spec.CutMark
+    ( CutMark
+    , doubleCutMark
+    , singleCutMark
+    , noCutMark
+    , leftMark
+    , rightMark
+    ) where
+
+import Data.Default.Class
+
+-- | Specifies how the place looks where a 'String' has been cut. Note that the
+-- cut mark may be cut itself to fit into a column.
+data CutMark
+    = CutMark
+    { leftMark  :: String
+    , rightMark :: String
+    }
+
+-- | A single ellipsis unicode character is used to show cut marks.
+instance Default CutMark where
+    def = singleCutMark "…"
+
+-- | Specify two different cut marks, one for cuts on the left and one for cuts
+-- on the right.
+doubleCutMark :: String -> String -> CutMark
+doubleCutMark = CutMark
+
+-- | Use the cut mark on both sides by reversing it on the other.
+singleCutMark :: String -> CutMark
+singleCutMark l = doubleCutMark l (reverse l)
+
+-- | Don't show any cut mark when text is cut.
+noCutMark :: CutMark
+noCutMark = singleCutMark ""
+
diff --git a/src/Text/Layout/Table/Spec/HeaderColSpec.hs b/src/Text/Layout/Table/Spec/HeaderColSpec.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/HeaderColSpec.hs
@@ -0,0 +1,20 @@
+module Text.Layout.Table.Spec.HeaderColSpec where
+
+import Data.Default.Class
+import Data.Default.Instances.Base ()
+
+import Text.Layout.Table.Spec.Position
+import Text.Layout.Table.Spec.CutMark
+
+-- | Specifies how a header is rendered.
+data HeaderColSpec = HeaderColSpec (Position H) (Maybe CutMark)
+
+-- | Smart constructor for 'HeaderColSpec'. By omitting the cut mark it will use
+-- the one specified in the 'Text.Layout.Primitives.Column.ColSpec' like the
+-- other cells in that column.
+headerColumn :: Position H -> Maybe CutMark -> HeaderColSpec
+headerColumn = HeaderColSpec
+
+-- | Header columns are usually centered.
+instance Default HeaderColSpec where
+    def = headerColumn center def
diff --git a/src/Text/Layout/Table/Spec/HeaderSpec.hs b/src/Text/Layout/Table/Spec/HeaderSpec.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/HeaderSpec.hs
@@ -0,0 +1,22 @@
+module Text.Layout.Table.Spec.HeaderSpec where
+
+import Data.Default.Class
+
+import Text.Layout.Table.Spec.HeaderColSpec
+
+-- | Specifies a header.
+data HeaderSpec
+    = HeaderHS [HeaderColSpec] [String]
+    | NoneHS
+
+-- | By the default the header is not shown.
+instance Default HeaderSpec where
+    def = NoneHS
+
+-- | Specify a header column for every title.
+fullH :: [HeaderColSpec] -> [String] -> HeaderSpec
+fullH = HeaderHS
+
+-- | Use titles with the default header column specification.
+titlesH :: [String] -> HeaderSpec
+titlesH = fullH $ repeat def
diff --git a/src/Text/Layout/Table/Spec/LenSpec.hs b/src/Text/Layout/Table/Spec/LenSpec.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/LenSpec.hs
@@ -0,0 +1,35 @@
+module Text.Layout.Table.Spec.LenSpec
+    ( LenSpec (..)
+    , expand
+    , fixed
+    , expandUntil
+    , fixedUntil
+    ) where
+
+import Data.Default.Class
+
+-- | Determines how long a column will be.
+data LenSpec
+    = Expand
+    | Fixed Int
+    | ExpandUntil Int
+    | FixedUntil Int
+
+instance Default LenSpec where
+    def = expand
+
+-- | Allows columns to use as much space as needed.
+expand :: LenSpec
+expand = Expand
+
+-- | Fixes column length to a specific width.
+fixed :: Int -> LenSpec
+fixed = Fixed
+
+-- | The column will expand as long as it is smaller as the given width.
+expandUntil :: Int -> LenSpec
+expandUntil = ExpandUntil
+
+-- | The column will be at least as wide as the given width.
+fixedUntil :: Int -> LenSpec
+fixedUntil = FixedUntil
diff --git a/src/Text/Layout/Table/Spec/OccSpec.hs b/src/Text/Layout/Table/Spec/OccSpec.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/OccSpec.hs
@@ -0,0 +1,30 @@
+module Text.Layout.Table.Spec.OccSpec
+    ( OccSpec
+    , predOccSpec
+    , splitAtOcc
+    , predicate
+    ) where
+
+import Control.Arrow
+
+-- | Specifies an occurence of a letter.
+data OccSpec = OccSpec (Char -> Bool) Int
+
+predicate :: OccSpec -> (Char -> Bool)
+predicate (OccSpec p _) = p
+
+-- | Construct an occurence specification by using a predicate.
+predOccSpec :: (Char -> Bool) -> OccSpec
+predOccSpec p = OccSpec p 0
+
+-- | Use an occurence specification to split a 'String'.
+splitAtOcc :: OccSpec -> String -> (String, String)
+splitAtOcc (OccSpec p occ) = first reverse . go 0 []
+  where
+    go n ls xs = case xs of
+        []      -> (ls, [])
+        x : xs' -> if p x
+                   then if n == occ
+                        then (ls, xs)
+                        else go (succ n) (x : ls) xs'
+                   else go n (x : ls) xs'
diff --git a/src/Text/Layout/Table/Spec/Position.hs b/src/Text/Layout/Table/Spec/Position.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/Position.hs
@@ -0,0 +1,48 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE EmptyDataDecls #-}
+module Text.Layout.Table.Spec.Position where
+
+import Data.Default.Class
+
+-- | Specifies a position relative from a beginning.
+data Position orientation
+    = Start
+    | Center
+    | End
+    deriving Eq
+
+instance Show (Position H) where
+    show p = case p of
+        Start  -> "left"
+        Center -> "center"
+        End    -> "right"
+
+instance Show (Position V) where
+    show p = case p of
+        Start  -> "top"
+        Center -> "center"
+        End    -> "bottom"
+
+instance Default (Position orientation) where
+    def = Start
+
+-- | Horizontal orientation.
+data H
+
+-- | Vertical orientation.
+data V
+
+left :: Position H
+left = Start
+
+right :: Position H
+right = End
+
+center :: Position orientation
+center = Center
+
+top :: Position V
+top = Start
+
+bottom :: Position V
+bottom = End
diff --git a/src/Text/Layout/Table/Spec/RowGroup.hs b/src/Text/Layout/Table/Spec/RowGroup.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/RowGroup.hs
@@ -0,0 +1,18 @@
+module Text.Layout.Table.Spec.RowGroup where
+
+import Text.Layout.Table.Spec.Util
+
+-- | Groups rows together which should not be visually seperated from each other.
+newtype RowGroup a
+    = RowGroup
+    { rows :: [Row a]
+    }
+
+-- | Group the given rows together.
+rowsG :: [Row a] -> RowGroup a
+rowsG = RowGroup
+
+-- | Make a group of a single row.
+rowG :: Row a -> RowGroup a
+rowG = RowGroup . (: [])
+
diff --git a/src/Text/Layout/Table/Spec/Util.hs b/src/Text/Layout/Table/Spec/Util.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/Spec/Util.hs
@@ -0,0 +1,7 @@
+module Text.Layout.Table.Spec.Util where
+
+-- | An alias for lists, conceptually for values with a horizontal arrangement.
+type Row a = [a]
+
+-- | An alias for lists, conceptually for values with a vertical arrangement.
+type Col a = [a]
diff --git a/src/Text/Layout/Table/StringBuilder.hs b/src/Text/Layout/Table/StringBuilder.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Layout/Table/StringBuilder.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE FlexibleInstances #-}
+module Text.Layout.Table.StringBuilder where
+
+import Data.Semigroup
+
+-- | A type that is used to construct parts of a table.
+class Monoid a => StringBuilder a where
+    -- | Create a builder with a 'String'.
+    stringB :: String -> a
+
+    -- | Create a builder with a single 'Char'.
+    charB :: Char -> a
+
+    -- | Create a builder with several 'Char's.
+    replicateCharB :: Int -> Char -> a
+    replicateCharB i c = stimesMonoid i (charB c)
+
+    {-# MINIMAL stringB, charB #-}
+
+-- | Create a builder that contains /k/ spaces. Negative numbers are treated as
+-- zero.
+spacesB :: StringBuilder a => Int -> a
+spacesB k = replicateCharB k ' '
+
+instance StringBuilder String where
+    stringB = id
+    charB = (: [])
+    replicateCharB = replicate
+
+instance StringBuilder (Endo String) where
+    stringB = diff
+    charB = Endo . (:)
+    replicateCharB i c = Endo $ \s -> foldr ($) s $ replicate i (c :) 
+
diff --git a/src/Text/Layout/Table/Vertical.hs b/src/Text/Layout/Table/Vertical.hs
--- a/src/Text/Layout/Table/Vertical.hs
+++ b/src/Text/Layout/Table/Vertical.hs
@@ -10,8 +10,8 @@
 
 import Data.List
 
-import Text.Layout.Table.Internal
-import Text.Layout.Table.Position.Internal
+import Text.Layout.Table.Spec.Position
+import Text.Layout.Table.Spec.Util
 import Text.Layout.Table.Primitives.Basic
 
 {- | Merges multiple columns together to a valid grid without holes. For example:
@@ -21,8 +21,8 @@
 
 The result is intended to be used with a grid layout function like 'Text.Layout.Table.grid'.
 -}
-colsAsRowsAll :: Position V -> [Col [a]] -> [Row [a]]
-colsAsRowsAll ps = transpose . vPadAll [] ps
+colsAsRowsAll :: Monoid a => Position V -> [Col a] -> [Row a]
+colsAsRowsAll ps = transpose . vPadAll mempty ps
 
 {- | Works like 'colsAsRowsAll' but every position can be specified on its
    own:
@@ -30,8 +30,8 @@
 >>> colsAsRows [top, center, bottom] [["a1"], ["b1", "b2", "b3"], ["c3"]]
 [["a1","b1",""],["","b2",""],["","b3","c3"]]
 -}
-colsAsRows :: [Position V] -> [Col [a]] -> [Row [a]]
-colsAsRows ps = transpose . vPad [] ps
+colsAsRows :: Monoid a => [Position V] -> [Col a] -> [Row a]
+colsAsRows ps = transpose . vPad mempty ps
 
 -- | Fill all columns to the same length by aligning at the given position.
 vPadAll :: a -> Position V -> [Col a] -> [Col a]
diff --git a/table-layout.cabal b/table-layout.cabal
--- a/table-layout.cabal
+++ b/table-layout.cabal
@@ -6,7 +6,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.8.0.5
+version:             0.9.0.0
 
 synopsis:            Layout text as grid or table.
 
@@ -40,7 +40,7 @@
 build-type:            Simple
 -- Extra files to be distributed with the package, such as examples or a 
 -- README.
-extra-source-files:    README.md
+extra-source-files:    README.md, CHANGELOG.md
 
 -- Constraint on the version of Cabal needed to build this package.
 cabal-version:         >=1.10
@@ -52,22 +52,33 @@
 
 library
   exposed-modules:     Text.Layout.Table,
+                       Text.Layout.Table.Cell,
+                       Text.Layout.Table.Cell.Formatted,
                        Text.Layout.Table.Justify,
                        Text.Layout.Table.Style,
-                       Text.Layout.Table.Position, 
-                       Text.Layout.Table.Primitives.Basic, 
-                       Text.Layout.Table.Primitives.AlignSpec, 
-                       Text.Layout.Table.Primitives.Column,
-                       Text.Layout.Table.Primitives.LenSpec,
-                       Text.Layout.Table.Primitives.Occurence,
-                       Text.Layout.Table.Internal,
-                       Text.Layout.Table.Vertical
-  
-  other-modules:       
-                       Text.Layout.Table.Primitives.AlignSpec.Internal,
-                       Text.Layout.Table.Primitives.LenSpec.Internal,
-                       Text.Layout.Table.Position.Internal
+                       Text.Layout.Table.Vertical,
+                       Text.Layout.Table.StringBuilder,
+                       Text.Layout.Table.Pandoc,
 
+
+                       -- Will be moved into another package in the future.
+                       Text.Layout.Table.Primitives.AlignInfo,
+                       Text.Layout.Table.Primitives.Basic,
+                       Text.Layout.Table.Primitives.ColumnModifier,
+                       Text.Layout.Table.Primitives.Header,
+                       Text.Layout.Table.Primitives.Table,
+                       Text.Layout.Table.Spec.AlignSpec,
+                       Text.Layout.Table.Spec.ColSpec,
+                       Text.Layout.Table.Spec.CutMark,
+                       Text.Layout.Table.Spec.HeaderColSpec,
+                       Text.Layout.Table.Spec.HeaderSpec,
+                       Text.Layout.Table.Spec.LenSpec,
+                       Text.Layout.Table.Spec.OccSpec,
+                       Text.Layout.Table.Spec.Position,
+                       Text.Layout.Table.Spec.RowGroup,
+                       Text.Layout.Table.Spec.Util
+  other-modules:
+
   
   -- LANGUAGE extensions used by modules in this package.
   other-extensions:    RecordWildCards,
@@ -77,7 +88,7 @@
                        MultiWayIf
   
   -- Other library packages from which modules are imported.
-  build-depends:       base >=4.8 && <4.13,
+  build-depends:       base >=4.9 && <4.14,
                        data-default-class >=0.1.1 && < 0.2,
                        data-default-instances-base ==0.1.*
 
@@ -88,31 +99,42 @@
 
 executable table-layout-test-styles
   main-is:             Test.hs
-  build-depends:       base >=4.8 && <4.13,
+  build-depends:       base >=4.9 && <4.14,
                        data-default-class >=0.1.1 && < 0.2,
                        data-default-instances-base ==0.1.*
   hs-source-dirs:      src
   other-modules:       Text.Layout.Table,
-                       Text.Layout.Table.Internal,
+                       Text.Layout.Table.Cell,
+                       Text.Layout.Table.Cell.Formatted,
                        Text.Layout.Table.Justify,
-                       Text.Layout.Table.Position,
-                       Text.Layout.Table.Position.Internal,
-                       Text.Layout.Table.Primitives.AlignSpec,
-                       Text.Layout.Table.Primitives.AlignSpec.Internal,
+                       Text.Layout.Table.Style,
+                       Text.Layout.Table.Vertical
+
+                       Text.Layout.Table.Primitives.AlignInfo,
                        Text.Layout.Table.Primitives.Basic,
-                       Text.Layout.Table.Primitives.Column,
-                       Text.Layout.Table.Primitives.LenSpec,
-                       Text.Layout.Table.Primitives.LenSpec.Internal,
-                       Text.Layout.Table.Primitives.Occurence,
-                       Text.Layout.Table.Style Text.Layout.Table.Vertical
+                       Text.Layout.Table.Primitives.ColumnModifier,
+                       Text.Layout.Table.Primitives.Header,
+                       Text.Layout.Table.Primitives.Table,
+                       Text.Layout.Table.StringBuilder,
 
+                       Text.Layout.Table.Spec.AlignSpec,
+                       Text.Layout.Table.Spec.ColSpec,
+                       Text.Layout.Table.Spec.CutMark,
+                       Text.Layout.Table.Spec.HeaderColSpec,
+                       Text.Layout.Table.Spec.HeaderSpec,
+                       Text.Layout.Table.Spec.LenSpec,
+                       Text.Layout.Table.Spec.OccSpec,
+                       Text.Layout.Table.Spec.Position,
+                       Text.Layout.Table.Spec.RowGroup,
+                       Text.Layout.Table.Spec.Util
+
   default-language:    Haskell2010
 
 test-suite table-layout-tests
   type:                exitcode-stdio-1.0
   hs-source-dirs:      test-suite, src
   main-is:             Spec.hs
-  build-depends:       base >=4.8 && <4.13,
+  build-depends:       base >=4.9 && <4.14,
                        QuickCheck >=2.8 && < 2.14,
                        HUnit >=1.3,
                        data-default-class >=0.1.1 && < 0.2,
@@ -120,19 +142,31 @@
                        hspec
 
   other-modules:       TestSpec,
-                       Text.Layout.Table,
-                       Text.Layout.Table.Internal,
+
+                       Text.Layout.Table
+
+                       Text.Layout.Table.Cell,
+                       Text.Layout.Table.Cell.Formatted,
                        Text.Layout.Table.Justify,
-                       Text.Layout.Table.Position,
-                       Text.Layout.Table.Position.Internal,
-                       Text.Layout.Table.Primitives.AlignSpec,
-                       Text.Layout.Table.Primitives.AlignSpec.Internal,
-                       Text.Layout.Table.Primitives.Basic,
-                       Text.Layout.Table.Primitives.Column,
-                       Text.Layout.Table.Primitives.LenSpec,
-                       Text.Layout.Table.Primitives.LenSpec.Internal,
-                       Text.Layout.Table.Primitives.Occurence,
                        Text.Layout.Table.Style,
                        Text.Layout.Table.Vertical
+
+                       Text.Layout.Table.Primitives.AlignInfo,
+                       Text.Layout.Table.Primitives.Basic,
+                       Text.Layout.Table.Primitives.ColumnModifier,
+                       Text.Layout.Table.Primitives.Header,
+                       Text.Layout.Table.Primitives.Table,
+                       Text.Layout.Table.StringBuilder,
+
+                       Text.Layout.Table.Spec.AlignSpec,
+                       Text.Layout.Table.Spec.ColSpec,
+                       Text.Layout.Table.Spec.CutMark,
+                       Text.Layout.Table.Spec.HeaderColSpec,
+                       Text.Layout.Table.Spec.HeaderSpec,
+                       Text.Layout.Table.Spec.LenSpec,
+                       Text.Layout.Table.Spec.OccSpec,
+                       Text.Layout.Table.Spec.Position,
+                       Text.Layout.Table.Spec.RowGroup,
+                       Text.Layout.Table.Spec.Util
 
   default-language:    Haskell2010
diff --git a/test-suite/TestSpec.hs b/test-suite/TestSpec.hs
--- a/test-suite/TestSpec.hs
+++ b/test-suite/TestSpec.hs
@@ -2,23 +2,25 @@
     ( spec
     ) where
 
+-- TODO idempotency of fitting CMIs
+
 import Test.Hspec
 import Test.Hspec.QuickCheck
 import Test.QuickCheck
-import Test.HUnit
 
 import Text.Layout.Table
-import Text.Layout.Table.Primitives.Occurence
+import Text.Layout.Table.Cell (determineCuts, CutInfo(..), determineCutAction, CutAction(..), applyCutInfo, viewRange)
+import Text.Layout.Table.Spec.OccSpec
 import Text.Layout.Table.Primitives.Basic
 
 spec :: Spec
 spec = do
     describe "fill" $ do
-        describe "fillLeft" $ do
+        describe "fillLeft" $
             it "ex1" $ fillLeft 4 "ab" `shouldBe` "  ab"
-        describe "fillRight" $ do
+        describe "fillRight" $
             it "ex1" $ fillRight 4 "ab" `shouldBe` "ab  "
-        describe "fillCenter" $ do
+        describe "fillCenter" $
             it "ex1" $ fillCenter 4 "ab" `shouldBe` " ab "
 
     describe "mark" $ do
@@ -42,15 +44,17 @@
     --     it "ensureWidthCMI" $ 
 
     describe "pad" $ do
-        prop "left" $ propPadLeft
-        prop "right" $ propPadRight
-        prop "center" $ propPadCenter
+        prop "left" propPadLeft
+        prop "right" propPadRight
+        prop "center" propPadCenter
 
     describe "trimOrPad" $ do
-        prop "pad" $ forAll hposG $ \p s (Positive (Small n)) -> length s > n || trimOrPad p noCutMark n s == pad p n s
+        prop "pad" $ forAll hposG $ \p s (Positive (Small n)) ->
+            length (s :: String) > n || trimOrPad p noCutMark n s == (pad p n s :: String)
         it "left" $ trimOrPad left customCM 5 "1234567890" `shouldBe` "12..>"
         it "right" $ trimOrPad right customCM 5 "1234567890" `shouldBe` "<..90"
         it "center" $ trimOrPad center customCM 8 "1234567890" `shouldBe` "<..56..>"
+        it "center one sided" $ trimOrPad center customCM 9 "1234567890" `shouldBe` "<..567890"
 
     describe "align" $ do
         let ai = deriveAlignInfo occS "abc:42"
@@ -58,6 +62,58 @@
         it "ex2" $ align occS ai "x" `shouldBe`   "  x   "
         it "ex3" $ align occS ai ":x" `shouldBe`  "   :x "
 
+    describe "determineCuts" $ do
+        describe "cases" $ do
+            it "view entails the cell" $ determineCuts 0 8 2 6 `shouldBe` SidesCI (FillCA 2) (FillCA 2)
+            it "cell entails the view" $ determineCuts 2 6 0 8 `shouldBe` SidesCI (CutCA 2) (CutCA 2)
+            it "disjunct and view left" $ determineCuts 0 2 4 6 `shouldBe` MarkRightCI
+            it "disjunct and view right" $ determineCuts 4 6 0 2 `shouldBe` MarkLeftCI
+            it "one side cut and view left" $ determineCuts 0 4 2 6 `shouldBe` SidesCI (FillCA 2) (CutCA 2)
+            it "one side cut and view right" $ determineCuts 2 6 0 4 `shouldBe` SidesCI (CutCA 2) (FillCA 2)
+
+        describe "bound tests" $ do
+            it "disjunct and view right" $ determineCuts 1 2 0 1 `shouldBe` MarkLeftCI
+            it "disjunct and view left" $ determineCuts 0 1 1 2 `shouldBe` MarkRightCI
+
+    describe "determineCutAction" $ do
+        it "actual width has less than required" $ determineCutAction 8 4 `shouldBe` FillCA 4
+        it "actual width has exactly the required amount" $ determineCutAction 8 8 `shouldBe` NoneCA
+        it "actual width has more than required" $ determineCutAction 4 6 `shouldBe` CutCA 2
+
+    describe "applyCutInfo" $ do
+        let apply ci = applyCutInfo ci customCM 5 11 "abcde:12345" :: String
+            apply2 ci s = applyCutInfo ci customCM 5 (length s) s :: String
+            apply3 ci n s = applyCutInfo ci customCM n (length s) s :: String
+        --                                     "<...>"
+        it "double cut" $ apply (SidesCI (CutCA 3) (CutCA 3)) `shouldBe` "<...>"
+        it "left cut" $ apply (SidesCI (CutCA 6) NoneCA) `shouldBe` "<..45"
+        it "left cut and pad" $ apply (SidesCI (CutCA 7) (FillCA 1)) `shouldBe` "<..5 "
+        it "right cut" $ apply (SidesCI NoneCA (CutCA 6)) `shouldBe` "ab..>"
+        it "right cut and pad" $ apply (SidesCI (FillCA 1) (CutCA 7)) `shouldBe` " a..>"
+        it "double pad" $ apply2 (SidesCI (FillCA 1) (FillCA 1)) "abc" `shouldBe` " abc "
+        it "no action" $ apply2 (SidesCI NoneCA NoneCA) "abcde" `shouldBe` "abcde"
+        it "mark right 1" $ apply3 MarkRightCI 1 "" `shouldBe` ">"
+        it "mark right 2" $ apply3 MarkRightCI 2 "" `shouldBe` ".>"
+        it "mark right 3" $ apply3 MarkRightCI 4 "a" `shouldBe` " ..>"
+        it "mark left 1" $ apply3 MarkLeftCI 1 "" `shouldBe` "<"
+        it "mark left 2" $ apply3 MarkLeftCI 2 "" `shouldBe` "<."
+        it "mark left 3" $ apply3 MarkLeftCI 4 "a" `shouldBe` "<.. "
+
+    describe "viewRange" $ do
+        -- "     :     "
+        -- "    "
+        it "left" $ viewRange left 4 5 5 `shouldBe` (0, 4)
+        -- "     :     "
+        --        "    "
+        --  01234567891
+        it "right" $ viewRange right 4 5 5 `shouldBe` (7, 11)
+        -- "     :     "
+        --     "    "    (left-biased centering)
+        --    "    "     (right-biased-centering)
+        -- (l + r + 1 - n) / 2 = (5 + 5 + 1 - 4) / 2 = 7 / 2 = 3 rem 1
+        it "center" $ viewRange center 4 5 5 `shouldBe` (4, 8)
+
+
     describe "alignFixed" $ do
         -- 5 spaces on each side.
         let ai               = deriveAlignInfo occS "     :     "
@@ -68,7 +124,9 @@
         it "left 2" $ alignFixed' left 6 "abcd:42" `shouldBe` " ab..>"
 
         it "left 3" $ alignFixed' left 5 "32" `shouldBe`  "   32"
-
+        --                             "     :     "
+        --                                "ab:1234"
+        --                                  "<..34 "
         it "right 1" $ alignFixed' right 6 "ab:1234" `shouldBe` "<..34 "
         it "right 2" $ alignFixed' right 6 "ab:12" `shouldBe` "<..   "
         -- ensure left-biased centering:
@@ -89,29 +147,29 @@
         -- TODO add test cases for all combinations of lengths
         -- (i.e.: i mod 2 = 1, i mod 2 = 0, l + r mod 2 = 0, l + r mod 2 = 1)
 
-        prop "alignFixed length" $ forAll hposG $ \p s (Positive (Small n)) -> length (alignFixed' p n s) `shouldBe` n
+        prop "alignFixed length" $ forAll hposG $ \p s (Positive (Small n)) ->
+            length (alignFixed' p n (s :: String) :: String) `shouldBe` n
+
+    describe "text justification" $
+        it "justify" $ justify 3 ["not", "now"] `shouldBe` ["not", "now"]
   where
     customCM = doubleCutMark "<.." "..>"
     occS     = predOccSpec (== ':')
 
     hposG    = elements [left, center, right]
-    noWS     = (/= ' ')
 
     propPadLeft :: String -> Positive (Small Int) -> Bool
     propPadLeft s (Positive (Small n)) =
         let len    = length s
             padded = pad left n s
-        in if len < n
-           then take len padded == s && all (== ' ') (drop len padded)
-           else True
+        in len >= n || (take len padded == s && all (== ' ') (drop len padded))
 
     propPadRight :: String -> Positive (Small Int) -> Bool
     propPadRight s (Positive (Small n)) =
         let len    = length s
             padded = pad right n s
-        in if len < n
-           then drop (n - len) padded == s && all (== ' ') (take (n - len) padded)
-           else True
+        in len >= n || (drop (n - len) padded == s
+                        && all (== ' ') (take (n - len) padded))
 
     propPadCenter :: String -> Positive (Small Int) -> Bool
     propPadCenter s (Positive (Small n)) =
@@ -119,6 +177,5 @@
             padded   = pad center n s
             (q, r)   = (n - len) `divMod` 2
             trimLeft = drop q padded
-        in if len < n
-           then all (== ' ') (take q padded) && take len trimLeft == s && (drop len trimLeft) == replicate (q + r) ' '
-           else True
+        in len >= n || (all (== ' ') (take q padded) && take len trimLeft == s
+                        && drop len trimLeft == replicate (q + r) ' ')
