{-# LANGUAGE DeriveDataTypeable         #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase                 #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# OPTIONS_HADDOCK show-extensions #-}

-- |
-- Module      :  Yi.Search
-- License     :  GPL-2
-- Maintainer  :  yi-devel@googlegroups.com
-- Stability   :  experimental
-- Portability :  portable
--
-- Search/Replace functions

module Yi.Search (
        setRegexE,      -- :: SearchExp -> EditorM ()
        resetRegexE,    -- :: EditorM ()
        getRegexE,      -- :: EditorM (Maybe SearchExp)
        SearchMatch,
        SearchResult(..),
        SearchOption(..),
        doSearch,            -- :: (Maybe String) -> [SearchOption]
                            -- -> Direction -> YiM ()
        searchInit,        -- :: String
                            -- -> [SearchOption]
                            -- -> IO SearchExp
        continueSearch,          -- :: SearchExp
                            -- -> IO SearchResult
        makeSimpleSearch,

        -- * Batch search-replace
        searchReplaceRegionB,
        searchReplaceSelectionB,
        replaceString,
        searchAndRepRegion,
        searchAndRepRegion0,
        searchAndRepUnit, -- :: String -> String -> Bool -> TextUnit -> EditorM Bool

        -- * Incremental Search
        isearchInitE,
        isearchIsEmpty,
        isearchAddE,
        isearchPrevE,
        isearchNextE,
        isearchWordE,
        isearchHistory,
        isearchDelE,
        isearchCancelE,
        isearchFinishE,
        isearchCancelWithE,
        isearchFinishWithE,

        -- * Replace
        qrNext,
        qrReplaceAll,
        qrReplaceOne,
        qrFinish
                 ) where

import           Lens.Micro.Platform          ((.=))
import           Control.Monad       (void, when)
import           Data.Binary         (Binary, get, put)
import           Data.Char           (isAlpha, isUpper)
import           Data.Default        (Default, def)
import           Data.Maybe          (listToMaybe)
import           Data.Monoid         ((<>))
import qualified Data.Text           as T (Text, any, break, empty, length, null, takeWhile, unpack)
import qualified Data.Text.Encoding  as E (decodeUtf8, encodeUtf8)
import           Data.Typeable       (Typeable)
import           Yi.Buffer
import           Yi.Editor
import           Yi.History          (historyFinishGen, historyMoveGen, historyStartGen)
import           Yi.Regex            (SearchOption(..), makeSearchOptsM, emptyRegex, SearchExp(..))
import qualified Yi.Rope             as R (YiString, null, toString, toText)
import           Yi.Search.Internal  (getRegexE, resetRegexE, setRegexE)
import           Yi.String           (showT)
import           Yi.Types            (YiVariable)
import           Yi.Utils            (fst3)
import           Yi.Window           (Window)

-- ---------------------------------------------------------------------
--
-- | Global searching. Search for regex and move point to that position.
-- @Nothing@ means reuse the last regular expression. @Just s@ means use
-- @s@ as the new regular expression. Direction of search can be
-- specified as either @Backward@ or @Forward@ (forwards in the buffer).
-- Arguments to modify the compiled regular expression can be supplied
-- as well.
--

type SearchMatch = Region
data SearchResult = PatternFound
                  | PatternNotFound
                  | SearchWrapped
  deriving SearchResult -> SearchResult -> Bool
(SearchResult -> SearchResult -> Bool)
-> (SearchResult -> SearchResult -> Bool) -> Eq SearchResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SearchResult -> SearchResult -> Bool
$c/= :: SearchResult -> SearchResult -> Bool
== :: SearchResult -> SearchResult -> Bool
$c== :: SearchResult -> SearchResult -> Bool
Eq

doSearch :: Maybe String        -- ^ @Nothing@ means used previous
                                -- pattern, if any. Complain otherwise.
                                -- Use getRegexE to check for previous patterns
        -> [SearchOption]            -- ^ Flags to modify the compiled regex
        -> Direction            -- ^ @Backward@ or @Forward@
        -> EditorM SearchResult

doSearch :: Maybe String -> [SearchOption] -> Direction -> EditorM SearchResult
doSearch (Just String
re) [SearchOption]
fs Direction
d = String
-> Direction -> [SearchOption] -> EditorM (SearchExp, Direction)
searchInit String
re Direction
d [SearchOption]
fs EditorM (SearchExp, Direction)
-> ((SearchExp, Direction) -> EditorM SearchResult)
-> EditorM SearchResult
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= BufferM SearchResult -> EditorM SearchResult
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM SearchResult -> EditorM SearchResult)
-> ((SearchExp, Direction) -> BufferM SearchResult)
-> (SearchExp, Direction)
-> EditorM SearchResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SearchExp, Direction) -> BufferM SearchResult
continueSearch
doSearch Maybe String
Nothing   [SearchOption]
_  Direction
d = do
  Maybe SearchExp
mre <- EditorM (Maybe SearchExp)
getRegexE
  case Maybe SearchExp
mre of
    Maybe SearchExp
Nothing -> String -> EditorM SearchResult
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"No previous search pattern" -- NB
    Just SearchExp
