{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, MultiParamTypeClasses #-}

-- Copyright (C) 2010 Petr Rockai
--
-- Permission is hereby granted, free of charge, to any person
-- obtaining a copy of this software and associated documentation
-- files (the "Software"), to deal in the Software without
-- restriction, including without limitation the rights to use, copy,
-- modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be
-- included in all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.

-- |
-- Module      : Darcs.Patch.Annotate
-- Copyright   : 2010 Petr Rockai
-- License     : MIT
-- Maintainer  : darcs-devel@darcs.net
-- Stability   : experimental
-- Portability : portable

module Darcs.Patch.Annotate
    (
      annotateFile
    , annotateDirectory
    , format
    , machineFormat
    , AnnotateResult
    , Annotate(..)
    ) where

import Prelude ()
import Darcs.Prelude

import Control.Monad.State ( modify, modify', when, gets, State, execState )

import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
import qualified Data.Map as M
import qualified Data.Vector as V

import Data.Function ( on )
import Data.List( nub, groupBy )
import Data.Maybe( isJust, mapMaybe )

import qualified Darcs.Patch.Prim.FileUUID as FileUUID

import Darcs.Patch.Info ( PatchInfo(..), displayPatchInfo, piAuthor, makePatchname )
import Darcs.Patch.Named ( Named(..) )
import Darcs.Patch.Named.Wrapped ( WrappedNamed(..) )
import Darcs.Patch.PatchInfoAnd( info, PatchInfoAnd, hopefully )
import Darcs.Patch.Prim.V1.Core ( Prim(..), DirPatchType(..), FilePatchType(..) )
import Darcs.Patch.TokenReplace ( annotateReplace )
import Darcs.Patch.Witnesses.Ordered

import Darcs.Util.Path ( FileName, movedirfilename, fn2ps, ps2fn )
import Darcs.Util.Printer( renderString )
import Darcs.Util.ByteString ( linesPS, decodeLocale )

data FileOrDirectory = File
                     | Directory
                       deriving (Int -> FileOrDirectory -> ShowS
[FileOrDirectory] -> ShowS
FileOrDirectory -> String
(Int -> FileOrDirectory -> ShowS)
-> (FileOrDirectory -> String)
-> ([FileOrDirectory] -> ShowS)
-> Show FileOrDirectory
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FileOrDirectory] -> ShowS
$cshowList :: [FileOrDirectory] -> ShowS
show :: FileOrDirectory -> String
$cshow :: FileOrDirectory -> String
showsPrec :: Int -> FileOrDirectory -> ShowS
$cshowsPrec :: Int -> FileOrDirectory -> ShowS
Show, FileOrDirectory -> FileOrDirectory -> Bool
(FileOrDirectory -> FileOrDirectory -> Bool)
-> (FileOrDirectory -> FileOrDirectory -> Bool)
-> Eq FileOrDirectory
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FileOrDirectory -> FileOrDirectory -> Bool
$c/= :: FileOrDirectory -> FileOrDirectory -> Bool
== :: FileOrDirectory -> FileOrDirectory -> Bool
$c== :: FileOrDirectory -> FileOrDirectory -> Bool
Eq)

type AnnotateResult = V.Vector (Maybe PatchInfo, B.ByteString)

data Annotated = Annotated
    { Annotated -> AnnotateResult
annotated     :: !AnnotateResult
    , Annotated -> [(Int, ByteString)]
current       :: ![(Int, B.ByteString)]
    , Annotated -> Maybe FileName
path          :: (Maybe FileName)
    , Annotated -> FileOrDirectory
what          :: FileOrDirectory
    , Annotated -> PatchInfo
currentInfo   :: PatchInfo
    } deriving Int -> Annotated -> ShowS
[Annotated] -> ShowS
Annotated -> String
(Int -> Annotated -> ShowS)
-> (Annotated -> String)
-> ([Annotated] -> ShowS)
-> Show Annotated
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Annotated] -> ShowS
$cshowList :: [Annotated] -> ShowS
show :: Annotated -> String
$cshow :: Annotated -> String
showsPrec :: Int -> Annotated -> ShowS
$cshowsPrec :: Int -> Annotated -> ShowS
Show

type AnnotatedM = State Annotated

class Annotate p where
  annotate :: p wX wY -> AnnotatedM ()

instance Annotate Prim where
  annotate :: Prim wX wY -> AnnotatedM ()
annotate (FP fn :: FileName
fn fp :: FilePatchType wX wY
fp) = case FilePatchType wX wY
fp of
    RmFile -> do
      FileName -> AnnotatedM () -> AnnotatedM ()
whenPathIs FileName
fn (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ (Annotated -> Annotated) -> AnnotatedM ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' (\s :: Annotated
s -> Annotated
s { path :: Maybe FileName
path = Maybe FileName
forall a. Maybe a
Nothing })
      FileOrDirectory -> AnnotatedM () -> AnnotatedM ()
