doing 2.0.20 → 2.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/doing.rdoc +1 -1
  6. data/lib/doing/version.rb +1 -1
  7. data/lib/helpers/fzf/.goreleaser.yml +119 -0
  8. data/lib/helpers/fzf/.rubocop.yml +28 -0
  9. data/lib/helpers/fzf/ADVANCED.md +565 -0
  10. data/lib/helpers/fzf/BUILD.md +49 -0
  11. data/lib/helpers/fzf/CHANGELOG.md +1193 -0
  12. data/lib/helpers/fzf/Dockerfile +11 -0
  13. data/lib/helpers/fzf/LICENSE +21 -0
  14. data/lib/helpers/fzf/Makefile +166 -0
  15. data/lib/helpers/fzf/README-VIM.md +486 -0
  16. data/lib/helpers/fzf/README.md +712 -0
  17. data/lib/helpers/fzf/bin/fzf-tmux +233 -0
  18. data/lib/helpers/fzf/doc/fzf.txt +512 -0
  19. data/lib/helpers/fzf/go.mod +17 -0
  20. data/lib/helpers/fzf/go.sum +31 -0
  21. data/lib/helpers/fzf/install +382 -0
  22. data/lib/helpers/fzf/install.ps1 +65 -0
  23. data/lib/helpers/fzf/main.go +14 -0
  24. data/lib/helpers/fzf/man/man1/fzf-tmux.1 +68 -0
  25. data/lib/helpers/fzf/man/man1/fzf.1 +1001 -0
  26. data/lib/helpers/fzf/plugin/fzf.vim +1048 -0
  27. data/lib/helpers/fzf/shell/completion.bash +381 -0
  28. data/lib/helpers/fzf/shell/completion.zsh +329 -0
  29. data/lib/helpers/fzf/shell/key-bindings.bash +96 -0
  30. data/lib/helpers/fzf/shell/key-bindings.fish +172 -0
  31. data/lib/helpers/fzf/shell/key-bindings.zsh +114 -0
  32. data/lib/helpers/fzf/src/LICENSE +21 -0
  33. data/lib/helpers/fzf/src/algo/algo.go +884 -0
  34. data/lib/helpers/fzf/src/algo/algo_test.go +197 -0
  35. data/lib/helpers/fzf/src/algo/normalize.go +492 -0
  36. data/lib/helpers/fzf/src/ansi.go +409 -0
  37. data/lib/helpers/fzf/src/ansi_test.go +427 -0
  38. data/lib/helpers/fzf/src/cache.go +81 -0
  39. data/lib/helpers/fzf/src/cache_test.go +39 -0
  40. data/lib/helpers/fzf/src/chunklist.go +89 -0
  41. data/lib/helpers/fzf/src/chunklist_test.go +80 -0
  42. data/lib/helpers/fzf/src/constants.go +85 -0
  43. data/lib/helpers/fzf/src/core.go +351 -0
  44. data/lib/helpers/fzf/src/history.go +96 -0
  45. data/lib/helpers/fzf/src/history_test.go +68 -0
  46. data/lib/helpers/fzf/src/item.go +44 -0
  47. data/lib/helpers/fzf/src/item_test.go +23 -0
  48. data/lib/helpers/fzf/src/matcher.go +235 -0
  49. data/lib/helpers/fzf/src/merger.go +120 -0
  50. data/lib/helpers/fzf/src/merger_test.go +88 -0
  51. data/lib/helpers/fzf/src/options.go +1691 -0
  52. data/lib/helpers/fzf/src/options_test.go +457 -0
  53. data/lib/helpers/fzf/src/pattern.go +425 -0
  54. data/lib/helpers/fzf/src/pattern_test.go +209 -0
  55. data/lib/helpers/fzf/src/protector/protector.go +8 -0
  56. data/lib/helpers/fzf/src/protector/protector_openbsd.go +10 -0
  57. data/lib/helpers/fzf/src/reader.go +201 -0
  58. data/lib/helpers/fzf/src/reader_test.go +63 -0
  59. data/lib/helpers/fzf/src/result.go +243 -0
  60. data/lib/helpers/fzf/src/result_others.go +16 -0
  61. data/lib/helpers/fzf/src/result_test.go +159 -0
  62. data/lib/helpers/fzf/src/result_x86.go +16 -0
  63. data/lib/helpers/fzf/src/terminal.go +2832 -0
  64. data/lib/helpers/fzf/src/terminal_test.go +638 -0
  65. data/lib/helpers/fzf/src/terminal_unix.go +26 -0
  66. data/lib/helpers/fzf/src/terminal_windows.go +45 -0
  67. data/lib/helpers/fzf/src/tokenizer.go +253 -0
  68. data/lib/helpers/fzf/src/tokenizer_test.go +112 -0
  69. data/lib/helpers/fzf/src/tui/dummy.go +46 -0
  70. data/lib/helpers/fzf/src/tui/light.go +987 -0
  71. data/lib/helpers/fzf/src/tui/light_unix.go +110 -0
  72. data/lib/helpers/fzf/src/tui/light_windows.go +145 -0
  73. data/lib/helpers/fzf/src/tui/tcell.go +721 -0
  74. data/lib/helpers/fzf/src/tui/tcell_test.go +392 -0
  75. data/lib/helpers/fzf/src/tui/ttyname_unix.go +47 -0
  76. data/lib/helpers/fzf/src/tui/ttyname_windows.go +14 -0
  77. data/lib/helpers/fzf/src/tui/tui.go +625 -0
  78. data/lib/helpers/fzf/src/tui/tui_test.go +20 -0
  79. data/lib/helpers/fzf/src/util/atomicbool.go +34 -0
  80. data/lib/helpers/fzf/src/util/atomicbool_test.go +17 -0
  81. data/lib/helpers/fzf/src/util/chars.go +198 -0
  82. data/lib/helpers/fzf/src/util/chars_test.go +46 -0
  83. data/lib/helpers/fzf/src/util/eventbox.go +96 -0
  84. data/lib/helpers/fzf/src/util/eventbox_test.go +61 -0
  85. data/lib/helpers/fzf/src/util/slab.go +12 -0
  86. data/lib/helpers/fzf/src/util/util.go +138 -0
  87. data/lib/helpers/fzf/src/util/util_test.go +40 -0
  88. data/lib/helpers/fzf/src/util/util_unix.go +47 -0
  89. data/lib/helpers/fzf/src/util/util_windows.go +83 -0
  90. data/lib/helpers/fzf/test/fzf.vader +175 -0
  91. data/lib/helpers/fzf/test/test_go.rb +2626 -0
  92. data/lib/helpers/fzf/uninstall +117 -0
  93. metadata +87 -1