r  -> BufferM SearchResult -> EditorM SearchResult
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer ((SearchExp, Direction) -> BufferM SearchResult
continueSearch (SearchExp
r,Direction
d))

-- | Set up a search.
searchInit :: String -> Direction -> [SearchOption] -> EditorM (SearchExp, Direction)
searchInit :: String
-> Direction -> [SearchOption] -> EditorM (SearchExp, Direction)
searchInit String
re Direction
d [SearchOption]
fs = do
    let Right SearchExp
c_re = [SearchOption] -> String -> Either String SearchExp
makeSearchOptsM [SearchOption]
fs String
re
    SearchExp -> EditorM ()
setRegexE SearchExp
c_re
    (Direction -> Identity Direction) -> Editor -> Identity Editor
Lens' Editor Direction
searchDirectionA ((Direction -> Identity Direction) -> Editor -> Identity Editor)
-> Direction -> EditorM ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Direction
d
    (SearchExp, Direction) -> EditorM (SearchExp, Direction)
forall (m :: * -> *) a. Monad m => a -> m a
return (SearchExp
c_re,Direction
d)

-- | Do a search, placing cursor at first char of pattern, if found.
-- Keymaps may implement their own regex language. How do we provide for this?
-- Also, what's happening with ^ not matching sol?
continueSearch :: (SearchExp, Direction) -> BufferM SearchResult
continueSearch :: (SearchExp, Direction) -> BufferM SearchResult
continueSearch (SearchExp
c_re, Direction
dir) = do
  Maybe (Either Region Region)
mp <- BufferM (Maybe (Either Region Region))
-> BufferM (Maybe (Either Region Region))
forall a. BufferM a -> BufferM a
savingPointB (BufferM (Maybe (Either Region Region))
 -> BufferM (Maybe (Either Region Region)))
-> BufferM (Maybe (Either Region Region))
-> BufferM (Maybe (Either Region Region))
forall a b. (a -> b) -> a -> b
$ do
    TextUnit -> Direction -> BufferM ()
moveB TextUnit
Character Direction
dir  -- start immed. after cursor
    [Region]
rs <- Direction -> SearchExp -> BufferM [Region]
regexB Direction
dir SearchExp
c_re
    TextUnit -> Direction -> BufferM ()
moveB TextUnit
Document (Direction -> Direction
reverseDir Direction
dir) -- wrap around
    [Region]
ls <- Direction -> SearchExp -> BufferM [Region]
regexB Direction
dir SearchExp
c_re
    Maybe (Either Region Region)
-> BufferM (Maybe (Either Region Region))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (Either Region Region)
 -> BufferM (Maybe (Either Region Region)))
-> Maybe (Either Region Region)
-> BufferM (Maybe (Either Region Region))
forall a b. (a -> b) -> a -> b
$ [Either Region Region] -> Maybe (Either Region Region)
forall a. [a] -> Maybe a
listToMaybe ([Either Region Region] -> Maybe (Either Region Region))
-> [Either Region Region] -> Maybe (Either Region Region)
forall a b. (a -> b) -> a -> b
$ (Region -> Either Region Region)
-> [Region] -> [Either Region Region]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Region -> Either Region Region
forall a b. b -> Either a b
Right [Region]
rs [Either Region Region]
-> [Either Region Region] -> [Either Region Region]
forall a. [a] -> [a] -> [a]
++ (Region -> Either Region Region)
-> [Region] -> [Either Region Region]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Region -> Either Region Region
forall a b. a -> Either a b
Left [Region]
ls
  BufferM ()
-> (Either Region Region -> BufferM ())
-> Maybe (Either Region Region)
-> BufferM ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> BufferM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) (Point -> BufferM ()
moveTo (Point -> BufferM ())
-> (Either Region Region -> Point)
-> Either Region Region
-> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Region -> Point
regionStart (Region -> Point)
-> (Either Region Region -> Region)
-> Either Region Region
-> Point
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Region -> Region)
-> (Region -> Region) -> Either Region Region -> Region
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Region -> Region
forall a. a -> a
id Region -> Region
forall a. a -> a
id) Maybe (Either Region Region)
mp
  SearchResult -> BufferM SearchResult
forall (m :: * -> *) a. Monad m => a -> m a
return (SearchResult -> BufferM SearchResult)
-> SearchResult -> BufferM SearchResult
forall a b. (a -> b) -> a -> b
$ Maybe (Either Region Region) -> SearchResult
forall a b. Maybe (Either a b) -> SearchResult
f Maybe (Either Region Region)
mp
    where
        f :: Maybe (Either a b) -> SearchResult
f (Just (Right b
_)) = SearchResult
PatternFound
        f (Just (Left  a
_)) = SearchResult
SearchWrapped
        f Maybe (Either a b)
Nothing          = SearchResult
PatternNotFound

------------------------------------------------------------------------
-- Batch search and replace
--

