19

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?

32

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).

| improve this answer | |
  • Thanks for mentioning my plugin; I was just about to recommend that as an alternative :-) – Ingo Karkat Mar 4 '15 at 20:54
  • 2
    Clever use of subscripting! – wchargin Mar 4 '15 at 22:00
  • 6
    Could you please add an explanation? I haven't seen this syntax before, and I would like to know how it works. – EvergreenTree Mar 4 '15 at 22:37
  • 1
    @EvergreenTree: Added some more explanation – Christian Brabandt Mar 5 '15 at 7:00
  • 2
    @ChristianBrabandt That is very clever. I never thought of you using v:searchforward as an index. – EvergreenTree Mar 5 '15 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

| improve this answer | |
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>"
| improve this answer | |

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.