rasa-0.1.10: src/Rasa/Internal/Action.hs
module Rasa.Internal.Action
( Action(..)
, dispatchActionAsync
, asyncActionProvider
, bufferDo
, addBuffer
, getBufRefs
, getExt
, setExt
, overExt
, exit
, shouldExit
, getBuffer
, getEditor
) where
import Rasa.Internal.ActionMonads
import Rasa.Internal.Editor
import Rasa.Internal.Buffer
import Rasa.Internal.Extensions
import qualified Yi.Rope as Y
-- | dispatchActionAsync allows you to perform a task asynchronously and then apply the
-- result. In @dispatchActionAsync asyncAction@, @asyncAction@ is an IO which resolves to
-- an Action, note that the context in which the second action is executed is
-- NOT the same context in which dispatchActionAsync is called; it is likely that text and
-- other state have changed while the IO executed, so it's a good idea to check
-- (inside the applying Action) that things are in a good state before making
-- changes. Here's an example:
--
-- > asyncCapitalize :: Action ()
-- > asyncCapitalize = do
-- > txt <- focusDo getText
-- > -- We give dispatchActionAsync an IO which resolves in an action
-- > dispatchActionAsync $ ioPart txt
-- >
-- > ioPart :: Text -> IO (Action ())
-- > ioPart txt = do
-- > result <- longAsyncronousCapitalizationProgram txt
-- > -- Note that this returns an Action, but it's still wrapped in IO
-- > return $ maybeApplyResult txt result
-- >
-- > maybeApplyResult :: Text -> Text -> Action ()
-- > maybeApplyResult oldTxt capitalized = do
-- > -- We get the current buffer's text, which may have changed since we started
-- > newTxt <- focusDo getText
-- > if newTxt == oldTxt
-- > -- If the text is the same as it was, we can apply the transformation
-- > then focusDo (setText capitalized)
-- > -- Otherwise we can choose to re-queue the whole action and try again
-- > -- Or we could just give up.
-- > else asyncCapitalize
dispatchActionAsync :: IO (Action ()) -> Action ()
dispatchActionAsync ioAction = liftActionF $ DispatchActionAsync ioAction ()
-- | Don't let the type signature confuse you; it's much simpler than it seems.
-- The first argument is a function which takes an action provider; the action provider
-- will be passed a dispatch function which can be called as often as you like with @Action ()@s.
-- When it is passed an 'Action' it forks off an IO to dispatch that 'Action' to the main event loop.
-- Note that the dispatch function calls forkIO on its own; so there's no need for you to do so.
--
-- Use this function when you have some long-running process which dispatches multiple 'Action's.
--
-- Here's an example which fires a @Timer@ event every second.
--
-- > data Timer = TimerFired
-- > dispatchTimer :: Action ()
-- > dispatchTimer = mkDispatcher Timer
-- > myTimer :: (Action () -> IO ()) -> IO ()
-- > myTimer dispatch = forever $ dispatch dispatchTimer >> threadDelay 1000000
-- >
-- > myAction :: Action ()
-- > myAction = onInit $ asyncActionProvider myTimer
asyncActionProvider :: ((Action () -> IO ()) -> IO ()) -> Action ()
asyncActionProvider asyncActionProv = liftActionF $ AsyncActionProvider asyncActionProv ()
-- | Runs a BufAction over the given BufRefs, returning any results.
--
-- Result list is not guaranteed to be the same length or positioning as input BufRef list; some buffers may no
-- longer exist.
bufferDo :: [BufRef] -> BufAction r -> Action [r]
bufferDo bufRefs bufAct = liftActionF $ BufferDo bufRefs bufAct id
-- | Adds a new buffer and returns the BufRef
addBuffer :: Y.YiString -> Action BufRef
addBuffer txt = liftActionF $ AddBuffer txt id
-- | Returns an up-to-date list of all 'BufRef's
getBufRefs :: Action [BufRef]
getBufRefs = liftActionF $ GetBufRefs id
-- | Retrieve the entire editor state. This is read-only for logging/rendering/debugging purposes only.
getEditor :: Action Editor
getEditor = liftActionF $ GetEditor id
-- | Retrieve a buffer. This is read-only for logging/rendering/debugging purposes only.
getBuffer :: BufRef -> Action (Maybe Buffer)
getBuffer bufRef = liftActionF $ GetBuffer bufRef id
-- | This signals to the editor that you'd like to shutdown. The current events
-- will finish processing, then the 'Rasa.Internal.Listeners.onExit' event will be dispatched,
-- then the editor will exit.
exit :: Action ()
exit = liftActionF $ Exit ()
shouldExit :: Action Bool
shouldExit = liftActionF $ ShouldExit id