Skip to content

Commit 577995c

Browse files
committed
rename
1 parent 826613f commit 577995c

File tree

2 files changed

+124
-2
lines changed

2 files changed

+124
-2
lines changed

lua/plenary/path2.lua

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
--- `C:/Users/test/test_file` relative to `C:/Windows/temp` is
4949
--- `../../Users/test/test_file` and there's no home directory absolute path
5050
--- in this.
51+
---
52+
--- - rename returns new path rather than mutating path
5153

5254
local bit = require "plenary.bit"
5355
local uv = vim.loop
@@ -346,6 +348,7 @@ end
346348
---@field relparts string[] path separator separated relative path parts
347349
---@field sep string path separator (respects 'shellslash' on Windows)
348350
---@field filename string
351+
---@field name string the final path component (eg. "foo/bar/baz.lua" -> "baz.lua")
349352
---@field cwd string
350353
---@field private _absolute string? lazy eval'ed fully resolved absolute path
351354
local Path = { path = path }
@@ -363,6 +366,15 @@ Path.__index = function(t, k)
363366
return rawget(t, k)
364367
end
365368

369+
if k == "name" then
370+
if #t.relparts > 0 then
371+
t.name = t.relparts[#t.relparts]
372+
else
373+
t.name = ""
374+
end
375+
return t.name
376+
end
377+
366378
if k == "anchor" then
367379
t.anchor = t.drv .. t.root
368380
return t.anchor
@@ -901,15 +913,13 @@ function Path:rm(opts)
901913

902914
for p, dirs, files in self:walk(false) do
903915
for _, file in ipairs(files) do
904-
print("delete file", file, (p / file):absolute())
905916
local _, err = uv.fs_unlink((p / file):absolute())
906917
if err then
907918
error(err)
908919
end
909920
end
910921

911922
for _, dir in ipairs(dirs) do
912-
print("delete dir", dir, (p / dir):absolute())
913923
local _, err = uv.fs_rmdir((p / dir):absolute())
914924
if err then
915925
error(err)
@@ -920,6 +930,29 @@ function Path:rm(opts)
920930
self:rmdir()
921931
end
922932

933+
---@class plenary.Path2.renameOpts
934+
---@field new_name string|plenary.Path2 destination path
935+
936+
---@param opts plenary.Path2.renameOpts
937+
---@return plenary.Path2
938+
function Path:rename(opts)
939+
if not opts.new_name or opts.new_name == "" then
940+
error "Please provide the new name!"
941+
end
942+
943+
local new_path = self:parent() / opts.new_name ---@type plenary.Path2
944+
945+
if new_path:exists() then
946+
error "File or directory already exists!"
947+
end
948+
949+
local _, err = uv.fs_rename(self:absolute(), new_path:absolute())
950+
if err ~= nil then
951+
error(err)
952+
end
953+
return new_path
954+
end
955+
923956
--- read file synchronously or asynchronously
924957
---@param callback fun(data: string)? callback to use for async version, nil for default
925958
---@return string? data

tests/plenary/path2_spec.lua

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,95 @@ describe("Path2", function()
546546
end)
547547
end)
548548

549+
describe("rename", function()
550+
after_each(function()
551+
uv.fs_unlink "a_random_filename.lua"
552+
uv.fs_unlink "not_a_random_filename.lua"
553+
uv.fs_unlink "some_random_filename.lua"
554+
uv.fs_unlink "../some_random_filename.lua"
555+
end)
556+
557+
it_cross_plat("can rename a file", function()
558+
local p = Path:new "a_random_filename.lua"
559+
assert.no_error(function()
560+
p:touch()
561+
end)
562+
assert.is_true(p:exists())
563+
564+
local new_p
565+
assert.no_error(function()
566+
new_p = p:rename { new_name = "not_a_random_filename.lua" }
567+
end)
568+
assert.not_nil(new_p)
569+
assert.are.same("not_a_random_filename.lua", new_p.name)
570+
end)
571+
572+
it_cross_plat("can handle an invalid filename", function()
573+
local p = Path:new "some_random_filename.lua"
574+
assert.no_error(function()
575+
p:touch()
576+
end)
577+
assert.is_true(p:exists())
578+
579+
assert.has_error(function()
580+
p:rename { new_name = "" }
581+
end)
582+
assert.has_error(function()
583+
---@diagnostic disable-next-line: missing-fields
584+
p:rename {}
585+
end)
586+
587+
assert.are.same("some_random_filename.lua", p.name)
588+
end)
589+
590+
it_cross_plat("can move to parent dir", function()
591+
local p = Path:new "some_random_filename.lua"
592+
assert.no_error(function()
593+
p:touch()
594+
end)
595+
assert.is_true(p:exists())
596+
597+
local new_p
598+
assert.no_error(function()
599+
new_p = p:rename { new_name = "../some_random_filename.lua" }
600+
end)
601+
assert.not_nil(new_p)
602+
assert.are.same(Path:new("../some_random_filename.lua"):absolute(), new_p:absolute())
603+
end)
604+
605+
it_cross_plat("cannot rename to an existing filename", function()
606+
local p1 = Path:new "a_random_filename.lua"
607+
local p2 = Path:new "not_a_random_filename.lua"
608+
assert.no_error(function()
609+
p1:touch()
610+
p2:touch()
611+
end)
612+
assert.is_true(p1:exists())
613+
assert.is_true(p2:exists())
614+
615+
assert.has_error(function()
616+
p1:rename { new_name = "not_a_random_filename.lua" }
617+
end)
618+
assert.are.same(p1.filename, "a_random_filename.lua")
619+
end)
620+
621+
it_cross_plat("handles Path as new_name", function()
622+
local p1 = Path:new "a_random_filename.lua"
623+
local p2 = Path:new "not_a_random_filename.lua"
624+
assert.no_error(function()
625+
p1:touch()
626+
end)
627+
assert.is_true(p1:exists())
628+
629+
local new_p
630+
assert.no_error(function()
631+
new_p = p1:rename { new_name = p2 }
632+
end)
633+
assert.not_nil(new_p)
634+
assert.are.same("not_a_random_filename.lua", new_p.name)
635+
end)
636+
end)
637+
549638
describe("parents", function()
550639
it_cross_plat("should extract the ancestors of the path", function()
551640
local p = Path:new(vim.fn.getcwd())

0 commit comments

Comments
 (0)