make spaces work properly, clean up everything
This commit is contained in:
		
							parent
							
								
									960f316059
								
							
						
					
					
						commit
						44bd3e8c14
					
				
							
								
								
									
										42
									
								
								Main.hs
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								Main.hs
									
									
									
									
									
								
							|  | @ -244,25 +244,31 @@ zeal Config {..} (Conflict m o y) = | |||
|         xs -> [Ok $ reverse xs] | ||||
|     pops (m:ms) (y:ys) | ||||
|       | m == y = (m :) <$> pops ms ys | ||||
|       | SpacesMy <- cfgSpaces | ||||
|       | cfgSpaceRetain == ResolveMy | ||||
|       , Toks.space m | ||||
|       , Toks.space y = (m :) <$> pops ms ys | ||||
|       | SpacesYour <- cfgSpaces | ||||
|       | cfgSpaceRetain == ResolveYour | ||||
|       , Toks.space m | ||||
|       , Toks.space y = (y :) <$> pops ms ys | ||||
|     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 | ||||
|   | not (all Toks.space $ concat [m, o, y]) = 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 | ||||
|   | cfgSpaceRetain == ResolveMy = Ok m | ||||
|   | cfgSpaceRetain == ResolveOld = Ok o | ||||
|   | cfgSpaceRetain == ResolveYour = Ok y | ||||
|   | cfgSpaceResolution == SpaceNormal = c | ||||
|   | cmResolveSeparate cfgSpaceConflicts && m == o = Ok y | ||||
|   | cmResolveSeparate cfgSpaceConflicts && o == y = Ok m | ||||
|   | cmResolveOverlaps cfgSpaceConflicts && m == y = Ok m | ||||
|   | SpaceSpecial r <- cfgSpaceResolution = | ||||
|     case r of | ||||
|       ResolveMy -> Ok m | ||||
|       ResolveOld -> Ok o | ||||
|       ResolveYour -> Ok y | ||||
|       ResolveKeep -> c | ||||
| resolveSpace _ x = x | ||||
| 
 | ||||
| expand :: Int -> [Merged] -> [Merged] | ||||
|  | @ -280,12 +286,18 @@ expand n = go | |||
|     go (x:xs) = x : go xs | ||||
| 
 | ||||
| resolve cfg@Config {..} c@(Conflict m o y) | ||||
|   | cfgSpaces /= SpacesNormal && all Toks.space (concat [m, o, y]) = | ||||
|     resolveSpace cfg c | ||||
|   | cfgSpaceResolution /= SpaceNormal | ||||
|   , all Toks.space (concat [m, o, y]) = resolveSpace cfg c | ||||
|   | m == o && o == y = Ok o | ||||
|   | m == o && cfgResolveSeparate = Ok y | ||||
|   | o == y && cfgResolveSeparate = Ok m | ||||
|   | m == y && cfgResolveOverlaps = Ok m | ||||
|   | cmResolveSeparate cfgConflicts && m == o = Ok y | ||||
|   | cmResolveSeparate cfgConflicts && o == y = Ok m | ||||
|   | cmResolveOverlaps cfgConflicts && m == y = Ok m | ||||
|   | otherwise = | ||||
|     case cfgResolution of | ||||
|       ResolveMy -> Ok m | ||||
|       ResolveOld -> Ok o | ||||
|       ResolveYour -> Ok y | ||||
|       ResolveKeep -> c | ||||
| resolve _ x = x | ||||
| 
 | ||||
| merge cfg@Config {..} ms ys = | ||||
|  |  | |||
							
								
								
									
										172
									
								
								Opts.hs
									
									
									
									
									
								
							
							
						
						
									
										172
									
								
								Opts.hs
									
									
									
									
									
								
							|  | @ -23,66 +23,127 @@ tokenizer = | |||
|               (long "tok-filter" | ||||
|                  <> short 'F' | ||||
|                  <> metavar "FILTER" | ||||
|                  <> help "external program to separate the text to tokens") | ||||
|                  <> help "External program to separate the text to tokens") | ||||
|     , flag' | ||||
|         TokenizeCharCategorySimple | ||||
|         (long "simple-tokens" | ||||
|            <> short 'i' | ||||
|            <> help | ||||
|                 "use wider character class to separate the tokens (results in larger tokens and ignores case)") | ||||
|                 "Use wider character class to separate the tokens (results in larger tokens and ignores case)") | ||||
|     , flag' | ||||
|         TokenizeCharCategory | ||||
|         (long "full-tokens" | ||||
|            <> short 'I' | ||||
|            <> help | ||||
|                 "separate characters by all known character classes (default)") | ||||
|                 "Separate characters by all known character classes (default)") | ||||
|     , pure TokenizeCharCategory | ||||
|     ] | ||||
| 
 | ||||
