Skip to content

Commit 9895af2

Browse files
committed
add path joining and is_dir
1 parent 977f057 commit 9895af2

File tree

2 files changed

+74
-19
lines changed

2 files changed

+74
-19
lines changed

lua/plenary/path2.lua

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ end
243243
---@field parts string[] path parts excluding separators
244244
---
245245
---@field filename string
246+
---@field cwd string
246247
---@field private _absolute string? lazy eval'ed fully resolved absolute path
247248
local Path = { path = path }
248249

@@ -256,6 +257,26 @@ Path.__index = function(t, k)
256257
t.filename = t:_filename()
257258
return t.filename
258259
end
260+
261+
if k == "cwd" then
262+
t.cwd = vim.fn.getcwd()
263+
return t.cwd
264+
end
265+
end
266+
267+
Path.__div = function(self, other)
268+
assert(Path.is_path(self))
269+
assert(Path.is_path(other) or type(other) == "string")
270+
271+
return self:joinpath(other)
272+
end
273+
274+
Path.__tostring = function(self)
275+
return self.filename
276+
end
277+
278+
Path.__concat = function(self, other)
279+
return self.filename .. other
259280
end
260281

261282
---@alias plenary.Path2Args string|plenary.Path2|(string|plenary.Path2)[]
@@ -310,18 +331,17 @@ function Path:new(...)
310331
end
311332
error "'Path' object is read-only"
312333
end,
334+
-- stylua: ignore start
335+
__div = function(t, other) return Path.__div(t, other) end,
336+
__concat = function(t, other) return Path.__concat(t, other) end,
337+
__tostring = function(t) return Path.__tostring(t) end,
313338
__metatable = Path,
339+
-- stylua: ignore end
314340
})
315341

316342
return obj
317343
end
318344

319-
---@param x any
320-
---@return boolean
321-
function Path.is_path(x)
322-
return getmetatable(x) == Path
323-
end
324-
325345
---@private
326346
---@param drv string?
327347
---@param root string?
@@ -344,6 +364,12 @@ function Path:_filename(drv, root, parts)
344364
return drv .. root .. relparts
345365
end
346366

367+
---@param x any
368+
---@return boolean
369+
function Path.is_path(x)
370+
return getmetatable(x) == Path
371+
end
372+
347373
---@return boolean
348374
function Path:is_absolute()
349375
if self.root == "" then
@@ -353,6 +379,16 @@ function Path:is_absolute()
353379
return self._path.has_drv and self.drv ~= ""
354380
end
355381

382+
--- if path doesn't exists, returns false
383+
---@return boolean
384+
function Path:is_dir()
385+
local stat = uv.fs_stat(self:absolute())
386+
if stat then
387+
return stat.type == "directory"
388+
end
389+
return false
390+
end
391+
356392
---@param parts string[] path parts
357393
---@return string[]
358394
local function resolve_dots(parts)
@@ -373,6 +409,10 @@ local function resolve_dots(parts)
373409
end
374410

375411
--- normalized and resolved absolute path
412+
---
413+
--- if given path doesn't exists and isn't already an absolute path, creates
414+
--- one using the cwd
415+
---
376416
--- respects 'shellslash' on Windows
377417
---@return string
378418
function Path:absolute()
@@ -381,16 +421,17 @@ function Path:absolute()
381421
end
382422

383423
local parts = resolve_dots(self.parts)
384-
local filename = self:_filename(self.drv, self.root, parts)
385424
if self:is_absolute() then
386-
self._absolute = filename
425+
self._absolute = self:_filename(nil, nil, parts)
387426
else
388427
-- using fs_realpath over fnamemodify
389428
-- fs_realpath resolves symlinks whereas fnamemodify doesn't but we're
390429
-- resolving/normalizing the path anyways for reasons of compat with old Path
391-
self._absolute = uv.fs_realpath(self:_filename())
430+
local p = uv.fs_realpath(self:_filename()) or Path:new({ self.cwd, self }):absolute()
392431
if self.path.isshellslash then
393-
self._absolute = self._absolute:gsub("\\", path.sep)
432+
self._absolute = p:gsub("\\", path.sep)
433+
else
434+
self._absolute = p
394435
end
395436
end
396437
return self._absolute

tests/plenary/path2_spec.lua

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -217,15 +217,29 @@ describe("Path2", function()
217217
assert.are.same(Path:new("lua", "plenary"), Path:new("lua"):joinpath "plenary")
218218
end)
219219

220-
-- it_cross_plat("can join paths with /", function()
221-
-- assert.are.same(Path:new("lua", "plenary"), Path:new "lua" / "plenary")
222-
-- end)
220+
it_cross_plat("can join paths with /", function()
221+
assert.are.same(Path:new("lua", "plenary"), Path:new "lua" / "plenary")
222+
end)
223+
224+
it_cross_plat("can join paths with paths", function()
225+
assert.are.same(Path:new("lua", "plenary"), Path:new("lua", Path:new "plenary"))
226+
end)
227+
228+
it_cross_plat("inserts slashes", function()
229+
assert.are.same("lua" .. path.sep .. "plenary", Path:new("lua", "plenary").filename)
230+
end)
223231

224-
-- it_cross_plat("can join paths with paths", function()
225-
-- assert.are.same(Path:new("lua", "plenary"), Path:new("lua", Path:new "plenary"))
226-
-- end)
232+
describe(".is_dir()", function()
233+
it_cross_plat("should find directories that exist", function()
234+
assert.are.same(true, Path:new("lua"):is_dir())
235+
end)
236+
237+
it_cross_plat("should return false when the directory does not exist", function()
238+
assert.are.same(false, Path:new("asdf"):is_dir())
239+
end)
227240

228-
-- it_cross_plat("inserts slashes", function()
229-
-- assert.are.same("lua" .. path.sep .. "plenary", Path:new("lua", "plenary").filename)
230-
-- end)
241+
it_cross_plat("should not show files as directories", function()
242+
assert.are.same(false, Path:new("README.md"):is_dir())
243+
end)
244+
end)
231245
end)

0 commit comments

Comments
 (0)