{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_HADDOCK show-extensions #-}
module Yi.Keymap.Vim.Operator
( VimOperator(..)
, defOperators
, opDelete
, opChange
, opYank
, opFormat
, stringToOperator
, mkCharTransformOperator
, operatorApplyToTextObjectE
, lastCharForOperator
) where
import Control.Monad (when)
import Data.Char (isSpace, toLower, toUpper)
import Data.Foldable (find)
import qualified Data.List.NonEmpty as NE
import Data.Maybe (fromJust)
import Data.Monoid ((<>))
import qualified Data.Text as T (unpack)
import Yi.Buffer hiding (Insert)
import Yi.Buffer.Misc (startUpdateTransactionB)
import Yi.Editor (EditorM, getEditorDyn, withCurrentBuffer)
import Yi.Keymap.Vim.Common
import Yi.Keymap.Vim.EventUtils (eventToEventString, parseEvents)
import Yi.Keymap.Vim.StateUtils (setRegisterE, switchModeE, modifyStateE)
import Yi.Keymap.Vim.StyledRegion (StyledRegion (..), transformCharactersInRegionB)
import Yi.Keymap.Vim.TextObject (CountedTextObject, regionOfTextObjectB)
import Yi.Keymap.Vim.Utils (indentBlockRegionB)
import Yi.Misc (rot13Char)
import Yi.Rope (YiString)
import qualified Yi.Rope as R
data VimOperator = VimOperator {
VimOperator -> OperatorName
operatorName :: !OperatorName
, VimOperator -> Int -> StyledRegion -> EditorM RepeatToken
operatorApplyToRegionE :: Int -> StyledRegion -> EditorM RepeatToken
}
defOperators :: [VimOperator]
defOperators :: [VimOperator]
defOperators =
[ VimOperator
opYank
, VimOperator
opDelete
, VimOperator
opChange
, VimOperator
opFormat
, OperatorName -> (Char -> Char) -> VimOperator
mkCharTransformOperator OperatorName
"gu" Char -> Char
toLower
, OperatorName -> (Char -> Char) -> VimOperator
mkCharTransformOperator OperatorName
"gU" Char -> Char
toUpper
, OperatorName -> (Char -> Char) -> VimOperator
mkCharTransformOperator OperatorName
"g~" Char -> Char
switchCaseChar
, OperatorName -> (Char -> Char) -> VimOperator
mkCharTransformOperator OperatorName
"g?" Char -> Char
rot13Char
, OperatorName -> (Int -> Int) -> VimOperator
mkShiftOperator OperatorName
">" Int -> Int
forall a. a -> a
id
, OperatorName -> (Int -> Int) -> VimOperator
mkShiftOperator OperatorName
"<lt>" Int -> Int
forall a. Num a => a -> a
negate
]
stringToOperator :: [VimOperator] -> OperatorName -> Maybe VimOperator
stringToOperator :: [VimOperator] -> OperatorName -> Maybe VimOperator
stringToOperator [VimOperator]
ops OperatorName
name = (VimOperator -> Bool) -> [VimOperator] -> Maybe VimOperator
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ((OperatorName -> OperatorName -> Bool
forall a. Eq a => a -> a -> Bool
== OperatorName
name) (OperatorName -> Bool)
-> (VimOperator -> OperatorName) -> VimOperator -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. VimOperator -> OperatorName
operatorName) [VimOperator]
ops
operatorApplyToTextObjectE :: VimOperator -> Int -> CountedTextObject -> EditorM RepeatToken
operatorApplyToTextObjectE :: VimOperator -> Int -> CountedTextObject -> EditorM RepeatToken
operatorApplyToTextObjectE VimOperator
op Int
count CountedTextObject
cto = do
StyledRegion
styledRegion <- BufferM StyledRegion -> EditorM StyledRegion
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM StyledRegion -> EditorM StyledRegion)
-> BufferM StyledRegion -> EditorM StyledRegion
forall a b. (a -> b) -> a -> b
$ CountedTextObject -> BufferM StyledRegion
regionOfTextObjectB CountedTextObject
cto
VimOperator -> Int -> StyledRegion -> EditorM RepeatToken
operatorApplyToRegionE VimOperator
op Int
count StyledRegion
styledRegion
opYank :: VimOperator
opYank :: VimOperator
opYank = VimOperator :: OperatorName
-> (Int -> StyledRegion -> EditorM RepeatToken) -> VimOperator
VimOperator {
operatorName :: OperatorName
operatorName = OperatorName
"y"
, operatorApplyToRegionE :: Int -> StyledRegion -> EditorM RepeatToken
operatorApplyToRegionE = \Int
_count (StyledRegion RegionStyle
style Region
reg) -> do
YiString
s <- 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
$ Region -> RegionStyle -> BufferM YiString
readRegionRopeWithStyleB Region
reg RegionStyle
style
Char
regName <- (VimState -> Char) -> EditorM VimState -> EditorM Char
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap VimState -> Char
vsActiveRegister EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
Char -> RegionStyle -> YiString -> EditorM ()
setRegisterE Char
regName RegionStyle
style YiString
s
BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Point -> BufferM ()
moveTo (Point -> BufferM ()) -> (Region -> Point) -> Region -> BufferM ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Region -> Point
regionStart (Region -> BufferM ()) -> BufferM Region -> BufferM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Region -> RegionStyle -> BufferM Region
convertRegionToStyleB Region
reg RegionStyle
style
VimMode -> EditorM ()
switchModeE VimMode
Normal
RepeatToken -> EditorM RepeatToken
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Finish
}
opDelete :: VimOperator
opDelete :: VimOperator
opDelete = VimOperator :: OperatorName
-> (Int -> StyledRegion -> EditorM RepeatToken) -> VimOperator
VimOperator {
operatorName :: OperatorName
operatorName = OperatorName
"d"
, operatorApplyToRegionE :: Int -> StyledRegion -> EditorM RepeatToken
operatorApplyToRegionE = \Int
_count (StyledRegion RegionStyle
style Region
reg) -> do
YiString
s <- 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
$ Region -> RegionStyle -> BufferM YiString
readRegionRopeWithStyleB Region
reg RegionStyle
style
Char
regName <- (VimState -> Char) -> EditorM VimState -> EditorM Char
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap VimState -> Char
vsActiveRegister EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
Char -> RegionStyle -> YiString -> EditorM ()
setRegisterE Char
regName RegionStyle
style YiString
s
BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
Point
point <- NonEmpty Point -> Point
forall a. NonEmpty a -> a
NE.head (NonEmpty Point -> Point)
-> BufferM (NonEmpty Point) -> BufferM Point
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Region -> RegionStyle -> BufferM (NonEmpty Point)
deleteRegionWithStyleB Region
reg RegionStyle
style
Point -> BufferM ()
moveTo Point
point
Bool
eof <- BufferM Bool
atEof
if Bool
eof
then do
BufferM ()
leftB
Char
c <- BufferM Char
readB
Bool -> BufferM () -> BufferM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\n') (BufferM () -> BufferM ()) -> BufferM () -> BufferM ()
forall a b. (a -> b) -> a -> b
$ Int -> BufferM ()
deleteN Int
1 BufferM () -> BufferM () -> BufferM ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> BufferM ()
moveToSol
else BufferM ()
leftOnEol
VimMode -> EditorM ()
switchModeE VimMode
Normal
RepeatToken -> EditorM RepeatToken
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Finish
}
opChange :: VimOperator
opChange :: VimOperator
opChange = VimOperator :: OperatorName
-> (Int -> StyledRegion -> EditorM RepeatToken) -> VimOperator
VimOperator {
operatorName :: OperatorName
operatorName = OperatorName
"c"
, operatorApplyToRegionE :: Int -> StyledRegion -> EditorM RepeatToken
operatorApplyToRegionE = \Int
_count (StyledRegion RegionStyle
style Region
reg) -> do
YiString
s <- 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
$ Region -> RegionStyle -> BufferM YiString
readRegionRopeWithStyleB Region
reg RegionStyle
style
Char
regName <- (VimState -> Char) -> EditorM VimState -> EditorM Char
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap VimState -> Char
vsActiveRegister EditorM VimState
forall (m :: * -> *) a.
(MonadEditor m, YiVariable a, Default a, Functor m) =>
m a
getEditorDyn
Char -> RegionStyle -> YiString -> EditorM ()
setRegisterE Char
regName RegionStyle
style YiString
s
do
BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ BufferM ()
startUpdateTransactionB
case RegionStyle
style of
RegionStyle
LineWise -> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
Point
point <- NonEmpty Point -> Point
forall a. NonEmpty a -> a
NE.head (NonEmpty Point -> Point)
-> BufferM (NonEmpty Point) -> BufferM Point
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Region -> RegionStyle -> BufferM (NonEmpty Point)
deleteRegionWithStyleB Region
reg RegionStyle
style
Point -> BufferM ()
moveTo Point
point
Char -> BufferM ()
insertB Char
'\n'
BufferM ()
leftB
RegionStyle
Block -> do
NonEmpty Point
points <- BufferM (NonEmpty Point) -> EditorM (NonEmpty Point)
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM (NonEmpty Point) -> EditorM (NonEmpty Point))
-> BufferM (NonEmpty Point) -> EditorM (NonEmpty Point)
forall a b. (a -> b) -> a -> b
$ do
NonEmpty Point
points <- Region -> RegionStyle -> BufferM (NonEmpty Point)
deleteRegionWithStyleB Region
reg RegionStyle
style
Point -> BufferM ()
moveTo (Point -> BufferM ()) -> Point -> BufferM ()
forall a b. (a -> b) -> a -> b
$ NonEmpty Point -> Point
forall a. NonEmpty a -> a
NE.head NonEmpty Point
points
NonEmpty Point -> BufferM (NonEmpty Point)
forall (m :: * -> *) a. Monad m => a -> m a
return NonEmpty Point
points
(VimState -> VimState) -> EditorM ()
modifyStateE ((VimState -> VimState) -> EditorM ())
-> (VimState -> VimState) -> EditorM ()
forall a b. (a -> b) -> a -> b
$ \VimState
s -> VimState
s { vsSecondaryCursors :: [Point]
vsSecondaryCursors = NonEmpty Point -> [Point]
forall a. NonEmpty a -> [a]
NE.tail NonEmpty Point
points }
RegionStyle
_ -> BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ do
Point
point <- NonEmpty Point -> Point
forall a. NonEmpty a -> a
NE.head (NonEmpty Point -> Point)
-> BufferM (NonEmpty Point) -> BufferM Point
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Region -> RegionStyle -> BufferM (NonEmpty Point)
deleteRegionWithStyleB Region
reg RegionStyle
style
Point -> BufferM ()
moveTo Point
point
VimMode -> EditorM ()
switchModeE (VimMode -> EditorM ()) -> VimMode -> EditorM ()
forall a b. (a -> b) -> a -> b
$ Char -> VimMode
Insert Char
'c'
RepeatToken -> EditorM RepeatToken
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Continue
}
opFormat :: VimOperator
opFormat :: VimOperator
opFormat = VimOperator :: OperatorName
-> (Int -> StyledRegion -> EditorM RepeatToken) -> VimOperator
VimOperator {
operatorName :: OperatorName
operatorName = OperatorName
"gq"
, operatorApplyToRegionE :: Int -> StyledRegion -> EditorM RepeatToken
operatorApplyToRegionE = \Int
_count (StyledRegion RegionStyle
style Region
reg) -> do
BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ RegionStyle -> Region -> BufferM ()
formatRegionB RegionStyle
style Region
reg
VimMode -> EditorM ()
switchModeE VimMode
Normal
RepeatToken -> EditorM RepeatToken
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Finish
}
formatRegionB :: RegionStyle -> Region -> BufferM ()
formatRegionB :: RegionStyle -> Region -> BufferM ()
formatRegionB RegionStyle
Block Region
_reg = () -> BufferM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
formatRegionB RegionStyle
_style Region
reg = do
Point
start <- Point -> BufferM Point
solPointB (Point -> BufferM Point) -> Point -> BufferM Point
forall a b. (a -> b) -> a -> b
$ Region -> Point
regionStart Region
reg
Point
end <- Point -> BufferM Point
eolPointB (Point -> BufferM Point) -> Point -> BufferM Point
forall a b. (a -> b) -> a -> b
$ Region -> Point
regionEnd Region
reg
Point -> BufferM ()
moveTo Point
start
BufferM Bool -> BufferM () -> BufferM ()
forall a. BufferM Bool -> BufferM a -> BufferM ()
untilB_ ((Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) (Char -> Bool) -> BufferM Char -> BufferM Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> BufferM Char
readB) BufferM ()
rightB
Int
indent <- BufferM Int
curCol
(YiString -> YiString) -> Region -> BufferM ()
modifyRegionB (Int -> YiString -> YiString
formatStringWithIndent Int
indent) (Region -> BufferM ()) -> Region -> BufferM ()
forall a b. (a -> b) -> a -> b
$ Region
reg { regionStart :: Point
regionStart = Point
start
, regionEnd :: Point
regionEnd = Point
end
}
Point -> BufferM ()
moveTo (Point -> BufferM ()) -> BufferM Point -> BufferM ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Point -> BufferM Point
solPointB Point
end
BufferM ()
firstNonSpaceB
formatStringWithIndent :: Int -> YiString -> YiString
formatStringWithIndent :: Int -> YiString -> YiString
formatStringWithIndent Int
indent YiString
str
| YiString -> Bool
R.null YiString
str = YiString
R.empty
| Bool
otherwise = let spaces :: YiString
spaces = Int -> Char -> YiString
R.replicateChar Int
indent Char
' '
(YiString
formattedLine, YiString
textToFormat) = Int -> YiString -> (YiString, YiString)
getNextLine (Int
80 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
indent) YiString
str
lineEnd :: YiString
lineEnd = if YiString -> Bool
R.null YiString
textToFormat
then YiString
R.empty
else Char
'\n' Char -> YiString -> YiString
`R.cons` Int -> YiString -> YiString
formatStringWithIndent Int
indent YiString
textToFormat
in [YiString] -> YiString
R.concat [ YiString
spaces
, YiString
formattedLine
, YiString
lineEnd
]
getNextLine :: Int -> YiString -> (YiString, YiString)
getNextLine :: Int -> YiString -> (YiString, YiString)
getNextLine Int
maxLength YiString
str = let firstSplit :: (YiString, YiString)
firstSplit = (YiString, YiString) -> (YiString, YiString)
takeBlock (YiString
R.empty, (Char -> Bool) -> YiString -> YiString
R.dropWhile Char -> Bool
isSpace YiString
str)
isMaxLength :: (YiString, YiString) -> Bool
isMaxLength (YiString
l, YiString
r) = YiString -> Int
R.length YiString
l Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxLength Bool -> Bool -> Bool
|| YiString -> Bool
R.null YiString
r
in if (YiString, YiString) -> Bool
isMaxLength (YiString, YiString)
firstSplit
then (YiString, YiString)
firstSplit
else let (YiString
line, YiString
remainingText) = ((YiString, YiString) -> Bool)
-> ((YiString, YiString) -> (YiString, YiString))
-> (YiString, YiString)
-> (YiString, YiString)
forall a. (a -> Bool) -> (a -> a) -> a -> a
until (YiString, YiString) -> Bool
isMaxLength
(YiString, YiString) -> (YiString, YiString)
takeBlock
(YiString, YiString)
firstSplit
in if YiString -> Int
R.length YiString
line Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
maxLength
then ((Char -> Bool) -> YiString -> YiString
R.dropWhileEnd Char -> Bool
isSpace YiString
line, YiString
remainingText)
else let (YiString
beginL, YiString
endL) = YiString -> (YiString, YiString)
breakAtLastItem YiString
line
in if Char -> Bool
isSpace (Char -> Bool) -> Char -> Bool
forall a b. (a -> b) -> a -> b
$ Maybe Char -> Char
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Char -> Char) -> Maybe Char -> Char
forall a b. (a -> b) -> a -> b
$ YiString -> Maybe Char
R.head YiString
endL
then (YiString
beginL, YiString
remainingText)
else ((Char -> Bool) -> YiString -> YiString
R.dropWhileEnd Char -> Bool
isSpace YiString
beginL, YiString
endL YiString -> YiString -> YiString
`R.append` YiString
remainingText)
where
isMatch :: Maybe Char -> Char -> Bool
isMatch (Just Char
x) Char
y = Char -> Bool
isSpace Char
x Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> Bool
isSpace Char
y
isMatch Maybe Char
Nothing Char
_ = Bool
False
takeBlock :: (YiString, YiString) -> (YiString, YiString)
takeBlock (YiString
cur, YiString
rest) =
let (YiString
word, YiString
line) = (Char -> Bool) -> YiString -> (YiString, YiString)
R.span (Maybe Char -> Char -> Bool
isMatch (Maybe Char -> Char -> Bool) -> Maybe Char -> Char -> Bool
forall a b. (a -> b) -> a -> b
$ YiString -> Maybe Char
R.head YiString
rest) YiString
rest
in (YiString
cur YiString -> YiString -> YiString
`R.append` (Char -> Char) -> YiString -> YiString
R.map (\Char
c -> if Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\n' then Char
' ' else Char
c) YiString
word, YiString
line)
breakAtLastItem :: YiString -> (YiString, YiString)
breakAtLastItem YiString
s =
let y :: YiString
y = (Char -> Bool) -> YiString -> YiString
R.takeWhileEnd (Maybe Char -> Char -> Bool
isMatch (Maybe Char -> Char -> Bool) -> Maybe Char -> Char -> Bool
forall a b. (a -> b) -> a -> b
$ YiString -> Maybe Char
R.last YiString
s) YiString
s
(YiString
x, YiString
_) = Int -> YiString -> (YiString, YiString)
R.splitAt (YiString -> Int
R.length YiString
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- YiString -> Int
R.length YiString
y) YiString
s
in (YiString
x, YiString
y)
mkCharTransformOperator :: OperatorName -> (Char -> Char) -> VimOperator
mkCharTransformOperator :: OperatorName -> (Char -> Char) -> VimOperator
mkCharTransformOperator OperatorName
name Char -> Char
f = VimOperator :: OperatorName
-> (Int -> StyledRegion -> EditorM RepeatToken) -> VimOperator
VimOperator {
operatorName :: OperatorName
operatorName = OperatorName
name
, operatorApplyToRegionE :: Int -> StyledRegion -> EditorM RepeatToken
operatorApplyToRegionE = \Int
count StyledRegion
sreg -> do
BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$ StyledRegion -> (Char -> Char) -> BufferM ()
transformCharactersInRegionB StyledRegion
sreg
((Char -> Char) -> BufferM ()) -> (Char -> Char) -> BufferM ()
forall a b. (a -> b) -> a -> b
$ ((Char -> Char) -> (Char -> Char) -> Char -> Char)
-> (Char -> Char) -> [Char -> Char] -> Char -> Char
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (Char -> Char) -> (Char -> Char) -> Char -> Char
forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) Char -> Char
forall a. a -> a
id (Int -> (Char -> Char) -> [Char -> Char]
forall a. Int -> a -> [a]
replicate Int
count Char -> Char
f)
VimMode -> EditorM ()
switchModeE VimMode
Normal
RepeatToken -> EditorM RepeatToken
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Finish
}
mkShiftOperator :: OperatorName -> (Int -> Int) -> VimOperator
mkShiftOperator :: OperatorName -> (Int -> Int) -> VimOperator
mkShiftOperator OperatorName
name Int -> Int
countMod = VimOperator :: OperatorName
-> (Int -> StyledRegion -> EditorM RepeatToken) -> VimOperator
VimOperator {
operatorName :: OperatorName
operatorName = OperatorName
name
, operatorApplyToRegionE :: Int -> StyledRegion -> EditorM RepeatToken
operatorApplyToRegionE = \Int
count (StyledRegion RegionStyle
style Region
reg) -> do
BufferM () -> EditorM ()
forall (m :: * -> *) a. MonadEditor m => BufferM a -> m a
withCurrentBuffer (BufferM () -> EditorM ()) -> BufferM () -> EditorM ()
forall a b. (a -> b) -> a -> b
$
if RegionStyle
style RegionStyle -> RegionStyle -> Bool
forall a. Eq a => a -> a -> Bool
== RegionStyle
Block
then Int -> Region -> BufferM ()
indentBlockRegionB (Int -> Int
countMod Int
count) Region
reg
else do
Region
reg' <- Region -> RegionStyle -> BufferM Region
convertRegionToStyleB Region
reg RegionStyle
style
Int -> Region -> BufferM ()
shiftIndentOfRegionB (Int -> Int
countMod Int
count) Region
reg'
VimMode -> EditorM ()
switchModeE VimMode
Normal
RepeatToken -> EditorM RepeatToken
forall (m :: * -> *) a. Monad m => a -> m a
return RepeatToken
Finish
}
lastCharForOperator :: VimOperator -> String
lastCharForOperator :: VimOperator -> String
lastCharForOperator (VimOperator { operatorName :: VimOperator -> OperatorName
operatorName = OperatorName
name })
= case EventString -> [Event]
parseEvents (Text -> EventString
Ev (Text -> EventString)
-> (OperatorName -> Text) -> OperatorName -> EventString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OperatorName -> Text
_unOp (OperatorName -> EventString) -> OperatorName -> EventString
forall a b. (a -> b) -> a -> b
$ OperatorName
name) of
[] -> String -> String
forall a. HasCallStack => String -> a
error (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
"invalid operator name " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack (OperatorName -> Text
_unOp OperatorName
name)
[Event]
evs -> Text -> String
T.unpack (Text -> String) -> (Event -> Text) -> Event -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EventString -> Text
_unEv (EventString -> Text) -> (Event -> EventString) -> Event -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Event -> EventString
eventToEventString (Event -> String) -> Event -> String
forall a b. (a -> b) -> a -> b
$ [Event] -> Event
forall a. [a] -> a
last [Event]
evs