1-----------------------------------------------------------------------------
2-- |
3-- Module      :  Plugins.HandleReader
4-- Copyright   :  (c) Pavan Rikhi
5-- License     :  BSD-style (see LICENSE)
6--
7-- Maintainer  :  Pavan Rikhi <pavan.rikhi@gmail.com>
8-- Stability   :  unstable
9-- Portability :  portable
10--
11-- A plugin for reading from 'Handle's
12--
13-----------------------------------------------------------------------------
14
15module Xmobar.Plugins.HandleReader
16    ( HandleReader(..)
17    )
18where
19
20import           System.IO                      ( Handle
21                                                , hIsEOF
22                                                , hGetLine
23                                                )
24
25import           Xmobar.Run.Exec                ( Exec(..) )
26
27
28-- | A HandleReader displays any text received from a Handle.
29--
30-- This is only useful if you are running @xmobar@ from other Haskell code.
31-- You can create a pair of @(read, write)@ 'Handle's using
32-- 'System.Process.createPipe'. Pass the @read@ 'Handle' to HandleReader
33-- and write your desired output to the @write@ 'Handle'.
34--
35-- @
36--  (readHandle, writeHandle) <- 'System.Process.createPipe'
37--  xmobarProcess <- 'System.Posix.Process.forkProcess' $ 'Xmobar.xmobar' myConfig
38--          { commands =
39--              'Xmobar.Run' ('HandleReader' readHandle "handle") : 'Xmobar.commands' myConfig
40--          }
41--  'System.IO.hPutStr' writeHandle "Hello World"
42-- @
43data HandleReader
44    = HandleReader
45        Handle
46        -- ^ The Handle to read from.
47        String
48        -- ^ Alias for the HandleReader
49    deriving (Show)
50
51-- | WARNING: This Read instance will throw an exception if used! It is
52-- only implemented because it is required to use HandleReader with
53-- 'Xmobar.Run' in 'Xmobar.commands'.
54instance Read HandleReader where
55    -- | Throws an 'error'!
56    readsPrec = error "HandleReader: Read instance is stub"
57
58-- | Asynchronously read from the 'Handle'.
59instance Exec HandleReader where
60    -- | Read from the 'Handle' until it is closed.
61    start (HandleReader handle _) cb =
62        untilM (hIsEOF handle) $ hGetLine handle >>= cb
63    -- | Use the 2nd argument to HandleReader as its alias.
64    alias (HandleReader _ a) = a
65
66-- Loop the action until predicateM returns True.
67untilM :: Monad m => m Bool -> m () -> m ()
68untilM predicateM action = do
69    predicate <- predicateM
70    if predicate then return () else action >> untilM predicateM action
71