Skip to content

Instantly share code, notes, and snippets.

@danmikita
Created November 16, 2018 19:16
Show Gist options
  • Save danmikita/d855174385b3059cd6bc399ad799555e to your computer and use it in GitHub Desktop.
Save danmikita/d855174385b3059cd6bc399ad799555e to your computer and use it in GitHub Desktop.
File preview with FZF, RG, Bat, and Devicons
nnoremap <silent> <leader>e :call Fzf_dev()<CR>
" ripgrep
if executable('rg')
let $FZF_DEFAULT_COMMAND = 'rg --files --hidden --follow --glob "!.git/*"'
set grepprg=rg\ --vimgrep
command! -bang -nargs=* Find call fzf#vim#grep('rg --column --line-number --no-heading --fixed-strings --ignore-case --hidden --follow --glob "!.git/*" --color "always" '.shellescape(<q-args>).'| tr -d "\017"', 1, <bang>0)
endif
" Files + devicons
function! Fzf_dev()
let l:fzf_files_options = '--preview "bat --theme="OneHalfDark" --style=numbers,changes --color always {2..-1} | head -'.&lines.'"'
function! s:files()
let l:files = split(system($FZF_DEFAULT_COMMAND), '\n')
return s:prepend_icon(l:files)
endfunction
function! s:prepend_icon(candidates)
let l:result = []
for l:candidate in a:candidates
let l:filename = fnamemodify(l:candidate, ':p:t')
let l:icon = WebDevIconsGetFileTypeSymbol(l:filename, isdirectory(l:filename))
call add(l:result, printf('%s %s', l:icon, l:candidate))
endfor
return l:result
endfunction
function! s:edit_file(item)
let l:pos = stridx(a:item, ' ')
let l:file_path = a:item[pos+1:-1]
execute 'silent e' l:file_path
endfunction
call fzf#run({
\ 'source': <sid>files(),
\ 'sink': function('s:edit_file'),
\ 'options': '-m ' . l:fzf_files_options,
\ 'down': '40%' })
endfunction
@annata83
Copy link

Awesome! Works Great.

@benfrain
Copy link

benfrain commented Nov 5, 2019

Brilliant, thanks for sharing 👍

By the way, is there a way of making this the default thing that fires when I press Ctrl+p?

I tried altering the nnoremap <silent> <leader>e :call Fzf_dev()<CR> to nnoremap <silent> <c-p> :call Fzf_dev()<CR> but that has the delay built in before firing.

Also, do you know if there is a way of incorporating the same functionality into Buffers? I use FZF to view buffers like this: nnoremap <Leader>b :Buffers<CR>

Apologies, realise this is probably obvious but I'm new to Vim

@matthiasdebernardini
Copy link

will this work in a vimrc? or is this strictly for neovim? thanks for sharing!

@danmikita
Copy link
Author

@matthiasdebernardini This should work just fine in vim. I don't believe there are any neovim specific features being leveraged.

@benwoodward
Copy link

One of the most useful vim snippets ever! Thank you. I just added an extra column that displays each file's git status, it's a bit hacky but it works.

" Files + devicons + floating fzf
function! FzfFilePreview()
  let l:fzf_files_options = '--preview "bat --theme="OneHalfDark" --style=numbers,changes --color always {3..-1} | head -200" --expect=ctrl-v,ctrl-x'
  let s:files_status = {}

  function! s:cacheGitStatus()
    let l:gitcmd = 'git -c color.status=false -C ' . $PWD . ' status -s'
    let l:statusesStr = system(l:gitcmd)
    let l:statusesSplit = split(l:statusesStr, '\n')
    for l:statusLine in l:statusesSplit
      let l:fileStatus = split(l:statusLine, ' ')[0]
      let l:fileName = split(l:statusLine, ' ')[1]
      let s:files_status[l:fileName] = l:fileStatus
    endfor
  endfunction

  function! s:files()
    call s:cacheGitStatus()
    let l:files = split(system($FZF_DEFAULT_COMMAND), '\n')
    return s:prepend_indicators(l:files)
  endfunction

  function! s:prepend_indicators(candidates)
    return s:prepend_git_status(s:prepend_icon(a:candidates))
  endfunction

  function! s:prepend_git_status(candidates)
    let l:result = []
    for l:candidate in a:candidates
      let l:status = ''
      let l:icon = split(l:candidate, ' ')[0]
      let l:filePathWithIcon = split(l:candidate, ' ')[1]

      let l:pos = strridx(l:filePathWithIcon, ' ')
      let l:file_path = l:filePathWithIcon[pos+1:-1]
      if has_key(s:files_status, l:file_path)
        let l:status = s:files_status[l:file_path]
        call add(l:result, printf('%s %s %s', l:status, l:icon, l:file_path))
      else
        " printf statement contains a load-bearing unicode space
        " the file path is extracted from the list item using {3..-1},
        " this breaks if there is a different number of spaces, which
        " means if we add a space in the following printf it breaks.
        " using a unicode space preserves the spacing in the fzf list
        " without breaking the {3..-1} index
        call add(l:result, printf('%s %s %s', '', l:icon, l:file_path))
      endif
    endfor

    return l:result
  endfunction

  function! s:prepend_icon(candidates)
    let l:result = []
    for l:candidate in a:candidates
      let l:filename = fnamemodify(l:candidate, ':p:t')
      let l:icon = WebDevIconsGetFileTypeSymbol(l:filename, isdirectory(l:filename))
      call add(l:result, printf('%s %s', l:icon, l:candidate))
    endfor

    return l:result
  endfunction

  function! s:edit_file(lines)
    if len(a:lines) < 2 | return | endif

    let l:cmd = get({'ctrl-x': 'split',
                 \ 'ctrl-v': 'vertical split',
                 \ 'ctrl-t': 'tabe'}, a:lines[0], 'e')

    for l:item in a:lines[1:]
      let l:pos = strridx(l:item, ' ')
      let l:file_path = l:item[pos+1:-1]
      execute 'silent '. l:cmd . ' ' . l:file_path
    endfor
  endfunction

  call fzf#run({
        \ 'source': <sid>files(),
        \ 'sink*':   function('s:edit_file'),
        \ 'options': '-m --preview-window=right:70%:noborder --prompt Files\> ' . l:fzf_files_options,
        \ 'down':    '40%',
        \ 'window': 'call FloatingFZF()'})

endfunction

image

@sushovannits
Copy link

sushovannits commented Mar 29, 2020

That is a great piece of work!! Thank you.
I am unable to open the file in splits using ctrl-x or ctrl-v 😢 Please help

@GGCristo
Copy link

GGCristo commented Aug 6, 2020

Any chance to make this compatible with fzf_action (CTRL-T, CTRL-X, etc).

@annguyenwasd
Copy link

Thanks a lot sir. Nice work!

@RoXuS
Copy link

RoXuS commented Oct 17, 2020

Any chance to make this compatible with fzf_action (CTRL-T, CTRL-X, etc).

+1, useless without that. But thx, it is beautiful.

@ItsNilDev
Copy link

Is it just me or calling this function takes at least 10 seconds?

@danmikita
Copy link
Author

Is it just me or calling this function takes at least 10 seconds?

It only takes ~500ms for me... But I am running on a newer Macbook Pro with at least an i7 and 16Gb of ram...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment