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] |         xs -> [Ok $ reverse xs] | ||||||
|     pops (m:ms) (y:ys) |     pops (m:ms) (y:ys) | ||||||
|       | m == y = (m :) <$> pops ms ys |       | m == y = (m :) <$> pops ms ys | ||||||
|       | SpacesMy <- cfgSpaces |       | cfgSpaceRetain == ResolveMy | ||||||
|       , Toks.space m |       , Toks.space m | ||||||
|       , Toks.space y = (m :) <$> pops ms ys |       , Toks.space y = (m :) <$> pops ms ys | ||||||
|       | SpacesYour <- cfgSpaces |       | cfgSpaceRetain == ResolveYour | ||||||
|       , Toks.space m |       , Toks.space m | ||||||
|       , Toks.space y = (y :) <$> pops ms ys |       , Toks.space y = (y :) <$> pops ms ys | ||||||
|     pops ms ys = ((ms, ys), []) |     pops ms ys = ((ms, ys), []) | ||||||
| zeal _ x = [x] | zeal _ x = [x] | ||||||
| 
 | 
 | ||||||
| resolveSpace Config {..} c@(Conflict m o y) | resolveSpace Config {..} c@(Conflict m o y) | ||||||
|   | not (all Toks.space $ concat [m, o, y]) |   | not (all Toks.space $ concat [m, o, y]) = c | ||||||
|       || cfgSpaces `elem` [SpacesNormal, SpacesConflict] = c |  | ||||||
|   | m == o && o == y = Ok o |   | m == o && o == y = Ok o | ||||||
|   | otherwise = |   | cfgSpaceRetain == ResolveMy = Ok m | ||||||
|     case cfgSpaces of |   | cfgSpaceRetain == ResolveOld = Ok o | ||||||
|       SpacesMy -> Ok m |   | cfgSpaceRetain == ResolveYour = Ok y | ||||||
|       SpacesOld -> Ok o |   | cfgSpaceResolution == SpaceNormal = c | ||||||
|       SpacesYour -> Ok y |   | cmResolveSeparate cfgSpaceConflicts && m == o = Ok y | ||||||
|       _ -> error $ "spaces resolution error " ++ show cfgSpaces |   | 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 | resolveSpace _ x = x | ||||||
| 
 | 
 | ||||||
| expand :: Int -> [Merged] -> [Merged] | expand :: Int -> [Merged] -> [Merged] | ||||||
|  | @ -280,12 +286,18 @@ expand n = go | ||||||
|     go (x:xs) = x : go xs |     go (x:xs) = x : go xs | ||||||
| 
 | 
 | ||||||
| resolve cfg@Config {..} c@(Conflict m o y) | resolve cfg@Config {..} c@(Conflict m o y) | ||||||
|   | cfgSpaces /= SpacesNormal && all Toks.space (concat [m, o, y]) = |   | cfgSpaceResolution /= SpaceNormal | ||||||
|     resolveSpace cfg c |   , all Toks.space (concat [m, o, y]) = resolveSpace cfg c | ||||||
|   | m == o && o == y = Ok o |   | m == o && o == y = Ok o | ||||||
|   | m == o && cfgResolveSeparate = Ok y |   | cmResolveSeparate cfgConflicts && m == o = Ok y | ||||||
|   | o == y && cfgResolveSeparate = Ok m |   | cmResolveSeparate cfgConflicts && o == y = Ok m | ||||||
|   | m == y && cfgResolveOverlaps = 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 | resolve _ x = x | ||||||
| 
 | 
 | ||||||
| merge cfg@Config {..} ms ys = | merge cfg@Config {..} ms ys = | ||||||
|  |  | ||||||
							
								
								
									
										170
									
								
								Opts.hs
									
									
									
									
									
								
							
							
						
						
									
										170
									
								
								Opts.hs
									
									
									
									
									
								
							|  | @ -23,66 +23,127 @@ tokenizer = | ||||||
|               (long "tok-filter" |               (long "tok-filter" | ||||||
|                  <> short 'F' |                  <> short 'F' | ||||||
|                  <> metavar "FILTER" |                  <> metavar "FILTER" | ||||||
|                  <> help "external program to separate the text to tokens") |                  <> help "External program to separate the text to tokens") | ||||||
|     , flag' |     , flag' | ||||||
|         TokenizeCharCategorySimple |         TokenizeCharCategorySimple | ||||||
|         (long "simple-tokens" |         (long "simple-tokens" | ||||||
|            <> short 'i' |            <> short 'i' | ||||||
|            <> help |            <> 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' |     , flag' | ||||||
|         TokenizeCharCategory |         TokenizeCharCategory | ||||||
|         (long "full-tokens" |         (long "full-tokens" | ||||||
|            <> short 'I' |            <> short 'I' | ||||||
|            <> help |            <> help | ||||||
|                 "separate characters by all known character classes (default)") |                 "Separate characters by all known character classes (default)") | ||||||
|     , pure TokenizeCharCategory |     , pure TokenizeCharCategory | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
| data Spaces | data ConflictMask = ConflictMask | ||||||
|   = SpacesNormal |   { cmResolveOverlaps :: Bool | ||||||
|   | SpacesConflict |   , cmResolveSeparate :: Bool | ||||||
|   | SpacesMy |   } deriving (Show) | ||||||
|   | SpacesOld | 
 | ||||||
|   | SpacesYour | 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) |   deriving (Show, Eq) | ||||||
| 
 | 
 | ||||||
| spaceMode x | spaceMode x | ||||||
|   | x `isPrefixOf` "normal" = Right SpacesNormal |   | x `isPrefixOf` "normal" = Right SpaceNormal | ||||||
|   | x `isPrefixOf` "conflict" = Right SpacesConflict |   | Right y <- resolutionMode x = Right (SpaceSpecial y) | ||||||
|   | x `isPrefixOf` "my" = Right SpacesMy |  | ||||||
|   | x `isPrefixOf` "old" = Right SpacesOld |  | ||||||
|   | x `isPrefixOf` "your" = Right SpacesYour |  | ||||||
|   | otherwise = |   | otherwise = | ||||||
|     Left |     Left | ||||||
|       $ "could not parse value `" |       $ "Could not parse value `" | ||||||
|           ++ x |           ++ x | ||||||
|           ++ "', use one of `normal', `conflict', `my', `old', and `your'" |           ++ "', use one of `normal', `keep', `my', `old', and `your'" | ||||||
| 
 | 
 | ||||||
| data Config = Config | data Config = Config | ||||||
|   { cfgTokenizer :: Tokenizer |   { cfgTokenizer :: Tokenizer | ||||||
|   , cfgSpaces :: Spaces |  | ||||||
|   , cfgContext :: Int |  | ||||||
|   , cfgZealous :: Bool |   , cfgZealous :: Bool | ||||||
|  |   , cfgSpaceRetain :: Resolution | ||||||
|  |   , cfgSpaceResolution :: SpaceResolution | ||||||
|  |   , cfgSpaceConflicts :: ConflictMask | ||||||
|  |   , cfgContext :: Int | ||||||
|  |   , cfgResolution :: Resolution | ||||||
|  |   , cfgConflicts :: ConflictMask | ||||||
|   , cfgLabelStart :: String |   , cfgLabelStart :: String | ||||||
|   , cfgLabelMyOld :: String |   , cfgLabelMyOld :: String | ||||||
|   , cfgLabelOldYour :: String |   , cfgLabelOldYour :: String | ||||||
|   , cfgLabelEnd :: String |   , cfgLabelEnd :: String | ||||||
|   , cfgResolveSpaces :: Bool |  | ||||||
|   , cfgResolveOverlaps :: Bool |  | ||||||
|   , cfgResolveSeparate :: Bool |  | ||||||
|   } deriving (Show) |   } deriving (Show) | ||||||
| 
 | 
 | ||||||
| config = do | config = do | ||||||
|   cfgTokenizer <- tokenizer |   cfgTokenizer <- tokenizer | ||||||
|   cfgSpaces <- |   cfgZealous <- | ||||||
|     option (eitherReader spaceMode) |     asum | ||||||
|       $ long "spaces" |       [ flag' False $ long "no-zeal" <> help "avoid zealous mode (default)" | ||||||
|           <> short 's' |       , flag' True | ||||||
|           <> metavar "(normal|conflict|my|old|your)" |           $ long "zeal" | ||||||
|  |               <> short 'z' | ||||||
|               <> help |               <> 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)" |                    "Try to zealously minify conflicts, potentially resolving them" | ||||||
|           <> value SpacesNormal |       , pure False | ||||||
|  |       ] | ||||||
|  |   cfgSpaceRetain <- | ||||||
|  |     option (eitherReader resolutionMode) | ||||||
|  |       $ long "space" | ||||||
|  |           <> short 'S' | ||||||
|  |           <> metavar "(keep|my|old|your)" | ||||||
|  |           <> help | ||||||
|  |                "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 <- |   cfgContext <- | ||||||
|     option auto |     option auto | ||||||
|       $ long "expand-context" |       $ long "expand-context" | ||||||
|  | @ -91,50 +152,41 @@ config = do | ||||||
|           <> value 1 |           <> value 1 | ||||||
|           <> showDefault |           <> showDefault | ||||||
|           <> help |           <> help | ||||||
|                "Consider changes that are at most N tokens apart to be a single change. Zero may cause bad resolutions of near conflicting edits." |                "Consider changes that are at most N tokens apart to be a single change. Zero may cause bad resolutions of near conflicting edits" | ||||||
|   cfgZealous <- |   cfgResolution <- | ||||||
|     asum |     option (eitherReader resolutionMode) | ||||||
|       [ flag' False $ long "no-zeal" <> help "avoid zealous mode (default)" |       $ long "resolve" | ||||||
|       , flag' True |           <> metavar "(keep|my|old|your)" | ||||||
|           $ long "zeal" |           <> value ResolveKeep | ||||||
|               <> short 'z' |  | ||||||
|           <> help |           <> help | ||||||
|                    "try to zealously minify conflicts, potentially resolving them" |                "Resolve general conflicts in favor of a given version, or keep the conflicts (default: keep)" | ||||||
|       , pure False |   cfgConflicts <- conflictMask "conflict" "general tokens" | ||||||
|       ] |  | ||||||
|   color <- |   color <- | ||||||
|     flag False True |     flag False True | ||||||
|       $ long "color" |       $ long "color" | ||||||
|           <> short 'G' |           <> short 'G' | ||||||
|           <> help |           <> 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 <- |   labelStart <- | ||||||
|     optional . strOption |     optional . strOption | ||||||
|       $ long "label-start" |       $ long "label-start" | ||||||
|           <> metavar "\"<<<<<\"" |           <> metavar "\"<<<<<\"" | ||||||
|           <> help "label for beginning of the conflict" |           <> help "Label for beginning of the conflict" | ||||||
|   labelMyOld <- |   labelMyOld <- | ||||||
|     optional . strOption |     optional . strOption | ||||||
|       $ long "label-mo" |       $ long "label-mo" | ||||||
|           <> metavar "\"|||||\"" |           <> metavar "\"|||||\"" | ||||||
|           <> help "separator of local edits and original" |           <> help "Separator of local edits and original" | ||||||
|   labelOldYour <- |   labelOldYour <- | ||||||
|     optional . strOption |     optional . strOption | ||||||
|       $ long "label-oy" |       $ long "label-oy" | ||||||
|           <> metavar "\"=====\"" |           <> metavar "\"=====\"" | ||||||
|           <> help "separator of original and other people's edits" |           <> help "Separator of original and other people's edits" | ||||||
|   labelEnd <- |   labelEnd <- | ||||||
|     optional . strOption |     optional . strOption | ||||||
|       $ long "label-end" |       $ long "label-end" | ||||||
|           <> metavar "\">>>>>\"" |           <> metavar "\">>>>>\"" | ||||||
|           <> help "label for end of the conflict" |           <> 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" |  | ||||||
|   pure |   pure | ||||||
|     Config |     Config | ||||||
|       { cfgLabelStart = |       { cfgLabelStart = | ||||||
|  | @ -161,10 +213,10 @@ data Command | ||||||
|   deriving (Show) |   deriving (Show) | ||||||
| 
 | 
 | ||||||
| cmdDiff3 = do | cmdDiff3 = do | ||||||
|   d3my <- strArgument $ metavar "MYFILE" <> help "version with local edits" |   d3my <- strArgument $ metavar "MYFILE" <> help "Version with local edits" | ||||||
|   d3old <- strArgument $ metavar "OLDFILE" <> help "original file version" |   d3old <- strArgument $ metavar "OLDFILE" <> help "Original file version" | ||||||
|   d3your <- |   d3your <- | ||||||
|     strArgument $ metavar "YOURFILE" <> help "version with other people's edits" |     strArgument $ metavar "YOURFILE" <> help "Version with other people's edits" | ||||||
|   pure CmdDiff3 {..} |   pure CmdDiff3 {..} | ||||||
| 
 | 
 | ||||||
| cmdGitMerge = do | cmdGitMerge = do | ||||||
|  | @ -173,12 +225,12 @@ cmdGitMerge = do | ||||||
|       [ fmap Just . some |       [ fmap Just . some | ||||||
|           $ strArgument |           $ strArgument | ||||||
|           $ metavar "UNMERGED" |           $ metavar "UNMERGED" | ||||||
|               <> help "unmerged git file (can be specified repeatedly)" |               <> help "Unmerged git file (can be specified repeatedly)" | ||||||
|       , flag' |       , flag' | ||||||
|           Nothing |           Nothing | ||||||
|           (long "unmerged" |           (long "unmerged" | ||||||
|              <> short 'u' |              <> short 'u' | ||||||
|              <> help "process all files marked as unmerged by git") |              <> help "Process all files marked as unmerged by git") | ||||||
|       ] |       ] | ||||||
|   gmDoAdd <- |   gmDoAdd <- | ||||||
|     asum |     asum | ||||||
|  | @ -186,8 +238,8 @@ cmdGitMerge = do | ||||||
|           True |           True | ||||||
|           (long "add" |           (long "add" | ||||||
|              <> short 'a' |              <> short 'a' | ||||||
|              <> help "run `git add' for fully merged files") |              <> help "Run `git add' for fully merged files") | ||||||
|       , flag' False (long "no-add" <> help "prevent running `git add'") |       , flag' False (long "no-add" <> help "Prevent running `git add'") | ||||||
|       , pure False |       , pure False | ||||||
|       ] |       ] | ||||||
|   pure CmdGitMerge {..} |   pure CmdGitMerge {..} | ||||||
|  | @ -202,7 +254,7 @@ cmd = | ||||||
|             $ progDesc "diff3-style merge of two changesets" |             $ progDesc "diff3-style merge of two changesets" | ||||||
|         , command "git" |         , command "git" | ||||||
|             $ info cmdGitMerge |             $ info cmdGitMerge | ||||||
|             $ progDesc "automerge unmerged files in git conflict" |             $ progDesc "Automerge unmerged files in git conflict" | ||||||
|         ] |         ] | ||||||
| 
 | 
 | ||||||
| parseOpts :: IO (Config, Command) | parseOpts :: IO (Config, Command) | ||||||
|  | @ -215,4 +267,4 @@ parseOpts = | ||||||
|         (fullDesc |         (fullDesc | ||||||
|            <> header |            <> header | ||||||
|                 "werge -- blanks-friendly mergetool for tiny interdwindled changes" |                 "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