searchvimconfigurationdirectionvim-registers

Searching backward for visual mode selection


I am looking to remap my # and * keys in visual mode in Vim so that I am able to highlight a portion of text and search for it backwards and forwards, respectively. With the help of a previous answer I have managed to get forward searches working. I am having difficulty getting backward searching to work however. Below are the relevant parts of my .vimrc.

function! GetVisualSelection() abort
  try
    let a_save = @a
    silent! normal! gv"ay
    return @a
  finally
    let @a = a_save
  endtry
endfunction

" Map # and * to search for the highlighted text in visual mode
vnoremap <silent> * <c-\><c-n>:let @/ = escape(GetVisualSelection(), '/\^$*.[~')<CR>n
vnoremap <silent> # <c-\><c-n>:let @/ = escape(GetVisualSelection(), '/\^$*.[~')<CR>N

The initial highlight and search backwards works well, but then once I press n to search for the next occurrence backwards, instead Vim resumes searching forward. I suspect this is because backward searches use the ? operator instead of /, which would mean I would have to press N instead of n. However this is counter-intuitive to the normal mode operation of #, so I attempted to assign the selection to the ? register, only to find that there is no register named ?. How would I solve this issue? Ideally I would prefer to do this without installing a plugin.


Solution

  • There are no option that you can switch on or off to define whether the search should be forwards or backwards, unfortunately. So the simplest way is to actually search with / or ?.

    In your case:

    vnoremap <silent> * <c-\><c-n>:let @/ = escape(GetVisualSelection(), '/\^$*.[~')<CR>/<CR>
    vnoremap <silent> # <c-\><c-n>:let @/ = escape(GetVisualSelection(), '/\^$*.[~')<CR>?<CR>
    

    Searching without argument will just repeat the last pattern (see :help ?<CR>)


    Although I feel like defining a function for that purpose is a bit overkill, here's what I have in my vimrc:

    vnoremap * y:let @/ = escape("<C-r>0", "/\^$*.[~")<CR>/<CR>
    vnoremap # y:let @/ = escape("<C-r>0", "/\^$*.[~")<CR>?<CR>
    

    Here I copy the selection, set the @/ register to the copied text, and search in the same way I showed above. The <C-r> allows to past the content of a register (see :help <C-r>)