| data Spaces | ||||
|   = SpacesNormal | ||||
|   | SpacesConflict | ||||
|   | SpacesMy | ||||
|   | SpacesOld | ||||
|   | SpacesYour | ||||
| data ConflictMask = ConflictMask | ||||
|   { cmResolveOverlaps :: Bool | ||||
|   , cmResolveSeparate :: Bool | ||||
|   } deriving (Show) | ||||
| 
 | ||||
| conflictMask label objs = do | ||||
|   cmResolveOverlaps' <- | ||||
|     fmap not . switch | ||||
|       $ long (label ++ "-overlaps") | ||||
|           <> help ("Never resolve overlapping changes in " ++ objs) | ||||
|   cmResolveSeparate' <- | ||||
|     fmap not . switch | ||||
|       $ long (label ++ "-separate") | ||||
|           <> help | ||||
|                ("Never resolve separate (non-overlapping) changes in " ++ objs) | ||||
|   cmAll <- | ||||
|     fmap not . switch | ||||
|       $ long (label ++ "-all") <> help ("Never resolve any changes in " ++ objs) | ||||
|   pure | ||||
|     ConflictMask | ||||
|       { cmResolveSeparate = cmResolveSeparate' && cmAll | ||||
|       , cmResolveOverlaps = cmResolveOverlaps' && cmAll | ||||
|       } | ||||
| 
 | ||||
| data Resolution | ||||
|   = ResolveKeep | ||||
|   | ResolveMy | ||||
|   | ResolveOld | ||||
|   | ResolveYour | ||||
|   deriving (Show, Eq) | ||||
| 
 | ||||
| resolutionMode x | ||||
|   | x `isPrefixOf` "keep" = Right ResolveKeep | ||||
|   | x `isPrefixOf` "my" = Right ResolveMy | ||||
|   | x `isPrefixOf` "old" = Right ResolveOld | ||||
|   | x `isPrefixOf` "your" = Right ResolveYour | ||||
|   | otherwise = | ||||
|     Left | ||||
|       $ "Could not parse value `" | ||||
|           ++ x | ||||
|           ++ "', use one of `keep', `my', `old', and `your'" | ||||
| 
 | ||||
| data SpaceResolution | ||||
|   = SpaceNormal | ||||
|   | SpaceSpecial Resolution | ||||
|   deriving (Show, Eq) | ||||
| 
 | ||||
| spaceMode x | ||||
|   | x `isPrefixOf` "normal" = Right SpacesNormal | ||||
|   | x `isPrefixOf` "conflict" = Right SpacesConflict | ||||
|   | x `isPrefixOf` "my" = Right SpacesMy | ||||
|   | x `isPrefixOf` "old" = Right SpacesOld | ||||
|   | x `isPrefixOf` "your" = Right SpacesYour | ||||
|   | x `isPrefixOf` "normal" = Right SpaceNormal | ||||
|   | Right y <- resolutionMode x = Right (SpaceSpecial y) | ||||
|   | otherwise = | ||||
|     Left | ||||
|       $ "could not parse value `" | ||||
|       $ "Could not parse value `" | ||||
|           ++ x | ||||
|           ++ "', use one of `normal', `conflict', `my', `old', and `your'" | ||||
|           ++ "', use one of `normal', `keep', `my', `old', and `your'" | ||||
| 
 | ||||
| data Config = Config | ||||
|   { cfgTokenizer :: Tokenizer | ||||
|   , cfgSpaces :: Spaces | ||||
|   , cfgContext :: Int | ||||
|   , cfgZealous :: Bool | ||||
|   , cfgSpaceRetain :: Resolution | ||||
|   , cfgSpaceResolution :: SpaceResolution | ||||
|   , cfgSpaceConflicts :: ConflictMask | ||||
|   , cfgContext :: Int | ||||
|   , cfgResolution :: Resolution | ||||
|   , cfgConflicts :: ConflictMask | ||||
|   , cfgLabelStart :: String | ||||
|   , cfgLabelMyOld :: String | ||||
|   , cfgLabelOldYour :: String | ||||
|   , cfgLabelEnd :: String | ||||
|   , cfgResolveSpaces :: Bool | ||||
|   , cfgResolveOverlaps :: Bool | ||||
|   , cfgResolveSeparate :: Bool | ||||
|   } deriving (Show) | ||||
| 
 | ||||
