Add fzf#vim#with_preview function for previewing search result

Close #225
This commit is contained in:
Junegunn Choi 2016-11-26 14:10:16 +09:00
parent 3fbcfdb9ea
commit 9ce2c2179f
No known key found for this signature in database
GPG key ID: 254BC280FEF9C627
3 changed files with 105 additions and 5 deletions

View file

@ -152,18 +152,40 @@ let g:fzf_tags_command = 'ctags -R'
let g:fzf_commands_expect = 'alt-enter,ctrl-x'
```
#### Advanced customization using autoload functions
#### Advanced customization
You can use autoload functions to define your own commands.
```vim
" git grep
" Command for git grep
" - fzf#vim#grep(command, with_column, [options], [fullscreen])
command! -bang -nargs=* GGrep
\ call fzf#vim#grep('git grep --line-number '.shellescape(<q-args>), 0, <bang>0)
" We use VimEnter event so that the code is run after fzf.vim is loaded
autocmd VimEnter * command! Colors
\ call fzf#vim#colors({'left': '15%', 'options': '--reverse --margin 30%,0'})
autocmd VimEnter * command! -bang Colors
\ call fzf#vim#colors({'left': '15%', 'options': '--reverse --margin 30%,0'}, <bang>0)
" Augmenting Ag command using fzf#vim#with_preview function
" * fzf#vim#with_preview([[options], preview window, [toggle keys...]])
" * Preview script requires Ruby
" * Install Highlight or CodeRay to enable syntax highlighting
"
" :Ag - Start fzf with hidden preview window that can be enabled with "?" key
" :Ag! - Start fzf in fullscreen and display the preview window above
autocmd VimEnter * command! -bang -nargs=* Ag
\ call fzf#vim#ag(<q-args>,
\ <bang>0 ? fzf#vim#with_preview('up:60%')
\ : fzf#vim#with_preview('right:50%:hidden', '?'),
\ <bang>0)
" Similarly, we can apply it to fzf#vim#grep. To use ripgrep instead of ag:
command! -bang -nargs=* Rg
\ call fzf#vim#grep(
\ 'rg --column --line-number --no-heading --color=always '.shellescape(<q-args>), 1,
\ <bang>0 ? fzf#vim#with_preview('up:60%')
\ : fzf#vim#with_preview('right:50%:hidden', '?'),
\ <bang>0)
```
Mappings

View file

@ -29,9 +29,47 @@ set cpo&vim
" ------------------------------------------------------------------
let s:layout_keys = ['window', 'up', 'down', 'left', 'right']
let s:bin = { 'preview': expand('<sfile>:h:h:h').'/bin/preview.rb' }
let s:TYPE = {'dict': type({}), 'funcref': type(function('call')), 'string': type('')}
function s:remove_layout(opts)
" [[options to wrap], preview window expression, [toggle-preview keys...]]
function! fzf#vim#with_preview(...)
" Default options
let options = {}
let window = 'right'
let args = copy(a:000)
" Options to wrap
if len(args) && type(args[0]) == s:TYPE.dict
let options = copy(args[0])
call remove(args, 0)
endif
" Preview window
if len(args) && type(args[0]) == s:TYPE.string
if args[0] !~# '^\(up\|down\|left\|right\)'
throw 'invalid preview window: '.args[0]
endif
let window = args[0]
call remove(args, 0)
endif
if !executable('ruby')
return options
endif
let preview = printf(' --preview-window %s --preview "%s"\ %s\ {}',
\ window,
\ shellescape(s:bin.preview), window =~ 'up\|down' ? '-v' : '')
if len(args)
let preview .= ' --bind '.join(map(args, 'v:val.":toggle-preview"'), ',')
endif
let options.options = get(options, 'options', '').preview
return options
endfunction
function! s:remove_layout(opts)
for key in s:layout_keys
if has_key(a:opts, key)
call remove(a:opts, key)

40
bin/preview.rb Executable file
View file

@ -0,0 +1,40 @@
#!/usr/bin/env ruby
#
# usage: ./preview.rb [-v] FILENAME[:LINE][:IGNORED]
require 'shellwords'
COMMAND = %[(highlight -O ansi -l {} || coderay {} || cat {}) 2> /dev/null]
ANSI = /\x1b\[[0-9;]*m/
REVERSE = "\x1b[7m"
RESET = "\x1b[m"
split = ARGV.delete('-v')
if ARGV.empty?
puts "usage: #$0 [-v] FILENAME[:LINENO][:IGNORED]"
exit 1
end
file, center = ARGV.first.split(':')
unless File.readable? file
puts "File not found: #{file}"
exit 1
end
center = (center || 0).to_i
height = File.readable?('/dev/tty') ? `stty size < /dev/tty`.split.first.to_i : 40
height /= 2 if split
height -= 2 # preview border
offset = [1, center - height / 3].max
IO.popen(['sh', '-c', COMMAND.gsub('{}', Shellwords.shellescape(file))]) do |io|
io.each_line.drop(offset - 1).take(height).each_with_index do |line, lno|
if lno + offset == center
puts REVERSE + line.chomp.gsub(ANSI) { |m| m + REVERSE } + RESET
else
puts line
end
end
end