From 7a655c9919a8f18247a59d6d0fe0bd897e069433 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 2 Mar 2026 19:40:26 -0500 Subject: [PATCH] feat(hl): highlight icons --- lua/nonicons/colors.lua | 71 +++++++++++++++++++++++++++++++++++++ lua/nonicons/health.lua | 2 +- lua/nonicons/hi-test.lua | 16 ++++++++- lua/nonicons/highlights.lua | 37 +++++++++++++++++++ lua/nonicons/init.lua | 7 +++- 5 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 lua/nonicons/colors.lua create mode 100644 lua/nonicons/highlights.lua diff --git a/lua/nonicons/colors.lua b/lua/nonicons/colors.lua new file mode 100644 index 0000000..8927e07 --- /dev/null +++ b/lua/nonicons/colors.lua @@ -0,0 +1,71 @@ +---@type table +local M = { + ['angular'] = { '#e23237', 161 }, + ['babel'] = { '#f9dc3e', 185 }, + ['book'] = { '#a8b1c7', 146 }, + ['c'] = { '#599eff', 111 }, + ['c-plusplus'] = { '#f34b7d', 204 }, + ['c-sharp'] = { '#68217a', 55 }, + ['code'] = { '#a9b7c6', 145 }, + ['css'] = { '#563d7c', 60 }, + ['dart'] = { '#00b4ab', 37 }, + ['database'] = { '#dad8d8', 188 }, + ['diff'] = { '#41535b', 59 }, + ['docker'] = { '#0db7ed', 39 }, + ['elixir'] = { '#a074c4', 140 }, + ['elm'] = { '#60b5cc', 74 }, + ['eslint'] = { '#4b32c3', 56 }, + ['file'] = { '#6d8086', 66 }, + ['file-binary'] = { '#9f0500', 124 }, + ['file-zip'] = { '#eca517', 214 }, + ['gear'] = { '#6d8086', 66 }, + ['git-branch'] = { '#f14e32', 196 }, + ['git-commit'] = { '#f14e32', 196 }, + ['globe'] = { '#519aba', 74 }, + ['go'] = { '#00add8', 38 }, + ['graphql'] = { '#e535ab', 199 }, + ['html'] = { '#e34c26', 166 }, + ['image'] = { '#a074c4', 140 }, + ['java'] = { '#cc3e44', 167 }, + ['javascript'] = { '#f1e05a', 185 }, + ['json'] = { '#fbc02d', 220 }, + ['key'] = { '#e6c419', 220 }, + ['kotlin'] = { '#7f52ff', 99 }, + ['law'] = { '#cbcb41', 185 }, + ['lock'] = { '#bbbbbb', 250 }, + ['log'] = { '#afb42b', 142 }, + ['logo-github'] = { '#f0eff1', 255 }, + ['lua'] = { '#51a0cf', 74 }, + ['markdown'] = { '#519aba', 74 }, + ['next'] = { '#a9b7c6', 145 }, + ['nginx'] = { '#009639', 28 }, + ['npm'] = { '#cb3837', 160 }, + ['package'] = { '#cb3837', 160 }, + ['perl'] = { '#39457e', 61 }, + ['php'] = { '#4f5d95', 61 }, + ['play'] = { '#e37933', 208 }, + ['prettier'] = { '#56b3b4', 73 }, + ['python'] = { '#3776ab', 68 }, + ['r'] = { '#276dc3', 68 }, + ['react'] = { '#61dafb', 75 }, + ['rss'] = { '#f26522', 208 }, + ['ruby'] = { '#cc342d', 160 }, + ['rust'] = { '#dea584', 180 }, + ['scala'] = { '#cc3e44', 167 }, + ['server'] = { '#6d8086', 66 }, + ['shield'] = { '#43853d', 35 }, + ['svelte'] = { '#ff3e00', 202 }, + ['swift'] = { '#f05138', 203 }, + ['terminal'] = { '#4d4d4d', 239 }, + ['terraform'] = { '#844fba', 135 }, + ['tmux'] = { '#1bb91f', 34 }, + ['toml'] = { '#9c4221', 130 }, + ['typescript'] = { '#3178c6', 68 }, + ['typography'] = { '#e34c26', 166 }, + ['vim'] = { '#019833', 28 }, + ['vue'] = { '#41b883', 35 }, + ['yaml'] = { '#cb171e', 160 }, + ['yarn'] = { '#2c8ebb', 68 }, +} + +return M diff --git a/lua/nonicons/health.lua b/lua/nonicons/health.lua index e78e2ae..275ba8c 100644 --- a/lua/nonicons/health.lua +++ b/lua/nonicons/health.lua @@ -7,7 +7,7 @@ function M.check() if ok and devicons then vim.health.ok('nvim-web-devicons available') else - vim.health.error('nvim-web-devicons not found') + vim.health.info('nvim-web-devicons not found (using built-in highlights)') end local result = vim.fn.system({ 'fc-list', ':family=nonicons' }) diff --git a/lua/nonicons/hi-test.lua b/lua/nonicons/hi-test.lua index 47de1f0..79041ef 100644 --- a/lua/nonicons/hi-test.lua +++ b/lua/nonicons/hi-test.lua @@ -52,6 +52,10 @@ return function() string.format(' %-4s %-28s %-7s %s', 'ICON', 'NAME', 'CODE', 'MAPPED FROM') lines[#lines + 1] = string.rep('-', 72) + local highlights = require('nonicons.highlights') + local icon_line_start = #lines + local icon_glyphs = {} ---@type string[] + for _, name in ipairs(icon_names) do local sources = {} ---@type string[] if ext_by_icon[name] then @@ -70,9 +74,11 @@ return function() end end + local glyph = char(name) local src_str = #sources > 0 and table.concat(sources, ', ') or '' lines[#lines + 1] = - string.format(' %s %-28s U+%04X %s', char(name), name, mapping[name], src_str) + string.format(' %s %-28s U+%04X %s', glyph, name, mapping[name], src_str) + icon_glyphs[#icon_glyphs + 1] = glyph end lines[#lines + 1] = '' @@ -80,6 +86,14 @@ return function() local buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) + + for i, name in ipairs(icon_names) do + local hl = highlights.get(name) + local col_start = 2 + local col_end = col_start + #icon_glyphs[i] + vim.api.nvim_buf_add_highlight(buf, -1, hl, icon_line_start + i - 1, col_start, col_end) + end + vim.bo[buf].modifiable = false vim.bo[buf].buftype = 'nofile' vim.bo[buf].bufhidden = 'wipe' diff --git a/lua/nonicons/highlights.lua b/lua/nonicons/highlights.lua new file mode 100644 index 0000000..fbf42e2 --- /dev/null +++ b/lua/nonicons/highlights.lua @@ -0,0 +1,37 @@ +local colors = require('nonicons.colors') + +local M = {} + +---@param icon_name string +---@return string +local function to_hl_group(icon_name) + local parts = {} + for part in icon_name:gmatch('[^-]+') do + parts[#parts + 1] = part:sub(1, 1):upper() .. part:sub(2) + end + return 'Nonicons' .. table.concat(parts) +end + +local function apply() + for name, data in pairs(colors) do + vim.api.nvim_set_hl(0, to_hl_group(name), { fg = data[1], ctermfg = data[2] }) + end +end + +function M.setup() + apply() + + local group = vim.api.nvim_create_augroup('NoniconsHighlights', { clear = true }) + vim.api.nvim_create_autocmd('ColorScheme', { + group = group, + callback = apply, + }) +end + +---@param icon_name string +---@return string hl_group +function M.get(icon_name) + return to_hl_group(icon_name) +end + +return M diff --git a/lua/nonicons/init.lua b/lua/nonicons/init.lua index e80afae..526bf18 100644 --- a/lua/nonicons/init.lua +++ b/lua/nonicons/init.lua @@ -29,15 +29,18 @@ M.mapping = require('nonicons.mapping') ---@param name string Icon name ---@return string? glyph +---@return string? hl_group function M.get(name) local code = M.mapping[name] if code then - return vim.fn.nr2char(code) + local hl = require('nonicons.highlights').get(name) + return vim.fn.nr2char(code), hl end end function M.apply() ensure_initialized() + require('nonicons.highlights').setup() if config.override then require('nonicons.override').apply() end @@ -46,6 +49,7 @@ end ---@param name string? Filename (e.g. `'init.lua'`) ---@param ext string? File extension (e.g. `'lua'`) ---@return string? glyph +---@return string? hl_group function M.get_icon(name, ext) local key = require('nonicons.resolve').resolve_name(name, ext) if key then @@ -55,6 +59,7 @@ end ---@param ft string Vim filetype ---@return string? glyph +---@return string? hl_group function M.get_icon_by_filetype(ft) local key = require('nonicons.resolve').resolve_filetype(ft) if key then