{-# LANGUAGE OverloadedStrings #-}

-- 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

{-# OPTIONS_GHC -Wno-orphans #-}
module Darcs.Patch.Annotate
    (
      annotateFile
    , annotateDirectory
    , format
    , machineFormat
    , AnnotateResult
    , Annotate(..)
    , AnnotateRP
    ) where

import Darcs.Prelude

import Control.Monad ( when )
import Control.Monad.State ( modify, modify', gets, 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 )
import Data.List.NonEmpty ( groupBy )
import qualified Data.List.NonEmpty as NE
import Data.Maybe( isJust, mapMaybe )

import qualified Darcs.Patch.Prim.FileUUID as FileUUID

import Darcs.Patch.Annotate.Class
import Darcs.Patch.Effect ( Effect(..) )
import Darcs.Patch.FromPrim ( PrimOf(..) )
import Darcs.Patch.Info ( displayPatchInfo, piAuthor, makePatchname )
import Darcs.Patch.Invert ( Invert, invert )
import Darcs.Patch.Named ( patchcontents )
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 ( AnchoredPath, movedirfilename, flatten )
import Darcs.Util.Printer( renderString )
import Darcs.Util.ByteString ( linesPS, decodeLocale )

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

-- |This constraint expresses what is needed for a repo patch to
-- support the high-level interface to annotation
-- (currently annotateFile and annotateDirectory)
type AnnotateRP p = (Annotate (PrimOf p), Invert (PrimOf p), Effect p)

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

instance Annotate FileUUID.Prim where
  annotate :: forall wX wY. Prim wX wY -> AnnotatedM ()
annotate Prim wX wY
_ = [Char] -> AnnotatedM ()
forall a. HasCallStack => [Char] -> a
error [Char]
"annotate not implemented for FileUUID patches"

annotatePIAP :: AnnotateRP p => PatchInfoAnd p wX wY -> AnnotatedM ()
annotatePIAP :: forall (p :: * -> * -> *) wX wY.
AnnotateRP p =>
PatchInfoAnd p wX wY -> AnnotatedM ()
annotatePIAP =
  [AnnotatedM ()] -> AnnotatedM ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ ([AnnotatedM ()] -> AnnotatedM ())
-> (PatchInfoAnd p wX wY -> [AnnotatedM ()])
-> PatchInfoAnd p wX wY
-> AnnotatedM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall wW wZ. PrimOf p wW wZ -> AnnotatedM ())
-> FL (PrimOf p) wY wX -> [AnnotatedM ()]
forall (a :: * -> * -> *) b wX wY.
(forall wW wZ. a wW wZ -> b) -> FL a wX wY -> [b]
mapFL PrimOf p wW wZ -> AnnotatedM ()
forall wW wZ. PrimOf p wW wZ -> AnnotatedM ()
forall (p :: * -> * -> *) wX wY.
Annotate p =>
p wX wY -> AnnotatedM ()
annotate (FL (PrimOf p) wY wX -> [AnnotatedM ()])
-> (PatchInfoAnd p wX wY -> FL (PrimOf p) wY wX)
-> PatchInfoAnd p wX wY
-> [AnnotatedM ()]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FL (PrimOf p) wX wY -> FL (PrimOf p) wY wX
forall wX wY. FL (PrimOf p) wX wY -> FL (PrimOf p) wY wX
forall (p :: * -> * -> *) wX wY. Invert p => p wX wY -> p wY wX
invert (FL (PrimOf p) wX wY -> FL (PrimOf p) wY wX)
-> (PatchInfoAnd p wX wY -> FL (PrimOf p) wX wY)
-> PatchInfoAnd p wX wY
-> FL (PrimOf p) wY wX
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FL p wX wY -> FL (PrimOf p) wX wY
FL p wX wY -> FL (PrimOf (FL p)) wX wY
forall wX wY. FL p wX wY -> FL (PrimOf (FL p)) wX wY
forall (p :: * -> * -> *) wX wY.
Effect p =>
p wX wY -> FL (PrimOf p) wX wY
effect (FL p wX wY -> FL (PrimOf p) wX wY)
-> (PatchInfoAnd p wX wY -> FL p wX wY)
-> PatchInfoAnd p wX wY
-> FL (PrimOf p) wX wY
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Named p wX wY -> FL p wX wY
forall (p :: * -> * -> *) wX wY. Named p wX wY -> FL p wX wY
patchcontents (Named p wX wY -> FL p wX wY)
-> (PatchInfoAnd p wX wY -> Named p wX wY)
-> PatchInfoAnd p wX wY
-> FL p wX wY
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PatchInfoAnd p wX wY -> Named p wX wY
forall (p :: * -> * -> *) wA wB. PatchInfoAndG p wA wB -> p wA wB
hopefully

withDirectory :: ([(Int, AnchoredPath)] -> AnnotatedM ()) -> AnnotatedM ()
withDirectory :: ([(Int, AnchoredPath)] -> AnnotatedM ()) -> AnnotatedM ()
withDirectory [(Int, AnchoredPath)] -> AnnotatedM ()
actions = do
  Content2 [] ((,) Int)
what <- (Annotated2 [] ((,) Int) -> Content2 [] ((,) Int))
-> StateT
     (Annotated2 [] ((,) Int)) Identity (Content2 [] ((,) Int))
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated2 [] ((,) Int) -> Content2 [] ((,) Int)
forall (f :: * -> *) (g :: * -> *). Annotated2 f g -> Content2 f g
current
  case Content2 [] ((,) Int)
what of
    DirContent [(Int, AnchoredPath)]
c -> [(Int, AnchoredPath)] -> AnnotatedM ()
actions [(Int, AnchoredPath)]
c
    FileContent [(Int, ByteString)]
_ -> () -> AnnotatedM ()
forall a. a -> StateT (Annotated2 [] ((,) Int)) Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

withFile :: ([(Int, B.ByteString)] -> AnnotatedM ()) -> AnnotatedM ()
withFile :: ([(Int, ByteString)] -> AnnotatedM ()) -> AnnotatedM ()
withFile [(Int, ByteString)] -> AnnotatedM ()
actions = do
  Content2 [] ((,) Int)
what <- (Annotated2 [] ((,) Int) -> Content2 [] ((,) Int))
-> StateT
     (Annotated2 [] ((,) Int)) Identity (Content2 [] ((,) Int))
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated2 [] ((,) Int) -> Content2 [] ((,) Int)
forall (f :: * -> *) (g :: * -> *). Annotated2 f g -> Content2 f g
current
  case Content2 [] ((,) Int)
what of
    FileContent [(Int, ByteString)]
c -> [(Int, ByteString)] -> AnnotatedM ()
actions [(Int, ByteString)]
c
    DirContent [(Int, AnchoredPath)]
_ -> () -> AnnotatedM ()
forall a. a -> StateT (Annotated2 [] ((,) Int)) Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

whenPathIs :: AnchoredPath -> AnnotatedM () -> AnnotatedM ()
whenPathIs :: AnchoredPath -> AnnotatedM () -> AnnotatedM ()
whenPathIs AnchoredPath
fn AnnotatedM ()
actions = do
  Maybe AnchoredPath
p <- (Annotated2 [] ((,) Int) -> Maybe AnchoredPath)
-> StateT (Annotated2 [] ((,) Int)) Identity (Maybe AnchoredPath)
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets Annotated2 [] ((,) Int) -> Maybe AnchoredPath
forall (f :: * -> *) (g :: * -> *).
Annotated2 f g -> Maybe AnchoredPath
currentPath
  Bool -> AnnotatedM () -> AnnotatedM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe AnchoredPath
p Maybe AnchoredPath -> Maybe AnchoredPath -> Bool
forall a. Eq a => a -> a -> Bool
== AnchoredPath -> Maybe AnchoredPath
forall a. a -> Maybe a
Just AnchoredPath
fn) AnnotatedM ()
actions

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

merge :: a
      -> V.Vector (Maybe a, BC.ByteString)
      -> [(Int, t)]
      -> V.Vector (Maybe a, BC.ByteString)
merge :: forall a t.
a
-> Vector (Maybe a, ByteString)
-> [(Int, t)]
-> Vector (Maybe a, ByteString)
merge a
i Vector (Maybe a, ByteString)
a [(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))
                     | (Int
line, t
_) <- [(Int, t)]
l, Int
line Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
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 :: AnchoredPath -> [(Int,AnchoredPath)] -> AnnotatedM ()
updateDirectory :: AnchoredPath -> [(Int, AnchoredPath)] -> AnnotatedM ()
updateDirectory AnchoredPath
path [(Int, AnchoredPath)]
files = do
    case ((Int, AnchoredPath) -> Bool)
-> [(Int, AnchoredPath)] -> [(Int, AnchoredPath)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((AnchoredPath -> AnchoredPath -> Bool
forall a. Eq a => a -> a -> Bool
==AnchoredPath
path) (AnchoredPath -> Bool)
-> ((Int, AnchoredPath) -> AnchoredPath)
-> (Int, AnchoredPath)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, AnchoredPath) -> AnchoredPath
forall a b. (a, b) -> b
snd) [(Int, AnchoredPath)]
files of
      [match :: (Int, AnchoredPath)
match@(Int
ident, AnchoredPath
_)] -> Int -> (Int, AnchoredPath) -> AnnotatedM ()
reannotate Int
ident (Int, AnchoredPath)
match
      [(Int, AnchoredPath)]
_ -> () -> AnnotatedM ()
forall a. a -> StateT (Annotated2 [] ((,) Int)) Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  where
    reannotate :: Int -> (Int, AnchoredPath) -> AnnotatedM ()
    reannotate :: Int -> (Int, AnchoredPath) -> AnnotatedM ()
reannotate Int
ident (Int, AnchoredPath)
match =
      (Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int))
