May 24, 2021 Vim
In the first few chapters we talked about how to set options in Vim. F
or the Boolean option, we
set someoption!
t
o "switch" the option.
If we could create a map for this command, that would be great.
Execute the following command:
:nnoremap <leader>N :setlocal number!<cr>
In normal mode,
<leader>N
see. V
im switches between turning the line number display on and off.
Switching maps like this is convenient, so we don't need two separate keys to turn on/off.
Unfortunately, this only works for the Boolean option. If we want to switch a non-Boolean option, more needs to be done.
Start by creating a function where you can switch options and calling a map of the function.
Add the following code to
~/.vimrc
(or a separate file
~/.vim/plugin/
you want):
nnoremap <leader>f :call FoldColumnToggle()<cr>
function! FoldColumnToggle()
echom &foldcolumn
endfunction
Save and source the file, and then press
<leader>f
try it. V
im displays the
foldcolumn
option.
If you are not familiar with this
:help foldcolumn
and continue.
Let's add the real switching feature. Modify the code to this:
nnoremap <leader>f :call FoldColumnToggle()<cr>
function! FoldColumnToggle()
if &foldcolumn
setlocal foldcolumn=0
else
setlocal foldcolumn=4
endif
endfunction
Save and source the file, and then try it. Each time you press it Vim will display or hide the folding status bar.
if
statement
&foldcolumn
is true (remember that Vim treats 0 as false and other numbers as true). I
f so, set it to 0 (hide it). O
therwise, set it to 4.
It's as simple as that.
You can use a simple function like this to switch any option
0
at 0 and open with other numbers.
Our dreams should not stop at switching options. A nother thing we want to switch to is the quickfix window. T he previous skeleton code is still used as a starting point. Add the following code to your file:
nnoremap <leader>q :call QuickfixToggle()<cr>
function! QuickfixToggle()
return
endfunction
This mapping does nothing for the time being. L et's turn it into something else that's a little bit useful (but it's not completely done yet). Change the code to this:
nnoremap <leader>q :call QuickfixToggle()<cr>
function! QuickfixToggle()
copen
endfunction
Save and source files. If you try this mapping now, you'll see an empty quickfix window.
In order to achieve the switching function, we will choose a quick and dirty means: global variables. Change the code to this:
nnoremap <leader>q :call QuickfixToggle()<cr>
function! QuickfixToggle()
if g:quickfix_is_open
cclose
let g:quickfix_is_open = 0
else
copen
let g:quickfix_is_open = 1
endif
endfunction
What we do is simple -- each time we call a function, we use a global variable to store the switch state of the quickfix window.
Save and source the file, then perform a mapping try. V im will complain that variables are not yet defined! So let's initialize the variables first.
nnoremap <leader>q :call QuickfixToggle()<cr>
let g:quickfix_is_open = 0
function! QuickfixToggle()
if g:quickfix_is_open
cclose
let g:quickfix_is_open = 0
else
copen
let g:quickfix_is_open = 1
endif
endfunction
Save and source the file, then try the mapping. It worked!
Our switch function works, but there are still some problems.
The first problem is that assuming that the
:copen
window
:cclose
our global variables will not be refreshed.
In fact, this is not a big problem, because most of the time users will use this mapping switch window, in case it is not open, they will press again.
This is another important experience with writing Vimscript code: if you try to deal with every marginal condition, you will be trapped in it and there will be no progress.
In most cases, it's much better to roll out code that works (and doesn't break it) and then go back and improve it, much better than spending many hours demanding perfection. E xcept that you're developing a plug-in that's likely to be used by a lot of people. In this case it is worth the time to reach an unassailable level, satisfy users, and reduce bug reporting.
Another problem with our function is that when the user has opened the quickfix window and performed this mapping, Vim closes the window and then bounces them to the previous split instead of sending them back to where they were before. If you just want to take a quick look at the quickfix window and get back to work, it's annoying that this is happening.
To solve this problem, we'll introduce a usage that is useful when writing Vim plug-ins. Change your code to this:
nnoremap <leader>q :call QuickfixToggle()<cr>
let g:quickfix_is_open = 0
function! QuickfixToggle()
if g:quickfix_is_open
cclose
let g:quickfix_is_open = 0
execute g:quickfix_return_to_window . "wincmd w"
else
let g:quickfix_return_to_window = winnr()
copen
let g:quickfix_is_open = 1
endif
endfunction
We added two new lines to the map.
One line (in
else
branch) sets another global variable to hold the current window serial number when
:copen
Another line (in
if
wincmd w with that serial
wincmd w
tell Vim to jump to the corresponding window.
Once again, our solution is not unassailable, with users likely to open or close new segments between execution maps. Even so, it's suitable for most occasions, so it's good enough at the moment.
In most programs, this trick of manually saving global state is condemned, but for a very short Vimscript function, it's fast and dirty, but it's mission-free and fulfills the task.
Read
:help foldcolumn
.
Read
:help winnr()
Read
:help ctrl-w_w
.
Read
:help wincmd
.
Add s: and
<SID>
to limit the function to a private namespace.
s: