diff --git a/vim/autoload/pythoncomplete.vim b/vim/autoload/pythoncomplete.vim new file mode 100644 index 0000000..2f52f97 --- /dev/null +++ b/vim/autoload/pythoncomplete.vim @@ -0,0 +1,599 @@ +"pythoncomplete.vim - Omni Completion for python +" Maintainer: Aaron Griffin +" Version: 0.7 +" Last Updated: 19 Oct 2006 +" +" Changes +" TODO: +" User defined docstrings aren't handled right... +" 'info' item output can use some formatting work +" Add an "unsafe eval" mode, to allow for return type evaluation +" Complete basic syntax along with import statements +" i.e. "import url" +" Continue parsing on invalid line?? +" +" v 0.7 +" * Fixed function list sorting (_ and __ at the bottom) +" * Removed newline removal from docs. It appears vim handles these better in +" recent patches +" +" v 0.6: +" * Fixed argument completion +" * Removed the 'kind' completions, as they are better indicated +" with real syntax +" * Added tuple assignment parsing (whoops, that was forgotten) +" * Fixed import handling when flattening scope +" +" v 0.5: +" Yeah, I skipped a version number - 0.4 was never public. +" It was a bugfix version on top of 0.3. This is a complete +" rewrite. +" + +if !has('python') + echo "Error: Required vim compiled with +python" + finish +endif + +function! pythoncomplete#Complete(findstart, base) + "findstart = 1 when we need to get the text length + if a:findstart == 1 + let line = getline('.') + let idx = col('.') + while idx > 0 + let idx -= 1 + let c = line[idx] + if c =~ '\w' + continue + elseif ! c =~ '\.' + let idx = -1 + break + else + break + endif + endwhile + + return idx + "findstart = 0 when we need to return the list of completions + else + "vim no longer moves the cursor upon completion... fix that + let line = getline('.') + let idx = col('.') + let cword = '' + while idx > 0 + let idx -= 1 + let c = line[idx] + if c =~ '\w' || c =~ '\.' || c == '(' + let cword = c . cword + continue + elseif strlen(cword) > 0 || idx == 0 + break + endif + endwhile + execute "python vimcomplete('" . cword . "', '" . a:base . "')" + return g:pythoncomplete_completions + endif +endfunction + +function! s:DefPython() +python << PYTHONEOF +import sys, tokenize, cStringIO, types +from token import NAME, DEDENT, NEWLINE, STRING + +debugstmts=[] +def dbg(s): debugstmts.append(s) +def showdbg(): + for d in debugstmts: print "DBG: %s " % d + +def vimcomplete(context,match): + global debugstmts + debugstmts = [] + try: + import vim + def complsort(x,y): + try: + xa = x['abbr'] + ya = y['abbr'] + if xa[0] == '_': + if xa[1] == '_' and ya[0:2] == '__': + return xa > ya + elif ya[0:2] == '__': + return -1 + elif y[0] == '_': + return xa > ya + else: + return 1 + elif ya[0] == '_': + return -1 + else: + return xa > ya + except: + return 0 + cmpl = Completer() + cmpl.evalsource('\n'.join(vim.current.buffer),vim.eval("line('.')")) + all = cmpl.get_completions(context,match) + all.sort(complsort) + dictstr = '[' + # have to do this for double quoting + for cmpl in all: + dictstr += '{' + for x in cmpl: dictstr += '"%s":"%s",' % (x,cmpl[x]) + dictstr += '"icase":0},' + if dictstr[-1] == ',': dictstr = dictstr[:-1] + dictstr += ']' + #dbg("dict: %s" % dictstr) + vim.command("silent let g:pythoncomplete_completions = %s" % dictstr) + #dbg("Completion dict:\n%s" % all) + except vim.error: + dbg("VIM Error: %s" % vim.error) + +class Completer(object): + def __init__(self): + self.compldict = {} + self.parser = PyParser() + + def evalsource(self,text,line=0): + sc = self.parser.parse(text,line) + src = sc.get_code() + dbg("source: %s" % src) + try: exec(src) in self.compldict + except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1])) + for l in sc.locals: + try: exec(l) in self.compldict + except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l)) + + def _cleanstr(self,doc): + return doc.replace('"',' ').replace("'",' ') + + def get_arguments(self,func_obj): + def _ctor(obj): + try: return class_ob.__init__.im_func + except AttributeError: + for base in class_ob.__bases__: + rc = _find_constructor(base) + if rc is not None: return rc + return None + + arg_offset = 1 + if type(func_obj) == types.ClassType: func_obj = _ctor(func_obj) + elif type(func_obj) == types.MethodType: func_obj = func_obj.im_func + else: arg_offset = 0 + + arg_text='' + if type(func_obj) in [types.FunctionType, types.LambdaType]: + try: + cd = func_obj.func_code + real_args = cd.co_varnames[arg_offset:cd.co_argcount] + defaults = func_obj.func_defaults or '' + defaults = map(lambda name: "=%s" % name, defaults) + defaults = [""] * (len(real_args)-len(defaults)) + defaults + items = map(lambda a,d: a+d, real_args, defaults) + if func_obj.func_code.co_flags & 0x4: + items.append("...") + if func_obj.func_code.co_flags & 0x8: + items.append("***") + arg_text = (','.join(items)) + ')' + + except: + dbg("arg completion: %s: %s" % (sys.exc_info()[0],sys.exc_info()[1])) + pass + if len(arg_text) == 0: + # The doc string sometimes contains the function signature + # this works for alot of C modules that are part of the + # standard library + doc = func_obj.__doc__ + if doc: + doc = doc.lstrip() + pos = doc.find('\n') + if pos > 0: + sigline = doc[:pos] + lidx = sigline.find('(') + ridx = sigline.find(')') + if lidx > 0 and ridx > 0: + arg_text = sigline[lidx+1:ridx] + ')' + if len(arg_text) == 0: arg_text = ')' + return arg_text + + def get_completions(self,context,match): + dbg("get_completions('%s','%s')" % (context,match)) + stmt = '' + if context: stmt += str(context) + if match: stmt += str(match) + try: + result = None + all = {} + ridx = stmt.rfind('.') + if len(stmt) > 0 and stmt[-1] == '(': + result = eval(_sanitize(stmt[:-1]), self.compldict) + doc = result.__doc__ + if doc == None: doc = '' + args = self.get_arguments(result) + return [{'word':self._cleanstr(args),'info':self._cleanstr(doc)}] + elif ridx == -1: + match = stmt + all = self.compldict + else: + match = stmt[ridx+1:] + stmt = _sanitize(stmt[:ridx]) + result = eval(stmt, self.compldict) + all = dir(result) + + dbg("completing: stmt:%s" % stmt) + completions = [] + + try: maindoc = result.__doc__ + except: maindoc = ' ' + if maindoc == None: maindoc = ' ' + for m in all: + if m == "_PyCmplNoType": continue #this is internal + try: + dbg('possible completion: %s' % m) + if m.find(match) == 0: + if result == None: inst = all[m] + else: inst = getattr(result,m) + try: doc = inst.__doc__ + except: doc = maindoc + typestr = str(inst) + if doc == None or doc == '': doc = maindoc + + wrd = m[len(match):] + c = {'word':wrd, 'abbr':m, 'info':self._cleanstr(doc)} + if "function" in typestr: + c['word'] += '(' + c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst)) + elif "method" in typestr: + c['word'] += '(' + c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst)) + elif "module" in typestr: + c['word'] += '.' + elif "class" in typestr: + c['word'] += '(' + c['abbr'] += '(' + completions.append(c) + except: + i = sys.exc_info() + dbg("inner completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) + return completions + except: + i = sys.exc_info() + dbg("completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) + return [] + +class Scope(object): + def __init__(self,name,indent): + self.subscopes = [] + self.docstr = '' + self.locals = [] + self.parent = None + self.name = name + self.indent = indent + + def add(self,sub): + #print 'push scope: [%s@%s]' % (sub.name,sub.indent) + sub.parent = self + self.subscopes.append(sub) + return sub + + def doc(self,str): + """ Clean up a docstring """ + d = str.replace('\n',' ') + d = d.replace('\t',' ') + while d.find(' ') > -1: d = d.replace(' ',' ') + while d[0] in '"\'\t ': d = d[1:] + while d[-1] in '"\'\t ': d = d[:-1] + self.docstr = d + + def local(self,loc): + if not self._hasvaralready(loc): + self.locals.append(loc) + + def copy_decl(self,indent=0): + """ Copy a scope's declaration only, at the specified indent level - not local variables """ + return Scope(self.name,indent) + + def _hasvaralready(self,test): + "Convienance function... keep out duplicates" + if test.find('=') > -1: + var = test.split('=')[0].strip() + for l in self.locals: + if l.find('=') > -1 and var == l.split('=')[0].strip(): + return True + return False + + def get_code(self): + # we need to start with this, to fix up broken completions + # hopefully this name is unique enough... + str = '"""'+self.docstr+'"""\n' + for l in self.locals: + if l.startswith('import'): str += l+'\n' + str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n' + for sub in self.subscopes: + str += sub.get_code() + for l in self.locals: + if not l.startswith('import'): str += l+'\n' + + return str + + def pop(self,indent): + #print 'pop scope: [%s] to [%s]' % (self.indent,indent) + outer = self + while outer.parent != None and outer.indent >= indent: + outer = outer.parent + return outer + + def currentindent(self): + #print 'parse current indent: %s' % self.indent + return ' '*self.indent + + def childindent(self): + #print 'parse child indent: [%s]' % (self.indent+1) + return ' '*(self.indent+1) + +class Class(Scope): + def __init__(self, name, supers, indent): + Scope.__init__(self,name,indent) + self.supers = supers + def copy_decl(self,indent=0): + c = Class(self.name,self.supers,indent) + for s in self.subscopes: + c.add(s.copy_decl(indent+1)) + return c + def get_code(self): + str = '%sclass %s' % (self.currentindent(),self.name) + if len(self.supers) > 0: str += '(%s)' % ','.join(self.supers) + str += ':\n' + if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' + if len(self.subscopes) > 0: + for s in self.subscopes: str += s.get_code() + else: + str += '%spass\n' % self.childindent() + return str + + +class Function(Scope): + def __init__(self, name, params, indent): + Scope.__init__(self,name,indent) + self.params = params + def copy_decl(self,indent=0): + return Function(self.name,self.params,indent) + def get_code(self): + str = "%sdef %s(%s):\n" % \ + (self.currentindent(),self.name,','.join(self.params)) + if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' + str += "%spass\n" % self.childindent() + return str + +class PyParser: + def __init__(self): + self.top = Scope('global',0) + self.scope = self.top + + def _parsedotname(self,pre=None): + #returns (dottedname, nexttoken) + name = [] + if pre == None: + tokentype, token, indent = self.next() + if tokentype != NAME and token != '*': + return ('', token) + else: token = pre + name.append(token) + while True: + tokentype, token, indent = self.next() + if token != '.': break + tokentype, token, indent = self.next() + if tokentype != NAME: break + name.append(token) + return (".".join(name), token) + + def _parseimportlist(self): + imports = [] + while True: + name, token = self._parsedotname() + if not name: break + name2 = '' + if token == 'as': name2, token = self._parsedotname() + imports.append((name, name2)) + while token != "," and "\n" not in token: + tokentype, token, indent = self.next() + if token != ",": break + return imports + + def _parenparse(self): + name = '' + names = [] + level = 1 + while True: + tokentype, token, indent = self.next() + if token in (')', ',') and level == 1: + names.append(name) + name = '' + if token == '(': + level += 1 + elif token == ')': + level -= 1 + if level == 0: break + elif token == ',' and level == 1: + pass + else: + name += str(token) + return names + + def _parsefunction(self,indent): + self.scope=self.scope.pop(indent) + tokentype, fname, ind = self.next() + if tokentype != NAME: return None + + tokentype, open, ind = self.next() + if open != '(': return None + params=self._parenparse() + + tokentype, colon, ind = self.next() + if colon != ':': return None + + return Function(fname,params,indent) + + def _parseclass(self,indent): + self.scope=self.scope.pop(indent) + tokentype, cname, ind = self.next() + if tokentype != NAME: return None + + super = [] + tokentype, next, ind = self.next() + if next == '(': + super=self._parenparse() + elif next != ':': return None + + return Class(cname,super,indent) + + def _parseassignment(self): + assign='' + tokentype, token, indent = self.next() + if tokentype == tokenize.STRING or token == 'str': + return '""' + elif token == '(' or token == 'tuple': + return '()' + elif token == '[' or token == 'list': + return '[]' + elif token == '{' or token == 'dict': + return '{}' + elif tokentype == tokenize.NUMBER: + return '0' + elif token == 'open' or token == 'file': + return 'file' + elif token == 'None': + return '_PyCmplNoType()' + elif token == 'type': + return 'type(_PyCmplNoType)' #only for method resolution + else: + assign += token + level = 0 + while True: + tokentype, token, indent = self.next() + if token in ('(','{','['): + level += 1 + elif token in (']','}',')'): + level -= 1 + if level == 0: break + elif level == 0: + if token in (';','\n'): break + assign += token + return "%s" % assign + + def next(self): + type, token, (lineno, indent), end, self.parserline = self.gen.next() + if lineno == self.curline: + #print 'line found [%s] scope=%s' % (line.replace('\n',''),self.scope.name) + self.currentscope = self.scope + return (type, token, indent) + + def _adjustvisibility(self): + newscope = Scope('result',0) + scp = self.currentscope + while scp != None: + if type(scp) == Function: + slice = 0 + #Handle 'self' params + if scp.parent != None and type(scp.parent) == Class: + slice = 1 + p = scp.params[0] + i = p.find('=') + if i != -1: p = p[:i] + newscope.local('%s = %s' % (scp.params[0],scp.parent.name)) + for p in scp.params[slice:]: + i = p.find('=') + if i == -1: + newscope.local('%s = _PyCmplNoType()' % p) + else: + newscope.local('%s = %s' % (p[:i],_sanitize(p[i+1]))) + + for s in scp.subscopes: + ns = s.copy_decl(0) + newscope.add(ns) + for l in scp.locals: newscope.local(l) + scp = scp.parent + + self.currentscope = newscope + return self.currentscope + + #p.parse(vim.current.buffer[:],vim.eval("line('.')")) + def parse(self,text,curline=0): + self.curline = int(curline) + buf = cStringIO.StringIO(''.join(text) + '\n') + self.gen = tokenize.generate_tokens(buf.readline) + self.currentscope = self.scope + + try: + freshscope=True + while True: + tokentype, token, indent = self.next() + #dbg( 'main: token=[%s] indent=[%s]' % (token,indent)) + + if tokentype == DEDENT or token == "pass": + self.scope = self.scope.pop(indent) + elif token == 'def': + func = self._parsefunction(indent) + if func == None: + print "function: syntax error..." + continue + freshscope = True + self.scope = self.scope.add(func) + elif token == 'class': + cls = self._parseclass(indent) + if cls == None: + print "class: syntax error..." + continue + freshscope = True + self.scope = self.scope.add(cls) + + elif token == 'import': + imports = self._parseimportlist() + for mod, alias in imports: + loc = "import %s" % mod + if len(alias) > 0: loc += " as %s" % alias + self.scope.local(loc) + freshscope = False + elif token == 'from': + mod, token = self._parsedotname() + if not mod or token != "import": + print "from: syntax error..." + continue + names = self._parseimportlist() + for name, alias in names: + loc = "from %s import %s" % (mod,name) + if len(alias) > 0: loc += " as %s" % alias + self.scope.local(loc) + freshscope = False + elif tokentype == STRING: + if freshscope: self.scope.doc(token) + elif tokentype == NAME: + name,token = self._parsedotname(token) + if token == '=': + stmt = self._parseassignment() + if stmt != None: + self.scope.local("%s = %s" % (name,stmt)) + freshscope = False + except StopIteration: #thrown on EOF + pass + except: + dbg("parse error: %s, %s @ %s" % + (sys.exc_info()[0], sys.exc_info()[1], self.parserline)) + return self._adjustvisibility() + +def _sanitize(str): + val = '' + level = 0 + for c in str: + if c in ('(','{','['): + level += 1 + elif c in (']','}',')'): + level -= 1 + elif level == 0: + val += c + return val + +sys.path.extend(['.','..']) +PYTHONEOF +endfunction + +call s:DefPython() +" vim: set et ts=4: diff --git a/vim/colors/freya.vim b/vim/colors/freya.vim new file mode 100644 index 0000000..d190851 --- /dev/null +++ b/vim/colors/freya.vim @@ -0,0 +1,79 @@ +set background=dark + +hi clear + +if exists("syntax_on") + syntax reset +endif + +let colors_name = "freya" + +hi Normal ctermbg=0 ctermfg=7 cterm=none guibg=#2a2a2a guifg=#dcdccc gui=none + +hi Cursor guibg=fg guifg=bg gui=none +hi CursorColumn guibg=#3f3f3f gui=none +hi CursorLine guibg=#3f3f3f gui=none +hi DiffAdd guibg=#008b00 guifg=fg gui=none +hi DiffChange guibg=#00008b guifg=fg gui=none +hi DiffDelete guibg=#8b0000 guifg=fg gui=none +hi DiffText guibg=#0000cd guifg=fg gui=bold +hi Directory guibg=bg guifg=#d4b064 gui=none +hi ErrorMsg guibg=bg guifg=#f07070 gui=bold +hi FoldColumn ctermbg=bg guibg=bg guifg=#c2b680 gui=none +hi Folded guibg=#101010 guifg=#c2b680 gui=none +hi IncSearch guibg=#866a4f guifg=fg gui=none +hi LineNr guibg=bg guifg=#9f8f80 gui=none +hi ModeMsg guibg=bg guifg=fg gui=bold +hi MoreMsg guibg=bg guifg=#dabfa5 gui=bold +hi NonText ctermfg=8 guibg=bg guifg=#9f8f80 gui=bold +hi Pmenu guibg=#a78869 guifg=#000000 gui=none +hi PmenuSbar guibg=#B99F86 guifg=fg gui=none +hi PmenuSel guibg=#c0aa94 guifg=bg gui=none +hi PmenuThumb guibg=#f7f7f1 guifg=bg gui=none +hi Question guibg=bg guifg=#dabfa5 gui=bold +hi Search guibg=#c0aa94 guifg=bg gui=none +hi SignColumn ctermbg=bg guibg=bg guifg=#c2b680 gui=none +hi SpecialKey guibg=bg guifg=#d4b064 gui=none +if has("spell") + hi SpellBad guisp=#f07070 gui=undercurl + hi SpellCap guisp=#7070f0 gui=undercurl + hi SpellLocal guisp=#70f0f0 gui=undercurl + hi SpellRare guisp=#f070f0 gui=undercurl +endif +hi StatusLine ctermbg=7 ctermfg=0 guibg=#736559 guifg=#f7f7f1 gui=bold +hi StatusLineNC ctermbg=8 ctermfg=0 guibg=#564d43 guifg=#f7f7f1 gui=none +hi TabLine guibg=#564d43 guifg=#f7f7f1 gui=underline +hi TabLineFill guibg=#564d43 guifg=#f7f7f1 gui=underline +hi TabLineSel guibg=bg guifg=#f7f7f1 gui=bold +hi Title ctermbg=0 ctermfg=15 guifg=#f7f7f1 gui=bold +hi VertSplit ctermbg=7 ctermfg=0 guibg=#564d43 guifg=#f7f7f1 gui=none +if version >= 700 + hi Visual ctermbg=7 ctermfg=0 guibg=#5f5f5f gui=none +else + hi Visual ctermbg=7 ctermfg=0 guibg=#5f5f5f guifg=fg gui=none +endif +hi VisualNOS guibg=bg guifg=#c0aa94 gui=bold,underline +hi WarningMsg guibg=bg guifg=#f07070 gui=none +hi WildMenu guibg=#c0aa94 guifg=bg gui=bold + +hi Comment guibg=bg guifg=#c2b680 gui=none +hi Constant guibg=bg guifg=#f8af80 gui=none +hi Error guibg=bg guifg=#f07070 gui=none +hi Identifier guibg=bg guifg=#dabfa5 gui=none +hi Ignore guibg=bg guifg=bg gui=none +hi lCursor guibg=#c0aa94 guifg=bg gui=none +hi MatchParen guibg=#008b8b gui=none +hi PreProc guibg=bg guifg=#c2d0ae gui=none +hi Special guibg=bg guifg=#d4b064 gui=none +hi Statement guibg=bg guifg=#e0af91 gui=bold +hi Todo guibg=#aed0ae guifg=bg gui=none +hi Type guibg=bg guifg=#dabfa5 gui=bold +hi Underlined guibg=bg guifg=#d4b064 gui=underline + +hi htmlBold ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=bold +hi htmlItalic ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=italic +hi htmlUnderline ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=underline +hi htmlBoldItalic ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=bold,italic +hi htmlBoldUnderline ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=bold,underline +hi htmlBoldUnderlineItalic ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=bold,underline,italic +hi htmlUnderlineItalic ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=underline,italic diff --git a/vim/colors/inkpot.vim b/vim/colors/inkpot.vim new file mode 100644 index 0000000..a062248 --- /dev/null +++ b/vim/colors/inkpot.vim @@ -0,0 +1,212 @@ +" Vim color file +" Name: inkpot.vim +" Maintainer: Ciaran McCreesh +" This should work in the GUI, rxvt-unicode (88 colour mode) and xterm (256 +" colour mode). It won't work in 8/16 colour terminals. +" +" To use a black background, :let g:inkpot_black_background = 1 + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif + +let colors_name = "inkpot" + +" map a urxvt cube number to an xterm-256 cube number +fun! M(a) + return strpart("0135", a:a, 1) + 0 +endfun + +" map a urxvt colour to an xterm-256 colour +fun! X(a) + if &t_Co == 88 + return a:a + else + if a:a == 8 + return 237 + elseif a:a < 16 + return a:a + elseif a:a > 79 + return 232 + (3 * (a:a - 80)) + else + let l:b = a:a - 16 + let l:x = l:b % 4 + let l:y = (l:b / 4) % 4 + let l:z = (l:b / 16) + return 16 + M(l:x) + (6 * M(l:y)) + (36 * M(l:z)) + endif + endif +endfun + +if ! exists("g:inkpot_black_background") + let g:inkpot_black_background = 0 +endif + +if has("gui_running") + if ! g:inkpot_black_background + hi Normal gui=NONE guifg=#cfbfad guibg=#1e1e27 + else + hi Normal gui=NONE guifg=#cfbfad guibg=#000000 + endif + + hi IncSearch gui=BOLD guifg=#303030 guibg=#cd8b60 + hi Search gui=NONE guifg=#303030 guibg=#cd8b60 + hi ErrorMsg gui=BOLD guifg=#ffffff guibg=#ce4e4e + hi WarningMsg gui=BOLD guifg=#ffffff guibg=#ce8e4e + hi ModeMsg gui=BOLD guifg=#7e7eae guibg=NONE + hi MoreMsg gui=BOLD guifg=#7e7eae guibg=NONE + hi Question gui=BOLD guifg=#ffcd00 guibg=NONE + + hi StatusLine gui=BOLD guifg=#b9b9b9 guibg=#3e3e5e + hi User1 gui=BOLD guifg=#00ff8b guibg=#3e3e5e + hi User2 gui=BOLD guifg=#7070a0 guibg=#3e3e5e + hi StatusLineNC gui=NONE guifg=#b9b9b9 guibg=#3e3e5e + hi VertSplit gui=NONE guifg=#b9b9b9 guibg=#3e3e5e + + hi WildMenu gui=BOLD guifg=#eeeeee guibg=#6e6eaf + + hi MBENormal guifg=#cfbfad guibg=#2e2e3f + hi MBEChanged guifg=#eeeeee guibg=#2e2e3f + hi MBEVisibleNormal guifg=#cfcfcd guibg=#4e4e8f + hi MBEVisibleChanged guifg=#eeeeee guibg=#4e4e8f + + hi DiffText gui=NONE guifg=#ffffcd guibg=#4a2a4a + hi DiffChange gui=NONE guifg=#ffffcd guibg=#306b8f + hi DiffDelete gui=NONE guifg=#ffffcd guibg=#6d3030 + hi DiffAdd gui=NONE guifg=#ffffcd guibg=#306d30 + + hi Cursor gui=NONE guifg=#404040 guibg=#8b8bff + hi lCursor gui=NONE guifg=#404040 guibg=#8fff8b + hi CursorIM gui=NONE guifg=#404040 guibg=#8b8bff + + hi Folded gui=NONE guifg=#cfcfcd guibg=#4b208f + hi FoldColumn gui=NONE guifg=#8b8bcd guibg=#2e2e2e + + hi Directory gui=NONE guifg=#00ff8b guibg=NONE + hi LineNr gui=NONE guifg=#8b8bcd guibg=#2e2e2e + hi NonText gui=BOLD guifg=#8b8bcd guibg=NONE + hi SpecialKey gui=BOLD guifg=#ab60ed guibg=NONE + hi Title gui=BOLD guifg=#af4f4b guibg=NONE + hi Visual gui=NONE guifg=#eeeeee guibg=#4e4e8f + + hi Comment gui=NONE guifg=#cd8b00 guibg=NONE + hi Constant gui=NONE guifg=#ffcd8b guibg=NONE + hi String gui=NONE guifg=#ffcd8b guibg=#404040 + hi Error gui=NONE guifg=#ffffff guibg=#6e2e2e + hi Identifier gui=NONE guifg=#ff8bff guibg=NONE + hi Ignore gui=NONE + hi Number gui=NONE guifg=#f0ad6d guibg=NONE + hi PreProc gui=NONE guifg=#409090 guibg=NONE + hi Special gui=NONE guifg=#c080d0 guibg=NONE + hi SpecialChar gui=NONE guifg=#c080d0 guibg=#404040 + hi Statement gui=NONE guifg=#808bed guibg=NONE + hi Todo gui=BOLD guifg=#303030 guibg=#d0a060 + hi Type gui=NONE guifg=#ff8bff guibg=NONE + hi Underlined gui=BOLD guifg=#df9f2d guibg=NONE + hi TaglistTagName gui=BOLD guifg=#808bed guibg=NONE + + hi perlSpecialMatch gui=NONE guifg=#c080d0 guibg=#404040 + hi perlSpecialString gui=NONE guifg=#c080d0 guibg=#404040 + + hi cSpecialCharacter gui=NONE guifg=#c080d0 guibg=#404040 + hi cFormat gui=NONE guifg=#c080d0 guibg=#404040 + + hi doxygenBrief gui=NONE guifg=#fdab60 guibg=NONE + hi doxygenParam gui=NONE guifg=#fdd090 guibg=NONE + hi doxygenPrev gui=NONE guifg=#fdd090 guibg=NONE + hi doxygenSmallSpecial gui=NONE guifg=#fdd090 guibg=NONE + hi doxygenSpecial gui=NONE guifg=#fdd090 guibg=NONE + hi doxygenComment gui=NONE guifg=#ad7b20 guibg=NONE + hi doxygenSpecial gui=NONE guifg=#fdab60 guibg=NONE + hi doxygenSpecialMultilineDesc gui=NONE guifg=#ad600b guibg=NONE + hi doxygenSpecialOnelineDesc gui=NONE guifg=#ad600b guibg=NONE + + if v:version >= 700 + hi Pmenu gui=NONE guifg=#eeeeee guibg=#4e4e8f + hi PmenuSel gui=BOLD guifg=#eeeeee guibg=#2e2e3f + hi PmenuSbar gui=BOLD guifg=#eeeeee guibg=#6e6eaf + hi PmenuThumb gui=BOLD guifg=#eeeeee guibg=#6e6eaf + + hi SpellBad gui=undercurl guisp=#cc6666 + hi SpellRare gui=undercurl guisp=#cc66cc + hi SpellLocal gui=undercurl guisp=#cccc66 + hi SpellCap gui=undercurl guisp=#66cccc + + hi MatchParen gui=NONE guifg=#404040 guibg=#8fff8b + endif +else + if ! g:inkpot_black_background + exec "hi Normal cterm=NONE ctermfg=" . X(79) . " ctermbg=" . X(80) + else + exec "hi Normal cterm=NONE ctermfg=" . X(79) . " ctermbg=" . X(16) + endif + + exec "hi IncSearch cterm=BOLD ctermfg=" . X(80) . " ctermbg=" . X(73) + exec "hi Search cterm=NONE ctermfg=" . X(80) . " ctermbg=" . X(73) + exec "hi ErrorMsg cterm=BOLD ctermfg=" . X(16) . " ctermbg=" . X(48) + exec "hi WarningMsg cterm=BOLD ctermfg=" . X(16) . " ctermbg=" . X(68) + exec "hi ModeMsg cterm=BOLD ctermfg=" . X(38) . " ctermbg=" . "NONE" + exec "hi MoreMsg cterm=BOLD ctermfg=" . X(38) . " ctermbg=" . "NONE" + exec "hi Question cterm=BOLD ctermfg=" . X(52) . " ctermbg=" . "NONE" + + exec "hi StatusLine cterm=BOLD ctermfg=" . X(85) . " ctermbg=" . X(81) + exec "hi User1 cterm=BOLD ctermfg=" . X(28) . " ctermbg=" . X(81) + exec "hi User2 cterm=BOLD ctermfg=" . X(39) . " ctermbg=" . X(81) + exec "hi StatusLineNC cterm=NONE ctermfg=" . X(84) . " ctermbg=" . X(81) + exec "hi VertSplit cterm=NONE ctermfg=" . X(84) . " ctermbg=" . X(81) + + exec "hi WildMenu cterm=BOLD ctermfg=" . X(87) . " ctermbg=" . X(38) + + exec "hi MBENormal ctermfg=" . X(85) . " ctermbg=" . X(81) + exec "hi MBEChanged ctermfg=" . X(87) . " ctermbg=" . X(81) + exec "hi MBEVisibleNormal ctermfg=" . X(85) . " ctermbg=" . X(82) + exec "hi MBEVisibleChanged ctermfg=" . X(87) . " ctermbg=" . X(82) + + exec "hi DiffText cterm=NONE ctermfg=" . X(79) . " ctermbg=" . X(34) + exec "hi DiffChange cterm=NONE ctermfg=" . X(79) . " ctermbg=" . X(17) + exec "hi DiffDelete cterm=NONE ctermfg=" . X(79) . " ctermbg=" . X(32) + exec "hi DiffAdd cterm=NONE ctermfg=" . X(79) . " ctermbg=" . X(20) + + exec "hi Folded cterm=NONE ctermfg=" . X(79) . " ctermbg=" . X(35) + exec "hi FoldColumn cterm=NONE ctermfg=" . X(39) . " ctermbg=" . X(80) + + exec "hi Directory cterm=NONE ctermfg=" . X(28) . " ctermbg=" . "NONE" + exec "hi LineNr cterm=NONE ctermfg=" . X(39) . " ctermbg=" . X(80) + exec "hi NonText cterm=BOLD ctermfg=" . X(39) . " ctermbg=" . "NONE" + exec "hi SpecialKey cterm=BOLD ctermfg=" . X(55) . " ctermbg=" . "NONE" + exec "hi Title cterm=BOLD ctermfg=" . X(48) . " ctermbg=" . "NONE" + exec "hi Visual cterm=NONE ctermfg=" . X(79) . " ctermbg=" . X(38) + + exec "hi Comment cterm=NONE ctermfg=" . X(52) . " ctermbg=" . "NONE" + exec "hi Constant cterm=NONE ctermfg=" . X(73) . " ctermbg=" . "NONE" + exec "hi String cterm=NONE ctermfg=" . X(73) . " ctermbg=" . X(81) + exec "hi Error cterm=NONE ctermfg=" . X(79) . " ctermbg=" . X(32) + exec "hi Identifier cterm=NONE ctermfg=" . X(53) . " ctermbg=" . "NONE" + exec "hi Ignore cterm=NONE" + exec "hi Number cterm=NONE ctermfg=" . X(69) . " ctermbg=" . "NONE" + exec "hi PreProc cterm=NONE ctermfg=" . X(25) . " ctermbg=" . "NONE" + exec "hi Special cterm=NONE ctermfg=" . X(55) . " ctermbg=" . "NONE" + exec "hi SpecialChar cterm=NONE ctermfg=" . X(55) . " ctermbg=" . X(81) + exec "hi Statement cterm=NONE ctermfg=" . X(27) . " ctermbg=" . "NONE" + exec "hi Todo cterm=BOLD ctermfg=" . X(16) . " ctermbg=" . X(57) + exec "hi Type cterm=NONE ctermfg=" . X(71) . " ctermbg=" . "NONE" + exec "hi Underlined cterm=BOLD ctermfg=" . X(77) . " ctermbg=" . "NONE" + exec "hi TaglistTagName cterm=BOLD ctermfg=" . X(39) . " ctermbg=" . "NONE" + + if v:version >= 700 + exec "hi Pmenu cterm=NONE ctermfg=" . X(87) . " ctermbg=" . X(82) + exec "hi PmenuSel cterm=BOLD ctermfg=" . X(87) . " ctermbg=" . X(38) + exec "hi PmenuSbar cterm=BOLD ctermfg=" . X(87) . " ctermbg=" . X(39) + exec "hi PmenuThumb cterm=BOLD ctermfg=" . X(87) . " ctermbg=" . X(39) + + exec "hi SpellBad cterm=NONE ctermbg=" . X(32) + exec "hi SpellRare cterm=NONE ctermbg=" . X(33) + exec "hi SpellLocal cterm=NONE ctermbg=" . X(36) + exec "hi SpellCap cterm=NONE ctermbg=" . X(21) + exec "hi MatchParen cterm=NONE ctermbg=" . X(14) . "ctermfg=" . X(25) + endif +endif + +" vim: set et : diff --git a/vim/colors/matrix.vim b/vim/colors/matrix.vim new file mode 100644 index 0000000..da5c687 --- /dev/null +++ b/vim/colors/matrix.vim @@ -0,0 +1,80 @@ +" vim:set ts=8 sts=2 sw=2 tw=0: +" +" matrix.vim - MATRIX like colorscheme. +" +" Maintainer: MURAOKA Taro +" Last Change: 10-Jun-2003. + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name = 'matrix' + +" the character under the cursor +hi Cursor guifg=#226622 guibg=#55ff55 +hi lCursor guifg=#226622 guibg=#55ff55 +" like Cursor, but used when in IME mode |CursorIM| +hi CursorIM guifg=#226622 guibg=#55ff55 +" directory names (and other special names in listings) +hi Directory guifg=#55ff55 guibg=#000000 +" diff mode: Added line |diff.txt| +hi DiffAdd guifg=#55ff55 guibg=#226622 gui=none +" diff mode: Changed line |diff.txt| +hi DiffChange guifg=#55ff55 guibg=#226622 gui=none +" diff mode: Deleted line |diff.txt| +hi DiffDelete guifg=#113311 guibg=#113311 gui=none +" diff mode: Changed text within a changed line |diff.txt| +hi DiffText guifg=#55ff55 guibg=#339933 gui=bold +" error messages on the command line +hi ErrorMsg guifg=#55ff55 guibg=#339933 +" the column separating vertically split windows +hi VertSplit guifg=#339933 guibg=#339933 +" line used for closed folds +hi Folded guifg=#44cc44 guibg=#113311 +" 'foldcolumn' +hi FoldColumn guifg=#44cc44 guibg=#226622 +" 'incsearch' highlighting; also used for the text replaced with +hi IncSearch guifg=#226622 guibg=#55ff55 gui=none +" line number for ":number" and ":#" commands, and when 'number' +hi LineNr guifg=#44cc44 guibg=#000000 +" 'showmode' message (e.g., "-- INSERT --") +hi ModeMsg guifg=#44cc44 guibg=#000000 +" |more-prompt| +hi MoreMsg guifg=#44cc44 guibg=#000000 +" '~' and '@' at the end of the window, characters from +hi NonText guifg=#44cc44 guibg=#113311 +" normal text +hi Normal guifg=#44cc44 guibg=#000000 +" |hit-enter| prompt and yes/no questions +hi Question guifg=#44cc44 guibg=#000000 +" Last search pattern highlighting (see 'hlsearch'). +hi Search guifg=#113311 guibg=#44cc44 gui=none +" Meta and special keys listed with ":map", also for text used +hi SpecialKey guifg=#44cc44 guibg=#000000 +" status line of current window +hi StatusLine guifg=#55ff55 guibg=#339933 gui=none +" status lines of not-current windows +hi StatusLineNC guifg=#113311 guibg=#339933 gui=none +" titles for output from ":set all", ":autocmd" etc. +hi Title guifg=#55ff55 guibg=#113311 gui=bold +" Visual mode selection +hi Visual guifg=#55ff55 guibg=#339933 gui=none +" Visual mode selection when vim is "Not Owning the Selection". +hi VisualNOS guifg=#44cc44 guibg=#000000 +" warning messages +hi WarningMsg guifg=#55ff55 guibg=#000000 +" current match in 'wildmenu' completion +hi WildMenu guifg=#226622 guibg=#55ff55 + +hi Comment guifg=#226622 guibg=#000000 +hi Constant guifg=#55ff55 guibg=#226622 +hi Special guifg=#44cc44 guibg=#226622 +hi Identifier guifg=#55ff55 guibg=#000000 +hi Statement guifg=#55ff55 guibg=#000000 gui=bold +hi PreProc guifg=#339933 guibg=#000000 +hi Type guifg=#55ff55 guibg=#000000 gui=bold +hi Underlined guifg=#55ff55 guibg=#000000 gui=underline +hi Error guifg=#55ff55 guibg=#339933 +hi Todo guifg=#113311 guibg=#44cc44 gui=none diff --git a/vim/colors/moria.vim b/vim/colors/moria.vim new file mode 100644 index 0000000..f03b297 --- /dev/null +++ b/vim/colors/moria.vim @@ -0,0 +1,205 @@ +if exists("g:moria_style") + let s:moria_style = g:moria_style +else + let s:moria_style = &background +endif + +execute "command! -nargs=1 Colo let g:moria_style = \"\" | colo moria" + +if s:moria_style == "black" || s:moria_style == "dark" || s:moria_style == "darkslategray" + set background=dark +elseif s:moria_style == "light" || s:moria_style == "white" + set background=light +else + let s:moria_style = &background +endif + +hi clear + +if exists("syntax_on") + syntax reset +endif + +let colors_name = "moria" + +if &background == "dark" + if s:moria_style == "darkslategray" + hi Normal ctermbg=0 ctermfg=7 guibg=#2f4f4f guifg=#d0d0d0 gui=none + + hi CursorColumn guibg=#404040 gui=none + hi CursorLine guibg=#404040 gui=none + hi FoldColumn ctermbg=bg guibg=bg guifg=#a0c0c0 gui=none + hi Folded guibg=#585858 guifg=#c0e0e0 gui=none + hi LineNr guifg=#a0c0c0 gui=none + hi NonText ctermfg=8 guibg=bg guifg=#a0c0c0 gui=bold + hi Pmenu guibg=#80a0a0 guifg=#000000 gui=none + hi PmenuSbar guibg=#608080 guifg=fg gui=none + hi PmenuThumb guibg=#c0e0e0 guifg=bg gui=none + hi SignColumn ctermbg=bg guibg=bg guifg=#a0c0c0 gui=none + hi StatusLine ctermbg=7 ctermfg=0 guibg=#507070 guifg=fg gui=bold + hi StatusLineNC ctermbg=8 ctermfg=0 guibg=#406060 guifg=fg gui=none + hi TabLine guibg=#567676 guifg=fg gui=underline + hi TabLineFill guibg=#567676 guifg=fg gui=underline + hi VertSplit ctermbg=7 ctermfg=0 guibg=#406060 guifg=fg gui=none + if version >= 700 + hi Visual ctermbg=7 ctermfg=0 guibg=#608080 gui=none + else + hi Visual ctermbg=7 ctermfg=0 guibg=#608080 guifg=fg gui=none + endif + hi VisualNOS guibg=bg guifg=#90b0b0 gui=bold,underline + else + if s:moria_style == "dark" + hi Normal ctermbg=0 ctermfg=7 guibg=#202020 guifg=#d0d0d0 gui=none + + hi CursorColumn guibg=#444444 gui=none + hi CursorLine guibg=#444444 gui=none + elseif s:moria_style == "black" + hi Normal ctermbg=0 ctermfg=7 guibg=#000000 guifg=#d0d0d0 gui=none + + hi CursorColumn guibg=#3a3a3a gui=none + hi CursorLine guibg=#3a3a3a gui=none + endif + hi FoldColumn ctermbg=bg guibg=bg guifg=#a0b0c0 gui=none + hi Folded guibg=#585858 guifg=#c0d0e0 gui=none + hi LineNr guifg=#a0b0c0 gui=none + hi NonText ctermfg=8 guibg=bg guifg=#a0b0c0 gui=bold + hi Pmenu guibg=#8090a0 guifg=#000000 gui=none + hi PmenuSbar guibg=#607080 guifg=fg gui=none + hi PmenuThumb guibg=#c0d0e0 guifg=bg gui=none + hi SignColumn ctermbg=bg guibg=bg guifg=#a0b0c0 gui=none + hi StatusLine ctermbg=7 ctermfg=0 guibg=#485868 guifg=fg gui=bold + hi StatusLineNC ctermbg=8 ctermfg=0 guibg=#304050 guifg=fg gui=none + hi TabLine guibg=#566676 guifg=fg gui=underline + hi TabLineFill guibg=#566676 guifg=fg gui=underline + hi VertSplit ctermbg=7 ctermfg=0 guibg=#304050 guifg=fg gui=none + if version >= 700 + hi Visual ctermbg=7 ctermfg=0 guibg=#607080 gui=none + else + hi Visual ctermbg=7 ctermfg=0 guibg=#607080 guifg=fg gui=none + endif + hi VisualNOS guibg=bg guifg=#90a0b0 gui=bold,underline + endif + hi Cursor guibg=#ffa500 guifg=bg gui=none + hi DiffAdd guibg=#008b00 guifg=fg gui=none + hi DiffChange guibg=#00008b guifg=fg gui=none + hi DiffDelete guibg=#8b0000 guifg=fg gui=none + hi DiffText guibg=#0000cd guifg=fg gui=bold + hi Directory guibg=bg guifg=#1e90ff gui=none + hi ErrorMsg guibg=#ee2c2c guifg=#ffffff gui=bold + hi IncSearch guibg=#e0cd78 guifg=#000000 gui=none + hi ModeMsg guibg=bg guifg=fg gui=bold + hi MoreMsg guibg=bg guifg=#7ec0ee gui=bold + hi PmenuSel guibg=#e0e000 guifg=#000000 gui=none + hi Question guibg=bg guifg=#e8b87e gui=bold + hi Search guibg=#90e090 guifg=#000000 gui=none + hi SpecialKey guibg=bg guifg=#e8b87e gui=none + if has("spell") + hi SpellBad guisp=#ee2c2c gui=undercurl + hi SpellCap guisp=#2c2cee gui=undercurl + hi SpellLocal guisp=#2ceeee gui=undercurl + hi SpellRare guisp=#ee2cee gui=undercurl + endif + hi TabLineSel guibg=bg guifg=fg gui=bold + hi Title ctermbg=0 ctermfg=15 guifg=fg gui=bold + hi WarningMsg guibg=bg guifg=#ee2c2c gui=bold + hi WildMenu guibg=#e0e000 guifg=#000000 gui=bold + + hi Comment guibg=bg guifg=#d0d0a0 gui=none + hi Constant guibg=bg guifg=#87df71 gui=none + hi Error guibg=bg guifg=#ee2c2c gui=none + hi Identifier guibg=bg guifg=#7ee0ce gui=none + hi Ignore guibg=bg guifg=bg gui=none + hi lCursor guibg=#00e700 guifg=#000000 gui=none + hi MatchParen guibg=#008b8b gui=none + hi PreProc guibg=bg guifg=#d7a0d7 gui=none + hi Special guibg=bg guifg=#e8b87e gui=none + hi Statement guibg=bg guifg=#7ec0ee gui=none + hi Todo guibg=#e0e000 guifg=#000000 gui=none + hi Type guibg=bg guifg=#f09479 gui=none + hi Underlined guibg=bg guifg=#00a0ff gui=underline + + hi htmlBold ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=bold + hi htmlItalic ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=italic + hi htmlUnderline ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=underline + hi htmlBoldItalic ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=bold,italic + hi htmlBoldUnderline ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=bold,underline + hi htmlBoldUnderlineItalic ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=bold,underline,italic + hi htmlUnderlineItalic ctermbg=0 ctermfg=15 guibg=bg guifg=fg gui=underline,italic +elseif &background == "light" + if s:moria_style == "light" + hi Normal ctermbg=15 ctermfg=0 guibg=#f0f0f0 guifg=#000000 gui=none + + hi CursorColumn guibg=#d4d4d4 gui=none + hi CursorLine guibg=#d4d4d4 gui=none + elseif s:moria_style == "white" + hi Normal ctermbg=15 ctermfg=0 guibg=#ffffff guifg=#000000 gui=none + + hi CursorColumn guibg=#dbdbdb gui=none + hi CursorLine guibg=#dbdbdb gui=none + endif + hi Cursor guibg=#883400 guifg=bg gui=none + hi DiffAdd guibg=#008b00 guifg=#ffffff gui=none + hi DiffChange guibg=#00008b guifg=#ffffff gui=none + hi DiffDelete guibg=#8b0000 guifg=#ffffff gui=none + hi DiffText guibg=#0000cd guifg=#ffffff gui=bold + hi Directory guibg=bg guifg=#0000f0 gui=none + hi ErrorMsg guibg=#ee2c2c guifg=#ffffff gui=bold + hi FoldColumn ctermbg=bg guibg=bg guifg=#506070 gui=none + hi Folded guibg=#c5c5c5 guifg=#203040 gui=none + hi IncSearch guibg=#ffcd78 gui=none + hi LineNr guifg=#506070 gui=none + hi ModeMsg ctermbg=15 ctermfg=0 guibg=bg guifg=fg gui=bold + hi MoreMsg guibg=bg guifg=#1f3f81 gui=bold + hi NonText ctermfg=8 guibg=bg guifg=#506070 gui=bold + hi Pmenu guibg=#8a9aaa guifg=#000000 gui=none + hi PmenuSbar guibg=#708090 guifg=fg gui=none + hi PmenuSel guibg=#ffff00 guifg=#000000 gui=none + hi PmenuThumb guibg=#b0c0d0 guifg=fg gui=none + hi Question guibg=bg guifg=#813f11 gui=bold + hi Search guibg=#a0f0a0 gui=none + hi SignColumn ctermbg=bg guibg=bg guifg=#506070 gui=none + hi SpecialKey guibg=bg guifg=#912f11 gui=none + if has("spell") + hi SpellBad guisp=#ee2c2c gui=undercurl + hi SpellCap guisp=#2c2cee gui=undercurl + hi SpellLocal guisp=#008b8b gui=undercurl + hi SpellRare guisp=#ee2cee gui=undercurl + endif + hi StatusLine ctermbg=0 ctermfg=15 guibg=#a0b0c0 guifg=fg gui=bold + hi StatusLineNC ctermbg=7 ctermfg=0 guibg=#b0c0d0 guifg=fg gui=none + hi TabLine guibg=#b4c4d4 guifg=fg gui=underline + hi TabLineFill guibg=#b4c4d4 guifg=fg gui=underline + hi TabLineSel guibg=bg guifg=fg gui=bold + hi Title guifg=fg gui=bold + hi VertSplit ctermbg=7 ctermfg=0 guibg=#b0c0d0 guifg=fg gui=none + if version >= 700 + hi Visual ctermbg=7 ctermfg=0 guibg=#c0d0e0 gui=none + else + hi Visual ctermbg=7 ctermfg=0 guibg=#c0d0e0 guifg=fg gui=none + endif + hi VisualNOS guibg=bg guifg=#90a0b0 gui=bold,underline + hi WarningMsg guibg=bg guifg=#ee2c2c gui=bold + hi WildMenu guibg=#ffff00 guifg=fg gui=bold + + hi Comment guibg=bg guifg=#786000 gui=none + hi Constant guibg=bg guifg=#077807 gui=none + hi Error guibg=bg guifg=#ee2c2c gui=none + hi Identifier guibg=bg guifg=#007080 gui=none + hi Ignore guibg=bg guifg=bg gui=none + hi lCursor guibg=#008000 guifg=#ffffff gui=none + hi MatchParen guibg=#00ffff gui=none + hi PreProc guibg=bg guifg=#800090 gui=none + hi Special guibg=bg guifg=#912f11 gui=none + hi Statement guibg=bg guifg=#1f3f81 gui=bold + hi Todo guibg=#ffff00 guifg=fg gui=none + hi Type guibg=bg guifg=#912f11 gui=bold + hi Underlined guibg=bg guifg=#0000cd gui=underline + + hi htmlBold guibg=bg guifg=fg gui=bold + hi htmlItalic guibg=bg guifg=fg gui=italic + hi htmlUnderline guibg=bg guifg=fg gui=underline + hi htmlBoldItalic guibg=bg guifg=fg gui=bold,italic + hi htmlBoldUnderline guibg=bg guifg=fg gui=bold,underline + hi htmlBoldUnderlineItalic guibg=bg guifg=fg gui=bold,underline,italic + hi htmlUnderlineItalic guibg=bg guifg=fg gui=underline,italic +endif diff --git a/vim/colors/oceandeep.vim b/vim/colors/oceandeep.vim new file mode 100644 index 0000000..c19b2c0 --- /dev/null +++ b/vim/colors/oceandeep.vim @@ -0,0 +1,111 @@ +" Vim color file +" Maintainer: Tom Regner +" Last Change: 2002-12-05 +" Version: 1.1 +" URL: http://vim.sourceforge.net/script.php?script_id=368 + + +""" Init +set background=dark +highlight clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name = "oceandeep" + + +""""""""\ Colors \"""""""" + + +"""" GUI Colors + +highlight Cursor gui=None guibg=PaleTurquoise3 guifg=White +highlight CursorIM gui=bold guifg=white guibg=PaleTurquoise3 +highlight Directory guifg=LightSeaGreen guibg=bg +highlight DiffAdd gui=None guifg=fg guibg=DarkCyan +highlight DiffChange gui=None guifg=fg guibg=Green4 +highlight DiffDelete gui=None guifg=fg guibg=black +highlight DiffText gui=bold guifg=fg guibg=bg +highlight ErrorMsg guifg=LightYellow guibg=FireBrick +" previously 'FillColumn': +"highlight FillColumn gui=NONE guifg=black guibg=grey60 +highlight VertSplit gui=NONE guifg=black guibg=grey60 +highlight Folded gui=bold guibg=#305060 guifg=#b0d0e0 +highlight FoldColumn gui=bold guibg=#305060 guifg=#b0d0e0 +highlight IncSearch gui=reverse guifg=fg guibg=bg +highlight LineNr gui=bold guibg=grey6 guifg=LightSkyBlue3 +highlight ModeMsg guibg=DarkGreen guifg=LightGreen +highlight MoreMsg gui=bold guifg=SeaGreen4 guibg=bg +if version < 600 + " same as SpecialKey + highlight NonText guibg=#123A4A guifg=#3D5D6D +else + " Bottom fill (use e.g. same as LineNr) + highlight NonText gui=None guibg=#103040 guifg=LightSkyBlue +endif +highlight Normal gui=None guibg=#103040 guifg=honeydew2 +highlight Question gui=bold guifg=SeaGreen2 guibg=bg +highlight Search gui=NONE guibg=LightSkyBlue4 guifg=NONE +highlight SpecialKey guibg=#103040 guifg=#324262 +highlight StatusLine gui=bold guibg=grey88 guifg=black +highlight StatusLineNC gui=NONE guibg=grey60 guifg=grey10 +highlight Title gui=bold guifg=MediumOrchid1 guibg=bg +highlight Visual gui=reverse guibg=WHITE guifg=SeaGreen +highlight VisualNOS gui=bold,underline guifg=fg guibg=bg +highlight WarningMsg gui=bold guifg=FireBrick1 guibg=bg +highlight WildMenu gui=bold guibg=Chartreuse guifg=Black + + +"""" Syntax Colors + +"highlight Comment gui=reverse guifg=#507080 +highlight Comment gui=None guifg=#507080 + +highlight Constant guifg=cyan3 guibg=bg +hi String gui=None guifg=turquoise2 guibg=bg + "hi Character gui=None guifg=Cyan guibg=bg + highlight Number gui=None guifg=Cyan guibg=bg + highlight Boolean gui=bold guifg=Cyan guibg=bg + "hi Float gui=None guifg=Cyan guibg=bg + +highlight Identifier guifg=LightSkyBlue3 +hi Function gui=None guifg=DarkSeaGreen3 guibg=bg + +highlight Statement gui=NONE guifg=LightGreen + highlight Conditional gui=None guifg=LightGreen guibg=bg + highlight Repeat gui=None guifg=SeaGreen2 guibg=bg + "hi Label gui=None guifg=LightGreen guibg=bg + highlight Operator gui=None guifg=Chartreuse guibg=bg + highlight Keyword gui=bold guifg=LightGreen guibg=bg + highlight Exception gui=bold guifg=LightGreen guibg=bg + +highlight PreProc guifg=SkyBlue1 +hi Include gui=None guifg=LightSteelBlue3 guibg=bg +hi Define gui=None guifg=LightSteelBlue2 guibg=bg +hi Macro gui=None guifg=LightSkyBlue3 guibg=bg +hi PreCondit gui=None guifg=LightSkyBlue2 guibg=bg + +highlight Type gui=NONE guifg=LightBlue +hi StorageClass gui=None guifg=LightBlue guibg=bg +hi Structure gui=None guifg=LightBlue guibg=bg +hi Typedef gui=None guifg=LightBlue guibg=bg + +highlight Special gui=bold guifg=aquamarine3 + "hi SpecialChar gui=bold guifg=White guibg=bg + "hi Tag gui=bold guifg=White guibg=bg + "hi Delimiter gui=bold guifg=White guibg=bg + "hi SpecialComment gui=bold guifg=White guibg=bg + "hi Debug gui=bold guifg=White guibg=bg + +highlight Underlined gui=underline guifg=honeydew4 guibg=bg + +highlight Ignore guifg=#204050 + +highlight Error guifg=LightYellow guibg=FireBrick + +highlight Todo guifg=Cyan guibg=#507080 + +""" OLD COLORS + + + diff --git a/vim/colors/zenburn.vim b/vim/colors/zenburn.vim new file mode 100644 index 0000000..42dacf5 --- /dev/null +++ b/vim/colors/zenburn.vim @@ -0,0 +1,133 @@ +" Vim color file +" Maintainer: Jani Nurminen +" Last Change: $Id$ +" URL: Not yet... +" License: GPL +" +" Nothing too fancy, just some alien fruit salad to keep you in the zone. +" This syntax file was designed to be used with dark environments and +" low light situations. Of course, if it works during a daybright office, go +" ahead :) +" +" Owes heavily to other Vim color files! With special mentions +" to "BlackDust", "Camo" and "Desert". +" +" To install, copy to ~/.vim/colors directory. Then :colorscheme zenburn. +" See also :help syntax +" +" CONFIGURABLE PARAMETERS: +" +" You can use the default (don't set any parameters), or you can +" set some parameters to tweak the Zenlook colours. +" +" * To get more contrast to the Visual selection, use +" +" let g:zenburn_alternate_Visual = 1 +" +" * To use alternate colouring for Error message, use +" +" let g:zenburn_alternate_Error = 1 +" +" * The new default for Include is a duller orang.e To use the original +" colouring for Include, use +" +" let g:zenburn_alternate_Include = 1 +" +" * To turn the parameter(s) back to defaults, use unlet. +" +" That's it, enjoy! +" +" TODO +" - IME colouring (CursorIM) +" - obscure syntax groups: check and colourize +" - add more groups if necessary + +set background=dark +hi clear +if exists("syntax_on") + syntax reset +endif +let g:colors_name="zenburn" + +hi Boolean guifg=#dca3a3 +hi Character guifg=#dca3a3 gui=bold +hi Comment guifg=#7f9f7f +hi Conditional guifg=#f0dfaf gui=bold +hi Constant guifg=#dca3a3 gui=bold +hi Cursor guifg=#000d18 guibg=#8faf9f gui=bold +hi Debug guifg=#dca3a3 gui=bold +hi Define guifg=#ffcfaf gui=bold +hi Delimiter guifg=#8f8f8f +hi DiffAdd guifg=#709080 guibg=#313c36 gui=bold +hi DiffChange guibg=#333333 +hi DiffDelete guifg=#333333 guibg=#464646 +hi DiffText guifg=#ecbcbc guibg=#41363c gui=bold +hi Directory guifg=#dcdccc gui=bold +hi ErrorMsg guifg=#60b48a guibg=#3f3f3f gui=bold +hi Exception guifg=#c3bf9f gui=bold +hi Float guifg=#c0bed1 +hi FoldColumn guifg=#93b3a3 guibg=#3f4040 +hi Folded guifg=#93b3a3 guibg=#3f4040 +hi Function guifg=#efef8f +hi Identifier guifg=#efdcbc +hi IncSearch guibg=#f8f893 guifg=#385f38 +hi Keyword guifg=#f0dfaf gui=bold +hi Label guifg=#dfcfaf gui=underline +hi LineNr guifg=#7f8f8f guibg=#464646 +hi Macro guifg=#ffcfaf gui=bold +hi ModeMsg guifg=#ffcfaf gui=none +hi MoreMsg guifg=#ffffff gui=bold +hi NonText guifg=#404040 +hi Normal guifg=#dcdccc guibg=#3f3f3f +hi Number guifg=#8cd0d3 +hi Operator guifg=#f0efd0 +hi PreCondit guifg=#dfaf8f gui=bold +hi PreProc guifg=#ffcfaf gui=bold +hi Question guifg=#ffffff gui=bold +hi Repeat guifg=#ffd7a7 gui=bold +hi Search guifg=#ffffe0 guibg=#385f38 +hi SpecialChar guifg=#dca3a3 gui=bold +hi SpecialComment guifg=#82a282 gui=bold +hi Special guifg=#cfbfaf +hi SpecialKey guifg=#9ece9e +hi Statement guifg=#e3ceab guibg=#3f3f3f gui=none +hi StatusLine guifg=#1e2320 guibg=#acbc90 +hi StatusLineNC guifg=#2e3330 guibg=#88b090 +hi StorageClass guifg=#c3bf9f gui=bold +hi String guifg=#cc9393 +hi Structure guifg=#efefaf gui=bold +hi Tag guifg=#dca3a3 gui=bold +hi Title guifg=#efefef guibg=#3f3f3f gui=bold +hi Todo guifg=#7faf8f guibg=#3f3f3f gui=bold +hi Typedef guifg=#dfe4cf gui=bold +hi Type guifg=#dfdfbf gui=bold +hi Underlined guifg=#dcdccc guibg=#3f3f3f gui=underline +hi VertSplit guifg=#303030 guibg=#688060 +hi VisualNOS guifg=#333333 guibg=#f18c96 gui=bold,underline +hi WarningMsg guifg=#ffffff guibg=#333333 gui=bold +hi WildMenu guibg=#2c302d guifg=#cbecd0 gui=underline + +if exists("g:zenburn_alternate_Visual") + " Visual with more contrast, thanks to Steve Hall & Cream posse + hi Visual guifg=#000000 guibg=#71d3b4 +else + " use default visual + hi Visual guifg=#233323 guibg=#71d3b4 +endif + +if exists("g:zenburn_alternate_Error") + " use a bit different Error + hi Error guifg=#ef9f9f guibg=#201010 gui=bold +else + " default + hi Error guifg=#e37170 guibg=#332323 gui=none +endif + +if exists("g:zenburn_alternate_Include") + " original setting + hi Include guifg=#ffcfaf gui=bold +else + " new, less contrasted one + hi Include guifg=#dfaf8f gui=bold +endif + " TODO check every syntax group that they're ok diff --git a/vim/doc/NERD_commenter.txt b/vim/doc/NERD_commenter.txt new file mode 100644 index 0000000..d79d278 --- /dev/null +++ b/vim/doc/NERD_commenter.txt @@ -0,0 +1,991 @@ +*NERD_commenter.txt* Plugin for commenting code + + + NERD COMMENTER REFERENCE MANUAL~ + + + + + +============================================================================== +CONTENTS *NERDCommenterContents* + + 1.Intro...................................|NERDCommenter| + 2.Functionality provided..................|NERDComFunctionality| + 2.1 Functionality Summary.............|NERDComFunctionalitySummary| + 2.2 Functionality Details.............|NERDComFunctionalityDetails| + 2.2.1 Comment map.................|NERDComComment| + 2.2.2 Nested comment map..........|NERDComNestedComment| + 2.2.3 Toggle comment map..........|NERDComToggleComment| + 2.2.4 Minimal comment map.........|NERDComMinimalComment| + 2.2.5 Invert comment map..........|NERDComInvertComment| + 2.2.6 Sexy comment map............|NERDComSexyComment| + 2.2.7 Yank comment map............|NERDComYankComment| + 2.2.8 Comment to EOL map..........|NERDComEOLComment| + 2.2.9 Append com to line map......|NERDComAppendComment| + 2.2.10 Insert comment map.........|NERDComInsertComment| + 2.2.11 Use alternate delims map...|NERDComAltDelim| + 2.2.12 Comment aligned maps.......|NERDComAlignedComment| + 2.2.13 Uncomment line map.........|NERDComUncommentLine| + 2.3 Supported filetypes...............|NERDComFiletypes| + 2.4 Sexy Comments.....................|NERDComSexyComments| + 2.5 The NERDComment function..........|NERDComNERDComment| + 3.Options.................................|NERDComOptions| + 3.1 Options summary...................|NERDComOptionsSummary| + 3.2 Options details...................|NERDComOptionsDetails| + 3.3 Default delimiter Options.........|NERDComDefaultDelims| + 4. Customising key mappings...............|NERDComMappings| + 5. Issues with the script.................|NERDComIssues| + 5.1 Delimiter detection heuristics....|NERDComHeuristics| + 5.2 Nesting issues....................|NERDComNesting| + 6.About.. ............................|NERDComAbout| + 7.Changelog...............................|NERDComChangelog| + 8.Credits.................................|NERDComCredits| + 9.License.................................|NERDComLicense| + +============================================================================== +1. Intro *NERDCommenter* + +The NERD commenter provides many different commenting operations and styles +which are invoked via key mappings and a menu. These operations are available +for most filetypes. + +There are also options that allow to tweak the commenting engine to your +taste. + +============================================================================== +2. Functionality provided *NERDComFunctionality* + +------------------------------------------------------------------------------ +2.1 Functionality summary *NERDComFunctionalitySummary* + +The following key mappings are provided by default (there is also a menu +with items corresponding to all the mappings below): + +[count],cc |NERDComComment| +Comment out the current line or text selected in visual mode. + + +[count],cn |NERDComNestedComment| +Same as ,cc but forces nesting. + + +[count],c |NERDComToggleComment| +Toggles the comment state of the selected line(s). If the topmost selected +line is commented, all selected lines are uncommented and vice versa. + + +[count],cm |NERDComMinimalComment| +Comments the given lines using only one set of multipart delimiters. + + +[count],ci |NERDComInvertComment| +Toggles the comment state of the selected line(s) individually. + + +[count],cs |NERDComSexyComment| +Comments out the selected lines ``sexily'' + + +[count],cy |NERDComYankComment| +Same as ,cc except that the commented line(s) are yanked first. + + +,c$ |NERDComEOLComment| +Comments the current line from the cursor to the end of line. + + +,cA |NERDComAppendComment| +Adds comment delimiters to the end of line and goes into insert mode between +them. + + +|NERDComInsertComment| +Adds comment delimiters at the current cursor position and inserts between. +Disabled by default. + + +,ca |NERDComAltDelim| +Switches to the alternative set of delimiters. + + +[count],cl +[count],cb |NERDComAlignedComment| +Same as |NERDComComment| except that the delimiters are aligned down the +left side (,cl) or both sides (,cb). + + +[count],cu |NERDComUncommentLine| +Uncomments the selected line(s). + +------------------------------------------------------------------------------ +2.2 Functionality details *NERDComFunctionalityDetails* + +------------------------------------------------------------------------------ +2.2.1 Comment map *NERDComComment* + +Default mapping: [count],cc +Mapped to: NERDCommenterComment +Applicable modes: normal visual visual-line visual-block. + + +Comments out the current line. If multiple lines are selected in visual-line +mode, they are all commented out. If some text is selected in visual or +visual-block mode then the script will try to comment out the exact text that +is selected using multi-part delimiters if they are available. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +2.2.2 Nested comment map *NERDComNestedComment* + +Default mapping: [count],cn +Mapped to: NERDCommenterNest +Applicable modes: normal visual visual-line visual-block. + +Performs nested commenting. Works the same as ,cc except that if a line is +already commented then it will be commented again. + +If |'NERDUsePlaceHolders'| is set then the previous comment delimiters will +be replaced by place-holder delimiters if needed. Otherwise the nested +comment will only be added if the current commenting delimiters have no right +delimiter (to avoid syntax errors) + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +Related options: +|'NERDDefaultNesting'| + +------------------------------------------------------------------------------ +2.2.3 Toggle comment map *NERDComToggleComment* + +Default mapping: [count],c +Mapped to: NERDCommenterToggle +Applicable modes: normal visual-line. + +Toggles commenting of the lines selected. The behaviour of this mapping +depends on whether the first line selected is commented or not. If so, all +selected lines are uncommented and vice versa. + +With this mapping, a line is only considered to be commented if it starts with +a left delimiter. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +2.2.4 Minimal comment map *NERDComMinimalComment* + +Default mapping: [count],cm +Mapped to: NERDCommenterMinimal +Applicable modes: normal visual-line. + +Comments the selected lines using one set of multipart delimiters if possible. + +For example: if you are programming in c and you select 5 lines and press ,cm +then a '/*' will be placed at the start of the top line and a '*/' will be +placed at the end of the last line. + +Sets of multipart comment delimiters that are between the top and bottom +selected lines are replaced with place holders (see |'NERDLPlace'|) if +|'NERDUsePlaceHolders'| is set for the current filetype. If it is not, then +the comment will be aborted if place holders are required to prevent illegal +syntax. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +2.2.5 Invert comment map *NERDComInvertComment* + +Default mapping: ,ci +Mapped to: NERDCommenterInvert +Applicable modes: normal visual-line. + +Inverts the commented state of each selected line. If the a selected line is +commented then it is uncommented and vice versa. Each line is examined and +commented/uncommented individually. + +With this mapping, a line is only considered to be commented if it starts with +a left delimiter. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +2.2.6 Sexy comment map *NERDComSexyComment* + +Default mapping: [count],cs +Mapped to: NERDCommenterSexy +Applicable modes: normal, visual-line. + +Comments the selected line(s) ``sexily''... see |NERDComSexyComments| for +a description of what sexy comments are. Can only be done on filetypes for +which there is at least one set of multipart comment delimiters specified. + +Sexy comments cannot be nested and lines inside a sexy comment cannot be +commented again. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +Related options: +|'NERDCompactSexyComs'| + +------------------------------------------------------------------------------ +2.2.7 Yank comment map *NERDComYankComment* + +Default mapping: [count],cy +Mapped to: NERDCommenterYank +Applicable modes: normal visual visual-line visual-block. + +Same as ,cc except that it yanks the line(s) that are commented first. + +------------------------------------------------------------------------------ +2.2.8 Comment to EOL map *NERDComEOLComment* + +Default mapping: ,c$ +Mapped to: NERDCommenterToEOL +Applicable modes: normal. + +Comments the current line from the current cursor position up to the end of +the line. + +------------------------------------------------------------------------------ +2.2.9 Append com to line map *NERDComAppendComment* + +Default mapping: ,cA +Mapped to: NERDCommenterAppend +Applicable modes: normal. + +Appends comment delimiters to the end of the current line and goes +to insert mode between the new delimiters. + +------------------------------------------------------------------------------ +2.2.10 Insert comment map *NERDComInsertComment* + +Default mapping: disabled by default. +Map it to: NERDCommenterInInsert +Applicable modes: insert. + +Adds comment delimiters at the current cursor position and inserts +between them. + +NOTE: prior to version 2.1.17 this was mapped to ctrl-c. To restore this +mapping add > + let NERDComInsertMap='' +< +to your vimrc. + +------------------------------------------------------------------------------ +2.2.11 Use alternate delims map *NERDComAltDelim* + +Default mapping: ,ca +Mapped to: NERDCommenterAltDelims +Applicable modes: normal. + +Changes to the alternative commenting style if one is available. For example, +if the user is editing a c++ file using // comments and they hit ,ca +then they will be switched over to /**/ comments. + +See also |NERDComDefaultDelims| + +------------------------------------------------------------------------------ +2.2.12 Comment aligned maps *NERDComAlignedComment* + +Default mappings: [count],cl [count],cb +Mapped to: NERDCommenterAlignLeft + NERDCommenterAlignBoth +Applicable modes: normal visual-line. + +Same as ,cc except that the comment delimiters are aligned on the left side or +both sides respectively. These comments are always nested if the line(s) are +already commented. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +------------------------------------------------------------------------------ +2.2.13 Uncomment line map *NERDComUncommentLine* + +Default mapping: [count],cu +Mapped to: NERDCommenterUncomment +Applicable modes: normal visual visual-line visual-block. + +Uncomments the current line. If multiple lines are selected in +visual mode then they are all uncommented. + +When uncommenting, if the line contains multiple sets of delimiters then the +``outtermost'' pair of delimiters will be removed. + +The script uses a set of heurisics to distinguish ``real'' delimiters from +``fake'' ones when uncommenting. See |NERDComIssues| for details. + +If a [count] is given in normal mode, the mapping works as though that many +lines were selected in visual-line mode. + +Related options: +|'NERDRemoveAltComs'| +|'NERDRemoveExtraSpaces'| + +------------------------------------------------------------------------------ +2.3 Supported filetypes *NERDComFiletypes* + +Filetypes that can be commented by this plugin: +abaqus abc acedb ada ahdl amiga aml ampl ant apache apachestyle asm68k asm asn +aspvbs atlas autohotkey autoit automake ave awk basic b bc bdf bib bindzone +bst btm caos catalog c cfg cg ch changelog cl clean clipper cmake conf config +context cpp crontab cs csc csp css cterm cupl csv cvs dcl debchangelog +debcontrol debsources def diff django docbk dns dosbatch dosini dot dracula +dsl dtd dtml dylan ecd eiffel elf elmfilt erlang eruby eterm expect exports +fetchmail fgl focexec form fortran foxpro fstab fvwm fx gdb gdmo geek +gentoo-package-keywords' gentoo-package-mask' gentoo-package-use' gnuplot +gtkrc haskell hb h help hercules hog html htmldjango htmlos ia64 icon idlang +idl indent inform inittab ishd iss ist jam java javascript jess jgraph +jproperties jproperties jsp kconfig kix kscript lace lex lftp lifelines lilo +lisp lite lotos lout lprolog lscript lss lua lynx m4 mail make maple masm +master matlab mel mf mib mma model moduala. modula2 modula3 monk mush muttrc +named nasm nastran natural ncf netdict netrw nqc nroff nsis objc ocaml occam +omlet omnimark openroad opl ora otl ox pascal passwd pcap pccts perl pfmain +php phtml pic pike pilrc pine plaintex plm plsql po postscr pov povini ppd +ppwiz procmail progress prolog psf ptcap python python qf radiance ratpoison r +rc readline rebol registry remind rexx robots rpl rtf ruby sa samba sas sass +sather scheme scilab screen scsh sdl sed selectbuf sgml sgmldecl sgmllnx sh +sicad simula sinda skill slang sl slrnrc sm smarty smil smith sml snnsnet +snnspat snnsres snobol4 spec specman spice sql sqlforms sqlj sqr squid st stp +strace svn systemverilog tads taglist tags tak tasm tcl terminfo tex text +plaintex texinfo texmf tf tidy tli trasys tsalt tsscl tssgm uc uil vb verilog +verilog_systemverilog vgrindefs vhdl vim viminfo virata vo_base vrml vsejcl +webmacro wget winbatch wml wvdial xdefaults xf86conf xhtml xkb xmath xml +xmodmap xpm2 xpm xslt yacc yaml z8a + +If a language is not in the list of hardcoded supported filetypes then the +&commentstring vim option is used. + +------------------------------------------------------------------------------ +2.4 Sexy Comments *NERDComSexyComments* +These are comments that use one set of multipart comment delimiters as well as +one other marker symbol. For example: > + /* + * This is a c style sexy comment + * So there! + */ + + /* This is a c style sexy comment + * So there! + * But this one is ``compact'' style */ +< +Here the multipart delimiters are /* and */ and the marker is *. + +------------------------------------------------------------------------------ +2.5 The NERDComment function *NERDComNERDComment* + +All of the NERD commenter mappings and menu items invoke a single function +which delegates the commenting work to other functions. This function is +public and has the prototype: > + function! NERDComment(isVisual, type) +< +The arguments to this function are simple: + - isVisual: if you wish to do any kind of visual comment then set this to + 1 and the function will use the '< and '> marks to find the comment + boundries. If set to 0 then the function will operate on the current + line. + - type: is used to specify what type of commenting operation is to be + performed, and it can be one of the following: "sexy", "invert", + "minimal", "toggle", "alignLeft", "alignBoth", "norm", "nested", + "toEOL", "append", "insert", "uncomment", "yank" + +For example, if you typed > + :call NERDComment(1, 'sexy') +< +then the script would do a sexy comment on the last visual selection. + + +============================================================================== +3. Options *NERDComOptions* + +------------------------------------------------------------------------------ +3.1 Options summary *NERDComOptionsSummary* + +|'loaded_nerd_comments'| Turns off the script. +|'NERDAllowAnyVisualDelims'| Allows multipart alternative delims to + be used when commenting in + visual/visual-block mode. +|'NERDBlockComIgnoreEmpty'| Forces right delims to be placed when + doing visual-block comments. +|'NERDCommentWholeLinesInVMode'| Changes behaviour of visual comments. +|'NERDCreateDefaultMappings'| Turn the default mappings on/off. +|'NERDDefaultNesting'| Tells the script to use nested comments + by default. +|'NERDMenuMode'| Specifies how the NERD commenter menu + will appear (if at all). +|'NERDLPlace'| Specifies what to use as the left + delimiter placeholder when nesting + comments. +|'NERDUsePlaceHolders'| Specifies which filetypes may use + placeholders when nesting comments. +|'NERDRemoveAltComs'| Tells the script whether to remove + alternative comment delimiters when + uncommenting. +|'NERDRemoveExtraSpaces'| Tells the script to always remove the + extra spaces when uncommenting + (regardless of whether NERDSpaceDelims + is set) +|'NERDRPlace'| Specifies what to use as the right + delimiter placeholder when nesting + comments. +|'NERDSpaceDelims'| Specifies whether to add extra spaces + around delimiters when commenting, and + whether to remove them when + uncommenting. +|'NERDCompactSexyComs'| Specifies whether to use the compact + style sexy comments. + +------------------------------------------------------------------------------ +3.3 Options details *NERDComOptionsDetails* + +To enable any of the below options you should put the given line in your +~/.vimrc + + *'loaded_nerd_comments'* +If this script is driving you insane you can turn it off by setting this +option > + let loaded_nerd_comments=1 +< +------------------------------------------------------------------------------ + *'NERDAllowAnyVisualDelims'* +Values: 0 or 1. +Default: 1. + +If set to 1 then, when doing a visual or visual-block comment (but not a +visual-line comment), the script will choose the right delimiters to use for +the comment. This means either using the current delimiters if they are +multipart or using the alternative delimiters if THEY are multipart. For +example if we are editing the following java code: > + float foo = 1221; + float bar = 324; + System.out.println(foo * bar); +< +If we are using // comments and select the "foo" and "bar" in visual-block +mode, as shown left below (where '|'s are used to represent the visual-block +boundary), and comment it then the script will use the alternative delims as +shown on the right: > + + float |foo| = 1221; float /*foo*/ = 1221; + float |bar| = 324; float /*bar*/ = 324; + System.out.println(foo * bar); System.out.println(foo * bar); +< +------------------------------------------------------------------------------ + *'NERDBlockComIgnoreEmpty'* +Values: 0 or 1. +Default: 1. + +This option affects visual-block mode commenting. If this option is turned +on, lines that begin outside the right boundary of the selection block will be +ignored. + +For example, if you are commenting this chunk of c code in visual-block mode +(where the '|'s are used to represent the visual-block boundary) > + #include + #include + #include + |int| main(){ + | | printf("SUCK THIS\n"); + | | while(1){ + | | fork(); + | | } + |} | +< +If NERDBlockComIgnoreEmpty=0 then this code will become: > + #include + #include + #include + /*int*/ main(){ + /* */ printf("SUCK THIS\n"); + /* */ while(1){ + /* */ fork(); + /* */ } + /*} */ +< +Otherwise, the code block would become: > + #include + #include + #include + /*int*/ main(){ + printf("SUCK THIS\n"); + while(1){ + fork(); + } + /*} */ +< +------------------------------------------------------------------------------ + *'NERDCommentWholeLinesInVMode'* +Values: 0, 1 or 2. +Default: 0. + +By default the script tries to comment out exactly what is selected in visual +mode (v). For example if you select and comment the following c code (using | +to represent the visual boundary): > + in|t foo = 3; + int bar =| 9; + int baz = foo + bar; +< +This will result in: > + in/*t foo = 3;*/ + /*int bar =*/ 9; + int baz = foo + bar; +< +But some people prefer it if the whole lines are commented like: > + /*int foo = 3;*/ + /*int bar = 9;*/ + int baz = foo + bar; +< +If you prefer the second option then stick this line in your vimrc: > + let NERDCommentWholeLinesInVMode=1 +< + +If the filetype you are editing only has no multipart delimiters (for example +a shell script) and you hadnt set this option then the above would become > + in#t foo = 3; + #int bar = 9; +< +(where # is the comment delimiter) as this is the closest the script can +come to commenting out exactly what was selected. If you prefer for whole +lines to be commented out when there is no multipart delimiters but the EXACT +text that was selected to be commented out if there IS multipart delimiters +then stick the following line in your vimrc: > + let NERDCommentWholeLinesInVMode=2 +< + +Note that this option does not affect the behaviour of commenting in +|visual-block| mode. + +------------------------------------------------------------------------------ + *'NERDCreateDefaultMappings'* +Values: 0 or 1. +Default: 1. + +If set to 0, none of the default mappings will be created. + +See also |NERDComMappings|. + +------------------------------------------------------------------------------ + *'NERDRemoveAltComs'* +Values: 0 or 1. +Default: 1. + +When uncommenting a line (for a filetype with an alternative commenting style) +this option tells the script whether to look for, and remove, comment +delimiters of the alternative style. + +For example, if you are editing a c++ file using // style comments and you go +,cu on this line: > + /* This is a c++ comment baby! */ +< +It will not be uncommented if the NERDRemoveAltComs is set to 0. + +------------------------------------------------------------------------------ + *'NERDRemoveExtraSpaces'* +Values: 0 or 1. +Default: 1. + +By default, the NERD commenter will remove spaces around comment delimiters if +either: +1. |'NERDSpaceDelims'| is set to 1. +2. NERDRemoveExtraSpaces is set to 1. + +This means that if we have the following lines in a c code file: > + /* int foo = 5; */ + /* int bar = 10; */ + int baz = foo + bar +< +If either of the above conditions hold then if these lines are uncommented +they will become: > + int foo = 5; + int bar = 10; + int baz = foo + bar +< +Otherwise they would become: > + int foo = 5; + int bar = 10; + int baz = foo + bar +< +If you want the spaces to be removed only if |'NERDSpaceDelims'| is set then +set NERDRemoveExtraSpaces to 0. + +------------------------------------------------------------------------------ + *'NERDLPlace'* + *'NERDRPlace'* +Values: arbitrary string. +Default: + NERDLPlace: "[>" + NERDRPlace: "<]" + +These options are used to control the strings used as place-holder delimiters. +Place holder delimiters are used when performing nested commenting when the +filetype supports commenting styles with both left and right delimiters. +To set these options use lines like: > + let NERDLPlace="FOO" + let NERDRPlace="BAR" +< +Following the above example, if we have line of c code: > + /* int horse */ +< +and we comment it with ,cn it will be changed to: > + /*FOO int horse BAR*/ +< +When we uncomment this line it will go back to what it was. + +------------------------------------------------------------------------------ + *'NERDMenuMode'* +Values: 0, 1, 2, 3. +Default: 3 + +This option can take 4 values: + "0": Turns the menu off. + "1": Turns the 'comment' menu on with no menu shortcut. + "2": Turns the 'comment 'menu on with -c as the shortcut. + "3": Turns the 'Plugin -> comment' menu on with -c as the shortcut. + +------------------------------------------------------------------------------ + *'NERDUsePlaceHolders'* +Values: 0 or 1. +Default 1. + +This option is used to specify whether place-holder delimiters should be used +when creating a nested comment. + +------------------------------------------------------------------------------ + *'NERDSpaceDelims'* +Values: 0 or 1. +Default 0. + +Some people prefer a space after the left delimiter and before the right +delimiter like this: > + /* int foo=2; */ +< +as opposed to this: > + /*int foo=2;*/ +< +If you want spaces to be added then set NERDSpaceDelims to 1 in your vimrc. + +See also |'NERDRemoveExtraSpaces'|. + +------------------------------------------------------------------------------ + *'NERDCompactSexyComs'* +Values: 0 or 1. +Default 0. + +Some people may want their sexy comments to be like this: > + /* Hi There! + * This is a sexy comment + * in c */ +< +As opposed to like this: > + /* + * Hi There! + * This is a sexy comment + * in c + */ +< +If this option is set to 1 then the top style will be used. + +------------------------------------------------------------------------------ + *'NERDDefaultNesting'* +Values: 0 or 1. +Default 1. + +When this option is set to 1, comments are nested automatically. That is, if +you hit ,cc on a line that is already commented it will be commented again + +------------------------------------------------------------------------------ +3.3 Default delimiter customisation *NERDComDefaultDelims* + +If you want the NERD commenter to use the alternative delimiters for a +specific filetype by default then put a line of this form into your vimrc: > + let NERD__alt_style=1 +< +Example: java uses // style comments by default, but you want it to default to +/* */ style comments instead. You would put this line in your vimrc: > + let NERD_java_alt_style=1 +< + +See |NERDComAltDelim| for switching commenting styles at runtime. + +============================================================================== +4. Key mapping customisation *NERDComMappings* + +To change a mapping just map another key combo to the internal mapping. +For example, to remap the |NERDComComment| mapping to ",omg" you would put +this line in your vimrc: > + map ,omg NERDCommenterComment +< +This will stop the corresponding default mappings from being created. + +See the help for the mapping in question to see which mapping to +map to. + +See also |'NERDCreateDefaultMappings'|. + +============================================================================== +5. Issues with the script *NERDComIssues* + + +------------------------------------------------------------------------------ +5.1 Delimiter detection heuristics *NERDComHeuristics* + +Heuristics are used to distinguish the real comment delimiters + +Because we have comment mappings that place delimiters in the middle of lines, +removing comment delimiters is a bit tricky. This is because if comment +delimiters appear in a line doesnt mean they really ARE delimiters. For +example, Java uses // comments but the line > + System.out.println("//"); +< +clearly contains no real comment delimiters. + +To distinguish between ``real'' comment delimiters and ``fake'' ones we use a +set of heuristics. For example, one such heuristic states that any comment +delimiter that has an odd number of non-escaped " characters both preceding +and following it on the line is not a comment because it is probably part of a +string. These heuristics, while usually pretty accurate, will not work for all +cases. + +------------------------------------------------------------------------------ +5.2 Nesting issues *NERDComNesting* + +If we have some line of code like this: > + /*int foo */ = /*5 + 9;*/ +< +This will not be uncommented legally. The NERD commenter will remove the +"outter most" delimiters so the line will become: > + int foo */ = /*5 + 9; +< +which almost certainly will not be what you want. Nested sets of comments will +uncomment fine though. Eg: > + /*int/* foo =*/ 5 + 9;*/ +< +will become: > + int/* foo =*/ 5 + 9; +< +(Note that in the above examples I have deliberately not used place holders +for simplicity) + +============================================================================== +6. About *NERDComAbout* + +The author of the NERD commenter is Martyzillatron --- the half robot, half +dinosaur bastard son of Megatron and Godzilla. He enjoys destroying +metropolises and eating tourist busses. + +Drop him a line at martin_grenfell at msn.com. He would love to hear from you. +its a lonely life being the worlds premier terror machine. How would you feel +if your face looked like a toaster and a t-rex put together? :( + +The latest stable versions can be found at + http://www.vim.org/scripts/script.php?script_id=1218 + +The latest dev versions are on github + http://github.com/scrooloose/nerdcommenter + +============================================================================== +8. Changelog *NERDComChangelog* + +2.2.2 + - remove the NERDShutup option and the message is suppresses, this makes + the plugin silently rely on &commentstring for unknown filetypes. + - add support for dhcpd, limits, ntp, resolv, rgb, sysctl, udevconf and + udevrules. Thanks to Thilo Six. + - match filetypes case insensitively + - add support for mp (metapost), thanks to Andrey Skvortsov. + - add support for htmlcheetah, thanks to Simon Hengel. + - add support for javacc, thanks to Matt Tolton. + - make <%# %> the default delims for eruby, thanks to tpope. + - add support for javascript.jquery, thanks to Ivan Devat. + - add support for cucumber and pdf. Fix sass and railslog delims, + thanks to tpope + +2.2.1 + - add support for newlisp and clojure, thanks to Matthew Lee Hinman. + - fix automake comments, thanks to Elias Pipping + - make haml comments default to -# with / as the alternative delimiter, + thanks to tpope + - add support for actionscript and processing thanks to Edwin Benavides + - add support for ps1 (powershell), thanks to Jason Mills + - add support for hostsaccess, thanks to Thomas Rowe + - add support for CVScommit + - add support for asciidoc, git and gitrebase. Thanks to Simon Ruderich. + - use # for gitcommit comments, thanks to Simon Ruderich. + - add support for mako and genshi, thanks to Keitheis. + - add support for conkyrc, thanks to David + - add support for SVNannotate, thanks to Miguel Jaque Barbero. + - add support for sieve, thanks to Stefan Walk + - add support for objj, thanks to Adam Thorsen. + +2.2.0 + - rewrote the mappings system to be more "standard". + - removed all the mapping options. Now, mappings to mappings are + used + - see :help NERDComMappings, and :help NERDCreateDefaultMappings for + more info + - remove "prepend comments" and "right aligned comments". + - add support for applescript, calbire, man, SVNcommit, potwiki, txt2tags and SVNinfo. + Thanks to nicothakis, timberke, sgronblo, mntnoe, Bernhard Grotz, John + O'Shea, François and Giacomo Mariani respectively. + - bugfix for haskell delimiters. Thanks to mntnoe. +2.1.18 + - add support for llvm. Thanks to nicothakis. + - add support for xquery. Thanks to Phillip Kovalev. +2.1.17 + - fixed haskell delimiters (hackily). Thanks to Elias Pipping. + - add support for mailcap. Thanks to Pascal Brueckner. + - add support for stata. Thanks to Jerónimo Carballo. + - applied a patch from ewfalor to fix an error in the help file with the + NERDMapleader doc + - disable the insert mode ctrl-c mapping by default, see :help + NERDComInsertComment if you wish to restore it + +============================================================================== +8. Credits *NERDComCredits* + +Thanks to the follow people for suggestions and patches: + +Nick Brettell +Matthew Hawkins +Mathieu Clabaut +Greg Searle +Nguyen +Litchi +Jorge Scandaliaris +Shufeng Zheng +Martin Stubenschrott +Markus Erlmann +Brent Rice +Richard Willis +Igor Prischepoff +Harry +David Bourgeois +Eike Von Seggern +Torsten Blix +Alexander Bosecke +Stefano Zacchiroli +Norick Chen +Joseph Barker +Gary Church +Tim Carey-Smith +Markus Klinik +Anders +Seth Mason +James Hales +Heptite +Cheng Fang +Yongwei Wu +David Miani +Jeremy Hinegardner +Marco +Ingo Karkat +Zhang Shuhan +tpope +Ben Schmidt +David Fishburn +Erik Falor +JaGoTerr +Elias Pipping +mntnoe +Mark S. + + +Thanks to the following people for sending me new filetypes to support: + +The hackers The filetypes~ +Sam R verilog +Jonathan Derque context, plaintext and mail +Vigil fetchmail +Michael Brunner kconfig +Antono Vasiljev netdict +Melissa Reid omlet +Ilia N Ternovich quickfix +John O'Shea RTF, SVNcommitlog and vcscommit, SVNCommit +Anders occam +Mark Woodward csv +fREW gentoo-package-mask, + gentoo-package-keywords, + gentoo-package-use, and vo_base +Alexey verilog_systemverilog, systemverilog +Lizendir fstab +Michael Böhler autoit, autohotkey and docbk +Aaron Small cmake +Ramiro htmldjango and django +Stefano Zacchiroli debcontrol, debchangelog, mkd +Alex Tarkovsky ebuild and eclass +Jorge Rodrigues gams +Rainer Müller Objective C +Jason Mills Groovy, ps1 +Normandie Azucena vera +Florian Apolloner ldif +David Fishburn lookupfile +Niels Aan de Brugh rst +Don Hatlestad ahk +Christophe Benz Desktop and xsd +Eyolf Østrem lilypond, bbx and lytex +Ingo Karkat dosbatch +Nicolas Weber markdown, objcpp +tinoucas gentoo-conf-d +Greg Weber D, haml +Bruce Sherrod velocity +timberke cobol, calibre +Aaron Schaefer factor +Mr X asterisk, mplayerconf +Kuchma Michael plsql +Brett Warneke spectre +Pipp lhaskell +Renald Buter scala +Vladimir Lomov asymptote +Marco mrxvtrc, aap +nicothakis SVNAnnotate, CVSAnnotate, SVKAnnotate, + SVNdiff, gitAnnotate, gitdiff, dtrace + llvm, applescript +Chen Xing Wikipedia +Jacobo Diaz dakota, patran +Li Jin gentoo-env-d, gentoo-init-d, + gentoo-make-conf, grub, modconf, sudoers +SpookeyPeanut rib +Greg Jandl pyrex/cython +Christophe Benz services, gitcommit +A Pontus vimperator +Stromnov slice, bzr +Martin Kustermann pamconf +Indriði Einarsson mason +Chris map +Krzysztof A. Adamski group +Pascal Brueckner mailcap +Jerónimo Carballo stata +Phillip Kovalev xquery +Bernhard Grotz potwiki +sgronblo man +François txt2tags +Giacomo Mariani SVNinfo +Matthew Lee Hinman newlisp, clojure +Elias Pipping automake +Edwin Benavides actionscript, processing +Thomas Rowe hostsaccess +Simon Ruderich asciidoc, git, gitcommit, gitrebase +Keitheis mako, genshi +David conkyrc +Miguel Jaque Barbero SVNannotate +Stefan Walk sieve +Adam Thorsen objj +Thilo Six dhcpd, limits, ntp, resolv, rgb, sysctl, + udevconf, udevrules +Andrey Skvortsov mp +Simon Hengel htmlcheetah +Matt Tolton javacc +Ivan Devat javascript.jquery +tpope cucumber,pdf +============================================================================== +9. License *NERDComLicense* + +The NERD commenter is released under the wtfpl. +See http://sam.zoy.org/wtfpl/COPYING. diff --git a/vim/doc/NERD_tree.txt b/vim/doc/NERD_tree.txt new file mode 100644 index 0000000..95f4c54 --- /dev/null +++ b/vim/doc/NERD_tree.txt @@ -0,0 +1,1077 @@ +*NERD_tree.txt* A tree explorer plugin that owns your momma! + + + + omg its ... ~ + + ________ ________ _ ____________ ____ __________ ____________~ + /_ __/ / / / ____/ / | / / ____/ __ \/ __ \ /_ __/ __ \/ ____/ ____/~ + / / / /_/ / __/ / |/ / __/ / /_/ / / / / / / / /_/ / __/ / __/ ~ + / / / __ / /___ / /| / /___/ _, _/ /_/ / / / / _, _/ /___/ /___ ~ + /_/ /_/ /_/_____/ /_/ |_/_____/_/ |_/_____/ /_/ /_/ |_/_____/_____/ ~ + + + Reference Manual~ + + + + +============================================================================== +CONTENTS *NERDTree-contents* + + 1.Intro...................................|NERDTree| + 2.Functionality provided..................|NERDTreeFunctionality| + 2.1.Global commands...................|NERDTreeGlobalCommands| + 2.2.Bookmarks.........................|NERDTreeBookmarks| + 2.2.1.The bookmark table..........|NERDTreeBookmarkTable| + 2.2.2.Bookmark commands...........|NERDTreeBookmarkCommands| + 2.2.3.Invalid bookmarks...........|NERDTreeInvalidBookmarks| + 2.3.NERD tree mappings................|NERDTreeMappings| + 2.4.The filesystem menu...............|NERDTreeFilesysMenu| + 3.Options.................................|NERDTreeOptions| + 3.1.Option summary....................|NERDTreeOptionSummary| + 3.2.Option details....................|NERDTreeOptionDetails| + 4.Hacking the NERD tree...................|NERDTreeHacking| + 5.About...................................|NERDTreeAbout| + 6.Changelog...............................|NERDTreeChangelog| + 7.Credits.................................|NERDTreeCredits| + 8.License.................................|NERDTreeLicense| + +============================================================================== +1. Intro *NERDTree* + +What is this "NERD tree"?? + +The NERD tree allows you to explore your filesystem and to open files and +directories. It presents the filesystem to you in the form of a tree which you +manipulate with the keyboard and/or mouse. It also allows you to perform +simple filesystem operations. + +The following features and functionality are provided by the NERD tree: + * Files and directories are displayed in a hierarchical tree structure + * Different highlighting is provided for the following types of nodes: + * files + * directories + * sym-links + * windows .lnk files + * read-only files + * executable files + * Many (customisable) mappings are provided to manipulate the tree: + * Mappings to open/close/explore directory nodes + * Mappings to open files in new/existing windows/tabs + * Mappings to change the current root of the tree + * Mappings to navigate around the tree + * ... + * Directories and files can be bookmarked. + * Most NERD tree navigation can also be done with the mouse + * Filtering of tree content (can be toggled at runtime) + * custom file filters to prevent e.g. vim backup files being displayed + * optional displaying of hidden files (. files) + * files can be "turned off" so that only directories are displayed + * A textual filesystem menu is provided which allows you to + create/delete/move file and directory nodes as well as copy (for + supported OSs) + * The position and size of the NERD tree window can be customised + * The order in which the nodes in the tree are listed can be customised. + * A model of your filesystem is created/maintained as you explore it. This + has several advantages: + * All filesystem information is cached and is only re-read on demand + * If you revisit a part of the tree that you left earlier in your + session, the directory nodes will be opened/closed as you left them + * The script remembers the cursor position and window position in the NERD + tree so you can toggle it off (or just close the tree window) and then + reopen it (with NERDTreeToggle) the NERD tree window will appear exactly + as you left it + * You can have a separate NERD tree for each tab, share trees across tabs, + or a mix of both. + * By default the script overrides the default file browser (netw), so if + you :edit a directory a (slighly modified) NERD tree will appear in the + current window + +============================================================================== +2. Functionality provided *NERDTreeFunctionality* + +------------------------------------------------------------------------------ +2.1. Global Commands *NERDTreeGlobalCommands* + +:NERDTree [ | ] *:NERDTree* + Opens a fresh NERD tree. The root of the tree depends on the argument + given. There are 3 cases: If no argument is given, the current directory + will be used. If a directory is given, that will be used. If a bookmark + name is given, the corresponding directory will be used. For example: > + :NERDTree /home/marty/vim7/src + :NERDTree foo (foo is the name of a bookmark) +< +:NERDTreeFromBookmark *:NERDTreeFromBookmark* + Opens a fresh NERD tree with the root initialized to the dir for + . This only reason to use this command over :NERDTree is for + the completion (which is for bookmarks rather than directories). + +:NERDTreeToggle [ | ] *:NERDTreeToggle* + If a NERD tree already exists for this tab, it is reopened and rendered + again. If no NERD tree exists for this tab then this command acts the + same as the |:NERDTree| command. + +:NERDTreeMirror *:NERDTreeMirror* + Shares an existing NERD tree, from another tab, in the current tab. + Changes made to one tree are reflected in both as they are actually the + same buffer. + + If only one other NERD tree exists, that tree is automatically mirrored. If + more than one exists, the script will ask which tree to mirror. + +:NERDTreeClose *:NERDTreeClose* + Close the NERD tree in this tab. + +------------------------------------------------------------------------------ +2.2. Bookmarks *NERDTreeBookmarks* + +Bookmarks in the NERD tree are a way to tag files or directories of interest. +For example, you could use bookmarks to tag all of your project directories. + +------------------------------------------------------------------------------ +2.2.1. The Bookmark Table *NERDTreeBookmarkTable* + +If the bookmark table is active (see |NERDTree-B| and +|'NERDTreeShowBookmarks'|), it will be rendered above the tree. You can double +click bookmarks or use the |NERDTree-o| mapping to activate them. See also, +|NERDTree-t| and |NERDTree-T| + +------------------------------------------------------------------------------ +2.2.2. Bookmark commands *NERDTreeBookmarkCommands* + +Note that the following commands are only available in the NERD tree buffer. + +:Bookmark + Bookmark the current node as . If there is already a + bookmark, it is overwritten. must not contain spaces. + +:BookmarkToRoot + Make the directory corresponding to the new root. If a treenode + corresponding to is already cached somewhere in the tree then + the current tree will be used, otherwise a fresh tree will be opened. + Note that if points to a file then its parent will be used + instead. + +:RevealBookmark + If the node is cached under the current root then it will be revealed + (i.e. directory nodes above it will be opened) and the cursor will be + placed on it. + +:OpenBookmark + must point to a file. The file is opened as though |NERDTree-o| + was applied. If the node is cached under the current root then it will be + revealed and the cursor will be placed on it. + +:ClearBookmarks [] + Remove all the given bookmarks. If no bookmarks are given then remove all + bookmarks on the current node. + +:ClearAllBookmarks + Remove all bookmarks. + +:ReadBookmarks + Re-read the bookmarks in the |'NERDTreeBookmarksFile'|. + +See also |:NERDTree| and |:NERDTreeFromBookmark|. + +------------------------------------------------------------------------------ +2.2.3. Invalid Bookmarks *NERDTreeInvalidBookmarks* + +If invalid bookmarks are detected, the script will issue an error message and +the invalid bookmarks will become unavailable for use. + +These bookmarks will still be stored in the bookmarks file (see +|'NERDTreeBookmarksFile'|), down the bottom. There will always be a blank line +after the valid bookmarks but before the invalid ones. + +Each line in the bookmarks file represents one bookmark. The proper format is: + + +After you have corrected any invalid bookmarks, either restart vim, or go +:ReadBookmarks from the NERD tree window. + +------------------------------------------------------------------------------ +2.3. NERD tree Mappings *NERDTreeMappings* + +Default Description~ help-tag~ +Key~ + +o.......Open files, directories and bookmarks....................|NERDTree-o| +go......Open selected file, but leave cursor in the NERDTree.....|NERDTree-go| +t.......Open selected node/bookmark in a new tab.................|NERDTree-t| +T.......Same as 't' but keep the focus on the current tab........|NERDTree-T| +i.......Open selected file in a split window.....................|NERDTree-i| +gi......Same as i, but leave the cursor on the NERDTree..........|NERDTree-gi| +s.......Open selected file in a new vsplit.......................|NERDTree-s| +gs......Same as s, but leave the cursor on the NERDTree..........|NERDTree-gs| +!.......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.......Edit the current dif.....................................|NERDTree-e| + +double-click.......same as the |NERDTree-o| map. +middle-click.......same as |NERDTree-i| for files, same as + |NERDTree-e| for dirs. + +D.......Delete the current bookmark .............................|NERDTree-D| + +P.......Jump to the root node....................................|NERDTree-P| +p.......Jump to current nodes parent.............................|NERDTree-p| +K.......Jump up inside directories at the current tree depth.....|NERDTree-K| +J.......Jump down inside directories at the current tree depth...|NERDTree-J| +...Jump down to the next sibling of the current directory...|NERDTree-c-j| +...Jump up to the previous sibling of the current directory.|NERDTree-c-k| + +C.......Change the tree root to the selected dir.................|NERDTree-C| +u.......Move the tree root up one directory......................|NERDTree-u| +U.......Same as 'u' except the old root node is left open........|NERDTree-U| +r.......Recursively refresh the current directory................|NERDTree-r| +R.......Recursively refresh the current root.....................|NERDTree-R| +m.......Display the filesystem menu..............................|NERDTree-m| +cd......Change the CWD to the dir of the selected node...........|NERDTree-cd| + +I.......Toggle whether hidden files displayed....................|NERDTree-I| +f.......Toggle whether the file filters are used.................|NERDTree-f| +F.......Toggle whether files are displayed.......................|NERDTree-F| +B.......Toggle whether the bookmark table is displayed...........|NERDTree-B| + +q.......Close the NERDTree window................................|NERDTree-q| +?.......Toggle the display of the quick help.....................|NERDTree-?| + +------------------------------------------------------------------------------ + *NERDTree-o* +Default key: o +Map option: NERDTreeMapActivateNode +Applies to: files and directories. + +If a file node is selected, it is opened in the previous window. + +If a directory is selected it is opened or closed depending on its current +state. + +If a bookmark that links to a directory is selected then that directory +becomes the new root. + +If a bookmark that links to a file is selected then that file is opened in the +previous window. + +------------------------------------------------------------------------------ + *NERDTree-go* +Default key: go +Map option: None +Applies to: files. + +If a file node is selected, it is opened in the previous window, but the +cursor does not move. + +The key combo for this mapping is always "g" + NERDTreeMapActivateNode (see +|NERDTree-o|). + +------------------------------------------------------------------------------ + *NERDTree-t* +Default key: t +Map option: NERDTreeMapOpenInTab +Applies to: files and directories. + +Opens the selected file in a new tab. If a directory is selected, a fresh +NERD Tree for that directory is opened in a new tab. + +If a bookmark which points to a directory is selected, open a NERD tree for +that directory in a new tab. If the bookmark points to a file, open that file +in a new tab. + +------------------------------------------------------------------------------ + *NERDTree-T* +Default key: T +Map option: NERDTreeMapOpenInTabSilent +Applies to: files and directories. + +The same as |NERDTree-t| except that the focus is kept in the current tab. + +------------------------------------------------------------------------------ + *NERDTree-i* +Default key: i +Map option: NERDTreeMapOpenSplit +Applies to: files. + +Opens the selected file in a new split window and puts the cursor in the new +window. + +------------------------------------------------------------------------------ + *NERDTree-gi* +Default key: gi +Map option: None +Applies to: files. + +The same as |NERDTree-i| except that the cursor is not moved. + +The key combo for this mapping is always "g" + NERDTreeMapOpenSplit (see +|NERDTree-i|). + +------------------------------------------------------------------------------ + *NERDTree-s* +Default key: s +Map option: NERDTreeMapOpenVSplit +Applies to: files. + +Opens the selected file in a new vertically split window and puts the cursor in +the new window. + +------------------------------------------------------------------------------ + *NERDTree-gs* +Default key: gs +Map option: None +Applies to: files. + +The same as |NERDTree-s| except that the cursor is not moved. + +The key combo for this mapping is always "g" + NERDTreeMapOpenVSplit (see +|NERDTree-s|). + +------------------------------------------------------------------------------ + *NERDTree-!* +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 its contents are not +cached. This is handy, especially if you have .svn directories. + +------------------------------------------------------------------------------ + *NERDTree-x* +Default key: x +Map option: NERDTreeMapCloseDir +Applies to: files and directories. + +Closes the parent of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-X* +Default key: X +Map option: NERDTreeMapCloseChildren +Applies to: directories. + +Recursively closes all children of the selected directory. + +Tip: To quickly "reset" the tree, use |NERDTree-P| with this mapping. + +------------------------------------------------------------------------------ + *NERDTree-e* +Default key: e +Map option: NERDTreeMapOpenExpl +Applies to: files and directories. + +|:edit|s the selected directory, or the selected file's directory. This could +result in a NERD tree or a netrw being opened, depending on +|'NERDTreeHijackNetrw'|. + +------------------------------------------------------------------------------ + *NERDTree-D* +Default key: D +Map option: NERDTreeMapDeleteBookmark +Applies to: lines in the bookmarks table + +Deletes the currently selected bookmark. + +------------------------------------------------------------------------------ + *NERDTree-P* +Default key: P +Map option: NERDTreeMapJumpRoot +Applies to: no restrictions. + +Jump to the tree root. + +------------------------------------------------------------------------------ + *NERDTree-p* +Default key: p +Map option: NERDTreeMapJumpParent +Applies to: files and directories. + +Jump to the parent node of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-K* +Default key: K +Map option: NERDTreeMapJumpFirstChild +Applies to: files and directories. + +Jump to the first child of the current nodes parent. + +If the cursor is already on the first node then do the following: + * loop back thru the siblings of the current nodes parent until we find an + open dir with children + * go to the first child of that node + +------------------------------------------------------------------------------ + *NERDTree-J* +Default key: J +Map option: NERDTreeMapJumpLastChild +Applies to: files and directories. + +Jump to the last child of the current nodes parent. + +If the cursor is already on the last node then do the following: + * loop forward thru the siblings of the current nodes parent until we find + an open dir with children + * go to the last child of that node + +------------------------------------------------------------------------------ + *NERDTree-c-j* +Default key: +Map option: NERDTreeMapJumpNextSibling +Applies to: files and directories. + +Jump to the next sibling of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-c-k* +Default key: +Map option: NERDTreeMapJumpPrevSibling +Applies to: files and directories. + +Jump to the previous sibling of the selected node. + +------------------------------------------------------------------------------ + *NERDTree-C* +Default key: C +Map option: NERDTreeMapChdir +Applies to: directories. + +Make the selected directory node the new tree root. If a file is selected, its +parent is used. + +------------------------------------------------------------------------------ + *NERDTree-u* +Default key: u +Map option: NERDTreeMapUpdir +Applies to: no restrictions. + +Move the tree root up a dir (like doing a "cd .."). + +------------------------------------------------------------------------------ + *NERDTree-U* +Default key: U +Map option: NERDTreeMapUpdirKeepOpen +Applies to: no restrictions. + +Like |NERDTree-u| except that the old tree root is kept open. + +------------------------------------------------------------------------------ + *NERDTree-r* +Default key: r +Map option: NERDTreeMapRefresh +Applies to: files and directories. + +If a dir is selected, recursively refresh that dir, i.e. scan the filesystem +for changes and represent them in the tree. + +If a file node is selected then the above is done on it's parent. + +------------------------------------------------------------------------------ + *NERDTree-R* +Default key: R +Map option: NERDTreeMapRefreshRoot +Applies to: no restrictions. + +Recursively refresh the tree root. + +------------------------------------------------------------------------------ + *NERDTree-m* +Default key: m +Map option: NERDTreeMapFilesystemMenu +Applies to: files and directories. + +Display the filesystem menu. See |NERDTreeFilesysMenu| for details. + +------------------------------------------------------------------------------ + *NERDTree-I* +Default key: I +Map option: NERDTreeMapToggleHidden +Applies to: no restrictions. + +Toggles whether hidden files (i.e. "dot files") are displayed. + +------------------------------------------------------------------------------ + *NERDTree-f* +Default key: f +Map option: NERDTreeMapToggleFilters +Applies to: no restrictions. + +Toggles whether file filters are used. See |'NERDTreeIgnore'| for details. + +------------------------------------------------------------------------------ + *NERDTree-F* +Default key: F +Map option: NERDTreeMapToggleFiles +Applies to: no restrictions. + +Toggles whether file nodes are displayed. + +------------------------------------------------------------------------------ + *NERDTree-B* +Default key: B +Map option: NERDTreeMapToggleBookmarks +Applies to: no restrictions. + +Toggles whether the bookmarks table is displayed. + +------------------------------------------------------------------------------ + *NERDTree-q* +Default key: q +Map option: NERDTreeMapQuit +Applies to: no restrictions. + +Closes the NERDtree window. + +------------------------------------------------------------------------------ + *NERDTree-?* +Default key: ? +Map option: NERDTreeMapHelp +Applies to: no restrictions. + +Toggles whether the quickhelp is displayed. + +------------------------------------------------------------------------------ +2.3. The filesystem menu *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 four supported +operations: > + 1. Adding nodes. + 2. Move nodes. + 3. Deleting nodes. + 3. Copying 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. Move nodes: +To move/rename a node, put the cursor on it and select the 'move' option from +the filesystem menu. Enter the new location for the node and it will be +moved. 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. + +4. Copying nodes: +To copy a node put the cursor on it and select the 'copy' option from the +filesystem menu. Enter the new location and you're done. Note: copying is +currently only supported for *nix operating systems. If someone knows a +one line copying command for windows that doesnt require user confirmation +then id be grateful if you'd email me. + +============================================================================== +3. Customisation *NERDTreeOptions* + + +------------------------------------------------------------------------------ +3.1. Customisation summary *NERDTreeOptionSummary* + +The script provides the following options that can customise the behaviour the +NERD tree. These options should be set in your vimrc. + +|'loaded_nerd_tree'| Turns off the script. + +|'NERDChristmasTree'| Tells the NERD tree to make itself colourful + and pretty. + +|'NERDTreeAutoCenter'| Controls whether the NERD tree window centers + when the cursor moves within a specified + distance to the top/bottom of the window. +|'NERDTreeAutoCenterThreshold'| Controls the sensitivity of autocentering. + +|'NERDTreeCaseSensitiveSort'| Tells the NERD tree whether to be case + sensitive or not when sorting nodes. + +|'NERDTreeChDirMode'| Tells the NERD tree if/when it should change + vim's current working directory. + +|'NERDTreeHighlightCursorline'| Tell the NERD tree whether to highlight the + current cursor line. + +|'NERDTreeHijackNetrw'| Tell the NERD tree whether to replace the netrw + autocommands for exploring local directories. + +|'NERDTreeIgnore'| Tells the NERD tree which files to ignore. + +|'NERDTreeBookmarksFile'| Where the bookmarks are stored. + +|'NERDTreeMouseMode'| Tells the NERD tree how to handle mouse + clicks. + +|'NERDTreeQuitOnOpen'| Closes the tree window after opening a file. + +|'NERDTreeShowBookmarks'| Tells the NERD tree whether to display the + bookmarks table on startup. + +|'NERDTreeShowFiles'| Tells the NERD tree whether to display files + in the tree on startup. + +|'NERDTreeShowHidden'| Tells the NERD tree whether to display hidden + files on startup. + +|'NERDTreeShowLineNumbers'| Tells the NERD tree whether to display line + numbers in the tree window. + +|'NERDTreeSortOrder'| Tell the NERD tree how to sort the nodes in + the tree. + +|'NERDTreeStatusline'| Set a statusline for NERD tree windows. + +|'NERDTreeWinPos'| Tells the script where to put the NERD tree + window. + +|'NERDTreeWinSize'| Sets the window size when the NERD tree is + opened. + +------------------------------------------------------------------------------ +3.2. Customisation details *NERDTreeOptionDetails* + +To enable any of the below options you should put the given line in your +~/.vimrc + + *'loaded_nerd_tree'* +If this plugin is making you feel homicidal, it may be a good idea to turn it +off with this line in your vimrc: > + let loaded_nerd_tree=1 +< +------------------------------------------------------------------------------ + *'NERDChristmasTree'* +Values: 0 or 1. +Default: 1. + +If this option is set to 1 then some extra syntax highlighting elements are +added to the nerd tree to make it more colourful. + +Set it to 0 for a more vanilla looking tree. + +------------------------------------------------------------------------------ + *'NERDTreeAutoCenter'* +Values: 0 or 1. +Default: 1 + +If set to 1, the NERD tree window will center around the cursor if it moves to +within |'NERDTreeAutoCenterThreshold'| lines of the top/bottom of the window. + +This is ONLY done in response to tree navigation mappings, +i.e. |NERDTree-J| |NERDTree-K| |NERDTree-C-J| |NERDTree-c-K| |NERDTree-p| +|NERDTree-P| + +The centering is done with a |zz| operation. + +------------------------------------------------------------------------------ + *'NERDTreeAutoCenterThreshold'* +Values: Any natural number. +Default: 3 + +This option controls the "sensitivity" of the NERD tree auto centering. See +|'NERDTreeAutoCenter'| for details. + +------------------------------------------------------------------------------ + *'NERDTreeCaseSensitiveSort'* +Values: 0 or 1. +Default: 0. + +By default the NERD tree does not sort nodes case sensitively, i.e. nodes +could appear like this: > + bar.c + Baz.c + blarg.c + boner.c + Foo.c +< +But, if you set this option to 1 then the case of the nodes will be taken into +account. The above nodes would then be sorted like this: > + Baz.c + Foo.c + bar.c + blarg.c + boner.c +< +------------------------------------------------------------------------------ + *'NERDTreeChDirMode'* + +Values: 0, 1 or 2. +Default: 0. + +Use this option to tell the script when (if at all) to change the current +working directory (CWD) for vim. + +If it is set to 0 then the CWD is never changed by the NERD tree. + +If set to 1 then the CWD is changed when the NERD tree is first loaded to the +directory it is initialized in. For example, if you start the NERD tree with > + :NERDTree /home/marty/foobar +< +then the CWD will be changed to /home/marty/foobar and will not be changed +again unless you init another NERD tree with a similar command. + +If the option is set to 2 then it behaves the same as if set to 1 except that +the CWD is changed whenever the tree root is changed. For example, if the CWD +is /home/marty/foobar and you make the node for /home/marty/foobar/baz the new +root then the CWD will become /home/marty/foobar/baz. + +------------------------------------------------------------------------------ + *'NERDTreeHighlightCursorline'* +Values: 0 or 1. +Default: 1. + +If set to 1, the current cursor line in the NERD tree buffer will be +highlighted. This is done using the |cursorline| option. + +------------------------------------------------------------------------------ + *'NERDTreeHijackNetrw'* +Values: 0 or 1. +Default: 1. + +If set to 1, doing a > + :edit +< +will open up a "secondary" NERD tree instead of a netrw in the target window. + +Secondary NERD trees behaves slighly different from a regular trees in the +following respects: + 1. 'o' will open the selected file in the same window as the tree, + replacing it. + 2. you can have as many secondary tree as you want in the same tab. + +------------------------------------------------------------------------------ + *'NERDTreeIgnore'* +Values: a list of regular expressions. +Default: ['\~$']. + +This option is used to specify which files the NERD tree should ignore. It +must be a list of regular expressions. When the NERD tree is rendered, any +files/dirs that match any of the regex's in 'NERDTreeIgnore' wont be +displayed. + +For example if you put the following line in your vimrc: > + let NERDTreeIgnore=['\.vim$', '\~$'] +< +then all files ending in .vim or ~ will be ignored. + +Note: to tell the NERD tree not to ignore any files you must use the following +line: > + let NERDTreeIgnore=[] +< + +The file filters can be turned on and off dynamically with the |NERDTree-f| +mapping. + +------------------------------------------------------------------------------ + *'NERDTreeBookmarksFile'* +Values: a path +Default: $HOME/.NERDTreeBookmarks + +This is where bookmarks are saved. See |NERDTreeBookmarkCommands|. + +------------------------------------------------------------------------------ + *'NERDTreeMouseMode'* +Values: 1, 2 or 3. +Default: 1. + +If set to 1 then a double click on a node is required to open it. +If set to 2 then a single click will open directory nodes, while a double +click will still be required for file nodes. +If set to 3 then a single click will open any node. + +Note: a double click anywhere on a line that a tree node is on will +activate it, but all single-click activations must be done on name of the node +itself. For example, if you have the following node: > + | | |-application.rb +< +then (to single click activate it) you must click somewhere in +'application.rb'. + +------------------------------------------------------------------------------ + *'NERDTreeQuitOnOpen'* + +Values: 0 or 1. +Default: 0 + +If set to 1, the NERD tree window will close after opening a file with the +|NERDTree-o| or |NERDTree-i| mappings. + +------------------------------------------------------------------------------ + *'NERDTreeShowBookmarks'* +Values: 0 or 1. +Default: 0. + +If this option is set to 1 then the bookmarks table will be displayed. + +This option can be toggled dynamically, per tree, with the |NERDTree-B| +mapping. + +------------------------------------------------------------------------------ + *'NERDTreeShowFiles'* +Values: 0 or 1. +Default: 1. + +If this option is set to 1 then files are displayed in the NERD tree. If it is +set to 0 then only directories are displayed. + +This option can be toggled dynamically, per tree, with the |NERDTree-F| +mapping and is useful for drastically shrinking the tree when you are +navigating to a different part of the tree. + +------------------------------------------------------------------------------ + *'NERDTreeShowHidden'* +Values: 0 or 1. +Default: 0. + +This option tells vim whether to display hidden files by default. This option +can be dynamically toggled, per tree, with the |NERDTree-I| mapping. Use one +of the follow lines to set this option: > + let NERDTreeShowHidden=0 + let NERDTreeShowHidden=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeShowLineNumbers'* +Values: 0 or 1. +Default: 0. + +This option tells vim whether to display line numbers for the NERD tree +window. Use one of the follow lines to set this option: > + let NERDTreeShowLineNumbers=0 + let NERDTreeShowLineNumbers=1 +< + +------------------------------------------------------------------------------ + *'NERDTreeSortOrder'* +Values: a list of regular expressions. +Default: ['\/$', '*', '\.swp$', '\.bak$', '\~$'] + +This option is set to a list of regular expressions which are used to +specify the order of nodes under their parent. + +For example, if the option is set to: > + ['\.vim$', '\.c$', '\.h$', '*', 'foobar'] +< +then all .vim files will be placed at the top, followed by all .c files then +all .h files. All files containing the string 'foobar' will be placed at the +end. The star is a special flag: it tells the script that every node that +doesnt match any of the other regexps should be placed here. + +If no star is present in 'NERDTreeSortOrder' then one is automatically +appended to the array. + +The regex '\/$' should be used to match directory nodes. + +After this sorting is done, the files in each group are sorted alphabetically. + +Other examples: > + (1) ['*', '\/$'] + (2) [] + (3) ['\/$', '\.rb$', '\.php$', '*', '\.swp$', '\.bak$', '\~$'] +< +1. Directories will appear last, everything else will appear above. +2. Everything will simply appear in alphabetical order. +3. Dirs will appear first, then ruby and php. Swap files, bak files and vim + backup files will appear last with everything else preceding them. + +------------------------------------------------------------------------------ + *'NERDTreeStatusline'* +Values: Any valid statusline setting. +Default: %{b:NERDTreeRoot.path.strForOS(0)} + +Tells the script what to use as the |'statusline'| setting for NERD tree +windows. + +Note that the statusline is set using |:let-&| not |:set| so escaping spaces +isn't necessary. + +Setting this option to -1 will will deactivate it so that your global +statusline setting is used instead. + +------------------------------------------------------------------------------ + *'NERDTreeWinPos'* +Values: "left" or "right" +Default: "left". + +This option is used to determine where NERD tree window is placed on the +screen. + +This option makes it possible to use two different explorer plugins +simultaneously. For example, you could have the taglist plugin on the left of +the window and the NERD tree on the right. + +------------------------------------------------------------------------------ + *'NERDTreeWinSize'* +Values: a positive integer. +Default: 31. + +This option is used to change the size of the NERD tree when it is loaded. + +============================================================================== +4. Hacking the NERD tree *NERDTreeHacking* + +Public functions ~ + +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 files/directories the tree nodes represent. + +The NERD tree filetype ~ + +NERD tree buffers have a filetype of "nerdtree". You can use this to hack the +NERD tree via autocommands (on |FileType|) or via an ftplugin. + +For example, putting this code in ~/.vim/ftplugin/nerdtree.vim would override +the o mapping, making it open the selected node in a new gvim instance. > + + nnoremap o :call openInNewVimInstance() + function! s:openInNewVimInstance() + let p = NERDTreeGetCurrentPath() + if p != {} + silent exec "!gvim " . p.strForOS(1) . "&" + endif + endfunction +< +This way you can add new mappings or :commands or override any existing +mapping. + +============================================================================== +5. About *NERDTreeAbout* + +The author of the NERD tree is a terrible terrible monster called Martyzilla +who gobbles up small children with milk and sugar for breakfast. + +He can be reached at martin_grenfell at 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 ;) + +The latest stable versions can be found at + http://www.vim.org/scripts/script.php?script_id=1658 + +The latest dev versions are on github + http://github.com/scrooloose/nerdtree + + +============================================================================== +6. Changelog *NERDTreeChangelog* + +3.1.0 + New features: + - add mappings to open files in a vsplit, see :help NERDTree-s and :help + NERDTree-gs + - make the statusline for the nerd tree window default to something + hopefully more useful. See :help 'NERDTreeStatusline' + Bugfixes: + - make the hijack netrw functionality work when vim is started with "vim + " (thanks to Alf Mikula for the patch). + - fix a bug where the CWD wasnt being changed for some operations even when + NERDTreeChDirMode==2 (thanks to Lucas S. Buchala) + - add -bar to all the nerd tree :commands so they can chain with other + :commands (thanks to tpope) + - fix bugs when ignorecase was set (thanks to nach) + - fix a bug with the relative path code (thanks to nach) + - fix a bug where doing a :cd would cause :NERDTreeToggle to fail (thanks nach) + + +3.0.1 + Bugfixes: + - fix bugs with :NERDTreeToggle and :NERDTreeMirror when 'hidden + was not set + - fix a bug where :NERDTree would fail if was relative and + didnt start with a ./ or ../ Thanks to James Kanze. + - make the q mapping work with secondary (:e style) trees, + thanks to jamessan + - fix a bunch of small bugs with secondary trees + + More insane refactoring. + +3.0.0 + - hijack netrw so that doing an :edit will put a NERD tree in + the window rather than a netrw browser. See :help 'NERDTreeHijackNetrw' + - allow sharing of trees across tabs, see :help :NERDTreeMirror + - remove "top" and "bottom" as valid settings for NERDTreeWinPos + - change the '' mapping to 'i' + - change the 'H' mapping to 'I' + - lots of refactoring + +============================================================================== +7. Credits *NERDTreeCredits* + +Thanks to the following people for testing, bug reports, ideas etc. Without +you I probably would have got bored of the hacking the NERD tree and +just downloaded pr0n instead. + + Tim Carey-Smith (halorgium) + Vigil + Nick Brettell + Thomas Scott Urban + Terrance Cohen + Yegappan Lakshmanan + Jason Mills + Michael Geddes (frogonwheels) + Yu Jun + Michael Madsen + AOYAMA Shotaro + Zhang Weiwu + Niels Aan de Brugh + Olivier Yiptong + Zhang Shuhan + Cory Echols + Piotr Czachur + Yuan Jiang + Matan Nassau + Maxim Kim + Charlton Wang + Matt Wozniski (godlygeek) + knekk + Sean Chou + Ryan Penn + Simon Peter Nicholls + Michael Foobar + Tomasz Chomiuk + Denis Pokataev + Tim Pope (tpope) + James Kanze + James Vega (jamessan) + Frederic Chanal (nach) + Alf Mikula + Lucas S. Buchala + +============================================================================== +8. License *NERDTreeLicense* + +The NERD tree is released under the wtfpl. +See http://sam.zoy.org/wtfpl/COPYING. diff --git a/vim/doc/bufexplorer.txt b/vim/doc/bufexplorer.txt new file mode 100644 index 0000000..9af0682 --- /dev/null +++ b/vim/doc/bufexplorer.txt @@ -0,0 +1,442 @@ +*bufexplorer.txt* Buffer Explorer Last Change: 19 Nov 2008 + +Buffer Explorer *buffer-explorer* *bufexplorer* + Version 7.2.2 + +Plugin for easily exploring (or browsing) Vim |:buffers|. + +|bufexplorer-usage| Usage +|bufexplorer-installation| Installation +|bufexplorer-customization| Customization +|bufexplorer-changelog| Change Log +|bufexplorer-todo| Todo +|bufexplorer-credits| Credits + +For Vim version 7.0 and above. +This plugin is only available if 'compatible' is not set. + +{Vi does not have any of this} + +============================================================================== +INSTALLATION *bufexplorer-installation* + +To install: + - Download the bufexplorer.zip. + - Extract the zip archive into your runtime directory. + The archive contains plugin/bufexplorer.vim, and doc/bufexplorer.txt. + - Start Vim or goto an existing instance of Vim. + - Execute the following command: +> + :helptag + \be OR :BufExplorer +To start exploring in a newly split horizontal window, use: > + \bs or :HSBufExplorer +To start exploring in a newly split vertical window, use: > + \bv or :VSBufExplorer + +If you would like to use something other than '\', you may simply change the +leader (see |mapleader|). + +Note: If the current buffer is modified when bufexplorer started, the current + window is always split and the new bufexplorer is displayed in that new + window. + +Commands to use once exploring: + + Opens the buffer that is under the cursor into the current + window. + Toggle help information. + Opens the buffer that is under the cursor into the current + window. + Opens the buffer that is under the cursor in another tab. + d |:wipeout| the buffer under the cursor from the list. + When a buffers is wiped, it will not be shown when unlisted + buffer are displayed. + D |:delete| the buffer under the cursor from the list. + The buffer's 'buflisted' is cleared. This allows for the buffer + to be displayed again using the 'show unlisted' command. + f Toggles whether you are taken to the active window when + selecting a buffer or not. + p Toggles the showing of a split filename/pathname. + q Quit exploring. + r Reverses the order the buffers are listed in. + R Toggles relative path/absolute path. + s Selects the order the buffers are listed in. Either by buffer + number, file name, file extension, most recently used (MRU), or + full path. + t Opens the buffer that is under the cursor in another tab. + u Toggles the showing of "unlisted" buffers. + +Once invoked, Buffer Explorer displays a sorted list (MRU is the default +sort method) of all the buffers that are currently opened. You are then +able to move the cursor to the line containing the buffer's name you are +wanting to act upon. Once you have selected the buffer you would like, +you can then either open it, close it(delete), resort the list, reverse +the sort, quit exploring and so on... + +=============================================================================== +CUSTOMIZATION *bufexplorer-customization* + + *g:bufExplorerDefaultHelp* +To control whether the default help is displayed or not, use: > + let g:bufExplorerDefaultHelp=0 " Do not show default help. + let g:bufExplorerDefaultHelp=1 " Show default help. +The default is to show the default help. + + *g:bufExplorerDetailedHelp* +To control whether detailed help is display by, use: > + let g:bufExplorerDetailedHelp=0 " Do not show detailed help. + let g:bufExplorerDetailedHelp=1 " Show detailed help. +The default is NOT to show detailed help. + + *g:bufExplorerFindActive* +To control whether you are taken to the active window when selecting a buffer, +use: > + let g:bufExplorerFindActive=0 " Do not go to active window. + let g:bufExplorerFindActive=1 " Go to active window. +The default is to be taken to the active window. + + *g:bufExplorerReverseSort* +To control whether to sort the buffer in reverse order or not, use: > + let g:bufExplorerReverseSort=0 " Do not sort in reverse order. + let g:bufExplorerReverseSort=1 " Sort in reverse order. +The default is NOT to sort in reverse order. + + *g:bufExplorerShowDirectories* +Directories usually show up in the list from using a command like ":e .". +To control whether to show directories in the buffer list or not, use: > + let g:bufExplorerShowDirectories=1 " Show directories. + let g:bufExplorerShowDirectories=0 " Don't show directories. +The default is to show directories. + + *g:bufExplorerShowRelativePath* +To control whether to show absolute paths or relative to the current +directory, use: > + let g:bufExplorerShowRelativePath=0 " Show absolute paths. + let g:bufExplorerShowRelativePath=1 " Show relative paths. +The default is to show absolute paths. + + *g:bufExplorerShowUnlisted* +To control whether to show unlisted buffer or not, use: > + let g:bufExplorerShowUnlisted=0 " Do not show unlisted buffers. + let g:bufExplorerShowUnlisted=1 " Show unlisted buffers. +The default is to NOT show unlisted buffers. + + *g:bufExplorerSortBy* +To control what field the buffers are sorted by, use: > + let g:bufExplorerSortBy='extension' " Sort by file extension. + let g:bufExplorerSortBy='fullpath' " Sort by full file path name. + let g:bufExplorerSortBy='mru' " Sort by most recently used. + let g:bufExplorerSortBy='name' " Sort by the buffer's name. + let g:bufExplorerSortBy='number' " Sort by the buffer's number. +The default is to sort by mru. + + *g:bufExplorerSplitBelow* +To control where the new split window will be placed above or below the +current window, use: > + let g:bufExplorerSplitBelow=1 " Split new window below current. + let g:bufExplorerSplitBelow=0 " Split new window above current. +The default is to use what ever is set by the global &splitbelow +variable. + + *g:bufExplorerSplitOutPathName* +To control whether to split out the path and file name or not, use: > + let g:bufExplorerSplitOutPathName=1 " Split the path and file name. + let g:bufExplorerSplitOutPathName=0 " Don't split the path and file + " name. +The default is to split the path and file name. + + *g:bufExplorerSplitRight* +To control where the new vsplit window will be placed to the left or right of +current window, use: > + let g:bufExplorerSplitRight=0 " Split left. + let g:bufExplorerSplitRight=1 " Split right. +The default is to use the global &splitright. + +=============================================================================== +CHANGE LOG *bufexplorer-changelog* + +7.2.2 - Fix: + * Thanks to David L. Dight for spotting and fixing an issue when + using ctrl^. bufexplorer would incorrectly handle the previous + buffer so that when ctrl^ was pressed the incorrect file was opened. +7.2.1 - Fix: + * Thanks to Dimitar for spotting and fixing a feature that was + inadvertently left out of the previous version. The feature was + when bufexplorer was used together with WinManager, you could use + the tab key to open a buffer in a split window. +7.2.0 - Enhancements: + * For all those missing the \bs and \bv commands, these have now + returned. Thanks to Phil O'Connell for asking for the return of + these missing features and helping test out this version. + Fixes: + * Fixed problem with the bufExplorerFindActive code not working + correctly. + * Fixed an incompatibility between bufexplorer and netrw that caused + buffers to be incorrectly removed from the MRU list. +7.1.7 - Fixes: + * TaCahiroy fixed several issues related to opening a buffer in a + tab. +7.1.6 - Fixes: + * Removed ff=unix from modeline in bufexplorer.txt. Found by Bill + McCarthy. +7.1.5 - Fixes: + * Could not open unnamed buffers. Fixed by TaCahiroy. +7.1.4 - Fixes: + * Sometimes when a file's path has 'white space' in it, extra buffers + would be created containing each piece of the path. i.e: + opening c:\document and settings\test.txt would create a buffer + named "and" and a buffer named "Documents". This was reported and + fixed by TaCa Yoss. +7.1.3 - Fixes: + * Added code to allow only one instance of the plugin to run at a + time. Thanks Dennis Hostetler. +7.1.2 - Fixes: + * Fixed a jumplist issue spotted by JiangJun. I overlooked the + 'jumplist' and with a couple calls to 'keepjumps', everything is + fine again. + * Went back to just having a plugin file, no autoload file. By having + the autoload, WinManager was no longer working and without really + digging into the cause, it was easier to go back to using just a + plugin file. +7.1.1 - Fixes: + * A problem spotted by Thomas Arendsen Hein. + When running Vim (7.1.94), error E493 was being thrown. + Enhancements: + * Added 'D' for 'delete' buffer as the 'd' command was a 'wipe' + buffer. +7.1.0 - Another 'major' update, some by Dave Larson, some by me. + * Making use of 'autoload' now to make the plugin load quicker. + * Removed '\bs' and '\bv'. These are now controlled by the user. The + user can issue a ':sp' or ':vs' to create a horizontal or vertical + split window and then issue a '\be' + * Added handling of tabs. +7.0.17 - Fixed issue with 'drop' command. + Various enhancements and improvements. +7.0.16 - Fixed issue reported by Liu Jiaping on non Windows systems, which was + ... + Open file1, open file2, modify file1, open bufexplorer, you get the + following error: + + --------8<-------- + Error detected while processing function + 14_StartBufExplorer..14_SplitOpen: + line 4: + E37: No write since last change (add ! to override) + + But the worse thing is, when I want to save the current buffer and + type ':w', I get another error message: + E382: Cannot write, 'buftype' option is set + --------8<-------- + +7.0.15 - Thanks to Mark Smithfield for suggesting bufexplorer needed to handle + the ':args' command. +7.0.14 - Thanks to Randall Hansen for removing the requirement of terminal + versions to be recompiled with 'gui' support so the 'drop' command + would work. The 'drop' command is really not needed in terminal + versions. +7.0.13 - Fixed integration with WinManager. + Thanks to Dave Eggum for another update. + - Fix: The detailed help didn't display the mapping for toggling + the split type, even though the split type is displayed. + - Fixed incorrect description in the detailed help for toggling + relative or full paths. + - Deprecated s:ExtractBufferNbr(). Vim's str2nr() does the same + thing. + - Created a s:Set() function that sets a variable only if it hasn't + already been defined. It's useful for initializing all those + default settings. + - Removed checks for repetitive command definitions. They were + unnecessary. + - Made the help highlighting a little more fancy. + - Minor reverse compatibility issue: Changed ambiguous setting + names to be more descriptive of what they do (also makes the code + easier to follow): + Changed bufExplorerSortDirection to bufExplorerReverseSort + Changed bufExplorerSplitType to bufExplorerSplitVertical + Changed bufExplorerOpenMode to bufExplorerUseCurrentWindow + - When the BufExplorer window closes, all the file-local marks are + now deleted. This may have the benefit of cleaning up some of the + jumplist. + - Changed the name of the parameter for StartBufExplorer from + "split" to "open". The parameter is a string which specifies how + the buffer will be open, not if it is split or not. + - Deprecated DoAnyMoreBuffersExist() - it is a one line function + only used in one spot. + - Created four functions (SplitOpen(), RebuildBufferList(), + UpdateHelpStatus() and ReSortListing()) all with one purpose - to + reduce repeated code. + - Changed the name of AddHeader() to CreateHelp() to be more + descriptive of what it does. It now returns an array instead of + updating the window directly. This has the benefit of making the + code more efficient since the text the function returns is used a + little differently in the two places the function is called. + - Other minor simplifications. +7.0.12 - MAJOR Update. + This version will ONLY run with Vim version 7.0 or greater. + Dave Eggum has made some 'significant' updates to this latest + version: + - Added BufExplorerGetAltBuf() global function to be used in the + user’s rulerformat. + - Added g:bufExplorerSplitRight option. + - Added g:bufExplorerShowRelativePath option with mapping. + - Added current line highlighting. + - The split type can now be changed whether bufexplorer is opened + in split mode or not. + - Various major and minor bug fixes and speed improvements. + - Sort by extension. + Other improvements/changes: + - Changed the help key from '?' to to be more 'standard'. + - Fixed splitting of vertical bufexplorer window. + Hopefully I have not forgot something :) +7.0.11 - Fixed a couple of highlighting bugs, reported by David Eggum. He also + changed passive voice to active on a couple of warning messages. +7.0.10 - Fixed bug report by Xiangjiang Ma. If the 'ssl' option is set, + the slash character used when displaying the path was incorrect. +7.0.9 - Martin Grenfell found and eliminated an annoying bug in the + bufexplorer/winmanager integration. The bug was were an + annoying message would be displayed when a window was split or + a new file was opened in a new window. Thanks Martin! +7.0.8 - Thanks to Mike Li for catching a bug in the WinManager integration. + The bug was related to the incorrect displaying of the buffer + explorer's window title. +7.0.7 - Thanks to Jeremy Cowgar for adding a new enhancement. This + enhancement allows the user to press 'S', that is capital S, which + will open the buffer under the cursor in a newly created split + window. +7.0.6 - Thanks to Larry Zhang for finding a bug in the "split" buffer code. + If you force set g:bufExplorerSplitType='v' in your vimrc, and if you + tried to do a \bs to split the bufexplorer window, it would always + split horizontal, not vertical. He also found that I had a typeo in + that the variable g:bufExplorerSplitVertSize was all lower case in + the documentation which was incorrect. +7.0.5 - Thanks to Mun Johl for pointing out a bug that if a buffer was + modified, the '+' was not showing up correctly. +7.0.4 - Fixed a problem discovered first by Xiangjiang Ma. Well since I've + been using vim 7.0 and not 6.3, I started using a function (getftype) + that is not in 6.3. So for backward compatibility, I conditionaly use + this function now. Thus, the g:bufExplorerShowDirectories feature is + only available when using vim 7.0 and above. +7.0.3 - Thanks to Erwin Waterlander for finding a problem when the last + buffer was deleted. This issue got me to rewrite the buffer display + logic (which I've wanted to do for sometime now). + Also great thanks to Dave Eggum for coming up with idea for + g:bufExplorerShowDirectories. Read the above information about this + feature. +7.0.2 - Thanks to Thomas Arendsen Hein for finding a problem when a user + has the default help turned off and then brought up the explorer. An + E493 would be displayed. +7.0.1 - Thanks to Erwin Waterlander for finding a couple problems. + The first problem allowed a modified buffer to be deleted. Opps! The + second problem occurred when several files were opened, BufExplorer + was started, the current buffer was deleted using the 'd' option, and + then BufExplorer was exited. The deleted buffer was still visible + while it is not in the buffers list. Opps again! +7.0.0 - Thanks to Shankar R. for suggesting to add the ability to set + the fixed width (g:bufExplorerSplitVertSize) of a new window + when opening bufexplorer vertically and fixed height + (g:bufExplorerSplitHorzSize) of a new window when opening + bufexplorer horizontally. By default, the windows are normally + split to use half the existing width or height. +6.3.0 - Added keepjumps so that the jumps list would not get cluttered with + bufexplorer related stuff. +6.2.3 - Thanks to Jay Logan for finding a bug in the vertical split position + of the code. When selecting that the window was to be split + vertically by doing a '\bv', from then on, all splits, i.e. '\bs', + were split vertically, even though g:bufExplorerSplitType was not set + to 'v'. +6.2.2 - Thanks to Patrik Modesto for adding a small improvement. For some + reason his bufexplorer window was always showing up folded. He added + 'setlocal nofoldenable' and it was fixed. +6.2.1 - Thanks goes out to Takashi Matsuo for added the 'fullPath' sorting + logic and option. +6.2.0 - Thanks goes out to Simon Johann-Ganter for spotting and fixing a + problem in that the last search pattern is overridden by the search + pattern for blank lines. +6.1.6 - Thanks to Artem Chuprina for finding a pesky bug that has been around + for sometime now. The key mapping was causing the buffer + explored to close prematurely when vim was run in an xterm. The + key mapping is now removed. +6.1.5 - Thanks to Khorev Sergey. Added option to show default help or not. +6.1.4 - Thanks goes out to Valery Kondakoff for suggesting the addition of + setlocal nonumber and foldcolumn=0. This allows for line numbering + and folding to be turned off temporarily while in the explorer. +6.1.3 - Added folding. Did some code cleanup. Added the ability to force the + newly split window to be temporarily vertical, which was suggested by + Thomas Glanzmann. +6.1.2 - Now pressing the key will quit, just like 'q'. + Added folds to hide winmanager configuration. + If anyone had the 'C' option in their cpoptions they would receive + a E10 error on startup of BufExplorer. cpo is now saved, updated and + restored. Thanks to Charles E Campbell, Jr. + Attempted to make sure there can only be one BufExplorer window open + at a time. +6.1.1 - Thanks to Brian D. Goodwin for adding toupper to FileNameCmp. This + way buffers sorted by name will be in the correct order regardless of + case. +6.0.16 - Thanks to Andre Pang for the original patch/idea to get bufexplorer + to work in insertmode/modeless mode (evim). Added Initialize + and Cleanup autocommands to handle commands that need to be + performed when starting or leaving bufexplorer. +6.0.15 - Srinath Avadhanulax added a patch for winmanager.vim. +6.0.14 - Fix a few more bug that I thought I already had fixed. Thanks + to Eric Bloodworth for adding 'Open Mode/Edit in Place'. Added + vertical splitting. +6.0.13 - Thanks to Charles E Campbell, Jr. for pointing out some embarrassing + typos that I had in the documentation. I guess I need to run + the spell checker more :o) +6.0.12 - Thanks to Madoka Machitani, for the tip on adding the augroup command + around the MRUList autocommands. +6.0.11 - Fixed bug report by Xiangjiang Ma. '"=' was being added to the + search history which messed up hlsearch. +6.0.10 - Added the necessary hooks so that the Srinath Avadhanula's + winmanager.vim script could more easily integrate with this script. + Tried to improve performance. +6.0.9 - Added MRU (Most Recently Used) sort ordering. +6.0.8 - Was not resetting the showcmd command correctly. + Added nifty help file. +6.0.7 - Thanks to Brett Carlane for some great enhancements. Some are added, + some are not, yet. Added highlighting of current and alternate + filenames. Added splitting of path/filename toggle. Reworked + ShowBuffers(). + Changed my email address. +6.0.6 - Copyright notice added. Needed this so that it could be distributed + with Debian Linux. Fixed problem with the SortListing() function + failing when there was only one buffer to display. +6.0.5 - Fixed problems reported by David Pascoe, in that you where unable to + hit 'd' on a buffer that belonged to a files that no longer existed + and that the 'yank' buffer was being overridden by the help text when + the bufexplorer was opened. +6.0.4 - Thanks to Charles Campbell, Jr. for making this plugin more plugin + *compliant*, adding default keymappings of be and bs + as well as fixing the 'w:sortDirLabel not being defined' bug. +6.0.3 - Added sorting capabilities. Sort taken from explorer.vim. +6.0.2 - Can't remember. +6.0.1 - Initial release. + +=============================================================================== +TODO *bufexplorer-todo* + +- The issuing of a ':bd' command does not always remove the buffer number from + the MRU list. + +=============================================================================== +CREDITS *bufexplorer-credits* + +Author: Jeff Lanzarotta + +Credit must go out to Bram Moolenaar and all the Vim developers for +making the world's best editor (IMHO). I also want to thank everyone who +helped and gave me suggestions. I wouldn't want to leave anyone out so I +won't list names. + +=============================================================================== +vim:tw=78:noet:wrap:ts=8:ft=help:norl: diff --git a/vim/doc/taglist.txt b/vim/doc/taglist.txt new file mode 100644 index 0000000..6a62b39 --- /dev/null +++ b/vim/doc/taglist.txt @@ -0,0 +1,1501 @@ +*taglist.txt* Plugin for browsing source code + +Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) +For Vim version 6.0 and above +Last change: 2007 May 24 + +1. Overview |taglist-intro| +2. Taglist on the internet |taglist-internet| +3. Requirements |taglist-requirements| +4. Installation |taglist-install| +5. Usage |taglist-using| +6. Options |taglist-options| +7. Commands |taglist-commands| +8. Global functions |taglist-functions| +9. Extending |taglist-extend| +10. FAQ |taglist-faq| +11. License |taglist-license| +12. Todo |taglist-todo| + +============================================================================== + *taglist-intro* +1. Overview~ + +The "Tag List" plugin is a source code browser plugin for Vim. This plugin +allows you to efficiently browse through source code files for different +programming languages. The "Tag List" plugin provides the following features: + + * Displays the tags (functions, classes, structures, variables, etc.) + defined in a file in a vertically or horizontally split Vim window. + * In GUI Vim, optionally displays the tags in the Tags drop-down menu and + in the popup menu. + * Automatically updates the taglist window as you switch between + files/buffers. As you open new files, the tags defined in the new files + are added to the existing file list and the tags defined in all the + files are displayed grouped by the filename. + * When a tag name is selected from the taglist window, positions the + cursor at the definition of the tag in the source file. + * Automatically highlights the current tag name. + * Groups the tags by their type and displays them in a foldable tree. + * Can display the prototype and scope of a tag. + * Can optionally display the tag prototype instead of the tag name in the + taglist window. + * The tag list can be sorted either by name or by chronological order. + * Supports the following language files: Assembly, ASP, Awk, Beta, C, + C++, C#, Cobol, Eiffel, Erlang, Fortran, HTML, Java, Javascript, Lisp, + Lua, Make, Pascal, Perl, PHP, Python, Rexx, Ruby, Scheme, Shell, Slang, + SML, Sql, TCL, Verilog, Vim and Yacc. + * Can be easily extended to support new languages. Support for + existing languages can be modified easily. + * Provides functions to display the current tag name in the Vim status + line or the window title bar. + * The list of tags and files in the taglist can be saved and + restored across Vim sessions. + * Provides commands to get the name and prototype of the current tag. + * Runs in both console/terminal and GUI versions of Vim. + * Works with the winmanager plugin. Using the winmanager plugin, you + can use Vim plugins like the file explorer, buffer explorer and the + taglist plugin at the same time like an IDE. + * Can be used in both Unix and MS-Windows systems. + +============================================================================== + *taglist-internet* +2. Taglist on the internet~ + +The home page of the taglist plugin is at: +> + http://vim-taglist.sourceforge.net/ +< +You can subscribe to the taglist mailing list to post your questions or +suggestions for improvement or to send bug reports. Visit the following page +for subscribing to the mailing list: +> + http://groups.yahoo.com/group/taglist +< +============================================================================== + *taglist-requirements* +3. Requirements~ + +The taglist plugin requires the following: + + * Vim version 6.0 and above + * Exuberant ctags 5.0 and above + +The taglist plugin will work on all the platforms where the exuberant ctags +utility and Vim are supported (this includes MS-Windows and Unix based +systems). + +The taglist plugin relies on the exuberant ctags utility to dynamically +generate the tag listing. The exuberant ctags utility must be installed in +your system to use this plugin. The exuberant ctags utility is shipped with +most of the Linux distributions. You can download the exuberant ctags utility +from +> + http://ctags.sourceforge.net +< +The taglist plugin doesn't use or create a tags file and there is no need to +create a tags file to use this plugin. The taglist plugin will not work with +the GNU ctags or the Unix ctags utility. + +This plugin relies on the Vim "filetype" detection mechanism to determine the +type of the current file. You have to turn on the Vim filetype detection by +adding the following line to your .vimrc file: +> + filetype on +< +The taglist plugin will not work if you run Vim in the restricted mode (using +the -Z command-line argument). + +The taglist plugin uses the Vim system() function to invoke the exuberant +ctags utility. If Vim is compiled without the system() function then you +cannot use the taglist plugin. Some of the Linux distributions (Suse) compile +Vim without the system() function for security reasons. + +============================================================================== + *taglist-install* +4. Installation~ + +1. Download the taglist.zip file and unzip the files to the $HOME/.vim or the + $HOME/vimfiles or the $VIM/vimfiles directory. After this step, you should + have the following two files (the directory structure should be preserved): + + plugin/taglist.vim - main taglist plugin file + doc/taglist.txt - documentation (help) file + + Refer to the |add-plugin|and |'runtimepath'| Vim help pages for more + details about installing Vim plugins. +2. Change to the $HOME/.vim/doc or $HOME/vimfiles/doc or $VIM/vimfiles/doc + directory, start Vim and run the ":helptags ." command to process the + taglist help file. Without this step, you cannot jump to the taglist help + topics. +3. If the exuberant ctags utility is not present in one of the directories in + the PATH environment variable, then set the 'Tlist_Ctags_Cmd' variable to + point to the location of the exuberant ctags utility (not to the directory) + in the .vimrc file. +4. If you are running a terminal/console version of Vim and the terminal + doesn't support changing the window width then set the + 'Tlist_Inc_Winwidth' variable to 0 in the .vimrc file. +5. Restart Vim. +6. You can now use the ":TlistToggle" command to open/close the taglist + window. You can use the ":help taglist" command to get more information + about using the taglist plugin. + +To uninstall the taglist plugin, remove the plugin/taglist.vim and +doc/taglist.txt files from the $HOME/.vim or $HOME/vimfiles directory. + +============================================================================== + *taglist-using* +5. Usage~ + +The taglist plugin can be used in several different ways. + +1. You can keep the taglist window open during the entire editing session. On + opening the taglist window, the tags defined in all the files in the Vim + buffer list will be displayed in the taglist window. As you edit files, the + tags defined in them will be added to the taglist window. You can select a + tag from the taglist window and jump to it. The current tag will be + highlighted in the taglist window. You can close the taglist window when + you no longer need the window. +2. You can configure the taglist plugin to process the tags defined in all the + edited files always. In this configuration, even if the taglist window is + closed and the taglist menu is not displayed, the taglist plugin will + processes the tags defined in newly edited files. You can then open the + taglist window only when you need to select a tag and then automatically + close the taglist window after selecting the tag. +3. You can configure the taglist plugin to display only the tags defined in + the current file in the taglist window. By default, the taglist plugin + displays the tags defined in all the files in the Vim buffer list. As you + switch between files, the taglist window will be refreshed to display only + the tags defined in the current file. +4. In GUI Vim, you can use the Tags pull-down and popup menu created by the + taglist plugin to display the tags defined in the current file and select a + tag to jump to it. You can use the menu without opening the taglist window. + By default, the Tags menu is disabled. +5. You can configure the taglist plugin to display the name of the current tag + in the Vim window status line or in the Vim window title bar. For this to + work without the taglist window or menu, you need to configure the taglist + plugin to process the tags defined in a file always. +6. You can save the tags defined in multiple files to a taglist session file + and load it when needed. You can also configure the taglist plugin to not + update the taglist window when editing new files. You can then manually add + files to the taglist window. + +Opening the taglist window~ +You can open the taglist window using the ":TlistOpen" or the ":TlistToggle" +commands. The ":TlistOpen" command opens the taglist window and jumps to it. +The ":TlistToggle" command opens or closes (toggle) the taglist window and the +cursor remains in the current window. If the 'Tlist_GainFocus_On_ToggleOpen' +variable is set to 1, then the ":TlistToggle" command opens the taglist window +and moves the cursor to the taglist window. + +You can map a key to invoke these commands. For example, the following command +creates a normal mode mapping for the key to toggle the taglist window. +> + nnoremap :TlistToggle +< +Add the above mapping to your ~/.vimrc or $HOME/_vimrc file. + +To automatically open the taglist window on Vim startup, set the +'Tlist_Auto_Open' variable to 1. + +You can also open the taglist window on startup using the following command +line: +> + $ vim +TlistOpen +< +Closing the taglist window~ +You can close the taglist window from the taglist window by pressing 'q' or +using the Vim ":q" command. You can also use any of the Vim window commands to +close the taglist window. Invoking the ":TlistToggle" command when the taglist +window is opened, closes the taglist window. You can also use the +":TlistClose" command to close the taglist window. + +To automatically close the taglist window when a tag or file is selected, you +can set the 'Tlist_Close_On_Select' variable to 1. To exit Vim when only the +taglist window is present, set the 'Tlist_Exit_OnlyWindow' variable to 1. + +Jumping to a tag or a file~ +You can select a tag in the taglist window either by pressing the key +or by double clicking the tag name using the mouse. To jump to a tag on a +single mouse click set the 'Tlist_Use_SingleClick' variable to 1. + +If the selected file is already opened in a window, then the cursor is moved +to that window. If the file is not currently opened in a window then the file +is opened in the window used by the taglist plugin to show the previously +selected file. If there are no usable windows, then the file is opened in a +new window. The file is not opened in special windows like the quickfix +window, preview window and windows containing buffer with the 'buftype' option +set. + +To jump to the tag in a new window, press the 'o' key. To open the file in the +previous window (Ctrl-W_p) use the 'P' key. You can press the 'p' key to jump +to the tag but still keep the cursor in the taglist window (preview). + +To open the selected file in a tab, use the 't' key. If the file is already +present in a tab then the cursor is moved to that tab otherwise the file is +opened in a new tab. To jump to a tag in a new tab press Ctrl-t. The taglist +window is automatically opened in the newly created tab. + +Instead of jumping to a tag, you can open a file by pressing the key +or by double clicking the file name using the mouse. + +In the taglist window, you can use the [[ or key to jump to the +beginning of the previous file. You can use the ]] or key to jump to the +beginning of the next file. When you reach the first or last file, the search +wraps around and the jumps to the next/previous file. + +Highlighting the current tag~ +The taglist plugin automatically highlights the name of the current tag in the +taglist window. The Vim |CursorHold| autocmd event is used for this. If the +current tag name is not visible in the taglist window, then the taglist window +contents are scrolled to make that tag name visible. You can also use the +":TlistHighlightTag" command to force the highlighting of the current tag. + +The tag name is highlighted if no activity is performed for |'updatetime'| +milliseconds. The default value for this Vim option is 4 seconds. To avoid +unexpected problems, you should not set the |'updatetime'| option to a very +low value. + +To disable the automatic highlighting of the current tag name in the taglist +window, set the 'Tlist_Auto_Highlight_Tag' variable to zero. + +When entering a Vim buffer/window, the taglist plugin automatically highlights +the current tag in that buffer/window. If you like to disable the automatic +highlighting of the current tag when entering a buffer, set the +'Tlist_Highlight_Tag_On_BufEnter' variable to zero. + +Adding files to the taglist~ +When the taglist window is opened, all the files in the Vim buffer list are +processed and the supported files are added to the taglist. When you edit a +file in Vim, the taglist plugin automatically processes this file and adds it +to the taglist. If you close the taglist window, the tag information in the +taglist is retained. + +To process files even when the taglist window is not open, set the +'Tlist_Process_File_Always' variable to 1. + +You can manually add multiple files to the taglist without opening them using +the ":TlistAddFiles" and the ":TlistAddFilesRecursive" commands. + +For example, to add all the C files in the /my/project/dir directory to the +taglist, you can use the following command: +> + :TlistAddFiles /my/project/dir/*.c +< +Note that when adding several files with a large number of tags or a large +number of files, it will take several seconds to several minutes for the +taglist plugin to process all the files. You should not interrupt the taglist +plugin by pressing . + +You can recursively add multiple files from a directory tree using the +":TlistAddFilesRecursive" command: +> + :TlistAddFilesRecursive /my/project/dir *.c +< +This command takes two arguments. The first argument specifies the directory +from which to recursively add the files. The second optional argument +specifies the wildcard matching pattern for selecting the files to add. The +default pattern is * and all the files are added. + +Displaying tags for only one file~ +The taglist window displays the tags for all the files in the Vim buffer list +and all the manually added files. To display the tags for only the current +active buffer, set the 'Tlist_Show_One_File' variable to 1. + +Removing files from the taglist~ +You can remove a file from the taglist window, by pressing the 'd' key when the +cursor is on one of the tags listed for the file in the taglist window. The +removed file will no longer be displayed in the taglist window in the current +Vim session. To again display the tags for the file, open the file in a Vim +window and then use the ":TlistUpdate" command or use ":TlistAddFiles" command +to add the file to the taglist. + +When a buffer is removed from the Vim buffer list using the ":bdelete" or the +":bwipeout" command, the taglist is updated to remove the stored information +for this buffer. + +Updating the tags displayed for a file~ +The taglist plugin keeps track of the modification time of a file. When the +modification time changes (the file is modified), the taglist plugin +automatically updates the tags listed for that file. The modification time of +a file is checked when you enter a window containing that file or when you +load that file. + +You can also update or refresh the tags displayed for a file by pressing the +"u" key in the taglist window. If an existing file is modified, after the file +is saved, the taglist plugin automatically updates the tags displayed for the +file. + +You can also use the ":TlistUpdate" command to update the tags for the current +buffer after you made some changes to it. You should save the modified buffer +before you update the taglist window. Otherwise the listed tags will not +include the new tags created in the buffer. + +If you have deleted the tags displayed for a file in the taglist window using +the 'd' key, you can again display the tags for that file using the +":TlistUpdate" command. + +Controlling the taglist updates~ +To disable the automatic processing of new files or modified files, you can +set the 'Tlist_Auto_Update' variable to zero. When this variable is set to +zero, the taglist is updated only when you use the ":TlistUpdate" command or +the ":TlistAddFiles" or the ":TlistAddFilesRecursive" commands. You can use +this option to control which files are added to the taglist. + +You can use the ":TlistLock" command to lock the taglist contents. After this +command is executed, new files are not automatically added to the taglist. +When the taglist is locked, you can use the ":TlistUpdate" command to add the +current file or the ":TlistAddFiles" or ":TlistAddFilesRecursive" commands to +add new files to the taglist. To unlock the taglist, use the ":TlistUnlock" +command. + +Displaying the tag prototype~ +To display the prototype of the tag under the cursor in the taglist window, +press the space bar. If you place the cursor on a tag name in the taglist +window, then the tag prototype is displayed at the Vim status line after +|'updatetime'| milliseconds. The default value for the |'updatetime'| Vim +option is 4 seconds. + +You can get the name and prototype of a tag without opening the taglist window +and the taglist menu using the ":TlistShowTag" and the ":TlistShowPrototype" +commands. These commands will work only if the current file is already present +in the taglist. To use these commands without opening the taglist window, set +the 'Tlist_Process_File_Always' variable to 1. + +You can use the ":TlistShowTag" command to display the name of the tag at or +before the specified line number in the specified file. If the file name and +line number are not supplied, then this command will display the name of the +current tag. For example, +> + :TlistShowTag + :TlistShowTag myfile.java 100 +< +You can use the ":TlistShowPrototype" command to display the prototype of the +tag at or before the specified line number in the specified file. If the file +name and the line number are not supplied, then this command will display the +prototype of the current tag. For example, +> + :TlistShowPrototype + :TlistShowPrototype myfile.c 50 +< +In the taglist window, when the mouse is moved over a tag name, the tag +prototype is displayed in a balloon. This works only in GUI versions where +balloon evaluation is supported. + +Taglist window contents~ +The taglist window contains the tags defined in various files in the taglist +grouped by the filename and by the tag type (variable, function, class, etc.). +For tags with scope information (like class members, structures inside +structures, etc.), the scope information is displayed in square brackets "[]" +after the tag name. + +The contents of the taglist buffer/window are managed by the taglist plugin. +The |'filetype'| for the taglist buffer is set to 'taglist'. The Vim +|'modifiable'| option is turned off for the taglist buffer. You should not +manually edit the taglist buffer, by setting the |'modifiable'| flag. If you +manually edit the taglist buffer contents, then the taglist plugin will be out +of sync with the taglist buffer contents and the plugin will no longer work +correctly. To redisplay the taglist buffer contents again, close the taglist +window and reopen it. + +Opening and closing the tag and file tree~ +In the taglist window, the tag names are displayed as a foldable tree using +the Vim folding support. You can collapse the tree using the '-' key or using +the Vim |zc| fold command. You can open the tree using the '+' key or using +the Vim |zo| fold command. You can open all the folds using the '*' key or +using the Vim |zR| fold command. You can also use the mouse to open/close the +folds. You can close all the folds using the '=' key. You should not manually +create or delete the folds in the taglist window. + +To automatically close the fold for the inactive files/buffers and open only +the fold for the current buffer in the taglist window, set the +'Tlist_File_Fold_Auto_Close' variable to 1. + +Sorting the tags for a file~ +The tags displayed in the taglist window can be sorted either by their name or +by their chronological order. The default sorting method is by the order in +which the tags appear in a file. You can change the default sort method by +setting the 'Tlist_Sort_Type' variable to either "name" or "order". You can +sort the tags by their name by pressing the "s" key in the taglist window. You +can again sort the tags by their chronological order using the "s" key. Each +file in the taglist window can be sorted using different order. + +Zooming in and out of the taglist window~ +You can press the 'x' key in the taglist window to maximize the taglist +window width/height. The window will be maximized to the maximum possible +width/height without closing the other existing windows. You can again press +'x' to restore the taglist window to the default width/height. + + *taglist-session* +Taglist Session~ +A taglist session refers to the group of files and their tags stored in the +taglist in a Vim session. + +You can save and restore a taglist session (and all the displayed tags) using +the ":TlistSessionSave" and ":TlistSessionLoad" commands. + +To save the information about the tags and files in the taglist to a file, use +the ":TlistSessionSave" command and specify the filename: +> + :TlistSessionSave +< +To load a saved taglist session, use the ":TlistSessionLoad" command: > + + :TlistSessionLoad +< +When you load a taglist session file, the tags stored in the file will be +added to the tags already stored in the taglist. + +The taglist session feature can be used to save the tags for large files or a +group of frequently used files (like a project). By using the taglist session +file, you can minimize the amount to time it takes to load/refresh the taglist +for multiple files. + +You can create more than one taglist session file for multiple groups of +files. + +Displaying the tag name in the Vim status line or the window title bar~ +You can use the Tlist_Get_Tagname_By_Line() function provided by the taglist +plugin to display the current tag name in the Vim status line or the window +title bar. Similarly, you can use the Tlist_Get_Tag_Prototype_By_Line() +function to display the current tag prototype in the Vim status line or the +window title bar. + +For example, the following command can be used to display the current tag name +in the status line: +> + :set statusline=%<%f%=%([%{Tlist_Get_Tagname_By_Line()}]%) +< +The following command can be used to display the current tag name in the +window title bar: +> + :set title titlestring=%<%f\ %([%{Tlist_Get_Tagname_By_Line()}]%) +< +Note that the current tag name can be displayed only after the file is +processed by the taglist plugin. For this, you have to either set the +'Tlist_Process_File_Always' variable to 1 or open the taglist window or use +the taglist menu. For more information about configuring the Vim status line, +refer to the documentation for the Vim |'statusline'| option. + +Changing the taglist window highlighting~ +The following Vim highlight groups are defined and used to highlight the +various entities in the taglist window: + + TagListTagName - Used for tag names + TagListTagScope - Used for tag scope + TagListTitle - Used for tag titles + TagListComment - Used for comments + TagListFileName - Used for filenames + +By default, these highlight groups are linked to the standard Vim highlight +groups. If you want to change the colors used for these highlight groups, +prefix the highlight group name with 'My' and define it in your .vimrc or +.gvimrc file: MyTagListTagName, MyTagListTagScope, MyTagListTitle, +MyTagListComment and MyTagListFileName. For example, to change the colors +used for tag names, you can use the following command: +> + :highlight MyTagListTagName guifg=blue ctermfg=blue +< +Controlling the taglist window~ +To use a horizontally split taglist window, instead of a vertically split +window, set the 'Tlist_Use_Horiz_Window' variable to 1. + +To use a vertically split taglist window on the rightmost side of the Vim +window, set the 'Tlist_Use_Right_Window' variable to 1. + +You can specify the width of the vertically split taglist window, by setting +the 'Tlist_WinWidth' variable. You can specify the height of the horizontally +split taglist window, by setting the 'Tlist_WinHeight' variable. + +When opening a vertically split taglist window, the Vim window width is +increased to accommodate the new taglist window. When the taglist window is +closed, the Vim window is reduced. To disable this, set the +'Tlist_Inc_Winwidth' variable to zero. + +To reduce the number of empty lines in the taglist window, set the +'Tlist_Compact_Format' variable to 1. + +To not display the Vim fold column in the taglist window, set the +'Tlist_Enable_Fold_Column' variable to zero. + +To display the tag prototypes instead of the tag names in the taglist window, +set the 'Tlist_Display_Prototype' variable to 1. + +To not display the scope of the tags next to the tag names, set the +'Tlist_Display_Tag_Scope' variable to zero. + + *taglist-keys* +Taglist window key list~ +The following table lists the description of the keys that can be used +in the taglist window. + + Key Description~ + + Jump to the location where the tag under cursor is + defined. + o Jump to the location where the tag under cursor is + defined in a new window. + P Jump to the tag in the previous (Ctrl-W_p) window. + p Display the tag definition in the file window and + keep the cursor in the taglist window itself. + t Jump to the tag in a new tab. If the file is already + opened in a tab, move to that tab. + Ctrl-t Jump to the tag in a new tab. + Display the prototype of the tag under the cursor. + For file names, display the full path to the file, + file type and the number of tags. For tag types, display the + tag type and the number of tags. + u Update the tags listed in the taglist window + s Change the sort order of the tags (by name or by order) + d Remove the tags for the file under the cursor + x Zoom-in or Zoom-out the taglist window + + Open a fold + - Close a fold + * Open all folds + = Close all folds + [[ Jump to the beginning of the previous file + Jump to the beginning of the previous file + ]] Jump to the beginning of the next file + Jump to the beginning of the next file + q Close the taglist window + Display help + +The above keys will work in both the normal mode and the insert mode. + + *taglist-menu* +Taglist menu~ +When using GUI Vim, the taglist plugin can display the tags defined in the +current file in the drop-down menu and the popup menu. By default, this +feature is turned off. To turn on this feature, set the 'Tlist_Show_Menu' +variable to 1. + +You can jump to a tag by selecting the tag name from the menu. You can use the +taglist menu independent of the taglist window i.e. you don't need to open the +taglist window to get the taglist menu. + +When you switch between files/buffers, the taglist menu is automatically +updated to display the tags defined in the current file/buffer. + +The tags are grouped by their type (variables, functions, classes, methods, +etc.) and displayed as a separate sub-menu for each type. If all the tags +defined in a file are of the same type (e.g. functions), then the sub-menu is +not used. + +If the number of items in a tag type submenu exceeds the value specified by +the 'Tlist_Max_Submenu_Items' variable, then the submenu will be split into +multiple submenus. The default setting for 'Tlist_Max_Submenu_Items' is 25. +The first and last tag names in the submenu are used to form the submenu name. +The menu items are prefixed by alpha-numeric characters for easy selection by +keyboard. + +If the popup menu support is enabled (the |'mousemodel'| option contains +"popup"), then the tags menu is added to the popup menu. You can access +the popup menu by right clicking on the GUI window. + +You can regenerate the tags menu by selecting the 'Tags->Refresh menu' entry. +You can sort the tags listed in the menu either by name or by order by +selecting the 'Tags->Sort menu by->Name/Order' menu entry. + +You can tear-off the Tags menu and keep it on the side of the Vim window +for quickly locating the tags. + +Using the taglist plugin with the winmanager plugin~ +You can use the taglist plugin with the winmanager plugin. This will allow you +to use the file explorer, buffer explorer and the taglist plugin at the same +time in different windows. To use the taglist plugin with the winmanager +plugin, set 'TagList' in the 'winManagerWindowLayout' variable. For example, +to use the file explorer plugin and the taglist plugin at the same time, use +the following setting: > + + let winManagerWindowLayout = 'FileExplorer|TagList' +< +Getting help~ +If you have installed the taglist help file (this file), then you can use the +Vim ":help taglist-" command to get help on the various taglist +topics. + +You can press the key in the taglist window to display the help +information about using the taglist window. If you again press the key, +the help information is removed from the taglist window. + + *taglist-debug* +Debugging the taglist plugin~ +You can use the ":TlistDebug" command to enable logging of the debug messages +from the taglist plugin. To display the logged debug messages, you can use the +":TlistMessages" command. To disable the logging of the debug messages, use +the ":TlistUndebug" command. + +You can specify a file name to the ":TlistDebug" command to log the debug +messages to a file. Otherwise, the debug messages are stored in a script-local +variable. In the later case, to minimize memory usage, only the last 3000 +characters from the debug messages are stored. + +============================================================================== + *taglist-options* +6. Options~ + +A number of Vim variables control the behavior of the taglist plugin. These +variables are initialized to a default value. By changing these variables you +can change the behavior of the taglist plugin. You need to change these +settings only if you want to change the behavior of the taglist plugin. You +should use the |:let| command in your .vimrc file to change the setting of any +of these variables. + +The configurable taglist variables are listed below. For a detailed +description of these variables refer to the text below this table. + +|'Tlist_Auto_Highlight_Tag'| Automatically highlight the current tag in the + taglist. +|'Tlist_Auto_Open'| Open the taglist window when Vim starts. +|'Tlist_Auto_Update'| Automatically update the taglist to include + newly edited files. +|'Tlist_Close_On_Select'| Close the taglist window when a file or tag is + selected. +|'Tlist_Compact_Format'| Remove extra information and blank lines from + the taglist window. +|'Tlist_Ctags_Cmd'| Specifies the path to the ctags utility. +|'Tlist_Display_Prototype'| Show prototypes and not tags in the taglist + window. +|'Tlist_Display_Tag_Scope'| Show tag scope next to the tag name. +|'Tlist_Enable_Fold_Column'| Show the fold indicator column in the taglist + window. +|'Tlist_Exit_OnlyWindow'| Close Vim if the taglist is the only window. +|'Tlist_File_Fold_Auto_Close'| Close tag folds for inactive buffers. +|'Tlist_GainFocus_On_ToggleOpen'| + Jump to taglist window on open. +|'Tlist_Highlight_Tag_On_BufEnter'| + On entering a buffer, automatically highlight + the current tag. +|'Tlist_Inc_Winwidth'| Increase the Vim window width to accommodate + the taglist window. +|'Tlist_Max_Submenu_Items'| Maximum number of items in a tags sub-menu. +|'Tlist_Max_Tag_Length'| Maximum tag length used in a tag menu entry. +|'Tlist_Process_File_Always'| Process files even when the taglist window is + closed. +|'Tlist_Show_Menu'| Display the tags menu. +|'Tlist_Show_One_File'| Show tags for the current buffer only. +|'Tlist_Sort_Type'| Sort method used for arranging the tags. +|'Tlist_Use_Horiz_Window'| Use a horizontally split window for the + taglist window. +|'Tlist_Use_Right_Window'| Place the taglist window on the right side. +|'Tlist_Use_SingleClick'| Single click on a tag jumps to it. +|'Tlist_WinHeight'| Horizontally split taglist window height. +|'Tlist_WinWidth'| Vertically split taglist window width. + + *'Tlist_Auto_Highlight_Tag'* +Tlist_Auto_Highlight_Tag~ +The taglist plugin will automatically highlight the current tag in the taglist +window. If you want to disable this, then you can set the +'Tlist_Auto_Highlight_Tag' variable to zero. Note that even though the current +tag highlighting is disabled, the tags for a new file will still be added to +the taglist window. +> + let Tlist_Auto_Highlight_Tag = 0 +< +With the above variable set to 1, you can use the ":TlistHighlightTag" command +to highlight the current tag. + + *'Tlist_Auto_Open'* +Tlist_Auto_Open~ +To automatically open the taglist window, when you start Vim, you can set the +'Tlist_Auto_Open' variable to 1. By default, this variable is set to zero and +the taglist window will not be opened automatically on Vim startup. +> + let Tlist_Auto_Open = 1 +< +The taglist window is opened only when a supported type of file is opened on +Vim startup. For example, if you open text files, then the taglist window will +not be opened. + + *'Tlist_Auto_Update'* +Tlist_Auto_Update~ +When a new file is edited, the tags defined in the file are automatically +processed and added to the taglist. To stop adding new files to the taglist, +set the 'Tlist_Auto_Update' variable to zero. By default, this variable is set +to 1. +> + let Tlist_Auto_Update = 0 +< +With the above variable set to 1, you can use the ":TlistUpdate" command to +add the tags defined in the current file to the taglist. + + *'Tlist_Close_On_Select'* +Tlist_Close_On_Select~ +If you want to close the taglist window when a file or tag is selected, then +set the 'Tlist_Close_On_Select' variable to 1. By default, this variable is +set zero and when you select a tag or file from the taglist window, the window +is not closed. +> + let Tlist_Close_On_Select = 1 +< + *'Tlist_Compact_Format'* +Tlist_Compact_Format~ +By default, empty lines are used to separate different tag types displayed for +a file and the tags displayed for different files in the taglist window. If +you want to display as many tags as possible in the taglist window, you can +set the 'Tlist_Compact_Format' variable to 1 to get a compact display. +> + let Tlist_Compact_Format = 1 +< + *'Tlist_Ctags_Cmd'* +Tlist_Ctags_Cmd~ +The 'Tlist_Ctags_Cmd' variable specifies the location (path) of the exuberant +ctags utility. If exuberant ctags is present in any one of the directories in +the PATH environment variable, then there is no need to set this variable. + +The exuberant ctags tool can be installed under different names. When the +taglist plugin starts up, if the 'Tlist_Ctags_Cmd' variable is not set, it +checks for the names exuberant-ctags, exctags, ctags, ctags.exe and tags in +the PATH environment variable. If any one of the named executable is found, +then the Tlist_Ctags_Cmd variable is set to that name. + +If exuberant ctags is not present in one of the directories specified in the +PATH environment variable, then set this variable to point to the location of +the ctags utility in your system. Note that this variable should point to the +fully qualified exuberant ctags location and NOT to the directory in which +exuberant ctags is installed. If the exuberant ctags tool is not found in +either PATH or in the specified location, then the taglist plugin will not be +loaded. Examples: +> + let Tlist_Ctags_Cmd = 'd:\tools\ctags.exe' + let Tlist_Ctags_Cmd = '/usr/local/bin/ctags' +< + *'Tlist_Display_Prototype'* +Tlist_Display_Prototype~ +By default, only the tag name will be displayed in the taglist window. If you +like to see tag prototypes instead of names, set the 'Tlist_Display_Prototype' +variable to 1. By default, this variable is set to zero and only tag names +will be displayed. +> + let Tlist_Display_Prototype = 1 +< + *'Tlist_Display_Tag_Scope'* +Tlist_Display_Tag_Scope~ +By default, the scope of a tag (like a C++ class) will be displayed in +square brackets next to the tag name. If you don't want the tag scopes +to be displayed, then set the 'Tlist_Display_Tag_Scope' to zero. By default, +this variable is set to 1 and the tag scopes will be displayed. +> + let Tlist_Display_Tag_Scope = 0 +< + *'Tlist_Enable_Fold_Column'* +Tlist_Enable_Fold_Column~ +By default, the Vim fold column is enabled and displayed in the taglist +window. If you wish to disable this (for example, when you are working with a +narrow Vim window or terminal), you can set the 'Tlist_Enable_Fold_Column' +variable to zero. +> + let Tlist_Enable_Fold_Column = 1 +< + *'Tlist_Exit_OnlyWindow'* +Tlist_Exit_OnlyWindow~ +If you want to exit Vim if only the taglist window is currently opened, then +set the 'Tlist_Exit_OnlyWindow' variable to 1. By default, this variable is +set to zero and the Vim instance will not be closed if only the taglist window +is present. +> + let Tlist_Exit_OnlyWindow = 1 +< + *'Tlist_File_Fold_Auto_Close'* +Tlist_File_Fold_Auto_Close~ +By default, the tags tree displayed in the taglist window for all the files is +opened. You can close/fold the tags tree for the files manually. To +automatically close the tags tree for inactive files, you can set the +'Tlist_File_Fold_Auto_Close' variable to 1. When this variable is set to 1, +the tags tree for the current buffer is automatically opened and for all the +other buffers is closed. +> + let Tlist_File_Fold_Auto_Close = 1 +< + *'Tlist_GainFocus_On_ToggleOpen'* +Tlist_GainFocus_On_ToggleOpen~ +When the taglist window is opened using the ':TlistToggle' command, this +option controls whether the cursor is moved to the taglist window or remains +in the current window. By default, this option is set to 0 and the cursor +remains in the current window. When this variable is set to 1, the cursor +moves to the taglist window after opening the taglist window. +> + let Tlist_GainFocus_On_ToggleOpen = 1 +< + *'Tlist_Highlight_Tag_On_BufEnter'* +Tlist_Highlight_Tag_On_BufEnter~ +When you enter a Vim buffer/window, the current tag in that buffer/window is +automatically highlighted in the taglist window. If the current tag name is +not visible in the taglist window, then the taglist window contents are +scrolled to make that tag name visible. If you like to disable the automatic +highlighting of the current tag when entering a buffer, you can set the +'Tlist_Highlight_Tag_On_BufEnter' variable to zero. The default setting for +this variable is 1. +> + let Tlist_Highlight_Tag_On_BufEnter = 0 +< + *'Tlist_Inc_Winwidth'* +Tlist_Inc_Winwidth~ +By default, when the width of the window is less than 100 and a new taglist +window is opened vertically, then the window width is increased by the value +set in the 'Tlist_WinWidth' variable to accommodate the new window. The value +of this variable is used only if you are using a vertically split taglist +window. + +If your terminal doesn't support changing the window width from Vim (older +version of xterm running in a Unix system) or if you see any weird problems in +the screen due to the change in the window width or if you prefer not to +adjust the window width then set the 'Tlist_Inc_Winwidth' variable to zero. +CAUTION: If you are using the MS-Windows version of Vim in a MS-DOS command +window then you must set this variable to zero, otherwise the system may hang +due to a Vim limitation (explained in :help win32-problems) +> + let Tlist_Inc_Winwidth = 0 +< + *'Tlist_Max_Submenu_Items'* +Tlist_Max_Submenu_Items~ +If a file contains too many tags of a particular type (function, variable, +class, etc.), greater than that specified by the 'Tlist_Max_Submenu_Items' +variable, then the menu for that tag type will be split into multiple +sub-menus. The default setting for the 'Tlist_Max_Submenu_Items' variable is +25. This can be changed by setting the 'Tlist_Max_Submenu_Items' variable: +> + let Tlist_Max_Submenu_Items = 20 +< +The name of the submenu is formed using the names of the first and the last +tag entries in that submenu. + + *'Tlist_Max_Tag_Length'* +Tlist_Max_Tag_Length~ +Only the first 'Tlist_Max_Tag_Length' characters from the tag names will be +used to form the tag type submenu name. The default value for this variable is +10. Change the 'Tlist_Max_Tag_Length' setting if you want to include more or +less characters: +> + let Tlist_Max_Tag_Length = 10 +< + *'Tlist_Process_File_Always'* +Tlist_Process_File_Always~ +By default, the taglist plugin will generate and process the tags defined in +the newly opened files only when the taglist window is opened or when the +taglist menu is enabled. When the taglist window is closed, the taglist plugin +will stop processing the tags for newly opened files. + +You can set the 'Tlist_Process_File_Always' variable to 1 to generate the list +of tags for new files even when the taglist window is closed and the taglist +menu is disabled. +> + let Tlist_Process_File_Always = 1 +< +To use the ":TlistShowTag" and the ":TlistShowPrototype" commands without the +taglist window and the taglist menu, you should set this variable to 1. + + *'Tlist_Show_Menu'* +Tlist_Show_Menu~ +When using GUI Vim, you can display the tags defined in the current file in a +menu named "Tags". By default, this feature is turned off. To turn on this +feature, set the 'Tlist_Show_Menu' variable to 1: +> + let Tlist_Show_Menu = 1 +< + *'Tlist_Show_One_File'* +Tlist_Show_One_File~ +By default, the taglist plugin will display the tags defined in all the loaded +buffers in the taglist window. If you prefer to display the tags defined only +in the current buffer, then you can set the 'Tlist_Show_One_File' to 1. When +this variable is set to 1, as you switch between buffers, the taglist window +will be refreshed to display the tags for the current buffer and the tags for +the previous buffer will be removed. +> + let Tlist_Show_One_File = 1 +< + *'Tlist_Sort_Type'* +Tlist_Sort_Type~ +The 'Tlist_Sort_Type' variable specifies the sort order for the tags in the +taglist window. The tags can be sorted either alphabetically by their name or +by the order of their appearance in the file (chronological order). By +default, the tag names will be listed by the order in which they are defined +in the file. You can change the sort type (from name to order or from order to +name) by pressing the "s" key in the taglist window. You can also change the +default sort order by setting 'Tlist_Sort_Type' to "name" or "order": +> + let Tlist_Sort_Type = "name" +< + *'Tlist_Use_Horiz_Window'* +Tlist_Use_Horiz_Window~ +Be default, the tag names are displayed in a vertically split window. If you +prefer a horizontally split window, then set the 'Tlist_Use_Horiz_Window' +variable to 1. If you are running MS-Windows version of Vim in a MS-DOS +command window, then you should use a horizontally split window instead of a +vertically split window. Also, if you are using an older version of xterm in a +Unix system that doesn't support changing the xterm window width, you should +use a horizontally split window. +> + let Tlist_Use_Horiz_Window = 1 +< + *'Tlist_Use_Right_Window'* +Tlist_Use_Right_Window~ +By default, the vertically split taglist window will appear on the left hand +side. If you prefer to open the window on the right hand side, you can set the +'Tlist_Use_Right_Window' variable to 1: +> + let Tlist_Use_Right_Window = 1 +< + *'Tlist_Use_SingleClick'* +Tlist_Use_SingleClick~ +By default, when you double click on the tag name using the left mouse +button, the cursor will be positioned at the definition of the tag. You +can set the 'Tlist_Use_SingleClick' variable to 1 to jump to a tag when +you single click on the tag name using the mouse. By default this variable +is set to zero. +> + let Tlist_Use_SingleClick = 1 +< +Due to a bug in Vim, if you set 'Tlist_Use_SingleClick' to 1 and try to resize +the taglist window using the mouse, then Vim will crash. This problem is fixed +in Vim 6.3 and above. In the meantime, instead of resizing the taglist window +using the mouse, you can use normal Vim window resizing commands to resize the +taglist window. + + *'Tlist_WinHeight'* +Tlist_WinHeight~ +The default height of the horizontally split taglist window is 10. This can be +changed by modifying the 'Tlist_WinHeight' variable: +> + let Tlist_WinHeight = 20 +< +The |'winfixheight'| option is set for the taglist window, to maintain the +height of the taglist window, when new Vim windows are opened and existing +windows are closed. + + *'Tlist_WinWidth'* +Tlist_WinWidth~ +The default width of the vertically split taglist window is 30. This can be +changed by modifying the 'Tlist_WinWidth' variable: +> + let Tlist_WinWidth = 20 +< +Note that the value of the |'winwidth'| option setting determines the minimum +width of the current window. If you set the 'Tlist_WinWidth' variable to a +value less than that of the |'winwidth'| option setting, then Vim will use the +value of the |'winwidth'| option. + +When new Vim windows are opened and existing windows are closed, the taglist +plugin will try to maintain the width of the taglist window to the size +specified by the 'Tlist_WinWidth' variable. + +============================================================================== + *taglist-commands* +7. Commands~ + +The taglist plugin provides the following ex-mode commands: + +|:TlistAddFiles| Add multiple files to the taglist. +|:TlistAddFilesRecursive| + Add files recursively to the taglist. +|:TlistClose| Close the taglist window. +|:TlistDebug| Start logging of taglist debug messages. +|:TlistLock| Stop adding new files to the taglist. +|:TlistMessages| Display the logged taglist plugin debug messages. +|:TlistOpen| Open and jump to the taglist window. +|:TlistSessionSave| Save the information about files and tags in the + taglist to a session file. +|:TlistSessionLoad| Load the information about files and tags stored + in a session file to taglist. +|:TlistShowPrototype| Display the prototype of the tag at or before the + specified line number. +|:TlistShowTag| Display the name of the tag defined at or before the + specified line number. +|:TlistHighlightTag| Highlight the current tag in the taglist window. +|:TlistToggle| Open or close (toggle) the taglist window. +|:TlistUndebug| Stop logging of taglist debug messages. +|:TlistUnlock| Start adding new files to the taglist. +|:TlistUpdate| Update the tags for the current buffer. + + *:TlistAddFiles* +:TlistAddFiles {file(s)} [file(s) ...] + Add one or more specified files to the taglist. You can + specify multiple filenames using wildcards. To specify a + file name with space character, you should escape the space + character with a backslash. + Examples: +> + :TlistAddFiles *.c *.cpp + :TlistAddFiles file1.html file2.html +< + If you specify a large number of files, then it will take some + time for the taglist plugin to process all of them. The + specified files will not be edited in a Vim window and will + not be added to the Vim buffer list. + + *:TlistAddFilesRecursive* +:TlistAddFilesRecursive {directory} [ {pattern} ] + Add files matching {pattern} recursively from the specified + {directory} to the taglist. If {pattern} is not specified, + then '*' is assumed. To specify the current directory, use "." + for {directory}. To specify a directory name with space + character, you should escape the space character with a + backslash. + Examples: +> + :TlistAddFilesRecursive myproject *.java + :TlistAddFilesRecursive smallproject +< + If large number of files are present in the specified + directory tree, then it will take some time for the taglist + plugin to process all of them. + + *:TlistClose* +:TlistClose Close the taglist window. This command can be used from any + one of the Vim windows. + + *:TlistDebug* +:TlistDebug [filename] + Start logging of debug messages from the taglist plugin. + If {filename} is specified, then the debug messages are stored + in the specified file. Otherwise, the debug messages are + stored in a script local variable. If the file {filename} is + already present, then it is overwritten. + + *:TlistLock* +:TlistLock + Lock the taglist and don't process new files. After this + command is executed, newly edited files will not be added to + the taglist. + + *:TlistMessages* +:TlistMessages + Display the logged debug messages from the taglist plugin + in a window. This command works only when logging to a + script-local variable. + + *:TlistOpen* +:TlistOpen Open and jump to the taglist window. Creates the taglist + window, if the window is not opened currently. After executing + this command, the cursor is moved to the taglist window. When + the taglist window is opened for the first time, all the files + in the buffer list are processed and the tags defined in them + are displayed in the taglist window. + + *:TlistSessionSave* +:TlistSessionSave {filename} + Saves the information about files and tags in the taglist to + the specified file. This command can be used to save and + restore the taglist contents across Vim sessions. + + *:TlistSessionLoad* +:TlistSessionLoad {filename} + Load the information about files and tags stored in the + specified session file to the taglist. + + *:TlistShowPrototype* +:TlistShowPrototype [filename] [linenumber] + Display the prototype of the tag at or before the specified + line number. If the file name and the line number are not + specified, then the current file name and line number are + used. A tag spans multiple lines starting from the line where + it is defined to the line before the next tag. This command + displays the prototype for the tag for any line number in this + range. + + *:TlistShowTag* +:TlistShowTag [filename] [linenumber] + Display the name of the tag defined at or before the specified + line number. If the file name and the line number are not + specified, then the current file name and line number are + used. A tag spans multiple lines starting from the line where + it is defined to the line before the next tag. This command + displays the tag name for any line number in this range. + + *:TlistHighlightTag* +:TlistHighlightTag + Highlight the current tag in the taglist window. By default, + the taglist plugin periodically updates the taglist window to + highlight the current tag. This command can be used to force + the taglist plugin to highlight the current tag. + + *:TlistToggle* +:TlistToggle Open or close (toggle) the taglist window. Opens the taglist + window, if the window is not opened currently. Closes the + taglist window, if the taglist window is already opened. When + the taglist window is opened for the first time, all the files + in the buffer list are processed and the tags are displayed in + the taglist window. After executing this command, the cursor + is not moved from the current window to the taglist window. + + *:TlistUndebug* +:TlistUndebug + Stop logging of debug messages from the taglist plugin. + + *:TlistUnlock* +:TlistUnlock + Unlock the taglist and start processing newly edited files. + + *:TlistUpdate* +:TlistUpdate Update the tags information for the current buffer. This + command can be used to re-process the current file/buffer and + get the tags information. As the taglist plugin uses the file + saved in the disk (instead of the file displayed in a Vim + buffer), you should save a modified buffer before you update + the taglist. Otherwise the listed tags will not include the + new tags created in the buffer. You can use this command even + when the taglist window is not opened. + +============================================================================== + *taglist-functions* +8. Global functions~ + +The taglist plugin provides several global functions that can be used from +other Vim plugins to interact with the taglist plugin. These functions are +described below. + +|Tlist_Update_File_Tags()| Update the tags for the specified file +|Tlist_Get_Tag_Prototype_By_Line()| Return the prototype of the tag at or + before the specified line number in the + specified file. +|Tlist_Get_Tagname_By_Line()| Return the name of the tag at or + before the specified line number in + the specified file. +|Tlist_Set_App()| Set the name of the application + controlling the taglist window. + + *Tlist_Update_File_Tags()* +Tlist_Update_File_Tags({filename}, {filetype}) + Update the tags for the file {filename}. The second argument + specifies the Vim filetype for the file. If the taglist plugin + has not processed the file previously, then the exuberant + ctags tool is invoked to generate the tags for the file. + + *Tlist_Get_Tag_Prototype_By_Line()* +Tlist_Get_Tag_Prototype_By_Line([{filename}, {linenumber}]) + Return the prototype of the tag at or before the specified + line number in the specified file. If the filename and line + number are not specified, then the current buffer name and the + current line number are used. + + *Tlist_Get_Tagname_By_Line()* +Tlist_Get_Tagname_By_Line([{filename}, {linenumber}]) + Return the name of the tag at or before the specified line + number in the specified file. If the filename and line number + are not specified, then the current buffer name and the + current line number are used. + + *Tlist_Set_App()* +Tlist_Set_App({appname}) + Set the name of the plugin that controls the taglist plugin + window and buffer. This can be used to integrate the taglist + plugin with other Vim plugins. + + For example, the winmanager plugin and the Cream package use + this function and specify the appname as "winmanager" and + "cream" respectively. + + By default, the taglist plugin is a stand-alone plugin and + controls the taglist window and buffer. If the taglist window + is controlled by an external plugin, then the appname should + be set appropriately. + +============================================================================== + *taglist-extend* +9. Extending~ + +The taglist plugin supports all the languages supported by the exuberant ctags +tool, which includes the following languages: Assembly, ASP, Awk, Beta, C, +C++, C#, Cobol, Eiffel, Erlang, Fortran, HTML, Java, Javascript, Lisp, Lua, +Make, Pascal, Perl, PHP, Python, Rexx, Ruby, Scheme, Shell, Slang, SML, Sql, +TCL, Verilog, Vim and Yacc. + +You can extend the taglist plugin to add support for new languages and also +modify the support for the above listed languages. + +You should NOT make modifications to the taglist plugin script file to add +support for new languages. You will lose these changes when you upgrade to the +next version of the taglist plugin. Instead you should follow the below +described instructions to extend the taglist plugin. + +You can extend the taglist plugin by setting variables in the .vimrc or _vimrc +file. The name of these variables depends on the language name and is +described below. + +Modifying support for an existing language~ +To modify the support for an already supported language, you have to set the +tlist_xxx_settings variable in the ~/.vimrc or $HOME/_vimrc file. Replace xxx +with the Vim filetype name for the language file. For example, to modify the +support for the perl language files, you have to set the tlist_perl_settings +variable. To modify the support for java files, you have to set the +tlist_java_settings variable. + +To determine the filetype name used by Vim for a file, use the following +command in the buffer containing the file: + + :set filetype + +The above command will display the Vim filetype for the current buffer. + +The format of the value set in the tlist_xxx_settings variable is + + ;flag1:name1;flag2:name2;flag3:name3 + +The different fields in the value are separated by the ';' character. + +The first field 'language_name' is the name used by exuberant ctags to refer +to this language file. This name can be different from the file type name used +by Vim. For example, for C++, the language name used by ctags is 'c++' but the +filetype name used by Vim is 'cpp'. To get the list of language names +supported by exuberant ctags, use the following command: + + $ ctags --list-maps=all + +The remaining fields follow the format "flag:name". The sub-field 'flag' is +the language specific flag used by exuberant ctags to generate the +corresponding tags. For example, for the C language, to list only the +functions, the 'f' flag is used. To get the list of flags supported by +exuberant ctags for the various languages use the following command: + + $ ctags --list-kinds=all + +The sub-field 'name' specifies the title text to use for displaying the tags +of a particular type. For example, 'name' can be set to 'functions'. This +field can be set to any text string name. + +For example, to list only the classes and functions defined in a C++ language +file, add the following line to your .vimrc file: + + let tlist_cpp_settings = 'c++;c:class;f:function' + +In the above setting, 'cpp' is the Vim filetype name and 'c++' is the name +used by the exuberant ctags tool. 'c' and 'f' are the flags passed to +exuberant ctags to list C++ classes and functions and 'class' is the title +used for the class tags and 'function' is the title used for the function tags +in the taglist window. + +For example, to display only functions defined in a C file and to use "My +Functions" as the title for the function tags, use + + let tlist_c_settings = 'c;f:My Functions' + +When you set the tlist_xxx_settings variable, you will override the default +setting used by the taglist plugin for the 'xxx' language. You cannot add to +the default options used by the taglist plugin for a particular file type. To +add to the options used by the taglist plugin for a language, copy the option +values from the taglist plugin file to your .vimrc file and modify it. + +Adding support for a new language~ +If you want to add support for a new language to the taglist plugin, you need +to first extend the exuberant ctags tool. For more information about extending +exuberant ctags, visit the following page: + + http://ctags.sourceforge.net/EXTENDING.html + +To add support for a new language, set the tlist_xxx_settings variable in the +~/.vimrc file appropriately as described above. Replace 'xxx' in the variable +name with the Vim filetype name for the new language. + +For example, to extend the taglist plugin to support the latex language, you +can use the following line (assuming, you have already extended exuberant +ctags to support the latex language): + + let tlist_tex_settings='latex;b:bibitem;c:command;l:label' + +With the above line, when you edit files of filetype "tex" in Vim, the taglist +plugin will invoke the exuberant ctags tool passing the "latex" filetype and +the flags b, c and l to generate the tags. The text heading 'bibitem', +'command' and 'label' will be used in the taglist window for the tags which +are generated for the flags b, c and l respectively. + +============================================================================== + *taglist-faq* +10. Frequently Asked Questions~ + +Q. The taglist plugin doesn't work. The taglist window is empty and the tags + defined in a file are not displayed. +A. Are you using Vim version 6.0 and above? The taglist plugin relies on the + features supported by Vim version 6.0 and above. You can use the following + command to get the Vim version: +> + $ vim --version +< + Are you using exuberant ctags version 5.0 and above? The taglist plugin + relies on the features supported by exuberant ctags and will not work with + GNU ctags or the Unix ctags utility. You can use the following command to + determine whether the ctags installed in your system is exuberant ctags: +> + $ ctags --version +< + Is exuberant ctags present in one of the directories in your PATH? If not, + you need to set the Tlist_Ctags_Cmd variable to point to the location of + exuberant ctags. Use the following Vim command to verify that this is setup + correctly: +> + :echo system(Tlist_Ctags_Cmd . ' --version') +< + The above command should display the version information for exuberant + ctags. + + Did you turn on the Vim filetype detection? The taglist plugin relies on + the filetype detected by Vim and passes the filetype to the exuberant ctags + utility to parse the tags. Check the output of the following Vim command: +> + :filetype +< + The output of the above command should contain "filetype detection:ON". + To turn on the filetype detection, add the following line to the .vimrc or + _vimrc file: +> + filetype on +< + Is your version of Vim compiled with the support for the system() function? + The following Vim command should display 1: +> + :echo exists('*system') +< + In some Linux distributions (particularly Suse Linux), the default Vim + installation is built without the support for the system() function. The + taglist plugin uses the system() function to invoke the exuberant ctags + utility. You need to rebuild Vim after enabling the support for the + system() function. If you use the default build options, the system() + function will be supported. + + Do you have the |'shellslash'| option set? You can try disabling the + |'shellslash'| option. When the taglist plugin invokes the exuberant ctags + utility with the path to the file, if the incorrect slashes are used, then + you will see errors. + + Check the shell related Vim options values using the following command: +> + :set shell? shellcmdflag? shellpipe? + :set shellquote? shellredir? shellxquote? +< + If these options are set in your .vimrc or _vimrc file, try removing those + lines. + + Are you using a Unix shell in a MS-Windows environment? For example, + the Unix shell from the MKS-toolkit. Do you have the SHELL environment + set to point to this shell? You can try resetting the SHELL environment + variable. + + If you are using a Unix shell on MS-Windows, you should try to use + exuberant ctags that is compiled for Unix-like environments so that + exuberant ctags will understand path names with forward slash characters. + + Is your filetype supported by the exuberant ctags utility? The file types + supported by the exuberant ctags utility are listed in the ctags help. If a + file type is not supported, you have to extend exuberant ctags. You can use + the following command to list the filetypes supported by exuberant ctags: +> + ctags --list-languages +< + Run the following command from the shell prompt and check whether the tags + defined in your file are listed in the output from exuberant ctags: +> + ctags -f - --format=2 --excmd=pattern --fields=nks +< + If you see your tags in the output from the above command, then the + exuberant ctags utility is properly parsing your file. + + Do you have the .ctags or _ctags or the ctags.cnf file in your home + directory for specifying default options or for extending exuberant ctags? + If you do have this file, check the options in this file and make sure + these options are not interfering with the operation of the taglist plugin. + + If you are using MS-Windows, check the value of the TEMP and TMP + environment variables. If these environment variables are set to a path + with space characters in the name, then try using the DOS 8.3 short name + for the path or set them to a path without the space characters in the + name. For example, if the temporary directory name is "C:\Documents and + Settings\xyz\Local Settings\Temp", then try setting the TEMP variable to + the following: +> + set TEMP=C:\DOCUMEN~1\xyz\LOCALS~1\Temp +< + If exuberant ctags is installed in a directory with space characters in the + name, then try adding the directory to the PATH environment variable or try + setting the 'Tlist_Ctags_Cmd' variable to the shortest path name to ctags + or try copying the exuberant ctags to a path without space characters in + the name. For example, if exuberant ctags is installed in the directory + "C:\Program Files\Ctags", then try setting the 'Tlist_Ctags_Cmd' variable + as below: +> + let Tlist_Ctags_Cmd='C:\Progra~1\Ctags\ctags.exe' +< + If you are using a cygwin compiled version of exuberant ctags on MS-Windows, + make sure that either you have the cygwin compiled sort utility installed + and available in your PATH or compile exuberant ctags with internal sort + support. Otherwise, when exuberant ctags sorts the tags output by invoking + the sort utility, it may end up invoking the MS-Windows version of + sort.exe, thereby resulting in failure. + +Q. When I try to open the taglist window, I am seeing the following error + message. How do I fix this problem? + + Taglist: Failed to generate tags for /my/path/to/file + ctags: illegal option -- -^@usage: ctags [-BFadtuwvx] [-f tagsfile] file ... + +A. The taglist plugin will work only with the exuberant ctags tool. You + cannot use the GNU ctags or the Unix ctags program with the taglist plugin. + You will see an error message similar to the one shown above, if you try + use a non-exuberant ctags program with Vim. To fix this problem, either add + the exuberant ctags tool location to the PATH environment variable or set + the 'Tlist_Ctags_Cmd' variable. + +Q. A file has more than one tag with the same name. When I select a tag name + from the taglist window, the cursor is positioned at the incorrect tag + location. +A. The taglist plugin uses the search pattern generated by the exuberant ctags + utility to position the cursor at the location of a tag definition. If a + file has more than one tag with the same name and same prototype, then the + search pattern will be the same. In this case, when searching for the tag + pattern, the cursor may be positioned at the incorrect location. + +Q. I have made some modifications to my file and introduced new + functions/classes/variables. I have not yet saved my file. The taglist + plugin is not displaying the new tags when I update the taglist window. +A. The exuberant ctags utility will process only files that are present in the + disk. To list the tags defined in a file, you have to save the file and + then update the taglist window. + +Q. I have created a ctags file using the exuberant ctags utility for my source + tree. How do I configure the taglist plugin to use this tags file? +A. The taglist plugin doesn't use a tags file stored in disk. For every opened + file, the taglist plugin invokes the exuberant ctags utility to get the + list of tags dynamically. The Vim system() function is used to invoke + exuberant ctags and get the ctags output. This function internally uses a + temporary file to store the output. This file is deleted after the output + from the command is read. So you will never see the file that contains the + output of exuberant ctags. + +Q. When I set the |'updatetime'| option to a low value (less than 1000) and if + I keep pressing a key with the taglist window open, the current buffer + contents are changed. Why is this? +A. The taglist plugin uses the |CursorHold| autocmd to highlight the current + tag. The CursorHold autocmd triggers for every |'updatetime'| milliseconds. + If the |'updatetime'| option is set to a low value, then the CursorHold + autocmd will be triggered frequently. As the taglist plugin changes + the focus to the taglist window to highlight the current tag, this could + interfere with the key movement resulting in changing the contents of + the current buffer. The workaround for this problem is to not set the + |'updatetime'| option to a low value. + +============================================================================== + *taglist-license* +11. License~ +Permission is hereby granted to use and distribute the taglist plugin, with or +without modifications, provided that this copyright notice is copied with it. +Like anything else that's free, taglist.vim is provided *as is* and comes with +no warranty of any kind, either expressed or implied. In no event will the +copyright holder be liable for any damamges resulting from the use of this +software. + +============================================================================== + *taglist-todo* +12. Todo~ + +1. Group tags according to the scope and display them. For example, + group all the tags belonging to a C++/Java class +2. Support for displaying tags in a modified (not-yet-saved) file. +3. Automatically open the taglist window only for selected filetypes. + For other filetypes, close the taglist window. +4. When using the shell from the MKS toolkit, the taglist plugin + doesn't work. +5. The taglist plugin doesn't work with files edited remotely using the + netrw plugin. The exuberant ctags utility cannot process files over + scp/rcp/ftp, etc. + +============================================================================== + +vim:tw=78:ts=8:noet:ft=help: diff --git a/vim/doc/tags b/vim/doc/tags new file mode 100644 index 0000000..3411667 --- /dev/null +++ b/vim/doc/tags @@ -0,0 +1,218 @@ +'NERDAllowAnyVisualDelims' NERD_commenter.txt /*'NERDAllowAnyVisualDelims'* +'NERDBlockComIgnoreEmpty' NERD_commenter.txt /*'NERDBlockComIgnoreEmpty'* +'NERDChristmasTree' NERD_tree.txt /*'NERDChristmasTree'* +'NERDCommentWholeLinesInVMode' NERD_commenter.txt /*'NERDCommentWholeLinesInVMode'* +'NERDCompactSexyComs' NERD_commenter.txt /*'NERDCompactSexyComs'* +'NERDCreateDefaultMappings' NERD_commenter.txt /*'NERDCreateDefaultMappings'* +'NERDDefaultNesting' NERD_commenter.txt /*'NERDDefaultNesting'* +'NERDLPlace' NERD_commenter.txt /*'NERDLPlace'* +'NERDMenuMode' NERD_commenter.txt /*'NERDMenuMode'* +'NERDRPlace' NERD_commenter.txt /*'NERDRPlace'* +'NERDRemoveAltComs' NERD_commenter.txt /*'NERDRemoveAltComs'* +'NERDRemoveExtraSpaces' NERD_commenter.txt /*'NERDRemoveExtraSpaces'* +'NERDSpaceDelims' NERD_commenter.txt /*'NERDSpaceDelims'* +'NERDTreeAutoCenter' NERD_tree.txt /*'NERDTreeAutoCenter'* +'NERDTreeAutoCenterThreshold' NERD_tree.txt /*'NERDTreeAutoCenterThreshold'* +'NERDTreeBookmarksFile' NERD_tree.txt /*'NERDTreeBookmarksFile'* +'NERDTreeCaseSensitiveSort' NERD_tree.txt /*'NERDTreeCaseSensitiveSort'* +'NERDTreeChDirMode' NERD_tree.txt /*'NERDTreeChDirMode'* +'NERDTreeHighlightCursorline' NERD_tree.txt /*'NERDTreeHighlightCursorline'* +'NERDTreeHijackNetrw' NERD_tree.txt /*'NERDTreeHijackNetrw'* +'NERDTreeIgnore' NERD_tree.txt /*'NERDTreeIgnore'* +'NERDTreeMouseMode' NERD_tree.txt /*'NERDTreeMouseMode'* +'NERDTreeQuitOnOpen' NERD_tree.txt /*'NERDTreeQuitOnOpen'* +'NERDTreeShowBookmarks' NERD_tree.txt /*'NERDTreeShowBookmarks'* +'NERDTreeShowFiles' NERD_tree.txt /*'NERDTreeShowFiles'* +'NERDTreeShowHidden' NERD_tree.txt /*'NERDTreeShowHidden'* +'NERDTreeShowLineNumbers' NERD_tree.txt /*'NERDTreeShowLineNumbers'* +'NERDTreeSortOrder' NERD_tree.txt /*'NERDTreeSortOrder'* +'NERDTreeStatusline' NERD_tree.txt /*'NERDTreeStatusline'* +'NERDTreeWinPos' NERD_tree.txt /*'NERDTreeWinPos'* +'NERDTreeWinSize' NERD_tree.txt /*'NERDTreeWinSize'* +'NERDUsePlaceHolders' NERD_commenter.txt /*'NERDUsePlaceHolders'* +'Tlist_Auto_Highlight_Tag' taglist.txt /*'Tlist_Auto_Highlight_Tag'* +'Tlist_Auto_Open' taglist.txt /*'Tlist_Auto_Open'* +'Tlist_Auto_Update' taglist.txt /*'Tlist_Auto_Update'* +'Tlist_Close_On_Select' taglist.txt /*'Tlist_Close_On_Select'* +'Tlist_Compact_Format' taglist.txt /*'Tlist_Compact_Format'* +'Tlist_Ctags_Cmd' taglist.txt /*'Tlist_Ctags_Cmd'* +'Tlist_Display_Prototype' taglist.txt /*'Tlist_Display_Prototype'* +'Tlist_Display_Tag_Scope' taglist.txt /*'Tlist_Display_Tag_Scope'* +'Tlist_Enable_Fold_Column' taglist.txt /*'Tlist_Enable_Fold_Column'* +'Tlist_Exit_OnlyWindow' taglist.txt /*'Tlist_Exit_OnlyWindow'* +'Tlist_File_Fold_Auto_Close' taglist.txt /*'Tlist_File_Fold_Auto_Close'* +'Tlist_GainFocus_On_ToggleOpen' taglist.txt /*'Tlist_GainFocus_On_ToggleOpen'* +'Tlist_Highlight_Tag_On_BufEnter' taglist.txt /*'Tlist_Highlight_Tag_On_BufEnter'* +'Tlist_Inc_Winwidth' taglist.txt /*'Tlist_Inc_Winwidth'* +'Tlist_Max_Submenu_Items' taglist.txt /*'Tlist_Max_Submenu_Items'* +'Tlist_Max_Tag_Length' taglist.txt /*'Tlist_Max_Tag_Length'* +'Tlist_Process_File_Always' taglist.txt /*'Tlist_Process_File_Always'* +'Tlist_Show_Menu' taglist.txt /*'Tlist_Show_Menu'* +'Tlist_Show_One_File' taglist.txt /*'Tlist_Show_One_File'* +'Tlist_Sort_Type' taglist.txt /*'Tlist_Sort_Type'* +'Tlist_Use_Horiz_Window' taglist.txt /*'Tlist_Use_Horiz_Window'* +'Tlist_Use_Right_Window' taglist.txt /*'Tlist_Use_Right_Window'* +'Tlist_Use_SingleClick' taglist.txt /*'Tlist_Use_SingleClick'* +'Tlist_WinHeight' taglist.txt /*'Tlist_WinHeight'* +'Tlist_WinWidth' taglist.txt /*'Tlist_WinWidth'* +'loaded_nerd_comments' NERD_commenter.txt /*'loaded_nerd_comments'* +'loaded_nerd_tree' NERD_tree.txt /*'loaded_nerd_tree'* +:NERDTree NERD_tree.txt /*:NERDTree* +:NERDTreeClose NERD_tree.txt /*:NERDTreeClose* +:NERDTreeFromBookmark NERD_tree.txt /*:NERDTreeFromBookmark* +:NERDTreeMirror NERD_tree.txt /*:NERDTreeMirror* +:NERDTreeToggle NERD_tree.txt /*:NERDTreeToggle* +:TlistAddFiles taglist.txt /*:TlistAddFiles* +:TlistAddFilesRecursive taglist.txt /*:TlistAddFilesRecursive* +:TlistClose taglist.txt /*:TlistClose* +:TlistDebug taglist.txt /*:TlistDebug* +:TlistHighlightTag taglist.txt /*:TlistHighlightTag* +:TlistLock taglist.txt /*:TlistLock* +:TlistMessages taglist.txt /*:TlistMessages* +:TlistOpen taglist.txt /*:TlistOpen* +:TlistSessionLoad taglist.txt /*:TlistSessionLoad* +:TlistSessionSave taglist.txt /*:TlistSessionSave* +:TlistShowPrototype taglist.txt /*:TlistShowPrototype* +:TlistShowTag taglist.txt /*:TlistShowTag* +:TlistToggle taglist.txt /*:TlistToggle* +:TlistUndebug taglist.txt /*:TlistUndebug* +:TlistUnlock taglist.txt /*:TlistUnlock* +:TlistUpdate taglist.txt /*:TlistUpdate* +NERDComAbout NERD_commenter.txt /*NERDComAbout* +NERDComAlignedComment NERD_commenter.txt /*NERDComAlignedComment* +NERDComAltDelim NERD_commenter.txt /*NERDComAltDelim* +NERDComAppendComment NERD_commenter.txt /*NERDComAppendComment* +NERDComChangelog NERD_commenter.txt /*NERDComChangelog* +NERDComComment NERD_commenter.txt /*NERDComComment* +NERDComCredits NERD_commenter.txt /*NERDComCredits* +NERDComDefaultDelims NERD_commenter.txt /*NERDComDefaultDelims* +NERDComEOLComment NERD_commenter.txt /*NERDComEOLComment* +NERDComFiletypes NERD_commenter.txt /*NERDComFiletypes* +NERDComFunctionality NERD_commenter.txt /*NERDComFunctionality* +NERDComFunctionalityDetails NERD_commenter.txt /*NERDComFunctionalityDetails* +NERDComFunctionalitySummary NERD_commenter.txt /*NERDComFunctionalitySummary* +NERDComHeuristics NERD_commenter.txt /*NERDComHeuristics* +NERDComInsertComment NERD_commenter.txt /*NERDComInsertComment* +NERDComInvertComment NERD_commenter.txt /*NERDComInvertComment* +NERDComIssues NERD_commenter.txt /*NERDComIssues* +NERDComLicense NERD_commenter.txt /*NERDComLicense* +NERDComMappings NERD_commenter.txt /*NERDComMappings* +NERDComMinimalComment NERD_commenter.txt /*NERDComMinimalComment* +NERDComNERDComment NERD_commenter.txt /*NERDComNERDComment* +NERDComNestedComment NERD_commenter.txt /*NERDComNestedComment* +NERDComNesting NERD_commenter.txt /*NERDComNesting* +NERDComOptions NERD_commenter.txt /*NERDComOptions* +NERDComOptionsDetails NERD_commenter.txt /*NERDComOptionsDetails* +NERDComOptionsSummary NERD_commenter.txt /*NERDComOptionsSummary* +NERDComSexyComment NERD_commenter.txt /*NERDComSexyComment* +NERDComSexyComments NERD_commenter.txt /*NERDComSexyComments* +NERDComToggleComment NERD_commenter.txt /*NERDComToggleComment* +NERDComUncommentLine NERD_commenter.txt /*NERDComUncommentLine* +NERDComYankComment NERD_commenter.txt /*NERDComYankComment* +NERDCommenter NERD_commenter.txt /*NERDCommenter* +NERDCommenterContents NERD_commenter.txt /*NERDCommenterContents* +NERDTree NERD_tree.txt /*NERDTree* +NERDTree-! NERD_tree.txt /*NERDTree-!* +NERDTree-? NERD_tree.txt /*NERDTree-?* +NERDTree-B NERD_tree.txt /*NERDTree-B* +NERDTree-C NERD_tree.txt /*NERDTree-C* +NERDTree-D NERD_tree.txt /*NERDTree-D* +NERDTree-F NERD_tree.txt /*NERDTree-F* +NERDTree-I NERD_tree.txt /*NERDTree-I* +NERDTree-J NERD_tree.txt /*NERDTree-J* +NERDTree-K NERD_tree.txt /*NERDTree-K* +NERDTree-O NERD_tree.txt /*NERDTree-O* +NERDTree-P NERD_tree.txt /*NERDTree-P* +NERDTree-R NERD_tree.txt /*NERDTree-R* +NERDTree-T NERD_tree.txt /*NERDTree-T* +NERDTree-U NERD_tree.txt /*NERDTree-U* +NERDTree-X NERD_tree.txt /*NERDTree-X* +NERDTree-c-j NERD_tree.txt /*NERDTree-c-j* +NERDTree-c-k NERD_tree.txt /*NERDTree-c-k* +NERDTree-contents NERD_tree.txt /*NERDTree-contents* +NERDTree-e NERD_tree.txt /*NERDTree-e* +NERDTree-f NERD_tree.txt /*NERDTree-f* +NERDTree-gi NERD_tree.txt /*NERDTree-gi* +NERDTree-go NERD_tree.txt /*NERDTree-go* +NERDTree-gs NERD_tree.txt /*NERDTree-gs* +NERDTree-i NERD_tree.txt /*NERDTree-i* +NERDTree-m NERD_tree.txt /*NERDTree-m* +NERDTree-o NERD_tree.txt /*NERDTree-o* +NERDTree-p NERD_tree.txt /*NERDTree-p* +NERDTree-q NERD_tree.txt /*NERDTree-q* +NERDTree-r NERD_tree.txt /*NERDTree-r* +NERDTree-s NERD_tree.txt /*NERDTree-s* +NERDTree-t NERD_tree.txt /*NERDTree-t* +NERDTree-u NERD_tree.txt /*NERDTree-u* +NERDTree-x NERD_tree.txt /*NERDTree-x* +NERDTreeAbout NERD_tree.txt /*NERDTreeAbout* +NERDTreeBookmarkCommands NERD_tree.txt /*NERDTreeBookmarkCommands* +NERDTreeBookmarkTable NERD_tree.txt /*NERDTreeBookmarkTable* +NERDTreeBookmarks NERD_tree.txt /*NERDTreeBookmarks* +NERDTreeChangelog NERD_tree.txt /*NERDTreeChangelog* +NERDTreeCredits NERD_tree.txt /*NERDTreeCredits* +NERDTreeFilesysMenu NERD_tree.txt /*NERDTreeFilesysMenu* +NERDTreeFunctionality NERD_tree.txt /*NERDTreeFunctionality* +NERDTreeGlobalCommands NERD_tree.txt /*NERDTreeGlobalCommands* +NERDTreeHacking NERD_tree.txt /*NERDTreeHacking* +NERDTreeInvalidBookmarks NERD_tree.txt /*NERDTreeInvalidBookmarks* +NERDTreeLicense NERD_tree.txt /*NERDTreeLicense* +NERDTreeMappings NERD_tree.txt /*NERDTreeMappings* +NERDTreeOptionDetails NERD_tree.txt /*NERDTreeOptionDetails* +NERDTreeOptionSummary NERD_tree.txt /*NERDTreeOptionSummary* +NERDTreeOptions NERD_tree.txt /*NERDTreeOptions* +NERD_commenter.txt NERD_commenter.txt /*NERD_commenter.txt* +NERD_tree.txt NERD_tree.txt /*NERD_tree.txt* +Tlist_Get_Tag_Prototype_By_Line() taglist.txt /*Tlist_Get_Tag_Prototype_By_Line()* +Tlist_Get_Tagname_By_Line() taglist.txt /*Tlist_Get_Tagname_By_Line()* +Tlist_Set_App() taglist.txt /*Tlist_Set_App()* +Tlist_Update_File_Tags() taglist.txt /*Tlist_Update_File_Tags()* +bufexplorer bufexplorer.txt /*bufexplorer* +bufexplorer-changelog bufexplorer.txt /*bufexplorer-changelog* +bufexplorer-credits bufexplorer.txt /*bufexplorer-credits* +bufexplorer-customization bufexplorer.txt /*bufexplorer-customization* +bufexplorer-installation bufexplorer.txt /*bufexplorer-installation* +bufexplorer-todo bufexplorer.txt /*bufexplorer-todo* +bufexplorer-usage bufexplorer.txt /*bufexplorer-usage* +bufexplorer.txt bufexplorer.txt /*bufexplorer.txt* +buffer-explorer bufexplorer.txt /*buffer-explorer* +g:bufExplorerDefaultHelp bufexplorer.txt /*g:bufExplorerDefaultHelp* +g:bufExplorerDetailedHelp bufexplorer.txt /*g:bufExplorerDetailedHelp* +g:bufExplorerFindActive bufexplorer.txt /*g:bufExplorerFindActive* +g:bufExplorerReverseSort bufexplorer.txt /*g:bufExplorerReverseSort* +g:bufExplorerShowDirectories bufexplorer.txt /*g:bufExplorerShowDirectories* +g:bufExplorerShowRelativePath bufexplorer.txt /*g:bufExplorerShowRelativePath* +g:bufExplorerShowUnlisted bufexplorer.txt /*g:bufExplorerShowUnlisted* +g:bufExplorerSortBy bufexplorer.txt /*g:bufExplorerSortBy* +g:bufExplorerSplitBelow bufexplorer.txt /*g:bufExplorerSplitBelow* +g:bufExplorerSplitOutPathName bufexplorer.txt /*g:bufExplorerSplitOutPathName* +g:bufExplorerSplitRight bufexplorer.txt /*g:bufExplorerSplitRight* +project project.txt /*project* +project-adding-mappings project.txt /*project-adding-mappings* +project-example project.txt /*project-example* +project-flags project.txt /*project-flags* +project-inheritance project.txt /*project-inheritance* +project-invoking project.txt /*project-invoking* +project-mappings project.txt /*project-mappings* +project-plugin project.txt /*project-plugin* +project-settings project.txt /*project-settings* +project-syntax project.txt /*project-syntax* +project-tips project.txt /*project-tips* +project.txt project.txt /*project.txt* +taglist-commands taglist.txt /*taglist-commands* +taglist-debug taglist.txt /*taglist-debug* +taglist-extend taglist.txt /*taglist-extend* +taglist-faq taglist.txt /*taglist-faq* +taglist-functions taglist.txt /*taglist-functions* +taglist-install taglist.txt /*taglist-install* +taglist-internet taglist.txt /*taglist-internet* +taglist-intro taglist.txt /*taglist-intro* +taglist-keys taglist.txt /*taglist-keys* +taglist-license taglist.txt /*taglist-license* +taglist-menu taglist.txt /*taglist-menu* +taglist-options taglist.txt /*taglist-options* +taglist-requirements taglist.txt /*taglist-requirements* +taglist-session taglist.txt /*taglist-session* +taglist-todo taglist.txt /*taglist-todo* +taglist-using taglist.txt /*taglist-using* +taglist.txt taglist.txt /*taglist.txt* diff --git a/vim/ftplugin/mako.vim b/vim/ftplugin/mako.vim new file mode 100644 index 0000000..3103eb0 --- /dev/null +++ b/vim/ftplugin/mako.vim @@ -0,0 +1,86 @@ +" Vim syntax file +" Language: Mako +" Maintainer: Armin Ronacher +" URL: http://lucumr.pocoo.org/ +" Last Change: 2008 September 12 +" Version: 0.6.1 +" +" Thanks to Brine Rue who noticed a bug in the +" delimiter handling. +" +" Known Limitations +" the <%text> block does not have correct attributes + +" For version 5.x: Clear all syntax items +" For version 6.x: Quit when a syntax file was already loaded +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + +if !exists("main_syntax") + let main_syntax = "html" +endif + +"Source the html syntax file +ru! syntax/html.vim +unlet b:current_syntax + +"Put the python syntax file in @pythonTop +syn include @pythonTop syntax/python.vim + +" End keywords +syn keyword makoEnd contained endfor endwhile endif endtry enddef + +" Block rules +syn region makoLine matchgroup=makoDelim start=#^\s*%# end=#$# keepend contains=@pythonTop,makoEnd +syn region makoBlock matchgroup=makoDelim start=#<%!\?# end=#%># keepend contains=@pythonTop,makoEnd + +" Variables +syn region makoNested start="{" end="}" transparent display contained contains=makoNested,@pythonTop +syn region makoVariable matchgroup=makoDelim start=#\${# end=#}# contains=makoNested,@pythonTop + +" Comments +syn region makoComment start="^\s*##" end="$" +syn region makoDocComment matchgroup=makoDelim start="<%doc>" end="" keepend + +" Literal Blocks +syn region makoText matchgroup=makoDelim start="<%text[^>]*>" end="" + +" Attribute Sublexing +syn match makoAttributeKey containedin=makoTag contained "[a-zA-Z_][a-zA-Z0-9_]*=" +syn region makoAttributeValue containedin=makoTag contained start=/"/ skip=/\\"/ end=/"/ +syn region makoAttributeValue containedin=MakoTag contained start=/'/ skip=/\\'/ end=/'/ + +" Tags +syn region makoTag matchgroup=makoDelim start="<%\(def\|call\|page\|include\|namespace\|inherit\)\>" end="/\?>" +syn match makoDelim "" + +" Newline Escapes +syn match makoEscape /\\$/ + +" Default highlighting links +if version >= 508 || !exists("did_mako_syn_inits") + if version < 508 + let did_mako_syn_inits = 1 + com -nargs=+ HiLink hi link + else + com -nargs=+ HiLink hi def link + endif + + HiLink makoDocComment makoComment + HiLink makoDefEnd makoDelim + + HiLink makoAttributeKey Type + HiLink makoAttributeValue String + HiLink makoText Normal + HiLink makoDelim Preproc + HiLink makoEnd Keyword + HiLink makoComment Comment + HiLink makoEscape Special + + delc HiLink +endif + +let b:current_syntax = "eruby" diff --git a/vim/ftplugin/python_fn.vim b/vim/ftplugin/python_fn.vim new file mode 100644 index 0000000..fbdd003 --- /dev/null +++ b/vim/ftplugin/python_fn.vim @@ -0,0 +1,446 @@ +" -*- vim -*- +" FILE: python.vim +" LAST MODIFICATION: 2008-05-17 6:29pm +" (C) Copyright 2001-2005 Mikael Berthe +" Maintained by Jon Franklin +" Version: 1.12 + +" USAGE: +" +" Save this file to $VIMFILES/ftplugin/python.vim. You can have multiple +" python ftplugins by creating $VIMFILES/ftplugin/python and saving your +" ftplugins in that directory. If saving this to the global ftplugin +" directory, this is the recommended method, since vim ships with an +" ftplugin/python.vim file already. +" You can set the global variable "g:py_select_leading_comments" to 0 +" if you don't want to select comments preceding a declaration (these +" are usually the description of the function/class). +" You can set the global variable "g:py_select_trailing_comments" to 0 +" if you don't want to select comments at the end of a function/class. +" If these variables are not defined, both leading and trailing comments +" are selected. +" Example: (in your .vimrc) "let g:py_select_leading_comments = 0" +" You may want to take a look at the 'shiftwidth' option for the +" shift commands... +" +" REQUIREMENTS: +" vim (>= 7) +" +" Shortcuts: +" ]t -- Jump to beginning of block +" ]e -- Jump to end of block +" ]v -- Select (Visual Line Mode) block +" ]< -- Shift block to left +" ]> -- Shift block to right +" ]# -- Comment selection +" ]u -- Uncomment selection +" ]c -- Select current/previous class +" ]d -- Select current/previous function +" ] -- Jump to previous line with the same/lower indentation +" ] -- Jump to next line with the same/lower indentation + +" Only do this when not done yet for this buffer +if exists("b:loaded_py_ftplugin") + finish +endif +let b:loaded_py_ftplugin = 1 + +map ]t :PBoB +vmap ]t :PBOBm'gv`` +map ]e :PEoB +vmap ]e :PEoBm'gv`` + +map ]v ]tV]e +map ]< ]tV]e< +vmap ]< < +map ]> ]tV]e> +vmap ]> > + +map ]# :call PythonCommentSelection() +vmap ]# :call PythonCommentSelection() +map ]u :call PythonUncommentSelection() +vmap ]u :call PythonUncommentSelection() + +map ]c :call PythonSelectObject("class") +map ]d :call PythonSelectObject("function") + +map ] :call PythonNextLine(-1) +map ] :call PythonNextLine(1) +" You may prefer use and ... :-) + +" jump to previous class +map ]J :call PythonDec("class", -1) +vmap ]J :call PythonDec("class", -1) + +" jump to next class +map ]j :call PythonDec("class", 1) +vmap ]j :call PythonDec("class", 1) + +" jump to previous function +map ]F :call PythonDec("function", -1) +vmap ]F :call PythonDec("function", -1) + +" jump to next function +map ]f :call PythonDec("function", 1) +vmap ]f :call PythonDec("function", 1) + + + +" Menu entries +nmenu &Python.Update\ IM-Python\ Menu + \:call UpdateMenu() +nmenu &Python.-Sep1- : +nmenu &Python.Beginning\ of\ Block[t + \]t +nmenu &Python.End\ of\ Block]e + \]e +nmenu &Python.-Sep2- : +nmenu &Python.Shift\ Block\ Left]< + \]< +vmenu &Python.Shift\ Block\ Left]< + \]< +nmenu &Python.Shift\ Block\ Right]> + \]> +vmenu &Python.Shift\ Block\ Right]> + \]> +nmenu &Python.-Sep3- : +vmenu &Python.Comment\ Selection]# + \]# +nmenu &Python.Comment\ Selection]# + \]# +vmenu &Python.Uncomment\ Selection]u + \]u +nmenu &Python.Uncomment\ Selection]u + \]u +nmenu &Python.-Sep4- : +nmenu &Python.Previous\ Class]J + \]J +nmenu &Python.Next\ Class]j + \]j +nmenu &Python.Previous\ Function]F + \]F +nmenu &Python.Next\ Function]f + \]f +nmenu &Python.-Sep5- : +nmenu &Python.Select\ Block]v + \]v +nmenu &Python.Select\ Function]d + \]d +nmenu &Python.Select\ Class]c + \]c +nmenu &Python.-Sep6- : +nmenu &Python.Previous\ Line\ wrt\ indent] + \] +nmenu &Python.Next\ Line\ wrt\ indent] + \] + +:com! PBoB execute "normal ".PythonBoB(line('.'), -1, 1)."G" +:com! PEoB execute "normal ".PythonBoB(line('.'), 1, 1)."G" +:com! UpdateMenu call UpdateMenu() + + +" Go to a block boundary (-1: previous, 1: next) +" If force_sel_comments is true, 'g:py_select_trailing_comments' is ignored +function! PythonBoB(line, direction, force_sel_comments) + let ln = a:line + let ind = indent(ln) + let mark = ln + let indent_valid = strlen(getline(ln)) + let ln = ln + a:direction + if (a:direction == 1) && (!a:force_sel_comments) && + \ exists("g:py_select_trailing_comments") && + \ (!g:py_select_trailing_comments) + let sel_comments = 0 + else + let sel_comments = 1 + endif + + while((ln >= 1) && (ln <= line('$'))) + if (sel_comments) || (match(getline(ln), "^\\s*#") == -1) + if (!indent_valid) + let indent_valid = strlen(getline(ln)) + let ind = indent(ln) + let mark = ln + else + if (strlen(getline(ln))) + if (indent(ln) < ind) + break + endif + let mark = ln + endif + endif + endif + let ln = ln + a:direction + endwhile + + return mark +endfunction + + +" Go to previous (-1) or next (1) class/function definition +function! PythonDec(obj, direction) + if (a:obj == "class") + let objregexp = "^\\s*class\\s\\+[a-zA-Z0-9_]\\+" + \ . "\\s*\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*:" + else + let objregexp = "^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*:" + endif + let flag = "W" + if (a:direction == -1) + let flag = flag."b" + endif + let res = search(objregexp, flag) +endfunction + + +" Comment out selected lines +" commentString is inserted in non-empty lines, and should be aligned with +" the block +function! PythonCommentSelection() range + let commentString = "#" + let cl = a:firstline + let ind = 1000 " I hope nobody use so long lines! :) + + " Look for smallest indent + while (cl <= a:lastline) + if strlen(getline(cl)) + let cind = indent(cl) + let ind = ((ind < cind) ? ind : cind) + endif + let cl = cl + 1 + endwhile + if (ind == 1000) + let ind = 1 + else + let ind = ind + 1 + endif + + let cl = a:firstline + execute ":".cl + " Insert commentString in each non-empty line, in column ind + while (cl <= a:lastline) + if strlen(getline(cl)) + execute "normal ".ind."|i".commentString + endif + execute "normal \" + let cl = cl + 1 + endwhile +endfunction + +" Uncomment selected lines +function! PythonUncommentSelection() range + " commentString could be different than the one from CommentSelection() + " For example, this could be "# \\=" + let commentString = "#" + let cl = a:firstline + while (cl <= a:lastline) + let ul = substitute(getline(cl), + \"\\(\\s*\\)".commentString."\\(.*\\)$", "\\1\\2", "") + call setline(cl, ul) + let cl = cl + 1 + endwhile +endfunction + + +" Select an object ("class"/"function") +function! PythonSelectObject(obj) + " Go to the object declaration + normal $ + call PythonDec(a:obj, -1) + let beg = line('.') + + if !exists("g:py_select_leading_comments") || (g:py_select_leading_comments) + let decind = indent(beg) + let cl = beg + while (cl>1) + let cl = cl - 1 + if (indent(cl) == decind) && (getline(cl)[decind] == "#") + let beg = cl + else + break + endif + endwhile + endif + + if (a:obj == "class") + let eod = "\\(^\\s*class\\s\\+[a-zA-Z0-9_]\\+\\s*" + \ . "\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*\\)\\@<=:" + else + let eod = "\\(^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*\\)\\@<=:" + endif + " Look for the end of the declaration (not always the same line!) + call search(eod, "") + + " Is it a one-line definition? + if match(getline('.'), "^\\s*\\(#.*\\)\\=$", col('.')) == -1 + let cl = line('.') + execute ":".beg + execute "normal V".cl."G" + else + " Select the whole block + execute "normal \" + let cl = line('.') + execute ":".beg + execute "normal V".PythonBoB(cl, 1, 0)."G" + endif +endfunction + + +" Jump to the next line with the same (or lower) indentation +" Useful for moving between "if" and "else", for example. +function! PythonNextLine(direction) + let ln = line('.') + let ind = indent(ln) + let indent_valid = strlen(getline(ln)) + let ln = ln + a:direction + + while((ln >= 1) && (ln <= line('$'))) + if (!indent_valid) && strlen(getline(ln)) + break + else + if (strlen(getline(ln))) + if (indent(ln) <= ind) + break + endif + endif + endif + let ln = ln + a:direction + endwhile + + execute "normal ".ln."G" +endfunction + +function! UpdateMenu() + " delete menu if it already exists, then rebuild it. + " this is necessary in case you've got multiple buffers open + " a future enhancement to this would be to make the menu aware of + " all buffers currently open, and group classes and functions by buffer + if exists("g:menuran") + aunmenu IM-Python + endif + let restore_fe = &foldenable + set nofoldenable + " preserve disposition of window and cursor + let cline=line('.') + let ccol=col('.') - 1 + norm H + let hline=line('.') + " create the menu + call MenuBuilder() + " restore disposition of window and cursor + exe "norm ".hline."Gzt" + let dnscroll=cline-hline + exe "norm ".dnscroll."j".ccol."l" + let &foldenable = restore_fe +endfunction + +function! MenuBuilder() + norm gg0 + let currentclass = -1 + let classlist = [] + let parentclass = "" + while line(".") < line("$") + " search for a class or function + if match ( getline("."), '^\s*class\s\+[_a-zA-Z].*:\|^\s*def\s\+[_a-zA-Z].*:' ) != -1 + norm ^ + let linenum = line('.') + let indentcol = col('.') + norm "nye + let classordef=@n + norm w"nywge + let objname=@n + let parentclass = FindParentClass(classlist, indentcol) + if classordef == "class" + call AddClass(objname, linenum, parentclass) + else " this is a function + call AddFunction(objname, linenum, parentclass) + endif + " We actually created a menu, so lets set the global variable + let g:menuran=1 + call RebuildClassList(classlist, [objname, indentcol], classordef) + endif " line matched + norm j + endwhile +endfunction + +" classlist contains the list of nested classes we are in. +" in most cases it will be empty or contain a single class +" but where a class is nested within another, it will contain 2 or more +" this function adds or removes classes from the list based on indentation +function! RebuildClassList(classlist, newclass, classordef) + let i = len(a:classlist) - 1 + while i > -1 + if a:newclass[1] <= a:classlist[i][1] + call remove(a:classlist, i) + endif + let i = i - 1 + endwhile + if a:classordef == "class" + call add(a:classlist, a:newclass) + endif +endfunction + +" we found a class or function, determine its parent class based on +" indentation and what's contained in classlist +function! FindParentClass(classlist, indentcol) + let i = 0 + let parentclass = "" + while i < len(a:classlist) + if a:indentcol <= a:classlist[i][1] + break + else + if len(parentclass) == 0 + let parentclass = a:classlist[i][0] + else + let parentclass = parentclass.'\.'.a:classlist[i][0] + endif + endif + let i = i + 1 + endwhile + return parentclass +endfunction + +" add a class to the menu +function! AddClass(classname, lineno, parentclass) + if len(a:parentclass) > 0 + let classstring = a:parentclass.'\.'.a:classname + else + let classstring = a:classname + endif + exe 'menu IM-Python.classes.'.classstring.' :call JumpToAndUnfold('.a:lineno.')' +endfunction + +" add a function to the menu, grouped by member class +function! AddFunction(functionname, lineno, parentclass) + if len(a:parentclass) > 0 + let funcstring = a:parentclass.'.'.a:functionname + else + let funcstring = a:functionname + endif + exe 'menu IM-Python.functions.'.funcstring.' :call JumpToAndUnfold('.a:lineno.')' +endfunction + + +function! s:JumpToAndUnfold(line) + " Go to the right line + execute 'normal '.a:line.'gg' + " Check to see if we are in a fold + let lvl = foldlevel(a:line) + if lvl != 0 + " and if so, then expand the fold out, other wise, ignore this part. + execute 'normal 15zo' + endif +endfunction + +"" This one will work only on vim 6.2 because of the try/catch expressions. +" function! s:JumpToAndUnfoldWithExceptions(line) +" try +" execute 'normal '.a:line.'gg15zo' +" catch /^Vim\((\a\+)\)\=:E490:/ +" " Do nothing, just consume the error +" endtry +"endfunction + + +" vim:set et sts=2 sw=2: + diff --git a/vim/ftplugin/python_fold.vim b/vim/ftplugin/python_fold.vim new file mode 100644 index 0000000..8964790 --- /dev/null +++ b/vim/ftplugin/python_fold.vim @@ -0,0 +1,122 @@ +" Vim folding file +" Language: Python +" Author: Jorrit Wiersma (foldexpr), Max Ischenko (foldtext), Robert +" Ames (line counts) +" Last Change: 2005 Jul 14 +" Version: 2.3 +" Bug fix: Drexler Christopher, Tom Schumm, Geoff Gerrietts + + +setlocal foldmethod=expr +setlocal foldexpr=GetPythonFold(v:lnum) +setlocal foldtext=PythonFoldText() + + +function! PythonFoldText() + let line = getline(v:foldstart) + let nnum = nextnonblank(v:foldstart + 1) + let nextline = getline(nnum) + if nextline =~ '^\s\+"""$' + let line = line . getline(nnum + 1) + elseif nextline =~ '^\s\+"""' + let line = line . ' ' . matchstr(nextline, '"""\zs.\{-}\ze\("""\)\?$') + elseif nextline =~ '^\s\+"[^"]\+"$' + let line = line . ' ' . matchstr(nextline, '"\zs.*\ze"') + elseif nextline =~ '^\s\+pass\s*$' + let line = line . ' pass' + endif + let size = 1 + v:foldend - v:foldstart + if size < 10 + let size = " " . size + endif + if size < 100 + let size = " " . size + endif + if size < 1000 + let size = " " . size + endif + return size . " lines: " . line +endfunction + + +function! GetPythonFold(lnum) + " Determine folding level in Python source + " + let line = getline(a:lnum) + let ind = indent(a:lnum) + + " Ignore blank lines + if line =~ '^\s*$' + return "=" + endif + + " Ignore triple quoted strings + if line =~ "(\"\"\"|''')" + return "=" + endif + + " Ignore continuation lines + if line =~ '\\$' + return '=' + endif + + " Support markers + if line =~ '{{{' + return "a1" + elseif line =~ '}}}' + return "s1" + endif + + " Classes and functions get their own folds + if line =~ '^\s*\(class\|def\)\s' + return ">" . (ind / &sw + 1) + endif + + let pnum = prevnonblank(a:lnum - 1) + + if pnum == 0 + " Hit start of file + return 0 + endif + + " If the previous line has foldlevel zero, and we haven't increased + " it, we should have foldlevel zero also + if foldlevel(pnum) == 0 + return 0 + endif + + " The end of a fold is determined through a difference in indentation + " between this line and the next. + " So first look for next line + let nnum = nextnonblank(a:lnum + 1) + if nnum == 0 + return "=" + endif + + " First I check for some common cases where this algorithm would + " otherwise fail. (This is all a hack) + let nline = getline(nnum) + if nline =~ '^\s*\(except\|else\|elif\)' + return "=" + endif + + " Python programmers love their readable code, so they're usually + " going to have blank lines at the ends of functions or classes + " If the next line isn't blank, we probably don't need to end a fold + if nnum == a:lnum + 1 + return "=" + endif + + " If next line has less indentation we end a fold. + " This ends folds that aren't there a lot of the time, and this sometimes + " confuses vim. Luckily only rarely. + let nind = indent(nnum) + if nind < ind + return "<" . (nind / &sw + 1) + endif + + " If none of the above apply, keep the indentation + return "=" + +endfunction + diff --git a/vim/indent/python.vim b/vim/indent/python.vim new file mode 100644 index 0000000..32c773c --- /dev/null +++ b/vim/indent/python.vim @@ -0,0 +1,196 @@ +" Python indent file +" Language: Python +" Maintainer: Eric Mc Sween +" Original Author: David Bustos +" Last Change: 2004 Jun 07 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal expandtab +setlocal nolisp +setlocal autoindent +setlocal indentexpr=GetPythonIndent(v:lnum) +setlocal indentkeys=!^F,o,O,<:>,0),0],0},=elif,=except + +let s:maxoff = 50 + +" Find backwards the closest open parenthesis/bracket/brace. +function! s:SearchParensPair() + let line = line('.') + let col = col('.') + + " Skip strings and comments and don't look too far + let skip = "line('.') < " . (line - s:maxoff) . " ? dummy :" . + \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? ' . + \ '"string\\|comment"' + + " Search for parentheses + call cursor(line, col) + let parlnum = searchpair('(', '', ')', 'bW', skip) + let parcol = col('.') + + " Search for brackets + call cursor(line, col) + let par2lnum = searchpair('\[', '', '\]', 'bW', skip) + let par2col = col('.') + + " Search for braces + call cursor(line, col) + let par3lnum = searchpair('{', '', '}', 'bW', skip) + let par3col = col('.') + + " Get the closest match + if par2lnum > parlnum || (par2lnum == parlnum && par2col > parcol) + let parlnum = par2lnum + let parcol = par2col + endif + if par3lnum > parlnum || (par3lnum == parlnum && par3col > parcol) + let parlnum = par3lnum + let parcol = par3col + endif + + " Put the cursor on the match + if parlnum > 0 + call cursor(parlnum, parcol) + endif + return parlnum +endfunction + +" Find the start of a multi-line statement +function! s:StatementStart(lnum) + let lnum = a:lnum + while 1 + if getline(lnum - 1) =~ '\\$' + let lnum = lnum - 1 + else + call cursor(lnum, 1) + let maybe_lnum = s:SearchParensPair() + if maybe_lnum < 1 + return lnum + else + let lnum = maybe_lnum + endif + endif + endwhile +endfunction + +" Find the block starter that matches the current line +function! s:BlockStarter(lnum, block_start_re) + let lnum = a:lnum + let maxindent = 10000 " whatever + while lnum > 1 + let lnum = prevnonblank(lnum - 1) + if indent(lnum) < maxindent + if getline(lnum) =~ a:block_start_re + return lnum + else + let maxindent = indent(lnum) + " It's not worth going further if we reached the top level + if maxindent == 0 + return -1 + endif + endif + endif + endwhile + return -1 +endfunction + +function! GetPythonIndent(lnum) + + " First line has indent 0 + if a:lnum == 1 + return 0 + endif + + " If we can find an open parenthesis/bracket/brace, line up with it. + call cursor(a:lnum, 1) + let parlnum = s:SearchParensPair() + if parlnum > 0 + let parcol = col('.') + let closing_paren = match(getline(a:lnum), '^\s*[])}]') != -1 + if match(getline(parlnum), '[([{]\s*$', parcol - 1) != -1 + if closing_paren + return indent(parlnum) + else + return indent(parlnum) + &shiftwidth + endif + else + if closing_paren + return parcol - 1 + else + return parcol + endif + endif + endif + + " Examine this line + let thisline = getline(a:lnum) + let thisindent = indent(a:lnum) + + " If the line starts with 'elif' or 'else', line up with 'if' or 'elif' + if thisline =~ '^\s*\(elif\|else\)\>' + let bslnum = s:BlockStarter(a:lnum, '^\s*\(if\|elif\)\>') + if bslnum > 0 + return indent(bslnum) + else + return -1 + endif + endif + + " If the line starts with 'except' or 'finally', line up with 'try' + " or 'except' + if thisline =~ '^\s*\(except\|finally\)\>' + let bslnum = s:BlockStarter(a:lnum, '^\s*\(try\|except\)\>') + if bslnum > 0 + return indent(bslnum) + else + return -1 + endif + endif + + " Examine previous line + let plnum = a:lnum - 1 + let pline = getline(plnum) + let sslnum = s:StatementStart(plnum) + + " If the previous line is blank, keep the same indentation + if pline =~ '^\s*$' + return -1 + endif + + " If this line is explicitly joined, try to find an indentation that looks + " good. + if pline =~ '\\$' + let compound_statement = '^\s*\(if\|while\|for\s.*\sin\|except\)\s*' + let maybe_indent = matchend(getline(sslnum), compound_statement) + if maybe_indent != -1 + return maybe_indent + else + return indent(sslnum) + &sw * 2 + endif + endif + + " If the previous line ended with a colon, indent relative to + " statement start. + if pline =~ ':\s*$' + return indent(sslnum) + &sw + endif + + " If the previous line was a stop-execution statement or a pass + if getline(sslnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\)\>' + " See if the user has already dedented + if indent(a:lnum) > indent(sslnum) - &sw + " If not, recommend one dedent + return indent(sslnum) - &sw + endif + " Otherwise, trust the user + return -1 + endif + + " In all other cases, line up with the start of the previous statement. + return indent(sslnum) +endfunction diff --git a/vim/myfunx.vim b/vim/myfunx.vim deleted file mode 100644 index 514a807..0000000 --- a/vim/myfunx.vim +++ /dev/null @@ -1,33 +0,0 @@ -" Converts a file to PDF and display it (only on OS X) -function! ToPDF() - "define PS file name - let psname= "/tmp/" . expand("%:t:r") . ".ps" - "save colorscheme name - let g:colorname=g:colors_name - execute "write" - execute "colorscheme default" - execute "hardcopy > " . l:psname - execute "silent !launch -w " . l:psname - execute "silent !rm " . l:psname - execute "colorscheme" g:colorname - redraw! -endfunction - -" Set up menu for the function -an 10.520 &File.-SEP3- -an 10.530 &File.&ToPDF :call ToPDF() -vunmenu &File.&ToPDF -vnoremenu &File.&ToPDF :call ToPDF() - -" Zoom in/out of gvim -function! Zoom() - if has("gui_running") - if &guifont =~ 'Monaco:h12' - set guifont=Monaco:h9 - set lines=70 - else - set guifont=Monaco:h12 - set lines=50 - endif - endif -endfunction diff --git a/vim/plugin/NERD_commenter.vim b/vim/plugin/NERD_commenter.vim new file mode 100644 index 0000000..18a348f --- /dev/null +++ b/vim/plugin/NERD_commenter.vim @@ -0,0 +1,3132 @@ +" ============================================================================ +" File: NERD_commenter.vim +" Description: vim global plugin that provides easy code commenting +" Maintainer: Martin Grenfell +" Version: 2.2.2 +" Last Change: 30th March, 2008 +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ + +" Section: script init stuff {{{1 +if exists("loaded_nerd_comments") + finish +endif +if v:version < 700 + echoerr "NERDCommenter: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!" + finish +endif +let loaded_nerd_comments = 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: space string init{{{2 +" When putting spaces after the left delim and before the right we use +" s:spaceStr for the space char. This way we can make it add anything after +" the left and before the right by modifying this variable +let s:spaceStr = ' ' +let s:lenSpaceStr = strlen(s:spaceStr) + +" Section: variable init calls {{{2 +call s:InitVariable("g:NERDAllowAnyVisualDelims", 1) +call s:InitVariable("g:NERDBlockComIgnoreEmpty", 0) +call s:InitVariable("g:NERDCommentWholeLinesInVMode", 0) +call s:InitVariable("g:NERDCompactSexyComs", 0) +call s:InitVariable("g:NERDCreateDefaultMappings", 1) +call s:InitVariable("g:NERDDefaultNesting", 1) +call s:InitVariable("g:NERDMenuMode", 3) +call s:InitVariable("g:NERDLPlace", "[>") +call s:InitVariable("g:NERDUsePlaceHolders", 1) +call s:InitVariable("g:NERDRemoveAltComs", 1) +call s:InitVariable("g:NERDRemoveExtraSpaces", 1) +call s:InitVariable("g:NERDRPlace", "<]") +call s:InitVariable("g:NERDSpaceDelims", 0) +call s:InitVariable("g:NERDDelimiterRequests", 1) + + + +let s:NERDFileNameEscape="[]#*$%'\" ?`!&();<>\\" + +" Section: Comment mapping functions, autocommands and commands {{{1 +" ============================================================================ +" Section: Comment enabler autocommands {{{2 +" ============================================================================ + +augroup commentEnablers + + "if the user enters a buffer or reads a buffer then we gotta set up + "the comment delimiters for that new filetype + autocmd BufEnter,BufRead * :call s:SetUpForNewFiletype(&filetype, 0) + + "if the filetype of a buffer changes, force the script to reset the + "delims for the buffer + autocmd Filetype * :call s:SetUpForNewFiletype(&filetype, 1) +augroup END + + +" Function: s:SetUpForNewFiletype(filetype) function {{{2 +" This function is responsible for setting up buffer scoped variables for the +" given filetype. +" +" These variables include the comment delimiters for the given filetype and calls +" MapDelimiters or MapDelimitersWithAlternative passing in these delimiters. +" +" Args: +" -filetype: the filetype to set delimiters for +" -forceReset: 1 if the delimiters should be reset if they have already be +" set for this buffer. +" +function s:SetUpForNewFiletype(filetype, forceReset) + "if we have already set the delimiters for this buffer then dont go thru + "it again + if !a:forceReset && exists("b:NERDLeft") && b:NERDLeft != '' + return + endif + + let b:NERDSexyComMarker = '' + + "check the filetype against all known filetypes to see if we have + "hardcoded the comment delimiters to use + if a:filetype ==? "" + call s:MapDelimiters('', '') + elseif a:filetype ==? "aap" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "abc" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "acedb" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "actionscript" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "ada" + call s:MapDelimitersWithAlternative('--','', '-- ', '') + elseif a:filetype ==? "ahdl" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "ahk" + call s:MapDelimitersWithAlternative(';', '', '/*', '*/') + elseif a:filetype ==? "amiga" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "aml" + call s:MapDelimiters('/*', '') + elseif a:filetype ==? "ampl" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "apache" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "apachestyle" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "asciidoc" + call s:MapDelimiters('//', '') + elseif a:filetype ==? "applescript" + call s:MapDelimitersWithAlternative('--', '', '(*', '*)') + elseif a:filetype ==? "asm68k" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "asm" + call s:MapDelimitersWithAlternative(';', '', '#', '') + elseif a:filetype ==? "asn" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "aspvbs" + call s:MapDelimiters('''', '') + elseif a:filetype ==? "asterisk" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "asy" + call s:MapDelimiters('//', '') + elseif a:filetype ==? "atlas" + call s:MapDelimiters('C','$') + elseif a:filetype ==? "autohotkey" + call s:MapDelimiters(';','') + elseif a:filetype ==? "autoit" + call s:MapDelimiters(';','') + elseif a:filetype ==? "ave" + call s:MapDelimiters("'",'') + elseif a:filetype ==? "awk" + call s:MapDelimiters('#','') + elseif a:filetype ==? "basic" + call s:MapDelimitersWithAlternative("'",'', 'REM ', '') + elseif a:filetype ==? "bbx" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "bc" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "bib" + call s:MapDelimiters('%','') + elseif a:filetype ==? "bindzone" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "bst" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "btm" + call s:MapDelimiters('::', '') + elseif a:filetype ==? "caos" + call s:MapDelimiters('*', '') + elseif a:filetype ==? "calibre" + call s:MapDelimiters('//','') + elseif a:filetype ==? "catalog" + call s:MapDelimiters('--','--') + elseif a:filetype ==? "c" + call s:MapDelimitersWithAlternative('/*','*/', '//', '') + elseif a:filetype ==? "cfg" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "cg" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "ch" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "cl" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "clean" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "clipper" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "clojure" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "cmake" + call s:MapDelimiters('#','') + elseif a:filetype ==? "conkyrc" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "cpp" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "crontab" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "cs" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "csp" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "cterm" + call s:MapDelimiters('*', '') + elseif a:filetype ==? "cucumber" + call s:MapDelimiters('#','') + elseif a:filetype ==? "cvs" + call s:MapDelimiters('CVS:','') + elseif a:filetype ==? "d" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "dcl" + call s:MapDelimiters('$!', '') + elseif a:filetype ==? "dakota" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "debcontrol" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "debsources" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "def" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "desktop" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "dhcpd" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "diff" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "django" + call s:MapDelimitersWithAlternative('', '{#', '#}') + elseif a:filetype ==? "docbk" + call s:MapDelimiters('') + elseif a:filetype ==? "dns" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "dosbatch" + call s:MapDelimitersWithAlternative('REM ','', '::', '') + elseif a:filetype ==? "dosini" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "dot" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "dracula" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "dsl" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "dtml" + call s:MapDelimiters('','') + elseif a:filetype ==? "dylan" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? 'ebuild' + call s:MapDelimiters('#', '') + elseif a:filetype ==? "ecd" + call s:MapDelimiters('#', '') + elseif a:filetype ==? 'eclass' + call s:MapDelimiters('#', '') + elseif a:filetype ==? "eiffel" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "elf" + call s:MapDelimiters("'", '') + elseif a:filetype ==? "elmfilt" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "erlang" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "eruby" + call s:MapDelimitersWithAlternative('<%#', '%>', '') + elseif a:filetype ==? "expect" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "exports" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "factor" + call s:MapDelimitersWithAlternative('! ', '', '!# ', '') + elseif a:filetype ==? "fgl" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "focexec" + call s:MapDelimiters('-*', '') + elseif a:filetype ==? "form" + call s:MapDelimiters('*', '') + elseif a:filetype ==? "foxpro" + call s:MapDelimiters('*', '') + elseif a:filetype ==? "fstab" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "fvwm" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "fx" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "gams" + call s:MapDelimiters('*', '') + elseif a:filetype ==? "gdb" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "gdmo" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "geek" + call s:MapDelimiters('GEEK_COMMENT:', '') + elseif a:filetype ==? "genshi" + call s:MapDelimitersWithAlternative('', '{#', '#}') + elseif a:filetype ==? "gentoo-conf-d" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "gentoo-env-d" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "gentoo-init-d" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "gentoo-make-conf" + call s:MapDelimiters('#', '') + elseif a:filetype ==? 'gentoo-package-keywords' + call s:MapDelimiters('#', '') + elseif a:filetype ==? 'gentoo-package-mask' + call s:MapDelimiters('#', '') + elseif a:filetype ==? 'gentoo-package-use' + call s:MapDelimiters('#', '') + elseif a:filetype ==? 'gitcommit' + call s:MapDelimiters('#', '') + elseif a:filetype ==? 'gitconfig' + call s:MapDelimiters(';', '') + elseif a:filetype ==? 'gitrebase' + call s:MapDelimiters('#', '') + elseif a:filetype ==? "gnuplot" + call s:MapDelimiters('#','') + elseif a:filetype ==? "groovy" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "gtkrc" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "haskell" + call s:MapDelimitersWithAlternative('{-','-}', '--', '') + elseif a:filetype ==? "hb" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "h" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "haml" + call s:MapDelimitersWithAlternative('-#', '', '/', '') + elseif a:filetype ==? "hercules" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "hog" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "hostsaccess" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "htmlcheetah" + call s:MapDelimiters('##','') + elseif a:filetype ==? "htmldjango" + call s:MapDelimitersWithAlternative('', '{#', '#}') + elseif a:filetype ==? "htmlos" + call s:MapDelimiters('#','/#') + elseif a:filetype ==? "ia64" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "icon" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "idlang" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "idl" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "inform" + call s:MapDelimiters('!', '') + elseif a:filetype ==? "inittab" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "ishd" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "iss" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "ist" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "java" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "javacc" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "javascript" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype == "javascript.jquery" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "jess" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "jgraph" + call s:MapDelimiters('(*','*)') + elseif a:filetype ==? "jproperties" + call s:MapDelimiters('#','') + elseif a:filetype ==? "jsp" + call s:MapDelimiters('<%--', '--%>') + elseif a:filetype ==? "kix" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "kscript" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "lace" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "ldif" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "lilo" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "lilypond" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "liquid" + call s:MapDelimiters('{%', '%}') + elseif a:filetype ==? "lisp" + call s:MapDelimitersWithAlternative(';','', '#|', '|#') + elseif a:filetype ==? "llvm" + call s:MapDelimiters(';','') + elseif a:filetype ==? "lotos" + call s:MapDelimiters('(*','*)') + elseif a:filetype ==? "lout" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "lprolog" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "lscript" + call s:MapDelimiters("'", '') + elseif a:filetype ==? "lss" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "lua" + call s:MapDelimitersWithAlternative('--','', '--[[', ']]') + elseif a:filetype ==? "lynx" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "lytex" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "mail" + call s:MapDelimiters('> ','') + elseif a:filetype ==? "mako" + call s:MapDelimiters('##', '') + elseif a:filetype ==? "man" + call s:MapDelimiters('."', '') + elseif a:filetype ==? "map" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "maple" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "markdown" + call s:MapDelimiters('') + elseif a:filetype ==? "masm" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "mason" + call s:MapDelimiters('<% #', '%>') + elseif a:filetype ==? "master" + call s:MapDelimiters('$', '') + elseif a:filetype ==? "matlab" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "mel" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "mib" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "mkd" + call s:MapDelimiters('>', '') + elseif a:filetype ==? "mma" + call s:MapDelimiters('(*','*)') + elseif a:filetype ==? "model" + call s:MapDelimiters('$','$') + elseif a:filetype =~ "moduala." + call s:MapDelimiters('(*','*)') + elseif a:filetype ==? "modula2" + call s:MapDelimiters('(*','*)') + elseif a:filetype ==? "modula3" + call s:MapDelimiters('(*','*)') + elseif a:filetype ==? "monk" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "mush" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "named" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "nasm" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "nastran" + call s:MapDelimiters('$', '') + elseif a:filetype ==? "natural" + call s:MapDelimiters('/*', '') + elseif a:filetype ==? "ncf" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "newlisp" + call s:MapDelimiters(';','') + elseif a:filetype ==? "nroff" + call s:MapDelimiters('\"', '') + elseif a:filetype ==? "nsis" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "ntp" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "objc" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "objcpp" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "objj" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "ocaml" + call s:MapDelimiters('(*','*)') + elseif a:filetype ==? "occam" + call s:MapDelimiters('--','') + elseif a:filetype ==? "omlet" + call s:MapDelimiters('(*','*)') + elseif a:filetype ==? "omnimark" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "openroad" + call s:MapDelimiters('//', '') + elseif a:filetype ==? "opl" + call s:MapDelimiters("REM", "") + elseif a:filetype ==? "ora" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "ox" + call s:MapDelimiters('//', '') + elseif a:filetype ==? "pascal" + call s:MapDelimitersWithAlternative('{','}', '(*', '*)') + elseif a:filetype ==? "patran" + call s:MapDelimitersWithAlternative('$','','/*', '*/') + elseif a:filetype ==? "pcap" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "pccts" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "pdf" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "pfmain" + call s:MapDelimiters('//', '') + elseif a:filetype ==? "php" + call s:MapDelimitersWithAlternative('//','','/*', '*/') + elseif a:filetype ==? "pic" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "pike" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "pilrc" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "pine" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "plm" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "plsql" + call s:MapDelimitersWithAlternative('--', '', '/*', '*/') + elseif a:filetype ==? "po" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "postscr" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "pov" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "povini" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "ppd" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "ppwiz" + call s:MapDelimiters(';;', '') + elseif a:filetype ==? "processing" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "prolog" + call s:MapDelimitersWithAlternative('%','','/*','*/') + elseif a:filetype ==? "ps1" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "psf" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "ptcap" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "radiance" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "ratpoison" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "r" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "rc" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "rebol" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "registry" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "remind" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "resolv" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "rgb" + call s:MapDelimiters('!', '') + elseif a:filetype ==? "rib" + call s:MapDelimiters('#','') + elseif a:filetype ==? "robots" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "sa" + call s:MapDelimiters('--','') + elseif a:filetype ==? "samba" + call s:MapDelimitersWithAlternative(';','', '#', '') + elseif a:filetype ==? "sass" + call s:MapDelimitersWithAlternative('//','', '/*', '') + elseif a:filetype ==? "sather" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "scala" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "scilab" + call s:MapDelimiters('//', '') + elseif a:filetype ==? "scsh" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "sed" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "sgmldecl" + call s:MapDelimiters('--','--') + elseif a:filetype ==? "sgmllnx" + call s:MapDelimiters('') + elseif a:filetype ==? "sicad" + call s:MapDelimiters('*', '') + elseif a:filetype ==? "simula" + call s:MapDelimitersWithAlternative('%', '', '--', '') + elseif a:filetype ==? "sinda" + call s:MapDelimiters('$', '') + elseif a:filetype ==? "skill" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "slang" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "slice" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "slrnrc" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "sm" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "smarty" + call s:MapDelimiters('{*', '*}') + elseif a:filetype ==? "smil" + call s:MapDelimiters('') + elseif a:filetype ==? "smith" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "sml" + call s:MapDelimiters('(*','*)') + elseif a:filetype ==? "snnsnet" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "snnspat" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "snnsres" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "snobol4" + call s:MapDelimiters('*', '') + elseif a:filetype ==? "spec" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "specman" + call s:MapDelimiters('//', '') + elseif a:filetype ==? "spectre" + call s:MapDelimitersWithAlternative('//', '', '*', '') + elseif a:filetype ==? "spice" + call s:MapDelimiters('$', '') + elseif a:filetype ==? "sql" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "sqlforms" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "sqlj" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "sqr" + call s:MapDelimiters('!', '') + elseif a:filetype ==? "squid" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "st" + call s:MapDelimiters('"','') + elseif a:filetype ==? "stp" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "systemverilog" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "tads" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "tags" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "tak" + call s:MapDelimiters('$', '') + elseif a:filetype ==? "tasm" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "tcl" + call s:MapDelimiters('#','') + elseif a:filetype ==? "texinfo" + call s:MapDelimiters("@c ", "") + elseif a:filetype ==? "texmf" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "tf" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "tidy" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "tli" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "trasys" + call s:MapDelimiters("$", "") + elseif a:filetype ==? "tsalt" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "tsscl" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "tssgm" + call s:MapDelimiters("comment = '","'") + elseif a:filetype ==? "txt2tags" + call s:MapDelimiters('%','') + elseif a:filetype ==? "uc" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "uil" + call s:MapDelimiters('!', '') + elseif a:filetype ==? "vb" + call s:MapDelimiters("'","") + elseif a:filetype ==? "velocity" + call s:MapDelimitersWithAlternative("##","", '#*', '*#') + elseif a:filetype ==? "vera" + call s:MapDelimitersWithAlternative('/*','*/','//','') + elseif a:filetype ==? "verilog" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "verilog_systemverilog" + call s:MapDelimitersWithAlternative('//','', '/*','*/') + elseif a:filetype ==? "vgrindefs" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "vhdl" + call s:MapDelimiters('--', '') + elseif a:filetype ==? "vimperator" + call s:MapDelimiters('"','') + elseif a:filetype ==? "virata" + call s:MapDelimiters('%', '') + elseif a:filetype ==? "vrml" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "vsejcl" + call s:MapDelimiters('/*', '') + elseif a:filetype ==? "webmacro" + call s:MapDelimiters('##', '') + elseif a:filetype ==? "wget" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "Wikipedia" + call s:MapDelimiters('') + elseif a:filetype ==? "winbatch" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "wml" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "wvdial" + call s:MapDelimiters(';', '') + elseif a:filetype ==? "xdefaults" + call s:MapDelimiters('!', '') + elseif a:filetype ==? "xkb" + call s:MapDelimiters('//', '') + elseif a:filetype ==? "xmath" + call s:MapDelimiters('#', '') + elseif a:filetype ==? "xpm2" + call s:MapDelimiters('!', '') + elseif a:filetype ==? "xquery" + call s:MapDelimiters('(:',':)') + elseif a:filetype ==? "z8a" + call s:MapDelimiters(';', '') + + else + + "extract the delims from &commentstring + let left= substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', '') + let right= substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g') + call s:MapDelimiters(left,right) + + endif +endfunction + +" Function: s:MapDelimiters(left, right) function {{{2 +" This function is a wrapper for s:MapDelimiters(left, right, leftAlt, rightAlt, useAlt) and is called when there +" is no alternative comment delimiters for the current filetype +" +" Args: +" -left: the left comment delimiter +" -right: the right comment delimiter +function s:MapDelimiters(left, right) + call s:MapDelimitersWithAlternative(a:left, a:right, "", "") +endfunction + +" Function: s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt) function {{{2 +" this function sets up the comment delimiter buffer variables +" +" Args: +" -left: the string defining the comment start delimiter +" -right: the string defining the comment end delimiter +" -leftAlt: the string for the alternative comment style defining the comment start delimiter +" -rightAlt: the string for the alternative comment style defining the comment end delimiter +function s:MapDelimitersWithAlternative(left, right, leftAlt, rightAlt) + if !exists('g:NERD_' . &filetype . '_alt_style') + let b:NERDLeft = a:left + let b:NERDRight = a:right + let b:NERDLeftAlt = a:leftAlt + let b:NERDRightAlt = a:rightAlt + else + let b:NERDLeft = a:leftAlt + let b:NERDRight = a:rightAlt + let b:NERDLeftAlt = a:left + let b:NERDRightAlt = a:right + endif +endfunction + +" Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2 +" This function is used to swap the delimiters that are being used to the +" alternative delimiters for that filetype. For example, if a c++ file is +" being edited and // comments are being used, after this function is called +" /**/ comments will be used. +" +" Args: +" -printMsgs: if this is 1 then a message is echoed to the user telling them +" if this function changed the delimiters or not +function s:SwitchToAlternativeDelimiters(printMsgs) + "if both of the alternative delimiters are empty then there is no + "alternative comment style so bail out + if b:NERDLeftAlt == "" && b:NERDRightAlt == "" + if a:printMsgs + call s:NerdEcho("Cannot use alternative delimiters, none are specified", 0) + endif + return 0 + endif + + "save the current delimiters + let tempLeft = b:NERDLeft + let tempRight = b:NERDRight + + "swap current delimiters for alternative + let b:NERDLeft = b:NERDLeftAlt + let b:NERDRight = b:NERDRightAlt + + "set the previously current delimiters to be the new alternative ones + let b:NERDLeftAlt = tempLeft + let b:NERDRightAlt = tempRight + + "tell the user what comment delimiters they are now using + if a:printMsgs + let leftNoEsc = b:NERDLeft + let rightNoEsc = b:NERDRight + call s:NerdEcho("Now using " . leftNoEsc . " " . rightNoEsc . " to delimit comments", 1) + endif + + return 1 +endfunction + +" Section: Comment delimiter add/removal functions {{{1 +" ============================================================================ +" Function: s:AppendCommentToLine(){{{2 +" This function appends comment delimiters at the EOL and places the cursor in +" position to start typing the comment +function s:AppendCommentToLine() + let left = s:GetLeft(0,1,0) + let right = s:GetRight(0,1,0) + + " get the len of the right delim + let lenRight = strlen(right) + + let isLineEmpty = strlen(getline(".")) == 0 + let insOrApp = (isLineEmpty==1 ? 'i' : 'A') + + "stick the delimiters down at the end of the line. We have to format the + "comment with spaces as appropriate + execute ":normal! " . insOrApp . (isLineEmpty ? '' : ' ') . left . right . " " + + " if there is a right delimiter then we gotta move the cursor left + " by the len of the right delimiter so we insert between the delimiters + if lenRight > 0 + let leftMoveAmount = lenRight + execute ":normal! " . leftMoveAmount . "h" + endif + startinsert +endfunction + +" Function: s:CommentBlock(top, bottom, lSide, rSide, forceNested ) {{{2 +" This function is used to comment out a region of code. This region is +" specified as a bounding box by arguments to the function. +" +" Args: +" -top: the line number for the top line of code in the region +" -bottom: the line number for the bottom line of code in the region +" -lSide: the column number for the left most column in the region +" -rSide: the column number for the right most column in the region +" -forceNested: a flag indicating whether comments should be nested +function s:CommentBlock(top, bottom, lSide, rSide, forceNested ) + " we need to create local copies of these arguments so we can modify them + let top = a:top + let bottom = a:bottom + let lSide = a:lSide + let rSide = a:rSide + + "if the top or bottom line starts with tabs we have to adjust the left and + "right boundaries so that they are set as though the tabs were spaces + let topline = getline(top) + let bottomline = getline(bottom) + if s:HasLeadingTabs(topline, bottomline) + + "find out how many tabs are in the top line and adjust the left + "boundary accordingly + let numTabs = s:NumberOfLeadingTabs(topline) + if lSide < numTabs + let lSide = &ts * lSide + else + let lSide = (lSide - numTabs) + (&ts * numTabs) + endif + + "find out how many tabs are in the bottom line and adjust the right + "boundary accordingly + let numTabs = s:NumberOfLeadingTabs(bottomline) + let rSide = (rSide - numTabs) + (&ts * numTabs) + endif + + "we must check that bottom IS actually below top, if it is not then we + "swap top and bottom. Similarly for left and right. + if bottom < top + let temp = top + let top = bottom + let bottom = top + endif + if rSide < lSide + let temp = lSide + let lSide = rSide + let rSide = temp + endif + + "if the current delimiters arent multipart then we will switch to the + "alternative delims (if THEY are) as the comment will be better and more + "accurate with multipart delims + let switchedDelims = 0 + if !s:Multipart() && g:NERDAllowAnyVisualDelims && s:AltMultipart() + let switchedDelims = 1 + call s:SwitchToAlternativeDelimiters(0) + endif + + "start the commenting from the top and keep commenting till we reach the + "bottom + let currentLine=top + while currentLine <= bottom + + "check if we are allowed to comment this line + if s:CanCommentLine(a:forceNested, currentLine) + + "convert the leading tabs into spaces + let theLine = getline(currentLine) + let lineHasLeadTabs = s:HasLeadingTabs(theLine) + if lineHasLeadTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + + "dont comment lines that begin after the right boundary of the + "block unless the user has specified to do so + if theLine !~ '^ \{' . rSide . '\}' || !g:NERDBlockComIgnoreEmpty + + "attempt to place the cursor in on the left of the boundary box, + "then check if we were successful, if not then we cant comment this + "line + call setline(currentLine, theLine) + if s:CanPlaceCursor(currentLine, lSide) + + let leftSpaced = s:GetLeft(0,1,0) + let rightSpaced = s:GetRight(0,1,0) + + "stick the left delimiter down + let theLine = strpart(theLine, 0, lSide-1) . leftSpaced . strpart(theLine, lSide-1) + + if s:Multipart() + "stick the right delimiter down + let theLine = strpart(theLine, 0, rSide+strlen(leftSpaced)) . rightSpaced . strpart(theLine, rSide+strlen(leftSpaced)) + + let firstLeftDelim = s:FindDelimiterIndex(b:NERDLeft, theLine) + let lastRightDelim = s:LastIndexOfDelim(b:NERDRight, theLine) + + if firstLeftDelim != -1 && lastRightDelim != -1 + let searchStr = strpart(theLine, 0, lastRightDelim) + let searchStr = strpart(searchStr, firstLeftDelim+strlen(b:NERDLeft)) + + "replace the outter most delims in searchStr with + "place-holders + let theLineWithPlaceHolders = s:ReplaceDelims(b:NERDLeft, b:NERDRight, g:NERDLPlace, g:NERDRPlace, searchStr) + + "add the right delimiter onto the line + let theLine = strpart(theLine, 0, firstLeftDelim+strlen(b:NERDLeft)) . theLineWithPlaceHolders . strpart(theLine, lastRightDelim) + endif + endif + endif + endif + + "restore tabs if needed + if lineHasLeadTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + call setline(currentLine, theLine) + endif + + let currentLine = currentLine + 1 + endwhile + + "if we switched delims then we gotta go back to what they were before + if switchedDelims == 1 + call s:SwitchToAlternativeDelimiters(0) + endif +endfunction + +" Function: s:CommentLines(forceNested, alignLeft, alignRight, firstLine, lastLine) {{{2 +" This function comments a range of lines. +" +" Args: +" -forceNested: a flag indicating whether the called is requesting the comment +" to be nested if need be +" -align: should be "left" or "both" or "none" +" -firstLine/lastLine: the top and bottom lines to comment +function s:CommentLines(forceNested, align, firstLine, lastLine) + " we need to get the left and right indexes of the leftmost char in the + " block of of lines and the right most char so that we can do alignment of + " the delimiters if the user has specified + let leftAlignIndx = s:LeftMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) + let rightAlignIndx = s:RightMostIndx(a:forceNested, 0, a:firstLine, a:lastLine) + + " gotta add the length of the left delimiter onto the rightAlignIndx cos + " we'll be adding a left delim to the line + let rightAlignIndx = rightAlignIndx + strlen(s:GetLeft(0,1,0)) + + " now we actually comment the lines. Do it line by line + let currentLine = a:firstLine + while currentLine <= a:lastLine + + " get the next line, check commentability and convert spaces to tabs + let theLine = getline(currentLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + if s:CanCommentLine(a:forceNested, currentLine) + "if the user has specified forceNesting then we check to see if we + "need to switch delimiters for place-holders + if a:forceNested && g:NERDUsePlaceHolders + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + endif + + " find out if the line is commented using normal delims and/or + " alternate ones + let isCommented = s:IsCommented(b:NERDLeft, b:NERDRight, theLine) || s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine) + + " check if we can comment this line + if !isCommented || g:NERDUsePlaceHolders || s:Multipart() + if a:align == "left" || a:align == "both" + let theLine = s:AddLeftDelimAligned(s:GetLeft(0,1,0), theLine, leftAlignIndx) + else + let theLine = s:AddLeftDelim(s:GetLeft(0,1,0), theLine) + endif + if a:align == "both" + let theLine = s:AddRightDelimAligned(s:GetRight(0,1,0), theLine, rightAlignIndx) + else + let theLine = s:AddRightDelim(s:GetRight(0,1,0), theLine) + endif + endif + endif + + " restore leading tabs if appropriate + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + " we are done with this line + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + +endfunction + +" Function: s:CommentLinesMinimal(firstLine, lastLine) {{{2 +" This function comments a range of lines in a minimal style. I +" +" Args: +" -firstLine/lastLine: the top and bottom lines to comment +function s:CommentLinesMinimal(firstLine, lastLine) + "check that minimal comments can be done on this filetype + if !s:HasMultipartDelims() + throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters' + endif + + "if we need to use place holders for the comment, make sure they are + "enabled for this filetype + if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine) + throw 'NERDCommenter.Settings exception: Placeoholders are required but disabled.' + endif + + "get the left and right delims to smack on + let left = s:GetSexyComLeft(g:NERDSpaceDelims,0) + let right = s:GetSexyComRight(g:NERDSpaceDelims,0) + + "make sure all multipart delims on the lines are replaced with + "placeholders to prevent illegal syntax + let currentLine = a:firstLine + while(currentLine <= a:lastLine) + let theLine = getline(currentLine) + let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine) + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + + "add the delim to the top line + let theLine = getline(a:firstLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let theLine = s:AddLeftDelim(left, theLine) + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:firstLine, theLine) + + "add the delim to the bottom line + let theLine = getline(a:lastLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let theLine = s:AddRightDelim(right, theLine) + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:lastLine, theLine) +endfunction + +" Function: s:CommentLinesSexy(topline, bottomline) function {{{2 +" This function is used to comment lines in the 'Sexy' style. eg in c: +" /* +" * This is a sexy comment +" */ +" Args: +" -topline: the line num of the top line in the sexy comment +" -bottomline: the line num of the bottom line in the sexy comment +function s:CommentLinesSexy(topline, bottomline) + let left = s:GetSexyComLeft(0, 0) + let right = s:GetSexyComRight(0, 0) + + "check if we can do a sexy comment with the available delimiters + if left == -1 || right == -1 + throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.' + endif + + "make sure the lines arent already commented sexually + if !s:CanSexyCommentLines(a:topline, a:bottomline) + throw 'NERDCommenter.Nesting exception: cannot nest sexy comments' + endif + + + let sexyComMarker = s:GetSexyComMarker(0,0) + let sexyComMarkerSpaced = s:GetSexyComMarker(1,0) + + + " we jam the comment as far to the right as possible + let leftAlignIndx = s:LeftMostIndx(1, 1, a:topline, a:bottomline) + + "check if we should use the compact style i.e that the left/right + "delimiters should appear on the first and last lines of the code and not + "on separate lines above/below the first/last lines of code + if g:NERDCompactSexyComs + let spaceString = (g:NERDSpaceDelims ? s:spaceStr : '') + + "comment the top line + let theLine = getline(a:topline) + let lineHasTabs = s:HasLeadingTabs(theLine) + if lineHasTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx) + if lineHasTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:topline, theLine) + + "comment the bottom line + if a:bottomline != a:topline + let theLine = getline(a:bottomline) + let lineHasTabs = s:HasLeadingTabs(theLine) + if lineHasTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + endif + let theLine = s:AddRightDelim(spaceString . right, theLine) + if lineHasTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + call setline(a:bottomline, theLine) + else + + " add the left delimiter one line above the lines that are to be commented + call cursor(a:topline, 1) + execute 'normal! O' + call setline(a:topline, repeat(' ', leftAlignIndx) . left ) + + " add the right delimiter after bottom line (we have to add 1 cos we moved + " the lines down when we added the left delim + call cursor(a:bottomline+1, 1) + execute 'normal! o' + call setline(a:bottomline+2, repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . right ) + + endif + + " go thru each line adding the sexyComMarker marker to the start of each + " line in the appropriate place to align them with the comment delims + let currentLine = a:topline+1 + while currentLine <= a:bottomline + !g:NERDCompactSexyComs + " get the line and convert the tabs to spaces + let theLine = getline(currentLine) + let lineHasTabs = s:HasLeadingTabs(theLine) + if lineHasTabs + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + endif + + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + + " add the sexyComMarker + let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx) + + if lineHasTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + + " set the line and move onto the next one + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + +endfunction + +" Function: s:CommentLinesToggle(forceNested, firstLine, lastLine) {{{2 +" Applies "toggle" commenting to the given range of lines +" +" Args: +" -forceNested: a flag indicating whether the called is requesting the comment +" to be nested if need be +" -firstLine/lastLine: the top and bottom lines to comment +function s:CommentLinesToggle(forceNested, firstLine, lastLine) + let currentLine = a:firstLine + while currentLine <= a:lastLine + + " get the next line, check commentability and convert spaces to tabs + let theLine = getline(currentLine) + let lineHasLeadingTabs = s:HasLeadingTabs(theLine) + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + if s:CanToggleCommentLine(a:forceNested, currentLine) + + "if the user has specified forceNesting then we check to see if we + "need to switch delimiters for place-holders + if g:NERDUsePlaceHolders + let theLine = s:SwapOutterMultiPartDelimsForPlaceHolders(theLine) + endif + + let theLine = s:AddLeftDelim(s:GetLeft(0, 1, 0), theLine) + let theLine = s:AddRightDelim(s:GetRight(0, 1, 0), theLine) + endif + + " restore leading tabs if appropriate + if lineHasLeadingTabs + let theLine = s:ConvertLeadingSpacesToTabs(theLine) + endif + + " we are done with this line + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + +endfunction + +" Function: s:CommentRegion(topline, topCol, bottomLine, bottomCol) function {{{2 +" This function comments chunks of text selected in visual mode. +" It will comment exactly the text that they have selected. +" Args: +" -topLine: the line num of the top line in the sexy comment +" -topCol: top left col for this comment +" -bottomline: the line num of the bottom line in the sexy comment +" -bottomCol: the bottom right col for this comment +" -forceNested: whether the caller wants comments to be nested if the +" line(s) are already commented +function s:CommentRegion(topLine, topCol, bottomLine, bottomCol, forceNested) + + "switch delims (if we can) if the current set isnt multipart + let switchedDelims = 0 + if !s:Multipart() && s:AltMultipart() && !g:NERDAllowAnyVisualDelims + let switchedDelims = 1 + call s:SwitchToAlternativeDelimiters(0) + endif + + "if there is only one line in the comment then just do it + if a:topLine == a:bottomLine + call s:CommentBlock(a:topLine, a:bottomLine, a:topCol, a:bottomCol, a:forceNested) + + "there are multiple lines in the comment + else + "comment the top line + call s:CommentBlock(a:topLine, a:topLine, a:topCol, strlen(getline(a:topLine)), a:forceNested) + + "comment out all the lines in the middle of the comment + let topOfRange = a:topLine+1 + let bottomOfRange = a:bottomLine-1 + if topOfRange <= bottomOfRange + call s:CommentLines(a:forceNested, "none", topOfRange, bottomOfRange) + endif + + "comment the bottom line + let bottom = getline(a:bottomLine) + let numLeadingSpacesTabs = strlen(substitute(bottom, '^\([ \t]*\).*$', '\1', '')) + call s:CommentBlock(a:bottomLine, a:bottomLine, numLeadingSpacesTabs+1, a:bottomCol, a:forceNested) + + endif + + "stick the cursor back on the char it was on before the comment + call cursor(a:topLine, a:topCol + strlen(b:NERDLeft) + g:NERDSpaceDelims) + + "if we switched delims then we gotta go back to what they were before + if switchedDelims == 1 + call s:SwitchToAlternativeDelimiters(0) + endif + +endfunction + +" Function: s:InvertComment(firstLine, lastLine) function {{{2 +" Inverts the comments on the lines between and including the given line +" numbers i.e all commented lines are uncommented and vice versa +" Args: +" -firstLine: the top of the range of lines to be inverted +" -lastLine: the bottom of the range of lines to be inverted +function s:InvertComment(firstLine, lastLine) + + " go thru all lines in the given range + let currentLine = a:firstLine + while currentLine <= a:lastLine + let theLine = getline(currentLine) + + let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine) + + " if the line is commented normally, uncomment it + if s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine) + call s:UncommentLines(currentLine, currentLine) + let currentLine = currentLine + 1 + + " check if the line is commented sexually + elseif !empty(sexyComBounds) + let numLinesBeforeSexyComRemoved = s:NumLinesInBuf() + call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1]) + + "move to the line after last line of the sexy comment + let numLinesAfterSexyComRemoved = s:NumLinesInBuf() + let currentLine = bottomBound - (numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved) + 1 + + " the line isnt commented + else + call s:CommentLinesToggle(1, currentLine, currentLine) + let currentLine = currentLine + 1 + endif + + endwhile +endfunction + +" Function: NERDComment(isVisual, type) function {{{2 +" This function is a Wrapper for the main commenting functions +" +" Args: +" -isVisual: a flag indicating whether the comment is requested in visual +" mode or not +" -type: the type of commenting requested. Can be 'sexy', 'invert', +" 'minimal', 'toggle', 'alignLeft', 'alignBoth', 'norm', +" 'nested', 'toEOL', 'append', 'insert', 'uncomment', 'yank' +function! NERDComment(isVisual, type) range + " we want case sensitivity when commenting + let oldIgnoreCase = &ignorecase + set noignorecase + + if a:isVisual + let firstLine = line("'<") + let lastLine = line("'>") + let firstCol = col("'<") + let lastCol = col("'>") - (&selection == 'exclusive' ? 1 : 0) + else + let firstLine = a:firstline + let lastLine = a:lastline + endif + + let countWasGiven = (a:isVisual == 0 && firstLine != lastLine) + + let forceNested = (a:type == 'nested' || g:NERDDefaultNesting) + + if a:type == 'norm' || a:type == 'nested' + if a:isVisual && visualmode() == "" + call s:CommentBlock(firstLine, lastLine, firstCol, lastCol, forceNested) + elseif a:isVisual && visualmode() == "v" && (g:NERDCommentWholeLinesInVMode==0 || (g:NERDCommentWholeLinesInVMode==2 && s:HasMultipartDelims())) + call s:CommentRegion(firstLine, firstCol, lastLine, lastCol, forceNested) + else + call s:CommentLines(forceNested, "none", firstLine, lastLine) + endif + + elseif a:type == 'alignLeft' || a:type == 'alignBoth' + let align = "none" + if a:type == "alignLeft" + let align = "left" + elseif a:type == "alignBoth" + let align = "both" + endif + call s:CommentLines(forceNested, align, firstLine, lastLine) + + elseif a:type == 'invert' + call s:InvertComment(firstLine, lastLine) + + elseif a:type == 'sexy' + try + call s:CommentLinesSexy(firstLine, lastLine) + catch /NERDCommenter.Delimiters/ + call s:CommentLines(forceNested, "none", firstLine, lastLine) + catch /NERDCommenter.Nesting/ + call s:NerdEcho("Sexy comment aborted. Nested sexy cannot be nested", 0) + endtry + + elseif a:type == 'toggle' + let theLine = getline(firstLine) + + if s:IsInSexyComment(firstLine) || s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine) + call s:UncommentLines(firstLine, lastLine) + else + call s:CommentLinesToggle(forceNested, firstLine, lastLine) + endif + + elseif a:type == 'minimal' + try + call s:CommentLinesMinimal(firstLine, lastLine) + catch /NERDCommenter.Delimiters/ + call s:NerdEcho("Minimal comments can only be used for filetypes that have multipart delimiters.", 0) + catch /NERDCommenter.Settings/ + call s:NerdEcho("Place holders are required but disabled.", 0) + endtry + + elseif a:type == 'toEOL' + call s:SaveScreenState() + call s:CommentBlock(firstLine, firstLine, col("."), col("$")-1, 1) + call s:RestoreScreenState() + + elseif a:type == 'append' + call s:AppendCommentToLine() + + elseif a:type == 'insert' + call s:PlaceDelimitersAndInsBetween() + + elseif a:type == 'uncomment' + call s:UncommentLines(firstLine, lastLine) + + elseif a:type == 'yank' + if a:isVisual + normal! gvy + elseif countWasGiven + execute firstLine .','. lastLine .'yank' + else + normal! yy + endif + execute firstLine .','. lastLine .'call NERDComment('. a:isVisual .', "norm")' + endif + + let &ignorecase = oldIgnoreCase +endfunction + +" Function: s:PlaceDelimitersAndInsBetween() function {{{2 +" This is function is called to place comment delimiters down and place the +" cursor between them +function s:PlaceDelimitersAndInsBetween() + " get the left and right delimiters without any escape chars in them + let left = s:GetLeft(0, 1, 0) + let right = s:GetRight(0, 1, 0) + + let theLine = getline(".") + let lineHasLeadTabs = s:HasLeadingTabs(theLine) || (theLine =~ '^ *$' && !&expandtab) + + "convert tabs to spaces and adjust the cursors column to take this into + "account + let untabbedCol = s:UntabbedCol(theLine, col(".")) + call setline(line("."), s:ConvertLeadingTabsToSpaces(theLine)) + call cursor(line("."), untabbedCol) + + " get the len of the right delim + let lenRight = strlen(right) + + let isDelimOnEOL = col(".") >= strlen(getline(".")) + + " if the cursor is in the first col then we gotta insert rather than + " append the comment delimiters here + let insOrApp = (col(".")==1 ? 'i' : 'a') + + " place the delimiters down. We do it differently depending on whether + " there is a left AND right delimiter + if lenRight > 0 + execute ":normal! " . insOrApp . left . right + execute ":normal! " . lenRight . "h" + else + execute ":normal! " . insOrApp . left + + " if we are tacking the delim on the EOL then we gotta add a space + " after it cos when we go out of insert mode the cursor will move back + " one and the user wont be in position to type the comment. + if isDelimOnEOL + execute 'normal! a ' + endif + endif + normal! l + + "if needed convert spaces back to tabs and adjust the cursors col + "accordingly + if lineHasLeadTabs + let tabbedCol = s:TabbedCol(getline("."), col(".")) + call setline(line("."), s:ConvertLeadingSpacesToTabs(getline("."))) + call cursor(line("."), tabbedCol) + endif + + startinsert +endfunction + +" Function: s:RemoveDelimiters(left, right, line) {{{2 +" this function is called to remove the first left comment delimiter and the +" last right delimiter of the given line. +" +" The args left and right must be strings. If there is no right delimiter (as +" is the case for e.g vim file comments) them the arg right should be "" +" +" Args: +" -left: the left comment delimiter +" -right: the right comment delimiter +" -line: the line to remove the delimiters from +function s:RemoveDelimiters(left, right, line) + + let l:left = a:left + let l:right = a:right + let lenLeft = strlen(left) + let lenRight = strlen(right) + + let delimsSpaced = (g:NERDSpaceDelims || g:NERDRemoveExtraSpaces) + + let line = a:line + + "look for the left delimiter, if we find it, remove it. + let leftIndx = s:FindDelimiterIndex(a:left, line) + if leftIndx != -1 + let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+lenLeft) + + "if the user has specified that there is a space after the left delim + "then check for the space and remove it if it is there + if delimsSpaced && strpart(line, leftIndx, s:lenSpaceStr) == s:spaceStr + let line = strpart(line, 0, leftIndx) . strpart(line, leftIndx+s:lenSpaceStr) + endif + endif + + "look for the right delimiter, if we find it, remove it + let rightIndx = s:FindDelimiterIndex(a:right, line) + if rightIndx != -1 + let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight) + + "if the user has specified that there is a space before the right delim + "then check for the space and remove it if it is there + if delimsSpaced && strpart(line, rightIndx-s:lenSpaceStr, s:lenSpaceStr) == s:spaceStr && s:Multipart() + let line = strpart(line, 0, rightIndx-s:lenSpaceStr) . strpart(line, rightIndx) + endif + endif + + return line +endfunction + +" Function: s:UncommentLines(topLine, bottomLine) {{{2 +" This function uncomments the given lines +" +" Args: +" topLine: the top line of the visual selection to uncomment +" bottomLine: the bottom line of the visual selection to uncomment +function s:UncommentLines(topLine, bottomLine) + "make local copies of a:firstline and a:lastline and, if need be, swap + "them around if the top line is below the bottom + let l:firstline = a:topLine + let l:lastline = a:bottomLine + if firstline > lastline + let firstline = lastline + let lastline = a:topLine + endif + + "go thru each line uncommenting each line removing sexy comments + let currentLine = firstline + while currentLine <= lastline + + "check the current line to see if it is part of a sexy comment + let sexyComBounds = s:FindBoundingLinesOfSexyCom(currentLine) + if !empty(sexyComBounds) + + "we need to store the num lines in the buf before the comment is + "removed so we know how many lines were removed when the sexy com + "was removed + let numLinesBeforeSexyComRemoved = s:NumLinesInBuf() + + call s:UncommentLinesSexy(sexyComBounds[0], sexyComBounds[1]) + + "move to the line after last line of the sexy comment + let numLinesAfterSexyComRemoved = s:NumLinesInBuf() + let numLinesRemoved = numLinesBeforeSexyComRemoved - numLinesAfterSexyComRemoved + let currentLine = sexyComBounds[1] - numLinesRemoved + 1 + let lastline = lastline - numLinesRemoved + + "no sexy com was detected so uncomment the line as normal + else + call s:UncommentLinesNormal(currentLine, currentLine) + let currentLine = currentLine + 1 + endif + endwhile + +endfunction + +" Function: s:UncommentLinesSexy(topline, bottomline) {{{2 +" This function removes all the comment characters associated with the sexy +" comment spanning the given lines +" Args: +" -topline/bottomline: the top/bottom lines of the sexy comment +function s:UncommentLinesSexy(topline, bottomline) + let left = s:GetSexyComLeft(0,1) + let right = s:GetSexyComRight(0,1) + + + "check if it is even possible for sexy comments to exist with the + "available delimiters + if left == -1 || right == -1 + throw 'NERDCommenter.Delimiters exception: cannot uncomment sexy comments with available delimiters.' + endif + + let leftUnEsc = s:GetSexyComLeft(0,0) + let rightUnEsc = s:GetSexyComRight(0,0) + + let sexyComMarker = s:GetSexyComMarker(0, 1) + let sexyComMarkerUnEsc = s:GetSexyComMarker(0, 0) + + "the markerOffset is how far right we need to move the sexyComMarker to + "line it up with the end of the left delim + let markerOffset = strlen(leftUnEsc)-strlen(sexyComMarkerUnEsc) + + " go thru the intermediate lines of the sexy comment and remove the + " sexy comment markers (eg the '*'s on the start of line in a c sexy + " comment) + let currentLine = a:topline+1 + while currentLine < a:bottomline + let theLine = getline(currentLine) + + " remove the sexy comment marker from the line. We also remove the + " space after it if there is one and if appropriate options are set + let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc) + if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)) + endif + + let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine) + + let theLine = s:ConvertLeadingWhiteSpace(theLine) + + " move onto the next line + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + + " gotta make a copy of a:bottomline cos we modify the position of the + " last line it if we remove the topline + let bottomline = a:bottomline + + " get the first line so we can remove the left delim from it + let theLine = getline(a:topline) + + " if the first line contains only the left delim then just delete it + if theLine =~ '^[ \t]*' . left . '[ \t]*$' && !g:NERDCompactSexyComs + call cursor(a:topline, 1) + normal! dd + let bottomline = bottomline - 1 + + " topline contains more than just the left delim + else + + " remove the delim. If there is a space after it + " then remove this too if appropriate + let delimIndx = stridx(theLine, leftUnEsc) + if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(leftUnEsc)) + endif + let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine) + call setline(a:topline, theLine) + endif + + " get the last line so we can remove the right delim + let theLine = getline(bottomline) + + " if the bottomline contains only the right delim then just delete it + if theLine =~ '^[ \t]*' . right . '[ \t]*$' + call cursor(bottomline, 1) + normal! dd + + " the last line contains more than the right delim + else + " remove the right delim. If there is a space after it and + " if the appropriate options are set then remove this too. + let delimIndx = s:LastIndexOfDelim(rightUnEsc, theLine) + if strpart(theLine, delimIndx+strlen(leftUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, delimIndx) . strpart(theLine, delimIndx+strlen(rightUnEsc)) + endif + + " if the last line also starts with a sexy comment marker then we + " remove this as well + if theLine =~ '^[ \t]*' . sexyComMarker + + " remove the sexyComMarker. If there is a space after it then + " remove that too + let sexyComMarkerIndx = stridx(theLine, sexyComMarkerUnEsc) + if strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc), s:lenSpaceStr) == s:spaceStr && g:NERDSpaceDelims + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)+s:lenSpaceStr) + else + let theLine = strpart(theLine, 0, sexyComMarkerIndx - markerOffset ) . strpart(theLine, sexyComMarkerIndx+strlen(sexyComMarkerUnEsc)) + endif + endif + + let theLine = s:SwapOutterPlaceHoldersForMultiPartDelims(theLine) + call setline(bottomline, theLine) + endif +endfunction + +" Function: s:UncommentLineNormal(line) {{{2 +" uncomments the given line and returns the result +" Args: +" -line: the line to uncomment +function s:UncommentLineNormal(line) + let line = a:line + + "get the comment status on the line so we know how it is commented + let lineCommentStatus = s:IsCommentedOuttermost(b:NERDLeft, b:NERDRight, b:NERDLeftAlt, b:NERDRightAlt, line) + + "it is commented with b:NERDLeft and b:NERDRight so remove these delims + if lineCommentStatus == 1 + let line = s:RemoveDelimiters(b:NERDLeft, b:NERDRight, line) + + "it is commented with b:NERDLeftAlt and b:NERDRightAlt so remove these delims + elseif lineCommentStatus == 2 && g:NERDRemoveAltComs + let line = s:RemoveDelimiters(b:NERDLeftAlt, b:NERDRightAlt, line) + + "it is not properly commented with any delims so we check if it has + "any random left or right delims on it and remove the outtermost ones + else + "get the positions of all delim types on the line + let indxLeft = s:FindDelimiterIndex(b:NERDLeft, line) + let indxLeftAlt = s:FindDelimiterIndex(b:NERDLeftAlt, line) + let indxRight = s:FindDelimiterIndex(b:NERDRight, line) + let indxRightAlt = s:FindDelimiterIndex(b:NERDRightAlt, line) + + "remove the outter most left comment delim + if indxLeft != -1 && (indxLeft < indxLeftAlt || indxLeftAlt == -1) + let line = s:RemoveDelimiters(b:NERDLeft, '', line) + elseif indxLeftAlt != -1 + let line = s:RemoveDelimiters(b:NERDLeftAlt, '', line) + endif + + "remove the outter most right comment delim + if indxRight != -1 && (indxRight < indxRightAlt || indxRightAlt == -1) + let line = s:RemoveDelimiters('', b:NERDRight, line) + elseif indxRightAlt != -1 + let line = s:RemoveDelimiters('', b:NERDRightAlt, line) + endif + endif + + + let indxLeft = s:FindDelimiterIndex(b:NERDLeft, line) + let indxLeftAlt = s:FindDelimiterIndex(b:NERDLeftAlt, line) + let indxLeftPlace = s:FindDelimiterIndex(g:NERDLPlace, line) + + let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line) + let indxRightAlt = s:FindDelimiterIndex(b:NERDRightAlt, line) + let indxRightPlace = s:FindDelimiterIndex(g:NERDRPlace, line) + + let right = b:NERDRight + let left = b:NERDLeft + if !s:Multipart() + let right = b:NERDRightAlt + let left = b:NERDLeftAlt + endif + + + "if there are place-holders on the line then we check to see if they are + "the outtermost delimiters on the line. If so then we replace them with + "real delimiters + if indxLeftPlace != -1 + if (indxLeftPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1) + let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line) + endif + elseif indxRightPlace != -1 + if (indxRightPlace < indxLeft || indxLeft==-1) && (indxLeftPlace < indxLeftAlt || indxLeftAlt==-1) + let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, line) + endif + + endif + + let line = s:ConvertLeadingWhiteSpace(line) + + return line +endfunction + +" Function: s:UncommentLinesNormal(topline, bottomline) {{{2 +" This function is called to uncomment lines that arent a sexy comment +" Args: +" -topline/bottomline: the top/bottom line numbers of the comment +function s:UncommentLinesNormal(topline, bottomline) + let currentLine = a:topline + while currentLine <= a:bottomline + let line = getline(currentLine) + call setline(currentLine, s:UncommentLineNormal(line)) + let currentLine = currentLine + 1 + endwhile +endfunction + + +" Section: Other helper functions {{{1 +" ============================================================================ + +" Function: s:AddLeftDelim(delim, theLine) {{{2 +" Args: +function s:AddLeftDelim(delim, theLine) + return substitute(a:theLine, '^\([ \t]*\)', '\1' . a:delim, '') +endfunction + +" Function: s:AddLeftDelimAligned(delim, theLine) {{{2 +" Args: +function s:AddLeftDelimAligned(delim, theLine, alignIndx) + + "if the line is not long enough then bung some extra spaces on the front + "so we can align the delim properly + let theLine = a:theLine + if strlen(theLine) < a:alignIndx + let theLine = repeat(' ', a:alignIndx - strlen(theLine)) + endif + + return strpart(theLine, 0, a:alignIndx) . a:delim . strpart(theLine, a:alignIndx) +endfunction + +" Function: s:AddRightDelim(delim, theLine) {{{2 +" Args: +function s:AddRightDelim(delim, theLine) + if a:delim == '' + return a:theLine + else + return substitute(a:theLine, '$', a:delim, '') + endif +endfunction + +" Function: s:AddRightDelimAligned(delim, theLine, alignIndx) {{{2 +" Args: +function s:AddRightDelimAligned(delim, theLine, alignIndx) + if a:delim == "" + return a:theLine + else + + " when we align the right delim we are just adding spaces + " so we get a string containing the needed spaces (it + " could be empty) + let extraSpaces = '' + let extraSpaces = repeat(' ', a:alignIndx-strlen(a:theLine)) + + " add the right delim + return substitute(a:theLine, '$', extraSpaces . a:delim, '') + endif +endfunction + +" Function: s:AltMultipart() {{{2 +" returns 1 if the alternative delims are multipart +function s:AltMultipart() + return b:NERDRightAlt != '' +endfunction + +" Function: s:CanCommentLine(forceNested, line) {{{2 +"This function is used to determine whether the given line can be commented. +"It returns 1 if it can be and 0 otherwise +" +" Args: +" -forceNested: a flag indicating whether the caller wants comments to be nested +" if the current line is already commented +" -lineNum: the line num of the line to check for commentability +function s:CanCommentLine(forceNested, lineNum) + let theLine = getline(a:lineNum) + + " make sure we don't comment lines that are just spaces or tabs or empty. + if theLine =~ "^[ \t]*$" + return 0 + endif + + "if the line is part of a sexy comment then just flag it... + if s:IsInSexyComment(a:lineNum) + return 0 + endif + + let isCommented = s:IsCommentedNormOrSexy(a:lineNum) + + "if the line isnt commented return true + if !isCommented + return 1 + endif + + "if the line is commented but nesting is allowed then return true + if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders) + return 1 + endif + + return 0 +endfunction + +" Function: s:CanPlaceCursor(line, col) {{{2 +" returns 1 if the cursor can be placed exactly in the given position +function s:CanPlaceCursor(line, col) + let c = col(".") + let l = line(".") + call cursor(a:line, a:col) + let success = (line(".") == a:line && col(".") == a:col) + call cursor(l,c) + return success +endfunction + +" Function: s:CanSexyCommentLines(topline, bottomline) {{{2 +" Return: 1 if the given lines can be commented sexually, 0 otherwise +function s:CanSexyCommentLines(topline, bottomline) + " see if the selected regions have any sexy comments + let currentLine = a:topline + while(currentLine <= a:bottomline) + if s:IsInSexyComment(currentLine) + return 0 + endif + let currentLine = currentLine + 1 + endwhile + return 1 +endfunction +" Function: s:CanToggleCommentLine(forceNested, line) {{{2 +"This function is used to determine whether the given line can be toggle commented. +"It returns 1 if it can be and 0 otherwise +" +" Args: +" -lineNum: the line num of the line to check for commentability +function s:CanToggleCommentLine(forceNested, lineNum) + let theLine = getline(a:lineNum) + if (s:IsCommentedFromStartOfLine(b:NERDLeft, theLine) || s:IsCommentedFromStartOfLine(b:NERDLeftAlt, theLine)) && !a:forceNested + return 0 + endif + + " make sure we don't comment lines that are just spaces or tabs or empty. + if theLine =~ "^[ \t]*$" + return 0 + endif + + "if the line is part of a sexy comment then just flag it... + if s:IsInSexyComment(a:lineNum) + return 0 + endif + + return 1 +endfunction + +" Function: s:ConvertLeadingSpacesToTabs(line) {{{2 +" This function takes a line and converts all leading tabs on that line into +" spaces +" +" Args: +" -line: the line whose leading tabs will be converted +function s:ConvertLeadingSpacesToTabs(line) + let toReturn = a:line + while toReturn =~ '^\t*' . s:TabSpace() . '\(.*\)$' + let toReturn = substitute(toReturn, '^\(\t*\)' . s:TabSpace() . '\(.*\)$' , '\1\t\2' , "") + endwhile + + return toReturn +endfunction + + +" Function: s:ConvertLeadingTabsToSpaces(line) {{{2 +" This function takes a line and converts all leading spaces on that line into +" tabs +" +" Args: +" -line: the line whose leading spaces will be converted +function s:ConvertLeadingTabsToSpaces(line) + let toReturn = a:line + while toReturn =~ '^\( *\)\t' + let toReturn = substitute(toReturn, '^\( *\)\t', '\1' . s:TabSpace() , "") + endwhile + + return toReturn +endfunction + +" Function: s:ConvertLeadingWhiteSpace(line) {{{2 +" Converts the leading white space to tabs/spaces depending on &ts +" +" Args: +" -line: the line to convert +function s:ConvertLeadingWhiteSpace(line) + let toReturn = a:line + while toReturn =~ '^ *\t' + let toReturn = substitute(toReturn, '^ *\zs\t\ze', s:TabSpace(), "g") + endwhile + + if !&expandtab + let toReturn = s:ConvertLeadingSpacesToTabs(toReturn) + endif + + return toReturn +endfunction + + +" Function: s:CountNonESCedOccurances(str, searchstr, escChar) {{{2 +" This function counts the number of substrings contained in another string. +" These substrings are only counted if they are not escaped with escChar +" Args: +" -str: the string to look for searchstr in +" -searchstr: the substring to search for in str +" -escChar: the escape character which, when preceding an instance of +" searchstr, will cause it not to be counted +function s:CountNonESCedOccurances(str, searchstr, escChar) + "get the index of the first occurrence of searchstr + let indx = stridx(a:str, a:searchstr) + + "if there is an instance of searchstr in str process it + if indx != -1 + "get the remainder of str after this instance of searchstr is removed + let lensearchstr = strlen(a:searchstr) + let strLeft = strpart(a:str, indx+lensearchstr) + + "if this instance of searchstr is not escaped, add one to the count + "and recurse. If it is escaped, just recurse + if !s:IsEscaped(a:str, indx, a:escChar) + return 1 + s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar) + else + return s:CountNonESCedOccurances(strLeft, a:searchstr, a:escChar) + endif + endif +endfunction +" Function: s:DoesBlockHaveDelim(delim, top, bottom) {{{2 +" Returns 1 if the given block of lines has a delimiter (a:delim) in it +" Args: +" -delim: the comment delimiter to check the block for +" -top: the top line number of the block +" -bottom: the bottom line number of the block +function s:DoesBlockHaveDelim(delim, top, bottom) + let currentLine = a:top + while currentLine < a:bottom + let theline = getline(currentLine) + if s:FindDelimiterIndex(a:delim, theline) != -1 + return 1 + endif + let currentLine = currentLine + 1 + endwhile + return 0 +endfunction + +" Function: s:DoesBlockHaveMultipartDelim(top, bottom) {{{2 +" Returns 1 if the given block has a >= 1 multipart delimiter in it +" Args: +" -top: the top line number of the block +" -bottom: the bottom line number of the block +function s:DoesBlockHaveMultipartDelim(top, bottom) + if s:HasMultipartDelims() + if s:Multipart() + return s:DoesBlockHaveDelim(b:NERDLeft, a:top, a:bottom) || s:DoesBlockHaveDelim(b:NERDRight, a:top, a:bottom) + else + return s:DoesBlockHaveDelim(b:NERDLeftAlt, a:top, a:bottom) || s:DoesBlockHaveDelim(b:NERDRightAlt, a:top, a:bottom) + endif + endif + return 0 +endfunction + + +" Function: s:Esc(str) {{{2 +" Escapes all the tricky chars in the given string +function s:Esc(str) + let charsToEsc = '*/\."&$+' + return escape(a:str, charsToEsc) +endfunction + +" Function: s:FindDelimiterIndex(delimiter, line) {{{2 +" This function is used to get the string index of the input comment delimiter +" on the input line. If no valid comment delimiter is found in the line then +" -1 is returned +" Args: +" -delimiter: the delimiter we are looking to find the index of +" -line: the line we are looking for delimiter on +function s:FindDelimiterIndex(delimiter, line) + + "make sure the delimiter isnt empty otherwise we go into an infinite loop. + if a:delimiter == "" + return -1 + endif + + + let l:delimiter = a:delimiter + let lenDel = strlen(l:delimiter) + + "get the index of the first occurrence of the delimiter + let delIndx = stridx(a:line, l:delimiter) + + "keep looping thru the line till we either find a real comment delimiter + "or run off the EOL + while delIndx != -1 + + "if we are not off the EOL get the str before the possible delimiter + "in question and check if it really is a delimiter. If it is, return + "its position + if delIndx != -1 + if s:IsDelimValid(l:delimiter, delIndx, a:line) + return delIndx + endif + endif + + "we have not yet found a real comment delimiter so move past the + "current one we are lookin at + let restOfLine = strpart(a:line, delIndx + lenDel) + let distToNextDelim = stridx(restOfLine , l:delimiter) + + "if distToNextDelim is -1 then there is no more potential delimiters + "on the line so set delIndx to -1. Otherwise, move along the line by + "distToNextDelim + if distToNextDelim == -1 + let delIndx = -1 + else + let delIndx = delIndx + lenDel + distToNextDelim + endif + endwhile + + "there is no comment delimiter on this line + return -1 +endfunction + +" Function: s:FindBoundingLinesOfSexyCom(lineNum) {{{2 +" This function takes in a line number and tests whether this line number is +" the top/bottom/middle line of a sexy comment. If it is then the top/bottom +" lines of the sexy comment are returned +" Args: +" -lineNum: the line number that is to be tested whether it is the +" top/bottom/middle line of a sexy com +" Returns: +" A string that has the top/bottom lines of the sexy comment encoded in it. +" The format is 'topline,bottomline'. If a:lineNum turns out not to be the +" top/bottom/middle of a sexy comment then -1 is returned +function s:FindBoundingLinesOfSexyCom(lineNum) + + "find which delimiters to look for as the start/end delims of the comment + let left = '' + let right = '' + if s:Multipart() + let left = s:GetLeft(0,0,1) + let right = s:GetRight(0,0,1) + elseif s:AltMultipart() + let left = s:GetLeft(1,0,1) + let right = s:GetRight(1,0,1) + else + return [] + endif + + let sexyComMarker = s:GetSexyComMarker(0, 1) + + "initialise the top/bottom line numbers of the sexy comment to -1 + let top = -1 + let bottom = -1 + + let currentLine = a:lineNum + while top == -1 || bottom == -1 + let theLine = getline(currentLine) + + "check if the current line is the top of the sexy comment + if currentLine <= a:lineNum && theLine =~ '^[ \t]*' . left && theLine !~ '.*' . right && currentLine < s:NumLinesInBuf() + let top = currentLine + let currentLine = a:lineNum + + "check if the current line is the bottom of the sexy comment + elseif theLine =~ '^[ \t]*' . right && theLine !~ '.*' . left && currentLine > 1 + let bottom = currentLine + + "the right delimiter is on the same line as the last sexyComMarker + elseif theLine =~ '^[ \t]*' . sexyComMarker . '.*' . right + let bottom = currentLine + + "we have not found the top or bottom line so we assume currentLine is an + "intermediate line and look to prove otherwise + else + + "if the line doesnt start with a sexyComMarker then it is not a sexy + "comment + if theLine !~ '^[ \t]*' . sexyComMarker + return [] + endif + + endif + + "if top is -1 then we havent found the top yet so keep looking up + if top == -1 + let currentLine = currentLine - 1 + "if we have found the top line then go down looking for the bottom + else + let currentLine = currentLine + 1 + endif + + endwhile + + return [top, bottom] +endfunction + + +" Function: s:GetLeft(alt, space, esc) {{{2 +" returns the left/left-alternative delimiter +" Args: +" -alt: specifies whether to get left or left-alternative delim +" -space: specifies whether the delim should be spaced or not +" (the space string will only be added if NERDSpaceDelims is set) +" -esc: specifies whether the tricky chars in the delim should be ESCed +function s:GetLeft(alt, space, esc) + let delim = b:NERDLeft + + if a:alt + if b:NERDLeftAlt == '' + return '' + else + let delim = b:NERDLeftAlt + endif + endif + if delim == '' + return '' + endif + + if a:space && g:NERDSpaceDelims + let delim = delim . s:spaceStr + endif + + if a:esc + let delim = s:Esc(delim) + endif + + return delim +endfunction + +" Function: s:GetRight(alt, space, esc) {{{2 +" returns the right/right-alternative delimiter +" Args: +" -alt: specifies whether to get right or right-alternative delim +" -space: specifies whether the delim should be spaced or not +" (the space string will only be added if NERDSpaceDelims is set) +" -esc: specifies whether the tricky chars in the delim should be ESCed +function s:GetRight(alt, space, esc) + let delim = b:NERDRight + + if a:alt + if !s:AltMultipart() + return '' + else + let delim = b:NERDRightAlt + endif + endif + if delim == '' + return '' + endif + + if a:space && g:NERDSpaceDelims + let delim = s:spaceStr . delim + endif + + if a:esc + let delim = s:Esc(delim) + endif + + return delim +endfunction + + +" Function: s:GetSexyComMarker() {{{2 +" Returns the sexy comment marker for the current filetype. +" +" C style sexy comments are assumed if possible. If not then the sexy comment +" marker is the last char of the delimiter pair that has both left and right +" delims and has the longest left delim +" +" Args: +" -space: specifies whether the marker is to have a space string after it +" (the space string will only be added if NERDSpaceDelims is set) +" -esc: specifies whether the tricky chars in the marker are to be ESCed +function s:GetSexyComMarker(space, esc) + let sexyComMarker = b:NERDSexyComMarker + + "if there is no hardcoded marker then we find one + if sexyComMarker == '' + + "if the filetype has c style comments then use standard c sexy + "comments + if s:HasCStyleComments() + let sexyComMarker = '*' + else + "find a comment marker by getting the longest available left delim + "(that has a corresponding right delim) and taking the last char + let lenLeft = strlen(b:NERDLeft) + let lenLeftAlt = strlen(b:NERDLeftAlt) + let left = '' + let right = '' + if s:Multipart() && lenLeft >= lenLeftAlt + let left = b:NERDLeft + elseif s:AltMultipart() + let left = b:NERDLeftAlt + else + return -1 + endif + + "get the last char of left + let sexyComMarker = strpart(left, strlen(left)-1) + endif + endif + + if a:space && g:NERDSpaceDelims + let sexyComMarker = sexyComMarker . s:spaceStr + endif + + if a:esc + let sexyComMarker = s:Esc(sexyComMarker) + endif + + return sexyComMarker +endfunction + +" Function: s:GetSexyComLeft(space, esc) {{{2 +" Returns the left delimiter for sexy comments for this filetype or -1 if +" there is none. C style sexy comments are used if possible +" Args: +" -space: specifies if the delim has a space string on the end +" (the space string will only be added if NERDSpaceDelims is set) +" -esc: specifies whether the tricky chars in the string are ESCed +function s:GetSexyComLeft(space, esc) + let lenLeft = strlen(b:NERDLeft) + let lenLeftAlt = strlen(b:NERDLeftAlt) + let left = '' + + "assume c style sexy comments if possible + if s:HasCStyleComments() + let left = '/*' + else + "grab the longest left delim that has a right + if s:Multipart() && lenLeft >= lenLeftAlt + let left = b:NERDLeft + elseif s:AltMultipart() + let left = b:NERDLeftAlt + else + return -1 + endif + endif + + if a:space && g:NERDSpaceDelims + let left = left . s:spaceStr + endif + + if a:esc + let left = s:Esc(left) + endif + + return left +endfunction + +" Function: s:GetSexyComRight(space, esc) {{{2 +" Returns the right delimiter for sexy comments for this filetype or -1 if +" there is none. C style sexy comments are used if possible. +" Args: +" -space: specifies if the delim has a space string on the start +" (the space string will only be added if NERDSpaceDelims +" is specified for the current filetype) +" -esc: specifies whether the tricky chars in the string are ESCed +function s:GetSexyComRight(space, esc) + let lenLeft = strlen(b:NERDLeft) + let lenLeftAlt = strlen(b:NERDLeftAlt) + let right = '' + + "assume c style sexy comments if possible + if s:HasCStyleComments() + let right = '*/' + else + "grab the right delim that pairs with the longest left delim + if s:Multipart() && lenLeft >= lenLeftAlt + let right = b:NERDRight + elseif s:AltMultipart() + let right = b:NERDRightAlt + else + return -1 + endif + endif + + if a:space && g:NERDSpaceDelims + let right = s:spaceStr . right + endif + + if a:esc + let right = s:Esc(right) + endif + + return right +endfunction + +" Function: s:HasMultipartDelims() {{{2 +" Returns 1 iff the current filetype has at least one set of multipart delims +function s:HasMultipartDelims() + return s:Multipart() || s:AltMultipart() +endfunction + +" Function: s:HasLeadingTabs(...) {{{2 +" Returns 1 if any of the given strings have leading tabs +function s:HasLeadingTabs(...) + for s in a:000 + if s =~ '^\t.*' + return 1 + end + endfor + return 0 +endfunction +" Function: s:HasCStyleComments() {{{2 +" Returns 1 iff the current filetype has c style comment delimiters +function s:HasCStyleComments() + return (b:NERDLeft == '/*' && b:NERDRight == '*/') || (b:NERDLeftAlt == '/*' && b:NERDRightAlt == '*/') +endfunction + +" Function: s:IsCommentedNormOrSexy(lineNum) {{{2 +"This function is used to determine whether the given line is commented with +"either set of delimiters or if it is part of a sexy comment +" +" Args: +" -lineNum: the line number of the line to check +function s:IsCommentedNormOrSexy(lineNum) + let theLine = getline(a:lineNum) + + "if the line is commented normally return 1 + if s:IsCommented(b:NERDLeft, b:NERDRight, theLine) || s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine) + return 1 + endif + + "if the line is part of a sexy comment return 1 + if s:IsInSexyComment(a:lineNum) + return 1 + endif + return 0 +endfunction + +" Function: s:IsCommented(left, right, line) {{{2 +"This function is used to determine whether the given line is commented with +"the given delimiters +" +" Args: +" -line: the line that to check if commented +" -left/right: the left and right delimiters to check for +function s:IsCommented(left, right, line) + "if the line isnt commented return true + if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart()) + return 1 + endif + return 0 +endfunction + +" Function: s:IsCommentedFromStartOfLine(left, line) {{{2 +"This function is used to determine whether the given line is commented with +"the given delimiters at the start of the line i.e the left delimiter is the +"first thing on the line (apart from spaces\tabs) +" +" Args: +" -line: the line that to check if commented +" -left: the left delimiter to check for +function s:IsCommentedFromStartOfLine(left, line) + let theLine = s:ConvertLeadingTabsToSpaces(a:line) + let numSpaces = strlen(substitute(theLine, '^\( *\).*$', '\1', '')) + let delimIndx = s:FindDelimiterIndex(a:left, theLine) + return delimIndx == numSpaces +endfunction + +" Function: s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) {{{2 +" Finds the type of the outtermost delims on the line +" +" Args: +" -line: the line that to check if the outtermost comments on it are +" left/right +" -left/right: the left and right delimiters to check for +" -leftAlt/rightAlt: the left and right alternative delimiters to check for +" +" Returns: +" 0 if the line is not commented with either set of delims +" 1 if the line is commented with the left/right delim set +" 2 if the line is commented with the leftAlt/rightAlt delim set +function s:IsCommentedOuttermost(left, right, leftAlt, rightAlt, line) + "get the first positions of the left delims and the last positions of the + "right delims + let indxLeft = s:FindDelimiterIndex(a:left, a:line) + let indxLeftAlt = s:FindDelimiterIndex(a:leftAlt, a:line) + let indxRight = s:LastIndexOfDelim(a:right, a:line) + let indxRightAlt = s:LastIndexOfDelim(a:rightAlt, a:line) + + "check if the line has a left delim before a leftAlt delim + if (indxLeft <= indxLeftAlt || indxLeftAlt == -1) && indxLeft != -1 + "check if the line has a right delim after any rightAlt delim + if (indxRight > indxRightAlt && indxRight > indxLeft) || !s:Multipart() + return 1 + endif + + "check if the line has a leftAlt delim before a left delim + elseif (indxLeftAlt <= indxLeft || indxLeft == -1) && indxLeftAlt != -1 + "check if the line has a rightAlt delim after any right delim + if (indxRightAlt > indxRight && indxRightAlt > indxLeftAlt) || !s:AltMultipart() + return 2 + endif + else + return 0 + endif + + return 0 + +endfunction + + +" Function: s:IsDelimValid(delimiter, delIndx, line) {{{2 +" This function is responsible for determining whether a given instance of a +" comment delimiter is a real delimiter or not. For example, in java the +" // string is a comment delimiter but in the line: +" System.out.println("//"); +" it does not count as a comment delimiter. This function is responsible for +" distinguishing between such cases. It does so by applying a set of +" heuristics that are not fool proof but should work most of the time. +" +" Args: +" -delimiter: the delimiter we are validating +" -delIndx: the position of delimiter in line +" -line: the line that delimiter occurs in +" +" Returns: +" 0 if the given delimiter is not a real delimiter (as far as we can tell) , +" 1 otherwise +function s:IsDelimValid(delimiter, delIndx, line) + "get the delimiter without the escchars + let l:delimiter = a:delimiter + + "get the strings before and after the delimiter + let preComStr = strpart(a:line, 0, a:delIndx) + let postComStr = strpart(a:line, a:delIndx+strlen(delimiter)) + + "to check if the delimiter is real, make sure it isnt preceded by + "an odd number of quotes and followed by the same (which would indicate + "that it is part of a string and therefore is not a comment) + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, '"', "\\")) + return 0 + endif + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "'", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "'", "\\")) + return 0 + endif + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, "`", "\\")) && !s:IsNumEven(s:CountNonESCedOccurances(postComStr, "`", "\\")) + return 0 + endif + + + "if the comment delimiter is escaped, assume it isnt a real delimiter + if s:IsEscaped(a:line, a:delIndx, "\\") + return 0 + endif + + "vim comments are so fuckin stupid!! Why the hell do they have comment + "delimiters that are used elsewhere in the syntax?!?! We need to check + "some conditions especially for vim + if &filetype == "vim" + if !s:IsNumEven(s:CountNonESCedOccurances(preComStr, '"', "\\")) + return 0 + endif + + "if the delimiter is on the very first char of the line or is the + "first non-tab/space char on the line then it is a valid comment delimiter + if a:delIndx == 0 || a:line =~ "^[ \t]\\{" . a:delIndx . "\\}\".*$" + return 1 + endif + + let numLeftParen =s:CountNonESCedOccurances(preComStr, "(", "\\") + let numRightParen =s:CountNonESCedOccurances(preComStr, ")", "\\") + + "if the quote is inside brackets then assume it isnt a comment + if numLeftParen > numRightParen + return 0 + endif + + "if the line has an even num of unescaped "'s then we can assume that + "any given " is not a comment delimiter + if s:IsNumEven(s:CountNonESCedOccurances(a:line, "\"", "\\")) + return 0 + endif + endif + + return 1 + +endfunction + +" Function: s:IsNumEven(num) {{{2 +" A small function the returns 1 if the input number is even and 0 otherwise +" Args: +" -num: the number to check +function s:IsNumEven(num) + return (a:num % 2) == 0 +endfunction + +" Function: s:IsEscaped(str, indx, escChar) {{{2 +" This function takes a string, an index into that string and an esc char and +" returns 1 if the char at the index is escaped (i.e if it is preceded by an +" odd number of esc chars) +" Args: +" -str: the string to check +" -indx: the index into str that we want to check +" -escChar: the escape char the char at indx may be ESCed with +function s:IsEscaped(str, indx, escChar) + "initialise numEscChars to 0 and look at the char before indx + let numEscChars = 0 + let curIndx = a:indx-1 + + "keep going back thru str until we either reach the start of the str or + "run out of esc chars + while curIndx >= 0 && strpart(a:str, curIndx, 1) == a:escChar + + "we have found another esc char so add one to the count and move left + "one char + let numEscChars = numEscChars + 1 + let curIndx = curIndx - 1 + + endwhile + + "if there is an odd num of esc chars directly before the char at indx then + "the char at indx is escaped + return !s:IsNumEven(numEscChars) +endfunction + +" Function: s:IsInSexyComment(line) {{{2 +" returns 1 if the given line number is part of a sexy comment +function s:IsInSexyComment(line) + return !empty(s:FindBoundingLinesOfSexyCom(a:line)) +endfunction + +" Function: s:IsSexyComment(topline, bottomline) {{{2 +" This function takes in 2 line numbers and returns 1 if the lines between and +" including the given line numbers are a sexy comment. It returns 0 otherwise. +" Args: +" -topline: the line that the possible sexy comment starts on +" -bottomline: the line that the possible sexy comment stops on +function s:IsSexyComment(topline, bottomline) + + "get the delim set that would be used for a sexy comment + let left = '' + let right = '' + if s:Multipart() + let left = b:NERDLeft + let right = b:NERDRight + elseif s:AltMultipart() + let left = b:NERDLeftAlt + let right = b:NERDRightAlt + else + return 0 + endif + + "swap the top and bottom line numbers around if need be + let topline = a:topline + let bottomline = a:bottomline + if bottomline < topline + topline = bottomline + bottomline = a:topline + endif + + "if there is < 2 lines in the comment it cannot be sexy + if (bottomline - topline) <= 0 + return 0 + endif + + "if the top line doesnt begin with a left delim then the comment isnt sexy + if getline(a:topline) !~ '^[ \t]*' . left + return 0 + endif + + "if there is a right delim on the top line then this isnt a sexy comment + if s:FindDelimiterIndex(right, getline(a:topline)) != -1 + return 0 + endif + + "if there is a left delim on the bottom line then this isnt a sexy comment + if s:FindDelimiterIndex(left, getline(a:bottomline)) != -1 + return 0 + endif + + "if the bottom line doesnt begin with a right delim then the comment isnt + "sexy + if getline(a:bottomline) !~ '^.*' . right . '$' + return 0 + endif + + let sexyComMarker = s:GetSexyComMarker(0, 1) + + "check each of the intermediate lines to make sure they start with a + "sexyComMarker + let currentLine = a:topline+1 + while currentLine < a:bottomline + let theLine = getline(currentLine) + + if theLine !~ '^[ \t]*' . sexyComMarker + return 0 + endif + + "if there is a right delim in an intermediate line then the block isnt + "a sexy comment + if s:FindDelimiterIndex(right, theLine) != -1 + return 0 + endif + + let currentLine = currentLine + 1 + endwhile + + "we have not found anything to suggest that this isnt a sexy comment so + return 1 + +endfunction + +" Function: s:LastIndexOfDelim(delim, str) {{{2 +" This function takes a string and a delimiter and returns the last index of +" that delimiter in string +" Args: +" -delim: the delimiter to look for +" -str: the string to look for delim in +function s:LastIndexOfDelim(delim, str) + let delim = a:delim + let lenDelim = strlen(delim) + + "set index to the first occurrence of delim. If there is no occurrence then + "bail + let indx = s:FindDelimiterIndex(delim, a:str) + if indx == -1 + return -1 + endif + + "keep moving to the next instance of delim in str till there is none left + while 1 + + "search for the next delim after the previous one + let searchStr = strpart(a:str, indx+lenDelim) + let indx2 = s:FindDelimiterIndex(delim, searchStr) + + "if we find a delim update indx to record the position of it, if we + "dont find another delim then indx is the last one so break out of + "this loop + if indx2 != -1 + let indx = indx + indx2 + lenDelim + else + break + endif + endwhile + + return indx + +endfunction + +" Function: s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2 +" This function takes in 2 line numbers and returns the index of the left most +" char (that is not a space or a tab) on all of these lines. +" Args: +" -countCommentedLines: 1 if lines that are commented are to be checked as +" well. 0 otherwise +" -countEmptyLines: 1 if empty lines are to be counted in the search +" -topline: the top line to be checked +" -bottomline: the bottom line to be checked +function s:LeftMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) + + " declare the left most index as an extreme value + let leftMostIndx = 1000 + + " go thru the block line by line updating leftMostIndx + let currentLine = a:topline + while currentLine <= a:bottomline + + " get the next line and if it is allowed to be commented, or is not + " commented, check it + let theLine = getline(currentLine) + if a:countEmptyLines || theLine !~ '^[ \t]*$' + if a:countCommentedLines || (!s:IsCommented(b:NERDLeft, b:NERDRight, theLine) && !s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine)) + " convert spaces to tabs and get the number of leading spaces for + " this line and update leftMostIndx if need be + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let leadSpaceOfLine = strlen( substitute(theLine, '\(^[ \t]*\).*$','\1','') ) + if leadSpaceOfLine < leftMostIndx + let leftMostIndx = leadSpaceOfLine + endif + endif + endif + + " move on to the next line + let currentLine = currentLine + 1 + endwhile + + if leftMostIndx == 1000 + return 0 + else + return leftMostIndx + endif +endfunction + +" Function: s:Multipart() {{{2 +" returns 1 if the current delims are multipart +function s:Multipart() + return b:NERDRight != '' +endfunction + +" Function: s:NerdEcho(msg, typeOfMsg) {{{2 +" Args: +" -msg: the message to echo +" -typeOfMsg: 0 = warning message +" 1 = normal message +function s:NerdEcho(msg, typeOfMsg) + if a:typeOfMsg == 0 + echohl WarningMsg + echo 'NERDCommenter:' . a:msg + echohl None + elseif a:typeOfMsg == 1 + echo 'NERDCommenter:' . a:msg + endif +endfunction + +" Function: s:NumberOfLeadingTabs(s) {{{2 +" returns the number of leading tabs in the given string +function s:NumberOfLeadingTabs(s) + return strlen(substitute(a:s, '^\(\t*\).*$', '\1', "")) +endfunction + +" Function: s:NumLinesInBuf() {{{2 +" Returns the number of lines in the current buffer +function s:NumLinesInBuf() + return line('$') +endfunction + +" Function: s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) {{{2 +" This function takes in a string, 2 delimiters in that string and 2 strings +" to replace these delimiters with. +" +" Args: +" -toReplace1: the first delimiter to replace +" -toReplace2: the second delimiter to replace +" -replacor1: the string to replace toReplace1 with +" -replacor2: the string to replace toReplace2 with +" -str: the string that the delimiters to be replaced are in +function s:ReplaceDelims(toReplace1, toReplace2, replacor1, replacor2, str) + let line = s:ReplaceLeftMostDelim(a:toReplace1, a:replacor1, a:str) + let line = s:ReplaceRightMostDelim(a:toReplace2, a:replacor2, line) + return line +endfunction + +" Function: s:ReplaceLeftMostDelim(toReplace, replacor, str) {{{2 +" This function takes a string and a delimiter and replaces the left most +" occurrence of this delimiter in the string with a given string +" +" Args: +" -toReplace: the delimiter in str that is to be replaced +" -replacor: the string to replace toReplace with +" -str: the string that contains toReplace +function s:ReplaceLeftMostDelim(toReplace, replacor, str) + let toReplace = a:toReplace + let replacor = a:replacor + "get the left most occurrence of toReplace + let indxToReplace = s:FindDelimiterIndex(toReplace, a:str) + + "if there IS an occurrence of toReplace in str then replace it and return + "the resulting string + if indxToReplace != -1 + let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace)) + return line + endif + + return a:str +endfunction + +" Function: s:ReplaceRightMostDelim(toReplace, replacor, str) {{{2 +" This function takes a string and a delimiter and replaces the right most +" occurrence of this delimiter in the string with a given string +" +" Args: +" -toReplace: the delimiter in str that is to be replaced +" -replacor: the string to replace toReplace with +" -str: the string that contains toReplace +" +function s:ReplaceRightMostDelim(toReplace, replacor, str) + let toReplace = a:toReplace + let replacor = a:replacor + let lenToReplace = strlen(toReplace) + + "get the index of the last delim in str + let indxToReplace = s:LastIndexOfDelim(toReplace, a:str) + + "if there IS a delimiter in str, replace it and return the result + let line = a:str + if indxToReplace != -1 + let line = strpart(a:str, 0, indxToReplace) . replacor . strpart(a:str, indxToReplace+strlen(toReplace)) + endif + return line +endfunction + +"FUNCTION: s:RestoreScreenState() {{{2 +" +"Sets the screen state back to what it was when s:SaveScreenState was last +"called. +" +function s:RestoreScreenState() + if !exists("t:NERDComOldTopLine") || !exists("t:NERDComOldPos") + throw 'NERDCommenter exception: cannot restore screen' + endif + + call cursor(t:NERDComOldTopLine, 0) + normal! zt + call setpos(".", t:NERDComOldPos) +endfunction + +" Function: s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) {{{2 +" This function takes in 2 line numbers and returns the index of the right most +" char on all of these lines. +" Args: +" -countCommentedLines: 1 if lines that are commented are to be checked as +" well. 0 otherwise +" -countEmptyLines: 1 if empty lines are to be counted in the search +" -topline: the top line to be checked +" -bottomline: the bottom line to be checked +function s:RightMostIndx(countCommentedLines, countEmptyLines, topline, bottomline) + let rightMostIndx = -1 + + " go thru the block line by line updating rightMostIndx + let currentLine = a:topline + while currentLine <= a:bottomline + + " get the next line and see if it is commentable, otherwise it doesnt + " count + let theLine = getline(currentLine) + if a:countEmptyLines || theLine !~ '^[ \t]*$' + + if a:countCommentedLines || (!s:IsCommented(b:NERDLeft, b:NERDRight, theLine) && !s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, theLine)) + + " update rightMostIndx if need be + let theLine = s:ConvertLeadingTabsToSpaces(theLine) + let lineLen = strlen(theLine) + if lineLen > rightMostIndx + let rightMostIndx = lineLen + endif + endif + endif + + " move on to the next line + let currentLine = currentLine + 1 + endwhile + + return rightMostIndx +endfunction + +"FUNCTION: s:SaveScreenState() {{{2 +"Saves the current cursor position in the current buffer and the window +"scroll position +function s:SaveScreenState() + let t:NERDComOldPos = getpos(".") + let t:NERDComOldTopLine = line("w0") +endfunction + +" Function: s:SwapOutterMultiPartDelimsForPlaceHolders(line) {{{2 +" This function takes a line and swaps the outter most multi-part delims for +" place holders +" Args: +" -line: the line to swap the delims in +" +function s:SwapOutterMultiPartDelimsForPlaceHolders(line) + " find out if the line is commented using normal delims and/or + " alternate ones + let isCommented = s:IsCommented(b:NERDLeft, b:NERDRight, a:line) + let isCommentedAlt = s:IsCommented(b:NERDLeftAlt, b:NERDRightAlt, a:line) + + let line2 = a:line + + "if the line is commented and there is a right delimiter, replace + "the delims with place-holders + if isCommented && s:Multipart() + let line2 = s:ReplaceDelims(b:NERDLeft, b:NERDRight, g:NERDLPlace, g:NERDRPlace, a:line) + + "similarly if the line is commented with the alternative + "delimiters + elseif isCommentedAlt && s:AltMultipart() + let line2 = s:ReplaceDelims(b:NERDLeftAlt, b:NERDRightAlt, g:NERDLPlace, g:NERDRPlace, a:line) + endif + + return line2 +endfunction + +" Function: s:SwapOutterPlaceHoldersForMultiPartDelims(line) {{{2 +" This function takes a line and swaps the outtermost place holders for +" multi-part delims +" Args: +" -line: the line to swap the delims in +" +function s:SwapOutterPlaceHoldersForMultiPartDelims(line) + let left = '' + let right = '' + if s:Multipart() + let left = b:NERDLeft + let right = b:NERDRight + elseif s:AltMultipart() + let left = b:NERDLeftAlt + let right = b:NERDRightAlt + endif + + let line = s:ReplaceDelims(g:NERDLPlace, g:NERDRPlace, left, right, a:line) + return line +endfunction +" Function: s:TabbedCol(line, col) {{{2 +" Gets the col number for given line and existing col number. The new col +" number is the col number when all leading spaces are converted to tabs +" Args: +" -line:the line to get the rel col for +" -col: the abs col +function s:TabbedCol(line, col) + let lineTruncated = strpart(a:line, 0, a:col) + let lineSpacesToTabs = substitute(lineTruncated, s:TabSpace(), '\t', 'g') + return strlen(lineSpacesToTabs) +endfunction +"FUNCTION: s:TabSpace() {{{2 +"returns a string of spaces equal in length to &tabstop +function s:TabSpace() + let tabSpace = "" + let spacesPerTab = &tabstop + while spacesPerTab > 0 + let tabSpace = tabSpace . " " + let spacesPerTab = spacesPerTab - 1 + endwhile + return tabSpace +endfunction + +" Function: s:UnEsc(str, escChar) {{{2 +" This function removes all the escape chars from a string +" Args: +" -str: the string to remove esc chars from +" -escChar: the escape char to be removed +function s:UnEsc(str, escChar) + return substitute(a:str, a:escChar, "", "g") +endfunction + +" Function: s:UntabbedCol(line, col) {{{2 +" Takes a line and a col and returns the absolute column of col taking into +" account that a tab is worth 3 or 4 (or whatever) spaces. +" Args: +" -line:the line to get the abs col for +" -col: the col that doesnt take into account tabs +function s:UntabbedCol(line, col) + let lineTruncated = strpart(a:line, 0, a:col) + let lineTabsToSpaces = substitute(lineTruncated, '\t', s:TabSpace(), 'g') + return strlen(lineTabsToSpaces) +endfunction +" Section: Comment mapping setup {{{1 +" =========================================================================== + +" switch to/from alternative delimiters +nnoremap NERDCommenterAltDelims :call SwitchToAlternativeDelimiters(1) + +" comment out lines +nnoremap NERDCommenterComment :call NERDComment(0, "norm") +vnoremap NERDCommenterComment :call NERDComment(1, "norm") + +" toggle comments +nnoremap NERDCommenterToggle :call NERDComment(0, "toggle") +vnoremap NERDCommenterToggle :call NERDComment(1, "toggle") + +" minimal comments +nnoremap NERDCommenterMinimal :call NERDComment(0, "minimal") +vnoremap NERDCommenterMinimal :call NERDComment(1, "minimal") + +" sexy comments +nnoremap NERDCommenterSexy :call NERDComment(0, "sexy") +vnoremap NERDCommenterSexy :call NERDComment(1, "sexy") + +" invert comments +nnoremap NERDCommenterInvert :call NERDComment(0, "invert") +vnoremap NERDCommenterInvert :call NERDComment(1, "invert") + +" yank then comment +nmap NERDCommenterYank :call NERDComment(0, "yank") +vmap NERDCommenterYank :call NERDComment(1, "yank") + +" left aligned comments +nnoremap NERDCommenterAlignLeft :call NERDComment(0, "alignLeft") +vnoremap NERDCommenterAlignLeft :call NERDComment(1, "alignLeft") + +" left and right aligned comments +nnoremap NERDCommenterAlignBoth :call NERDComment(0, "alignBoth") +vnoremap NERDCommenterAlignBoth :call NERDComment(1, "alignBoth") + +" nested comments +nnoremap NERDCommenterNest :call NERDComment(0, "nested") +vnoremap NERDCommenterNest :call NERDComment(1, "nested") + +" uncomment +nnoremap NERDCommenterUncomment :call NERDComment(0, "uncomment") +vnoremap NERDCommenterUncomment :call NERDComment(1, "uncomment") + +" comment till the end of the line +nnoremap NERDCommenterToEOL :call NERDComment(0, "toEOL") + +" append comments +nmap NERDCommenterAppend :call NERDComment(0, "append") + +" insert comments +inoremap NERDCommenterInInsert :call NERDComment(0, "insert") + + +function! s:CreateMaps(target, combo) + if !hasmapto(a:target, 'n') + exec 'nmap ' . a:combo . ' ' . a:target + endif + + if !hasmapto(a:target, 'v') + exec 'vmap ' . a:combo . ' ' . a:target + endif +endfunction + +if g:NERDCreateDefaultMappings + call s:CreateMaps('NERDCommenterComment', ',cc') + call s:CreateMaps('NERDCommenterToggle', ',c') + call s:CreateMaps('NERDCommenterMinimal', ',cm') + call s:CreateMaps('NERDCommenterSexy', ',cs') + call s:CreateMaps('NERDCommenterInvert', ',ci') + call s:CreateMaps('NERDCommenterYank', ',cy') + call s:CreateMaps('NERDCommenterAlignLeft', ',cl') + call s:CreateMaps('NERDCommenterAlignBoth', ',cb') + call s:CreateMaps('NERDCommenterNest', ',cn') + call s:CreateMaps('NERDCommenterUncomment', ',cu') + call s:CreateMaps('NERDCommenterToEOL', ',c$') + call s:CreateMaps('NERDCommenterAppend', ',cA') + + if !hasmapto('NERDCommenterAltDelims', 'n') + nmap ,ca NERDCommenterAltDelims + endif +endif + + + +" Section: Menu item setup {{{1 +" =========================================================================== +"check if the user wants the menu to be displayed +if g:NERDMenuMode != 0 + + let menuRoot = "" + if g:NERDMenuMode == 1 + let menuRoot = 'comment' + elseif g:NERDMenuMode == 2 + let menuRoot = '&comment' + elseif g:NERDMenuMode == 3 + let menuRoot = '&Plugin.&comment' + endif + + function! s:CreateMenuItems(target, desc, root) + exec 'nmenu ' . a:root . '.' . a:desc . ' ' . a:target + exec 'vmenu ' . a:root . '.' . a:desc . ' ' . a:target + endfunction + call s:CreateMenuItems("NERDCommenterComment", 'Comment', menuRoot) + call s:CreateMenuItems("NERDCommenterToggle", 'Toggle', menuRoot) + call s:CreateMenuItems('NERDCommenterMinimal', 'Minimal', menuRoot) + call s:CreateMenuItems('NERDCommenterNest', 'Nested', menuRoot) + exec 'nmenu '. menuRoot .'.To\ EOL NERDCommenterToEOL' + call s:CreateMenuItems('NERDCommenterInvert', 'Invert', menuRoot) + call s:CreateMenuItems('NERDCommenterSexy', 'Sexy', menuRoot) + call s:CreateMenuItems('NERDCommenterYank', 'Yank\ then\ comment', menuRoot) + exec 'nmenu '. menuRoot .'.Append NERDCommenterAppend' + exec 'menu '. menuRoot .'.-Sep- :' + call s:CreateMenuItems('NERDCommenterAlignLeft', 'Left\ aligned', menuRoot) + call s:CreateMenuItems('NERDCommenterAlignBoth', 'Left\ and\ right\ aligned', menuRoot) + exec 'menu '. menuRoot .'.-Sep2- :' + call s:CreateMenuItems('NERDCommenterUncomment', 'Uncomment', menuRoot) + exec 'nmenu '. menuRoot .'.Switch\ Delimiters NERDCommenterAltDelims' + exec 'imenu '. menuRoot .'.Insert\ Comment\ Here NERDCommenterInInsert' + exec 'menu '. menuRoot .'.-Sep3- :' + exec 'menu '. menuRoot .'.Help :help NERDCommenterContents' +endif +" vim: set foldmethod=marker : diff --git a/vim/plugin/NERD_tree.vim b/vim/plugin/NERD_tree.vim new file mode 100644 index 0000000..709328f --- /dev/null +++ b/vim/plugin/NERD_tree.vim @@ -0,0 +1,3796 @@ +" ============================================================================ +" File: NERD_tree.vim +" Description: vim global plugin that provides a nice tree explorer +" Maintainer: Martin Grenfell +" Last Change: 27 Jan, 2009 +" License: This program is free software. It comes without any warranty, +" to the extent permitted by applicable law. You can redistribute +" it and/or modify it under the terms of the Do What The Fuck You +" Want To Public License, Version 2, as published by Sam Hocevar. +" See http://sam.zoy.org/wtfpl/COPYING for more details. +" +" ============================================================================ +let s:NERD_tree_version = '3.1.0' + +" SECTION: Script init stuff {{{1 +"============================================================ +if exists("loaded_nerd_tree") + finish +endif +if v:version < 700 + echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!" + finish +endif +let loaded_nerd_tree = 1 + +"for line continuation - i.e dont want C in &cpo +let s:old_cpo = &cpo +set cpo&vim + +"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", 0) +if !exists("g:NERDTreeIgnore") + let g:NERDTreeIgnore = ['\~$'] +endif +call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks') +call s:initVariable("g:NERDTreeHighlightCursorline", 1) +call s:initVariable("g:NERDTreeHijackNetrw", 1) +call s:initVariable("g:NERDTreeMouseMode", 1) +call s:initVariable("g:NERDTreeNotificationThreshold", 100) +call s:initVariable("g:NERDTreeQuitOnOpen", 0) +call s:initVariable("g:NERDTreeShowBookmarks", 0) +call s:initVariable("g:NERDTreeShowFiles", 1) +call s:initVariable("g:NERDTreeShowHidden", 0) +call s:initVariable("g:NERDTreeShowLineNumbers", 0) +call s:initVariable("g:NERDTreeSortDirs", 1) + +if !exists("g:NERDTreeSortOrder") + let g:NERDTreeSortOrder = ['\/$', '*', '\.swp$', '\.bak$', '\~$'] +else + "if there isnt a * in the sort sequence then add one + if count(g:NERDTreeSortOrder, '*') < 1 + call add(g:NERDTreeSortOrder, '*') + endif +endif + +"we need to use this number many times for sorting... so we calculate it only +"once here +let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*') + +call s:initVariable("g:NERDTreeStatusline", "%{b:NERDTreeRoot.path.strForOS(0)}") +call s:initVariable("g:NERDTreeWinPos", "left") +call s:initVariable("g:NERDTreeWinSize", 31) + +let s:running_windows = has("win16") || has("win32") || has("win64") + +"init the shell commands that will be used to copy nodes, and remove dir trees +" +"Note: the space after the command is important +if s:running_windows + call s:initVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ') +else + call s:initVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ') + call s:initVariable("g:NERDTreeCopyCmd", 'cp -r ') +endif + + +"SECTION: Init variable calls for key mappings {{{2 +call s:initVariable("g:NERDTreeMapActivateNode", "o") +call s:initVariable("g:NERDTreeMapChangeRoot", "C") +call s:initVariable("g:NERDTreeMapChdir", "cd") +call s:initVariable("g:NERDTreeMapCloseChildren", "X") +call s:initVariable("g:NERDTreeMapCloseDir", "x") +call s:initVariable("g:NERDTreeMapDeleteBookmark", "D") +call s:initVariable("g: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", "") +call s:initVariable("g:NERDTreeMapJumpParent", "p") +call s:initVariable("g:NERDTreeMapJumpPrevSibling", "") +call s:initVariable("g:NERDTreeMapJumpRoot", "P") +call s:initVariable("g:NERDTreeMapOpenExpl", "e") +call s:initVariable("g:NERDTreeMapOpenInTab", "t") +call s:initVariable("g:NERDTreeMapOpenInTabSilent", "T") +call s:initVariable("g:NERDTreeMapOpenRecursively", "O") +call s:initVariable("g:NERDTreeMapOpenSplit", "i") +call s:initVariable("g:NERDTreeMapOpenVSplit", "s") +call s:initVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode) +call s:initVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit) +call s:initVariable("g:NERDTreeMapPreviewVSplit", "g" . NERDTreeMapOpenVSplit) +call s:initVariable("g:NERDTreeMapQuit", "q") +call s:initVariable("g:NERDTreeMapRefresh", "r") +call s:initVariable("g:NERDTreeMapRefreshRoot", "R") +call s:initVariable("g:NERDTreeMapToggleBookmarks", "B") +call s:initVariable("g:NERDTreeMapToggleFiles", "F") +call s:initVariable("g:NERDTreeMapToggleFilters", "f") +call s:initVariable("g:NERDTreeMapToggleHidden", "I") +call s:initVariable("g:NERDTreeMapUpdir", "u") +call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U") + +"SECTION: Script level variable declaration{{{2 +let s:escape_chars = " \\`\|\"#%&,?()\*^<>" +let s:NERDTreeBufName = 'NERD_tree_' + +let s:tree_wid = 2 +let s:tree_markup_reg = '^[ `|]*[\-+~]' +let s:tree_up_dir_line = '.. (up a dir)' + +let s:os_slash = '/' +if s:running_windows + let s:os_slash = '\' +endif + +"the number to add to the nerd tree buffer name to make the buf name unique +let s:next_buffer_number = 1 + +" SECTION: Commands {{{1 +"============================================================ +"init the command that users start the nerd tree with +command! -n=? -complete=dir -bar NERDTree :call s:initNerdTree('') +command! -n=? -complete=dir -bar NERDTreeToggle :call s:toggle('') +command! -n=0 -bar NERDTreeClose :call s:closeTreeIfOpen() +command! -n=1 -complete=customlist,s:completeBookmarks -bar NERDTreeFromBookmark call s:initNerdTree('') +command! -n=0 -complete=customlist,s:completeNERDTreeMirrors -bar NERDTreeMirror call s:initNerdTreeMirror() +" SECTION: Auto commands {{{1 +"============================================================ +augroup NERDTree + "Save the cursor position whenever we close the nerd tree + exec "autocmd BufWinLeave *". s:NERDTreeBufName ." call saveScreenState()" + "cache bookmarks when vim loads + autocmd VimEnter * call s:Bookmark.CacheBookmarks(0) +augroup END + +if g:NERDTreeHijackNetrw + augroup NERDTreeHijackNetrw + autocmd VimEnter * silent! autocmd! FileExplorer + au BufEnter,VimEnter * call s:checkForBrowse(expand("")) + augroup END +endif + +"SECTION: Classes {{{1 +"============================================================ +"CLASS: Bookmark {{{2 +"============================================================ +let s:Bookmark = {} +" FUNCTION: Bookmark.AddBookmark(name, path) {{{3 +" Class method to add a new bookmark to the list, if a previous bookmark exists +" with the same name, just update the path for that bookmark +function! s:Bookmark.AddBookmark(name, path) + for i in s:Bookmark.Bookmarks() + if i.name ==# a:name + let i.path = a:path + return + endif + endfor + call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path)) + call s:Bookmark.Sort() +endfunction +" Function: Bookmark.Bookmarks() {{{3 +" Class method to get all bookmarks. Lazily initializes the bookmarks global +" variable +function! s:Bookmark.Bookmarks() + if !exists("g:NERDTreeBookmarks") + let g:NERDTreeBookmarks = [] + endif + return g:NERDTreeBookmarks +endfunction +" Function: Bookmark.BookmarkExistsFor(name) {{{3 +" class method that returns 1 if a bookmark with the given name is found, 0 +" otherwise +function! s:Bookmark.BookmarkExistsFor(name) + try + call s:Bookmark.BookmarkFor(a:name) + return 1 + catch /^NERDTree.BookmarkNotFoundError/ + return 0 + endtry +endfunction +" Function: Bookmark.BookmarkFor(name) {{{3 +" Class method to get the bookmark that has the given name. {} is return if no +" bookmark is found +function! s:Bookmark.BookmarkFor(name) + for i in s:Bookmark.Bookmarks() + if i.name ==# a:name + return i + endif + endfor + throw "NERDTree.BookmarkNotFoundError: no bookmark found for name: \"". a:name .'"' +endfunction +" Function: Bookmark.BookmarkNames() {{{3 +" Class method to return an array of all bookmark names +function! s:Bookmark.BookmarkNames() + let names = [] + for i in s:Bookmark.Bookmarks() + call add(names, i.name) + endfor + return names +endfunction +" FUNCTION: Bookmark.CacheBookmarks(silent) {{{3 +" Class method to read all bookmarks from the bookmarks file intialize +" bookmark objects for each one. +" +" Args: +" silent - dont echo an error msg if invalid bookmarks are found +function! s:Bookmark.CacheBookmarks(silent) + if filereadable(g:NERDTreeBookmarksFile) + let g:NERDTreeBookmarks = [] + let g:NERDTreeInvalidBookmarks = [] + let bookmarkStrings = readfile(g:NERDTreeBookmarksFile) + let invalidBookmarksFound = 0 + for i in bookmarkStrings + + "ignore blank lines + if i != '' + + let name = substitute(i, '^\(.\{-}\) .*$', '\1', '') + let path = substitute(i, '^.\{-} \(.*\)$', '\1', '') + + try + let bookmark = s:Bookmark.New(name, s:Path.New(path)) + call add(g:NERDTreeBookmarks, bookmark) + catch /^NERDTree.InvalidArgumentsError/ + call add(g:NERDTreeInvalidBookmarks, i) + let invalidBookmarksFound += 1 + endtry + endif + endfor + if invalidBookmarksFound + call s:Bookmark.Write() + if !a:silent + call s:echo(invalidBookmarksFound . " invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.") + endif + endif + call s:Bookmark.Sort() + endif +endfunction +" FUNCTION: Bookmark.compareTo(otherbookmark) {{{3 +" Compare these two bookmarks for sorting purposes +function! s:Bookmark.compareTo(otherbookmark) + return a:otherbookmark.name < self.name +endfunction +" FUNCTION: Bookmark.ClearAll() {{{3 +" Class method to delete all bookmarks. +function! s:Bookmark.ClearAll() + for i in s:Bookmark.Bookmarks() + call i.delete() + endfor + call s:Bookmark.Write() +endfunction +" FUNCTION: Bookmark.delete() {{{3 +" Delete this bookmark. If the node for this bookmark is under the current +" root, then recache bookmarks for its Path object +function! s:Bookmark.delete() + let node = {} + try + let node = self.getNode(1) + catch /^NERDTree.BookmarkedNodeNotFoundError/ + endtry + call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self)) + if !empty(node) + call node.path.cacheDisplayString() + endif + call s:Bookmark.Write() +endfunction +" FUNCTION: Bookmark.getNode(searchFromAbsoluteRoot) {{{3 +" Gets the treenode for this bookmark +" +" Args: +" searchFromAbsoluteRoot: specifies whether we should search from the current +" tree root, or the highest cached node +function! s:Bookmark.getNode(searchFromAbsoluteRoot) + let searchRoot = a:searchFromAbsoluteRoot ? s:TreeDirNode.AbsoluteTreeRoot() : b:NERDTreeRoot + let targetNode = searchRoot.findNode(self.path) + if empty(targetNode) + throw "NERDTree.BookmarkedNodeNotFoundError: no node was found for bookmark: " . self.name + endif + return targetNode +endfunction +" FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) {{{3 +" Class method that finds the bookmark with the given name and returns the +" treenode for it. +function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) + let bookmark = s:Bookmark.BookmarkFor(a:name) + return bookmark.getNode(a:searchFromAbsoluteRoot) +endfunction +" Function: Bookmark.InvalidBookmarks() {{{3 +" Class method to get all invalid bookmark strings read from the bookmarks +" file +function! s:Bookmark.InvalidBookmarks() + if !exists("g:NERDTreeInvalidBookmarks") + let g:NERDTreeInvalidBookmarks = [] + endif + return g:NERDTreeInvalidBookmarks +endfunction +" FUNCTION: Bookmark.mustExist() {{{3 +function! s:Bookmark.mustExist() + if !self.path.exists() + call s:Bookmark.CacheBookmarks(1) + throw "NERDTree.BookmarkPointsToInvalidLocationError: the bookmark \"". + \ self.name ."\" points to a non existing location: \"". self.path.strForOS(0) + endif +endfunction +" FUNCTION: Bookmark.New(name, path) {{{3 +" Create a new bookmark object with the given name and path object +function! s:Bookmark.New(name, path) + if a:name =~ ' ' + throw "NERDTree.IllegalBookmarkNameError: illegal name:" . a:name + endif + + let newBookmark = copy(self) + let newBookmark.name = a:name + let newBookmark.path = a:path + return newBookmark +endfunction +" Function: Bookmark.setPath(path) {{{3 +" makes this bookmark point to the given path +function! s:Bookmark.setPath(path) + let self.path = a:path +endfunction +" Function: Bookmark.Sort() {{{3 +" Class method that sorts all bookmarks +function! s:Bookmark.Sort() + let CompareFunc = function("s:compareBookmarks") + call sort(s:Bookmark.Bookmarks(), CompareFunc) +endfunction +" Function: Bookmark.str() {{{3 +" Get the string that should be rendered in the view for this bookmark +function! s:Bookmark.str() + let pathStrMaxLen = winwidth(s:getTreeWinNum()) - 4 - len(self.name) + if &nu + let pathStrMaxLen = pathStrMaxLen - &numberwidth + endif + + let pathStr = self.path.strForOS(0) + if len(pathStr) > pathStrMaxLen + let pathStr = '<' . strpart(pathStr, len(pathStr) - pathStrMaxLen) + endif + return '>' . self.name . ' ' . pathStr +endfunction +" FUNCTION: Bookmark.toRoot() {{{3 +" Make the node for this bookmark the new tree root +function! s:Bookmark.toRoot() + if self.validate() + try + let targetNode = self.getNode(1) + catch /^NERDTree.BookmarkedNodeNotFoundError/ + let targetNode = s:TreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path) + endtry + call targetNode.makeRoot() + call s:renderView() + call targetNode.putCursorHere(0, 0) + endif +endfunction +" FUNCTION: Bookmark.ToRoot(name) {{{3 +" Make the node for this bookmark the new tree root +function! s:Bookmark.ToRoot(name) + let bookmark = s:Bookmark.BookmarkFor(a:name) + call bookmark.toRoot() +endfunction + + +"FUNCTION: Bookmark.validate() {{{3 +function! s:Bookmark.validate() + if self.path.exists() + return 1 + else + call s:Bookmark.CacheBookmarks(1) + call s:renderView() + call s:echo(self.name . "now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.") + return 0 + endif +endfunction + +" Function: Bookmark.Write() {{{3 +" Class method to write all bookmarks to the bookmarks file +function! s:Bookmark.Write() + let bookmarkStrings = [] + for i in s:Bookmark.Bookmarks() + call add(bookmarkStrings, i.name . ' ' . i.path.strForOS(0)) + endfor + + "add a blank line before the invalid ones + call add(bookmarkStrings, "") + + for j in s:Bookmark.InvalidBookmarks() + call add(bookmarkStrings, j) + endfor + call writefile(bookmarkStrings, g:NERDTreeBookmarksFile) +endfunction +"CLASS: TreeFileNode {{{2 +"This class is the parent of the TreeDirNode class and constitures the +"'Component' part of the composite design pattern between the treenode +"classes. +"============================================================ +let s:TreeFileNode = {} +"FUNCTION: TreeFileNode.bookmark(name) {{{3 +"bookmark this node with a:name +function! s:TreeFileNode.bookmark(name) + try + let oldMarkedNode = s:Bookmark.GetNodeForName(a:name, 1) + call oldMarkedNode.path.cacheDisplayString() + catch /^NERDTree.BookmarkNotFoundError/ + endtry + + call s:Bookmark.AddBookmark(a:name, self.path) + call self.path.cacheDisplayString() + call s:Bookmark.Write() +endfunction +"FUNCTION: TreeFileNode.cacheParent() {{{3 +"initializes self.parent if it isnt already +function! s:TreeFileNode.cacheParent() + if empty(self.parent) + let parentPath = self.path.getParent() + if parentPath.equals(self.path) + throw "NERDTree.CannotCacheParentError: already at root" + endif + let self.parent = s:TreeFileNode.New(parentPath) + endif +endfunction +"FUNCTION: TreeFileNode.compareNodes {{{3 +"This is supposed to be a class level method but i cant figure out how to +"get func refs to work from a dict.. +" +"A class level method that compares two nodes +" +"Args: +"n1, n2: the 2 nodes to compare +function! s:compareNodes(n1, n2) + return a:n1.path.compareTo(a:n2.path) +endfunction + +"FUNCTION: TreeFileNode.clearBoomarks() {{{3 +function! s:TreeFileNode.clearBoomarks() + for i in s:Bookmark.Bookmarks() + if i.path.equals(self.path) + call i.delete() + end + endfor + call self.path.cacheDisplayString() +endfunction +"FUNCTION: TreeFileNode.copy(dest) {{{3 +function! s:TreeFileNode.copy(dest) + call self.path.copy(a:dest) + let newPath = s:Path.New(a:dest) + let parent = b:NERDTreeRoot.findNode(newPath.getParent()) + if !empty(parent) + call parent.refresh() + endif + return parent.findNode(newPath) +endfunction + +"FUNCTION: TreeFileNode.delete {{{3 +"Removes this node from the tree and calls the Delete method for its path obj +function! s:TreeFileNode.delete() + call self.path.delete() + call self.parent.removeChild(self) +endfunction + +"FUNCTION: TreeFileNode.renderToString {{{3 +"returns a string representation for this tree to be rendered in the view +function! s:TreeFileNode.renderToString() + return self._renderToString(0, 0, [], self.getChildCount() ==# 1) +endfunction + + +"Args: +"depth: the current depth in the tree for this call +"drawText: 1 if we should actually draw the line for this node (if 0 then the +"child nodes are rendered only) +"vertMap: a binary array that indicates whether a vertical bar should be draw +"for each depth in the tree +"isLastChild:true if this curNode is the last child of its parent +function! s:TreeFileNode._renderToString(depth, drawText, vertMap, isLastChild) + let output = "" + if a:drawText ==# 1 + + let treeParts = '' + + "get all the leading spaces and vertical tree parts for this line + if a:depth > 1 + for j in a:vertMap[0:-2] + if j ==# 1 + let treeParts = treeParts . '| ' + else + let treeParts = treeParts . ' ' + 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 . '`' + else + let treeParts = treeParts . '|' + endif + + + "smack the appropriate dir/file symbol on the line before the file/dir + "name itself + if self.path.isDirectory + if self.isOpen + let treeParts = treeParts . '~' + else + let treeParts = treeParts . '+' + endif + else + let treeParts = treeParts . '-' + endif + let line = treeParts . self.strDisplay() + + let output = output . line . "\n" + endif + + "if the node is an open dir, draw its children + if self.path.isDirectory ==# 1 && self.isOpen ==# 1 + + let childNodesToDraw = self.getVisibleChildren() + if len(childNodesToDraw) > 0 + + "draw all the nodes children except the last + let lastIndx = len(childNodesToDraw)-1 + if lastIndx > 0 + for i in childNodesToDraw[0:lastIndx-1] + let output = output . i._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 1), 0) + endfor + endif + + "draw the last child, indicating that it IS the last + let output = output . childNodesToDraw[lastIndx]._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 0), 1) + endif + endif + + return output +endfunction +"FUNCTION: TreeFileNode.equals(treenode) {{{3 +" +"Compares this treenode to the input treenode and returns 1 if they are the +"same node. +" +"Use this method instead of == because sometimes when the treenodes contain +"many children, vim seg faults when doing == +" +"Args: +"treenode: the other treenode to compare to +function! s:TreeFileNode.equals(treenode) + return self.path.str(1) ==# a:treenode.path.str(1) +endfunction + +"FUNCTION: TreeFileNode.findNode(path) {{{3 +"Returns self if this node.path.Equals the given path. +"Returns {} if not equal. +" +"Args: +"path: the path object to compare against +function! s:TreeFileNode.findNode(path) + if a:path.equals(self.path) + return self + endif + return {} +endfunction +"FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{3 +" +"Finds the next sibling for this node in the indicated direction. This sibling +"must be a directory and may/may not have children as specified. +" +"Args: +"direction: 0 if you want to find the previous sibling, 1 for the next sibling +" +"Return: +"a treenode object or {} if no appropriate sibling could be found +function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) + "if we have no parent then we can have no siblings + if self.parent != {} + let nextSibling = self.findSibling(a:direction) + + while nextSibling != {} + if nextSibling.path.isDirectory && nextSibling.hasVisibleChildren() && nextSibling.isOpen + return nextSibling + endif + let nextSibling = nextSibling.findSibling(a:direction) + endwhile + endif + + return {} +endfunction +"FUNCTION: TreeFileNode.findSibling(direction) {{{3 +" +"Finds the next sibling for this node in the indicated direction +" +"Args: +"direction: 0 if you want to find the previous sibling, 1 for the next sibling +" +"Return: +"a treenode object or {} if no sibling could be found +function! s:TreeFileNode.findSibling(direction) + "if we have no parent then we can have no siblings + if self.parent != {} + + "get the index of this node in its parents children + let siblingIndx = self.parent.getChildIndex(self.path) + + if siblingIndx != -1 + "move a long to the next potential sibling node + let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 + + "keep moving along to the next sibling till we find one that is valid + let numSiblings = self.parent.getChildCount() + while siblingIndx >= 0 && siblingIndx < numSiblings + + "if the next node is not an ignored node (i.e. wont show up in the + "view) then return it + if self.parent.children[siblingIndx].path.ignore() ==# 0 + return self.parent.children[siblingIndx] + endif + + "go to next node + let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1 + endwhile + endif + endif + + return {} +endfunction + +"FUNCTION: TreeFileNode.getLineNum(){{{3 +"returns the line number this node is rendered on, or -1 if it isnt rendered +function! s:TreeFileNode.getLineNum() + "if the node is the root then return the root line no. + if self.isRoot() + return s:TreeFileNode.GetRootLineNum() + endif + + let totalLines = line("$") + + "the path components we have matched so far + let pathcomponents = [substitute(b:NERDTreeRoot.path.str(0), '/ *$', '', '')] + "the index of the component we are searching for + let curPathComponent = 1 + + let fullpath = self.path.str(0) + + + let lnum = s:TreeFileNode.GetRootLineNum() + while lnum > 0 + let lnum = lnum + 1 + "have we reached the bottom of the tree? + if lnum ==# totalLines+1 + return -1 + endif + + let curLine = getline(lnum) + + let indent = s:indentLevelFor(curLine) + if indent ==# curPathComponent + let curLine = s:stripMarkupFromLine(curLine, 1) + + let curPath = join(pathcomponents, '/') . '/' . curLine + if stridx(fullpath, curPath, 0) ==# 0 + if fullpath ==# curPath || strpart(fullpath, len(curPath)-1,1) ==# '/' + let curLine = substitute(curLine, '/ *$', '', '') + call add(pathcomponents, curLine) + let curPathComponent = curPathComponent + 1 + + if fullpath ==# curPath + return lnum + endif + endif + endif + endif + endwhile + return -1 +endfunction + +"FUNCTION: TreeFileNode.GetRootLineNum(){{{3 +"gets the line number of the root node +function! s:TreeFileNode.GetRootLineNum() + let rootLine = 1 + while getline(rootLine) !~ '^/' + let rootLine = rootLine + 1 + endwhile + return rootLine +endfunction + +"FUNCTION: TreeFileNode.GetSelected() {{{3 +"gets the treenode that the cursor is currently over +function! s:TreeFileNode.GetSelected() + try + let path = s:getPath(line(".")) + if path ==# {} + return {} + endif + return b:NERDTreeRoot.findNode(path) + catch /NERDTree/ + return {} + endtry +endfunction +"FUNCTION: TreeFileNode.isVisible() {{{3 +"returns 1 if this node should be visible according to the tree filters and +"hidden file filters (and their on/off status) +function! s:TreeFileNode.isVisible() + return !self.path.ignore() +endfunction +"FUNCTION: TreeFileNode.isRoot() {{{3 +"returns 1 if this node is b:NERDTreeRoot +function! s:TreeFileNode.isRoot() + if !s:treeExistsForBuf() + throw "NERDTree.NoTreeError: No tree exists for the current buffer" + endif + + return self.equals(b:NERDTreeRoot) +endfunction + +"FUNCTION: TreeFileNode.makeRoot() {{{3 +"Make this node the root of the tree +function! s:TreeFileNode.makeRoot() + if self.path.isDirectory + let b:NERDTreeRoot = self + else + call self.cacheParent() + let b:NERDTreeRoot = self.parent + endif + + call b:NERDTreeRoot.open() + + "change dir to the dir of the new root if instructed to + if g:NERDTreeChDirMode ==# 2 + exec "cd " . b:NERDTreeRoot.path.strForEditCmd() + endif +endfunction +"FUNCTION: TreeFileNode.New(path) {{{3 +"Returns a new TreeNode object with the given path and parent +" +"Args: +"path: a path object representing the full filesystem path to the file/dir that the node represents +function! s:TreeFileNode.New(path) + if a:path.isDirectory + return s:TreeDirNode.New(a:path) + else + let newTreeNode = {} + let newTreeNode = copy(self) + let newTreeNode.path = a:path + let newTreeNode.parent = {} + return newTreeNode + endif +endfunction + +"FUNCTION: TreeFileNode.open() {{{3 +"Open the file represented by the given node in the current window, splitting +"the window if needed +" +"ARGS: +"treenode: file node to open +function! s:TreeFileNode.open() + if b:NERDTreeType ==# "secondary" + exec 'edit ' . self.path.strForEditCmd() + return + endif + + "if the file is already open in this tab then just stick the cursor in it + let winnr = bufwinnr('^' . self.path.strForOS(0) . '$') + if winnr != -1 + call s:exec(winnr . "wincmd w") + + else + if !s:isWindowUsable(winnr("#")) && s:firstNormalWindow() ==# -1 + call self.openSplit() + else + try + if !s:isWindowUsable(winnr("#")) + call s:exec(s:firstNormalWindow() . "wincmd w") + else + call s:exec('wincmd p') + endif + exec ("edit " . self.path.strForEditCmd()) + catch /^Vim\%((\a\+)\)\=:E37/ + call s:putCursorInTreeWin() + throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str(0) ." is already open and modified." + catch /^Vim\%((\a\+)\)\=:/ + echo v:exception + endtry + endif + endif +endfunction +"FUNCTION: TreeFileNode.openSplit() {{{3 +"Open this node in a new window +function! s:TreeFileNode.openSplit() + + if b:NERDTreeType ==# "secondary" + exec "split " . self.path.strForEditCmd() + return + endif + + " Save the user's settings for splitbelow and splitright + let savesplitbelow=&splitbelow + let savesplitright=&splitright + + " 'there' will be set to a command to move from the split window + " back to the explorer window + " + " 'back' will be set to a command to move from the explorer window + " back to the newly split window + " + " 'right' and 'below' will be set to the settings needed for + " splitbelow and splitright IF the explorer is the only window. + " + let there= g:NERDTreeWinPos ==# "left" ? "wincmd h" : "wincmd l" + let back = g:NERDTreeWinPos ==# "left" ? "wincmd l" : "wincmd h" + let right= g:NERDTreeWinPos ==# "left" + let below=0 + + " Attempt to go to adjacent window + call s:exec(back) + + let onlyOneWin = (winnr("$") ==# 1) + + " If no adjacent window, set splitright and splitbelow appropriately + if onlyOneWin + let &splitright=right + let &splitbelow=below + else + " found adjacent window - invert split direction + let &splitright=!right + let &splitbelow=!below + endif + + let splitMode = onlyOneWin ? "vertical" : "" + + " Open the new window + try + exec(splitMode." sp " . self.path.strForEditCmd()) + catch /^Vim\%((\a\+)\)\=:E37/ + call s:putCursorInTreeWin() + throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self.path.str(0) ." is already open and modified." + catch /^Vim\%((\a\+)\)\=:/ + "do nothing + endtry + + "resize the tree window if no other window was open before + if onlyOneWin + let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize + call s:exec(there) + exec("silent ". splitMode ." resize ". size) + call s:exec('wincmd p') + endif + + " Restore splitmode settings + let &splitbelow=savesplitbelow + let &splitright=savesplitright +endfunction +"FUNCTION: TreeFileNode.openVSplit() {{{3 +"Open this node in a new vertical window +function! s:TreeFileNode.openVSplit() + if b:NERDTreeType ==# "secondary" + exec "vnew " . self.path.strForEditCmd() + return + endif + + let winwidth = winwidth(".") + if winnr("$")==#1 + let winwidth = g:NERDTreeWinSize + endif + + call s:exec("wincmd p") + exec "vnew " . self.path.strForEditCmd() + + "resize the nerd tree back to the original size + call s:putCursorInTreeWin() + exec("silent vertical resize ". winwidth) + call s:exec('wincmd p') +endfunction +"FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{3 +"Places the cursor on the line number this node is rendered on +" +"Args: +"isJump: 1 if this cursor movement should be counted as a jump by vim +"recurseUpward: try to put the cursor on the parent if the this node isnt +"visible +function! s:TreeFileNode.putCursorHere(isJump, recurseUpward) + let ln = self.getLineNum() + if ln != -1 + if a:isJump + mark ' + endif + call cursor(ln, col(".")) + else + if a:recurseUpward + let node = self + while node != {} && node.getLineNum() ==# -1 + let node = node.parent + call node.open() + endwhile + call s:renderView() + call node.putCursorHere(a:isJump, 0) + endif + endif +endfunction + +"FUNCTION: TreeFileNode.refresh() {{{3 +function! s:TreeFileNode.refresh() + call self.path.refresh() +endfunction +"FUNCTION: TreeFileNode.rename() {{{3 +"Calls the rename method for this nodes path obj +function! s:TreeFileNode.rename(newName) + let newName = substitute(a:newName, '\(\\\|\/\)$', '', '') + call self.path.rename(newName) + call self.parent.removeChild(self) + + let parentPath = self.path.getPathTrunk() + let newParent = b:NERDTreeRoot.findNode(parentPath) + + if newParent != {} + call newParent.createChild(self.path, 1) + call newParent.refresh() + endif +endfunction +"FUNCTION: TreeFileNode.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:TreeFileNode.strDisplay() + return self.path.strDisplay() +endfunction + +"CLASS: TreeDirNode {{{2 +"This class is a child of the TreeFileNode class and constitutes the +"'Composite' part of the composite design pattern between the treenode +"classes. +"============================================================ +let s:TreeDirNode = copy(s:TreeFileNode) +"FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{3 +"class method that returns the highest cached ancestor of the current root +function! s:TreeDirNode.AbsoluteTreeRoot() + let currentNode = b:NERDTreeRoot + while currentNode.parent != {} + let currentNode = currentNode.parent + endwhile + return currentNode +endfunction +"FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{3 +"Adds the given treenode to the list of children for this node +" +"Args: +"-treenode: the node to add +"-inOrder: 1 if the new node should be inserted in sorted order +function! s:TreeDirNode.addChild(treenode, inOrder) + call add(self.children, a:treenode) + let a:treenode.parent = self + + if a:inOrder + call self.sortChildren() + endif +endfunction + +"FUNCTION: TreeDirNode.close() {{{3 +"Closes this directory +function! s:TreeDirNode.close() + let self.isOpen = 0 +endfunction + +"FUNCTION: TreeDirNode.closeChildren() {{{3 +"Closes all the child dir nodes of this node +function! s:TreeDirNode.closeChildren() + for i in self.children + if i.path.isDirectory + call i.close() + call i.closeChildren() + endif + endfor +endfunction + +"FUNCTION: TreeDirNode.createChild(path, inOrder) {{{3 +"Instantiates a new child node for this node with the given path. The new +"nodes parent is set to this node. +" +"Args: +"path: a Path object that this node will represent/contain +"inOrder: 1 if the new node should be inserted in sorted order +" +"Returns: +"the newly created node +function! s:TreeDirNode.createChild(path, inOrder) + let newTreeNode = s:TreeFileNode.New(a:path) + call self.addChild(newTreeNode, a:inOrder) + return newTreeNode +endfunction + +"FUNCTION: TreeDirNode.findNode(path) {{{3 +"Will find one of the children (recursively) that has the given path +" +"Args: +"path: a path object +unlet s:TreeDirNode.findNode +function! s:TreeDirNode.findNode(path) + if a:path.equals(self.path) + return self + endif + if stridx(a:path.str(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: TreeDirNode.getChildCount() {{{3 +"Returns the number of children this node has +function! s:TreeDirNode.getChildCount() + return len(self.children) +endfunction + +"FUNCTION: TreeDirNode.getChild(path) {{{3 +"Returns child node of this node that has the given path or {} if no such node +"exists. +" +"This function doesnt not recurse into child dir nodes +" +"Args: +"path: a path object +function! s:TreeDirNode.getChild(path) + if stridx(a:path.str(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: TreeDirNode.getChildByIndex(indx, visible) {{{3 +"returns the child at the given index +"Args: +"indx: the index to get the child from +"visible: 1 if only the visible children array should be used, 0 if all the +"children should be searched. +function! s:TreeDirNode.getChildByIndex(indx, visible) + let array_to_search = a:visible? self.getVisibleChildren() : self.children + if a:indx > len(array_to_search) + throw "NERDTree.InvalidArgumentsError: Index is out of bounds." + endif + return array_to_search[a:indx] +endfunction + +"FUNCTION: TreeDirNode.getChildIndex(path) {{{3 +"Returns the index of the child node of this node that has the given path or +"-1 if no such node exists. +" +"This function doesnt not recurse into child dir nodes +" +"Args: +"path: a path object +function! s:TreeDirNode.getChildIndex(path) + if stridx(a:path.str(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: TreeDirNode.GetSelected() {{{3 +"Returns the current node if it is a dir node, or else returns the current +"nodes parent +unlet s:TreeDirNode.GetSelected +function! s:TreeDirNode.GetSelected() + let currentDir = s:TreeFileNode.GetSelected() + if currentDir != {} && !currentDir.isRoot() + if currentDir.path.isDirectory ==# 0 + let currentDir = currentDir.parent + endif + endif + return currentDir +endfunction +"FUNCTION: TreeDirNode.getVisibleChildCount() {{{3 +"Returns the number of visible children this node has +function! s:TreeDirNode.getVisibleChildCount() + return len(self.getVisibleChildren()) +endfunction + +"FUNCTION: TreeDirNode.getVisibleChildren() {{{3 +"Returns a list of children to display for this node, in the correct order +" +"Return: +"an array of treenodes +function! s:TreeDirNode.getVisibleChildren() + let toReturn = [] + for i in self.children + if i.path.ignore() ==# 0 + call add(toReturn, i) + endif + endfor + return toReturn +endfunction + +"FUNCTION: TreeDirNode.hasVisibleChildren() {{{3 +"returns 1 if this node has any childre, 0 otherwise.. +function! s:TreeDirNode.hasVisibleChildren() + return self.getVisibleChildCount() != 0 +endfunction + +"FUNCTION: TreeDirNode._initChildren() {{{3 +"Removes all childen from this node and re-reads them +" +"Args: +"silent: 1 if the function should not echo any "please wait" messages for +"large directories +" +"Return: the number of child nodes read +function! s:TreeDirNode._initChildren(silent) + "remove all the current child nodes + let self.children = [] + + "get an array of all the files in the nodes dir + let dir = self.path + let filesStr = globpath(dir.strForGlob(), '*') . "\n" . globpath(dir.strForGlob(), '.*') + let files = split(filesStr, "\n") + + if !a:silent && len(files) > g:NERDTreeNotificationThreshold + call s:echo("Please wait, caching a large dir ...") + endif + + let invalidFilesFound = 0 + for i in files + + "filter out the .. and . directories + "Note: we must match .. AND ../ cos sometimes the globpath returns + "../ for path with strange chars (eg $) + if i !~ '\.\.\/\?$' && i !~ '\.\/\?$' + + "put the next file in a new node and attach it + try + let path = s:Path.New(i) + call self.createChild(path, 0) + catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/ + let invalidFilesFound += 1 + endtry + endif + endfor + + call self.sortChildren() + + if !a:silent && len(files) > g:NERDTreeNotificationThreshold + call s:echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).") + endif + + if invalidFilesFound + call s:echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree") + endif + return self.getChildCount() +endfunction +"FUNCTION: TreeDirNode.New(path) {{{3 +"Returns a new TreeNode object with the given path and parent +" +"Args: +"path: a path object representing the full filesystem path to the file/dir that the node represents +unlet s:TreeDirNode.New +function! s:TreeDirNode.New(path) + if a:path.isDirectory != 1 + throw "NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object." + endif + + let newTreeNode = copy(self) + let newTreeNode.path = a:path + + let newTreeNode.isOpen = 0 + let newTreeNode.children = [] + + let newTreeNode.parent = {} + + return newTreeNode +endfunction +"FUNCTION: TreeDirNode.open() {{{3 +"Reads in all this nodes children +" +"Return: the number of child nodes read +unlet s:TreeDirNode.open +function! s:TreeDirNode.open() + let self.isOpen = 1 + if self.children ==# [] + return self._initChildren(0) + else + return 0 + endif +endfunction + +" FUNCTION: TreeDirNode.openExplorer() {{{3 +" opens an explorer window for this node in the previous window (could be a +" nerd tree or a netrw) +function! s:TreeDirNode.openExplorer() + let oldwin = winnr() + call s:exec('wincmd p') + if oldwin ==# winnr() || (&modified && s:bufInWindows(winbufnr(winnr())) < 2) + call s:exec('wincmd p') + call self.openSplit() + else + exec ("silent edit " . self.path.strForEditCmd()) + endif +endfunction +"FUNCTION: TreeDirNode.openRecursively() {{{3 +"Opens this treenode and all of its children whose paths arent 'ignored' +"because of the file filters. +" +"This method is actually a wrapper for the OpenRecursively2 method which does +"the work. +function! s:TreeDirNode.openRecursively() + call self._openRecursively2(1) +endfunction + +"FUNCTION: TreeDirNode._openRecursively2() {{{3 +"Opens this all children of this treenode recursively if either: +" *they arent filtered by file filters +" *a:forceOpen is 1 +" +"Args: +"forceOpen: 1 if this node should be opened regardless of file filters +function! s:TreeDirNode._openRecursively2(forceOpen) + if self.path.ignore() ==# 0 || a:forceOpen + let self.isOpen = 1 + if self.children ==# [] + call self._initChildren(1) + endif + + for i in self.children + if i.path.isDirectory ==# 1 + call i._openRecursively2(0) + endif + endfor + endif +endfunction + +"FUNCTION: TreeDirNode.refresh() {{{3 +unlet s:TreeDirNode.refresh +function! s:TreeDirNode.refresh() + call self.path.refresh() + + "if this node was ever opened, refresh its children + if self.isOpen || !empty(self.children) + "go thru all the files/dirs under this node + let newChildNodes = [] + let invalidFilesFound = 0 + let dir = self.path + let filesStr = globpath(dir.strForGlob(), '*') . "\n" . globpath(dir.strForGlob(), '.*') + 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:Path.New(i) + let newNode = self.getChild(path) + if newNode != {} + call newNode.refresh() + call add(newChildNodes, newNode) + + "the node doesnt exist so create it + else + let newNode = s:TreeFileNode.New(path) + let newNode.parent = self + call add(newChildNodes, newNode) + endif + + + catch /^NERDTree.InvalidArgumentsError/ + let invalidFilesFound = 1 + endtry + endif + endfor + + "swap this nodes children out for the children we just read/refreshed + let self.children = newChildNodes + call self.sortChildren() + + if invalidFilesFound + call s:echoWarning("some files could not be loaded into the NERD tree") + endif + endif +endfunction + +"FUNCTION: TreeDirNode.removeChild(treenode) {{{3 +" +"Removes the given treenode from this nodes set of children +" +"Args: +"treenode: the node to remove +" +"Throws a NERDTree.ChildNotFoundError if the given treenode is not found +function! s:TreeDirNode.removeChild(treenode) + for i in range(0, self.getChildCount()-1) + if self.children[i].equals(a:treenode) + call remove(self.children, i) + return + endif + endfor + + throw "NERDTree.ChildNotFoundError: child node was not found" +endfunction + +"FUNCTION: TreeDirNode.sortChildren() {{{3 +" +"Sorts the children of this node according to alphabetical order and the +"directory priority. +" +function! s:TreeDirNode.sortChildren() + let CompareFunc = function("s:compareNodes") + call sort(self.children, CompareFunc) +endfunction + +"FUNCTION: TreeDirNode.toggleOpen() {{{3 +"Opens this directory if it is closed and vice versa +function! s:TreeDirNode.toggleOpen() + if self.isOpen ==# 1 + call self.close() + else + call self.open() + endif +endfunction + +"FUNCTION: TreeDirNode.transplantChild(newNode) {{{3 +"Replaces the child of this with the given node (where the child node's full +"path matches a:newNode's fullpath). The search for the matching node is +"non-recursive +" +"Arg: +"newNode: the node to graft into the tree +function! s:TreeDirNode.transplantChild(newNode) + for i in range(0, self.getChildCount()-1) + if self.children[i].equals(a:newNode) + let self.children[i] = a:newNode + let a:newNode.parent = self + break + endif + endfor +endfunction +"============================================================ +"CLASS: Path {{{2 +"============================================================ +let s:Path = {} +"FUNCTION: Path.AbsolutePathFor(str) {{{3 +function! s:Path.AbsolutePathFor(str) + let prependCWD = 0 + if s:running_windows + let prependCWD = a:str !~ '^.:\(\\\|\/\)' + else + let prependCWD = a:str !~ '^/' + endif + + let toReturn = a:str + if prependCWD + let toReturn = getcwd() . s:os_slash . a:str + endif + + return toReturn +endfunction +"FUNCTION: Path.bookmarkNames() {{{3 +function! s:Path.bookmarkNames() + if !exists("self._bookmarkNames") + call self.cacheDisplayString() + endif + return self._bookmarkNames +endfunction +"FUNCTION: Path.cacheDisplayString() {{{3 +function! s:Path.cacheDisplayString() + let self.cachedDisplayString = self.getLastPathComponent(1) + + if self.isExecutable + let self.cachedDisplayString = self.cachedDisplayString . '*' + endif + + let self._bookmarkNames = [] + for i in s:Bookmark.Bookmarks() + if i.path.equals(self) + call add(self._bookmarkNames, i.name) + endif + endfor + if !empty(self._bookmarkNames) + let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}' + endif + + if self.isSymLink + let self.cachedDisplayString .= ' -> ' . self.symLinkDest + endif + + if self.isReadOnly + let self.cachedDisplayString .= ' [RO]' + endif +endfunction +"FUNCTION: Path.changeToDir() {{{3 +function! s:Path.changeToDir() + let dir = self.strForCd() + if self.isDirectory ==# 0 + let dir = self.getPathTrunk().strForCd() + endif + + try + execute "cd " . dir + call s:echo("CWD is now: " . getcwd()) + catch + throw "NERDTree.PathChangeError: cannot change CWD to " . dir + endtry +endfunction + +"FUNCTION: Path.compareTo() {{{3 +" +"Compares this Path to the given path and returns 0 if they are equal, -1 if +"this Path is "less than" the given path, or 1 if it is "greater". +" +"Args: +"path: the path object to compare this to +" +"Return: +"1, -1 or 0 +function! s:Path.compareTo(path) + let thisPath = self.getLastPathComponent(1) + let thatPath = a:path.getLastPathComponent(1) + + "if the paths are the same then clearly we return 0 + if thisPath ==# thatPath + return 0 + endif + + let thisSS = self.getSortOrderIndex() + let thatSS = a:path.getSortOrderIndex() + + "compare the sort sequences, if they are different then the return + "value is easy + if thisSS < thatSS + return -1 + elseif thisSS > thatSS + return 1 + else + "if the sort sequences are the same then compare the paths + "alphabetically + let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath >> +"FUNCTION: s:checkForBrowse(dir) {{{2 +"inits a secondary nerd tree in the current buffer if appropriate +function! s:checkForBrowse(dir) + if a:dir != '' && isdirectory(a:dir) + call s:initNerdTreeInPlace(a:dir) + endif +endfunction +"FUNCTION: s:compareBookmarks(first, second) {{{2 +"Compares two bookmarks +function! s:compareBookmarks(first, second) + return a:first.compareTo(a:second) +endfunction + +" FUNCTION: s:completeBookmarks(A,L,P) {{{2 +" completion function for the bookmark commands +function! s:completeBookmarks(A,L,P) + return filter(s:Bookmark.BookmarkNames(), 'v:val =~ "^' . a:A . '"') +endfunction +" FUNCTION: s:exec(cmd) {{{2 +" same as :exec cmd but eventignore=all is set for the duration +function! s:exec(cmd) + let old_ei = &ei + set ei=all + exec a:cmd + let &ei = old_ei +endfunction +"FUNCTION: s:initNerdTree(name) {{{2 +"Initialise the nerd tree for this tab. The tree will start in either the +"given directory, or the directory associated with the given bookmark +" +"Args: +"name: the name of a bookmark or a directory +function! s:initNerdTree(name) + let path = {} + if s:Bookmark.BookmarkExistsFor(a:name) + let path = s:Bookmark.BookmarkFor(a:name).path + else + let dir = a:name ==# '' ? getcwd() : a:name + + "hack to get an absolute path if a relative path is given + if dir =~ '^\.' + let dir = getcwd() . s:os_slash . dir + endif + let dir = resolve(dir) + + try + let path = s:Path.New(dir) + catch /^NERDTree.InvalidArgumentsError/ + call s:echo("No bookmark or directory found for: " . a:name) + return + endtry + endif + if !path.isDirectory + let path = path.getParent() + endif + + "if instructed to, then change the vim CWD to the dir the NERDTree is + "inited in + if g:NERDTreeChDirMode != 0 + exec 'cd ' . path.strForCd() + endif + + if s:treeExistsForTab() + if s:isTreeOpen() + call s:closeTree() + endif + unlet t:NERDTreeBufName + endif + + let newRoot = s:TreeDirNode.New(path) + call newRoot.open() + + call s:createTreeWin() + let b:treeShowHelp = 0 + let b:NERDTreeIgnoreEnabled = 1 + let b:NERDTreeShowFiles = g:NERDTreeShowFiles + let b:NERDTreeShowHidden = g:NERDTreeShowHidden + let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks + let b:NERDTreeRoot = newRoot + + let b:NERDTreeType = "primary" + + call s:renderView() + call b:NERDTreeRoot.putCursorHere(0, 0) +endfunction + +"FUNCTION: s:initNerdTreeInPlace(dir) {{{2 +function! s:initNerdTreeInPlace(dir) + try + let path = s:Path.New(a:dir) + catch /^NERDTree.InvalidArgumentsError/ + call s:echo("Invalid directory name:" . a:name) + return + endtry + + "we want the directory buffer to disappear when we do the :edit below + setlocal bufhidden=wipe + + let previousBuf = expand("#") + + "we need a unique name for each secondary tree buffer to ensure they are + "all independent + exec "silent edit " . s:nextBufferName() + + let b:NERDTreePreviousBuf = bufnr(previousBuf) + + let b:NERDTreeRoot = s:TreeDirNode.New(path) + call b:NERDTreeRoot.open() + + "throwaway buffer options + setlocal noswapfile + setlocal buftype=nofile + setlocal bufhidden=hide + setlocal nowrap + setlocal foldcolumn=0 + setlocal nobuflisted + setlocal nospell + if g:NERDTreeShowLineNumbers + setlocal nu + else + setlocal nonu + endif + + iabc + + if g:NERDTreeHighlightCursorline + setlocal cursorline + endif + + call s:setupStatusline() + + let b:treeShowHelp = 0 + let b:NERDTreeIgnoreEnabled = 1 + let b:NERDTreeShowFiles = g:NERDTreeShowFiles + let b:NERDTreeShowHidden = g:NERDTreeShowHidden + let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks + + let b:NERDTreeType = "secondary" + + call s:bindMappings() + setfiletype nerdtree + " syntax highlighting + if has("syntax") && exists("g:syntax_on") && !has("syntax_items") + call s:setupSyntaxHighlighting() + endif + + call s:renderView() +endfunction +" FUNCTION: s:initNerdTreeMirror() {{{2 +function! s:initNerdTreeMirror() + + "get the names off all the nerd tree buffers + let treeBufNames = [] + for i in range(1, tabpagenr("$")) + let nextName = s:tabpagevar(i, 'NERDTreeBufName') + if nextName != -1 && (!exists("t:NERDTreeBufName") || nextName != t:NERDTreeBufName) + call add(treeBufNames, nextName) + endif + endfor + let treeBufNames = s:unique(treeBufNames) + + "map the option names (that the user will be prompted with) to the nerd + "tree buffer names + let options = {} + let i = 0 + while i < len(treeBufNames) + let bufName = treeBufNames[i] + let treeRoot = getbufvar(bufName, "NERDTreeRoot") + let options[i+1 . '. ' . treeRoot.path.strForOS(0) . ' (buf name: ' . bufName . ')'] = bufName + let i = i + 1 + endwhile + + "work out which tree to mirror, if there is more than 1 then ask the user + let bufferName = '' + if len(keys(options)) > 1 + let choices = ["Choose a tree to mirror"] + let choices = extend(choices, sort(keys(options))) + let choice = inputlist(choices) + if choice < 1 || choice > len(options) || choice ==# '' + return + endif + + let bufferName = options[keys(options)[choice-1]] + elseif len(keys(options)) ==# 1 + let bufferName = values(options)[0] + else + call s:echo("No trees to mirror") + return + endif + + if s:treeExistsForTab() && s:isTreeOpen() + call s:closeTree() + endif + + let t:NERDTreeBufName = bufferName + call s:createTreeWin() + exec 'buffer ' . bufferName + if !&hidden + call s:renderView() + endif +endfunction +" FUNCTION: s:nextBufferName() {{{2 +" returns the buffer name for the next nerd tree +function! s:nextBufferName() + let name = s:NERDTreeBufName . s:next_buffer_number + let s:next_buffer_number += 1 + return name +endfunction +" FUNCTION: s:tabpagevar(tabnr, var) {{{2 +function! s:tabpagevar(tabnr, var) + let currentTab = tabpagenr() + let old_ei = &ei + set ei=all + + exec "tabnext " . a:tabnr + let v = -1 + if exists('t:' . a:var) + exec 'let v = t:' . a:var + endif + exec "tabnext " . currentTab + + let &ei = old_ei + + return v +endfunction +" Function: s:treeExistsForBuffer() {{{2 +" Returns 1 if a nerd tree root exists in the current buffer +function! s:treeExistsForBuf() + return exists("b:NERDTreeRoot") +endfunction +" Function: s:treeExistsForTab() {{{2 +" Returns 1 if a nerd tree root exists in the current tab +function! s:treeExistsForTab() + return exists("t:NERDTreeBufName") +endfunction +" Function: s:unique(list) {{{2 +" returns a:list without duplicates +function! s:unique(list) + let uniqlist = [] + for elem in a:list + if index(uniqlist, elem) ==# -1 + let uniqlist += [elem] + endif + endfor + return uniqlist +endfunction +" SECTION: Public 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.NoTreeForTabError: 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:TreeFileNode.GetSelected() + + if winnr != winnr() + call s:exec('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.NoTreeFoundError: no NERDTree is open" + endif + + if winnr("$") != 1 + call s:exec(s:getTreeWinNum() . " wincmd w") + close + call s:exec("wincmd p") + else + :q + endif +endfunction + +"FUNCTION: s:closeTreeIfOpen() {{{2 +"Closes the NERD tree window if it is open +function! s:closeTreeIfOpen() + if s:isTreeOpen() + call s:closeTree() + endif +endfunction +"FUNCTION: s:closeTreeIfQuitOnOpen() {{{2 +"Closes the NERD tree window if the close on open option is set +function! s:closeTreeIfQuitOnOpen() + if g:NERDTreeQuitOnOpen + call s:closeTree() + endif +endfunction +"FUNCTION: s:createTreeWin() {{{2 +"Inits the NERD tree window. ie. opens it, sizes it, sets all the local +"options etc +function! s:createTreeWin() + "create the nerd tree window + let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright " + let splitSize = g:NERDTreeWinSize + silent! exec splitLocation . 'vertical ' . splitSize . ' new' + + if !exists('t:NERDTreeBufName') + let t:NERDTreeBufName = s:nextBufferName() + silent! exec "edit " . t:NERDTreeBufName + else + silent! exec "buffer " . t:NERDTreeBufName + endif + + setlocal winfixwidth + + "throwaway buffer options + setlocal noswapfile + setlocal buftype=nofile + setlocal nowrap + setlocal foldcolumn=0 + setlocal nobuflisted + setlocal nospell + if g:NERDTreeShowLineNumbers + setlocal nu + else + setlocal nonu + endif + + iabc + + if g:NERDTreeHighlightCursorline + setlocal cursorline + endif + + call s:setupStatusline() + + call s:bindMappings() + setfiletype nerdtree + " syntax highlighting + if has("syntax") && exists("g:syntax_on") && !has("syntax_items") + call s:setupSyntaxHighlighting() + endif +endfunction + +"FUNCTION: s:dumpHelp {{{2 +"prints out the quick help +function! s:dumpHelp() + let old_h = @h + if b:treeShowHelp ==# 1 + let @h= "\" NERD tree (" . s:NERD_tree_version . ") quickhelp~\n" + let @h=@h."\" ============================\n" + let @h=@h."\" File node mappings~\n" + let @h=@h."\" ". (g:NERDTreeMouseMode ==# 3 ? "single" : "double") ."-click,\n" + if b:NERDTreeType ==# "primary" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in prev window\n" + else + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open in current window\n" + endif + if b:NERDTreeType ==# "primary" + let @h=@h."\" ". g:NERDTreeMapPreview .": preview\n" + endif + let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let @h=@h."\" middle-click,\n" + let @h=@h."\" ". g:NERDTreeMapOpenSplit .": open split\n" + let @h=@h."\" ". g:NERDTreeMapPreviewSplit .": preview split\n" + let @h=@h."\" ". g:NERDTreeMapOpenVSplit .": open vsplit\n" + let @h=@h."\" ". g:NERDTreeMapPreviewVSplit .": preview vsplit\n" + let @h=@h."\" ". 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.": explore selected dir\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Bookmark table mappings~\n" + let @h=@h."\" double-click,\n" + let @h=@h."\" ". g:NERDTreeMapActivateNode .": open bookmark\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTab.": open in new tab\n" + let @h=@h."\" ". g:NERDTreeMapOpenInTabSilent .": open in new tab silently\n" + let @h=@h."\" ". g:NERDTreeMapDeleteBookmark .": delete bookmark\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Tree navigation mappings~\n" + let @h=@h."\" ". g:NERDTreeMapJumpRoot .": go to root\n" + let @h=@h."\" ". g:NERDTreeMapJumpParent .": go to parent\n" + let @h=@h."\" ". g:NERDTreeMapJumpFirstChild .": go to first child\n" + let @h=@h."\" ". g:NERDTreeMapJumpLastChild .": go to last child\n" + let @h=@h."\" ". g:NERDTreeMapJumpNextSibling .": go to next sibling\n" + let @h=@h."\" ". g:NERDTreeMapJumpPrevSibling .": go to prev sibling\n" + + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Filesystem mappings~\n" + let @h=@h."\" ". g:NERDTreeMapChangeRoot .": change tree root to the\n" + let @h=@h."\" selected dir\n" + let @h=@h."\" ". g:NERDTreeMapUpdir .": move tree root up a dir\n" + let @h=@h."\" ". g:NERDTreeMapUpdirKeepOpen .": move tree root up a dir\n" + let @h=@h."\" but leave old root open\n" + let @h=@h."\" ". g:NERDTreeMapRefresh .": refresh cursor dir\n" + let @h=@h."\" ". g:NERDTreeMapRefreshRoot .": refresh current root\n" + let @h=@h."\" ". g: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 (" . (b:NERDTreeShowHidden ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleFilters .": file filters (" . (b:NERDTreeIgnoreEnabled ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleFiles .": files (" . (b:NERDTreeShowFiles ? "on" : "off") . ")\n" + let @h=@h."\" ". g:NERDTreeMapToggleBookmarks .": bookmarks (" . (b:NERDTreeShowBookmarks ? "on" : "off") . ")\n" + + 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" + let @h=@h."\"\n\" ----------------------------\n" + let @h=@h."\" Bookmark commands~\n" + let @h=@h."\" :Bookmark \n" + let @h=@h."\" :BookmarkToRoot \n" + let @h=@h."\" :RevealBookmark \n" + let @h=@h."\" :OpenBookmark \n" + let @h=@h."\" :ClearBookmarks []\n" + let @h=@h."\" :ClearAllBookmarks\n" + 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 + echomsg "NERDTree: " . a:msg +endfunction +"FUNCTION: s:echoWarning {{{2 +"Wrapper for s:echo, sets the message type to warningmsg for this message +"Args: +"msg: the message to echo +function! s:echoWarning(msg) + echohl warningmsg + call s:echo(a:msg) + echohl normal +endfunction +"FUNCTION: s:echoError {{{2 +"Wrapper for s:echo, sets the message type to errormsg for this message +"Args: +"msg: the message to echo +function! s:echoError(msg) + echohl errormsg + call s:echo(a:msg) + echohl normal +endfunction +"FUNCTION: s:firstNormalWindow(){{{2 +"find the window number of the first normal window +function! s:firstNormalWindow() + let i = 1 + while i <= winnr("$") + let bnum = winbufnr(i) + if bnum != -1 && getbufvar(bnum, '&buftype') ==# '' + \ && !getwinvar(i, '&previewwindow') + return i + endif + + let i += 1 + endwhile + return -1 +endfunction +"FUNCTION: s:getPath(ln) {{{2 +"Gets the full path to the node that is rendered on the given line number +" +"Args: +"ln: the line number to get the path for +" +"Return: +"A path if a node was selected, {} if nothing is selected. +"If the 'up a dir' line was selected then the path to the parent of the +"current root is returned +function! s:getPath(ln) + let line = getline(a:ln) + + "check to see if we have the root node + if line =~ '^\/' + return b:NERDTreeRoot.path + endif + + " in case called from outside the tree + if line !~ '^ *[|`]' || line =~ '^$' + return {} + endif + + if line ==# s:tree_up_dir_line + return b:NERDTreeRoot.path.getParent() + endif + + let indent = s:indentLevelFor(line) + + "remove the tree parts and the leading space + let curFile = s:stripMarkupFromLine(line, 0) + + let wasdir = 0 + if curFile =~ '/$' + let wasdir = 1 + let curFile = substitute(curFile, '/\?$', '/', "") + endif + + + let dir = "" + let lnum = a:ln + while lnum > 0 + let lnum = lnum - 1 + let curLine = getline(lnum) + let curLineStripped = s:stripMarkupFromLine(curLine, 1) + + "have we reached the top of the tree? + if curLine =~ '^/' + let dir = substitute (curLine, ' *$', "", "") . dir + break + endif + if curLineStripped =~ '/$' + let lpindent = s:indentLevelFor(curLine) + if lpindent < indent + let indent = indent - 1 + + let dir = substitute (curLineStripped,'^\\', "", "") . dir + continue + endif + endif + endwhile + let curFile = b:NERDTreeRoot.path.drive . dir . curFile + let toReturn = s:Path.New(curFile) + return toReturn +endfunction + +"FUNCTION: s:getSelectedBookmark() {{{2 +"returns the bookmark the cursor is over in the bookmarks table or {} +function! s:getSelectedBookmark() + let line = getline(".") + let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '') + if name != line + try + return s:Bookmark.BookmarkFor(name) + catch /^NERDTree.BookmarkNotFoundError/ + return {} + endtry + endif + return {} +endfunction + +"FUNCTION: s:getTreeWinNum() {{{2 +"gets the nerd tree window number for this tab +function! s:getTreeWinNum() + if exists("t:NERDTreeBufName") + return bufwinnr(t:NERDTreeBufName) + else + return -1 + endif +endfunction +"FUNCTION: s:indentLevelFor(line) {{{2 +function! s:indentLevelFor(line) + return match(a:line, '[^ \-+~`|]') / s:tree_wid +endfunction +"FUNCTION: s:isTreeOpen() {{{2 +function! s:isTreeOpen() + return s:getTreeWinNum() != -1 +endfunction +"FUNCTION: s:isWindowUsable(winnumber) {{{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:isWindowUsable(winnumber) + "gotta split if theres only one window (i.e. the NERD tree) + if winnr("$") ==# 1 + return 0 + endif + + let oldwinnr = winnr() + call s:exec(a:winnumber . "wincmd p") + let specialWindow = getbufvar("%", '&buftype') != '' || getwinvar('%', '&previewwindow') + let modified = &modified + call s:exec(oldwinnr . "wincmd p") + + "if its a special window e.g. quickfix or another explorer plugin then we + "have to split + if specialWindow + return 0 + endif + + if &hidden + return 1 + endif + + return !modified || s:bufInWindows(winbufnr(a:winnumber)) >= 2 +endfunction + +" FUNCTION: s:jumpToChild(direction) {{{2 +" Args: +" direction: 0 if going to first child, 1 if going to last +function! s:jumpToChild(direction) + let currentNode = s:TreeFileNode.GetSelected() + if currentNode ==# {} || currentNode.isRoot() + call s:echo("cannot jump to " . (a:direction ? "last" : "first") . " child") + return + end + let dirNode = currentNode.parent + let childNodes = dirNode.getVisibleChildren() + + let targetNode = childNodes[0] + if a:direction + let targetNode = childNodes[len(childNodes) - 1] + endif + + if targetNode.equals(currentNode) + let siblingDir = currentNode.parent.findOpenDirSiblingWithVisibleChildren(a:direction) + if siblingDir != {} + let indx = a:direction ? siblingDir.getVisibleChildCount()-1 : 0 + let targetNode = siblingDir.getChildByIndex(indx, 1) + endif + endif + + call targetNode.putCursorHere(1, 0) + + call s:centerView() +endfunction + + +"FUNCTION: s:promptToDelBuffer(bufnum, msg){{{2 +"prints out the given msg and, if the user responds by pushing 'y' then the +"buffer with the given bufnum is deleted +" +"Args: +"bufnum: the buffer that may be deleted +"msg: a message that will be echoed to the user asking them if they wish to +" del the buffer +function! s:promptToDelBuffer(bufnum, msg) + echo a:msg + if nr2char(getchar()) ==# 'y' + exec "silent bdelete! " . a:bufnum + endif +endfunction + +"FUNCTION: s:putCursorOnBookmarkTable(){{{2 +"Places the cursor at the top of the bookmarks table +function! s:putCursorOnBookmarkTable() + if !b:NERDTreeShowBookmarks + throw "NERDTree.IllegalOperationError: cant find bookmark table, bookmarks arent active" + endif + + let rootNodeLine = s:TreeFileNode.GetRootLineNum() + + let line = 1 + while getline(line) !~ '^>-\+Bookmarks-\+$' + let line = line + 1 + if line >= rootNodeLine + throw "NERDTree.BookmarkTableNotFoundError: didnt find the bookmarks table" + endif + endwhile + call cursor(line, 0) +endfunction + +"FUNCTION: s:putCursorInTreeWin(){{{2 +"Places the cursor in the nerd tree window +function! s:putCursorInTreeWin() + if !s:isTreeOpen() + throw "NERDTree.InvalidOperationError: cant put cursor in NERD tree window, no window exists" + endif + + call s:exec(s:getTreeWinNum() . "wincmd w") +endfunction + +"FUNCTION: s:renderBookmarks {{{2 +function! s:renderBookmarks() + + call setline(line(".")+1, ">----------Bookmarks----------") + call cursor(line(".")+1, col(".")) + + for i in s:Bookmark.Bookmarks() + call setline(line(".")+1, i.str()) + call cursor(line(".")+1, col(".")) + endfor + + call setline(line(".")+1, '') + call cursor(line(".")+1, col(".")) +endfunction +"FUNCTION: s:renderView {{{2 +"The entry function for rendering the tree +function! s:renderView() + setlocal modifiable + + "remember the top line of the buffer and the current line so we can + "restore the view exactly how it was + let curLine = line(".") + let curCol = col(".") + let topLine = line("w0") + + "delete all lines in the buffer (being careful not to clobber a register) + silent 1,$delete _ + + call s:dumpHelp() + + "delete the blank line before the help and add one after it + call setline(line(".")+1, "") + call cursor(line(".")+1, col(".")) + + if b:NERDTreeShowBookmarks + call s:renderBookmarks() + endif + + "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, b:NERDTreeRoot.path.str(0)) + call cursor(line(".")+1, col(".")) + + "draw the tree + let old_o = @o + let @o = b:NERDTreeRoot.renderToString() + silent put o + let @o = old_o + + "delete the blank line at the top of the buffer + silent 1,1delete _ + + "restore the view + let old_scrolloff=&scrolloff + let &scrolloff=0 + call cursor(topLine, 1) + normal! zt + call cursor(curLine, curCol) + let &scrolloff = old_scrolloff + + setlocal nomodifiable +endfunction + +"FUNCTION: s:renderViewSavingPosition {{{2 +"Renders the tree and ensures the cursor stays on the current node or the +"current nodes parent if it is no longer available upon re-rendering +function! s:renderViewSavingPosition() + let currentNode = s:TreeFileNode.GetSelected() + + "go up the tree till we find a node that will be visible or till we run + "out of nodes + while currentNode != {} && !currentNode.isVisible() && !currentNode.isRoot() + let currentNode = currentNode.parent + endwhile + + call s:renderView() + + if currentNode != {} + call currentNode.putCursorHere(0, 0) + endif +endfunction +"FUNCTION: s:restoreScreenState() {{{2 +" +"Sets the screen state back to what it was when s:saveScreenState was last +"called. +" +"Assumes the cursor is in the NERDTree window +function! s:restoreScreenState() + if !exists("b:NERDTreeOldTopLine") || !exists("b:NERDTreeOldPos") || !exists("b:NERDTreeOldWindowSize") + return + endif + exec("silent vertical resize ".b:NERDTreeOldWindowSize) + + let old_scrolloff=&scrolloff + let &scrolloff=0 + call cursor(b:NERDTreeOldTopLine, 0) + normal! zt + call setpos(".", b:NERDTreeOldPos) + let &scrolloff=old_scrolloff +endfunction + +"FUNCTION: s:saveScreenState() {{{2 +"Saves the current cursor position in the current buffer and the window +"scroll position +function! s:saveScreenState() + let win = winnr() + try + call s:putCursorInTreeWin() + let b:NERDTreeOldPos = getpos(".") + let b:NERDTreeOldTopLine = line("w0") + let b:NERDTreeOldWindowSize = winwidth("") + call s:exec(win . "wincmd w") + catch /^NERDTree.InvalidOperationError/ + endtry +endfunction + +"FUNCTION: s:setupStatusline() {{{2 +function! s:setupStatusline() + if g:NERDTreeStatusline != -1 + let &l:statusline = g:NERDTreeStatusline + endif +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 treeHelpCommand #" :.\{-}\>#hs=s+3 + syn match treeHelp #^".*# contains=treeHelpKey,treeHelpTitle,treeFlag,treeToggleOff,treeToggleOn,treeHelpCommand + + "highlighting for readonly files + syn match treeRO #.*\[RO\]#hs=s+2 contains=treeFlag,treeBookmark,treePart,treePartFile + + "highlighting for sym links + syn match treeLink #[^-| `].* -> # contains=treeBookmark,treeOpenable,treeClosable,treeDirSlash + + "highlighing for directory nodes and file nodes + syn match treeDirSlash #/# + syn match treeDir #[^-| `].*/# contains=treeLink,treeDirSlash,treeOpenable,treeClosable + syn match treeExecFile #[|`]-.*\*\($\| \)# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark + syn match treeFile #|-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark,treeExecFile + syn match treeFile #`-.*# contains=treeLink,treePart,treeRO,treePartFile,treeBookmark,treeExecFile + syn match treeCWD #^/.*$# + + "highlighting for bookmarks + syn match treeBookmark # {.*}#hs=s+1 + + "highlighting for the bookmarks table + syn match treeBookmarksLeader #^># + syn match treeBookmarksHeader #^>-\+Bookmarks-\+$# contains=treeBookmarksLeader + syn match treeBookmarkName #^>.\{-} #he=e-1 contains=treeBookmarksLeader + syn match treeBookmark #^>.*$# contains=treeBookmarksLeader,treeBookmarkName,treeBookmarksHeader + + if g:NERDChristmasTree + hi def link treePart Special + hi def link treePartFile Type + hi def link treeFile Normal + hi def link treeExecFile Title + 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 treeBookmarksHeader statement + hi def link treeBookmarksLeader ignore + hi def link treeBookmarkName Identifier + hi def link treeBookmark normal + + hi def link treeHelp String + hi def link treeHelpKey Identifier + hi def link treeHelpCommand 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 Macro + hi def link treeOpenable Title + hi def link treeFlag ignore + hi def link treeRO WarningMsg + hi def link treeBookmark Statement + + hi def link NERDTreeCurrentNode Search +endfunction + +"FUNCTION: s:stripMarkupFromLine(line, removeLeadingSpaces){{{2 +"returns the given line with all the tree parts stripped off +" +"Args: +"line: the subject line +"removeLeadingSpaces: 1 if leading spaces are to be removed (leading spaces = +"any spaces before the actual text of the node) +function! s:stripMarkupFromLine(line, removeLeadingSpaces) + let line = a:line + "remove the tree parts and the leading space + let line = substitute (line, s:tree_markup_reg,"","") + + "strip off any read only flag + let line = substitute (line, ' \[RO\]', "","") + + "strip off any bookmark flags + let line = substitute (line, ' {[^}]*}', "","") + + "strip off any executable flags + let line = substitute (line, '*\ze\($\| \)', "","") + + let wasdir = 0 + if line =~ '/$' + let wasdir = 1 + endif + let line = substitute (line,' -> .*',"","") " remove link to + if wasdir ==# 1 + let line = substitute (line, '/\?$', '/', "") + endif + + if a:removeLeadingSpaces + let line = substitute (line, '^ *', '', '') + endif + + return line +endfunction + +"FUNCTION: s:toggle(dir) {{{2 +"Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is +"closed it is restored or initialized (if it doesnt exist) +" +"Args: +"dir: the full path for the root node (is only used if the NERD tree is being +"initialized. +function! s:toggle(dir) + if s:treeExistsForTab() + if !s:isTreeOpen() + call s:createTreeWin() + call s:restoreScreenState() + if !&hidden + call s:renderView() + endif + else + call s:closeTree() + endif + else + call s:initNerdTree(a:dir) + endif +endfunction +"SECTION: Interface bindings {{{1 +"============================================================ +"FUNCTION: s:activateNode(forceKeepWindowOpen) {{{2 +"If the current node is a file, open it in the previous window (or a new one +"if the previous is modified). If it is a directory then it is opened. +" +"args: +"forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set +function! s:activateNode(forceKeepWindowOpen) + if getline(".") ==# s:tree_up_dir_line + return s:upDir(0) + endif + + let treenode = s:TreeFileNode.GetSelected() + if treenode != {} + if treenode.path.isDirectory + call treenode.toggleOpen() + call s:renderView() + call treenode.putCursorHere(0, 0) + else + call treenode.open() + if !a:forceKeepWindowOpen + call s:closeTreeIfQuitOnOpen() + end + endif + else + let bookmark = s:getSelectedBookmark() + if !empty(bookmark) + if bookmark.path.isDirectory + call bookmark.toRoot() + else + if bookmark.validate() + call (s:TreeFileNode.New(bookmark.path)).open() + endif + endif + endif + endif +endfunction + +"FUNCTION: s:bindMappings() {{{2 +function! s:bindMappings() + " set up mappings and commands for this buffer + nnoremap :call handleMiddleMouse() + nnoremap :call checkForActivate() + nnoremap <2-leftmouse> :call activateNode(0) + + exec "nnoremap ". g:NERDTreeMapActivateNode . " :call activateNode(0)" + exec "nnoremap ". g:NERDTreeMapOpenSplit ." :call openEntrySplit(0,0)" + + exec "nnoremap ". g:NERDTreeMapPreview ." :call previewNode(0)" + exec "nnoremap ". g:NERDTreeMapPreviewSplit ." :call previewNode(1)" + + exec "nnoremap ". g:NERDTreeMapOpenVSplit ." :call openEntrySplit(1,0)" + exec "nnoremap ". g:NERDTreeMapPreviewVSplit ." :call previewNode(2)" + + exec "nnoremap ". g:NERDTreeMapExecute ." :call executeNode()" + + exec "nnoremap ". g:NERDTreeMapOpenRecursively ." :call openNodeRecursively()" + + exec "nnoremap ". g:NERDTreeMapUpdirKeepOpen ." :call upDir(1)" + exec "nnoremap ". g:NERDTreeMapUpdir ." :call upDir(0)" + exec "nnoremap ". g:NERDTreeMapChangeRoot ." :call chRoot()" + + exec "nnoremap ". g:NERDTreeMapChdir ." :call chCwd()" + + exec "nnoremap ". g:NERDTreeMapQuit ." :call closeTreeWindow()" + + exec "nnoremap ". g:NERDTreeMapRefreshRoot ." :call refreshRoot()" + exec "nnoremap ". g:NERDTreeMapRefresh ." :call refreshCurrent()" + + exec "nnoremap ". g:NERDTreeMapHelp ." :call displayHelp()" + exec "nnoremap ". g:NERDTreeMapToggleHidden ." :call toggleShowHidden()" + exec "nnoremap ". g:NERDTreeMapToggleFilters ." :call toggleIgnoreFilter()" + exec "nnoremap ". g:NERDTreeMapToggleFiles ." :call toggleShowFiles()" + exec "nnoremap ". g:NERDTreeMapToggleBookmarks ." :call toggleShowBookmarks()" + + exec "nnoremap ". g:NERDTreeMapCloseDir ." :call closeCurrentDir()" + exec "nnoremap ". g:NERDTreeMapCloseChildren ." :call closeChildren()" + + exec "nnoremap ". g:NERDTreeMapFilesystemMenu ." :call showFileSystemMenu()" + + exec "nnoremap ". g:NERDTreeMapJumpParent ." :call jumpToParent()" + exec "nnoremap ". g:NERDTreeMapJumpNextSibling ." :call jumpToSibling(1)" + exec "nnoremap ". g:NERDTreeMapJumpPrevSibling ." :call jumpToSibling(0)" + exec "nnoremap ". g:NERDTreeMapJumpFirstChild ." :call jumpToFirstChild()" + exec "nnoremap ". g:NERDTreeMapJumpLastChild ." :call jumpToLastChild()" + exec "nnoremap ". g:NERDTreeMapJumpRoot ." :call jumpToRoot()" + + exec "nnoremap ". g:NERDTreeMapOpenInTab ." :call openInNewTab(0)" + exec "nnoremap ". g:NERDTreeMapOpenInTabSilent ." :call openInNewTab(1)" + + exec "nnoremap ". g:NERDTreeMapOpenExpl ." :call openExplorer()" + + exec "nnoremap ". g:NERDTreeMapDeleteBookmark ." :call deleteBookmark()" + + command! -buffer -nargs=1 Bookmark :call bookmarkNode('') + command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 RevealBookmark :call revealBookmark('') + command! -buffer -complete=customlist,s:completeBookmarks -nargs=1 OpenBookmark :call openBookmark('') + command! -buffer -complete=customlist,s:completeBookmarks -nargs=* ClearBookmarks call clearBookmarks('') + command! -buffer -complete=customlist,s:completeBookmarks -nargs=+ BookmarkToRoot call s:Bookmark.ToRoot('') + command! -buffer -nargs=0 ClearAllBookmarks call s:Bookmark.ClearAll() call renderView() + command! -buffer -nargs=0 ReadBookmarks call s:Bookmark.CacheBookmarks(0) call renderView() + command! -buffer -nargs=0 WriteBookmarks call s:Bookmark.Write() +endfunction + +" FUNCTION: s:bookmarkNode(name) {{{2 +" Associate the current node with the given name +function! s:bookmarkNode(name) + let currentNode = s:TreeFileNode.GetSelected() + if currentNode != {} + try + call currentNode.bookmark(a:name) + call s:renderView() + catch /^NERDTree.IllegalBookmarkNameError/ + call s:echo("bookmark names must not contain spaces") + endtry + else + call s:echo("select a node first") + endif +endfunction +"FUNCTION: s:checkForActivate() {{{2 +"Checks if the click should open the current node, if so then activate() is +"called (directories are automatically opened if the symbol beside them is +"clicked) +function! s:checkForActivate() + let currentNode = s:TreeFileNode.GetSelected() + if currentNode != {} + let startToCur = strpart(getline(line(".")), 0, col(".")) + 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 + if startToCur =~ s:tree_markup_reg . '$' && char =~ '[+~]' + call s:activateNode(0) + return + endif + endif + + if (g:NERDTreeMouseMode ==# 2 && currentNode.path.isDirectory) || g:NERDTreeMouseMode ==# 3 + if char !~ s:tree_markup_reg && startToCur !~ '\/$' + call s:activateNode(0) + return + endif + endif + endif +endfunction + +" FUNCTION: s:chCwd() {{{2 +function! s:chCwd() + let treenode = s:TreeFileNode.GetSelected() + if treenode ==# {} + call s:echo("Select a node first") + return + endif + + try + call treenode.path.changeToDir() + catch /^NERDTree.PathChangeError/ + call s:echoWarning("could not change cwd") + endtry +endfunction + +" FUNCTION: s:chRoot() {{{2 +" changes the current root to the selected one +function! s:chRoot() + let treenode = s:TreeFileNode.GetSelected() + if treenode ==# {} + call s:echo("Select a node first") + return + endif + + call treenode.makeRoot() + call s:renderView() + call b:NERDTreeRoot.putCursorHere(0, 0) +endfunction + +" FUNCTION: s:clearBookmarks(bookmarks) {{{2 +function! s:clearBookmarks(bookmarks) + if a:bookmarks ==# '' + let currentNode = s:TreeFileNode.GetSelected() + if currentNode != {} + call currentNode.clearBoomarks() + endif + else + for name in split(a:bookmarks, ' ') + let bookmark = s:Bookmark.BookmarkFor(name) + call bookmark.delete() + endfor + endif + call s:renderView() +endfunction +" FUNCTION: s:closeChildren() {{{2 +" closes all childnodes of the current node +function! s:closeChildren() + let currentNode = s:TreeDirNode.GetSelected() + if currentNode ==# {} + call s:echo("Select a node first") + return + endif + + call currentNode.closeChildren() + call s:renderView() + call currentNode.putCursorHere(0, 0) +endfunction +" FUNCTION: s:closeCurrentDir() {{{2 +" closes the parent dir of the current node +function! s:closeCurrentDir() + let treenode = s:TreeFileNode.GetSelected() + if treenode ==# {} + call s:echo("Select a node first") + return + endif + + let parent = treenode.parent + if parent.isRoot() + call s:echo("cannot close tree root") + else + call treenode.parent.close() + call s:renderView() + call treenode.parent.putCursorHere(0, 0) + endif +endfunction +" FUNCTION: s:closeTreeWindow() {{{2 +" close the tree window +function! s:closeTreeWindow() + if b:NERDTreeType ==# "secondary" && b:NERDTreePreviousBuf != -1 + exec "buffer " . b:NERDTreePreviousBuf + else + if winnr("$") > 1 + wincmd c + else + call s:echo("Cannot close last window") + endif + endif +endfunction +" FUNCTION: s:copyNode() {{{2 +function! s:copyNode() + let currentNode = s:TreeFileNode.GetSelected() + if currentNode ==# {} + call s:echo("Put the cursor on a file node first") + return + endif + + let newNodePath = input("Copy the current node\n" . + \ "==========================================================\n" . + \ "Enter the new path to copy the node to: \n" . + \ "", currentNode.path.str(0)) + + if newNodePath != "" + "strip trailing slash + let newNodePath = substitute(newNodePath, '\/$', '', '') + + let confirmed = 1 + if currentNode.path.copyingWillOverwrite(newNodePath) + call s:echo("\nWarning: copying may overwrite files! Continue? (yN)") + let choice = nr2char(getchar()) + let confirmed = choice ==# 'y' + endif + + if confirmed + try + let newNode = currentNode.copy(newNodePath) + call s:renderView() + call newNode.putCursorHere(0, 0) + catch /^NERDTree/ + call s:echoWarning("Could not copy node") + endtry + endif + else + call s:echo("Copy aborted.") + endif + redraw +endfunction + +" FUNCTION: s:deleteBookmark() {{{2 +" if the cursor is on a bookmark, prompt to delete +function! s:deleteBookmark() + let bookmark = s:getSelectedBookmark() + if bookmark ==# {} + call s:echo("Put the cursor on a bookmark") + return + endif + + echo "Are you sure you wish to delete the bookmark:\n\"" . bookmark.name . "\" (yN):" + + if nr2char(getchar()) ==# 'y' + try + call bookmark.delete() + call s:renderView() + redraw + catch /^NERDTree/ + call s:echoWarning("Could not remove bookmark") + endtry + else + call s:echo("delete aborted" ) + endif + +endfunction + +" FUNCTION: s: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:TreeFileNode.GetSelected() + 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 b:treeShowHelp = b:treeShowHelp ? 0 : 1 + call s:renderView() + call s:centerView() +endfunction + +" FUNCTION: s:executeNode() {{{2 +function! s:executeNode() + let treenode = s:TreeFileNode.GetSelected() + 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:TreeFileNode.GetSelected() + if curNode ==# {} + call s:echo("Put the cursor on a node first" ) + return + endif + + if curNode.path.isDirectory + call s:openExplorer() + else + call s:openEntrySplit(0,0) + endif +endfunction + + +" FUNCTION: s:insertNewNode() {{{2 +" Adds a new node to the filesystem and then into the tree +function! s:insertNewNode() + let curDirNode = s:TreeDirNode.GetSelected() + 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.strForGlob() . s:os_slash) + + if newNodeName ==# '' + call s:echo("Node Creation Aborted.") + return + endif + + try + let newPath = s:Path.Create(newNodeName) + let parentNode = b:NERDTreeRoot.findNode(newPath.getPathTrunk()) + + let newTreeNode = s:TreeFileNode.New(newPath) + if parentNode.isOpen || !empty(parentNode.children) + call parentNode.addChild(newTreeNode, 1) + call s:renderView() + call newTreeNode.putCursorHere(1, 0) + 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:TreeFileNode.GetSelected() + if !empty(currentNode) + if !empty(currentNode.parent) + call currentNode.parent.putCursorHere(1, 0) + call s:centerView() + else + call s:echo("cannot jump to parent") + endif + else + call s:echo("put the cursor on a node first") + endif +endfunction + +" FUNCTION: s:jumpToRoot() {{{2 +" moves the cursor to the root node +function! s:jumpToRoot() + call b:NERDTreeRoot.putCursorHere(1, 0) + call s:centerView() +endfunction + +" FUNCTION: s:jumpToSibling() {{{2 +" moves the cursor to the sibling of the current node in the given direction +" +" Args: +" forward: 1 if the cursor should move to the next sibling, 0 if it should +" move back to the previous sibling +function! s:jumpToSibling(forward) + let currentNode = s:TreeFileNode.GetSelected() + if !empty(currentNode) + let sibling = currentNode.findSibling(a:forward) + + if !empty(sibling) + call sibling.putCursorHere(1, 0) + call s:centerView() + endif + else + call s:echo("put the cursor on a node first") + endif +endfunction + +" FUNCTION: s:openBookmark(name) {{{2 +" put the cursor on the given bookmark and, if its a file, open it +function! s:openBookmark(name) + try + let targetNode = s:Bookmark.GetNodeForName(a:name, 0) + call targetNode.putCursorHere(0, 1) + redraw! + catch /^NERDTree.BookmarkedNodeNotFoundError/ + call s:echo("note - target node is not cached") + let bookmark = s:Bookmark.BookmarkFor(a:name) + let targetNode = s:TreeFileNode.New(bookmark.path) + endtry + if targetNode.path.isDirectory + call targetNode.openExplorer() + else + call targetNode.open() + endif +endfunction +" FUNCTION: s:openEntrySplit(vertical, forceKeepWindowOpen) {{{2 +"Opens the currently selected file from the explorer in a +"new window +" +"args: +"forceKeepWindowOpen - dont close the window even if NERDTreeQuitOnOpen is set +function! s:openEntrySplit(vertical, forceKeepWindowOpen) + let treenode = s:TreeFileNode.GetSelected() + if treenode != {} + if a:vertical + call treenode.openVSplit() + else + call treenode.openSplit() + endif + if !a:forceKeepWindowOpen + call s:closeTreeIfQuitOnOpen() + endif + else + call s:echo("select a node first") + endif +endfunction + +" FUNCTION: s:openExplorer() {{{2 +function! s:openExplorer() + let treenode = s:TreeDirNode.GetSelected() + if treenode != {} + call treenode.openExplorer() + else + call s:echo("select a node first") + endif +endfunction + +" FUNCTION: s:openInNewTab(stayCurrentTab) {{{2 +" Opens the selected node or bookmark in a new tab +" Args: +" stayCurrentTab: if 1 then vim will stay in the current tab, if 0 then vim +" will go to the tab where the new file is opened +function! s:openInNewTab(stayCurrentTab) + let currentTab = tabpagenr() + + let treenode = s:TreeFileNode.GetSelected() + if treenode != {} + if treenode.path.isDirectory + tabnew + call s:initNerdTree(treenode.path.strForOS(0)) + else + exec "tabedit " . treenode.path.strForEditCmd() + endif + else + let bookmark = s:getSelectedBookmark() + if bookmark != {} + if bookmark.path.isDirectory + tabnew + call s:initNerdTree(bookmark.name) + else + exec "tabedit " . bookmark.path.strForEditCmd() + endif + endif + endif + if a:stayCurrentTab + exec "tabnext " . currentTab + endif +endfunction + +" FUNCTION: s:openNodeRecursively() {{{2 +function! s:openNodeRecursively() + let treenode = s:TreeFileNode.GetSelected() + if treenode ==# {} || treenode.path.isDirectory ==# 0 + call s:echo("Select a directory node first" ) + else + call s:echo("Recursively opening node. Please wait...") + call treenode.openRecursively() + call s:renderView() + redraw + call s:echo("Recursively opening node. Please wait... DONE") + endif + +endfunction + +"FUNCTION: s:previewNode() {{{2 +"Args: +" openNewWin: if 0, use the previous window, if 1 open in new split, if 2 +" open in a vsplit +function! s:previewNode(openNewWin) + let currentBuf = bufnr("") + if a:openNewWin > 0 + call s:openEntrySplit(a:openNewWin ==# 2,1) + else + call s:activateNode(1) + end + call s:exec(bufwinnr(currentBuf) . "wincmd w") +endfunction + +" FUNCTION: s:revealBookmark(name) {{{2 +" put the cursor on the node associate with the given name +function! s:revealBookmark(name) + try + let targetNode = s:Bookmark.GetNodeForName(a:name, 0) + call targetNode.putCursorHere(0, 1) + catch /^NERDTree.BookmarkNotFoundError/ + call s:echo("Bookmark isnt cached under the current root") + endtry +endfunction +" FUNCTION: s:refreshRoot() {{{2 +" Reloads the current root. All nodes below this will be lost and the root dir +" will be reloaded. +function! s:refreshRoot() + call s:echo("Refreshing the root node. This could take a while...") + call b:NERDTreeRoot.refresh() + call s:renderView() + redraw + call s:echo("Refreshing the root node. This could take a while... DONE") +endfunction + +" FUNCTION: s:refreshCurrent() {{{2 +" refreshes the root for the current node +function! s:refreshCurrent() + let treenode = s:TreeDirNode.GetSelected() + if treenode ==# {} + call s:echo("Refresh failed. Select a node first") + return + endif + + call s:echo("Refreshing node. This could take a while...") + call treenode.refresh() + call s:renderView() + redraw + call s:echo("Refreshing node. This could take a while... DONE") +endfunction +" FUNCTION: s:renameCurrent() {{{2 +" allows the user to rename the current node +function! s:renameCurrent() + let curNode = s:TreeFileNode.GetSelected() + 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.strForOS(0)) + + if newNodePath ==# '' + call s:echo("Node Renaming Aborted.") + return + endif + + 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 = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Delete this buffer? (yN)" + call s:promptToDelBuffer(bufnum, prompt) + endif + + call curNode.putCursorHere(1, 0) + + redraw + catch /^NERDTree/ + call s:echoWarning("Node Not Renamed.") + endtry +endfunction + +" FUNCTION: s:showFileSystemMenu() {{{2 +function! s:showFileSystemMenu() + let curNode = s:TreeFileNode.GetSelected() + if curNode ==# {} + call s:echo("Put the cursor on a node first" ) + return + endif + + + let prompt = "NERDTree Filesystem Menu\n" . + \ "==========================================================\n". + \ "Select the desired operation: \n" . + \ " (a)dd a childnode\n". + \ " (m)ove the current node\n". + \ " (d)elete the current node\n" + if s:Path.CopyingSupported() + let prompt = prompt . " (c)opy the current node\n\n" + else + let prompt = prompt . " \n" + endif + + echo prompt + + let choice = nr2char(getchar()) + + if choice ==? "a" + call s:insertNewNode() + elseif choice ==? "m" + call s:renameCurrent() + elseif choice ==? "d" + call s:deleteNode() + elseif choice ==? "c" && s:Path.CopyingSupported() + call s:copyNode() + endif +endfunction + +" FUNCTION: s:toggleIgnoreFilter() {{{2 +" toggles the use of the NERDTreeIgnore option +function! s:toggleIgnoreFilter() + let b:NERDTreeIgnoreEnabled = !b:NERDTreeIgnoreEnabled + call s:renderViewSavingPosition() + call s:centerView() +endfunction + +" FUNCTION: s:toggleShowBookmarks() {{{2 +" toggles the display of bookmarks +function! s:toggleShowBookmarks() + let b:NERDTreeShowBookmarks = !b:NERDTreeShowBookmarks + if b:NERDTreeShowBookmarks + call s:renderView() + call s:putCursorOnBookmarkTable() + else + call s:renderViewSavingPosition() + endif + call s:centerView() +endfunction +" FUNCTION: s:toggleShowFiles() {{{2 +" toggles the display of hidden files +function! s:toggleShowFiles() + let b:NERDTreeShowFiles = !b:NERDTreeShowFiles + call s:renderViewSavingPosition() + call s:centerView() +endfunction + +" FUNCTION: s:toggleShowHidden() {{{2 +" toggles the display of hidden files +function! s:toggleShowHidden() + let b:NERDTreeShowHidden = !b:NERDTreeShowHidden + call s:renderViewSavingPosition() + call s:centerView() +endfunction + +"FUNCTION: s:upDir(keepState) {{{2 +"moves the tree up a level +" +"Args: +"keepState: 1 if the current root should be left open when the tree is +"re-rendered +function! s:upDir(keepState) + let cwd = b:NERDTreeRoot.path.str(0) + if cwd ==# "/" || cwd =~ '^[^/]..$' + call s:echo("already at top dir") + else + if !a:keepState + call b:NERDTreeRoot.close() + endif + + let oldRoot = b:NERDTreeRoot + + if empty(b:NERDTreeRoot.parent) + let path = b:NERDTreeRoot.path.getPathTrunk() + let newRoot = s:TreeDirNode.New(path) + call newRoot.open() + call newRoot.transplantChild(b:NERDTreeRoot) + let b:NERDTreeRoot = newRoot + else + let b:NERDTreeRoot = b:NERDTreeRoot.parent + endif + + if g:NERDTreeChDirMode ==# 2 + exec 'cd ' . b:NERDTreeRoot.path.strForCd() + endif + + call s:renderView() + call oldRoot.putCursorHere(0, 0) + endif +endfunction + + +"reset &cpo back to users setting +let &cpo = s:old_cpo + +" vim: set sw=4 sts=4 et fdm=marker: diff --git a/vim/plugin/bufexplorer.vim b/vim/plugin/bufexplorer.vim new file mode 100644 index 0000000..42673d6 --- /dev/null +++ b/vim/plugin/bufexplorer.vim @@ -0,0 +1,869 @@ +"============================================================================= +" Copyright: Copyright (C) 2001-2008 Jeff Lanzarotta +" 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, +" bufexplorer.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 damages +" resulting from the use of this software. +" Name Of File: bufexplorer.vim +" Description: Buffer Explorer Vim Plugin +" Maintainer: Jeff Lanzarotta (delux256-vim at yahoo dot com) +" Last Changed: Wednesday, 19 Nov 2008 +" Version: See g:bufexplorer_version for version number. +" Usage: This file should reside in the plugin directory and be +" automatically sourced. +" +" You may use the default keymappings of +" +" be - Opens BufExplorer +" bs - Opens horizontally split window BufExplorer +" bv - Opens vertically split window BufExplorer +" +" Or you can use +" +" ":BufExplorer" - Opens BufExplorer +" ":HSBufExplorer" - Opens horizontally window BufExplorer +" ":VSBufExplorer" - Opens vertically split window BufExplorer +" +" For more help see supplied documentation. +" History: See supplied documentation. +"============================================================================= + +" Exit quickly if already running or when 'compatible' is set. {{{1 +if exists("g:bufexplorer_version") || &cp + finish +endif +"1}}} + +" Version number +let g:bufexplorer_version = "7.2.2" + +" Check for Vim version 700 or greater {{{1 +if v:version < 700 + echo "Sorry, bufexplorer ".g:bufexplorer_version."\nONLY runs with Vim 7.0 and greater." + finish +endif + +" Public Interface {{{1 +nmap be :BufExplorer +nmap bs :HSBufExplorer +nmap bv :VSBufExplorer + +" Create commands {{{1 +command BufExplorer :call StartBufExplorer(has ("gui") ? "drop" : "hide edit") +command HSBufExplorer :call HorizontalSplitBufExplorer() +command VSBufExplorer :call VerticalSplitBufExplorer() + +" Set {{{1 +function s:Set(var, default) + if !exists(a:var) + if type(a:default) + exec "let" a:var "=" string(a:default) + else + exec "let" a:var "=" a:default + endif + + return 1 + endif + + return 0 +endfunction + +" Default values {{{1 +call s:Set("g:bufExplorerDefaultHelp", 1) " Show default help? +call s:Set("g:bufExplorerDetailedHelp", 0) " Show detailed help? +call s:Set("g:bufExplorerFindActive", 1) " When selecting an active buffer, take you to the window where it is active? +call s:Set("g:bufExplorerReverseSort", 0) " sort reverse? +call s:Set("g:bufExplorerShowDirectories", 1) " (Dir's are added by commands like ':e .') +call s:Set("g:bufExplorerShowRelativePath", 0) " Show listings with relative or absolute paths? +call s:Set("g:bufExplorerShowUnlisted", 0) " Show unlisted buffers? +call s:Set("g:bufExplorerSortBy", "mru") " Sorting methods are in s:sort_by: +call s:Set("g:bufExplorerSplitOutPathName", 1) " Split out path and file name? +call s:Set("g:bufExplorerSplitRight", &splitright) " Should vertical splits be on the right or left of current window? +call s:Set("g:bufExplorerSplitBelow", &splitbelow) " Should horizontal splits be below or above current window? + +" Global variables {{{1 +let s:MRUList = [] +let s:running = 0 +let s:sort_by = ["number", "name", "fullpath", "mru", "extension"] +let s:tabSpace = [] +let s:types = {"fullname": ':p', "path": ':p:h', "relativename": ':~:.', "relativepath": ':~:.:h', "shortname": ':t'} +let s:originBuffer = 0 +let s:splitMode = "sp" + +" Setup the autocommands that handle the MRUList and other stuff. {{{1 +autocmd VimEnter * call s:Setup() + +" Setup {{{1 +function s:Setup() + " Build initial MRUList. + let s:MRUList = range(1, bufnr('$')) + let s:tabSpace = [] + " Now that the MRUList is created, add the other autocmds. + autocmd BufEnter,BufNew * call s:ActivateBuffer() + autocmd BufWipeOut * call s:DeactivateBuffer(1) + autocmd BufDelete * call s:DeactivateBuffer(0) + + autocmd BufWinEnter \[BufExplorer\] call s:Initialize() + autocmd BufWinLeave \[BufExplorer\] call s:Cleanup() +endfunction + +" ActivateBuffer {{{1 +function s:ActivateBuffer() + let b = bufnr("%") + let l = get(s:tabSpace, tabpagenr(), []) + + if empty(l) || index(l, b) == -1 + call add(l, b) + let s:tabSpace[tabpagenr()] = l + endif + + call s:MRUPush(b) +endfunction + +" DeactivateBuffer {{{1 +function s:DeactivateBuffer(remove) + "echom "afile:" expand("") + "echom "bufnr, afile:" bufnr(expand("")) + "echom "buffers:" string(tabpagebuflist()) + "echom "MRU before:" string(s:MRUList) + + let _bufnr = bufnr(expand("")) + let _buftype = getbufvar(_bufnr, "&buftype") + + if empty(_buftype) || _buftype == "nofile" || !buflisted(_bufnr) || empty(bufname(_bufnr)) || fnamemodify(bufname(_bufnr), ":t") == "[BufExplorer]" + return + end + + if a:remove + call s:MRUPop(bufnr(expand(""))) + end +endfunction + +" MRUPop {{{1 +function s:MRUPop(buf) + call filter(s:MRUList, 'v:val != '.a:buf) +endfunction + +" MRUPush {{{1 +function s:MRUPush(buf) + " Skip temporary buffer with buftype set. Don't add the BufExplorer window to the + " list. + if !empty(getbufvar(a:buf, "&buftype")) || + \ !buflisted(a:buf) || empty(bufname(a:buf)) || + \ fnamemodify(bufname(a:buf), ":t") == "[BufExplorer]" + return + end + " Remove the buffer number from the list if it already exists. + call s:MRUPop(a:buf) + " Add the buffer number to the head of the list. + call insert(s:MRUList,a:buf) +endfunction + +" Initialize {{{1 +function s:Initialize() + let s:_insertmode = &insertmode + set noinsertmode + + let s:_showcmd = &showcmd + set noshowcmd + + let s:_cpo = &cpo + set cpo&vim + + let s:_report = &report + let &report = 10000 + + let s:_list = &list + set nolist + + setlocal nonumber + setlocal foldcolumn=0 + setlocal nofoldenable + setlocal cursorline + setlocal nospell + + set nobuflisted + + let s:running = 1 +endfunction + +" Cleanup {{{1 +function s:Cleanup() + let &insertmode = s:_insertmode + let &showcmd = s:_showcmd + let &cpo = s:_cpo + let &report = s:_report + let &list = s:_list + let s:running = 0 + let s:splitMode = "" + + delmarks! +endfunction + +" HorizontalSplitBufExplorer {{{1 +function HorizontalSplitBufExplorer() + let s:splitMode = "sp" + exec "BufExplorer" +endfunction + +" VerticalSplitBufExplorer {{{1 +function VerticalSplitBufExplorer() + let s:splitMode = "vsp" + exec "BufExplorer" +endfunction + +" StartBufExplorer {{{1 +function StartBufExplorer(open) + let name = '[BufExplorer]' + + if !has("win32") + " On non-Windows boxes, escape the name so that is shows up correctly. + let name = escape(name, "[]") + endif + " Make sure there is only one explorer open at a time. + if s:running == 1 + " Go to the open buffer. + if has("gui") + exec "drop" name + endif + + return + endif + + let s:originBuffer = bufnr("%") + silent let s:raw_buffer_listing = s:GetBufferInfo() + + let copy = copy(s:raw_buffer_listing) + + if (g:bufExplorerShowUnlisted == 0) + call filter(copy, 'v:val.attributes !~ "u"') + endif + + if (!empty(copy)) + call filter(copy, 'v:val.shortname !~ "\\\[No Name\\\]"') + endif + + if len(copy) <= 1 + echo "\r" + call s:Warning("Sorry, there are no more buffers to explore") + + return + endif + " We may have to split the current window. + if (s:splitMode != "") + " Save off the original settings. + let [_splitbelow, _splitright] = [&splitbelow, &splitright] + " Set the setting to ours. + let [&splitbelow, &splitright] = [g:bufExplorerSplitBelow, g:bufExplorerSplitRight] + " Do it. + exe s:splitMode + " Restore the original settings. + let [&splitbelow, &splitright] = [_splitbelow, _splitright] + endif + + if !exists("b:displayMode") || b:displayMode != "winmanager" + " Do not use keepalt when opening bufexplorer to allow the buffer that we are + " leaving to become the new alternate buffer + exec "silent keepjumps ".a:open." ".name + endif + + call s:DisplayBufferList() +endfunction + +" DisplayBufferList {{{1 +function s:DisplayBufferList() + setlocal bufhidden=delete + setlocal buftype=nofile + setlocal modifiable + setlocal noswapfile + setlocal nowrap + + call s:SetupSyntax() + call s:MapKeys() + call setline(1, s:CreateHelp()) + call s:BuildBufferList() + call cursor(s:firstBufferLine, 1) + + if !g:bufExplorerResize + normal! zz + endif + + setlocal nomodifiable +endfunction + +" MapKeys {{{1 +function s:MapKeys() + if exists("b:displayMode") && b:displayMode == "winmanager" + nnoremap :call SelectBuffer("tab") + endif + + nnoremap :call ToggleHelp() + nnoremap <2-leftmouse> :call SelectBuffer() + nnoremap :call SelectBuffer() + nnoremap t :call SelectBuffer("tab") + nnoremap :call SelectBuffer("tab") + nnoremap d :call RemoveBuffer("wipe") + nnoremap D :call RemoveBuffer("delete") + nnoremap m :call MRUListShow() + nnoremap p :call ToggleSplitOutPathName() + nnoremap q :call Close() + nnoremap r :call SortReverse() + nnoremap R :call ToggleShowRelativePath() + nnoremap s :call SortSelect() + nnoremap u :call ToggleShowUnlisted() + nnoremap f :call ToggleFindActive() + + for k in ["G", "n", "N", "L", "M", "H"] + exec "nnoremap " k ":keepjumps normal!" k."" + endfor +endfunction + +" SetupSyntax {{{1 +function s:SetupSyntax() + if has("syntax") + syn match bufExplorerHelp "^\".*" contains=bufExplorerSortBy,bufExplorerMapping,bufExplorerTitle,bufExplorerSortType,bufExplorerToggleSplit,bufExplorerToggleOpen + syn match bufExplorerOpenIn "Open in \w\+ window" contained + syn match bufExplorerSplit "\w\+ split" contained + syn match bufExplorerSortBy "Sorted by .*" contained contains=bufExplorerOpenIn,bufExplorerSplit + syn match bufExplorerMapping "\" \zs.\+\ze :" contained + syn match bufExplorerTitle "Buffer Explorer.*" contained + syn match bufExplorerSortType "'\w\{-}'" contained + syn match bufExplorerBufNbr /^\s*\d\+/ + syn match bufExplorerToggleSplit "toggle split type" contained + syn match bufExplorerToggleOpen "toggle open mode" contained + + syn match bufExplorerModBuf /^\s*\d\+.\{4}+.*/ + syn match bufExplorerLockedBuf /^\s*\d\+.\{3}[\-=].*/ + syn match bufExplorerHidBuf /^\s*\d\+.\{2}h.*/ + syn match bufExplorerActBuf /^\s*\d\+.\{2}a.*/ + syn match bufExplorerCurBuf /^\s*\d\+.%.*/ + syn match bufExplorerAltBuf /^\s*\d\+.#.*/ + syn match bufExplorerUnlBuf /^\s*\d\+u.*/ + + hi def link bufExplorerBufNbr Number + hi def link bufExplorerMapping NonText + hi def link bufExplorerHelp Special + hi def link bufExplorerOpenIn Identifier + hi def link bufExplorerSortBy String + hi def link bufExplorerSplit NonText + hi def link bufExplorerTitle NonText + hi def link bufExplorerSortType bufExplorerSortBy + hi def link bufExplorerToggleSplit bufExplorerSplit + hi def link bufExplorerToggleOpen bufExplorerOpenIn + + hi def link bufExplorerActBuf Identifier + hi def link bufExplorerAltBuf String + hi def link bufExplorerCurBuf Type + hi def link bufExplorerHidBuf Constant + hi def link bufExplorerLockedBuf Special + hi def link bufExplorerModBuf Exception + hi def link bufExplorerUnlBuf Comment + endif +endfunction + +" ToggleHelp {{{1 +function s:ToggleHelp() + let g:bufExplorerDetailedHelp = !g:bufExplorerDetailedHelp + + setlocal modifiable + " Save position. + normal! ma + " Remove old header. + if (s:firstBufferLine > 1) + exec "keepjumps 1,".(s:firstBufferLine - 1) "d _" + endif + + call append(0, s:CreateHelp()) + + silent! normal! g`a + delmarks a + + setlocal nomodifiable + + if exists("b:displayMode") && b:displayMode == "winmanager" + call WinManagerForceReSize("BufExplorer") + end +endfunction + +" GetHelpStatus {{{1 +function s:GetHelpStatus() + let ret = '" Sorted by '.((g:bufExplorerReverseSort == 1) ? "reverse " : "").g:bufExplorerSortBy + let ret .= ' | '.((g:bufExplorerFindActive == 0) ? "Don't " : "")."Locate buffer" + let ret .= ((g:bufExplorerShowUnlisted == 0) ? "" : " | Show unlisted") + let ret .= ' | '.((g:bufExplorerShowRelativePath == 0) ? "Absolute" : "Relative") + let ret .= ' '.((g:bufExplorerSplitOutPathName == 0) ? "Full" : "Split")." path" + + return ret +endfunction + +" CreateHelp {{{1 +function s:CreateHelp() + if g:bufExplorerDefaultHelp == 0 && g:bufExplorerDetailedHelp == 0 + let s:firstBufferLine = 1 + return [] + endif + + let header = [] + + if g:bufExplorerDetailedHelp == 1 + call add(header, '" Buffer Explorer ('.g:bufexplorer_version.')') + call add(header, '" --------------------------') + call add(header, '" : toggle this help') + call add(header, '" or Mouse-Double-Click : open buffer under cursor') + call add(header, '" or t : open buffer in another tab') + call add(header, '" d : wipe buffer') + call add(header, '" D : delete buffer') + call add(header, '" p : toggle spliting of file and path name') + call add(header, '" q : quit') + call add(header, '" r : reverse sort') + call add(header, '" R : toggle showing relative or full paths') + call add(header, '" u : toggle showing unlisted buffers') + call add(header, '" s : select sort field '.string(s:sort_by).'') + call add(header, '" f : toggle find active buffer') + else + call add(header, '" Press for Help') + endif + + call add(header, s:GetHelpStatus()) + call add(header, '"=') + + let s:firstBufferLine = len(header) + 1 + + return header +endfunction + +" GetBufferInfo {{{1 +function s:GetBufferInfo() + redir => bufoutput + buffers! + redir END + + let [all, allwidths, listedwidths] = [[], {}, {}] + + for n in keys(s:types) + let allwidths[n] = [] + let listedwidths[n] = [] + endfor + + for buf in split(bufoutput, '\n') + let bits = split(buf, '"') + let b = {"attributes": bits[0], "line": substitute(bits[2], '\s*', '', '')} + + for [key, val] in items(s:types) + let b[key] = fnamemodify(bits[1], val) + endfor + + if getftype(b.fullname) == "dir" && g:bufExplorerShowDirectories == 1 + let b.shortname = "" + end + + call add(all, b) + + for n in keys(s:types) + call add(allwidths[n], len(b[n])) + + if b.attributes !~ "u" + call add(listedwidths[n], len(b[n])) + endif + endfor + endfor + + let [s:allpads, s:listedpads] = [{}, {}] + + for n in keys(s:types) + let s:allpads[n] = repeat(' ', max(allwidths[n])) + let s:listedpads[n] = repeat(' ', max(listedwidths[n])) + endfor + + return all +endfunction + +" BuildBufferList {{{1 +function s:BuildBufferList() + let lines = [] + " Loop through every buffer. + for buf in s:raw_buffer_listing + if (!g:bufExplorerShowUnlisted && buf.attributes =~ "u") + " Skip unlisted buffers if we are not to show them. + continue + endif + + let line = buf.attributes." " + + if g:bufExplorerSplitOutPathName + let type = (g:bufExplorerShowRelativePath) ? "relativepath" : "path" + let path = buf[type] + let pad = (g:bufExplorerShowUnlisted) ? s:allpads.shortname : s:listedpads.shortname + let line .= buf.shortname." ".strpart(pad.path, len(buf.shortname)) + else + let type = (g:bufExplorerShowRelativePath) ? "relativename" : "fullname" + let path = buf[type] + let line .= path + endif + + let pads = (g:bufExplorerShowUnlisted) ? s:allpads : s:listedpads + + if !empty(pads[type]) + let line .= strpart(pads[type], len(path))." " + endif + + let line .= buf.line + + call add(lines, line) + endfor + + call setline(s:firstBufferLine, lines) + + call s:SortListing() +endfunction + +" SelectBuffer {{{1 +function s:SelectBuffer(...) + " Sometimes messages are not cleared when we get here so it looks like an error has + " occurred when it really has not. + echo "" + " Are we on a line with a file name? + if line('.') < s:firstBufferLine + exec "normal! \" + return + endif + + let _bufNbr = str2nr(getline('.')) + + if exists("b:displayMode") && b:displayMode == "winmanager" + let bufname = expand("#"._bufNbr.":p") + + if (a:0 == 1) && (a:1 == "tab") + call WinManagerFileEdit(bufname, 1) + else + call WinManagerFileEdit(bufname, 0) + endif + + return + end + + if bufexists(_bufNbr) + if bufnr("#") == _bufNbr + return s:Close() + endif + + if (a:0 == 1) && (a:1 == "tab") + " Restore [BufExplorer] buffer. + exec "keepjumps silent buffer!".s:originBuffer + + let tabNbr = s:GetTabNbr(_bufNbr) + + if tabNbr == 0 + " _bufNbr is not opened in any tabs. Open a new tab with the selected buffer in it. + exec "999tab split +buffer" . _bufNbr + else + " The _bufNbr is already opened in tab(s), go to that tab. + exec tabNbr . "tabnext" + " Focus window. + exec s:GetWinNbr(tabNbr, _bufNbr) . "wincmd w" + endif + else + if bufloaded(_bufNbr) && g:bufExplorerFindActive + call s:Close() + + let tabNbr = s:GetTabNbr(_bufNbr) + + if tabNbr != 0 + " The buffer is located in a tab. Go to that tab number. + exec tabNbr . "tabnext" + else + let bufname = expand("#"._bufNbr.":p") + exec bufname ? "drop ".escape(bufname, " ") : "buffer "._bufNbr + endif + endif + " Switch to the buffer. + exec "keepalt keepjumps silent b!" _bufNbr + endif + " Make the buffer 'listed' again. + call setbufvar(_bufNbr, "&buflisted", "1") + else + call s:Error("Sorry, that buffer no longer exists, please select another") + call s:DeleteBuffer(_bufNbr, "wipe") + endif +endfunction + +" RemoveBuffer {{{1 +function s:RemoveBuffer(mode) + " Are we on a line with a file name? + if line('.') < s:firstBufferLine + return + endif + " Do not allow this buffer to be deleted if it is the last one. + if len(s:MRUList) == 1 + call s:Error("Sorry, you are not allowed to delete the last buffer") + return + endif + " These commands are to temporarily suspend the activity of winmanager. + if exists("b:displayMode") && b:displayMode == "winmanager" + call WinManagerSuspendAUs() + end + + let _bufNbr = str2nr(getline('.')) + + if getbufvar(_bufNbr, '&modified') == 1 + call s:Error("Sorry, no write since last change for buffer "._bufNbr.", unable to delete") + return + else + " Okay, everything is good, delete or wipe the buffer. + call s:DeleteBuffer(_bufNbr, a:mode) + endif + " Reactivate winmanager autocommand activity. + if exists("b:displayMode") && b:displayMode == "winmanager" + call WinManagerForceReSize("BufExplorer") + call WinManagerResumeAUs() + end +endfunction + +" DeleteBuffer {{{1 +function s:DeleteBuffer(buf, mode) + " This routine assumes that the buffer to be removed is on the current line. + try + if a:mode == "wipe" + exe "silent bw" a:buf + else + exe "silent bd" a:buf + end + + setlocal modifiable + normal! "_dd + setlocal nomodifiable + " Delete the buffer from the raw buffer list. + call filter(s:raw_buffer_listing, 'v:val.attributes !~ " '.a:buf.' "') + catch + call s:Error(v:exception) + endtry +endfunction + +" Close {{{1 +function s:Close() + " Get only the listed buffers. + let listed = filter(copy(s:MRUList), "buflisted(v:val)") + " If we needed to split the main window, close the split one. + if (s:splitMode != "") + exec "wincmd c" + end + + for b in reverse(listed[0:1]) + exec "keepjumps silent b ".b + endfor +endfunction + +" ToggleSplitOutPathName {{{1 +function s:ToggleSplitOutPathName() + let g:bufExplorerSplitOutPathName = !g:bufExplorerSplitOutPathName + call s:RebuildBufferList() + call s:UpdateHelpStatus() +endfunction + +" ToggleShowRelativePath {{{1 +function s:ToggleShowRelativePath() + let g:bufExplorerShowRelativePath = !g:bufExplorerShowRelativePath + call s:RebuildBufferList() + call s:UpdateHelpStatus() +endfunction + +" ToggleShowUnlisted {{{1 +function s:ToggleShowUnlisted() + let g:bufExplorerShowUnlisted = !g:bufExplorerShowUnlisted + let num_bufs = s:RebuildBufferList(g:bufExplorerShowUnlisted == 0) + call s:UpdateHelpStatus() +endfunction + +" ToggleFindActive {{{1 +function s:ToggleFindActive() + let g:bufExplorerFindActive = !g:bufExplorerFindActive + call s:UpdateHelpStatus() +endfunction + +" RebuildBufferList {{{1 +function s:RebuildBufferList(...) + setlocal modifiable + + let curPos = getpos('.') + + if a:0 + " Clear the list first. + exec "keepjumps ".s:firstBufferLine.',$d "_' + endif + + let num_bufs = s:BuildBufferList() + + call setpos('.', curPos) + + setlocal nomodifiable + + return num_bufs +endfunction + +" UpdateHelpStatus {{{1 +function s:UpdateHelpStatus() + setlocal modifiable + + let text = s:GetHelpStatus() + call setline(s:firstBufferLine - 2, text) + + setlocal nomodifiable +endfunction + +" MRUCmp {{{1 +function s:MRUCmp(line1, line2) + return index(s:MRUList, str2nr(a:line1)) - index(s:MRUList, str2nr(a:line2)) +endfunction + +" SortReverse {{{1 +function s:SortReverse() + let g:bufExplorerReverseSort = !g:bufExplorerReverseSort + + call s:ReSortListing() +endfunction + +" SortSelect {{{1 +function s:SortSelect() + let g:bufExplorerSortBy = get(s:sort_by, index(s:sort_by, g:bufExplorerSortBy) + 1, s:sort_by[0]) + + call s:ReSortListing() +endfunction + +" ReSortListing {{{1 +function s:ReSortListing() + setlocal modifiable + + let curPos = getpos('.') + + call s:SortListing() + call s:UpdateHelpStatus() + + call setpos('.', curPos) + + setlocal nomodifiable +endfunction + +" SortListing {{{1 +function s:SortListing() + let sort = s:firstBufferLine.",$sort".((g:bufExplorerReverseSort == 1) ? "!": "") + + if g:bufExplorerSortBy == "number" + " Easiest case. + exec sort 'n' + elseif g:bufExplorerSortBy == "name" + if g:bufExplorerSplitOutPathName + exec sort 'ir /\d.\{7}\zs\f\+\ze/' + else + exec sort 'ir /\zs[^\/\\]\+\ze\s*line/' + endif + elseif g:bufExplorerSortBy == "fullpath" + if g:bufExplorerSplitOutPathName + " Sort twice - first on the file name then on the path. + exec sort 'ir /\d.\{7}\zs\f\+\ze/' + endif + + exec sort 'ir /\zs\f\+\ze\s\+line/' + elseif g:bufExplorerSortBy == "extension" + exec sort 'ir /\.\zs\w\+\ze\s/' + elseif g:bufExplorerSortBy == "mru" + let l = getline(s:firstBufferLine, "$") + + call sort(l, "MRUCmp") + + if g:bufExplorerReverseSort + call reverse(l) + endif + + call setline(s:firstBufferLine, l) + endif +endfunction + +" MRUListShow {{{1 +function s:MRUListShow() + echomsg "MRUList=".string(s:MRUList) +endfunction + +" Error {{{1 +function s:Error(msg) + echohl ErrorMsg | echo a:msg | echohl none +endfunction + +" Warning {{{1 +function s:Warning(msg) + echohl WarningMsg | echo a:msg | echohl none +endfunction + +" GetTabNbr {{{1 +function s:GetTabNbr(bufNbr) + " Searching buffer bufno, in tabs. + for i in range(tabpagenr("$")) + if index(tabpagebuflist(i + 1), a:bufNbr) != -1 + return i + 1 + endif + endfor + + return 0 +endfunction + +" GetWinNbr" {{{1 +function s:GetWinNbr(tabNbr, bufNbr) + " window number in tabpage. + return index(tabpagebuflist(a:tabNbr), a:bufNbr) + 1 +endfunction + +" Winmanager Integration {{{1 +let g:BufExplorer_title = "\[Buf\ List\]" +call s:Set("g:bufExplorerResize", 1) +call s:Set("g:bufExplorerMaxHeight", 25) " Handles dynamic resizing of the window. + +" Function to start display. Set the mode to 'winmanager' for this buffer. +" This is to figure out how this plugin was called. In a standalone fashion +" or by winmanager. +function BufExplorer_Start() + let b:displayMode = "winmanager" + call StartBufExplorer("e") +endfunction + +" Returns whether the display is okay or not. +function BufExplorer_IsValid() + return 0 +endfunction + +" Handles dynamic refreshing of the window. +function BufExplorer_Refresh() + let b:displayMode = "winmanager" + call StartBufExplorer("e") +endfunction + +function BufExplorer_ReSize() + if !g:bufExplorerResize + return + end + + let nlines = min([line("$"), g:bufExplorerMaxHeight]) + + exe nlines." wincmd _" + + " The following lines restore the layout so that the last file line is also + " the last window line. Sometimes, when a line is deleted, although the + " window size is exactly equal to the number of lines in the file, some of + " the lines are pushed up and we see some lagging '~'s. + let pres = getpos(".") + + exe $ + + let _scr = &scrolloff + let &scrolloff = 0 + + normal! z- + + let &scrolloff = _scr + + call setpos(".", pres) +endfunction +"1}}} + +" vim:ft=vim foldmethod=marker sw=2 diff --git a/vim/plugin/pydoc.vim b/vim/plugin/pydoc.vim new file mode 100644 index 0000000..06ab856 --- /dev/null +++ b/vim/plugin/pydoc.vim @@ -0,0 +1,78 @@ +"pydoc.vim: pydoc integration for vim +"performs searches and can display the documentation of python modules +"Author: André Kelpe +"http://www.vim.org/scripts/script.php?script_id=910 +"This plugin integrates the pydoc into vim. You can view the +"documentation of a module by using :Pydoc foo.bar.baz or search +"a word (uses pydoc -k) in the documentation by typing PydocSearch +"foobar. You can also view the documentation of the word under the +"cursor by pressing pw or the WORD (see :help WORD) by pressing +"pW. "This is very useful if you want to jump to a module which was found by +"PydocSearch. To have a browser like feeling you can use u and CTRL-R to +"go back and forward, just like editing normal text. + +"If you want to use the script and pydoc is not in your PATH, just put a +"line like + +" let g:pydoc_cmd = \"/usr/bin/pydoc" (without the backslash!!) + +"in your .vimrc + + +"pydoc.vim is free software, you can redistribute or modify +"it under the terms of the GNU General Public License Version 2 or any +"later Version (see http://www.gnu.org/copyleft/gpl.html for details). + +"Please feel free to contact me. + + +set switchbuf=useopen +function! ShowPyDoc(name, type) + if !exists('g:pydoc_cmd') + let g:pydoc_cmd = 'pydoc' + endif + if bufnr("__doc__") >0 + exe "sb __doc__" + else + exe 'split __doc__' + endif + setlocal noswapfile + set buftype=nofile + setlocal modifiable + normal ggdG + let s:name2 = substitute(a:name, '(.*', '', 'g' ) + if a:type==1 + execute "silent read ! " g:pydoc_cmd . " " . s:name2 + else + execute "silent read ! ".g:pydoc_cmd. " -k " . s:name2 + endif + setlocal nomodified + set filetype=man + normal 1G + if !exists('g:pydoc_highlight') + let g:pydoc_highlight = 1 + endif + if g:pydoc_highlight ==1 + call Highlight(s:name2) + endif +endfunction + + +function! Highlight(name) + exe "sb __doc__" + set filetype=man + syn on + exe 'syntax keyword pydoc '.s:name2 + hi pydoc gui=reverse + +endfunction + + + + +"mappings +map pw :call ShowPyDoc('', 1) +map pW :call ShowPyDoc('', 1) +"commands +command -nargs=1 Pydoc :call ShowPyDoc('', 1) +command -nargs=* PydocSearch :call ShowPyDoc('', 0) diff --git a/vim/skeleton.vim b/vim/plugin/skeleton.vim similarity index 94% rename from vim/skeleton.vim rename to vim/plugin/skeleton.vim index cc3cde6..b4f766f 100644 --- a/vim/skeleton.vim +++ b/vim/plugin/skeleton.vim @@ -1,5 +1,3 @@ -" TEMPLATE SYSTEM FOR VIM -" " Preserve template files augroup newfiles " First we load templates for the file type @@ -18,7 +16,7 @@ augroup newfiles endif " Set up python support - au FileType python source ~/.vim/addon/python.vim + "au FileType python source ~/.vim/addon/python.vim augroup END diff --git a/vim/plugin/taglist.vim b/vim/plugin/taglist.vim new file mode 100644 index 0000000..114cc14 --- /dev/null +++ b/vim/plugin/taglist.vim @@ -0,0 +1,2845 @@ +" File: taglist.vim +" Author: Yegappan Lakshmanan (yegappan AT yahoo DOT com) +" Version: 3.4 +" Last Modified: August 15, 2004 +" +" The "Tag List" plugin is a source code browser plugin for Vim and +" provides an overview of the structure of source code 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://www.geocities.com/yegappan/taglist +" +" 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/doc/vimfiles directory, start Vim and run the ":helptags ." +" command to process the taglist help file. +" 3. 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 ":Tlist" 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 ************************ +if exists('loaded_taglist') || &cp + finish +endif +let loaded_taglist='yes' + +" Location of the exuberant ctags tool +if !exists('Tlist_Ctags_Cmd') + if executable('exuberant-ctags') + let Tlist_Ctags_Cmd = 'exuberant-ctags' + 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.' + " Taglist plugin functionality is not available + finish + endif +endif + +" Taglist plugin functionality is available +let loaded_taglist = 'available' + +" 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 + +" Automatically open the taglist window on Vim startup +if !exists('Tlist_Auto_Open') + let Tlist_Auto_Open = 0 +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 + +" Automatically highlight the current tag +if !exists('Tlist_Auto_Highlight_Tag') + let Tlist_Auto_Highlight_Tag = 1 +endif + +" Process files even when the taglist window is not open +if !exists('Tlist_Process_File_Always') + let Tlist_Process_File_Always = 0 +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 + +"------------------- end of user configurable options -------------------- + +" Initialize the taglist plugin local variables for the supported file types +" and tag types + +" 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++;v:variable;d:macro;t:typedef;c:class;' . + \ 'n:namespace;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;p:package;s:subroutine' + +" php language +let s:tlist_def_php_settings = 'php;c:class;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;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;P:parameter;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 or not +let s:tlist_winsize_chgd = 0 +" Taglist window is maximized or not +let s:tlist_win_maximized = 0 +" Number of files displayed in the taglist window +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 deleted on user request +let s:tlist_deleted_flist = "" +let s:tlist_cur_file_idx = -1 +" 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__" + +" 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_Display_Help() +function! s:Tlist_Display_Help() + if s:tlist_app_name == "winmanager" + " To handle a bug in the winmanager plugin, add a space at the + " last line + call setline('$', ' ') + endif + + if s:tlist_brief_help + " Add the brief help + call append(0, '" Press ? to display help text') + else + " Add the extensive help + call append(0, '" : Jump to tag definition') + call append(1, '" o : Jump to tag definition in new window') + call append(2, '" p : Preview the tag definition') + call append(3, '" : Display tag prototype') + call append(4, '" u : Update tag list') + call append(5, '" s : Select sort field') + call append(6, '" d : Remove file from taglist') + call append(7, '" x : Zoom-out/Zoom-in taglist window') + call append(8, '" + : Open a fold') + call append(9, '" - : Close a fold') + call append(10, '" * : Open all folds') + call append(11, '" = : Close all folds') + call append(12, '" [[ : Move to the start of previous file') + call append(13, '" ]] : Move to the start of next file') + call append(14, '" q : Close the taglist window') + call append(15, '" ? : Remove help text') + endif +endfunction + +" Tlist_Toggle_Help_Text() +" Toggle taglist plugin help text between the full version and the brief +" version +function! s:Tlist_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_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_Update_Line_Offsets(0, 0, full_help_size - brief_help_size) + endif + + call s:Tlist_Display_Help() + + " Restore the report option + let &report = old_report + + setlocal nomodifiable +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 + +" Tlist_Get_File_Index() +" Return the index of the specified filename +function! s:Tlist_Get_File_Index(fname) + let i = 0 + + " Do a linear search + while i < s:tlist_file_count + if s:tlist_{i}_filename == a:fname + return i + endif + let i = i + 1 + endwhile + + return -1 +endfunction + +" Tlist_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_Get_File_Index_By_Linenum(lnum) + let i = 0 + + " TODO: Convert this to a binary search + while i < s:tlist_file_count + if a:lnum >= s:tlist_{i}_start && a:lnum <= s:tlist_{i}_end + return i + endif + let i = i + 1 + endwhile + + return -1 +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 + if a:filename == '' + return 1 + endif + + " Skip buffers with filetype not set + if 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_FileType_Init +" Initialize the ctags arguments and tag variable for the specified +" file type +function! s:Tlist_FileType_Init(ftype) + " If the user didn't specify any settings, then use the default + " ctags args. Otherwise, use the settings specified by the user + let var = 'g:tlist_' . a:ftype . '_settings' + if exists(var) + " User specified ctags arguments + let settings = {var} . ';' + else + " Default ctags arguments + let var = 's:tlist_def_' . a:ftype . '_settings' + if !exists(var) + " No default settings for this file type. This filetype is + " not supported + return 0 + endif + let settings = s:tlist_def_{a:ftype}_settings . ';' + endif + + let msg = 'Taglist: Invalid ctags option setting - ' . settings + + " Format of the option that specifies the filetype and ctags arugments: + " + " ;flag1:name1;flag2:name2;flag3:name3 + " + + " Extract the file type to pass to ctags. This may be different from the + " file type detected by Vim + let pos = stridx(settings, ';') + if pos == -1 + call s:Tlist_Warning_Msg(msg) + return 0 + endif + let ctags_ftype = strpart(settings, 0, pos) + if ctags_ftype == '' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + " Make sure a valid filetype is supplied. If the user didn't specify a + " valid filetype, then the ctags option settings may be treated as the + " filetype + if ctags_ftype =~ ':' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + + " Remove the file type from settings + let settings = strpart(settings, pos + 1) + if settings == '' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + + " Process all the specified ctags flags. The format is + " flag1:name1;flag2:name2;flag3:name3 + let ctags_flags = '' + let cnt = 0 + while settings != '' + " Extract the flag + let pos = stridx(settings, ':') + if pos == -1 + call s:Tlist_Warning_Msg(msg) + return 0 + endif + let flag = strpart(settings, 0, pos) + if flag == '' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + " Remove the flag from settings + let settings = strpart(settings, pos + 1) + + " Extract the tag type name + let pos = stridx(settings, ';') + if pos == -1 + call s:Tlist_Warning_Msg(msg) + return 0 + endif + let name = strpart(settings, 0, pos) + if name == '' + call s:Tlist_Warning_Msg(msg) + return 0 + endif + let settings = strpart(settings, pos + 1) + + let cnt = cnt + 1 + + let s:tlist_{a:ftype}_{cnt}_name = flag + let s:tlist_{a:ftype}_{cnt}_fullname = name + let ctags_flags = ctags_flags . flag + endwhile + + let s:tlist_{a:ftype}_ctags_args = '--language-force=' . ctags_ftype . + \ ' --' . ctags_ftype . '-types=' . ctags_flags + let s:tlist_{a:ftype}_count = cnt + let s:tlist_{a:ftype}_ctags_flags = ctags_flags + + " Save the filetype name + let s:tlist_ftype_{s:tlist_ftype_count}_name = a:ftype + let s:tlist_ftype_count = s:tlist_ftype_count + 1 + + return 1 +endfunction + +" Tlist_Discard_TagInfo +" Discard the stored tag information for a file +function! s:Tlist_Discard_TagInfo(fidx) + 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 + unlet! s:tlist_{a:fidx}_tag_{i} + let i = i + 1 + endwhile + + let s:tlist_{a:fidx}_tag_count = 0 + + " Discard information about tags groups by their type + let i = 1 + while i <= s:tlist_{ftype}_count + let ttype = s:tlist_{ftype}_{i}_name + if s:tlist_{a:fidx}_{ttype} != '' + let s:tlist_{a:fidx}_{ttype} = '' + let s:tlist_{a:fidx}_{ttype}_start = 0 + let cnt = s:tlist_{a:fidx}_{ttype}_count + let s:tlist_{a:fidx}_{ttype}_count = 0 + let j = 1 + while j <= cnt + unlet! s:tlist_{a:fidx}_{ttype}_{j} + let j = j + 1 + endwhile + endif + let i = i + 1 + endwhile +endfunction + +" Tlist_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_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_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}_start + 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 +endfunction + +" Tlist_Remove_File_From_Display +" Remove the specified file from display +function! s:Tlist_Remove_File_From_Display(fidx) + " 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_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_Get_File_Index_By_Linenum(line('.')) + if fidx == -1 + return + endif + endif + + call s:Tlist_Remove_File_From_Display(fidx) + + if a:user_request + " As the user requested to remove the file from taglist, + " add it to the removed list + let s:tlist_deleted_flist = s:tlist_deleted_flist . + \ s:tlist_{fidx}_filename . "\n" + endif + + 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 k = 1 + while k <= s:tlist_{j}_tag_count + let s:tlist_{j}_tag_{k} = s:tlist_{i}_tag_{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}_start = s:tlist_{i}_{ttype}_start + 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 are displayed and if we just + " now removed the 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_Open_Window +" Create a new taglist window. If it is already open, jump to it +function! s:Tlist_Open_Window() + " 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 + " Open a horizontally split window. Increase the window size, if + " needed, to accomodate the new window + if g:Tlist_Inc_Winwidth && + \ &columns < (80 + g:Tlist_WinWidth) + " 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 + + 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 + + " Initialize the taglist window + call s:Tlist_Init_Window() +endfunction + +" Tlist_Zoom_Window +" Zoom (maximize/minimize) the taglist window +function! s:Tlist_Zoom_Window() + 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_Init_Window +" Set the default options for the taglist window +function! s:Tlist_Init_Window() + " Define taglist window element highlighting + if has('syntax') + 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 link TagListTagName Search + endif + " Colors to highlight comments and titles + if hlexists('MyTagListComment') + highlight link TagListComment MyTagListComment + else + highlight clear TagListComment + highlight link TagListComment Comment + endif + if hlexists('MyTagListTitle') + highlight link TagListTitle MyTagListTitle + else + highlight clear TagListTitle + highlight link TagListTitle Title + endif + if hlexists('MyTagListFileName') + highlight link TagListFileName MyTagListFileName + else + highlight clear TagListFileName + highlight link TagListFileName LineNr + endif + if hlexists('MyTagListTagScope') + highlight link TagListTagScope MyTagListTagScope + else + highlight clear TagListTagScope + highlight link TagListTagScope Identifier + endif + else + highlight TagListTagName term=reverse cterm=reverse + endif + endif + + " Folding related settings + if has('folding') + setlocal foldenable + setlocal foldminlines=0 + setlocal foldmethod=manual + if g:Tlist_Enable_Fold_Column + setlocal foldcolumn=3 + else + setlocal foldcolumn=0 + endif + setlocal foldtext=v:folddashes.getline(v:foldstart) + endif + + 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 + + " Create buffer local mappings for jumping to the tags and sorting the list + nnoremap :call Tlist_Jump_To_Tag(0) + nnoremap o :call Tlist_Jump_To_Tag(1) + nnoremap p :call Tlist_Jump_To_Tag(2) + nnoremap <2-LeftMouse> :call Tlist_Jump_To_Tag(0) + nnoremap s :call Tlist_Change_Sort() + nnoremap + :silent! foldopen + nnoremap - :silent! foldclose + nnoremap * :silent! %foldopen! + nnoremap = :silent! %foldclose + nnoremap :silent! foldopen + nnoremap :silent! foldclose + nnoremap :silent! %foldopen! + nnoremap :call Tlist_Show_Tag_Prototype() + nnoremap u :call Tlist_Update_Window() + nnoremap d :call Tlist_Remove_File(-1, 1) + nnoremap x :call Tlist_Zoom_Window() + nnoremap [[ :call Tlist_Move_To_File(-1) + nnoremap ]] :call Tlist_Move_To_File(1) + nnoremap ? :call Tlist_Toggle_Help_Text() + nnoremap q :close + + " Insert mode mappings + inoremap :call Tlist_Jump_To_Tag(0) + " Windows needs return + inoremap :call Tlist_Jump_To_Tag(0) + inoremap o :call Tlist_Jump_To_Tag(1) + inoremap p :call Tlist_Jump_To_Tag(2) + inoremap <2-LeftMouse> :call + \ Tlist_Jump_To_Tag(0) + inoremap s :call Tlist_Change_Sort() + inoremap + :silent! foldopen + inoremap - :silent! foldclose + inoremap * :silent! %foldopen! + inoremap = :silent! %foldclose + inoremap :silent! foldopen + inoremap :silent! foldclose + inoremap :silent! %foldopen! + inoremap :call + \ Tlist_Show_Tag_Prototype() + inoremap u :call Tlist_Update_Window() + inoremap d :call Tlist_Remove_File(-1, 1) + inoremap x :call Tlist_Zoom_Window() + inoremap [[ :call Tlist_Move_To_File(-1) + inoremap ]] :call Tlist_Move_To_File(1) + inoremap ? :call Tlist_Toggle_Help_Text() + inoremap q :close + + " Map single left mouse click if the user wants this functionality + if g:Tlist_Use_SingleClick == 1 + " Contributed by Bindu Wavell + " attempt to perform single click mapping, it would be much + " nicer if we could nnoremap ... however vim does + " not fire the when you use the mouse + " to enter a buffer. + let clickmap = ':if bufname("%") =~ "__Tag_List__" ' . + \ 'call Tlist_Jump_To_Tag(0) endif ' + if maparg('', 'n') == '' + " no mapping for leftmouse + exe ':nnoremap ' . clickmap + else + " we have a mapping + let mapcmd = ':nnoremap ' + let mapcmd = mapcmd . substitute(substitute( + \ maparg('', 'n'), '|', '', 'g'), + \ '\c^', '', '') + let mapcmd = mapcmd . clickmap + exe mapcmd + endif + endif + + " Define the taglist autocommands + augroup TagListAutoCmds + autocmd! + " Display the tag prototype for the tag under the cursor. + autocmd CursorHold __Tag_List__ call s:Tlist_Show_Tag_Prototype() + " Highlight the current tag + autocmd CursorHold * silent call Tlist_Highlight_Tag( + \ fnamemodify(bufname('%'), ':p'), line('.'), 1) + " Adjust the Vim window width when taglist window is closed + autocmd BufUnload __Tag_List__ call Tlist_Post_Close_Cleanup() + " Close the fold for this buffer when it's not visible in any window + autocmd BufWinLeave * silent call Tlist_Update_File_Display( + \ fnamemodify(expand(''), ':p'), 1) + " Remove the file from the list when it's buffer is deleted + autocmd BufDelete * silent call Tlist_Update_File_Display( + \ fnamemodify(expand(''), ':p'), 2) + " Exit Vim itself if only the taglist window is present (optional) + autocmd BufEnter __Tag_List__ call Tlist_Check_Only_Window() + if s:tlist_app_name != "winmanager" && !g:Tlist_Process_File_Always + " Auto refresh the taglist window + autocmd BufEnter * call Tlist_Refresh() + endif + augroup end +endfunction + +" Tlist_Refresh_Window +" Display the tags for all the files in the taglist window +function! s:Tlist_Refresh_Window() + " 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 _ + + if g:Tlist_Compact_Format == 0 + " Display help in non-compact mode + call s:Tlist_Display_Help() + endif + + " Mark the buffer as not modifiable + setlocal nomodifiable + + " Restore the report option + let &report = old_report + + if !g:Tlist_Show_One_File + " 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 + " Mark the file as not visible, so that Tlist_Explore_File() will + " display the tags for this file and mark the file as visible + let s:tlist_{i}_visible = 0 + call s:Tlist_Explore_File(s:tlist_{i}_filename, + \ s:tlist_{i}_filetype) + let i = i + 1 + endwhile + + " If Tlist_File_Fold_Auto_Close option is set, then close all the + " folds + if g:Tlist_File_Fold_Auto_Close + if has('folding') + " Close all the folds + silent! %foldclose + endif + endif + endif +endfunction + +" Tlist_Post_Close_Cleanup() +" Close the taglist window and adjust the Vim window width +function! s: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 + + if has('syntax') + silent! syntax clear TagListTitle + silent! syntax clear TagListComment + silent! syntax clear TagListTagScope + endif + + " Remove the left mouse click mapping if it was setup initially + if g:Tlist_Use_SingleClick + if hasmapto('') + nunmap + endif + endif + + if s:tlist_app_name != "winmanager" + if g:Tlist_Use_Horiz_Window || g:Tlist_Inc_Winwidth == 0 || + \ s:tlist_winsize_chgd == 0 || + \ &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 + " Adjust the Vim window width + let &columns= &columns - (g:Tlist_WinWidth + 1) + endif + endif + + " Reset taglist state variables + if s:tlist_app_name == "winmanager" + let s:tlist_app_name = "none" + let s:tlist_window_initialized = 0 + endif +endfunction + +" Tlist_Check_Only_Window +" Check if only the taglist window is opened currently. If the +" Tlist_Exit_OnlyWindow variable is set, then close the taglist window +function! s:Tlist_Check_Only_Window() + if g:Tlist_Exit_OnlyWindow + if winbufnr(2) == -1 && bufname(winbufnr(1)) == g:TagList_title + " If only the taglist window is currently open, then the buffer + " number associated with window 2 will be -1. + quit + endif + endif +endfunction + +" Tlist_Explore_File() +" List the tags defined in the specified file in a Vim window +function! s:Tlist_Explore_File(filename, ftype) + " First check whether the file already exists + let fidx = s:Tlist_Get_File_Index(a:filename) + if fidx != -1 + let file_exists = 1 + else + let file_exists = 0 + endif + + if !file_exists + " Check whether this file is removed based on user request + " If it is, then don't display the tags for this file + let esc_fname = escape(a:filename, '\') . "\n" + if match(s:tlist_deleted_flist, esc_fname) != -1 + return + endif + endif + + if file_exists && 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 has('folding') + 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_Remove_File_From_Display(fidx) + endif + + " Process and generate a list of tags defined in the file + if !file_exists || !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_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 + while i <= s:tlist_{a:ftype}_count + let ttype = s:tlist_{a:ftype}_{i}_name + " Add the tag type only if there are tags for that type + if s:tlist_{fidx}_{ttype} != '' + 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 =s:tlist_{fidx}_{ttype} + + if g:Tlist_Compact_Format + exe (line('.') + s:tlist_{fidx}_{ttype}_count) + endif + + let s:tlist_{fidx}_{ttype}_start = ttype_start_lnum - file_start + + " create a fold for this tag type + if has('folding') + let fold_start = ttype_start_lnum + let fold_end = fold_start + s:tlist_{fidx}_{ttype}_count + exe fold_start . ',' . fold_end . 'fold' + endif + + if g:Tlist_Compact_Format == 0 + silent! put ='' + endif + endif + let i = i + 1 + endwhile + + if s:tlist_{fidx}_tag_count == 0 + put ='' + endif + + let s:tlist_{fidx}_end = line('.') - 1 + + " Create a fold for the entire file + if has('folding') + exe s:tlist_{fidx}_start . ',' . s:tlist_{fidx}_end . 'fold' + exe 'silent! ' . s:tlist_{fidx}_start . ',' . + \ s:tlist_{fidx}_end . 'foldopen!' + endif + + " 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_Update_Line_Offsets(fidx + 1, 1, end - start + 1) + + return +endfunction + +" Tlist_Init_File +" Initialize the variables for a new file +function! s:Tlist_Init_File(filename, ftype) + " 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 + + " 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 + + " 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}_start = 0 + let s:tlist_{fidx}_{ttype}_count = 0 + let i = i + 1 + endwhile + + return fidx +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) + " Check for valid filename and valid filetype + if a:filename == '' || !filereadable(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 . '"' + + " 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 myshellslash = &shellslash + set noshellslash + endif + + " 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 = myshellslash + endif + + " Handle errors + if v:shell_error && cmd_output != '' + let msg = "Taglist: Failed to generate tags for " . a:filename + call s:Tlist_Warning_Msg(msg) + call s:Tlist_Warning_Msg(cmd_output) + return fidx + endif + + " No tags for current file + if cmd_output == '' + call s:Tlist_Warning_Msg('Taglist: No tags found for ' . a:filename) + return fidx + endif + + " Store the modification time for the file + let s:tlist_{fidx}_mtime = getftime(a:filename) + + " Process the ctags output one line at a time. Separate the tag output + " based on the tag type and store it in the tag type variable + " The format of each line in the ctags output is: + " + " tag_namefile_nameex_cmd;"extension_fields + " + 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) + + if ttype == '' + " Line is not in proper tags format + continue + endif + + " make sure the tag type is supported + if s:tlist_{a:ftype}_ctags_flags !~# ttype + " Tag type is not supported + continue + endif + + " Extract the tag name + if g:Tlist_Display_Prototype == 0 + let ttxt = ' ' . strpart(one_line, 0, stridx(one_line, "\t")) + + " Add the tag scope, if it is available. Tag scope is the last + " field after the 'line:\t' field + if g:Tlist_Display_Tag_Scope " only if it is selected + let tag_scope = s:Tlist_Extract_Tag_Scope(one_line) + if tag_scope != '' + let ttxt = ttxt . ' [' . tag_scope . ']' + endif + endif + else + let ttxt = s:Tlist_Extract_Tag_Prototype(one_line) + endif + + " Update the count of this tag type + let cnt = s:tlist_{fidx}_{ttype}_count + 1 + let s:tlist_{fidx}_{ttype}_count = cnt + + " Add this tag to the tag type variable + let s:tlist_{fidx}_{ttype} = s:tlist_{fidx}_{ttype} . ttxt . "\n" + + " Update the total tag count + let s:tlist_{fidx}_tag_count = s:tlist_{fidx}_tag_count + 1 + " Store the ctags output line and the tagtype count + let s:tlist_{fidx}_tag_{s:tlist_{fidx}_tag_count} = + \ cnt . ':' . one_line + " Store the tag output index + let s:tlist_{fidx}_{ttype}_{cnt} = s:tlist_{fidx}_tag_count + endwhile + + return fidx +endfunction + +" Tlist_Update_File_Tags +" Update the tags for a file (if needed) +function! Tlist_Update_File_Tags(filename, ftype) + " If the file doesn't support tag listing, skip it + if s:Tlist_Skip_File(a:filename, a:ftype) + return + endif + + " First check whether the file already exists + let fidx = s:Tlist_Get_File_Index(a:filename) + + if fidx != -1 && s:tlist_{fidx}_valid + " File exists and the tags are valid + return + else + " Check whether this file is removed based on user request + " If it is, then don't display the tags for this file + let esc_fname = escape(a:filename, '\') . "\n" + if match(s:tlist_deleted_flist, esc_fname) != -1 + return + endif + 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(a:filename, a:ftype) + else + " Save the current window number + let save_winnr = winnr() + + " Goto the taglist window + call s:Tlist_Open_Window() + + " Update the taglist window + call s:Tlist_Explore_File(a:filename, a:ftype) + + if winnr() != save_winnr + " Go back to the original window + exe save_winnr . 'wincmd w' + endif + endif +endfunction + +" Tlist_Close_Window +" Close the taglist window +function! s:Tlist_Close_Window() + " 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_Toggle_Window() +" Open or close a taglist window +function! s:Tlist_Toggle_Window() + let curline = line('.') + + " If taglist window is open then close it. + let winnum = bufwinnr(g:TagList_title) + if winnum != -1 + call s:Tlist_Close_Window() + 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 = getbufvar('%', '&filetype') + + " Mark the current window as the desired window to open a file + " when a tag is selcted + let w:tlist_file_window = "yes" + + " Open the taglist window + call s:Tlist_Open_Window() + + call s:Tlist_Refresh_Window() + + 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_Explore_File(curbuf_name, curbuf_ftype) + endif + else + " Add and list the tags for all the buffers in the bufferlist + let i = 1 + while i < bufnr('$') + let fname = fnamemodify(bufname(i), ':p') + let ftype = getbufvar(i, '&filetype') + " If the file doesn't support tag listing, skip it + if !s:Tlist_Skip_File(fname, ftype) + call s:Tlist_Explore_File(fname, ftype) + endif + let i = i + 1 + endwhile + endif + + " Highlight the current tag + call s:Tlist_Highlight_Tag(curbuf_name, curline, 1) + + " Go back to the original window + let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh + let s:Tlist_Skip_Refresh = 1 + wincmd p + let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh +endfunction + +" Tlist_Extract_Tagtype +" Extract the tag type from the tag text +function! s:Tlist_Extract_Tagtype(tag_txt) + " 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_txt, '/;"' . "\t") + 4 + let end = strridx(a:tag_txt, 'line:') - 1 + let ttype = strpart(a:tag_txt, start, end - start) + + return ttype +endfunction + +" Tlist_Extract_Tag_Prototype +" Extract the tag protoype from the tag text +function! s:Tlist_Extract_Tag_Prototype(tag_txt) + let start = stridx(a:tag_txt, '/^') + 2 + let end = strridx(a:tag_txt, '/;"' . "\t") + " The search patterns for some tag types doesn't end with + " the ;" character + if a:tag_txt[end - 1] == '$' + let end = end -1 + endif + let tag_pat = strpart(a:tag_txt, start, end - start) + + " Remove all the leading space characters + let tag_pat = substitute(tag_pat, '\s*', '', '') + + return tag_pat +endfunction + +" Tlist_Extract_Tag_Scope +" Extract the tag scope from the tag text +function! s:Tlist_Extract_Tag_Scope(tag_txt) + let start = strridx(a:tag_txt, 'line:') + let end = strridx(a:tag_txt, "\t") + if end <= start + return '' + endif + + let tag_scope = strpart(a:tag_txt, 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() + " 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 || (s:tlist_app_name == "winmanager") + return + endif + + " Skip buffers with 'buftype' set to nofile, nowrite, quickfix or help + if &buftype != '' + return + endif + + let filename = fnamemodify(bufname('%'), ':p') + let ftype = &filetype + + " If the file doesn't support tag listing, skip it + if s:Tlist_Skip_File(filename, ftype) + return + endif + + let curline = line('.') + + " Make sure the taglist window is open. Otherwise, no need to refresh + let winnum = bufwinnr(g:TagList_title) + if winnum == -1 + if g:Tlist_Process_File_Always + call Tlist_Update_File_Tags(filename, ftype) + endif + return + endif + + let fidx = s:Tlist_Get_File_Index(filename) + if fidx != -1 + 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 window + call Tlist_Update_File_Tags(s:tlist_{fidx}_filename, + \ s:tlist_{fidx}_filetype) + + " Store the new file modification time + let s:tlist_{fidx}_mtime = mtime + endif + + if s:tlist_{fidx}_visible + " If the tag listing for the current window is already present, no + " need to refresh it + if !g:Tlist_Auto_Highlight_Tag + return + endif + + " Highlight the current tag + call s:Tlist_Highlight_Tag(filename, curline, 1) + + return + endif + endif + + " Save the current window number + let cur_winnr = winnr() + + " Goto the taglist window + call s:Tlist_Open_Window() + + if !g:Tlist_Auto_Highlight_Tag + " Save the cursor position + let save_line = line('.') + let save_col = col('.') + endif + + " Update the taglist window + call s:Tlist_Explore_File(filename, ftype) + + " Highlight the current tag + call s:Tlist_Highlight_Tag(filename, curline, 1) + + if !g:Tlist_Auto_Highlight_Tag + " Restore the cursor position + call cursor(save_line, save_col) + endif + + " Refresh the taglist window + redraw + + if s:tlist_app_name != "winmanager" + " Jump back to the original window + exe cur_winnr . 'wincmd w' + endif +endfunction + +" Tlist_Change_Sort() +" Change the sort order of the tag listing +function! s:Tlist_Change_Sort() + let fidx = s:Tlist_Get_File_Index_By_Linenum(line('.')) + if fidx == -1 + return + endif + + " Remove the previous highlighting + match none + + 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 + + " Save the current line for later restoration + let curline = '\V\^' . getline('.') . '\$' + + " Invalidate the tags listed for this file + let s:tlist_{fidx}_valid = 0 + + call s:Tlist_Explore_File(s:tlist_{fidx}_filename, s:tlist_{fidx}_filetype) + + " Go back to the cursor line before the tag list is sorted + call search(curline, 'w') +endfunction + +" Tlist_Update_Tags() +" Update taglist for the current buffer by regenerating the tag list +" Contributed by WEN Guopeng. +function! s:Tlist_Update_Tags() + if winnr() == bufwinnr(g:TagList_title) + " In the taglist window. Update the current file + call s:Tlist_Update_Window() + return + 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 + else + " As the user requested to update the tags for the current + " file, remove it from the deleted list (if it was previously + " deleted on user request) + let esc_fname = escape(filename, '\') . "\n" + let s:tlist_deleted_flist = substitute(s:tlist_deleted_flist, + \ esc_fname, '', '') + endif + call Tlist_Update_File_Tags(filename, &filetype) + endif +endfunction + +" Tlist_Update_Window() +" Update the window by regenerating the tag list +function! s:Tlist_Update_Window() + let fidx = s:Tlist_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_Explore_File(s:tlist_{fidx}_filename, s:tlist_{fidx}_filetype) + + " Go back to the tag line before the list is updated + call search(curline, 'w') +endfunction + +" Tlist_Get_Tag_Index() +" Return the tag index for the current line +function! s:Tlist_Get_Tag_Index(fidx) + let lnum = line('.') + 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}_start + let end = start_lnum + s:tlist_{a:fidx}_{ttype}_count + if lnum >= start_lnum && 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 0 + endif + + " Compute the index into the displayed tags for the tag type + let tidx = lnum - start_lnum + if tidx == 0 + return 0 + endif + + " Get the corresponding tag line and return it + return s:tlist_{a:fidx}_{ttype}_{tidx} +endfunction + +" Tlist_Highlight_Tagline +" Higlight the current tagline +function! s:Tlist_Highlight_Tagline() + " Clear previously selected name + match none + + " Highlight the current selected name + if g:Tlist_Display_Prototype == 0 + exe 'match TagListTagName /\%' . line('.') . 'l\s\+\zs.*/' + else + exe 'match TagListTagName /\%' . line('.') . 'l.*/' + endif +endfunction + +" Tlist_Jump_To_Tag() +" Jump to the location of the current tag +" win_ctrl == 0 - Reuse the existing file window +" win_ctrl == 1 - Open a new window +" win_ctrl == 2 - Preview the tag +function! s:Tlist_Jump_To_Tag(win_ctrl) + " 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 try to jump to the tag + if foldclosed('.') != -1 + return + endif + + let fidx = s:Tlist_Get_File_Index_By_Linenum(line('.')) + if fidx == -1 + return + endif + + " Get the tag output for the current tag + let tidx = s:Tlist_Get_Tag_Index(fidx) + if tidx != 0 + let mtxt = s:tlist_{fidx}_tag_{tidx} + let start = stridx(mtxt, '/^') + 2 + let end = strridx(mtxt, '/;"' . "\t") + if mtxt[end - 1] == '$' + let end = end - 1 + endif + let tagpat = '\V\^' . strpart(mtxt, start, end - start) . + \ (mtxt[end] == '$' ? '\$' : '') + + " Highlight the tagline + call s:Tlist_Highlight_Tagline() + else + " Selected a line which is not a tag name. Just edit the file + let tagpat = '' + endif + + call s:Tlist_Open_File(a:win_ctrl, s:tlist_{fidx}_filename, tagpat) +endfunction + +" Tlist_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_Open_File(win_ctrl, filename, tagpat) + 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) + else + " Goto the window containing the file. If the window is not there, open a + " new window + let winnum = bufwinnr(a:filename) + if winnum == -1 + " Locate the previously used window for opening a file + let fwin_num = 0 + + let i = 1 + while winbufnr(i) != -1 + if getwinvar(i, 'tlist_file_window') == "yes" + let fwin_num = i + break + endif + let i = i + 1 + endwhile + + 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 == 1 + split + endif + exe "edit " . a:filename + else + " Open a new window + if g:Tlist_Use_Horiz_Window + exe 'leftabove split #' . bufnr(a:filename) + " Go to the taglist window to change the window size to the user + " configured value + wincmd p + exe 'resize ' . g:Tlist_WinHeight + " Go back to the file window + wincmd p + else + " Open the file in a window and skip refreshing the taglist + " window + exe 'rightbelow vertical split #' . bufnr(a:filename) + " Go to the taglist window to change the window size to the user + " configured value + wincmd p + exe 'vertical resize ' . g:Tlist_WinWidth + " Go back to the file window + wincmd p + endif + let w:tlist_file_window = "yes" + endif + else + 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 == 1 + split + endif + endif + endif + + " Jump to the tag + if a:tagpat != '' + silent call search(a:tagpat, 'w') + endif + + " Bring the line to the middle of the window + normal! z. + + " If the line is inside a fold, open the fold + if has('folding') + if foldlevel('.') != 0 + normal! zv + endif + endif + + " If the user selects to preview the tag then jump back to the + " taglist window + if a:win_ctrl == 2 + " Go back to the taglist window + let winnum = bufwinnr(g:TagList_title) + exe winnum . 'wincmd w' + endif + + let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh +endfunction + +" Tlist_Show_Tag_Prototype() +" Display the prototype of the tag under the cursor +function! s:Tlist_Show_Tag_Prototype() + " If we have already display prototype in the tag window, no need to + " display it in the status line + if g:Tlist_Display_Prototype + return + endif + + " 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 + + " Get the file index + let fidx = s:Tlist_Get_File_Index_By_Linenum(line('.')) + if fidx == -1 + return + endif + + " Get the tag output line for the current tag + let tidx = s:Tlist_Get_Tag_Index(fidx) + if tidx == 0 + return + endif + + let mtxt = s:tlist_{fidx}_tag_{tidx} + + " Get the tag search pattern and display it + echo s:Tlist_Extract_Tag_Prototype(mtxt) +endfunction + +" Tlist_Find_Tag_text +" Find the tag text given the line number in the source window +function! s:Tlist_Find_Tag_text(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' + " Tag list sorted by order, do a binary search comparing the line + " numbers and pick a tag entry that contains the current line and + " highlight it. 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 txt = s:tlist_{a:fidx}_tag_1 + " 5 == length of 'line:' + let start = strridx(txt, 'line:') + 5 + let end = strridx(txt, "\t") + if end < start + let first_lnum = strpart(txt, start) + 0 + else + let first_lnum = strpart(txt, start, end - start) + 0 + endif + + if a:linenum < first_lnum + return "" + endif + + while left < right + let middle = (right + left + 1) / 2 + let txt = s:tlist_{a:fidx}_tag_{middle} + + " 5 == length of 'line:' + let start = strridx(txt, 'line:') + 5 + let end = strridx(txt, "\t") + if end < start + let middle_lnum = strpart(txt, start) + 0 + else + let middle_lnum = strpart(txt, start, end - start) + 0 + endif + + 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 + " sorted by name, brute force method (Dave Eggum) + let closest_lnum = 0 + let final_left = 0 + while left < right + let txt = s:tlist_{a:fidx}_tag_{left} + + " 5 == length of 'line:' + let start = strridx(txt, 'line:') + 5 + let end = strridx(txt, "\t") + if end < start + let lnum = strpart(txt, start) + 0 + else + let lnum = strpart(txt, start, end - start) + 0 + endif + + if lnum < a:linenum && lnum > closest_lnum + let closest_lnum = lnum + let final_left = left + elseif lnum == a:linenum + let closest_lnum = lnum + break + else + let left = left + 1 + endif + endwhile + if closest_lnum == 0 + return "" + endif + if left == right + let left = final_left + endif + endif + + return s:tlist_{a:fidx}_tag_{left} +endfunction + +" Tlist_Highlight_Tag() +" Highlight the current tag +" cntx == 1, Called by the taglist plugin itself +" cntx == 2, Forced by the user through the TlistSync command +function! s:Tlist_Highlight_Tag(filename, curline, cntx) + " 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 there are no tags for this file, then no need to proceed further + if s:tlist_{fidx}_tag_count == 0 + return + endif + + " If part of winmanager then disable winmanager autocommands + if s:tlist_app_name == "winmanager" + call WinManagerSuspendAUs() + 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 + + " Go to the taglist window + if !in_taglist_window + exe winnum . 'wincmd w' + endif + + " Clear previously selected name + match none + + let tag_txt = s:Tlist_Find_Tag_text(fidx, a:curline) + if tag_txt == "" + " 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 cur_lnum = line('.') + + if cur_lnum < s:tlist_{fidx}_start || cur_lnum > s:tlist_{fidx}_end + " Move the cursor to the beginning of the file + exe s:tlist_{fidx}_start + endif + + if has('folding') + normal! zv + endif + + call winline() + + if !in_taglist_window + let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh + let s:Tlist_Skip_Refresh = 1 + exe org_winnr . 'wincmd w' + let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh + endif + if s:tlist_app_name == "winmanager" + call WinManagerResumeAUs() + endif + return + endif + + " Extract the tag type + let ttype = s:Tlist_Extract_Tagtype(tag_txt) + + " Extract the tag offset + let offset = strpart(tag_txt, 0, stridx(tag_txt, ':')) + 0 + + " Compute the line number + let lnum = s:tlist_{fidx}_start + s:tlist_{fidx}_{ttype}_start + offset + + " Goto the line containing the tag + exe lnum + + " Open the fold + if has('folding') + normal! zv + endif + + " 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() + + " Highlight the tag name + call s:Tlist_Highlight_Tagline() + + " Go back to the original window + if !in_taglist_window + let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh + let s:Tlist_Skip_Refresh = 1 + exe org_winnr . 'wincmd w' + let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh + endif + + if s:tlist_app_name == "winmanager" + call WinManagerResumeAUs() + endif + + return +endfunction + +" Tlist_Get_Tag_Prototype_By_Line +" Get the prototype for the tag on or before the specified line number in the +" current buffer +function! Tlist_Get_Tag_Prototype_By_Line(...) + if a:0 == 0 + " Arguments are not supplied. Use the current buffer name + " and line number + let filename = bufname('%') + let linenr = line('.') + elseif a:0 == 2 + " Filename and line number are specified + let filename = a:1 + let linenr = a:2 + if linenr !~ '\d\+' + " Invalid line number + return "" + endif + else + " Sufficient arguments are not supplied + let msg = 'Usage: Tlist_Get_Tag_Prototype_By_Line ' . + \ '' + call s:Tlist_Warning_Msg(msg) + return "" + endif + + " Expand the file to a fully qualified name + let filename = fnamemodify(filename, ':p') + if filename == '' + return "" + endif + + let fidx = s:Tlist_Get_File_Index(filename) + if fidx == -1 + return "" + endif + + " If there are no tags for this file, then no need to proceed further + if s:tlist_{fidx}_tag_count == 0 + return "" + endif + + " Get the tag text using the line number + let tag_txt = s:Tlist_Find_Tag_text(fidx, linenr) + if tag_txt == "" + return "" + endif + + " Extract the tag search pattern and return it + return s:Tlist_Extract_Tag_Prototype(tag_txt) +endfunction + +" Tlist_Get_Tagname_By_Line +" Get the tag name on or before the specified line number in the +" current buffer +function! Tlist_Get_Tagname_By_Line(...) + if a:0 == 0 + " Arguments are not supplied. Use the current buffer name + " and line number + let filename = bufname('%') + let linenr = line('.') + elseif a:0 == 2 + " Filename and line number are specified + let filename = a:1 + let linenr = a:2 + if linenr !~ '\d\+' + " Invalid line number + return "" + endif + else + " Sufficient arguments are not supplied + let msg = 'Usage: Tlist_Get_Tagname_By_Line ' + call s:Tlist_Warning_Msg(msg) + return "" + endif + + " Make sure the current file has a name + let filename = fnamemodify(filename, ':p') + if filename == '' + return "" + endif + + let fidx = s:Tlist_Get_File_Index(filename) + if fidx == -1 + return "" + endif + + " If there are no tags for this file, then no need to proceed further + if s:tlist_{fidx}_tag_count == 0 + return "" + endif + + " Get the tag name using the line number + let tag_txt = s:Tlist_Find_Tag_text(fidx, linenr) + if tag_txt == "" + return "" + endif + + " Remove the line number at the beginning + let start = stridx(tag_txt, ':') + 1 + + " Extract the tag name and return it + return strpart(tag_txt, start, stridx(tag_txt, "\t") - start) +endfunction + +" Tlist_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_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_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 + " At the first file, can't move to previous file + return + endif + + " Otherwise, move to the beginning of the previous file + let fidx = fidx - 1 + exe s:tlist_{fidx}_start + return + else + let fidx = fidx + 1 + + if fidx == s:tlist_file_count + " At the last file, can't move to the next file + return + endif + + " Otherwise, move to the beginning of the next file + if s:tlist_{fidx}_start != 0 + exe s:tlist_{fidx}_start + endif + return + endif +endfunction + +" Tlist_Session_Load +" Load a taglist session (information about all the displayed files +" and the tags) from the specified file +function! s:Tlist_Session_Load(...) + if a:0 == 0 || a:1 == '' + call s:Tlist_Warning_Msg('Usage: TlistSessionLoad ') + return + endif + + let sessionfile = a:1 + + if !filereadable(sessionfile) + let msg = 'Taglist: Error - Unable to open file ' . sessionfile + call s:Tlist_Warning_Msg(msg) + return + endif + + " Mark the current window as the file window + if bufname('%') !~ g:TagList_title + let w:tlist_file_window = "yes" + endif + + " Open the taglist window + call s:Tlist_Open_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. + let esc_fname = escape(fname, '\') . "\n" + let s:tlist_deleted_flist = substitute(s:tlist_deleted_flist, + \ esc_fname, '', '') + 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 + " Mark the file as not visible, so that Tlist_Init_Window() function + " will display the tags for this file + let s:tlist_{fidx}_visible = 0 + + 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}_tag_{j} = g:tlist_{i}_tag_{j} + unlet! g:tlist_{i}_tag_{j} + 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}_start = 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}_start = 0 + let s:tlist_{fidx}_{ttype}_count = 0 + endif + + let j = j + 1 + endwhile + + let i = i + 1 + endwhile + + " Initialize the taglist window + call s:Tlist_Refresh_Window() + + " Go back to the original window + let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh + let s:Tlist_Skip_Refresh = 1 + wincmd p + let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh + + call s:Tlist_Refresh() +endfunction + +" Tlist_Session_Save +" Save a taglist session (information about all the displayed files +" and the tags) into the specified file +function! s:Tlist_Session_Save(...) + if a:0 == 0 || a:1 == '' + call s:Tlist_Warning_Msg('Usage: TlistSessionSave ') + return + endif + + let sessionfile = a:1 + + if s:tlist_file_count == 0 + " There is nothing to save + call s:Tlist_Warning_Msg('Warning: Taglist is empty. Nothing to save.') + return + endif + + if filereadable(sessionfile) + let ans = input("Do you want to overwrite " . sessionfile . " (Y/N)?") + if ans !=? 'y' + return + endif + + echo "\n" + endif + + 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}_tag_{j}, '"\\') + silent! echo 'let tlist_' . i . '_tag_' . j . ' = "' . txt . '"' + 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 = substitute(s:tlist_{i}_{ttype}, "\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 +endfunction + +" Tlist_Update_File_Display +" Update a file displayed in the taglist window. +" action == 1, Close the fold for the file +" action == 2, Remove the file from the taglist window +function! s:Tlist_Update_File_Display(filename, action) + " Make sure a valid filename is supplied + 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('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 + + " Go to the taglist window + if !in_taglist_window + exe winnum . 'wincmd w' + endif + + " Get tag list index of the specified file + let idx = s:Tlist_Get_File_Index(a:filename) + if idx != -1 + " Save the cursor position + let save_lnum = line('.') + + " Perform the requested action on the file + if a:action == 1 + " Close the fold for the file + + if g:Tlist_File_Fold_Auto_Close + " Close the fold for the file + if has('folding') + exe "silent! " . s:tlist_{idx}_start . "," . + \ s:tlist_{idx}_end . "foldclose" + endif + endif + elseif a:action == 2 + " Remove the file from the list + call s:Tlist_Remove_File(idx, 0) + endif + + " Move the cursor to the original location + exe save_lnum + endif + + " Go back to the original window + if !in_taglist_window + let prev_Tlist_Skip_Refresh = s:Tlist_Skip_Refresh + let s:Tlist_Skip_Refresh = 1 + exe org_winnr . 'wincmd w' + let s:Tlist_Skip_Refresh = prev_Tlist_Skip_Refresh + endif +endfunction + +" Define the taglist autocommand to automatically open the taglist window on +" Vim startup +if g:Tlist_Auto_Open + autocmd VimEnter * nested Tlist +endif + +" Refresh the taglist +if g:Tlist_Process_File_Always + autocmd BufEnter * call Tlist_Refresh() +endif + +" Define the user commands to manage the taglist window +command! -nargs=0 Tlist call s:Tlist_Toggle_Window() +command! -nargs=0 TlistClose call s:Tlist_Close_Window() +command! -nargs=0 TlistUpdate call s:Tlist_Update_Tags() +command! -nargs=0 TlistSync call s:Tlist_Highlight_Tag( + \ fnamemodify(bufname('%'), ':p'), line('.'), 2) +command! -nargs=* -complete=buffer TlistShowPrototype + \ echo Tlist_Get_Tag_Prototype_By_Line() +command! -nargs=* -complete=buffer TlistShowTag + \ echo Tlist_Get_Tagname_By_Line() +command! -nargs=* -complete=file TlistSessionLoad + \ call s:Tlist_Session_Load() +command! -nargs=* -complete=file TlistSessionSave + \ call s:Tlist_Session_Save() + +" 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 = getbufvar(bufnum, '&filetype') + endif + + " Initialize the taglist window, if it is not already initialized + if !exists("s:tlist_window_initialized") || !s:tlist_window_initialized + call s:Tlist_Init_Window() + call s:Tlist_Refresh_Window() + let s:tlist_window_initialized = 1 + endif + + " Update the taglist window + if bufnum != -1 + if !s:Tlist_Skip_File(filename, ftype) + call s:Tlist_Explore_File(filename, ftype) + endif + endif +endfunction + +function! TagList_IsValid() + return 0 +endfunction + +function! TagList_WrapUp() + return 0 +endfunction diff --git a/vim/syntax/python.vim b/vim/syntax/python.vim new file mode 100644 index 0000000..d47cc16 --- /dev/null +++ b/vim/syntax/python.vim @@ -0,0 +1,299 @@ +" Vim syntax file +" Language: Python +" Maintainer: Dmitry Vasiliev +" URL: http://www.hlabs.spb.ru/vim/python.vim +" Last Change: $Date$ +" Filenames: *.py +" Version: 2.5.5 +" $Rev$ +" +" Based on python.vim (from Vim 6.1 distribution) +" by Neil Schemenauer +" + +" +" Options: +" +" For set option do: let OPTION_NAME = 1 +" For clear option do: let OPTION_NAME = 0 +" +" Option names: +" +" For highlight builtin functions: +" python_highlight_builtins +" +" For highlight standard exceptions: +" python_highlight_exceptions +" +" For highlight string formatting: +" python_highlight_string_formatting +" +" For highlight indentation errors: +" python_highlight_indent_errors +" +" For highlight trailing spaces: +" python_highlight_space_errors +" +" For highlight doc-tests: +" python_highlight_doctests +" +" If you want all possible Python highlighting: +" (This option not override previously set options) +" python_highlight_all +" +" For fast machines: +" python_slow_sync +" + +" For version 5.x: Clear all syntax items +" For version 6.x: Quit when a syntax file was already loaded +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif +let python_highlight_all=1 +let python_slow_sync=1 + +if exists("python_highlight_all") && python_highlight_all != 0 + " Not override previously set options + if !exists("python_highlight_builtins") + let python_highlight_builtins = 1 + endif + if !exists("python_highlight_exceptions") + let python_highlight_exceptions = 1 + endif + if !exists("python_highlight_string_formatting") + let python_highlight_string_formatting = 1 + endif + if !exists("python_highlight_indent_errors") + let python_highlight_indent_errors = 1 + endif + if !exists("python_highlight_space_errors") + let python_highlight_space_errors = 1 + endif + if !exists("python_highlight_doctests") + let python_highlight_doctests = 1 + endif +endif + +" Keywords +syn keyword pythonStatement break continue del +syn keyword pythonStatement exec return +syn keyword pythonStatement pass print raise +syn keyword pythonStatement global assert +syn keyword pythonStatement lambda yield +syn keyword pythonStatement with +syn keyword pythonStatement def class nextgroup=pythonFunction skipwhite +syn match pythonFunction "[a-zA-Z_][a-zA-Z0-9_]*" display contained +syn keyword pythonRepeat for while +syn keyword pythonConditional if elif else +syn keyword pythonImport import from as +syn keyword pythonException try except finally +syn keyword pythonOperator and in is not or + +" Decorators (new in Python 2.4) +syn match pythonDecorator "@" display nextgroup=pythonFunction skipwhite + +" Comments +syn match pythonComment "#.*$" display contains=pythonTodo +syn match pythonRun "\%^#!.*$" +syn match pythonCoding "\%^.*\(\n.*\)\?#.*coding[:=]\s*[0-9A-Za-z-_.]\+.*$" +syn keyword pythonTodo TODO FIXME XXX contained + +" Errors +syn match pythonError "\<\d\+\D\+\>" display +syn match pythonError "[$?]" display +syn match pythonError "[-+&|]\{2,}" display +syn match pythonError "[=]\{3,}" display + +" TODO: Mixing spaces and tabs also may be used for pretty formatting multiline +" statements. For now I don't know how to work around this. +if exists("python_highlight_indent_errors") && python_highlight_indent_errors != 0 + syn match pythonIndentError "^\s*\( \t\|\t \)\s*\S"me=e-1 display +endif + +" Trailing space errors +if exists("python_highlight_space_errors") && python_highlight_space_errors != 0 + syn match pythonSpaceError "\s\+$" display +endif + +" Strings +syn region pythonString start=+'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end=+$+ keepend contains=pythonEscape,pythonEscapeError +syn region pythonString start=+"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=pythonEscape,pythonEscapeError +syn region pythonString start=+"""+ end=+"""+ keepend contains=pythonEscape,pythonEscapeError,pythonDocTest2,pythonSpaceError +syn region pythonString start=+'''+ end=+'''+ keepend contains=pythonEscape,pythonEscapeError,pythonDocTest,pythonSpaceError + +syn match pythonEscape +\\[abfnrtv'"\\]+ display contained +syn match pythonEscape "\\\o\o\=\o\=" display contained +syn match pythonEscapeError "\\\o\{,2}[89]" display contained +syn match pythonEscape "\\x\x\{2}" display contained +syn match pythonEscapeError "\\x\x\=\X" display contained +syn match pythonEscape "\\$" + +" Unicode strings +syn region pythonUniString start=+[uU]'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end=+$+ keepend contains=pythonEscape,pythonUniEscape,pythonEscapeError,pythonUniEscapeError +syn region pythonUniString start=+[uU]"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=pythonEscape,pythonUniEscape,pythonEscapeError,pythonUniEscapeError +syn region pythonUniString start=+[uU]"""+ end=+"""+ keepend contains=pythonEscape,pythonUniEscape,pythonEscapeError,pythonUniEscapeError,pythonDocTest2,pythonSpaceError +syn region pythonUniString start=+[uU]'''+ end=+'''+ keepend contains=pythonEscape,pythonUniEscape,pythonEscapeError,pythonUniEscapeError,pythonDocTest,pythonSpaceError + +syn match pythonUniEscape "\\u\x\{4}" display contained +syn match pythonUniEscapeError "\\u\x\{,3}\X" display contained +syn match pythonUniEscape "\\U\x\{8}" display contained +syn match pythonUniEscapeError "\\U\x\{,7}\X" display contained +syn match pythonUniEscape "\\N{[A-Z ]\+}" display contained +syn match pythonUniEscapeError "\\N{[^A-Z ]\+}" display contained + +" Raw strings +syn region pythonRawString start=+[rR]'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end=+$+ keepend contains=pythonRawEscape +syn region pythonRawString start=+[rR]"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=pythonRawEscape +syn region pythonRawString start=+[rR]"""+ end=+"""+ keepend contains=pythonDocTest2,pythonSpaceError +syn region pythonRawString start=+[rR]'''+ end=+'''+ keepend contains=pythonDocTest,pythonSpaceError + +syn match pythonRawEscape +\\['"]+ display transparent contained + +" Unicode raw strings +syn region pythonUniRawString start=+[uU][rR]'+ skip=+\\\\\|\\'\|\\$+ excludenl end=+'+ end=+$+ keepend contains=pythonRawEscape,pythonUniRawEscape,pythonUniRawEscapeError +syn region pythonUniRawString start=+[uU][rR]"+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end=+$+ keepend contains=pythonRawEscape,pythonUniRawEscape,pythonUniRawEscapeError +syn region pythonUniRawString start=+[uU][rR]"""+ end=+"""+ keepend contains=pythonUniRawEscape,pythonUniRawEscapeError,pythonDocTest2,pythonSpaceError +syn region pythonUniRawString start=+[uU][rR]'''+ end=+'''+ keepend contains=pythonUniRawEscape,pythonUniRawEscapeError,pythonDocTest,pythonSpaceError + +syn match pythonUniRawEscape "\([^\\]\(\\\\\)*\)\@<=\\u\x\{4}" display contained +syn match pythonUniRawEscapeError "\([^\\]\(\\\\\)*\)\@<=\\u\x\{,3}\X" display contained + +if exists("python_highlight_string_formatting") && python_highlight_string_formatting != 0 + " String formatting + syn match pythonStrFormat "%\(([^)]\+)\)\=[-#0 +]*\d*\(\.\d\+\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonUniString,pythonRawString,pythonUniRawString + syn match pythonStrFormat "%[-#0 +]*\(\*\|\d\+\)\=\(\.\(\*\|\d\+\)\)\=[hlL]\=[diouxXeEfFgGcrs%]" contained containedin=pythonString,pythonUniString,pythonRawString,pythonUniRawString +endif + +if exists("python_highlight_doctests") && python_highlight_doctests != 0 + " DocTests + syn region pythonDocTest start="^\s*>>>" end=+'''+he=s-1 end="^\s*$" contained + syn region pythonDocTest2 start="^\s*>>>" end=+"""+he=s-1 end="^\s*$" contained +endif + +" Numbers (ints, longs, floats, complex) +syn match pythonHexNumber "\<0[xX]\x\+[lL]\=\>" display +syn match pythonHexNumber "\<0[xX]\>" display +syn match pythonNumber "\<\d\+[lLjJ]\=\>" display +syn match pythonFloat "\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>" display +syn match pythonFloat "\<\d\+[eE][+-]\=\d\+[jJ]\=\>" display +syn match pythonFloat "\<\d\+\.\d*\([eE][+-]\=\d\+\)\=[jJ]\=" display + +syn match pythonOctalError "\<0\o*[89]\d*[lL]\=\>" display +syn match pythonHexError "\<0[xX]\X\+[lL]\=\>" display + +if exists("python_highlight_builtins") && python_highlight_builtins != 0 + " Builtin functions, types and objects + syn keyword pythonBuiltinObj True False Ellipsis None NotImplemented + + syn keyword pythonBuiltinFunc __import__ abs all any apply + syn keyword pythonBuiltinFunc basestring bool buffer callable + syn keyword pythonBuiltinFunc chr classmethod cmp coerce compile complex + syn keyword pythonBuiltinFunc delattr dict dir divmod enumerate eval + syn keyword pythonBuiltinFunc execfile file filter float frozenset getattr + syn keyword pythonBuiltinfunc globals hasattr hash help hex id + syn keyword pythonBuiltinFunc input int intern isinstance + syn keyword pythonBuiltinFunc issubclass iter len list locals long map max + syn keyword pythonBuiltinFunc min object oct open ord pow property range + syn keyword pythonBuiltinFunc raw_input reduce reload repr + syn keyword pythonBuiltinFunc reversed round set setattr + syn keyword pythonBuiltinFunc slice sorted staticmethod str sum super tuple + syn keyword pythonBuiltinFunc type unichr unicode vars xrange zip +endif + +if exists("python_highlight_exceptions") && python_highlight_exceptions != 0 + " Builtin exceptions and warnings + syn keyword pythonExClass BaseException + syn keyword pythonExClass Exception StandardError ArithmeticError + syn keyword pythonExClass LookupError EnvironmentError + + syn keyword pythonExClass AssertionError AttributeError EOFError + syn keyword pythonExClass FloatingPointError GeneratorExit IOError + syn keyword pythonExClass ImportError IndexError KeyError + syn keyword pythonExClass KeyboardInterrupt MemoryError NameError + syn keyword pythonExClass NotImplementedError OSError OverflowError + syn keyword pythonExClass ReferenceError RuntimeError StopIteration + syn keyword pythonExClass SyntaxError IndentationError TabError + syn keyword pythonExClass SystemError SystemExit TypeError + syn keyword pythonExClass UnboundLocalError UnicodeError + syn keyword pythonExClass UnicodeEncodeError UnicodeDecodeError + syn keyword pythonExClass UnicodeTranslateError ValueError + syn keyword pythonExClass WindowsError ZeroDivisionError + + syn keyword pythonExClass Warning UserWarning DeprecationWarning + syn keyword pythonExClass PendingDepricationWarning SyntaxWarning + syn keyword pythonExClass RuntimeWarning FutureWarning OverflowWarning + syn keyword pythonExClass ImportWarning UnicodeWarning +endif + +if exists("python_slow_sync") && python_slow_sync != 0 + syn sync minlines=2000 +else + " This is fast but code inside triple quoted strings screws it up. It + " is impossible to fix because the only way to know if you are inside a + " triple quoted string is to start from the beginning of the file. + syn sync match pythonSync grouphere NONE "):$" + syn sync maxlines=200 +endif + +if version >= 508 || !exists("did_python_syn_inits") + if version <= 508 + let did_python_syn_inits = 1 + command -nargs=+ HiLink hi link + else + command -nargs=+ HiLink hi def link + endif + + HiLink pythonStatement Statement + HiLink pythonImport Statement + HiLink pythonFunction Function + HiLink pythonConditional Conditional + HiLink pythonRepeat Repeat + HiLink pythonException Exception + HiLink pythonOperator Operator + + HiLink pythonDecorator Define + + HiLink pythonComment Comment + HiLink pythonCoding Special + HiLink pythonRun Special + HiLink pythonTodo Todo + + HiLink pythonError Error + HiLink pythonIndentError Error + HiLink pythonSpaceError Error + + HiLink pythonString String + HiLink pythonUniString String + HiLink pythonRawString String + HiLink pythonUniRawString String + + HiLink pythonEscape Special + HiLink pythonEscapeError Error + HiLink pythonUniEscape Special + HiLink pythonUniEscapeError Error + HiLink pythonUniRawEscape Special + HiLink pythonUniRawEscapeError Error + + HiLink pythonStrFormat Special + + HiLink pythonDocTest Special + HiLink pythonDocTest2 Special + + HiLink pythonNumber Number + HiLink pythonHexNumber Number + HiLink pythonFloat Float + HiLink pythonOctalError Error + HiLink pythonHexError Error + + HiLink pythonBuiltinObj Structure + HiLink pythonBuiltinFunc Function + + HiLink pythonExClass Structure + + delcommand HiLink +endif + +let b:current_syntax = "python"