1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
local util = require("luasnip.util.util")
local Path = require("luasnip.util.path")
local loader_util = require("luasnip.loaders.util")
local session = require("luasnip.session")
local loader_data = require("luasnip.loaders.data")
local fs_watchers = require("luasnip.loaders.fs_watchers")
local log = require("luasnip.util.log").new("loader")
local M = {}
-- used to map cache-name to name passed to format.
local clean_name = {
vscode_packages = "vscode",
vscode_standalone = "vscode-standalone",
snipmate = "snipmate",
lua = "lua",
}
local function default_format(path, _)
path = path:gsub(
vim.pesc(vim.fn.stdpath("data") .. "/site/pack/packer/start"),
"$PLUGINS"
)
if vim.env.HOME then
path = path:gsub(vim.pesc(vim.env.HOME .. "/.config/nvim"), "$CONFIG")
end
return path
end
local function default_edit(file)
vim.cmd("edit " .. file)
end
--- Quickly jump to snippet-file from any source for the active filetypes.
---@param opts nil|table, options for this function:
--- - ft_filter: fn(filetype:string) -> bool
--- Optionally filter filetypes which can be picked from. `true` -> filetype
--- is listed, `false` -> not listed.
---
--- - format: fn(path:string, source_name:string) -> string|nil
--- source_name is one of "vscode", "snipmate" or "lua".
--- May be used to format the displayed items. For example, replace the
--- excessively long packer-path with something shorter.
--- If format returns nil for some item, the item will not be displayed.
---
--- - edit: fn(file:string): this function is called with the snippet-file as
--- the lone argument.
--- The default is a function which just calls `vim.cmd("edit " .. file)`.
function M.edit_snippet_files(opts)
opts = opts or {}
local format = opts.format or default_format
local edit = opts.edit or default_edit
local extend = opts.extend or function(_, _)
return {}
end
local function ft_edit_picker(ft, _)
if ft then
local ft_paths = {}
local items = {}
-- concat files from all loaders for the selected filetype ft.
for cache_name, ft_file_set in pairs({
vscode_packages = loader_data.vscode_ft_paths[ft],
vscode_standalone = {},
snipmate = loader_data.snipmate_ft_paths[ft],
lua = loader_data.lua_ft_paths[ft],
}) do
for path, _ in pairs(ft_file_set or {}) do
local fmt_name = format(path, clean_name[cache_name])
if fmt_name then
table.insert(ft_paths, path)
table.insert(items, fmt_name)
end
end
end
-- extend filetypes with user-defined function.
local extended = extend(ft, ft_paths)
assert(
type(extended) == "table",
"You must return a table in extend function"
)
for _, pair in ipairs(extended) do
table.insert(items, pair[1])
table.insert(ft_paths, pair[2])
end
-- prompt user again if there are multiple files providing this filetype.
if #ft_paths > 1 then
vim.ui.select(items, {
prompt = "Multiple files for this filetype, choose one:",
}, function(_, indx)
if indx and ft_paths[indx] then
edit(ft_paths[indx])
end
end)
elseif ft_paths[1] then
edit(ft_paths[1])
end
end
end
local ft_filter = opts.ft_filter or util.yes
local all_fts = {}
vim.list_extend(all_fts, util.get_snippet_filetypes())
vim.list_extend(
all_fts,
loader_util.get_load_fts(vim.api.nvim_get_current_buf())
)
all_fts = util.deduplicate(all_fts)
local filtered_fts = {}
for _, ft in ipairs(all_fts) do
if ft_filter(ft) then
table.insert(filtered_fts, ft)
end
end
if #filtered_fts == 1 then
ft_edit_picker(filtered_fts[1])
elseif #filtered_fts > 1 then
vim.ui.select(filtered_fts, {
prompt = "Select filetype:",
}, ft_edit_picker)
end
end
function M.cleanup()
require("luasnip.loaders.from_lua").clean()
require("luasnip.loaders.from_snipmate").clean()
require("luasnip.loaders.from_vscode").clean()
end
function M.load_lazy_loaded(bufnr)
local fts = loader_util.get_load_fts(bufnr)
for _, ft in ipairs(fts) do
if not session.loaded_fts[ft] then
require("luasnip.loaders.from_lua")._load_lazy_loaded_ft(ft)
require("luasnip.loaders.from_snipmate")._load_lazy_loaded_ft(ft)
require("luasnip.loaders.from_vscode")._load_lazy_loaded_ft(ft)
end
session.loaded_fts[ft] = true
end
end
function M.reload_file(path)
local realpath = Path.normalize(path)
if not realpath then
return nil, ("Could not reload file %s: does not exist."):format(path)
else
fs_watchers.write_notify(realpath)
return true
end
end
return M
|