{-# 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 (m :: * -> *) a. Monad m => a -> m a
return Region
region
     RegionStyle
Block     -> Region -> BufferM Region
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
  Point
start <- BufferM Point
pointB
  Point -> BufferM ()
moveTo (Point -> BufferM ()) -> Point -> BufferM ()
forall a b. (a -> b) -> a -> b
$ Region -> Point
regionEnd Region
region
  TextUnit -> (Direction, BoundarySide) -> Direction -> BufferM ()
genMaybeMoveB TextUnit
unit (Direction
Forward, BoundarySide
bs2) Direction
Forward
  Point
stop <- BufferM Point
pointB
  Region -> BufferM Region
forall (m :: * -> *) a. Monad m => a -> m a
return (Region -> BufferM Region) -> Region -> BufferM Region
forall a b. (a -> b) -> a -> b
$ Direction -> Point -> Point -> Region
mkRegion' (Region -> Direction
regionDirection Region
region) Point
start Point
stop