@@ -0,0 +1,1048 @@
1
+ " Copyright (c) 2017 Junegunn Choi
2
+ "
3
+ " MIT License
4
+ "
5
+ " Permission is hereby granted, free of charge, to any person obtaining
6
+ " a copy of this software and associated documentation files (the
7
+ " "Software"), to deal in the Software without restriction, including
8
+ " without limitation the rights to use, copy, modify, merge, publish,
9
+ " distribute, sublicense, and/or sell copies of the Software, and to
10
+ " permit persons to whom the Software is furnished to do so, subject to
11
+ " the following conditions:
12
+ "
13
+ " The above copyright notice and this permission notice shall be
14
+ " included in all copies or substantial portions of the Software.
15
+ "
16
+ " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ if exists('g:loaded_fzf')
25
+ finish
26
+ endif
27
+ let g:loaded_fzf = 1
28
+
29
+ let s:is_win = has('win32') || has('win64')
30
+ if s:is_win && &shellslash
31
+ set noshellslash
32
+ let s:base_dir = expand('<sfile>:h:h')
33
+ set shellslash
34
+ else
35
+ let s:base_dir = expand('<sfile>:h:h')
36
+ endif
37
+ if s:is_win
38
+ let s:term_marker = '&::FZF'
39
+
40
+ function! s:fzf_call(fn, ...)
41
+ let shellslash = &shellslash
42
+ try
43
+ set noshellslash
44
+ return call(a:fn, a:000)
45
+ finally
46
+ let &shellslash = shellslash
47
+ endtry
48
+ endfunction
49
+
50
+ " Use utf-8 for fzf.vim commands
51
+ " Return array of shell commands for cmd.exe
52
+ function! s:enc_to_cp(str)
53
+ if !has('iconv')
54
+ return a:str
55
+ endif
56
+ if !exists('s:codepage')
57
+ let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0)
58
+ endif
59
+ return iconv(a:str, &encoding, 'cp'.s:codepage)
60
+ endfunction
61
+ function! s:wrap_cmds(cmds)
62
+ return map([
63
+ \ '@echo off',
64
+ \ 'setlocal enabledelayedexpansion']
65
+ \ + (has('gui_running') ? ['set TERM= > nul'] : [])
66
+ \ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds])
67
+ \ + ['endlocal'],
68
+ \ '<SID>enc_to_cp(v:val."\r")')
69
+ endfunction
70
+ else
71
+ let s:term_marker = ";#FZF"
72
+
73
+ function! s:fzf_call(fn, ...)
74
+ return call(a:fn, a:000)
75
+ endfunction
76
+
77
+ function! s:wrap_cmds(cmds)
78
+ return a:cmds
79
+ endfunction
80
+
81
+ function! s:enc_to_cp(str)
82
+ return a:str
83
+ endfunction
84
+ endif
85
+
86
+ function! s:shellesc_cmd(arg)
87
+ let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g')
88
+ let escaped = substitute(escaped, '%', '%%', 'g')
89
+ let escaped = substitute(escaped, '"', '\\^&', 'g')
90
+ let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g')
91
+ return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"'
92
+ endfunction
93
+
94
+ function! fzf#shellescape(arg, ...)
95
+ let shell = get(a:000, 0, s:is_win ? 'cmd.exe' : 'sh')
96
+ if shell =~# 'cmd.exe$'
97
+ return s:shellesc_cmd(a:arg)
98
+ endif
99
+ return s:fzf_call('shellescape', a:arg)
100
+ endfunction
101
+
102
+ function! s:fzf_getcwd()
103
+ return s:fzf_call('getcwd')
104
+ endfunction
105
+
106
+ function! s:fzf_fnamemodify(fname, mods)
107
+ return s:fzf_call('fnamemodify', a:fname, a:mods)
108
+ endfunction
109
+
110
+ function! s:fzf_expand(fmt)
111
+ return s:fzf_call('expand', a:fmt, 1)
112
+ endfunction
113
+
114
+ function! s:fzf_tempname()
115
+ return s:fzf_call('tempname')
116
+ endfunction
117
+
118
+ let s:layout_keys = ['window', 'tmux', 'up', 'down', 'left', 'right']
119
+ let s:fzf_go = s:base_dir.'/bin/fzf'
120
+ let s:fzf_tmux = s:base_dir.'/bin/fzf-tmux'
121
+
122
+ let s:cpo_save = &cpo
123
+ set cpo&vim
124
+
125
+ function! s:popup_support()
126
+ return has('nvim') ? has('nvim-0.4') : has('popupwin') && has('patch-8.2.191')
127
+ endfunction
128
+
129
+ function! s:default_layout()
130
+ return s:popup_support()
131
+ \ ? { 'window' : { 'width': 0.9, 'height': 0.6 } }
132
+ \ : { 'down': '~40%' }
133
+ endfunction
134
+
135
+ function! fzf#install()
136
+ if s:is_win && !has('win32unix')
137
+ let script = s:base_dir.'/install.ps1'
138
+ if !filereadable(script)
139
+ throw script.' not found'
140
+ endif
141
+ let script = 'powershell -ExecutionPolicy Bypass -file ' . script
142
+ else
143
+ let script = s:base_dir.'/install'
144
+ if !executable(script)
145
+ throw script.' not found'
146
+ endif
147
+ let script .= ' --bin'
148
+ endif
149
+
150
+ call s:warn('Running fzf installer ...')
151
+ call system(script)
152
+ if v:shell_error
153
+ throw 'Failed to download fzf: '.script
154
+ endif
155
+ endfunction
156
+
157
+ let s:versions = {}
158
+ function s:get_version(bin)
159
+ if has_key(s:versions, a:bin)
160
+ return s:versions[a:bin]
161
+ end
162
+ let command = a:bin . ' --version --no-height'
163
+ let output = systemlist(command)
164
+ if v:shell_error || empty(output)
165
+ return ''
166
+ endif
167
+ let ver = matchstr(output[-1], '[0-9.]\+')
168
+ let s:versions[a:bin] = ver
169
+ return ver
170
+ endfunction
171
+
172
+ function! s:compare_versions(a, b)
173
+ let a = split(a:a, '\.')
174
+ let b = split(a:b, '\.')
175
+ for idx in range(0, max([len(a), len(b)]) - 1)
176
+ let v1 = str2nr(get(a, idx, 0))
177
+ let v2 = str2nr(get(b, idx, 0))
178
+ if v1 < v2 | return -1
179
+ elseif v1 > v2 | return 1
180
+ endif
181
+ endfor
182
+ return 0
183
+ endfunction
184
+
185
+ function! s:compare_binary_versions(a, b)
186
+ return s:compare_versions(s:get_version(a:a), s:get_version(a:b))
187
+ endfunction
188
+
189
+ let s:checked = {}
190
+ function! fzf#exec(...)
191
+ if !exists('s:exec')
192
+ let binaries = []
193
+ if executable('fzf')
194
+ call add(binaries, 'fzf')
195
+ endif
196
+ if executable(s:fzf_go)
197
+ call add(binaries, s:fzf_go)
198
+ endif
199
+
200
+ if empty(binaries)
201
+ if input('fzf executable not found. Download binary? (y/n) ') =~? '^y'
202
+ redraw
203
+ call fzf#install()
204
+ return fzf#exec()
205
+ else
206
+ redraw
207
+ throw 'fzf executable not found'
208
+ endif
209
+ elseif len(binaries) > 1
210
+ call sort(binaries, 's:compare_binary_versions')
211
+ endif
212
+
213
+ let s:exec = binaries[-1]
214
+ endif
215
+
216
+ if a:0 && !has_key(s:checked, a:1)
217
+ let fzf_version = s:get_version(s:exec)
218
+ if empty(fzf_version)
219
+ let message = printf('Failed to run "%s --version"', s:exec)
220
+ unlet s:exec
221
+ throw message
222
+ end
223
+
224
+ if s:compare_versions(fzf_version, a:1) >= 0
225
+ let s:checked[a:1] = 1
226
+ return s:exec
227
+ elseif a:0 < 2 && input(printf('You need fzf %s or above. Found: %s. Download binary? (y/n) ', a:1, fzf_version)) =~? '^y'
228
+ let s:versions = {}
229
+ unlet s:exec
230
+ redraw
231
+ call fzf#install()
232
+ return fzf#exec(a:1, 1)
233
+ else
234
+ throw printf('You need to upgrade fzf (required: %s or above)', a:1)
235
+ endif
236
+ endif
237
+
238
+ return s:exec
239
+ endfunction
240
+
241
+ function! s:tmux_enabled()
242
+ if has('gui_running') || !exists('$TMUX')
243
+ return 0
244
+ endif
245
+
246
+ if exists('s:tmux')
247
+ return s:tmux
248
+ endif
249
+
250
+ let s:tmux = 0
251
+ if !executable(s:fzf_tmux)
252
+ if executable('fzf-tmux')
253
+ let s:fzf_tmux = 'fzf-tmux'
254
+ else
255
+ return 0
256
+ endif
257
+ endif
258
+
259
+ let output = system('tmux -V')
260
+ let s:tmux = !v:shell_error && output >= 'tmux 1.7'
261
+ return s:tmux
262
+ endfunction
263
+
264
+ function! s:escape(path)
265
+ let path = fnameescape(a:path)
266
+ return s:is_win ? escape(path, '$') : path
267
+ endfunction
268
+
269
+ function! s:error(msg)
270
+ echohl ErrorMsg
271
+ echom a:msg
272
+ echohl None
273
+ endfunction
274
+
275
+ function! s:warn(msg)
276
+ echohl WarningMsg
277
+ echom a:msg
278
+ echohl None
279
+ endfunction
280
+
281
+ function! s:has_any(dict, keys)
282
+ for key in a:keys
283
+ if has_key(a:dict, key)
284
+ return 1
285
+ endif
286
+ endfor
287
+ return 0
288
+ endfunction
289
+
290
+ function! s:open(cmd, target)
291
+ if stridx('edit', a:cmd) == 0 && s:fzf_fnamemodify(a:target, ':p') ==# s:fzf_expand('%:p')
292
+ return
293
+ endif
294
+ execute a:cmd s:escape(a:target)
295
+ endfunction
296
+
297
+ function! s:common_sink(action, lines) abort
298
+ if len(a:lines) < 2
299
+ return
300
+ endif
301
+ let key = remove(a:lines, 0)
302
+ let Cmd = get(a:action, key, 'e')
303
+ if type(Cmd) == type(function('call'))
304
+ return Cmd(a:lines)
305
+ endif
306
+ if len(a:lines) > 1
307
+ augroup fzf_swap
308
+ autocmd SwapExists * let v:swapchoice='o'
309
+ \| call s:warn('fzf: E325: swap file exists: '.s:fzf_expand('<afile>'))
310
+ augroup END
311
+ endif
312
+ try
313
+ let empty = empty(s:fzf_expand('%')) && line('$') == 1 && empty(getline(1)) && !&modified
314
+ " Preserve the current working directory in case it's changed during
315
+ " the execution (e.g. `set autochdir` or `autocmd BufEnter * lcd ...`)
316
+ let cwd = exists('w:fzf_pushd') ? w:fzf_pushd.dir : expand('%:p:h')
317
+ for item in a:lines
318
+ if item[0] != '~' && item !~ (s:is_win ? '^[A-Z]:\' : '^/')
319
+ let sep = s:is_win ? '\' : '/'
320
+ let item = join([cwd, item], cwd[len(cwd)-1] == sep ? '' : sep)
321
+ endif
322
+ if empty
323
+ execute 'e' s:escape(item)
324
+ let empty = 0
325
+ else
326
+ call s:open(Cmd, item)
327
+ endif
328
+ if !has('patch-8.0.0177') && !has('nvim-0.2') && exists('#BufEnter')
329
+ \ && isdirectory(item)
330
+ doautocmd BufEnter
331
+ endif
332
+ endfor
333
+ catch /^Vim:Interrupt$/
334
+ finally
335
+ silent! autocmd! fzf_swap
336
+ endtry
337
+ endfunction
338
+
339
+ function! s:get_color(attr, ...)
340
+ let gui = !s:is_win && !has('win32unix') && has('termguicolors') && &termguicolors
341
+ let fam = gui ? 'gui' : 'cterm'
342
+ let pat = gui ? '^#[a-f0-9]\+' : '^[0-9]\+$'
343
+ for group in a:000
344
+ let code = synIDattr(synIDtrans(hlID(group)), a:attr, fam)
345
+ if code =~? pat
346
+ return code
347
+ endif
348
+ endfor
349
+ return ''
350
+ endfunction
351
+
352
+ function! s:defaults()
353
+ let rules = copy(get(g:, 'fzf_colors', {}))
354
+ let colors = join(map(items(filter(map(rules, 'call("s:get_color", v:val)'), '!empty(v:val)')), 'join(v:val, ":")'), ',')
355
+ return empty(colors) ? '' : fzf#shellescape('--color='.colors)
356
+ endfunction
357
+
358
+ function! s:validate_layout(layout)
359
+ for key in keys(a:layout)
360
+ if index(s:layout_keys, key) < 0
361
+ throw printf('Invalid entry in g:fzf_layout: %s (allowed: %s)%s',
362
+ \ key, join(s:layout_keys, ', '), key == 'options' ? '. Use $FZF_DEFAULT_OPTS.' : '')
363
+ endif
364
+ endfor
365
+ return a:layout
366
+ endfunction
367
+
368
+ function! s:evaluate_opts(options)
369
+ return type(a:options) == type([]) ?
370
+ \ join(map(copy(a:options), 'fzf#shellescape(v:val)')) : a:options
371
+ endfunction
372
+
373
+ " [name string,] [opts dict,] [fullscreen boolean]
374
+ function! fzf#wrap(...)
375
+ let args = ['', {}, 0]
376
+ let expects = map(copy(args), 'type(v:val)')
377
+ let tidx = 0
378
+ for arg in copy(a:000)
379
+ let tidx = index(expects, type(arg) == 6 ? type(0) : type(arg), tidx)
380
+ if tidx < 0
381
+ throw 'Invalid arguments (expected: [name string] [opts dict] [fullscreen boolean])'
382
+ endif
383
+ let args[tidx] = arg
384
+ let tidx += 1
385
+ unlet arg
386
+ endfor
387
+ let [name, opts, bang] = args
388
+
389
+ if len(name)
390
+ let opts.name = name
391
+ end
392
+
393
+ " Layout: g:fzf_layout (and deprecated g:fzf_height)
394
+ if bang
395
+ for key in s:layout_keys
396
+ if has_key(opts, key)
397
+ call remove(opts, key)
398
+ endif
399
+ endfor
400
+ elseif !s:has_any(opts, s:layout_keys)
401
+ if !exists('g:fzf_layout') && exists('g:fzf_height')
402
+ let opts.down = g:fzf_height
403
+ else
404
+ let opts = extend(opts, s:validate_layout(get(g:, 'fzf_layout', s:default_layout())))
405
+ endif
406
+ endif
407
+
408
+ " Colors: g:fzf_colors
409
+ let opts.options = s:defaults() .' '. s:evaluate_opts(get(opts, 'options', ''))
410
+
411
+ " History: g:fzf_history_dir
412
+ if len(name) && len(get(g:, 'fzf_history_dir', ''))
413
+ let dir = s:fzf_expand(g:fzf_history_dir)
414
+ if !isdirectory(dir)
415
+ call mkdir(dir, 'p')
416
+ endif
417
+ let history = fzf#shellescape(dir.'/'.name)
418
+ let opts.options = join(['--history', history, opts.options])
419
+ endif
420
+
421
+ " Action: g:fzf_action
422
+ if !s:has_any(opts, ['sink', 'sinklist', 'sink*'])
423
+ let opts._action = get(g:, 'fzf_action', s:default_action)
424
+ let opts.options .= ' --expect='.join(keys(opts._action), ',')
425
+ function! opts.sinklist(lines) abort
426
+ return s:common_sink(self._action, a:lines)
427
+ endfunction
428
+ let opts['sink*'] = opts.sinklist " For backward compatibility
429
+ endif
430
+
431
+ return opts
432
+ endfunction
433
+
434
+ function! s:use_sh()
435
+ let [shell, shellslash, shellcmdflag, shellxquote] = [&shell, &shellslash, &shellcmdflag, &shellxquote]
436
+ if s:is_win
437
+ set shell=cmd.exe
438
+ set noshellslash
439
+ let &shellcmdflag = has('nvim') ? '/s /c' : '/c'
440
+ let &shellxquote = has('nvim') ? '"' : '('
441
+ else
442
+ set shell=sh
443
+ endif
444
+ return [shell, shellslash, shellcmdflag, shellxquote]
445
+ endfunction
446
+
447
+ function! fzf#run(...) abort
448
+ try
449
+ let [shell, shellslash, shellcmdflag, shellxquote] = s:use_sh()
450
+
451
+ let dict = exists('a:1') ? copy(a:1) : {}
452
+ let temps = { 'result': s:fzf_tempname() }
453
+ let optstr = s:evaluate_opts(get(dict, 'options', ''))
454
+ try
455
+ let fzf_exec = fzf#shellescape(fzf#exec())
456
+ catch
457
+ throw v:exception
458
+ endtry
459
+
460
+ if !s:present(dict, 'dir')
461
+ let dict.dir = s:fzf_getcwd()
462
+ endif
463
+ if has('win32unix') && s:present(dict, 'dir')
464
+ let dict.dir = fnamemodify(dict.dir, ':p')
465
+ endif
466
+
467
+ if has_key(dict, 'source')
468
+ let source = remove(dict, 'source')
469
+ let type = type(source)
470
+ if type == 1
471
+ let source_command = source
472
+ elseif type == 3
473
+ let temps.input = s:fzf_tempname()
474
+ call writefile(source, temps.input)
475
+ let source_command = (s:is_win ? 'type ' : 'cat ').fzf#shellescape(temps.input)
476
+ else
477
+ throw 'Invalid source type'
478
+ endif
479
+ else
480
+ let source_command = ''
481
+ endif
482
+
483
+ let prefer_tmux = get(g:, 'fzf_prefer_tmux', 0) || has_key(dict, 'tmux')
484
+ let use_height = has_key(dict, 'down') && !has('gui_running') &&
485
+ \ !(has('nvim') || s:is_win || has('win32unix') || s:present(dict, 'up', 'left', 'right', 'window')) &&
486
+ \ executable('tput') && filereadable('/dev/tty')
487
+ let has_vim8_term = has('terminal') && has('patch-8.0.995')
488
+ let has_nvim_term = has('nvim-0.2.1') || has('nvim') && !s:is_win
489
+ let use_term = has_nvim_term ||
490
+ \ has_vim8_term && !has('win32unix') && (has('gui_running') || s:is_win || s:present(dict, 'down', 'up', 'left', 'right', 'window'))
491
+ let use_tmux = (has_key(dict, 'tmux') || (!use_height && !use_term || prefer_tmux) && !has('win32unix') && s:splittable(dict)) && s:tmux_enabled()
492
+ if prefer_tmux && use_tmux
493
+ let use_height = 0
494
+ let use_term = 0
495
+ endif
496
+ if use_term
497
+ let optstr .= ' --no-height'
498
+ elseif use_height
499
+ let height = s:calc_size(&lines, dict.down, dict)
500
+ let optstr .= ' --height='.height
501
+ endif
502
+ let optstr .= s:border_opt(get(dict, 'window', 0))
503
+ let prev_default_command = $FZF_DEFAULT_COMMAND
504
+ if len(source_command)
505
+ let $FZF_DEFAULT_COMMAND = source_command
506
+ endif
507
+ let command = (use_tmux ? s:fzf_tmux(dict) : fzf_exec).' '.optstr.' > '.temps.result
508
+
509
+ if use_term
510
+ return s:execute_term(dict, command, temps)
511
+ endif
512
+
513
+ let lines = use_tmux ? s:execute_tmux(dict, command, temps)
514
+ \ : s:execute(dict, command, use_height, temps)
515
+ call s:callback(dict, lines)
516
+ return lines
517
+ finally
518
+ if len(source_command)
519
+ if len(prev_default_command)
520
+ let $FZF_DEFAULT_COMMAND = prev_default_command
521
+ else
522
+ let $FZF_DEFAULT_COMMAND = ''
523
+ silent! execute 'unlet $FZF_DEFAULT_COMMAND'
524
+ endif
525
+ endif
526
+ let [&shell, &shellslash, &shellcmdflag, &shellxquote] = [shell, shellslash, shellcmdflag, shellxquote]
527
+ endtry
528
+ endfunction
529
+
530
+ function! s:present(dict, ...)
531
+ for key in a:000
532
+ if !empty(get(a:dict, key, ''))
533
+ return 1
534
+ endif
535
+ endfor
536
+ return 0
537
+ endfunction
538
+
539
+ function! s:fzf_tmux(dict)
540
+ let size = get(a:dict, 'tmux', '')
541
+ if empty(size)
542
+ for o in ['up', 'down', 'left', 'right']
543
+ if s:present(a:dict, o)
544
+ let spec = a:dict[o]
545
+ if (o == 'up' || o == 'down') && spec[0] == '~'
546
+ let size = '-'.o[0].s:calc_size(&lines, spec, a:dict)
547
+ else
548
+ " Legacy boolean option
549
+ let size = '-'.o[0].(spec == 1 ? '' : substitute(spec, '^\~', '', ''))
550
+ endif
551
+ break
552
+ endif
553
+ endfor
554
+ endif
555
+ return printf('LINES=%d COLUMNS=%d %s %s - --',
556
+ \ &lines, &columns, fzf#shellescape(s:fzf_tmux), size)
557
+ endfunction
558
+
559
+ function! s:splittable(dict)
560
+ return s:present(a:dict, 'up', 'down') && &lines > 15 ||
561
+ \ s:present(a:dict, 'left', 'right') && &columns > 40
562
+ endfunction
563
+
564
+ function! s:pushd(dict)
565
+ if s:present(a:dict, 'dir')
566
+ let cwd = s:fzf_getcwd()
567
+ let w:fzf_pushd = {
568
+ \ 'command': haslocaldir() ? 'lcd' : (exists(':tcd') && haslocaldir(-1) ? 'tcd' : 'cd'),
569
+ \ 'origin': cwd,
570
+ \ 'bufname': bufname('')
571
+ \ }
572
+ execute 'lcd' s:escape(a:dict.dir)
573
+ let cwd = s:fzf_getcwd()
574
+ let w:fzf_pushd.dir = cwd
575
+ let a:dict.pushd = w:fzf_pushd
576
+ return cwd
577
+ endif
578
+ return ''
579
+ endfunction
580
+
581
+ augroup fzf_popd
582
+ autocmd!
583
+ autocmd WinEnter * call s:dopopd()
584
+ augroup END
585
+
586
+ function! s:dopopd()
587
+ if !exists('w:fzf_pushd')
588
+ return
589
+ endif
590
+
591
+ " FIXME: We temporarily change the working directory to 'dir' entry
592
+ " of options dictionary (set to the current working directory if not given)
593
+ " before running fzf.
594
+ "
595
+ " e.g. call fzf#run({'dir': '/tmp', 'source': 'ls', 'sink': 'e'})
596
+ "
597
+ " After processing the sink function, we have to restore the current working
598
+ " directory. But doing so may not be desirable if the function changed the
599
+ " working directory on purpose.
600
+ "
601
+ " So how can we tell if we should do it or not? A simple heuristic we use
602
+ " here is that we change directory only if the current working directory
603
+ " matches 'dir' entry. However, it is possible that the sink function did
604
+ " change the directory to 'dir'. In that case, the user will have an
605
+ " unexpected result.
606
+ if s:fzf_getcwd() ==# w:fzf_pushd.dir && (!&autochdir || w:fzf_pushd.bufname ==# bufname(''))
607
+ execute w:fzf_pushd.command s:escape(w:fzf_pushd.origin)
608
+ endif
609
+ unlet! w:fzf_pushd
610
+ endfunction
611
+
612
+ function! s:xterm_launcher()
613
+ let fmt = 'xterm -T "[fzf]" -bg "%s" -fg "%s" -geometry %dx%d+%d+%d -e bash -ic %%s'
614
+ if has('gui_macvim')
615
+ let fmt .= '&& osascript -e "tell application \"MacVim\" to activate"'
616
+ endif
617
+ return printf(fmt,
618
+ \ escape(synIDattr(hlID("Normal"), "bg"), '#'), escape(synIDattr(hlID("Normal"), "fg"), '#'),
619
+ \ &columns, &lines/2, getwinposx(), getwinposy())
620
+ endfunction
621
+ unlet! s:launcher
622
+ if s:is_win || has('win32unix')
623
+ let s:launcher = '%s'
624
+ else
625
+ let s:launcher = function('s:xterm_launcher')
626
+ endif
627
+
628
+ function! s:exit_handler(code, command, ...)
629
+ if a:code == 130
630
+ return 0
631
+ elseif has('nvim') && a:code == 129
632
+ " When deleting the terminal buffer while fzf is still running,
633
+ " Nvim sends SIGHUP.
634
+ return 0
635
+ elseif a:code > 1
636
+ call s:error('Error running ' . a:command)
637
+ if !empty(a:000)
638
+ sleep
639
+ endif
640
+ return 0
641
+ endif
642
+ return 1
643
+ endfunction
644
+
645
+ function! s:execute(dict, command, use_height, temps) abort
646
+ call s:pushd(a:dict)
647
+ if has('unix') && !a:use_height
648
+ silent! !clear 2> /dev/null
649
+ endif
650
+ let escaped = (a:use_height || s:is_win) ? a:command : escape(substitute(a:command, '\n', '\\n', 'g'), '%#!')
651
+ if has('gui_running')
652
+ let Launcher = get(a:dict, 'launcher', get(g:, 'Fzf_launcher', get(g:, 'fzf_launcher', s:launcher)))
653
+ let fmt = type(Launcher) == 2 ? call(Launcher, []) : Launcher
654
+ if has('unix')
655
+ let escaped = "'".substitute(escaped, "'", "'\"'\"'", 'g')."'"
656
+ endif
657
+ let command = printf(fmt, escaped)
658
+ else
659
+ let command = escaped
660
+ endif
661
+ if s:is_win
662
+ let batchfile = s:fzf_tempname().'.bat'
663
+ call writefile(s:wrap_cmds(command), batchfile)
664
+ let command = batchfile
665
+ let a:temps.batchfile = batchfile
666
+ if has('nvim')
667
+ let fzf = {}
668
+ let fzf.dict = a:dict
669
+ let fzf.temps = a:temps
670
+ function! fzf.on_exit(job_id, exit_status, event) dict
671
+ call s:pushd(self.dict)
672
+ let lines = s:collect(self.temps)
673
+ call s:callback(self.dict, lines)
674
+ endfunction
675
+ let cmd = 'start /wait cmd /c '.command
676
+ call jobstart(cmd, fzf)
677
+ return []
678
+ endif
679
+ elseif has('win32unix') && $TERM !=# 'cygwin'
680
+ let shellscript = s:fzf_tempname()
681
+ call writefile([command], shellscript)
682
+ let command = 'cmd.exe /C '.fzf#shellescape('set "TERM=" & start /WAIT sh -c '.shellscript)
683
+ let a:temps.shellscript = shellscript
684
+ endif
685
+ if a:use_height
686
+ call system(printf('tput cup %d > /dev/tty; tput cnorm > /dev/tty; %s < /dev/tty 2> /dev/tty', &lines, command))
687
+ else
688
+ execute 'silent !'.command
689
+ endif
690
+ let exit_status = v:shell_error
691
+ redraw!
692
+ let lines = s:collect(a:temps)
693
+ return s:exit_handler(exit_status, command) ? lines : []
694
+ endfunction
695
+
696
+ function! s:execute_tmux(dict, command, temps) abort
697
+ let command = a:command
698
+ let cwd = s:pushd(a:dict)
699
+ if len(cwd)
700
+ " -c '#{pane_current_path}' is only available on tmux 1.9 or above
701
+ let command = join(['cd', fzf#shellescape(cwd), '&&', command])
702
+ endif
703
+
704
+ call system(command)
705
+ let exit_status = v:shell_error
706
+ redraw!
707
+ let lines = s:collect(a:temps)
708
+ return s:exit_handler(exit_status, command) ? lines : []
709
+ endfunction
710
+
711
+ function! s:calc_size(max, val, dict)
712
+ let val = substitute(a:val, '^\~', '', '')
713
+ if val =~ '%$'
714
+ let size = a:max * str2nr(val[:-2]) / 100
715
+ else
716
+ let size = min([a:max, str2nr(val)])
717
+ endif
718
+
719
+ let srcsz = -1
720
+ if type(get(a:dict, 'source', 0)) == type([])
721
+ let srcsz = len(a:dict.source)
722
+ endif
723
+
724
+ let opts = $FZF_DEFAULT_OPTS.' '.s:evaluate_opts(get(a:dict, 'options', ''))
725
+ if opts =~ 'preview'
726
+ return size
727
+ endif
728
+ let margin = match(opts, '--inline-info\|--info[^-]\{-}inline') > match(opts, '--no-inline-info\|--info[^-]\{-}\(default\|hidden\)') ? 1 : 2
729
+ let margin += stridx(opts, '--border') > stridx(opts, '--no-border') ? 2 : 0
730
+ if stridx(opts, '--header') > stridx(opts, '--no-header')
731
+ let margin += len(split(opts, "\n"))
732
+ endif
733
+ return srcsz >= 0 ? min([srcsz + margin, size]) : size
734
+ endfunction
735
+
736
+ function! s:getpos()
737
+ return {'tab': tabpagenr(), 'win': winnr(), 'winid': win_getid(), 'cnt': winnr('$'), 'tcnt': tabpagenr('$')}
738
+ endfunction
739
+
740
+ function! s:border_opt(window)
741
+ if type(a:window) != type({})
742
+ return ''
743
+ endif
744
+
745
+ " Border style
746
+ let style = tolower(get(a:window, 'border', 'rounded'))
747
+ if !has_key(a:window, 'border') && !get(a:window, 'rounded', 1)
748
+ let style = 'sharp'
749
+ endif
750
+ if style == 'none' || style == 'no'
751
+ return ''
752
+ endif
753
+
754
+ " For --border styles, we need fzf 0.24.0 or above
755
+ call fzf#exec('0.24.0')
756
+ let opt = ' --border=' . style
757
+ if has_key(a:window, 'highlight')
758
+ let color = s:get_color('fg', a:window.highlight)
759
+ if len(color)
760
+ let opt .= ' --color=border:' . color
761
+ endif
762
+ endif
763
+ return opt
764
+ endfunction
765
+
766
+ function! s:split(dict)
767
+ let directions = {
768
+ \ 'up': ['topleft', 'resize', &lines],
769
+ \ 'down': ['botright', 'resize', &lines],
770
+ \ 'left': ['vertical topleft', 'vertical resize', &columns],
771
+ \ 'right': ['vertical botright', 'vertical resize', &columns] }
772
+ let ppos = s:getpos()
773
+ let is_popup = 0
774
+ try
775
+ if s:present(a:dict, 'window')
776
+ if type(a:dict.window) == type({})
777
+ if !s:popup_support()
778
+ throw 'Nvim 0.4+ or Vim 8.2.191+ with popupwin feature is required for pop-up window'
779
+ end
780
+ call s:popup(a:dict.window)
781
+ let is_popup = 1
782
+ else
783
+ execute 'keepalt' a:dict.window
784
+ endif
785
+ elseif !s:splittable(a:dict)
786
+ execute (tabpagenr()-1).'tabnew'
787
+ else
788
+ for [dir, triple] in items(directions)
789
+ let val = get(a:dict, dir, '')
790
+ if !empty(val)
791
+ let [cmd, resz, max] = triple
792
+ if (dir == 'up' || dir == 'down') && val[0] == '~'
793
+ let sz = s:calc_size(max, val, a:dict)
794
+ else
795
+ let sz = s:calc_size(max, val, {})
796
+ endif
797
+ execute cmd sz.'new'
798
+ execute resz sz
799
+ return [ppos, {}, is_popup]
800
+ endif
801
+ endfor
802
+ endif
803
+ return [ppos, is_popup ? {} : { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }, is_popup]
804
+ finally
805
+ if !is_popup
806
+ setlocal winfixwidth winfixheight
807
+ endif
808
+ endtry
809
+ endfunction
810
+
811
+ nnoremap <silent> <Plug>(fzf-insert) i
812
+ nnoremap <silent> <Plug>(fzf-normal) <Nop>
813
+ if exists(':tnoremap')
814
+ tnoremap <silent> <Plug>(fzf-insert) <C-\><C-n>i
815
+ tnoremap <silent> <Plug>(fzf-normal) <C-\><C-n>
816
+ endif
817
+
818
+ function! s:execute_term(dict, command, temps) abort
819
+ let winrest = winrestcmd()
820
+ let pbuf = bufnr('')
821
+ let [ppos, winopts, is_popup] = s:split(a:dict)
822
+ call s:use_sh()
823
+ let b:fzf = a:dict
824
+ let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,
825
+ \ 'winopts': winopts, 'winrest': winrest, 'lines': &lines,
826
+ \ 'columns': &columns, 'command': a:command }
827
+ function! fzf.switch_back(inplace)
828
+ if a:inplace && bufnr('') == self.buf
829
+ if bufexists(self.pbuf)
830
+ execute 'keepalt keepjumps b' self.pbuf
831
+ endif
832
+ " No other listed buffer
833
+ if bufnr('') == self.buf
834
+ enew
835
+ endif
836
+ endif
837
+ endfunction
838
+ function! fzf.on_exit(id, code, ...)
839
+ if s:getpos() == self.ppos " {'window': 'enew'}
840
+ for [opt, val] in items(self.winopts)
841
+ execute 'let' opt '=' val
842
+ endfor
843
+ call self.switch_back(1)
844
+ else
845
+ if bufnr('') == self.buf
846
+ " We use close instead of bd! since Vim does not close the split when
847
+ " there's no other listed buffer (nvim +'set nobuflisted')
848
+ close
849
+ endif
850
+ silent! execute 'tabnext' self.ppos.tab
851
+ silent! execute self.ppos.win.'wincmd w'
852
+ endif
853
+
854
+ if bufexists(self.buf)
855
+ execute 'bd!' self.buf
856
+ endif
857
+
858
+ if &lines == self.lines && &columns == self.columns && s:getpos() == self.ppos
859
+ execute self.winrest
860
+ endif
861
+
862
+ let lines = s:collect(self.temps)
863
+ if !s:exit_handler(a:code, self.command, 1)
864
+ return
865
+ endif
866
+
867
+ call s:pushd(self.dict)
868
+ call s:callback(self.dict, lines)
869
+ call self.switch_back(s:getpos() == self.ppos)
870
+
871
+ if &buftype == 'terminal'
872
+ call feedkeys(&filetype == 'fzf' ? "\<Plug>(fzf-insert)" : "\<Plug>(fzf-normal)")
873
+ endif
874
+ endfunction
875
+
876
+ try
877
+ call s:pushd(a:dict)
878
+ if s:is_win
879
+ let fzf.temps.batchfile = s:fzf_tempname().'.bat'
880
+ call writefile(s:wrap_cmds(a:command), fzf.temps.batchfile)
881
+ let command = fzf.temps.batchfile
882
+ else
883
+ let command = a:command
884
+ endif
885
+ let command .= s:term_marker
886
+ if has('nvim')
887
+ call termopen(command, fzf)
888
+ else
889
+ let term_opts = {'exit_cb': function(fzf.on_exit)}
890
+ if v:version >= 802
891
+ let term_opts.term_kill = 'term'
892
+ endif
893
+ if is_popup
894
+ let term_opts.hidden = 1
895
+ else
896
+ let term_opts.curwin = 1
897
+ endif
898
+ let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts)
899
+ if is_popup && exists('#TerminalWinOpen')
900
+ doautocmd <nomodeline> TerminalWinOpen
901
+ endif
902
+ if !has('patch-8.0.1261') && !s:is_win
903
+ call term_wait(fzf.buf, 20)
904
+ endif
905
+ endif
906
+ tnoremap <buffer> <c-z> <nop>
907
+ if exists('&termwinkey') && (empty(&termwinkey) || &termwinkey =~? '<c-w>')
908
+ tnoremap <buffer> <c-w> <c-w>.
909
+ endif
910
+ finally
911
+ call s:dopopd()
912
+ endtry
913
+ setlocal nospell bufhidden=wipe nobuflisted nonumber
914
+ setf fzf
915
+ startinsert
916
+ return []
917
+ endfunction
918
+
919
+ function! s:collect(temps) abort
920
+ try
921
+ return filereadable(a:temps.result) ? readfile(a:temps.result) : []
922
+ finally
923
+ for tf in values(a:temps)
924
+ silent! call delete(tf)
925
+ endfor
926
+ endtry
927
+ endfunction
928
+
929
+ function! s:callback(dict, lines) abort
930
+ let popd = has_key(a:dict, 'pushd')
931
+ if popd
932
+ let w:fzf_pushd = a:dict.pushd
933
+ endif
934
+
935
+ try
936
+ if has_key(a:dict, 'sink')
937
+ for line in a:lines
938
+ if type(a:dict.sink) == 2
939
+ call a:dict.sink(line)
940
+ else
941
+ execute a:dict.sink s:escape(line)
942
+ endif
943
+ endfor
944
+ endif
945
+ if has_key(a:dict, 'sink*')
946
+ call a:dict['sink*'](a:lines)
947
+ elseif has_key(a:dict, 'sinklist')
948
+ call a:dict['sinklist'](a:lines)
949
+ endif
950
+ catch
951
+ if stridx(v:exception, ':E325:') < 0
952
+ echoerr v:exception
953
+ endif
954
+ endtry
955
+
956
+ " We may have opened a new window or tab
957
+ if popd
958
+ let w:fzf_pushd = a:dict.pushd
959
+ call s:dopopd()
960
+ endif
961
+ endfunction
962
+
963
+ if has('nvim')
964
+ function s:create_popup(hl, opts) abort
965
+ let buf = nvim_create_buf(v:false, v:true)
966
+ let opts = extend({'relative': 'editor', 'style': 'minimal'}, a:opts)
967
+ let win = nvim_open_win(buf, v:true, opts)
968
+ call setwinvar(win, '&winhighlight', 'NormalFloat:'..a:hl)
969
+ call setwinvar(win, '&colorcolumn', '')
970
+ return buf
971
+ endfunction
972
+ else
973
+ function! s:create_popup(hl, opts) abort
974
+ let s:popup_create = {buf -> popup_create(buf, #{
975
+ \ line: a:opts.row,
976
+ \ col: a:opts.col,
977
+ \ minwidth: a:opts.width,
978
+ \ maxwidth: a:opts.width,
979
+ \ minheight: a:opts.height,
980
+ \ maxheight: a:opts.height,
981
+ \ zindex: 1000,
982
+ \ })}
983
+ autocmd TerminalOpen * ++once call s:popup_create(str2nr(expand('<abuf>')))
984
+ endfunction
985
+ endif
986
+
987
+ function! s:popup(opts) abort
988
+ let xoffset = get(a:opts, 'xoffset', 0.5)
989
+ let yoffset = get(a:opts, 'yoffset', 0.5)
990
+ let relative = get(a:opts, 'relative', 0)
991
+
992
+ " Use current window size for positioning relatively positioned popups
993
+ let columns = relative ? winwidth(0) : &columns
994
+ let lines = relative ? winheight(0) : (&lines - has('nvim'))
995
+
996
+ " Size and position
997
+ let width = min([max([8, a:opts.width > 1 ? a:opts.width : float2nr(columns * a:opts.width)]), columns])
998
+ let height = min([max([4, a:opts.height > 1 ? a:opts.height : float2nr(lines * a:opts.height)]), lines])
999
+ let row = float2nr(yoffset * (lines - height)) + (relative ? win_screenpos(0)[0] - 1 : 0)
1000
+ let col = float2nr(xoffset * (columns - width)) + (relative ? win_screenpos(0)[1] - 1 : 0)
1001
+
1002
+ " Managing the differences
1003
+ let row = min([max([0, row]), &lines - has('nvim') - height])
1004
+ let col = min([max([0, col]), &columns - width])
1005
+ let row += !has('nvim')
1006
+ let col += !has('nvim')
1007
+
1008
+ call s:create_popup('Normal', {
1009
+ \ 'row': row, 'col': col, 'width': width, 'height': height
1010
+ \ })
1011
+ endfunction
1012
+
1013
+ let s:default_action = {
1014
+ \ 'ctrl-t': 'tab split',
1015
+ \ 'ctrl-x': 'split',
1016
+ \ 'ctrl-v': 'vsplit' }
1017
+
1018
+ function! s:shortpath()
1019
+ let short = fnamemodify(getcwd(), ':~:.')
1020
+ if !has('win32unix')
1021
+ let short = pathshorten(short)
1022
+ endif
1023
+ let slash = (s:is_win && !&shellslash) ? '\' : '/'
1024
+ return empty(short) ? '~'.slash : short . (short =~ escape(slash, '\').'$' ? '' : slash)
1025
+ endfunction
1026
+
1027
+ function! s:cmd(bang, ...) abort
1028
+ let args = copy(a:000)
1029
+ let opts = { 'options': ['--multi'] }
1030
+ if len(args) && isdirectory(expand(args[-1]))
1031
+ let opts.dir = substitute(substitute(remove(args, -1), '\\\(["'']\)', '\1', 'g'), '[/\\]*$', '/', '')
1032
+ if s:is_win && !&shellslash
1033
+ let opts.dir = substitute(opts.dir, '/', '\\', 'g')
1034
+ endif
1035
+ let prompt = opts.dir
1036
+ else
1037
+ let prompt = s:shortpath()
1038
+ endif
1039
+ let prompt = strwidth(prompt) < &columns - 20 ? prompt : '> '
1040
+ call extend(opts.options, ['--prompt', prompt])
1041
+ call extend(opts.options, args)
1042
+ call fzf#run(fzf#wrap('FZF', opts, a:bang))
1043
+ endfunction
1044
+
1045
+ command! -nargs=* -complete=dir -bang FZF call s:cmd(<bang>0, <f-args>)
1046
+
1047
+ let &cpo = s:cpo_save
1048
+ unlet s:cpo_save