Emacs Evil 模式:如何创建一个新的文本对象来选择任意非空格字符的单词?

11

我正在尝试在Evil中创建一个新的文本对象。例如,文本对象iw只会选择包含连字符的子字符串。我希望新的文本对象能匹配任何非空格字符组成的单词。目前为止,我得到的是:

(evil-define-text-object evil-inner-space (count &optional beg end type)
  "Select inner space."
  :extend-selection nil
  (evil-regexp-range count beg end type "[ \n]" " " t))

(define-key evil-inner-text-objects-map " " 'evil-inner-space)

这段代码无法正确匹配行末的单词。由于有`\ n`,它可以匹配行首的单词。

我尝试了很多事情,但都没有成功。对我来说麻烦的是,当某些事情不起作用时,我不知道是由于错误的正则表达式还是Evil-regexp-range的限制。例如,使用`\s-`会报错,这似乎是Evil的限制。

3个回答

21
更新: evil-regexp-range 最近被替换为 evil-select-paren。这适用于当前的 evil,并且与旧版具有相同的用法:
(defmacro define-and-bind-text-object (key start-regex end-regex)
  (let ((inner-name (make-symbol "inner-name"))
        (outer-name (make-symbol "outer-name")))
    `(progn
       (evil-define-text-object ,inner-name (count &optional beg end type)
         (evil-select-paren ,start-regex ,end-regex beg end type count nil))
       (evil-define-text-object ,outer-name (count &optional beg end type)
         (evil-select-paren ,start-regex ,end-regex beg end type count t))
       (define-key evil-inner-text-objects-map ,key (quote ,inner-name))
       (define-key evil-outer-text-objects-map ,key (quote ,outer-name)))))

如果你需要定义多个文本对象的话,重复操作可能会变得烦人,特别是当你想要绑定内部和外部对象时。如果你遇到这种情况,请尝试以下方法:
(defmacro define-and-bind-text-object (key start-regex end-regex)
  (let ((inner-name (make-symbol "inner-name"))
        (outer-name (make-symbol "outer-name")))
    `(progn
      (evil-define-text-object ,inner-name (count &optional beg end type)
        (evil-regexp-range count beg end type ,start-regex ,end-regex t))
      (evil-define-text-object ,outer-name (count &optional beg end type)
        (evil-regexp-range count beg end type ,start-regex ,end-regex nil))
      (define-key evil-inner-text-objects-map ,key (quote ,inner-name))
      (define-key evil-outer-text-objects-map ,key (quote ,outer-name)))))

使用方法:

; between dollar signs:
(define-and-bind-text-object "$" "\\$" "\\$")

; between pipe characters:
(define-and-bind-text-object "|" "|" "|")

; from regex "b" up to regex "c", bound to k (invoke with "vik" or "vak"):
(define-and-bind-text-object "k" "b" "c")

(这里提供的内容可能超出您的需求,但如果有助于他人,我会保留下来 :))

1
谢谢你!我经常发现自己希望有一个文本对象,例如匹配C++声明而不需要括号--例如匹配 _foo::bar::baz_(),包括 : 但忽略 ()。你的解决方案使这变得非常容易:(define-and-bind-text-object "k" "[[:space:]\(\)]" "[[:space:]\(\)]")。非常感谢! - Kevin Ushey
1
看起来 evil-regexp-range 已经从最新版本的 Evil 中删除了 -- 我相信现在我们需要使用 evil - Kevin Ushey

10

我认为您不需要创建新的文本对象。Evil已经包含符号文本对象。符号语法是由主模式定义的,通常包括连字符、数字、下划线和其他非空格字符。

符号文本对象绑定到o。定义在Bitbucket的evil-maps.el中。


1
嗯,我正在寻找的文本对象确实在vim/evil中实现了,但正如@PythonNut在评论中所说,它绑定到W。对于某些情况,这种实现比我发布的正则表达式更有效。 - Lionel Henry
Lionel是正确的,这并不完全回答了问题 - 但o非常有用,谢谢JoeS! - Croad Langshan

1
正确的正则表达式是“ \|.?$”。以下代码实现了一个匹配任何非空格字符的新文本对象。
(evil-define-text-object evil-inner-space (count &optional beg end type)
  "Select inner space."
  :extend-selection nil
  (evil-regexp-range count beg end type "[ \n]" " \\|.?$" t))

2
我会补充当前的“恶意”已经与内部WORD文本对象绑定到“i W”。 - PythonNut
哈哈,我在网上搜索没有找到这个... 我应该有一天去看一下 Vim 手册。谢谢 - Lionel Henry
1
如其他答案所述:evil-regexp-range已被替换为evil-select-paren - Hi-Angel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接