diff --git a/Text/Trifecta.hs b/Text/Trifecta.hs
--- a/Text/Trifecta.hs
+++ b/Text/Trifecta.hs
@@ -1,17 +1,23 @@
 module Text.Trifecta 
-  ( module Text.Trifecta.Cursor
-  , module Text.Trifecta.Delta
+  ( module Text.Trifecta.It
   , module Text.Trifecta.Hunk
-  , module Text.Trifecta.It
   , module Text.Trifecta.Path
   , module Text.Trifecta.Rope
+  , module Text.Trifecta.Bytes
+  , module Text.Trifecta.Caret
+  , module Text.Trifecta.Delta
+  , module Text.Trifecta.Strand
   , module Text.Trifecta.Supply
+  , module Text.Trifecta.Parser
   ) where
 
-import Text.Trifecta.Cursor
-import Text.Trifecta.Delta
-import Text.Trifecta.Hunk
 import Text.Trifecta.It
+import Text.Trifecta.Hunk
 import Text.Trifecta.Path
 import Text.Trifecta.Rope
+import Text.Trifecta.Caret
+import Text.Trifecta.Bytes
+import Text.Trifecta.Delta
+import Text.Trifecta.Strand
 import Text.Trifecta.Supply
+import Text.Trifecta.Parser
diff --git a/Text/Trifecta/Bytes.hs b/Text/Trifecta/Bytes.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Bytes.hs
@@ -0,0 +1,15 @@
+module Text.Trifecta.Bytes
+  ( HasBytes(..)
+  ) where
+
+import Data.ByteString as Strict
+import Data.FingerTree
+
+class HasBytes t where
+  bytes :: t -> Int
+
+instance HasBytes ByteString where
+  bytes = Strict.length
+
+instance (Measured v a, HasBytes v) => HasBytes (FingerTree v a) where
+  bytes = bytes . measure
diff --git a/Text/Trifecta/Caret.hs b/Text/Trifecta/Caret.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Caret.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, BangPatterns, PatternGuards #-}
+module Text.Trifecta.Caret
+  ( Caret(..)
+  , HasCaret(..)
+  , Careted(..)
+  , Cover(..)
+  , HasCover(..)
+  , Covered(..)
+  , Fixit(..)
+  , Diagnostic(..)
+  ) where
+
+import Data.Hashable
+import Data.ByteString as Strict
+import Text.Trifecta.Delta
+
+-- |
+-- > In file included from baz.c:9
+-- > In file included from bar.c:4
+-- > foo.c:8:36: note
+-- > int main(int argc, char ** argv) { int; }
+-- >                                    ^
+data Caret = Caret !Delta {-# UNPACK #-} !ByteString deriving (Eq,Ord,Show)
+
+instance Hashable Caret where
+  hash (Caret d bs) = hash d `hashWithSalt` bs
+
+class HasCaret t where
+  caret :: t -> Caret
+
+instance HasCaret Caret where
+  caret = id
+
+data Careted a = a :^ Caret deriving (Eq,Ord,Show)
+
+instance HasCaret (Careted a) where
+  caret (_ :^ c) = c
+
+instance Hashable a => Hashable (Careted a) where
+  
+-- |
+-- > In file included from bar.c:9
+-- > foo.c:8:36: note
+-- > int main(int argc, char ** argv) { int; }
+-- >                                    ^~~
+data Cover = Cover {-# UNPACK #-} !Caret !Delta deriving (Eq,Ord,Show)
+
+instance HasCaret Cover where
+  caret (Cover c _) = c
+
+class HasCover t where
+  cover :: t -> Cover
+
+instance HasCover Cover where
+  cover = id
+
+data Covered a = a :~ Cover deriving (Eq,Ord,Show)
+
+instance HasCover (Covered a) where
+  cover (_ :~ c) = c
+
+instance HasCaret (Covered a) where
+  caret = caret . cover
+
+instance Hashable Cover where
+  hash (Cover c bs) = hash c `hashWithSalt` bs
+
+instance Hashable a => Hashable (Covered a) where
+  hash (a :~ s) = hash a `hashWithSalt` s
+
+-- |
+-- > In file included from bar.c:12
+-- > foo.c:12:17: note
+-- > int main(int argc char ** argv) { int; }
+-- >                  ^
+-- >                  ,
+data Fixit = Fixit 
+  { fixitCover        :: {-# UNPACK #-} !Cover
+  , fixitReplacement  :: {-# UNPACK #-} !ByteString 
+  } deriving (Eq,Ord,Show)
+
+instance HasCover Fixit where
+  cover (Fixit s _) = s
+
+instance HasCaret Fixit where
+  caret = caret . cover
+
+instance Hashable Fixit where
+  hash (Fixit s b) = hash s `hashWithSalt` b
+
+-- |
+-- > In file included from bar.h:12
+-- > baz.h:12:17: note
+-- > foo + bar
+-- > ~~~ ^ ~~~
+data Diagnostic = Diagnostic !Caret [Cover] [Fixit]
+
+instance HasCaret Diagnostic where
+  caret (Diagnostic c _ _) = c
+
+instance Hashable Diagnostic where
+  hash (Diagnostic c ss fs) = hash c `hashWithSalt` ss `hashWithSalt` fs
diff --git a/Text/Trifecta/Cursor.hs b/Text/Trifecta/Cursor.hs
deleted file mode 100644
--- a/Text/Trifecta/Cursor.hs
+++ /dev/null
@@ -1,34 +0,0 @@
-module Text.Trifecta.Cursor 
-  ( Cursor(..)
-  ) where
-
-import Data.Hashable
-import Data.Monoid
-import Data.Sequence
-import Data.Interned
-import Data.Semigroup
-import Data.Foldable
-
-import Text.Trifecta.Delta
-
-data Cursor = Cursor 
-  { cursorBytes   :: {-# UNPACK #-} !Int
-  , cursorDelta   :: !Delta
-  , cursorSeqHash :: {-# UNPACK #-} !Int
-  , cursorSeq     :: !(Seq Id)
-  } deriving Show
-
-
-instance Eq Cursor where
-  Cursor _ _ h k == Cursor _ _ h' k' = h == h' && k == k'
-
-instance Hashable Cursor where
-  hash (Cursor _ _ _ s) = hash (toList s)
-    
-instance Monoid Cursor where
-  mempty = Cursor 0 mempty 0 mempty
-  Cursor s d l q `mappend` Cursor s' d' l' q' = Cursor (s + s') (d <> d') (l + l') (q <> q')
-
-instance Semigroup Cursor where
-  Cursor s d l q <> Cursor s' d' l' q' = Cursor (s + s') (d <> d') (l + l') (q <> q')
-
diff --git a/Text/Trifecta/Delta.hs b/Text/Trifecta/Delta.hs
--- a/Text/Trifecta/Delta.hs
+++ b/Text/Trifecta/Delta.hs
@@ -2,6 +2,8 @@
   ( Delta(..) 
   , HasDelta(..)
   , nextTab
+  , rewind
+  , near
   ) where
 
 import Data.Monoid
@@ -9,65 +11,102 @@
 import Data.Hashable
 import Data.Word
 import Data.Foldable
+import Data.FingerTree
 import Data.ByteString
 import Text.Trifecta.Path
+import Text.Trifecta.Bytes
 
 data Delta
-  = Directed                 !Path -- ^ the sequence of #line directives since the start of the file
-              {-# UNPACK #-} !Int  -- ^ the number of lines since the last line directive
+  = Columns   {-# UNPACK #-} !Int  -- ^ the number of characters
+              {-# UNPACK #-} !Int  -- ^ the number of bytes
+  | Tab       {-# UNPACK #-} !Int  -- ^ the number of characters before the tab
+              {-# UNPACK #-} !Int  -- ^ the number of characters after the tab
+              {-# UNPACK #-} !Int  -- ^ the number of bytes
+  | Lines     {-# UNPACK #-} !Int  -- ^ the number of newlines contained
               {-# UNPACK #-} !Int  -- ^ the number of characters since the last newline
+              {-# UNPACK #-} !Int  -- ^ number of bytes
               {-# UNPACK #-} !Int  -- ^ the number of bytes since the last newline
-  | Lines     {-# UNPACK #-} !Int  -- ^ the number of newlines contained
+  | Directed                 !Path -- ^ the sequence of #line directives since the start of the file
+              {-# UNPACK #-} !Int  -- ^ the number of lines since the last line directive
               {-# UNPACK #-} !Int  -- ^ the number of characters since the last newline
+              {-# UNPACK #-} !Int  -- ^ number of bytes
               {-# UNPACK #-} !Int  -- ^ the number of bytes since the last newline
-  | Tab       {-# UNPACK #-} !Int  -- ^ the number of characters before the tab
-              {-# UNPACK #-} !Int  -- ^ the number of characters after the tab
-              {-# UNPACK #-} !Int  -- ^ the number of bytes in this range
-  | Columns   {-# UNPACK #-} !Int  -- ^ the number of characters
-              {-# UNPACK #-} !Int  -- ^ the number of bytes
-  deriving Show
+  deriving (Eq, Ord, Show)
 
+instance HasBytes Delta where
+  bytes (Columns _ b) = b
+  bytes (Tab _ _ b) = b
+  bytes (Lines _ _ b _) = b
+  bytes (Directed _ _ _ b _) = b
+
 instance Hashable Delta where
-  hash (Columns c a)      = 0 `hashWithSalt` c `hashWithSalt` a
-  hash (Tab x y a)        = 1 `hashWithSalt` x `hashWithSalt` y `hashWithSalt` a
-  hash (Lines l c a)      = 2 `hashWithSalt` l `hashWithSalt` c `hashWithSalt` a
-  hash (Directed p l c a) = 3 `hashWithSalt` p `hashWithSalt` l `hashWithSalt` c `hashWithSalt` a
+  hash (Columns c a)        = 0 `hashWithSalt` c `hashWithSalt` a
+  hash (Tab x y a)          = 1 `hashWithSalt` x `hashWithSalt` y `hashWithSalt` a
+  hash (Lines l c b a)      = 2 `hashWithSalt` l `hashWithSalt` c `hashWithSalt` b `hashWithSalt` a
+  hash (Directed p l c b a) = 3 `hashWithSalt` p `hashWithSalt` l `hashWithSalt` c `hashWithSalt` b `hashWithSalt` a
 
 instance Monoid Delta where
   mempty = Columns 0 0
   mappend = (<>)
 
 instance Semigroup Delta where
-  Columns c a      <> Columns d b         = Columns (c + d) (a + b)
-  Columns c a      <> Tab x y b           = Tab (c + x) y (a + b)
-  Lines l c a      <> Columns d b         = Lines l (c + d) (a + b)
-  Lines l _ _      <> Lines m d b         = Lines (l + m) d b
-  Lines l c a      <> Tab x y b           = Lines l (nextTab (c + x) + y) (a + b)
-  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) 
-  Directed p l _ a <> Lines m d b         = Directed p (l + m) d (a + b)
-  Directed p l c a <> Columns d b         = Directed p l (c + d) (a + b)
-  Directed p l c a <> Tab x y b           = Directed p l (nextTab (c + x) + y) (a + b)
-  Directed p l _ _ <> Directed p' l' c' b = Directed (appendPath p l p') l' c' b
-  _                <> t                   = t
+  Columns c a        <> Columns d b            = Columns (c + d) (a + b)
+  Columns c a        <> Tab x y b              = Tab (c + x) y (a + b)
+  Columns _ a        <> Lines l c t a'         = Lines l c (t + a) a'
+  Columns _ a        <> Directed p l c t a'    = Directed p l c (t + a) a'
+  Lines l c t a      <> Columns d b            = Lines l (c + d) (t + b) (a + b)
+  Lines l c t a      <> Tab x y b              = Lines l (nextTab (c + x) + y) (t + b) (a + b)
+  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 _ _ 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' 
+  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 a <> Lines m d t' b         = Directed p (l + m) d (t + t') (a + b)
+  Directed p l _ t _ <> Directed p' l' c' t' b = Directed (appendPath p l p') l' c' (t + t') b
   
 nextTab :: Int -> Int
 nextTab x = x + (8 - mod x 8)
 
+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 
+
+near :: Delta -> Delta -> Bool
+near (Directed p l _ _ _) (Directed p' l' _ _ _) = p == p' && l == l'
+near (Lines l _ _ _) (Lines l' _ _ _) = l == l'
+near _ _ = True
+
 class HasDelta t where
   delta :: t -> Delta
 
+instance HasDelta Delta where
+  delta = id
+
 instance HasDelta Char where
   delta '\t' = Tab 0 0 1
-  delta '\n' = Lines 1 0 0
-  delta _    = Columns 1 1
+  delta '\n' = Lines 1 0 1 0
+  delta c | o <= 0x7f   = Columns 1 1
+          | o <= 0x7ff  = Columns 1 2
+          | o <= 0xffff = Columns 1 3
+          | otherwise   = Columns 1 4
+    where o = fromEnum c
 
 instance HasDelta Word8 where
   delta 9  = Tab 0 0 1
-  delta 10 = Lines 1 0 0
+  delta 10 = Lines 1 0 1 0
   delta n | n <= 0x7f              = Columns 1 1
           | n >= 0xc0 && n <= 0xf4 = Columns 1 1
           | otherwise              = Columns 0 1
 
 instance HasDelta ByteString where
   delta = foldMap delta . unpack
+
+instance HasDelta Path where
+  delta p = Directed p 0 0 0 0
+
+instance (Measured v a, HasDelta v) => HasDelta (FingerTree v a) where
+  delta = delta . measure
diff --git a/Text/Trifecta/Hunk.hs b/Text/Trifecta/Hunk.hs
--- a/Text/Trifecta/Hunk.hs
+++ b/Text/Trifecta/Hunk.hs
@@ -1,10 +1,11 @@
 {-# LANGUAGE MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-}
 module Text.Trifecta.Hunk 
   ( Hunk(..)
+  , hunk
   ) where
 
 import Data.ByteString
-import Data.FingerTree
+import Data.FingerTree as FingerTree
 import Data.Function (on)
 import Data.Hashable
 import Data.Interned
@@ -13,10 +14,12 @@
 import GHC.IO
 import Text.Trifecta.Delta
 import Text.PrettyPrint.Leijen.Extras
---import Control.Exception
 
 data Hunk = Hunk {-# UNPACK #-} !Id !Delta {-# UNPACK #-} !ByteString
 
+hunk :: ByteString -> Hunk
+hunk = intern 
+
 -- assuming utf8 encoding
 prettyByteString :: ByteString -> Doc e
 prettyByteString bs = string (Text.unpack (toUnicode (unsafeDupablePerformIO (open "UTF8" Nothing)) bs))
@@ -27,7 +30,6 @@
 instance Show Hunk where
   showsPrec _ h = displayS (renderPretty 0.9 80 (pretty h))
 
-
 instance Eq Hunk where
   (==) = (==) `on` identity
 
@@ -46,7 +48,6 @@
   describe = Describe
   identify i bs = Hunk i (delta bs) bs
   identity (Hunk i _ _) = i
--- modifyAdvice = bracket_ (Prelude.putStrLn "entering hunk") (Prelude.putStrLn "exiting hunk")
   cache = hunkCache
 
 instance Uninternable Hunk where
diff --git a/Text/Trifecta/It.hs b/Text/Trifecta/It.hs
--- a/Text/Trifecta/It.hs
+++ b/Text/Trifecta/It.hs
@@ -1,30 +1,19 @@
 {-# LANGUAGE MultiParamTypeClasses, BangPatterns #-}
 module Text.Trifecta.It 
   ( It(..)
-  , getRope
-  , getMeasure
-  , getEof
-  , getWord8
-  , sliceIt
-  , slice
-  , sliced
+  , input
+  , peekIt
   ) where
 
 import Control.Applicative
 import Control.Monad
-import Control.Monad.Trans.Class
 import Data.Semigroup
 import Data.Monoid
-import Data.Word
-import Data.Interned
-import Data.Foldable (toList)
 import Data.FingerTree as FingerTree
-import Data.ByteString as Strict
 import Data.ByteString.Lazy as Lazy
+import Data.ByteString.Lazy.UTF8 as LazyUTF8
 import Data.Functor.Bind
 import Data.Functor.Plus
-import Text.Trifecta.Cursor
-import Text.Trifecta.Hunk
 import Text.Trifecta.Rope as Rope
 import Text.Trifecta.Delta
 import Text.Parsec.Prim hiding ((<|>))
@@ -81,61 +70,19 @@
   mplus = (<!>) 
   mzero = fail "mzero"
 
-getRope :: It Rope
-getRope = Cont $ \r e -> Done r e r
-
-getMeasure :: It Cursor
-getMeasure = Cont $ \r e -> Done r e (measure r)
-
-getEof :: It Bool
-getEof = Cont $ \ r e -> Done r e e 
+input :: It Rope
+input = Cont $ \r e -> Done r e r
 
-instance Stream Cursor It Char where
-  uncons (Cursor b d _ _) = (getWord8 b >>= go) <|> return Nothing where
-    go c | c <= 0x7f = do
-        Cursor _ _ i t <- getMeasure
-        return $ Just (toEnum (fromEnum c), Cursor (b + 1) (d <> delta c) i t) -- TODO: add in PathHunks
-         | otherwise = error "TODO"
-    -- TODO: finish these
+instance Stream Delta It Char where
+  uncons d = k <$> peekIt d <|> return Nothing where 
+    k (d', bs) = case LazyUTF8.uncons bs of
+      Just (c, _) -> Just (c, d' <> delta c)
+      Nothing     -> Nothing
 
-getWord8 :: Int -> It Word8
-getWord8 n = Cont go where
+peekIt :: Delta -> It (Delta, Lazy.ByteString)
+peekIt n = Cont go where
   go h eof 
-    | n < Rope.lastNewline h eof = Done h eof $ indexByte n h
-    | eof                        = Fail h True "Unexpected EOF"
-    | otherwise                  = Cont $ \h' -> go (h <> h') -- h' <> h
-
-sliceIt :: Int -> Int -> It Strict.ByteString
-sliceIt !i !j = Cont go where
-  go :: Rope -> Bool -> It Strict.ByteString
-  go t@(Rope _ h) eof
-    | j <= cursorBytes (measure h) || eof = Done t eof (sliceStrands h)
-    | otherwise = Cont $ \t' eof' -> go (t <> t') eof'
-  sliceStrands :: FingerTree Cursor Strand -> Strict.ByteString
-  sliceStrands !t
-    | req <= rmn = Strict.take req first -- yay! sharing
-    | otherwise = Strict.concat 
-                $ Lazy.toChunks 
-                $ Lazy.take (fromIntegral req) 
-                $ Lazy.fromChunks 
-                $ first : Prelude.foldr iter [] (toList r')
-    where iter (HunkStrand h) b = unintern h : b
-          iter (PathStrand _) b = b
-          (l,r) = FingerTree.split (\m -> cursorBytes m > i) t
-          HunkStrand (Hunk _ _ a) :< r' = FingerTree.viewl r
-          first = Strict.drop (i - cursorBytes (measure l)) a
-          req = j - i
-          rmn = Strict.length first
-
-slice :: Cursor -> Cursor -> ParsecT Cursor u It Strict.ByteString
-slice mark release = lift $ sliceIt (cursorBytes mark) (cursorBytes release)
-
-sliced :: ParsecT Cursor u It a -> ParsecT Cursor u It Strict.ByteString
-sliced p = do
-  mark <- getInput
-  _ <- p
-  release <- getInput
-  slice mark release
-
--- sliceDelta :: Int -> Int -> It Delta
-
+    | n < lastNewline h eof = grab n h (\c lbs -> Done h eof (c, lbs)) 
+                                       (Fail h eof "peek: failed to grab rope")
+    | eof                   = Fail h True "Unexpected EOF"
+    | otherwise             = Cont $ \h' -> go (h <> h') -- h' <> h
diff --git a/Text/Trifecta/Parser.hs b/Text/Trifecta/Parser.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Parser.hs
@@ -0,0 +1,80 @@
+{-# LANGUAGE MultiParamTypeClasses, BangPatterns #-}
+module Text.Trifecta.Parser
+  ( P
+  , line
+  , slice
+  , sliced
+  , careted
+  , covered
+  ) where
+
+import Control.Applicative
+import Control.Monad.Trans.Class
+import Data.Semigroup
+import Data.Interned
+import Data.Foldable (toList)
+import Data.FingerTree as FingerTree
+import Data.ByteString as Strict
+import Data.ByteString.Lazy as Lazy
+import Text.Trifecta.Hunk
+import Text.Trifecta.Bytes
+import Text.Trifecta.Rope as Rope
+import Text.Trifecta.Delta
+import Text.Trifecta.Strand
+import Text.Trifecta.Caret
+import Text.Trifecta.It
+import Text.Parsec.Prim hiding ((<|>))
+
+type P u = ParsecT Delta u It
+
+-- grab the contents of the line that contains delta
+line :: Delta -> P u Strict.ByteString
+line d = lift $ Strict.concat 
+              . Lazy.toChunks 
+              . Lazy.takeWhile (/= 10)
+              . snd <$> peekIt (rewind d)
+
+slice :: Delta -> Delta -> P u Strict.ByteString
+slice !i !j = lift (Cont loop)
+  where
+    bi = bytes i
+    bj = bytes j
+    loop t eof
+      | bj <= bytes t || eof = Done t eof $ go $ strands t
+      | otherwise = Cont $ \t' eof' -> loop (t <> t') eof'
+    go !t
+      | required <= Strict.length first = Strict.take required first
+      | otherwise = Strict.concat 
+                  $ Lazy.toChunks 
+                  $ Lazy.take (fromIntegral required) 
+                  $ Lazy.fromChunks 
+                  $ first : Prelude.foldr iter [] (toList r')
+      where 
+        iter (HunkStrand h) b = unintern h : b
+        iter (PathStrand _) b = b
+        (l,r) = FingerTree.split (\m -> bytes m > bi) t
+        HunkStrand (Hunk _ _ a) :< r' = FingerTree.viewl r
+        first = Strict.drop (bi - bytes l) a
+        required = bj - bi
+
+sliced :: P u a -> P u Strict.ByteString
+sliced pa = do
+  mark <- getInput
+  _ <- pa
+  release <- getInput
+  slice mark release
+
+covered :: P u a -> P u (Covered a)
+covered p = do
+  m <- getInput
+  l <- line m
+  a <- p
+  r <- getInput
+  return $ a :~ Cover (Caret m l) r
+
+careted :: P u a -> P u (Careted a)
+careted p = do
+  m <- getInput
+  l <- line m
+  a <- p 
+  return $ a :^ Caret m l
diff --git a/Text/Trifecta/Path.hs b/Text/Trifecta/Path.hs
--- a/Text/Trifecta/Path.hs
+++ b/Text/Trifecta/Path.hs
@@ -12,14 +12,16 @@
 import Data.Hashable
 import Data.Interned
 import Data.Interned.String
---import Control.Exception
+import Data.Function (on)
 import Data.Semigroup
 import Text.PrettyPrint.Leijen.Extras
 
 type FileName = InternedString
 
 data Path = Path {-# UNPACK #-} !Id !History !MaybeFileName {-# UNPACK #-} !Int [Int]
+  deriving Show
 
+-- Todo: Make a prettier path
 prettyPathWith :: (Doc e -> Doc e) -> Path -> Int -> Doc e 
 prettyPathWith wrapDir = go where
   go (Path _ h mf l flags) delta 
@@ -35,19 +37,26 @@
 instance Pretty Path where
   pretty p = prettyPathWith id p 0
 
-instance Show Path where
-  showsPrec _ p = displayS (renderPretty 0.9 80 (pretty p))
 
-data History = Continue !Path {-# UNPACK #-} !Int | Complete
-data MaybeFileName = JustFileName !FileName | NothingFileName deriving Eq
+instance Eq Path where
+  (==) = (==) `on` identity
 
+-- NB: this is subtle in that it also lets us say 
+-- if one might be a prefix of the other due to
+-- the way we construct the hash cons table
+instance Ord Path where
+  compare = compare `on` identity
+
+data History = Continue !Path {-# UNPACK #-} !Int | Complete deriving (Eq, Show)
+
+data MaybeFileName = JustFileName !FileName | NothingFileName deriving (Eq, Show)
+
 startPath :: FileName -> Path 
 startPath !n = path Complete (JustFileName n) 0 []
 
 snocPath :: Path -> Int -> MaybeFileName -> Int -> [Int] -> Path
 snocPath d l jf l' flags = path (Continue d l) jf l' flags
 
--- does case analysis to ensure the Maybe carries a fully evaluated argument
 path :: History -> MaybeFileName -> Int -> [Int] -> Path
 path !h !mf l flags = intern (UPath h mf l flags)
 
@@ -79,7 +88,6 @@
         JustFileName f -> Just (identity f)
         NothingFileName -> Nothing
                      
---  modifyAdvice = bracket_ (putStrLn "entering path") (putStrLn "exiting path")
   identify i (UPath h mf l flags) = Path i h mf l flags
   identity (Path i _ _ _ _) = i
   cache = pathCache
diff --git a/Text/Trifecta/Rope.hs b/Text/Trifecta/Rope.hs
--- a/Text/Trifecta/Rope.hs
+++ b/Text/Trifecta/Rope.hs
@@ -1,90 +1,100 @@
-{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, BangPatterns, PatternGuards #-}
 module Text.Trifecta.Rope
-  ( Strand(..)
-  , Rope(..)
-  , indexByte
-  , size
+  ( Rope(..)
+  , rope
+  , strands
+  , grab
   , lastNewline
   ) where
 
-import Data.Sequence as Seq
-import Data.Interned
-import Data.Hashable
 import Data.Monoid
 import Data.Semigroup
-import Data.ByteString as Strict
+import Data.Semigroup.Reducer
+import qualified Data.ByteString as Strict
+import qualified Data.ByteString.Lazy as Lazy
 import Data.FingerTree as FingerTree
-import Data.Word
 import Data.Foldable (toList)
 import Text.Trifecta.Hunk
 import Text.Trifecta.Path
-import Text.Trifecta.Cursor
 import Text.Trifecta.Delta
--- import Control.Exception
+import Text.Trifecta.Bytes
+import Text.Trifecta.Strand
 
-data Strand
-  = HunkStrand !Hunk
-  | PathStrand !Path
+data Rope = Rope !Delta !(FingerTree Delta Strand)
 
-instance Show Strand where
-  showsPrec d (HunkStrand h) = showsPrec d h
-  showsPrec d (PathStrand p) = showsPrec d p
+rope :: FingerTree Delta Strand -> Rope
+rope r = Rope (measure r) r
 
--- measure twice, cut once
-instance Measured Cursor Strand where
-  measure (HunkStrand s) = Cursor (Strict.length (unintern s)) (delta s) i (Seq.singleton i) where i = 42 + (identity s * 2)
-  measure (PathStrand p) = Cursor 0 (Directed p 0 0 0) i (Seq.singleton i)   where i = 230 + (identity p * 2 + 1)
+strands :: Rope -> FingerTree Delta Strand
+strands (Rope _ r) = r
 
-data Rope = Rope 
-  { _ropeId  :: {-# UNPACK #-} !Id
-  , ropeTree :: !(FingerTree Cursor Strand)
-  }
+instance HasBytes Rope where
+  bytes = bytes . measure
 
-size :: Rope -> Int
-size = cursorBytes . measure
+instance HasDelta Rope where
+  delta = measure
 
-instance Measured Cursor Rope where
-  measure (Rope _ t) = measure t
+instance Measured Delta Rope where
+  measure (Rope s _) = s
 
+instance Reducer Rope Rope where
+  unit = id
+
+instance Reducer Strand Rope where
+  unit s = rope (singleton s)
+  cons s (Rope mt t) = Rope (delta s `mappend` mt) (s <| t)
+  snoc (Rope mt t) !s = Rope (mt `mappend` delta s) (t |> s)
+
+instance Reducer Hunk Rope where
+  unit s = Rope (delta s) (singleton (HunkStrand s))
+  cons s (Rope mt t) = Rope (delta s `mappend` mt) (HunkStrand s <| t)
+  snoc (Rope mt t) s = Rope (mt `mappend` delta s) (t |> HunkStrand s)
+  
+instance Reducer Path Rope where
+  unit s = Rope (delta s) (singleton (PathStrand s))
+  cons s (Rope mt t) = Rope (delta s `mappend` mt) (PathStrand s <| t)
+  snoc (Rope mt t) s = Rope (mt `mappend` delta s) (t |> PathStrand s)
+
+instance Reducer Strict.ByteString Rope where
+  unit = unit . hunk
+  cons = cons . hunk 
+  snoc r = snoc r . hunk
+
 instance Show Rope where
   showsPrec d (Rope _ r) = showsPrec d (toList r)
 
-lastNewline :: Rope -> Bool -> Int
-lastNewline t True  = size t
-lastNewline t False = case d of
-	Columns _ _       -> 0
-        Tab _ _ _         -> 0
-        Lines _ _ b'      -> b - b'
-        Directed _ _ _ b' -> b - b'
-  where Cursor b d _ _ = measure t
+-- | obtain the byte location of the last newline in a rope, or the end of the rope if at EOF
+lastNewline :: Rope -> Bool -> Delta
+lastNewline t True  = delta t
+lastNewline t False = rewind (delta t)
 
+-- | grab a lazy bytestring starting from some point. This bytestring does not cross path nodes
+--   if the index is to the start of a bytestring fragment, we update it to deal with any 
+--   intervening path fragments
+grab :: Delta -> Rope -> (Delta -> Lazy.ByteString -> r) -> r -> r
+grab i t ks kf = case FingerTree.viewl r of
+  HunkStrand (Hunk _ _ a) :< r' -> case bi - bl of 
+    0  -> ks (measure l) (Lazy.fromChunks $ a : chunks r')
+    db -> ks i           (Lazy.fromChunks $ (Strict.drop db a) : chunks r')
+  _ -> kf
+  where 
+    bi = bytes i
+    bl = bytes l
+    (l, r) = FingerTree.split (\b -> bytes b > bi) (strands t)
+    chunks s = case viewl s of 
+      HunkStrand (Hunk _ _ a) :< s' -> a : chunks s'
+      _ -> []
+
+{-
 indexByte :: Int -> Rope -> Word8
-indexByte i (Rope _ t) = Strict.index a $ i - cursorBytes (measure l) where
-   (l, r) = FingerTree.split (\b -> cursorBytes b > i) t
-   HunkStrand (Hunk _ _ a) FingerTree.:< _ = FingerTree.viewl r
+indexByte i (Rope _ t) = Strict.index a $ i - bytes l where
+   (l, r) = FingerTree.split (\b -> bytes b > i) t
+   HunkStrand (Hunk _ _ a) :< _ = FingerTree.viewl r
+-}
 
 instance Monoid Rope where
-  mempty = intern mempty
-  mappend x y = intern (unintern x `mappend` unintern y)
+  mempty = Rope mempty mempty
+  mappend = (<>)
 
 instance Semigroup Rope where
-  x <> y = intern (unintern x `mappend` unintern y)
-
-instance Interned Rope where
-  type Uninterned Rope = FingerTree Cursor Strand
-  data Description Rope = DR {-# UNPACK #-} !Int !(Seq Id) deriving Eq
-  describe t = DR h i where Cursor _ _ h i = measure t
-  identify = Rope
-  identity (Rope i _) = i
--- modifyAdvice = bracket_ (Prelude.putStrLn "entering rope") (Prelude.putStrLn "exiting rope")
-  cache = ropeCache
-
-instance Hashable (Description Rope) where
-  hash (DR i s) = hashWithSalt i (toList s) 
-
-instance Uninternable Rope where
-  unintern (Rope _ r) = r
-
-ropeCache :: Cache Rope
-ropeCache = mkCache
-{-# NOINLINE ropeCache #-}
+  Rope mx x <> Rope my y = Rope (mx <> my) (x `mappend` y)
diff --git a/Text/Trifecta/Strand.hs b/Text/Trifecta/Strand.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Strand.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances #-}
+module Text.Trifecta.Strand
+  ( Strand(..)
+  ) where
+
+import Data.Interned
+import Data.Hashable
+import Data.ByteString as Strict
+import Data.FingerTree as FingerTree
+import Text.Trifecta.Hunk
+import Text.Trifecta.Path
+import Text.Trifecta.Bytes
+import Text.Trifecta.Delta
+import Text.PrettyPrint.Leijen.Extras
+
+data Strand
+  = HunkStrand !Hunk
+  | PathStrand !Path
+
+instance Show Strand where
+  showsPrec d (HunkStrand h) = showsPrec d h
+  showsPrec d (PathStrand p) = showsPrec d p
+
+instance Pretty Strand where
+  pretty (HunkStrand h) = pretty h
+  pretty (PathStrand p) = pretty p
+
+instance Measured Delta Strand where
+  measure (HunkStrand s) = delta s
+  measure (PathStrand p) = delta p
+
+instance Hashable Strand where
+  hash (HunkStrand h) = hashWithSalt 0 h
+  hash (PathStrand p) = hashWithSalt 0 p
+
+instance HasDelta Strand where
+  delta = measure
+
+instance HasBytes Strand where
+  bytes (HunkStrand h) = Strict.length (unintern h)
+  bytes _ = 0
diff --git a/Text/Trifecta/Supply.hs b/Text/Trifecta/Supply.hs
--- a/Text/Trifecta/Supply.hs
+++ b/Text/Trifecta/Supply.hs
@@ -1,29 +1,32 @@
+{-# LANGUAGE FlexibleContexts #-}
 module Text.Trifecta.Supply 
   ( Supply(..)
-  , EOF(..)
+  , EOF(EOF)
   , supplyEOF
-  , supplyRope
+  -- * type restricted versions of supply
+  , supplyDefault
   , supplyStrand
   , supplyHunk
   , supplyPath
   , supplyByteString
   ) where
 
-import Text.Trifecta.Path
-import Text.Trifecta.Rope
-import Text.Trifecta.Hunk
-import Text.Trifecta.It
-import Data.Interned
+import Control.Parallel.Strategies hiding (Done)
 import Data.Monoid
-import Data.Semigroup
+import Data.Semigroup.Reducer
 import Data.Foldable
 import Data.Word
 import Data.Semigroup.Foldable
 import Data.List.NonEmpty
 import Data.FingerTree as FingerTree
-import Data.ByteString as Strict
+import qualified Data.ByteString as Strict
+import qualified Data.ByteString.Lazy as Lazy
 import Data.ByteString.UTF8 as UTF8
-import Control.Parallel.Strategies hiding (Done)
+import Text.Trifecta.Path
+import Text.Trifecta.Rope
+import Text.Trifecta.Hunk
+import Text.Trifecta.Strand
+import Text.Trifecta.It
 
 -- enumerators for our iteratee
 
@@ -42,40 +45,42 @@
 supplyEOF (Done r _ a) = Done r True a
 supplyEOF (Fail r _ a) = Fail r True a
 
-supplyRope :: Rope -> It a -> It a
-supplyRope new (Done old _ a) = Done (old <> new) False a
-supplyRope new (Fail old _ a) = Fail (old <> new) False a
-supplyRope new (Cont k) = k new False
+supplyDefault :: Reducer t Rope => t -> It a -> It a
+supplyDefault new (Done old _ a) = Done (snoc old new) False a
+supplyDefault new (Fail old _ a) = Fail (snoc old new) False a
+supplyDefault new (Cont k)       = k (unit new) False
 
 supplyStrand :: Strand -> It a -> It a 
-supplyStrand = supplyRope . intern . FingerTree.singleton
+supplyStrand = supplyDefault
 
 supplyHunk :: Hunk -> It a -> It a
-supplyHunk = supplyStrand . HunkStrand
+supplyHunk = supplyDefault
 
 supplyPath :: Path -> It a -> It a
-supplyPath = supplyStrand . PathStrand
+supplyPath = supplyDefault
 
 supplyByteString :: ByteString -> It a -> It a 
-supplyByteString bs = supplyHunk (intern bs)
+supplyByteString = supplyDefault
 
+-- DO NOT WANT
 instance Supply Word8 where
   supply = supplyByteString . Strict.singleton
   supplyList = supplyByteString . Strict.pack
 
 instance Supply Char where
-  supply c | fromEnum c <= 0x7f = supplyByteString $ Strict.singleton $ toEnum $ fromEnum c
-           | otherwise = error "TODO"
-        -- TODO: more
+  supply c = supplyByteString (UTF8.fromString [c])
   supplyList = supplyByteString . UTF8.fromString
 
 instance Supply a => Supply [a] where
   supply = supplyList
 
-instance Supply ByteString where
+instance Supply Strict.ByteString where
   supply = supplyByteString
-  supplyList = supplyList . Prelude.map (HunkStrand . intern)
+  supplyList = supplyList . Prelude.map (HunkStrand . hunk)
 
+instance Supply Lazy.ByteString where
+  supply = supplyList . Lazy.toChunks 
+
 instance Supply Hunk where
   supply = supplyHunk
   supplyList = supplyList . Prelude.map HunkStrand
@@ -83,13 +88,13 @@
 instance Supply Path where
   supply = supplyPath
   supplyList [] = id
-  supplyList (x:xs) = supplyPath $ fold1 (x:|xs)
+  supplyList (x:xs) = supplyPath $ fold1 (x :| xs)
 
 instance Supply Strand where
   supply = supplyStrand
-  supplyList xs = supplyRope (intern (FingerTree.fromList xs')) where
+  supplyList xs = supply (rope (FingerTree.fromList xs')) where
      !xs' = withStrategy (evalList rseq) xs
 
 instance Supply Rope where
-  supply = supplyRope
-  supplyList = supplyRope . fold
+  supply = supplyDefault
+  supplyList = supplyDefault . fold
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.2
+version:       0.3
 license:       BSD3
 cabal-version: >= 1.6
 license-file:  LICENSE
@@ -29,7 +29,7 @@
     wl-pprint-extras >= 1.2      && < 1.3,
     semigroups       >= 0.7.1    && < 0.8, 
     fingertree       >= 0.0.1    && < 0.1,
-    reducers         >= 0.1      && < 0.2,
+    reducers         >= 0.1.2    && < 0.2,
     parsec           >= 3.1.1    && < 3.2,
     utf8-string      >= 0.3.6    && < 0.4,
     semigroupoids    >= 1.2.4    && < 1.3,
@@ -40,11 +40,13 @@
 
   exposed-modules:
     Text.Trifecta
+    Text.Trifecta.It
     Text.Trifecta.Path
-    Text.Trifecta.Delta
-    Text.Trifecta.Cursor
     Text.Trifecta.Rope
     Text.Trifecta.Hunk
-    Text.Trifecta.It
+    Text.Trifecta.Bytes
+    Text.Trifecta.Caret
+    Text.Trifecta.Delta
+    Text.Trifecta.Strand
     Text.Trifecta.Supply
-
+    Text.Trifecta.Parser
