packages feed

zwirn-0.2.3.1: app/zwirnmill/Editor/Eval.hs

{- HLINT ignore "Use tuple-section" -}

module Editor.Eval where

import Brick (EventM, get, modify)
import Brick.BChan (BChan, writeBChan)
import Control.Concurrent (forkIO, threadDelay)
import Control.Monad.RWS (MonadIO (..))
import Data.Functor (void)
import qualified Data.Text as T
import Editor.Core
import Editor.Util (currentLine, getContent)
import Lens.Micro
import UI.Core (AppEvent (..), EditorEventEnv (..), Name, envEditorState, envEnv)
import Zwirn.Language.Compiler (CIError (..), CompilerOutput (..), Environment, compilerInterpreterWithBlock, getBlockStartEnd, runCI)

evalEvent :: EventM Name EditorEventEnv ()
evalEvent = do
  (EditorEventEnv chan _ _ _ env es) <- get
  x <- liftIO $ evalCode es env
  case x of
    Left (CIError err env') -> do
      modify $ \as -> as & envEnv .~ env'
      block <- liftIO $ tryGetBlock es env
      liftIO $ writeBChan chan (UpdateOutput (OutputError, show err))
      liftIO $ clearFlash chan
      modify $
        envEditorState
          %~ (esMessage ?~ show err)
            . (esFlashBlock .~ ((\b -> (OutputError, b)) <$> block))
    Right (OutMessage t, env', block) -> do
      modify $ \as -> as & envEnv .~ env'
      liftIO $ writeBChan chan (UpdateOutput (OutputInfo, T.unpack t))
      liftIO $ clearFlash chan
      liftIO $ writeBChan chan UpdateEnv
      modify $
        envEditorState
          %~ (esMessage ?~ T.unpack t)
            . (esFlashBlock ?~ (OutputInfo, block))
    Right (_, env', block) -> do
      modify $ \as -> as & envEnv .~ env'
      liftIO $ writeBChan chan (UpdateOutput (OutputInfo, "Ok"))
      liftIO $ clearFlash chan
      liftIO $ writeBChan chan UpdateEnv
      modify $
        envEditorState
          %~ (esMessage ?~ "Ok.")
            . (esFlashBlock ?~ (OutputInfo, block))
  where
    clearFlash :: BChan AppEvent -> IO ()
    clearFlash chan = void $ forkIO $ do
      threadDelay 100000
      writeBChan chan ClearFlash

evalCode :: EditorState -> Environment -> IO (Either CIError (CompilerOutput, Environment, (Int, Int)))
evalCode es env = runCI env (compilerInterpreterWithBlock r content)
  where
    content = getContent es
    r = currentLine es

tryGetBlock :: EditorState -> Environment -> IO (Maybe (Int, Int))
tryGetBlock es env = do
  x <- runCI env (getBlockStartEnd r content)
  case x of
    Left _ -> return Nothing
    Right block -> return $ Just block
  where
    content = getContent es
    r = currentLine es