    {-# OPTIONS_HADDOCK show-extensions #-}

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

    module Yi.Keymap.Vim.ReplaceSingleCharMap
        ( defReplaceSingleMap
        ) where

    import           Control.Monad            (replicateM_, when)
    import           Data.Maybe               (fromMaybe)
    import qualified Data.Text                as T (unpack)
    import           Yi.Buffer
    import           Yi.Editor                (getEditorDyn, withCurrentBuffer)
    import           Yi.Keymap.Keys           (Key (KEsc), spec)
    import           Yi.Keymap.Vim.Common
    import           Yi.Keymap.Vim.StateUtils (resetCount, resetCountE, switchMode, switchModeE)
    import           Yi.Keymap.Vim.Utils      (mkBindingE)
    import           Yi.Utils                 (SemiNum ((~-)))

    defReplaceSingleMap :: [VimBinding]
    defReplaceSingleMap :: [VimBinding]
    defReplaceSingleMap = [VimBinding
    escBinding, VimBinding
    actualReplaceBinding]

    escBinding :: VimBinding
    escBinding :: VimBinding
    escBinding = VimMode
    -> RepeatToken
    -> (Event, EditorM (), VimState -> VimState)
    -> VimBinding
    mkBindingE VimMode
    ReplaceSingleChar RepeatToken
    Drop (Key -> Event
    spec Key
    KEsc, () -> EditorM ()
    forall a. a -> EditorM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (), VimState -> VimState
    resetCount (VimState -> VimState)
    -> (VimState -> VimState) -> VimState -> VimState
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . VimMode -> VimState -> VimState
    switchMode VimMode
    Normal)

    actualReplaceBinding :: VimBinding
    actualReplaceBinding :: VimBinding
    actualReplaceBinding = (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
    s | VimMode
    ReplaceSingleChar VimMode -> VimMode -> Bool
    forall a. Eq a => a -> a -> Bool
    == VimState -> VimMode
    vsMode VimState
    s = 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
            currentState <- EditorM VimState
    forall (m :: * -> *) a.
    (MonadEditor m, YiVariable a, Default a, Functor m) =>
    m a
    getEditorDyn
            let count = Int -> Maybe Int -> Int
    forall a. a -> Maybe a -> a
    fromMaybe Int
    1 (Maybe Int -> Int) -> Maybe Int -> Int
    forall a b. (a -> b) -> a -> b
    $ VimState -> Maybe Int
    vsCount VimState
    currentState
            let replacer = case String
    evs of
                            (Char
    c:[]) -> Char -> BufferM ()
    replaceCharB Char
    c
                            String
    "<lt>" -> Char -> BufferM ()
    replaceCharB Char
    '<'
                            String
    "<C-e>" -> BufferM ()
    replaceCharWithBelowB
                            String
    "<C-y>" -> BufferM ()
    replaceCharWithAboveB
                            String
    _ -> () -> BufferM ()
    forall a. a -> BufferM a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
            withCurrentBuffer $ do
                -- Is there more easy way to get distance to eol?
                here <- pointB
                moveToEol
                eol <- pointB
                moveTo here

                let effectiveCount = Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    min Int
    count (Size -> Int
    fromSize (Size -> Int) -> Size -> Int
    forall a b. (a -> b) -> a -> b
    $ Point
    eol Point -> Point -> Size
    forall absolute relative.
    SemiNum absolute relative =>
    absolute -> absolute -> relative
    ~- Point
    here)

                when (effectiveCount > 0) $ do
                    replicateM_ effectiveCount $ replacer >> rightB
                    leftB

            resetCountE
            switchModeE Normal
            return Finish
        f String
    _ VimState
    _ = MatchResult (EditorM RepeatToken)
    forall a. MatchResult a
    NoMatch