    {-# LANGUAGE CPP #-}

    -- | A normalized API to many buffer operations.

    -- The idea is that most operations should be parametric in both
    --  * the textual units they work on
    --  * the direction towards which they operate (if applicable)

    module Yi.Buffer.Normal ( TextUnit(Character, Line, VLine, Document, GenUnit)
                            , isAnySep
                            , isWordChar
                            , leftBoundaryUnit
                            , outsideUnit
                            , unitDelimited
                            , unitEmacsParagraph
                            , unitParagraph
                            , unitSentence
                            , unitSep
                            , unitSepThisLine
                            , unitViWORD
                            , unitViWORDAnyBnd
                            , unitViWORDOnLine
                            , unitViWord
                            , unitViWordAnyBnd
                            , unitViWordOnLine
                            , unitWord
                             -- TextUnit is exported abstract intentionally:
                             -- we'd like to move more units to the GenUnit format.
                            , atBoundaryB
                            , deleteB
                            , doIfCharB
                            , doUntilB_
                            , genMaybeMoveB
                            , genMoveB
                            , maybeMoveB
                            , moveB
                            , numberOfB
                            , readPrevUnitB
                            , readUnitB
                            , regionOfB
                            , regionOfNonEmptyB
                            , regionOfPartB
                            , regionOfPartNonEmptyAtB
                            , regionOfPartNonEmptyB
                            , transformB
                            , transposeB
                            , untilB
                            , untilB_
                            , whileB
                            , BoundarySide(..)
                            , checkPeekB
                            , genAtBoundaryB
                            , genEnclosingUnit
                            , genUnitBoundary
                            , RegionStyle(..)
                            , convertRegionToStyleB
                            , extendRegionToBoundaries
                            , getRegionStyle
                            , mkRegionOfStyleB
                            , putRegionStyle
                            , unitWiseRegion
                            ) where

    import           Data.List          (sort)
    import           Yi.Buffer.Basic    (Direction (Backward, Forward), Point)
    import           Yi.Buffer.Misc     (BufferM, getBufferDyn, moveTo, pointB, putBufferDyn, savingPointB)
    import           Yi.Buffer.Region   (Region (..), inclusiveRegionB, mkRegion, mkRegion')
    import           Yi.Buffer.TextUnit
    import           Yi.Types           (RegionStyle (..))

    getRegionStyle :: BufferM RegionStyle
    getRegionStyle :: BufferM RegionStyle
    getRegionStyle = BufferM RegionStyle
    forall (m :: * -> *) a.
    (Default a, YiVariable a, MonadState FBuffer m, Functor m) =>
    m a
    getBufferDyn
    putRegionStyle :: RegionStyle -> BufferM ()
    putRegionStyle :: RegionStyle -> BufferM ()
    putRegionStyle = RegionStyle -> BufferM ()
    forall a (m :: * -> *).
    (YiVariable a, MonadState FBuffer m, Functor m) =>
    a -> m ()
    putBufferDyn

    convertRegionToStyleB :: Region -> RegionStyle -> BufferM Region
    convertRegionToStyleB :: Region -> RegionStyle -> BufferM Region
    convertRegionToStyleB Region
    r = Point -> Point -> RegionStyle -> BufferM Region
    mkRegionOfStyleB (Region -> Point
    regionStart Region
    r) (Region -> Point
    regionEnd Region
    r)

    mkRegionOfStyleB :: Point -> Point -> RegionStyle -> BufferM Region
    mkRegionOfStyleB :: Point -> Point -> RegionStyle -> BufferM Region
    mkRegionOfStyleB Point
    start' Point
    stop' RegionStyle
    regionStyle =
       let [Point
    start, Point
    stop] = [Point] -> [Point]
    forall a. Ord a => [a] -> [a]
    sort [Point
    start', Point
    stop']
           region :: Region
    region = Point -> Point -> Region
    mkRegion Point
    start Point
    stop in
       case RegionStyle
    regionStyle of
         RegionStyle
    LineWise  -> Region -> BufferM Region
    inclusiveRegionB (Region -> BufferM Region) -> BufferM Region -> BufferM Region
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< TextUnit -> Region -> BufferM Region
    unitWiseRegion TextUnit
    Line Region
    region
         RegionStyle
    Inclusive -> Region -> BufferM Region
    inclusiveRegionB Region
    region
         RegionStyle
    Exclusive -> Region -> BufferM Region
    forall a. a -> BufferM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Region
    region
         RegionStyle
    Block     -> Region -> BufferM Region
    forall a. a -> BufferM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Region
    region

    unitWiseRegion :: TextUnit -> Region -> BufferM Region
    unitWiseRegion :: TextUnit -> Region -> BufferM Region
    unitWiseRegion TextUnit
    unit = TextUnit
    -> BoundarySide -> BoundarySide -> Region -> BufferM Region
    extendRegionToBoundaries TextUnit
    unit BoundarySide
    InsideBound BoundarySide
    OutsideBound

    -- | Extend the given region to boundaries of the text unit.
    -- For instance one can extend the selection to complete lines, or
    -- paragraphs.
    extendRegionToBoundaries :: TextUnit -> BoundarySide -> BoundarySide -> Region -> BufferM Region
    extendRegionToBoundaries :: TextUnit
    -> BoundarySide -> BoundarySide -> Region -> BufferM Region
    extendRegionToBoundaries TextUnit
    unit BoundarySide
    bs1 BoundarySide
    bs2 Region
    region = BufferM Region -> BufferM Region
    forall a. BufferM a -> BufferM a
    savingPointB (BufferM Region -> BufferM Region)
    -> BufferM Region -> BufferM Region
    forall a b. (a -> b) -> a -> b
    $ do
      Point -> BufferM ()
    moveTo (Point -> BufferM ()) -> Point -> BufferM ()
    forall a b. (a -> b) -> a -> b
    $ Region -> Point
    regionStart Region
    region
      TextUnit -> (Direction, BoundarySide) -> Direction -> BufferM ()
    genMaybeMoveB TextUnit
    unit (Direction
    Backward, BoundarySide
    bs1) Direction
    Backward
      start <- BufferM Point
    pointB
      moveTo $ regionEnd region
      genMaybeMoveB unit (Forward, bs2) Forward
      stop <- pointB
      return $ mkRegion' (regionDirection region) start stop