sarsi-0.0.4.0: sarsi-vi/Main.hs
module Main where
import Data.Machine (ProcessT, (<~), asParts, final, scan, sinkPart_, runT)
import Codec.Sarsi (Event(..), Message(..), Level(..), Location(..))
import Control.Concurrent.MVar (MVar, newMVar, readMVar, swapMVar)
import Data.Text (Text, pack)
import Data.Text.IO (hPutStrLn)
import Sarsi (Topic(..), getBroker, getTopic)
import Sarsi.Consumer (consumeOrWait)
import System.IO (Handle, IOMode(WriteMode), hClose, hFlush, openFile)
import System.IO.Machine (sinkIO)
import qualified Data.List as List
import qualified Data.Text as Text
import qualified Sarsi as Sarsi
-- TODO Remove the MVar by impl. scanM ((a -> b -> m a) -> a -> ProcessT m (k b) a) in machines
title :: String
title = concat [Sarsi.title, "-vi"]
-- :set efm=%f:%l:%c:%t\ %m
toVi :: Message -> Text
toVi (Message (Location fp col ln) lvl txts) = Text.concat [header, pack " ", body]
where
header = Text.concat $ List.intersperse (pack ":") [fp, pack $ show ln, pack $ show col, tpe lvl]
body = Text.concat $ List.intersperse (pack " ") txts
tpe Error = pack "e"
tpe Warning = pack "w"
data Action = Append | Replace deriving Show
data LogEvent = LogEvent Action Text deriving Show
data Command = Throw LogEvent | Echo String
convert :: Bool -> Event -> (Bool, [Command])
convert first (Notify msg@(Message loc lvl _)) = (False, [Throw e, Echo $ concat [show loc, " ", show lvl]])
where
e = LogEvent mode $ toVi msg
mode = if first then Replace else Append
convert _ e = (True, [Echo $show e])
converter :: Bool -> ProcessT IO Event (Bool, [Command])
converter first = scan f (first, []) where f (first', _) event = convert first' event
dump :: FilePath -> Maybe Handle -> Command -> IO (Maybe Handle)
dump _ h (Echo txt) = (putStrLn $ concat [title, ": ", txt]) >> return h
dump fp Nothing e = openFile fp WriteMode >>= \h -> dump fp (Just h) e
dump _ (Just h) (Throw (LogEvent Append txt)) = fmap (const $ Just h) $ (hPutStrLn h txt >> hFlush h)
dump fp (Just h) (Throw (LogEvent Replace txt)) = hClose h >> dump fp Nothing (Throw $ LogEvent Append txt)
writer :: FilePath -> MVar (Maybe Handle) -> Command -> IO ()
writer tp var c = do
h <- readMVar var
h' <- dump fp h c
_ <- swapMVar var h'
return ()
where fp = tp ++ ".vi"
main :: IO ()
main = do
b <- getBroker
t <- getTopic b "."
var <- newMVar Nothing
consumeOrWait t $ consumer t var
where
consumer (Topic _ tp) var first src = do
res <- runT $ final <~ sinkPart_ id ((sinkIO $ writer tp var) <~ asParts) <~ converter (maybe True id first) <~ src
return $ Left $ head res