-- | Search and Replace all within the current region.
-- Note the region is the final argument since we might perform
-- the same search and replace over multiple regions however we are
-- unlikely to perform several search and replaces over the same region
-- since the first such may change the bounds of the region.
searchReplaceRegionB :: R.YiString -- ^ The string to search for
                     -> R.YiString -- ^ The string to replace it with
                     -> Region -- ^ The region to perform this over
                     -> BufferM Int
searchReplaceRegionB :: YiString -> YiString -> Region -> BufferM Int
searchReplaceRegionB YiString
from YiString
to =
  SearchExp -> YiString -> Bool -> Region -> BufferM Int
searchAndRepRegion0 (YiString -> SearchExp
makeSimpleSearch YiString
from) YiString
to Bool
True


-- | Peform a search and replace on the selection
searchReplaceSelectionB :: R.YiString  -- ^ text to search for
                        -> R.YiString  -- ^ text to replace it with
                        -> BufferM Int
searchReplaceSelectionB :: YiString -> YiString -> BufferM Int
searchReplaceSelectionB YiString
from YiString
to =
  BufferM Region
getSelectRegionB BufferM Region -> (Region -> BufferM Int) -> BufferM Int
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= YiString -> YiString -> Region -> BufferM Int
searchReplaceRegionB YiString
from YiString
to

-- | Replace a string by another everywhere in the document
replaceString :: R.YiString -> R.YiString -> BufferM Int
replaceString :: YiString -> YiString -> BufferM Int
replaceString YiString
a YiString
b = TextUnit -> BufferM Region
regionOfB TextUnit
Document BufferM Region -> (Region -> BufferM Int) -> BufferM Int
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= YiString -> YiString -> Region -> BufferM Int
searchReplaceRegionB YiString
a YiString
b

------------------------------------------------------------------------
-- | Search and replace in the given region.
--
-- If the input boolean is True, then the replace is done globally,
-- otherwise only the first match is replaced. Returns the number of
-- replacements done.
searchAndRepRegion0 :: SearchExp -> R.YiString -> Bool -> Region -> BufferM Int
searchAndRepRegion0 :: SearchExp -> YiString -> Bool -> Region -> BufferM Int
searchAndRepRegion0 SearchExp
c_re YiString
str Bool
globally Region
region = do
    [Region]
mp <- (if Bool
globally then [Region] -> [Region]
forall a. a -> a
id else Int -> [Region] -> [Region]
forall a. Int -> [a] -> [a]
take Int
1) ([Region] -> [Region]) -> BufferM [Region] -> BufferM [Region]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SearchExp -> Region -> BufferM [Region]
regexRegionB SearchExp
c_re Region
region  -- find the regex
    -- mp' is a maybe not reversed version of mp, the goal
    -- is to avoid replaceRegionB to mess up the next regions.
    -- So we start from the end.
    let mp' :: [Region]
mp' = Direction -> [Region] -> [Region]
forall a. Direction -> [a] -> [a]
mayReverse (Direction -> Direction
reverseDir (Direction -> Direction) -> Direction -> Direction
forall a b. (a -> b) -> a -> b
$ Region -> Direction
regionDirection Region
region) [Region]
mp
    (Region -> BufferM ()) -> [Region] -> BufferM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Region -> YiString -> BufferM ()
`replaceRegionB` YiString
str) [Region]
mp'
    Int -> BufferM Int
forall (m :: * -> *) a. Monad m => a -> m a
return ([Region] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Region]
mp)

searchAndRepRegion :: R.YiString -> R.YiString -> Bool -> Region -> EditorM Bool
searchAndRepRegion :: YiString -> YiString -> Bool -> Region -> EditorM Bool
searchAndRepRegion YiString
s YiString
str Bool
globally Region
region = case YiString -> Bool
R.null YiString
s of
  Bool
False -> Bool -> EditorM Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
  Bool
True -> do
    let c_re :: SearchExp
c_re = YiString -> SearchExp
makeSimpleSearch YiString
s
    SearchExp -> EditorM ()
setRegexE SearchExp
c_re     -- store away for later use
    (Direction -> Identity Direction) -> Editor -> Identity Editor
Lens' Editor Direction
searchDirectionA ((Direction -> Identity Direction) -> Editor -> Identity Editor)
-> Direction -> EditorM ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Direction
Forward
    BufferM Bool -> EditorM Bool
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM Bool -> EditorM Bool) -> BufferM Bool -> EditorM Bool
forall a b. (a -> b) -> a -> b
$ (Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0) (Int -> Bool) -> BufferM Int -> BufferM Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> SearchExp -> YiString -> Bool -> Region -> BufferM Int
searchAndRepRegion0 SearchExp
c_re YiString
str Bool
globally Region
region

------------------------------------------------------------------------
-- | Search and replace in the region defined by the given unit.
-- The rest is as in 'searchAndRepRegion'.
searchAndRepUnit :: R.YiString -> R.YiString -> Bool -> TextUnit -> EditorM Bool
searchAndRepUnit :: YiString -> YiString -> Bool -> TextUnit -> EditorM Bool
searchAndRepUnit YiString
re YiString
str Bool
g TextUnit
unit =
  BufferM Region -> EditorM Region
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (TextUnit -> BufferM Region
regionOfB TextUnit
unit) EditorM Region -> (Region -> EditorM Bool) -> EditorM Bool
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= YiString -> YiString -> Bool -> Region -> EditorM Bool
searchAndRepRegion YiString
re YiString
str Bool
g