-> AnnotatedM ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int))
 -> AnnotatedM ())
-> (Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int))
-> AnnotatedM ()
forall a b. (a -> b) -> a -> b
$ \Annotated2 [] ((,) Int)
x -> Annotated2 [] ((,) Int)
x { annotated = annotated x V.// [ (ident, update $ currentInfo x) ]
                       , current = DirContent $ filter (/= match) files }
    update :: a -> (Maybe a, ByteString)
update a
inf = (a -> Maybe a
forall a. a -> Maybe a
Just a
inf, AnchoredPath -> ByteString
flatten AnchoredPath
path)

complete :: Annotated -> Bool
complete :: Annotated2 [] ((,) Int) -> Bool
complete Annotated2 [] ((,) Int)
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
$ Annotated2 [] ((,) Int) -> AnnotateResult
forall (f :: * -> *) (g :: * -> *).
Annotated2 f g -> AnnotateResult
annotated Annotated2 [] ((,) Int)
x

annotate' :: AnnotateRP p
          => RL (PatchInfoAnd p) wX wY
          -> Annotated
          -> Annotated
annotate' :: forall (p :: * -> * -> *) wX wY.
AnnotateRP p =>
RL (PatchInfoAnd p) wX wY
-> Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int)
annotate' RL (PatchInfoAnd p) wX wY
NilRL Annotated2 [] ((,) Int)
ann = Annotated2 [] ((,) Int)
ann
annotate' (RL (PatchInfoAnd p) wX wY
ps :<: PatchInfoAnd p wY wY
p) Annotated2 [] ((,) Int)
ann
    | Annotated2 [] ((,) Int) -> Bool
