12

When using incremental search in vim, the cursor immediately goes to the next occurrence of the search term as far as you have typed it. Emacs has a similar incremental search function. However, there is a feature of emacs isearch that I have found very useful that I really would like in vim. In emacs, if you type:

<ctrl-s>word

it immediately goes to "word", just like vim incremental search. In emacs, you can now type additional <ctrl-s> to move to the next result occurrence of "word" and in emacs this does not end your incremental search session. To do the same in vim, you must hit <cr>, to end the search term, then hit n to go to the next search result. Because emacs does not end the search session, you can do things like:

<ctrl-s>word<ctrl-s><ctrl-s>more

This lets you "home in" on your search once you get closer to where you want to go and turns out to be incredibly useful!

Is there a way to get vim to do the same?

00prometheus
  • 767
  • 7
  • 20
  • How about this sequence: 1) `/word`, 2) ``, 3) `n`, ..., `n`, 4) `/`, 5, ``? You'll return to your search command, i.e. `/word`. Then you can continue entering `more`. – Ruslan Osmanov Oct 22 '16 at 14:04
  • Yes, that works (and is roughly what I do now), it's just that its less convenient than the emacs version. Vim should be _more_ convenient than emacs at all times! ;-) – 00prometheus Oct 22 '16 at 14:07
  • Of course the hardest part is hitting ``, you could instead use `/` to insert search register that is contains your previous searched item. – dNitro Oct 22 '16 at 14:12
  • '/' - to initiate a search 'Ctrl-l' - to expand search pattern using characters after the cursor (similar to 'Ctrl-w' in emacs). – maximk Dec 11 '17 at 07:30

4 Answers4

16

Recent versions of Vim provide builtin mappings of command-line mode to do exactly what you want.

You can find this in help:

CTRL-G

When 'incsearch' is set, entering a search pattern for "/" or "?" and the current match is displayed then CTRL-G will move to the next match (does not take search-offset into account). Use CTRL-T to move to the previous match. Hint: on a regular keyboard T is above G.

Patch numbers for reference as not all installations have the mappings:

  • Patch 7.4.2259 made Ctrl-N/Ctrl-P act like Ctrl-S/Ctrl-R in Emacs.

  • Patch 7.4.2268 changed the mappings to Ctrl-G/Ctrl-T (the ones used initially have different purpose).

xaizek
  • 5,098
  • 1
  • 34
  • 60
  • I upgraded vim, and this works! However, the keymappings by yolenoyer and Ruslan are actually better: They let me continue on an old search! Ctrl-T/Ctrl-G does not let me append on the previous search, which is at the core of what I want. – 00prometheus Oct 22 '16 at 17:53
  • 1
    @00prometheus What do you mean by saying that you can't append to previous search? Pattern remains in place for me and I can continue editing it. – xaizek Oct 22 '16 at 18:06
  • 1
    Sorry, I figured it out now! Simply do a search, hit `/` and type some more to home in without leaving search at all. Perfect! – 00prometheus Oct 23 '16 at 01:49
6

The two mappings below let me hit <Tab> or <S-Tab> to jump to the next or previous match without leaving incremental search:

" needed for mapping <Tab> in command-line mode
set wildcharm=<C-z>

cnoremap <expr> <Tab>   getcmdtype() == "/" \|\| getcmdtype() == "?" ? "<CR>/<C-r>/" : "<C-z>"
cnoremap <expr> <S-Tab> getcmdtype() == "/" \|\| getcmdtype() == "?" ? "<CR>?<C-r>/" : "<S-Tab>"
romainl
  • 186,200
  • 21
  • 280
  • 313
  • What is the advantage of the getcmdtype conditional compared to just plain keymapping? This is deeper into vim than I am accustomed to go :-) – 00prometheus Oct 22 '16 at 15:58
  • Right now, I have `nnoremap /` `cnoremap /` `cnoremap ?`, in my .vimrc. It allows me to use ctrl-s to go forwards and ctrl-z to go back. – 00prometheus Oct 22 '16 at 16:00
  • @00prometheus: This is a nice emulation of xaizek's answer for older Vim versions. – Ingo Karkat Oct 24 '16 at 12:54
  • If you add `zv` after the first ``, it will also open folds if needed. E.g. `cnoremap getcmdtype() == "/" \|\| getcmdtype() == "?" ? "zv//" : ""` – Von Jun 03 '17 at 16:06
1

You can use a key mapping:

nnoremap <C-s> /<Up>

(for normal mode)

If you want to stay the the previous match (not to move to the next match), you may just return to the previous match after /<Up>:

nnoremap <C-s> N/<Up>

Usage:

  1. /word<CR> - start searching for word
  2. n, ..., n - move to the next matches
  3. <C-s>, i.e. Control + s - call the previous search (1)
  4. Type more - start searching for /wordmore
Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60
  • This is getting us there! I also tried adding `:cnoremap n/` as well, so I can hit `ctrl-s` to go to the next match without leaving the search at all, but that jumps two results at a time. Any idea how to avoid that? – 00prometheus Oct 22 '16 at 14:38
  • @00prometheus, how about `nnoremap N/`? – Ruslan Osmanov Oct 22 '16 at 14:48
  • @yolenoyer figured it out; see his answer! – 00prometheus Oct 22 '16 at 14:56
  • @00prometheus, his solution doesn't work for me. But my mapping works just as it is described in the question. – Ruslan Osmanov Oct 22 '16 at 15:10
  • Strange, it works for me. I am using `nnoremap /` and `cnoremap /`in my .vimrc now, and it works great! Now I just need to find a free key for reverse-isearch as well! :-) – 00prometheus Oct 22 '16 at 15:43
  • If you also add `cnoremap ?` you can use ctrl-z to go back as well as ctrl-s to go forwards (ctrl-z isn't used in command mode otherwise). – 00prometheus Oct 22 '16 at 15:54
1

With the same idea:

:cnoremap <c-s> <cr>/<up>

With this mapping, he use of Ctrl-L during search is even more useful.

yolenoyer
  • 8,797
  • 2
  • 27
  • 61