packages feed

swarm-0.7.0.0: src/swarm-tui/Swarm/TUI/Controller/EventHandlers/REPL.hs

{-# LANGUAGE OverloadedStrings #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Here is the REPL player configurable key event handler.
module Swarm.TUI.Controller.EventHandlers.REPL (
  replEventHandlers,
) where

import Brick
import Brick.Keybindings qualified as B
import Control.Lens as Lens
import Control.Monad (when)
import Data.Maybe (isJust)
import Data.Text qualified as T
import Swarm.Game.CESK (cancel)
import Swarm.Game.Robot.Concrete
import Swarm.Game.State
import Swarm.Game.State.Substate
import Swarm.TUI.Controller.Util
import Swarm.TUI.Model
import Swarm.TUI.Model.Event
import Swarm.TUI.Model.Repl
import Swarm.TUI.Model.UI.Gameplay

-- | Handle a user input key event for the REPL.
--
-- See 'Swarm.TUI.Controller.handleREPLEvent'.
replEventHandlers :: [B.KeyEventHandler SwarmEvent (EventM Name AppState)]
replEventHandlers = allHandlers REPL $ \case
  CancelRunningProgramEvent -> ("Cancel running base robot program", Brick.zoom (playState . scenarioState) cancelRunningBase)
  TogglePilotingModeEvent -> ("Toggle piloting mode", Brick.zoom (playState . scenarioState) $ onlyCreative togglePilotingMode)
  ToggleCustomKeyHandlingEvent -> ("Toggle custom key handling mode", Brick.zoom (playState . scenarioState) toggleCustomKeyHandling)

-- | Cancel the running base CESK machine and clear REPL input text.
--
-- It is handled in top REPL handler so we can always cancel the currently running
-- base program no matter what REPL control mode we are in.
cancelRunningBase :: EventM Name ScenarioState ()
cancelRunningBase = do
  working <- use $ gameState . gameControls . replWorking
  when working $ gameState . baseRobot . machine %= cancel
  Brick.zoom (uiGameplay . uiREPL) $ do
    replPromptType .= CmdPrompt []
    replPromptText .= ""

togglePilotingMode :: EventM Name ScenarioState ()
togglePilotingMode = do
  s <- get
  let theRepl = s ^. uiGameplay . uiREPL
      uinput = theRepl ^. replPromptText
      curMode = theRepl ^. replControlMode
  case curMode of
    Piloting -> uiGameplay . uiREPL . replControlMode .= Typing
    _ ->
      if T.null uinput
        then uiGameplay . uiREPL . replControlMode .= Piloting
        else do
          addREPLHistItem REPLError "Please clear the REPL before engaging pilot mode."
          invalidateCacheEntry REPLHistoryCache

toggleCustomKeyHandling :: EventM Name ScenarioState ()
toggleCustomKeyHandling = do
  s <- get
  when (isJust (s ^. gameState . gameControls . inputHandler)) $ do
    curMode <- use $ uiGameplay . uiREPL . replControlMode
    (uiGameplay . uiREPL . replControlMode) .= case curMode of Handling -> Typing; _ -> Handling