1
1
" Vim auto-load script
2
2
" Author: Peter Odding <peter@peterodding.com>
3
- " Last Change: April 18 , 2013
3
+ " Last Change: April 28 , 2013
4
4
" URL: http://peterodding.com/code/vim/misc/
5
5
6
6
let s: windows_compatible = has (' win32' ) || has (' win64' )
7
7
let s: mac_os_x_compatible = has (' macunix' )
8
8
9
- function ! xolox#misc#path#which (... )
9
+ function ! xolox#misc#path#which (... ) " {{{1
10
+ " Scan the executable search path for programs.
10
11
let extensions = s: windows_compatible ? split ($PATHEXT , ' ;' ) : [' ' ]
11
12
let matches = []
12
13
let checked = {}
@@ -29,13 +30,24 @@ function! xolox#misc#path#which(...)
29
30
return matches
30
31
endfunction
31
32
32
- " Split a pathname into a list of path components.
33
-
34
- function ! xolox#misc#path#split (path )
33
+ function ! xolox#misc#path#split (path ) " {{{1
34
+ " Split a pathname into a list of path components.
35
35
if type (a: path ) == type (' ' )
36
36
if s: windows_compatible
37
- return split (a: path , ' [\/]\+' )
37
+ if a: path = ~ ' ^[\/][\/]'
38
+ " On Windows, pathnames starting with two slashes or backslashes are
39
+ " UNC paths where the leading slashes are significant... In this case
40
+ " we split like this:
41
+ " '//server/share/directory' -> ['//server', 'share', 'directory']
42
+ return split (a: path , ' \%>2c[\/]\+' )
43
+ else
44
+ " If it's not a UNC path we can simply split on slashes & backslashes.
45
+ return split (a: path , ' [\/]\+' )
46
+ endif
38
47
else
48
+ " Everything except Windows is treated like UNIX until someone
49
+ " has a better suggestion :-). In this case we split like this:
50
+ " '/foo/bar/baz' -> ['/', 'foo', 'bar', 'baz']
39
51
let absolute = (a: path = ~ ' ^/' )
40
52
let segments = split (a: path , ' /\+' )
41
53
return absolute ? insert (segments, ' /' ) : segments
@@ -44,42 +56,61 @@ function! xolox#misc#path#split(path)
44
56
return []
45
57
endfunction
46
58
47
- " Join a list of path components into a pathname.
48
-
49
- function ! xolox#misc#path#join (parts)
59
+ function ! xolox#misc#path#join (parts) " {{{1
60
+ " Join a list of pathname components into a single pathname.
50
61
if type (a: parts ) == type ([])
51
- if ! s: windows_compatible && a: parts [0 ] == ' /'
52
- return join (a: parts , ' /' )[1 : -1 ]
62
+ if s: windows_compatible
63
+ return join (a: parts , xolox#misc#path#directory_separator ())
64
+ elseif a: parts [0 ] == ' /'
65
+ " Absolute path on UNIX (non-Windows).
66
+ return ' /' . join (a: parts [1 :], ' /' )
53
67
else
68
+ " Relative path on UNIX (non-Windows).
54
69
return join (a: parts , ' /' )
55
70
endif
56
71
endif
57
72
return ' '
58
73
endfunction
59
74
60
- " Canonicalize and resolve a pathname.
75
+ function ! xolox#misc#path#directory_separator () " {{{1
76
+ " Find the preferred directory separator for the platform and settings.
77
+ return exists (' +shellslash' ) && &shellslash ? ' /' : ' \'
78
+ endfunction
61
79
62
- function ! xolox#misc#path#absolute (path )
80
+ function ! xolox#misc#path#absolute (path ) " {{{1
81
+ " Canonicalize and resolve a pathname, regardless of whether it exists. This
82
+ " is intended to support string comparison to determine whether two pathnames
83
+ " point to the same directory or file.
63
84
if type (a: path ) == type (' ' )
64
- let path = fnamemodify (a: path , ' :p' )
65
- " resolve() doesn't work when there's a trailing path separator.
66
- if path = ~ ' /$'
67
- let stripped_slash = 1
68
- let path = substitute (path , ' /$' , ' ' , ' ' )
85
+ let path = a: path
86
+ " Make the pathname absolute.
87
+ if path = ~ ' ^\~'
88
+ " Expand ~ to $HOME.
89
+ let path = $HOME . ' /' . path [1 :]
90
+ elseif xolox#misc#path#is_relative (path )
91
+ " Make relative pathnames absolute.
92
+ let path = getcwd () . ' /' . path
69
93
endif
70
- let path = resolve (path )
71
- " Restore the path separator after calling resolve().
72
- if exists (' stripped_slash' ) && path !~ ' /$'
73
- let path .= ' /'
94
+ " Resolve symbolic links to find the canonical pathname. In my tests this
95
+ " also removes all symbolic pathname segments (`.' and `..'), even when
96
+ " the pathname does not exist. Also there used to be a bug in resolve()
97
+ " where it wouldn't resolve pathnames ending in a directory separator.
98
+ " Since it's not much trouble to work around, that's what we do.
99
+ let path = resolve (substitute (path , s: windows_compatible ? ' [\/]\+$' : ' /\+$' , ' ' , ' ' ))
100
+ " Normalize directory separators (especially relevant on Windows).
101
+ let parts = xolox#misc#path#split (path )
102
+ if s: windows_compatible && parts[0 ] = ~ ' ^[\/][\/]'
103
+ " Also normalize the two leading "directory separators" (I'm not
104
+ " sure what else to call them :-) in Windows UNC pathnames.
105
+ let parts[0 ] = repeat (xolox#misc#path#directory_separator (), 2 ) . parts[0 ][2 :]
74
106
endif
75
- return path
107
+ return xolox#misc# path#join (parts)
76
108
endif
77
109
return ' '
78
110
endfunction
79
111
80
- " Make an absolute pathname relative.
81
-
82
- function ! xolox#misc#path#relative (path , base)
112
+ function ! xolox#misc#path#relative (path , base) " {{{1
113
+ " Make an absolute pathname relative.
83
114
let path = xolox#misc#path#split (a: path )
84
115
let base = xolox#misc#path#split (a: base )
85
116
while path != [] && base != [] && path [0 ] == base[0 ]
@@ -90,9 +121,9 @@ function! xolox#misc#path#relative(path, base)
90
121
return xolox#misc#path#join (distance + path )
91
122
endfunction
92
123
93
- " Join a directory and filename into a single pathname.
94
124
95
- function ! xolox#misc#path#merge (parent, child, ... )
125
+ function ! xolox#misc#path#merge (parent, child, ... ) " {{{1
126
+ " Join a directory and filename into a single pathname.
96
127
" TODO Use isabs()!
97
128
if type (a: parent ) == type (' ' ) && type (a: child ) == type (' ' )
98
129
if s: windows_compatible
@@ -108,9 +139,8 @@ function! xolox#misc#path#merge(parent, child, ...)
108
139
return ' '
109
140
endfunction
110
141
111
- " Find the common prefix of path components in a list of pathnames.
112
-
113
- function ! xolox#misc#path#commonprefix (paths)
142
+ function ! xolox#misc#path#commonprefix (paths) " {{{1
143
+ " Find the common prefix of path components in a list of pathnames.
114
144
let common = xolox#misc#path#split (a: paths [0 ])
115
145
for path in a: paths
116
146
let index = 0
@@ -127,9 +157,8 @@ function! xolox#misc#path#commonprefix(paths)
127
157
return xolox#misc#path#join (common)
128
158
endfunction
129
159
130
- " Encode a pathname so it can be used as a filename.
131
-
132
- function ! xolox#misc#path#encode (path )
160
+ function ! xolox#misc#path#encode (path ) " {{{1
161
+ " Encode a pathname so it can be used as a filename.
133
162
if s: windows_compatible
134
163
let mask = ' [*|\\/:"<>?%]'
135
164
elseif s: mac_os_x_compatible
@@ -140,13 +169,13 @@ function! xolox#misc#path#encode(path)
140
169
return substitute (a: path , mask, ' \=printf("%%%x", char2nr(submatch(0)))' , ' g' )
141
170
endfunction
142
171
143
- " Decode a pathname previously encoded with xolox#misc#path#encode().
144
172
145
- function ! xolox#misc#path#decode (encoded_path)
173
+ function ! xolox#misc#path#decode (encoded_path) " {{{1
174
+ " Decode a pathname previously encoded with xolox#misc#path#encode().
146
175
return substitute (a: encoded_path , ' %\(\x\x\?\)' , ' \=nr2char("0x" . submatch(1))' , ' g' )
147
176
endfunction
148
177
149
- " Check whether two pathnames point to the same file.
178
+ " xolox#misc#path#equals(a, b) - Check whether two pathnames point to the same file. {{{1
150
179
151
180
if s: windows_compatible
152
181
function ! xolox#misc#path#equals (a , b )
158
187
endfunction
159
188
endif
160
189
161
- " Check whether a path is relative.
162
-
163
- function ! xolox#misc#path#is_relative (path )
190
+ function ! xolox#misc#path#is_relative (path ) " {{{1
191
+ " Check whether a path is relative.
164
192
if a: path = ~ ' ^\w\+://'
165
193
return 0
166
194
elseif s: windows_compatible
@@ -170,9 +198,8 @@ function! xolox#misc#path#is_relative(path)
170
198
endif
171
199
endfunction
172
200
173
- " Create a temporary directory and return the path.
174
-
175
- function ! xolox#misc#path#tempdir ()
201
+ function ! xolox#misc#path#tempdir () " {{{1
202
+ " Create a temporary directory and return the path.
176
203
if ! exists (' s:tempdir_counter' )
177
204
let s: tempdir_counter = 1
178
205
endif
0 commit comments