whenWhatIs FileOrDirectory
Directory (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ FileName -> AnnotatedM ()
updateDirectory FileName
fn
    AddFile -> () -> AnnotatedM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    Hunk off :: Int
off o :: [ByteString]
o n :: [ByteString]
n -> FileName -> AnnotatedM () -> AnnotatedM ()
whenPathIs FileName
fn (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ FileOrDirectory -> AnnotatedM () -> AnnotatedM ()
whenWhatIs FileOrDirectory
File (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ do
      let remove :: Int
remove = [ByteString] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ByteString]
o
      let add :: Int
add = [ByteString] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ByteString]
n
      PatchInfo
i <- (Annotated -> PatchInfo) -> StateT Annotated Identity PatchInfo
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated -> PatchInfo
currentInfo
      [(Int, ByteString)]
c <- (Annotated -> [(Int, ByteString)])
-> StateT Annotated Identity [(Int, ByteString)]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated -> [(Int, ByteString)]
current
      AnnotateResult
a <- (Annotated -> AnnotateResult)
-> StateT Annotated Identity AnnotateResult
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated -> AnnotateResult
annotated
      -- NOTE patches are inverted and in inverse order
      (Annotated -> Annotated) -> AnnotatedM ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Annotated -> Annotated) -> AnnotatedM ())
-> (Annotated -> Annotated) -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ \s :: Annotated
s ->
        -- NOTE subtract one from offset because darcs counts from one,
        -- whereas vectors and lists count from zero.
        let (to :: [(Int, ByteString)]
to,from :: [(Int, ByteString)]
from) = Int
-> [(Int, ByteString)]
-> ([(Int, ByteString)], [(Int, ByteString)])
forall a. Int -> [a] -> ([a], [a])
splitAt (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
-1) [(Int, ByteString)]
c
        in  Annotated
s { current :: [(Int, ByteString)]
current = ((Int, ByteString) -> (Int, ByteString))
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> [a] -> [b]
map (Int, ByteString) -> (Int, ByteString)
eval ([(Int, ByteString)] -> [(Int, ByteString)])
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> a -> b
$ [(Int, ByteString)]
to [(Int, ByteString)] -> [(Int, ByteString)] -> [(Int, ByteString)]
forall a. [a] -> [a] -> [a]
++ Int -> (Int, ByteString) -> [(Int, ByteString)]
forall a. Int -> a -> [a]
replicate Int
add (-1, ByteString
B.empty) [(Int, ByteString)] -> [(Int, ByteString)] -> [(Int, ByteString)]
forall a. [a] -> [a] -> [a]
++ Int -> [(Int, ByteString)] -> [(Int, ByteString)]
forall a. Int -> [a] -> [a]
drop Int
remove [(Int, ByteString)]
from
              , annotated :: AnnotateResult
annotated = PatchInfo
-> AnnotateResult -> [(Int, ByteString)] -> AnnotateResult
forall a t.
a
-> Vector (Maybe a, ByteString)
-> [(Int, t)]
-> Vector (Maybe a, ByteString)
merge PatchInfo
i AnnotateResult
a ([(Int, ByteString)] -> AnnotateResult)
-> [(Int, ByteString)] -> AnnotateResult
forall a b. (a -> b) -> a -> b
$ ((Int, ByteString) -> (Int, ByteString))
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> [a] -> [b]
map (Int, ByteString) -> (Int, ByteString)
eval ([(Int, ByteString)] -> [(Int, ByteString)])
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> a -> b
$ Int -> [(Int, ByteString)] -> [(Int, ByteString)]
forall a. Int -> [a] -> [a]
take Int
remove ([(Int, ByteString)] -> [(Int, ByteString)])
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> a -> b
$ [(Int, ByteString)]
from
              }
    TokReplace t :: String
t o :: String
o n :: String
n -> FileName -> AnnotatedM () -> AnnotatedM ()
whenPathIs FileName
fn (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ FileOrDirectory -> AnnotatedM () -> AnnotatedM ()
whenWhatIs FileOrDirectory
File (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ do
      let test :: ByteString -> Bool
test = String -> ByteString -> ByteString -> ByteString -> Bool
annotateReplace String
t (String -> ByteString
BC.pack String
o) (String -> ByteString
BC.pack String
n)
      PatchInfo
i <- (Annotated -> PatchInfo) -> StateT Annotated Identity PatchInfo
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated -> PatchInfo
currentInfo
      [(Int, ByteString)]
c <- (Annotated -> [(Int, ByteString)])
-> StateT Annotated Identity [(Int, ByteString)]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated -> [(Int, ByteString)]
current
      AnnotateResult
a <- (Annotated -> AnnotateResult)
-> StateT Annotated Identity AnnotateResult
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated -> AnnotateResult
annotated
      (Annotated -> Annotated) -> AnnotatedM ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Annotated -> Annotated) -> AnnotatedM ())