complete Annotated2 [] ((,) Int)
ann = Annotated2 [] ((,) Int)
ann
    | Bool
otherwise = RL (PatchInfoAnd p) wX wY
-> Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int)
forall (p :: * -> * -> *) wX wY.
AnnotateRP p =>
RL (PatchInfoAnd p) wX wY
-> Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int)
annotate' RL (PatchInfoAnd p) wX wY
ps (Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int))
-> Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int)
forall a b. (a -> b) -> a -> b
$ AnnotatedM () -> Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int)
forall s a. State s a -> s -> s
execState (PatchInfoAnd p wY wY -> AnnotatedM ()
forall (p :: * -> * -> *) wX wY.
AnnotateRP p =>
PatchInfoAnd p wX wY -> AnnotatedM ()
annotatePIAP PatchInfoAnd p wY wY
p) (Annotated2 [] ((,) Int)
ann { currentInfo = info p })

annotateFile :: AnnotateRP p
             => RL (PatchInfoAnd p) wX wY
             -> AnchoredPath
             -> B.ByteString
             -> AnnotateResult
annotateFile :: forall (p :: * -> * -> *) wX wY.
AnnotateRP p =>
RL (PatchInfoAnd p) wX wY
-> AnchoredPath -> ByteString -> AnnotateResult
annotateFile RL (PatchInfoAnd p) wX wY
patches AnchoredPath
inipath ByteString
inicontent = Annotated2 [] ((,) Int) -> AnnotateResult
forall (f :: * -> *) (g :: * -> *).
Annotated2 f g -> AnnotateResult
annotated (Annotated2 [] ((,) Int) -> AnnotateResult)
-> Annotated2 [] ((,) Int) -> AnnotateResult
forall a b. (a -> b) -> a -> b
$ RL (PatchInfoAnd p) wX wY
-> Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int)
forall (p :: * -> * -> *) wX wY.
AnnotateRP p =>
RL (PatchInfoAnd p) wX wY
-> Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int)
annotate' RL (PatchInfoAnd p) wX wY
patches Annotated2 [] ((,) Int)
initial
  where
    initial :: Annotated2 [] ((,) Int)
