diff --git a/.github/workflows/quality.yaml b/.github/workflows/quality.yaml index 77049fd..4a4795a 100644 --- a/.github/workflows/quality.yaml +++ b/.github/workflows/quality.yaml @@ -25,6 +25,7 @@ jobs: - '*.lua' - '.luarc.json' - '*.toml' + - 'vim.yaml' markdown: - '*.md' @@ -35,11 +36,8 @@ jobs: if: ${{ needs.changes.outputs.lua == 'true' }} steps: - uses: actions/checkout@v4 - - uses: JohnnyMorganz/stylua-action@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: 2.1.0 - args: --check . + - uses: cachix/install-nix-action@v31 + - run: nix develop --command stylua --check . lua-lint: name: Lua Lint Check @@ -48,11 +46,8 @@ jobs: if: ${{ needs.changes.outputs.lua == 'true' }} steps: - uses: actions/checkout@v4 - - name: Lint with Selene - uses: NTBBloodbath/selene-action@v1.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --display-style quiet . + - uses: cachix/install-nix-action@v31 + - run: nix develop --command selene --display-style quiet . lua-typecheck: name: Lua Type Check @@ -75,15 +70,28 @@ jobs: if: ${{ needs.changes.outputs.markdown == 'true' }} steps: - uses: actions/checkout@v4 - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 8 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - - name: Install prettier - run: pnpm add -g prettier@3.1.0 - - name: Check markdown formatting with prettier - run: prettier --check . + - uses: cachix/install-nix-action@v31 + - run: nix develop --command prettier --check . + + mapping-sync: + name: Mapping Sync Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check mapping against upstream + run: | + curl -sL https://raw.githubusercontent.com/ya2s/nonicons/main/src/template/nonicon.json \ + | jq -r 'to_entries[] | "\(.key | sub("-16$"; "")) \(.value)"' \ + | sort > /tmp/upstream.txt + + grep -oP "^\s*\['\K[^']+(?='\]\s*=\s*\d)" lua/nonicons/mapping.lua \ + | while read -r key; do + val=$(grep -oP "^\s*\['${key}'\]\s*=\s*\K\d+" lua/nonicons/mapping.lua) + echo "$key $val" + done | sort > /tmp/local.txt + + if ! diff -u /tmp/local.txt /tmp/upstream.txt; then + echo '' + echo '::warning::mapping.lua is out of sync with ya2s/nonicons upstream' + exit 1 + fi diff --git a/.github/workflows/sync.yaml b/.github/workflows/sync.yaml new file mode 100644 index 0000000..08758bc --- /dev/null +++ b/.github/workflows/sync.yaml @@ -0,0 +1,72 @@ +name: sync + +on: + schedule: + - cron: '0 8 * * *' + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + sync-mapping: + name: Sync Upstream Mapping + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Generate mapping from upstream + run: | + curl -sL https://raw.githubusercontent.com/ya2s/nonicons/main/src/template/nonicon.json \ + | jq -r 'to_entries | sort_by(.key) | .[] | "\(.key | sub("-16$"; "")) \(.value)"' \ + > /tmp/upstream.txt + + { + echo '---@type table' + echo 'local M = {' + while IFS=' ' read -r name code; do + printf " ['%s'] = %s,\n" "$name" "$code" + done < /tmp/upstream.txt + echo '}' + echo 'return M' + } > lua/nonicons/mapping.lua + + - name: Generate colors from nvim-web-devicons + run: | + sudo apt-get install -y -qq lua5.4 > /dev/null + + curl -sL https://raw.githubusercontent.com/nvim-tree/nvim-web-devicons/master/lua/nvim-web-devicons/default/icons_by_file_extension.lua \ + -o /tmp/devicons_ext.lua + curl -sL https://raw.githubusercontent.com/nvim-tree/nvim-web-devicons/master/lua/nvim-web-devicons/default/icons_by_filename.lua \ + -o /tmp/devicons_fname.lua + + lua5.4 scripts/gen-colors.lua > lua/nonicons/colors.lua + + - name: Check for changes + id: diff + run: | + if git diff --quiet lua/nonicons/mapping.lua lua/nonicons/colors.lua; then + echo "changed=false" >> "$GITHUB_OUTPUT" + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + - name: Create pull request + if: steps.diff.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v7 + with: + branch: sync/upstream + title: 'fix: sync with upstream nonicons font and devicons colors' + body: | + ## Problem + + `mapping.lua` or `colors.lua` is out of sync with upstream sources. + + ## Solution + + Auto-generated from upstream [ya2s/nonicons](https://github.com/ya2s/nonicons) `nonicon.json` + and [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) color definitions. + commit-message: 'fix: sync with upstream nonicons font and devicons colors' + labels: upstream-sync + delete-branch: true diff --git a/.gitignore b/.gitignore index eabe60d..93ac2c5 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ node_modules/ result result-* .direnv/ +.envrc diff --git a/.luarc.json b/.luarc.json index b438cce..23646d3 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,5 +1,5 @@ { - "runtime.version": "Lua 5.1", + "runtime.version": "LuaJIT", "runtime.path": ["lua/?.lua", "lua/?/init.lua"], "diagnostics.globals": ["vim", "jit"], "workspace.library": ["$VIMRUNTIME/lua", "${3rd}/luv/library"], diff --git a/README.md b/README.md index 5362ff8..c604091 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ ## Requirements -- [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) - [nonicons font](https://github.com/ya2s/nonicons/releases) installed +- (Optionally) [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) ## Installation @@ -32,7 +32,7 @@ luarocks install nonicons.nvim ## FAQ -**How do I integrate with plugin \?** +**Q: How do I integrate with plugin `X`?** See `:help nonicons-recipes`. diff --git a/doc/nonicons.nvim.txt b/doc/nonicons.nvim.txt index b10b13d..8b43865 100644 --- a/doc/nonicons.nvim.txt +++ b/doc/nonicons.nvim.txt @@ -19,14 +19,15 @@ REQUIREMENTS *nonicons-requirements* ============================================================================== SETUP *nonicons-setup* -Using lazy.nvim: >lua +Load nvim-web-devicons before nonicons.nvim. For example, with lazy.nvim: >lua { 'barrettruth/nonicons.nvim', dependencies = { 'nvim-tree/nvim-web-devicons' }, + lazy = false, } < -The plugin applies overrides automatically via `plugin/nonicons.lua`. No -`setup()` call is needed. +The plugin works automatically with no configuration required. For +customization, see |nonicons-config|. ============================================================================== CONFIGURATION *nonicons-config* @@ -52,6 +53,33 @@ API *nonicons-api* Parameters: ~ {name} `string` Icon name (e.g. `'lua'`, `'python'`, `'git-branch'`) + Returns: ~ + `string?` The single-character nonicons glyph + + *nonicons.get_icon()* +`require('nonicons').get_icon(name, ext)` + Returns the nonicons character for a file, resolved by filename and/or + extension. Returns `nil` if no match is found (caller decides fallback). + + Resolution order: exact extension → exact filename → extracted extension. + + Parameters: ~ + {name} `string?` Filename (e.g. `'init.lua'`, `'Makefile'`) + {ext} `string?` File extension (e.g. `'lua'`, `'py'`) + + Returns: ~ + `string?` The single-character nonicons glyph + + *nonicons.get_icon_by_filetype()* +`require('nonicons').get_icon_by_filetype(ft)` + Returns the nonicons character for a vim filetype. Returns `nil` if no + match is found. + + Resolution order: direct mapping key → extension table → filetype table. + + Parameters: ~ + {ft} `string` Vim filetype (e.g. `'python'`, `'typescriptreact'`) + Returns: ~ `string?` The single-character nonicons glyph @@ -66,6 +94,10 @@ API *nonicons-api* ============================================================================== RECIPES *nonicons-recipes* +Plugins that call nvim-web-devicons functions (oil.nvim, telescope.nvim, +fzf-lua, etc.) pick up nonicons glyphs automatically. The recipes below are +for plugins that accept icon configuration directly. + lualine ~ >lua local get = require('nonicons').get @@ -123,17 +155,29 @@ mason.nvim ~ oil.nvim ~ - No configuration needed. oil.nvim reads the devicons extension/filename - tables directly, which nonicons.nvim mutates on load. + No configuration needed. oil.nvim detects nonicons.nvim and uses it as a + direct icon provider. If devicons is also loaded, the devicons override + still applies to other plugins. fzf-lua ~ - - No configuration needed. fzf-lua calls `get_icon()` from devicons, which - nonicons.nvim wraps automatically. +>lua + require('fzf-lua').setup({ + file_icon_padding = ' ', + }) +< telescope.nvim ~ +>lua + local get = require('nonicons').get - No configuration needed. telescope.nvim calls `get_icon()` from devicons. + require('telescope').setup({ + defaults = { + prompt_prefix = ' ' .. get('telescope') .. ' ', + selection_caret = ' > ', + entry_prefix = ' ', + }, + }) +< nvim-tree ~ >lua @@ -168,8 +212,7 @@ Download the font from: https://github.com/ya2s/nonicons/releases ghostty ~ > - font-family = Nonicons - font-family = YourMainFont + font_codepoint_map = "U+f101-U+f25c=nonicons" < kitty ~ @@ -189,6 +232,16 @@ iTerm2 ~ Preferences > Profiles > Text > Non-ASCII Font > select Nonicons +============================================================================== +COMMANDS *nonicons-commands* + + *:NoniconsHiTest* +`:NoniconsHiTest` + Open a scratch buffer listing every icon in the nonicons font alongside + its name, Unicode codepoint, and which extensions / filenames / filetypes + map to it. Use this to visually verify that glyphs render correctly and + that resolution tables point to the intended icons. + ============================================================================== HEALTH CHECK *nonicons-health* diff --git a/flake.nix b/flake.nix index 5d6a2f4..c375a80 100644 --- a/flake.nix +++ b/flake.nix @@ -22,6 +22,7 @@ pkgs.prettier pkgs.stylua pkgs.selene + pkgs.lua-language-server ]; }; }); diff --git a/lua/nonicons/colors.lua b/lua/nonicons/colors.lua new file mode 100644 index 0000000..7092f12 --- /dev/null +++ b/lua/nonicons/colors.lua @@ -0,0 +1,69 @@ +---@type table +local M = { + ['babel'] = { '#CBCB41', 185 }, + ['book'] = { '#3D6117', 22 }, + ['c'] = { '#A074C4', 140 }, + ['c-plusplus'] = { '#A074C4', 140 }, + ['c-sharp'] = { '#596706', 58 }, + ['code'] = { '#3882D2', 32 }, + ['css'] = { '#563D7C', 54 }, + ['dart'] = { '#03589C', 25 }, + ['database'] = { '#DAD8D8', 188 }, + ['diff'] = { '#41535B', 239 }, + ['docker'] = { '#458EE6', 68 }, + ['elixir'] = { '#A074C4', 140 }, + ['elm'] = { '#519ABA', 74 }, + ['eslint'] = { '#4B32C3', 56 }, + ['file'] = { '#89E051', 113 }, + ['file-binary'] = { '#4D2C0B', 52 }, + ['file-zip'] = { '#ECA517', 214 }, + ['gear'] = { '#6D8086', 66 }, + ['git-branch'] = { '#F14C28', 196 }, + ['git-commit'] = { '#F54D27', 196 }, + ['globe'] = { '#5D7096', 60 }, + ['go'] = { '#00ADD8', 38 }, + ['graphql'] = { '#E535AB', 199 }, + ['html'] = { '#E34C26', 196 }, + ['image'] = { '#A074C4', 140 }, + ['java'] = { '#ffaf67', 215 }, + ['javascript'] = { '#CBCB41', 185 }, + ['json'] = { '#CBCB41', 185 }, + ['key'] = { '#FAF743', 227 }, + ['kotlin'] = { '#7F52FF', 99 }, + ['law'] = { '#CBCB41', 185 }, + ['lock'] = { '#BBBBBB', 250 }, + ['log'] = { '#DDDDDD', 253 }, + ['logo-github'] = { '#E24329', 196 }, + ['lua'] = { '#00A2FF', 75 }, + ['markdown'] = { '#519ABA', 74 }, + ['next'] = { '#FFFFFF', 231 }, + ['npm'] = { '#E8274B', 197 }, + ['package'] = { '#EADCD1', 253 }, + ['perl'] = { '#519ABA', 74 }, + ['php'] = { '#F05340', 203 }, + ['play'] = { '#0075AA', 24 }, + ['prettier'] = { '#4285F4', 33 }, + ['python'] = { '#5AA7E4', 39 }, + ['r'] = { '#519ABA', 74 }, + ['react'] = { '#1354BF', 26 }, + ['rss'] = { '#FB9D3B', 215 }, + ['ruby'] = { '#701516', 52 }, + ['rust'] = { '#DEA584', 216 }, + ['scala'] = { '#CC3E44', 167 }, + ['server'] = { '#A074C4', 140 }, + ['shield'] = { '#BEC4C9', 251 }, + ['svelte'] = { '#FF3E00', 196 }, + ['swift'] = { '#E37933', 166 }, + ['terminal'] = { '#4273CA', 68 }, + ['terraform'] = { '#5F43E9', 93 }, + ['tmux'] = { '#14BA19', 34 }, + ['toml'] = { '#9C4221', 124 }, + ['typescript'] = { '#519ABA', 74 }, + ['typography'] = { '#ECECEC', 255 }, + ['vim'] = { '#019833', 28 }, + ['vue'] = { '#8DC149', 113 }, + ['yaml'] = { '#6D8086', 66 }, + ['yarn'] = { '#F9AD02', 214 }, +} + +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 new file mode 100644 index 0000000..8df09cd --- /dev/null +++ b/lua/nonicons/hi-test.lua @@ -0,0 +1,104 @@ +local mapping = require('nonicons.mapping') +local resolve = require('nonicons.resolve') + +---@param name string +---@return string +local function char(name) + local code = mapping[name] + if code then + return vim.fn.nr2char(code) + end + return '?' +end + +---@param t table +---@return string[] +local function sorted_keys(t) + local keys = {} + for k in pairs(t) do + keys[#keys + 1] = k + end + table.sort(keys) + return keys +end + +---@param t table +---@return table +local function invert(t) + local inv = {} + for k, v in pairs(t) do + inv[v] = inv[v] or {} + inv[v][#inv[v] + 1] = k + end + for _, list in pairs(inv) do + table.sort(list) + end + return inv +end + +return function() + local lines = {} ---@type string[] + + local ext_by_icon = invert(resolve.ext_map) + local fname_by_icon = invert(resolve.filename_map) + local ft_by_icon = invert(resolve.ft_map) + + local icon_names = sorted_keys(mapping) + + lines[#lines + 1] = 'nonicons.nvim — icon reference' + lines[#lines + 1] = string.rep('=', 72) + lines[#lines + 1] = '' + lines[#lines + 1] = + 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 + for _, ext in ipairs(ext_by_icon[name]) do + sources[#sources + 1] = 'ext:' .. ext + end + end + if fname_by_icon[name] then + for _, fname in ipairs(fname_by_icon[name]) do + sources[#sources + 1] = 'file:' .. fname + end + end + if ft_by_icon[name] then + for _, ft in ipairs(ft_by_icon[name]) do + sources[#sources + 1] = 'ft:' .. ft + 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', glyph, name, mapping[name], src_str) + icon_glyphs[#icon_glyphs + 1] = glyph + end + + lines[#lines + 1] = '' + lines[#lines + 1] = string.format('%d icons total', #icon_names) + + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) + + local ns = vim.api.nvim_create_namespace('nonicons_hitest') + for i, name in ipairs(icon_names) do + local col_start = 2 + local col_end = col_start + #icon_glyphs[i] + vim.api.nvim_buf_set_extmark(buf, ns, icon_line_start + i - 1, col_start, { + end_col = col_end, + hl_group = highlights.get(name), + }) + end + + vim.bo[buf].modifiable = false + vim.bo[buf].buftype = 'nofile' + vim.bo[buf].bufhidden = 'wipe' + vim.api.nvim_set_current_buf(buf) +end diff --git a/lua/nonicons/highlights.lua b/lua/nonicons/highlights.lua new file mode 100644 index 0000000..0398c49 --- /dev/null +++ b/lua/nonicons/highlights.lua @@ -0,0 +1,39 @@ +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) + if colors[icon_name] then + return to_hl_group(icon_name) + end +end + +return M diff --git a/lua/nonicons/init.lua b/lua/nonicons/init.lua index dbdb186..526bf18 100644 --- a/lua/nonicons/init.lua +++ b/lua/nonicons/init.lua @@ -24,20 +24,47 @@ local function ensure_initialized() initialized = true end +---@type table 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 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 + return M.get(key) + end +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 + return M.get(key) + end +end + return M diff --git a/lua/nonicons/mapping.lua b/lua/nonicons/mapping.lua index 6e74952..dd22fd3 100644 --- a/lua/nonicons/mapping.lua +++ b/lua/nonicons/mapping.lua @@ -1,22 +1,40 @@ ---@type table local M = { + ['accessibility'] = 61995, + ['accessibility-inset'] = 62026, + ['agent'] = 62080, + ['ai-model'] = 62081, ['alert'] = 61697, + ['alert-fill'] = 62027, ['angular'] = 61698, + ['apps'] = 61996, ['archive'] = 61699, ['arrow-both'] = 61700, ['arrow-down'] = 61701, + ['arrow-down-left'] = 62028, + ['arrow-down-right'] = 62029, ['arrow-left'] = 61702, ['arrow-right'] = 61703, ['arrow-switch'] = 61704, ['arrow-up'] = 61705, + ['arrow-up-left'] = 62030, + ['arrow-up-right'] = 62031, + ['babel'] = 61989, ['backbone'] = 61706, ['beaker'] = 61707, ['bell'] = 61708, + ['bell-fill'] = 61997, ['bell-slash'] = 61709, + ['biome'] = 62078, + ['blocked'] = 61961, ['bold'] = 61710, ['book'] = 61711, ['bookmark'] = 61712, + ['bookmark-filled'] = 62082, ['bookmark-slash'] = 61713, + ['bookmark-slash-fill'] = 62083, + ['boolean-off'] = 62084, + ['boolean-on'] = 62085, ['briefcase'] = 61714, ['broadcast'] = 61715, ['browser'] = 61716, @@ -24,10 +42,14 @@ local M = { ['c'] = 61718, ['c-plusplus'] = 61719, ['c-sharp'] = 61720, + ['cache'] = 62032, ['calendar'] = 61721, + ['capacitor'] = 61993, ['check'] = 61722, ['check-circle'] = 61723, ['check-circle-fill'] = 61724, + ['checkbox'] = 62033, + ['checkbox-fill'] = 62086, ['checklist'] = 61725, ['chevron-down'] = 61726, ['chevron-left'] = 61727, @@ -35,118 +57,216 @@ local M = { ['chevron-up'] = 61729, ['circle'] = 61730, ['circle-slash'] = 61731, + ['class'] = 61952, ['clippy'] = 61732, ['clock'] = 61733, + ['clock-fill'] = 62034, + ['cloud'] = 61998, + ['cloud-offline'] = 61999, ['code'] = 61734, + ['code-of-conduct'] = 62000, ['code-review'] = 61735, ['code-square'] = 61736, + ['codescan'] = 61962, + ['codescan-checkmark'] = 61963, + ['codespaces'] = 61964, + ['columns'] = 61973, + ['command-palette'] = 62035, ['comment'] = 61737, + ['comment-ai'] = 62087, ['comment-discussion'] = 61738, + ['compose'] = 62088, + ['constant'] = 61953, ['container'] = 61739, + ['copilot'] = 62036, + ['copilot-error'] = 62037, + ['copilot-warning'] = 62038, + ['copy'] = 61984, ['cpu'] = 61740, ['credit-card'] = 61741, ['cross-reference'] = 61742, + ['crosshairs'] = 62089, ['css'] = 61743, ['dart'] = 61744, ['dash'] = 61745, ['database'] = 61746, + ['dependabot'] = 61965, ['desktop-download'] = 61747, ['device-camera'] = 61748, ['device-camera-video'] = 61749, ['device-desktop'] = 61750, ['device-mobile'] = 61751, + ['devices'] = 62051, + ['diamond'] = 61974, + ['dice'] = 62090, ['diff'] = 61752, ['diff-added'] = 61753, ['diff-ignored'] = 61754, ['diff-modified'] = 61755, ['diff-removed'] = 61756, ['diff-renamed'] = 61757, + ['discussion-closed'] = 62052, + ['discussion-duplicate'] = 62053, + ['discussion-outdated'] = 62054, ['docker'] = 61758, ['dot'] = 61759, ['dot-fill'] = 61760, ['download'] = 61761, + ['duplicate'] = 61966, + ['elixir'] = 61971, ['ellipsis'] = 61762, ['elm'] = 61763, + ['error'] = 62055, + ['eslint'] = 61981, + ['exclamation'] = 62091, ['eye'] = 61764, ['eye-closed'] = 61765, + ['feed-discussion'] = 62001, + ['feed-forked'] = 62002, + ['feed-heart'] = 62003, + ['feed-issue-closed'] = 62092, + ['feed-issue-draft'] = 62093, + ['feed-issue-open'] = 62094, + ['feed-issue-reopen'] = 62095, + ['feed-merged'] = 62004, + ['feed-person'] = 62005, + ['feed-plus'] = 62096, + ['feed-public'] = 62097, + ['feed-pull-request-closed'] = 62098, + ['feed-pull-request-draft'] = 62099, + ['feed-pull-request-open'] = 62100, + ['feed-repo'] = 62006, + ['feed-rocket'] = 62007, + ['feed-star'] = 62008, + ['feed-tag'] = 62009, + ['feed-trophy'] = 62010, + ['field'] = 61954, ['file'] = 61766, + ['file-added'] = 62039, ['file-badge'] = 61767, ['file-binary'] = 61768, + ['file-check'] = 62101, ['file-code'] = 61769, ['file-diff'] = 61770, ['file-directory'] = 61771, + ['file-directory-fill'] = 62011, + ['file-directory-open-fill'] = 62012, ['file-directory-outline'] = 61772, + ['file-directory-symlink'] = 62102, + ['file-media'] = 62103, + ['file-moved'] = 62040, + ['file-removed'] = 62041, ['file-submodule'] = 61773, ['file-symlink-file'] = 61774, ['file-zip'] = 61775, ['filter'] = 61776, + ['filter-remove'] = 62104, + ['fiscal-host'] = 62056, ['flame'] = 61777, + ['flowchart'] = 62105, + ['focus-center'] = 62106, ['fold'] = 61778, ['fold-down'] = 61779, ['fold-up'] = 61780, ['gear'] = 61781, ['gift'] = 61782, ['git-branch'] = 61783, + ['git-branch-check'] = 62107, ['git-commit'] = 61784, ['git-compare'] = 61785, ['git-merge'] = 61786, + ['git-merge-queue'] = 62042, ['git-pull-request'] = 61787, + ['git-pull-request-closed'] = 61975, + ['git-pull-request-draft'] = 61976, ['globe'] = 61788, ['go'] = 61789, + ['goal'] = 62057, ['grabber'] = 61790, ['graph'] = 61791, + ['graph-bar-horizontal'] = 62108, + ['graph-bar-vertical'] = 62109, + ['graphql'] = 61994, + ['hash'] = 61977, ['heading'] = 61792, ['heart'] = 61793, ['heart-fill'] = 61794, ['history'] = 61795, ['home'] = 61796, + ['home-fill'] = 62110, ['horizontal-rule'] = 61797, ['hourglass'] = 61798, ['html'] = 61799, ['hubot'] = 61800, + ['id-badge'] = 62013, ['image'] = 61801, ['inbox'] = 61802, + ['inbox-fill'] = 62111, ['infinity'] = 61803, ['info'] = 61804, + ['interface'] = 61955, + ['ionic'] = 61990, ['issue-closed'] = 61805, + ['issue-draft'] = 61978, ['issue-opened'] = 61806, ['issue-reopened'] = 61807, + ['issue-tracked-by'] = 62043, + ['issue-tracked-in'] = 62044, + ['issue-tracks'] = 62058, ['italic'] = 61808, + ['iterations'] = 62014, ['java'] = 61809, ['javascript'] = 61810, ['json'] = 61811, ['kebab-horizontal'] = 61812, ['key'] = 61813, + ['key-asterisk'] = 61985, + ['keyword'] = 61956, ['kotlin'] = 61814, ['kubernetes'] = 61815, ['law'] = 61816, + ['layout'] = 62059, ['light-bulb'] = 61817, ['link'] = 61818, ['link-external'] = 61819, ['list-ordered'] = 61820, ['list-unordered'] = 61821, + ['loading'] = 62060, ['location'] = 61822, ['lock'] = 61823, + ['log'] = 62015, ['logo-gist'] = 61824, ['logo-github'] = 61825, + ['loop'] = 62112, ['lua'] = 61826, ['mail'] = 61827, ['mark-github'] = 61828, ['markdown'] = 61829, + ['maximize'] = 62113, + ['mcp'] = 62114, ['megaphone'] = 61830, ['mention'] = 61831, ['meter'] = 61832, ['milestone'] = 61833, + ['minimize'] = 62115, ['mirror'] = 61834, ['moon'] = 61835, ['mortar-board'] = 61836, + ['move-to-bottom'] = 62061, + ['move-to-end'] = 62062, + ['move-to-start'] = 62063, + ['move-to-top'] = 62064, + ['multi-select'] = 61948, ['mute'] = 61837, + ['next'] = 61991, ['nginx'] = 61838, ['no-entry'] = 61839, ['node'] = 61840, ['north-star'] = 61841, + ['not-found'] = 62065, ['note'] = 61842, ['npm'] = 61843, + ['number'] = 61949, ['octoface'] = 61844, ['organization'] = 61845, ['package'] = 61846, @@ -154,34 +274,54 @@ local M = { ['package-dependents'] = 61848, ['paintbrush'] = 61849, ['paper-airplane'] = 61850, + ['paperclip'] = 62045, + ['passkey-fill'] = 62066, + ['paste'] = 61986, + ['pause'] = 62116, ['pencil'] = 61851, + ['pencil-ai'] = 62117, ['people'] = 61852, ['perl'] = 61853, ['person'] = 61854, + ['person-add'] = 61967, + ['person-fill'] = 62016, ['php'] = 61855, ['pin'] = 61856, + ['pin-slash'] = 62067, + ['pivot-column'] = 62118, ['play'] = 61857, ['plug'] = 61858, ['plus'] = 61859, ['plus-circle'] = 61860, + ['prettier'] = 61982, + ['prisma'] = 62046, ['project'] = 61861, + ['project-roadmap'] = 62047, + ['project-symlink'] = 62048, + ['project-template'] = 62068, ['pulse'] = 61862, ['python'] = 61863, ['question'] = 61864, ['quote'] = 61865, ['r'] = 61866, ['react'] = 61867, + ['read'] = 62069, ['rectangle'] = 61868, + ['redo'] = 62119, + ['rel-file-path'] = 62070, ['reply'] = 61869, ['repo'] = 61870, ['repo-clone'] = 61871, + ['repo-deleted'] = 62017, ['repo-forked'] = 61872, + ['repo-locked'] = 62018, ['repo-pull'] = 61873, ['repo-push'] = 61874, ['repo-template'] = 61875, ['report'] = 61876, ['require'] = 61877, ['rocket'] = 61878, + ['rows'] = 61979, ['rss'] = 61879, ['ruby'] = 61880, ['rust'] = 61881, @@ -189,52 +329,97 @@ local M = { ['screen-full'] = 61883, ['screen-normal'] = 61884, ['search'] = 61885, + ['select-single'] = 61980, ['server'] = 61886, ['share'] = 61887, ['share-android'] = 61888, ['shield'] = 61889, ['shield-check'] = 61890, ['shield-lock'] = 61891, + ['shield-slash'] = 62049, ['shield-x'] = 61892, + ['sidebar-collapse'] = 61968, + ['sidebar-expand'] = 61969, ['sign-in'] = 61893, ['sign-out'] = 61894, + ['single-select'] = 62019, ['skip'] = 61895, + ['skip-fill'] = 62050, + ['sliders'] = 62020, ['smiley'] = 61896, + ['smiley-frown'] = 62120, + ['smiley-frustrated'] = 62121, + ['smiley-grin'] = 62122, + ['smiley-neutral'] = 62123, + ['snippet'] = 61957, + ['sort-asc'] = 61987, + ['sort-desc'] = 61988, + ['space'] = 62124, + ['spacing-large'] = 62125, + ['spacing-medium'] = 62126, + ['spacing-small'] = 62127, + ['sparkle'] = 62128, + ['sparkle-fill'] = 62071, + ['sparkles-fill'] = 62129, + ['split-view'] = 62130, + ['sponsor-tiers'] = 62072, ['square'] = 61897, + ['square-circle'] = 62131, ['square-fill'] = 61898, ['squirrel'] = 61899, + ['stack'] = 62021, ['star'] = 61900, ['star-fill'] = 61901, ['stop'] = 61902, ['stopwatch'] = 61903, ['strikethrough'] = 61904, + ['struct'] = 61958, ['sun'] = 61905, + ['svelte'] = 61992, ['swift'] = 61906, ['sync'] = 61907, + ['tab'] = 62132, + ['tab-external'] = 62022, + ['table'] = 61970, ['tag'] = 61908, ['tasklist'] = 61909, ['telescope'] = 61910, + ['telescope-fill'] = 62023, + ['template'] = 62073, ['terminal'] = 61911, + ['terraform'] = 61972, ['three-bars'] = 61912, ['thumbsdown'] = 61913, ['thumbsup'] = 61914, ['tmux'] = 61915, ['toml'] = 61916, ['tools'] = 61917, + ['tracked-by-closed-completed'] = 62133, + ['tracked-by-closed-not-planned'] = 62134, + ['trash'] = 61950, ['trashcan'] = 61918, ['triangle-down'] = 61919, ['triangle-left'] = 61920, ['triangle-right'] = 61921, ['triangle-up'] = 61922, + ['trophy'] = 62024, + ['turborepo'] = 62079, + ['type'] = 61959, ['typescript'] = 61923, ['typography'] = 61924, + ['undo'] = 62135, ['unfold'] = 61925, + ['unlink'] = 62074, ['unlock'] = 61926, ['unmute'] = 61927, + ['unread'] = 62075, ['unverified'] = 61928, + ['unwrap'] = 62136, ['upload'] = 61929, + ['variable'] = 61960, ['verified'] = 61930, ['versions'] = 61931, + ['video'] = 61951, ['vim'] = 61932, ['vim-command-mode'] = 61933, ['vim-insert-mode'] = 61934, @@ -243,91 +428,18 @@ local M = { ['vim-select-mode'] = 61937, ['vim-terminal-mode'] = 61938, ['vim-visual-mode'] = 61939, + ['vscode'] = 61983, ['vue'] = 61940, + ['webhook'] = 62025, ['workflow'] = 61941, + ['wrap'] = 62137, ['x'] = 61942, ['x-circle'] = 61943, ['x-circle-fill'] = 61944, ['yaml'] = 61945, ['yarn'] = 61946, ['zap'] = 61947, - ['multi-select'] = 61948, - ['number'] = 61949, - ['trash'] = 61950, - ['video'] = 61951, - ['class'] = 61952, - ['constant'] = 61953, - ['field'] = 61954, - ['interface'] = 61955, - ['keyword'] = 61956, - ['snippet'] = 61957, - ['struct'] = 61958, - ['type'] = 61959, - ['variable'] = 61960, - ['blocked'] = 61961, - ['codescan'] = 61962, - ['codescan-checkmark'] = 61963, - ['codespaces'] = 61964, - ['dependabot'] = 61965, - ['duplicate'] = 61966, - ['person-add'] = 61967, - ['sidebar-collapse'] = 61968, - ['sidebar-expand'] = 61969, - ['table'] = 61970, - ['elixir'] = 61971, - ['terraform'] = 61972, - ['columns'] = 61973, - ['diamond'] = 61974, - ['git-pull-request-closed'] = 61975, - ['git-pull-request-draft'] = 61976, - ['hash'] = 61977, - ['issue-draft'] = 61978, - ['rows'] = 61979, - ['select-single'] = 61980, - ['eslint'] = 61981, - ['prettier'] = 61982, - ['vscode'] = 61983, - ['copy'] = 61984, - ['key-asterisk'] = 61985, - ['paste'] = 61986, - ['sort-asc'] = 61987, - ['sort-desc'] = 61988, - ['babel'] = 61989, - ['ionic'] = 61990, - ['next'] = 61991, - ['svelte'] = 61992, - ['capacitor'] = 61993, - ['graphql'] = 61994, - ['accessibility'] = 61995, - ['apps'] = 61996, - ['bell-fill'] = 61997, - ['cloud'] = 61998, - ['cloud-offline'] = 61999, - ['code-of-conduct'] = 62000, - ['feed-discussion'] = 62001, - ['feed-forked'] = 62002, - ['feed-heart'] = 62003, - ['feed-merged'] = 62004, - ['feed-person'] = 62005, - ['feed-repo'] = 62006, - ['feed-rocket'] = 62007, - ['feed-star'] = 62008, - ['feed-tag'] = 62009, - ['feed-trophy'] = 62010, - ['file-directory-fill'] = 62011, - ['file-directory-open-fill'] = 62012, - ['id-badge'] = 62013, - ['iterations'] = 62014, - ['log'] = 62015, - ['person-fill'] = 62016, - ['repo-deleted'] = 62017, - ['repo-locked'] = 62018, - ['single-select'] = 62019, - ['sliders'] = 62020, - ['stack'] = 62021, - ['tab-external'] = 62022, - ['telescope-fill'] = 62023, - ['trophy'] = 62024, - ['webhook'] = 62025, + ['zoom-in'] = 62076, + ['zoom-out'] = 62077, } return M diff --git a/lua/nonicons/override.lua b/lua/nonicons/override.lua index 9e18a9b..d861524 100644 --- a/lua/nonicons/override.lua +++ b/lua/nonicons/override.lua @@ -1,5 +1,8 @@ local mapping = require('nonicons.mapping') +local resolve_mod = require('nonicons.resolve') +---@param name string +---@return string? local function char(name) local code = mapping[name] if code then @@ -7,442 +10,16 @@ local function char(name) end end +---@type string local fallback_icon -local ext_map = { - lua = 'lua', - luac = 'lua', - luau = 'lua', - - js = 'javascript', - cjs = 'javascript', - mjs = 'javascript', - jsx = 'react', - tsx = 'react', - - ts = 'typescript', - cts = 'typescript', - mts = 'typescript', - ['d.ts'] = 'typescript', - - py = 'python', - pyc = 'python', - pyd = 'python', - pyi = 'python', - pyo = 'python', - pyw = 'python', - pyx = 'python', - - rb = 'ruby', - rake = 'ruby', - gemspec = 'ruby', - - rs = 'rust', - rlib = 'rust', - - go = 'go', - - c = 'c', - h = 'c', - - cpp = 'c-plusplus', - cc = 'c-plusplus', - cxx = 'c-plusplus', - ['c++'] = 'c-plusplus', - cp = 'c-plusplus', - cppm = 'c-plusplus', - cxxm = 'c-plusplus', - mpp = 'c-plusplus', - hh = 'c-plusplus', - hpp = 'c-plusplus', - hxx = 'c-plusplus', - ixx = 'c-plusplus', - mm = 'c-plusplus', - - cs = 'c-sharp', - cshtml = 'c-sharp', - csproj = 'c-sharp', - - java = 'java', - jar = 'java', - - kt = 'kotlin', - kts = 'kotlin', - - swift = 'swift', - - dart = 'dart', - - elm = 'elm', - - ex = 'elixir', - exs = 'elixir', - eex = 'elixir', - heex = 'elixir', - leex = 'elixir', - - vue = 'vue', - - svelte = 'svelte', - - html = 'html', - htm = 'html', - - css = 'css', - scss = 'css', - sass = 'css', - less = 'css', - styl = 'css', - - json = 'json', - json5 = 'json', - jsonc = 'json', - cson = 'json', - - yaml = 'yaml', - yml = 'yaml', - - toml = 'toml', - - md = 'markdown', - markdown = 'markdown', - mdx = 'markdown', - - php = 'php', - ['blade.php'] = 'php', - - pl = 'perl', - pm = 'perl', - - r = 'r', - R = 'r', - rmd = 'r', - - scala = 'scala', - sc = 'scala', - sbt = 'scala', - - vim = 'vim', - - graphql = 'graphql', - gql = 'graphql', - - tf = 'terraform', - tfvars = 'terraform', - - Dockerfile = 'docker', - dockerignore = 'docker', - - angular = 'angular', - - sh = 'terminal', - bash = 'terminal', - zsh = 'terminal', - fish = 'terminal', - ksh = 'terminal', - csh = 'terminal', - terminal = 'terminal', - ps1 = 'terminal', - - nix = 'code', - - sql = 'database', - sqlite = 'database', - sqlite3 = 'database', - db = 'database', - dump = 'database', - - rss = 'rss', - tmux = 'tmux', - nginx = 'nginx', - - diff = 'diff', - patch = 'diff', - - lock = 'lock', - lck = 'lock', - - conf = 'gear', - cfg = 'gear', - ini = 'gear', - env = 'key', - - git = 'git-branch', - - license = 'law', - - log = 'log', - - xml = 'code', - xslt = 'code', - - tex = 'book', - bib = 'book', - - png = 'image', - jpg = 'image', - jpeg = 'image', - gif = 'image', - bmp = 'image', - ico = 'image', - webp = 'image', - avif = 'image', - svg = 'image', - tiff = 'image', - jxl = 'image', - - zip = 'file-zip', - gz = 'file-zip', - tgz = 'file-zip', - ['7z'] = 'file-zip', - rar = 'file-zip', - bz = 'file-zip', - bz2 = 'file-zip', - bz3 = 'file-zip', - xz = 'file-zip', - zst = 'file-zip', - txz = 'file-zip', - tar = 'file-zip', - - bin = 'file-binary', - exe = 'file-binary', - dll = 'file-binary', - so = 'file-binary', - o = 'file-binary', - a = 'file-binary', - elf = 'file-binary', - ko = 'file-binary', - lib = 'file-binary', - out = 'file-binary', - - mp3 = 'play', - mp4 = 'play', - mkv = 'play', - mov = 'play', - avi = 'play', - flac = 'play', - ogg = 'play', - wav = 'play', - webm = 'play', - aac = 'play', - m4a = 'play', - m4v = 'play', - ogv = 'play', - wma = 'play', - wmv = 'play', - - ttf = 'typography', - otf = 'typography', - woff = 'typography', - woff2 = 'typography', - eot = 'typography', - - pdf = 'file', - doc = 'file', - docx = 'file', - ppt = 'file', - pptx = 'file', - xls = 'file', - xlsx = 'file', - csv = 'file', - txt = 'file', - - erl = 'code', - hrl = 'code', - hs = 'code', - lhs = 'code', - ml = 'code', - mli = 'code', - clj = 'code', - cljs = 'code', - cljc = 'code', - edn = 'code', - fnl = 'code', - el = 'code', - elc = 'code', - eln = 'code', - nim = 'code', - zig = 'code', - odin = 'code', - gleam = 'code', - cr = 'code', - jl = 'code', - nu = 'code', - pro = 'code', - scm = 'code', - rkt = 'code', - sol = 'code', - wasm = 'code', - ipynb = 'code', - gradle = 'code', - groovy = 'code', - ino = 'code', - prisma = 'code', - astro = 'code', - hx = 'code', - d = 'code', - ada = 'code', - adb = 'code', - ads = 'code', - f90 = 'code', - vala = 'code', - v = 'code', - vh = 'code', - vhd = 'code', - vhdl = 'code', - sv = 'code', - svh = 'code', - mo = 'code', - mojo = 'code', -} - -local filename_map = { - ['dockerfile'] = 'docker', - ['containerfile'] = 'docker', - ['docker-compose.yml'] = 'docker', - ['docker-compose.yaml'] = 'docker', - ['compose.yml'] = 'docker', - ['compose.yaml'] = 'docker', - ['.dockerignore'] = 'docker', - - ['.gitignore'] = 'git-branch', - ['.gitconfig'] = 'git-branch', - ['.gitattributes'] = 'git-branch', - ['.gitmodules'] = 'git-branch', - ['.git-blame-ignore-revs'] = 'git-branch', - ['.mailmap'] = 'git-branch', - ['commit_editmsg'] = 'git-commit', - - ['.bashrc'] = 'terminal', - ['.bash_profile'] = 'terminal', - ['.zshrc'] = 'terminal', - ['.zshenv'] = 'terminal', - ['.zprofile'] = 'terminal', - ['makefile'] = 'terminal', - ['gnumakefile'] = 'terminal', - ['.justfile'] = 'terminal', - ['justfile'] = 'terminal', - - ['.eslintrc'] = 'eslint', - ['.eslintignore'] = 'eslint', - ['eslint.config.js'] = 'eslint', - ['eslint.config.cjs'] = 'eslint', - ['eslint.config.mjs'] = 'eslint', - ['eslint.config.ts'] = 'eslint', - - ['.prettierrc'] = 'prettier', - ['.prettierignore'] = 'prettier', - ['.prettierrc.js'] = 'prettier', - ['.prettierrc.cjs'] = 'prettier', - ['.prettierrc.mjs'] = 'prettier', - ['.prettierrc.json'] = 'prettier', - ['.prettierrc.json5'] = 'prettier', - ['.prettierrc.toml'] = 'prettier', - ['.prettierrc.yaml'] = 'prettier', - ['.prettierrc.yml'] = 'prettier', - ['prettier.config.js'] = 'prettier', - ['prettier.config.cjs'] = 'prettier', - ['prettier.config.mjs'] = 'prettier', - ['prettier.config.ts'] = 'prettier', - - ['.babelrc'] = 'babel', - - ['package.json'] = 'npm', - ['package-lock.json'] = 'npm', - ['.npmrc'] = 'npm', - ['.npmignore'] = 'npm', - - ['pnpm-lock.yaml'] = 'yarn', - ['pnpm-workspace.yaml'] = 'package', - ['.pnpmfile.cjs'] = 'npm', - ['bun.lock'] = 'package', - ['bun.lockb'] = 'package', - - ['tsconfig.json'] = 'typescript', - - ['license'] = 'law', - ['license.md'] = 'law', - ['copying'] = 'law', - ['copying.lesser'] = 'law', - ['unlicense'] = 'law', - - ['tmux.conf'] = 'tmux', - ['tmux.conf.local'] = 'tmux', - - ['readme'] = 'book', - ['readme.md'] = 'book', - - ['go.mod'] = 'go', - ['go.sum'] = 'go', - ['go.work'] = 'go', - - ['.vimrc'] = 'vim', - ['.gvimrc'] = 'vim', - ['_vimrc'] = 'vim', - ['_gvimrc'] = 'vim', - - ['next.config.js'] = 'next', - ['next.config.cjs'] = 'next', - ['next.config.ts'] = 'next', - - ['svelte.config.js'] = 'svelte', - - ['mix.lock'] = 'elixir', - - ['.env'] = 'key', - - ['config'] = 'gear', - ['.editorconfig'] = 'gear', - - ['procfile'] = 'server', - - ['Gemfile'] = 'ruby', - ['rakefile'] = 'ruby', - - ['Jenkinsfile'] = 'gear', - - ['.gitlab-ci.yml'] = 'logo-github', - - ['security'] = 'shield', - ['security.md'] = 'shield', - - ['robots.txt'] = 'globe', - - ['vite.config.js'] = 'code', - ['vite.config.ts'] = 'code', - ['vite.config.cjs'] = 'code', - ['vite.config.cts'] = 'code', - ['vite.config.mjs'] = 'code', - ['vite.config.mts'] = 'code', - - ['build.gradle'] = 'code', - ['settings.gradle'] = 'code', - - ['pom.xml'] = 'code', - - ['hyprland.conf'] = 'gear', - ['hyprlock.conf'] = 'gear', - ['hypridle.conf'] = 'gear', - ['hyprpaper.conf'] = 'gear', - - ['cmakelists.txt'] = 'code', - ['code_of_conduct'] = 'book', - ['code_of_conduct.md'] = 'book', -} - +---@param name string? +---@param ext string? +---@return string local function resolve(name, ext) - if ext and ext_map[ext] then - return char(ext_map[ext]) - end - if name then - local lower = name:lower() - if filename_map[lower] then - return char(filename_map[lower]) - end - local dot_ext = lower:match('%.(.+)$') - if dot_ext and ext_map[dot_ext] then - return char(ext_map[dot_ext]) - end + local key = resolve_mod.resolve_name(name, ext) + if key then + return char(key) or fallback_icon end return fallback_icon end @@ -455,7 +32,7 @@ function M.apply() return end - fallback_icon = char('file') + fallback_icon = char('file') or '' local orig_get_icon = devicons.get_icon devicons.get_icon = function(name, ext, opts) @@ -470,8 +47,8 @@ function M.apply() devicons.get_icon_by_filetype = function(ft, opts) local icon, hl = orig_get_icon_by_filetype(ft, opts) if icon then - local nonicons_name = ext_map[ft] - icon = nonicons_name and char(nonicons_name) or fallback_icon + local key = resolve_mod.resolve_filetype(ft) + icon = key and char(key) or fallback_icon end return icon, hl end @@ -507,8 +84,8 @@ function M.apply() devicons.get_icon_colors_by_filetype = function(ft, opts) local icon, color, cterm_color = orig_get_icon_colors_by_filetype(ft, opts) if icon then - local nonicons_name = ext_map[ft] - icon = nonicons_name and char(nonicons_name) or fallback_icon + local key = resolve_mod.resolve_filetype(ft) + icon = key and char(key) or fallback_icon end return icon, color, cterm_color end @@ -517,8 +94,8 @@ function M.apply() devicons.get_icon_color_by_filetype = function(ft, opts) local icon, color = orig_get_icon_color_by_filetype(ft, opts) if icon then - local nonicons_name = ext_map[ft] - icon = nonicons_name and char(nonicons_name) or fallback_icon + local key = resolve_mod.resolve_filetype(ft) + icon = key and char(key) or fallback_icon end return icon, color end @@ -527,8 +104,8 @@ function M.apply() devicons.get_icon_cterm_color_by_filetype = function(ft, opts) local icon, cterm_color = orig_get_icon_cterm_color_by_filetype(ft, opts) if icon then - local nonicons_name = ext_map[ft] - icon = nonicons_name and char(nonicons_name) or fallback_icon + local key = resolve_mod.resolve_filetype(ft) + icon = key and char(key) or fallback_icon end return icon, cterm_color end @@ -536,7 +113,7 @@ function M.apply() local function override_tables() local by_ext = devicons.get_icons_by_extension() for ext, data in pairs(by_ext) do - local name = ext_map[ext] + local name = resolve_mod.ext_map[ext] or resolve_mod.ext_map[ext:lower()] if name then data.icon = char(name) or fallback_icon else @@ -546,7 +123,7 @@ function M.apply() local by_filename = devicons.get_icons_by_filename() for fname, data in pairs(by_filename) do - local name = filename_map[fname] + local name = resolve_mod.filename_map[fname] or resolve_mod.filename_map[fname:lower()] if name then data.icon = char(name) or fallback_icon else diff --git a/lua/nonicons/resolve.lua b/lua/nonicons/resolve.lua new file mode 100644 index 0000000..c3e1960 --- /dev/null +++ b/lua/nonicons/resolve.lua @@ -0,0 +1,485 @@ +local M = {} + +---@type table +M.ext_map = { + lua = 'lua', + luac = 'lua', + luau = 'lua', + + js = 'javascript', + cjs = 'javascript', + mjs = 'javascript', + jsx = 'react', + tsx = 'react', + + ts = 'typescript', + cts = 'typescript', + mts = 'typescript', + ['d.ts'] = 'typescript', + + py = 'python', + pyc = 'python', + pyd = 'python', + pyi = 'python', + pyo = 'python', + pyw = 'python', + pyx = 'python', + + rb = 'ruby', + rake = 'ruby', + gemspec = 'ruby', + + rs = 'rust', + rlib = 'rust', + + go = 'go', + + c = 'c', + h = 'c', + + cpp = 'c-plusplus', + cc = 'c-plusplus', + cxx = 'c-plusplus', + ['c++'] = 'c-plusplus', + cp = 'c-plusplus', + cppm = 'c-plusplus', + cxxm = 'c-plusplus', + mpp = 'c-plusplus', + hh = 'c-plusplus', + hpp = 'c-plusplus', + hxx = 'c-plusplus', + ixx = 'c-plusplus', + mm = 'c-plusplus', + + cs = 'c-sharp', + cshtml = 'c-sharp', + csproj = 'c-sharp', + + java = 'java', + jar = 'java', + + kt = 'kotlin', + kts = 'kotlin', + + swift = 'swift', + + dart = 'dart', + + elm = 'elm', + + ex = 'elixir', + exs = 'elixir', + eex = 'elixir', + heex = 'elixir', + leex = 'elixir', + + vue = 'vue', + + svelte = 'svelte', + + html = 'html', + htm = 'html', + + css = 'css', + scss = 'css', + sass = 'css', + less = 'css', + styl = 'css', + + json = 'json', + json5 = 'json', + jsonc = 'json', + cson = 'json', + + yaml = 'yaml', + yml = 'yaml', + + toml = 'toml', + + md = 'markdown', + markdown = 'markdown', + mdx = 'markdown', + + php = 'php', + ['blade.php'] = 'php', + + pl = 'perl', + pm = 'perl', + + r = 'r', + rmd = 'r', + + scala = 'scala', + sc = 'scala', + sbt = 'scala', + + vim = 'vim', + + graphql = 'graphql', + gql = 'graphql', + + tf = 'terraform', + tfvars = 'terraform', + + dockerfile = 'docker', + dockerignore = 'docker', + + angular = 'angular', + + sh = 'terminal', + bash = 'terminal', + zsh = 'terminal', + fish = 'terminal', + ksh = 'terminal', + csh = 'terminal', + terminal = 'terminal', + ps1 = 'terminal', + + nix = 'code', + + sql = 'database', + sqlite = 'database', + sqlite3 = 'database', + db = 'database', + dump = 'database', + + rss = 'rss', + tmux = 'tmux', + nginx = 'nginx', + + diff = 'diff', + patch = 'diff', + + lock = 'lock', + lck = 'lock', + + conf = 'gear', + cfg = 'gear', + ini = 'gear', + env = 'key', + + git = 'git-branch', + + license = 'law', + + log = 'log', + + xml = 'code', + xslt = 'code', + + tex = 'book', + bib = 'book', + + png = 'image', + jpg = 'image', + jpeg = 'image', + gif = 'image', + bmp = 'image', + ico = 'image', + webp = 'image', + avif = 'image', + svg = 'image', + tiff = 'image', + jxl = 'image', + + zip = 'file-zip', + gz = 'file-zip', + tgz = 'file-zip', + ['7z'] = 'file-zip', + rar = 'file-zip', + bz = 'file-zip', + bz2 = 'file-zip', + bz3 = 'file-zip', + xz = 'file-zip', + zst = 'file-zip', + txz = 'file-zip', + tar = 'file-zip', + + bin = 'file-binary', + exe = 'file-binary', + dll = 'file-binary', + so = 'file-binary', + o = 'file-binary', + a = 'file-binary', + elf = 'file-binary', + ko = 'file-binary', + lib = 'file-binary', + out = 'file-binary', + + mp3 = 'play', + mp4 = 'play', + mkv = 'play', + mov = 'play', + avi = 'play', + flac = 'play', + ogg = 'play', + wav = 'play', + webm = 'play', + aac = 'play', + m4a = 'play', + m4v = 'play', + ogv = 'play', + wma = 'play', + wmv = 'play', + + ttf = 'typography', + otf = 'typography', + woff = 'typography', + woff2 = 'typography', + eot = 'typography', + + pdf = 'file', + doc = 'file', + docx = 'file', + ppt = 'file', + pptx = 'file', + xls = 'file', + xlsx = 'file', + csv = 'file', + txt = 'file', + + erl = 'code', + hrl = 'code', + hs = 'code', + lhs = 'code', + ml = 'code', + mli = 'code', + clj = 'code', + cljs = 'code', + cljc = 'code', + edn = 'code', + fnl = 'code', + el = 'code', + elc = 'code', + eln = 'code', + nim = 'code', + zig = 'code', + odin = 'code', + gleam = 'code', + cr = 'code', + jl = 'code', + nu = 'code', + pro = 'code', + scm = 'code', + rkt = 'code', + sol = 'code', + wasm = 'code', + ipynb = 'code', + gradle = 'code', + groovy = 'code', + ino = 'code', + prisma = 'code', + astro = 'code', + hx = 'code', + d = 'code', + ada = 'code', + adb = 'code', + ads = 'code', + f90 = 'code', + vala = 'code', + v = 'code', + vh = 'code', + vhd = 'code', + vhdl = 'code', + sv = 'code', + svh = 'code', + mo = 'code', + mojo = 'code', +} + +---@type table +M.filename_map = { + ['dockerfile'] = 'docker', + ['containerfile'] = 'docker', + ['docker-compose.yml'] = 'docker', + ['docker-compose.yaml'] = 'docker', + ['compose.yml'] = 'docker', + ['compose.yaml'] = 'docker', + ['.dockerignore'] = 'docker', + + ['.gitignore'] = 'git-branch', + ['.gitconfig'] = 'git-branch', + ['.gitattributes'] = 'git-branch', + ['.gitmodules'] = 'git-branch', + ['.git-blame-ignore-revs'] = 'git-branch', + ['.mailmap'] = 'git-branch', + ['commit_editmsg'] = 'git-commit', + + ['.bashrc'] = 'terminal', + ['.bash_profile'] = 'terminal', + ['.zshrc'] = 'terminal', + ['.zshenv'] = 'terminal', + ['.zprofile'] = 'terminal', + ['makefile'] = 'terminal', + ['gnumakefile'] = 'terminal', + ['.justfile'] = 'terminal', + ['justfile'] = 'terminal', + + ['.eslintrc'] = 'eslint', + ['.eslintignore'] = 'eslint', + ['eslint.config.js'] = 'eslint', + ['eslint.config.cjs'] = 'eslint', + ['eslint.config.mjs'] = 'eslint', + ['eslint.config.ts'] = 'eslint', + + ['.prettierrc'] = 'prettier', + ['.prettierignore'] = 'prettier', + ['.prettierrc.js'] = 'prettier', + ['.prettierrc.cjs'] = 'prettier', + ['.prettierrc.mjs'] = 'prettier', + ['.prettierrc.json'] = 'prettier', + ['.prettierrc.json5'] = 'prettier', + ['.prettierrc.toml'] = 'prettier', + ['.prettierrc.yaml'] = 'prettier', + ['.prettierrc.yml'] = 'prettier', + ['prettier.config.js'] = 'prettier', + ['prettier.config.cjs'] = 'prettier', + ['prettier.config.mjs'] = 'prettier', + ['prettier.config.ts'] = 'prettier', + + ['.babelrc'] = 'babel', + + ['package.json'] = 'npm', + ['package-lock.json'] = 'npm', + ['.npmrc'] = 'npm', + ['.npmignore'] = 'npm', + + ['pnpm-lock.yaml'] = 'yarn', + ['pnpm-workspace.yaml'] = 'package', + ['.pnpmfile.cjs'] = 'npm', + ['bun.lock'] = 'package', + ['bun.lockb'] = 'package', + + ['tsconfig.json'] = 'typescript', + + ['license'] = 'law', + ['license.md'] = 'law', + ['copying'] = 'law', + ['copying.lesser'] = 'law', + ['unlicense'] = 'law', + + ['tmux.conf'] = 'tmux', + ['tmux.conf.local'] = 'tmux', + + ['readme'] = 'book', + ['readme.md'] = 'book', + + ['go.mod'] = 'go', + ['go.sum'] = 'go', + ['go.work'] = 'go', + + ['.vimrc'] = 'vim', + ['.gvimrc'] = 'vim', + ['_vimrc'] = 'vim', + ['_gvimrc'] = 'vim', + + ['next.config.js'] = 'next', + ['next.config.cjs'] = 'next', + ['next.config.ts'] = 'next', + + ['svelte.config.js'] = 'svelte', + + ['mix.lock'] = 'elixir', + + ['.env'] = 'key', + + ['config'] = 'gear', + ['.editorconfig'] = 'gear', + + ['procfile'] = 'server', + + ['gemfile'] = 'ruby', + ['rakefile'] = 'ruby', + + ['jenkinsfile'] = 'gear', + + ['.gitlab-ci.yml'] = 'logo-github', + + ['security'] = 'shield', + ['security.md'] = 'shield', + + ['robots.txt'] = 'globe', + + ['vite.config.js'] = 'code', + ['vite.config.ts'] = 'code', + ['vite.config.cjs'] = 'code', + ['vite.config.cts'] = 'code', + ['vite.config.mjs'] = 'code', + ['vite.config.mts'] = 'code', + + ['build.gradle'] = 'code', + ['settings.gradle'] = 'code', + + ['pom.xml'] = 'code', + + ['hyprland.conf'] = 'gear', + ['hyprlock.conf'] = 'gear', + ['hypridle.conf'] = 'gear', + ['hyprpaper.conf'] = 'gear', + + ['cmakelists.txt'] = 'code', + ['code_of_conduct'] = 'book', + ['code_of_conduct.md'] = 'book', +} + +---@type table +M.ft_map = { + typescriptreact = 'react', + javascriptreact = 'react', + make = 'terminal', + dockerfile = 'docker', + gitcommit = 'git-commit', + gitrebase = 'git-branch', + help = 'book', + text = 'file', + plaintex = 'book', + latex = 'book', +} + +---@param name string? Filename (e.g. `'init.lua'`) +---@param ext string? File extension (e.g. `'lua'`) +---@return string? icon_name +function M.resolve_name(name, ext) + if ext and M.ext_map[ext] then + return M.ext_map[ext] + end + if name then + local lower = name:lower() + if M.filename_map[lower] then + return M.filename_map[lower] + end + local last_ext = lower:match('%.([^%.]+)$') + if last_ext and M.ext_map[last_ext] then + return M.ext_map[last_ext] + end + local compound = lower:match('%.(.+)$') + if compound and compound ~= last_ext then + while compound do + if M.ext_map[compound] then + return M.ext_map[compound] + end + compound = compound:match('%.(.+)$') + end + end + end +end + +---@param ft string? Vim filetype +---@return string? icon_name +function M.resolve_filetype(ft) + if not ft then + return + end + local mapping = require('nonicons.mapping') + if mapping[ft] then + return ft + end + if M.ext_map[ft] then + return M.ext_map[ft] + end + if M.ft_map[ft] then + return M.ft_map[ft] + end +end + +return M diff --git a/plugin/nonicons.lua b/plugin/nonicons.lua index 7219658..e381004 100644 --- a/plugin/nonicons.lua +++ b/plugin/nonicons.lua @@ -4,3 +4,7 @@ end vim.g.loaded_nonicons = 1 require('nonicons').apply() + +vim.api.nvim_create_user_command('NoniconsHiTest', function() + require('nonicons.hi-test')() +end, { desc = 'nonicons: display all icons' }) diff --git a/scripts/gen-colors.lua b/scripts/gen-colors.lua new file mode 100644 index 0000000..f26c28c --- /dev/null +++ b/scripts/gen-colors.lua @@ -0,0 +1,39 @@ +#!/usr/bin/env lua + +local resolve = dofile('lua/nonicons/resolve.lua') +local ext_icons = dofile('/tmp/devicons_ext.lua') +local fname_icons = dofile('/tmp/devicons_fname.lua') + +local colors = {} + +for ext, icon_name in pairs(resolve.ext_map) do + if not colors[icon_name] and ext_icons[ext] then + colors[icon_name] = { + ext_icons[ext].color, + tonumber(ext_icons[ext].cterm_color), + } + end +end + +for fname, icon_name in pairs(resolve.filename_map) do + if not colors[icon_name] and fname_icons[fname] then + colors[icon_name] = { + fname_icons[fname].color, + tonumber(fname_icons[fname].cterm_color), + } + end +end + +local names = {} +for name in pairs(colors) do + names[#names + 1] = name +end +table.sort(names) + +io.write('---@type table\n') +io.write('local M = {\n') +for _, name in ipairs(names) do + local c = colors[name] + io.write(string.format(" ['%s'] = { '%s', %d },\n", name, c[1], c[2])) +end +io.write('}\n\nreturn M\n') diff --git a/selene.toml b/selene.toml index 96cf5ab..f2ada4b 100644 --- a/selene.toml +++ b/selene.toml @@ -1 +1,4 @@ std = 'vim' + +[lints] +bad_string_escape = 'allow' diff --git a/vim.toml b/vim.toml deleted file mode 100644 index 3a84ac2..0000000 --- a/vim.toml +++ /dev/null @@ -1,33 +0,0 @@ -[selene] -base = "lua51" -name = "vim" - -[vim] -any = true - -[jit] -any = true - -[bit] -any = true - -[assert] -any = true - -[describe] -any = true - -[it] -any = true - -[before_each] -any = true - -[after_each] -any = true - -[spy] -any = true - -[stub] -any = true diff --git a/vim.yaml b/vim.yaml new file mode 100644 index 0000000..3821d25 --- /dev/null +++ b/vim.yaml @@ -0,0 +1,26 @@ +--- +base: lua51 +name: vim +lua_versions: + - luajit +globals: + vim: + any: true + jit: + any: true + assert: + any: true + describe: + any: true + it: + any: true + before_each: + any: true + after_each: + any: true + spy: + any: true + stub: + any: true + bit: + any: true