diff options
Diffstat (limited to 'vim/autoload/fuf.vim')
-rw-r--r-- | vim/autoload/fuf.vim | 1046 |
1 files changed, 0 insertions, 1046 deletions
diff --git a/vim/autoload/fuf.vim b/vim/autoload/fuf.vim deleted file mode 100644 index fe9e6eb..0000000 --- a/vim/autoload/fuf.vim +++ /dev/null @@ -1,1046 +0,0 @@ -"============================================================================= -" Copyright (c) 2007-2010 Takeshi NISHIDA -" -"============================================================================= -" LOAD GUARD {{{1 - -if !l9#guardScriptLoading(expand('<sfile>:p'), 0, 0, []) - finish -endif - -" }}}1 -"============================================================================= -" GLOBAL FUNCTIONS {{{1 - - -" returns list of paths. -" An argument for glob() is normalized in order to avoid a bug on Windows. -function fuf#glob(expr) - " Substitutes "\", because on Windows, "**\" doesn't include ".\", - " but "**/" include "./". I don't know why. - return split(glob(substitute(a:expr, '\', '/', 'g')), "\n") -endfunction - -" -function fuf#countModifiedFiles(files, time) - return len(filter(copy(a:files), 'getftime(expand(v:val)) > a:time')) -endfunction - -" -function fuf#getCurrentTagFiles() - return sort(filter(map(tagfiles(), 'fnamemodify(v:val, '':p'')'), 'filereadable(v:val)')) -endfunction - -" -function fuf#mapToSetSerialIndex(in, offset) - for i in range(len(a:in)) - let a:in[i].index = i + a:offset - endfor - return a:in -endfunction - -" -function fuf#updateMruList(mrulist, newItem, maxItem, exclude) - let result = copy(a:mrulist) - let result = filter(result,'v:val.word !=# a:newItem.word') - let result = insert(result, a:newItem) - if len(a:exclude) - let result = filter(result, 'v:val.word !~ a:exclude') - endif - return result[0 : a:maxItem - 1] -endfunction - -" takes suffix number. if no digits, returns -1 -function fuf#suffixNumber(str) - let s = matchstr(a:str, '\d\+$') - return (len(s) ? str2nr(s) : -1) -endfunction - -" "foo/bar/buz/hoge" -> { head: "foo/bar/buz/", tail: "hoge" } -function fuf#splitPath(path) - let head = matchstr(a:path, '^.*[/\\]') - return { - \ 'head' : head, - \ 'tail' : a:path[strlen(head):] - \ } -endfunction - -" "foo/.../bar/...hoge" -> "foo/.../bar/../../hoge" -function fuf#expandTailDotSequenceToParentDir(pattern) - return substitute(a:pattern, '^\(.*[/\\]\)\?\zs\.\(\.\+\)\ze[^/\\]*$', - \ '\=repeat(".." . l9#getPathSeparator(), len(submatch(2)))', '') -endfunction - -" -function fuf#formatPrompt(prompt, partialMatching, otherString) - let indicator = escape((a:partialMatching ? '!' : '') . a:otherString, '\') - return substitute(a:prompt, '[]', indicator, 'g') -endfunction - -" -function fuf#getFileLines(file) - let bufnr = (type(a:file) ==# type(0) ? a:file : bufnr('^' . a:file . '$')) - let lines = getbufline(bufnr, 1, '$') - if !empty(lines) - return lines - endif - return l9#readFile(a:file) -endfunction - -" -function fuf#makePreviewLinesAround(lines, indices, page, maxHeight) - let index = ((empty(a:indices) ? 0 : a:indices[0]) - \ + a:page * a:maxHeight) % len(a:lines) - if empty(a:lines) || a:maxHeight <= 0 - return [] - endif - let beg = max([0, index - a:maxHeight / 2]) - let end = min([beg + a:maxHeight, len(a:lines)]) - let beg = max([0, end - a:maxHeight]) - let lines = [] - for i in range(beg, end - 1) - let mark = (count(a:indices, i) ? '>' : ' ') - call add(lines, printf('%s%4d ', mark, i + 1) . a:lines[i]) - endfor - return lines -endfunction - -" a:file: a path string or a buffer number -function fuf#makePreviewLinesForFile(file, count, maxHeight) - let lines = fuf#getFileLines(a:file) - if empty(lines) - return [] - endif - let bufnr = (type(a:file) ==# type(0) ? a:file : bufnr('^' . a:file . '$')) - if exists('s:bufferCursorPosMap[bufnr]') - let indices = [s:bufferCursorPosMap[bufnr][1] - 1] - else - let indices = [] - endif - return fuf#makePreviewLinesAround( - \ lines, indices, a:count, a:maxHeight) -endfunction - -" -function fuf#echoWarning(msg) - call l9#echoHl('WarningMsg', a:msg, '[fuf] ', 1) -endfunction - -" -function fuf#echoError(msg) - call l9#echoHl('ErrorMsg', a:msg, '[fuf] ', 1) -endfunction - -" -function fuf#openBuffer(bufNr, mode, reuse) - if a:reuse && ((a:mode ==# s:OPEN_TYPE_SPLIT && - \ l9#moveToBufferWindowInCurrentTabpage(a:bufNr)) || - \ (a:mode ==# s:OPEN_TYPE_VSPLIT && - \ l9#moveToBufferWindowInCurrentTabpage(a:bufNr)) || - \ (a:mode ==# s:OPEN_TYPE_TAB && - \ l9#moveToBufferWindowInOtherTabpage(a:bufNr))) - return - endif - execute printf({ - \ s:OPEN_TYPE_CURRENT : '%sbuffer' , - \ s:OPEN_TYPE_SPLIT : '%ssbuffer' , - \ s:OPEN_TYPE_VSPLIT : 'vertical %ssbuffer', - \ s:OPEN_TYPE_TAB : 'tab %ssbuffer' , - \ }[a:mode], a:bufNr) -endfunction - -" -function fuf#openFile(path, mode, reuse) - let bufNr = bufnr('^' . a:path . '$') - if bufNr > -1 - call fuf#openBuffer(bufNr, a:mode, a:reuse) - else - execute { - \ s:OPEN_TYPE_CURRENT : 'edit ' , - \ s:OPEN_TYPE_SPLIT : 'split ' , - \ s:OPEN_TYPE_VSPLIT : 'vsplit ' , - \ s:OPEN_TYPE_TAB : 'tabedit ', - \ }[a:mode] . fnameescape(fnamemodify(a:path, ':~:.')) - endif -endfunction - -" -function fuf#openTag(tag, mode) - execute { - \ s:OPEN_TYPE_CURRENT : 'tjump ' , - \ s:OPEN_TYPE_SPLIT : 'stjump ' , - \ s:OPEN_TYPE_VSPLIT : 'vertical stjump ', - \ s:OPEN_TYPE_TAB : 'tab stjump ' , - \ }[a:mode] . a:tag -endfunction - -" -function fuf#openHelp(tag, mode) - execute { - \ s:OPEN_TYPE_CURRENT : 'help ' , - \ s:OPEN_TYPE_SPLIT : 'help ' , - \ s:OPEN_TYPE_VSPLIT : 'vertical help ', - \ s:OPEN_TYPE_TAB : 'tab help ' , - \ }[a:mode] . a:tag -endfunction - -" -function fuf#prejump(mode) - execute { - \ s:OPEN_TYPE_CURRENT : '' , - \ s:OPEN_TYPE_SPLIT : 'split' , - \ s:OPEN_TYPE_VSPLIT : 'vsplit' , - \ s:OPEN_TYPE_TAB : 'tab split', - \ }[a:mode] -endfunction - -" -function fuf#compareRanks(i1, i2) - if exists('a:i1.ranks') && exists('a:i2.ranks') - for i in range(min([len(a:i1.ranks), len(a:i2.ranks)])) - if a:i1.ranks[i] > a:i2.ranks[i] - return +1 - elseif a:i1.ranks[i] < a:i2.ranks[i] - return -1 - endif - endfor - endif - return 0 -endfunction - -" -function fuf#makePathItem(fname, menu, appendsDirSuffix) - let pathPair = fuf#splitPath(a:fname) - let dirSuffix = (a:appendsDirSuffix && isdirectory(expand(a:fname)) - \ ? l9#getPathSeparator() - \ : '') - return { - \ 'word' : a:fname . dirSuffix, - \ 'wordForPrimaryHead': s:toLowerForIgnoringCase(pathPair.head), - \ 'wordForPrimaryTail': s:toLowerForIgnoringCase(pathPair.tail), - \ 'wordForBoundary' : s:toLowerForIgnoringCase(s:getWordBoundaries(pathPair.tail)), - \ 'wordForRefining' : s:toLowerForIgnoringCase(a:fname . dirSuffix), - \ 'wordForRank' : s:toLowerForIgnoringCase(pathPair.tail), - \ 'menu' : a:menu, - \ } -endfunction - -" -function fuf#makeNonPathItem(word, menu) - let wordL = s:toLowerForIgnoringCase(a:word) - return { - \ 'word' : a:word, - \ 'wordForPrimary' : wordL, - \ 'wordForBoundary': s:toLowerForIgnoringCase(s:getWordBoundaries(a:word)), - \ 'wordForRefining': wordL, - \ 'wordForRank' : wordL, - \ 'menu' : a:menu, - \ } -endfunction - -" -function fuf#makePatternSet(patternBase, interpreter, partialMatching) - let MakeMatchingExpr = function(a:partialMatching - \ ? 's:makePartialMatchingExpr' - \ : 's:makeFuzzyMatchingExpr') - let [primary; refinings] = split(a:patternBase, g:fuf_patternSeparator, 1) - let elements = call(a:interpreter, [primary]) - let primaryExprs = map(elements.matchingPairs, 'MakeMatchingExpr(v:val[0], v:val[1])') - let refiningExprs = map(refinings, 's:makeRefiningExpr(v:val)') - return { - \ 'primary' : elements.primary, - \ 'primaryForRank': elements.primaryForRank, - \ 'filteringExpr' : join(primaryExprs + refiningExprs, ' && '), - \ } -endfunction - -" -function fuf#enumExpandedDirsEntries(dir, exclude) - let entries = fuf#glob(a:dir . '*') + fuf#glob(a:dir . '.*') - " removes "*/." and "*/.." - call filter(entries, 'v:val !~ ''\v(^|[/\\])\.\.?$''') - call map(entries, 'fuf#makePathItem(v:val, "", 1)') - if len(a:exclude) - call filter(entries, 'v:val.word !~ a:exclude') - endif - return entries -endfunction - -" -function fuf#mapToSetAbbrWithSnippedWordAsPath(items) - let maxLenStats = {} - call map(a:items, 's:makeFileAbbrInfo(v:val, maxLenStats)') - let snippedHeads = - \ map(maxLenStats, 's:getSnippedHead(v:key[: -2], v:val)') - return map(a:items, 's:setAbbrWithFileAbbrData(v:val, snippedHeads)') -endfunction - -" -function fuf#setAbbrWithFormattedWord(item, abbrIndex) - let lenMenu = (exists('a:item.menu') ? len(a:item.menu) + 2 : 0) - let abbrPrefix = (exists('a:item.abbrPrefix') ? a:item.abbrPrefix : '') - let a:item.abbr = abbrPrefix . a:item.word - if a:abbrIndex - let a:item.abbr = printf('%4d: ', a:item.index) . a:item.abbr - endif - let a:item.abbr = l9#snipTail(a:item.abbr, g:fuf_maxMenuWidth - lenMenu, s:ABBR_SNIP_MASK) - return a:item -endfunction - -" -function s:onCommandPre() - for m in filter(copy(fuf#getModeNames()), 'fuf#{v:val}#requiresOnCommandPre()') - call fuf#{m}#onCommandPre(getcmdtype() . getcmdline()) - endfor - " lets last entry become the newest in the history - call histadd(getcmdtype(), getcmdline()) - " this is not mapped again (:help recursive_mapping) - return "\<CR>" -endfunction - -" -let s:modeNames = [] - -" -function fuf#addMode(modeName) - if count(g:fuf_modesDisable, a:modeName) > 0 - return - endif - call add(s:modeNames, a:modeName) - call fuf#{a:modeName}#renewCache() - call fuf#{a:modeName}#onInit() - if fuf#{a:modeName}#requiresOnCommandPre() - " cnoremap has a problem, which doesn't expand cabbrev. - cmap <silent> <expr> <CR> <SID>onCommandPre() - endif -endfunction - -" -function fuf#getModeNames() - return s:modeNames -endfunction - -" -function fuf#defineLaunchCommand(CmdName, modeName, prefixInitialPattern, tempVars) - if empty(a:tempVars) - let preCmd = '' - else - let preCmd = printf('call l9#tempvariables#setList(%s, %s) | ', - \ string(s:TEMP_VARIABLES_GROUP), string(a:tempVars)) - endif - execute printf('command! -range -bang -narg=? %s %s call fuf#launch(%s, %s . <q-args>, len(<q-bang>))', - \ a:CmdName, preCmd, string(a:modeName), a:prefixInitialPattern) -endfunction - -" -function fuf#defineKeyMappingInHandler(key, func) - " hacks to be able to use feedkeys(). - execute printf( - \ 'inoremap <buffer> <silent> %s <C-r>=fuf#getRunningHandler().%s ? "" : ""<CR>', - \ a:key, a:func) -endfunction - -" -let s:oneTimeVariables = [] - -" -function fuf#setOneTimeVariables(...) - let s:oneTimeVariables += a:000 -endfunction - -" -function fuf#launch(modeName, initialPattern, partialMatching) - if exists('s:runningHandler') - call fuf#echoWarning('FuzzyFinder is running.') - endif - if count(fuf#getModeNames(), a:modeName) == 0 - echoerr 'This mode is not available: ' . a:modeName - return - endif - let s:runningHandler = fuf#{a:modeName}#createHandler(copy(s:handlerBase)) - let s:runningHandler.stats = fuf#loadDataFile(s:runningHandler.getModeName(), 'stats') - let s:runningHandler.partialMatching = a:partialMatching - let s:runningHandler.bufNrPrev = bufnr('%') - let s:runningHandler.lastCol = -1 - let s:runningHandler.windowRestoringCommand = winrestcmd() - call s:runningHandler.onModeEnterPre() - " NOTE: updatetime is set, because in Buffer-Tag mode on Vim 7.3 on Windows, - " Vim keeps from triggering CursorMovedI for updatetime after system() is - " called. I don't know why. - call fuf#setOneTimeVariables( - \ ['&completeopt', 'menuone'], - \ ['&ignorecase', 0], - \ ['&updatetime', 10], - \ ) - if s:runningHandler.getPreviewHeight() > 0 - call fuf#setOneTimeVariables( - \ ['&cmdheight', s:runningHandler.getPreviewHeight() + 1]) - endif - call l9#tempvariables#setList(s:TEMP_VARIABLES_GROUP, s:oneTimeVariables) - let s:oneTimeVariables = [] - call s:activateFufBuffer() - augroup FufLocal - autocmd! - autocmd CursorMovedI <buffer> call s:runningHandler.onCursorMovedI() - autocmd InsertLeave <buffer> nested call s:runningHandler.onInsertLeave() - augroup END - for [key, func] in [ - \ [ g:fuf_keyOpen , 'onCr(' . s:OPEN_TYPE_CURRENT . ')' ], - \ [ g:fuf_keyOpenSplit , 'onCr(' . s:OPEN_TYPE_SPLIT . ')' ], - \ [ g:fuf_keyOpenVsplit , 'onCr(' . s:OPEN_TYPE_VSPLIT . ')' ], - \ [ g:fuf_keyOpenTabpage , 'onCr(' . s:OPEN_TYPE_TAB . ')' ], - \ [ '<BS>' , 'onBs()' ], - \ [ '<C-h>' , 'onBs()' ], - \ [ '<C-w>' , 'onDeleteWord()' ], - \ [ g:fuf_keyPreview , 'onPreviewBase(1)' ], - \ [ g:fuf_keyNextMode , 'onSwitchMode(+1)' ], - \ [ g:fuf_keyPrevMode , 'onSwitchMode(-1)' ], - \ [ g:fuf_keySwitchMatching, 'onSwitchMatching()' ], - \ [ g:fuf_keyPrevPattern , 'onRecallPattern(+1)' ], - \ [ g:fuf_keyNextPattern , 'onRecallPattern(-1)' ], - \ ] - call fuf#defineKeyMappingInHandler(key, func) - endfor - " Starts Insert mode and makes CursorMovedI event now. Command prompt is - " needed to forces a completion menu to update every typing. - call setline(1, s:runningHandler.getPrompt() . a:initialPattern) - call s:runningHandler.onModeEnterPost() - call feedkeys("A", 'n') " startinsert! does not work in InsertLeave event handler - redraw -endfunction - -" -function fuf#loadDataFile(modeName, dataName) - if !s:dataFileAvailable - return [] - endif - let lines = l9#readFile(l9#concatPaths([g:fuf_dataDir, a:modeName, a:dataName])) - return map(lines, 'eval(v:val)') -endfunction - -" -function fuf#saveDataFile(modeName, dataName, items) - if !s:dataFileAvailable - return -1 - endif - let lines = map(copy(a:items), 'string(v:val)') - return l9#writeFile(lines, l9#concatPaths([g:fuf_dataDir, a:modeName, a:dataName])) -endfunction - -" -function fuf#getDataFileTime(modeName, dataName) - if !s:dataFileAvailable - return -1 - endif - return getftime(expand(l9#concatPaths([g:fuf_dataDir, a:modeName, a:dataName]))) -endfunction - -" -function s:createDataBufferListener(dataFile) - let listener = { 'dataFile': a:dataFile } - - function listener.onWrite(lines) - let [modeName, dataName] = split(self.dataFile, l9#getPathSeparator()) - let items = map(filter(a:lines, '!empty(v:val)'), 'eval(v:val)') - call fuf#saveDataFile(modeName, dataName, items) - echo "Data files updated" - return 1 - endfunction - - return listener -endfunction - -" -function s:createEditDataListener() - let listener = {} - - function listener.onComplete(dataFile, method) - let bufName = '[fuf-info]' - let lines = l9#readFile(l9#concatPaths([g:fuf_dataDir, a:dataFile])) - call l9#tempbuffer#openWritable(bufName, 'vim', lines, 0, 0, 0, - \ s:createDataBufferListener(a:dataFile)) - endfunction - - return listener -endfunction - -" -function s:getEditableDataFiles(modeName) - let dataFiles = fuf#{a:modeName}#getEditableDataNames() - call filter(dataFiles, 'fuf#getDataFileTime(a:modeName, v:val) != -1') - return map(dataFiles, 'l9#concatPaths([a:modeName, v:val])') -endfunction - -" -function fuf#editDataFile() - let dataFiles = map(copy(fuf#getModeNames()), 's:getEditableDataFiles(v:val)') - let dataFiles = l9#concat(dataFiles) - call fuf#callbackitem#launch('', 0, '>Mode>', s:createEditDataListener(), dataFiles, 0) -endfunction - -" -function fuf#getRunningHandler() - return s:runningHandler -endfunction - -" -function fuf#onComplete(findstart, base) - return s:runningHandler.onComplete(a:findstart, a:base) -endfunction - -" }}}1 -"============================================================================= -" LOCAL FUNCTIONS/VARIABLES {{{1 - -let s:TEMP_VARIABLES_GROUP = expand('<sfile>:p') -let s:ABBR_SNIP_MASK = '...' -let s:OPEN_TYPE_CURRENT = 1 -let s:OPEN_TYPE_SPLIT = 2 -let s:OPEN_TYPE_VSPLIT = 3 -let s:OPEN_TYPE_TAB = 4 - -" a:pattern: 'str' -> '\V\.\*s\.\*t\.\*r\.\*' -function s:makeFuzzyMatchingExpr(target, pattern) - let wi = '' - for c in split(a:pattern, '\zs') - if wi =~# '[^*?]$' && c !~ '[*?]' - let wi .= '*' - endif - let wi .= c - endfor - return s:makePartialMatchingExpr(a:target, wi) -endfunction - -" a:pattern: 'str' -> '\Vstr' -" 'st*r' -> '\Vst\.\*r' -function s:makePartialMatchingExpr(target, pattern) - let patternMigemo = s:makeAdditionalMigemoPattern(a:pattern) - if a:pattern !~ '[*?]' && empty(patternMigemo) - " NOTE: stridx is faster than regexp matching - return 'stridx(' . a:target . ', ' . string(a:pattern) . ') >= 0' - endif - return a:target . ' =~# ' . - \ string(l9#convertWildcardToRegexp(a:pattern)) . patternMigemo -endfunction - -" -function s:makeRefiningExpr(pattern) - if g:fuf_fuzzyRefining - let expr = s:makeFuzzyMatchingExpr('v:val.wordForRefining', a:pattern) - else - let expr = s:makePartialMatchingExpr('v:val.wordForRefining', a:pattern) - endif - if a:pattern =~# '\D' - return expr - else - return '(' . expr . ' || v:val.index == ' . string(a:pattern) . ')' - endif -endfunction - -" -function s:makeAdditionalMigemoPattern(pattern) - if !g:fuf_useMigemo || a:pattern =~# '[^\x01-\x7e]' - return '' - endif - return '\|\m' . substitute(migemo(a:pattern), '\\_s\*', '.*', 'g') -endfunction - -" -function s:interpretPrimaryPatternForPathTail(pattern) - let pattern = fuf#expandTailDotSequenceToParentDir(a:pattern) - let pairL = fuf#splitPath(s:toLowerForIgnoringCase(pattern)) - return { - \ 'primary' : pattern, - \ 'primaryForRank': pairL.tail, - \ 'matchingPairs' : [['v:val.wordForPrimaryTail', pairL.tail],], - \ } -endfunction - -" -function s:interpretPrimaryPatternForPath(pattern) - let pattern = fuf#expandTailDotSequenceToParentDir(a:pattern) - let patternL = s:toLowerForIgnoringCase(pattern) - let pairL = fuf#splitPath(patternL) - if g:fuf_splitPathMatching - let matches = [ - \ ['v:val.wordForPrimaryHead', pairL.head], - \ ['v:val.wordForPrimaryTail', pairL.tail], - \ ] - else - let matches = [ - \ ['v:val.wordForPrimaryHead . v:val.wordForPrimaryTail', patternL], - \ ] - endif - return { - \ 'primary' : pattern, - \ 'primaryForRank': pairL.tail, - \ 'matchingPairs' : matches, - \ } -endfunction - -" -function s:interpretPrimaryPatternForNonPath(pattern) - let patternL = s:toLowerForIgnoringCase(a:pattern) - return { - \ 'primary' : a:pattern, - \ 'primaryForRank': patternL, - \ 'matchingPairs' : [['v:val.wordForPrimary', patternL],], - \ } -endfunction - -" -function s:getWordBoundaries(word) - return substitute(a:word, '\a\zs\l\+\|\zs\A', '', 'g') -endfunction - -" -function s:toLowerForIgnoringCase(str) - return (g:fuf_ignoreCase ? tolower(a:str) : a:str) -endfunction - -" -function s:setRanks(item, pattern, exprBoundary, stats) - "let word2 = substitute(a:eval_word, '\a\zs\l\+\|\zs\A', '', 'g') - let a:item.ranks = [ - \ s:evaluateLearningRank(a:item.word, a:stats), - \ -s:scoreSequentialMatching(a:item.wordForRank, a:pattern), - \ -s:scoreBoundaryMatching(a:item.wordForBoundary, - \ a:pattern, a:exprBoundary), - \ a:item.index, - \ ] - return a:item -endfunction - -" -function s:evaluateLearningRank(word, stats) - for i in range(len(a:stats)) - if a:stats[i].word ==# a:word - return i - endif - endfor - return len(a:stats) -endfunction - -" range of return value is [0.0, 1.0] -function s:scoreSequentialMatching(word, pattern) - if empty(a:pattern) - return str2float('0.0') - endif - let pos = stridx(a:word, a:pattern) - if pos < 0 - return str2float('0.0') - endif - let lenRest = len(a:word) - len(a:pattern) - pos - return str2float(pos == 0 ? '0.5' : '0.0') + str2float('0.5') / (lenRest + 1) -endfunction - -" range of return value is [0.0, 1.0] -function s:scoreBoundaryMatching(wordForBoundary, pattern, exprBoundary) - if empty(a:pattern) - return str2float('0.0') - endif - if !eval(a:exprBoundary) - return 0 - endif - return (s:scoreSequentialMatching(a:wordForBoundary, a:pattern) + 1) / 2 -endfunction - -" -function s:highlightPrompt(prompt) - syntax clear - execute printf('syntax match %s /^\V%s/', g:fuf_promptHighlight, escape(a:prompt, '\/')) -endfunction - -" -function s:highlightError() - syntax clear - syntax match Error /^.*$/ -endfunction - -" -function s:expandAbbrevMap(pattern, abbrevMap) - let result = [a:pattern] - for [pattern, subs] in items(a:abbrevMap) - let exprs = result - let result = [] - for expr in exprs - let result += map(copy(subs), 'substitute(expr, pattern, escape(v:val, ''\''), "g")') - endfor - endfor - return l9#unique(result) -endfunction - -" -function s:makeFileAbbrInfo(item, maxLenStats) - let head = matchstr(a:item.word, '^.*[/\\]\ze.') - let a:item.abbr = { 'head' : head, - \ 'tail' : a:item.word[strlen(head):], - \ 'key' : head . '.', - \ 'prefix' : printf('%4d: ', a:item.index), } - if exists('a:item.abbrPrefix') - let a:item.abbr.prefix .= a:item.abbrPrefix - endif - let len = len(a:item.abbr.prefix) + len(a:item.word) + - \ (exists('a:item.menu') ? len(a:item.menu) + 2 : 0) - if !exists('a:maxLenStats[a:item.abbr.key]') || len > a:maxLenStats[a:item.abbr.key] - let a:maxLenStats[a:item.abbr.key] = len - endif - return a:item -endfunction - -" -function s:getSnippedHead(head, baseLen) - return l9#snipMid(a:head, len(a:head) + g:fuf_maxMenuWidth - a:baseLen, s:ABBR_SNIP_MASK) -endfunction - -" -function s:setAbbrWithFileAbbrData(item, snippedHeads) - let lenMenu = (exists('a:item.menu') ? len(a:item.menu) + 2 : 0) - let abbr = a:item.abbr.prefix . a:snippedHeads[a:item.abbr.key] . a:item.abbr.tail - let a:item.abbr = l9#snipTail(abbr, g:fuf_maxMenuWidth - lenMenu, s:ABBR_SNIP_MASK) - return a:item -endfunction - -" -let s:FUF_BUF_NAME = '[fuf]' - -" -function s:activateFufBuffer() - " lcd . : To avoid the strange behavior that unnamed buffer changes its cwd - " if 'autochdir' was set on. - lcd . - let cwd = getcwd() - call l9#tempbuffer#openScratch(s:FUF_BUF_NAME, 'fuf', [], 1, 0, 1, {}) - resize 1 " for issue #21 - " lcd ... : countermeasure against auto-cd script - lcd `=cwd` - setlocal nocursorline " for highlighting - setlocal nocursorcolumn " for highlighting - setlocal omnifunc=fuf#onComplete - redraw " for 'lazyredraw' - if exists(':AcpLock') - AcpLock - elseif exists(':AutoComplPopLock') - AutoComplPopLock - endif -endfunction - -" -function s:deactivateFufBuffer() - if exists(':AcpUnlock') - AcpUnlock - elseif exists(':AutoComplPopUnlock') - AutoComplPopUnlock - endif - call l9#tempbuffer#close(s:FUF_BUF_NAME) -endfunction - -" }}}1 -"============================================================================= -" s:handlerBase {{{1 - -let s:handlerBase = {} - -"----------------------------------------------------------------------------- -" PURE VIRTUAL FUNCTIONS {{{2 -" -" " -" s:handler.getModeName() -" -" " -" s:handler.getPrompt() -" -" " -" s:handler.getCompleteItems(patternSet) -" -" " -" s:handler.onOpen(word, mode) -" -" " Before entering FuzzyFinder buffer. This function should return in a short time. -" s:handler.onModeEnterPre() -" -" " After entering FuzzyFinder buffer. -" s:handler.onModeEnterPost() -" -" " After leaving FuzzyFinder buffer. -" s:handler.onModeLeavePost(opened) -" -" }}}2 -"----------------------------------------------------------------------------- - -" -function s:handlerBase.concretize(deriv) - call extend(self, a:deriv, 'error') - return self -endfunction - -" -function s:handlerBase.addStat(pattern, word) - let stat = { 'pattern' : a:pattern, 'word' : a:word } - call filter(self.stats, 'v:val !=# stat') - call insert(self.stats, stat) - let self.stats = self.stats[0 : g:fuf_learningLimit - 1] -endfunction - -" -function s:handlerBase.getMatchingCompleteItems(patternBase) - let MakeMatchingExpr = function(self.partialMatching - \ ? 's:makePartialMatchingExpr' - \ : 's:makeFuzzyMatchingExpr') - let patternSet = self.makePatternSet(a:patternBase) - let exprBoundary = s:makeFuzzyMatchingExpr('a:wordForBoundary', patternSet.primaryForRank) - let stats = filter( - \ copy(self.stats), 'v:val.pattern ==# patternSet.primaryForRank') - let items = self.getCompleteItems(patternSet.primary) - " NOTE: In order to know an excess, plus 1 to limit number - let items = l9#filterWithLimit( - \ items, patternSet.filteringExpr, g:fuf_enumeratingLimit + 1) - return map(items, - \ 's:setRanks(v:val, patternSet.primaryForRank, exprBoundary, stats)') -endfunction - -" -function s:handlerBase.onComplete(findstart, base) - if a:findstart - return 0 - elseif !self.existsPrompt(a:base) - return [] - endif - call s:highlightPrompt(self.getPrompt()) - let items = [] - for patternBase in s:expandAbbrevMap(self.removePrompt(a:base), g:fuf_abbrevMap) - let items += self.getMatchingCompleteItems(patternBase) - if len(items) > g:fuf_enumeratingLimit - let items = items[ : g:fuf_enumeratingLimit - 1] - call s:highlightError() - break - endif - endfor - if empty(items) - call s:highlightError() - else - call sort(items, 'fuf#compareRanks') - if g:fuf_autoPreview - call feedkeys("\<C-p>\<Down>\<C-r>=fuf#getRunningHandler().onPreviewBase(0) ? '' : ''\<CR>", 'n') - else - call feedkeys("\<C-p>\<Down>", 'n') - endif - let self.lastFirstWord = items[0].word - endif - return items -endfunction - -" -function s:handlerBase.existsPrompt(line) - return strlen(a:line) >= strlen(self.getPrompt()) && - \ a:line[:strlen(self.getPrompt()) -1] ==# self.getPrompt() -endfunction - -" -function s:handlerBase.removePrompt(line) - return a:line[(self.existsPrompt(a:line) ? strlen(self.getPrompt()) : 0):] -endfunction - -" -function s:handlerBase.restorePrompt(line) - let i = 0 - while i < len(self.getPrompt()) && i < len(a:line) && self.getPrompt()[i] ==# a:line[i] - let i += 1 - endwhile - return self.getPrompt() . a:line[i : ] -endfunction - -" -function s:handlerBase.onCursorMovedI() - if !self.existsPrompt(getline('.')) - call setline('.', self.restorePrompt(getline('.'))) - call feedkeys("\<End>", 'n') - elseif col('.') <= len(self.getPrompt()) - " if the cursor is moved before command prompt - call feedkeys(repeat("\<Right>", len(self.getPrompt()) - col('.') + 1), 'n') - elseif col('.') > strlen(getline('.')) && col('.') != self.lastCol - " if the cursor is placed on the end of the line and has been actually moved. - let self.lastCol = col('.') - let self.lastPattern = self.removePrompt(getline('.')) - call feedkeys("\<C-x>\<C-o>", 'n') - endif -endfunction - -" -function s:handlerBase.onInsertLeave() - unlet s:runningHandler - let tempVars = l9#tempvariables#getList(s:TEMP_VARIABLES_GROUP) - call l9#tempvariables#end(s:TEMP_VARIABLES_GROUP) - call s:deactivateFufBuffer() - call fuf#saveDataFile(self.getModeName(), 'stats', self.stats) - execute self.windowRestoringCommand - let fOpen = exists('s:reservedCommand') - if fOpen - call self.onOpen(s:reservedCommand[0], s:reservedCommand[1]) - unlet s:reservedCommand - endif - call self.onModeLeavePost(fOpen) - if exists('self.reservedMode') - call l9#tempvariables#setList(s:TEMP_VARIABLES_GROUP, tempVars) - call fuf#launch(self.reservedMode, self.lastPattern, self.partialMatching) - endif -endfunction - -" -function s:handlerBase.onCr(openType) - if pumvisible() - call feedkeys(printf("\<C-y>\<C-r>=fuf#getRunningHandler().onCr(%d) ? '' : ''\<CR>", - \ a:openType), 'n') - return - endif - if !empty(self.lastPattern) - call self.addStat(self.lastPattern, self.removePrompt(getline('.'))) - endif - if !self.isOpenable(getline('.')) - " To clear i_<C-r> expression (fuf#getRunningHandler().onCr...) - echo '' - return - endif - let s:reservedCommand = [self.removePrompt(getline('.')), a:openType] - call feedkeys("\<Esc>", 'n') " stopinsert behavior is strange... -endfunction - -" -function s:handlerBase.onBs() - call feedkeys((pumvisible() ? "\<C-e>\<BS>" : "\<BS>"), 'n') -endfunction - -" -function s:getLastBlockLength(pattern, patternIsPath) - let separatorPos = strridx(a:pattern, g:fuf_patternSeparator) - if separatorPos >= 0 - return len(a:pattern) - separatorPos - endif - if a:patternIsPath && a:pattern =~# '[/\\].' - return len(matchstr(a:pattern, '[^/\\]*.$')) - endif - return len(a:pattern) -endfunction - -" -function s:handlerBase.onDeleteWord() - let pattern = self.removePrompt(getline('.')[ : col('.') - 2]) - let numBs = s:getLastBlockLength(pattern, 1) - call feedkeys((pumvisible() ? "\<C-e>" : "") . repeat("\<BS>", numBs), 'n') -endfunction - -" -function s:handlerBase.onPreviewBase(repeatable) - if self.getPreviewHeight() <= 0 - return - elseif !pumvisible() - return - elseif !self.existsPrompt(getline('.')) - let word = self.removePrompt(getline('.')) - elseif !exists('self.lastFirstWord') - return - else - let word = self.lastFirstWord - endif - redraw - if a:repeatable && exists('self.lastPreviewInfo') && self.lastPreviewInfo.word ==# word - let self.lastPreviewInfo.count += 1 - else - let self.lastPreviewInfo = {'word': word, 'count': 0} - endif - let lines = self.makePreviewLines(word, self.lastPreviewInfo.count) - let lines = lines[: self.getPreviewHeight() - 1] - call map(lines, 'substitute(v:val, "\t", repeat(" ", &tabstop), "g")') - call map(lines, 'strtrans(v:val)') - call map(lines, 'l9#snipTail(v:val, &columns - 1, s:ABBR_SNIP_MASK)') - echo join(lines, "\n") -endfunction - -" -function s:handlerBase.onSwitchMode(shift) - let modes = copy(fuf#getModeNames()) - call map(modes, '{ "ranks": [ fuf#{v:val}#getSwitchOrder(), v:val ] }') - call filter(modes, 'v:val.ranks[0] >= 0') - call sort(modes, 'fuf#compareRanks') - let self.reservedMode = self.getModeName() - for i in range(len(modes)) - if modes[i].ranks[1] ==# self.getModeName() - let self.reservedMode = modes[(i + a:shift) % len(modes)].ranks[1] - break - endif - endfor - call feedkeys("\<Esc>", 'n') " stopinsert doesn't work. -endfunction - -" -function s:handlerBase.onSwitchMatching() - let self.partialMatching = !self.partialMatching - let self.lastCol = -1 - call setline('.', self.restorePrompt(self.lastPattern)) - call feedkeys("\<End>", 'n') - "call self.onCursorMovedI() -endfunction - -" -function s:handlerBase.onRecallPattern(shift) - let patterns = map(copy(self.stats), 'v:val.pattern') - if !exists('self.indexRecall') - let self.indexRecall = -1 - endif - let self.indexRecall += a:shift - if self.indexRecall < 0 - let self.indexRecall = -1 - elseif self.indexRecall >= len(patterns) - let self.indexRecall = len(patterns) - 1 - else - call setline('.', self.getPrompt() . patterns[self.indexRecall]) - call feedkeys("\<End>", 'n') - endif -endfunction - -" }}}1 -"============================================================================= -" INITIALIZATION {{{1 - -augroup FufGlobal - autocmd! - autocmd BufLeave * let s:bufferCursorPosMap[bufnr('')] = getpos('.') -augroup END - -let s:bufferCursorPosMap = {} - -" -let s:DATA_FILE_VERSION = 400 - -" -function s:checkDataFileCompatibility() - if empty(g:fuf_dataDir) - let s:dataFileAvailable = 0 - return - endif - let versionPath = l9#concatPaths([g:fuf_dataDir, 'VERSION']) - let lines = l9#readFile(versionPath) - if empty(lines) - call l9#writeFile([s:DATA_FILE_VERSION], versionPath) - let s:dataFileAvailable = 1 - elseif str2nr(lines[0]) == s:DATA_FILE_VERSION - let s:dataFileAvailable = 1 - else - call fuf#echoWarning(printf( - \ "=======================================================\n" . - \ " Existing data files for FuzzyFinder is no longer \n" . - \ " compatible with this version of FuzzyFinder. Remove \n" . - \ " %-53s\n" . - \ "=======================================================\n" , - \ string(g:fuf_dataDir))) - call l9#inputHl('Question', 'Press Enter') - let s:dataFileAvailable = 0 - endif -endfunction - -call s:checkDataFileCompatibility() - -" }}}1 -"============================================================================= -" vim: set fdm=marker: - |