VimScript 执行搜索不再起作用

VimScript execute search does not work anymore

不知道从什么时候开始,我的视觉选择搜索功能不再起作用了。我将问题分解为这个最小的例子。

假设以下缓冲区:

word
word
word

当我运行/word时,我找到了所有结果并且可以在它们之间跳转。

当我 运行 :execute '/word' 这和以前一样工作。

当我编写一个简短的自动加载函数时,它只是做同样的事情,但它却不一样:

~/.config/nvim/autoload/utils/search.vim:

function! utils#search#visual_selection() abort
    execute '/word'
endfunction

执行:call utils#search#visual_selection()使光标停留在第一个结果上,但没有结果突出显示。此外,它使用旧的搜索模式而不是新的搜索模式。因此,如果我首先搜索 foo 等不存在的内容,然后执行此功能,按 n 会给我错误消息 Pattern not found: foo.

发生了什么变化。这里有什么区别?

这实际上是 Vim 和 NeoVim 的记录行为。它与 :execute 的使用并没有真正相关(您可以直接使用 /word 重现它),但与搜索(和重做)在函数中的工作方式有关。

参见 :help function-search-undo,其中指出:

The last used search pattern and the redo command "." will not be changed by the function. This also implies that the effect of :nohlsearch is undone when the function returns.

您可以通过显式设置 search pattern register 来解决这个问题,您可以使用 let 命令来完成。

function! utils#search#visual_selection()
    let @/ = 'word'
    execute "normal /\<cr>"
endfunction

第二个命令从正常模式执行一个简单的 /,这足以搜索单词,因为它将查找现在设置为您想要的最后一个搜索模式。

函数完成后,搜索模式将保持其值,这意味着通过 'hlsearch' 突出显示将起作用,n 命令也将找到下一个匹配项。


上述方法的一个限制是您不能真正设置 n 重复的搜索方向。即使可以设置 v:searchforward,该变量也会在作为 :help function-search-undo 效果的一部分的函数后重置。对于那个你似乎无能为力...

如果此函数的目的是用于键映射,您可能会考虑一种完全不同的方法,使用 nnoremap <expr> 并使用函数 return 作为搜索的正常模式命令一个字符串,这样实际搜索发生在函数之外,function-search-undo 的限制将不适用。

例如:

function! utils#search#visual_selection(searchforward)
    let pattern = 'word'
    if a:searchforward
        let dir = '?'
    else
        let dir = '/'
    endif
    return dir.pattern."\<cr>"
endfunction

然后:

" Mappings for next-word and previous-word
nnoremap <expr> <leader>nw utils#search#visual_selection(1)
nnoremap <expr> <leader>pw utils#search#visual_selection(0)

这完全避免了 :help function-search-undo 的问题,因此如果可能的话,请考虑类似这种方法。