mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	feat: add vim.filetype.get_option()
				
					
				
			This commit is contained in:
		@@ -1971,8 +1971,8 @@ nvim_get_option_value({name}, {*opts})               *nvim_get_option_value()*
 | 
			
		||||
                  Implies {scope} is "local".
 | 
			
		||||
                • filetype: |filetype|. Used to get the default option for a
 | 
			
		||||
                  specific filetype. Cannot be used with any other option.
 | 
			
		||||
                  Note: this is expensive, it is recommended to cache this
 | 
			
		||||
                  value.
 | 
			
		||||
                  Note: this will trigger |ftplugin| and all |FileType|
 | 
			
		||||
                  autocommands for the corresponding filetype.
 | 
			
		||||
 | 
			
		||||
    Return: ~
 | 
			
		||||
        Option value
 | 
			
		||||
 
 | 
			
		||||
@@ -2206,6 +2206,28 @@ add({filetypes})                                          *vim.filetype.add()*
 | 
			
		||||
      • {filetypes}  (table) A table containing new filetype maps (see
 | 
			
		||||
                     example).
 | 
			
		||||
 | 
			
		||||
get_option({filetype}, {option})                   *vim.filetype.get_option()*
 | 
			
		||||
    Get the default option value for a {filetype}.
 | 
			
		||||
 | 
			
		||||
    The returned value is what would be set in a new buffer after 'filetype'
 | 
			
		||||
    is set, meaning it should respect all FileType autocmds and ftplugin
 | 
			
		||||
    files.
 | 
			
		||||
 | 
			
		||||
    Example: >lua
 | 
			
		||||
      vim.filetype.get_option('vim', 'commentstring')
 | 
			
		||||
<
 | 
			
		||||
 | 
			
		||||
    Note: this uses |nvim_get_option_value()| but caches the result. This
 | 
			
		||||
    means |ftplugin| and |FileType| autocommands are only triggered once and
 | 
			
		||||
    may not reflect later changes.
 | 
			
		||||
 | 
			
		||||
    Parameters: ~
 | 
			
		||||
      • {filetype}  string Filetype
 | 
			
		||||
      • {option}    string Option name
 | 
			
		||||
 | 
			
		||||
    Return: ~
 | 
			
		||||
        string|boolean|integer: Option value
 | 
			
		||||
 | 
			
		||||
match({args})                                           *vim.filetype.match()*
 | 
			
		||||
    Perform filetype detection.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -213,6 +213,9 @@ The following new APIs or features were added.
 | 
			
		||||
• |nvim_get_option_value()| now has a `filetype` option so it can return the
 | 
			
		||||
  default option for a specific filetype.
 | 
			
		||||
 | 
			
		||||
• |vim.filetype.get_option()| to get the default option value for a specific
 | 
			
		||||
  filetype. This is a wrapper around |nvim_get_option_value()| with caching.
 | 
			
		||||
 | 
			
		||||
==============================================================================
 | 
			
		||||
CHANGED FEATURES                                                 *news-changes*
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2631,4 +2631,24 @@ function M.match(args)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- Get the default option value for a {filetype}.
 | 
			
		||||
---
 | 
			
		||||
--- The returned value is what would be set in a new buffer after 'filetype'
 | 
			
		||||
--- is set, meaning it should respect all FileType autocmds and ftplugin files.
 | 
			
		||||
---
 | 
			
		||||
--- Example:
 | 
			
		||||
--- <pre>lua
 | 
			
		||||
---   vim.filetype.get_option('vim', 'commentstring')
 | 
			
		||||
--- </pre>
 | 
			
		||||
---
 | 
			
		||||
--- Note: this uses |nvim_get_option_value()| but caches the result.
 | 
			
		||||
--- This means |ftplugin| and |FileType| autocommands are only
 | 
			
		||||
--- triggered once and may not reflect later changes.
 | 
			
		||||
--- @param filetype string Filetype
 | 
			
		||||
--- @param option string Option name
 | 
			
		||||
--- @return string|boolean|integer: Option value
 | 
			
		||||
function M.get_option(filetype, option)
 | 
			
		||||
  return require('vim.filetype.options').get_option(filetype, option)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return M
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										82
									
								
								runtime/lua/vim/filetype/options.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								runtime/lua/vim/filetype/options.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
