8

I want to have the very first search result centered on the screen. I know about :nnoremap n nzz mapping, but it only works for centering next matches, not the first.

I thought that maybe I could use some AutoCmd, but I haven't found an appropriate event.

15

You can use the following mapping:

cnoremap <expr> <CR> getcmdtype() == '/' ? '<CR>zz' : '<CR>'

Which can be explained like this:

  • cnoremap Create a mapping in the command line mode
  • <expr> The mapping will evaluate an expression (allowing to use conditions)
  • <CR> The key to remap (Enter)
  • getcmdtype() Return a character indicating which command line mode is used
  • == '/' Did getcmdtype() returned a / which means we are in search mode?
  • '<CR>zz' If we are in search mode execute zz after pressing <CR>
  • '<CR>' Else execute only <CR>

Related help topics:


EDIT Note that it would be interesting to create a mapping which would work with both forward and backward search i.e. when getcmdtype() return / or ?. Here is the mapping to do that:

cnoremap <expr> <CR> (getcmdtype() == '?' \|\| getcmdtype() == '/') ? '<CR>zz' : '<CR>'

Note the escaping of the | characters: if they are not escapes vim will understand cnoremap <expr> <CR> (getcmdtype() == '?' as the first command to execute followed by getcmdtype() == '/') ? '<CR>zz' : '<CR>' which doesn't make sense and create an error.


EDIT 2 @Antony suggested a more readable solution, thanks to him:

cnoremap <expr> <CR> getcmdtype() =~ '[/?]' ? '<CR>zz' : '<CR>'
6
  • 4
    Maybe getcmdtype() =~ '[?/]' would be a little easier.
    – Antony
    Dec 28 '16 at 13:49
  • @Antony Indeed that's much better, I edited my answer. Thank you!
    – statox
    Dec 28 '16 at 13:53
  • 3
    Awesome! Just what I need, thank you! And thanks for detailed explanations, they are very helpful for learning vimscript. Dec 28 '16 at 14:00
  • Recently had a problem with this using / as a motion: e.g. c/search will change from my current position to the next location matching search but, because of the cnoremap, insert the text zz. Thoughts on a workaround, or should I remove the mapping?
    – D. Ben Knoble
    Feb 17 '18 at 15:56
  • 1
    @DavidBenKnoble indeed that's a problem I didn't think about. I will try to find a workaround and edit my answer if I find one.
    – statox
    Feb 19 '18 at 10:52
5

Statox's answer is definitely the best so far, but as an alternative, I've just found out about Vim-slash, a plugin aiming to "enhance the in-buffer search experience."

And from it's readme:

Customization

zz after search

Places the current match at the center of the window.

noremap <plug>(slash-after) zz

Just tried it out and it is working smoothly in both directions (/ and ?).

2

Just in case someone still wondering about this, now you can use autocmd.

autocmd CmdlineEnter /,\? :cnoremap <CR> <CR>zz
autocmd CmdlineLeave /,\? :cunmap <CR>

It's basically remap enter when in search mode and unmap if leave search mode. It was inpired by example from :help 'incsearch' and you can use it without incsearch.

EDIT:
If you don't want to to remap <CR> or enter when you use search as motion, you can do something like this:

augroup incsearch_center
  autocmd CmdlineEnter /,\?
    \ if empty(v:operator) |
    \   cnoremap <CR> <CR>zz|
    \ endif
  autocmd CmdlineLeave /,\?
    \ if empty(v:operator) |
    \   cunmap <CR>|
    \ endif
augroup END

v:operator is basically to check the last operator given in Normal mode such as c, d, and so on. For more info :help v:operator

If you want to use the accepted answer, you can use something like this:

cnoremap <expr> <CR> getcmdtype() =~ '[/?]' && empty(v:operator) ? '<CR>zz' : '<CR>'
2
  • Don't forget to put your autocommands in an augroup. Also out of curiosity what advantage do you see when using your solution which creates and delete a mapping each time to switch to the search command line over simply creating the mapping just once as done in the accepted answer? I see the point of using the autocommand strategy for setting/unsetting things like hlsearch but for a mapping I'm not sure.
    – statox
    Apr 30 at 10:53
  • @statox Originally i used that with scrolloff option and incsearch so that the search result would appear in the middle while typing and when hitting enter. The autocommand is something like this autocmd CmdlineEnter /,\? :set scrolloff=999 | cnoremap <CR> <CR>zz and autocmd CmdlineLeave /,\? :set scrolloff=-1 | cunmap <CR>. I'm not sure whether the author use incsearch or not, so I only give the mapping. I mean, scrolloff is not really useful without incsearch on after all. May 1 at 8:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.