--------------------------
-- Incremental search


newtype Isearch = Isearch [(T.Text, Region, Direction)]
  deriving (Typeable, Int -> Isearch -> ShowS
[Isearch] -> ShowS
Isearch -> String
(Int -> Isearch -> ShowS)
-> (Isearch -> String) -> ([Isearch] -> ShowS) -> Show Isearch
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Isearch] -> ShowS
$cshowList :: [Isearch] -> ShowS
show :: Isearch -> String
$cshow :: Isearch -> String
showsPrec :: Int -> Isearch -> ShowS
$cshowsPrec :: Int -> Isearch -> ShowS
Show)

instance Binary Isearch where
  put :: Isearch -> Put
put (Isearch [(Text, Region, Direction)]
ts) = [(ByteString, Region, Direction)] -> Put
forall t. Binary t => t -> Put
put ((Text -> ByteString)
-> [(Text, Region, Direction)] -> [(ByteString, Region, Direction)]
forall a d b c. (a -> d) -> [(a, b, c)] -> [(d, b, c)]
map3 Text -> ByteString
E.encodeUtf8 [(Text, Region, Direction)]
ts)
  get :: Get Isearch
get = [(Text, Region, Direction)] -> Isearch
Isearch ([(Text, Region, Direction)] -> Isearch)
-> ([(ByteString, Region, Direction)]
    -> [(Text, Region, Direction)])
-> [(ByteString, Region, Direction)]
-> Isearch
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Text)
-> [(ByteString, Region, Direction)] -> [(Text, Region, Direction)]
forall a d b c. (a -> d) -> [(a, b, c)] -> [(d, b, c)]
map3 ByteString -> Text
E.decodeUtf8 ([(ByteString, Region, Direction)] -> Isearch)
-> Get [(ByteString, Region, Direction)] -> Get Isearch
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get [(ByteString, Region, Direction)]
forall t. Binary t => Get t
get

map3 :: (a -> d) -> [(a, b, c)] -> [(d, b, c)]
map3 :: (a -> d) -> [(a, b, c)] -> [(d, b, c)]
map3 a -> d
_ [] = []
map3 a -> d
f ((a
a, b
b, c
c):[(a, b, c)]
xs) = (a -> d
f a
a, b
b, c
c) (d, b, c) -> [(d, b, c)] -> [(d, b, c)]
forall a. a -> [a] -> [a]
: (a -> d) -> [(a, b, c)] -> [(d, b, c)]
forall a d b c. (a -> d) -> [(a, b, c)] -> [(d, b, c)]
map3 a -> d
f [(a, b, c)]
xs


-- This contains: (string currently searched, position where we
-- searched it, direction, overlay for highlighting searched text)

-- Note that this info cannot be embedded in the Keymap state: the state
-- modification can depend on the state of the editor.

instance Default Isearch where
    def :: Isearch
def = [(Text, Region, Direction)] -> Isearch
Isearch []

instance YiVariable Isearch

isearchInitE :: Direction -> EditorM ()
isearchInitE :: Direction -> EditorM ()
isearchInitE Direction
dir = do
  Text -> EditorM ()
historyStartGen Text
iSearch
  Point
p <- BufferM Point -> EditorM Point
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM Point
pointB
  Isearch -> EditorM ()
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Functor m) =>
a -> m ()
putEditorDyn ([(Text, Region, Direction)] -> Isearch
Isearch [(Text
T.empty ,Point -> Point -> Region
mkRegion Point
p Point
p, Direction
dir)])
  Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg Text
"I-search: "

isearchIsEmpty :: EditorM Bool
isearchIsEmpty :: EditorM Bool
isearchIsEmpty = do
  Isearch [(Text, Region, Direction)]
s <- EditorM Isearch
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
  Bool -> EditorM Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> EditorM Bool)
-> ((Text, Region, Direction) -> Bool)
-> (Text, Region, Direction)
-> EditorM Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Bool
not (Bool -> Bool)
-> ((Text, Region, Direction) -> Bool)
-> (Text, Region, Direction)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
T.null (Text -> Bool)
-> ((Text, Region, Direction) -> Text)
-> (Text, Region, Direction)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text, Region, Direction) -> Text
forall a b c. (a, b, c) -> a
fst3 ((Text, Region, Direction) -> EditorM Bool)
-> (Text, Region, Direction) -> EditorM Bool
forall a b. (a -> b) -> a -> b
$ [(Text, Region, Direction)] -> (Text, Region, Direction)
forall a. [a] -> a
head [(Text, Region, Direction)]
s

isearchAddE :: T.Text -> EditorM ()
isearchAddE :: Text -> EditorM ()
isearchAddE Text
inc = (Text -> Text) -> EditorM ()
isearchFunE (Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
inc)

-- | Create a SearchExp that matches exactly its argument
makeSimpleSearch :: R.YiString -> SearchExp
makeSimpleSearch :: YiString -> SearchExp
makeSimpleSearch YiString
s = SearchExp
se
    where Right SearchExp
