packages feed

ghcitui-0.1.0.0: lib/ghcitui-brick/Ghcitui/Brick/AppInterpState.hs

{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE RecordWildCards #-}

module Ghcitui.Brick.AppInterpState
    ( AppInterpState (_liveEditor, _viewLock, _commandBuffer, historyPos)
    , commandBuffer
    , emptyAppInterpState
    , futHistoryPos
    , cmdHistory
    , isScanningHist
    , liveEditor
    , pastHistoryPos
    , pushHistory
    , viewLock
    ) where

import qualified Brick.Widgets.Edit as BE
import qualified Data.Text as T
import Lens.Micro as Lens

data AppInterpState s n = AppInterpState
    { _liveEditor :: BE.Editor s n
    , _viewLock :: !Bool
    -- ^ Whether we're locked to the bottom of the interpreter (True) window or not (False).
    , _commandBuffer :: [s]
    -- ^ The text currently typed into the editor, but not yet executed or in the history.
    , _cmdHistory :: [[s]]
    , historyPos :: !Int
    }

-- | Lens accessor for the editor. See '_liveEditor'.
liveEditor :: Lens.Lens' (AppInterpState s n) (BE.Editor s n)
liveEditor = Lens.lens _liveEditor (\ais le -> ais{_liveEditor = le})

-- | Lens for the view lock setting. See '_viewLock'.
viewLock :: Lens.Lens' (AppInterpState s n) Bool
viewLock = Lens.lens _viewLock (\ais x -> ais{_viewLock = x})

-- | Lens for the current contents of the command line buffer. See '_commandBuffer'.
commandBuffer :: Lens.Lens' (AppInterpState s n) [s]
commandBuffer = Lens.lens _commandBuffer (\ais x -> ais{_commandBuffer = x})

-- | Return the interpreter command history.
cmdHistory :: AppInterpState s n -> [[s]]
cmdHistory = _cmdHistory

-- | Create a base interpreter state.
emptyAppInterpState
    :: n
    -- ^ Name for the 'Brick.Editor'.
    -> AppInterpState T.Text n
emptyAppInterpState name =
    AppInterpState
        { _liveEditor = initInterpWidget name (Just 1)
        , _viewLock = True
        , _commandBuffer = mempty
        , _cmdHistory = mempty
        , historyPos = 0
        }

resetHistoryPos :: AppInterpState s n -> AppInterpState s n
resetHistoryPos s = s{historyPos = 0}

-- | Move interpreter history back.
pastHistoryPos :: AppInterpState s n -> AppInterpState s n
pastHistoryPos s@AppInterpState{..} =
    -- Note we do want it to stop at length _history, not length _history - 1
    -- because 0 is not the beginning of the history, it's the commandBuffer.
    s{historyPos = min (length _cmdHistory) $ succ historyPos}

-- | Are we currently viewing past contents?
isScanningHist :: AppInterpState s n -> Bool
isScanningHist AppInterpState{..} = historyPos /= 0

-- | Move interpreter history forward.
futHistoryPos :: AppInterpState s n -> AppInterpState s n
futHistoryPos s@AppInterpState{..} = s{historyPos = max 0 $ pred historyPos}

-- | Push a new value on to the history stack and reset the position.
pushHistory :: [s] -> AppInterpState s n -> AppInterpState s n
pushHistory cmdLines s = resetHistoryPos $ s{_cmdHistory = cmdLines : cmdHistory s}

-- | Create the initial live interpreter widget object.
initInterpWidget
    :: n
    -- ^ Editor name (must be a unique identifier).
    -> Maybe Int
    -- ^ Line height of the editor. Nothing for unlimited.
    -> BE.Editor T.Text n
initInterpWidget name height = BE.editorText name height mempty