feat(stdlib): vim.fs.ext() returns file extension #36997

Problem:
Checking the extension of a file is done often, e.g. in Nvim's codebase
for differentiating Lua and Vimscript files in the runtime. The current
way to do this in Lua is (1) a Lua pattern match, which has pitfalls
such as not considering filenames starting with a dot, or (2)
fnamemodify() which is both hard to discover and hard to use / read if
not very familiar with the possible modifiers.

vim.fs.ext() returns the file extension including the leading dot of
the extension. Similar to the "file extension" implementation of many
other stdlibs (including fnamemodify(file, ":e")), a leading dot
doesn't indicate the start of the extension. E.g.: the .git folder in a
repository doesn't have the extension .git, but it simply has no
extension, similar to a folder named git or any other filename without
dot(s).
This commit is contained in:
Yochem van Rosmalen
2026-03-20 10:08:00 +01:00
committed by GitHub
parent 1244fe157f
commit 72a63346d8
7 changed files with 57 additions and 5 deletions

View File

@@ -409,7 +409,7 @@ end
---
--- -- Find the parent directory containing any file with a .csproj extension
--- vim.fs.root(0, function(name, path)
--- return name:match('%.csproj$') ~= nil
--- return vim.fs.ext(name) == 'csproj'
--- end)
---
--- -- Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if
@@ -835,4 +835,27 @@ function M.relpath(base, target, opts)
return vim.startswith(target, base) and target:sub(#base + 1) or nil
end
--- Return the file's last extension, if any.
---
--- Similar to |fnamemodify()| with the |::e| modifier. The extension does not include a leading
--- period.
---
--- Examples:
---
--- ```lua
--- vim.fs.ext('archive.tar.gz') -- 'gz'
--- vim.fs.ext('~/.git') -- ''
--- vim.fs.ext('plugin/myplug.lua') -- 'lua'
--- ```
---
---@since 14
---@param file string Path
---@param opts table? Reserved for future use
---@return string Extension of {file}
function M.ext(file, opts)
vim.validate('file', file, 'string')
vim.validate('opts', opts, 'table', true)
return vim.fn.fnamemodify(file, ':e')
end
return M