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

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

    module Yi.Keymap.Vim.SearchMotionMap (defSearchMotionMap) where

    import           Control.Monad            (replicateM_)
    import           Data.Maybe               (fromMaybe)
    import qualified Data.Text                as T (pack, unpack)
    import           Yi.Buffer                (Direction (Backward, Forward), elemsB)
    import           Yi.Editor                (getEditorDyn, withCurrentBuffer)
    import           Yi.History               (historyFinish, historyPrefixSet)
    import           Yi.Keymap.Vim.Common
    import           Yi.Keymap.Vim.Search     (continueVimSearch)
    import           Yi.Keymap.Vim.StateUtils (getCountE, switchModeE)
    import           Yi.Keymap.Vim.Utils      (matchFromBool)
    import qualified Yi.Rope                  as R (toText)
    import           Yi.Search

    defSearchMotionMap :: [VimBinding]
    defSearchMotionMap :: [VimBinding]
    defSearchMotionMap = [VimBinding
    enterBinding, VimBinding
    editBinding, VimBinding
    exitBinding]

    enterBinding :: VimBinding
    enterBinding :: VimBinding
    enterBinding = (EventString -> VimState -> MatchResult (EditorM RepeatToken))
    -> VimBinding
    VimBindingE EventString -> VimState -> MatchResult (EditorM RepeatToken)
    forall {a}.
    (Eq a, IsString a) =>
    a -> VimState -> MatchResult (EditorM RepeatToken)
    f
        where f :: a -> VimState -> MatchResult (EditorM RepeatToken)
    f a
    "<CR>" (VimState { vsMode :: VimState -> VimMode
    vsMode = Search {}} ) = EditorM RepeatToken -> MatchResult (EditorM RepeatToken)
    forall a. a -> MatchResult a
    WholeMatch (EditorM RepeatToken -> MatchResult (EditorM RepeatToken))
    -> EditorM RepeatToken -> MatchResult (EditorM RepeatToken)
    forall a b. (a -> b) -> a -> b
    $ do
                  Search prevMode dir <- (VimState -> VimMode) -> EditorM VimState -> EditorM VimMode
    forall a b. (a -> b) -> EditorM a -> EditorM b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap VimState -> VimMode
    vsMode EditorM VimState
    forall (m :: * -> *) a.
    (MonadEditor m, YiVariable a, Default a, Functor m) =>
    m a
    getEditorDyn
                  -- TODO: parse cmd into regex and flags
                  isearchFinishE
                  historyFinish
                  switchModeE prevMode

                  count <- getCountE
                  getRegexE >>= \case
                    Maybe SearchExp
    Nothing -> () -> EditorM ()
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
                    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
    $
                      if Int
    count Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Int
    1 Bool -> Bool -> Bool
    && Direction
    dir Direction -> Direction -> Bool
    forall a. Eq a => a -> a -> Bool
    == Direction
    Forward
                      then do
                        -- Workaround for isearchFinishE leaving cursor after match
                        (SearchExp, Direction) -> BufferM ()
    continueVimSearch (SearchExp
    regex, Direction
    Backward)
                        (SearchExp, Direction) -> BufferM ()
    continueVimSearch (SearchExp
    regex, Direction
    Forward)
                      else Int -> BufferM () -> BufferM ()
    forall (m :: * -> *) a. Applicative m => Int -> m a -> m ()
    replicateM_ (Int
    count Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1) (BufferM () -> BufferM ()) -> BufferM () -> BufferM ()
    forall a b. (a -> b) -> a -> b
    $ (SearchExp, Direction) -> BufferM ()
    continueVimSearch (SearchExp
    regex, Direction
    dir)
                  case prevMode of
                      Visual RegionStyle
    _ -> RepeatToken -> EditorM RepeatToken
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return RepeatToken
    Continue
                      VimMode
    _ -> RepeatToken -> EditorM RepeatToken
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return RepeatToken
    Finish
              f a
    _ VimState
    _ = MatchResult (EditorM RepeatToken)
    forall a. MatchResult a
    NoMatch

    editBinding :: VimBinding
    editBinding :: VimBinding
    editBinding = (EventString -> VimState -> MatchResult (EditorM RepeatToken))
    -> VimBinding
    VimBindingE (String -> VimState -> MatchResult (EditorM RepeatToken)
    f (String -> VimState -> MatchResult (EditorM RepeatToken))
    -> (EventString -> String)
    -> EventString
    -> VimState
    -> MatchResult (EditorM RepeatToken)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> String
    T.unpack (Text -> String) -> (EventString -> Text) -> EventString -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . EventString -> Text
    _unEv)
      where
        f :: String -> VimState -> MatchResult (EditorM RepeatToken)
    f String
    evs (VimState { vsMode :: VimState -> VimMode
    vsMode = Search {}} )
          = String -> EditorM RepeatToken
    action String
    evs EditorM RepeatToken
    -> MatchResult () -> MatchResult (EditorM RepeatToken)
    forall a b. a -> MatchResult b -> MatchResult a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$
            Bool -> MatchResult ()
    matchFromBool (String
    evs String -> [String] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` ((Text, EditorM ()) -> String) -> [(Text, EditorM ())] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Text -> String
    T.unpack (Text -> String)
    -> ((Text, EditorM ()) -> Text) -> (Text, EditorM ()) -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text, EditorM ()) -> Text
    forall a b. (a, b) -> a
    fst) [(Text, EditorM ())]
    binds
                           Bool -> Bool -> Bool
    || String -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null (Int -> String -> String
    forall a. Int -> [a] -> [a]
    drop Int
    1 String
    evs))
        f String
    _ VimState
    _ = MatchResult (EditorM RepeatToken)
    forall a. MatchResult a
    NoMatch
        action :: String -> EditorM RepeatToken
    action String
    evs = do
          let evs' :: Text
    evs' = String -> Text
    T.pack String
    evs
          EditorM () -> Maybe (EditorM ()) -> EditorM ()
    forall a. a -> Maybe a -> a
    fromMaybe (Text -> EditorM ()
    isearchAddE Text
    evs') (Text -> [(Text, EditorM ())] -> Maybe (EditorM ())
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup Text
    evs' [(Text, EditorM ())]
    binds)
          BufferM YiString -> EditorM YiString
    forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
    withCurrentBuffer BufferM YiString
    elemsB EditorM YiString -> (YiString -> EditorM ()) -> EditorM ()
    forall a b. EditorM a -> (a -> EditorM b) -> EditorM b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Text -> EditorM ()
    historyPrefixSet (Text -> EditorM ())
    -> (YiString -> Text) -> YiString -> EditorM ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . YiString -> Text
    R.toText
          RepeatToken -> EditorM RepeatToken
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return RepeatToken
    Continue

        binds :: [(Text, EditorM ())]
    binds = [ (Text
    "<BS>", EditorM ()
    isearchDelE)
                , (Text
    "<C-h>", EditorM ()
    isearchDelE)
                , (Text
    "<C-p>", Int -> EditorM ()
    isearchHistory Int
    1)
                , (Text
    "<Up>", Int -> EditorM ()
    isearchHistory Int
    1)
                , (Text
    "<C-n>", Int -> EditorM ()
    isearchHistory (-Int
    1))
                , (Text
    "<Down>", Int -> EditorM ()
    isearchHistory (-Int
    1))
                , (Text
    "<lt>", Text -> EditorM ()
    isearchAddE Text
    "<")
                ]

    exitBinding :: VimBinding
    exitBinding :: VimBinding
    exitBinding = (EventString -> VimState -> MatchResult (EditorM RepeatToken))
    -> VimBinding
    VimBindingE EventString -> VimState -> MatchResult (EditorM RepeatToken)
    forall {p}. p -> VimState -> MatchResult (EditorM RepeatToken)
    f
        where f :: p -> VimState -> MatchResult (EditorM RepeatToken)
    f p
    _ (VimState { vsMode :: VimState -> VimMode
    vsMode = Search {}} ) = EditorM RepeatToken -> MatchResult (EditorM RepeatToken)
    forall a. a -> MatchResult a
    WholeMatch (EditorM RepeatToken -> MatchResult (EditorM RepeatToken))
    -> EditorM RepeatToken -> MatchResult (EditorM RepeatToken)
    forall a b. (a -> b) -> a -> b
    $ do
                  Search prevMode _dir <- (VimState -> VimMode) -> EditorM VimState -> EditorM VimMode
    forall a b. (a -> b) -> EditorM a -> EditorM b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap VimState -> VimMode
    vsMode EditorM VimState
    forall (m :: * -> *) a.
    (MonadEditor m, YiVariable a, Default a, Functor m) =>
    m a
    getEditorDyn
                  isearchCancelE
                  switchModeE prevMode
                  return Drop
              f p
    _ VimState
    _ = MatchResult (EditorM RepeatToken)
    forall a. MatchResult a
    NoMatch