initial = Annotated2 { currentPath :: Maybe AnchoredPath
currentPath = AnchoredPath -> Maybe AnchoredPath
forall a. a -> Maybe a
Just AnchoredPath
inipath
                        , currentInfo :: PatchInfo
currentInfo = [Char] -> PatchInfo
forall a. HasCallStack => [Char] -> a
error [Char]
"There is no currentInfo."
                        , current :: Content2 [] ((,) Int)
current = [(Int, ByteString)] -> Content2 [] ((,) Int)
forall (f :: * -> *) (g :: * -> *).
f (g ByteString) -> Content2 f g
FileContent ([(Int, ByteString)] -> Content2 [] ((,) Int))
-> [(Int, ByteString)] -> Content2 [] ((,) Int)
forall a b. (a -> b) -> a -> b
$ [Int] -> [ByteString] -> [(Int, ByteString)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] (ByteString -> [ByteString]
linesPS ByteString
inicontent)
                        , annotated :: AnnotateResult
annotated = Int -> (Maybe PatchInfo, ByteString) -> AnnotateResult
forall a. Int -> a -> Vector a
V.replicate ([ByteString] -> Int
forall a. [a] -> 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 :: AnnotateRP p
                  => RL (PatchInfoAnd p) wX wY
                  -> AnchoredPath
                  -> [AnchoredPath]
                  -> AnnotateResult
annotateDirectory :: forall (p :: * -> * -> *) wX wY.
AnnotateRP p =>
RL (PatchInfoAnd p) wX wY
-> AnchoredPath -> [AnchoredPath] -> AnnotateResult
annotateDirectory RL (PatchInfoAnd p) wX wY
patches AnchoredPath
inipath [AnchoredPath]
inicontent = Annotated2 [] ((,) Int) -> AnnotateResult
forall (f :: * -> *) (g :: * -> *).
Annotated2 f g -> AnnotateResult
annotated (Annotated2 [] ((,) Int) -> AnnotateResult)
-> Annotated2 [] ((,) Int) -> AnnotateResult
forall a b. (a -> b) -> a -> b
$ RL (PatchInfoAnd p) wX wY
-> Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int)
forall (p :: * -> * -> *) wX wY.
AnnotateRP p =>
RL (PatchInfoAnd p) wX wY
-> Annotated2 [] ((,) Int) -> Annotated2 [] ((,) Int)
annotate' RL (PatchInfoAnd p) wX wY
patches Annotated2 [] ((,) Int)
initial
  where
    initial :: Annotated2 [] ((,) Int)
initial = Annotated2 { currentPath :: Maybe AnchoredPath
currentPath = AnchoredPath -> Maybe AnchoredPath
forall a. a -> Maybe a
Just AnchoredPath
inipath
                        , currentInfo :: PatchInfo
currentInfo = [Char] -> PatchInfo
forall a. HasCallStack => [Char] -> a
error [Char]
"There is no currentInfo."
                        , current :: Content2 [] ((,) Int)
current = [(Int, AnchoredPath)] -> Content2 [] ((,) Int)
forall (f :: * -> *) (g :: * -> *).
f (g AnchoredPath) -> Content2 f g
DirContent ([(Int, AnchoredPath)] -> Content2 [] ((,) Int))
-> [(Int, AnchoredPath)] -> Content2 [] ((,) Int)
forall a b. (a -> b) -> a -> b
$ [Int] -> [AnchoredPath] -> [(Int, AnchoredPath)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] [AnchoredPath]
inicontent
                        , annotated :: AnnotateResult
annotated = Int -> (Maybe PatchInfo, ByteString) -> AnnotateResult
forall a. Int -> a -> Vector a
V.replicate ([AnchoredPath] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [AnchoredPath]
inicontent) (Maybe PatchInfo
forall a. Maybe a
Nothing, ByteString
B.empty)
                        }

machineFormat :: B.ByteString -> AnnotateResult -> String
machineFormat :: ByteString -> AnnotateResult -> [Char]
machineFormat ByteString
d AnnotateResult
a = [[Char]] -> [Char]
unlines [ case Maybe PatchInfo
i of
                                 Just PatchInfo
inf -> SHA1 -> [Char]
forall a. Show a => a -> [Char]
show (SHA1 -> [Char]) -> SHA1 -> [Char]
forall a b. (a -> b) -> a -> b
$ PatchInfo -> SHA1
makePatchname PatchInfo
inf
                                 Maybe PatchInfo
Nothing -> -- make unknowns uniform, for easier parsing
                                   Int -> ShowS
forall a. Int -> [a] -> [a]
take Int
40 ( Char -> [Char]
forall a. a -> [a]
repeat Char
'0' ) -- fake hash of the right size
                              [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
" | " [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
BC.unpack ByteString
line [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
" " [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ ByteString -> [Char]
BC.unpack ByteString
add
                            | ((Maybe PatchInfo
i, ByteString
add), 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 -> [Char]
format ByteString
d AnnotateResult
a = [Char]
pi_list [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
"\n" [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
numbered
  where
    numberedLines :: [(Int, [Char])]
numberedLines = [Int] -> [[Char]] -> [(Int, [Char])]
forall a b. [a] -> [b] -> [(a, b)]
zip [(Int
1 :: Int)..] ([[Char]] -> [(Int, [Char])])
-> ([Char] -> [[Char]]) -> [Char] -> [(Int, [Char])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]]
lines ([Char] -> [(Int, [Char])]) -> [Char] -> [(Int, [Char])]
forall a b. (a -> b) -> a -> b
$ [Char]
file

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

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

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

    file :: [Char]
file = [[Char]] -> [Char]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ (Maybe PatchInfo, ByteString) -> [Char]
forall {b}. (Maybe PatchInfo, b) -> [Char]
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
$ NonEmpty ((Maybe PatchInfo, ByteString), ByteString)
-> ((Maybe PatchInfo, ByteString), ByteString)
forall a. NonEmpty a -> a
NE.head NonEmpty ((Maybe PatchInfo, ByteString), ByteString)
chunk) [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
" | " [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ ((Maybe PatchInfo, ByteString), ByteString) -> [Char]
forall {a}. ((a, ByteString), ByteString) -> [Char]
line (NonEmpty ((Maybe PatchInfo, ByteString), ByteString)
-> ((Maybe PatchInfo, ByteString), ByteString)
forall a. NonEmpty a -> a
NE.head NonEmpty ((Maybe PatchInfo, ByteString), ByteString)
chunk) [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++
                    [Char]
"\n" [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [[Char]] -> [Char]
unlines [ Int -> ShowS
indent Int
25 ([Char]
" | " [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ ((Maybe PatchInfo, ByteString), ByteString) -> [Char]
forall {a}. ((a, ByteString), ByteString) -> [Char]
line ((Maybe PatchInfo, ByteString), ByteString)
l) | ((Maybe PatchInfo, ByteString), ByteString)
l <- NonEmpty ((Maybe PatchInfo, ByteString), ByteString)
-> [((Maybe PatchInfo, ByteString), ByteString)]
forall a. NonEmpty a -> [a]
NE.tail NonEmpty ((Maybe PatchInfo, ByteString), ByteString)
chunk ]
                  | NonEmpty ((Maybe PatchInfo, ByteString), ByteString)
chunk <- [NonEmpty ((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 [Int
1 :: Int ..])

    file_ann :: [NonEmpty ((Maybe PatchInfo, ByteString), ByteString)]
file_ann = (((Maybe PatchInfo, ByteString), ByteString)
 -> ((Maybe PatchInfo, ByteString), ByteString) -> Bool)
-> [((Maybe PatchInfo, ByteString), ByteString)]
-> [NonEmpty ((Maybe PatchInfo, ByteString), ByteString)]
forall (f :: * -> *) a.
Foldable f =>
(a -> a -> Bool) -> f a -> [NonEmpty 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)]
 -> [NonEmpty ((Maybe PatchInfo, ByteString), ByteString)])
-> [((Maybe PatchInfo, ByteString), ByteString)]
-> [NonEmpty ((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) -> [Char]
line ((a
_, ByteString
add), ByteString
l) = ByteString -> [Char]
decodeLocale (ByteString -> [Char]) -> ByteString -> [Char]
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
BC.concat [ByteString
l, ByteString
" ", ByteString
add]

    annotation :: (Maybe PatchInfo, b) -> [Char]
annotation (Just PatchInfo
i, b
_) | Just 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 Int
20 (PatchInfo -> [Char]
piMail PatchInfo
i) [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ [Char]
" " [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> ShowS
pad Int
4 (Char
'#' Char -> ShowS
forall a. a -> [a] -> [a]
: Int -> [Char]
forall a. Show a => a -> [Char]
show Int
n)
    annotation (Maybe PatchInfo, b)
_ = Int -> ShowS
pad Int
25 [Char]
"unknown"

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

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

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

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