module Xmobar.Plugins.Monitors.MultiCpu (startMultiCpu) where
import Xmobar.Plugins.Monitors.Common
import qualified Data.ByteString.Lazy.Char8 as B
import Data.List (isPrefixOf, transpose, unfoldr)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import System.Console.GetOpt
data MultiCpuOpts = MultiCpuOpts
{ MultiCpuOpts -> [IconPattern]
loadIconPatterns :: [IconPattern]
, MultiCpuOpts -> Maybe IconPattern
loadIconPattern :: Maybe IconPattern
, MultiCpuOpts -> Maybe IconPattern
fallbackIconPattern :: Maybe IconPattern
, MultiCpuOpts -> Bool
contiguous :: Bool
}
defaultOpts :: MultiCpuOpts
defaultOpts :: MultiCpuOpts
defaultOpts = MultiCpuOpts
{ loadIconPatterns :: [IconPattern]
loadIconPatterns = []
, loadIconPattern :: Maybe IconPattern
loadIconPattern = forall a. Maybe a
Nothing
, fallbackIconPattern :: Maybe IconPattern
fallbackIconPattern = forall a. Maybe a
Nothing
, contiguous :: Bool
contiguous = Bool
False
}
options :: [OptDescr (MultiCpuOpts -> MultiCpuOpts)]
options :: [OptDescr (MultiCpuOpts -> MultiCpuOpts)]
options =
[ forall a. [Char] -> [[Char]] -> ArgDescr a -> [Char] -> OptDescr a
Option [Char]
"" [[Char]
"load-icon-pattern"] (forall a. ([Char] -> a) -> [Char] -> ArgDescr a
ReqArg (\[Char]
x MultiCpuOpts
o ->
MultiCpuOpts
o { loadIconPattern :: Maybe IconPattern
loadIconPattern = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [Char] -> IconPattern
parseIconPattern [Char]
x }) [Char]
"") [Char]
""
, forall a. [Char] -> [[Char]] -> ArgDescr a -> [Char] -> OptDescr a
Option [Char]
"" [[Char]
"load-icon-patterns"] (forall a. ([Char] -> a) -> [Char] -> ArgDescr a
ReqArg (\[Char]
x MultiCpuOpts
o ->
MultiCpuOpts
o { loadIconPatterns :: [IconPattern]
loadIconPatterns = [Char] -> IconPattern
parseIconPattern [Char]
x forall a. a -> [a] -> [a]
: MultiCpuOpts -> [IconPattern]
loadIconPatterns MultiCpuOpts
o }) [Char]
"") [Char]
""
, forall a. [Char] -> [[Char]] -> ArgDescr a -> [Char] -> OptDescr a
Option [Char]
"" [[Char]
"fallback-icon-pattern"] (forall a. ([Char] -> a) -> [Char] -> ArgDescr a
ReqArg (\[Char]
x MultiCpuOpts
o ->
MultiCpuOpts
o { fallbackIconPattern :: Maybe IconPattern
fallbackIconPattern = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [Char] -> IconPattern
parseIconPattern [Char]
x }) [Char]
"") [Char]
""
, forall a. [Char] -> [[Char]] -> ArgDescr a -> [Char] -> OptDescr a
Option [Char]
"" [[Char]
"contiguous-icons"] (forall a. a -> ArgDescr a
NoArg (\MultiCpuOpts
o -> MultiCpuOpts
o {contiguous :: Bool
contiguous = Bool
True})) [Char]
""
]
variables :: [String]
variables :: [[Char]]
variables = [[Char]
"bar", [Char]
"vbar",[Char]
"ipat",[Char]
"total",[Char]
"user",[Char]
"nice",[Char]
"system",[Char]
"idle"]
vNum :: Int
vNum :: Int
vNum = forall (t :: * -> *) a. Foldable t => t a -> Int
length [[Char]]
variables
multiCpuConfig :: IO MConfig
multiCpuConfig :: IO MConfig
multiCpuConfig =
[Char] -> [[Char]] -> IO MConfig
mkMConfig [Char]
"Cpu: <total>%" forall a b. (a -> b) -> a -> b
$
[[Char]
"auto" forall a. [a] -> [a] -> [a]
++ [Char]
k | [Char]
k <- [[Char]]
variables] forall a. [a] -> [a] -> [a]
++
[ [Char]
k forall a. [a] -> [a] -> [a]
++ [Char]
n | [Char]
n <- [Char]
"" forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map forall a. Show a => a -> [Char]
show [Int
0 :: Int ..]
, [Char]
k <- [[Char]]
variables]
type CpuDataRef = IORef [[Int]]
cpuData :: IO [[Int]]
cpuData :: IO [[Int]]
cpuData = ByteString -> [[Int]]
parse forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` [Char] -> IO ByteString
B.readFile [Char]
"/proc/stat"
where parse :: ByteString -> [[Int]]
parse = forall a b. (a -> b) -> [a] -> [b]
map [ByteString] -> [Int]
parseList forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [[ByteString]]
cpuLists
cpuLists :: ByteString -> [[ByteString]]
cpuLists = forall a. (a -> Bool) -> [a] -> [a]
takeWhile [ByteString] -> Bool
isCpu forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ByteString -> [ByteString]
B.words forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
B.lines
isCpu :: [ByteString] -> Bool
isCpu (ByteString
w:[ByteString]
_) = [Char]
"cpu" forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` ByteString -> [Char]
B.unpack ByteString
w
isCpu [ByteString]
_ = Bool
False
parseList :: [ByteString] -> [Int]
parseList = forall a b. (a -> b) -> [a] -> [b]
map ([Char] -> Int
parseInt forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [Char]
B.unpack) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
tail
parseCpuData :: CpuDataRef -> IO [[Float]]
parseCpuData :: CpuDataRef -> IO [[Float]]
parseCpuData CpuDataRef
cref =
do [[Int]]
as <- forall a. IORef a -> IO a
readIORef CpuDataRef
cref
[[Int]]
bs <- IO [[Int]]
cpuData
forall a. IORef a -> a -> IO ()
writeIORef CpuDataRef
cref [[Int]]
bs
let p0 :: [[Float]]
p0 = forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith [Int] -> [Int] -> [Float]
percent [[Int]]
bs [[Int]]
as
forall (m :: * -> *) a. Monad m => a -> m a
return [[Float]]
p0
percent :: [Int] -> [Int] -> [Float]
percent :: [Int] -> [Int] -> [Float]
percent [Int]
b [Int]
a = if Float
tot forall a. Ord a => a -> a -> Bool
> Float
0 then forall a b. (a -> b) -> [a] -> [b]
map (forall a. Fractional a => a -> a -> a
/ Float
tot) forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
take Int
4 [Float]
dif else [Float
0, Float
0, Float
0, Float
0]
where dif :: [Float]
dif = forall a b. (a -> b) -> [a] -> [b]
map forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) [Int]
b [Int]
a
tot :: Float
tot = forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Float]
dif
formatMultiCpus :: MultiCpuOpts -> [[Float]] -> Monitor [String]
formatMultiCpus :: MultiCpuOpts -> [[Float]] -> Monitor [[Char]]
formatMultiCpus MultiCpuOpts
_ [] = forall (m :: * -> *) a. Monad m => a -> m a
return []
formatMultiCpus MultiCpuOpts
opts [[Float]]
xs =
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\(Int
i, [Float]
x) -> MultiCpuOpts -> Int -> [Float] -> Monitor [[Char]]
formatCpu MultiCpuOpts
opts Int
i [Float]
x) (forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] [[Float]]
xs)
formatCpu :: MultiCpuOpts -> Int -> [Float] -> Monitor [String]
formatCpu :: MultiCpuOpts -> Int -> [Float] -> Monitor [[Char]]
formatCpu MultiCpuOpts
opts Int
i [Float]
xs
| forall (t :: * -> *) a. Foldable t => t a -> Int
length [Float]
xs forall a. Ord a => a -> a -> Bool
< Int
4 = [Float] -> Monitor [[Char]]
showPercentsWithColors forall a b. (a -> b) -> a -> b
$ forall a. Int -> a -> [a]
replicate Int
vNum Float
0.0
| Bool
otherwise = let t :: Float
t = forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
take Int
3 [Float]
xs
in do [Char]
b <- Float -> Float -> Monitor [Char]
showPercentBar (Float
100 forall a. Num a => a -> a -> a
* Float
t) Float
t
[Char]
h <- Float -> Float -> Monitor [Char]
showVerticalBar (Float
100 forall a. Num a => a -> a -> a
* Float
t) Float
t
[Char]
d <- Maybe IconPattern -> Float -> Monitor [Char]
showIconPattern Maybe IconPattern
tryString Float
t
[[Char]]
ps <- [Float] -> Monitor [[Char]]
showPercentsWithColors (Float
tforall a. a -> [a] -> [a]
:[Float]
xs)
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char]
bforall a. a -> [a] -> [a]
:[Char]
hforall a. a -> [a] -> [a]
:[Char]
dforall a. a -> [a] -> [a]
:[[Char]]
ps)
where tryString :: Maybe IconPattern
tryString
| Int
i forall a. Eq a => a -> a -> Bool
== Int
0 = MultiCpuOpts -> Maybe IconPattern
loadIconPattern MultiCpuOpts
opts
| Int
i forall a. Ord a => a -> a -> Bool
<= forall (t :: * -> *) a. Foldable t => t a -> Int
length (MultiCpuOpts -> [IconPattern]
loadIconPatterns MultiCpuOpts
opts) =
forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ MultiCpuOpts -> [IconPattern]
loadIconPatterns MultiCpuOpts
opts forall a. [a] -> Int -> a
!! (Int
i forall a. Num a => a -> a -> a
- Int
1)
| Bool
otherwise = MultiCpuOpts -> Maybe IconPattern
fallbackIconPattern MultiCpuOpts
opts
splitEvery :: Int -> [a] -> [[a]]
splitEvery :: forall a. Int -> [a] -> [[a]]
splitEvery Int
n = forall b a. (b -> Maybe (a, b)) -> b -> [a]
unfoldr (\[a]
x -> if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a]
x then forall a. Maybe a
Nothing else forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> ([a], [a])
splitAt Int
n [a]
x)
groupData :: [String] -> [[String]]
groupData :: [[Char]] -> [[[Char]]]
groupData = forall a. [[a]] -> [[a]]
transpose forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> [a]
tail forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> [a] -> [[a]]
splitEvery Int
vNum
formatAutoCpus :: MultiCpuOpts -> [String] -> Monitor [String]
formatAutoCpus :: MultiCpuOpts -> [[Char]] -> Monitor [[Char]]
formatAutoCpus MultiCpuOpts
_ [] = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. Int -> a -> [a]
replicate Int
vNum [Char]
""
formatAutoCpus MultiCpuOpts
opts [[Char]]
xs =
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (if MultiCpuOpts -> Bool
contiguous MultiCpuOpts
opts then forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat else [[Char]] -> [Char]
unwords) ([[Char]] -> [[[Char]]]
groupData [[Char]]
xs)
runMultiCpu :: CpuDataRef -> [String] -> Monitor String
runMultiCpu :: CpuDataRef -> [[Char]] -> Monitor [Char]
runMultiCpu CpuDataRef
cref [[Char]]
argv =
do [[Float]]
c <- forall a. IO a -> Monitor a
io forall a b. (a -> b) -> a -> b
$ CpuDataRef -> IO [[Float]]
parseCpuData CpuDataRef
cref
MultiCpuOpts
opts <- forall a. IO a -> Monitor a
io forall a b. (a -> b) -> a -> b
$ forall opts.
[OptDescr (opts -> opts)] -> opts -> [[Char]] -> IO opts
parseOptsWith [OptDescr (MultiCpuOpts -> MultiCpuOpts)]
options MultiCpuOpts
defaultOpts [[Char]]
argv
[[Char]]
l <- MultiCpuOpts -> [[Float]] -> Monitor [[Char]]
formatMultiCpus MultiCpuOpts
opts [[Float]]
c
[[Char]]
a <- MultiCpuOpts -> [[Char]] -> Monitor [[Char]]
formatAutoCpus MultiCpuOpts
opts [[Char]]
l
[[Char]] -> Monitor [Char]
parseTemplate forall a b. (a -> b) -> a -> b
$ [[Char]]
a forall a. [a] -> [a] -> [a]
++ [[Char]]
l
startMultiCpu :: [String] -> Int -> (String -> IO ()) -> IO ()
startMultiCpu :: [[Char]] -> Int -> ([Char] -> IO ()) -> IO ()
startMultiCpu [[Char]]
a Int
r [Char] -> IO ()
cb = do
CpuDataRef
cref <- forall a. a -> IO (IORef a)
newIORef [[]]
[[Float]]
_ <- CpuDataRef -> IO [[Float]]
parseCpuData CpuDataRef
cref
[[Char]]
-> IO MConfig
-> ([[Char]] -> Monitor [Char])
-> Int
-> ([Char] -> IO ())
-> IO ()
runM [[Char]]
a IO MConfig
multiCpuConfig (CpuDataRef -> [[Char]] -> Monitor [Char]
runMultiCpu CpuDataRef
cref) Int
r [Char] -> IO ()
cb