-> (Annotated -> Annotated) -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ \s :: Annotated
s -> Annotated
s
        { current :: [(Int, ByteString)]
current = ((Int, ByteString) -> (Int, ByteString))
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> [a] -> [b]
map (\(ix :: Int
ix,b :: ByteString
b)->if ByteString -> Bool
test ByteString
b then (-1,ByteString
B.empty) else (Int
ix,ByteString
b)) [(Int, ByteString)]
c
        , annotated :: AnnotateResult
annotated = PatchInfo
-> AnnotateResult -> [(Int, ByteString)] -> AnnotateResult
forall a t.
a
-> Vector (Maybe a, ByteString)
-> [(Int, t)]
-> Vector (Maybe a, ByteString)
merge PatchInfo
i AnnotateResult
a ([(Int, ByteString)] -> AnnotateResult)
-> [(Int, ByteString)] -> AnnotateResult
forall a b. (a -> b) -> a -> b
$ ((Int, ByteString) -> (Int, ByteString))
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> [a] -> [b]
map (Int, ByteString) -> (Int, ByteString)
eval ([(Int, ByteString)] -> [(Int, ByteString)])
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> a -> b
$ ((Int, ByteString) -> Bool)
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a. (a -> Bool) -> [a] -> [a]
filter (ByteString -> Bool
test (ByteString -> Bool)
-> ((Int, ByteString) -> ByteString) -> (Int, ByteString) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, ByteString) -> ByteString
forall a b. (a, b) -> b
snd) ([(Int, ByteString)] -> [(Int, ByteString)])
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> a -> b
$ [(Int, ByteString)]
c
        }
    -- TODO what if the status of a file changed from text to binary?
    Binary _ _ -> FileName -> AnnotatedM () -> AnnotatedM ()
whenPathIs FileName
fn (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ String -> AnnotatedM ()
forall a. String -> a
bug "annotate: can't handle binary changes"
  annotate (DP _ AddDir) = () -> AnnotatedM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  annotate (DP fn :: FileName
fn RmDir) = FileOrDirectory -> AnnotatedM () -> AnnotatedM ()
whenWhatIs FileOrDirectory
Directory (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ do
    FileName -> AnnotatedM () -> AnnotatedM ()
whenPathIs FileName
fn (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ (Annotated -> Annotated) -> AnnotatedM ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' (\s :: Annotated
s -> Annotated
s { path :: Maybe FileName
path = Maybe FileName
forall a. Maybe a
Nothing })
    FileName -> AnnotatedM ()
updateDirectory FileName
fn
  annotate (Move fn :: FileName
fn fn' :: FileName
fn') = do
    (Annotated -> Annotated) -> AnnotatedM ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' (\s :: Annotated
s -> Annotated
s { path :: Maybe FileName
path = (FileName -> FileName) -> Maybe FileName -> Maybe FileName
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (FileName -> FileName -> FileName -> FileName
movedirfilename FileName
fn FileName
fn') (Annotated -> Maybe FileName
path Annotated
s) })
    FileOrDirectory -> AnnotatedM () -> AnnotatedM ()
whenWhatIs FileOrDirectory
Directory (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ do
      let fix :: (a, ByteString) -> (a, ByteString)
fix (i :: a
i, x :: ByteString
x) = (a
i, FileName -> ByteString
fn2ps (FileName -> ByteString) -> FileName -> ByteString
forall a b. (a -> b) -> a -> b
$ FileName -> FileName -> FileName -> FileName
movedirfilename FileName
fn FileName
fn' (ByteString -> FileName
ps2fn ByteString
x))
      (Annotated -> Annotated) -> AnnotatedM ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((Annotated -> Annotated) -> AnnotatedM ())
-> (Annotated -> Annotated) -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ \s :: Annotated
s -> Annotated
s { current :: [(Int, ByteString)]
current = ((Int, ByteString) -> (Int, ByteString))
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> [a] -> [b]
map (Int, ByteString) -> (Int, ByteString)
forall a. (a, ByteString) -> (a, ByteString)
fix ([(Int, ByteString)] -> [(Int, ByteString)])
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> a -> b
$ Annotated -> [(Int, ByteString)]
current Annotated
s }
  annotate (ChangePref _ _ _) = () -> AnnotatedM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

instance Annotate FileUUID.Prim where
  annotate :: Prim wX wY -> AnnotatedM ()
annotate _ = String -> AnnotatedM ()
forall a. String -> a
bug "annotate not implemented for FileUUID patches"

instance Annotate p => Annotate (FL p) where
  annotate :: FL p wX wY -> AnnotatedM ()
annotate = [AnnotatedM ()] -> AnnotatedM ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ ([AnnotatedM ()] -> AnnotatedM ())
-> (FL p wX wY -> [AnnotatedM ()]) -> FL p wX wY -> AnnotatedM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall wW wZ. p wW wZ -> AnnotatedM ())
-> FL p wX wY -> [AnnotatedM ()]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> FL a wX wY -> [b]
mapFL forall wW wZ. p wW wZ -> AnnotatedM ()
forall (p :: * -> * -> *) wX wY.
Annotate p =>
p wX wY -> AnnotatedM ()
annotate

instance Annotate p => Annotate (Named p) where
  annotate :: Named p wX wY -> AnnotatedM ()
annotate (NamedP _ _ p :: FL p wX wY
p) = FL p wX wY -> AnnotatedM ()
forall (p :: * -> * -> *) wX wY.
Annotate p =>
p wX wY -> AnnotatedM ()
annotate FL p wX wY
p

instance Annotate p => Annotate (WrappedNamed rt p) where
  annotate :: WrappedNamed rt p wX wY -> AnnotatedM ()
annotate (NormalP n :: Named p wX wY
n) = Named p wX wY -> AnnotatedM ()
forall (p :: * -> * -> *) wX wY.
Annotate p =>
p wX wY -> AnnotatedM ()
annotate Named p wX wY
n
  annotate (RebaseP _ _) = String -> AnnotatedM ()
forall a. String -> a
bug "annotate not implemented for Rebase patches"

instance Annotate p => Annotate (PatchInfoAnd rt p) where
  annotate :: PatchInfoAnd rt p wX wY -> AnnotatedM ()
annotate = WrappedNamed rt p wX wY -> AnnotatedM ()
forall (p :: * -> * -> *) wX wY.
Annotate p =>
p wX wY -> AnnotatedM ()
annotate (WrappedNamed rt p wX wY -> AnnotatedM ())
-> (PatchInfoAnd rt p wX wY -> WrappedNamed rt p wX wY)
-> PatchInfoAnd rt p wX wY
-> AnnotatedM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PatchInfoAnd rt p wX wY -> WrappedNamed rt p wX wY
forall (rt :: RepoType) (p :: * -> * -> *) wA wB.
PatchInfoAnd rt p wA wB -> WrappedNamed rt p wA wB
hopefully

whenWhatIs :: FileOrDirectory -> AnnotatedM () -> AnnotatedM ()
whenWhatIs :: FileOrDirectory -> AnnotatedM () -> AnnotatedM ()
whenWhatIs w :: FileOrDirectory
w actions :: AnnotatedM ()
actions = do
  FileOrDirectory
w' <- (Annotated -> FileOrDirectory)
-> StateT Annotated Identity FileOrDirectory
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated -> FileOrDirectory
what
  Bool -> AnnotatedM () -> AnnotatedM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FileOrDirectory
w FileOrDirectory -> FileOrDirectory -> Bool
forall a. Eq a => a -> a -> Bool
== FileOrDirectory
w') AnnotatedM ()
actions

whenPathIs :: FileName -> AnnotatedM () -> AnnotatedM ()
whenPathIs :: FileName -> AnnotatedM () -> AnnotatedM ()
whenPathIs fn :: FileName
fn actions :: AnnotatedM ()
actions = do
  Maybe FileName
p <- (Annotated -> Maybe FileName)
-> StateT Annotated Identity (Maybe FileName)
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated -> Maybe FileName
path
  Bool -> AnnotatedM () -> AnnotatedM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe FileName
p Maybe FileName -> Maybe FileName -> Bool
forall a. Eq a => a -> a -> Bool
== FileName -> Maybe FileName
forall a. a -> Maybe a
Just FileName
fn) AnnotatedM ()
actions