se = [SearchOption] -> String -> Either String SearchExp
makeSearchOptsM [SearchOption
QuoteRegex] (YiString -> String
R.toString YiString
s)

makeISearch :: T.Text -> SearchExp
makeISearch :: Text -> SearchExp
makeISearch Text
s = case [SearchOption] -> String -> Either String SearchExp
makeSearchOptsM [SearchOption]
opts (Text -> String
T.unpack Text
s) of
                  Left String
_ -> String -> Regex -> Regex -> [SearchOption] -> SearchExp
SearchExp (Text -> String
T.unpack Text
s) Regex
emptyRegex Regex
emptyRegex []
                  Right SearchExp
search -> SearchExp
search
   where opts :: [SearchOption]
opts = SearchOption
QuoteRegex SearchOption -> [SearchOption] -> [SearchOption]
forall a. a -> [a] -> [a]
: if (Char -> Bool) -> Text -> Bool
T.any Char -> Bool
isUpper Text
s then [] else [SearchOption
IgnoreCase]

isearchFunE :: (T.Text -> T.Text) -> EditorM ()
isearchFunE :: (Text -> Text) -> EditorM ()
isearchFunE Text -> Text
fun = do
  Isearch [(Text, Region, Direction)]
s <- EditorM Isearch
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
  case [(Text, Region, Direction)]
s of
    [(Text, Region, Direction)
_] -> EditorM ()
resetRegexE
    [(Text, Region, Direction)]
_ -> () -> EditorM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  let (Text
previous,Region
p0,Direction
direction) = [(Text, Region, Direction)] -> (Text, Region, Direction)
forall a. [a] -> a
head [(Text, Region, Direction)]
s
      current :: Text
current = Text -> Text
fun Text
previous
      srch :: SearchExp
srch = Text -> SearchExp
makeISearch Text
current
  Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg (Text -> EditorM ()) -> Text -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text
"I-search: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
current
  SearchExp -> EditorM ()
setRegexE SearchExp
srch
  Point
prevPoint <- BufferM Point -> EditorM Point
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM Point
pointB
  [Region]
matches <- BufferM [Region] -> EditorM [Region]
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM [Region] -> EditorM [Region])
-> BufferM [Region] -> EditorM [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
p0
      Bool -> BufferM () -> BufferM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Direction
direction Direction -> Direction -> Bool
forall a. Eq a => a -> a -> Bool
== Direction
Backward) (BufferM () -> BufferM ()) -> BufferM () -> BufferM ()
forall a b. (a -> b) -> a -> b
$
         Int -> BufferM ()
moveN (Int -> BufferM ()) -> Int -> BufferM ()
forall a b. (a -> b) -> a -> b
$ Text -> Int
T.length Text
current
      Direction -> SearchExp -> BufferM [Region]
regexB Direction
direction SearchExp
srch

  let onSuccess :: Region -> m ()
onSuccess Region
p = do BufferM () -> m ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> m ()) -> BufferM () -> m ()
forall a b. (a -> b) -> a -> b
$ Point -> BufferM ()
moveTo (Region -> Point
regionEnd Region
p)
                       Isearch -> m ()
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Functor m) =>
a -> m ()
putEditorDyn (Isearch -> m ()) -> Isearch -> m ()
forall a b. (a -> b) -> a -> b
$ [(Text, Region, Direction)] -> Isearch
Isearch ((Text
current, Region
p, Direction
direction) (Text, Region, Direction)
-> [(Text, Region, Direction)] -> [(Text, Region, Direction)]
forall a. a -> [a] -> [a]
: [(Text, Region, Direction)]
s)

  case [Region]
matches of
    (Region
p:[Region]
_) -> Region -> EditorM ()
forall (m :: * -> *). MonadEditor m => Region -> m ()
onSuccess Region
p
    [] -> do [Region]
matchesAfterWrap <- BufferM [Region] -> EditorM [Region]
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM [Region] -> EditorM [Region])
-> BufferM [Region] -> EditorM [Region]
forall a b. (a -> b) -> a -> b
$ do
               case Direction
direction of
                 Direction
Forward -> Point -> BufferM ()
moveTo Point
0
                 Direction
Backward -> do
                   Point
bufferLength <- BufferM Point
sizeB
                   Point -> BufferM ()
moveTo Point
bufferLength
               Direction -> SearchExp -> BufferM [Region]
regexB Direction
direction SearchExp
srch

             case [Region]
matchesAfterWrap of
               (Region
p:[Region]
_) -> Region -> EditorM ()
forall (m :: * -> *). MonadEditor m => Region -> m ()
onSuccess Region
p
               [] -> do BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Point -> BufferM ()
moveTo Point
prevPoint -- go back to where we were
                        Isearch -> EditorM ()
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Functor m) =>
a -> m ()
putEditorDyn (Isearch -> EditorM ()) -> Isearch -> EditorM ()
forall a b. (a -> b) -> a -> b
$ [(Text, Region, Direction)] -> Isearch
Isearch ((Text
current, Region
p0, Direction
direction) (Text, Region, Direction)
-> [(Text, Region, Direction)] -> [(Text, Region, Direction)]
forall a. a -> [a] -> [a]
: [(Text, Region, Direction)]
s)
                        Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg (Text -> EditorM ()) -> Text -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text
