diff options
-rw-r--r-- | Main.hs | 28 | ||||
-rw-r--r-- | Parsers.hs | 45 |
2 files changed, 45 insertions, 28 deletions
@@ -1,3 +1,4 @@ +{-# LANGUAGE FlexibleContexts #-} ----------------------------------------------------------------------------- -- | -- Module : Xmobar.Main @@ -24,6 +25,8 @@ import Parsers import Config import XUtil +import Data.List (intercalate) + import Paths_xmobar (version) import Data.IORef import Data.Version (showVersion) @@ -33,6 +36,8 @@ import System.Exit import System.Environment import System.Posix.Files +import Control.Monad.Writer (MonadWriter,MonadIO,unless,runWriterT) + -- $main -- | The main entry point @@ -41,9 +46,12 @@ main = do d <- openDisplay "" args <- getArgs (o,file) <- getOpts args - c <- case file of - [cfgfile] -> readConfig cfgfile - _ -> readDefaultConfig + (c,defaultings) <- runWriterT $ case file of + [cfgfile] -> readConfig cfgfile + _ -> readDefaultConfig + + unless (null defaultings) $ putStrLn $ "Fields missing from config defaulted: " + ++ intercalate "," defaultings -- listen for ConfigureEvents on the root window, for xrandr support: rootw <- rootWindow d (defaultScreen d) @@ -60,18 +68,18 @@ main = do releaseFont d fs -- | Reads the configuration files or quits with an error -readConfig :: FilePath -> IO Config +readConfig :: (MonadIO m, MonadWriter [String] m) => FilePath -> m Config readConfig f = do - file <- fileExist f - s <- if file then readFileSafe f else error $ f ++ ": file not found!\n" ++ usage + file <- io $ fileExist f + s <- io $ if file then readFileSafe f else error $ f ++ ": file not found!\n" ++ usage either (\err -> error $ f ++ ": configuration file contains errors at:\n" ++ show err) - return $ parseConfig s + id $ parseConfig s -- | Read default configuration file or load the default config -readDefaultConfig :: IO Config +readDefaultConfig :: (MonadIO m, MonadWriter [String] m) => m Config readDefaultConfig = do - home <- getEnv "HOME" + home <- io $ getEnv "HOME" let path = home ++ "/.xmobarrc" - f <- fileExist path + f <- io $ fileExist path if f then readConfig path else return defaultConfig data Opts = Help @@ -1,3 +1,4 @@ +{-# LANGUAGE FlexibleContexts #-} ----------------------------------------------------------------------------- -- | -- Module : Xmobar.Parsers @@ -27,9 +28,11 @@ import qualified Data.Map as Map import Data.Foldable (sequenceA_) import Data.List (find,inits,tails) -import Control.Applicative.Permutation(optAtom, runPermsSep) -import Control.Monad(Monad(return), mapM_, ap) +import Control.Applicative.Permutation -- (atom, maybeAtom, optAtom, runPermsSep) +import Control.Monad(Monad(return), mapM_, liftM, ap) import Control.Applicative hiding (many) +import Control.Monad.Writer +import Data.Either -- | Runs the string parser parseString :: Config -> String -> IO [(String, String)] @@ -137,27 +140,33 @@ safeLast :: [a] -> Maybe a safeLast [] = Nothing safeLast xs = Just (last xs) --- | Parse the config -parseConfig :: String -> Either ParseError Config +liftM9 :: (Monad m) => (a1 -> a -> a11 -> a2 -> a3 -> a4 -> a5 -> a6 -> a7 -> b) -> m a1 -> m a -> m a11 -> m a2 -> m a3 -> m a4 -> m a5 -> m a6 -> m a7 -> m b +liftM9 fun a b c d e f g h i = fun `liftM` a `ap` b `ap` c `ap` d `ap` e `ap` f `ap` g `ap` h `ap` i + +-- | Parse the config, logging a list of fields that were missing and replaced +-- by the default definition. +parseConfig :: MonadWriter [String] m => String -> Either ParseError (m Config) parseConfig = flip parse "Config" $ sepEndSpaces ["Config","{"] - *> perms<* wrapSkip (string "}") + *> perms <* wrapSkip (string "}") <* eof where - perms = runPermsSep (wrapSkip $ string ",") $ Config - <$> withDef font (strField "font") - <*> withDef bgColor (strField "bgColor") - <*> withDef fgColor (strField "fgColor") - <*> withDef position (field "position" readsToParsec) - <*> withDef lowerOnStart (field "lowerOnStart" parseEnum) - <*> withDef commands (field "commands" readsToParsec) - <*> withDef sepChar (strField "sepChar") - <*> withDef alignSep (strField "alignSep") - <*> withDef template (strField "template") + perms = runPermsSep (wrapSkip $ string ",") $ liftM9 Config + <$> withDef font "font" strField + <*> withDef bgColor "bgColor" strField + <*> withDef fgColor "fgColor" strField + <*> withDef position "position" (field readsToParsec) + <*> withDef lowerOnStart "lowerOnStart" (field parseEnum ) + <*> withDef commands "commands" (field readsToParsec) + <*> withDef sepChar "sepChar" strField + <*> withDef alignSep "alignSep" strField + <*> withDef template "template" strField wrapSkip x = many space *> x <* many space sepEndSpaces = mapM_ (\s -> string s <* many space) - withDef f = optAtom (f defaultConfig) + + withDef ext name parser = optAtom (do tell [name]; return $ ext defaultConfig) + (liftM return $ parser name) parseEnum = choice $ map (\x -> x <$ string (show x)) [minBound .. maxBound] - strField name = field name $ between (char '"') (char '"') (many1 . satisfy $ (/= '"')) - field name cont = sepEndSpaces [name,"="] *> cont + strField name = flip field name $ between (char '"') (char '"') (many1 . satisfy $ (/= '"')) + field cont name = sepEndSpaces [name,"="] *> cont |