-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | A modular text editor
--
-- A modular text editor This is only a snippet, see the project's
-- README.
--
-- Rasa is a text editor project with a few interesting goals. For better
-- or worse it attempts to be as modular as possible. This means that
-- most functionality which would typically be considered to be
-- core in other editors is implemented as extensions in Rasa.
-- This approach comes with its own share of pros and cons, for instance:
--
-- Pros
--
--
-- - Implementing most core functionality as extensions ensures a
-- powerful and elegant extension interface.
-- - Flexibility; don't like the default cursor implementation? Write
-- your own!
-- - Adaptability; the core of Rasa is miniscule, you can mix and match
-- extensions to build any editor you want.
--
--
-- Cons
--
--
-- - Module cross-dependencies makes the community infrastructure more
-- fragile; We'll likely have to develop a solution to this as a
-- community as time goes on.
-- - Fragmentation; Not having a single implementation for a given
-- feature means extensions that depend on a feature have to pick a
-- specific implementation to augment. Over time data-structures and
-- types will be standardized into Rasa's core to help alleviate
-- this.
--
--
-- While highly experimental, I've found the current API to be quite
-- expressive and adaptable; for instance I was able to implement the
-- notion of multiple cursors using the extension API in less than a day.
-- I hope to keep the learning curve low as development continues.
--
-- Getting Started
--
-- First clone the Github repo and try running the example-config
-- included there. Once you get it running (see the README) then
-- you can customize your keymap to add a few mappings you like. Then I'd
-- check out the Building your own extensions guide. It goes in
-- depth into everything you'd want to know!
--
-- If you have any issues (and I'm sure there'll be a few; it's a new
-- project!) please report them here and we'll talk about it!
@package rasa
@version 0.1.8
module Rasa.Internal.Text
-- | An iso which converts to/from YiString -> Text
asText :: Iso' YiString Text
-- | An iso which converts to/from YiString -> String
asString :: Iso' YiString String
-- | An iso which converts to/from YiString -> [YiString]
asLines :: Iso' YiString [YiString]
module Rasa.Internal.Range
-- | A type alias to Coord' which specializes the types to integers.
type Coord = Coord' Int Int
-- | (Coord Row Column) represents a char in a block of text. (zero
-- indexed) e.g. Coord 0 0 is the first character in the text, Coord 2 1
-- is the second character of the third row
data Coord' a b
Coord :: a -> b -> Coord' a b
[_coordRow] :: Coord' a b -> a
[_coordCol] :: Coord' a b -> b
-- | Applies a function over the row of a Coord
overRow :: (Int -> Int) -> Coord -> Coord
-- | Applies a function over the column of a Coord
overCol :: (Int -> Int) -> Coord -> Coord
-- | Applies a function over both functors in any Bifunctor.
overBoth :: Bifunctor f => (a -> b) -> f a a -> f b b
coordRow :: forall a_ag8S b_ag8T a_aghm. Lens (Coord' a_ag8S b_ag8T) (Coord' a_aghm b_ag8T) a_ag8S a_aghm
coordCol :: forall a_ag8S b_ag8T b_aghl. Lens (Coord' a_ag8S b_ag8T) (Coord' a_ag8S b_aghl) b_ag8T b_aghl
-- | An Offset represents an exact position in a file as a number of
-- characters from the start.
newtype Offset
Offset :: Int -> Offset
-- | Given the text you're operating over, creates an iso from an
-- Offset to a Coord.
asCoord :: YiString -> Iso' Offset Coord
-- | This will restrict a given Coord to a valid one which lies
-- within the given text.
clampCoord :: YiString -> Coord -> Coord
-- | This will restrict a given Range to a valid one which lies
-- within the given text.
clampRange :: YiString -> CrdRange -> CrdRange
-- | This represents a range between two coordinates (Coord)
data Range a b
Range :: a -> b -> Range a b
[_rStart] :: Range a b -> a
[_rEnd] :: Range a b -> b
-- | A type alias to Range' which specializes the types to
-- Coords.
type CrdRange = Range Coord Coord
-- | A lens over text which is encompassed by a Range
range :: CrdRange -> Lens' YiString YiString
rStart :: forall a_adXu b_adXv a_ag8D. Lens (Range a_adXu b_adXv) (Range a_ag8D b_adXv) a_adXu a_ag8D
rEnd :: forall a_adXu b_adXv b_ag8C. Lens (Range a_adXu b_adXv) (Range a_adXu b_ag8C) b_adXv b_ag8C
-- | Returns the number of rows and columns that a chunk of text spans as a
-- Coord
sizeOf :: YiString -> Coord
-- | Returns the number of rows and columns that a Range spans as a
-- Coord
sizeOfR :: CrdRange -> Coord
-- | Moves a Range by a given Coord It may be unintuitive,
-- but for (Coord row col) a given range will be moved down by row and to
-- the right by col.
moveRange :: Coord -> CrdRange -> CrdRange
-- | Moves a range forward by the given amount
moveRangeByN :: Int -> CrdRange -> CrdRange
-- | Moves a Coord forward by the given amount of columns
moveCursorByN :: Int -> Coord -> Coord
-- | Adds the rows and columns of the given two Coords.
moveCursor :: Coord -> Coord -> Coord
-- | A span which maps a piece of Monoidal data over a range.
data Span a b
Span :: a -> b -> Span a b
-- | Combines a list of spans containing some monoidal data into a list of
-- offsets with with the data that applies from each Offset forwards.
combineSpans :: forall a. Monoid a => [Span CrdRange a] -> [(Coord, a)]
-- | clamp min max val restricts val to be within min and max
-- (inclusive)
clamp :: Int -> Int -> Int -> Int
-- | A lens over text before a given Coord
beforeC :: Coord -> Lens' YiString YiString
-- | A lens over text after a given Coord
afterC :: Coord -> Lens' YiString YiString
instance GHC.Classes.Eq Rasa.Internal.Range.Marker
instance GHC.Show.Show Rasa.Internal.Range.Marker
instance GHC.Base.Functor (Rasa.Internal.Range.Span a)
instance (GHC.Classes.Eq b, GHC.Classes.Eq a) => GHC.Classes.Eq (Rasa.Internal.Range.Span a b)
instance (GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (Rasa.Internal.Range.Span a b)
instance GHC.Classes.Eq Rasa.Internal.Range.Offset
instance GHC.Show.Show Rasa.Internal.Range.Offset
instance Data.Bifunctor.Bifunctor Rasa.Internal.Range.Coord'
instance Data.Biapplicative.Biapplicative Rasa.Internal.Range.Coord'
instance (GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (Rasa.Internal.Range.Coord' a b)
instance Data.Bifunctor.Bifunctor Rasa.Internal.Range.Span
instance (GHC.Num.Num a, GHC.Num.Num b) => GHC.Num.Num (Rasa.Internal.Range.Coord' a b)
instance (GHC.Classes.Eq b, GHC.Classes.Eq a) => GHC.Classes.Eq (Rasa.Internal.Range.Coord' a b)
instance (GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (Rasa.Internal.Range.Coord' a b)
instance Data.Bifunctor.Bifunctor Rasa.Internal.Range.Range
instance Data.Bifoldable.Bifoldable Rasa.Internal.Range.Range
instance Data.Bitraversable.Bitraversable Rasa.Internal.Range.Range
instance (GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (Rasa.Internal.Range.Range a b)
instance (GHC.Classes.Eq b, GHC.Classes.Eq a) => GHC.Classes.Eq (Rasa.Internal.Range.Range a b)
instance (GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (Rasa.Internal.Range.Range a b)
module Rasa.Internal.Extensions
-- | A wrapper around an extension of any type so it can be stored in an
-- ExtMap
data Ext
Ext :: a -> Ext
-- | A map of extension types to their current value.
type ExtMap = Map TypeRep Ext
-- | Members of this class have access to buffer extensions. (Each
-- Buffer is a member of this class)
class HasBufExts s
-- | This lens focuses the Extensions States map of the in-scope buffer.
bufExts :: HasBufExts s => Lens' s (Map TypeRep Ext)
-- | Members of this class have access to editor extensions.
class HasExts s
-- | This lens focuses the Extensions States
exts :: HasExts s => Lens' s (Map TypeRep Ext)
-- | bufExt is a lens which will focus a given extension's state
-- within a buffer (within a BufAction). The lens will
-- automagically focus the required extension by using type inference.
-- It's a little bit of magic, if you treat the focus as a member of your
-- extension state it should just work out.
--
-- This lens falls back on the extension's Default instance (when
-- getting) if nothing has yet been stored.
bufExt :: forall a s. (Show a, Typeable a, Default a, HasBufExts s) => Lens' s a
-- | This is a lens which will focus the extension state that matches the
-- type inferred as the focal point. It's a little bit of magic, if you
-- treat the focus as a member of your extension state it should just
-- work out.
--
-- This lens falls back on the extension's Default instance (when
-- getting) if nothing has yet been stored.
ext :: forall a e. (Show a, Typeable a, Default a, HasExts e) => Lens' e a
instance GHC.Show.Show Rasa.Internal.Extensions.Ext
module Rasa.Internal.Buffer
-- | A buffer, holds the text in the buffer and any extension states that
-- are set on the buffer.
data Buffer
-- | This allows creation of polymorphic lenses over any type which has
-- access to a Buffer
class HasBuffer a
buffer :: HasBuffer a => Lens' a Buffer
-- | This lens focuses the text of the in-scope buffer.
text :: HasBuffer b => Lens' b YiString
-- | Creates a new buffer from the given text.
mkBuffer :: YiString -> Buffer
instance Rasa.Internal.Extensions.HasBufExts Rasa.Internal.Buffer.Buffer
instance GHC.Show.Show Rasa.Internal.Buffer.Buffer
instance Rasa.Internal.Buffer.HasBuffer Rasa.Internal.Buffer.Buffer
module Rasa.Internal.Editor
-- | This is the primary state of the editor.
data Editor
-- | This allows polymorphic lenses over anything that has access to an
-- Editor context
class HasEditor a
editor :: HasEditor a => Lens' a Editor
-- | A lens over the map of available buffers
buffers :: HasEditor e => Lens' e (IntMap Buffer)
-- | A lens over the exiting status of the editor
exiting :: HasEditor e => Lens' e Bool
-- | A lens over the next buffer id to be allocated
nextBufId :: HasEditor e => Lens' e Int
-- | An opaque reference to a buffer. When operating over a BufRef Rasa
-- checks if the Buffer still exists and simply ignores any
-- operations over non-existent buffers; typically returning
-- Nothing
newtype BufRef
BufRef :: Int -> BufRef
instance GHC.Show.Show Rasa.Internal.Editor.Editor
instance Rasa.Internal.Editor.HasEditor Rasa.Internal.Editor.Editor
instance Rasa.Internal.Extensions.HasExts Rasa.Internal.Editor.Editor
instance Data.Default.Class.Default Rasa.Internal.Editor.Editor
instance GHC.Classes.Ord Rasa.Internal.Editor.BufRef
instance GHC.Classes.Eq Rasa.Internal.Editor.BufRef
instance GHC.Show.Show Rasa.Internal.Editor.BufRef
module Rasa.Internal.Events
-- | This event is dispatched exactly once when the editor starts up.
data Init
Init :: Init
-- | This event is dispatched immediately before dispatching any events
-- from asyncronous event listeners (like Keypresss)
data BeforeEvent
BeforeEvent :: BeforeEvent
-- | This event is dispatched immediately before dispatching the
-- OnRender event.
data BeforeRender
BeforeRender :: BeforeRender
-- | This event is dispatched when it's time for extensions to render to
-- screen.
data OnRender
OnRender :: OnRender
-- | This event is dispatched immediately after dispatching
-- OnRender.
data AfterRender
AfterRender :: AfterRender
-- | This event is dispatched before exiting the editor, listen for this to
-- do any clean-up (saving files, etc.)
data Exit
Exit :: Exit
-- | This event is dispatched after adding a new buffer. The contained
-- BufRef refers to the new buffer.
data BufAdded
BufAdded :: BufRef -> BufAdded
-- | This event is dispatched in response to keyboard key presses. It
-- contains both the char that was pressed and any modifiers (Mod)
-- that where held when the key was pressed.
data Keypress
Keypress :: Char -> [Mod] -> Keypress
KEsc :: Keypress
KBS :: Keypress
KEnter :: Keypress
KUnknown :: Keypress
KLeft :: Keypress
KRight :: Keypress
KUp :: Keypress
KDown :: Keypress
-- | This represents each modifier key that could be pressed along with a
-- key.
data Mod
Ctrl :: Mod
Alt :: Mod
Shift :: Mod
-- | This is triggered when text in a buffer is changed. The Event data
-- includes the CrdRange that changed and the new text which is
-- now contined in that range.
data BufTextChanged
BufTextChanged :: CrdRange -> YiString -> BufTextChanged
instance GHC.Classes.Eq Rasa.Internal.Events.BufTextChanged
instance GHC.Show.Show Rasa.Internal.Events.BufTextChanged
instance GHC.Classes.Eq Rasa.Internal.Events.Keypress
instance GHC.Show.Show Rasa.Internal.Events.Keypress
instance GHC.Classes.Eq Rasa.Internal.Events.Mod
instance GHC.Show.Show Rasa.Internal.Events.Mod
instance GHC.Classes.Eq Rasa.Internal.Events.BufAdded
instance GHC.Show.Show Rasa.Internal.Events.BufAdded
instance GHC.Classes.Eq Rasa.Internal.Events.Exit
instance GHC.Show.Show Rasa.Internal.Events.Exit
instance GHC.Classes.Eq Rasa.Internal.Events.AfterRender
instance GHC.Show.Show Rasa.Internal.Events.AfterRender
instance GHC.Classes.Eq Rasa.Internal.Events.OnRender
instance GHC.Show.Show Rasa.Internal.Events.OnRender
instance GHC.Classes.Eq Rasa.Internal.Events.BeforeRender
instance GHC.Show.Show Rasa.Internal.Events.BeforeRender
instance GHC.Classes.Eq Rasa.Internal.Events.BeforeEvent
instance GHC.Show.Show Rasa.Internal.Events.BeforeEvent
instance GHC.Classes.Eq Rasa.Internal.Events.Init
instance GHC.Show.Show Rasa.Internal.Events.Init
module Rasa.Internal.Action
-- | This is a monad for performing actions against the editor. You can
-- register Actions to be run in response to events using
-- onEveryTrigger
--
-- Within an Action you can:
--
--
-- - Use liftIO for IO
-- - Access/edit extensions that are stored globally, see
-- ext
-- - Embed any Actions exported other extensions
-- - Embed buffer actions using bufDo or buffersDo
-- - Add/Edit/Focus buffers and a few other Editor-level things, see
-- the Rasa.Internal.Actions module.
--
newtype Action a
Action :: Free (ActionF ActionState) a -> Action a
[getAction] :: Action a -> Free (ActionF ActionState) a
-- | Runs an Action into an IO
runAction :: ActionState -> Action a -> IO (a, ActionState)
-- | Evals an Action into an IO
evalAction :: ActionState -> Action a -> IO a
-- | Execs an Action into an IO
execAction :: ActionState -> Action a -> IO ActionState
-- | This contains all data representing the editor's state. It acts as the
-- state object for an 'Action
data ActionState
mkActionState :: Output (Action ()) -> ActionState
-- | A wrapper around event listeners so they can be stored in
-- Listeners.
data Listener
Listener :: ListenerId -> (a -> Action ()) -> Listener
-- | An opaque reverence to a specific registered event-listener. A
-- ListenerId is used only to remove listeners later with
-- removeListener.
data ListenerId
ListenerId :: Int -> TypeRep -> ListenerId
-- | A map of Event types to a list of listeners for that event
type Listeners = Map TypeRep [Listener]
listeners :: Lens' ActionState Listeners
nextListenerId :: Lens' ActionState Int
actionQueue :: Lens' ActionState (Output (Action ()))
instance GHC.Show.Show Rasa.Internal.Action.ActionState
instance Rasa.Internal.Editor.HasEditor Rasa.Internal.Action.ActionState
instance Rasa.Internal.Extensions.HasExts Rasa.Internal.Action.ActionState
instance Control.Monad.State.Class.MonadState Rasa.Internal.Action.ActionState Rasa.Internal.Action.Action
instance Control.Monad.IO.Class.MonadIO Rasa.Internal.Action.Action
instance GHC.Base.Monad Rasa.Internal.Action.Action
instance GHC.Base.Applicative Rasa.Internal.Action.Action
instance GHC.Base.Functor Rasa.Internal.Action.Action
instance GHC.Base.Functor (Rasa.Internal.Action.ActionF state)
instance GHC.Classes.Eq Rasa.Internal.Action.ListenerId
module Rasa.Internal.Listeners
-- | A wrapper around event listeners so they can be stored in
-- Listeners.
data Listener
-- | A map of Event types to a list of listeners for that event
type Listeners = Map TypeRep [Listener]
-- | This registers an event listener, as long as the listener is
-- well-typed similar to this:
--
-- MyEventType -> Action () then it will be triggered on all
-- dispatched events of type MyEventType. It returns an ID which
-- may be used with removeListener to cancel the listener
onEveryTrigger :: forall a b. Typeable a => (a -> Action b) -> Action ListenerId
onEveryTrigger_ :: forall a b. Typeable a => (a -> Action b) -> Action ()
-- | This acts as onEveryTrigger but listens only for the first
-- event of a given type.
onNextEvent :: forall a b. Typeable a => (a -> Action b) -> Action ()
-- | Registers an action to be performed during the Initialization phase.
--
-- This phase occurs exactly ONCE when the editor starts up. Though
-- arbitrary actions may be performed in the configuration block; it's
-- recommended to embed such actions in the onInit event listener so that
-- all event listeners are registered before anything Actions occur.
onInit :: forall a. Action a -> Action ()
-- | Registers an action to be performed BEFORE each event phase.
beforeEveryEvent :: forall a. Action a -> Action ListenerId
beforeEveryEvent_ :: forall a. Action a -> Action ()
-- | Registers an action to be performed ONCE before only the NEXT event
-- phase.
beforeNextEvent :: forall a. Action a -> Action ()
-- | Registers an action to be performed BEFORE each render phase.
--
-- This is a good spot to add information useful to the renderer since
-- all actions have been performed. Only cosmetic changes should occur
-- during this phase.
beforeEveryRender :: forall a. Action a -> Action ListenerId
beforeEveryRender_ :: forall a. Action a -> Action ()
-- | Registers an action to be performed ONCE before only the NEXT render
-- phase.
beforeNextRender :: forall a. Action a -> Action ()
-- | Registers an action to be performed during each render phase.
--
-- This phase should only be used by extensions which actually render
-- something.
onEveryRender :: forall a. Action a -> Action ListenerId
onEveryRender_ :: forall a. Action a -> Action ()
-- | Registers an action to be performed ONCE before only the NEXT render
-- phase.
--
-- This phase should only be used by extensions which actually render
-- something.
onNextRender :: forall a. Action a -> Action ()
-- | Registers an action to be performed AFTER each render phase.
--
-- This is useful for cleaning up extension state that was registered for
-- the renderer, but needs to be cleared before the next iteration.
afterEveryRender :: forall a. Action a -> Action ListenerId
afterEveryRender_ :: forall a. Action a -> Action ()
-- | Registers an action to be performed after the NEXT render phase.
afterNextRender :: forall a. Action a -> Action ()
-- | Use this to dispatch an event of any type, any listeners which are
-- listening for this event will be triggered with the provided event.
-- Use this within an Action.
dispatchEvent :: Typeable a => a -> Action ()
-- | Registers an action to be performed during the exit phase.
--
-- This is only triggered exactly once when the editor is shutting down.
-- It allows an opportunity to do clean-up, kill any processes you've
-- started, or save any data before the editor terminates.
onExit :: forall a. Action a -> Action ()
-- | This removes a listener and prevents it from responding to any more
-- events.
removeListener :: ListenerId -> Action ()
-- | This extracts all event listeners from a map of listeners which match
-- the type of the provided event.
matchingListeners :: forall a. Typeable a => Listeners -> [a -> Action ()]
-- | Registers an action to be performed after a new buffer is added.
--
-- The supplied function will be called with a BufRef to the new
-- buffer, and the resulting Action will be run.
onBufAdded :: forall a. (BufRef -> Action a) -> Action ListenerId
-- | This is fired every time text in a buffer changes.
--
-- The range of text which was altered and the new value of that text are
-- provided inside a BufTextChanged event.
onBufTextChanged :: forall a. (CrdRange -> YiString -> Action a) -> Action ListenerId
module Rasa.Internal.Async
-- | This allows long-running IO processes to provide Events to Rasa
-- asyncronously.
--
-- Don't let the type signature confuse you; it's much simpler than it
-- seems.
--
-- Let's break it down:
--
-- (Dispatcher -> IO ()): Dispatcher is
-- a type alias just to make defining your own functions easier; Using
-- Dispatcher with asyncEventProvider requires the
-- Rank2Types language pragma.
--
-- This type as a whole represents a function which accepts a
-- Dispatcher and returns an IO; the dispatcher itself
-- accepts data of ANY Typeable type and emits it as an event (see
-- the Rasa.Internal.Events).
--
-- When you call asyncEventProvider you pass it a function which
-- accepts a dispatch function as an argument and then calls it
-- with various events within the resulting IO.
--
-- Note that asyncEventProvider calls forkIO internally, so there's no
-- need to do that yourself.
--
-- Here's a simple example which fires a Timer event every
-- second.
--
--
-- {-# language Rank2Types #-}
-- data Timer = Timer
-- myTimer :: Dispatcher -> IO ()
-- myTimer dispatch = forever $ dispatch Timer >> threadDelay 1000000
--
-- myAction :: Action ()
-- myAction = onInit $ asyncEventProvider myTimer
--
asyncEventProvider :: (Dispatcher -> IO ()) -> Action ()
-- | This is a type alias to make defining your event provider functions
-- easier; It represents the function your event provider function will
-- be passed to allow dispatching events. Using this type requires the
-- Rank2Types language pragma.
type Dispatcher = forall a. Typeable a => a -> IO ()
-- | 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 Actions.
asyncActionProvider :: ((Action () -> IO ()) -> IO ()) -> Action ()
-- | This function takes an IO which results in some Event, it runs the IO
-- asynchronously and dispatches the event
dispatchEventAsync :: Typeable a => IO a -> Action ()
-- | 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 $ use text
-- -- 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 (use text)
-- if newTxt == oldTxt
-- -- If the text is the same as it was, we can apply the transformation
-- then focusDo (text .= 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 ()
module Rasa.Internal.BufAction
-- | This is a monad for performing actions on a specific buffer. You run
-- BufActions by embedding them in a Action via
-- bufferDo or buffersDo
--
-- Within a BufAction you can:
--
--
newtype BufAction a
BufAction :: Free (BufActionF BufActionState) a -> BufAction a
[getBufAction] :: BufAction a -> Free (BufActionF BufActionState) a
-- | Returns the text of the current buffer
getText :: BufAction YiString
-- | Sets the text of the current buffer
setText :: YiString -> BufAction ()
-- | Gets the range of text from the buffer
getRange :: CrdRange -> BufAction YiString
-- | Sets the range of text from the buffer
setRange :: CrdRange -> YiString -> BufAction ()
-- | Allows running state actions over BufActionState; used to lift mtl
-- state functions
liftState :: (BufActionState -> (a, BufActionState)) -> BufAction a
-- | This lifts up an Action to be run inside a BufAction
liftAction :: Action r -> BufAction r
-- | This lifts up a bufAction into an Action which performs the
-- BufAction over the referenced buffer and returns the result (if
-- the buffer existed)
runBufAction :: BufAction a -> BufRef -> Action (Maybe a)
instance GHC.Base.Monad Rasa.Internal.BufAction.BufAction
instance GHC.Base.Applicative Rasa.Internal.BufAction.BufAction
instance GHC.Base.Functor Rasa.Internal.BufAction.BufAction
instance GHC.Base.Functor (Rasa.Internal.BufAction.BufActionF state)
instance Rasa.Internal.Extensions.HasBufExts Rasa.Internal.BufAction.BufActionState
instance Control.Monad.State.Class.MonadState Rasa.Internal.BufAction.BufActionState Rasa.Internal.BufAction.BufAction
instance Control.Monad.IO.Class.MonadIO Rasa.Internal.BufAction.BufAction
module Rasa.Internal.Actions
-- | This lifts a BufAction to an Action which performs the
-- BufAction on the buffer referred to by the BufRef If the
-- buffer referred to no longer exists this returns: Nothing.
bufDo :: BufRef -> BufAction a -> Action (Maybe a)
bufDo_ :: BufRef -> BufAction a -> Action ()
-- | This lifts a BufAction to an Action which performs the
-- BufAction on every buffer and collects the return values as a
-- list.
buffersDo :: BufAction a -> Action [a]
buffersDo_ :: BufAction a -> Action ()
-- | This signals to the editor that you'd like to shutdown. The current
-- events will finish processing, then the onExit event will be
-- dispatched, then the editor will exit.
exit :: Action ()
-- | This adds a new buffer with the given text, returning a reference to
-- that buffer.
newBuffer :: YiString -> Action BufRef
-- | Returns an up-to-date list of all BufRefs
getBufRefs :: Action [BufRef]
-- | Returns an up-to-date list of all Buffers, returned values are
-- read-only; altering them has no effect on the actual stored buffers.
-- This function is useful for renderers.
getBuffers :: Action [(BufRef, Buffer)]
-- | Returns the Buffer for a BufRef if it still exists. This is
-- read-only; altering the buffer has no effect on the stored buffer.
-- This function is useful for renderers.
getBuffer :: BufRef -> Action (Maybe Buffer)
-- | Gets BufRef that comes after the one provided
nextBufRef :: BufRef -> Action BufRef
-- | Gets BufRef that comes before the one provided
prevBufRef :: BufRef -> Action BufRef
-- | Runs function over given range of text
overRange :: CrdRange -> (YiString -> YiString) -> BufAction ()
-- | Replaces the text in the given range with the given text.
replaceRange :: CrdRange -> YiString -> BufAction ()
-- | Deletes the text in the given range from the buffer.
deleteRange :: CrdRange -> BufAction ()
-- | Inserts text into the buffer at the given Coord.
insertAt :: Coord -> YiString -> BufAction ()
-- | Returns the number of rows and columns that a chunk of text spans as a
-- Coord
sizeOf :: YiString -> Coord
-- | This module contains the public API for building an extension for
-- Rasa. It re-exports the parts of rasa that are public API for creating
-- extensions.
--
-- There are two main things that an extension can do, either react to
-- editor events, or expose useful actions and/or state for other
-- extensions to use.
--
-- Whether performing its own actions or being used by a different
-- extension an extension will want to define some Actions to
-- perform. Actions can operate over buffers or even perform IO and
-- comprise the main way in which extensons do what they need to do. Read
-- more here: Action, BufAction.
--
-- To sum it all up, Here's an example of a simple logging extension that
-- simply writes each keypress to a file.
--
--
-- logKeypress :: Keypress -> Action ()
-- logKeypress (Keypress char _) = liftIO $ appendFile "logs" ("You pressed " ++ [char] ++ "\n")
--
-- logger :: Action ()
-- logger = do
-- onInit $ liftIO $ writeFile "logs" "==Logs==\n"
-- -- Listeners should also be registered using 'onInit'.
-- -- It ensures all listeners are ready before any actions occur.
-- onInit $ onEveryTrigger_ logKeypress
-- onExit $ liftIO $ appendFile "logs" "==Done=="
--
--
-- Check out this tutorial on building extensions, it's also just a great
-- way to learn how the editor works: Extension-Guide.
module Rasa.Ext
-- | This is a monad for performing actions against the editor. You can
-- register Actions to be run in response to events using
-- onEveryTrigger
--
-- Within an Action you can:
--
--
-- - Use liftIO for IO
-- - Access/edit extensions that are stored globally, see
-- ext
-- - Embed any Actions exported other extensions
-- - Embed buffer actions using bufDo or buffersDo
-- - Add/Edit/Focus buffers and a few other Editor-level things, see
-- the Rasa.Internal.Actions module.
--
data Action a
-- | This signals to the editor that you'd like to shutdown. The current
-- events will finish processing, then the onExit event will be
-- dispatched, then the editor will exit.
exit :: Action ()
-- | This adds a new buffer with the given text, returning a reference to
-- that buffer.
newBuffer :: YiString -> Action BufRef
-- | Gets BufRef that comes after the one provided
nextBufRef :: BufRef -> Action BufRef
-- | Gets BufRef that comes before the one provided
prevBufRef :: BufRef -> Action BufRef
-- | Returns an up-to-date list of all BufRefs
getBufRefs :: Action [BufRef]
-- | Returns an up-to-date list of all Buffers, returned values are
-- read-only; altering them has no effect on the actual stored buffers.
-- This function is useful for renderers.
getBuffers :: Action [(BufRef, Buffer)]
-- | Returns the Buffer for a BufRef if it still exists. This is
-- read-only; altering the buffer has no effect on the stored buffer.
-- This function is useful for renderers.
getBuffer :: BufRef -> Action (Maybe Buffer)
-- | A buffer, holds the text in the buffer and any extension states that
-- are set on the buffer.
data Buffer
-- | This allows creation of polymorphic lenses over any type which has
-- access to a Buffer
class HasBuffer a
buffer :: HasBuffer a => Lens' a Buffer
-- | An opaque reference to a buffer. When operating over a BufRef Rasa
-- checks if the Buffer still exists and simply ignores any
-- operations over non-existent buffers; typically returning
-- Nothing
data BufRef
-- | This lens focuses the text of the in-scope buffer.
text :: HasBuffer b => Lens' b YiString
-- | This allows polymorphic lenses over anything that has access to an
-- Editor context
class HasEditor a
-- | Returns the text of the current buffer
getText :: BufAction YiString
-- | Gets the range of text from the buffer
getRange :: CrdRange -> BufAction YiString
-- | This is a monad for performing actions on a specific buffer. You run
-- BufActions by embedding them in a Action via
-- bufferDo or buffersDo
--
-- Within a BufAction you can:
--
--
data BufAction a
-- | This lifts up an Action to be run inside a BufAction
liftAction :: Action r -> BufAction r
-- | This lifts a BufAction to an Action which performs the
-- BufAction on the buffer referred to by the BufRef If the
-- buffer referred to no longer exists this returns: Nothing.
bufDo :: BufRef -> BufAction a -> Action (Maybe a)
bufDo_ :: BufRef -> BufAction a -> Action ()
-- | This lifts a BufAction to an Action which performs the
-- BufAction on every buffer and collects the return values as a
-- list.
buffersDo :: BufAction a -> Action [a]
buffersDo_ :: BufAction a -> Action ()
-- | Runs function over given range of text
overRange :: CrdRange -> (YiString -> YiString) -> BufAction ()
-- | Replaces the text in the given range with the given text.
replaceRange :: CrdRange -> YiString -> BufAction ()
-- | Deletes the text in the given range from the buffer.
deleteRange :: CrdRange -> BufAction ()
-- | Inserts text into the buffer at the given Coord.
insertAt :: Coord -> YiString -> BufAction ()
-- | Returns the number of rows and columns that a chunk of text spans as a
-- Coord
sizeOf :: YiString -> Coord
-- | Members of this class have access to editor extensions.
class HasExts s
-- | This lens focuses the Extensions States
exts :: HasExts s => Lens' s (Map TypeRep Ext)
-- | This is a lens which will focus the extension state that matches the
-- type inferred as the focal point. It's a little bit of magic, if you
-- treat the focus as a member of your extension state it should just
-- work out.
--
-- This lens falls back on the extension's Default instance (when
-- getting) if nothing has yet been stored.
ext :: forall a e. (Show a, Typeable a, Default a, HasExts e) => Lens' e a
-- | Members of this class have access to buffer extensions. (Each
-- Buffer is a member of this class)
class HasBufExts s
-- | This lens focuses the Extensions States map of the in-scope buffer.
bufExts :: HasBufExts s => Lens' s (Map TypeRep Ext)
-- | bufExt is a lens which will focus a given extension's state
-- within a buffer (within a BufAction). The lens will
-- automagically focus the required extension by using type inference.
-- It's a little bit of magic, if you treat the focus as a member of your
-- extension state it should just work out.
--
-- This lens falls back on the extension's Default instance (when
-- getting) if nothing has yet been stored.
bufExt :: forall a s. (Show a, Typeable a, Default a, HasBufExts s) => Lens' s a
-- | This event is dispatched in response to keyboard key presses. It
-- contains both the char that was pressed and any modifiers (Mod)
-- that where held when the key was pressed.
data Keypress
Keypress :: Char -> [Mod] -> Keypress
KEsc :: Keypress
KBS :: Keypress
KEnter :: Keypress
KUnknown :: Keypress
KLeft :: Keypress
KRight :: Keypress
KUp :: Keypress
KDown :: Keypress
-- | This represents each modifier key that could be pressed along with a
-- key.
data Mod
Ctrl :: Mod
Alt :: Mod
Shift :: Mod
-- | An opaque reverence to a specific registered event-listener. A
-- ListenerId is used only to remove listeners later with
-- removeListener.
data ListenerId
-- | Use this to dispatch an event of any type, any listeners which are
-- listening for this event will be triggered with the provided event.
-- Use this within an Action.
dispatchEvent :: Typeable a => a -> Action ()
-- | This registers an event listener, as long as the listener is
-- well-typed similar to this:
--
-- MyEventType -> Action () then it will be triggered on all
-- dispatched events of type MyEventType. It returns an ID which
-- may be used with removeListener to cancel the listener
onEveryTrigger :: forall a b. Typeable a => (a -> Action b) -> Action ListenerId
onEveryTrigger_ :: forall a b. Typeable a => (a -> Action b) -> Action ()
-- | This acts as onEveryTrigger but listens only for the first
-- event of a given type.
onNextEvent :: forall a b. Typeable a => (a -> Action b) -> Action ()
-- | This removes a listener and prevents it from responding to any more
-- events.
removeListener :: ListenerId -> Action ()
-- | Registers an action to be performed during the Initialization phase.
--
-- This phase occurs exactly ONCE when the editor starts up. Though
-- arbitrary actions may be performed in the configuration block; it's
-- recommended to embed such actions in the onInit event listener so that
-- all event listeners are registered before anything Actions occur.
onInit :: forall a. Action a -> Action ()
-- | Registers an action to be performed BEFORE each event phase.
beforeEveryEvent :: forall a. Action a -> Action ListenerId
beforeEveryEvent_ :: forall a. Action a -> Action ()
-- | Registers an action to be performed ONCE before only the NEXT event
-- phase.
beforeNextEvent :: forall a. Action a -> Action ()
-- | Registers an action to be performed BEFORE each render phase.
--
-- This is a good spot to add information useful to the renderer since
-- all actions have been performed. Only cosmetic changes should occur
-- during this phase.
beforeEveryRender :: forall a. Action a -> Action ListenerId
beforeEveryRender_ :: forall a. Action a -> Action ()
-- | Registers an action to be performed ONCE before only the NEXT render
-- phase.
beforeNextRender :: forall a. Action a -> Action ()
-- | Registers an action to be performed during each render phase.
--
-- This phase should only be used by extensions which actually render
-- something.
onEveryRender :: forall a. Action a -> Action ListenerId
onEveryRender_ :: forall a. Action a -> Action ()
-- | Registers an action to be performed ONCE before only the NEXT render
-- phase.
--
-- This phase should only be used by extensions which actually render
-- something.
onNextRender :: forall a. Action a -> Action ()
-- | Registers an action to be performed AFTER each render phase.
--
-- This is useful for cleaning up extension state that was registered for
-- the renderer, but needs to be cleared before the next iteration.
afterEveryRender :: forall a. Action a -> Action ListenerId
afterEveryRender_ :: forall a. Action a -> Action ()
-- | Registers an action to be performed after the NEXT render phase.
afterNextRender :: forall a. Action a -> Action ()
-- | Registers an action to be performed during the exit phase.
--
-- This is only triggered exactly once when the editor is shutting down.
-- It allows an opportunity to do clean-up, kill any processes you've
-- started, or save any data before the editor terminates.
onExit :: forall a. Action a -> Action ()
-- | Registers an action to be performed after a new buffer is added.
--
-- The supplied function will be called with a BufRef to the new
-- buffer, and the resulting Action will be run.
onBufAdded :: forall a. (BufRef -> Action a) -> Action ListenerId
-- | This is fired every time text in a buffer changes.
--
-- The range of text which was altered and the new value of that text are
-- provided inside a BufTextChanged event.
onBufTextChanged :: forall a. (CrdRange -> YiString -> Action a) -> Action ListenerId
-- | This is a type alias to make defining your event provider functions
-- easier; It represents the function your event provider function will
-- be passed to allow dispatching events. Using this type requires the
-- Rank2Types language pragma.
type Dispatcher = forall a. Typeable a => a -> IO ()
-- | 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 $ use text
-- -- 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 (use text)
-- if newTxt == oldTxt
-- -- If the text is the same as it was, we can apply the transformation
-- then focusDo (text .= 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 ()
-- | This function takes an IO which results in some Event, it runs the IO
-- asynchronously and dispatches the event
dispatchEventAsync :: Typeable a => IO a -> Action ()
-- | This allows long-running IO processes to provide Events to Rasa
-- asyncronously.
--
-- Don't let the type signature confuse you; it's much simpler than it
-- seems.
--
-- Let's break it down:
--
-- (Dispatcher -> IO ()): Dispatcher is
-- a type alias just to make defining your own functions easier; Using
-- Dispatcher with asyncEventProvider requires the
-- Rank2Types language pragma.
--
-- This type as a whole represents a function which accepts a
-- Dispatcher and returns an IO; the dispatcher itself
-- accepts data of ANY Typeable type and emits it as an event (see
-- the Rasa.Internal.Events).
--
-- When you call asyncEventProvider you pass it a function which
-- accepts a dispatch function as an argument and then calls it
-- with various events within the resulting IO.
--
-- Note that asyncEventProvider calls forkIO internally, so there's no
-- need to do that yourself.
--
-- Here's a simple example which fires a Timer event every
-- second.
--
--
-- {-# language Rank2Types #-}
-- data Timer = Timer
-- myTimer :: Dispatcher -> IO ()
-- myTimer dispatch = forever $ dispatch Timer >> threadDelay 1000000
--
-- myAction :: Action ()
-- myAction = onInit $ asyncEventProvider myTimer
--
asyncEventProvider :: (Dispatcher -> IO ()) -> Action ()
-- | 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 Actions.
asyncActionProvider :: ((Action () -> IO ()) -> IO ()) -> Action ()
-- | This represents a range between two coordinates (Coord)
data Range a b
Range :: a -> b -> Range a b
[_rStart] :: Range a b -> a
[_rEnd] :: Range a b -> b
-- | A type alias to Range' which specializes the types to
-- Coords.
type CrdRange = Range Coord Coord
-- | A type alias to Coord' which specializes the types to integers.
type Coord = Coord' Int Int
-- | (Coord Row Column) represents a char in a block of text. (zero
-- indexed) e.g. Coord 0 0 is the first character in the text, Coord 2 1
-- is the second character of the third row
data Coord' a b
Coord :: a -> b -> Coord' a b
[_coordRow] :: Coord' a b -> a
[_coordCol] :: Coord' a b -> b
-- | An Offset represents an exact position in a file as a number of
-- characters from the start.
newtype Offset
Offset :: Int -> Offset
-- | A span which maps a piece of Monoidal data over a range.
data Span a b
Span :: a -> b -> Span a b
-- | Applies a function over the row of a Coord
overRow :: (Int -> Int) -> Coord -> Coord
-- | Applies a function over the column of a Coord
overCol :: (Int -> Int) -> Coord -> Coord
coordRow :: forall a_ag8S b_ag8T a_aghm. Lens (Coord' a_ag8S b_ag8T) (Coord' a_aghm b_ag8T) a_ag8S a_aghm
coordCol :: forall a_ag8S b_ag8T b_aghl. Lens (Coord' a_ag8S b_ag8T) (Coord' a_ag8S b_aghl) b_ag8T b_aghl
-- | Applies a function over both functors in any Bifunctor.
overBoth :: Bifunctor f => (a -> b) -> f a a -> f b b
-- | Combines a list of spans containing some monoidal data into a list of
-- offsets with with the data that applies from each Offset forwards.
combineSpans :: forall a. Monoid a => [Span CrdRange a] -> [(Coord, a)]
-- | Given the text you're operating over, creates an iso from an
-- Offset to a Coord.
asCoord :: YiString -> Iso' Offset Coord
-- | This will restrict a given Coord to a valid one which lies
-- within the given text.
clampCoord :: YiString -> Coord -> Coord
-- | This will restrict a given Range to a valid one which lies
-- within the given text.
clampRange :: YiString -> CrdRange -> CrdRange
rStart :: forall a_adXu b_adXv a_ag8D. Lens (Range a_adXu b_adXv) (Range a_ag8D b_adXv) a_adXu a_ag8D
rEnd :: forall a_adXu b_adXv b_ag8C. Lens (Range a_adXu b_adXv) (Range a_adXu b_ag8C) b_adXv b_ag8C
-- | Returns the number of rows and columns that a Range spans as a
-- Coord
sizeOfR :: CrdRange -> Coord
-- | A lens over text after a given Coord
afterC :: Coord -> Lens' YiString YiString
-- | A lens over text before a given Coord
beforeC :: Coord -> Lens' YiString YiString
-- | Moves a Range by a given Coord It may be unintuitive,
-- but for (Coord row col) a given range will be moved down by row and to
-- the right by col.
moveRange :: Coord -> CrdRange -> CrdRange
-- | Moves a range forward by the given amount
moveRangeByN :: Int -> CrdRange -> CrdRange
-- | Moves a Coord forward by the given amount of columns
moveCursorByN :: Int -> Coord -> Coord
-- | An iso which converts to/from YiString -> Text
asText :: Iso' YiString Text
-- | An iso which converts to/from YiString -> String
asString :: Iso' YiString String
-- | An iso which converts to/from YiString -> [YiString]
asLines :: Iso' YiString [YiString]
-- | clamp min max val restricts val to be within min and max
-- (inclusive)
clamp :: Int -> Int -> Int -> Int
module Rasa
-- | The main function to run rasa.
--
--
-- rasa eventProviders extensions
--
--
-- This should be imported by a user-config with and called with an
-- Action containing any extensions which have event listeners.
--
--
-- rasa $ do
-- cursor
-- vim
-- slate
--
rasa :: Action () -> IO ()