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