众所周知,evil 会自动把被删除的文本复制到 register 里,那么想要把替换一段文本又不想把被删除掉的文本写入 register 里(说人话就是只想删除文本不想剪切),这样就能够持续的把一段文本替换到多处。如果不想用任何插件,想通过 vim 命令来直接解决的办法就是先选中文本然后再输入命令"ay
,也就是通过把这段文本复制到 a
寄存器里,然后对于想要替换的文本要先选中,然后再输入 "ap
也就是把寄存器 a 里的文本替换这段选中的文本。
以上的操作看着就知道有多麻烦,在之前我是使用 evil-replace-with-register
插件来解决这个问题,这个插件提供了一个命令绑定到 gr
从而可以实现类似其他常用 vim 命令的方便的操作方式,比如 yiw
复制了一个单词以后,就可以一直不停的 griw
(当然也是 dot-repeatable 的)去替换你想要替换掉的单词,而不必担心被删除掉的文本被剪切了。
但是这个命令对于 visual block 的实现不太友好,简单来说他没办法做到以下的情形:
aa ee
bb gg
cc hh
没办法通过块选择以及块替换把以上的文本替换成
aa aa
bb bb
cc cc
原因在于 这个插件处理 block 情形时没有调用 evil 的原生api,选择自己逐行处理的,因此没办法处理这种替换文本和被替换的区域都是个整体的情形。
其实调用 evil 的原生 api 能非常简单的解决这个问题,我写了一个简单的代码就解决了 block 的场景,同时对于更加常用的 line-wise 模式和 char-wise 模式的支持也没有问题。
(evil-define-operator evil-replace-with-register (count beg end type register)
"Replacing an existing text with the contents of a register"
:move-point nil
(interactive "<vc><R><x>")
(setq count (or count 1))
(if (eq type 'block)
(evil-visual-paste count register)
(delete-region beg end)
(evil-paste-before count register)))