diff --git a/Text/Trifecta.hs b/Text/Trifecta.hs
--- a/Text/Trifecta.hs
+++ b/Text/Trifecta.hs
@@ -13,6 +13,7 @@
   , module Text.Trifecta.Supply
   , module Text.Trifecta.Render
   , module Text.Trifecta.Rendered
+  , module Text.Trifecta.Diagnostic
   ) where
 
 import Text.Trifecta.It
@@ -29,3 +30,4 @@
 import Text.Trifecta.Supply
 import Text.Trifecta.Render
 import Text.Trifecta.Rendered
+import Text.Trifecta.Diagnostic
diff --git a/Text/Trifecta/Delta.hs b/Text/Trifecta/Delta.hs
--- a/Text/Trifecta/Delta.hs
+++ b/Text/Trifecta/Delta.hs
@@ -7,15 +7,19 @@
   , column
   ) where
 
+import Control.Applicative
 import Data.Monoid
 import Data.Semigroup
 import Data.Hashable
 import Data.Word
+import Data.Interned
 import Data.Foldable
-import Data.FingerTree
-import Data.ByteString
+import Data.FingerTree hiding (empty)
+import Data.ByteString hiding (empty)
 import Text.Trifecta.Path
 import Text.Trifecta.Bytes
+import Text.PrettyPrint.Free hiding (column)
+import System.Console.Terminfo.PrettyPrint
 
 data Delta
   = Columns   {-# UNPACK #-} !Int  -- the number of characters
@@ -33,6 +37,22 @@
               {-# UNPACK #-} !Int  -- number of bytes
               {-# UNPACK #-} !Int  -- the number of bytes since the last newline
   deriving (Eq, Ord, Show)
+
+instance Pretty Delta where
+  pretty p = prettyTerm p *> empty
+
+instance PrettyTerm Delta where
+  prettyTerm d = case d of
+    Columns c _ -> k "-" 1 c
+    Tab x y _ -> k "-" 1 (nextTab x + y)
+    Lines l c _ _ -> k "-" l c
+    Directed (Path _ _ _ fn _ _) l c _ _ -> k (maybeFileName "-" unintern fn) l c  -- TODO: add include path
+    where 
+      k fn ln cn = bold (string fn)           
+                <> char ':' 
+                <> bold (int ln)         
+                <> char ':' 
+                <> bold (int (cn + 1))
 
 column :: HasDelta t => t -> Int
 column t = case delta t of 
diff --git a/Text/Trifecta/Diagnostic.hs b/Text/Trifecta/Diagnostic.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Diagnostic.hs
@@ -0,0 +1,115 @@
+module Text.Trifecta.Diagnostic 
+  ( DiagnosticLevel(..)
+  , Diagnostic(..)
+  ) where
+
+import Control.Applicative
+import Control.Comonad
+import Data.Bifunctor
+import Data.Functor.Apply
+import Data.Bifoldable
+import Data.Bitraversable
+import Data.Foldable
+import Data.Traversable
+import Data.Monoid
+import Data.List.NonEmpty hiding (map)
+import Data.Semigroup
+import Data.Semigroup.Foldable
+import Data.Semigroup.Traversable
+import Data.Semigroup.Bifoldable
+import Data.Semigroup.Bitraversable
+import Text.Trifecta.Bytes
+import Text.Trifecta.Delta
+import Text.Trifecta.Render
+import Text.PrettyPrint.Free
+import System.Console.Terminfo.PrettyPrint
+
+data DiagnosticLevel = Note | Warning | Error | Fatal
+  deriving (Eq,Ord,Show,Read)
+
+instance Semigroup DiagnosticLevel where
+  (<>) = max
+
+instance Pretty DiagnosticLevel where
+  pretty p = prettyTerm p *> empty
+
+instance PrettyTerm DiagnosticLevel where
+  prettyTerm Note    = text "note"
+  prettyTerm Warning = magenta $ text "warning"
+  prettyTerm Error   = red $ text "error"
+  prettyTerm Fatal   = red $ text "fatal"
+
+data Diagnostic l m = Diagnostic !Render l m [Diagnostic l m]
+
+instance Renderable (Diagnostic l m) where
+  render (Diagnostic r _ _ _) = r
+
+instance HasDelta (Diagnostic l m) where
+  delta (Diagnostic r _ _ _) = delta r
+
+instance HasBytes (Diagnostic l m) where
+  bytes = bytes . delta
+
+instance Extend (Diagnostic l) where
+  extend f d@(Diagnostic r l _ xs) = Diagnostic r l (f d) (map (extend f) xs)
+
+instance Comonad (Diagnostic l) where
+  extract (Diagnostic _ _ m _) = m
+
+instance (Pretty l, Pretty m) => Pretty (Diagnostic l m) where
+  pretty (Diagnostic r l m xs) = vsep $
+    [ pretty (delta r) <> char ':' <+> pretty l <> char ':' <+> pretty m
+    , pretty r
+    ] ++ if Prelude.null xs then [] else [indent 2 (prettyList xs)]
+  prettyList = Prelude.foldr ((<>) . pretty) empty
+
+instance (PrettyTerm l, PrettyTerm m) => PrettyTerm (Diagnostic l m) where
+  prettyTerm (Diagnostic r l m xs) = vsep $ 
+    [ prettyTerm (delta r) <> char ':' <+> prettyTerm l <> char ':' <+> prettyTerm m
+    , prettyTerm r
+    ] ++ if Prelude.null xs then [] else [indent 2 (prettyTermList xs)]
+  prettyTermList = Prelude.foldr ((<>) . prettyTerm) empty
+
+
+instance (Pretty l, Pretty m) => Show (Diagnostic l m) where
+  showsPrec d = showsPrec d . pretty
+
+instance Functor (Diagnostic l) where
+  fmap f (Diagnostic r l m xs) = Diagnostic r l (f m) $ map (fmap f) xs
+
+instance Bifunctor Diagnostic where
+  bimap f g (Diagnostic r l m xs) = Diagnostic r (f l) (g m) $ map (bimap f g) xs
+
+instance Foldable (Diagnostic l) where
+  foldMap f (Diagnostic _ _ m xs) = f m `mappend` foldMap (foldMap f) xs
+
+instance Traversable (Diagnostic l) where
+  traverse f (Diagnostic r l m xs) = Diagnostic r l <$> f m <*> traverse (traverse f) xs
+
+instance Foldable1 (Diagnostic l) where
+  foldMap1 f (Diagnostic _ _ m []) = f m
+  foldMap1 f (Diagnostic _ _ m (x:xs)) = f m <> foldMap1 (foldMap1 f) (x:|xs)
+
+instance Traversable1 (Diagnostic l) where
+  traverse1 f (Diagnostic r l m [])     = fmap (\fm -> Diagnostic r l fm []) (f m)
+  traverse1 f (Diagnostic r l m (x:xs)) = (\fm (y:|ys) -> Diagnostic r l fm (y:ys)) 
+                                      <$> f m 
+                                      <.> traverse1 (traverse1 f) (x:|xs)
+
+instance Bifoldable Diagnostic where
+  bifoldMap f g (Diagnostic _ l m xs) = f l `mappend` g m `mappend` foldMap (bifoldMap f g) xs
+
+instance Bitraversable Diagnostic where
+  bitraverse f g (Diagnostic r l m xs) = Diagnostic r <$> f l <*>  g m <*> traverse (bitraverse f g) xs
+  
+instance Bifoldable1 Diagnostic where
+  bifoldMap1 f g (Diagnostic _ l m [])     = f l <> g m
+  bifoldMap1 f g (Diagnostic _ l m (x:xs)) = f l <> g m <> foldMap1 (bifoldMap1 f g) (x:|xs)
+
+instance Bitraversable1 Diagnostic where
+  bitraverse1 f g (Diagnostic r l m [])     = (\fl gm -> Diagnostic r fl gm []) <$> f l <.> g m
+  bitraverse1 f g (Diagnostic r l m (x:xs)) = (\fl gm (y:|ys) -> Diagnostic r fl gm (y:ys)) 
+                                      <$> f l
+                                      <.> g m
+                                      <.> traverse1 (bitraverse1 f g) (x:|xs)
+
diff --git a/Text/Trifecta/Path.hs b/Text/Trifecta/Path.hs
--- a/Text/Trifecta/Path.hs
+++ b/Text/Trifecta/Path.hs
@@ -7,6 +7,9 @@
   , path
   , appendPath
   , comparablePath
+  -- * Internals
+  , MaybeFileName(..)
+  , maybeFileName
   ) where
 
 import Data.Hashable
@@ -37,6 +40,10 @@
 data History = Continue !Path {-# UNPACK #-} !Int | Complete deriving (Eq, Show)
 
 data MaybeFileName = JustFileName !FileName | NothingFileName deriving (Eq, Show)
+
+maybeFileName :: r -> (FileName -> r) -> MaybeFileName -> r
+maybeFileName n _ NothingFileName  = n
+maybeFileName _ f (JustFileName a) = f a
 
 file :: String -> Path 
 file !n = path Complete (JustFileName (intern n)) 0 []
diff --git a/Text/Trifecta/Render.hs b/Text/Trifecta/Render.hs
--- a/Text/Trifecta/Render.hs
+++ b/Text/Trifecta/Render.hs
@@ -19,7 +19,7 @@
 import Text.Trifecta.Delta
 import Data.Semigroup
 import Data.Array
-import Text.PrettyPrint.Leijen.Extras hiding (column)
+import Text.PrettyPrint.Free hiding (column)
 import System.Console.Terminfo.PrettyPrint
 import Control.Monad.State
 import Prelude as P
@@ -102,9 +102,9 @@
 
 instance PrettyTerm Render where
   prettyTerm (Render d ll l f) = nesting $ \k -> columns $ \n -> go (n - k) where
-    go cols = align (vsep (P.map ln [t..b])) <> linebreak where 
+    go cols = align (vsep (P.map ln [t..b])) where 
       (lo, hi) = window (column d) ll (cols - 2)
-      a = f d $ l $ array ((0,lo),(-1,hi)) [] -- blankLine lo hi
+      a = f d $ l $ array ((0,lo),(-1,hi)) []
       ((t,_),(b,_)) = bounds a
       ln y = hcat 
            $ P.map (\g -> P.foldr with (string (P.map snd g)) (fst (P.head g)))
diff --git a/trifecta.cabal b/trifecta.cabal
--- a/trifecta.cabal
+++ b/trifecta.cabal
@@ -1,6 +1,6 @@
 name:          trifecta
 category:      Text, Parsing
-version:       0.10
+version:       0.11
 license:       BSD3
 cabal-version: >= 1.6
 license-file:  LICENSE
@@ -22,6 +22,7 @@
     base               >= 4       && < 5,
     array              >= 0.3.0.2 && < 0.4, 
     containers         >= 0.3     && < 0.5,
+    bifunctors         >= 0.1.1.3 && < 0.2,
     intern             >= 0.5.1.1 && < 0.6,
     hashable           >= 1.1.2.1 && < 1.2,
     bytestring         >= 0.9.1   && < 0.10,
@@ -35,9 +36,9 @@
     parallel           >= 3.1.0.1 && < 3.2,
     transformers       >= 0.2.2   && < 0.3,
     comonad            >= 1.1.1   && < 1.2,
-    wl-pprint-extras   >= 1.2.2   && < 1.3,
-    wl-pprint-terminfo >= 0.2.1.3 && < 0.3,
-    terminfo           >= 0.3.2   && < 0.4
+    terminfo           >= 0.3.2   && < 0.4,
+    wl-pprint-extras   >= 1.4     && < 1.5,
+    wl-pprint-terminfo >= 0.4     && < 0.5
 
   ghc-options: -Wall
 
@@ -47,9 +48,9 @@
     Text.Trifecta.Path
     Text.Trifecta.Rope
     Text.Trifecta.Hunk
+    Text.Trifecta.Span
     Text.Trifecta.Bytes
     Text.Trifecta.Caret
-    Text.Trifecta.Span
     Text.Trifecta.Fixit
     Text.Trifecta.Delta
     Text.Trifecta.Slice
@@ -57,6 +58,7 @@
     Text.Trifecta.Supply
     Text.Trifecta.Render
     Text.Trifecta.Rendered
+    Text.Trifecta.Diagnostic
 
   other-modules:
     Text.Trifecta.Util
