{-# LANGUAGE TemplateHaskell, OverloadedStrings, Rank2Types #-} module Rasa.Ext.Cursors.Internal.Base ( rangeDo , rangeDo_ , overRanges , getRanges , setRanges , overEachRange , addRange , setStyleProvider ) where import Rasa.Ext import Control.Monad.State import Control.Lens import Data.Typeable import Data.List import Data.Default import qualified Yi.Rope as Y -- | Stores the cursor ranges in each buffer. data Cursors = Cursors [CrdRange] deriving (Typeable, Show) instance Default Cursors where def = Cursors [Range (Coord 0 0) (Coord 0 1)] -- | Adjusts input ranges to contain at least one character. ensureSize :: CrdRange -> CrdRange ensureSize r@(Range start end) | start == end = if start^.coordCol == 0 then r & rEnd %~ moveCursorByN 1 else r & rStart %~ moveCursorByN (-1) | otherwise = r -- | Sorts Ranges, removes duplicates, ensures they contain at least one character -- and restricts them to fit within the given text. cleanRanges :: Y.YiString -> [CrdRange] -> [CrdRange] cleanRanges txt = fmap (ensureSize . clampRange txt) . reverse . nub . sort -- | Get the list of ranges getRanges :: BufAction [CrdRange] getRanges = do Cursors ranges <- getBufExt return ranges setRanges :: [CrdRange] -> BufAction () setRanges new = do txt <- getText setBufExt . Cursors $ cleanRanges txt new overRanges :: ([CrdRange] -> [CrdRange]) -> BufAction () overRanges f = getRanges >>= setRanges . f -- | Sequences actions over each range as a 'BufAction' rangeDo :: (CrdRange -> BufAction a) -> BufAction [a] rangeDo f = getRanges >>= mapM f -- | 'rangeDo' with void return. rangeDo_ :: (CrdRange -> BufAction a) -> BufAction () rangeDo_ = void . rangeDo -- | Sequences actions over each range and replaces each range with its result. overEachRange :: (CrdRange -> BufAction CrdRange) -> BufAction () overEachRange f = rangeDo f >>= setRanges -- | Adds a new range to the list of ranges. addRange :: CrdRange -> BufAction () addRange r = overRanges (++[r]) -- | Adds cursor specific styles setStyleProvider :: BufAction () setStyleProvider = void . addStyleProvider $ rangeDo setStyle where setStyle :: CrdRange -> BufAction (Span CrdRange Style) setStyle r = return $ Span r (flair ReverseVideo)