通过名称切换到VIM窗口

10

有一些优秀的Vim插件可以通过键入部分名称来切换到特定的文件缓冲区,但是是否有像这些插件一样的插件能够快速地在打开的窗口之间进行切换呢?

例如,如果我在一个vsplit窗格中有名为'a.txt'的文件,在另一个窗格中有名为'b.txt'的文件,我希望能够通过键入文件名(或仅输入'a'或'b'进行增量搜索)来在它们之间进行快速切换。对于两个窗口来说可能用处不大,但我通常会打开多达5个窗口,因此使用正常的导航按钮在它们之间进行切换可能很麻烦。

WinWalker似乎支持这种类型的功能,但是包含在一个更大的窗口导航框架中。


1
你真的会同时查看所有窗口吗?使用内置的:b part-of-file-name可以让你走得更远,我更喜欢使用它(实际上我主要使用标签页),而不是打开太多窗口。有时候程序应该适应我们,有时候我们应该适应它们 :) - Jonatan Littke
(我不知道你问题的答案,只是想放大一下视角) - Jonatan Littke
通常我会同时打开两个文件,它们通常被分成两部分,这样我就可以在处理另一个文件时参考文件的某些部分。然后我会有另一个窗口显示我的标签,最后是一个文件树。 - Zack L
只是为了补充一下,我在我的vimrc中有这个设置:noremap <silent> ,h :wincmd h<CR> ,以及后面的3个设置。 - sidyll
6个回答

6
如果您在vimrc中设置了:setswitchbuf+=useopen,那么:b命令会高兴地执行。它支持文件名自动补全,例如使用Ctrl-D

来自#vim的MarcWeber等人


6
不适用于:b命令,但适用于:sbuffer命令,例如:sbuffer NAME,其中NAME是要跳转到的缓冲区名称。它也可以使用部分匹配的NAME - Jasha

3

对于我来说,@Aaron Thoma的switchbuf+=useopen设置无效。实际上,文档中没有提到该设置被:b命令支持。

我使用了以下代码片段:

let windowNr = bufwinnr(pattern)
if windowNr > 0
  execute windowNr 'wincmd w'
endif  

查看 bufwinnr() 函数的文档


只是补充一下,这不是替换当前缓冲区,而是转到相关的打开窗口,这正是问题中指定的。 - G Eitan

2

在尝试实现同样的功能后,我想出了这个小函数。

function! ActivateWindowByName(name)
    let l:bufid = bufnr(a:name)
    let l:winids = win_findbuf(l:bufid)
    call win_gotoid(l:winids[0])
endfunction

解释:

  • bufnr('substring-of-buffer-name')返回缓冲区编号
  • win_findbuf(buffer_number)返回使用与buffer_number标识的缓冲区的窗口ID列表(不同于缓冲区编号)
  • win_gotoid(window_ID)转到使用window_ID标识的窗口,该窗口可以位于当前选项卡页之外

bufnr不能保证找到缓冲区,因此可能会返回-1。 在这种情况下,win_findbuf将找到一个空列表,并且[0]将超出范围。


我正在使用VIM 7.4,但我没有win_findbuf和win_gotoid。 - G Eitan

0

我不知道如何根据文件名切换到一个窗口,但我在我的.vimrc中使用以下快捷键在窗口之间移动。

noremap <S-W> <C-w><Up>
noremap <S-S> <C-w><Down>
noremap <S-A> <C-w><Left>
noremap <S-D> <C-w><Right>

这些很简单,我从来不会打开超过4个窗口,所以任何一个窗口都不会超过2步。而且,你无需键入文件名。

我使用标准的FPS移动键 wasd 在窗口之间移动,因为它对我来说非常直观,我不必转换到箭头键 -- 小拇指在Shift键上,其他三个手指放在字母上。您可以根据自己的喜好更改它们(hjkl是一个不错的选择)。

我更喜欢使用Shift代替Ctrl/Alt/Option/Cmd,因为键盘之间的位置和大小不同(例如,在Macbook Pro上,Fn是最左边的键,而在全尺寸的Mac键盘上,Ctrl是最左边的键),我在Linux上遇到了vim无法识别Cmd键的问题。


4
你不需要使用 <S-,因为 WSAD 应该完全可以胜任。并且请使用 nnoremap:1) 你不需要在操作符待定模式下执行此行为,也可能不需要在可视和选择模式下执行;2) 你不知道操作员是否已经重新映射了 <C-w> 到其他窗口处理操作。 - ZyX
没错。按目前的情况,你不需要 <S-。这只是我.vimrc进化过程中的奇怪方式。我甚至不记得它们何时变成了大写字母。至于第二点,<C-w>是窗口移动的默认方式。如果OP已经重新映射了它,那么他/她应该相应地进行调整。 - user616736
如果在map之前添加nore,那么您将使解决方案能够正常工作,无论OP是否重新映射它。建议调整是不好的:采用这种方法可能会导致相互依赖的映射,因此删除或更改其中一个映射将导致调试困难。 - ZyX
@yoda:既然您同意ZyX的观点,为什么不编辑您的答案以反映这一点?希望您不介意我代为修改。 - Aaron Thoma
1
@accolade 谢谢。那时我还是新手,对规约不太了解 :) 我已经批准了你的编辑。 - user616736

0

这个使用Python API,所以你只能在Vim中使用它,但我相信喜欢Vim脚本的人可以很容易地将其转换。

像这样使用:

:WSeek win
:WSeek READ
:WSeek README
:WSeek a.
etc.

很抱歉,没有自动完成功能。

" Call using:
" :source window-swap.vim or put in plugins dir

function! WSeek(target) 
  if !has('python')
    echo "Error: this plugin requires vim with +python"
    finish
  else
python << EOF

import vim

target = vim.eval("a:target")
found = False
for i in range(0, len(vim.windows)):
  vim.command(str(i+1) + "wincmd w")
  bits = vim.current.buffer.name.split("/")
  bits = bits[-1]
  if (bits.startswith(target)):
    found = True
    break

# Go back to the start on no match
if not found:
  vim.command("1wincmd w")

EOF
  endif
endfunction 

command! -nargs=1 WSeek :call WSeek(<q-args>)

1
奇怪的命令:vim.command("exe 1 . \"wincmd w\"")。这里不需要在 eval 内部执行 eval,只需使用 vim.command("1wincmd w") - ZyX
与上面相同:vim.command(str(i+1)."wincmd w")。你实际上做的与 execute "execute ".(i+1).".\"wincmd w\"" 等效。看起来很奇怪,不是吗? - ZyX
^_^!哦是的,好主意。根据@ZyX的神奇之处进行了编辑解决方案。 :) - Doug

-1

我建议使用Command-T插件。它可以索引当前文件夹(及其子文件夹)中的文件,并允许您键入文件名的一部分来打开它。在我的 .vimrc 文件中,我还添加了这个链接:

nnoremap <S-F12> :CommandT<CR>

这样我按Shift-F12键,然后输入文件名来打开它。

希望能有所帮助。


1
我在原帖中链接了CommandT。它绝对非常有用(也是我想要这个功能的一部分),但那只是用于在特定缓冲区中加载文件,而不是切换到另一个已存在的窗口。 - Zack L
是的,没错,但对你来说有什么区别呢?刚开始我也是这么想的,但后来我问自己,通过缓冲区列表打开缓冲区与通过文件列表打开缓冲区的区别在哪里?毕竟它已经打开了,会自动切换到该缓冲区。不要太过于追求完美啦 :-) - Rafid

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