{-# LANGUAGE FlexibleContexts #-}
module Monad where
import Agda.IR
import Agda.Interaction.Base ( IOTCM )
import Agda.TypeChecking.Monad ( TCMT )
import Control.Concurrent
import Control.Monad.Reader
import Data.Text ( Text
, pack
)
import Server.CommandController ( CommandController )
import qualified Server.CommandController as CommandController
import Server.ResponseController ( ResponseController )
import qualified Server.ResponseController as ResponseController
import Data.IORef ( IORef
, modifyIORef'
, newIORef
, readIORef
, writeIORef
)
import Data.Maybe ( isJust )
import Language.LSP.Server ( MonadLsp
, getConfig
)
import qualified Language.LSP.Types as LSP
import Options
--------------------------------------------------------------------------------
data Env = Env
{ envOptions :: Options
, envDevMode :: Bool
, envConfig :: Config
, envLogChan :: Chan Text
, envCommandController :: CommandController
, envResponseChan :: Chan Response
, envResponseController :: ResponseController
}
createInitEnv :: (MonadIO m, MonadLsp Config m) => Options -> m Env
createInitEnv options =
Env options (isJust (optViaTCP options))
<$> getConfig
<*> liftIO newChan
<*> liftIO CommandController.new
<*> liftIO newChan
<*> liftIO ResponseController.new
--------------------------------------------------------------------------------
-- | OUR monad
type ServerM m = ReaderT Env m
runServerM :: Env -> ServerM m a -> m a
runServerM = flip runReaderT
--------------------------------------------------------------------------------
writeLog :: (Monad m, MonadIO m) => Text -> ServerM m ()
writeLog msg = do
chan <- asks envLogChan
liftIO $ writeChan chan msg
writeLog' :: (Monad m, MonadIO m, Show a) => a -> ServerM m ()
writeLog' x = do
chan <- asks envLogChan
liftIO $ writeChan chan $ pack $ show x
-- | Provider
provideCommand :: (Monad m, MonadIO m) => IOTCM -> ServerM m ()
provideCommand iotcm = do
controller <- asks envCommandController
liftIO $ CommandController.put controller iotcm
-- | Consumter
consumeCommand :: (Monad m, MonadIO m) => Env -> m IOTCM
consumeCommand env = liftIO $ CommandController.take (envCommandController env)
waitUntilResponsesSent :: (Monad m, MonadIO m) => ServerM m ()
waitUntilResponsesSent = do
controller <- asks envResponseController
liftIO $ ResponseController.setCheckpointAndWait controller
signalCommandFinish :: (Monad m, MonadIO m) => ServerM m ()
signalCommandFinish = do
writeLog "[Command] Finished"
-- send `ResponseEnd`
env <- ask
liftIO $ writeChan (envResponseChan env) ResponseEnd
-- allow the next Command to be consumed
liftIO $ CommandController.release (envCommandController env)
-- | Sends a Response to the client via "envResponseChan"
sendResponse :: (Monad m, MonadIO m) => Env -> Response -> TCMT m ()
sendResponse env response = liftIO $ writeChan (envResponseChan env) response