eval :: (Int, B.ByteString) -> (Int, B.ByteString)
eval :: (Int, ByteString) -> (Int, ByteString)
eval (i :: Int
i,b :: ByteString
b) = Int -> (Int, ByteString) -> (Int, ByteString)
forall a b. a -> b -> b
seq Int
i ((Int, ByteString) -> (Int, ByteString))
-> (Int, ByteString) -> (Int, ByteString)
forall a b. (a -> b) -> a -> b
$ ByteString -> (Int, ByteString) -> (Int, ByteString)
forall a b. a -> b -> b
seq ByteString
b ((Int, ByteString) -> (Int, ByteString))
-> (Int, ByteString) -> (Int, ByteString)
forall a b. (a -> b) -> a -> b
$ (Int
i,ByteString
b)

merge :: a
      -> V.Vector (Maybe a, BC.ByteString)
      -> [(Int, t)]
      -> V.Vector (Maybe a, BC.ByteString)
merge :: a
-> Vector (Maybe a, ByteString)
-> [(Int, t)]
-> Vector (Maybe a, ByteString)
merge i :: a
i a :: Vector (Maybe a, ByteString)
a l :: [(Int, t)]
l = Vector (Maybe a, ByteString)
a Vector (Maybe a, ByteString)
-> [(Int, (Maybe a, ByteString))] -> Vector (Maybe a, ByteString)
forall a. Vector a -> [(Int, a)] -> Vector a
V.// [ (Int
line, (a -> Maybe a
forall a. a -> Maybe a
Just a
i, ByteString
B.empty))
                     | (line :: Int
line, _) <- [(Int, t)]
l, Int
line Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= 0 Bool -> Bool -> Bool
&& Int
line Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Vector (Maybe a, ByteString) -> Int
forall a. Vector a -> Int
V.length Vector (Maybe a, ByteString)
a]

updateDirectory :: FileName -> AnnotatedM ()
updateDirectory :: FileName -> AnnotatedM ()
updateDirectory p :: FileName
p = FileOrDirectory -> AnnotatedM () -> AnnotatedM ()
whenWhatIs FileOrDirectory
Directory (AnnotatedM () -> AnnotatedM ()) -> AnnotatedM () -> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ do
    let line :: ByteString
line = FileName -> ByteString
fn2ps FileName
p
    [(Int, ByteString)]
