Pakej is a status bar daemon. It does not actually draw any status bars, only executes I/O actions in the background and stores their results. This is most useful together with tools like tmux or xmobar.
Installation is a fairly involved remarkably simple process:
$ git clone https://github.com/supki/pakej
% cabal install cabal-install --constraint='cabal-install >= 1.20'
$ cabal install pakej/pakej.cabal
$ pakej --init
$ pakej --recompile
$ pakej
The default pakej configuration isn't very interesting though, so you'd really want to customize it for yourself. We have a tutorial!
pakej
is sandbox-aware, just drop (or link) the appropriate cabal.sandbox.config
into ~/.pakej
and it will be used
Here I assume you've successfully installed pakej
package already. I encourage you
to test the assumption by executing
$ cabal exec ghc -- -e 'import Pakej'
The expected result is GHC staying silent. If you see something akin to:
<no location info>:
Could not find module `Pakej'
that means Pakej has not been installed successfully!
This tutorial walks through the process of configuring Pakej. We start with nothing and end up with a nice status bar for tmux. I expect some kind of familiarity with the command line, but you don't need to install tmux if you don't like it—there will be screen captures illustrating our progress.
First, let's initialize Pakej environment:
$ pakej --init
This will create ~/.pakej
directory and populate it with the pakej.hs
template.
Go look at it! ..It's not very interesting, but that's a start. We can compile it:
$ pakej --recompile
...
and even run:
$ pakej
pakej 0.2.0.0, listening on
- localhost:/home/maksenov/.pakej/pakej.sock
$
It's a daemon, so it releases the console right away, but you can look up the
pakej process with tools like ps
or pgrep
, say.
Let's make our first widget!
Widgets, in Pakej terms, are smallish, composable things that generate other useful things—think text—over time. For example, you can think about date as the string "14.02.2014" today and the string "15.02.2014" tomorrow. So, if we want the datetime widget we'd start with a function that can produce something similar:
import Data.String (IsString(..))
import Data.Text.Lazy (Text)
import Data.Time (formatTime, getZonedTime)
import System.Locale (defaultTimeLocale)
datetime :: IO Text
datetime = fmap format getZonedTime
where format = fromString . formatTime defaultTimeLocale formatString
formatString = "%m.%d.%y, %a, %H:%M"
Whoa, that was fast! Let me explain. datetime
generates strings like "02.15.14, Sat, 09:05"
using time and old-locale packages. Both come with GHC, so you
do not need to worry about installing them manually. getZonedTime
gets the local time blob
that respects current timezone. formatTime
formats this blob using a format string.
Next, we need to wrap datetime
in a text
widget, so Pakej can understand to call it
repeatedly and to send its results down the pipeline:
import Pakej
import Prelude hiding ((.), id)
main :: IO ()
main = pakej $ text datetime
Almost all Pakej machinery is in place, we only need to label the widget's result so we can lookup it later:
{-# LANGUAGE OverloadedStrings #-}
main :: IO ()
main = pakej $ private "datetime" . text datetime
Let's try it:
$ pakej --recompile
$ pakej --replace
$ pakej --stat
datetime
$ pakej datetime
02.15.14, Sat, 10:58
Seems to work! Next step is to update tmux configuration file, ~/.tmux.conf
:
set-option -g status-right-length 50
set-option -g status-right '#(pakej datetime)'
You can find full source code for this example in example/datetime.hs
.
A single widget is cool, but we want more! For example, we also want to see average
load in the tmux status bar. We can write a simple function to parse /proc/loadavg
and wrap it in a text
widget:
import Data.List (intercalate)
main :: IO ()
main = pakej $ private "datetime" . text datetime
-- private "loadavg" . text loadavg
loadavg :: FilePath -> IO Text
loadavg = fmap (fromString . intercalate " → " . take 3 . words) . readFile
But how do we compose both widgets' values nicely separated by a bar into a single string?
Here's where aggregate
comes in:
main :: IO ()
main = pakej $ private "status" . aggregate $
[ private "loadavg" . text (loadavg "/proc/loadavg")
, private "datetime" . text datetime
]
So, let's try it:
$ pakej --recompile
$ pakej --replace
$ pakej --stat
datetime loadavg status
$ pakej datetime
02.15.14, Sat, 11:31
$ pakej loadavg
0.72 → 0.62 → 0.50
$ pakej status
0.72 → 0.62 → 0.50 | 02.15.14, Sat, 11:31
Very nice! Now tmux configuration needs an update:
set-option -g status-right-length 50
set-option -g status-right '#(pakej status)'
You can find full source code for this example in example/aggregation.hs
.
There's much more to Pakej: non-static widgets, widgets quering other Pakej instances, Pakej REPL and more, but all this is left for reader to explore.
Haddocks cover the entire Pakej API.