@@ -136,31 +136,70 @@ end
136
136
137
137
--- @param parts string[]
138
138
--- @param sep string
139
- --- @return string[] new_path
139
+ --- @return string[] new_parts
140
140
function _WindowsPath :expand (parts , sep )
141
- -- Variables have a percent sign on both sides: %ThisIsAVariable%
142
- -- The variable name can include spaces, punctuation and mixed case:
143
- -- %_Another Ex.ample%
144
- -- But they aren't case sensitive
145
- --
146
- -- A variable name may include any of the following characters:
147
- -- A-Z, a-z, 0-9, # $ ' ( ) * + , - . ? @ [ ] _ { } ~
148
- -- The first character of the name must not be numeric.
149
-
150
- -- this would be MUCH cleaner to implement with LPEG but backwards compatibility...
151
- local pattern = " %%[A-Za-z#$'()*+,%-.?@[%]_{}~][A-Za-z0-9#$'()*+,%-.?@[%]_{}~]*%%"
152
-
153
141
local new_parts = {}
142
+
143
+ local function add_expand (sub_parts , var , part , start , end_ )
144
+ --- @diagnostic disable-next-line : missing-parameter
145
+ local val = uv .os_getenv (var )
146
+ if val then
147
+ table.insert (sub_parts , (val :gsub (" \\ " , sep )))
148
+ else
149
+ table.insert (sub_parts , part :sub (start , end_ ))
150
+ end
151
+ end
152
+
154
153
for _ , part in ipairs (parts ) do
155
- part = part : gsub ( pattern , function ( m )
156
- local var_name = m : sub ( 2 , - 2 )
154
+ local sub_parts = {}
155
+ local i = 1
157
156
158
- --- @diagnostic disable-next-line : missing-parameter
159
- local var = uv .os_getenv (var_name )
160
- return var and (var :gsub (" \\ " , sep )) or m
161
- end )
157
+ while i <= # part do
158
+ local ch = part :sub (i , i )
159
+ if ch == " '" then -- no expansion inside single quotes
160
+ local end_ = part :find (" '" , i + 1 , true )
161
+ if end_ then
162
+ table.insert (sub_parts , part :sub (i , end_ ))
163
+ i = end_
164
+ else
165
+ table.insert (sub_parts , ch )
166
+ end
167
+ elseif ch == " %" then
168
+ local end_ = part :find (" %" , i + 1 , true )
169
+ if end_ then
170
+ local var = part :sub (i + 1 , end_ - 1 )
171
+ add_expand (sub_parts , var , part , i , end_ )
172
+ i = end_
173
+ else
174
+ table.insert (sub_parts , ch )
175
+ end
176
+ elseif ch == " $" then
177
+ local nextch = part :sub (i + 1 , i + 1 )
178
+ if nextch == " $" then
179
+ i = i + 1
180
+ table.insert (sub_parts , ch )
181
+ elseif nextch == " {" then
182
+ local end_ = part :find (" }" , i + 2 , true )
183
+ if end_ then
184
+ local var = part :sub (i + 2 , end_ - 1 )
185
+ add_expand (sub_parts , var , part , i , end_ )
186
+ i = end_
187
+ else
188
+ table.insert (sub_parts , ch )
189
+ end
190
+ else
191
+ local end_ = part :find (" [^%w_]" , i + 1 , false ) or # part + 1
192
+ local var = part :sub (i + 1 , end_ - 1 )
193
+ add_expand (sub_parts , var , part , i , end_ - 1 )
194
+ i = end_ - 1
195
+ end
196
+ else
197
+ table.insert (sub_parts , ch )
198
+ end
199
+ i = i + 1
200
+ end
162
201
163
- table.insert (new_parts , part )
202
+ table.insert (new_parts , table.concat ( sub_parts ) )
164
203
end
165
204
166
205
return new_parts
@@ -232,28 +271,47 @@ function _PosixPath:join(path, ...)
232
271
end
233
272
234
273
--- @param parts string[]
235
- --- @return string[] new_path
274
+ --- @return string[] new_parts
236
275
function _PosixPath :expand (parts )
237
- -- Environment variable names used by the utilities in the Shell and
238
- -- Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase
239
- -- letters, digits, and the '_' (underscore) from the characters defined in
240
- -- Portable Character Set and do not begin with a digit. Other characters may
241
- -- be permitted by an implementation; applications shall tolerate the
242
- -- presence of such names.
243
-
244
- local pattern = " %$[A-Z_][A-Z0-9_]*"
276
+ local function add_expand (sub_parts , var , part , start , end_ )
277
+ --- @diagnostic disable-next-line : missing-parameter
278
+ local val = uv .os_getenv (var )
279
+ if val then
280
+ table.insert (sub_parts , val )
281
+ else
282
+ table.insert (sub_parts , part :sub (start , end_ ))
283
+ end
284
+ end
245
285
246
286
local new_parts = {}
247
287
for _ , part in ipairs (parts ) do
248
- part = part :gsub (pattern , function (m )
249
- local var_name = m :sub (2 )
250
-
251
- --- @diagnostic disable-next-line : missing-parameter
252
- local var = uv .os_getenv (var_name )
253
- return var or m
254
- end )
288
+ local i = 1
289
+ local sub_parts = {}
290
+ while i <= # part do
291
+ local ch = part :sub (i , i )
292
+ if ch == " $" then
293
+ if part :sub (i + 1 , i + 1 ) == " {" then
294
+ local end_ = part :find (" }" , i + 2 , true )
295
+ if end_ then
296
+ local var = part :sub (i + 2 , end_ - 1 )
297
+ add_expand (sub_parts , var , part , i , end_ )
298
+ i = end_
299
+ else
300
+ table.insert (sub_parts , ch )
301
+ end
302
+ else
303
+ local end_ = part :find (" [^%w_]" , i + 1 , false ) or # part + 1
304
+ local var = part :sub (i + 1 , end_ - 1 )
305
+ add_expand (sub_parts , var , part , i , end_ - 1 )
306
+ i = end_ - 1
307
+ end
308
+ else
309
+ table.insert (sub_parts , ch )
310
+ end
311
+ i = i + 1
312
+ end
255
313
256
- table.insert (new_parts , part )
314
+ table.insert (new_parts , table.concat ( sub_parts ) )
257
315
end
258
316
259
317
return new_parts
@@ -714,15 +772,17 @@ function Path:absolute()
714
772
end
715
773
716
774
--- get the environment variable expanded filename
775
+ --- also expand ~/ but NOT ~user/ constructs
717
776
--- @return string
718
777
function Path :expand ()
719
778
local relparts = self ._flavor :expand (self .relparts , self .sep )
720
779
local filename = self :_filename (nil , nil , relparts )
721
780
722
- filename = filename :gsub (" ^~([^" .. self .sep .. " ]+)" .. self .sep , function (m )
723
- return Path :new (self .path .home ):parent ().filename .. self .sep .. m .. self .sep
724
- end )
725
- return (filename :gsub (" ^~" , self .path .home ))
781
+ if filename :sub (1 , 2 ) == " ~" .. self .sep then
782
+ filename = self .path .home .. filename :sub (2 )
783
+ end
784
+
785
+ return filename
726
786
end
727
787
728
788
--- @param ... plenary .Path2Args
0 commit comments