files <- (Annotated -> [(Int, ByteString)])
-> StateT Annotated Identity [(Int, ByteString)]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated -> [(Int, ByteString)]
current
    case ((Int, ByteString) -> Bool)
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
==ByteString
line) (ByteString -> Bool)
-> ((Int, ByteString) -> ByteString) -> (Int, ByteString) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, ByteString) -> ByteString
forall a b. (a, b) -> b
snd) [(Int, ByteString)]
files of
      [match :: (Int, ByteString)
match@(ident :: Int
ident, _)] -> Int -> (Int, ByteString) -> ByteString -> AnnotatedM ()
forall (m :: * -> *).
MonadState Annotated m =>
Int -> (Int, ByteString) -> ByteString -> m ()
reannotate Int
ident (Int, ByteString)
match ByteString
line
      _ -> () -> AnnotatedM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  where
    reannotate :: Int -> (Int, ByteString) -> ByteString -> m ()
reannotate ident :: Int
ident match :: (Int, ByteString)
match line :: ByteString
line =
      (Annotated -> Annotated) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((Annotated -> Annotated) -> m ())
-> (Annotated -> Annotated) -> m ()
forall a b. (a -> b) -> a -> b
$ \x :: Annotated
x -> Annotated
x { annotated :: AnnotateResult
annotated = Annotated -> AnnotateResult
annotated Annotated
x AnnotateResult
-> [(Int, (Maybe PatchInfo, ByteString))] -> AnnotateResult
forall a. Vector a -> [(Int, a)] -> Vector a
V.// [ (Int
ident, ByteString -> PatchInfo -> (Maybe PatchInfo, ByteString)
forall a. ByteString -> a -> (Maybe a, ByteString)
update ByteString
line (PatchInfo -> (Maybe PatchInfo, ByteString))
-> PatchInfo -> (Maybe PatchInfo, ByteString)
forall a b. (a -> b) -> a -> b
$ Annotated -> PatchInfo
currentInfo Annotated
x) ]
                       , current :: [(Int, ByteString)]
current = ((Int, ByteString) -> Bool)
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int, ByteString) -> (Int, ByteString) -> Bool
forall a. Eq a => a -> a -> Bool
/= (Int, ByteString)
match) ([(Int, ByteString)] -> [(Int, ByteString)])
-> [(Int, ByteString)] -> [(Int, ByteString)]
forall a b. (a -> b) -> a -> b
$ Annotated -> [(Int, ByteString)]
current Annotated
x }
    update :: ByteString -> a -> (Maybe a, ByteString)
update line :: ByteString
line inf :: a
inf = (a -> Maybe a
forall a. a -> Maybe a
Just a
inf, [ByteString] -> ByteString
BC.concat [ " -- created as: ", ByteString
line ])

complete :: Annotated -> Bool
complete :: Annotated -> Bool
complete x :: Annotated
x = ((Maybe PatchInfo, ByteString) -> Bool) -> AnnotateResult -> Bool
forall a. (a -> Bool) -> Vector a -> Bool
V.all (Maybe PatchInfo -> Bool
forall a. Maybe a -> Bool
isJust (Maybe PatchInfo -> Bool)
-> ((Maybe PatchInfo, ByteString) -> Maybe PatchInfo)
-> (Maybe PatchInfo, ByteString)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe PatchInfo, ByteString) -> Maybe PatchInfo
forall a b. (a, b) -> a
fst) (AnnotateResult -> Bool) -> AnnotateResult -> Bool
forall a b. (a -> b) -> a -> b
$ Annotated -> AnnotateResult
annotated Annotated
x

annotate' :: Annotate p
          => FL (PatchInfoAnd rt p) wX wY
          -> Annotated
          -> Annotated
annotate' :: FL (PatchInfoAnd rt p) wX wY -> Annotated -> Annotated
annotate' NilFL ann :: Annotated
ann = Annotated
ann
annotate' (p :: PatchInfoAnd rt p wX wY
p :>: ps :: FL (PatchInfoAnd rt p) wY wY
ps) ann :: Annotated
ann
    | Annotated -> Bool
complete Annotated
ann = Annotated
ann
    | Bool
otherwise = FL (PatchInfoAnd rt p) wY wY -> Annotated -> Annotated
forall (p :: * -> * -> *) (rt :: RepoType) wX wY.
Annotate p =>
FL (PatchInfoAnd rt p) wX wY -> Annotated -> Annotated
annotate' FL (PatchInfoAnd rt p) wY wY
ps (Annotated -> Annotated) -> Annotated -> Annotated
forall a b. (a -> b) -> a -> b
$ AnnotatedM () -> Annotated -> Annotated
forall s a. State s a -> s -> s
execState (PatchInfoAnd rt p wX wY -> AnnotatedM ()
forall (p :: * -> * -> *) wX wY.
Annotate p =>
p wX wY -> AnnotatedM ()
annotate PatchInfoAnd rt p wX wY
p) (Annotated
ann { currentInfo :: PatchInfo
currentInfo = PatchInfoAnd rt p wX wY -> PatchInfo
forall (rt :: RepoType) (p :: * -> * -> *) wA wB.
PatchInfoAnd rt p wA wB -> PatchInfo
info PatchInfoAnd rt p wX wY
p })

annotateFile :: Annotate p
             => FL (PatchInfoAnd rt p) wX wY
             -> FileName
             -> B.ByteString
             -> AnnotateResult
