From c8568cfa0b35d2a401a32d129940b93920c01164 Mon Sep 17 00:00:00 2001 From: Ro <29069815+rokbot@users.noreply.github.com> Date: Tue, 7 Jul 2026 19:26:33 -0400 Subject: [PATCH] feat: Add icons by pattern and better env support - This allows to use icons by lua patterns - Improve icons for env specific files .env.example, .env.local etc. Useful links: https://www.lua.org/pil/20.2.html https://www.lua.org/manual/5.1/manual.html#5.4.1 https://gitspartv.github.io/lua-patterns/ --- CONTRIBUTING.md | 10 +-- README.md | 9 +++ lua/nvim-web-devicons.lua | 61 +++++++++++++++++-- .../default/icons_by_pattern.lua | 3 + lua/nvim-web-devicons/hi-test.lua | 3 + lua/nvim-web-devicons/icons-default.lua | 1 + lua/nvim-web-devicons/icons-light.lua | 1 + .../light/icons_by_pattern.lua | 3 + scripts/generate.lua | 1 + 9 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 lua/nvim-web-devicons/default/icons_by_pattern.lua create mode 100644 lua/nvim-web-devicons/light/icons_by_pattern.lua diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f585dc95..c17f89a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,13 +70,15 @@ Icons must be added to `/default/` files only. The `/light/` files are automatic 1. `icons_by_filename.lua` 2. `icons_by_file_extension.lua` -3. `icons_by_operating_system.lua` -4. `icons_by_desktop_environment.lua` -5. `icons_by_window_manager.lua` +3. `icons_by_pattern.lua` +4. `icons_by_operating_system.lua` +5. `icons_by_desktop_environment.lua` +6. `icons_by_window_manager.lua` Add the icon to table in file **1.** if the icon is for a file that is always named that way, for example `.gitconfig`. Add the icon to table in file **2.** if the icon is for all files with an extension, for example `vim`. -Add the icon to table in files **3.**, **4.** and **5.** if the icon is from an OS, DE or WM. +Add the icon to table in file **3.** if the icon is for all files with an pattern, for example `^%.env%.[%l]+[.]?[%l]+$`. +Add the icon to table in files **4.**, **5.** and **6.** if the icon is from an OS, DE or WM. Each icon must have the following structure (this is an example): diff --git a/README.md b/README.md index 6773db80..88265195 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,15 @@ require'nvim-web-devicons'.setup { name = "Log" } }; + -- same as `override` but specifically for overrides by pattern + -- takes effect when `strict` is true + override_by_pattern = { + ["^%.env%.[%l]+[.]?[%l]+$"] = { + icon = "", + color = "#f85e43", + name = "SpecificEnvs" -- env.example, env.local + } + }; -- same as `override` but specifically for operating system -- takes effect when `strict` is true override_by_operating_system = { diff --git a/lua/nvim-web-devicons.lua b/lua/nvim-web-devicons.lua index c30b6396..fee9ac88 100644 --- a/lua/nvim-web-devicons.lua +++ b/lua/nvim-web-devicons.lua @@ -9,9 +9,9 @@ local M = {} ---@field name iconName -- NOTE: When adding new icons, remember to add an entry to the `filetypes` table, if applicable. -local icons, icons_by_filename, icons_by_file_extension, icons_by_operating_system +local icons, icons_by_filename, icons_by_file_extension, icons_by_pattern, icons_by_operating_system local icons_by_desktop_environment, icons_by_window_manager -local user_icons +local user_icons, user_patterns_sorted, icons_by_pattern_default local filetypes = require "nvim-web-devicons.filetypes" @@ -35,6 +35,10 @@ function M.get_icons_by_extension() return icons_by_file_extension end +function M.get_icons_by_pattern() + return icons_by_pattern +end + function M.get_icons_by_operating_system() return icons_by_operating_system end @@ -94,6 +98,8 @@ local function refresh_icons() icons_by_filename = theme.icons_by_filename icons_by_file_extension = theme.icons_by_file_extension + icons_by_pattern = theme.icons_by_pattern + icons_by_pattern_default = theme.icons_by_pattern icons_by_operating_system = theme.icons_by_operating_system icons_by_desktop_environment = theme.icons_by_desktop_environment icons_by_window_manager = theme.icons_by_window_manager @@ -106,6 +112,7 @@ local function refresh_icons() {}, icons_by_filename, icons_by_file_extension, + icons_by_pattern, icons_by_operating_system, icons_by_desktop_environment, icons_by_window_manager @@ -206,6 +213,15 @@ local function get_highlight_ctermfg(icon_data) end end +---Count regex metas and other non literal characters, return number of literal chars to +---determine pattern specificity as higher chars = more specific +---@param pattern string +---@return integer +local function count_literal_chars(pattern) + local _, count = pattern:gsub("[a-zA-Z0-9_]", "") + return count +end + local function apply_user_icons() if type(user_icons) ~= "table" then return @@ -217,6 +233,7 @@ local function apply_user_icons() local user_filename_icons = user_icons.override_by_filename local user_file_ext_icons = user_icons.override_by_extension + local user_pattern_icons = user_icons.override_by_pattern local user_operating_system_icons = user_icons.override_by_operating_system local user_desktop_environment_icons = user_icons.override_by_desktop_environment local user_window_manager_icons = user_icons.override_by_window_manager @@ -232,6 +249,7 @@ local function apply_user_icons() user_icons.override or {}, user_filename_icons or {}, user_file_ext_icons or {}, + user_pattern_icons or {}, user_operating_system_icons or {}, user_desktop_environment_icons or {}, user_window_manager_icons or {} @@ -242,6 +260,7 @@ local function apply_user_icons() user_icons.override or {}, user_filename_icons or {}, user_file_ext_icons or {}, + user_pattern_icons or {}, user_operating_system_icons or {}, user_desktop_environment_icons or {}, user_window_manager_icons or {} @@ -253,6 +272,14 @@ local function apply_user_icons() if user_file_ext_icons then icons_by_file_extension = vim.tbl_extend("force", icons_by_file_extension, user_file_ext_icons) end + if user_pattern_icons then + icons_by_pattern = vim.tbl_extend("force", icons_by_pattern, user_pattern_icons) + user_patterns_sorted = {} + for pattern, icon_data in pairs(user_pattern_icons) do + user_patterns_sorted[#user_patterns_sorted + 1] = { pattern, icon_data } + end + table.sort(user_patterns_sorted, function(a, b) return count_literal_chars(a[1]) > count_literal_chars(b[1]) end) + end if user_operating_system_icons then icons_by_operating_system = vim.tbl_extend("force", icons_by_operating_system, user_operating_system_icons) end @@ -320,6 +347,7 @@ function M.setup(opts) global_opts.override, icons_by_filename, icons_by_file_extension, + icons_by_pattern_default or icons_by_pattern, icons_by_operating_system, icons_by_desktop_environment, icons_by_window_manager @@ -359,6 +387,23 @@ local function get_icon_by_extension(name, ext, opts) return iterate_multi_dotted_extension(name, icon_table) end +local function get_icon_by_pattern(name) + if name then + if user_patterns_sorted then + for _, entry in ipairs(user_patterns_sorted) do + if name:match(entry[1]) then + return entry[2] + end + end + end + for pattern, icon_data in pairs(icons_by_pattern) do + if name:match(pattern) then + return icon_data + end + end + end +end + local function get_icon_data(name, ext, opts) if type(name) == "string" then name = name:lower() @@ -372,9 +417,17 @@ local function get_icon_data(name, ext, opts) local is_strict = if_nil(opts and opts.strict, global_opts.strict) local icon_data if is_strict then - icon_data = icons_by_filename[name] or get_icon_by_extension(name, ext, opts) or (has_default and default_icon) + icon_data = icons_by_filename[name] or get_icon_by_extension(name, ext, opts) else - icon_data = icons[name] or get_icon_by_extension(name, ext, opts) or (has_default and default_icon) + icon_data = icons[name] or get_icon_by_extension(name, ext, opts) + end + + if not icon_data then + icon_data = get_icon_by_pattern(name) + end + + if not icon_data and has_default then + icon_data = default_icon end return icon_data diff --git a/lua/nvim-web-devicons/default/icons_by_pattern.lua b/lua/nvim-web-devicons/default/icons_by_pattern.lua new file mode 100644 index 00000000..338ec8a1 --- /dev/null +++ b/lua/nvim-web-devicons/default/icons_by_pattern.lua @@ -0,0 +1,3 @@ +return { + ["^%.env%.[%l]+[.]?[%l]+$"] = { icon = "", color = "#FAF743", cterm_color = "227", name = "Env"}, +} --[[@as table]] diff --git a/lua/nvim-web-devicons/hi-test.lua b/lua/nvim-web-devicons/hi-test.lua index c4c8b672..d5a22f45 100644 --- a/lua/nvim-web-devicons/hi-test.lua +++ b/lua/nvim-web-devicons/hi-test.lua @@ -110,6 +110,7 @@ end ---@param global_override table[] all global overrides "Overrides" ---@param icons_by_filename table[] filename "By File Name" ---@param icons_by_file_extension table[] extension "By File Extension" +---@param icons_by_pattern table[] extension "By Pattern" ---@param icons_by_operating_system table[] os "By Operating System" ---@param icons_by_desktop_environment table[] os "By Desktop Environment" ---@param icons_by_window_manager table[] os "By Window Manager" @@ -118,6 +119,7 @@ return function( global_override, icons_by_filename, icons_by_file_extension, + icons_by_pattern, icons_by_operating_system, icons_by_desktop_environment, icons_by_window_manager @@ -133,6 +135,7 @@ return function( end l = render_icons(bufnr, l, icons_by_filename, "By File Name") l = render_icons(bufnr, l, icons_by_file_extension, "By File Extension") + l = render_icons(bufnr, l, icons_by_pattern, "By Pattern") l = render_icons(bufnr, l, icons_by_operating_system, "By Operating System") l = render_icons(bufnr, l, icons_by_desktop_environment, "By Desktop Environment") render_icons(bufnr, l, icons_by_window_manager, "By Window Manager") diff --git a/lua/nvim-web-devicons/icons-default.lua b/lua/nvim-web-devicons/icons-default.lua index 5cd10f45..a7b93c98 100644 --- a/lua/nvim-web-devicons/icons-default.lua +++ b/lua/nvim-web-devicons/icons-default.lua @@ -1,6 +1,7 @@ return { icons_by_filename = require "nvim-web-devicons.default.icons_by_filename", icons_by_file_extension = require "nvim-web-devicons.default.icons_by_file_extension", + icons_by_pattern = require "nvim-web-devicons.default.icons_by_pattern", icons_by_operating_system = require "nvim-web-devicons.default.icons_by_operating_system", icons_by_desktop_environment = require "nvim-web-devicons.default.icons_by_desktop_environment", icons_by_window_manager = require "nvim-web-devicons.default.icons_by_window_manager", diff --git a/lua/nvim-web-devicons/icons-light.lua b/lua/nvim-web-devicons/icons-light.lua index 18e62804..67e8222f 100644 --- a/lua/nvim-web-devicons/icons-light.lua +++ b/lua/nvim-web-devicons/icons-light.lua @@ -1,6 +1,7 @@ return { icons_by_filename = require "nvim-web-devicons.light.icons_by_filename", icons_by_file_extension = require "nvim-web-devicons.light.icons_by_file_extension", + icons_by_pattern = require "nvim-web-devicons.light.icons_by_pattern", icons_by_operating_system = require "nvim-web-devicons.light.icons_by_operating_system", icons_by_desktop_environment = require "nvim-web-devicons.light.icons_by_desktop_environment", icons_by_window_manager = require "nvim-web-devicons.light.icons_by_window_manager", diff --git a/lua/nvim-web-devicons/light/icons_by_pattern.lua b/lua/nvim-web-devicons/light/icons_by_pattern.lua new file mode 100644 index 00000000..a857c3ba --- /dev/null +++ b/lua/nvim-web-devicons/light/icons_by_pattern.lua @@ -0,0 +1,3 @@ +return { -- this file is generated from lua/nvim-web-devicons/default/icons_by_pattern.lua, please do not edit + ["^%.env%.[%l]+[.]?[%l]+$"] = { icon = "", color = "#32310D", cterm_color = "236", name = "Env"}, +} --[[@as table]] diff --git a/scripts/generate.lua b/scripts/generate.lua index 4af8606a..f5cf689e 100644 --- a/scripts/generate.lua +++ b/scripts/generate.lua @@ -21,6 +21,7 @@ _G.ICON_FILES = { "icons_by_file_extension.lua", "icons_by_filename.lua", "icons_by_operating_system.lua", + "icons_by_pattern.lua", "icons_by_window_manager.lua", }