local api = vim.api
 | 
			
		||||
 | 
			
		||||
local M = {}
 | 
			
		||||
 | 
			
		||||
local function get_ftplugin_runtime(filetype)
 | 
			
		||||
  return api.nvim__get_runtime({
 | 
			
		||||
    string.format('ftplugin/%s.vim', filetype),
 | 
			
		||||
    string.format('ftplugin/%s_*.vim', filetype),
 | 
			
		||||
    string.format('ftplugin/%s/*.vim', filetype),
 | 
			
		||||
    string.format('ftplugin/%s.lua', filetype),
 | 
			
		||||
    string.format('ftplugin/%s_*.lua', filetype),
 | 
			
		||||
    string.format('ftplugin/%s/*.lua', filetype),
 | 
			
		||||
  }, true, {}) --[[@as string[] ]]
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Keep track of ftplugin files
 | 
			
		||||
local ftplugin_cache = {} ---@type table<string,table<string,integer>>
 | 
			
		||||
 | 
			
		||||
-- Keep track of total number of FileType autocmds
 | 
			
		||||
local ft_autocmd_num ---@type integer?
 | 
			
		||||
 | 
			
		||||
-- Keep track of filetype options
 | 
			
		||||
local ft_option_cache = {} ---@type table<string,table<string,any>>
 | 
			
		||||
 | 
			
		||||
--- @param path string
 | 
			
		||||
--- @return integer
 | 
			
		||||
local function hash(path)
 | 
			
		||||
  local mtime0 = vim.loop.fs_stat(path).mtime
 | 
			
		||||
  return mtime0.sec * 1000000000 + mtime0.nsec
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- Only update the cache on changes to the number of FileType autocmds
 | 
			
		||||
--- and changes to any ftplugin/ file. This isn't guaranteed to catch everything
 | 
			
		||||
--- but should be good enough.
 | 
			
		||||
--- @param filetype string
 | 
			
		||||
local function update_ft_option_cache(filetype)
 | 
			
		||||
  local new_ftautos = #api.nvim_get_autocmds({ event = 'FileType' })
 | 
			
		||||
  if new_ftautos ~= ft_autocmd_num then
 | 
			
		||||
    -- invalidate
 | 
			
		||||
    ft_option_cache[filetype] = nil
 | 
			
		||||
    ft_autocmd_num = new_ftautos
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  local files = get_ftplugin_runtime(filetype)
 | 
			
		||||
 | 
			
		||||
  ftplugin_cache[filetype] = ftplugin_cache[filetype] or {}
 | 
			
		||||
 | 
			
		||||
  if #files ~= #vim.tbl_keys(ftplugin_cache[filetype]) then
 | 
			
		||||
    -- invalidate
 | 
			
		||||
    ft_option_cache[filetype] = nil
 | 
			
		||||
    ftplugin_cache[filetype] = {}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  for _, f in ipairs(files) do
 | 
			
		||||
    -- VIMRUNTIME should be static so shouldn't need to worry about it changing
 | 
			
		||||
    if not vim.startswith(f, vim.env.VIMRUNTIME) then
 | 
			
		||||
      local mtime = hash(f)
 | 
			
		||||
      if ftplugin_cache[filetype][f] ~= mtime then
 | 
			
		||||
        -- invalidate
 | 
			
		||||
        ft_option_cache[filetype] = nil
 | 
			
		||||
        ftplugin_cache[filetype][f] = mtime
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--- @private
 | 
			
		||||
--- @param filetype string Filetype
 | 
			
		||||
--- @param option string Option name
 | 
			
		||||
--- @return string|integer|boolean
 | 
			
		||||
function M.get_option(filetype, option)
 | 
			
		||||
  update_ft_option_cache(filetype)
 | 
			
		||||
 | 
			
		||||
  if not ft_option_cache[filetype] or not ft_option_cache[filetype][option] then
 | 
			
		||||
    ft_option_cache[filetype] = ft_option_cache[filetype] or {}
 | 
			
		||||
    ft_option_cache[filetype][option] = api.nvim_get_option_value(option, { filetype = filetype })
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  return ft_option_cache[filetype][option]
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return M
 | 
			
		||||
