I have the following autocmd to search for function definitions in C files.

autocmd Filetype c,cpp execute "nnoremap ]m /\\v^[^=]*(([a-zA-Z_][a-zA-Z_0-9]+)|(operator .*))\\(.*\\)( const|:)?( \\{)?$\<cr>:nohl\<cr>"

As I have incsearch defined, it will hightlight all the matches, why I can :nohl at the end. However the search fails if there are no matches found, and the :nohl is not executed in this case

This would be fine, if the search didn't fail and throw an error if it found nothing, but would just didn't change the cursor (which it should).

  • 1
    use either :try|:catch|:finally clause (which would be hard in your case, or wrap the optional part into an :exe command and add the :nohl at the end. That should work nomatter whether the :exe returns an error or not. BTW: Your mapping is too complex. Jul 9 '16 at 18:02
  • Why too complex? I guess regexes are always complex.
    – hgiesel
    Jul 9 '16 at 18:07
  • 2
    it's not easily understandable. 1) you don't need the :exe part 2) your pattern needs to be double escaped because of double quotes That is what I call too complex Jul 9 '16 at 18:09

Here's a mapping that won't change the last search register or print errors:

nnoremap <expr> ]m filter([search('pattern', 'nW'), line('.')], 'v:val')[0].'G'

filter() takes a list of items and returns a list containing the ones that are satisfied by the second argument. It's using a simple 'v:val' to evaluate the item as a boolean. Note that it's using the first item from the filtered list: filter(...)[0].'G'.

Since search() returns a matching line number on success, it will be the first item in that list. If there is no match, it'll return 0 and won't be in the filtered list. As a fallback, the current line number is used.

If the pattern matches on line 15 the map expression will return 15G which jumps to that line. Since G is a jump motion, the jump list will be updated.

It can work in the opposite direction by adding the b flag to the search flags:

nnoremap <expr> [m filter([search('pattern', 'bnW'), line('.')], 'v:val')[0].'G'

If you wanted it to wrap around the buffer, you could remove the W flag.

A real example of this working:

augroup vimrc_fugitive
  autocmd FileType gitcommit
        \ nnoremap <expr><buffer> } filter([search('\%(\_^#\?\s*\_$\)\\|\%$', 'nW'), line('$')], 'v:val')[0].'G' |
        \ nnoremap <expr><buffer> { max([1, search('\%(\_^#\?\s*\_$\)\\|\%^', 'nbW')]).'G'
augroup END

This is what I'm using to get paragraph motions back in vim-fugitive

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.