annotateFile :: FL (PatchInfoAnd rt p) wX wY
-> FileName -> ByteString -> AnnotateResult
annotateFile patches :: FL (PatchInfoAnd rt p) wX wY
patches inipath :: FileName
inipath inicontent :: ByteString
inicontent = Annotated -> AnnotateResult
annotated (Annotated -> AnnotateResult) -> Annotated -> AnnotateResult
forall a b. (a -> b) -> a -> b
$ FL (PatchInfoAnd rt p) wX wY -> Annotated -> Annotated
forall (p :: * -> * -> *) (rt :: RepoType) wX wY.
Annotate p =>
FL (PatchInfoAnd rt p) wX wY -> Annotated -> Annotated
annotate' FL (PatchInfoAnd rt p) wX wY
patches Annotated
initial
  where
    initial :: Annotated
initial = $WAnnotated :: AnnotateResult
-> [(Int, ByteString)]
-> Maybe FileName
-> FileOrDirectory
-> PatchInfo
-> Annotated
Annotated { path :: Maybe FileName
path = FileName -> Maybe FileName
forall a. a -> Maybe a
Just FileName
inipath
                        , currentInfo :: PatchInfo
currentInfo = String -> PatchInfo
forall a. String -> a
bug "There is no currentInfo."
                        , current :: [(Int, ByteString)]
current = [Int] -> [ByteString] -> [(Int, ByteString)]
forall a b. [a] -> [b] -> [(a, b)]
zip [0..] (ByteString -> [ByteString]
linesPS ByteString
inicontent)
                        , what :: FileOrDirectory
what = FileOrDirectory
File
                        , annotated :: AnnotateResult
annotated = Int -> (Maybe PatchInfo, ByteString) -> AnnotateResult
forall a. Int -> a -> Vector a
V.replicate ([ByteString] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([ByteString] -> Int) -> [ByteString] -> Int
forall a b. (a -> b) -> a -> b
$ ByteString -> [ByteString]
breakLines ByteString
inicontent)
                                                      (Maybe PatchInfo
forall a. Maybe a
Nothing, ByteString
B.empty)
                        }

annotateDirectory :: Annotate p
                  => FL (PatchInfoAnd rt p) wX wY
                  -> FileName
                  -> [FileName]
                  -> AnnotateResult
annotateDirectory :: FL (PatchInfoAnd rt p) wX wY
-> FileName -> [FileName] -> AnnotateResult
annotateDirectory patches :: FL (PatchInfoAnd rt p) wX wY
patches inipath :: FileName
inipath inicontent :: [FileName]
inicontent = Annotated -> AnnotateResult
annotated (Annotated -> AnnotateResult) -> Annotated -> AnnotateResult
forall a b. (a -> b) -> a -> b
$ FL (PatchInfoAnd rt p) wX wY -> Annotated -> Annotated
forall (p :: * -> * -> *) (rt :: RepoType) wX wY.
Annotate p =>
FL (PatchInfoAnd rt p) wX wY -> Annotated -> Annotated
annotate' FL (PatchInfoAnd rt p) wX wY
patches Annotated
initial
  where
    initial :: Annotated
initial = $WAnnotated :: AnnotateResult
-> [(Int, ByteString)]
-> Maybe FileName
-> FileOrDirectory
-> PatchInfo
-> Annotated
Annotated { path :: Maybe FileName
path = FileName -> Maybe FileName
forall a. a -> Maybe a
Just FileName
inipath
                        , currentInfo :: PatchInfo
currentInfo = String -> PatchInfo
forall a. String -> a
bug "There is no currentInfo."
                        , current :: [(Int, ByteString)]
current = [Int] -> [ByteString] -> [(Int, ByteString)]
forall a b. [a] -> [b] -> [(a, b)]
zip [0..] ((FileName -> ByteString) -> [FileName] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map FileName -> ByteString
fn2ps [FileName]
inicontent)
                        , what :: FileOrDirectory
what = FileOrDirectory
Directory
                        , annotated :: AnnotateResult
annotated = Int -> (Maybe PatchInfo, ByteString) -> AnnotateResult
forall a. Int -> a -> Vector a
V.replicate ([FileName] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [FileName]
inicontent) (Maybe PatchInfo
forall a. Maybe a
Nothing, ByteString
B.empty)
                        }

machineFormat :: B.ByteString -> AnnotateResult -> String
machineFormat :: ByteString -> AnnotateResult -> String
machineFormat d :: ByteString
d a :: AnnotateResult
a = [String] -> String
unlines [ case Maybe PatchInfo
i of
                                 Just inf :: PatchInfo
inf -> SHA1 -> String
forall a. Show a => a -> String
show (SHA1 -> String) -> SHA1 -> String
forall a b. (a -> b) -> a -> b
$ PatchInfo -> SHA1
makePatchname PatchInfo
inf
                                 Nothing -> -- make unknowns uniform, for easier parsing
                                   Int -> ShowS
forall a. Int -> [a] -> [a]
take 40 ( Char -> String
forall a. a -> [a]
repeat '0' ) -- fake hash of the right size
                              String -> ShowS
forall a. [a] -> [a] -> [a]
++ " | " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> String
BC.unpack ByteString
line String -> ShowS
forall a. [a] -> [a] -> [a]
++ " " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> String
BC.unpack ByteString
add
                            | ((i :: Maybe PatchInfo
i, add :: ByteString
add), line :: ByteString
line) <- [(Maybe PatchInfo, ByteString)]
-> [ByteString] -> [((Maybe PatchInfo, ByteString), ByteString)]
forall a b. [a] -> [b] -> [(a, b)]
zip (AnnotateResult -> [(Maybe PatchInfo, ByteString)]
forall a. Vector a -> [a]
V.toList AnnotateResult
a) (ByteString -> [ByteString]
breakLines ByteString
d) ]

