diff --git a/Text/Trifecta/Diagnostic/Err.hs b/Text/Trifecta/Diagnostic/Err.hs
--- a/Text/Trifecta/Diagnostic/Err.hs
+++ b/Text/Trifecta/Diagnostic/Err.hs
@@ -16,6 +16,9 @@
   , fatalErr
   ) where
 
+import Control.Applicative
+import Data.Foldable
+import Data.Traversable
 import Data.Semigroup
 import Data.Functor.Plus
 import Text.Trifecta.Diagnostic.Prim
@@ -46,6 +49,19 @@
   fmap _ (PanicErr s) = PanicErr s
   fmap f (Err rs l e es) = Err rs l (f e) (fmap (fmap f) es)
 
+instance Foldable Err where
+  foldMap _ EmptyErr   = mempty
+  foldMap _ FailErr{}  = mempty
+  foldMap _ PanicErr{} = mempty
+  foldMap f (Err _ _ e ds) = f e `mappend` foldMap (foldMap f) ds
+
+instance Traversable Err where
+  traverse _ EmptyErr = pure EmptyErr
+  traverse _ (FailErr s) = pure $ FailErr s
+  traverse _ (PanicErr s) = pure $ PanicErr s
+  traverse f (Err rs l e ds) = Err rs l <$> f e <*> traverse (traverse f) ds
+
+-- | Merge two errors, selecting the most severe.
 instance Alt Err where
   a                   <!> EmptyErr            = a
   _                   <!> a@(Err _ Fatal _ _) = a
