From 2f6eca0dc513d474765290f1a5a4c02aed549be0 Mon Sep 17 00:00:00 2001 From: Hugues Hiegel Date: Wed, 7 Nov 2018 10:34:07 +0100 Subject: Plein de trucs en vrac... J’ai honte.. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- autoload/fuf.vim | 1046 +++++++++++++++++ autoload/fuf/bookmarkdir.vim | 163 +++ autoload/fuf/bookmarkfile.vim | 199 ++++ autoload/fuf/buffer.vim | 189 ++++ autoload/fuf/buffertag.vim | 300 +++++ autoload/fuf/callbackfile.vim | 137 +++ autoload/fuf/callbackitem.vim | 139 +++ autoload/fuf/changelist.vim | 172 +++ autoload/fuf/coveragefile.vim | 199 ++++ autoload/fuf/dir.vim | 132 +++ autoload/fuf/file.vim | 139 +++ autoload/fuf/givencmd.vim | 123 ++ autoload/fuf/givendir.vim | 123 ++ autoload/fuf/givenfile.vim | 121 ++ autoload/fuf/help.vim | 198 ++++ autoload/fuf/jumplist.vim | 182 +++ autoload/fuf/line.vim | 135 +++ autoload/fuf/mrucmd.vim | 134 +++ autoload/fuf/mrufile.vim | 234 ++++ autoload/fuf/quickfix.vim | 154 +++ autoload/fuf/tag.vim | 178 +++ autoload/fuf/taggedfile.vim | 159 +++ autoload/l9.vim | 570 ++++++++++ autoload/l9/async.py | 92 ++ autoload/l9/async.vim | 67 ++ autoload/l9/quickfix.vim | 107 ++ autoload/l9/tempbuffer.vim | 112 ++ autoload/l9/tempvariables.vim | 60 + autoload/plug.vim | 2504 +++++++++++++++++++++++++++++++++++++++++ bundle/plantuml-syntax | 1 + doc/fuf.jax | 1405 +++++++++++++++++++++++ doc/fuf.txt | 1883 +++++++++++++++++++++++++++++++ doc/l9.jax | 55 + doc/l9.txt | 73 ++ plugged/vim-easy-align | 1 + plugin/fuf.vim | 158 +++ plugin/l9.vim | 108 ++ 37 files changed, 11752 insertions(+) create mode 100644 autoload/fuf.vim create mode 100644 autoload/fuf/bookmarkdir.vim create mode 100644 autoload/fuf/bookmarkfile.vim create mode 100644 autoload/fuf/buffer.vim create mode 100644 autoload/fuf/buffertag.vim create mode 100644 autoload/fuf/callbackfile.vim create mode 100644 autoload/fuf/callbackitem.vim create mode 100644 autoload/fuf/changelist.vim create mode 100644 autoload/fuf/coveragefile.vim create mode 100644 autoload/fuf/dir.vim create mode 100644 autoload/fuf/file.vim create mode 100644 autoload/fuf/givencmd.vim create mode 100644 autoload/fuf/givendir.vim create mode 100644 autoload/fuf/givenfile.vim create mode 100644 autoload/fuf/help.vim create mode 100644 autoload/fuf/jumplist.vim create mode 100644 autoload/fuf/line.vim create mode 100644 autoload/fuf/mrucmd.vim create mode 100644 autoload/fuf/mrufile.vim create mode 100644 autoload/fuf/quickfix.vim create mode 100644 autoload/fuf/tag.vim create mode 100644 autoload/fuf/taggedfile.vim create mode 100644 autoload/l9.vim create mode 100644 autoload/l9/async.py create mode 100644 autoload/l9/async.vim create mode 100644 autoload/l9/quickfix.vim create mode 100644 autoload/l9/tempbuffer.vim create mode 100644 autoload/l9/tempvariables.vim create mode 100644 autoload/plug.vim create mode 160000 bundle/plantuml-syntax create mode 100644 doc/fuf.jax create mode 100644 doc/fuf.txt create mode 100644 doc/l9.jax create mode 100644 doc/l9.txt create mode 160000 plugged/vim-easy-align create mode 100644 plugin/fuf.vim create mode 100644 plugin/l9.vim diff --git a/autoload/fuf.vim b/autoload/fuf.vim new file mode 100644 index 0000000..fe9e6eb --- /dev/null +++ b/autoload/fuf.vim @@ -0,0 +1,1046 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':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 "\" +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 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 . , len())', + \ a:CmdName, preCmd, string(a:modeName), a:prefixInitialPattern) +endfunction + +" +function fuf#defineKeyMappingInHandler(key, func) + " hacks to be able to use feedkeys(). + execute printf( + \ 'inoremap %s =fuf#getRunningHandler().%s ? "" : ""', + \ 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 call s:runningHandler.onCursorMovedI() + autocmd InsertLeave 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 . ')' ], + \ [ '' , 'onBs()' ], + \ [ '' , 'onBs()' ], + \ [ '' , '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(':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("\\\=fuf#getRunningHandler().onPreviewBase(0) ? '' : ''\", 'n') + else + call feedkeys("\\", '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("\", 'n') + elseif col('.') <= len(self.getPrompt()) + " if the cursor is moved before command prompt + call feedkeys(repeat("\", 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("\\", '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("\\=fuf#getRunningHandler().onCr(%d) ? '' : ''\", + \ 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_ expression (fuf#getRunningHandler().onCr...) + echo '' + return + endif + let s:reservedCommand = [self.removePrompt(getline('.')), a:openType] + call feedkeys("\", 'n') " stopinsert behavior is strange... +endfunction + +" +function s:handlerBase.onBs() + call feedkeys((pumvisible() ? "\\" : "\"), '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() ? "\" : "") . repeat("\", 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("\", '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("\", '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("\", '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: + diff --git a/autoload/fuf/bookmarkdir.vim b/autoload/fuf/bookmarkdir.vim new file mode 100644 index 0000000..01585ff --- /dev/null +++ b/autoload/fuf/bookmarkdir.vim @@ -0,0 +1,163 @@ +"============================================================================= +" Copyright (c) 2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#bookmarkdir#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#bookmarkdir#getSwitchOrder() + return g:fuf_bookmarkdir_switchOrder +endfunction + +" +function fuf#bookmarkdir#getEditableDataNames() + return ['items'] +endfunction + +" +function fuf#bookmarkdir#renewCache() +endfunction + +" +function fuf#bookmarkdir#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#bookmarkdir#onInit() + call fuf#defineLaunchCommand('FufBookmarkDir', s:MODE_NAME, '""', []) + command! -bang -narg=? FufBookmarkDirAdd call s:bookmark() +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') +let s:OPEN_TYPE_DELETE = -1 + +" +function s:bookmark(word) + let item = { + \ 'time' : localtime(), + \ } + + let item.path = l9#inputHl('Question', '[fuf] Directory to bookmark:', + \ fnamemodify(getcwd(), ':p:~'), 'dir') + if item.path !~ '\S' + call fuf#echoWarning('Canceled') + return + endif + let item.word = l9#inputHl('Question', '[fuf] Bookmark as:', + \ fnamemodify(getcwd(), ':p:~')) + if item.word !~ '\S' + call fuf#echoWarning('Canceled') + return + endif + let items = fuf#loadDataFile(s:MODE_NAME, 'items') + call insert(items, item) + call fuf#saveDataFile(s:MODE_NAME, 'items', items) +endfunction + +" +function s:findItem(items, word) + for item in a:items + if item.word ==# a:word + return item + endif + endfor + return {} +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_bookmarkdir_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return 0 +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return [] +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + if a:mode ==# s:OPEN_TYPE_DELETE + let items = fuf#loadDataFile(s:MODE_NAME, 'items') + call filter(items, 'v:val.word !=# a:word') + call fuf#saveDataFile(s:MODE_NAME, 'items', items) + let self.reservedMode = self.getModeName() + return + else + let item = s:findItem(fuf#loadDataFile(s:MODE_NAME, 'items'), a:word) + if !empty(item) + execute ':cd ' . fnameescape(item.path) + endif + endif +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + call fuf#defineKeyMappingInHandler(g:fuf_bookmarkdir_keyDelete, + \ 'onCr(' . s:OPEN_TYPE_DELETE . ')') + let self.items = fuf#loadDataFile(s:MODE_NAME, 'items') + call map(self.items, 'fuf#makeNonPathItem(v:val.word, strftime(g:fuf_timeFormat, v:val.time))') + call fuf#mapToSetSerialIndex(self.items, 1) + call map(self.items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/bookmarkfile.vim b/autoload/fuf/bookmarkfile.vim new file mode 100644 index 0000000..12ac80f --- /dev/null +++ b/autoload/fuf/bookmarkfile.vim @@ -0,0 +1,199 @@ +"============================================================================= +" Copyright (c) 2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#bookmarkfile#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#bookmarkfile#getSwitchOrder() + return g:fuf_bookmarkfile_switchOrder +endfunction + +" +function fuf#bookmarkfile#getEditableDataNames() + return ['items'] +endfunction + +" +function fuf#bookmarkfile#renewCache() +endfunction + +" +function fuf#bookmarkfile#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#bookmarkfile#onInit() + call fuf#defineLaunchCommand('FufBookmarkFile', s:MODE_NAME, '""', []) + command! -bang -narg=? FufBookmarkFileAdd call s:bookmarkHere() + command! -bang -narg=0 -range FufBookmarkFileAddAsSelectedText call s:bookmarkHere(l9#getSelectedText()) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') +let s:OPEN_TYPE_DELETE = -1 + +" opens a:path and jumps to the line matching to a:pattern from a:lnum within +" a:range. if not found, jumps to a:lnum. +function s:jumpToBookmark(path, mode, pattern, lnum) + call fuf#openFile(a:path, a:mode, g:fuf_reuseWindow) + call cursor(s:getMatchingLineNumber(getline(1, '$'), a:pattern, a:lnum), 0) + normal! zvzz +endfunction + +" +function s:getMatchingLineNumber(lines, pattern, lnumBegin) + let l = min([a:lnumBegin, len(a:lines)]) + for [l0, l1] in map(range(0, g:fuf_bookmarkfile_searchRange), + \ '[l + v:val, l - v:val]') + if l0 <= len(a:lines) && a:lines[l0 - 1] =~# a:pattern + return l0 + elseif l1 >= 0 && a:lines[l1 - 1] =~# a:pattern + return l1 + endif + endfor + return l +endfunction + +" +function s:getLinePattern(lnum) + return '\C\V\^' . escape(getline(a:lnum), '\') . '\$' +endfunction + +" +function s:bookmarkHere(word) + if !empty(&buftype) || expand('%') !~ '\S' + call fuf#echoWarning('Can''t bookmark this buffer.') + return + endif + let item = { + \ 'word' : (a:word =~# '\S' ? substitute(a:word, '\n', ' ', 'g') + \ : pathshorten(expand('%:p:~')) . '|' . line('.') . '| ' . getline('.')), + \ 'path' : expand('%:p'), + \ 'lnum' : line('.'), + \ 'pattern' : s:getLinePattern(line('.')), + \ 'time' : localtime(), + \ } + let item.word = l9#inputHl('Question', '[fuf] Bookmark as:', item.word) + if item.word !~ '\S' + call fuf#echoWarning('Canceled') + return + endif + let items = fuf#loadDataFile(s:MODE_NAME, 'items') + call insert(items, item) + call fuf#saveDataFile(s:MODE_NAME, 'items', items) +endfunction + +" +function s:findItem(items, word) + for item in a:items + if item.word ==# a:word + return item + endif + endfor + return {} +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_bookmarkfile_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + let item = s:findItem(fuf#loadDataFile(s:MODE_NAME, 'items'), a:word) + let lines = fuf#getFileLines(item.path) + if empty(lines) + return [] + endif + let index = s:getMatchingLineNumber(lines, item.pattern, item.lnum) - 1 + return fuf#makePreviewLinesAround( + \ lines, [index], a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + if a:mode ==# s:OPEN_TYPE_DELETE + let items = fuf#loadDataFile(s:MODE_NAME, 'items') + call filter(items, 'v:val.word !=# a:word') + call fuf#saveDataFile(s:MODE_NAME, 'items', items) + let self.reservedMode = self.getModeName() + return + else + let item = s:findItem(fuf#loadDataFile(s:MODE_NAME, 'items'), a:word) + if !empty(item) + call s:jumpToBookmark(item.path, a:mode, item.pattern, item.lnum) + endif + endif +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + call fuf#defineKeyMappingInHandler(g:fuf_bookmarkfile_keyDelete, + \ 'onCr(' . s:OPEN_TYPE_DELETE . ')') + let self.items = fuf#loadDataFile(s:MODE_NAME, 'items') + call map(self.items, 'fuf#makeNonPathItem(v:val.word, strftime(g:fuf_timeFormat, v:val.time))') + call fuf#mapToSetSerialIndex(self.items, 1) + call map(self.items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/buffer.vim b/autoload/fuf/buffer.vim new file mode 100644 index 0000000..08b954a --- /dev/null +++ b/autoload/fuf/buffer.vim @@ -0,0 +1,189 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#buffer#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#buffer#getSwitchOrder() + return g:fuf_buffer_switchOrder +endfunction + +" +function fuf#buffer#getEditableDataNames() + return [] +endfunction + +" +function fuf#buffer#renewCache() +endfunction + +" +function fuf#buffer#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#buffer#onInit() + call fuf#defineLaunchCommand('FufBuffer', s:MODE_NAME, '""', []) + augroup fuf#buffer + autocmd! + autocmd BufEnter * call s:updateBufTimes() + autocmd BufWritePost * call s:updateBufTimes() + augroup END +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') +let s:OPEN_TYPE_DELETE = -1 + +let s:bufTimes = {} + +" +function s:updateBufTimes() + let s:bufTimes[bufnr('%')] = localtime() +endfunction + +" +function s:makeItem(nr) + let fname = (empty(bufname(a:nr)) + \ ? '[No Name]' + \ : fnamemodify(bufname(a:nr), ':p:~:.')) + let time = (exists('s:bufTimes[a:nr]') ? s:bufTimes[a:nr] : 0) + let item = fuf#makePathItem(fname, strftime(g:fuf_timeFormat, time), 0) + let item.index = a:nr + let item.bufNr = a:nr + let item.time = time + let item.abbrPrefix = s:getBufIndicator(a:nr) . ' ' + return item +endfunction + +" +function s:getBufIndicator(bufNr) + if !getbufvar(a:bufNr, '&modifiable') + return '[-]' + elseif getbufvar(a:bufNr, '&modified') + return '[+]' + elseif getbufvar(a:bufNr, '&readonly') + return '[R]' + else + return ' ' + endif +endfunction + +" +function s:compareTimeDescending(i1, i2) + return a:i1.time == a:i2.time ? 0 : a:i1.time > a:i2.time ? -1 : +1 +endfunction + +" +function s:findItem(items, word) + for item in a:items + if item.word ==# a:word + return item + endif + endfor + return {} +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_buffer_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + let item = s:findItem(self.items, a:word) + if empty(item) + return [] + endif + return fuf#makePreviewLinesForFile(item.bufNr, a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + " not use bufnr(a:word) in order to handle unnamed buffer + let item = s:findItem(self.items, a:word) + if empty(item) + " do nothing + elseif a:mode ==# s:OPEN_TYPE_DELETE + execute item.bufNr . 'bdelete' + let self.reservedMode = self.getModeName() + else + call fuf#openBuffer(item.bufNr, a:mode, g:fuf_reuseWindow) + endif +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + call fuf#defineKeyMappingInHandler(g:fuf_buffer_keyDelete, + \ 'onCr(' . s:OPEN_TYPE_DELETE . ')') + let self.items = range(1, bufnr('$')) + call filter(self.items, 'buflisted(v:val) && v:val != self.bufNrPrev && v:val != bufnr("%")') + call map(self.items, 's:makeItem(v:val)') + if g:fuf_buffer_mruOrder + call sort(self.items, 's:compareTimeDescending') + call fuf#mapToSetSerialIndex(self.items, 1) + endif + let self.items = fuf#mapToSetAbbrWithSnippedWordAsPath(self.items) +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/buffertag.vim b/autoload/fuf/buffertag.vim new file mode 100644 index 0000000..392b996 --- /dev/null +++ b/autoload/fuf/buffertag.vim @@ -0,0 +1,300 @@ +"============================================================================= +" Copyright (c) 2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#buffertag#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#buffertag#getSwitchOrder() + return g:fuf_buffertag_switchOrder +endfunction + +" +function fuf#buffertag#getEditableDataNames() + return [] +endfunction + +" +function fuf#buffertag#renewCache() + let s:tagItemsCache = {} + let s:tagDataCache = {} +endfunction + +" +function fuf#buffertag#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#buffertag#onInit() + call fuf#defineLaunchCommand('FufBufferTag', s:MODE_NAME, '""', + \ [['g:fuf_buffertag_forAll', 0]]) + call fuf#defineLaunchCommand('FufBufferTagAll', s:MODE_NAME, '""', + \ [['g:fuf_buffertag_forAll', 1]]) + call fuf#defineLaunchCommand('FufBufferTagWithCursorWord', s:MODE_NAME, + \ 'expand('''')', [['g:fuf_buffertag_forAll', 0]]) + call fuf#defineLaunchCommand('FufBufferTagAllWithCursorWord', s:MODE_NAME, + \ 'expand('''')', [['g:fuf_buffertag_forAll', 1]]) + call fuf#defineLaunchCommand('FufBufferTagWithSelectedText', s:MODE_NAME, + \ 'l9#getSelectedText()', [['g:fuf_buffertag_forAll', 0]]) + call fuf#defineLaunchCommand('FufBufferTagAllWithSelectedText', s:MODE_NAME, + \ 'l9#getSelectedText()', [['g:fuf_buffertag_forAll', 1]]) + call l9#defineVariableDefault('g:fuf_buffertag_forAll', 0) " private option + " the following settings originate from taglist.vim + call l9#defineVariableDefault('g:fuf_buffertag__asm' , '--language-force=asm --asm-types=dlmt') + call l9#defineVariableDefault('g:fuf_buffertag__aspperl' , '--language-force=asp --asp-types=fsv') + call l9#defineVariableDefault('g:fuf_buffertag__aspvbs' , '--language-force=asp --asp-types=fsv') + call l9#defineVariableDefault('g:fuf_buffertag__awk' , '--language-force=awk --awk-types=f') + call l9#defineVariableDefault('g:fuf_buffertag__beta' , '--language-force=beta --beta-types=fsv') + call l9#defineVariableDefault('g:fuf_buffertag__c' , '--language-force=c --c-types=dgsutvf') + call l9#defineVariableDefault('g:fuf_buffertag__cpp' , '--language-force=c++ --c++-types=nvdtcgsuf') + call l9#defineVariableDefault('g:fuf_buffertag__cs' , '--language-force=c# --c#-types=dtncEgsipm') + call l9#defineVariableDefault('g:fuf_buffertag__cobol' , '--language-force=cobol --cobol-types=dfgpPs') + call l9#defineVariableDefault('g:fuf_buffertag__eiffel' , '--language-force=eiffel --eiffel-types=cf') + call l9#defineVariableDefault('g:fuf_buffertag__erlang' , '--language-force=erlang --erlang-types=drmf') + call l9#defineVariableDefault('g:fuf_buffertag__expect' , '--language-force=tcl --tcl-types=cfp') + call l9#defineVariableDefault('g:fuf_buffertag__fortran' , '--language-force=fortran --fortran-types=pbceiklmntvfs') + call l9#defineVariableDefault('g:fuf_buffertag__html' , '--language-force=html --html-types=af') + call l9#defineVariableDefault('g:fuf_buffertag__java' , '--language-force=java --java-types=pcifm') + call l9#defineVariableDefault('g:fuf_buffertag__javascript', '--language-force=javascript --javascript-types=f') + call l9#defineVariableDefault('g:fuf_buffertag__lisp' , '--language-force=lisp --lisp-types=f') + call l9#defineVariableDefault('g:fuf_buffertag__lua' , '--language-force=lua --lua-types=f') + call l9#defineVariableDefault('g:fuf_buffertag__make' , '--language-force=make --make-types=m') + call l9#defineVariableDefault('g:fuf_buffertag__pascal' , '--language-force=pascal --pascal-types=fp') + call l9#defineVariableDefault('g:fuf_buffertag__perl' , '--language-force=perl --perl-types=clps') + call l9#defineVariableDefault('g:fuf_buffertag__php' , '--language-force=php --php-types=cdvf') + call l9#defineVariableDefault('g:fuf_buffertag__python' , '--language-force=python --python-types=cmf') + call l9#defineVariableDefault('g:fuf_buffertag__rexx' , '--language-force=rexx --rexx-types=s') + call l9#defineVariableDefault('g:fuf_buffertag__ruby' , '--language-force=ruby --ruby-types=cfFm') + call l9#defineVariableDefault('g:fuf_buffertag__scheme' , '--language-force=scheme --scheme-types=sf') + call l9#defineVariableDefault('g:fuf_buffertag__sh' , '--language-force=sh --sh-types=f') + call l9#defineVariableDefault('g:fuf_buffertag__csh' , '--language-force=sh --sh-types=f') + call l9#defineVariableDefault('g:fuf_buffertag__zsh' , '--language-force=sh --sh-types=f') + call l9#defineVariableDefault('g:fuf_buffertag__slang' , '--language-force=slang --slang-types=nf') + call l9#defineVariableDefault('g:fuf_buffertag__sml' , '--language-force=sml --sml-types=ecsrtvf') + call l9#defineVariableDefault('g:fuf_buffertag__sql' , '--language-force=sql --sql-types=cFPrstTvfp') + call l9#defineVariableDefault('g:fuf_buffertag__tcl' , '--language-force=tcl --tcl-types=cfmp') + call l9#defineVariableDefault('g:fuf_buffertag__vera' , '--language-force=vera --vera-types=cdefgmpPtTvx') + call l9#defineVariableDefault('g:fuf_buffertag__verilog' , '--language-force=verilog --verilog-types=mcPertwpvf') + call l9#defineVariableDefault('g:fuf_buffertag__vim' , '--language-force=vim --vim-types=avf') + call l9#defineVariableDefault('g:fuf_buffertag__yacc' , '--language-force=yacc --yacc-types=l') +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:parseTagLine(line) + " tag W:\Win32\SRC7\NCSIM\NCVW32\CUBEFACE.H /^#define CUBEFACE_H$/;" macro line:4 + let fields = matchlist(a:line, '\v^([^\t]+)\t(.+)\t\/\^(.+)\$\/\;\"\t(.+)\tline\:(\d+)') + if empty(fields) + return {} + endif + return { + \ 'tag' : fields[1], + \ 'fname' : fields[2], + \ 'pattern': fields[3], + \ 'kind' : fields[4], + \ 'lnum' : str2nr(fields[5]), + \ } +endfunction + +" +let s:TEMP_VARIABLES_GROUP = expand(':p') + +" +function s:getFileType(bufNr) + let ft = getbufvar(a:bufNr, '&filetype') + if !empty(ft) || bufloaded(a:bufNr) + return ft + endif + let ft = getbufvar(a:bufNr, 'fuf_buffertag_filetype') + if !empty(ft) + return ft + endif + call l9#tempvariables#set(s:TEMP_VARIABLES_GROUP, '&eventignore', 'FileType') + call l9#tempvariables#set(s:TEMP_VARIABLES_GROUP, '&filetype', &filetype) + " from taglist.vim + execute 'doautocmd filetypedetect BufRead ' . bufname(a:bufNr) + let ft = &filetype + call l9#tempvariables#end(s:TEMP_VARIABLES_GROUP) + call setbufvar(a:bufNr, 'fuf_buffertag_filetype', ft) + return ft +endfunction + +" +function s:makeCtagsCmd(bufNr) + let ft = s:getFileType(a:bufNr) + if !exists('g:fuf_buffertag__{ft}') + return '' + endif + " + let cmd = join([g:fuf_buffertag_ctagsPath, + \ '-f - --sort=no --excmd=pattern --fields=nKs', + \ g:fuf_buffertag__{ft}, + \ shellescape(fnamemodify(bufname(a:bufNr), ':p'))]) + return cmd +endfunction + +" +function s:getTagItems(bufNr) + let cmd = s:makeCtagsCmd(a:bufNr) + if empty(cmd) + return [] + elseif !exists('s:tagItemsCache[cmd]') || + \ s:tagItemsCache[cmd].time < getftime(expand(bufname(a:bufNr))) + let items = split(system(cmd), "\n") + if v:shell_error + call fuf#echoError([cmd] + items) + throw "Command error" + endif + call map(items, 's:parseTagLine(v:val)') + call filter(items, '!empty(v:val)') + let s:tagItemsCache[cmd] = { + \ 'time' : localtime(), + \ 'items' : items, + \ } + endif + return s:tagItemsCache[cmd].items +endfunction + +" +function s:makeItem(tag, itemMap) + let menu = fnamemodify(a:itemMap[a:tag][0].fname, ':t') + \ . ' [' . a:itemMap[a:tag][0].kind . ']' + if len(a:itemMap[a:tag]) > 1 + let menu .= ' (' . len(a:itemMap[a:tag]) . ')' + endif + let item = fuf#makeNonPathItem(a:tag, menu) + return item +endfunction + +" +function s:getTagData(bufNrs) + let key = join([0] + sort(copy(a:bufNrs)), "\n") + let bufNames = map(copy(a:bufNrs), 'bufname(v:val)') + if !exists('s:tagDataCache[key]') || + \ fuf#countModifiedFiles(bufNames, s:tagDataCache[key].time) > 0 + let itemMap = {} + for item in l9#concat(map(copy(a:bufNrs), 's:getTagItems(v:val)')) + if !exists('itemMap[item.tag]') + let itemMap[item.tag] = [] + endif + call add(itemMap[item.tag], item) + endfor + let items = sort(keys(itemMap)) + call map(items, 's:makeItem(v:val, itemMap)') + call fuf#mapToSetSerialIndex(items, 1) + call map(items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') + let s:tagDataCache[key] = { + \ 'time' : localtime(), + \ 'itemMap': itemMap, + \ 'items' : items, + \ } + endif + return [s:tagDataCache[key].items, s:tagDataCache[key].itemMap] +endfunction + +" +function s:jumpToTag(item, mode) + call fuf#openFile(a:item.fname, a:mode, g:fuf_reuseWindow) + call cursor(a:item.lnum, 1) + normal! zvzz +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_buffertag_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return 0 +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return [] +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + if !exists('self.itemMap[a:word][0]') + call fuf#echoError('Definition not found:' . a:word) + return + elseif len(self.itemMap[a:word]) == 1 + let i = 0 + else + let list = map(fuf#mapToSetSerialIndex(copy(self.itemMap[a:word]), 1), + \ 'printf(" %2d: %s|%d| [%s] %s",v:val.index, fnamemodify(v:val.fname, ":~:."), v:val.lnum, v:val.kind, v:val.pattern)') + let i = inputlist(['Select a definition of "' . a:word . '":'] + list) - 1 + endif + if 0 <= i && i < len(self.itemMap[a:word]) + call s:jumpToTag(self.itemMap[a:word][i], a:mode) + endif +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + if g:fuf_buffertag_forAll + let bufNrs = filter(range(1, bufnr('$')), 'buflisted(v:val)') + else + let bufNrs = [self.bufNrPrev] + endif + let [self.items, self.itemMap] = s:getTagData(bufNrs) +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/callbackfile.vim b/autoload/fuf/callbackfile.vim new file mode 100644 index 0000000..fedf0cf --- /dev/null +++ b/autoload/fuf/callbackfile.vim @@ -0,0 +1,137 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#callbackfile#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#callbackfile#getSwitchOrder() + return -1 +endfunction + +" +function fuf#callbackfile#getEditableDataNames() + return [] +endfunction + +" +function fuf#callbackfile#renewCache() + let s:cache = {} +endfunction + +" +function fuf#callbackfile#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#callbackfile#onInit() +endfunction + +" +function fuf#callbackfile#launch(initialPattern, partialMatching, prompt, exclude, listener) + let s:prompt = (empty(a:prompt) ? '>' : a:prompt) + let s:exclude = a:exclude + let s:listener = a:listener + call fuf#launch(s:MODE_NAME, a:initialPattern, a:partialMatching) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:enumItems(dir) + let key = getcwd() . g:fuf_ignoreCase . s:exclude . "\n" . a:dir + if !exists('s:cache[key]') + let s:cache[key] = fuf#enumExpandedDirsEntries(a:dir, s:exclude) + if isdirectory(a:dir) + call insert(s:cache[key], fuf#makePathItem(a:dir . '.', '', 0)) + endif + call fuf#mapToSetSerialIndex(s:cache[key], 1) + call fuf#mapToSetAbbrWithSnippedWordAsPath(s:cache[key]) + endif + return s:cache[key] +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(s:prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return a:enteredPattern =~# '[^/\\]$' +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForPathTail', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return fuf#makePreviewLinesForFile(a:word, a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + let items = copy(s:enumItems(fuf#splitPath(a:patternPrimary).head)) + return filter(items, 'bufnr("^" . v:val.word . "$") != self.bufNrPrev') +endfunction + +" +function s:handler.onOpen(word, mode) + call s:listener.onComplete(a:word, a:mode) +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() +endfunction + +" +function s:handler.onModeLeavePost(opened) + if !a:opened && exists('s:listener.onAbort()') + call s:listener.onAbort() + endif +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/callbackitem.vim b/autoload/fuf/callbackitem.vim new file mode 100644 index 0000000..118ee08 --- /dev/null +++ b/autoload/fuf/callbackitem.vim @@ -0,0 +1,139 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#callbackitem#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#callbackitem#getSwitchOrder() + return -1 +endfunction + +" +function fuf#callbackitem#getEditableDataNames() + return [] +endfunction + +" +function fuf#callbackitem#renewCache() +endfunction + +" +function fuf#callbackitem#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#callbackitem#onInit() +endfunction + +" +function fuf#callbackitem#launch(initialPattern, partialMatching, prompt, listener, items, forPath) + let s:prompt = (empty(a:prompt) ? '>' : a:prompt) + let s:listener = a:listener + let s:forPath = a:forPath + let s:items = copy(a:items) + if s:forPath + call map(s:items, 'fuf#makePathItem(v:val, "", 1)') + call fuf#mapToSetSerialIndex(s:items, 1) + call fuf#mapToSetAbbrWithSnippedWordAsPath(s:items) + else + call map(s:items, 'fuf#makeNonPathItem(v:val, "")') + call fuf#mapToSetSerialIndex(s:items, 1) + call map(s:items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') + endif + call fuf#launch(s:MODE_NAME, a:initialPattern, a:partialMatching) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(s:prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + if s:forPath + return g:fuf_previewHeight + endif + return 0 +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + let parser = (s:forPath + \ ? 's:interpretPrimaryPatternForPath' + \ : 's:interpretPrimaryPatternForNonPath') + return fuf#makePatternSet(a:patternBase, parser, self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + if s:forPath + return fuf#makePreviewLinesForFile(a:word, a:count, self.getPreviewHeight()) + endif + return [] +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return s:items +endfunction + +" +function s:handler.onOpen(word, mode) + call s:listener.onComplete(a:word, a:mode) +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() +endfunction + +" +function s:handler.onModeLeavePost(opened) + if !a:opened && exists('s:listener.onAbort()') + call s:listener.onAbort() + endif +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/changelist.vim b/autoload/fuf/changelist.vim new file mode 100644 index 0000000..545f6ca --- /dev/null +++ b/autoload/fuf/changelist.vim @@ -0,0 +1,172 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#changelist#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#changelist#getSwitchOrder() + return g:fuf_changelist_switchOrder +endfunction + +" +function fuf#changelist#getEditableDataNames() + return [] +endfunction + +" +function fuf#changelist#renewCache() +endfunction + +" +function fuf#changelist#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#changelist#onInit() + call fuf#defineLaunchCommand('FufChangeList', s:MODE_NAME, '""', []) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:getChangesLines() + redir => result + :silent changes + redir END + return split(result, "\n") +endfunction + +" +function s:parseChangesLine(line) + " return matchlist(a:line, '^\(.\)\s\+\(\d\+\)\s\(.*\)$') + let elements = matchlist(a:line, '\v^(.)\s*(\d+)\s+(\d+)\s+(\d+)\s*(.*)$') + if empty(elements) + return {} + endif + return { + \ 'prefix': elements[1], + \ 'count' : elements[2], + \ 'lnum' : elements[3], + \ 'text' : printf('|%d:%d|%s', elements[3], elements[4], elements[5]), + \ } +endfunction + +" +function s:makeItem(line) + let parsed = s:parseChangesLine(a:line) + if empty(parsed) + return {} + endif + let item = fuf#makeNonPathItem(parsed.text, '') + let item.abbrPrefix = parsed.prefix + let item.lnum = parsed.lnum + return item +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_changelist_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + let items = filter(copy(self.items), 'v:val.word ==# a:word') + if empty(items) + return [] + endif + let lines = fuf#getFileLines(self.bufNrPrev) + return fuf#makePreviewLinesAround( + \ lines, [items[0].lnum - 1], a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#prejump(a:mode) + let older = 0 + for line in reverse(s:getChangesLines()) + if stridx(line, '>') == 0 + let older = 1 + endif + let parsed = s:parseChangesLine(line) + if !empty(parsed) && parsed.text ==# a:word + if parsed.count != 0 + execute 'normal! ' . parsed.count . (older ? 'g;' : 'g,') . 'zvzz' + endif + break + endif + endfor +endfunction + +" +function s:handler.onModeEnterPre() + let self.items = s:getChangesLines() +endfunction + +" +function s:handler.onModeEnterPost() + call map(self.items, 's:makeItem(v:val)') + call filter(self.items, '!empty(v:val)') + call reverse(self.items) + call fuf#mapToSetSerialIndex(self.items, 1) + call map(self.items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: + diff --git a/autoload/fuf/coveragefile.vim b/autoload/fuf/coveragefile.vim new file mode 100644 index 0000000..1471ef8 --- /dev/null +++ b/autoload/fuf/coveragefile.vim @@ -0,0 +1,199 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#coveragefile#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#coveragefile#getSwitchOrder() + return g:fuf_coveragefile_switchOrder +endfunction + +" +function fuf#coveragefile#getEditableDataNames() + return ['coverages'] +endfunction + +" +function fuf#coveragefile#renewCache() + let s:cache = {} +endfunction + +" +function fuf#coveragefile#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#coveragefile#onInit() + call fuf#defineLaunchCommand('FufCoverageFile', s:MODE_NAME, '""', []) + call l9#defineVariableDefault('g:fuf_coveragefile_name', '') " private option + command! -bang -narg=0 FufCoverageFileRegister call s:registerCoverage() + command! -bang -narg=? FufCoverageFileChange call s:changeCoverage() +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:enumItems() + let key = join([getcwd(), g:fuf_ignoreCase, g:fuf_coveragefile_exclude, + \ g:fuf_coveragefile_globPatterns], "\n") + if !exists('s:cache[key]') + let s:cache[key] = l9#concat(map(copy(g:fuf_coveragefile_globPatterns), + \ 'fuf#glob(v:val)')) + call filter(s:cache[key], 'filereadable(v:val)') " filter out directories + call map(s:cache[key], 'fuf#makePathItem(fnamemodify(v:val, ":~:."), "", 0)') + if len(g:fuf_coveragefile_exclude) + call filter(s:cache[key], 'v:val.word !~ g:fuf_coveragefile_exclude') + endif + call fuf#mapToSetSerialIndex(s:cache[key], 1) + call fuf#mapToSetAbbrWithSnippedWordAsPath(s:cache[key]) + endif + return s:cache[key] +endfunction + +" +function s:registerCoverage() + let patterns = [] + while 1 + let pattern = l9#inputHl('Question', '[fuf] Glob pattern for coverage ( and end):', + \ '', 'file') + if pattern !~ '\S' + break + endif + call add(patterns, pattern) + endwhile + if empty(patterns) + call fuf#echoWarning('Canceled') + return + endif + echo '[fuf] patterns: ' . string(patterns) + let name = l9#inputHl('Question', '[fuf] Coverage name:') + if name !~ '\S' + call fuf#echoWarning('Canceled') + return + endif + let coverages = fuf#loadDataFile(s:MODE_NAME, 'coverages') + call insert(coverages, {'name': name, 'patterns': patterns}) + call fuf#saveDataFile(s:MODE_NAME, 'coverages', coverages) +endfunction + +" +function s:createChangeCoverageListener() + let listener = {} + + function listener.onComplete(name, method) + call s:changeCoverage(a:name) + endfunction + + return listener +endfunction + +" +function s:changeCoverage(name) + let coverages = fuf#loadDataFile(s:MODE_NAME, 'coverages') + if a:name !~ '\S' + let names = map(copy(coverages), 'v:val.name') + call fuf#callbackitem#launch('', 0, '>Coverage>', s:createChangeCoverageListener(), names, 0) + return + else + let name = a:name + endif + call filter(coverages, 'v:val.name ==# name') + if empty(coverages) + call fuf#echoError('Coverage not found: ' . name) + return + endif + call fuf#setOneTimeVariables( + \ ['g:fuf_coveragefile_globPatterns', coverages[0].patterns], + \ ['g:fuf_coveragefile_name' , a:name] + \ ) + FufCoverageFile +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + let nameString = (empty(g:fuf_coveragefile_name) ? '' + \ : '[' . g:fuf_coveragefile_name . ']') + return fuf#formatPrompt(g:fuf_coveragefile_prompt, self.partialMatching, + \ nameString) +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return fuf#makePreviewLinesForFile(a:word, a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#openFile(a:word, a:mode, g:fuf_reuseWindow) +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + " NOTE: Comparing filenames is faster than bufnr('^' . fname . '$') + let bufNamePrev = fnamemodify(bufname(self.bufNrPrev), ':~:.') + let self.items = copy(s:enumItems()) + call filter(self.items, 'v:val.word !=# bufNamePrev') +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/dir.vim b/autoload/fuf/dir.vim new file mode 100644 index 0000000..5316093 --- /dev/null +++ b/autoload/fuf/dir.vim @@ -0,0 +1,132 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#dir#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#dir#getSwitchOrder() + return g:fuf_dir_switchOrder +endfunction + +" +function fuf#dir#getEditableDataNames() + return [] +endfunction + +" +function fuf#dir#renewCache() + let s:cache = {} +endfunction + +" +function fuf#dir#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#dir#onInit() + call fuf#defineLaunchCommand('FufDir' , s:MODE_NAME, '""', []) + call fuf#defineLaunchCommand('FufDirWithFullCwd' , s:MODE_NAME, 'fnamemodify(getcwd(), '':p'')', []) + call fuf#defineLaunchCommand('FufDirWithCurrentBufferDir', s:MODE_NAME, 'expand(''%:~:.'')[:-1-len(expand(''%:~:.:t''))]', []) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:enumItems(dir) + let key = getcwd() . g:fuf_ignoreCase . g:fuf_dir_exclude . "\n" . a:dir + if !exists('s:cache[key]') + let s:cache[key] = fuf#enumExpandedDirsEntries(a:dir, g:fuf_dir_exclude) + call filter(s:cache[key], 'v:val.word =~# ''[/\\]$''') + if isdirectory(a:dir) + call insert(s:cache[key], fuf#makePathItem(a:dir . '.', '', 0)) + endif + call fuf#mapToSetSerialIndex(s:cache[key], 1) + call fuf#mapToSetAbbrWithSnippedWordAsPath(s:cache[key]) + endif + return s:cache[key] +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_dir_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return a:enteredPattern =~# '[^/\\]$' +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForPathTail', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return fuf#makePreviewLinesAround( + \ fuf#glob(fnamemodify(a:word, ':p') . '*'), + \ [], a:count, self.getPreviewHeight()) + return +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return s:enumItems(fuf#splitPath(a:patternPrimary).head) +endfunction + +" +function s:handler.onOpen(word, mode) + execute ':cd ' . fnameescape(a:word) +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/file.vim b/autoload/fuf/file.vim new file mode 100644 index 0000000..1569192 --- /dev/null +++ b/autoload/fuf/file.vim @@ -0,0 +1,139 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#file#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#file#getSwitchOrder() + return g:fuf_file_switchOrder +endfunction + +" +function fuf#file#getEditableDataNames() + return [] +endfunction + +" +function fuf#file#renewCache() + let s:cache = {} +endfunction + +" +function fuf#file#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#file#onInit() + call fuf#defineLaunchCommand('FufFile' , s:MODE_NAME, '""', []) + call fuf#defineLaunchCommand('FufFileWithFullCwd' , s:MODE_NAME, 'fnamemodify(getcwd(), '':p'')', []) + call fuf#defineLaunchCommand('FufFileWithCurrentBufferDir', s:MODE_NAME, 'expand(''%:~:.'')[:-1-len(expand(''%:~:.:t''))]', []) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:enumItems(dir) + let key = join([getcwd(), g:fuf_ignoreCase, g:fuf_file_exclude, a:dir], "\n") + if !exists('s:cache[key]') + let s:cache[key] = fuf#enumExpandedDirsEntries(a:dir, g:fuf_file_exclude) + call fuf#mapToSetSerialIndex(s:cache[key], 1) + call fuf#mapToSetAbbrWithSnippedWordAsPath(s:cache[key]) + endif + return s:cache[key] +endfunction + +" +function s:enumNonCurrentItems(dir, bufNrPrev, cache) + let key = a:dir . 'AVOIDING EMPTY KEY' + if !exists('a:cache[key]') + " NOTE: Comparing filenames is faster than bufnr('^' . fname . '$') + let bufNamePrev = bufname(a:bufNrPrev) + let a:cache[key] = + \ filter(copy(s:enumItems(a:dir)), 'v:val.word !=# bufNamePrev') + endif + return a:cache[key] +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_file_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return a:enteredPattern =~# '[^/\\]$' +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForPathTail', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return fuf#makePreviewLinesForFile(a:word, a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return s:enumNonCurrentItems( + \ fuf#splitPath(a:patternPrimary).head, self.bufNrPrev, self.cache) +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#openFile(a:word, a:mode, g:fuf_reuseWindow) +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + let self.cache = {} +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/givencmd.vim b/autoload/fuf/givencmd.vim new file mode 100644 index 0000000..d59178c --- /dev/null +++ b/autoload/fuf/givencmd.vim @@ -0,0 +1,123 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#givencmd#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#givencmd#getSwitchOrder() + return -1 +endfunction + +" +function fuf#givencmd#getEditableDataNames() + return [] +endfunction + +" +function fuf#givencmd#renewCache() +endfunction + +" +function fuf#givencmd#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#givencmd#onInit() +endfunction + +" +function fuf#givencmd#launch(initialPattern, partialMatching, prompt, items) + let s:prompt = (empty(a:prompt) ? '>' : a:prompt) + let s:items = copy(a:items) + call map(s:items, 'fuf#makeNonPathItem(v:val, "")') + call fuf#mapToSetSerialIndex(s:items, 1) + call map(s:items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') + call fuf#launch(s:MODE_NAME, a:initialPattern, a:partialMatching) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(s:prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return 0 +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return [] +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return s:items +endfunction + +" +function s:handler.onOpen(word, mode) + if a:word[0] =~# '[:/?]' + call histadd(a:word[0], a:word[1:]) + endif + call feedkeys(a:word . "\", 'n') +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/givendir.vim b/autoload/fuf/givendir.vim new file mode 100644 index 0000000..e654d85 --- /dev/null +++ b/autoload/fuf/givendir.vim @@ -0,0 +1,123 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#givendir#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#givendir#getSwitchOrder() + return -1 +endfunction + +" +function fuf#givendir#getEditableDataNames() + return [] +endfunction + +" +function fuf#givendir#renewCache() +endfunction + +" +function fuf#givendir#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#givendir#onInit() +endfunction + +" +function fuf#givendir#launch(initialPattern, partialMatching, prompt, items) + let s:prompt = (empty(a:prompt) ? '>' : a:prompt) + let s:items = map(copy(a:items), 'substitute(v:val, ''[/\\]\?$'', "", "")') + let s:items = map(s:items, 'fuf#makePathItem(v:val, "", 0)') + call fuf#mapToSetSerialIndex(s:items, 1) + call fuf#mapToSetAbbrWithSnippedWordAsPath(s:items) + call fuf#launch(s:MODE_NAME, a:initialPattern, a:partialMatching) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(s:prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return fuf#makePreviewLinesAround( + \ fuf#glob(fnamemodify(a:word, ':p') . '*'), + \ [], a:count, self.getPreviewHeight()) + return +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return s:items +endfunction + +" +function s:handler.onOpen(word, mode) + execute ':cd ' . fnameescape(a:word) +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/givenfile.vim b/autoload/fuf/givenfile.vim new file mode 100644 index 0000000..5419ff8 --- /dev/null +++ b/autoload/fuf/givenfile.vim @@ -0,0 +1,121 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#givenfile#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#givenfile#getSwitchOrder() + return -1 +endfunction + +" +function fuf#givenfile#getEditableDataNames() + return [] +endfunction + +" +function fuf#givenfile#renewCache() +endfunction + +" +function fuf#givenfile#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#givenfile#onInit() +endfunction + +" +function fuf#givenfile#launch(initialPattern, partialMatching, prompt, items) + let s:prompt = (empty(a:prompt) ? '>' : a:prompt) + let s:items = map(copy(a:items), 'fuf#makePathItem(v:val, "", 0)') + call fuf#mapToSetSerialIndex(s:items, 1) + call map(s:items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') + call fuf#launch(s:MODE_NAME, a:initialPattern, a:partialMatching) +endfunction + + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(s:prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return fuf#makePreviewLinesForFile(a:word, a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return s:items +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#openFile(a:word, a:mode, g:fuf_reuseWindow) +endfunction + + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/help.vim b/autoload/fuf/help.vim new file mode 100644 index 0000000..8f03e36 --- /dev/null +++ b/autoload/fuf/help.vim @@ -0,0 +1,198 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#help#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#help#getSwitchOrder() + return g:fuf_help_switchOrder +endfunction + +" +function fuf#help#getEditableDataNames() + return [] +endfunction + +" +function fuf#help#renewCache() + let s:cache = {} +endfunction + +" +function fuf#help#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#help#onInit() + call fuf#defineLaunchCommand('FufHelp' , s:MODE_NAME, '""', []) + call fuf#defineLaunchCommand('FufHelpWithCursorWord', s:MODE_NAME, 'expand('''')', []) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:getCurrentHelpTagFiles() + let prefix = 'doc' . l9#getPathSeparator() + let tagFiles = split(globpath(&runtimepath, prefix . 'tags' ), "\n") + \ + split(globpath(&runtimepath, prefix . 'tags-??'), "\n") + return sort(map(tagFiles, 'fnamemodify(v:val, ":p")')) +endfunction + +" +function s:parseHelpTagEntry(line, tagFile) + let elements = split(a:line, "\t") + if len(elements) != 3 || elements[0][0] ==# '!' + return {} + endif + let suffix = matchstr(a:tagFile, '-\zs..$') + if empty(suffix) + let suffix = '@en' + else + let suffix = '@' . suffix + endif + let dir = fnamemodify(a:tagFile, ':h') . l9#getPathSeparator() + return { + \ 'word' : elements[0] . suffix, + \ 'path' : dir . elements[1], + \ 'pattern': elements[2][1:], + \ } +endfunction + +" +function s:getHelpTagEntries(tagFile) + let names = map(l9#readFile(a:tagFile), 's:parseHelpTagEntry(v:val, a:tagFile)') + return filter(names, '!empty(v:val)') +endfunction + +" +function s:parseHelpTagFiles(tagFiles, key) + let cacheName = 'cache-' . l9#hash224(a:key) + let cacheTime = fuf#getDataFileTime(s:MODE_NAME, cacheName) + if cacheTime != -1 && fuf#countModifiedFiles(a:tagFiles, cacheTime) == 0 + return fuf#loadDataFile(s:MODE_NAME, cacheName) + endif + let items = l9#unique(l9#concat(map(copy(a:tagFiles), 's:getHelpTagEntries(v:val)'))) + let items = map(items, 'extend(v:val, fuf#makeNonPathItem(v:val.word, ""))') + call fuf#mapToSetSerialIndex(items, 1) + let items = map(items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') + call fuf#saveDataFile(s:MODE_NAME, cacheName, items) + return items +endfunction + +" +function s:enumHelpTags(tagFiles) + if !len(a:tagFiles) + return [] + endif + let key = join([g:fuf_ignoreCase] + a:tagFiles, "\n") + if !exists('s:cache[key]') || fuf#countModifiedFiles(a:tagFiles, s:cache[key].time) + let s:cache[key] = { + \ 'time' : localtime(), + \ 'items' : s:parseHelpTagFiles(a:tagFiles, key) + \ } + endif + return s:cache[key].items +endfunction + +" +function s:getMatchingIndex(lines, pattern) + if empty(a:pattern) + return -1 + endif + for i in range(len(a:lines)) + if stridx(a:lines[i], a:pattern) >= 0 + return i + endif + endfor + return -1 +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_help_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + let items = filter(copy(s:enumHelpTags(self.tagFiles)), 'v:val.word ==# a:word') + if empty(items) + return [] + endif + let lines = fuf#getFileLines(items[0].path) + let index = s:getMatchingIndex(lines, items[0].pattern) + return [items[0].path . ':'] + fuf#makePreviewLinesAround( + \ lines, (index < 0 ? [] : [index]), a:count, self.getPreviewHeight() - 1) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return s:enumHelpTags(self.tagFiles) +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#openHelp(a:word, a:mode) +endfunction + +" +function s:handler.onModeEnterPre() + let self.tagFiles = s:getCurrentHelpTagFiles() +endfunction + +" +function s:handler.onModeEnterPost() +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/jumplist.vim b/autoload/fuf/jumplist.vim new file mode 100644 index 0000000..ddbb1ab --- /dev/null +++ b/autoload/fuf/jumplist.vim @@ -0,0 +1,182 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#jumplist#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#jumplist#getSwitchOrder() + return g:fuf_jumplist_switchOrder +endfunction + +" +function fuf#jumplist#getEditableDataNames() + return [] +endfunction + +" +function fuf#jumplist#renewCache() +endfunction + +" +function fuf#jumplist#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#jumplist#onInit() + call fuf#defineLaunchCommand('FufJumpList', s:MODE_NAME, '""', []) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:getJumpsLines() + redir => result + :silent jumps + redir END + return split(result, "\n") +endfunction + +" +function s:parseJumpsLine(line, bufnrPrev) + "return matchlist(a:line, '^\(.\)\s\+\(\d\+\)\s\(.*\)$') + let elements = matchlist(a:line, '\v^(.)\s*(\d+)\s+(\d+)\s+(\d+)\s*(.*)$') + if empty(elements) + return {} + endif + let linePrevBuffer = join(getbufline(a:bufnrPrev, elements[3])) + if stridx(linePrevBuffer, elements[5]) >= 0 + let fname = bufname(a:bufnrPrev) + let text = elements[5] + else + let fname = elements[5] + let text = join(getbufline('^' . elements[5] . '$', elements[3])) + endif + return { + \ 'prefix': elements[1], + \ 'count' : elements[2], + \ 'lnum' : elements[3], + \ 'fname' : fname, + \ 'text' : printf('%s|%d:%d|%s', fname, elements[3], elements[4], text), + \ } +endfunction + +" +function s:makeItem(line, bufnrPrev) + let parsed = s:parseJumpsLine(a:line, a:bufnrPrev) + if empty(parsed) + return {} + endif + let item = fuf#makeNonPathItem(parsed.text, '') + let item.abbrPrefix = parsed.prefix + let item.lnum = parsed.lnum + let item.fname = parsed.fname + return item +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_jumplist_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + let items = filter(copy(self.items), 'v:val.word ==# a:word') + if empty(items) + return [] + endif + let lines = fuf#getFileLines(items[0].fname) + return fuf#makePreviewLinesAround( + \ lines, [items[0].lnum - 1], a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#prejump(a:mode) + let older = 0 + for line in reverse(s:getJumpsLines()) + if stridx(line, '>') == 0 + let older = 1 + endif + let parsed = s:parseJumpsLine(line, self.bufNrPrev) + if !empty(parsed) && parsed.text ==# a:word + if parsed.count != 0 + execute 'normal! ' . parsed.count . (older ? "\" : "\") . 'zvzz' + endif + break + endif + endfor +endfunction + +" +function s:handler.onModeEnterPre() + let self.items = s:getJumpsLines() +endfunction + +" +function s:handler.onModeEnterPost() + call map(self.items, 's:makeItem(v:val, self.bufNrPrev)') + call filter(self.items, '!empty(v:val)') + call reverse(self.items) + call fuf#mapToSetSerialIndex(self.items, 1) + call map(self.items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: + diff --git a/autoload/fuf/line.vim b/autoload/fuf/line.vim new file mode 100644 index 0000000..60447b5 --- /dev/null +++ b/autoload/fuf/line.vim @@ -0,0 +1,135 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#line#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#line#getSwitchOrder() + return g:fuf_line_switchOrder +endfunction + +" +function fuf#line#getEditableDataNames() + return [] +endfunction + +" +function fuf#line#renewCache() +endfunction + +" +function fuf#line#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#line#onInit() + call fuf#defineLaunchCommand('FufLine', s:MODE_NAME, '""', []) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') +let s:OPEN_TYPE_DELETE = -1 + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_line_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + let items = filter(copy(self.items), 'v:val.word ==# a:word') + if empty(items) + return [] + endif + let lines = fuf#getFileLines(self.bufNrPrev) + return fuf#makePreviewLinesAround( + \ lines, [items[0].index - 1], a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#prejump(a:mode) + call filter(self.items, 'v:val.word ==# a:word') + if empty(self.items) + return + execute 'cc ' . self.items[0].index + endif + call cursor(self.items[0].index, 0) + normal! zvzz +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + let tab = repeat(' ', getbufvar(self.bufNrPrev, '&tabstop')) + let self.items = getbufline(self.bufNrPrev, 1, '$') + let lnumFormat = '%' . len(string(len(self.items) + 1)) . 'd|' + for i in range(len(self.items)) + let self.items[i] = printf(lnumFormat, i + 1) + \ . substitute(self.items[i], "\t", tab, 'g') + endfor + call map(self.items, 'fuf#makeNonPathItem(v:val, "")') + call fuf#mapToSetSerialIndex(self.items, 1) + call map(self.items, 'fuf#setAbbrWithFormattedWord(v:val, 0)') +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/mrucmd.vim b/autoload/fuf/mrucmd.vim new file mode 100644 index 0000000..58632ce --- /dev/null +++ b/autoload/fuf/mrucmd.vim @@ -0,0 +1,134 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#mrucmd#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#mrucmd#getSwitchOrder() + return g:fuf_mrucmd_switchOrder +endfunction + +" +function fuf#mrucmd#getEditableDataNames() + return ['items'] +endfunction + +" +function fuf#mrucmd#renewCache() +endfunction + +" +function fuf#mrucmd#requiresOnCommandPre() + return 1 +endfunction + +" +function fuf#mrucmd#onInit() + call fuf#defineLaunchCommand('FufMruCmd', s:MODE_NAME, '""', []) +endfunction + +" +function fuf#mrucmd#onCommandPre(cmd) + if getcmdtype() =~# '^[:/?]' + call s:updateInfo(a:cmd) + endif +endfunction + + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:updateInfo(cmd) + let items = fuf#loadDataFile(s:MODE_NAME, 'items') + let items = fuf#updateMruList( + \ items, { 'word' : a:cmd, 'time' : localtime() }, + \ g:fuf_mrucmd_maxItem, g:fuf_mrucmd_exclude) + call fuf#saveDataFile(s:MODE_NAME, 'items', items) +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_mrucmd_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return 0 +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return [] +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + call s:updateInfo(a:word) + call histadd(a:word[0], a:word[1:]) + call feedkeys(a:word . "\", 'n') +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + let self.items = fuf#loadDataFile(s:MODE_NAME, 'items') + call map(self.items, 'fuf#makeNonPathItem(v:val.word, strftime(g:fuf_timeFormat, v:val.time))') + call fuf#mapToSetSerialIndex(self.items, 1) + call map(self.items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/mrufile.vim b/autoload/fuf/mrufile.vim new file mode 100644 index 0000000..f90b9e3 --- /dev/null +++ b/autoload/fuf/mrufile.vim @@ -0,0 +1,234 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#mrufile#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#mrufile#getSwitchOrder() + return g:fuf_mrufile_switchOrder +endfunction + +" +function fuf#mrufile#getEditableDataNames() + return ['items', 'itemdirs'] +endfunction + +" +function fuf#mrufile#renewCache() + let s:cache = {} + let s:aroundCache = {} +endfunction + +" +function fuf#mrufile#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#mrufile#onInit() + call fuf#defineLaunchCommand('FufMruFile', s:MODE_NAME, '""', []) + call fuf#defineLaunchCommand('FufMruFileInCwd', s:MODE_NAME, + \ '""', [['g:fuf_mrufile_underCwd', 1]]) + call l9#defineVariableDefault('g:fuf_mrufile_underCwd', 0) " private option + call l9#defineVariableDefault('g:fuf_mrufile_searchAroundLevel', -1) " private option + augroup fuf#mrufile + autocmd! + autocmd BufEnter * call s:updateData() + autocmd BufWritePost * call s:updateData() + augroup END +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') +let s:OPEN_TYPE_EXPAND = -1 + +" +function s:updateData() + if !empty(&buftype) || !filereadable(expand('%')) + return + endif + let items = fuf#loadDataFile(s:MODE_NAME, 'items') + let items = fuf#updateMruList( + \ items, { 'word' : expand('%:p'), 'time' : localtime() }, + \ g:fuf_mrufile_maxItem, g:fuf_mrufile_exclude) + call fuf#saveDataFile(s:MODE_NAME, 'items', items) + call s:removeItemFromCache(expand('%:p')) + let itemDirs = fuf#loadDataFile(s:MODE_NAME, 'itemdirs') + let itemDirs = fuf#updateMruList( + \ itemDirs, { 'word' : expand('%:p:h') }, + \ g:fuf_mrufile_maxItemDir, g:fuf_mrufile_exclude) + call fuf#saveDataFile(s:MODE_NAME, 'itemdirs', itemDirs) +endfunction + +" +function s:removeItemFromCache(word) + for items in values(s:cache) + if exists('items[a:word]') + unlet items[a:word] + endif + endfor +endfunction + +" returns empty value if invalid item +function s:formatItemUsingCache(item) + if a:item.word !~ '\S' + return {} + endif + if !exists('s:cache[a:item.word]') + if filereadable(a:item.word) + let s:cache[a:item.word] = fuf#makePathItem( + \ fnamemodify(a:item.word, ':p:~'), strftime(g:fuf_timeFormat, a:item.time), 0) + else + let s:cache[a:item.word] = {} + endif + endif + return s:cache[a:item.word] +endfunction + +" +function s:expandSearchDir(dir, level) + let dirs = [a:dir] + let dirPrev = a:dir + for i in range(a:level) + let dirPrev = l9#concatPaths([dirPrev, '*']) + call add(dirs, dirPrev) + endfor + let dirPrev = a:dir + for i in range(a:level) + let dirPrevPrev = dirPrev + let dirPrev = fnamemodify(dirPrev, ':h') + if dirPrevPrev ==# dirPrev + break + endif + call add(dirs, dirPrev) + endfor + return dirs +endfunction + +" +function s:listAroundFiles(dir) + if !exists('s:aroundCache[a:dir]') + let s:aroundCache[a:dir] = [a:dir] + + \ fuf#glob(l9#concatPaths([a:dir, '*' ])) + + \ fuf#glob(l9#concatPaths([a:dir, '.*'])) + call filter(s:aroundCache[a:dir], 'filereadable(v:val)') + call map(s:aroundCache[a:dir], 'fuf#makePathItem(fnamemodify(v:val, ":~"), "", 0)') + if len(g:fuf_mrufile_exclude) + call filter(s:aroundCache[a:dir], 'v:val.word !~ g:fuf_mrufile_exclude') + endif + endif + return s:aroundCache[a:dir] +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + let cwdString = (g:fuf_mrufile_underCwd ? '[CWD]' : '') + let levelString = (g:fuf_mrufile_searchAroundLevel < 0 ? '' + \ : '[Around:' . g:fuf_mrufile_searchAroundLevel . ']') + return fuf#formatPrompt(g:fuf_mrufile_prompt, self.partialMatching, cwdString . levelString) +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return fuf#makePreviewLinesForFile(a:word, a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + if a:mode ==# s:OPEN_TYPE_EXPAND + let nextLevel = (self.searchAroundLevel < 0 ? 0 : self.searchAroundLevel + 1) + call fuf#setOneTimeVariables(['g:fuf_mrufile_searchAroundLevel', nextLevel]) + let self.reservedMode = self.getModeName() + return + else + call fuf#openFile(a:word, a:mode, g:fuf_reuseWindow) + endif +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + let self.searchAroundLevel = g:fuf_mrufile_searchAroundLevel + call fuf#defineKeyMappingInHandler(g:fuf_mrufile_keyExpand, + \ 'onCr(' . s:OPEN_TYPE_EXPAND . ')') + if self.searchAroundLevel < 0 + let self.items = fuf#loadDataFile(s:MODE_NAME, 'items') + call map(self.items, 's:formatItemUsingCache(v:val)') + else + let self.items = fuf#loadDataFile(s:MODE_NAME, 'itemdirs') + call map(self.items, 's:expandSearchDir(v:val.word, g:fuf_mrufile_searchAroundLevel)') + let self.items = l9#concat(self.items) + let self.items = l9#unique(self.items) + call map(self.items, 's:listAroundFiles(v:val)') + let self.items = l9#concat(self.items) + endif + " NOTE: Comparing filenames is faster than bufnr('^' . fname . '$') + let bufNamePrev = fnamemodify(bufname(self.bufNrPrev), ':p:~') + call filter(self.items, '!empty(v:val) && v:val.word !=# bufNamePrev') + if g:fuf_mrufile_underCwd + let cwd = fnamemodify(getcwd(), ':p:~') + call filter(self.items, 'stridx(v:val.word, cwd) == 0') + endif + call fuf#mapToSetSerialIndex(self.items, 1) + call fuf#mapToSetAbbrWithSnippedWordAsPath(self.items) +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/quickfix.vim b/autoload/fuf/quickfix.vim new file mode 100644 index 0000000..dd5d67c --- /dev/null +++ b/autoload/fuf/quickfix.vim @@ -0,0 +1,154 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#quickfix#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#quickfix#getSwitchOrder() + return g:fuf_quickfix_switchOrder +endfunction + +" +function fuf#quickfix#getEditableDataNames() + return [] +endfunction + +" +function fuf#quickfix#renewCache() +endfunction + +" +function fuf#quickfix#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#quickfix#onInit() + call fuf#defineLaunchCommand('FufQuickfix', s:MODE_NAME, '""', []) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:getJumpsLines() + redir => result + :silent jumps + redir END + return split(result, "\n") +endfunction + +" +function s:parseJumpsLine(line) + return matchlist(a:line, '^\(.\)\s\+\(\d\+\)\s\(.*\)$') +endfunction + +" +function s:makeItem(qfItem) + if !a:qfItem.valid + return {} + endif + let item = fuf#makeNonPathItem( + \ printf('%s|%d:%d|%s', bufname(a:qfItem.bufnr), a:qfItem.lnum, + \ a:qfItem.col, matchstr(a:qfItem.text, '\s*\zs.*\S')) + \ , '') + let item.bufnr = a:qfItem.bufnr + let item.lnum = a:qfItem.lnum + return item +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_quickfix_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + let items = filter(copy(self.items), 'v:val.word ==# a:word') + if empty(items) + return [] + endif + let lines = fuf#getFileLines(items[0].bufnr) + return fuf#makePreviewLinesAround( + \ lines, [items[0].lnum - 1], a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#prejump(a:mode) + call filter(self.items, 'v:val.word ==# a:word') + if !empty(self.items) + execute 'cc ' . self.items[0].index + endif +endfunction + +" +function s:handler.onModeEnterPre() +endfunction + +" +function s:handler.onModeEnterPost() + let self.items = getqflist() + call map(self.items, 's:makeItem(v:val)') + call fuf#mapToSetSerialIndex(self.items, 1) + call filter(self.items, 'exists("v:val.word")') + call map(self.items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: + diff --git a/autoload/fuf/tag.vim b/autoload/fuf/tag.vim new file mode 100644 index 0000000..362cabf --- /dev/null +++ b/autoload/fuf/tag.vim @@ -0,0 +1,178 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#tag#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#tag#getSwitchOrder() + return g:fuf_tag_switchOrder +endfunction + +" +function fuf#tag#getEditableDataNames() + return [] +endfunction + +" +function fuf#tag#renewCache() + let s:cache = {} +endfunction + +" +function fuf#tag#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#tag#onInit() + call fuf#defineLaunchCommand('FufTag' , s:MODE_NAME, '""', []) + call fuf#defineLaunchCommand('FufTagWithCursorWord', s:MODE_NAME, 'expand('''')', []) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:getTagNames(tagFile) + let names = map(l9#readFile(a:tagFile), 'matchstr(v:val, ''^[^!\t][^\t]*'')') + return filter(names, 'v:val =~# ''\S''') +endfunction + +" +function s:parseTagFiles(tagFiles, key) + let cacheName = 'cache-' . l9#hash224(a:key) + let cacheTime = fuf#getDataFileTime(s:MODE_NAME, cacheName) + if cacheTime != -1 && fuf#countModifiedFiles(a:tagFiles, cacheTime) == 0 + return fuf#loadDataFile(s:MODE_NAME, cacheName) + endif + let items = l9#unique(l9#concat(map(copy(a:tagFiles), 's:getTagNames(v:val)'))) + let items = map(items, 'fuf#makeNonPathItem(v:val, "")') + call fuf#mapToSetSerialIndex(items, 1) + let items = map(items, 'fuf#setAbbrWithFormattedWord(v:val, 1)') + call fuf#saveDataFile(s:MODE_NAME, cacheName, items) + return items +endfunction + +" +function s:enumTags(tagFiles) + if !len(a:tagFiles) + return [] + endif + let key = join([g:fuf_ignoreCase] + a:tagFiles, "\n") + if !exists('s:cache[key]') || fuf#countModifiedFiles(a:tagFiles, s:cache[key].time) + let s:cache[key] = { + \ 'time' : localtime(), + \ 'items' : s:parseTagFiles(a:tagFiles, key) + \ } + endif + return s:cache[key].items +endfunction + +" +function s:getMatchingIndex(lines, cmd) + if a:cmd !~# '\D' + return str2nr(a:cmd) + endif + let pattern = matchstr(a:cmd, '^\/\^\zs.*\ze\$\/$') + if empty(pattern) + return -1 + endif + for i in range(len(a:lines)) + if a:lines[i] ==# pattern + return i + endif + endfor + return -1 +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_tag_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForNonPath', + \ self.partialMatching) +endfunction + +" 'cmd' is '/^hoge hoge$/' or line number +function s:handler.makePreviewLines(word, count) + let tags = taglist('^' . a:word . '$') + if empty(tags) + return [] + endif + let i = a:count % len(tags) + let title = printf('(%d/%d) %s', i + 1, len(tags), tags[i].filename) + let lines = fuf#getFileLines(tags[i].filename) + let index = s:getMatchingIndex(lines, tags[i].cmd) + return [title] + fuf#makePreviewLinesAround( + \ lines, (index < 0 ? [] : [index]), 0, self.getPreviewHeight() - 1) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return s:enumTags(self.tagFiles) +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#openTag(a:word, a:mode) +endfunction + +" +function s:handler.onModeEnterPre() + let self.tagFiles = fuf#getCurrentTagFiles() +endfunction + +" +function s:handler.onModeEnterPost() + let &l:tags = join(self.tagFiles, ',') +endfunction + +" +function s:handler.onModeLeavePost(opened) + let &l:tags = '' +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/fuf/taggedfile.vim b/autoload/fuf/taggedfile.vim new file mode 100644 index 0000000..74652fc --- /dev/null +++ b/autoload/fuf/taggedfile.vim @@ -0,0 +1,159 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" GLOBAL FUNCTIONS {{{1 + +" +function fuf#taggedfile#createHandler(base) + return a:base.concretize(copy(s:handler)) +endfunction + +" +function fuf#taggedfile#getSwitchOrder() + return g:fuf_taggedfile_switchOrder +endfunction + +" +function fuf#taggedfile#getEditableDataNames() + return [] +endfunction + +" +function fuf#taggedfile#renewCache() + let s:cache = {} +endfunction + +" +function fuf#taggedfile#requiresOnCommandPre() + return 0 +endfunction + +" +function fuf#taggedfile#onInit() + call fuf#defineLaunchCommand('FufTaggedFile', s:MODE_NAME, '""', []) +endfunction + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS/VARIABLES {{{1 + +let s:MODE_NAME = expand(':t:r') + +" +function s:getTaggedFileList(tagfile) + execute 'cd ' . fnamemodify(a:tagfile, ':h') + let result = map(l9#readFile(a:tagfile), 'matchstr(v:val, ''^[^!\t][^\t]*\t\zs[^\t]\+'')') + call map(l9#readFile(a:tagfile), 'fnamemodify(v:val, ":p")') + cd - + call map(l9#readFile(a:tagfile), 'fnamemodify(v:val, ":~:.")') + return filter(result, 'v:val =~# ''[^/\\ ]$''') +endfunction + +" +function s:parseTagFiles(tagFiles, key) + let cacheName = 'cache-' . l9#hash224(a:key) + let cacheTime = fuf#getDataFileTime(s:MODE_NAME, cacheName) + if cacheTime != -1 && fuf#countModifiedFiles(a:tagFiles, cacheTime) == 0 + return fuf#loadDataFile(s:MODE_NAME, cacheName) + endif + let items = l9#unique(l9#concat(map(copy(a:tagFiles), 's:getTaggedFileList(v:val)'))) + call map(items, 'fuf#makePathItem(v:val, "", 0)') + call fuf#mapToSetSerialIndex(items, 1) + call fuf#mapToSetAbbrWithSnippedWordAsPath(items) + call fuf#saveDataFile(s:MODE_NAME, cacheName, items) + return items +endfunction + +" +function s:enumTaggedFiles(tagFiles) + if !len(a:tagFiles) + return [] + endif + let key = join([getcwd(), g:fuf_ignoreCase] + a:tagFiles, "\n") + if !exists('s:cache[key]') || fuf#countModifiedFiles(a:tagFiles, s:cache[key].time) + let s:cache[key] = { + \ 'time' : localtime(), + \ 'items' : s:parseTagFiles(a:tagFiles, key) + \ } + endif + return s:cache[key].items +endfunction + +" }}}1 +"============================================================================= +" s:handler {{{1 + +let s:handler = {} + +" +function s:handler.getModeName() + return s:MODE_NAME +endfunction + +" +function s:handler.getPrompt() + return fuf#formatPrompt(g:fuf_taggedfile_prompt, self.partialMatching, '') +endfunction + +" +function s:handler.getPreviewHeight() + return g:fuf_previewHeight +endfunction + +" +function s:handler.isOpenable(enteredPattern) + return 1 +endfunction + +" +function s:handler.makePatternSet(patternBase) + return fuf#makePatternSet(a:patternBase, 's:interpretPrimaryPatternForPath', + \ self.partialMatching) +endfunction + +" +function s:handler.makePreviewLines(word, count) + return fuf#makePreviewLinesForFile(a:word, a:count, self.getPreviewHeight()) +endfunction + +" +function s:handler.getCompleteItems(patternPrimary) + return self.items +endfunction + +" +function s:handler.onOpen(word, mode) + call fuf#openFile(a:word, a:mode, g:fuf_reuseWindow) +endfunction + +" +function s:handler.onModeEnterPre() + let self.tagFiles = fuf#getCurrentTagFiles() +endfunction + +" +function s:handler.onModeEnterPost() + " NOTE: Comparing filenames is faster than bufnr('^' . fname . '$') + let bufNamePrev = fnamemodify(bufname(self.bufNrPrev), ':p:~:.') + " NOTE: Don't do this in onModeEnterPre() + " because that should return in a short time. + let self.items = copy(s:enumTaggedFiles(self.tagFiles)) + call filter(self.items, 'v:val.word !=# bufNamePrev') +endfunction + +" +function s:handler.onModeLeavePost(opened) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/l9.vim b/autoload/l9.vim new file mode 100644 index 0000000..b6a0ae7 --- /dev/null +++ b/autoload/l9.vim @@ -0,0 +1,570 @@ +"============================================================================= +" Copyright (c) 2009-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if exists('g:loaded_autoload_l9') + finish +endif +let g:loaded_autoload_l9 = 1 + +" }}}1 +"============================================================================= +" COMPATIBILITY TEST {{{1 + +" +let s:L9_VERSION_CURRENT = 101 +let s:L9_VERSION_PASSABLE = 101 + +" returns true if given version is compatible. +function l9#isCompatible(ver) + return +endfunction + +let s:VERSION_FACTOR = str2float('0.01') + +" returns false if the caller script should finish. +" a:vimVersion: if 0, don't check vim version +" a:l9Version: same rule as v:version +function l9#guardScriptLoading(path, vimVersion, l9Version, exprs) + let loadedVarName = 'g:loaded_' . substitute(a:path, '\W', '_', 'g') + if exists(loadedVarName) + return 0 + elseif a:vimVersion > 0 && a:vimVersion > v:version + echoerr a:path . ' requires Vim version ' . string(a:vimVersion * s:VERSION_FACTOR) + return 0 + elseif a:l9Version > 0 && (a:l9Version > s:L9_VERSION_CURRENT || + \ a:l9Version < s:L9_VERSION_PASSABLE) + echoerr a:path . ' requires L9 library version ' . string(a:l9Version * s:VERSION_FACTOR) + return 0 + endif + for expr in a:exprs + if !eval(expr) + echoerr a:path . ' requires: ' . expr + return 0 + endif + endfor + let {loadedVarName} = 1 + return 1 +endfunction + +" +function l9#getVersion() + return s:L9_VERSION_CURRENT +endfunction + +" }}}1 +"============================================================================= +" LIST {{{1 + +" Removes duplicates (unstable) +" This function doesn't change the list of argument. +function l9#unique(items) + let sorted = sort(a:items) + if len(sorted) < 2 + return sorted + endif + let last = remove(sorted, 0) + let result = [last] + for item in sorted + if item != last + call add(result, item) + let last = item + endif + endfor + return result +endfunction + +" Removes duplicates (stable) +" This function doesn't change the list of argument. +function l9#uniqueStably(items) + let result = [] + for item in a:items + if count(result, item, &ignorecase) == 0 + call add(result, item) + endif + endfor + return result +endfunction + +" [ [0], [1,2], [3] ] -> [ 0, 1, 2, 3 ] +" This function doesn't change the list of argument. +function l9#concat(items) + let result = [] + for l in a:items + let result += l + endfor + return result +endfunction + +" [ [0,1,2], [3,4], [5,6,7,8] ] -> [ [0,3,5],[1,4,6] ] +" This function doesn't change the list of argument. +function l9#zip(items) + let result = [] + for i in range(min(map(copy(a:items), 'len(v:val)'))) + call add(result, map(copy(a:items), 'v:val[i]')) + endfor + return result +endfunction + +" filter() with the maximum number of items +" This function doesn't change the list of argument. +function l9#filterWithLimit(items, expr, limit) + if a:limit <= 0 + return filter(copy(a:items), a:expr) + endif + let result = [] + let stride = a:limit * 3 / 2 " x1.5 + for i in range(0, len(a:items) - 1, stride) + let result += filter(a:items[i : i + stride - 1], a:expr) + if len(result) >= a:limit + return remove(result, 0, a:limit - 1) + endif + endfor + return result +endfunction + +" Removes if a:expr is evaluated as non-zero and returns removed items. +" This function change the list of argument. +function l9#removeIf(items, expr) + let removed = filter(copy(a:items), a:expr) + call filter(a:items, '!( ' . a:expr . ')') + return removed +endfunction + +" }}}1 +"============================================================================= +" NUMERIC {{{1 + +" }}}1 +"============================================================================= +" STRING {{{1 + +" Snips a:str and add a:mask if the length of a:str is more than a:len +function l9#snipHead(str, len, mask) + if a:len >= len(a:str) + return a:str + elseif a:len <= len(a:mask) + return a:mask + endif + return a:mask . a:str[-a:len + len(a:mask):] +endfunction + +" Snips a:str and add a:mask if the length of a:str is more than a:len +function l9#snipTail(str, len, mask) + if a:len >= len(a:str) + return a:str + elseif a:len <= len(a:mask) + return a:mask + endif + return a:str[:a:len - 1 - len(a:mask)] . a:mask +endfunction + +" Snips a:str and add a:mask if the length of a:str is more than a:len +function l9#snipMid(str, len, mask) + if a:len >= len(a:str) + return a:str + elseif a:len <= len(a:mask) + return a:mask + endif + let len_head = (a:len - len(a:mask)) / 2 + let len_tail = a:len - len(a:mask) - len_head + return (len_head > 0 ? a:str[: len_head - 1] : '') . a:mask . + \ (len_tail > 0 ? a:str[-len_tail :] : '') +endfunction + +" +function l9#hash224(str) + let a = 0x00000800 " shift 11 bit (if unsigned) + let b = 0x001fffff " extract 11 bit (if unsigned) + let nHash = 7 + let hashes = repeat([0], nHash) + for i in range(len(a:str)) + let iHash = i % nHash + let hashes[iHash] = hashes[iHash] * a + hashes[iHash] / b + let hashes[iHash] += char2nr(a:str[i]) + endfor + return join(map(hashes, 'printf("%08x", v:val)'), '') +endfunction + +" wildcard -> regexp +function l9#convertWildcardToRegexp(expr) + let re = escape(a:expr, '\') + for [pat, sub] in [ [ '*', '\\.\\*' ], [ '?', '\\.' ], [ '[', '\\[' ], ] + let re = substitute(re, pat, sub, 'g') + endfor + return '\V' . re +endfunction + +" }}}1 +"============================================================================= +" LINES {{{1 + +" Removes from the line matching with a:begin first to the line matching with +" a:end next and returns removed lines. +" If matching range is not found, returns [] +function l9#removeLinesBetween(lines, begin, end) + for i in range(len(a:lines) - 1) + if a:lines[i] =~ a:begin + break + endif + endfor + for j in range(i + 1, len(a:lines) - 1) + if a:lines[j] =~ a:end + let g:l0 += [a:lines[i : j]] + return remove(a:lines, i, j) + endif + endfor + return [] +endfunction + +" }}}1 +"============================================================================= +" PATH {{{1 + +" returns the path separator charactor. +function l9#getPathSeparator() + return (!&shellslash && (has('win32') || has('win64')) ? '\' : '/') +endfunction + +" [ 'a', 'b/', '/c' ] -> 'a/b/c' +function l9#concatPaths(paths) + let result = '' + for p in a:paths + if empty(p) + continue + elseif empty(result) + let result = p + else + let result = substitute(result, '[/\\]$', '', '') . l9#getPathSeparator() + \ . substitute(p, '^[/\\]', '', '') + endif + endfor + return result +endfunction + +" path: '/a/b/c/d', dir: '/a/b' => 'c/d' +function l9#modifyPathRelativeToDir(path, dir) + let pathFull = fnamemodify(a:path, ':p') + let dirFull = fnamemodify(a:dir, ':p') + if len(pathFull) < len(dirFull) || pathFull[:len(dirFull) - 1] !=# dirFull + return pathFull + endif + return pathFull[len(dirFull):] +endfunction + +" }}}1 +"============================================================================= +" FILE {{{1 + +" Almost same as readfile(). +function l9#readFile(...) + let args = copy(a:000) + let args[0] = expand(args[0]) + try + return call('readfile', args) + catch + endtry + return [] +endfunction + +" Almost same as writefile(). +function l9#writeFile(...) + let args = copy(a:000) + let args[1] = expand(args[1]) + let dir = fnamemodify(args[1], ':h') + try + if !isdirectory(dir) + call mkdir(dir, 'p') + endif + return call('writefile', args) + catch + endtry + return -1 " -1 is error code. +endfunction + +" }}}1 +"============================================================================= +" BUFFER {{{1 + +" :wall/:wall! wrapper. Useful for writing readonly buffers. +function l9#writeAll() + try + silent update " NOTE: avoiding a problem with a buftype=acwrite buffer. + silent wall + catch /^Vim/ " E45, E505 + if l9#inputHl('Question', v:exception . "\nWrite readonly files? (Y/N) : ", 'Y') ==? 'y' + redraw + :wall! + endif + endtry +endfunction + +" Loads given files with :edit command +function l9#loadFilesToBuffers(files) + for file in filter(copy(a:files), '!bufloaded(v:val)') + execute 'edit ' . fnameescape(file) + if !exists('bufNrFirst') + let bufNrFirst = bufnr('%') + endif + endfor + if exists('bufNrFirst') + execute bufNrFirst . 'buffer' + endif +endfunction + +" Deletes all buffers except given files with :bdelete command +function l9#deleteAllBuffersExcept(files) + let bufNrExcepts = map(copy(a:files), 'bufnr("^" . v:val . "$")') + for bufNr in filter(range(1, bufnr('$')), 'bufloaded(v:val)') + if count(bufNrExcepts, bufNr) == 0 + execute bufNr . 'bdelete' + endif + endfor +endfunction + +" }}}1 +"============================================================================= +" WINDOW {{{1 + +" move current window to next tabpage. +function l9#shiftWinNextTabpage() + if tabpagenr('$') < 2 + return + endif + let bufnr = bufnr('%') + tabnext + execute bufnr . 'sbuffer' + tabprevious + if winnr('$') > 1 + close + tabnext + else + close " if tabpage is closed, next tabpage will become current + endif +endfunction + +" move current window to previous tabpage. +function l9#shiftWinPrevTabpage() + if tabpagenr('$') < 2 + return + endif + let bufnr = bufnr('%') + tabprevious + execute bufnr . 'sbuffer' + tabnext + close + tabprevious +endfunction + +" move to a window containing specified buffer. +" returns 0 if the buffer is not found. +function l9#moveToBufferWindowInCurrentTabpage(bufNr) + if bufnr('%') == a:bufNr + return 1 + elseif count(tabpagebuflist(), a:bufNr) == 0 + return 0 + endif + execute bufwinnr(a:bufNr) . 'wincmd w' + return 1 +endfunction + +" returns 0 if the buffer is not found. +function s:moveToOtherTabpageOpeningBuffer(bufNr) + for tabNr in range(1, tabpagenr('$')) + if tabNr != tabpagenr() && count(tabpagebuflist(tabNr), a:bufNr) > 0 + execute 'tabnext ' . tabNr + return 1 + endif + endfor + return 0 +endfunction + +" move to a window containing specified buffer. +" returns 0 if the buffer is not found. +function l9#moveToBufferWindowInOtherTabpage(bufNr) + if !s:moveToOtherTabpageOpeningBuffer(a:bufNr) + return 0 + endif + return l9#moveToBufferWindowInCurrentTabpage(a:bufNr) +endfunction + +" }}}1 +"============================================================================= +" COMMAND LINE {{{1 + +" echo/echomsg with highlighting. +function l9#echoHl(hl, msg, prefix, addingHistory) + let echoCmd = (a:addingHistory ? 'echomsg' : 'echo') + execute "echohl " . a:hl + try + for l in (type(a:msg) == type([]) ? a:msg : split(a:msg, "\n")) + execute echoCmd . ' a:prefix . l' + endfor + finally + echohl None + endtry +endfunction + +" input() with highlighting. +" This function can take list as {completion} argument. +function l9#inputHl(hl, ...) + execute "echohl " . a:hl + try + let args = copy(a:000) + if len(args) > 2 && type(args[2]) == type([]) + let s:candidatesForInputHl = args[2] + let args[2] = 'custom,l9#completeForInputHl' + endif + let s = call('input', args) + unlet! s:candidatesForInputHl + finally + echohl None + endtry + redraw " needed to show following echo to next line. + return s +endfunction + +" only called by l9#inputHl() for completion. +function l9#completeForInputHl(lead, line, pos) + return join(s:candidatesForInputHl, "\n") +endfunction + +" }}}1 +"============================================================================= +" VISUAL MODE {{{1 + +" returns last selected text in Visual mode. +function l9#getSelectedText() + let reg_ = [@", getregtype('"')] + let regA = [@a, getregtype('a')] + if mode() =~# "[vV\]" + silent normal! "aygv + else + let pos = getpos('.') + silent normal! gv"ay + call setpos('.', pos) + endif + let text = @a + call setreg('"', reg_[0], reg_[1]) + call setreg('a', regA[0], regA[1]) + return text +endfunction + + +" }}}1 +"============================================================================= +" EVAL {{{1 + +" loads given text as Vim script with :source command +function l9#loadScript(text) + let lines = (type(a:text) == type([]) ? a:text : split(a:text, "\n")) + let fname = tempname() + call writefile(lines, fname) + source `=fname` + call delete(fname) +endfunction + + +" }}}1 +"============================================================================= +" VARIABLES {{{1 + +" +function l9#defineVariableDefault(name, default) + if !exists(a:name) + let {a:name} = a:default + endif +endfunction + +" }}}1 +"============================================================================= +" GREP {{{1 + +" Execute :vimgrep and opens the quickfix window if matches are found. +" +" a:pattern: search pattern. If ommitted, last search pattern (@/) is used. +" a:files: List of files +function l9#grepFiles(pattern, files) + let target = join(map(a:files, 'escape(v:val, " ")'), ' ') + let pattern = (a:pattern[0] ==# '/' ? a:pattern[1:] : a:pattern) + let pattern = (empty(pattern) ? @/ : pattern) + try + execute printf('vimgrep/%s/j %s', pattern, target) + catch /^Vim/ + call setqflist([]) + endtry + call l9#quickfix#sort() + call l9#quickfix#openIfNotEmpty(1, 0) +endfunction + +" Execute :vimgrep for buffers using l9#grepFiles() +" See also: :L9GrepBuffer :L9GrepBufferAll +function l9#grepBuffers(pattern, bufNrs) + let files = map(filter(a:bufNrs, 'bufloaded(v:val)'), 'bufname(v:val)') + call l9#grepFiles(a:pattern, files) +endfunction + +" }}}1 +"============================================================================= +" SIGN {{{1 + +" Highlights lines using :sign define and :sign place. +" +" a:linehl, a:text, a:texthl: See |signs|. Ignored if empty string. +" a:locations: List of [{buffer number}, {line number}] for highlighting +function l9#placeSign(linehl, text, texthl, locations) + let argLinehl = (empty(a:linehl) ? '' : 'linehl=' . a:linehl) + let argText = (empty(a:text) ? '' : 'text=' . a:text) + let argTexthl = (empty(a:texthl) ? '' : 'texthl=' . a:texthl) + let name = 'l9--' . a:linehl . '--' . a:text . '--' . a:texthl + execute printf('sign define %s linehl=%s text=%s texthl=%s', + \ name, a:linehl, a:text, a:texthl) + for [bufNr, lnum] in a:locations + execute printf('sign place 1 line=%d name=%s buffer=%d', lnum, name, bufNr) + endfor +endfunction + +" }}}1 +"============================================================================= +" NOTIFY EXTERNALLY {{{1 + +" Notify a message using an external program. +" Currently supports Balloonly, Screen, and Tmux. +function l9#notifyExternally(msg) + return l9#notifyBalloonly(a:msg) + \ || l9#notifyScreen(a:msg) + \ || l9#notifyTmux(a:msg) +endfunction + +" +function l9#notifyBalloonly(msg) + if !(has('win32') || has('win64')) || !executable(g:l9_balloonly) + return 0 + endif + execute 'silent !start ' . shellescape(g:l9_balloonly) . ' 4000 "l9" ' . shellescape(a:msg) + return 1 +endfunction + +" +function l9#notifyScreen(msg) + if !has('unix') || has('gui_running') || $WINDOW !~ '\d' || !executable('screen') + return 0 + endif + call system('screen -X wall ' . shellescape('l9: ' . a:msg)) + return 1 +endfunction + +" +function l9#notifyTmux(msg) + if !has('unix') || has('gui_running') || empty($TMUX) || !executable('tmux') + return 0 + endif + call system('tmux display-message ' . shellescape('l9: ' . a:msg)) + return 1 +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/autoload/l9/async.py b/autoload/l9/async.py new file mode 100644 index 0000000..eeb0cc3 --- /dev/null +++ b/autoload/l9/async.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python + +from __future__ import with_statement +import vim +import os +import subprocess +import threading +import Queue + + +class Asyncer: + + def __init__(self): + self._workers = {} + + def execute(self, var_key, var_command, var_cwd, var_input, var_appends): + key = vim.eval(var_key) + command = vim.eval(var_command) + cwd = vim.eval(var_cwd) + input = vim.eval(var_input) + appends = vim.eval(var_appends) + if key not in self._workers: + self._workers[key] = Worker() + self._workers[key].start() + self._workers[key].put(Executor(command, cwd, input, appends)) + + def print_output(self, var_key): + key = vim.eval(var_key) + if key not in self._workers: + return + for l in self._workers[key].copy_outputs(): + print l, + + def print_worker_keys(self): + for k in self._workers.keys(): + print k + + def print_active_worker_keys(self): + for k in self._workers.keys(): + print k + + +class Worker(threading.Thread): + + def __init__(self): + threading.Thread.__init__(self) + self._queue = Queue.Queue() + self._lines = [] + self._lock = threading.Lock() + + def run(self): + while True: + self._queue.get().execute(self) + self._queue.task_done() + + def put(self, executor): + self._queue.put(executor) + + def clear_outputs(self): + with self._lock: + self._lines = [] + + def record_output(self, line): + with self._lock: + self._lines.append(line) + + def copy_outputs(self): + with self._lock: + return self._lines[:] + + +class Executor: + + def __init__(self, command, cwd, input, appends): + self._command = command + self._cwd = cwd + self._input = input + self._appends = appends + + def execute(self, worker): + if not self._appends: + worker.clear_outputs() + os.chdir(self._cwd) + p = subprocess.Popen(self._command, shell=True, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + p.stdin.write(self._input) + line = p.stdout.readline() + while line: + worker.record_output(line) + line = p.stdout.readline() + + diff --git a/autoload/l9/async.vim b/autoload/l9/async.vim new file mode 100644 index 0000000..fa66e9f --- /dev/null +++ b/autoload/l9/async.vim @@ -0,0 +1,67 @@ +"============================================================================= +" Copyright (C) 2009-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, ['has("python")']) + finish +endif + +" }}}1 +"============================================================================= +" ASYNC EXECUTE {{{1 + +" +function s:checkKey(key) + if a:key =~ '\n' || a:key !~ '\S' + throw "Asyncer: Invalid key: " . a:key + endif +endfunction + +" +function l9#async#execute(key, cmd, cwd, input, appends) + call s:checkKey(a:key) + python asyncer.execute('a:key', 'a:cmd', 'a:cwd', 'a:input', 'a:appends') +endfunction + +" +function l9#async#read(key) + call s:checkKey(a:key) + redir => result + silent python asyncer.print_output('a:key') + redir END + " NOTE: "\n" is somehow inserted by redir. + return (result[0] ==# "\n" ? result[1:] : result) +endfunction + +" +function l9#async#listWorkers() + redir => result + silent python asyncer.print_worker_keys() + redir END + return split(result, "\n") +endfunction + +" +function l9#async#listActiveWorkers() + redir => result + silent python asyncer.print_active_worker_keys() + redir END + return split(result, "\n") +endfunction + +" }}}1 +"============================================================================= +" INITIALIZATION {{{1 + +let s:ASYNC_PY_PATH = fnamemodify(expand(':p:h'), ':p') . 'async.py' + +pyfile `=s:ASYNC_PY_PATH` +python asyncer = Asyncer() + +" }}}1 +"============================================================================= +" vim: set fdm=marker: + + diff --git a/autoload/l9/quickfix.vim b/autoload/l9/quickfix.vim new file mode 100644 index 0000000..1758b39 --- /dev/null +++ b/autoload/l9/quickfix.vim @@ -0,0 +1,107 @@ +"============================================================================= +" Copyright (C) 2009-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" QUICKFIX {{{1 + +" Returns non-zero if quickfix window is opened. +function l9#quickfix#isWindowOpened() + return count(map(range(1, winnr('$')), 'getwinvar(v:val, "&buftype")'), 'quickfix') > 0 +endfunction + +" Opens quickfix window if quickfix is not empty, and echo the number of errors. +" +" a:onlyRecognized: if non-zero, opens only if quickfix has recognized errors. +" a:holdCursor: if non-zero, the cursor won't move to quickfix window. +function l9#quickfix#openIfNotEmpty(onlyRecognized, holdCursor) + let numErrors = len(filter(getqflist(), 'v:val.valid')) + let numOthers = len(getqflist()) - numErrors + if numErrors > 0 || (!a:onlyRecognized && numOthers > 0) + copen + if a:holdCursor + wincmd p + endif + else + cclose + endif + redraw + if numOthers > 0 + echo printf('Quickfix: %d(+%d)', numErrors, numOthers) + else + echo printf('Quickfix: %d', numErrors) + endif +endfunction + +" Toggles Quickfix window +function l9#quickfix#toggleWindow() + if l9#quickfix#isWindowOpened() + cclose + else + call l9#quickfix#openIfNotEmpty(0, 0) + endif +endfunction + +" Creates quickfix list form given lines and opens the quickfix window if +" errors exists. +" +" a:lines: +" a:jump: if non-zero, jump to the first error. +function l9#quickfix#setMakeResult(lines) + cexpr a:lines + call l9#quickfix#openIfNotEmpty(0, 1) +endfunction + +" Compares quickfix entries for sorting. +function l9#quickfix#compareEntries(e0, e1) + if a:e0.bufnr != a:e1.bufnr + let i0 = bufname(a:e0.bufnr) + let i1 = bufname(a:e1.bufnr) + elseif a:e0.lnum != a:e1.lnum + let i0 = a:e0.lnum + let i1 = a:e1.lnum + elseif a:e0.col != a:e1.col + let i0 = a:e0.col + let i1 = a:e1.col + else + return 0 + endif + return (i0 > i1 ? +1 : -1) +endfunction + +" Sorts quickfix +function l9#quickfix#sort() + call setqflist(sort(getqflist(), 'l9#quickfix#compareEntries'), 'r') +endfunction + +" Highlights Quickfix lines by :sign. +" Inspired by errormarker plugin. +" +" You can customize the highlighting via L9ErrorLine and L9WarningLine +" highlight groups. +function l9#quickfix#placeSign() + let warnings = [] + let errors = [] + for e in filter(getqflist(), 'v:val.valid') + let warning = (e.type ==? 'w' || e.text =~? '^\s*warning:') + call add((warning ? warnings : errors), [e.bufnr, e.lnum]) + endfor + sign unplace * + call l9#placeSign('L9WarningLine', '>>', '', warnings) + call l9#placeSign('L9ErrorLine', '>>', '', errors) +endfunction + +highlight default L9ErrorLine ctermfg=white ctermbg=52 guibg=#5F0000 +highlight default L9WarningLine ctermfg=white ctermbg=17 guibg=#00005F + +" }}}1 +"============================================================================= +" vim: set fdm=marker: + diff --git a/autoload/l9/tempbuffer.vim b/autoload/l9/tempbuffer.vim new file mode 100644 index 0000000..6f11a78 --- /dev/null +++ b/autoload/l9/tempbuffer.vim @@ -0,0 +1,112 @@ +"============================================================================= +" Copyright (C) 2009-2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" TEMPORARY BUFFER {{{1 + +" each key is a buffer name. +let s:dataMap = {} + +" +function s:onBufDelete(bufname) + if exists('s:dataMap[a:bufname].listener.onClose') + call s:dataMap[a:bufname].listener.onClose(s:dataMap[a:bufname].written) + endif + if bufnr('%') == s:dataMap[a:bufname].bufNr && winnr('#') != 0 + " if winnr('#') returns 0, "wincmd p" causes ringing the bell. + wincmd p + endif +endfunction + +" +function s:onBufWriteCmd(bufname) + if !exists('s:dataMap[a:bufname].listener.onWrite') || + \ s:dataMap[a:bufname].listener.onWrite(getline(1, '$')) + setlocal nomodified + let s:dataMap[a:bufname].written = 1 + call l9#tempbuffer#close(a:bufname) + else + endif +endfunction + +" a:bufname: +" a:height: Window height. If 0, default height is used. +" If less than 0, the window becomes full-screen. +" a:listener: +" a:listener.onClose(written) +function l9#tempbuffer#openScratch(bufname, filetype, lines, topleft, vertical, height, listener) + let openCmdPrefix = (a:topleft ? 'topleft ' : '') + \ . (a:vertical ? 'vertical ' : '') + \ . (a:height > 0 ? a:height : '') + if !exists('s:dataMap[a:bufname]') || !bufexists(s:dataMap[a:bufname].bufNr) + execute openCmdPrefix . 'new' + else + call l9#tempbuffer#close(a:bufname) + execute openCmdPrefix . 'split' + execute 'silent ' . s:dataMap[a:bufname].bufNr . 'buffer' + endif + if a:height < 0 + only + endif + setlocal buflisted noswapfile bufhidden=delete modifiable noreadonly buftype=nofile + let &l:filetype = a:filetype + silent file `=a:bufname` + call setline(1, a:lines) + setlocal nomodified + augroup L9TempBuffer + autocmd! * + execute printf('autocmd BufDelete call s:onBufDelete (%s)', string(a:bufname)) + execute printf('autocmd BufWriteCmd nested call s:onBufWriteCmd(%s)', string(a:bufname)) + augroup END + let s:dataMap[a:bufname] = { + \ 'bufNr': bufnr('%'), + \ 'written': 0, + \ 'listener': a:listener, + \ } +endfunction + +" +function l9#tempbuffer#openReadOnly(bufname, filetype, lines, topleft, vertical, height, listener) + call l9#tempbuffer#openScratch(a:bufname, a:filetype, a:lines, a:topleft, a:vertical, a:height, a:listener) + setlocal nomodifiable readonly +endfunction + +" a:listener: +" a:listener.onClose(written) +" a:listener.onWrite(lines) +function l9#tempbuffer#openWritable(bufname, filetype, lines, topleft, vertical, height, listener) + call l9#tempbuffer#openScratch(a:bufname, a:filetype, a:lines, a:topleft, a:vertical, a:height, a:listener) + setlocal buftype=acwrite +endfunction + +" makes specified temp buffer current. +function l9#tempbuffer#moveTo(bufname) + return l9#moveToBufferWindowInCurrentTabpage(s:dataMap[a:bufname].bufNr) || + \ l9#moveToBufferWindowInOtherTabpage(s:dataMap[a:bufname].bufNr) +endfunction + +" +function l9#tempbuffer#close(bufname) + if !l9#tempbuffer#isOpen(a:bufname) + return + endif + execute printf('%dbdelete!', s:dataMap[a:bufname].bufNr) +endfunction + +" +function l9#tempbuffer#isOpen(bufname) + return exists('s:dataMap[a:bufname]') && bufloaded(s:dataMap[a:bufname].bufNr) +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: + diff --git a/autoload/l9/tempvariables.vim b/autoload/l9/tempvariables.vim new file mode 100644 index 0000000..ee847ee --- /dev/null +++ b/autoload/l9/tempvariables.vim @@ -0,0 +1,60 @@ +"============================================================================= +" Copyright (C) 2010 Takeshi NISHIDA +" +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 0, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" TEMPORARY VARIABLES {{{1 + +" +let s:origMap = {} + +" set temporary variables +function l9#tempvariables#set(group, name, value) + if !exists('s:origMap[a:group]') + let s:origMap[a:group] = {} + endif + if !exists('s:origMap[a:group][a:name]') + let s:origMap[a:group][a:name] = eval(a:name) + endif + execute 'let ' . a:name . ' = a:value' +endfunction + +" set temporary variables +function l9#tempvariables#setList(group, variables) + for [name, value] in a:variables + call l9#tempvariables#set(a:group, name, value) + unlet value " to avoid E706 + endfor +endfunction + +" get temporary variables +function l9#tempvariables#getList(group) + if !exists('s:origMap[a:group]') + return [] + endif + return map(keys(s:origMap[a:group]), '[v:val, eval(v:val)]') +endfunction + +" restore original variables and clean up. +function l9#tempvariables#end(group) + if !exists('s:origMap[a:group]') + return + endif + for [name, value] in items(s:origMap[a:group]) + execute 'let ' . name . ' = value' + unlet value " to avoid E706 + endfor + unlet s:origMap[a:group] +endfunction + +" }}}1 +"============================================================================= +" vim: set fdm=marker: + diff --git a/autoload/plug.vim b/autoload/plug.vim new file mode 100644 index 0000000..9ebcf53 --- /dev/null +++ b/autoload/plug.vim @@ -0,0 +1,2504 @@ +" vim-plug: Vim plugin manager +" ============================ +" +" Download plug.vim and put it in ~/.vim/autoload +" +" curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ +" https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim +" +" Edit your .vimrc +" +" call plug#begin('~/.vim/plugged') +" +" " Make sure you use single quotes +" +" " Shorthand notation; fetches https://github.com/junegunn/vim-easy-align +" Plug 'junegunn/vim-easy-align' +" +" " Any valid git URL is allowed +" Plug 'https://github.com/junegunn/vim-github-dashboard.git' +" +" " Multiple Plug commands can be written in a single line using | separators +" Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets' +" +" " On-demand loading +" Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } +" Plug 'tpope/vim-fireplace', { 'for': 'clojure' } +" +" " Using a non-master branch +" Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' } +" +" " Using a tagged release; wildcard allowed (requires git 1.9.2 or above) +" Plug 'fatih/vim-go', { 'tag': '*' } +" +" " Plugin options +" Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' } +" +" " Plugin outside ~/.vim/plugged with post-update hook +" Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } +" +" " Unmanaged plugin (manually installed and updated) +" Plug '~/my-prototype-plugin' +" +" " Initialize plugin system +" call plug#end() +" +" Then reload .vimrc and :PlugInstall to install plugins. +" +" Plug options: +" +"| Option | Description | +"| ----------------------- | ------------------------------------------------ | +"| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use | +"| `rtp` | Subdirectory that contains Vim plugin | +"| `dir` | Custom directory for the plugin | +"| `as` | Use different name for the plugin | +"| `do` | Post-update hook (string or funcref) | +"| `on` | On-demand loading: Commands or ``-mappings | +"| `for` | On-demand loading: File types | +"| `frozen` | Do not update unless explicitly specified | +" +" More information: https://github.com/junegunn/vim-plug +" +" +" Copyright (c) 2017 Junegunn Choi +" +" MIT License +" +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be +" included in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +if exists('g:loaded_plug') + finish +endif +let g:loaded_plug = 1 + +let s:cpo_save = &cpo +set cpo&vim + +let s:plug_src = 'https://github.com/junegunn/vim-plug.git' +let s:plug_tab = get(s:, 'plug_tab', -1) +let s:plug_buf = get(s:, 'plug_buf', -1) +let s:mac_gui = has('gui_macvim') && has('gui_running') +let s:is_win = has('win32') || has('win64') +let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win) +let s:vim8 = has('patch-8.0.0039') && exists('*job_start') +let s:me = resolve(expand(':p')) +let s:base_spec = { 'branch': 'master', 'frozen': 0 } +let s:TYPE = { +\ 'string': type(''), +\ 'list': type([]), +\ 'dict': type({}), +\ 'funcref': type(function('call')) +\ } +let s:loaded = get(s:, 'loaded', {}) +let s:triggers = get(s:, 'triggers', {}) + +function! plug#begin(...) + if a:0 > 0 + let s:plug_home_org = a:1 + let home = s:path(fnamemodify(expand(a:1), ':p')) + elseif exists('g:plug_home') + let home = s:path(g:plug_home) + elseif !empty(&rtp) + let home = s:path(split(&rtp, ',')[0]) . '/plugged' + else + return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.') + endif + if fnamemodify(home, ':t') ==# 'plugin' && fnamemodify(home, ':h') ==# s:first_rtp + return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.') + endif + + let g:plug_home = home + let g:plugs = {} + let g:plugs_order = [] + let s:triggers = {} + + call s:define_commands() + return 1 +endfunction + +function! s:define_commands() + command! -nargs=+ -bar Plug call plug#() + if !executable('git') + return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.') + endif + command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(0, []) + command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(0, []) + command! -nargs=0 -bar -bang PlugClean call s:clean(0) + command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif + command! -nargs=0 -bar PlugStatus call s:status() + command! -nargs=0 -bar PlugDiff call s:diff() + command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(0, ) +endfunction + +function! s:to_a(v) + return type(a:v) == s:TYPE.list ? a:v : [a:v] +endfunction + +function! s:to_s(v) + return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n" +endfunction + +function! s:glob(from, pattern) + return s:lines(globpath(a:from, a:pattern)) +endfunction + +function! s:source(from, ...) + let found = 0 + for pattern in a:000 + for vim in s:glob(a:from, pattern) + execute 'source' s:esc(vim) + let found = 1 + endfor + endfor + return found +endfunction + +function! s:assoc(dict, key, val) + let a:dict[a:key] = add(get(a:dict, a:key, []), a:val) +endfunction + +function! s:ask(message, ...) + call inputsave() + echohl WarningMsg + let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) ')) + echohl None + call inputrestore() + echo "\r" + return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0 +endfunction + +function! s:ask_no_interrupt(...) + try + return call('s:ask', a:000) + catch + return 0 + endtry +endfunction + +function! plug#end() + if !exists('g:plugs') + return s:err('Call plug#begin() first') + endif + + if exists('#PlugLOD') + augroup PlugLOD + autocmd! + augroup END + augroup! PlugLOD + endif + let lod = { 'ft': {}, 'map': {}, 'cmd': {} } + + if exists('g:did_load_filetypes') + filetype off + endif + for name in g:plugs_order + if !has_key(g:plugs, name) + continue + endif + let plug = g:plugs[name] + if get(s:loaded, name, 0) || !has_key(plug, 'on') && !has_key(plug, 'for') + let s:loaded[name] = 1 + continue + endif + + if has_key(plug, 'on') + let s:triggers[name] = { 'map': [], 'cmd': [] } + for cmd in s:to_a(plug.on) + if cmd =~? '^.\+' + if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i')) + call s:assoc(lod.map, cmd, name) + endif + call add(s:triggers[name].map, cmd) + elseif cmd =~# '^[A-Z]' + let cmd = substitute(cmd, '!*$', '', '') + if exists(':'.cmd) != 2 + call s:assoc(lod.cmd, cmd, name) + endif + call add(s:triggers[name].cmd, cmd) + else + call s:err('Invalid `on` option: '.cmd. + \ '. Should start with an uppercase letter or ``.') + endif + endfor + endif + + if has_key(plug, 'for') + let types = s:to_a(plug.for) + if !empty(types) + augroup filetypedetect + call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim') + augroup END + endif + for type in types + call s:assoc(lod.ft, type, name) + endfor + endif + endfor + + for [cmd, names] in items(lod.cmd) + execute printf( + \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "", , , , %s)', + \ cmd, string(cmd), string(names)) + endfor + + for [map, names] in items(lod.map) + for [mode, map_prefix, key_prefix] in + \ [['i', '', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']] + execute printf( + \ '%snoremap %s %s:call lod_map(%s, %s, %s, "%s")', + \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix) + endfor + endfor + + for [ft, names] in items(lod.ft) + augroup PlugLOD + execute printf('autocmd FileType %s call lod_ft(%s, %s)', + \ ft, string(ft), string(names)) + augroup END + endfor + + call s:reorg_rtp() + filetype plugin indent on + if has('vim_starting') + if has('syntax') && !exists('g:syntax_on') + syntax enable + end + else + call s:reload_plugins() + endif +endfunction + +function! s:loaded_names() + return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)') +endfunction + +function! s:load_plugin(spec) + call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim') +endfunction + +function! s:reload_plugins() + for name in s:loaded_names() + call s:load_plugin(g:plugs[name]) + endfor +endfunction + +function! s:trim(str) + return substitute(a:str, '[\/]\+$', '', '') +endfunction + +function! s:version_requirement(val, min) + for idx in range(0, len(a:min) - 1) + let v = get(a:val, idx, 0) + if v < a:min[idx] | return 0 + elseif v > a:min[idx] | return 1 + endif + endfor + return 1 +endfunction + +function! s:git_version_requirement(...) + if !exists('s:git_version') + let s:git_version = map(split(split(s:system('git --version'))[2], '\.'), 'str2nr(v:val)') + endif + return s:version_requirement(s:git_version, a:000) +endfunction + +function! s:progress_opt(base) + return a:base && !s:is_win && + \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' +endfunction + +if s:is_win + function! s:rtp(spec) + return s:path(a:spec.dir . get(a:spec, 'rtp', '')) + endfunction + + function! s:path(path) + return s:trim(substitute(a:path, '/', '\', 'g')) + endfunction + + function! s:dirpath(path) + return s:path(a:path) . '\' + endfunction + + function! s:is_local_plug(repo) + return a:repo =~? '^[a-z]:\|^[%~]' + endfunction +else + function! s:rtp(spec) + return s:dirpath(a:spec.dir . get(a:spec, 'rtp', '')) + endfunction + + function! s:path(path) + return s:trim(a:path) + endfunction + + function! s:dirpath(path) + return substitute(a:path, '[/\\]*$', '/', '') + endfunction + + function! s:is_local_plug(repo) + return a:repo[0] =~ '[/$~]' + endfunction +endif + +function! s:err(msg) + echohl ErrorMsg + echom '[vim-plug] '.a:msg + echohl None +endfunction + +function! s:warn(cmd, msg) + echohl WarningMsg + execute a:cmd 'a:msg' + echohl None +endfunction + +function! s:esc(path) + return escape(a:path, ' ') +endfunction + +function! s:escrtp(path) + return escape(a:path, ' ,') +endfunction + +function! s:remove_rtp() + for name in s:loaded_names() + let rtp = s:rtp(g:plugs[name]) + execute 'set rtp-='.s:escrtp(rtp) + let after = globpath(rtp, 'after') + if isdirectory(after) + execute 'set rtp-='.s:escrtp(after) + endif + endfor +endfunction + +function! s:reorg_rtp() + if !empty(s:first_rtp) + execute 'set rtp-='.s:first_rtp + execute 'set rtp-='.s:last_rtp + endif + + " &rtp is modified from outside + if exists('s:prtp') && s:prtp !=# &rtp + call s:remove_rtp() + unlet! s:middle + endif + + let s:middle = get(s:, 'middle', &rtp) + let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])') + let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)') + let rtp = join(map(rtps, 'escape(v:val, ",")'), ',') + \ . ','.s:middle.',' + \ . join(map(afters, 'escape(v:val, ",")'), ',') + let &rtp = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g') + let s:prtp = &rtp + + if !empty(s:first_rtp) + execute 'set rtp^='.s:first_rtp + execute 'set rtp+='.s:last_rtp + endif +endfunction + +function! s:doautocmd(...) + if exists('#'.join(a:000, '#')) + execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '' : '') join(a:000) + endif +endfunction + +function! s:dobufread(names) + for name in a:names + let path = s:rtp(g:plugs[name]).'/**' + for dir in ['ftdetect', 'ftplugin'] + if len(finddir(dir, path)) + if exists('#BufRead') + doautocmd BufRead + endif + return + endif + endfor + endfor +endfunction + +function! plug#load(...) + if a:0 == 0 + return s:err('Argument missing: plugin name(s) required') + endif + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000 + let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)') + if !empty(unknowns) + let s = len(unknowns) > 1 ? 's' : '' + return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', '))) + end + let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)') + if !empty(unloaded) + for name in unloaded + call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + endfor + call s:dobufread(unloaded) + return 1 + end + return 0 +endfunction + +function! s:remove_triggers(name) + if !has_key(s:triggers, a:name) + return + endif + for cmd in s:triggers[a:name].cmd + execute 'silent! delc' cmd + endfor + for map in s:triggers[a:name].map + execute 'silent! unmap' map + execute 'silent! iunmap' map + endfor + call remove(s:triggers, a:name) +endfunction + +function! s:lod(names, types, ...) + for name in a:names + call s:remove_triggers(name) + let s:loaded[name] = 1 + endfor + call s:reorg_rtp() + + for name in a:names + let rtp = s:rtp(g:plugs[name]) + for dir in a:types + call s:source(rtp, dir.'/**/*.vim') + endfor + if a:0 + if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2)) + execute 'runtime' a:1 + endif + call s:source(rtp, a:2) + endif + call s:doautocmd('User', name) + endfor +endfunction + +function! s:lod_ft(pat, names) + let syn = 'syntax/'.a:pat.'.vim' + call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn) + execute 'autocmd! PlugLOD FileType' a:pat + call s:doautocmd('filetypeplugin', 'FileType') + call s:doautocmd('filetypeindent', 'FileType') +endfunction + +function! s:lod_cmd(cmd, bang, l1, l2, args, names) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) +endfunction + +function! s:lod_map(map, names, with_prefix, prefix) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + let extra = '' + while 1 + let c = getchar(0) + if c == 0 + break + endif + let extra .= nr2char(c) + endwhile + + if a:with_prefix + let prefix = v:count ? v:count : '' + let prefix .= '"'.v:register.a:prefix + if mode(1) == 'no' + if v:operator == 'c' + let prefix = "\" . prefix + endif + let prefix .= v:operator + endif + call feedkeys(prefix, 'n') + endif + call feedkeys(substitute(a:map, '^', "\", '') . extra) +endfunction + +function! plug#(repo, ...) + if a:0 > 1 + return s:err('Invalid number of arguments (1..2)') + endif + + try + let repo = s:trim(a:repo) + let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec + let name = get(opts, 'as', fnamemodify(repo, ':t:s?\.git$??')) + let spec = extend(s:infer_properties(name, repo), opts) + if !has_key(g:plugs, name) + call add(g:plugs_order, name) + endif + let g:plugs[name] = spec + let s:loaded[name] = get(s:loaded, name, 0) + catch + return s:err(v:exception) + endtry +endfunction + +function! s:parse_options(arg) + let opts = copy(s:base_spec) + let type = type(a:arg) + if type == s:TYPE.string + let opts.tag = a:arg + elseif type == s:TYPE.dict + call extend(opts, a:arg) + if has_key(opts, 'dir') + let opts.dir = s:dirpath(expand(opts.dir)) + endif + else + throw 'Invalid argument type (expected: string or dictionary)' + endif + return opts +endfunction + +function! s:infer_properties(name, repo) + let repo = a:repo + if s:is_local_plug(repo) + return { 'dir': s:dirpath(expand(repo)) } + else + if repo =~ ':' + let uri = repo + else + if repo !~ '/' + throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo) + endif + let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git') + let uri = printf(fmt, repo) + endif + return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri } + endif +endfunction + +function! s:install(force, names) + call s:update_impl(0, a:force, a:names) +endfunction + +function! s:update(force, names) + call s:update_impl(1, a:force, a:names) +endfunction + +function! plug#helptags() + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + for spec in values(g:plugs) + let docd = join([s:rtp(spec), 'doc'], '/') + if isdirectory(docd) + silent! execute 'helptags' s:esc(docd) + endif + endfor + return 1 +endfunction + +function! s:syntax() + syntax clear + syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber + syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX + syn match plugNumber /[0-9]\+[0-9.]*/ contained + syn match plugBracket /[[\]]/ contained + syn match plugX /x/ contained + syn match plugDash /^-/ + syn match plugPlus /^+/ + syn match plugStar /^*/ + syn match plugMessage /\(^- \)\@<=.*/ + syn match plugName /\(^- \)\@<=[^ ]*:/ + syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/ + syn match plugTag /(tag: [^)]\+)/ + syn match plugInstall /\(^+ \)\@<=[^:]*/ + syn match plugUpdate /\(^* \)\@<=[^:]*/ + syn match plugCommit /^ \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag + syn match plugEdge /^ \X\+$/ + syn match plugEdge /^ \X*/ contained nextgroup=plugSha + syn match plugSha /[0-9a-f]\{7,9}/ contained + syn match plugRelDate /([^)]*)$/ contained + syn match plugNotLoaded /(not loaded)$/ + syn match plugError /^x.*/ + syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/ + syn match plugH2 /^.*:\n-\+$/ + syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean + hi def link plug1 Title + hi def link plug2 Repeat + hi def link plugH2 Type + hi def link plugX Exception + hi def link plugBracket Structure + hi def link plugNumber Number + + hi def link plugDash Special + hi def link plugPlus Constant + hi def link plugStar Boolean + + hi def link plugMessage Function + hi def link plugName Label + hi def link plugInstall Function + hi def link plugUpdate Type + + hi def link plugError Error + hi def link plugDeleted Ignore + hi def link plugRelDate Comment + hi def link plugEdge PreProc + hi def link plugSha Identifier + hi def link plugTag Constant + + hi def link plugNotLoaded Comment +endfunction + +function! s:lpad(str, len) + return a:str . repeat(' ', a:len - len(a:str)) +endfunction + +function! s:lines(msg) + return split(a:msg, "[\r\n]") +endfunction + +function! s:lastline(msg) + return get(s:lines(a:msg), -1, '') +endfunction + +function! s:new_window() + execute get(g:, 'plug_window', 'vertical topleft new') +endfunction + +function! s:plug_window_exists() + let buflist = tabpagebuflist(s:plug_tab) + return !empty(buflist) && index(buflist, s:plug_buf) >= 0 +endfunction + +function! s:switch_in() + if !s:plug_window_exists() + return 0 + endif + + if winbufnr(0) != s:plug_buf + let s:pos = [tabpagenr(), winnr(), winsaveview()] + execute 'normal!' s:plug_tab.'gt' + let winnr = bufwinnr(s:plug_buf) + execute winnr.'wincmd w' + call add(s:pos, winsaveview()) + else + let s:pos = [winsaveview()] + endif + + setlocal modifiable + return 1 +endfunction + +function! s:switch_out(...) + call winrestview(s:pos[-1]) + setlocal nomodifiable + if a:0 > 0 + execute a:1 + endif + + if len(s:pos) > 1 + execute 'normal!' s:pos[0].'gt' + execute s:pos[1] 'wincmd w' + call winrestview(s:pos[2]) + endif +endfunction + +function! s:finish_bindings() + nnoremap R :call retry() + nnoremap D :PlugDiff + nnoremap S :PlugStatus + nnoremap U :call status_update() + xnoremap U :call status_update() + nnoremap ]] :silent! call section('') + nnoremap [[ :silent! call section('b') +endfunction + +function! s:prepare(...) + if empty(getcwd()) + throw 'Invalid current working directory. Cannot proceed.' + endif + + for evar in ['$GIT_DIR', '$GIT_WORK_TREE'] + if exists(evar) + throw evar.' detected. Cannot proceed.' + endif + endfor + + call s:job_abort() + if s:switch_in() + if b:plug_preview == 1 + pc + endif + enew + else + call s:new_window() + endif + + nnoremap q :if b:plug_preview==1pcendifbd + if a:0 == 0 + call s:finish_bindings() + endif + let b:plug_preview = -1 + let s:plug_tab = tabpagenr() + let s:plug_buf = winbufnr(0) + call s:assign_name() + + for k in ['', 'L', 'o', 'X', 'd', 'dd'] + execute 'silent! unmap ' k + endfor + setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell + setf vim-plug + if exists('g:syntax_on') + call s:syntax() + endif +endfunction + +function! s:assign_name() + " Assign buffer name + let prefix = '[Plugins]' + let name = prefix + let idx = 2 + while bufexists(name) + let name = printf('%s (%s)', prefix, idx) + let idx = idx + 1 + endwhile + silent! execute 'f' fnameescape(name) +endfunction + +function! s:chsh(swap) + let prev = [&shell, &shellcmdflag, &shellredir] + if s:is_win + set shell=cmd.exe shellcmdflag=/c shellredir=>%s\ 2>&1 + elseif a:swap + set shell=sh shellredir=>%s\ 2>&1 + endif + return prev +endfunction + +function! s:bang(cmd, ...) + try + let [sh, shellcmdflag, shrd] = s:chsh(a:0) + " FIXME: Escaping is incomplete. We could use shellescape with eval, + " but it won't work on Windows. + let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd + if s:is_win + let batchfile = tempname().'.bat' + call writefile(['@echo off', cmd], batchfile) + let cmd = batchfile + endif + let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%') + execute "normal! :execute g:_plug_bang\\" + finally + unlet g:_plug_bang + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win + call delete(batchfile) + endif + endtry + return v:shell_error ? 'Exit status: ' . v:shell_error : '' +endfunction + +function! s:regress_bar() + let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '') + call s:progress_bar(2, bar, len(bar)) +endfunction + +function! s:is_updated(dir) + return !empty(s:system_chomp('git log --pretty=format:"%h" "HEAD...HEAD@{1}"', a:dir)) +endfunction + +function! s:do(pull, force, todo) + for [name, spec] in items(a:todo) + if !isdirectory(spec.dir) + continue + endif + let installed = has_key(s:update.new, name) + let updated = installed ? 0 : + \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir)) + if a:force || installed || updated + execute 'cd' s:esc(spec.dir) + call append(3, '- Post-update hook for '. name .' ... ') + let error = '' + let type = type(spec.do) + if type == s:TYPE.string + if spec.do[0] == ':' + if !get(s:loaded, name, 0) + let s:loaded[name] = 1 + call s:reorg_rtp() + endif + call s:load_plugin(spec) + try + execute spec.do[1:] + catch + let error = v:exception + endtry + if !s:plug_window_exists() + cd - + throw 'Warning: vim-plug was terminated by the post-update hook of '.name + endif + else + let error = s:bang(spec.do) + endif + elseif type == s:TYPE.funcref + try + let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged') + call spec.do({ 'name': name, 'status': status, 'force': a:force }) + catch + let error = v:exception + endtry + else + let error = 'Invalid hook type' + endif + call s:switch_in() + call setline(4, empty(error) ? (getline(4) . 'OK') + \ : ('x' . getline(4)[1:] . error)) + if !empty(error) + call add(s:update.errors, name) + call s:regress_bar() + endif + cd - + endif + endfor +endfunction + +function! s:hash_match(a, b) + return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0 +endfunction + +function! s:checkout(spec) + let sha = a:spec.commit + let output = s:system('git rev-parse HEAD', a:spec.dir) + if !v:shell_error && !s:hash_match(sha, s:lines(output)[0]) + let output = s:system( + \ 'git fetch --depth 999999 && git checkout '.s:esc(sha).' --', a:spec.dir) + endif + return output +endfunction + +function! s:finish(pull) + let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen')) + if new_frozen + let s = new_frozen > 1 ? 's' : '' + call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s)) + endif + call append(3, '- Finishing ... ') | 4 + redraw + call plug#helptags() + call plug#end() + call setline(4, getline(4) . 'Done!') + redraw + let msgs = [] + if !empty(s:update.errors) + call add(msgs, "Press 'R' to retry.") + endif + if a:pull && len(s:update.new) < len(filter(getline(5, '$'), + \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'")) + call add(msgs, "Press 'D' to see the updated changes.") + endif + echo join(msgs, ' ') + call s:finish_bindings() +endfunction + +function! s:retry() + if empty(s:update.errors) + return + endif + echo + call s:update_impl(s:update.pull, s:update.force, + \ extend(copy(s:update.errors), [s:update.threads])) +endfunction + +function! s:is_managed(name) + return has_key(g:plugs[a:name], 'uri') +endfunction + +function! s:names(...) + return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')) +endfunction + +function! s:check_ruby() + silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'") + if !exists('g:plug_ruby') + redraw! + return s:warn('echom', 'Warning: Ruby interface is broken') + endif + let ruby_version = split(g:plug_ruby, '\.') + unlet g:plug_ruby + return s:version_requirement(ruby_version, [1, 8, 7]) +endfunction + +function! s:update_impl(pull, force, args) abort + let sync = index(a:args, '--sync') >= 0 || has('vim_starting') + let args = filter(copy(a:args), 'v:val != "--sync"') + let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? + \ remove(args, -1) : get(g:, 'plug_threads', 16) + + let managed = filter(copy(g:plugs), 's:is_managed(v:key)') + let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') : + \ filter(managed, 'index(args, v:key) >= 0') + + if empty(todo) + return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install')) + endif + + if !s:is_win && s:git_version_requirement(2, 3) + let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : '' + let $GIT_TERMINAL_PROMPT = 0 + for plug in values(todo) + let plug.uri = substitute(plug.uri, + \ '^https://git::@github\.com', 'https://github.com', '') + endfor + endif + + if !isdirectory(g:plug_home) + try + call mkdir(g:plug_home, 'p') + catch + return s:err(printf('Invalid plug directory: %s. '. + \ 'Try to call plug#begin with a valid directory', g:plug_home)) + endtry + endif + + if has('nvim') && !exists('*jobwait') && threads > 1 + call s:warn('echom', '[vim-plug] Update Neovim for parallel installer') + endif + + let use_job = s:nvim || s:vim8 + let python = (has('python') || has('python3')) && !use_job + let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby() + + let s:update = { + \ 'start': reltime(), + \ 'all': todo, + \ 'todo': copy(todo), + \ 'errors': [], + \ 'pull': a:pull, + \ 'force': a:force, + \ 'new': {}, + \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1, + \ 'bar': '', + \ 'fin': 0 + \ } + + call s:prepare(1) + call append(0, ['', '']) + normal! 2G + silent! redraw + + let s:clone_opt = get(g:, 'plug_shallow', 1) ? + \ '--depth 1' . (s:git_version_requirement(1, 7, 10) ? ' --no-single-branch' : '') : '' + + if has('win32unix') + let s:clone_opt .= ' -c core.eol=lf -c core.autocrlf=input' + endif + + " Python version requirement (>= 2.7) + if python && !has('python3') && !ruby && !use_job && s:update.threads > 1 + redir => pyv + silent python import platform; print platform.python_version() + redir END + let python = s:version_requirement( + \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6]) + endif + + if (python || ruby) && s:update.threads > 1 + try + let imd = &imd + if s:mac_gui + set noimd + endif + if ruby + call s:update_ruby() + else + call s:update_python() + endif + catch + let lines = getline(4, '$') + let printed = {} + silent! 4,$d _ + for line in lines + let name = s:extract_name(line, '.', '') + if empty(name) || !has_key(printed, name) + call append('$', line) + if !empty(name) + let printed[name] = 1 + if line[0] == 'x' && index(s:update.errors, name) < 0 + call add(s:update.errors, name) + end + endif + endif + endfor + finally + let &imd = imd + call s:update_finish() + endtry + else + call s:update_vim() + while use_job && sync + sleep 100m + if s:update.fin + break + endif + endwhile + endif +endfunction + +function! s:log4(name, msg) + call setline(4, printf('- %s (%s)', a:msg, a:name)) + redraw +endfunction + +function! s:update_finish() + if exists('s:git_terminal_prompt') + let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt + endif + if s:switch_in() + call append(3, '- Updating ...') | 4 + for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))')) + let [pos, _] = s:logpos(name) + if !pos + continue + endif + if has_key(spec, 'commit') + call s:log4(name, 'Checking out '.spec.commit) + let out = s:checkout(spec) + elseif has_key(spec, 'tag') + let tag = spec.tag + if tag =~ '\*' + let tags = s:lines(s:system('git tag --list '.s:shellesc(tag).' --sort -version:refname 2>&1', spec.dir)) + if !v:shell_error && !empty(tags) + let tag = tags[0] + call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag)) + call append(3, '') + endif + endif + call s:log4(name, 'Checking out '.tag) + let out = s:system('git checkout -q '.s:esc(tag).' -- 2>&1', spec.dir) + else + let branch = s:esc(get(spec, 'branch', 'master')) + call s:log4(name, 'Merging origin/'.branch) + let out = s:system('git checkout -q '.branch.' -- 2>&1' + \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only origin/'.branch.' 2>&1')), spec.dir) + endif + if !v:shell_error && filereadable(spec.dir.'/.gitmodules') && + \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir)) + call s:log4(name, 'Updating submodules. This may take a while.') + let out .= s:bang('git submodule update --init --recursive 2>&1', spec.dir) + endif + let msg = s:format_message(v:shell_error ? 'x': '-', name, out) + if v:shell_error + call add(s:update.errors, name) + call s:regress_bar() + silent execute pos 'd _' + call append(4, msg) | 4 + elseif !empty(out) + call setline(pos, msg[0]) + endif + redraw + endfor + silent 4 d _ + try + call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, "do")')) + catch + call s:warn('echom', v:exception) + call s:warn('echo', '') + return + endtry + call s:finish(s:update.pull) + call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.') + call s:switch_out('normal! gg') + endif +endfunction + +function! s:job_abort() + if (!s:nvim && !s:vim8) || !exists('s:jobs') + return + endif + + for [name, j] in items(s:jobs) + if s:nvim + silent! call jobstop(j.jobid) + elseif s:vim8 + silent! call job_stop(j.jobid) + endif + if j.new + call s:system('rm -rf ' . s:shellesc(g:plugs[name].dir)) + endif + endfor + let s:jobs = {} +endfunction + +function! s:last_non_empty_line(lines) + let len = len(a:lines) + for idx in range(len) + let line = a:lines[len-idx-1] + if !empty(line) + return line + endif + endfor + return '' +endfunction + +function! s:job_out_cb(self, data) abort + let self = a:self + let data = remove(self.lines, -1) . a:data + let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]') + call extend(self.lines, lines) + " To reduce the number of buffer updates + let self.tick = get(self, 'tick', -1) + 1 + if !self.running || self.tick % len(s:jobs) == 0 + let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-') + let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines) + call s:log(bullet, self.name, result) + endif +endfunction + +function! s:job_exit_cb(self, data) abort + let a:self.running = 0 + let a:self.error = a:data != 0 + call s:reap(a:self.name) + call s:tick() +endfunction + +function! s:job_cb(fn, job, ch, data) + if !s:plug_window_exists() " plug window closed + return s:job_abort() + endif + call call(a:fn, [a:job, a:data]) +endfunction + +function! s:nvim_cb(job_id, data, event) dict abort + return a:event == 'stdout' ? + \ s:job_cb('s:job_out_cb', self, 0, join(a:data, "\n")) : + \ s:job_cb('s:job_exit_cb', self, 0, a:data) +endfunction + +function! s:spawn(name, cmd, opts) + let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''], + \ 'batchfile': (s:is_win && (s:nvim || s:vim8)) ? tempname().'.bat' : '', + \ 'new': get(a:opts, 'new', 0) } + let s:jobs[a:name] = job + let cmd = has_key(a:opts, 'dir') ? s:with_cd(a:cmd, a:opts.dir) : a:cmd + if !empty(job.batchfile) + call writefile(['@echo off', cmd], job.batchfile) + let cmd = job.batchfile + endif + let argv = add(s:is_win ? ['cmd', '/c'] : ['sh', '-c'], cmd) + + if s:nvim + call extend(job, { + \ 'on_stdout': function('s:nvim_cb'), + \ 'on_exit': function('s:nvim_cb'), + \ }) + let jid = jobstart(argv, job) + if jid > 0 + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = [jid < 0 ? argv[0].' is not executable' : + \ 'Invalid arguments (or job table is full)'] + endif + elseif s:vim8 + let jid = job_start(s:is_win ? join(argv, ' ') : argv, { + \ 'out_cb': function('s:job_cb', ['s:job_out_cb', job]), + \ 'exit_cb': function('s:job_cb', ['s:job_exit_cb', job]), + \ 'out_mode': 'raw' + \}) + if job_status(jid) == 'run' + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = ['Failed to start job'] + endif + else + let job.lines = s:lines(call('s:system', [cmd])) + let job.error = v:shell_error != 0 + let job.running = 0 + endif +endfunction + +function! s:reap(name) + let job = s:jobs[a:name] + if job.error + call add(s:update.errors, a:name) + elseif get(job, 'new', 0) + let s:update.new[a:name] = 1 + endif + let s:update.bar .= job.error ? 'x' : '=' + + let bullet = job.error ? 'x' : '-' + let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines) + call s:log(bullet, a:name, empty(result) ? 'OK' : result) + call s:bar() + + if has_key(job, 'batchfile') && !empty(job.batchfile) + call delete(job.batchfile) + endif + call remove(s:jobs, a:name) +endfunction + +function! s:bar() + if s:switch_in() + let total = len(s:update.all) + call setline(1, (s:update.pull ? 'Updating' : 'Installing'). + \ ' plugins ('.len(s:update.bar).'/'.total.')') + call s:progress_bar(2, s:update.bar, total) + call s:switch_out() + endif +endfunction + +function! s:logpos(name) + for i in range(4, line('$')) + if getline(i) =~# '^[-+x*] '.a:name.':' + for j in range(i + 1, line('$')) + if getline(j) !~ '^ ' + return [i, j - 1] + endif + endfor + return [i, i] + endif + endfor + return [0, 0] +endfunction + +function! s:log(bullet, name, lines) + if s:switch_in() + let [b, e] = s:logpos(a:name) + if b > 0 + silent execute printf('%d,%d d _', b, e) + if b > winheight('.') + let b = 4 + endif + else + let b = 4 + endif + " FIXME For some reason, nomodifiable is set after :d in vim8 + setlocal modifiable + call append(b - 1, s:format_message(a:bullet, a:name, a:lines)) + call s:switch_out() + endif +endfunction + +function! s:update_vim() + let s:jobs = {} + + call s:bar() + call s:tick() +endfunction + +function! s:tick() + let pull = s:update.pull + let prog = s:progress_opt(s:nvim || s:vim8) +while 1 " Without TCO, Vim stack is bound to explode + if empty(s:update.todo) + if empty(s:jobs) && !s:update.fin + call s:update_finish() + let s:update.fin = 1 + endif + return + endif + + let name = keys(s:update.todo)[0] + let spec = remove(s:update.todo, name) + let new = !isdirectory(spec.dir) + + call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') + redraw + + let has_tag = has_key(spec, 'tag') + if !new + let [error, _] = s:git_validate(spec, 0) + if empty(error) + if pull + let fetch_opt = (has_tag && !empty(globpath(spec.dir, '.git/shallow'))) ? '--depth 99999999' : '' + call s:spawn(name, printf('git fetch %s %s 2>&1', fetch_opt, prog), { 'dir': spec.dir }) + else + let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 } + endif + else + let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 } + endif + else + call s:spawn(name, + \ printf('git clone %s %s %s %s 2>&1', + \ has_tag ? '' : s:clone_opt, + \ prog, + \ s:shellesc(spec.uri), + \ s:shellesc(s:trim(spec.dir))), { 'new': 1 }) + endif + + if !s:jobs[name].running + call s:reap(name) + endif + if len(s:jobs) >= s:update.threads + break + endif +endwhile +endfunction + +function! s:update_python() +let py_exe = has('python') ? 'python' : 'python3' +execute py_exe "<< EOF" +import datetime +import functools +import os +try: + import queue +except ImportError: + import Queue as queue +import random +import re +import shutil +import signal +import subprocess +import tempfile +import threading as thr +import time +import traceback +import vim + +G_NVIM = vim.eval("has('nvim')") == '1' +G_PULL = vim.eval('s:update.pull') == '1' +G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1 +G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)')) +G_CLONE_OPT = vim.eval('s:clone_opt') +G_PROGRESS = vim.eval('s:progress_opt(1)') +G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) +G_STOP = thr.Event() +G_IS_WIN = vim.eval('s:is_win') == '1' + +class PlugError(Exception): + def __init__(self, msg): + self.msg = msg +class CmdTimedOut(PlugError): + pass +class CmdFailed(PlugError): + pass +class InvalidURI(PlugError): + pass +class Action(object): + INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] + +class Buffer(object): + def __init__(self, lock, num_plugs, is_pull): + self.bar = '' + self.event = 'Updating' if is_pull else 'Installing' + self.lock = lock + self.maxy = int(vim.eval('winheight(".")')) + self.num_plugs = num_plugs + + def __where(self, name): + """ Find first line with name in current buffer. Return line num. """ + found, lnum = False, 0 + matcher = re.compile('^[-+x*] {0}:'.format(name)) + for line in vim.current.buffer: + if matcher.search(line) is not None: + found = True + break + lnum += 1 + + if not found: + lnum = -1 + return lnum + + def header(self): + curbuf = vim.current.buffer + curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs) + + num_spaces = self.num_plugs - len(self.bar) + curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ') + + with self.lock: + vim.command('normal! 2G') + vim.command('redraw') + + def write(self, action, name, lines): + first, rest = lines[0], lines[1:] + msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] + msg.extend([' ' + line for line in rest]) + + try: + if action == Action.ERROR: + self.bar += 'x' + vim.command("call add(s:update.errors, '{0}')".format(name)) + elif action == Action.DONE: + self.bar += '=' + + curbuf = vim.current.buffer + lnum = self.__where(name) + if lnum != -1: # Found matching line num + del curbuf[lnum] + if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): + lnum = 3 + else: + lnum = 3 + curbuf.append(msg, lnum) + + self.header() + except vim.error: + pass + +class Command(object): + CD = 'cd /d' if G_IS_WIN else 'cd' + + def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None): + self.cmd = cmd + if cmd_dir: + self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd) + self.timeout = timeout + self.callback = cb if cb else (lambda msg: None) + self.clean = clean if clean else (lambda: None) + self.proc = None + + @property + def alive(self): + """ Returns true only if command still running. """ + return self.proc and self.proc.poll() is None + + def execute(self, ntries=3): + """ Execute the command with ntries if CmdTimedOut. + Returns the output of the command if no Exception. + """ + attempt, finished, limit = 0, False, self.timeout + + while not finished: + try: + attempt += 1 + result = self.try_command() + finished = True + return result + except CmdTimedOut: + if attempt != ntries: + self.notify_retry() + self.timeout += limit + else: + raise + + def notify_retry(self): + """ Retry required for command, notify user. """ + for count in range(3, 0, -1): + if G_STOP.is_set(): + raise KeyboardInterrupt + msg = 'Timeout. Will retry in {0} second{1} ...'.format( + count, 's' if count != 1 else '') + self.callback([msg]) + time.sleep(1) + self.callback(['Retrying ...']) + + def try_command(self): + """ Execute a cmd & poll for callback. Returns list of output. + Raises CmdFailed -> return code for Popen isn't 0 + Raises CmdTimedOut -> command exceeded timeout without new output + """ + first_line = True + + try: + tfile = tempfile.NamedTemporaryFile(mode='w+b') + preexec_fn = not G_IS_WIN and os.setsid or None + self.proc = subprocess.Popen(self.cmd, stdout=tfile, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, shell=True, + preexec_fn=preexec_fn) + thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,)) + thrd.start() + + thread_not_started = True + while thread_not_started: + try: + thrd.join(0.1) + thread_not_started = False + except RuntimeError: + pass + + while self.alive: + if G_STOP.is_set(): + raise KeyboardInterrupt + + if first_line or random.random() < G_LOG_PROB: + first_line = False + line = '' if G_IS_WIN else nonblock_read(tfile.name) + if line: + self.callback([line]) + + time_diff = time.time() - os.path.getmtime(tfile.name) + if time_diff > self.timeout: + raise CmdTimedOut(['Timeout!']) + + thrd.join(0.5) + + tfile.seek(0) + result = [line.decode('utf-8', 'replace').rstrip() for line in tfile] + + if self.proc.returncode != 0: + raise CmdFailed([''] + result) + + return result + except: + self.terminate() + raise + + def terminate(self): + """ Terminate process and cleanup. """ + if self.alive: + if G_IS_WIN: + os.kill(self.proc.pid, signal.SIGINT) + else: + os.killpg(self.proc.pid, signal.SIGTERM) + self.clean() + +class Plugin(object): + def __init__(self, name, args, buf_q, lock): + self.name = name + self.args = args + self.buf_q = buf_q + self.lock = lock + self.tag = args.get('tag', 0) + + def manage(self): + try: + if os.path.exists(self.args['dir']): + self.update() + else: + self.install() + with self.lock: + thread_vim_command("let s:update.new['{0}'] = 1".format(self.name)) + except PlugError as exc: + self.write(Action.ERROR, self.name, exc.msg) + except KeyboardInterrupt: + G_STOP.set() + self.write(Action.ERROR, self.name, ['Interrupted!']) + except: + # Any exception except those above print stack trace + msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip()) + self.write(Action.ERROR, self.name, msg.split('\n')) + raise + + def install(self): + target = self.args['dir'] + if target[-1] == '\\': + target = target[0:-1] + + def clean(target): + def _clean(): + try: + shutil.rmtree(target) + except OSError: + pass + return _clean + + self.write(Action.INSTALL, self.name, ['Installing ...']) + callback = functools.partial(self.write, Action.INSTALL, self.name) + cmd = 'git clone {0} {1} {2} {3} 2>&1'.format( + '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], + esc(target)) + com = Command(cmd, None, G_TIMEOUT, callback, clean(target)) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + + def repo_uri(self): + cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url' + command = Command(cmd, self.args['dir'], G_TIMEOUT,) + result = command.execute(G_RETRIES) + return result[-1] + + def update(self): + actual_uri = self.repo_uri() + expect_uri = self.args['uri'] + regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$') + ma = regex.match(actual_uri) + mb = regex.match(expect_uri) + if ma is None or mb is None or ma.groups() != mb.groups(): + msg = ['', + 'Invalid URI: {0}'.format(actual_uri), + 'Expected {0}'.format(expect_uri), + 'PlugClean required.'] + raise InvalidURI(msg) + + if G_PULL: + self.write(Action.UPDATE, self.name, ['Updating ...']) + callback = functools.partial(self.write, Action.UPDATE, self.name) + fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else '' + cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS) + com = Command(cmd, self.args['dir'], G_TIMEOUT, callback) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + else: + self.write(Action.DONE, self.name, ['Already installed']) + + def write(self, action, name, msg): + self.buf_q.put((action, name, msg)) + +class PlugThread(thr.Thread): + def __init__(self, tname, args): + super(PlugThread, self).__init__() + self.tname = tname + self.args = args + + def run(self): + thr.current_thread().name = self.tname + buf_q, work_q, lock = self.args + + try: + while not G_STOP.is_set(): + name, args = work_q.get_nowait() + plug = Plugin(name, args, buf_q, lock) + plug.manage() + work_q.task_done() + except queue.Empty: + pass + +class RefreshThread(thr.Thread): + def __init__(self, lock): + super(RefreshThread, self).__init__() + self.lock = lock + self.running = True + + def run(self): + while self.running: + with self.lock: + thread_vim_command('noautocmd normal! a') + time.sleep(0.33) + + def stop(self): + self.running = False + +if G_NVIM: + def thread_vim_command(cmd): + vim.session.threadsafe_call(lambda: vim.command(cmd)) +else: + def thread_vim_command(cmd): + vim.command(cmd) + +def esc(name): + return '"' + name.replace('"', '\"') + '"' + +def nonblock_read(fname): + """ Read a file with nonblock flag. Return the last line. """ + fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) + buf = os.read(fread, 100000).decode('utf-8', 'replace') + os.close(fread) + + line = buf.rstrip('\r\n') + left = max(line.rfind('\r'), line.rfind('\n')) + if left != -1: + left += 1 + line = line[left:] + + return line + +def main(): + thr.current_thread().name = 'main' + nthreads = int(vim.eval('s:update.threads')) + plugs = vim.eval('s:update.todo') + mac_gui = vim.eval('s:mac_gui') == '1' + + lock = thr.Lock() + buf = Buffer(lock, len(plugs), G_PULL) + buf_q, work_q = queue.Queue(), queue.Queue() + for work in plugs.items(): + work_q.put(work) + + start_cnt = thr.active_count() + for num in range(nthreads): + tname = 'PlugT-{0:02}'.format(num) + thread = PlugThread(tname, (buf_q, work_q, lock)) + thread.start() + if mac_gui: + rthread = RefreshThread(lock) + rthread.start() + + while not buf_q.empty() or thr.active_count() != start_cnt: + try: + action, name, msg = buf_q.get(True, 0.25) + buf.write(action, name, ['OK'] if not msg else msg) + buf_q.task_done() + except queue.Empty: + pass + except KeyboardInterrupt: + G_STOP.set() + + if mac_gui: + rthread.stop() + rthread.join() + +main() +EOF +endfunction + +function! s:update_ruby() + ruby << EOF + module PlugStream + SEP = ["\r", "\n", nil] + def get_line + buffer = '' + loop do + char = readchar rescue return + if SEP.include? char.chr + buffer << $/ + break + else + buffer << char + end + end + buffer + end + end unless defined?(PlugStream) + + def esc arg + %["#{arg.gsub('"', '\"')}"] + end + + def killall pid + pids = [pid] + if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM + pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil } + else + unless `which pgrep 2> /dev/null`.empty? + children = pids + until children.empty? + children = children.map { |pid| + `pgrep -P #{pid}`.lines.map { |l| l.chomp } + }.flatten + pids += children + end + end + pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil } + end + end + + def compare_git_uri a, b + regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$} + regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1) + end + + require 'thread' + require 'fileutils' + require 'timeout' + running = true + iswin = VIM::evaluate('s:is_win').to_i == 1 + pull = VIM::evaluate('s:update.pull').to_i == 1 + base = VIM::evaluate('g:plug_home') + all = VIM::evaluate('s:update.todo') + limit = VIM::evaluate('get(g:, "plug_timeout", 60)') + tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1 + nthr = VIM::evaluate('s:update.threads').to_i + maxy = VIM::evaluate('winheight(".")').to_i + vim7 = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/ + cd = iswin ? 'cd /d' : 'cd' + tot = VIM::evaluate('len(s:update.todo)') || 0 + bar = '' + skip = 'Already installed' + mtx = Mutex.new + take1 = proc { mtx.synchronize { running && all.shift } } + logh = proc { + cnt = bar.length + $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" + $curbuf[2] = '[' + bar.ljust(tot) + ']' + VIM::command('normal! 2G') + VIM::command('redraw') + } + where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } } + log = proc { |name, result, type| + mtx.synchronize do + ing = ![true, false].include?(type) + bar += type ? '=' : 'x' unless ing + b = case type + when :install then '+' when :update then '*' + when true, nil then '-' else + VIM::command("call add(s:update.errors, '#{name}')") + 'x' + end + result = + if type || type.nil? + ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"] + elsif result =~ /^Interrupted|^Timeout/ + ["#{b} #{name}: #{result}"] + else + ["#{b} #{name}"] + result.lines.map { |l| " " << l } + end + if lnum = where.call(name) + $curbuf.delete lnum + lnum = 4 if ing && lnum > maxy + end + result.each_with_index do |line, offset| + $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp) + end + logh.call + end + } + bt = proc { |cmd, name, type, cleanup| + tried = timeout = 0 + begin + tried += 1 + timeout += limit + fd = nil + data = '' + if iswin + Timeout::timeout(timeout) do + tmp = VIM::evaluate('tempname()') + system("(#{cmd}) > #{tmp}") + data = File.read(tmp).chomp + File.unlink tmp rescue nil + end + else + fd = IO.popen(cmd).extend(PlugStream) + first_line = true + log_prob = 1.0 / nthr + while line = Timeout::timeout(timeout) { fd.get_line } + data << line + log.call name, line.chomp, type if name && (first_line || rand < log_prob) + first_line = false + end + fd.close + end + [$? == 0, data.chomp] + rescue Timeout::Error, Interrupt => e + if fd && !fd.closed? + killall fd.pid + fd.close + end + cleanup.call if cleanup + if e.is_a?(Timeout::Error) && tried < tries + 3.downto(1) do |countdown| + s = countdown > 1 ? 's' : '' + log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type + sleep 1 + end + log.call name, 'Retrying ...', type + retry + end + [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"] + end + } + main = Thread.current + threads = [] + watcher = Thread.new { + if vim7 + while VIM::evaluate('getchar(1)') + sleep 0.1 + end + else + require 'io/console' # >= Ruby 1.9 + nil until IO.console.getch == 3.chr + end + mtx.synchronize do + running = false + threads.each { |t| t.raise Interrupt } unless vim7 + end + threads.each { |t| t.join rescue nil } + main.kill + } + refresh = Thread.new { + while true + mtx.synchronize do + break unless running + VIM::command('noautocmd normal! a') + end + sleep 0.2 + end + } if VIM::evaluate('s:mac_gui') == 1 + + clone_opt = VIM::evaluate('s:clone_opt') + progress = VIM::evaluate('s:progress_opt(1)') + nthr.times do + mtx.synchronize do + threads << Thread.new { + while pair = take1.call + name = pair.first + dir, uri, tag = pair.last.values_at *%w[dir uri tag] + exists = File.directory? dir + ok, result = + if exists + chdir = "#{cd} #{iswin ? dir : esc(dir)}" + ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil + current_uri = data.lines.to_a.last + if !ret + if data =~ /^Interrupted|^Timeout/ + [false, data] + else + [false, [data.chomp, "PlugClean required."].join($/)] + end + elsif !compare_git_uri(current_uri, uri) + [false, ["Invalid URI: #{current_uri}", + "Expected: #{uri}", + "PlugClean required."].join($/)] + else + if pull + log.call name, 'Updating ...', :update + fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : '' + bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil + else + [true, skip] + end + end + else + d = esc dir.sub(%r{[\\/]+$}, '') + log.call name, 'Installing ...', :install + bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc { + FileUtils.rm_rf dir + } + end + mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok + log.call name, result, ok + end + } if running + end + end + threads.each { |t| t.join rescue nil } + logh.call + refresh.kill if refresh + watcher.kill +EOF +endfunction + +function! s:shellesc_cmd(arg) + let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g') + let escaped = substitute(escaped, '%', '%%', 'g') + let escaped = substitute(escaped, '"', '\\^&', 'g') + let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g') + return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"' +endfunction + +function! s:shellesc(arg) + if &shell =~# 'cmd.exe$' + return s:shellesc_cmd(a:arg) + endif + return shellescape(a:arg) +endfunction + +function! s:glob_dir(path) + return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)') +endfunction + +function! s:progress_bar(line, bar, total) + call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']') +endfunction + +function! s:compare_git_uri(a, b) + " See `git help clone' + " https:// [user@] github.com[:port] / junegunn/vim-plug [.git] + " [git@] github.com[:port] : junegunn/vim-plug [.git] + " file:// / junegunn/vim-plug [/] + " / junegunn/vim-plug [/] + let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$' + let ma = matchlist(a:a, pat) + let mb = matchlist(a:b, pat) + return ma[1:2] ==# mb[1:2] +endfunction + +function! s:format_message(bullet, name, message) + if a:bullet != 'x' + return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))] + else + let lines = map(s:lines(a:message), '" ".v:val') + return extend([printf('x %s:', a:name)], lines) + endif +endfunction + +function! s:with_cd(cmd, dir) + return printf('cd%s %s && %s', s:is_win ? ' /d' : '', s:shellesc(a:dir), a:cmd) +endfunction + +function! s:system(cmd, ...) + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + let cmd = a:0 > 0 ? s:with_cd(a:cmd, a:1) : a:cmd + if s:is_win + let batchfile = tempname().'.bat' + call writefile(['@echo off', cmd], batchfile) + let cmd = batchfile + endif + return system(s:is_win ? '('.cmd.')' : cmd) + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win + call delete(batchfile) + endif + endtry +endfunction + +function! s:system_chomp(...) + let ret = call('s:system', a:000) + return v:shell_error ? '' : substitute(ret, '\n$', '', '') +endfunction + +function! s:git_validate(spec, check_branch) + let err = '' + if isdirectory(a:spec.dir) + let result = s:lines(s:system('git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url', a:spec.dir)) + let remote = result[-1] + if v:shell_error + let err = join([remote, 'PlugClean required.'], "\n") + elseif !s:compare_git_uri(remote, a:spec.uri) + let err = join(['Invalid URI: '.remote, + \ 'Expected: '.a:spec.uri, + \ 'PlugClean required.'], "\n") + elseif a:check_branch && has_key(a:spec, 'commit') + let result = s:lines(s:system('git rev-parse HEAD 2>&1', a:spec.dir)) + let sha = result[-1] + if v:shell_error + let err = join(add(result, 'PlugClean required.'), "\n") + elseif !s:hash_match(sha, a:spec.commit) + let err = join([printf('Invalid HEAD (expected: %s, actual: %s)', + \ a:spec.commit[:6], sha[:6]), + \ 'PlugUpdate required.'], "\n") + endif + elseif a:check_branch + let branch = result[0] + " Check tag + if has_key(a:spec, 'tag') + let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) + if a:spec.tag !=# tag && a:spec.tag !~ '\*' + let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', + \ (empty(tag) ? 'N/A' : tag), a:spec.tag) + endif + " Check branch + elseif a:spec.branch !=# branch + let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', + \ branch, a:spec.branch) + endif + if empty(err) + let [ahead, behind] = split(s:lastline(s:system(printf( + \ 'git rev-list --count --left-right HEAD...origin/%s', + \ a:spec.branch), a:spec.dir)), '\t') + if !v:shell_error && ahead + if behind + " Only mention PlugClean if diverged, otherwise it's likely to be + " pushable (and probably not that messed up). + let err = printf( + \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n" + \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', a:spec.branch, ahead, behind) + else + let err = printf("Ahead of origin/%s by %d commit(s).\n" + \ .'Cannot update until local changes are pushed.', + \ a:spec.branch, ahead) + endif + endif + endif + endif + else + let err = 'Not found' + endif + return [err, err =~# 'PlugClean'] +endfunction + +function! s:rm_rf(dir) + if isdirectory(a:dir) + call s:system((s:is_win ? 'rmdir /S /Q ' : 'rm -rf ') . s:shellesc(a:dir)) + endif +endfunction + +function! s:clean(force) + call s:prepare() + call append(0, 'Searching for invalid plugins in '.g:plug_home) + call append(1, '') + + " List of valid directories + let dirs = [] + let errs = {} + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + if !s:is_managed(name) + call add(dirs, spec.dir) + else + let [err, clean] = s:git_validate(spec, 1) + if clean + let errs[spec.dir] = s:lines(err)[0] + else + call add(dirs, spec.dir) + endif + endif + let cnt += 1 + call s:progress_bar(2, repeat('=', cnt), total) + normal! 2G + redraw + endfor + + let allowed = {} + for dir in dirs + let allowed[s:dirpath(fnamemodify(dir, ':h:h'))] = 1 + let allowed[dir] = 1 + for child in s:glob_dir(dir) + let allowed[child] = 1 + endfor + endfor + + let todo = [] + let found = sort(s:glob_dir(g:plug_home)) + while !empty(found) + let f = remove(found, 0) + if !has_key(allowed, f) && isdirectory(f) + call add(todo, f) + call append(line('$'), '- ' . f) + if has_key(errs, f) + call append(line('$'), ' ' . errs[f]) + endif + let found = filter(found, 'stridx(v:val, f) != 0') + end + endwhile + + 4 + redraw + if empty(todo) + call append(line('$'), 'Already clean.') + else + let s:clean_count = 0 + call append(3, ['Directories to delete:', '']) + redraw! + if a:force || s:ask_no_interrupt('Delete all directories?') + call s:delete([6, line('$')], 1) + else + call setline(4, 'Cancelled.') + nnoremap d :set opfunc=delete_opg@ + nmap dd d_ + xnoremap d :call delete_op(visualmode(), 1) + echo 'Delete the lines (d{motion}) to delete the corresponding directories' + endif + endif + 4 + setlocal nomodifiable +endfunction + +function! s:delete_op(type, ...) + call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0) +endfunction + +function! s:delete(range, force) + let [l1, l2] = a:range + let force = a:force + while l1 <= l2 + let line = getline(l1) + if line =~ '^- ' && isdirectory(line[2:]) + execute l1 + redraw! + let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1) + let force = force || answer > 1 + if answer + call s:rm_rf(line[2:]) + setlocal modifiable + call setline(l1, '~'.line[1:]) + let s:clean_count += 1 + call setline(4, printf('Removed %d directories.', s:clean_count)) + setlocal nomodifiable + endif + endif + let l1 += 1 + endwhile +endfunction + +function! s:upgrade() + echo 'Downloading the latest version of vim-plug' + redraw + let tmp = tempname() + let new = tmp . '/plug.vim' + + try + let out = s:system(printf('git clone --depth 1 %s %s', s:plug_src, tmp)) + if v:shell_error + return s:err('Error upgrading vim-plug: '. out) + endif + + if readfile(s:me) ==# readfile(new) + echo 'vim-plug is already up-to-date' + return 0 + else + call rename(s:me, s:me . '.old') + call rename(new, s:me) + unlet g:loaded_plug + echo 'vim-plug has been upgraded' + return 1 + endif + finally + silent! call s:rm_rf(tmp) + endtry +endfunction + +function! s:upgrade_specs() + for spec in values(g:plugs) + let spec.frozen = get(spec, 'frozen', 0) + endfor +endfunction + +function! s:status() + call s:prepare() + call append(0, 'Checking plugins') + call append(1, '') + + let ecnt = 0 + let unloaded = 0 + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + let is_dir = isdirectory(spec.dir) + if has_key(spec, 'uri') + if is_dir + let [err, _] = s:git_validate(spec, 1) + let [valid, msg] = [empty(err), empty(err) ? 'OK' : err] + else + let [valid, msg] = [0, 'Not found. Try PlugInstall.'] + endif + else + if is_dir + let [valid, msg] = [1, 'OK'] + else + let [valid, msg] = [0, 'Not found.'] + endif + endif + let cnt += 1 + let ecnt += !valid + " `s:loaded` entry can be missing if PlugUpgraded + if is_dir && get(s:loaded, name, -1) == 0 + let unloaded = 1 + let msg .= ' (not loaded)' + endif + call s:progress_bar(2, repeat('=', cnt), total) + call append(3, s:format_message(valid ? '-' : 'x', name, msg)) + normal! 2G + redraw + endfor + call setline(1, 'Finished. '.ecnt.' error(s).') + normal! gg + setlocal nomodifiable + if unloaded + echo "Press 'L' on each line to load plugin, or 'U' to update" + nnoremap L :call status_load(line('.')) + xnoremap L :call status_load(line('.')) + end +endfunction + +function! s:extract_name(str, prefix, suffix) + return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$') +endfunction + +function! s:status_load(lnum) + let line = getline(a:lnum) + let name = s:extract_name(line, '-', '(not loaded)') + if !empty(name) + call plug#load(name) + setlocal modifiable + call setline(a:lnum, substitute(line, ' (not loaded)$', '', '')) + setlocal nomodifiable + endif +endfunction + +function! s:status_update() range + let lines = getline(a:firstline, a:lastline) + let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)') + if !empty(names) + echo + execute 'PlugUpdate' join(names) + endif +endfunction + +function! s:is_preview_window_open() + silent! wincmd P + if &previewwindow + wincmd p + return 1 + endif +endfunction + +function! s:find_name(lnum) + for lnum in reverse(range(1, a:lnum)) + let line = getline(lnum) + if empty(line) + return '' + endif + let name = s:extract_name(line, '-', '') + if !empty(name) + return name + endif + endfor + return '' +endfunction + +function! s:preview_commit() + if b:plug_preview < 0 + let b:plug_preview = !s:is_preview_window_open() + endif + + let sha = matchstr(getline('.'), '^ \X*\zs[0-9a-f]\{7,9}') + if empty(sha) + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir) + return + endif + + if exists('g:plug_pwindow') && !s:is_preview_window_open() + execute g:plug_pwindow + execute 'e' sha + else + execute 'pedit' sha + wincmd P + endif + setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + let cmd = 'cd '.s:shellesc(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha + if s:is_win + let batchfile = tempname().'.bat' + call writefile(['@echo off', cmd], batchfile) + let cmd = batchfile + endif + execute 'silent %!' cmd + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win + call delete(batchfile) + endif + endtry + setlocal nomodifiable + nnoremap q :q + wincmd p +endfunction + +function! s:section(flags) + call search('\(^[x-] \)\@<=[^:]\+:', a:flags) +endfunction + +function! s:format_git_log(line) + let indent = ' ' + let tokens = split(a:line, nr2char(1)) + if len(tokens) != 5 + return indent.substitute(a:line, '\s*$', '', '') + endif + let [graph, sha, refs, subject, date] = tokens + let tag = matchstr(refs, 'tag: [^,)]\+') + let tag = empty(tag) ? ' ' : ' ('.tag.') ' + return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date) +endfunction + +function! s:append_ul(lnum, text) + call append(a:lnum, ['', a:text, repeat('-', len(a:text))]) +endfunction + +function! s:diff() + call s:prepare() + call append(0, ['Collecting changes ...', '']) + let cnts = [0, 0] + let bar = '' + let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)') + call s:progress_bar(2, bar, len(total)) + for origin in [1, 0] + let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))')))) + if empty(plugs) + continue + endif + call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:') + for [k, v] in plugs + let range = origin ? '..origin/'.v.branch : 'HEAD@{1}..' + let diff = s:system_chomp('git log --graph --color=never '.join(map(['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range], 's:shellesc(v:val)')), v.dir) + if !empty(diff) + let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : '' + call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)'))) + let cnts[origin] += 1 + endif + let bar .= '=' + call s:progress_bar(2, bar, len(total)) + normal! 2G + redraw + endfor + if !cnts[origin] + call append(5, ['', 'N/A']) + endif + endfor + call setline(1, printf('%d plugin(s) updated.', cnts[0]) + \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : '')) + + if cnts[0] || cnts[1] + nnoremap :silent! call preview_commit() + nnoremap o :silent! call preview_commit() + endif + if cnts[0] + nnoremap X :call revert() + echo "Press 'X' on each block to revert the update" + endif + normal! gg + setlocal nomodifiable +endfunction + +function! s:revert() + if search('^Pending updates', 'bnW') + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || + \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y' + return + endif + + call s:system('git reset --hard HEAD@{1} && git checkout '.s:esc(g:plugs[name].branch).' --', g:plugs[name].dir) + setlocal modifiable + normal! "_dap + setlocal nomodifiable + echo 'Reverted' +endfunction + +function! s:snapshot(force, ...) abort + call s:prepare() + setf vim + call append(0, ['" Generated by vim-plug', + \ '" '.strftime("%c"), + \ '" :source this file in vim to restore the snapshot', + \ '" or execute: vim -S snapshot.vim', + \ '', '', 'PlugUpdate!']) + 1 + let anchor = line('$') - 3 + let names = sort(keys(filter(copy(g:plugs), + \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)'))) + for name in reverse(names) + let sha = s:system_chomp('git rev-parse --short HEAD', g:plugs[name].dir) + if !empty(sha) + call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha)) + redraw + endif + endfor + + if a:0 > 0 + let fn = expand(a:1) + if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?')) + return + endif + call writefile(getline(1, '$'), fn) + echo 'Saved as '.a:1 + silent execute 'e' s:esc(fn) + setf vim + endif +endfunction + +function! s:split_rtp() + return split(&rtp, '\\\@ + abc *a*b*c* *abc* + dir/file dir/*f*i*l*e* dir/*file* + d*r/file d*r/*f*i*l*e* d*r/*file* + ../**/s ../**/*s* ../**/*s* + (** : 再帰検索) +< +次のような場面で有用です: + + "./AhLongLongLongLongLongFile.txt" + "./AhLongLongLongLongLongName.txt" + "./OhLongLongLongLongLongFile.txt" + "./OhLongLongLongLongLongName.txt" <- 欲しいファイル :-O + +"ON" と入力すれば "OhLongLongLongLongLongName.txt" が選択できます. :-D + +FuzzyFinder が検索できる対象は次の通りです: + - バッファ + - ファイル + - ディレクトリ + - 最近使ったファイル + - 最近使ったファイルの近くのファイル + - 最近使ったコマンドライン + - ブックマークされたファイル + - ブックマークされたディレクトリ + - タグ + - タグファイルに含まれるファイル + - ジャンプリスト + - チェンジリスト + - バッファの行 + - quickfix + - ヘルプ + +FuzzyFinder は ファイルを検索したりアイテムを選択するシステムを利用するための +API も提供します。 + +FuzzyFinder はマルチバイト文字をサポートしています。 + + +============================================================================== +インストール *fuf-installation* + +ZIPファイルをランタイムディレクトリに展開します。 + +以下のようにファイルが配置されるはずです。 +> + <ランタイムディレクトリ>/plugin/fuf.vim + <ランタイムディレクトリ>/doc/fuf.txt + ... +< +もしランタイムディレクトリが多数のプラグインでごちゃごちゃになるのが嫌なら、各 +プラグインを個別のディレクトリに配置し、そのディレクトリのパスを 'runtimepath' +に追加してください。アンインストールも楽になります。 + +その後、ヘルプを有効にするためにタグファイルを更新してください。詳しくは +|add-local-help|を参照してください。 + +必要なもの: ~ + +- L9 library (vimscript #3252) + + +============================================================================== +使い方 *fuf-usage* + +次のコマンドで FuzzyFinder を起動します: + + コマンド モード ~ + |:FufBuffer| - Buffer モード (|fuf-buffer-mode|) + |:FufFile| - File モード (|fuf-file-mode|) + |:FufCoverageFile| - Coverage-File モード (|fuf-coveragefile-mode|) + |:FufDir| - Directory モード (|fuf-dir-mode|) + |:FufMruFile| - MRU-File モード (|fuf-mrufile-mode|) + |:FufMruCmd| - MRU-Command モード (|fuf-mrucmd-mode|) + |:FufBookmarkFile| - Bookmark-File モード (|fuf-bookmarkfile-mode|) + |:FufBookmarkDir| - Bookmark-Dir モード (|fuf-bookmarkdir-mode|) + |:FufTag| - Tag モード (|fuf-tag-mode|) + |:FufBufferTag| - Buffer-Tag モード (|fuf-buffertag-mode|) + |:FufTaggedFile| - Tagged-File モード (|fuf-taggedfile-mode|) + |:FufJumpList| - Jump-List モード (|fuf-jumplist-mode|) + |:FufChangeList| - Change-List モード (|fuf-changelist-mode|) + |:FufQuickfix| - Quickfix モード (|fuf-quickfix-mode|) + |:FufLine| - Line モード (|fuf-line-mode|) + |:FufHelp| - Help モード (|fuf-help-mode|) + +これらのコマンドを押しやすいキーにマッピングすることを推奨します。 + +これらのコマンドを実行するとパターンを入力するための1行のバッファを開き、イン +サートモードを開始します。 + +FuzzyFinder は入力されたパターンにマッチするアイテムを検索し、それを補完メニュ +ーに表示します。パターンマッチングの詳細は|fuf-search-patterns|を参照してくだ +さい。 + +多くのアイテムがマッチングする場合、FuzzyFinder はレスポンスを向上させるために +列挙するアイテムの数(|g:fuf_enumeratingLimit|)を制限し、その際、入力されたパタ +ーンを"Error" グループでハイライトします。 + +補完メニューの最初のアイテムは自動的に選択状態になります。 + + で入力パターンからカーソル前の、ディレクトリ名などのひとかたまりを削除す +ることができます。 + + (|g:fuf_keyPrevPattern|) と (|g:fuf_keyNextPattern|) で、履歴から +過去に入力したパターンを呼び出すことができます。 + +いろいろな方法で、選択されたアイテムを開くことができます: + + (|g:fuf_keyOpen|) - 直前のウィンドウで開きます。 + (|g:fuf_keyOpenSplit|) - ウィンドウを分割して開きます。 + (|g:fuf_keyOpenVsplit|) - ウィンドウを垂直分割して開きます。 + (|g:fuf_keyOpenTabpage|) - 別のタブページで開きます。 + +キャンセルして直前のウィンドウに戻るには、インサートモードを抜けてください。 + + (|g:fuf_keySwitchMatching|) で、検索方法をあいまいマッチングまたは +部分一致マッチングに交互に切り替えることができます。 + + (|g:fuf_keyNextMode|) と (|g:fuf_keyPrevMode|) で、インサートモー +ドを抜けることなくカレントモードを切り替えることが出来ます。 + +いくつかのモードでは、選択されたアイテムを (|g:fuf_keyPreview|) でプレビ +ューすることができます。同じアイテムでキーを繰り返すことで別の情報を表示させる +ことができます。プレビューをサポートするモードを起動すると、コマンドラインの高 +さが|g:fuf_previewHeight|になります。この機能は|g:fuf_previewHeight|が0ではな +い場合、有効になります。 + + +============================================================================== +モード *fuf-modes* + + *fuf-buffer-mode* +Buffer モード ~ + +このモードはバッファを選択して開くインターフェースを提供します。 + +Buffer モード中に (|g:fuf_buffer_keyDelete|) を押すと選択したバッファを +削除することができます。 + + *fuf-file-mode* +File モード ~ + +このモードはファイルツリーからファイルを検索して開くインターフェースを提供しま +す。 + + *fuf-coveragefile-mode* +Coverage-File モード ~ + +このモードはあらかじめ設定した検索対象の全ファイルからファイルを選択して開くイ +ンターフェースを提供します。 + +デフォルトではカレントディレクトリ以下の全ファイルを列挙します。 +(|g:fuf_coveragefile_globPatterns|) + +他の検索対象を検索したい場合、|FufCoverageFileRegister|コマンドで新しい検索対 +象を登録し、|FufCoverageFileChange|コマンドで検索対象を選択して Coverage-File +モードを起動します。 + +加えて、|fuf#setOneTimeVariables()|関数を使う方法もあります。 + + +例: .hと.cファイルだけ検索する: +> + call fuf#setOneTimeVariables(['g:fuf_coveragefile_globPatterns', ['**/*.h', '**/*.c']]) + \ | FufCoverageFile +< +例: デフォルトの検索対象に加えてホームディレクトリも検索する: +> + call fuf#setOneTimeVariables(['g:fuf_coveragefile_globPatterns', g:fuf_coveragefile_globPatterns + ['~/**/.*', '~/**/*']]) + \ | FufCoverageFile +< + + *fuf-dir-mode* +Directory モード ~ + +このモードはファイルツリーからディレクトリを検索してカレントディレクトリを変更 +するインターフェースを提供します。 + + *fuf-mrufile-mode* +MRU-File モード ~ + +このモードは最近使ったファイルを選択して開くインターフェースを提供します。 + +このモード中に (|g:fuf_mrufile_keyExpand|) を押すと、最近使ったファイル +の付近にあるファイルを検索します。このキーを押す毎に、検索範囲をディレクトリツ +リーの上下に1階層ずつ広げます。 + +|BufEnter| と |BufWritePost| で行う処理がパフォーマンス上の問題を起こしうるの +で、デフォルトでは無効化するモードに指定されています。(|g:fuf_modesDisable|) + +See also: |FufMruFileInCwd| + + *fuf-mrucmd-mode* +MRU-Command モード ~ + +このモードは最近使ったコマンドラインを選択して開くインターフェースを提供します +。 +このモードに必要な、コマンドラインモードの のマッピングに副作用があるので、 +、デフォルトでは無効化するモードに指定されています。(|g:fuf_modesDisable|) + + *fuf-bookmarkfile-mode* +Bookmark-File モード ~ + +このモードは事前に追加したブックマークを選択してその行へジャンプするインターフ +ェースを提供します。 + +|:FufBookmarkFileAdd|コマンドでカーソルのある行をブックマークに追加できます。 +このコマンドを実行すると、ブックマーク名の入力を求められます。 + +FuzzyFinder はジャンプする行番号を調整します。ブックマークされた行がブックマー +クされたときのパターンとマッチしない場合、FuzzyFinder はブックマークされた位置 +の周辺でマッチする行を探します。なのでブックマークした行が多少移動していたとし +ても、そこでジャンプすることができます。ブックマークした行番号へ調整せずにジャ +ンプしたい場合、|g:fuf_bookmarkfile_searchRange|を 0 に設定してください。 + +このモード中に (|g:fuf_bookmarkfile_keyDelete|) を押すと選択したブックマ +ークを削除することができます。 + + *fuf-bookmarkdir-mode* +Bookmark-Dir モード ~ + +このモードは事前に追加したブックマークを選択してカレントディレクトリを変更する +するインターフェースを提供します。 + +|:FufBookmarkDirAdd|コマンドでディレクトリをブックマークに追加できます。このコ +マンドを実行すると、ディレクトリのパスとブックマーク名の入力を求められます。 + +このモード中に (|g:fuf_bookmarkdir_keyDelete|) を押すと選択したブックマ +ークを削除することができます。 + + *fuf-tag-mode* +Tag モード ~ + +このモードはタグを選択してその定義へジャンプするインターフェースを提供します。 + +以下は を置き換えるマッピングです。 +> + noremap :FufTagWithCursorWord! +< + + *fuf-buffertag-mode* +Buffer-Tag モード ~ + +このモードはカレントバッファまたは全バッファのタグを選択してその定義へジャンプ +するインターフェースを提供します。 + +タグのリストはFuzzyFinderの起動時にその場で作成されるので、前もってtagsファイ +ルを作成する必要はありません。 + +|FufBufferTag|はカレントバッファを対象にし、|FufBufferTagAll|は全バッファを対 +象にします。 + +以下は を置き換えるマッピングです: +> + nnoremap :FufBufferTagWithCursorWord! + vnoremap :FufBufferTagAllWithSelectedText! +< +または +> + nnoremap :FufBufferTagAllWithCursorWord! + vnoremap :FufBufferTagAllWithSelectedText! +< +このモードは taglist.vim (vimscript #273) にインスパイアされました。コードも参 +考にしています。 + + *fuf-taggedfile-mode* +Tagged-File モード ~ + +このモードはタグファイルに含まれるファイルを選択して開くインターフェースを提供 +します。 + + *fuf-jumplist-mode* +Jump-List モード ~ + +このモードはカレントウィンドウの|jumplist|から選択した位置へジャンプするインタ +ーフェースを提供します。 + + *fuf-changelist-mode* +Change-List モード ~ + +このモードはカレントバッファの|changelist|から選択した位置へジャンプするインタ +ーフェースを提供します。 + + *fuf-quickfix-mode* +Quickfix モード ~ + +このモードは|quickfix|リストから選択した位置へジャンプするインターフェースを提 +供します。 + + *fuf-line-mode* +Line モード ~ + +このモードはカレントバッファの行を選択してジャンプするインターフェースを提供し +ます。 + + *fuf-help-mode* +Help モード ~ + +このモードはヘルプタグを選択してそのヘルプページへジャンプするインターフェース +を提供します。 + + *fuf-givenfile-mode* +Given-File モード ~ + +このモードは与えられたリストから選択されたファイルを開く API を提供します。 + +API 関数: +> + function fuf#givenfile#launch( + \ initialPattern, partialMatching, prompt, items) +< + initialPattern - FuzzyFinder 起動直後に挿入される文字列 + partialMatching - あいまい検索ではなく部分一致検索を行うか + prompt - プロンプト文字列 + items - アイテムのリスト + +利用例: +> + " ドットファイルを開く + call fuf#givenfile#launch('', 0, '>', split(glob('~/.*'), "\n")) +< + + *fuf-givendir-mode* +Given-Directory モード ~ + +このモードは与えられたリストから選択されたディレクトリにカレントディレクトリを +変更する API を提供します。 + +API 関数: +> + function fuf#givendir#launch( + \ initialPattern, partialMatching, prompt, items) +< + initialPattern - FuzzyFinder 起動直後に挿入される文字列 + partialMatching - あいまい検索ではなく部分一致検索を行うか + prompt - プロンプト文字列 + items - アイテムのリスト + + +利用例: +> + " ランタイムディレクトリのどれかをカレントディレクトリにする + call fuf#givendir#launch('', 0, '>', split(&runtimepath, ',')) +< + + *fuf-givencmd-mode* +Given-Command モード ~ + +このモードは与えられたリストから選択されたコマンドを実行する API を提供します。 + +選択されたコマンドは feedkeys() によって実行されるので、ノーマルモードでの一連 +のキー入力をエミュレートさせることも可能です。 + +API 関数: +> + function fuf#givencmd#launch( + \ initialPattern, partialMatching, prompt, items) +< + initialPattern - FuzzyFinder 起動直後に挿入される文字列 + partialMatching - あいまい検索ではなく部分一致検索を行うか + prompt - プロンプト文字列 + items - アイテムのリスト + + +利用例: +> + function GetAllCommands() + redir => commands + silent command + redir END + return map((split(commands, "\n")[3:]), + \ '":" . matchstr(v:val, ''^....\zs\S*'')') + endfunction + + " ユーザー定義コマンドを選択して実行 + call fuf#givencmd#launch('', 0, '>', GetAllCommands()) + +< + + *fuf-callbackfile-mode* +Callback-File モード ~ + +このモードはファイルを検索して選択されたファイルパスを得る API を提供します。 + +API 関数: +> + function fuf#callbackfile#launch( + \ initialPattern, partialMatching, prompt, exclude, listener) +< + initialPattern - FuzzyFinder 起動直後に挿入される文字列 + partialMatching - あいまい検索ではなく部分一致検索を行うか + prompt - プロンプト文字列 + exclude - 補完リストから除外したいアイテムの正規表現パターン + listener - 'onComplete' と 'onAbort' を持つ|Dictionary|。これ + らは FuzzyFinder 終了時に呼ばれます。 + listener.onComplete(item, method) は選択が完了したと + き、選択されたアイテム名とオープン方式番号の2引数と + 共に呼ばれます。listener.onAbort() は選択を中止した + ときに呼ばれます。 + +利用例: +> + let listener = {} + + function listener.onComplete(item, method) + echo "Item: " . a:item . "\nMethod: " . a:method + endfunction + + function listener.onAbort() + echo "Abort" + endfunction + + " カレントディレクトリからファイルを選択 + call fuf#callbackfile#launch('', 0, '>', '', listener) + + " ホームディレクトリからファイルを選択 + call fuf#callbackfile#launch('~/', 0, '>', '', listener) +< + + *fuf-callbackitem-mode* +Callback-Item モード ~ + +このモードは与えられたリストから選択されたアイテムを得るための API を提供しま +す。 + +API 関数: +> + function fuf#callbackitem#launch( + \ initialPattern, partialMatching, prompt, listener, items, forPath) +< + initialPattern - FuzzyFinder 起動直後に挿入される文字列 + partialMatching - あいまい検索ではなく部分一致検索を行うか + prompt - プロンプト文字列 + listener - 'onComplete' と 'onAbort' を持つ|Dictionary|。これ + らは FuzzyFinder 終了時に呼ばれます。 + listener.onComplete(item, method) は選択が完了したと + き、選択されたアイテム名とオープン方式番号の2引数と + 共に呼ばれます。listener.onAbort() は選択を中止した + ときに呼ばれます。 + items - アイテムのリスト + forPath - ファイル選択に特化したマッチングを利用するか + +利用例: +> + let listener = {} + + function listener.onComplete(item, method) + echo "Item: " . a:item . "\nMethod: " . a:method + endfunction + + function listener.onAbort() + echo "Abort" + endfunction + + " 与えられたリストからアイテムを選択 + call fuf#callbackitem#launch('', 0, '>', listener, ['ed', 'vi', 'vim'], 0) + + " 与えられたリストからファイルを選択 + call fuf#callbackitem#launch('', 0, '>', listener, ['../foo/bar', 'baz'], 1) +< + +============================================================================== +詳細なトピック *fuf-detailed-topics* + + *fuf-setting-one-time-option* *fuf#setOneTimeVariables()* +一回限りのオプションの設定 ~ + +次回の FuzzyFinder 用に一回限りのオプションを設定したいとき、 +|fuf#setOneTimeVariables()|関数が役に立ちます。この関数は次のようにして使いま +す: +> + call fuf#setOneTimeVariables(['g:fuf_ignoreCase', 0], ['&lines', 50]) +< +この関数は 0 個以上の引数を取り、各々は変数名と値のペアです。指定されたオプシ +ョンは次回 FuzzyFinder が起動したときに実際に設定され、終了するときに復元され +ます。 + + *fuf-search-patterns* +検索パターン ~ + +検索パターンとして、一つのプライマリパターンと0個以上の絞り込みパターンを入力 +することができます。入力パターンは ";" (|g:fuf_patternSeparator|) で区切られ、 +最初のパターンがプライマリパターンになり、残りのパターンが絞り込みパターンにな +ります。 +> + プライマリ 絞り込み 絞り込み + |----------| |-------| |----| + >MruFile>bookmark.vim;autoload/;/home/ +< +プライマリパターンにマッチしたアイテムのリストを別のパターンで絞り込むために、 +絞り込みパターンを利用します。 + +プライマリパターンでは、あいまいマッチングと部分一致マッチングのうち、選択され +た方を行います。絞り込みパターンでは、デフォルトで部分一致マッチングを行います +。(|g:fuf_fuzzyRefining|) + +絞り込みパターンとして数値を入力した場合、アイテムのインデックスに対しても +マッチングします。 + +ファイルパスの静的な集合を対象とするモード (Buffer, MRU-File モードなど。File, +Directory モードなどではない) で|g:fuf_splitPathMatching|が真の場合、プライマ +リパターンのマッチングは head 部とtail 部に分けて行われます。 +> + head tail + |------||-----| + foo/bar/baz.vim + + あいまいマッチング例: + +----------------+---------+---------+---------+ + | item \ pattern | foo/bar | foo/ | bar | + +----------------+---------+---------+---------+ + | foo/bar | match | match | match | + | foo/abc | unmatch | match | unmatch | + | abc/bar | unmatch | unmatch | match | + | foobar | unmatch | unmatch | match | + | foooo/barrrr | match | match | match | + | foooo/fooooo | unmatch | match | unmatch | + +----------------+---------+---------+---------+ +< +上記のケースで、絞り込みパターンはパス全体に対してマッチングできます。 + + *fuf-sorting-of-completion-items* +補完アイテムのソート ~ + +FuzzyFinder は幾つかのルールに従って補完アイテムをソートします。 + +パターン全体が一部分にぴったりマッチするアイテムは優先されます。例えば、パター +ン "bc" ではアイテム "abc" は "bac" より優先されます。 + +このケースで、マッチする部分が先頭であるアイテムはそうでないアイテムより優先さ +れます。例えばパターン "foo" ではアイテム "foobar" は"barfoo" より優先されます +。 + +マッチング位置より後の文字数が少ないほど優先されます。例えばパターン "bar" で +はアイテム"foobar" は"foobarbaz"より優先されます。 + +単語の境界文字にだけマッチングするアイテムは優先されます。 例えば、パターン +"fb" ではアイテム"fooBarBaz" や "foo_bar_baz" などが優先されます。 + +加えて、FuzzyFinder には学習システムがあります。現在のパターンで、過去に補完さ +れたことのあるアイテムを優先します。 + + *fuf-reusing-window* +目的のバッファ/ファイルが開かれているウィンドウの再利用 ~ + +ウィンドウを分割してバッファ/ファイルを開くときに、現在のタブページでそれが開 +かれているウィンドウが見つかった場合、そこへ移動します。別のタブページでバッフ +ァ/ファイルを開くときに、他のタブページでそれが開かれているウィンドウが見つか +った場合、そこへ移動します。 + +常にバッファ/ファイルを新ウィンドウで開きたい場合、'reuse_window'オプションで +この機能を無効にすることができます。 + + *fuf-hiding-menu* +補完メニューの一時非表示 ~ + + で補完メニューを閉じることができます。また、で再度開くことがで +きます。 + + *fuf-abbreviation* *fuf-multiple-search* +短縮入力及び複合検索 ~ + +|g:fuf_abbrevMap|を設定することで、全モードで短縮入力と複合検索が利用できます。 + +例えば次のように設定したとします: +> + let g:fuf_abbrevMap = { + \ "^doc:" : [ + \ "~/project/**/doc/", + \ ".vim/doc/", + \ ], + \ } +< +そして File モードで "doc:txt" と入力すると、次の2つのパターンの検索結果を複合 +します: + + "~/project/**/doc/*t*x*t*" + ".vim/doc/*t*x*t*" + + *fuf-data-file* +データファイル ~ + +FuzzyFinder は補完統計、MRUデータ、ブックマークなどを|g:fuf_dataDir|以下のファ +イルに書き込みます。 + +|:FufEditDataFile|コマンドはデータファイルの編集を補助します。このコマンドを実 +行すると、データファイルを無名バッファに読み込みます。:write などで書き込みを +行うと、データファイルを更新します。 + + *fuf-cache* +キャッシュ ~ + +一旦キャッシュが生成されると、レスポンスを向上させるため自動的には更新されませ +ん。これを更新するには|:FufRenewCache|コマンドを実行してください。 + + *fuf-dot-sequence* +ドット列で親ディレクトリへ移動 ~ + +ドット列を入力することで親ディレクトリを上がっていくことができます。パス区切り +文字直後のドット列は "../" の列に展開されます。 + + ドット列 展開パターン ~ + /.. /../ + /... /../../ + /.... /../../../ + + *fuf-how-to-add-mode* +モードの追加方法 ~ + +"mymode" モードを追加するには、ソースファイルを autoload/fuf/mymode.vim に置き +、 fuf#addMode('mymode') を呼びます。 + + *fuf-migemo* +Migemo とは ~ + +以下のページを参照してください。 + - http://0xcc.net/migemo/ + - http://www.kaoriya.net/#CMIGEMO + + +============================================================================== +コマンド *fuf-commands* + +See also: |fuf-vimrc-example| + + *:FufBuffer* +:FufBuffer [{pattern}] + Buffer モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufFile* +:FufFile [{pattern}] + File モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufFileWithFullCwd* +:FufFileWithFullCwd [{pattern}] + カレントディレクトリのフルパスを初期パターンとする以外は|:FufFile|と同 + じです。 + + *:FufFileWithCurrentBufferDir* +:FufFileWithCurrentBufferDir [{pattern}] + カレントバッファのディレクトリを初期パターンとする以外は|:FufFile|と同 + じです。 + + *:FufDir* +:FufDir [{pattern}] + Directory モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufDirWithFullCwd* +:FufDirWithFullCwd [{pattern}] + カレントディレクトリのフルパスを初期パターンとする以外は|:FufDir|と同 + じです。 + + *:FufDirWithCurrentBufferDir* +:FufDirWithCurrentBufferDir [{pattern}] + カレントバッファのディレクトリを初期パターンとする以外は|:FufDir|と同 + じです。 + + *:FufMruFile* +:FufMruFile [{pattern}] + MRU-File モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufMruFileInCwd* +:FufMruFileInCwd [{pattern}] + カレントディレクトリ内のファイルのみを対象とする以外は + |:FufMruFile|と同じです。 + + *:FufMruCmd* +:FufMruCmd [{pattern}] + MRU-Command モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufBookmarkFile* +:FufBookmarkFile [{pattern}] + Bookmark-File モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufBookmarkDir* +:FufBookmarkDir [{pattern}] + Bookmark-Dir モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufTag* +:FufTag [{pattern}] + Tag モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufTagWithCursorWord* +:FufTagWithCursorWord [{pattern}] + カーソル下の単語を初期パターンとする以外は|:FufTag|と同じです。 + + *:FufBufferTag* +:FufBufferTag[!] [{pattern}] + Buffer-Tag モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufBufferTagAll* +:FufBufferTagAll[!] [{pattern}] + カレントバッファだけでなく他の全てのバッファからもタグを集める以外は + |:FufBufferTag|と同じです。 + + *:FufBufferTagWithCursorWord* +:FufBufferTagWithCursorWord[!] [{pattern}] + カーソル下の単語を初期パターンとする以外は|:FufBufferTag|と同じです。 + + *:FufBufferTagAllWithCursorWord* +:FufBufferTagAllWithCursorWord[!] [{pattern}] + カーソル下の単語を初期パターンとする以外は|:FufBufferTagAll|と同じです + 。 + + *:FufBufferTagWithSelectedText* +:FufBufferTagWithSelectedText[!] [{pattern}] + 最後に選択したテキストを初期パターンとする以外は|:FufBufferTag|と同じ + です。 + + *:FufBufferTagAllWithSelectedText* +:FufBufferTagAllWithSelectedText[!] [{pattern}] + 最後に選択したテキストを初期パターンとする以外は|:FufBufferTagAll|と同 + じです。 + + *:FufTaggedFile* +:FufTaggedFile [{pattern}] + Tagged-File モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufJumpList* +:FufJumpList [{pattern}] + Jump-List モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufChangeList* +:FufChangeList [{pattern}] + Change-List モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufQuickfix* +:FufQuickfix [{pattern}] + Quickfix モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufLine* +:FufLine [{pattern}] + Line モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufHelp* +:FufHelp[!] [{pattern}] + Help モードを起動します。 + + ! 修飾子を付けて実行した場合、あいまい検索ではなく部分一致検索を行うよ + うになります。 + + FuzzyFinder 起動後に {pattern} が挿入されます。 + + *:FufEditDataFile* +:FufEditDataFile + データファイルを編集するためのバッファを開きます。詳しくは + |fuf-data-file|を参照してください。 + + *:FufCoverageFileRegister* +:FufCoverageFileRegister + Coverage-File モードで検索される、新しい検索対象を登録します。最初に + ~/* のような glob パターンを入力します。 を入力するまでパターン + を追加することができます。次に対象名を入力します。 + + See also: |glob()|, |fuf-coveragefile-mode| + + *:FufCoverageFileChange* +:FufCoverageFileChange [{name}] + |FufCoverageFileRegister|コマンドで登録されている中から選択された検索 + 対象でCoverage-File モードを起動します。 + + 対象名が与えられた場合、選択プロセスは飛ばされます。 + + See also: |fuf-coveragefile-mode| + + *:FufBookmarkFileAdd* +:FufBookmarkFileAdd [{name}] + カーソル行をブックマークに追加します。 + + See also: |fuf-bookmarkfile-mode| + + *:FufBookmarkFileAddAsSelectedText* +:FufBookmarkFileAddAsSelectedText + 最後に選択されたテキストをブックマーク名とする以外は + |:FufBookmarkFileAdd|と同じです。 + + *:FufBookmarkDirAdd* +:FufBookmarkDirAdd [{name}] + ディレクトリをブックマークに追加します。 + + See also: |fuf-bookmarkdir-mode| + + *:FufRenewCache* +:FufRenewCache + 補完アイテムを作り直すためにキャッシュを削除します。詳しくは + |fuf-cache|を参照してください。 + + +============================================================================== +オプション *fuf-options* + + *fuf-options-for-all-modes* +全モード用 ~ + + *g:fuf_modesDisable* > + let g:fuf_modesDisable = [ 'mrufile', 'mrucmd', ] +< + 無効にするモード名のリスト。これに含まれるモードは初期化されず、イベン + トの処理も行われません。 + + *g:fuf_keyOpen* > + let g:fuf_keyOpen = '' +< + 補完を確定し、バッファ/ファイルを直前のウィンドウで開くキー。 + + *g:fuf_keyOpenSplit* > + let g:fuf_keyOpenSplit = '' +< + 補完を確定し、バッファ/ファイルを直前のウィンドウを分割して開くキー。 + + *g:fuf_keyOpenVsplit* > + let g:fuf_keyOpenVsplit = '' +< + 補完を確定し、バッファ/ファイルを直前のウィンドウを垂直分割して開くキ + ー。 + + *g:fuf_keyOpenTabpage* > + let g:fuf_keyOpenTabpage = '' +< + 補完を確定し、バッファ/ファイルを別タブページ開くキー。 + + *g:fuf_keyPreview* > + let g:fuf_keyPreview = '' +< + 選択されている補完アイテムの情報をコマンドライン領域に表示するキー。プ + レビューをサポートするモードでのみ作用します。 + + *g:fuf_keyNextMode* > + let g:fuf_keyNextMode = '' +< + 次のモードに切り替えるキー。 + + *g:fuf_keyPrevMode* > + let g:fuf_keyPrevMode = '' +< + 前のモードに切り替えるキー。 + + *g:fuf_keyPrevPattern* > + let g:fuf_keyPrevPattern = '' +< + 履歴から前の入力パターンを呼び出すキー。 + + *g:fuf_keyNextPattern* > + let g:fuf_keyNextPattern = '' +< + 履歴から次の入力パターンを呼び出すキー。 + + *g:fuf_keySwitchMatching* > + let g:fuf_keySwitchMatching = '' +< + あいまいマッチングと部分一致マッチングを切り替えるキー。 + + *g:fuf_dataDir* > + let g:fuf_dataDir = '~/.vim-fuf-data' +< + データファイルを置くディレクトリのパス。空文字列を設定するとファイルへ + の書き込みは行われなくなります。 + + *g:fuf_abbrevMap* > + let g:fuf_abbrevMap = {} +< + |Dictionary|型でそれぞれの値は|List|型です。入力されたテキストの、キー + にマッチする部分が対応する値に展開されます。 + + *g:fuf_patternSeparator* > + let g:fuf_patternSeparator = ';' +< + 入力パターンをプライマリパターンと絞り込みパターン列に区切る文字列。 + + *g:fuf_promptHighlight* > + let g:fuf_promptHighlight = 'Question' +< + プロンプトをハイライトするグループ名。 + + *g:fuf_ignoreCase* > + let g:fuf_ignoreCase = 1 +< + 真なら、大文字小文字を無視します。 + + *g:fuf_splitPathMatching* > + let g:fuf_splitPathMatching = 1 +< + 真なら、プライマリパターンのマッチングは head 部とtail 部に分けて行わ + れます。 + + See also: |fuf-search-patterns| + + *g:fuf_fuzzyRefining* > + let g:fuf_fuzzyRefining = 0 +< + 真なら、絞り込みパターンについて部分一致マッチングの代わりにあいまいマ + ッチングが行われます。 + + See also: |fuf-search-patterns| + + *g:fuf_reuseWindow* > + let g:fuf_reuseWindow = 1 +< + 真なら、すでに開かれているバッファを開くとき、目的のバッファを含むウィ + ンドウを再利用します。 + + *g:fuf_timeFormat* > + let g:fuf_timeFormat = '(%Y-%m-%d %H:%M:%S)' +< + アイテムが登録された日時の書式を設定します。書式の詳細は|strftime()|を + 参照してください。 + + *g:fuf_learningLimit* > + let g:fuf_learningLimit = 100 +< + 保持する補完統計データのモード毎の上限値です。 + + *g:fuf_enumeratingLimit* > + let g:fuf_enumeratingLimit = 50 +< + レスポンスを向上させるため、補完アイテムの列挙をこの数に達した時点で打 + ち切ります。 + + *g:fuf_maxMenuWidth* > + let g:fuf_maxMenuWidth = 78 +< + 長い補完アイテムは、この長さに収まるよう省略して表示します。 + + *g:fuf_previewHeight* > + let g:fuf_previewHeight = 0 +< + プレビューをサポートするモードを起動したとき、'cmdheight'がこの値に設 + 定されます。選択されている補完アイテムの情報がコマンドライン領域に表示 + されます。0 ならプレビュー機能は無効になります。 + + *g:fuf_autoPreview* > + let g:fuf_autoPreview = 0 +< + 真ならプレビューを自動的に表示します。 + + *g:fuf_useMigemo* > + let g:fuf_useMigemo = 0 +< + 真なら migemo を利用します。 + + *fuf-options-for-buffer-mode* +Buffer モード用 ~ + + *g:fuf_buffer_prompt* > + let g:fuf_buffer_prompt = '>Buffer[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_buffer_switchOrder* > + let g:fuf_buffer_switchOrder = 10 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *g:fuf_buffer_mruOrder* > + let g:fuf_buffer_mruOrder = 1 +< + 真なら、最後に使った時間順に補完アイテムをソートします。 + + *g:fuf_buffer_keyDelete* > + let g:fuf_buffer_keyDelete = '' +< + 選択したバッファを削除するキー。 + + *fuf-options-for-file-mode* +File モード用 ~ + + *g:fuf_file_prompt* > + let g:fuf_file_prompt = '>File[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_file_switchOrder* > + let g:fuf_file_switchOrder = 20 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *g:fuf_file_exclude* > + let g:fuf_file_exclude = '\v\~$|\.(o|exe|bak|orig|swp)$|(^|[/\\])\.(hg|git|bzr)($|[/\\])' +< + 補完リストから除外したいアイテムの正規表現パターン。 + + *fuf-options-for-coveragefile-mode* +Coverage-File モード用 ~ + + *g:fuf_coveragefile_prompt* > + let g:fuf_coveragefile_prompt = '>CoverageFile[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_coveragefile_switchOrder* > + let g:fuf_coveragefile_switchOrder = 30 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *g:fuf_coveragefile_exclude* > + let g:fuf_coveragefile_exclude = '\v\~$|\.(o|exe|dll|bak|orig|swp)$|(^|[/\\])\.(hg|git|bzr)($|[/\\])' +< + 補完リストから除外したいアイテムの正規表現パターン。 + + *g:fuf_coveragefile_globPatterns* > + let g:fuf_coveragefile_globPatterns = ['**/.*', '**/*'] +< + 検索されるファイルパスを得るためのglobパターンのリスト。 + + *fuf-options-for-dir-mode* +Directory モード用 ~ + + *g:fuf_dir_prompt* > + let g:fuf_dir_prompt = '>Dir[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_dir_switchOrder* > + let g:fuf_dir_switchOrder = 40 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *g:fuf_dir_exclude* > + let g:fuf_dir_exclude = '\v(^|[/\\])\.(hg|git|bzr)($|[/\\])' +< + 補完リストから除外したいアイテムの正規表現パターン。 + + *fuf-options-for-mrufile-mode* +MRU-File モード用 ~ + + *g:fuf_mrufile_prompt* > + let g:fuf_mrufile_prompt = '>MRU-File[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_mrufile_switchOrder* > + let g:fuf_mrufile_switchOrder = 50 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *g:fuf_mrufile_exclude* > + let g:fuf_mrufile_exclude = '\v\~$|\.(o|exe|dll|bak|orig|sw[po])$|^(\/\/|\\\\|\/mnt\/|\/media\/)' +< + 補完リストから除外したいアイテムの正規表現パターン。 + + *g:fuf_mrufile_maxItem* > + let g:fuf_mrufile_maxItem = 200 +< + 保持するMRUアイテムの上限値。 + + *g:fuf_mrufile_maxItemDir* > + let g:fuf_mrufile_maxItemDir = 50 +< + 保持するMRUアイテムの親ディレクトリ(周辺検索で使われる)の上限値。 + + *g:fuf_mrufile_keyExpand* > + let g:fuf_mrufile_keyExpand = '' +< + 検索する範囲を広げるキー。 + + *fuf-options-for-mrucmd-mode* +MRU-Cmd モード用 ~ + + *g:fuf_mrucmd_prompt* > + let g:fuf_mrucmd_prompt = '>MRU-Cmd[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_mrucmd_switchOrder* > + let g:fuf_mrucmd_switchOrder = 60 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *g:fuf_mrucmd_exclude* > + let g:fuf_mrucmd_exclude = '^$' +< + 補完リストから除外したいアイテムの正規表現パターン。 + + *g:fuf_mrucmd_maxItem* > + let g:fuf_mrucmd_maxItem = 200 +< + 保持するMRUアイテムの上限値。 + + *fuf-options-for-bookmarkfile-mode* +Bookmark-File モード用 ~ + + *g:fuf_bookmarkfile_prompt* > + let g:fuf_bookmarkfile_prompt = '>BookmarkFile[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_bookmarkfile_switchOrder* > + let g:fuf_bookmarkfile_switchOrder = 70 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *g:fuf_bookmarkfile_searchRange* > + let g:fuf_bookmarkfile_searchRange = 400 +< + ジャンプするとき、ブックマークした位置からこの行数の範囲内でブックマー + クしたときのパターンとマッチする行を探します。 + + *g:fuf_bookmarkfile_keyDelete* > + let g:fuf_bookmarkfile_keyDelete = '' +< + 選択したブックマークを削除するキー。 + + *fuf-options-for-bookmarkdir-mode* +Bookmark-Dir モード用 ~ + + *g:fuf_bookmarkdir_prompt* > + let g:fuf_bookmarkdir_prompt = '>BookmarkDir[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_bookmarkdir_switchOrder* > + let g:fuf_bookmarkdir_switchOrder = 80 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *g:fuf_bookmarkdir_keyDelete* > + let g:fuf_bookmarkdir_keyDelete = '' +< + 選択したブックマークを削除するキー。 + + *fuf-options-for-tag-mode* +Tag モード用 ~ + + *g:fuf_tag_prompt* > + let g:fuf_tag_prompt = '>Tag[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_tag_switchOrder* > + let g:fuf_tag_switchOrder = 90 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *fuf-options-for-buffertag-mode* +For Buffer-Tag モード用 ~ + + *g:fuf_buffertag_prompt* > + let g:fuf_buffertag_prompt = '>Buffer-Tag[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_buffertag_switchOrder* > + let g:fuf_buffertag_switchOrder = 100 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *g:fuf_buffertag_ctagsPath* > + let g:fuf_buffertag_ctagsPath = 'ctags' +< + Ctagsの実行ファイルのパス + + *fuf-options-for-taggedfile-mode* +Tagged-File モード用 ~ + + *g:fuf_taggedfile_prompt* > + let g:fuf_taggedfile_prompt = '>Tagged-File[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_taggedfile_switchOrder* > + let g:fuf_taggedfile_switchOrder = 110 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *fuf-options-for-jumplist-mode* +Jump-List モード用 ~ + + *g:fuf_jumplist_prompt* > + let g:fuf_jumplist_prompt = '>Jump-List[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_jumplist_switchOrder* > + let g:fuf_jumplist_switchOrder = 120 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *fuf-options-for-changelist-mode* +Change-List モード用 ~ + + *g:fuf_changelist_prompt* > + let g:fuf_changelist_prompt = '>Change-List[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_changelist_switchOrder* > + let g:fuf_changelist_switchOrder = 130 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *fuf-options-for-quickfix-mode* +Quickfix モード用 ~ + + *g:fuf_quickfix_prompt* > + let g:fuf_quickfix_prompt = '>Quickfix[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_quickfix_switchOrder* > + let g:fuf_quickfix_switchOrder = 140 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *fuf-options-for-line-mode* +Line モード用 ~ + + *g:fuf_line_prompt* > + let g:fuf_line_prompt = '>Line[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_line_switchOrder* > + let g:fuf_line_switchOrder = 150 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + *fuf-options-for-help-mode* +Help モード用 ~ + + *g:fuf_help_prompt* > + let g:fuf_help_prompt = '>Help[]>' +< + プロンプト文字列。"[]" はインジケータに置換されます。 + + *g:fuf_help_switchOrder* > + let g:fuf_help_switchOrder = 160 +< + 次/前のモードに切り替えるときの、モードの順位です。負数ならこのモード + には切り替えません。 + + +============================================================================== +vimrc の例 *fuf-vimrc-example* + +> + let g:fuf_modesDisable = [] + let g:fuf_mrufile_maxItem = 400 + let g:fuf_mrucmd_maxItem = 400 + nnoremap sj :FufBuffer + nnoremap sk :FufFileWithCurrentBufferDir + nnoremap sK :FufFileWithFullCwd + nnoremap s :FufFile + nnoremap sl :FufCoverageFileChange + nnoremap sL :FufCoverageFileChange + nnoremap s :FufCoverageFileRegister + nnoremap sd :FufDirWithCurrentBufferDir + nnoremap sD :FufDirWithFullCwd + nnoremap s :FufDir + nnoremap sn :FufMruFile + nnoremap sN :FufMruFileInCwd + nnoremap sm :FufMruCmd + nnoremap su :FufBookmarkFile + nnoremap s :FufBookmarkFileAdd + vnoremap s :FufBookmarkFileAddAsSelectedText + nnoremap si :FufBookmarkDir + nnoremap s :FufBookmarkDirAdd + nnoremap st :FufTag + nnoremap sT :FufTag! + nnoremap s :FufTagWithCursorWord! + nnoremap s, :FufBufferTag + nnoremap s< :FufBufferTag! + vnoremap s, :FufBufferTagWithSelectedText! + vnoremap s< :FufBufferTagWithSelectedText + nnoremap s} :FufBufferTagWithCursorWord! + nnoremap s. :FufBufferTagAll + nnoremap s> :FufBufferTagAll! + vnoremap s. :FufBufferTagAllWithSelectedText! + vnoremap s> :FufBufferTagAllWithSelectedText + nnoremap s] :FufBufferTagAllWithCursorWord! + nnoremap sg :FufTaggedFile + nnoremap sG :FufTaggedFile! + nnoremap so :FufJumpList + nnoremap sp :FufChangeList + nnoremap sq :FufQuickfix + nnoremap sy :FufLine + nnoremap sh :FufHelp + nnoremap se :FufEditDataFile + nnoremap sr :FufRenewCache +< + +============================================================================== +あばうと *fuf-about* *fuf-contact* *fuf-author* + +作者: Takeshi NISHIDA +ライセンス: MIT Licence +URL: http://www.vim.org/scripts/script.php?script_id=1984 + http://bitbucket.org/ns9tks/vim-fuzzyfinder/ + +バグや要望など ~ + +こちらへどうぞ: http://bitbucket.org/ns9tks/vim-fuzzyfinder/issues/ + +============================================================================== + vim:tw=78:ts=8:ft=help:norl: diff --git a/doc/fuf.txt b/doc/fuf.txt new file mode 100644 index 0000000..2e36831 --- /dev/null +++ b/doc/fuf.txt @@ -0,0 +1,1883 @@ +*fuf.txt* buffer/file/command/tag/etc explorer with fuzzy matching. + + Copyright (c) 2007-2010 Takeshi NISHIDA + +FuzzyFinder *fuzzyfinder* *fuf* + +INTRODUCTION |fuf-introduction| +INSTALLATION |fuf-installation| +USAGE |fuf-usage| +MODES |fuf-modes| +DETAILED TOPICS |fuf-detailed-topics| +COMMANDS |fuf-commands| +OPTIONS |fuf-options| +VIMRC EXAMPLE |fuf-vimrc-example| +SPECIAL THANKS |fuf-thanks| +CHANGELOG |fuf-changelog| +ABOUT |fuf-about| + +============================================================================== +INTRODUCTION *fuf-introduction* + +FuzzyFinder provides convenient ways to quickly reach the +buffer/file/command/bookmark/tag you want. FuzzyFinder searches with the +fuzzy/partial pattern to which it converted an entered pattern. + + Entered pattern Fuzzy pattern Partial pattern ~ +> + abc *a*b*c* *abc* + dir/file dir/*f*i*l*e* dir/*file* + d*r/file d*r/*f*i*l*e* d*r/*file* + ../**/s ../**/*s* ../**/*s* + (** allows searching a directory tree.) +< +You will be happy when: + + "./AhLongLongLongLongLongFile.txt" + "./AhLongLongLongLongLongName.txt" + "./OhLongLongLongLongLongFile.txt" + "./OhLongLongLongLongLongName.txt" <- you want :O + +Type "ON" and "OhLongLongLongLongLongName.txt" will be selected. :D + +FuzzyFinder can search: + + - buffers + - files + - directories + - most recently used files + - files around most recently used files + - most recently used command-lines + - bookmarked files + - bookmarked directories + - tags + - files which are included in current tagfiles + - jump list + - change list + - buffer lines + - quickfix + - help + +FuzzyFinder also provides APIs to use its system of searching files or +selecting items. + +FuzzyFinder supports multibyte characters. + + +============================================================================== +INSTALLATION *fuf-installation* + +Put all files into your runtime directory. If you have the zip file, extract +it to your runtime directory. + +You should place the files as follows: +> + /plugin/fuf.vim + /doc/fuf.txt + ... +< +If you are disgusted to make your runtime directory confused with a lot of +plugins, put each of the plugins into a directory individually and just add +the directory path to 'runtimepath'. It's easy to uninstall plugins. + +Then update your help tags files to enable help for this plugin. See +|add-local-help| for details. + +Requirements: ~ + +- L9 library (vimscript #3252) + + +============================================================================== +USAGE *fuf-usage* + +You can launch FuzzyFinder by the following commands: + + Command Mode ~ + |:FufBuffer| - Buffer mode (|fuf-buffer-mode|) + |:FufFile| - File mode (|fuf-file-mode|) + |:FufCoverageFile| - Coverage-File mode (|fuf-coveragefile-mode|) + |:FufDir| - Directory mode (|fuf-dir-mode|) + |:FufMruFile| - MRU-File mode (|fuf-mrufile-mode|) + |:FufMruCmd| - MRU-Command mode (|fuf-mrucmd-mode|) + |:FufBookmarkFile| - Bookmark-File mode (|fuf-bookmarkfile-mode|) + |:FufBookmarkDir| - Bookmark-Dir mode (|fuf-bookmarkdir-mode|) + |:FufTag| - Tag mode (|fuf-tag-mode|) + |:FufBufferTag| - Buffer-Tag mode (|fuf-buffertag-mode|) + |:FufTaggedFile| - Tagged-File mode (|fuf-taggedfile-mode|) + |:FufJumpList| - Jump-List mode (|fuf-jumplist-mode|) + |:FufChangeList| - Change-List mode (|fuf-changelist-mode|) + |:FufQuickfix| - Quickfix mode (|fuf-quickfix-mode|) + |:FufLine| - Line mode (|fuf-line-mode|) + |:FufHelp| - Help mode (|fuf-help-mode|) + +It is recommended to map these commands. + +These commands open 1-line buffer to enter search pattern and start insert +mode. + +FuzzyFinder searchs for matching items with an entered pattern and shows them +in a completion menu. For more details on pattern matching, see +|fuf-search-patterns|. + +If there are a lot of matching items, FuzzyFinder limits the number of +enumerating items (|g:fuf_enumeratingLimit|) to speed up a response time, and +highlights the pattern with "Error" group. + +The first item in the completion menu will be selected automatically. + +Typing deletes one block of an entered pattern before the cursor, like a +directory name. + +with (|g:fuf_keyPrevPattern|) and (|g:fuf_keyNextPattern|), You +can recall patterns which have been entered before from history. + +You can open a selected item in various ways: + + (|g:fuf_keyOpen|) - opens in a previous window. + (|g:fuf_keyOpenSplit|) - opens in a split window. + (|g:fuf_keyOpenVsplit|) - opens in a vertical-split window. + (|g:fuf_keyOpenTabpage|) - opens in a new tab page. + +To cancel and return to previous window, just leave Insert mode. + +With (|g:fuf_keySwitchMatching|), You can switch search method +between fuzzy matching and partial matching. + +With (|g:fuf_keyNextMode|) and (|g:fuf_keyPrevMode|), You can +switch current mode without leaving Insert mode . + +You can preview selected item with (|g:fuf_keyPreview|) in some modes. +Repeating the key on the same item shows another information. The height +of command-line area is changed to |g:fuf_previewHeight| when you launch a +mode supporting preview. This feature is available when |g:fuf_previewHeight| +is not 0. + + +============================================================================== +MODES *fuf-modes* + + *fuf-buffer-mode* +Buffer mode ~ + +This mode provides an interface to select a buffer from a list of existing +buffers and open it. + +Press (|g:fuf_buffer_keyDelete|) in this mode and selected buffer will +be deleted. + + *fuf-file-mode* +File mode ~ + +This mode provides an interface to search a file tree for a file and open it. + + *fuf-coveragefile-mode* +Coverage-File mode ~ + +This mode provides an interface to select a file from all files of a preset +coverage and open it. + +By default, This mode lists all files under the current working directory +recursively. (|g:fuf_coveragefile_globPatterns|) + +If you want to search other coverage, execute |FufCoverageFileRegister| +command to register new search coverage and |FufCoverageFileChange| command to +choose a search coverage and launch Coverage-File mode. + +In addition, there is another way to change a search coverage with +|fuf#setOneTimeVariables()| function. + +Example: search only .h and .c files: +> + call fuf#setOneTimeVariables(['g:fuf_coveragefile_globPatterns', ['**/*.h', '**/*.c']]) + \ | FufCoverageFile +< +Example: search your home directory in addition to the default coverage: +> + call fuf#setOneTimeVariables(['g:fuf_coveragefile_globPatterns', g:fuf_coveragefile_globPatterns + ['~/**/.*', '~/**/*']]) + \ | FufCoverageFile +< + + *fuf-dir-mode* +Directory mode ~ + +This mode provides an interface to search a file tree for a directory and +change the current directory. + + *fuf-mrufile-mode* +MRU-File mode ~ + +This mode provides an interface to select a file from the most recently used +files and open it. + +Press (|g:fuf_mrufile_keyExpand|) in this mode and files around the most +recently used files are listed. Each time the key is pressed, the search range +are expanded one level along the directory tree upwardly/downwardly. + +This mode is set to disable by default (|g:fuf_modesDisable|) because +processes for this mode in |BufEnter| and |BufWritePost| could cause +Performance issue. + +See also: |FufMruFileInCwd| + + *fuf-mrucmd-mode* +MRU-Command mode ~ + +This mode provides an interface to select a command from the most recently +used commands and execute it. + +This mode is set to disable by default (|g:fuf_modesDisable|) because mapping + of Command-line mode required by this mode has side effects. + + *fuf-bookmarkfile-mode* +Bookmark-File mode ~ + +This mode provides an interface to select one of the bookmarks you have added +beforehand and jump there. + +You can add a cursor line to bookmarks by |:FufBookmarkFileAdd| command. +Execute that command and you will be prompted to enter a bookmark name. + +FuzzyFinder adjusts a line number for jump. If a line of bookmarked position +does not match to a pattern when the bookmark was added, FuzzyFinder searches +a matching line around bookmarked position. So you can jump to a bookmarked +line even if the line is out of bookmarked position. If you want to jump to +bookmarked line number without the adjustment, set +|g:fuf_bookmarkfile_searchRange| option to 0. + +Press (|g:fuf_bookmarkfile_keyDelete|) in this mode and selected +bookmark will be deleted. + + *fuf-bookmarkdir-mode* +Bookmark-Dir mode ~ + +This mode provides an interface to select one of the bookmarks you have added +beforehand and change the current directory. + +You can add a directory to bookmarks by |:FufBookmarkDirAdd| command. Execute +that command and you will be prompted to enter a directory path and a +bookmark name. + +Press (|g:fuf_bookmarkdir_keyDelete|) in this mode and selected bookmark +will be deleted. + + *fuf-tag-mode* +Tag mode ~ + +This mode provides an interface to select a tag and jump to the definition of +it. + +Following mapping is a replacement for : +> + noremap :FufTagWithCursorWord! +< + + *fuf-buffertag-mode* +Buffer-Tag mode ~ + +This mode provides an interface to select a tag of current buffer or all +buffers and jump to the definition of it. + +Tag list is instantly created when FuzzyFinder is launched, so there is no +need to make tags file in advance. + +|FufBufferTag| covers current buffer and |FufBufferTagAll| covers all buffers. + +Following mapping is a replacement for : +> + nnoremap :FufBufferTagWithCursorWord! + vnoremap :FufBufferTagAllWithSelectedText! +< +or +> + nnoremap :FufBufferTagAllWithCursorWord! + vnoremap :FufBufferTagAllWithSelectedText! +< +This mode is inspired by taglist.vim (vimscript #273) and refered its codes. + + *fuf-taggedfile-mode* +Tagged-File mode ~ + +This mode provides an interface to select one of the files which are included +in current tagfiles and open it. + + *fuf-jumplist-mode* +Jump-List mode ~ + +This mode provides an interface to select one from the |jumplist| of the +current window and jump there. + + *fuf-changelist-mode* +Change-List mode ~ + +This mode provides an interface to select one from the |changelist| of the +current buffer and jump there. + + *fuf-quickfix-mode* +Quickfix mode ~ + +This mode provides an interface to select one from the |quickfix| list and +jump there. + + *fuf-line-mode* +Line mode ~ + +This mode provides an interface to select a line from current buffer and jump +there. + + *fuf-help-mode* +Help mode ~ + +This mode provides an interface to select a help tag and jump to the help +page. + + *fuf-givenfile-mode* +Given-File mode ~ + +This mode provides an API to open a selected file from a given list. + +API function: +> + function fuf#givenfile#launch( + \ initialPattern, partialMatching, prompt, items) +< + initialPattern - String which is inserted after launching + FuzzyFinder. + partialMatching - If non-zero, enable partial matching instead of + fuzzy matching. + prompt - Prompt string + items - List of items. + +Example of use: +> + " Open one of your dotfiles. + call fuf#givenfile#launch('', 0, '>', split(glob('~/.*'), "\n")) +< + + *fuf-givendir-mode* +Given-Directory mode ~ + +This mode provides an API to change current working directory to a selected +one from a given list. + +API function: +> + function fuf#givendir#launch( + \ initialPattern, partialMatching, prompt, items) +< + initialPattern - String which is inserted after launching + FuzzyFinder. + partialMatching - If non-zero, enable partial matching instead of + fuzzy matching. + prompt - Prompt string + items - List of items. + + +Example of use: +> + " Change current working directory to one of your runtime directory. + call fuf#givendir#launch('', 0, '>', split(&runtimepath, ',')) +< + + *fuf-givencmd-mode* +Given-Command mode ~ + +This mode provides an API to execute a selected command from a given list. + +A selected command is executed by |feedkeys()|, so it is able to emulate a +series of key input in Normal mode. + +API function: +> + function fuf#givencmd#launch( + \ initialPattern, partialMatching, prompt, items) +< + initialPattern - String which is inserted after launching + FuzzyFinder. + partialMatching - If non-zero, enable partial matching instead of + fuzzy matching. + prompt - Prompt string + items - List of items. + + +Example of use: +> + function GetAllCommands() + redir => commands + silent command + redir END + return map((split(commands, "\n")[3:]), + \ '":" . matchstr(v:val, ''^....\zs\S*'')') + endfunction + + " execute one of the user-defined commands + call fuf#givencmd#launch('', 0, '>', GetAllCommands()) + +< + + *fuf-callbackfile-mode* +Callback-File mode ~ + +This mode provides an API to find and get a file path which is selected by an +user. + +API function: +> + function fuf#callbackfile#launch( + \ initialPattern, partialMatching, prompt, exclude, listener) +< + initialPattern - String which is inserted after launching + FuzzyFinder. + partialMatching - If non-zero, enable partial matching instead of + fuzzy matching. + prompt - Prompt string. + exclude - Regexp pattern for items which you want to exclude + from completion list. + listener - |Dictionary| which has 'onComplete' and 'onAbort'. + They are called at the end of FuzzyFinder. + listener.onComplete(item, method) is called with 2 + arguments which are a name of selected item and a + number of open method when completed. + listener.onAbort() is called when aborted. + +Example of use: +> + let listener = {} + + function listener.onComplete(item, method) + echo "Item: " . a:item . "\nMethod: " . a:method + endfunction + + function listener.onAbort() + echo "Abort" + endfunction + + " Find a file from current working directory. + call fuf#callbackfile#launch('', 0, '>', '', listener) + + " Find a file from home directory. + call fuf#callbackfile#launch('~/', 0, '>', '', listener) +< + + *fuf-callbackitem-mode* +Callback-Item mode ~ + +This mode provides an API to get an item which is selected from a given list +by an user. + +API function: +> + function fuf#callbackitem#launch( + \ initialPattern, partialMatching, prompt, listener, items, forPath) +< + initialPattern - String which is inserted after launching + FuzzyFinder. + partialMatching - If non-zero, enable partial matching instead of + fuzzy matching. + prompt - Prompt string + listener - |Dictionary| which has 'onComplete' and 'onAbort'. + They are called at the end of FuzzyFinder. + listener.onComplete(item, method) is called with 2 + arguments which are a name of selected item and a + number of open method when completed. + listener.onAbort() is called when aborted. + items - List of items. + forPath - If non-zero, use a matching method for files. + +Example of use: +> + let listener = {} + + function listener.onComplete(item, method) + echo "Item: " . a:item . "\nMethod: " . a:method + endfunction + + function listener.onAbort() + echo "Abort" + endfunction + + " Select an item from a given list. + call fuf#callbackitem#launch('', 0, '>', listener, ['ed', 'vi', 'vim'], 0) + + " Select a file from a given list. + call fuf#callbackitem#launch('', 0, '>', listener, ['../foo/bar', 'baz'], 1) +< + +============================================================================== +DETAILED TOPICS *fuf-detailed-topics* + + *fuf-setting-one-time-option* *fuf#setOneTimeVariables()* +Setting One-Time Options ~ + +If you want to set one-time options only for the next FuzzyFinder, +|fuf#setOneTimeVariables()| function will be of help. This function is used as +follows: +> + call fuf#setOneTimeVariables(['g:fuf_ignoreCase', 0], ['&lines', 50]) +< +This function takes 0 or more arguments and each of them is a pair of a +variable name and its value. Specified options will be set practically next +time FuzzyFinder is launched, and restored when FuzzyFinder is closed. + + *fuf-search-patterns* +Search Patterns ~ + +You can enter one primary pattern and zero or more refining patterns as search +patterns. An entered pattern is separated by ";" (|g:fuf_patternSeparator|), +and the first pattern is a primary pattern and the rest of patterns is a +refining pattern. +> + primary refining refining + |----------| |-------| |----| + >MruFile>bookmark.vim;autoload/;/home/ +< +A refining pattern is used to narrow down the list of matching items by +another pattern. + +With a primary pattern, FuzzyFinder does fuzzy matching or partial matching, +which you specified. With a refining pattern, FuzzyFinder does partial +matching by default. (|g:fuf_fuzzyRefining|) + +When you enter a number as refining pattern, it also can match the index of +each item. + +In a mode which targets a static set of file paths (such as Buffer or MRU-File +mode, not File or Directory) and |g:fuf_splitPathMatching| is non-zero, +matching with a primary pattern is divided into head part and tail part and +done individually. +> + head tail + |------||-----| + foo/bar/baz.vim + + fuzzy matching example: + +----------------+---------+---------+---------+ + | item \ pattern | foo/bar | foo/ | bar | + +----------------+---------+---------+---------+ + | foo/bar | match | match | match | + | foo/abc | unmatch | match | unmatch | + | abc/bar | unmatch | unmatch | match | + | foobar | unmatch | unmatch | match | + | foooo/barrrr | match | match | match | + | foooo/fooooo | unmatch | match | unmatch | + +----------------+---------+---------+---------+ +< +refining pattern can match anywhere on each path in the above case. + + *fuf-sorting-of-completion-items* +Sorting Of Completion Items ~ + +FuzzyFinder sorts completion items with some rules. + +An item, one part of which is matched with a whole pattern, is placed upper. +E.g., with the pattern "bc", the item "abc" is placed upper than "bac". + +In the above case, items, each having matching part at the head of itself, are +placed upper than others. E.g., with the pattern "foo", the item "foobar" is +placed upper than "foobarbaz". + +And the shorter the length of the item after matching position puts it higher. +E.g., with the pattern "bar", the item "foobar" is placed upper than +"foobarbaz". + +If a pattern matches an item at only word boundaries of it, the item is placed +upper. E.g., with a pattern "fb", items such as "fooBarBaz" and "foo_bar_baz" +is placed upper. + +Plus, FuzzyFinder has a learning system. An item which has been completed in +the past with current pattern is placed upper. + + *fuf-reusing-window* +Reusing Of A Window Containing Target Buffer/File ~ + +If a window containing target buffer is found in current tab page when +FuzzyFinder is going to open the buffer in a split new window, move to it. If +a window containing target buffer is found in other tab page when FuzzyFinder +is going to open the buffer in a new tab page, move to it. + +You can disable that feature via 'reuse_window' options if always want to open +a buffer in a new window. + + *fuf-hiding-menu* +To Hide The Completion Menu Temporarily In FuzzyFinder ~ + +You can close it by and reopen it by . + + *fuf-abbreviation* *fuf-multiple-search* +Abbreviations And Multiple Search ~ + +You can use abbreviations and multiple search in all modes by setting +|g:fuf_abbrevMap| option. + +For example, set as below: +> + let g:fuf_abbrevMap = { + \ "^doc:" : [ + \ "~/project/**/doc/", + \ ".vim/doc/", + \ ], + \ } +< +and enter "doc:txt" in File mode, then FuzzyFinder searches by the following +patterns: + + "~/project/**/doc/*t*x*t*" + ".vim/doc/*t*x*t*" + +and show concatenated search results. + + *fuf-data-file* +Data File ~ + +FuzzyFinder writes completion statistics, MRU data, bookmark, etc to files +under |g:fuf_dataDir|. + +|:FufEditDataFile| command is helpful in editing your data files. This command +reads the data file in new unnamed buffer. Write the buffer and the data file +will be updated. + + *fuf-cache* +Cache ~ + +Once a cache was created, It is not automatically updated to speed up the +response time by default. To update it, use |:FufRenewCache| command. + + *fuf-dot-sequence* +Going Up Parent Directories With Dot Sequence ~ + +You can go up parent directories with entering dot sequence. Dot sequence +after a path separator is expanded to "../" sequence. + + Dot sequence Expanded pattern ~ + /.. /../ + /... /../../ + /.... /../../../ + + *fuf-how-to-add-mode* +How To Add Mode ~ + +To add "mymode" mode, put the source file at autoload/fuf/mymode.vim and call +fuf#addMode("mymode") . + + *fuf-migemo* +What Is Migemo ~ + +Migemo is a search method for Japanese language. + + +============================================================================== +COMMANDS *fuf-commands* + +See also: |fuf-vimrc-example| + + *:FufBuffer* +:FufBuffer[!] [{pattern}] + Launchs Buffer mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufFile* +:FufFile[!] [{pattern}] + Launchs File mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufFileWithFullCwd* +:FufFileWithFullCwd[!] [{pattern}] + Is mostly the same as |:FufFile|, except that initial pattern is a + full path of current working directory. + + *:FufFileWithCurrentBufferDir* +:FufFileWithCurrentBufferDir[!] [{pattern}] + Is mostly the same as |:FufFile|, except that initial pattern is a + path of directory current buffer is in. + + *:FufCoverageFile* +:FufCoverageFile[!] [{pattern}] + Launchs Coverage-File mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufDir* +:FufDir[!] [{pattern}] + Launchs Directory mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufDirWithFullCwd* +:FufDirWithFullCwd[!] [{pattern}] + Is mostly the same as |:FufDir|, except that initial pattern is a full + path of current working directory. + + *:FufDirWithCurrentBufferDir* +:FufDirWithCurrentBufferDir[!] [{pattern}] + Is mostly the same as |:FufDir|, except that initial pattern is a path + of directory current buffer is in. + + *:FufMruFile* +:FufMruFile[!] [{pattern}] + Launchs MRU-File mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufMruFileInCwd* +:FufMruFileInCwd[!] [{pattern}] + Is mostly the same as |:FufMruFile|, except that files + only in current working directory are listed. + + *:FufMruCmd* +:FufMruCmd[!] [{pattern}] + Launchs MRU-Command mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufBookmarkFile* +:FufBookmarkFile[!] [{pattern}] + Launchs Bookmark-File mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufBookmarkDir* +:FufBookmarkDir[!] [{pattern}] + Launchs Bookmark-Dir mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufTag* +:FufTag[!] [{pattern}] + Launchs Tag mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufTagWithCursorWord* +:FufTagWithCursorWord[!] [{pattern}] + Is mostly the same as |:FufTag|, except that initial pattern is the + word under the cursor. + + *:FufBufferTag* +:FufBufferTag[!] [{pattern}] + Launchs Buffer-Tag mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufBufferTagAll* +:FufBufferTagAll[!] [{pattern}] + Is mostly the same as |:FufBufferTag|, except that tags are gathered + from all other buffers in addition to the current one. + + *:FufBufferTagWithCursorWord* +:FufBufferTagWithCursorWord[!] [{pattern}] + Is mostly the same as |:FufBufferTag|, except that initial pattern is + the word under the cursor. + + *:FufBufferTagAllWithCursorWord* +:FufBufferTagAllWithCursorWord[!] [{pattern}] + Is mostly the same as |:FufBufferTagAll|, except that initial pattern + is the word under the cursor. + + *:FufBufferTagWithSelectedText* +:FufBufferTagWithSelectedText[!] [{pattern}] + Is mostly the same as |:FufBufferTag|, except that initial pattern is + the last selected text. + + *:FufBufferTagAllWithSelectedText* +:FufBufferTagAllWithSelectedText[!] [{pattern}] + Is mostly the same as |:FufBufferTagAll|, except that initial pattern + is the last selected text. + + *:FufTaggedFile* +:FufTaggedFile[!] [{pattern}] + Launchs Tagged-File mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufJumpList* +:FufJumpList[!] [{pattern}] + Launchs Jump-List mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufChangeList* +:FufChangeList[!] [{pattern}] + Launchs Change-List mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufQuickfix* +:FufQuickfix[!] [{pattern}] + Launchs Quickfix mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufLine* +:FufLine[!] [{pattern}] + Launchs Line mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufHelp* +:FufHelp[!] [{pattern}] + Launchs Help mode. + + If a command was executed with a ! modifier, it does partial matching + instead of fuzzy matching. + + {pattern} will be inserted after launching FuzzyFinder. + + *:FufEditDataFile* +:FufEditDataFile + Opens a buffer for editing your data files. See |fuf-data-file| for + details. + + *:FufCoverageFileRegister* +:FufCoverageFileRegister + Registers new search coverage to be searched in Coverage-File mode. + First, input glob patterns, like ~/* . You can add patterns unless + typing . Next, input coverage name. + + See also: |glob()|, |fuf-coveragefile-mode| + + *:FufCoverageFileChange* +:FufCoverageFileChange [{name}] + Launchs Coverage-File mode with a chosen coverage, registered with + |FufCoverageFileRegister| command. + + If location name is given, the choise process will be skipped. + + See also: |fuf-coveragefile-mode| + + *:FufBookmarkFileAdd* +:FufBookmarkFileAdd [{name}] + Adds a cursor line to bookmarks. + + See also: |fuf-bookmarkfile-mode| + + *:FufBookmarkFileAddAsSelectedText* +:FufBookmarkFileAddAsSelectedText + Is mostly the same as |:FufBookmarkFileAdd|, except that initial + pattern is the last selected one. + + *:FufBookmarkDirAdd* +:FufBookmarkDirAdd [{name}] + Adds a directory to bookmarks. + + See also: |fuf-bookmarkdir-mode| + + *:FufRenewCache* +:FufRenewCache + Removes caches to renew completion items. See |fuf-cache| for details. + + +============================================================================== +OPTIONS *fuf-options* + + *fuf-options-for-all-modes* +For All Modes ~ + + *g:fuf_modesDisable* > + let g:fuf_modesDisable = [ 'mrufile', 'mrucmd', ] +< + List of mode names to disable. + + Modes which are listed will never be initialized and never handle any + event. + + *g:fuf_keyOpen* > + let g:fuf_keyOpen = '' +< + Key mapped to select completion item or finish input and open a + buffer/file in previous window. + + *g:fuf_keyOpenSplit* > + let g:fuf_keyOpenSplit = '' +< + Key mapped to select completion item or finish input and open a + buffer/file in split new window + + *g:fuf_keyOpenVsplit* > + let g:fuf_keyOpenVsplit = '' +< + Key mapped to select completion item or finish input and open a + buffer/file in vertical-split new window. + + *g:fuf_keyOpenTabpage* > + let g:fuf_keyOpenTabpage = '' +< + + Key mapped to select completion item or finish input and open a + buffer/file in a new tab page. + + *g:fuf_keyPreview* > + let g:fuf_keyPreview = '' +< + + Key mapped to show information of selected completion item on + command-line area. This key makes sense only in modes supporting + preview. + + *g:fuf_keyNextMode* > + let g:fuf_keyNextMode = '' +< + Key mapped to switch to next mode. + + *g:fuf_keyPrevMode* > + let g:fuf_keyPrevMode = '' +< + Key mapped to switch to previous mode. + + *g:fuf_keyPrevPattern* > + let g:fuf_keyPrevPattern = '' +< + Key mapped to recall previous entered patten from history. + + *g:fuf_keyNextPattern* > + let g:fuf_keyNextPattern = '' +< + Key mapped to recall next entered patten from history. + + *g:fuf_keySwitchMatching* > + let g:fuf_keySwitchMatching = '' +< + Key mapped to switch between fuzzy matching and partial matching. + + *g:fuf_dataDir* > + let g:fuf_dataDir = '~/.vim-fuf-data' +< + Directory path to which data files is put. If empty string, + FuzzyFinder does not write data files. + + *g:fuf_abbrevMap* > + let g:fuf_abbrevMap = {} +< + |Dictionary|. Each value must be a |List|. All matchs of a + key in entered text is expanded with the value. + + *g:fuf_patternSeparator* > + let g:fuf_patternSeparator = ';' +< + String which sparates a input pattern into a primary pattern and + refining patterns. + + *g:fuf_promptHighlight* > + let g:fuf_promptHighlight = 'Question' +< + a highlight group name for a prompt string. + + *g:fuf_ignoreCase* > + let g:fuf_ignoreCase = 1 +< + If non-zero, FuzzyFinder ignores case in search patterns. + + *g:fuf_splitPathMatching* > + let g:fuf_splitPathMatching = 1 +< + If non-zero, matching with a primary pattern is divided into head part + and tail part and done individually. + + See also: |fuf-search-patterns| + + *g:fuf_fuzzyRefining* > + let g:fuf_fuzzyRefining = 0 +< + If non-zero, fuzzy matching is done with refining pattern instead of + partial matching. + + See also: |fuf-search-patterns| + + *g:fuf_reuseWindow* > + let g:fuf_reuseWindow = 1 +< + If non-zero and when FuzzyFinder opens a buffer which has already been + opened, it reuses a window containing the target buffer. + + *g:fuf_timeFormat* > + let g:fuf_timeFormat = '(%Y-%m-%d %H:%M:%S)' +< + String to format time string. See |strftime()| for details. + + *g:fuf_learningLimit* > + let g:fuf_learningLimit = 100 +< + Ceiling for the number of completion statistics to be stored. + + *g:fuf_enumeratingLimit* > + let g:fuf_enumeratingLimit = 50 +< + To speed up the response time, FuzzyFinder ends enumerating completion + items when found over this. + + *g:fuf_maxMenuWidth* > + let g:fuf_maxMenuWidth = 78 +< + If a length of a completion item is more than this, it is snipped in + completion menu. + + *g:fuf_previewHeight* > + let g:fuf_previewHeight = 0 +< + 'cmdheight' is set to this when a mode supporting preview is launched. + Information of selected completion item will be shown on command-line + area. If zero, preview feature is disabled. + + *g:fuf_autoPreview* > + let g:fuf_autoPreview = 0 +< + If non-zero, previews will be shown automatically. + + *g:fuf_useMigemo* > + let g:fuf_useMigemo = 0 +< + If non-zero, FuzzyFinder uses Migemo. + + *fuf-options-for-buffer-mode* +For Buffer Mode ~ + + *g:fuf_buffer_prompt* > + let g:fuf_buffer_prompt = '>Buffer[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_buffer_switchOrder* > + let g:fuf_buffer_switchOrder = 10 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *g:fuf_buffer_mruOrder* > + let g:fuf_buffer_mruOrder = 1 +< + If non-zero, completion items is sorted in order of recently used. + + *g:fuf_buffer_keyDelete* > + let g:fuf_buffer_keyDelete = '' +< + Key mapped to delete selected buffer. + + *fuf-options-for-file-mode* +For File Mode ~ + + *g:fuf_file_prompt* > + let g:fuf_file_prompt = '>File[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_file_switchOrder* > + let g:fuf_file_switchOrder = 20 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *g:fuf_file_exclude* > + let g:fuf_file_exclude = '\v\~$|\.(o|exe|dll|bak|orig|swp)$|(^|[/\\])\.(hg|git|bzr)($|[/\\])' +< + Regexp pattern for items which you want to exclude from completion + list. + + *fuf-options-for-coveragefile-mode* +For Coverage-File Mode ~ + + *g:fuf_coveragefile_prompt* > + let g:fuf_coveragefile_prompt = '>CoverageFile[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_coveragefile_switchOrder* > + let g:fuf_coveragefile_switchOrder = 30 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *g:fuf_coveragefile_exclude* > + let g:fuf_coveragefile_exclude = '\v\~$|\.(o|exe|dll|bak|orig|swp)$|(^|[/\\])\.(hg|git|bzr)($|[/\\])' +< + Regexp pattern for items which you want to exclude from completion + list. + + *g:fuf_coveragefile_globPatterns* > + let g:fuf_coveragefile_globPatterns = ['**/.*', '**/*'] +< + List of glob patterns to get file paths to be searched. + + See also: |glob()| + + *fuf-options-for-dir-mode* +For Directory Mode ~ + + *g:fuf_dir_prompt* > + let g:fuf_dir_prompt = '>Dir[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_dir_switchOrder* > + let g:fuf_dir_switchOrder = 40 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *g:fuf_dir_exclude* > + let g:fuf_dir_exclude = '\v(^|[/\\])\.(hg|git|bzr)($|[/\\])' +< + Regexp pattern for items which you want to exclude from completion + list. + + *fuf-options-for-mrufile-mode* +For MRU-File Mode ~ + + *g:fuf_mrufile_prompt* > + let g:fuf_mrufile_prompt = '>MRU-File[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_mrufile_switchOrder* > + let g:fuf_mrufile_switchOrder = 50 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *g:fuf_mrufile_exclude* > + let g:fuf_mrufile_exclude = '\v\~$|\.(o|exe|dll|bak|orig|sw[po])$|^(\/\/|\\\\|\/mnt\/|\/media\/)' +< + Regexp pattern for items which you want to exclude from completion + list. + + *g:fuf_mrufile_maxItem* > + let g:fuf_mrufile_maxItem = 200 +< + Ceiling for the number of MRU items to be stored. + + *g:fuf_mrufile_maxItemDir* > + let g:fuf_mrufile_maxItemDir = 50 +< + Ceiling for the number of parent directories of MRU items to be + stored, which are used for around search. + + *g:fuf_mrufile_keyExpand* > + let g:fuf_mrufile_keyExpand = '' +< + Key mapped to expand search range. + + *fuf-options-for-mrucmd-mode* +For MRU-Cmd Mode ~ + + *g:fuf_mrucmd_prompt* > + let g:fuf_mrucmd_prompt = '>MRU-Cmd[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_mrucmd_switchOrder* > + let g:fuf_mrucmd_switchOrder = 60 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *g:fuf_mrucmd_exclude* > + let g:fuf_mrucmd_exclude = '^$' +< + Regexp pattern for items which you want to exclude from completion + list. + + *g:fuf_mrucmd_maxItem* > + let g:fuf_mrucmd_maxItem = 200 +< + This is the ceiling for the number of MRU items to be stored. + + *fuf-options-for-bookmarkfile-mode* +For Bookmark-File Mode ~ + + *g:fuf_bookmarkfile_prompt* > + let g:fuf_bookmarkfile_prompt = '>BookmarkFile[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_bookmarkfile_switchOrder* > + let g:fuf_bookmarkfile_switchOrder = 70 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *g:fuf_bookmarkfile_searchRange* > + let g:fuf_bookmarkfile_searchRange = 400 +< + Number of lines which FuzzyFinder searches a matching line from + bookmarked position within. + + *g:fuf_bookmarkfile_keyDelete* > + let g:fuf_bookmarkfile_keyDelete = '' +< + Key mapped to delete selected bookmark. + + *fuf-options-for-bookmarkdir-mode* +For Bookmark-Dir Mode ~ + + *g:fuf_bookmarkdir_prompt* > + let g:fuf_bookmarkdir_prompt = '>BookmarkDir[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_bookmarkdir_switchOrder* > + let g:fuf_bookmarkdir_switchOrder = 80 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *g:fuf_bookmarkdir_keyDelete* > + let g:fuf_bookmarkdir_keyDelete = '' +< + Key mapped to delete selected bookmark. + + *fuf-options-for-tag-mode* +For Tag Mode ~ + + *g:fuf_tag_prompt* > + let g:fuf_tag_prompt = '>Tag[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_tag_switchOrder* > + let g:fuf_tag_switchOrder = 90 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *fuf-options-for-buffertag-mode* +For Buffer-Tag Mode ~ + + *g:fuf_buffertag_prompt* > + let g:fuf_buffertag_prompt = '>Buffer-Tag[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_buffertag_switchOrder* > + let g:fuf_buffertag_switchOrder = 100 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *g:fuf_buffertag_ctagsPath* > + let g:fuf_buffertag_ctagsPath = 'ctags' +< + Executable file path of Ctags. + + *fuf-options-for-taggedfile-mode* +For Tagged-File Mode ~ + + *g:fuf_taggedfile_prompt* > + let g:fuf_taggedfile_prompt = '>Tagged-File[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_taggedfile_switchOrder* > + let g:fuf_taggedfile_switchOrder = 110 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *fuf-options-for-jumplist-mode* +For Jump-List Mode ~ + + *g:fuf_jumplist_prompt* > + let g:fuf_jumplist_prompt = '>Jump-List[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_jumplist_switchOrder* > + let g:fuf_jumplist_switchOrder = 120 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *fuf-options-for-changelist-mode* +For Change-List Mode ~ + + *g:fuf_changelist_prompt* > + let g:fuf_changelist_prompt = '>Change-List[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_changelist_switchOrder* > + let g:fuf_changelist_switchOrder = 130 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *fuf-options-for-quickfix-mode* +For Quickfix Mode ~ + + *g:fuf_quickfix_prompt* > + let g:fuf_quickfix_prompt = '>Quickfix[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_quickfix_switchOrder* > + let g:fuf_quickfix_switchOrder = 140 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *fuf-options-for-line-mode* +For Line Mode ~ + + *g:fuf_line_prompt* > + let g:fuf_line_prompt = '>Line[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_line_switchOrder* > + let g:fuf_line_switchOrder = 150 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + *fuf-options-for-help-mode* +For Help Mode ~ + + *g:fuf_help_prompt* > + let g:fuf_help_prompt = '>Help[]>' +< + Prompt string. "[]" will be substituted with indicators. + + *g:fuf_help_switchOrder* > + let g:fuf_help_switchOrder = 160 +< + Number of order for switching to the next/previous mode. If negative + number, Fuzzyfinder never switches to this mode. + + +============================================================================== +VIMRC EXAMPLE *fuf-vimrc-example* + +> + let g:fuf_modesDisable = [] + let g:fuf_mrufile_maxItem = 400 + let g:fuf_mrucmd_maxItem = 400 + nnoremap sj :FufBuffer + nnoremap sk :FufFileWithCurrentBufferDir + nnoremap sK :FufFileWithFullCwd + nnoremap s :FufFile + nnoremap sl :FufCoverageFileChange + nnoremap sL :FufCoverageFileChange + nnoremap s :FufCoverageFileRegister + nnoremap sd :FufDirWithCurrentBufferDir + nnoremap sD :FufDirWithFullCwd + nnoremap s :FufDir + nnoremap sn :FufMruFile + nnoremap sN :FufMruFileInCwd + nnoremap sm :FufMruCmd + nnoremap su :FufBookmarkFile + nnoremap s :FufBookmarkFileAdd + vnoremap s :FufBookmarkFileAddAsSelectedText + nnoremap si :FufBookmarkDir + nnoremap s :FufBookmarkDirAdd + nnoremap st :FufTag + nnoremap sT :FufTag! + nnoremap s :FufTagWithCursorWord! + nnoremap s, :FufBufferTag + nnoremap s< :FufBufferTag! + vnoremap s, :FufBufferTagWithSelectedText! + vnoremap s< :FufBufferTagWithSelectedText + nnoremap s} :FufBufferTagWithCursorWord! + nnoremap s. :FufBufferTagAll + nnoremap s> :FufBufferTagAll! + vnoremap s. :FufBufferTagAllWithSelectedText! + vnoremap s> :FufBufferTagAllWithSelectedText + nnoremap s] :FufBufferTagAllWithCursorWord! + nnoremap sg :FufTaggedFile + nnoremap sG :FufTaggedFile! + nnoremap so :FufJumpList + nnoremap sp :FufChangeList + nnoremap sq :FufQuickfix + nnoremap sy :FufLine + nnoremap sh :FufHelp + nnoremap se :FufEditDataFile + nnoremap sr :FufRenewCache +< + +============================================================================== +SPECIAL THANKS *fuf-thanks* + +- Vincent Wang +- Ingo Karkat +- Nikolay Golubev +- Brian Doyle +- id:secondlife +- Nathan Neff + + +============================================================================== +CHANGELOG *fuf-changelog* + +4.2.2: + - Fixed a bug that unloaded buffers weren't covered by FufBufferTagAll. + +4.2.1: + - Improved response of Buffer-Tag mode. + - Fixed a bug that buffers which had been opened weren't listed in + Coverage-File mode + - Fixed a bug that tag entries including tab characters weren't parsed + correctly in Coverage-File mode + +4.2: + - L9 library (vimscript #3252) version 1.1 is required. + - Added Buffer-Tag mode, inspired by taglist.vim (vimscript #273). + - Added :FufMruFileInCwd command. + +4.1.1: + - Fixed a bug causing a error in MRU-File mode. + +4.1: + - Added Bookmark-Dir mode. + - Added Bookmark-File mode and removed Bookmark mode. + - Changed the filename to store data of Coverage-File mode, from + '~/.vim-fuf-data/coveragefile/items' to + '~/.vim-fuf-data/coveragefile/coverages' . + - Fixed a bug that floating point numbers weren't evaluated correctly and + caused errors on some non-English locales. + - Removed Around-MRU-File mode and integrated its feature to MRU-File mode. + +4.0: + - From this version, L9 library (vimscript #3252) is required. + - Added Coverage-File mode for users wanting something like TextMate's + command-t. (But I've never used it.) + - Added Around-MRU-File mode. (Too slow. There is room for improvement.) + - Added new feature which deletes selected buffer with FuzzyFinder and + g:fuf_buffer_keyDelete option. + - Added new feature which allows to set one-time options/variables with + fuf#setOneTimeVariables() function. + - Added g:fuf_dataDir option and removed g:fuf_infoFile, + g:g:fuf_tag_cache_dir, g:fuf_taggedfile_cache_dir, and + g:fuf_help_cache_dir options. + - Added :FufEditDataFile command and removed :FufEditInfo command. + - Added g:fuf_fuzzyRefining option. + - Added new feature which is auto-preview and g:fuf_autoPreview option. + - Changed the default value of g:fuf_previewHeight to 0 in order to disable + preview feature. There is an unfixable problem which is caused by a Vim's + bug. + - Changed the default value of g:fuf_modesDisable option. + - Changed the default value of g:fuf_*_switchOrder options. + - Improved speed of changing buffers. + - Improved the way to add user-defined mode. + - Fixed a bug that FuzzyFinder caused reseting window layout. + - Removed g:fuf_smartBs option. Use instead. + +3.5: + - Added Line mode. + - Added Help mode. + - Added key mapping to switch between fuzzy matching and partial matching. + - Changed the default values of g:fuf_file_exclude for ignoring "*.dll". + - Changed Tag mode and Tagged-File mode to cache parsed data to files in + "~/.vim-fuf-cache/". + - Fixed a bug that repeating preview key produced no effect. + - Fixed a bug that File mode and Directory mode didn't list items in a + directory whose name includes uppercase characters. (Thanks, ryo7000) + +3.4: + - Added new feature which makes it possible to preview selected completion + item. + - Changed matching rules and added g:fuf_splitPathMatching. + - Changed sorting rules. + - Changed the default values of g:fuf_file_exclude and g:fuf_dir_exclude in + order to ignore ".hg", ".git", and ".bzr" directories. + - Changed the default value of g:fuf_mrufile_exclude in order to ignore + network files (\\*) on Windows and ignore /mnt/* and /media/* on Unix like + systems. + - Fixed a bug that an exclude pattern of File, Dir, and Callback-File mode + can't be changed. + +3.3: + - Added Jump-List mode, Change-List mode, and Quickfix mode which enable + jumps with jump list, change list, and quickfix list. + - Added new feature which deletes selected bookmark with FuzzyFinder and + g:fuf_bookmark_keyDelete option. + - Changed default values of g:fuf_keyPrevPattern. + - Changed to show error message when incompatible with a installed vim. + +3.2: + - Added g:fuf_promptHighlight option to integrate such options for each + mode. + - Changed APIs of Given-File, Given-Directory, Given-Command, Callback-File, + and Callback-Item modes to be able to set a prompt string. + - Changed default values of g:fuf_keyPrevPattern and g:fuf_keyNextPattern. + - Fixed a bug that MRU-File data was not updated When a file was opened with + FuzzyFinder. + - Fixed a bug with scoring matchings for sorting. Thanks to Vincent. + - Brought back the removed feature which is switching to an other mode in + FuzzyFinder. + +3.1: + - Added new feature to recall patterns which have been entered before from + history. + +3.0: + - Redesigned the whole plugin for improvements of maintainability and + performance. "fuzzyfinder" is abbreviated to "fuf" in the sorce code and + filenames. All commands and options are renamed. + - Added new feature which is refining pattern. + - Improved the rules for sorting completion items. Thanks to the suggestion + by Nathan, the rule for boundary matching was implemented. + - Changed to open one line buffer of FuzzyFinder with :topleft command + instead of :leftabove. The window will alway appear at the top and occupy + the full with of the vim window. Thanks to Jan Christoph. + - Changed default filename of information file. + - Changed MRU-File mode and MRU-Command mode to be disabled by default + due to performance and side effect issues. + - Removed the feature which is switching to an other mode in FuzzyFinder. + - Removed the feature which is temporarily switching 'ignorecase' in + FuzzyFinder. + +2.22.3: + - Fixed a bug that Fuzzyfinder could not open files with '$' in the name on + Windows. + +2.22.2: + - Changed to consider a length of a date/time string when abbreviates long + completion items. + - Fixed a bug that '**/' pattern did not search for files directly under the + current working directory in File mode. Thanks to Martin for reporting. + +2.22.1: + - Fixed a bug that Fuzzyfinder could not expand abbreviations to patterns + including '\' correctly. + - Fixed to show item number in Given-File, Given-Directory, and + Given-Command mode. + +2.22.0: + - More improved the abbreviation method for long completion items. + - Added Given-File mode for third-party script to select a file from a given + list and open. + - Added Given-Directory mode for third-party script to select a directory + from a given list and change current working directory to it. + - Added Given-Command mode for third-party script to select a command from a + given list and execute. + - Changed ways to launch Callback-File mode and Callback-item mode. + +2.21.0: + - Improved a method of trimming long completion items. Thanks to Andy, + pyrhockz, and Nathan. + - Changed not to map command-line for MRU-Command mode if + g:FuzzyFinderOptions.MruCmd.mode_available is set 0 before loading + fuzzyfinder.vim. + - Added Callback-File mode and Callback-Item mode for third-party script to + find a file/directory or an item from a given list using Fuzzyfinder. + - Changed not to append ".." to a completion menu in File/Directory mode. + Use dot sequence feature. + - Changed default value of g:FuzzyFinderOptions.File.excluded_path option. + - Changed default value of g:FuzzyFinderOptions.Dir.excluded_path option. + - Fixed a bug that couldn't jump to a tag. Thanks to Thinca. + +2.20: + - Added help files which are doc/fuzzyfinder.txt and doc/fuzzyfinder.jax. + - Fixed a bug that an error occurs if current directory included spaces. + Thanks id:cho45 and id:secondlife. + - Implemented a feature to reuse a window containing target buffer. + - Added g:FuzzyFinderOptions.Buffer.reuse_window option. + - Added g:FuzzyFinderOptions.File.reuse_window option. + - Added g:FuzzyFinderOptions.MruFile.reuse_window option. + - Added g:FuzzyFinderOptions.Bookmark.reuse_window option. + - Added g:FuzzyFinderOptions.TaggedFile.reuse_window option. + - Changed to use 'omnifunc' instead of 'completefunc'. Now you can use + to delete all entered characters. + - Changed default value of g:FuzzyFinderOptions.Base.key_open_tab option. + - Changed default value of g:FuzzyFinderOptions.Base.key_next_mode option. + - Changed default value of g:FuzzyFinderOptions.Base.key_prev_mode option. + - Changed default value of g:FuzzyFinderOptions.Base.key_ignore_case option. + - Changed to truncate long completion items from the head instead of tail. + - Added g:FuzzyFinderOptions.Base.max_menu_width option instead of + g:FuzzyFinderOptions.Base.trim_length option. + - Added :FuzzyFinderFileWithFullCwd command. + - Added :FuzzyFinderFileWithCurrentBufferDir command. + - Added :FuzzyFinderDirWithFullCwd command. + - Added :FuzzyFinderDirWithCurrentBufferDir command. + - Added :FuzzyFinderTagWithCursorWord command. + - Renamed :FuzzyFinderRemoveCache command to :FuzzyFinderRenewCache. + +2.19: + - Changed MRU-File mode that always formats completion items to be relative + to the home directory. + - Fixed a bug that a file was opened in an unintended window with Tag List + plugin. Thanks Alexey. + - Fixed a bug that garbage characters were entered when switched current + mode. Thanks id:lugecy. + +2.18: + - Improved rules for the sorting of completion items. + - Changed not to learn a completion if an entered pattern is empty. + - Fixed a bug that Buffer mode did not work. Thanks ryo7000. + +2.17: + - Introduced a learning system for the sorting of completion items. + - Added g:FuzzyFinderOptions.Base.learning_limit option. + - Changed the specification of the information file. Please remove your + information file for Fuzzyfinder. + +2.16: + - Improved response time by caching in MRU-File mode. + - Fixed a bug in Bookmark mode that Fuzzyfinder did not jump to the + Bookmarked line number when Bookmarked pattern was not found. + +2.15: + - Added Bookmark mode. + - Removed Favorite-file mode. Use Bookmark mode instead. + - Fixed not to record a entry of input() in MRU-Command mode. + +2.14: + - Changed to show buffer status in Buffer mode. + - Fixed a bug that an error occurs when nonexistent buffer-name was entered + in Buffer mode. Thanks Maxim Kim. + - Added 'enumerating_limit' option. Thanks id:secondlife. + - Removed 'matching_limit' option. Use 'enumerating_limit' instead. + +2.13: + - Fixed a bug that a directory disappeared when a file in that directory was + being opened in File/Mru-File mode. + +2.12: + - Changed to be able to show completion items in the order of recently used + in Buffer mode. + - Added g:FuzzyFinderOptions.Buffer.mru_order option. + +2.11: + - Changed that a dot sequence of entered pattern is expanded to parent + directories in File/Dir mode. + E.g.: "foo/...bar" -> "foo/../../bar" + - Fixed a bug that a prompt string was excessively inserted. + +2.10: + - Changed not to show a current buffer in a completion menu. + - Fixed a bug that a filename to open was not been escaped. + - Added 'prompt' option. + - Added 'prompt_highlight' option. + - Removed g:FuzzyFinderOptions.MruFile.no_special_buffer option. + +2.9: + - Enhanced behavior in Fuzzyfinder and added 'smart_bs' option. + - Fixed a bug that entered pattern was not been escaped. + - Fixed not to insert "zv" with "c/pattern" command in Normal mode. + - Avoid the slow down problem caused by filereadable() check for the MRU + information in BufEnter/BufWritePost. + +2.8.1: + - Fixed a bug caused by the non-escaped buffer name "[Fuzzyfinder]". + - Fixed a command to open in a new tab page in Buffer mode. +2.8: + - Added 'trim_length' option. + - Added 'switch_order' option. + - Fixed a bug that entered command did not become the newest in the history. + - Fixed a bug that folds could not open with in a command-line when + searching. + - Removed 'excluded_indicator' option. Now a completion list in Buffer mode + is the same as a result of :buffers. + +2.7: + - Changed to find an item whose index is matched with the number suffixed + with entered pattern. + - Fixed the cache bug after changing current directory in File mode. + +2.6.2: + - Fixed not to miss changes in options when updates the MRU information. + +2.6.1: + - Fixed a bug related to floating-point support. + - Added support for GetLatestVimScripts. + +2.6: + - Revived MRU-command mode. The problem with a command-line abbreviation was + solved. + - Changed the specification of the information file. + - Added :FuzzyFinderEditInfo command. + +2.5.1: + - Fixed to be able to match "foo/./bar" by "foo/**/bar" in File mode. + - Fixed to be able to open a space-containing file in File mode. + - Fixed to honor the current working directory properly in File mode. + +2.5: + - Fixed the bug that a wrong initial text is entered after switching to a + next mode. + - Fixed the bug that it does not return to previous window after leaving + Fuzzyfinder one. + +2.4: + - Fixed the bug that Fuzzyfinder fails to open a file caused by auto-cd + plugin/script. + +2.3: + - Added a key mapping to open items in a new tab page and + g:FuzzyFinderOptions.Base.key_open_tab option. + - Changed to show Fuzzyfinder window above last window even if 'splitbelow' + was set. + - Changed to set nocursorline and nocursorcolumn in Fuzzyfinder. + - Fixed not to push up a buffer number unlimitedly. + +2.2: + - Added new feature, which is the partial matching. + - Fixed the bug that an error occurs when "'" was entered. + +2.1: + - Restructured the option system AGAIN. Sorry :p + - Changed to inherit a typed text when switching a mode without leaving + Insert mode. + - Changed commands which launch explorers to be able to take a argument for + initial text. + - Changed to complete file names by relative path and not full path in the + buffer/mru-file/tagged-file mode. + - Changed to highlight a typed text when the completion item was not found + or the completion process was aborted. + - Changed to create caches for each tag file and not working directory in + the tag/tagged-file mode. + - Fixed the bug that the buffer mode couldn't open a unnamed buffer. + - Added 'matching_limit' option. + - Removed 'max_match' option. Use 'matching_limit' option instead. + - Removed 'initial_text' option. Use command argument instead. + - Removed the MRU-command mode. + +2.0: + - Added the tag mode. + - Added the tagged-file mode. + - Added :FuzzyFinderRemoveCache command. + - Restructured the option system. many options are changed names or default + values of some options. + - Changed to hold and reuse caches of completion lists by default. + - Changed to set filetype 'fuzzyfinder'. + - Disabled the MRU-command mode by default because there are problems. + - Removed FuzzyFinderAddMode command. + +1.5: + - Added the directory mode. + - Fixed the bug that it caused an error when switch a mode in Insert mode. + - Changed g:FuzzyFinder_KeySwitchMode type to a list. + +1.4: + - Changed the specification of the information file. + - Added the MRU-commands mode. + - Renamed :FuzzyFinderAddFavorite command to :FuzzyFinderAddFavFile. + - Renamed g:FuzzyFinder_MruModeVars option to g:FuzzyFinder_MruFileModeVars. + - Renamed g:FuzzyFinder_FavoriteModeVars option to + g:FuzzyFinder_FavFileModeVars. + - Changed to show registered time of each item in MRU/favorite mode. + - Added 'timeFormat' option for MRU/favorite modes. + +1.3: + - Fixed a handling of multi-byte characters. + +1.2: + - Added support for Migemo. (Migemo is Japanese search method.) + +1.1: + - Added the favorite mode. + - Added new features, which are abbreviations and multiple search. + - Added 'abbrevMap' option for each mode. + - Added g:FuzzyFinder_MruModeVars['ignoreSpecialBuffers'] option. + - Fixed the bug that it did not work correctly when a user have mapped + or . + +1.0: + - Added the MRU mode. + - Added commands to add and use original mode. + - Improved the sorting algorithm for completion items. + - Added 'initialInput' option to automatically insert a text at the + beginning of a mode. + - Changed that 'excludedPath' option works for the entire path. + - Renamed some options. + - Changed default values of some options. + - Packed the mode-specific options to dictionaries. + - Removed some options. + +0.6: + - Fixed some bugs. + +0.5: + - Improved response by aborting processing too many items. + - Changed to be able to open a buffer/file not only in previous window but + also in new window. + - Fixed a bug that recursive searching with '**' does not work. + - Added g:FuzzyFinder_CompletionItemLimit option. + - Added g:FuzzyFinder_KeyOpen option. + +0.4: + - Improved response of the input. + - Improved the sorting algorithm for completion items. It is based on the + matching level. 1st is perfect matching, 2nd is prefix matching, and 3rd + is fuzzy matching. + - Added g:FuzzyFinder_ExcludePattern option. + - Removed g:FuzzyFinder_WildIgnore option. + - Removed g:FuzzyFinder_EchoPattern option. + - Removed g:FuzzyFinder_PathSeparator option. + - Changed the default value of g:FuzzyFinder_MinLengthFile from 1 to 0. + +0.3: + - Added g:FuzzyFinder_IgnoreCase option. + - Added g:FuzzyFinder_KeyToggleIgnoreCase option. + - Added g:FuzzyFinder_EchoPattern option. + - Changed the open command in a buffer mode from ":edit" to ":buffer" to + avoid being reset cursor position. + - Changed the default value of g:FuzzyFinder_KeyToggleMode from to + because does not work on some CUI environments. + - Changed to avoid being loaded by Vim before 7.0. + - Fixed a bug with making a fuzzy pattern which has '\'. + +0.2: + - A bug it does not work on Linux is fixed. + +0.1: + - First release. + + +============================================================================== +ABOUT *fuf-about* *fuf-contact* *fuf-author* + +Author: Takeshi NISHIDA +Licence: MIT Licence +URL: http://www.vim.org/scripts/script.php?script_id=1984 + http://bitbucket.org/ns9tks/vim-fuzzyfinder/ + +Bugs/Issues/Suggestions/Improvements ~ + +Please submit to http://bitbucket.org/ns9tks/vim-fuzzyfinder/issues/ . + +============================================================================== + vim:tw=78:ts=8:ft=help:norl: diff --git a/doc/l9.jax b/doc/l9.jax new file mode 100644 index 0000000..c84d45f --- /dev/null +++ b/doc/l9.jax @@ -0,0 +1,55 @@ +*l9.txt* Vimスクリプトライブラリ + + Copyright (c) 2009-2010 Takeshi NISHIDA + +l9 *l9* + +概要 |l9-introduction| +インストール |l9-installation| +使い方 |l9-usage| +CHANGELOG |l9-changelog| +あばうと |l9-about| + +============================================================================== +概要 *l9-introduction* + +l9はVimスクリプトの関数やコマンドを提供するライブラリです。 + + +============================================================================== + インストール *l9-installation* + +ZIPファイルをランタイムディレクトリに展開します。 + +以下のようにファイルが配置されるはずです。 +> + /plugin/l9.vim + /doc/l9.txt + ... +< +もしランタイムディレクトリが多数のプラグインでごちゃごちゃになるのが嫌なら、各 +プラグインを個別のディレクトリに配置し、そのディレクトリのパスを 'runtimepath' +に追加してください。アンインストールも楽になります。 + +その後、ヘルプを有効にするためにタグファイルを更新してください。詳しくは +|add-local-help|を参照してください。 + +============================================================================== +使い方 *l9-usage* + +ソースコードを参照してください。 + +============================================================================== +あばうと *l9-about* *l9-contact* *l9-author* + +作者: Takeshi NISHIDA +ライセンス: MIT Licence +URL: http://www.vim.org/scripts/script.php?script_id=3252 + http://bitbucket.org/ns9tks/vim-l9/ + +バグや要望など ~ + +こちらへどうぞ: http://bitbucket.org/ns9tks/vim-l9/issues/ + +============================================================================== + vim:tw=78:ts=8:ft=help:norl: diff --git a/doc/l9.txt b/doc/l9.txt new file mode 100644 index 0000000..8664ad4 --- /dev/null +++ b/doc/l9.txt @@ -0,0 +1,73 @@ +*l9.txt* Vim-script library + + Copyright (c) 2009-2010 Takeshi NISHIDA + +l9 *l9* + +INTRODUCTION |l9-introduction| +INSTALLATION |l9-installation| +USAGE |l9-usage| +CHANGELOG |l9-changelog| +ABOUT |l9-about| + +============================================================================== +INTRODUCTION *l9-introduction* + +l9 is a Vim-script library, which provides some utility functions and commands +for programming in Vim. + +============================================================================== + INSTALLATION *l9-installation* + +Put all files into your runtime directory. If you have the zip file, extract +it to your runtime directory. + +You should place the files as follows: +> + /plugin/l9.vim + /doc/l9.txt + ... +< +If you are disgusted to make your runtime directory confused with a lot of +plugins, put each of the plugins into a directory individually and just add +the directory path to 'runtimepath'. It's easy to uninstall the plugin. + +Then update your help tags files to enable fuzzyfinder help. See +|add-local-help| for details. + +============================================================================== +USAGE *l9-usage* + +See source code. + +============================================================================== +CHANGELOG *l9-changelog* + +1.1: + - Added l9#zip() + - Added l9#tempvariables#getList() + - Changed l9#guardScriptLoading() + - Removed l9#tempvariables#swap() + +1.0.1: + - Fixed a bug that floating point numbers weren't evaluated correctly and + caused errors on some non-English locales. + +1.0: + - First release. + + +============================================================================== +ABOUT *l9-about* *l9-contact* *l9-author* + +Author: Takeshi NISHIDA +Licence: MIT Licence +URL: http://www.vim.org/scripts/script.php?script_id=3252 + http://bitbucket.org/ns9tks/vim-l9/ + +Bugs/Issues/Suggestions/Improvements ~ + +Please submit to http://bitbucket.org/ns9tks/vim-l9/issues/ . + +============================================================================== + vim:tw=78:ts=8:ft=help:norl: diff --git a/plugged/vim-easy-align b/plugged/vim-easy-align new file mode 160000 index 0000000..1cd724d --- /dev/null +++ b/plugged/vim-easy-align @@ -0,0 +1 @@ +Subproject commit 1cd724dc239c3a0f7a12e0fac85945cc3dbe07b0 diff --git a/plugin/fuf.vim b/plugin/fuf.vim new file mode 100644 index 0000000..9826dab --- /dev/null +++ b/plugin/fuf.vim @@ -0,0 +1,158 @@ +"============================================================================= +" Copyright (c) 2007-2010 Takeshi NISHIDA +" +" GetLatestVimScripts: 1984 1 :AutoInstall: FuzzyFinder +"============================================================================= +" LOAD GUARD {{{1 + +try + if !l9#guardScriptLoading(expand(':p'), 702, 101, []) + finish + endif +catch /E117/ + echoerr '***** L9 library must be installed! *****' + finish +endtry + +" }}}1 +"============================================================================= +" LOCAL FUNCTIONS {{{1 + +" +function s:initialize() + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_modesDisable' , [ 'mrufile', 'mrucmd', ]) + call l9#defineVariableDefault('g:fuf_keyOpen' , '') + call l9#defineVariableDefault('g:fuf_keyOpenSplit' , '') + call l9#defineVariableDefault('g:fuf_keyOpenVsplit' , '') + call l9#defineVariableDefault('g:fuf_keyOpenTabpage' , '') + call l9#defineVariableDefault('g:fuf_keyPreview' , '') + call l9#defineVariableDefault('g:fuf_keyNextMode' , '') + call l9#defineVariableDefault('g:fuf_keyPrevMode' , '') + call l9#defineVariableDefault('g:fuf_keyPrevPattern' , '') + call l9#defineVariableDefault('g:fuf_keyNextPattern' , '') + call l9#defineVariableDefault('g:fuf_keySwitchMatching', '') + call l9#defineVariableDefault('g:fuf_dataDir' , '~/.vim-fuf-data') + call l9#defineVariableDefault('g:fuf_abbrevMap' , {}) + call l9#defineVariableDefault('g:fuf_patternSeparator' , ';') + call l9#defineVariableDefault('g:fuf_promptHighlight' , 'Question') + call l9#defineVariableDefault('g:fuf_ignoreCase' , 1) + call l9#defineVariableDefault('g:fuf_splitPathMatching', 1) + call l9#defineVariableDefault('g:fuf_fuzzyRefining' , 0) + call l9#defineVariableDefault('g:fuf_smartBs' , 1) + call l9#defineVariableDefault('g:fuf_reuseWindow' , 1) + call l9#defineVariableDefault('g:fuf_timeFormat' , '(%Y-%m-%d %H:%M:%S)') + call l9#defineVariableDefault('g:fuf_learningLimit' , 100) + call l9#defineVariableDefault('g:fuf_enumeratingLimit' , 50) + call l9#defineVariableDefault('g:fuf_maxMenuWidth' , 78) + call l9#defineVariableDefault('g:fuf_previewHeight' , 0) + call l9#defineVariableDefault('g:fuf_autoPreview' , 0) + call l9#defineVariableDefault('g:fuf_useMigemo' , 0) + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_buffer_prompt' , '>Buffer[]>') + call l9#defineVariableDefault('g:fuf_buffer_switchOrder', 10) + call l9#defineVariableDefault('g:fuf_buffer_mruOrder' , 1) + call l9#defineVariableDefault('g:fuf_buffer_keyDelete' , '') + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_file_prompt' , '>File[]>') + call l9#defineVariableDefault('g:fuf_file_switchOrder', 20) + call l9#defineVariableDefault('g:fuf_file_exclude' , '\v\~$|\.(o|exe|dll|bak|orig|sw[po])$|(^|[/\\])\.(hg|git|bzr)($|[/\\])') + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_coveragefile_prompt' , '>CoverageFile[]>') + call l9#defineVariableDefault('g:fuf_coveragefile_switchOrder', 30) + call l9#defineVariableDefault('g:fuf_coveragefile_exclude' , '\v\~$|\.(o|exe|dll|bak|orig|sw[po])$|(^|[/\\])\.(hg|git|bzr)($|[/\\])') + call l9#defineVariableDefault('g:fuf_coveragefile_globPatterns', ['**/.*', '**/*']) + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_dir_prompt' , '>Dir[]>') + call l9#defineVariableDefault('g:fuf_dir_switchOrder', 40) + call l9#defineVariableDefault('g:fuf_dir_exclude' , '\v(^|[/\\])\.(hg|git|bzr)($|[/\\])') + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_mrufile_prompt' , '>MRU-File[]>') + call l9#defineVariableDefault('g:fuf_mrufile_switchOrder', 50) + call l9#defineVariableDefault('g:fuf_mrufile_exclude' , '\v\~$|\.(o|exe|dll|bak|orig|sw[po])$|^(\/\/|\\\\|\/mnt\/|\/media\/)') + call l9#defineVariableDefault('g:fuf_mrufile_maxItem' , 200) + call l9#defineVariableDefault('g:fuf_mrufile_maxItemDir' , 50) + call l9#defineVariableDefault('g:fuf_mrufile_keyExpand' , '') + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_mrucmd_prompt' , '>MRU-Cmd[]>') + call l9#defineVariableDefault('g:fuf_mrucmd_switchOrder', 60) + call l9#defineVariableDefault('g:fuf_mrucmd_exclude' , '^$') + call l9#defineVariableDefault('g:fuf_mrucmd_maxItem' , 200) + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_bookmarkfile_prompt' , '>Bookmark-File[]>') + call l9#defineVariableDefault('g:fuf_bookmarkfile_switchOrder', 70) + call l9#defineVariableDefault('g:fuf_bookmarkfile_searchRange', 400) + call l9#defineVariableDefault('g:fuf_bookmarkfile_keyDelete' , '') + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_bookmarkdir_prompt' , '>Bookmark-Dir[]>') + call l9#defineVariableDefault('g:fuf_bookmarkdir_switchOrder', 80) + call l9#defineVariableDefault('g:fuf_bookmarkdir_keyDelete' , '') + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_tag_prompt' , '>Tag[]>') + call l9#defineVariableDefault('g:fuf_tag_switchOrder', 90) + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_buffertag_prompt' , '>Buffer-Tag[]>') + call l9#defineVariableDefault('g:fuf_buffertag_switchOrder', 100) + call l9#defineVariableDefault('g:fuf_buffertag_ctagsPath' , 'ctags') + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_taggedfile_prompt' , '>Tagged-File[]>') + call l9#defineVariableDefault('g:fuf_taggedfile_switchOrder', 110) + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_jumplist_prompt' , '>Jump-List[]>') + call l9#defineVariableDefault('g:fuf_jumplist_switchOrder', 120) + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_changelist_prompt' , '>Change-List[]>') + call l9#defineVariableDefault('g:fuf_changelist_switchOrder', 130) + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_quickfix_prompt' , '>Quickfix[]>') + call l9#defineVariableDefault('g:fuf_quickfix_switchOrder', 140) + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_line_prompt' , '>Line[]>') + call l9#defineVariableDefault('g:fuf_line_switchOrder', 150) + "--------------------------------------------------------------------------- + call l9#defineVariableDefault('g:fuf_help_prompt' , '>Help[]>') + call l9#defineVariableDefault('g:fuf_help_switchOrder', 160) + "--------------------------------------------------------------------------- + command! -bang -narg=0 FufEditDataFile call fuf#editDataFile() + command! -bang -narg=0 FufRenewCache call s:renewCachesOfAllModes() + "--------------------------------------------------------------------------- + call fuf#addMode('buffer') + call fuf#addMode('file') + call fuf#addMode('coveragefile') + call fuf#addMode('dir') + call fuf#addMode('mrufile') + call fuf#addMode('mrucmd') + call fuf#addMode('bookmarkfile') + call fuf#addMode('bookmarkdir') + call fuf#addMode('tag') + call fuf#addMode('buffertag') + call fuf#addMode('taggedfile') + call fuf#addMode('jumplist') + call fuf#addMode('changelist') + call fuf#addMode('quickfix') + call fuf#addMode('line') + call fuf#addMode('help') + call fuf#addMode('givenfile') + call fuf#addMode('givendir') + call fuf#addMode('givencmd') + call fuf#addMode('callbackfile') + call fuf#addMode('callbackitem') + "--------------------------------------------------------------------------- +endfunction + +" +function s:renewCachesOfAllModes() + for m in fuf#getModeNames() + call fuf#{m}#renewCache() + endfor +endfunction + +" }}}1 +"============================================================================= +" INITIALIZATION {{{1 + +call s:initialize() + +" }}}1 +"============================================================================= +" vim: set fdm=marker: diff --git a/plugin/l9.vim b/plugin/l9.vim new file mode 100644 index 0000000..03613e4 --- /dev/null +++ b/plugin/l9.vim @@ -0,0 +1,108 @@ +"============================================================================= +" Copyright (C) 2009-2010 Takeshi NISHIDA +" +" GetLatestVimScripts: 3252 1 :AutoInstall: L9 +"============================================================================= +" LOAD GUARD {{{1 + +if !l9#guardScriptLoading(expand(':p'), 702, 0, []) + finish +endif + +" }}}1 +"============================================================================= +" OPTIONS: {{{1 + +call l9#defineVariableDefault('g:l9_balloonly', 'balloonly.exe') + +" }}}1 +"============================================================================= +" ASSERTION: {{{1 + +" This command has effect only if $L9_DEBUG is non-zero. +" Used as follows: +" L9Assert a:i > 0 +" This command can't interpret script-local variables directly. +" NG: L9Assert s:a == 1 +" OK: execute 'L9Assert ' . s:a . ' == 1' +" +if $L9_DEBUG + command -nargs=* L9Assert call eval(() ? 0 : s:handleFailedAssersion()) + + function s:handleFailedAssersion(expr) + echoerr '[L9Assert] Assersion failure: ' . a:expr + if input('[L9Assert] Continue? (Y/N) ', 'Y') !=? 'Y' + throw 'L9Assert ' . a:expr + endif + endfunction + +else + command -nargs=* L9Assert : +endif + +" }}}1 +"============================================================================= +" TIMER: {{{1 + +" These commands have effect only if $L9_TIMER is non-zero. +" Used as follows: +" L9Timer foo +" ... (1) +" L9Timer bar +" ... (2) +" L9TimerStop +" ... +" L9TimerDump <- shows each elapsed time of (1) and (2) +" +if $L9_TIMER + command -nargs=1 L9Timer call s:timerBegin() + command -nargs=0 L9TimerStop call s:timerStop() + command -nargs=0 L9TimerDump call s:timerDump() + + let s:timerData = [] + let s:timerTagMaxLen = 0 + + function s:timerBegin(tag) + L9TimerStop + let s:timerCurrent = {'tag': strftime('%c ') . a:tag . ' ', 'time': reltime()} + let s:timerTagMaxLen = max([len(s:timerCurrent.tag), s:timerTagMaxLen]) + endfunction + + function s:timerStop() + if !exists('s:timerCurrent') + return + endif + let s:timerCurrent.time = reltimestr(reltime(s:timerCurrent.time)) + call add(s:timerData, s:timerCurrent) + unlet s:timerCurrent + endfunction + + function s:timerDump() + L9TimerStop + let lines = map(s:timerData, 'v:val.tag . repeat(" ", s:timerTagMaxLen - len(v:val.tag)) . v:val.time') + call l9#tempbuffer#openReadOnly('[l9-timer]', '', lines, 0, 0, 0, {}) + let s:timerData = [] + let s:timerTagMaxLen = 0 + endfunction + +else + command -nargs=1 L9Timer : + command -nargs=0 L9TimerStop : + command -nargs=0 L9TimerDump : +endif + +" }}}1 +"============================================================================= +" GREP BUFFER: {{{1 + +" Grep for current buffer by l9#grepBuffers() +" Used as :L9GrepBuffer/pattern +command -nargs=? L9GrepBuffer call l9#grepBuffers(, [bufnr('%')]) + +" Grep for all buffers by l9#grepBuffers() +" Used as :L9GrepBufferAll/pattern +command -nargs=? L9GrepBufferAll call l9#grepBuffers(, range(1, bufnr('$'))) + +" }}}1 +"============================================================================= +" vim: set fdm=marker: -- cgit v1.2.3