From 095b9f98f3e37b53520c766a12cb413dd0589028 Mon Sep 17 00:00:00 2001 From: xvzc Date: Fri, 24 Oct 2025 09:34:12 +0900 Subject: [PATCH] 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()`. --- runtime/lua/vim/filetype.lua | 8 ++++++++ test/functional/lua/filetype_spec.lua | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index e80d09497c..f116d89322 100644 --- 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 index e52f64eab3..b6622472af 100644 --- 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',