@@ -114,7 +114,11 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err)
 | 
			
		||||
 | 
			
		||||
  ftbuf->b_p_ft = xstrdup(filetype);
 | 
			
		||||
 | 
			
		||||
  apply_autocmds(EVENT_FILETYPE, ftbuf->b_p_ft, ftbuf->b_fname, true, ftbuf);
 | 
			
		||||
  TRY_WRAP({
 | 
			
		||||
    try_start();
 | 
			
		||||
    apply_autocmds(EVENT_FILETYPE, ftbuf->b_p_ft, ftbuf->b_fname, true, ftbuf);
 | 
			
		||||
    try_end(err);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return ftbuf;
 | 
			
		||||
}
 | 
			
		||||
@@ -133,8 +137,8 @@ static buf_T *do_ft_buf(char *filetype, aco_save_T *aco, Error *err)
 | 
			
		||||
///                         Implies {scope} is "local".
 | 
			
		||||
///                  - filetype: |filetype|. Used to get the default option for a
 | 
			
		||||
///                    specific filetype. Cannot be used with any other option.
 | 
			
		||||
///                    Note: this is expensive, it is recommended to cache this
 | 
			
		||||
///                    value.
 | 
			
		||||
///                    Note: this will trigger |ftplugin| and all |FileType|
 | 
			
		||||
///                    autocommands for the corresponding filetype.
 | 
			
		||||
/// @param[out] err  Error details, if any
 | 
			
		||||
/// @return          Option value
 | 
			
		||||
Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
 | 
			
		||||
 
 | 
			
		||||
@@ -1518,6 +1518,31 @@ describe('API', function()
 | 
			
		||||
      nvim('get_option_value', 'filetype', {buf = buf})
 | 
			
		||||
      eq({1, 9}, nvim('win_get_cursor', win))
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('can get default option values for filetypes', function()
 | 
			
		||||
      command('filetype plugin on')
 | 
			
		||||
      for ft, opts in pairs {
 | 
			
		||||
        lua = { commentstring = '-- %s' },
 | 
			
		||||
        vim = { commentstring = '"%s' },
 | 
			
		||||
        man = { tagfunc = 'v:lua.require\'man\'.goto_tag' },
 | 
			
		||||
        xml = { formatexpr = 'xmlformat#Format()' }
 | 
			
		||||
      } do
 | 
			
		||||
        for option, value in pairs(opts) do
 | 
			
		||||
          eq(value, nvim('get_option_value', option, { filetype = ft }))
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      command'au FileType lua setlocal commentstring=NEW\\ %s'
 | 
			
		||||
 | 
			
		||||
      eq('NEW %s', nvim('get_option_value', 'commentstring', { filetype = 'lua' }))
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
    it('errors for bad FileType autocmds', function()
 | 
			
		||||
      command'au FileType lua setlocal commentstring=BAD'
 | 
			
		||||
      eq([[FileType Autocommands for "lua": Vim(setlocal):E537: 'commentstring' must be empty or contain %s: commentstring=BAD]],
 | 
			
		||||
         pcall_err(nvim, 'get_option_value', 'commentstring', { filetype = 'lua' }))
 | 
			
		||||
    end)
 | 
			
		||||
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  describe('nvim_{get,set}_current_buf, nvim_list_bufs', function()
 | 
			
		||||
 
 | 
			
		||||
@@ -114,6 +114,21 @@ describe('vim.filetype', function()
 | 
			
		||||
    ]])
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('can get default option values for filetypes via vim.filetype.get_option()', function()
 | 
			
		||||
    command('filetype plugin on')
 | 
			
		||||
 | 
			
		||||
    for ft, opts in pairs {
 | 
			
		||||
      lua = { commentstring = '-- %s' },
 | 
			
		||||
      vim = { commentstring = '"%s' },
 | 
			
		||||
      man = { tagfunc = 'v:lua.require\'man\'.goto_tag' },
 | 
			
		||||
      xml = { formatexpr = 'xmlformat#Format()' }
 | 
			
		||||
    } do
 | 
			
		||||
      for option, value in pairs(opts) do
 | 
			
		||||
        eq(value, exec_lua([[ return vim.filetype.get_option(...) ]], ft, option))
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
describe('filetype.lua', function()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user