commit 095b9f98f3e37b53520c766a12cb413dd0589028
parent c05ff026bc8f4e8a1ee48b19ea384f7feb6e2d79
Author: xvzc <me@xvzc.dev>
Date: Fri, 24 Oct 2025 09:34:12 +0900
fix(filetype): handle invalid `bufnr` in _getlines(), _getline() #36272
**Problem:**
`vim.filetype.match({ filename = 'a.sh' })` returns `nil` because
an invalid buffer ID is passed to `vim.api.nvim_buf_get_lines()`.
For filetypes like `csh`, `txt`, or any other extensions that call
`_getlines()` or `_getline()` to detect their filetypes, the same
issue occurs.
When only the `filename` argument is passed, an error is raised
inside a `pcall()` that wraps the filetype detection function,
causing it to return no value without showing any error message.
**Solution:**
Validate the `bufnr` value in `_getlines()` and `_getline()`.
Diffstat:
2 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
@@ -46,6 +46,10 @@ end
---@param end_lnum integer|nil The line number of the last line (inclusive, 1-based)
---@return string[] # Array of lines
function M._getlines(bufnr, start_lnum, end_lnum)
+ if not bufnr or bufnr < 0 then
+ return {}
+ end
+
if start_lnum then
return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum or start_lnum, false)
end
@@ -59,6 +63,10 @@ end
---@param start_lnum integer The line number of the first line (inclusive, 1-based)
---@return string
function M._getline(bufnr, start_lnum)
+ if not bufnr or bufnr < 0 then
+ return ''
+ end
+
-- Return a single line
return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] or ''
end
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
@@ -55,6 +55,26 @@ describe('vim.filetype', function()
)
end)
+ it('works with filenames that call _getlines() internally #36272', function()
+ eq(
+ 'sh',
+ exec_lua(function()
+ vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$'
+ return vim.filetype.match({ filename = 'main.sh' })
+ end)
+ )
+ end)
+
+ it('works with filenames that call _getline() internally #36272', function()
+ eq(
+ 'text',
+ exec_lua(function()
+ vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$'
+ return vim.filetype.match({ filename = 'main.txt' })
+ end)
+ )
+ end)
+
it('works with filenames', function()
eq(
'nim',