neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

options.lua (2621B)


      1 local api = vim.api
      2 
      3 local M = {}
      4 
      5 local function get_ftplugin_runtime(filetype)
      6  local files = api.nvim__get_runtime({
      7    string.format('ftplugin/%s.vim', filetype),
      8    string.format('ftplugin/%s_*.vim', filetype),
      9    string.format('ftplugin/%s/*.vim', filetype),
     10    string.format('ftplugin/%s.lua', filetype),
     11    string.format('ftplugin/%s_*.lua', filetype),
     12    string.format('ftplugin/%s/*.lua', filetype),
     13  }, true, {}) --[[@as string[] ]]
     14 
     15  local r = {} ---@type string[]
     16  for _, f in ipairs(files) do
     17    -- VIMRUNTIME should be static so shouldn't need to worry about it changing
     18    if not vim.startswith(f, vim.env.VIMRUNTIME) then
     19      r[#r + 1] = f
     20    end
     21  end
     22  return r
     23 end
     24 
     25 -- Keep track of ftplugin files
     26 local ftplugin_cache = {} ---@type table<string,table<string,integer>>
     27 
     28 -- Keep track of total number of FileType autocmds
     29 local ft_autocmd_num ---@type integer?
     30 
     31 -- Keep track of filetype options
     32 local ft_option_cache = {} ---@type table<string,table<string,any>>
     33 
     34 --- @param path string
     35 --- @return integer
     36 local function hash(path)
     37  local mtime0 = vim.uv.fs_stat(path).mtime
     38  return mtime0.sec * 1000000000 + mtime0.nsec
     39 end
     40 
     41 --- Only update the cache on changes to the number of FileType autocmds
     42 --- and changes to any ftplugin/ file. This isn't guaranteed to catch everything
     43 --- but should be good enough.
     44 --- @param filetype string
     45 local function update_ft_option_cache(filetype)
     46  local new_ftautos = #api.nvim_get_autocmds({ event = 'FileType' })
     47  if new_ftautos ~= ft_autocmd_num then
     48    -- invalidate
     49    ft_option_cache[filetype] = nil
     50    ft_autocmd_num = new_ftautos
     51  end
     52 
     53  local files = get_ftplugin_runtime(filetype)
     54 
     55  ftplugin_cache[filetype] = ftplugin_cache[filetype] or {}
     56 
     57  if #files ~= #vim.tbl_keys(ftplugin_cache[filetype]) then
     58    -- invalidate
     59    ft_option_cache[filetype] = nil
     60    ftplugin_cache[filetype] = {}
     61  end
     62 
     63  for _, f in ipairs(files) do
     64    local mtime = hash(f)
     65    if ftplugin_cache[filetype][f] ~= mtime then
     66      -- invalidate
     67      ft_option_cache[filetype] = nil
     68      ftplugin_cache[filetype][f] = mtime
     69    end
     70  end
     71 end
     72 
     73 --- @nodoc
     74 --- @param filetype string Filetype
     75 --- @param option string Option name
     76 --- @return string|integer|boolean
     77 function M.get_option(filetype, option)
     78  update_ft_option_cache(filetype)
     79 
     80  if not ft_option_cache[filetype] or ft_option_cache[filetype][option] == nil then
     81    ft_option_cache[filetype] = ft_option_cache[filetype] or {}
     82    ft_option_cache[filetype][option] = api.nvim_get_option_value(option, { filetype = filetype })
     83  end
     84 
     85  return ft_option_cache[filetype][option]
     86 end
     87 
     88 return M