vim.fs
Methods14
function M.parents(start: string) -> (fun(_, dir: string) -> nil | string, nil, nil | string)
Iterate over all the parents of the given path (not expanded/resolved, the caller must do that).
Example:
local root_dir
for dir in vim.fs.parents(vim.api.nvim_buf_get_name(0)) do
if vim.fn.isdirectory(dir .. '/.git') == 1 then
root_dir = dir
break
end
end
if root_dir then
print('Found git repository at', root_dir)
end
startstringInitial path.
- fun(_, dir: string) -> nil | string
Iterator
- nil
- nil | string
@since 10
function M.dirname<T>(file: T) -> T
Gets the parent directory of the given path (not expanded/resolved, the caller must do that).
fileTPath
- T
Parent directory of
file
@since 10
function M.basename<T>(file: T) -> T
Gets the basename of the given path (not expanded/resolved).
fileTPath
- T
Basename of
file
@since 10
function M.joinpath(...: string) -> string
Concatenates partial paths (one absolute or relative path followed by zero or more relative paths). Slashes are normalized: redundant slashes are removed, and (on Windows) backslashes are replaced with forward-slashes. Empty segments are removed. Paths are not expanded/resolved.
Examples:
- "foo/", "/bar" => "foo/bar"
- "", "after/plugin" => "after/plugin"
- Windows: "afoo", "bar" => "a/foo/bar"
@since 12
function M.slug(path: string, opts: sub<table,maxlen> | nil) -> string
Gets a filesystem-safe, mnemonic slug (readable prefix + short hash) of an arbitrary filepath or other "identity string".
- The input is normalized so equivalent paths produce the same result.
- A hash of the normalized input is appended to prevent collisions.
- Unsafe chars are replaced with "-".
$HOMEis replaced with "~".- UNC paths (Windows) are prefixed with "=unc-".
- If
opts.maxlenis exceeded, the result will be truncated to{head}~~~{tail}-{hash8}. - If the sanitized name is empty, the reserved label
=specialwill be used.
Examples:
vim.print(vim.fs.slug('/tmp/test/foo.md')) --> "tmp-test-foo.md-{hash}"
vim.print(vim.fs.slug('C:/src/project/main.c')) --> "C--src-project-main.c-{hash}"
vim.print(vim.fs.slug(vim.fn.expand('~/file.txt'))) --> "~-file.txt-{hash}"
vim.print(vim.fs.slug('---')) --> "=special-{hash}"
vim.print(vim.fs.slug(('/a/very/long/path'):rep(10) .. '/file.txt', { maxlen = 60 }))
--> "a-very-long-~~~-path-a-very-long-path-file.txt-{hash}"
pathstringFilepath (or other identity string).
optssub<table,maxlen> | nil: (integer, default: 180) Max length (bytes) of the result.
- string
Filesystem-safe, mnemonic slug.
@since 15
function M.dir(path: string, opts: vim.fs.dir.Opts | nil) -> fun() -> ...nil | string
Gets an iterator over items found in path (normalized via |vim.fs.normalize()|).
Example:
for name, type, err in vim.fs.dir(path, { err = true }) do
if err then
-- Failed to scan directory {name} (may be the root {path} itself).
end
end
pathstringDirectory to iterate over, expanded (unless
opts.plain=true) and normalized.optsvim.fs.dir.Opts | nil
- fun() -> ...nil | string
Iterator over items in {path}, yielding (name, type, err):
- name: Basename of the item relative to {path}.
- type: One of: "file", "directory", "link", "fifo", "socket", "char", "block", "unknown".
- err: Error string, or nil. Only if
opts.err=true. If the root {path} itself could not
be scanned, yields a single (name, nil, err) item.
@since 10
function M.find(names: string | string[] | fun(name: string, path: string) -> boolean, opts: vim.fs.find.Opts | nil) -> (string[], string[])
Find files or directories (or other items as specified by opts.type) in the given path.
Finds items given in {names} starting from {path}. If {upward} is "true" then the search traverses upward through parent directories; otherwise, the search traverses downward. Note that downward searches are recursive and may search through many directories! If {stop} is non-nil, then the search stops when the directory given in {stop} is reached. The search terminates when {limit} (default 1) matches are found. You can set {type} to "file", "directory", "link", "socket", "char", "block", or "fifo" to narrow the search to find only that type.
Examples:
-- List all test directories under the runtime directory.
local dirs = vim.fs.find(
{ 'test', 'tst', 'testdir' },
{ limit = math.huge, type = 'directory', path = './runtime/' }
)
-- Get all "lib/*.cpp" and "lib/*.hpp" files, using Lua patterns.
-- Or use `vim.glob.to_lpeg(…):match(…)` for glob/wildcard matching.
local files = vim.fs.find(function(name, path)
return name:match('.*%.[ch]pp$') and path:match('[/\\]lib$')
end, { limit = math.huge, type = 'file' })
namesstring | string[] | fun(name: string, path: string) -> booleanNames 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:
- name: base name of the current item
- path: full path of the current item
The function should return
trueif the given item is considered a match.optsvim.fs.find.Opts | nilOptional keyword arguments:
- string[]
Normalized paths |vim.fs.normalize()| of all matching items.
- string[]
Errors collected while searching.
@since 10
function M.root(source: string | integer, marker: string | string[] | fun(name: string, path: string) -> boolean[] | string | fun(name: string, path: string) -> boolean) -> nil | string
Find the first parent directory containing a specific "marker", relative to a file path or buffer.
If the buffer is unnamed (has no backing file) or has a non-empty 'buftype' then the search begins from Nvim's |current-directory|.
Examples:
-- Find the root of a Python project, starting from file 'main.py'
vim.fs.root(vim.fs.joinpath(vim.env.PWD, 'main.py'), {'pyproject.toml', 'setup.py' })
-- Find the root of a git repository
vim.fs.root(0, '.git')
-- Find the parent directory containing any file with a .csproj extension
vim.fs.root(0, function(name, path)
return vim.fs.ext(name) == 'csproj'
end)
-- Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if
-- not found, find the first ancestor containing ".git":
vim.fs.root(0, { { 'stylua.toml', '.luarc.json' }, '.git' })
sourcestring | integerBuffer number (0 for current buffer) or file path (absolute or relative, expanded via
abspath()) to begin the search from.markerstring | string[] | fun(name: string, path: string) -> boolean[] | string | fun(name: string, path: string) -> boolean
- nil | string
Directory path containing one of the given markers, or nil if no directory was found.
@since 12
function M.normalize(path: string, opts: vim.fs.normalize.Opts | nil) -> string
Normalize a path to a standard format. Expands environment variables, and tilde "~" at the beginning of the path. Resolves "." and ".." components, except when the path is relative and resolving it would produce an absolute path.
- "." as the only part in a relative path:
- "." => "."
- "././" => "."
- ".." when it leads outside the current directory
- "foo/../../bar" => "../bar"
- "../../foo" => "../../foo"
- ".." in the root directory returns the root directory.
- "/../../" => "/"
On Windows, backslashes (\) are converted to forward slashes (/).
Examples:
[[C:\Users\jdoe]] --> "C:/Users/jdoe"
"~/src/neovim" --> "/home/jdoe/src/neovim"
"$XDG_CONFIG_HOME/nvim/init.vim" --> "/Users/jdoe/.config/nvim/init.vim"
"~/src/nvim/api/../tui/./tui.c" --> "/home/jdoe/src/nvim/tui/tui.c"
"./foo/bar" --> "foo/bar"
"foo/../../../bar" --> "../../bar"
"/home/jdoe/../../../bar" --> "/bar"
"C:foo/../../baz" --> "C:../baz"
"C:/foo/../../baz" --> "C:/baz"
[[\\?\UNC\server\share\foo\..\..\..\bar]] --> "//?/UNC/server/share/bar"
pathstringPath to normalize
optsvim.fs.normalize.Opts | nil
- string
: Normalized path
@since 10
function M.mkdir(path: string, opts: vim.fs.mkdir.Opts | nil) -> nil
Creates a directory.
pathstringPath to create (not expanded/resolved).
optsvim.fs.mkdir.Opts | nilOptional keyword arguments.
- nil
@since 15
function M.rm(path: string, opts: vim.fs.rm.Opts | nil) -> nil
Removes a file or directory.
Removes symlinks without touching the origin. To remove the origin, resolve it explicitly with |uv.fs_realpath()|:
vim.fs.rm(vim.uv.fs_realpath('symlink-dir'), { recursive = true })
pathstringPath to remove (not expanded/resolved).
optsvim.fs.rm.Opts | nil
- nil
@since 13
function M.abspath(path: string, opts: vim.fs.abspath.Opts | nil) -> Absolute string
Converts path to an absolute path. Expands tilde (~) at the beginning of the path (unless plain=true). Does not check if the path exists, normalize the path, resolve symlinks or hardlinks (including "." and ".."), or expand environment variables. If the path is already absolute, it is returned unchanged. Converts \ path separators to /.
pathstringPath
optsvim.fs.abspath.Opts | nil
Absolutestringpath
@since 13
function M.relpath(base: string, target: string, opts: nil | table) -> nil | string
Gets target path relative to base, or nil if base is not an ancestor.
Example:
vim.fs.relpath('/var', '/var/lib') -- 'lib'
vim.fs.relpath('/var', '/usr/bin') -- nil
basestringtargetstringoptsnil | tableReserved for future use
- nil | string
@since 13
function M.ext(file: string, opts: nil | table) -> Extension string
Return the file's last extension, if any.
Similar to |fnamemodify()| with the |::e| modifier. The extension does not include a leading period.
Examples:
vim.fs.ext('archive.tar.gz') -- 'gz'
vim.fs.ext('~/.git') -- ''
vim.fs.ext('plugin/myplug.lua') -- 'lua'
filestringPath
optsnil | tableReserved for future use
Extensionstringof {file}
@since 14