xmobar 0.31 → 0.32
raw patch · 14 files changed
+392/−140 lines, 14 filesdep ~base
Dependency ranges changed: base
Files
- changelog.md +27/−1
- readme.md +95/−37
- src/Xmobar/App/Config.hs +22/−19
- src/Xmobar/App/Main.hs +4/−5
- src/Xmobar/Plugins/DateZone.hs +5/−1
- src/Xmobar/Plugins/Kbd.hs +1/−1
- src/Xmobar/Plugins/Mail.hs +45/−9
- src/Xmobar/Plugins/Monitors/Batt.hs +53/−10
- src/Xmobar/Plugins/Monitors/Common/Output.hs +2/−1
- src/Xmobar/Plugins/Monitors/Disk.hs +13/−6
- src/Xmobar/Plugins/Monitors/MPD.hs +14/−4
- src/Xmobar/Plugins/Monitors/Net.hs +50/−35
- src/Xmobar/Plugins/Monitors/Volume.hs +59/−9
- xmobar.cabal +2/−2
changelog.md view
@@ -1,4 +1,30 @@-## Version 0.31+## Version 0.32++_New features_++ - New options `--host` and `--port` for `MPD` monitor.+ - New plugin `MailX` extending `Mail` with colors and prefix/suffix.+ - New options `--lows`, `--mediums`, and `--highs` for `Battery`+ to display an additional string depending on battery level (thanks+ to *slotThe*).+ - New options `-L` and `-H` for `Volume` to set low and high volume+ levels, as well as `-l`, `-m`, and `-h` to display an additional+ string depending on current volume level (thanks to *slotThe*).+ - New option `-P` in `Battery` to add a `%` symbol to `<left>`.+ - New option `--devices` in `DynNetwork` to select what interfaces+ to monitor (thanks to *vindex10*).+ - DateZone plugin now also checks TZDIR (thanks to Emmanuel Rosa).++_Bug fixes_++ - `Kbd` plugin: ignore "terminate" layout token (thanks to Greg+ Steuck).+ - Fixed compilation with GHC 8.8.x (thanks to Vanessa McHale).+ - Avoid creating `~/.xmobar` ([issue #405]).++[issue #405]: https://github.com/jaor/xmobar/issues/405++## Version 0.31 (October, 2019) _New features_
readme.md view
@@ -198,11 +198,11 @@ managers to feed xmobar strings with `<action>` tags mixed with un-trusted content (e.g. window titles). For example, if xmobar is invoked as - ```xmobar -c "[Run UnsafeStdinReader]" -t "%UnsafeStdinReader%"```+ xmobar -c "[Run UnsafeStdinReader]" -t "%UnsafeStdinReader%" and receives on standard input the line - ```<action=`echo test` button=1><raw=41:<action=`echo mooo` button=1>foo</action>/></action>```+ <action=`echo test` button=1><raw=41:<action=`echo mooo` button=1>foo</action>/></action>` then it will display the text ```<action=`echo mooo` button=1>foo</action>```, which, when clicked, will cause `test` to be echoed.@@ -799,13 +799,15 @@ - Thresholds are expressed in Kb/s - Args: default monitor arguments, plus: - `--rx-icon-pattern`: dynamic string for reception rate in `rxipat`.- - `--tx-icon-pattern`: dynamic string for transmission rate in `txipat`.+ - `--tx-icon-pattern`: dynamic string for transmission rate in `txipat`+ - `--devices`: comma-separated list of devices to show. - Variables that can be used with the `-t`/`--template` argument: `dev`, `rx`, `tx`, `rxbar`, `rxvbar`, `rxipat`, `txbar`, `txvbar`, `txipat`. Reception and transmission rates (`rx` and `tx`) are displayed in Kbytes per second, and you can set the `-S` to "True" to make them displayed with units (the string "Kb/s"). - Default template: `<dev>: <rx>KB|<tx>KB`+- Example of usage of `--devices` option: `["--", "--devices", "wlp2s0,enp0s20f41"]` ### `Wireless Interface Args RefreshRate` @@ -911,13 +913,21 @@ percentage left in the battery is less or equal than the threshold given by the `-A` option. If not present, no action is undertaken.+ - `-P`: to include a percentage symbol in `left`. - `--on-icon-pattern`: dynamic string for current battery charge when AC is "on" in `leftipat`. - `--off-icon-pattern`: dynamic string for current battery charge when AC is "off" in `leftipat`. - `--idle-icon-pattern`: dynamic string for current battery charge when AC is "idle" in `leftipat`.+ - `--lows`: string for AC "off" status and power lower than the `-L`+ threshold (default: "")+ - `--mediums`: string for AC "off" status and power lower than the `-H`+ threshold (default: "")+ - `--high`: string for AC "off" status and power higher than the `-H`+ threshold (default: "") + - Variables that can be used with the `-t`/`--template` argument: `left`, `leftbar`, `leftvbar`, `leftipat`, `timeleft`, `watts`, `acstatus` - Default template: `Batt: <watts>, <left>% / <timeleft>`@@ -1148,6 +1158,25 @@ - `--highd` _number_ High threshold for dB. Defaults to -5.0. - `--lowd` _number_ Low threshold for dB. Defaults to -30.0. - `--volume-icon-pattern` _string_ dynamic string for current volume in `volumeipat`.+ - `-H` _number_ High threshold for volume (in %). Defaults to 60.0.+ - Long option: `--highv`+ - `-L` _number_ Low threshold for volume (in %). Defaults to 20.0.+ - Long option: `--lowv`+ - `-h`: _string_ High string+ - The string added in front of `<status>` when the mixer element+ is on and the volume percentage is higher than the `-H` threshold.+ Defaults to "".+ - Long option: `--highs`+ - `-m`: _string_ Medium string+ - The string added in front of `<status>` when the mixer element+ is on and the volume percentage is lower than the `-H` threshold.+ Defaults to "".+ - Long option: `--mediums`+ - `-l`: _string_ Low string+ - The string added in front of `<status>` when the mixer element+ is on and the volume percentage is lower than the `-L` threshold.+ Defaults to "".+ - Long option: `--lows` - Variables that can be used with the `-t`/`--template` argument: `volume`, `volumebar`, `volumevbar`, `volumeipat`, `dB`, `status` - Note that `dB` might only return 0 on your system. This is known@@ -1159,29 +1188,35 @@ ### `Alsa Mixer Element Args` -Like [Volume](#volume-mixer-element-args-refreshrate), but with the following differences:-- Uses event-based refreshing via `alsactl monitor` instead of polling, so it will refresh- instantly when there's a volume change, and won't use CPU until a change happens.-- Aliases to `alsa:` followed by the mixer name and element name separated by a colon. Thus,- `Alsa "default" "Master" []` can be used as `%alsa:default:Master%`.+Like [Volume](#volume-mixer-element-args-refreshrate), but with the+following differences:+- Uses event-based refreshing via `alsactl monitor` instead of+ polling, so it will refresh instantly when there's a volume change,+ and won't use CPU until a change happens.+- Aliases to `alsa:` followed by the mixer name and element name+ separated by a colon. Thus, `Alsa "default" "Master" []` can be used+ as `%alsa:default:Master%`. - Additional options (after the `--`): - `--alsactl=/path/to/alsactl`- - If this option is not specified, `alsactl` will be sought in your `PATH`- first, and failing that, at `/usr/sbin/alsactl` (this is its location on- Debian systems. `alsactl monitor` works as a non-root user despite living- in `/usr/sbin`.).-- `stdbuf` (from coreutils) must be (and most probably already is) in your `PATH`.+ - If this option is not specified, `alsactl` will be sought in+ your `PATH` first, and failing that, at `/usr/sbin/alsactl`+ (this is its location on Debian systems. `alsactl monitor`+ works as a non-root user despite living in `/usr/sbin`.).+- `stdbuf` (from coreutils) must be (and most probably already is) in+ your `PATH`. ### `MPD Args RefreshRate` - This monitor will only be compiled if you ask for it using the `with_mpd` flag. It needs [libmpd] 5.0 or later (available on Hackage). - Aliases to `mpd`-- Args: default monitor arguments. In addition you can provide- `-P`, `-S` and `-Z`, with an string argument, to represent the- playing, stopped and paused states in the `statei` template field.- The environment variables `MPD_HOST` and `MPD_PORT` are used to configure the- mpd server to communicate with. Also available:+- Args: default monitor arguments. In addition you can provide `-P`,+ `-S` and `-Z`, with an string argument, to represent the playing,+ stopped and paused states in the `statei` template field. The+ environment variables `MPD_HOST` and `MPD_PORT` are used to+ configure the mpd server to communicate with, unless given in the+ additional arguments `-p` (`--port`) and `-h` (`--host`). Also+ available: - `lapsed-icon-pattern`: dynamic string for current track position in `ipat`. - Variables that can be used with the `-t`/`--template` argument: `bar`, `vbar`, `ipat`, `state`, `statei`, `volume`, `length`,@@ -1245,6 +1280,30 @@ ("lists", "~/var/mail/lists")] "mail" +### `MailX Args Opts Alias`++- Args: list of maildirs in form+ `[("name1","path1","color1"),...]`. Paths may start with a '~'+ to expand to the user's home directory. When mails are present,+ counts are displayed with the given name and color.+- Opts is a possibly empty list of options, as flags. Possible values:+ -d dir --dir dir a string giving the base directory where maildir files with+ a relative path live.+ -p prefix --prefix prefix a string giving a prefix for the list+ of displayed mail counts+ -s suffix --suffix suffix a string giving a suffix for the list+ of displayed mail counts+- This plugin requires inotify support in your Linux kernel and the+ [hinotify] package. To activate, pass `--flags="with_inotify"`+ during compilation.+- Example:++ Run MailX [("I", "inbox", "green"),+ ("L", "lists", "orange")]+ ["-d", "~/var/mail", "-p", " ", "-s", " "]+ "mail"++ ### `MBox Mboxes Opts Alias` - Mboxes a list of mbox files of the form `[("name", "path", "color")]`,@@ -1405,7 +1464,7 @@ ## Other Plugins -<font size="+1">**`StdinReader`**</font>+### `StdinReader` - Aliases to StdinReader - Displays any text received by xmobar on its standard input.@@ -1413,7 +1472,7 @@ actions via stdin. This is safer than `UnsafeStdinReader` because there is no need to escape the content before passing it to xmobar's standard input. -<font size="+1">**`UnsafeStdinReader`**</font>+### `UnsafeStdinReader` - Aliases to UnsafeStdinReader - Displays any text received by xmobar on its standard input.@@ -1427,13 +1486,13 @@ clicking on xmobar: ```<action=`xdotool key alt+1`>ws1</action> <action=`xdotool key alt+1`>ws2</action>``` -<font size="+1">**`Date Format Alias RefreshRate`**</font>+### `Date Format Alias RefreshRate` - Format is a time format string, as accepted by the standard ISO C `strftime` function (or Haskell's `formatCalendarTime`). - Sample usage: `Run Date "%a %b %_d %Y <fc=#ee9a00>%H:%M:%S</fc>" "date" 10` -<font size="+1">**`DateZone Format Locale Zone Alias RefreshRate`**</font>+### `DateZone Format Locale Zone Alias RefreshRate` - Format is a time format string, as accepted by the standard ISO C `strftime` function (or Haskell's `formatCalendarTime`).@@ -1446,17 +1505,17 @@ - Sample usage: `Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "Europe/Vienna" "viennaTime" 10` -<font size="+1">**`CommandReader "/path/to/program" Alias`**</font>+### `CommandReader "/path/to/program" Alias` - Runs the given program, and displays its standard output. -<font size="+1">**`PipeReader "default text:/path/to/pipe" Alias`**</font>+### `PipeReader "default text:/path/to/pipe" Alias` - Reads its displayed output from the given pipe. - Prefix an optional default text separated by a colon - Expands environment variables in the first argument of syntax '${VAR}' or '$VAR' -<font size="+1">**`MarqueePipeReader "default text:/path/to/pipe" (length, rate, sep) Alias`**</font>+### `MarqueePipeReader "default text:/path/to/pipe" (length, rate, sep) Alias` - Generally equivalent to PipeReader - Text is displayed as marquee with the specified length, rate in 10th@@ -1466,9 +1525,7 @@ - Expands environment variables in the first argument -<font size="+1">-**`BufferedPipeReader Alias [(Timeout, Bool, "/path/to/pipe1"), ..]`**-</font>+### `BufferedPipeReader Alias [(Timeout, Bool, "/path/to/pipe1"), ..]` - Display data from multiple pipes. - Timeout (in tenth of seconds) is the value after which the previous@@ -1500,7 +1557,7 @@ [examples/status.sh]: http://github.com/jaor/xmobar/raw/master/examples/status.sh -<font size="+1">**`XMonadLog`**</font>+### `XMonadLog` - Aliases to XMonadLog - Displays information from xmonad's `_XMONAD_LOG`. You can set this@@ -1518,7 +1575,7 @@ [here]: http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Hooks-DynamicLog.html -<font size="+1">**`UnsafeXMonadLog`**</font>+### `UnsafeXMonadLog` - Aliases to UnsafeXMonadLog - Similar to StdinReader versus UnsafeStdinReader, this does not strip `<action@@ -1618,13 +1675,14 @@ Lunter, Vanessa McHale, Robert J. Macomber, Dmitry Malikov, David McLean, Marcin Mikołajczyk, Dino Morelli, Tony Morris, Eric Mrak, Thiago Negri, Edward O'Callaghan, Svein Ove, Martin Perner, Jens-Petersen, Alexander Polakov, Pavan Rikhi, Petr Rockai, Andrew-Sackville-West, Markus Scherer, Daniel Schüssler, Olivier Schneider,-Alexander Shabalin, Valentin Shirokov, Peter Simons, Alexander-Solovyov, Will Song, John Soros, Felix Springer, Travis Staton, Artem-Tarasov, Samuli Thomasson, Edward Tjörnhammar, Sergei Trofimovich,-Thomas Tuegel, John Tyree, Jan Vornberger, Anton Vorontsov, Daniel-Wagner, Zev Weiss, Phil Xiaojun Hu, Edward Z. Yang and Norbert Zeh.+Petersen, Alexander Polakov, Pavan Rikhi, Petr Rockai, Andrew Emmanuel+Rosa, Sackville-West, Markus Scherer, Daniel Schüssler, Olivier+Schneider, Alexander Shabalin, Valentin Shirokov, Peter Simons,+Alexander Solovyov, Will Song, John Soros, Felix Springer, Travis+Staton, Artem Tarasov, Samuli Thomasson, Edward Tjörnhammar, Sergei+Trofimovich, Thomas Tuegel, John Tyree, Jan Vornberger, Anton+Vorontsov, Daniel Wagner, Zev Weiss, Phil Xiaojun Hu, Edward Z. Yang+and Norbert Zeh. [jao]: http://jao.io [incorporates patches]: http://www.ohloh.net/p/xmobar/contributors
src/Xmobar/App/Config.hs view
@@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Config.Defaults--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2019 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -21,6 +21,8 @@ xmobarDataDir, xmobarConfigFile) where +import Control.Monad (when)+ import System.Environment import System.Directory import System.FilePath ((</>))@@ -79,10 +81,10 @@ -- -- The first directory that exists will be used. If none of the -- directories exist then (1) will be used if it is set, otherwise (2)--- will be used. Either way, a directory will be created if necessary.+-- will be used. xmobarConfigDir :: IO String xmobarConfigDir =- findFirstDirWithEnv "XMOBAR_CONFIG_DIR"+ findFirstDirWithEnv False "XMOBAR_CONFIG_DIR" [ getAppUserDataDirectory "xmobar" , getXdgDirectory XdgConfig "xmobar" ]@@ -94,8 +96,8 @@ -- Several directories are considered. In order of preference: -- -- 1. The directory specified in the @XMOBAR_DATA_DIR@ environment variable.--- 2. The @~\/.xmobar@ directory.--- 3. The @XDG_DATA_HOME/xmobar@ directory.+-- 2. The @XDG_DATA_HOME/xmobar@ directory.+-- 3. The @~\/.xmobar@ directory. -- -- The first directory that exists will be used. If none of the -- directories exist then (1) will be used if it is set, otherwise (2)@@ -103,24 +105,25 @@ -- necessary. xmobarDataDir :: IO String xmobarDataDir =- findFirstDirWithEnv "XMOBAR_DATA_DIR"- [ getAppUserDataDirectory "xmobar"- , getXdgDirectory XdgData "xmobar"+ findFirstDirWithEnv True "XMOBAR_DATA_DIR"+ [ getXdgDirectory XdgData "xmobar"+ , getAppUserDataDirectory "xmobar" ] -- | Helper function that will find the first existing directory and--- return its path. If none of the directories can be found, create--- and return the first from the list. If the list is empty this--- function returns the historical @~\/.xmobar@ directory.-findFirstDirOf :: [IO FilePath] -> IO FilePath-findFirstDirOf [] = findFirstDirOf [getAppUserDataDirectory "xmobar"]-findFirstDirOf possibles = do+-- return its path. If none of the directories can be found,+-- optionally create and return the first from the list. If the list+-- is empty this function returns the historical @~\/.xmobar@+-- directory.+findFirstDirOf :: Bool -> [IO FilePath] -> IO FilePath+findFirstDirOf create [] = findFirstDirOf create [getAppUserDataDirectory "xmobar"]+findFirstDirOf create possibles = do found <- go possibles case found of Just path -> return path Nothing -> do primary <- head possibles- createDirectoryIfMissing True primary+ when create (createDirectoryIfMissing True primary) return primary where go [] = return Nothing@@ -130,12 +133,12 @@ -- | Simple wrapper around @findFirstDirOf@ that allows the primary -- path to be specified by an environment variable.-findFirstDirWithEnv :: String -> [IO FilePath] -> IO FilePath-findFirstDirWithEnv envName paths = do+findFirstDirWithEnv :: Bool -> String -> [IO FilePath] -> IO FilePath+findFirstDirWithEnv create envName paths = do envPath' <- lookupEnv envName case envPath' of- Nothing -> findFirstDirOf paths- Just envPath -> findFirstDirOf (return envPath:paths)+ Nothing -> findFirstDirOf create paths+ Just envPath -> findFirstDirOf create (return envPath:paths) xmobarConfigFile :: IO (Maybe FilePath) xmobarConfigFile =
src/Xmobar/App/Main.hs view
@@ -70,13 +70,13 @@ for_ (concat vars) $ \(asyncs, _) -> for_ asyncs cancel -buildLaunch :: Bool -> Bool -> FilePath -> String -> ParseError -> IO ()-buildLaunch verb force p datadir e = do+buildLaunch :: Bool -> Bool -> String -> ParseError -> IO ()+buildLaunch verb force p e = do let exec = takeBaseName p confDir = takeDirectory p ext = takeExtension p if ext `elem` [".hs", ".hsc", ".lhs"]- then recompile confDir datadir exec force verb >>+ then xmobarDataDir >>= \dd -> recompile confDir dd exec force verb >> executeFile (confDir </> exec) False [] Nothing else trace True ("Invalid configuration file: " ++ show e) >> trace True "\n(No compilation attempted: \@@ -101,8 +101,7 @@ (c:_) -> error $ c ++ ": file not found" _ -> doOpts defaultConfig flags >>= xmobar Just p -> do r <- readConfig defaultConfig p- dataDir <- xmobarDataDir case r of Left e ->- buildLaunch (verboseFlag flags) (recompileFlag flags) p dataDir e+ buildLaunch (verboseFlag flags) (recompileFlag flags) p e Right (c, defs) -> doOpts c flags >>= xmobar' defs
src/Xmobar/Plugins/DateZone.hs view
@@ -28,7 +28,10 @@ import Control.Concurrent.STM import System.IO.Unsafe+import System.Environment (lookupEnv) +import Data.Maybe (fromMaybe)+ import Data.Time.Format import Data.Time.LocalTime import Data.Time.LocalTime.TimeZone.Olson@@ -63,7 +66,8 @@ locale <- getTimeLocale atomically $ putTMVar localeLock lock if z /= "" then do- timeZone <- getTimeZoneSeriesFromOlsonFile ("/usr/share/zoneinfo/" ++ z)+ tzdir <- lookupEnv "TZDIR"+ timeZone <- getTimeZoneSeriesFromOlsonFile ((fromMaybe "/usr/share/zoneinfo" tzdir) ++ "/" ++ z) go (dateZone f locale timeZone) else go (date f locale)
src/Xmobar/Plugins/Kbd.hs view
@@ -27,7 +27,7 @@ -- 'Bad' prefixes of layouts noLaySymbols :: [String]-noLaySymbols = ["group", "inet", "ctr", "pc", "ctrl"]+noLaySymbols = ["group", "inet", "ctr", "pc", "ctrl", "terminate"] -- splits the layout string into the actual layouts
src/Xmobar/Plugins/Mail.hs view
@@ -13,7 +13,7 @@ -- ----------------------------------------------------------------------------- -module Xmobar.Plugins.Mail(Mail(..)) where+module Xmobar.Plugins.Mail(Mail(..),MailX(..)) where import Xmobar.Run.Exec #ifdef INOTIFY@@ -26,6 +26,7 @@ import System.Directory import System.FilePath import System.INotify+import System.Console.GetOpt import Data.List (isPrefixOf) import Data.Set (Set)@@ -47,23 +48,56 @@ import System.IO #endif +data MOptions = MOptions+ { oDir :: FilePath+ , oPrefix :: String+ , oSuffix :: String+ } +defaults :: MOptions+defaults = MOptions {oDir = "", oPrefix = "", oSuffix = ""}++options :: [OptDescr (MOptions -> MOptions)]+options =+ [ Option "d" ["dir"] (ReqArg (\x o -> o { oDir = x }) "") ""+ , Option "p" ["prefix"] (ReqArg (\x o -> o { oPrefix = x }) "") ""+ , Option "s" ["suffix"] (ReqArg (\x o -> o { oSuffix = x }) "") ""+ ]++parseOptions :: [String] -> IO MOptions+parseOptions args =+ case getOpt Permute options args of+ (o, _, []) -> return $ foldr id defaults o+ (_, _, errs) -> ioError . userError $ concat errs++ -- | A list of mail box names and paths to maildirs. data Mail = Mail [(String, FilePath)] String deriving (Read, Show) +-- | A list of mail box names, paths to maildirs and display colors.+data MailX = MailX [(String, FilePath, String)] [String] String+ deriving (Read, Show)+ instance Exec Mail where- alias (Mail _ a) = a+ alias (Mail _ a) = a+ start (Mail ms a) = start (MailX (map (\(n,p) -> (n,p,"")) ms) [] a)++instance Exec MailX where+ alias (MailX _ _ a) = a #ifndef INOTIFY start _ _ = hPutStrLn stderr $ "Warning: xmobar is not compiled with -fwith_inotify," ++ " but the Mail plugin requires it." #else- start (Mail ms _) cb = do+ start (MailX ms args _) cb = do vs <- mapM (const $ newTVarIO S.empty) ms-- let ts = map fst ms- rs = map ((</> "new") . snd) ms+ opts <- parseOptions args+ let prefix = oPrefix opts+ suffix = oSuffix opts+ dir = oDir opts+ ps = map (\(_,p,_) -> if null dir then p else dir </> p) ms+ rs = map (</> "new") ps ev = [Move, MoveIn, MoveOut, Create, Delete] ds <- mapM expandHome rs@@ -76,9 +110,11 @@ atomically $ modifyTVar v (S.union s) changeLoop (mapM (fmap S.size . readTVar) vs) $ \ns ->- cb . unwords $ [m ++ show n- | (m, n) <- zip ts ns- , n /= 0 ]+ let showmbx m n c = if c == ""+ then m ++ show n+ else "<fc=" ++ c ++ ">" ++ m ++ show n ++ "</fc>"+ cnts = [showmbx m n c | ((m,_,c), n) <- zip ms ns , n /= 0 ]+ in cb $ if null cnts then "" else prefix ++ unwords cnts ++ suffix handle :: TVar (Set String) -> Event -> IO () handle v e = atomically $ modifyTVar v $ case e of
src/Xmobar/Plugins/Monitors/Batt.hs view
@@ -45,6 +45,10 @@ , onIconPattern :: Maybe IconPattern , offIconPattern :: Maybe IconPattern , idleIconPattern :: Maybe IconPattern+ , lowString :: String+ , mediumString :: String+ , highString :: String+ , incPerc :: Bool } defaultOpts :: BattOpts@@ -65,6 +69,10 @@ , onIconPattern = Nothing , offIconPattern = Nothing , idleIconPattern = Nothing+ , lowString = ""+ , mediumString = ""+ , highString = ""+ , incPerc = False } options :: [OptDescr (BattOpts -> BattOpts)]@@ -81,6 +89,7 @@ , Option "f" ["online"] (ReqArg (\x o -> o { onlineFile = x }) "") "" , Option "s" ["scale"] (ReqArg (\x o -> o {scale = read x}) "") "" , Option "a" ["action"] (ReqArg (\x o -> o { onLowAction = Just x }) "") ""+ , Option "P" ["percent"] (NoArg (\o -> o {incPerc = True})) "" , Option "A" ["action-threshold"] (ReqArg (\x o -> o { actionThreshold = read x }) "") "" , Option "" ["on-icon-pattern"] (ReqArg (\x o ->@@ -89,6 +98,9 @@ o { offIconPattern = Just $ parseIconPattern x }) "") "" , Option "" ["idle-icon-pattern"] (ReqArg (\x o -> o { idleIconPattern = Just $ parseIconPattern x }) "") ""+ , Option "" ["lows"] (ReqArg (\x o -> o { lowString = x }) "") ""+ , Option "" ["mediums"] (ReqArg (\x o -> o { mediumString = x }) "") ""+ , Option "" ["highs"] (ReqArg (\x o -> o { highString = x }) "") "" ] parseOpts :: [String] -> IO BattOpts@@ -125,6 +137,23 @@ , status :: !String } +data BatteryStatus+ = BattHigh+ | BattMedium+ | BattLow++-- | Convert the current battery charge into a 'BatteryStatus'+getBattStatus+ :: Float -- ^ Current battery charge, assumed to be in [0,1]+ -> BattOpts -- ^ Battery options, including high/low thresholds+ -> BatteryStatus+getBattStatus charge opts+ | c >= highThreshold opts = BattHigh+ | c >= lowThreshold opts = BattMedium+ | otherwise = BattLow+ where+ c = 100 * min 1 charge+ safeFileExist :: String -> String -> IO Bool safeFileExist d f = handle noErrors $ fileExist (d </> f) where noErrors = const (return False) :: SomeException -> IO Bool@@ -217,25 +246,29 @@ runBatt' :: [String] -> [String] -> Monitor String runBatt' bfs args = do opts <- io $ parseOpts args+ let sp = incPerc opts c <- io $ readBatteries opts =<< mapM batteryFiles bfs suffix <- getConfigValue useSuffix d <- getConfigValue decDigits nas <- getConfigValue naString case c of Result x w t s ->- do l <- fmtPercent x+ do l <- fmtPercent x sp ws <- fmtWatts w opts suffix d si <- getIconPattern opts s x- st <- showWithColors' (fmtStatus opts s nas) (100 * x)+ st <- showWithColors'+ (fmtStatus opts s nas (getBattStatus x opts))+ (100 * x) parseTemplate (l ++ [st, fmtTime $ floor t, ws, si]) NA -> getConfigValue naString- where fmtPercent :: Float -> Monitor [String]- fmtPercent x = do+ where fmtPercent :: Float -> Bool -> Monitor [String]+ fmtPercent x sp = do let x' = minimum [1, x]+ pc <- if sp then colorizeString (100 * x') "%" else return "" p <- showPercentWithColors x' b <- showPercentBar (100 * x') x' vb <- showVerticalBar (100 * x') x'- return [b, vb, p]+ return [b, vb, p ++ pc] fmtWatts x o s d = do ws <- showWithPadding $ showDigits d x ++ (if s then "W" else "") return $ color x o ws@@ -244,11 +277,21 @@ then minutes else '0' : minutes where hours = show (x `div` 3600) minutes = show ((x `mod` 3600) `div` 60)- fmtStatus opts Idle _ = idleString opts- fmtStatus _ Unknown na = na- fmtStatus opts Full _ = idleString opts- fmtStatus opts Charging _ = onString opts- fmtStatus opts Discharging _ = offString opts+ fmtStatus+ :: BattOpts+ -> Status+ -> String -- ^ What to in case battery status is unknown+ -> BatteryStatus+ -> String+ fmtStatus opts Idle _ _ = idleString opts+ fmtStatus _ Unknown na _ = na+ fmtStatus opts Full _ _ = idleString opts+ fmtStatus opts Charging _ _ = onString opts+ fmtStatus opts Discharging _ battStatus =+ (case battStatus of+ BattHigh -> highString+ BattMedium -> mediumString+ BattLow -> lowString) opts ++ offString opts maybeColor Nothing str = str maybeColor (Just c) str = "<fc=" ++ c ++ ">" ++ str ++ "</fc>" color x o | x >= 0 = maybeColor (posColor o)
src/Xmobar/Plugins/Monitors/Common/Output.hs view
@@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Plugins.Monitors.Strings--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2019 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -18,6 +18,7 @@ module Xmobar.Plugins.Monitors.Common.Output ( IconPattern , parseIconPattern , padString+ , colorizeString , showWithPadding , showWithColors , showWithColors'
src/Xmobar/Plugins/Monitors/Disk.hs view
@@ -31,6 +31,7 @@ { totalIconPattern :: Maybe IconPattern , writeIconPattern :: Maybe IconPattern , readIconPattern :: Maybe IconPattern+ , contiguous :: Bool } parseDiskIOOpts :: [String] -> IO DiskIOOpts@@ -42,6 +43,7 @@ { totalIconPattern = Nothing , writeIconPattern = Nothing , readIconPattern = Nothing+ , contiguous = False } options = [ Option "" ["total-icon-pattern"] (ReqArg (\x o ->@@ -50,6 +52,7 @@ o { writeIconPattern = Just $ parseIconPattern x}) "") "" , Option "" ["read-icon-pattern"] (ReqArg (\x o -> o { readIconPattern = Just $ parseIconPattern x}) "") ""+ , Option "c" ["contiguous"] (NoArg (\o -> o {contiguous = True})) "" ] diskIOConfig :: IO MConfig@@ -66,6 +69,7 @@ data DiskUOpts = DiskUOpts { freeIconPattern :: Maybe IconPattern , usedIconPattern :: Maybe IconPattern+ , contiguousU :: Bool } parseDiskUOpts :: [String] -> IO DiskUOpts@@ -76,12 +80,14 @@ where defaultOpts = DiskUOpts { freeIconPattern = Nothing , usedIconPattern = Nothing+ , contiguousU = False } options = [ Option "" ["free-icon-pattern"] (ReqArg (\x o -> o { freeIconPattern = Just $ parseIconPattern x}) "") "" , Option "" ["used-icon-pattern"] (ReqArg (\x o -> o { usedIconPattern = Just $ parseIconPattern x}) "") ""+ , Option "c" ["contiguous"] (NoArg (\o -> o {contiguousU = True})) "" ] diskUConfig :: IO MConfig@@ -147,25 +153,26 @@ return $ map (parseDev (zipWith diff dt' dt)) devs where diff (dev, xs) (_, ys) = (dev, zipWith (-) xs ys) + parseDev :: [(DevName, [Float])] -> DevName -> (DevName, [Float]) parseDev dat dev = case find ((==dev) . fst) dat of Nothing -> (dev, [0, 0, 0]) Just (_, xs) ->- let r = xs !! 2- w = xs !! 6+ let r = 4096 * xs !! 2+ w = 4096 * xs !! 6 t = r + w rSp = speed r (xs !! 3) wSp = speed w (xs !! 7) sp = speed t (xs !! 3 + xs !! 7)- speed x d = if d == 0 then 0 else 500 * x / d+ speed x d = if d == 0 then 0 else x / d dat' = if length xs > 6 then [sp, rSp, wSp, t, r, w] else [0, 0, 0, 0, 0, 0] in (dev, dat') speedToStr :: Float -> String-speedToStr = showWithUnits 2 1+speedToStr = showWithUnits 2 1 . (/ 1024) sizeToStr :: Integer -> String sizeToStr = showWithUnits 3 0 . fromIntegral@@ -205,7 +212,7 @@ dev <- io $ mountedOrDiskDevices (map fst disks) dat <- io $ mountedData dref (map fst dev) strs <- mapM (runDiskIO' opts) $ devTemplates disks dev dat- return $ unwords strs+ return $ (if contiguous opts then concat else unwords) strs startDiskIO :: [(String, String)] -> [String] -> Int -> (String -> IO ()) -> IO ()@@ -249,4 +256,4 @@ devs <- io $ mountedDevices (map fst disks) opts <- io $ parseDiskUOpts argv strs <- mapM (\(d, p) -> runDiskU' opts (findTempl d p disks) p) devs- return $ unwords strs+ return $ (if contiguousU opts then concat else unwords) strs
src/Xmobar/Plugins/Monitors/MPD.hs view
@@ -34,6 +34,8 @@ , mStopped :: String , mPaused :: String , mLapsedIconPattern :: Maybe IconPattern+ , mPort :: Maybe String+ , mHost :: Maybe String } defaultOpts :: MOpts@@ -42,6 +44,8 @@ , mStopped = "><" , mPaused = "||" , mLapsedIconPattern = Nothing+ , mPort = Nothing+ , mHost = Nothing } options :: [OptDescr (MOpts -> MOpts)]@@ -49,15 +53,20 @@ [ Option "P" ["playing"] (ReqArg (\x o -> o { mPlaying = x }) "") "" , Option "S" ["stopped"] (ReqArg (\x o -> o { mStopped = x }) "") "" , Option "Z" ["paused"] (ReqArg (\x o -> o { mPaused = x }) "") ""+ , Option "p" ["port"] (ReqArg (\x o -> o { mPort = Just x }) "") ""+ , Option "h" ["host"] (ReqArg (\x o -> o { mHost = Just x }) "") "" , Option "" ["lapsed-icon-pattern"] (ReqArg (\x o -> o { mLapsedIconPattern = Just $ parseIconPattern x }) "") "" ] +withMPD :: MOpts -> M.MPD a -> IO (M.Response a)+withMPD opts = M.withMPD_ (mHost opts) (mPort opts)+ runMPD :: [String] -> Monitor String runMPD args = do opts <- io $ mopts args- status <- io $ M.withMPD M.status- song <- io $ M.withMPD M.currentSong+ status <- io $ withMPD opts M.status+ song <- io $ withMPD opts M.currentSong s <- parseMPD status song opts parseTemplate s @@ -69,8 +78,9 @@ _ -> return () mpdReady :: [String] -> Monitor Bool-mpdReady _ = do- response <- io $ M.withMPD M.ping+mpdReady args = do+ opts <- io $ mopts args+ response <- io $ withMPD opts M.ping case response of Right _ -> return True -- Only cases where MPD isn't responding is an issue; bogus information at
src/Xmobar/Plugins/Monitors/Net.hs view
@@ -13,6 +13,8 @@ -- ----------------------------------------------------------------------------- +{-# LANGUAGE OverloadedStrings #-}+ module Xmobar.Plugins.Monitors.Net ( startNet , startDynNet@@ -20,26 +22,40 @@ import Xmobar.Plugins.Monitors.Common -import Data.Word (Word64) import Data.IORef (IORef, newIORef, readIORef, writeIORef)+import Data.Monoid ((<>)) import Data.Time.Clock (UTCTime, getCurrentTime, diffUTCTime)+import Data.Word (Word64) import Control.Monad (forM, filterM) import System.Directory (getDirectoryContents, doesFileExist) import System.FilePath ((</>)) import System.Console.GetOpt import System.IO.Error (catchIOError)+import System.IO.Unsafe (unsafeInterleaveIO) -import qualified Data.ByteString.Lazy.Char8 as B+import qualified Data.ByteString.Char8 as B +type DevList = [String]++parseDevList :: String -> DevList+parseDevList = splitOnComma+ where splitOnComma [] = [[]]+ splitOnComma (',':xs) = [] : splitOnComma xs+ splitOnComma (x:xs) =+ let rest = splitOnComma xs+ in (x : head rest) : tail rest+ data NetOpts = NetOpts { rxIconPattern :: Maybe IconPattern , txIconPattern :: Maybe IconPattern+ , onlyDevList :: Maybe DevList } defaultOpts :: NetOpts defaultOpts = NetOpts { rxIconPattern = Nothing , txIconPattern = Nothing+ , onlyDevList = Nothing } options :: [OptDescr (NetOpts -> NetOpts)]@@ -48,6 +64,8 @@ o { rxIconPattern = Just $ parseIconPattern x }) "") "" , Option "" ["tx-icon-pattern"] (ReqArg (\x o -> o { txIconPattern = Just $ parseIconPattern x }) "") ""+ , Option "" ["devices"] (ReqArg (\x o ->+ o { onlyDevList = Just $ parseDevList x }) "") "" ] parseOpts :: [String] -> IO NetOpts@@ -65,10 +83,8 @@ show MBs = "MB/s" show GBs = "GB/s" -data NetDev num- = NA- | NI String- | ND String num num deriving (Eq,Show,Read)+data NetDev num = N String (NetDevInfo num) | NA deriving (Eq,Show,Read)+data NetDevInfo num = NI | ND num num deriving (Eq,Show,Read) type NetDevRawTotal = NetDev Word64 type NetDevRate = NetDev Float@@ -79,18 +95,17 @@ -- Note that names don't matter. Therefore, if only the names differ, -- a compare evaluates to EQ while (==) evaluates to False. instance Ord num => Ord (NetDev num) where- compare NA NA = EQ- compare NA _ = LT- compare _ NA = GT- compare (NI _) (NI _) = EQ- compare (NI _) ND {} = LT- compare ND {} (NI _) = GT- compare (ND _ x1 y1) (ND _ x2 y2) =- if downcmp /= EQ- then downcmp- else y1 `compare` y2- where downcmp = x1 `compare` x2+ compare NA NA = EQ+ compare NA _ = LT+ compare _ NA = GT+ compare (N _ i1) (N _ i2) = i1 `compare` i2 +instance Ord num => Ord (NetDevInfo num) where+ compare NI NI = EQ+ compare NI ND {} = LT+ compare ND {} NI = GT+ compare (ND x1 y1) (ND x2 y2) = x1 `compare` x2 <> y1 `compare` y2+ netConfig :: IO MConfig netConfig = mkMConfig "<dev>: <rx>KB|<tx>KB" -- template@@ -108,25 +123,20 @@ isUp :: String -> IO Bool isUp d = flip catchIOError (const $ return False) $ do operstate <- B.readFile (operstateDir d)- return $! (B.unpack . head . B.lines) operstate `elem` ["up", "unknown"]+ return $! (head . B.lines) operstate `elem` ["up", "unknown"] readNetDev :: [String] -> IO NetDevRawTotal-readNetDev (d:x:y:_) = do- up <- isUp d- return (if up then ND d (r x) (r y) else NI d)+readNetDev ~[d, x, y] = do+ up <- unsafeInterleaveIO $ isUp d+ return $ N d (if up then ND (r x) (r y) else NI) where r s | s == "" = 0 | otherwise = read s -readNetDev _ = return NA- netParser :: B.ByteString -> IO [NetDevRawTotal] netParser = mapM (readNetDev . splitDevLine) . readDevLines where readDevLines = drop 2 . B.lines- splitDevLine = selectCols . wordsBy (`elem` " :") . B.unpack+ splitDevLine = map B.unpack . selectCols . filter (not . B.null) . B.splitWith (`elem` [' ',':']) selectCols cols = map (cols!!) [0,1,9]- wordsBy f s = case dropWhile f s of- [] -> []- s' -> w : wordsBy f s'' where (w, s'') = break f s' findNetDev :: String -> IO NetDevRawTotal findNetDev dev = do@@ -134,8 +144,7 @@ case filter isDev nds of x:_ -> return x _ -> return NA- where isDev (ND d _ _) = d == dev- isDev (NI d) = d == dev+ where isDev (N d _) = d == dev isDev NA = False formatNet :: Maybe IconPattern -> Float -> Monitor (String, String, String, String)@@ -154,11 +163,11 @@ printNet :: NetOpts -> NetDevRate -> Monitor String printNet opts nd = case nd of- ND d r t -> do+ N d (ND r t) -> do (rx, rb, rvb, ripat) <- formatNet (rxIconPattern opts) r (tx, tb, tvb, tipat) <- formatNet (txIconPattern opts) t parseTemplate [d,rx,tx,rb,rvb,ripat,tb,tvb,tipat]- NI _ -> return ""+ N _ NI -> return "" NA -> getConfigValue naString parseNet :: NetDevRef -> String -> IO NetDevRate@@ -170,9 +179,9 @@ let scx = realToFrac (diffUTCTime t1 t0) scx' = if scx > 0 then scx else 1 rate da db = takeDigits 2 $ fromIntegral (db - da) / scx'- diffRate (ND d ra ta) (ND _ rb tb) = ND d (rate ra rb) (rate ta tb)- diffRate (NI d) _ = NI d- diffRate _ (NI d) = NI d+ diffRate (N d (ND ra ta)) (N _ (ND rb tb)) = N d (ND (rate ra rb) (rate ta tb))+ diffRate (N d NI) _ = N d NI+ diffRate _ (N d NI) = N d NI diffRate _ _ = NA return $ diffRate n0 n1 @@ -187,10 +196,16 @@ runNets :: [(NetDevRef, String)] -> [String] -> Monitor String runNets refs argv = do- dev <- io $ parseActive refs opts <- io $ parseOpts argv+ dev <- io $ parseActive $ filterRefs opts refs printNet opts dev where parseActive refs' = fmap selectActive (parseNets refs')+ refInDevList opts' (_, refname') = case onlyDevList opts' of+ Just theList -> refname' `elem` theList+ Nothing -> True+ filterRefs opts' refs' = case filter (refInDevList opts') refs' of+ [] -> refs'+ xs -> xs selectActive = maximum startNet :: String -> [String] -> Int -> (String -> IO ()) -> IO ()
src/Xmobar/Plugins/Monitors/Volume.hs view
@@ -21,7 +21,7 @@ , VolumeOpts ) where -import Control.Applicative ((<$>))+import Control.Applicative ( (<$>), liftA3 ) import Control.Monad ( liftM2, liftM3, mplus ) import Data.Traversable (sequenceA) import Xmobar.Plugins.Monitors.Common@@ -42,6 +42,11 @@ , highDbThresh :: Float , lowDbThresh :: Float , volumeIconPattern :: Maybe IconPattern+ , lowVolThresh :: Maybe Float+ , highVolThresh :: Maybe Float+ , lowString :: String+ , mediumString :: String+ , highString :: String } defaultOpts :: VolumeOpts@@ -53,8 +58,32 @@ , highDbThresh = -5.0 , lowDbThresh = -30.0 , volumeIconPattern = Nothing+ , lowVolThresh = Just 20.0+ , highVolThresh = Just 60.0+ , lowString = ""+ , mediumString = ""+ , highString = "" } +data VolumeStatus+ = VolLow+ | VolMedium+ | VolHigh+ | VolOff++-- | Set the volume status according to user set thresholds and the current+-- volume+getVolStatus :: Float -- ^ Low volume threshold, in [0,100]+ -> Float -- ^ High volume threshold, in [0,100]+ -> Float -- ^ Current volume, in [0,1]+ -> VolumeStatus+getVolStatus lo hi val'+ | val >= hi = VolHigh+ | val >= lo = VolMedium+ | otherwise = VolLow+ where+ val = val' * 100+ options :: [OptDescr (VolumeOpts -> VolumeOpts)] options = [ Option "O" ["on"] (ReqArg (\x o -> o { onString = x }) "") ""@@ -65,6 +94,11 @@ , Option "c" ["offc"] (ReqArg (\x o -> o { offColor = Just x }) "") "" , Option "" ["volume-icon-pattern"] (ReqArg (\x o -> o { volumeIconPattern = Just $ parseIconPattern x }) "") ""+ , Option "L" ["lowv"] (ReqArg (\x o -> o { lowVolThresh = Just $ read x }) "") ""+ , Option "H" ["highv"] (ReqArg (\x o -> o { highVolThresh = Just $ read x }) "") ""+ , Option "l" ["lows"] (ReqArg (\x o -> o { lowString = x }) "") ""+ , Option "m" ["mediums"] (ReqArg (\x o -> o { mediumString = x }) "") ""+ , Option "h" ["highs"] (ReqArg (\x o -> o { highString = x }) "") "" ] parseOpts :: [String] -> IO VolumeOpts@@ -98,16 +132,27 @@ switchHelper :: VolumeOpts -> (VolumeOpts -> Maybe String) -> (VolumeOpts -> String)+ -> VolumeStatus -> Monitor String-switchHelper opts cHelp strHelp = return $+switchHelper opts cHelp strHelp vs = return $ colorHelper (cHelp opts)+ ++ volHelper vs opts ++ strHelp opts ++ maybe "" (const "</fc>") (cHelp opts) -formatSwitch :: VolumeOpts -> Bool -> Monitor String-formatSwitch opts True = switchHelper opts onColor onString-formatSwitch opts False = switchHelper opts offColor offString+formatSwitch :: VolumeOpts -> Bool -> VolumeStatus -> Monitor String+formatSwitch opts True vs = switchHelper opts onColor onString vs+formatSwitch opts False _ = switchHelper opts offColor offString VolOff +-- | Convert the current volume status into user defined strings+volHelper :: VolumeStatus -> VolumeOpts -> String+volHelper volStatus opts =+ case volStatus of+ VolHigh -> highString opts+ VolMedium -> mediumString opts+ VolLow -> lowString opts+ VolOff -> ""+ colorHelper :: Maybe String -> String colorHelper = maybe "" (\c -> "<fc=" ++ c ++ ">") @@ -138,7 +183,11 @@ b <- liftMonitor $ liftM3 formatVolBar lo hi val v <- liftMonitor $ liftM3 formatVolVBar lo hi val d <- getFormatDB opts db- s <- getFormatSwitch opts sw+ let volStat = liftA3 getVolStatus+ (lowVolThresh opts)+ (highVolThresh opts)+ (liftA3 percent val lo hi) -- current volume in %+ s <- getFormatSwitch opts sw volStat ipat <- liftMonitor $ liftM3 (formatVolDStr $ volumeIconPattern opts) lo hi val parseTemplate [p, b, v, d, s, ipat] @@ -191,8 +240,9 @@ getFormatDB _ Nothing = unavailable getFormatDB opts' (Just d) = formatDb opts' d - getFormatSwitch :: VolumeOpts -> Maybe Bool -> Monitor String- getFormatSwitch _ Nothing = unavailable- getFormatSwitch opts' (Just sw) = formatSwitch opts' sw+ getFormatSwitch :: VolumeOpts -> Maybe Bool -> Maybe VolumeStatus -> Monitor String+ getFormatSwitch _ Nothing _ = unavailable+ getFormatSwitch _ _ Nothing = unavailable+ getFormatSwitch opts' (Just sw) (Just vs) = formatSwitch opts' sw vs unavailable = getConfigValue naString
xmobar.cabal view
@@ -1,5 +1,5 @@ name: xmobar-version: 0.31+version: 0.32 homepage: http://xmobar.org synopsis: A Minimalistic Text Based Status Bar description: Xmobar is a minimalistic text based status bar.@@ -159,7 +159,7 @@ ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind build-depends:- base >= 4.9.1.0 && < 4.13,+ base >= 4.9.1.0 && < 4.14, containers, regex-compat, process,