From 80913aeed46fc607f057a77ffdd884b5db77a0bc Mon Sep 17 00:00:00 2001
From: Pavan Rikhi <pavan.rikhi@gmail.com>
Date: Thu, 9 Apr 2020 13:51:37 -0400
Subject: Add a HandleReader Plugin

This adds a new `HandleReader` plugin, which displays data from a
Haskell `Handle`. This is really only useful if you are running xmobar
from within another Haskell program, but lets you avoid the mechanics of
creating a named pipe with the proper file permissions.

Instead, you can use `System.Process.createPipe` to make a pair of read
& write Handles. If you pass the read handle to HandleReader, you can
use hPutStr on the write Handle to send data to xmobar from your
application code.
---
 src/Xmobar/Plugins/HandleReader.hs | 70 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 src/Xmobar/Plugins/HandleReader.hs

(limited to 'src/Xmobar/Plugins')

diff --git a/src/Xmobar/Plugins/HandleReader.hs b/src/Xmobar/Plugins/HandleReader.hs
new file mode 100644
index 0000000..e1ee6a5
--- /dev/null
+++ b/src/Xmobar/Plugins/HandleReader.hs
@@ -0,0 +1,70 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.HandleReader
+-- Copyright   :  (c) Pavan Rikhi
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Pavan Rikhi <pavan.rikhi@gmail.com>
+-- Stability   :  unstable
+-- Portability :  portable
+--
+-- A plugin for reading from 'Handle's
+--
+-----------------------------------------------------------------------------
+
+module Xmobar.Plugins.HandleReader
+    ( HandleReader(..)
+    )
+where
+
+import           System.IO                      ( Handle
+                                                , hIsEOF
+                                                )
+
+import           Xmobar.Run.Exec                ( Exec(..) )
+import           Xmobar.System.Utils            ( hGetLineSafe )
+
+
+-- | A HandleReader displays any text received from a Handle.
+--
+-- This is only useful if you are running @xmobar@ from other Haskell code.
+-- You can create a pair of @(read, write)@ 'Handle's using
+-- 'System.Process.createPipe'. Pass the @read@ 'Handle' to HandleReader
+-- and write your desired output to the @write@ 'Handle'.
+--
+-- @
+--  (readHandle, writeHandle) <- 'System.Process.createPipe'
+--  xmobarProcess <- 'System.Posix.Process.forkProcess' $ 'Xmobar.xmobar' myConfig
+--          { commands =
+--              'Xmobar.Run' ('HandleReader' readHandle "handle") : 'Xmobar.commands' myConfig
+--          }
+--  'System.IO.hPutStr' writeHandle "Hello World"
+-- @
+data HandleReader
+    = HandleReader
+        Handle
+        -- ^ The Handle to read from.
+        String
+        -- ^ Alias for the HandleReader
+    deriving (Show)
+
+-- | WARNING: This Read instance will throw an exception if used! It is
+-- only implemented because it is required to use HandleReader with
+-- 'Xmobar.Run' in 'Xmobar.commands'.
+instance Read HandleReader where
+    -- | Throws an 'error'!
+    readsPrec = error "HandleReader: Read instance is stub"
+
+-- | Asynchronously read from the 'Handle'.
+instance Exec HandleReader where
+    -- | Read from the 'Handle' until it is closed.
+    start (HandleReader handle _) cb =
+        untilM (hIsEOF handle) $ hGetLineSafe handle >>= cb
+    -- | Use the 2nd argument to HandleReader as its alias.
+    alias (HandleReader _ a) = a
+
+-- Loop the action until predicateM returns True.
+untilM :: Monad m => m Bool -> m () -> m ()
+untilM predicateM action = do
+    predicate <- predicateM
+    if predicate then return () else action >> untilM predicateM action
-- 
cgit v1.2.3