赞
踩
上周偶然读到了这篇 Vim Tab Madness. Buffers vs Tabs。这是一篇关于 Vim 中 Buffer、Window 和 Tab 的外文资料,文中关于这三者关系的解释非常详细且容易理解,作者在最后还分享了自己的 Vim 使用经验。这篇文章对我有不小的启发,不过原文作者的使用习惯跟博主本人还是有些差异,故作此文,谈一谈我对 Vim 中这三个容易导致混乱的概念的理解。本文跟原文内容上有相似之处,但并不是对原文的翻译,推荐有阅读外文资料习惯的读者读一读原文。废话不多说,咱们进入正题。
Vim 中的 Buffer、Window 和 Tab 是非常容易混淆的三个概念,相信初学者或多或少有类似以下的经历:
split
命令创建了一个分屏,可是切换 Tab 的时候居然不见了!尤其是当你装了类似于 vim-airline 或者 MiniBufExpl 这样的 “Tab” 显示工具,那就更容易被迷惑了。更有甚者,把不同人的配置一起复制到自己的 vimrc 里面,混合使用的时候整个界面就混乱了…
这三者总是让人傻傻分不清楚,尤其是在没有深入理解这些概念的时候就接触 tabnew、tabnext、tabprevious、bnext、bprevious、split、vsplit… 等一系列命令和缩写,胡乱使用的话稍不注意就会导致整个编辑器界面混乱,开始怀疑人生,最后不得不 :q<CR>
关掉编辑器重头再来,并默默发誓以后再也不使用 Tab 了。那么到底什么时候该使用 Buffer,什么时候该使用 Tab?Window 又是个什么鬼?Tab 到底该不该背这个锅?还得从最基本的概念讲起。我们先上结论,再一个个解释。
以下是 Vim 官方文档中对于这三者的解释(执行 :help window
就能查看):
Summary:
A buffer is the in-memory text of a file.
A window is a viewport on a buffer.
A tab page is a collection of windows.
Vim 中的 Buffer 是文件在内存中的缓存数据,一个 Buffer 总是也只能是对应一个文件。当你使用 edit(e)
命令的时候,实际上就是将文件内容载入到 Buffer 里面。bnext/bprevious/bdelete/bwipe 命令的操作对象都是 Buffer,这也就是为什么执行 bnext
有时可以切换文件的原因。至于为什么是 “有时”,稍后再作解释。现在你只需记住,这几个命令都是直接对于文件缓存的操作。
用习惯 Sublime 或者 VS Code(以下简称 Vsc)的人可能会习惯性地把 Window 理解为窗口,把 split/vsplit
理解为分屏命令。但是这根本没办法解释为什么切换 Tab 的时候分屏会消失,按照之前的经验,切换 Tab 应该不影响分屏的展示才对。
其实 Window 跟前面说的两款编辑器中的窗口根本不是一个概念,在 Vim 中,Window 只负责展示 Buffer 的数据且不会影响 Buffer。当我们执行 split
或者 vsplit
的时候,其实是打开了一个新的 Window 并载入当前的 Buffer,而当我们使用 q
命令关闭一个窗口时,并不会关闭相应的 Buffer。除此之外,使用 help
命令、使用 NERDTree 打开文件树、使用 Tagbar 打开标签界面的时候,都是打开了一个新的 Window。一个 Window 在同一时间内只能展示一个 Buffer,一个 Buffer 可以同时被多个 Window 展示,使用上一节中的命令可以切换 Window 中展示的 Buffer。
理解了上面两个概念之后,Tab 就很好解释了。Tab 是一系列 Window 的集合,是一种 “布局”。一个 Tab 上可以有多个 Window,不同 Tab 之间的 Window 互不影响。
理解完上面这些概念之后,我想你大概已经明白了,在 Vim 中这三者的关系大概是这样的:Buffer 负责保存数据,Window 负责展示数据,Tab 为 Window 提供排版布局,Buffer 和 Tab 对 Window 总是一对多的关系。如果把 Vim 想象成一个机房的话,Buffer 就是主机,Window 是显示器,而 Tab 是一个个显示器架子。只不过这个机房里面的显示器可以随意连接到别的主机上面,一个主机可以被多个显示器连接。
前面提到过,尽管 Buffer 只是负责数据的保存,并不关心数据的展示,而 bnext/bprevious
命令是用于切换 Buffer 的,可是有时候调用 bnext/bprevious
命令却打开了一个新的 Window!这种奇怪的现象其实跟你的配置有关系,Vim 里面有一个 hidden
配置项,它负责告诉 Vim 是否允许隐藏一个未保存的 Buffer。当你 :set nohidden
时,Vim 会在切换 Buffer 的时候检测当前 Buffer 是否保存,如果还未保存,则会以打开一个新 Window 的形式打开另一个 Buffer。博主的建议是在 vimrc 中加入 set hidden
,这样才不容易导致迷惑。
拿 Vsc 来作比较,就很容易理解为什么在 Vim 中这三者容易导致迷惑了。在 Vsc 里面,一个 Tab 对应了一个文件(注:这里指双击打开的文件,而不是单击用浏览模式打开),一个 Tab 永远都只会显示同一个文件。明白了吗?其实 Vsc 里面的 Tab 更像是 Vim 里 Window 的概念。只不过 Vsc 中这两者是一种一经打开就无法修改的强一一对应的关系,而 Vim 却可以做到随意切换。而 Vsc 的窗口分屏却有点类似于 Vim Tab 的概念,只不过 Vsc 的布局只能有一种,而 Vim 可以有多种布局,随意切换。
类似于 Vsc 这样的编辑器把布局和展示的概念简化了,通过建立一种只有一个布局(Vim 中的 Tab,Vsc 中的窗口),展示(Vim 中的 Window,Vsc 中的 Tab)和数据强一一对应的机制,使得编辑器的使用更加简单,不容易出错。而 Vim 却不会管那么多,它向你提供 Buffer、Window 和 Tab,具体要怎么用,是操作者应该考虑的问题。
尽管 Vsc 这类编辑器操作更加友好,使用更加简单,但却没有 Vim 那么灵活,丧失了可定制性。而 Vim 为了灵活性却导致了学习成本太高,使人望而生畏。博主个人是比较倾向于 Vsc 那种操作逻辑的(以为我会夸 Vim?不存在的),在我个人的日常工作中也是尽量简化了 Vim 里面这三者的使用。不过还是推荐读者们根据个人习惯进行定制,毕竟自己用得顺手才是最好的。
由于 Tmux 这种神器的存在,而且刚入职不久公司还没给配屏幕,除非多项目切换频繁,博主一般不会使用多 Tab,也不使用分屏,而是使用单 Tab、单 Window、多 Buffer 切换的模式,把分屏的工作交给 Tmux。这样一来就可以大大简化会使用到的快捷键。下面奉上个人配置:
" 允许隐藏被修改过的 buffer
set hidden
" normal 模式下使用 bl 列出 Buffer 列表
nnoremap <silent> bl :ls<CR>
" normal 模式下使用 bo 打开一个新 Buffer
nnoremap <silent> bo :enew<CR>
" normal 模式下使用 bn 切换到下一个 Buffer
nnoremap <silent> bn :bnext<CR>
" normal 模式下使用 bn 切换到上一个 Buffer
nnoremap <silent> bp :bprevious<CR>
" normal 模式下使用 bd 关闭当前 Buffer
nnoremap <silent> bd :bdelete<CR>
" 允许 airline 在顶部显示 Buffer 列表
let g:airline#extensions#tabline#enabled=1
" 显示 buffer 编号,方便切换
let g:airline#extensions#tabline#buffer_nr_show=1
需要注意的是最后两行配置是 Vim 插件 vim-airline 的配置,需要先安装插件才能生效。另外,尽量使用 bdelete
而不是 bw/bwipe
命令关闭 Buffer,那样会导致某些插件运行出错。
更多博主的个人配置可以访问我的 GitHub,尽管配置项和配套的文档还不太完善,不过我基本每天都会拿出一小段时间进行不断更新,后续也会逐渐完善文档和注释的。
Vim 是一款神奇的编辑器,当你对它还不太了解的时候,总是感觉它高高在上、遥不可及,但是深入学习后又发现这是一款简单又实用的工具。Vim 的简单却带来了更大的灵活性,而有些代码编辑工具却设计得如此糟糕,大而全到底能不能代表好用呢?这是个值得思考的问题…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。