├── .vintrc.yaml ├── LICENSE ├── README.md ├── autoload ├── fz.vim └── fz │ └── utils.vim ├── plugin └── fz.vim └── screenshot.gif /.vintrc.yaml: -------------------------------------------------------------------------------- 1 | cmdargs: 2 | severity: style_problem 3 | 4 | policies: 5 | ProhibitUnusedVariable: 6 | enabled: true 7 | ProhibitImplicitScopeVariable: 8 | enabled: true 9 | ProhibitNoAbortFunction: 10 | enabled: true 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Yasuhiro Matsumoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-fz 2 | 3 | Ultra Fast Fuzzy finder for Vim8 and NeoVim. 4 | 5 | But very very experimental! 6 | 7 | ![Fz](https://raw.githubusercontent.com/mattn/vim-fz/master/screenshot.gif) 8 | 9 | ## Usage 10 | 11 | ``` 12 | :Fz 13 | ``` 14 | 15 | Or type `,f` 16 | 17 | ## APIs 18 | 19 | ### type: cmd 20 | 21 | ```vim 22 | nnoremap :execute system('git rev-parse --is-inside-work-tree') =~ 'true' 23 | \ ? fz#run({ 'type': 'cmd', 'cmd': 'git ls-files' }) 24 | \ : 'Fz' 25 | ``` 26 | 27 | ### type: list 28 | 29 | ```vim 30 | command! FzColors call fz#run({ 31 | \ 'type': 'list', 32 | \ 'list': uniq(map(split(globpath(&rtp, "colors/*.vim"), "\n"), "substitute(fnamemodify(v:val, ':t'), '\\..\\{-}$', '', '')")), 33 | \ 'accept': {result->execute('colorscheme ' . result['items'][0])}, 34 | \ }) 35 | ``` 36 | 37 | ## Requirements 38 | 39 | * [gof](https://github.com/mattn/gof) 40 | * vim8 or neovim 41 | 42 | ## Installation 43 | 44 | ``` 45 | $ go get github.com/mattn/gof 46 | ``` 47 | 48 | * [Pathogen](https://github.com/tpope/vim-pathogen) 49 | * `git clone https://github.com/mattn/vim-fz.git ~/.vim/bundle/vim-fz` 50 | * [vim-plug](https://github.com/junegunn/vim-plug) 51 | * `Plug 'mattn/vim-fz'` 52 | * [Vim packages](http://vimhelp.appspot.com/repeat.txt.html#packages) 53 | * `git clone https://github.com/mattn/vim-fz.git ~/.vim/pack/plugins/start/vim-fz` 54 | 55 | ## License 56 | 57 | MIT 58 | 59 | ## Author 60 | 61 | Yasuhiro Matsumoto (a.k.a. mattn) 62 | -------------------------------------------------------------------------------- /autoload/fz.vim: -------------------------------------------------------------------------------- 1 | let s:is_nvim = has('nvim') 2 | let s:is_win = has('win32') || has('win64') 3 | 4 | function! s:absolute_path(path) abort 5 | if has('win32') 6 | return a:path =~# '^\([/\\]\|[a-zA-Z]:[/\\]\)' 7 | endif 8 | return a:path =~# '^/' 9 | endfunction 10 | 11 | function! s:wipe(ctx) abort 12 | if buflisted(a:ctx['buf'] ) 13 | exe a:ctx['buf'] 'bwipe!' 14 | endif 15 | endfunction 16 | 17 | " first argument is the ctx 18 | " neovim passes third argument as 'exit' while vim passes only 2 arguments 19 | function! s:exit_cb(ctx, job, st, ...) abort 20 | if has_key(a:ctx, 'tmp_input') && !has_key(a:ctx, 'file') 21 | call delete(a:ctx['tmp_input']) 22 | endif 23 | if a:st != 0 24 | call s:wipe(a:ctx) 25 | call delete(a:ctx['tmp_result']) 26 | return 27 | endif 28 | if !s:is_nvim 29 | silent! call ch_close(job_getchannel(term_getjob(a:ctx['buf']))) 30 | endif 31 | let l:items = readfile(a:ctx['tmp_result']) 32 | call delete(a:ctx['tmp_result']) 33 | call s:wipe(a:ctx) 34 | if len(l:items) == 0 35 | return 36 | endif 37 | if has_key(a:ctx['options'], 'accept') 38 | let l:params = {} 39 | if has_key(a:ctx, 'actions') 40 | let l:params['actions'] = a:ctx['actions'] 41 | if has_key(l:params['actions'], l:items[0]) 42 | let l:params['action'] = l:params['actions'][l:items[0]] 43 | else 44 | let l:params['action'] = l:items[0] 45 | endif 46 | let l:params['items'] = l:items[1:] 47 | else 48 | let l:params['items'] = l:items 49 | endif 50 | call a:ctx['options']['accept'](l:params) 51 | else 52 | if has_key(a:ctx, 'actions') 53 | let l:action = l:items[0] 54 | let l:items = l:items[1:] 55 | else 56 | let l:action = '' 57 | endif 58 | 59 | if len(l:items) ==# 1 && l:action ==# '' 60 | let l:path = expand(l:items[0]) 61 | if !s:absolute_path(l:path) 62 | let l:path = a:ctx.basepath . '/' . l:path 63 | endif 64 | if filereadable(expand(l:path)) 65 | if &modified 66 | if winwidth(win_getid()) > winheight(win_getid()) * 3 67 | exe 'vsplit' l:path 68 | else 69 | exe 'split' l:path 70 | endif 71 | else 72 | exe 'edit' l:path 73 | endif 74 | endif 75 | else 76 | for l:item in l:items 77 | let l:path = expand(l:item) 78 | if !s:absolute_path(l:path) 79 | let l:path = a:ctx.basepath . '/' . l:path 80 | endif 81 | if filereadable(expand(l:path)) 82 | if l:action == '' 83 | exe 'sp' l:path 84 | else 85 | exe a:ctx['actions'][l:action] . ' ' . l:path 86 | endif 87 | endif 88 | endfor 89 | endif 90 | endif 91 | endfunction 92 | 93 | function! s:get_fzcmd_options(ctx) abort 94 | " should include empty space if it contains options 95 | let l:actions = get(a:ctx['options'], 'actions', g:fz_command_actions) 96 | if !empty(l:actions) 97 | let l:options_action = get(a:ctx['options'], 'options_action', g:fz_command_options_action) 98 | if l:options_action == '' 99 | return '' 100 | endif 101 | let a:ctx['actions'] = l:actions 102 | return ' ' . printf(l:options_action, join(keys(l:actions), ',')) 103 | endif 104 | return '' 105 | endfunction 106 | 107 | function! fz#run(...) 108 | if !s:is_nvim && !has('patch-8.0.928') 109 | echohl ErrorMsg | echo "vim-fz doesn't work on legacy vim" | echohl None 110 | return 111 | endif 112 | 113 | " create context 114 | let l:ctx = { 115 | \ 'options': get(a:000, 0, {}), 116 | \ 'basepath': '' 117 | \ } 118 | 119 | " check argument 120 | if type(l:ctx['options']) != type({}) 121 | echohl ErrorMsg | echo 'invalid argument' | echohl None 122 | return 123 | endif 124 | 125 | " Get basepath 126 | let l:basepath = get(l:ctx['options'], 'basepath', '') 127 | if empty(l:basepath) 128 | let l:basepath = '.' 129 | endif 130 | let l:ctx['basepath'] = expand(l:basepath) 131 | 132 | " check type 133 | let l:typ = get(l:ctx['options'], 'type', 'cmd') 134 | let l:pipe_cmd = '' 135 | if l:typ ==# 'cmd' 136 | let l:fz_command = get(l:ctx['options'], 'fz_command', g:fz_command) 137 | if has_key(l:ctx['options'], 'cmd') 138 | let l:pipe_cmd = l:ctx['options']['cmd'] . ' | ' 139 | endif 140 | elseif l:typ ==# 'file' 141 | if !has_key(l:ctx['options'], 'file') 142 | echohl ErrorMsg | echo "invalid argument. 'file' required." | echohl None 143 | return 144 | endif 145 | call writefile(l:ctx['options']['list'], l:ctx['tmp_input']) 146 | let l:ctx['tmp_input'] = l:ctx['options']['file'] 147 | elseif l:typ ==# 'list' 148 | if !has_key(l:ctx['options'], 'list') 149 | echohl ErrorMsg | echo "invalid argument. 'list' required." | echohl None 150 | return 151 | endif 152 | if type(l:ctx['options']['list']) != type([]) 153 | echohl ErrorMsg | echo "invalid argument 'list'." | echohl None 154 | return 155 | endif 156 | let l:ctx['tmp_input'] = tempname() 157 | call writefile(l:ctx['options']['list'], l:ctx['tmp_input']) 158 | else 159 | echohl ErrorMsg | echo 'unsupported type' | echohl None 160 | return 161 | endif 162 | let l:ctx['tmp_result'] = tempname() 163 | let l:fz_command = get(l:ctx['options'], 'fz_command', g:fz_command) 164 | let l:fz_options = s:get_fzcmd_options(l:ctx) 165 | if has_key(l:ctx, 'tmp_input') 166 | if s:is_win 167 | let l:cmd = printf('%s %s "%s%s <%s >%s"', &shell, &shellcmdflag, l:fz_command, l:fz_options, l:ctx['tmp_input'], l:ctx['tmp_result']) 168 | else 169 | let l:cmd = [&shell, &shellcmdflag, printf('%s%s > %s < %s', l:fz_command, l:fz_options, l:ctx['tmp_result'], l:ctx['tmp_input'])] 170 | endif 171 | else 172 | let l:cmd = [&shell, &shellcmdflag, printf('%s%s%s > %s', l:pipe_cmd, l:fz_command, l:fz_options, l:ctx['tmp_result'])] 173 | endif 174 | botright new 175 | let l:ctx['buf'] = bufnr('%') 176 | if s:is_nvim 177 | call termopen(l:cmd, {'on_exit': function('s:exit_cb', [l:ctx]), 'cwd': l:ctx['basepath']}) | startinsert 178 | else 179 | call term_start(l:cmd, {'term_name': 'Fz', 'curwin': l:ctx['buf'] > 0, 'exit_cb': function('s:exit_cb', [l:ctx]), 'tty_type': 'conpty', 'cwd': l:ctx['basepath']}) 180 | endif 181 | if has_key(l:ctx['options'], 'message') 182 | echo l:ctx['options']['message'] 183 | endif 184 | endfunction 185 | -------------------------------------------------------------------------------- /autoload/fz/utils.vim: -------------------------------------------------------------------------------- 1 | function! s:uniq(list) abort 2 | let l:result = [] 3 | for l:item in a:list 4 | if index(l:result, l:item) == -1 5 | call add(l:result, l:item) 6 | endif 7 | endfor 8 | return l:result 9 | endfunction 10 | 11 | function! fz#utils#mru() abort 12 | let l:files = map(range(bufnr('$'), 1, -1), 'bufname(v:val)') + copy(v:oldfiles) 13 | let l:files = filter(map(l:files, 'expand(v:val)'), 'filereadable(v:val)') 14 | return s:uniq(map(l:files, 'fnamemodify(v:val, ":~:.:gs!\\!/!")')) 15 | endfunction 16 | -------------------------------------------------------------------------------- /plugin/fz.vim: -------------------------------------------------------------------------------- 1 | if exists('g:fz_loaded') 2 | finish 3 | endif 4 | let g:fz_loaded = 1 5 | 6 | let g:fz_command = get(g:, 'fz_command', 'gof') 7 | let g:fz_command_options_action = get(g:, 'fz_command_options_action', '-a=%s') 8 | let g:fz_command_actions = { 9 | \ 'ctrl-o': 'edit', 10 | \ 'ctrl-t': 'tab split', 11 | \ 'ctrl-x': 'split', 12 | \ 'ctrl-v': 'vsplit' 13 | \ } 14 | 15 | command! -nargs=* -complete=dir Fz call fz#run({'basepath': }) 16 | command! -nargs=* -complete=dir FzMRU call fz#run({'basepath': , 'type': 'list', 'list': fz#utils#mru()}) 17 | nnoremap (fz) :Fz 18 | nnoremap (fz-mru) :FzMRU 19 | if !hasmapto('(fz)') 20 | nmap ,f (fz) 21 | endif 22 | if !hasmapto('(fz-mru)') 23 | nmap ,, (fz-mru) 24 | endif 25 | -------------------------------------------------------------------------------- /screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/vim-fz/693bb547c59080544a1bcca3341b9bdc81a027f4/screenshot.gif --------------------------------------------------------------------------------