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

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

module Yi.Keymap.Vim.NormalMap (defNormalMap) where

import           Prelude                    hiding (lookup)

import           Lens.Micro.Platform        (use, (.=))
import           Control.Monad              (replicateM_, unless, void, when)
import           Data.Char                  (ord)
import           Data.HashMap.Strict        (lookup, insert)
import           Data.List                  (group)
import           Data.Maybe                 (fromMaybe)
import           Data.Monoid                ((<>))
import qualified Data.Text                  as T (drop, empty, pack, replicate, unpack)
import           System.Directory           (doesFileExist)
import           System.FriendlyPath        (expandTilda)
import           Yi.Buffer                  hiding (Insert)
import           Yi.Core                    (closeWindow, quitEditor)
import           Yi.Editor
import           Yi.Event                   (Event (Event), Key (KASCII, KEnter, KEsc, KTab), Modifier (MCtrl))
import           Yi.File                    (fwriteE, openNewFile)
import           Yi.History                 (historyPrefixSet, historyStart)
import           Yi.Keymap                  (YiM)
import           Yi.Keymap.Keys             (char, ctrlCh, spec)
import           Yi.Keymap.Vim.Common
import           Yi.Keymap.Vim.Eval         (scheduleActionStringForEval)
import           Yi.Keymap.Vim.Motion       (CountedMove (CountedMove), regionOfMoveB, stringToMove)
import           Yi.Keymap.Vim.Operator     (VimOperator (..), opChange, opDelete, opYank)
import           Yi.Keymap.Vim.Search       (doVimSearch)
import           Yi.Keymap.Vim.StateUtils
import           Yi.Keymap.Vim.StyledRegion (StyledRegion (StyledRegion), transformCharactersInLineN)
import           Yi.Keymap.Vim.Substitution (repeatSubstitutionE, repeatSubstitutionFlaglessE)
import           Yi.Keymap.Vim.Tag          (gotoTag, popTag)
import           Yi.Keymap.Vim.Utils
import           Yi.MiniBuffer              (spawnMinibufferE)
import           Yi.Misc                    (printFileInfoE)
import           Yi.Monad                   (maybeM, whenM)
import           Yi.Regex                   (makeSearchOptsM, seInput)
import qualified Yi.Rope                    as R (fromText, null, toString, toText)
import           Yi.Search                  (getRegexE, isearchInitE, makeSimpleSearch, setRegexE)
import           Yi.String                  (showT)
import           Yi.Tag                     (Tag (..))
import           Yi.Utils                   (io)

data EOLStickiness = Sticky | NonSticky deriving EOLStickiness -> EOLStickiness -> Bool
(EOLStickiness -> EOLStickiness -> Bool)
-> (EOLStickiness -> EOLStickiness -> Bool) -> Eq EOLStickiness
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EOLStickiness -> EOLStickiness -> Bool
== :: EOLStickiness -> EOLStickiness -> Bool
$c/= :: EOLStickiness -> EOLStickiness -> Bool
/= :: EOLStickiness -> EOLStickiness -> Bool
Eq

mkDigitBinding :: Char -> VimBinding
mkDigitBinding :: Char -> VimBinding
mkDigitBinding Char
c = VimMode
-> RepeatToken
-> (Event, EditorM (), VimState -> VimState)
-> VimBinding
mkBindingE VimMode
Normal RepeatToken
Continue (Char -> Event
char Char
c, () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimState -> VimState
mutate)
  where
    mutate :: VimState -> VimState
mutate vs :: VimState
vs@(VimState {vsCount :: VimState -> Maybe Int
vsCount = Maybe Int
Nothing}) = VimState
vs { vsCount = Just d }
    mutate vs :: VimState
vs@(VimState {vsCount :: VimState -> Maybe Int
vsCount = Just Int
count}) =
      VimState
vs { vsCount = Just $ count * 10 + d }
    d :: Int
d = Char -> Int
ord Char
c Int -> Int -> Int
forall a. Num a => a -> a -> a
- Char -> Int
ord Char
'0'

