summaryrefslogtreecommitdiff
path: root/.vim/plugin
diff options
context:
space:
mode:
authorRené 'Necoro' Neumann <necoro@necoro.net>2009-10-07 17:05:19 +0200
committerRené 'Necoro' Neumann <necoro@necoro.net>2009-10-07 17:05:19 +0200
commitdd5427baaf49f8de4355abeb6bc8c6dd14f74e25 (patch)
tree46fcfc70bd792e80ceebaab89a7f8fc06bc29101 /.vim/plugin
downloaddotfiles-dd5427baaf49f8de4355abeb6bc8c6dd14f74e25.tar.gz
dotfiles-dd5427baaf49f8de4355abeb6bc8c6dd14f74e25.tar.bz2
dotfiles-dd5427baaf49f8de4355abeb6bc8c6dd14f74e25.zip
Initial check-in of files
Diffstat (limited to '')
-rw-r--r--.vim/plugin/NERD_tree.vim3917
-rw-r--r--.vim/plugin/a.vim840
-rw-r--r--.vim/plugin/autotag.vim150
-rw-r--r--.vim/plugin/scmCloseParens.vim58
-rw-r--r--.vim/plugin/surround.vim727
-rw-r--r--.vim/plugin/tEchoPair.vim369
-rw-r--r--.vim/plugin/taglist.vim4546
-rw-r--r--.vim/plugin/toggle_words.vim67
8 files changed, 10674 insertions, 0 deletions
diff --git a/.vim/plugin/NERD_tree.vim b/.vim/plugin/NERD_tree.vim
new file mode 100644
index 0000000..cb2d422
--- /dev/null
+++ b/.vim/plugin/NERD_tree.vim
@@ -0,0 +1,3917 @@
+" vim global plugin that provides a nice tree explorer
+" Last Change: 26 august 2007
+" Maintainer: Martin Grenfell <martin_grenfell at msn dot com>
+let s:NERD_tree_version = '2.6.2'
+
+"A help file is installed when the script is run for the first time.
+"Go :help NERD_tree.txt to see it.
+
+" 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
+"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 . ' = ' . "'" . a:value . "'"
+ 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", 1)
+if !exists("g:NERDTreeIgnore")
+ let g:NERDTreeIgnore = ['\~$']
+endif
+call s:InitVariable("g:NERDTreeHighlightCursorline", 1)
+call s:InitVariable("g:NERDTreeMouseMode", 1)
+call s:InitVariable("g:NERDTreeNotificationThreshold", 100)
+call s:InitVariable("g:NERDTreeShowHidden", 0)
+call s:InitVariable("g:NERDTreeShowFiles", 1)
+call s:InitVariable("g:NERDTreeSortDirs", 1)
+
+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 g:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*')
+
+call s:InitVariable("g:NERDTreeSplitVertical", 1)
+call s:InitVariable("g:NERDTreeWinPos", 1)
+call s:InitVariable("g:NERDTreeWinSize", 31)
+
+let s:running_windows = has("win16") || has("win32") || has("win64")
+
+"init the shell command that will be used to 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 ')
+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:NERDTreeMapExecute", "!")
+call s:InitVariable("g:NERDTreeMapFilesystemMenu", "m")
+call s:InitVariable("g:NERDTreeMapHelp", "?")
+call s:InitVariable("g:NERDTreeMapJumpFirstChild", "K")
+call s:InitVariable("g:NERDTreeMapJumpLastChild", "J")
+call s:InitVariable("g:NERDTreeMapJumpNextSibling", "<C-j>")
+call s:InitVariable("g:NERDTreeMapJumpParent", "p")
+call s:InitVariable("g:NERDTreeMapJumpPrevSibling", "<C-k>")
+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", "<tab>")
+call s:InitVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode)
+call s:InitVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit)
+call s:InitVariable("g:NERDTreeMapQuit", "q")
+call s:InitVariable("g:NERDTreeMapRefresh", "r")
+call s:InitVariable("g:NERDTreeMapRefreshRoot", "R")
+call s:InitVariable("g:NERDTreeMapToggleFiles", "F")
+call s:InitVariable("g:NERDTreeMapToggleFilters", "f")
+call s:InitVariable("g:NERDTreeMapToggleHidden", "H")
+call s:InitVariable("g:NERDTreeMapUpdir", "u")
+call s:InitVariable("g:NERDTreeMapUpdirKeepOpen", "U")
+
+"SECTION: Script level variable declaration{{{2
+let s:escape_chars = " `|\"~'#"
+let s:NERDTreeWinName = '_NERD_tree_'
+
+"init all the nerd tree markup
+let s:tree_vert = '|'
+let s:tree_vert_last = '`'
+let s:tree_wid = 2
+let s:tree_wid_str = ' '
+let s:tree_wid_strM1 = ' '
+let s:tree_dir_open = '~'
+let s:tree_dir_closed = '+'
+let s:tree_file = '-'
+let s:tree_markup_reg = '[ \-+~`|]'
+let s:tree_markup_reg_neg = '[^ \-+~`|]'
+let s:tree_up_dir_line = '.. (up a dir)'
+let s:tree_RO_str = ' [RO]'
+let s:tree_RO_str_reg = ' \[RO\]'
+
+let s:os_slash = '/'
+if s:running_windows
+ let s:os_slash = '\'
+endif
+
+
+" SECTION: Commands {{{1
+"============================================================
+"init the command that users start the nerd tree with
+command! -n=? -complete=dir NERDTree :call s:InitNerdTree('<args>')
+command! -n=? -complete=dir NERDTreeToggle :call s:Toggle('<args>')
+" SECTION: Auto commands {{{1
+"============================================================
+"Save the cursor position whenever we close the nerd tree
+exec "autocmd BufWinLeave *". s:NERDTreeWinName ."* :call <SID>SaveScreenState()"
+
+"SECTION: Classes {{{1
+"============================================================
+"CLASS: oTreeFileNode {{{2
+"This class is the parent of the oTreeDirNode class and constitures the
+"'Component' part of the composite design pattern between the treenode
+"classes.
+"============================================================
+let s:oTreeFileNode = {}
+"FUNCTION: oTreeFileNode.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: oTreeFileNode.Delete {{{3
+"Removes this node from the tree and calls the Delete method for its path obj
+function! s:oTreeFileNode.Delete() dict
+ call self.path.Delete()
+ call self.parent.RemoveChild(self)
+endfunction
+
+"FUNCTION: oTreeFileNode.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:oTreeFileNode.Equals(treenode) dict
+ return self.path.Str(1) == a:treenode.path.Str(1)
+endfunction
+
+"FUNCTION: oTreeFileNode.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:oTreeFileNode.FindNode(path) dict
+ if a:path.Equals(self.path)
+ return self
+ endif
+ return {}
+endfunction
+"FUNCTION: oTreeFileNode.FindOpenDirSiblingWithChildren(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:oTreeFileNode.FindOpenDirSiblingWithChildren(direction) dict
+ "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: oTreeFileNode.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:oTreeFileNode.FindSibling(direction) dict
+ "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: oTreeFileNode.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:oTreeFileNode.IsVisible() dict
+ return !self.path.Ignore()
+endfunction
+
+
+"FUNCTION: oTreeFileNode.IsRoot() {{{3
+"returns 1 if this node is t:NERDTreeRoot
+function! s:oTreeFileNode.IsRoot() dict
+ if !s:TreeExistsForTab()
+ throw "NERDTree.TreeFileNode.IsRoot exception: No tree exists for the current tab"
+ endif
+ return self.Equals(t:NERDTreeRoot)
+endfunction
+
+"FUNCTION: oTreeFileNode.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:oTreeFileNode.New(path) dict
+ if a:path.isDirectory
+ return s:oTreeDirNode.New(a:path)
+ else
+ let newTreeNode = {}
+ let newTreeNode = copy(self)
+ let newTreeNode.path = a:path
+ let newTreeNode.parent = {}
+ return newTreeNode
+ endif
+endfunction
+
+"FUNCTION: oTreeFileNode.Rename {{{3
+"Calls the rename method for this nodes path obj
+function! s:oTreeFileNode.Rename(newName) dict
+ call self.path.Rename(a:newName)
+ call self.parent.RemoveChild(self)
+
+ let parentPath = self.path.GetPathTrunk()
+ let newParent = t:NERDTreeRoot.FindNode(parentPath)
+
+ if newParent != {}
+ call newParent.CreateChild(self.path, 1)
+ endif
+endfunction
+
+"FUNCTION: oTreeFileNode.StrDisplay() {{{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:oTreeFileNode.StrDisplay() dict
+ return self.path.StrDisplay()
+endfunction
+
+"CLASS: oTreeDirNode {{{2
+"This class is a child of the oTreeFileNode class and constitutes the
+"'Composite' part of the composite design pattern between the treenode
+"classes.
+"============================================================
+let s:oTreeDirNode = copy(s:oTreeFileNode)
+"FUNCTION: oTreeDirNode.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:oTreeDirNode.AddChild(treenode, inOrder) dict
+ call add(self.children, a:treenode)
+ let a:treenode.parent = self
+
+ if a:inOrder
+ call self.SortChildren()
+ endif
+endfunction
+
+"FUNCTION: oTreeDirNode.Close {{{3
+"Closes this directory
+function! s:oTreeDirNode.Close() dict
+ let self.isOpen = 0
+endfunction
+
+"FUNCTION: oTreeDirNode.CloseChildren {{{3
+"Closes all the child dir nodes of this node
+function! s:oTreeDirNode.CloseChildren() dict
+ for i in self.children
+ if i.path.isDirectory
+ call i.Close()
+ call i.CloseChildren()
+ endif
+ endfor
+endfunction
+
+"FUNCTION: oTreeDirNode.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:oTreeDirNode.CreateChild(path, inOrder) dict
+ let newTreeNode = s:oTreeFileNode.New(a:path)
+ call self.AddChild(newTreeNode, a:inOrder)
+ return newTreeNode
+endfunction
+
+"FUNCTION: oTreeDirNode.FindNode(path) {{{3
+"Will find one of the children (recursively) that has the given path
+"
+"Args:
+"path: a path object
+unlet s:oTreeDirNode.FindNode
+function! s:oTreeDirNode.FindNode(path) dict
+ if a:path.Equals(self.path)
+ return self
+ endif
+ if stridx(a:path.Str(1), self.path.Str(1), 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: oTreeDirNode.GetChildDirs() {{{3
+"Returns the number of children this node has
+function! s:oTreeDirNode.GetChildCount() dict
+ return len(self.children)
+endfunction
+
+"FUNCTION: oTreeDirNode.GetChildDirs() {{{3
+"Returns an array of all children of this node that are directories
+"
+"Return:
+"an array of directory treenodes
+function! s:oTreeDirNode.GetChildDirs() dict
+ let toReturn = []
+ for i in self.children
+ if i.path.isDirectory
+ call add(toReturn, i)
+ endif
+ endfor
+ return toReturn
+endfunction
+
+"FUNCTION: oTreeDirNode.GetChildFiles() {{{3
+"Returns an array of all children of this node that are files
+"
+"Return:
+"an array of file treenodes
+function! s:oTreeDirNode.GetChildFiles() dict
+ let toReturn = []
+ for i in self.children
+ if i.path.isDirectory == 0
+ call add(toReturn, i)
+ endif
+ endfor
+ return toReturn
+endfunction
+
+"FUNCTION: oTreeDirNode.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:oTreeDirNode.GetChild(path) dict
+ if stridx(a:path.Str(1), self.path.Str(1), 0) == -1
+ return {}
+ endif
+
+ let index = self.GetChildIndex(a:path)
+ if index == -1
+ return {}
+ else
+ return self.children[index]
+ endif
+
+endfunction
+
+"FUNCTION: oTreeDirNode.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:oTreeDirNode.GetChildByIndex(indx, visible) dict
+ let array_to_search = a:visible? self.GetVisibleChildren() : self.children
+ if a:indx > len(array_to_search)
+ throw "NERDTree.TreeDirNode.InvalidArguments exception. Index is out of bounds."
+ endif
+ return array_to_search[a:indx]
+endfunction
+
+"FUNCTION: oTreeDirNode.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:oTreeDirNode.GetChildIndex(path) dict
+ if stridx(a:path.Str(1), self.path.Str(1), 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: oTreeDirNode.GetVisibleChildCount() {{{3
+"Returns the number of visible children this node has
+function! s:oTreeDirNode.GetVisibleChildCount() dict
+ return len(self.GetVisibleChildren())
+endfunction
+
+"FUNCTION: oTreeDirNode.GetVisibleChildren() {{{3
+"Returns a list of children to display for this node, in the correct order
+"
+"Return:
+"an array of treenodes
+function! s:oTreeDirNode.GetVisibleChildren() dict
+ let toReturn = []
+ for i in self.children
+ if i.path.Ignore() == 0
+ call add(toReturn, i)
+ endif
+ endfor
+ return toReturn
+endfunction
+
+"FUNCTION: oTreeDirNode.HasVisibleChildren {{{3
+"returns 1 if this node has any childre, 0 otherwise..
+function! s:oTreeDirNode.HasVisibleChildren()
+ return self.GetChildCount() != 0
+endfunction
+
+"FUNCTION: oTreeDirNode.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:oTreeDirNode.InitChildren(silent) dict
+ "remove all the current child nodes
+ let self.children = []
+
+ "get an array of all the files in the nodes dir
+ let filesStr = globpath(self.path.GetDir(0), '*') . "\n" . globpath(self.path.GetDir(0), '.*')
+ 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
+ if i !~ '\.\.$' && i !~ '\.$'
+
+ "put the next file in a new node and attach it
+ try
+ let path = s:oPath.New(i)
+ call self.CreateChild(path, 0)
+ catch /^NERDTree.Path.InvalidArguments/
+ 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 ...")
+ call s:Echo("Please wait, caching a large dir ... DONE (". self.GetChildCount() ." nodes cached).")
+ endif
+
+ if invalidFilesFound
+ call s:EchoWarning("some files could not be loaded into the NERD tree")
+ endif
+ return self.GetChildCount()
+endfunction
+"FUNCTION: oTreeDirNode.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:oTreeDirNode.New
+function! s:oTreeDirNode.New(path) dict
+ if a:path.isDirectory != 1
+ throw "NERDTree.TreeDirNode.InvalidArguments exception. 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: oTreeDirNode.Open {{{3
+"Reads in all this nodes children
+"
+"Return: the number of child nodes read
+function! s:oTreeDirNode.Open() dict
+ let self.isOpen = 1
+ if self.children == []
+ return self.InitChildren(0)
+ else
+ return 0
+ endif
+endfunction
+
+"FUNCTION: oTreeDirNode.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:oTreeDirNode.OpenRecursively() dict
+ call self.OpenRecursively2(1)
+endfunction
+
+"FUNCTION: oTreeDirNode.OpenRecursively2 {{{3
+"Dont call this method from outside this object.
+"
+"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:oTreeDirNode.OpenRecursively2(forceOpen) dict
+ 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: oTreeDirNode.Refresh {{{3
+function! s:oTreeDirNode.Refresh() dict
+ let newChildNodes = []
+ let invalidFilesFound = 0
+
+ "go thru all the files/dirs under this node
+ let filesStr = globpath(self.path.GetDir(0), '*') . "\n" . globpath(self.path.GetDir(0), '.*')
+ let files = split(filesStr, "\n")
+ for i in files
+ if i !~ '\.\.$' && i !~ '\.$'
+
+ try
+ "create a new path and see if it exists in this nodes children
+ let path = s:oPath.New(i)
+ let newNode = self.GetChild(path)
+ if newNode != {}
+
+ "if the existing node is a dir can be refreshed then
+ "refresh it
+ if newNode.path.isDirectory && (!empty(newNode.children) || newNode.isOpen == 1)
+ call newNode.Refresh()
+
+ "if we have a filenode then refresh the path
+ elseif newNode.path.isDirectory == 0
+ call newNode.path.Refresh()
+ endif
+
+ call add(newChildNodes, newNode)
+
+ "the node doesnt exist so create it
+ else
+ let newNode = s:oTreeFileNode.New(path)
+ let newNode.parent = self
+ call add(newChildNodes, newNode)
+ endif
+
+
+ catch /^NERDTree.InvalidArguments/
+ 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
+endfunction
+
+"FUNCTION: oTreeDirNode.RemoveChild {{{3
+"
+"Removes the given treenode from this nodes set of children
+"
+"Args:
+"treenode: the node to remove
+"
+"Throws a NERDTree.TreeDirNode exception if the given treenode is not found
+function! s:oTreeDirNode.RemoveChild(treenode) dict
+ 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.TreeDirNode exception: child node was not found"
+endfunction
+
+"FUNCTION: oTreeDirNode.SortChildren {{{3
+"
+"Sorts the children of this node according to alphabetical order and the
+"directory priority.
+"
+function! s:oTreeDirNode.SortChildren() dict
+ let CompareFunc = function("s:CompareNodes")
+ call sort(self.children, CompareFunc)
+endfunction
+
+"FUNCTION: oTreeDirNode.ToggleOpen {{{3
+"Opens this directory if it is closed and vice versa
+function! s:oTreeDirNode.ToggleOpen() dict
+ if self.isOpen == 1
+ call self.Close()
+ else
+ call self.Open()
+ endif
+endfunction
+
+"FUNCTION: oTreeDirNode.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:oTreeDirNode.TransplantChild(newNode) dict
+ 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: oPath {{{2
+"============================================================
+let s:oPath = {}
+"FUNCTION: oPath.ChangeToDir() {{{3
+function! s:oPath.ChangeToDir() dict
+ let dir = self.Str(1)
+ if self.isDirectory == 0
+ let dir = self.GetPathTrunk().Str(1)
+ endif
+
+ try
+ execute "cd " . dir
+ call s:Echo("CWD is now: " . getcwd())
+ catch
+ throw "NERDTree.Path.Change exception: cannot change to " . dir
+ endtry
+endfunction
+
+"FUNCTION: oPath.ChopTrailingSlash(str) {{{3
+function! s:oPath.ChopTrailingSlash(str) dict
+ if a:str =~ '\/$'
+ return substitute(a:str, "\/$", "", "")
+ else
+ return substitute(a:str, "\\$", "", "")
+ endif
+endfunction
+
+"FUNCTION: oPath.CompareTo() {{{3
+"
+"Compares this oPath to the given path and returns 0 if they are equal, -1 if
+"this oPath 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:oPath.CompareTo(path) dict
+ 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 <? thatPath
+ if pathCompare
+ return -1
+ else
+ return 1
+ endif
+ endif
+endfunction
+
+"FUNCTION: oPath.Create() {{{3
+"
+"Factory method.
+"
+"Creates a path object with the given path. The path is also created on the
+"filesystem. If the path already exists, a NERDTree.Path.Exists exception is
+"thrown. If any other errors occur, a NERDTree.Path exception is thrown.
+"
+"Args:
+"fullpath: the full filesystem path to the file/dir to create
+function! s:oPath.Create(fullpath) dict
+ "bail if the a:fullpath already exists
+ if isdirectory(a:fullpath) || filereadable(a:fullpath)
+ throw "NERDTree.Path.Exists Exception: Directory Exists: '" . a:fullpath . "'"
+ endif
+
+ "get the unix version of the input path
+ let fullpath = a:fullpath
+ if s:running_windows
+ let fullpath = s:oPath.WinToUnixPath(fullpath)
+ endif
+
+ try
+
+ "if it ends with a slash, assume its a dir create it
+ if fullpath =~ '\/$'
+ "whack the trailing slash off the end if it exists
+ let fullpath = substitute(fullpath, '\/$', '', '')
+
+ call mkdir(fullpath, 'p')
+
+ "assume its a file and create
+ else
+ call writefile([], fullpath)
+ endif
+ catch /.*/
+ throw "NERDTree.Path Exception: Could not create path: '" . a:fullpath . "'"
+ endtry
+
+ return s:oPath.New(fullpath)
+endfunction
+
+"FUNCTION: oPath.Delete() {{{3
+"
+"Deletes the file represented by this path.
+"Deletion of directories is not supported
+"
+"Throws NERDTree.Path.Deletion exceptions
+function! s:oPath.Delete() dict
+ if self.isDirectory
+
+ let cmd = ""
+ if s:running_windows
+ "if we are runnnig windows then put quotes around the pathstring
+ let cmd = g:NERDTreeRemoveDirCmd . self.StrForOS(1)
+ else
+ let cmd = g:NERDTreeRemoveDirCmd . self.StrForOS(0)
+ endif
+ let success = system(cmd)
+
+ if v:shell_error != 0
+ throw "NERDTree.Path.Deletion Exception: Could not delete directory: '" . self.StrForOS(0) . "'"
+ endif
+ else
+ let success = delete(self.Str(0))
+ if success != 0
+ throw "NERDTree.Path.Deletion Exception: Could not delete file: '" . self.Str(0) . "'"
+ endif
+ endif
+endfunction
+
+"FUNCTION: oPath.GetDir() {{{3
+"
+"Gets the directory part of this path. If this path IS a directory then the
+"whole thing is returned
+"
+"Args:
+"trailingSlash: 1 if a trailing slash is to be stuck on the end of the
+"returned dir
+"
+"Return:
+"string
+function! s:oPath.GetDir(trailingSlash) dict
+ let toReturn = ''
+ if self.isDirectory
+ let toReturn = '/'. join(self.pathSegments, '/')
+ else
+ let toReturn = '/'. join(self.pathSegments[0:-2], '/')
+ endif
+
+ if a:trailingSlash && toReturn !~ '\/$'
+ let toReturn = toReturn . '/'
+ endif
+
+ return toReturn
+endfunction
+
+"FUNCTION: oPath.GetFile() {{{3
+"
+"Returns the file component of this path.
+"
+"Throws NERDTree.IllegalOperation exception if the node is a directory node
+function! s:oPath.GetFile() dict
+ if self.isDirectory == 0
+ return self.GetLastPathComponent(0)
+ else
+ throw "NERDTree.Path.IllegalOperation Exception: cannot get file component of a directory path"
+ endif
+endfunction
+
+"FUNCTION: oPath.GetLastPathComponent(dirSlash) {{{3
+"
+"Gets the last part of this path.
+"
+"Args:
+"dirSlash: if 1 then a trailing slash will be added to the returned value for
+"directory nodes.
+function! s:oPath.GetLastPathComponent(dirSlash) dict
+ if empty(self.pathSegments)
+ return ''
+ endif
+ let toReturn = self.pathSegments[-1]
+ if a:dirSlash && self.isDirectory
+ let toReturn = toReturn . '/'
+ endif
+ return toReturn
+endfunction
+
+"FUNCTION: oPath.GetPathTrunk() {{{3
+"Gets the path without the last segment on the end.
+function! s:oPath.GetPathTrunk() dict
+ return s:oPath.New('/' . join(self.pathSegments[0:-2], '/'))
+endfunction
+
+"FUNCTION: oPath.GetSortOrderIndex() {{{3
+"returns the index of the pattern in g:NERDTreeSortOrder that this path matches
+function! s:oPath.GetSortOrderIndex() dict
+ let i = 0
+ while i < len(g:NERDTreeSortOrder)
+ if self.GetLastPathComponent(1) =~ g:NERDTreeSortOrder[i]
+ return i
+ endif
+ let i = i + 1
+ endwhile
+ return g:NERDTreeSortStarIndex
+endfunction
+
+"FUNCTION: oPath.Ignore() {{{3
+"returns true if this path should be ignored
+function! s:oPath.Ignore() dict
+ let lastPathComponent = self.GetLastPathComponent(0)
+
+ "filter out the user specified paths to ignore
+ if t:NERDTreeIgnoreEnabled
+ for i in g:NERDTreeIgnore
+ if lastPathComponent =~ i
+ return 1
+ endif
+ endfor
+ endif
+
+ "dont show hidden files unless instructed to
+ if g:NERDTreeShowHidden == 0 && lastPathComponent =~ '^\.'
+ return 1
+ endif
+
+ if g:NERDTreeShowFiles == 0 && self.isDirectory == 0
+ return 1
+ endif
+
+ return 0
+endfunction
+
+"FUNCTION: oPath.Equals() {{{3
+"
+"Determines whether 2 path objecs are "equal".
+"They are equal if the paths they represent are the same
+"
+"Args:
+"path: the other path obj to compare this with
+function! s:oPath.Equals(path) dict
+ let this = self.ChopTrailingSlash(self.Str(1))
+ let that = self.ChopTrailingSlash(a:path.Str(1))
+ return this == that
+endfunction
+
+"FUNCTION: oPath.New() {{{3
+"
+"The Constructor for the Path object
+"Throws NERDTree.Path.InvalidArguments exception.
+function! s:oPath.New(fullpath) dict
+ let newPath = copy(self)
+
+ call newPath.ReadInfoFromDisk(a:fullpath)
+
+ return newPath
+endfunction
+
+"FUNCTION: oPath.NewMinimal() {{{3
+function! s:oPath.NewMinimal(fullpath) dict
+ let newPath = copy(self)
+
+ let fullpath = a:fullpath
+
+ if s:running_windows
+ let fullpath = s:oPath.WinToUnixPath(fullpath)
+ endif
+
+ let newPath.pathSegments = split(fullpath, '/')
+
+ let newPath.isDirectory = isdirectory(fullpath)
+
+ return newPath
+endfunction
+
+"FUNCTION: oPath.ReadInfoFromDisk(fullpath) {{{3
+"
+"
+"Throws NERDTree.Path.InvalidArguments exception.
+function! s:oPath.ReadInfoFromDisk(fullpath) dict
+ let fullpath = a:fullpath
+
+ if s:running_windows
+ let fullpath = s:oPath.WinToUnixPath(fullpath)
+ endif
+
+ let self.pathSegments = split(fullpath, '/')
+
+ let self.isReadOnly = 0
+ if isdirectory(fullpath)
+ let self.isDirectory = 1
+ elseif filereadable(fullpath)
+ let self.isDirectory = 0
+ let self.isReadOnly = filewritable(fullpath) == 0
+ else
+ throw "NERDTree.Path.InvalidArguments Exception: Invalid path = " . fullpath
+ endif
+
+ "grab the last part of the path (minus the trailing slash)
+ let lastPathComponent = self.GetLastPathComponent(0)
+
+ "get the path to the new node with the parent dir fully resolved
+ let hardPath = resolve(self.StrTrunk()) . '/' . lastPathComponent
+
+ "if the last part of the path is a symlink then flag it as such
+ let self.isSymLink = (resolve(hardPath) != hardPath)
+ if self.isSymLink
+ let self.symLinkDest = resolve(fullpath)
+
+ "if the link is a dir then slap a / on the end of its dest
+ if isdirectory(self.symLinkDest)
+
+ "we always wanna treat MS windows shortcuts as files for
+ "simplicity
+ if hardPath !~ '\.lnk$'
+
+ let self.symLinkDest = self.symLinkDest . '/'
+ endif
+ endif
+ endif
+endfunction
+
+"FUNCTION: oPath.Refresh() {{{3
+function! s:oPath.Refresh() dict
+ call self.ReadInfoFromDisk(self.Str(0))
+endfunction
+
+"FUNCTION: oPath.Rename() {{{3
+"
+"Renames this node on the filesystem
+function! s:oPath.Rename(newPath) dict
+ if a:newPath == ''
+ throw "NERDTree.Path.InvalidArguments exception. Invalid newPath for renaming = ". a:newPath
+ endif
+
+ let success = rename(self.Str(0), a:newPath)
+ if success != 0
+ throw "NERDTree.Path.Rename Exception: Could not rename: '" . self.Str(0) . "'" . 'to:' . a:newPath
+ endif
+ let self.pathSegments = split(a:newPath, '/')
+endfunction
+
+"FUNCTION: oPath.Str(esc) {{{3
+"
+"Gets the actual string path that this obj represents.
+"
+"Args:
+"esc: if 1 then all the tricky chars in the returned string will be escaped
+function! s:oPath.Str(esc) dict
+ let toReturn = '/' . join(self.pathSegments, '/')
+ if self.isDirectory && toReturn != '/'
+ let toReturn = toReturn . '/'
+ endif
+
+ if a:esc
+ let toReturn = escape(toReturn, s:escape_chars)
+ endif
+ return toReturn
+endfunction
+
+"FUNCTION: oPath.StrAbs() {{{3
+"
+"Returns a string representing this path with all the symlinks resolved
+"
+"Return:
+"string
+function! s:oPath.StrAbs() dict
+ return resolve(self.Str(1))
+endfunction
+
+"FUNCTION: oPath.StrDisplay() {{{3
+"
+"Returns a string that specifies how the path should be represented as a
+"string
+"
+"Return:
+"a string that can be used in the view to represent this path
+function! s:oPath.StrDisplay() dict
+ let toReturn = self.GetLastPathComponent(1)
+
+ if self.isSymLink
+ let toReturn .= ' -> ' . self.symLinkDest
+ endif
+
+ if self.isReadOnly
+ let toReturn .= s:tree_RO_str
+ endif
+
+ return toReturn
+endfunction
+
+"FUNCTION: oPath.StrForEditCmd() {{{3
+"
+"Return: the string for this path that is suitable to be used with the :edit
+"command
+function! s:oPath.StrForEditCmd() dict
+ if s:running_windows
+ return self.StrForOS(0)
+ else
+ return self.Str(1)
+ endif
+
+endfunction
+"FUNCTION: oPath.StrForOS(esc) {{{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
+"
+"Args:
+"esc: if 1 then all the tricky chars in the returned string will be
+" escaped. If we are running windows then the str is double quoted instead.
+function! s:oPath.StrForOS(esc) dict
+ let lead = s:os_slash
+
+ "if we are running windows then slap a drive letter on the front
+ if s:running_windows
+ let lead = strpart(getcwd(), 0, 2) . s:os_slash
+ endif
+
+ let toReturn = lead . join(self.pathSegments, s:os_slash)
+
+ if a:esc
+ if s:running_windows
+ let toReturn = '"' . toReturn . '"'
+ else
+ let toReturn = escape(toReturn, s:escape_chars)
+ endif
+ endif
+ return toReturn
+endfunction
+
+"FUNCTION: oPath.StrTrunk() {{{3
+"Gets the path without the last segment on the end.
+function! s:oPath.StrTrunk() dict
+ return '/' . join(self.pathSegments[0:-2], '/')
+endfunction
+
+"FUNCTION: oPath.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:oPath.WinToUnixPath(pathstr) dict
+ 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:Abs(num){{{2
+"returns the absolute value of the input
+function! s:Abs(num)
+ if a:num > 0
+ return a:num
+ else
+ return 0 - a:num
+ end
+endfunction
+
+"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:InitNerdTree(dir) {{{2
+"Initialized the NERD tree, where the root will be initialized with the given
+"directory
+"
+"Arg:
+"dir: the dir to init the root with
+function! s:InitNerdTree(dir)
+ let dir = a:dir == '' ? expand('%:p:h') : a:dir
+ let dir = resolve(dir)
+
+ if !isdirectory(dir)
+ call s:EchoWarning("Error reading: " . dir)
+ return
+ endif
+
+ "if instructed to, then change the vim CWD to the dir the NERDTree is
+ "inited in
+ if g:NERDTreeChDirMode != 0
+ exec "cd " . dir
+ endif
+
+ let t:treeShowHelp = 0
+ let t:NERDTreeIgnoreEnabled = 1
+
+ if s:TreeExistsForTab()
+ if s:IsTreeOpen()
+ call s:CloseTree()
+ endif
+ unlet t:NERDTreeRoot
+ endif
+
+ let path = s:oPath.New(dir)
+ let t:NERDTreeRoot = s:oTreeDirNode.New(path)
+ call t:NERDTreeRoot.Open()
+
+ call s:CreateTreeWin()
+
+ call s:RenderView()
+endfunction
+
+" Function: s:InstallDocumentation(full_name, revision) {{{2
+" 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
+ call s: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:
+ call s:Echo("Unable to open documentation directory")
+ call s:Echo("type :help add-local-help for more information.")
+ call s: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
+
+ " Remove fold marks:
+ :%s/{{{[1-9]/ /
+
+ " 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 . "/\<CR>"
+ exe "normal! :%s/#version#/ v" . a:revision . "/\<CR>"
+
+ " 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
+
+" Function: s:TreeExistsForTab() {{{2
+" Returns 1 if a nerd tree root exists in the current tab
+function! s:TreeExistsForTab()
+ return exists("t:NERDTreeRoot")
+endfunction
+
+" SECTION: Public Functions {{{1
+"============================================================
+"Returns the node that the cursor is currently on.
+"
+"If the cursor is not in the NERDTree window, it is temporarily put there.
+"
+"If no NERD tree window exists for the current tab, a NERDTree.NoTreeForTab
+"exception is thrown.
+"
+"If the cursor is not on a node then an empty dictionary {} is returned.
+function! NERDTreeGetCurrentNode()
+ if !s:TreeExistsForTab() || !s:IsTreeOpen()
+ throw "NERDTree.NoTreeForTab exception: there is no NERD tree open for the current tab"
+ endif
+
+ let winnr = winnr()
+ if winnr != s:GetTreeWinNum()
+ call s:PutCursorInTreeWin()
+ endif
+
+ let treenode = s:GetSelectedNode()
+
+ if winnr != winnr()
+ wincmd w
+ endif
+
+ return treenode
+endfunction
+
+"Returns the path object for the current node.
+"
+"Subject to the same conditions as NERDTreeGetCurrentNode
+function! NERDTreeGetCurrentPath()
+ let node = NERDTreeGetCurrentNode()
+ if node != {}
+ return node.path
+ else
+ return {}
+ endif
+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 NERD tree window
+function! s:CloseTree()
+ if !s:IsTreeOpen()
+ throw "NERDTree.view.CloseTree exception: no NERDTree is open"
+ endif
+
+ if winnr("$") != 1
+ execute s:GetTreeWinNum() . " wincmd w"
+ close
+ execute "wincmd p"
+ else
+ :q
+ 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 ? "topleft " : "belowright "
+ let splitMode = g:NERDTreeSplitVertical ? "vertical " : ""
+ let splitSize = g:NERDTreeWinSize
+ let t:NERDTreeWinName = localtime() . s:NERDTreeWinName
+ let cmd = splitLocation . splitMode . splitSize . ' new ' . t:NERDTreeWinName
+ silent! execute cmd
+
+ setl winfixwidth
+
+ "throwaway buffer options
+ setlocal noswapfile
+ setlocal buftype=nofile
+ setlocal bufhidden=delete
+ setlocal nowrap
+ setlocal foldcolumn=0
+ setlocal nobuflisted
+ setlocal nospell
+ iabc <buffer>
+
+ if g:NERDTreeHighlightCursorline
+ setlocal cursorline
+ endif
+
+ " syntax highlighting
+ if has("syntax") && exists("g:syntax_on") && !has("syntax_items")
+ call s:SetupSyntaxHighlighting()
+ endif
+
+ " for line continuation
+ let cpo_save1 = &cpo
+ set cpo&vim
+
+ call s:BindMappings()
+endfunction
+
+"FUNCTION: s:DrawTree {{{2
+"Draws the given node recursively
+"
+"Args:
+"curNode: the node that is being rendered with this call
+"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:DrawTree(curNode, depth, drawText, vertMap, isLastChild)
+ 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 j == 1
+ let treeParts = treeParts . s:tree_vert . s:tree_wid_strM1
+ else
+ let treeParts = treeParts . s:tree_wid_str
+ 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 a:isLastChild
+ let treeParts = treeParts . s:tree_vert_last
+ else
+ let treeParts = treeParts . s:tree_vert
+ endif
+
+
+ "smack the appropriate dir/file symbol on the line before the file/dir
+ "name itself
+ if a:curNode.path.isDirectory
+ if a:curNode.isOpen
+ let treeParts = treeParts . s:tree_dir_open
+ else
+ let treeParts = treeParts . s:tree_dir_closed
+ endif
+ else
+ let treeParts = treeParts . s:tree_file
+ endif
+ let line = treeParts . a:curNode.StrDisplay()
+
+ call setline(line(".")+1, line)
+ call cursor(line(".")+1, col("."))
+ endif
+
+ "if the node is an open dir, draw its children
+ if a:curNode.path.isDirectory == 1 && a:curNode.isOpen == 1
+
+ let childNodesToDraw = a:curNode.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]
+ call s:DrawTree(i, a:depth + 1, 1, add(copy(a:vertMap), 1), 0)
+ endfor
+ endif
+
+ "draw the last child, indicating that it IS the last
+ call s:DrawTree(childNodesToDraw[lastIndx], a:depth + 1, 1, add(copy(a:vertMap), 0), 1)
+ endif
+ endif
+endfunction
+
+
+"FUNCTION: s:DumpHelp {{{2
+"prints out the quick help
+function! s:DumpHelp()
+ let old_h = @h
+ if t: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."\" ". g:NERDTreeMapActivateNode .": open in prev window\n"
+ let @h=@h."\" ". g:NERDTreeMapPreview .": preview \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."\" middle-click,\n"
+ let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n"
+ let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n"
+ let @h=@h."\" ". g:NERDTreeMapExecute.": Execute file\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.": Open netrw for selected\n"
+ let @h=@h."\" node \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:NERDTreeMapFilesystemMenu .": Show filesystem 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 (" . (g:NERDTreeShowHidden ? "on" : "off") . ")\n"
+ let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (t:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n"
+ let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (g:NERDTreeShowFiles ? "on" : "off") . ")\n"
+
+ 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:NERDTreeMapHelp .": toggle help\n"
+ else
+ let @h="\" Press ". g:NERDTreeMapHelp ." for help\n"
+ endif
+
+ silent! put h
+
+ 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
+ echo "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:FindNodeLineNumber(treenode){{{2
+"Finds the line number for the given tree node
+"
+"Args:
+"treenode: the node to find the line no. for
+function! s:FindNodeLineNumber(treenode)
+ "if the node is the root then return the root line no.
+ if a:treenode.IsRoot()
+ return s:FindRootNodeLineNumber()
+ endif
+
+ let totalLines = line("$")
+
+ "the path components we have matched so far
+ let pathcomponents = [substitute(t:NERDTreeRoot.path.Str(0), '/ *$', '', '')]
+ "the index of the component we are searching for
+ let curPathComponent = 1
+
+ let fullpath = a:treenode.path.Str(0)
+
+
+ let lnum = s:FindRootNodeLineNumber()
+ 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 = match(curLine,s:tree_markup_reg_neg) / s:tree_wid
+ 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: s:FindRootNodeLineNumber(path){{{2
+"Finds the line number of the root node
+function! s:FindRootNodeLineNumber()
+ let rootLine = 1
+ while getline(rootLine) !~ '^/'
+ let rootLine = rootLine + 1
+ endwhile
+ return rootLine
+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)
+
+ "check to see if we have the root node
+ if line =~ '^\/'
+ return t:NERDTreeRoot.path
+ endif
+
+ " in case called from outside the tree
+ if line !~ '^ *[|`]' || line =~ '^$'
+ return {}
+ endif
+
+ if line == s:tree_up_dir_line
+ return s:oPath.New( t:NERDTreeRoot.path.GetDir(0) )
+ endif
+
+ "get the indent level for the file (i.e. how deep in the tree it is)
+ "let indent = match(line,'[^-| `]') / s:tree_wid
+ let indent = match(line, s:tree_markup_reg_neg) / s:tree_wid
+
+
+ "remove the tree parts and the leading space
+ let curFile = s:StripMarkupFromLine(line, 0)
+
+ let wasdir = 0
+ if curFile =~ '/$'
+ let wasdir = 1
+ endif
+ let curFile = substitute (curFile,' -> .*',"","") " remove link to
+ if wasdir == 1
+ let curFile = substitute (curFile, '/\?$', '/', "")
+ endif
+
+
+ let dir = ""
+ let lnum = a:ln
+ while lnum > 0
+ let lnum = lnum - 1
+ let curLine = getline(lnum)
+
+ "have we reached the top of the tree?
+ if curLine =~ '^/'
+ let sd = substitute (curLine, '[ ]*$', "", "")
+ let dir = sd . dir
+ break
+ endif
+ if curLine =~ '/$'
+ let lpindent = match(curLine,s:tree_markup_reg_neg) / s:tree_wid
+ if lpindent < indent
+ let indent = indent - 1
+ let sd = substitute (curLine, '^' . s:tree_markup_reg . '*',"","")
+ let sd = substitute (sd, ' -> .*', '',"")
+
+ " remove leading escape
+ let sd = substitute (sd,'^\\', "", "")
+
+ let dir = sd . dir
+ continue
+ endif
+ endif
+ endwhile
+ let curFile = dir . curFile
+ return s:oPath.NewMinimal(curFile)
+endfunction
+
+"FUNCTION: s:GetSelectedDir() {{{2
+"Returns the current node if it is a dir node, or else returns the current
+"nodes parent
+function! s:GetSelectedDir()
+ let currentDir = s:GetSelectedNode()
+ if currentDir != {} && !currentDir.IsRoot()
+ if currentDir.path.isDirectory == 0
+ let currentDir = currentDir.parent
+ endif
+ endif
+ return currentDir
+endfunction
+"FUNCTION: s:GetSelectedNode() {{{2
+"gets the treenode that the cursor is currently over
+function! s:GetSelectedNode()
+ try
+ let path = s:GetPath(line("."))
+ if path == {}
+ return {}
+ endif
+ return t:NERDTreeRoot.FindNode(path)
+ catch /^NERDTree/
+ return {}
+ endtry
+endfunction
+
+"FUNCTION: s:GetTreeBufNum() {{{2
+"gets the nerd tree buffer number for this tab
+function! s:GetTreeBufNum()
+ if exists("t:NERDTreeWinName")
+ return bufnr(t:NERDTreeWinName)
+ else
+ return -1
+ endif
+endfunction
+"FUNCTION: s:GetTreeWinNum() {{{2
+"gets the nerd tree window number for this tab
+function! s:GetTreeWinNum()
+ if exists("t:NERDTreeWinName")
+ return bufwinnr(t:NERDTreeWinName)
+ else
+ return -1
+ endif
+endfunction
+
+"FUNCTION: s:IsTreeOpen() {{{2
+function! s:IsTreeOpen()
+ return s:GetTreeWinNum() != -1
+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:GetSelectedNode()
+ 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.FindOpenDirSiblingWithChildren(a:direction)
+ if siblingDir != {}
+ let indx = a:direction ? siblingDir.GetVisibleChildCount()-1 : 0
+ let targetNode = siblingDir.GetChildByIndex(indx, 1)
+ endif
+ endif
+
+ call s:PutCursorOnNode(targetNode, 1)
+
+ call s:CenterView()
+endfunction
+
+
+"FUNCTION: s:OpenDirNodeSplit(treenode) {{{2
+"Open the file represented by the given node in a new window.
+"No action is taken for file nodes
+"
+"ARGS:
+"treenode: file node to open
+function! s:OpenDirNodeSplit(treenode)
+ if a:treenode.path.isDirectory == 1
+ call s:OpenNodeSplit(a:treenode)
+ endif
+endfunction
+
+"FUNCTION: s:OpenFileNode(treenode) {{{2
+"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:OpenFileNode(treenode)
+ call s:PutCursorInTreeWin()
+
+ if s:ShouldSplitToOpen(winnr("#"))
+ call s:OpenFileNodeSplit(a:treenode)
+ else
+ try
+ wincmd p
+ exec ("edit " . a:treenode.path.StrForEditCmd())
+ catch /^Vim\%((\a\+)\)\=:E37/
+ call s:PutCursorInTreeWin()
+ call s:Echo("Cannot open file, it is already open and modified")
+ catch /^Vim\%((\a\+)\)\=:/
+ echo v:exception
+ endtry
+ endif
+endfunction
+
+"FUNCTION: s:OpenFileNodeSplit(treenode) {{{2
+"Open the file represented by the given node in a new window.
+"No action is taken for dir nodes
+"
+"ARGS:
+"treenode: file node to open
+function! s:OpenFileNodeSplit(treenode)
+ if a:treenode.path.isDirectory == 0
+ try
+ call s:OpenNodeSplit(a:treenode)
+ catch /^NERDTree.view.FileOpen/
+ call s:Echo("Cannot open file, it is already open and modified" )
+ endtry
+ endif
+endfunction
+
+"FUNCTION: s:OpenNodeSplit(treenode) {{{2
+"Open the file/dir represented by the given node in a new window
+"
+"ARGS:
+"treenode: file node to open
+function! s:OpenNodeSplit(treenode)
+ call s:PutCursorInTreeWin()
+
+ " Save the user's settings for splitbelow and splitright
+ let savesplitbelow=&splitbelow
+ let savesplitright=&splitright
+
+ " Figure out how to do the split based on the user's preferences.
+ " We want to split to the (left,right,top,bottom) of the explorer
+ " window, but we want to extract the screen real-estate from the
+ " window next to the explorer if possible.
+ "
+ " '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.
+ "
+ if g:NERDTreeSplitVertical == 1
+ let there= g:NERDTreeWinPos ? "wincmd h" : "wincmd l"
+ let back= g:NERDTreeWinPos ? "wincmd l" : "wincmd h"
+ let right=g:NERDTreeWinPos ? 1 : 0
+ let below=0
+ else
+ let there= g:NERDTreeWinPos ? "wincmd k" : "wincmd j"
+ let back= g:NERDTreeWinPos ? "wincmd j" : "wincmd k"
+ let right=0
+ let below=g:NERDTreeWinPos ? 1 : 0
+ endif
+
+ " Attempt to go to adjacent window
+ exec(back)
+
+ let onlyOneWin = (winnr() == s:GetTreeWinNum())
+
+ " 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
+
+ " Create a variable to use if splitting vertically
+ let splitMode = ""
+ if (onlyOneWin && g:NERDTreeSplitVertical) || (!onlyOneWin && !g:NERDTreeSplitVertical)
+ let splitMode = "vertical"
+ endif
+
+ " Open the new window
+ try
+ exec("silent " . splitMode." sp " . a:treenode.path.StrForEditCmd())
+ catch /^Vim\%((\a\+)\)\=:E37/
+ call s:PutCursorInTreeWin()
+ throw "NERDTree.view.FileOpen exception: ". a:treenode.path.Str(0) ." is already open and modified."
+ catch /^Vim\%((\a\+)\)\=:/
+ do nothing
+ endtry
+
+ " resize the explorer window if it is larger than the requested size
+ exec(there)
+
+ if g:NERDTreeWinSize =~ '[0-9]\+' && winheight("") > g:NERDTreeWinSize
+ exec("silent vertical resize ".g:NERDTreeWinSize)
+ endif
+
+ wincmd p
+
+ " Restore splitmode settings
+ let &splitbelow=savesplitbelow
+ let &splitright=savesplitright
+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:PutCursorOnNode(treenode, is_jump){{{2
+"Places the cursor on the line number representing the given node
+"
+"Args:
+"treenode: the node to put the cursor on
+"is_jump: 1 if this cursor movement should be counted as a jump by vim
+function! s:PutCursorOnNode(treenode, is_jump)
+ let ln = s:FindNodeLineNumber(a:treenode)
+ if ln != -1
+ if a:is_jump
+ mark '
+ endif
+ call cursor(ln, col("."))
+ endif
+endfunction
+
+"FUNCTION: s:PutCursorInTreeWin(){{{2
+"Places the cursor in the nerd tree window
+function! s:PutCursorInTreeWin()
+ if !s:IsTreeOpen()
+ throw "NERDTree.view.InvalidOperation Exception: No NERD tree window exists"
+ endif
+
+ exec s:GetTreeWinNum() . "wincmd w"
+endfunction
+
+"FUNCTION: s:RenderView {{{2
+"The entry function for rendering the tree. Renders the root then calls
+"s:DrawTree to draw the children of the root
+"
+"Args:
+function! s:RenderView()
+ execute s:GetTreeWinNum() . "wincmd w"
+
+ 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
+ call setline(line(".")+1, " ")
+ call cursor(line(".")+1, col("."))
+
+ "add the 'up a dir' line
+ call setline(line(".")+1, s:tree_up_dir_line)
+ call cursor(line(".")+1, col("."))
+
+ "draw the header line
+ call setline(line(".")+1, t:NERDTreeRoot.path.Str(0))
+ call cursor(line(".")+1, col("."))
+
+ "draw the tree
+ call s:DrawTree(t:NERDTreeRoot, 0, 0, [], t:NERDTreeRoot.GetChildCount() == 1)
+
+ "delete the blank line at the top of the buffer
+ :silent 1,1delete _
+
+ "restore the view
+ call cursor(topLine, 1)
+ normal! zt
+ call cursor(curLine, curCol)
+
+ 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:GetSelectedNode()
+
+ "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 s:PutCursorOnNode(currentNode, 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("t:NERDTreeOldTopLine") || !exists("t:NERDTreeOldPos")
+ return
+ endif
+
+ call cursor(t:NERDTreeOldTopLine, 0)
+ normal! zt
+ call setpos(".", t:NERDTreeOldPos)
+endfunction
+
+"FUNCTION: s:SaveScreenState() {{{2
+"Saves the current cursor position in the current buffer and the window
+"scroll position
+"
+"Assumes the cursor is in the NERDTree window
+function! s:SaveScreenState()
+ let t:NERDTreeOldPos = getpos(".")
+ let t:NERDTreeOldTopLine = line("w0")
+endfunction
+
+"FUNCTION: s:SetupSyntaxHighlighting() {{{2
+function! s:SetupSyntaxHighlighting()
+ "treeFlags are syntax items that should be invisible, but give clues as to
+ "how things should be highlighted
+ syn match treeFlag #\~#
+ syn match treeFlag #\[RO\]#
+
+ "highlighting for the .. (up dir) line at the top of the tree
+ execute "syn match treeUp #". s:tree_up_dir_line ."#"
+
+ "highlighting for the ~/+ symbols for the directory nodes
+ syn match treeClosable #\~\<#
+ syn match treeClosable #\~\.#
+ syn match treeOpenable #+\<#
+ syn match treeOpenable #+\.#he=e-1
+
+ "highlighting for the tree structural parts
+ syn match treePart #|#
+ syn match treePart #`#
+ syn match treePartFile #[|`]-#hs=s+1 contains=treePart
+
+ "quickhelp syntax elements
+ syn match treeHelpKey #" \{1,2\}[^ ]*:#hs=s+2,he=e-1
+ syn match treeHelpKey #" \{1,2\}[^ ]*,#hs=s+2,he=e-1
+ syn match treeHelpTitle #" .*\~#hs=s+2,he=e-1 contains=treeFlag
+ syn match treeToggleOn #".*(on)#hs=e-2,he=e-1 contains=treeHelpKey
+ syn match treeToggleOff #".*(off)#hs=e-3,he=e-1 contains=treeHelpKey
+ syn match treeHelp #^" .*# contains=treeHelpKey,treeHelpTitle,treeFlag,treeToggleOff,treeToggleOn
+
+ "highlighting for sym links
+ syn match treeLink #[^-| `].* -> #
+
+ "highlighting for readonly files
+ syn match treeRO #[0-9a-zA-Z]\+.*\[RO\]# contains=treeFlag
+
+ "highlighing for directory nodes and file nodes
+ syn match treeDirSlash #/#
+ syn match treeDir #[^-| `].*/\([ {}]\{4\}\)*$# contains=treeLink,treeDirSlash,treeOpenable,treeClosable
+ syn match treeFile #|-.*# contains=treeLink,treePart,treeRO,treePartFile
+ syn match treeFile #`-.*# contains=treeLink,treePart,treeRO,treePartFile
+ syn match treeCWD #^/.*$#
+
+ if g:NERDChristmasTree
+ hi def link treePart Special
+ hi def link treePartFile Type
+ hi def link treeFile Macro
+ hi def link treeDirSlash Identifier
+ hi def link treeClosable Type
+ else
+ hi def link treePart Normal
+ hi def link treePartFile Normal
+ hi def link treeFile Normal
+ hi def link treeClosable Title
+ endif
+
+ hi def link treeHelp String
+ hi def link treeHelpKey Identifier
+ hi def link treeHelpTitle Macro
+ hi def link treeToggleOn Question
+ hi def link treeToggleOff WarningMsg
+
+ hi def link treeDir Directory
+ hi def link treeUp Directory
+ hi def link treeCWD Statement
+ hi def link treeLink Title
+ hi def link treeOpenable Title
+ hi def link treeFlag ignore
+ hi def link treeRO WarningMsg
+
+ hi def link NERDTreeCurrentNode Search
+endfunction
+
+"FUNCTION: s:ShouldSplitToOpen() {{{2
+"Returns 1 if opening a file from the tree in the given window requires it to
+"be split
+"
+"Args:
+"winnumber: the number of the window in question
+function! s:ShouldSplitToOpen(winnumber)
+ if &hidden
+ return 0
+ endif
+ let oldwinnr = winnr()
+
+ exec a:winnumber . "wincmd p"
+ let modified = &modified
+ exec oldwinnr . "wincmd p"
+
+ return winnr("$") == 1 || (modified && s:BufInWindows(winbufnr(a:winnumber)) < 2)
+endfunction
+
+"FUNCTION: s:StripMarkupFromLine(line){{{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, s:tree_RO_str_reg, "","")
+
+ 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()
+ call s:RenderView()
+
+ call s:RestoreScreenState()
+ else
+ call s:CloseTree()
+ endif
+ else
+ call s:InitNerdTree(a:dir)
+ endif
+endfunction
+"SECTION: Interface bindings {{{1
+"============================================================
+"FUNCTION: s:ActivateNode() {{{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.
+function! s:ActivateNode()
+ if getline(".") == s:tree_up_dir_line
+ return s:UpDir(0)
+ endif
+ let treenode = s:GetSelectedNode()
+ if treenode == {}
+ call s:EchoWarning("cannot open selected entry")
+ return
+ endif
+
+ if treenode.path.isDirectory
+ call treenode.ToggleOpen()
+ call s:RenderView()
+ call s:PutCursorOnNode(treenode, 0)
+ else
+ call s:OpenFileNode(treenode)
+ endif
+endfunction
+
+"FUNCTION: s:BindMappings() {{{2
+function! s:BindMappings()
+ " set up mappings and commands for this buffer
+ nnoremap <silent> <buffer> <middlerelease> :call <SID>HandleMiddleMouse()<cr>
+ nnoremap <silent> <buffer> <leftrelease> <leftrelease>:call <SID>CheckForActivate()<cr>
+ nnoremap <silent> <buffer> <2-leftmouse> :call <SID>ActivateNode()<cr>
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapActivateNode . " :call <SID>ActivateNode()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenSplit ." :call <SID>OpenEntrySplit()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreview ." :call <SID>PreviewNode(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapPreviewSplit ." :call <SID>PreviewNode(1)<cr>"
+
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapExecute ." :call <SID>ExecuteNode()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenRecursively ." :call <SID>OpenNodeRecursively()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdirKeepOpen ." :call <SID>UpDir(1)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapUpdir ." :call <SID>UpDir(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChangeRoot ." :call <SID>ChRoot()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapChdir ." :call <SID>ChCwd()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapQuit ." :NERDTreeToggle<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefreshRoot ." :call <SID>RefreshRoot()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapRefresh ." :call <SID>RefreshCurrent()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapHelp ." :call <SID>DisplayHelp()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleHidden ." :call <SID>ToggleShowHidden()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFilters ." :call <SID>ToggleIgnoreFilter()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapToggleFiles ." :call <SID>ToggleShowFiles()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseDir ." :call <SID>CloseCurrentDir()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapCloseChildren ." :call <SID>CloseChildren()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapFilesystemMenu ." :call <SID>ShowFileSystemMenu()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpParent ." :call <SID>JumpToParent()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpNextSibling ." :call <SID>JumpToSibling(1)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpPrevSibling ." :call <SID>JumpToSibling(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpFirstChild ." :call <SID>JumpToFirstChild()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpLastChild ." :call <SID>JumpToLastChild()<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapJumpRoot ." :call <SID>JumpToRoot()<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTab ." :call <SID>OpenNodeNewTab(0)<cr>"
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenInTabSilent ." :call <SID>OpenNodeNewTab(1)<cr>"
+
+ exec "nnoremap <silent> <buffer> ". g:NERDTreeMapOpenExpl ." :call <SID>OpenExplorer()<cr>"
+
+
+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:GetSelectedNode()
+ if currentNode != {}
+ let startToCur = strpart(getline(line(".")), 0, col("."))
+ let char = strpart(startToCur, strlen(startToCur)-1, 1)
+
+ "if they clicked a dir, check if they clicked on the + or ~ sign
+ "beside it
+ if currentNode.path.isDirectory
+ let reg = '^' . s:tree_markup_reg .'*[' . s:tree_dir_open . s:tree_dir_closed . ']$'
+ if startToCur =~ reg
+ call s:ActivateNode()
+ return
+ endif
+ endif
+
+ if (g:NERDTreeMouseMode == 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode == 3
+ if char !~ s:tree_markup_reg && startToCur !~ '\/$'
+ call s:ActivateNode()
+ return
+ endif
+ endif
+ endif
+endfunction
+
+" FUNCTION: s:ChCwd() {{{2
+function! s:ChCwd()
+ let treenode = s:GetSelectedNode()
+ if treenode == {}
+ call s:Echo("Select a node first")
+ return
+ endif
+
+ try
+ call treenode.path.ChangeToDir()
+ catch /^NERDTree.Path.Change/
+ 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:GetSelectedNode()
+ if treenode == {} || treenode.path.isDirectory == 0
+ call s:Echo("Select a directory node first")
+ return
+ endif
+
+ if treenode.isOpen == 0
+ call treenode.Open()
+ endif
+
+ let t:NERDTreeRoot = treenode
+
+ "change dir to the dir of the new root if instructed to
+ if g:NERDTreeChDirMode == 2
+ exec "cd " . treenode.path.StrForEditCmd()
+ endif
+
+
+ call s:RenderView()
+ call s:PutCursorOnNode(t:NERDTreeRoot, 0)
+endfunction
+
+" FUNCTION: s:CloseChildren() {{{2
+" closes all childnodes of the current node
+function! s:CloseChildren()
+ let currentNode = s:GetSelectedDir()
+ if currentNode == {}
+ call s:Echo("Select a node first")
+ return
+ endif
+
+ call currentNode.CloseChildren()
+ call s:RenderView()
+ call s:PutCursorOnNode(currentNode, 0)
+endfunction
+" FUNCTION: s:CloseCurrentDir() {{{2
+" closes the parent dir of the current node
+function! s:CloseCurrentDir()
+ let treenode = s:GetSelectedNode()
+ if treenode == {}
+ call s:Echo("Select a node first")
+ return
+ endif
+
+ let parent = treenode.parent
+ if parent.IsRoot()
+ call s:Echo("cannot close tree root")
+ else
+ call treenode.parent.Close()
+ call s:RenderView()
+ call s:PutCursorOnNode(treenode.parent, 0)
+ endif
+endfunction
+
+" FUNCTION: s:DeleteNode() {{{2
+" if the current node is a file, pops up a dialog giving the user the option
+" to delete it
+function! s:DeleteNode()
+ let currentNode = s:GetSelectedNode()
+ if currentNode == {}
+ call s:Echo("Put the cursor on a file node first")
+ return
+ endif
+
+ 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.StrForOS(0) . ": ")
+ let confirmed = choice == 'yes'
+ else
+ echo "Delete the current node\n" .
+ \ "==========================================================\n".
+ \ "Are you sure you wish to delete the node:\n" .
+ \ "" . currentNode.path.StrForOS(0) . " (yN):"
+ let choice = nr2char(getchar())
+ let confirmed = choice == 'y'
+ endif
+
+
+ if confirmed
+ try
+ call currentNode.Delete()
+ call s:RenderView()
+
+ "if the node is open in a buffer, ask the user if they want to
+ "close that buffer
+ let bufnum = bufnr(currentNode.path.Str(0))
+ 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: s:DisplayHelp() {{{2
+" toggles the help display
+function! s:DisplayHelp()
+ let t:treeShowHelp = t:treeShowHelp ? 0 : 1
+ call s:RenderView()
+ call s:CenterView()
+endfunction
+
+" FUNCTION: s:ExecuteNode() {{{2
+function! s:ExecuteNode()
+ let treenode = s:GetSelectedNode()
+ if treenode == {} || treenode.path.isDirectory
+ call s:Echo("Select an executable file node first" )
+ else
+ echo "NERDTree executor\n" .
+ \ "==========================================================\n".
+ \ "Complete the command to execute (add arguments etc): \n\n"
+ let cmd = treenode.path.StrForOS(1)
+ let cmd = input(':!', cmd . ' ')
+
+ if cmd != ''
+ exec ':!' . cmd
+ else
+ call s:Echo("command aborted")
+ endif
+ endif
+endfunction
+
+" FUNCTION: s:HandleMiddleMouse() {{{2
+function! s:HandleMiddleMouse()
+ let curNode = s:GetSelectedNode()
+ 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()
+ endif
+endfunction
+
+
+" FUNCTION: s:InsertNewNode() {{{2
+" Adds a new node to the filesystem and then into the tree
+function! s:InsertNewNode()
+ let curDirNode = s:GetSelectedDir()
+ if curDirNode == {}
+ call s:Echo("Put the cursor on a node first" )
+ return
+ endif
+
+ let newNodeName = input("Add a childnode\n".
+ \ "==========================================================\n".
+ \ "Enter the dir/file name to be created. Dirs end with a '/'\n" .
+ \ "", curDirNode.path.Str(0))
+
+ if newNodeName == ''
+ call s:Echo("Node Creation Aborted.")
+ return
+ endif
+
+ try
+ let newPath = s:oPath.Create(newNodeName)
+
+ let parentNode = t:NERDTreeRoot.FindNode(newPath.GetPathTrunk())
+
+ let newTreeNode = s:oTreeFileNode.New(newPath)
+ if parentNode.isOpen || !empty(parentNode.children)
+ call parentNode.AddChild(newTreeNode, 1)
+ call s:RenderView()
+ call s:PutCursorOnNode(newTreeNode, 1)
+ endif
+ catch /^NERDTree/
+ call s:EchoWarning("Node Not Created.")
+ endtry
+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:GetSelectedNode()
+ if !empty(currentNode)
+ if !empty(currentNode.parent)
+ call s:PutCursorOnNode(currentNode.parent, 1)
+ 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 s:PutCursorOnNode(t:NERDTreeRoot, 1)
+ 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:GetSelectedNode()
+ if !empty(currentNode)
+
+ if !currentNode.path.isDirectory
+
+ if a:forward
+ let sibling = currentNode.parent.FindSibling(1)
+ else
+ let sibling = currentNode.parent
+ endif
+
+ else
+ let sibling = currentNode.FindSibling(a:forward)
+ endif
+
+ if !empty(sibling)
+ call s:PutCursorOnNode(sibling, 1)
+ call s:CenterView()
+ endif
+ else
+ call s:Echo("put the cursor on a node first")
+ endif
+endfunction
+
+" FUNCTION: s:OpenEntrySplit() {{{2
+" Opens the currently selected file from the explorer in a
+" new window
+function! s:OpenEntrySplit()
+ let treenode = s:GetSelectedNode()
+ if treenode != {}
+ call s:OpenFileNodeSplit(treenode)
+ else
+ call s:Echo("select a node first")
+ endif
+endfunction
+
+" FUNCTION: s:OpenExplorer() {{{2
+function! s:OpenExplorer()
+ let treenode = s:GetSelectedDir()
+ if treenode != {}
+ let oldwin = winnr()
+ wincmd p
+ if oldwin == winnr() || (&modified && s:BufInWindows(winbufnr(winnr())) < 2)
+ wincmd p
+ call s:OpenDirNodeSplit(treenode)
+ else
+ exec ("silent edit " . treenode.path.StrForEditCmd())
+ endif
+ else
+ call s:Echo("select a node first")
+ endif
+endfunction
+
+" FUNCTION: s:OpenNodeNewTab(stayCurrentTab) {{{2
+" Opens the currently selected file from the explorer 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:OpenNodeNewTab(stayCurrentTab)
+ let treenode = s:GetSelectedNode()
+ if treenode != {}
+ let curTabNr = tabpagenr()
+ exec "tabedit " . treenode.path.StrForEditCmd()
+ if a:stayCurrentTab
+ exec "tabnext " . curTabNr
+ endif
+ else
+ call s:Echo("select a node first")
+ endif
+endfunction
+
+
+" FUNCTION: s:OpenNodeRecursively() {{{2
+function! s:OpenNodeRecursively()
+ let treenode = s:GetSelectedNode()
+ 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
+function! s:PreviewNode(openNewWin)
+ let treenode = s:GetSelectedNode()
+ if treenode == {} || treenode.path.isDirectory
+ call s:Echo("Select a file node first" )
+ return
+ endif
+
+ if a:openNewWin
+ call s:OpenEntrySplit()
+ else
+ call s:ActivateNode()
+ end
+ call s:PutCursorInTreeWin()
+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 t: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:GetSelectedDir()
+ 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:RenameCurrent() {{{2
+" allows the user to rename the current node
+function! s:RenameCurrent()
+ let curNode = s:GetSelectedNode()
+ if curNode == {}
+ call s:Echo("Put the cursor on a node first" )
+ return
+ endif
+
+ let newNodePath = input("Rename the current node\n" .
+ \ "==========================================================\n" .
+ \ "Enter the new path for the node: \n" .
+ \ "", curNode.path.Str(0))
+
+ if newNodePath == ''
+ call s:Echo("Node Renaming Aborted.")
+ return
+ endif
+
+ let newNodePath = substitute(newNodePath, '\/$', '', '')
+
+ try
+ let bufnum = bufnr(curNode.path.Str(0))
+
+ call curNode.Rename(newNodePath)
+ call s:RenderView()
+
+ "if the node is open in a buffer, ask the user if they want to
+ "close that buffer
+ if bufnum != -1
+ let prompt = "|\n|Node renamed.\n|\n|The old file is open in buffer ". bufnum . (bufwinnr(bufnum) == -1 ? " (hidden)" : "") .". Delete this buffer? (yN)"
+ call s:PromptToDelBuffer(bufnum, prompt)
+ endif
+
+ call s:PutCursorOnNode(curNode, 1)
+
+ redraw
+ catch /^NERDTree/
+ call s:EchoWarning("Node Not Renamed.")
+ endtry
+endfunction
+
+" FUNCTION: s:ShowFileSystemMenu() {{{2
+function! s:ShowFileSystemMenu()
+ let curNode = s:GetSelectedNode()
+ if curNode == {}
+ call s:Echo("Put the cursor on a node first" )
+ return
+ endif
+
+
+ echo "NERDTree Filesystem Menu\n" .
+ \ "==========================================================\n".
+ \ "Select the desired operation: \n" .
+ \ " (1) - Add a childnode\n".
+ \ " (2) - Rename the current node\n".
+ \ " (3) - Delete the current node\n\n"
+
+ let choice = nr2char(getchar())
+
+ if choice == 1
+ call s:InsertNewNode()
+ elseif choice == 2
+ call s:RenameCurrent()
+ elseif choice == 3
+ call s:DeleteNode()
+ endif
+endfunction
+
+" FUNCTION: s:ToggleIgnoreFilter() {{{2
+" toggles the use of the NERDTreeIgnore option
+function! s:ToggleIgnoreFilter()
+ let t:NERDTreeIgnoreEnabled = !t:NERDTreeIgnoreEnabled
+ call s:RenderViewSavingPosition()
+ call s:CenterView()
+endfunction
+
+" FUNCTION: s:ToggleShowFiles() {{{2
+" toggles the display of hidden files
+function! s:ToggleShowFiles()
+ let g:NERDTreeShowFiles = !g:NERDTreeShowFiles
+ call s:RenderViewSavingPosition()
+ call s:CenterView()
+endfunction
+
+" FUNCTION: s:ToggleShowHidden() {{{2
+" toggles the display of hidden files
+function! s:ToggleShowHidden()
+ let g:NERDTreeShowHidden = !g:NERDTreeShowHidden
+ call s:RenderViewSavingPosition()
+ call s:CenterView()
+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 = t:NERDTreeRoot.path.Str(0)
+ if cwd == "/" || cwd =~ '^[^/]..$'
+ call s:Echo("already at top dir")
+ else
+ if !a:keepState
+ call t:NERDTreeRoot.Close()
+ endif
+
+ let oldRoot = t:NERDTreeRoot
+
+ if empty(t:NERDTreeRoot.parent)
+ let path = t:NERDTreeRoot.path.GetPathTrunk()
+ let newRoot = s:oTreeDirNode.New(path)
+ call newRoot.Open()
+ call newRoot.TransplantChild(t:NERDTreeRoot)
+ let t:NERDTreeRoot = newRoot
+ else
+ let t:NERDTreeRoot = t:NERDTreeRoot.parent
+
+ endif
+
+ call s:RenderView()
+ call s:PutCursorOnNode(oldRoot, 0)
+ endif
+endfunction
+
+
+" SECTION: Doc installation call {{{1
+silent call s:InstallDocumentation(expand('<sfile>:p'), s:NERD_tree_version)
+"============================================================
+finish
+" SECTION: The help file {{{1
+"=============================================================================
+" Title {{{2
+" ============================================================================
+=== START_DOC
+*NERD_tree.txt* A tree explorer plugin that owns your momma! #version#
+
+
+
+
+
+ ________ ________ _ ____________ ____ __________ ____________~
+ /_ __/ / / / ____/ / | / / ____/ __ \/ __ \ /_ __/ __ \/ ____/ ____/~
+ / / / /_/ / __/ / |/ / __/ / /_/ / / / / / / / /_/ / __/ / __/ ~
+ / / / __ / /___ / /| / /___/ _, _/ /_/ / / / / _, _/ /___/ /___ ~
+ /_/ /_/ /_/_____/ /_/ |_/_____/_/ |_/_____/ /_/ /_/ |_/_____/_____/ ~
+
+
+ Reference Manual~
+
+
+
+
+==============================================================================
+CONTENTS {{{2 *NERDTree-contents*
+
+ 1.Intro...................................|NERDTree|
+ 2.Functionality provided..................|NERDTreeFunctionality|
+ 2.1 Commands..........................|NERDTreeCommands|
+ 2.2 NERD tree mappings................|NERDTreeMappings|
+ 2.3 The filesystem menu...............|NERDTreeFilesysMenu|
+ 3.Options.................................|NERDTreeOptions|
+ 3.1 Option summary....................|NERDTreeOptionSummary|
+ 3.2 Option details....................|NERDTreeOptionDetails|
+ 4.Public functions........................|NERDTreePublicFunctions|
+ 5.TODO list...............................|NERDTreeTodo|
+ 6.The Author..............................|NERDTreeAuthor|
+ 7.Changelog...............................|NERDTreeChangelog|
+ 8.Credits.................................|NERDTreeCredits|
+
+==============================================================================
+1. Intro {{{2 *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 so you can alter the tree dynamically.
+
+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
+ * 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
+ * ...
+ * Most NERD tree navigation can also be done with the mouse
+ * Dynamic customisation of tree content
+ * 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
+ * A textual filesystem menu is provided which allows you to
+ create/delete/rename file and directory nodes
+ * 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
+
+==============================================================================
+2. Functionality provided {{{2 *NERDTreeFunctionality*
+
+------------------------------------------------------------------------------
+2.1. Commands {{{3 *NERDTreeCommands*
+
+:NERDTree [start-directory] *:NERDTree*
+ Opens a fresh NERD tree in [start-directory] or the current
+ directory if [start-directory] isn't specified.
+ For example: >
+ :NERDTree /home/marty/vim7/src
+< will open a NERD tree in /home/marty/vim7/src.
+
+:NERDTreeToggle [start-directory] *: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.
+
+------------------------------------------------------------------------------
+2.2. NERD tree Mappings {{{3 *NERDTreeMappings*
+
+Default Description~ help-tag~
+Key~
+
+o.......Open selected file, or expand selected dir...............|NERDTree-o|
+go......Open selected file, but leave cursor in the NERDTree.....|NERDTree-go|
+t.......Open selected node in a new tab..........................|NERDTree-t|
+T.......Same as 't' but keep the focus on the current tab........|NERDTree-T|
+<tab>...Open selected file in a split window.....................|NERDTree-tab|
+g<tab>..Same as <tab>, but leave the cursor on the NERDTree......|NERDTree-gtab|
+!.......Execute the current file.................................|NERDTree-!|
+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.......Open a netrw for the current dir.........................|NERDTree-e|
+
+double-click.......same as the |NERDTree-o| map.
+middle-click.......same as |NERDTree-tab| for files, same as
+ |NERDTree-e| for dirs.
+
+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|
+<C-j>...Jump down to the next sibling of the current directory...|NERDTree-c-j|
+<C-k>...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 filesystem menu..............................|NERDTree-m|
+cd......Change the CWD to the dir of the selected node...........|NERDTree-cd|
+
+H.......Toggle whether hidden files displayed....................|NERDTree-H|
+f.......Toggle whether the file filters are used.................|NERDTree-f|
+F.......Toggle whether files are displayed.......................|NERDTree-F|
+
+q.......Close the NERDTree window................................|NERDTree-q|
+?.......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.
+
+------------------------------------------------------------------------------
+ *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 netrw is
+opened 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-tab*
+Default key: <tab>
+Map option: NERDTreeMapOpenSplit
+Applies to: files.
+
+Opens the selected file in a new split window and puts the cursor in the new
+window.
+
+------------------------------------------------------------------------------
+ *NERDTree-gtab*
+Default key: g<tab>
+Map option: None
+Applies to: files.
+
+The same as |NERDTree-tab| except that the cursor is not moved.
+
+The key combo for this mapping is always "g" + NERDTreeMapOpenSplit (see
+|NERDTree-tab|).
+
+------------------------------------------------------------------------------
+ *NERDTree-!*
+Default key: !
+Map option: NERDTreeMapExecute
+Applies to: files.
+
+Executes the selected file, prompting for arguments first.
+
+------------------------------------------------------------------------------
+ *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 it is not opened. 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.
+
+Opens a netrw on the selected directory, or the selected file's directory.
+
+------------------------------------------------------------------------------
+ *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: <C-j>
+Map option: NERDTreeMapJumpNextSibling
+Applies to: files and directories.
+
+If a dir node is selected, jump to the next sibling of that node.
+If a file node is selected, jump to the next sibling of that nodes parent.
+
+------------------------------------------------------------------------------
+ *NERDTree-c-k*
+Default key: <C-k>
+Map option: NERDTreeMapJumpPrevSibling
+Applies to: files and directories.
+
+If a dir node is selected, jump to the previous sibling of that node.
+If a file node is selected, jump to the previous sibling of that nodes parent.
+
+------------------------------------------------------------------------------
+ *NERDTree-C*
+Default key: C
+Map option: NERDTreeMapChdir
+Applies to: directories.
+
+Made the selected directory node the new tree root.
+
+------------------------------------------------------------------------------
+ *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: NERDTreeMapFilesystemMenu
+Applies to: files and directories.
+
+Display the filesystem menu. See |NERDTreeFilesysMenu| for details.
+
+------------------------------------------------------------------------------
+ *NERDTree-H*
+Default key: H
+Map option: NERDTreeMapToggleHidden
+Applies to: no restrictions.
+
+Toggles whether hidden files are displayed. Hidden files are any
+file/directory that starts with a "."
+
+------------------------------------------------------------------------------
+ *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-q*
+Default key: q
+Map option: NERDTreeMapQuit
+Applies to: no restrictions.
+
+Closes the NERDtree window.
+
+------------------------------------------------------------------------------
+ *NERDTree-?*
+Default key: ?
+Map option: NERDTreeMapHelp
+Applies to: no restrictions.
+
+Toggles whether the quickhelp is displayed.
+
+------------------------------------------------------------------------------
+2.3. The filesystem menu {{{3 *NERDTreeFilesysMenu*
+
+The purpose of the filesystem menu is to allow you to perform basic filesystem
+operations quickly from the NERD tree rather than the console.
+
+The filesystem menu can be accessed with 'm' mapping and has three supported
+operations: >
+ 1. Adding nodes.
+ 2. Renaming nodes.
+ 3. Deleting nodes.
+<
+1. Adding nodes:
+To add a node move the cursor onto (or anywhere inside) the directory you wish
+to create the new node inside. Select the 'add node' option from the
+filesystem menu and type a filename. If the filename you type ends with a '/'
+character then a directory will be created. Once the operation is completed,
+the cursor is placed on the new node.
+
+2. Renaming nodes:
+To rename a node, put the cursor on it and select the 'rename' option from the
+filesystem menu. Enter the new name for the node and it will be renamed. If
+the old file is open in a buffer, you will be asked if you wish to delete that
+buffer. Once the operation is complete the cursor will be placed on the
+renamed node.
+
+3. Deleting nodes:
+To delete a node put the cursor on it and select the 'delete' option from the
+filesystem menu. After confirmation the node will be deleted. If a file is
+deleted but still exists as a buffer you will be given the option to delete
+that buffer.
+
+==============================================================================
+3. Customisation {{{2 *NERDTreeOptions*
+
+
+------------------------------------------------------------------------------
+3.1. Customisation summary {{{3 *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.
+
+|NERDTreeIgnore| Tells the NERD tree which files to ignore.
+
+|NERDTreeMouseMode| Tells the NERD tree how to handle mouse
+ clicks.
+
+|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.
+
+|NERDTreeSortOrder| Tell the NERD tree how to sort the nodes in
+ the tree.
+
+|NERDTreeSplitVertical| Tells the script whether the NERD tree should
+ be created by splitting the window vertically
+ or horizontally.
+
+|NERDTreeWinPos| Tells the script where to put the NERD tree
+ window.
+
+
+|NERDTreeWinSize| Sets the window size when the NERD tree is
+ opened.
+
+------------------------------------------------------------------------------
+3.2. Customisation details {{{3 *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: 1.
+
+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.
+
+Note to windows users: it is highly recommended that you have this option set
+to either 1 or 2 or else the script wont function properly if you attempt to
+open a NERD tree on a different drive to the one vim is currently in.
+
+Authors note: at work i have this option set to 1 because i have a giant ctags
+file in the root dir of my project. This way i can initialise the NERD tree
+with the root dir of my project and always have ctags available to me --- no
+matter where i go with the NERD tree.
+
+------------------------------------------------------------------------------
+ *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.
+
+------------------------------------------------------------------------------
+ *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.
+
+------------------------------------------------------------------------------
+ *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'.
+
+------------------------------------------------------------------------------
+ *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 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 with the |NERDTree-H| mapping.
+Use one of the follow lines to set this option: >
+ let NERDTreeShowHidden=0
+ let NERDTreeShowHidden=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. Every 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.
+
+------------------------------------------------------------------------------
+ *NERDTreeSplitVertical*
+Values: 0 or 1.
+Default: 1.
+
+This option, along with |NERDTreeWinPos|, is used to determine where the NERD
+tree window appears.
+
+If it is set to 1 then the NERD tree window will appear on either the left or
+right side of the screen (depending on the |NERDTreeWinPos| option).
+
+If it set to 0 then the NERD tree window will appear at the top of the screen.
+
+------------------------------------------------------------------------------
+ *NERDTreeWinPos*
+Values: 0 or 1.
+Default: 1.
+
+This option works in conjunction with the |NERDTreeSplitVertical| option to
+determine where NERD tree window is placed on the screen.
+
+If the option is set to 1 then the NERD tree will appear on the left or top of
+the screen (depending on the value of |NERDTreeSplitVertical|). If set to 0,
+the window will appear on the right or bottom of the screen.
+
+This option is makes it possible to use two different explorer type
+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.
+
+==============================================================================
+ *NERDTreePublicFunctions*
+5. Public functions {{{2 ~
+
+The script provides 2 public functions for your hacking pleasure. Their
+signatures are: >
+ function! NERDTreeGetCurrentNode()
+ function! NERDTreeGetCurrentPath()
+<
+The first returns the node object that the cursor is currently on, while the
+second returns the corresponding path object.
+
+This is probably a good time to mention that the script implements prototype
+style OO. To see the functions that each class provides you can read look at
+the code.
+
+Use the node objects to manipulate the structure of the tree. Use the path
+objects to access the data the tree represents and to make changes to the
+filesystem.
+
+==============================================================================
+5. TODO list {{{2 *NERDTreeTodo*
+
+Window manager integration?
+
+==============================================================================
+6. The Author {{{2 *NERDTreeAuthor*
+
+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 has an odd
+love/hate relationship with computers (but monsters hate everything by nature
+you know...) which can be awkward for him since he is a pro computer nerd for
+a living.
+
+He can be reached at martin_grenfell at msn.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 ;)
+
+==============================================================================
+7. Changelog {{{2 *NERDTreeChangelog*
+
+2.6.2
+ - Now when you try to open a file node into a window that is modified, the
+ window is not split if the &hidden option is set. Thanks to Niels Aan
+ de Brugh for this suggestion.
+
+2.6.1
+ - Fixed a major bug with the <tab> mapping. Thanks to Zhang Weiwu for
+ emailing me.
+
+2.6.0
+ - Extended the behaviour of <c-j/k>. Now if the cursor is on a file node
+ and you use <c-j/k> the cursor will jump to its PARENTS next/previous
+ sibling. Go :help NERDTree-c-j and :help NERDTree-c-k for info.
+ - Extended the behaviour of the J/K mappings. Now if the cursor is on the
+ last child of a node and you push J/K it will jump down to the last child
+ of the next/prev of its parents siblings that is open and has children.
+ Go :help NERDTree-J and :help NERDTree-K for info.
+ - The goal of these changes is to make tree navigation faster.
+ - Reorganised the help page a bit.
+ - Removed the E mapping.
+ - bugfixes
+
+2.5.0
+ - Added an option to enforce case sensitivity when sorting tree nodes.
+ Read :help NERDTreeCaseSensitiveSort for details. (thanks to Michael
+ Madsen for emailing me about this). Case sensitivity defaults to off.
+ - Made the script echo a "please wait" style message when opening large
+ directories. Thanks to AOYAMA Shotaro for this suggestion.
+ - Added 2 public functions that can be used to retrieve the treenode and
+ path that the cursor is on. Read :help NERDTreePublicFunctions for
+ details (thanks again to AOYAMA Shotaro for the idea :).
+ - added 2 new mappings for file nodes: "g<tab>" and "go". These are the
+ same as the "<tab>" and "o" maps except that the cursor stays in the
+ NERDTree. Note: these maps are slaved to the o and <tab> mappings, so if
+ eg you remap "<tab>" to "i" then the "g<tab>" map will also be changed
+ to "gi".
+ - Renamed many of the help tags to be simpler.
+ - Simplified the ascii "graphics" for the filesystem menu
+ - Fixed bugs.
+ - Probably created bugs.
+ - Refactoring.
+
+2.4.0
+ - Added the P mapping to jump to the tree root.
+ - Added window centering functionality that can be triggered when doing
+ using any of the tree nav mappings. Essentially, if the cursor comes
+ within a certain distance of the top/bottom of the window then a zz is
+ done in the window. Two related options were added: NERDTreeAutoCenter
+ to turn this functionality on/off, and NERDTreeAutoCenterThreshold to
+ control how close the cursor has to be to the window edge to trigger the
+ centering.
+
+2.3.0
+ - Tree navigation changes:
+ - Added J and K mappings to jump to last/first child of the current dir.
+ Options to customise these mappings have also been added.
+ - Remapped the jump to next/prev sibling commands to be <C-j> and <C-k> by
+ default.
+ These changes should hopefully make tree navigation mappings easier to
+ remember and use as the j and k keys are simply reused 3 times (twice
+ with modifier keys).
+
+ - Made it so that, when any of the tree filters are toggled, the cursor
+ stays with the selected node (or goes to its parent/grandparent/... if
+ that node is no longer visible)
+ - Fixed an error in the doc for the mouse mode option.
+ - Made the quickhelp correctly display the current single/double click
+ mappings for opening nodes as specified by the NERDTreeMouseMode option.
+ - Fixed a bug where the script was spazzing after prompting you to delete
+ a modified buffer when using the filesystem menu.
+ - Refactoring
+2.2.3
+ - Refactored the :echo output from the script.
+ - Fixed some minor typos in the doc.
+ - Made some minor changes to the output of the 'Tree filtering mappings'
+ part of the quickhelp
+
+2.2.2
+ - More bugfixes... doh.
+
+2.2.1
+ - Bug fix that was causing an exception when closing the nerd tree. Thanks
+ to Tim carey-smith and Yu Jun for pointing this out.
+
+2.2.0
+ - Now 'cursorline' is set in the NERD tree buffer by default. See :help
+ NERDTreeHighlightCursorline for how to disable it.
+
+2.1.2
+ - Stopped the script from clobbering the 1,2,3 .. 9 registers.
+ - Made it "silent!"ly delete buffers when renaming/deleting file nodes.
+ - Minor correction to the doc
+ - Fixed a bug when refreshing that was occurring when the node you
+ refreshed had been deleted externally.
+ - Fixed a bug that was occurring when you open a file that is already open
+ and modified.
+
+2.1.1
+ - Added a bit more info about the buffers you are prompted to delete when
+ renaming/deleting nodes from the filesystem menu that are already loaded
+ into buffers.
+ - Refactoring and bugfixes
+
+2.1.0
+ - Finally removed the blank line that always appears at the top of the
+ NERDTree buffer
+ - Added NERDTreeMouseMode option. If set to 1, then a double click is
+ required to activate all nodes, if set to 2 then a single click will
+ activate directory nodes, if set to 3 then a single click will activate
+ all nodes.
+ - Now if you delete a file node and have it open in a buffer you are given
+ the option to delete that buffer as well. Similarly if you rename a file
+ you are given the option to delete any buffers containing the old file
+ (if any exist)
+ - When you rename or create a node, the cursor is now put on the new node,
+ this makes it easy immediately edit the new file.
+ - Fixed a bug with the ! mapping that was occurring on windows with paths
+ containing spaces.
+ - Made all the mappings customisable. See |NERD_tree-mappings| for
+ details. A side effect is that a lot of the "double mappings" have
+ disappeared. E.g 'o' is now the key that is used to activate a node,
+ <CR> is no longer mapped to the same.
+ - Made the script echo warnings in some places rather than standard echos
+ - Insane amounts of refactoring all over the place.
+
+2.0.0
+ - Added two new NERDChristmasTree decorations. First person to spot them
+ and email me gets a free copy of the NERDTree.
+ - Made it so that when you jump around the tree (with the p, s and S
+ mappings) it is counted as a jump by vim. This means if you, eg, push
+ 'p' one too many times then you can go `` or ctrl-o.
+ - Added a new option called NERDTreeSortOrder which takes an array of
+ regexs and is used to determine the order that the treenodes are listed
+ in. Go :help NERDTreeSortOrder for details.
+ - Removed the NERDTreeSortDirs option because it is consumed by
+ NERDTreeSortOrder
+ - Added the 'i' mapping which is the same as <tab> but requires less
+ effort to reach.
+ - Added the ! mapping which is used to execute file in the tree (after it
+ prompts you for arguments etc)
+
+
+==============================================================================
+8. Credits {{{2 *NERDTreeCredits*
+
+Thanks to Tim Carey-Smith for testing/using the NERD tree from the first
+pre-beta version, for his many suggestions and for his constant stream of bug
+complaints.
+
+Thanks to Vigil for trying it out before the first release :) and suggesting
+that mappings to open files in new tabs should be implemented.
+
+Thanks to Nick Brettell for testing, fixing my spelling and suggesting i put a
+ .. (up a directory)
+line in the gui.
+
+Thanks to Thomas Scott Urban - the author of the vtreeexplorer plugin - whose
+gui code i borrowed from.
+
+Thanks to Terrance Cohen for pointing out a bug where the script was changing
+vims CWD all over the show.
+
+Thanks to Yegappan Lakshmanan (author of Taglist and other orgasmically
+wonderful plugins) for telling me how to fix a bug that was causing vim to go
+into visual mode everytime you double clicked a node :)
+
+Thanks to Jason Mills for sending me a fix that allows windows paths to use
+forward slashes as well as backward.
+
+Thanks to Michael Geddes (frogonwheels on #vim at freenode) for giving me some
+tips about syntax highlighting when i was doing highlighting for the
+quickhelp.
+
+Thanks to Yu Jun for emailing me about a bug that was occurring when closing
+the tree.
+
+Thanks to Michael Madsen for emailing me about making case sensitivity
+optional when sorting nodes.
+
+Thanks to AOYAMA Shotaro for suggesting that i echo a "please wait" message
+when opening large directories.
+
+Thanks to Michael Madsen for requesting the NERDTreeCaseSensitiveSort option.
+
+Thanks to AOYAMA Shotaro for suggesting that a "please wait" style message be
+echoed when opening large directories. Also, thanks for the suggestion of
+having public functions in the script to access the internal data :D
+
+Thanks to Zhang Weiwu for emailing me about a bug with the the <tab> mapping
+in 2.6.0
+
+Thanks to Niels Aan de Brugh for the suggestion that the script now split the
+window if you try to open a file in a window containing a modified buffer when
+the &hidden option is set.
+
+=== END_DOC
+" vim: set ts=4 sw=4 foldmethod=marker foldmarker={{{,}}} foldlevel=2:
diff --git a/.vim/plugin/a.vim b/.vim/plugin/a.vim
new file mode 100644
index 0000000..e73817d
--- /dev/null
+++ b/.vim/plugin/a.vim
@@ -0,0 +1,840 @@
+" Copyright (c) 1998-2006
+" Michael Sharpe <feline@irendi.com>
+"
+" 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_<EXT> variable to a comma separated list of alternates,
+" where <EXT> 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 <feline@irendi.com>
+function! <SID>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 <SID>AddAlternateExtensionMapping('h',"c,cpp,cxx,cc,CC")
+call <SID>AddAlternateExtensionMapping('H',"C,CPP,CXX,CC")
+call <SID>AddAlternateExtensionMapping('hpp',"cpp,c")
+call <SID>AddAlternateExtensionMapping('HPP',"CPP,C")
+call <SID>AddAlternateExtensionMapping('c',"h")
+call <SID>AddAlternateExtensionMapping('C',"H")
+call <SID>AddAlternateExtensionMapping('cpp',"h,hpp")
+call <SID>AddAlternateExtensionMapping('CPP',"H,HPP")
+call <SID>AddAlternateExtensionMapping('cc',"h")
+call <SID>AddAlternateExtensionMapping('CC',"H,h")
+call <SID>AddAlternateExtensionMapping('cxx',"h")
+call <SID>AddAlternateExtensionMapping('CXX',"H")
+" Mappings for PSL7
+call <SID>AddAlternateExtensionMapping('psl',"ph")
+call <SID>AddAlternateExtensionMapping('ph',"psl")
+" Mappings for ADA
+call <SID>AddAlternateExtensionMapping('adb',"ads")
+call <SID>AddAlternateExtensionMapping('ads',"adb")
+" Mappings for lex and yacc files
+call <SID>AddAlternateExtensionMapping('l',"y,yacc,ypp")
+call <SID>AddAlternateExtensionMapping('lex',"yacc,y,ypp")
+call <SID>AddAlternateExtensionMapping('lpp',"ypp,y,yacc")
+call <SID>AddAlternateExtensionMapping('y',"l,lex,lpp")
+call <SID>AddAlternateExtensionMapping('yacc',"lex,l,lpp")
+call <SID>AddAlternateExtensionMapping('ypp',"lpp,l,lex")
+" Mappings for OCaml
+call <SID>AddAlternateExtensionMapping('ml',"mli")
+call <SID>AddAlternateExtensionMapping('mli',"ml")
+" ASP stuff
+call <SID>AddAlternateExtensionMapping('aspx.cs', 'aspx')
+call <SID>AddAlternateExtensionMapping('aspx.vb', 'aspx')
+call <SID>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 <feline@irendi.com>
+" History : Renamed from GetNthExtensionFromSpec to GetNthItemFromList
+" to reflect a more generic use of this function. -- Bindu
+function! <SID>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:<sep><pattern><sep><subst><sep><flag><sep>
+"
+" <sep> seperator character, we often use one of [/|%#]
+" <pattern> is what you are looking for
+" <subst> is the output pattern
+" <flag> 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 <bindu@wavell.net>
+function! <SID>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! <SID>FindFileInSearchPath(fileName, pathList, relPathBase)
+ let filepath = ""
+ let m = 1
+ let pathListLen = strlen(a:pathList)
+ if (pathListLen > 0)
+ while (1)
+ let pathSpec = <SID>GetNthItemFromList(a:pathList, m)
+ if (pathSpec != "")
+ let path = <SID>ExpandAlternatePath(pathSpec, a:relPathBase)
+ let fullname = path . "/" . a:fileName
+ let foundMatch = <SID>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 <SID>FindFileInSearchPath() but with extensions
+function! <SID>FindFileInSearchPathEx(fileName, pathList, relPathBase, count)
+ let filepath = ""
+ let m = 1
+ let spath = ""
+ let pathListLen = strlen(a:pathList)
+ if (pathListLen > 0)
+ while (1)
+ let pathSpec = <SID>GetNthItemFromList(a:pathList, m)
+ if (pathSpec != "")
+ let path = <SID>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 <feline@irendi.com>
+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 = <SID>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 <feline@irendi.com>
+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 = <SID>GetNthItemFromList(a:pathList, m)
+ if (pathSpec != "")
+ let path = <SID>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 <feline@irendi.com>
+" 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 <SID>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 = <SID>GetNthItemFromList(allfiles, n)
+ let bestFile = onefile
+ while (onefile != "" && score < 2)
+ let score = <SID>BufferOrFileExists(onefile)
+ if (score > bestScore)
+ let bestScore = score
+ let bestFile = onefile
+ endif
+ let n = n + 1
+ let onefile = <SID>GetNthItemFromList(allfiles, n)
+ endwhile
+
+ if (bestScore == 0 && g:alternateNoDefaultAlternate == 1)
+ echo "No existing alternate available"
+ else
+ call <SID>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("<cfile>")
+ let currentPath = expand("%:p:h")
+ let openCount = 1
+
+ let fileName = <SID>FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, openCount)
+ if (fileName != "")
+ call <SID>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 = <SID>FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, openCount)
+ if (fileName != "")
+ call <SID>FindOrCreateBuffer(fileName, "n".a:bang, 0)
+ let b:openCount = openCount
+ let b:cursorFile = cursorFile
+ let b:currentPath = currentPath
+ else
+ let fileName = <SID>FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, 1)
+ if (fileName != "")
+ call <SID>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<bang>", <f-args>)
+comm! -nargs=? -bang IHS call AlternateOpenFileUnderCursor("h<bang>", <f-args>)
+comm! -nargs=? -bang IHV call AlternateOpenFileUnderCursor("v<bang>", <f-args>)
+comm! -nargs=? -bang IHT call AlternateOpenFileUnderCursor("t<bang>", <f-args>)
+comm! -nargs=? -bang IHN call AlternateOpenNextFile("<bang>")
+"imap <Leader>ih <ESC>:IHS<CR>
+nmap <Leader>ih :IHS<CR>
+"imap <Leader>is <ESC>:IHS<CR>:A<CR>
+nmap <Leader>is :IHS<CR>:A<CR>
+"imap <Leader>ihn <ESC>:IHN<CR>
+nmap <Leader>ihn :IHN<CR>
+
+"function! <SID>PrintList(theList)
+" let n = 1
+" let oneFile = <SID>GetNthItemFromList(a:theList, n)
+" while (oneFile != "")
+" let n = n + 1
+" let oneFile = <SID>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 <feline@irendi.com>
+function! NextAlternate(bang)
+ if (exists('b:AlternateAllFiles'))
+ let currentFile = expand("%")
+ let n = 1
+ let onefile = <SID>GetNthItemFromList(b:AlternateAllFiles, n)
+ while (onefile != "" && !<SID>EqualFilePaths(fnamemodify(onefile,":p"), fnamemodify(currentFile,":p")))
+ let n = n + 1
+ let onefile = <SID>GetNthItemFromList(b:AlternateAllFiles, n)
+ endwhile
+
+ if (onefile != "")
+ let stop = n
+ let n = n + 1
+ let foundAlternate = 0
+ let nextAlternate = ""
+ while (n != stop)
+ let nextAlternate = <SID>GetNthItemFromList(b:AlternateAllFiles, n)
+ if (nextAlternate == "")
+ let n = 1
+ continue
+ endif
+ let n = n + 1
+ if (<SID>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 <SID>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<bang>", <f-args>)
+comm! -nargs=? -bang AS call AlternateFile("h<bang>", <f-args>)
+comm! -nargs=? -bang AV call AlternateFile("v<bang>", <f-args>)
+comm! -nargs=? -bang AT call AlternateFile("t<bang>", <f-args>)
+comm! -nargs=? -bang AN call NextAlternate("<bang>")
+
+" 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 <feline@irendi.com>
+" History : Updated code to handle buffernames using just the
+" filename and not the path.
+function! <SID>BufferOrFileExists(fileName)
+ let result = 0
+
+ let lastBuffer = bufnr("$")
+ let i = 1
+ while i <= lastBuffer
+ if <SID>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 <feline@irendi.com>
+" 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! <SID>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 <SID>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 <ilya@po4ta.com>
+function! <SID>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/autotag.vim b/.vim/plugin/autotag.vim
new file mode 100644
index 0000000..8bb2d0e
--- /dev/null
+++ b/.vim/plugin/autotag.vim
@@ -0,0 +1,150 @@
+" This file supplies automatic tag regeneration when saving files
+" There's a problem with ctags when run with -a (append)
+" ctags doesn't remove entries for the supplied source file that no longer exist
+" so this script (implemented in python) finds a tags file for the file vim has
+" just saved, removes all entries for that source file and *then* runs ctags -a
+
+if has("python")
+
+python << EEOOFF
+import os
+import string
+import os.path
+import fileinput
+import sys
+import vim
+
+def echo(str):
+ str=str.replace('\\', '\\\\')
+ str=str.replace('"', "'")
+ vim.command("redraw | echo \"%s\"" % str)
+
+class AutoTag:
+ def __init__(self, excludesuffix="", ctags_cmd="ctags", verbose=0):
+ self.tags = {}
+ self.excludesuffix = [ "." + s for s in excludesuffix.split(".") ]
+ verbose = long(verbose)
+ if verbose > 0:
+ self.verbose = verbose
+ else:
+ self.verbose = 0
+ self.sep_used_by_ctags = '/'
+ self.cwd = os.getcwd()
+ self.ctags_cmd = ctags_cmd
+ self.count = 0
+
+ def findTagFile(self, source):
+ ( drive, file ) = os.path.splitdrive(source)
+ while file:
+ file = os.path.dirname(file)
+ tagsFile = os.path.join(drive, file, "tags")
+ self.diag(2, "does %s exist?", tagsFile)
+ if os.path.isfile(tagsFile):
+ self.diag(2, "Found tags file %s", tagsFile)
+ return tagsFile
+ elif not file or file == os.sep or file == "//" or file == "\\\\":
+ self.diag(2, "exhausted search for tag file for %s", source)
+ return None
+ self.diag(2, "Nope. :-| %s does NOT exist", tagsFile)
+ return None
+
+ def addSource(self, source):
+ if not source:
+ return
+ if os.path.splitext(source)[1] in self.excludesuffix:
+ self.diag(1, "Ignoring excluded file " + source)
+ return
+ tagsFile = self.findTagFile(source)
+ if tagsFile:
+ self.diag(2, "if tagsFile:")
+ relativeSource = source[len(os.path.dirname(tagsFile)):]
+ self.diag(2, "relativeSource = source[len(os.path.dirname(tagsFile)):]")
+ if relativeSource[0] == os.sep:
+ self.diag(2, "if relativeSource[0] == os.sep:")
+ relativeSource = relativeSource[1:]
+ self.diag(2, "relativeSource = relativeSource[1:]")
+ if os.sep != self.sep_used_by_ctags:
+ self.diag(2, "if os.sep != self.sep_used_by_ctags:")
+ relativeSource = string.replace(relativeSource, os.sep, self.sep_used_by_ctags)
+ self.diag(2, "relativeSource = string.replace(relativeSource, os.sep, self.sep_used_by_ctags)")
+ if self.tags.has_key(tagsFile):
+ self.diag(2, "if self.tags.has_key(tagsFile):")
+ self.tags[tagsFile].append(relativeSource)
+ self.diag(2, "self.tags[tagsFile].append(relativeSource)")
+ else:
+ self.diag(2, "else:")
+ self.tags[tagsFile] = [ relativeSource ]
+ self.diag(2, "self.tags[tagsFile] = [ relativeSource ]")
+
+ def stripTags(self, tagsFile, sources):
+ self.diag(1, "Removing tags for %s from tags file %s", (sources, tagsFile))
+ backup = ".SAFE"
+ for line in fileinput.input(files=tagsFile, inplace=True, backup=backup):
+ if line[-1:] == '\n':
+ line = line[:-1]
+ if line[-1:] == '\r':
+ line = line[:-1]
+ if line[0] == "!":
+ print line
+ else:
+ fields = string.split(line, "\t")
+ if len(fields) > 3:
+ found = False
+ for source in sources:
+ if fields[1] == source:
+ found = True
+ break
+ if not found:
+ print line
+ else:
+ print line
+ os.unlink(tagsFile + backup)
+
+ def rebuildTagFiles(self):
+ for tagsFile in self.tags.keys():
+ tagsDir = os.path.dirname(tagsFile)
+ sources = self.tags[tagsFile]
+ os.chdir(tagsDir)
+ self.stripTags(tagsFile, sources)
+ cmd = "%s -a " % self.ctags_cmd
+ for source in sources:
+ if os.path.isfile(source):
+ cmd += " '%s'" % source
+ self.diag(1, "%s: %s", (tagsDir, cmd))
+ (ch_in, ch_out) = os.popen2(cmd)
+ for line in ch_out:
+ pass
+ os.chdir(self.cwd)
+
+ def diag(self, level, msg, args = None):
+ if msg and args:
+ msg = msg % args
+ if level <= self.verbose:
+ echo(msg)
+EEOOFF
+
+function! AutoTag()
+python << EEOOFF
+at = AutoTag(vim.eval("g:autotagExcludeSuffixes"), vim.eval("g:autotagCtagsCmd"), long(vim.eval("g:autotagVerbosityLevel")))
+at.addSource(vim.eval("expand(\"%:p\")"))
+at.rebuildTagFiles()
+EEOOFF
+endfunction
+
+if !exists("g:autotagVerbosityLevel")
+ let g:autotagVerbosityLevel=0
+endif
+if !exists("g:autotagExcludeSuffixes")
+ let g:autotagExcludeSuffixes="tml.xml"
+endif
+if !exists("g:autotagCtagsCmd")
+ let g:autotagCtagsCmd="ctags"
+endif
+if !exists("g:autotag_autocmd_set")
+ let g:autotag_autocmd_set=1
+ autocmd BufWritePost,FileWritePost * call AutoTag ()
+endif
+
+endif " has("python")
+
+" vim:sw=3:ts=3
diff --git a/.vim/plugin/scmCloseParens.vim b/.vim/plugin/scmCloseParens.vim
new file mode 100644
index 0000000..8aca684
--- /dev/null
+++ b/.vim/plugin/scmCloseParens.vim
@@ -0,0 +1,58 @@
+" Description: Simple script (hack ?) that closes opened parens
+" Author: Adrien Pierard <pierarda#iro.umontreal.ca>
+" Modified: 04/05/07
+" Version: 0.1
+"
+" Usage: I mapped it to <Leader>p
+" So, just go to normal mode, and type the shortcut, or :call
+" RunScmCloseParens() yourself
+
+
+let b:msg = ""
+let b:bcpt = 0
+
+function! SetCursorWhereItIsGoodToPutItEh()
+ let line = substitute(getline("."), "\\s\\+$", "", "")
+ call setline(line("."),line)
+ norm $
+ let charUnderCursor = strpart(line("."), col(".") - 1, 1)
+ norm a)
+ call CountAsMuchAsPossible()
+endfunction
+
+function! CountAsMuchAsPossible()
+ let cpt = 0
+ while (CanWeGoOn() > 0)
+ let cpt = cpt + 1
+ call OhGetBackAndSetAnotherOne()
+ endwhile
+ let line = substitute(getline("."), ")$", "", "")
+ call setline(line("."),line)
+ let b:cpt = cpt
+endfunction
+
+function! CanWeGoOn()
+ return (searchpair('(', '', ')' , 'b' ))
+endfunction
+
+function! OhGetBackAndSetAnotherOne()
+ call searchpair('(', '', ')')
+ norm a)
+
+endfunction
+
+function! InitScmCloseParens()
+ if ! exists("g:ScmCloseParens")
+ let g:ScmCloseParens = "Scheme on you !"
+ execute 'nmap <Leader>p :call RunScmCloseParens()<Cr>'
+ endif
+endfunction
+
+fun! RunScmCloseParens()
+ let b:bcpt = 0
+ call SetCursorWhereItIsGoodToPutItEh()
+ norm :echo b:bcpt
+endfunction
+
+call InitScmCloseParens()
+
diff --git a/.vim/plugin/surround.vim b/.vim/plugin/surround.vim
new file mode 100644
index 0000000..ec00098
--- /dev/null
+++ b/.vim/plugin/surround.vim
@@ -0,0 +1,727 @@
+" surround.vim - Surroundings
+" Maintainer: Tim Pope <vimNOSPAM@tpope.info>
+" GetLatestVimScripts: 1697 1 :AutoInstall: surround.vim
+" $Id: surround.vim,v 1.16 2006/11/06 05:53:09 tpope Exp $
+" Help is below; it may be read here. Alternatively, after the plugin is
+" installed and running, :call SurroundHelp() to install a proper help file.
+
+" *surround.txt* Plugin for deleting, changing, and adding "surroundings"
+"
+" Author: Tim Pope <vimNOSPAM@tpope.info> *surround-author*
+" License: Same terms as Vim itself (see |license|)
+"
+" This plugin is only available if 'compatible' is not set.
+"
+" Introduction: *surround*
+"
+" This plugin is a tool for dealing with pairs of "surroundings." Examples
+" of surroundings include parentheses, quotes, and HTML tags. They are
+" closely related to what Vim refers to as |text-objects|. Provided
+" are mappings to allow for removing, changing, and adding surroundings.
+"
+" Details follow on the exact semantics, but first, consider the following
+" examples. An asterisk (*) is used to denote the cursor position.
+"
+" Old text Command New text ~
+" "Hello *world!" ds" Hello world!
+" [123+4*56]/2 cs]) (123+456)/2
+" "Look ma, I'm *HTML!" cs"<q> <q>Look ma, I'm HTML!</q>
+" if *x>3 { ysW( if ( x>3 ) {
+" my $str = *whee!; vlllls' my $str = 'whee!';
+"
+" While a few features of this plugin will work in older versions of Vim,
+" Vim 7 is recommended for full functionality.
+"
+" Mappings: *surround-mappings*
+"
+" Delete surroundings is *ds*. The next character given determines the target
+" to delete. The exact nature of the target are explained in
+" |surround-targets| but essentially it is the last character of a
+" |text-object|. This mapping deletes the difference between the "inner"
+" object and "an" object. This is easiest to understand with some examples:
+"
+" Old text Command New text ~
+" "Hello *world!" ds" Hello world!
+" (123+4*56)/2 ds) 123+456/2
+" <div>Yo!*</div> dst Yo!
+"
+" Change surroundings is *cs*. It takes two arguments, a target like with
+" |ds|, and a replacement. Details about the second argument can be found
+" below in |surround-replacements|. Once again, examples are in order.
+"
+" Old text Command New text ~
+" "Hello *world!" cs"' 'Hello world!'
+" "Hello *world!" cs"<q> <q>Hello world!</q>
+" (123+4*56)/2 cs)] [123+456]/2
+" (123+4*56)/2 cs)[ [ 123+456 ]/2
+" <div>Yo!*</div> cst<p> <p>Yo!</p>
+"
+" *ys* takes an valid Vim motion or text object as the first object, and wraps
+" it using the second argument as with |cs|. (Unfortunately there's no good
+" mnemonic for "ys").
+"
+" Old text Command New text ~
+" Hello w*orld! ysiw) Hello (world)!
+"
+" As a special case, *yss* operates on the current line, ignoring leading
+" whitespace.
+"
+" Old text Command New text ~
+" Hello w*orld! yssB {Hello world!}
+"
+" There is also *yS* and *ySS* which indent the surrounded text and place it
+" on a line of its own.
+"
+" In visual mode, a simple "s" with an argument wraps the selection. This is
+" referred to as the *vs* mapping, although ordinarily there will be
+" additional keystrokes between the v and s. In linewise visual mode, the
+" surroundings are placed on separate lines. In blockwise visual mode, each
+" line is surrounded.
+"
+" An "S" in visual mode (*vS*) behaves similarly but always places the
+" surroundings on separate lines. Additionally, the surrounded text is
+" indented. In blockwise visual mode, using "S" instead of "s" instead skips
+" trailing whitespace.
+"
+" Note that "s" and "S" already have valid meaning in visual mode, but it is
+" identical to "c". If you have muscle memory for "s" and would like to use a
+" different key, add your own mapping and the existing one will be disabled.
+" >
+" vmap <Leader>s <Plug>Vsurround
+" vmap <Leader>S <Plug>VSurround
+" <
+" Finally, there is an experimental insert mode mapping on <C-S>. Beware that
+" this won't work on terminals with flow control (if you accidentally freeze
+" your terminal, use <C-Q> to unfreeze it). The mapping inserts the specified
+" surroundings and puts the cursor between them. If, immediately after <C-S>
+" and before the replacement, a second <C-S> or carriage return is pressed,
+" the prefix, cursor, and suffix will be placed on three separate lines. If
+" this is a common use case you can add a mapping for it as well.
+" >
+" imap <C-Z> <Plug>Isurround<CR>
+" <
+" Targets: *surround-targets*
+"
+" The |ds| and |cs| commands both take a target as their first argument. The
+" possible targets are based closely on the |text-objects| provided by Vim.
+" In order for a target to work, the corresponding text object must be
+" supported in the version of Vim used (Vim 7 adds several text objects, and
+" thus is highly recommended). All targets are currently just one character.
+"
+" Eight punctuation marks, (, ), {, }, [, ], <, and >, represent themselves
+" and their counterpart. If the opening mark is used, contained whitespace is
+" also trimmed. The targets b, B, r, and a are aliases for ), }, ], and >
+" (the first two mirror Vim; the second two are completely arbitrary and
+" subject to change).
+"
+" Three quote marks, ', ", `, represent themselves, in pairs. They are only
+" searched for on the current line.
+"
+" A t is a pair of HTML or XML tags. See |tag-blocks| for details. Remember
+" that you can specify a numerical argument if you want to get to a tag other
+" than the innermost one.
+"
+" The letters w, W, and s correspond to a |word|, a |WORD|, and a |sentence|,
+" respectively. These are special in that they have nothing do delete, and
+" used with |ds| they are a no-op. With |cs|, one could consider them a
+" slight shortcut for ysi (cswb == ysiwb, more or less).
+"
+" A p represents a |paragraph|. This behaves similarly to w, W, and s above;
+" however, newlines are sometimes added and/or removed.
+"
+" Replacements: *surround-replacements*
+"
+" A replacement argument is a single character, and is required by |cs|, |ys|,
+" and |vs|. Undefined replacement characters (with the exception of
+" alphabetic characters) default to placing themselves at the beginning and
+" end of the destination, which can be useful for characters like / and |.
+"
+" If either ), }, ], or > is used, the text is wrapped in the appropriate
+" pair of characters. Similar behavior can be found with (, {, and [ (but not
+" <), which append an additional space to the inside. Like with the targets
+" above, b, B, r, and a are aliases for ), }, ], and >.
+"
+" If t or < is used, Vim prompts for an HTML/XML tag to insert. You may
+" specify attributes here and they will be stripped from the closing tag.
+" End your input by pressing <CR> or >. As an experimental feature, if , or
+" <C-T> is used, the tags will appear on lines by themselves.
+"
+" An experimental replacement of a LaTeX environment is provided on \ and l.
+" The name of the environment and any arguments will be input from a prompt.
+" The following shows the resulting environment from csp\tabular}{lc<CR>
+" >
+" \begin{tabular}{lc}
+" \end{tabular}
+" <
+" Customizing: *surround-customizing*
+"
+" The following adds a potential replacement on "-" (ASCII 45) in PHP files.
+" (To determine the ASCII code to use, :echo char2nr("-")). The carriage
+" return will be replaced by the original text.
+" >
+" autocmd FileType php let b:surround_45 = "<?php \r ?>"
+" <
+" This can be used in a PHP file as in the following example.
+"
+" Old text Command New text ~
+" print "Hello *world!" yss- <?php print "Hello world!" ?>
+"
+" Additionally, one can use a global variable for globally available
+" replacements.
+" >
+" let g:surround_45 = "<% \r %>"
+" let g:surround_61 = "<%= \r %>"
+" <
+" Issues: *surround-issues*
+"
+" Vim could potentially get confused when deleting/changing occurs at the very
+" end of the line. Please report any repeatable instances of this.
+"
+" Do we need to use |inputsave()|/|inputrestore()| with the tag replacement?
+"
+" Customization isn't very flexible. Need a system that allows for prompting,
+" like with HTML tags and LaTeX environments.
+"
+" Indenting is handled haphazardly. Need to decide the most appropriate
+" behavior and implement it. Right now one can do :let b:surround_indent = 1
+" (or the global equivalent) to enable automatic re-indenting by Vim via |=|;
+" should this be the default?
+"
+" It would be nice if |.| would work to repeat an operation.
+
+" ============================================================================
+
+" Exit quickly when:
+" - this plugin was already loaded (or disabled)
+" - when 'compatible' is set
+if (exists("g:loaded_surround") && g:loaded_surround) || &cp
+ finish
+endif
+let g:loaded_surround = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+function! SurroundHelp() " {{{1
+ if !isdirectory(s:dir."/doc/") && exists("*mkdir")
+ call mkdir(s:dir."/doc/")
+ endif
+ let old_hidden = &hidden
+ let old_cpo = &cpo
+ set hidden
+ set cpo&vim
+ exe "split ".fnamemodify(s:dir."/doc/surround.txt",":~")
+ setlocal noai modifiable noreadonly
+ %d_
+ exe "0r ".fnamemodify(s:file,":~")
+ norm "_d}}"_dG
+ a
+ vim:tw=78:ts=8:ft=help:norl:
+.
+ 1d_
+ %s/^" \=//
+ silent! %s/^\(\u\l\+\):\(\s\+\*\)/\U\1 \2/
+ setlocal noreadonly
+ write
+ bwipe!
+ let &hidden = old_hidden
+ let &cpo = old_cpo
+ exe "helptags ".fnamemodify(s:dir."/doc",":~")
+ help surround
+endfunction
+let s:file = expand("<sfile>:p")
+let s:dir = expand("<sfile>:p:h:h") " }}}1
+
+" Input functions {{{1
+
+function! s:getchar()
+ let c = getchar()
+ if c =~ '^\d\+$'
+ let c = nr2char(c)
+ endif
+ return c
+endfunction
+
+function! s:inputtarget()
+ let c = s:getchar()
+ while c =~ '^\d\+$'
+ let c = c . s:getchar()
+ endwhile
+ if c == " "
+ let c = c . s:getchar()
+ endif
+ if c =~ "\<Esc>\|\<C-C>\|\0"
+ return ""
+ else
+ return c
+ endif
+endfunction
+
+function! s:inputreplacement()
+ "echo '-- SURROUND --'
+ let c = s:getchar()
+ if c == " "
+ let c = c . s:getchar()
+ endif
+ if c =~ "\<Esc>" || c =~ "\<C-C>"
+ return ""
+ else
+ return c
+ endif
+endfunction
+
+function! s:beep()
+ exe "norm! \<Esc>"
+ return ""
+endfunction
+
+function! s:redraw()
+ redraw
+ return ""
+endfunction
+
+" }}}1
+
+" Wrapping functions {{{1
+
+function! s:extractbefore(str)
+ if a:str =~ '\r'
+ return matchstr(a:str,'.*\ze\r')
+ else
+ return matchstr(a:str,'.*\ze\n')
+ endif
+endfunction
+
+function! s:extractafter(str)
+ if a:str =~ '\r'
+ return matchstr(a:str,'\r\zs.*')
+ else
+ return matchstr(a:str,'\n\zs.*')
+ endif
+endfunction
+
+function! s:repeat(str,count)
+ let cnt = a:count
+ let str = ""
+ while cnt > 0
+ let str = str . a:str
+ let cnt = cnt - 1
+ endwhile
+ return str
+endfunction
+
+function! s:fixindent(str,spc)
+ let str = substitute(a:str,'\t',s:repeat(' ',&sw),'g')
+ let spc = substitute(a:spc,'\t',s:repeat(' ',&sw),'g')
+ let str = substitute(str,'\(\n\|\%^\).\@=','\1'.spc,'g')
+ if ! &et
+ let str = substitute(str,'\s\{'.&ts.'\}',"\t",'g')
+ endif
+ return str
+endfunction
+
+function! s:wrap(string,char,type,...)
+ let keeper = a:string
+ let newchar = a:char
+ let type = a:type
+ let linemode = type ==# 'V' ? 1 : 0
+ let special = a:0 ? a:1 : 0
+ let before = ""
+ let after = ""
+ if type == "V"
+ let initspaces = matchstr(keeper,'\%^\s*')
+ else
+ let initspaces = matchstr(getline('.'),'\%^\s*')
+ endif
+ " Duplicate b's are just placeholders (removed)
+ let pairs = "b()B{}r[]a<>"
+ let extraspace = ""
+ if newchar =~ '^ '
+ let newchar = strpart(newchar,1)
+ let extraspace = ' '
+ endif
+ let idx = stridx(pairs,newchar)
+ if exists("b:surround_".char2nr(newchar))
+ let before = s:extractbefore(b:surround_{char2nr(newchar)})
+ let after = s:extractafter(b:surround_{char2nr(newchar)})
+ elseif exists("g:surround_".char2nr(newchar))
+ let before = s:extractbefore(g:surround_{char2nr(newchar)})
+ let after = s:extractafter(g:surround_{char2nr(newchar)})
+ elseif newchar ==# "p"
+ let before = "\n"
+ let after = "\n\n"
+ elseif newchar =~# "[tT\<C-T><,]"
+ "let dounmapr = 0
+ let dounmapb = 0
+ "if !mapcheck("<CR>","c")
+ "let dounmapr = 1
+ "cnoremap <CR> ><CR>
+ "endif
+ if !mapcheck(">","c")
+ let dounmapb= 1
+ cnoremap > ><CR>
+ endif
+ let default = ""
+ if newchar ==# "T"
+ if !exists("s:lastdel")
+ let s:lastdel = ""
+ endif
+ let default = matchstr(s:lastdel,'<\zs.\{-\}\ze>')
+ endif
+ let tag = input("<",default)
+ echo "<".substitute(tag,'>*$','>','')
+ "if dounmapr
+ "silent! cunmap <CR>
+ "endif
+ if dounmapb
+ silent! cunmap >
+ endif
+ if tag != ""
+ let tag = substitute(tag,'>*$','','')
+ let before = "<".tag.">"
+ let after = "</".substitute(tag," .*",'','').">"
+ if newchar == "\<C-T>" || newchar == ","
+ if type ==# "v" || type ==# "V"
+ let before = before . "\n\t"
+ endif
+ if type ==# "v"
+ let after = "\n". after
+ endif
+ endif
+ endif
+ elseif newchar ==# 'l' || newchar == '\'
+ " LaTeX
+ let env = input('\begin{')
+ let env = '{' . env
+ let env = env . s:closematch(env)
+ echo '\begin'.env
+ if env != ""
+ let before = '\begin'.env
+ let after = '\end'.matchstr(env,'[^}]*').'}'
+ endif
+ "if type ==# 'v' || type ==# 'V'
+ "let before = before ."\n\t"
+ "endif
+ "if type ==# 'v'
+ "let after = "\n".initspaces.after
+ "endif
+ elseif newchar ==# 'f' || newchar ==# 'F'
+ let fnc = input('function: ')
+ if fnc != ""
+ let before = substitute(fnc,'($','','').'('
+ let after = ')'
+ if newchar ==# 'F'
+ let before = before . ' '
+ let after = ' ' . after
+ endif
+ endif
+ elseif idx >= 0
+ let spc = (idx % 3) == 1 ? " " : ""
+ let idx = idx / 3 * 3
+ let before = strpart(pairs,idx+1,1) . spc
+ let after = spc . strpart(pairs,idx+2,1)
+ elseif newchar !~ '\a'
+ let before = newchar
+ let after = newchar
+ else
+ let before = ''
+ let after = ''
+ endif
+ "let before = substitute(before,'\n','\n'.initspaces,'g')
+ let after = substitute(after ,'\n','\n'.initspaces,'g')
+ "let after = substitute(after,"\n\\s*\<C-U>\\s*",'\n','g')
+ if type ==# 'V' || (special && type ==# "v")
+ let before = substitute(before,' \+$','','')
+ let after = substitute(after ,'^ \+','','')
+ if after !~ '^\n'
+ let after = initspaces.after
+ endif
+ if keeper !~ '\n$' && after !~ '^\n'
+ let keeper = keeper . "\n"
+ endif
+ if before !~ '\n\s*$'
+ let before = before . "\n"
+ if special
+ let before = before . "\t"
+ endif
+ endif
+ endif
+ if type ==# 'V'
+ let before = initspaces.before
+ endif
+ if before =~ '\n\s*\%$'
+ if type ==# 'v'
+ let keeper = initspaces.keeper
+ endif
+ let padding = matchstr(before,'\n\zs\s\+\%$')
+ let before = substitute(before,'\n\s\+\%$','\n','')
+ let keeper = s:fixindent(keeper,padding)
+ endif
+ if type ==# 'V'
+ let keeper = before.keeper.after
+ elseif type =~ "^\<C-V>"
+ " Really we should be iterating over the buffer
+ let repl = substitute(before,'[\\~]','\\&','g').'\1'.substitute(after,'[\\~]','\\&','g')
+ let repl = substitute(repl,'\n',' ','g')
+ let keeper = substitute(keeper."\n",'\(.\{-\}\)\('.(special ? '\s\{-\}' : '').'\n\)',repl.'\n','g')
+ let keeper = substitute(keeper,'\n\%$','','')
+ else
+ let keeper = before.extraspace.keeper.extraspace.after
+ endif
+ return keeper
+endfunction
+
+function! s:wrapreg(reg,char,...)
+ let orig = getreg(a:reg)
+ let type = substitute(getregtype(a:reg),'\d\+$','','')
+ let special = a:0 ? a:1 : 0
+ let new = s:wrap(orig,a:char,type,special)
+ call setreg(a:reg,new,type)
+endfunction
+" }}}1
+
+function! s:insert(...) " {{{1
+ " Optional argument causes the result to appear on 3 lines, not 1
+ "call inputsave()
+ let linemode = a:0 ? a:1 : 0
+ let char = s:inputreplacement()
+ while char == "\<CR>" || char == "\<C-S>"
+ " TODO: use total count for additional blank lines
+ let linemode = linemode + 1
+ let char = s:inputreplacement()
+ endwhile
+ "call inputrestore()
+ if char == ""
+ return ""
+ endif
+ "call inputsave()
+ let reg_save = @@
+ call setreg('"',"\r",'v')
+ call s:wrapreg('"',char,linemode)
+ "if linemode
+ "call setreg('"',substitute(getreg('"'),'^\s\+','',''),'c')
+ "endif
+ if col('.') > col('$')
+ norm! p`]
+ else
+ norm! P`]
+ endif
+ call search('\r','bW')
+ let @@ = reg_save
+ return "\<Del>"
+endfunction " }}}1
+
+function! s:reindent() " {{{1
+ if (exists("b:surround_indent") || exists("g:surround_indent"))
+ silent norm! '[=']
+ endif
+endfunction " }}}1
+
+function! s:dosurround(...) " {{{1
+ let scount = v:count1
+ let char = (a:0 ? a:1 : s:inputtarget())
+ let spc = ""
+ if char =~ '^\d\+'
+ let scount = scount * matchstr(char,'^\d\+')
+ let char = substitute(char,'^\d\+','','')
+ endif
+ if char =~ '^ '
+ let char = strpart(char,1)
+ let spc = 1
+ endif
+ if char == 'a'
+ let char = '>'
+ endif
+ if char == 'r'
+ let char = ']'
+ endif
+ let newchar = ""
+ if a:0 > 1
+ let newchar = a:2
+ if newchar == "\<Esc>" || newchar == "\<C-C>" || newchar == ""
+ return s:beep()
+ endif
+ endif
+ let append = ""
+ let original = getreg('"')
+ let otype = getregtype('"')
+ call setreg('"',"")
+ exe "norm d".(scount==1 ? "": scount)."i".char
+ "exe "norm vi".char."d"
+ let keeper = getreg('"')
+ let okeeper = keeper " for reindent below
+ if keeper == ""
+ call setreg('"',original,otype)
+ return ""
+ endif
+ let oldline = getline('.')
+ let oldlnum = line('.')
+ if char ==# "p"
+ "let append = matchstr(keeper,'\n*\%$')
+ "let keeper = substitute(keeper,'\n*\%$','','')
+ call setreg('"','','V')
+ elseif char ==# "s" || char ==# "w" || char ==# "W"
+ " Do nothing
+ call setreg('"','')
+ elseif char =~ "[\"'`]"
+ exe "norm! i \<Esc>d2i".char
+ call setreg('"',substitute(getreg('"'),' ','',''))
+ else
+ exe "norm! da".char
+ endif
+ let removed = getreg('"')
+ let rem2 = substitute(removed,'\n.*','','')
+ let oldhead = strpart(oldline,0,strlen(oldline)-strlen(rem2))
+ let oldtail = strpart(oldline, strlen(oldline)-strlen(rem2))
+ let regtype = getregtype('"')
+ if char == 'p'
+ let regtype = "V"
+ endif
+ if char =~# '[\[({<T]' || spc
+ let keeper = substitute(keeper,'^\s\+','','')
+ let keeper = substitute(keeper,'\s\+$','','')
+ endif
+ if col("']") == col("$") && col('.') + 1 == col('$')
+ "let keeper = substitute(keeper,'^\n\s*','','')
+ "let keeper = substitute(keeper,'\n\s*$','','')
+ if oldhead =~# '^\s*$' && a:0 < 2
+ "let keeper = substitute(keeper,oldhead.'\%$','','')
+ let keeper = substitute(keeper,'\%^\n'.oldhead.'\(\s*.\{-\}\)\n\s*\%$','\1','')
+ endif
+ let pcmd = "p"
+ else
+ if oldhead == "" && a:0 < 2
+ "let keeper = substitute(keeper,'\%^\n\(.*\)\n\%$','\1','')
+ endif
+ let pcmd = "P"
+ endif
+ if line('.') < oldlnum && regtype ==# "V"
+ let pcmd = "p"
+ endif
+ call setreg('"',keeper,regtype)
+ if newchar != ""
+ call s:wrapreg('"',newchar)
+ endif
+ silent exe "norm! ".pcmd.'`['
+ if removed =~ '\n' || okeeper =~ '\n' || getreg('"') =~ '\n'
+ call s:reindent()
+ else
+ endif
+ if getline('.') =~ '^\s\+$' && keeper =~ '^\s*\n'
+ silent norm! cc
+ endif
+ call setreg('"',removed,regtype)
+ let s:lastdel = removed
+endfunction " }}}1
+
+function! s:changesurround() " {{{1
+ let a = s:inputtarget()
+ if a == ""
+ return s:beep()
+ endif
+ let b = s:inputreplacement()
+ if b == ""
+ return s:beep()
+ endif
+ call s:dosurround(a,b)
+endfunction " }}}1
+
+function! s:opfunc(type,...) " {{{1
+ let char = s:inputreplacement()
+ if char == ""
+ return s:beep()
+ endif
+ let reg = '"'
+ let sel_save = &selection
+ let &selection = "inclusive"
+ let reg_save = getreg(reg)
+ let reg_type = getregtype(reg)
+ let type = a:type
+ if a:type == "char"
+ silent exe 'norm! `[v`]"'.reg."y"
+ let type = 'v'
+ elseif a:type == "line"
+ silent exe 'norm! `[V`]"'.reg."y"
+ let type = 'V'
+ elseif a:type ==# "v" || a:type ==# "V" || a:type ==# "\<C-V>"
+ silent exe 'norm! gv"'.reg."y"
+ elseif a:type =~ '^\d\+$'
+ silent exe 'norm! ^v'.a:type.'$h"'.reg.'y'
+ else
+ let &selection = sel_save
+ return s:beep()
+ endif
+ let keeper = getreg(reg)
+ if type == "v"
+ let append = matchstr(keeper,'\s*$')
+ let keeper = substitute(keeper,'\s*$','','')
+ endif
+ call setreg(reg,keeper,type)
+ call s:wrapreg(reg,char,a:0)
+ if type == "v" && append != ""
+ call setreg(reg,append,"ac")
+ endif
+ silent exe 'norm! gv'.(reg == '"' ? '' : '"' . reg).'p`['
+ if type == 'V' || (getreg(reg) =~ '\n' && type == 'v')
+ call s:reindent()
+ endif
+ call setreg(reg,reg_save,reg_type)
+ let &selection = sel_save
+endfunction
+
+function! s:opfunc2(arg)
+ call s:opfunc(a:arg,1)
+endfunction " }}}1
+
+function! s:closematch(str) " {{{1
+ " Close an open (, {, [, or < on the command line.
+ let tail = matchstr(a:str,'.[^\[\](){}<>]*$')
+ if tail =~ '^\[.\+'
+ return "]"
+ elseif tail =~ '^(.\+'
+ return ")"
+ elseif tail =~ '^{.\+'
+ return "}"
+ elseif tail =~ '^<.+'
+ return ">"
+ else
+ return ""
+ endif
+endfunction " }}}1
+
+nnoremap <silent> <Plug>Dsurround :<C-U>call <SID>dosurround(<SID>inputtarget())<CR>
+nnoremap <silent> <Plug>Csurround :<C-U>call <SID>changesurround()<CR>
+nnoremap <silent> <Plug>Yssurround :<C-U>call <SID>opfunc(v:count1)<CR>
+nnoremap <silent> <Plug>YSsurround :<C-U>call <SID>opfunc2(v:count1)<CR>
+" <C-U> discards the numerical argument but there's not much we can do with it
+nnoremap <silent> <Plug>Ysurround :<C-U>set opfunc=<SID>opfunc<CR>g@
+nnoremap <silent> <Plug>YSurround :<C-U>set opfunc=<SID>opfunc2<CR>g@
+vnoremap <silent> <Plug>Vsurround :<C-U>call <SID>opfunc(visualmode())<CR>
+vnoremap <silent> <Plug>VSurround :<C-U>call <SID>opfunc2(visualmode())<CR>
+inoremap <silent> <Plug>Isurround <C-R>=<SID>insert()<CR>
+inoremap <silent> <Plug>ISurround <C-R>=<SID>insert(1)<CR>
+
+if !exists("g:surround_no_mappings") || ! g:surround_no_mappings
+ nmap ds <Plug>Dsurround
+ nmap cs <Plug>Csurround
+ nmap ys <Plug>Ysurround
+ nmap yS <Plug>YSurround
+ nmap yss <Plug>Yssurround
+ nmap ySs <Plug>YSsurround
+ nmap ySS <Plug>YSsurround
+ if !hasmapto("<Plug>Vsurround","v")
+ vmap s <Plug>Vsurround
+ endif
+ if !hasmapto("<Plug>VSurround","v")
+ vmap S <Plug>VSurround
+ endif
+ if !hasmapto("<Plug>Isurround","i") && !mapcheck("<C-S>","i")
+ imap <C-S> <Plug>Isurround
+ endif
+ "Implemented internally instead
+ "imap <C-S><C-S> <Plug>ISurround
+endif
+
+let &cpo = s:cpo_save
+
+" vim:set ft=vim sw=4 sts=4 et:
diff --git a/.vim/plugin/tEchoPair.vim b/.vim/plugin/tEchoPair.vim
new file mode 100644
index 0000000..b1f3c19
--- /dev/null
+++ b/.vim/plugin/tEchoPair.vim
@@ -0,0 +1,369 @@
+" tEchoPair.vim
+" @Author: Thomas Link (mailto:samul AT web de?subject=vim-tEchoPair)
+" @Website: http://www.vim.org/account/profile.php?user_id=4037
+" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
+" @Created: 2007-03-24.
+" @Last Change: 2007-03-27.
+" @Revision: 0.1.175
+
+if &cp || exists("loaded_techopair")
+ finish
+endif
+let loaded_techopair = 1
+
+" if !exists('g:tEchoPairStyle') | let g:tEchoPairStyle = 'inner' | endif
+if !exists('g:tEchoPairStyle') | let g:tEchoPairStyle = 'indicate' | endif
+if !exists('g:tEchoPairInstall') | let g:tEchoPairInstall = [] | endif
+
+if !exists('g:tEchoPairIndicateOpen') | let g:tEchoPairIndicateOpen = ' <<<&' | endif
+if !exists('g:tEchoPairIndicateClose') | let g:tEchoPairIndicateClose = '&>>> ' | endif
+if !exists('g:tEchoPairIndicateCursor') | let g:tEchoPairIndicateCursor = ' <<<&>>> ' | endif
+
+if !exists('g:tEchoPairs')
+ " \ 'viki': [
+ " \ 'fold;-1',
+ " \ ],
+ let g:tEchoPairs = {
+ \ 'ruby': [
+ \ ['(', ')'],
+ \ ['{', '}'],
+ \ ['[', ']'],
+ \ ['\<\(module\|class\|def\|begin\|do\|if\|unless\)\>', '', '\<end\>', 'TEchoSkipRuby()'],
+ \ ],
+ \ 'vim': [
+ \ ['(', ')'],
+ \ ['{', '}'],
+ \ ['[', ']'],
+ \ ['\<for\>', '\<endfor\?\>'],
+ \ ['\<wh\(i\(l\(e\)\?\)\?\)\?\>', '\<endw\(h\(i\(l\(e\)\?\)\?\)\?\)\?\>'],
+ \ ['\<if\>', '\<end\(i\(f\)\?\)\?\>'],
+ \ ['\<try\>', '\<endt\(r\(y\)\?\)\?\>'],
+ \ ['\<fu\(n\(c\(tion\)\?\)\?\)\?\>', '\<endf\(u\(n\(c\(tion\)\?\)\?\)\?\)\?\>'],
+ \ ]
+ \ }
+endif
+
+if !exists('g:tEchoPairStyle_inner')
+ let g:tEchoPairStyle_inner = ['lisp', 'scheme']
+endif
+
+if !exists('g:tEchoPairStyle_indicate')
+ let g:tEchoPairStyle_indicate = []
+endif
+
+if !exists('g:tEchoPairStyles')
+endif
+
+let s:tEchoPairStyles = []
+
+fun! TEchoCollectStyles()
+ redir => vars
+ silent let
+ redir END
+ let s:tEchoPairStyles = split(vars, '\n')
+ call filter(s:tEchoPairStyles, 'v:val =~ ''^tEchoPairStyle_''')
+ call map(s:tEchoPairStyles, 'matchstr(v:val, ''^tEchoPairStyle_\zs\S\+'')')
+endf
+
+" fun! TEchoPair(backwards, type, ?what, ?[args])
+fun! TEchoPair(backwards, type, ...)
+ let lz = &lazyredraw
+ set lazyredraw
+ try
+ let w0 = line('w0')
+ let l0 = line('.')
+ let c0 = col('.')
+ " let c0 = col['.']
+ let pos = getpos('.')
+ let what = a:0 >= 1 ? a:1 : '.'
+ if a:type == 'rx'
+ let args0 = a:0 >= 2 ? a:2 : []
+ let args = []
+ " call add(args, '\V'. escape(get(args0, 0, '('), '\'))
+ call add(args, '\V'. get(args0, 0, '('))
+ " let m = escape(get(args0, 1, ''), '\')
+ let m = get(args0, 1, '')
+ call add(args, empty(m) ? m : '\V'.m)
+ " call add(args, '\V'. escape(get(args0, 2, ')'), '\'))
+ call add(args, '\V'. get(args0, 2, ')'))
+ call add(args, a:backwards ? 'bW' : 'W')
+ let args += args0[3:-1]
+ echom "DBG searchpairs: ". string(args)
+ " echom "DBG TEchoPair: ". string(args)
+ let what = a:backwards ? args[0] : args[2]
+ let this = a:backwards ? args[2] : args[0]
+ " echom 'DBG '. what .' '. a:backwards .' '. expand('<cword>') .' '. (expand('<cword>')=~ '\V\^'. what .'\$')
+ if a:backwards
+ if expand('<cword>') =~ '\V\^'. this .'\$'
+ call search('\V'. this, 'cb', l0)
+ endif
+ else
+ if expand('<cword>') =~ '\V\^'. this .'\$'
+ call search('\V'. this, 'c', l0)
+ endif
+ endif
+ call call('searchpair', args)
+ elseif a:type =~ '^fold'
+ let fold_args = split(a:type, ';')
+ if a:backwards
+ call s:Normal('[z', 'silent!')
+ else
+ call s:Normal(']z', 'silent!')
+ endif
+ let lineshift = get(fold_args, a:backwards ? 1 : 2, 0)
+ if lineshift > 0
+ call s:Normal(lineshift .'j', 'silent!')
+ elseif lineshift < 0
+ call s:Normal((-lineshift) .'k', 'silent!')
+ endif
+ endif
+ " else
+ " if a:backwards
+ " exec 'norm! ['. a:what
+ " else
+ " exec 'norm! ]'. a:what
+ " endif
+ " endif
+ let l1 = line('.')
+ let c1 = col('.')
+ if l1 != l0
+ if a:backwards
+ let c0 = col('$')
+ else
+ " let c0 = matchend(getline(l1), '^\s*') - 1
+ let c0 = matchend(getline(l1), '^\s*')
+ endif
+ endif
+ let text = getline(l1)
+ if empty(s:tEchoPairStyles)
+ call TEchoCollectStyles()
+ endif
+ if exists('b:tEchoPairStyle')
+ let style = b:tEchoPairStyle
+ else
+ let style = g:tEchoPairStyle
+ for s in s:tEchoPairStyles
+ if index(g:tEchoPairStyle_{s}, &filetype) != -1
+ let style = s
+ endif
+ endfor
+ endif
+ " if l1 < l0 || c1 < c0
+ if a:backwards
+ let text = TEchoPair_open_{style}(what, text, c0, l0, c1, l1)
+ else
+ let text = TEchoPair_close_{style}(what, text, c0, l0, c1, l1)
+ endif
+ if &debug != ''
+ echo text . ' '. a:backwards .':'. c0.'x'.l0.'-'.c1.'x'.l1
+ else
+ echo text
+ endif
+ let b:tEchoPair = text
+ call s:Normal(w0 .'zt')
+ call setpos('.', pos)
+ " return a:what
+ finally
+ let &lz = lz
+ endtry
+endf
+
+fun! s:Normal(cmd, ...)
+ let p = a:0 >= 1 ? a:1 : ''
+ let m = mode()
+ if m ==? 's' || m == ''
+ exec p .' norm! '. a:cmd
+ else
+ exec p .'norm! '. a:cmd
+ endif
+endf
+
+fun! TEchoPair_open_inner(what, text, c0, l0, c1, l1)
+ return strpart(a:text, a:c1 - 1, a:c0 - a:c1)
+endf
+
+fun! TEchoPair_close_inner(what, text, c0, l0, c1, l1)
+ return strpart(a:text, a:c0, a:c1 - a:c0)
+endf
+
+fun! TEchoPair_open_indicate(what, text, c0, l0, c1, l1)
+ let text = s:IndicateCursor(a:text, a:c0, a:l0, a:c1, a:l1)
+ " let text = a:l1.': '. substitute(text, '\V\%'. a:c1 .'c'. a:what, ' <<<&<<< ', '')
+ let text = a:l1.': '. substitute(text, '\V\%'. a:c1 .'c'. a:what, g:tEchoPairIndicateOpen, '')
+ let cmdh = s:GetCmdHeight()
+ if cmdh > 1
+ let acc = [text]
+ for i in range(a:l1 + 1, a:l1 + cmdh - 1)
+ if i > a:l0
+ break
+ endif
+ " call add(acc, i.': '. s:IndicateCursor(getline(i), a:c0, a:l0, a:c1, i))
+ call add(acc, i.': '. getline(i))
+ endfor
+ let text = join(acc, "\<c-j>")
+ endif
+ return text
+endf
+
+fun! TEchoPair_close_indicate(what, text, c0, l0, c1, l1)
+ " let text = substitute(a:text, '\V\%'. a:c1 .'c'. a:what, ' >>>&>>> ', '')
+ let text = substitute(a:text, '\V\%'. a:c1 .'c'. a:what, g:tEchoPairIndicateClose, '')
+ let text = a:l1.': '. s:IndicateCursor(text, a:c0, a:l0, a:c1, a:l1)
+ let cmdh = s:GetCmdHeight()
+ if cmdh > 1
+ let acc = [text]
+ for i in range(a:l1 - 1, a:l1 - cmdh + 1, -1)
+ if i < a:l0
+ break
+ endif
+ " call insert(acc, i.': '. s:IndicateCursor(getline(i), a:c0, a:l0, a:c1, i))
+ call insert(acc, i.': '. getline(i))
+ endfor
+ let text = join(acc, "\<c-j>")
+ endif
+ return text
+endf
+
+fun! s:IndicateCursor(text, c0, l0, c1, l1)
+ if a:l0 == a:l1
+ return substitute(a:text, '\%'. a:c0 .'c.', g:tEchoPairIndicateCursor, '')
+ else
+ return a:text
+ endif
+endf
+
+fun! s:GetCmdHeight()
+ let ch = &cmdheight
+ if mode() == 'i' && &showmode
+ let ch -= 1
+ endif
+ return ch
+endf
+
+fun! TEchoSkipRuby()
+ let n = synIDattr(synID(line('.'), col('.'), 1), 'name')
+ return (n =~ '^ruby\(Comment\|String\)$')
+endf
+
+fun! TEchoPairReset()
+ augroup TEchoPair
+ au!
+ augroup END
+endf
+" call TEchoPairReset()
+
+fun! TEchoPairInstall(pattern, ...)
+ augroup TEchoPair
+ if a:0 >= 1
+ let list = a:1
+ elseif has_key(g:tEchoPairs, &filetype)
+ let list = g:tEchoPairs[&filetype]
+ else
+ " [a b]
+ " [['(', ')'], ['{', '}']]
+ let list = split(&matchpairs, ',')
+ call map(list, 'split(v:val, ":")')
+ endif
+ for i in list
+ if type(i) == 1
+ if i =~ '^fold'
+ exec 'au CursorMoved '. a:pattern .' if foldclosed(line(".")) == -1 '.
+ \ ' | keepjumps call TEchoPair(1, '. string(i) .') | endif'
+ endif
+ elseif type(i) == 3
+ if len(i) == 2
+ let [io, ie] = i
+ call insert(i, '', 1)
+ let im = ''
+ else
+ let [io, im, ie; rest] = i
+ endif
+ if len(io) == 1
+ let condo = 'getline(".")[col(".") - 1] == '. string(io)
+ else
+ " let condo = 'strpart(getline("."), col(".") - 1) =~ ''\V\^'''. string(io)
+ let condo = 'expand("<cword>") =~ ''\V\^'. io .'\$'''
+ endif
+ if len(ie) == 1
+ let conde = 'getline(".")[col(".") - 1] == '. string(ie)
+ else
+ " let conde = 'strpart(getline("."), col(".") - 1) =~ ''\V\^'''. string(io)
+ let conde = 'expand("<cword>") =~ ''\V\^'. ie .'\$'''
+ endif
+ exec 'au CursorMoved '. a:pattern .' if '. condo .
+ \ ' | keepjumps call TEchoPair(0, "rx", '. string(ie) .', '. string(i) .') | endif'
+ exec 'au CursorMoved '. a:pattern .' if '. conde .
+ \ ' | keepjumps call TEchoPair(1, "rx", '. string(io) .', '. string(i) .') | endif'
+ exec 'au CursorMovedI '. a:pattern .' if '. condo .
+ \ ' | keepjumps call TEchoPair(0, "rx", '. string(ie) .', '. string(i) .') | endif'
+ exec 'au CursorMovedI '. a:pattern .' if '. conde .
+ \ ' | keepjumps call TEchoPair(1, "rx", '. string(io) .', '. string(i) .') | endif'
+ endif
+ endfor
+ augroup END
+endf
+
+" command! TEchoPairInstallGlobal call TEchoPairInstall('*')
+command! TEchoPairInstallBuffer call TEchoPairInstall(expand('%:p'))
+
+for ft in g:tEchoPairInstall
+ exec 'au Filetype '. ft .' TEchoPairInstallBuffer'
+endfor
+
+
+finish
+____________________________________________________________________
+
+tEchoPair.vim -- Display matching parenthesis in the echo area
+
+
+VIM is an excellent editor but in comparison too e.g. emacs it lacks a
+minor feature that makes editing lisp code somewhat cumbersome. While
+VIM can highlight the matching parenthesis, this doesn't help much with
+long functions when the matching parenthesis is off the screen.
+Emacs users are better off in such a situation, since emace displays the
+matching line in the echo area.
+
+This plugin tries to mimic Emacs's behaviour.
+
+
+In order to enable this plugin, you choose between the following
+options:
+ TEchoPairInstallBuffer ... enable for the current buffer
+
+ call TEchoPairInstall('*') ... enable globally
+
+ let g:tEchoPairInstall = ['lisp', 'scheme'] ... enable for certain
+ filetypes
+
+
+Currently, there are the following display modes:
+ indicate ... Display the whole line and highlight the matching
+ parenthesis. If 'cmdheight' is greater than 1, additional lines
+ are display.
+
+ inner ... Display the inner text Emacs-style.
+
+In order to see the matching parenthesis when 'showmode' is on, set
+'cmdheight' to something greater than 1.
+
+You can select the preferred display mode on a filetype basis, by
+setting g:tEchoPairStyle_{STYLE}.
+
+Example:
+ let g:tEchoPairStyle_inner = ['lisp', 'scheme']
+ let g:tEchoPairStyle_indicate = ['java']
+
+
+The pairs are usually deduced from the value of 'matchpairs' unless
+there is an entry for the current buffer's filetype in g:tEchoPairs. For
+the following filetypes custom pairs are pre-defined:
+ - ruby
+ - vim
+
+
+CHANGES
+
+0.1:
+Initial release
+
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(<f-args>)
+ command! -nargs=+ -complete=dir TlistAddFilesRecursive
+ \ call s:Tlist_Add_Files_Recursive(<f-args>)
+ 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(<f-args>)
+ command! -nargs=* -complete=buffer TlistShowTag
+ \ echo Tlist_Get_Tagname_By_Line(<f-args>)
+ command! -nargs=* -complete=file TlistSessionLoad
+ \ call s:Tlist_Session_Load(<q-args>)
+ command! -nargs=* -complete=file TlistSessionSave
+ \ call s:Tlist_Session_Save(<q-args>)
+ 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(<q-args>)
+ 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 <SID>xx <SID>xx
+ let s:tlist_sid = substitute(maparg('<SID>xx'), '<SNR>\(\d\+_\)xx$',
+ \ '\1', '')
+ unmap <SID>xx
+
+ exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Window_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined *' . s:tlist_sid . 'Tlist_Menu_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined Tlist_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+ exe 'autocmd FuncUndefined TagList_* source ' .
+ \ escape(expand('<sfile>'), ' ')
+
+ 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>;<flag>:<name>;<flag>:<name>;...
+"
+" 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 <F1> to display help text')
+ else
+ " Add the extensive help
+ call append(0, '" <enter> : 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, '" <space> : 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, '" <F1> : 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:
+ "
+ " <language_name>;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 <buffer> <silent> <CR>
+ \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ nnoremap <buffer> <silent> o
+ \ :call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
+ nnoremap <buffer> <silent> p
+ \ :call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
+ nnoremap <buffer> <silent> P
+ \ :call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
+ if v:version >= 700
+ nnoremap <buffer> <silent> t
+ \ :call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
+ nnoremap <buffer> <silent> <C-t>
+ \ :call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
+ endif
+ nnoremap <buffer> <silent> <2-LeftMouse>
+ \ :call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ nnoremap <buffer> <silent> s
+ \ :call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
+ nnoremap <buffer> <silent> + :silent! foldopen<CR>
+ nnoremap <buffer> <silent> - :silent! foldclose<CR>
+ nnoremap <buffer> <silent> * :silent! %foldopen!<CR>
+ nnoremap <buffer> <silent> = :silent! %foldclose<CR>
+ nnoremap <buffer> <silent> <kPlus> :silent! foldopen<CR>
+ nnoremap <buffer> <silent> <kMinus> :silent! foldclose<CR>
+ nnoremap <buffer> <silent> <kMultiply> :silent! %foldopen!<CR>
+ nnoremap <buffer> <silent> <Space> :call <SID>Tlist_Window_Show_Info()<CR>
+ nnoremap <buffer> <silent> u :call <SID>Tlist_Window_Update_File()<CR>
+ nnoremap <buffer> <silent> d :call <SID>Tlist_Remove_File(-1, 1)<CR>
+ nnoremap <buffer> <silent> x :call <SID>Tlist_Window_Zoom()<CR>
+ nnoremap <buffer> <silent> [[ :call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ nnoremap <buffer> <silent> <BS> :call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ nnoremap <buffer> <silent> ]] :call <SID>Tlist_Window_Move_To_File(1)<CR>
+ nnoremap <buffer> <silent> <Tab> :call <SID>Tlist_Window_Move_To_File(1)<CR>
+ nnoremap <buffer> <silent> <F1> :call <SID>Tlist_Window_Toggle_Help_Text()<CR>
+ nnoremap <buffer> <silent> q :close<CR>
+
+ " Insert mode mappings
+ inoremap <buffer> <silent> <CR>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ " Windows needs return
+ inoremap <buffer> <silent> <Return>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ inoremap <buffer> <silent> o
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newwin')<CR>
+ inoremap <buffer> <silent> p
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('preview')<CR>
+ inoremap <buffer> <silent> P
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('prevwin')<CR>
+ if v:version >= 700
+ inoremap <buffer> <silent> t
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('checktab')<CR>
+ inoremap <buffer> <silent> <C-t>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('newtab')<CR>
+ endif
+ inoremap <buffer> <silent> <2-LeftMouse>
+ \ <C-o>:call <SID>Tlist_Window_Jump_To_Tag('useopen')<CR>
+ inoremap <buffer> <silent> s
+ \ <C-o>:call <SID>Tlist_Change_Sort('cmd', 'toggle', '')<CR>
+ inoremap <buffer> <silent> + <C-o>:silent! foldopen<CR>
+ inoremap <buffer> <silent> - <C-o>:silent! foldclose<CR>
+ inoremap <buffer> <silent> * <C-o>:silent! %foldopen!<CR>
+ inoremap <buffer> <silent> = <C-o>:silent! %foldclose<CR>
+ inoremap <buffer> <silent> <kPlus> <C-o>:silent! foldopen<CR>
+ inoremap <buffer> <silent> <kMinus> <C-o>:silent! foldclose<CR>
+ inoremap <buffer> <silent> <kMultiply> <C-o>:silent! %foldopen!<CR>
+ inoremap <buffer> <silent> <Space> <C-o>:call
+ \ <SID>Tlist_Window_Show_Info()<CR>
+ inoremap <buffer> <silent> u
+ \ <C-o>:call <SID>Tlist_Window_Update_File()<CR>
+ inoremap <buffer> <silent> d <C-o>:call <SID>Tlist_Remove_File(-1, 1)<CR>
+ inoremap <buffer> <silent> x <C-o>:call <SID>Tlist_Window_Zoom()<CR>
+ inoremap <buffer> <silent> [[ <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ inoremap <buffer> <silent> <BS> <C-o>:call <SID>Tlist_Window_Move_To_File(-1)<CR>
+ inoremap <buffer> <silent> ]] <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
+ inoremap <buffer> <silent> <Tab> <C-o>:call <SID>Tlist_Window_Move_To_File(1)<CR>
+ inoremap <buffer> <silent> <F1> <C-o>:call <SID>Tlist_Window_Toggle_Help_Text()<CR>
+ inoremap <buffer> <silent> q <C-o>:close<CR>
+
+ " 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 <buffer> ... however vim does
+ " not fire the <buffer> <leftmouse> when you use the mouse
+ " to enter a buffer.
+ let clickmap = ':if bufname("%") =~ "__Tag_List__" <bar> ' .
+ \ 'call <SID>Tlist_Window_Jump_To_Tag("useopen") ' .
+ \ '<bar> endif <CR>'
+ if maparg('<leftmouse>', 'n') == ''
+ " no mapping for leftmouse
+ exe ':nnoremap <silent> <leftmouse> <leftmouse>' . clickmap
+ else
+ " we have a mapping
+ let mapcmd = ':nnoremap <silent> <leftmouse> <leftmouse>'
+ let mapcmd = mapcmd . substitute(substitute(
+ \ maparg('<leftmouse>', 'n'), '|', '<bar>', 'g'),
+ \ '\c^<leftmouse>', '', '')
+ 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('<abuf>'))
+ 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('<LeftMouse>')
+ nunmap <LeftMouse>
+ 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_name<TAB>file_name<TAB>ex_cmd;"<TAB>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:<num>\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:<num>\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 <filename> ' .
+ \ '<line_number>'
+ 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 <filename> <line_number>'
+ 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 <filename>')
+ 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 <filename>')
+ 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('<afile>: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 <silent> T&ags.Refresh\ menu :call <SID>Tlist_Menu_Refresh()<CR>
+ anoremenu <silent> T&ags.Sort\ menu\ by.Name
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
+ anoremenu <silent> T&ags.Sort\ menu\ by.Order
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
+ anoremenu T&ags.-SEP1- :
+
+ if &mousemodel =~ 'popup'
+ anoremenu <silent> PopUp.T&ags.Refresh\ menu
+ \ :call <SID>Tlist_Menu_Refresh()<CR>
+ anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Name
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'name')<CR>
+ anoremenu <silent> PopUp.T&ags.Sort\ menu\ by.Order
+ \ :call <SID>Tlist_Change_Sort('menu', 'set', 'order')<CR>
+ 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 <silent> 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 <SID>Tlist_Menu_Jump_To_Tag(' .
+ \ tidx . ')<CR>|'
+
+ 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 <silent> 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 <SID>Tlist_Menu_Jump_To_Tag(' . tidx
+ \ . ')<CR>|'
+
+ 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 . ' <Nop>'
+ 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/plugin/toggle_words.vim b/.vim/plugin/toggle_words.vim
new file mode 100644
index 0000000..2d79df5
--- /dev/null
+++ b/.vim/plugin/toggle_words.vim
@@ -0,0 +1,67 @@
+" toggle_words.vim
+" Author: Vincent Wang (linsong dot qizi at gmail dot com)
+" Created: Fri Oct 13 07:51:16 CST 2006
+" Requires: Vim Ver7.0+
+" Version: 1.0
+" TODO:
+"
+" Documentation:
+" The purpose of this plugin is very simple, it can toggle words among
+" ['true', 'false'], ['on', 'off'], ['yes', 'no'], ['if', 'elseif', 'else',
+" 'endif'] etc . It will search the candicates words to toggle based on
+" current filetype, for example, you can put the following configuration
+" into your .vimrc to define some words for python:
+" let g:toggle_words_dict = {'python': [['if', 'elif', 'else'], ['True',
+" 'False']]}
+"
+" There are some default words for toggling predefined in the
+" script(g:_toogle_words_dict) that will work for all filetypes.
+" Any comment, suggestion, bug report are welcomed.
+
+if v:version < 700
+ "TODO: maybe I should make this script works under vim7.0
+ echo "This script required vim7.0 or above version."
+ finish
+endif
+
+if exists("g:load_toggle_words")
+ finish
+endif
+
+let s:keepcpo= &cpo
+set cpo&vim
+
+let g:load_toggle_words = "1.0"
+
+let g:_toggle_words_dict = {'*': [['true', 'false'], ['on', 'off'], ['yes', 'no'], ['+', '-'], ['define', 'undef'], ['if', 'elseif', 'else', 'endif'], ['>', '<'], ['{', '}'], ['(', ')'], ['[', ']'] ], }
+
+if exists('g:toggle_words_dict')
+ :call extend(g:_toggle_words_dict, g:toggle_words_dict)
+endif
+
+function! s:ToggleWord()
+ let cur_filetype = &filetype
+ if ! has_key(g:_toggle_words_dict, cur_filetype)
+ let words_candicates_array = g:_toggle_words_dict['*']
+ else
+ let words_candicates_array = g:_toggle_words_dict[cur_filetype] + g:_toggle_words_dict['*']
+ endif
+ let cur_word = expand("<cword>")
+ for words_candicates in words_candicates_array
+ let index = index(words_candicates, cur_word)
+ if index != -1
+ let new_word_index = (index+1)%len(words_candicates)
+ let new_word = words_candicates[new_word_index]
+ " use the new word to replace the old word
+ exec "norm ciw" . new_word . ""
+ break
+ endif
+ endfor
+endfunction
+
+command! ToggleWord :call <SID>ToggleWord() <CR>
+nmap ,t :call <SID>ToggleWord()<CR>
+vmap ,t <ESC>:call <SID>ToggleWord()<CR>
+
+let &cpo= s:keepcpo
+unlet s:keepcpo