From e561be78fc0b570ba658ac392e43be579af85529 Mon Sep 17 00:00:00 2001 From: Kolan Sh Date: Mon, 4 Feb 2013 18:00:48 +0400 Subject: [PATCH] .vim/ updated --- .vim/after/syntax/vala.vim | 200 ++ .vim/autoload/fuf.vim | 1046 ++++++ .vim/autoload/fuf/bookmarkdir.vim | 163 + .vim/autoload/fuf/bookmarkfile.vim | 199 ++ .vim/autoload/fuf/buffer.vim | 189 + .vim/autoload/fuf/buffertag.vim | 300 ++ .vim/autoload/fuf/callbackfile.vim | 137 + .vim/autoload/fuf/callbackitem.vim | 139 + .vim/autoload/fuf/changelist.vim | 172 + .vim/autoload/fuf/coveragefile.vim | 199 ++ .vim/autoload/fuf/dir.vim | 132 + .vim/autoload/fuf/file.vim | 139 + .vim/autoload/fuf/givencmd.vim | 123 + .vim/autoload/fuf/givendir.vim | 123 + .vim/autoload/fuf/givenfile.vim | 121 + .vim/autoload/fuf/help.vim | 198 ++ .vim/autoload/fuf/jumplist.vim | 182 + .vim/autoload/fuf/line.vim | 135 + .vim/autoload/fuf/mrucmd.vim | 134 + .vim/autoload/fuf/mrufile.vim | 234 ++ .vim/autoload/fuf/quickfix.vim | 154 + .vim/autoload/fuf/tag.vim | 178 + .vim/autoload/fuf/taggedfile.vim | 159 + .vim/autoload/tagbar.vim | 31 + .vim/doc/NERD_tree.txt | 1291 +++++++ .vim/doc/fuf.jax | 1405 ++++++++ .vim/doc/fuf.txt | 1883 ++++++++++ .vim/doc/taglist.txt | 1501 ++++++++ .vim/ftdetect/vala.vim | 4 + .vim/indent/vala.vim | 15 + .vim/nerdtree_plugin/exec_menuitem.vim | 41 + .vim/nerdtree_plugin/fs_menu.vim | 224 ++ .vim/plugin/NERD_tree.vim | 4017 +++++++++++++++++++++ .vim/plugin/VimExplorer.vim | 3538 ++++++++++++++++++ .vim/plugin/a.vim | 840 +++++ .vim/plugin/cscope_maps.vim | 165 + .vim/plugin/fuf.vim | 158 + .vim/plugin/po.vim | 135 + .vim/plugin/taglist.vim | 4546 ++++++++++++++++++++++++ .vim/syntax/nerdtree.vim | 88 + 40 files changed, 24638 insertions(+) create mode 100644 .vim/after/syntax/vala.vim create mode 100644 .vim/autoload/fuf.vim create mode 100644 .vim/autoload/fuf/bookmarkdir.vim create mode 100644 .vim/autoload/fuf/bookmarkfile.vim create mode 100644 .vim/autoload/fuf/buffer.vim create mode 100644 .vim/autoload/fuf/buffertag.vim create mode 100644 .vim/autoload/fuf/callbackfile.vim create mode 100644 .vim/autoload/fuf/callbackitem.vim create mode 100644 .vim/autoload/fuf/changelist.vim create mode 100644 .vim/autoload/fuf/coveragefile.vim create mode 100644 .vim/autoload/fuf/dir.vim create mode 100644 .vim/autoload/fuf/file.vim create mode 100644 .vim/autoload/fuf/givencmd.vim create mode 100644 .vim/autoload/fuf/givendir.vim create mode 100644 .vim/autoload/fuf/givenfile.vim create mode 100644 .vim/autoload/fuf/help.vim create mode 100644 .vim/autoload/fuf/jumplist.vim create mode 100644 .vim/autoload/fuf/line.vim create mode 100644 .vim/autoload/fuf/mrucmd.vim create mode 100644 .vim/autoload/fuf/mrufile.vim create mode 100644 .vim/autoload/fuf/quickfix.vim create mode 100644 .vim/autoload/fuf/tag.vim create mode 100644 .vim/autoload/fuf/taggedfile.vim create mode 100644 .vim/autoload/tagbar.vim create mode 100644 .vim/doc/NERD_tree.txt create mode 100644 .vim/doc/fuf.jax create mode 100644 .vim/doc/fuf.txt create mode 100644 .vim/doc/taglist.txt create mode 100644 .vim/ftdetect/vala.vim create mode 100644 .vim/indent/vala.vim create mode 100644 .vim/nerdtree_plugin/exec_menuitem.vim create mode 100644 .vim/nerdtree_plugin/fs_menu.vim create mode 100644 .vim/plugin/NERD_tree.vim create mode 100644 .vim/plugin/VimExplorer.vim create mode 100644 .vim/plugin/a.vim create mode 100644 .vim/plugin/cscope_maps.vim create mode 100644 .vim/plugin/fuf.vim create mode 100644 .vim/plugin/po.vim create mode 100644 .vim/plugin/taglist.vim create mode 100644 .vim/syntax/nerdtree.vim diff --git a/.vim/after/syntax/vala.vim b/.vim/after/syntax/vala.vim new file mode 100644 index 0000000..3700fb6 --- /dev/null +++ b/.vim/after/syntax/vala.vim @@ -0,0 +1,200 @@ +" Vim syntax file +" Language: Vala +" Maintainers: Emmanuele Bassi +" Hans Vercammen +" pancake +" Sebastian Reichel +" Last Change: 2012-02-19 +" Filenames: *.vala *.vapi +" +" REFERENCES: +" [1] http://live.gnome.org/Vala +" +" TODO: Possibly when reaching vala 1.0 release +" - validate code attributes +" - better error checking for known errors +" - full support for valadoc +" +" add vala in /usr/share/vim/vim73/scripts.vim below ruby +" to have shebang support + +if exists("b:current_syntax") + finish +endif + +let s:vala_cpo_save = &cpo +set cpo&vim + +" Types +syn keyword valaType bool char double float size_t ssize_t string unichar void +syn keyword valaType int int8 int16 int32 int64 long short +syn keyword valaType uint uint8 uint16 uint32 uint64 ulong ushort +" Storage keywords +syn keyword valaStorage class delegate enum errordomain interface namespace struct +" repeat / condition / label +syn keyword valaRepeat break continue do for foreach return while +syn keyword valaConditional else if switch assert +" User Labels +syn keyword valaLabel case default + +" Modifiers +syn keyword valaModifier abstract const dynamic ensures extern inline internal override +syn keyword valaModifier private protected public requires signal static virtual volatile weak +syn keyword valaModifier async owned unowned +" Constants +syn keyword valaConstant false null true +" Exceptions +syn keyword valaException try catch finally throw +" Unspecified Statements +syn keyword valaUnspecifiedStatement as base construct delete get in is lock new out params ref sizeof set this throws typeof using value var yield + +" Comments +syn cluster valaCommentGroup contains=valaTodo +syn keyword valaTodo contained TODO FIXME XXX NOTE + +" valadoc Comments (ported from javadoc comments in java.vim) +" TODO: need to verify valadoc syntax +if !exists("vala_ignore_valadoc") + syn cluster valaDocCommentGroup contains=valaDocTags,valaDocSeeTag + syn region valaDocTags contained start="{@\(link\|linkplain\|inherit[Dd]oc\|doc[rR]oot\|value\)" end="}" + syn match valaDocTags contained "@\(param\|exception\|throws\|since\)\s\+\S\+" contains=valaDocParam + syn match valaDocParam contained "\s\S\+" + syn match valaDocTags contained "@\(author\|brief\|version\|return\|deprecated\)\>" + syn region valaDocSeeTag contained matchgroup=valaDocTags start="@see\s\+" matchgroup=NONE end="\_."re=e-1 contains=valaDocSeeTagParam + syn match valaDocSeeTagParam contained @"\_[^"]\+"\|\|\(\k\|\.\)*\(#\k\+\((\_[^)]\+)\)\=\)\=@ extend +endif + +" Comment Strings (ported from c.vim) +if exists("vala_comment_strings") + syn match valaCommentSkip contained "^\s*\*\($\|\s\+\)" + syn region valaCommentString contained start=+L\=\\\@" skip="\\$" end="$" end="//"me=s-1 +syn match valaPreCondit display "^\s*\(%:\|#\)\s*\(else\|endif\)\>" + +" Comment if 0 blocks (ported from c.vim) +if !exists("vala_no_if0") + syn region valaCppOut start="^\s*\(%:\|#\)\s*if\s\+0\+\>" end=".\@=\|$" contains=valaCppOut2 fold + syn region valaCppOut2 contained start="0" end="^\s*\(%:\|#\)\s*\(endif\>\|else\>\|elif\>\)" contains=valaSpaceError,valaCppSkip + syn region valaCppSkip contained start="^\s*\(%:\|#\)\s*\(if\>\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\(%:\|#\)\s*endif\>" contains=valaSpaceError,valaCppSkip +endif + +" match comment errors +syntax match valaCommentError display "\*/" +syntax match valaCommentStartError display "/\*"me=e-1 contained +" match the special comment /**/ +syn match valaComment "/\*\*/" + +" Vala Code Attributes +syn region valaAttribute start="^\s*\[" end="\]$" contains=valaComment,valaString keepend +syn region valaAttribute start="\[CCode" end="\]" contains=valaComment,valaString + +" Avoid escaped keyword matching +syn match valaUserContent display "@\I*" + +" Strings and constants +syn match valaSpecialError contained "\\." +syn match valaSpecialCharError contained "[^']" +syn match valaSpecialChar contained +\\["\\'0abfnrtvx]+ +syn region valaString start=+"+ end=+"+ end=+$+ contains=valaSpecialChar,valaSpecialError,valaUnicodeNumber,@Spell +syn region valaVerbatimString start=+"""+ end=+"""+ contains=@Spell +syn match valaUnicodeNumber +\\\(u\x\{4}\|U\x\{8}\)+ contained contains=valaUnicodeSpecifier +syn match valaUnicodeSpecifier +\\[uU]+ contained +syn match valaCharacter "'[^']*'" contains=valaSpecialChar,valaSpecialCharError +syn match valaCharacter "'\\''" contains=valaSpecialChar +syn match valaCharacter "'[^\\]'" +syn match valaNumber display "\<\(0[0-7]*\|0[xX]\x\+\|\d\+\)[lL]\=\>" +syn match valaNumber display "\(\<\d\+\.\d*\|\.\d\+\)\([eE][-+]\=\d\+\)\=[fFdD]\=" +syn match valaNumber display "\<\d\+[eE][-+]\=\d\+[fFdD]\=\>" +syn match valaNumber display "\<\d\+\([eE][-+]\=\d\+\)\=[fFdD]\>" + +" when wanted, highlight trailing white space +if exists("vala_space_errors") + if !exists("vala_no_trail_space_error") + syn match valaSpaceError display excludenl "\s\+$" + endif + if !exists("vala_no_tab_space_error") + syn match valaSpaceError display " \+\t"me=e-1 + endif +endif + +" when wanted, set minimum lines for comment syntax syncing +if exists("vala_minlines") + let b:vala_minlines = vala_minlines +else + let b:vala_minlines = 50 +endif +exec "syn sync ccomment valaComment minlines=" . b:vala_minlines + +" code folding +syn region valaBlock start="{" end="}" transparent fold + +" The default highlighting. +hi def link valaType Type +hi def link valaStorage StorageClass +hi def link valaRepeat Repeat +hi def link valaConditional Conditional +hi def link valaLabel Label +hi def link valaModifier StorageClass +hi def link valaConstant Constant +hi def link valaException Exception +hi def link valaUnspecifiedStatement Statement +hi def link valaUnspecifiedKeyword Keyword +hi def link valaContextualStatement Statement + +hi def link valaCommentError Error +hi def link valaCommentStartError Error +hi def link valaSpecialError Error +hi def link valaSpecialCharError Error +hi def link valaSpaceError Error + +hi def link valaTodo Todo +hi def link valaCommentL valaComment +hi def link valaCommentStart valaComment +hi def link valaCommentSkip valaComment +hi def link valaComment Comment +hi def link valaDocComment Comment +hi def link valaDocTags Special +hi def link valaDocParam Function +hi def link valaDocSeeTagParam Function +hi def link valaAttribute PreCondit + +hi def link valaCommentString valaString +hi def link valaComment2String valaString +hi def link valaString String +hi def link valaVerbatimString String +hi def link valaCharacter Character +hi def link valaSpecialChar SpecialChar +hi def link valaNumber Number +hi def link valaUnicodeNumber SpecialChar +hi def link valaUnicodeSpecifier SpecialChar + +hi def link valaPreCondit PreCondit + +if !exists("vala_no_if0") + hi def link valaCppSkip valaCppOut + hi def link valaCppOut2 valaCppOut + hi def link valaCppOut Comment +endif + +let b:current_syntax = "vala" + +let &cpo = s:vala_cpo_save +unlet s:vala_cpo_save + +" vim: ts=8 diff --git a/.vim/autoload/fuf.vim b/.vim/autoload/fuf.vim new file mode 100644 index 0000000..fe9e6eb --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/bookmarkdir.vim b/.vim/autoload/fuf/bookmarkdir.vim new file mode 100644 index 0000000..01585ff --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/bookmarkfile.vim b/.vim/autoload/fuf/bookmarkfile.vim new file mode 100644 index 0000000..12ac80f --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/buffer.vim b/.vim/autoload/fuf/buffer.vim new file mode 100644 index 0000000..08b954a --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/buffertag.vim b/.vim/autoload/fuf/buffertag.vim new file mode 100644 index 0000000..392b996 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/callbackfile.vim b/.vim/autoload/fuf/callbackfile.vim new file mode 100644 index 0000000..fedf0cf --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/callbackitem.vim b/.vim/autoload/fuf/callbackitem.vim new file mode 100644 index 0000000..118ee08 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/changelist.vim b/.vim/autoload/fuf/changelist.vim new file mode 100644 index 0000000..545f6ca --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/coveragefile.vim b/.vim/autoload/fuf/coveragefile.vim new file mode 100644 index 0000000..1471ef8 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/dir.vim b/.vim/autoload/fuf/dir.vim new file mode 100644 index 0000000..5316093 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/file.vim b/.vim/autoload/fuf/file.vim new file mode 100644 index 0000000..1569192 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/givencmd.vim b/.vim/autoload/fuf/givencmd.vim new file mode 100644 index 0000000..d59178c --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/givendir.vim b/.vim/autoload/fuf/givendir.vim new file mode 100644 index 0000000..e654d85 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/givenfile.vim b/.vim/autoload/fuf/givenfile.vim new file mode 100644 index 0000000..5419ff8 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/help.vim b/.vim/autoload/fuf/help.vim new file mode 100644 index 0000000..8f03e36 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/jumplist.vim b/.vim/autoload/fuf/jumplist.vim new file mode 100644 index 0000000..ddbb1ab --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/line.vim b/.vim/autoload/fuf/line.vim new file mode 100644 index 0000000..60447b5 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/mrucmd.vim b/.vim/autoload/fuf/mrucmd.vim new file mode 100644 index 0000000..58632ce --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/mrufile.vim b/.vim/autoload/fuf/mrufile.vim new file mode 100644 index 0000000..f90b9e3 --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/quickfix.vim b/.vim/autoload/fuf/quickfix.vim new file mode 100644 index 0000000..dd5d67c --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/tag.vim b/.vim/autoload/fuf/tag.vim new file mode 100644 index 0000000..362cabf --- /dev/null +++ b/.vim/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/.vim/autoload/fuf/taggedfile.vim b/.vim/autoload/fuf/taggedfile.vim new file mode 100644 index 0000000..74652fc --- /dev/null +++ b/.vim/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/.vim/autoload/tagbar.vim b/.vim/autoload/tagbar.vim new file mode 100644 index 0000000..eae549c --- /dev/null +++ b/.vim/autoload/tagbar.vim @@ -0,0 +1,31 @@ +" Vala {{{3 + let type_vala = {} + let type_vala.ctagstype = 'vala' + let type_vala.kinds = [ + \ {'short' : 'c', 'long' : 'classes', 'fold' : 0}, + \ {'short' : 'd', 'long' : 'delegates', 'fold' : 0}, + \ {'short' : 'e', 'long' : 'enumerations', 'fold' : 0}, + \ {'short' : 'E', 'long' : 'error domains', 'fold' : 0}, + \ {'short' : 'f', 'long' : 'fields', 'fold' : 0}, + \ {'short' : 'i', 'long' : 'interfaces', 'fold' : 0}, + \ {'short' : 'm', 'long' : 'methods', 'fold' : 0}, + \ {'short' : 'p', 'long' : 'properties', 'fold' : 0}, + \ {'short' : 'r', 'long' : 'error codes', 'fold' : 0}, + \ {'short' : 's', 'long' : 'structures', 'fold' : 0}, + \ {'short' : 'S', 'long' : 'signals', 'fold' : 0}, + \ {'short' : 'v', 'long' : 'enumeration values', 'fold' : 0} + \ ] + let type_vala.sro = '.' + let type_vala.kind2scope = { + \ 'i' : 'interface', + \ 'c' : 'class', + \ 's' : 'structure', + \ 'e' : 'enum' + \ } + let type_vala.scope2kind = { + \ 'interface' : 'i', + \ 'class' : 'c', + \ 'struct' : 's', + \ 'enum' : 'e' + \ } + let s:known_types.vala = type_vala diff --git a/.vim/doc/NERD_tree.txt b/.vim/doc/NERD_tree.txt new file mode 100644 index 0000000..174229d --- /dev/null +++ b/.vim/doc/NERD_tree.txt @@ -0,0 +1,1291 @@ +*NERD_tree.txt* A tree explorer plugin that owns your momma! + + + + omg its ... ~ + + ________ ________ _ ____________ ____ __________ ____________~ + /_ __/ / / / ____/ / | / / ____/ __ \/ __ \ /_ __/ __ \/ ____/ ____/~ + / / / /_/ / __/ / |/ / __/ / /_/ / / / / / / / /_/ / __/ / __/ ~ + / / / __ / /___ / /| / /___/ _, _/ /_/ / / / / _, _/ /___/ /___ ~ + /_/ /_/ /_/_____/ /_/ |_/_____/_/ |_/_____/ /_/ /_/ |_/_____/_____/ ~ + + + Reference Manual~ + + + + +============================================================================== +CONTENTS *NERDTree-contents* + + 1.Intro...................................|NERDTree| + 2.Functionality provided..................|NERDTreeFunctionality| + 2.1.Global commands...................|NERDTreeGlobalCommands| + 2.2.Bookmarks.........................|NERDTreeBookmarks| + 2.2.1.The bookmark table..........|NERDTreeBookmarkTable| + 2.2.2.Bookmark commands...........|NERDTreeBookmarkCommands| + 2.2.3.Invalid bookmarks...........|NERDTreeInvalidBookmarks| + 2.3.NERD tree mappings................|NERDTreeMappings| + 2.4.The NERD tree menu................|NERDTreeMenu| + 3.Options.................................|NERDTreeOptions| + 3.1.Option summary....................|NERDTreeOptionSummary| + 3.2.Option details....................|NERDTreeOptionDetails| + 4.The NERD tree API.......................|NERDTreeAPI| + 4.1.Key map API.......................|NERDTreeKeymapAPI| + 4.2.Menu API..........................|NERDTreeMenuAPI| + 5.About...................................|NERDTreeAbout| + 6.Changelog...............................|NERDTreeChangelog| + 7.Credits.................................|NERDTreeCredits| + 8.License.................................|NERDTreeLicense| + +============================================================================== +1. Intro *NERDTree* + +What is this "NERD tree"?? + +The NERD tree allows you to explore your filesystem and to open files and +directories. It presents the filesystem to you in the form of a tree which you +manipulate with the keyboard and/or mouse. It also allows you to perform +simple filesystem operations. + +The following features and functionality are provided by the NERD tree: + * Files and directories are displayed in a hierarchical tree structure + * Different highlighting is provided for the following types of nodes: + * files + * directories + * sym-links + * windows .lnk files + * read-only files + * executable files + * Many (customisable) mappings are provided to manipulate the tree: + * Mappings to open/close/explore directory nodes + * Mappings to open files in new/existing windows/tabs + * Mappings to change the current root of the tree + * Mappings to navigate around the tree + * ... + * Directories and files can be bookmarked. + * Most NERD tree navigation can also be done with the mouse + * Filtering of tree content (can be toggled at runtime) + * custom file filters to prevent e.g. vim backup files being displayed + * optional displaying of hidden files (. files) + * files can be "turned off" so that only directories are displayed + * The position and size of the NERD tree window can be customised + * The order in which the nodes in the tree are listed can be customised. + * A model of your filesystem is created/maintained as you explore it. This + has several advantages: + * All filesystem information is cached and is only re-read on demand + * If you revisit a part of the tree that you left earlier in your + session, the directory nodes will be opened/closed as you left them + * The script remembers the cursor position and window position in the NERD + tree so you can toggle it off (or just close the tree window) and then + reopen it (with NERDTreeToggle) the NERD tree window will appear exactly + as you left it + * You can have a separate NERD tree for each tab, share trees across tabs, + or a mix of both. + * By default the script overrides the default file browser (netw), so if + you :edit a directory a (slighly modified) NERD tree will appear in the + current window + * A programmable menu system is provided (simulates right clicking on a + node) + * one default menu plugin is provided to perform basic filesytem + operations (create/delete/move/copy files/directories) + * There's an API for adding your own keymappings + + +============================================================================== +2. Functionality provided *NERDTreeFunctionality* + +------------------------------------------------------------------------------ +2.1. Global Commands *NERDTreeGlobalCommands* + +:NERDTree [ | ] *:NERDTree* + Opens a fresh NERD tree. The root of the tree depends on the argument + given. There are 3 cases: If no argument is given, the current directory + will be used. If a directory is given, that will be used. If a bookmark + name is given, the corresponding directory will be used. For example: > + :NERDTree /home/marty/vim7/src + :NERDTree foo (foo is the name of a bookmark) +< +:NERDTreeFromBookmark *:NERDTreeFromBookmark* + Opens a fresh NERD tree with the root initialized to the dir for + . This only reason to use this command over :NERDTree is for + the completion (which is for bookmarks rather than directories). + +:NERDTreeToggle [ | ] *:NERDTreeToggle* + If a NERD tree already exists for this tab, it is reopened and rendered + again. If no NERD tree exists for this tab then this command acts the + same as the |:NERDTree| command. + +:NERDTreeMirror *:NERDTreeMirror* + Shares an existing NERD tree, from another tab, in the current tab. + Changes made to one tree are reflected in both as they are actually the + same buffer. + + If only one other NERD tree exists, that tree is automatically mirrored. If + more than one exists, the script will ask which tree to mirror. + +:NERDTreeClose *:NERDTreeClose* + Close the NERD tree in this tab. + +:NERDTreeFind *:NERDTreeFind* + Find the current file in the tree. + + If not tree exists and the current file is under vim's CWD, then init a + tree at the CWD and reveal the file. Otherwise init a tree in the current + file's directory. + + In any case, the current file is revealed and the cursor is placed on it. + +------------------------------------------------------------------------------ +2.2. Bookmarks *NERDTreeBookmarks* + +Bookmarks in the NERD tree are a way to tag files or directories of interest. +For example, you could use bookmarks to tag all of your project directories. + +------------------------------------------------------------------------------ +2.2.1. The Bookmark Table *NERDTreeBookmarkTable* + +If the bookmark table is active (see |NERDTree-B| and +|'NERDTreeShowBookmarks'|), it will be rendered above the tree. You can double +click bookmarks or use the |NERDTree-o| mapping to activate them. See also, +|NERDTree-t| and |NERDTree-T| + +------------------------------------------------------------------------------ +2.2.2. Bookmark commands *NERDTreeBookmarkCommands* + +Note that the following commands are only available in the NERD tree buffer. + +:Bookmark + Bookmark the current node as . If there is already a + bookmark, it is overwritten. must not contain spaces. + If is not provided, it defaults to the file or directory name. + For directories, a trailing slash is present. + +:BookmarkToRoot + Make the directory corresponding to the new root. If a treenode + corresponding to is already cached somewhere in the tree then + the current tree will be used, otherwise a fresh tree will be opened. + Note that if points to a file then its parent will be used + instead. + +:RevealBookmark + If the node is cached under the current root then it will be revealed + (i.e. directory nodes above it will be opened) and the cursor will be + placed on it. + +:OpenBookmark + must point to a file. The file is opened as though |NERDTree-o| + was applied. If the node is cached under the current root then it will be + revealed and the cursor will be placed on it. + +:ClearBookmarks [] + Remove all the given bookmarks. If no bookmarks are given then remove all + bookmarks on the current node. + +:ClearAllBookmarks + Remove all bookmarks. + +:ReadBookmarks + Re-read the bookmarks in the |'NERDTreeBookmarksFile'|. + +See also |:NERDTree| and |:NERDTreeFromBookmark|. + +------------------------------------------------------------------------------ +2.2.3. Invalid Bookmarks *NERDTreeInvalidBookmarks* + +If invalid bookmarks are detected, the script will issue an error message and +the invalid bookmarks will become unavailable for use. + +These bookmarks will still be stored in the bookmarks file (see +|'NERDTreeBookmarksFile'|), down the bottom. There will always be a blank line +after the valid bookmarks but before the invalid ones. + +Each line in the bookmarks file represents one bookmark. The proper format is: + + +After you have corrected any invalid bookmarks, either restart vim, or go +:ReadBookmarks from the NERD tree window. + +------------------------------------------------------------------------------ +2.3. NERD tree Mappings *NERDTreeMappings* + +Default Description~ help-tag~ +Key~ + +o.......Open files, directories and bookmarks....................|NERDTree-o| +go......Open selected file, but leave cursor in the NERDTree.....|NERDTree-go| +t.......Open selected node/bookmark in a new tab.................|NERDTree-t| +T.......Same as 't' but keep the focus on the current tab........|NERDTree-T| +i.......Open selected file in a split window.....................|NERDTree-i| +gi......Same as i, but leave the cursor on the NERDTree..........|NERDTree-gi| +s.......Open selected file in a new vsplit.......................|NERDTree-s| +gs......Same as s, but leave the cursor on the NERDTree..........|NERDTree-gs| +O.......Recursively open the selected directory..................|NERDTree-O| +x.......Close the current nodes parent...........................|NERDTree-x| +X.......Recursively close all children of the current node.......|NERDTree-X| +e.......Edit the current dif.....................................|NERDTree-e| + +...............same as |NERDTree-o|. +double-click.......same as the |NERDTree-o| map. +middle-click.......same as |NERDTree-i| for files, same as + |NERDTree-e| for dirs. + +D.......Delete the current bookmark .............................|NERDTree-D| + +P.......Jump to the root node....................................|NERDTree-P| +p.......Jump to current nodes parent.............................|NERDTree-p| +K.......Jump up inside directories at the current tree depth.....|NERDTree-K| +J.......Jump down inside directories at the current tree depth...|NERDTree-J| +...Jump down to the next sibling of the current directory...|NERDTree-C-J| +...Jump up to the previous sibling of the current directory.|NERDTree-C-K| + +C.......Change the tree root to the selected dir.................|NERDTree-C| +u.......Move the tree root up one directory......................|NERDTree-u| +U.......Same as 'u' except the old root node is left open........|NERDTree-U| +r.......Recursively refresh the current directory................|NERDTree-r| +R.......Recursively refresh the current root.....................|NERDTree-R| +m.......Display the NERD tree menu...............................|NERDTree-m| +cd......Change the CWD to the dir of the selected node...........|NERDTree-cd| + +I.......Toggle whether hidden files displayed....................|NERDTree-I| +f.......Toggle whether the file filters are used.................|NERDTree-f| +F.......Toggle whether files are displayed.......................|NERDTree-F| +B.......Toggle whether the bookmark table is displayed...........|NERDTree-B| + +q.......Close the NERDTree window................................|NERDTree-q| +A.......Zoom (maximize/minimize) the NERDTree window.............|NERDTree-A| +?.......Toggle the display of the quick help.....................|NERDTree-?| + +------------------------------------------------------------------------------ + *NERDTree-o* +Default key: o +Map option: NERDTreeMapActivateNode +Applies to: files and directories. + +If a file node is selected, it is opened in the previous window. + +If a directory is selected it is opened or closed depending on its current +state. + +If a bookmark that links to a directory is selected then that directory +becomes the new root. + +If a bookmark that links to a file is selected then that file is opened in the +previous window. + +------------------------------------------------------------------------------ + *NERDTree-go* +Default key: go +Map option: None +Applies to: files. + +If a file node is selected, it is opened in the previous window, but the +cursor does not move. + +The key combo for this mapping is always "g" + NERDTreeMapActivateNode (see +|NERDTree-o|). + +------------------------------------------------------------------------------ + *NERDTree-t* +Default key: t +Map option: NERDTreeMapOpenInTab +Applies to: files and directories. + +Opens the selected file in a new tab. If a directory is selected, a fresh +NERD Tree for that directory is opened in a new tab. + +If a bookmark which points to a directory is selected, open a NERD tree for +that directory in a new tab. If the bookmark points to a file, open that file +in a new tab. + +------------------------------------------------------------------------------ + *NERDTree-T* +Default key: T +Map option: NERDTreeMapOpenInTabSilent +Applies to: files and directories. + +The same as |NERDTree-t| except that the focus is kept in the current tab. + +------------------------------------------------------------------------------ + *NERDTree-i* +Default key: i +Map option: NERDTreeMapOpenSplit +Applies to: files. + +Opens the selected file in a new split window and puts the cursor in the new +window. + +------------------------------------------------------------------------------ + *NERDTree-gi* +Default key: gi +Map option: None +Applies to: files. + +The same as |NERDTree-i| except that the cursor is not moved. + +The key combo for this mapping is always "g" + NERDTreeMapOpenSplit (see +|NERDTree-i|). + +------------------------------------------------------------------------------ + *NERDTree-s* +Default key: s +Map option: NERDTreeMapOpenVSplit +Applies to: files. + +Opens the selected file in a new vertically split window and puts the cursor in +the new window. + +------------------------------------------------------------------------------ + *NERDTree-gs* +Default key: gs +Map option: None +Applies to: files. + +The same as |NERDTree-s| except that the cursor is not moved. + +The key combo for this mapping is always "g" + NERDTreeMapOpenVSplit (see +|NERDTree-s|). + +------------------------------------------------------------------------------ + *NERDTree-O* +Default key: O +Map option: NERDTreeMapOpenRecursively +Applies to: directories. + +Recursively opens the selelected directory. + +All files and directories are cached, but if a directory would not be +displayed due to file filters (see |'NERDTreeIgnore'| |NERDTree-f|) or the +hidden file filter (see |'NERDTreeShowHidden'|) then its contents are not +cached. This is handy, especially if you have .svn directories. + +------------------------------------------------------------------------------ + *NERDTree-x* +Default key: x +Map option: NERDTreeMapCloseDir +Applies to: files and directories. + +Closes the parent of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-X* +Default key: X +Map option: NERDTreeMapCloseChildren +Applies to: directories. + +Recursively closes all children of the selected directory. + +Tip: To quickly "reset" the tree, use |NERDTree-P| with this mapping. + +------------------------------------------------------------------------------ + *NERDTree-e* +Default key: e +Map option: NERDTreeMapOpenExpl +Applies to: files and directories. + +|:edit|s the selected directory, or the selected file's directory. This could +result in a NERD tree or a netrw being opened, depending on +|'NERDTreeHijackNetrw'|. + +------------------------------------------------------------------------------ + *NERDTree-D* +Default key: D +Map option: NERDTreeMapDeleteBookmark +Applies to: lines in the bookmarks table + +Deletes the currently selected bookmark. + +------------------------------------------------------------------------------ + *NERDTree-P* +Default key: P +Map option: NERDTreeMapJumpRoot +Applies to: no restrictions. + +Jump to the tree root. + +------------------------------------------------------------------------------ + *NERDTree-p* +Default key: p +Map option: NERDTreeMapJumpParent +Applies to: files and directories. + +Jump to the parent node of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-K* +Default key: K +Map option: NERDTreeMapJumpFirstChild +Applies to: files and directories. + +Jump to the first child of the current nodes parent. + +If the cursor is already on the first node then do the following: + * loop back thru the siblings of the current nodes parent until we find an + open dir with children + * go to the first child of that node + +------------------------------------------------------------------------------ + *NERDTree-J* +Default key: J +Map option: NERDTreeMapJumpLastChild +Applies to: files and directories. + +Jump to the last child of the current nodes parent. + +If the cursor is already on the last node then do the following: + * loop forward thru the siblings of the current nodes parent until we find + an open dir with children + * go to the last child of that node + +------------------------------------------------------------------------------ + *NERDTree-C-J* +Default key: +Map option: NERDTreeMapJumpNextSibling +Applies to: files and directories. + +Jump to the next sibling of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-C-K* +Default key: +Map option: NERDTreeMapJumpPrevSibling +Applies to: files and directories. + +Jump to the previous sibling of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-C* +Default key: C +Map option: NERDTreeMapChdir +Applies to: directories. + +Make the selected directory node the new tree root. If a file is selected, its +parent is used. + +------------------------------------------------------------------------------ + *NERDTree-u* +Default key: u +Map option: NERDTreeMapUpdir +Applies to: no restrictions. + +Move the tree root up a dir (like doing a "cd .."). + +------------------------------------------------------------------------------ + *NERDTree-U* +Default key: U +Map option: NERDTreeMapUpdirKeepOpen +Applies to: no restrictions. + +Like |NERDTree-u| except that the old tree root is kept open. + +------------------------------------------------------------------------------ + *NERDTree-r* +Default key: r +Map option: NERDTreeMapRefresh +Applies to: files and directories. + +If a dir is selected, recursively refresh that dir, i.e. scan the filesystem +for changes and represent them in the tree. + +If a file node is selected then the above is done on it's parent. + +------------------------------------------------------------------------------ + *NERDTree-R* +Default key: R +Map option: NERDTreeMapRefreshRoot +Applies to: no restrictions. + +Recursively refresh the tree root. + +------------------------------------------------------------------------------ + *NERDTree-m* +Default key: m +Map option: NERDTreeMapMenu +Applies to: files and directories. + +Display the NERD tree menu. See |NERDTreeMenu| for details. + +------------------------------------------------------------------------------ + *NERDTree-cd* +Default key: cd +Map option: NERDTreeMapChdir +Applies to: files and directories. + +Change vims current working directory to that of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-I* +Default key: I +Map option: NERDTreeMapToggleHidden +Applies to: no restrictions. + +Toggles whether hidden files (i.e. "dot files") are displayed. + +------------------------------------------------------------------------------ + *NERDTree-f* +Default key: f +Map option: NERDTreeMapToggleFilters +Applies to: no restrictions. + +Toggles whether file filters are used. See |'NERDTreeIgnore'| for details. + +------------------------------------------------------------------------------ + *NERDTree-F* +Default key: F +Map option: NERDTreeMapToggleFiles +Applies to: no restrictions. + +Toggles whether file nodes are displayed. + +------------------------------------------------------------------------------ + *NERDTree-B* +Default key: B +Map option: NERDTreeMapToggleBookmarks +Applies to: no restrictions. + +Toggles whether the bookmarks table is displayed. + +------------------------------------------------------------------------------ + *NERDTree-q* +Default key: q +Map option: NERDTreeMapQuit +Applies to: no restrictions. + +Closes the NERDtree window. + +------------------------------------------------------------------------------ + *NERDTree-A* +Default key: A +Map option: NERDTreeMapToggleZoom +Applies to: no restrictions. + +Maximize (zoom) and minimize the NERDtree window. + +------------------------------------------------------------------------------ + *NERDTree-?* +Default key: ? +Map option: NERDTreeMapHelp +Applies to: no restrictions. + +Toggles whether the quickhelp is displayed. + +------------------------------------------------------------------------------ +2.3. The NERD tree menu *NERDTreeMenu* + +The NERD tree has a menu that can be programmed via the an API (see +|NERDTreeMenuAPI|). The idea is to simulate the "right click" menus that most +file explorers have. + +The script comes with two default menu plugins: exec_menuitem.vim and +fs_menu.vim. fs_menu.vim adds some basic filesystem operations to the menu for +creating/deleting/moving/copying files and dirs. exec_menuitem.vim provides a +menu item to execute executable files. + +Related tags: |NERDTree-m| |NERDTreeApi| + +============================================================================== +3. Customisation *NERDTreeOptions* + + +------------------------------------------------------------------------------ +3.1. Customisation summary *NERDTreeOptionSummary* + +The script provides the following options that can customise the behaviour the +NERD tree. These options should be set in your vimrc. + +|'loaded_nerd_tree'| Turns off the script. + +|'NERDChristmasTree'| Tells the NERD tree to make itself colourful + and pretty. + +|'NERDTreeAutoCenter'| Controls whether the NERD tree window centers + when the cursor moves within a specified + distance to the top/bottom of the window. +|'NERDTreeAutoCenterThreshold'| Controls the sensitivity of autocentering. + +|'NERDTreeCaseSensitiveSort'| Tells the NERD tree whether to be case + sensitive or not when sorting nodes. + +|'NERDTreeChDirMode'| Tells the NERD tree if/when it should change + vim's current working directory. + +|'NERDTreeHighlightCursorline'| Tell the NERD tree whether to highlight the + current cursor line. + +|'NERDTreeHijackNetrw'| Tell the NERD tree whether to replace the netrw + autocommands for exploring local directories. + +|'NERDTreeIgnore'| Tells the NERD tree which files to ignore. + +|'NERDTreeBookmarksFile'| Where the bookmarks are stored. + +|'NERDTreeMouseMode'| Tells the NERD tree how to handle mouse + clicks. + +|'NERDTreeQuitOnOpen'| Closes the tree window after opening a file. + +|'NERDTreeShowBookmarks'| Tells the NERD tree whether to display the + bookmarks table on startup. + +|'NERDTreeShowFiles'| Tells the NERD tree whether to display files + in the tree on startup. + +|'NERDTreeShowHidden'| Tells the NERD tree whether to display hidden + files on startup. + +|'NERDTreeShowLineNumbers'| Tells the NERD tree whether to display line + numbers in the tree window. + +|'NERDTreeSortOrder'| Tell the NERD tree how to sort the nodes in + the tree. + +|'NERDTreeStatusline'| Set a statusline for NERD tree windows. + +|'NERDTreeWinPos'| Tells the script where to put the NERD tree + window. + +|'NERDTreeWinSize'| Sets the window size when the NERD tree is + opened. + +|'NERDTreeMinimalUI'| Disables display of the 'Bookmarks' label and + 'Press ? for help' text. + +|'NERDTreeDirArrows'| Tells the NERD tree to use arrows instead of + + ~ chars when displaying directories. + +------------------------------------------------------------------------------ +3.2. Customisation details *NERDTreeOptionDetails* + +To enable any of the below options you should put the given line in your +~/.vimrc + + *'loaded_nerd_tree'* +If this plugin is making you feel homicidal, it may be a good idea to turn it +off with this line in your vimrc: > + let loaded_nerd_tree=1 +< +------------------------------------------------------------------------------ + *'NERDChristmasTree'* +Values: 0 or 1. +Default: 1. + +If this option is set to 1 then some extra syntax highlighting elements are +added to the nerd tree to make it more colourful. + +Set it to 0 for a more vanilla looking tree. + +------------------------------------------------------------------------------ + *'NERDTreeAutoCenter'* +Values: 0 or 1. +Default: 1 + +If set to 1, the NERD tree window will center around the cursor if it moves to +within |'NERDTreeAutoCenterThreshold'| lines of the top/bottom of the window. + +This is ONLY done in response to tree navigation mappings, +i.e. |NERDTree-J| |NERDTree-K| |NERDTree-C-J| |NERDTree-C-K| |NERDTree-p| +|NERDTree-P| + +The centering is done with a |zz| operation. + +------------------------------------------------------------------------------ + *'NERDTreeAutoCenterThreshold'* +Values: Any natural number. +Default: 3 + +This option controls the "sensitivity" of the NERD tree auto centering. See +|'NERDTreeAutoCenter'| for details. + +------------------------------------------------------------------------------ + *'NERDTreeCaseSensitiveSort'* +Values: 0 or 1. +Default: 0. + +By default the NERD tree does not sort nodes case sensitively, i.e. nodes +could appear like this: > + bar.c + Baz.c + blarg.c + boner.c + Foo.c +< +But, if you set this option to 1 then the case of the nodes will be taken into +account. The above nodes would then be sorted like this: > + Baz.c + Foo.c + bar.c + blarg.c + boner.c +< +------------------------------------------------------------------------------ + *'NERDTreeChDirMode'* + +Values: 0, 1 or 2. +Default: 0. + +Use this option to tell the script when (if at all) to change the current +working directory (CWD) for vim. + +If it is set to 0 then the CWD is never changed by the NERD tree. + +If set to 1 then the CWD is changed when the NERD tree is first loaded to the +directory it is initialized in. For example, if you start the NERD tree with > + :NERDTree /home/marty/foobar +< +then the CWD will be changed to /home/marty/foobar and will not be changed +again unless you init another NERD tree with a similar command. + +If the option is set to 2 then it behaves the same as if set to 1 except that +the CWD is changed whenever the tree root is changed. For example, if the CWD +is /home/marty/foobar and you make the node for /home/marty/foobar/baz the new +root then the CWD will become /home/marty/foobar/baz. + +------------------------------------------------------------------------------ + *'NERDTreeHighlightCursorline'* +Values: 0 or 1. +Default: 1. + +If set to 1, the current cursor line in the NERD tree buffer will be +highlighted. This is done using the |'cursorline'| option. + +------------------------------------------------------------------------------ + *'NERDTreeHijackNetrw'* +Values: 0 or 1. +Default: 1. + +If set to 1, doing a > + :edit +< +will open up a "secondary" NERD tree instead of a netrw in the target window. + +Secondary NERD trees behaves slighly different from a regular trees in the +following respects: + 1. 'o' will open the selected file in the same window as the tree, + replacing it. + 2. you can have as many secondary tree as you want in the same tab. + +------------------------------------------------------------------------------ + *'NERDTreeIgnore'* +Values: a list of regular expressions. +Default: ['\~$']. + +This option is used to specify which files the NERD tree should ignore. It +must be a list of regular expressions. When the NERD tree is rendered, any +files/dirs that match any of the regex's in 'NERDTreeIgnore' wont be +displayed. + +For example if you put the following line in your vimrc: > + let NERDTreeIgnore=['\.vim$', '\~$'] +< +then all files ending in .vim or ~ will be ignored. + +Note: to tell the NERD tree not to ignore any files you must use the following +line: > + let NERDTreeIgnore=[] +< + +The file filters can be turned on and off dynamically with the |NERDTree-f| +mapping. + +------------------------------------------------------------------------------ + *'NERDTreeBookmarksFile'* +Values: a path +Default: $HOME/.NERDTreeBookmarks + +This is where bookmarks are saved. See |NERDTreeBookmarkCommands|. + +------------------------------------------------------------------------------ + *'NERDTreeMouseMode'* +Values: 1, 2 or 3. +Default: 1. + +If set to 1 then a double click on a node is required to open it. +If set to 2 then a single click will open directory nodes, while a double +click will still be required for file nodes. +If set to 3 then a single click will open any node. + +Note: a double click anywhere on a line that a tree node is on will +activate it, but all single-click activations must be done on name of the node +itself. For example, if you have the following node: > + | | |-application.rb +< +then (to single click activate it) you must click somewhere in +'application.rb'. + +------------------------------------------------------------------------------ + *'NERDTreeQuitOnOpen'* + +Values: 0 or 1. +Default: 0 + +If set to 1, the NERD tree window will close after opening a file with the +|NERDTree-o|, |NERDTree-i|, |NERDTree-t| and |NERDTree-T| mappings. + +------------------------------------------------------------------------------ + *'NERDTreeShowBookmarks'* +Values: 0 or 1. +Default: 0. + +If this option is set to 1 then the bookmarks table will be displayed. + +This option can be toggled dynamically, per tree, with the |NERDTree-B| +mapping. + +------------------------------------------------------------------------------ + *'NERDTreeShowFiles'* +Values: 0 or 1. +Default: 1. + +If this option is set to 1 then files are displayed in the NERD tree. If it is +set to 0 then only directories are displayed. + +This option can be toggled dynamically, per tree, with the |NERDTree-F| +mapping and is useful for drastically shrinking the tree when you are +navigating to a different part of the tree. + +------------------------------------------------------------------------------ + *'NERDTreeShowHidden'* +Values: 0 or 1. +Default: 0. + +This option tells vim whether to display hidden files by default. This option +can be dynamically toggled, per tree, with the |NERDTree-I| mapping. Use one +of the follow lines to set this option: > + let NERDTreeShowHidden=0 + let NERDTreeShowHidden=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeShowLineNumbers'* +Values: 0 or 1. +Default: 0. + +This option tells vim whether to display line numbers for the NERD tree +window. Use one of the follow lines to set this option: > + let NERDTreeShowLineNumbers=0 + let NERDTreeShowLineNumbers=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeSortOrder'* +Values: a list of regular expressions. +Default: ['\/$', '*', '\.swp$', '\.bak$', '\~$'] + +This option is set to a list of regular expressions which are used to +specify the order of nodes under their parent. + +For example, if the option is set to: > + ['\.vim$', '\.c$', '\.h$', '*', 'foobar'] +< +then all .vim files will be placed at the top, followed by all .c files then +all .h files. All files containing the string 'foobar' will be placed at the +end. The star is a special flag: it tells the script that every node that +doesnt match any of the other regexps should be placed here. + +If no star is present in 'NERDTreeSortOrder' then one is automatically +appended to the array. + +The regex '\/$' should be used to match directory nodes. + +After this sorting is done, the files in each group are sorted alphabetically. + +Other examples: > + (1) ['*', '\/$'] + (2) [] + (3) ['\/$', '\.rb$', '\.php$', '*', '\.swp$', '\.bak$', '\~$'] +< +1. Directories will appear last, everything else will appear above. +2. Everything will simply appear in alphabetical order. +3. Dirs will appear first, then ruby and php. Swap files, bak files and vim + backup files will appear last with everything else preceding them. + +------------------------------------------------------------------------------ + *'NERDTreeStatusline'* +Values: Any valid statusline setting. +Default: %{b:NERDTreeRoot.path.strForOS(0)} + +Tells the script what to use as the |'statusline'| setting for NERD tree +windows. + +Note that the statusline is set using |:let-&| not |:set| so escaping spaces +isn't necessary. + +Setting this option to -1 will will deactivate it so that your global +statusline setting is used instead. + +------------------------------------------------------------------------------ + *'NERDTreeWinPos'* +Values: "left" or "right" +Default: "left". + +This option is used to determine where NERD tree window is placed on the +screen. + +This option makes it possible to use two different explorer plugins +simultaneously. For example, you could have the taglist plugin on the left of +the window and the NERD tree on the right. + +------------------------------------------------------------------------------ + *'NERDTreeWinSize'* +Values: a positive integer. +Default: 31. + +This option is used to change the size of the NERD tree when it is loaded. + +------------------------------------------------------------------------------ + *'NERDTreeMinimalUI'* +Values: 0 or 1 +Default: 0 + +This options disables the 'Bookmarks' label 'Press ? for help' text. Use one +of the following lines to set this option: > + let NERDTreeMinimalUI=0 + let NERDTreeMinimalUI=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeDirArrows'* +Values: 0 or 1 +Default: 0. + +This option is used to change the default look of directory nodes displayed in +the tree. When set to 0 it shows old-school bars (|), + and ~ chars. If set to +1 it shows right and down arrows. Use one of the follow lines to set this +option: > + let NERDTreeDirArrows=0 + let NERDTreeDirArrows=1 +< + +============================================================================== +4. The NERD tree API *NERDTreeAPI* + +The NERD tree script allows you to add custom key mappings and menu items via +a set of API calls. Any scripts that use this API should be placed in +~/.vim/nerdtree_plugin/ (*nix) or ~/vimfiles/nerdtree_plugin (windows). + +The script exposes some prototype objects that can be used to manipulate the +tree and/or get information from it: > + g:NERDTreePath + g:NERDTreeDirNode + g:NERDTreeFileNode + g:NERDTreeBookmark +< +See the code/comments in NERD_tree.vim to find how to use these objects. The +following code conventions are used: + * class members start with a capital letter + * instance members start with a lower case letter + * private members start with an underscore + +See this blog post for more details: + http://got-ravings.blogspot.com/2008/09/vim-pr0n-prototype-based-objects.html + +------------------------------------------------------------------------------ +4.1. Key map API *NERDTreeKeymapAPI* + +NERDTreeAddKeyMap({options}) *NERDTreeAddKeyMap()* + Adds a new keymapping for all NERD tree buffers. + {options} must be a dictionary, and must contain the following keys: + "key" - the trigger key for the new mapping + "callback" - the function the new mapping will be bound to + "quickhelpText" - the text that will appear in the quickhelp (see + |NERDTree-?|) + + Example: > + call NERDTreeAddKeyMap({ + \ 'key': 'b', + \ 'callback': 'NERDTreeEchoCurrentNode', + \ 'quickhelpText': 'echo full path of current node' }) + + function! NERDTreeEchoCurrentNode() + let n = g:NERDTreeFileNode.GetSelected() + if n != {} + echomsg 'Current node: ' . n.path.str() + endif + endfunction +< + This code should sit in a file like ~/.vim/nerdtree_plugin/mymapping.vim. + It adds a (rather useless) mapping on 'b' which echos the full path to the + current node. + +------------------------------------------------------------------------------ +4.2. Menu API *NERDTreeMenuAPI* + +NERDTreeAddSubmenu({options}) *NERDTreeAddSubmenu()* + Creates and returns a new submenu. + + {options} must be a dictionary and must contain the following keys: + "text" - the text of the submenu that the user will see + "shortcut" - a shortcut key for the submenu (need not be unique) + + The following keys are optional: + "isActiveCallback" - a function that will be called to determine whether + this submenu item will be displayed or not. The callback function must return + 0 or 1. + "parent" - the parent submenu of the new submenu (returned from a previous + invocation of NERDTreeAddSubmenu()). If this key is left out then the new + submenu will sit under the top level menu. + + See below for an example. + +NERDTreeAddMenuItem({options}) *NERDTreeAddMenuItem()* + Adds a new menu item to the NERD tree menu (see |NERDTreeMenu|). + + {options} must be a dictionary and must contain the + following keys: + "text" - the text of the menu item which the user will see + "shortcut" - a shortcut key for the menu item (need not be unique) + "callback" - the function that will be called when the user activates the + menu item. + + The following keys are optional: + "isActiveCallback" - a function that will be called to determine whether + this menu item will be displayed or not. The callback function must return + 0 or 1. + "parent" - if the menu item belongs under a submenu then this key must be + specified. This value for this key will be the object that + was returned when the submenu was created with |NERDTreeAddSubmenu()|. + + See below for an example. + +NERDTreeAddMenuSeparator([{options}]) *NERDTreeAddMenuSeparator()* + Adds a menu separator (a row of dashes). + + {options} is an optional dictionary that may contain the following keys: + "isActiveCallback" - see description in |NERDTreeAddMenuItem()|. + +Below is an example of the menu API in action. > + call NERDTreeAddMenuSeparator() + + call NERDTreeAddMenuItem({ + \ 'text': 'a (t)op level menu item', + \ 'shortcut': 't', + \ 'callback': 'SomeFunction' }) + + let submenu = NERDTreeAddSubmenu({ + \ 'text': 'a (s)ub menu', + \ 'shortcut': 's' }) + + call NERDTreeAddMenuItem({ + \ 'text': '(n)ested item 1', + \ 'shortcut': 'n', + \ 'callback': 'SomeFunction', + \ 'parent': submenu }) + + call NERDTreeAddMenuItem({ + \ 'text': '(n)ested item 2', + \ 'shortcut': 'n', + \ 'callback': 'SomeFunction', + \ 'parent': submenu }) +< +This will create the following menu: > + -------------------- + a (t)op level menu item + a (s)ub menu +< +Where selecting "a (s)ub menu" will lead to a second menu: > + (n)ested item 1 + (n)ested item 2 +< +When any of the 3 concrete menu items are selected the function "SomeFunction" +will be called. + +------------------------------------------------------------------------------ +NERDTreeRender() *NERDTreeRender()* + Re-renders the NERD tree buffer. Useful if you change the state of the + tree and you want to it to be reflected in the UI. + +============================================================================== +5. About *NERDTreeAbout* + +The author of the NERD tree is a terrible terrible monster called Martyzilla +who gobbles up small children with milk and sugar for breakfast. + +He can be reached at martin.grenfell at gmail dot com. He would love to hear +from you, so feel free to send him suggestions and/or comments about this +plugin. Don't be shy --- the worst he can do is slaughter you and stuff you in +the fridge for later ;) + +The latest stable versions can be found at + http://www.vim.org/scripts/script.php?script_id=1658 + +The latest dev versions are on github + http://github.com/scrooloose/nerdtree + + +============================================================================== +6. Changelog *NERDTreeChangelog* + +4.2.0 + - Add NERDTreeDirArrows option to make the UI use pretty arrow chars + instead of the old +~| chars to define the tree structure (sickill) + - shift the syntax highlighting out into its own syntax file (gnap) + - add some mac specific options to the filesystem menu - for macvim + only (andersonfreitas) + - Add NERDTreeMinimalUI option to remove some non functional parts of the + nerdtree ui (camthompson) + - tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the + new behaviour (benjamingeiger) + - if no name is given to :Bookmark, make it default to the name of the + target file/dir (minyoung) + - use 'file' completion when doing copying, create, and move + operations (EvanDotPro) + - lots of misc bug fixes (paddyoloughlin, sdewald, camthompson, Vitaly + Bogdanov, AndrewRadev, mathias, scottstvnsn, kml, wycats, me RAWR!) + +4.1.0 + features: + - NERDTreeFind to reveal the node for the current buffer in the tree, + see |NERDTreeFind|. This effectively merges the FindInNERDTree plugin (by + Doug McInnes) into the script. + - make NERDTreeQuitOnOpen apply to the t/T keymaps too. Thanks to Stefan + Ritter and Rémi Prévost. + - truncate the root node if wider than the tree window. Thanks to Victor + Gonzalez. + + bugfixes: + - really fix window state restoring + - fix some win32 path escaping issues. Thanks to Stephan Baumeister, Ricky, + jfilip1024, and Chris Chambers + +4.0.0 + - add a new programmable menu system (see :help NERDTreeMenu). + - add new APIs to add menus/menu-items to the menu system as well as + custom key mappings to the NERD tree buffer (see :help NERDTreeAPI). + - removed the old API functions + - added a mapping to maximize/restore the size of nerd tree window, thanks + to Guillaume Duranceau for the patch. See :help NERDTree-A for details. + + - fix a bug where secondary nerd trees (netrw hijacked trees) and + NERDTreeQuitOnOpen didnt play nicely, thanks to Curtis Harvey. + - fix a bug where the script ignored directories whose name ended in a dot, + thanks to Aggelos Orfanakos for the patch. + - fix a bug when using the x mapping on the tree root, thanks to Bryan + Venteicher for the patch. + - fix a bug where the cursor position/window size of the nerd tree buffer + wasnt being stored on closing the window, thanks to Richard Hart. + - fix a bug where NERDTreeMirror would mirror the wrong tree + +3.1.1 + - fix a bug where a non-listed no-name buffer was getting created every + time the tree windows was created, thanks to Derek Wyatt and owen1 + - make behave the same as the 'o' mapping + - some helptag fixes in the doc, thanks strull + - fix a bug when using :set nohidden and opening a file where the previous + buf was modified. Thanks iElectric + - other minor fixes + +3.1.0 + New features: + - add mappings to open files in a vsplit, see :help NERDTree-s and :help + NERDTree-gs + - make the statusline for the nerd tree window default to something + hopefully more useful. See :help 'NERDTreeStatusline' + Bugfixes: + - make the hijack netrw functionality work when vim is started with "vim + " (thanks to Alf Mikula for the patch). + - fix a bug where the CWD wasnt being changed for some operations even when + NERDTreeChDirMode==2 (thanks to Lucas S. Buchala) + - add -bar to all the nerd tree :commands so they can chain with other + :commands (thanks to tpope) + - fix bugs when ignorecase was set (thanks to nach) + - fix a bug with the relative path code (thanks to nach) + - fix a bug where doing a :cd would cause :NERDTreeToggle to fail (thanks nach) + + +3.0.1 + Bugfixes: + - fix bugs with :NERDTreeToggle and :NERDTreeMirror when 'hidden + was not set + - fix a bug where :NERDTree would fail if was relative and + didnt start with a ./ or ../ Thanks to James Kanze. + - make the q mapping work with secondary (:e style) trees, + thanks to jamessan + - fix a bunch of small bugs with secondary trees + + More insane refactoring. + +3.0.0 + - hijack netrw so that doing an :edit will put a NERD tree in + the window rather than a netrw browser. See :help 'NERDTreeHijackNetrw' + - allow sharing of trees across tabs, see :help :NERDTreeMirror + - remove "top" and "bottom" as valid settings for NERDTreeWinPos + - change the '' mapping to 'i' + - change the 'H' mapping to 'I' + - lots of refactoring + +============================================================================== +7. Credits *NERDTreeCredits* + +Thanks to the following people for testing, bug reports, ideas etc. Without +you I probably would have got bored of the hacking the NERD tree and +just downloaded pr0n instead. + + Tim Carey-Smith (halorgium) + Vigil + Nick Brettell + Thomas Scott Urban + Terrance Cohen + Yegappan Lakshmanan + Jason Mills + Michael Geddes (frogonwheels) + Yu Jun + Michael Madsen + AOYAMA Shotaro + Zhang Weiwu + Niels Aan de Brugh + Olivier Yiptong + Zhang Shuhan + Cory Echols + Piotr Czachur + Yuan Jiang + Matan Nassau + Maxim Kim + Charlton Wang + Matt Wozniski (godlygeek) + knekk + Sean Chou + Ryan Penn + Simon Peter Nicholls + Michael Foobar + Tomasz Chomiuk + Denis Pokataev + Tim Pope (tpope) + James Kanze + James Vega (jamessan) + Frederic Chanal (nach) + Alf Mikula + Lucas S. Buchala + Curtis Harvey + Guillaume Duranceau + Richard Hart (hates) + Doug McInnes + Stefan Ritter + Rémi Prévost + Victor Gonzalez + Stephan Baumeister + Ricky + jfilip1024 + Chris Chambers + Vitaly Bogdanov + Patrick O'Loughlin (paddyoloughlin) + Cam Thompson (camthompson) + Marcin Kulik (sickill) + Steve DeWald (sdewald) + Ivan Necas (iNecas) + George Ang (gnap) + Evan Coury (EvanDotPro) + Andrew Radev (AndrewRadev) + Matt Gauger (mathias) + Scott Stevenson (scottstvnsn) + Anderson Freitas (andersonfreitas) + Kamil K. Lemański (kml) + Yehuda Katz (wycats) + Min-Young Wu (minyoung) + Benjamin Geiger (benjamingeiger) + +============================================================================== +8. License *NERDTreeLicense* + +The NERD tree is released under the wtfpl. +See http://sam.zoy.org/wtfpl/COPYING. diff --git a/.vim/doc/fuf.jax b/.vim/doc/fuf.jax new file mode 100644 index 0000000..403872f --- /dev/null +++ b/.vim/doc/fuf.jax @@ -0,0 +1,1405 @@ +*fuf.jax* バッファ/ファイル/その他を、あいまい検索 + + Copyright (c) 2007-2010 Takeshi NISHIDA + +FuzzyFinder *fuzzyfinder* *fuf* + +概要 |fuf-introduction| +インストール |fuf-installation| +使い方 |fuf-usage| +モード |fuf-modes| +詳細なトピック |fuf-detailed-topics| +コマンド |fuf-commands| +オプション |fuf-options| +VIMRC の例 |fuf-vimrc-example| +SPECIAL THANKS |fuf-thanks| +CHANGELOG |fuf-changelog| +あばうと |fuf-about| + +============================================================================== +概要 *fuf-introduction* + +FuzzyFinder はバッファ/ファイル/コマンド/ブックマーク/タグに素早くアクセスする +ための手段を提供します。入力されたパターンから変換されたあいまいパターンまたは +部分一致パターンで検索を行います。 + + 入力パターン あいまいパターン 部分一致パターン ~ +> + 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/.vim/doc/fuf.txt b/.vim/doc/fuf.txt new file mode 100644 index 0000000..2e36831 --- /dev/null +++ b/.vim/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/.vim/doc/taglist.txt b/.vim/doc/taglist.txt new file mode 100644 index 0000000..6a62b39 --- /dev/null +++ b/.vim/doc/taglist.txt @@ -0,0 +1,1501 @@ +*taglist.txt* Plugin for browsing source code + +Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) +For Vim version 6.0 and above +Last change: 2007 May 24 + +1. Overview |taglist-intro| +2. Taglist on the internet |taglist-internet| +3. Requirements |taglist-requirements| +4. Installation |taglist-install| +5. Usage |taglist-using| +6. Options |taglist-options| +7. Commands |taglist-commands| +8. Global functions |taglist-functions| +9. Extending |taglist-extend| +10. FAQ |taglist-faq| +11. License |taglist-license| +12. Todo |taglist-todo| + +============================================================================== + *taglist-intro* +1. Overview~ + +The "Tag List" plugin is a source code browser plugin for Vim. This plugin +allows you to efficiently browse through source code files for different +programming languages. The "Tag List" plugin provides the following features: + + * Displays the tags (functions, classes, structures, variables, etc.) + defined in a file in a vertically or horizontally split Vim window. + * In GUI Vim, optionally displays the tags in the Tags drop-down menu and + in the popup menu. + * Automatically updates the taglist window as you switch between + files/buffers. As you open new files, the tags defined in the new files + are added to the existing file list and the tags defined in all the + files are displayed grouped by the filename. + * When a tag name is selected from the taglist window, positions the + cursor at the definition of the tag in the source file. + * Automatically highlights the current tag name. + * Groups the tags by their type and displays them in a foldable tree. + * Can display the prototype and scope of a tag. + * Can optionally display the tag prototype instead of the tag name in the + taglist window. + * The tag list can be sorted either by name or by chronological order. + * Supports the following language files: Assembly, ASP, Awk, Beta, C, + C++, C#, Cobol, Eiffel, Erlang, Fortran, HTML, Java, Javascript, Lisp, + Lua, Make, Pascal, Perl, PHP, Python, Rexx, Ruby, Scheme, Shell, Slang, + SML, Sql, TCL, Verilog, Vim and Yacc. + * Can be easily extended to support new languages. Support for + existing languages can be modified easily. + * Provides functions to display the current tag name in the Vim status + line or the window title bar. + * The list of tags and files in the taglist can be saved and + restored across Vim sessions. + * Provides commands to get the name and prototype of the current tag. + * Runs in both console/terminal and GUI versions of Vim. + * Works with the winmanager plugin. Using the winmanager plugin, you + can use Vim plugins like the file explorer, buffer explorer and the + taglist plugin at the same time like an IDE. + * Can be used in both Unix and MS-Windows systems. + +============================================================================== + *taglist-internet* +2. Taglist on the internet~ + +The home page of the taglist plugin is at: +> + http://vim-taglist.sourceforge.net/ +< +You can subscribe to the taglist mailing list to post your questions or +suggestions for improvement or to send bug reports. Visit the following page +for subscribing to the mailing list: +> + http://groups.yahoo.com/group/taglist +< +============================================================================== + *taglist-requirements* +3. Requirements~ + +The taglist plugin requires the following: + + * Vim version 6.0 and above + * Exuberant ctags 5.0 and above + +The taglist plugin will work on all the platforms where the exuberant ctags +utility and Vim are supported (this includes MS-Windows and Unix based +systems). + +The taglist plugin relies on the exuberant ctags utility to dynamically +generate the tag listing. The exuberant ctags utility must be installed in +your system to use this plugin. The exuberant ctags utility is shipped with +most of the Linux distributions. You can download the exuberant ctags utility +from +> + http://ctags.sourceforge.net +< +The taglist plugin doesn't use or create a tags file and there is no need to +create a tags file to use this plugin. The taglist plugin will not work with +the GNU ctags or the Unix ctags utility. + +This plugin relies on the Vim "filetype" detection mechanism to determine the +type of the current file. You have to turn on the Vim filetype detection by +adding the following line to your .vimrc file: +> + filetype on +< +The taglist plugin will not work if you run Vim in the restricted mode (using +the -Z command-line argument). + +The taglist plugin uses the Vim system() function to invoke the exuberant +ctags utility. If Vim is compiled without the system() function then you +cannot use the taglist plugin. Some of the Linux distributions (Suse) compile +Vim without the system() function for security reasons. + +============================================================================== + *taglist-install* +4. Installation~ + +1. Download the taglist.zip file and unzip the files to the $HOME/.vim or the + $HOME/vimfiles or the $VIM/vimfiles directory. After this step, you should + have the following two files (the directory structure should be preserved): + + plugin/taglist.vim - main taglist plugin file + doc/taglist.txt - documentation (help) file + + Refer to the |add-plugin|and |'runtimepath'| Vim help pages for more + details about installing Vim plugins. +2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or $VIM/vimfiles/doc + directory, start Vim and run the ":helptags ." command to process the + taglist help file. Without this step, you cannot jump to the taglist help + topics. +3. If the exuberant ctags utility is not present in one of the directories in + the PATH environment variable, then set the 'Tlist_Ctags_Cmd' variable to + point to the location of the exuberant ctags utility (not to the directory) + in the .vimrc file. +4. If you are running a terminal/console version of Vim and the terminal + doesn't support changing the window width then set the + 'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file. +5. Restart Vim. +6. You can now use the ":TlistToggle" command to open/close the taglist + window. You can use the ":help taglist" command to get more information + about using the taglist plugin. + +To uninstall the taglist plugin, remove the plugin/taglist.vim and +doc/taglist.txt files from the $HOME/.vim or $HOME/vimfiles directory. + +============================================================================== + *taglist-using* +5. Usage~ + +The taglist plugin can be used in several different ways. + +1. You can keep the taglist window open during the entire editing session. On + opening the taglist window, the tags defined in all the files in the Vim + buffer list will be displayed in the taglist window. As you edit files, the + tags defined in them will be added to the taglist window. You can select a + tag from the taglist window and jump to it. The current tag will be + highlighted in the taglist window. You can close the taglist window when + you no longer need the window. +2. You can configure the taglist plugin to process the tags defined in all the + edited files always. In this configuration, even if the taglist window is + closed and the taglist menu is not displayed, the taglist plugin will + processes the tags defined in newly edited files. You can then open the + taglist window only when you need to select a tag and then automatically + close the taglist window after selecting the tag. +3. You can configure the taglist plugin to display only the tags defined in + the current file in the taglist window. By default, the taglist plugin + displays the tags defined in all the files in the Vim buffer list. As you + switch between files, the taglist window will be refreshed to display only + the tags defined in the current file. +4. In GUI Vim, you can use the Tags pull-down and popup menu created by the + taglist plugin to display the tags defined in the current file and select a + tag to jump to it. You can use the menu without opening the taglist window. + By default, the Tags menu is disabled. +5. You can configure the taglist plugin to display the name of the current tag + in the Vim window status line or in the Vim window title bar. For this to + work without the taglist window or menu, you need to configure the taglist + plugin to process the tags defined in a file always. +6. You can save the tags defined in multiple files to a taglist session file + and load it when needed. You can also configure the taglist plugin to not + update the taglist window when editing new files. You can then manually add + files to the taglist window. + +Opening the taglist window~ +You can open the taglist window using the ":TlistOpen" or the ":TlistToggle" +commands. The ":TlistOpen" command opens the taglist window and jumps to it. +The ":TlistToggle" command opens or closes (toggle) the taglist window and the +cursor remains in the current window. If the 'Tlist_GainFocus_On_ToggleOpen' +variable is set to 1, then the ":TlistToggle" command opens the taglist window +and moves the cursor to the taglist window. + +You can map a key to invoke these commands. For example, the following command +creates a normal mode mapping for the key to toggle the taglist window. +> + nnoremap :TlistToggle +< +Add the above mapping to your ~/.vimrc or $HOME/_vimrc file. + +To automatically open the taglist window on Vim startup, set the +'Tlist_Auto_Open' variable to 1. + +You can also open the taglist window on startup using the following command +line: +> + $ vim +TlistOpen +< +Closing the taglist window~ +You can close the taglist window from the taglist window by pressing 'q' or +using the Vim ":q" command. You can also use any of the Vim window commands to +close the taglist window. Invoking the ":TlistToggle" command when the taglist +window is opened, closes the taglist window. You can also use the +":TlistClose" command to close the taglist window. + +To automatically close the taglist window when a tag or file is selected, you +can set the 'Tlist_Close_On_Select' variable to 1. To exit Vim when only the +taglist window is present, set the 'Tlist_Exit_OnlyWindow' variable to 1. + +Jumping to a tag or a file~ +You can select a tag in the taglist window either by pressing the key +or by double clicking the tag name using the mouse. To jump to a tag on a +single mouse click set the 'Tlist_Use_SingleClick' variable to 1. + +If the selected file is already opened in a window, then the cursor is moved +to that window. If the file is not currently opened in a window then the file +is opened in the window used by the taglist plugin to show the previously +selected file. If there are no usable windows, then the file is opened in a +new window. The file is not opened in special windows like the quickfix +window, preview window and windows containing buffer with the 'buftype' option +set. + +To jump to the tag in a new window, press the 'o' key. To open the file in the +previous window (Ctrl-W_p) use the 'P' key. You can press the 'p' key to jump +to the tag but still keep the cursor in the taglist window (preview). + +To open the selected file in a tab, use the 't' key. If the file is already +present in a tab then the cursor is moved to that tab otherwise the file is +opened in a new tab. To jump to a tag in a new tab press Ctrl-t. The taglist +window is automatically opened in the newly created tab. + +Instead of jumping to a tag, you can open a file by pressing the key +or by double clicking the file name using the mouse. + +In the taglist window, you can use the [[ or key to jump to the +beginning of the previous file. You can use the ]] or key to jump to the +beginning of the next file. When you reach the first or last file, the search +wraps around and the jumps to the next/previous file. + +Highlighting the current tag~ +The taglist plugin automatically highlights the name of the current tag in the +taglist window. The Vim |CursorHold| autocmd event is used for this. If the +current tag name is not visible in the taglist window, then the taglist window +contents are scrolled to make that tag name visible. You can also use the +":TlistHighlightTag" command to force the highlighting of the current tag. + +The tag name is highlighted if no activity is performed for |'updatetime'| +milliseconds. The default value for this Vim option is 4 seconds. To avoid +unexpected problems, you should not set the |'updatetime'| option to a very +low value. + +To disable the automatic highlighting of the current tag name in the taglist +window, set the 'Tlist_Auto_Highlight_Tag' variable to zero. + +When entering a Vim buffer/window, the taglist plugin automatically highlights +the current tag in that buffer/window. If you like to disable the automatic +highlighting of the current tag when entering a buffer, set the +'Tlist_Highlight_Tag_On_BufEnter' variable to zero. + +Adding files to the taglist~ +When the taglist window is opened, all the files in the Vim buffer list are +processed and the supported files are added to the taglist. When you edit a +file in Vim, the taglist plugin automatically processes this file and adds it +to the taglist. If you close the taglist window, the tag information in the +taglist is retained. + +To process files even when the taglist window is not open, set the +'Tlist_Process_File_Always' variable to 1. + +You can manually add multiple files to the taglist without opening them using +the ":TlistAddFiles" and the ":TlistAddFilesRecursive" commands. + +For example, to add all the C files in the /my/project/dir directory to the +taglist, you can use the following command: +> + :TlistAddFiles /my/project/dir/*.c +< +Note that when adding several files with a large number of tags or a large +number of files, it will take several seconds to several minutes for the +taglist plugin to process all the files. You should not interrupt the taglist +plugin by pressing . + +You can recursively add multiple files from a directory tree using the +":TlistAddFilesRecursive" command: +> + :TlistAddFilesRecursive /my/project/dir *.c +< +This command takes two arguments. The first argument specifies the directory +from which to recursively add the files. The second optional argument +specifies the wildcard matching pattern for selecting the files to add. The +default pattern is * and all the files are added. + +Displaying tags for only one file~ +The taglist window displays the tags for all the files in the Vim buffer list +and all the manually added files. To display the tags for only the current +active buffer, set the 'Tlist_Show_One_File' variable to 1. + +Removing files from the taglist~ +You can remove a file from the taglist window, by pressing the 'd' key when the +cursor is on one of the tags listed for the file in the taglist window. The +removed file will no longer be displayed in the taglist window in the current +Vim session. To again display the tags for the file, open the file in a Vim +window and then use the ":TlistUpdate" command or use ":TlistAddFiles" command +to add the file to the taglist. + +When a buffer is removed from the Vim buffer list using the ":bdelete" or the +":bwipeout" command, the taglist is updated to remove the stored information +for this buffer. + +Updating the tags displayed for a file~ +The taglist plugin keeps track of the modification time of a file. When the +modification time changes (the file is modified), the taglist plugin +automatically updates the tags listed for that file. The modification time of +a file is checked when you enter a window containing that file or when you +load that file. + +You can also update or refresh the tags displayed for a file by pressing the +"u" key in the taglist window. If an existing file is modified, after the file +is saved, the taglist plugin automatically updates the tags displayed for the +file. + +You can also use the ":TlistUpdate" command to update the tags for the current +buffer after you made some changes to it. You should save the modified buffer +before you update the taglist window. Otherwise the listed tags will not +include the new tags created in the buffer. + +If you have deleted the tags displayed for a file in the taglist window using +the 'd' key, you can again display the tags for that file using the +":TlistUpdate" command. + +Controlling the taglist updates~ +To disable the automatic processing of new files or modified files, you can +set the 'Tlist_Auto_Update' variable to zero. When this variable is set to +zero, the taglist is updated only when you use the ":TlistUpdate" command or +the ":TlistAddFiles" or the ":TlistAddFilesRecursive" commands. You can use +this option to control which files are added to the taglist. + +You can use the ":TlistLock" command to lock the taglist contents. After this +command is executed, new files are not automatically added to the taglist. +When the taglist is locked, you can use the ":TlistUpdate" command to add the +current file or the ":TlistAddFiles" or ":TlistAddFilesRecursive" commands to +add new files to the taglist. To unlock the taglist, use the ":TlistUnlock" +command. + +Displaying the tag prototype~ +To display the prototype of the tag under the cursor in the taglist window, +press the space bar. If you place the cursor on a tag name in the taglist +window, then the tag prototype is displayed at the Vim status line after +|'updatetime'| milliseconds. The default value for the |'updatetime'| Vim +option is 4 seconds. + +You can get the name and prototype of a tag without opening the taglist window +and the taglist menu using the ":TlistShowTag" and the ":TlistShowPrototype" +commands. These commands will work only if the current file is already present +in the taglist. To use these commands without opening the taglist window, set +the 'Tlist_Process_File_Always' variable to 1. + +You can use the ":TlistShowTag" command to display the name of the tag at or +before the specified line number in the specified file. If the file name and +line number are not supplied, then this command will display the name of the +current tag. For example, +> + :TlistShowTag + :TlistShowTag myfile.java 100 +< +You can use the ":TlistShowPrototype" command to display the prototype of the +tag at or before the specified line number in the specified file. If the file +name and the line number are not supplied, then this command will display the +prototype of the current tag. For example, +> + :TlistShowPrototype + :TlistShowPrototype myfile.c 50 +< +In the taglist window, when the mouse is moved over a tag name, the tag +prototype is displayed in a balloon. This works only in GUI versions where +balloon evaluation is supported. + +Taglist window contents~ +The taglist window contains the tags defined in various files in the taglist +grouped by the filename and by the tag type (variable, function, class, etc.). +For tags with scope information (like class members, structures inside +structures, etc.), the scope information is displayed in square brackets "[]" +after the tag name. + +The contents of the taglist buffer/window are managed by the taglist plugin. +The |'filetype'| for the taglist buffer is set to 'taglist'. The Vim +|'modifiable'| option is turned off for the taglist buffer. You should not +manually edit the taglist buffer, by setting the |'modifiable'| flag. If you +manually edit the taglist buffer contents, then the taglist plugin will be out +of sync with the taglist buffer contents and the plugin will no longer work +correctly. To redisplay the taglist buffer contents again, close the taglist +window and reopen it. + +Opening and closing the tag and file tree~ +In the taglist window, the tag names are displayed as a foldable tree using +the Vim folding support. You can collapse the tree using the '-' key or using +the Vim |zc| fold command. You can open the tree using the '+' key or using +the Vim |zo| fold command. You can open all the folds using the '*' key or +using the Vim |zR| fold command. You can also use the mouse to open/close the +folds. You can close all the folds using the '=' key. You should not manually +create or delete the folds in the taglist window. + +To automatically close the fold for the inactive files/buffers and open only +the fold for the current buffer in the taglist window, set the +'Tlist_File_Fold_Auto_Close' variable to 1. + +Sorting the tags for a file~ +The tags displayed in the taglist window can be sorted either by their name or +by their chronological order. The default sorting method is by the order in +which the tags appear in a file. You can change the default sort method by +setting the 'Tlist_Sort_Type' variable to either "name" or "order". You can +sort the tags by their name by pressing the "s" key in the taglist window. You +can again sort the tags by their chronological order using the "s" key. Each +file in the taglist window can be sorted using different order. + +Zooming in and out of the taglist window~ +You can press the 'x' key in the taglist window to maximize the taglist +window width/height. The window will be maximized to the maximum possible +width/height without closing the other existing windows. You can again press +'x' to restore the taglist window to the default width/height. + + *taglist-session* +Taglist Session~ +A taglist session refers to the group of files and their tags stored in the +taglist in a Vim session. + +You can save and restore a taglist session (and all the displayed tags) using +the ":TlistSessionSave" and ":TlistSessionLoad" commands. + +To save the information about the tags and files in the taglist to a file, use +the ":TlistSessionSave" command and specify the filename: +> + :TlistSessionSave +< +To load a saved taglist session, use the ":TlistSessionLoad" command: > + + :TlistSessionLoad +< +When you load a taglist session file, the tags stored in the file will be +added to the tags already stored in the taglist. + +The taglist session feature can be used to save the tags for large files or a +group of frequently used files (like a project). By using the taglist session +file, you can minimize the amount to time it takes to load/refresh the taglist +for multiple files. + +You can create more than one taglist session file for multiple groups of +files. + +Displaying the tag name in the Vim status line or the window title bar~ +You can use the Tlist_Get_Tagname_By_Line() function provided by the taglist +plugin to display the current tag name in the Vim status line or the window +title bar. Similarly, you can use the Tlist_Get_Tag_Prototype_By_Line() +function to display the current tag prototype in the Vim status line or the +window title bar. + +For example, the following command can be used to display the current tag name +in the status line: +> + :set statusline=%<%f%=%([%{Tlist_Get_Tagname_By_Line()}]%) +< +The following command can be used to display the current tag name in the +window title bar: +> + :set title titlestring=%<%f\ %([%{Tlist_Get_Tagname_By_Line()}]%) +< +Note that the current tag name can be displayed only after the file is +processed by the taglist plugin. For this, you have to either set the +'Tlist_Process_File_Always' variable to 1 or open the taglist window or use +the taglist menu. For more information about configuring the Vim status line, +refer to the documentation for the Vim |'statusline'| option. + +Changing the taglist window highlighting~ +The following Vim highlight groups are defined and used to highlight the +various entities in the taglist window: + + TagListTagName - Used for tag names + TagListTagScope - Used for tag scope + TagListTitle - Used for tag titles + TagListComment - Used for comments + TagListFileName - Used for filenames + +By default, these highlight groups are linked to the standard Vim highlight +groups. If you want to change the colors used for these highlight groups, +prefix the highlight group name with 'My' and define it in your .vimrc or +.gvimrc file: MyTagListTagName, MyTagListTagScope, MyTagListTitle, +MyTagListComment and MyTagListFileName. For example, to change the colors +used for tag names, you can use the following command: +> + :highlight MyTagListTagName guifg=blue ctermfg=blue +< +Controlling the taglist window~ +To use a horizontally split taglist window, instead of a vertically split +window, set the 'Tlist_Use_Horiz_Window' variable to 1. + +To use a vertically split taglist window on the rightmost side of the Vim +window, set the 'Tlist_Use_Right_Window' variable to 1. + +You can specify the width of the vertically split taglist window, by setting +the 'Tlist_WinWidth' variable. You can specify the height of the horizontally +split taglist window, by setting the 'Tlist_WinHeight' variable. + +When opening a vertically split taglist window, the Vim window width is +increased to accommodate the new taglist window. When the taglist window is +closed, the Vim window is reduced. To disable this, set the +'Tlist_Inc_Winwidth' variable to zero. + +To reduce the number of empty lines in the taglist window, set the +'Tlist_Compact_Format' variable to 1. + +To not display the Vim fold column in the taglist window, set the +'Tlist_Enable_Fold_Column' variable to zero. + +To display the tag prototypes instead of the tag names in the taglist window, +set the 'Tlist_Display_Prototype' variable to 1. + +To not display the scope of the tags next to the tag names, set the +'Tlist_Display_Tag_Scope' variable to zero. + + *taglist-keys* +Taglist window key list~ +The following table lists the description of the keys that can be used +in the taglist window. + + Key Description~ + + Jump to the location where the tag under cursor is + defined. + o Jump to the location where the tag under cursor is + defined in a new window. + P Jump to the tag in the previous (Ctrl-W_p) window. + p Display the tag definition in the file window and + keep the cursor in the taglist window itself. + t Jump to the tag in a new tab. If the file is already + opened in a tab, move to that tab. + Ctrl-t Jump to the tag in a new tab. + Display the prototype of the tag under the cursor. + For file names, display the full path to the file, + file type and the number of tags. For tag types, display the + tag type and the number of tags. + u Update the tags listed in the taglist window + s Change the sort order of the tags (by name or by order) + d Remove the tags for the file under the cursor + x Zoom-in or Zoom-out the taglist window + + Open a fold + - Close a fold + * Open all folds + = Close all folds + [[ Jump to the beginning of the previous file + Jump to the beginning of the previous file + ]] Jump to the beginning of the next file + Jump to the beginning of the next file + q Close the taglist window + Display help + +The above keys will work in both the normal mode and the insert mode. + + *taglist-menu* +Taglist menu~ +When using GUI Vim, the taglist plugin can display the tags defined in the +current file in the drop-down menu and the popup menu. By default, this +feature is turned off. To turn on this feature, set the 'Tlist_Show_Menu' +variable to 1. + +You can jump to a tag by selecting the tag name from the menu. You can use the +taglist menu independent of the taglist window i.e. you don't need to open the +taglist window to get the taglist menu. + +When you switch between files/buffers, the taglist menu is automatically +updated to display the tags defined in the current file/buffer. + +The tags are grouped by their type (variables, functions, classes, methods, +etc.) and displayed as a separate sub-menu for each type. If all the tags +defined in a file are of the same type (e.g. functions), then the sub-menu is +not used. + +If the number of items in a tag type submenu exceeds the value specified by +the 'Tlist_Max_Submenu_Items' variable, then the submenu will be split into +multiple submenus. The default setting for 'Tlist_Max_Submenu_Items' is 25. +The first and last tag names in the submenu are used to form the submenu name. +The menu items are prefixed by alpha-numeric characters for easy selection by +keyboard. + +If the popup menu support is enabled (the |'mousemodel'| option contains +"popup"), then the tags menu is added to the popup menu. You can access +the popup menu by right clicking on the GUI window. + +You can regenerate the tags menu by selecting the 'Tags->Refresh menu' entry. +You can sort the tags listed in the menu either by name or by order by +selecting the 'Tags->Sort menu by->Name/Order' menu entry. + +You can tear-off the Tags menu and keep it on the side of the Vim window +for quickly locating the tags. + +Using the taglist plugin with the winmanager plugin~ +You can use the taglist plugin with the winmanager plugin. This will allow you +to use the file explorer, buffer explorer and the taglist plugin at the same +time in different windows. To use the taglist plugin with the winmanager +plugin, set 'TagList' in the 'winManagerWindowLayout' variable. For example, +to use the file explorer plugin and the taglist plugin at the same time, use +the following setting: > + + let winManagerWindowLayout = 'FileExplorer|TagList' +< +Getting help~ +If you have installed the taglist help file (this file), then you can use the +Vim ":help taglist-" command to get help on the various taglist +topics. + +You can press the key in the taglist window to display the help +information about using the taglist window. If you again press the key, +the help information is removed from the taglist window. + + *taglist-debug* +Debugging the taglist plugin~ +You can use the ":TlistDebug" command to enable logging of the debug messages +from the taglist plugin. To display the logged debug messages, you can use the +":TlistMessages" command. To disable the logging of the debug messages, use +the ":TlistUndebug" command. + +You can specify a file name to the ":TlistDebug" command to log the debug +messages to a file. Otherwise, the debug messages are stored in a script-local +variable. In the later case, to minimize memory usage, only the last 3000 +characters from the debug messages are stored. + +============================================================================== + *taglist-options* +6. Options~ + +A number of Vim variables control the behavior of the taglist plugin. These +variables are initialized to a default value. By changing these variables you +can change the behavior of the taglist plugin. You need to change these +settings only if you want to change the behavior of the taglist plugin. You +should use the |:let| command in your .vimrc file to change the setting of any +of these variables. + +The configurable taglist variables are listed below. For a detailed +description of these variables refer to the text below this table. + +|'Tlist_Auto_Highlight_Tag'| Automatically highlight the current tag in the + taglist. +|'Tlist_Auto_Open'| Open the taglist window when Vim starts. +|'Tlist_Auto_Update'| Automatically update the taglist to include + newly edited files. +|'Tlist_Close_On_Select'| Close the taglist window when a file or tag is + selected. +|'Tlist_Compact_Format'| Remove extra information and blank lines from + the taglist window. +|'Tlist_Ctags_Cmd'| Specifies the path to the ctags utility. +|'Tlist_Display_Prototype'| Show prototypes and not tags in the taglist + window. +|'Tlist_Display_Tag_Scope'| Show tag scope next to the tag name. +|'Tlist_Enable_Fold_Column'| Show the fold indicator column in the taglist + window. +|'Tlist_Exit_OnlyWindow'| Close Vim if the taglist is the only window. +|'Tlist_File_Fold_Auto_Close'| Close tag folds for inactive buffers. +|'Tlist_GainFocus_On_ToggleOpen'| + Jump to taglist window on open. +|'Tlist_Highlight_Tag_On_BufEnter'| + On entering a buffer, automatically highlight + the current tag. +|'Tlist_Inc_Winwidth'| Increase the Vim window width to accommodate + the taglist window. +|'Tlist_Max_Submenu_Items'| Maximum number of items in a tags sub-menu. +|'Tlist_Max_Tag_Length'| Maximum tag length used in a tag menu entry. +|'Tlist_Process_File_Always'| Process files even when the taglist window is + closed. +|'Tlist_Show_Menu'| Display the tags menu. +|'Tlist_Show_One_File'| Show tags for the current buffer only. +|'Tlist_Sort_Type'| Sort method used for arranging the tags. +|'Tlist_Use_Horiz_Window'| Use a horizontally split window for the + taglist window. +|'Tlist_Use_Right_Window'| Place the taglist window on the right side. +|'Tlist_Use_SingleClick'| Single click on a tag jumps to it. +|'Tlist_WinHeight'| Horizontally split taglist window height. +|'Tlist_WinWidth'| Vertically split taglist window width. + + *'Tlist_Auto_Highlight_Tag'* +Tlist_Auto_Highlight_Tag~ +The taglist plugin will automatically highlight the current tag in the taglist +window. If you want to disable this, then you can set the +'Tlist_Auto_Highlight_Tag' variable to zero. Note that even though the current +tag highlighting is disabled, the tags for a new file will still be added to +the taglist window. +> + let Tlist_Auto_Highlight_Tag = 0 +< +With the above variable set to 1, you can use the ":TlistHighlightTag" command +to highlight the current tag. + + *'Tlist_Auto_Open'* +Tlist_Auto_Open~ +To automatically open the taglist window, when you start Vim, you can set the +'Tlist_Auto_Open' variable to 1. By default, this variable is set to zero and +the taglist window will not be opened automatically on Vim startup. +> + let Tlist_Auto_Open = 1 +< +The taglist window is opened only when a supported type of file is opened on +Vim startup. For example, if you open text files, then the taglist window will +not be opened. + + *'Tlist_Auto_Update'* +Tlist_Auto_Update~ +When a new file is edited, the tags defined in the file are automatically +processed and added to the taglist. To stop adding new files to the taglist, +set the 'Tlist_Auto_Update' variable to zero. By default, this variable is set +to 1. +> + let Tlist_Auto_Update = 0 +< +With the above variable set to 1, you can use the ":TlistUpdate" command to +add the tags defined in the current file to the taglist. + + *'Tlist_Close_On_Select'* +Tlist_Close_On_Select~ +If you want to close the taglist window when a file or tag is selected, then +set the 'Tlist_Close_On_Select' variable to 1. By default, this variable is +set zero and when you select a tag or file from the taglist window, the window +is not closed. +> + let Tlist_Close_On_Select = 1 +< + *'Tlist_Compact_Format'* +Tlist_Compact_Format~ +By default, empty lines are used to separate different tag types displayed for +a file and the tags displayed for different files in the taglist window. If +you want to display as many tags as possible in the taglist window, you can +set the 'Tlist_Compact_Format' variable to 1 to get a compact display. +> + let Tlist_Compact_Format = 1 +< + *'Tlist_Ctags_Cmd'* +Tlist_Ctags_Cmd~ +The 'Tlist_Ctags_Cmd' variable specifies the location (path) of the exuberant +ctags utility. If exuberant ctags is present in any one of the directories in +the PATH environment variable, then there is no need to set this variable. + +The exuberant ctags tool can be installed under different names. When the +taglist plugin starts up, if the 'Tlist_Ctags_Cmd' variable is not set, it +checks for the names exuberant-ctags, exctags, ctags, ctags.exe and tags in +the PATH environment variable. If any one of the named executable is found, +then the Tlist_Ctags_Cmd variable is set to that name. + +If exuberant ctags is not present in one of the directories specified in the +PATH environment variable, then set this variable to point to the location of +the ctags utility in your system. Note that this variable should point to the +fully qualified exuberant ctags location and NOT to the directory in which +exuberant ctags is installed. If the exuberant ctags tool is not found in +either PATH or in the specified location, then the taglist plugin will not be +loaded. Examples: +> + let Tlist_Ctags_Cmd = 'd:\tools\ctags.exe' + let Tlist_Ctags_Cmd = '/usr/local/bin/ctags' +< + *'Tlist_Display_Prototype'* +Tlist_Display_Prototype~ +By default, only the tag name will be displayed in the taglist window. If you +like to see tag prototypes instead of names, set the 'Tlist_Display_Prototype' +variable to 1. By default, this variable is set to zero and only tag names +will be displayed. +> + let Tlist_Display_Prototype = 1 +< + *'Tlist_Display_Tag_Scope'* +Tlist_Display_Tag_Scope~ +By default, the scope of a tag (like a C++ class) will be displayed in +square brackets next to the tag name. If you don't want the tag scopes +to be displayed, then set the 'Tlist_Display_Tag_Scope' to zero. By default, +this variable is set to 1 and the tag scopes will be displayed. +> + let Tlist_Display_Tag_Scope = 0 +< + *'Tlist_Enable_Fold_Column'* +Tlist_Enable_Fold_Column~ +By default, the Vim fold column is enabled and displayed in the taglist +window. If you wish to disable this (for example, when you are working with a +narrow Vim window or terminal), you can set the 'Tlist_Enable_Fold_Column' +variable to zero. +> + let Tlist_Enable_Fold_Column = 1 +< + *'Tlist_Exit_OnlyWindow'* +Tlist_Exit_OnlyWindow~ +If you want to exit Vim if only the taglist window is currently opened, then +set the 'Tlist_Exit_OnlyWindow' variable to 1. By default, this variable is +set to zero and the Vim instance will not be closed if only the taglist window +is present. +> + let Tlist_Exit_OnlyWindow = 1 +< + *'Tlist_File_Fold_Auto_Close'* +Tlist_File_Fold_Auto_Close~ +By default, the tags tree displayed in the taglist window for all the files is +opened. You can close/fold the tags tree for the files manually. To +automatically close the tags tree for inactive files, you can set the +'Tlist_File_Fold_Auto_Close' variable to 1. When this variable is set to 1, +the tags tree for the current buffer is automatically opened and for all the +other buffers is closed. +> + let Tlist_File_Fold_Auto_Close = 1 +< + *'Tlist_GainFocus_On_ToggleOpen'* +Tlist_GainFocus_On_ToggleOpen~ +When the taglist window is opened using the ':TlistToggle' command, this +option controls whether the cursor is moved to the taglist window or remains +in the current window. By default, this option is set to 0 and the cursor +remains in the current window. When this variable is set to 1, the cursor +moves to the taglist window after opening the taglist window. +> + let Tlist_GainFocus_On_ToggleOpen = 1 +< + *'Tlist_Highlight_Tag_On_BufEnter'* +Tlist_Highlight_Tag_On_BufEnter~ +When you enter a Vim buffer/window, the current tag in that buffer/window is +automatically highlighted in the taglist window. If the current tag name is +not visible in the taglist window, then the taglist window contents are +scrolled to make that tag name visible. If you like to disable the automatic +highlighting of the current tag when entering a buffer, you can set the +'Tlist_Highlight_Tag_On_BufEnter' variable to zero. The default setting for +this variable is 1. +> + let Tlist_Highlight_Tag_On_BufEnter = 0 +< + *'Tlist_Inc_Winwidth'* +Tlist_Inc_Winwidth~ +By default, when the width of the window is less than 100 and a new taglist +window is opened vertically, then the window width is increased by the value +set in the 'Tlist_WinWidth' variable to accommodate the new window. The value +of this variable is used only if you are using a vertically split taglist +window. + +If your terminal doesn't support changing the window width from Vim (older +version of xterm running in a Unix system) or if you see any weird problems in +the screen due to the change in the window width or if you prefer not to +adjust the window width then set the 'Tlist_Inc_Winwidth' variable to zero. +CAUTION: If you are using the MS-Windows version of Vim in a MS-DOS command +window then you must set this variable to zero, otherwise the system may hang +due to a Vim limitation (explained in :help win32-problems) +> + let Tlist_Inc_Winwidth = 0 +< + *'Tlist_Max_Submenu_Items'* +Tlist_Max_Submenu_Items~ +If a file contains too many tags of a particular type (function, variable, +class, etc.), greater than that specified by the 'Tlist_Max_Submenu_Items' +variable, then the menu for that tag type will be split into multiple +sub-menus. The default setting for the 'Tlist_Max_Submenu_Items' variable is +25. This can be changed by setting the 'Tlist_Max_Submenu_Items' variable: +> + let Tlist_Max_Submenu_Items = 20 +< +The name of the submenu is formed using the names of the first and the last +tag entries in that submenu. + + *'Tlist_Max_Tag_Length'* +Tlist_Max_Tag_Length~ +Only the first 'Tlist_Max_Tag_Length' characters from the tag names will be +used to form the tag type submenu name. The default value for this variable is +10. Change the 'Tlist_Max_Tag_Length' setting if you want to include more or +less characters: +> + let Tlist_Max_Tag_Length = 10 +< + *'Tlist_Process_File_Always'* +Tlist_Process_File_Always~ +By default, the taglist plugin will generate and process the tags defined in +the newly opened files only when the taglist window is opened or when the +taglist menu is enabled. When the taglist window is closed, the taglist plugin +will stop processing the tags for newly opened files. + +You can set the 'Tlist_Process_File_Always' variable to 1 to generate the list +of tags for new files even when the taglist window is closed and the taglist +menu is disabled. +> + let Tlist_Process_File_Always = 1 +< +To use the ":TlistShowTag" and the ":TlistShowPrototype" commands without the +taglist window and the taglist menu, you should set this variable to 1. + + *'Tlist_Show_Menu'* +Tlist_Show_Menu~ +When using GUI Vim, you can display the tags defined in the current file in a +menu named "Tags". By default, this feature is turned off. To turn on this +feature, set the 'Tlist_Show_Menu' variable to 1: +> + let Tlist_Show_Menu = 1 +< + *'Tlist_Show_One_File'* +Tlist_Show_One_File~ +By default, the taglist plugin will display the tags defined in all the loaded +buffers in the taglist window. If you prefer to display the tags defined only +in the current buffer, then you can set the 'Tlist_Show_One_File' to 1. When +this variable is set to 1, as you switch between buffers, the taglist window +will be refreshed to display the tags for the current buffer and the tags for +the previous buffer will be removed. +> + let Tlist_Show_One_File = 1 +< + *'Tlist_Sort_Type'* +Tlist_Sort_Type~ +The 'Tlist_Sort_Type' variable specifies the sort order for the tags in the +taglist window. The tags can be sorted either alphabetically by their name or +by the order of their appearance in the file (chronological order). By +default, the tag names will be listed by the order in which they are defined +in the file. You can change the sort type (from name to order or from order to +name) by pressing the "s" key in the taglist window. You can also change the +default sort order by setting 'Tlist_Sort_Type' to "name" or "order": +> + let Tlist_Sort_Type = "name" +< + *'Tlist_Use_Horiz_Window'* +Tlist_Use_Horiz_Window~ +Be default, the tag names are displayed in a vertically split window. If you +prefer a horizontally split window, then set the 'Tlist_Use_Horiz_Window' +variable to 1. If you are running MS-Windows version of Vim in a MS-DOS +command window, then you should use a horizontally split window instead of a +vertically split window. Also, if you are using an older version of xterm in a +Unix system that doesn't support changing the xterm window width, you should +use a horizontally split window. +> + let Tlist_Use_Horiz_Window = 1 +< + *'Tlist_Use_Right_Window'* +Tlist_Use_Right_Window~ +By default, the vertically split taglist window will appear on the left hand +side. If you prefer to open the window on the right hand side, you can set the +'Tlist_Use_Right_Window' variable to 1: +> + let Tlist_Use_Right_Window = 1 +< + *'Tlist_Use_SingleClick'* +Tlist_Use_SingleClick~ +By default, when you double click on the tag name using the left mouse +button, the cursor will be positioned at the definition of the tag. You +can set the 'Tlist_Use_SingleClick' variable to 1 to jump to a tag when +you single click on the tag name using the mouse. By default this variable +is set to zero. +> + let Tlist_Use_SingleClick = 1 +< +Due to a bug in Vim, if you set 'Tlist_Use_SingleClick' to 1 and try to resize +the taglist window using the mouse, then Vim will crash. This problem is fixed +in Vim 6.3 and above. In the meantime, instead of resizing the taglist window +using the mouse, you can use normal Vim window resizing commands to resize the +taglist window. + + *'Tlist_WinHeight'* +Tlist_WinHeight~ +The default height of the horizontally split taglist window is 10. This can be +changed by modifying the 'Tlist_WinHeight' variable: +> + let Tlist_WinHeight = 20 +< +The |'winfixheight'| option is set for the taglist window, to maintain the +height of the taglist window, when new Vim windows are opened and existing +windows are closed. + + *'Tlist_WinWidth'* +Tlist_WinWidth~ +The default width of the vertically split taglist window is 30. This can be +changed by modifying the 'Tlist_WinWidth' variable: +> + let Tlist_WinWidth = 20 +< +Note that the value of the |'winwidth'| option setting determines the minimum +width of the current window. If you set the 'Tlist_WinWidth' variable to a +value less than that of the |'winwidth'| option setting, then Vim will use the +value of the |'winwidth'| option. + +When new Vim windows are opened and existing windows are closed, the taglist +plugin will try to maintain the width of the taglist window to the size +specified by the 'Tlist_WinWidth' variable. + +============================================================================== + *taglist-commands* +7. Commands~ + +The taglist plugin provides the following ex-mode commands: + +|:TlistAddFiles| Add multiple files to the taglist. +|:TlistAddFilesRecursive| + Add files recursively to the taglist. +|:TlistClose| Close the taglist window. +|:TlistDebug| Start logging of taglist debug messages. +|:TlistLock| Stop adding new files to the taglist. +|:TlistMessages| Display the logged taglist plugin debug messages. +|:TlistOpen| Open and jump to the taglist window. +|:TlistSessionSave| Save the information about files and tags in the + taglist to a session file. +|:TlistSessionLoad| Load the information about files and tags stored + in a session file to taglist. +|:TlistShowPrototype| Display the prototype of the tag at or before the + specified line number. +|:TlistShowTag| Display the name of the tag defined at or before the + specified line number. +|:TlistHighlightTag| Highlight the current tag in the taglist window. +|:TlistToggle| Open or close (toggle) the taglist window. +|:TlistUndebug| Stop logging of taglist debug messages. +|:TlistUnlock| Start adding new files to the taglist. +|:TlistUpdate| Update the tags for the current buffer. + + *:TlistAddFiles* +:TlistAddFiles {file(s)} [file(s) ...] + Add one or more specified files to the taglist. You can + specify multiple filenames using wildcards. To specify a + file name with space character, you should escape the space + character with a backslash. + Examples: +> + :TlistAddFiles *.c *.cpp + :TlistAddFiles file1.html file2.html +< + If you specify a large number of files, then it will take some + time for the taglist plugin to process all of them. The + specified files will not be edited in a Vim window and will + not be added to the Vim buffer list. + + *:TlistAddFilesRecursive* +:TlistAddFilesRecursive {directory} [ {pattern} ] + Add files matching {pattern} recursively from the specified + {directory} to the taglist. If {pattern} is not specified, + then '*' is assumed. To specify the current directory, use "." + for {directory}. To specify a directory name with space + character, you should escape the space character with a + backslash. + Examples: +> + :TlistAddFilesRecursive myproject *.java + :TlistAddFilesRecursive smallproject +< + If large number of files are present in the specified + directory tree, then it will take some time for the taglist + plugin to process all of them. + + *:TlistClose* +:TlistClose Close the taglist window. This command can be used from any + one of the Vim windows. + + *:TlistDebug* +:TlistDebug [filename] + Start logging of debug messages from the taglist plugin. + If {filename} is specified, then the debug messages are stored + in the specified file. Otherwise, the debug messages are + stored in a script local variable. If the file {filename} is + already present, then it is overwritten. + + *:TlistLock* +:TlistLock + Lock the taglist and don't process new files. After this + command is executed, newly edited files will not be added to + the taglist. + + *:TlistMessages* +:TlistMessages + Display the logged debug messages from the taglist plugin + in a window. This command works only when logging to a + script-local variable. + + *:TlistOpen* +:TlistOpen Open and jump to the taglist window. Creates the taglist + window, if the window is not opened currently. After executing + this command, the cursor is moved to the taglist window. When + the taglist window is opened for the first time, all the files + in the buffer list are processed and the tags defined in them + are displayed in the taglist window. + + *:TlistSessionSave* +:TlistSessionSave {filename} + Saves the information about files and tags in the taglist to + the specified file. This command can be used to save and + restore the taglist contents across Vim sessions. + + *:TlistSessionLoad* +:TlistSessionLoad {filename} + Load the information about files and tags stored in the + specified session file to the taglist. + + *:TlistShowPrototype* +:TlistShowPrototype [filename] [linenumber] + Display the prototype of the tag at or before the specified + line number. If the file name and the line number are not + specified, then the current file name and line number are + used. A tag spans multiple lines starting from the line where + it is defined to the line before the next tag. This command + displays the prototype for the tag for any line number in this + range. + + *:TlistShowTag* +:TlistShowTag [filename] [linenumber] + Display the name of the tag defined at or before the specified + line number. If the file name and the line number are not + specified, then the current file name and line number are + used. A tag spans multiple lines starting from the line where + it is defined to the line before the next tag. This command + displays the tag name for any line number in this range. + + *:TlistHighlightTag* +:TlistHighlightTag + Highlight the current tag in the taglist window. By default, + the taglist plugin periodically updates the taglist window to + highlight the current tag. This command can be used to force + the taglist plugin to highlight the current tag. + + *:TlistToggle* +:TlistToggle Open or close (toggle) the taglist window. Opens the taglist + window, if the window is not opened currently. Closes the + taglist window, if the taglist window is already opened. When + the taglist window is opened for the first time, all the files + in the buffer list are processed and the tags are displayed in + the taglist window. After executing this command, the cursor + is not moved from the current window to the taglist window. + + *:TlistUndebug* +:TlistUndebug + Stop logging of debug messages from the taglist plugin. + + *:TlistUnlock* +:TlistUnlock + Unlock the taglist and start processing newly edited files. + + *:TlistUpdate* +:TlistUpdate Update the tags information for the current buffer. This + command can be used to re-process the current file/buffer and + get the tags information. As the taglist plugin uses the file + saved in the disk (instead of the file displayed in a Vim + buffer), you should save a modified buffer before you update + the taglist. Otherwise the listed tags will not include the + new tags created in the buffer. You can use this command even + when the taglist window is not opened. + +============================================================================== + *taglist-functions* +8. Global functions~ + +The taglist plugin provides several global functions that can be used from +other Vim plugins to interact with the taglist plugin. These functions are +described below. + +|Tlist_Update_File_Tags()| Update the tags for the specified file +|Tlist_Get_Tag_Prototype_By_Line()| Return the prototype of the tag at or + before the specified line number in the + specified file. +|Tlist_Get_Tagname_By_Line()| Return the name of the tag at or + before the specified line number in + the specified file. +|Tlist_Set_App()| Set the name of the application + controlling the taglist window. + + *Tlist_Update_File_Tags()* +Tlist_Update_File_Tags({filename}, {filetype}) + Update the tags for the file {filename}. The second argument + specifies the Vim filetype for the file. If the taglist plugin + has not processed the file previously, then the exuberant + ctags tool is invoked to generate the tags for the file. + + *Tlist_Get_Tag_Prototype_By_Line()* +Tlist_Get_Tag_Prototype_By_Line([{filename}, {linenumber}]) + Return the prototype of the tag at or before the specified + line number in the specified file. If the filename and line + number are not specified, then the current buffer name and the + current line number are used. + + *Tlist_Get_Tagname_By_Line()* +Tlist_Get_Tagname_By_Line([{filename}, {linenumber}]) + Return the name of the tag at or before the specified line + number in the specified file. If the filename and line number + are not specified, then the current buffer name and the + current line number are used. + + *Tlist_Set_App()* +Tlist_Set_App({appname}) + Set the name of the plugin that controls the taglist plugin + window and buffer. This can be used to integrate the taglist + plugin with other Vim plugins. + + For example, the winmanager plugin and the Cream package use + this function and specify the appname as "winmanager" and + "cream" respectively. + + By default, the taglist plugin is a stand-alone plugin and + controls the taglist window and buffer. If the taglist window + is controlled by an external plugin, then the appname should + be set appropriately. + +============================================================================== + *taglist-extend* +9. Extending~ + +The taglist plugin supports all the languages supported by the exuberant ctags +tool, which includes the following languages: Assembly, ASP, Awk, Beta, C, +C++, C#, Cobol, Eiffel, Erlang, Fortran, HTML, Java, Javascript, Lisp, Lua, +Make, Pascal, Perl, PHP, Python, Rexx, Ruby, Scheme, Shell, Slang, SML, Sql, +TCL, Verilog, Vim and Yacc. + +You can extend the taglist plugin to add support for new languages and also +modify the support for the above listed languages. + +You should NOT make modifications to the taglist plugin script file to add +support for new languages. You will lose these changes when you upgrade to the +next version of the taglist plugin. Instead you should follow the below +described instructions to extend the taglist plugin. + +You can extend the taglist plugin by setting variables in the .vimrc or _vimrc +file. The name of these variables depends on the language name and is +described below. + +Modifying support for an existing language~ +To modify the support for an already supported language, you have to set the +tlist_xxx_settings variable in the ~/.vimrc or $HOME/_vimrc file. Replace xxx +with the Vim filetype name for the language file. For example, to modify the +support for the perl language files, you have to set the tlist_perl_settings +variable. To modify the support for java files, you have to set the +tlist_java_settings variable. + +To determine the filetype name used by Vim for a file, use the following +command in the buffer containing the file: + + :set filetype + +The above command will display the Vim filetype for the current buffer. + +The format of the value set in the tlist_xxx_settings variable is + + ;flag1:name1;flag2:name2;flag3:name3 + +The different fields in the value are separated by the ';' character. + +The first field 'language_name' is the name used by exuberant ctags to refer +to this language file. This name can be different from the file type name used +by Vim. For example, for C++, the language name used by ctags is 'c++' but the +filetype name used by Vim is 'cpp'. To get the list of language names +supported by exuberant ctags, use the following command: + + $ ctags --list-maps=all + +The remaining fields follow the format "flag:name". The sub-field 'flag' is +the language specific flag used by exuberant ctags to generate the +corresponding tags. For example, for the C language, to list only the +functions, the 'f' flag is used. To get the list of flags supported by +exuberant ctags for the various languages use the following command: + + $ ctags --list-kinds=all + +The sub-field 'name' specifies the title text to use for displaying the tags +of a particular type. For example, 'name' can be set to 'functions'. This +field can be set to any text string name. + +For example, to list only the classes and functions defined in a C++ language +file, add the following line to your .vimrc file: + + let tlist_cpp_settings = 'c++;c:class;f:function' + +In the above setting, 'cpp' is the Vim filetype name and 'c++' is the name +used by the exuberant ctags tool. 'c' and 'f' are the flags passed to +exuberant ctags to list C++ classes and functions and 'class' is the title +used for the class tags and 'function' is the title used for the function tags +in the taglist window. + +For example, to display only functions defined in a C file and to use "My +Functions" as the title for the function tags, use + + let tlist_c_settings = 'c;f:My Functions' + +When you set the tlist_xxx_settings variable, you will override the default +setting used by the taglist plugin for the 'xxx' language. You cannot add to +the default options used by the taglist plugin for a particular file type. To +add to the options used by the taglist plugin for a language, copy the option +values from the taglist plugin file to your .vimrc file and modify it. + +Adding support for a new language~ +If you want to add support for a new language to the taglist plugin, you need +to first extend the exuberant ctags tool. For more information about extending +exuberant ctags, visit the following page: + + http://ctags.sourceforge.net/EXTENDING.html + +To add support for a new language, set the tlist_xxx_settings variable in the +~/.vimrc file appropriately as described above. Replace 'xxx' in the variable +name with the Vim filetype name for the new language. + +For example, to extend the taglist plugin to support the latex language, you +can use the following line (assuming, you have already extended exuberant +ctags to support the latex language): + + let tlist_tex_settings='latex;b:bibitem;c:command;l:label' + +With the above line, when you edit files of filetype "tex" in Vim, the taglist +plugin will invoke the exuberant ctags tool passing the "latex" filetype and +the flags b, c and l to generate the tags. The text heading 'bibitem', +'command' and 'label' will be used in the taglist window for the tags which +are generated for the flags b, c and l respectively. + +============================================================================== + *taglist-faq* +10. Frequently Asked Questions~ + +Q. The taglist plugin doesn't work. The taglist window is empty and the tags + defined in a file are not displayed. +A. Are you using Vim version 6.0 and above? The taglist plugin relies on the + features supported by Vim version 6.0 and above. You can use the following + command to get the Vim version: +> + $ vim --version +< + Are you using exuberant ctags version 5.0 and above? The taglist plugin + relies on the features supported by exuberant ctags and will not work with + GNU ctags or the Unix ctags utility. You can use the following command to + determine whether the ctags installed in your system is exuberant ctags: +> + $ ctags --version +< + Is exuberant ctags present in one of the directories in your PATH? If not, + you need to set the Tlist_Ctags_Cmd variable to point to the location of + exuberant ctags. Use the following Vim command to verify that this is setup + correctly: +> + :echo system(Tlist_Ctags_Cmd . ' --version') +< + The above command should display the version information for exuberant + ctags. + + Did you turn on the Vim filetype detection? The taglist plugin relies on + the filetype detected by Vim and passes the filetype to the exuberant ctags + utility to parse the tags. Check the output of the following Vim command: +> + :filetype +< + The output of the above command should contain "filetype detection:ON". + To turn on the filetype detection, add the following line to the .vimrc or + _vimrc file: +> + filetype on +< + Is your version of Vim compiled with the support for the system() function? + The following Vim command should display 1: +> + :echo exists('*system') +< + In some Linux distributions (particularly Suse Linux), the default Vim + installation is built without the support for the system() function. The + taglist plugin uses the system() function to invoke the exuberant ctags + utility. You need to rebuild Vim after enabling the support for the + system() function. If you use the default build options, the system() + function will be supported. + + Do you have the |'shellslash'| option set? You can try disabling the + |'shellslash'| option. When the taglist plugin invokes the exuberant ctags + utility with the path to the file, if the incorrect slashes are used, then + you will see errors. + + Check the shell related Vim options values using the following command: +> + :set shell? shellcmdflag? shellpipe? + :set shellquote? shellredir? shellxquote? +< + If these options are set in your .vimrc or _vimrc file, try removing those + lines. + + Are you using a Unix shell in a MS-Windows environment? For example, + the Unix shell from the MKS-toolkit. Do you have the SHELL environment + set to point to this shell? You can try resetting the SHELL environment + variable. + + If you are using a Unix shell on MS-Windows, you should try to use + exuberant ctags that is compiled for Unix-like environments so that + exuberant ctags will understand path names with forward slash characters. + + Is your filetype supported by the exuberant ctags utility? The file types + supported by the exuberant ctags utility are listed in the ctags help. If a + file type is not supported, you have to extend exuberant ctags. You can use + the following command to list the filetypes supported by exuberant ctags: +> + ctags --list-languages +< + Run the following command from the shell prompt and check whether the tags + defined in your file are listed in the output from exuberant ctags: +> + ctags -f - --format=2 --excmd=pattern --fields=nks +< + If you see your tags in the output from the above command, then the + exuberant ctags utility is properly parsing your file. + + Do you have the .ctags or _ctags or the ctags.cnf file in your home + directory for specifying default options or for extending exuberant ctags? + If you do have this file, check the options in this file and make sure + these options are not interfering with the operation of the taglist plugin. + + If you are using MS-Windows, check the value of the TEMP and TMP + environment variables. If these environment variables are set to a path + with space characters in the name, then try using the DOS 8.3 short name + for the path or set them to a path without the space characters in the + name. For example, if the temporary directory name is "C:\Documents and + Settings\xyz\Local Settings\Temp", then try setting the TEMP variable to + the following: +> + set TEMP=C:\DOCUMEN~1\xyz\LOCALS~1\Temp +< + If exuberant ctags is installed in a directory with space characters in the + name, then try adding the directory to the PATH environment variable or try + setting the 'Tlist_Ctags_Cmd' variable to the shortest path name to ctags + or try copying the exuberant ctags to a path without space characters in + the name. For example, if exuberant ctags is installed in the directory + "C:\Program Files\Ctags", then try setting the 'Tlist_Ctags_Cmd' variable + as below: +> + let Tlist_Ctags_Cmd='C:\Progra~1\Ctags\ctags.exe' +< + If you are using a cygwin compiled version of exuberant ctags on MS-Windows, + make sure that either you have the cygwin compiled sort utility installed + and available in your PATH or compile exuberant ctags with internal sort + support. Otherwise, when exuberant ctags sorts the tags output by invoking + the sort utility, it may end up invoking the MS-Windows version of + sort.exe, thereby resulting in failure. + +Q. When I try to open the taglist window, I am seeing the following error + message. How do I fix this problem? + + Taglist: Failed to generate tags for /my/path/to/file + ctags: illegal option -- -^@usage: ctags [-BFadtuwvx] [-f tagsfile] file ... + +A. The taglist plugin will work only with the exuberant ctags tool. You + cannot use the GNU ctags or the Unix ctags program with the taglist plugin. + You will see an error message similar to the one shown above, if you try + use a non-exuberant ctags program with Vim. To fix this problem, either add + the exuberant ctags tool location to the PATH environment variable or set + the 'Tlist_Ctags_Cmd' variable. + +Q. A file has more than one tag with the same name. When I select a tag name + from the taglist window, the cursor is positioned at the incorrect tag + location. +A. The taglist plugin uses the search pattern generated by the exuberant ctags + utility to position the cursor at the location of a tag definition. If a + file has more than one tag with the same name and same prototype, then the + search pattern will be the same. In this case, when searching for the tag + pattern, the cursor may be positioned at the incorrect location. + +Q. I have made some modifications to my file and introduced new + functions/classes/variables. I have not yet saved my file. The taglist + plugin is not displaying the new tags when I update the taglist window. +A. The exuberant ctags utility will process only files that are present in the + disk. To list the tags defined in a file, you have to save the file and + then update the taglist window. + +Q. I have created a ctags file using the exuberant ctags utility for my source + tree. How do I configure the taglist plugin to use this tags file? +A. The taglist plugin doesn't use a tags file stored in disk. For every opened + file, the taglist plugin invokes the exuberant ctags utility to get the + list of tags dynamically. The Vim system() function is used to invoke + exuberant ctags and get the ctags output. This function internally uses a + temporary file to store the output. This file is deleted after the output + from the command is read. So you will never see the file that contains the + output of exuberant ctags. + +Q. When I set the |'updatetime'| option to a low value (less than 1000) and if + I keep pressing a key with the taglist window open, the current buffer + contents are changed. Why is this? +A. The taglist plugin uses the |CursorHold| autocmd to highlight the current + tag. The CursorHold autocmd triggers for every |'updatetime'| milliseconds. + If the |'updatetime'| option is set to a low value, then the CursorHold + autocmd will be triggered frequently. As the taglist plugin changes + the focus to the taglist window to highlight the current tag, this could + interfere with the key movement resulting in changing the contents of + the current buffer. The workaround for this problem is to not set the + |'updatetime'| option to a low value. + +============================================================================== + *taglist-license* +11. License~ +Permission is hereby granted to use and distribute the taglist plugin, with or +without modifications, provided that this copyright notice is copied with it. +Like anything else that's free, taglist.vim is provided *as is* and comes with +no warranty of any kind, either expressed or implied. In no event will the +copyright holder be liable for any damamges resulting from the use of this +software. + +============================================================================== + *taglist-todo* +12. Todo~ + +1. Group tags according to the scope and display them. For example, + group all the tags belonging to a C++/Java class +2. Support for displaying tags in a modified (not-yet-saved) file. +3. Automatically open the taglist window only for selected filetypes. + For other filetypes, close the taglist window. +4. When using the shell from the MKS toolkit, the taglist plugin + doesn't work. +5. The taglist plugin doesn't work with files edited remotely using the + netrw plugin. The exuberant ctags utility cannot process files over + scp/rcp/ftp, etc. + +============================================================================== + +vim:tw=78:ts=8:noet:ft=help: diff --git a/.vim/ftdetect/vala.vim b/.vim/ftdetect/vala.vim new file mode 100644 index 0000000..f665d70 --- /dev/null +++ b/.vim/ftdetect/vala.vim @@ -0,0 +1,4 @@ +au BufRead *.vala set efm=%f:%l.%c-%[%^:]%#:\ %t%[%^:]%#:\ %m +au BufRead *.vapi set efm=%f:%l.%c-%[%^:]%#:\ %t%[%^:]%#:\ %m +au BufRead,BufNewFile *.vala setf vala +au BufRead,BufNewFile *.vapi setf vala diff --git a/.vim/indent/vala.vim b/.vim/indent/vala.vim new file mode 100644 index 0000000..e224382 --- /dev/null +++ b/.vim/indent/vala.vim @@ -0,0 +1,15 @@ +" Vim indent file +" Language: C +" Maintainer: Bram Moolenaar +" Last Change: 2005 Mar 27 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +" C indenting is built-in, thus this is very simple +setlocal cindent + +let b:undo_indent = "setl cin<" diff --git a/.vim/nerdtree_plugin/exec_menuitem.vim b/.vim/nerdtree_plugin/exec_menuitem.vim new file mode 100644 index 0000000..e7a7c53 --- /dev/null +++ b/.vim/nerdtree_plugin/exec_menuitem.vim @@ -0,0 +1,41 @@ +" ============================================================================ +" File: exec_menuitem.vim +" Description: plugin for NERD Tree that provides an execute file menu item +" Maintainer: Martin Grenfell +" Last Change: 22 July, 2009 +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ +if exists("g:loaded_nerdtree_exec_menuitem") + finish +endif +let g:loaded_nerdtree_exec_menuitem = 1 + +call NERDTreeAddMenuItem({ + \ 'text': '(!)Execute file', + \ 'shortcut': '!', + \ 'callback': 'NERDTreeExecFile', + \ 'isActiveCallback': 'NERDTreeExecFileActive' }) + +function! NERDTreeExecFileActive() + let node = g:NERDTreeFileNode.GetSelected() + return !node.path.isDirectory && node.path.isExecutable +endfunction + +function! NERDTreeExecFile() + let treenode = g:NERDTreeFileNode.GetSelected() + echo "==========================================================\n" + echo "Complete the command to execute (add arguments etc):\n" + let cmd = treenode.path.str({'escape': 1}) + let cmd = input(':!', cmd . ' ') + + if cmd != '' + exec ':!' . cmd + else + echo "Aborted" + endif +endfunction diff --git a/.vim/nerdtree_plugin/fs_menu.vim b/.vim/nerdtree_plugin/fs_menu.vim new file mode 100644 index 0000000..0e2f728 --- /dev/null +++ b/.vim/nerdtree_plugin/fs_menu.vim @@ -0,0 +1,224 @@ +" ============================================================================ +" File: fs_menu.vim +" Description: plugin for the NERD Tree that provides a file system menu +" Maintainer: Martin Grenfell +" Last Change: 17 July, 2009 +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ +if exists("g:loaded_nerdtree_fs_menu") + finish +endif +let g:loaded_nerdtree_fs_menu = 1 + +call NERDTreeAddMenuItem({'text': '(a)dd a childnode', 'shortcut': 'a', 'callback': 'NERDTreeAddNode'}) +call NERDTreeAddMenuItem({'text': '(m)ove the current node', 'shortcut': 'm', 'callback': 'NERDTreeMoveNode'}) +call NERDTreeAddMenuItem({'text': '(d)elete the current node', 'shortcut': 'd', 'callback': 'NERDTreeDeleteNode'}) + +if has("gui_mac") || has("gui_macvim") + call NERDTreeAddMenuItem({'text': '(r)eveal in Finder the current node', 'shortcut': 'r', 'callback': 'NERDTreeRevealInFinder'}) + call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFile'}) + call NERDTreeAddMenuItem({'text': '(q)uicklook the current node', 'shortcut': 'q', 'callback': 'NERDTreeQuickLook'}) +endif + +if g:NERDTreePath.CopyingSupported() + call NERDTreeAddMenuItem({'text': '(c)copy the current node', 'shortcut': 'c', 'callback': 'NERDTreeCopyNode'}) +endif + +"FUNCTION: s:echo(msg){{{1 +function! s:echo(msg) + redraw + echomsg "NERDTree: " . a:msg +endfunction + +"FUNCTION: s:echoWarning(msg){{{1 +function! s:echoWarning(msg) + echohl warningmsg + call s:echo(a:msg) + echohl normal +endfunction + +"FUNCTION: s:promptToDelBuffer(bufnum, msg){{{1 +"prints out the given msg and, if the user responds by pushing 'y' then the +"buffer with the given bufnum is deleted +" +"Args: +"bufnum: the buffer that may be deleted +"msg: a message that will be echoed to the user asking them if they wish to +" del the buffer +function! s:promptToDelBuffer(bufnum, msg) + echo a:msg + if nr2char(getchar()) ==# 'y' + exec "silent bdelete! " . a:bufnum + endif +endfunction + +"FUNCTION: NERDTreeAddNode(){{{1 +function! NERDTreeAddNode() + let curDirNode = g:NERDTreeDirNode.GetSelected() + + let newNodeName = input("Add a childnode\n". + \ "==========================================================\n". + \ "Enter the dir/file name to be created. Dirs end with a '/'\n" . + \ "", curDirNode.path.str() . g:NERDTreePath.Slash(), "file") + + if newNodeName ==# '' + call s:echo("Node Creation Aborted.") + return + endif + + try + let newPath = g:NERDTreePath.Create(newNodeName) + let parentNode = b:NERDTreeRoot.findNode(newPath.getParent()) + + let newTreeNode = g:NERDTreeFileNode.New(newPath) + if parentNode.isOpen || !empty(parentNode.children) + call parentNode.addChild(newTreeNode, 1) + call NERDTreeRender() + call newTreeNode.putCursorHere(1, 0) + endif + catch /^NERDTree/ + call s:echoWarning("Node Not Created.") + endtry +endfunction + +"FUNCTION: NERDTreeMoveNode(){{{1 +function! NERDTreeMoveNode() + let curNode = g:NERDTreeFileNode.GetSelected() + let newNodePath = input("Rename the current node\n" . + \ "==========================================================\n" . + \ "Enter the new path for the node: \n" . + \ "", curNode.path.str(), "file") + + if newNodePath ==# '' + call s:echo("Node Renaming Aborted.") + return + endif + + try + let bufnum = bufnr(curNode.path.str()) + + call curNode.rename(newNodePath) + call NERDTreeRender() + + "if the node is open in a buffer, ask the user if they want to + "close that buffer + if bufnum != -1 + let prompt = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Delete this buffer? (yN)" + call s:promptToDelBuffer(bufnum, prompt) + endif + + call curNode.putCursorHere(1, 0) + + redraw + catch /^NERDTree/ + call s:echoWarning("Node Not Renamed.") + endtry +endfunction + +" FUNCTION: NERDTreeDeleteNode() {{{1 +function! NERDTreeDeleteNode() + let currentNode = g:NERDTreeFileNode.GetSelected() + let confirmed = 0 + + if currentNode.path.isDirectory + let choice =input("Delete the current node\n" . + \ "==========================================================\n" . + \ "STOP! To delete this entire directory, type 'yes'\n" . + \ "" . currentNode.path.str() . ": ") + let confirmed = choice ==# 'yes' + else + echo "Delete the current node\n" . + \ "==========================================================\n". + \ "Are you sure you wish to delete the node:\n" . + \ "" . currentNode.path.str() . " (yN):" + let choice = nr2char(getchar()) + let confirmed = choice ==# 'y' + endif + + + if confirmed + try + call currentNode.delete() + call NERDTreeRender() + + "if the node is open in a buffer, ask the user if they want to + "close that buffer + let bufnum = bufnr(currentNode.path.str()) + if buflisted(bufnum) + let prompt = "\nNode deleted.\n\nThe file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Delete this buffer? (yN)" + call s:promptToDelBuffer(bufnum, prompt) + endif + + redraw + catch /^NERDTree/ + call s:echoWarning("Could not remove node") + endtry + else + call s:echo("delete aborted") + endif + +endfunction + +" FUNCTION: NERDTreeCopyNode() {{{1 +function! NERDTreeCopyNode() + let currentNode = g:NERDTreeFileNode.GetSelected() + let newNodePath = input("Copy the current node\n" . + \ "==========================================================\n" . + \ "Enter the new path to copy the node to: \n" . + \ "", currentNode.path.str(), "file") + + if newNodePath != "" + "strip trailing slash + let newNodePath = substitute(newNodePath, '\/$', '', '') + + let confirmed = 1 + if currentNode.path.copyingWillOverwrite(newNodePath) + call s:echo("Warning: copying may overwrite files! Continue? (yN)") + let choice = nr2char(getchar()) + let confirmed = choice ==# 'y' + endif + + if confirmed + try + let newNode = currentNode.copy(newNodePath) + if !empty(newNode) + call NERDTreeRender() + call newNode.putCursorHere(0, 0) + endif + catch /^NERDTree/ + call s:echoWarning("Could not copy node") + endtry + endif + else + call s:echo("Copy aborted.") + endif + redraw +endfunction + +function! NERDTreeQuickLook() + let treenode = g:NERDTreeFileNode.GetSelected() + if treenode != {} + call system("qlmanage -p 2>/dev/null '" . treenode.path.str() . "'") + endif +endfunction + +function! NERDTreeRevealInFinder() + let treenode = g:NERDTreeFileNode.GetSelected() + if treenode != {} + let x = system("open -R '" . treenode.path.str() . "'") + endif +endfunction + +function! NERDTreeExecuteFile() + let treenode = g:NERDTreeFileNode.GetSelected() + if treenode != {} + let x = system("open '" . treenode.path.str() . "'") + endif +endfunction + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/plugin/NERD_tree.vim b/.vim/plugin/NERD_tree.vim new file mode 100644 index 0000000..bc34775 --- /dev/null +++ b/.vim/plugin/NERD_tree.vim @@ -0,0 +1,4017 @@ +" ============================================================================ +" File: NERD_tree.vim +" Description: vim global plugin that provides a nice tree explorer +" Maintainer: Martin Grenfell +" Last Change: 28 December, 2011 +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ +let s:NERD_tree_version = '4.2.0' + +" SECTION: Script init stuff {{{1 +"============================================================ +if exists("loaded_nerd_tree") + finish +endif +if v:version < 700 + echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!" + finish +endif +let loaded_nerd_tree = 1 + +"for line continuation - i.e dont want C in &cpo +let s:old_cpo = &cpo +set cpo&vim + +let s:running_windows = has("win16") || has("win32") || has("win64") + +"Function: s:initVariable() function {{{2 +"This function is used to initialise a given variable to a given value. The +"variable is only initialised if it does not exist prior +" +"Args: +"var: the name of the var to be initialised +"value: the value to initialise var to +" +"Returns: +"1 if the var is set, 0 otherwise +function! s:initVariable(var, value) + if !exists(a:var) + exec 'let ' . a:var . ' = ' . "'" . substitute(a:value, "'", "''", "g") . "'" + return 1 + endif + return 0 +endfunction + +"SECTION: Init variable calls and other random constants {{{2 +call s:initVariable("g:NERDChristmasTree", 1) +call s:initVariable("g:NERDTreeAutoCenter", 1) +call s:initVariable("g:NERDTreeAutoCenterThreshold", 3) +call s:initVariable("g:NERDTreeCaseSensitiveSort", 0) +call s:initVariable("g:NERDTreeChDirMode", 0) +call s:initVariable("g:NERDTreeMinimalUI", 0) +if !exists("g:NERDTreeIgnore") + let g:NERDTreeIgnore = ['\~$'] +endif +call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks') +call s:initVariable("g:NERDTreeHighlightCursorline", 1) +call s:initVariable("g:NERDTreeHijackNetrw", 1) +call s:initVariable("g:NERDTreeMouseMode", 1) +call s:initVariable("g:NERDTreeNotificationThreshold", 100) +call s:initVariable("g:NERDTreeQuitOnOpen", 0) +call s:initVariable("g:NERDTreeShowBookmarks", 0) +call s:initVariable("g:NERDTreeShowFiles", 1) +call s:initVariable("g:NERDTreeShowHidden", 0) +call s:initVariable("g:NERDTreeShowLineNumbers", 0) +call s:initVariable("g:NERDTreeSortDirs", 1) +call s:initVariable("g:NERDTreeDirArrows", !s:running_windows) + +if !exists("g:NERDTreeSortOrder") + let g:NERDTreeSortOrder = ['\/$', '*', '\.swp$', '\.bak$', '\~$'] +else + "if there isnt a * in the sort sequence then add one + if count(g:NERDTreeSortOrder, '*') < 1 + call add(g:NERDTreeSortOrder, '*') + endif +endif + +"we need to use this number many times for sorting... so we calculate it only +"once here +let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') + +if !exists('g:NERDTreeStatusline') + + "the exists() crap here is a hack to stop vim spazzing out when + "loading a session that was created with an open nerd tree. It spazzes + "because it doesnt store b:NERDTreeRoot (its a b: var, and its a hash) + let g:NERDTreeStatusline = "%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''}" + +endif +call s:initVariable("g:NERDTreeWinPos", "left") +call s:initVariable("g:NERDTreeWinSize", 31) + +"init the shell commands that will be used to copy nodes, and remove dir trees +" +"Note: the space after the command is important +if s:running_windows + call s:initVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ') +else + call s:initVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ') + call s:initVariable("g:NERDTreeCopyCmd", 'cp -r ') +endif + + +"SECTION: Init variable calls for key mappings {{{2 +call s:initVariable("g:NERDTreeMapActivateNode", "o") +call s:initVariable("g:NERDTreeMapChangeRoot", "C") +call s:initVariable("g:NERDTreeMapChdir", "cd") +call s:initVariable("g:NERDTreeMapCloseChildren", "X") +call s:initVariable("g:NERDTreeMapCloseDir", "x") +call s:initVariable("g:NERDTreeMapDeleteBookmark", "D") +call s:initVariable("g:NERDTreeMapMenu", "m") +call s:initVariable("g:NERDTreeMapHelp", "?") +call s:initVariable("g:NERDTreeMapJumpFirstChild", "K") +call s:initVariable("g:NERDTreeMapJumpLastChild", "J") +call s:initVariable("g:NERDTreeMapJumpNextSibling", "") +call s:initVariable("g:NERDTreeMapJumpParent", "p") +call s:initVariable("g:NERDTreeMapJumpPrevSibling", "") +call s:initVariable("g:NERDTreeMapJumpRoot", "P") +call s:initVariable("g:NERDTreeMapOpenExpl", "e") +call s:initVariable("g:NERDTreeMapOpenInTab", "t") +call s:initVariable("g:NERDTreeMapOpenInTabSilent", "T") +call s:initVariable("g:NERDTreeMapOpenRecursively", "O") +call s:initVariable("g:NERDTreeMapOpenSplit", "i") +call s:initVariable("g:NERDTreeMapOpenVSplit", "s") +call s:initVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode) +call s:initVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit) +call s:initVariable("g:NERDTreeMapPreviewVSplit", "g" . NERDTreeMapOpenVSplit) +call s:initVariable("g:NERDTreeMapQuit", "q") +call s:initVariable("g:NERDTreeMapRefresh", "r") +call s:initVariable("g:NERDTreeMapRefreshRoot", "R") +call s:initVariable("g:NERDTreeMapToggleBookmarks", "B") +call s:initVariable("g:NERDTreeMapToggleFiles", "F") +call s:initVariable("g:NERDTreeMapToggleFilters", "f") +call s:initVariable("g:NERDTreeMapToggleHidden", "I") +call s:initVariable("g:NERDTreeMapToggleZoom", "A") +call s:initVariable("g:NERDTreeMapUpdir", "u") +call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U") + +"SECTION: Script level variable declaration{{{2 +if s:running_windows + let s:escape_chars = " `\|\"#%&,?()\*^<>" +else + let s:escape_chars = " \\`\|\"#%&,?()\*^<>[]" +endif +let s:NERDTreeBufName = 'NERD_tree_' + +let s:tree_wid = 2 +let s:tree_markup_reg = '^[ `|]*[\-+~▾▸ ]\+' +let s:tree_up_dir_line = '.. (up a dir)' + +"the number to add to the nerd tree buffer name to make the buf name unique +let s:next_buffer_number = 1 + +" SECTION: Commands {{{1 +"============================================================ +"init the command that users start the nerd tree with +command! -n=? -complete=dir -bar NERDTree :call s:initNerdTree('') +command! -n=? -complete=dir -bar NERDTreeToggle :call s:toggle('') +command! -n=0 -bar NERDTreeClose :call s:closeTreeIfOpen() +command! -n=1 -complete=customlist,s:completeBookmarks -bar NERDTreeFromBookmark call s:initNerdTree('') +command! -n=0 -bar NERDTreeMirror call s:initNerdTreeMirror() +command! -n=0 -bar NERDTreeFind call s:findAndRevealPath() +" SECTION: Auto commands {{{1 +"============================================================ +augroup NERDTree + "Save the cursor position whenever we close the nerd tree + exec "autocmd BufWinLeave ". s:NERDTreeBufName ."* call saveScreenState()" + + "disallow insert mode in the NERDTree + exec "autocmd BufEnter ". s:NERDTreeBufName ."* stopinsert" + + "cache bookmarks when vim loads + autocmd VimEnter * call s:Bookmark.CacheBookmarks(0) + + "load all nerdtree plugins after vim starts + autocmd VimEnter * runtime! nerdtree_plugin/**/*.vim +augroup END + +if g:NERDTreeHijackNetrw + augroup NERDTreeHijackNetrw + autocmd VimEnter * silent! autocmd! FileExplorer + au BufEnter,VimEnter * call s:checkForBrowse(expand("")) + augroup END +endif + +"SECTION: Classes {{{1 +"============================================================ +"CLASS: Bookmark {{{2 +"============================================================ +let s:Bookmark = {} +" FUNCTION: Bookmark.activate() {{{3 +function! s:Bookmark.activate() + if self.path.isDirectory + call self.toRoot() + else + if self.validate() + let n = s:TreeFileNode.New(self.path) + call n.open() + call s:closeTreeIfQuitOnOpen() + endif + endif +endfunction +" FUNCTION: Bookmark.AddBookmark(name, path) {{{3 +" Class method to add a new bookmark to the list, if a previous bookmark exists +" with the same name, just update the path for that bookmark +function! s:Bookmark.AddBookmark(name, path) + for i in s:Bookmark.Bookmarks() + if i.name ==# a:name + let i.path = a:path + return + endif + endfor + call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path)) + call s:Bookmark.Sort() +endfunction +" Function: Bookmark.Bookmarks() {{{3 +" Class method to get all bookmarks. Lazily initializes the bookmarks global +" variable +function! s:Bookmark.Bookmarks() + if !exists("g:NERDTreeBookmarks") + let g:NERDTreeBookmarks = [] + endif + return g:NERDTreeBookmarks +endfunction +" Function: Bookmark.BookmarkExistsFor(name) {{{3 +" class method that returns 1 if a bookmark with the given name is found, 0 +" otherwise +function! s:Bookmark.BookmarkExistsFor(name) + try + call s:Bookmark.BookmarkFor(a:name) + return 1 + catch /^NERDTree.BookmarkNotFoundError/ + return 0 + endtry +endfunction +" Function: Bookmark.BookmarkFor(name) {{{3 +" Class method to get the bookmark that has the given name. {} is return if no +" bookmark is found +function! s:Bookmark.BookmarkFor(name) + for i in s:Bookmark.Bookmarks() + if i.name ==# a:name + return i + endif + endfor + throw "NERDTree.BookmarkNotFoundError: no bookmark found for name: \"". a:name .'"' +endfunction +" Function: Bookmark.BookmarkNames() {{{3 +" Class method to return an array of all bookmark names +function! s:Bookmark.BookmarkNames() + let names = [] + for i in s:Bookmark.Bookmarks() + call add(names, i.name) + endfor + return names +endfunction +" FUNCTION: Bookmark.CacheBookmarks(silent) {{{3 +" Class method to read all bookmarks from the bookmarks file intialize +" bookmark objects for each one. +" +" Args: +" silent - dont echo an error msg if invalid bookmarks are found +function! s:Bookmark.CacheBookmarks(silent) + if filereadable(g:NERDTreeBookmarksFile) + let g:NERDTreeBookmarks = [] + let g:NERDTreeInvalidBookmarks = [] + let bookmarkStrings = readfile(g:NERDTreeBookmarksFile) + let invalidBookmarksFound = 0 + for i in bookmarkStrings + + "ignore blank lines + if i != '' + + let name = substitute(i, '^\(.\{-}\) .*$', '\1', '') + let path = substitute(i, '^.\{-} \(.*\)$', '\1', '') + + try + let bookmark = s:Bookmark.New(name, s:Path.New(path)) + call add(g:NERDTreeBookmarks, bookmark) + catch /^NERDTree.InvalidArgumentsError/ + call add(g:NERDTreeInvalidBookmarks, i) + let invalidBookmarksFound += 1 + endtry + endif + endfor + if invalidBookmarksFound + call s:Bookmark.Write() + if !a:silent + call s:echo(invalidBookmarksFound . " invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.") + endif + endif + call s:Bookmark.Sort() + endif +endfunction +" FUNCTION: Bookmark.compareTo(otherbookmark) {{{3 +" Compare these two bookmarks for sorting purposes +function! s:Bookmark.compareTo(otherbookmark) + return a:otherbookmark.name < self.name +endfunction +" FUNCTION: Bookmark.ClearAll() {{{3 +" Class method to delete all bookmarks. +function! s:Bookmark.ClearAll() + for i in s:Bookmark.Bookmarks() + call i.delete() + endfor + call s:Bookmark.Write() +endfunction +" FUNCTION: Bookmark.delete() {{{3 +" Delete this bookmark. If the node for this bookmark is under the current +" root, then recache bookmarks for its Path object +function! s:Bookmark.delete() + let node = {} + try + let node = self.getNode(1) + catch /^NERDTree.BookmarkedNodeNotFoundError/ + endtry + call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self)) + if !empty(node) + call node.path.cacheDisplayString() + endif + call s:Bookmark.Write() +endfunction +" FUNCTION: Bookmark.getNode(searchFromAbsoluteRoot) {{{3 +" Gets the treenode for this bookmark +" +" Args: +" searchFromAbsoluteRoot: specifies whether we should search from the current +" tree root, or the highest cached node +function! s:Bookmark.getNode(searchFromAbsoluteRoot) + let searchRoot = a:searchFromAbsoluteRoot ? s:TreeDirNode.AbsoluteTreeRoot() : b:NERDTreeRoot + let targetNode = searchRoot.findNode(self.path) + if empty(targetNode) + throw "NERDTree.BookmarkedNodeNotFoundError: no node was found for bookmark: " . self.name + endif + return targetNode +endfunction +" FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) {{{3 +" Class method that finds the bookmark with the given name and returns the +" treenode for it. +function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) + let bookmark = s:Bookmark.BookmarkFor(a:name) + return bookmark.getNode(a:searchFromAbsoluteRoot) +endfunction +" FUNCTION: Bookmark.GetSelected() {{{3 +" returns the Bookmark the cursor is over, or {} +function! s:Bookmark.GetSelected() + let line = getline(".") + let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '') + if name != line + try + return s:Bookmark.BookmarkFor(name) + catch /^NERDTree.BookmarkNotFoundError/ + return {} + endtry + endif + return {} +endfunction + +" Function: Bookmark.InvalidBookmarks() {{{3 +" Class method to get all invalid bookmark strings read from the bookmarks +" file +function! s:Bookmark.InvalidBookmarks() + if !exists("g:NERDTreeInvalidBookmarks") + let g:NERDTreeInvalidBookmarks = [] + endif + return g:NERDTreeInvalidBookmarks +endfunction +" FUNCTION: Bookmark.mustExist() {{{3 +function! s:Bookmark.mustExist() + if !self.path.exists() + call s:Bookmark.CacheBookmarks(1) + throw "NERDTree.BookmarkPointsToInvalidLocationError: the bookmark \"". + \ self.name ."\" points to a non existing location: \"". self.path.str() + endif +endfunction +" FUNCTION: Bookmark.New(name, path) {{{3 +" Create a new bookmark object with the given name and path object +function! s:Bookmark.New(name, path) + if a:name =~# ' ' + throw "NERDTree.IllegalBookmarkNameError: illegal name:" . a:name + endif + + let newBookmark = copy(self) + let newBookmark.name = a:name + let newBookmark.path = a:path + return newBookmark +endfunction +" FUNCTION: Bookmark.openInNewTab(options) {{{3 +" Create a new bookmark object with the given name and path object +function! s:Bookmark.openInNewTab(options) + let currentTab = tabpagenr() + if self.path.isDirectory + tabnew + call s:initNerdTree(self.name) + else + exec "tabedit " . self.path.str({'format': 'Edit'}) + endif + + if has_key(a:options, 'stayInCurrentTab') + exec "tabnext " . currentTab + endif +endfunction +" Function: Bookmark.setPath(path) {{{3 +" makes this bookmark point to the given path +function! s:Bookmark.setPath(path) + let self.path = a:path +endfunction +" Function: Bookmark.Sort() {{{3 +" Class method that sorts all bookmarks +function! s:Bookmark.Sort() + let CompareFunc = function("s:compareBookmarks") + call sort(s:Bookmark.Bookmarks(), CompareFunc) +endfunction +" Function: Bookmark.str() {{{3 +" Get the string that should be rendered in the view for this bookmark +function! s:Bookmark.str() + let pathStrMaxLen = winwidth(s:getTreeWinNum()) - 4 - len(self.name) + if &nu + let pathStrMaxLen = pathStrMaxLen - &numberwidth + endif + + let pathStr = self.path.str({'format': 'UI'}) + if len(pathStr) > pathStrMaxLen + let pathStr = '<' . strpart(pathStr, len(pathStr) - pathStrMaxLen) + endif + return '>' . self.name . ' ' . pathStr +endfunction +" FUNCTION: Bookmark.toRoot() {{{3 +" Make the node for this bookmark the new tree root +function! s:Bookmark.toRoot() + if self.validate() + try + let targetNode = self.getNode(1) + catch /^NERDTree.BookmarkedNodeNotFoundError/ + let targetNode = s:TreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path) + endtry + call targetNode.makeRoot() + call s:renderView() + call targetNode.putCursorHere(0, 0) + endif +endfunction +" FUNCTION: Bookmark.ToRoot(name) {{{3 +" Make the node for this bookmark the new tree root +function! s:Bookmark.ToRoot(name) + let bookmark = s:Bookmark.BookmarkFor(a:name) + call bookmark.toRoot() +endfunction + + +"FUNCTION: Bookmark.validate() {{{3 +function! s:Bookmark.validate() + if self.path.exists() + return 1 + else + call s:Bookmark.CacheBookmarks(1) + call s:renderView() + call s:echo(self.name . "now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.") + return 0 + endif +endfunction + +" Function: Bookmark.Write() {{{3 +" Class method to write all bookmarks to the bookmarks file +function! s:Bookmark.Write() + let bookmarkStrings = [] + for i in s:Bookmark.Bookmarks() + call add(bookmarkStrings, i.name . ' ' . i.path.str()) + endfor + + "add a blank line before the invalid ones + call add(bookmarkStrings, "") + + for j in s:Bookmark.InvalidBookmarks() + call add(bookmarkStrings, j) + endfor + call writefile(bookmarkStrings, g:NERDTreeBookmarksFile) +endfunction +"CLASS: KeyMap {{{2 +"============================================================ +let s:KeyMap = {} +"FUNCTION: KeyMap.All() {{{3 +function! s:KeyMap.All() + if !exists("s:keyMaps") + let s:keyMaps = [] + endif + return s:keyMaps +endfunction + +"FUNCTION: KeyMap.BindAll() {{{3 +function! s:KeyMap.BindAll() + for i in s:KeyMap.All() + call i.bind() + endfor +endfunction + +"FUNCTION: KeyMap.bind() {{{3 +function! s:KeyMap.bind() + exec "nnoremap ". self.key ." :call ". self.callback ."()" +endfunction + +"FUNCTION: KeyMap.Create(options) {{{3 +function! s:KeyMap.Create(options) + let newKeyMap = copy(self) + let newKeyMap.key = a:options['key'] + let newKeyMap.quickhelpText = a:options['quickhelpText'] + let newKeyMap.callback = a:options['callback'] + call add(s:KeyMap.All(), newKeyMap) +endfunction +"CLASS: MenuController {{{2 +"============================================================ +let s:MenuController = {} +"FUNCTION: MenuController.New(menuItems) {{{3 +"create a new menu controller that operates on the given menu items +function! s:MenuController.New(menuItems) + let newMenuController = copy(self) + if a:menuItems[0].isSeparator() + let newMenuController.menuItems = a:menuItems[1:-1] + else + let newMenuController.menuItems = a:menuItems + endif + return newMenuController +endfunction + +"FUNCTION: MenuController.showMenu() {{{3 +"start the main loop of the menu and get the user to choose/execute a menu +"item +function! s:MenuController.showMenu() + call self._saveOptions() + + try + let self.selection = 0 + + let done = 0 + while !done + redraw! + call self._echoPrompt() + let key = nr2char(getchar()) + let done = self._handleKeypress(key) + endwhile + finally + call self._restoreOptions() + endtry + + if self.selection != -1 + let m = self._current() + call m.execute() + endif +endfunction + +"FUNCTION: MenuController._echoPrompt() {{{3 +function! s:MenuController._echoPrompt() + echo "NERDTree Menu. Use j/k/enter and the shortcuts indicated" + echo "==========================================================" + + for i in range(0, len(self.menuItems)-1) + if self.selection == i + echo "> " . self.menuItems[i].text + else + echo " " . self.menuItems[i].text + endif + endfor +endfunction + +"FUNCTION: MenuController._current(key) {{{3 +"get the MenuItem that is currently selected +function! s:MenuController._current() + return self.menuItems[self.selection] +endfunction + +"FUNCTION: MenuController._handleKeypress(key) {{{3 +"change the selection (if appropriate) and return 1 if the user has made +"their choice, 0 otherwise +function! s:MenuController._handleKeypress(key) + if a:key == 'j' + call self._cursorDown() + elseif a:key == 'k' + call self._cursorUp() + elseif a:key == nr2char(27) "escape + let self.selection = -1 + return 1 + elseif a:key == "\r" || a:key == "\n" "enter and ctrl-j + return 1 + else + let index = self._nextIndexFor(a:key) + if index != -1 + let self.selection = index + if len(self._allIndexesFor(a:key)) == 1 + return 1 + endif + endif + endif + + return 0 +endfunction + +"FUNCTION: MenuController._allIndexesFor(shortcut) {{{3 +"get indexes to all menu items with the given shortcut +function! s:MenuController._allIndexesFor(shortcut) + let toReturn = [] + + for i in range(0, len(self.menuItems)-1) + if self.menuItems[i].shortcut == a:shortcut + call add(toReturn, i) + endif + endfor + + return toReturn +endfunction + +"FUNCTION: MenuController._nextIndexFor(shortcut) {{{3 +"get the index to the next menu item with the given shortcut, starts from the +"current cursor location and wraps around to the top again if need be +function! s:MenuController._nextIndexFor(shortcut) + for i in range(self.selection+1, len(self.menuItems)-1) + if self.menuItems[i].shortcut == a:shortcut + return i + endif + endfor + + for i in range(0, self.selection) + if self.menuItems[i].shortcut == a:shortcut + return i + endif + endfor + + return -1 +endfunction + +"FUNCTION: MenuController._setCmdheight() {{{3 +"sets &cmdheight to whatever is needed to display the menu +function! s:MenuController._setCmdheight() + let &cmdheight = len(self.menuItems) + 3 +endfunction + +"FUNCTION: MenuController._saveOptions() {{{3 +"set any vim options that are required to make the menu work (saving their old +"values) +function! s:MenuController._saveOptions() + let self._oldLazyredraw = &lazyredraw + let self._oldCmdheight = &cmdheight + set nolazyredraw + call self._setCmdheight() +endfunction + +"FUNCTION: MenuController._restoreOptions() {{{3 +"restore the options we saved in _saveOptions() +function! s:MenuController._restoreOptions() + let &cmdheight = self._oldCmdheight + let &lazyredraw = self._oldLazyredraw +endfunction + +"FUNCTION: MenuController._cursorDown() {{{3 +"move the cursor to the next menu item, skipping separators +function! s:MenuController._cursorDown() + let done = 0 + while !done + if self.selection < len(self.menuItems)-1 + let self.selection += 1 + else + let self.selection = 0 + endif + + if !self._current().isSeparator() + let done = 1 + endif + endwhile +endfunction + +"FUNCTION: MenuController._cursorUp() {{{3 +"move the cursor to the previous menu item, skipping separators +function! s:MenuController._cursorUp() + let done = 0 + while !done + if self.selection > 0 + let self.selection -= 1 + else + let self.selection = len(self.menuItems)-1 + endif + + if !self._current().isSeparator() + let done = 1 + endif + endwhile +endfunction + +"CLASS: MenuItem {{{2 +"============================================================ +let s:MenuItem = {} +"FUNCTION: MenuItem.All() {{{3 +"get all top level menu items +function! s:MenuItem.All() + if !exists("s:menuItems") + let s:menuItems = [] + endif + return s:menuItems +endfunction + +"FUNCTION: MenuItem.AllEnabled() {{{3 +"get all top level menu items that are currently enabled +function! s:MenuItem.AllEnabled() + let toReturn = [] + for i in s:MenuItem.All() + if i.enabled() + call add(toReturn, i) + endif + endfor + return toReturn +endfunction + +"FUNCTION: MenuItem.Create(options) {{{3 +"make a new menu item and add it to the global list +function! s:MenuItem.Create(options) + let newMenuItem = copy(self) + + let newMenuItem.text = a:options['text'] + let newMenuItem.shortcut = a:options['shortcut'] + let newMenuItem.children = [] + + let newMenuItem.isActiveCallback = -1 + if has_key(a:options, 'isActiveCallback') + let newMenuItem.isActiveCallback = a:options['isActiveCallback'] + endif + + let newMenuItem.callback = -1 + if has_key(a:options, 'callback') + let newMenuItem.callback = a:options['callback'] + endif + + if has_key(a:options, 'parent') + call add(a:options['parent'].children, newMenuItem) + else + call add(s:MenuItem.All(), newMenuItem) + endif + + return newMenuItem +endfunction + +"FUNCTION: MenuItem.CreateSeparator(options) {{{3 +"make a new separator menu item and add it to the global list +function! s:MenuItem.CreateSeparator(options) + let standard_options = { 'text': '--------------------', + \ 'shortcut': -1, + \ 'callback': -1 } + let options = extend(a:options, standard_options, "force") + + return s:MenuItem.Create(options) +endfunction + +"FUNCTION: MenuItem.CreateSubmenu(options) {{{3 +"make a new submenu and add it to global list +function! s:MenuItem.CreateSubmenu(options) + let standard_options = { 'callback': -1 } + let options = extend(a:options, standard_options, "force") + + return s:MenuItem.Create(options) +endfunction + +"FUNCTION: MenuItem.enabled() {{{3 +"return 1 if this menu item should be displayed +" +"delegates off to the isActiveCallback, and defaults to 1 if no callback was +"specified +function! s:MenuItem.enabled() + if self.isActiveCallback != -1 + return {self.isActiveCallback}() + endif + return 1 +endfunction + +"FUNCTION: MenuItem.execute() {{{3 +"perform the action behind this menu item, if this menuitem has children then +"display a new menu for them, otherwise deletegate off to the menuitem's +"callback +function! s:MenuItem.execute() + if len(self.children) + let mc = s:MenuController.New(self.children) + call mc.showMenu() + else + if self.callback != -1 + call {self.callback}() + endif + endif +endfunction + +"FUNCTION: MenuItem.isSeparator() {{{3 +"return 1 if this menuitem is a separator +function! s:MenuItem.isSeparator() + return self.callback == -1 && self.children == [] +endfunction + +"FUNCTION: MenuItem.isSubmenu() {{{3 +"return 1 if this menuitem is a submenu +function! s:MenuItem.isSubmenu() + return self.callback == -1 && !empty(self.children) +endfunction + +"CLASS: TreeFileNode {{{2 +"This class is the parent of the TreeDirNode class and constitures the +"'Component' part of the composite design pattern between the treenode +"classes. +"============================================================ +let s:TreeFileNode = {} +"FUNCTION: TreeFileNode.activate(forceKeepWinOpen) {{{3 +function! s:TreeFileNode.activate(forceKeepWinOpen) + call self.open() + if !a:forceKeepWinOpen + call s:closeTreeIfQuitOnOpen() + end +endfunction +"FUNCTION: TreeFileNode.bookmark(name) {{{3 +"bookmark this node with a:name +function! s:TreeFileNode.bookmark(name) + + "if a bookmark exists with the same name and the node is cached then save + "it so we can update its display string + let oldMarkedNode = {} + try + let oldMarkedNode = s:Bookmark.GetNodeForName(a:name, 1) + catch /^NERDTree.BookmarkNotFoundError/ + catch /^NERDTree.BookmarkedNodeNotFoundError/ + endtry + + call s:Bookmark.AddBookmark(a:name, self.path) + call self.path.cacheDisplayString() + call s:Bookmark.Write() + + if !empty(oldMarkedNode) + call oldMarkedNode.path.cacheDisplayString() + endif +endfunction +"FUNCTION: TreeFileNode.cacheParent() {{{3 +"initializes self.parent if it isnt already +function! s:TreeFileNode.cacheParent() + if empty(self.parent) + let parentPath = self.path.getParent() + if parentPath.equals(self.path) + throw "NERDTree.CannotCacheParentError: already at root" + endif + let self.parent = s:TreeFileNode.New(parentPath) + endif +endfunction +"FUNCTION: TreeFileNode.compareNodes {{{3 +"This is supposed to be a class level method but i cant figure out how to +"get func refs to work from a dict.. +" +"A class level method that compares two nodes +" +"Args: +"n1, n2: the 2 nodes to compare +function! s:compareNodes(n1, n2) + return a:n1.path.compareTo(a:n2.path) +endfunction + +"FUNCTION: TreeFileNode.clearBoomarks() {{{3 +function! s:TreeFileNode.clearBoomarks() + for i in s:Bookmark.Bookmarks() + if i.path.equals(self.path) + call i.delete() + end + endfor + call self.path.cacheDisplayString() +endfunction +"FUNCTION: TreeFileNode.copy(dest) {{{3 +function! s:TreeFileNode.copy(dest) + call self.path.copy(a:dest) + let newPath = s:Path.New(a:dest) + let parent = b:NERDTreeRoot.findNode(newPath.getParent()) + if !empty(parent) + call parent.refresh() + return parent.findNode(newPath) + else + return {} + endif +endfunction + +"FUNCTION: TreeFileNode.delete {{{3 +"Removes this node from the tree and calls the Delete method for its path obj +function! s:TreeFileNode.delete() + call self.path.delete() + call self.parent.removeChild(self) +endfunction + +"FUNCTION: TreeFileNode.displayString() {{{3 +" +"Returns a string that specifies how the node should be represented as a +"string +" +"Return: +"a string that can be used in the view to represent this node +function! s:TreeFileNode.displayString() + return self.path.displayString() +endfunction + +"FUNCTION: TreeFileNode.equals(treenode) {{{3 +" +"Compares this treenode to the input treenode and returns 1 if they are the +"same node. +" +"Use this method instead of == because sometimes when the treenodes contain +"many children, vim seg faults when doing == +" +"Args: +"treenode: the other treenode to compare to +function! s:TreeFileNode.equals(treenode) + return self.path.str() ==# a:treenode.path.str() +endfunction + +"FUNCTION: TreeFileNode.findNode(path) {{{3 +"Returns self if this node.path.Equals the given path. +"Returns {} if not equal. +" +"Args: +"path: the path object to compare against +function! s:TreeFileNode.findNode(path) + if a:path.equals(self.path) + return self + endif + return {} +endfunction +"FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{3 +" +"Finds the next sibling for this node in the indicated direction. This sibling +"must be a directory and may/may not have children as specified. +" +"Args: +"direction: 0 if you want to find the previous sibling, 1 for the next sibling +" +"Return: +"a treenode object or {} if no appropriate sibling could be found +function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) + "if we have no parent then we can have no siblings + if self.parent != {} + let nextSibling = self.findSibling(a:direction) + + while nextSibling != {} + if nextSibling.path.isDirectory && nextSibling.hasVisibleChildren() && nextSibling.isOpen + return nextSibling + endif + let nextSibling = nextSibling.findSibling(a:direction) + endwhile + endif + + return {} +endfunction +"FUNCTION: TreeFileNode.findSibling(direction) {{{3 +" +"Finds the next sibling for this node in the indicated direction +" +"Args: +"direction: 0 if you want to find the previous sibling, 1 for the next sibling +" +"Return: +"a treenode object or {} if no sibling could be found +function! s:TreeFileNode.findSibling(direction) + "if we have no parent then we can have no siblings + if self.parent != {} + + "get the index of this node in its parents children + let siblingIndx = self.parent.getChildIndex(self.path) + + if siblingIndx != -1 + "move a long to the next potential sibling node + let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 + + "keep moving along to the next sibling till we find one that is valid + let numSiblings = self.parent.getChildCount() + while siblingIndx >= 0 && siblingIndx < numSiblings + + "if the next node is not an ignored node (i.e. wont show up in the + "view) then return it + if self.parent.children[siblingIndx].path.ignore() ==# 0 + return self.parent.children[siblingIndx] + endif + + "go to next node + let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 + endwhile + endif + endif + + return {} +endfunction + +"FUNCTION: TreeFileNode.getLineNum(){{{3 +"returns the line number this node is rendered on, or -1 if it isnt rendered +function! s:TreeFileNode.getLineNum() + "if the node is the root then return the root line no. + if self.isRoot() + return s:TreeFileNode.GetRootLineNum() + endif + + let totalLines = line("$") + + "the path components we have matched so far + let pathcomponents = [substitute(b:NERDTreeRoot.path.str({'format': 'UI'}), '/ *$', '', '')] + "the index of the component we are searching for + let curPathComponent = 1 + + let fullpath = self.path.str({'format': 'UI'}) + + + let lnum = s:TreeFileNode.GetRootLineNum() + while lnum > 0 + let lnum = lnum + 1 + "have we reached the bottom of the tree? + if lnum ==# totalLines+1 + return -1 + endif + + let curLine = getline(lnum) + + let indent = s:indentLevelFor(curLine) + if indent ==# curPathComponent + let curLine = s:stripMarkupFromLine(curLine, 1) + + let curPath = join(pathcomponents, '/') . '/' . curLine + if stridx(fullpath, curPath, 0) ==# 0 + if fullpath ==# curPath || strpart(fullpath, len(curPath)-1,1) ==# '/' + let curLine = substitute(curLine, '/ *$', '', '') + call add(pathcomponents, curLine) + let curPathComponent = curPathComponent + 1 + + if fullpath ==# curPath + return lnum + endif + endif + endif + endif + endwhile + return -1 +endfunction + +"FUNCTION: TreeFileNode.GetRootForTab(){{{3 +"get the root node for this tab +function! s:TreeFileNode.GetRootForTab() + if s:treeExistsForTab() + return getbufvar(t:NERDTreeBufName, 'NERDTreeRoot') + end + return {} +endfunction +"FUNCTION: TreeFileNode.GetRootLineNum(){{{3 +"gets the line number of the root node +function! s:TreeFileNode.GetRootLineNum() + let rootLine = 1 + while getline(rootLine) !~# '^\(/\|<\)' + let rootLine = rootLine + 1 + endwhile + return rootLine +endfunction + +"FUNCTION: TreeFileNode.GetSelected() {{{3 +"gets the treenode that the cursor is currently over +function! s:TreeFileNode.GetSelected() + try + let path = s:getPath(line(".")) + if path ==# {} + return {} + endif + return b:NERDTreeRoot.findNode(path) + catch /NERDTree/ + return {} + endtry +endfunction +"FUNCTION: TreeFileNode.isVisible() {{{3 +"returns 1 if this node should be visible according to the tree filters and +"hidden file filters (and their on/off status) +function! s:TreeFileNode.isVisible() + return !self.path.ignore() +endfunction +"FUNCTION: TreeFileNode.isRoot() {{{3 +"returns 1 if this node is b:NERDTreeRoot +function! s:TreeFileNode.isRoot() + if !s:treeExistsForBuf() + throw "NERDTree.NoTreeError: No tree exists for the current buffer" + endif + + return self.equals(b:NERDTreeRoot) +endfunction + +"FUNCTION: TreeFileNode.makeRoot() {{{3 +"Make this node the root of the tree +function! s:TreeFileNode.makeRoot() + if self.path.isDirectory + let b:NERDTreeRoot = self + else + call self.cacheParent() + let b:NERDTreeRoot = self.parent + endif + + call b:NERDTreeRoot.open() + + "change dir to the dir of the new root if instructed to + if g:NERDTreeChDirMode ==# 2 + exec "cd " . b:NERDTreeRoot.path.str({'format': 'Edit'}) + endif +endfunction +"FUNCTION: TreeFileNode.New(path) {{{3 +"Returns a new TreeNode object with the given path and parent +" +"Args: +"path: a path object representing the full filesystem path to the file/dir that the node represents +function! s:TreeFileNode.New(path) + if a:path.isDirectory + return s:TreeDirNode.New(a:path) + else + let newTreeNode = copy(self) + let newTreeNode.path = a:path + let newTreeNode.parent = {} + return newTreeNode + endif +endfunction + +"FUNCTION: TreeFileNode.open() {{{3 +"Open the file represented by the given node in the current window, splitting +"the window if needed +" +"ARGS: +"treenode: file node to open +function! s:TreeFileNode.open() + if b:NERDTreeType ==# "secondary" + exec 'edit ' . self.path.str({'format': 'Edit'}) + return + endif + + "if the file is already open in this tab then just stick the cursor in it + let winnr = bufwinnr('^' . self.path.str() . '$') + if winnr != -1 + call s:exec(winnr . "wincmd w") + + else + if !s:isWindowUsable(winnr("#")) && s:firstUsableWindow() ==# -1 + call self.openSplit() + else + try + if !s:isWindowUsable(winnr("#")) + call s:exec(s:firstUsableWindow() . "wincmd w") + else + call s:exec('wincmd p') + endif + exec ("edit " . self.path.str({'format': 'Edit'})) + catch /^Vim\%((\a\+)\)\=:E37/ + call s:putCursorInTreeWin() + throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str() ." is already open and modified." + catch /^Vim\%((\a\+)\)\=:/ + echo v:exception + endtry + endif + endif +endfunction +"FUNCTION: TreeFileNode.openSplit() {{{3 +"Open this node in a new window +function! s:TreeFileNode.openSplit() + + if b:NERDTreeType ==# "secondary" + exec "split " . self.path.str({'format': 'Edit'}) + return + endif + + " Save the user's settings for splitbelow and splitright + let savesplitbelow=&splitbelow + let savesplitright=&splitright + + " 'there' will be set to a command to move from the split window + " back to the explorer window + " + " 'back' will be set to a command to move from the explorer window + " back to the newly split window + " + " 'right' and 'below' will be set to the settings needed for + " splitbelow and splitright IF the explorer is the only window. + " + let there= g:NERDTreeWinPos ==# "left" ? "wincmd h" : "wincmd l" + let back = g:NERDTreeWinPos ==# "left" ? "wincmd l" : "wincmd h" + let right= g:NERDTreeWinPos ==# "left" + let below=0 + + " Attempt to go to adjacent window + call s:exec(back) + + let onlyOneWin = (winnr("$") ==# 1) + + " If no adjacent window, set splitright and splitbelow appropriately + if onlyOneWin + let &splitright=right + let &splitbelow=below + else + " found adjacent window - invert split direction + let &splitright=!right + let &splitbelow=!below + endif + + let splitMode = onlyOneWin ? "vertical" : "" + + " Open the new window + try + exec(splitMode." sp " . self.path.str({'format': 'Edit'})) + catch /^Vim\%((\a\+)\)\=:E37/ + call s:putCursorInTreeWin() + throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str() ." is already open and modified." + catch /^Vim\%((\a\+)\)\=:/ + "do nothing + endtry + + "resize the tree window if no other window was open before + if onlyOneWin + let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize + call s:exec(there) + exec("silent ". splitMode ." resize ". size) + call s:exec('wincmd p') + endif + + " Restore splitmode settings + let &splitbelow=savesplitbelow + let &splitright=savesplitright +endfunction +"FUNCTION: TreeFileNode.openVSplit() {{{3 +"Open this node in a new vertical window +function! s:TreeFileNode.openVSplit() + if b:NERDTreeType ==# "secondary" + exec "vnew " . self.path.str({'format': 'Edit'}) + return + endif + + let winwidth = winwidth(".") + if winnr("$")==#1 + let winwidth = g:NERDTreeWinSize + endif + + call s:exec("wincmd p") + exec "vnew " . self.path.str({'format': 'Edit'}) + + "resize the nerd tree back to the original size + call s:putCursorInTreeWin() + exec("silent vertical resize ". winwidth) + call s:exec('wincmd p') +endfunction +"FUNCTION: TreeFileNode.openInNewTab(options) {{{3 +function! s:TreeFileNode.openInNewTab(options) + let currentTab = tabpagenr() + + if !has_key(a:options, 'keepTreeOpen') + call s:closeTreeIfQuitOnOpen() + endif + + exec "tabedit " . self.path.str({'format': 'Edit'}) + + if has_key(a:options, 'stayInCurrentTab') && a:options['stayInCurrentTab'] + exec "tabnext " . currentTab + endif + +endfunction +"FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{3 +"Places the cursor on the line number this node is rendered on +" +"Args: +"isJump: 1 if this cursor movement should be counted as a jump by vim +"recurseUpward: try to put the cursor on the parent if the this node isnt +"visible +function! s:TreeFileNode.putCursorHere(isJump, recurseUpward) + let ln = self.getLineNum() + if ln != -1 + if a:isJump + mark ' + endif + call cursor(ln, col(".")) + else + if a:recurseUpward + let node = self + while node != {} && node.getLineNum() ==# -1 + let node = node.parent + call node.open() + endwhile + call s:renderView() + call node.putCursorHere(a:isJump, 0) + endif + endif +endfunction + +"FUNCTION: TreeFileNode.refresh() {{{3 +function! s:TreeFileNode.refresh() + call self.path.refresh() +endfunction +"FUNCTION: TreeFileNode.rename() {{{3 +"Calls the rename method for this nodes path obj +function! s:TreeFileNode.rename(newName) + let newName = substitute(a:newName, '\(\\\|\/\)$', '', '') + call self.path.rename(newName) + call self.parent.removeChild(self) + + let parentPath = self.path.getParent() + let newParent = b:NERDTreeRoot.findNode(parentPath) + + if newParent != {} + call newParent.createChild(self.path, 1) + call newParent.refresh() + endif +endfunction +"FUNCTION: TreeFileNode.renderToString {{{3 +"returns a string representation for this tree to be rendered in the view +function! s:TreeFileNode.renderToString() + return self._renderToString(0, 0, [], self.getChildCount() ==# 1) +endfunction + + +"Args: +"depth: the current depth in the tree for this call +"drawText: 1 if we should actually draw the line for this node (if 0 then the +"child nodes are rendered only) +"vertMap: a binary array that indicates whether a vertical bar should be draw +"for each depth in the tree +"isLastChild:true if this curNode is the last child of its parent +function! s:TreeFileNode._renderToString(depth, drawText, vertMap, isLastChild) + let output = "" + if a:drawText ==# 1 + + let treeParts = '' + + "get all the leading spaces and vertical tree parts for this line + if a:depth > 1 + for j in a:vertMap[0:-2] + if g:NERDTreeDirArrows + let treeParts = treeParts . ' ' + else + if j ==# 1 + let treeParts = treeParts . '| ' + else + let treeParts = treeParts . ' ' + endif + endif + endfor + endif + + "get the last vertical tree part for this line which will be different + "if this node is the last child of its parent + if !g:NERDTreeDirArrows + if a:isLastChild + let treeParts = treeParts . '`' + else + let treeParts = treeParts . '|' + endif + endif + + "smack the appropriate dir/file symbol on the line before the file/dir + "name itself + if self.path.isDirectory + if self.isOpen + if g:NERDTreeDirArrows + let treeParts = treeParts . '▾ ' + else + let treeParts = treeParts . '~' + endif + else + if g:NERDTreeDirArrows + let treeParts = treeParts . '▸ ' + else + let treeParts = treeParts . '+' + endif + endif + else + if g:NERDTreeDirArrows + let treeParts = treeParts . ' ' + else + let treeParts = treeParts . '-' + endif + endif + let line = treeParts . self.displayString() + + let output = output . line . "\n" + endif + + "if the node is an open dir, draw its children + if self.path.isDirectory ==# 1 && self.isOpen ==# 1 + + let childNodesToDraw = self.getVisibleChildren() + if len(childNodesToDraw) > 0 + + "draw all the nodes children except the last + let lastIndx = len(childNodesToDraw)-1 + if lastIndx > 0 + for i in childNodesToDraw[0:lastIndx-1] + let output = output . i._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 1), 0) + endfor + endif + + "draw the last child, indicating that it IS the last + let output = output . childNodesToDraw[lastIndx]._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 0), 1) + endif + endif + + return output +endfunction +"CLASS: TreeDirNode {{{2 +"This class is a child of the TreeFileNode class and constitutes the +"'Composite' part of the composite design pattern between the treenode +"classes. +"============================================================ +let s:TreeDirNode = copy(s:TreeFileNode) +"FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{3 +"class method that returns the highest cached ancestor of the current root +function! s:TreeDirNode.AbsoluteTreeRoot() + let currentNode = b:NERDTreeRoot + while currentNode.parent != {} + let currentNode = currentNode.parent + endwhile + return currentNode +endfunction +"FUNCTION: TreeDirNode.activate(forceKeepWinOpen) {{{3 +unlet s:TreeDirNode.activate +function! s:TreeDirNode.activate(forceKeepWinOpen) + call self.toggleOpen() + call s:renderView() + call self.putCursorHere(0, 0) +endfunction +"FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{3 +"Adds the given treenode to the list of children for this node +" +"Args: +"-treenode: the node to add +"-inOrder: 1 if the new node should be inserted in sorted order +function! s:TreeDirNode.addChild(treenode, inOrder) + call add(self.children, a:treenode) + let a:treenode.parent = self + + if a:inOrder + call self.sortChildren() + endif +endfunction + +"FUNCTION: TreeDirNode.close() {{{3 +"Closes this directory +function! s:TreeDirNode.close() + let self.isOpen = 0 +endfunction + +"FUNCTION: TreeDirNode.closeChildren() {{{3 +"Closes all the child dir nodes of this node +function! s:TreeDirNode.closeChildren() + for i in self.children + if i.path.isDirectory + call i.close() + call i.closeChildren() + endif + endfor +endfunction + +"FUNCTION: TreeDirNode.createChild(path, inOrder) {{{3 +"Instantiates a new child node for this node with the given path. The new +"nodes parent is set to this node. +" +"Args: +"path: a Path object that this node will represent/contain +"inOrder: 1 if the new node should be inserted in sorted order +" +"Returns: +"the newly created node +function! s:TreeDirNode.createChild(path, inOrder) + let newTreeNode = s:TreeFileNode.New(a:path) + call self.addChild(newTreeNode, a:inOrder) + return newTreeNode +endfunction + +"FUNCTION: TreeDirNode.findNode(path) {{{3 +"Will find one of the children (recursively) that has the given path +" +"Args: +"path: a path object +unlet s:TreeDirNode.findNode +function! s:TreeDirNode.findNode(path) + if a:path.equals(self.path) + return self + endif + if stridx(a:path.str(), self.path.str(), 0) ==# -1 + return {} + endif + + if self.path.isDirectory + for i in self.children + let retVal = i.findNode(a:path) + if retVal != {} + return retVal + endif + endfor + endif + return {} +endfunction +"FUNCTION: TreeDirNode.getChildCount() {{{3 +"Returns the number of children this node has +function! s:TreeDirNode.getChildCount() + return len(self.children) +endfunction + +"FUNCTION: TreeDirNode.getChild(path) {{{3 +"Returns child node of this node that has the given path or {} if no such node +"exists. +" +"This function doesnt not recurse into child dir nodes +" +"Args: +"path: a path object +function! s:TreeDirNode.getChild(path) + if stridx(a:path.str(), self.path.str(), 0) ==# -1 + return {} + endif + + let index = self.getChildIndex(a:path) + if index ==# -1 + return {} + else + return self.children[index] + endif + +endfunction + +"FUNCTION: TreeDirNode.getChildByIndex(indx, visible) {{{3 +"returns the child at the given index +"Args: +"indx: the index to get the child from +"visible: 1 if only the visible children array should be used, 0 if all the +"children should be searched. +function! s:TreeDirNode.getChildByIndex(indx, visible) + let array_to_search = a:visible? self.getVisibleChildren() : self.children + if a:indx > len(array_to_search) + throw "NERDTree.InvalidArgumentsError: Index is out of bounds." + endif + return array_to_search[a:indx] +endfunction + +"FUNCTION: TreeDirNode.getChildIndex(path) {{{3 +"Returns the index of the child node of this node that has the given path or +"-1 if no such node exists. +" +"This function doesnt not recurse into child dir nodes +" +"Args: +"path: a path object +function! s:TreeDirNode.getChildIndex(path) + if stridx(a:path.str(), self.path.str(), 0) ==# -1 + return -1 + endif + + "do a binary search for the child + let a = 0 + let z = self.getChildCount() + while a < z + let mid = (a+z)/2 + let diff = a:path.compareTo(self.children[mid].path) + + if diff ==# -1 + let z = mid + elseif diff ==# 1 + let a = mid+1 + else + return mid + endif + endwhile + return -1 +endfunction + +"FUNCTION: TreeDirNode.GetSelected() {{{3 +"Returns the current node if it is a dir node, or else returns the current +"nodes parent +unlet s:TreeDirNode.GetSelected +function! s:TreeDirNode.GetSelected() + let currentDir = s:TreeFileNode.GetSelected() + if currentDir != {} && !currentDir.isRoot() + if currentDir.path.isDirectory ==# 0 + let currentDir = currentDir.parent + endif + endif + return currentDir +endfunction +"FUNCTION: TreeDirNode.getVisibleChildCount() {{{3 +"Returns the number of visible children this node has +function! s:TreeDirNode.getVisibleChildCount() + return len(self.getVisibleChildren()) +endfunction + +"FUNCTION: TreeDirNode.getVisibleChildren() {{{3 +"Returns a list of children to display for this node, in the correct order +" +"Return: +"an array of treenodes +function! s:TreeDirNode.getVisibleChildren() + let toReturn = [] + for i in self.children + if i.path.ignore() ==# 0 + call add(toReturn, i) + endif + endfor + return toReturn +endfunction + +"FUNCTION: TreeDirNode.hasVisibleChildren() {{{3 +"returns 1 if this node has any childre, 0 otherwise.. +function! s:TreeDirNode.hasVisibleChildren() + return self.getVisibleChildCount() != 0 +endfunction + +"FUNCTION: TreeDirNode._initChildren() {{{3 +"Removes all childen from this node and re-reads them +" +"Args: +"silent: 1 if the function should not echo any "please wait" messages for +"large directories +" +"Return: the number of child nodes read +function! s:TreeDirNode._initChildren(silent) + "remove all the current child nodes + let self.children = [] + + "get an array of all the files in the nodes dir + let dir = self.path + let globDir = dir.str({'format': 'Glob'}) + let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*') + let files = split(filesStr, "\n") + + if !a:silent && len(files) > g:NERDTreeNotificationThreshold + call s:echo("Please wait, caching a large dir ...") + endif + + let invalidFilesFound = 0 + for i in files + + "filter out the .. and . directories + "Note: we must match .. AND ../ cos sometimes the globpath returns + "../ for path with strange chars (eg $) + if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' + + "put the next file in a new node and attach it + try + let path = s:Path.New(i) + call self.createChild(path, 0) + catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/ + let invalidFilesFound += 1 + endtry + endif + endfor + + call self.sortChildren() + + if !a:silent && len(files) > g:NERDTreeNotificationThreshold + call s:echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).") + endif + + if invalidFilesFound + call s:echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree") + endif + return self.getChildCount() +endfunction +"FUNCTION: TreeDirNode.New(path) {{{3 +"Returns a new TreeNode object with the given path and parent +" +"Args: +"path: a path object representing the full filesystem path to the file/dir that the node represents +unlet s:TreeDirNode.New +function! s:TreeDirNode.New(path) + if a:path.isDirectory != 1 + throw "NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object." + endif + + let newTreeNode = copy(self) + let newTreeNode.path = a:path + + let newTreeNode.isOpen = 0 + let newTreeNode.children = [] + + let newTreeNode.parent = {} + + return newTreeNode +endfunction +"FUNCTION: TreeDirNode.open() {{{3 +"Reads in all this nodes children +" +"Return: the number of child nodes read +unlet s:TreeDirNode.open +function! s:TreeDirNode.open() + let self.isOpen = 1 + if self.children ==# [] + return self._initChildren(0) + else + return 0 + endif +endfunction + +" FUNCTION: TreeDirNode.openExplorer() {{{3 +" opens an explorer window for this node in the previous window (could be a +" nerd tree or a netrw) +function! s:TreeDirNode.openExplorer() + let oldwin = winnr() + call s:exec('wincmd p') + if oldwin ==# winnr() || (&modified && s:bufInWindows(winbufnr(winnr())) < 2) + call s:exec('wincmd p') + call self.openSplit() + else + exec ("silent edit " . self.path.str({'format': 'Edit'})) + endif +endfunction +"FUNCTION: TreeDirNode.openInNewTab(options) {{{3 +unlet s:TreeDirNode.openInNewTab +function! s:TreeDirNode.openInNewTab(options) + let currentTab = tabpagenr() + + if !has_key(a:options, 'keepTreeOpen') || !a:options['keepTreeOpen'] + call s:closeTreeIfQuitOnOpen() + endif + + tabnew + call s:initNerdTree(self.path.str()) + + if has_key(a:options, 'stayInCurrentTab') && a:options['stayInCurrentTab'] + exec "tabnext " . currentTab + endif +endfunction +"FUNCTION: TreeDirNode.openRecursively() {{{3 +"Opens this treenode and all of its children whose paths arent 'ignored' +"because of the file filters. +" +"This method is actually a wrapper for the OpenRecursively2 method which does +"the work. +function! s:TreeDirNode.openRecursively() + call self._openRecursively2(1) +endfunction + +"FUNCTION: TreeDirNode._openRecursively2() {{{3 +"Opens this all children of this treenode recursively if either: +" *they arent filtered by file filters +" *a:forceOpen is 1 +" +"Args: +"forceOpen: 1 if this node should be opened regardless of file filters +function! s:TreeDirNode._openRecursively2(forceOpen) + if self.path.ignore() ==# 0 || a:forceOpen + let self.isOpen = 1 + if self.children ==# [] + call self._initChildren(1) + endif + + for i in self.children + if i.path.isDirectory ==# 1 + call i._openRecursively2(0) + endif + endfor + endif +endfunction + +"FUNCTION: TreeDirNode.refresh() {{{3 +unlet s:TreeDirNode.refresh +function! s:TreeDirNode.refresh() + call self.path.refresh() + + "if this node was ever opened, refresh its children + if self.isOpen || !empty(self.children) + "go thru all the files/dirs under this node + let newChildNodes = [] + let invalidFilesFound = 0 + let dir = self.path + let globDir = dir.str({'format': 'Glob'}) + let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*') + let files = split(filesStr, "\n") + for i in files + "filter out the .. and . directories + "Note: we must match .. AND ../ cos sometimes the globpath returns + "../ for path with strange chars (eg $) + if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$' + + try + "create a new path and see if it exists in this nodes children + let path = s:Path.New(i) + let newNode = self.getChild(path) + if newNode != {} + call newNode.refresh() + call add(newChildNodes, newNode) + + "the node doesnt exist so create it + else + let newNode = s:TreeFileNode.New(path) + let newNode.parent = self + call add(newChildNodes, newNode) + endif + + + catch /^NERDTree.InvalidArgumentsError/ + let invalidFilesFound = 1 + endtry + endif + endfor + + "swap this nodes children out for the children we just read/refreshed + let self.children = newChildNodes + call self.sortChildren() + + if invalidFilesFound + call s:echoWarning("some files could not be loaded into the NERD tree") + endif + endif +endfunction + +"FUNCTION: TreeDirNode.reveal(path) {{{3 +"reveal the given path, i.e. cache and open all treenodes needed to display it +"in the UI +function! s:TreeDirNode.reveal(path) + if !a:path.isUnder(self.path) + throw "NERDTree.InvalidArgumentsError: " . a:path.str() . " should be under " . self.path.str() + endif + + call self.open() + + if self.path.equals(a:path.getParent()) + let n = self.findNode(a:path) + call s:renderView() + call n.putCursorHere(1,0) + return + endif + + let p = a:path + while !p.getParent().equals(self.path) + let p = p.getParent() + endwhile + + let n = self.findNode(p) + call n.reveal(a:path) +endfunction +"FUNCTION: TreeDirNode.removeChild(treenode) {{{3 +" +"Removes the given treenode from this nodes set of children +" +"Args: +"treenode: the node to remove +" +"Throws a NERDTree.ChildNotFoundError if the given treenode is not found +function! s:TreeDirNode.removeChild(treenode) + for i in range(0, self.getChildCount()-1) + if self.children[i].equals(a:treenode) + call remove(self.children, i) + return + endif + endfor + + throw "NERDTree.ChildNotFoundError: child node was not found" +endfunction + +"FUNCTION: TreeDirNode.sortChildren() {{{3 +" +"Sorts the children of this node according to alphabetical order and the +"directory priority. +" +function! s:TreeDirNode.sortChildren() + let CompareFunc = function("s:compareNodes") + call sort(self.children, CompareFunc) +endfunction + +"FUNCTION: TreeDirNode.toggleOpen() {{{3 +"Opens this directory if it is closed and vice versa +function! s:TreeDirNode.toggleOpen() + if self.isOpen ==# 1 + call self.close() + else + call self.open() + endif +endfunction + +"FUNCTION: TreeDirNode.transplantChild(newNode) {{{3 +"Replaces the child of this with the given node (where the child node's full +"path matches a:newNode's fullpath). The search for the matching node is +"non-recursive +" +"Arg: +"newNode: the node to graft into the tree +function! s:TreeDirNode.transplantChild(newNode) + for i in range(0, self.getChildCount()-1) + if self.children[i].equals(a:newNode) + let self.children[i] = a:newNode + let a:newNode.parent = self + break + endif + endfor +endfunction +"============================================================ +"CLASS: Path {{{2 +"============================================================ +let s:Path = {} +"FUNCTION: Path.AbsolutePathFor(str) {{{3 +function! s:Path.AbsolutePathFor(str) + let prependCWD = 0 + if s:running_windows + let prependCWD = a:str !~# '^.:\(\\\|\/\)' + else + let prependCWD = a:str !~# '^/' + endif + + let toReturn = a:str + if prependCWD + let toReturn = getcwd() . s:Path.Slash() . a:str + endif + + return toReturn +endfunction +"FUNCTION: Path.bookmarkNames() {{{3 +function! s:Path.bookmarkNames() + if !exists("self._bookmarkNames") + call self.cacheDisplayString() + endif + return self._bookmarkNames +endfunction +"FUNCTION: Path.cacheDisplayString() {{{3 +function! s:Path.cacheDisplayString() + let self.cachedDisplayString = self.getLastPathComponent(1) + + if self.isExecutable + let self.cachedDisplayString = self.cachedDisplayString . '*' + endif + + let self._bookmarkNames = [] + for i in s:Bookmark.Bookmarks() + if i.path.equals(self) + call add(self._bookmarkNames, i.name) + endif + endfor + if !empty(self._bookmarkNames) + let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}' + endif + + if self.isSymLink + let self.cachedDisplayString .= ' -> ' . self.symLinkDest + endif + + if self.isReadOnly + let self.cachedDisplayString .= ' [RO]' + endif +endfunction +"FUNCTION: Path.changeToDir() {{{3 +function! s:Path.changeToDir() + let dir = self.str({'format': 'Cd'}) + if self.isDirectory ==# 0 + let dir = self.getParent().str({'format': 'Cd'}) + endif + + try + execute "cd " . dir + call s:echo("CWD is now: " . getcwd()) + catch + throw "NERDTree.PathChangeError: cannot change CWD to " . dir + endtry +endfunction + +"FUNCTION: Path.compareTo() {{{3 +" +"Compares this Path to the given path and returns 0 if they are equal, -1 if +"this Path is "less than" the given path, or 1 if it is "greater". +" +"Args: +"path: the path object to compare this to +" +"Return: +"1, -1 or 0 +function! s:Path.compareTo(path) + let thisPath = self.getLastPathComponent(1) + let thatPath = a:path.getLastPathComponent(1) + + "if the paths are the same then clearly we return 0 + if thisPath ==# thatPath + return 0 + endif + + let thisSS = self.getSortOrderIndex() + let thatSS = a:path.getSortOrderIndex() + + "compare the sort sequences, if they are different then the return + "value is easy + if thisSS < thatSS + return -1 + elseif thisSS > thatSS + return 1 + else + "if the sort sequences are the same then compare the paths + "alphabetically + let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath limit + let toReturn = "<" . strpart(toReturn, len(toReturn) - limit + 1) + endif + endif + + return toReturn +endfunction + +"FUNCTION: Path._strForUI() {{{3 +function! s:Path._strForUI() + let toReturn = '/' . join(self.pathSegments, '/') + if self.isDirectory && toReturn != '/' + let toReturn = toReturn . '/' + endif + return toReturn +endfunction + +"FUNCTION: Path._strForCd() {{{3 +" +" returns a string that can be used with :cd +function! s:Path._strForCd() + return escape(self.str(), s:escape_chars) +endfunction +"FUNCTION: Path._strForEdit() {{{3 +" +"Return: the string for this path that is suitable to be used with the :edit +"command +function! s:Path._strForEdit() + let p = self.str({'format': 'UI'}) + let cwd = getcwd() + + if s:running_windows + let p = tolower(self.str()) + let cwd = tolower(getcwd()) + endif + + let p = escape(p, s:escape_chars) + + let cwd = cwd . s:Path.Slash() + + "return a relative path if we can + if stridx(p, cwd) ==# 0 + let p = strpart(p, strlen(cwd)) + endif + + if p ==# '' + let p = '.' + endif + + return p + +endfunction +"FUNCTION: Path._strForGlob() {{{3 +function! s:Path._strForGlob() + let lead = s:Path.Slash() + + "if we are running windows then slap a drive letter on the front + if s:running_windows + let lead = self.drive . '\' + endif + + let toReturn = lead . join(self.pathSegments, s:Path.Slash()) + + if !s:running_windows + let toReturn = escape(toReturn, s:escape_chars) + endif + return toReturn +endfunction +"FUNCTION: Path._str() {{{3 +" +"Gets the string path for this path object that is appropriate for the OS. +"EG, in windows c:\foo\bar +" in *nix /foo/bar +function! s:Path._str() + let lead = s:Path.Slash() + + "if we are running windows then slap a drive letter on the front + if s:running_windows + let lead = self.drive . '\' + endif + + return lead . join(self.pathSegments, s:Path.Slash()) +endfunction + +"FUNCTION: Path.strTrunk() {{{3 +"Gets the path without the last segment on the end. +function! s:Path.strTrunk() + return self.drive . '/' . join(self.pathSegments[0:-2], '/') +endfunction + +"FUNCTION: Path.WinToUnixPath(pathstr){{{3 +"Takes in a windows path and returns the unix equiv +" +"A class level method +" +"Args: +"pathstr: the windows path to convert +function! s:Path.WinToUnixPath(pathstr) + if !s:running_windows + return a:pathstr + endif + + let toReturn = a:pathstr + + "remove the x:\ of the front + let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', "") + + "convert all \ chars to / + let toReturn = substitute(toReturn, '\', '/', "g") + + return toReturn +endfunction + +" SECTION: General Functions {{{1 +"============================================================ +"FUNCTION: s:bufInWindows(bnum){{{2 +"[[STOLEN FROM VTREEEXPLORER.VIM]] +"Determine the number of windows open to this buffer number. +"Care of Yegappan Lakshman. Thanks! +" +"Args: +"bnum: the subject buffers buffer number +function! s:bufInWindows(bnum) + let cnt = 0 + let winnum = 1 + while 1 + let bufnum = winbufnr(winnum) + if bufnum < 0 + break + endif + if bufnum ==# a:bnum + let cnt = cnt + 1 + endif + let winnum = winnum + 1 + endwhile + + return cnt +endfunction " >>> +"FUNCTION: s:checkForBrowse(dir) {{{2 +"inits a secondary nerd tree in the current buffer if appropriate +function! s:checkForBrowse(dir) + if a:dir != '' && isdirectory(a:dir) + call s:initNerdTreeInPlace(a:dir) + endif +endfunction +"FUNCTION: s:compareBookmarks(first, second) {{{2 +"Compares two bookmarks +function! s:compareBookmarks(first, second) + return a:first.compareTo(a:second) +endfunction + +" FUNCTION: s:completeBookmarks(A,L,P) {{{2 +" completion function for the bookmark commands +function! s:completeBookmarks(A,L,P) + return filter(s:Bookmark.BookmarkNames(), 'v:val =~# "^' . a:A . '"') +endfunction +" FUNCTION: s:exec(cmd) {{{2 +" same as :exec cmd but eventignore=all is set for the duration +function! s:exec(cmd) + let old_ei = &ei + set ei=all + exec a:cmd + let &ei = old_ei +endfunction +" FUNCTION: s:findAndRevealPath() {{{2 +function! s:findAndRevealPath() + try + let p = s:Path.New(expand("%:p")) + catch /^NERDTree.InvalidArgumentsError/ + call s:echo("no file for the current buffer") + return + endtry + + if !s:treeExistsForTab() + try + let cwd = s:Path.New(getcwd()) + catch /^NERDTree.InvalidArgumentsError/ + call s:echo("current directory does not exist.") + let cwd = p.getParent() + endtry + + if p.isUnder(cwd) + call s:initNerdTree(cwd.str()) + else + call s:initNerdTree(p.getParent().str()) + endif + else + if !p.isUnder(s:TreeFileNode.GetRootForTab().path) + call s:initNerdTree(p.getParent().str()) + else + if !s:isTreeOpen() + call s:toggle("") + endif + endif + endif + call s:putCursorInTreeWin() + call b:NERDTreeRoot.reveal(p) +endfunction +"FUNCTION: s:initNerdTree(name) {{{2 +"Initialise the nerd tree for this tab. The tree will start in either the +"given directory, or the directory associated with the given bookmark +" +"Args: +"name: the name of a bookmark or a directory +function! s:initNerdTree(name) + let path = {} + if s:Bookmark.BookmarkExistsFor(a:name) + let path = s:Bookmark.BookmarkFor(a:name).path + else + let dir = a:name ==# '' ? getcwd() : a:name + + "hack to get an absolute path if a relative path is given + if dir =~# '^\.' + let dir = getcwd() . s:Path.Slash() . dir + endif + let dir = resolve(dir) + + try + let path = s:Path.New(dir) + catch /^NERDTree.InvalidArgumentsError/ + call s:echo("No bookmark or directory found for: " . a:name) + return + endtry + endif + if !path.isDirectory + let path = path.getParent() + endif + + "if instructed to, then change the vim CWD to the dir the NERDTree is + "inited in + if g:NERDTreeChDirMode != 0 + call path.changeToDir() + endif + + if s:treeExistsForTab() + if s:isTreeOpen() + call s:closeTree() + endif + unlet t:NERDTreeBufName + endif + + let newRoot = s:TreeDirNode.New(path) + call newRoot.open() + + call s:createTreeWin() + let b:treeShowHelp = 0 + let b:NERDTreeIgnoreEnabled = 1 + let b:NERDTreeShowFiles = g:NERDTreeShowFiles + let b:NERDTreeShowHidden = g:NERDTreeShowHidden + let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks + let b:NERDTreeRoot = newRoot + + let b:NERDTreeType = "primary" + + call s:renderView() + call b:NERDTreeRoot.putCursorHere(0, 0) +endfunction + +"FUNCTION: s:initNerdTreeInPlace(dir) {{{2 +function! s:initNerdTreeInPlace(dir) + try + let path = s:Path.New(a:dir) + catch /^NERDTree.InvalidArgumentsError/ + call s:echo("Invalid directory name:" . a:name) + return + endtry + + "we want the directory buffer to disappear when we do the :edit below + setlocal bufhidden=wipe + + let previousBuf = expand("#") + + "we need a unique name for each secondary tree buffer to ensure they are + "all independent + exec "silent edit " . s:nextBufferName() + + let b:NERDTreePreviousBuf = bufnr(previousBuf) + + let b:NERDTreeRoot = s:TreeDirNode.New(path) + call b:NERDTreeRoot.open() + + call s:setCommonBufOptions() + let b:NERDTreeType = "secondary" + + call s:renderView() +endfunction +" FUNCTION: s:initNerdTreeMirror() {{{2 +function! s:initNerdTreeMirror() + + "get the names off all the nerd tree buffers + let treeBufNames = [] + for i in range(1, tabpagenr("$")) + let nextName = s:tabpagevar(i, 'NERDTreeBufName') + if nextName != -1 && (!exists("t:NERDTreeBufName") || nextName != t:NERDTreeBufName) + call add(treeBufNames, nextName) + endif + endfor + let treeBufNames = s:unique(treeBufNames) + + "map the option names (that the user will be prompted with) to the nerd + "tree buffer names + let options = {} + let i = 0 + while i < len(treeBufNames) + let bufName = treeBufNames[i] + let treeRoot = getbufvar(bufName, "NERDTreeRoot") + let options[i+1 . '. ' . treeRoot.path.str() . ' (buf name: ' . bufName . ')'] = bufName + let i = i + 1 + endwhile + + "work out which tree to mirror, if there is more than 1 then ask the user + let bufferName = '' + if len(keys(options)) > 1 + let choices = ["Choose a tree to mirror"] + let choices = extend(choices, sort(keys(options))) + let choice = inputlist(choices) + if choice < 1 || choice > len(options) || choice ==# '' + return + endif + + let bufferName = options[sort(keys(options))[choice-1]] + elseif len(keys(options)) ==# 1 + let bufferName = values(options)[0] + else + call s:echo("No trees to mirror") + return + endif + + if s:treeExistsForTab() && s:isTreeOpen() + call s:closeTree() + endif + + let t:NERDTreeBufName = bufferName + call s:createTreeWin() + exec 'buffer ' . bufferName + if !&hidden + call s:renderView() + endif +endfunction +" FUNCTION: s:nextBufferName() {{{2 +" returns the buffer name for the next nerd tree +function! s:nextBufferName() + let name = s:NERDTreeBufName . s:next_buffer_number + let s:next_buffer_number += 1 + return name +endfunction +" FUNCTION: s:tabpagevar(tabnr, var) {{{2 +function! s:tabpagevar(tabnr, var) + let currentTab = tabpagenr() + let old_ei = &ei + set ei=all + + exec "tabnext " . a:tabnr + let v = -1 + if exists('t:' . a:var) + exec 'let v = t:' . a:var + endif + exec "tabnext " . currentTab + + let &ei = old_ei + + return v +endfunction +" Function: s:treeExistsForBuffer() {{{2 +" Returns 1 if a nerd tree root exists in the current buffer +function! s:treeExistsForBuf() + return exists("b:NERDTreeRoot") +endfunction +" Function: s:treeExistsForTab() {{{2 +" Returns 1 if a nerd tree root exists in the current tab +function! s:treeExistsForTab() + return exists("t:NERDTreeBufName") +endfunction +" Function: s:unique(list) {{{2 +" returns a:list without duplicates +function! s:unique(list) + let uniqlist = [] + for elem in a:list + if index(uniqlist, elem) ==# -1 + let uniqlist += [elem] + endif + endfor + return uniqlist +endfunction +" SECTION: Public API {{{1 +"============================================================ +let g:NERDTreePath = s:Path +let g:NERDTreeDirNode = s:TreeDirNode +let g:NERDTreeFileNode = s:TreeFileNode +let g:NERDTreeBookmark = s:Bookmark + +function! NERDTreeAddMenuItem(options) + call s:MenuItem.Create(a:options) +endfunction + +function! NERDTreeAddMenuSeparator(...) + let opts = a:0 ? a:1 : {} + call s:MenuItem.CreateSeparator(opts) +endfunction + +function! NERDTreeAddSubmenu(options) + return s:MenuItem.Create(a:options) +endfunction + +function! NERDTreeAddKeyMap(options) + call s:KeyMap.Create(a:options) +endfunction + +function! NERDTreeRender() + call s:renderView() +endfunction + +" SECTION: View Functions {{{1 +"============================================================ +"FUNCTION: s:centerView() {{{2 +"centers the nerd tree window around the cursor (provided the nerd tree +"options permit) +function! s:centerView() + if g:NERDTreeAutoCenter + let current_line = winline() + let lines_to_top = current_line + let lines_to_bottom = winheight(s:getTreeWinNum()) - current_line + if lines_to_top < g:NERDTreeAutoCenterThreshold || lines_to_bottom < g:NERDTreeAutoCenterThreshold + normal! zz + endif + endif +endfunction +"FUNCTION: s:closeTree() {{{2 +"Closes the primary NERD tree window for this tab +function! s:closeTree() + if !s:isTreeOpen() + throw "NERDTree.NoTreeFoundError: no NERDTree is open" + endif + + if winnr("$") != 1 + if winnr() == s:getTreeWinNum() + wincmd p + let bufnr = bufnr("") + wincmd p + else + let bufnr = bufnr("") + endif + + call s:exec(s:getTreeWinNum() . " wincmd w") + close + call s:exec(bufwinnr(bufnr) . " wincmd w") + else + close + endif +endfunction + +"FUNCTION: s:closeTreeIfOpen() {{{2 +"Closes the NERD tree window if it is open +function! s:closeTreeIfOpen() + if s:isTreeOpen() + call s:closeTree() + endif +endfunction +"FUNCTION: s:closeTreeIfQuitOnOpen() {{{2 +"Closes the NERD tree window if the close on open option is set +function! s:closeTreeIfQuitOnOpen() + if g:NERDTreeQuitOnOpen && s:isTreeOpen() + call s:closeTree() + endif +endfunction +"FUNCTION: s:createTreeWin() {{{2 +"Inits the NERD tree window. ie. opens it, sizes it, sets all the local +"options etc +function! s:createTreeWin() + "create the nerd tree window + let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright " + let splitSize = g:NERDTreeWinSize + + if !exists('t:NERDTreeBufName') + let t:NERDTreeBufName = s:nextBufferName() + silent! exec splitLocation . 'vertical ' . splitSize . ' new' + silent! exec "edit " . t:NERDTreeBufName + else + silent! exec splitLocation . 'vertical ' . splitSize . ' split' + silent! exec "buffer " . t:NERDTreeBufName + endif + + setlocal winfixwidth + call s:setCommonBufOptions() +endfunction + +"FUNCTION: s:dumpHelp {{{2 +"prints out the quick help +function! s:dumpHelp() + let old_h = @h + if b:treeShowHelp ==# 1 + let @h= "\" NERD tree (" . s:NERD_tree_version . ") quickhelp~\n" + let @h=@h."\" ============================\n" + let @h=@h."\" File node mappings~\n" + let @h=@h."\" ". (g:NERDTreeMouseMode ==# 3 ? "single" : "double") ."-click,\n" + let @h=@h."\" ,\n" + if b:NERDTreeType ==# "primary" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n" + else + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in current window\n" + endif + if b:NERDTreeType ==# "primary" + let @h=@h."\" ". g:NERDTreeMapPreview .": preview\n" + endif + let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let @h=@h."\" middle-click,\n" + let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n" + let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n" + let @h=@h."\" ". g:NERDTreeMapOpenVSplit .": open vsplit\n" + let @h=@h."\" ". g:NERDTreeMapPreviewVSplit .": preview vsplit\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Directory node mappings~\n" + let @h=@h."\" ". (g:NERDTreeMouseMode ==# 1 ? "double" : "single") ."-click,\n" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open & close node\n" + let @h=@h."\" ". g:NERDTreeMapOpenRecursively .": recursively open node\n" + let @h=@h."\" ". g:NERDTreeMapCloseDir .": close parent of node\n" + let @h=@h."\" ". g:NERDTreeMapCloseChildren .": close all child nodes of\n" + let @h=@h."\" current node recursively\n" + let @h=@h."\" middle-click,\n" + let @h=@h."\" ". g:NERDTreeMapOpenExpl.": explore selected dir\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Bookmark table mappings~\n" + let @h=@h."\" double-click,\n" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open bookmark\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let @h=@h."\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Tree navigation mappings~\n" + let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n" + let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n" + let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n" + let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n" + let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n" + let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Filesystem mappings~\n" + let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n" + let @h=@h."\" selected dir\n" + let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n" + let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n" + let @h=@h."\" but leave old root open\n" + let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n" + let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n" + let @h=@h."\" ". g:NERDTreeMapMenu .": Show menu\n" + let @h=@h."\" ". g:NERDTreeMapChdir .":change the CWD to the\n" + let @h=@h."\" selected dir\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Tree filtering mappings~\n" + let @h=@h."\" ". g:NERDTreeMapToggleHidden .": hidden files (" . (b:NERDTreeShowHidden ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (b:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (b:NERDTreeShowFiles ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (b:NERDTreeShowBookmarks ? "on" : "off") . ")\n" + + "add quickhelp entries for each custom key map + if len(s:KeyMap.All()) + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Custom mappings~\n" + for i in s:KeyMap.All() + let @h=@h."\" ". i.key .": ". i.quickhelpText ."\n" + endfor + endif + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Other mappings~\n" + let @h=@h."\" ". g:NERDTreeMapQuit .": Close the NERDTree window\n" + let @h=@h."\" ". g:NERDTreeMapToggleZoom .": Zoom (maximize-minimize)\n" + let @h=@h."\" the NERDTree window\n" + let @h=@h."\" ". g:NERDTreeMapHelp .": toggle help\n" + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Bookmark commands~\n" + let @h=@h."\" :Bookmark \n" + let @h=@h."\" :BookmarkToRoot \n" + let @h=@h."\" :RevealBookmark \n" + let @h=@h."\" :OpenBookmark \n" + let @h=@h."\" :ClearBookmarks []\n" + let @h=@h."\" :ClearAllBookmarks\n" + silent! put h + elseif g:NERDTreeMinimalUI == 0 + let @h="\" Press ". g:NERDTreeMapHelp ." for help\n" + silent! put h + endif + + let @h = old_h +endfunction +"FUNCTION: s:echo {{{2 +"A wrapper for :echo. Appends 'NERDTree:' on the front of all messages +" +"Args: +"msg: the message to echo +function! s:echo(msg) + redraw + echomsg "NERDTree: " . a:msg +endfunction +"FUNCTION: s:echoWarning {{{2 +"Wrapper for s:echo, sets the message type to warningmsg for this message +"Args: +"msg: the message to echo +function! s:echoWarning(msg) + echohl warningmsg + call s:echo(a:msg) + echohl normal +endfunction +"FUNCTION: s:echoError {{{2 +"Wrapper for s:echo, sets the message type to errormsg for this message +"Args: +"msg: the message to echo +function! s:echoError(msg) + echohl errormsg + call s:echo(a:msg) + echohl normal +endfunction +"FUNCTION: s:firstUsableWindow(){{{2 +"find the window number of the first normal window +function! s:firstUsableWindow() + let i = 1 + while i <= winnr("$") + let bnum = winbufnr(i) + if bnum != -1 && getbufvar(bnum, '&buftype') ==# '' + \ && !getwinvar(i, '&previewwindow') + \ && (!getbufvar(bnum, '&modified') || &hidden) + return i + endif + + let i += 1 + endwhile + return -1 +endfunction +"FUNCTION: s:getPath(ln) {{{2 +"Gets the full path to the node that is rendered on the given line number +" +"Args: +"ln: the line number to get the path for +" +"Return: +"A path if a node was selected, {} if nothing is selected. +"If the 'up a dir' line was selected then the path to the parent of the +"current root is returned +function! s:getPath(ln) + let line = getline(a:ln) + + let rootLine = s:TreeFileNode.GetRootLineNum() + + "check to see if we have the root node + if a:ln == rootLine + return b:NERDTreeRoot.path + endif + + if !g:NERDTreeDirArrows + " in case called from outside the tree + if line !~# '^ *[|`▸▾ ]' || line =~# '^$' + return {} + endif + endif + + if line ==# s:tree_up_dir_line + return b:NERDTreeRoot.path.getParent() + endif + + let indent = s:indentLevelFor(line) + + "remove the tree parts and the leading space + let curFile = s:stripMarkupFromLine(line, 0) + + let wasdir = 0 + if curFile =~# '/$' + let wasdir = 1 + let curFile = substitute(curFile, '/\?$', '/', "") + endif + + let dir = "" + let lnum = a:ln + while lnum > 0 + let lnum = lnum - 1 + let curLine = getline(lnum) + let curLineStripped = s:stripMarkupFromLine(curLine, 1) + + "have we reached the top of the tree? + if lnum == rootLine + let dir = b:NERDTreeRoot.path.str({'format': 'UI'}) . dir + break + endif + if curLineStripped =~# '/$' + let lpindent = s:indentLevelFor(curLine) + if lpindent < indent + let indent = indent - 1 + + let dir = substitute (curLineStripped,'^\\', "", "") . dir + continue + endif + endif + endwhile + let curFile = b:NERDTreeRoot.path.drive . dir . curFile + let toReturn = s:Path.New(curFile) + return toReturn +endfunction + +"FUNCTION: s:getTreeWinNum() {{{2 +"gets the nerd tree window number for this tab +function! s:getTreeWinNum() + if exists("t:NERDTreeBufName") + return bufwinnr(t:NERDTreeBufName) + else + return -1 + endif +endfunction +"FUNCTION: s:indentLevelFor(line) {{{2 +function! s:indentLevelFor(line) + let level = match(a:line, '[^ \-+~▸▾`|]') / s:tree_wid + " check if line includes arrows + if match(a:line, '[▸▾]') > -1 + " decrement level as arrow uses 3 ascii chars + let level = level - 1 + endif + return level +endfunction +"FUNCTION: s:isTreeOpen() {{{2 +function! s:isTreeOpen() + return s:getTreeWinNum() != -1 +endfunction +"FUNCTION: s:isWindowUsable(winnumber) {{{2 +"Returns 0 if opening a file from the tree in the given window requires it to +"be split, 1 otherwise +" +"Args: +"winnumber: the number of the window in question +function! s:isWindowUsable(winnumber) + "gotta split if theres only one window (i.e. the NERD tree) + if winnr("$") ==# 1 + return 0 + endif + + let oldwinnr = winnr() + call s:exec(a:winnumber . "wincmd p") + let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow') + let modified = &modified + call s:exec(oldwinnr . "wincmd p") + + "if its a special window e.g. quickfix or another explorer plugin then we + "have to split + if specialWindow + return 0 + endif + + if &hidden + return 1 + endif + + return !modified || s:bufInWindows(winbufnr(a:winnumber)) >= 2 +endfunction + +" FUNCTION: s:jumpToChild(direction) {{{2 +" Args: +" direction: 0 if going to first child, 1 if going to last +function! s:jumpToChild(direction) + let currentNode = s:TreeFileNode.GetSelected() + if currentNode ==# {} || currentNode.isRoot() + call s:echo("cannot jump to " . (a:direction ? "last" : "first") . " child") + return + end + let dirNode = currentNode.parent + let childNodes = dirNode.getVisibleChildren() + + let targetNode = childNodes[0] + if a:direction + let targetNode = childNodes[len(childNodes) - 1] + endif + + if targetNode.equals(currentNode) + let siblingDir = currentNode.parent.findOpenDirSiblingWithVisibleChildren(a:direction) + if siblingDir != {} + let indx = a:direction ? siblingDir.getVisibleChildCount()-1 : 0 + let targetNode = siblingDir.getChildByIndex(indx, 1) + endif + endif + + call targetNode.putCursorHere(1, 0) + + call s:centerView() +endfunction + + +"FUNCTION: s:promptToDelBuffer(bufnum, msg){{{2 +"prints out the given msg and, if the user responds by pushing 'y' then the +"buffer with the given bufnum is deleted +" +"Args: +"bufnum: the buffer that may be deleted +"msg: a message that will be echoed to the user asking them if they wish to +" del the buffer +function! s:promptToDelBuffer(bufnum, msg) + echo a:msg + if nr2char(getchar()) ==# 'y' + exec "silent bdelete! " . a:bufnum + endif +endfunction + +"FUNCTION: s:putCursorOnBookmarkTable(){{{2 +"Places the cursor at the top of the bookmarks table +function! s:putCursorOnBookmarkTable() + if !b:NERDTreeShowBookmarks + throw "NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active" + endif + + if g:NERDTreeMinimalUI + return cursor(1, 2) + endif + + let rootNodeLine = s:TreeFileNode.GetRootLineNum() + + let line = 1 + while getline(line) !~# '^>-\+Bookmarks-\+$' + let line = line + 1 + if line >= rootNodeLine + throw "NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table" + endif + endwhile + call cursor(line, 2) +endfunction + +"FUNCTION: s:putCursorInTreeWin(){{{2 +"Places the cursor in the nerd tree window +function! s:putCursorInTreeWin() + if !s:isTreeOpen() + throw "NERDTree.InvalidOperationError: cant put cursor in NERD tree window, no window exists" + endif + + call s:exec(s:getTreeWinNum() . "wincmd w") +endfunction + +"FUNCTION: s:renderBookmarks {{{2 +function! s:renderBookmarks() + + if g:NERDTreeMinimalUI == 0 + call setline(line(".")+1, ">----------Bookmarks----------") + call cursor(line(".")+1, col(".")) + endif + + for i in s:Bookmark.Bookmarks() + call setline(line(".")+1, i.str()) + call cursor(line(".")+1, col(".")) + endfor + + call setline(line(".")+1, '') + call cursor(line(".")+1, col(".")) +endfunction +"FUNCTION: s:renderView {{{2 +"The entry function for rendering the tree +function! s:renderView() + setlocal modifiable + + "remember the top line of the buffer and the current line so we can + "restore the view exactly how it was + let curLine = line(".") + let curCol = col(".") + let topLine = line("w0") + + "delete all lines in the buffer (being careful not to clobber a register) + silent 1,$delete _ + + call s:dumpHelp() + + "delete the blank line before the help and add one after it + if g:NERDTreeMinimalUI == 0 + call setline(line(".")+1, "") + call cursor(line(".")+1, col(".")) + endif + + if b:NERDTreeShowBookmarks + call s:renderBookmarks() + endif + + "add the 'up a dir' line + if !g:NERDTreeMinimalUI + call setline(line(".")+1, s:tree_up_dir_line) + call cursor(line(".")+1, col(".")) + endif + + "draw the header line + let header = b:NERDTreeRoot.path.str({'format': 'UI', 'truncateTo': winwidth(0)}) + call setline(line(".")+1, header) + call cursor(line(".")+1, col(".")) + + "draw the tree + let old_o = @o + let @o = b:NERDTreeRoot.renderToString() + silent put o + let @o = old_o + + "delete the blank line at the top of the buffer + silent 1,1delete _ + + "restore the view + let old_scrolloff=&scrolloff + let &scrolloff=0 + call cursor(topLine, 1) + normal! zt + call cursor(curLine, curCol) + let &scrolloff = old_scrolloff + + setlocal nomodifiable +endfunction + +"FUNCTION: s:renderViewSavingPosition {{{2 +"Renders the tree and ensures the cursor stays on the current node or the +"current nodes parent if it is no longer available upon re-rendering +function! s:renderViewSavingPosition() + let currentNode = s:TreeFileNode.GetSelected() + + "go up the tree till we find a node that will be visible or till we run + "out of nodes + while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot() + let currentNode = currentNode.parent + endwhile + + call s:renderView() + + if currentNode != {} + call currentNode.putCursorHere(0, 0) + endif +endfunction +"FUNCTION: s:restoreScreenState() {{{2 +" +"Sets the screen state back to what it was when s:saveScreenState was last +"called. +" +"Assumes the cursor is in the NERDTree window +function! s:restoreScreenState() + if !exists("b:NERDTreeOldTopLine") || !exists("b:NERDTreeOldPos") || !exists("b:NERDTreeOldWindowSize") + return + endif + exec("silent vertical resize ".b:NERDTreeOldWindowSize) + + let old_scrolloff=&scrolloff + let &scrolloff=0 + call cursor(b:NERDTreeOldTopLine, 0) + normal! zt + call setpos(".", b:NERDTreeOldPos) + let &scrolloff=old_scrolloff +endfunction + +"FUNCTION: s:saveScreenState() {{{2 +"Saves the current cursor position in the current buffer and the window +"scroll position +function! s:saveScreenState() + let win = winnr() + try + call s:putCursorInTreeWin() + let b:NERDTreeOldPos = getpos(".") + let b:NERDTreeOldTopLine = line("w0") + let b:NERDTreeOldWindowSize = winwidth("") + call s:exec(win . "wincmd w") + catch /^NERDTree.InvalidOperationError/ + endtry +endfunction + +"FUNCTION: s:setCommonBufOptions() {{{2 +function! s:setCommonBufOptions() + "throwaway buffer options + setlocal noswapfile + setlocal buftype=nofile + setlocal bufhidden=hide + setlocal nowrap + setlocal foldcolumn=0 + setlocal nobuflisted + setlocal nospell + if g:NERDTreeShowLineNumbers + setlocal nu + else + setlocal nonu + if v:version >= 703 + setlocal nornu + endif + endif + + iabc + + if g:NERDTreeHighlightCursorline + setlocal cursorline + endif + + call s:setupStatusline() + + + let b:treeShowHelp = 0 + let b:NERDTreeIgnoreEnabled = 1 + let b:NERDTreeShowFiles = g:NERDTreeShowFiles + let b:NERDTreeShowHidden = g:NERDTreeShowHidden + let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks + setfiletype nerdtree + call s:bindMappings() +endfunction + +"FUNCTION: s:setupStatusline() {{{2 +function! s:setupStatusline() + if g:NERDTreeStatusline != -1 + let &l:statusline = g:NERDTreeStatusline + endif +endfunction +"FUNCTION: s:stripMarkupFromLine(line, removeLeadingSpaces){{{2 +"returns the given line with all the tree parts stripped off +" +"Args: +"line: the subject line +"removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces = +"any spaces before the actual text of the node) +function! s:stripMarkupFromLine(line, removeLeadingSpaces) + let line = a:line + "remove the tree parts and the leading space + let line = substitute (line, s:tree_markup_reg,"","") + + "strip off any read only flag + let line = substitute (line, ' \[RO\]', "","") + + "strip off any bookmark flags + let line = substitute (line, ' {[^}]*}', "","") + + "strip off any executable flags + let line = substitute (line, '*\ze\($\| \)', "","") + + let wasdir = 0 + if line =~# '/$' + let wasdir = 1 + endif + let line = substitute (line,' -> .*',"","") " remove link to + if wasdir ==# 1 + let line = substitute (line, '/\?$', '/', "") + endif + + if a:removeLeadingSpaces + let line = substitute (line, '^ *', '', '') + endif + + return line +endfunction + +"FUNCTION: s:toggle(dir) {{{2 +"Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is +"closed it is restored or initialized (if it doesnt exist) +" +"Args: +"dir: the full path for the root node (is only used if the NERD tree is being +"initialized. +function! s:toggle(dir) + if s:treeExistsForTab() + if !s:isTreeOpen() + call s:createTreeWin() + if !&hidden + call s:renderView() + endif + call s:restoreScreenState() + else + call s:closeTree() + endif + else + call s:initNerdTree(a:dir) + endif +endfunction +"SECTION: Interface bindings {{{1 +"============================================================ +"FUNCTION: s:activateNode(forceKeepWindowOpen) {{{2 +"If the current node is a file, open it in the previous window (or a new one +"if the previous is modified). If it is a directory then it is opened. +" +"args: +"forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set +function! s:activateNode(forceKeepWindowOpen) + if getline(".") ==# s:tree_up_dir_line + return s:upDir(0) + endif + + let treenode = s:TreeFileNode.GetSelected() + if treenode != {} + call treenode.activate(a:forceKeepWindowOpen) + else + let bookmark = s:Bookmark.GetSelected() + if !empty(bookmark) + call bookmark.activate() + endif + endif +endfunction + +"FUNCTION: s:bindMappings() {{{2 +function! s:bindMappings() + " set up mappings and commands for this buffer + nnoremap :call handleMiddleMouse() + nnoremap :call checkForActivate() + nnoremap <2-leftmouse> :call activateNode(0) + + exec "nnoremap ". g:NERDTreeMapActivateNode . " :call activateNode(0)" + exec "nnoremap ". g:NERDTreeMapOpenSplit ." :call openEntrySplit(0,0)" + exec "nnoremap :call activateNode(0)" + + exec "nnoremap ". g:NERDTreeMapPreview ." :call previewNode(0)" + exec "nnoremap ". g:NERDTreeMapPreviewSplit ." :call previewNode(1)" + + exec "nnoremap ". g:NERDTreeMapOpenVSplit ." :call openEntrySplit(1,0)" + exec "nnoremap ". g:NERDTreeMapPreviewVSplit ." :call previewNode(2)" + + exec "nnoremap ". g:NERDTreeMapOpenRecursively ." :call openNodeRecursively()" + + exec "nnoremap ". g:NERDTreeMapUpdirKeepOpen ." :call upDir(1)" + exec "nnoremap ". g:NERDTreeMapUpdir ." :call upDir(0)" + exec "nnoremap ". g:NERDTreeMapChangeRoot ." :call chRoot()" + + exec "nnoremap ". g:NERDTreeMapChdir ." :call chCwd()" + + exec "nnoremap ". g:NERDTreeMapQuit ." :call closeTreeWindow()" + + exec "nnoremap ". g:NERDTreeMapRefreshRoot ." :call refreshRoot()" + exec "nnoremap ". g:NERDTreeMapRefresh ." :call refreshCurrent()" + + exec "nnoremap ". g:NERDTreeMapHelp ." :call displayHelp()" + exec "nnoremap ". g:NERDTreeMapToggleZoom ." :call toggleZoom()" + exec "nnoremap ". g:NERDTreeMapToggleHidden ." :call toggleShowHidden()" + exec "nnoremap ". g:NERDTreeMapToggleFilters ." :call toggleIgnoreFilter()" + exec "nnoremap ". g:NERDTreeMapToggleFiles ." :call toggleShowFiles()" + exec "nnoremap ". g:NERDTreeMapToggleBookmarks ." :call toggleShowBookmarks()" + + exec "nnoremap ". g:NERDTreeMapCloseDir ." :call closeCurrentDir()" + exec "nnoremap ". g:NERDTreeMapCloseChildren ." :call closeChildren()" + + exec "nnoremap ". g:NERDTreeMapMenu ." :call showMenu()" + + exec "nnoremap ". g:NERDTreeMapJumpParent ." :call jumpToParent()" + exec "nnoremap ". g:NERDTreeMapJumpNextSibling ." :call jumpToSibling(1)" + exec "nnoremap ". g:NERDTreeMapJumpPrevSibling ." :call jumpToSibling(0)" + exec "nnoremap ". g:NERDTreeMapJumpFirstChild ." :call jumpToFirstChild()" + exec "nnoremap ". g:NERDTreeMapJumpLastChild ." :call jumpToLastChild()" + exec "nnoremap ". g:NERDTreeMapJumpRoot ." :call jumpToRoot()" + + exec "nnoremap ". g:NERDTreeMapOpenInTab ." :call openInNewTab(0)" + exec "nnoremap ". g:NERDTreeMapOpenInTabSilent ." :call openInNewTab(1)" + + exec "nnoremap ". g:NERDTreeMapOpenExpl ." :call openExplorer()" + + exec "nnoremap ". g:NERDTreeMapDeleteBookmark ." :call deleteBookmark()" + + "bind all the user custom maps + call s:KeyMap.BindAll() + + command! -buffer -nargs=? Bookmark :call bookmarkNode('') + command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 RevealBookmark :call revealBookmark('') + command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 OpenBookmark :call openBookmark('') + command! -buffer -complete=customlist,s:completeBookmarks -nargs=* ClearBookmarks call clearBookmarks('') + command! -buffer -complete=customlist,s:completeBookmarks -nargs=+ BookmarkToRoot call s:Bookmark.ToRoot('') + command! -buffer -nargs=0 ClearAllBookmarks call s:Bookmark.ClearAll() call renderView() + command! -buffer -nargs=0 ReadBookmarks call s:Bookmark.CacheBookmarks(0) call renderView() + command! -buffer -nargs=0 WriteBookmarks call s:Bookmark.Write() +endfunction + +" FUNCTION: s:bookmarkNode(name) {{{2 +" Associate the current node with the given name +function! s:bookmarkNode(...) + let currentNode = s:TreeFileNode.GetSelected() + if currentNode != {} + let name = a:1 + if empty(name) + let name = currentNode.path.getLastPathComponent(0) + endif + try + call currentNode.bookmark(name) + call s:renderView() + catch /^NERDTree.IllegalBookmarkNameError/ + call s:echo("bookmark names must not contain spaces") + endtry + else + call s:echo("select a node first") + endif +endfunction +"FUNCTION: s:checkForActivate() {{{2 +"Checks if the click should open the current node, if so then activate() is +"called (directories are automatically opened if the symbol beside them is +"clicked) +function! s:checkForActivate() + let currentNode = s:TreeFileNode.GetSelected() + if currentNode != {} + let startToCur = strpart(getline(line(".")), 0, col(".")) + + if currentNode.path.isDirectory + if startToCur =~# s:tree_markup_reg . '$' && startToCur =~# '[+~▾▸]$' + call s:activateNode(0) + return + endif + endif + + if (g:NERDTreeMouseMode ==# 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode ==# 3 + let char = strpart(startToCur, strlen(startToCur)-1, 1) + if char !~# s:tree_markup_reg + call s:activateNode(0) + return + endif + endif + endif +endfunction + +" FUNCTION: s:chCwd() {{{2 +function! s:chCwd() + let treenode = s:TreeFileNode.GetSelected() + if treenode ==# {} + call s:echo("Select a node first") + return + endif + + try + call treenode.path.changeToDir() + catch /^NERDTree.PathChangeError/ + call s:echoWarning("could not change cwd") + endtry +endfunction + +" FUNCTION: s:chRoot() {{{2 +" changes the current root to the selected one +function! s:chRoot() + let treenode = s:TreeFileNode.GetSelected() + if treenode ==# {} + call s:echo("Select a node first") + return + endif + + call treenode.makeRoot() + call s:renderView() + call b:NERDTreeRoot.putCursorHere(0, 0) +endfunction + +" FUNCTION: s:clearBookmarks(bookmarks) {{{2 +function! s:clearBookmarks(bookmarks) + if a:bookmarks ==# '' + let currentNode = s:TreeFileNode.GetSelected() + if currentNode != {} + call currentNode.clearBoomarks() + endif + else + for name in split(a:bookmarks, ' ') + let bookmark = s:Bookmark.BookmarkFor(name) + call bookmark.delete() + endfor + endif + call s:renderView() +endfunction +" FUNCTION: s:closeChildren() {{{2 +" closes all childnodes of the current node +function! s:closeChildren() + let currentNode = s:TreeDirNode.GetSelected() + if currentNode ==# {} + call s:echo("Select a node first") + return + endif + + call currentNode.closeChildren() + call s:renderView() + call currentNode.putCursorHere(0, 0) +endfunction +" FUNCTION: s:closeCurrentDir() {{{2 +" closes the parent dir of the current node +function! s:closeCurrentDir() + let treenode = s:TreeFileNode.GetSelected() + if treenode ==# {} + call s:echo("Select a node first") + return + endif + + let parent = treenode.parent + if parent ==# {} || parent.isRoot() + call s:echo("cannot close tree root") + else + call treenode.parent.close() + call s:renderView() + call treenode.parent.putCursorHere(0, 0) + endif +endfunction +" FUNCTION: s:closeTreeWindow() {{{2 +" close the tree window +function! s:closeTreeWindow() + if b:NERDTreeType ==# "secondary" && b:NERDTreePreviousBuf != -1 + exec "buffer " . b:NERDTreePreviousBuf + else + if winnr("$") > 1 + call s:closeTree() + else + call s:echo("Cannot close last window") + endif + endif +endfunction +" FUNCTION: s:deleteBookmark() {{{2 +" if the cursor is on a bookmark, prompt to delete +function! s:deleteBookmark() + let bookmark = s:Bookmark.GetSelected() + if bookmark ==# {} + call s:echo("Put the cursor on a bookmark") + return + endif + + echo "Are you sure you wish to delete the bookmark:\n\"" . bookmark.name . "\" (yN):" + + if nr2char(getchar()) ==# 'y' + try + call bookmark.delete() + call s:renderView() + redraw + catch /^NERDTree/ + call s:echoWarning("Could not remove bookmark") + endtry + else + call s:echo("delete aborted" ) + endif + +endfunction + +" FUNCTION: s:displayHelp() {{{2 +" toggles the help display +function! s:displayHelp() + let b:treeShowHelp = b:treeShowHelp ? 0 : 1 + call s:renderView() + call s:centerView() +endfunction + +" FUNCTION: s:handleMiddleMouse() {{{2 +function! s:handleMiddleMouse() + let curNode = s:TreeFileNode.GetSelected() + if curNode ==# {} + call s:echo("Put the cursor on a node first" ) + return + endif + + if curNode.path.isDirectory + call s:openExplorer() + else + call s:openEntrySplit(0,0) + endif +endfunction + + +" FUNCTION: s:jumpToFirstChild() {{{2 +" wrapper for the jump to child method +function! s:jumpToFirstChild() + call s:jumpToChild(0) +endfunction + +" FUNCTION: s:jumpToLastChild() {{{2 +" wrapper for the jump to child method +function! s:jumpToLastChild() + call s:jumpToChild(1) +endfunction + +" FUNCTION: s:jumpToParent() {{{2 +" moves the cursor to the parent of the current node +function! s:jumpToParent() + let currentNode = s:TreeFileNode.GetSelected() + if !empty(currentNode) + if !empty(currentNode.parent) + call currentNode.parent.putCursorHere(1, 0) + call s:centerView() + else + call s:echo("cannot jump to parent") + endif + else + call s:echo("put the cursor on a node first") + endif +endfunction + +" FUNCTION: s:jumpToRoot() {{{2 +" moves the cursor to the root node +function! s:jumpToRoot() + call b:NERDTreeRoot.putCursorHere(1, 0) + call s:centerView() +endfunction + +" FUNCTION: s:jumpToSibling() {{{2 +" moves the cursor to the sibling of the current node in the given direction +" +" Args: +" forward: 1 if the cursor should move to the next sibling, 0 if it should +" move back to the previous sibling +function! s:jumpToSibling(forward) + let currentNode = s:TreeFileNode.GetSelected() + if !empty(currentNode) + let sibling = currentNode.findSibling(a:forward) + + if !empty(sibling) + call sibling.putCursorHere(1, 0) + call s:centerView() + endif + else + call s:echo("put the cursor on a node first") + endif +endfunction + +" FUNCTION: s:openBookmark(name) {{{2 +" put the cursor on the given bookmark and, if its a file, open it +function! s:openBookmark(name) + try + let targetNode = s:Bookmark.GetNodeForName(a:name, 0) + call targetNode.putCursorHere(0, 1) + redraw! + catch /^NERDTree.BookmarkedNodeNotFoundError/ + call s:echo("note - target node is not cached") + let bookmark = s:Bookmark.BookmarkFor(a:name) + let targetNode = s:TreeFileNode.New(bookmark.path) + endtry + if targetNode.path.isDirectory + call targetNode.openExplorer() + else + call targetNode.open() + endif +endfunction +" FUNCTION: s:openEntrySplit(vertical, forceKeepWindowOpen) {{{2 +"Opens the currently selected file from the explorer in a +"new window +" +"args: +"forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set +function! s:openEntrySplit(vertical, forceKeepWindowOpen) + let treenode = s:TreeFileNode.GetSelected() + if treenode != {} + if a:vertical + call treenode.openVSplit() + else + call treenode.openSplit() + endif + if !a:forceKeepWindowOpen + call s:closeTreeIfQuitOnOpen() + endif + else + call s:echo("select a node first") + endif +endfunction + +" FUNCTION: s:openExplorer() {{{2 +function! s:openExplorer() + let treenode = s:TreeDirNode.GetSelected() + if treenode != {} + call treenode.openExplorer() + else + call s:echo("select a node first") + endif +endfunction + +" FUNCTION: s:openInNewTab(stayCurrentTab) {{{2 +" Opens the selected node or bookmark in a new tab +" Args: +" stayCurrentTab: if 1 then vim will stay in the current tab, if 0 then vim +" will go to the tab where the new file is opened +function! s:openInNewTab(stayCurrentTab) + let target = s:TreeFileNode.GetSelected() + if target == {} + let target = s:Bookmark.GetSelected() + endif + + if target != {} + call target.openInNewTab({'stayInCurrentTab': a:stayCurrentTab}) + endif +endfunction + +" FUNCTION: s:openNodeRecursively() {{{2 +function! s:openNodeRecursively() + let treenode = s:TreeFileNode.GetSelected() + if treenode ==# {} || treenode.path.isDirectory ==# 0 + call s:echo("Select a directory node first" ) + else + call s:echo("Recursively opening node. Please wait...") + call treenode.openRecursively() + call s:renderView() + redraw + call s:echo("Recursively opening node. Please wait... DONE") + endif + +endfunction + +"FUNCTION: s:previewNode() {{{2 +"Args: +" openNewWin: if 0, use the previous window, if 1 open in new split, if 2 +" open in a vsplit +function! s:previewNode(openNewWin) + let currentBuf = bufnr("") + if a:openNewWin > 0 + call s:openEntrySplit(a:openNewWin ==# 2,1) + else + call s:activateNode(1) + end + call s:exec(bufwinnr(currentBuf) . "wincmd w") +endfunction + +" FUNCTION: s:revealBookmark(name) {{{2 +" put the cursor on the node associate with the given name +function! s:revealBookmark(name) + try + let targetNode = s:Bookmark.GetNodeForName(a:name, 0) + call targetNode.putCursorHere(0, 1) + catch /^NERDTree.BookmarkNotFoundError/ + call s:echo("Bookmark isnt cached under the current root") + endtry +endfunction +" FUNCTION: s:refreshRoot() {{{2 +" Reloads the current root. All nodes below this will be lost and the root dir +" will be reloaded. +function! s:refreshRoot() + call s:echo("Refreshing the root node. This could take a while...") + call b:NERDTreeRoot.refresh() + call s:renderView() + redraw + call s:echo("Refreshing the root node. This could take a while... DONE") +endfunction + +" FUNCTION: s:refreshCurrent() {{{2 +" refreshes the root for the current node +function! s:refreshCurrent() + let treenode = s:TreeDirNode.GetSelected() + if treenode ==# {} + call s:echo("Refresh failed. Select a node first") + return + endif + + call s:echo("Refreshing node. This could take a while...") + call treenode.refresh() + call s:renderView() + redraw + call s:echo("Refreshing node. This could take a while... DONE") +endfunction +" FUNCTION: s:showMenu() {{{2 +function! s:showMenu() + let curNode = s:TreeFileNode.GetSelected() + if curNode ==# {} + call s:echo("Put the cursor on a node first" ) + return + endif + + let mc = s:MenuController.New(s:MenuItem.AllEnabled()) + call mc.showMenu() +endfunction + +" FUNCTION: s:toggleIgnoreFilter() {{{2 +" toggles the use of the NERDTreeIgnore option +function! s:toggleIgnoreFilter() + let b:NERDTreeIgnoreEnabled = !b:NERDTreeIgnoreEnabled + call s:renderViewSavingPosition() + call s:centerView() +endfunction + +" FUNCTION: s:toggleShowBookmarks() {{{2 +" toggles the display of bookmarks +function! s:toggleShowBookmarks() + let b:NERDTreeShowBookmarks = !b:NERDTreeShowBookmarks + if b:NERDTreeShowBookmarks + call s:renderView() + call s:putCursorOnBookmarkTable() + else + call s:renderViewSavingPosition() + endif + call s:centerView() +endfunction +" FUNCTION: s:toggleShowFiles() {{{2 +" toggles the display of hidden files +function! s:toggleShowFiles() + let b:NERDTreeShowFiles = !b:NERDTreeShowFiles + call s:renderViewSavingPosition() + call s:centerView() +endfunction + +" FUNCTION: s:toggleShowHidden() {{{2 +" toggles the display of hidden files +function! s:toggleShowHidden() + let b:NERDTreeShowHidden = !b:NERDTreeShowHidden + call s:renderViewSavingPosition() + call s:centerView() +endfunction + +" FUNCTION: s:toggleZoom() {{2 +" zoom (maximize/minimize) the NERDTree window +function! s:toggleZoom() + if exists("b:NERDTreeZoomed") && b:NERDTreeZoomed + let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize + exec "silent vertical resize ". size + let b:NERDTreeZoomed = 0 + else + exec "vertical resize" + let b:NERDTreeZoomed = 1 + endif +endfunction + +"FUNCTION: s:upDir(keepState) {{{2 +"moves the tree up a level +" +"Args: +"keepState: 1 if the current root should be left open when the tree is +"re-rendered +function! s:upDir(keepState) + let cwd = b:NERDTreeRoot.path.str({'format': 'UI'}) + if cwd ==# "/" || cwd =~# '^[^/]..$' + call s:echo("already at top dir") + else + if !a:keepState + call b:NERDTreeRoot.close() + endif + + let oldRoot = b:NERDTreeRoot + + if empty(b:NERDTreeRoot.parent) + let path = b:NERDTreeRoot.path.getParent() + let newRoot = s:TreeDirNode.New(path) + call newRoot.open() + call newRoot.transplantChild(b:NERDTreeRoot) + let b:NERDTreeRoot = newRoot + else + let b:NERDTreeRoot = b:NERDTreeRoot.parent + endif + + if g:NERDTreeChDirMode ==# 2 + call b:NERDTreeRoot.path.changeToDir() + endif + + call s:renderView() + call oldRoot.putCursorHere(0, 0) + endif +endfunction + + +"reset &cpo back to users setting +let &cpo = s:old_cpo + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/.vim/plugin/VimExplorer.vim b/.vim/plugin/VimExplorer.vim new file mode 100644 index 0000000..4ef4127 --- /dev/null +++ b/.vim/plugin/VimExplorer.vim @@ -0,0 +1,3538 @@ +"================================================== +" File: VimExplorer.vim +" Brief: VE - the File Manager within Vim! +" Authors: Ming Bai +" Last Change: 2009-05-06 00:20:25 +" Version: 0.99 +" Licence: LGPL +" +" Usage: :h VimExplorer +" +"================================================== + + +" See if we are already loaded, thanks to Dennis Hostetler. +if exists("loaded_vimExplorer") + finish +else + let loaded_vimExplorer = 1 +endif +" + +" Vim version 7.x is needed. +if v:version < 700 + echohl ErrorMsg | echomsg "VimExplorer needs vim version >= 7.0!" | echohl None + finish +endif + +"Load config {{{1 +"####################################################################### +"VimExplorer configuration. +" +let VEConf = {} + +"Normal configurations. + +"Common settings +"========================================== + +"Important! It is used to do iconv() to the path when calling +"sytem() function. Mine is Simplified Chinese (cp936). +if exists("g:VEConf_systemEncoding") + let VEConf.systemEncoding = g:VEConf_systemEncoding +else + let VEConf.systemEncoding = '' +endif + +"VimExplorer will check all the disks in this list at startup. +"Delete some of these to fit your system can increase start up +"speed. +"let VEConf.win32Disks = ["C:","D:","E:"] +if exists("g:VEConf_win32Disks") + let VEConf.win32Disks = g:VEConf_win32Disks +else + let VEConf.win32Disks = ["A:","B:","C:","D:","E:","F:","G:","H:", + \"I:","J:","K:","L:","M:","N:","O:","P:","Q:","R:", + \"S:","T:","U:","V:","W:","X:","Y:","Z:"] +endif + +"Set the forward and backward history stack depth. +if exists("g:VEConf_browseHistory") + let VEConf.browseHistory = g:VEConf_browseHistory +else + let VEConf.browseHistory = 100 +endif + +"Split location of preview window +if exists("g:VEConf_previewSplitLocation") + let VEConf.previewSplitLocation = g:VEConf_previewSplitLocation +else + let VEConf.previewSplitLocation = "belowright" +endif + +"Show hidden files ( .* ) +if exists("g:VEConf_showHiddenFiles") + let VEConf.showHiddenFiles = VEConf_showHiddenFiles +else + let VEConf.showHiddenFiles = 1 +endif + +"External explorer name +if (has("win32") || has("win95") || has("win64") || has("win16") || has("dos32")) + if exists("g:VEConf_externalExplorer") + let VEConf.externalExplorer = g:VEConf_externalExplorer + else + let VEConf.externalExplorer = "explorer.exe" + endif +else + if exists("g:VEConf_externalExplorer") + let VEConf.externalExplorer = g:VEConf_externalExplorer + else + let VEConf.externalExplorer = "nautilus" + endif +endif + +"Sort case sensitive , for everything +if exists("g:VEConf_sortCaseSensitive") + let VEConf.sortCaseSensitive = g:VEConf_sortCaseSensitive +else + let VEConf.sortCaseSensitive = 0 +endif + +"favorite file name +if exists("g:VEConf_favorite") + let VEConf.favorite = g:VEConf_favorite +else + let VEConf.favorite = ".ve_favorite" +endif + +"Overwrite existing files. +"boverWrite 0 ask, 1 allyes, 2 allno +if exists("g:VEConf_overWriteExisting") + let VEConf.overWriteExisting = g:VEConf_overWriteExisting +else + let VEConf.overWriteExisting = 0 +endif + +"Kde or gonme. +if !exists("g:VEConf_usingKDE") + let g:VEConf_usingKDE = 0 +endif +if !exists("g:VEConf_usingGnome") + let g:VEConf_usingGnome = 0 +endif + +"Recycle path +if !exists("g:VEConf_recyclePath") + let g:VEConf.recyclePath = '' +else + let g:VEConf.recyclePath = g:VEConf_recyclePath +endif + +"Tree panel settings +"========================================== + +"Show '+' before empty folders. +"It will cause a little performance lost. +if exists("g:VEConf_showFolderStatus") + let VEConf.showFolderStatus = g:VEConf_showFolderStatus +else + let VEConf.showFolderStatus = 1 +endif + +"Tree panel width +if exists("g:VEConf_treePanelWidth") + let VEConf.treePanelWidth = g:VEConf_treePanelWidth +else + let VEConf.treePanelWidth = 30 +endif + +"Split mode of tree panel +if exists("g:VEConf_treePanelSplitMode") + let VEConf.treePanelSplitMode = g:VEConf_treePanelSplitMode +else + let VEConf.treePanelSplitMode = "vertical" +endif + +"Split location of file panel +if exists("g:VEConf_treePanelSplitLocation") + let VEConf.treePanelSplitLocation = g:VEConf_treePanelSplitLocation +else + let VEConf.treePanelSplitLocation = "leftabove" +endif + +"Set the tree panel sort direction. +if exists("g:VEConf_treeSortDirection") + let VEConf.treeSortDirection = g:VEConf_treeSortDirection +else + let VEConf.treeSortDirection = 1 +endif + +"File panel settings +"========================================== + +"Set the file group sort direction. +if exists("g:VEConf_fileGroupSortDirection") + let VEConf.fileGroupSortDirection = g:VEConf_fileGroupSortDirection +else + let VEConf.fileGroupSortDirection = 1 +endif + +"Delete file confirm. +if exists("g:VEConf_fileDeleteConfirm") + let VEConf.fileDeleteConfirm = g:VEConf_fileDeleteConfirm +else + let VEConf.fileDeleteConfirm = 1 +endif + +"File panel width +if exists("g:VEConf_filePanelWidth") + let VEConf.filePanelWidth = g:VEConf_filePanelWidth +else + let VEConf.filePanelWidth = 40 +endif + +"Split mode of file panel +if exists("g:VEConf_filePanelSplitMode") + let VEConf.filePanelSplitMode = g:VEConf_filePanelSplitMode +else + let VEConf.filePanelSplitMode = "vertical" +endif + +"Split location of file panel +if exists("g:VEConf_filePanelSplitLocation") + let VEConf.filePanelSplitLocation = g:VEConf_filePanelSplitLocation +else + let VEConf.filePanelSplitLocation = "belowright" +endif + +"File panel sort type. +if exists("g:VEConf_filePanelSortType") + let VEConf.filePanelSortType = g:VEConf_filePanelSortType +else + let VEConf.filePanelSortType = 0 +endif + +"Show file size in M/K/B +if exists("g:VEConf_showFileSizeInMKB") + let VEConf.showFileSizeInMKB = g:VEConf_showFileSizeInMKB +else + let VEConf.showFileSizeInMKB = 1 +endif + +"File panel filter. +if exists("g:VEConf_filePanelFilter") + let VEConf.filePanelFilter = g:VEConf_filePanelFilter +else + let VEConf.filePanelFilter = '' +endif + + +"####################################################################### +"Tree panel hot key bindings. +let VEConf.treePanelHotkey = {} +let VEConf.treePanelHotkey.help = '?' +let VEConf.treePanelHotkey.toggleNode = '' +let VEConf.treePanelHotkey.toggleNodeMouse = '<2-LeftMouse>' +let VEConf.treePanelHotkey.refresh = 'r' +let VEConf.treePanelHotkey.favorite = 'f' +let VEConf.treePanelHotkey.addToFavorite = 'F' +let VEConf.treePanelHotkey.browseHistory = 'b' +let VEConf.treePanelHotkey.toggleFilePanel = 't' +let VEConf.treePanelHotkey.toUpperDir = '' +let VEConf.treePanelHotkey.switchPanel = '' +let VEConf.treePanelHotkey.gotoPath = '' +let VEConf.treePanelHotkey.quitVE = 'Q' + +if exists("g:VEConf_treeHotkey") + if type(g:VEConf_treeHotkey) != type({}) + echohl WarningMsg | echo "g:VEConf_treeHotkey is not dictionary type!" | echohl None + finish + endif + for i in keys(g:VEConf_treeHotkey) + let VEConf.treePanelHotkey[i] = g:VEConf_treeHotkey[i] + endfor +endif + +"File panel hot key bindings. +"normal mode hotkeys +let VEConf.filePanelHotkey = {} +"normal +let VEConf.filePanelHotkey.help = '?' +let VEConf.filePanelHotkey.itemClicked = '' +let VEConf.filePanelHotkey.itemClickMouse = '<2-LeftMouse>' +let VEConf.filePanelHotkey.refresh = 'r' +let VEConf.filePanelHotkey.toggleTreePanel = 't' +let VEConf.filePanelHotkey.toggleModes = 'i' +let VEConf.filePanelHotkey.newFile = '+f' +let VEConf.filePanelHotkey.newDirectory = '+d' +let VEConf.filePanelHotkey.switchPanel = '' +let VEConf.filePanelHotkey.quitVE = 'Q' +let VEConf.filePanelHotkey.toggleHidden = 'H' +let VEConf.filePanelHotkey.search = 'g/' +let VEConf.filePanelHotkey.markPlace = 'm' +let VEConf.filePanelHotkey.gotoPlace = "'" +let VEConf.filePanelHotkey.viewMarks = 'J' +let VEConf.filePanelHotkey.contextMenuN = '' +"Browsing +let VEConf.filePanelHotkey.toUpperDir = '' +let VEConf.filePanelHotkey.gotoForward = '' +let VEConf.filePanelHotkey.gotoBackward = '' +let VEConf.filePanelHotkey.favorite = 'f' +let VEConf.filePanelHotkey.addToFavorite = 'F' +let VEConf.filePanelHotkey.browseHistory = 'b' +let VEConf.filePanelHotkey.gotoPath = '' +"single file actions +let VEConf.filePanelHotkey.rename = 'R' +let VEConf.filePanelHotkey.yankSingle = 'yy' +let VEConf.filePanelHotkey.cutSingle = 'xx' +let VEConf.filePanelHotkey.showYankList = 'yl' +let VEConf.filePanelHotkey.deleteSingle = 'dd' +let VEConf.filePanelHotkey.deleteSingleF = 'DD' +let VEConf.filePanelHotkey.openPreview = 'u' +let VEConf.filePanelHotkey.closePreview = 'U' +"mark +let VEConf.filePanelHotkey.toggleSelectUp = '' +let VEConf.filePanelHotkey.toggleSelectDown= '' +let VEConf.filePanelHotkey.toggleSelMouse = '' +let VEConf.filePanelHotkey.markViaRegexp = 'Mr' +let VEConf.filePanelHotkey.markVimFiles = 'Mv' +let VEConf.filePanelHotkey.markDirectory = 'Md' +let VEConf.filePanelHotkey.markExecutable = 'Me' +let VEConf.filePanelHotkey.clearSelect = 'Mc' +"multiple file actions +let VEConf.filePanelHotkey.deleteSelected = 'sd' +let VEConf.filePanelHotkey.deleteSelectedF = 'sD' +let VEConf.filePanelHotkey.yankSelected = 'sy' +let VEConf.filePanelHotkey.cutSelected = 'sx' +let VEConf.filePanelHotkey.tabViewMulti = 'se' +let VEConf.filePanelHotkey.paste = 'p' +let VEConf.filePanelHotkey.diff2files = '=' +"visual mode hotkeys. +let VEConf.filePanelHotkey.visualSelect = '' +let VEConf.filePanelHotkey.visualDelete = 'd' +let VEConf.filePanelHotkey.visualDeleteF = 'D' +let VEConf.filePanelHotkey.visualYank = 'y' +let VEConf.filePanelHotkey.visualCut = 'x' +"User defined hotkeys, see below. +let VEConf.filePanelHotkey.tabView = 'e' +let VEConf.filePanelHotkey.openRenamer = ';r' +let VEConf.filePanelHotkey.startShell = ';c' +let VEConf.filePanelHotkey.startExplorer = ';e' + +if exists("g:VEConf_fileHotkey") + if type(g:VEConf_fileHotkey) != type({}) + echohl WarningMsg | echo "g:VEConf_fileHotkey is not dictionary type!" | echohl None + finish + endif + for i in keys(g:VEConf_fileHotkey) + let VEConf.filePanelHotkey[i] = g:VEConf_fileHotkey[i] + endfor +endif + +"####################################################################### +"User defined file actions. +if !exists("g:VEConf_normalActions") + let VEConf_normalActions = {} +endif +if !exists("g:VEConf_normalHotKeys") + let VEConf_normalHotKeys = {} +endif +if !exists("g:VEConf_singleFileActions") + let VEConf_singleFileActions = {} +endif +if !exists("g:VEConf_singleFileHotKeys") + let VEConf_singleFileHotKeys = {} +endif + +if !exists("g:VEConf_multiFileActions") + let VEConf_multiFileActions = {} +endif +if !exists("g:VEConf_multiFileHotKeys") + let VEConf_multiFileHotKeys = {} +endif + +"Template +" let VEConf_singleFileHotKeys['actionName'] = '' +" function! VEConf_singleFileActions['actionName'](path) +" "do some jobs here. +" endfunction +" +"the 'path' is the file name under cursor in the file panel, you +"can use this path to do some actions. +"Pay attention to the hotKeys you have defined, dont conflict +"whth the default hotKey bindings. +"Normal Actions just run in current path, no path needed to +"pass. + +"There are some examples: +"Open current file using vim in a new tab. +let VEConf_singleFileHotKeys['openInNewTab'] = VEConf.filePanelHotkey.tabView +function! VEConf_singleFileActions['openInNewTab'](path) + if !isdirectory(a:path) + exec "tabe " . g:VEPlatform.escape(a:path) + else + exec "VE " . g:VEPlatform.escape(a:path) + endif +endfunction + +"Renamer is a very good plugin. +let VEConf_normalHotKeys['openRenamer'] = VEConf.filePanelHotkey.openRenamer +function! VEConf_normalActions['openRenamer']() + Renamer +endfunction + +"start shell in current directory. +let VEConf_normalHotKeys['startShell'] = VEConf.filePanelHotkey.startShell +function! VEConf_normalActions['startShell']() + call g:VEPlatform.startShell() +endfunction + +"start file explorer in current directory +"(nautilus,konquer,Explorer.exe and so on). +let VEConf_normalHotKeys['startExplorer'] = VEConf.filePanelHotkey.startExplorer +function! VEConf_normalActions['startExplorer']() + call g:VEPlatform.startExplorer() +endfunction + +"Multiple file name are contained in the fileList. +let VEConf_multiFileHotKeys['openMultiFilesWithVim'] = VEConf.filePanelHotkey.tabViewMulti +function! VEConf_multiFileActions['openMultiFilesWithVim'](fileList) + if empty(a:fileList) + return + endif + for i in a:fileList + exec "tabe " . g:VEPlatform.escape(i) + endfor +endfunction + +"####################################################################### +"Syntax and highlight configuration. +function! VEConf.treePanelSyntax() + syn clear + syn match Question "^.*Press ? for help.*$" "Host name + syn match WarningMsg "\[[A-Z]:[\\/]\]" "root node name + syn match Identifier "^\s*\zs[+-]" "+- + syn match SpecialKey "^.*\[current\]$" "current folder +endfunction + +function! VEConf.filePanelSyntax() + syntax clear + syn match Type "\[ .* \]" "group + syn match Comment '\t.\{10}' "file size + syn match Comment '\d\{4}-\d\{2}-\d\{2}\ \d\{2}:\d\{2}:\d\{2}' "time + syn match Special '^Path: .*$' "path + syn match WarningMsg '^\~*$' "line + syn match Function '^.*[\\/]' "directory + syn match Search '^\*.*$' "selectedFiles + syn match LineNr '[rwx-]\{9}' "perm +endfunction + +"####################################################################### + +" classes relationship +" +" VEFrameWork +" VETreePanel +" VETree +" VENode +" VEFilePanel +" VEPlatform + +" class VEPlatform {{{1 +"============================= +let VEPlatform = {} + +"it's a static class, no constructor + +"has win +function! VEPlatform.haswin32() + if (has("win32") || has("win95") || has("win64") || has("win16") || has("dos32")) + return 1 + else + return 0 + endif +endfunction + +"return a path always end with slash. +function! VEPlatform.getcwd() + let path = getcwd() + if g:VEPlatform.haswin32() && !&ssl + if path[-1:] != "\\" + let path = path . "\\" + endif + else + if path[-1:] != "/" + let path = path . "/" + endif + endif + return path +endfunction + +"get home path, end with a slash +function! VEPlatform.getHome() + if g:VEPlatform.haswin32() && !&ssl + if $HOME[-1:] != "\\" + return $HOME . "\\" + else + return $HOME + endif + else + if $HOME[-1:] != "/" + return $HOME . "/" + else + return $HOME + endif + endif +endfunction + +function! VEPlatform.escape(path) + if g:VEPlatform.haswin32() + return escape(a:path,'%#') + else + return escape(a:path,' %#') + endif +endfunction + +"start a program and then return to vim, no wait. +function! VEPlatform.start(path) + let convPath = self.escape(a:path) + "escape() function will do iconv to the string, so call it + "before iconv(). + if g:VEPlatform.haswin32() + let convPath = substitute(convPath,'/',"\\",'g') + let convPath = " start \"\" \"" . convPath . "\"" + let ret = self.system(convPath) + else + if g:VEConf_usingKDE + let convPath = "kfmclient exec " . convPath + let ret = self.system(convPath) + elseif g:VEConf_usingGnome + let convPath = "gnome-open " . convPath + let ret = self.system(convPath) + else " default using gnome-open. + let convPath = "gnome-open " . convPath + let ret = self.system(convPath) + endif + endif + if !ret + echohl ErrorMsg | echomsg "Failed to start " . a:path | echohl None + return 0 + endif + return 1 +endfunction + +function! VEPlatform.system(cmd) + "can not escape here! example: 'rm -r blabla\ bbb' + "let convCmd = escape(a:cmd,' %#') + let convCmd = a:cmd + if g:VEConf.systemEncoding != '' + let convCmd = iconv(convCmd,&encoding,g:VEConf.systemEncoding) + endif + call system(convCmd) + return !(v:shell_error) +endfunction + +" Return successful copyed file list. +function! VEPlatform.copyMultiFile(fileList,topath) + let boverWrite = g:VEConf.overWriteExisting + let retList = [] + for i in a:fileList + "boverWrite 0 ask, 1 allyes, 2 allno + if boverWrite == 0 + if i[-1:] == "\\" || i[-1:] == "/" + let i = i[:-2] + endif + let tofile = a:topath . matchstr(i,'[\\/]\zs[^\\/]\+$') + if findfile(tofile) != '' + "echohl WarningMsg + "let result = tolower(input("File [ " . tofile . " ] exists! Over write ? (Y)es/(N)o/(A)llyes/A(L)lno/(C)ancel ","Y")) + let result = confirm("File [ " . matchstr(i,'[\\/]\zs[^\\/]\+$') . + \" ] exists! Over write ? ","&Yes\n&No\nYes to &All\nNo &To All\n&Cancel ",1) + "echohl None + if result == 1 + if !self.copyfile(i,a:topath) + echohl ErrorMsg | echomsg "Copy file error: " . i | echohl None + else + let retList += [i] + endif + elseif result == 2 + continue + elseif result == 3 + let boverWrite = 1 + if !self.copyfile(i,a:topath) + echohl ErrorMsg | echomsg "Copy file error: " . i | echohl None + else + let retList += [i] + endif + elseif result == 4 + let boverWrite = 2 + else + break + endif + else + if !self.copyfile(i,a:topath) + echohl ErrorMsg | echomsg "Copy file error: " . i | echohl None + else + let retList += [i] + endif + endif + elseif boverWrite == 1 + if !self.copyfile(i,a:topath) + echohl ErrorMsg | echomsg "Copy file error: " . i | echohl None + else + let retList += [i] + endif + elseif boverWrite == 2 + if i[-1:] == "\\" || i[-1:] == "/" + let i = i[:-2] + endif + let tofile = a:topath . matchstr(i,'[\\/]\zs[^\\/]\+$') + if findfile(tofile) != '' + continue + endif + if !self.copyfile(i,a:topath) + echohl ErrorMsg | echomsg "Copy file error: " . i | echohl None + else + let retList += [i] + endif + endif + endfor + echohl Special | echomsg " " . len(retList) . " file(s) pasted!" | echohl None + return retList +endfunction + +function! VEPlatform.copyfile(filename,topath) + "return + let filename = self.escape(a:filename) + let topath = self.escape(a:topath) + if g:VEPlatform.haswin32() + let filename = substitute(a:filename,'/',"\\",'g') + let topath = substitute(a:topath,'/',"\\",'g') + if isdirectory(filename) + if filename[-1:] == "\\" + let filename = filename[:-2] + endif + let topath = "\"" . topath . matchstr(filename,'[^\\]*$') . "\"" + let filename = "\"" . filename . "\"" + let cmd = "xcopy ".filename . " " . topath . " /E /I /H /R /Y" + else + let topath = "\"" . topath . "\"" + let filename = "\"" . filename . "\"" + let cmd = "xcopy ". filename . " " . topath . " /I /H /R /Y" + endif + return self.system(cmd) + else + let cmd = "cp -r " . filename . " " . topath . "&" + return self.system(cmd) + endif +endfunction + +" The "move" command in win32 is so poor.. +" So I have no choice but copy then delete. +"function! VEPlatform.movefile(filename,topath) +" let filename = self.escape(a:filename) +" let topath = self.escape(a:topath) +" if executable("mv") +" let cmd = "mv -f " . filename . " " . topath +" return self.system(cmd) +" else +" if self.copyfile(a:filename,a:topath) +" return self.delete(a:filename,1) +" else +" return 0 +" endif +" endif +"endfunction + +function! VEPlatform.mkdir(path) + if g:VEConf.systemEncoding != '' + let convPath = iconv(a:path,&encoding,g:VEConf.systemEncoding) + else + let convPath = a:path + endif + return mkdir(convPath,'p') +endfunction + +function! VEPlatform.mkfile(filename) + if findfile(a:filename) != '' || isdirectory(a:filename) + return 0 + endif + if writefile([],a:filename) == 0 "here it is not need to convert filename + return 1 + else + return 0 + endif +endfunction + +function! VEPlatform.executable(filename) + if isdirectory(a:filename) + return 0 + endif + if getfperm(a:filename)[2] == 'x' + return 1 + else + return 0 + endif +endfunction + +function! VEPlatform.search(filename,path) + if a:filename == '.' || a:filename == '..' + return [] + else + return split(globpath(a:path,"**/" . a:filename),"\n") + endif +endfunction + +function! VEPlatform.globpath(path) + if g:VEConf.showHiddenFiles + let tmp = globpath(a:path,"*") . "\n" . globpath(a:path,".[^.]*") "need to cut . and .. + " can not show files start with .. such as ..foo , :( + " I do not know how to write the shell regexp. + if tmp == "\n" + return '' + else + return tmp + endif + else + return globpath(a:path,"*") + endif +endfunction + +"globpath used in file panel, including filter. +function! VEPlatform.globpath_file(path) + if g:VEConf.filePanelFilter != '' + return globpath(a:path,g:VEConf.filePanelFilter) + endif + if g:VEConf.showHiddenFiles + let tmp = globpath(a:path,"*") . "\n" . globpath(a:path,".[^.]*") "need to cut . and .. + " can not show files start with .. such as ..foo , :( + " I do not know how to write the shell regexp. + if tmp == "\n" + return '' + else + return tmp + endif + else + return globpath(a:path,"*") + endif +endfunction + +function! VEPlatform.cdToPath(path) + try + "In win32, VE can create folder starts with space. So ... + exec "lcd " . escape(a:path,' %#') + catch + echohl ErrorMsg | echomsg "Can not cd to path: " . a:path | echohl None + endtry +endfunction + +function! VEPlatform.startShell() + if g:VEPlatform.haswin32() + !start cmd.exe + else + shell + endif +endfunction + +function! VEPlatform.startExplorer() + let pwd = self.escape(g:VEPlatform.getcwd()) + if g:VEPlatform.haswin32() + let pwd = substitute(pwd,'/',"\\",'g') + endif + if !self.system(g:VEConf.externalExplorer . " " . pwd) + "echohl ErrorMsg | echomsg "Failed to start external explorer: " . g:VEConf.externalExplorer | echohl None + " M$ windows Explorer.exe always return 1 even it starts successfully, shit! + endif +endfunction + +function! VEPlatform.getRoot(rootDict) + if g:VEPlatform.haswin32() + "Create new root list. + let newRootList = [] + for i in g:VEConf.win32Disks + if &ssl + let i = i . "/" + else + let i = i . "\\" + endif + if g:VEPlatform.globpath(i) != '' + call add(newRootList,i) + endif + endfor + "Remove nolonger exist root nodes. + for i in keys(a:rootDict) + if index(newRootList,i) == -1 + call remove(a:rootDict,i) + endif + endfor + "Create new root nodes. + for i in newRootList + if !has_key(a:rootDict,i) + let a:rootDict[i] = deepcopy(s:VENode) + call a:rootDict[i].init(i) + let a:rootDict[i].hasOwnChilds = 1 + endif + endfor + else "Assert the other platform acts like UNIX + let newRootList = ["/"] " ~/ + for i in newRootList + if !has_key(a:rootDict,i) + let a:rootDict[i] = deepcopy(s:VENode) + call a:rootDict[i].init(i) + let a:rootDict[i].hasOwnChilds = 1 + endif + endfor + endif +endfunction + +function! VEPlatform.pathToName(path) + let time = strftime("%Y-%m-%d %H:%M:%S",getftime(a:path)) + let size = getfsize(a:path) + let perm = getfperm(a:path) + if g:VEPlatform.haswin32() && !&ssl + if a:path[-1:] != "\\" + let name = substitute(a:path,'^.*\\','','g') + else + let name = substitute(a:path,'^.*\\\ze.\+\\$','','g') + endif + else + if a:path[-1:] != "/" + let name = substitute(a:path,'^.*\/','','g') + else + let name = substitute(a:path,'^.*\/\ze.\+\/$','','g') + endif + endif + if g:VEConf.showFileSizeInMKB + if size > (1024 * 1024) + let size = (size / 1024 / 1024) . ' M' + elseif size > 1024 + let size = (size / 1024) . ' K' + elseif size > 0 + let size = size . ' B' + endif + endif + let tail = printf("%10.10s ".perm . ' ' .time,size==0?'':size) + return name . "\t" . tail +endfunction + +function! VEPlatform.getUpperDir(path) + if g:VEPlatform.haswin32() && !&ssl + return substitute(a:path,'\\\zs[^\\]\+\\$','','g') + else + return substitute(a:path,'\/\zs[^/]\+\/$','','g') + endif +endfunction + +"default choice and return value: 1:YES 0:NO +function! VEPlatform.confirm(text,defaultChoice) + if a:defaultChoice + let ret = confirm(a:text,"&Yes\n&No",1) + else + let ret = confirm(a:text,"&Yes\n&No",2) + endif + if ret == 1 + return 1 + else + return 0 + endif + "if a:defaultChoice + " echohl WarningMsg + " let result = tolower(input(a:text . " ","Y")) + " echohl None + "else + " echohl WarningMsg + " let result = tolower(input(a:text . " "),"N") + " echohl None + "endif + "if result == "y" || result == "ye" || result == "yes" + " return 1 + "else + " return 0 + "endif +endfunction + +"delete a single file or directory +"return 0:failed 1:success +function! VEPlatform.deleteSingle(path,bforce) + if !isdirectory(a:path) + if g:VEConf.fileDeleteConfirm && !self.confirm("Delete \n\"".a:path."\" ?",1) + echo " " + "clear the command line + return 0 + endif + if self.delete(a:path,a:bforce) + echohl Special | echomsg "File: [" . a:path . "] deleted!" | echohl None + return 1 + else + echohl ErrorMsg | echomsg "Can not delete the file! [" . a:path . "]" | echohl None + return 0 + endif + else + if g:VEConf.fileDeleteConfirm && !self.confirm("Remove the folder \n\"".a:path."\" and all its contents?",1) + echo " " + return 0 + endif + echo " " + return self.delete(a:path,a:bforce) + endif +endfunction + +"delete multiple files/directory. +"return 0:failed 1:success +function! VEPlatform.deleteMultiple(fileList,bforce) + if g:VEConf.fileDeleteConfirm && !self.confirm("Delete selected file(s) ?",1) + echo " " + return 0 + endif + for i in a:fileList + if !self.delete(i,a:bforce) + echohl ErrorMsg | echomsg "Failed to delete: " . i | echohl None + endif + endfor + return 1 +endfunction + +function! VEPlatform.delete(name,bforce) + if g:VEPlatform.haswin32() + let recPath = tolower(g:VEConf.recyclePath) + let delName = tolower(a:name) + else + let recPath = g:VEConf.recyclePath + let delName = a:name + endif + if !a:bforce && g:VEConf.recyclePath != '' && (stridx(delName,recPath) == -1) + if !isdirectory(g:VEConf.recyclePath) + if !self.mkdir(g:VEConf.recyclePath) || !isdirectory(g:VEConf.recyclePath) + echohl ErrorMsg | echomsg "Can not access recycle bin!" | echohl None + return 0 + endif + endif + if !self.copyfile(a:name,g:VEConf.recyclePath) + echohl ErrorMsg | echomsg "Failed to move the file: [" . a:name . "] to recycle bin." | echohl None + return 0 + "else + " return 1 + endif + endif + if isdirectory(a:name) + if g:VEPlatform.haswin32() + return g:VEPlatform.system(" rmdir /S /Q \"" . self.escape(a:name) . "\"") + else + return g:VEPlatform.system("rm -r " . self.escape(a:name) . "&") + endif + else + if delete(a:name) == 0 + return 1 + else + return 0 + endif + endif +endfunction + +function! VEPlatform.select(list,title) + let selectList = deepcopy(a:list) + if len(selectList) == 0 + return + endif + call insert(selectList,a:title,0) + for i in range(1,len(selectList)-1) + let selectList[i] = i . " " . selectList[i] + endfor + let result = inputlist(selectList) + if result > len(a:list) || result <= 0 + return -1 + else + return result-1 + endif +endfunction + +" This is not a member of VEPlatform, because sort() +" can not use dict function. +function! VEPlatform_sortCompare(t1,t2) + if g:VEConf.sortCaseSensitive + return a:t1 ==# a:t2 ? 0 : a:t1 ># a:t2 ? 1 : -1 + else + return a:t1 ==? a:t2 ? 0 : a:t1 >? a:t2 ? 1 : -1 + endif +endfunction + + +" class VENode {{{1 +"============================= +let s:VENode = {} +let s:VENode.name = '' +let s:VENode.path = '' +let s:VENode.isopen = 0 +let s:VENode.hasOwnChilds = 0 +let s:VENode.childs = {} + +"Object Constructor +function! s:VENode.init(path) + let self.path = a:path + if g:VEPlatform.haswin32() && !&ssl + let self.name = matchstr(a:path,'[^\\]*\\$','','g') + else + let self.name = matchstr(a:path,'[^/]*\/$','','g') + endif +endfunction + +"Refresh tree node +function! s:VENode.updateNode() + "Once a node is updated, it means that the node has been opened. + let self.isopen = 1 + "Create new dir list + let newDirList = [] + for i in split(g:VEPlatform.globpath(self.path),"\n") + if isdirectory(i) == 1 + if g:VEPlatform.haswin32() && !&ssl + let i = matchstr(i,'[^\\]*$','','g') . "\\" + else + let i = matchstr(i,'[^/]*$','','g') . "/" + endif + call add(newDirList,i) + endif + endfor + "Remove nolonger exist dirs. + for i in keys(self.childs) + if index(newDirList,i) == -1 + call remove(self.childs,i) + endif + endfor + "Create new nodes + for i in newDirList + if !has_key(self.childs,i) + let self.childs[i] = deepcopy(s:VENode) + call self.childs[i].init(self.path . i) + endif + endfor + "find out which child has their own childs + if !empty(self.childs) + let self.hasOwnChilds = 1 + else + let self.hasOwnChilds = 0 + return + endif + if g:VEConf.showFolderStatus == 0 + for i in keys(self.childs) + let self.childs[i].hasOwnChilds = 1 + endfor + else + for i in keys(self.childs) + let _hasOwnChilds = 0 + for j in split(g:VEPlatform.globpath(self.childs[i].path),"\n") + if isdirectory(j) == 1 + let _hasOwnChilds = 1 + break + endif + endfor + if _hasOwnChilds == 1 + let self.childs[i].hasOwnChilds = 1 + endif + endfor + endif + "update opened child nodes + for i in keys(self.childs) + if self.childs[i].isopen == 1 + call self.childs[i].updateNode() + endif + endfor +endfunction + +"Toggle open/close status of one node +"the path should end with '\' such as c:\aaa\bbb\ +"example "c:\\aaa\\bbb\\" "aaa\\bbb\\" "bbb\\" +function! s:VENode.toggle(path) + if g:VEPlatform.haswin32() && !&ssl + let childPath = substitute(a:path,'^.\{-}\\','','g') + else + let childPath = substitute(a:path,'^.\{-}\/','','g') + endif + if childPath == '' + let self.isopen = !self.isopen + if self.isopen == 1 + call self.updateNode() + endif + else + if g:VEPlatform.haswin32() && !&ssl + let nodeName = matchstr(childPath,'^.\{-}\\') + else + let nodeName = matchstr(childPath,'^.\{-}\/') + endif + if !has_key(self.childs,nodeName) + echoerr "path error" + endif + let self.isopen = 1 + call self.childs[nodeName].toggle(childPath) + endif +endfunction + +"Open the giving path +"the path should end with '\' such as c:\aaa\bbb\ +"example "c:\\aaa\\bbb\\" "aaa\\bbb\\" "bbb\\" +function! s:VENode.openPath(path) + if g:VEPlatform.haswin32() && !&ssl + let childPath = substitute(a:path,'^.\{-}\\','','g') + else + let childPath = substitute(a:path,'^.\{-}\/','','g') + endif + if childPath == '' + if empty(self.childs) + call self.updateNode() + endif + return + else + if g:VEPlatform.haswin32() && !&ssl + let nodeName = matchstr(childPath,'^.\{-}\\') + else + let nodeName = matchstr(childPath,'^.\{-}\/') + endif + if !has_key(self.childs,nodeName) + call self.updateNode() + endif + if !has_key(self.childs,nodeName) "refreshed and still can not find the path. + echoerr "Path error!" + return + else + let self.isopen = 1 + call self.childs[nodeName].openPath(childPath) + endif + endif +endfunction + + +"Draw the tree, depend on the status of every tree node. +function! s:VENode.draw(tree,depth) + if self.hasOwnChilds == 0 + let name = repeat(' ',a:depth*2).' '.self.name + call add(a:tree,[name,self.path]) + return + endif + if self.isopen + let name = repeat(' ',a:depth*2).'- '.self.name + if a:depth == 0 "let the root node looks different + let name = '- [' . self.name . ']' + endif + call add(a:tree,[name,self.path]) + let keys = sort(keys(self.childs),"VEPlatform_sortCompare") + if !g:VEConf.treeSortDirection + call reverse(keys) + endif + for i in keys + call self.childs[i].draw(a:tree,a:depth+1) + endfor + else + let name = repeat(' ',a:depth*2).'+ '.self.name + if a:depth == 0 "let the root node looks different + let name = '+ [' . self.name . ']' + endif + call add(a:tree,[name,self.path]) + endif +endfunction + +" class VETree {{{1 +"============================= +let s:VETree = {} +let s:VETree.content = [] +let s:VETree.rootNodes = {} + +"Object Constructor +function! s:VETree.init() + call g:VEPlatform.getRoot(self.rootNodes) + "for i in keys(self.rootNodes) + " call self.rootNodes[i].updateNode() + "endfor +endfunction + +function! s:VETree.togglePath(path) + if g:VEPlatform.haswin32() && !&ssl + let rootNodeName = matchstr(a:path,'^.\{-}\\') + else + let rootNodeName = matchstr(a:path,'^.\{-}\/') + endif + call self.rootNodes[rootNodeName].toggle(a:path) +endfunction + +function! s:VETree.openPath(path) + if g:VEPlatform.haswin32() && !&ssl + let rootNodeName = matchstr(a:path,'^.\{-}\\') + else + let rootNodeName = matchstr(a:path,'^.\{-}\/') + endif + call self.rootNodes[rootNodeName].openPath(a:path) +endfunction + +" fill self.content +function! s:VETree.draw() + let keys = sort(keys(self.rootNodes),"VEPlatform_sortCompare") + if g:VEConf.treeSortDirection == 0 + call reverse(keys) + endif + for i in keys + call self.rootNodes[i].draw(self.content,0) + endfor +endfunction + +function! s:VETree.update(path) + call g:VEPlatform.getRoot(self.rootNodes) + "toggle twice to update current directory + call self.togglePath(a:path) + call self.togglePath(a:path) + " costs too much time. + "for i in keys(self.rootNodes) + " call self.rootNodes[i].updateNode() + "endfor +endfunction + +" class VETreePanel {{{1 +"============================= +let s:VETreePanel = {} +let s:VETreePanel.tree = {} +let s:VETreePanel.name = '' +let s:VETreePanel.path = '' +let s:VETreePanel.width = 0 +let s:VETreePanel.splitMode = '' +let s:VETreePanel.splitLocation = '' + +"Object Constructor +function! s:VETreePanel.init(name,path) + let self.name = "VETreePanel" . a:name + let self.path = a:path + let self.width = g:VEConf.treePanelWidth + let self.splitMode = g:VEConf.treePanelSplitMode + let self.splitLocation = g:VEConf.treePanelSplitLocation + let self.tree = deepcopy(s:VETree) + call self.tree.init() + call self.tree.openPath(a:path) +endfunction + +function! s:VETreePanel.setFocus() + let VETreeWinNr = bufwinnr(self.name) + if VETreeWinNr != -1 + exec VETreeWinNr . " wincmd w" + return 1 + else + let bufNr = bufnr(self.name) + if bufNr != -1 + exec "bwipeout " . bufNr + endif + return 0 + endif +endfunction + +"Sync the tree with filesystem and refresh the tree panel +function! s:VETreePanel.refresh() + if !self.setFocus() + return + endif + call self.tree.update(self.path) + call self.drawTree() +endfunction + +"Draw the dir tree but do not sync the tree with filesystem +function! s:VETreePanel.drawTree() + if !self.setFocus() + return + endif + if !empty(self.tree.content) + call remove(self.tree.content,0,-1) + endif + call add(self.tree.content,[hostname() . " (Press ? for help)",""]) + call self.tree.draw() + let tree = [] + let lineNr = line(".") + for i in self.tree.content + if i[1] == self.path + let i[0] = i[0] . " [current]" + let lineNr = index(self.tree.content,i) + 1 + endif + call add(tree,i[0]) + endfor + setlocal noreadonly + setlocal modifiable + "Let the cursor go back to right line and right position in + "the screen. + normal! H + let Hline = line(".") + silent normal! ggdG + call append(0,tree) + silent normal! Gddgg + exec "normal! " . Hline . "G" + normal! zt + exec "normal! " . lineNr . "G" + setlocal readonly + setlocal nomodifiable +endfunction + +"Show tree panel +function! s:VETreePanel.show() + if self.setFocus() + return + endif + let cmd = self.splitLocation . " " . self.splitMode . ' ' . self.width . ' new ' . self.name + silent! execute cmd + let VETreeWinNr = bufwinnr(self.name) + if VETreeWinNr != -1 + exec VETreeWinNr . " wincmd w" + setlocal winfixwidth + setlocal noswapfile + setlocal buftype=nowrite + setlocal bufhidden=delete + setlocal nowrap + setlocal foldcolumn=0 + setlocal nobuflisted + setlocal nospell + setlocal nonumber + setlocal cursorline + setlocal readonly + setlocal nomodifiable + "call self.refresh() + call self.drawTree() + call self.createActions() + call self.createSyntax() + else + echoerr "create tree window failed!" + endif +endfunction + +"Hide tree panel +function! s:VETreePanel.hide() + if !self.setFocus() + return + else + "make sure there are no more than 1 buffer has the same name + let bufNr = bufnr('%') + "exec "wincmd c" + quit + exec "bwipeout ".bufNr + endif +endfunction + +function! s:VETreePanel.getPathUnderCursor(num) + return self.tree.content[a:num][1] +endfunction + +function! s:VETreePanel.nodeClicked(num) + if self.tree.content[a:num][1] == "" + return + endif + let path = self.tree.content[a:num][1] + if self.path != path + "let self.path = path + call VE_GotoPath(path) + "Do not toggle if it is the first time switch to another tree node. + call self.setFocus() + return + endif + call self.tree.togglePath(path) + call self.drawTree() +endfunction + +function! s:VETreePanel.pathChanged(path) + if self.path == a:path + return + endif + call g:VEPlatform.cdToPath(a:path) + let self.path = g:VEPlatform.getcwd() + call self.tree.openPath(self.path) + call self.drawTree() +endfunction + +function! s:VETreePanel.createActions() + exec "nnoremap " . g:VEConf.treePanelHotkey.help . " :tab h VimExplorer" + exec "nnoremap " . g:VEConf.treePanelHotkey.toggleNode . " :call VE_OnTreeNodeClick()" + exec "nnoremap " . g:VEConf.treePanelHotkey.toggleNodeMouse. " :call VE_OnTreeNodeClick()" + exec "nnoremap " . g:VEConf.treePanelHotkey.refresh . " :call VE_TreeRefresh()" + exec "nnoremap " . g:VEConf.treePanelHotkey.toggleFilePanel ." :call VE_ToggleFilePanel()" + exec "nnoremap " . g:VEConf.treePanelHotkey.toUpperDir . " :call VE_ToUpperDir()" + exec "nnoremap " . g:VEConf.treePanelHotkey.switchPanel . " " + exec "nnoremap " . g:VEConf.treePanelHotkey.favorite . " :call VE_GotoFavorite()" + exec "nnoremap " . g:VEConf.treePanelHotkey.addToFavorite . " :call VE_AddToFavorite('treePanel')" + exec "nnoremap " . g:VEConf.treePanelHotkey.browseHistory . " :call VE_BrowseHistory()" + exec "nnoremap " . g:VEConf.treePanelHotkey.gotoPath . " :call VE_OpenPath()" + exec "nnoremap " . g:VEConf.treePanelHotkey.quitVE . " :call VEDestroy()" + " autocmd + au! * + au BufEnter call VE_SyncDir() + " Status line + setlocal statusline=%{getcwd()} +endfunction + +function! s:VETreePanel.createSyntax() + if !self.setFocus() + return + endif + call g:VEConf.treePanelSyntax() +endfunction + + +" class VEFilePanel {{{1 +"============================= +let s:VEFilePanel = {} +let s:VEFilePanel.fileList = [] +let s:VEFilePanel.displayList = [] +" displayList [ +" [ "display name", "real path" ], +" ... +" ] +let s:VEFilePanel.selectedFiles = [] +let s:VEFilePanel.leavePosition = {} +let s:VEFilePanel.name = '' +let s:VEFilePanel.path = '' +let s:VEFilePanel.width = 0 +let s:VEFilePanel.splitMode = "" +let s:VEFilePanel.splitLocation = "" + +function! s:VEFilePanel.init(name,path) + let self.name = "VEFilePanel".a:name + let self.path = a:path + let self.splitMode = g:VEConf.filePanelSplitMode + let self.splitLocation = g:VEConf.filePanelSplitLocation + let self.width = g:VEConf.filePanelWidth +endfunction + +function! s:VEFilePanel.show() + if self.setFocus() + return + endif + let cmd = self.splitLocation . " " . self.splitMode . ' ' . self.width . ' new ' . self.name + silent! exec cmd + if !self.setFocus() + echoerr "create file window failed!" + endif + setlocal winfixwidth + setlocal noswapfile + setlocal buftype=nowrite + setlocal bufhidden=delete + setlocal nowrap + setlocal foldcolumn=0 + setlocal nobuflisted + setlocal nospell + setlocal nonumber + setlocal cursorline + setlocal readonly + setlocal nomodifiable + setlocal tabstop=40 + "This is used to display file list more orderliness. + call self.refresh() + call self.createActions() + call self.createSyntax() +endfunction + +function! s:VEFilePanel.only() + if !self.setFocus() + return + endif + only +endfunction + +function! s:VEFilePanel.hide() + if !self.setFocus() + return + else + let bufNr = bufnr('%') + exec "wincmd c" + exec "bwipeout ".bufNr + endif +endfunction + +function! s:VEFilePanel.refresh() + call self.getFileListFromCwd() + call self.updateDisplayList() + call self.drawList() +endfunction + +"Draw the displayList on the screen. +function! s:VEFilePanel.drawList() + if !self.setFocus() + return + endif + "calculate window width + let VEFileWinNr = bufwinnr(self.name) + let winWidth = winwidth(VEFileWinNr) + exec "setlocal tabstop=" . ((winWidth-41)<20?20:(winWidth-41)) + setlocal noreadonly + setlocal modifiable + let curLine = line(".") + normal! H + let Hline = line(".") + silent normal! ggdG + let displayContent = [] + for i in self.displayList "here i is reference,not copy + if index(self.selectedFiles,i[1]) != -1 + let tmpi = '*' . substitute(i[0],'^.','','g') + else + let tmpi = i[0] + endif + call add(displayContent,tmpi) + endfor + call append(0,displayContent) + normal! Gddgg + exec "normal! " . Hline . "G" + normal! zt + exec "normal! " . curLine . "G" + setlocal readonly + setlocal nomodifiable +endfunction + +"Update the displayList. +function! s:VEFilePanel.updateDisplayList() + if g:VEConf.filePanelSortType == 1 + call self.sortByName() + elseif g:VEConf.filePanelSortType == 2 + call self.sortByTime() + else + call self.sortByType() + endif +endfunction + +function! s:VEFilePanel.toggleModes() + if g:VEConf.filePanelSortType < 2 + let g:VEConf.filePanelSortType = g:VEConf.filePanelSortType + 1 + else + let g:VEConf.filePanelSortType = 0 + endif + call self.updateDisplayList() + call self.drawList() +endfunction + +function! s:VEFilePanel.getFileListFromCwd() + let self.fileList = split(g:VEPlatform.globpath_file(self.path),"\n") +endfunction + +" 1 +function! s:VEFilePanel.sortByName() + let fileGroup = {} + " example + " { + " "name" : "path" + " } + for i in self.fileList + if g:VEPlatform.haswin32() && !&ssl + let name = matchstr(i,'[^\\]*$','','g') + else + let name = matchstr(i,'[^/]*$','','g') + endif + if isdirectory(i) + if g:VEPlatform.haswin32() && !&ssl + if i[-1:] != "\\" + let i = i . "\\" + endif + else + if i[-1:] != "/" + let i = i . "/" + endif + endif + " add # before directory to sort separately. + let name = '#' . name + endif + let fileGroup[name] = i + endfor + let keys = sort(keys(fileGroup),"VEPlatform_sortCompare") + if !g:VEConf.fileGroupSortDirection + call reverse(keys) + endif + let self.displayList = [] + call add(self.displayList,["Path: ".self.path,'']) + call add(self.displayList,[repeat("~",100),'']) + call add(self.displayList,['[ Sort by name ]','']) + for i in keys + call add(self.displayList,[" " . g:VEPlatform.pathToName(fileGroup[i]),fileGroup[i]]) + endfor +endfunction + +" 2 +function! s:VEFilePanel.sortByTime() + let fileGroup = {} + " example + " { + " "name" : "path" + " } + for i in self.fileList + let time = strftime("%Y-%m-%d %H:%M:%S",getftime(i)) + let time = time . i "let the key of dict unique + if isdirectory(i) + if g:VEPlatform.haswin32() && !&ssl + if i[-1:] != "\\" + let i = i . "\\" + endif + else + if i[-1:] != "/" + let i = i . "/" + endif + endif + endif + let fileGroup[time] = i + endfor + let keys = sort(keys(fileGroup),"VEPlatform_sortCompare") + if !g:VEConf.fileGroupSortDirection + call reverse(keys) + endif + let self.displayList = [] + call add(self.displayList,["Path: ".self.path,'']) + call add(self.displayList,[repeat("~",100),'']) + call add(self.displayList,['[ Sort by time ]','']) + for i in keys + call add(self.displayList,[" " . g:VEPlatform.pathToName(fileGroup[i]),fileGroup[i]]) + endfor +endfunction + +" 3 not implemented yet +"function! s:VEFilePanel.sortBySize() +" let fileGroup = {} +" " example +" " { +" " "name" : "path" +" " } +" for i in self.fileList +" let time = strftime("%Y-%m-%d %H:%M:%S",getftime(i)) +" let time = time . i "let the key of dict unique +" if isdirectory(i) +" " add # before directory to sort separately. +" " need?? +" "let time = '#' . time +" if i[-1:] != "\\" +" let i = i . "\\" +" endif +" endif +" let fileGroup[time] = i +" endfor +" let keys = sort(keys(fileGroup)) +" if !g:VEConf.fileGroupSortDirection +" call reverse(keys) +" endif +" let self.displayList = [] +" call add(self.displayList,["Path: ".self.path,'']) +" call add(self.displayList,[repeat("~",100),'']) +" call add(self.displayList,['[ Sort by time ]','']) +" for i in keys +" call add(self.displayList,[" " . g:VEPlatform.pathToName(fileGroup[i]),fileGroup[i]]) +" endfor +"endfunction + +" 0 +function! s:VEFilePanel.sortByType() + let fileGroup = {} + " example + " { + " "directory" : [ + " "c:\\aaa\\", + " "c:\\bbb\\" + " ] + " "txt" : [ + " "c:\\mm.txt", + " "c:\\nn.txt" + " ] + " } + for i in self.fileList + " i ("c:\\ddd\\eee.fff") + if isdirectory(i) + "if the group dos not exist,create it first + if !has_key(fileGroup,'#Directory') "assert file name does not contain '#' + let fileGroup['#Directory'] = [] + endif + if g:VEPlatform.haswin32() && !&ssl + if i[-1:] != "\\" + let i = i . "\\" + endif + else + if i[-1:] != "/" + let i = i . "/" + endif + endif + call add(fileGroup['#Directory'],i) + continue + endif + if g:VEPlatform.haswin32() && !&ssl + let matchStr = '\\\.[^\\]\+$' + else + let matchStr = '\/\.[^/]\+$' + endif + if matchstr(i,matchStr) != '' + if !has_key(fileGroup,'#Hidden files') + let fileGroup['#Hidden files'] = [] + endif + call add(fileGroup['#Hidden files'],i) + continue + endif + if g:VEPlatform.haswin32() && !&ssl + let fileExtension = matchstr(substitute(i,'^.*\\','','g'),'\.[^.]\{-}$') + else + let fileExtension = matchstr(substitute(i,'^.*\/','','g'),'\.[^.]\{-}$') + endif + if fileExtension == '' "files have no extensions + if !has_key(fileGroup,'#Files') + let fileGroup['#Files'] = [] + endif + call add(fileGroup['#Files'],i) + continue + else "group the file by it's ext.name + " # is always smaller than $ + " so it can keep dir in the top + if !has_key(fileGroup,"$".fileExtension) + let fileGroup["$".fileExtension] = [] + endif + call add(fileGroup["$".fileExtension],i) + endif + endfor + "update self.displayList + let self.displayList = [] + call add(self.displayList,["Path: ".self.path,'']) + call add(self.displayList,[repeat("~",100),'']) + let keys = sort(keys(fileGroup),"VEPlatform_sortCompare") + if !g:VEConf.fileGroupSortDirection + call reverse(keys) + endif + for i in keys + call add(self.displayList,['[ '.i[1:].' ]','']) + call sort(fileGroup[i],"VEPlatform_sortCompare") + if !g:VEConf.fileGroupSortDirection + call reverse(fileGroup[i]) + endif + for j in fileGroup[i] + call add(self.displayList,[" " . g:VEPlatform.pathToName(j),j]) + endfor + call add(self.displayList,[" ",'']) + endfor + if self.displayList[-1][0] == " " + call remove(self.displayList,-1) "remove last empty line + endif +endfunction + +function! s:VEFilePanel.pathChanged(path) + call self.setFocus() + if self.path == a:path + return + endif + "store the current mouse position. + let linePos = line('.') + normal! H + let topPos = line('.') + let self.leavePosition[self.path] = [topPos,linePos] + " + call g:VEPlatform.cdToPath(a:path) + let self.selectedFiles = [] "clear the selectedFile list + let self.path = g:VEPlatform.getcwd() + call self.refresh() + "restore position + if has_key(self.leavePosition,self.path) + exec "normal! " . self.leavePosition[self.path][0] . "G" + normal! zt + exec "normal! " . self.leavePosition[self.path][1] . "G" + else + normal! ggM + if line('.') < 4 "put the cursor to first dir. + normal! 4G + endif + endif +endfunction + +function! s:VEFilePanel.setFocus() + let VEFileWinNr = bufwinnr(self.name) + if VEFileWinNr != -1 + exec VEFileWinNr . " wincmd w" + return 1 + else + "If the window of buffer was closed by hand and the + "buffer still in buffer list, wipeout it. + "In case of bufnr() returns empty when there are two + "buffers have the same name. + let bufNr = bufnr(self.name) + if bufNr != -1 + exec "bwipeout " . bufNr + endif + return 0 + endif +endfunction + +function! s:VEFilePanel.itemClicked(line) + let path = self.displayList[a:line][1] + if path == '' + return + endif + if isdirectory(path) + call VE_GotoPath(path) + call self.setFocus() + return + else + call g:VEPlatform.start(path) + endif +endfunction + +function! s:VEFilePanel.itemPreview(line) + let path = self.displayList[a:line][1] + if path == '' + return + endif + exec g:VEConf.previewSplitLocation . " pedit " . g:VEPlatform.escape(path) +endfunction + +function! s:VEFilePanel.singleFileAction(line,actionName) + let path = self.displayList[a:line][1] + if path == '' + return + endif + call g:VEConf_singleFileActions[a:actionName](path) +endfunction + +function! s:VEFilePanel.normalAction(actionName) + call g:VEConf_normalActions[a:actionName]() +endfunction + +function! s:VEFilePanel.multiAction(actionName) + call g:VEConf_multiFileActions[a:actionName](self.selectedFiles) +endfunction + +function! s:VEFilePanel.deleteSingle(line,bForce) + let path = self.displayList[a:line][1] + if path == '' + return + endif + if g:VEPlatform.deleteSingle(path,a:bForce) + if index(self.selectedFiles,path) != -1 + call remove(self.selectedFiles,index(self.selectedFiles,path)) + endif + call self.refresh() + endif +endfunction + +function! s:VEFilePanel.deleteSelectedFiles(bForce) + if empty(self.selectedFiles) + return + endif + if g:VEPlatform.deleteMultiple(self.selectedFiles,a:bForce) + let self.selectedFiles = [] + call self.refresh() + endif +endfunction + +function! s:VEFilePanel.toggleSelect(direction) + if a:direction == "up" + exec "norm " . "\" + endif + let line = line(".") - 1 + let path = self.displayList[line][1] + if path != '' + let idx = index(self.selectedFiles,path) + if idx == -1 + call add(self.selectedFiles,path) + else + call remove(self.selectedFiles,idx) + endif + call self.drawList() + endif + if a:direction == "down" + exec "norm " . "\" + endif +endfunction! + +function! s:VEFilePanel.clearSelect() + let self.selectedFiles = [] + call self.drawList() +endfunction + +function! s:VEFilePanel.visualSelect(firstLine,lastLine) + for line in range(a:firstLine,(a:lastLine>=len(self.displayList)?(len(self.displayList)-1):a:lastLine)) + let path = self.displayList[line][1] + if path == '' + continue + endif + let idx = index(self.selectedFiles,path) + if idx == -1 + call add(self.selectedFiles,path) + else + call remove(self.selectedFiles,idx) + endif + endfor + call self.drawList() +endfunction + +function! s:VEFilePanel.visualDelete(firstLine,lastLine,bForce) + let displayList = [] + for line in range(a:firstLine,(a:lastLine>=len(self.displayList)?(len(self.displayList)-1):a:lastLine)) + let path = self.displayList[line][1] + if path == '' + continue + endif + call add(displayList,path) + endfor + if empty(displayList) + return + endif + if g:VEPlatform.deleteMultiple(displayList,a:bForce) + call self.refresh() + endif +endfunction + +function! s:VEFilePanel.visualYank(firstLine,lastLine,mode) + let displayList = [] + for line in range(a:firstLine,(a:lastLine>=len(self.displayList)?(len(self.displayList)-1):a:lastLine)) + let path = self.displayList[line][1] + if path == '' + continue + endif + call add(displayList,path) + endfor + if empty(displayList) + return + endif + let winName = matchstr(bufname("%"),'_[^_]*$') + let s:VEContainer.yankMode = a:mode + let s:VEContainer.clipboard = displayList + call s:VEContainer.showClipboard() +endfunction + +function! s:VEFilePanel.yankSingle(mode) + let line = line(".") - 1 + let path = self.displayList[line][1] + if path != '' + let s:VEContainer.yankMode = a:mode + let s:VEContainer.clipboard = [] + call add(s:VEContainer.clipboard,path) + endif + call s:VEContainer.showClipboard() +endfunction + +function! s:VEFilePanel.paste() + if s:VEContainer.yankMode == '' || s:VEContainer.clipboard == [] + return + endif + let retList = g:VEPlatform.copyMultiFile(s:VEContainer.clipboard,self.path) + if s:VEContainer.yankMode == 'cut' && len(retList) != 0 + "let tmpRec = g:VEConf.recyclePath " save recycle path + "let g:VEConf.recyclePath = '' + for i in retList + call g:VEPlatform.delete(i,1) "force delete + endfor + "let g:VEConf.recyclePath = tmpRec + let s:VEContainer.yankMode = '' + let s:VEContainer.clipboard = [] + endif + "if s:VEContainer.yankMode == 'cut' + " call g:VEPlatform.copyMultiFile(s:VEContainer.clipboard,self.path,1) + "else + " call g:VEPlatform.copyMultiFile(s:VEContainer.clipboard,self.path,0) + "endif + let s:VEContainer.yankMode = '' + let s:VEContainer.clipboard = [] + call self.refresh() + "call s:VEContainer.showClipboard() +endfunction! + +function! s:VEFilePanel.markViaRegexp(regexp) + if a:regexp == '' + echohl Special + let regexp = input("Mark files (regexp): ") + echohl None + else + let regexp = a:regexp + endif + let self.selectedFiles = [] + for i in self.displayList + if g:VEPlatform.haswin32() && !&ssl + let name = matchstr(i[1],'[^\\]*.$','','g') + else + let name = matchstr(i[1],'[^/]*.$','','g') + endif + if matchstr(name,regexp) != '' + call add(self.selectedFiles,i[1]) + endif + endfor + call self.drawList() +endfunction + +function! s:VEFilePanel.markExecutable() + let self.selectedFiles = [] + for i in self.displayList + if g:VEPlatform.executable(i[1]) + call add(self.selectedFiles,i[1]) + endif + endfor + call self.drawList() +endfunction + +function! s:VEFilePanel.newFile() + echohl Special + let filename = input("Create file : ",self.path,"file") + echohl None + if filename == '' + echo " " + return + endif + if g:VEPlatform.mkfile(filename) + echohl Special | echomsg "OK" | echohl None + call self.refresh() + else + echohl ErrorMsg | echomsg "Can not create file!" | echohl None + endif +endfunction + +function! s:VEFilePanel.newDirectory() + if !exists("*mkdir") + echoerr "mkdir feature not found!" + endif + echohl Special + let dirname = input("Create directory : ",self.path,"file") + echohl None + if dirname == '' + echo " " + return + endif + if findfile(dirname) == '' && g:VEPlatform.mkdir(dirname) + echohl Special | echomsg "OK" | echohl None + call self.refresh() + else + echohl ErrorMsg | echomsg "Can not create directory!" | echohl None + endif +endfunction + +function! s:VEFilePanel.rename(line) + let path = self.displayList[a:line][1] + if path == '' + return + endif + echohl Special + let name = input("Rename to: ",path,"file") + echohl None + if name == '' + echo " " + return + endif + if findfile(name) != '' + echohl ErrorMsg | echomsg "File exists!" | echohl None + return + endif + if rename(path,name) == 0 + echohl Special | echomsg "OK" | echohl None + call self.refresh() + else + echohl ErrorMsg | echomsg "Can not rename!" | echohl None + endif +endfunction + +function! s:VEFilePanel.search() + echohl Special + let filename = input("Search : ") + echohl None + if filename == '' + echo " " + return + endif + echohl Special | echomsg "Searching [" . filename . "] in " . self.path . ", please wait...(Ctrl-C to break)" | echohl None + let self.fileList = g:VEPlatform.search(filename,self.path) + call self.updateDisplayList() + call self.drawList() +endfunction + +function! s:VEFilePanel.statusFileName() + let line = line(".") - 1 + let fname = self.displayList[line][1] + "let fname = substitute(fname,self.path,'','g') + let fname = fname[len(self.path):] + return fname +endfunction + +function! s:VEFilePanel.createActions() + exec "nnoremap " . g:VEConf.filePanelHotkey.help . " :tab h VimExplorer" + exec "nnoremap " . g:VEConf.filePanelHotkey.switchPanel . " " + exec "nnoremap " . g:VEConf.filePanelHotkey.itemClicked . " :call VE_OnFileItemClick()" + exec "nnoremap " . g:VEConf.filePanelHotkey.itemClickMouse. " :call VE_OnFileItemClick()" + exec "nnoremap " . g:VEConf.filePanelHotkey.toggleTreePanel ." :call VE_ToggleTreePanel()" + exec "nnoremap " . g:VEConf.filePanelHotkey.toUpperDir . " :call VE_ToUpperDir()" + exec "nnoremap " . g:VEConf.filePanelHotkey.gotoForward . " :call VE_GotoForward()" + exec "nnoremap " . g:VEConf.filePanelHotkey.gotoBackward . " :call VE_GotoBackward()" + exec "nnoremap " . g:VEConf.filePanelHotkey.openPreview . " :call VE_OnFileOpenPreview()" + exec "nnoremap " . g:VEConf.filePanelHotkey.closePreview . " :call VE_ClosePreviewPanel()" + exec "nnoremap " . g:VEConf.filePanelHotkey.deleteSingle . " :call VE_DeleteSingle(0)" + exec "nnoremap " . g:VEConf.filePanelHotkey.deleteSingleF. " :call VE_DeleteSingle(1)" + exec "nnoremap " . g:VEConf.filePanelHotkey.rename . " :call VE_Rename()" + exec "nnoremap " . g:VEConf.filePanelHotkey.refresh . " :call VE_RefreshFilePanel()" + exec "nnoremap " . g:VEConf.filePanelHotkey.toggleSelectUp ." :call VE_ToggleSelectFile(\"up\")" + exec "nnoremap " . g:VEConf.filePanelHotkey.toggleSelectDown." :call VE_ToggleSelectFile(\"down\")" + exec "nnoremap " . g:VEConf.filePanelHotkey.clearSelect . " :call VE_ClearSelectFile()" + exec "nnoremap " . g:VEConf.filePanelHotkey.deleteSelected . " :call VE_DeleteSelectedFiles(0)" + exec "nnoremap " . g:VEConf.filePanelHotkey.deleteSelectedF. " :call VE_DeleteSelectedFiles(1)" + exec "nnoremap " . g:VEConf.filePanelHotkey.yankSelected . " :call VE_YankSelectedFiles(\"copy\")" + exec "nnoremap " . g:VEConf.filePanelHotkey.cutSelected . " :call VE_YankSelectedFiles(\"cut\")" + exec "nnoremap " . g:VEConf.filePanelHotkey.yankSingle . " :call VE_YankSingle(\"copy\")" + exec "nnoremap " . g:VEConf.filePanelHotkey.cutSingle . " :call VE_YankSingle(\"cut\")" + exec "nnoremap " . g:VEConf.filePanelHotkey.showYankList . " :call VE_ShowYankList()" + exec "nnoremap " . g:VEConf.filePanelHotkey.toggleModes . " :call VE_ToggleModes()" + exec "nnoremap " . g:VEConf.filePanelHotkey.paste . " :call VE_Paste()" + exec "nnoremap " . g:VEConf.filePanelHotkey.markViaRegexp . " :call VE_MarkViaRegexp('')" + exec "nnoremap " . g:VEConf.filePanelHotkey.markExecutable . " :call VE_MarkExecutable()" + exec "nnoremap " . g:VEConf.filePanelHotkey.markVimFiles . " :call VE_MarkViaRegexp('.*.vim$')" + exec "nnoremap " . g:VEConf.filePanelHotkey.markDirectory . " :call VE_MarkViaRegexp('.*[\\/]$')" + exec "nnoremap " . g:VEConf.filePanelHotkey.newFile . " :call VE_NewFile()" + exec "nnoremap " . g:VEConf.filePanelHotkey.newDirectory . " :call VE_NewDirectory()" + exec "nnoremap " . g:VEConf.filePanelHotkey.markViaRegexp . " :call VE_MarkViaRegexp('')" + exec "nnoremap " . g:VEConf.filePanelHotkey.favorite . " :call VE_GotoFavorite()" + exec "nnoremap " . g:VEConf.filePanelHotkey.addToFavorite . " :call VE_AddToFavorite('filePanel')" + exec "nnoremap " . g:VEConf.filePanelHotkey.browseHistory . " :call VE_BrowseHistory()" + exec "nnoremap " . g:VEConf.filePanelHotkey.gotoPath . " :call VE_OpenPath()" + exec "nnoremap " . g:VEConf.filePanelHotkey.diff2files . " :call VE_Diff()" + exec "nnoremap " . g:VEConf.filePanelHotkey.quitVE . " :call VEDestroy()" + exec "nnoremap " . g:VEConf.filePanelHotkey.toggleHidden . " :call VE_ToggleHidden()" + exec "nnoremap " . g:VEConf.filePanelHotkey.search . " :call VE_FileSearch()" + exec "nnoremap " . g:VEConf.filePanelHotkey.toggleSelMouse . " :call VE_ToggleSelectFile(\"\")" + exec "nnoremap " . g:VEConf.filePanelHotkey.contextMenuN . " :popup ]FilePanelPopup" + + let letter = char2nr('a') + while letter <= char2nr('z') + exec "nnoremap " . g:VEConf.filePanelHotkey.markPlace . nr2char(letter) . + \" :call VE_MarkPlace(\"" . nr2char(letter) . "\")" + exec "nnoremap " . g:VEConf.filePanelHotkey.gotoPlace . nr2char(letter) . + \" :call VE_MarkSwitchTo(\"" . nr2char(letter) . "\")" + let letter = letter + 1 + endwhile + exec "nnoremap " . g:VEConf.filePanelHotkey.viewMarks . " :call VE_MarkList()" + + " visual mode map + exec "vnoremap " . g:VEConf.filePanelHotkey.visualSelect . " :call VE_VisualSelect()" + exec "vnoremap " . g:VEConf.filePanelHotkey.visualDelete . " :call VE_VisualDelete(0)" + exec "vnoremap " . g:VEConf.filePanelHotkey.visualDeleteF. " :call VE_VisualDelete(1)" + exec "vnoremap " . g:VEConf.filePanelHotkey.visualYank . " :call VE_VisualYank(\"copy\")" + exec "vnoremap " . g:VEConf.filePanelHotkey.visualCut . " :call VE_VisualYank(\"cut\")" + + " User defined map + for i in keys(g:VEConf_normalHotKeys) + exec "nnoremap " . g:VEConf_normalHotKeys[i] . + \" :call VE_NormalAction(\"" . i . "\")" + endfor + for i in keys(g:VEConf_singleFileHotKeys) + exec "nnoremap " . g:VEConf_singleFileHotKeys[i] . + \" :call VE_SingleFileAction(\"" . i . "\")" + endfor + for i in keys(g:VEConf_multiFileHotKeys) + exec "nnoremap " . g:VEConf_multiFileHotKeys[i] . + \" :call VE_MultiFileAction(\"" . i . "\")" + endfor + " Auto commands + au! * + au BufEnter call VE_SyncDir() + " Status line + setlocal statusline=%{VE_GetStatusFileName()}%=[%{getcwd()}]\ %{strftime(\"\%Y-\%m-\%d\ \%H:\%M\")} +endfunction + +function! s:VEFilePanel.createSyntax() + let VEFileWinNr = bufwinnr(self.name) + if VEFileWinNr != -1 + exec VEFileWinNr . " wincmd w" + else + return + endif + call g:VEConf.filePanelSyntax() +endfunction + +function! s:VEFilePanel.getPathUnderCursor(num) + return self.displayList[a:num][1] +endfunction + +" class VEPreviewPanel {{{1 +"============================= +"let s:VEPreviewPanel = {} +"let s:VEPreviewPanel.name = '' +"let s:VEPreviewPanel.width = 0 +"let s:VEPreviewPanel.splitMode = '' +"let s:VEPreviewPanel.splitLocation = '' +" +"function! s:VEPreviewPanel.init(name) +" let self.name = "VEPreviewPanel" . a:name +" let self.width = g:VEConf.previewPanelWidth +" let self.splitMode = g:VEConf.previewPanelSplitMode +" let self.splitLocation = g:VEConf.previewPanelSplitLocation +"endfunction + +"function! s:VEPreviewPanel.show() +" if self.setFocus() +" return +" endif +" let cmd = self.splitLocation . " " . self.splitMode . self.width . ' new ' +" exec cmd +" if !self.setFocus() +" echoerr "create file window failed!" +" else +" edit self.name +" endif +"endfunction + +"function! s:VEPreviewPanel.setFocus() +" let VEPreviewWinNr = bufwinnr(self.name) +" if VEPreviewWinNr != -1 +" exec VEPreviewWinNr . " wincmd w" +" return 1 +" else +" "If the window of buffer was closed by hand and the +" "buffer still in buffer list, wipeout it. +" "In case of bufnr() returns empty when there are two +" "buffers have the same name. +" let bufNr = bufnr(self.name) +" if bufNr != -1 +" exec "bwipeout " . bufNr +" endif +" return 0 +" endif +"endfunction +" +"function! s:VEPreviewPanel.hide() +" if !self.setFocus() +" return +" else +" let bufNr = bufnr('%') +"" exec "wincmd c" +" exec "bwipeout ".bufNr +" endif +"endfunction +" +"function! s:VEPreviewPanel.preview(path) +" if !self.setFocus() +" let self.name = a:path +" let cmd = self.splitLocation . " " . self.splitMode . self.width . ' new' +" exec cmd +" exec "edit " . self.name +" return +" else +" let self.name = a:path +" exec "edit " . self.name +" endif +"endfunction + + + +" class VEFrameWork {{{1 +"============================= +let s:VEFrameWork = {} +let s:VEFrameWork.name = '' +let s:VEFrameWork.treePanel = {} +let s:VEFrameWork.filePanel = {} +"let s:VEFrameWork.previewPanel = {} +let s:VEFrameWork.pathHistory = [] +let s:VEFrameWork.pathPosition = -1 + +"Object Constructor +function! s:VEFrameWork.init(name,path) + let self.name = "VEFrameWork".a:name + let self.filePanel = deepcopy(s:VEFilePanel) + let self.treePanel = deepcopy(s:VETreePanel) + "let self.previewPanel = deepcopy(s:VEPreviewPanel) + call self.filePanel.init(a:name,a:path) + call self.treePanel.init(a:name,a:path) + "call self.previewPanel.init(a:name) + call add(self.pathHistory,a:path) + let self.pathPosition += 1 +endfunction + +function! s:VEFrameWork.show() + tabnew + call self.filePanel.show() + call self.filePanel.only() "so,here it means filePanel should be displayed first + call self.treePanel.show() + call self.filePanel.setFocus() + call self.filePanel.refresh() + normal! M +endfunction + +"Switch to another path, it will change the forward/backward +"history. +function! s:VEFrameWork.gotoPath(path) + call self.treePanel.pathChanged(a:path) + call self.filePanel.pathChanged(a:path) + if len(self.pathHistory) > self.pathPosition+1 + call remove(self.pathHistory,self.pathPosition+1,-1) + endif + call add(self.pathHistory,a:path) + if len(self.pathHistory) > g:VEConf.browseHistory + call remove(self.pathHistory,0) + else + let self.pathPosition += 1 + endif +endfunction + +"Forward and backward +function! s:VEFrameWork.gotoForward() + if self.pathPosition >= len(self.pathHistory) || + \ self.pathPosition < 0 || + \ empty(self.pathHistory) + return + endif + if self.pathPosition+1 == len(self.pathHistory) "Can not forward + return + endif + let self.pathPosition += 1 + "Do not call VE_GotoPath here! It will change pathHistory. + "Call the follows instead. + call self.treePanel.pathChanged(self.pathHistory[self.pathPosition]) + call self.filePanel.pathChanged(self.pathHistory[self.pathPosition]) +endfunction + +function! s:VEFrameWork.gotoBackward() + if self.pathPosition >= len(self.pathHistory) || + \ self.pathPosition < 0 || + \ empty(self.pathHistory) + return + endif + if self.pathPosition == 0 "Can not go back. + return + endif + let self.pathPosition -= 1 + "Do not call VE_GotoPath here! It will change pathHistory. + "Call the follows instead. + call self.treePanel.pathChanged(self.pathHistory[self.pathPosition]) + call self.filePanel.pathChanged(self.pathHistory[self.pathPosition]) +endfunction + +"Object destructor +function! s:VEFrameWork.destroy() + call self.filePanel.hide() + call self.treePanel.hide() +endfunction + + + + + + +"#################################################### +"global variables and functions {{{1 + +let s:VEContainer = {} "contains all VEFrameWorks +let s:VEContainer.clipboard = [] "shared clipboard +let s:VEContainer.yankMode = '' "cut or yank +let s:VEContainer.markPlaces = {} + +function! s:VECreatePopMenu() + silent! unmenu ]FilePanelPopup + menu ]FilePanelPopup.&Open :call VE_OnFileItemClick() + menu ]FilePanelPopup.-sep0- : + menu ]FilePanelPopup.&Copy :call VE_YankSingle("copy") + menu ]FilePanelPopup.C&ut :call VE_YankSingle("cut") + menu ]FilePanelPopup.-sep1- : + menu ]FilePanelPopup.&Rename :call VE_Rename() + menu ]FilePanelPopup.&Delete :call VE_DeleteSingle(0) + menu ]FilePanelPopup.Pre&view :call VE_OnFileOpenPreview() + menu ]FilePanelPopup.&Mark :call VE_ToggleSelectFile("") + menu ]FilePanelPopup.-sep2- : + menu ]FilePanelPopup.&Paste :call VE_Paste() + menu ]FilePanelPopup.&New.&File :call VE_NewFile() + menu ]FilePanelPopup.&New.&Directory :call VE_NewDirectory() + menu ]FilePanelPopup.-sep3- : + menu ]FilePanelPopup.Re&fresh :call VE_RefreshFilePanel() +endfunction + +function! VENew(path) + call s:VECreatePopMenu() + let frameName = '_' . substitute(reltimestr(reltime()),'\.','','g') + if a:path == '' + echohl Special + let workPath = input("VimExplorer (directory): ",g:VEPlatform.getcwd(),"file") + echohl None + if workPath == '' + return + endif + else + let workPath = a:path + endif + call g:VEPlatform.cdToPath(workPath) + let workPath = g:VEPlatform.getcwd() "Conversions capitalisations + "does not work here. + if !isdirectory(workPath) + echohl ErrorMsg | echomsg "Directory not exist!" | echohl None + return + endif + let s:VEContainer[frameName] = deepcopy(s:VEFrameWork) + call s:VEContainer[frameName].init(frameName,workPath) + call s:VEContainer[frameName].show() + let letter = char2nr('a') + while letter <= char2nr('z') + let s:VEContainer.markPlaces[nr2char(letter)] = '' + let letter = letter + 1 + endwhile +endfunction + +function! VEDestroy() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].destroy() + call remove(s:VEContainer,winName) + endif +endfunction + +function! s:VEContainer.showClipboard() + echohl Special + let msg = len(self.clipboard) . " files in clipboard, Mode: " . self.yankMode . ", " + let msg = msg . '(press ' . g:VEConf.filePanelHotkey.showYankList . ' to show file list)' + echomsg msg + echohl None +endfunction + +" Get path name under cursor +function! VE_getPathUnderCursor(where) + let winName = matchstr(bufname("%"),'_[^_]*$') + let path = '' + if has_key(s:VEContainer,winName) + if a:where == 'treePanel' + let path = s:VEContainer[winName].treePanel.getPathUnderCursor(line(".")-1) + elseif a:where == 'filePanel' + let path = s:VEContainer[winName].filePanel.getPathUnderCursor(line(".")-1) + endif + endif + + if !isdirectory(path) + return '' + else + return path + endif +endfunction + + +"Command handlers +"=================================== + +"TreePanel command handlers +"---------------------------- +"Node click event +function! VE_OnTreeNodeClick() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].treePanel.nodeClicked(line(".")-1) + endif +endfunction + +"Refresh tree command +function! VE_TreeRefresh() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].treePanel.refresh() + endif +endfunction + +"FilePanel command handlers +"---------------------------- +"Item click event. +function! VE_OnFileItemClick() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.itemClicked(line(".")-1) + endif +endfunction + +"Open preview. +function! VE_OnFileOpenPreview() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.itemPreview(line(".")-1) + endif +endfunction + +"Refresh the panel. +function! VE_RefreshFilePanel() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.refresh() + endif +endfunction + +"User defined single file actions. +function! VE_SingleFileAction(actionName) + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.singleFileAction((line(".")-1),a:actionName) + endif +endfunction + +"User defined normal actions. +function! VE_NormalAction(actionName) + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.normalAction(a:actionName) + endif +endfunction + +"Multiple file actions. +function! VE_MultiFileAction(actionName) + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.multiAction(a:actionName) + endif +endfunction + +"Delete single file or directory. +function! VE_DeleteSingle(bForce) + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.deleteSingle(line(".")-1,a:bForce) + endif +endfunction + +"Rename file or dir +function! VE_Rename() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.rename(line(".")-1) + endif +endfunction + +"Toggle select a file in file panel. +function! VE_ToggleSelectFile(direction) + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.toggleSelect(a:direction) + endif +endfunction + +"Clear selection. +function! VE_ClearSelectFile() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.clearSelect() + endif +endfunction + +"Toggle sort mode +function! VE_ToggleModes() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.toggleModes() + endif +endfunction + +"Mark via regexp +function! VE_MarkViaRegexp(regexp) + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.markViaRegexp(a:regexp) + endif +endfunction + +"Mark executable files. +function! VE_MarkExecutable() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.markExecutable() + endif +endfunction + +"create file +function! VE_NewFile() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.newFile() + endif +endfunction + +"create directory +function! VE_NewDirectory() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.newDirectory() + endif +endfunction + +"delete selected files. +function! VE_DeleteSelectedFiles(bForce) + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.deleteSelectedFiles(a:bForce) + endif +endfunction + +"delete selected files. +function! VE_YankSelectedFiles(mode) + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + let s:VEContainer.clipboard = s:VEContainer[winName].filePanel.selectedFiles + let s:VEContainer.yankMode = a:mode + endif + call s:VEContainer.showClipboard() +endfunction + +function! VE_YankSingle(mode) + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.yankSingle(a:mode) + endif +endfunction + +function! VE_Paste() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.paste() + endif +endfunction + +function! VE_FileSearch() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.search() + endif +endfunction + + +"visual mode functions. +"visual select +function! VE_VisualSelect() range + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.visualSelect(a:firstline-1,a:lastline-1) + endif +endfunction + +"visual delete +function! VE_VisualDelete(bForce) range + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.visualDelete(a:firstline-1,a:lastline-1,a:bForce) + endif +endfunction + +"visual yank +function! VE_VisualYank(mode) range + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].filePanel.visualYank(a:firstline-1,a:lastline-1,a:mode) + endif +endfunction + +function! VE_ShowYankList() + if s:VEContainer.clipboard == [] + return + endif + for i in s:VEContainer.clipboard + echo i + endfor +endfunction + +"Common command handlers +"-------------------------- +"get file name for status line. +function! VE_GetStatusFileName() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + return s:VEContainer[winName].filePanel.statusFileName() + else + return '' + endif +endfunction + +"mark palce +function! VE_MarkPlace(char) + let s:VEContainer.markPlaces[a:char] = g:VEPlatform.getcwd() +endfunction + +"goto marked place +function! VE_MarkSwitchTo(char) + call VE_GotoPath(s:VEContainer.markPlaces[a:char]) +endfunction + +function! VE_MarkList() + let list = [] + let letter = char2nr('a') + while letter <= char2nr('z') + if s:VEContainer.markPlaces[nr2char(letter)] != '' + echo nr2char(letter) . " " . s:VEContainer.markPlaces[nr2char(letter)] + endif + let letter = letter + 1 + endwhile +endfunction + +"Toggle tree panel. +function! VE_ToggleTreePanel() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + if s:VEContainer[winName].treePanel.setFocus() + call s:VEContainer[winName].treePanel.hide() + else + call s:VEContainer[winName].treePanel.show() + endif + endif + exec "wincmd p" +endfunction + +"Toggle file panel. +function! VE_ToggleFilePanel() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + if s:VEContainer[winName].filePanel.setFocus() + call s:VEContainer[winName].filePanel.hide() + else + call s:VEContainer[winName].filePanel.show() + endif + endif + call s:VEContainer[winName].treePanel.setFocus() + exec g:VEConf.treePanelWidth . " wincmd |" +endfunction + +function! VE_ClosePreviewPanel() + pclose +endfunction + + +"Go to upper directory. +function! VE_ToUpperDir() + let winNr = bufwinnr('%') + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + let path = s:VEContainer[winName].filePanel.path + " Assert filePanel.path == treePanel.path + let upperPath = g:VEPlatform.getUpperDir(path) + if upperPath == path + return + endif + call VE_GotoPath(upperPath) + let dir = split(path,'/') + call search(" " . dir[-1] . "/\t") + endif + exec winNr . "wincmd w" +endfunction + +"Path change event +function! VE_GotoPath(path) + if !isdirectory(a:path) + return + endif + call g:VEPlatform.cdToPath(a:path) + let path = g:VEPlatform.getcwd() + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].gotoPath(path) + endif +endfunction + +"Used in +function! VE_OpenPath() + echohl Special + let workPath = input("Change path to (directory): ",'',"file") + echohl None + if workPath == '' + return + endif + call g:VEPlatform.cdToPath(workPath) + let workPath = g:VEPlatform.getcwd() + call VE_GotoPath(workPath) +endfunction + +"Goto forward +function! VE_GotoForward() + let winNr = bufwinnr('%') + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].gotoForward() + endif + exec winNr . "wincmd w" +endfunction + +"Goto backward +function! VE_GotoBackward() + let winNr = bufwinnr('%') + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + call s:VEContainer[winName].gotoBackward() + endif + exec winNr . "wincmd w" +endfunction + +"Favorite +function! VE_GotoFavorite() + let fav_filename = g:VEPlatform.getHome() . g:VEConf.favorite + if findfile(fav_filename)=='' || !filereadable(fav_filename) + return + endif + let fav = readfile(fav_filename) + let result = g:VEPlatform.select(fav,"Favorite folder list:") + if result == -1 + return + endif + call VE_GotoPath(fav[result]) +endfunction + +function! VE_AddToFavorite(where) + let winNr = bufwinnr('%') + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + let cwd = s:VEContainer[winName].filePanel.path + else + return + endif + let pathUnderCursor = VE_getPathUnderCursor(a:where) + if pathUnderCursor != '' + " if no path name under cursor, use current working path + let cwd = pathUnderCursor + endif + let fav_filename = g:VEPlatform.getHome() . g:VEConf.favorite + let fav = [] + if findfile(fav_filename) != '' + if !filereadable(fav_filename) + echoerr "Can not read favorite folder list!" + return + endif + if !filewritable(fav_filename) + echoerr "Can not write favorite folder list to file!" + return + endif + let fav = readfile(fav_filename) + endif + if index(fav,cwd) != -1 + "echohl WarningMsg | echomsg "Current directory already in the favorite list." | echohl None + echohl WarningMsg | echomsg "[ ".cwd." ] already in the favorite!" | echohl None + return + endif + call add(fav,cwd) + if writefile(fav,fav_filename) == 0 + echohl Special | echomsg "[ ".cwd." ] added to favorite." | echohl None + else + echoerr "Can not write favorite folder list to file!" + endif +endfunction + +"forward and backward history +function! VE_BrowseHistory() + let winNr = bufwinnr('%') + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + let pathlist = s:VEContainer[winName].pathHistory + let result = g:VEPlatform.select(pathlist,"Browse history:") + if result == -1 + return + else + call s:VEContainer[winName].treePanel.pathChanged(pathlist[result]) + call s:VEContainer[winName].filePanel.pathChanged(pathlist[result]) + let s:VEContainer[winName].pathPosition = result + endif + endif +endfunction + +"sync directory +function! VE_SyncDir() + let winNr = bufwinnr('%') + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + let path = s:VEContainer[winName].filePanel.path + call g:VEPlatform.cdToPath(path) + endif +endfunction + +"diff 2 files +function! VE_Diff() + let winNr = bufwinnr('%') + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + let diffFiles = s:VEContainer[winName].filePanel.selectedFiles + if len(diffFiles) != 2 || isdirectory(diffFiles[0]) || isdirectory(diffFiles[1]) + echohl WarningMsg | echo "Please select 2 files to diff!" | echohl None + return + endif + exec "tabe " . g:VEPlatform.escape(diffFiles[0]) + exec "vertical diffsplit " . g:VEPlatform.escape(diffFiles[1]) + endif +endfunction + +"toggle show hidden files +function! VE_ToggleHidden() + let winNr = bufwinnr('%') + let winName = matchstr(bufname("%"),'_[^_]*$') + if has_key(s:VEContainer,winName) + let g:VEConf.showHiddenFiles = !g:VEConf.showHiddenFiles + call s:VEContainer[winName].treePanel.refresh() + call s:VEContainer[winName].filePanel.refresh() + endif +endfunction + +command! -nargs=? -complete=file VE call VENew('') +command! -nargs=0 -complete=file VEC call VEDestroy() + + +"==================================================================== +" +" Function: s:InstallDocumentation(full_name, revision) +" Install help documentation. +" Arguments: +" full_name: Full name of this vim plugin script, including path name. +" revision: Revision of the vim script. #version# mark in the document file +" will be replaced with this string with 'v' prefix. +" Return: +" 1 if new document installed, 0 otherwise. +" Note: Cleaned and generalized by guo-peng Wen. +" +" Note about authorship: this function was taken from the vimspell plugin +" which can be found at http://www.vim.org/scripts/script.php?script_id=465 +" +function! s:InstallDocumentation(full_name, revision) + " Name of the document path based on the system we use: + if has("vms") + " No chance that this script will work with + " VMS - to much pathname juggling here. + return 1 + elseif (has("unix")) + " On UNIX like system, using forward slash: + let l:slash_char = '/' + let l:mkdir_cmd = ':silent !mkdir -p ' + else + " On M$ system, use backslash. Also mkdir syntax is different. + " This should only work on W2K and up. + let l:slash_char = '\' + let l:mkdir_cmd = ':silent !mkdir ' + endif + + let l:doc_path = l:slash_char . 'doc' + let l:doc_home = l:slash_char . '.vim' . l:slash_char . 'doc' + + " Figure out document path based on full name of this script: + let l:vim_plugin_path = fnamemodify(a:full_name, ':h') + let l:vim_doc_path = fnamemodify(a:full_name, ':h:h') . l:doc_path + if (!(filewritable(l:vim_doc_path) == 2)) + "Doc path: " . l:vim_doc_path + echo "Doc path: " . l:vim_doc_path + execute l:mkdir_cmd . '"' . l:vim_doc_path . '"' + if (!(filewritable(l:vim_doc_path) == 2)) + " Try a default configuration in user home: + let l:vim_doc_path = expand("~") . l:doc_home + if (!(filewritable(l:vim_doc_path) == 2)) + execute l:mkdir_cmd . '"' . l:vim_doc_path . '"' + if (!(filewritable(l:vim_doc_path) == 2)) + " Put a warning: + echo "Unable to open documentation directory" + echo "type :help add-local-help for more information." + echo l:vim_doc_path + return 0 + endif + endif + endif + endif + + " Exit if we have problem to access the document directory: + if (!isdirectory(l:vim_plugin_path) || !isdirectory(l:vim_doc_path) || filewritable(l:vim_doc_path) != 2) + return 0 + endif + + " Full name of script and documentation file: + let l:script_name = fnamemodify(a:full_name, ':t') + let l:doc_name = fnamemodify(a:full_name, ':t:r') . '.txt' + let l:plugin_file = l:vim_plugin_path . l:slash_char . l:script_name + let l:doc_file = l:vim_doc_path . l:slash_char . l:doc_name + + " Bail out if document file is still up to date: + if (filereadable(l:doc_file) && getftime(l:plugin_file) < getftime(l:doc_file)) + return 0 + endif + + " Prepare window position restoring command: + if (strlen(@%)) + let l:go_back = 'b ' . bufnr("%") + else + let l:go_back = 'enew!' + endif + + " Create a new buffer & read in the plugin file (me): + setl nomodeline + exe 'enew!' + exe 'r ' . l:plugin_file + + setl modeline + let l:buf = bufnr("%") + setl noswapfile modifiable + + norm zR + norm gg + + " Delete from first line to a line starts with + " === START_DOC + 1,/^=\{3,}\s\+START_DOC\C/ d + + " Delete from a line starts with + " === END_DOC + " to the end of the documents: + /^=\{3,}\s\+END_DOC\C/,$ d + + " Add modeline for help doc: the modeline string is mangled intentionally + " to avoid it be recognized by VIM: + call append(line('$'), '') + call append(line('$'), ' v' . 'im:tw=78:ts=8:ft=help:norl:') + + " Replace revision: + "exe "normal :1s/#version#/ v" . a:revision . "/\" + exe "normal :%s/#version#/ v" . a:revision . "/\" + + " Save the help document: + exe 'w! ' . l:doc_file + exe l:go_back + exe 'bw ' . l:buf + + " Build help tags: + exe 'helptags ' . l:vim_doc_path + + return 1 +endfunction + +" Doc installation call {{{1 +silent call s:InstallDocumentation(expand(':p'),"0.99") +"============================================================ +finish + +"Manual {{{1 +=== START_DOC +*VimExplorer* A powerful file manager #version# + + + VimExplorer Reference Manual + by Ming Bai (mbbill AT gmail.com) + + +============================================================================== +CONTENTS *VimExplorer-contents* + +1. Intro.......................................|VimExplorer-start| +2. Functionality...............................|VimExplorer-functionality| + 2.1 Tree Panel Hotkeys.....................|VimExplorer-treehotkey| + 2.2 File Panel Hotkeys.....................|VimExplorer-filehotkey| + 2.3 Commands...............................|VimExplorer-commands| +3. Directory Browsing..........................|VimExplorer-browse| + 3.1 Tree Browsing..........................|VimExplorer-treebrowse| + 3.2 File Browsing..........................|VimExplorer-filebrowse| + 3.3 Forward and Backward...................|VimExplorer-forbackward| + 3.4 Favorites..............................|VimExplorer-favorite| + 3.5 Temp Marks.............................|VimExplorer-tempmark| +4. Marks.......................................|VimExplorer-mark| + 4.1 Single File Marks......................|VimExplorer-marksingle| + 4.2 Visual Marks...........................|VimExplorer-markvisual| + 4.3 Regexp Marks...........................|VimExplorer-markregexp| +5. File operations.............................|VimExplorer-fileoperation| + 5.1 Create.................................|VimExplorer-new| + 5.2 Move...................................|VimExplorer-move| + 5.3 Delete.................................|VimExplorer-delete| + 5.4 Diff...................................|VimExplorer-diff| + 5.5 Search.................................|VimExplorer-search| + 5.6 Other Operations.......................|VimExplorer-otherfileopt| +6. Other Functionalities.......................|VimExplorer-otherfuncs| +7. Customization...............................|VimExplorer-customize| + 7.1 Normal Options.........................|VimExplorer-custnormal| + 7.2 Hotkey Customization...................|VimExplorer-custhotkey| + 7.3 Command Customization..................|VimExplorer-custcommand| +8. The Author..................................|VimExplorer-author| +9. Problems and Fixes..........................|VimExplorer-problems| +10. Changelog...................................|VimExplorer-changelog| +11. TODO........................................|VimExplorer-todo| + + +============================================================================== +1. Intro *VimExplorer-start* + +What is VimExplorer ? +VimExplorer is a file manager, it can do a lot of file operations such as +copy, delete, move, preview, search and so on. Also it has a variety of other +capacities and customization abilities. + +You can start VimExplorer by the following command: +> + :VE +< +Then it will ask you for the starting directory, default is the current path. +> + VimExplorer (directory): /home/username/ +< +You can change it to some other directories or just push "Enter" to start it. + +The second approach to start VimExplorer: +> + :VE [directory] +< +Example: +> + :VE /usr/src/ +< +Now, VimExplorer will start using the path '/usr/src/'. When you are typing +the path, and will help you to complete the path automatically. +After all of these operations, you can see a new tab which has two panels +within it, one is the "Tree Panel" and the other is "File Panel". From now you +will have a happy journey using the powerful file manager. + + +============================================================================== +2. Functionality *VimExplorer-functionality* + +2.1 Tree Panel Hotkeys *VimExplorer-treehotkey* + +Member of |VEConf_treeHotkey|, refer to section 7.2 . + +Mapping Key Description~ +help ? Help. +toggleNode Open/Close/Switch to current node. +toggleNodeMouse <2-LeftMouse> Open/Close/Switch to current node. +refresh r Refresh the tree panel. +favorite f View favorite folder list. +addToFavorite F Add the folder under cursor to + favorite list. If no path under + cursor, use current working path. +browseHistory b View browse history. +toggleFilePanel t Toggle the file panel. +toUpperDir Go to upper directory. +switchPanel Switch to File Panel. +gotoPath Change to another path. +quitVE Q Quit VimExplorer. + +2.2 File Panel Hotkeys *VimExplorer-filehotkey* + +Member of |VEConf_fileHotkey|, refer to section 7.2 . + +Mapping Default Description~ +help ? Help. +itemClicked Enter the directory or open the file + by default association. +itemClickMouse <2-LeftMouse> Enter the directory or open the file + by default association. +refresh r Refresh. +toggleTreePanel t Toggle the Tree Panel. +toggleModes i Toggle file sort mode (type/data/file + extension). +newFile +f Create a new file. +newDirectory +d Create a new directory. +switchPanel Switch to the Tree Panel. +quitVE Q Quit VimExplorer. +toggleHidden H Toggle show hidden files.(files start + with '.') +search g/ Search. +markPlace m{a-z} Put current path to register(a-z). +gotoPlace '{a-z} Jump to path in register(a-z). +viewMarks J View path in register. +contextMenuN File panel context menu in normal mode. +toUpperDir Go to upper directory. +gotoForward Forward. +gotoBackward Backward. +favorite f View favorite folder list. +addToFavorite F Add the folder under cursor to + favorite list. If no path under + cursor, use current working path. +browseHistory b View browse history. +gotoPath Change to another path. +rename R Rename the file under cursor. +yankSingle yy Copy file under cursor. +cutSingle xx Cut file under cursor. +showYankList yl Show clipboard. +deleteSingle dd Delete file under cursor to recycle bin. +deleteSingle DD Force delete file under cursor. +openPreview u Preview. +closePreview U Close the preview panel. +toggleSelectUp Move the cursor up and mark/unmark the + file under cursor. +toggleSelectDown Mark/unmark the file under cursor and + move the cursor down. +toggleSelMouse Mark/unmark the file under cursor. +markViaRegexp Mr Mark via regular expression. +markVimFiles Mv Mark all vim files. +markDirectory Md Mark all directories. +markExecutable Me Mark all executable files. +clearSelect Mc Clear all marks. +deleteSelected sd Delete marked files to recycle bin. +deleteSelected sD Force delete marked files. +yankSelected sy Copy marked files. +cutSelected sx Cut marked files. +tabViewMulti se Edit every marked file in separate + tabs. +paste p Paste. +diff2files = Diff two files. +tabView e Edit file in new tab. +openRenamer ;r Open Renamer (Note 1) +startShell ;c Start a shell from current path. +startExplorer ;e Start another file + manager(nautilus,konquer,explorer.exe). + +Visual Mode Hotkeys~ +visualSelect Mark files. +visualDelete d Delete files to recycle bin. +visualDelete D Force delete files. +visualYank y Copy files. +visualCut x Cut files. +tabView e View files in new tabs. + +2.3 Commands *VimExplorer-commands* +> + VE +< +Start VimExplorer. + +> + VEC +< +Close VimExplorer, Hotkey |Q| has the same ability. + +============================================================================== +3. Directory Browsing *VimExplorer-browse* + +3.1 Tree Browsing *VimExplorer-treebrowse* + +Press "Enter" on one tree node will change the path and add the new path to +browse history. By default, if a directory has it's own child directories, |+| +will be displayed before it's name, and It will cause a little performance +lost. If you don't need this feature ,set the following variable to zero can +disable it. +> + let VEConf_showFolderStatus = 0 +< +There are some differences between win32 and other platforms. In win32, there +are several root nodes (such as C:\,D:\), but one root node (/) in other +platforms. + +3.2 File Browsing *VimExplorer-filebrowse* + +The file panel consist of two parts: the path in the top and the following +file list. Every line of the file list consist from the following regions: + +[*] {file-name} [file-size] {permission} {modify-time} + +The file panel can sort by type, file name and date. Hotkey |i| is used to +cycle between these modes. Default sort mode controlled by following variable: +> + VEConf_filePanelSortType + +< +See Customization section for more details. + +3.3 Forward and Backward *VimExplorer-forbackward* + +When using "Enter" switch to an new folder, the path will be add to browse +history. Then you can use || and || to go backward and forward. +Hotkey |b| is used to list all browse history, select by number or mouse can +take you directory to that path. + +By default, the depth of browse history is 100. Controled by this variable: +> + VEConf_browseHistory +< +VimExplorer can remember the cursor position every time leaving a directory, +so it can restore the cursor when return to it. If a directory is newly +entered, the cursor will be put in the middle of the screen. + +3.4 Favorites *VimExplorer-favorite* + +The favorite folder list is saved to the file $HOME/.ve_favorite . It will be +updated when new folder is added to favorite by hotkey |F|. The format of +".ve_favorite" is very simple: every line is a path, so edit it is quite +easy. + +3.5 Temp Marks *VimExplorer-tempmark* + +Just like the favorites, |ma| put current path into register 'a', and |'a| can +jump to the path. |J| is used to list every non empty register. All paths in +register will disappear after VimExplorer exists. + +============================================================================== +4. Marks *VimExplorer-mark* + +The simplest way is to press upon a file. There will be a '*' before +marked files and also be displayed in a different color. +There are three way to mark files: + +4.1 Single File Marks *VimExplorer-marksingle* + + Invert selection, move the cursor down. + Move the cursor up, then invert selection. +Just like most of vim commands, 5 will mark 5 files start from current +cursor. + +4.2 Visual Marks *VimExplorer-markvisual* + + in visual mode will invert selected these files. + +4.3 Regexp Marks *VimExplorer-markregexp* + +Hotkey: |Mr| +Only the file name is the target of regexp match. Example: +> + Mark file (regexp): ^abc.*\.vim$ +< +It will mark all vim scripts start with abc. The following functionalities is +derived from this feature: +|Mv| mark all vim scripts. +|Me| mark all executable files. +|Md| mark all directories. +and |Mc| to clear all marks. + +============================================================================== +5. File Operations *VimExplorer-fileoperation* + +5.1 Create *VimExplorer-new* + +|+f| and |+d| is used to create new files and directories. + +5.2 Move *VimExplorer-move* + +There are several hotkey used to copy/cut files: +|yy| and |sy| in normal mode ,|y| in visual mode is to copy file. +|xx| and |sx| in normal mode ,|x| in visual mode is to cut file. +|p| paste file. +Note that the clipboard is shared between all VimExplorers ,you can cut in one +VE tab and paste in another. +If you want to view the clipboard, |yl| can be help. + +5.3 Delete *VimExplorer-delete* + +|dd|,|sd| in normal mode and |d| in visual mode can delete file(s) to recycle bin. +Corresponding |DD|,|sD| and |D| are used to force delete file(s). + +5.4 Diff *VimExplorer-diff* + +|=| is used to diff 2 files, so make sure you have selected 2 files before +using this command. + +5.5 Search *VimExplorer-search* + +Just like / ,but the pattern here is not the regexp in vim, it will be +expended by shell. + +5.6 Other Operations *VimExplorer-otherfileopt* + +|e| |R| |u| and so on ... Refer to section 2.2 + +============================================================================== +6. Other Functionalities *VimExplorer-otherfuncs* + +|;r| |;c| |;e| and so on ...Rever to section 2.2 + +============================================================================== +7. Customization *VimExplorer-customize* + +7.1 Normal Options *VimExplorer-custnormal* + +Common Options~ + +|g:VEConf_systemEncoding| It controls the encoding of vim calling + function system(). If your system encoding + is different from '&encoding', set this + value to system encoding. Example: let + g:VEConf_systemEncoding = 'utf-8' + ,Default: '' (empty) + +|g:VEConf_win32Disks| The default value is all 26 volumes. Set this + value to fit your system can increase the + startup speed. If you are not using + Microsoft Windows, ignore it. Example: + let VEConf_win32Disks = + ["A:","B:","C:","D:"] + +|g:VEConf_browseHistory| Depth of browse history. Default: 100 + +|g:VEConf_previewSplitLocation| Split location of preview panel. Optional + parameters are: + "belowright","topleft","leftabove","botright". + Default: "belowright" + +|g:VEConf_showHiddenFiles| Show hidden files, 1: show,0: hide. Default: 1 + +|g:VEConf_externalExplorer| Name of the external file explorer. You can + set this value according to you system. + Default: "explorer.exe"(win32) "nautilus" + (gnome) + +|g:VEConf_sortCaseSensitive| 0: not case sensitive 1: case sensitive + Default: 1 + +|g:VEConf_favorite| Favorite folder file name. Always stored in + $HOME. Default: ".ve_favorite" + +|g:VEConf_overWriteExisting| Ask when over write existing files. + 0: ask 1: always over write 2: always + not over write Default: 0 + +|g:VEConf_usingKDE| If set to 1, use "kfmclient" +|g:VEConf_usingGnome| If set to 1, use "gnome-open" + +|g:VEConf_recyclePath| Recycle path. Example: + let g:VEConf_recyclePath = 'C:\VErecycle\' + +Tree Panel Options~ + +|g:VEConf_showFolderStatus| It controls whether show '+' before the + folders which have their own child + folders. If it is set to 1, every folder + will have a '+'. Default: 1 + +|g:VEConf_treePanelWidth| Width of tree panel. Default: 30 + +|g:VEConf_treePanelSplitMode| Split mode of tree panel. Default: "vertical" + +|g:VEConf_treePanelSplitLocation| Split location of tree panel, Optional + parameters: "belowright" , "topleft" , + "leftabove" , "botright", Default: + "leftabove" + +|g:VEConf_treeSortDirection| Sort direction. 1: A-Z 0: Z-A. Default: 1 + +File Panel Options~ + +|g:VEConf_fileGroupSortDirection| Sort direction. 1: A-Z 0: Z-A, Default: 1 + +|g:VEConf_fileDeleteConfirm| Confirm when deleting a file. 1: confirm 2: + no confirm. Default: 1 + +|g:VEConf_filePanelWidth| Width of file panel. Default: 40 + +|g:VEConf_filePanelSplitMode| Split mode of file panel. Default: "vertical" + +|g:VEConf_filePanelSplitLocation| Split location of file panel, Optional + parameters: "belowright" , "topleft" , + "leftabove" , "botright" ,Default: + "leftabove" + +|g:VEConf_filePanelSortType| File sort type. 1: sort by name 2: sort by + time 3: sort by type, Default: 3 + +|g:VEConf_showFileSizeInMKB| 1: Show file size in MKB format. 0: always + show file size in byte. + +|g:VEConf_filePanelFilter| Filter of the file panel, which will be + passed to glob() function. Example: + let g:VEConf_filePanelFilter = '*.txt' + +7.2 Hotkey Customization *VimExplorer-custhotkey* + +All user defined hotkeys are controlled by the two dicts: +|g:VEConf_treeHotkey| and |g:VEConf_fileHotkey| +Example: +> + let g:VEConf_treeHotkey = {} + let g:VEConf_treeHotkey.help = '??' + let g:VEConf_treeHotkey.quitVE = 'qq' + let g:VEConf_treeHotkey.switchPanel = '' +< +All definable hotkeys and their default bindings refer to section 2 . + +7.3. Command Customization *VimExplorer-custcommand* + +VimExplorer supports three types of command interface: +single file hotkeys and actions, multi file hotkeys and actions and normal +hotkeys and actions. +They are controlled by these variables: + + |g:VEConf_singleFileActions| |g:VEConf_singleFileHotKeys| + + |g:VEConf_multiFileActions| |g:VEConf_multiFileHotKeys| + + |g:VEConf_normalActions| |g:VEConf_normalHotKeys| + +All of them are dicts. Example: +> + let g:VEConf_normalActions = {} + let g:VEConf_normalHotKeys = {} + let g:VEConf_normalHotKeys['test1'] = 'T1' + function! VEConf_normalActions['test1']() + Renamer + endfunction +< +"test1" is the key. VimExplorer will bind the hotkey and corresponding actions +automatically. +> + let g:VEConf_singleFileActions = {} + let g:VEConf_singleFileHotKeys = {} + let g:VEConf_singleFileHotKeys['test2'] = 'T2' + function! VEConf_singleFileActions['test2'](path) + call g:VEPlatform.system("notepad.exe " . g:VEPlatform.escape(a:path)) + endfunction +< +Here, parameter "path" is the path of file under cursor. +> + let g:VEConf_multiFileActions = {} + let g:VEConf_multiFileHotKeys = {} + let g:VEConf_multiFileHotKeys['test3'] = 'T3' + function! VEConf_multiFileActions['test3'](fileList) + for i in a:fileList + call g:VEPlatform.start("nautilus " . i) + endfor + endfunction +< +Parameter "fileList" consists of all paths of marked files. +In addition, VimExplorer provides some platform independent functions: +> + g:VEPlatform.start(path) + g:VEPlatform.system(cmd) + g:VEPlatform.copyfile(filename,topath) + g:VEPlatform.search(filename,path) + g:VEPlatform.deleteSingle(path) +< +These functions can be used in user defined actions. + + + + +============================================================================== +8. The Author *VimExplorer-author* + +If you have find a bug, or have some suggestions , mail me. + +mail: mbbillgmailcom + +============================================================================== +9. Problems and Fixes *VimExplorer-problems* + + *VimExplorer-p1* +P1. Case sensitive in Win32. + At present, the path in win32 is case sensitive. Pay attention to this + when starting VE, editing the favorite list or using to change + path. A good suggestion is using or to complete path + automatically. + + *VimExplorer-p2* +P2. 'wildignre' option cause some files disappeared. + If 'wildignore' is not empty, glob() function will not return files + matching the file pattern listed in it, then you may find some files + disappeared in the file panel. + + + +============================================================================== +10. Changelog *VimExplorer-changelog* + +0.95 + - Initial release. + +0.96 + - BUG: VE_normalAction not found. + +0.97 + - NEW: Add options |g:VEConf_usingKDE| and |g:VEConf_usingGnome| for + starting program in *nix environment. + - NEW: Check if the script is already loaded, thanks to Dennis Hostetler. + - BUG: Escape ' %#' for path. + - BUG: Favorite selection out of range. + - CHG: Change the behaviour of hotkey 'F', now it adds the path under + cursor to favorite list. If no path under cursor, use current + working path instead.(Thanks to Vincent Wang) + - CHG: Change default g:VEConf_systemEncoding to '' (empty). +0.98 + - NEW: Add option VEConf_filePanelFilter. + - BUG: Escape in command 'e' 'se' 'u' and '='. + - BUG: 'Cut' and 'Paste' command causes file lost. + - CHG: Change the default hotkey 'M' and 'B' to 'm','J'. + - CHG: Change forward and backward hotkey to || and ||(). + - CHG: Change hotkey || to ||. + - CHG: Change hotkey |mr| |mv| |md| |me| |mc| to |Mr| |Mv| |Md| |Me| |Mc|. + - CHG: When GUI is running, use confirm() to pop a dialog instead of input(). +0.99 + - NEW: Add toggle selection hotkey . + - NEW: Add a context menu in file panel, right click on a file to popup it. + - NEW: Add "delete to recycle",hotkey |dd|,|sd| and |d| in visual mode + are used to delete file(s) to recycle bin.The curresponding + |DD|,|sD|,|D| hotkey are used to force delete files. + - NEW: Now VE can remember the cursor position when reenter a directory. + - BUG: All files are put to "Hidden Files" group in a hidden directory. + - BUG: 'sd' twice after selection will cause an error. + +============================================================================== +11. TODO *VimExplorer-todo* + - More clipboard. + - Diff files in different directories. + - Two panel mode, just like TotalCommand. + - Diff directories. + - Browse via e.g. FTP, SCP ... directorys on a server. + - Rename file when file exsits in copy operation. + - Compress file. + - Send to. + + +============================================================================== +Note 1: +Renamer is a good plugin, which is used to rename group of files. The author +is John Orr. It can be found here: +http://www.vim.org/scripts/script.php?script_id=1721 + + +=== END_DOC +" vim: set et fdm=marker sts=4 sw=4 tw=78: diff --git a/.vim/plugin/a.vim b/.vim/plugin/a.vim new file mode 100644 index 0000000..637feb5 --- /dev/null +++ b/.vim/plugin/a.vim @@ -0,0 +1,840 @@ +" Copyright (c) 1998-2006 +" Michael Sharpe +" +" We grant permission to use, copy modify, distribute, and sell this +" software for any purpose without fee, provided that the above copyright +" notice and this text are not removed. We make no guarantee about the +" suitability of this software for any purpose and we are not liable +" for any damages resulting from its use. Further, we are under no +" obligation to maintain or extend this software. It is provided on an +" "as is" basis without any expressed or implied warranty. + +" Directory & regex enhancements added by Bindu Wavell who is well known on +" vim.sf.net +" +" Patch for spaces in files/directories from Nathan Stien (also reported by +" Soeren Sonnenburg) + +" Do not load a.vim if is has already been loaded. +if exists("loaded_alternateFile") + finish +endif +if (v:progname == "ex") + finish +endif +let loaded_alternateFile = 1 + +let alternateExtensionsDict = {} + +" setup the default set of alternate extensions. The user can override in thier +" .vimrc if the defaults are not suitable. To override in a .vimrc simply set a +" g:alternateExtensions_ variable to a comma separated list of alternates, +" where is the extension to map. +" E.g. let g:alternateExtensions_CPP = "inc,h,H,HPP,hpp" +" let g:alternateExtensions_{'aspx.cs'} = "aspx" + + +" This variable will be increased when an extension with greater number of dots +" is added by the AddAlternateExtensionMapping call. +let s:maxDotsInExtension = 1 + +" Function : AddAlternateExtensionMapping (PRIVATE) +" Purpose : simple helper function to add the default alternate extension +" mappings. +" Args : extension -- the extension to map +" alternates -- comma separated list of alternates extensions +" Returns : nothing +" Author : Michael Sharpe +function! AddAlternateExtensionMapping(extension, alternates) + " This code does not actually work for variables like foo{'a.b.c.d.e'} + "let varName = "g:alternateExtensions_" . a:extension + "if (!exists(varName)) + " let g:alternateExtensions_{a:extension} = a:alternates + "endif + + " This code handles extensions which contains a dot. exists() fails with + " such names. + "let v:errmsg = "" + " FIXME this line causes ex to return 1 instead of 0 for some reason?? + "silent! echo g:alternateExtensions_{a:extension} + "if (v:errmsg != "") + "let g:alternateExtensions_{a:extension} = a:alternates + "endif + + let g:alternateExtensionsDict[a:extension] = a:alternates + let dotsNumber = strlen(substitute(a:extension, "[^.]", "", "g")) + if s:maxDotsInExtension < dotsNumber + let s:maxDotsInExtension = dotsNumber + endif +endfunction + + +" Add all the default extensions +" Mappings for C and C++ +call AddAlternateExtensionMapping('h',"c,cpp,cxx,cc,CC") +call AddAlternateExtensionMapping('H',"C,CPP,CXX,CC") +call AddAlternateExtensionMapping('hpp',"cpp,c") +call AddAlternateExtensionMapping('HPP',"CPP,C") +call AddAlternateExtensionMapping('c',"h") +call AddAlternateExtensionMapping('C',"H") +call AddAlternateExtensionMapping('cpp',"h,hpp") +call AddAlternateExtensionMapping('CPP',"H,HPP") +call AddAlternateExtensionMapping('cc',"h") +call AddAlternateExtensionMapping('CC',"H,h") +call AddAlternateExtensionMapping('cxx',"h") +call AddAlternateExtensionMapping('CXX',"H") +" Mappings for PSL7 +call AddAlternateExtensionMapping('psl',"ph") +call AddAlternateExtensionMapping('ph',"psl") +" Mappings for ADA +call AddAlternateExtensionMapping('adb',"ads") +call AddAlternateExtensionMapping('ads',"adb") +" Mappings for lex and yacc files +call AddAlternateExtensionMapping('l',"y,yacc,ypp") +call AddAlternateExtensionMapping('lex',"yacc,y,ypp") +call AddAlternateExtensionMapping('lpp',"ypp,y,yacc") +call AddAlternateExtensionMapping('y',"l,lex,lpp") +call AddAlternateExtensionMapping('yacc',"lex,l,lpp") +call AddAlternateExtensionMapping('ypp',"lpp,l,lex") +" Mappings for OCaml +call AddAlternateExtensionMapping('ml',"mli") +call AddAlternateExtensionMapping('mli',"ml") +" ASP stuff +call AddAlternateExtensionMapping('aspx.cs', 'aspx') +call AddAlternateExtensionMapping('aspx.vb', 'aspx') +call AddAlternateExtensionMapping('aspx', 'aspx.cs,aspx.vb') + +" Setup default search path, unless the user has specified +" a path in their [._]vimrc. +if (!exists('g:alternateSearchPath')) + let g:alternateSearchPath = 'sfr:../source,sfr:../src,sfr:../include,sfr:../inc' +endif + +" If this variable is true then a.vim will not alternate to a file/buffer which +" does not exist. E.g while editing a.c and the :A will not swtich to a.h +" unless it exists. +if (!exists('g:alternateNoDefaultAlternate')) + " by default a.vim will alternate to a file which does not exist + let g:alternateNoDefaultAlternate = 0 +endif + +" If this variable is true then a.vim will convert the alternate filename to a +" filename relative to the current working directory. +" Feature by Nathan Huizinga +if (!exists('g:alternateRelativeFiles')) + " by default a.vim will not convert the filename to one relative to the + " current working directory + let g:alternateRelativeFiles = 0 +endif + + +" Function : GetNthItemFromList (PRIVATE) +" Purpose : Support reading items from a comma seperated list +" Used to iterate all the extensions in an extension spec +" Used to iterate all path prefixes +" Args : list -- the list (extension spec, file paths) to iterate +" n -- the extension to get +" Returns : the nth item (extension, path) from the list (extension +" spec), or "" for failure +" Author : Michael Sharpe +" History : Renamed from GetNthExtensionFromSpec to GetNthItemFromList +" to reflect a more generic use of this function. -- Bindu +function! GetNthItemFromList(list, n) + let itemStart = 0 + let itemEnd = -1 + let pos = 0 + let item = "" + let i = 0 + while (i != a:n) + let itemStart = itemEnd + 1 + let itemEnd = match(a:list, ",", itemStart) + let i = i + 1 + if (itemEnd == -1) + if (i == a:n) + let itemEnd = strlen(a:list) + endif + break + endif + endwhile + if (itemEnd != -1) + let item = strpart(a:list, itemStart, itemEnd - itemStart) + endif + return item +endfunction + +" Function : ExpandAlternatePath (PRIVATE) +" Purpose : Expand path info. A path with a prefix of "wdr:" will be +" treated as relative to the working directory (i.e. the +" directory where vim was started.) A path prefix of "abs:" will +" be treated as absolute. No prefix or "sfr:" will result in the +" path being treated as relative to the source file (see sfPath +" argument). +" +" A prefix of "reg:" will treat the pathSpec as a regular +" expression substitution that is applied to the source file +" path. The format is: +" +" reg: +" +" seperator character, we often use one of [/|%#] +" is what you are looking for +" is the output pattern +" can be g for global replace or empty +" +" EXAMPLE: 'reg:/inc/src/g/' will replace every instance +" of 'inc' with 'src' in the source file path. It is possible +" to use match variables so you could do something like: +" 'reg:|src/\([^/]*\)|inc/\1||' (see 'help :substitute', +" 'help pattern' and 'help sub-replace-special' for more details +" +" NOTE: a.vim uses ',' (comma) internally so DON'T use it +" in your regular expressions or other pathSpecs unless you update +" the rest of the a.vim code to use some other seperator. +" +" Args : pathSpec -- path component (or substitution patterns) +" sfPath -- source file path +" Returns : a path that can be used by AlternateFile() +" Author : Bindu Wavell +function! ExpandAlternatePath(pathSpec, sfPath) + let prfx = strpart(a:pathSpec, 0, 4) + if (prfx == "wdr:" || prfx == "abs:") + let path = strpart(a:pathSpec, 4) + elseif (prfx == "reg:") + let re = strpart(a:pathSpec, 4) + let sep = strpart(re, 0, 1) + let patend = match(re, sep, 1) + let pat = strpart(re, 1, patend - 1) + let subend = match(re, sep, patend + 1) + let sub = strpart(re, patend+1, subend - patend - 1) + let flag = strpart(re, strlen(re) - 2) + if (flag == sep) + let flag = '' + endif + let path = substitute(a:sfPath, pat, sub, flag) + "call confirm('PAT: [' . pat . '] SUB: [' . sub . ']') + "call confirm(a:sfPath . ' => ' . path) + else + let path = a:pathSpec + if (prfx == "sfr:") + let path = strpart(path, 4) + endif + let path = a:sfPath . "/" . path + endif + return path +endfunction + +" Function : FindFileInSearchPath (PRIVATE) +" Purpose : Searches for a file in the search path list +" Args : filename -- name of the file to search for +" pathList -- the path list to search +" relPathBase -- the path which relative paths are expanded from +" Returns : An expanded filename if found, the empty string otherwise +" Author : Michael Sharpe (feline@irendi.com) +" History : inline code written by Bindu Wavell originally +function! FindFileInSearchPath(fileName, pathList, relPathBase) + let filepath = "" + let m = 1 + let pathListLen = strlen(a:pathList) + if (pathListLen > 0) + while (1) + let pathSpec = GetNthItemFromList(a:pathList, m) + if (pathSpec != "") + let path = ExpandAlternatePath(pathSpec, a:relPathBase) + let fullname = path . "/" . a:fileName + let foundMatch = BufferOrFileExists(fullname) + if (foundMatch) + let filepath = fullname + break + endif + else + break + endif + let m = m + 1 + endwhile + endif + return filepath +endfunction + +" Function : FindFileInSearchPathEx (PRIVATE) +" Purpose : Searches for a file in the search path list +" Args : filename -- name of the file to search for +" pathList -- the path list to search +" relPathBase -- the path which relative paths are expanded from +" count -- find the count'th occurence of the file on the path +" Returns : An expanded filename if found, the empty string otherwise +" Author : Michael Sharpe (feline@irendi.com) +" History : Based on FindFileInSearchPath() but with extensions +function! FindFileInSearchPathEx(fileName, pathList, relPathBase, count) + let filepath = "" + let m = 1 + let spath = "" + let pathListLen = strlen(a:pathList) + if (pathListLen > 0) + while (1) + let pathSpec = GetNthItemFromList(a:pathList, m) + if (pathSpec != "") + let path = ExpandAlternatePath(pathSpec, a:relPathBase) + if (spath != "") + let spath = spath . ',' + endif + let spath = spath . path + else + break + endif + let m = m + 1 + endwhile + endif + + if (&path != "") + if (spath != "") + let spath = spath . ',' + endif + let spath = spath . &path + endif + + let filepath = findfile(a:fileName, spath, a:count) + return filepath +endfunction + +" Function : EnumerateFilesByExtension (PRIVATE) +" Purpose : enumerates all files by a particular list of alternate extensions. +" Args : path -- path of a file (not including the file) +" baseName -- base name of the file to be expanded +" extension -- extension whose alternates are to be enumerated +" Returns : comma separated list of files with extensions +" Author : Michael Sharpe +function! EnumerateFilesByExtension(path, baseName, extension) + let enumeration = "" + let extSpec = "" + let v:errmsg = "" + silent! echo g:alternateExtensions_{a:extension} + if (v:errmsg == "") + let extSpec = g:alternateExtensions_{a:extension} + endif + if (extSpec == "") + if (has_key(g:alternateExtensionsDict, a:extension)) + let extSpec = g:alternateExtensionsDict[a:extension] + endif + endif + if (extSpec != "") + let n = 1 + let done = 0 + while (!done) + let ext = GetNthItemFromList(extSpec, n) + if (ext != "") + if (a:path != "") + let newFilename = a:path . "/" . a:baseName . "." . ext + else + let newFilename = a:baseName . "." . ext + endif + if (enumeration == "") + let enumeration = newFilename + else + let enumeration = enumeration . "," . newFilename + endif + else + let done = 1 + endif + let n = n + 1 + endwhile + endif + return enumeration +endfunction + +" Function : EnumerateFilesByExtensionInPath (PRIVATE) +" Purpose : enumerates all files by expanding the path list and the extension +" list. +" Args : baseName -- base name of the file +" extension -- extension whose alternates are to be enumerated +" pathList -- the list of paths to enumerate +" relPath -- the path of the current file for expansion of relative +" paths in the path list. +" Returns : A comma separated list of paths with extensions +" Author : Michael Sharpe +function! EnumerateFilesByExtensionInPath(baseName, extension, pathList, relPathBase) + let enumeration = "" + let filepath = "" + let m = 1 + let pathListLen = strlen(a:pathList) + if (pathListLen > 0) + while (1) + let pathSpec = GetNthItemFromList(a:pathList, m) + if (pathSpec != "") + let path = ExpandAlternatePath(pathSpec, a:relPathBase) + let pe = EnumerateFilesByExtension(path, a:baseName, a:extension) + if (enumeration == "") + let enumeration = pe + else + let enumeration = enumeration . "," . pe + endif + else + break + endif + let m = m + 1 + endwhile + endif + return enumeration +endfunction + +" Function : DetermineExtension (PRIVATE) +" Purpose : Determines the extension of a filename based on the register +" alternate extension. This allow extension which contain dots to +" be considered. E.g. foo.aspx.cs to foo.aspx where an alternate +" exists for the aspx.cs extension. Note that this will only accept +" extensions which contain less than 5 dots. This is only +" implemented in this manner for simplicity...it is doubtful that +" this will be a restriction in non-contrived situations. +" Args : The path to the file to find the extension in +" Returns : The matched extension if any +" Author : Michael Sharpe (feline@irendi.com) +" History : idea from Tom-Erik Duestad +" Notes : there is some magic occuring here. The exists() function does not +" work well when the curly brace variable has dots in it. And why +" should it, dots are not valid in variable names. But the exists +" function is wierd too. Lets say foo_c does exist. Then +" exists("foo_c.e.f") will be true...even though the variable does +" not exist. However the curly brace variables do work when the +" variable has dots in it. E.g foo_{'c'} is different from +" foo_{'c.d.e'}...and foo_{'c'} is identical to foo_c and +" foo_{'c.d.e'} is identical to foo_c.d.e right? Yes in the current +" implementation of vim. To trick vim to test for existence of such +" variables echo the curly brace variable and look for an error +" message. +function! DetermineExtension(path) + let mods = ":t" + let i = 0 + while i <= s:maxDotsInExtension + let mods = mods . ":e" + let extension = fnamemodify(a:path, mods) + if (has_key(g:alternateExtensionsDict, extension)) + return extension + endif + let v:errmsg = "" + silent! echo g:alternateExtensions_{extension} + if (v:errmsg == "") + return extension + endif + let i = i + 1 + endwhile + return "" +endfunction + +" Function : AlternateFile (PUBLIC) +" Purpose : Opens a new buffer by looking at the extension of the current +" buffer and finding the corresponding file. E.g. foo.c <--> foo.h +" Args : accepts one argument. If present it used the argument as the new +" extension. +" Returns : nothing +" Author : Michael Sharpe +" History : + When an alternate can't be found in the same directory as the +" source file, a search path will be traversed looking for the +" alternates. +" + Moved some code into a separate function, minor optimization +" + rework to favor files in memory based on complete enumeration of +" all files extensions and paths +function! AlternateFile(splitWindow, ...) + let extension = DetermineExtension(expand("%:p")) + let baseName = substitute(expand("%:t"), "\." . extension . '$', "", "") + let currentPath = expand("%:p:h") + + if (a:0 != 0) + let newFullname = currentPath . "/" . baseName . "." . a:1 + call FindOrCreateBuffer(newFullname, a:splitWindow, 0) + else + let allfiles = "" + if (extension != "") + let allfiles1 = EnumerateFilesByExtension(currentPath, baseName, extension) + let allfiles2 = EnumerateFilesByExtensionInPath(baseName, extension, g:alternateSearchPath, currentPath) + + if (allfiles1 != "") + if (allfiles2 != "") + let allfiles = allfiles1 . ',' . allfiles2 + else + let allfiles = allfiles1 + endif + else + let allfiles = allfiles2 + endif + endif + + if (allfiles != "") + let bestFile = "" + let bestScore = 0 + let score = 0 + let n = 1 + + let onefile = GetNthItemFromList(allfiles, n) + let bestFile = onefile + while (onefile != "" && score < 2) + let score = BufferOrFileExists(onefile) + if (score > bestScore) + let bestScore = score + let bestFile = onefile + endif + let n = n + 1 + let onefile = GetNthItemFromList(allfiles, n) + endwhile + + if (bestScore == 0 && g:alternateNoDefaultAlternate == 1) + echo "No existing alternate available" + else + call FindOrCreateBuffer(bestFile, a:splitWindow, 1) + let b:AlternateAllFiles = allfiles + endif + else + echo "No alternate file/buffer available" + endif + endif +endfunction + +" Function : AlternateOpenFileUnderCursor (PUBLIC) +" Purpose : Opens file under the cursor +" Args : splitWindow -- indicates how to open the file +" Returns : Nothing +" Author : Michael Sharpe (feline@irendi.com) www.irendi.com +function! AlternateOpenFileUnderCursor(splitWindow,...) + let cursorFile = (a:0 > 0) ? a:1 : expand("") + let currentPath = expand("%:p:h") + let openCount = 1 + + let fileName = FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, openCount) + if (fileName != "") + call FindOrCreateBuffer(fileName, a:splitWindow, 1) + let b:openCount = openCount + let b:cursorFile = cursorFile + let b:currentPath = currentPath + else + echo "Can't find file" + endif +endfunction + +" Function : AlternateOpenNextFile (PUBLIC) +" Purpose : Opens the next file corresponding to the search which found the +" current file +" Args : bang -- indicates what to do if the current file has not been +" saved +" Returns : nothing +" Author : Michael Sharpe (feline@irendi.com) www.irendi.com +function! AlternateOpenNextFile(bang) + let cursorFile = "" + if (exists("b:cursorFile")) + let cursorFile = b:cursorFile + endif + + let currentPath = "" + if (exists("b:currentPath")) + let currentPath = b:currentPath + endif + + let openCount = 0 + if (exists("b:openCount")) + let openCount = b:openCount + 1 + endif + + if (cursorFile != "" && currentPath != "" && openCount != 0) + let fileName = FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, openCount) + if (fileName != "") + call FindOrCreateBuffer(fileName, "n".a:bang, 0) + let b:openCount = openCount + let b:cursorFile = cursorFile + let b:currentPath = currentPath + else + let fileName = FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, 1) + if (fileName != "") + call FindOrCreateBuffer(fileName, "n".a:bang, 0) + let b:openCount = 1 + let b:cursorFile = cursorFile + let b:currentPath = currentPath + else + echo "Can't find next file" + endif + endif + endif +endfunction + +comm! -nargs=? -bang IH call AlternateOpenFileUnderCursor("n", ) +comm! -nargs=? -bang IHS call AlternateOpenFileUnderCursor("h", ) +comm! -nargs=? -bang IHV call AlternateOpenFileUnderCursor("v", ) +comm! -nargs=? -bang IHT call AlternateOpenFileUnderCursor("t", ) +comm! -nargs=? -bang IHN call AlternateOpenNextFile("") +imap ih :IHS +nmap ih :IHS +imap is :IHS:A +nmap is :IHS:A +imap ihn :IHN +nmap ihn :IHN + +"function! PrintList(theList) +" let n = 1 +" let oneFile = GetNthItemFromList(a:theList, n) +" while (oneFile != "") +" let n = n + 1 +" let oneFile = GetNthItemFromList(a:theList, n) +" endwhile +"endfunction + +" Function : NextAlternate (PUBLIC) +" Purpose : Used to cycle through any other alternate file which existed on +" the search path. +" Args : bang (IN) - used to implement the AN vs AN! functionality +" Returns : nothing +" Author : Michael Sharpe +function! NextAlternate(bang) + if (exists('b:AlternateAllFiles')) + let currentFile = expand("%") + let n = 1 + let onefile = GetNthItemFromList(b:AlternateAllFiles, n) + while (onefile != "" && !EqualFilePaths(fnamemodify(onefile,":p"), fnamemodify(currentFile,":p"))) + let n = n + 1 + let onefile = GetNthItemFromList(b:AlternateAllFiles, n) + endwhile + + if (onefile != "") + let stop = n + let n = n + 1 + let foundAlternate = 0 + let nextAlternate = "" + while (n != stop) + let nextAlternate = GetNthItemFromList(b:AlternateAllFiles, n) + if (nextAlternate == "") + let n = 1 + continue + endif + let n = n + 1 + if (EqualFilePaths(fnamemodify(nextAlternate, ":p"), fnamemodify(currentFile, ":p"))) + continue + endif + if (filereadable(nextAlternate)) + " on cygwin filereadable("foo.H") returns true if "foo.h" exists + if (has("unix") && $WINDIR != "" && fnamemodify(nextAlternate, ":p") ==? fnamemodify(currentFile, ":p")) + continue + endif + let foundAlternate = 1 + break + endif + endwhile + if (foundAlternate == 1) + let s:AlternateAllFiles = b:AlternateAllFiles + "silent! execute ":e".a:bang." " . nextAlternate + call FindOrCreateBuffer(nextAlternate, "n".a:bang, 0) + let b:AlternateAllFiles = s:AlternateAllFiles + else + echo "Only this alternate file exists" + endif + else + echo "Could not find current file in alternates list" + endif + else + echo "No other alternate files exist" + endif +endfunction + +comm! -nargs=? -bang A call AlternateFile("n", ) +comm! -nargs=? -bang AS call AlternateFile("h", ) +comm! -nargs=? -bang AV call AlternateFile("v", ) +comm! -nargs=? -bang AT call AlternateFile("t", ) +comm! -nargs=? -bang AN call NextAlternate("") + +" Function : BufferOrFileExists (PRIVATE) +" Purpose : determines if a buffer or a readable file exists +" Args : fileName (IN) - name of the file to check +" Returns : 2 if it exists in memory, 1 if it exists, 0 otherwise +" Author : Michael Sharpe +" History : Updated code to handle buffernames using just the +" filename and not the path. +function! BufferOrFileExists(fileName) + let result = 0 + + let lastBuffer = bufnr("$") + let i = 1 + while i <= lastBuffer + if EqualFilePaths(expand("#".i.":p"), a:fileName) + let result = 2 + break + endif + let i = i + 1 + endwhile + + if (!result) + let bufName = fnamemodify(a:fileName,":t") + let memBufName = bufname(bufName) + if (memBufName != "") + let memBufBasename = fnamemodify(memBufName, ":t") + if (bufName == memBufBasename) + let result = 2 + endif + endif + + if (!result) + let result = bufexists(bufName) || bufexists(a:fileName) || filereadable(a:fileName) + endif + endif + + if (!result) + let result = filereadable(a:fileName) + endif + return result +endfunction + +" Function : FindOrCreateBuffer (PRIVATE) +" Purpose : searches the buffer list (:ls) for the specified filename. If +" found, checks the window list for the buffer. If the buffer is in +" an already open window, it switches to the window. If the buffer +" was not in a window, it switches to that buffer. If the buffer did +" not exist, it creates it. +" Args : filename (IN) -- the name of the file +" doSplit (IN) -- indicates whether the window should be split +" ("v", "h", "n", "v!", "h!", "n!", "t", "t!") +" findSimilar (IN) -- indicate weather existing buffers should be +" prefered +" Returns : nothing +" Author : Michael Sharpe +" History : + bufname() was not working very well with the possibly strange +" paths that can abound with the search path so updated this +" slightly. -- Bindu +" + updated window switching code to make it more efficient -- Bindu +" Allow ! to be applied to buffer/split/editing commands for more +" vim/vi like consistency +" + implemented fix from Matt Perry +function! FindOrCreateBuffer(fileName, doSplit, findSimilar) + " Check to see if the buffer is already open before re-opening it. + let FILENAME = escape(a:fileName, ' ') + let bufNr = -1 + let lastBuffer = bufnr("$") + let i = 1 + if (a:findSimilar) + while i <= lastBuffer + if EqualFilePaths(expand("#".i.":p"), a:fileName) + let bufNr = i + break + endif + let i = i + 1 + endwhile + + if (bufNr == -1) + let bufName = bufname(a:fileName) + let bufFilename = fnamemodify(a:fileName,":t") + + if (bufName == "") + let bufName = bufname(bufFilename) + endif + + if (bufName != "") + let tail = fnamemodify(bufName, ":t") + if (tail != bufFilename) + let bufName = "" + endif + endif + if (bufName != "") + let bufNr = bufnr(bufName) + let FILENAME = bufName + endif + endif + endif + + if (g:alternateRelativeFiles == 1) + let FILENAME = fnamemodify(FILENAME, ":p:.") + endif + + let splitType = a:doSplit[0] + let bang = a:doSplit[1] + if (bufNr == -1) + " Buffer did not exist....create it + let v:errmsg="" + if (splitType == "h") + silent! execute ":split".bang." " . FILENAME + elseif (splitType == "v") + silent! execute ":vsplit".bang." " . FILENAME + elseif (splitType == "t") + silent! execute ":tab split".bang." " . FILENAME + else + silent! execute ":e".bang." " . FILENAME + endif + if (v:errmsg != "") + echo v:errmsg + endif + else + + " Find the correct tab corresponding to the existing buffer + let tabNr = -1 + " iterate tab pages + for i in range(tabpagenr('$')) + " get the list of buffers in the tab + let tabList = tabpagebuflist(i + 1) + let idx = 0 + " iterate each buffer in the list + while idx < len(tabList) + " if it matches the buffer we are looking for... + if (tabList[idx] == bufNr) + " ... save the number + let tabNr = i + 1 + break + endif + let idx = idx + 1 + endwhile + if (tabNr != -1) + break + endif + endfor + " switch the the tab containing the buffer + if (tabNr != -1) + execute "tabn ".tabNr + endif + + " Buffer was already open......check to see if it is in a window + let bufWindow = bufwinnr(bufNr) + if (bufWindow == -1) + " Buffer was not in a window so open one + let v:errmsg="" + if (splitType == "h") + silent! execute ":sbuffer".bang." " . FILENAME + elseif (splitType == "v") + silent! execute ":vert sbuffer " . FILENAME + elseif (splitType == "t") + silent! execute ":tab sbuffer " . FILENAME + else + silent! execute ":buffer".bang." " . FILENAME + endif + if (v:errmsg != "") + echo v:errmsg + endif + else + " Buffer is already in a window so switch to the window + execute bufWindow."wincmd w" + if (bufWindow != winnr()) + " something wierd happened...open the buffer + let v:errmsg="" + if (splitType == "h") + silent! execute ":split".bang." " . FILENAME + elseif (splitType == "v") + silent! execute ":vsplit".bang." " . FILENAME + elseif (splitType == "t") + silent! execute ":tab split".bang." " . FILENAME + else + silent! execute ":e".bang." " . FILENAME + endif + if (v:errmsg != "") + echo v:errmsg + endif + endif + endif + endif +endfunction + +" Function : EqualFilePaths (PRIVATE) +" Purpose : Compares two paths. Do simple string comparison anywhere but on +" Windows. On Windows take into account that file paths could differ +" in usage of separators and the fact that case does not matter. +" "c:\WINDOWS" is the same path as "c:/windows". has("win32unix") Vim +" version does not count as one having Windows path rules. +" Args : path1 (IN) -- first path +" path2 (IN) -- second path +" Returns : 1 if path1 is equal to path2, 0 otherwise. +" Author : Ilya Bobir +function! EqualFilePaths(path1, path2) + if has("win16") || has("win32") || has("win64") || has("win95") + return substitute(a:path1, "\/", "\\", "g") ==? substitute(a:path2, "\/", "\\", "g") + else + return a:path1 == a:path2 + endif +endfunction diff --git a/.vim/plugin/cscope_maps.vim b/.vim/plugin/cscope_maps.vim new file mode 100644 index 0000000..c577b45 --- /dev/null +++ b/.vim/plugin/cscope_maps.vim @@ -0,0 +1,165 @@ +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" CSCOPE settings for vim +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" +" This file contains some boilerplate settings for vim's cscope interface, +" plus some keyboard mappings that I've found useful. +" +" USAGE: +" -- vim 6: Stick this file in your ~/.vim/plugin directory (or in a +" 'plugin' directory in some other directory that is in your +" 'runtimepath'. +" +" -- vim 5: Stick this file somewhere and 'source cscope.vim' it from +" your ~/.vimrc file (or cut and paste it into your .vimrc). +" +" NOTE: +" These key maps use multiple keystrokes (2 or 3 keys). If you find that vim +" keeps timing you out before you can complete them, try changing your timeout +" settings, as explained below. +" +" Happy cscoping, +" +" Jason Duell jduell@alumni.princeton.edu 2002/3/7 +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + + +" This tests to see if vim was configured with the '--enable-cscope' option +" when it was compiled. If it wasn't, time to recompile vim... +if has("cscope") + + """"""""""""" Standard cscope/vim boilerplate + + " use both cscope and ctag for 'ctrl-]', ':ta', and 'vim -t' + set cscopetag + + " check cscope for definition of a symbol before checking ctags: set to 1 + " if you want the reverse search order. + set csto=0 + + " add any cscope database in current directory + if filereadable("cscope.out") + cs add cscope.out + " else add the database pointed to by environment variable + elseif $CSCOPE_DB != "" + cs add $CSCOPE_DB + endif + + " show msg when any other cscope db added + set cscopeverbose + + + """"""""""""" My cscope/vim key mappings + " + " The following maps all invoke one of the following cscope search types: + " + " 's' symbol: find all references to the token under cursor + " 'g' global: find global definition(s) of the token under cursor + " 'c' calls: find all calls to the function name under cursor + " 't' text: find all instances of the text under cursor + " 'e' egrep: egrep search for the word under cursor + " 'f' file: open the filename under cursor + " 'i' includes: find files that include the filename under cursor + " 'd' called: find functions that function under cursor calls + " + " Below are three sets of the maps: one set that just jumps to your + " search result, one that splits the existing vim window horizontally and + " diplays your search result in the new window, and one that does the same + " thing, but does a vertical split instead (vim 6 only). + " + " I've used CTRL-\ and CTRL-@ as the starting keys for these maps, as it's + " unlikely that you need their default mappings (CTRL-\'s default use is + " as part of CTRL-\ CTRL-N typemap, which basically just does the same + " thing as hitting 'escape': CTRL-@ doesn't seem to have any default use). + " If you don't like using 'CTRL-@' or CTRL-\, , you can change some or all + " of these maps to use other keys. One likely candidate is 'CTRL-_' + " (which also maps to CTRL-/, which is easier to type). By default it is + " used to switch between Hebrew and English keyboard mode. + " + " All of the maps involving the macro use '^$': this is so + " that searches over '#include " return only references to + " 'time.h', and not 'sys/time.h', etc. (by default cscope will return all + " files that contain 'time.h' as part of their name). + + + " To do the first type of search, hit 'CTRL-\', followed by one of the + " cscope search types above (s,g,c,t,e,f,i,d). The result of your cscope + " search will be displayed in the current window. You can use CTRL-T to + " go back to where you were before the search. + " + + nmap s :cs find s =expand("") + nmap g :cs find g =expand("") + nmap c :cs find c =expand("") + nmap t :cs find t =expand("") + nmap e :cs find e =expand("") + nmap f :cs find f =expand("") + nmap i :cs find i ^=expand("")$ + nmap d :cs find d =expand("") + + + " Using 'CTRL-spacebar' (intepreted as CTRL-@ by vim) then a search type + " makes the vim window split horizontally, with search result displayed in + " the new window. + " + " (Note: earlier versions of vim may not have the :scs command, but it + " can be simulated roughly via: + " nmap s :cs find s =expand("") + + nmap s :scs find s =expand("") + nmap g :scs find g =expand("") + nmap c :scs find c =expand("") + nmap t :scs find t =expand("") + nmap e :scs find e =expand("") + nmap f :scs find f =expand("") + nmap i :scs find i ^=expand("")$ + nmap d :scs find d =expand("") + + + " Hitting CTRL-space *twice* before the search type does a vertical + " split instead of a horizontal one (vim 6 and up only) + " + " (Note: you may wish to put a 'set splitright' in your .vimrc + " if you prefer the new window on the right instead of the left + + nmap s :vert scs find s =expand("") + nmap g :vert scs find g =expand("") + nmap c :vert scs find c =expand("") + nmap t :vert scs find t =expand("") + nmap e :vert scs find e =expand("") + nmap f :vert scs find f =expand("") + nmap i :vert scs find i ^=expand("")$ + nmap d :vert scs find d =expand("") + + + """"""""""""" key map timeouts + " + " By default Vim will only wait 1 second for each keystroke in a mapping. + " You may find that too short with the above typemaps. If so, you should + " either turn off mapping timeouts via 'notimeout'. + " + "set notimeout + " + " Or, you can keep timeouts, by uncommenting the timeoutlen line below, + " with your own personal favorite value (in milliseconds): + " + "set timeoutlen=4000 + " + " Either way, since mapping timeout settings by default also set the + " timeouts for multicharacter 'keys codes' (like ), you should also + " set ttimeout and ttimeoutlen: otherwise, you will experience strange + " delays as vim waits for a keystroke after you hit ESC (it will be + " waiting to see if the ESC is actually part of a key code like ). + " + "set ttimeout + " + " personally, I find a tenth of a second to work well for key code + " timeouts. If you experience problems and have a slow terminal or network + " connection, set it higher. If you don't set ttimeoutlen, the value for + " timeoutlent (default: 1000 = 1 second, which is sluggish) is used. + " + "set ttimeoutlen=100 + +endif + + diff --git a/.vim/plugin/fuf.vim b/.vim/plugin/fuf.vim new file mode 100644 index 0000000..9826dab --- /dev/null +++ b/.vim/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/.vim/plugin/po.vim b/.vim/plugin/po.vim new file mode 100644 index 0000000..124d524 --- /dev/null +++ b/.vim/plugin/po.vim @@ -0,0 +1,135 @@ +" Vim syntax file +" Language: po (gettext) +" Maintainer: Dwayne Bailey +" Last Change: 2008 Jan 08 +" Contributors: Dwayne Bailey (Most advanced syntax highlighting) +" Leonardo Fontenelle (Spell checking) +" Nam SungHyun (Original maintainer) + +" For version 5.x: Clear all syntax items +" For version 6.x: Quit when a syntax file was already loaded +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + +syn sync minlines=10 + +" Identifiers +syn match poStatementMsgCTxt "^msgctxt" +syn match poStatementMsgidplural "^msgid_plural" contained +syn match poPluralCaseN "[0-9]" contained +syn match poStatementMsgstr "^msgstr\(\[[0-9]\]\)" contains=poPluralCaseN + +" Simple HTML and XML highlighting +syn match poHtml "<\_[^<>]\+>" contains=poHtmlTranslatables,poLineBreak +syn match poHtmlNot +"<[^<]\+>"+ms=s+1,me=e-1 +syn region poHtmlTranslatables start=+\(abbr\|alt\|content\|summary\|standby\|title\)=\\"+ms=e-1 end=+\\"+ contained contains=@Spell +syn match poLineBreak +"\n"+ contained + +" Translation blocks +syn region poMsgCTxt matchgroup=poStatementMsgCTxt start=+^msgctxt "+rs=e-1 matchgroup=poStringCTxt end=+^msgid "+me=s-1 contains=poStringCTxt +syn region poMsgID matchgroup=poStatementMsgid start=+^msgid "+rs=e-1 matchgroup=poStringID end=+^msgstr\(\|\[[\]0\[]\]\) "+me=s-1 contains=poStringID,poStatementMsgidplural,poStatementMsgid +syn region poMsgSTR matchgroup=poStatementMsgstr start=+^msgstr\(\|\[[\]0\[]\]\) "+rs=e-1 matchgroup=poStringSTR end=+\n\n+me=s-1 contains=poStringSTR,poStatementMsgstr +syn region poStringCTxt start=+"+ skip=+\\\\\|\\"+ end=+"+ +syn region poStringID start=+"+ skip=+\\\\\|\\"+ end=+"+ contained + \ contains=poSpecial,poFormat,poCommentKDE,poPluralKDE,poKDEdesktopFile,poHtml,poAcceleratorId,poHtmlNot,poVariable +syn region poStringSTR start=+"+ skip=+\\\\\|\\"+ end=+"+ contained + \ contains=@Spell,poSpecial,poFormat,poHeaderItem,poCommentKDEError,poHeaderUndefined,poPluralKDEError,poMsguniqError,poKDEdesktopFile,poHtml,poAcceleratorStr,poHtmlNot,poVariable + +" Header and Copyright +syn match poHeaderItem "\(Project-Id-Version\|Report-Msgid-Bugs-To\|POT-Creation-Date\|PO-Revision-Date\|Last-Translator\|Language-Team\|MIME-Version\|Content-Type\|Content-Transfer-Encoding\|Plural-Forms\|X-Generator\): " contained +syn match poHeaderUndefined "\(PACKAGE VERSION\|YEAR-MO-DA HO:MI+ZONE\|FULL NAME \|LANGUAGE \|CHARSET\|ENCODING\|INTEGER\|EXPRESSION\)" contained +syn match poCopyrightUnset "SOME DESCRIPTIVE TITLE\|FIRST AUTHOR , YEAR\|Copyright (C) YEAR Free Software Foundation, Inc\|YEAR THE PACKAGE\'S COPYRIGHT HOLDER\|PACKAGE" contained + +" Translation comment block including: translator comment, automatic coments, flags and locations +syn match poComment "^#.*$" +syn keyword poFlagFuzzy fuzzy contained +syn match poCommentTranslator "^# .*$" contains=poCopyrightUnset +syn match poCommentAutomatic "^#\..*$" +syn match poCommentSources "^#:.*$" +syn match poCommentFlags "^#,.*$" contains=poFlagFuzzy + +" Translations (also includes header fields as they appear in a translation msgstr) +syn region poCommentKDE start=+"_: +ms=s+1 end="\\n" end="\"\n^msgstr"me=s-1 contained +syn region poCommentKDEError start=+"\(\|\s\+\)_:+ms=s+1 end="\\n" end=+"\n\n+me=s-1 contained +syn match poPluralKDE +"_n: +ms=s+1 contained +syn region poPluralKDEError start=+"\(\|\s\+\)_n:+ms=s+1 end="\"\n\n"me=s-1 contained +syn match poSpecial contained "\\\(x\x\+\|\o\{1,3}\|.\|$\)" +syn match poFormat "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlL]\|ll\)\=\([diuoxXfeEgGcCsSpn]\|\[\^\=.[^]]*\]\)" contained +syn match poFormat "%%" contained + +" msguniq and msgcat conflicts +syn region poMsguniqError matchgroup=poMsguniqErrorMarkers start="#-#-#-#-#" end='#\("\n"\|\)-\("\n"\|\)#\("\n"\|\)-\("\n"\|\)#\("\n"\|\)-\("\n"\|\)#\("\n"\|\)-\("\n"\|\)#\("\n"\|\)\\n' contained + +" Obsolete messages +syn match poObsolete "^#\~.*$" + +" KDE Name= handling +syn match poKDEdesktopFile "\"\(Name\|Comment\|GenericName\|Description\|Keywords\|About\)="ms=s+1,me=e-1 + +" Accelerator keys - this messes up if the preceding or following char is a multibyte unicode char +syn match poAcceleratorId contained "[^&_~][&_~]\(\a\|\d\)[^:]"ms=s+1,me=e-1 +syn match poAcceleratorStr contained "[^&_~][&_~]\(\a\|\d\)[^:]"ms=s+1,me=e-1 contains=@Spell + +" Variables simple +syn match poVariable contained "%\d" + +" Define the default highlighting. +" For version 5.7 and earlier: only when not done already +" For version 5.8 and later: only when an item doesn't have highlighting yet +if version >= 508 || !exists("did_po_syn_inits") + if version < 508 + let did_po_syn_inits = 1 + command -nargs=+ HiLink hi link + else + command -nargs=+ HiLink hi def link + endif + + HiLink poCommentSources PreProc + HiLink poComment Comment + HiLink poCommentAutomatic Comment + HiLink poCommentTranslator Comment + HiLink poCommentFlags Special + HiLink poCopyrightUnset Todo + HiLink poFlagFuzzy Todo + HiLink poObsolete Comment + + HiLink poStatementMsgid Statement + HiLink poStatementMsgstr Statement + HiLink poStatementMsgidplural Statement + HiLink poStatementMsgCTxt Statement + HiLink poPluralCaseN Constant + + HiLink poStringCTxt Comment + HiLink poStringID String + HiLink poStringSTR String + HiLink poCommentKDE Comment + HiLink poCommentKDEError Error + HiLink poPluralKDE Comment + HiLink poPluralKDEError Error + HiLink poHeaderItem Identifier + HiLink poHeaderUndefined Todo + HiLink poKDEdesktopFile Identifier + + HiLink poHtml Identifier + HiLink poHtmlNot String + HiLink poHtmlTranslatables String + HiLink poLineBreak String + + HiLink poFormat poSpecial + HiLink poSpecial Special + HiLink poAcceleratorId Special + HiLink poAcceleratorStr Special + HiLink poVariable Special + + HiLink poMsguniqError Special + HiLink poMsguniqErrorMarkers Comment + + delcommand HiLink +endif + +let b:current_syntax = "po" + +" vim:set ts=8 sts=2 sw=2 noet: diff --git a/.vim/plugin/taglist.vim b/.vim/plugin/taglist.vim new file mode 100644 index 0000000..59901f6 --- /dev/null +++ b/.vim/plugin/taglist.vim @@ -0,0 +1,4546 @@ +" File: taglist.vim +" Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) +" Version: 4.5 +" Last Modified: September 21, 2007 +" Copyright: Copyright (C) 2002-2007 Yegappan Lakshmanan +" Permission is hereby granted to use and distribute this code, +" with or without modifications, provided that this copyright +" notice is copied with it. Like anything else that's free, +" taglist.vim is provided *as is* and comes with no warranty of any +" kind, either expressed or implied. In no event will the copyright +" holder be liable for any damamges resulting from the use of this +" software. +" +" The "Tag List" plugin is a source code browser plugin for Vim and provides +" an overview of the structure of the programming language files and allows +" you to efficiently browse through source code files for different +" programming languages. You can visit the taglist plugin home page for more +" information: +" +" http://vim-taglist.sourceforge.net +" +" You can subscribe to the taglist mailing list to post your questions +" or suggestions for improvement or to report bugs. Visit the following +" page for subscribing to the mailing list: +" +" http://groups.yahoo.com/group/taglist/ +" +" For more information about using this plugin, after installing the +" taglist plugin, use the ":help taglist" command. +" +" Installation +" ------------ +" 1. Download the taglist.zip file and unzip the files to the $HOME/.vim +" or the $HOME/vimfiles or the $VIM/vimfiles directory. This should +" unzip the following two files (the directory structure should be +" preserved): +" +" plugin/taglist.vim - main taglist plugin file +" doc/taglist.txt - documentation (help) file +" +" Refer to the 'add-plugin', 'add-global-plugin' and 'runtimepath' +" Vim help pages for more details about installing Vim plugins. +" 2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or +" $VIM/vimfiles/doc directory, start Vim and run the ":helptags ." +" command to process the taglist help file. +" 3. If the exuberant ctags utility is not present in your PATH, then set the +" Tlist_Ctags_Cmd variable to point to the location of the exuberant ctags +" utility (not to the directory) in the .vimrc file. +" 4. If you are running a terminal/console version of Vim and the +" terminal doesn't support changing the window width then set the +" 'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file. +" 5. Restart Vim. +" 6. You can now use the ":TlistToggle" command to open/close the taglist +" window. You can use the ":help taglist" command to get more +" information about using the taglist plugin. +" +" ****************** Do not modify after this line ************************ + +" Line continuation used here +let s:cpo_save = &cpo +set cpo&vim + +if !exists('loaded_taglist') + " First time loading the taglist plugin + " + " To speed up the loading of Vim, the taglist plugin uses autoload + " mechanism to load the taglist functions. + " Only define the configuration variables, user commands and some + " auto-commands and finish sourcing the file + + " The taglist plugin requires the built-in Vim system() function. If this + " function is not available, then don't load the plugin. + if !exists('*system') + echomsg 'Taglist: Vim system() built-in function is not available. ' . + \ 'Plugin is not loaded.' + let loaded_taglist = 'no' + let &cpo = s:cpo_save + finish + endif + + " Location of the exuberant ctags tool + if !exists('Tlist_Ctags_Cmd') + if executable('exuberant-ctags') + " On Debian Linux, exuberant ctags is installed + " as exuberant-ctags + let Tlist_Ctags_Cmd = 'exuberant-ctags' + elseif executable('exctags') + " On Free-BSD, exuberant ctags is installed as exctags + let Tlist_Ctags_Cmd = 'exctags' + elseif executable('ctags') + let Tlist_Ctags_Cmd = 'ctags' + elseif executable('ctags.exe') + let Tlist_Ctags_Cmd = 'ctags.exe' + elseif executable('tags') + let Tlist_Ctags_Cmd = 'tags' + else + echomsg 'Taglist: Exuberant ctags (http://ctags.sf.net) ' . + \ 'not found in PATH. Plugin is not loaded.' + " Skip loading the plugin + let loaded_taglist = 'no' + let &cpo = s:cpo_save + finish + endif + endif + + + " Automatically open the taglist window on Vim startup + if !exists('Tlist_Auto_Open') + let Tlist_Auto_Open = 0 + endif + + " When the taglist window is toggle opened, move the cursor to the + " taglist window + if !exists('Tlist_GainFocus_On_ToggleOpen') + let Tlist_GainFocus_On_ToggleOpen = 0 + endif + + " Process files even when the taglist window is not open + if !exists('Tlist_Process_File_Always') + let Tlist_Process_File_Always = 0 + endif + + if !exists('Tlist_Show_Menu') + let Tlist_Show_Menu = 0 + endif + + " Tag listing sort type - 'name' or 'order' + if !exists('Tlist_Sort_Type') + let Tlist_Sort_Type = 'order' + endif + + " Tag listing window split (horizontal/vertical) control + if !exists('Tlist_Use_Horiz_Window') + let Tlist_Use_Horiz_Window = 0 + endif + + " Open the vertically split taglist window on the left or on the right + " side. This setting is relevant only if Tlist_Use_Horiz_Window is set to + " zero (i.e. only for vertically split windows) + if !exists('Tlist_Use_Right_Window') + let Tlist_Use_Right_Window = 0 + endif + + " Increase Vim window width to display vertically split taglist window. + " For MS-Windows version of Vim running in a MS-DOS window, this must be + " set to 0 otherwise the system may hang due to a Vim limitation. + if !exists('Tlist_Inc_Winwidth') + if (has('win16') || has('win95')) && !has('gui_running') + let Tlist_Inc_Winwidth = 0 + else + let Tlist_Inc_Winwidth = 1 + endif + endif + + " Vertically split taglist window width setting + if !exists('Tlist_WinWidth') + let Tlist_WinWidth = 30 + endif + + " Horizontally split taglist window height setting + if !exists('Tlist_WinHeight') + let Tlist_WinHeight = 10 + endif + + " Display tag prototypes or tag names in the taglist window + if !exists('Tlist_Display_Prototype') + let Tlist_Display_Prototype = 0 + endif + + " Display tag scopes in the taglist window + if !exists('Tlist_Display_Tag_Scope') + let Tlist_Display_Tag_Scope = 1 + endif + + " Use single left mouse click to jump to a tag. By default this is disabled. + " Only double click using the mouse will be processed. + if !exists('Tlist_Use_SingleClick') + let Tlist_Use_SingleClick = 0 + endif + + " Control whether additional help is displayed as part of the taglist or + " not. Also, controls whether empty lines are used to separate the tag + " tree. + if !exists('Tlist_Compact_Format') + let Tlist_Compact_Format = 0 + endif + + " Exit Vim if only the taglist window is currently open. By default, this is + " set to zero. + if !exists('Tlist_Exit_OnlyWindow') + let Tlist_Exit_OnlyWindow = 0 + endif + + " Automatically close the folds for the non-active files in the taglist + " window + if !exists('Tlist_File_Fold_Auto_Close') + let Tlist_File_Fold_Auto_Close = 0 + endif + + " Close the taglist window when a tag is selected + if !exists('Tlist_Close_On_Select') + let Tlist_Close_On_Select = 0 + endif + + " Automatically update the taglist window to display tags for newly + " edited files + if !exists('Tlist_Auto_Update') + let Tlist_Auto_Update = 1 + endif + + " Automatically highlight the current tag + if !exists('Tlist_Auto_Highlight_Tag') + let Tlist_Auto_Highlight_Tag = 1 + endif + + " Automatically highlight the current tag on entering a buffer + if !exists('Tlist_Highlight_Tag_On_BufEnter') + let Tlist_Highlight_Tag_On_BufEnter = 1 + endif + + " Enable fold column to display the folding for the tag tree + if !exists('Tlist_Enable_Fold_Column') + let Tlist_Enable_Fold_Column = 1 + endif + + " Display the tags for only one file in the taglist window + if !exists('Tlist_Show_One_File') + let Tlist_Show_One_File = 0 + endif + + if !exists('Tlist_Max_Submenu_Items') + let Tlist_Max_Submenu_Items = 20 + endif + + if !exists('Tlist_Max_Tag_Length') + let Tlist_Max_Tag_Length = 10 + endif + + " Do not change the name of the taglist title variable. The winmanager + " plugin relies on this name to determine the title for the taglist + " plugin. + let TagList_title = "__Tag_List__" + + " Taglist debug messages + let s:tlist_msg = '' + + " Define the taglist autocommand to automatically open the taglist window + " on Vim startup + if g:Tlist_Auto_Open + autocmd VimEnter * nested call s:Tlist_Window_Check_Auto_Open() + endif + + " Refresh the taglist + if g:Tlist_Process_File_Always + autocmd BufEnter * call s:Tlist_Refresh() + endif + + if g:Tlist_Show_Menu + autocmd GUIEnter * call s:Tlist_Menu_Init() + endif + + " When the taglist buffer is created when loading a Vim session file, + " the taglist buffer needs to be initialized. The BufFilePost event + " is used to handle this case. + autocmd BufFilePost __Tag_List__ call s:Tlist_Vim_Session_Load() + + " Define the user commands to manage the taglist window + command! -nargs=0 -bar TlistToggle call s:Tlist_Window_Toggle() + command! -nargs=0 -bar TlistOpen call s:Tlist_Window_Open() + " For backwards compatiblity define the Tlist command + command! -nargs=0 -bar Tlist TlistToggle + command! -nargs=+ -complete=file TlistAddFiles + \ call s:Tlist_Add_Files() + command! -nargs=+ -complete=dir TlistAddFilesRecursive + \ call s:Tlist_Add_Files_Recursive() + command! -nargs=0 -bar TlistClose call s:Tlist_Window_Close() + command! -nargs=0 -bar TlistUpdate call s:Tlist_Update_Current_File() + command! -nargs=0 -bar TlistHighlightTag call s:Tlist_Window_Highlight_Tag( + \ fnamemodify(bufname('%'), ':p'), line('.'), 2, 1) + " For backwards compatiblity define the TlistSync command + command! -nargs=0 -bar TlistSync TlistHighlightTag + command! -nargs=* -complete=buffer TlistShowPrototype + \ echo Tlist_Get_Tag_Prototype_By_Line() + command! -nargs=* -complete=buffer TlistShowTag + \ echo Tlist_Get_Tagname_By_Line() + command! -nargs=* -complete=file TlistSessionLoad + \ call s:Tlist_Session_Load() + command! -nargs=* -complete=file TlistSessionSave + \ call s:Tlist_Session_Save() + command! -bar TlistLock let Tlist_Auto_Update=0 + command! -bar TlistUnlock let Tlist_Auto_Update=1 + + " Commands for enabling/disabling debug and to display debug messages + command! -nargs=? -complete=file -bar TlistDebug + \ call s:Tlist_Debug_Enable() + command! -nargs=0 -bar TlistUndebug call s:Tlist_Debug_Disable() + command! -nargs=0 -bar TlistMessages call s:Tlist_Debug_Show() + + " Define autocommands to autoload the taglist plugin when needed. + + " Trick to get the current script ID + map xx xx + let s:tlist_sid = substitute(maparg('xx'), '\(\d\+_\)xx$', + \ '\1', '') + unmap xx + + exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_* source ' . + \ escape(expand(''), ' ') + exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Window_* source ' . + \ escape(expand(''), ' ') + exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Menu_* source ' . + \ escape(expand(''), ' ') + exe 'autocmd FuncUndefined Tlist_* source ' . + \ escape(expand(''), ' ') + exe 'autocmd FuncUndefined TagList_* source ' . + \ escape(expand(''), ' ') + + let loaded_taglist = 'fast_load_done' + + if g:Tlist_Show_Menu && has('gui_running') + call s:Tlist_Menu_Init() + endif + + " restore 'cpo' + let &cpo = s:cpo_save + finish +endif + +if !exists('s:tlist_sid') + " Two or more versions of taglist plugin are installed. Don't + " load this version of the plugin. + finish +endif + +unlet! s:tlist_sid + +if loaded_taglist != 'fast_load_done' + " restore 'cpo' + let &cpo = s:cpo_save + finish +endif + +" Taglist plugin functionality is available +let loaded_taglist = 'available' + +"------------------- end of user configurable options -------------------- + +" Default language specific settings for supported file types and tag types +" +" Variable name format: +" +" s:tlist_def_{vim_ftype}_settings +" +" vim_ftype - Filetype detected by Vim +" +" Value format: +" +" ;:;:;... +" +" ctags_ftype - File type supported by exuberant ctags +" flag - Flag supported by exuberant ctags to generate a tag type +" name - Name of the tag type used in the taglist window to display the +" tags of this type +" + +" assembly language +let s:tlist_def_asm_settings = 'asm;d:define;l:label;m:macro;t:type' + +" aspperl language +let s:tlist_def_aspperl_settings = 'asp;f:function;s:sub;v:variable' + +" aspvbs language +let s:tlist_def_aspvbs_settings = 'asp;f:function;s:sub;v:variable' + +" awk language +let s:tlist_def_awk_settings = 'awk;f:function' + +" beta language +let s:tlist_def_beta_settings = 'beta;f:fragment;s:slot;v:pattern' + +" c language +let s:tlist_def_c_settings = 'c;d:macro;g:enum;s:struct;u:union;t:typedef;' . + \ 'v:variable;f:function' + +" c++ language +let s:tlist_def_cpp_settings = 'c++;n:namespace;v:variable;d:macro;t:typedef;' . + \ 'c:class;g:enum;s:struct;u:union;f:function' + +" c# language +let s:tlist_def_cs_settings = 'c#;d:macro;t:typedef;n:namespace;c:class;' . + \ 'E:event;g:enum;s:struct;i:interface;' . + \ 'p:properties;m:method' + +" cobol language +let s:tlist_def_cobol_settings = 'cobol;d:data;f:file;g:group;p:paragraph;' . + \ 'P:program;s:section' + +" eiffel language +let s:tlist_def_eiffel_settings = 'eiffel;c:class;f:feature' + +" erlang language +let s:tlist_def_erlang_settings = 'erlang;d:macro;r:record;m:module;f:function' + +" expect (same as tcl) language +let s:tlist_def_expect_settings = 'tcl;c:class;f:method;p:procedure' + +" fortran language +let s:tlist_def_fortran_settings = 'fortran;p:program;b:block data;' . + \ 'c:common;e:entry;i:interface;k:type;l:label;m:module;' . + \ 'n:namelist;t:derived;v:variable;f:function;s:subroutine' + +" HTML language +let s:tlist_def_html_settings = 'html;a:anchor;f:javascript function' + +" java language +let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' . + \ 'f:field;m:method' + +" javascript language +let s:tlist_def_javascript_settings = 'javascript;f:function' + +" lisp language +let s:tlist_def_lisp_settings = 'lisp;f:function' + +" lua language +let s:tlist_def_lua_settings = 'lua;f:function' + +" makefiles +let s:tlist_def_make_settings = 'make;m:macro' + +" pascal language +let s:tlist_def_pascal_settings = 'pascal;f:function;p:procedure' + +" perl language +let s:tlist_def_perl_settings = 'perl;c:constant;l:label;p:package;s:subroutine' + +" php language +let s:tlist_def_php_settings = 'php;c:class;d:constant;v:variable;f:function' + +" python language +let s:tlist_def_python_settings = 'python;c:class;m:member;f:function' + +" rexx language +let s:tlist_def_rexx_settings = 'rexx;s:subroutine' + +" ruby language +let s:tlist_def_ruby_settings = 'ruby;c:class;f:method;F:function;' . + \ 'm:singleton method' + +" scheme language +let s:tlist_def_scheme_settings = 'scheme;s:set;f:function' + +" shell language +let s:tlist_def_sh_settings = 'sh;f:function' + +" C shell language +let s:tlist_def_csh_settings = 'sh;f:function' + +" Z shell language +let s:tlist_def_zsh_settings = 'sh;f:function' + +" slang language +let s:tlist_def_slang_settings = 'slang;n:namespace;f:function' + +" sml language +let s:tlist_def_sml_settings = 'sml;e:exception;c:functor;s:signature;' . + \ 'r:structure;t:type;v:value;f:function' + +" sql language +let s:tlist_def_sql_settings = 'sql;c:cursor;F:field;P:package;r:record;' . + \ 's:subtype;t:table;T:trigger;v:variable;f:function;p:procedure' + +" tcl language +let s:tlist_def_tcl_settings = 'tcl;c:class;f:method;m:method;p:procedure' + +" vera language +let s:tlist_def_vera_settings = 'vera;c:class;d:macro;e:enumerator;' . + \ 'f:function;g:enum;m:member;p:program;' . + \ 'P:prototype;t:task;T:typedef;v:variable;' . + \ 'x:externvar' + +"verilog language +let s:tlist_def_verilog_settings = 'verilog;m:module;c:constant;P:parameter;' . + \ 'e:event;r:register;t:task;w:write;p:port;v:variable;f:function' + +" vim language +let s:tlist_def_vim_settings = 'vim;a:autocmds;v:variable;f:function' + +" yacc language +let s:tlist_def_yacc_settings = 'yacc;l:label' + +"------------------- end of language specific options -------------------- + +" Vim window size is changed by the taglist plugin or not +let s:tlist_winsize_chgd = -1 +" Taglist window is maximized or not +let s:tlist_win_maximized = 0 +" Name of files in the taglist +let s:tlist_file_names='' +" Number of files in the taglist +let s:tlist_file_count = 0 +" Number of filetypes supported by taglist +let s:tlist_ftype_count = 0 +" Is taglist part of other plugins like winmanager or cream? +let s:tlist_app_name = "none" +" Are we displaying brief help text +let s:tlist_brief_help = 1 +" List of files removed on user request +let s:tlist_removed_flist = "" +" Index of current file displayed in the taglist window +let s:tlist_cur_file_idx = -1 +" Taglist menu is empty or not +let s:tlist_menu_empty = 1 + +" An autocommand is used to refresh the taglist window when entering any +" buffer. We don't want to refresh the taglist window if we are entering the +" file window from one of the taglist functions. The 'Tlist_Skip_Refresh' +" variable is used to skip the refresh of the taglist window and is set +" and cleared appropriately. +let s:Tlist_Skip_Refresh = 0 + +" Tlist_Window_Display_Help() +function! s:Tlist_Window_Display_Help() + if s:tlist_app_name == "winmanager" + " To handle a bug in the winmanager plugin, add a space at the + " last line + call setline('$', ' ') + endif + + if s:tlist_brief_help + " Add the brief help + call append(0, '" Press to display help text') + else + " Add the extensive help + call append(0, '" : Jump to tag definition') + call append(1, '" o : Jump to tag definition in new window') + call append(2, '" p : Preview the tag definition') + call append(3, '" : Display tag prototype') + call append(4, '" u : Update tag list') + call append(5, '" s : Select sort field') + call append(6, '" d : Remove file from taglist') + call append(7, '" x : Zoom-out/Zoom-in taglist window') + call append(8, '" + : Open a fold') + call append(9, '" - : Close a fold') + call append(10, '" * : Open all folds') + call append(11, '" = : Close all folds') + call append(12, '" [[ : Move to the start of previous file') + call append(13, '" ]] : Move to the start of next file') + call append(14, '" q : Close the taglist window') + call append(15, '" : Remove help text') + endif +endfunction + +" Tlist_Window_Toggle_Help_Text() +" Toggle taglist plugin help text between the full version and the brief +" version +function! s:Tlist_Window_Toggle_Help_Text() + if g:Tlist_Compact_Format + " In compact display mode, do not display help + return + endif + + " Include the empty line displayed after the help text + let brief_help_size = 1 + let full_help_size = 16 + + setlocal modifiable + + " Set report option to a huge value to prevent informational messages + " while deleting the lines + let old_report = &report + set report=99999 + + " Remove the currently highlighted tag. Otherwise, the help text + " might be highlighted by mistake + match none + + " Toggle between brief and full help text + if s:tlist_brief_help + let s:tlist_brief_help = 0 + + " Remove the previous help + exe '1,' . brief_help_size . ' delete _' + + " Adjust the start/end line numbers for the files + call s:Tlist_Window_Update_Line_Offsets(0, 1, full_help_size - brief_help_size) + else + let s:tlist_brief_help = 1 + + " Remove the previous help + exe '1,' . full_help_size . ' delete _' + + " Adjust the start/end line numbers for the files + call s:Tlist_Window_Update_Line_Offsets(0, 0, full_help_size - brief_help_size) + endif + + call s:Tlist_Window_Display_Help() + + " Restore the report option + let &report = old_report + + setlocal nomodifiable +endfunction + +" Taglist debug support +let s:tlist_debug = 0 + +" File for storing the debug messages +let s:tlist_debug_file = '' + +" Tlist_Debug_Enable +" Enable logging of taglist debug messages. +function! s:Tlist_Debug_Enable(...) + let s:tlist_debug = 1 + + " Check whether a valid file name is supplied. + if a:1 != '' + let s:tlist_debug_file = fnamemodify(a:1, ':p') + + " Empty the log file + exe 'redir! > ' . s:tlist_debug_file + redir END + + " Check whether the log file is present/created + if !filewritable(s:tlist_debug_file) + call s:Tlist_Warning_Msg('Taglist: Unable to create log file ' + \ . s:tlist_debug_file) + let s:tlist_debug_file = '' + endif + endif +endfunction + +" Tlist_Debug_Disable +" Disable logging of taglist debug messages. +function! s:Tlist_Debug_Disable(...) + let s:tlist_debug = 0 + let s:tlist_debug_file = '' +endfunction + +" Tlist_Debug_Show +" Display the taglist debug messages in a new window +function! s:Tlist_Debug_Show() + if s:tlist_msg == '' + call s:Tlist_Warning_Msg('Taglist: No debug messages') + return + endif + + " Open a new window to display the taglist debug messages + new taglist_debug.txt + " Delete all the lines (if the buffer already exists) + silent! %delete _ + " Add the messages + silent! put =s:tlist_msg + " Move the cursor to the first line + normal! gg +endfunction + +" Tlist_Log_Msg +" Log the supplied debug message along with the time +function! s:Tlist_Log_Msg(msg) + if s:tlist_debug + if s:tlist_debug_file != '' + exe 'redir >> ' . s:tlist_debug_file + silent echon strftime('%H:%M:%S') . ': ' . a:msg . "\n" + redir END + else + " Log the message into a variable + " Retain only the last 3000 characters + let len = strlen(s:tlist_msg) + if len > 3000 + let s:tlist_msg = strpart(s:tlist_msg, len - 3000) + endif + let s:tlist_msg = s:tlist_msg . strftime('%H:%M:%S') . ': ' . + \ a:msg . "\n" + endif + endif +endfunction + +" Tlist_Warning_Msg() +" Display a message using WarningMsg highlight group +function! s:Tlist_Warning_Msg(msg) + echohl WarningMsg + echomsg a:msg + echohl None +endfunction + +" Last returned file index for file name lookup. +" Used to speed up file lookup +let s:tlist_file_name_idx_cache = -1 + +" Tlist_Get_File_Index() +" Return the index of the specified filename +function! s:Tlist_Get_File_Index(fname) + if s:tlist_file_count == 0 || a:fname == '' + return -1 + endif + + " If the new filename is same as the last accessed filename, then + " return that index + if s:tlist_file_name_idx_cache != -1 && + \ s:tlist_file_name_idx_cache < s:tlist_file_count + if s:tlist_{s:tlist_file_name_idx_cache}_filename == a:fname + " Same as the last accessed file + return s:tlist_file_name_idx_cache + endif + endif + + " First, check whether the filename is present + let s_fname = a:fname . "\n" + let i = stridx(s:tlist_file_names, s_fname) + if i == -1 + let s:tlist_file_name_idx_cache = -1 + return -1 + endif + + " Second, compute the file name index + let nl_txt = substitute(strpart(s:tlist_file_names, 0, i), "[^\n]", '', 'g') + let s:tlist_file_name_idx_cache = strlen(nl_txt) + return s:tlist_file_name_idx_cache +endfunction + +" Last returned file index for line number lookup. +" Used to speed up file lookup +let s:tlist_file_lnum_idx_cache = -1 + +" Tlist_Window_Get_File_Index_By_Linenum() +" Return the index of the filename present in the specified line number +" Line number refers to the line number in the taglist window +function! s:Tlist_Window_Get_File_Index_By_Linenum(lnum) + call s:Tlist_Log_Msg('Tlist_Window_Get_File_Index_By_Linenum (' . a:lnum . ')') + + " First try to see whether the new line number is within the range + " of the last returned file + if s:tlist_file_lnum_idx_cache != -1 && + \ s:tlist_file_lnum_idx_cache < s:tlist_file_count + if a:lnum >= s:tlist_{s:tlist_file_lnum_idx_cache}_start && + \ a:lnum <= s:tlist_{s:tlist_file_lnum_idx_cache}_end + return s:tlist_file_lnum_idx_cache + endif + endif + + let fidx = -1 + + if g:Tlist_Show_One_File + " Displaying only one file in the taglist window. Check whether + " the line is within the tags displayed for that file + if s:tlist_cur_file_idx != -1 + if a:lnum >= s:tlist_{s:tlist_cur_file_idx}_start + \ && a:lnum <= s:tlist_{s:tlist_cur_file_idx}_end + let fidx = s:tlist_cur_file_idx + endif + + endif + else + " Do a binary search in the taglist + let left = 0 + let right = s:tlist_file_count - 1 + + while left < right + let mid = (left + right) / 2 + + if a:lnum >= s:tlist_{mid}_start && a:lnum <= s:tlist_{mid}_end + let s:tlist_file_lnum_idx_cache = mid + return mid + endif + + if a:lnum < s:tlist_{mid}_start + let right = mid - 1 + else + let left = mid + 1 + endif + endwhile + + if left >= 0 && left < s:tlist_file_count + \ && a:lnum >= s:tlist_{left}_start + \ && a:lnum <= s:tlist_{left}_end + let fidx = left + endif + endif + + let s:tlist_file_lnum_idx_cache = fidx + + return fidx +endfunction + +" Tlist_Exe_Cmd_No_Acmds +" Execute the specified Ex command after disabling autocommands +function! s:Tlist_Exe_Cmd_No_Acmds(cmd) + let old_eventignore = &eventignore + set eventignore=all + exe a:cmd + let &eventignore = old_eventignore +endfunction + +" Tlist_Skip_File() +" Check whether tag listing is supported for the specified file +function! s:Tlist_Skip_File(filename, ftype) + " Skip buffers with no names and buffers with filetype not set + if a:filename == '' || a:ftype == '' + return 1 + endif + + " Skip files which are not supported by exuberant ctags + " First check whether default settings for this filetype are available. + " If it is not available, then check whether user specified settings are + " available. If both are not available, then don't list the tags for this + " filetype + let var = 's:tlist_def_' . a:ftype . '_settings' + if !exists(var) + let var = 'g:tlist_' . a:ftype . '_settings' + if !exists(var) + return 1 + endif + endif + + " Skip files which are not readable or files which are not yet stored + " to the disk + if !filereadable(a:filename) + return 1 + endif + + return 0 +endfunction + +" Tlist_User_Removed_File +" Returns 1 if a file is removed by a user from the taglist +function! s:Tlist_User_Removed_File(filename) + return stridx(s:tlist_removed_flist, a:filename . "\n") != -1 +endfunction + +" Tlist_Update_Remove_List +" Update the list of user removed files from the taglist +" add == 1, add the file to the removed list +" add == 0, delete the file from the removed list +function! s:Tlist_Update_Remove_List(filename, add) + if a:add + let s:tlist_removed_flist = s:tlist_removed_flist . a:filename . "\n" + else + let idx = stridx(s:tlist_removed_flist, a:filename . "\n") + let text_before = strpart(s:tlist_removed_flist, 0, idx) + let rem_text = strpart(s:tlist_removed_flist, idx) + let next_idx = stridx(rem_text, "\n") + let text_after = strpart(rem_text, next_idx + 1) + + let s:tlist_removed_flist = text_before . text_after + endif +endfunction + +" Tlist_FileType_Init +" Initialize the ctags arguments and tag variable for the specified +" file type +function! s:Tlist_FileType_Init(ftype) + call s:Tlist_Log_Msg('Tlist_FileType_Init (' . a:ftype . ')') + " If the user didn't specify any settings, then use the default + " ctags args. Otherwise, use the settings specified by the user + let var = 'g:tlist_' . a:ftype . '_settings' + if exists(var) + " User specified ctags arguments + let settings = {var} . ';' + else + " Default ctags arguments + let var = 's:tlist_def_' . a:ftype . '_settings' + if !exists(var) + " No default settings for this file type. This filetype is + " not supported + return 0 + endif + let settings = s:tlist_def_{a:ftype}_settings . ';' + endif + + let msg = 'Taglist: Invalid ctags option setting - ' . settings + + " Format of the option that specifies the filetype and ctags arugments: + " + " ;flag1:name1;flag2:name2;flag3:name3 + " + + " Extract the file type to pass to ctags. This may be different from the + " file type detected by Vim + let pos = stridx(settings, ';') + if pos == -1 + call s:Tlist_Warning_Msg(msg) + return 0 + endif + let ctags_ftype = strpart(settings, 0, pos) + if ctags_ftype == '' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + " Make sure a valid filetype is supplied. If the user didn't specify a + " valid filetype, then the ctags option settings may be treated as the + " filetype + if ctags_ftype =~ ':' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + + " Remove the file type from settings + let settings = strpart(settings, pos + 1) + if settings == '' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + + " Process all the specified ctags flags. The format is + " flag1:name1;flag2:name2;flag3:name3 + let ctags_flags = '' + let cnt = 0 + while settings != '' + " Extract the flag + let pos = stridx(settings, ':') + if pos == -1 + call s:Tlist_Warning_Msg(msg) + return 0 + endif + let flag = strpart(settings, 0, pos) + if flag == '' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + " Remove the flag from settings + let settings = strpart(settings, pos + 1) + + " Extract the tag type name + let pos = stridx(settings, ';') + if pos == -1 + call s:Tlist_Warning_Msg(msg) + return 0 + endif + let name = strpart(settings, 0, pos) + if name == '' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + let settings = strpart(settings, pos + 1) + + let cnt = cnt + 1 + + let s:tlist_{a:ftype}_{cnt}_name = flag + let s:tlist_{a:ftype}_{cnt}_fullname = name + let ctags_flags = ctags_flags . flag + endwhile + + let s:tlist_{a:ftype}_ctags_args = '--language-force=' . ctags_ftype . + \ ' --' . ctags_ftype . '-types=' . ctags_flags + let s:tlist_{a:ftype}_count = cnt + let s:tlist_{a:ftype}_ctags_flags = ctags_flags + + " Save the filetype name + let s:tlist_ftype_{s:tlist_ftype_count}_name = a:ftype + let s:tlist_ftype_count = s:tlist_ftype_count + 1 + + return 1 +endfunction + +" Tlist_Detect_Filetype +" Determine the filetype for the specified file using the filetypedetect +" autocmd. +function! s:Tlist_Detect_Filetype(fname) + " Ignore the filetype autocommands + let old_eventignore = &eventignore + set eventignore=FileType + + " Save the 'filetype', as this will be changed temporarily + let old_filetype = &filetype + + " Run the filetypedetect group of autocommands to determine + " the filetype + exe 'doautocmd filetypedetect BufRead ' . a:fname + + " Save the detected filetype + let ftype = &filetype + + " Restore the previous state + let &filetype = old_filetype + let &eventignore = old_eventignore + + return ftype +endfunction + +" Tlist_Get_Buffer_Filetype +" Get the filetype for the specified buffer +function! s:Tlist_Get_Buffer_Filetype(bnum) + let buf_ft = getbufvar(a:bnum, '&filetype') + + if bufloaded(a:bnum) + " For loaded buffers, the 'filetype' is already determined + return buf_ft + endif + + " For unloaded buffers, if the 'filetype' option is set, return it + if buf_ft != '' + return buf_ft + endif + + " Skip non-existent buffers + if !bufexists(a:bnum) + return '' + endif + + " For buffers whose filetype is not yet determined, try to determine + " the filetype + let bname = bufname(a:bnum) + + return s:Tlist_Detect_Filetype(bname) +endfunction + +" Tlist_Discard_TagInfo +" Discard the stored tag information for a file +function! s:Tlist_Discard_TagInfo(fidx) + call s:Tlist_Log_Msg('Tlist_Discard_TagInfo (' . + \ s:tlist_{a:fidx}_filename . ')') + let ftype = s:tlist_{a:fidx}_filetype + + " Discard information about the tags defined in the file + let i = 1 + while i <= s:tlist_{a:fidx}_tag_count + let fidx_i = 's:tlist_' . a:fidx . '_' . i + unlet! {fidx_i}_tag + unlet! {fidx_i}_tag_name + unlet! {fidx_i}_tag_type + unlet! {fidx_i}_ttype_idx + unlet! {fidx_i}_tag_proto + unlet! {fidx_i}_tag_searchpat + unlet! {fidx_i}_tag_linenum + let i = i + 1 + endwhile + + let s:tlist_{a:fidx}_tag_count = 0 + + " Discard information about tag type groups + let i = 1 + while i <= s:tlist_{ftype}_count + let ttype = s:tlist_{ftype}_{i}_name + if s:tlist_{a:fidx}_{ttype} != '' + let fidx_ttype = 's:tlist_' . a:fidx . '_' . ttype + let {fidx_ttype} = '' + let {fidx_ttype}_offset = 0 + let cnt = {fidx_ttype}_count + let {fidx_ttype}_count = 0 + let j = 1 + while j <= cnt + unlet! {fidx_ttype}_{j} + let j = j + 1 + endwhile + endif + let i = i + 1 + endwhile + + " Discard the stored menu command also + let s:tlist_{a:fidx}_menu_cmd = '' +endfunction + +" Tlist_Window_Update_Line_Offsets +" Update the line offsets for tags for files starting from start_idx +" and displayed in the taglist window by the specified offset +function! s:Tlist_Window_Update_Line_Offsets(start_idx, increment, offset) + let i = a:start_idx + + while i < s:tlist_file_count + if s:tlist_{i}_visible + " Update the start/end line number only if the file is visible + if a:increment + let s:tlist_{i}_start = s:tlist_{i}_start + a:offset + let s:tlist_{i}_end = s:tlist_{i}_end + a:offset + else + let s:tlist_{i}_start = s:tlist_{i}_start - a:offset + let s:tlist_{i}_end = s:tlist_{i}_end - a:offset + endif + endif + let i = i + 1 + endwhile +endfunction + +" Tlist_Discard_FileInfo +" Discard the stored information for a file +function! s:Tlist_Discard_FileInfo(fidx) + call s:Tlist_Log_Msg('Tlist_Discard_FileInfo (' . + \ s:tlist_{a:fidx}_filename . ')') + call s:Tlist_Discard_TagInfo(a:fidx) + + let ftype = s:tlist_{a:fidx}_filetype + + let i = 1 + while i <= s:tlist_{ftype}_count + let ttype = s:tlist_{ftype}_{i}_name + unlet! s:tlist_{a:fidx}_{ttype} + unlet! s:tlist_{a:fidx}_{ttype}_offset + unlet! s:tlist_{a:fidx}_{ttype}_count + let i = i + 1 + endwhile + + unlet! s:tlist_{a:fidx}_filename + unlet! s:tlist_{a:fidx}_sort_type + unlet! s:tlist_{a:fidx}_filetype + unlet! s:tlist_{a:fidx}_mtime + unlet! s:tlist_{a:fidx}_start + unlet! s:tlist_{a:fidx}_end + unlet! s:tlist_{a:fidx}_valid + unlet! s:tlist_{a:fidx}_visible + unlet! s:tlist_{a:fidx}_tag_count + unlet! s:tlist_{a:fidx}_menu_cmd +endfunction + +" Tlist_Window_Remove_File_From_Display +" Remove the specified file from display +function! s:Tlist_Window_Remove_File_From_Display(fidx) + call s:Tlist_Log_Msg('Tlist_Window_Remove_File_From_Display (' . + \ s:tlist_{a:fidx}_filename . ')') + " If the file is not visible then no need to remove it + if !s:tlist_{a:fidx}_visible + return + endif + + " Remove the tags displayed for the specified file from the window + let start = s:tlist_{a:fidx}_start + " Include the empty line after the last line also + if g:Tlist_Compact_Format + let end = s:tlist_{a:fidx}_end + else + let end = s:tlist_{a:fidx}_end + 1 + endif + + setlocal modifiable + exe 'silent! ' . start . ',' . end . 'delete _' + setlocal nomodifiable + + " Correct the start and end line offsets for all the files following + " this file, as the tags for this file are removed + call s:Tlist_Window_Update_Line_Offsets(a:fidx + 1, 0, end - start + 1) +endfunction + +" Tlist_Remove_File +" Remove the file under the cursor or the specified file index +" user_request - User requested to remove the file from taglist +function! s:Tlist_Remove_File(file_idx, user_request) + let fidx = a:file_idx + + if fidx == -1 + let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.')) + if fidx == -1 + return + endif + endif + call s:Tlist_Log_Msg('Tlist_Remove_File (' . + \ s:tlist_{fidx}_filename . ', ' . a:user_request . ')') + + let save_winnr = winnr() + let winnum = bufwinnr(g:TagList_title) + if winnum != -1 + " Taglist window is open, remove the file from display + + if save_winnr != winnum + let old_eventignore = &eventignore + set eventignore=all + exe winnum . 'wincmd w' + endif + + call s:Tlist_Window_Remove_File_From_Display(fidx) + + if save_winnr != winnum + exe save_winnr . 'wincmd w' + let &eventignore = old_eventignore + endif + endif + + let fname = s:tlist_{fidx}_filename + + if a:user_request + " As the user requested to remove the file from taglist, + " add it to the removed list + call s:Tlist_Update_Remove_List(fname, 1) + endif + + " Remove the file name from the taglist list of filenames + let idx = stridx(s:tlist_file_names, fname . "\n") + let text_before = strpart(s:tlist_file_names, 0, idx) + let rem_text = strpart(s:tlist_file_names, idx) + let next_idx = stridx(rem_text, "\n") + let text_after = strpart(rem_text, next_idx + 1) + let s:tlist_file_names = text_before . text_after + + call s:Tlist_Discard_FileInfo(fidx) + + " Shift all the file variables by one index + let i = fidx + 1 + + while i < s:tlist_file_count + let j = i - 1 + + let s:tlist_{j}_filename = s:tlist_{i}_filename + let s:tlist_{j}_sort_type = s:tlist_{i}_sort_type + let s:tlist_{j}_filetype = s:tlist_{i}_filetype + let s:tlist_{j}_mtime = s:tlist_{i}_mtime + let s:tlist_{j}_start = s:tlist_{i}_start + let s:tlist_{j}_end = s:tlist_{i}_end + let s:tlist_{j}_valid = s:tlist_{i}_valid + let s:tlist_{j}_visible = s:tlist_{i}_visible + let s:tlist_{j}_tag_count = s:tlist_{i}_tag_count + let s:tlist_{j}_menu_cmd = s:tlist_{i}_menu_cmd + + let k = 1 + while k <= s:tlist_{j}_tag_count + let s:tlist_{j}_{k}_tag = s:tlist_{i}_{k}_tag + let s:tlist_{j}_{k}_tag_name = s:tlist_{i}_{k}_tag_name + let s:tlist_{j}_{k}_tag_type = s:Tlist_Get_Tag_Type_By_Tag(i, k) + let s:tlist_{j}_{k}_ttype_idx = s:tlist_{i}_{k}_ttype_idx + let s:tlist_{j}_{k}_tag_proto = s:Tlist_Get_Tag_Prototype(i, k) + let s:tlist_{j}_{k}_tag_searchpat = s:Tlist_Get_Tag_SearchPat(i, k) + let s:tlist_{j}_{k}_tag_linenum = s:Tlist_Get_Tag_Linenum(i, k) + let k = k + 1 + endwhile + + let ftype = s:tlist_{i}_filetype + + let k = 1 + while k <= s:tlist_{ftype}_count + let ttype = s:tlist_{ftype}_{k}_name + let s:tlist_{j}_{ttype} = s:tlist_{i}_{ttype} + let s:tlist_{j}_{ttype}_offset = s:tlist_{i}_{ttype}_offset + let s:tlist_{j}_{ttype}_count = s:tlist_{i}_{ttype}_count + if s:tlist_{j}_{ttype} != '' + let l = 1 + while l <= s:tlist_{j}_{ttype}_count + let s:tlist_{j}_{ttype}_{l} = s:tlist_{i}_{ttype}_{l} + let l = l + 1 + endwhile + endif + let k = k + 1 + endwhile + + " As the file and tag information is copied to the new index, + " discard the previous information + call s:Tlist_Discard_FileInfo(i) + + let i = i + 1 + endwhile + + " Reduce the number of files displayed + let s:tlist_file_count = s:tlist_file_count - 1 + + if g:Tlist_Show_One_File + " If the tags for only one file is displayed and if we just + " now removed that file, then invalidate the current file idx + if s:tlist_cur_file_idx == fidx + let s:tlist_cur_file_idx = -1 + endif + endif +endfunction + +" Tlist_Window_Goto_Window +" Goto the taglist window +function! s:Tlist_Window_Goto_Window() + let winnum = bufwinnr(g:TagList_title) + if winnum != -1 + if winnr() != winnum + call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w') + endif + endif +endfunction + +" Tlist_Window_Create +" Create a new taglist window. If it is already open, jump to it +function! s:Tlist_Window_Create() + call s:Tlist_Log_Msg('Tlist_Window_Create()') + " If the window is open, jump to it + let winnum = bufwinnr(g:TagList_title) + if winnum != -1 + " Jump to the existing window + if winnr() != winnum + exe winnum . 'wincmd w' + endif + return + endif + + " If used with winmanager don't open windows. Winmanager will handle + " the window/buffer management + if s:tlist_app_name == "winmanager" + return + endif + + " Create a new window. If user prefers a horizontal window, then open + " a horizontally split window. Otherwise open a vertically split + " window + if g:Tlist_Use_Horiz_Window + " Open a horizontally split window + let win_dir = 'botright' + " Horizontal window height + let win_size = g:Tlist_WinHeight + else + if s:tlist_winsize_chgd == -1 + " Open a vertically split window. Increase the window size, if + " needed, to accomodate the new window + if g:Tlist_Inc_Winwidth && + \ &columns < (80 + g:Tlist_WinWidth) + " Save the original window position + let s:tlist_pre_winx = getwinposx() + let s:tlist_pre_winy = getwinposy() + + " one extra column is needed to include the vertical split + let &columns= &columns + g:Tlist_WinWidth + 1 + + let s:tlist_winsize_chgd = 1 + else + let s:tlist_winsize_chgd = 0 + endif + endif + + if g:Tlist_Use_Right_Window + " Open the window at the rightmost place + let win_dir = 'botright vertical' + else + " Open the window at the leftmost place + let win_dir = 'topleft vertical' + endif + let win_size = g:Tlist_WinWidth + endif + + " If the tag listing temporary buffer already exists, then reuse it. + " Otherwise create a new buffer + let bufnum = bufnr(g:TagList_title) + if bufnum == -1 + " Create a new buffer + let wcmd = g:TagList_title + else + " Edit the existing buffer + let wcmd = '+buffer' . bufnum + endif + + " Create the taglist window + exe 'silent! ' . win_dir . ' ' . win_size . 'split ' . wcmd + + " Save the new window position + let s:tlist_winx = getwinposx() + let s:tlist_winy = getwinposy() + + " Initialize the taglist window + call s:Tlist_Window_Init() +endfunction + +" Tlist_Window_Zoom +" Zoom (maximize/minimize) the taglist window +function! s:Tlist_Window_Zoom() + if s:tlist_win_maximized + " Restore the window back to the previous size + if g:Tlist_Use_Horiz_Window + exe 'resize ' . g:Tlist_WinHeight + else + exe 'vert resize ' . g:Tlist_WinWidth + endif + let s:tlist_win_maximized = 0 + else + " Set the window size to the maximum possible without closing other + " windows + if g:Tlist_Use_Horiz_Window + resize + else + vert resize + endif + let s:tlist_win_maximized = 1 + endif +endfunction + +" Tlist_Ballon_Expr +" When the mouse cursor is over a tag in the taglist window, display the +" tag prototype (balloon) +function! Tlist_Ballon_Expr() + " Get the file index + let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(v:beval_lnum) + if fidx == -1 + return '' + endif + + " Get the tag output line for the current tag + let tidx = s:Tlist_Window_Get_Tag_Index(fidx, v:beval_lnum) + if tidx == 0 + return '' + endif + + " Get the tag search pattern and display it + return s:Tlist_Get_Tag_Prototype(fidx, tidx) +endfunction + +" Tlist_Window_Check_Width +" Check the width of the taglist window. For horizontally split windows, the +" 'winfixheight' option is used to fix the height of the window. For +" vertically split windows, Vim doesn't support the 'winfixwidth' option. So +" need to handle window width changes from this function. +function! s:Tlist_Window_Check_Width() + let tlist_winnr = bufwinnr(g:TagList_title) + if tlist_winnr == -1 + return + endif + + let width = winwidth(tlist_winnr) + if width != g:Tlist_WinWidth + call s:Tlist_Log_Msg("Tlist_Window_Check_Width: Changing window " . + \ "width from " . width . " to " . g:Tlist_WinWidth) + let save_winnr = winnr() + if save_winnr != tlist_winnr + call s:Tlist_Exe_Cmd_No_Acmds(tlist_winnr . 'wincmd w') + endif + exe 'vert resize ' . g:Tlist_WinWidth + if save_winnr != tlist_winnr + call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') + endif + endif +endfunction + +" Tlist_Window_Exit_Only_Window +" If the 'Tlist_Exit_OnlyWindow' option is set, then exit Vim if only the +" taglist window is present. +function! s:Tlist_Window_Exit_Only_Window() + " Before quitting Vim, delete the taglist buffer so that + " the '0 mark is correctly set to the previous buffer. + if v:version < 700 + if winbufnr(2) == -1 + bdelete + quit + endif + else + if winbufnr(2) == -1 + if tabpagenr('$') == 1 + " Only one tag page is present + bdelete + quit + else + " More than one tab page is present. Close only the current + " tab page + close + endif + endif + endif +endfunction + +" Tlist_Window_Init +" Set the default options for the taglist window +function! s:Tlist_Window_Init() + call s:Tlist_Log_Msg('Tlist_Window_Init()') + + " The 'readonly' option should not be set for the taglist buffer. + " If Vim is started as "view/gview" or if the ":view" command is + " used, then the 'readonly' option is set for all the buffers. + " Unset it for the taglist buffer + setlocal noreadonly + + " Set the taglist buffer filetype to taglist + setlocal filetype=taglist + + " Define taglist window element highlighting + syntax match TagListComment '^" .*' + syntax match TagListFileName '^[^" ].*$' + syntax match TagListTitle '^ \S.*$' + syntax match TagListTagScope '\s\[.\{-\}\]$' + + " Define the highlighting only if colors are supported + if has('gui_running') || &t_Co > 2 + " Colors to highlight various taglist window elements + " If user defined highlighting group exists, then use them. + " Otherwise, use default highlight groups. + if hlexists('MyTagListTagName') + highlight link TagListTagName MyTagListTagName + else + highlight default link TagListTagName Search + endif + " Colors to highlight comments and titles + if hlexists('MyTagListComment') + highlight link TagListComment MyTagListComment + else + highlight clear TagListComment + highlight default link TagListComment Comment + endif + if hlexists('MyTagListTitle') + highlight link TagListTitle MyTagListTitle + else + highlight clear TagListTitle + highlight default link TagListTitle Title + endif + if hlexists('MyTagListFileName') + highlight link TagListFileName MyTagListFileName + else + highlight clear TagListFileName + highlight default TagListFileName guibg=Grey ctermbg=darkgray + \ guifg=white ctermfg=white + endif + if hlexists('MyTagListTagScope') + highlight link TagListTagScope MyTagListTagScope + else + highlight clear TagListTagScope + highlight default link TagListTagScope Identifier + endif + else + highlight default TagListTagName term=reverse cterm=reverse + endif + + " Folding related settings + setlocal foldenable + setlocal foldminlines=0 + setlocal foldmethod=manual + setlocal foldlevel=9999 + if g:Tlist_Enable_Fold_Column + setlocal foldcolumn=3 + else + setlocal foldcolumn=0 + endif + setlocal foldtext=v:folddashes.getline(v:foldstart) + + if s:tlist_app_name != "winmanager" + " Mark buffer as scratch + silent! setlocal buftype=nofile + if s:tlist_app_name == "none" + silent! setlocal bufhidden=delete + endif + silent! setlocal noswapfile + " Due to a bug in Vim 6.0, the winbufnr() function fails for unlisted + " buffers. So if the taglist buffer is unlisted, multiple taglist + " windows will be opened. This bug is fixed in Vim 6.1 and above + if v:version >= 601 + silent! setlocal nobuflisted + endif + endif + + silent! setlocal nowrap + + " If the 'number' option is set in the source window, it will affect the + " taglist window. So forcefully disable 'number' option for the taglist + " window + silent! setlocal nonumber + + " Use fixed height when horizontally split window is used + if g:Tlist_Use_Horiz_Window + if v:version >= 602 + set winfixheight + endif + endif + if !g:Tlist_Use_Horiz_Window && v:version >= 700 + set winfixwidth + endif + + " Setup balloon evaluation to display tag prototype + if v:version >= 700 && has('balloon_eval') + setlocal balloonexpr=Tlist_Ballon_Expr() + set ballooneval + endif + + " Setup the cpoptions properly for the maps to work + let old_cpoptions = &cpoptions + set cpoptions&vim + + " Create buffer local mappings for jumping to the tags and sorting the list + nnoremap + \ :call Tlist_Window_Jump_To_Tag('useopen') + nnoremap o + \ :call Tlist_Window_Jump_To_Tag('newwin') + nnoremap p + \ :call Tlist_Window_Jump_To_Tag('preview') + nnoremap P + \ :call Tlist_Window_Jump_To_Tag('prevwin') + if v:version >= 700 + nnoremap t + \ :call Tlist_Window_Jump_To_Tag('checktab') + nnoremap + \ :call Tlist_Window_Jump_To_Tag('newtab') + endif + nnoremap <2-LeftMouse> + \ :call Tlist_Window_Jump_To_Tag('useopen') + nnoremap s + \ :call Tlist_Change_Sort('cmd', 'toggle', '') + nnoremap + :silent! foldopen + nnoremap - :silent! foldclose + nnoremap * :silent! %foldopen! + nnoremap = :silent! %foldclose + nnoremap :silent! foldopen + nnoremap :silent! foldclose + nnoremap :silent! %foldopen! + nnoremap :call Tlist_Window_Show_Info() + nnoremap u :call Tlist_Window_Update_File() + nnoremap d :call Tlist_Remove_File(-1, 1) + nnoremap x :call Tlist_Window_Zoom() + nnoremap [[ :call Tlist_Window_Move_To_File(-1) + nnoremap :call Tlist_Window_Move_To_File(-1) + nnoremap ]] :call Tlist_Window_Move_To_File(1) + nnoremap :call Tlist_Window_Move_To_File(1) + nnoremap :call Tlist_Window_Toggle_Help_Text() + nnoremap q :close + + " Insert mode mappings + inoremap + \ :call Tlist_Window_Jump_To_Tag('useopen') + " Windows needs return + inoremap + \ :call Tlist_Window_Jump_To_Tag('useopen') + inoremap o + \ :call Tlist_Window_Jump_To_Tag('newwin') + inoremap p + \ :call Tlist_Window_Jump_To_Tag('preview') + inoremap P + \ :call Tlist_Window_Jump_To_Tag('prevwin') + if v:version >= 700 + inoremap t + \ :call Tlist_Window_Jump_To_Tag('checktab') + inoremap + \ :call Tlist_Window_Jump_To_Tag('newtab') + endif + inoremap <2-LeftMouse> + \ :call Tlist_Window_Jump_To_Tag('useopen') + inoremap s + \ :call Tlist_Change_Sort('cmd', 'toggle', '') + inoremap + :silent! foldopen + inoremap - :silent! foldclose + inoremap * :silent! %foldopen! + inoremap = :silent! %foldclose + inoremap :silent! foldopen + inoremap :silent! foldclose + inoremap :silent! %foldopen! + inoremap :call + \ Tlist_Window_Show_Info() + inoremap u + \ :call Tlist_Window_Update_File() + inoremap d :call Tlist_Remove_File(-1, 1) + inoremap x :call Tlist_Window_Zoom() + inoremap [[ :call Tlist_Window_Move_To_File(-1) + inoremap :call Tlist_Window_Move_To_File(-1) + inoremap ]] :call Tlist_Window_Move_To_File(1) + inoremap :call Tlist_Window_Move_To_File(1) + inoremap :call Tlist_Window_Toggle_Help_Text() + inoremap q :close + + " Map single left mouse click if the user wants this functionality + if g:Tlist_Use_SingleClick == 1 + " Contributed by Bindu Wavell + " attempt to perform single click mapping, it would be much + " nicer if we could nnoremap ... however vim does + " not fire the when you use the mouse + " to enter a buffer. + let clickmap = ':if bufname("%") =~ "__Tag_List__" ' . + \ 'call Tlist_Window_Jump_To_Tag("useopen") ' . + \ ' endif ' + if maparg('', 'n') == '' + " no mapping for leftmouse + exe ':nnoremap ' . clickmap + else + " we have a mapping + let mapcmd = ':nnoremap ' + let mapcmd = mapcmd . substitute(substitute( + \ maparg('', 'n'), '|', '', 'g'), + \ '\c^', '', '') + let mapcmd = mapcmd . clickmap + exe mapcmd + endif + endif + + " Define the taglist autocommands + augroup TagListAutoCmds + autocmd! + " Display the tag prototype for the tag under the cursor. + autocmd CursorHold __Tag_List__ call s:Tlist_Window_Show_Info() + " Highlight the current tag periodically + autocmd CursorHold * silent call s:Tlist_Window_Highlight_Tag( + \ fnamemodify(bufname('%'), ':p'), line('.'), 1, 0) + + " Adjust the Vim window width when taglist window is closed + autocmd BufUnload __Tag_List__ call s:Tlist_Post_Close_Cleanup() + " Close the fold for this buffer when leaving the buffer + if g:Tlist_File_Fold_Auto_Close + autocmd BufEnter * silent + \ call s:Tlist_Window_Open_File_Fold(expand('')) + endif + " Exit Vim itself if only the taglist window is present (optional) + if g:Tlist_Exit_OnlyWindow + autocmd BufEnter __Tag_List__ nested + \ call s:Tlist_Window_Exit_Only_Window() + endif + if s:tlist_app_name != "winmanager" && + \ !g:Tlist_Process_File_Always && + \ (!has('gui_running') || !g:Tlist_Show_Menu) + " Auto refresh the taglist window + autocmd BufEnter * call s:Tlist_Refresh() + endif + + if !g:Tlist_Use_Horiz_Window + if v:version < 700 + autocmd WinEnter * call s:Tlist_Window_Check_Width() + endif + endif + if v:version >= 700 + autocmd TabEnter * silent call s:Tlist_Refresh_Folds() + endif + augroup end + + " Restore the previous cpoptions settings + let &cpoptions = old_cpoptions +endfunction + +" Tlist_Window_Refresh +" Display the tags for all the files in the taglist window +function! s:Tlist_Window_Refresh() + call s:Tlist_Log_Msg('Tlist_Window_Refresh()') + " Set report option to a huge value to prevent informational messages + " while deleting the lines + let old_report = &report + set report=99999 + + " Mark the buffer as modifiable + setlocal modifiable + + " Delete the contents of the buffer to the black-hole register + silent! %delete _ + + " As we have cleared the taglist window, mark all the files + " as not visible + let i = 0 + while i < s:tlist_file_count + let s:tlist_{i}_visible = 0 + let i = i + 1 + endwhile + + if g:Tlist_Compact_Format == 0 + " Display help in non-compact mode + call s:Tlist_Window_Display_Help() + endif + + " Mark the buffer as not modifiable + setlocal nomodifiable + + " Restore the report option + let &report = old_report + + " If the tags for only one file should be displayed in the taglist + " window, then no need to add the tags here. The bufenter autocommand + " will add the tags for that file. + if g:Tlist_Show_One_File + return + endif + + " List all the tags for the previously processed files + " Do this only if taglist is configured to display tags for more than + " one file. Otherwise, when Tlist_Show_One_File is configured, + " tags for the wrong file will be displayed. + let i = 0 + while i < s:tlist_file_count + call s:Tlist_Window_Refresh_File(s:tlist_{i}_filename, + \ s:tlist_{i}_filetype) + let i = i + 1 + endwhile + + if g:Tlist_Auto_Update + " Add and list the tags for all buffers in the Vim buffer list + let i = 1 + let last_bufnum = bufnr('$') + while i <= last_bufnum + if buflisted(i) + let fname = fnamemodify(bufname(i), ':p') + let ftype = s:Tlist_Get_Buffer_Filetype(i) + " If the file doesn't support tag listing, skip it + if !s:Tlist_Skip_File(fname, ftype) + call s:Tlist_Window_Refresh_File(fname, ftype) + endif + endif + let i = i + 1 + endwhile + endif + + " If Tlist_File_Fold_Auto_Close option is set, then close all the folds + if g:Tlist_File_Fold_Auto_Close + " Close all the folds + silent! %foldclose + endif + + " Move the cursor to the top of the taglist window + normal! gg +endfunction + +" Tlist_Post_Close_Cleanup() +" Close the taglist window and adjust the Vim window width +function! s:Tlist_Post_Close_Cleanup() + call s:Tlist_Log_Msg('Tlist_Post_Close_Cleanup()') + " Mark all the files as not visible + let i = 0 + while i < s:tlist_file_count + let s:tlist_{i}_visible = 0 + let i = i + 1 + endwhile + + " Remove the taglist autocommands + silent! autocmd! TagListAutoCmds + + " Clear all the highlights + match none + + silent! syntax clear TagListTitle + silent! syntax clear TagListComment + silent! syntax clear TagListTagScope + + " Remove the left mouse click mapping if it was setup initially + if g:Tlist_Use_SingleClick + if hasmapto('') + nunmap + endif + endif + + if s:tlist_app_name != "winmanager" + if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 || + \ s:tlist_winsize_chgd != 1 || + \ &columns < (80 + g:Tlist_WinWidth) + " No need to adjust window width if using horizontally split taglist + " window or if columns is less than 101 or if the user chose not to + " adjust the window width + else + " If the user didn't manually move the window, then restore the window + " position to the pre-taglist position + if s:tlist_pre_winx != -1 && s:tlist_pre_winy != -1 && + \ getwinposx() == s:tlist_winx && + \ getwinposy() == s:tlist_winy + exe 'winpos ' . s:tlist_pre_winx . ' ' . s:tlist_pre_winy + endif + + " Adjust the Vim window width + let &columns= &columns - (g:Tlist_WinWidth + 1) + endif + endif + + let s:tlist_winsize_chgd = -1 + + " Reset taglist state variables + if s:tlist_app_name == "winmanager" + let s:tlist_app_name = "none" + endif + let s:tlist_window_initialized = 0 +endfunction + +" Tlist_Window_Refresh_File() +" List the tags defined in the specified file in a Vim window +function! s:Tlist_Window_Refresh_File(filename, ftype) + call s:Tlist_Log_Msg('Tlist_Window_Refresh_File (' . a:filename . ')') + " First check whether the file already exists + let fidx = s:Tlist_Get_File_Index(a:filename) + if fidx != -1 + let file_listed = 1 + else + let file_listed = 0 + endif + + if !file_listed + " Check whether this file is removed based on user request + " If it is, then don't display the tags for this file + if s:Tlist_User_Removed_File(a:filename) + return + endif + endif + + if file_listed && s:tlist_{fidx}_visible + " Check whether the file tags are currently valid + if s:tlist_{fidx}_valid + " Goto the first line in the file + exe s:tlist_{fidx}_start + + " If the line is inside a fold, open the fold + if foldclosed('.') != -1 + exe "silent! " . s:tlist_{fidx}_start . "," . + \ s:tlist_{fidx}_end . "foldopen!" + endif + return + endif + + " Discard and remove the tags for this file from display + call s:Tlist_Discard_TagInfo(fidx) + call s:Tlist_Window_Remove_File_From_Display(fidx) + endif + + " Process and generate a list of tags defined in the file + if !file_listed || !s:tlist_{fidx}_valid + let ret_fidx = s:Tlist_Process_File(a:filename, a:ftype) + if ret_fidx == -1 + return + endif + let fidx = ret_fidx + endif + + " Set report option to a huge value to prevent informational messages + " while adding lines to the taglist window + let old_report = &report + set report=99999 + + if g:Tlist_Show_One_File + " Remove the previous file + if s:tlist_cur_file_idx != -1 + call s:Tlist_Window_Remove_File_From_Display(s:tlist_cur_file_idx) + let s:tlist_{s:tlist_cur_file_idx}_visible = 0 + let s:tlist_{s:tlist_cur_file_idx}_start = 0 + let s:tlist_{s:tlist_cur_file_idx}_end = 0 + endif + let s:tlist_cur_file_idx = fidx + endif + + " Mark the buffer as modifiable + setlocal modifiable + + " Add new files to the end of the window. For existing files, add them at + " the same line where they were previously present. If the file is not + " visible, then add it at the end + if s:tlist_{fidx}_start == 0 || !s:tlist_{fidx}_visible + if g:Tlist_Compact_Format + let s:tlist_{fidx}_start = line('$') + else + let s:tlist_{fidx}_start = line('$') + 1 + endif + endif + + let s:tlist_{fidx}_visible = 1 + + " Goto the line where this file should be placed + if g:Tlist_Compact_Format + exe s:tlist_{fidx}_start + else + exe s:tlist_{fidx}_start - 1 + endif + + let txt = fnamemodify(s:tlist_{fidx}_filename, ':t') . ' (' . + \ fnamemodify(s:tlist_{fidx}_filename, ':p:h') . ')' + if g:Tlist_Compact_Format == 0 + silent! put =txt + else + silent! put! =txt + " Move to the next line + exe line('.') + 1 + endif + let file_start = s:tlist_{fidx}_start + + " Add the tag names grouped by tag type to the buffer with a title + let i = 1 + let ttype_cnt = s:tlist_{a:ftype}_count + while i <= ttype_cnt + let ttype = s:tlist_{a:ftype}_{i}_name + " Add the tag type only if there are tags for that type + let fidx_ttype = 's:tlist_' . fidx . '_' . ttype + let ttype_txt = {fidx_ttype} + if ttype_txt != '' + let txt = ' ' . s:tlist_{a:ftype}_{i}_fullname + if g:Tlist_Compact_Format == 0 + let ttype_start_lnum = line('.') + 1 + silent! put =txt + else + let ttype_start_lnum = line('.') + silent! put! =txt + endif + silent! put =ttype_txt + + let {fidx_ttype}_offset = ttype_start_lnum - file_start + + " create a fold for this tag type + let fold_start = ttype_start_lnum + let fold_end = fold_start + {fidx_ttype}_count + exe fold_start . ',' . fold_end . 'fold' + + " Adjust the cursor position + if g:Tlist_Compact_Format == 0 + exe ttype_start_lnum + {fidx_ttype}_count + else + exe ttype_start_lnum + {fidx_ttype}_count + 1 + endif + + if g:Tlist_Compact_Format == 0 + " Separate the tag types by a empty line + silent! put ='' + endif + endif + let i = i + 1 + endwhile + + if s:tlist_{fidx}_tag_count == 0 + if g:Tlist_Compact_Format == 0 + silent! put ='' + endif + endif + + let s:tlist_{fidx}_end = line('.') - 1 + + " Create a fold for the entire file + exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold' + exe 'silent! ' . s:tlist_{fidx}_start . ',' . + \ s:tlist_{fidx}_end . 'foldopen!' + + " Goto the starting line for this file, + exe s:tlist_{fidx}_start + + if s:tlist_app_name == "winmanager" + " To handle a bug in the winmanager plugin, add a space at the + " last line + call setline('$', ' ') + endif + + " Mark the buffer as not modifiable + setlocal nomodifiable + + " Restore the report option + let &report = old_report + + " Update the start and end line numbers for all the files following this + " file + let start = s:tlist_{fidx}_start + " include the empty line after the last line + if g:Tlist_Compact_Format + let end = s:tlist_{fidx}_end + else + let end = s:tlist_{fidx}_end + 1 + endif + call s:Tlist_Window_Update_Line_Offsets(fidx + 1, 1, end - start + 1) + + " Now that we have updated the taglist window, update the tags + " menu (if present) + if g:Tlist_Show_Menu + call s:Tlist_Menu_Update_File(1) + endif +endfunction + +" Tlist_Init_File +" Initialize the variables for a new file +function! s:Tlist_Init_File(filename, ftype) + call s:Tlist_Log_Msg('Tlist_Init_File (' . a:filename . ')') + " Add new files at the end of the list + let fidx = s:tlist_file_count + let s:tlist_file_count = s:tlist_file_count + 1 + " Add the new file name to the taglist list of file names + let s:tlist_file_names = s:tlist_file_names . a:filename . "\n" + + " Initialize the file variables + let s:tlist_{fidx}_filename = a:filename + let s:tlist_{fidx}_sort_type = g:Tlist_Sort_Type + let s:tlist_{fidx}_filetype = a:ftype + let s:tlist_{fidx}_mtime = -1 + let s:tlist_{fidx}_start = 0 + let s:tlist_{fidx}_end = 0 + let s:tlist_{fidx}_valid = 0 + let s:tlist_{fidx}_visible = 0 + let s:tlist_{fidx}_tag_count = 0 + let s:tlist_{fidx}_menu_cmd = '' + + " Initialize the tag type variables + let i = 1 + while i <= s:tlist_{a:ftype}_count + let ttype = s:tlist_{a:ftype}_{i}_name + let s:tlist_{fidx}_{ttype} = '' + let s:tlist_{fidx}_{ttype}_offset = 0 + let s:tlist_{fidx}_{ttype}_count = 0 + let i = i + 1 + endwhile + + return fidx +endfunction + +" Tlist_Get_Tag_Type_By_Tag +" Return the tag type for the specified tag index +function! s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx) + let ttype_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_type' + + " Already parsed and have the tag name + if exists(ttype_var) + return {ttype_var} + endif + + let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag + let {ttype_var} = s:Tlist_Extract_Tagtype(tag_line) + + return {ttype_var} +endfunction + +" Tlist_Get_Tag_Prototype +function! s:Tlist_Get_Tag_Prototype(fidx, tidx) + let tproto_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_proto' + + " Already parsed and have the tag prototype + if exists(tproto_var) + return {tproto_var} + endif + + " Parse and extract the tag prototype + let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag + let start = stridx(tag_line, '/^') + 2 + let end = stridx(tag_line, '/;"' . "\t") + if tag_line[end - 1] == '$' + let end = end -1 + endif + let tag_proto = strpart(tag_line, start, end - start) + let {tproto_var} = substitute(tag_proto, '\s*', '', '') + + return {tproto_var} +endfunction + +" Tlist_Get_Tag_SearchPat +function! s:Tlist_Get_Tag_SearchPat(fidx, tidx) + let tpat_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_searchpat' + + " Already parsed and have the tag search pattern + if exists(tpat_var) + return {tpat_var} + endif + + " Parse and extract the tag search pattern + let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag + let start = stridx(tag_line, '/^') + 2 + let end = stridx(tag_line, '/;"' . "\t") + if tag_line[end - 1] == '$' + let end = end -1 + endif + let {tpat_var} = '\V\^' . strpart(tag_line, start, end - start) . + \ (tag_line[end] == '$' ? '\$' : '') + + return {tpat_var} +endfunction + +" Tlist_Get_Tag_Linenum +" Return the tag line number, given the tag index +function! s:Tlist_Get_Tag_Linenum(fidx, tidx) + let tline_var = 's:tlist_' . a:fidx . '_' . a:tidx . '_tag_linenum' + + " Already parsed and have the tag line number + if exists(tline_var) + return {tline_var} + endif + + " Parse and extract the tag line number + let tag_line = s:tlist_{a:fidx}_{a:tidx}_tag + let start = strridx(tag_line, 'line:') + 5 + let end = strridx(tag_line, "\t") + if end < start + let {tline_var} = strpart(tag_line, start) + 0 + else + let {tline_var} = strpart(tag_line, start, end - start) + 0 + endif + + return {tline_var} +endfunction + +" Tlist_Parse_Tagline +" Parse a tag line from the ctags output. Separate the tag output based on the +" tag type and store it in the tag type variable. +" The format of each line in the ctags output is: +" +" tag_namefile_nameex_cmd;"extension_fields +" +function! s:Tlist_Parse_Tagline(tag_line) + if a:tag_line == '' + " Skip empty lines + return + endif + + " Extract the tag type + let ttype = s:Tlist_Extract_Tagtype(a:tag_line) + + " Make sure the tag type is a valid and supported one + if ttype == '' || stridx(s:ctags_flags, ttype) == -1 + " Line is not in proper tags format or Tag type is not supported + return + endif + + " Update the total tag count + let s:tidx = s:tidx + 1 + + " The following variables are used to optimize this code. Vim is slow in + " using curly brace names. To reduce the amount of processing needed, the + " curly brace variables are pre-processed here + let fidx_tidx = 's:tlist_' . s:fidx . '_' . s:tidx + let fidx_ttype = 's:tlist_' . s:fidx . '_' . ttype + + " Update the count of this tag type + let ttype_idx = {fidx_ttype}_count + 1 + let {fidx_ttype}_count = ttype_idx + + " Store the ctags output for this tag + let {fidx_tidx}_tag = a:tag_line + + " Store the tag index and the tag type index (back pointers) + let {fidx_ttype}_{ttype_idx} = s:tidx + let {fidx_tidx}_ttype_idx = ttype_idx + + " Extract the tag name + let tag_name = strpart(a:tag_line, 0, stridx(a:tag_line, "\t")) + + " Extract the tag scope/prototype + if g:Tlist_Display_Prototype + let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(s:fidx, s:tidx) + else + let ttxt = ' ' . tag_name + + " Add the tag scope, if it is available and is configured. Tag + " scope is the last field after the 'line:\t' field + if g:Tlist_Display_Tag_Scope + let tag_scope = s:Tlist_Extract_Tag_Scope(a:tag_line) + if tag_scope != '' + let ttxt = ttxt . ' [' . tag_scope . ']' + endif + endif + endif + + " Add this tag to the tag type variable + let {fidx_ttype} = {fidx_ttype} . ttxt . "\n" + + " Save the tag name + let {fidx_tidx}_tag_name = tag_name +endfunction + +" Tlist_Process_File +" Get the list of tags defined in the specified file and store them +" in Vim variables. Returns the file index where the tags are stored. +function! s:Tlist_Process_File(filename, ftype) + call s:Tlist_Log_Msg('Tlist_Process_File (' . a:filename . ', ' . + \ a:ftype . ')') + " Check whether this file is supported + if s:Tlist_Skip_File(a:filename, a:ftype) + return -1 + endif + + " If the tag types for this filetype are not yet created, then create + " them now + let var = 's:tlist_' . a:ftype . '_count' + if !exists(var) + if s:Tlist_FileType_Init(a:ftype) == 0 + return -1 + endif + endif + + " If this file is already processed, then use the cached values + let fidx = s:Tlist_Get_File_Index(a:filename) + if fidx == -1 + " First time, this file is loaded + let fidx = s:Tlist_Init_File(a:filename, a:ftype) + else + " File was previously processed. Discard the tag information + call s:Tlist_Discard_TagInfo(fidx) + endif + + let s:tlist_{fidx}_valid = 1 + + " Exuberant ctags arguments to generate a tag list + let ctags_args = ' -f - --format=2 --excmd=pattern --fields=nks ' + + " Form the ctags argument depending on the sort type + if s:tlist_{fidx}_sort_type == 'name' + let ctags_args = ctags_args . '--sort=yes' + else + let ctags_args = ctags_args . '--sort=no' + endif + + " Add the filetype specific arguments + let ctags_args = ctags_args . ' ' . s:tlist_{a:ftype}_ctags_args + + " Ctags command to produce output with regexp for locating the tags + let ctags_cmd = g:Tlist_Ctags_Cmd . ctags_args + let ctags_cmd = ctags_cmd . ' "' . a:filename . '"' + + if &shellxquote == '"' + " Double-quotes within double-quotes will not work in the + " command-line.If the 'shellxquote' option is set to double-quotes, + " then escape the double-quotes in the ctags command-line. + let ctags_cmd = escape(ctags_cmd, '"') + endif + + " In Windows 95, if not using cygwin, disable the 'shellslash' + " option. Otherwise, this will cause problems when running the + " ctags command. + if has('win95') && !has('win32unix') + let old_shellslash = &shellslash + set noshellslash + endif + + if has('win32') && !has('win32unix') && !has('win95') + \ && (&shell =~ 'cmd.exe') + " Windows does not correctly deal with commands that have more than 1 + " set of double quotes. It will strip them all resulting in: + " 'C:\Program' is not recognized as an internal or external command + " operable program or batch file. To work around this, place the + " command inside a batch file and call the batch file. + " Do this only on Win2K, WinXP and above. + " Contributed by: David Fishburn. + let s:taglist_tempfile = fnamemodify(tempname(), ':h') . + \ '\taglist.cmd' + exe 'redir! > ' . s:taglist_tempfile + silent echo ctags_cmd + redir END + + call s:Tlist_Log_Msg('Cmd inside batch file: ' . ctags_cmd) + let ctags_cmd = '"' . s:taglist_tempfile . '"' + endif + + call s:Tlist_Log_Msg('Cmd: ' . ctags_cmd) + + " Run ctags and get the tag list + let cmd_output = system(ctags_cmd) + + " Restore the value of the 'shellslash' option. + if has('win95') && !has('win32unix') + let &shellslash = old_shellslash + endif + + if exists('s:taglist_tempfile') + " Delete the temporary cmd file created on MS-Windows + call delete(s:taglist_tempfile) + endif + + " Handle errors + if v:shell_error + let msg = "Taglist: Failed to generate tags for " . a:filename + call s:Tlist_Warning_Msg(msg) + if cmd_output != '' + call s:Tlist_Warning_Msg(cmd_output) + endif + return fidx + endif + + " Store the modification time for the file + let s:tlist_{fidx}_mtime = getftime(a:filename) + + " No tags for current file + if cmd_output == '' + call s:Tlist_Log_Msg('No tags defined in ' . a:filename) + return fidx + endif + + call s:Tlist_Log_Msg('Generated tags information for ' . a:filename) + + if v:version > 601 + " The following script local variables are used by the + " Tlist_Parse_Tagline() function. + let s:ctags_flags = s:tlist_{a:ftype}_ctags_flags + let s:fidx = fidx + let s:tidx = 0 + + " Process the ctags output one line at a time. The substitute() + " command is used to parse the tag lines instead of using the + " matchstr()/stridx()/strpart() functions for performance reason + call substitute(cmd_output, "\\([^\n]\\+\\)\n", + \ '\=s:Tlist_Parse_Tagline(submatch(1))', 'g') + + " Save the number of tags for this file + let s:tlist_{fidx}_tag_count = s:tidx + + " The following script local variables are no longer needed + unlet! s:ctags_flags + unlet! s:tidx + unlet! s:fidx + else + " Due to a bug in Vim earlier than version 6.1, + " we cannot use substitute() to parse the ctags output. + " Instead the slow str*() functions are used + let ctags_flags = s:tlist_{a:ftype}_ctags_flags + let tidx = 0 + + while cmd_output != '' + " Extract one line at a time + let idx = stridx(cmd_output, "\n") + let one_line = strpart(cmd_output, 0, idx) + " Remove the line from the tags output + let cmd_output = strpart(cmd_output, idx + 1) + + if one_line == '' + " Line is not in proper tags format + continue + endif + + " Extract the tag type + let ttype = s:Tlist_Extract_Tagtype(one_line) + + " Make sure the tag type is a valid and supported one + if ttype == '' || stridx(ctags_flags, ttype) == -1 + " Line is not in proper tags format or Tag type is not + " supported + continue + endif + + " Update the total tag count + let tidx = tidx + 1 + + " The following variables are used to optimize this code. Vim is + " slow in using curly brace names. To reduce the amount of + " processing needed, the curly brace variables are pre-processed + " here + let fidx_tidx = 's:tlist_' . fidx . '_' . tidx + let fidx_ttype = 's:tlist_' . fidx . '_' . ttype + + " Update the count of this tag type + let ttype_idx = {fidx_ttype}_count + 1 + let {fidx_ttype}_count = ttype_idx + + " Store the ctags output for this tag + let {fidx_tidx}_tag = one_line + + " Store the tag index and the tag type index (back pointers) + let {fidx_ttype}_{ttype_idx} = tidx + let {fidx_tidx}_ttype_idx = ttype_idx + + " Extract the tag name + let tag_name = strpart(one_line, 0, stridx(one_line, "\t")) + + " Extract the tag scope/prototype + if g:Tlist_Display_Prototype + let ttxt = ' ' . s:Tlist_Get_Tag_Prototype(fidx, tidx) + else + let ttxt = ' ' . tag_name + + " Add the tag scope, if it is available and is configured. Tag + " scope is the last field after the 'line:\t' field + if g:Tlist_Display_Tag_Scope + let tag_scope = s:Tlist_Extract_Tag_Scope(one_line) + if tag_scope != '' + let ttxt = ttxt . ' [' . tag_scope . ']' + endif + endif + endif + + " Add this tag to the tag type variable + let {fidx_ttype} = {fidx_ttype} . ttxt . "\n" + + " Save the tag name + let {fidx_tidx}_tag_name = tag_name + endwhile + + " Save the number of tags for this file + let s:tlist_{fidx}_tag_count = tidx + endif + + call s:Tlist_Log_Msg('Processed ' . s:tlist_{fidx}_tag_count . + \ ' tags in ' . a:filename) + + return fidx +endfunction + +" Tlist_Update_File +" Update the tags for a file (if needed) +function! Tlist_Update_File(filename, ftype) + call s:Tlist_Log_Msg('Tlist_Update_File (' . a:filename . ')') + " If the file doesn't support tag listing, skip it + if s:Tlist_Skip_File(a:filename, a:ftype) + return + endif + + " Convert the file name to a full path + let fname = fnamemodify(a:filename, ':p') + + " First check whether the file already exists + let fidx = s:Tlist_Get_File_Index(fname) + + if fidx != -1 && s:tlist_{fidx}_valid + " File exists and the tags are valid + " Check whether the file was modified after the last tags update + " If it is modified, then update the tags + if s:tlist_{fidx}_mtime == getftime(fname) + return + endif + else + " If the tags were removed previously based on a user request, + " as we are going to update the tags (based on the user request), + " remove the filename from the deleted list + call s:Tlist_Update_Remove_List(fname, 0) + endif + + " If the taglist window is opened, update it + let winnum = bufwinnr(g:TagList_title) + if winnum == -1 + " Taglist window is not present. Just update the taglist + " and return + call s:Tlist_Process_File(fname, a:ftype) + else + if g:Tlist_Show_One_File && s:tlist_cur_file_idx != -1 + " If tags for only one file are displayed and we are not + " updating the tags for that file, then no need to + " refresh the taglist window. Otherwise, the taglist + " window should be updated. + if s:tlist_{s:tlist_cur_file_idx}_filename != fname + call s:Tlist_Process_File(fname, a:ftype) + return + endif + endif + + " Save the current window number + let save_winnr = winnr() + + " Goto the taglist window + call s:Tlist_Window_Goto_Window() + + " Save the cursor position + let save_line = line('.') + let save_col = col('.') + + " Update the taglist window + call s:Tlist_Window_Refresh_File(fname, a:ftype) + + " Restore the cursor position + if v:version >= 601 + call cursor(save_line, save_col) + else + exe save_line + exe 'normal! ' . save_col . '|' + endif + + if winnr() != save_winnr + " Go back to the original window + call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w') + endif + endif + + " Update the taglist menu + if g:Tlist_Show_Menu + call s:Tlist_Menu_Update_File(1) + endif +endfunction + +" Tlist_Window_Close +" Close the taglist window +function! s:Tlist_Window_Close() + call s:Tlist_Log_Msg('Tlist_Window_Close()') + " Make sure the taglist window exists + let winnum = bufwinnr(g:TagList_title) + if winnum == -1 + call s:Tlist_Warning_Msg('Error: Taglist window is not open') + return + endif + + if winnr() == winnum + " Already in the taglist window. Close it and return + if winbufnr(2) != -1 + " If a window other than the taglist window is open, + " then only close the taglist window. + close + endif + else + " Goto the taglist window, close it and then come back to the + " original window + let curbufnr = bufnr('%') + exe winnum . 'wincmd w' + close + " Need to jump back to the original window only if we are not + " already in that window + let winnum = bufwinnr(curbufnr) + if winnr() != winnum + exe winnum . 'wincmd w' + endif + endif +endfunction + +" Tlist_Window_Mark_File_Window +" Mark the current window as the file window to use when jumping to a tag. +" Only if the current window is a non-plugin, non-preview and non-taglist +" window +function! s:Tlist_Window_Mark_File_Window() + if getbufvar('%', '&buftype') == '' && !&previewwindow + let w:tlist_file_window = "yes" + endif +endfunction + +" Tlist_Window_Open +" Open and refresh the taglist window +function! s:Tlist_Window_Open() + call s:Tlist_Log_Msg('Tlist_Window_Open()') + " If the window is open, jump to it + let winnum = bufwinnr(g:TagList_title) + if winnum != -1 + " Jump to the existing window + if winnr() != winnum + exe winnum . 'wincmd w' + endif + return + endif + + if s:tlist_app_name == "winmanager" + " Taglist plugin is no longer part of the winmanager app + let s:tlist_app_name = "none" + endif + + " Get the filename and filetype for the specified buffer + let curbuf_name = fnamemodify(bufname('%'), ':p') + let curbuf_ftype = s:Tlist_Get_Buffer_Filetype('%') + let cur_lnum = line('.') + + " Mark the current window as the desired window to open a file when a tag + " is selected. + call s:Tlist_Window_Mark_File_Window() + + " Open the taglist window + call s:Tlist_Window_Create() + + call s:Tlist_Window_Refresh() + + if g:Tlist_Show_One_File + " Add only the current buffer and file + " + " If the file doesn't support tag listing, skip it + if !s:Tlist_Skip_File(curbuf_name, curbuf_ftype) + call s:Tlist_Window_Refresh_File(curbuf_name, curbuf_ftype) + endif + endif + + if g:Tlist_File_Fold_Auto_Close + " Open the fold for the current file, as all the folds in + " the taglist window are closed + let fidx = s:Tlist_Get_File_Index(curbuf_name) + if fidx != -1 + exe "silent! " . s:tlist_{fidx}_start . "," . + \ s:tlist_{fidx}_end . "foldopen!" + endif + endif + + " Highlight the current tag + call s:Tlist_Window_Highlight_Tag(curbuf_name, cur_lnum, 1, 1) +endfunction + +" Tlist_Window_Toggle() +" Open or close a taglist window +function! s:Tlist_Window_Toggle() + call s:Tlist_Log_Msg('Tlist_Window_Toggle()') + " If taglist window is open then close it. + let winnum = bufwinnr(g:TagList_title) + if winnum != -1 + call s:Tlist_Window_Close() + return + endif + + call s:Tlist_Window_Open() + + " Go back to the original window, if Tlist_GainFocus_On_ToggleOpen is not + " set + if !g:Tlist_GainFocus_On_ToggleOpen + call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') + endif + + " Update the taglist menu + if g:Tlist_Show_Menu + call s:Tlist_Menu_Update_File(0) + endif +endfunction + +" Tlist_Process_Filelist +" Process multiple files. Each filename is separated by "\n" +" Returns the number of processed files +function! s:Tlist_Process_Filelist(file_names) + let flist = a:file_names + + " Enable lazy screen updates + let old_lazyredraw = &lazyredraw + set lazyredraw + + " Keep track of the number of processed files + let fcnt = 0 + + " Process one file at a time + while flist != '' + let nl_idx = stridx(flist, "\n") + let one_file = strpart(flist, 0, nl_idx) + + " Remove the filename from the list + let flist = strpart(flist, nl_idx + 1) + + if one_file == '' + continue + endif + + " Skip directories + if isdirectory(one_file) + continue + endif + + let ftype = s:Tlist_Detect_Filetype(one_file) + + echon "\r " + echon "\rProcessing tags for " . fnamemodify(one_file, ':p:t') + + let fcnt = fcnt + 1 + + call Tlist_Update_File(one_file, ftype) + endwhile + + " Clear the displayed informational messages + echon "\r " + + " Restore the previous state + let &lazyredraw = old_lazyredraw + + return fcnt +endfunction + +" Tlist_Process_Dir +" Process the files in a directory matching the specified pattern +function! s:Tlist_Process_Dir(dir_name, pat) + let flist = glob(a:dir_name . '/' . a:pat) . "\n" + + let fcnt = s:Tlist_Process_Filelist(flist) + + let len = strlen(a:dir_name) + if a:dir_name[len - 1] == '\' || a:dir_name[len - 1] == '/' + let glob_expr = a:dir_name . '*' + else + let glob_expr = a:dir_name . '/*' + endif + let all_files = glob(glob_expr) . "\n" + + while all_files != '' + let nl_idx = stridx(all_files, "\n") + let one_file = strpart(all_files, 0, nl_idx) + + let all_files = strpart(all_files, nl_idx + 1) + if one_file == '' + continue + endif + + " Skip non-directory names + if !isdirectory(one_file) + continue + endif + + echon "\r " + echon "\rProcessing files in directory " . fnamemodify(one_file, ':t') + let fcnt = fcnt + s:Tlist_Process_Dir(one_file, a:pat) + endwhile + + return fcnt +endfunction + +" Tlist_Add_Files_Recursive +" Add files recursively from a directory +function! s:Tlist_Add_Files_Recursive(dir, ...) + let dir_name = fnamemodify(a:dir, ':p') + if !isdirectory(dir_name) + call s:Tlist_Warning_Msg('Error: ' . dir_name . ' is not a directory') + return + endif + + if a:0 == 1 + " User specified file pattern + let pat = a:1 + else + " Default file pattern + let pat = '*' + endif + + echon "\r " + echon "\rProcessing files in directory " . fnamemodify(dir_name, ':t') + let fcnt = s:Tlist_Process_Dir(dir_name, pat) + + echon "\rAdded " . fcnt . " files to the taglist" +endfunction + +" Tlist_Add_Files +" Add the specified list of files to the taglist +function! s:Tlist_Add_Files(...) + let flist = '' + let i = 1 + + " Get all the files matching the file patterns supplied as argument + while i <= a:0 + let flist = flist . glob(a:{i}) . "\n" + let i = i + 1 + endwhile + + if flist == '' + call s:Tlist_Warning_Msg('Error: No matching files are found') + return + endif + + let fcnt = s:Tlist_Process_Filelist(flist) + echon "\rAdded " . fcnt . " files to the taglist" +endfunction + +" Tlist_Extract_Tagtype +" Extract the tag type from the tag text +function! s:Tlist_Extract_Tagtype(tag_line) + " The tag type is after the tag prototype field. The prototype field + " ends with the /;"\t string. We add 4 at the end to skip the characters + " in this special string.. + let start = strridx(a:tag_line, '/;"' . "\t") + 4 + let end = strridx(a:tag_line, 'line:') - 1 + let ttype = strpart(a:tag_line, start, end - start) + + return ttype +endfunction + +" Tlist_Extract_Tag_Scope +" Extract the tag scope from the tag text +function! s:Tlist_Extract_Tag_Scope(tag_line) + let start = strridx(a:tag_line, 'line:') + let end = strridx(a:tag_line, "\t") + if end <= start + return '' + endif + + let tag_scope = strpart(a:tag_line, end + 1) + let tag_scope = strpart(tag_scope, stridx(tag_scope, ':') + 1) + + return tag_scope +endfunction + +" Tlist_Refresh() +" Refresh the taglist +function! s:Tlist_Refresh() + call s:Tlist_Log_Msg('Tlist_Refresh (Skip_Refresh = ' . + \ s:Tlist_Skip_Refresh . ', ' . bufname('%') . ')') + " If we are entering the buffer from one of the taglist functions, then + " no need to refresh the taglist window again. + if s:Tlist_Skip_Refresh + " We still need to update the taglist menu + if g:Tlist_Show_Menu + call s:Tlist_Menu_Update_File(0) + endif + return + endif + + " If part of the winmanager plugin and not configured to process + " tags always and not configured to display the tags menu, then return + if (s:tlist_app_name == 'winmanager') && !g:Tlist_Process_File_Always + \ && !g:Tlist_Show_Menu + return + endif + + " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help + if &buftype != '' + return + endif + + let filename = fnamemodify(bufname('%'), ':p') + let ftype = s:Tlist_Get_Buffer_Filetype('%') + + " If the file doesn't support tag listing, skip it + if s:Tlist_Skip_File(filename, ftype) + return + endif + + let tlist_win = bufwinnr(g:TagList_title) + + " If the taglist window is not opened and not configured to process + " tags always and not displaying the tags menu, then return + if tlist_win == -1 && !g:Tlist_Process_File_Always && !g:Tlist_Show_Menu + return + endif + + let fidx = s:Tlist_Get_File_Index(filename) + if fidx == -1 + " Check whether this file is removed based on user request + " If it is, then don't display the tags for this file + if s:Tlist_User_Removed_File(filename) + return + endif + + " If the taglist should not be auto updated, then return + if !g:Tlist_Auto_Update + return + endif + endif + + let cur_lnum = line('.') + + if fidx == -1 + " Update the tags for the file + let fidx = s:Tlist_Process_File(filename, ftype) + else + let mtime = getftime(filename) + if s:tlist_{fidx}_mtime != mtime + " Invalidate the tags listed for this file + let s:tlist_{fidx}_valid = 0 + + " Update the taglist and the window + call Tlist_Update_File(filename, ftype) + + " Store the new file modification time + let s:tlist_{fidx}_mtime = mtime + endif + endif + + " Update the taglist window + if tlist_win != -1 + " Disable screen updates + let old_lazyredraw = &lazyredraw + set nolazyredraw + + " Save the current window number + let save_winnr = winnr() + + " Goto the taglist window + call s:Tlist_Window_Goto_Window() + + if !g:Tlist_Auto_Highlight_Tag || !g:Tlist_Highlight_Tag_On_BufEnter + " Save the cursor position + let save_line = line('.') + let save_col = col('.') + endif + + " Update the taglist window + call s:Tlist_Window_Refresh_File(filename, ftype) + + " Open the fold for the file + exe "silent! " . s:tlist_{fidx}_start . "," . + \ s:tlist_{fidx}_end . "foldopen!" + + if g:Tlist_Highlight_Tag_On_BufEnter && g:Tlist_Auto_Highlight_Tag + if g:Tlist_Show_One_File && s:tlist_cur_file_idx != fidx + " If displaying tags for only one file in the taglist + " window and about to display the tags for a new file, + " then center the current tag line for the new file + let center_tag_line = 1 + else + let center_tag_line = 0 + endif + + " Highlight the current tag + call s:Tlist_Window_Highlight_Tag(filename, cur_lnum, 1, center_tag_line) + else + " Restore the cursor position + if v:version >= 601 + call cursor(save_line, save_col) + else + exe save_line + exe 'normal! ' . save_col . '|' + endif + endif + + " Jump back to the original window + if save_winnr != winnr() + call s:Tlist_Exe_Cmd_No_Acmds(save_winnr . 'wincmd w') + endif + + " Restore screen updates + let &lazyredraw = old_lazyredraw + endif + + " Update the taglist menu + if g:Tlist_Show_Menu + call s:Tlist_Menu_Update_File(0) + endif +endfunction + +" Tlist_Change_Sort() +" Change the sort order of the tag listing +" caller == 'cmd', command used in the taglist window +" caller == 'menu', taglist menu +" action == 'toggle', toggle sort from name to order and vice versa +" action == 'set', set the sort order to sort_type +function! s:Tlist_Change_Sort(caller, action, sort_type) + call s:Tlist_Log_Msg('Tlist_Change_Sort (caller = ' . a:caller . + \ ', action = ' . a:action . ', sort_type = ' . a:sort_type . ')') + if a:caller == 'cmd' + let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.')) + if fidx == -1 + return + endif + + " Remove the previous highlighting + match none + elseif a:caller == 'menu' + let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p')) + if fidx == -1 + return + endif + endif + + if a:action == 'toggle' + let sort_type = s:tlist_{fidx}_sort_type + + " Toggle the sort order from 'name' to 'order' and vice versa + if sort_type == 'name' + let s:tlist_{fidx}_sort_type = 'order' + else + let s:tlist_{fidx}_sort_type = 'name' + endif + else + let s:tlist_{fidx}_sort_type = a:sort_type + endif + + " Invalidate the tags listed for this file + let s:tlist_{fidx}_valid = 0 + + if a:caller == 'cmd' + " Save the current line for later restoration + let curline = '\V\^' . getline('.') . '\$' + + call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename, + \ s:tlist_{fidx}_filetype) + + exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!' + + " Go back to the cursor line before the tag list is sorted + call search(curline, 'w') + + call s:Tlist_Menu_Update_File(1) + else + call s:Tlist_Menu_Remove_File() + + call s:Tlist_Refresh() + endif +endfunction + +" Tlist_Update_Current_File() +" Update taglist for the current buffer by regenerating the tag list +" Contributed by WEN Guopeng. +function! s:Tlist_Update_Current_File() + call s:Tlist_Log_Msg('Tlist_Update_Current_File()') + if winnr() == bufwinnr(g:TagList_title) + " In the taglist window. Update the current file + call s:Tlist_Window_Update_File() + else + " Not in the taglist window. Update the current buffer + let filename = fnamemodify(bufname('%'), ':p') + let fidx = s:Tlist_Get_File_Index(filename) + if fidx != -1 + let s:tlist_{fidx}_valid = 0 + endif + let ft = s:Tlist_Get_Buffer_Filetype('%') + call Tlist_Update_File(filename, ft) + endif +endfunction + +" Tlist_Window_Update_File() +" Update the tags displayed in the taglist window +function! s:Tlist_Window_Update_File() + call s:Tlist_Log_Msg('Tlist_Window_Update_File()') + let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.')) + if fidx == -1 + return + endif + + " Remove the previous highlighting + match none + + " Save the current line for later restoration + let curline = '\V\^' . getline('.') . '\$' + + let s:tlist_{fidx}_valid = 0 + + " Update the taglist window + call s:Tlist_Window_Refresh_File(s:tlist_{fidx}_filename, + \ s:tlist_{fidx}_filetype) + + exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'foldopen!' + + " Go back to the tag line before the list is updated + call search(curline, 'w') +endfunction + +" Tlist_Window_Get_Tag_Type_By_Linenum() +" Return the tag type index for the specified line in the taglist window +function! s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum) + let ftype = s:tlist_{a:fidx}_filetype + + " Determine to which tag type the current line number belongs to using the + " tag type start line number and the number of tags in a tag type + let i = 1 + while i <= s:tlist_{ftype}_count + let ttype = s:tlist_{ftype}_{i}_name + let start_lnum = + \ s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset + let end = start_lnum + s:tlist_{a:fidx}_{ttype}_count + if a:lnum >= start_lnum && a:lnum <= end + break + endif + let i = i + 1 + endwhile + + " Current line doesn't belong to any of the displayed tag types + if i > s:tlist_{ftype}_count + return '' + endif + + return ttype +endfunction + +" Tlist_Window_Get_Tag_Index() +" Return the tag index for the specified line in the taglist window +function! s:Tlist_Window_Get_Tag_Index(fidx, lnum) + let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(a:fidx, a:lnum) + + " Current line doesn't belong to any of the displayed tag types + if ttype == '' + return 0 + endif + + " Compute the index into the displayed tags for the tag type + let ttype_lnum = s:tlist_{a:fidx}_start + s:tlist_{a:fidx}_{ttype}_offset + let tidx = a:lnum - ttype_lnum + if tidx == 0 + return 0 + endif + + " Get the corresponding tag line and return it + return s:tlist_{a:fidx}_{ttype}_{tidx} +endfunction + +" Tlist_Window_Highlight_Line +" Highlight the current line +function! s:Tlist_Window_Highlight_Line() + " Clear previously selected name + match none + + " Highlight the current line + if g:Tlist_Display_Prototype == 0 + let pat = '/\%' . line('.') . 'l\s\+\zs.*/' + else + let pat = '/\%' . line('.') . 'l.*/' + endif + + exe 'match TagListTagName ' . pat +endfunction + +" Tlist_Window_Open_File +" Open the specified file in either a new window or an existing window +" and place the cursor at the specified tag pattern +function! s:Tlist_Window_Open_File(win_ctrl, filename, tagpat) + call s:Tlist_Log_Msg('Tlist_Window_Open_File (' . a:filename . ',' . + \ a:win_ctrl . ')') + let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh + let s:Tlist_Skip_Refresh = 1 + + if s:tlist_app_name == "winmanager" + " Let the winmanager edit the file + call WinManagerFileEdit(a:filename, a:win_ctrl == 'newwin') + else + + if a:win_ctrl == 'newtab' + " Create a new tab + exe 'tabnew ' . escape(a:filename, ' ') + " Open the taglist window in the new tab + call s:Tlist_Window_Open() + endif + + if a:win_ctrl == 'checktab' + " Check whether the file is present in any of the tabs. + " If the file is present in the current tab, then use the + " current tab. + if bufwinnr(a:filename) != -1 + let file_present_in_tab = 1 + let i = tabpagenr() + else + let i = 1 + let bnum = bufnr(a:filename) + let file_present_in_tab = 0 + while i <= tabpagenr('$') + if index(tabpagebuflist(i), bnum) != -1 + let file_present_in_tab = 1 + break + endif + let i += 1 + endwhile + endif + + if file_present_in_tab + " Goto the tab containing the file + exe 'tabnext ' . i + else + " Open a new tab + exe 'tabnew ' . escape(a:filename, ' ') + + " Open the taglist window + call s:Tlist_Window_Open() + endif + endif + + let winnum = -1 + if a:win_ctrl == 'prevwin' + " Open the file in the previous window, if it is usable + let cur_win = winnr() + wincmd p + if &buftype == '' && !&previewwindow + exe "edit " . escape(a:filename, ' ') + let winnum = winnr() + else + " Previous window is not usable + exe cur_win . 'wincmd w' + endif + endif + + " Goto the window containing the file. If the window is not there, open a + " new window + if winnum == -1 + let winnum = bufwinnr(a:filename) + endif + + if winnum == -1 + " Locate the previously used window for opening a file + let fwin_num = 0 + let first_usable_win = 0 + + let i = 1 + let bnum = winbufnr(i) + while bnum != -1 + if getwinvar(i, 'tlist_file_window') == 'yes' + let fwin_num = i + break + endif + if first_usable_win == 0 && + \ getbufvar(bnum, '&buftype') == '' && + \ !getwinvar(i, '&previewwindow') + " First non-taglist, non-plugin and non-preview window + let first_usable_win = i + endif + let i = i + 1 + let bnum = winbufnr(i) + endwhile + + " If a previously used window is not found, then use the first + " non-taglist window + if fwin_num == 0 + let fwin_num = first_usable_win + endif + + if fwin_num != 0 + " Jump to the file window + exe fwin_num . "wincmd w" + + " If the user asked to jump to the tag in a new window, then split + " the existing window into two. + if a:win_ctrl == 'newwin' + split + endif + exe "edit " . escape(a:filename, ' ') + else + " Open a new window + if g:Tlist_Use_Horiz_Window + exe 'leftabove split ' . escape(a:filename, ' ') + else + if winbufnr(2) == -1 + " Only the taglist window is present + if g:Tlist_Use_Right_Window + exe 'leftabove vertical split ' . + \ escape(a:filename, ' ') + else + exe 'rightbelow vertical split ' . + \ escape(a:filename, ' ') + endif + + " Go to the taglist window to change the window size to + " the user configured value + call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') + if g:Tlist_Use_Horiz_Window + exe 'resize ' . g:Tlist_WinHeight + else + exe 'vertical resize ' . g:Tlist_WinWidth + endif + " Go back to the file window + call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') + else + " A plugin or help window is also present + wincmd w + exe 'leftabove split ' . escape(a:filename, ' ') + endif + endif + endif + " Mark the window, so that it can be reused. + call s:Tlist_Window_Mark_File_Window() + else + if v:version >= 700 + " If the file is opened in more than one window, then check + " whether the last accessed window has the selected file. + " If it does, then use that window. + let lastwin_bufnum = winbufnr(winnr('#')) + if bufnr(a:filename) == lastwin_bufnum + let winnum = winnr('#') + endif + endif + exe winnum . 'wincmd w' + + " If the user asked to jump to the tag in a new window, then split the + " existing window into two. + if a:win_ctrl == 'newwin' + split + endif + endif + endif + + " Jump to the tag + if a:tagpat != '' + " Add the current cursor position to the jump list, so that user can + " jump back using the ' and ` marks. + mark ' + silent call search(a:tagpat, 'w') + + " Bring the line to the middle of the window + normal! z. + + " If the line is inside a fold, open the fold + if foldclosed('.') != -1 + .foldopen + endif + endif + + " If the user selects to preview the tag then jump back to the + " taglist window + if a:win_ctrl == 'preview' + " Go back to the taglist window + let winnum = bufwinnr(g:TagList_title) + exe winnum . 'wincmd w' + else + " If the user has selected to close the taglist window, when a + " tag is selected, close the taglist window + if g:Tlist_Close_On_Select + call s:Tlist_Window_Goto_Window() + close + + " Go back to the window displaying the selected file + let wnum = bufwinnr(a:filename) + if wnum != -1 && wnum != winnr() + call s:Tlist_Exe_Cmd_No_Acmds(wnum . 'wincmd w') + endif + endif + endif + + let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh +endfunction + +" Tlist_Window_Jump_To_Tag() +" Jump to the location of the current tag +" win_ctrl == useopen - Reuse the existing file window +" win_ctrl == newwin - Open a new window +" win_ctrl == preview - Preview the tag +" win_ctrl == prevwin - Open in previous window +" win_ctrl == newtab - Open in new tab +function! s:Tlist_Window_Jump_To_Tag(win_ctrl) + call s:Tlist_Log_Msg('Tlist_Window_Jump_To_Tag(' . a:win_ctrl . ')') + " Do not process comment lines and empty lines + let curline = getline('.') + if curline =~ '^\s*$' || curline[0] == '"' + return + endif + + " If inside a closed fold, then use the first line of the fold + " and jump to the file. + let lnum = foldclosed('.') + if lnum == -1 + " Jump to the selected tag or file + let lnum = line('.') + else + " Open the closed fold + .foldopen! + endif + + let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum) + if fidx == -1 + return + endif + + " Get the tag output for the current tag + let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum) + if tidx != 0 + let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, tidx) + + " Highlight the tagline + call s:Tlist_Window_Highlight_Line() + else + " Selected a line which is not a tag name. Just edit the file + let tagpat = '' + endif + + call s:Tlist_Window_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat) +endfunction + +" Tlist_Window_Show_Info() +" Display information about the entry under the cursor +function! s:Tlist_Window_Show_Info() + call s:Tlist_Log_Msg('Tlist_Window_Show_Info()') + + " Clear the previously displayed line + echo + + " Do not process comment lines and empty lines + let curline = getline('.') + if curline =~ '^\s*$' || curline[0] == '"' + return + endif + + " If inside a fold, then don't display the prototype + if foldclosed('.') != -1 + return + endif + + let lnum = line('.') + + " Get the file index + let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(lnum) + if fidx == -1 + return + endif + + if lnum == s:tlist_{fidx}_start + " Cursor is on a file name + let fname = s:tlist_{fidx}_filename + if strlen(fname) > 50 + let fname = fnamemodify(fname, ':t') + endif + echo fname . ', Filetype=' . s:tlist_{fidx}_filetype . + \ ', Tag count=' . s:tlist_{fidx}_tag_count + return + endif + + " Get the tag output line for the current tag + let tidx = s:Tlist_Window_Get_Tag_Index(fidx, lnum) + if tidx == 0 + " Cursor is on a tag type + let ttype = s:Tlist_Window_Get_Tag_Type_By_Linenum(fidx, lnum) + if ttype == '' + return + endif + + let ttype_name = '' + + let ftype = s:tlist_{fidx}_filetype + let i = 1 + while i <= s:tlist_{ftype}_count + if ttype == s:tlist_{ftype}_{i}_name + let ttype_name = s:tlist_{ftype}_{i}_fullname + break + endif + let i = i + 1 + endwhile + + echo 'Tag type=' . ttype_name . + \ ', Tag count=' . s:tlist_{fidx}_{ttype}_count + return + endif + + " Get the tag search pattern and display it + echo s:Tlist_Get_Tag_Prototype(fidx, tidx) +endfunction + +" Tlist_Find_Nearest_Tag_Idx +" Find the tag idx nearest to the supplied line number +" Returns -1, if a tag couldn't be found for the specified line number +function! s:Tlist_Find_Nearest_Tag_Idx(fidx, linenum) + let sort_type = s:tlist_{a:fidx}_sort_type + + let left = 1 + let right = s:tlist_{a:fidx}_tag_count + + if sort_type == 'order' + " Tags sorted by order, use a binary search. + " The idea behind this function is taken from the ctags.vim script (by + " Alexey Marinichev) available at the Vim online website. + + " If the current line is the less than the first tag, then no need to + " search + let first_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, 1) + + if a:linenum < first_lnum + return -1 + endif + + while left < right + let middle = (right + left + 1) / 2 + let middle_lnum = s:Tlist_Get_Tag_Linenum(a:fidx, middle) + + if middle_lnum == a:linenum + let left = middle + break + endif + + if middle_lnum > a:linenum + let right = middle - 1 + else + let left = middle + endif + endwhile + else + " Tags sorted by name, use a linear search. (contributed by Dave + " Eggum). + " Look for a tag with a line number less than or equal to the supplied + " line number. If multiple tags are found, then use the tag with the + " line number closest to the supplied line number. IOW, use the tag + " with the highest line number. + let closest_lnum = 0 + let final_left = 0 + while left <= right + let lnum = s:Tlist_Get_Tag_Linenum(a:fidx, left) + + if lnum < a:linenum && lnum > closest_lnum + let closest_lnum = lnum + let final_left = left + elseif lnum == a:linenum + let closest_lnum = lnum + let final_left = left + break + else + let left = left + 1 + endif + endwhile + if closest_lnum == 0 + return -1 + endif + if left >= right + let left = final_left + endif + endif + + return left +endfunction + +" Tlist_Window_Highlight_Tag() +" Highlight the current tag +" cntx == 1, Called by the taglist plugin itself +" cntx == 2, Forced by the user through the TlistHighlightTag command +" center = 1, move the tag line to the center of the taglist window +function! s:Tlist_Window_Highlight_Tag(filename, cur_lnum, cntx, center) + " Highlight the current tag only if the user configured the + " taglist plugin to do so or if the user explictly invoked the + " command to highlight the current tag. + if !g:Tlist_Auto_Highlight_Tag && a:cntx == 1 + return + endif + + if a:filename == '' + return + endif + + " Make sure the taglist window is present + let winnum = bufwinnr(g:TagList_title) + if winnum == -1 + call s:Tlist_Warning_Msg('Error: Taglist window is not open') + return + endif + + let fidx = s:Tlist_Get_File_Index(a:filename) + if fidx == -1 + return + endif + + " If the file is currently not displayed in the taglist window, then retrn + if !s:tlist_{fidx}_visible + return + endif + + " If there are no tags for this file, then no need to proceed further + if s:tlist_{fidx}_tag_count == 0 + return + endif + + " Ignore all autocommands + let old_ei = &eventignore + set eventignore=all + + " Save the original window number + let org_winnr = winnr() + + if org_winnr == winnum + let in_taglist_window = 1 + else + let in_taglist_window = 0 + endif + + " Go to the taglist window + if !in_taglist_window + exe winnum . 'wincmd w' + endif + + " Clear previously selected name + match none + + let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, a:cur_lnum) + if tidx == -1 + " Make sure the current tag line is visible in the taglist window. + " Calling the winline() function makes the line visible. Don't know + " of a better way to achieve this. + let lnum = line('.') + + if lnum < s:tlist_{fidx}_start || lnum > s:tlist_{fidx}_end + " Move the cursor to the beginning of the file + exe s:tlist_{fidx}_start + endif + + if foldclosed('.') != -1 + .foldopen + endif + + call winline() + + if !in_taglist_window + exe org_winnr . 'wincmd w' + endif + + " Restore the autocommands + let &eventignore = old_ei + return + endif + + " Extract the tag type + let ttype = s:Tlist_Get_Tag_Type_By_Tag(fidx, tidx) + + " Compute the line number + " Start of file + Start of tag type + offset + let lnum = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset + + \ s:tlist_{fidx}_{tidx}_ttype_idx + + " Goto the line containing the tag + exe lnum + + " Open the fold + if foldclosed('.') != -1 + .foldopen + endif + + if a:center + " Move the tag line to the center of the taglist window + normal! z. + else + " Make sure the current tag line is visible in the taglist window. + " Calling the winline() function makes the line visible. Don't know + " of a better way to achieve this. + call winline() + endif + + " Highlight the tag name + call s:Tlist_Window_Highlight_Line() + + " Go back to the original window + if !in_taglist_window + exe org_winnr . 'wincmd w' + endif + + " Restore the autocommands + let &eventignore = old_ei + return +endfunction + +" Tlist_Get_Tag_Prototype_By_Line +" Get the prototype for the tag on or before the specified line number in the +" current buffer +function! Tlist_Get_Tag_Prototype_By_Line(...) + if a:0 == 0 + " Arguments are not supplied. Use the current buffer name + " and line number + let filename = bufname('%') + let linenr = line('.') + elseif a:0 == 2 + " Filename and line number are specified + let filename = a:1 + let linenr = a:2 + if linenr !~ '\d\+' + " Invalid line number + return "" + endif + else + " Sufficient arguments are not supplied + let msg = 'Usage: Tlist_Get_Tag_Prototype_By_Line ' . + \ '' + call s:Tlist_Warning_Msg(msg) + return "" + endif + + " Expand the file to a fully qualified name + let filename = fnamemodify(filename, ':p') + if filename == '' + return "" + endif + + let fidx = s:Tlist_Get_File_Index(filename) + if fidx == -1 + return "" + endif + + " If there are no tags for this file, then no need to proceed further + if s:tlist_{fidx}_tag_count == 0 + return "" + endif + + " Get the tag text using the line number + let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr) + if tidx == -1 + return "" + endif + + return s:Tlist_Get_Tag_Prototype(fidx, tidx) +endfunction + +" Tlist_Get_Tagname_By_Line +" Get the tag name on or before the specified line number in the +" current buffer +function! Tlist_Get_Tagname_By_Line(...) + if a:0 == 0 + " Arguments are not supplied. Use the current buffer name + " and line number + let filename = bufname('%') + let linenr = line('.') + elseif a:0 == 2 + " Filename and line number are specified + let filename = a:1 + let linenr = a:2 + if linenr !~ '\d\+' + " Invalid line number + return "" + endif + else + " Sufficient arguments are not supplied + let msg = 'Usage: Tlist_Get_Tagname_By_Line ' + call s:Tlist_Warning_Msg(msg) + return "" + endif + + " Make sure the current file has a name + let filename = fnamemodify(filename, ':p') + if filename == '' + return "" + endif + + let fidx = s:Tlist_Get_File_Index(filename) + if fidx == -1 + return "" + endif + + " If there are no tags for this file, then no need to proceed further + if s:tlist_{fidx}_tag_count == 0 + return "" + endif + + " Get the tag name using the line number + let tidx = s:Tlist_Find_Nearest_Tag_Idx(fidx, linenr) + if tidx == -1 + return "" + endif + + return s:tlist_{fidx}_{tidx}_tag_name +endfunction + +" Tlist_Window_Move_To_File +" Move the cursor to the beginning of the current file or the next file +" or the previous file in the taglist window +" dir == -1, move to start of current or previous function +" dir == 1, move to start of next function +function! s:Tlist_Window_Move_To_File(dir) + if foldlevel('.') == 0 + " Cursor is on a non-folded line (it is not in any of the files) + " Move it to a folded line + if a:dir == -1 + normal! zk + else + " While moving down to the start of the next fold, + " no need to do go to the start of the next file. + normal! zj + return + endif + endif + + let fidx = s:Tlist_Window_Get_File_Index_By_Linenum(line('.')) + if fidx == -1 + return + endif + + let cur_lnum = line('.') + + if a:dir == -1 + if cur_lnum > s:tlist_{fidx}_start + " Move to the beginning of the current file + exe s:tlist_{fidx}_start + return + endif + + if fidx != 0 + " Move to the beginning of the previous file + let fidx = fidx - 1 + else + " Cursor is at the first file, wrap around to the last file + let fidx = s:tlist_file_count - 1 + endif + + exe s:tlist_{fidx}_start + return + else + " Move to the beginning of the next file + let fidx = fidx + 1 + + if fidx >= s:tlist_file_count + " Cursor is at the last file, wrap around to the first file + let fidx = 0 + endif + + if s:tlist_{fidx}_start != 0 + exe s:tlist_{fidx}_start + endif + return + endif +endfunction + +" Tlist_Session_Load +" Load a taglist session (information about all the displayed files +" and the tags) from the specified file +function! s:Tlist_Session_Load(...) + if a:0 == 0 || a:1 == '' + call s:Tlist_Warning_Msg('Usage: TlistSessionLoad ') + return + endif + + let sessionfile = a:1 + + if !filereadable(sessionfile) + let msg = 'Taglist: Error - Unable to open file ' . sessionfile + call s:Tlist_Warning_Msg(msg) + return + endif + + " Mark the current window as the file window + call s:Tlist_Window_Mark_File_Window() + + " Source the session file + exe 'source ' . sessionfile + + let new_file_count = g:tlist_file_count + unlet! g:tlist_file_count + + let i = 0 + while i < new_file_count + let ftype = g:tlist_{i}_filetype + unlet! g:tlist_{i}_filetype + + if !exists('s:tlist_' . ftype . '_count') + if s:Tlist_FileType_Init(ftype) == 0 + let i = i + 1 + continue + endif + endif + + let fname = g:tlist_{i}_filename + unlet! g:tlist_{i}_filename + + let fidx = s:Tlist_Get_File_Index(fname) + if fidx != -1 + let s:tlist_{fidx}_visible = 0 + let i = i + 1 + continue + else + " As we are loading the tags from the session file, if this + " file was previously deleted by the user, now we need to + " add it back. So remove the file from the deleted list. + call s:Tlist_Update_Remove_List(fname, 0) + endif + + let fidx = s:Tlist_Init_File(fname, ftype) + + let s:tlist_{fidx}_filename = fname + + let s:tlist_{fidx}_sort_type = g:tlist_{i}_sort_type + unlet! g:tlist_{i}_sort_type + + let s:tlist_{fidx}_filetype = ftype + let s:tlist_{fidx}_mtime = getftime(fname) + + let s:tlist_{fidx}_start = 0 + let s:tlist_{fidx}_end = 0 + + let s:tlist_{fidx}_valid = 1 + + let s:tlist_{fidx}_tag_count = g:tlist_{i}_tag_count + unlet! g:tlist_{i}_tag_count + + let j = 1 + while j <= s:tlist_{fidx}_tag_count + let s:tlist_{fidx}_{j}_tag = g:tlist_{i}_{j}_tag + let s:tlist_{fidx}_{j}_tag_name = g:tlist_{i}_{j}_tag_name + let s:tlist_{fidx}_{j}_ttype_idx = g:tlist_{i}_{j}_ttype_idx + unlet! g:tlist_{i}_{j}_tag + unlet! g:tlist_{i}_{j}_tag_name + unlet! g:tlist_{i}_{j}_ttype_idx + let j = j + 1 + endwhile + + let j = 1 + while j <= s:tlist_{ftype}_count + let ttype = s:tlist_{ftype}_{j}_name + + if exists('g:tlist_' . i . '_' . ttype) + let s:tlist_{fidx}_{ttype} = g:tlist_{i}_{ttype} + unlet! g:tlist_{i}_{ttype} + let s:tlist_{fidx}_{ttype}_offset = 0 + let s:tlist_{fidx}_{ttype}_count = g:tlist_{i}_{ttype}_count + unlet! g:tlist_{i}_{ttype}_count + + let k = 1 + while k <= s:tlist_{fidx}_{ttype}_count + let s:tlist_{fidx}_{ttype}_{k} = g:tlist_{i}_{ttype}_{k} + unlet! g:tlist_{i}_{ttype}_{k} + let k = k + 1 + endwhile + else + let s:tlist_{fidx}_{ttype} = '' + let s:tlist_{fidx}_{ttype}_offset = 0 + let s:tlist_{fidx}_{ttype}_count = 0 + endif + + let j = j + 1 + endwhile + + let i = i + 1 + endwhile + + " If the taglist window is open, then update it + let winnum = bufwinnr(g:TagList_title) + if winnum != -1 + let save_winnr = winnr() + + " Goto the taglist window + call s:Tlist_Window_Goto_Window() + + " Refresh the taglist window + call s:Tlist_Window_Refresh() + + " Go back to the original window + if save_winnr != winnr() + call s:Tlist_Exe_Cmd_No_Acmds('wincmd p') + endif + endif +endfunction + +" Tlist_Session_Save +" Save a taglist session (information about all the displayed files +" and the tags) into the specified file +function! s:Tlist_Session_Save(...) + if a:0 == 0 || a:1 == '' + call s:Tlist_Warning_Msg('Usage: TlistSessionSave ') + return + endif + + let sessionfile = a:1 + + if s:tlist_file_count == 0 + " There is nothing to save + call s:Tlist_Warning_Msg('Warning: Taglist is empty. Nothing to save.') + return + endif + + if filereadable(sessionfile) + let ans = input('Do you want to overwrite ' . sessionfile . ' (Y/N)?') + if ans !=? 'y' + return + endif + + echo "\n" + endif + + let old_verbose = &verbose + set verbose&vim + + exe 'redir! > ' . sessionfile + + silent! echo '" Taglist session file. This file is auto-generated.' + silent! echo '" File information' + silent! echo 'let tlist_file_count = ' . s:tlist_file_count + + let i = 0 + + while i < s:tlist_file_count + " Store information about the file + silent! echo 'let tlist_' . i . "_filename = '" . + \ s:tlist_{i}_filename . "'" + silent! echo 'let tlist_' . i . '_sort_type = "' . + \ s:tlist_{i}_sort_type . '"' + silent! echo 'let tlist_' . i . '_filetype = "' . + \ s:tlist_{i}_filetype . '"' + silent! echo 'let tlist_' . i . '_tag_count = ' . + \ s:tlist_{i}_tag_count + " Store information about all the tags + let j = 1 + while j <= s:tlist_{i}_tag_count + let txt = escape(s:tlist_{i}_{j}_tag, '"\\') + silent! echo 'let tlist_' . i . '_' . j . '_tag = "' . txt . '"' + silent! echo 'let tlist_' . i . '_' . j . '_tag_name = "' . + \ s:tlist_{i}_{j}_tag_name . '"' + silent! echo 'let tlist_' . i . '_' . j . '_ttype_idx' . ' = ' . + \ s:tlist_{i}_{j}_ttype_idx + let j = j + 1 + endwhile + + " Store information about all the tags grouped by their type + let ftype = s:tlist_{i}_filetype + let j = 1 + while j <= s:tlist_{ftype}_count + let ttype = s:tlist_{ftype}_{j}_name + if s:tlist_{i}_{ttype}_count != 0 + let txt = escape(s:tlist_{i}_{ttype}, '"\') + let txt = substitute(txt, "\n", "\\\\n", 'g') + silent! echo 'let tlist_' . i . '_' . ttype . ' = "' . + \ txt . '"' + silent! echo 'let tlist_' . i . '_' . ttype . '_count = ' . + \ s:tlist_{i}_{ttype}_count + let k = 1 + while k <= s:tlist_{i}_{ttype}_count + silent! echo 'let tlist_' . i . '_' . ttype . '_' . k . + \ ' = ' . s:tlist_{i}_{ttype}_{k} + let k = k + 1 + endwhile + endif + let j = j + 1 + endwhile + + silent! echo + + let i = i + 1 + endwhile + + redir END + + let &verbose = old_verbose +endfunction + +" Tlist_Buffer_Removed +" A buffer is removed from the Vim buffer list. Remove the tags defined +" for that file +function! s:Tlist_Buffer_Removed(filename) + call s:Tlist_Log_Msg('Tlist_Buffer_Removed (' . a:filename . ')') + + " Make sure a valid filename is supplied + if a:filename == '' + return + endif + + " Get tag list index of the specified file + let fidx = s:Tlist_Get_File_Index(a:filename) + if fidx == -1 + " File not present in the taglist + return + endif + + " Remove the file from the list + call s:Tlist_Remove_File(fidx, 0) +endfunction + +" When a buffer is deleted, remove the file from the taglist +autocmd BufDelete * silent call s:Tlist_Buffer_Removed(expand(':p')) + +" Tlist_Window_Open_File_Fold +" Open the fold for the specified file and close the fold for all the +" other files +function! s:Tlist_Window_Open_File_Fold(acmd_bufnr) + call s:Tlist_Log_Msg('Tlist_Window_Open_File_Fold (' . a:acmd_bufnr . ')') + + " Make sure the taglist window is present + let winnum = bufwinnr(g:TagList_title) + if winnum == -1 + call s:Tlist_Warning_Msg('Taglist: Error - Taglist window is not open') + return + endif + + " Save the original window number + let org_winnr = winnr() + if org_winnr == winnum + let in_taglist_window = 1 + else + let in_taglist_window = 0 + endif + + if in_taglist_window + " When entering the taglist window, no need to update the folds + return + endif + + " Go to the taglist window + if !in_taglist_window + call s:Tlist_Exe_Cmd_No_Acmds(winnum . 'wincmd w') + endif + + " Close all the folds + silent! %foldclose + + " Get tag list index of the specified file + let fname = fnamemodify(bufname(a:acmd_bufnr + 0), ':p') + if filereadable(fname) + let fidx = s:Tlist_Get_File_Index(fname) + if fidx != -1 + " Open the fold for the file + exe "silent! " . s:tlist_{fidx}_start . "," . + \ s:tlist_{fidx}_end . "foldopen" + endif + endif + + " Go back to the original window + if !in_taglist_window + call s:Tlist_Exe_Cmd_No_Acmds(org_winnr . 'wincmd w') + endif +endfunction + +" Tlist_Window_Check_Auto_Open +" Open the taglist window automatically on Vim startup. +" Open the window only when files present in any of the Vim windows support +" tags. +function! s:Tlist_Window_Check_Auto_Open() + let open_window = 0 + + let i = 1 + let buf_num = winbufnr(i) + while buf_num != -1 + let filename = fnamemodify(bufname(buf_num), ':p') + let ft = s:Tlist_Get_Buffer_Filetype(buf_num) + if !s:Tlist_Skip_File(filename, ft) + let open_window = 1 + break + endif + let i = i + 1 + let buf_num = winbufnr(i) + endwhile + + if open_window + call s:Tlist_Window_Toggle() + endif +endfunction + +" Tlist_Refresh_Folds +" Remove and create the folds for all the files displayed in the taglist +" window. Used after entering a tab. If this is not done, then the folds +" are not properly created for taglist windows displayed in multiple tabs. +function! s:Tlist_Refresh_Folds() + let winnum = bufwinnr(g:TagList_title) + if winnum == -1 + return + endif + + let save_wnum = winnr() + exe winnum . 'wincmd w' + + " First remove all the existing folds + normal! zE + + " Create the folds for each in the tag list + let fidx = 0 + while fidx < s:tlist_file_count + let ftype = s:tlist_{fidx}_filetype + + " Create the folds for each tag type in a file + let j = 1 + while j <= s:tlist_{ftype}_count + let ttype = s:tlist_{ftype}_{j}_name + if s:tlist_{fidx}_{ttype}_count + let s = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_offset + let e = s + s:tlist_{fidx}_{ttype}_count + exe s . ',' . e . 'fold' + endif + let j = j + 1 + endwhile + + exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold' + exe 'silent! ' . s:tlist_{fidx}_start . ',' . + \ s:tlist_{fidx}_end . 'foldopen!' + let fidx = fidx + 1 + endwhile + + exe save_wnum . 'wincmd w' +endfunction + +function! s:Tlist_Menu_Add_Base_Menu() + call s:Tlist_Log_Msg('Adding the base menu') + + " Add the menu + anoremenu T&ags.Refresh\ menu :call Tlist_Menu_Refresh() + anoremenu T&ags.Sort\ menu\ by.Name + \ :call Tlist_Change_Sort('menu', 'set', 'name') + anoremenu T&ags.Sort\ menu\ by.Order + \ :call Tlist_Change_Sort('menu', 'set', 'order') + anoremenu T&ags.-SEP1- : + + if &mousemodel =~ 'popup' + anoremenu PopUp.T&ags.Refresh\ menu + \ :call Tlist_Menu_Refresh() + anoremenu PopUp.T&ags.Sort\ menu\ by.Name + \ :call Tlist_Change_Sort('menu', 'set', 'name') + anoremenu PopUp.T&ags.Sort\ menu\ by.Order + \ :call Tlist_Change_Sort('menu', 'set', 'order') + anoremenu PopUp.T&ags.-SEP1- : + endif +endfunction + +let s:menu_char_prefix = + \ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + +" Tlist_Menu_Get_Tag_Type_Cmd +" Get the menu command for the specified tag type +" fidx - File type index +" ftype - File Type +" add_ttype_name - To add or not to add the tag type name to the menu entries +" ttype_idx - Tag type index +function! s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, ttype_idx) + " Curly brace variable name optimization + let ftype_ttype_idx = a:ftype . '_' . a:ttype_idx + + let ttype = s:tlist_{ftype_ttype_idx}_name + if a:add_ttype_name + " If the tag type name contains space characters, escape it. This + " will be used to create the menu entries. + let ttype_fullname = escape(s:tlist_{ftype_ttype_idx}_fullname, ' ') + endif + + " Curly brace variable name optimization + let fidx_ttype = a:fidx . '_' . ttype + + " Number of tag entries for this tag type + let tcnt = s:tlist_{fidx_ttype}_count + if tcnt == 0 " No entries for this tag type + return '' + endif + + let mcmd = '' + + " Create the menu items for the tags. + " Depending on the number of tags of this type, split the menu into + " multiple sub-menus, if needed. + if tcnt > g:Tlist_Max_Submenu_Items + let j = 1 + while j <= tcnt + let final_index = j + g:Tlist_Max_Submenu_Items - 1 + if final_index > tcnt + let final_index = tcnt + endif + + " Extract the first and last tag name and form the + " sub-menu name + let tidx = s:tlist_{fidx_ttype}_{j} + let first_tag = s:tlist_{a:fidx}_{tidx}_tag_name + + let tidx = s:tlist_{fidx_ttype}_{final_index} + let last_tag = s:tlist_{a:fidx}_{tidx}_tag_name + + " Truncate the names, if they are greater than the + " max length + let first_tag = strpart(first_tag, 0, g:Tlist_Max_Tag_Length) + let last_tag = strpart(last_tag, 0, g:Tlist_Max_Tag_Length) + + " Form the menu command prefix + let m_prefix = 'anoremenu T\&ags.' + if a:add_ttype_name + let m_prefix = m_prefix . ttype_fullname . '.' + endif + let m_prefix = m_prefix . first_tag . '\.\.\.' . last_tag . '.' + + " Character prefix used to number the menu items (hotkey) + let m_prefix_idx = 0 + + while j <= final_index + let tidx = s:tlist_{fidx_ttype}_{j} + + let tname = s:tlist_{a:fidx}_{tidx}_tag_name + + let mcmd = mcmd . m_prefix . '\&' . + \ s:menu_char_prefix[m_prefix_idx] . '\.' . + \ tname . ' :call Tlist_Menu_Jump_To_Tag(' . + \ tidx . ')|' + + let m_prefix_idx = m_prefix_idx + 1 + let j = j + 1 + endwhile + endwhile + else + " Character prefix used to number the menu items (hotkey) + let m_prefix_idx = 0 + + let m_prefix = 'anoremenu T\&ags.' + if a:add_ttype_name + let m_prefix = m_prefix . ttype_fullname . '.' + endif + let j = 1 + while j <= tcnt + let tidx = s:tlist_{fidx_ttype}_{j} + + let tname = s:tlist_{a:fidx}_{tidx}_tag_name + + let mcmd = mcmd . m_prefix . '\&' . + \ s:menu_char_prefix[m_prefix_idx] . '\.' . + \ tname . ' :call Tlist_Menu_Jump_To_Tag(' . tidx + \ . ')|' + + let m_prefix_idx = m_prefix_idx + 1 + let j = j + 1 + endwhile + endif + + return mcmd +endfunction + +" Update the taglist menu with the tags for the specified file +function! s:Tlist_Menu_File_Refresh(fidx) + call s:Tlist_Log_Msg('Refreshing the tag menu for ' . s:tlist_{a:fidx}_filename) + " The 'B' flag is needed in the 'cpoptions' option + let old_cpoptions = &cpoptions + set cpoptions&vim + + exe s:tlist_{a:fidx}_menu_cmd + + " Update the popup menu (if enabled) + if &mousemodel =~ 'popup' + let cmd = substitute(s:tlist_{a:fidx}_menu_cmd, ' T\\&ags\.', + \ ' PopUp.T\\\&ags.', "g") + exe cmd + endif + + " The taglist menu is not empty now + let s:tlist_menu_empty = 0 + + " Restore the 'cpoptions' settings + let &cpoptions = old_cpoptions +endfunction + +" Tlist_Menu_Update_File +" Add the taglist menu +function! s:Tlist_Menu_Update_File(clear_menu) + if !has('gui_running') + " Not running in GUI mode + return + endif + + call s:Tlist_Log_Msg('Updating the tag menu, clear_menu = ' . a:clear_menu) + + " Remove the tags menu + if a:clear_menu + call s:Tlist_Menu_Remove_File() + + endif + + " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help + if &buftype != '' + return + endif + + let filename = fnamemodify(bufname('%'), ':p') + let ftype = s:Tlist_Get_Buffer_Filetype('%') + + " If the file doesn't support tag listing, skip it + if s:Tlist_Skip_File(filename, ftype) + return + endif + + let fidx = s:Tlist_Get_File_Index(filename) + if fidx == -1 || !s:tlist_{fidx}_valid + " Check whether this file is removed based on user request + " If it is, then don't display the tags for this file + if s:Tlist_User_Removed_File(filename) + return + endif + + " Process the tags for the file + let fidx = s:Tlist_Process_File(filename, ftype) + if fidx == -1 + return + endif + endif + + let fname = escape(fnamemodify(bufname('%'), ':t'), '.') + if fname != '' + exe 'anoremenu T&ags.' . fname . ' ' + anoremenu T&ags.-SEP2- : + endif + + if !s:tlist_{fidx}_tag_count + return + endif + + if s:tlist_{fidx}_menu_cmd != '' + " Update the menu with the cached command + call s:Tlist_Menu_File_Refresh(fidx) + + return + endif + + " We are going to add entries to the tags menu, so the menu won't be + " empty + let s:tlist_menu_empty = 0 + + let cmd = '' + + " Determine whether the tag type name needs to be added to the menu + " If more than one tag type is present in the taglisting for a file, + " then the tag type name needs to be present + let add_ttype_name = -1 + let i = 1 + while i <= s:tlist_{ftype}_count && add_ttype_name < 1 + let ttype = s:tlist_{ftype}_{i}_name + if s:tlist_{fidx}_{ttype}_count + let add_ttype_name = add_ttype_name + 1 + endif + let i = i + 1 + endwhile + + " Process the tags by the tag type and get the menu command + let i = 1 + while i <= s:tlist_{ftype}_count + let mcmd = s:Tlist_Menu_Get_Tag_Type_Cmd(fidx, ftype, add_ttype_name, i) + if mcmd != '' + let cmd = cmd . mcmd + endif + + let i = i + 1 + endwhile + + " Cache the menu command for reuse + let s:tlist_{fidx}_menu_cmd = cmd + + " Update the menu + call s:Tlist_Menu_File_Refresh(fidx) +endfunction + +" Tlist_Menu_Remove_File +" Remove the tags displayed in the tags menu +function! s:Tlist_Menu_Remove_File() + if !has('gui_running') || s:tlist_menu_empty + return + endif + + call s:Tlist_Log_Msg('Removing the tags menu for a file') + + " Cleanup the Tags menu + silent! unmenu T&ags + if &mousemodel =~ 'popup' + silent! unmenu PopUp.T&ags + endif + + " Add a dummy menu item to retain teared off menu + noremenu T&ags.Dummy l + + silent! unmenu! T&ags + if &mousemodel =~ 'popup' + silent! unmenu! PopUp.T&ags + endif + + call s:Tlist_Menu_Add_Base_Menu() + + " Remove the dummy menu item + unmenu T&ags.Dummy + + let s:tlist_menu_empty = 1 +endfunction + +" Tlist_Menu_Refresh +" Refresh the taglist menu +function! s:Tlist_Menu_Refresh() + call s:Tlist_Log_Msg('Refreshing the tags menu') + let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p')) + if fidx != -1 + " Invalidate the cached menu command + let s:tlist_{fidx}_menu_cmd = '' + endif + + " Update the taglist, menu and window + call s:Tlist_Update_Current_File() +endfunction + +" Tlist_Menu_Jump_To_Tag +" Jump to the selected tag +function! s:Tlist_Menu_Jump_To_Tag(tidx) + let fidx = s:Tlist_Get_File_Index(fnamemodify(bufname('%'), ':p')) + if fidx == -1 + return + endif + + let tagpat = s:Tlist_Get_Tag_SearchPat(fidx, a:tidx) + if tagpat == '' + return + endif + + " Add the current cursor position to the jump list, so that user can + " jump back using the ' and ` marks. + mark ' + + silent call search(tagpat, 'w') + + " Bring the line to the middle of the window + normal! z. + + " If the line is inside a fold, open the fold + if foldclosed('.') != -1 + .foldopen + endif +endfunction + +" Tlist_Menu_Init +" Initialize the taglist menu +function! s:Tlist_Menu_Init() + call s:Tlist_Menu_Add_Base_Menu() + + " Automatically add the tags defined in the current file to the menu + augroup TagListMenuCmds + autocmd! + + if !g:Tlist_Process_File_Always + autocmd BufEnter * call s:Tlist_Refresh() + endif + autocmd BufLeave * call s:Tlist_Menu_Remove_File() + augroup end + + call s:Tlist_Menu_Update_File(0) +endfunction + +" Tlist_Vim_Session_Load +" Initialize the taglist window/buffer, which is created when loading +" a Vim session file. +function! s:Tlist_Vim_Session_Load() + call s:Tlist_Log_Msg('Tlist_Vim_Session_Load') + + " Initialize the taglist window + call s:Tlist_Window_Init() + + " Refresh the taglist window + call s:Tlist_Window_Refresh() +endfunction + +" Tlist_Set_App +" Set the name of the external plugin/application to which taglist +" belongs. +" Taglist plugin is part of another plugin like cream or winmanager. +function! Tlist_Set_App(name) + if a:name == "" + return + endif + + let s:tlist_app_name = a:name +endfunction + +" Winmanager integration + +" Initialization required for integration with winmanager +function! TagList_Start() + " If current buffer is not taglist buffer, then don't proceed + if bufname('%') != '__Tag_List__' + return + endif + + call Tlist_Set_App('winmanager') + + " Get the current filename from the winmanager plugin + let bufnum = WinManagerGetLastEditedFile() + if bufnum != -1 + let filename = fnamemodify(bufname(bufnum), ':p') + let ftype = s:Tlist_Get_Buffer_Filetype(bufnum) + endif + + " Initialize the taglist window, if it is not already initialized + if !exists('s:tlist_window_initialized') || !s:tlist_window_initialized + call s:Tlist_Window_Init() + call s:Tlist_Window_Refresh() + let s:tlist_window_initialized = 1 + endif + + " Update the taglist window + if bufnum != -1 + if !s:Tlist_Skip_File(filename, ftype) && g:Tlist_Auto_Update + call s:Tlist_Window_Refresh_File(filename, ftype) + endif + endif +endfunction + +function! TagList_IsValid() + return 0 +endfunction + +function! TagList_WrapUp() + return 0 +endfunction + +" restore 'cpo' +let &cpo = s:cpo_save +unlet s:cpo_save + diff --git a/.vim/syntax/nerdtree.vim b/.vim/syntax/nerdtree.vim new file mode 100644 index 0000000..636d2af --- /dev/null +++ b/.vim/syntax/nerdtree.vim @@ -0,0 +1,88 @@ +let s:tree_up_dir_line = '.. (up a dir)' +"NERDTreeFlags are syntax items that should be invisible, but give clues as to +"how things should be highlighted +syn match NERDTreeFlag #\~# +syn match NERDTreeFlag #\[RO\]# + +"highlighting for the .. (up dir) line at the top of the tree +execute "syn match NERDTreeUp #\\V". s:tree_up_dir_line ."#" + +"highlighting for the ~/+ symbols for the directory nodes +syn match NERDTreeClosable #\~\<# +syn match NERDTreeClosable #\~\.# +syn match NERDTreeOpenable #+\<# +syn match NERDTreeOpenable #+\.#he=e-1 + +"highlighting for the tree structural parts +syn match NERDTreePart #|# +syn match NERDTreePart #`# +syn match NERDTreePartFile #[|`]-#hs=s+1 contains=NERDTreePart + +"quickhelp syntax elements +syn match NERDTreeHelpKey #" \{1,2\}[^ ]*:#hs=s+2,he=e-1 +syn match NERDTreeHelpKey #" \{1,2\}[^ ]*,#hs=s+2,he=e-1 +syn match NERDTreeHelpTitle #" .*\~#hs=s+2,he=e-1 contains=NERDTreeFlag +syn match NERDTreeToggleOn #".*(on)#hs=e-2,he=e-1 contains=NERDTreeHelpKey +syn match NERDTreeToggleOff #".*(off)#hs=e-3,he=e-1 contains=NERDTreeHelpKey +syn match NERDTreeHelpCommand #" :.\{-}\>#hs=s+3 +syn match NERDTreeHelp #^".*# contains=NERDTreeHelpKey,NERDTreeHelpTitle,NERDTreeFlag,NERDTreeToggleOff,NERDTreeToggleOn,NERDTreeHelpCommand + +"highlighting for readonly files +syn match NERDTreeRO #.*\[RO\]#hs=s+2 contains=NERDTreeFlag,NERDTreeBookmark,NERDTreePart,NERDTreePartFile + +"highlighting for sym links +syn match NERDTreeLink #[^-| `].* -> # contains=NERDTreeBookmark,NERDTreeOpenable,NERDTreeClosable,NERDTreeDirSlash + +"highlighing for directory nodes and file nodes +syn match NERDTreeDirSlash #/# +syn match NERDTreeDir #[^-| `].*/# contains=NERDTreeLink,NERDTreeDirSlash,NERDTreeOpenable,NERDTreeClosable +syn match NERDTreeExecFile #[|` ].*\*\($\| \)# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark +syn match NERDTreeFile #|-.*# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile +syn match NERDTreeFile #`-.*# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile +syn match NERDTreeCWD #^[# +syn match NERDTreeBookmarksHeader #^>-\+Bookmarks-\+$# contains=NERDTreeBookmarksLeader +syn match NERDTreeBookmarkName #^>.\{-} #he=e-1 contains=NERDTreeBookmarksLeader +syn match NERDTreeBookmark #^>.*$# contains=NERDTreeBookmarksLeader,NERDTreeBookmarkName,NERDTreeBookmarksHeader + +if exists("g:NERDChristmasTree") && g:NERDChristmasTree + hi def link NERDTreePart Special + hi def link NERDTreePartFile Type + hi def link NERDTreeFile Normal + hi def link NERDTreeExecFile Title + hi def link NERDTreeDirSlash Identifier + hi def link NERDTreeClosable Type +else + hi def link NERDTreePart Normal + hi def link NERDTreePartFile Normal + hi def link NERDTreeFile Normal + hi def link NERDTreeClosable Title +endif + +hi def link NERDTreeBookmarksHeader statement +hi def link NERDTreeBookmarksLeader ignore +hi def link NERDTreeBookmarkName Identifier +hi def link NERDTreeBookmark normal + +hi def link NERDTreeHelp String +hi def link NERDTreeHelpKey Identifier +hi def link NERDTreeHelpCommand Identifier +hi def link NERDTreeHelpTitle Macro +hi def link NERDTreeToggleOn Question +hi def link NERDTreeToggleOff WarningMsg + +hi def link NERDTreeDir Directory +hi def link NERDTreeUp Directory +hi def link NERDTreeCWD Statement +hi def link NERDTreeLink Macro +hi def link NERDTreeOpenable Title +hi def link NERDTreeFlag ignore +hi def link NERDTreeRO WarningMsg +hi def link NERDTreeBookmark Statement + +hi def link NERDTreeCurrentNode Search