packages feed

xmobar 0.5 → 0.6

raw patch · 20 files changed

+542/−402 lines, 20 files

Files

Commands.hs view
@@ -1,3 +1,23 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  XMobar.Commands+-- Copyright   :  (c) Andrea Rossato+-- License     :  BSD-style (see LICENSE)+-- +-- Maintainer  :  Andrea Rossato <andrea.rossato@unibz.it>+-- Stability   :  unstable+-- Portability :  unportable+--+-- The 'Exec' class and the 'Command' data type.+--+-- The 'Exec' class rappresents the executable types, whose constructors may+-- appear in the 'Config.commands' field of the 'Config.Config' data type.+--+-- The 'Command' data type stores the monitors to be run internally by+-- XMobar.+--+-----------------------------------------------------------------------------+ module Commands where  import System.Process@@ -12,54 +32,59 @@ import Monitors.Cpu import Monitors.Batt -data Command = Exec Program Args Alias -             | Weather Station Args -             | Network Interface Args-             | Memory Args-             | Swap Args-             | Cpu Args-             | Battery Args-               deriving (Read,Eq)+class Exec e where+    run :: e -> IO String+    rate :: e -> Int+    alias :: e -> String +data Command = Com Program Args Alias Rate+             | Weather Station Args Rate+             | Network Interface Args Rate+             | Memory Args Rate+             | Swap Args Rate+             | Cpu Args Rate+             | Battery Args Rate+               deriving (Show,Read,Eq)+ type Args = [String] type Program = String type Alias = String type Station = String type Interface = String--instance Show Command where-    show (Weather s _) = s-    show (Network i _) = i-    show (Memory _) = "memory"-    show (Swap _) = "swap"-    show (Cpu _) = "cpu"-    show (Battery _) = "battery"-    show (Exec p _ a) | p /= "" = if  a == "" then p else a-                      | otherwise = ""-class Exec e where-    run :: e -> IO String+type Rate = Int  instance Exec Command where-    run (Weather s a) = do let af = return "No station ID specified"-                           runM (a ++ [s]) weatherConfig af runWeather -    run (Network i a) = do let f = return "No device specified"-                           runM (a ++ [i]) netConfig f runNet-    run (Memory args) = do let af = runMem []-                           runM args memConfig af runMem-    run (Swap args) = do let af = runSwap []-                         runM args swapConfig af runSwap-    run (Cpu args) = do let af = runCpu []-                        runM args cpuConfig af runCpu-    run (Battery args) = do let af = runBatt []-                            runM args battConfig af runBatt-    run (Exec prog args _) = do (i,o,e,p) <- runInteractiveCommand (prog ++ concat (map (' ':) args))-                                exit <- waitForProcess p-                                let closeHandles = do hClose o-                                                      hClose i-                                                      hClose e-                                case exit of-                                  ExitSuccess -> do str <- hGetLine o-                                                    closeHandles-                                                    return str-                                  _ -> do closeHandles-                                          return $ "Could not execute command " ++ prog+    alias (Weather s _ _) = s+    alias (Network i _ _) = i+    alias (Memory _ _) = "memory"+    alias (Swap _ _) = "swap"+    alias (Cpu _ _) = "cpu"+    alias (Battery _ _) = "battery"+    alias (Com p _ a _) | p /= "" = if  a == "" then p else a+                        | otherwise = ""+    rate (Weather _ _ r) = r+    rate (Network _ _ r) = r+    rate (Memory _ r) = r+    rate (Swap _ r) = r+    rate (Cpu _ r) = r+    rate (Battery _ r) = r+    rate (Com _ _ _ r) = r+    run (Weather s a _) = runM (a ++ [s]) weatherConfig runWeather +    run (Network i a _) = runM (a ++ [i]) netConfig runNet+    run (Memory args _) = runM args memConfig runMem+    run (Swap args _) = runM args swapConfig runSwap+    run (Cpu args _) = runM args cpuConfig runCpu+    run (Battery args _) = runM args battConfig runBatt+    run (Com prog args _ _) = do (i,o,e,p) <- runInteractiveCommand (prog ++ concat (map (' ':) args))+                                 exit <- waitForProcess p+                                 let closeHandles = do hClose o+                                                       hClose i+                                                       hClose e+                                 case exit of+                                   ExitSuccess -> do str <- hGetLine o+                                                     closeHandles+                                                     return str+                                   _ -> do closeHandles+                                           return $ "Could not execute command " ++ prog++
Config.hs view
@@ -16,9 +16,12 @@                 -- $config                 Config (..)               , defaultConfig+              , runnableTypes               ) where  import Commands+import {-# SOURCE #-} Runnable+ -- $config -- Configuration data type and default configuration @@ -33,7 +36,7 @@            , height         :: Int      -- ^ Window height            , align          :: String   -- ^ text alignment            , refresh        :: Int      -- ^ Refresh rate in tenth of seconds-           , commands       :: [(Command,Int)] -- ^ For setting the command, the command argujments +           , commands       :: [Runnable] -- ^ For setting the command, the command argujments                                                 -- and refresh rate for the programs to run (optional)            , sepChar        :: String -- ^ The character to be used for indicating                                       -- commands in the output template (default '%')@@ -52,7 +55,16 @@            , height = 15            , align = "left"            , refresh = 10-           , commands = [(Memory [],10)]+           , commands = [Run $ Memory [] 10]            , sepChar = "%"            , template = "Uptime: <fc=#00FF00>%uptime%</fc> ** <fc=#FF0000>%date%</fc> %memory%"            }++-- | This is the list of types that can be hidden inside+-- 'Runnable.Runnable', the existential type that stores all commands+-- to be executed by XMobar. It is used by 'Runnable.readRunnable' in+-- the 'Runnable.Runnable' Read instance. To install a plugin just add+-- the plugin's type to the list of types appearing in this function's type+-- signature.+runnableTypes :: (Command,())+runnableTypes = undefined
Main.hs view
@@ -15,13 +15,15 @@ module Main ( -- * Main Stuff               -- $main               main-            , readConfig +            , readConfig+            , readDefaultConfig             ) where  import XMobar import Parsers import Config import System.Environment+import System.IO.Error  -- $main  @@ -29,11 +31,9 @@ main :: IO () main =      do args <- getArgs-       config <--           if length args /= 1-              then do putStrLn ("No configuration file specified. Using default settings.")-                      return defaultConfig-              else readConfig (args!!0)+       config <- case args of+           [cfgfile] -> readConfig cfgfile+           _         -> readDefaultConfig        cl <- parseTemplate config (template config)        var <- execCommands config cl        (d,w) <- createWin config@@ -48,4 +48,11 @@          [] -> error ("Corrupt config file: " ++ f)          _ -> error ("Some problem occured. Aborting...") +-- | Read default configuration or quit with an error+readDefaultConfig :: IO Config+readDefaultConfig = +    do home <- getEnv "HOME"+       let path = home ++ "/.xmobarrc"+       catch (readConfig path)+             (\e -> if isUserError e then ioError e else return defaultConfig) 
Monitors/Batt.hs view
@@ -14,25 +14,15 @@  module Monitors.Batt where -import Data.IORef import qualified Data.ByteString.Lazy.Char8 as B import System.Posix.Files  import Monitors.Common  battConfig :: IO MConfig-battConfig = -    do lc <- newIORef "#FF0000"-       l <- newIORef 25-       nc <- newIORef "#FF0000"-       h <- newIORef 75-       hc <- newIORef "#00FF00"-       t <- newIORef "Batt: <left>"-       p <- newIORef package-       u <- newIORef ""-       a <- newIORef []-       e <- newIORef ["left"]-       return $ MC nc l lc h hc t p u a e+battConfig = mkMConfig+       "Batt: <left>" -- template+       ["left"]       -- available replacements  fileB1 :: (String, String) fileB1 = ("/proc/acpi/battery/BAT1/info", "/proc/acpi/battery/BAT1/state")@@ -70,18 +60,8 @@        l <- showWithColors f (x * 100)        return [l] -package :: String-package = "xmb-batt"- runBatt :: [String] -> Monitor String runBatt _ =     do c <- io $ parseBATT        l <- formatBatt c        parseTemplate l -    -{--main :: IO ()-main =-    do let af = runBatt []-       runMonitor battConfig af runBatt--}
Monitors/Common.hs view
@@ -20,7 +20,7 @@                        , Opts (..)                        , setConfigValue                        , getConfigValue-                       , runMonitor+                       , mkMConfig                        , runM                        , io                        -- * Parsers@@ -57,23 +57,18 @@ import Text.ParserCombinators.Parsec  import System.Console.GetOpt-import System.Environment-import System.Exit  -- $monitor  type Monitor a = ReaderT MConfig IO a  data MConfig =-    MC { normalColor :: IORef String+    MC { normalColor :: IORef (Maybe String)        , low :: IORef Int-       , lowColor :: IORef String+       , lowColor :: IORef (Maybe String)        , high :: IORef Int-       , highColor :: IORef String+       , highColor :: IORef (Maybe String)        , template :: IORef String-       , packageName :: IORef String-       , usageTail :: IORef String-       , addedArgs :: IORef [OptDescr Opts]        , export :: IORef [String]        }  @@ -98,87 +93,61 @@ getConfigValue s =     sel s +mkMConfig :: String+          -> [String]+          -> IO MConfig+mkMConfig tmpl exprts =+    do lc <- newIORef Nothing+       l <- newIORef 33+       nc <- newIORef Nothing+       h <- newIORef 66+       hc <- newIORef Nothing+       t <- newIORef tmpl+       e <- newIORef exprts+       return $ MC nc l lc h hc t e -data Opts = Help-          | Version-          | HighColor String+data Opts = HighColor String           | NormalColor String           | LowColor String           | Low String           | High String           | Template String-          | Others String -options :: Monitor [OptDescr Opts]+options :: [OptDescr Opts] options =-    do t <- getConfigValue export-       ao <- getConfigValue addedArgs -       tmpl <- getConfigValue template-       return $ [ Option ['h']  ["help"]    (NoArg Help)    "Show this help"-                , Option ['V']  ["version"] (NoArg Version) "Show version information"-                , Option ['H']  ["High"]  (ReqArg High "number") "The high threshold"-                , Option ['L']  ["Low"]  (ReqArg Low "number") "The low threshold"-                , Option []  ["high"]  (ReqArg HighColor "color number") "Color for the high threshold: es \"#FF0000\""-                , Option []  ["normal"]  (ReqArg NormalColor "color number") "Color for the normal threshold: es \"#00FF00\""-                , Option []  ["low"]  (ReqArg LowColor "color number") "Color for the low threshold: es \"#0000FF\""-                , Option ['t']  ["template"]  (ReqArg Template "output template") -                             ("Output template.\nAvaliable variables: " ++ show t ++ "\nDefault template: " ++ show tmpl)-                ] ++ ao--usage :: Monitor ()-usage =-    do pn <- io $ getProgName-       u <- getConfigValue usageTail-       opts <- options-       io $ putStr $ usageInfo ("Usage: " ++ pn ++ " [OPTIONS...] " ++ u) opts--version :: String-version = "0.5"--versinfo :: String -> String -> IO ()-versinfo p v = putStrLn $ p ++" " ++ v+    [ Option ['H']  ["High"]  (ReqArg High "number") "The high threshold"+    , Option ['L']  ["Low"]  (ReqArg Low "number") "The low threshold"+    , Option ['h']  ["high"]  (ReqArg HighColor "color number") "Color for the high threshold: ex \"#FF0000\""+    , Option ['n']  ["normal"]  (ReqArg NormalColor "color number") "Color for the normal threshold: ex \"#00FF00\""+    , Option ['l']  ["low"]  (ReqArg LowColor "color number") "Color for the low threshold: ex \"#0000FF\""+    , Option ['t']  ["template"]  (ReqArg Template "output template") "Output template."+    ]  doArgs :: [String] -       -> Monitor String         -> ([String] -> Monitor String)        -> Monitor String-doArgs args actionFail action =-    do opts <- options-       case (getOpt Permute opts args) of-         (o, n, []) -> do-           doConfigOptions o-           case n of-             []   -> actionFail-             nd   -> action nd-         (_, _, errs) -> io $ error (concat errs)+doArgs args action =+    do case (getOpt Permute options args) of+         (o, n, []) -> do doConfigOptions o+                          action n+         (_, _, errs) -> return (concat errs)  doConfigOptions :: [Opts] -> Monitor () doConfigOptions [] = io $ return () doConfigOptions (o:oo) =-    do pn <- getConfigValue packageName-       let next = doConfigOptions oo+    do let next = doConfigOptions oo        case o of-         Help -> usage >> io (exitWith ExitSuccess)-         Version -> io $ versinfo pn version >> exitWith ExitSuccess          High h -> setConfigValue (read h) high >> next          Low l -> setConfigValue (read l) low >> next-         HighColor hc -> setConfigValue hc highColor >> next-         NormalColor nc -> setConfigValue nc normalColor >> next-         LowColor lc -> setConfigValue lc lowColor >> next+         HighColor hc -> setConfigValue (Just hc) highColor >> next+         NormalColor nc -> setConfigValue (Just nc) normalColor >> next+         LowColor lc -> setConfigValue (Just lc) lowColor >> next          Template t -> setConfigValue t template >> next-         _ -> next -runMonitor ::  IO MConfig -> Monitor String -> ([String] -> Monitor String) -> IO ()-runMonitor conf actionFail action =-    do c <- conf-       args <- getArgs-       let ac = doArgs args actionFail action-       putStrLn =<< runReaderT ac c--runM :: [String] -> IO MConfig -> Monitor String -> ([String] -> Monitor String) -> IO String-runM args conf actionFail action =+runM :: [String] -> IO MConfig -> ([String] -> Monitor String) -> IO String+runM args conf action =     do c <- conf-       let ac = doArgs args actionFail action+       let ac = doArgs args action        runReaderT ac c  io :: IO a -> Monitor a@@ -269,7 +238,8 @@  takeDigits :: Int -> Float -> Float takeDigits d n = -    read $ showFFloat (Just d) n ""+    fromIntegral ((round (n * fact)) :: Int) / fact+  where fact = 10 ^ d  floatToPercent :: Float -> String floatToPercent n = @@ -279,11 +249,13 @@ stringParser (x,y) =      flip (!!) x . map B.unpack . B.words . flip (!!) y . B.lines -setColor :: String -> Selector String -> Monitor String+setColor :: String -> Selector (Maybe String) -> Monitor String setColor str s =     do a <- getConfigValue s-       return $ "<fc=" ++ a ++ ">" ++-              str ++ "</fc>"+       case a of+            Nothing -> return str+            Just c -> return $+                "<fc=" ++ c ++ ">" ++ str ++ "</fc>"  showWithColors :: (Float -> String) -> Float -> Monitor String showWithColors f x =
Monitors/Cpu.hs view
@@ -16,21 +16,11 @@  import Monitors.Common import qualified Data.ByteString.Lazy.Char8 as B-import Data.IORef  cpuConfig :: IO MConfig-cpuConfig = -    do lc <- newIORef "#BFBFBF"-       l <- newIORef 2-       nc <- newIORef "#00FF00"-       h <- newIORef 60-       hc <- newIORef "#FF0000"-       t <- newIORef "Cpu: <total>"-       p <- newIORef package-       u <- newIORef ""-       a <- newIORef []-       e <- newIORef ["total","user","nice","system","idle"]-       return $ MC nc l lc h hc t p u a e+cpuConfig = mkMConfig+       "Cpu: <total>"                           -- template+       ["total","user","nice","system","idle"]  -- available replacements  cpuData :: IO [Float] cpuData = do s <- B.readFile "/proc/stat"@@ -56,18 +46,8 @@            list = t:x        mapM (showWithColors f) . map (* 100) $ list -package :: String-package = "xmb-cpu"- runCpu :: [String] -> Monitor String runCpu _ =     do c <- io $ parseCPU        l <- formatCpu c        parseTemplate l -    -{--main :: IO ()-main =-    do let af = runCpu []-       runMonitor cpuConfig af runCpu--}
Monitors/Mem.hs view
@@ -16,21 +16,11 @@  import Monitors.Common -import Data.IORef- memConfig :: IO MConfig-memConfig = -    do lc <- newIORef "#BFBFBF"-       l <- newIORef 300-       nc <- newIORef "#00FF00"-       h <- newIORef 500-       hc <- newIORef "#FF0000"-       t <- newIORef "Mem: <usedratio>% (<cache>M)"-       p <- newIORef package-       u <- newIORef ""-       a <- newIORef []-       e <- newIORef ["total", "free", "buffer", "cache", "rest", "used", "usedratio"]-       return $ MC nc l lc h hc t p u a e+memConfig = mkMConfig+       "Mem: <usedratio>% (<cache>M)" -- template+       ["total", "free", "buffer",    -- available replacements+        "cache", "rest", "used", "usedratio"]  fileMEM :: IO String fileMEM = readFile "/proc/meminfo"@@ -50,18 +40,8 @@     do let f n = show (takeDigits 2 n)        mapM (showWithColors f) x -package :: String-package = "xmb-mem"- runMem :: [String] -> Monitor String runMem _ =     do m <- io $ parseMEM        l <- formatMem m        parseTemplate l -    -{--main :: IO ()-main =-    do let af = runMem []-       runMonitor monitorConfig af runMem--}
Monitors/Net.hs view
@@ -15,9 +15,7 @@ module Monitors.Net where  import Monitors.Common--import Data.IORef-import Text.ParserCombinators.Parsec+import qualified Data.ByteString.Lazy.Char8 as B  data NetDev = NA             | ND { netDev :: String@@ -29,24 +27,47 @@ interval = 500000  netConfig :: IO MConfig-netConfig = -    do lc <- newIORef "#BFBFBF"-       l <- newIORef 0-       nc <- newIORef "#00FF00"-       h <- newIORef 32-       hc <- newIORef "#FF0000"-       t <- newIORef "<dev>: <rx>|<tx>"-       p <- newIORef package-       u <- newIORef "dev"-       a <- newIORef []-       e <- newIORef ["dev", "rx", "tx"]-       return $ MC nc l lc h hc t p u a e+netConfig = mkMConfig+    "<dev>: <rx>|<tx>"      -- template+    ["dev", "rx", "tx"]     -- available replacements -fileNET :: IO String++-- takes to element of a list given their indexes+getTwoElementsAt :: Int -> Int -> [a] -> [a]+getTwoElementsAt x y xs =+    z : [zz]+      where z = xs !! x+            zz = xs !! y++-- split a list of strings returning a list with: 1. the first part of+-- the split; 2. the second part of the split without the Char; 3. the+-- rest of the list. For instance: +--+-- > splitAtChar ':' ["lo:31174097","31174097"] +--+-- will become ["lo","31174097","31174097"]+splitAtChar :: Char ->  [String] -> [String]+splitAtChar c xs =+    first : (rest xs)+        where rest = map $ \x -> if (c `elem` x) then (tail $ dropWhile (/= c) x) else x+              first = head $ map (takeWhile (/= c)) . filter (\x -> (c `elem` x)) $ xs++readNetDev :: [String] -> NetDev               +readNetDev [] = NA+readNetDev xs =+    ND (xs !! 0) (r (xs !! 1)) (r (xs !! 2))+       where r s | s == "" = 0+                 | otherwise = (read s) / 1024++fileNET :: IO [NetDev] fileNET = -    do f <- readFile "/proc/net/dev"-       return $ unlines $ drop 2 $ lines f+    do f <- B.readFile "/proc/net/dev"+       return $ netParser f +netParser :: B.ByteString -> [NetDev]+netParser =+    map readNetDev . map (splitAtChar ':') . map (getTwoElementsAt 0 8) . map (words . B.unpack) . drop 2 . B.lines+ formatNet :: Float -> Monitor String formatNet d =     showWithColors f d@@ -60,26 +81,9 @@                         parseTemplate [d,rx,tx]          NA -> return "N/A" -pNetDev :: Parser NetDev-pNetDev = -    do { skipMany1 space-       ; dn <- manyTill alphaNum $ char ':'-       ; [rx] <- count 1 getNumbers-       ; _ <- count 7 getNumbers-       ; [tx] <- count 1 getNumbers-       ; _ <- count 7 getNumbers-       ; char '\n'-       ; return $ ND dn (rx / 1024) (tx / 1024)-       } --parserNet :: Parser [NetDev]-parserNet = manyTill pNetDev eof- parseNET :: String -> IO [NetDev] parseNET nd = -    do (a',b') <- doActionTwiceWithDelay interval fileNET-       a <- runP parserNet a'-       b <- runP parserNet b'+    do (a,b) <- doActionTwiceWithDelay interval fileNET        let netRate f da db = takeDigits 2 $ ((f db) - (f da)) * fromIntegral (1000000 `div` interval)            diffRate (da,db) = ND (netDev da)                                (netRate netRx da db)@@ -93,14 +97,3 @@               [x] -> return x               _ -> return $ NA        printNet n---package :: String-package = "xmb-net"--{--main :: IO ()-main =-    do let f = return "No device specified"-       runMonitor netConfig f runNet--}
Monitors/Swap.hs view
@@ -16,22 +16,12 @@  import Monitors.Common -import Data.IORef import qualified Data.ByteString.Lazy.Char8 as B  swapConfig :: IO MConfig-swapConfig = -    do lc <- newIORef "#BFBFBF"-       l <- newIORef 30-       nc <- newIORef "#00FF00"-       h <- newIORef 75-       hc <- newIORef "#FF0000"-       t <- newIORef "Swap: <usedratio>%"-       p <- newIORef package-       u <- newIORef ""-       a <- newIORef []-       e <- newIORef ["total", "used", "free", "usedratio"]-       return $ MC nc l lc h hc t p u a e+swapConfig = mkMConfig+        "Swap: <usedratio>"                    -- template+        ["total", "used", "free", "usedratio"] -- available replacements  fileMEM :: IO B.ByteString fileMEM = B.readFile "/proc/meminfo"@@ -42,25 +32,19 @@        let p x y = flip (/) 1024 . read . stringParser x $ y            tot = p (1,11) file            free = p (1,12) file-       return [tot, (tot - free), free, (tot - free) / tot * 100]+       return [tot, (tot - free), free, (tot - free) / tot]  formatSwap :: [Float] -> Monitor [String]  formatSwap x =-    do let f n = show (takeDigits 2 n)-       mapM (showWithColors f) x--package :: String-package = "xmb-swap"+    do let f1 n = show (takeDigits 2 n)+           f2 n = floatToPercent n+           (hd, tl) = splitAt 3 x+       firsts <- mapM (showWithColors f1) hd+       lasts <- mapM (showWithColors f2) tl+       return $ firsts ++ lasts  runSwap :: [String] -> Monitor String runSwap _ =     do m <- io $ parseMEM        l <- formatSwap m        parseTemplate l -    -{--main :: IO ()-main =-    do let af = runSwap []-       runMonitor swapConfig af runSwap--}
Monitors/Weather.hs view
@@ -16,8 +16,6 @@  import Monitors.Common -import Data.IORef- import System.Process import System.Exit import System.IO@@ -26,32 +24,23 @@   weatherConfig :: IO MConfig-weatherConfig = -    do lc <- newIORef "#BFBFBF"-       l <- newIORef 15-       nc <- newIORef "#00FF00"-       h <- newIORef 27-       hc <- newIORef "#FF0000"-       t <- newIORef "<station>: <tempC>C, rh <rh>% (<hour>)"-       p <- newIORef package-       u <- newIORef "station ID"-       a <- newIORef []-       e <- newIORef ["station"-                     , "stationState"-                     , "year"-                     , "month"-                     , "day"-                     , "hour"-                     , "wind"-                     , "visibility"-                     , "skyCondition"-                     , "tempC"-                     , "tempF"-                     , "dewPoint"-                     , "rh"-                     ,"pressure"-                     ]-       return $ MC nc l lc h hc t p u a e+weatherConfig = mkMConfig+       "<station>: <tempC>C, rh <rh>% (<hour>)" -- template+       ["station"                               -- available replacements+       , "stationState"+       , "year"+       , "month"+       , "day"+       , "hour"+       , "wind"+       , "visibility"+       , "skyCondition"+       , "tempC"+       , "tempF"+       , "dewPoint"+       , "rh"+       ,"pressure"+       ]  data WeatherInfo =     WI { stationPlace :: String@@ -81,15 +70,13 @@            return (y, m, d ,([h]++[hh]++":"++[mi]++mimi))  pTemp :: Parser Float-pTemp = do string ": "-           manyTill anyChar $ char '('+pTemp = do manyTill anyChar $ char '('            s <- manyTill digit $ (char ' ' <|> char '.')            skipRestOfLine            return $read s  pRh :: Parser Float-pRh = do string ": "-         s <- manyTill digit $ (char '%' <|> char '.')+pRh = do s <- manyTill digit $ (char '%' <|> char '.')          return $ read s  parseData :: Parser [WeatherInfo]@@ -102,10 +89,10 @@        w <- getAfterString "Wind: "        v <- getAfterString "Visibility: "        sk <- getAfterString "Sky conditions: "-       skipTillString "Temperature"+       skipTillString "Temperature: "        temp <- pTemp        dp <- getAfterString "Dew Point: "-       skipTillString "Relative Humidity"+       skipTillString "Relative Humidity: "        rh <- pRh        p <- getAfterString "Pressure (altimeter): "        manyTill skipRestOfLine eof@@ -140,13 +127,3 @@     do d <- io $ getData $ head str        i <- io $ runP parseData d        formatWeather i--package :: String-package = "xmb-weather"--{--main :: IO ()-main =-    do let af = return "No station ID specified"-       runMonitor weatherConfig af runWeather--}
Parsers.hs view
@@ -27,6 +27,7 @@  import Config import Commands+import Runnable import Text.ParserCombinators.Parsec import qualified Data.Map as Map @@ -103,20 +104,20 @@ templateParser c = many (templateStringParser c)  -- | Actually runs the template parsers-parseTemplate :: Config -> String -> IO [(Command,String,String)]+parseTemplate :: Config -> String -> IO [(Runnable,String,String)] parseTemplate config s =      do str <- case (parse (templateParser config) "" s) of                 Left _ -> return [("","","")]                 Right x  -> return x-       let comList = map (show . fst) $ commands config-           m = Map.fromList . zip comList . map fst $ (commands config)-       return $ combine m str+       let comList = map alias (commands config)+           m = Map.fromList $ zip comList (commands config)+       return $ combine config m str  -- | Given a finite "Map" and a parsed templatet produces the -- | resulting output string.-combine :: Map.Map String Command -> [(String, String, String)] -> [(Command,String,String)]-combine _ [] = []-combine m ((ts,s,ss):xs) = -    [(com, s, ss)] ++ combine m xs+combine :: Config -> Map.Map String Runnable -> [(String, String, String)] -> [(Runnable,String,String)]+combine _ _ [] = []+combine config m ((ts,s,ss):xs) = +    [(com, s, ss)] ++ combine config m xs         where com = Map.findWithDefault dflt ts m-              dflt = Exec ts [] [] --"<" ++ ts ++ " not found!>"+              dflt = Run $ Com ts [] [] (refresh config) --"<" ++ ts ++ " not found!>"
+ Plugins.hs view
@@ -0,0 +1,20 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Xmobar.Plugins+-- Copyright   :  (c) Andrea Rossato+-- License     :  BSD-style (see LICENSE)+-- +-- Maintainer  :  Andrea Rossato <andrea.rossato@unibz.it>+-- Stability   :  unstable+-- Portability :  unportable+--+-- This module exports the API for plugins.+--+-- Have a look at Plugins\/HelloWorld.hs+--+-----------------------------------------------------------------------------++module Plugins ( Exec (..) +               ) where++import Commands
+ Plugins/HelloWorld.hs view
@@ -0,0 +1,25 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Plugins.HelloWorld+-- Copyright   :  (c) Andrea Rossato+-- License     :  BSD-style (see LICENSE)+-- +-- Maintainer  :  Andrea Rossato <andrea.rossato@unibz.it>+-- Stability   :  unstable+-- Portability :  unportable+--+-- A plugin example for XMobar, a status bar for the Xmonad Window Manager +--+-----------------------------------------------------------------------------++module Plugins.HelloWorld where++import Plugins++data HelloWorld = HelloWorld+    deriving (Read)++instance Exec HelloWorld where+    run HelloWorld = return "<fc=red>Hello World!!</fc>"+    rate HelloWorld = 1000+    alias HelloWorld = "helloWorld"
+ Plugins/helloworld.config view
@@ -0,0 +1,16 @@+Config { font = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"+       , bgColor = "#000000"+       , fgColor = "#BFBFBF"+       , xPos = 0+       , yPos = 0+       , width = 1024+       , height = 15+       , align = "right"+       , refresh = 10+       , commands = [ Run Cpu [] 10+                    , Run Weather "LIPB" [] 36000+                    , Run HelloWorld+                    ]+       , sepChar = "%"+       , template = "%cpu% | %helloWorld% | %LIPB% | <fc=yellow>%date%</fc>"+       }
README view
@@ -3,7 +3,7 @@ ABOUT ===== -Xmobar is a minimalisti, text based, status bar, designed for the+Xmobar is a minimalistic, text based, status bar, designed for the XMonad Window Manager.  It was inspired by the Ion3 status bar, and supports similar features.@@ -15,14 +15,19 @@ INSTALLATION ============ -tar xvfz xmobar-0.5+tar xvfz xmobar-0.6+cd xmobar-0.6 runhaskell Setup.lhs configure --prefix=/usr/local runhaskell Setup.lhs build runhaskell Setup.lhs haddock (optional for building the code documentation) runhaskell Setup.lhs install (possibly to be run as root)  Run with:-xmobar /path/to/config $+xmobar /path/to/config &+or+xmobar &+if you have the default configuration file saved as:+~/.xmobarrc  CONFIGURATION =============@@ -59,36 +64,43 @@ -------------------  The output template must contain at least one command. XMobar will-parse the template and will search for the commands to be executed in+parse the template and will search for the command to be executed in the "commands" configuration option. First an "alias" will be search (internal commands such as Weather or Network have default aliasing, see below). After that the command name will be tried. If a command is-found, its arguments will be used. If no command is found in the-commands list, then XMobar will try to execute the program with the-name found in the template. If the execution is not successful an-error will be reported.+found, the arguments specified in the "commands" list will be used. ++If no command is found in the "commands" list, XMobar will try to+execute a program with the name found in the template. If the+execution is not successful an error will be reported.     The "commands" Configuration Option ----------------------------------- -The "commands" configuration option is a list of commands for storing-information to be used by XMobar wen parsing the template. Each member-of the list consists in a tuple formed by a command with arguments and-a number, the refresh rate in tenth of second.+The "commands" configuration option is a list of commands' information+and arguments to be used by XMobar when parsing the output template.+Each member of the list consists in a command prefixed by the "Run"+keyword. Each command has arguments to control the way XMobar is going+to execute it. -Available commands are: Weather, Network, memory, Swap, Cpu, Battery,-and Exec. This last one is used to execute external programs.+Available template commands are: Weather, Network, Memory, Swap, Cpu,+Battery, and Com. This last one is used to execute external programs. -Es: (Memory ["-t","Mem: <usedratio>%"], 10)+Other commands can be created as plugins with the Plugin+infrastructure. +This is an example of a command in the "commands" list:+Run Memory ["-t","Mem: <usedratio>%"] 10+ Internal Commands and Aliases ----------------------------- -Each command in the "commands" configuration option has an alias to be-used in the template.+Each command in the "commands" configuration option list has an alias+to be used in the template.  Internal commands have default aliases:-Weather StationID Args++Weather StationID Args RefreshRate - aliases to the Station ID: so Weather "LIPB" [] can be used in template as %LIBP% - Args: the argument list (see below) - Variables that can be used with the "-t"/"--template" argument: @@ -97,35 +109,35 @@ 	    "dewPoint", "rh", "pressure" - Default template: "<station>: <tempC>C, rh <rh>% (<hour>)" -Network Interface ARGS+Network Interface Args RefreshRate - aliases to the interface name: so Network "eth0" [] can be used as %eth0% - Args: the argument list (see below) - Variables that can be used with the "-t"/"--template" argument:  	    "dev", "rx", "tx" - Default template: "<dev>: <rx>|<tx>" -Memory Args+Memory Args RefreshRate - aliases to "memory" - Args: the argument list (see below) - Variables that can be used with the "-t"/"--template" argument:  	    "total", "free", "buffer", "cache", "rest", "used", "usedratio" - Default template: "Mem: <usedratio>% (<cache>M)" -Swap Args+Swap Args RefreshRate - aliases to "swap" - Args: the argument list (see below) - Variables that can be used with the "-t"/"--template" argument:  	    "total", "used", "free", "usedratio" - Default template: "Swap: <usedratio>%" -Cpu Args+Cpu Args RefreshRate - aliases to "cpu" - Args: the argument list (see below) - Variables that can be used with the "-t"/"--template" argument:  	    "total", "user", "nice", "system", "idle" - Default template: "Cpu: <total>" -Battery Args+Battery Args RefreshRate - aliases to "battery" - Args: the argument list (see below) - Variables that can be used with the "-t"/"--template" argument: @@ -140,33 +152,109 @@  -H number           --High=number               The high threshold -L number           --Low=number                The low threshold-                    --high=color number         Color for the high threshold: es "#FF0000"-                    --normal=color number       Color for the normal threshold: es "#00FF00"-                    --low=color number          Color for the low threshold: es "#0000FF"--t output template  --template=output template  Output template+-h color number     --high=color number         Color for the high threshold: es "#FF0000"+-n color number     --normal=color number       Color for the normal threshold: es "#00FF00"+-l color number     --low=color number          Color for the low threshold: es "#0000FF"+-t output template  --template=output template  Output template of the command. -Commands must be set as a list. Es:-(Weather "EGPF" ["-t","<station>: <tempC>C"], 36000)+Commands' arguments must be set as a list. Es:+Run Weather "EGPF" ["-t","<station>: <tempC>C"] 36000 +In this case XMobar will run the weather monitor, getting information+for the weather station ID EGPF (Glasgow Airport, as a homage to GHC)+every hour (36000 tenth of seconds), with a template that will output+something like:+"Glasgow Airport: 16.0C"+ Executing External Commands ---------------------------  In order to execute an external command you can either write the command name in the template, in this case it will be executed without arguments, or you can configure it in the "commands" configuration-option with the Exec command:+option list with the Com template command: -Exec ProgarmName Args Alias+Com ProgarmName Args Alias RefreshRate - ProgramName: the name of the program - Args: the arguments to be passed to the program at execution time - Alias: a name to be used in the template. If the alias is en empty   string the program name can be used in the template. Es:-(Exec "uname" ["-s","-r"] "", 36000)+Run Com "uname" ["-s","-r"] "" 36000 can be used in the output template as %uname%-(Exec "date" ["+\"%a %b %_d %H:%M\""] "mydate", 600)++Run Com "date" ["+\"%a %b %_d %H:%M\""] "mydate" 600 can be used in the output template as %mydate% +PLUGINS+=======++Writing a Plugin+----------------++Writing a plugin for XMobar should be very simple. You need to create+a data type with at least one constructor.++Next you must declare this data type an instance of the Exec class, by+defining the 3 needed methods:++    run :: e -> IO String+    rate :: e -> Int+    alias :: e -> String++"run" must produce the IO String that will be displayed by XMobar.+"rate" is the refresh rate for you plugin (the number of tenth of+seconds between two succesive runs);+"alias" is the name to be used in the output template.++That requires importing the plugin API (the Exec class definition),+that is exported by Plugins.hs. So you just need to import it in your+module with:++import Plugins++After that your type constructor can be used as an argument for the+Runnable type constructor "Run" in the "commands" list of the+configuration options.++This requires importing you plugin into Config.hs and adding you type+to the type list in the type signature of Config.runnableTypes.++For a vary basic example see Plugins/HelloWorld.hs that is distributed+with XMobar.++Installing a Plugin+-------------------++Installing a plugin should require 3 steps. Here we are going to+install the HelloWorld plugin that comes with XMobar:++1. import the plugin module in Config.hs, by adding: +   +import Plugins.HelloWorld++2. add the plugin data type to the list of data types in the type+   signauture of "runnableTypes" in Config.hs. For instance, for the+   HelloWorld plugin, chnage "runnableTypes" into:++runnableTypes :: (Command,(HelloWorld,()))+runnableTypes = undefined++3. Rebuild and reinstall XMobar. Now test it with:++xmobar Plugins/helloworld.config++As you may see in the example configuration file, the plugin can be+used by adding, in the "commands" list:++Run HelloWorld++and, in the output template, the alias of the plugin:++%helloWorld%++That's it.+ AUTHOR ====== @@ -174,6 +262,9 @@  CREDITS =======++Thanks to Robert Manea for his help in understanding how X works. He+gave me suggestions on how to solve many many problems with XMobar.  XMobar incorporates patches from: Krzysztof Kosciuszkiewicz
+ Runnable.hs view
@@ -0,0 +1,58 @@+{-# OPTIONS -fglasgow-exts #-}+-----------------------------------------------------------------------------+-- |+-- Module      :  XMobar.Runnable+-- Copyright   :  (c) Andrea Rossato+-- License     :  BSD-style (see LICENSE)+-- +-- Maintainer  :  Andrea Rossato <andrea.rossato@unibz.it>+-- Stability   :  unstable+-- Portability :  unportable+--+-- The existential type to store the list of commands to be executed.+-- I must thank Claus Reinke for the help in understanding the mysteries of+-- reading existential types. The Read instance of Runnable must be credited to +-- him. +-- +-- See here:+-- http:\/\/www.haskell.org\/pipermail\/haskell-cafe\/2007-July\/028227.html+--+-----------------------------------------------------------------------------++module Runnable where++import Control.Monad+import Text.Read+import Text.ParserCombinators.ReadPrec+import Config (runnableTypes)+import Commands++data Runnable = forall r . (Exec r, Read r) => Run r++instance Exec Runnable where+     run (Run a) = run a+     rate (Run a) = rate a+     alias (Run a) = alias a++instance Read Runnable where+    readPrec = readRunnable++class ReadAsAnyOf ts ex where+    -- | Reads an existential type as any of hidden types ts+    readAsAnyOf :: ts -> ReadPrec ex++instance ReadAsAnyOf () ex where +    readAsAnyOf ~() = mzero++instance (Read t, Exec t, ReadAsAnyOf ts Runnable) => ReadAsAnyOf (t,ts) Runnable where +    readAsAnyOf ~(t,ts) = r t `mplus` readAsAnyOf ts+              where r ty = do { m <- readPrec; return (Run (m `asTypeOf` ty)) }++-- | The 'Prelude.Read' parser for the 'Runnable' existential type. It+-- needs an 'Prelude.undefined' with a type signature containing the+-- list of all possible types hidden within 'Runnable'. See 'Config.runnableTypes'.+-- Each hidden type must have a 'Prelude.Read' instance.+readRunnable :: ReadPrec Runnable+readRunnable = prec 10 $ do+                 Ident "Run" <- lexP+                 parens $ readAsAnyOf runnableTypes
+ Runnable.hs-boot view
@@ -0,0 +1,11 @@+{-# OPTIONS -fglasgow-exts #-}+module Runnable where+import Commands++data Runnable = forall r . (Exec r,Read r) => Run r++instance Read Runnable+instance Exec Runnable+++
XMobar.hs view
@@ -47,6 +47,7 @@ import Config import Parsers import Commands+import Runnable  -- $main --@@ -90,10 +91,10 @@      let dflt = defaultScreen dpy      rootw  <- rootWindow dpy dflt      win <- mkUnmanagedWindow dpy (defaultScreenOfDisplay dpy) rootw -            (fromIntegral $ xPos config) -            (fromIntegral $ yPos config) -            (fromIntegral $ width config) -            (fromIntegral $ height config)+            (fi $ xPos config) +            (fi $ yPos config) +            (fi $ width config) +            (fi $ height config)      mapWindow dpy win      return (dpy,win) @@ -111,80 +112,83 @@        --let's get the fonts        fontst <-  io $ loadQueryFont dpy (font config)        io $ setFont dpy gc (fontFromFontStruct fontst)--       -- set window background +       -- create a pixmap to write to and fill it with a rectangle+       p <- io $ createPixmap dpy win +            (fi (width config)) +            (fi (height config)) +            (defaultDepthOfScreen (defaultScreenOfDisplay dpy))+       -- the fgcolor of the rectangle will be the bgcolor of the window        io $ setForeground dpy gc bgcolor-       io $ fillRectangle dpy win gc 0 0 -              (fromIntegral $ width config) -              (fromIntegral $ height config)-       -- write+       io $ fillRectangle dpy p gc 0 0 +              (fi $ width config) +              (fi $ height config)+       -- write to the pixmap the new string        let strWithLenth = map (\(s,c) -> (s,c,textWidth fontst s)) str-       printStrings gc fontst 1 strWithLenth -       -- free everything+       p' <- printStrings p gc fontst 1 strWithLenth +       -- copy the pixmap with the new string to the window+       io $ copyArea dpy p' win gc 0 0 (fi (width config)) (fi (height config)) 0 0+       -- free up everything (we do not want to leak memory!)        io $ freeFont dpy fontst        io $ freeGC dpy gc+       io $ freePixmap dpy p'+       -- resync        io $ sync dpy True  -- | An easy way to print the stuff we need to print-printStrings :: GC+printStrings :: Drawable +             -> GC              -> FontStruct              -> Position              -> [(String, String, Position)]-             -> Xbar ()-printStrings _ _ _ [] = return ()-printStrings gc fontst offs sl@((s,c,l):xs) =+             -> Xbar Pixmap+printStrings p _ _ _ [] = return p+printStrings p gc fontst offs sl@((s,c,l):xs) =     do config <- ask        st <- get        let (_,asc,_,_) = textExtents fontst s            totSLen = foldr (\(_,_,len) -> (+) len) 0 sl-           valign = (fromIntegral (height config) + fromIntegral asc) `div` 2-           remWidth = fromIntegral (width config) - fromIntegral totSLen+           valign = (fi (height config) + fi asc) `div` 2+           remWidth = fi (width config) - fi totSLen            offset = case (align config) of                       "center" -> (remWidth + offs) `div` 2                       "right" -> remWidth - 1                       "left" -> offs                       _ -> offs-       color <- io $ initColor (display st) c-       io $ setForeground (display st) gc color-       io $ drawString (display st) (window st) gc offset valign s-       printStrings gc fontst (offs + l) xs+       fgcolor <- io $ initColor (display st) c+       bgcolor <- io $ initColor (display st) (bgColor config)+       io $ setForeground (display st) gc fgcolor+       io $ setBackground (display st) gc bgcolor+       io $ drawImageString (display st) p gc offset valign s+       p' <- printStrings p gc fontst (offs + l) xs+       return p'  -- $commands --- | Gets the refresh rate set in configuration for a given command.-getRefRate :: Config -> Command -> Int-getRefRate c com =-    let l = commands c-        p = filter (\(s,_) -> s == com) l-    in case p of-         [(_,int)] -> int-         _ -> refresh c- -- | Runs a list of programs as independent threads and returns their thread id -- and the MVar they will be writing to.-execCommands :: Config -> [(Command,String,String)] -> IO [(ThreadId, MVar String)]+execCommands :: Config -> [(Runnable,String,String)] -> IO [(ThreadId, MVar String)] execCommands _ [] = return [] execCommands c (x:xs) =     do i <- execCommand c x        is <- execCommands c xs        return $ i : is -execCommand :: Config -> (Command,String,String) -> IO (ThreadId, MVar String)+execCommand :: Config -> (Runnable,String,String) -> IO (ThreadId, MVar String) execCommand c com =      do var <- newMVar "Updating..."        h <- forkIO $ runCommandLoop var c com        return (h,var) -runCommandLoop :: MVar String -> Config -> (Command,String,String) -> IO ()+runCommandLoop :: MVar String -> Config -> (Runnable,String,String) -> IO () runCommandLoop var conf c@(com,s,ss)-    | show com == "" = +    | alias com == "" =          do modifyMVar_ var (\_ -> return $ "Could not parse the template")            tenthSeconds (refresh conf)            runCommandLoop var conf c     | otherwise =         do str <- run com            modifyMVar_ var (\_ -> return $ s ++ str ++ ss)-           tenthSeconds (getRefRate conf com)+           tenthSeconds (rate com)             runCommandLoop var conf c  -- | Reads MVars set by 'runCommandLoop'@@ -244,3 +248,7 @@                | otherwise = threadDelay (s * 100000)                where y = (maxBound :: Int)                      x = y `div` 100000++-- | Short-hand for 'fromIntegral'+fi :: (Integral a, Num b) => a -> b+fi = fromIntegral
xmobar.cabal view
@@ -1,5 +1,5 @@ name:               xmobar-version:            0.5+version:            0.6 homepage:           http://gorgias.mine.nu/repos/xmobar/ synopsis:           A Statusbar for the XMonad Window Manager description: 	    Xmobar is a minimal status bar for the XMonad Window Manager.@@ -15,7 +15,7 @@ executable:         xmobar main-is:            Main.hs Hs-Source-Dirs:     ./-Other-Modules:      XMobar, Config, Parsers, Commands, Monitors.Common, Monitors.Batt -		    Monitors.Weather, Monitors.Swap, Monitors.Mem, Monitors.Cpu+Other-Modules:      XMobar, Config, Parsers, Commands, Runnable, Plugins, Monitors.Common, Monitors.Batt +		    Monitors.Weather, Monitors.Swap, Monitors.Mem, Monitors.Cpu, Monitors.Net ghc-options:        -funbox-strict-fields -O2 -fasm -Wall -optl-Wl,-s -threaded ghc-prof-options:   -prof -auto-all
xmobar.config-sample view
@@ -1,21 +1,21 @@ Config { font = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"-       , bgColor = "#000000"-       , fgColor = "#BFBFBF"+       , bgColor = "black"+       , fgColor = "grey"        , xPos = 0        , yPos = 0        , width = 1024        , height = 15        , align = "right"        , refresh = 10-       , commands = [ (Weather "EGPF" ["-t","<station>: <tempC>C"], 36000)-                    , (Network "eth0" [], 10)-                    , (Network "eth1" [], 10)-                    , (Cpu [], 10)-                    , (Exec "date" ["+\"%a %b %_d %H:%M\""] "mydate", 600)-                    , (Exec "date" ["+%Y"] "year", 304128000)-                    , (Memory ["-t","Mem: <usedratio>%"], 10)-                    , (Swap [], 10)-                    , (Exec "uname" ["-s","-r"] "", 36000)+       , commands = [ Run Weather "EGPF" ["-t","<station>: <tempC>C","-L","18","-H","25","--normal","green","--high","red","--low","lightblue"] 36000+                    , Run Network "eth0" ["-L","0","-H","32","--normal","green","--high","red"] 10+                    , Run Network "eth1" ["-L","0","-H","32","--normal","green","--high","red"] 10+                    , Run Cpu ["-L","3","-H","50","--normal","green","--high","red"] 10+                    , Run Com "date" ["+\"%a %b %_d %H:%M\""] "mydate" 600+                    , Run Com "date" ["+%Y"] "year" 304128000+                    , Run Memory ["-t","Mem: <usedratio>%"] 10+                    , Run Swap [] 10+                    , Run Com "uname" ["-s","-r"] "" 36000                     ]        , sepChar = "%"        , template = "%cpu% | %memory% * %swap% | %eth0% - %eth1% | %EGPF% | <fc=#ee9a00>%mydate% of %year%</fc> %uname%"