defNormalMap :: [VimOperator] -> [VimBinding]
defNormalMap :: [VimOperator] -> [VimBinding]
defNormalMap [VimOperator]
operators =
    [VimBinding
recordMacroBinding, VimBinding
finishRecordingMacroBinding, VimBinding
playMacroBinding] [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimBinding
zeroBinding, VimBinding
repeatBinding, VimBinding
motionBinding, VimBinding
searchBinding] [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimBinding
chooseRegisterBinding, VimBinding
setMarkBinding] [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    (Char -> VimBinding) -> String -> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Char -> VimBinding
mkDigitBinding [Char
'1' .. Char
'9'] [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimOperator] -> [VimBinding]
operatorBindings [VimOperator]
operators [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimBinding]
finishingBingings [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimBinding]
continuingBindings [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimBinding]
nonrepeatableBindings [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimBinding]
jumpBindings [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimBinding]
fileEditBindings [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimBinding
tabTraversalBinding] [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<>
    [VimBinding
tagJumpBinding, VimBinding
tagPopBinding]

tagJumpBinding :: VimBinding
tagJumpBinding :: VimBinding
tagJumpBinding = VimMode -> (Event, YiM (), VimState -> VimState) -> VimBinding
mkBindingY VimMode
Normal (Key -> [Modifier] -> Event
Event (Char -> Key
KASCII Char
']') [Modifier
MCtrl], YiM ()
f, VimState -> VimState
forall a. a -> a
id)
   where f :: YiM ()
f = BufferM YiString -> YiM YiString
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM YiString
readCurrentWordB YiM YiString -> (YiString -> YiM ()) -> YiM ()
forall a b. YiM a -> (a -> YiM b) -> YiM b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Tag -> YiM ()
g (Tag -> YiM ()) -> (YiString -> Tag) -> YiString -> YiM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Tag
Tag (Text -> Tag) -> (YiString -> Text) -> YiString -> Tag
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YiString -> Text
R.toText
         g :: Tag -> YiM ()
g Tag
tag = Tag -> Int -> Maybe (String, Int, Int) -> YiM ()
gotoTag Tag
tag Int
0 Maybe (String, Int, Int)
forall a. Maybe a
Nothing

tagPopBinding :: VimBinding
tagPopBinding :: VimBinding
tagPopBinding = VimMode -> (Event, YiM (), VimState -> VimState) -> VimBinding
mkBindingY VimMode
Normal (Key -> [Modifier] -> Event
Event (Char -> Key
KASCII Char
't') [Modifier
MCtrl], YiM ()
f, VimState -> VimState
forall a. a -> a
id)
   where f :: YiM ()
f = YiM ()
popTag

motionBinding :: VimBinding
motionBinding :: VimBinding
motionBinding = RepeatToken -> (VimMode -> Bool) -> VimBinding
mkMotionBinding RepeatToken
Drop ((VimMode -> Bool) -> VimBinding)
-> (VimMode -> Bool) -> VimBinding
forall a b. (a -> b) -> a -> b
$
    \VimMode
m -> case VimMode
m of
        VimMode
Normal -> Bool
True
        VimMode
_ -> Bool
False

chooseRegisterBinding :: VimBinding
chooseRegisterBinding :: VimBinding
chooseRegisterBinding = (VimState -> Bool) -> VimBinding
mkChooseRegisterBinding ((VimMode -> VimMode -> Bool
forall a. Eq a => a -> a -> Bool
== VimMode
Normal) (VimMode -> Bool) -> (VimState -> VimMode) -> VimState -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimState -> VimMode
vsMode)

zeroBinding :: VimBinding
zeroBinding :: VimBinding
zeroBinding = (EventString -> VimState -> MatchResult (EditorM RepeatToken))
-> VimBinding
VimBindingE EventString -> VimState -> MatchResult (EditorM RepeatToken)
forall {a}.
(IsString a, Eq a) =>
a -> VimState -> MatchResult (EditorM RepeatToken)
f
    where f :: a -> VimState -> MatchResult (EditorM RepeatToken)
f a
"0" (VimState {vsMode :: VimState -> VimMode
vsMode = VimMode
Normal}) = 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
              case vsCount currentState of
                  Just Int
c -> do
                      Int -> EditorM ()
setCountE (Int
10 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
c)
                      RepeatToken -> EditorM RepeatToken
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Continue
                  Maybe Int
Nothing -> do
                      BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
moveToSol
                      EditorM ()
resetCountE
                      BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ (Bool -> Identity Bool) -> FBuffer -> Identity FBuffer
forall c. HasAttributes c => Lens' c Bool
Lens' FBuffer Bool
stickyEolA ((Bool -> Identity Bool) -> FBuffer -> Identity FBuffer)
-> Bool -> BufferM ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
False
                      RepeatToken -> EditorM RepeatToken
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Drop
          f a
_ VimState
_ = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
NoMatch

repeatBinding :: VimBinding
repeatBinding :: VimBinding
repeatBinding = (EventString -> VimState -> MatchResult (EditorM RepeatToken))
-> VimBinding
VimBindingE (String -> VimState -> MatchResult (EditorM RepeatToken)
forall {a}.
(Eq a, IsString a) =>
a -> 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 :: a -> VimState -> MatchResult (EditorM RepeatToken)
f a
"." (VimState {vsMode :: VimState -> VimMode
vsMode = VimMode
Normal}) = 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
      case vsRepeatableAction currentState of
          Maybe RepeatableAction
Nothing -> () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
          Just (RepeatableAction Int
prevCount (Ev Text
actionString)) -> do
              let count :: Text
count = Int -> Text
forall a. Show a => a -> Text
showT (Int -> Text) -> Int -> Text
forall a b. (a -> b) -> a -> b
$ Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
prevCount (VimState -> Maybe Int
vsCount VimState
currentState)
              EventString -> EditorM ()
scheduleActionStringForEval (EventString -> EditorM ())
-> (Text -> EventString) -> Text -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> EventString
Ev (Text -> EditorM ()) -> Text -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Text
count Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
actionString
              EditorM ()
resetCountE
      return Drop
    f a
_ VimState
_ = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
NoMatch

jumpBindings :: [VimBinding]
jumpBindings :: [VimBinding]
jumpBindings = ((Event, EditorM (), VimState -> VimState) -> VimBinding)
-> [(Event, EditorM (), VimState -> VimState)] -> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (VimMode
-> RepeatToken
-> (Event, EditorM (), VimState -> VimState)
-> VimBinding
mkBindingE VimMode
Normal RepeatToken
Drop)
    [ (Char -> Event
ctrlCh Char
'o', EditorM ()
jumpBackE, VimState -> VimState
forall a. a -> a
id)
    , (Key -> Event
spec Key
KTab, EditorM ()
jumpForwardE, VimState -> VimState
forall a. a -> a
id)
    , (Char -> Event
ctrlCh Char
'^', EditorM ()
controlCaret, VimState -> VimState
resetCount)
    , (Char -> Event
ctrlCh Char
'6', EditorM ()
controlCaret, VimState -> VimState
resetCount)
    ]
  where
    controlCaret :: EditorM ()
controlCaret = Int -> EditorM ()
alternateBufferE (Int -> EditorM ()) -> (Int -> Int) -> Int -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (-Int
1)) (Int -> EditorM ()) -> EditorM Int -> EditorM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< EditorM Int
getCountE

finishingBingings :: [VimBinding]
finishingBingings :: [VimBinding]
finishingBingings = ((EventString, EditorM (), VimState -> VimState) -> VimBinding)
-> [(EventString, EditorM (), VimState -> VimState)]
-> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (VimMode
-> RepeatToken
-> (EventString, EditorM (), VimState -> VimState)
-> VimBinding
mkStringBindingE VimMode
Normal RepeatToken
Finish)
    [ (EventString
"x", Direction -> EOLStickiness -> Int -> EditorM ()
cutCharE Direction
Forward EOLStickiness
NonSticky (Int -> EditorM ()) -> EditorM Int -> EditorM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< EditorM Int
getCountE, VimState -> VimState
resetCount)
    , (EventString
"<Del>", Direction -> EOLStickiness -> Int -> EditorM ()
cutCharE Direction
Forward EOLStickiness
NonSticky (Int -> EditorM ()) -> EditorM Int -> EditorM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< EditorM Int
getCountE, VimState -> VimState
resetCount)
    , (EventString
"X", Direction -> EOLStickiness -> Int -> EditorM ()
cutCharE Direction
Backward EOLStickiness
NonSticky (Int -> EditorM ()) -> EditorM Int -> EditorM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< EditorM Int
getCountE, VimState -> VimState
resetCount)

    , (EventString
"D",
        do region <- 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
$ BufferM () -> BufferM () -> BufferM Region
forall a b. BufferM a -> BufferM b -> BufferM Region
regionWithTwoMovesB (() -> BufferM ()
forall a. a -> BufferM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()) BufferM ()
moveToEol
           void $ operatorApplyToRegionE opDelete 1 $ StyledRegion Exclusive region
        , VimState -> VimState
forall a. a -> a
id)

    -- Pasting
    , (EventString
"p", EditorM ()
pasteAfter, VimState -> VimState
forall a. a -> a
id)
    , (EventString
"P", EditorM ()
pasteBefore, VimState -> VimState
forall a. a -> a
id)

    -- Miscellaneous.
    , (EventString
"~", do
           count <- EditorM Int
getCountE
           withCurrentBuffer $ do
               transformCharactersInLineN count switchCaseChar
               leftOnEol
        , VimState -> VimState
resetCount)
    , (EventString
"J", do
        count <- (Int -> Int) -> EditorM Int -> EditorM Int
forall a b. (a -> b) -> EditorM a -> EditorM b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Int -> Int -> Int) -> Int -> Int -> Int
forall a b c. (a -> b -> c) -> b -> a -> c
flip (-) Int
1 (Int -> Int) -> (Int -> Int) -> Int -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
2) EditorM Int
getCountE
        withCurrentBuffer $ do
            (StyledRegion s r) <- case stringToMove "j" of
                WholeMatch Move
m -> CountedMove -> BufferM StyledRegion
regionOfMoveB (CountedMove -> BufferM StyledRegion)
-> CountedMove -> BufferM StyledRegion
forall a b. (a -> b) -> a -> b
$ Maybe Int -> Move -> CountedMove
CountedMove (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
count) Move
m
                MatchResult Move
_ -> String -> BufferM StyledRegion
forall a. HasCallStack => String -> a
error String
"can't happen"
            void $ lineMoveRel $ count - 1
            moveToEol
            joinLinesB =<< convertRegionToStyleB r s
       , VimState -> VimState
resetCount)
    ]