@@ -55,13 +71,16 @@
   _                   <!> b                   = b
   {-# INLINE (<!>) #-}
 
+-- | Merge two errors, selecting the most severe.
 instance Plus Err where
   zero = EmptyErr
 
+-- | Merge two errors, selecting the most severe.
 instance Semigroup (Err t) where
   (<>) = (<!>)
   times1p _ = id
 
+-- | Merge two errors, selecting the most severe.
 instance Monoid (Err t) where
   mempty = EmptyErr
   mappend = (<!>) 
diff --git a/Text/Trifecta/Highlight/Prim.hs b/Text/Trifecta/Highlight/Prim.hs
--- a/Text/Trifecta/Highlight/Prim.hs
+++ b/Text/Trifecta/Highlight/Prim.hs
@@ -38,6 +38,8 @@
   | ReservedConstructorOperator
   | BadInput
   | Unbound
+  | Layout
+  | MatchedSymbols
   deriving (Eq,Ord,Show,Read,Enum,Ix,Bounded)
 
 type Highlights = IntervalMap Delta Highlight
diff --git a/Text/Trifecta/Parser/Layout.hs b/Text/Trifecta/Parser/Layout.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Parser/Layout.hs
@@ -0,0 +1,110 @@
+{-# LANGUAGE MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleInstances, UndecidableInstances #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Trifecta.Parser.Layout
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+----------------------------------------------------------------------------
+module Text.Trifecta.Parser.Layout
+  ( Layout(..)
+  , runLayout
+  , defaultLayoutState
+  ) where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.State.Class
+import Control.Monad.Trans.State.Strict (StateT(..))
+import Control.Monad.Writer.Class
+import Control.Monad.Reader.Class
+import Control.Monad.Cont.Class
+import Control.Monad.Trans.Class
+import Data.Lens
+import Text.Trifecta.Diagnostic.Class
+import Text.Trifecta.Parser.Class
+import Text.Trifecta.Parser.Combinators
+import Text.Trifecta.Parser.Token.Class
+import Text.Trifecta.Parser.Layout.Class
+import Text.Trifecta.Rope.Delta
+
+newtype Layout m a = Layout { unlayout :: StateT LayoutState m a }
+  deriving (Functor, Applicative, Alternative, Monad, MonadPlus, MonadTrans, MonadCont)
+
+runLayout :: Monad m => Layout m a -> LayoutState -> m (a, LayoutState)
+runLayout = runStateT . unlayout
+
+instance MonadTokenParser m => MonadParser (Layout m) where
+  satisfy p   = try $ layoutEq Other *> lift (satisfy p)
+  satisfy8 p  = try $ layoutEq Other *> lift (satisfy8 p)
+  line        = lift line
+  mark        = lift mark
+  release     = lift . release
+  liftIt      = lift . liftIt
+  unexpected  = lift . unexpected
+  try         = Layout . try . unlayout
+  labels m s  = Layout $ labels (unlayout m) s
+  skipMany    = Layout . skipMany . unlayout
+  highlight h = Layout . highlight h . unlayout
+
+instance MonadDiagnostic e m => MonadDiagnostic e (Layout m) where
+  fatalWith xs r e = lift $ fatalWith xs r e
+  errWith xs r e   = lift $ errWith xs r e
+  logWith l xs r e = lift $ logWith l xs r e
+
+instance MonadTokenParser m => MonadTokenParser (Layout m) where
+  whiteSpace = skipOptional $ try (() <$ layoutEq WhiteSpace <?> "")
+  nesting (Layout m) = disableLayout $ Layout (nesting m)
+  semi = getLayout layoutStack >>= \ stk -> case stk of
+    IndentedLayout _:_ -> try (';' <$ layoutEq VirtualSemi <?> "virtual semi-colon")
+                      <|> lift semi
+    _                  -> lift semi
+
+instance MonadTokenParser m => MonadLayoutParser (Layout m) where
+  getLayout l = Layout $ access l
+  setLayout l t = () <$ (Layout $ l ~= t)
+  modLayout l f = () <$ (Layout $ l %= f)
+  layout = do
+    bol <- getLayout layoutBol
+    m <- mark
+    lift whiteSpace
+    r <- mark
+    if near m r && not bol
+      then onside m r
+      else do
+        stk <- getLayout layoutStack
+        case compare (column r) (depth stk) of
+          LT -> case stk of
+            (IndentedLayout _:xs) -> VirtualRightBrace <$ setLayout layoutStack xs <* setLayout layoutBol True
+            [] -> unexpected "empty layout"
+            _  -> unexpected "layout"
+          EQ -> return VirtualSemi
+          GT -> onside m r
+    where
+      onside m r
+        | r /= m    = pure WhiteSpace
+        | otherwise = setLayout layoutBol False *> option Other (VirtualRightBrace <$ eof <* trailing)
+      trailing = getLayout layoutStack >>= \ stk -> case stk of
+          (IndentedLayout _:xs) -> setLayout layoutStack xs
+          _ -> empty
+
+      depth []                   = 0
+      depth (IndentedLayout r:_) = column r
+      depth (DisabledLayout _:_) = -1
+
+instance MonadState s m => MonadState s (Layout m) where
+  get = Layout $ lift get
+  put = Layout . lift . put
+
+instance MonadReader e m => MonadReader e (Layout m) where
+  ask = Layout $ lift ask
+  local f (Layout m) = Layout $ local f m
+
+instance MonadWriter w m => MonadWriter w (Layout m) where
+  tell = Layout . lift . tell
+  listen (Layout m) = Layout $ listen m
+  pass (Layout m) = Layout $ pass m
diff --git a/Text/Trifecta/Parser/Layout/Class.hs b/Text/Trifecta/Parser/Layout/Class.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Parser/Layout/Class.hs
@@ -0,0 +1,148 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+module Text.Trifecta.Parser.Layout.Class
+  ( LayoutToken(..)
+  , LayoutState(..)
+  , LayoutContext(..)
+  , MonadLayoutParser(..)
+  , defaultLayoutState
+  , layoutBol
+  , layoutStack
+  , layoutEq
+  , disableLayout
+  , enableLayout
+  , laidout
+  ) where
+
+import Control.Applicative
+import Control.Monad (guard)
+import Data.Lens.Common
+import Data.Monoid
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.Reader
+import Control.Monad.Trans.Identity
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import qualified Control.Monad.Trans.RWS.Lazy as Lazy
+import qualified Control.Monad.Trans.RWS.Strict as Strict
+import Text.Trifecta.Rope.Delta
+import Text.Trifecta.Rope.Bytes
+import Text.Trifecta.Parser.Class
+import Text.Trifecta.Parser.Token.Class
+import Text.Trifecta.Parser.Token.Combinators
+import qualified Text.Trifecta.Highlight.Prim as Highlight
+import Text.Trifecta.Diagnostic.Rendering.Prim
+
+data LayoutToken
+  = VirtualSemi
+  | VirtualRightBrace
+  | WhiteSpace
+  | Other
+  deriving (Eq,Ord,Show,Read)
+
+data LayoutContext
+  = IndentedLayout Rendering
+  | DisabledLayout Rendering
+
+instance HasDelta LayoutContext where
+  delta (IndentedLayout r) = delta r
+  delta (DisabledLayout r) = delta r
+
+instance HasBytes LayoutContext where
+  bytes = bytes . delta
+
+data LayoutState = LayoutState
+  { _layoutBol      :: Bool
+  , _layoutStack    :: [LayoutContext]
+  }
+
+defaultLayoutState :: LayoutState
+defaultLayoutState = LayoutState False []
+
+layoutBol :: Lens LayoutState Bool
+layoutBol = lens _layoutBol (\s l -> l { _layoutBol = s})
+
+layoutStack :: Lens LayoutState [LayoutContext]
+layoutStack = lens _layoutStack (\s l -> l { _layoutStack = s})
+
+disableLayout :: MonadLayoutParser m => m a -> m a
+disableLayout p = do
+  r <- rend
+  modLayout layoutStack (DisabledLayout r:)
+  result <- p
+  stk <- getLayout layoutStack
+  case stk of
+    DisabledLayout r':xs | delta r == delta r' -> result <$ setLayout layoutStack xs
+    _ -> unexpected "layout"
+
+enableLayout :: MonadLayoutParser m => m a -> m a
+enableLayout p = do
+  result <- highlight Highlight.Layout $ do
+    r <- rend
+    modLayout layoutStack (IndentedLayout r:)
+    p
+  result <$ layout <?> "virtual right brace"
+
+laidout :: MonadLayoutParser m => m a -> m a
+laidout p = braces p <|> enableLayout p
+
+layoutEq :: MonadLayoutParser m => LayoutToken -> m LayoutToken
+layoutEq s = try $ do
+  r <- layout
+  guard (s == r)
+  return r
+
+class MonadTokenParser m => MonadLayoutParser m where
+  layout    :: m LayoutToken
+  getLayout :: Lens LayoutState t -> m t
+  setLayout :: Lens LayoutState t -> t -> m ()
+  modLayout :: Lens LayoutState t -> (t -> t) -> m ()
+
+instance MonadLayoutParser m => MonadLayoutParser (Strict.StateT s m) where
+  layout = lift layout
+  getLayout l = lift $ getLayout l
+  setLayout l t = lift $ setLayout l t
+  modLayout l f = lift $ modLayout l f
+
+instance MonadLayoutParser m => MonadLayoutParser (Lazy.StateT s m) where
+  layout = lift layout
+  getLayout l = lift $ getLayout l
+  setLayout l t = lift $ setLayout l t
+  modLayout l f = lift $ modLayout l f
+
+instance MonadLayoutParser m => MonadLayoutParser (ReaderT e m) where
+  layout = lift layout
+  getLayout l = lift $ getLayout l
+  setLayout l t = lift $ setLayout l t
+  modLayout l f = lift $ modLayout l f
+
+instance (Monoid w, MonadLayoutParser m) => MonadLayoutParser (Strict.WriterT w m) where
+  layout = lift layout
+  getLayout l = lift $ getLayout l
+  setLayout l t = lift $ setLayout l t
+  modLayout l f = lift $ modLayout l f
+
+instance (Monoid w, MonadLayoutParser m) => MonadLayoutParser (Lazy.WriterT w m) where
+  layout = lift layout
+  getLayout l = lift $ getLayout l
+  setLayout l t = lift $ setLayout l t
+  modLayout l f = lift $ modLayout l f
+
+instance (Monoid w, MonadLayoutParser m) => MonadLayoutParser (Strict.RWST r w s m) where
+  layout = lift layout
+  getLayout l = lift $ getLayout l
+  setLayout l t = lift $ setLayout l t
+  modLayout l f = lift $ modLayout l f
+
+instance (Monoid w, MonadLayoutParser m) => MonadLayoutParser (Lazy.RWST r w s m) where
+  layout = lift layout
+  getLayout l = lift $ getLayout l
+  setLayout l t = lift $ setLayout l t
+  modLayout l f = lift $ modLayout l f
+
+instance MonadLayoutParser m => MonadLayoutParser (IdentityT m) where
+  layout = lift layout
+  getLayout l = lift $ getLayout l
+  setLayout l t = lift $ setLayout l t
+  modLayout l f = lift $ modLayout l f
diff --git a/Text/Trifecta/Parser/Token/Class.hs b/Text/Trifecta/Parser/Token/Class.hs
--- a/Text/Trifecta/Parser/Token/Class.hs
+++ b/Text/Trifecta/Parser/Token/Class.hs
@@ -31,54 +31,52 @@
   -- occurrences of a 'space', a line comment or a block (multi
   -- line) comment. Block comments may be nested. How comments are
   -- started and ended is defined by this method.
-  whiteSpace       :: m ()
-  
-  -- | @lexeme p@ first applies parser @p@ and then the 'whiteSpace'
-  -- parser, returning the value of @p@. Every lexical
-  -- token (lexeme) is defined using @lexeme@, this way every parse
-  -- starts at a point without white space. Parsers that use @lexeme@ are
-  -- called /lexeme/ parsers in this document.
-  -- 
-  -- The only point where the 'whiteSpace' parser should be
-  -- called explicitly is the start of the main parser in order to skip
-  -- any leading white space.
-  --
-  -- >    mainParser  = do { whiteSpace
-  -- >                     ; ds <- many (lexeme digit)
-  -- >                     ; eof
-  -- >                     ; return (sum ds)
-  -- >                     }
-  lexeme :: m a -> m a
-  lexeme p = p <* whiteSpace
+  whiteSpace :: m ()
 
+  -- | Called when we enter a nested pair of symbols. Used to disable
+  -- layout or highlight nested contexts.
+  nesting :: m a -> m a
+
+  -- | Lexeme parser |semi| parses the character \';\' and skips any
+  -- trailing white space. Returns the character \';\'.‗
+  semi :: m Char
+
 instance MonadTokenParser m => MonadTokenParser (ReaderT r m) where
   whiteSpace = lift whiteSpace
-  lexeme (ReaderT m) = ReaderT $ lexeme . m
+  nesting (ReaderT m) = ReaderT $ \r -> nesting (m r)
+  semi = lift semi
 
 instance MonadTokenParser m => MonadTokenParser (Lazy.StateT s m) where
   whiteSpace = lift whiteSpace
-  lexeme (Lazy.StateT m) = Lazy.StateT $ lexeme . m
+  nesting (Lazy.StateT m) = Lazy.StateT $ \s -> nesting (m s)
+  semi = lift semi
 
 instance MonadTokenParser m => MonadTokenParser (Strict.StateT s m) where
   whiteSpace = lift whiteSpace
-  lexeme (Strict.StateT m) = Strict.StateT $ lexeme . m
+  nesting (Strict.StateT m) = Strict.StateT $ \s -> nesting (m s)
+  semi = lift semi
 
 instance (MonadTokenParser m, Monoid w) => MonadTokenParser (Lazy.WriterT w m) where
   whiteSpace = lift whiteSpace
-  lexeme (Lazy.WriterT m) = Lazy.WriterT $ lexeme m
+  nesting (Lazy.WriterT m) = Lazy.WriterT $ nesting m
+  semi = lift semi
 
 instance (MonadTokenParser m, Monoid w) => MonadTokenParser (Strict.WriterT w m) where
   whiteSpace = lift whiteSpace
-  lexeme (Strict.WriterT m) = Strict.WriterT $ lexeme m
+  nesting (Strict.WriterT m) = Strict.WriterT $ nesting m
+  semi = lift semi
 
 instance (MonadTokenParser m, Monoid w) => MonadTokenParser (Lazy.RWST r w s m) where
   whiteSpace = lift whiteSpace
-  lexeme (Lazy.RWST m) = Lazy.RWST $ \r s -> lexeme (m r s)
+  nesting (Lazy.RWST m) = Lazy.RWST $ \r s -> nesting (m r s)
+  semi = lift semi
 
 instance (MonadTokenParser m, Monoid w) => MonadTokenParser (Strict.RWST r w s m) where
   whiteSpace = lift whiteSpace
-  lexeme (Strict.RWST m) = Strict.RWST $ \r s -> lexeme (m r s)
+  nesting (Strict.RWST m) = Strict.RWST $ \r s -> nesting (m r s)
+  semi = lift semi
 
 instance MonadTokenParser m => MonadTokenParser (IdentityT m) where
   whiteSpace = lift whiteSpace
-  lexeme = IdentityT . lexeme . runIdentityT
+  nesting (IdentityT m) = IdentityT (nesting m)
+  semi = lift semi
diff --git a/Text/Trifecta/Parser/Token/Combinators.hs b/Text/Trifecta/Parser/Token/Combinators.hs
--- a/Text/Trifecta/Parser/Token/Combinators.hs
+++ b/Text/Trifecta/Parser/Token/Combinators.hs
@@ -11,7 +11,8 @@
 -- 
 -----------------------------------------------------------------------------
 module Text.Trifecta.Parser.Token.Combinators
-  ( charLiteral
+  ( lexeme
+  , charLiteral
   , stringLiteral
   , natural
   , integer
@@ -23,7 +24,6 @@
   , braces
   , angles
   , brackets
-  , semi
   , comma
   , colon
   , dot
@@ -42,6 +42,24 @@
 import Text.Trifecta.Parser.Token.Prim
 import Text.Trifecta.Highlight.Prim
 
+-- | @lexeme p@ first applies parser @p@ and then the 'whiteSpace'
+-- parser, returning the value of @p@. Every lexical
+-- token (lexeme) is defined using @lexeme@, this way every parse
+-- starts at a point without white space. Parsers that use @lexeme@ are
+-- called /lexeme/ parsers in this document.
+--
+-- The only point where the 'whiteSpace' parser should be
+-- called explicitly is the start of the main parser in order to skip
+-- any leading white space.
+--
+-- >    mainParser  = do { whiteSpace
+-- >                     ; ds <- many (lexeme digit)
+-- >                     ; eof
+-- >                     ; return (sum ds)
+-- >                     }
+lexeme :: MonadTokenParser m => m a -> m a
+lexeme p = p <* whiteSpace
+
 -- | This lexeme parser parses a single literal character. Returns the
 -- literal character value. This parsers deals correctly with escape
 -- sequences. The literal character is parsed according to the grammar
@@ -114,31 +132,25 @@
 -- returning the value of @p@.
 
 parens :: MonadTokenParser m => m a -> m a
-parens = between (symbolic '(') (symbolic ')')
+parens = nesting . between (symbolic '(') (symbolic ')')
 
 -- | Lexeme parser @braces p@ parses @p@ enclosed in braces (\'{\' and
 -- \'}\'), returning the value of @p@. 
 
 braces :: MonadTokenParser m => m a -> m a
-braces = between (symbolic '{') (symbolic '}')
+braces = nesting . between (symbolic '{') (symbolic '}')
 
 -- | Lexeme parser @angles p@ parses @p@ enclosed in angle brackets (\'\<\'
 -- and \'>\'), returning the value of @p@. 
 
 angles :: MonadTokenParser m => m a -> m a
-angles = between (symbolic '<') (symbolic '>')
+angles = nesting . between (symbolic '<') (symbolic '>')
 
 -- | Lexeme parser @brackets p@ parses @p@ enclosed in brackets (\'[\'
 -- and \']\'), returning the value of @p@. 
 
 brackets :: MonadTokenParser m => m a -> m a
-brackets = between (symbolic '<') (symbolic '>')
-
--- | Lexeme parser |semi| parses the character \';\' and skips any
--- trailing white space. Returns the string \";\". 
-
-semi :: MonadTokenParser m => m Char
-semi = symbolic ';'
+brackets = nesting . between (symbolic '[') (symbolic ']')
 
 -- | Lexeme parser @comma@ parses the character \',\' and skips any
 -- trailing white space. Returns the string \",\". 
diff --git a/Text/Trifecta/Parser/Token/Identifier.hs b/Text/Trifecta/Parser/Token/Identifier.hs
--- a/Text/Trifecta/Parser/Token/Identifier.hs
+++ b/Text/Trifecta/Parser/Token/Identifier.hs
@@ -29,6 +29,7 @@
 import Text.Trifecta.Parser.Char
 import Text.Trifecta.Parser.Combinators
 import Text.Trifecta.Parser.Token.Class
+import Text.Trifecta.Parser.Token.Combinators
 import Text.Trifecta.Highlight.Prim
 
 data IdentifierStyle m = IdentifierStyle
diff --git a/Text/Trifecta/Parser/Token/Style.hs b/Text/Trifecta/Parser/Token/Style.hs
--- a/Text/Trifecta/Parser/Token/Style.hs
+++ b/Text/Trifecta/Parser/Token/Style.hs
@@ -20,17 +20,19 @@
 import Data.Char (isSpace)
 import Control.Applicative
 import Data.List (nub)
+import qualified Data.ByteString.Char8 as B
 import Text.Trifecta.Parser.Class
 import Text.Trifecta.Parser.Char
 import Text.Trifecta.Parser.Combinators
+import Text.Trifecta.Rope.Delta
 import Text.Trifecta.Highlight.Prim
 
-data CommentStyle = CommentStyle 
+data CommentStyle = CommentStyle
   { commentStart   :: String
   , commentEnd     :: String
   , commentLine    :: String
   , commentNesting :: Bool
-  } 
+  }
 
 emptyCommentStyle, javaCommentStyle, haskellCommentStyle :: CommentStyle
 emptyCommentStyle   = CommentStyle "" "" "" True
@@ -50,8 +52,9 @@
     simpleSpace = skipSome (satisfy isSpace)
     oneLineComment = highlight Comment $ do
       _ <- try $ string lineStyle
-      skipMany (satisfyAscii (/= '\n')) -- TODO: use skipping/restOfLine and fiddle with the last byte
-      return ()
+      r <- restOfLine
+      let b = B.length r
+      skipping $ if b /= 0 && B.last r == '\n' then Lines 1 0 (fromIntegral b) 0 else delta r
     multiLineComment = highlight Comment $ do
       _ <- try $ string startStyle
       inComment
diff --git a/Text/Trifecta/Rope/Delta.hs b/Text/Trifecta/Rope/Delta.hs
--- a/Text/Trifecta/Rope/Delta.hs
+++ b/Text/Trifecta/Rope/Delta.hs
@@ -9,8 +9,8 @@
 -- Portability :  non-portable
 --
 ----------------------------------------------------------------------------
-module Text.Trifecta.Rope.Delta 
-  ( Delta(..) 
+module Text.Trifecta.Rope.Delta
+  ( Delta(..)
   , HasDelta(..)
   , nextTab
   , rewind
@@ -68,7 +68,7 @@
     Tab x y _ -> k f 0 (nextTab x + y)
     Lines l c _ _ -> k f l c
     Directed fn l c _ _ -> k (UTF8.toString fn) l c
-    where 
+    where
       k fn ln cn = bold (pretty fn) <> char ':' <> bold (int64 (ln+1)) <> char ':' <> bold (int64 (cn+1))
       f = "(interactive)"
 
@@ -76,7 +76,7 @@
 int64 = pretty . show
 
 column :: HasDelta t => t -> Int64
-column t = case delta t of 
+column t = case delta t of
   Columns c _ -> c
   Tab b a _ -> nextTab b + a
   Lines _ c _ _ -> c
@@ -116,9 +116,9 @@
   Lines l _ t _      <> Lines m d t' b      = Lines      (l + m) d                         (t + t') b
   Lines _ _ t _      <> Directed p l c t' a = Directed p l       c                         (t + t') a
   Tab x y a          <> Columns d b         = Tab                x (y + d)                          (a + b)
-  Tab x y a          <> Tab x' y' b         = Tab                x (nextTab (y + x') + y')          (a + b) 
+  Tab x y a          <> Tab x' y' b         = Tab                x (nextTab (y + x') + y')          (a + b)
   Tab _ _ a          <> Lines l c t a'      = Lines      l       c                         (t + a ) a'
-  Tab _ _ a          <> Directed p l c t a' = Directed p l       c                         (t + a ) a' 
+  Tab _ _ a          <> Directed p l c t a' = Directed p l       c                         (t + a ) a'
   Directed p l c t a <> Columns d b         = Directed p l       (c + d)                   (t + b ) (a + b)
   Directed p l c t a <> Tab x y b           = Directed p l       (nextTab (c + x) + y)     (t + b ) (a + b)
   Directed p l _ t _ <> Lines m d t' b      = Directed p (l + m) d                         (t + t') b
@@ -131,7 +131,7 @@
 rewind :: Delta -> Delta
 rewind (Lines n _ b d)      = Lines n 0 (b - d) 0
 rewind (Directed p n _ b d) = Directed p n 0 (b - d) 0
-rewind _                    = Columns 0 0 
+rewind _                    = Columns 0 0
 {-# INLINE rewind #-}
 
 near :: (HasDelta s, HasDelta t) => s -> t -> Bool
@@ -147,7 +147,7 @@
 instance HasDelta Char where
   delta '\t' = Tab 0 0 1
   delta '\n' = Lines 1 0 1 0
-  delta c 
+  delta c
     | o <= 0x7f   = Columns 1 1
     | o <= 0x7ff  = Columns 1 2
     | o <= 0xffff = Columns 1 3
@@ -157,7 +157,7 @@
 instance HasDelta Word8 where
   delta 9  = Tab 0 0 1
   delta 10 = Lines 1 0 1 0
-  delta n 
+  delta n
     | n <= 0x7f              = Columns 1 1
     | n >= 0xc0 && n <= 0xf4 = Columns 1 1
     | otherwise              = Columns 0 1
diff --git a/examples/RFC2616.hs b/examples/RFC2616.hs
--- a/examples/RFC2616.hs
+++ b/examples/RFC2616.hs
@@ -41,6 +41,7 @@
                        <*  skipHSpaces 
                        <*> (highlight Identifier (some (satisfy (not . isHSpace))) <?> "url")
                        <*  skipHSpaces 
+                       -- <*> try (highlight ReservedIdentifier (string "HTTP/" *> many httpVersion <* endOfLine) <?> "protocol")
                        <*> (try (highlight ReservedIdentifier (string "HTTP/" *> many httpVersion <* endOfLine)) <?> "protocol")
  where
   httpVersion = satisfy $ \c -> c == '1' || c == '0' || c == '.' || c == '9'
diff --git a/trifecta.cabal b/trifecta.cabal
--- a/trifecta.cabal
+++ b/trifecta.cabal
@@ -1,6 +1,6 @@
 name:          trifecta
 category:      Text, Parsing, Diagnostics, Pretty Printer, Logging
-version:       0.41
+version:       0.42
 license:       BSD3
 cabal-version: >= 1.6
 license-file:  LICENSE
@@ -10,12 +10,12 @@
 homepage:      http://github.com/ekmett/trifecta/
 copyright:     Copyright (C) 2010-2011 Edward A. Kmett
 synopsis:      A modern parser combinator library with convenient diagnostics
-description:   
+description:
   A modern unicode-aware parser combinator library with slicing and Clang-style colored diagnostics
   .
   Current documentation is available from <http://ekmett.github.com/trifecta/>.
 
-build-type:    Simple  
+build-type:    Simple
 extra-source-files:
   examples/RFC2616.hs
 
@@ -67,6 +67,8 @@
     Text.Trifecta.Parser.Combinators
     Text.Trifecta.Parser.Expr
     Text.Trifecta.Parser.It
+    Text.Trifecta.Parser.Layout
+    Text.Trifecta.Parser.Layout.Class
     Text.Trifecta.Parser.Perm
     Text.Trifecta.Parser.Prim
     Text.Trifecta.Parser.Result
@@ -84,18 +86,20 @@
 
   ghc-options: -Wall
 
-  build-depends: 
+  build-depends:
     base                 >= 4       && < 5,
-    array                >= 0.3.0.2 && < 0.4, 
+    array                >= 0.3.0.2 && < 0.4,
     containers           >= 0.3     && < 0.5,
     unordered-containers >= 0.1.4   && < 0.2,
     blaze-builder        >= 0.3.0.1 && < 0.4,
     blaze-html           >= 0.4.1.6 && < 0.5,
     bifunctors           >= 0.1.2   && < 0.2,
+    data-lens            >= 2.0.1   && < 2.1,
+    data-lens-fd         >= 2.0     && < 2.1,
     hashable             >= 1.1.2.1 && < 1.2,
     bytestring           >= 0.9.1   && < 0.10,
     mtl                  >= 2.0.1   && < 2.1,
-    semigroups           >= 0.8     && < 0.9, 
+    semigroups           >= 0.8     && < 0.9,
     fingertree           >= 0.0.1   && < 0.1,
     reducers             >= 0.1.6   && < 0.2,
     profunctors          >= 0.1.1   && < 0.2,
