" Copyright (c) 1998-2006 " Michael Sharpe " " We grant permission to use, copy modify, distribute, and sell this " software for any purpose without fee, provided that the above copyright " notice and this text are not removed. We make no guarantee about the " suitability of this software for any purpose and we are not liable " for any damages resulting from its use. Further, we are under no " obligation to maintain or extend this software. It is provided on an " "as is" basis without any expressed or implied warranty. " Directory & regex enhancements added by Bindu Wavell who is well known on " vim.sf.net " Do not load a.vim if is has already been loaded. if exists("loaded_alternateFile") finish endif if (v:progname == "ex") finish endif let loaded_alternateFile = 1 let alternateExtensionsDict = {} " setup the default set of alternate extensions. The user can override in thier " .vimrc if the defaults are not suitable. To override in a .vimrc simply set a " g:alternateExtensions_ variable to a comma separated list of alternates, " where is the extension to map. " E.g. let g:alternateExtensions_CPP = "inc,h,H,HPP,hpp" " let g:alternateExtensions_{'aspx.cs'} = "aspx" " This variable will be increased when an extension with greater number of dots " is added by the AddAlternateExtensionMapping call. let s:maxDotsInExtension = 1 " Function : AddAlternateExtensionMapping (PRIVATE) " Purpose : simple helper function to add the default alternate extension " mappings. " Args : extension -- the extension to map " alternates -- comma separated list of alternates extensions " Returns : nothing " Author : Michael Sharpe function! AddAlternateExtensionMapping(extension, alternates) " This code does not actually work for variables like foo{'a.b.c.d.e'} "let varName = "g:alternateExtensions_" . a:extension "if (!exists(varName)) " let g:alternateExtensions_{a:extension} = a:alternates "endif " This code handles extensions which contains a dot. exists() fails with " such names. "let v:errmsg = "" " FIXME this line causes ex to return 1 instead of 0 for some reason?? "silent! echo g:alternateExtensions_{a:extension} "if (v:errmsg != "") "let g:alternateExtensions_{a:extension} = a:alternates "endif let g:alternateExtensionsDict[a:extension] = a:alternates let dotsNumber = strlen(substitute(a:extension, "[^.]", "", "g")) if s:maxDotsInExtension < dotsNumber let s:maxDotsInExtension = dotsNumber endif endfunction " Add all the default extensions " Mappings for C and C++ call AddAlternateExtensionMapping('h',"c,cpp,cxx,cc,CC") call AddAlternateExtensionMapping('H',"C,CPP,CXX,CC") call AddAlternateExtensionMapping('hpp',"cpp,c") call AddAlternateExtensionMapping('HPP',"CPP,C") call AddAlternateExtensionMapping('c',"h") call AddAlternateExtensionMapping('C',"H") call AddAlternateExtensionMapping('cpp',"h,hpp") call AddAlternateExtensionMapping('CPP',"H,HPP") call AddAlternateExtensionMapping('cc',"h") call AddAlternateExtensionMapping('CC',"H,h") call AddAlternateExtensionMapping('cxx',"h") call AddAlternateExtensionMapping('CXX',"H") " Mappings for PSL7 call AddAlternateExtensionMapping('psl',"ph") call AddAlternateExtensionMapping('ph',"psl") " Mappings for ADA call AddAlternateExtensionMapping('adb',"ads") call AddAlternateExtensionMapping('ads',"adb") " Mappings for lex and yacc files call AddAlternateExtensionMapping('l',"y,yacc,ypp") call AddAlternateExtensionMapping('lex',"yacc,y,ypp") call AddAlternateExtensionMapping('lpp',"ypp,y,yacc") call AddAlternateExtensionMapping('y',"l,lex,lpp") call AddAlternateExtensionMapping('yacc',"lex,l,lpp") call AddAlternateExtensionMapping('ypp',"lpp,l,lex") " Mappings for OCaml call AddAlternateExtensionMapping('ml',"mli") call AddAlternateExtensionMapping('mli',"ml") " ASP stuff call AddAlternateExtensionMapping('aspx.cs', 'aspx') call AddAlternateExtensionMapping('aspx.vb', 'aspx') call AddAlternateExtensionMapping('aspx', 'aspx.cs,aspx.vb') " Setup default search path, unless the user has specified " a path in their [._]vimrc. if (!exists('g:alternateSearchPath')) let g:alternateSearchPath = 'sfr:../source,sfr:../src,sfr:../include,sfr:../inc' endif " If this variable is true then a.vim will not alternate to a file/buffer which " does not exist. E.g while editing a.c and the :A will not swtich to a.h " unless it exists. if (!exists('g:alternateNoDefaultAlternate')) " by default a.vim will alternate to a file which does not exist let g:alternateNoDefaultAlternate = 0 endif " Function : GetNthItemFromList (PRIVATE) " Purpose : Support reading items from a comma seperated list " Used to iterate all the extensions in an extension spec " Used to iterate all path prefixes " Args : list -- the list (extension spec, file paths) to iterate " n -- the extension to get " Returns : the nth item (extension, path) from the list (extension " spec), or "" for failure " Author : Michael Sharpe " History : Renamed from GetNthExtensionFromSpec to GetNthItemFromList " to reflect a more generic use of this function. -- Bindu function! GetNthItemFromList(list, n) let itemStart = 0 let itemEnd = -1 let pos = 0 let item = "" let i = 0 while (i != a:n) let itemStart = itemEnd + 1 let itemEnd = match(a:list, ",", itemStart) let i = i + 1 if (itemEnd == -1) if (i == a:n) let itemEnd = strlen(a:list) endif break endif endwhile if (itemEnd != -1) let item = strpart(a:list, itemStart, itemEnd - itemStart) endif return item endfunction " Function : ExpandAlternatePath (PRIVATE) " Purpose : Expand path info. A path with a prefix of "wdr:" will be " treated as relative to the working directory (i.e. the " directory where vim was started.) A path prefix of "abs:" will " be treated as absolute. No prefix or "sfr:" will result in the " path being treated as relative to the source file (see sfPath " argument). " " A prefix of "reg:" will treat the pathSpec as a regular " expression substitution that is applied to the source file " path. The format is: " " reg: " " seperator character, we often use one of [/|%#] " is what you are looking for " is the output pattern " can be g for global replace or empty " " EXAMPLE: 'reg:/inc/src/g/' will replace every instance " of 'inc' with 'src' in the source file path. It is possible " to use match variables so you could do something like: " 'reg:|src/\([^/]*\)|inc/\1||' (see 'help :substitute', " 'help pattern' and 'help sub-replace-special' for more details " " NOTE: a.vim uses ',' (comma) internally so DON'T use it " in your regular expressions or other pathSpecs unless you update " the rest of the a.vim code to use some other seperator. " " Args : pathSpec -- path component (or substitution patterns) " sfPath -- source file path " Returns : a path that can be used by AlternateFile() " Author : Bindu Wavell function! ExpandAlternatePath(pathSpec, sfPath) let prfx = strpart(a:pathSpec, 0, 4) if (prfx == "wdr:" || prfx == "abs:") let path = strpart(a:pathSpec, 4) elseif (prfx == "reg:") let re = strpart(a:pathSpec, 4) let sep = strpart(re, 0, 1) let patend = match(re, sep, 1) let pat = strpart(re, 1, patend - 1) let subend = match(re, sep, patend + 1) let sub = strpart(re, patend+1, subend - patend - 1) let flag = strpart(re, strlen(re) - 2) if (flag == sep) let flag = '' endif let path = substitute(a:sfPath, pat, sub, flag) "call confirm('PAT: [' . pat . '] SUB: [' . sub . ']') "call confirm(a:sfPath . ' => ' . path) else let path = a:pathSpec if (prfx == "sfr:") let path = strpart(path, 4) endif let path = a:sfPath . "/" . path endif return path endfunction " Function : FindFileInSearchPath (PRIVATE) " Purpose : Searches for a file in the search path list " Args : filename -- name of the file to search for " pathList -- the path list to search " relPathBase -- the path which relative paths are expanded from " Returns : An expanded filename if found, the empty string otherwise " Author : Michael Sharpe (feline@irendi.com) " History : inline code written by Bindu Wavell originally function! FindFileInSearchPath(fileName, pathList, relPathBase) let filepath = "" let m = 1 let pathListLen = strlen(a:pathList) if (pathListLen > 0) while (1) let pathSpec = GetNthItemFromList(a:pathList, m) if (pathSpec != "") let path = ExpandAlternatePath(pathSpec, a:relPathBase) let fullname = path . "/" . a:fileName let foundMatch = BufferOrFileExists(fullname) if (foundMatch) let filepath = fullname break endif else break endif let m = m + 1 endwhile endif return filepath endfunction " Function : FindFileInSearchPathEx (PRIVATE) " Purpose : Searches for a file in the search path list " Args : filename -- name of the file to search for " pathList -- the path list to search " relPathBase -- the path which relative paths are expanded from " count -- find the count'th occurence of the file on the path " Returns : An expanded filename if found, the empty string otherwise " Author : Michael Sharpe (feline@irendi.com) " History : Based on FindFileInSearchPath() but with extensions function! FindFileInSearchPathEx(fileName, pathList, relPathBase, count) let filepath = "" let m = 1 let spath = "" let pathListLen = strlen(a:pathList) if (pathListLen > 0) while (1) let pathSpec = GetNthItemFromList(a:pathList, m) if (pathSpec != "") let path = ExpandAlternatePath(pathSpec, a:relPathBase) if (spath != "") let spath = spath . ',' endif let spath = spath . path else break endif let m = m + 1 endwhile endif if (&path != "") if (spath != "") let spath = spath . ',' endif let spath = spath . &path endif let filepath = findfile(a:fileName, spath, a:count) return filepath endfunction " Function : EnumerateFilesByExtension (PRIVATE) " Purpose : enumerates all files by a particular list of alternate extensions. " Args : path -- path of a file (not including the file) " baseName -- base name of the file to be expanded " extension -- extension whose alternates are to be enumerated " Returns : comma separated list of files with extensions " Author : Michael Sharpe function! EnumerateFilesByExtension(path, baseName, extension) let enumeration = "" let extSpec = "" if (has_key(g:alternateExtensionsDict, a:extension)) let extSpec = g:alternateExtensionsDict[a:extension] endif if (extSpec == "") let v:errmsg = "" silent! echo g:alternateExtensions_{a:extension} if (v:errmsg == "") let extSpec = g:alternateExtensions_{a:extension} endif endif if (extSpec != "") let n = 1 let done = 0 while (!done) let ext = GetNthItemFromList(extSpec, n) if (ext != "") if (a:path != "") let newFilename = a:path . "/" . a:baseName . "." . ext else let newFilename = a:baseName . "." . ext endif if (enumeration == "") let enumeration = newFilename else let enumeration = enumeration . "," . newFilename endif else let done = 1 endif let n = n + 1 endwhile endif return enumeration endfunction " Function : EnumerateFilesByExtensionInPath (PRIVATE) " Purpose : enumerates all files by expanding the path list and the extension " list. " Args : baseName -- base name of the file " extension -- extension whose alternates are to be enumerated " pathList -- the list of paths to enumerate " relPath -- the path of the current file for expansion of relative " paths in the path list. " Returns : A comma separated list of paths with extensions " Author : Michael Sharpe function! EnumerateFilesByExtensionInPath(baseName, extension, pathList, relPathBase) let enumeration = "" let filepath = "" let m = 1 let pathListLen = strlen(a:pathList) if (pathListLen > 0) while (1) let pathSpec = GetNthItemFromList(a:pathList, m) if (pathSpec != "") let path = ExpandAlternatePath(pathSpec, a:relPathBase) let pe = EnumerateFilesByExtension(path, a:baseName, a:extension) if (enumeration == "") let enumeration = pe else let enumeration = enumeration . "," . pe endif else break endif let m = m + 1 endwhile endif return enumeration endfunction " Function : DetermineExtension (PRIVATE) " Purpose : Determines the extension of a filename based on the register " alternate extension. This allow extension which contain dots to " be considered. E.g. foo.aspx.cs to foo.aspx where an alternate " exists for the aspx.cs extension. Note that this will only accept " extensions which contain less than 5 dots. This is only " implemented in this manner for simplicity...it is doubtful that " this will be a restriction in non-contrived situations. " Args : The path to the file to find the extension in " Returns : The matched extension if any " Author : Michael Sharpe (feline@irendi.com) " History : idea from Tom-Erik Duestad " Notes : there is some magic occuring here. The exists() function does not " work well when the curly brace variable has dots in it. And why " should it, dots are not valid in variable names. But the exists " function is wierd too. Lets say foo_c does exist. Then " exists("foo_c.e.f") will be true...even though the variable does " not exist. However the curly brace variables do work when the " variable has dots in it. E.g foo_{'c'} is different from " foo_{'c.d.e'}...and foo_{'c'} is identical to foo_c and " foo_{'c.d.e'} is identical to foo_c.d.e right? Yes in the current " implementation of vim. To trick vim to test for existence of such " variables echo the curly brace variable and look for an error " message. function! DetermineExtension(path) let mods = ":t" let i = 0 while i <= s:maxDotsInExtension let mods = mods . ":e" let extension = fnamemodify(a:path, mods) if (has_key(g:alternateExtensionsDict, extension)) return extension endif let v:errmsg = "" silent! echo g:alternateExtensions_{extension} if (v:errmsg == "") return extension endif let i = i + 1 endwhile return "" endfunction " Function : AlternateFile (PUBLIC) " Purpose : Opens a new buffer by looking at the extension of the current " buffer and finding the corresponding file. E.g. foo.c <--> foo.h " Args : accepts one argument. If present it used the argument as the new " extension. " Returns : nothing " Author : Michael Sharpe " History : + When an alternate can't be found in the same directory as the " source file, a search path will be traversed looking for the " alternates. " + Moved some code into a separate function, minor optimization " + rework to favor files in memory based on complete enumeration of " all files extensions and paths function! AlternateFile(splitWindow, ...) let extension = DetermineExtension(expand("%:p")) let baseName = substitute(expand("%:t"), "\." . extension . '$', "", "") let currentPath = expand("%:p:h") if (a:0 != 0) let newFullname = currentPath . "/" . baseName . "." . a:1 call FindOrCreateBuffer(newFullname, a:splitWindow, 0) else let allfiles = "" if (extension != "") let allfiles1 = EnumerateFilesByExtension(currentPath, baseName, extension) let allfiles2 = EnumerateFilesByExtensionInPath(baseName, extension, g:alternateSearchPath, currentPath) if (allfiles1 != "") if (allfiles2 != "") let allfiles = allfiles1 . ',' . allfiles2 else let allfiles = allfiles1 endif else let allfiles = allfiles2 endif endif if (allfiles != "") let bestFile = "" let bestScore = 0 let score = 0 let n = 1 let onefile = GetNthItemFromList(allfiles, n) let bestFile = onefile while (onefile != "" && score < 2) let score = BufferOrFileExists(onefile) if (score > bestScore) let bestScore = score let bestFile = onefile endif let n = n + 1 let onefile = GetNthItemFromList(allfiles, n) endwhile if (bestScore == 0 && g:alternateNoDefaultAlternate == 1) echo "No existing alternate available" else call FindOrCreateBuffer(bestFile, a:splitWindow, 1) let b:AlternateAllFiles = allfiles endif else echo "No alternate file/buffer available" endif endif endfunction " Function : AlternateOpenFileUnderCursor (PUBLIC) " Purpose : Opens file under the cursor " Args : splitWindow -- indicates how to open the file " Returns : Nothing " Author : Michael Sharpe (feline@irendi.com) www.irendi.com function! AlternateOpenFileUnderCursor(splitWindow,...) let cursorFile = (a:0 > 0) ? a:1 : expand("") let currentPath = expand("%:p:h") let openCount = 1 let fileName = FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, openCount) if (fileName != "") call FindOrCreateBuffer(fileName, a:splitWindow, 1) let b:openCount = openCount let b:cursorFile = cursorFile let b:currentPath = currentPath else echo "Can't find file" endif endfunction " Function : AlternateOpenNextFile (PUBLIC) " Purpose : Opens the next file corresponding to the search which found the " current file " Args : bang -- indicates what to do if the current file has not been " saved " Returns : nothing " Author : Michael Sharpe (feline@irendi.com) www.irendi.com function! AlternateOpenNextFile(bang) let cursorFile = "" if (exists("b:cursorFile")) let cursorFile = b:cursorFile endif let currentPath = "" if (exists("b:currentPath")) let currentPath = b:currentPath endif let openCount = 0 if (exists("b:openCount")) let openCount = b:openCount + 1 endif if (cursorFile != "" && currentPath != "" && openCount != 0) let fileName = FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, openCount) if (fileName != "") call FindOrCreateBuffer(fileName, "n".a:bang, 0) let b:openCount = openCount let b:cursorFile = cursorFile let b:currentPath = currentPath else let fileName = FindFileInSearchPathEx(cursorFile, g:alternateSearchPath, currentPath, 1) if (fileName != "") call FindOrCreateBuffer(fileName, "n".a:bang, 0) let b:openCount = 1 let b:cursorFile = cursorFile let b:currentPath = currentPath else echo "Can't find next file" endif endif endif endfunction comm! -nargs=? -bang IH call AlternateOpenFileUnderCursor("n", ) comm! -nargs=? -bang IHS call AlternateOpenFileUnderCursor("h", ) comm! -nargs=? -bang IHV call AlternateOpenFileUnderCursor("v", ) comm! -nargs=? -bang IHT call AlternateOpenFileUnderCursor("t", ) comm! -nargs=? -bang IHN call AlternateOpenNextFile("") imap ih :IHS nmap ih :IHS imap is :IHS:A nmap is :IHS:A imap ihn :IHN nmap ihn :IHN "function! PrintList(theList) " let n = 1 " let oneFile = GetNthItemFromList(a:theList, n) " while (oneFile != "") " let n = n + 1 " let oneFile = GetNthItemFromList(a:theList, n) " endwhile "endfunction " Function : NextAlternate (PUBLIC) " Purpose : Used to cycle through any other alternate file which existed on " the search path. " Args : bang (IN) - used to implement the AN vs AN! functionality " Returns : nothing " Author : Michael Sharpe function! NextAlternate(bang) if (exists('b:AlternateAllFiles')) let currentFile = expand("%") let n = 1 let onefile = GetNthItemFromList(b:AlternateAllFiles, n) while (onefile != "" && !EqualFilePaths(fnamemodify(onefile,":p"), fnamemodify(currentFile,":p"))) let n = n + 1 let onefile = GetNthItemFromList(b:AlternateAllFiles, n) endwhile if (onefile != "") let stop = n let n = n + 1 let foundAlternate = 0 let nextAlternate = "" while (n != stop) let nextAlternate = GetNthItemFromList(b:AlternateAllFiles, n) if (nextAlternate == "") let n = 1 continue endif let n = n + 1 if (EqualFilePaths(fnamemodify(nextAlternate, ":p"), fnamemodify(currentFile, ":p"))) continue endif if (filereadable(nextAlternate)) " on cygwin filereadable("foo.H") returns true if "foo.h" exists if (has("unix") && $WINDIR != "" && fnamemodify(nextAlternate, ":p") ==? fnamemodify(currentFile, ":p")) continue endif let foundAlternate = 1 break endif endwhile if (foundAlternate == 1) let s:AlternateAllFiles = b:AlternateAllFiles "silent! execute ":e".a:bang." " . nextAlternate call FindOrCreateBuffer(nextAlternate, "n".a:bang, 0) let b:AlternateAllFiles = s:AlternateAllFiles else echo "Only this alternate file exists" endif else echo "Could not find current file in alternates list" endif else echo "No other alternate files exist" endif endfunction comm! -nargs=? -bang A call AlternateFile("n", ) comm! -nargs=? -bang AS call AlternateFile("h", ) comm! -nargs=? -bang AV call AlternateFile("v", ) comm! -nargs=? -bang AT call AlternateFile("t", ) comm! -nargs=? -bang AN call NextAlternate("") " Function : BufferOrFileExists (PRIVATE) " Purpose : determines if a buffer or a readable file exists " Args : fileName (IN) - name of the file to check " Returns : 2 if it exists in memory, 1 if it exists, 0 otherwise " Author : Michael Sharpe " History : Updated code to handle buffernames using just the " filename and not the path. function! BufferOrFileExists(fileName) let result = 0 let lastBuffer = bufnr("$") let i = 1 while i <= lastBuffer if EqualFilePaths(expand("#".i.":p"), a:fileName) let result = 2 break endif let i = i + 1 endwhile if (!result) let bufName = fnamemodify(a:fileName,":t") let memBufName = bufname(bufName) if (memBufName != "") let memBufBasename = fnamemodify(memBufName, ":t") if (bufName == memBufBasename) let result = 2 endif endif if (!result) let result = bufexists(bufName) || bufexists(a:fileName) || filereadable(a:fileName) endif endif if (!result) let result = filereadable(a:fileName) endif return result endfunction " Function : FindOrCreateBuffer (PRIVATE) " Purpose : searches the buffer list (:ls) for the specified filename. If " found, checks the window list for the buffer. If the buffer is in " an already open window, it switches to the window. If the buffer " was not in a window, it switches to that buffer. If the buffer did " not exist, it creates it. " Args : filename (IN) -- the name of the file " doSplit (IN) -- indicates whether the window should be split " ("v", "h", "n", "v!", "h!", "n!", "t", "t!") " findSimilar (IN) -- indicate weather existing buffers should be " prefered " Returns : nothing " Author : Michael Sharpe " History : + bufname() was not working very well with the possibly strange " paths that can abound with the search path so updated this " slightly. -- Bindu " + updated window switching code to make it more efficient -- Bindu " Allow ! to be applied to buffer/split/editing commands for more " vim/vi like consistency " + implemented fix from Matt Perry function! FindOrCreateBuffer(fileName, doSplit, findSimilar) " Check to see if the buffer is already open before re-opening it. let FILENAME = a:fileName let bufNr = -1 let lastBuffer = bufnr("$") let i = 1 if (a:findSimilar) while i <= lastBuffer if EqualFilePaths(expand("#".i.":p"), a:fileName) let bufNr = i break endif let i = i + 1 endwhile if (bufNr == -1) let bufName = bufname(a:fileName) let bufFilename = fnamemodify(a:fileName,":t") if (bufName == "") let bufName = bufname(bufFilename) endif if (bufName != "") let tail = fnamemodify(bufName, ":t") if (tail != bufFilename) let bufName = "" endif endif if (bufName != "") let bufNr = bufnr(bufName) let FILENAME = bufName endif endif endif let splitType = a:doSplit[0] let bang = a:doSplit[1] if (bufNr == -1) " Buffer did not exist....create it let v:errmsg="" if (splitType == "h") silent! execute ":split".bang." " . FILENAME elseif (splitType == "v") silent! execute ":vsplit".bang." " . FILENAME elseif (splitType == "t") silent! execute ":tab split".bang." " . FILENAME else silent! execute ":e".bang." " . FILENAME endif if (v:errmsg != "") echo v:errmsg endif else " Find the correct tab corresponding to the existing buffer let tabNr = -1 " iterate tab pages for i in range(tabpagenr('$')) " get the list of buffers in the tab let tabList = tabpagebuflist(i + 1) let idx = 0 " iterate each buffer in the list while idx < len(tabList) " if it matches the buffer we are looking for... if (tabList[idx] == bufNr) " ... save the number let tabNr = i + 1 break endif let idx = idx + 1 endwhile if (tabNr != -1) break endif endfor " switch the the tab containing the buffer if (tabNr != -1) execute "tabn ".tabNr endif " Buffer was already open......check to see if it is in a window let bufWindow = bufwinnr(bufNr) if (bufWindow == -1) " Buffer was not in a window so open one let v:errmsg="" if (splitType == "h") silent! execute ":sbuffer".bang." " . FILENAME elseif (splitType == "v") silent! execute ":vert sbuffer " . FILENAME elseif (splitType == "t") silent! execute ":tab sbuffer " . FILENAME else silent! execute ":buffer".bang." " . FILENAME endif if (v:errmsg != "") echo v:errmsg endif else " Buffer is already in a window so switch to the window execute bufWindow."wincmd w" if (bufWindow != winnr()) " something wierd happened...open the buffer let v:errmsg="" if (splitType == "h") silent! execute ":split".bang." " . FILENAME elseif (splitType == "v") silent! execute ":vsplit".bang." " . FILENAME elseif (splitType == "t") silent! execute ":tab split".bang." " . FILENAME else silent! execute ":e".bang." " . FILENAME endif if (v:errmsg != "") echo v:errmsg endif endif endif endif endfunction " Function : EqualFilePaths (PRIVATE) " Purpose : Compares two paths. Do simple string comparison anywhere but on " Windows. On Windows take into account that file paths could differ " in usage of separators and the fact that case does not matter. " "c:\WINDOWS" is the same path as "c:/windows". has("win32unix") Vim " version does not count as one having Windows path rules. " Args : path1 (IN) -- first path " path2 (IN) -- second path " Returns : 1 if path1 is equal to path2, 0 otherwise. " Author : Ilya Bobir function! EqualFilePaths(path1, path2) if has("win16") || has("win32") || has("win64") || has("win95") return substitute(a:path1, "\/", "\\", "g") ==? substitute(a:path2, "\/", "\\", "g") else return a:path1 == a:path2 endif endfunction