feat: initial nonicons.nvim rewrite

Problem: the original ya2s/nvim-nonicons fork diverged enough that
maintaining it as a fork was pointless. The set_icon() approach broke
with modern nvim-web-devicons, and the extensions directory coupled
integrations that belong in user config.

Solution: from-scratch rewrite with function wrapping + table mutation
override engine, vim.g.nonicons config pattern, vendored mapping with
integer codepoints, health check, vimdoc with recipes, and no built-in
plugin integrations.
This commit is contained in:
Barrett Ruth 2026-02-17 19:34:13 -05:00
commit 04791cd41a
Signed by: barrett
GPG key ID: A6C96C9349D2FC81
15 changed files with 1491 additions and 0 deletions

9
.editorconfig Normal file
View file

@ -0,0 +1,9 @@
root = true
[*]
insert_final_newline = true
charset = utf-8
[*.lua]
indent_style = space
indent_size = 2

12
.gitignore vendored Normal file
View file

@ -0,0 +1,12 @@
doc/tags
*.log
.*cache*
CLAUDE.md
.claude/
node_modules/
result
result-*
.direnv/

8
.luarc.json Normal file
View file

@ -0,0 +1,8 @@
{
"runtime.version": "Lua 5.1",
"runtime.path": ["lua/?.lua", "lua/?/init.lua"],
"diagnostics.globals": ["vim", "jit"],
"workspace.library": ["$VIMRUNTIME/lua", "${3rd}/luv/library"],
"workspace.checkThirdParty": false,
"completion.callSnippet": "Replace"
}

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Barrett Ruth
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

180
README.md Normal file
View file

