├── .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 |
--------------------------------------------------------------------------------