diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 70c605464a..8f9078cdff 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -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. ============================================================================== diff --git a/runtime/filetype.lua b/runtime/filetype.lua index 730991a00c..e471faf75b 100644 --- a/runtime/filetype.lua +++ b/runtime/filetype.lua @@ -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, diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 549ff6b977..295925593f 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -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}. diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index b6622472af..9b3d6f6e19 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -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()