├── .gitignore ├── README.md ├── autoload └── fzy.vim ├── doc └── fzy.txt ├── ftplugin └── fzy.vim └── plugin └── fzy.vim /.gitignore: -------------------------------------------------------------------------------- 1 | Session.vim 2 | /doc/tags 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-fzy 2 | 3 | Quickly navigate to **files** under a directory, jump to lines matching a 4 | pattern using **grep**, open **buffers**, **tags** generated by ctags, Vim's 5 | **help tags**, **old files**, and **file marks** using the fuzzy-searcher 6 | [fzy][fzy]. 7 | 8 | The terminal buffer can be displayed either in a normal window at the bottom 9 | of the screen or in a popup window. 10 | 11 |
12 |

13 | 14 | 15 | 16 |

17 |
18 | 19 | 20 | ## Requirements 21 | 22 | - [fzy][fzy] 23 | - [cut(1)][cut] (for the `:FzyHelp` command) 24 | - [find(1)][find] or similar (for the `:FzyFind` command) 25 | - [grep(1)][grep] or similar (for the `:FzyGrep` command) 26 | 27 | 28 | ## Commands 29 | 30 | | Command | Description | 31 | | ----------------- | --------------------------------------------------------------------------------------- | 32 | | `:FzyFind [dir]` | Find **files** in `[dir]`, edit selected file in the current window. | 33 | | `:FzyGrep {args}` | Grep **lines** using pattern `{args}`, jump to selected location in the current window. | 34 | | `:FzyBuffer` | List **buffers**, edit selected buffer in the current window. | 35 | | `:FzyArgs` | List **global arglist**, edit selected file in the current window. | 36 | | `:FzyLargs` | List **local arglist**, edit selected file in the current window. | 37 | | `:FzyOldfiles` | List **most recently used** files, edit selected file in current window. | 38 | | `:FzyTjump` | List **tags**, jump to selected tag in the current window. | 39 | | `:FzyMarks` | List **marks**, jump to the selected mark in the current window. | 40 | | `:FzyHelp` | List **help tags**, open help page with the selected tag in a new split. | 41 | 42 | `[dir]` is the directory to search in. If omitted, the search is performed in 43 | the current working directory. Environment variables can be passed, for example, 44 | `:FzyFind $VIMRUNTIME`. 45 | 46 | Each command has a related command that opens the selected item in a new split, 47 | like `:FzyBufferSplit`. These commands accept a **command modifier**. For 48 | example, to open a buffer in a new vertical split, run `:vert FzyBufferSplit`, 49 | `:tab FzyBufferSplit` will open the selected buffer in a new tab. For a full 50 | list of supported command modifiers, see `:help fzy-commands-split`. 51 | 52 | 53 | ## Configuration 54 | 55 | Options can be passed to fzy through the dictionary `g:fzy`. The following 56 | entries are supported: 57 | 58 | | Entry | Description | Default | 59 | | ---------------- | ---------------------------------------------------------------------------- | ---------------------------------- | 60 | | `lines` | Specify how many lines of results to show. This sets fzy's `--lines` option. | `10` | 61 | | `prompt` | Set the fzy input prompt. | `'▶ '` | 62 | | `showinfo` | If true, fzy is invoked with the `--show-info` option. | `v:false` | 63 | | `term_highlight` | Highlight group for the terminal window. | `'Terminal'` | 64 | | `popupwin` | Display fzy in a popup terminal. | `v:false` | 65 | | `popup` | Popup window options (dictionary). | [see below](#popup-window-options) | 66 | | `findcmd` | File-search command (string). | [see below](#find-command) | 67 | | `grepcmd` | Grep-search command. | `&grepprg` | 68 | | `grepformat` | Format string for parsing the selected grep-output line. | `&grepformat` | 69 | | `histadd` | If true, add edit command to history. | `v:false` | 70 | 71 | When `popupwin` is set to `v:false`, the terminal window is opened at the bottom 72 | of the screen and will occupy the full width of the Vim window. 73 | 74 | ### Popup window options 75 | 76 | The appearance of the popup window can be configured through the `popup` key. 77 | The following options can be set: 78 | 79 | | Entry | Description | Default | 80 | | ----------------- | ---------------------------------------------------------------------------- | ------------------------------------------ | 81 | | `highlight` | Highlight group for popup window padding and border. | `'Pmenu'` | 82 | | `padding` | List with numbers defining padding between popup window and its border. | `[0, 1, 0, 1]` | 83 | | `border` | List with numbers (0 or 1) specifying whether to draw a popup window border. | `[1, 1, 1, 1]` | 84 | | `borderchars` | List with characters used for drawing the border. | `['═', '║', '═', '║', '╔', '╗', '╝', '╚']` | 85 | | `borderhighlight` | List with highlight group names for drawing the border.¹ | `['Pmenu']` | 86 | | `minwidth` | Minimum width of popup window. | `80` | 87 | 88 | ¹When only one item is specified it is used on all four sides. 89 | 90 | ### Find command 91 | 92 | If `findcmd` is not specified, the following default command is used: 93 | ```bash 94 | find 95 | -name '.*' 96 | -a '!' -name . 97 | -a '!' -name .gitignore 98 | -a '!' -name .vim 99 | -a -prune 100 | -o '(' -type f -o -type l ')' 101 | -a -print 2> /dev/null 102 | | cut -b3- 103 | ``` 104 | 105 | Broken down the expression means: 106 | - Ignore all hidden files and directories, except for `.gitignore`, and `.vim`, 107 | - print only files and symlinks. 108 | - The `cut` command will remove the leading `./` from all file paths. 109 | 110 | ### Example 111 | 112 | ```vim 113 | g:fzy = { 114 | findcmd: 'fd --type f', 115 | grepcmd: 'grep -Hn', 116 | grepformat: '%f:%l:%m', 117 | histadd: true, 118 | prompt: '>>> ', 119 | showinfo: true, 120 | lines: 15, 121 | term_highlight: 'Pmenu', 122 | popupwin: true, 123 | popup: { 124 | borderchars: [' '] 125 | } 126 | } 127 | ``` 128 | More examples can be found under `:help fzy-config-examples`. 129 | 130 | 131 | ## Writing custom fzy commands 132 | 133 | Writing custom commands that invoke fzy is very simple. Internally, the above 134 | commands call the `Start()` function that passes the items to fzy in a terminal 135 | window. The function is documented in `:help fzy-api`. Examples can be found in 136 | `:help fzy-api-examples`. 137 | 138 | 139 | ## Installation 140 | 141 | Run the following commands in your terminal: 142 | ```bash 143 | $ cd ~/.vim/pack/git-plugins/start 144 | $ git clone https://github.com/bfrg/vim-fzy 145 | $ vim -u NONE -c 'helptags vim-fzy/doc | quit' 146 | ``` 147 | **Note:** The directory name `git-plugins` is arbitrary, you can pick any other 148 | name. For more details see `:help packages`. Alternatively, use your favorite 149 | plugin manager. 150 | 151 | 152 | ## License 153 | 154 | Distributed under the same terms as Vim itself. See `:help license`. 155 | 156 | [fzy]: https://github.com/jhawthorn/fzy 157 | [find]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html 158 | [grep]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html 159 | [cut]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/cut.html 160 | -------------------------------------------------------------------------------- /autoload/fzy.vim: -------------------------------------------------------------------------------- 1 | vim9script 2 | # ============================================================================== 3 | # Run fzy asynchronously inside a Vim terminal-window 4 | # File: autoload/fzy.vim 5 | # Author: bfrg 6 | # Website: https://github.com/bfrg/vim-fzy 7 | # Last Change: Oct 21, 2022 8 | # License: Same as Vim itself (see :h license) 9 | # ============================================================================== 10 | 11 | const findcmd: list =<< trim END 12 | find 13 | -name '.*' 14 | -a '!' -name . 15 | -a '!' -name .gitignore 16 | -a '!' -name .vim 17 | -a -prune 18 | -o '(' -type f -o -type l ')' 19 | -a -print 2> /dev/null 20 | | cut -b3- 21 | END 22 | 23 | def Error(msg: string) 24 | echohl ErrorMsg | echomsg msg | echohl None 25 | enddef 26 | 27 | def Update_cmd_history(cmd: string) 28 | if get(get(g:, 'fzy', {}), 'histadd', false) 29 | histadd('cmd', cmd) 30 | endif 31 | enddef 32 | 33 | def Tryexe(cmd: string) 34 | try 35 | execute cmd 36 | catch 37 | echohl ErrorMsg 38 | echomsg matchstr(v:exception, '^Vim\%((\a\+)\)\=:\zs.*') 39 | echohl None 40 | endtry 41 | enddef 42 | 43 | def Exit_cb(ctx: dict, job: job, status: number) 44 | # Redraw screen in case a prompt like :tselect shows up after selecting an 45 | # item. If not redrawn, popup window remains visible 46 | if ctx.popupwin 47 | close 48 | redraw 49 | else 50 | const winnr: number = winnr() 51 | win_gotoid(ctx.winid) 52 | execute $':{winnr}close' 53 | redraw 54 | endif 55 | 56 | if filereadable(ctx.selectfile) 57 | try 58 | ctx.on_select_cb(readfile(ctx.selectfile)[0]) 59 | catch /^Vim\%((\a\+)\)\=:E684/ 60 | endtry 61 | endif 62 | 63 | delete(ctx.selectfile) 64 | if has_key(ctx, 'itemsfile') 65 | delete(ctx.itemsfile) 66 | endif 67 | enddef 68 | 69 | def Term_open(opts: dict, ctx: dict): number 70 | const cmd: list = [&shell, &shellcmdflag, opts.shellcmd] 71 | 72 | var term_opts: dict = { 73 | norestore: true, 74 | exit_cb: funcref(Exit_cb, [ctx]), 75 | term_name: 'fzy', 76 | term_rows: opts.rows 77 | } 78 | 79 | if has_key(opts, 'term_highlight') 80 | extend(term_opts, {term_highlight: opts.term_highlight}) 81 | endif 82 | 83 | var bufnr: number 84 | if ctx.popupwin 85 | if !has_key(opts, 'term_highlight') 86 | extend(term_opts, {term_highlight: 'Pmenu'}) 87 | endif 88 | 89 | bufnr = term_start(cmd, extend(term_opts, { 90 | hidden: true, 91 | term_finish: 'close' 92 | })) 93 | 94 | extend(opts.popup, { 95 | minwidth: &columns > 80 ? 80 : &columns - 4, 96 | padding: [0, 1, 0, 1], 97 | border: [] 98 | }, 'keep') 99 | 100 | # Stop terminal job when popup window is closed with mouse 101 | popup_create(bufnr, deepcopy(opts.popup)->extend({ 102 | minheight: opts.rows, 103 | callback: (_, i) => i == -2 ? bufnr->term_getjob()->job_stop() : 0 104 | })) 105 | else 106 | botright bufnr = term_start(cmd, term_opts) 107 | &l:number = false 108 | &l:relativenumber = false 109 | &l:winfixheight = true 110 | &l:bufhidden = 'wipe' 111 | &l:statusline = opts.statusline 112 | endif 113 | 114 | setbufvar(bufnr, '&filetype', 'fzy') 115 | return bufnr 116 | enddef 117 | 118 | def Opts(title: string, space: bool = false): dict 119 | var opts: dict = get(g:, 'fzy', {})->deepcopy()->extend({statusline: title}) 120 | get(opts, 'popup', {})->extend({title: space ? ' ' .. title : title}) 121 | return opts 122 | enddef 123 | 124 | def Find_cb(dir: string, vim_cmd: string, choice: string) 125 | var fpath: string = fnamemodify(dir, ':p:s?/$??') .. '/' .. choice 126 | fpath = fpath->resolve()->fnamemodify(':.')->fnameescape() 127 | Update_cmd_history($'{vim_cmd} {fpath}') 128 | Tryexe($'{vim_cmd} {fpath}') 129 | enddef 130 | 131 | def Open_file_cb(vim_cmd: string, choice: string) 132 | const fname: string = fnameescape(choice) 133 | Update_cmd_history($'{vim_cmd} {fname}') 134 | Tryexe($'{vim_cmd} {fname}') 135 | enddef 136 | 137 | def Open_tag_cb(vim_cmd: string, choice: string) 138 | Update_cmd_history(vim_cmd .. ' ' .. choice) 139 | Tryexe(vim_cmd .. ' ' .. escape(choice, '"')) 140 | enddef 141 | 142 | def Marks_cb(split_cmd: string, bang: bool, item: string) 143 | if !empty(split_cmd) 144 | execute split_cmd 145 | endif 146 | const cmd: string = bang ? "g`" : "`" 147 | Tryexe($'normal! {cmd}{item[1]}') 148 | enddef 149 | 150 | def Grep_cb(efm: string, vim_cmd: string, choice: string) 151 | const items: list = getqflist({lines: [choice], efm: efm})->get('items', []) 152 | if empty(items) || !items[0].bufnr 153 | Error('fzy: no valid item selected') 154 | return 155 | endif 156 | setbufvar(items[0].bufnr, '&buflisted', 1) 157 | const cmd: string = $'{vim_cmd} {items[0].bufnr} | call cursor({items[0].lnum}, {items[0].col})' 158 | Update_cmd_history(cmd) 159 | Tryexe(cmd) 160 | enddef 161 | 162 | export def Start(items: any, On_select_cb: func, options: dict = {}): number 163 | if empty(items) 164 | Error('fzy-E10: No items passed') 165 | return 0 166 | endif 167 | 168 | var ctx: dict = { 169 | winid: win_getid(), 170 | selectfile: tempname(), 171 | on_select_cb: On_select_cb, 172 | popupwin: get(options, 'popupwin') ? true : false 173 | } 174 | 175 | var opts: dict = options->deepcopy()->extend({ 176 | exe: exepath('fzy'), 177 | prompt: '> ', 178 | lines: 10, 179 | showinfo: 0, 180 | popup: {}, 181 | histadd: false, 182 | statusline: 'fzy-term' 183 | }, 'keep') 184 | 185 | if !executable(opts.exe) 186 | Error($'fzy: executable "{opts.exe}" not found') 187 | return 0 188 | endif 189 | 190 | var lines: number = opts.lines < 3 ? 3 : opts.lines 191 | opts.rows = opts.showinfo ? lines + 2 : lines + 1 192 | 193 | const fzycmd: string = printf('%s --lines=%d --prompt=%s %s > %s', 194 | opts.exe, 195 | lines, 196 | shellescape(opts.prompt), 197 | opts.showinfo ? '--show-info' : '', 198 | ctx.selectfile 199 | ) 200 | 201 | var fzybuf: number 202 | if type(items) == v:t_list 203 | ctx.itemsfile = tempname() 204 | 205 | # Automatically resize terminal window 206 | if len(items) < lines 207 | lines = len(items) < 3 ? 3 : len(items) 208 | opts.rows = get(opts, 'showinfo') ? lines + 2 : lines + 1 209 | endif 210 | 211 | opts.shellcmd = $'{fzycmd} < {ctx.itemsfile}' 212 | if executable('mkfifo') 213 | system($'mkfifo {ctx.itemsfile}') 214 | fzybuf = Term_open(opts, ctx) 215 | writefile(items, ctx.itemsfile) 216 | else 217 | writefile(items, ctx.itemsfile) 218 | fzybuf = Term_open(opts, ctx) 219 | endif 220 | elseif type(items) == v:t_string 221 | opts.shellcmd = $'{items} | {fzycmd}' 222 | fzybuf = Term_open(opts, ctx) 223 | else 224 | Error('fzy-E11: Only list and string supported') 225 | return 0 226 | endif 227 | 228 | return fzybuf 229 | enddef 230 | 231 | export def Stop() 232 | if &buftype != 'terminal' || bufname() != 'fzy' 233 | Error('fzy-E12: Not a fzy terminal window') 234 | return 235 | endif 236 | bufnr()->term_getjob()->job_stop() 237 | enddef 238 | 239 | export def Find(dir: string, vim_cmd: string, mods: string) 240 | if !isdirectory(expand(dir, true)) 241 | Error($'fzy-find: Directory "{expand(dir, true)}" does not exist') 242 | return 243 | endif 244 | 245 | const path: string = dir->expand(true)->fnamemodify(':~')->simplify() 246 | const cmd: string = printf('cd %s; %s', 247 | expand(path, true)->shellescape(), 248 | get(g:, 'fzy', {})->get('findcmd', join(findcmd)) 249 | ) 250 | const editcmd: string = empty(mods) ? vim_cmd : (mods .. ' ' .. vim_cmd) 251 | const stl: string = $':{editcmd} [directory: {path}]' 252 | Start(cmd, funcref(Find_cb, [path, editcmd]), Opts(stl)) 253 | enddef 254 | 255 | export def Buffers(edit_cmd: string, bang: bool, mods: string) 256 | const cmd: string = empty(mods) ? edit_cmd : (mods .. ' ' .. edit_cmd) 257 | const items: list = range(1, bufnr('$')) 258 | ->filter(bang ? (_, i: number): bool => bufexists(i) : (_, i: number): bool => buflisted(i)) 259 | ->mapnew((_, i: number): any => i->bufname()->empty() ? i : i->bufname()->fnamemodify(':~:.')) 260 | const stl: string = printf(':%s (%s buffers)', cmd, bang ? 'all' : 'listed') 261 | Start(items, funcref(Open_file_cb, [cmd]), Opts(stl)) 262 | enddef 263 | 264 | export def Oldfiles(edit_cmd: string, mods: string) 265 | const cmd: string = empty(mods) ? edit_cmd : (mods .. ' ' .. edit_cmd) 266 | const items: list = v:oldfiles 267 | ->copy() 268 | ->filter((_, i: string): bool => i->fnamemodify(':p')->filereadable()) 269 | ->map((_, i: string): string => fnamemodify(i, ':~:.')) 270 | const stl: string = $':{cmd} (oldfiles)' 271 | Start(items, funcref(Open_file_cb, [cmd]), Opts(stl)) 272 | enddef 273 | 274 | export def Arg(edit_cmd: string, local: bool, mods: string) 275 | const items: list = local ? argv() : argv(-1, -1) 276 | const str: string = local ? 'local arglist' : 'global arglist' 277 | const cmd: string = empty(mods) ? edit_cmd : (mods .. ' ' .. edit_cmd) 278 | Start(items, funcref(Open_file_cb, [cmd]), Opts($':{cmd} ({str})')) 279 | enddef 280 | 281 | export def Help(help_cmd: string, mods: string) 282 | const cmd: string = empty(mods) ? help_cmd : (mods .. ' ' .. help_cmd) 283 | const items: string = 'cut -f 1 ' .. findfile('doc/tags', &runtimepath, -1)->join() 284 | const stl: string = $':{cmd} (helptags)' 285 | Start(items, funcref(Open_tag_cb, [cmd]), Opts(stl)) 286 | enddef 287 | 288 | export def Grep(edit_cmd: string, mods: string, args: string) 289 | const cmd: string = empty(mods) ? edit_cmd : (mods .. ' ' .. edit_cmd) 290 | const grep_cmd: string = get(g:, 'fzy', {})->get('grepcmd', &grepprg) .. ' ' .. args 291 | const grep_efm: string = get(g:, 'fzy', {})->get('grepformat', &grepformat) 292 | const stl: string = $':{cmd} ({grep_cmd})' 293 | Start(grep_cmd, funcref(Grep_cb, [grep_efm, cmd]), Opts(stl)) 294 | enddef 295 | 296 | export def Tags(tags_cmd: string, mods: string) 297 | const cmd: string = empty(mods) ? tags_cmd : (mods .. ' ' .. tags_cmd) 298 | const items: any = executable('sed') && executable('cut') && executable('sort') && executable('uniq') 299 | ? printf("sed '/^!_TAG_/ d' %s | cut -f 1 | sort | uniq", tagfiles()->join()) 300 | : taglist('.*')->mapnew((_, i: dict): string => i.name)->sort()->uniq() 301 | const stl: string = printf(':%s [%s]', cmd, tagfiles()->map((_, i: string): string => fnamemodify(i, ':~:.'))->join(', ')) 302 | Start(items, funcref(Open_tag_cb, [cmd]), Opts(stl)) 303 | enddef 304 | 305 | export def Marks(bang: bool, ...args: list) 306 | const cmd: string = !empty(args) ? args[0] .. ' split' : '' 307 | const output: list = execute('marks')->split('\n') 308 | Start(output[1 :], funcref(Marks_cb, [cmd, bang]), Opts(output[0], true)) 309 | enddef 310 | -------------------------------------------------------------------------------- /doc/fzy.txt: -------------------------------------------------------------------------------- 1 | *fzy.txt* Run fzy asynchronously in a Vim terminal window. 2 | 3 | Author: bfrg 4 | Website: https://github.com/bfrg/vim-fzy 5 | License: Same terms as Vim itself (see |license|) 6 | 7 | ============================================================================== 8 | INTRODUCTION *vim-fzy* 9 | 10 | vim-fzy provides commands for quickly navigating to files under a directory, 11 | jumping to lines matching a pattern using a grep command, opening |:buffers|, 12 | tags generated by ctags, |:help| tags, |:oldfiles|, as well as |:marks| using 13 | the fuzzy-searcher https://github.com/jhawthorn/fzy. 14 | 15 | The terminal buffer is opened either in a normal window at the bottom of the 16 | screen or in a |popup-window|. 17 | 18 | ============================================================================== 19 | COMMANDS *fzy-commands* 20 | 21 | :FzyFind [dir] *:FzyFind* 22 | Find files recursively under the directory [dir], open the 23 | selected file in the current window. 24 | 25 | The file-search command can be specified through |g:fzy.findcmd| 26 | (see below). 27 | 28 | If [dir] is omitted, the search is performed in the current 29 | working directory (as obtained by |getcwd()|). 30 | 31 | :FzyGrep {args} *:FzyGrep* 32 | Find lines matching the pattern specified with {args} using a grep 33 | command, jump to the selected location in the current window. 34 | 35 | The grep-search command can be specified with |g:fzy.grepcmd|. The 36 | grep-output is parsed with |g:fzy.grepformat| (see below). 37 | 38 | Note: special characters like % and # in {args} are expanded 39 | before the grep command is invoked. To avoid that insert a 40 | backslash before the character. See |cmdline-special| for more 41 | details. 42 | 43 | :FzyBuffer[!] *:FzyBuffer* 44 | List buffers (same as |:ls|), edit the selected buffer in current 45 | window. 46 | 47 | Add ! to show all existing buffers (listed and unlisted buffers). 48 | This is similar to the |:ls|! output. 49 | 50 | :FzyArgs *:FzyArgs* 51 | List the global |argument-list|, edit the selected file in the 52 | current window. 53 | 54 | :FzyLargs *:FzyLargs* 55 | List the local |argument-list| (local to the window), edit the 56 | selected file in the current window. 57 | 58 | :FzyOldfiles *:FzyOldfiles* 59 | List |:oldfiles|, edit the selected file in the current window. 60 | 61 | :FzyTjump *:FzyTjump* 62 | List tags from all tags files, jump to the selected tag in the 63 | current window. This is similar to |:tjump|. 64 | 65 | :FzyMarks[!] *:FzyMarks* 66 | List marks (same as |:marks|), jump to the selected mark in the 67 | current window. 68 | 69 | Add ! to jump to the selected mark without changing the jumplist 70 | when jumping within the current buffer. 71 | 72 | :FzyHelp *:FzyHelp* 73 | List all help tags, jump to the selected tag in a new |split|. 74 | The Command can be preceded by a command modifier (see below). 75 | 76 | Note that Vim does not provide any commands to open a help page in 77 | the current window. 78 | 79 | *fzy-commands-split* 80 | Each command has a related command that opens the selected item in a new 81 | |split|. 82 | 83 | *:FzyFindSplit* 84 | Same as |:FzyFind|, but opens the selected file in a new |split|. 85 | *:FzyGrepSplit* 86 | Same as |:FzyGrep|, but opens the selected file in a new |split|. 87 | *:FzyBufferSplit* 88 | Same as |:FzyBuffer|, but opens selected buffer in new |split|. 89 | *:FzyArgsSplit* 90 | Same as |:FzyArgs|, but opens the selected file in new |split|. 91 | *:FzyLargsSplit* 92 | Same as |:FzyLargs|, but opens the selected file in new |split|. 93 | *:FzyOldfilesSplit* 94 | Same as |:FzyOldfiles|, but opens selected file in new |split|. 95 | *:FzyTjumpSplit* 96 | Same as |:FzyTjump|, but opens the selected tag in new |split|. 97 | *:FzyMarksSplit* 98 | Same as |:FzyMarks|, but jump to the selected mark in new |split|. 99 | 100 | The commands can be preceded by a command modifier. For example, to open the 101 | selected file in a new |vertical| split, run > 102 | :vert FzyFindSplit [dir] 103 | < 104 | Possible modifiers: 105 | |vertical| 106 | |tab| 107 | |topleft| 108 | |botright| 109 | |leftabove| (same as |aboveleft|) 110 | |rightbelow| (same as |belowright|) 111 | 112 | ============================================================================== 113 | CONFIGURATION *fzy-config* 114 | 115 | *g:fzy* 116 | Options can be passed to fzy through the |Dictionary| variable g:fzy. The 117 | following options are supported: 118 | 119 | lines *g:fzy.lines* 120 | Specify how many lines of results to show. This is equivalent to 121 | fzy's "--lines" option. 122 | Default: 10 123 | 124 | prompt *g:fzy.prompt* 125 | Fzy input prompt. Equivalent to fzy's "--prompt" option. 126 | Default: "> " 127 | 128 | showinfo *g:fzy.showinfo* 129 | Show selection info line. Equivalent to fzy's "--show-info" 130 | option. 131 | Default: 0 132 | 133 | term_highlight *g:fzy.term_highlight* 134 | Highlighting for the terminal window. 135 | Default: |hl-Terminal| 136 | 137 | popupwin *g:fzy.popupwin* 138 | If true, fzy is opened in a |popup-terminal|. The appearance of 139 | the popup window can be specified through the "popup" entry (see 140 | below). 141 | Default: |v:false| 142 | 143 | popup *g:fzy.popup* 144 | Dictionary for setting the appearance of the popup window. 145 | Default: `{'padding': [0,1,0,1], 'border': [], 'minwidth': 80}` 146 | 147 | The following popup options are supported: 148 | "line", "col", "pos", "minwidth", "drag", "resize", "close", 149 | "padding", "border", "borderhighlight", "borderchars", 150 | "highlight", and "zindex". For more details on each entry see 151 | |popup-usage| as well as the examples below. 152 | 153 | findcmd *g:fzy.findcmd* 154 | Set the find executable for the |:FzyFind| and |:FzyFindSplit| 155 | commands. Example: > 156 | g:fzy = {findcmd: 'fd --type f'} 157 | < 158 | The file-search command is always run in the specified search 159 | directory to avoid long file paths. 160 | 161 | If no |g:fzy.findcmd| is specified, the default find(1) executable 162 | is used: > 163 | find 164 | -name '.*' 165 | -a '!' -name . 166 | -a '!' -name .gitignore 167 | -a '!' -name .vim 168 | -a -prune 169 | -o '(' -type f -o -type l ')' 170 | -a -print 2> /dev/null 171 | | cut -b3- 172 | < 173 | Broken down the expression means: 174 | - ignore all files and directories starting with a dot, 175 | - except for the current directory, .gitignore and .vim 176 | - list only files and symlinks 177 | - the cut(1) command will remove the leading "./" from all 178 | file paths 179 | 180 | grepcmd *g:fzy.grepcmd* 181 | Set the grep executable for the |:FzyGrep| and |:FzyGrepSplit| 182 | commands. Example: > 183 | g:fzy = {grepcmd: 'rg --vimgrep'} 184 | < 185 | If not specified, defaults to 'grepprg'. 186 | 187 | Note: All arguments passed to |:FzyGrep| and |:FzyGrepSplit| are 188 | appended to |g:fzy.grepcmd|. I.e. running ":FzyGrep foo $PROJECT" 189 | will run "rg --vimgrep foo $PROJECT" in the 'shell' before passing 190 | the output to fzy. 191 | 192 | grepformat *g:fzy.grepformat* 193 | Set the format string for parsing the fuzzy-selected grep-output 194 | line. This is a scanf-like string that uses the same format as the 195 | 'grepformat' option. Example: > 196 | g:fzy = { 197 | grepcmd: 'rg --vimgrep', 198 | grepformat: '%f:%l:%c:%m' 199 | } 200 | < 201 | If not specified, defaults to 'grepformat'. 202 | 203 | histadd *g:fzy.histadd* 204 | Add the Ex command to Vim's command-line history. 205 | Default: |v:false| 206 | 207 | ============================================================================== 208 | CONFIGURATION EXAMPLES *fzy-config-examples* 209 | 210 | 1. Display 15 items, use a custom prompt, and show the selection info line: > 211 | g:fzy = { 212 | lines: 15, 213 | prompt: '>>> ', 214 | showinfo: true 215 | } 216 | 217 | 2. Same as 1. but display fzy in a popup window, use the default popup 218 | options: > 219 | g:fzy = { 220 | lines: 15, 221 | prompt: '>>> ', 222 | showinfo: true, 223 | popupwin: true 224 | } 225 | 226 | 3. Use a custom popup border and custom highlighting: > 227 | g:fzy = { 228 | lines: 15, 229 | showinfo: true, 230 | term_highlight: 'NormalDark', 231 | popupwin: true, 232 | popup: { 233 | minwidth: 90, 234 | highlight: 'NormalDark', 235 | borderchars: ['─', '│', '─', '│', '┌', '┐', '┘', '└'], 236 | padding: [0, 1, 0, 1], 237 | borderhighlight: ['GreyDark'] 238 | } 239 | } 240 | 241 | 4. Same as 3. but don't draw a popup border: > 242 | g:fzy = { 243 | lines: 15, 244 | showinfo: true, 245 | term_highlight: 'NormalDark', 246 | popupwin: true, 247 | popup: { 248 | minwidth: 90, 249 | highlight: 'NormalDark', 250 | borderchars: [' '], 251 | padding: [0, 1, 0, 1], 252 | borderhighlight: ['GreyDark'] 253 | } 254 | } 255 | 256 | 5. Display the popup window at the 5th screen line from the top of the 257 | screen: > 258 | g:fzy = { 259 | lines: 15, 260 | showinfo: true, 261 | popupwin: true, 262 | popup: { 263 | padding: [0, 1, 0, 1], 264 | pos: 'topleft', 265 | line: 5, 266 | } 267 | } 268 | 269 | 6. Find files using fd https://github.com/sharkdp/fd 270 | > 271 | g:fzy = {findcmd: 'fd --type f --type l --exclude tmp'} 272 | < 273 | 7. Find files using ripgrep https://github.com/BurntSushi/ripgrep 274 | > 275 | g:fzy = {findcmd: 'rg --files --no-messages'} 276 | < 277 | 8. Find files using the_silver_searcher 278 | https://github.com/ggreer/the_silver_searcher 279 | > 280 | g:fzy = {findcmd: 'ag --silent --ignore __pycache__ -g ""'} 281 | < 282 | 9. Find lines that match a pattern using grep(1): 283 | > 284 | g:fzy = {grepcmd: 'grep -Hn', grepformat: '%f:%l:%m'} 285 | < 286 | 10. Find lines that match a pattern using ripgrep: 287 | > 288 | g:fzy = { 289 | grepcmd: 'rg --vimgrep --smart-case --sort path', 290 | grepformat: '%f:%l:%c:%m' 291 | } 292 | < 293 | ============================================================================== 294 | API *fzy-api* 295 | 296 | *fzy.Start()* 297 | fzy.Start({items}, {callback} [, {options}]) 298 | Run fzy asynchronously in a new |terminal-window|. By default the fzy 299 | terminal buffer is opened in a normal window at the bottom of the 300 | screen. 301 | *fzy-E10* *fzy-E11* 302 | {items} must be a |string| or a |list| of strings. When a string is 303 | passed, the string will be run as a command in 'shell' and its output 304 | piped to fzy. If {items} is a list, on systems that support FIFOs 305 | (named pipes), the items are written to a FIFO and passed as stdin to 306 | fzy. On all other systems that do not provide an "mkfifo" command, the 307 | items are instead written to a temporary file on disk before passed to 308 | fzy. 309 | 310 | {callback} is a |Funcref| that is invoked after an item has been 311 | selected. The function is called after the terminal window is closed. 312 | The callback function is called with one argument, the selected item. 313 | See |fzy-api-examples| below. 314 | 315 | {options} is an optional |Dictionary| that can contain the following 316 | entries: 317 | 318 | "exe" Path to fzy executable. 319 | Default: value found in $PATH 320 | 321 | "lines" Specify how many lines of results to show. Minimum 322 | is 3 (limited by fzy) 323 | Default: 10 324 | 325 | "prompt" fzy input prompt. 326 | Default: "> " 327 | 328 | "showinfo" Whether to show the selection info line. If set to 329 | 1, fzy is invoked with the "--show-info" option. 330 | Default: |v:false| 331 | 332 | "statusline" Content of the 'statusline' for the terminal 333 | window. This entry is used only when fzy is 334 | displayed in a normal window. Popup windows do not 335 | have a statusline, use the "title" entry instead. 336 | Default: "fzy-term" 337 | 338 | "term_highlight" Highlight group for the terminal window. 339 | Default: |hl-Terminal| (normal window), |hl-Pmenu| 340 | (popup window) 341 | 342 | "popupwin" If true, fzy is opened in a |popup-terminal|. The 343 | appearance of the popup window can be specified 344 | through the "popup" entry (see below). 345 | Default: |v:false| 346 | 347 | "popup" Dictionary for setting popup options. The keys are 348 | similar to what is passed to |popup_create()|. The 349 | following keys can be used to change the 350 | appearance and position of the popup window: 351 | "line", "pos", "col", "minwidth", "title", "drag", 352 | "resize", "close", "highlight", "padding", 353 | "border", "borderhighlight", "borderchars", 354 | "zindex". See |popup-usage| for more details. 355 | Default: > 356 | { 357 | 'padding': [0,1,0,1], 358 | 'border': [], 359 | 'minwidth': 80 360 | } 361 | < 362 | Note: The height of the popup window is set automatically based on 363 | the "lines", "padding" and "border" entries. 364 | 365 | When "popupwin" is set to |v:false|, the terminal window is displayed 366 | at the bottom and occupy the full width of the Vim window. 367 | 368 | The function returns the buffer number of the terminal window. If 369 | opening the window fails zero is returned. 370 | 371 | fzy.Stop() *fzy-E12* *fzy.Stop()* 372 | Stop a running fzy process and close the corresponding terminal 373 | window. The function must be called with focus on a fzy terminal 374 | window. If the buffer is not a terminal window, an error is emitted. 375 | See |job_stop()| for details. 376 | 377 | *ft-fzy* 378 | The |filetype| of the terminal buffer where fzy is running is set to fzy. 379 | 380 | ============================================================================== 381 | EXAMPLES *fzy-api-examples* 382 | 383 | Fuzzy-select a |colorscheme|: 384 | > 385 | import autoload 'fzy.vim' 386 | 387 | # Callback function invoked with the selected item 388 | def Fzy_cb(item: string) 389 | execute 'colorscheme' item 390 | enddef 391 | 392 | def Setcolors() 393 | # List of colorschemes 394 | const items: list = getcompletion('', 'color') 395 | fzy.Start(items, funcref(Fzy_cb), { 396 | exe: expand('~/.local/bin/fzy'), 397 | lines: 15, 398 | prompt: '▶ ', 399 | statusline: ':colorscheme {name}' 400 | }) 401 | enddef 402 | 403 | command Color Setcolors() 404 | nnoremap c Setcolors() 405 | < 406 | vim:tw=78:et:ft=help:norl: 407 | -------------------------------------------------------------------------------- /ftplugin/fzy.vim: -------------------------------------------------------------------------------- 1 | vim9script 2 | # ============================================================================== 3 | # Run fzy asynchronously inside a Vim terminal-window 4 | # File: ftplugin/fzy.vim 5 | # Author: bfrg 6 | # Website: https://github.com/bfrg/vim-fzy 7 | # Last Change: Oct 21, 2022 8 | # License: Same as Vim itself (see :h license) 9 | # ============================================================================== 10 | 11 | tnoremap :call fzy#Stop() 12 | 13 | b:undo_ftplugin = 'execute "tunmap "' 14 | -------------------------------------------------------------------------------- /plugin/fzy.vim: -------------------------------------------------------------------------------- 1 | vim9script 2 | # ============================================================================== 3 | # Fuzzy-select files, buffers, args, tags, help tags, oldfiles, marks 4 | # File: plugin/fzy.vim 5 | # Author: bfrg 6 | # Website: https://github.com/bfrg/vim-fzy 7 | # Last Change: Dec 24, 2023 8 | # License: Same as Vim itself (see :h license) 9 | # ============================================================================== 10 | 11 | import autoload '../autoload/fzy.vim' 12 | 13 | command -nargs=? -complete=dir FzyFind fzy.Find(empty() ? getcwd() : , 'edit', '') 14 | command -nargs=? -complete=dir FzyFindSplit fzy.Find(empty() ? getcwd() : , 'split', ) 15 | 16 | command -nargs=+ -complete=file FzyGrep fzy.Grep('buffer', '', ) 17 | command -nargs=+ -complete=file FzyGrepSplit fzy.Grep('sbuffer', , ) 18 | 19 | command -bar -bang FzyBuffer fzy.Buffers('buffer', 0, '') 20 | command -bar -bang FzyBufferSplit fzy.Buffers('sbuffer', 0, ) 21 | 22 | command -bar -bang FzyMarks fzy.Marks(0) 23 | command -bar -bang FzyMarksSplit fzy.Marks(0, ) 24 | 25 | command -bar FzyOldfiles fzy.Oldfiles('edit', '') 26 | command -bar FzyOldfilesSplit fzy.Oldfiles('split', ) 27 | 28 | command -bar FzyArgs fzy.Arg('edit', false, '') 29 | command -bar FzyArgsSplit fzy.Arg('split', false, ) 30 | 31 | command -bar FzyLargs fzy.Arg('edit', true, '') 32 | command -bar FzyLargsSplit fzy.Arg('split', true, ) 33 | 34 | command -bar FzyTjump fzy.Tags('tjump', '') 35 | command -bar FzyTjumpSplit fzy.Tags('stjump', ) 36 | 37 | command -bar FzyHelp fzy.Help('help', ) 38 | --------------------------------------------------------------------------------