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 +32/−0
- changelog.md +9/−0
- readme.md +9/−0
- src/Xmobar/Plugins/Monitors/Common/Output.hs +70/−1
- src/Xmobar/Plugins/Monitors/Common/Parsers.hs +36/−0
- src/Xmobar/Plugins/Monitors/Common/Run.hs +26/−6
- src/Xmobar/Plugins/Monitors/Common/Types.hs +72/−1
- src/Xmobar/Plugins/Monitors/Cpu.hs +199/−28
- src/Xmobar/Plugins/Monitors/MultiCoreTemp.hs +42/−26
- test/Xmobar/Plugins/Monitors/CpuSpec.hs +41/−0
- xmobar.cabal +18/−7
+ 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