updateFile :: ([B.ByteString]
           -> AnnotatedM [B.ByteString])
           -> AnnotatedM ()
updateFile job = (==File) <$> gets what >>= flip when go
  where
    go = do
        before <- map snd `fmap` gets current
        after <- job before
        da <- gets diffAlgorithm
        reannotate $ getChanges da before after

    reannotate [] = return ()
    reannotate ((off, remove, add):rest) = do
        i <- gets currentInfo
        c <- gets current
        a <- gets annotated
        modify $ \s -> s { current = take off c ++ [ (-1, x) | x <- add ] ++
                                     drop (off + length remove) c
                         , annotated = merge i a $ take (length remove) $ drop off c
                         }
        reannotate rest

    merge i a l = a V.// [ (line, (Just i, B.empty))
                         | (line, _) <- l, line >= 0 && line < V.length a]
updateFile :: ([B.ByteString]
           -> AnnotatedM [B.ByteString])
           -> AnnotatedM ()
updateFile job = (==File) <$> gets what >>= flip when go
  where
    go = do
        before <- map snd `fmap` gets current
        after <- job before
        da <- gets diffAlgorithm
        reannotate $ getChanges da before after

    reannotate [] = return ()
    reannotate ((off, remove, add):rest) = do
        i <- gets currentInfo
        c <- gets current
        a <- gets annotated
        modify $ \s -> s { current = take off c ++ [ (-1, x) | x <- add ] ++
                                     drop (off + length remove) c
                         , annotated = merge i a $ take (length remove) $ drop off c
                         }
        reannotate rest

    merge i a l = a V.// [ (line, (Just i, B.empty))
                         | (line, _) <- l, line >= 0 && line < V.length a]
updateFile job = (==File) <$> gets what >>= flip when go
  where
    go = do
        before <- map snd `fmap` gets current
        after <- job before
        da <- gets diffAlgorithm
        reannotate $ getChanges da before after

    reannotate [] = return ()
    reannotate ((off, remove, add):rest) = do
        i <- gets currentInfo
        c <- gets current
        a <- gets annotated
        modify $ \s -> s { current = take off c ++ [ (-1, x) | x <- add ] ++
                                     drop (off + length remove) c
                         , annotated = merge i a $ take (length remove) $ drop off c
                         }
        reannotate rest

    merge i a l = a V.// [ (line, (Just i, B.empty))
                         | (line, _) <- l, line >= 0 && line < V.length a]