虽然evil-search的regex超棒,但是有的时候还是直接region选中了直接搜索方便,比如我想用cgn
替换的时候。
效果:
- 选中region
- 按
/
进入evil-search - 选中的字符自动成为搜索字符
网上有isearch
的解决方案,但是没法复制到evil-search
。请问有没有人造过轮子了?
虽然evil-search的regex超棒,但是有的时候还是直接region选中了直接搜索方便,比如我想用cgn
替换的时候。
效果:
/
进入evil-search网上有isearch
的解决方案,但是没法复制到evil-search
。请问有没有人造过轮子了?
(when (evil-visual-state-p)
(let ((evil-ex-search-history `(,(buffer-substring (region-beginning) (region-end)))))
(evil-normal-state)
(evil-ex-search-forward)))
hacky but works。我感觉用处不大啊,用C-r C-w
或者 ivy的C-w
方便一些
绑定到/
吗?我待会看看能不能写成advice
evil-search 最终也是调用 isearch
差点忘了这回事了……我是这么写的:
(defun moon-put-region-in-search-history (count)
"Put region into evil-search history.
COUNT is passed to evil-search command."
(when (evil-visual-state-p)
(let ((region (buffer-substring-no-properties
;; evil seems to treat point differently,
;; so I added 1 to end point
(region-beginning) (1+ (region-end)))))
(push region evil-ex-search-history)
(setq evil-ex-search-pattern (evil-ex-make-search-pattern region))
;; (push region evil-ex-s)
(evil-normal-state)
)))
(advice-add 'evil-ex-search-forward :before #'moon-put-region-in-search-history)
@amosbird 谢谢你的指点
这行比较关键:
(setq evil-ex-search-pattern (evil-ex-make-search-pattern region))
更新evil-ex-search-pattern
才能让gn
指向选中的region。
最终的效果是:
当然可以吧这个advice做成command绑定到一个键上,就不用/再esc按两个键了。
一直以为 evil-ex-search
是 evil-search
的增强版,没想到是不同的实现。
如果用 evil-search
,就可以共享 isearch
的 advice 了。
evil-ex-search
支持一些evil的text-object(具体名字不清楚),
比如next-match。
所以想用gn
motion就要用evil-ex-search
visual-state里面(region-end)
返回的结果似乎跟emacs下直接运行的不太一样
M-x eval-expression (region-end)
返回的point,比我在我的函数里(message (region-end))
打印的多一位。
advice 放到 evil-ex-start-search
之前比较好,这样 forward/backward 都能用了。
我这里不需要这一行。
考虑到 region 之后可能还要编辑,对于无需编辑的搜索,可以绑定到 * / # :
(define-key evil-motion-state-map "#" #'evil-search-symbol-or-region-backward)
(define-key evil-motion-state-map "*" #'evil-search-symbol-or-region-forward)
...
(defun evil-search-symbol-or-region-backward ()
(if (evil-visual-state-p)
... ;; search region text
... ;; search symbol at point))
这个现象我很早就注意到了,算是 evil 的 “feature“ 吧。因为 visual 模式下的 region,其 region-end 位置实际上是光标所在字符之前,我们按 y
能复制到期望的字符,应该是 evil 做了处理。但是 buffer-substring-no-properties 的实现是并不关心 evil 的。
visual 模式下选中了:
|<------>|
some-tex[t]
实际上是相当于 insert / emacs 模式下:
|<----->|
some-tex|t
要想获得正确的 region,光标位置必须再 forward 一个字符:
|<------>|
some-text|
绑定*/#挺好的,不过直接绑定函数没法处理count,比如3#。
我还是比较喜欢advice的路线,这样可以处理count:
(defun moon-evil-ex-search-word-backward-advice (old-func count &optional symbol)
(if (evil-visual-state-p)
(let ((region (buffer-substring-no-properties
(region-beginning) (1+ (region-end)))))
(setq evil-ex-search-pattern region)
(deactivate-mark)
(evil-ex-search-full-pattern region count 'backward))
(apply old-func count symbol)))
...
(advice-add #'evil-ex-search-word-backward :around #'moon-evil-ex-search-word-backward-advice)
hmm, 你这个需求可以试试 evil-multiedit 。 iedit的 iedit-show/hide-unmatched-lines
第一次用惊艳到我了
evil-multiedit挺不错的,不过多光标有一个问题就是有可能选中多余的文本。用多光标搜索替换经常要手动修改,不如一个个替换方便灵活。
具体可以看这篇文章:
编辑还是要多种手段并用,像 cgn
.
这样的操作无法中途跳过一/多个匹配项。
另外,把 region 压入 evil-ex-search-history 也不是很好的方法:
没有立即搜索。按下 / 的时候,虽然 region 内容出现在搜索提示符后面,但是并没有立即搜索并高亮匹配的项,而是要 esc / enter 退出,再按 n 或其它操作才能看到效果。
无法编辑关键字。例如当我选中 fooba 进行搜索,发现漏了一个字符,想要补全。一按键就会触发删除的 hook,把 history 清空。
想跳过匹配项的话按n就可以了。
第一条挺有意思的,我可以看看evil是怎么高亮的然后修改一下我的advice,看看能不能实现。
你说的第二点比较难搞,没法用advice/hook添加,我能想到的只有重写evil-ex-search的实现。 如果需要的话可以按C-p自动输入上一个历史再修改。也不算太麻烦。
失察了,n 确实不会影响 . 操作
后边 1、2 那两个问题我这个函数解决了:
(defun evil-ex-start-search-with-region-string ()
(let ((selection (with-current-buffer (other-buffer (current-buffer) 1)
(when (evil-visual-state-p)
(let ((selection (buffer-substring-no-properties (region-beginning)
(1+ (region-end)))))
(evil-normal-state)
selection)))))
(when selection
(evil-ex-remove-default)
(insert selection)
(evil-ex-search-activate-highlight (list selection
evil-ex-search-count
evil-ex-search-direction)))))
(advice-add 'evil-ex-search-setup :after 'evil-ex-start-search-with-region-string)
没太懂,原版evil /
n
*
里哪些是evil-search
,哪些是evil-ex-search
?我因为把w
b
都改成对symbol操作所以*
是这个:
(defun jjpandari/evil-search-symbol-forward ()
"Search forward for symbol under point."
(interactive)
(evil-ex-search-word-forward 1 t)
)
是不是避免了你们这个问题?
虽然直接调用 evil-ex-search-XXX
函数是不会有问题,但 n
和其它操作操作仍然绑定 isearch
行为,相当于临时地执行了一次 evil-ex-search
,所以不能连贯地使用 motion,有一点点混乱。
正确的设置是:
(evil-select-search-module 'evil-search-module 'evil-search)
然后 /
搜索,退出,再 gn
就可以跳至下个匹配点,isearch
没这个效果。
选了 evil-search
作为 search-module 了之后,没有参数的 XXX-search-symbol-forward
函数就不能绑定到 *
/#
,会出错。
我是定义了新的函数,相当于抄了一遍 evil-ex-search-word-forward
函数,只把函数最末一句从 symbol
改为固定值 t
:
(evil-define-motion evil-ex-search-symbol-forward (count &optional symbol)
"Search for the next occurrence of symbol under the cursor."
:jump t
:type exclusive
(interactive (list (prefix-numeric-value current-prefix-arg)
evil-symbol-word-search))
(evil-ex-start-word-search nil 'forward count t))
(define-key evil-motion-state-map "*" #'evil-ex-search-symbol-forward)