13
13
14
14
module Yi.Keymap.Vim.VisualMap ( defVisualMap ) where
15
15
16
- import Lens.Micro.Platform ((.=) )
17
- import Control.Monad (forM_ , void )
16
+ import Lens.Micro.Platform ((.=) )
17
+ import Control.Monad (forM_ , void , when )
18
18
import Data.Char (ord )
19
19
import Data.List (group )
20
20
import Data.Maybe (fromJust , fromMaybe )
@@ -27,10 +27,10 @@ import Yi.Keymap.Vim.StateUtils
27
27
import Yi.Keymap.Vim.StyledRegion (StyledRegion (StyledRegion ), transformCharactersInRegionB )
28
28
import Yi.Keymap.Vim.Tag (gotoTag )
29
29
import Yi.Keymap.Vim.TextObject
30
- import Yi.Keymap.Vim.Utils (matchFromBool , mkChooseRegisterBinding , mkMotionBinding , addNewLineIfNecessary )
30
+ import Yi.Keymap.Vim.Utils (matchFromBool , mkChooseRegisterBinding , mkMotionBinding , addNewLineIfNecessary , pasteInclusiveB )
31
31
import Yi.MiniBuffer (spawnMinibufferE )
32
32
import Yi.Monad (whenM )
33
- import qualified Yi.Rope as R (toText )
33
+ import qualified Yi.Rope as R (toText , countNewLines )
34
34
import Yi.Tag (Tag (Tag ))
35
35
import Yi.Utils (SemiNum ((-~) ))
36
36
@@ -230,39 +230,72 @@ replaceBinding = VimBindingE (f . T.unpack . _unEv)
230
230
region <- withCurrentBuffer regionOfSelectionB
231
231
withCurrentBuffer $ transformCharactersInRegionB (StyledRegion style region)
232
232
(\ x -> if x == ' \n ' then x else c)
233
- escAction
233
+ void escAction
234
234
return Finish
235
235
_ -> NoMatch
236
236
f _ _ = NoMatch
237
237
238
+
239
+ data VisualPaste
240
+ = PasteBefore
241
+ | ReplaceSelection
242
+ deriving (Eq , Ord , Show )
243
+
238
244
pasteBinding :: VimBinding
239
245
pasteBinding = VimBindingE (f . T. unpack . _unEv)
240
246
where
241
- f " p" (VimState { vsMode = (Visual style) }) = WholeMatch $ do
247
+ f " P" VimState { vsMode = (Visual style) } = pasteMatch style PasteBefore
248
+ f " p" VimState { vsMode = (Visual style) } = pasteMatch style ReplaceSelection
249
+ f _ _ = NoMatch
250
+
251
+ pasteMatch :: RegionStyle -> VisualPaste -> MatchResult (EditorM RepeatToken )
252
+ pasteMatch style p = WholeMatch $ do
242
253
register <- getRegisterE . vsActiveRegister =<< getEditorDyn
243
- case (register, style) of
244
- (Just (Register _style rope), LineWise ) -> withCurrentBuffer $ do
245
- region <- regionOfSelectionB
246
- _ <- deleteRegionWithStyleB region LineWise
247
- insertRopeWithStyleB (addNewLineIfNecessary rope) LineWise
248
- (Just (Register Block rope), Block ) -> withCurrentBuffer $ do
249
- here <- pointB
250
- there <- getSelectionMarkPointB
251
- (here', there') <- flipRectangleB here there
252
- reg <- regionOfSelectionB
253
- void $ deleteRegionWithStyleB reg Block
254
- moveTo (minimum [here, there, here', there'])
255
- insertRopeWithStyleB rope Block
256
- (Just (Register _ _), Block ) ->
257
- printMsg " Pasting non-block string into a block selection is not implemented"
258
- (Just (Register _style rope), _) -> withCurrentBuffer $ do
259
- region <- regionOfSelectionB
260
- region' <- convertRegionToStyleB region Inclusive
261
- replaceRegionB region' rope
262
- _ -> pure ()
263
- escAction
254
+ maybe (pure () ) (paste style p) register
255
+ void escAction
264
256
return Finish
265
- f _ _ = NoMatch
257
+
258
+ paste :: RegionStyle -> VisualPaste -> Register -> EditorM ()
259
+ paste LineWise = linePaste
260
+ paste Block = blockPaste
261
+ paste Inclusive = otherPaste
262
+ paste Exclusive = otherPaste
263
+
264
+ linePaste :: VisualPaste -> Register -> EditorM ()
265
+ linePaste p (Register _style rope) = withCurrentBuffer $ do
266
+ region <- regionOfSelectionB
267
+ when (p == ReplaceSelection ) . void $ deleteRegionWithStyleB region LineWise
268
+ insertRopeWithStyleB (addNewLineIfNecessary rope) LineWise
269
+
270
+ blockPaste :: VisualPaste -> Register -> EditorM ()
271
+ blockPaste p (Register _style rope) = withCurrentBuffer $ do
272
+ here <- pointB
273
+ there <- getSelectionMarkPointB
274
+ (here', there') <- flipRectangleB here there
275
+ reg <- regionOfSelectionB
276
+ moveTo (minimum [here, there, here', there'])
277
+ when (p == ReplaceSelection ) . void $ deleteRegionWithStyleB reg Block
278
+ if R. countNewLines rope == 0
279
+ then actionOnLeft reg $ maybe (pure () ) (\ _ -> insertRopeWithStyleB rope _style)
280
+ else pasteInclusiveB rope _style
281
+ where
282
+ -- Taken from deleteRegionWithStyleB
283
+ actionOnLeft :: Region -> (Maybe Point -> BufferM () ) -> BufferM ()
284
+ actionOnLeft reg action = savingPointB $ do
285
+ (start, lengths) <- shapeOfBlockRegionB reg
286
+ moveTo start
287
+ forM_ (zip [0 .. ] lengths) $ \ (i, l) -> do
288
+ p' <- pointB
289
+ moveTo start
290
+ void $ lineMoveRel i
291
+ action (if l == 0 then Nothing else Just p')
292
+
293
+ otherPaste :: VisualPaste -> Register -> EditorM ()
294
+ otherPaste _ (Register _style rope) = withCurrentBuffer $ do
295
+ region <- regionOfSelectionB
296
+ region' <- convertRegionToStyleB region Inclusive
297
+ replaceRegionB region' rope
298
+
266
299
267
300
switchEdgeBinding :: VimBinding
268
301
switchEdgeBinding = VimBindingE (f . T. unpack . _unEv)
@@ -305,7 +338,7 @@ tagJumpBinding = VimBindingY (f . T.unpack . _unEv)
305
338
= WholeMatch $ do
306
339
tag <- Tag . R. toText <$> withCurrentBuffer
307
340
(regionOfSelectionB >>= readRegionB)
308
- withEditor escAction
341
+ void $ withEditor escAction
309
342
gotoTag tag 0 Nothing
310
343
return Finish
311
344
f _ _ = NoMatch
0 commit comments