spaces kinda work
This commit is contained in:
		
							parent
							
								
									951e8bb18a
								
							
						
					
					
						commit
						960f316059
					
				
							
								
								
									
										195
									
								
								Main.hs
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								Main.hs
									
									
									
									
									
								
							|  | @ -6,6 +6,7 @@ import Control.Exception | |||
| import Control.Monad | ||||
| import Data.Bool | ||||
| import Data.Foldable | ||||
| import Data.Function | ||||
| import Data.List | ||||
| import Data.Maybe | ||||
| import Data.Traversable | ||||
|  | @ -20,6 +21,8 @@ import System.Process | |||
| import qualified Toks | ||||
| import Toks (Tok) | ||||
| 
 | ||||
| import Debug.Trace | ||||
| 
 | ||||
| {- | ||||
|  - interface to other programs | ||||
|  -} | ||||
|  | @ -127,8 +130,6 @@ hSplitToFile cfg h path = | |||
| {- | ||||
|  - merge algorithms | ||||
|  -} | ||||
| despace toks = filter (not . Toks.space) | ||||
| 
 | ||||
| data Op | ||||
|   = Del | ||||
|   | Keep | ||||
|  | @ -145,22 +146,79 @@ pdiff path = map go . lines <$> readFile path | |||
| 
 | ||||
| data Merged | ||||
|   = Ok [String] | ||||
|   | Replace [String] [String] | ||||
|   | Conflict [String] [String] [String] | ||||
|   deriving (Show) | ||||
| 
 | ||||
| align :: [(Op, String)] -> [(Op, String)] -> [Merged] | ||||
| align [] [] = [] | ||||
| align ((Keep, m):ms) ((Keep, y):ys) | ||||
|   | m == y = Ok [m] : align ms ys | ||||
| align ((Del, m):ms) ((Del, y):ys) | ||||
|   | m == y = Conflict [] [m] [] : align ms ys | ||||
| align ((Del, m):ms) ((Keep, y):ys) | ||||
|   | m == y = Conflict [] [m] [m] : align ms ys | ||||
| align ((Keep, m):ms) ((Del, y):ys) | ||||
|   | m == y = Conflict [m] [m] [] : align ms ys | ||||
| align ((Add, m):ms) ys = Conflict [m] [] [] : align ms ys | ||||
| align ms ((Add, y):ys) = Conflict [] [] [y] : align ms ys | ||||
| align _ _ = error "diffs do not align" | ||||
| isKeepTok (Keep, _) = True | ||||
| isKeepTok _ = False | ||||
| 
 | ||||
| isDelTok (Del, _) = True | ||||
| isDelTok _ = False | ||||
| 
 | ||||
| chunks :: [(Op, String)] -> [Merged] | ||||
| chunks [] = [] | ||||
| chunks xs@((Keep, _):_) = | ||||
|   let (oks, ys) = span isKeepTok xs | ||||
|    in Ok (map snd oks) : chunks ys | ||||
| chunks xs = | ||||
|   let (reps, ys) = break isKeepTok xs | ||||
|    in uncurry (Replace `on` map snd) (partition isDelTok reps) : chunks ys | ||||
| 
 | ||||
| align1 as [] = ([], as, []) | ||||
| align1 [] bs = ([], [], bs) | ||||
| align1 (a:as) (b:bs) | ||||
|   | a == b | ||||
|   , (xs, as', bs') <- align1 as bs = (a : xs, as', bs') | ||||
| align1 _ _ = error "chunks do not align" | ||||
| 
 | ||||
