I'm using grep in vim to do something such as:

:grep pattern file

and have a key-map for it that looks like that:

function! Escaped()
    call inputsave()
    let result = escape(@", '\\/.*$^~[]#')
    let result = substitute(result, "\n$", "", "")
    let result = substitute(result, "\n", '\\n', "g")
    call inputrestore()
    return result

xnoremap <silent> <unique> * y:grep "<C-r>=Escaped()<CR>" file

This does work great but I want to open the result of this command in a split window instead.
I tried inserting sp, split and such at the start of the command, or before grep, but it doesn't seem to work.

Quickfix does seem to work, but since it keeps old matches I would prefer for it to be either deleting the old match, or (as the question suggests) opening the result in a split window in vim (without tmux etc)

How could I do that?

  • 1
    This question is unclear to me, since :grep opens its result on the Quickfix window, so it's already a split window in a way... You mention the Quickfix in "I would prefer for it to be either deleting the old match", which I don't really understand what you mean by it... Can you give an example that illustrates what you want to do with it? – filbranden Sep 5 '20 at 1:29
  • But maybe what you want is as simple as :split | grep pattern file ? (Or :snew as the first command?) This would create a split first, then run your grep. – filbranden Sep 5 '20 at 1:42
  • 1
    my bad, i failed to explain some part of this: basically using split on the commandline as you showed work...but using it on the keymap i showed doesn't seem to work. – Nordine Lotfi Sep 5 '20 at 12:43
  • 2
    @NordineLotfi you’ll need to escape the | in a map, or use <Bar> – D. Ben Knoble Sep 5 '20 at 14:26

You can run :split before you run your :grep.

Note that :split is not a command modifier, so you need to run the two commands as separate commands.

You can separate them with |, as in:

:split | grep pattern file

If you're doing it from your mapping, you need to use <Bar>, or \|, since a single | will terminate the map command itself:

xnoremap <silent> <unique> * y:split<Bar>grep "<C-r>=Escaped()<CR>" file<CR>

A much better approach, though, is to move the whole body of the mapping into a function (instead of just the Escape() part), in which case you can simply have commands on separate lines. You also don't need to mess with <C-r>=, just using :execute instead is much easier.

function! GrepSelection()
    normal! gvy
    let result = escape(@", '\\/.*$^~[]#')
    let result = substitute(result, "\n$", "", "")
    let result = substitute(result, "\n", '\\n', "g")
    execute 'grep "'.result.'" file'
xnoremap <silent> <unique> * :<C-U>call GrepSelection()<CR>

You need <C-U> here to clear up the :'<,'> inserted by Vim when you go to command-line mode from Visual mode. You need an extra gv inside the function to restore the Visual selection before yanking it.

If you yank the selection inside the function, you can also take the opportunity to save the contents of the register you yank to and restore it at the end of the function, so that using this mapping doesn't disrupt your next put command. (Other questions cover this technique, so I won't include a snippet for it here.)

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.