% Copyright (C) 2002-2004 David Roundy % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation; either version 2, or (at your option) % any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program; see the file COPYING. If not, write to % the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, % Boston, MA 02110-1301, USA. \begin{code} module PatchViewing ( showContextPatch, patch_summary, xml_summary, patch_description ) where import Prelude hiding ( pi ) import Control.Monad ( liftM ) import List ( sort ) import SlurpDirectory ( Slurpy, get_slurp, get_filecontents ) import FastPackedString ( nullPS ) import FileName ( FileName, fp2fn, fn2fp ) import Printer ( Doc, empty, vcat, text, blueText, minus, plus, ($$), (<+>), (<>), prefix, userchunkPS, ) import PatchInfo ( human_friendly ) import PatchCore ( Patch(..), DirPatchType(..), FilePatchType(..), flatten_to_primitives, fn2d, is_hunk, null_patch, patch2patchinfo ) import PatchShow ( showPatch, showNamedPrefix ) import PatchApply ( apply_to_slurpy ) import PatchCommute ( merger_equivalent ) #include "impossible.h" \end{code} \begin{code} showContextPatch :: Slurpy -> Patch -> Doc showContextPatch s p@(FP _ (Hunk _ _ _)) = showContextHunk s p showContextPatch s (ComP ps) = showContextComP s ps showContextPatch s (Split ps) = showContextSplit s ps showContextPatch s p@(NamedP _ _ _) = showContextNamed s p showContextPatch _ p = showPatch p \end{code} \begin{code} showContextComP :: Slurpy -> [Patch] -> Doc showContextComP slurpy patches = text "{" $$ showContextSeries slurpy patches $$ text "}" showContextSeries :: Slurpy -> [Patch] -> Doc showContextSeries slur patches = scs slur null_patch patches where scs s pold (p:p2:ps) | is_hunk p = coolContextHunk s pold p p2 $$ scs (fromJust $ apply_to_slurpy p s) p (p2:ps) scs s pold [p] | is_hunk p = coolContextHunk s pold p null_patch scs s _ (p:ps) = showContextPatch s p $$ scs (fromJust $ apply_to_slurpy p s) p ps scs _ _ [] = empty \end{code} \begin{code} showContextSplit :: Slurpy -> [Patch] -> Doc showContextSplit slurpy patches = text "(" $$ showContextSeries slurpy patches <> text ")" \end{code} \begin{code} showContextHunk :: Slurpy -> Patch -> Doc showContextHunk s p = coolContextHunk s null_patch p null_patch coolContextHunk :: Slurpy -> Patch -> Patch -> Patch -> Doc coolContextHunk s prev p@(FP f (Hunk l o n)) next = case (fst . get_filecontents) `liftM` get_slurp f s of Nothing -> showPatch p -- This is a weird error... Just ls -> let numpre = case prev of (FP f' (Hunk lprev _ nprev)) | f' == f && l - (lprev + length nprev + 3) < 3 && lprev < l -> max 0 $ l - (lprev + length nprev + 3) _ -> if l >= 4 then 3 else l - 1 pre = take numpre $ drop (l - numpre - 1) ls numpost = case next of (FP f' (Hunk lnext _ _)) | f' == f && lnext < l+length n+4 && lnext > l -> lnext - (l+length n) _ -> 3 cleanedls = case reverse ls of (x:xs) | nullPS x -> reverse xs _ -> ls post = take numpost $ drop (max 0 $ l+length o-1) cleanedls in blueText "hunk" <+> fn2d f <+> text (show l) $$ prefix " " (vcat $ map userchunkPS pre) $$ prefix "-" (vcat $ map userchunkPS o) $$ prefix "+" (vcat $ map userchunkPS n) $$ prefix " " (vcat $ map userchunkPS post) coolContextHunk _ _ _ _ = impossible \end{code} \begin{code} showContextNamed :: Slurpy -> Patch -> Doc showContextNamed s (NamedP n d p) = showNamedPrefix n d <+> showContextPatch s p showContextNamed _ _ = impossible \end{code} \begin{code} patch_description :: Patch -> Doc patch_description p = case patch2patchinfo p of Nothing -> showPatch p Just pi -> human_friendly pi \end{code} \begin{code} -- FIXME: The following code is terribly crude (especially in the presense of mv's). patch_summary :: Patch -> Doc patch_summary = gen_summary False xml_summary :: Patch -> Doc xml_summary p = text "" $$ gen_summary True p $$ text "" -- Yuck duplicated code below... escapeXML :: String -> Doc escapeXML = text . strReplace '\'' "'" . strReplace '"' """ . strReplace '>' ">" . strReplace '<' "<" . strReplace '&' "&" strReplace :: Char -> String -> String -> String strReplace _ _ [] = [] strReplace x y (z:zs) | x == z = y ++ (strReplace x y zs) | otherwise = z : (strReplace x y zs) -- end yuck duplicated code. gen_summary :: Bool -> Patch -> Doc gen_summary use_xml p = vcat themoves $$ vcat themods where themods = map summ $ combine $ sort $ concatMap s $ flatten_to_primitives p s :: Patch -> [(FileName, Int, Int, Int, Bool, Bool)] s (FP f (Hunk _ o n)) = [(f, length o, length n, 0, False, False)] s (FP f (Binary _ _)) = [(f, 0, 0, 0, False, False)] s (FP f AddFile) = [(f, -1, 0, 0, False, False)] s (FP f RmFile) = [(f, 0, -1, 0, False, False)] s (FP f (TokReplace _ _ _)) = [(f, 0, 0, 1, False, False)] s (DP d AddDir) = [(d, -1, 0, 0, True, False)] s (DP d RmDir) = [(d, 0, -1, 0, True, False)] s m@(Merger _ _ _ _ _ _) = map (\ (a,b,c,d,e,_) -> (a,b,c,d,e,True)) $ concatMap s $ flatten_to_primitives $ merger_equivalent m s _ = [(fp2fn "", 0, 0, 0, False, False)] (-1) .+ _ = -1 _ .+ (-1) = -1 a .+ b = a + b combine ((f,a,b,r,isd,c):(f',a',b',r',_,c'):ss) -- Don't combine AddFile and RmFile: (maybe an old revision of) darcs -- allows a single patch to add and remove the same file, see issue 185 | f == f' && (a /= -1 || b' /= -1) && (a' /= -1 || b /= -1) = combine ((f,a.+a',b.+b',r+r',isd,c||c'):ss) combine ((f,a,b,r,isd,c):ss) = (f,a,b,r,isd,c) : combine ss combine [] = [] summ (f,_,-1,_,False,False) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) $$ text "" else text "R" <+> text (fn2fp f) summ (f,_,-1,_,False,True) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) $$ text "" else text "R!" <+> text (fn2fp f) summ (f,-1,_,_,False,False) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) $$ text "" else text "A" <+> text (fn2fp f) summ (f,-1,_,_,False,True) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) $$ text "" else text "A!" <+> text (fn2fp f) summ (f,0,0,0,False,False) | f == fp2fn "" = empty summ (f,0,0,0,False,True) | f == fp2fn "" = if use_xml then empty -- don't know what to do here... else text "!" <+> text (fn2fp f) summ (f,a,b,r,False,False) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) <> xrm a <> xad b <> xrp r $$ text "" else text "M" <+> text (fn2fp f) <+> rm a <+> ad b <+> rp r summ (f,a,b,r,False,True) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) <> xrm a <> xad b <> xrp r $$ text "" else text "M!" <+> text (fn2fp f) <+> rm a <+> ad b <+> rp r summ (f,_,-1,_,True,False) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) $$ text "" else text "R" <+> text (fn2fp f) <> text "/" summ (f,_,-1,_,True,True) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) $$ text "" else text "R!" <+> text (fn2fp f) <> text "/" summ (f,-1,_,_,True,False) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) $$ text "" else text "A" <+> text (fn2fp f) <> text "/" summ (f,-1,_,_,True,True) = if use_xml then text "" $$ escapeXML (drop_dotslash $ fn2fp f) $$ text "" else text "A!" <+> text (fn2fp f) <> text "/" summ _ = empty ad 0 = empty ad a = plus <> text (show a) xad 0 = empty xad a = text "" rm 0 = empty rm a = minus <> text (show a) xrm 0 = empty xrm a = text "" rp 0 = empty rp a = text "r" <> text (show a) xrp 0 = empty xrp a = text "" drop_dotslash ('.':'/':str) = drop_dotslash str drop_dotslash str = str themoves :: [Doc] themoves = map showmoves $ flatten_to_primitives p showmoves :: Patch -> Doc showmoves (Move a b) = if use_xml then text " escapeXML (drop_dotslash $ fn2fp a) <> text "\" to=\"" <> escapeXML (drop_dotslash $ fn2fp b) <> text"\"/>" else text " " <> text (fn2fp a) <> text " -> " <> text (fn2fp b) showmoves _ = empty \end{code}