pasteBefore :: EditorM ()
pasteBefore :: EditorM ()
pasteBefore = do
    -- TODO: use count
    register <- Char -> EditorM (Maybe Register)
getRegisterE (Char -> EditorM (Maybe Register))
-> (VimState -> Char) -> VimState -> EditorM (Maybe Register)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimState -> Char
vsActiveRegister (VimState -> EditorM (Maybe Register))
-> EditorM VimState -> EditorM (Maybe Register)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
    case register of
        Maybe Register
Nothing -> () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        Just (Register RegionStyle
LineWise YiString
rope) -> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Bool -> BufferM () -> BufferM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (YiString -> Bool
R.null YiString
rope) (BufferM () -> BufferM ()) -> BufferM () -> BufferM ()
forall a b. (a -> b) -> a -> b
$
            -- Beware of edge cases ahead
            YiString -> RegionStyle -> BufferM ()
insertRopeWithStyleB (YiString -> YiString
addNewLineIfNecessary YiString
rope) RegionStyle
LineWise
        Just (Register RegionStyle
style YiString
rope) -> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ YiString -> RegionStyle -> BufferM ()
pasteInclusiveB YiString
rope RegionStyle
style

pasteAfter :: EditorM ()
pasteAfter :: EditorM ()
pasteAfter = do
    -- TODO: use count
    register <- Char -> EditorM (Maybe Register)
getRegisterE (Char -> EditorM (Maybe Register))
-> (VimState -> Char) -> VimState -> EditorM (Maybe Register)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimState -> Char
vsActiveRegister (VimState -> EditorM (Maybe Register))
-> EditorM VimState -> EditorM (Maybe Register)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
    case register of
        Maybe Register
Nothing -> () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        Just (Register RegionStyle
LineWise YiString
rope) -> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
            -- Beware of edge cases ahead
            BufferM ()
moveToEol
            eof <- BufferM Bool
atEof
            when eof $ insertB '\n'
            rightB
            insertRopeWithStyleB (addNewLineIfNecessary rope) LineWise
            when eof $ savingPointB $ do
                newSize <- sizeB
                moveTo (newSize - 1)
                curChar <- readB
                when (curChar == '\n') $ deleteN 1
        Just (Register RegionStyle
style YiString
rope) -> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
            BufferM Bool -> BufferM () -> BufferM ()
forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
whenM ((Bool -> Bool) -> BufferM Bool -> BufferM Bool
forall a b. (a -> b) -> BufferM a -> BufferM b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Bool -> Bool
not BufferM Bool
atEol) BufferM ()
rightB
            YiString -> RegionStyle -> BufferM ()
pasteInclusiveB YiString
rope RegionStyle
style

operatorBindings :: [VimOperator] -> [VimBinding]
operatorBindings :: [VimOperator] -> [VimBinding]
operatorBindings = (VimOperator -> VimBinding) -> [VimOperator] -> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap VimOperator -> VimBinding
mkOperatorBinding
  where
    mkT :: OperatorName -> (EventString, m (), VimState -> VimState)
mkT (Op Text
o) = (Text -> EventString
Ev Text
o, () -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> (OperatorName -> VimMode)
-> OperatorName
-> VimState
-> VimState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OperatorName -> VimMode
NormalOperatorPending (OperatorName -> VimState -> VimState)
-> OperatorName -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Text -> OperatorName
Op Text
o)
    mkOperatorBinding :: VimOperator -> VimBinding
mkOperatorBinding (VimOperator {operatorName :: VimOperator -> OperatorName
operatorName = OperatorName
opName}) =
      VimMode
-> RepeatToken
-> (EventString, EditorM (), VimState -> VimState)
-> VimBinding
mkStringBindingE VimMode
Normal RepeatToken
Continue ((EventString, EditorM (), VimState -> VimState) -> VimBinding)
-> (EventString, EditorM (), VimState -> VimState) -> VimBinding
forall a b. (a -> b) -> a -> b
$ OperatorName -> (EventString, EditorM (), VimState -> VimState)
forall {m :: * -> *}.
Monad m =>
OperatorName -> (EventString, m (), VimState -> VimState)
mkT OperatorName
opName

