matterhorn-50200.4.0: src/State/ListOverlay.hs
{-# LANGUAGE RankNTypes #-}
module State.ListOverlay
( listOverlayActivateCurrent
, listOverlaySearchString
, listOverlayMove
, exitListOverlay
, enterListOverlayMode
, resetListOverlaySearch
, onEventListOverlay
)
where
import Prelude ()
import Prelude.MH
import qualified Brick.Widgets.List as L
import qualified Brick.Widgets.Edit as E
import qualified Data.Text.Zipper as Z
import qualified Data.Vector as Vec
import Lens.Micro.Platform ( Lens', (%=), (.=) )
import Network.Mattermost.Types ( Session )
import qualified Graphics.Vty as Vty
import Types
import State.Common
import Events.Keybindings ( KeyConfig, Keybinding, handleKeyboardEvent )
-- | Activate the specified list overlay's selected item by invoking the
-- overlay's configured enter keypress handler function.
listOverlayActivateCurrent :: Lens' ChatState (ListOverlayState a b) -> MH ()
listOverlayActivateCurrent which = do
mItem <- L.listSelectedElement <$> use (which.listOverlaySearchResults)
case mItem of
Nothing -> return ()
Just (_, val) -> do
handler <- use (which.listOverlayEnterHandler)
activated <- handler val
if activated
then setMode Main
else return ()
-- | Get the current search string for the specified overlay.
listOverlaySearchString :: Lens' ChatState (ListOverlayState a b) -> MH Text
listOverlaySearchString which =
(head . E.getEditContents) <$> use (which.listOverlaySearchInput)
-- | Move the list cursor in the specified overlay.
listOverlayMove :: Lens' ChatState (ListOverlayState a b)
-- ^ Which overlay
-> (L.List Name a -> L.List Name a)
-- ^ How to transform the list in the overlay
-> MH ()
listOverlayMove which how = which.listOverlaySearchResults %= how
-- | Clear the state of the specified list overlay and return to the
-- Main mode.
exitListOverlay :: Lens' ChatState (ListOverlayState a b)
-- ^ Which overlay to reset
-> MH ()
exitListOverlay which = do
newList <- use (which.listOverlayNewList)
which.listOverlaySearchResults .= newList mempty
which.listOverlayEnterHandler .= (const $ return False)
setMode Main
-- | Initialize a list overlay with the specified arguments and switch
-- to the specified mode.
enterListOverlayMode :: (Lens' ChatState (ListOverlayState a b))
-- ^ Which overlay to initialize
-> Mode
-- ^ The mode to change to
-> b
-- ^ The overlay's initial search scope
-> (a -> MH Bool)
-- ^ The overlay's enter keypress handler
-> (b -> Session -> Text -> IO (Vec.Vector a))
-- ^ The overlay's results fetcher function
-> MH ()
enterListOverlayMode which mode scope enterHandler fetcher = do
which.listOverlaySearchScope .= scope
which.listOverlaySearchInput.E.editContentsL %= Z.clearZipper
which.listOverlayEnterHandler .= enterHandler
which.listOverlayFetchResults .= fetcher
which.listOverlaySearching .= False
newList <- use (which.listOverlayNewList)
which.listOverlaySearchResults .= newList mempty
setMode mode
resetListOverlaySearch which
-- | Reset the overlay's search by initiating a new search request for
-- the string that is currently in the overlay's editor. This does
-- nothing if a search for this overlay is already in progress.
resetListOverlaySearch :: Lens' ChatState (ListOverlayState a b) -> MH ()
resetListOverlaySearch which = do
searchPending <- use (which.listOverlaySearching)
when (not searchPending) $ do
searchString <- listOverlaySearchString which
which.listOverlaySearching .= True
newList <- use (which.listOverlayNewList)
session <- getSession
scope <- use (which.listOverlaySearchScope)
fetcher <- use (which.listOverlayFetchResults)
doAsyncWith Preempt $ do
results <- fetcher scope session searchString
return $ Just $ do
which.listOverlaySearchResults .= newList results
which.listOverlaySearching .= False
-- Now that the results are available, check to see if the
-- search string changed since this request was submitted.
-- If so, issue another search.
afterSearchString <- listOverlaySearchString which
when (searchString /= afterSearchString) $ resetListOverlaySearch which
-- | Generically handle an event for the list overlay state targeted
-- by the specified lens. Automatically dispatches new searches in the
-- overlay's editor if the editor contents change.
onEventListOverlay :: Lens' ChatState (ListOverlayState a b)
-- ^ Which overlay to dispatch to?
-> (KeyConfig -> [Keybinding])
-- ^ The keybinding builder
-> Vty.Event
-- ^ The event
-> MH ()
onEventListOverlay which keybindings =
handleKeyboardEvent keybindings $ \e -> do
-- Get the editor content before the event.
before <- listOverlaySearchString which
-- Handle the editor input event.
mhHandleEventLensed (which.listOverlaySearchInput) E.handleEditorEvent e
-- Get the editor content after the event. If the string changed,
-- start a new search.
after <- listOverlaySearchString which
when (before /= after) $ resetListOverlaySearch which