citadel

My dotfiles, scripts and nix configs
git clone git://jb55.com/citadel
Log | Files | Refs | README | LICENSE

a.vim (31424B)


      1 " Copyright (c) 1998-2006
      2 " Michael Sharpe <feline@irendi.com>
      3 "
      4 " We grant permission to use, copy modify, distribute, and sell this
      5 " software for any purpose without fee, provided that the above copyright
      6 " notice and this text are not removed. We make no guarantee about the
      7 " suitability of this software for any purpose and we are not liable
      8 " for any damages resulting from its use. Further, we are under no
      9 " obligation to maintain or extend this software. It is provided on an
     10 " "as is" basis without any expressed or implied warranty.
     11 
     12 " Directory & regex enhancements added by Bindu Wavell who is well known on
     13 " vim.sf.net
     14 "
     15 " Patch for spaces in files/directories from Nathan Stien (also reported by
     16 " Soeren Sonnenburg)
     17 
     18 " Do not load a.vim if is has already been loaded.
     19 if exists("loaded_alternateFile")
     20     finish
     21 endif
     22 if (v:progname == "ex")
     23    finish
     24 endif
     25 let loaded_alternateFile = 1
     26 
     27 let alternateExtensionsDict = {}
     28 
     29 " setup the default set of alternate extensions. The user can override in thier
     30 " .vimrc if the defaults are not suitable. To override in a .vimrc simply set a
     31 " g:alternateExtensions_<EXT> variable to a comma separated list of alternates,
     32 " where <EXT> is the extension to map.
     33 " E.g. let g:alternateExtensions_CPP = "inc,h,H,HPP,hpp"
     34 "      let g:alternateExtensions_{'aspx.cs'} = "aspx"
     35 
     36 
     37 " This variable will be increased when an extension with greater number of dots
     38 " is added by the AddAlternateExtensionMapping call.
     39 let s:maxDotsInExtension = 1
     40 
     41 " Function : AddAlternateExtensionMapping (PRIVATE)
     42 " Purpose  : simple helper function to add the default alternate extension
     43 "            mappings.
     44 " Args     : extension -- the extension to map
     45 "            alternates -- comma separated list of alternates extensions
     46 " Returns  : nothing
     47 " Author   : Michael Sharpe <feline@irendi.com>
     48 function! <SID>AddAlternateExtensionMapping(extension, alternates)
     49    " This code does not actually work for variables like foo{'a.b.c.d.e'}
     50    "let varName = "g:alternateExtensions_" . a:extension
     51    "if (!exists(varName))
     52    "   let g:alternateExtensions_{a:extension} = a:alternates
     53    "endif
     54 
     55    " This code handles extensions which contains a dot. exists() fails with
     56    " such names.
     57    "let v:errmsg = ""
     58    " FIXME this line causes ex to return 1 instead of 0 for some reason??
     59    "silent! echo g:alternateExtensions_{a:extension}
     60    "if (v:errmsg != "")
     61       "let g:alternateExtensions_{a:extension} = a:alternates
     62    "endif
     63 
     64    let g:alternateExtensionsDict[a:extension] = a:alternates
     65    let dotsNumber = strlen(substitute(a:extension, "[^.]", "", "g"))
     66    if s:maxDotsInExtension < dotsNumber
     67      let s:maxDotsInExtension = dotsNumber
     68    endif
     69 endfunction
     70 
     71 
     72 " Add all the default extensions
     73 " Mappings for C and C++
     74 call <SID>AddAlternateExtensionMapping('h',"c,cpp,cxx,cc,CC")
     75 call <SID>AddAlternateExtensionMapping('H',"C,CPP,CXX,CC")
     76 call <SID>AddAlternateExtensionMapping('hpp',"cpp,c")
     77 call <SID>AddAlternateExtensionMapping('HPP',"CPP,C")
     78 call <SID>AddAlternateExtensionMapping('c',"h")
     79 call <SID>AddAlternateExtensionMapping('C',"H")
     80 call <SID>AddAlternateExtensionMapping('cpp',"h,hpp")
     81 call <SID>AddAlternateExtensionMapping('CPP',"H,HPP")
     82 call <SID>AddAlternateExtensionMapping('cc',"h")
     83 call <SID>AddAlternateExtensionMapping('CC',"H,h")
     84 call <SID>AddAlternateExtensionMapping('cxx',"h")
     85 call <SID>AddAlternateExtensionMapping('CXX',"H")
     86 " Mappings for PSL7
     87 call <SID>AddAlternateExtensionMapping('psl',"ph")
     88 call <SID>AddAlternateExtensionMapping('ph',"psl")
     89 " Mappings for ADA
     90 call <SID>AddAlternateExtensionMapping('adb',"ads")
     91 call <SID>AddAlternateExtensionMapping('ads',"adb")
     92 " Mappings for lex and yacc files
     93 call <SID>AddAlternateExtensionMapping('l',"y,yacc,ypp")
     94 call <SID>AddAlternateExtensionMapping('lex',"yacc,y,ypp")
     95 call <SID>AddAlternateExtensionMapping('lpp',"ypp,y,yacc")
     96 call <SID>AddAlternateExtensionMapping('y',"l,lex,lpp")
     97 call <SID>AddAlternateExtensionMapping('yacc',"lex,l,lpp")
     98 call <SID>AddAlternateExtensionMapping('ypp',"lpp,l,lex")
     99 " Mappings for OCaml
    100 call <SID>AddAlternateExtensionMapping('ml',"mli")
    101 call <SID>AddAlternateExtensionMapping('mli',"ml")
    102 " ASP stuff
    103 call <SID>AddAlternateExtensionMapping('aspx.cs', 'aspx')
    104 call <SID>AddAlternateExtensionMapping('aspx.vb', 'aspx')
    105 call <SID>AddAlternateExtensionMapping('aspx', 'aspx.cs,aspx.vb')
    106 
    107 " Setup default search path, unless the user has specified
    108 " a path in their [._]vimrc. 
    109 if (!exists('g:alternateSearchPath'))
    110   let g:alternateSearchPath = 'sfr:../source,sfr:../src,sfr:../include,sfr:../inc'
    111 endif
    112 
    113 " If this variable is true then a.vim will not alternate to a file/buffer which
    114 " does not exist. E.g while editing a.c and the :A will not swtich to a.h
    115 " unless it exists.
    116 if (!exists('g:alternateNoDefaultAlternate'))
    117    " by default a.vim will alternate to a file which does not exist
    118    let g:alternateNoDefaultAlternate = 0
    119 endif
    120 
    121 " If this variable is true then a.vim will convert the alternate filename to a
    122 " filename relative to the current working directory.
    123 " Feature by Nathan Huizinga
    124 if (!exists('g:alternateRelativeFiles'))                                        
    125    " by default a.vim will not convert the filename to one relative to the
    126    " current working directory
    127    let g:alternateRelativeFiles = 0
    128 endif
    129 
    130 
    131 " Function : GetNthItemFromList (PRIVATE)
    132 " Purpose  : Support reading items from a comma seperated list
    133 "            Used to iterate all the extensions in an extension spec
    134 "            Used to iterate all path prefixes
    135 " Args     : list -- the list (extension spec, file paths) to iterate
    136 "            n -- the extension to get
    137 " Returns  : the nth item (extension, path) from the list (extension 
    138 "            spec), or "" for failure
    139 " Author   : Michael Sharpe <feline@irendi.com>
    140 " History  : Renamed from GetNthExtensionFromSpec to GetNthItemFromList
    141 "            to reflect a more generic use of this function. -- Bindu
    142 function! <SID>GetNthItemFromList(list, n) 
    143    let itemStart = 0
    144    let itemEnd = -1
    145    let pos = 0
    146    let item = ""
    147    let i = 0
    148    while (i != a:n)
    149       let itemStart = itemEnd + 1
    150       let itemEnd = match(a:list, ",", itemStart)
    151       let i = i + 1
    152       if (itemEnd == -1)
    153          if (i == a:n)
    154             let itemEnd = strlen(a:list)
    155          endif
    156          break
    157       endif
    158    endwhile 
    159    if (itemEnd != -1) 
    160       let item = strpart(a:list, itemStart, itemEnd - itemStart)
    161    endif
    162    return item 
    163 endfunction
    164 
    165 " Function : ExpandAlternatePath (PRIVATE)
    166 " Purpose  : Expand path info.  A path with a prefix of "wdr:" will be 
    167 "            treated as relative to the working directory (i.e. the 
    168 "            directory where vim was started.) A path prefix of "abs:" will 
    169 "            be treated as absolute. No prefix or "sfr:" will result in the 
    170 "            path being treated as relative to the source file (see sfPath 
    171 "            argument). 
    172 "
    173 "            A prefix of "reg:" will treat the pathSpec as a regular
    174 "            expression substitution that is applied to the source file 
    175 "            path. The format is:
    176 "
    177 "              reg:<sep><pattern><sep><subst><sep><flag><sep>
    178 "          
    179 "            <sep> seperator character, we often use one of [/|%#] 
    180 "            <pattern> is what you are looking for
    181 "            <subst> is the output pattern
    182 "            <flag> can be g for global replace or empty
    183 "
    184 "            EXAMPLE: 'reg:/inc/src/g/' will replace every instance 
    185 "            of 'inc' with 'src' in the source file path. It is possible
    186 "            to use match variables so you could do something like:
    187 "            'reg:|src/\([^/]*\)|inc/\1||' (see 'help :substitute', 
    188 "            'help pattern' and 'help sub-replace-special' for more details
    189 "
    190 "            NOTE: a.vim uses ',' (comma) internally so DON'T use it
    191 "            in your regular expressions or other pathSpecs unless you update 
    192 "            the rest of the a.vim code to use some other seperator.
    193 "
    194 " Args     : pathSpec -- path component (or substitution patterns)
    195 "            sfPath -- source file path
    196 " Returns  : a path that can be used by AlternateFile()
    197 " Author   : Bindu Wavell <bindu@wavell.net>
    198 function! <SID>ExpandAlternatePath(pathSpec, sfPath) 
    199    let prfx = strpart(a:pathSpec, 0, 4)
    200    if (prfx == "wdr:" || prfx == "abs:")
    201       let path = strpart(a:pathSpec, 4)
    202    elseif (prfx == "reg:")
    203       let re = strpart(a:pathSpec, 4)
    204       let sep = strpart(re, 0, 1)
    205       let patend = match(re, sep, 1)
    206       let pat = strpart(re, 1, patend - 1)
    207       let subend = match(re, sep, patend + 1)
    208       let sub = strpart(re, patend+1, subend - patend - 1)
    209       let flag = strpart(re, strlen(re) - 2)
    210       if (flag == sep)
    211         let flag = ''
    212       endif
    213       let path = substitute(a:sfPath, pat, sub, flag)
    214       "call confirm('PAT: [' . pat . '] SUB: [' . sub . ']')
    215       "call confirm(a:sfPath . ' => ' . path)
    216    else
    217       let path = a:pathSpec
    218       if (prfx == "sfr:")
    219          let path = strpart(path, 4)
    220       endif
    221       let path = a:sfPath . "/" . path
    222    endif
    223    return path
    224 endfunction
    225 
    226 " Function : FindFileInSearchPath (PRIVATE)
    227 " Purpose  : Searches for a file in the search path list
    228 " Args     : filename -- name of the file to search for
    229 "            pathList -- the path list to search
    230 "            relPathBase -- the path which relative paths are expanded from
    231 " Returns  : An expanded filename if found, the empty string otherwise
    232 " Author   : Michael Sharpe (feline@irendi.com)
    233 " History  : inline code written by Bindu Wavell originally
    234 function! <SID>FindFileInSearchPath(fileName, pathList, relPathBase)
    235    let filepath = ""
    236    let m = 1
    237    let pathListLen = strlen(a:pathList)
    238    if (pathListLen > 0)
    239       while (1)
    240          let pathSpec = <SID>GetNthItemFromList(a:pathList, m) 
    241          if (pathSpec != "")
    242             let path = <SID>ExpandAlternatePath(pathSpec, a:relPathBase)
    243             let fullname = path . "/" . a:fileName
    244             let foundMatch = <SID>BufferOrFileExists(fullname)
    245             if (foundMatch)
    246                let filepath = fullname
    247                break
    248             endif
    249          else
    250             break
    251          endif
    252          let m = m + 1
    253       endwhile
    254    endif
    255    return filepath
    256 endfunction
    257 
    258 " Function : FindFileInSearchPathEx (PRIVATE)
    259 " Purpose  : Searches for a file in the search path list
    260 " Args     : filename -- name of the file to search for
    261 "            pathList -- the path list to search
    262 "            relPathBase -- the path which relative paths are expanded from
    263 "            count -- find the count'th occurence of the file on the path
    264 " Returns  : An expanded filename if found, the empty string otherwise
    265 " Author   : Michael Sharpe (feline@irendi.com)
    266 " History  : Based on <SID>FindFileInSearchPath() but with extensions
    267 function! <SID>FindFileInSearchPathEx(fileName, pathList, relPathBase, count)
    268    let filepath = ""
    269    let m = 1
    270    let spath = ""
    271    let pathListLen = strlen(a:pathList)
    272    if (pathListLen > 0)
    273       while (1)
    274          let pathSpec = <SID>GetNthItemFromList(a:pathList, m) 
    275          if (pathSpec != "")
    276             let path = <SID>ExpandAlternatePath(pathSpec, a:relPathBase)
    277             if (spath != "")
    278                let spath = spath . ','
    279             endif
    280             let spath = spath . path
    281          else
    282             break
    283          endif
    284          let m = m + 1
    285       endwhile
    286    endif
    287 
    288    if (&path != "")
    289       if (spath != "")
    290          let spath = spath . ','
    291       endif
    292       let spath = spath . &path
    293    endif
    294 
    295    let filepath = findfile(a:fileName, spath, a:count)
    296    return filepath
    297 endfunction
    298 
    299 " Function : EnumerateFilesByExtension (PRIVATE)
    300 " Purpose  : enumerates all files by a particular list of alternate extensions.
    301 " Args     : path -- path of a file (not including the file)
    302 "            baseName -- base name of the file to be expanded
    303 "            extension -- extension whose alternates are to be enumerated
    304 " Returns  : comma separated list of files with extensions
    305 " Author   : Michael Sharpe <feline@irendi.com>
    306 function! EnumerateFilesByExtension(path, baseName, extension)
    307    let enumeration = ""
    308    let extSpec = ""
    309    let v:errmsg = ""
    310    silent! echo g:alternateExtensions_{a:extension}
    311    if (v:errmsg == "")
    312       let extSpec = g:alternateExtensions_{a:extension}
    313    endif
    314    if (extSpec == "")
    315       if (has_key(g:alternateExtensionsDict, a:extension))
    316          let extSpec = g:alternateExtensionsDict[a:extension]
    317       endif
    318    endif
    319    if (extSpec != "") 
    320       let n = 1
    321       let done = 0
    322       while (!done)
    323          let ext = <SID>GetNthItemFromList(extSpec, n)
    324          if (ext != "")
    325             if (a:path != "")
    326                let newFilename = a:path . "/" . a:baseName . "." . ext
    327             else
    328                let newFilename =  a:baseName . "." . ext
    329             endif
    330             if (enumeration == "")
    331                let enumeration = newFilename
    332             else
    333                let enumeration = enumeration . "," . newFilename
    334             endif
    335          else
    336             let done = 1
    337          endif
    338          let n = n + 1
    339       endwhile
    340    endif
    341    return enumeration
    342 endfunction
    343 
    344 " Function : EnumerateFilesByExtensionInPath (PRIVATE)
    345 " Purpose  : enumerates all files by expanding the path list and the extension
    346 "            list.
    347 " Args     : baseName -- base name of the file
    348 "            extension -- extension whose alternates are to be enumerated
    349 "            pathList -- the list of paths to enumerate
    350 "            relPath -- the path of the current file for expansion of relative
    351 "                       paths in the path list.
    352 " Returns  : A comma separated list of paths with extensions
    353 " Author   : Michael Sharpe <feline@irendi.com>
    354 function! EnumerateFilesByExtensionInPath(baseName, extension, pathList, relPathBase)
    355    let enumeration = ""
    356    let filepath = ""
    357    let m = 1
    358    let pathListLen = strlen(a:pathList)
    359    if (pathListLen > 0)
    360       while (1)
    361          let pathSpec = <SID>GetNthItemFromList(a:pathList, m) 
    362          if (pathSpec != "")
    363             let path = <SID>ExpandAlternatePath(pathSpec, a:relPathBase)
    364             let pe = EnumerateFilesByExtension(path, a:baseName, a:extension)
    365             if (enumeration == "")
    366                let enumeration = pe
    367             else
    368                let enumeration = enumeration . "," . pe
    369             endif
    370          else
    371             break
    372          endif
    373          let m = m + 1
    374       endwhile
    375    endif
    376    return enumeration
    377 endfunction
    378 
    379 " Function : DetermineExtension (PRIVATE)
    380 " Purpose  : Determines the extension of a filename based on the register
    381 "            alternate extension. This allow extension which contain dots to 
    382 "            be considered. E.g. foo.aspx.cs to foo.aspx where an alternate
    383 "            exists for the aspx.cs extension. Note that this will only accept
    384 "            extensions which contain less than 5 dots. This is only
    385 "            implemented in this manner for simplicity...it is doubtful that 
    386 "            this will be a restriction in non-contrived situations.
    387 " Args     : The path to the file to find the extension in
    388 " Returns  : The matched extension if any
    389 " Author   : Michael Sharpe (feline@irendi.com)
    390 " History  : idea from Tom-Erik Duestad
    391 " Notes    : there is some magic occuring here. The exists() function does not
    392 "            work well when the curly brace variable has dots in it. And why
    393 "            should it, dots are not valid in variable names. But the exists
    394 "            function is wierd too. Lets say foo_c does exist. Then
    395 "            exists("foo_c.e.f") will be true...even though the variable does 
    396 "            not exist. However the curly brace variables do work when the
    397 "            variable has dots in it. E.g foo_{'c'} is different from 
    398 "            foo_{'c.d.e'}...and foo_{'c'} is identical to foo_c and
    399 "            foo_{'c.d.e'} is identical to foo_c.d.e right? Yes in the current
    400 "            implementation of vim. To trick vim to test for existence of such
    401 "            variables echo the curly brace variable and look for an error 
    402 "            message.
    403 function! DetermineExtension(path) 
    404   let mods = ":t"
    405   let i = 0
    406   while i <= s:maxDotsInExtension
    407     let mods = mods . ":e"
    408     let extension = fnamemodify(a:path, mods)
    409     if (has_key(g:alternateExtensionsDict, extension))
    410        return extension
    411     endif
    412     let v:errmsg = ""
    413     silent! echo g:alternateExtensions_{extension}
    414     if (v:errmsg == "")
    415       return extension
    416     endif
    417     let i = i + 1
    418   endwhile
    419   return ""
    420 endfunction
    421 
    422 " Function : AlternateFile (PUBLIC)
    423 " Purpose  : Opens a new buffer by looking at the extension of the current
    424 "            buffer and finding the corresponding file. E.g. foo.c <--> foo.h
    425 " Args     : accepts one argument. If present it used the argument as the new
    426 "            extension.
    427 " Returns  : nothing
    428 " Author   : Michael Sharpe <feline@irendi.com>
    429 " History  : + When an alternate can't be found in the same directory as the
    430 "              source file, a search path will be traversed looking for the
    431 "              alternates.
    432 "            + Moved some code into a separate function, minor optimization
    433 "            + rework to favor files in memory based on complete enumeration of
    434 "              all files extensions and paths
    435 function! AlternateFile(splitWindow, ...)
    436   let extension   = DetermineExtension(expand("%:p"))
    437   let baseName    = substitute(expand("%:t"), "\." . extension . '$', "", "")
    438   let currentPath = expand("%:p:h")
    439 
    440   if (a:0 != 0)
    441      let newFullname = currentPath . "/" .  baseName . "." . a:1
    442      call <SID>FindOrCreateBuffer(newFullname, a:splitWindow, 0)
    443   else
    444      let allfiles = ""
    445      if (extension != "")
    446         let allfiles1 = EnumerateFilesByExtension(currentPath, baseName, extension)
    447         let allfiles2 = EnumerateFilesByExtensionInPath(baseName, extension, g:alternateSearchPath, currentPath)
    448 
    449         if (allfiles1 != "")
    450            if (allfiles2 != "")
    451               let allfiles = allfiles1 . ',' . allfiles2
    452            else
    453               let allfiles = allfiles1
    454            endif
    455         else 
    456            let allfiles = allfiles2
    457         endif
    458      endif
    459 
    460      if (allfiles != "") 
    461         let bestFile = ""
    462         let bestScore = 0
    463         let score = 0
    464         let n = 1
    465          
    466         let onefile = <SID>GetNthItemFromList(allfiles, n)
    467         let bestFile = onefile
    468         while (onefile != "" && score < 2)
    469            let score = <SID>BufferOrFileExists(onefile)
    470            if (score > bestScore)
    471               let bestScore = score
    472               let bestFile = onefile
    473            endif
    474            let n = n + 1
    475            let onefile = <SID>GetNthItemFromList(allfiles, n)
    476         endwhile
    477 
    478         if (bestScore == 0 && g:alternateNoDefaultAlternate == 1)
    479            echo "No existing alternate available"
    480         else
    481            call <SID>FindOrCreateBuffer(bestFile, a:splitWindow, 1)
    482            let b:AlternateAllFiles = allfiles
    483         endif
    484      else
    485         echo "No alternate file/buffer available"
    486      endif
    487    endif
    488 endfunction
    489 
    490 " Function : AlternateOpenFileUnderCursor (PUBLIC)
    491 " Purpose  : Opens file under the cursor
    492 " Args     : splitWindow -- indicates how to open the file
    493 " Returns  : Nothing
    494 " Author   : Michael Sharpe (feline@irendi.com) www.irendi.com
    495 function! AlternateOpenFileUnderCursor(splitWindow,...)
    496    let cursorFile = (a:0 > 0) ? a:1 : expand("<cfile>") 
    497    let currentPath = expand("%:p:h")
    498    let openCount = 1
    499 
    500    let fileName = <SID>FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, openCount)
    501    if (fileName != "")
    502       call <SID>FindOrCreateBuffer(fileName, a:splitWindow, 1)
    503       let b:openCount = openCount
    504       let b:cursorFile = cursorFile
    505       let b:currentPath = currentPath
    506    else
    507       echo "Can't find file"
    508    endif
    509 endfunction
    510 
    511 " Function : AlternateOpenNextFile (PUBLIC)
    512 " Purpose  : Opens the next file corresponding to the search which found the 
    513 "            current file
    514 " Args     : bang -- indicates what to do if the current file has not been 
    515 "                    saved
    516 " Returns  : nothing
    517 " Author   : Michael Sharpe (feline@irendi.com) www.irendi.com
    518 function! AlternateOpenNextFile(bang)
    519    let cursorFile = ""
    520    if (exists("b:cursorFile"))
    521       let cursorFile = b:cursorFile
    522    endif
    523 
    524    let currentPath = ""
    525    if (exists("b:currentPath"))
    526       let currentPath = b:currentPath
    527    endif
    528 
    529    let openCount = 0
    530    if (exists("b:openCount"))
    531       let openCount = b:openCount + 1
    532    endif
    533 
    534    if (cursorFile != ""  && currentPath != ""  && openCount != 0)
    535       let fileName = <SID>FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, openCount)
    536       if (fileName != "")
    537          call <SID>FindOrCreateBuffer(fileName, "n".a:bang, 0)
    538          let b:openCount = openCount
    539          let b:cursorFile = cursorFile
    540          let b:currentPath = currentPath
    541       else 
    542          let fileName = <SID>FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, 1)
    543          if (fileName != "")
    544             call <SID>FindOrCreateBuffer(fileName, "n".a:bang, 0)
    545             let b:openCount = 1
    546             let b:cursorFile = cursorFile
    547             let b:currentPath = currentPath
    548          else
    549             echo "Can't find next file"
    550          endif
    551       endif
    552    endif
    553 endfunction
    554 
    555 comm! -nargs=? -bang IH call AlternateOpenFileUnderCursor("n<bang>", <f-args>)
    556 comm! -nargs=? -bang IHS call AlternateOpenFileUnderCursor("h<bang>", <f-args>)
    557 comm! -nargs=? -bang IHV call AlternateOpenFileUnderCursor("v<bang>", <f-args>)
    558 comm! -nargs=? -bang IHT call AlternateOpenFileUnderCursor("t<bang>", <f-args>)
    559 comm! -nargs=? -bang IHN call AlternateOpenNextFile("<bang>")
    560 imap <Leader>ih <ESC>:IHS<CR>
    561 nmap <Leader>ih :IHS<CR>
    562 imap <Leader>is <ESC>:IHS<CR>:A<CR>
    563 nmap <Leader>is :IHS<CR>:A<CR>
    564 imap <Leader>ihn <ESC>:IHN<CR>
    565 nmap <Leader>ihn :IHN<CR>
    566 
    567 "function! <SID>PrintList(theList) 
    568 "   let n = 1
    569 "   let oneFile = <SID>GetNthItemFromList(a:theList, n)
    570 "   while (oneFile != "")
    571 "      let n = n + 1
    572 "      let oneFile = <SID>GetNthItemFromList(a:theList, n)
    573 "   endwhile
    574 "endfunction
    575 
    576 " Function : NextAlternate (PUBLIC)
    577 " Purpose  : Used to cycle through any other alternate file which existed on
    578 "            the search path.
    579 " Args     : bang (IN) - used to implement the AN vs AN! functionality
    580 " Returns  : nothing
    581 " Author   : Michael Sharpe <feline@irendi.com>
    582 function! NextAlternate(bang)
    583    if (exists('b:AlternateAllFiles'))
    584       let currentFile = expand("%")
    585       let n = 1
    586       let onefile = <SID>GetNthItemFromList(b:AlternateAllFiles, n)
    587       while (onefile != "" && !<SID>EqualFilePaths(fnamemodify(onefile,":p"), fnamemodify(currentFile,":p")))
    588          let n = n + 1
    589          let onefile = <SID>GetNthItemFromList(b:AlternateAllFiles, n)
    590       endwhile
    591 
    592       if (onefile != "")
    593          let stop = n
    594          let n = n + 1
    595          let foundAlternate = 0
    596          let nextAlternate = ""
    597          while (n != stop)
    598             let nextAlternate = <SID>GetNthItemFromList(b:AlternateAllFiles, n)
    599             if (nextAlternate == "")
    600                let n = 1
    601                continue
    602             endif
    603             let n = n + 1
    604             if (<SID>EqualFilePaths(fnamemodify(nextAlternate, ":p"), fnamemodify(currentFile, ":p")))
    605                 continue
    606             endif
    607             if (filereadable(nextAlternate))
    608                 " on cygwin filereadable("foo.H") returns true if "foo.h" exists
    609                if (has("unix") && $WINDIR != "" && fnamemodify(nextAlternate, ":p") ==? fnamemodify(currentFile, ":p")) 
    610                   continue
    611                endif
    612                let foundAlternate = 1
    613                break
    614             endif
    615          endwhile
    616          if (foundAlternate == 1)
    617             let s:AlternateAllFiles = b:AlternateAllFiles
    618             "silent! execute ":e".a:bang." " . nextAlternate
    619             call <SID>FindOrCreateBuffer(nextAlternate, "n".a:bang, 0)
    620             let b:AlternateAllFiles = s:AlternateAllFiles
    621          else 
    622             echo "Only this alternate file exists"
    623          endif
    624       else 
    625          echo "Could not find current file in alternates list"
    626       endif
    627    else 
    628       echo "No other alternate files exist"
    629    endif
    630 endfunction
    631 
    632 comm! -nargs=? -bang A call AlternateFile("n<bang>", <f-args>)
    633 comm! -nargs=? -bang AS call AlternateFile("h<bang>", <f-args>)
    634 comm! -nargs=? -bang AV call AlternateFile("v<bang>", <f-args>)
    635 comm! -nargs=? -bang AT call AlternateFile("t<bang>", <f-args>)
    636 comm! -nargs=? -bang AN call NextAlternate("<bang>")
    637 
    638 " Function : BufferOrFileExists (PRIVATE)
    639 " Purpose  : determines if a buffer or a readable file exists
    640 " Args     : fileName (IN) - name of the file to check
    641 " Returns  : 2 if it exists in memory, 1 if it exists, 0 otherwise
    642 " Author   : Michael Sharpe <feline@irendi.com>
    643 " History  : Updated code to handle buffernames using just the
    644 "            filename and not the path.
    645 function! <SID>BufferOrFileExists(fileName)
    646    let result = 0
    647 
    648    let lastBuffer = bufnr("$")
    649    let i = 1
    650    while i <= lastBuffer
    651      if <SID>EqualFilePaths(expand("#".i.":p"), a:fileName)
    652        let result = 2
    653        break
    654      endif
    655      let i = i + 1
    656    endwhile
    657 
    658    if (!result) 
    659       let bufName = fnamemodify(a:fileName,":t")
    660       let memBufName = bufname(bufName)
    661       if (memBufName != "")
    662          let memBufBasename = fnamemodify(memBufName, ":t")
    663          if (bufName == memBufBasename)
    664             let result = 2
    665          endif
    666       endif
    667 
    668       if (!result)
    669          let result  = bufexists(bufName) || bufexists(a:fileName) || filereadable(a:fileName)
    670       endif
    671    endif
    672 
    673    if (!result)
    674       let result = filereadable(a:fileName)
    675    endif
    676    return result
    677 endfunction
    678 
    679 " Function : FindOrCreateBuffer (PRIVATE)
    680 " Purpose  : searches the buffer list (:ls) for the specified filename. If
    681 "            found, checks the window list for the buffer. If the buffer is in
    682 "            an already open window, it switches to the window. If the buffer
    683 "            was not in a window, it switches to that buffer. If the buffer did
    684 "            not exist, it creates it.
    685 " Args     : filename (IN) -- the name of the file
    686 "            doSplit (IN) -- indicates whether the window should be split
    687 "                            ("v", "h", "n", "v!", "h!", "n!", "t", "t!") 
    688 "            findSimilar (IN) -- indicate weather existing buffers should be
    689 "                                prefered
    690 " Returns  : nothing
    691 " Author   : Michael Sharpe <feline@irendi.com>
    692 " History  : + bufname() was not working very well with the possibly strange
    693 "            paths that can abound with the search path so updated this
    694 "            slightly.  -- Bindu
    695 "            + updated window switching code to make it more efficient -- Bindu
    696 "            Allow ! to be applied to buffer/split/editing commands for more
    697 "            vim/vi like consistency
    698 "            + implemented fix from Matt Perry
    699 function! <SID>FindOrCreateBuffer(fileName, doSplit, findSimilar)
    700   " Check to see if the buffer is already open before re-opening it.
    701   let FILENAME = escape(a:fileName, ' ')
    702   let bufNr = -1
    703   let lastBuffer = bufnr("$")
    704   let i = 1
    705   if (a:findSimilar) 
    706      while i <= lastBuffer
    707        if <SID>EqualFilePaths(expand("#".i.":p"), a:fileName)
    708          let bufNr = i
    709          break
    710        endif
    711        let i = i + 1
    712      endwhile
    713 
    714      if (bufNr == -1)
    715         let bufName = bufname(a:fileName)
    716         let bufFilename = fnamemodify(a:fileName,":t")
    717 
    718         if (bufName == "")
    719            let bufName = bufname(bufFilename)
    720         endif
    721 
    722         if (bufName != "")
    723            let tail = fnamemodify(bufName, ":t")
    724            if (tail != bufFilename)
    725               let bufName = ""
    726            endif
    727         endif
    728         if (bufName != "")
    729            let bufNr = bufnr(bufName)
    730            let FILENAME = bufName
    731         endif
    732      endif
    733   endif
    734 
    735   if (g:alternateRelativeFiles == 1)                                            
    736         let FILENAME = fnamemodify(FILENAME, ":p:.")
    737   endif
    738 
    739   let splitType = a:doSplit[0]
    740   let bang = a:doSplit[1]
    741   if (bufNr == -1)
    742      " Buffer did not exist....create it
    743      let v:errmsg=""
    744      if (splitType == "h")
    745         silent! execute ":split".bang." " . FILENAME
    746      elseif (splitType == "v")
    747         silent! execute ":vsplit".bang." " . FILENAME
    748      elseif (splitType == "t")
    749         silent! execute ":tab split".bang." " . FILENAME
    750      else
    751         silent! execute ":e".bang." " . FILENAME
    752      endif
    753      if (v:errmsg != "")
    754         echo v:errmsg
    755      endif
    756   else
    757 
    758      " Find the correct tab corresponding to the existing buffer
    759      let tabNr = -1
    760      " iterate tab pages
    761      for i in range(tabpagenr('$'))
    762         " get the list of buffers in the tab
    763         let tabList =  tabpagebuflist(i + 1)
    764         let idx = 0
    765         " iterate each buffer in the list
    766         while idx < len(tabList)
    767            " if it matches the buffer we are looking for...
    768            if (tabList[idx] == bufNr)
    769               " ... save the number
    770               let tabNr = i + 1
    771               break
    772            endif
    773            let idx = idx + 1
    774         endwhile
    775         if (tabNr != -1)
    776            break
    777         endif
    778      endfor
    779      " switch the the tab containing the buffer
    780      if (tabNr != -1)
    781         execute "tabn ".tabNr
    782      endif
    783 
    784      " Buffer was already open......check to see if it is in a window
    785      let bufWindow = bufwinnr(bufNr)
    786      if (bufWindow == -1) 
    787         " Buffer was not in a window so open one
    788         let v:errmsg=""
    789         if (splitType == "h")
    790            silent! execute ":sbuffer".bang." " . FILENAME
    791         elseif (splitType == "v")
    792            silent! execute ":vert sbuffer " . FILENAME
    793         elseif (splitType == "t")
    794            silent! execute ":tab sbuffer " . FILENAME
    795         else
    796            silent! execute ":buffer".bang." " . FILENAME
    797         endif
    798         if (v:errmsg != "")
    799            echo v:errmsg
    800         endif
    801      else
    802         " Buffer is already in a window so switch to the window
    803         execute bufWindow."wincmd w"
    804         if (bufWindow != winnr()) 
    805            " something wierd happened...open the buffer
    806            let v:errmsg=""
    807            if (splitType == "h")
    808               silent! execute ":split".bang." " . FILENAME
    809            elseif (splitType == "v")
    810               silent! execute ":vsplit".bang." " . FILENAME
    811            elseif (splitType == "t")
    812               silent! execute ":tab split".bang." " . FILENAME
    813            else
    814               silent! execute ":e".bang." " . FILENAME
    815            endif
    816            if (v:errmsg != "")
    817               echo v:errmsg
    818            endif
    819         endif
    820      endif
    821   endif
    822 endfunction
    823 
    824 " Function : EqualFilePaths (PRIVATE)
    825 " Purpose  : Compares two paths. Do simple string comparison anywhere but on
    826 "            Windows. On Windows take into account that file paths could differ
    827 "            in usage of separators and the fact that case does not matter.
    828 "            "c:\WINDOWS" is the same path as "c:/windows". has("win32unix") Vim
    829 "            version does not count as one having Windows path rules.
    830 " Args     : path1 (IN) -- first path
    831 "            path2 (IN) -- second path
    832 " Returns  : 1 if path1 is equal to path2, 0 otherwise.
    833 " Author   : Ilya Bobir <ilya@po4ta.com>
    834 function! <SID>EqualFilePaths(path1, path2)
    835   if has("win16") || has("win32") || has("win64") || has("win95")
    836     return substitute(a:path1, "\/", "\\", "g") ==? substitute(a:path2, "\/", "\\", "g")
    837   else
    838     return a:path1 == a:path2
    839   endif
    840 endfunction