xmobar 0.36 → 0.37
raw patch · 19 files changed
+588/−289 lines, 19 filesdep ~libmpddep ~timezone-olson
Dependency ranges changed: libmpd, timezone-olson
Files
- bench/main.hs +28/−21
- changelog.md +14/−0
- readme.md +378/−205
- src/Xmobar.hs +2/−0
- src/Xmobar/App/Config.hs +2/−1
- src/Xmobar/App/EventLoop.hs +4/−4
- src/Xmobar/App/Main.hs +1/−1
- src/Xmobar/App/Opts.hs +3/−0
- src/Xmobar/App/Timer.hs +3/−3
- src/Xmobar/Config/Parse.hs +3/−2
- src/Xmobar/Plugins/Date.hs +17/−12
- src/Xmobar/Plugins/Monitors.hs +5/−2
- src/Xmobar/Plugins/NotmuchMail.hs +96/−0
- src/Xmobar/Plugins/StdinReader.hs +20/−17
- src/Xmobar/System/Utils.hs +0/−11
- src/Xmobar/X11/Draw.hs +3/−2
- src/Xmobar/X11/Types.hs +1/−1
- test/Xmobar/Plugins/Monitors/CpuSpec.hs +1/−1
- xmobar.cabal +7/−6
bench/main.hs view
@@ -1,32 +1,39 @@-{-#LANGUAGE RecordWildCards#-}+module Main (main) where +import Data.IORef (newIORef)+import Data.Time 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+ defaultMain =<< sequence [cpuBench, dateBench] 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+mkCpuArgs = getArguments ["-L", "3", "-H", "50", "--normal", "green", "--high", "red", "-t", "Cpu: <total>%"] -cpuBenchmark :: CpuArguments -> Benchmarkable-cpuBenchmark cpuParams = nfIO $ cpuAction cpuParams+cpuBench :: IO Benchmark+cpuBench = do+ cpuArgs <- mkCpuArgs+ return $ bgroup "Cpu Benchmarks"+ [ bench "CPU normal args" $ nfIO (runCpu cpuArgs)+ ] -normalCpuBench :: CpuArguments -> [Benchmark]-normalCpuBench args = [bench "CPU normal args" (cpuBenchmark args)]+dateBench :: IO Benchmark+dateBench = do+ let format = "D: %B %d %A W%V"+ zone <- getCurrentTimeZone+ zone' <- newIORef =<< getCurrentTimeZone+ return $ bgroup "Date Benchmarks"+ [ bench "Date" $ nfIO (date zone' format)+ , bench "DateZonedTime" $ nfIO (dateZonedTime format)+ , bench "DateWithTimeZone" $ nfIO (dateWithTimeZone zone format)+ ]++dateZonedTime :: String -> IO String+dateZonedTime format = fmap (formatTime defaultTimeLocale format) getZonedTime++dateWithTimeZone :: TimeZone -> String -> IO String+dateWithTimeZone zone format =+ fmap (formatTime defaultTimeLocale format . utcToZonedTime zone) getCurrentTime
changelog.md view
@@ -1,3 +1,17 @@+## Version 0.37 (November, 2020)++_New features_++ - New command line option `--add-font` (Ivan Brennan)+ - New monitor `MPDX` that extends `MPD` with the ability of having a+ custom alias. Useful for connecting with multiple servers.+ - New plugin `NotmuchMail` to monitor mail indexed by `notmuch`.++_Bug fixes_++ - Fix date plugin not picking up DST and timezone changes (refresh+ timezone once a minute to preserve the optimized performace of 0.34).+ ## Version 0.36 (August, 2020) _New features_
readme.md view
@@ -4,7 +4,6 @@ **Table of Contents** - [About](#about)-- [Bug reports](#bug-reports) - [Installation](#installation) - [Using cabal-install](#using-cabal-install) - [From source](#from-source)@@ -46,11 +45,13 @@ - [`Volume Mixer Element Args RefreshRate`](#volume-mixer-element-args-refreshrate) - [`Alsa Mixer Element Args`](#alsa-mixer-element-args) - [`MPD Args RefreshRate`](#mpd-args-refreshrate)+ - [`MPDX Args RefreshRate Alias`](#mpdx-args-refreshrate-alias) - [`Mpris1 PlayerName Args RefreshRate`](#mpris1-playername-args-refreshrate) - [`Mpris2 PlayerName Args RefreshRate`](#mpris2-playername-args-refreshrate) - [`Mail Args Alias`](#mail-args-alias) - [`MailX Args Opts Alias`](#mailx-args-opts-alias) - [`MBox Mboxes Opts Alias`](#mbox-mboxes-opts-alias)+ - [`NotmuchMail Alias Args Rate`](#notmuchmail-alias-args-rate) - [`XPropertyLog PropName`](#xpropertylog-propname) - [`UnsafeXPropertyLog PropName`](#unsafexpropertylog-propname) - [`NamedXPropertyLog PropName Alias`](#namedxpropertylog-propname-alias)@@ -89,29 +90,25 @@ # About Xmobar is a minimalistic status bar. It was originally designed and-implemented by Andrea Rossato to work with [xmonad], but it is-actually usable with any window manager.--Xmobar was inspired by the [Ion3] status bar, and supports similar-features, like dynamic color management, icons, output templates, and-extensibility through plugins.--These are two xmobar instances using the author's configuration:+implemented by Andrea Rossato to work with+[xmonad](http://xmonad.org), but it is actually usable with any window+manager. -+Xmobar was inspired by the [Ion3](http://tuomov.iki.fi/software/)+status bar, and supports similar features, like dynamic color+management, icons, output templates, and extensibility through+plugins. -+These are some xmobar [screenshots](doc/screenshots) using the+author's configuration: -and [this one](doc/xmobar-xmonad.png) is a full desktop with [xmonad]-and, again, two instances of xmobar.+ -[xmonad]: http://xmonad.org-[Ion3]: http://tuomov.iki.fi/software/+ -# Bug reports+ -To submit bug reports you can use the [bug tracker over at-Github](https://github.com/jaor/xmobar/issues).+This is the [changelog](https://xmobar.org/changelog.html) for recent releases. # Installation @@ -186,11 +183,15 @@ use the `xft:` prefix in the `font` configuration option. For instance: + ``` haskell font = "xft:Times New Roman-10:italic"+ ``` Or to have fallback fonts, just separate them by commas: + ``` haskell font = "xft:Open Sans:size=9,WenQuanYi Zen Hei:size=9"+ ``` - `with_mpd` Enables support for the [MPD] daemon. Requires the [libmpd] package.@@ -353,21 +354,29 @@ For example: - position = BottomW C 75+ ``` haskell+ position = BottomW C 75+ ``` to place xmobar at the bottom, centered with the 75% of the screen width. Or - position = BottomP 120 0+ ``` haskell+ position = BottomP 120 0+ ``` to place xmobar at the bottom, with 120 pixel indent of the left. Or - position = Static { xpos = 0 , ypos = 0, width = 1024, height = 15 }+ ``` haskell+ position = Static { xpos = 0 , ypos = 0, width = 1024, height = 15 }+ ``` or - position = Top+ ``` haskell+ position = Top+ ``` - `textOffset` The vertical offset, in pixels, for the text baseline. If negative or not given, xmobar will try to center text@@ -471,39 +480,40 @@ Example: - xmobar -B white -a right -F blue -t '%LIPB%' -c '[Run Weather "LIPB" [] 36000]'+ xmobar -B white -a right -F blue -t '%LIPB%' -c '[Run Weather "LIPB" [] 36000]' This is the list of command line options (the output of xmobar --help): - Usage: xmobar [OPTION...] [FILE]- Options:- -h, -? --help This help- -V --version Show version information- -v --verbose Emit verbose debugging messages- -r --recompile Force recompilation (for Haskell FILE)- -f font name --font=font name Font name- -w class --wmclass=class X11 WM_CLASS property- -n name --wmname=name X11 WM_NAME property- -B bg color --bgcolor=bg color Background color. Default black- -F fg color --fgcolor=fg color Foreground color. Default grey- -A alpha --alpha=alpha Transparency: 0 is transparent- and 255 (the default) is opaque- -o --top Place xmobar at the top of the screen- -b --bottom Place xmobar at the bottom of the screen- -p --position=position Specify position, same as in config file- -d --dock Try to start xmobar as a dock- -a alignsep --alignsep=alignsep Separators for left, center and right text- alignment. Default: '}{'- -s char --sepchar=char Character used to separate commands in- the output template. Default '%'- -t template --template=template Output template- -i path --iconroot=path Default directory for icon pattern files- -c commands --commands=commands List of commands to be executed- -C command --add-command=command Add to the list of commands to be executed- -x screen --screen=screen On which X screen number to start+ Usage: xmobar [OPTION...] [FILE]+ Options:+ -h, -? --help This help+ -V --version Show version information+ -v --verbose Emit verbose debugging messages+ -r --recompile Force recompilation (for Haskell FILE)+ -f font name --font=font name Font name+ -N font name --add-font=font name Add to the list of additional fonts+ -w class --wmclass=class X11 WM_CLASS property+ -n name --wmname=name X11 WM_NAME property+ -B bg color --bgcolor=bg color Background color. Default black+ -F fg color --fgcolor=fg color Foreground color. Default grey+ -A alpha --alpha=alpha Transparency: 0 is transparent+ and 255 (the default) is opaque+ -o --top Place xmobar at the top of the screen+ -b --bottom Place xmobar at the bottom of the screen+ -p --position=position Specify position, same as in config file+ -d --dock Try to start xmobar as a dock+ -a alignsep --alignsep=alignsep Separators for left, center and right text+ alignment. Default: '}{'+ -s char --sepchar=char Character used to separate commands in+ the output template. Default '%'+ -t template --template=template Output template+ -i path --iconroot=path Default directory for icon pattern files+ -c commands --commands=commands List of commands to be executed+ -C command --add-command=command Add to the list of commands to be executed+ -x screen --screen=screen On which X screen number to start - Mail bug reports and suggestions to <mail@jao.io>+ Mail bug reports and suggestions to <mail@jao.io> ## The Output Template@@ -523,7 +533,7 @@ It's possible to insert in the global templates icon directives of the form: - <icon=/path/to/bitmap.xbm/>+ <icon=/path/to/bitmap.xbm/> which will produce the expected result. Accepted image formats are XBM and XPM (when `with_xpm` flag is enabled). If path does not start with@@ -531,7 +541,7 @@ It's also possible to use action directives of the form: - <action=`command` button=12345>+ <action=`command` button=12345> which will be executed when clicked on with specified mouse buttons. This tag can be nested, allowing different commands to be run depending on button clicked.@@ -549,17 +559,23 @@ Example: - [Run Memory ["-t","Mem: <usedratio>%"] 10, Run Swap [] 10]+ ``` haskell+ [Run Memory ["-t","Mem: <usedratio>%"] 10, Run Swap [] 10]+ ``` to run the Memory monitor plugin with the specified template, and the swap monitor plugin, with default options, every second. And here's an example of a template for the commands above using an icon: - template="<icon=/home/jao/.xmobar/mem.xbm/><memory> <swap>"+ ``` haskell+ template="<icon=/home/jao/.xmobar/mem.xbm/><memory> <swap>"+ ``` This example will run "xclock" command when date is clicked: - template="<action=`xclock`>%date%</action>+ ``` haskell+ template="<action=`xclock`>%date%</action>+ ``` The only internal available command is `Com` (see below Executing External Commands). All other commands are provided by plugins. xmobar@@ -590,11 +606,13 @@ as `"%"`, `"%%"` as `"3"`, `"%%%"` as `"3%"`, `"%%%%"` as `"33"` and so on). Essentially it allows to replace vertical bars with custom icons. For example, - Run Brightness- [ "-t", "<ipat>"- , "--"- , "--brightness-icon-pattern", "<icon=bright_%%.xpm/>"- ] 30+ ``` haskell+ Run Brightness+ [ "-t", "<ipat>"+ , "--"+ , "--brightness-icon-pattern", "<icon=bright_%%.xpm/>"+ ] 30+ ``` Will display `bright_0.xpm` to `bright_8.xpm` depending on current brightness value.@@ -729,14 +747,16 @@ Commands' arguments must be set as a list. E.g.: - Run Weather "EGPF" ["-t", "<station>: <tempC>C"] 36000+ ``` haskell+ Run Weather "EGPF" ["-t", "<station>: <tempC>C"] 36000+ ``` In this case xmobar will run the weather monitor, getting information for the weather station ID EGPF (Glasgow Airport, as a homage to GHC) every hour (36000 tenth of seconds), with a template that will output something like: - Glasgow Airport: 16.0C+ Glasgow Airport: 16.0C ## `Uptime Args RefreshRate`@@ -784,24 +804,24 @@ For example: -```haskell- WeatherX "LEBL"- [ ("clear", "🌣")- , ("sunny", "🌣")- , ("mostly clear", "🌤")- , ("mostly sunny", "🌤")- , ("partly sunny", "⛅")- , ("fair", "🌑")- , ("cloudy","☁")- , ("overcast","☁")- , ("partly cloudy", "⛅")- , ("mostly cloudy", "🌧")- , ("considerable cloudiness", "⛈")]- ["-t", "<fn=2><skyConditionS></fn> <tempC>° <rh>% <windKmh> (<hour>)"- , "-L","10", "-H", "25", "--normal", "black"- , "--high", "lightgoldenrod4", "--low", "darkseagreen4"]- 18000-```+ ``` haskell+ WeatherX "LEBL"+ [ ("clear", "🌣")+ , ("sunny", "🌣")+ , ("mostly clear", "🌤")+ , ("mostly sunny", "🌤")+ , ("partly sunny", "⛅")+ , ("fair", "🌑")+ , ("cloudy","☁")+ , ("overcast","☁")+ , ("partly cloudy", "⛅")+ , ("mostly cloudy", "🌧")+ , ("considerable cloudiness", "⛈")]+ ["-t", "<fn=2><skyConditionS></fn> <tempC>° <rh>% <windKmh> (<hour>)"+ , "-L","10", "-H", "25", "--normal", "black"+ , "--high", "lightgoldenrod4", "--low", "darkseagreen4"]+ 18000+ ``` As mentioned, the replacement string can also be an icon specification, such as `("clear", "<icon=weather-clear.xbm/>")`.@@ -917,8 +937,12 @@ ## `Battery Args RefreshRate` -- Same as `BatteryP ["BAT", "BAT0", "BAT1", "BAT2"] Args RefreshRate`.+- Same as + ``` haskell+ BatteryP ["BAT", "BAT0", "BAT1", "BAT2"] Args RefreshRate+ ```+ ## `BatteryP Dirs Args RefreshRate` - Aliases to `battery`@@ -969,15 +993,17 @@ - Example (note that you need "--" to separate regular monitor options from Battery's specific ones): - Run BatteryP ["BAT0"]- ["-t", "<acstatus><watts> (<left>%)",- "-L", "10", "-H", "80", "-p", "3",- "--", "-O", "<fc=green>On</fc> - ", "-i", "",- "-L", "-15", "-H", "-5",- "-l", "red", "-m", "blue", "-h", "green"- "-a", "notify-send -u critical 'Battery running out!!'",- "-A", "3"]- 600+ ``` haskell+ Run BatteryP ["BAT0"]+ ["-t", "<acstatus><watts> (<left>%)",+ "-L", "10", "-H", "80", "-p", "3",+ "--", "-O", "<fc=green>On</fc> - ", "-i", "",+ "-L", "-15", "-H", "-5",+ "-l", "red", "-m", "blue", "-h", "green"+ "-a", "notify-send -u critical 'Battery running out!!'",+ "-A", "3"]+ 600+ ``` In the above example, the thresholds before the "--" separator affect only the `<left>` and `<leftbar>` fields, while those after@@ -990,12 +1016,14 @@ It is also possible to specify template variables in the `-O` and `-o` switches, as in the following example: - Run BatteryP ["BAT0"]- ["-t", "<acstatus>"- , "-L", "10", "-H", "80"- , "-l", "red", "-h", "green"- , "--", "-O", "Charging", "-o", "Battery: <left>%"- ] 10+ ``` haskell+ Run BatteryP ["BAT0"]+ ["-t", "<acstatus>"+ , "-L", "10", "-H", "80"+ , "-l", "red", "-h", "green"+ , "--", "-O", "Charging", "-o", "Battery: <left>%"+ ] 10+ ``` - The "idle" AC state is selected whenever the AC power entering the battery is zero.@@ -1051,9 +1079,11 @@ - Default template: none (you must specify a template for each file system). - Example: - DiskU [("/", "<used>/<size>"), ("sdb1", "<usedbar>")]- ["-L", "20", "-H", "50", "-m", "1", "-p", "3"]- 20+ ``` haskell+ DiskU [("/", "<used>/<size>"), ("sdb1", "<usedbar>")]+ ["-L", "20", "-H", "50", "-m", "1", "-p", "3"]+ 20+ ``` ## `DiskIO Disks Args RefreshRate` @@ -1076,7 +1106,9 @@ - Default template: none (you must specify a template for each file system). - Example: - DiskIO [("/", "<read> <write>"), ("sdb1", "<total>")] [] 10+ ``` haskell+ DiskIO [("/", "<read> <write>"), ("sdb1", "<total>")] [] 10+ ``` ## `ThermalZone Number Args RefreshRate` @@ -1093,7 +1125,9 @@ directory). - Example: - Run ThermalZone 0 ["-t","<id>: <temp>C"] 30+ ``` haskell+ Run ThermalZone 0 ["-t","<id>: <temp>C"] 30+ ``` ## `Thermal Zone Args RefreshRate` @@ -1110,7 +1144,9 @@ Check directories in /proc/acpi/thermal_zone for possible values. - Example: - Run Thermal "THRM" ["-t","iwl4965-temp: <temp>C"] 50+ ``` haskell+ Run Thermal "THRM" ["-t","iwl4965-temp: <temp>C"] 50+ ``` ## `CpuFreq Args RefreshRate` @@ -1123,8 +1159,10 @@ - This monitor requires acpi_cpufreq module to be loaded in kernel - Example: - Run CpuFreq ["-t", "Freq:<cpu0>|<cpu1>GHz", "-L", "0", "-H", "2",- "-l", "lightblue", "-n","white", "-h", "red"] 50+ ``` haskell+ Run CpuFreq ["-t", "Freq:<cpu0>|<cpu1>GHz", "-L", "0", "-H", "2",+ "-l", "lightblue", "-n","white", "-h", "red"] 50+ ``` ## `CoreTemp Args RefreshRate` @@ -1137,9 +1175,11 @@ - This monitor requires coretemp module to be loaded in kernel - Example: - Run CoreTemp ["-t", "Temp:<core0>|<core1>C",- "-L", "40", "-H", "60",- "-l", "lightblue", "-n", "gray90", "-h", "red"] 50+ ``` haskell+ Run CoreTemp ["-t", "Temp:<core0>|<core1>C",+ "-L", "40", "-H", "60",+ "-l", "lightblue", "-n", "gray90", "-h", "red"] 50+ ``` ## `MultiCoreTemp Args RefreshRate` @@ -1173,10 +1213,12 @@ - This monitor requires coretemp module to be loaded in kernel - Example: - Run MultiCoreTemp ["-t", "Temp: <avg>°C | <avgpc>%",- "-L", "60", "-H", "80",- "-l", "green", "-n", "yellow", "-h", "red",- "--", "--mintemp", "20", "--maxtemp", "100"] 50+ ``` haskell+ Run MultiCoreTemp ["-t", "Temp: <avg>°C | <avgpc>%",+ "-L", "60", "-H", "80",+ "-l", "green", "-n", "yellow", "-h", "red",+ "--", "--mintemp", "20", "--maxtemp", "100"] 50+ ``` ## `Volume Mixer Element Args RefreshRate` @@ -1274,10 +1316,16 @@ - Example (note that you need "--" to separate regular monitor options from MPD's specific ones): - Run MPD ["-t",- "<composer> <title> (<album>) <track>/<plength> <statei> [<flags>]",- "--", "-P", ">>", "-Z", "|", "-S", "><"] 10+ ``` haskell+ Run MPD ["-t",+ "<composer> <title> (<album>) <track>/<plength> <statei> [<flags>]",+ "--", "-P", ">>", "-Z", "|", "-S", "><"] 10+ ``` +## `MPDX Args RefreshRate Alias`++Like `MPD` but uses as alias its last argument instead of "mpd".+ ## `Mpris1 PlayerName Args RefreshRate` - Aliases to `mpris1`@@ -1292,7 +1340,9 @@ - Default template: `<artist> - <title>` - Example: - Run Mpris1 "clementine" ["-t", "<artist> - [<tracknumber>] <title>"] 10+ ``` haskell+ Run Mpris1 "clementine" ["-t", "<artist> - [<tracknumber>] <title>"] 10+ ``` ## `Mpris2 PlayerName Args RefreshRate` @@ -1309,7 +1359,9 @@ - Default template: `<artist> - <title>` - Example: - Run Mpris2 "spotify" ["-t", "<artist> - [<composer>] <title>"] 10+ ``` haskell+ Run Mpris2 "spotify" ["-t", "<artist> - [<composer>] <title>"] 10+ ``` ## `Mail Args Alias` @@ -1321,9 +1373,11 @@ during compilation. - Example: - Run Mail [("inbox", "~/var/mail/inbox"),- ("lists", "~/var/mail/lists")]- "mail"+ ``` haskell+ Run Mail [("inbox", "~/var/mail/inbox"),+ ("lists", "~/var/mail/lists")]+ "mail"+ ``` ## `MailX Args Opts Alias` @@ -1343,11 +1397,12 @@ during compilation. - Example: - Run MailX [("I", "inbox", "green"),- ("L", "lists", "orange")]- ["-d", "~/var/mail", "-p", " ", "-s", " "]- "mail"-+ ``` haskell+ Run MailX [("I", "inbox", "green"),+ ("L", "lists", "orange")]+ ["-d", "~/var/mail", "-p", " ", "-s", " "]+ "mail"+ ``` ## `MBox Mboxes Opts Alias` @@ -1373,9 +1428,89 @@ (when it's not empty); it can be used in the template with the alias `mbox`: - Run MBox [("I ", "inbox", "red"), ("O ", "~/foo/mbox", "")]- ["-d", "/var/mail/", "-p", " "] "mbox"+ ``` haskell+ Run MBox [("I ", "inbox", "red"), ("O ", "~/foo/mbox", "")]+ ["-d", "/var/mail/", "-p", " "] "mbox"+ ``` +## `NotmuchMail Alias Args Rate`++This plugin checks for new mail, provided that this mail is indexed by+`notmuch`. In the `notmuch` spirit, this plugin checks for new+**threads** and not new individual messages.++- Alias: What name the plugin should have in your template string.+- Args: A list of `MailItem`s of the form++ ``` haskell+ [ MailItem "name" "address" "query"+ ...+ ]+ ```++ or, using explicit record syntax:++ ``` haskell+ [ MailItem+ { name = "name"+ , address = "address"+ , query = "query"+ }+ ...+ ]+ ```++ where++ - `name` is what gets printed in the status bar before the number+ of new threads.+ - `address` is the e-mail address of the recipient, i.e. we only+ query mail that was send to this particular address (in more+ concrete terms, we pass the address to the `to:` constructor when+ performing the search). If `address` is empty, we search through+ all unread mail, regardless of whom it was sent to.+ - `query` is funneled to `notmuch search` verbatim. For the general+ query syntax, consult `notmuch search --help`, as well as+ `notmuch-search-terms(7)`. Note that the `unread` tag is+ **always** added in front of the query and composed with it via an+ **and**.++- Rate: Rate with which to update the plugin (in deciseconds).+- Example:++ - A single `MailItem` that displays all unread threads from the given+ address:++ ``` haskell+ MailItem "mbs:" "soliditsallgood@mailbox.org" ""+ ```++ - A single `MailItem` that displays all unread threads with+ "[My-Subject]" somewhere in the title:++ ``` haskell+ MailItem "S:" "" "subject:[My-Subject]"+ ```++ - A full example of a `NotmuchMail` configuration:++ ``` haskell+ Run NotmuchMail "mail" -- name for the template string+ [ -- All unread mail to the below address, but nothing that's tagged+ -- with @lists@ or @haskell@.+ MailItem "mbs:"+ "soliditsallgood@mailbox.org"+ "not tag:lists and not tag:haskell"++ -- All unread mail that has @[Haskell-Cafe]@ in the subject line.+ , MailItem "C:" "" "subject:[Haskell-Cafe]"++ -- All unread mail that's tagged as @lists@, but not @haskell@.+ , MailItem "H:" "" "tag:lists and not tag:haskell"+ ]+ 600 -- update every 60 seconds+ ```+ ## `XPropertyLog PropName` - Aliases to `PropName`@@ -1420,7 +1555,9 @@ - Default template: `<percent>` - Example: - Run Brightness ["-t", "<bar>"] 60+ ``` haskell+ Run Brightness ["-t", "<bar>"] 60+ ``` ## `Kbd Opts` @@ -1432,7 +1569,9 @@ - second element of the tuple is the corresponding replacement - Example: - Run Kbd [("us(dvorak)", "DV"), ("us", "US")]+ ``` haskell+ Run Kbd [("us(dvorak)", "DV"), ("us", "US")]+ ``` ## `Locks` @@ -1440,7 +1579,9 @@ - Aliases to `locks` - Example: - Run Locks+ ``` haskell+ Run Locks+ ``` ## `CatInt n filename` @@ -1450,7 +1591,9 @@ have several. - Example: - Run CatInt 0 "/sys/devices/platform/thinkpad_hwmon/fan1_input" [] 50+ ``` haskell+ Run CatInt 0 "/sys/devices/platform/thinkpad_hwmon/fan1_input" [] 50+ ``` ## `UVMeter` @@ -1469,7 +1612,9 @@ http://www.arpansa.gov.au/uvindex/realtime/xml/uvvalues.xml - Example: + ``` haskell Run UVMeter "Brisbane" ["-H", "3", "-L", "3", "--low", "green", "--high", "red"] 900+ ``` # Executing External Commands @@ -1490,12 +1635,16 @@ E.g.: - Run Com "uname" ["-s","-r"] "" 0+ ``` haskell+ Run Com "uname" ["-s","-r"] "" 0+ ``` can be used in the output template as `%uname%` (and xmobar will call _uname_ only once), while - Run Com "date" ["+\"%a %b %_d %H:%M\""] "mydate" 600+ ``` haskell+ Run Com "date" ["+\"%a %b %_d %H:%M\""] "mydate" 600+ ``` can be used in the output template as `%mydate%`. @@ -1508,7 +1657,9 @@ Works like `Com`, but displaying `ExitMessage` (a string) if the execution fails. For instance: - Run ComX "date" ["+\"%a %b %_d %H:%M\""] "N/A" "mydate" 600+ ``` haskell+ Run ComX "date" ["+\"%a %b %_d %H:%M\""] "N/A" "mydate" 600+ ``` will display "N/A" if for some reason the `date` invocation fails. @@ -1539,8 +1690,13 @@ - 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`+- Timezone changes are picked up automatically every minute.+- Sample usage: + ``` haskell+ Run Date "%a %b %_d %Y <fc=#ee9a00>%H:%M:%S</fc>" "date" 10+ ```+ ## `DateZone Format Locale Zone Alias RefreshRate` - Format is a time format string, as accepted by the standard ISO C@@ -1552,8 +1708,11 @@ in /usr/share/zoneinfo/. If "" is given as Zone, the default system time is used. - Sample usage:- `Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "Europe/Vienna" "viennaTime" 10` + ``` haskell+ Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "Europe/Vienna" "viennaTime" 10+ ```+ ## `CommandReader "/path/to/program" Alias` - Runs the given program, and displays its standard output.@@ -1570,7 +1729,9 @@ - Text is displayed as marquee with the specified length, rate in 10th seconds and separator when it wraps around + ``` haskell Run MarqueePipeReader "/tmp/testpipe" (10, 7, "+") "mpipe"+ ``` - Expands environment variables in the first argument @@ -1590,10 +1751,12 @@ - Use it for OSD-like status bars e.g. for setting the volume or brightness: + ``` haskell Run BufferedPipeReader "bpr" [ ( 0, False, "/tmp/xmobar_window" ) , ( 15, True, "/tmp/xmobar_status" ) ]+ ``` Have your window manager send window titles to `"/tmp/xmobar_window"`. They will always be shown and not reveal@@ -1613,11 +1776,14 @@ property by using `xmonadPropLog` as your log hook in xmonad's configuration, as in the following example (more info [here]): + ``` haskell main = do spawn "xmobar" xmonad $ defaultConfig { logHook = dynamicLogString defaultPP >>= xmonadPropLog }+ ```+ This plugin can be used as a sometimes more convenient alternative to `StdinReader`. For instance, it allows you to (re)start xmobar outside xmonad.@@ -1632,10 +1798,12 @@ - It is advised that you still use `xmobarStrip` for the ppTitle in your logHook: + ``` haskell myPP = defaultPP { ppTitle = xmobarStrip } main = xmonad $ defaultConfig { logHook = dynamicLogString myPP >>= xmonadPropLog }+ ``` ## `HandleReader Handle Alias` @@ -1646,12 +1814,14 @@ Handles. Pass the `read` Handle to HandleReader and write your output to the `write` Handle: + ``` haskell (readHandle, writeHandle) <- createPipe xmobarProcess <- forkProcess $ xmobar myConfig { commands = Run (HandleReader readHandle "handle") : commands myConfig } hPutStr writeHandle "Hello World"+ ``` # The DBus Interface @@ -1697,7 +1867,9 @@ Bind the key which should {,un}map xmobar to a dummy value. This is necessary for {,un}grabKey in xmonad. - ((0, xK_Alt_L ), return ())+ ``` haskell+ ((0, xK_Alt_L ), return ())+ ``` Also, install `avoidStruts` layout modifier from `XMonad.Hooks.ManageDocks` @@ -1705,53 +1877,55 @@ `myDocksEventHook` is a replacement for `docksEventHook` which reacts on unmap events as well (which `docksEventHook` doesn't). - import qualified XMonad.Util.ExtensibleState as XS+ ``` haskell+ import qualified XMonad.Util.ExtensibleState as XS - data DockToggleTime = DTT { lastTime :: Time } deriving (Eq, Show, Typeable)+ data DockToggleTime = DTT { lastTime :: Time } deriving (Eq, Show, Typeable) - instance ExtensionClass DockToggleTime where- initialValue = DTT 0+ instance ExtensionClass DockToggleTime where+ initialValue = DTT 0 - toggleDocksHook :: Int -> KeySym -> Event -> X All- toggleDocksHook to ks ( KeyEvent { ev_event_display = d- , ev_event_type = et- , ev_keycode = ekc- , ev_time = etime- } ) =- io (keysymToKeycode d ks) >>= toggleDocks >> return (All True)- where- toggleDocks kc- | ekc == kc && et == keyPress = do- safeSendSignal ["Reveal 0", "TogglePersistent"]- XS.put ( DTT etime )- | ekc == kc && et == keyRelease = do- gap <- XS.gets ( (-) etime . lastTime )- safeSendSignal [ "TogglePersistent"- , "Hide " ++ show (if gap < 400 then to else 0)- ]- | otherwise = return ()+ toggleDocksHook :: Int -> KeySym -> Event -> X All+ toggleDocksHook to ks ( KeyEvent { ev_event_display = d+ , ev_event_type = et+ , ev_keycode = ekc+ , ev_time = etime+ } ) =+ io (keysymToKeycode d ks) >>= toggleDocks >> return (All True)+ where+ toggleDocks kc+ | ekc == kc && et == keyPress = do+ safeSendSignal ["Reveal 0", "TogglePersistent"]+ XS.put ( DTT etime )+ | ekc == kc && et == keyRelease = do+ gap <- XS.gets ( (-) etime . lastTime )+ safeSendSignal [ "TogglePersistent"+ , "Hide " ++ show (if gap < 400 then to else 0)+ ]+ | otherwise = return () - safeSendSignal s = catchX (io $ sendSignal s) (return ())- sendSignal = withSession . callSignal- withSession mc = connectSession >>= \c -> callNoReply c mc >> disconnect c- callSignal :: [String] -> MethodCall- callSignal s = ( methodCall- ( objectPath_ "/org/Xmobar/Control" )- ( interfaceName_ "org.Xmobar.Control" )- ( memberName_ "SendSignal" )- ) { methodCallDestination = Just $ busName_ "org.Xmobar.Control"- , methodCallBody = map toVariant s- }+ safeSendSignal s = catchX (io $ sendSignal s) (return ())+ sendSignal = withSession . callSignal+ withSession mc = connectSession >>= \c -> callNoReply c mc >> disconnect c+ callSignal :: [String] -> MethodCall+ callSignal s = ( methodCall+ ( objectPath_ "/org/Xmobar/Control" )+ ( interfaceName_ "org.Xmobar.Control" )+ ( memberName_ "SendSignal" )+ ) { methodCallDestination = Just $ busName_ "org.Xmobar.Control"+ , methodCallBody = map toVariant s+ } - toggleDocksHook _ _ _ = return (All True)+ toggleDocksHook _ _ _ = return (All True) - myDocksEventHook :: Event -> X All- myDocksEventHook e = do- when (et == mapNotify || et == unmapNotify) $- whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) refresh- return (All True)- where w = ev_window e+ myDocksEventHook :: Event -> X All+ myDocksEventHook e = do+ when (et == mapNotify || et == unmapNotify) $+ whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) refresh+ return (All True)+ where w = ev_window e et = ev_event_type e+ ``` # User plugins @@ -1764,10 +1938,12 @@ defining the 1 needed method (alternatively `start` or `run`) and 2 optional ones (alias and rate): - start :: e -> (String -> IO ()) -> IO ()- run :: e -> IO String- rate :: e -> Int- alias :: e -> String+ ``` haskell+ start :: e -> (String -> IO ()) -> IO ()+ run :: e -> IO String+ rate :: e -> Int+ alias :: e -> String+ ``` `start` must receive a callback to be used to display the `String` produced by the plugin. This method can be used for plugins that need@@ -1783,16 +1959,18 @@ Notice that Date could be implemented as: - instance Exec Date where- alias (Date _ a _) = a- start (Date f _ r) = date f r+ ``` haskell+ instance Exec Date where+ alias (Date _ a _) = a+ start (Date f _ r) = date f r - date :: String -> Int -> (String -> IO ()) -> IO ()- date format r callback = do go- where go = do- t <- toCalendarTime =<< getClockTime- callback $ formatCalendarTime defaultTimeLocale format t- tenthSeconds r >> go+ date :: String -> Int -> (String -> IO ()) -> IO ()+ date format r callback = do go+ where go = do+ t <- toCalendarTime =<< getClockTime+ callback $ formatCalendarTime defaultTimeLocale format t+ tenthSeconds r >> go+ ``` This implementation is equivalent to the one you can read in `Plugins/Date.hs`.@@ -1813,8 +1991,9 @@ When xmobar runs with the full path to that Haskell file as its argument (or if you put it in `~/.config/xmobar/xmobar.hs`), and with-the xmobar library installed, the Haskell code will be compiled as-needed, and the new executable spawned for you.+the xmobar library installed (e.g., with `cabal install --lib xmobar`),+the Haskell code will be compiled as needed, and the new executable+spawned for you. That's it! @@ -1828,14 +2007,15 @@ # Authors and credits Andrea Rossato originally designed and implemented xmobar up to-version 0.11.1. Since then, it is maintained and developed by [jao],-with the help of the greater xmobar and Haskell communities.+version 0.11.1. Since then, it is maintained and developed by+[jao](https://jao.io), with the help of the greater xmobar and Haskell+communities. -In particular, xmobar [incorporates patches] by Mohammed Alshiekh,-Alex Ameen, Axel Angel, Dhananjay Balan, Claudio Bley, Dragos Boca,-Ben Boeckel, Duncan Burke, Roman Cheplyaka, Patrick Chilton, Antoine-Eiche, Nathaniel Wesley Filardo, John Goerzen, Reto Hablützel, Juraj-Hercek, Tomáš Janoušek, Ada Joule, Spencer Janssen, Roman Joost,+In particular, xmobar incorporates patches by Mohammed Alshiekh, Alex+Ameen, Axel Angel, Dhananjay Balan, Claudio Bley, Dragos Boca, Ben+Boeckel, Ivan Brennan, Duncan Burke, Roman Cheplyaka, Patrick Chilton,+Antoine Eiche, Nathaniel Wesley Filardo, John Goerzen, Reto Hablützel,+Juraj Hercek, Tomáš Janoušek, Ada Joule, Spencer Janssen, Roman Joost, Jochen Keil, Lennart Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Todd Lunter, Vanessa McHale, Robert J. Macomber, Dmitry Malikov, David McLean, Marcin Mikołajczyk, Dino Morelli, Tony Morris,@@ -1849,9 +2029,6 @@ 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- ## Thanks __Andrea Rossato__:@@ -1873,11 +2050,7 @@ - To understand the internal mysteries of xmobar you may try reading [this tutorial] on X Window Programming in Haskell. -- My [sawflibs] project includes a module to automate running xmobar- in [sawfish].- [this tutorial]: http://www.haskell.org/haskellwiki/X_window_programming_in_Haskell-[sawflibs]: http://github.com/jaor/sawflibs # License
src/Xmobar.hs view
@@ -39,6 +39,7 @@ , module Xmobar.Plugins.Mail , module Xmobar.Plugins.MBox #endif+ , module Xmobar.Plugins.NotmuchMail , module Xmobar.Plugins.Monitors , module Xmobar.Plugins.PipeReader , module Xmobar.Plugins.MarqueePipeReader@@ -70,6 +71,7 @@ import Xmobar.Plugins.StdinReader import Xmobar.Plugins.MarqueePipeReader import Xmobar.Plugins.XMonadLog+import Xmobar.Plugins.NotmuchMail import Xmobar.App.Main(xmobar, xmobarMain, configFromArgs) import Xmobar.App.Config(defaultConfig)
src/Xmobar/App/Config.hs view
@@ -21,6 +21,7 @@ xmobarConfigFile) where import Control.Monad (when, filterM)+import Data.Functor ((<&>)) import System.Environment import System.Directory@@ -105,7 +106,7 @@ go [] = return Nothing go (x:xs) = do exists <- x >>= doesDirectoryExist- if exists then x >>= return . Just else go xs+ if exists then x <&> Just else go xs -- | Simple wrapper around @findFirstDirOf@ that allows the primary -- path to be specified by an environment variable.
src/Xmobar/App/EventLoop.hs view
@@ -70,7 +70,7 @@ runX xc f = runReaderT f xc newRefreshLock :: IO (TMVar ())-newRefreshLock = atomically $ newTMVar ()+newRefreshLock = newTMVarIO () refreshLock :: TMVar () -> IO a -> IO a refreshLock var = bracket_ lock unlock@@ -95,7 +95,7 @@ #ifdef XFT xftInitFtLibrary #endif- tv <- atomically $ newTVar []+ tv <- newTVarIO [] _ <- forkIO (handle (handler "checker") (checker tv [] vs sig pauser)) #ifdef THREADED_RUNTIME _ <- forkOS (handle (handler "eventer") (eventer sig))@@ -238,10 +238,10 @@ -> (Runnable,String,String) -> IO ([Async ()], TVar String) startCommand sig (com,s,ss)- | alias com == "" = do var <- atomically $ newTVar is+ | alias com == "" = do var <- newTVarIO is atomically $ writeTVar var (s ++ ss) return ([], var)- | otherwise = do var <- atomically $ newTVar is+ | otherwise = do var <- newTVarIO is let cb str = atomically $ writeTVar var (s ++ str ++ ss) a1 <- async $ start com cb a2 <- async $ trigger com $ maybe (return ())
src/Xmobar/App/Main.hs view
@@ -63,7 +63,7 @@ let ic = Map.empty to = textOffset conf ts = textOffsets conf ++ replicate (length fl) (-1)- startLoop (XConf d r w (fs :| fl) (to:ts) ic conf) sig refLock vars+ startLoop (XConf d r w (fs :| fl) (to :| ts) ic conf) sig refLock vars configFromArgs :: Config -> IO Config configFromArgs cfg = getArgs >>= getOpts >>= doOpts cfg . fst
src/Xmobar/App/Opts.hs view
@@ -31,6 +31,7 @@ | Recompile | Version | Font String+ | AddFont String | BgColor String | FgColor String | Alpha String@@ -56,6 +57,7 @@ , Option "r" ["recompile"] (NoArg Recompile) "Force recompilation" , Option "V" ["version"] (NoArg Version) "Show version information" , Option "f" ["font"] (ReqArg Font "font name") "Font name"+ , Option "N" ["add-font"] (ReqArg AddFont "font name") "Add to the list of additional fonts" , Option "w" ["wmclass"] (ReqArg WmClass "class") "X11 WM_CLASS property" , Option "n" ["wmname"] (ReqArg WmName "name") "X11 WM_NAME property" , Option "B" ["bgcolor"] (ReqArg BgColor "bg color" )@@ -127,6 +129,7 @@ Recompile -> doOpts' conf Verbose -> doOpts' (conf {verbose = True}) Font s -> doOpts' (conf {font = s})+ AddFont s -> doOpts' (conf {additionalFonts = additionalFonts conf ++ [s]}) WmClass s -> doOpts' (conf {wmClass = s}) WmName s -> doOpts' (conf {wmName = s}) BgColor s -> doOpts' (conf {bgColor = s})
src/Xmobar/App/Timer.hs view
@@ -2,7 +2,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.App.Timer--- Copyright: (c) 2019 Tomáš Janoušek+-- Copyright: (c) 2019, 2020 Tomáš Janoušek -- License: BSD3-style (see LICENSE) -- -- Maintainer: Tomáš Janoušek <tomi@nomi.cz>@@ -54,7 +54,7 @@ newPeriod r = do u <- newUnique t <- now- v <- atomically newEmptyTMVar+ v <- newEmptyTMVarIO let t' = t - t `mod` r return (u, Period { rate = r, next = t', tick = v }) @@ -212,7 +212,7 @@ delay = (tNext - tNow) `min` fromIntegral maxDelay delayUsec = fromIntegral delay * 100000 registerDelay delayUsec- Nothing -> atomically $ newTVar False+ Nothing -> newTVarIO False atomically $ do delayOver <- readTVar delayVar periods' <- fromJust <$> readTVar periodsVar
src/Xmobar/Config/Parse.hs view
@@ -2,7 +2,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Config.Parse--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2020 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -22,6 +22,7 @@ import Text.ParserCombinators.Parsec.Number (int) import Text.ParserCombinators.Parsec.Perm ((<|?>), (<$?>), permute) import Control.Monad.IO.Class (liftIO)+import Data.Functor ((<&>)) import Xmobar.Config.Types @@ -174,4 +175,4 @@ -- parsed. readConfig :: Config -> FilePath -> IO (Either ParseError (Config,[String])) readConfig defaultConfig f =- liftIO (readFileSafe f) >>= return . parseConfig defaultConfig+ liftIO (readFileSafe f) <&> parseConfig defaultConfig
src/Xmobar/Plugins/Date.hs view
@@ -17,14 +17,16 @@ -- ----------------------------------------------------------------------------- -module Xmobar.Plugins.Date (Date(..)) where+module Xmobar.Plugins.Date (Date(..), date) where import Xmobar.Run.Exec #if ! MIN_VERSION_time(1,5,0) import System.Locale #endif+import Data.IORef import Data.Time+import Control.Concurrent.Async (concurrently_) data Date = Date String String Int deriving (Read, Show)@@ -32,15 +34,18 @@ instance Exec Date where alias (Date _ a _) = a rate (Date _ _ r) = r- start (Date f _ r) cb = do- t <- getCurrentTime- zone <- getTimeZone t- go zone- where- go zone = doEveryTenthSeconds r $ date zone f >>= cb+ start (Date f _ r) cb =+ -- refresh time zone once a minute to avoid wasting CPU cycles+ withRefreshingZone 600 $ \zone ->+ doEveryTenthSeconds r $ date zone f >>= cb -date :: TimeZone -> String -> IO String-date timezone format = do- time <- getCurrentTime- let zonedTime = utcToZonedTime timezone time- pure $ formatTime defaultTimeLocale format zonedTime+date :: IORef TimeZone -> String -> IO String+date zoneRef format = do+ zone <- readIORef zoneRef+ fmap (formatTime defaultTimeLocale format . utcToZonedTime zone) getCurrentTime++withRefreshingZone :: Int -> (IORef TimeZone -> IO ()) -> IO ()+withRefreshingZone r action = do+ zone <- newIORef =<< getCurrentTimeZone+ let refresh = atomicWriteIORef zone =<< getCurrentTimeZone+ concurrently_ (doEveryTenthSeconds r refresh) (action zone)
src/Xmobar/Plugins/Monitors.hs view
@@ -3,7 +3,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Xmobar.Plugins.Monitors--- Copyright : (c) 2010, 2011, 2012, 2013, 2017, 2018, 2019 Jose Antonio Ortega Ruiz+-- Copyright : (c) 2010, 2011, 2012, 2013, 2017, 2018, 2019, 2020 Jose Antonio Ortega Ruiz -- (c) 2007-10 Andrea Rossato -- License : BSD-style (see LICENSE) --@@ -89,7 +89,8 @@ | Wireless Interface Args Rate #endif #ifdef LIBMPD- | MPD Args Rate+ | MPD Args Rate+ | MPDX Args Rate Alias | AutoMPD Args #endif #ifdef ALSA@@ -148,6 +149,7 @@ #ifdef LIBMPD alias (MPD _ _) = "mpd" alias (AutoMPD _) = "autompd"+ alias (MPDX _ _ a) = a #endif #ifdef ALSA alias (Volume m c _ _) = m ++ ":" ++ c@@ -191,6 +193,7 @@ #endif #ifdef LIBMPD start (MPD a r) = runMD a mpdConfig runMPD r mpdReady+ start (MPDX a r _) = start (MPD a r) start (AutoMPD a) = runMBD a mpdConfig runMPD mpdWait mpdReady #endif #ifdef ALSA
+ src/Xmobar/Plugins/NotmuchMail.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE ScopedTypeVariables #-}++-----------------------------------------------------------------------------+-- |+-- Module : Xmobar.Plugins.NotmuchMail+-- Copyright : (c) slotThe+-- License : BSD-style (see LICENSE)+--+-- Maintainer : slotThe <soliditsallgood@mailbox.org>+-- Stability : unstable+-- Portability : unportable+--+-- This plugin checks for new mail, provided that this mail is indexed+-- by @notmuch@. You can think of it as a thin wrapper around the+-- functionality provided by @notmuch search@.+--+-- As mail that was tagged is moved from the @new@ directory to @cur@,+-- the @inotify@ solution that he mail 'Mail' plugin (and its variants)+-- uses won't work for such mail. Hence, we have to resort to a+-- refresh-based monitor.+--+-- Note that, in the `notmuch` spirit, this plugin checks for new+-- threads and not new individual messages. For convenience, the+-- @unread@ tag is added before the user query (compose via an @and@).+--+-----------------------------------------------------------------------------++module Xmobar.Plugins.NotmuchMail+ ( -- * Types+ MailItem(..) -- instances: Read, Show+ , NotmuchMail(..) -- instances: Read, Show+ ) where++import Xmobar.Run.Exec (Exec(alias, rate, run))++import Control.Concurrent.Async (mapConcurrently)+import Data.Maybe (catMaybes)+import System.Exit (ExitCode(ExitSuccess))+import System.Process (readProcessWithExitCode)+++-- | A 'MailItem' is a name, an address, and a query to give to @notmuch@.+data MailItem = MailItem+ { name :: String -- ^ Display name for the item in the bar+ , address :: String -- ^ Only check for mail sent to this address; may be+ -- the empty string to query all indexed mail instead+ , query :: String -- ^ Query to give to @notmuch search@+ }+ deriving (Read, Show)++-- | A full mail configuration.+data NotmuchMail = NotmuchMail+ { nmAlias :: String -- ^ Alias for the template string+ , mailItems :: [MailItem] -- ^ 'MailItem's to check+ , nmRate :: Int -- ^ Update frequency (in deciseconds)+ }+ deriving (Read, Show)++-- | How to execute this plugin.+instance Exec NotmuchMail where+ -- | How often to update the plugin (in deciseconds).+ rate :: NotmuchMail -> Int+ rate NotmuchMail{ nmRate } = nmRate++ -- | How to alias the plugin in the template string.+ alias :: NotmuchMail -> String+ alias NotmuchMail{ nmAlias } = nmAlias++ -- | Run the plugin exactly once.+ run :: NotmuchMail -> IO String+ run NotmuchMail{ mailItems } =+ unwords . catMaybes <$> mapConcurrently notmuchSpawn mailItems+ where+ -- | Given a single 'MailItem', shell out to @notmuch@ and get the number+ -- of unread mails, then decide whether what we have is worth printing.+ notmuchSpawn :: MailItem -> IO (Maybe String)+ = \MailItem{ address, name, query } -> do+ -- Shell out to @notmuch@+ let args = [ "search"+ , tryAdd "to:" address+ , "tag:unread", tryAdd "and " query+ ]+ (exitCode, out, _) <- readProcessWithExitCode "notmuch" args []++ -- Only print something when there is at least _some_ new mail+ let numThreads = length (lines out)+ pure $!+ (name <>) . show <$> if exitCode /= ExitSuccess || numThreads < 1+ then Nothing+ else Just numThreads++ -- | Only add something to a 'String' if it's not empty.+ tryAdd :: String -> String -> String+ = \prefix str -> if null str then "" else prefix <> str
src/Xmobar/Plugins/StdinReader.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE ViewPatterns #-}+ ----------------------------------------------------------------------------- -- | -- Module : Plugins.StdinReader@@ -22,30 +24,31 @@ import System.Posix.Process import System.Exit import System.IO+import System.IO.Error (isEOFError) import Xmobar.Run.Exec import Xmobar.X11.Actions (stripActions)-import Xmobar.System.Utils (onSomeException)-import Control.Monad (when)+import Control.Exception+import Control.Monad (forever) data StdinReader = StdinReader | UnsafeStdinReader deriving (Read, Show) instance Exec StdinReader where- start stdinReader cb = do- -- The EOF check is necessary for certain systems- -- More details here https://github.com/jaor/xmobar/issues/442- eof <- isEOF- when eof $- do hPrint stderr "xmobar: eof at an early stage"- exitImmediately ExitSuccess- s <-- getLine `onSomeException`- (\e -> do- let errorMessage = "xmobar: Received exception " <> show e- hPrint stderr errorMessage- cb errorMessage)- cb $ escape stdinReader s- start stdinReader cb+ start stdinReader cb = forever $ (cb . escape stdinReader =<< getLine) `catch` handler+ where+ -- rethrow async exceptions like ThreadKilled, etc.+ handler (fromException -> Just e) = throwIO (e :: SomeAsyncException)+ -- XMonad.Hooks.DynamicLog.statusBar starts new xmobar on every xmonad+ -- reload and the old xmobar is only signalled to exit via the pipe+ -- being closed, so we must unconditionally terminate on EOF, otherwise+ -- there'd be a pileup of xmobars+ handler (fromException -> Just e) | isEOFError e = exitImmediately ExitSuccess+ -- any other exception, like "invalid argument (invalid byte sequence)",+ -- is logged to both stderr and the bar itself+ handler e = do+ let errorMessage = "xmobar: Received exception " <> show e+ hPutStrLn stderr errorMessage+ cb $ stripActions errorMessage escape :: StdinReader -> String -> String escape StdinReader = stripActions
src/Xmobar/System/Utils.hs view
@@ -20,7 +20,6 @@ module Xmobar.System.Utils ( expandHome , changeLoop- , onSomeException , safeIndex ) where @@ -31,7 +30,6 @@ import System.Environment import System.FilePath-import Control.Exception expandHome :: FilePath -> IO FilePath expandHome ('~':'/':path) = fmap (</> path) (getEnv "HOME")@@ -46,15 +44,6 @@ new <- s guard (new /= old) return new)---- | Like 'finally', but only performs the final action if there was an--- exception raised by the computation.------ Note that this implementation is a slight modification of--- onException function.-onSomeException :: IO a -> (SomeException -> IO b) -> IO a-onSomeException io what = io `catch` \e -> do _ <- what e- throwIO (e :: SomeException) (!!?) :: [a] -> Int -> Maybe a (!!?) xs i
src/Xmobar/X11/Draw.hs view
@@ -131,7 +131,7 @@ #endif -- | An easy way to print the stuff we need to print-printStrings :: Drawable -> GC -> NE.NonEmpty XFont -> [Int] -> Position+printStrings :: Drawable -> GC -> NE.NonEmpty XFont -> NE.NonEmpty Int -> Position -> Align -> [((Position, Position), Box)] -> [(Widget, TextRenderInfo, Int, Position)] -> X () printStrings _ _ _ _ _ _ _ [] = return () printStrings dr gc fontlist voffs offs a boxes sl@((s,c,i,l):xs) = do@@ -142,6 +142,7 @@ totSLen = foldr (\(_,_,_,len) -> (+) len) 0 sl remWidth = fi wid - fi totSLen fontst = safeIndex fontlist i+ voff = safeIndex voffs i offset = case a of C -> (remWidth + offs) `div` 2 R -> remWidth@@ -149,7 +150,7 @@ (fc,bc) = case break (==',') (tColorsString c) of (f,',':b) -> (f, b ) (f, _) -> (f, bgColor conf)- valign <- verticalOffset ht s (NE.head fontlist) (voffs !! i) conf+ valign <- verticalOffset ht s fontst voff conf let (ht',ay) = case (tBgTopOffset c, tBgBottomOffset c) of (-1,_) -> (0, -1) (_,-1) -> (0, -1)
src/Xmobar/X11/Types.hs view
@@ -35,7 +35,7 @@ , rect :: Rectangle , window :: Window , fontListS :: NE.NonEmpty XFont- , verticalOffsets :: [Int]+ , verticalOffsets :: NE.NonEmpty Int , iconS :: Map FilePath Bitmap , config :: Config }
test/Xmobar/Plugins/Monitors/CpuSpec.hs view
@@ -23,7 +23,7 @@ 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)+ cpuValue `shouldSatisfy` (all (`elem` ":#") . last . words) 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
xmobar.cabal view
@@ -1,5 +1,5 @@ name: xmobar-version: 0.36+version: 0.37 homepage: http://xmobar.org synopsis: A Minimalistic Text Based Status Bar description: Xmobar is a minimalistic text based status bar.@@ -140,6 +140,7 @@ Xmobar.Plugins.XMonadLog, Xmobar.Plugins.Kbd, Xmobar.Plugins.Locks,+ Xmobar.Plugins.NotmuchMail, Xmobar.Plugins.Monitors, Xmobar.Plugins.Monitors.Batt, Xmobar.Plugins.Monitors.Common,@@ -229,7 +230,7 @@ cpp-options: -DUSE_NL80211 if flag(with_mpd) || flag(all_extensions)- build-depends: libmpd >= 0.9.0.10+ build-depends: libmpd >= 0.9.2.0 other-modules: Xmobar.Plugins.Monitors.MPD cpp-options: -DLIBMPD @@ -242,7 +243,7 @@ cpp-options: -DALSA if flag(with_datezone) || flag(all_extensions)- build-depends: timezone-olson >= 0.1 && < 0.3, timezone-series == 0.1.*+ build-depends: timezone-olson >= 0.2 && < 0.3, timezone-series == 0.1.* other-modules: Xmobar.Plugins.DateZone cpp-options: -DDATEZONE @@ -335,6 +336,7 @@ Xmobar.Plugins.Monitors.Common.Output Xmobar.Plugins.Monitors.Common.Files Xmobar.Plugins.Monitors.Cpu+ Xmobar.Plugins.Monitors.CpuSpec Xmobar.Plugins.Monitors.Common.Run Xmobar.Run.Exec Xmobar.App.Timer@@ -347,7 +349,6 @@ other-modules: Xmobar.Plugins.Monitors.Volume Xmobar.Plugins.Monitors.Alsa Xmobar.Plugins.Monitors.AlsaSpec- Xmobar.Plugins.Monitors.CpuSpec cpp-options: -DALSA @@ -356,6 +357,6 @@ main-is: main.hs hs-source-dirs: bench- ghc-options: -O2- build-depends: base, gauge, xmobar, mtl+ ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind -O2+ build-depends: base, gauge, xmobar, mtl, time default-language: Haskell2010