format :: B.ByteString -> AnnotateResult -> String
format :: ByteString -> AnnotateResult -> String
format d :: ByteString
d a :: AnnotateResult
a = String
pi_list String -> ShowS
forall a. [a] -> [a] -> [a]
++ "\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
numbered
  where
    numberedLines :: [(Int, String)]
numberedLines = [Int] -> [String] -> [(Int, String)]
forall a b. [a] -> [b] -> [(a, b)]
zip [(1 :: Int)..] ([String] -> [(Int, String)])
-> (String -> [String]) -> String -> [(Int, String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines (String -> [(Int, String)]) -> String -> [(Int, String)]
forall a b. (a -> b) -> a -> b
$ String
file

    prependNum :: (a, String) -> String
prependNum (lnum :: a
lnum, annLine :: String
annLine) =
        let maxDigits :: Int
maxDigits = String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (String -> Int)
-> ([(Int, String)] -> String) -> [(Int, String)] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show (Int -> String)
-> ([(Int, String)] -> Int) -> [(Int, String)] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Int, String)] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([(Int, String)] -> Int) -> [(Int, String)] -> Int
forall a b. (a -> b) -> a -> b
$ [(Int, String)]
numberedLines
            lnumStr :: String
lnumStr = a -> String
forall a. Show a => a -> String
show a
lnum
            paddingNum :: Int
paddingNum = Int
maxDigits Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
lnumStr
        in Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
paddingNum ' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
lnumStr String -> ShowS
forall a. [a] -> [a] -> [a]
++ ": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
annLine

    numbered :: String
numbered = [String] -> String
unlines ([String] -> String)
-> ([(Int, String)] -> [String]) -> [(Int, String)] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, String) -> String) -> [(Int, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Int, String) -> String
forall a. Show a => (a, String) -> String
prependNum ([(Int, String)] -> String) -> [(Int, String)] -> String
forall a b. (a -> b) -> a -> b
$ [(Int, String)]
numberedLines

    pi_list :: String
pi_list = [String] -> String
unlines [ Int -> String
forall a. Show a => a -> String
show Int
n String -> ShowS
forall a. [a] -> [a] -> [a]
++ ": " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Doc -> String
renderString (PatchInfo -> Doc
displayPatchInfo PatchInfo
i)
                      | (Int
n :: Int, i :: PatchInfo
i) <- [Int] -> [PatchInfo] -> [(Int, PatchInfo)]
forall a b. [a] -> [b] -> [(a, b)]
zip [1..] [PatchInfo]
pis ]

    file :: String
file = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ (Maybe PatchInfo, ByteString) -> String
forall b. (Maybe PatchInfo, b) -> String
annotation (((Maybe PatchInfo, ByteString), ByteString)
-> (Maybe PatchInfo, ByteString)
forall a b. (a, b) -> a
fst (((Maybe PatchInfo, ByteString), ByteString)
 -> (Maybe PatchInfo, ByteString))
-> ((Maybe PatchInfo, ByteString), ByteString)
-> (Maybe PatchInfo, ByteString)
forall a b. (a -> b) -> a -> b
$ [((Maybe PatchInfo, ByteString), ByteString)]
-> ((Maybe PatchInfo, ByteString), ByteString)
forall a. [a] -> a
head [((Maybe PatchInfo, ByteString), ByteString)]
chunk) String -> ShowS
forall a. [a] -> [a] -> [a]
++ " | " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ((Maybe PatchInfo, ByteString), ByteString) -> String
forall a. ((a, ByteString), ByteString) -> String
line ([((Maybe PatchInfo, ByteString), ByteString)]
-> ((Maybe PatchInfo, ByteString), ByteString)
forall a. [a] -> a
head [((Maybe PatchInfo, ByteString), ByteString)]
chunk) String -> ShowS
forall a. [a] -> [a] -> [a]
++
                    "\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ [String] -> String
unlines [ Int -> ShowS
indent 25 (" | " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ((Maybe PatchInfo, ByteString), ByteString) -> String
forall a. ((a, ByteString), ByteString) -> String
line ((Maybe PatchInfo, ByteString), ByteString)
l) | ((Maybe PatchInfo, ByteString), ByteString)
l <- [((Maybe PatchInfo, ByteString), ByteString)]
-> [((Maybe PatchInfo, ByteString), ByteString)]
forall a. [a] -> [a]
tail [((Maybe PatchInfo, ByteString), ByteString)]
chunk ]
                  | [((Maybe PatchInfo, ByteString), ByteString)]
chunk <- [[((Maybe PatchInfo, ByteString), ByteString)]]
file_ann ]

    pis :: [PatchInfo]
