{-# LANGUAGE RecordWildCards #-}
module Xmobar.Plugins.QueueReader
  (QueueReader (..)
  ) where

import Xmobar.Run.Exec (Exec (..))

import Control.Monad (forever)
import qualified Control.Concurrent.STM as STM

-- | A 'QueueReader' displays data from an 'TQueue a' where
-- the data items 'a' are rendered by a user supplied function.
--
-- Like the 'HandleReader' plugin this is only useful if you are
-- running @xmobar@ from other Haskell code.  You should create a
-- new @TQueue a@ and pass it to this plugin.
--
-- @
-- main :: IO
-- main = do
--   q <- STM.newQueueIO @String
--   bar <- forkIO $ xmobar conf
--     { commands = Run (QueueReader q id "Queue") : commands conf }
--   STM.atomically $ STM.writeTQueue q "Some Message"
-- @
data QueueReader a
  = QueueReader
  { QueueReader a -> TQueue a
qQueue    :: STM.TQueue a
  , QueueReader a -> a -> String
qShowItem :: a -> String
  , QueueReader a -> String
qName :: String
  }

-- | This cannot be read back.
instance Show (QueueReader a) where
  -- | Only show the name/alias for the queue reader.
  show :: QueueReader a -> String
show QueueReader a
q = String
"QueueReader " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> QueueReader a -> String
forall a. QueueReader a -> String
qName QueueReader a
q

-- | WARNING: This read instance will throw an exception if used! It is
-- only implemented, because it is required by 'Xmobar.Run` in 'Xmobar.commands'.
instance Read (QueueReader a) where
  -- | Throws an 'error'!
  readsPrec :: Int -> ReadS (QueueReader a)
readsPrec = String -> Int -> ReadS (QueueReader a)
forall a. HasCallStack => String -> a
error String
"QueueReader: instance is a stub"

-- | Async queue/channel reading.
instance Exec (QueueReader a) where
  -- | Read from queue as data arrives.
  start :: QueueReader a -> (String -> IO ()) -> IO ()
start QueueReader{String
TQueue a
a -> String
qName :: String
qShowItem :: a -> String
qQueue :: TQueue a
qName :: forall a. QueueReader a -> String
qShowItem :: forall a. QueueReader a -> a -> String
qQueue :: forall a. QueueReader a -> TQueue a
..} String -> IO ()
cb =
    IO () -> IO ()
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (STM String -> IO String
forall a. STM a -> IO a
STM.atomically (a -> String
qShowItem (a -> String) -> STM a -> STM String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TQueue a -> STM a
forall a. TQueue a -> STM a
STM.readTQueue TQueue a
qQueue) IO String -> (String -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO ()
cb)

  alias :: QueueReader a -> String
alias = QueueReader a -> String
forall a. QueueReader a -> String
qName