| align :: [Merged] -> [Merged] -> [Merged] | ||||
| align m y = connect $ slice m y | ||||
|   where | ||||
|     erase x = Replace x [] | ||||
|     nemap _ [] = [] | ||||
|     nemap f xs = [f xs] | ||||
|     slice (Ok m:ms) (Ok y:ys) = | ||||
|       let (ok, m', y') = align1 m y | ||||
|        in (Ok ok, Ok ok) : slice (nemap Ok m' ++ ms) (nemap Ok y' ++ ys) | ||||
|     slice (Replace m mr:ms) (Ok y:ys) = | ||||
|       let (ok, m', y') = align1 m y | ||||
|        in (Replace ok mr, Ok ok) | ||||
|             : slice (nemap erase m' ++ ms) (nemap Ok y' ++ ys) | ||||
|     slice (Ok m:ms) (Replace y yr:ys) = | ||||
|       let (ok, m', y') = align1 m y | ||||
|        in (Ok ok, Replace ok yr) | ||||
|             : slice (nemap Ok m' ++ ms) (nemap erase y' ++ ys) | ||||
|     slice (Replace m mr:ms) (Replace y yr:ys) = | ||||
|       let (ok, m', y') = align1 m y | ||||
|        in (Replace ok mr, Replace ok yr) | ||||
|             : slice (nemap erase m' ++ ms) (nemap erase y' ++ ys) | ||||
|     slice [Replace [] mr] [] = [(Replace [] mr, Ok [])] | ||||
|     slice [] [Replace [] yr] = [(Ok [], Replace [] yr)] | ||||
|     slice [] [] = [] | ||||
|     slice _ _ = error "unacceptable chunks" | ||||
|     coFlag (Ok _) = False | ||||
|     coFlag (Replace _ _) = True | ||||
|     coSig (a, b) = (coFlag a, coFlag b) | ||||
|     coConn' (a, b) (a', b') = (a && a') || (b && b') | ||||
|     coConn = coConn' `on` coSig | ||||
|     coGroup [] = [] | ||||
|     coGroup (x:xs) = | ||||
|       case coGroup xs of | ||||
|         xs'@(ys@(y:_):yss) | ||||
|           | coConn x y -> (x : ys) : yss | ||||
|         xs' -> [x] : xs' | ||||
|     connect = map confl . coGroup | ||||
|     toCon (Ok m, Ok _) = Ok m | ||||
|     toCon (Ok o, Replace _ y) = Conflict o o y | ||||
|     toCon (Replace o m, Ok _) = Conflict m o o | ||||
|     toCon (Replace o m, Replace _ y) = Conflict m o y | ||||
|     confl = foldr cappend (Ok []) . map toCon | ||||
|     cappend (Ok x) (Ok o) = Ok (x ++ o) | ||||
|     cappend (Ok x) (Conflict m o y) = error "align consistency check fail" -- Conflict (x++m) (x++o) (x++y) | ||||
|     cappend (Conflict m o y) (Ok x) = Conflict (m ++ x) (o ++ x) (y ++ x) | ||||
|     cappend (Conflict m o y) (Conflict m' o' y') = | ||||
|       Conflict (m ++ m') (o ++ o') (y ++ y') | ||||
| 
 | ||||
| regroup :: [Merged] -> [Merged] | ||||
| regroup [] = [] | ||||
|  | @ -169,55 +227,8 @@ regroup (x@(Ok a):xs) = | |||
|   case regroup xs of | ||||
|     (Ok b:xs') -> Ok (a ++ b) : xs' | ||||
|     xs' -> x : xs' | ||||
| regroup (Conflict [] [] []:xs) = regroup xs | ||||
| regroup (x@(Conflict m1 o1 y1):xs) = | ||||
|   case regroup xs of | ||||
|     (Conflict m2 o2 y2:xs') -> Conflict (m1 ++ m2) (o1 ++ o2) (y1 ++ y2) : xs' | ||||
|     xs' -> x : xs' | ||||
| regroup (x:xs) = x : regroup xs | ||||
| 
 | ||||
| respace :: Config -> [Tok] -> [Tok] -> [Tok] -> [Merged] -> [Merged] | ||||
| respace Config {..} m o y cs = go m o y cs | ||||
|   where | ||||
|     decide m o y = | ||||
|       case cfgSpaces of | ||||
|         SpacesConflict -> Conflict m o y | ||||
|         SpacesMy -> Ok m | ||||
|         SpacesOld -> Ok o | ||||
|         SpacesYour -> Ok y | ||||
|     go m o y [] | ||||
|       | all (all Toks.space) [m, o, y] = [decide m o y] | ||||
|       | otherwise = error "respace trailed" | ||||
|     go m o y (Ok a:cs) = | ||||
|       let [(sm, rm), (so, ro), (sy, ry)] = map (re True a) [m, o, y] | ||||
|        in decide sm so sy : go rm ro ry cs | ||||
|     go m o y (Conflict m' o' y':cs) = | ||||
|       let [(sm, rm), (so, ro), (sy, ry)] = | ||||
|             zipWith (re False) [m', o', y'] [m, o, y] | ||||
|        in Conflict sm so sy : go rm ro ry cs | ||||
|     re False [] sp = ([], sp) | ||||
|     re True [] sp = break (not . Toks.space) sp | ||||
|     re greedy (t:ts) sp = | ||||
|       let (sp0, sp') = break (not . Toks.space) sp | ||||
|        in case sp' of | ||||
|             (s:ss) | ||||
|               | s == t -> | ||||
|                 let (sp1, rest) = re greedy ts ss | ||||
|                  in (sp0 ++ s : sp1, rest) | ||||
|             [] -> error "respace misaligned" | ||||
| 
 | ||||
| expand :: Int -> [Merged] -> [Merged] | ||||
| expand n = go | ||||
|   where | ||||
|     go [] = [] | ||||
|     go (x@(Conflict m1 o1 y1):xs) = | ||||
|       case go xs of | ||||
|         (Ok a:Conflict m2 o2 y2:xs') | ||||
|           | length a <= n -> | ||||
|             Conflict (m1 ++ a ++ m2) (o1 ++ a ++ o2) (y1 ++ a ++ y2) : xs' | ||||
|         xs' -> x : xs' | ||||
|     go (x:xs) = x : go xs | ||||
| 
 | ||||
| zeal Config {..} (Conflict m o y) = | ||||
|   before' ++ (Conflict (reverse m'') o (reverse y'') : after') | ||||
|   where | ||||
|  | @ -242,8 +253,34 @@ zeal Config {..} (Conflict m o y) = | |||
|     pops ms ys = ((ms, ys), []) | ||||
| zeal _ x = [x] | ||||
| 
 | ||||
| resolveSpace Config {..} c@(Conflict m o y) | ||||
|   | not (all Toks.space $ concat [m, o, y]) | ||||
|       || cfgSpaces `elem` [SpacesNormal, SpacesConflict] = c | ||||
|   | m == o && o == y = Ok o | ||||
|   | otherwise = | ||||
|     case cfgSpaces of | ||||
|       SpacesMy -> Ok m | ||||
|       SpacesOld -> Ok o | ||||
|       SpacesYour -> Ok y | ||||
|       _ -> error $ "spaces resolution error " ++ show cfgSpaces | ||||
| resolveSpace _ x = x | ||||
| 
 | ||||
| expand :: Int -> [Merged] -> [Merged] | ||||
| expand n = go | ||||
|   where | ||||
|     go [] = [] | ||||
|     go (x@(Conflict m1 o1 y1):xs) = | ||||
|       case go xs of | ||||
|         (Conflict m2 o2 y2:xs') -> | ||||
|           Conflict (m1 ++ m2) (o1 ++ o2) (y1 ++ y2) : xs' | ||||
|         (Ok a:Conflict m2 o2 y2:xs') | ||||
|           | length a <= n -> | ||||
|             Conflict (m1 ++ a ++ m2) (o1 ++ a ++ o2) (y1 ++ a ++ y2) : xs' | ||||
|         xs' -> x : xs' | ||||
|     go (x:xs) = x : go xs | ||||
| 
 | ||||
| resolve cfg@Config {..} c@(Conflict m o y) | ||||
|   | all Toks.space (concat [m, o, y]) && cfgSpaces /= SpacesNormal = | ||||
|   | cfgSpaces /= SpacesNormal && all Toks.space (concat [m, o, y]) = | ||||
|     resolveSpace cfg c | ||||
|   | m == o && o == y = Ok o | ||||
|   | m == o && cfgResolveSeparate = Ok y | ||||
|  | @ -251,39 +288,15 @@ resolve cfg@Config {..} c@(Conflict m o y) | |||
|   | m == y && cfgResolveOverlaps = Ok m | ||||
| resolve _ x = x | ||||
| 
 | ||||
| -- TODO: there might be a bit of interplay between the spaces handling and | ||||
| -- separate/overlapped conflict resolution -- e.g., what if someone wants to | ||||
| -- merge overlapping edits in text but separate edits in spaces? At this point | ||||
| -- that might be ignorable. | ||||
| -- | ||||
| -- Also, conflicts that are made out of an ignorable space change and a | ||||
| -- mergeable non-space change now cause conflicts because the spaces are no | ||||
| -- longer truly separable/alignable here. Ideally some part of the space | ||||
| -- merging should be done at alignment (e.g., fake all spaces to cause them to | ||||
| -- align well). Also it might be necessary to group space-tokens together | ||||
| -- (newline and indent are now 2 space tokens, which won't ever merge with a | ||||
| -- single space) | ||||
| resolveSpace Config {..} c@(Conflict m o y) | ||||
|   | m == o && o == y = Ok o | ||||
|   | otherwise = | ||||
|     case cfgSpaces of | ||||
|       SpacesConflict -> c | ||||
|       SpacesMy -> Ok m | ||||
|       SpacesOld -> Ok o | ||||
|       SpacesYour -> Ok y | ||||
|       _ -> error "spaces resolution failed" | ||||
| 
 | ||||
| resolveSpaces _ x = x | ||||
| 
 | ||||
| -- TODO mix in the despace & respace | ||||
| merge cfg@Config {..} ms ys = | ||||
|   regroup | ||||
|     . map (resolve cfg) | ||||
|     . regroup | ||||
|     . bool id (concatMap $ zeal cfg) cfgZealous | ||||
|     . expand cfgContext | ||||
|     . regroup | ||||
|     $ align ms ys | ||||
|     . map (resolveSpace cfg) | ||||
|     . bool id (concatMap $ zeal cfg) cfgZealous | ||||
|     . regroup | ||||
|     $ align (chunks ms) (chunks ys) | ||||
| 
 | ||||
| {- | ||||
|  - front-end | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Mirek Kratochvil
						Mirek Kratochvil