packages feed

xmobar 0.34 → 0.35

raw patch · 11 files changed

+554/−69 lines, 11 filesdep +gaugedep ~basedep ~mtldep ~timezone-olson

Dependencies added: gauge

Dependency ranges changed: base, mtl, timezone-olson

Files

+ bench/main.hs view
@@ -0,0 +1,32 @@+{-#LANGUAGE RecordWildCards#-}++import Gauge+import Xmobar+import Xmobar.Plugins.Monitors.Common.Types+import Xmobar.Plugins.Monitors.Common.Run+import Xmobar.Plugins.Monitors.Cpu+import Control.Monad.Reader+import Data.IORef (newIORef)++main :: IO ()+main = do+  cpuParams <- mkCpuArgs+  defaultMain $ normalBench cpuParams+    where+      normalBench args = [ bgroup "Cpu Benchmarks" $ normalCpuBench args]++runMonitor :: MConfig -> Monitor a -> IO a+runMonitor config r = runReaderT r config++mkCpuArgs :: IO CpuArguments+mkCpuArgs = getArguments ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>%"]+  +-- | The action which will be benchmarked+cpuAction :: CpuArguments -> IO String+cpuAction = runCpu++cpuBenchmark :: CpuArguments -> Benchmarkable+cpuBenchmark cpuParams = nfIO $ cpuAction cpuParams++normalCpuBench :: CpuArguments -> [Benchmark]+normalCpuBench args = [bench "CPU normal args" (cpuBenchmark args)]
changelog.md view
@@ -1,3 +1,12 @@+## Version 0.35 (June, 2020)++_New features_++  - `MultiCoreTemp` now works with Ryzen processors.  New option+    `--hwmonitor-path` for better performance.+  - CPU Monitor optimizations.+  - Version bumps for some dependencies, including timezone-olson.+ ## Version 0.34 (June, 2020)  _New features_
readme.md view
@@ -1135,6 +1135,15 @@     limit for percentage calculation.   - `--maxtemp`: temperature in degree Celsius, that sets the upper     limit for percentage calculation.+  - `--hwmonitor-path`: this monitor tries to find coretemp devices by+    looking for them in directories following the pattern+    `/sys/bus/platform/devices/coretemp.*/hwmon/hwmon*`, but some+    processors (notably Ryzen) might expose those files in a different+    tree (e.g., Ryzen) puts them somewhere in+    "/sys/class/hwmon/hwmon*", and the lookup is most costly.  With+    this option, it is possible to explicitly specify the full path to+    the directory where the `tempN_label` and `tempN_input` files are+    located. - Thresholds refer to temperature in degree Celsius - Variables that can be used with the `-t`/`--template` argument:             `max`, `maxpc`, `maxbar`, `maxvbar`, `maxipat`,
src/Xmobar/Plugins/Monitors/Common/Output.hs view
@@ -1,3 +1,5 @@+{-#LANGUAGE RecordWildCards#-}+ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Plugins.Monitors.Strings@@ -37,6 +39,11 @@                                              , parseFloat                                              , parseInt                                              , stringParser+                                             , pShowPercentsWithColors+                                             , pShowPercentBar+                                             , pShowVerticalBar+                                             , pShowIconPattern+                                             , pShowPercentWithColors                                              ) where  import Data.Char@@ -44,11 +51,64 @@ import qualified Data.ByteString.Lazy.Char8 as B import Numeric import Control.Monad (zipWithM)-+import Control.Monad.IO.Class (MonadIO(..)) import Xmobar.Plugins.Monitors.Common.Types  type IconPattern = Int -> String +pShowVerticalBar :: (MonadIO m) => MonitorConfig -> Float -> Float -> m String+pShowVerticalBar p v x = pColorizeString p v [convert $ 100 * x]+  where convert :: Float -> Char+        convert val+          | t <= 9600 = ' '+          | t > 9608 = chr 9608+          | otherwise = chr t+          where t = 9600 + (round val `div` 12)++pShowPercentsWithColors :: (MonadIO m) => MonitorConfig -> [Float] -> m [String]+pShowPercentsWithColors p fs =+  do let fstrs = map (pFloatToPercent p) fs+         temp = map (*100) fs+     zipWithM (pShowWithColors p . const) fstrs temp++pShowPercentWithColors :: (MonadIO m) => MonitorConfig -> Float -> m String+pShowPercentWithColors p f = fmap head $ pShowPercentsWithColors p [f]++pShowPercentBar :: (MonadIO m) => MonitorConfig -> Float -> Float -> m String+pShowPercentBar p@MonitorConfig{..} v x = do+  let len = min pBarWidth $ round (fromIntegral pBarWidth * x)+  s <- pColorizeString p v (take len $ cycle pBarFore)+  return $ s ++ take (pBarWidth - len) (cycle pBarBack)++pShowWithColors :: (Num a, Ord a, MonadIO m) => MonitorConfig -> (a -> String) -> a -> m String+pShowWithColors p f x = do+  let str = pShowWithPadding p (f x)+  pColorizeString p x str++pColorizeString :: (Num a, Ord a, MonadIO m) => MonitorConfig -> a -> String -> m String+pColorizeString p x s = do+    let col = pSetColor p s+        [ll,hh] = map fromIntegral $ sort [pLow p, pHigh p] -- consider high < low+    pure $ head $ [col pHighColor   | x > hh ] +++                  [col pNormalColor | x > ll ] +++                  [col pLowColor    | True]++pSetColor :: MonitorConfig -> String -> PSelector (Maybe String) -> String+pSetColor config str s =+    do let a = getPConfigValue config s+       case a of+            Nothing -> str+            Just c -> "<fc=" ++ c ++ ">" ++ str ++ "</fc>"++pShowWithPadding :: MonitorConfig -> String -> String+pShowWithPadding MonitorConfig {..} =+  padString pMinWidth pMaxWidth pPadChars pPadRight pMaxWidthEllipsis++pFloatToPercent :: MonitorConfig -> Float -> String+pFloatToPercent MonitorConfig{..} n = let p = showDigits 0 (n * 100)+                                          ps = if pUseSuffix then "%" else ""+                                      in padString pPpad pPpad pPadChars pPadRight "" p ++ ps+ parseIconPattern :: String -> IconPattern parseIconPattern path =     let spl = splitOnPercent path@@ -168,6 +228,15 @@ showIconPattern :: Maybe IconPattern -> Float -> Monitor String showIconPattern Nothing _ = return "" showIconPattern (Just str) x = return $ str $ convert $ 100 * x+  where convert val+          | t <= 0 = 0+          | t > 8 = 8+          | otherwise = t+          where t = round val `div` 12++pShowIconPattern :: Maybe IconPattern -> Float -> IO String+pShowIconPattern Nothing _ = return ""+pShowIconPattern (Just str) x = return $ str $ convert $ 100 * x   where convert val           | t <= 0 = 0           | t > 8 = 8
src/Xmobar/Plugins/Monitors/Common/Parsers.hs view
@@ -1,3 +1,6 @@+{-#LANGUAGE RecordWildCards#-}+{-#LANGUAGE ScopedTypeVariables#-}+ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Plugins.Monitors.Parsers@@ -25,6 +28,10 @@                                               , parseTemplate                                               , parseTemplate'                                               , parseOptsWith+                                              , templateParser+                                              , runExportParser+                                              , runTemplateParser+                                              , pureParseTemplate                                               ) where  import Xmobar.Plugins.Monitors.Common.Types@@ -33,6 +40,35 @@ import qualified Data.Map as Map import System.Console.GetOpt (ArgOrder(Permute), OptDescr, getOpt) import Text.ParserCombinators.Parsec++runTemplateParser :: MonitorConfig -> IO [(String, String, String)]+runTemplateParser MonitorConfig{..} = runP templateParser pTemplate++runExportParser :: [String] -> IO [(String, [(String, String,String)])]+runExportParser [] = pure []+runExportParser (x:xs) = do+  s <- runP templateParser x+  rest <- runExportParser xs+  pure $ (x,s):rest++pureParseTemplate :: MonitorConfig -> TemplateInput -> IO String+pureParseTemplate MonitorConfig{..} TemplateInput{..} =+    do let m = let expSnds :: [([(String, String, String)], String)]  = zip (map snd temAllTemplate) temMonitorValues+               in Map.fromList $ zip (map fst temAllTemplate) expSnds+       s <- minCombine m temInputTemplate+       let (n, s') = if pMaxTotalWidth > 0 && length s > pMaxTotalWidth+                     then trimTo (pMaxTotalWidth - length pMaxTotalWidthEllipsis) "" s+                     else (1, s)+       return $ if n > 0 then s' else s' ++ pMaxTotalWidthEllipsis++minCombine :: Map.Map String ([(String, String, String)], String) -> [(String, String, String)] -> IO String+minCombine _ [] = return []+minCombine m ((s,ts,ss):xs) =+    do next <- minCombine m xs+       str <- case Map.lookup ts m of+         Nothing -> return $ "<" ++ ts ++ ">"+         Just (s',r) -> let f "" = r; f n = n; in f <$> minCombine m s'+       pure $ s ++ str ++ ss ++ next  runP :: Parser [a] -> String -> IO [a] runP p i =
src/Xmobar/Plugins/Monitors/Common/Run.hs view
@@ -22,6 +22,9 @@                                           , runML                                           , runMLD                                           , getArgvs+                                          , doArgs+                                          , computeMonitorConfig+                                          , pluginOptions                                           ) where  import Control.Exception (SomeException,handle)@@ -32,11 +35,11 @@ import Xmobar.Plugins.Monitors.Common.Types import Xmobar.Run.Exec (doEveryTenthSeconds) -options :: [OptDescr Opts]-options =+pluginOptions :: [OptDescr Opts]+pluginOptions =     [-      Option "H" ["High"] (ReqArg High "number") "The high threshold"-    , Option "L" ["Low"] (ReqArg Low "number") "The low threshold"+      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\""@@ -61,16 +64,18 @@ -- | Get all argument values out of a list of arguments. getArgvs :: [String] -> [String] getArgvs args =-    case getOpt Permute options args of+    case getOpt Permute pluginOptions args of         (_, n, []  ) -> n         (_, _, errs) -> errs ++ doArgs :: [String]        -> ([String] -> Monitor String)        -> ([String] -> Monitor Bool)        -> Monitor String doArgs args action detect =-    case getOpt Permute options args of+    case getOpt Permute pluginOptions args of       (o, n, [])   -> do doConfigOptions o                          ready <- detect n                          if ready@@ -139,3 +144,18 @@  showException :: SomeException -> String showException = ("error: "++) . show . flip asTypeOf undefined++computeMonitorConfig :: [String] -> IO MConfig -> IO MonitorConfig+computeMonitorConfig args mconfig = do+  newConfig <- getMConfig args mconfig+  getMonitorConfig newConfig++getMConfig :: [String] -> IO MConfig -> IO MConfig+getMConfig args mconfig = do+  config <- mconfig+  runReaderT (updateOptions args >> ask) config++updateOptions :: [String] -> Monitor ()+updateOptions args= case getOpt Permute pluginOptions args of+                      (o, _, []) -> doConfigOptions o+                      _ -> return ()
src/Xmobar/Plugins/Monitors/Common/Types.hs view
@@ -1,3 +1,5 @@+{-#LANGUAGE RecordWildCards#-}+ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Plugins.Monitors.Types@@ -20,9 +22,14 @@                                             , Opts (..)                                             , Selector                                             , setConfigValue-                                            , getConfigValue                                             , mkMConfig                                             , io+                                            , MonitorConfig (..)+                                            , getPConfigValue+                                            , getConfigValue+                                            , getMonitorConfig+                                            , PSelector+                                            , TemplateInput(..)                                             ) where  import Control.Monad.Reader (ReaderT, ask, liftIO)@@ -34,6 +41,12 @@ io :: IO a -> Monitor a io = liftIO +data TemplateInput = TemplateInput {+      temMonitorValues :: [String],+      temInputTemplate :: [(String, String, String)],+      temAllTemplate :: [(String, [(String, String, String)])]+    }+ data MConfig =     MC { normalColor :: IORef (Maybe String)        , low :: IORef Int@@ -58,9 +71,64 @@        , maxTotalWidthEllipsis :: IORef String        } +data MonitorConfig =+  MonitorConfig+    { pNormalColor :: Maybe String+    , pLow :: Int+    , pLowColor :: Maybe String+    , pHigh :: Int+    , pHighColor :: Maybe String+    , pTemplate :: String+    , pExport :: [String]+    , pPpad :: Int+    , pDecDigits :: Int+    , pMinWidth :: Int+    , pMaxWidth :: Int+    , pMaxWidthEllipsis :: String+    , pPadChars :: String+    , pPadRight :: Bool+    , pBarBack :: String+    , pBarFore :: String+    , pBarWidth :: Int+    , pUseSuffix :: Bool+    , pNaString :: String+    , pMaxTotalWidth :: Int+    , pMaxTotalWidthEllipsis :: String+    }+  deriving (Eq, Ord)++getMonitorConfig :: MConfig -> IO MonitorConfig+getMonitorConfig MC{..} = do+  pNormalColor <- readIORef normalColor+  pLow <- readIORef low+  pLowColor <- readIORef lowColor+  pHigh <- readIORef high+  pHighColor <- readIORef highColor+  pTemplate <- readIORef template+  pExport <- readIORef export+  pPpad <- readIORef ppad+  pDecDigits <- readIORef decDigits+  pMinWidth <- readIORef minWidth+  pMaxWidth <- readIORef maxWidth+  pMaxWidthEllipsis <- readIORef maxWidthEllipsis+  pPadChars <- readIORef padChars+  pPadRight <- readIORef padRight+  pBarBack <- readIORef barBack+  pBarFore <- readIORef barFore+  pBarWidth <- readIORef barWidth+  pUseSuffix <- readIORef useSuffix +  pNaString <- readIORef naString+  pMaxTotalWidth <- readIORef maxTotalWidth+  pMaxTotalWidthEllipsis <- readIORef maxTotalWidthEllipsis+  pure $ MonitorConfig {..}+ -- | from 'http:\/\/www.haskell.org\/hawiki\/MonadState' type Selector a = MConfig -> IORef a+type PSelector a = MonitorConfig -> a +psel :: MonitorConfig -> PSelector a -> a+psel value accessor = accessor value+ sel :: Selector a -> Monitor a sel s =     do hs <- ask@@ -77,6 +145,9 @@  getConfigValue :: Selector a -> Monitor a getConfigValue = sel++getPConfigValue :: MonitorConfig -> PSelector a -> a+getPConfigValue = psel  mkMConfig :: String           -> [String]
src/Xmobar/Plugins/Monitors/Cpu.hs view
@@ -1,3 +1,5 @@+{-#LANGUAGE RecordWildCards#-}+ ----------------------------------------------------------------------------- -- | -- Module      :  Plugins.Monitors.Cpu@@ -13,12 +15,23 @@ -- ----------------------------------------------------------------------------- -module Xmobar.Plugins.Monitors.Cpu (startCpu) where+module Xmobar.Plugins.Monitors.Cpu+  ( startCpu+  , runCpu+  , cpuConfig+  , CpuDataRef+  , CpuOpts+  , CpuArguments+  , parseCpu+  , getArguments+  ) where  import Xmobar.Plugins.Monitors.Common import qualified Data.ByteString.Lazy.Char8 as B import Data.IORef (IORef, newIORef, readIORef, writeIORef) import System.Console.GetOpt+import Xmobar.App.Timer (doEveryTenthSeconds)+import Control.Monad (void)  newtype CpuOpts = CpuOpts   { loadIconPattern :: Maybe IconPattern@@ -35,48 +48,206 @@      o { loadIconPattern = Just $ parseIconPattern x }) "") ""   ] +barField :: String+barField = "bar"++vbarField :: String+vbarField = "vbar"++ipatField :: String+ipatField = "ipat"++totalField :: String+totalField = "total"++userField :: String+userField = "user"++niceField :: String+niceField = "nice"++systemField :: String+systemField = "system"++idleField :: String+idleField = "idle"++iowaitField :: String+iowaitField = "iowait"+ cpuConfig :: IO MConfig-cpuConfig = mkMConfig-       "Cpu: <total>%"-       ["bar","vbar","ipat","total","user","nice","system","idle","iowait"]+cpuConfig =+  mkMConfig+    "Cpu: <total>%"+    [ barField+    , vbarField+    , ipatField+    , totalField+    , userField+    , niceField+    , systemField+    , idleField+    , iowaitField+    ]  type CpuDataRef = IORef [Int] +-- Details about the fields here: https://www.kernel.org/doc/Documentation/filesystems/proc.txt cpuData :: IO [Int]-cpuData = cpuParser `fmap` B.readFile "/proc/stat"+cpuData = cpuParser <$> B.readFile "/proc/stat" +readInt :: B.ByteString -> Int+readInt bs = case B.readInt bs of+               Nothing -> 0+               Just (i, _) -> i+ cpuParser :: B.ByteString -> [Int]-cpuParser = map (read . B.unpack) . tail . B.words . head . B.lines+cpuParser = map readInt . tail . B.words . head . B.lines -parseCpu :: CpuDataRef -> IO [Float]+data CpuData = CpuData {+      cpuUser :: !Float,+      cpuNice :: !Float,+      cpuSystem :: !Float,+      cpuIdle :: !Float,+      cpuIowait :: !Float,+      cpuTotal :: !Float+    }++convertToCpuData :: [Float] -> CpuData+convertToCpuData (u:n:s:ie:iw:_) =+  CpuData+    { cpuUser = u+    , cpuNice = n+    , cpuSystem = s+    , cpuIdle = ie+    , cpuIowait = iw+    , cpuTotal = sum [u, n, s]+    }+convertToCpuData args = error $ "convertToCpuData: Unexpected list" <> show args++parseCpu :: CpuDataRef -> IO CpuData parseCpu cref =     do a <- readIORef cref        b <- cpuData        writeIORef cref b        let dif = zipWith (-) b a            tot = fromIntegral $ sum dif-           percent = map ((/ tot) . fromIntegral) dif-       return percent+           safeDiv n = case tot of+                         0 -> 0+                         v -> fromIntegral n / v+           percent = map safeDiv dif+       return $ convertToCpuData percent -formatCpu :: CpuOpts -> [Float] -> Monitor [String]-formatCpu _ [] = return $ replicate 8 ""-formatCpu opts xs = do-  let t = sum $ take 3 xs-  b <- showPercentBar (100 * t) t-  v <- showVerticalBar (100 * t) t-  d <- showIconPattern (loadIconPattern opts) t-  ps <- showPercentsWithColors (t:xs)-  return (b:v:d:ps)+data Field = Field {+      fieldName :: !String,+      fieldCompute :: !ShouldCompute+    } deriving (Eq, Ord, Show) -runCpu :: CpuDataRef -> [String] -> Monitor String-runCpu cref argv =-    do c <- io (parseCpu cref)-       opts <- io $ parseOptsWith options defaultOpts argv-       l <- formatCpu opts c-       parseTemplate l+data ShouldCompute = Compute | Skip deriving (Eq, Ord, Show) +formatField :: MonitorConfig -> CpuOpts -> CpuData -> Field -> IO String+formatField cpuParams cpuOpts cpuInfo@CpuData {..} Field {..}+  | fieldName == barField =+    if fieldCompute == Compute+      then pShowPercentBar cpuParams (100 * cpuTotal) cpuTotal+      else pure []+  | fieldName == vbarField =+    if fieldCompute == Compute+      then pShowVerticalBar cpuParams (100 * cpuTotal) cpuTotal+      else pure []+  | fieldName == ipatField =+    if fieldCompute == Compute+      then pShowIconPattern (loadIconPattern cpuOpts) cpuTotal+      else pure []+  | otherwise =+    if fieldCompute == Compute+      then pShowPercentWithColors cpuParams (getFieldValue fieldName cpuInfo)+      else pure []++getFieldValue :: String -> CpuData -> Float+getFieldValue field CpuData{..}+    | field == barField = cpuTotal+    | field == vbarField = cpuTotal+    | field == ipatField = cpuTotal+    | field == totalField = cpuTotal+    | field == userField = cpuUser+    | field == niceField = cpuNice+    | field == systemField = cpuSystem+    | field == idleField = cpuIdle+    | otherwise = cpuIowait++computeFields :: [String] -> [String] -> [Field]+computeFields [] _ = []+computeFields (x:xs) inputFields =+  if x `elem` inputFields+    then (Field {fieldName = x, fieldCompute = Compute}) :+         computeFields xs inputFields+    else (Field {fieldName = x, fieldCompute = Skip}) :+         computeFields xs inputFields++formatCpu :: CpuArguments -> CpuData -> IO [String]+formatCpu CpuArguments{..} cpuInfo = do+  strs <- mapM (formatField cpuParams cpuOpts cpuInfo) cpuFields+  pure $ filter (not . null) strs++getInputFields :: CpuArguments -> [String]+getInputFields CpuArguments{..} = map (\(_,f,_) -> f) cpuInputTemplate++optimizeAllTemplate :: CpuArguments -> CpuArguments+optimizeAllTemplate args@CpuArguments {..} =+  let inputFields = getInputFields args+      allTemplates =+        filter (\(field, _) -> field `elem` inputFields) cpuAllTemplate+   in args {cpuAllTemplate = allTemplates}++data CpuArguments =+  CpuArguments+    { cpuDataRef :: !CpuDataRef+    , cpuParams :: !MonitorConfig+    , cpuArgs :: ![String]+    , cpuOpts :: !CpuOpts+    , cpuInputTemplate :: ![(String, String, String)] -- [("Cpu: ","total","% "),("","user","%")]+    , cpuAllTemplate :: ![(String, [(String, String, String)])] -- [("bar",[]),("vbar",[]),("ipat",[]),("total",[]),...]+    , cpuFields :: ![Field]+    }+++getArguments :: [String] -> IO CpuArguments+getArguments cpuArgs = do+  initCpuData <- cpuData+  cpuDataRef <- newIORef initCpuData+  void $ parseCpu cpuDataRef+  cpuParams <- computeMonitorConfig cpuArgs cpuConfig+  cpuInputTemplate <- runTemplateParser cpuParams+  cpuAllTemplate <- runExportParser (pExport cpuParams)+  nonOptions <-+    case getOpt Permute pluginOptions cpuArgs of+      (_, n, []) -> pure n+      (_, _, errs) -> error $ "getArguments: " <> show errs+  cpuOpts <-+    case getOpt Permute options nonOptions of+      (o, _, []) -> pure $ foldr id defaultOpts o+      (_, _, errs) -> error $ "getArguments options: " <> show errs+  let cpuFields =+        computeFields+          (map fst cpuAllTemplate)+          (map (\(_, f, _) -> f) cpuInputTemplate)+  pure $ optimizeAllTemplate CpuArguments {..}+++runCpu :: CpuArguments -> IO String+runCpu args@CpuArguments {..} = do+  cpuValue <- parseCpu cpuDataRef+  temMonitorValues <- formatCpu args cpuValue+  let templateInput =+        TemplateInput+          { temInputTemplate = cpuInputTemplate+          , temAllTemplate = cpuAllTemplate+          , ..+          }+  pureParseTemplate cpuParams templateInput+ startCpu :: [String] -> Int -> (String -> IO ()) -> IO ()-startCpu a r cb = do-  cref <- newIORef []-  _ <- parseCpu cref-  runM a cpuConfig (runCpu cref) r cb+startCpu args refreshRate cb = do+  cpuArgs <- getArguments args+  doEveryTenthSeconds refreshRate (runCpu cpuArgs >>= cb)
src/Xmobar/Plugins/Monitors/MultiCoreTemp.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module      :  Plugins.Monitors.MultiCoreTemp--- Copyright   :  (c) 2019 Felix Springer+-- Copyright   :  (c) 2019, 2020 Felix Springer -- License     :  BSD-style (see LICENSE) -- -- Maintainer  :  Felix Springer <felixspringer149@gmail.com>@@ -26,6 +26,7 @@                      , avgIconPattern :: Maybe IconPattern                      , mintemp :: Float                      , maxtemp :: Float+                     , hwMonitorPath :: Maybe String                      }  -- | Set default Options.@@ -34,6 +35,7 @@                      , avgIconPattern = Nothing                      , mintemp = 0                      , maxtemp = 100+                     , hwMonitorPath = Nothing                      }  -- | Apply configured Options.@@ -58,6 +60,11 @@                 (\ arg opts -> opts { maxtemp = read arg })                 "")               ""+          , Option [] ["hwmon-path"]+              (ReqArg+                (\ arg opts -> opts { hwMonitorPath = Just arg })+                "")+              ""           ]  -- | Generate Config with a default template and options.@@ -68,41 +75,50 @@                     , "avg" , "avgpc" , "avgbar" , "avgvbar" , "avgipat"                     ] ++ map (("core" ++) . show) [0 :: Int ..] + -- | Returns the first coretemp.N path found.-coretempPath :: IO String+coretempPath :: IO (Maybe String) coretempPath = do xs <- filterM doesDirectoryExist ps-                  let x = head xs-                  return x-  where ps = [ "/sys/bus/platform/devices/coretemp." ++ show (x :: Int) ++ "/" | x <- [0..9] ]+                  return (if null xs then Nothing else Just $ head xs)+  where ps = [ "/sys/bus/platform/devices/coretemp." ++ show (x :: Int) ++ "/"+             | x <- [0..9] ] --- | Returns the first hwmonN path found.-hwmonPath :: IO String-hwmonPath = do p <- coretempPath-               xs <- filterM doesDirectoryExist [ p ++ "hwmon/hwmon" ++ show (x :: Int) ++ "/" | x <- [0..9] ]-               let x = head xs-               return x+-- | Returns the first hwmonN in coretemp path found or the ones in sys/class.+hwmonPaths :: IO [String]+hwmonPaths = do p <- coretempPath+                let (sc, path) = case p of+                                   Just s -> (False, s)+                                   Nothing -> (True, "/sys/class/")+                let cps  = [ path ++ "hwmon/hwmon" ++ show (x :: Int) ++ "/"+                           | x <- [0..9] ]+                ecps <- filterM doesDirectoryExist cps+                return $ if sc || null ecps then ecps else [head ecps]  -- | Checks Labels, if they refer to a core and returns Strings of core- -- temperatures.-corePaths :: IO [String]-corePaths = do p <- hwmonPath-               ls <- filterM doesFileExist [ p ++ "temp" ++ show (x :: Int) ++ "_label" | x <- [0..9] ]-               cls <- filterM isLabelFromCore ls-               return $ map labelToCore cls+corePaths :: Maybe String -> IO [String]+corePaths s = do ps <- case s of+                        Just pth -> return [pth]+                        _ -> hwmonPaths+                 let cps = [p ++ "temp" ++ show (x :: Int) ++ "_label"+                           | x <- [0..9], p <- ps ]+                 ls <- filterM doesFileExist cps+                 cls <- filterM isLabelFromCore ls+                 return $ map labelToCore cls  -- | Checks if Label refers to a core. isLabelFromCore :: FilePath -> IO Bool isLabelFromCore p = do a <- readFile p-                       return $ take 4 a == "Core"+                       return $ take 4 a `elem` ["Core", "Tdie", "Tctl"]  -- | Transform a path to Label to a path to core-temperature. labelToCore :: FilePath -> FilePath labelToCore = (++ "input") . reverse . drop 5 . reverse  -- | Reads core-temperatures as data from the system.-cTData :: IO [Float]-cTData = do fps <- corePaths-            traverse readSingleFile fps+cTData :: Maybe String -> IO [Float]+cTData p = do fps <- corePaths p+              traverse readSingleFile fps   where readSingleFile :: FilePath -> IO Float         readSingleFile s = do a <- readFile s                               return $ parseContent a@@ -110,10 +126,10 @@                 parseContent = read . head . lines  -- | Transforms data of temperatures into temperatures of degree Celsius.-parseCT :: IO [Float]-parseCT = do rawCTs <- cTData-             let normalizedCTs = map (/ 1000) rawCTs :: [Float]-             return normalizedCTs+parseCT :: CTOpts -> IO [Float]+parseCT opts = do rawCTs <- cTData (hwMonitorPath opts)+                  let normalizedCTs = map (/ 1000) rawCTs :: [Float]+                  return normalizedCTs  -- | Performs calculation for maximum and average. -- Sets up Bars and Values to be printed.@@ -150,8 +166,8 @@   runCT :: [String] -> Monitor String-runCT argv = do cTs <- io parseCT-                opts <- io $ parseOptsWith options defaultOpts argv+runCT argv = do opts <- io $ parseOptsWith options defaultOpts argv+                cTs <- io $ parseCT opts                 l <- formatCT opts cTs                 parseTemplate l 
+ test/Xmobar/Plugins/Monitors/CpuSpec.hs view
@@ -0,0 +1,41 @@+module Xmobar.Plugins.Monitors.CpuSpec+  ( +   spec, main+  ) where++import Test.Hspec+import Xmobar.Plugins.Monitors.Common+import Xmobar.Plugins.Monitors.Cpu+import Data.List++main :: IO ()+main = hspec spec++spec :: Spec+spec =+  describe "CPU Spec" $ do+    it "works with total template" $+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>%"]+         cpuArgs <- getArguments args+         cpuValue <- runCpu cpuArgs+         cpuValue `shouldSatisfy` (\item -> "Cpu:" `isPrefixOf` item)+    it "works with bar template" $+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>% <bar>"]+         cpuArgs <- getArguments args+         cpuValue <- runCpu cpuArgs+         cpuValue `shouldSatisfy` (\item -> "::" `isSuffixOf` item)+    it "works with no icon pattern template" $+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>% <bar>", "--", "--load-icon-pattern", "<icon=bright_%%.xpm/>"]+         cpuArgs <- getArguments args+         cpuValue <- runCpu cpuArgs+         cpuValue `shouldSatisfy` (\item -> not $ "<icon=bright_" `isInfixOf` cpuValue)+    it "works with icon pattern template" $+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>% <bar> <ipat>", "--", "--load-icon-pattern", "<icon=bright_%%.xpm/>"]+         cpuArgs <- getArguments args+         cpuValue <- runCpu cpuArgs+         cpuValue `shouldSatisfy` (\item -> "<icon=bright_" `isInfixOf` cpuValue)+    it "works with other parameters in template" $+      do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <user> <nice> <iowait>"]+         cpuArgs <- getArguments args+         cpuValue <- runCpu cpuArgs+         cpuValue `shouldSatisfy` (\item -> "Cpu:" `isPrefixOf` cpuValue)
xmobar.cabal view
@@ -1,5 +1,5 @@ name:               xmobar-version:            0.34+version:            0.35 homepage:           http://xmobar.org synopsis:           A Minimalistic Text Based Status Bar description: 	    Xmobar is a minimalistic text based status bar.@@ -95,7 +95,10 @@     default-language: Haskell2010     hs-source-dirs:  src -    exposed-modules: Xmobar+    exposed-modules: Xmobar,+                     Xmobar.Plugins.Monitors.Common.Types,+                     Xmobar.Plugins.Monitors.Common.Run,+                     Xmobar.Plugins.Monitors.Cpu      other-modules: Paths_xmobar,                    Xmobar.Config.Types,@@ -140,14 +143,11 @@                    Xmobar.Plugins.Monitors,                    Xmobar.Plugins.Monitors.Batt,                    Xmobar.Plugins.Monitors.Common,-                   Xmobar.Plugins.Monitors.Common.Types,-                   Xmobar.Plugins.Monitors.Common.Run,                    Xmobar.Plugins.Monitors.Common.Output,                    Xmobar.Plugins.Monitors.Common.Parsers,                    Xmobar.Plugins.Monitors.Common.Files,                    Xmobar.Plugins.Monitors.CoreTemp,                    Xmobar.Plugins.Monitors.CpuFreq,-                   Xmobar.Plugins.Monitors.Cpu,                    Xmobar.Plugins.Monitors.Disk,                    Xmobar.Plugins.Monitors.Mem,                    Xmobar.Plugins.Monitors.MultiCoreTemp,@@ -242,7 +242,7 @@        cpp-options: -DALSA      if flag(with_datezone) || flag(all_extensions)-       build-depends: timezone-olson == 0.1.*, timezone-series == 0.1.*+       build-depends: timezone-olson >= 0.1 && < 0.3, timezone-series == 0.1.*        other-modules: Xmobar.Plugins.DateZone        cpp-options: -DDATEZONE @@ -331,10 +331,11 @@   other-modules: Xmobar.Plugins.Monitors.CommonSpec                  Xmobar.Plugins.Monitors.Common                  Xmobar.Plugins.Monitors.Common.Parsers-                 Xmobar.Plugins.Monitors.Common.Run                  Xmobar.Plugins.Monitors.Common.Types                  Xmobar.Plugins.Monitors.Common.Output                  Xmobar.Plugins.Monitors.Common.Files+                 Xmobar.Plugins.Monitors.Cpu+                 Xmobar.Plugins.Monitors.Common.Run                  Xmobar.Run.Exec                  Xmobar.App.Timer                  Xmobar.System.Signal@@ -346,5 +347,15 @@       other-modules: Xmobar.Plugins.Monitors.Volume                      Xmobar.Plugins.Monitors.Alsa                      Xmobar.Plugins.Monitors.AlsaSpec+                     Xmobar.Plugins.Monitors.CpuSpec        cpp-options: -DALSA++benchmark xmobarbench+  type: exitcode-stdio-1.0+  main-is: main.hs+  hs-source-dirs:+      bench+  ghc-options: -O2+  build-depends: base, gauge, xmobar, mtl+  default-language: Haskell2010