8000 mini.nvim/lua/mini/snippets.lua at main · gerazov/mini.nvim · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
2683 lines (2435 loc) · 119 KB

snippets.lua

File metadata and controls

2683 lines (2435 loc) · 119 KB
local patterns = opts.lang_patterns[lang]
if patterns == nil and lang == '' then return {} end
-- NOTE: Don't use `{json,lua}` for better compatibility, as it seems that
-- its support might depend on the shell (and might not work on Windows).
-- Which is shame because fewer patterns used mean fewer calls to cache.
patterns = patterns
or { lang .. '/**/*.json', lang .. '/**/*.lua', '**/' .. lang .. '.json', '**/' .. lang .. '.lua' }
local res = {}
for _, pat in ipairs(patterns) do
local loader = loaders[pat] or MiniSnippets.gen_loader.from_runtime(pat, loader_opts)
loaders[pat] = loader
table.insert(res, loader(context))
end
return res
end
end
--- Generate runtime loader
---
--- Output loads files which match `pattern` inside "snippets/" directories from
--- 'runtimepath'. This is useful to simultaneously read several similarly
--- named files from different sources. Order from 'runtimepath' is preserved.
---
--- Typical case is loading snippets for a language from files like `xxx.{json,lua}`
--- but located in different "snippets/" directories inside 'runtimepath'.
--- - `<config>`/snippets/lua.json - manually curated snippets in user config.
--- - `<path/to/installed/plugin>`/snippets/lua.json - from installed plugin.
--- - `<config>`/after/snippets/lua.json - used to adjust snippets from plugins.
--- For example, remove some snippets by using prefixes and no body.
---
---@param pattern string Pattern of files to read. Can have wildcards as described
--- in |nvim_get_runtime_file()|. Example for "lua" language: `'lua.{json,lua}'`.
---@param opts table|nil Options. Possible fields:
--- - <all> `(boolean)` - whether to load from all matching runtime files.
--- Default: `true`.
--- - __minisnippets_cache_opt
--- Note: caching is done per `pattern` value, which assumes that both
--- 'runtimepath' value and snippet files do not change during Neovim session.
--- Caching this way gives significant speed improvement by reducing the need
--- to traverse file system on every snippet expand.
--- - __minisnippets_silent_opt
---
---@return __minisnippets_loader_return
MiniSnippets.gen_loader.from_runtime = function(pattern, opts)
if type(pattern) ~= 'string' then H.error('`pattern` should be string') end
opts = vim.tbl_extend('force', { all = true, cache = true, silent = false }, opts or {})
pattern = 'snippets/' .. pattern
local cache, read_opts = opts.cache, { cache = opts.cache, silent = opts.silent }
local read = function(p) return MiniSnippets.read_file(p, read_opts) end
return function()
if cache and H.cache.runtime[pattern] ~= nil then return vim.deepcopy(H.cache.runtime[pattern]) end
local res = vim.tbl_map(read, vim.api.nvim_get_runtime_file(pattern, opts.all))
if cache then H.cache.runtime[pattern] = vim.deepcopy(res) end
return res
end
end
--- Generate single file loader
---
--- Output is a thin wrapper around |MiniSnippets.read_file()| which will skip
--- warning if file is absent (other messages are still shown). Use it to load
--- file which is not guaranteed to exist (like project-local snippets).
---
---@param path string Same as in |MiniSnippets.read_file()|.
---@param opts table|nil Same as in |MiniSnippets.read_file()|.
---
---@return __minisnippets_loader_return
MiniSnippets.gen_loader.from_file = function(path, opts)
if type(path) ~= 'string' then H.error('`path` should be string') end
opts = vim.tbl_extend('force', { cache = true, silent = false }, opts or {})
return function()
local full_path = vim.fn.fnamemodify(path, ':p')
if vim.fn.filereadable(full_path) ~= 1 then return {} end
return MiniSnippets.read_file(full_path, opts) or {}
end
end
--- Read file with snippet data
---
---@param path string Path to file with snippets. Can be relative.
--- See |MiniSnippets-file-specification| for supported file formats.
---@param opts table|nil Options. Possible fields:
--- - __minisnippets_cache_opt
--- Note: Caching is done per full path only after successful reading.
--- - __minisnippets_silent_opt
---
---@return table|nil Array of snippets or `nil` if failed (also warn with |vim.notify()|
--- about the reason).
MiniSnippets.read_file = function(path, opts)
if type(path) ~= 'string' then H.error('`path` should be string') end
opts = vim.tbl_extend('force', { cache = true, silent = false }, opts or {})
path = vim.fn.fnamemodify(path, ':p')
local problem_prefix = 'There were problems reading file ' .. path .. ':\n'
if opts.cache and H.cache.file[path] ~= nil then return vim.deepcopy(H.cache.file[path]) end
if vim.fn.filereadable(path) ~= 1 then
return H.notify(problem_prefix .. 'File is absent or not readable', 'WARN', opts.silent)
end
local ext = path:match('%.([^%.]+)$')
if ext == nil or not (ext == 'lua' or ext == 'json' or ext == 'code-snippets') then
return H.notify(problem_prefix .. 'Extension is not supported', 'WARN', opts.silent)
end
local res = H.file_readers[ext](path, opts.silent)
-- Notify about problems but still cache if there are read snippets
local prob = table.concat(res.problems, '\n')
if prob ~= '' then H.notify(problem_prefix .. prob, 'WARN', opts.silent) end
if res.snippets == nil then return nil end
if opts.cache then H.cache.file[path] = vim.deepcopy(res.snippets) end
return res.snippets
end
--- Default prepare
---
--- Normalize raw snippets (as in `snippets` from |MiniSnippets.config|) based on
--- supplied context:
--- - Traverse and flatten nested arrays. Function loaders are executed with
--- `opts.context` as argument and output is processed recursively.
0