ghci4luatex-0.0: app/ghci4luatex.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
module Main (main) where
import Control.Monad
import GHC.Generics
import System.IO
import Data.IORef
import Network.Simple.TCP
import qualified Data.ByteString.Lazy as BL
import System.Console.CmdArgs
import Data.Aeson
import System.Process.Ghci
import qualified Data.Memoizer.Sessions as Memo
data ServerMsg = NewSession String | ContinueSession String
deriving (Show, Eq, Generic)
instance ToJSON ServerMsg where
toEncoding = genericToEncoding defaultOptions
instance FromJSON ServerMsg
data Ghci4luatexMsg = GhciMsg String | ServerMsg ServerMsg
deriving (Show, Eq, Generic)
instance ToJSON Ghci4luatexMsg where
toEncoding = genericToEncoding defaultOptions
instance FromJSON Ghci4luatexMsg
data Ghci4luatex = Ghci4luatex
{ command :: String
, host :: String
, port :: String
}
deriving (Data,Typeable,Show,Eq)
type GhciMemo = Memo.SessionMemoizer String String BL.ByteString
cmdArg :: Ghci4luatex
cmdArg = Ghci4luatex
{ command = "ghci" &= help "Command to run (defaults to ghci)"
, host = "127.0.0.1" &= help "Host address (defaults to localhost)"
, port = "54123" &= help "Port (defaults to 54123)"
}
&= verbosity
&= summary "ghci4luatex v0.1, (C) Alice Rixte"
main :: IO ()
main = do
Ghci4luatex str addr prt <- cmdArgs cmdArg
case words str of
[] -> putStrLn "Error : Empty ghci command."
cmd : ghciArgs -> do
v <- getVerbosity
when (v >= Normal) $ do
putChar '\n'
putStrLn "(-: Starting GHCi Server :-)"
putChar '\n'
ghci <- startGhci v cmd ghciArgs
when (v >= Normal) $ do
putChar '\n'
putStrLn "(-: GHCi server is ready :-)"
putChar '\n'
memo <- newIORef (Memo.initSession "main" :: GhciMemo)
serve (Host addr) prt $ \(sock, remoteAddr) -> do
when (v > Normal) $ putStrLn $ "New connection of " ++ show remoteAddr
handleClient v sock ghci memo
printGhciMsg :: String -> IO ()
printGhciMsg str =
case lines str of
[] -> return ()
-- [s] -> when (s /= "") $ putStrLn $ "ghci| " ++ s
(x:q) -> do
putStrLn $ "ghci> " ++ x
mapM_ (putStrLn . ("ghci| " ++)) q
handleClient :: Verbosity -> Socket -> Ghci -> IORef GhciMemo -> IO ()
handleClient v sock ghci memo =
loop
where
loop = do
msg <- recv sock 1024
case msg of
Just bs -> do
case decodeStrict bs :: Maybe Ghci4luatexMsg of
Nothing ->
let json = encode (GhciResult "ghci4luatex :: Error : Could not parse JSON message." "")
in do
hPutStr stderr $ "Error : Could not parse JSON message : "
hPutStr stderr $ show bs
hPutStr stderr "\n"
hFlush stderr
sendLazy sock json
Just (GhciMsg s) -> do
m <-readIORef memo
json <- case Memo.lookup s m of
Nothing -> do
when (v >= Normal) $ printGhciMsg s
res <- execGhciCmd ghci v (s ++ "\n")
when (v >= Normal) $ putStrLn ""
let json = encode res <> "\n"
modifyIORef memo (Memo.storeResult s json)
return json
Just json -> do
when (v >= Loud) $ do
printGhciMsg s
putStrLn "Memoized !"
putStrLn ""
modifyIORef memo Memo.nextCmd
return json
sendLazy sock json
Just (ServerMsg (NewSession s)) -> do
modifyIORef memo (Memo.newSession s)
when (v >= Normal) $ do
putStrLn $ "--- New session : " ++ show s ++ "---\n"
Just (ServerMsg (ContinueSession s)) -> do
modifyIORef memo (Memo.continueSession s)
when (v >= Normal) $ do
putStrLn $ "--- Continue session : " ++ show s ++ "---\n"
loop
Nothing -> when (v >= Loud) $ do
putChar '\n'
putStrLn "Connexion was closed"