{-# LANGUAGE UnicodeSyntax #-} -- | Module for parsing config files module Todos.ReadConfig (readAllConfigs, readConfigFile) where import Prelude hiding (putStrLn,readFile,getContents,print) import Prelude.Unicode import System.Environment import System.FilePath import System.Directory (doesFileExist, getCurrentDirectory) import Text.ParserCombinators.Parsec import Todos.IO word ∷ Parser String word = choice $ map try [quotedOption, simpleOption, quoted, simpleWord] simpleWord ∷ Parser String simpleWord = many1 $ noneOf " \t\r\n=\"'" quotedOption ∷ Parser String quotedOption = (try quotedLongOption) <|> quotedShortOption quotedLongOption ∷ Parser String quotedLongOption = do string "--" o ← simpleWord char '=' v ← quoted return ("--" ⧺ o ⧺ "=" ⧺ v) quotedShortOption ∷ Parser String quotedShortOption = do string "-" o ← simpleWord v ← quoted return ("-" ⧺ o ⧺ v) simpleOption ∷ Parser String simpleOption = do o ← simpleWord optional $ char '=' v ← simpleWord return (o ⧺ "=" ⧺ v) quoted ∷ Parser String quoted = quoted1 <|> quoted2 where quoted1 = do char '\'' s ← many1 $ noneOf "'" char '\'' return s quoted2 = do char '"' s ← many1 $ noneOf "\"" char '"' return s pConfig ∷ Parser [String] pConfig = word `sepBy` space parseConfig ∷ String → [String] parseConfig str = case parse pConfig "config file" str of Right lst → lst Left err → error $ show err -- | Read list of options from given config file readConfigFile ∷ FilePath → IO [String] readConfigFile path = do b ← doesFileExist path if not b then return [] else do str ← readFile path return $ parseConfig (unwords $ lines str) readFiles ∷ [FilePath] → IO [String] readFiles [] = return [] readFiles (path:other) = do content ← readConfigFile path case content of "%":options → do otherOptions ← readFiles other return $ otherOptions ⧺ options [] → readFiles other _ → return content -- | Read list of options from config files readAllConfigs ∷ IO [String] readAllConfigs = do home ← getEnv "HOME" let homepath = home ".config" "todos" "todos.conf" homecfg ← readConfigFile homepath pwd <- getCurrentDirectory localcfg ← readFiles $ map ( ".todos.conf") $ scanl1 () $ splitPath pwd return $ homecfg ⧺ localcfg