{-# 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 (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 ([Char] -> VimState -> MatchResult (EditorM RepeatToken)
f ([Char] -> VimState -> MatchResult (EditorM RepeatToken))
-> (EventString -> [Char])
-> EventString
-> VimState
-> MatchResult (EditorM RepeatToken)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Char]
T.unpack (Text -> [Char]) -> (EventString -> Text) -> EventString -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EventString -> Text
_unEv)
  where
    f :: [Char] -> VimState -> MatchResult (EditorM RepeatToken)
f [Char]
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
        VimState
currentState <- EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
        let count :: Int
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 :: BufferM ()
replacer = case [Char]
evs of
                        (c:[]) -> Char -> BufferM ()
replaceCharB Char
c
                        [Char]
"<lt>" -> Char -> BufferM ()
replaceCharB Char
'<'
                        [Char]
"<C-e>" -> BufferM ()
replaceCharWithBelowB
                        [Char]
"<C-y>" -> BufferM ()
replaceCharWithAboveB
                        [Char]
_ -> () -> BufferM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
            -- Is there more easy way to get distance to eol?
            Point
here <- BufferM Point
pointB
            BufferM ()
moveToEol
            Point
eol <- BufferM Point
pointB
            Point -> BufferM ()
moveTo Point
here

            let effectiveCount :: Int
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)

            Bool -> BufferM () -> BufferM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
effectiveCount Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (BufferM () -> BufferM ()) -> BufferM () -> BufferM ()
forall a b. (a -> b) -> a -> b
$ do
                Int -> BufferM () -> BufferM ()
forall (m :: * -> *) a. Applicative m => Int -> m a -> m ()
replicateM_ Int
effectiveCount (BufferM () -> BufferM ()) -> BufferM () -> BufferM ()
forall a b. (a -> b) -> a -> b
$ BufferM ()
replacer BufferM () -> BufferM () -> BufferM ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> BufferM ()
rightB
                BufferM ()
leftB

        EditorM ()
resetCountE
        VimMode -> EditorM ()
switchModeE VimMode
Normal
        RepeatToken -> EditorM RepeatToken
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Finish
    f [Char]
_ VimState
_ = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
NoMatch