0
|
1 "============================================================================= |
|
2 " fuzzyfinder.vim : Fuzzy/Partial pattern explorer for |
|
3 " buffer/file/MRU/command/favorite/tag/etc. |
|
4 "============================================================================= |
|
5 " |
|
6 " Author: Takeshi NISHIDA <ns9tks@DELETE-ME.gmail.com> |
|
7 " Version: 2.13, for Vim 7.1 |
|
8 " Licence: MIT Licence |
|
9 " URL: http://www.vim.org/scripts/script.php?script_id=1984 |
|
10 " |
|
11 " GetLatestVimScripts: 1984 1 :AutoInstall: fuzzyfinder.vim |
|
12 " |
|
13 "============================================================================= |
|
14 " DOCUMENT: {{{1 |
|
15 " Japanese: http://vim.g.hatena.ne.jp/keyword/fuzzyfinder.vim |
|
16 " |
|
17 "----------------------------------------------------------------------------- |
|
18 " Description: |
|
19 " Fuzzyfinder provides convenient ways to quickly reach the buffer/file you |
|
20 " want. Fuzzyfinder finds matching files/buffers with a fuzzy/partial |
|
21 " pattern to which it converted the entered pattern. |
|
22 " |
|
23 " E.g.: entered pattern -> fuzzy pattern / partial pattern |
|
24 " abc -> *a*b*c* / *abc* |
|
25 " a?c -> *a?c* / *a?c* |
|
26 " dir/file -> dir/*f*i*l*e* / dir/*file* |
|
27 " d*r/file -> d*r/*f*i*l*e* / d*r/*file* |
|
28 " ../**/s -> ../**/*s* / ../**/*s* |
|
29 " |
|
30 " (** allows searching a directory tree.) |
|
31 " |
|
32 " You will be happy when: |
|
33 " "./OhLongLongLongLongLongFile.txt" |
|
34 " "./AhLongLongLongLongLongName.txt" |
|
35 " "./AhLongLongLongLongLongFile.txt" <- you want :O |
|
36 " Type "AF" and "AhLongLongLongLongLongFile.txt" will be select. :D |
|
37 " |
|
38 " Fuzzyfinder has some modes: |
|
39 " - Buffer mode |
|
40 " - File mode |
|
41 " - Directory mode (yet another :cd command) |
|
42 " - MRU-file mode (most recently used files) |
|
43 " - MRU-command mode (most recently used command-lines) |
|
44 " - Favorite-file mode |
|
45 " - Tag mode (yet another :tag command) |
|
46 " - Tagged-file mode (files which are included in current tags) |
|
47 " |
|
48 " Fuzzyfinder supports the multibyte. |
|
49 " |
|
50 "----------------------------------------------------------------------------- |
|
51 " Installation: |
|
52 " Drop this file in your plugin directory. |
|
53 " |
|
54 "----------------------------------------------------------------------------- |
|
55 " Usage: |
|
56 " Starting Fuzzyfinder: |
|
57 " You can start Fuzzyfinder by the following commands: |
|
58 " |
|
59 " :FuzzyFinderBuffer - launchs buffer-mode Fuzzyfinder. |
|
60 " :FuzzyFinderFile - launchs file-mode Fuzzyfinder. |
|
61 " :FuzzyFinderDir - launchs directory-mode Fuzzyfinder. |
|
62 " :FuzzyFinderMruFile - launchs MRU-file-mode Fuzzyfinder. |
|
63 " :FuzzyFinderMruCmd - launchs MRU-command-mode Fuzzyfinder. |
|
64 " :FuzzyFinderFavFile - launchs favorite-file-mode Fuzzyfinder. |
|
65 " :FuzzyFinderTag - launchs tag-mode Fuzzyfinder. |
|
66 " :FuzzyFinderTaggedFile - launchs tagged-file-mode Fuzzyfinder. |
|
67 " |
|
68 " It is recommended to map these commands. These commands can take initial |
|
69 " text as a command argument. The text will be entered after Fuzzyfinder |
|
70 " launched. If a command was executed with a ! modifier (e.g. |
|
71 " :FuzzyFinderTag!), it enables the partial matching instead of the fuzzy |
|
72 " matching. |
|
73 " |
|
74 " |
|
75 " In Fuzzyfinder: |
|
76 " The entered pattern is converted to the fuzzy pattern and buffers/files |
|
77 " which match the pattern is shown in a completion menu. |
|
78 " |
|
79 " A completion menu is shown when you type at the end of the line and the |
|
80 " length of entered pattern is more than setting value. By default, it is |
|
81 " shown at the beginning. |
|
82 " |
|
83 " If too many items (200, by default) were matched, the completion is |
|
84 " aborted to reduce nonresponse. |
|
85 " |
|
86 " If an item were matched with entered pattern exactly, it is shown first. |
|
87 " The item whose file name has longer prefix matching is placed upper. |
|
88 " Also, an item which matched more sequentially is placed upper. The item |
|
89 " whose index were matched with a number suffixed with entered pattern is |
|
90 " placed lower. the first item in the completion menu will be selected |
|
91 " automatically. |
|
92 " |
|
93 " You can open a selected item in various ways: |
|
94 " <CR> - opens in a previous window. |
|
95 " <C-j> - opens in a split window. |
|
96 " <C-k> - opens in a vertical-split window. |
|
97 " <C-]> - opens in a new tab page. |
|
98 " In MRU-command mode, <CR> executes a selected command and others just |
|
99 " put it into a command-line. These key mappings are customizable. |
|
100 " |
|
101 " To cancel and return to previous window, leave Insert mode. |
|
102 " |
|
103 " To Switch the mode without leaving Insert mode, use <C-l> or <C-o>. |
|
104 " This key mapping is customizable. |
|
105 " |
|
106 " If you want to temporarily change whether or not to ignore case, use |
|
107 " <C-t>. This key mapping is customizable. |
|
108 " |
|
109 " To Hide The Completion Temporarily Menu In Fuzzyfinder: |
|
110 " You can close it by <C-e> and reopen it by <C-x><C-u>. |
|
111 " |
|
112 " About Highlighting: |
|
113 " Fuzzyfinder highlights the buffer with "Error" group when the completion |
|
114 " item was not found or the completion process was aborted. |
|
115 " |
|
116 " About Alternative Approach For Tag Jump: |
|
117 " Following mappings are replacements for :tag and <C-]>: |
|
118 " |
|
119 " nnoremap <silent> <C-f><C-t> :FuzzyFinderTag!<CR> |
|
120 " nnoremap <silent> <C-]> :FuzzyFinderTag! <C-r>=expand('<cword>')<CR><CR> |
|
121 " |
|
122 " In the tag mode, it is recommended to use partial matching instead of |
|
123 " fuzzy matching. |
|
124 " |
|
125 " About Tagged File Mode: |
|
126 " The files which are included in the current tags are the ones which are |
|
127 " related to the current working environment. So this mode is a pseudo |
|
128 " project mode. |
|
129 " |
|
130 " About Usage Of Command Argument: |
|
131 " As an example, if you want to launch file-mode Fuzzyfinder with the full |
|
132 " path of current directory, map like below: |
|
133 " |
|
134 " nnoremap <C-p> :FuzzyFinderFile <C-r>=fnamemodify(getcwd(), ':p')<CR><CR> |
|
135 " |
|
136 " Instead, if you want the directory of current buffer and not current |
|
137 " directory: |
|
138 " |
|
139 " nnoremap <C-p> :FuzzyFinderFile <C-r>=expand('%:~:.')[:-1-len(expand('%:~:.:t'))]<CR><CR> |
|
140 " |
|
141 " About Abbreviations And Multiple Search: |
|
142 " You can use abbreviations and multiple search in each mode. For example, |
|
143 " set as below: |
|
144 " |
|
145 " let g:FuzzyFinderOptions.Base.abbrev_map = { |
|
146 " \ "^WORK" : [ |
|
147 " \ "~/project/**/src/", |
|
148 " \ ".vim/plugin/", |
|
149 " \ ], |
|
150 " \ } |
|
151 " |
|
152 " And type "WORKtxt" in file-mode Fuzzyfinder, then it searches by |
|
153 " following patterns: |
|
154 " |
|
155 " "~/project/**/src/*t*x*t*" |
|
156 " ".vim/plugin/*t*x*t*" |
|
157 " |
|
158 " Adding Favorite Files: |
|
159 " You can add a favorite file by the following commands: |
|
160 " |
|
161 " :FuzzyFinderAddFavFile {filename} |
|
162 " |
|
163 " If you do not specify the filename, current file name is used. |
|
164 " |
|
165 " About Information File: |
|
166 " Fuzzyfinder writes information of the MRU, favorite, etc to the file by |
|
167 " default (~/.vimfuzzyfinder). |
|
168 |
|
169 " :FuzzyFinderEditInfo command is helpful in editing your information |
|
170 " file. This command reads the information file in new unnamed buffer. |
|
171 " Write the buffer and the information file will be updated. |
|
172 " |
|
173 " About Cache: |
|
174 " Once a cache was created, It is not updated automatically to improve |
|
175 " response by default. To update it, use :FuzzyFinderRemoveCache command. |
|
176 " |
|
177 " About Migemo: |
|
178 " Migemo is a search method for Japanese language. |
|
179 " |
|
180 "----------------------------------------------------------------------------- |
|
181 " Options: |
|
182 " You can set options via g:FuzzyFinderOptions which is a dictionary. See |
|
183 " the folded section named "GLOBAL OPTIONS:" for details. To easily set |
|
184 " options for customization, put necessary entries from GLOBAL OPTIONS into |
|
185 " your vimrc file and edit those values. |
|
186 " |
|
187 "----------------------------------------------------------------------------- |
|
188 " Setting Example: |
|
189 " let g:FuzzyFinderOptions = { 'Base':{}, 'Buffer':{}, 'File':{}, 'Dir':{}, 'MruFile':{}, 'MruCmd':{}, 'FavFile':{}, 'Tag':{}, 'TaggedFile':{}} |
|
190 " let g:FuzzyFinderOptions.Base.ignore_case = 1 |
|
191 " let g:FuzzyFinderOptions.Base.abbrev_map = { |
|
192 " \ '\C^VR' : [ |
|
193 " \ '$VIMRUNTIME/**', |
|
194 " \ '~/.vim/**', |
|
195 " \ '$VIM/.vim/**', |
|
196 " \ '$VIM/vimfiles/**', |
|
197 " \ ], |
|
198 " \ } |
|
199 " let g:FuzzyFinderOptions.MruFile.max_item = 200 |
|
200 " let g:FuzzyFinderOptions.MruCmd.max_item = 200 |
|
201 " nnoremap <silent> <C-n> :FuzzyFinderBuffer<CR> |
|
202 " nnoremap <silent> <C-m> :FuzzyFinderFile <C-r>=expand('%:~:.')[:-1-len(expand('%:~:.:t'))]<CR><CR> |
|
203 " nnoremap <silent> <C-j> :FuzzyFinderMruFile<CR> |
|
204 " nnoremap <silent> <C-k> :FuzzyFinderMruCmd<CR> |
|
205 " nnoremap <silent> <C-p> :FuzzyFinderDir <C-r>=expand('%:p:~')[:-1-len(expand('%:p:~:t'))]<CR><CR> |
|
206 " nnoremap <silent> <C-f><C-d> :FuzzyFinderDir<CR> |
|
207 " nnoremap <silent> <C-f><C-f> :FuzzyFinderFavFile<CR> |
|
208 " nnoremap <silent> <C-f><C-t> :FuzzyFinderTag!<CR> |
|
209 " nnoremap <silent> <C-f><C-g> :FuzzyFinderTaggedFile<CR> |
|
210 " noremap <silent> g] :FuzzyFinderTag! <C-r>=expand('<cword>')<CR><CR> |
|
211 " nnoremap <silent> <C-f>F :FuzzyFinderAddFavFile<CR> |
|
212 " nnoremap <silent> <C-f><C-e> :FuzzyFinderEditInfo<CR> |
|
213 " |
|
214 "----------------------------------------------------------------------------- |
|
215 " Special Thanks: |
|
216 " Vincent Wang |
|
217 " Ingo Karkat |
|
218 " Nikolay Golubev |
|
219 " Brian Doyle |
|
220 " id:secondlife |
|
221 " Matt Tolton |
|
222 " |
|
223 "----------------------------------------------------------------------------- |
|
224 " ChangeLog: |
|
225 " 2.13: |
|
226 " - Fixed a bug that a directory disappeared when a file in that directroy |
|
227 " was being opened in File/Mru-File mode. |
|
228 " |
|
229 " 2.12: |
|
230 " - Changed to be able to show completion items in the order of recently |
|
231 " used in Buffer mode. |
|
232 " - Added g:FuzzyFinderOptions.Buffer.mru_order option. |
|
233 " |
|
234 " 2.11: |
|
235 " - Changed that a dot sequence of entered pattern is expanded to parent |
|
236 " directroies in File/Dir mode. |
|
237 " E.g.: "foo/...bar" -> "foo/../../bar" |
|
238 " - Fixed a bug that a prompt string was excessively inserted. |
|
239 " |
|
240 " 2.10: |
|
241 " - Changed not to show a current buffer in a completion menu. |
|
242 " - Fixed a bug that a filename to open was not been escaped. |
|
243 " - Added 'prompt' option. |
|
244 " - Added 'prompt_highlight' option. |
|
245 " - Removed g:FuzzyFinderOptions.MruFile.no_special_buffer option. |
|
246 " |
|
247 " 2.9: |
|
248 " - Enhanced <BS> behavior in Fuzzyfinder and added 'smart_bs' option. |
|
249 " - Fixed a bug that entered pattern was not been escaped. |
|
250 " - Fixed not to insert "zv" with "c/pattern<CR>" command in Normal mode. |
|
251 " - Avoid the slow down problem caused by filereadable() check for the MRU |
|
252 " information in BufEnter/BufWritePost. |
|
253 " |
|
254 " 2.8.1: |
|
255 " - Fixed a bug caused by the non-escaped buffer name "[Fuzzyfinder]". |
|
256 " - Fixed a command to open in a new tab page in Buffer mode. |
|
257 " 2.8: |
|
258 " - Added 'trim_length' option. |
|
259 " - Added 'switch_order' option. |
|
260 " - Fixed a bug that entered command did not become the newest in the |
|
261 " history. |
|
262 " - Fixed a bug that folds could not open with <CR> in a command-line when |
|
263 " searching. |
|
264 " - Removed 'excluded_indicator' option. Now a completion list in Buffer |
|
265 " mode is the same as a result of :buffers. |
|
266 " |
|
267 " 2.7: |
|
268 " - Changed to find an item whose index is matched with the number |
|
269 " suffixed with entered pattern. |
|
270 " - Fixed the cache bug after changing current directroy in File mode. |
|
271 " |
|
272 " 2.6.2: |
|
273 " - Fixed not to miss changes in options when updates the MRU information. |
|
274 " |
|
275 " 2.6.1: |
|
276 " - Fixed a bug related to floating-point support. |
|
277 " - Added support for GetLatestVimScripts. |
|
278 " |
|
279 " 2.6: |
|
280 " - Revived MRU-command mode. The problem with a command-line abbreviation |
|
281 " was solved. |
|
282 " - Changed the specification of the information file. |
|
283 " - Added :FuzzyFinderEditInfo command. |
|
284 |
|
285 " 2.5.1: |
|
286 " - Fixed to be able to match "foo/./bar" by "foo/**/bar" in File mode. |
|
287 " - Fixed to be able to open a space-containing file in File mode. |
|
288 " - Fixed to honor the current working directory properly in File mode. |
|
289 " |
|
290 " 2.5: |
|
291 " - Fixed the bug that a wrong initial text is entered after switching to a |
|
292 " next mode. |
|
293 " - Fixed the bug that it does not return to previous window after leaving |
|
294 " Fuzzyfinder one. |
|
295 " |
|
296 " 2.4: |
|
297 " - Fixed the bug that Fuzzyfinder fails to open a file caused by auto-cd |
|
298 " plugin/script. |
|
299 " |
|
300 " 2.3: |
|
301 " - Added a key mapping to open items in a new tab page and |
|
302 " g:FuzzyFinderOptions.Base.key_open_tab opton. |
|
303 " - Changed to show Fuzzyfinder window above last window even if |
|
304 " 'splitbelow' was set. |
|
305 " - Changed to set nocursorline and nocursorcolumn in Fuzzyfinder. |
|
306 " - Fixed not to push up a buffer number unlimitedly. |
|
307 " |
|
308 " 2.2: |
|
309 " - Added new feature, which is the partial matching. |
|
310 " - Fixed the bug that an error occurs when "'" was entered. |
|
311 " |
|
312 " 2.1: |
|
313 " - Restructured the option system AGAIN. Sorry :p |
|
314 " - Changed to inherit a typed text when switching a mode without leaving |
|
315 " Insert mode. |
|
316 " - Changed commands which launch explorers to be able to take a argument |
|
317 " for initial text. |
|
318 " - Changed to complete file names by relative path and not full path in |
|
319 " the buffer/mru-file/tagged-file mode. |
|
320 " - Changed to highlight a typed text when the completion item was not |
|
321 " found or the completion process was aborted. |
|
322 " - Changed to create caches for each tag file and not working directory |
|
323 " in the tag/tagged-file mode. |
|
324 " - Fixed the bug that the buffer mode couldn't open a unnamed buffer. |
|
325 " - Added 'matching_limit' option. |
|
326 " - Removed 'max_match' option. Use 'matching_limit' option instead. |
|
327 " - Removed 'initial_text' option. Use command argument instead. |
|
328 " - Removed the MRU-command mode. |
|
329 " |
|
330 " 2.0: |
|
331 " - Added the tag mode. |
|
332 " - Added the tagged-file mode. |
|
333 " - Added :FuzzyFinderRemoveCache command. |
|
334 " - Restructured the option system. many options are changed names or |
|
335 " default values of some options. |
|
336 " - Changed to hold and reuse caches of completion lists by default. |
|
337 " - Changed to set filetype 'fuzzyfinder'. |
|
338 " - Disabled the MRU-command mode by default because there are problems. |
|
339 " - Removed FuzzyFinderAddMode command. |
|
340 " |
|
341 " 1.5: |
|
342 " - Added the directory mode. |
|
343 " - Fixed the bug that it caused an error when switch a mode in Insert |
|
344 " mode. |
|
345 " - Changed g:FuzzyFinder_KeySwitchMode type to a list. |
|
346 " |
|
347 " 1.4: |
|
348 " - Changed the specification of the information file. |
|
349 " - Added the MRU-commands mode. |
|
350 " - Renamed :FuzzyFinderAddFavorite command to :FuzzyFinderAddFavFile. |
|
351 " - Renamed g:FuzzyFinder_MruModeVars option to |
|
352 " g:FuzzyFinder_MruFileModeVars. |
|
353 " - Renamed g:FuzzyFinder_FavoriteModeVars option to |
|
354 " g:FuzzyFinder_FavFileModeVars. |
|
355 " - Changed to show registered time of each item in MRU/favorite mode. |
|
356 " - Added 'timeFormat' option for MRU/favorite modes. |
|
357 " |
|
358 " 1.3: |
|
359 " - Fixed a handling of multi-byte characters. |
|
360 " |
|
361 " 1.2: |
|
362 " - Added support for Migemo. (Migemo is Japanese search method.) |
|
363 " |
|
364 " 1.1: |
|
365 " - Added the favorite mode. |
|
366 " - Added new features, which are abbreviations and multiple search. |
|
367 " - Added 'abbrevMap' option for each mode. |
|
368 " - Added g:FuzzyFinder_MruModeVars['ignoreSpecialBuffers'] option. |
|
369 " - Fixed the bug that it did not work correctly when a user have mapped |
|
370 " <C-p> or <Down>. |
|
371 " |
|
372 " 1.0: |
|
373 " - Added the MRU mode. |
|
374 " - Added commands to add and use original mode. |
|
375 " - Improved the sorting algorithm for completion items. |
|
376 " - Added 'initialInput' option to automatically insert a text at the |
|
377 " beginning of a mode. |
|
378 " - Changed that 'excludedPath' option works for the entire path. |
|
379 " - Renamed some options. |
|
380 " - Changed default values of some options. |
|
381 " - Packed the mode-specific options to dictionaries. |
|
382 " - Removed some options. |
|
383 " |
|
384 " 0.6: |
|
385 " - Fixed some bugs. |
|
386 |
|
387 " 0.5: |
|
388 " - Improved response by aborting processing too many items. |
|
389 " - Changed to be able to open a buffer/file not only in previous window |
|
390 " but also in new window. |
|
391 " - Fixed a bug that recursive searching with '**' does not work. |
|
392 " - Added g:FuzzyFinder_CompletionItemLimit option. |
|
393 " - Added g:FuzzyFinder_KeyOpen option. |
|
394 " |
|
395 " 0.4: |
|
396 " - Improved response of the input. |
|
397 " - Improved the sorting algorithm for completion items. It is based on |
|
398 " the matching level. 1st is perfect matching, 2nd is prefix matching, |
|
399 " and 3rd is fuzzy matching. |
|
400 " - Added g:FuzzyFinder_ExcludePattern option. |
|
401 " - Removed g:FuzzyFinder_WildIgnore option. |
|
402 " - Removed g:FuzzyFinder_EchoPattern option. |
|
403 " - Removed g:FuzzyFinder_PathSeparator option. |
|
404 " - Changed the default value of g:FuzzyFinder_MinLengthFile from 1 to 0. |
|
405 " |
|
406 " 0.3: |
|
407 " - Added g:FuzzyFinder_IgnoreCase option. |
|
408 " - Added g:FuzzyFinder_KeyToggleIgnoreCase option. |
|
409 " - Added g:FuzzyFinder_EchoPattern option. |
|
410 " - Changed the open command in a buffer mode from ":edit" to ":buffer" to |
|
411 " avoid being reset cursor position. |
|
412 " - Changed the default value of g:FuzzyFinder_KeyToggleMode from |
|
413 " <C-Space> to <F12> because <C-Space> does not work on some CUI |
|
414 " environments. |
|
415 " - Changed to avoid being loaded by Vim before 7.0. |
|
416 " - Fixed a bug with making a fuzzy pattern which has '\'. |
|
417 " |
|
418 " 0.2: |
|
419 " - A bug it does not work on Linux is fixed. |
|
420 " |
|
421 " 0.1: |
|
422 " - First release. |
|
423 " |
|
424 " }}}1 |
|
425 "============================================================================= |
|
426 " INCLUDE GUARD: {{{1 |
|
427 if exists('loaded_fuzzyfinder') || v:version < 701 |
|
428 finish |
|
429 endif |
|
430 let loaded_fuzzyfinder = 1 |
|
431 |
|
432 " }}}1 |
|
433 "============================================================================= |
|
434 " FUNCTION: {{{1 |
|
435 "----------------------------------------------------------------------------- |
|
436 " LIST FUNCTIONS: |
|
437 |
|
438 function! s:Unique(in) |
|
439 let sorted = sort(a:in) |
|
440 if len(sorted) < 2 |
|
441 return sorted |
|
442 endif |
|
443 let last = remove(sorted, 0) |
|
444 let result = [last] |
|
445 for item in sorted |
|
446 if item != last |
|
447 call add(result, item) |
|
448 let last = item |
|
449 endif |
|
450 endfor |
|
451 return result |
|
452 endfunction |
|
453 |
|
454 " [ [0], [1,2], [3] ] -> [ 0, 1, 2, 3 ] |
|
455 function! s:Concat(in) |
|
456 let result = [] |
|
457 for l in a:in |
|
458 let result += l |
|
459 endfor |
|
460 return result |
|
461 endfunction |
|
462 |
|
463 " [ [ 0, 1 ], [ 2, 3, 4 ], ] -> [ [0,2], [0,3], [0,4], [1,2], [1,3], [1,4] ] |
|
464 function! s:CartesianProduct(lists) |
|
465 if empty(a:lists) |
|
466 return [] |
|
467 endif |
|
468 "let result = map((a:lists[0]), '[v:val]') |
|
469 let result = [ [] ] |
|
470 for l in a:lists |
|
471 let temp = [] |
|
472 for r in result |
|
473 let temp += map(copy(l), 'add(copy(r), v:val)') |
|
474 endfor |
|
475 let result = temp |
|
476 endfor |
|
477 return result |
|
478 endfunction |
|
479 |
|
480 " copy + filter + limit |
|
481 function! s:FilterEx(in, expr, limit) |
|
482 if a:limit <= 0 |
|
483 return filter(copy(a:in), a:expr) |
|
484 endif |
|
485 let result = [] |
|
486 let stride = a:limit * 3 / 2 " x1.5 |
|
487 for i in range(0, len(a:in) - 1, stride) |
|
488 let result += filter(a:in[i : i + stride - 1], a:expr) |
|
489 if len(result) >= a:limit |
|
490 return remove(result, 0, a:limit - 1) |
|
491 endif |
|
492 endfor |
|
493 return result |
|
494 endfunction |
|
495 |
|
496 " |
|
497 function! s:FilterMatching(entries, key, pattern, index, limit) |
|
498 return s:FilterEx(a:entries, 'v:val[''' . a:key . '''] =~ ' . string(a:pattern) . ' || v:val.index == ' . a:index, a:limit) |
|
499 endfunction |
|
500 |
|
501 function! s:ExtendIndexToEach(in, offset) |
|
502 for i in range(len(a:in)) |
|
503 let a:in[i].index = i + a:offset |
|
504 endfor |
|
505 return a:in |
|
506 endfunction |
|
507 |
|
508 function! s:UpdateMruList(mrulist, new_item, key, max_item, excluded) |
|
509 let result = copy(a:mrulist) |
|
510 let result = filter(result,'v:val[a:key] != a:new_item[a:key]') |
|
511 let result = insert(result, a:new_item) |
|
512 let result = filter(result, 'v:val[a:key] !~ a:excluded') |
|
513 return result[0 : a:max_item - 1] |
|
514 endfunction |
|
515 |
|
516 "----------------------------------------------------------------------------- |
|
517 " STRING FUNCTIONS: |
|
518 |
|
519 " trims a:str and add a:mark if a length of a:str is more than a:len |
|
520 function! s:TrimLast(str, len) |
|
521 if a:len <= 0 || len(a:str) <= a:len |
|
522 return a:str |
|
523 endif |
|
524 return a:str[:(a:len - len(s:ABBR_TRIM_MARK) - 1)] . s:ABBR_TRIM_MARK |
|
525 endfunction |
|
526 |
|
527 " takes suffix numer. if no digits, returns -1 |
|
528 function! s:SuffixNumber(str) |
|
529 let s = matchstr(a:str, '\d\+$') |
|
530 return (len(s) ? str2nr(s) : -1) |
|
531 endfunction |
|
532 |
|
533 function! s:ConvertWildcardToRegexp(expr) |
|
534 let re = escape(a:expr, '\') |
|
535 for [pat, sub] in [ [ '*', '\\.\\*' ], [ '?', '\\.' ], [ '[', '\\[' ], ] |
|
536 let re = substitute(re, pat, sub, 'g') |
|
537 endfor |
|
538 return '\V' . re |
|
539 endfunction |
|
540 |
|
541 " "foo/bar/hoge" -> { head: "foo/bar/", tail: "hoge" } |
|
542 function! s:SplitPath(path) |
|
543 let dir = matchstr(a:path, '^.*[/\\]') |
|
544 return { |
|
545 \ 'head' : dir, |
|
546 \ 'tail' : a:path[strlen(dir):] |
|
547 \ } |
|
548 endfunction |
|
549 |
|
550 function! s:EscapeFilename(fn) |
|
551 return escape(a:fn, " \t\n*?[{`$%#'\"|!<") |
|
552 endfunction |
|
553 |
|
554 " "foo/.../bar/...hoge" -> "foo/.../bar/../../hoge" |
|
555 function! s:ExpandTailDotSequenceToParentDir(base) |
|
556 return substitute(a:base, '^\(.*[/\\]\)\?\zs\.\(\.\+\)\ze[^/\\]*$', |
|
557 \ '\=repeat(".." . s:PATH_SEPARATOR, len(submatch(2)))', '') |
|
558 endfunction |
|
559 |
|
560 "----------------------------------------------------------------------------- |
|
561 " FUNCTIONS FOR COMPLETION ITEM: |
|
562 |
|
563 function! s:FormatCompletionItem(expr, number, abbr, trim_len, time, base_pattern, evals_path_tail) |
|
564 if a:evals_path_tail |
|
565 let rate = s:EvaluateMatchingRate(s:SplitPath(matchstr(a:expr, '^.*[^/\\]')).tail, |
|
566 \ s:SplitPath(a:base_pattern).tail) |
|
567 else |
|
568 let rate = s:EvaluateMatchingRate(a:expr, a:base_pattern) |
|
569 endif |
|
570 return { |
|
571 \ 'word' : a:expr, |
|
572 \ 'abbr' : s:TrimLast((a:number >= 0 ? printf('%2d: ', a:number) : '') . a:abbr, a:trim_len), |
|
573 \ 'menu' : printf('%s[%s]', (len(a:time) ? a:time . ' ' : ''), s:MakeRateStar(rate, 5)), |
|
574 \ 'ranks' : [-rate, (a:number >= 0 ? a:number : a:expr)] |
|
575 \ } |
|
576 endfunction |
|
577 |
|
578 function! s:EvaluateMatchingRate(expr, pattern) |
|
579 if a:expr == a:pattern |
|
580 return s:MATCHING_RATE_BASE |
|
581 endif |
|
582 let rate = 0 |
|
583 let rate_increment = (s:MATCHING_RATE_BASE * 9) / (len(a:pattern) * 10) " zero divide ok |
|
584 let matched = 1 |
|
585 let i_pattern = 0 |
|
586 for i_expr in range(len(a:expr)) |
|
587 if a:expr[i_expr] == a:pattern[i_pattern] |
|
588 let rate += rate_increment |
|
589 let matched = 1 |
|
590 let i_pattern += 1 |
|
591 if i_pattern >= len(a:pattern) |
|
592 break |
|
593 endif |
|
594 elseif matched |
|
595 let rate_increment = rate_increment / 2 |
|
596 let matched = 0 |
|
597 endif |
|
598 endfor |
|
599 return rate |
|
600 endfunction |
|
601 |
|
602 function! s:MakeRateStar(rate, base) |
|
603 let len = (a:base * a:rate) / s:MATCHING_RATE_BASE |
|
604 return repeat('*', len) . repeat('.', a:base - len) |
|
605 endfunction |
|
606 |
|
607 "----------------------------------------------------------------------------- |
|
608 " MISC FUNCTIONS: |
|
609 |
|
610 function! s:IsAvailableMode(mode) |
|
611 return exists('a:mode.mode_available') && a:mode.mode_available |
|
612 endfunction |
|
613 |
|
614 function! s:GetAvailableModes() |
|
615 return filter(values(g:FuzzyFinderMode), 's:IsAvailableMode(v:val)') |
|
616 endfunction |
|
617 |
|
618 function! s:GetSortedAvailableModes() |
|
619 let modes = filter(items(g:FuzzyFinderMode), 's:IsAvailableMode(v:val[1])') |
|
620 let modes = map(modes, 'extend(v:val[1], { "ranks" : [v:val[1].switch_order, v:val[0]] })') |
|
621 return sort(modes, 's:CompareRanks') |
|
622 endfunction |
|
623 |
|
624 function! s:GetSidPrefix() |
|
625 return matchstr(expand('<sfile>'), '<SNR>\d\+_') |
|
626 endfunction |
|
627 |
|
628 function! s:OnCmdCR() |
|
629 for m in s:GetAvailableModes() |
|
630 call m.extend_options() |
|
631 call m.on_command_pre(getcmdtype() . getcmdline()) |
|
632 endfor |
|
633 " lets last entry become the newest in the history |
|
634 if getcmdtype() =~ '[:/=@]' |
|
635 call histadd(getcmdtype(), getcmdline()) |
|
636 endif |
|
637 |
|
638 " this is not mapped again (:help recursive_mapping) |
|
639 return "\<CR>" |
|
640 endfunction |
|
641 |
|
642 function! s:ExpandAbbrevMap(base, abbrev_map) |
|
643 let result = [a:base] |
|
644 |
|
645 " expand |
|
646 for [pattern, sub_list] in items(a:abbrev_map) |
|
647 let exprs = result |
|
648 let result = [] |
|
649 for expr in exprs |
|
650 let result += map(copy(sub_list), 'substitute(expr, pattern, v:val, "g")') |
|
651 endfor |
|
652 endfor |
|
653 |
|
654 return s:Unique(result) |
|
655 endfunction |
|
656 |
|
657 " "**" is expanded to ["**", "."]. E.g.: "foo/**/bar" -> [ "foo/./bar", "foo/**/bar" ] |
|
658 function! s:ExpandEx(dir) |
|
659 if a:dir !~ '\S' |
|
660 return [''] |
|
661 endif |
|
662 |
|
663 " [ ["foo/"], ["**/", "./" ], ["bar/"] ] |
|
664 let lists = [] |
|
665 for i in split(a:dir, '[/\\]\zs') |
|
666 let m = matchlist(i, '^\*\{2,}\([/\\]*\)$') |
|
667 call add(lists, (empty(m) ? [i] : [i, '.' . m[1]])) |
|
668 endfor |
|
669 |
|
670 " expand wlidcards |
|
671 return split(join(map(s:CartesianProduct(lists), 'expand(join(v:val, ""))'), "\n"), "\n") |
|
672 endfunction |
|
673 |
|
674 function! s:EnumExpandedDirsEntries(dir, excluded) |
|
675 let dirs = s:ExpandEx(a:dir) |
|
676 let entries = s:Concat(map(copy(dirs), 'split(glob(v:val . ".*"), "\n") + ' . |
|
677 \ 'split(glob(v:val . "*" ), "\n")')) |
|
678 if len(dirs) <= 1 |
|
679 call map(entries, 'extend(s:SplitPath(v:val), { "suffix" : (isdirectory(v:val) ? s:PATH_SEPARATOR : ""), "head" : a:dir })') |
|
680 else |
|
681 call map(entries, 'extend(s:SplitPath(v:val), { "suffix" : (isdirectory(v:val) ? s:PATH_SEPARATOR : "") })') |
|
682 endif |
|
683 if len(a:excluded) |
|
684 call filter(entries, '(v:val.head . v:val.tail . v:val.suffix) !~ a:excluded') |
|
685 endif |
|
686 return entries |
|
687 endfunction |
|
688 |
|
689 function! s:GetTagList(tagfile) |
|
690 return map(readfile(a:tagfile), 'matchstr(v:val, ''^[^!\t][^\t]*'')') |
|
691 endfunction |
|
692 |
|
693 function! s:GetTaggedFileList(tagfile) |
|
694 execute 'cd ' . fnamemodify(a:tagfile, ':h') |
|
695 let result = map(readfile(a:tagfile), 'fnamemodify(matchstr(v:val, ''^[^!\t][^\t]*\t\zs[^\t]\+''), '':p:~'')') |
|
696 cd - |
|
697 return result |
|
698 endfunction |
|
699 |
|
700 function! s:HighlightPrompt(prompt, highlight) |
|
701 syntax clear |
|
702 execute printf('syntax match %s /^\V%s/', a:highlight, escape(a:prompt, '\')) |
|
703 endfunction |
|
704 |
|
705 function! s:HighlightError() |
|
706 syntax clear |
|
707 syntax match Error /^.*$/ |
|
708 endfunction |
|
709 |
|
710 function! s:CompareTimeDescending(i1, i2) |
|
711 return a:i1.time == a:i2.time ? 0 : a:i1.time > a:i2.time ? -1 : +1 |
|
712 endfunction |
|
713 |
|
714 function! s:CompareRanks(i1, i2) |
|
715 if exists('a:i1.ranks') && exists('a:i2.ranks') |
|
716 for i in range(min([len(a:i1.ranks), len(a:i2.ranks)])) |
|
717 if a:i1.ranks[i] > a:i2.ranks[i] |
|
718 return +1 |
|
719 elseif a:i1.ranks[i] < a:i2.ranks[i] |
|
720 return -1 |
|
721 endif |
|
722 endfor |
|
723 endif |
|
724 return 0 |
|
725 endfunction |
|
726 |
|
727 function! s:GetCurrentTagFiles() |
|
728 return sort(filter(map(tagfiles(), 'fnamemodify(v:val, '':p'')'), 'filereadable(v:val)')) |
|
729 endfunction |
|
730 |
|
731 " }}}1 |
|
732 "============================================================================= |
|
733 " OBJECT: {{{1 |
|
734 "----------------------------------------------------------------------------- |
|
735 let g:FuzzyFinderMode = { 'Base' : {} } |
|
736 |
|
737 function! g:FuzzyFinderMode.Base.launch(initial_text, partial_matching, prev_bufnr, tag_files) |
|
738 " initializes this object |
|
739 call self.extend_options() |
|
740 let self.partial_matching = a:partial_matching |
|
741 let self.prev_bufnr = a:prev_bufnr |
|
742 let self.tag_files = a:tag_files " to get local value of current buffer |
|
743 let self.last_col = -1 |
|
744 call s:InfoFileManager.load() |
|
745 if !s:IsAvailableMode(self) |
|
746 echo 'This mode is not available: ' . self.to_str() |
|
747 return |
|
748 endif |
|
749 |
|
750 call s:WindowManager.activate(self.make_complete_func('CompleteFunc')) |
|
751 call s:OptionManager.set('completeopt', 'menuone') |
|
752 call s:OptionManager.set('ignorecase', self.ignore_case) |
|
753 |
|
754 " local autocommands |
|
755 augroup FuzzyfinderLocal |
|
756 autocmd! |
|
757 execute 'autocmd CursorMovedI <buffer> call ' . self.to_str('on_cursor_moved_i()') |
|
758 execute 'autocmd InsertLeave <buffer> nested call ' . self.to_str('on_insert_leave()' ) |
|
759 augroup END |
|
760 |
|
761 " local mapping |
|
762 for [lhs, rhs] in [ |
|
763 \ [ self.key_open , self.to_str('on_cr(0, 0)' ) ], |
|
764 \ [ self.key_open_split , self.to_str('on_cr(1, 0)' ) ], |
|
765 \ [ self.key_open_vsplit, self.to_str('on_cr(2, 0)' ) ], |
|
766 \ [ self.key_open_tab , self.to_str('on_cr(3, 0)' ) ], |
|
767 \ [ '<BS>' , self.to_str('on_bs()' ) ], |
|
768 \ [ '<C-h>' , self.to_str('on_bs()' ) ], |
|
769 \ [ self.key_next_mode , self.to_str('on_switch_mode(+1)' ) ], |
|
770 \ [ self.key_prev_mode , self.to_str('on_switch_mode(-1)' ) ], |
|
771 \ [ self.key_ignore_case, self.to_str('on_switch_ignore_case()') ], |
|
772 \ ] |
|
773 " hacks to be able to use feedkeys(). |
|
774 execute printf('inoremap <buffer> <silent> %s <C-r>=%s ? "" : ""<CR>', lhs, rhs) |
|
775 endfor |
|
776 |
|
777 call self.on_mode_enter() |
|
778 |
|
779 " Starts Insert mode and makes CursorMovedI event now. Command prompt is |
|
780 " needed to forces a completion menu to update every typing. |
|
781 call setline(1, self.prompt . a:initial_text) |
|
782 call feedkeys("A", 'n') " startinsert! does not work in InsertLeave handler |
|
783 endfunction |
|
784 |
|
785 function! g:FuzzyFinderMode.Base.on_cursor_moved_i() |
|
786 let ln = getline('.') |
|
787 let cl = col('.') |
|
788 if !self.exists_prompt(ln) |
|
789 " if command prompt is removed |
|
790 "call setline('.', self.prompt . ln) |
|
791 call setline('.', self.restore_prompt(ln)) |
|
792 call feedkeys(repeat("\<Right>", len(getline('.')) - len(ln)), 'n') |
|
793 elseif cl <= len(self.prompt) |
|
794 " if the cursor is moved before command prompt |
|
795 call feedkeys(repeat("\<Right>", len(self.prompt) - cl + 1), 'n') |
|
796 elseif cl > strlen(ln) && cl != self.last_col |
|
797 " if the cursor is placed on the end of the line and has been actually moved. |
|
798 let self.last_col = cl |
|
799 call feedkeys("\<C-x>\<C-u>", 'n') |
|
800 endif |
|
801 endfunction |
|
802 |
|
803 function! g:FuzzyFinderMode.Base.on_insert_leave() |
|
804 let text = getline('.') |
|
805 call self.on_mode_leave() |
|
806 call self.empty_cache_if_existed(0) |
|
807 call s:OptionManager.restore_all() |
|
808 call s:WindowManager.deactivate() |
|
809 |
|
810 " switchs to next mode, or finishes fuzzyfinder. |
|
811 if exists('s:reserved_switch_mode') |
|
812 let m = self.next_mode(s:reserved_switch_mode < 0) |
|
813 call m.launch(self.remove_prompt(text), self.partial_matching, self.prev_bufnr, self.tag_files) |
|
814 unlet s:reserved_switch_mode |
|
815 else |
|
816 if exists('s:reserved_command') |
|
817 call feedkeys(self.on_open(s:reserved_command[0], s:reserved_command[1]), 'n') |
|
818 unlet s:reserved_command |
|
819 endif |
|
820 endif |
|
821 endfunction |
|
822 |
|
823 function! g:FuzzyFinderMode.Base.on_buf_enter() |
|
824 endfunction |
|
825 |
|
826 function! g:FuzzyFinderMode.Base.on_buf_write_post() |
|
827 endfunction |
|
828 |
|
829 function! g:FuzzyFinderMode.Base.on_command_pre(cmd) |
|
830 endfunction |
|
831 |
|
832 function! g:FuzzyFinderMode.Base.on_cr(index, check_dir) |
|
833 if pumvisible() |
|
834 call feedkeys(printf("\<C-y>\<C-r>=%s(%d, 1) ? '' : ''\<CR>", self.to_str('on_cr'), a:index), 'n') |
|
835 elseif !a:check_dir || getline('.') !~ '[/\\]$' |
|
836 let s:reserved_command = [self.remove_prompt(getline('.')), a:index] |
|
837 call feedkeys("\<Esc>", 'n') |
|
838 endif |
|
839 endfunction |
|
840 |
|
841 function! g:FuzzyFinderMode.Base.on_bs() |
|
842 let bs_count = 1 |
|
843 if self.smart_bs && col('.') > 2 && getline('.')[col('.') - 2] =~ '[/\\]' |
|
844 let bs_count = len(matchstr(getline('.')[:col('.') - 3], '[^/\\]*$')) + 1 |
|
845 endif |
|
846 call feedkeys((pumvisible() ? "\<C-e>" : "") . repeat("\<BS>", bs_count), 'n') |
|
847 endfunction |
|
848 |
|
849 function! g:FuzzyFinderMode.Base.on_mode_enter() |
|
850 endfunction |
|
851 |
|
852 function! g:FuzzyFinderMode.Base.on_mode_leave() |
|
853 endfunction |
|
854 |
|
855 function! g:FuzzyFinderMode.Base.on_open(expr, mode) |
|
856 return [ |
|
857 \ ':edit ', |
|
858 \ ':split ', |
|
859 \ ':vsplit ', |
|
860 \ ':tabedit ', |
|
861 \ ][a:mode] . s:EscapeFilename(a:expr) . "\<CR>" |
|
862 endfunction |
|
863 |
|
864 function! g:FuzzyFinderMode.Base.on_switch_mode(next_prev) |
|
865 let s:reserved_switch_mode = a:next_prev |
|
866 call feedkeys("\<Esc>", 'n') |
|
867 endfunction |
|
868 |
|
869 function! g:FuzzyFinderMode.Base.on_switch_ignore_case() |
|
870 let &ignorecase = !&ignorecase |
|
871 echo "ignorecase = " . &ignorecase |
|
872 let self.last_col = -1 |
|
873 call self.on_cursor_moved_i() |
|
874 endfunction |
|
875 |
|
876 " export string list |
|
877 function! g:FuzzyFinderMode.Base.serialize_info() |
|
878 let header = self.to_key() . "\t" |
|
879 return map(copy(self.info), 'header . string(v:val)') |
|
880 endfunction |
|
881 |
|
882 " import related items from string list |
|
883 function! g:FuzzyFinderMode.Base.deserialize_info(lines) |
|
884 let header = self.to_key() . "\t" |
|
885 let self.info = map(filter(copy(a:lines), 'v:val[: len(header) - 1] ==# header'), |
|
886 \ 'eval(v:val[len(header) :])') |
|
887 endfunction |
|
888 |
|
889 function! g:FuzzyFinderMode.Base.complete(findstart, base) |
|
890 if a:findstart |
|
891 return 0 |
|
892 elseif !self.exists_prompt(a:base) || len(self.remove_prompt(a:base)) < self.min_length |
|
893 return [] |
|
894 endif |
|
895 call s:HighlightPrompt(self.prompt, self.prompt_highlight) |
|
896 " FIXME: ExpandAbbrevMap duplicates index |
|
897 let result = [] |
|
898 for expanded_base in s:ExpandAbbrevMap(self.remove_prompt(a:base), self.abbrev_map) |
|
899 let result += self.on_complete(expanded_base) |
|
900 endfor |
|
901 call sort(result, 's:CompareRanks') |
|
902 if empty(result) |
|
903 call s:HighlightError() |
|
904 else |
|
905 call feedkeys("\<C-p>\<Down>", 'n') |
|
906 endif |
|
907 return result |
|
908 endfunction |
|
909 |
|
910 " This function is set to 'completefunc' which doesn't accept dictionary-functions. |
|
911 function! g:FuzzyFinderMode.Base.make_complete_func(name) |
|
912 execute printf("function! s:%s(findstart, base)\n" . |
|
913 \ " return %s.complete(a:findstart, a:base)\n" . |
|
914 \ "endfunction", a:name, self.to_str()) |
|
915 return s:GetSidPrefix() . a:name |
|
916 endfunction |
|
917 |
|
918 " fuzzy : 'str' -> {'base':'str', 'wi':'*s*t*r*', 're':'\V\.\*s\.\*t\.\*r\.\*'} |
|
919 " partial: 'str' -> {'base':'str', 'wi':'*str*', 're':'\V\.\*str\.\*'} |
|
920 function! g:FuzzyFinderMode.Base.make_pattern(base) |
|
921 if self.partial_matching |
|
922 let wi = (a:base !~ '^[*?]' ? '*' : '') . a:base . |
|
923 \ (a:base =~ '[^*?]$' ? '*' : '') |
|
924 let re = s:ConvertWildcardToRegexp(wi) |
|
925 return { 'base': a:base, 'wi':wi, 're': re } |
|
926 else |
|
927 let wi = '' |
|
928 for char in split(a:base, '\zs') |
|
929 if wi !~ '[*?]$' && char !~ '[*?]' |
|
930 let wi .= '*'. char |
|
931 else |
|
932 let wi .= char |
|
933 endif |
|
934 endfor |
|
935 |
|
936 if wi !~ '[*?]$' |
|
937 let wi .= '*' |
|
938 endif |
|
939 |
|
940 let re = s:ConvertWildcardToRegexp(wi) |
|
941 |
|
942 if self.migemo_support && a:base !~ '[^\x01-\x7e]' |
|
943 let re .= '\|\m.*' . substitute(migemo(a:base), '\\_s\*', '.*', 'g') . '.*' |
|
944 endif |
|
945 |
|
946 return { 'base': a:base, 'wi':wi, 're': re } |
|
947 endif |
|
948 endfunction |
|
949 |
|
950 " glob with caching-feature, etc. |
|
951 function! g:FuzzyFinderMode.Base.glob_ex(dir, file, excluded, index, matching_limit) |
|
952 let key = fnamemodify(a:dir, ':p') |
|
953 call extend(self, { 'cache' : {} }, 'keep') |
|
954 if !exists('self.cache[key]') |
|
955 echo 'Caching file list...' |
|
956 let self.cache[key] = s:EnumExpandedDirsEntries(key, a:excluded) |
|
957 call s:ExtendIndexToEach(self.cache[key], 1) |
|
958 endif |
|
959 echo 'Filtering file list...' |
|
960 "return map(s:FilterEx(self.cache[key], 'v:val.tail =~ ' . string(a:file), a:matching_limit), |
|
961 return map(s:FilterMatching(self.cache[key], 'tail', a:file, a:index, a:matching_limit), |
|
962 \ '{ "index" : v:val.index, "path" : (v:val.head == key ? a:dir : v:val.head) . v:val.tail . v:val.suffix }') |
|
963 endfunction |
|
964 |
|
965 function! g:FuzzyFinderMode.Base.glob_dir_ex(dir, file, excluded, index, matching_limit) |
|
966 let key = fnamemodify(a:dir, ':p') |
|
967 call extend(self, { 'cache' : {} }, 'keep') |
|
968 if !exists('self.cache[key]') |
|
969 echo 'Caching file list...' |
|
970 let self.cache[key] = filter(s:EnumExpandedDirsEntries(key, a:excluded), 'len(v:val.suffix)') |
|
971 call insert(self.cache[key], { 'head' : key, 'tail' : '..', 'suffix' : s:PATH_SEPARATOR }) |
|
972 call insert(self.cache[key], { 'head' : key, 'tail' : '.' , 'suffix' : '' }) |
|
973 call s:ExtendIndexToEach(self.cache[key], 1) |
|
974 endif |
|
975 echo 'Filtering file list...' |
|
976 "return map(s:FilterEx(self.cache[key], 'v:val.tail =~ ' . string(a:file), a:matching_limit), |
|
977 return map(s:FilterMatching(self.cache[key], 'tail', a:file, a:index, a:matching_limit), |
|
978 \ '{ "index" : v:val.index, "path" : (v:val.head == key ? a:dir : v:val.head) . v:val.tail . v:val.suffix }') |
|
979 endfunction |
|
980 |
|
981 function! g:FuzzyFinderMode.Base.empty_cache_if_existed(force) |
|
982 if exists('self.cache') && (a:force || !exists('self.lasting_cache') || !self.lasting_cache) |
|
983 unlet self.cache |
|
984 "let self.cache = (type(self.cache) == type({}) ? {} : |
|
985 " \ type(self.cache) == type([]) ? [] : |
|
986 " \ type(self.cache) == type('') ? '' : 0) |
|
987 endif |
|
988 endfunction |
|
989 |
|
990 function! g:FuzzyFinderMode.Base.to_key() |
|
991 return filter(keys(g:FuzzyFinderMode), 'g:FuzzyFinderMode[v:val] is self')[0] |
|
992 endfunction |
|
993 |
|
994 " returns 'g:FuzzyFinderMode.{key}{.argument}' |
|
995 function! g:FuzzyFinderMode.Base.to_str(...) |
|
996 return 'g:FuzzyFinderMode.' . self.to_key() . (a:0 > 0 ? '.' . a:1 : '') |
|
997 endfunction |
|
998 |
|
999 " takes in g:FuzzyFinderOptions |
|
1000 function! g:FuzzyFinderMode.Base.extend_options() |
|
1001 let n = filter(keys(g:FuzzyFinderMode), 'g:FuzzyFinderMode[v:val] is self')[0] |
|
1002 call extend(self, g:FuzzyFinderOptions.Base, 'force') |
|
1003 call extend(self, g:FuzzyFinderOptions[self.to_key()], 'force') |
|
1004 endfunction |
|
1005 |
|
1006 function! g:FuzzyFinderMode.Base.next_mode(rev) |
|
1007 let modes = (a:rev ? s:GetSortedAvailableModes() : reverse(s:GetSortedAvailableModes())) |
|
1008 let m_last = modes[-1] |
|
1009 for m in modes |
|
1010 if m is self |
|
1011 break |
|
1012 endif |
|
1013 let m_last = m |
|
1014 endfor |
|
1015 return m_last |
|
1016 " vim crashed using map() |
|
1017 endfunction |
|
1018 |
|
1019 function! g:FuzzyFinderMode.Base.exists_prompt(in) |
|
1020 return strlen(a:in) >= strlen(self.prompt) && a:in[:strlen(self.prompt) -1] ==# self.prompt |
|
1021 endfunction |
|
1022 |
|
1023 function! g:FuzzyFinderMode.Base.remove_prompt(in) |
|
1024 return a:in[(self.exists_prompt(a:in) ? strlen(self.prompt) : 0):] |
|
1025 endfunction |
|
1026 |
|
1027 function! g:FuzzyFinderMode.Base.restore_prompt(in) |
|
1028 let i = 0 |
|
1029 while i < len(self.prompt) && i < len(a:in) && self.prompt[i] ==# a:in[i] |
|
1030 let i += 1 |
|
1031 endwhile |
|
1032 return self.prompt . a:in[i : ] |
|
1033 endfunction |
|
1034 |
|
1035 "----------------------------------------------------------------------------- |
|
1036 let g:FuzzyFinderMode.Buffer = copy(g:FuzzyFinderMode.Base) |
|
1037 |
|
1038 function! g:FuzzyFinderMode.Buffer.on_complete(base) |
|
1039 let patterns = self.make_pattern(a:base) |
|
1040 let result = s:FilterMatching(self.cache, 'path', patterns.re, s:SuffixNumber(patterns.base), 0) |
|
1041 return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, v:val.time, a:base, 1)') |
|
1042 endfunction |
|
1043 |
|
1044 function! g:FuzzyFinderMode.Buffer.on_open(expr, mode) |
|
1045 " attempts to convert the path to the number for handling unnamed buffer |
|
1046 return printf([ |
|
1047 \ ':%sbuffer', |
|
1048 \ ':%ssbuffer', |
|
1049 \ ':vertical :%ssbuffer', |
|
1050 \ ':tab :%ssbuffer', |
|
1051 \ ][a:mode] . "\<CR>", filter(self.cache, 'v:val.path == a:expr')[0].buf_nr) |
|
1052 endfunction |
|
1053 |
|
1054 function! g:FuzzyFinderMode.Buffer.on_mode_enter() |
|
1055 let self.cache = map(filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != self.prev_bufnr'), |
|
1056 \ 'self.make_item(v:val)') |
|
1057 if self.mru_order |
|
1058 call s:ExtendIndexToEach(sort(self.cache, 's:CompareTimeDescending'), 1) |
|
1059 endif |
|
1060 endfunction |
|
1061 |
|
1062 function! g:FuzzyFinderMode.Buffer.on_buf_enter() |
|
1063 call self.update_buf_times() |
|
1064 endfunction |
|
1065 |
|
1066 function! g:FuzzyFinderMode.Buffer.on_buf_write_post() |
|
1067 call self.update_buf_times() |
|
1068 endfunction |
|
1069 |
|
1070 function! g:FuzzyFinderMode.Buffer.update_buf_times() |
|
1071 if !exists('self.buf_times') |
|
1072 let self.buf_times = {} |
|
1073 endif |
|
1074 let self.buf_times[bufnr('%')] = localtime() |
|
1075 endfunction |
|
1076 |
|
1077 function! g:FuzzyFinderMode.Buffer.make_item(nr) |
|
1078 return { |
|
1079 \ 'index' : a:nr, |
|
1080 \ 'buf_nr' : a:nr, |
|
1081 \ 'path' : empty(bufname(a:nr)) ? '[No Name]' : fnamemodify(bufname(a:nr), ':~:.'), |
|
1082 \ 'time' : (exists('self.buf_times[a:nr]') ? strftime(self.time_format, self.buf_times[a:nr]) : ''), |
|
1083 \ } |
|
1084 endfunction |
|
1085 |
|
1086 "----------------------------------------------------------------------------- |
|
1087 let g:FuzzyFinderMode.File = copy(g:FuzzyFinderMode.Base) |
|
1088 |
|
1089 function! g:FuzzyFinderMode.File.on_complete(base) |
|
1090 let base = s:ExpandTailDotSequenceToParentDir(a:base) |
|
1091 let patterns = map(s:SplitPath(base), 'self.make_pattern(v:val)') |
|
1092 let result = self.glob_ex(patterns.head.base, patterns.tail.re, self.excluded_path, s:SuffixNumber(patterns.tail.base), self.matching_limit) |
|
1093 let result = filter(result, 'bufnr("^" . v:val.path . "$") != self.prev_bufnr') |
|
1094 if len(result) >= self.matching_limit |
|
1095 call s:HighlightError() |
|
1096 endif |
|
1097 return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, "", base, 1)') |
|
1098 endfunction |
|
1099 |
|
1100 "----------------------------------------------------------------------------- |
|
1101 let g:FuzzyFinderMode.Dir = copy(g:FuzzyFinderMode.Base) |
|
1102 |
|
1103 function! g:FuzzyFinderMode.Dir.on_complete(base) |
|
1104 let base = s:ExpandTailDotSequenceToParentDir(a:base) |
|
1105 let patterns = map(s:SplitPath(base), 'self.make_pattern(v:val)') |
|
1106 let result = self.glob_dir_ex(patterns.head.base, patterns.tail.re, self.excluded_path, s:SuffixNumber(patterns.tail.base), 0) |
|
1107 return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, "", base, 1)') |
|
1108 endfunction |
|
1109 |
|
1110 function! g:FuzzyFinderMode.Dir.on_open(expr, mode) |
|
1111 return ':cd ' . escape(a:expr, ' ') . [ |
|
1112 \ "\<CR>", |
|
1113 \ "", |
|
1114 \ "", |
|
1115 \ "", |
|
1116 \ ][a:mode] |
|
1117 endfunction |
|
1118 |
|
1119 "----------------------------------------------------------------------------- |
|
1120 let g:FuzzyFinderMode.MruFile = copy(g:FuzzyFinderMode.Base) |
|
1121 |
|
1122 function! g:FuzzyFinderMode.MruFile.on_complete(base) |
|
1123 let patterns = self.make_pattern(a:base) |
|
1124 let result = s:FilterMatching(self.cache, 'path', patterns.re, s:SuffixNumber(patterns.base), 0) |
|
1125 return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, v:val.time, a:base, 1)') |
|
1126 endfunction |
|
1127 |
|
1128 function! g:FuzzyFinderMode.MruFile.on_mode_enter() |
|
1129 let self.cache = copy(self.info) |
|
1130 let self.cache = filter(self.cache, 'bufnr("^" . v:val.path . "$") != self.prev_bufnr') |
|
1131 let self.cache = filter(self.cache, 'filereadable(v:val.path)') |
|
1132 let self.cache = map(self.cache, '{ "path" : fnamemodify(v:val.path, ":~:."), "time" : strftime(self.time_format, v:val.time) }') |
|
1133 let self.cache = s:ExtendIndexToEach(self.cache, 1) |
|
1134 endfunction |
|
1135 |
|
1136 function! g:FuzzyFinderMode.MruFile.on_buf_enter() |
|
1137 call self.update_info() |
|
1138 endfunction |
|
1139 |
|
1140 function! g:FuzzyFinderMode.MruFile.on_buf_write_post() |
|
1141 call self.update_info() |
|
1142 endfunction |
|
1143 |
|
1144 function! g:FuzzyFinderMode.MruFile.update_info() |
|
1145 "if !empty(&buftype) || !filereadable(expand('%')) |
|
1146 if !empty(&buftype) |
|
1147 return |
|
1148 endif |
|
1149 call s:InfoFileManager.load() |
|
1150 let self.info = s:UpdateMruList(self.info, { 'path' : expand('%:p'), 'time' : localtime() }, |
|
1151 \ 'path', self.max_item, self.excluded_path) |
|
1152 call s:InfoFileManager.save() |
|
1153 endfunction |
|
1154 |
|
1155 "----------------------------------------------------------------------------- |
|
1156 let g:FuzzyFinderMode.MruCmd = copy(g:FuzzyFinderMode.Base) |
|
1157 |
|
1158 function! g:FuzzyFinderMode.MruCmd.on_complete(base) |
|
1159 let patterns = self.make_pattern(a:base) |
|
1160 let result = s:FilterMatching(self.cache, 'command', patterns.re, s:SuffixNumber(patterns.base), 0) |
|
1161 return map(result, 's:FormatCompletionItem(v:val.command, v:val.index, v:val.command, self.trim_length, v:val.time, a:base, 0)') |
|
1162 endfunction |
|
1163 |
|
1164 function! g:FuzzyFinderMode.MruCmd.on_open(expr, mode) |
|
1165 redraw |
|
1166 " use feedkeys to remap <CR> |
|
1167 return a:expr . [ |
|
1168 \ "\<C-r>=feedkeys(\"\\<CR>\", 'm')?'':''\<CR>", |
|
1169 \ "", |
|
1170 \ "", |
|
1171 \ "", |
|
1172 \ ][a:mode] |
|
1173 endfunction |
|
1174 |
|
1175 function! g:FuzzyFinderMode.MruCmd.on_mode_enter() |
|
1176 let self.cache = s:ExtendIndexToEach(map(copy(self.info), |
|
1177 \ '{ "command" : v:val.command, "time" : strftime(self.time_format, v:val.time) }'), 1) |
|
1178 endfunction |
|
1179 |
|
1180 function! g:FuzzyFinderMode.MruCmd.on_command_pre(cmd) |
|
1181 call self.update_info(a:cmd) |
|
1182 endfunction |
|
1183 |
|
1184 function! g:FuzzyFinderMode.MruCmd.update_info(cmd) |
|
1185 call s:InfoFileManager.load() |
|
1186 let self.info = s:UpdateMruList(self.info, { 'command' : a:cmd, 'time' : localtime() }, |
|
1187 \ 'command', self.max_item, self.excluded_command) |
|
1188 call s:InfoFileManager.save() |
|
1189 endfunction |
|
1190 |
|
1191 "----------------------------------------------------------------------------- |
|
1192 let g:FuzzyFinderMode.FavFile = copy(g:FuzzyFinderMode.Base) |
|
1193 |
|
1194 function! g:FuzzyFinderMode.FavFile.on_complete(base) |
|
1195 let patterns = self.make_pattern(a:base) |
|
1196 let result = s:FilterMatching(self.cache, 'path', patterns.re, s:SuffixNumber(patterns.base), 0) |
|
1197 return map(result, 's:FormatCompletionItem(v:val.path, v:val.index, v:val.path, self.trim_length, v:val.time, a:base, 1)') |
|
1198 endfunction |
|
1199 |
|
1200 function! g:FuzzyFinderMode.FavFile.on_mode_enter() |
|
1201 let self.cache = copy(self.info) |
|
1202 let self.cache = filter(self.cache, 'bufnr("^" . v:val.path . "$") != self.prev_bufnr') |
|
1203 let self.cache = map(self.cache, '{ "path" : fnamemodify(v:val.path, ":~:."), "time" : strftime(self.time_format, v:val.time) }') |
|
1204 let self.cache = s:ExtendIndexToEach(self.cache, 1) |
|
1205 endfunction |
|
1206 |
|
1207 function! g:FuzzyFinderMode.FavFile.add(in_file, adds) |
|
1208 call s:InfoFileManager.load() |
|
1209 |
|
1210 let file = fnamemodify((empty(a:in_file) ? expand('%') : a:in_file), ':p:~') |
|
1211 |
|
1212 call filter(self.info, 'v:val.path != file') |
|
1213 if a:adds |
|
1214 call add(self.info, { 'path' : file, 'time' : localtime() }) |
|
1215 endif |
|
1216 |
|
1217 call s:InfoFileManager.save() |
|
1218 endfunction |
|
1219 |
|
1220 "----------------------------------------------------------------------------- |
|
1221 let g:FuzzyFinderMode.Tag = copy(g:FuzzyFinderMode.Base) |
|
1222 |
|
1223 function! g:FuzzyFinderMode.Tag.on_complete(base) |
|
1224 let patterns = self.make_pattern(a:base) |
|
1225 let result = self.find_tag(patterns.re, self.matching_limit) |
|
1226 if len(result) >= self.matching_limit |
|
1227 call s:HighlightError() |
|
1228 endif |
|
1229 return map(result, 's:FormatCompletionItem(v:val, -1, v:val, self.trim_length, "", a:base, 1)') |
|
1230 endfunction |
|
1231 |
|
1232 function! g:FuzzyFinderMode.Tag.on_open(expr, mode) |
|
1233 return [ |
|
1234 \ ':tjump ', |
|
1235 \ ':stjump ', |
|
1236 \ ':vertical :stjump ', |
|
1237 \ ':tab :stjump ', |
|
1238 \ ][a:mode] . a:expr . "\<CR>" |
|
1239 endfunction |
|
1240 |
|
1241 function! g:FuzzyFinderMode.Tag.find_tag(pattern, matching_limit) |
|
1242 if !len(self.tag_files) |
|
1243 return [] |
|
1244 endif |
|
1245 |
|
1246 let key = join(self.tag_files, "\n") |
|
1247 |
|
1248 " cache not created or tags file updated? |
|
1249 call extend(self, { 'cache' : {} }, 'keep') |
|
1250 if !exists('self.cache[key]') || max(map(copy(self.tag_files), 'getftime(v:val) >= self.cache[key].time')) |
|
1251 echo 'Caching tag list...' |
|
1252 let self.cache[key] = { |
|
1253 \ 'time' : localtime(), |
|
1254 \ 'data' : s:Unique(s:Concat(map(copy(self.tag_files), 's:GetTagList(v:val)'))), |
|
1255 \ } |
|
1256 endif |
|
1257 |
|
1258 echo 'Filtering tag list...' |
|
1259 return s:FilterEx(self.cache[key].data, 'v:val =~ ' . string(a:pattern), a:matching_limit) |
|
1260 endfunction |
|
1261 |
|
1262 "----------------------------------------------------------------------------- |
|
1263 let g:FuzzyFinderMode.TaggedFile = copy(g:FuzzyFinderMode.Base) |
|
1264 |
|
1265 function! g:FuzzyFinderMode.TaggedFile.on_complete(base) |
|
1266 let patterns = self.make_pattern(a:base) |
|
1267 echo 'Making tagged file list...' |
|
1268 let result = self.find_tagged_file(patterns.re, self.matching_limit) |
|
1269 if len(result) >= self.matching_limit |
|
1270 call s:HighlightError() |
|
1271 endif |
|
1272 return map(result, 's:FormatCompletionItem(v:val, -1, v:val, self.trim_length, "", a:base, 1)') |
|
1273 endfunction |
|
1274 |
|
1275 function! g:FuzzyFinderMode.TaggedFile.find_tagged_file(pattern, matching_limit) |
|
1276 if !len(self.tag_files) |
|
1277 return [] |
|
1278 endif |
|
1279 |
|
1280 let key = join(self.tag_files, "\n") |
|
1281 |
|
1282 " cache not created or tags file updated? |
|
1283 call extend(self, { 'cache' : {} }, 'keep') |
|
1284 if !exists('self.cache[key]') || max(map(copy(self.tag_files), 'getftime(v:val) >= self.cache[key].time')) |
|
1285 echo 'Caching tagged-file list...' |
|
1286 let self.cache[key] = { |
|
1287 \ 'time' : localtime(), |
|
1288 \ 'data' : s:Unique(s:Concat(map(copy(self.tag_files), 's:GetTaggedFileList(v:val)'))), |
|
1289 \ } |
|
1290 endif |
|
1291 |
|
1292 echo 'Filtering tagged-file list...' |
|
1293 return s:FilterEx(map(self.cache[key].data, 'fnamemodify(v:val, '':.'')'), |
|
1294 \ 'v:val =~ ' . string(a:pattern), |
|
1295 \ a:matching_limit) |
|
1296 |
|
1297 endfunction |
|
1298 |
|
1299 "----------------------------------------------------------------------------- |
|
1300 " sets or restores temporary options |
|
1301 let s:OptionManager = { 'originals' : {} } |
|
1302 |
|
1303 function! s:OptionManager.set(name, value) |
|
1304 call extend(self.originals, { a:name : eval('&' . a:name) }, 'keep') |
|
1305 execute printf('let &%s = a:value', a:name) |
|
1306 endfunction |
|
1307 |
|
1308 function! s:OptionManager.restore_all() |
|
1309 for [name, value] in items(self.originals) |
|
1310 execute printf('let &%s = value', name) |
|
1311 endfor |
|
1312 let self.originals = {} |
|
1313 endfunction |
|
1314 |
|
1315 "----------------------------------------------------------------------------- |
|
1316 " manages buffer/window for fuzzyfinder |
|
1317 let s:WindowManager = { 'buf_nr' : -1 } |
|
1318 |
|
1319 function! s:WindowManager.activate(complete_func) |
|
1320 let self.prev_winnr = winnr() |
|
1321 let cwd = getcwd() |
|
1322 |
|
1323 if !bufexists(self.buf_nr) |
|
1324 leftabove 1new |
|
1325 file `='[Fuzzyfinder]'` |
|
1326 let self.buf_nr = bufnr('%') |
|
1327 elseif bufwinnr(self.buf_nr) == -1 |
|
1328 leftabove 1split |
|
1329 execute self.buf_nr . 'buffer' |
|
1330 delete _ |
|
1331 elseif bufwinnr(self.buf_nr) != bufwinnr('%') |
|
1332 execute bufwinnr(self.buf_nr) . 'wincmd w' |
|
1333 endif |
|
1334 |
|
1335 " countermeasure for auto-cd script |
|
1336 execute ':lcd ' . cwd |
|
1337 |
|
1338 setlocal filetype=fuzzyfinder |
|
1339 setlocal bufhidden=delete |
|
1340 setlocal buftype=nofile |
|
1341 setlocal noswapfile |
|
1342 setlocal nobuflisted |
|
1343 setlocal modifiable |
|
1344 setlocal nocursorline " for highlighting |
|
1345 setlocal nocursorcolumn " for highlighting |
|
1346 let &l:completefunc = a:complete_func |
|
1347 |
|
1348 redraw " for 'lazyredraw' |
|
1349 |
|
1350 " suspend autocomplpop.vim |
|
1351 if exists(':AutoComplPopLock') |
|
1352 :AutoComplPopLock |
|
1353 endif |
|
1354 endfunction |
|
1355 |
|
1356 function! s:WindowManager.deactivate() |
|
1357 " resume autocomplpop.vim |
|
1358 if exists(':AutoComplPopUnlock') |
|
1359 :AutoComplPopUnlock |
|
1360 endif |
|
1361 |
|
1362 close |
|
1363 execute self.prev_winnr . 'wincmd w' |
|
1364 endfunction |
|
1365 |
|
1366 "----------------------------------------------------------------------------- |
|
1367 let s:InfoFileManager = { 'originals' : {} } |
|
1368 |
|
1369 function! s:InfoFileManager.load() |
|
1370 for m in s:GetAvailableModes() |
|
1371 let m.info = [] |
|
1372 endfor |
|
1373 |
|
1374 try |
|
1375 let lines = readfile(expand(self.get_info_file())) |
|
1376 catch /.*/ |
|
1377 return |
|
1378 endtry |
|
1379 |
|
1380 " compatibility check |
|
1381 if !count(lines, self.get_info_version_line()) |
|
1382 call self.warn_old_info() |
|
1383 let g:FuzzyFinderOptions.Base.info_file = '' |
|
1384 return |
|
1385 endif |
|
1386 |
|
1387 for m in s:GetAvailableModes() |
|
1388 call m.deserialize_info(lines) |
|
1389 endfor |
|
1390 endfunction |
|
1391 |
|
1392 function! s:InfoFileManager.save() |
|
1393 let lines = [ self.get_info_version_line() ] |
|
1394 for m in s:GetAvailableModes() |
|
1395 let lines += m.serialize_info() |
|
1396 endfor |
|
1397 |
|
1398 try |
|
1399 call writefile(lines, expand(self.get_info_file())) |
|
1400 catch /.*/ |
|
1401 endtry |
|
1402 endfunction |
|
1403 |
|
1404 function! s:InfoFileManager.edit() |
|
1405 |
|
1406 new |
|
1407 file `='[FuzzyfinderInfo]'` |
|
1408 let self.bufnr = bufnr('%') |
|
1409 |
|
1410 setlocal filetype=vim |
|
1411 setlocal bufhidden=delete |
|
1412 setlocal buftype=acwrite |
|
1413 setlocal noswapfile |
|
1414 |
|
1415 augroup FuzzyfinderInfo |
|
1416 autocmd! |
|
1417 autocmd BufWriteCmd <buffer> call s:InfoFileManager.on_buf_write_cmd() |
|
1418 augroup END |
|
1419 |
|
1420 execute '0read ' . expand(self.get_info_file()) |
|
1421 setlocal nomodified |
|
1422 |
|
1423 endfunction |
|
1424 |
|
1425 function! s:InfoFileManager.on_buf_write_cmd() |
|
1426 for m in s:GetAvailableModes() |
|
1427 call m.deserialize_info(getline(1, '$')) |
|
1428 endfor |
|
1429 call self.save() |
|
1430 setlocal nomodified |
|
1431 execute printf('%dbdelete! ', self.bufnr) |
|
1432 echo "Information file updated" |
|
1433 endfunction |
|
1434 |
|
1435 function! s:InfoFileManager.get_info_version_line() |
|
1436 return "VERSION\t206" |
|
1437 endfunction |
|
1438 |
|
1439 function! s:InfoFileManager.get_info_file() |
|
1440 return g:FuzzyFinderOptions.Base.info_file |
|
1441 endfunction |
|
1442 |
|
1443 function! s:InfoFileManager.warn_old_info() |
|
1444 echohl WarningMsg |
|
1445 echo printf("==================================================\n" . |
|
1446 \ " Your Fuzzyfinder information file is no longer \n" . |
|
1447 \ " supported. Please remove \n" . |
|
1448 \ " %-48s\n" . |
|
1449 \ "==================================================\n" , |
|
1450 \ '"' . expand(self.get_info_file()) . '".') |
|
1451 echohl None |
|
1452 endfunction |
|
1453 |
|
1454 " }}}1 |
|
1455 "============================================================================= |
|
1456 " GLOBAL OPTIONS: {{{1 |
|
1457 " stores user-defined g:FuzzyFinderOptions ------------------------------ {{{2 |
|
1458 let user_options = (exists('g:FuzzyFinderOptions') ? g:FuzzyFinderOptions : {}) |
|
1459 " }}}2 |
|
1460 |
|
1461 " Initializes g:FuzzyFinderOptions. |
|
1462 let g:FuzzyFinderOptions = { 'Base':{}, 'Buffer':{}, 'File':{}, 'Dir':{}, 'MruFile':{}, 'MruCmd':{}, 'FavFile':{}, 'Tag':{}, 'TaggedFile':{}} |
|
1463 "----------------------------------------------------------------------------- |
|
1464 " [All Mode] This is mapped to select completion item or finish input and |
|
1465 " open a buffer/file in previous window. |
|
1466 let g:FuzzyFinderOptions.Base.key_open = '<CR>' |
|
1467 " [All Mode] This is mapped to select completion item or finish input and |
|
1468 " open a buffer/file in split new window |
|
1469 let g:FuzzyFinderOptions.Base.key_open_split = '<C-j>' |
|
1470 " [All Mode] This is mapped to select completion item or finish input and |
|
1471 " open a buffer/file in vertical-split new window. |
|
1472 let g:FuzzyFinderOptions.Base.key_open_vsplit = '<C-k>' |
|
1473 " [All Mode] This is mapped to select completion item or finish input and |
|
1474 " open a buffer/file in a new tab page. |
|
1475 let g:FuzzyFinderOptions.Base.key_open_tab = '<C-]>' |
|
1476 " [All Mode] This is mapped to switch to the next mode. |
|
1477 let g:FuzzyFinderOptions.Base.key_next_mode = '<C-l>' |
|
1478 " [All Mode] This is mapped to switch to the previous mode. |
|
1479 let g:FuzzyFinderOptions.Base.key_prev_mode = '<C-o>' |
|
1480 " [All Mode] This is mapped to temporarily switch whether or not to ignore |
|
1481 " case. |
|
1482 let g:FuzzyFinderOptions.Base.key_ignore_case = '<C-t>' |
|
1483 " [All Mode] This is the file name to write information of the MRU, etc. If |
|
1484 " "" was set, Fuzzyfinder does not write to the file. |
|
1485 let g:FuzzyFinderOptions.Base.info_file = '~/.vimfuzzyfinder' |
|
1486 " [All Mode] Fuzzyfinder does not start a completion if a length of entered |
|
1487 " text is less than this. |
|
1488 let g:FuzzyFinderOptions.Base.min_length = 0 |
|
1489 " [All Mode] This is a dictionary. Each value must be a list. All matchs of a |
|
1490 " key in entered text is expanded with the value. |
|
1491 let g:FuzzyFinderOptions.Base.abbrev_map = {} |
|
1492 " [All Mode] Fuzzyfinder ignores case in search patterns if non-zero is set. |
|
1493 let g:FuzzyFinderOptions.Base.ignore_case = 1 |
|
1494 " [All Mode] This is a string to format time string. See :help strftime() for |
|
1495 " details. |
|
1496 let g:FuzzyFinderOptions.Base.time_format = '(%x %H:%M:%S)' |
|
1497 " [All Mode] If a length of completion item is more than this, it is trimmed |
|
1498 " when shown in completion menu. |
|
1499 let g:FuzzyFinderOptions.Base.trim_length = 80 |
|
1500 " [All Mode] Fuzzyfinder does not remove caches of completion lists at the end |
|
1501 " of explorer to reuse at the next time if non-zero was set. |
|
1502 let g:FuzzyFinderOptions.Base.lasting_cache = 1 |
|
1503 " [All Mode] Fuzzyfinder uses Migemo if non-zero is set. |
|
1504 let g:FuzzyFinderOptions.Base.migemo_support = 0 |
|
1505 "----------------------------------------------------------------------------- |
|
1506 " [Buffer Mode] This disables all functions of this mode if zero was set. |
|
1507 let g:FuzzyFinderOptions.Buffer.mode_available = 1 |
|
1508 " [Buffer Mode] The prompt string. |
|
1509 let g:FuzzyFinderOptions.Buffer.prompt = '>Buffer>' |
|
1510 " [Buffer Mode] The highlight group name for a prompt string. |
|
1511 let g:FuzzyFinderOptions.Buffer.prompt_highlight = 'Question' |
|
1512 " [Buffer Mode] Pressing <BS> after a path separator deletes one directory |
|
1513 " name if non-zero is set. |
|
1514 let g:FuzzyFinderOptions.Buffer.smart_bs = 1 |
|
1515 " [Buffer Mode] The completion items is sorted in the order of recently used |
|
1516 " if non-zero is set. |
|
1517 let g:FuzzyFinderOptions.Buffer.mru_order = 1 |
|
1518 " [Buffer Mode] This is used to sort modes for switching to the next/previous |
|
1519 " mode. |
|
1520 let g:FuzzyFinderOptions.Buffer.switch_order = 10 |
|
1521 "----------------------------------------------------------------------------- |
|
1522 " [File Mode] This disables all functions of this mode if zero was set. |
|
1523 let g:FuzzyFinderOptions.File.mode_available = 1 |
|
1524 " [File Mode] The prompt string. |
|
1525 let g:FuzzyFinderOptions.File.prompt = '>File>' |
|
1526 " [File Mode] The highlight group name for a prompt string. |
|
1527 let g:FuzzyFinderOptions.File.prompt_highlight = 'Question' |
|
1528 " [File Mode] Pressing <BS> after a path separator deletes one directory name |
|
1529 " if non-zero is set. |
|
1530 let g:FuzzyFinderOptions.File.smart_bs = 1 |
|
1531 " [File Mode] This is used to sort modes for switching to the next/previous |
|
1532 " mode. |
|
1533 let g:FuzzyFinderOptions.File.switch_order = 20 |
|
1534 " [File Mode] The items matching this are excluded from the completion list. |
|
1535 let g:FuzzyFinderOptions.File.excluded_path = '\v\~$|\.o$|\.exe$|\.bak$|\.swp$|((^|[/\\])\.[/\\]$)' |
|
1536 " [File Mode] If a number of matched items was over this, the completion |
|
1537 " process is aborted. |
|
1538 let g:FuzzyFinderOptions.File.matching_limit = 200 |
|
1539 "----------------------------------------------------------------------------- |
|
1540 " [Directory Mode] This disables all functions of this mode if zero was set. |
|
1541 let g:FuzzyFinderOptions.Dir.mode_available = 1 |
|
1542 " [Directory Mode] The prompt string. |
|
1543 let g:FuzzyFinderOptions.Dir.prompt = '>Dir>' |
|
1544 " [Directory Mode] The highlight group name for a prompt string. |
|
1545 let g:FuzzyFinderOptions.Dir.prompt_highlight = 'Question' |
|
1546 " [Directory Mode] Pressing <BS> after a path separator deletes one directory |
|
1547 " name if non-zero is set. |
|
1548 let g:FuzzyFinderOptions.Dir.smart_bs = 1 |
|
1549 " [Directory Mode] This is used to sort modes for switching to the |
|
1550 " next/previous mode. |
|
1551 let g:FuzzyFinderOptions.Dir.switch_order = 30 |
|
1552 " [Directory Mode] The items matching this are excluded from the completion |
|
1553 " list. |
|
1554 let g:FuzzyFinderOptions.Dir.excluded_path = '\v(^|[/\\])\.{1,2}[/\\]$' |
|
1555 "----------------------------------------------------------------------------- |
|
1556 " [Mru-File Mode] This disables all functions of this mode if zero was set. |
|
1557 let g:FuzzyFinderOptions.MruFile.mode_available = 1 |
|
1558 " [Mru-File Mode] The prompt string. |
|
1559 let g:FuzzyFinderOptions.MruFile.prompt = '>MruFile>' |
|
1560 " [Mru-File Mode] The highlight group name for a prompt string. |
|
1561 let g:FuzzyFinderOptions.MruFile.prompt_highlight = 'Question' |
|
1562 " [Mru-File Mode] Pressing <BS> after a path separator deletes one directory |
|
1563 " name if non-zero is set. |
|
1564 let g:FuzzyFinderOptions.MruFile.smart_bs = 1 |
|
1565 " [Mru-File Mode] This is used to sort modes for switching to the |
|
1566 " next/previous mode. |
|
1567 let g:FuzzyFinderOptions.MruFile.switch_order = 40 |
|
1568 " [Mru-File Mode] The items matching this are excluded from the completion |
|
1569 " list. |
|
1570 let g:FuzzyFinderOptions.MruFile.excluded_path = '\v\~$|\.bak$|\.swp$' |
|
1571 " [Mru-File Mode] This is an upper limit of MRU items to be stored. |
|
1572 let g:FuzzyFinderOptions.MruFile.max_item = 99 |
|
1573 "----------------------------------------------------------------------------- |
|
1574 " [Mru-Cmd Mode] This disables all functions of this mode if zero was set. |
|
1575 let g:FuzzyFinderOptions.MruCmd.mode_available = 1 |
|
1576 " [Mru-Cmd Mode] The prompt string. |
|
1577 let g:FuzzyFinderOptions.MruCmd.prompt = '>MruCmd>' |
|
1578 " [Mru-Cmd Mode] The highlight group name for a prompt string. |
|
1579 let g:FuzzyFinderOptions.MruCmd.prompt_highlight = 'Question' |
|
1580 " [Mru-Cmd Mode] Pressing <BS> after a path separator deletes one directory |
|
1581 " name if non-zero is set. |
|
1582 let g:FuzzyFinderOptions.MruCmd.smart_bs = 0 |
|
1583 " [Mru-Cmd Mode] This is used to sort modes for switching to the next/previous |
|
1584 " mode. |
|
1585 let g:FuzzyFinderOptions.MruCmd.switch_order = 50 |
|
1586 " [Mru-Cmd Mode] The items matching this are excluded from the completion |
|
1587 " list. |
|
1588 let g:FuzzyFinderOptions.MruCmd.excluded_command = '^$' |
|
1589 " [Mru-Cmd Mode] This is an upper limit of MRU items to be stored. |
|
1590 let g:FuzzyFinderOptions.MruCmd.max_item = 99 |
|
1591 "----------------------------------------------------------------------------- |
|
1592 " [Favorite-File Mode] This disables all functions of this mode if zero was |
|
1593 " set. |
|
1594 let g:FuzzyFinderOptions.FavFile.mode_available = 1 |
|
1595 " [Favorite-File Mode] The prompt string. |
|
1596 let g:FuzzyFinderOptions.FavFile.prompt = '>FavFile>' |
|
1597 " [Favorite-File Mode] The highlight group name for a prompt string. |
|
1598 let g:FuzzyFinderOptions.FavFile.prompt_highlight = 'Question' |
|
1599 " [Favorite-File Mode] Pressing <BS> after a path separator deletes one |
|
1600 " directory name if non-zero is set. |
|
1601 let g:FuzzyFinderOptions.FavFile.smart_bs = 1 |
|
1602 " [Favorite-File Mode] This is used to sort modes for switching to the |
|
1603 " next/previous mode. |
|
1604 let g:FuzzyFinderOptions.FavFile.switch_order = 60 |
|
1605 "----------------------------------------------------------------------------- |
|
1606 " [Tag Mode] This disables all functions of this mode if zero was set. |
|
1607 let g:FuzzyFinderOptions.Tag.mode_available = 1 |
|
1608 " [Tag Mode] The prompt string. |
|
1609 let g:FuzzyFinderOptions.Tag.prompt = '>Tag>' |
|
1610 " [Tag Mode] The highlight group name for a prompt string. |
|
1611 let g:FuzzyFinderOptions.Tag.prompt_highlight = 'Question' |
|
1612 " [Tag Mode] Pressing <BS> after a path separator deletes one directory name |
|
1613 " if non-zero is set. |
|
1614 let g:FuzzyFinderOptions.Tag.smart_bs = 0 |
|
1615 " [Tag Mode] This is used to sort modes for switching to the next/previous |
|
1616 " mode. |
|
1617 let g:FuzzyFinderOptions.Tag.switch_order = 70 |
|
1618 " [Tag Mode] The items matching this are excluded from the completion list. |
|
1619 let g:FuzzyFinderOptions.Tag.excluded_path = '\v\~$|\.bak$|\.swp$' |
|
1620 " [Tag Mode] If a number of matched items was over this, the completion |
|
1621 " process is aborted. |
|
1622 let g:FuzzyFinderOptions.Tag.matching_limit = 200 |
|
1623 "----------------------------------------------------------------------------- |
|
1624 " [Tagged-File Mode] This disables all functions of this mode if zero was set. |
|
1625 let g:FuzzyFinderOptions.TaggedFile.mode_available = 1 |
|
1626 " [Tagged-File Mode] The prompt string. |
|
1627 let g:FuzzyFinderOptions.TaggedFile.prompt = '>TaggedFile>' |
|
1628 " [Tagged-File Mode] The highlight group name for a prompt string. |
|
1629 let g:FuzzyFinderOptions.TaggedFile.prompt_highlight = 'Question' |
|
1630 " [Tagged-File Mode] Pressing <BS> after a path separator deletes one |
|
1631 " directory name if non-zero is set. |
|
1632 let g:FuzzyFinderOptions.TaggedFile.smart_bs = 0 |
|
1633 " [Tagged-File Mode] This is used to sort modes for switching to the |
|
1634 " next/previous mode. |
|
1635 let g:FuzzyFinderOptions.TaggedFile.switch_order = 80 |
|
1636 " [Tagged-File Mode] If a number of matched items was over this, the |
|
1637 " completion process is aborted. |
|
1638 let g:FuzzyFinderOptions.TaggedFile.matching_limit = 200 |
|
1639 |
|
1640 " overwrites default values of g:FuzzyFinderOptions with user-defined values - {{{2 |
|
1641 call map(user_options, 'extend(g:FuzzyFinderOptions[v:key], v:val, ''force'')') |
|
1642 call map(copy(g:FuzzyFinderMode), 'v:val.extend_options()') |
|
1643 " }}}2 |
|
1644 |
|
1645 " }}}1 |
|
1646 "============================================================================= |
|
1647 " COMMANDS/AUTOCOMMANDS/MAPPINGS/ETC.: {{{1 |
|
1648 |
|
1649 let s:PATH_SEPARATOR = (has('win32') || has('win64') ? '\' : '/') |
|
1650 let s:MATCHING_RATE_BASE = 10000000 |
|
1651 let s:ABBR_TRIM_MARK = '...' |
|
1652 |
|
1653 augroup FuzzyfinderGlobal |
|
1654 autocmd! |
|
1655 autocmd BufEnter * for m in s:GetAvailableModes() | call m.extend_options() | call m.on_buf_enter() | endfor |
|
1656 autocmd BufWritePost * for m in s:GetAvailableModes() | call m.extend_options() | call m.on_buf_write_post() | endfor |
|
1657 augroup END |
|
1658 |
|
1659 " cnoremap has a problem, which doesn't expand cabbrev. |
|
1660 cmap <silent> <expr> <CR> <SID>OnCmdCR() |
|
1661 |
|
1662 command! -bang -narg=? -complete=buffer FuzzyFinderBuffer call g:FuzzyFinderMode.Buffer.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles()) |
|
1663 command! -bang -narg=? -complete=file FuzzyFinderFile call g:FuzzyFinderMode.File.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles()) |
|
1664 command! -bang -narg=? -complete=dir FuzzyFinderDir call g:FuzzyFinderMode.Dir.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles()) |
|
1665 command! -bang -narg=? -complete=file FuzzyFinderMruFile call g:FuzzyFinderMode.MruFile.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles()) |
|
1666 command! -bang -narg=? -complete=file FuzzyFinderMruCmd call g:FuzzyFinderMode.MruCmd.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles()) |
|
1667 command! -bang -narg=? -complete=file FuzzyFinderFavFile call g:FuzzyFinderMode.FavFile.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles()) |
|
1668 command! -bang -narg=? -complete=tag FuzzyFinderTag call g:FuzzyFinderMode.Tag.launch (<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles()) |
|
1669 command! -bang -narg=? -complete=file FuzzyFinderTaggedFile call g:FuzzyFinderMode.TaggedFile.launch(<q-args>, len(<q-bang>), bufnr('%'), s:GetCurrentTagFiles()) |
|
1670 command! -bang -narg=? -complete=file FuzzyFinderEditInfo call s:InfoFileManager.edit() |
|
1671 command! -bang -narg=? -complete=file FuzzyFinderAddFavFile call g:FuzzyFinderMode.FavFile.add(<q-args>, 1) |
|
1672 command! -bang -narg=0 FuzzyFinderRemoveCache for m in s:GetAvailableModes() | call m.empty_cache_if_existed(1) | endfor |
|
1673 |
|
1674 " }}}1 |
|
1675 "============================================================================= |
|
1676 " vim: set fdm=marker: |