"Failing I-search: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
current

isearchDelE :: EditorM ()
isearchDelE :: EditorM ()
isearchDelE = do
  Isearch [(Text, Region, Direction)]
s <- EditorM Isearch
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
  case [(Text, Region, Direction)]
s of
    ((Text, Region, Direction)
_:(Text
text,Region
p,Direction
dir):[(Text, Region, Direction)]
rest) -> do
      BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$
        Point -> BufferM ()
moveTo (Point -> BufferM ()) -> Point -> BufferM ()
forall a b. (a -> b) -> a -> b
$ Region -> Point
regionEnd Region
p
      Isearch -> EditorM ()
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Functor m) =>
a -> m ()
putEditorDyn (Isearch -> EditorM ()) -> Isearch -> EditorM ()
forall a b. (a -> b) -> a -> b
$ [(Text, Region, Direction)] -> Isearch
Isearch ((Text
text,Region
p,Direction
dir)(Text, Region, Direction)
-> [(Text, Region, Direction)] -> [(Text, Region, Direction)]
forall a. a -> [a] -> [a]
:[(Text, Region, Direction)]
rest)
      SearchExp -> EditorM ()
setRegexE (SearchExp -> EditorM ()) -> SearchExp -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text -> SearchExp
makeISearch Text
text
      Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg (Text -> EditorM ()) -> Text -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text
"I-search: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
text
    [(Text, Region, Direction)]
_ -> () -> EditorM ()
forall (m :: * -> *) a. Monad m => a -> m a
return () -- if the searched string is empty, don't try to remove chars from it.

isearchHistory :: Int -> EditorM ()
isearchHistory :: Int -> EditorM ()
isearchHistory Int
delta = do
  Isearch ((Text
current,Region
_p0,Direction
_dir):[(Text, Region, Direction)]
_) <- EditorM Isearch
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
  Text
h <- Text -> Int -> EditorM Text -> EditorM Text
historyMoveGen Text
iSearch Int
delta (Text -> EditorM Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
current)
  (Text -> Text) -> EditorM ()
isearchFunE (Text -> Text -> Text
forall a b. a -> b -> a
const Text
h)

isearchPrevE :: EditorM ()
isearchPrevE :: EditorM ()
isearchPrevE = Direction -> EditorM ()
isearchNext0 Direction
Backward

isearchNextE :: EditorM ()
isearchNextE :: EditorM ()
isearchNextE = Direction -> EditorM ()
isearchNext0 Direction
Forward

isearchNext0 :: Direction -> EditorM ()
isearchNext0 :: Direction -> EditorM ()
isearchNext0 Direction
newDir = do
  Isearch ((Text
current,Region
_p0,Direction
_dir):[(Text, Region, Direction)]
_rest) <- EditorM Isearch
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
  if Text -> Bool
T.null Text
current
    then Int -> EditorM ()
isearchHistory Int
1
    else Direction -> EditorM ()
isearchNext Direction
newDir


isearchNext :: Direction -> EditorM ()
isearchNext :: Direction -> EditorM ()
isearchNext Direction
direction = do
  Isearch ((Text
current, Region
p0, Direction
_dir) : [(Text, Region, Direction)]
rest) <- EditorM Isearch
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
  BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Point -> BufferM ()
moveTo (Region -> Point
regionStart Region
p0 Point -> Point -> Point
forall a. Num a => a -> a -> a
+ Point
startOfs)
  [Region]
mp <- BufferM [Region] -> EditorM [Region]
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM [Region] -> EditorM [Region])
-> BufferM [Region] -> EditorM [Region]
forall a b. (a -> b) -> a -> b
$
    Direction -> SearchExp -> BufferM [Region]
regexB Direction
direction (Text -> SearchExp
makeISearch Text
current)
  case [Region]
mp of
    [] -> do
      Point
endPoint <- BufferM Point -> EditorM Point
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM Point -> EditorM Point) -> BufferM Point -> EditorM Point
forall a b. (a -> b) -> a -> b
$ do
              Point -> BufferM ()
moveTo (Region -> Point
regionEnd Region
p0) -- revert to offset we were before.
              BufferM Point
sizeB
      Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg Text
"isearch: end of document reached"
      let wrappedOfs :: Region
wrappedOfs = case Direction
direction of
                         Direction
Forward -> Point -> Point -> Region
mkRegion Point
0 Point
0
                         Direction
Backward -> Point -> Point -> Region
mkRegion Point
endPoint Point
endPoint
      Isearch -> EditorM ()
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Functor m) =>
a -> m ()
putEditorDyn (Isearch -> EditorM ()) -> Isearch -> EditorM ()
forall a b. (a -> b) -> a -> b
$ [(Text, Region, Direction)] -> Isearch
Isearch ((Text
current,Region
wrappedOfs,Direction
direction)(Text, Region, Direction)
-> [(Text, Region, Direction)] -> [(Text, Region, Direction)]
forall a. a -> [a] -> [a]
:[(Text, Region, Direction)]
rest) -- prepare to wrap around.
    (Region
p:[Region]
_) -> do
      BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$
        Point -> BufferM ()
