fix(filetype): move fallback logic to vim.filetype.match() #30141

Problem:
Previously, the fallback logic to ".conf" was located outside of
`vim.filetype.match()` and directly within the AutoCmd definition. As a
result, `vim.filetype.match()` would return nil instead of ".conf" for
fallback cases (#30100).

Solution:
Added a boolean return value to `vim.filetype.match()` that indicates
whether the match was the result of fallback. If true, the filetype will
be set using `setf FALLBACK <ft>` instead of `setf <ft>`.
This commit is contained in:
Jonny Kong
2025-10-28 18:45:50 -07:00
committed by GitHub
parent c1b1c8c2e0
commit e2cb675705
4 changed files with 43 additions and 12 deletions

View File

@@ -2414,6 +2414,11 @@ vim.filetype.match({args}) *vim.filetype.match()*
(`function?`) A function that modifies buffer state when called (for
example, to set some filetype specific buffer variables). The function
accepts a buffer number as its only argument.
(`boolean?`) Return true if a match was found by falling back to a
generic filetype (e.g. ".conf"). If true, the filetype
should be set with `:setf FALLBACK conf`, which enables a later
|:setf| command to override the filetype. See `:help setf` for more
information.
==============================================================================

View File

@@ -11,21 +11,13 @@ vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile', 'StdinReadPost' }, {
if not vim.api.nvim_buf_is_valid(args.buf) then
return
end
local ft, on_detect = vim.filetype.match({
local ft, on_detect, is_fallback = vim.filetype.match({
-- The unexpanded file name is needed here. #27914
-- However, bufname() can't be used, as it doesn't work with :doautocmd. #31306
filename = args.file,
buf = args.buf,
})
if not ft then
-- Generic configuration file used as fallback
ft = require('vim.filetype.detect').conf(args.file, args.buf)
if ft then
vim._with({ buf = args.buf }, function()
vim.api.nvim_cmd({ cmd = 'setf', args = { 'FALLBACK', ft } }, {})
end)
end
else
if ft then
-- on_detect is called before setting the filetype so that it can set any buffer local
-- variables that may be used the filetype's ftplugin
if on_detect then
@@ -33,7 +25,10 @@ vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile', 'StdinReadPost' }, {
end
vim._with({ buf = args.buf }, function()
vim.api.nvim_cmd({ cmd = 'setf', args = { ft } }, {})
vim.api.nvim_cmd({
cmd = 'setf',
args = (is_fallback and { 'FALLBACK', ft } or { ft }),
}, {})
end)
end
end,

View File

@@ -3101,6 +3101,10 @@ end
---@return function|nil # A function that modifies buffer state when called (for example, to set some
--- filetype specific buffer variables). The function accepts a buffer number as
--- its only argument.
---@return boolean|nil # Return true if a match was found by falling back to a generic configuration
--- file (i.e., ".conf"). If true, the filetype should be set with
--- `:setf FALLBACK conf`, which enables a later |:setf| command to override the
--- filetype. See `:help setf` for more information.
function M.match(args)
vim.validate('arg', args, 'table')
@@ -3193,11 +3197,19 @@ function M.match(args)
return dispatch(extension[ext], name, bufnr)
end
)
if ok then
if ok and ft then
return ft, on_detect
end
end
end
-- Generic configuration file used as fallback
if name and bufnr then
local ft = detect.conf(name, bufnr)
if ft then
return ft, nil, true
end
end
end
--- Get the default option value for a {filetype}.

View File

@@ -210,6 +210,25 @@ describe('vim.filetype', function()
)
rmdir('Xfiletype')
end)
it('fallback to conf if any of the first five lines start with a #', function()
eq(
{ 'conf', true },
exec_lua(function()
local bufnr = vim.api.nvim_create_buf(true, false)
local lines = {
'# foo',
}
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
-- Needs to be set so detect.conf() doesn't fail
vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$'
local ft, _, fallback = vim.filetype.match({ buf = bufnr })
return { ft, fallback }
end)
)
end)
end)
describe('filetype.lua', function()