pis = [PatchInfo] -> [PatchInfo]
forall a. Eq a => [a] -> [a]
nub ([PatchInfo] -> [PatchInfo]) -> [PatchInfo] -> [PatchInfo]
forall a b. (a -> b) -> a -> b
$ ((Maybe PatchInfo, ByteString) -> Maybe PatchInfo)
-> [(Maybe PatchInfo, ByteString)] -> [PatchInfo]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (Maybe PatchInfo, ByteString) -> Maybe PatchInfo
forall a b. (a, b) -> a
fst ([(Maybe PatchInfo, ByteString)] -> [PatchInfo])
-> [(Maybe PatchInfo, ByteString)] -> [PatchInfo]
forall a b. (a -> b) -> a -> b
$ AnnotateResult -> [(Maybe PatchInfo, ByteString)]
forall a. Vector a -> [a]
V.toList AnnotateResult
a

    pi_map :: Map PatchInfo Int
pi_map = [(PatchInfo, Int)] -> Map PatchInfo Int
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([PatchInfo] -> [Int] -> [(PatchInfo, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip [PatchInfo]
pis [1 :: Int ..])

    file_ann :: [[((Maybe PatchInfo, ByteString), ByteString)]]
file_ann = (((Maybe PatchInfo, ByteString), ByteString)
 -> ((Maybe PatchInfo, ByteString), ByteString) -> Bool)
-> [((Maybe PatchInfo, ByteString), ByteString)]
-> [[((Maybe PatchInfo, ByteString), ByteString)]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy ((Maybe PatchInfo, ByteString)
-> (Maybe PatchInfo, ByteString) -> Bool
forall a. Eq a => a -> a -> Bool
(==) ((Maybe PatchInfo, ByteString)
 -> (Maybe PatchInfo, ByteString) -> Bool)
-> (((Maybe PatchInfo, ByteString), ByteString)
    -> (Maybe PatchInfo, ByteString))
-> ((Maybe PatchInfo, ByteString), ByteString)
-> ((Maybe PatchInfo, ByteString), ByteString)
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` ((Maybe PatchInfo, ByteString), ByteString)
-> (Maybe PatchInfo, ByteString)
forall a b. (a, b) -> a
fst) ([((Maybe PatchInfo, ByteString), ByteString)]
 -> [[((Maybe PatchInfo, ByteString), ByteString)]])
-> [((Maybe PatchInfo, ByteString), ByteString)]
-> [[((Maybe PatchInfo, ByteString), ByteString)]]
forall a b. (a -> b) -> a -> b
$ [(Maybe PatchInfo, ByteString)]
-> [ByteString] -> [((Maybe PatchInfo, ByteString), ByteString)]
forall a b. [a] -> [b] -> [(a, b)]
zip (AnnotateResult -> [(Maybe PatchInfo, ByteString)]
forall a. Vector a -> [a]
V.toList AnnotateResult
a) (ByteString -> [ByteString]
breakLines ByteString
d)

    line :: ((a, ByteString), ByteString) -> String
line ((_, add :: ByteString
add), l :: ByteString
l) = ByteString -> String
decodeLocale (ByteString -> String) -> ByteString -> String
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
BC.concat [ByteString
l, " ", ByteString
add]

    annotation :: (Maybe PatchInfo, b) -> String
annotation (Just i :: PatchInfo
i, _) | Just n :: Int
n <- PatchInfo -> Map PatchInfo Int -> Maybe Int
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup PatchInfo
i Map PatchInfo Int
pi_map =
        Int -> ShowS
pad 20 (PatchInfo -> String
piMail PatchInfo
i) String -> ShowS
forall a. [a] -> [a] -> [a]
++ " " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> ShowS
pad 4 ('#' Char -> ShowS
forall a. a -> [a] -> [a]
: Int -> String
forall a. Show a => a -> String
show Int
n)
    annotation _ = Int -> ShowS
pad 25 "unknown"

    pad :: Int -> ShowS
pad n :: Int
n str :: String
str = Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
str) ' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> ShowS
forall a. Int -> [a] -> [a]
take Int
n String
str

    indent :: Int -> ShowS
indent n :: Int
n str :: String
str = Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
n ' ' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
str

    piMail :: PatchInfo -> String
piMail pi :: PatchInfo
pi
        | '<' Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` PatchInfo -> String
piAuthor PatchInfo
pi = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '>') ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ShowS
forall a. Int -> [a] -> [a]
drop 1 ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '<') ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ PatchInfo -> String
piAuthor PatchInfo
pi
        | Bool
otherwise = PatchInfo -> String
piAuthor PatchInfo
pi

breakLines :: BC.ByteString -> [BC.ByteString]
breakLines :: ByteString -> [ByteString]
breakLines s :: ByteString
s = case Char -> ByteString -> [ByteString]
BC.split '\n' ByteString
s of
    [] -> []
    split :: [ByteString]
split | ByteString -> Bool
BC.null ([ByteString] -> ByteString
forall a. [a] -> a
last [ByteString]
split) -> [ByteString] -> [ByteString]
forall a. [a] -> [a]
init [ByteString]
split
          | Bool
otherwise -> [ByteString]
split