summaryrefslogtreecommitdiffhomepage
path: root/doc/using-haskell.org
diff options
context:
space:
mode:
Diffstat (limited to 'doc/using-haskell.org')
-rw-r--r--doc/using-haskell.org125
1 files changed, 125 insertions, 0 deletions
diff --git a/doc/using-haskell.org b/doc/using-haskell.org
new file mode 100644
index 0000000..5c48c06
--- /dev/null
+++ b/doc/using-haskell.org
@@ -0,0 +1,125 @@
+#+title: Using Haskell
+
+* Writing your own xmobar in Haskell
+ :PROPERTIES:
+ :CUSTOM_ID: xmobar-in-haskell
+ :END:
+
+ Besides an standalone program, ~xmobar~ is also a Haskell library providing
+ an interface to write your own status bar. You can write, instead of a
+ configuration file, a real Haskell program that will be compiled and run
+ when you invoke =xmobar=.
+
+ Make sure that ~ghc~ will be able to locate the xmobar library, e.g. with
+
+ #+begin_src shell
+ cabal install --lib xmobar
+ #+end_src
+
+ and then write your Haskell configuration and main function using the
+ functions and types exported in the library, which closely resemble those
+ used in configuration files. Here's a small example:
+
+ #+begin_src haskell
+ import Xmobar
+
+ config :: Config
+ config =
+ defaultConfig
+ { font = "xft:Terminus-8",
+ allDesktops = True,
+ alpha = 200,
+ commands =
+ [ Run XMonadLog,
+ Run $ Memory ["t", "Mem: <usedratio>%"] 10,
+ Run $ Kbd [],
+ Run $ Date "%a %_d %b %Y <fc=#ee9a00>%H:%M:%S</fc>" "date" 10
+ ],
+ template = "%XMonadLog% }{ %kbd% | %date% | %memory%",
+ alignSep = "}{"
+ }
+
+ main :: IO ()
+ main = xmobar config
+ #+end_src
+
+ You can then for instance run =ghc --make xmobar.hs= to create a new xmobar
+ executable running exactly the monitors defined above. Or put your
+ =xmobar.hs= program in =~/.config/xmobar/xmobar.hs= and, when running the
+ system-wide xmobar, it will notice that you have your own implementation
+ and (re)compile and run it as needed.
+
+* Writing a plugin
+ :PROPERTIES:
+ :CUSTOM_ID: writing-a-plugin
+ :END:
+ Writing a plugin for xmobar is very simple!
+
+ First, you need to create a data type with at least one constructor. Next
+ you must declare this data type an instance of the =Exec= class, by defining
+ the one needed method (alternatively =start= or =run=) and 3 optional ones
+ (=alias=, =rate=, and =trigger=):
+
+ #+begin_src haskell
+ start :: e -> (String -> IO ()) -> IO ()
+ run :: e -> IO String
+ rate :: e -> Int
+ alias :: e -> String
+ trigger :: e -> (Maybe SignalType -> IO ()) -> IO ()
+ #+end_src
+
+ =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 to perform
+ asynchronous actions. See =src/Xmobar/Plugins/PipeReader.hs= for an example.
+
+ =run= can be used for simpler plugins. If you define only =run= the plugin
+ will be run every second. To overwrite this default you just need to
+ implement =rate=, which must return the number of tenth of seconds between
+ every successive runs. See [[../examples/xmobar.hs][examples/xmobar.hs]] for an example of a plugin
+ that runs just once, and [[../src/Xmobar/Plugins/Date.hs][src/Xmobar/Plugins/Date.hs]] for one that
+ implements =rate=.
+
+ Notice that Date could be implemented as:
+
+ #+begin_src 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
+ #+end_src
+
+ Modulo some technicalities like refreshing the time-zone in a clever way,
+ this implementation is equivalent to the one you can read in
+ =Plugins/Date.hs=.
+
+ =alias= is the name to be used in the output template. Default alias will be
+ the data type constructor.
+
+ After that your type constructor can be used as an argument for the
+ Runnable type constructor =Run= in the =commands= list of the configuration
+ options.
+
+ If your plugin only implements =alias= and =start=, then it is advisable to
+ put it into the =Xmobar/Plugins/Monitors= directory and use one of the many
+ =run*= functions in [[../src/Xmobar/Plugins/Monitors/Common/Run.hs][Xmobar.Plugins.Monitors.Run]] in order to define
+ =start=. The =Exec= instance should then live in [[../src/Xmobar/Plugins/Monitors.hs][Xmobar.Plugins.Monitors]].
+
+* Using a Plugin
+
+ To use your new plugin, you just need to use a pure Haskell configuration
+ for xmobar (as explained [[#xmobar-in-haskell][above]]) and load your definitions in your =xmobar.hs=
+ file. You can see an example in [[../examples/xmobar.hs][examples/xmobar.hs]] showing you how to write
+ a Haskell configuration that uses a new plugin, all in one file.
+
+ 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 (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!