25

Vim has (at least) two sets of commands that search in opposite directions. Typing / and then a pattern will search forward through the document for the pattern; typing ? and then a pattern will search backward. The same relationship exists between the * and # commands.

What I don’t like is that these commands also set the search direction for the n and N commands. After using /, n goes forward through the document and N goes backward; after using ?, n goes backward and N goes forward. (In other words, n always goes in the same direction as the original search and N always goes in the other direction.)

How can I get n to go forward through the document, and N to go backward, regardless of which direction I started searching in?

3 Answers 3

39

You can change the behaviour of n and N to search consistently downwards/upwards by useing the following:

nnoremap <expr> n 'Nn'[v:searchforward]
nnoremap <expr> N 'nN'[v:searchforward]

Update: How does it work?

This uses expression-maps, which maps the lhs of the map to an expression that will be evaluated, everytime the lhs is encountered. See :h map-expression in the help.

What happens is, that the v:searchforward variable (which determines the internal state of which direction the last search was, see :h v:searchforward) is used as an index for the string in front of it. So in case of the first map, if the last search direction was forward, the n will be mapped to 'n' (index of 1, meaning return the second character) and if it was backward, the 'n' will be mapped to 'N' (because the v:searchforward variable is 0 and therefore the 'N' will be returned.

An alternative way to write those maps would be (which might be clearer):

nnoremap <expr> n (v:searchforward ? 'n' : 'N')
nnoremap <expr> N (v:searchforward ? 'N' : 'n')

There are also some plugins, that do that (ie the SearchRepeat plugin and possibly others as well).

10
  • 1
    Thanks for mentioning my plugin; I was just about to recommend that as an alternative :-) Commented Mar 4, 2015 at 20:54
  • 3
    Clever use of subscripting!
    – wchargin
    Commented Mar 4, 2015 at 22:00
  • 7
    Could you please add an explanation? I haven't seen this syntax before, and I would like to know how it works. Commented Mar 4, 2015 at 22:37
  • 2
    @EvergreenTree: Added some more explanation Commented Mar 5, 2015 at 7:00
  • 3
    @ChristianBrabandt That is very clever. I never thought of you using v:searchforward as an index. Commented Mar 5, 2015 at 12:40
1

Based on Christian Brabandt's solution I came up with

nnoremap <expr> n 'Nn'[v:searchforward].(&fdo=~'search\\|all'?'zv':'')
nnoremap <expr> N 'nN'[v:searchforward].(&fdo=~'search\\|all'?'zv':'')

These mappings also obey the foldopen setting

1

I’m using the SearchIndex plugin. To use Christian Brabandt’s answer but keep the plugin’s functionality of displaying the match number each time I type n or N, I put this in my vimrc:

nnoremap <silent><expr> n (v:searchforward ? 'n' : 'N') . ":SearchIndex<CR>"
nnoremap <silent><expr> N (v:searchforward ? 'N' : 'n') . ":SearchIndex<CR>"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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