matterhorn-50200.17.0: src/Matterhorn/State/ListWindow.hs
{-# LANGUAGE RankNTypes #-}
module Matterhorn.State.ListWindow
( listWindowActivateCurrent
, listWindowActivate
, listWindowSearchString
, listWindowMove
, exitListWindow
, enterListWindowMode
, resetListWindowSearch
, onEventListWindow
)
where
import Prelude ()
import Matterhorn.Prelude
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, TeamId )
import qualified Graphics.Vty as Vty
import Matterhorn.Types
import Matterhorn.State.Common
import Matterhorn.State.Editing ( editingKeybindings )
import Matterhorn.Events.Keybindings ( KeyConfig, KeyHandlerMap, handleKeyboardEvent )
-- | Activate the specified list window's selected item by invoking the
-- window's configured enter keypress handler function.
listWindowActivateCurrent :: TeamId -> Lens' ChatState (ListWindowState a b) -> MH ()
listWindowActivateCurrent tId which = do
mItem <- L.listSelectedElement <$> use (which.listWindowSearchResults)
case mItem of
Nothing -> return ()
Just (_, val) -> listWindowActivate tId which val
-- | Activate the specified list window's selected item by invoking the
-- window's configured enter keypress handler function.
listWindowActivate :: TeamId -> Lens' ChatState (ListWindowState a b) -> a -> MH ()
listWindowActivate tId which val = do
handler <- use (which.listWindowEnterHandler)
activated <- handler val
if activated
then popMode tId
else return ()
-- | Get the current search string for the specified window.
listWindowSearchString :: Lens' ChatState (ListWindowState a b) -> MH Text
listWindowSearchString which =
(head . E.getEditContents) <$> use (which.listWindowSearchInput)
-- | Move the list cursor in the specified window.
listWindowMove :: Lens' ChatState (ListWindowState a b)
-- ^ Which window
-> (L.List Name a -> L.List Name a)
-- ^ How to transform the list in the window
-> MH ()
listWindowMove which how = which.listWindowSearchResults %= how
-- | Clear the state of the specified list window and return to the
-- Main mode.
exitListWindow :: TeamId
-> Lens' ChatState (ListWindowState a b)
-- ^ Which window to reset
-> MH ()
exitListWindow tId which = do
newList <- use (which.listWindowNewList)
which.listWindowSearchResults .= newList mempty
which.listWindowEnterHandler .= (const $ return False)
popMode tId
-- | Initialize a list window with the specified arguments and switch
-- to the specified mode.
enterListWindowMode :: TeamId
-> (Lens' ChatState (ListWindowState a b))
-- ^ Which window to initialize
-> Mode
-- ^ The mode to change to
-> b
-- ^ The window's initial search scope
-> (a -> MH Bool)
-- ^ The window's enter keypress handler
-> (b -> Session -> Text -> IO (Vec.Vector a))
-- ^ The window's results fetcher function
-> MH ()
enterListWindowMode tId which mode scope enterHandler fetcher = do
which.listWindowSearchScope .= scope
which.listWindowSearchInput.E.editContentsL %= Z.clearZipper
which.listWindowEnterHandler .= enterHandler
which.listWindowFetchResults .= fetcher
which.listWindowSearching .= False
newList <- use (which.listWindowNewList)
which.listWindowSearchResults .= newList mempty
pushMode tId mode
resetListWindowSearch which
-- | Reset the window's search by initiating a new search request for
-- the string that is currently in the window's editor. This does
-- nothing if a search for this window is already in progress.
resetListWindowSearch :: Lens' ChatState (ListWindowState a b) -> MH ()
resetListWindowSearch which = do
searchPending <- use (which.listWindowSearching)
when (not searchPending) $ do
searchString <- listWindowSearchString which
which.listWindowSearching .= True
newList <- use (which.listWindowNewList)
session <- getSession
scope <- use (which.listWindowSearchScope)
fetcher <- use (which.listWindowFetchResults)
doAsyncWith Preempt $ do
results <- fetcher scope session searchString
return $ Just $ do
which.listWindowSearchResults .= newList results
which.listWindowSearching .= 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 <- listWindowSearchString which
when (searchString /= afterSearchString) $ resetListWindowSearch which
-- | Generically handle an event for the list window state targeted
-- by the specified lens. Automatically dispatches new searches in the
-- window's editor if the editor contents change.
onEventListWindow :: Lens' ChatState (ListWindowState a b)
-- ^ Which window to dispatch to?
-> (KeyConfig -> KeyHandlerMap)
-- ^ The keybinding builder
-> Vty.Event
-- ^ The event
-> MH Bool
onEventListWindow which keybindings =
handleEventWith [ handleKeyboardEvent keybindings
, handleEditorEvent which
]
handleEditorEvent :: Lens' ChatState (ListWindowState a b) -> Vty.Event -> MH Bool
handleEditorEvent which e = do
-- Get the editor content before the event.
before <- listWindowSearchString which
-- First find a matching keybinding in the keybinding list.
handled <- handleKeyboardEvent (editingKeybindings (which.listWindowSearchInput)) e
-- If we didn't find a matching binding, just handle the event as a
-- normal editor input event.
when (not handled) $
mhHandleEventLensed (which.listWindowSearchInput) E.handleEditorEvent e
-- Get the editor content after the event. If the string changed,
-- start a new search.
after <- listWindowSearchString which
when (before /= after) $ resetListWindowSearch which
return True