1 " Vim script
  2 " Maintainer: Peter Odding <peter@peterodding.com>
  3 " Last Change: June 15, 2010
  4 " URL: http://peterodding.com/code/vim/profile/autoload/xolox/path.vim
  5 
  6 let s:windows_compatible = has('win32') || has('win64')
  7 
  8 " split() -- split a pathname into a list of path components {{{1
  9 
 10 function! xolox#path#split(path)
 11   if type(a:path) == type('')
 12     if s:windows_compatible
 13       return split(a:path, '[\/]\+')
 14     else
 15       let absolute = (a:path =~ '^/')
 16       let segments = split(a:path, '/\+')
 17       return absolute ? insert(segments, '/') : segments
 18     endif
 19   endif
 20   return []
 21 endfunction
 22 
 23 " join() -- join a list of path components into a pathname {{{1
 24 
 25 function! xolox#path#join(parts)
 26   if type(a:parts) == type([])
 27     if !s:windows_compatible && a:parts[0] == '/'
 28       return join(a:parts, '/')[1 : -1]
 29     else
 30       return join(a:parts, '/')
 31     endif
 32   endif
 33   return ''
 34 endfunction
 35 
 36 " absolute() -- canonicalize and resolve a pathname {{{1
 37 
 38 function! xolox#path#absolute(path)
 39   if type(a:path) == type('')
 40     let path = fnamemodify(a:path, ':p')
 41     " resolve() doesn't work when there's a trailing path separator.
 42     if path =~ '/$'
 43       let stripped_slash = 1
 44       let path = substitute(path, '/$', '', '')
 45     endif
 46     let path = resolve(path)
 47     " Restore the path separator after calling resolve().
 48     if exists('stripped_slash') && path !~ '/$'
 49       let path .= '/'
 50     endif
 51     return path
 52   endif
 53   return ''
 54 endfunction
 55 
 56 " relative() -- make an absolute pathname relative {{{1
 57 
 58 function! xolox#path#relative(path, base)
 59   let path = xolox#path#split(a:path)
 60   let base = xolox#path#split(a:base)
 61   while path != [] && base != [] && path[0] == base[0]
 62     call remove(path, 0)
 63     call remove(base, 0)
 64   endwhile
 65   let distance = repeat(['..'], len(base))
 66   return xolox#path#join(distance + path)
 67 endfunction
 68 
 69 " merge() -- join a directory and filename into a single pathname {{{1
 70 
 71 function! xolox#path#merge(parent, child)
 72   if type(a:parent) == type('') && type(a:child) == type('')
 73     if s:windows_compatible
 74       let parent = substitute(a:parent, '[\\/]\+$', '', '')
 75       let child = substitute(a:child, '^[\\/]\+', '', '')
 76       return parent . '/' . child
 77     else
 78       let parent = substitute(a:parent, '/\+$', '', '')
 79       let child = substitute(a:child, '^/\+', '', '')
 80       return parent . '/' . child
 81     endif
 82   endif
 83   return ''
 84 endfunction
 85 
 86 " commonprefix() -- find the common prefix of path components in a list of pathnames {{{1
 87 
 88 function! xolox#path#commonprefix(paths)
 89   let common = xolox#path#split(a:paths[0])
 90   for path in a:paths
 91     let index = 0
 92     for segment in xolox#path#split(path)
 93       if len(common) <= index
 94         break
 95       elseif common[index] != segment
 96         call remove(common, index, -1)
 97         break
 98       endif
 99       let index += 1
100     endfor
101   endfor
102   return xolox#path#join(common)
103 endfunction
104 
105 " encode() -- encode a pathname so it can be used as a filename {{{1
106 
107 function! xolox#path#encode(path)
108   let mask = s:windows_compatible ? '[*|\\/:"<>?%]' : '[\\/%]'
109   return substitute(a:path, mask, '\=printf("%%%x", char2nr(submatch(0)))', 'g')
110 endfunction
111 
112 " decode() -- decode a pathname previously encoded with xolox#path#encode() {{{1
113 
114 function! xolox#path#decode(encoded_path)
115   return substitute(a:encoded_path, '%\(\x\x\?\)', '\=nr2char("0x" . submatch(1))', 'g')
116 endfunction
117 
118 " equals() -- check whether two pathnames point to the same file {{{1
119 
120 if s:windows_compatible
121   function! xolox#path#equals(a, b)
122     return a:a ==? a:b || xolox#path#absolute(a:a) ==? xolox#path#absolute(a:b)
123   endfunction
124 else
125   function! xolox#path#equals(a, b)
126     return a:a ==# a:b || xolox#path#absolute(a:a) ==# xolox#path#absolute(a:b)
127   endfunction
128 endif
129 
130 " tempdir() -- create a temporary directory and return the path {{{1
131 
132 function! xolox#path#tempdir()
133   if !exists('s:tempdir_counter')
134     let s:tempdir_counter = 1
135   endif
136   if exists('*mkdir')
137     if s:windows_compatible
138       let template = $TMP . '\vim_tempdir_'
139     elseif filewritable('/tmp') == 2
140       let template = '/tmp/vim_tempdir_'
141     endif
142   endif
143   if !exists('template')
144     throw "xolox#path#tempdir() hasn't been implemented on your platform!"
145   endif
146   while 1
147     let directory = template . s:tempdir_counter
148     try
149       call mkdir(directory, '', 0700)
150       return directory
151     catch /\<E739\>/
152       " Keep looking for a non-existing directory.
153     endtry
154     let s:tempdir_counter += 1
155   endwhile
156 endfunction
157 
158 " vim: ts=2 sw=2 et