Mercurial > dotfiles
comparison .vim/plugin/fuzzyfinder.vim @ 0:c30d68fbd368
Initial import from svn.
| author | Augie Fackler <durin42@gmail.com> |
|---|---|
| date | Wed, 26 Nov 2008 10:56:09 -0600 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:c30d68fbd368 |
|---|---|
| 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: |
