0

I would like to filter the output of vim commands with fzf. The idea is for example, if I use vim unimpaired plugin and I don't exactly remember which map was to navigate to the next git conflict but I do remember that it started with "[", to be able to do something like:

:map [ | fzf

And then I can search for "conflict" or "git" to explore the different mappings.

1
com -nargs=+ FF call fzf#run({'source' : split(execute(<q-args>), "\n"), 'sink':'"'})

Examples:

FF map [
FF set termcap
FF buffers
FF oldfiles

:h :quote is used as sink, it's ignored.

update

Filter blank lines, add -bang to support reverse order, add sink to copy into default register.

command! -nargs=+ -bang -complete=command FF call fzf#run({
            \ 'source' : filter(split(execute(<q-args>), "\n"), {i,v->!empty(v)}),
            \ 'sink': function('s:ff_sink'),
            \ 'options' : <bang>0 ? '--tac' : ''})

" copy into @@, ignore leading index
function! s:ff_sink(item)
  let text = substitute(a:item, '\v^\>?\s*\d+\:?\s*', '', '')
  let @@ = empty(text) ? a:item : text
endfunction
| improve this answer | |
1

If you're only interested in working with fzf plugin you probably should do as @dedowsdi suggests. I'm going to talk about the general case, as stands in the question title.

  1. First of all, let's not forget that Vim has a builtin function for filtering command output which can come in handy on many occasions. Its usage (:h :filter) is quite straightforward:

    :filter /conflict/ map [
    
  2. We can create a command of our own mixing system() and execute():

    function! Pipe(...)
        let l:bar = index(a:000, "\<bar>")
        if l:bar <= 0 || l:bar >= a:0 - 1
            return ''
        endif
        let l:result = execute(join(a:000[: l:bar - 1]))
        return system(join(a:000[l:bar + 1 :]), l:result)
    endfunction
    
    command! -nargs=+ -complete=command Pipe echo Pipe(<f-args>)
    

Now you can do :Pipe map [ | grep "conflict", or whatever else.

  1. The typical redirection pattern in Vim requires a (temporary) buffer usage. That is, dumping output into a buffer, filtering it, etc.

To redirect commands' output into a buffer you can use the following mapping:

nnoremap <silent><leader>x :-1put=trim(execute(input(\":\")))<CR>

Now press <leader>x and type any command you like.

When the result gets into buffer you can either redirect it to an external terminal window (note that visual mode / Ex ranges are supported too):

:w !grep "conflict"

or simply apply a filter in-place:

:%!grep "conflict"
| improve this answer | |
  • This is very general, I love it. Thank you – Blasco Oct 19 '19 at 12:40
  • It doesn't seem to work with :Pipe map [ | fzfI'll guess I'll have with the plugin option as I would like to dynamically filter – Blasco Oct 19 '19 at 12:43
  • @Blasco Definitely, it does work: it opens another terminal window to run fzf, and echoes the result back in Vim after it's ready. If you're seeking for a tighter integration of fzf and Vim you're suggested to explore/reuse code written by the fzf's author (as it's in two other answers). I'm not going to rewrite the whole plugin myself. – Matt Oct 19 '19 at 14:03
1

Redirect the output of the command to a new window, then use :BLines. This is mainly useful for editing the output.

function! Exec(cmd)
redir @a
exec printf('silent %s',a:cmd)
redir END
tabnew
norm "ap
endfunction

This function executes the command and printes the output onto a new tab. I use it from time to time.

For example try :

call Exec('nmap')
| improve this answer | |
  • Sorry but I don't fully understand what you mean, could you fully elaborate with an example? How do I redirect the output of the command to a new window? – Blasco Oct 19 '19 at 12:39

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.