moveTo (Region -> Point
regionEnd Region
p)
      Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg (Text -> EditorM ()) -> Text -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text
"I-search: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
current
      Isearch -> EditorM ()
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Functor m) =>
a -> m ()
putEditorDyn (Isearch -> EditorM ()) -> Isearch -> EditorM ()
forall a b. (a -> b) -> a -> b
$ [(Text, Region, Direction)] -> Isearch
Isearch ((Text
current,Region
p,Direction
direction)(Text, Region, Direction)
-> [(Text, Region, Direction)] -> [(Text, Region, Direction)]
forall a. a -> [a] -> [a]
:[(Text, Region, Direction)]
rest)
 where startOfs :: Point
startOfs = case Direction
direction of
                      Direction
Forward  ->  Point
1
                      Direction
Backward -> -Point
1

isearchWordE :: EditorM ()
isearchWordE :: EditorM ()
isearchWordE = do
   -- add maximum 32 chars at a time.
  Text
text <- YiString -> Text
R.toText (YiString -> Text) -> EditorM YiString -> EditorM Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BufferM YiString -> EditorM YiString
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM Point
pointB BufferM Point -> (Point -> BufferM YiString) -> BufferM YiString
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> Point -> BufferM YiString
nelemsB Int
32)

  let (Text
prefix, Text
rest) = (Char -> Bool) -> Text -> (Text, Text)
T.break Char -> Bool
isAlpha Text
text
      word :: Text
word = (Char -> Bool) -> Text -> Text
T.takeWhile Char -> Bool
isAlpha Text
rest
  Text -> EditorM ()
isearchAddE (Text -> EditorM ()) -> Text -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text
prefix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
word

-- | Succesfully finish a search. Also see 'isearchFinishWithE'.
isearchFinishE :: EditorM ()
isearchFinishE :: EditorM ()
isearchFinishE = Bool -> EditorM ()
isearchEnd Bool
True

-- | Cancel a search. Also see 'isearchCancelWithE'.
isearchCancelE :: EditorM ()
isearchCancelE :: EditorM ()
isearchCancelE = Bool -> EditorM ()
isearchEnd Bool
False

-- | Wrapper over 'isearchEndWith' that passes through the action and
-- accepts the search as successful (i.e. when the user wants to stay
-- at the result).
isearchFinishWithE :: EditorM a -> EditorM ()
isearchFinishWithE :: EditorM a -> EditorM ()
isearchFinishWithE EditorM a
act = EditorM a -> Bool -> EditorM ()
forall a. EditorM a -> Bool -> EditorM ()
isearchEndWith EditorM a
act Bool
True

-- | Wrapper over 'isearchEndWith' that passes through the action and
-- marks the search as unsuccessful (i.e. when the user wants to
-- jump back to where the search started).
isearchCancelWithE :: EditorM a -> EditorM ()
isearchCancelWithE :: EditorM a -> EditorM ()
isearchCancelWithE EditorM a
act = EditorM a -> Bool -> EditorM ()
forall a. EditorM a -> Bool -> EditorM ()
isearchEndWith EditorM a
act Bool
False

iSearch :: T.Text
iSearch :: Text
iSearch = Text
"isearch"

-- | Editor action describing how to end finish incremental search.
-- The @act@ parameter allows us to specify an extra action to run
-- before finishing up the search. For Vim, we don't want to do
-- anything so we use 'isearchEnd' which just does nothing. For emacs,
-- we want to cancel highlighting and stay where we are.
isearchEndWith :: EditorM a -> Bool -> EditorM ()
isearchEndWith :: EditorM a -> Bool -> EditorM ()
isearchEndWith EditorM a
act Bool
accept = EditorM Isearch
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn EditorM Isearch -> (Isearch -> EditorM ()) -> EditorM ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  Isearch [] -> () -> EditorM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  Isearch s :: [(Text, Region, Direction)]
s@((Text
lastSearched, Region
_, Direction
dir):[(Text, Region, Direction)]
_) -> do
    let (Text
_,Region
p0,Direction
_) = [(Text, Region, Direction)] -> (Text, Region, Direction)
forall a. [a] -> a
last [(Text, Region, Direction)]
s
    Text -> EditorM Text -> EditorM ()
historyFinishGen Text
iSearch (Text -> EditorM Text
forall (m :: * -> *) a. Monad m => a -> m a
return Text
lastSearched)
    (Direction -> Identity Direction) -> Editor -> Identity Editor
Lens' Editor Direction
searchDirectionA ((Direction -> Identity Direction) -> Editor -> Identity Editor)
-> Direction -> EditorM ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Direction
dir
    if Bool
accept
       then do EditorM a -> EditorM ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void EditorM a
act
               Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg Text
"Quit"
       else do EditorM ()
resetRegexE
               BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Point -> BufferM ()
moveTo (Point -> BufferM ()) -> Point -> BufferM ()
forall a b. (a -> b) -> a -> b
$ Region -> Point
regionStart Region
p0

