Reputation: 1038
I would like Vim to place my cursor vertically in the middle of screen after search. I have achieved that for *
, #
, n
and N
commands with the following lines in my vimrc
:
nmap * *zz
nmap # #zz
nmap n nzz
nmap N Nzz
My question is: How to map /
and ?
the same way? In other words, I would like to position the cursor in the same way after some text has been found using the following commands:
/some-text-to-find-forward
?some-text-to-find-backward
Upvotes: 6
Views: 2369
Reputation: 390
Below is an excerpt from my ~/.vimrc
that improves the search behavior in vim
by centering the search matches vertically when the n
, N
, /
or ?
commands are used, but only if jumping from the current cursor position to the search match goes up or down more than 3/4 (75%) of the actual window height. This helps a lot with the navigation through the edited file while searching, by preserving the context.
" Center the window vertically at the last search match if the search ends up
" scrolling the window up or down at least 75% (3/4) of the actual window height,
" which preserves the context and makes search navigation much easier
"
function! CenterSearch(command = v:null)
set lazyredraw
if a:command isnot v:null
let winstartold = line("w0")
let winendold = line("w$")
try
execute "normal! " .. a:command
catch
echohl ErrorMsg
echo substitute(v:exception, "^Vim(.*):", "", "")
echohl NONE
endtry
else
let winstartold = s:winstartold
let winendold = s:winendold
endif
let winstartnew = line("w0")
let winendnew = line("w$")
let winframe = float2nr(winheight(0) * (1.0 - 0.75))
if (winendnew - winstartnew + 1 > 0 && winendold - winstartold + 1 > 0)
\ && ((winstartnew < winstartold && winendnew < winendold
\ && winendnew <= winstartold + winframe)
\ || (winstartnew > winstartold && winendnew > winendold
\ && winstartnew >= winendold - winframe))
execute "normal zz"
endif
redraw
set nolazyredraw
endfunction
nnoremap <silent> n :call CenterSearch("n")<CR>
nnoremap <silent> N :call CenterSearch("N")<CR>
" Execute the search as usual, while remembering the resulting window position
" and possibly centering the window vertically at the resulting match
"
function! ExecuteSearch()
let cmdtype = getcmdtype()
if cmdtype ==# "/" || cmdtype ==# "?"
let s:winstartold = line("w0")
let s:winendold = line("w$")
return "\<CR>\<Esc>:call CenterSearch()\<CR>"
endif
return "\<CR>"
endfunction
cnoremap <silent> <expr> <CR> ExecuteSearch()
I know, this is a sizable chunk of vimscript code, but it also does quite a lot, which includes eliminating the screen flickering that may happen quite often as a result of the function scrolling the window.
I find this approach much more useful than just having the search matches always centered vertically, which doesn't preserve the context and, as a result, often makes the navigation through the edited file cumbersome.
I'd highly suggest that you also configure vim
to keep a minimal number of screen lines above and below the cursor, to preserve even more context of the edited file, by adding the following to your ~/.vimrc
:
set scrolloff=3
See also this answer, which may provide some additional comfort in vim
.
Upvotes: 0
Reputation: 21
Solution from Randy Morris but as a oneliner:
cnoremap <silent><expr> <enter> index(['/', '?'], getcmdtype()) >= 0 ? '<enter>zz' : '<enter>'
Upvotes: 1
Reputation: 40927
Edit: Threw away my initial answer as it was too much of a kludge. Here's a much better solution.
function! CenterSearch()
let cmdtype = getcmdtype()
if cmdtype == '/' || cmdtype == '?'
return "\<enter>zz"
endif
return "\<enter>"
endfunction
cnoremap <silent> <expr> <enter> CenterSearch()
The way this works is to remap Enter in command-line-mode to a custom expression.
The function performs the current search followed by zz if the command-line is currently in a search. Otherwise it just executes whatever command was being done.
Upvotes: 4
Reputation: 143
It's not very pretty, but
:nnoremap / :execute "normal! /\<lt>cr>zz"<c-left><right>
will get the job done. (Puts an :execute "normal! /"
command on the commandline, then adds a <cr>zz
to the end to it so that you automatically zz
when you issue the command. The final <c-left><right>
just steps into the search pattern at the right spot
Upvotes: 1