module GitHUD.Config.Parse ( parseConfigFile , commentParser , itemParser , fallThroughItemParser , configItemsFolder , ConfigItem(..) , colorConfigToColor , intensityConfigToIntensity , stringConfigToStringList ) where import Control.Monad (void, when) import Text.Parsec (parse) import Text.Parsec.Char (anyChar, char, newline, noneOf, letter, spaces, string) import Text.Parsec.Combinator (choice, eof, many1, manyTill, optional, sepBy) import Text.Parsec.Prim (many, try, unexpected, (<|>), ()) import Text.Parsec.String (parseFromFile, Parser) import GitHUD.Config.Types import GitHUD.Terminal.Types data ConfigItem = Item String String | Comment | ErrorLine deriving (Eq, Show) parseConfigFile :: FilePath -> IO Config parseConfigFile filePath = do eitherParsed <- parseFromFile configFileParser filePath return $ either (const defaultConfig) id eitherParsed configFileParser :: Parser Config configFileParser = do items <- many configItemParser return $ foldl configItemsFolder defaultConfig items configItemParser :: Parser ConfigItem configItemParser = choice [ commentParser , itemParser , fallThroughItemParser ] "config file line" endItem :: Parser () endItem = choice [ void newline , eof ] "end of item" commentParser :: Parser ConfigItem commentParser = try $ do char '#' manyTill anyChar (try endItem) return Comment itemParser :: Parser ConfigItem itemParser = try $ do key <- manyTill validKeyChar (char '=') when (key == "") $ unexpected "A key in the config file should not be empty" value <- manyTill anyChar (try endItem) return $ Item key value validKeyChar :: Parser Char validKeyChar = letter <|> (char '_') -- | Must not be able to process an empty string -- This is mandated by the use of 'many' in configFileParser -- Therefore the definition `manyTill anyChar eof` is invalid, thus using newline fallThroughItemParser :: Parser ConfigItem fallThroughItemParser = do manyTill anyChar (try newline) return ErrorLine configItemsFolder :: Config -> ConfigItem -> Config configItemsFolder conf (Item "show_part_repo_indicator" value) = conf { confShowPartRepoIndicator = boolConfigToIntensity value } configItemsFolder conf (Item "show_part_merge_branch_commits_diff" value) = conf { confShowPartMergeBranchCommitsDiff = boolConfigToIntensity value } configItemsFolder conf (Item "show_part_local_branch" value) = conf { confShowPartLocalBranch = boolConfigToIntensity value } configItemsFolder conf (Item "show_part_commits_to_origin" value) = conf { confShowPartCommitsToOrigin = boolConfigToIntensity value } configItemsFolder conf (Item "show_part_local_changes_state" value) = conf { confShowPartLocalChangesState = boolConfigToIntensity value } configItemsFolder conf (Item "show_part_stashes" value) = conf { confShowPartStashes = boolConfigToIntensity value } configItemsFolder conf (Item "git_repo_indicator" repoIndicator) = conf { confRepoIndicator = repoIndicator } configItemsFolder conf (Item "no_tracked_upstream_text" value) = conf { confNoTrackedUpstreamString = value } configItemsFolder conf (Item "no_tracked_upstream_text_color" value) = conf { confNoTrackedUpstreamStringColor = colorConfigToColor value } configItemsFolder conf (Item "no_tracked_upstream_text_intensity" value) = conf { confNoTrackedUpstreamStringIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "no_tracked_upstream_indicator" value) = conf { confNoTrackedUpstreamIndicator = value } configItemsFolder conf (Item "no_tracked_upstream_indicator_color" value) = conf { confNoTrackedUpstreamIndicatorColor = colorConfigToColor value } configItemsFolder conf (Item "no_tracked_upstream_indicator_intensity" value) = conf { confNoTrackedUpstreamIndicatorIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "merge_branch_commits_indicator" value) = conf { confMergeBranchCommitsIndicator = value } configItemsFolder conf (Item "merge_branch_commits_pull_prefix" value) = conf { confMergeBranchCommitsOnlyPull = value } configItemsFolder conf (Item "merge_branch_commits_push_prefix" value) = conf { confMergeBranchCommitsOnlyPush = value } configItemsFolder conf (Item "merge_branch_commits_push_pull_infix" value) = conf { confMergeBranchCommitsBothPullPush = value } configItemsFolder conf (Item "merge_branch_ignore_branches" value) = conf { confMergeBranchIgnoreBranches = stringConfigToStringList value } configItemsFolder conf (Item "local_branch_prefix" value) = conf { confLocalBranchNamePrefix = value } configItemsFolder conf (Item "local_branch_suffix" value) = conf { confLocalBranchNameSuffix = value } configItemsFolder conf (Item "local_branch_color" value) = conf { confLocalBranchColor = colorConfigToColor value } configItemsFolder conf (Item "local_branch_intensity" value) = conf { confLocalBranchIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "local_detached_prefix" value) = conf { confLocalDetachedPrefix = value } configItemsFolder conf (Item "local_detached_color" value) = conf { confLocalDetachedColor = colorConfigToColor value } configItemsFolder conf (Item "local_detached_intensity" value) = conf { confLocalDetachedIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "local_commits_push_suffix" value) = conf { confLocalCommitsPushSuffix = value } configItemsFolder conf (Item "local_commits_push_suffix_color" value) = conf { confLocalCommitsPushSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "local_commits_push_suffix_intensity" value) = conf { confLocalCommitsPushSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "local_commits_pull_suffix" value) = conf { confLocalCommitsPullSuffix = value } configItemsFolder conf (Item "local_commits_pull_suffix_color" value) = conf { confLocalCommitsPullSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "local_commits_pull_suffix_intensity" value) = conf { confLocalCommitsPullSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "local_commits_push_pull_infix" value) = conf { confLocalCommitsPushPullInfix = value } configItemsFolder conf (Item "local_commits_push_pull_infix_color" value) = conf { confLocalCommitsPushPullInfixColor = colorConfigToColor value } configItemsFolder conf (Item "local_commits_push_pull_infix_intensity" value) = conf { confLocalCommitsPushPullInfixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "change_index_add_suffix" value) = conf { confChangeIndexAddSuffix = value } configItemsFolder conf (Item "change_index_add_suffix_color" value) = conf { confChangeIndexAddSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "change_index_add_suffix_intensity" value) = conf { confChangeIndexAddSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "change_index_mod_suffix" value) = conf { confChangeIndexModSuffix = value } configItemsFolder conf (Item "change_index_mod_suffix_color" value) = conf { confChangeIndexModSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "change_index_mod_suffix_intensity" value) = conf { confChangeIndexModSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "change_index_del_suffix" value) = conf { confChangeIndexDelSuffix = value } configItemsFolder conf (Item "change_index_del_suffix_color" value) = conf { confChangeIndexDelSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "change_index_del_suffix_intensity" value) = conf { confChangeIndexDelSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "change_local_add_suffix" value) = conf { confChangeLocalAddSuffix = value } configItemsFolder conf (Item "change_local_add_suffix_color" value) = conf { confChangeLocalAddSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "change_local_add_suffix_intensity" value) = conf { confChangeLocalAddSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "change_local_mod_suffix" value) = conf { confChangeLocalModSuffix = value } configItemsFolder conf (Item "change_local_mod_suffix_color" value) = conf { confChangeLocalModSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "change_local_mod_suffix_intensity" value) = conf { confChangeLocalModSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "change_local_del_suffix" value) = conf { confChangeLocalDelSuffix = value } configItemsFolder conf (Item "change_local_del_suffix_color" value) = conf { confChangeLocalDelSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "change_local_del_suffix_intensity" value) = conf { confChangeLocalDelSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "change_renamed_suffix" value) = conf { confChangeRenamedSuffix = value } configItemsFolder conf (Item "change_renamed_suffix_color" value) = conf { confChangeRenamedSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "change_renamed_suffix_intensity" value) = conf { confChangeRenamedSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "change_conflicted_suffix" value) = conf { confChangeConflictedSuffix = value } configItemsFolder conf (Item "change_conflicted_suffix_color" value) = conf { confChangeConflictedSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "change_conflicted_suffix_intensity" value) = conf { confChangeConflictedSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf (Item "stash_suffix" value) = conf { confStashSuffix = value } configItemsFolder conf (Item "stash_suffix_color" value) = conf { confStashSuffixColor = colorConfigToColor value } configItemsFolder conf (Item "stash_suffix_intensity" value) = conf { confStashSuffixIntensity = intensityConfigToIntensity value } configItemsFolder conf _ = conf colorConfigToColor :: String -> Color colorConfigToColor str = either (const NoColor) id (parse colorParser "" str) colorParser :: Parser Color colorParser = choice [ string "Black" >> return Black , string "Red" >> return Red , string "Green" >> return Green , string "Yellow" >> return Yellow , string "Blue" >> return Blue , string "Magenta" >> return Magenta , string "Cyan" >> return Cyan , string "White" >> return White , string "NoColor" >> return NoColor ] "color" intensityConfigToIntensity :: String -> ColorIntensity intensityConfigToIntensity str = either (const Vivid) id (parse intensityParser "" str) intensityParser :: Parser ColorIntensity intensityParser = choice [ string "Dull" >> return Dull , string "Vivid" >> return Vivid ] "intensity" boolConfigToIntensity :: String -> Bool boolConfigToIntensity str = either (const True) id (parse boolParser "" str) stringConfigToStringList :: String -> [String] stringConfigToStringList str = either (const []) id (parse stringListParser "" str) stringListParser :: Parser [String] stringListParser = do branchNameList <- sepBy stripedBranchName (char ',') return $ filter noEmptyStringFilter branchNameList noEmptyStringFilter :: String -> Bool noEmptyStringFilter str = not (str == "") stripedBranchName :: Parser String stripedBranchName = do spaces branchName <- many (noneOf [',', ' ']) spaces return branchName boolParser :: Parser Bool boolParser = choice [ string "False" >> return False , string "F" >> return False , string "false" >> return False , string "f" >> return False , string "No" >> return False , string "N" >> return False , string "no" >> return False , string "n" >> return False , string "True" >> return True , string "T" >> return True , string "true" >> return True , string "t" >> return True , string "Yes" >> return True , string "Y" >> return True , string "yes" >> return True , string "y" >> return True ] "bool"