mirror of
https://github.com/folke/snacks.nvim
synced 2025-12-23 08:47:57 +00:00
feat(picker.icons): make it easier to add custom icon sources
This commit is contained in:
parent
a4176301e3
commit
82e69661cd
3 changed files with 70 additions and 6 deletions
|
|
@ -535,9 +535,14 @@ M.highlights = {
|
|||
}
|
||||
|
||||
---@class snacks.picker.icons.Config: snacks.picker.Config
|
||||
---@field icon_sources? string[]
|
||||
---@field icon_sources? string[] list of sources to use
|
||||
--- Custom icon sources can be added here. The key is the source name,
|
||||
--- and the value is the file path or URL to load icons from.
|
||||
--- The file should be a JSON array of:
|
||||
--- `{[1]:string, [2]:string}|{icon:string, name:string, category:string}`
|
||||
--- The format is compatible with https://github.com/nvim-telescope/telescope-symbols.nvim
|
||||
---@field custom_sources? table<string,string> additional icon sources `table<source,file|url>`
|
||||
M.icons = {
|
||||
icon_sources = { "nerd_fonts", "emoji" },
|
||||
main = { current = true },
|
||||
finder = "icons",
|
||||
format = "icon",
|
||||
|
|
|
|||
|
|
@ -709,7 +709,8 @@ function M.icon(item, picker)
|
|||
---@cast item snacks.picker.Icon
|
||||
local ret = {} ---@type snacks.picker.Highlight[]
|
||||
|
||||
ret[#ret + 1] = { a(item.icon, 2), "SnacksPickerIcon" }
|
||||
local icon_width = vim.api.nvim_strwidth(item.icon)
|
||||
ret[#ret + 1] = { a(item.icon, icon_width > 3 and 15 or 3), "SnacksPickerIcon" }
|
||||
ret[#ret + 1] = { " " }
|
||||
ret[#ret + 1] = { a(item.source, 10), "SnacksPickerIconSource" }
|
||||
ret[#ret + 1] = { " " }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,13 @@
|
|||
local M = {}
|
||||
|
||||
---@class snacks.picker.icons.Source
|
||||
---@field url string
|
||||
---@field v? number
|
||||
---@field priority? number
|
||||
---@field build fun(data:table):snacks.picker.Icon[]
|
||||
|
||||
---@alias snacks.picker.icons.source.Item {[1]:string, [2]:string}|{icon:string, name:string, category:string}
|
||||
|
||||
local NERDFONTS_SETS = {
|
||||
cod = "Codicons",
|
||||
dev = "Devicons",
|
||||
|
|
@ -16,9 +24,32 @@ local NERDFONTS_SETS = {
|
|||
md = "Material Design Icons",
|
||||
}
|
||||
|
||||
---@type table<string, {url: string, v?:number, build: fun(data:table):snacks.picker.Icon[]}>
|
||||
---@param source string
|
||||
local function custom_source(source, url)
|
||||
---@type snacks.picker.icons.Source
|
||||
return {
|
||||
v = 3,
|
||||
url = url,
|
||||
build = function(data)
|
||||
---@cast data snacks.picker.icons.source.Item[]
|
||||
local ret = {} ---@type snacks.picker.Icon[]
|
||||
for _, info in ipairs(data) do
|
||||
table.insert(ret, {
|
||||
name = vim.trim(info.name or info[2] or ""),
|
||||
icon = vim.trim(info.icon or info[1] or ""),
|
||||
category = info.category,
|
||||
source = source,
|
||||
})
|
||||
end
|
||||
return ret
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
---@type table<string, snacks.picker.icons.Source>
|
||||
M.sources = {
|
||||
nerd_fonts = {
|
||||
priority = 10,
|
||||
url = "https://github.com/ryanoasis/nerd-fonts/raw/refs/heads/master/glyphnames.json",
|
||||
v = 4,
|
||||
build = function(data)
|
||||
|
|
@ -43,6 +74,7 @@ M.sources = {
|
|||
},
|
||||
emoji = {
|
||||
url = "https://raw.githubusercontent.com/muan/unicode-emoji-json/refs/heads/main/data-by-emoji.json",
|
||||
priority = 20,
|
||||
v = 4,
|
||||
build = function(data)
|
||||
---@cast data table<string, {name:string, slug:string, group:string}>
|
||||
|
|
@ -70,7 +102,21 @@ M.sources = {
|
|||
---@param source_name string
|
||||
local function load(source_name)
|
||||
local source = M.sources[source_name]
|
||||
local file = vim.fn.stdpath("cache") .. "/snacks/picker/icons/" .. source_name .. "-v" .. (source.v or 1) .. ".json"
|
||||
if not source then
|
||||
Snacks.notify.error("Unknown icon source: " .. source_name)
|
||||
return {}
|
||||
end
|
||||
|
||||
-- Load from local file if not a URL
|
||||
if not source.url:find("^https?://") then
|
||||
local fd = assert(io.open(source.url, "r"))
|
||||
local data = fd:read("*a")
|
||||
fd:close()
|
||||
return source.build(vim.json.decode(data))
|
||||
end
|
||||
|
||||
local parts = { source_name, "v" .. (source.v or 1), "-", vim.fn.sha256(source.url):sub(1, 8), ".json" }
|
||||
local file = vim.fn.stdpath("cache") .. "/snacks/picker/icons/" .. table.concat(parts, "")
|
||||
vim.fn.mkdir(vim.fn.fnamemodify(file, ":h"), "p")
|
||||
if vim.fn.filereadable(file) == 1 then
|
||||
local fd = assert(io.open(file, "r"))
|
||||
|
|
@ -100,7 +146,19 @@ end
|
|||
---@type snacks.picker.finder
|
||||
function M.icons(opts)
|
||||
local ret = {} ---@type snacks.picker.Icon[]
|
||||
for _, source in ipairs(opts.icon_sources or { "nerd_fonts", "emoji" }) do
|
||||
|
||||
for source, url in pairs(opts.custom_sources or {}) do
|
||||
M.sources[source] = custom_source(source, url)
|
||||
end
|
||||
|
||||
local sources = opts.icon_sources or vim.tbl_keys(M.sources)
|
||||
table.sort(sources, function(a, b)
|
||||
local sa = M.sources[a] and M.sources[a].priority or 0
|
||||
local sb = M.sources[b] and M.sources[b].priority or 0
|
||||
return sa > sb
|
||||
end)
|
||||
|
||||
for _, source in ipairs(sources) do
|
||||
vim.list_extend(ret, load(source))
|
||||
end
|
||||
for _, icon in ipairs(ret) do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue