aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/fs.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/fs.lua')
-rw-r--r--runtime/lua/vim/fs.lua84
1 files changed, 74 insertions, 10 deletions
diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua
index b05220ee2c..ccddf826f7 100644
--- a/runtime/lua/vim/fs.lua
+++ b/runtime/lua/vim/fs.lua
@@ -1,6 +1,10 @@
+local uv = vim.uv
+
local M = {}
-local iswin = vim.uv.os_uname().sysname == 'Windows_NT'
+-- Can't use `has('win32')` because the `nvim -ll` test runner doesn't support `vim.fn` yet.
+local sysname = uv.os_uname().sysname:lower()
+local iswin = not not (sysname:find('windows') or sysname:find('mingw'))
local os_sep = iswin and '\\' or '/'
--- Iterate over all the parents of the given path.
@@ -21,6 +25,7 @@ local os_sep = iswin and '\\' or '/'
--- end
--- ```
---
+---@since 10
---@param start (string) Initial path.
---@return fun(_, dir: string): string? # Iterator
---@return nil
@@ -40,6 +45,7 @@ end
--- Return the parent directory of the given path
---
+---@since 10
---@generic T : string|nil
---@param file T Path
---@return T Parent directory of {file}
@@ -69,6 +75,7 @@ end
--- Return the basename of the given path
---
+---@since 10
---@generic T : string|nil
---@param file T Path
---@return T Basename of {file}
@@ -89,6 +96,7 @@ end
--- Concatenate directories and/or file paths into a single path with normalization
--- (e.g., `"foo/"` and `"bar"` get joined to `"foo/bar"`)
---
+---@since 12
---@param ... string
---@return string
function M.joinpath(...)
@@ -99,6 +107,7 @@ end
--- Return an iterator over the items located in {path}
---
+---@since 10
---@param path (string) An absolute or relative path to the directory to iterate
--- over. The path is first normalized |vim.fs.normalize()|.
--- @param opts table|nil Optional keyword arguments:
@@ -122,12 +131,12 @@ function M.dir(path, opts)
path = M.normalize(path)
if not opts.depth or opts.depth == 1 then
- local fs = vim.uv.fs_scandir(path)
+ local fs = uv.fs_scandir(path)
return function()
if not fs then
return
end
- return vim.uv.fs_scandir_next(fs)
+ return uv.fs_scandir_next(fs)
end
end
@@ -138,9 +147,9 @@ function M.dir(path, opts)
--- @type string, integer
local dir0, level = unpack(table.remove(dirs, 1))
local dir = level == 1 and dir0 or M.joinpath(path, dir0)
- local fs = vim.uv.fs_scandir(dir)
+ local fs = uv.fs_scandir(dir)
while fs do
- local name, t = vim.uv.fs_scandir_next(fs)
+ local name, t = uv.fs_scandir_next(fs)
if not name then
break
end
@@ -210,6 +219,7 @@ end
--- end, {limit = math.huge, type = 'file'})
--- ```
---
+---@since 10
---@param names (string|string[]|fun(name: string, path: string): boolean) Names of the items to find.
--- Must be base names, paths and globs are not supported when {names} is a string or a table.
--- If {names} is a function, it is called for each traversed item with args:
@@ -234,7 +244,7 @@ function M.find(names, opts)
names = { names }
end
- local path = opts.path or assert(vim.uv.cwd())
+ local path = opts.path or assert(uv.cwd())
local stop = opts.stop
local limit = opts.limit or 1
@@ -265,7 +275,7 @@ function M.find(names, opts)
local t = {} --- @type string[]
for _, name in ipairs(names) do
local f = M.joinpath(p, name)
- local stat = vim.uv.fs_stat(f)
+ local stat = uv.fs_stat(f)
if stat and (not opts.type or opts.type == stat.type) then
t[#t + 1] = f
end
@@ -349,6 +359,7 @@ end
--- end)
--- ```
---
+--- @since 12
--- @param source integer|string Buffer number (0 for current buffer) or file path (absolute or
--- relative to the |current-directory|) to begin the search from.
--- @param marker (string|string[]|fun(name: string, path: string): boolean) A marker, or list
@@ -365,7 +376,7 @@ function M.root(source, marker)
path = source
elseif type(source) == 'number' then
if vim.bo[source].buftype ~= '' then
- path = assert(vim.uv.cwd())
+ path = assert(uv.cwd())
else
path = vim.api.nvim_buf_get_name(source)
end
@@ -528,6 +539,7 @@ end
--- [[\\?\UNC\server\share\foo\..\..\..\bar]] => "//?/UNC/server/share/bar"
--- ```
---
+---@since 10
---@param path (string) Path to normalize
---@param opts? vim.fs.normalize.Opts
---@return (string) : Normalized path
@@ -552,7 +564,7 @@ function M.normalize(path, opts)
-- Expand ~ to users home directory
if vim.startswith(path, '~') then
- local home = vim.uv.os_homedir() or '~'
+ local home = uv.os_homedir() or '~'
if home:sub(-1) == os_sep_local then
home = home:sub(1, -2)
end
@@ -561,7 +573,7 @@ function M.normalize(path, opts)
-- Expand environment variables if `opts.expand_env` isn't `false`
if opts.expand_env == nil or opts.expand_env then
- path = path:gsub('%$([%w_]+)', vim.uv.os_getenv)
+ path = path:gsub('%$([%w_]+)', uv.os_getenv)
end
if win then
@@ -609,4 +621,56 @@ function M.normalize(path, opts)
return path
end
+--- @param path string Path to remove
+--- @param ty string type of path
+--- @param recursive? boolean
+--- @param force? boolean
+local function rm(path, ty, recursive, force)
+ --- @diagnostic disable-next-line:no-unknown
+ local rm_fn
+
+ if ty == 'directory' then
+ if recursive then
+ for file, fty in vim.fs.dir(path) do
+ rm(M.joinpath(path, file), fty, true, force)
+ end
+ elseif not force then
+ error(string.format('%s is a directory', path))
+ end
+
+ rm_fn = uv.fs_rmdir
+ else
+ rm_fn = uv.fs_unlink
+ end
+
+ local ret, err, errnm = rm_fn(path)
+ if ret == nil and (not force or errnm ~= 'ENOENT') then
+ error(err)
+ end
+end
+
+--- @class vim.fs.rm.Opts
+--- @inlinedoc
+---
+--- Remove directories and their contents recursively
+--- @field recursive? boolean
+---
+--- Ignore nonexistent files and arguments
+--- @field force? boolean
+
+--- Remove files or directories
+--- @since 13
+--- @param path string Path to remove
+--- @param opts? vim.fs.rm.Opts
+function M.rm(path, opts)
+ opts = opts or {}
+
+ local stat, err, errnm = uv.fs_stat(path)
+ if stat then
+ rm(path, stat.type, opts.recursive, opts.force)
+ elseif not opts.force or errnm ~= 'ENOENT' then
+ error(err)
+ end
+end
+
return M