Skip to content

Commit f3c0169

Browse files
committed
add write and fix read file closing
1 parent 72c8734 commit f3c0169

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

lua/plenary/path2.lua

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,7 @@ function Path:touch(opts)
888888

889889
if not not opts.parents then
890890
local mode = type(opts.parents) == "number" and opts.parents or nil ---@cast mode number?
891-
_ = Path:new(self:parent()):mkdir { mode = mode, parents = true, exists_ok = true }
891+
self:parent():mkdir { mode = mode, parents = true, exists_ok = true }
892892
end
893893

894894
local fd, err = uv.fs_open(self:absolute(), "w", opts.mode)
@@ -1061,11 +1061,16 @@ function Path:_read_sync()
10611061
if data == nil then
10621062
error(err)
10631063
end
1064+
1065+
_, err = uv.fs_close(fd)
1066+
if err ~= nil then
1067+
error(err)
1068+
end
10641069
return data
10651070
end
10661071

10671072
---@private
1068-
---@param callback fun(data: string) callback to use for async version, nil for default
1073+
---@param callback fun(data: string)
10691074
function Path:_read_async(callback)
10701075
uv.fs_open(self:absolute(), "r", 438, function(err_open, fd)
10711076
if err_open then
@@ -1081,7 +1086,12 @@ function Path:_read_async(callback)
10811086
if err_read or data == nil then
10821087
error(err_read)
10831088
end
1084-
callback(data)
1089+
uv.fs_close(fd, function(err_close)
1090+
if err_close then
1091+
error(err_close)
1092+
end
1093+
callback(data)
1094+
end)
10851095
end)
10861096
end)
10871097
end)
@@ -1201,6 +1211,38 @@ function Path:tail(lines)
12011211
return (table.concat(data):gsub("\n$", ""))
12021212
end
12031213

1214+
--- write to file
1215+
---@param data string|string[] data to write
1216+
---@param flags uv.aliases.fs_access_flags|integer flag used to open file (eg. "w" or "a")
1217+
---@param mode integer? mode used to open file (default: `438`)
1218+
---@return number # bytes written
1219+
function Path:write(data, flags, mode)
1220+
vim.validate {
1221+
txt = { data, { "s", "t" } },
1222+
flags = { flags, { "s", "n" } },
1223+
mode = { mode, "n", true },
1224+
}
1225+
1226+
mode = vim.F.if_nil(mode, 438)
1227+
local fd, err = uv.fs_open(self:absolute(), flags, mode)
1228+
if fd == nil then
1229+
error(err)
1230+
end
1231+
1232+
local b
1233+
b, err = uv.fs_write(fd, data, -1)
1234+
if b == nil then
1235+
error(err)
1236+
end
1237+
1238+
_, err = uv.fs_close(fd)
1239+
if err ~= nil then
1240+
error(err)
1241+
end
1242+
1243+
return b
1244+
end
1245+
12041246
---@param top_down boolean? walk from current path down (default: `true`)
12051247
---@return fun(): plenary.Path2?, string[]?, string[]? # iterator which yields (dirpath, dirnames, filenames)
12061248
function Path:walk(top_down)
@@ -1260,4 +1302,18 @@ function Path:walk(top_down)
12601302
end
12611303
end
12621304

1305+
--[[
1306+
Fail || Path2 write write string - windows (noshellslash)
1307+
./lua/plenary/path2.lua:896: EPERM: operation not permitted: C:\Users\jtrew\neovim\plenary.nvim\foobar
1308+
1309+
stack traceback:
1310+
...s/jtrew/neovim/plenary.nvim/tests/plenary/path2_spec.lua:859: in function <...s/jtrew/neovim/plenary.nvim/tests/plenary/path2_spec.lua:857>
1311+
1312+
]]
1313+
1314+
vim.o.shellslash = false
1315+
local p = Path:new "foobar"
1316+
p:touch()
1317+
vim.o.shellslash = true
1318+
12631319
return Path

tests/plenary/path2_spec.lua

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,52 @@ describe("Path2", function()
849849
end)
850850
end)
851851

852+
describe("write", function()
853+
after_each(function()
854+
uv.fs_unlink "foobar.txt"
855+
end)
856+
857+
it_cross_plat("can write string", function()
858+
local p = Path:new "foobar.txt"
859+
p:touch()
860+
assert.no_error(function()
861+
p:write("hello world", "w")
862+
end)
863+
864+
local content = p:read()
865+
assert.not_nil(content)
866+
assert.are.same("hello world", content)
867+
end)
868+
869+
it_cross_plat("can append string", function()
870+
local p = Path:new "foobar.txt"
871+
p:touch()
872+
assert.no_error(function()
873+
p:write("hello world", "w")
874+
end)
875+
876+
assert.no_error(function()
877+
p:write("\ngoodbye", "a")
878+
end)
879+
880+
local content = p:read()
881+
assert.not_nil(content)
882+
assert.are.same("hello world\ngoodbye", content)
883+
end)
884+
885+
it_cross_plat("can write string list", function()
886+
local p = Path:new "foobar.txt"
887+
p:touch()
888+
assert.no_error(function()
889+
p:write({ "hello", " ", "world" }, "w")
890+
end)
891+
892+
local content = p:read()
893+
assert.not_nil(content)
894+
assert.are.same("hello world", content)
895+
end)
896+
end)
897+
852898
describe("head", function()
853899
it_cross_plat("should read head of file", function()
854900
local p = Path:new "LICENSE"

0 commit comments

Comments
 (0)