在之前的章节里,我们讲了怎么在vim里设置选项。对于布尔型选项,我们可以用set someoption!来切换选项的值。当我们对这个命令设置一个快捷键的话,它就变的非常有用了。
运行下面的命令:
:nnoremap N :set local number!
在normal模式下输入
不幸的是,这只对布尔型选项有效。如果你想切换一个非布尔型的选项的话,我们需要一些额外的工作。
我们从创建一个用来切换选项的函数开始,然后建立一个映射来调用这个函数。把下面的代码放到你的~/.vimrc文件里(或者一个单独的文件放在~/.vim/plugin目录下):
nnoremap :call FoldColumnToggle()
function! FoldColumnToggle()
echom &foldcolumn
endfunction
写入文件并且加载,然后通过
下面我们加入实际的功能。编辑代码,修改成如下内容:
nnoremap :call FoldColumnToggle()
function! FoldColumnToggle()
if &foldcolumn
setlocal foldcolumn=0
else
setlocal foldcolumn=4
endif
endfunction
写入文件,并加载。每次你输入
这里的if语句只是检查foldcolumn的值是否为真值(在vim里整数0代表假,其他的数字代表真值)。所以,如果是假值的话,就会把它设置成0,这样就会隐藏它。否则的话就把它的值设置为4。很简单。
你可以用类似的简单函数来操作任何的0值代表关闭,其他值代表打开的选项。
选项并不是我们想要进行切换的唯一功能。一个很有用的功能就是对快速补全窗口设置快捷键。我们先像之前一样先写一个简单的框架。把下面的代码加入到你的文件里:
nnoremap :call QuickfixToggle()
function! QuickfixToggle()
return
endfunction
这个映射并不会做任何事情。我们来把改变它,是它变得有用起来(不过并没有完全完成)。修改代码如下所示:
nnoremap :call QuickfixToggle()
function! QuickfixToggle()
copen
endfunction
写入并且加载这个文件。如果你再试试这个映射的话,你会看到它只是打开了一个快速补全窗口。
为了达到我们要切换的目的,我们先用一个简单,但是很不好的方法:全局变量。修改代码如下所示:
nnoremap :call QuickfixToggle()
function! QuickfixToggle()
if g:quickfix_is_open:
cclose
let g:quick_fix_is_open = 0
else
copen
let g:quick_fix_is_open = 1
endif
endfunction
我们所做的很简单——我们用一个全局变量来表示快速补全窗口的状态,每次改变状态的时候,都把当前的状态存入到这个变量里。
写入,并且加载这个文件,试着运行这个映射。vim会抱怨说这个变量没有定义!我们来修复这个问题,对它进行一下初始化:
nnoremap :call QuickfixToggle()
let g:quick_fix_is_open = 0
function! QuickfixToggle()
if g:quickfix_is_open:
cclose
let g:quick_fix_is_open = 0
else
copen
let g:quick_fix_is_open = 1
endif
endfunction
写入并且加载这个文件,再试试这个映射,它起作用了。
我们的切换功能起作用了,但是它还是存在一些问题。
第一个问题是,如果用户手动用:copen和:cclose来打开和关闭这个窗口的话,那么我们的变量的值就没法相应地进行更新了。这个问题并不是很严重,因为大部分情况下用户都会用映射来打开这个窗口的,如果不是的话,他们只需要多按一次映射键就可以了。
这个也说明了一个道理:当你在写vimscript代码的时候,如果你想要把所有的边界条件都覆盖到的话,你会陷入困境,并且很难完成你的任务的。
让一个功能大部分情况下都能正常工作(并不是说在不工作的时候爆发出一大堆问题)以及继续编码会比花大量的时间来让它达到100%的完美更好。不过一个例外就是,当你在写一个插件供很多人使用的时候。这个情况下,你最好多花点时间,让它能够处理绝大多数的场景,这样会让你用户开心,同时也会减少bug报告。
我们的函数的另外一个缺陷是,如果用户使用映射的时候他已经在快速补全窗口中了,那么vim会关闭它,并且把它切换到上一个窗口里,而不是把它放到它之前所在的地方。这个在你想很快检查一下快速补全窗口里的选项并且继续工作时,比较让人讨厌。
为了解决这个问题,我们引入一个写vim插件会迟早会用到的功能。修改你的代码如下所示:
let g:quick_fix_is_open = 0
function! QuickfixToggle()
if g:quickfix_is_open:
cclose
let g:quick_fix_is_open = 0
execute g:quickfix_return_to_window . "window w"
else
let g:quickfix_return_to_window = winnr()
copen
let g:quick_fix_is_open = 1
endif
endfunction
我们在函数的代码里添加了新的两行。第一个(在else语句里),会在运行:copen之前,把当前窗口的编号存入到另一个全局变量里。
第二行(在if语句里)执行wincmd,并且用窗口的编号作为前缀,来告诉vim跳转到对应的窗口。
再次说明一下,我们的方案并不是完美的。因为我们的用户可能在运行映射的时候打开或者关闭一个新的split。即使是这样,这个功能对于现在而言已经足够好了。
这种手动保存全局变量的方法在一些很严肃的程序里是不可取的,但是对于简单的vimscript函数而言这是一个快速但是恶心的可以让你的功能很快完成,并且继续你的生活的方式。。