@ -0,0 +1,180 @@
# nonicons.nvim
**Nonicons for Neovim**
Replace [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)
glyphs with icons from the [nonicons](https://github.com/yamatsum/nonicons)
font. Any plugin that uses nvim-web-devicons automatically displays nonicons
glyphs.
## Requirements
- [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)
- [nonicons font](https://github.com/yamatsum/nonicons/releases) installed in
your terminal
## Installation
Install the nonicons font and configure your terminal to use it as a fallback:
**ghostty**
```
font-family = Nonicons
font-family = YourMainFont
```
**kitty**
```
symbol_map U+F101-U+F219 Nonicons
```
**wezterm**
```lua
config.font = wezterm.font_with_fallback({
'YourMainFont',
'Nonicons',
})
```
Install with your package manager of choice or via
[luarocks](https://luarocks.org/modules/barrettruth/nonicons.nvim):
```
luarocks install nonicons.nvim
```
**lazy.nvim**
```lua
{
'barrettruth/nonicons.nvim',
dependencies = { 'nvim-tree/nvim-web-devicons' },
}
```
The plugin applies overrides automatically. No `setup()` call is needed.
## Configuration
Configure via `vim.g.nonicons` before the plugin loads:
```lua
vim.g.nonicons = {
override = true, -- default; set false to disable devicons wrapping
}
```
## Usage
```lua
local get = require('nonicons').get
get('lua') -- returns the nonicons lua character
get('python') -- returns the nonicons python character
get('git-branch') -- returns the nonicons git-branch character
```
The raw mapping table is available for advanced use:
```lua
local code = require('nonicons').mapping['lua']
local icon = vim.fn.nr2char(code)
```
## Recipes
**lualine** — mode icons:
```lua
local get = require('nonicons').get
require('lualine').setup({
sections = {
lualine_a = {
{
'mode',
fmt = function(mode)
local map = {
NORMAL = get('vim-normal-mode'),
INSERT = get('vim-insert-mode'),
VISUAL = get('vim-visual-mode'),
REPLACE = get('vim-replace-mode'),
COMMAND = get('vim-command-mode'),
}
return map[mode] or mode
end,
},
},
},
})
```
**nvim-notify**:
```lua
require('notify').setup({
icons = {
ERROR = require('nonicons').get('x-circle'),
WARN = require('nonicons').get('alert'),
INFO = require('nonicons').get('info'),
DEBUG = require('nonicons').get('bug'),
TRACE = require('nonicons').get('play'),
},
})
```
**mason.nvim**:
```lua
require('mason').setup({
ui = {
icons = {
package_installed = require('nonicons').get('check'),
package_pending = require('nonicons').get('sync'),
package_uninstalled = require('nonicons').get('x'),
},
},
})
```
**oil.nvim**, **fzf-lua**, **telescope.nvim** — no configuration needed. These
plugins read from nvim-web-devicons which nonicons.nvim wraps automatically.
**nvim-tree**:
```lua
local get = require('nonicons').get
require('nvim-tree').setup({
renderer = {
icons = {
glyphs = {
default = get('file'),
symlink = get('file-symlink-file'),
folder = {
default = get('file-directory-fill'),
open = get('file-directory-open-fill'),
symlink = get('file-submodule'),
empty = get('file-directory-outline'),
arrow_open = get('chevron-down'),
arrow_closed = get('chevron-right'),
},
},
},
},
})
```
## Documentation
```vim
:help nonicons.nvim
```
## Acknowledgements
- [yamatsum/nonicons](https://github.com/yamatsum/nonicons) — icon font
- [ya2s/nvim-nonicons](https://github.com/ya2s/nvim-nonicons) — original plugin

207
doc/nonicons.nvim.txt Normal file
View file

@ -0,0 +1,207 @@
*nonicons.nvim.txt* Nonicons for Neovim
Author: Barrett Ruth <br.barrettruth@gmail.com>
License: MIT
==============================================================================
INTRODUCTION *nonicons.nvim*
nonicons.nvim replaces nvim-web-devicons glyphs with icons from the nonicons
font (https://github.com/yamatsum/nonicons). It wraps devicons functions so
that any plugin using nvim-web-devicons automatically displays nonicons glyphs.
==============================================================================
REQUIREMENTS *nonicons-requirements*
- nvim-web-devicons (https://github.com/nvim-tree/nvim-web-devicons)
- nonicons font installed in your terminal
==============================================================================
SETUP *nonicons-setup*
Using lazy.nvim: >lua
{
'barrettruth/nonicons.nvim',
dependencies = { 'nvim-tree/nvim-web-devicons' },
}
<
The plugin applies overrides automatically via `plugin/nonicons.lua`. No
`setup()` call is needed.
==============================================================================
CONFIGURATION *nonicons-config*
Configure via `vim.g.nonicons` before the plugin loads: >lua
vim.g.nonicons = {
override = true,
}
<
*nonicons.config.override*
override ~
`boolean` (default: `true`)
Whether to wrap nvim-web-devicons functions with nonicons glyphs.
==============================================================================
API *nonicons-api*
*nonicons.get()*
`require('nonicons').get(name)`
Returns the nonicons character for the given icon name, or `nil` if the
name is not in the mapping.
Parameters: ~
{name} `string` Icon name (e.g. `'lua'`, `'python'`, `'git-branch'`)
Returns: ~
`string?` The single-character nonicons glyph
*nonicons.mapping*
`require('nonicons').mapping`
The raw `table<string, integer>` mapping icon names to Unicode codepoints.
Useful for advanced use cases where you need the codepoint directly: >lua
local code = require('nonicons').mapping['lua']
local icon = vim.fn.nr2char(code)
<
==============================================================================
RECIPES *nonicons-recipes*
lualine ~
>lua
local get = require('nonicons').get
require('lualine').setup({
sections = {
lualine_a = {
{
'mode',
fmt = function(mode)
local map = {
NORMAL = get('vim-normal-mode'),
INSERT = get('vim-insert-mode'),
VISUAL = get('vim-visual-mode'),
['V-LINE'] = get('vim-visual-mode'),
['V-BLOCK'] = get('vim-visual-mode'),
REPLACE = get('vim-replace-mode'),
COMMAND = get('vim-command-mode'),
SELECT = get('vim-select-mode'),
TERMINAL = get('vim-terminal-mode'),
}
return map[mode] or mode
end,
},
},
},
})
<
nvim-notify ~
>lua
require('notify').setup({
icons = {
ERROR = require('nonicons').get('x-circle'),
WARN = require('nonicons').get('alert'),
INFO = require('nonicons').get('info'),
DEBUG = require('nonicons').get('bug'),
TRACE = require('nonicons').get('play'),
},
})
<
mason.nvim ~
>lua
require('mason').setup({
ui = {
icons = {
package_installed = require('nonicons').get('check'),
package_pending = require('nonicons').get('sync'),
package_uninstalled = require('nonicons').get('x'),
},
},
})
<
oil.nvim ~
No configuration needed. oil.nvim reads the devicons extension/filename
tables directly, which nonicons.nvim mutates on load.
fzf-lua ~
No configuration needed. fzf-lua calls `get_icon()` from devicons, which
nonicons.nvim wraps automatically.
telescope.nvim ~
No configuration needed. telescope.nvim calls `get_icon()` from devicons.
nvim-tree ~
>lua
local get = require('nonicons').get
require('nvim-tree').setup({
renderer = {
icons = {
glyphs = {
default = get('file'),
symlink = get('file-symlink-file'),
folder = {
default = get('file-directory-fill'),
open = get('file-directory-open-fill'),
symlink = get('file-submodule'),
empty = get('file-directory-outline'),
arrow_open = get('chevron-down'),
arrow_closed = get('chevron-right'),
},
},
},
},
})
<
==============================================================================
FONT SETUP *nonicons-font*
The nonicons font must be installed and configured in your terminal emulator.
Download the font from: https://github.com/yamatsum/nonicons/releases
ghostty ~
>
font-family = Nonicons
font-family = YourMainFont
<
kitty ~
>
symbol_map U+F101-U+F219 Nonicons
<
wezterm ~
>lua
config.font = wezterm.font_with_fallback({
'YourMainFont',
'Nonicons',
})
<
iTerm2 ~
Preferences > Profiles > Text > Non-ASCII Font > select Nonicons
==============================================================================
HEALTH CHECK *nonicons-health*
Run `:checkhealth nonicons` to verify:
- nvim-web-devicons is available
- The nonicons font is installed (via `fc-list`)
- The mapping table loaded successfully
==============================================================================
ACKNOWLEDGEMENTS *nonicons-acknowledgements*
- yamatsum/nonicons (https://github.com/yamatsum/nonicons) — icon font
- ya2s/nvim-nonicons (https://github.com/ya2s/nvim-nonicons) — original plugin
==============================================================================
vim:tw=78:ts=8:ft=help:norl:

29
lua/nonicons/health.lua Normal file
View file

@ -0,0 +1,29 @@
local M = {}
function M.check()
vim.health.start('nonicons.nvim')
local ok, devicons = pcall(require, 'nvim-web-devicons')
if ok and devicons then
vim.health.ok('nvim-web-devicons available')
else
vim.health.error('nvim-web-devicons not found')
end
local result = vim.fn.system({ 'fc-list', ':family=nonicons' })
if result ~= '' then
vim.health.ok('nonicons font installed')
else
vim.health.warn('nonicons font not detected (fc-list :family=nonicons returned empty)')
end
local mapping = require('nonicons.mapping')
local count = vim.tbl_count(mapping)
if count > 0 then
vim.health.ok('mapping loaded (' .. count .. ' icons)')
else
vim.health.error('mapping table is empty')
end
end
return M

43
lua/nonicons/init.lua Normal file
View file

@ -0,0 +1,43 @@
local M = {}
---@class nonicons.Config
---@field override boolean
---@type nonicons.Config
local default = {
override = true,
}
local initialized = false
---@type nonicons.Config
local config
local function ensure_initialized()
if initialized then
return
end
local user = vim.g.nonicons or {}
vim.validate('nonicons', user, 'table')
vim.validate('nonicons.override', user.override, 'boolean', true)
config = vim.tbl_deep_extend('force', default, user)
initialized = true
end
M.mapping = require('nonicons.mapping')
function M.get(name)
local code = M.mapping[name]
if code then
return vim.fn.nr2char(code)
end
end
function M.apply()
ensure_initialized()
if config.override then
require('nonicons.override').apply()
end
end
return M

333
lua/nonicons/mapping.lua Normal file
View file

@ -0,0 +1,333 @@
---@type table<string, integer>
local M = {
['alert'] = 61697,
['angular'] = 61698,
['archive'] = 61699,
['arrow-both'] = 61700,
['arrow-down'] = 61701,
['arrow-left'] = 61702,
['arrow-right'] = 61703,
['arrow-switch'] = 61704,
['arrow-up'] = 61705,
['backbone'] = 61706,
['beaker'] = 61707,
['bell'] = 61708,
['bell-slash'] = 61709,
['bold'] = 61710,
['book'] = 61711,
['bookmark'] = 61712,
['bookmark-slash'] = 61713,
['briefcase'] = 61714,
['broadcast'] = 61715,
['browser'] = 61716,
['bug'] = 61717,
['c'] = 61718,
['c-plusplus'] = 61719,
['c-sharp'] = 61720,
['calendar'] = 61721,
['check'] = 61722,
['check-circle'] = 61723,
['check-circle-fill'] = 61724,
['checklist'] = 61725,
['chevron-down'] = 61726,
['chevron-left'] = 61727,
['chevron-right'] = 61728,
['chevron-up'] = 61729,
['circle'] = 61730,
['circle-slash'] = 61731,
['clippy'] = 61732,
['clock'] = 61733,
['code'] = 61734,
['code-review'] = 61735,
['code-square'] = 61736,
['comment'] = 61737,
['comment-discussion'] = 61738,
['container'] = 61739,
['cpu'] = 61740,
['credit-card'] = 61741,
['cross-reference'] = 61742,
['css'] = 61743,
['dart'] = 61744,
['dash'] = 61745,
['database'] = 61746,
['desktop-download'] = 61747,
['device-camera'] = 61748,
['device-camera-video'] = 61749,
['device-desktop'] = 61750,
['device-mobile'] = 61751,
['diff'] = 61752,
['diff-added'] = 61753,
['diff-ignored'] = 61754,
['diff-modified'] = 61755,
['diff-removed'] = 61756,
['diff-renamed'] = 61757,
['docker'] = 61758,
['dot'] = 61759,
['dot-fill'] = 61760,
['download'] = 61761,
['ellipsis'] = 61762,
['elm'] = 61763,
['eye'] = 61764,
['eye-closed'] = 61765,
['file'] = 61766,
['file-badge'] = 61767,
['file-binary'] = 61768,
['file-code'] = 61769,
['file-diff'] = 61770,
['file-directory'] = 61771,
['file-directory-outline'] = 61772,
['file-submodule'] = 61773,
['file-symlink-file'] = 61774,
['file-zip'] = 61775,
['filter'] = 61776,
['flame'] = 61777,
['fold'] = 61778,
['fold-down'] = 61779,
['fold-up'] = 61780,
['gear'] = 61781,
['gift'] = 61782,
['git-branch'] = 61783,
['git-commit'] = 61784,
['git-compare'] = 61785,
['git-merge'] = 61786,
['git-pull-request'] = 61787,
['globe'] = 61788,
['go'] = 61789,
['grabber'] = 61790,
['graph'] = 61791,
['heading'] = 61792,
['heart'] = 61793,
['heart-fill'] = 61794,
['history'] = 61795,
['home'] = 61796,
['horizontal-rule'] = 61797,
['hourglass'] = 61798,
['html'] = 61799,
['hubot'] = 61800,
['image'] = 61801,
['inbox'] = 61802,
['infinity'] = 61803,
['info'] = 61804,
['issue-closed'] = 61805,
['issue-opened'] = 61806,
['issue-reopened'] = 61807,
['italic'] = 61808,
['java'] = 61809,
['javascript'] = 61810,
['json'] = 61811,
['kebab-horizontal'] = 61812,
['key'] = 61813,
['kotlin'] = 61814,
['kubernetes'] = 61815,
['law'] = 61816,
['light-bulb'] = 61817,
['link'] = 61818,
['link-external'] = 61819,
['list-ordered'] = 61820,
['list-unordered'] = 61821,
['location'] = 61822,
['lock'] = 61823,
['logo-gist'] = 61824,
['logo-github'] = 61825,
['lua'] = 61826,
['mail'] = 61827,
['mark-github'] = 61828,
['markdown'] = 61829,
['megaphone'] = 61830,
['mention'] = 61831,
['meter'] = 61832,
['milestone'] = 61833,
['mirror'] = 61834,
['moon'] = 61835,
['mortar-board'] = 61836,
['mute'] = 61837,
['nginx'] = 61838,
['no-entry'] = 61839,
['node'] = 61840,
['north-star'] = 61841,
['note'] = 61842,
['npm'] = 61843,
['octoface'] = 61844,
['organization'] = 61845,
['package'] = 61846,
['package-dependencies'] = 61847,
['package-dependents'] = 61848,
['paintbrush'] = 61849,
['paper-airplane'] = 61850,
['pencil'] = 61851,
['people'] = 61852,
['perl'] = 61853,
['person'] = 61854,
['php'] = 61855,
['pin'] = 61856,
['play'] = 61857,
['plug'] = 61858,
['plus'] = 61859,
['plus-circle'] = 61860,
['project'] = 61861,
['pulse'] = 61862,
['python'] = 61863,
['question'] = 61864,
['quote'] = 61865,
['r'] = 61866,
['react'] = 61867,
['rectangle'] = 61868,
['reply'] = 61869,
['repo'] = 61870,
['repo-clone'] = 61871,
['repo-forked'] = 61872,
['repo-pull'] = 61873,
['repo-push'] = 61874,
['repo-template'] = 61875,
['report'] = 61876,
['require'] = 61877,
['rocket'] = 61878,
['rss'] = 61879,
['ruby'] = 61880,
['rust'] = 61881,
['scala'] = 61882,
['screen-full'] = 61883,
['screen-normal'] = 61884,
['search'] = 61885,
['server'] = 61886,
['share'] = 61887,
['share-android'] = 61888,
['shield'] = 61889,
['shield-check'] = 61890,
['shield-lock'] = 61891,
['shield-x'] = 61892,
['sign-in'] = 61893,
['sign-out'] = 61894,
['skip'] = 61895,
['smiley'] = 61896,
['square'] = 61897,
['square-fill'] = 61898,
['squirrel'] = 61899,
['star'] = 61900,
['star-fill'] = 61901,
['stop'] = 61902,
['stopwatch'] = 61903,
['strikethrough'] = 61904,
['sun'] = 61905,
['swift'] = 61906,
['sync'] = 61907,
['tag'] = 61908,
['tasklist'] = 61909,
['telescope'] = 61910,
['terminal'] = 61911,
['three-bars'] = 61912,
['thumbsdown'] = 61913,
['thumbsup'] = 61914,
['tmux'] = 61915,
['toml'] = 61916,
['tools'] = 61917,
['trashcan'] = 61918,
['triangle-down'] = 61919,
['triangle-left'] = 61920,
['triangle-right'] = 61921,
['triangle-up'] = 61922,
['typescript'] = 61923,
['typography'] = 61924,
['unfold'] = 61925,
['unlock'] = 61926,
['unmute'] = 61927,
['unverified'] = 61928,
['upload'] = 61929,
['verified'] = 61930,
['versions'] = 61931,
['vim'] = 61932,
['vim-command-mode'] = 61933,
['vim-insert-mode'] = 61934,
['vim-normal-mode'] = 61935,
['vim-replace-mode'] = 61936,
['vim-select-mode'] = 61937,
['vim-terminal-mode'] = 61938,
['vim-visual-mode'] = 61939,
['vue'] = 61940,
['workflow'] = 61941,
['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,
}
return M

580
lua/nonicons/override.lua Normal file
View file

@ -0,0 +1,580 @@
local mapping = require('nonicons.mapping')
local function char(name)
local code = mapping[name]
if code then
return vim.fn.nr2char(code)
end
end
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',
}
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
end
return fallback_icon
end
local M = {}
function M.apply()
local ok, devicons = pcall(require, 'nvim-web-devicons')
if not ok then
return
end
fallback_icon = char('file')
local orig_get_icon = devicons.get_icon
devicons.get_icon = function(name, ext, opts)
local icon, hl = orig_get_icon(name, ext, opts)
if icon then
icon = resolve(name, ext)
end
return icon, hl
end
local orig_get_icon_by_filetype = devicons.get_icon_by_filetype
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
end
return icon, hl
end
local orig_get_icon_colors = devicons.get_icon_colors
devicons.get_icon_colors = function(name, ext, opts)
local icon, color, cterm_color = orig_get_icon_colors(name, ext, opts)
if icon then
icon = resolve(name, ext)
end
return icon, color, cterm_color
end
local orig_get_icon_color = devicons.get_icon_color
devicons.get_icon_color = function(name, ext, opts)
local icon, color = orig_get_icon_color(name, ext, opts)
if icon then
icon = resolve(name, ext)
end
return icon, color
end
local orig_get_icon_cterm_color = devicons.get_icon_cterm_color
devicons.get_icon_cterm_color = function(name, ext, opts)
local icon, cterm_color = orig_get_icon_cterm_color(name, ext, opts)
if icon then
icon = resolve(name, ext)
end
return icon, cterm_color
end
local orig_get_icon_colors_by_filetype = devicons.get_icon_colors_by_filetype
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
end
return icon, color, cterm_color
end
local orig_get_icon_color_by_filetype = devicons.get_icon_color_by_filetype
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
end
return icon, color
end
local orig_get_icon_cterm_color_by_filetype = devicons.get_icon_cterm_color_by_filetype
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
end
return icon, cterm_color
end
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]
if name then
data.icon = char(name) or fallback_icon
else
data.icon = fallback_icon
end
end
local by_filename = devicons.get_icons_by_filename()
for fname, data in pairs(by_filename) do
local name = filename_map[fname]
if name then
data.icon = char(name) or fallback_icon
else
data.icon = fallback_icon
end
end
devicons.set_default_icon(fallback_icon)
end
override_tables()
local group = vim.api.nvim_create_augroup('Nonicons', { clear = true })
vim.api.nvim_create_autocmd('OptionSet', {
pattern = 'background',
group = group,
callback = function()
vim.schedule(override_tables)
end,
})
vim.api.nvim_create_autocmd('ColorScheme', {
group = group,
callback = function()
vim.schedule(override_tables)
end,
})
end
return M

View file

@ -0,0 +1,21 @@
rockspec_format = '3.0'
package = 'nonicons.nvim'
version = 'scm-1'
source = {
url = 'git+https://github.com/barrettruth/nonicons.nvim.git',
}
description = {
summary = 'Nonicons for Neovim',
homepage = 'https://github.com/barrettruth/nonicons.nvim',
license = 'MIT',
}
dependencies = {
'lua >= 5.1',
}
build = {
type = 'builtin',
}

6
plugin/nonicons.lua Normal file
View file

@ -0,0 +1,6 @@
if vim.g.loaded_nonicons then
return
end
vim.g.loaded_nonicons = 1
require('nonicons').apply()

1
selene.toml Normal file
View file

@ -0,0 +1 @@
std = 'vim'

8
stylua.toml Normal file
View file

@ -0,0 +1,8 @@
column_width = 100
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2
quote_style = "AutoPreferSingle"
call_parentheses = "Always"
[sort_requires]
enabled = true

33
vim.toml Normal file
View file

@ -0,0 +1,33 @@
[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