continuingBindings :: [VimBinding]
continuingBindings :: [VimBinding]
continuingBindings = ((EventString, EditorM (), VimState -> VimState) -> VimBinding)
-> [(EventString, EditorM (), VimState -> VimState)]
-> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (VimMode
-> RepeatToken
-> (EventString, EditorM (), VimState -> VimState)
-> VimBinding
mkStringBindingE VimMode
Normal RepeatToken
Continue)
    [ (EventString
"r", () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimMode -> VimState -> VimState
switchMode VimMode
ReplaceSingleChar) -- TODO make it just a binding

    -- Transition to insert mode
    , (EventString
"i", () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'i')
    , (EventString
"<Ins>", () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'i')
    , (EventString
"I", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
firstNonSpaceB, VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'I')
    , (EventString
"a", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Int -> BufferM ()
moveXorEol Int
1, VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'a')
    , (EventString
"A", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
moveToEol, VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'A')
    , (EventString
"o", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
          BufferM ()
moveToEol
          BufferM ()
newlineB
          BufferM ()
indentAsTheMostIndentedNeighborLineB
        , VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'o')
    , (EventString
"O", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
                     BufferM ()
moveToSol
                     BufferM ()
newlineB
                     BufferM ()
leftB
                     BufferM ()
indentAsNextB
        , VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'O')

    -- Transition to visual
    , (EventString
"v", RegionStyle -> EditorM ()
enableVisualE RegionStyle
Inclusive, VimState -> VimState
resetCount (VimState -> VimState)
-> (VimState -> VimState) -> VimState -> VimState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimMode -> VimState -> VimState
switchMode (RegionStyle -> VimMode
Visual RegionStyle
Inclusive))
    , (EventString
"V", RegionStyle -> EditorM ()
enableVisualE RegionStyle
LineWise, VimState -> VimState
resetCount (VimState -> VimState)
-> (VimState -> VimState) -> VimState -> VimState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimMode -> VimState -> VimState
switchMode (RegionStyle -> VimMode
Visual RegionStyle
LineWise))
    , (EventString
"<C-v>", RegionStyle -> EditorM ()
enableVisualE RegionStyle
Block, VimState -> VimState
resetCount (VimState -> VimState)
-> (VimState -> VimState) -> VimState -> VimState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimMode -> VimState -> VimState
switchMode (RegionStyle -> VimMode
Visual RegionStyle
Block))
    ] [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. [a] -> [a] -> [a]
++ ((Event, EditorM (), VimState -> VimState) -> VimBinding)
-> [(Event, EditorM (), VimState -> VimState)] -> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (VimMode
-> RepeatToken
-> (Event, EditorM (), VimState -> VimState)
-> VimBinding
mkBindingE VimMode
Normal RepeatToken
Continue)
    [
    -- Changing
      (Char -> Event
char Char
'C',
        do region <- 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
$ BufferM () -> BufferM () -> BufferM Region
forall a b. BufferM a -> BufferM b -> BufferM Region
regionWithTwoMovesB (() -> BufferM ()
forall a. a -> BufferM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()) BufferM ()
moveToEol
           void $ operatorApplyToRegionE opChange 1 $ StyledRegion Exclusive region
        , VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'C')
    , (Char -> Event
char Char
's', Direction -> EOLStickiness -> Int -> EditorM ()
cutCharE Direction
Forward EOLStickiness
Sticky (Int -> EditorM ()) -> EditorM Int -> EditorM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< EditorM Int
getCountE, VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
's')
    , (Char -> Event
char Char
'S',
        do region <- 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
$ BufferM () -> BufferM () -> BufferM Region
forall a b. BufferM a -> BufferM b -> BufferM Region
regionWithTwoMovesB BufferM ()
firstNonSpaceB BufferM ()
moveToEol
           void $ operatorApplyToRegionE opDelete 1 $ StyledRegion Exclusive region
        , VimMode -> VimState -> VimState
switchMode (VimMode -> VimState -> VimState)
-> VimMode -> VimState -> VimState
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'S')

    -- Replacing
    , (Char -> Event
char Char
'R', () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimMode -> VimState -> VimState
switchMode VimMode
Replace)
    ]

nonrepeatableBindings :: [VimBinding]
nonrepeatableBindings :: [VimBinding]
nonrepeatableBindings = ((Event, EditorM (), VimState -> VimState) -> VimBinding)
-> [(Event, EditorM (), VimState -> VimState)] -> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (VimMode
-> RepeatToken
-> (Event, EditorM (), VimState -> VimState)
-> VimBinding
mkBindingE VimMode
Normal 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)
    , (Char -> Event
ctrlCh Char
'c', () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimState -> VimState
resetCount)

    -- Yanking
    , ( Char -> Event
char Char
'Y'
      , do region <- 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
$ BufferM () -> BufferM () -> BufferM Region
forall a b. BufferM a -> BufferM b -> BufferM Region
regionWithTwoMovesB (() -> BufferM ()
forall a. a -> BufferM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()) BufferM ()
moveToEol
           void $ operatorApplyToRegionE opYank 1 $ StyledRegion Exclusive region
      , VimState -> VimState
forall a. a -> a
id
      )

    -- Search
    , (Char -> Event
char Char
'*', EditorM ()
addVimJumpHereE EditorM () -> EditorM () -> EditorM ()
forall a b. EditorM a -> EditorM b -> EditorM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> Direction -> EditorM ()
searchWordE Bool
True Direction
Forward, VimState -> VimState
resetCount)
    , (Char -> Event
char Char
'#', EditorM ()
addVimJumpHereE EditorM () -> EditorM () -> EditorM ()
forall a b. EditorM a -> EditorM b -> EditorM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> Direction -> EditorM ()
searchWordE Bool
True Direction
Backward, VimState -> VimState
resetCount)
    , (Char -> Event
char Char
'n', EditorM ()
addVimJumpHereE EditorM () -> EditorM () -> EditorM ()
forall a b. EditorM a -> EditorM b -> EditorM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> EditorM () -> EditorM ()
withCount ((Direction -> Direction) -> EditorM ()
continueSearching Direction -> Direction
forall a. a -> a
id), VimState -> VimState
resetCount)
    , (Char -> Event
char Char
'N', EditorM ()
addVimJumpHereE EditorM () -> EditorM () -> EditorM ()
forall a b. EditorM a -> EditorM b -> EditorM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> EditorM () -> EditorM ()
withCount ((Direction -> Direction) -> EditorM ()
continueSearching Direction -> Direction
reverseDir), VimState -> VimState
resetCount)
    , (Char -> Event
char Char
';', (Direction -> Direction) -> EditorM ()
repeatGotoCharE Direction -> Direction
forall a. a -> a
id, VimState -> VimState
forall a. a -> a
id)
    , (Char -> Event
char Char
',', (Direction -> Direction) -> EditorM ()
repeatGotoCharE Direction -> Direction
reverseDir, VimState -> VimState
forall a. a -> a
id)

    -- Repeat
    , (Char -> Event
char Char
'&', EditorM (Maybe Substitution)
loadSubstitutionE EditorM (Maybe Substitution)
-> (Maybe Substitution -> 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
>>= EditorM ()
-> (Substitution -> EditorM ()) -> Maybe Substitution -> EditorM ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> EditorM ()
forall a. a -> EditorM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) Substitution -> EditorM ()
repeatSubstitutionFlaglessE, VimState -> VimState
forall a. a -> a
id)

    -- Transition to ex
    , (Char -> Event
char Char
':', do
        EditorM BufferRef -> EditorM ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Text -> KeymapEndo -> EditorM BufferRef
spawnMinibufferE Text
":" KeymapEndo
forall a. a -> a
id)
        EditorM ()
historyStart
        Text -> EditorM ()
historyPrefixSet Text
""
      , VimMode -> VimState -> VimState
switchMode VimMode
Ex)

    -- Undo
    , (Char -> Event
char Char
'u', BufferM () -> EditorM ()
withCountOnBuffer BufferM ()
undoB EditorM () -> EditorM () -> EditorM ()
forall a b. EditorM a -> EditorM b -> EditorM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
leftOnEol, VimState -> VimState
forall a. a -> a
id)
    , (Char -> Event
char Char
'U', BufferM () -> EditorM ()
withCountOnBuffer BufferM ()
undoB EditorM () -> EditorM () -> EditorM ()
forall a b. EditorM a -> EditorM b -> EditorM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
leftOnEol, VimState -> VimState
forall a. a -> a
id) -- TODO
    , (Char -> Event
ctrlCh Char
'r', BufferM () -> EditorM ()
withCountOnBuffer BufferM ()
redoB EditorM () -> EditorM () -> EditorM ()
forall a b. EditorM a -> EditorM b -> EditorM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
leftOnEol, VimState -> VimState
forall a. a -> a
id)

    -- scrolling
    ,(Char -> Event
ctrlCh Char
'b', EditorM Int
getCountE EditorM Int -> (Int -> 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
>>= BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> (Int -> BufferM ()) -> Int -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> BufferM ()
upScreensB, VimState -> VimState
forall a. a -> a
id)
    ,(Char -> Event
ctrlCh Char
'f', EditorM Int
getCountE EditorM Int -> (Int -> 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
>>= BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> (Int -> BufferM ()) -> Int -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> BufferM ()
downScreensB, VimState -> VimState
forall a. a -> a
id)
    ,(Char -> Event
ctrlCh Char
'u', EditorM Int
getCountE EditorM Int -> (Int -> 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
>>= BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> (Int -> BufferM ()) -> Int -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int) -> Int -> BufferM ()
vimScrollByB (Int -> Int
forall a. Num a => a -> a
negate (Int -> Int) -> (Int -> Int) -> Int -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2)), VimState -> VimState
forall a. a -> a
id)
    ,(Char -> Event
ctrlCh Char
'd', EditorM Int
getCountE EditorM Int -> (Int -> 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
>>= BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> (Int -> BufferM ()) -> Int -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int) -> Int -> BufferM ()
vimScrollByB (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2), VimState -> VimState
forall a. a -> a
id)
    ,(Char -> Event
ctrlCh Char
'y', EditorM Int
getCountE EditorM Int -> (Int -> 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
>>= BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> (Int -> BufferM ()) -> Int -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> BufferM ()
vimScrollB (Int -> BufferM ()) -> (Int -> Int) -> Int -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int
forall a. Num a => a -> a
negate, VimState -> VimState
forall a. a -> a
id)
    ,(Char -> Event
ctrlCh Char
'e', EditorM Int
getCountE EditorM Int -> (Int -> 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
>>= BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> (Int -> BufferM ()) -> Int -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> BufferM ()
vimScrollB, VimState -> VimState
forall a. a -> a
id)

    -- unsorted TODO
    , (Char -> Event
char Char
'-', () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimState -> VimState
forall a. a -> a
id)
    , (Char -> Event
char Char
'+', () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimState -> VimState
forall a. a -> a
id)
    , (Key -> Event
spec Key
KEnter, () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (), VimState -> VimState
forall a. a -> a
id)
    ] [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<> ((EventString, EditorM (), VimState -> VimState) -> VimBinding)
-> [(EventString, EditorM (), VimState -> VimState)]
-> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (VimMode
-> RepeatToken
-> (EventString, EditorM (), VimState -> VimState)
-> VimBinding
mkStringBindingE VimMode
Normal RepeatToken
Drop)
    [ (EventString
"g*", Bool -> Direction -> EditorM ()
searchWordE Bool
False Direction
Forward, VimState -> VimState
resetCount)
    , (EventString
"g#", Bool -> Direction -> EditorM ()
searchWordE Bool
False Direction
Backward, VimState -> VimState
resetCount)
    , (EventString
"gd", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ (forall syntax. Mode syntax -> BufferM ()) -> BufferM ()
forall a. (forall syntax. Mode syntax -> BufferM a) -> BufferM a
withModeB Mode syntax -> BufferM ()
forall syntax. Mode syntax -> BufferM ()
modeGotoDeclaration, VimState -> VimState
resetCount)
    , (EventString
"gD", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ (forall syntax. Mode syntax -> BufferM ()) -> BufferM ()
forall a. (forall syntax. Mode syntax -> BufferM a) -> BufferM a
withModeB Mode syntax -> BufferM ()
forall syntax. Mode syntax -> BufferM ()
modeGotoDeclaration, VimState -> VimState
resetCount)
    , (EventString
"g&", EditorM (Maybe Substitution)
loadSubstitutionE EditorM (Maybe Substitution)
-> (Maybe Substitution -> 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
>>= EditorM ()
-> (Substitution -> EditorM ()) -> Maybe Substitution -> EditorM ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> EditorM ()
forall a. a -> EditorM a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) Substitution -> EditorM ()
repeatSubstitutionE, VimState -> VimState
forall a. a -> a
id)
    , (EventString
"<C-g>", EditorM ()
printFileInfoE, VimState -> VimState
resetCount)
    , (EventString
"<C-w>c", EditorM ()
tryCloseE, VimState -> VimState
resetCount)
    , (EventString
"<C-w>o", EditorM ()
closeOtherE, VimState -> VimState
resetCount)
    , (EventString
"<C-w>s", EditorM ()
splitE, VimState -> VimState
resetCount)
    , (EventString
"<C-w>w", EditorM ()
nextWinE, VimState -> VimState
resetCount)
    , (EventString
"<C-w><Down>", EditorM ()
nextWinE, VimState -> VimState
resetCount) -- TODO: please implement downWinE
    , (EventString
"<C-w><Right>", EditorM ()
nextWinE, VimState -> VimState
resetCount) -- TODO: please implement rightWinE
    , (EventString
"<C-w><C-w>", EditorM ()
nextWinE, VimState -> VimState
resetCount)
    , (EventString
"<C-w>W", EditorM ()
prevWinE, VimState -> VimState
resetCount)
    , (EventString
"<C-w>p", EditorM ()
prevWinE, VimState -> VimState
resetCount)
    , (EventString
"<C-w><Up>", EditorM ()
prevWinE, VimState -> VimState
resetCount) -- TODO: please implement upWinE
    , (EventString
"<C-w><Left>", EditorM ()
prevWinE, VimState -> VimState
resetCount) -- TODO: please implement leftWinE
    , (EventString
"<C-w>l", EditorM ()
layoutManagersNextE, VimState -> VimState
resetCount)
    , (EventString
"<C-w>L", EditorM ()
layoutManagersPreviousE, VimState -> VimState
resetCount)
    --, ("<C-w> ", layoutManagersNextE, resetCount)
    , (EventString
"<C-w>v", EditorM ()
layoutManagerNextVariantE, VimState -> VimState
resetCount)
    , (EventString
"<C-w>V", EditorM ()
layoutManagerPreviousVariantE, VimState -> VimState
resetCount)
    , (EventString
"<C-a>", EditorM Int
getCountE EditorM Int -> (Int -> 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
>>= BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> (Int -> BufferM ()) -> Int -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> BufferM ()
incrementNextNumberByB, VimState -> VimState
resetCount)
    , (EventString
"<C-x>", EditorM Int
getCountE EditorM Int -> (Int -> 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
>>= BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ())
-> (Int -> BufferM ()) -> Int -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> BufferM ()
incrementNextNumberByB (Int -> BufferM ()) -> (Int -> Int) -> Int -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int
forall a. Num a => a -> a
negate, VimState -> VimState
resetCount)

    -- z commands
    -- TODO Add prefix count
    , (EventString
"zt", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
scrollCursorToTopB, VimState -> VimState
resetCount)
    , (EventString
"zb", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
scrollCursorToBottomB, VimState -> VimState
resetCount)
    , (EventString
"zz", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
scrollToCursorB, VimState -> VimState
resetCount)
    {- -- TODO Horizantal scrolling
    , ("ze", withCurrentBuffer .., resetCount)
    , ("zs", withCurrentBuffer .., resetCount)
    , ("zH", withCurrentBuffer .., resetCount)
    , ("zL", withCurrentBuffer .., resetCount)
    , ("zh", withCurrentBuffer .., resetCount)
    , ("zl", withCurrentBuffer .., resetCount)
    -}
    , (EventString
"z.", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ BufferM ()
scrollToCursorB BufferM () -> BufferM () -> BufferM ()
forall a b. BufferM a -> BufferM b -> BufferM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> BufferM ()
moveToSol, VimState -> VimState
resetCount)
    , (EventString
"z+", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
scrollToLineBelowWindowB, VimState -> VimState
resetCount)
    , (EventString
"z-", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ BufferM ()
scrollCursorToBottomB BufferM () -> BufferM () -> BufferM ()
forall a b. BufferM a -> BufferM b -> BufferM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> BufferM ()
moveToSol, VimState -> VimState
resetCount)
    , (EventString
"z^", BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
scrollToLineAboveWindowB, VimState -> VimState
resetCount)
    {- -- TODO Code folding
    , ("zf", .., resetCount)
    , ("zc", .., resetCount)
    , ("zo", .., resetCount)
    , ("za", .., resetCount)
    , ("zC", .., resetCount)
    , ("zO", .., resetCount)
    , ("zA", .., resetCount)
    , ("zr", .., resetCount)
    , ("zR", .., resetCount)
    , ("zm", .., resetCount)
    , ("zM", .., resetCount)
    -}

    -- Z commands
    ] [VimBinding] -> [VimBinding] -> [VimBinding]
forall a. Semigroup a => a -> a -> a
<> ((EventString, YiM (), VimState -> VimState) -> VimBinding)
-> [(EventString, YiM (), VimState -> VimState)] -> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (VimMode
-> (EventString, YiM (), VimState -> VimState) -> VimBinding
mkStringBindingY VimMode
Normal)
    [ (EventString
"ZQ", YiM ()
quitEditor, VimState -> VimState
forall a. a -> a
id)
    -- TODO ZZ should replicate :x not :wq
    , (EventString
"ZZ", YiM Bool
fwriteE YiM Bool -> YiM () -> YiM ()
forall a b. YiM a -> YiM b -> YiM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> YiM ()
closeWindow, VimState -> VimState
forall a. a -> a
id)
    ]

fileEditBindings :: [VimBinding]
fileEditBindings :: [VimBinding]
fileEditBindings =  ((EventString, YiM (), VimState -> VimState) -> VimBinding)
-> [(EventString, YiM (), VimState -> VimState)] -> [VimBinding]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (VimMode
-> (EventString, YiM (), VimState -> VimState) -> VimBinding
mkStringBindingY VimMode
Normal)
    [ (EventString
"gf", Maybe (EditorM ()) -> YiM ()
openFileUnderCursor Maybe (EditorM ())
forall a. Maybe a
Nothing, VimState -> VimState
resetCount)
    , (EventString
"<C-w>gf", Maybe (EditorM ()) -> YiM ()
openFileUnderCursor (Maybe (EditorM ()) -> YiM ()) -> Maybe (EditorM ()) -> YiM ()
forall a b. (a -> b) -> a -> b
$ EditorM () -> Maybe (EditorM ())
forall a. a -> Maybe a
Just EditorM ()
newTabE, VimState -> VimState
resetCount)
    , (EventString
"<C-w>f", Maybe (EditorM ()) -> YiM ()
openFileUnderCursor (Maybe (EditorM ()) -> YiM ()) -> Maybe (EditorM ()) -> YiM ()
forall a b. (a -> b) -> a -> b
$ EditorM () -> Maybe (EditorM ())
forall a. a -> Maybe a
Just (EditorM ()
splitE EditorM () -> EditorM () -> EditorM ()
forall a b. EditorM a -> EditorM b -> EditorM b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> EditorM ()
prevWinE), VimState -> VimState
resetCount)
    ]

setMarkBinding :: VimBinding
setMarkBinding :: VimBinding
setMarkBinding = (EventString -> VimState -> MatchResult (EditorM RepeatToken))
-> VimBinding
VimBindingE (String -> VimState -> MatchResult (EditorM RepeatToken)
forall {m :: * -> *}.
MonadEditor m =>
String -> VimState -> MatchResult (m 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 (m RepeatToken)
f String
_ VimState
s | VimState -> VimMode
vsMode VimState
s VimMode -> VimMode -> Bool
forall a. Eq a => a -> a -> Bool
/= VimMode
Normal = MatchResult (m RepeatToken)
forall a. MatchResult a
NoMatch
          f String
"m" VimState
_ = MatchResult (m RepeatToken)
forall a. MatchResult a
PartialMatch
          f (Char
'm':Char
c:[]) VimState
_ = m RepeatToken -> MatchResult (m RepeatToken)
forall a. a -> MatchResult a
WholeMatch (m RepeatToken -> MatchResult (m RepeatToken))
-> m RepeatToken -> MatchResult (m RepeatToken)
forall a b. (a -> b) -> a -> b
$ do
              BufferM () -> m ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> m ()) -> BufferM () -> m ()
forall a b. (a -> b) -> a -> b
$ String -> BufferM ()
setNamedMarkHereB [Char
c]
              RepeatToken -> m RepeatToken
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Drop
          f String
_ VimState
_ = MatchResult (m RepeatToken)
forall a. MatchResult a
NoMatch

searchWordE :: Bool -> Direction -> EditorM ()
searchWordE :: Bool -> Direction -> EditorM ()
searchWordE Bool
wholeWord Direction
dir = do
  word <- BufferM YiString -> EditorM YiString
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM YiString
readCurrentWordB

  let search SearchExp
re = do
        SearchExp -> EditorM ()
setRegexE SearchExp
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
dir
        EditorM () -> EditorM ()
withCount (EditorM () -> EditorM ()) -> EditorM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ (Direction -> Direction) -> EditorM ()
continueSearching (Direction -> Direction -> Direction
forall a b. a -> b -> a
const Direction
dir)

  if wholeWord
  then case makeSearchOptsM [] $ "\\<" <> R.toString word <> "\\>" of
          Right SearchExp
re -> SearchExp -> EditorM ()
search SearchExp
re
          Left String
_ -> () -> EditorM ()
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  else search $ makeSimpleSearch word

searchBinding :: VimBinding
searchBinding :: VimBinding
searchBinding = (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 = VimMode
Normal }) | String
evs String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String -> [String]
forall a. Eq a => [a] -> [[a]]
group [Char
'/', Char
'?']
            = 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
                  state <- (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
                  let dir = if String
evs String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"/" then Direction
Forward else Direction
Backward
                  switchModeE $ Search state dir
                  isearchInitE dir
                  historyStart
                  historyPrefixSet T.empty
                  return Continue
          f String
_ VimState
_ = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
NoMatch

continueSearching :: (Direction -> Direction) -> EditorM ()
continueSearching :: (Direction -> Direction) -> EditorM ()
continueSearching Direction -> Direction
fdir =
  EditorM (Maybe SearchExp)
getRegexE EditorM (Maybe SearchExp)
-> (Maybe SearchExp -> 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
>>= \case
    Just SearchExp
regex -> do
      dir <- Direction -> Direction
fdir (Direction -> Direction) -> EditorM Direction -> EditorM Direction
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Getting Direction Editor Direction -> EditorM Direction
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting Direction Editor Direction
Lens' Editor Direction
searchDirectionA
      printMsg . T.pack $ (if dir == Forward then '/' else '?') : seInput regex
      void $ doVimSearch Nothing [] dir
    Maybe SearchExp
Nothing -> Text -> EditorM ()
forall (m :: * -> *). MonadEditor m => Text -> m ()
printMsg Text
"No previous search pattern"

repeatGotoCharE :: (Direction -> Direction) -> EditorM ()
repeatGotoCharE :: (Direction -> Direction) -> EditorM ()
repeatGotoCharE Direction -> Direction
mutateDir = do
    prevCommand <- (VimState -> Maybe GotoCharCommand)
-> EditorM VimState -> EditorM (Maybe GotoCharCommand)
forall a b. (a -> b) -> EditorM a -> EditorM b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap VimState -> Maybe GotoCharCommand
vsLastGotoCharCommand EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
    count <- getCountE
    withCurrentBuffer $ case prevCommand of
        Just (GotoCharCommand Char
c Direction
dir RegionStyle
style) -> do
            let newDir :: Direction
newDir = Direction -> Direction
mutateDir Direction
dir
            let move :: BufferM ()
move = Char -> Direction -> RegionStyle -> Bool -> BufferM ()
gotoCharacterB Char
c Direction
newDir RegionStyle
style Bool
True
            p0 <- BufferM Point
pointB
            replicateM_ (count - 1) $ do
                move
                when (style == Exclusive) $ moveB Character newDir
            p1 <- pointB
            move
            p2 <- pointB
            when (p1 == p2) $ moveTo p0
        Maybe GotoCharCommand
Nothing -> () -> BufferM ()
forall a. a -> BufferM a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

enableVisualE :: RegionStyle -> EditorM ()
enableVisualE :: RegionStyle -> EditorM ()
enableVisualE RegionStyle
style = BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
    RegionStyle -> BufferM ()
putRegionStyle RegionStyle
style
    (Bool -> Identity Bool) -> FBuffer -> Identity FBuffer
Lens' FBuffer Bool
rectangleSelectionA ((Bool -> Identity Bool) -> FBuffer -> Identity FBuffer)
-> Bool -> BufferM ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= (RegionStyle
Block RegionStyle -> RegionStyle -> Bool
forall a. Eq a => a -> a -> Bool
== RegionStyle
style)
    Bool -> BufferM ()
setVisibleSelection Bool
True
    BufferM Point
pointB BufferM Point -> (Point -> BufferM ()) -> BufferM ()
forall a b. BufferM a -> (a -> BufferM b) -> BufferM b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Point -> BufferM ()
setSelectionMarkPointB

cutCharE :: Direction -> EOLStickiness -> Int -> EditorM ()
cutCharE :: Direction -> EOLStickiness -> Int -> EditorM ()
cutCharE Direction
dir EOLStickiness
stickiness Int
count = do
    r <- BufferM YiString -> EditorM YiString
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM YiString -> EditorM YiString)
-> BufferM YiString -> EditorM YiString
forall a b. (a -> b) -> a -> b
$ do
        p0 <- BufferM Point
pointB
        (if dir == Forward then moveXorEol else moveXorSol) count
        p1 <- pointB
        let region = Point -> Point -> Region
mkRegion Point
p0 Point
p1
        rope <- readRegionB region
        deleteRegionB $ mkRegion p0 p1
        when (stickiness == NonSticky) leftOnEol
        return rope
    regName <- fmap vsActiveRegister getEditorDyn
    setRegisterE regName Inclusive r

tabTraversalBinding :: VimBinding
tabTraversalBinding :: VimBinding
tabTraversalBinding = (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
"g" (VimState { vsMode :: VimState -> VimMode
vsMode = VimMode
Normal }) = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
PartialMatch
          f (Char
'g':Char
c:[]) (VimState { vsMode :: VimState -> VimMode
vsMode = VimMode
Normal }) | Char
c Char -> String -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char
't', Char
'T'] = 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
              count <- EditorM Int
getCountE
              replicateM_ count $ if c == 'T' then previousTabE else nextTabE
              resetCountE
              return Drop
          f String
_ VimState
_ = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
NoMatch

openFileUnderCursor :: Maybe (EditorM ()) -> YiM ()
openFileUnderCursor :: Maybe (EditorM ()) -> YiM ()
openFileUnderCursor Maybe (EditorM ())
editorAction = do
  fileName <- (YiString -> String) -> YiM YiString -> YiM String
forall a b. (a -> b) -> YiM a -> YiM b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap YiString -> String
R.toString (YiM YiString -> YiM String)
-> (BufferM YiString -> YiM YiString)
-> BufferM YiString
-> YiM String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BufferM YiString -> YiM YiString
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM YiString -> YiM String) -> BufferM YiString -> YiM String
forall a b. (a -> b) -> a -> b
$ TextUnit -> BufferM YiString
readUnitB TextUnit
unitViWORD
  fileExists <- io $ doesFileExist =<< expandTilda fileName
  if fileExists then do
      maybeM withEditor editorAction
      openNewFile $ fileName
  else
      withEditor . fail $ "Can't find file \"" <> fileName <> "\""

recordMacroBinding :: VimBinding
recordMacroBinding :: VimBinding
recordMacroBinding = (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
"q" (VimState { vsMode :: VimState -> VimMode
vsMode = VimMode
Normal
                          , vsCurrentMacroRecording :: VimState -> Maybe (Char, EventString)
vsCurrentMacroRecording = Maybe (Char, EventString)
Nothing })
                = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
PartialMatch
          f [Char
'q', Char
c] (VimState { vsMode :: VimState -> VimMode
vsMode = VimMode
Normal })
              = 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 -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s ->
                        VimState
s { vsCurrentMacroRecording = Just (c, mempty) }
                    RepeatToken -> EditorM RepeatToken
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Finish
          f String
_ VimState
_ = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
NoMatch

finishRecordingMacroBinding :: VimBinding
finishRecordingMacroBinding :: VimBinding
finishRecordingMacroBinding = (EventString -> VimState -> MatchResult (EditorM RepeatToken))
-> VimBinding
VimBindingE (String -> VimState -> MatchResult (EditorM RepeatToken)
forall {a}.
(Eq a, IsString a) =>
a -> 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 :: a -> VimState -> MatchResult (EditorM RepeatToken)
f a
"q" (VimState { vsMode :: VimState -> VimMode
vsMode = VimMode
Normal
                          , vsCurrentMacroRecording :: VimState -> Maybe (Char, EventString)
vsCurrentMacroRecording = Just (Char
macroName, Ev Text
macroBody) })
                = 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
                      let reg :: Register
reg = RegionStyle -> YiString -> Register
Register RegionStyle
Exclusive (Text -> YiString
R.fromText (Int -> Text -> Text
T.drop Int
2 Text
macroBody))
                      (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s -> VimState
s
                          { vsCurrentMacroRecording = Nothing
                          , vsRegisterMap = insert macroName reg (vsRegisterMap s)
                          }
                      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

playMacroBinding :: VimBinding
playMacroBinding :: VimBinding
playMacroBinding = (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
"@" (VimState { vsMode :: VimState -> VimMode
vsMode = VimMode
Normal }) = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
PartialMatch
          f [Char
'@', Char
c] (VimState { vsMode :: VimState -> VimMode
vsMode = VimMode
Normal
                               , vsRegisterMap :: VimState -> HashMap Char Register
vsRegisterMap = HashMap Char Register
registers
                               , vsCount :: VimState -> Maybe Int
vsCount = Maybe Int
mbCount }) = 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
              EditorM ()
resetCountE
              case Char -> HashMap Char Register -> Maybe Register
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
lookup Char
c HashMap Char Register
registers of
                  Just reg :: Register
reg@(Register RegionStyle
_ YiString
evs) -> do
                      let count :: Int
count = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
1 Maybe Int
mbCount
                          mkAct :: YiString -> EventString
mkAct = Text -> EventString
Ev (Text -> EventString)
-> (YiString -> Text) -> YiString -> EventString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Text -> Text
T.replicate Int
count (Text -> Text) -> (YiString -> Text) -> YiString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YiString -> Text
R.toText
                      EventString -> EditorM ()
scheduleActionStringForEval (EventString -> EditorM ())
-> (YiString -> EventString) -> YiString -> EditorM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. YiString -> EventString
mkAct (YiString -> EditorM ()) -> YiString -> EditorM ()
forall a b. (a -> b) -> a -> b
$ YiString
evs
                      (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s ->
                          VimState
s { vsRegisterMap = insert '@' reg (vsRegisterMap s) }
                      RepeatToken -> EditorM RepeatToken
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Finish
                  Maybe Register
Nothing -> RepeatToken -> EditorM RepeatToken
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Drop
          f String
_ VimState
_ = MatchResult (EditorM RepeatToken)
forall a. MatchResult a
NoMatch

-- TODO: withCount name implies that parameter has type (Int -> EditorM ())
--       Is there a better name for this function?
withCount :: EditorM () -> EditorM ()
withCount :: EditorM () -> EditorM ()
withCount EditorM ()
action = (Int -> EditorM () -> EditorM ())
-> EditorM () -> Int -> EditorM ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> EditorM () -> EditorM ()
forall (m :: * -> *) a. Applicative m => Int -> m a -> m ()
replicateM_ EditorM ()
action (Int -> EditorM ()) -> EditorM Int -> EditorM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< EditorM Int
getCountE

withCountOnBuffer :: BufferM () -> EditorM ()
withCountOnBuffer :: BufferM () -> EditorM ()
withCountOnBuffer BufferM ()
action = EditorM () -> EditorM ()
withCount (EditorM () -> EditorM ()) -> EditorM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer BufferM ()
action