Portability | semi-portable (uses MPTC and type families) |
---|---|
Stability | experimental |
Maintainer | felipe.lessa@gmail.com |
Safe Haskell | Safe-Infered |
Hello!
This is dzen-utils
' main module. It re-exports every other
module from this library, so you may just say
import System.Dzen
and you'll have everything in hand. To learn more about this library, please see the documentation of each module exported here. To get you started, there are some simple examples below. :)
- module System.Dzen.Base
- module System.Dzen.Colour
- module System.Dzen.Graphics
- module System.Dzen.Padding
- module System.Dzen.Bars
- module System.Dzen.Process
Example 1
Suppose you have
import Data.Time import System.Locale getZonedTime :: IO ZonedTime -- from time package getCurrentWindow :: IO String -- from somewhere you know :)
and that you want your bar to look like
"Wndw: [my window title here] - Sun 15 Mar 07:10:02"
Okay, that's pretty nice. What you will do first will be to
construct the Printer
of your bar. Basically, what you want is to
concatenate "Wndw: "
, the result of getCurrentWindow
, the
separator, and the formated result of getZonedTime
. The Printer
we'll build below contain all the information necessary to create
the final output string above from the two get
functions!
Constructing - Part 1
To write the constant strings, we use str
:
str :: String -> DString str "Wndw: " :: DString str " - " :: DString
That is pretty straightforward. But how can we print the current
window? We will just use cstr
here
cstr :: Printer String
While str
is used as a common function, you just apply the
string you want to it, cstr
will get the string from another
source. What we'll do shortly is to pipe IO String
into
Printer String
to obtain our final output. Instead of
Printer a
, think of it as Printer input
.
To concatenate we just have to use +++
from Combine
, which
is an ugly class used to create beautiful types:
str "Wndn: " +++ cstr +++ str " - " :: Printer String
Whenever you concatenate a DString
with a Printer input
, you
get a Printer input
as a result. That is, if you concatenate a
constant string to something that takes an input and produces a
string, what you get is something that takes an input and produces
the concatenated string. Note that you don't need to write the
type above.
Constructing - Part 2
Now we can't just go ahead and use cstr
directly with
getZonedTime
because, unlike getCurrentWindow
, its result is
not a string, but a ZonedTime
. To format the ZonedTime
is
outside the scope of this example, but you can get the format
shown above with
format :: ZonedTime -> String format = formatTime defaultTimeLocale "%a %e %b %H:%M:%S"
While you can write
fmap format getZoneTime :: IO String
you don't need to push the format function into the IO
monad,
just put it in the Printer
, the place where it belongs! To
accomplish that use simple'
instead of cstr
:
simple' :: (input -> String) -> Printer input simple' format :: Printer ZonedTime
And it's done! Concatenating everything:
printer :: Printer (String, ZonedTime) printer = str "Wndn: " +++ cstr +++ str " - " +++ simple' format
Whenever you concatenate Printer a
with Printer b
you
get Printer (a,b)
.
Applying
In the end we just want strings, not Printer
s, so we need to
apply our printer
to some inputs. We already have functions for
each part of our input, but we need to combine them. We may just
use from System.Dzen.Process in this case (and in most others as
well):
supply :: IO (String, ZonedTime) supply = getCurrentWindow ## getZonedTime
Now we could use apply
, applyMany
or applyForever
to
get strings out of our printer, but we'll use runDzen
directly
which is a tad easier:
myDzen :: IO () myDzen = runDzen "dzen2" [] 500 printer supply
And that's it! You may use myDzen
directly as main
, or you
may use forkIO myDzen
inside xmonad
. Pretty nice, uh?
Whole code
This is the whole code plus a stub getCurrentWindow
and a main
.
We omit the signatures on purpose to show how you could have
written it lazily. You may also get the file Example1.hs
from the
source code which contains all the type signatures.
import Data.Time import System.Dzen import System.Locale printer = str "Wndn: " +++ cstr +++ str " - " +++ simple' format format = formatTime defaultTimeLocale "%a %e %b %H:%M:%S" supply = getCurrentWindow ## getZonedTime myDzen = runDzen "dzen2" [] 500 printer supply getCurrentWindow = return "My =^.^= Lolcats" main = myDzen
Example 2
Now we want to do something different: let's have a graphical bar for our clock! And, why not, a graphical separator.
Separator
The graphical separator will be very simple. Instead of dash
(" - "
) we'll use a small dot:
import Data.Monoid sep :: DString sep = mconcat [pos 4, rect 3 3, pos 4]
This is a 3x3 rectangle with 4 pixels of spacing on each side. And, thats it!
Time bar
Now something more challenging. Instead of showing the minutes and the seconds, we want to show a graphical bar, something like
"Wndw: [my window title here] - Sun 15 Mar 07:[== ]"
Well, that bar will show minutes and seconds, but we can
take as input just seconds, ranging from 0
to 60*60-1
.
We'll use plain simple cgdbar
, which mimics gdbar
:
(please look at System.Dzen.Bars for more info)
timeBar :: Printer Int timeBar = cgdbar False (40,10) Nothing Nothing True (0, 60*60-1)
But what we have is not the number of seconds, but a ZonedTime
.
So we need
zonedSecs :: ZonedTime -> Int zonedSecs = extract . localTimeOfDay . zonedTimeToLocalTime where extract t = let minutes = fromIntegral (todMin t) in round (minutes * 60 + todSec t)
As Printer
s are cofunctors, we can use comap
to get
a suitable timeBar
:
timeBar' :: Printer ZonedTime timeBar' = comap zonedSecs timeBar
Glueing the time text with the bar
We also want the rest of the time, not just the bar. First,
we need a new format
, as we don't want to show the minutes
anymore:
format :: ZonedTime -> String format = formatTime defaultTimeLocale "%a %e %b %H:"
You may be tempted to write simple' format +++ timeBar'
now,
but there's a small glitch: it would have type
Printer (ZonedTime, ZonedTime)
, but we want both to use
the same ZonedTime
. We could use comap
again or combine
,
but it is easier to write
time :: Printer ZonedTime time = simple' format +=+ timeBar'
Whole code
The rest is just glue! So we now present the whole code,
again in a compact form. See Example2.hs
for the whole
code with type signatures:
import Data.Monoid import Data.Time import System.Dzen import System.Locale zonedSecs = extract . localTimeOfDay . zonedTimeToLocalTime where extract t = let minutes = fromIntegral (todMin t) in round (minutes * 60 + todSec t) time = simple' format +=+ comap zonedSecs timeBar where format = formatTime defaultTimeLocale "%a %e %b %H:" timeBar = cgdbar False (40,10) Nothing Nothing True (0, 60*60-1) printer = str "Wndn: " +++ cstr +++ sep +++ time where sep = mconcat [str " ", rectO 5 5, str " "] supply = getCurrentWindow ## getZonedTime myDzen = runDzen "dzen2" [] 500 printer supply getCurrentWindow = return "My =^.^= Lolcats" main = myDzen
Module exports
module System.Dzen.Base
module System.Dzen.Colour
module System.Dzen.Graphics
module System.Dzen.Padding
module System.Dzen.Bars
module System.Dzen.Process