-- | Specialised 'isearchEndWith' to do nothing as the action.
isearchEnd :: Bool -> EditorM ()
isearchEnd :: Bool -> EditorM ()
isearchEnd = EditorM () -> Bool -> EditorM ()
forall a. EditorM a -> Bool -> EditorM ()
isearchEndWith (() -> EditorM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())

-----------------
-- Query-Replace

-- | Find the next match and select it.
-- Point is end, mark is beginning.
qrNext :: Window -> BufferRef -> SearchExp -> EditorM ()
qrNext :: Window -> BufferRef -> SearchExp -> EditorM ()
qrNext Window
win BufferRef
b SearchExp
what = do
  [Region]
mp <- Window -> BufferRef -> BufferM [Region] -> EditorM [Region]
forall (m :: * -> *) a.
MonadEditor m =>
Window -> BufferRef -> BufferM a -> m a
withGivenBufferAndWindow Window
win BufferRef
b (BufferM [Region] -> EditorM [Region])
-> BufferM [Region] -> EditorM [Region]
forall a b. (a -> b) -> a -> b
$ Direction -> SearchExp -> BufferM [Region]
regexB Direction
Forward SearchExp
what
  case [Region]
mp of
    [] -> do
      Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg Text
"String to search not found"
      EditorM ()
qrFinish
    (Region
r:[Region]
_) -> Window -> BufferRef -> BufferM () -> EditorM ()
forall (m :: * -> *) a.
MonadEditor m =>
Window -> BufferRef -> BufferM a -> m a
withGivenBufferAndWindow Window
win BufferRef
b (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Region -> BufferM ()
setSelectRegionB Region
r

-- | Replace all the remaining occurrences.
qrReplaceAll :: Window -> BufferRef -> SearchExp -> R.YiString -> EditorM ()
qrReplaceAll :: Window -> BufferRef -> SearchExp -> YiString -> EditorM ()
qrReplaceAll Window
win BufferRef
b SearchExp
what YiString
replacement = do
  Int
n <- Window -> BufferRef -> BufferM Int -> EditorM Int
forall (m :: * -> *) a.
MonadEditor m =>
Window -> BufferRef -> BufferM a -> m a
withGivenBufferAndWindow Window
win BufferRef
b (BufferM Int -> EditorM Int) -> BufferM Int -> EditorM Int
forall a b. (a -> b) -> a -> b
$ do
    BufferM ()
exchangePointAndMarkB -- so we replace the current occurence too
    SearchExp -> YiString -> Bool -> Region -> BufferM Int
searchAndRepRegion0 SearchExp
what YiString
replacement Bool
True (Region -> BufferM Int) -> BufferM Region -> BufferM Int
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< TextUnit -> Direction -> BufferM Region
regionOfPartB TextUnit
Document Direction
Forward
  Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg (Text -> EditorM ()) -> Text -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text
"Replaced " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
showT Int
n Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" occurrences"
  EditorM ()
qrFinish

-- | Exit from query/replace.
qrFinish :: EditorM ()
qrFinish :: EditorM ()
qrFinish = do
  (Maybe SearchExp -> Identity (Maybe SearchExp))
-> Editor -> Identity Editor
Lens' Editor (Maybe SearchExp)
currentRegexA ((Maybe SearchExp -> Identity (Maybe SearchExp))
 -> Editor -> Identity Editor)
-> Maybe SearchExp -> EditorM ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Maybe SearchExp
forall a. Maybe a
Nothing
  EditorM ()
closeBufferAndWindowE  -- the minibuffer.

-- | We replace the currently selected match and then move to the next
-- match.
qrReplaceOne :: Window -> BufferRef -> SearchExp -> R.YiString -> EditorM ()
qrReplaceOne :: Window -> BufferRef -> SearchExp -> YiString -> EditorM ()
qrReplaceOne Window
win BufferRef
b SearchExp
reg YiString
replacement = do
  Window -> BufferRef -> YiString -> EditorM ()
qrReplaceCurrent Window
win BufferRef
b YiString
replacement
  Window -> BufferRef -> SearchExp -> EditorM ()
qrNext Window
win BufferRef
b SearchExp
reg

-- | This may actually be a bit more general it replaces the current
-- selection with the given replacement string in the given window and
-- buffer.
qrReplaceCurrent :: Window -> BufferRef -> R.YiString -> EditorM ()
qrReplaceCurrent :: Window -> BufferRef -> YiString -> EditorM ()
qrReplaceCurrent Window
win BufferRef
b YiString
replacement =
  Window -> BufferRef -> BufferM () -> EditorM ()
forall (m :: * -> *) a.
MonadEditor m =>
Window -> BufferRef -> BufferM a -> m a
withGivenBufferAndWindow Window
win BufferRef
b (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$
   (Region -> YiString -> BufferM ())
-> YiString -> Region -> BufferM ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Region -> YiString -> BufferM ()
replaceRegionB YiString
replacement (Region -> BufferM ()) -> BufferM Region -> BufferM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< BufferM Region
getRawestSelectRegionB