在向前或向后移动单词时跳过标点符号的设置

8
当我使用vim时,通常情况下,当我按下w或b向前或向后移动时,我不想移动到标点符号。因此,我想知道是否有一种设置或功能可以更改这种行为?
例如,如果我有如下代码:
object.method(args)
并且我的光标在“object”中的[o]处,则我希望w将光标移动到“method”中的[m]处,再按一次w将光标移动到“args”中的[a]处。我不希望它停留在“.”或“(”处。如果我想要移动到标点符号,我通常会使用f或F来直接跳转到它。我从未想过在移动单词时移动到标点符号,现在意识到这真的很烦人。

我不知道是否有更好的解决方案,但如果您不介意更改 @/ 的内容,您可以随时键入 /\<\w。或者,如果您经常使用它,可以创建一个映射到该命令的快捷方式。 - sidyll
请查看 https://dev59.com/JHVC5IYBdhLWcg3wpS7g。 - borrible
1
@yoda:我又想到了一个点子。如果有一个命令像_/这样的,可以搜索但不包括模式在@/寄存器中,那会怎么样呢?嗯,如果Vim缺少这个功能,那肯定是值得研究并创建可能的补丁的有趣事情。 - sidyll
@sidyll:我喜欢你的解决方案,使用/\<\w移动光标非常方便,但一个烦人的问题是当你开启了高亮显示时,它会突出显示所有要移动到的单词。 - user616736
@borrible:不幸的是,更改iskeyword不会解决问题。这只能使w的行为像W。 - Tub
显示剩余3条评论
2个回答

6

我也认为我想要一个更加包容的运动,比起 w 更加包容,但不如 W 那么宽泛。特别地,我想要一个只考虑以字母或数字字符开头的标记(token)为有效的运动。

因此,我提出了以下建议:

" <SPACE>   : forward to next word beginning with alphanumeric char
" <S-SPACE> : backward to prev word beginning with alphanumeric char
" <C-SPACE> : same as above (as <S-SPACE> not available in console Vim
" <BS>      : back to prev word ending with alphanumeric char
function! <SID>GotoPattern(pattern, dir) range
    let g:_saved_search_reg = @/
    let l:flags = "We"
    if a:dir == "b"
        let l:flags .= "b"
    endif
    for i in range(v:count1)
        call search(a:pattern, l:flags)
    endfor
    let @/ = g:_saved_search_reg
endfunction
nnoremap <silent> <SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'f')<CR>
vnoremap <silent> <SPACE> :<C-U>let g:_saved_search_reg=@/<CR>gv/\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let @/=g:_saved_search_reg<CR>gv
nnoremap <silent> <S-SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'b')<CR>
vnoremap <silent> <S-SPACE> :<C-U>let g:_saved_search_reg=@/<CR>gv?\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let @/=g:_saved_search_reg<CR>gv
nnoremap <silent> <BS> :call <SID>GotoPattern('[A-Za-z0-9_]\(\>\\|$\)', 'b')<CR>
vnoremap <silent> <BS> :<C-U>let g:_saved_search_reg=@/<CR>gv?[A-Za-z0-9_]\(\>\\|$\)<CR>:<C-U>let @/=g:_saved_search_reg<CR>gv

" Redundant mapping of <C-SPACE> to <S-SPACE> so that
" above mappings are available in console Vim.
"noremap <C-@> <C-B>
if has("gui_running")
    map <silent> <C-Space> <S-SPACE>
else
    if has("unix")
        map <Nul> <S-SPACE>
    else
        map <C-@> <S-SPACE>
    endif
endif

我已经使用这个技巧很长时间了,我发现在编码时,我使用<SPACE>/<C-SPACE>的移动方式比使用wW更加频繁;它似乎更有用。当然,你可以将命令映射到任何你觉得有用或更合适的键上。


1
谢谢@Jeet。在小测试中,那个效果非常好。我想知道你是否可以编写一个额外的映射,像“e”一样跳到单词的末尾,但只考虑字母数字字符。 - Tub
@Tub:这个映射与 <SPACE>e 有什么不同的行为吗? - Jeet

2
即使冒着为内置功能创建脚本的风险(如上次所做的那样),这里有一个小函数可以帮助实现此目标。请参考以下内容:(链接)
function! JumpToNextWord()
    normal w
    while strpart(getline('.'), col('.')-1, 1) !~ '\w'
        normal w
    endwhile
endfunction

基本上,它的作用是执行标准的 w 命令,并在光标下的字符不是单词字符时重复执行该命令(可以随意更改该模式)。
如果您在.vimrc中添加这个小映射:
nnoremap <silent> ,w :call JumpToNextWord()<CR>

它应该可以正常工作。


谢谢@yoda,我已经更新了它以匹配答案而不是问题。那个答案很糟糕,但我决定把它留在那里 :-) - sidyll
嗨,sidyll,我喜欢这个解决方案。不知道你能否让它在可视模式下工作(以便可以扩展可视选择)。 - Jeet
@sidyll:如果它能够完成任务,简单永远是更好的选择!这就是为什么我喜欢你的解决方案。但是,不幸的是,如果要成为 Vim 生态系统的一部分,对于任何移动操作来说,支持可视化模式相当重要。我会看看能否让你的方法在可视化模式下工作。 - Jeet
谢谢@Jeet,是的,可视化模式也很重要。好的,如果你想出了解决方案,请将其添加到你的答案中! - sidyll
我喜欢这个解决方案。但是,如果缓冲区为空,会出现无限循环。所以你必须小心 :) - Lev Sivashov
显示剩余2条评论

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