{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_HADDOCK show-extensions #-}

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

module Yi.Keymap.Vim.Search (doVimSearch, continueVimSearch) where

import Data.Maybe         (listToMaybe)
import Data.Text          ()
import Yi.Buffer
import Yi.Editor          (EditorM, printMsg, withCurrentBuffer)
import Yi.Search          (SearchOption, getRegexE, searchInit)

doVimSearch :: Maybe String -> [SearchOption] -> Direction -> EditorM ()
doVimSearch :: Maybe String -> [SearchOption] -> Direction -> EditorM ()
doVimSearch Maybe String
Nothing [SearchOption]
_ Direction
dir = do
    Maybe SearchExp
mbRegex <- EditorM (Maybe SearchExp)
getRegexE
    case Maybe SearchExp
mbRegex of
        Just SearchExp
regex -> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ (SearchExp, Direction) -> BufferM ()
continueVimSearch (SearchExp
regex, Direction
dir)
        Maybe SearchExp
Nothing -> Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg Text
"No previous search pattern"
doVimSearch (Just String
needle) [SearchOption]
opts Direction
dir =
    String
-> Direction -> [SearchOption] -> EditorM (SearchExp, Direction)
searchInit String
needle Direction
dir [SearchOption]
opts EditorM (SearchExp, Direction)
-> ((SearchExp, Direction) -> EditorM ()) -> EditorM ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> ((SearchExp, Direction) -> BufferM ())
-> (SearchExp, Direction)
-> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SearchExp, Direction) -> BufferM ()
continueVimSearch

continueVimSearch :: (SearchExp, Direction) -> BufferM ()
continueVimSearch :: (SearchExp, Direction) -> BufferM ()
continueVimSearch (SearchExp
searchExp, Direction
dir) = do
    Maybe Region
mp <- BufferM (Maybe Region) -> BufferM (Maybe Region)
forall a. BufferM a -> BufferM a
savingPointB (BufferM (Maybe Region) -> BufferM (Maybe Region))
-> BufferM (Maybe Region) -> BufferM (Maybe 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
searchExp
        TextUnit -> Direction -> BufferM ()
moveB TextUnit
Document (Direction -> Direction
reverseDir Direction
dir) -- wrap around
        [Region]
ls <- Direction -> SearchExp -> BufferM [Region]
regexB Direction
dir SearchExp
searchExp
        Maybe Region -> BufferM (Maybe Region)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Region -> BufferM (Maybe Region))
-> Maybe Region -> BufferM (Maybe Region)
forall a b. (a -> b) -> a -> b
$ [Region] -> Maybe Region
forall a. [a] -> Maybe a
listToMaybe ([Region] -> Maybe Region) -> [Region] -> Maybe Region
forall a b. (a -> b) -> a -> b
$ [Region]
rs [Region] -> [Region] -> [Region]
forall a. [a] -> [a] -> [a]
++ [Region]
ls
    -- regionFirst doesn't work right here, because something inside
    -- Buffer.Implementation.regexRegionBI breaks Region invariant and
    -- may return Region (Forward, A, B) where A > B
    -- TODO: investigate
    BufferM () -> (Region -> BufferM ()) -> Maybe 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 ()) -> (Region -> Point) -> Region -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Region -> Point
regionFirst') Maybe Region
mp

regionFirst' :: Region -> Point
regionFirst' :: Region -> Point
regionFirst' Region
r = Int -> Point
Point (Int -> Point) -> Int -> Point
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
a Int
b
    where a :: Int
a = Point -> Int
fromPoint (Point -> Int) -> Point -> Int
forall a b. (a -> b) -> a -> b
$ Region -> Point
regionStart Region
r
          b :: Int
b = Point -> Int
fromPoint (Point -> Int) -> Point -> Int
forall a b. (a -> b) -> a -> b
$ Region -> Point
regionEnd Region
r