| config = do | ||||
|   cfgTokenizer <- tokenizer | ||||
|   cfgSpaces <- | ||||
|     option (eitherReader spaceMode) | ||||
|       $ long "spaces" | ||||
|           <> short 's' | ||||
|           <> metavar "(normal|conflict|my|old|your)" | ||||
|   cfgZealous <- | ||||
|     asum | ||||
|       [ flag' False $ long "no-zeal" <> help "avoid zealous mode (default)" | ||||
|       , flag' True | ||||
|           $ long "zeal" | ||||
|               <> short 'z' | ||||
|               <> help | ||||
|                    "Try to zealously minify conflicts, potentially resolving them" | ||||
|       , pure False | ||||
|       ] | ||||
|   cfgSpaceRetain <- | ||||
|     option (eitherReader resolutionMode) | ||||
|       $ long "space" | ||||
|           <> short 'S' | ||||
|           <> metavar "(keep|my|old|your)" | ||||
|           <> help | ||||
|                "mode of merging the space-only changes; instead of usual resolution one may choose to always conflict or to default the space from the source files (default: normal)" | ||||
|           <> value SpacesNormal | ||||
|                "Retain spacing from a selected version, or keep all space changes for merging (default: keep)" | ||||
|           <> value ResolveKeep | ||||
|   cfgSpaceResolution <- | ||||
|     asum | ||||
|       [ flag' (SpaceSpecial ResolveKeep) | ||||
|           $ short 's' | ||||
|               <> help | ||||
|                    "Shortcut for `--resolve-space keep' (this separates space-only conflicts, enabling better automated resolution)" | ||||
|       , option (eitherReader spaceMode) | ||||
|           $ long "resolve-space" | ||||
|               <> metavar ("(normal|keep|my|old|your)") | ||||
|               <> value SpaceNormal | ||||
|               <> help | ||||
|                    "Resolve conflicts in space-only tokens separately, and either keep unresolved conflicts, or resolve in favor of a given version; `normal' resolves the spaces together with other tokens, ignoring choices in --resolve-space-* (default: normal)" | ||||
|       ] | ||||
|   cfgSpaceConflicts <- conflictMask "conflict-space" "space-only tokens" | ||||
|   cfgContext <- | ||||
|     option auto | ||||
|       $ long "expand-context" | ||||
|  | @ -91,50 +152,41 @@ config = do | |||
|           <> value 1 | ||||
|           <> showDefault | ||||
|           <> help | ||||
|                "Consider changes that are at most N tokens apart to be a single change. Zero may cause bad resolutions of near conflicting edits." | ||||
|   cfgZealous <- | ||||
|     asum | ||||
|       [ flag' False $ long "no-zeal" <> help "avoid zealous mode (default)" | ||||
|       , flag' True | ||||
|           $ long "zeal" | ||||
|               <> short 'z' | ||||
|               <> help | ||||
|                    "try to zealously minify conflicts, potentially resolving them" | ||||
|       , pure False | ||||
|       ] | ||||
|                "Consider changes that are at most N tokens apart to be a single change. Zero may cause bad resolutions of near conflicting edits" | ||||
|   cfgResolution <- | ||||
|     option (eitherReader resolutionMode) | ||||
|       $ long "resolve" | ||||
|           <> metavar "(keep|my|old|your)" | ||||
|           <> value ResolveKeep | ||||
|           <> help | ||||
|                "Resolve general conflicts in favor of a given version, or keep the conflicts (default: keep)" | ||||
|   cfgConflicts <- conflictMask "conflict" "general tokens" | ||||
|   color <- | ||||
|     flag False True | ||||
|       $ long "color" | ||||
|           <> short 'G' | ||||
|           <> help | ||||
|                "use shorter, gaily colored output markers by default (requires ANSI color support; good for terminals or `less -R')" | ||||
|                "Use shorter, gaily colored output markers by default (requires ANSI color support; good for terminals or `less -R')" | ||||
|   labelStart <- | ||||
|     optional . strOption | ||||
|       $ long "label-start" | ||||
|           <> metavar "\"<<<<<\"" | ||||
|           <> help "label for beginning of the conflict" | ||||
|           <> help "Label for beginning of the conflict" | ||||
|   labelMyOld <- | ||||
|     optional . strOption | ||||
|       $ long "label-mo" | ||||
|           <> metavar "\"|||||\"" | ||||
|           <> help "separator of local edits and original" | ||||
|           <> help "Separator of local edits and original" | ||||
|   labelOldYour <- | ||||
|     optional . strOption | ||||
|       $ long "label-oy" | ||||
|           <> metavar "\"=====\"" | ||||
|           <> help "separator of original and other people's edits" | ||||
|           <> help "Separator of original and other people's edits" | ||||
|   labelEnd <- | ||||
|     optional . strOption | ||||
|       $ long "label-end" | ||||
|           <> metavar "\">>>>>\"" | ||||
|           <> help "label for end of the conflict" | ||||
|   cfgResolveOverlaps <- | ||||
|     fmap not . switch | ||||
|       $ long "conflict-overlaps" <> help "do not resolve overlapping changes" | ||||
|   cfgResolveSeparate <- | ||||
|     fmap not . switch | ||||
|       $ long "conflict-separate" | ||||
|           <> help "do not resolve separate (non-overlapping) changes" | ||||
|           <> help "Label for end of the conflict" | ||||
|   pure | ||||
|     Config | ||||
|       { cfgLabelStart = | ||||
|  | @ -161,10 +213,10 @@ data Command | |||
|   deriving (Show) | ||||
| 
 | ||||
| cmdDiff3 = do | ||||
|   d3my <- strArgument $ metavar "MYFILE" <> help "version with local edits" | ||||
|   d3old <- strArgument $ metavar "OLDFILE" <> help "original file version" | ||||
|   d3my <- strArgument $ metavar "MYFILE" <> help "Version with local edits" | ||||
|   d3old <- strArgument $ metavar "OLDFILE" <> help "Original file version" | ||||
|   d3your <- | ||||
|     strArgument $ metavar "YOURFILE" <> help "version with other people's edits" | ||||
|     strArgument $ metavar "YOURFILE" <> help "Version with other people's edits" | ||||
|   pure CmdDiff3 {..} | ||||
| 
 | ||||
| cmdGitMerge = do | ||||
|  | @ -173,12 +225,12 @@ cmdGitMerge = do | |||
|       [ fmap Just . some | ||||
|           $ strArgument | ||||
|           $ metavar "UNMERGED" | ||||
|               <> help "unmerged git file (can be specified repeatedly)" | ||||
|               <> help "Unmerged git file (can be specified repeatedly)" | ||||
|       , flag' | ||||
|           Nothing | ||||
|           (long "unmerged" | ||||
|              <> short 'u' | ||||
|              <> help "process all files marked as unmerged by git") | ||||
|              <> help "Process all files marked as unmerged by git") | ||||
|       ] | ||||
|   gmDoAdd <- | ||||
|     asum | ||||
|  | @ -186,8 +238,8 @@ cmdGitMerge = do | |||
|           True | ||||
|           (long "add" | ||||
|              <> short 'a' | ||||
|              <> help "run `git add' for fully merged files") | ||||
|       , flag' False (long "no-add" <> help "prevent running `git add'") | ||||
|              <> help "Run `git add' for fully merged files") | ||||
|       , flag' False (long "no-add" <> help "Prevent running `git add'") | ||||
|       , pure False | ||||
|       ] | ||||
|   pure CmdGitMerge {..} | ||||
|  | @ -202,7 +254,7 @@ cmd = | |||
|             $ progDesc "diff3-style merge of two changesets" | ||||
|         , command "git" | ||||
|             $ info cmdGitMerge | ||||
|             $ progDesc "automerge unmerged files in git conflict" | ||||
|             $ progDesc "Automerge unmerged files in git conflict" | ||||
|         ] | ||||
| 
 | ||||
| parseOpts :: IO (Config, Command) | ||||
|  | @ -215,4 +267,4 @@ parseOpts = | |||
|         (fullDesc | ||||
|            <> header | ||||
|                 "werge -- blanks-friendly mergetool for tiny interdwindled changes" | ||||
|            <> (footer $ "werge is a free software, use it accordingly.")) | ||||
|            <> footer "werge is a free software, use it accordingly.") | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Mirek Kratochvil
						Mirek Kratochvil