{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_HADDOCK show-extensions #-}
module Yi.Keymap.Vim.StateUtils
( switchMode
, switchModeE
, resetCount
, resetCountE
, setCountE
, modifyStateE
, getMaybeCountE
, getCountE
, accumulateEventE
, accumulateBindingEventE
, accumulateTextObjectEventE
, flushAccumulatorE
, dropAccumulatorE
, dropBindingAccumulatorE
, dropTextObjectAccumulatorE
, setRegisterE
, getRegisterE
, normalizeCountE
, maybeMult
, updateModeIndicatorE
, saveInsertEventStringE
, resetActiveRegisterE
, saveSubstitutionE
, loadSubstitutionE
) where
import Control.Monad (when)
import qualified Data.HashMap.Strict as HM (insert, lookup)
import Data.Maybe (fromMaybe, isJust)
import Data.Monoid ((<>))
import qualified Data.Text as T (null)
import Yi.Buffer.Normal (RegionStyle (Block, LineWise))
import Yi.Editor (EditorM, getEditorDyn, putEditorDyn, setStatus)
import Yi.Event (Event)
import Yi.Keymap.Vim.Common
import Yi.Keymap.Vim.EventUtils
import Yi.Rope (YiString)
import Yi.String (showT)
import Yi.Style (defaultStyle)
switchMode :: VimMode -> VimState -> VimState
switchMode :: VimMode -> VimState -> VimState
switchMode VimMode
mode VimState
state = VimState
state { vsMode = mode }
switchModeE :: VimMode -> EditorM ()
switchModeE :: VimMode -> EditorM ()
switchModeE VimMode
mode = (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ VimMode -> VimState -> VimState
switchMode VimMode
mode
modifyStateE :: (VimState -> VimState) -> EditorM ()
modifyStateE :: (VimState -> VimState) -> EditorM ()
modifyStateE VimState -> VimState
f = do
VimState
currentState <- EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
VimState -> EditorM ()
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Functor m) =>
a -> m ()
putEditorDyn (VimState -> EditorM ()) -> VimState -> EditorM ()
forall a b. (a -> b) -> a -> b
$ VimState -> VimState
f VimState
currentState
resetCount :: VimState -> VimState
resetCount :: VimState -> VimState
resetCount VimState
s = VimState
s { vsCount = Nothing }
resetCountE :: EditorM ()
resetCountE :: EditorM ()
resetCountE = (VimState -> VimState) -> EditorM ()
modifyStateE VimState -> VimState
resetCount
getMaybeCountE :: EditorM (Maybe Int)
getMaybeCountE :: EditorM (Maybe Int)
getMaybeCountE = (VimState -> Maybe Int) -> EditorM VimState -> EditorM (Maybe Int)
forall a b. (a -> b) -> EditorM a -> EditorM b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap VimState -> Maybe Int
vsCount EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
getCountE :: EditorM Int
getCountE :: EditorM Int
getCountE = do
VimState
currentState <- EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
Int -> EditorM Int
forall a. a -> EditorM a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> EditorM Int) -> Int -> EditorM Int
forall a b. (a -> b) -> a -> b
$! Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
1 (VimState -> Maybe Int
vsCount VimState
currentState)
setCountE :: Int -> EditorM ()
setCountE :: Int -> EditorM ()
setCountE Int
n = (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s -> VimState
s { vsCount = Just n }
accumulateBindingEventE :: Event -> EditorM ()
accumulateBindingEventE :: Event -> EditorM ()
accumulateBindingEventE Event
e = (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$
\VimState
s -> VimState
s { vsBindingAccumulator = vsBindingAccumulator s <> eventToEventString e }
accumulateEventE :: Event -> EditorM ()
accumulateEventE :: Event -> EditorM ()
accumulateEventE Event
e = (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$
\VimState
s -> VimState
s { vsAccumulator = vsAccumulator s <> eventToEventString e }
accumulateTextObjectEventE :: EventString -> EditorM ()
accumulateTextObjectEventE :: EventString -> EditorM ()
accumulateTextObjectEventE EventString
evs = (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$
\VimState
s -> VimState
s { vsTextObjectAccumulator = vsTextObjectAccumulator s <> evs }
flushAccumulatorE :: EditorM ()
flushAccumulatorE :: EditorM ()
flushAccumulatorE = do
EventString
accum <- VimState -> EventString
vsAccumulator (VimState -> EventString)
-> EditorM VimState -> EditorM EventString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
let repeatableAction :: RepeatableAction
repeatableAction = EventString -> RepeatableAction
stringToRepeatableAction EventString
accum
EventString
accum EventString -> EditorM () -> EditorM ()
forall a b. a -> b -> b
`seq` (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s ->
VimState
s { vsRepeatableAction = Just repeatableAction
, vsAccumulator = mempty
, vsCurrentMacroRecording = fmap (fmap (<> accum))
(vsCurrentMacroRecording s)
}
dropAccumulatorE :: EditorM ()
dropAccumulatorE :: EditorM ()
dropAccumulatorE =
(VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s ->
let accum :: EventString
accum = VimState -> EventString
vsAccumulator VimState
s
in VimState
s { vsAccumulator = mempty
, vsCurrentMacroRecording = fmap (fmap (<> accum))
(vsCurrentMacroRecording s)
}
dropBindingAccumulatorE :: EditorM ()
dropBindingAccumulatorE :: EditorM ()
dropBindingAccumulatorE =
(VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s -> VimState
s { vsBindingAccumulator = mempty }
dropTextObjectAccumulatorE :: EditorM ()
dropTextObjectAccumulatorE :: EditorM ()
dropTextObjectAccumulatorE =
(VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s -> VimState
s { vsTextObjectAccumulator = mempty }
getRegisterE :: RegisterName -> EditorM (Maybe Register)
getRegisterE :: RegisterName -> EditorM (Maybe Register)
getRegisterE RegisterName
name = (VimState -> Maybe Register)
-> EditorM VimState -> EditorM (Maybe Register)
forall a b. (a -> b) -> EditorM a -> EditorM b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (RegisterName -> HashMap RegisterName Register -> Maybe Register
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup RegisterName
name (HashMap RegisterName Register -> Maybe Register)
-> (VimState -> HashMap RegisterName Register)
-> VimState
-> Maybe Register
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimState -> HashMap RegisterName Register
vsRegisterMap) EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
setRegisterE :: RegisterName -> RegionStyle -> YiString -> EditorM ()
setRegisterE :: RegisterName -> RegionStyle -> YiString -> EditorM ()
setRegisterE RegisterName
name RegionStyle
style YiString
rope = do
HashMap RegisterName Register
rmap <- (VimState -> HashMap RegisterName Register)
-> EditorM VimState -> EditorM (HashMap RegisterName Register)
forall a b. (a -> b) -> EditorM a -> EditorM b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap VimState -> HashMap RegisterName Register
vsRegisterMap EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
let rmap' :: HashMap RegisterName Register
rmap' = RegisterName
-> Register
-> HashMap RegisterName Register
-> HashMap RegisterName Register
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HM.insert RegisterName
name (RegionStyle -> YiString -> Register
Register RegionStyle
style YiString
rope) HashMap RegisterName Register
rmap
(VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
state -> VimState
state { vsRegisterMap = rmap' }
normalizeCountE :: Maybe Int -> EditorM ()
normalizeCountE :: Maybe Int -> EditorM ()
normalizeCountE Maybe Int
n = do
Maybe Int
mcount <- EditorM (Maybe Int)
getMaybeCountE
(VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s -> VimState
s {
vsCount = maybeMult mcount n
, vsAccumulator = Ev (showT . fromMaybe 1 $ maybeMult mcount n)
<> snd (splitCountedCommand . normalizeCount $ vsAccumulator s)
}
maybeMult :: Num a => Maybe a -> Maybe a -> Maybe a
maybeMult :: forall a. Num a => Maybe a -> Maybe a -> Maybe a
maybeMult (Just a
a) (Just a
b) = a -> Maybe a
forall a. a -> Maybe a
Just (a
a a -> a -> a
forall a. Num a => a -> a -> a
* a
b)
maybeMult Maybe a
Nothing Maybe a
Nothing = Maybe a
forall a. Maybe a
Nothing
maybeMult Maybe a
a Maybe a
Nothing = Maybe a
a
maybeMult Maybe a
Nothing Maybe a
b = Maybe a
b
updateModeIndicatorE :: VimState -> EditorM ()
updateModeIndicatorE :: VimState -> EditorM ()
updateModeIndicatorE VimState
prevState = do
VimState
currentState <- EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
let mode :: VimMode
mode = VimState -> VimMode
vsMode VimState
currentState
prevMode :: VimMode
prevMode = VimState -> VimMode
vsMode VimState
prevState
paste :: Bool
paste = VimState -> Bool
vsPaste VimState
currentState
isRecording :: Bool
isRecording = Maybe (RegisterName, EventString) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe (RegisterName, EventString) -> Bool)
-> (VimState -> Maybe (RegisterName, EventString))
-> VimState
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimState -> Maybe (RegisterName, EventString)
vsCurrentMacroRecording (VimState -> Bool) -> VimState -> Bool
forall a b. (a -> b) -> a -> b
$ VimState
currentState
prevRecording :: Bool
prevRecording = Maybe (RegisterName, EventString) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe (RegisterName, EventString) -> Bool)
-> (VimState -> Maybe (RegisterName, EventString))
-> VimState
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimState -> Maybe (RegisterName, EventString)
vsCurrentMacroRecording (VimState -> Bool) -> VimState -> Bool
forall a b. (a -> b) -> a -> b
$ VimState
prevState
Bool -> EditorM () -> EditorM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (VimMode
mode VimMode -> VimMode -> Bool
forall a. Eq a => a -> a -> Bool
/= VimMode
prevMode Bool -> Bool -> Bool
|| Bool
isRecording Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
/= Bool
prevRecording) (EditorM () -> EditorM ()) -> EditorM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
let modeName :: Text
modeName = case VimMode
mode of
Insert RegisterName
_ -> Text
"INSERT" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> if Bool
paste then Text
" (paste) " else Text
""
VimMode
InsertNormal -> Text
"(insert)"
VimMode
InsertVisual -> Text
"(insert) VISUAL"
VimMode
Replace -> Text
"REPLACE"
Visual RegionStyle
Block -> Text
"VISUAL BLOCK"
Visual RegionStyle
LineWise -> Text
"VISUAL LINE"
Visual RegionStyle
_ -> Text
"VISUAL"
VimMode
_ -> Text
""
decoratedModeName' :: Text
decoratedModeName' = if Text -> Bool
T.null Text
modeName
then Text
forall a. Monoid a => a
mempty
else Text
"-- " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
modeName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" --"
decoratedModeName :: Text
decoratedModeName = if Bool
isRecording
then Text
decoratedModeName' Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"recording"
else Text
decoratedModeName'
Status -> EditorM ()
forall (m :: * -> *). MonadEditor m => Status -> m ()
setStatus ([Text
decoratedModeName], StyleName
defaultStyle)
saveInsertEventStringE :: EventString -> EditorM ()
saveInsertEventStringE :: EventString -> EditorM ()
saveInsertEventStringE EventString
evs = (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s ->
VimState
s { vsOngoingInsertEvents = vsOngoingInsertEvents s <> evs }
resetActiveRegisterE :: EditorM ()
resetActiveRegisterE :: EditorM ()
resetActiveRegisterE = (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s -> VimState
s { vsActiveRegister = '\0' }
saveSubstitutionE :: Substitution -> EditorM ()
saveSubstitutionE :: Substitution -> EditorM ()
saveSubstitutionE Substitution
sub = (VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s -> VimState
s { vsLastSubstitution = Just sub }
loadSubstitutionE :: EditorM (Maybe Substitution)
loadSubstitutionE :: EditorM (Maybe Substitution)
loadSubstitutionE = VimState -> Maybe Substitution
vsLastSubstitution (VimState -> Maybe Substitution)
-> EditorM VimState -> EditorM (Maybe Substitution)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn