8000 mini.nvim/lua/mini/icons.lua at main · isti115/mini.nvim · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
2142 lines (2058 loc) · 117 KB

icons.lua

File metadata and controls

2142 lines (2058 loc) · 117 KB
--- *mini.icons* Icon provider
--- *MiniIcons*
---
--- MIT License Copyright (c) 2024 Evgeni Chasnovski
---
--- ==============================================================================
---
--- Features:
---
--- - Provide icons with their highlighting via a single |MiniIcons.get()| for
--- various categories: filetype, file/directory path, extension, operating
--- system, LSP kind values. Icons and category defaults can be overridden.
---
--- - Configurable styles: "glyph" (icon glyphs) or "ascii" (non-glyph fallback).
---
--- - Fixed set of highlight groups (linked to built-in groups by default) for
--- better blend with color scheme.
---
--- - Caching for maximum performance.
---
--- - Integration with |vim.filetype.add()| and |vim.filetype.match()|.
---
--- - Mocking methods of 'nvim-tree/nvim-web-devicons' for better integrations
--- with plugins outside 'mini.nvim'. See |MiniIcons.mock_nvim_web_devicons()|.
---
--- - Tweaking built-in maps for "LSP kind" to include icons. In particular, this
--- makes |mini.completion| use icons in LSP step. See |MiniIcons.tweak_lsp_kind()|.
---
--- Notes:
---
--- - It is not a goal to become a collection of icons for as much use cases as
--- possible. There are specific criteria for icon data to be included as
--- built-in in each category (see |MiniIcons.get()|).
--- The main supported category is "filetype".
---
--- Recommendations for plugin authors using 'mini.icons' as a dependency:
---
--- - Check if `_G.MiniIcons` table is present (which means that user explicitly
--- enabled 'mini.icons') and provide icons only if it is.
---
--- - Use |MiniIcons.get()| function to get icon string and more data about it.
---
--- - For file icons prefer using full path instead of relative or only basename.
--- It makes a difference if path matches pattern that uses parent directories.
--- The |MiniIcons.config| has an example of that.
---
--- # Dependencies ~
---
--- Suggested dependencies:
---
--- - Terminal emulator that supports showing special utf8 glyphs, possibly with
--- "overflow" view (displaying is done not in one but two visual cells).
--- Most modern feature-rich terminal emulators support this out of the box:
--- WezTerm, Kitty, Alacritty, iTerm2, Ghostty.
--- Not having "overflow" feature only results into smaller icons.
--- Not having support for special utf8 glyphs will result into seemingly
--- random symbols (or question mark squares) instead of icon glyphs.
---
--- - Font that supports Nerd Fonts (https://www.nerdfonts.com) icons from
--- version 3.0.0+ (in particular `nf-md-*` class).
--- This should be configured on terminal emulator level either by using font
--- patched with Nerd Fonts icons or using `NerdFontsSymbolsOnly` font as
--- a fallback for glyphs that are not supported in main font.
---
--- If using terminal emulator and/or font with icon support is impossible, use
--- `config.style = 'ascii'`. It will use a (less visually appealing) set of
--- non-glyph icons.
---
--- # Setup ~
---
--- This module needs a setup with `require('mini.icons').setup({})` (replace `{}`
--- with your `config` table). It will create global Lua table `MiniIcons` which you
--- can use for scripting or manually (with `:lua MiniIcons.*`).
---
--- See |MiniIcons.config| for `config` structure and default values.
---
--- # Comparisons ~
---
--- - 'nvim-tree/nvim-web-devicons' (for users):
--- - Sets individual colors to each icon with separate specific highlight
--- groups, while this modules uses fixed set of highlight groups.
--- This makes it easier to customize in bulk and actually blend with any
--- color scheme.
---
--- - This module prefers richer set of `nf-md-*` (from "Material design" set)
--- Nerd Fonts icons while 'nvim-web-devicons' mostly prefers `nf-dev-*`
--- (from "devicons" set).
---
--- - Supported categories are slightly different (with much overlap).
---
--- - Both support customization of any icon. Only this module supports
--- customization of default ones per supported category.
---
--- - Using this module can occasionally result in small delays when used
--- synchronously for many times to get icons for not typical files (like
--- in |mini.files|). This is due to using |vim.filetype.match()| fallback and
--- is present only during first call, as value is cached for later uses.
---
--- - This module supports different icon styles (like "ascii" for when using
--- glyphs is not possible), while 'nvim-web-devicons' does not.
---
--- - This module provides |MiniIcons.mock_nvim_web_devicons()| function which
--- when called imitates installed 'nvim-web-devicons' plugin to support
--- other plugins which do not provide 'mini.icons' yet.
---
--- - 'nvim-tree/nvim-web-devicons' (for plugin developers):
--- - Both have main "get icon" type of function:
--- - Both return tuple of icon and highlight group strings.
---
--- - This module always returns icon data possibly falling back to
--- user's configured default, while 'nvim-web-devicons' is able to
--- return `nil`. This module's approach is more aligned with the most
--- common use case of always showing an icon instead or near some data.
--- There is a third returned value indicating if output is a result of
--- a fallback (see |MiniIcons.get()|).
---
--- - This module uses |vim.filetype.match()| as a fallback for "file"
--- and "extension" categories, while 'nvim-web-devicons' completely
--- relies on the manually maintained tables of supported filenames
--- and extensions.
--- Using fallback results in a wider support and deeper integration
--- with Neovim's filetype detection at the cost of occasional slower
--- first call. The difference is reduced as much as is reasonable by
--- preferring faster file extension resolution over filetype matching.
---
--- - This module caches all its return values resulting in really fast
--- next same argument calls, while 'nvim-web-devicons' doesn't do that.
---
--- - This module works with full file/directory paths as input.
---
--- - Different sets of supported categories (see |MiniIcons.config|):
--- - Both support "file", "extension", "filetype", "operating system".
--- Albeit in different volumes: 'nvim-web-devicons' covers more
--- cases for "operating system", while this module has better eventual
--- coverage for other cases.
---
--- - This module supports "directory" and "lsp" categories.
---
--- - 'nvim-web-devicons' covers "desktop environment" and "window
--- management" categories. This modules does not include them due to
--- relatively low demand.
---
--- - 'onsails/lspkind.nvim':
--- - Provides icons only for `CompletionItemKind`, while this module also has
--- icons for `SymbolKind` and other non-LSP categories.
--- - Provides dedicated formatting function for 'hrsh7th/nvim-cmp' while this
--- module intentionally does not (adding icons should be straightforward
--- to manually implement while anything else is out of scope).
---
--- # Highlight groups ~
---
--- Only the following set of highlight groups is used as icon highlight.
--- It is recommended that they all only define colored foreground:
---
--- * `MiniIconsAzure` - azure.
--- * `MiniIconsBlue` - blue.
--- * `MiniIconsCyan` - cyan.
--- * `MiniIconsGreen` - green.
--- * `MiniIconsGrey` - grey.
--- * `MiniIconsOrange` - orange.
--- * `MiniIconsPurple` - purple.
--- * `MiniIconsRed` - red.
--- * `MiniIconsYellow` - yellow.
---
--- To change any highlight group, modify it directly with |:highlight|.
---@diagnostic disable:undefined-field
---@diagnostic disable:discard-returns
---@diagnostic disable:unused-local
---@diagnostic disable:cast-local-type
---@diagnostic disable:undefined-doc-name
---@diagnostic disable:luadoc-miss-type-name
-- Module definition ==========================================================
local MiniIcons = {}
local H = {}
--- Module setup
---
---@param config table|nil Module config table. See |MiniIcons.config|.
---
---@usage >lua
--- require('mini.icons').setup() -- use default config
--- -- OR
--- require('mini.icons').setup({}) -- replace {} with your config table
--- <
MiniIcons.setup = function(config)
-- Export module
_G.MiniIcons = MiniIcons
-- Setup config
config = H.setup_config(config)
-- Apply config
H.apply_config(config)
-- Define behavior
H.create_autocommands()
-- Create default highlighting
H.create_default_hl()
end
--stylua: ignore
--- Module config
---
--- Default values:
---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
---@text # Style ~
---
--- `config.style` is a string defining which icon style to use. It can be:
--- - `'glyph'` (default) - use glyph icons (like 󰈔 and 󰉋 ).
--- - `'ascii'` - use fallback ASCII-compatible icons. Those are computed as
--- an upper first character of the icon's resolved name inside its category.
--- Examples: >lua
---
--- MiniIcons.get('file', 'Makefile') -- Has `'M'` as icon
--- MiniIcons.get('extension', 'lua') -- Has `'L'` as icon
--- MiniIcons.get('file', 'file.lua') -- Has `'L'` as icon; it is resolved to
--- -- come from 'lua' 'extension' category
--- MiniIcons.get('file', 'myfile') -- Has `'F'` as icon; it is resolved to
--- -- come from 'file' 'default' category
--- <
--- # Customization per category ~
---
--- The following entries can be used to customize icons for supported categories:
--- - `config.default`
--- - `config.directory`
--- - `config.extension`
--- - `config.file`
--- - `config.filetype`
--- - `config.lsp`
--- - `config.os`
---
--- Customization should be done by supplying a table with <glyph> (icon glyph)
--- and/or <hl> (name of highlight group) string fields as a value for an icon
--- name entry. Example: >lua
---
--- require('mini.icons').setup({
--- default = {
--- -- Override default glyph for "file" category (reuse highlight group)
--- file = { glyph = '󰈤' },
--- },
--- extension = {
--- -- Override highlight group (not necessary from 'mini.icons')
--- lua = { hl = 'Special' },
---
--- -- Add icons for custom extension. This will also be used in
--- -- 'file' category for input like 'file.my.ext'.
--- ['my.ext'] = { glyph = '󰻲', hl = 'MiniIconsRed' },
--- },
--- })
--- <
--- Notes:
--- - These customizations only take effect inside |MiniIcons.setup()| call.
--- Changing interactively via `:lua MiniIcons.config.xxx = { ... }` does not work
--- for performance reasons.
--- - Use lower case names for categories which are matched ignoring case.
--- See |MiniIcons.get()| for more details.
---
--- # Using extension during file resolution ~
---
--- `config.use_file_extension` is a function which can be used to control which
--- extensions will be considered as a source of icon data during "file" category
--- resolution (see |MiniIcons.get()| for more details).
--- Default: function which always returns `true` (i.e. consider all extensions).
---
--- Will be called once for the biggest suffix after dot found in the file name.
--- The arguments will be `ext` (found extension; lowercase) and `file` (input for
--- which icon is computed; as is). Should explicitly return `true` if `ext` is to
--- be considered (i.e. call `MiniIcons.get('extension', ext)` and use its
--- output if it is not default). Otherwise extension won't be even considered.
---
--- The primary use case for this setting is to ensure that some extensions are
--- ignored in order for resolution to reach |vim.filetype.match()| stage. This
--- is needed if there is a set up filetype detection for files with recognizable
--- extension and conflicting icons (which you want to use). Note: if problematic
--- filetype detection involves only known in advance file names, prefer using
--- `config.file` customization.
---
--- Example: >lua
---
--- -- Built-in filetype detection recognizes files like "queries/.*%.scm"
--- -- as "query" filetype. However, without special setup, 'mini.icons' will
--- -- use "scm" extension to resolve as Scheme file. Here is a setup to ignore
--- -- "scm" extension and completely rely on `vim.filetype.match()` fallback.
--- require('mini.icons').setup({
--- -- Check last letters explicitly to account for dots in file name
--- use_file_extension = function(ext) return ext:sub(-3) ~= 'scm' end
--- })
---
--- -- Another common choices for extensions to ignore: "yml", "json", "txt".
--- <
MiniIcons.config = {
-- Icon style: 'glyph' or 'ascii'
style = 'glyph',
-- Customize per category. See `:h MiniIcons.config` for details.
default = {},
directory = {},
extension = {},
file = {},
filetype = {},
lsp = {},
os = {},
-- Control which extensions will be considered during "file" resolution
use_file_extension = function(ext, file) return true end,
}
--minidoc_afterlines_end
--- Get icon data
---
--- Usage example: >lua
---
--- -- Results into `icon='󰢱'`, `hl='MiniIconsAzure'`, `is_default=false`
--- local icon, hl, is_default = MiniIcons.get('file', 'file.lua')
--- <
--- Notes:
--- - Always returns some data, even if icon name is not explicitly supported
--- within target category. Category "default" is used as a fallback. Use third
--- output value to check if this particular case is a result of a fallback.
---
--- - Glyphs are explicitly preferred (when reasonable) from a richer set of
--- `nf-md-*` class ("Material design" set) of Nerd Fonts icons.
---
--- - Output is cached after the first call to increase performance of next calls
--- with same arguments. To reset cache, call |MiniIcons.setup()|.
---
--- - To increase first call performance for "extension" and "file" categories,
--- add frequently used values in |MiniIcons.config|. They will be preferred
--- over executing |vim.filetype.match()|.
---
--- - Matching icon name for "file" and "directory" categories is done exactly
--- and respecting case. Others are done ignoring case.
---
---@param category string Category name. Supported categories:
--- - `'default'` - icon data used as fallback for any category.
--- Icon names:
--- - <Input>: any supported category name.
--- - <Built-in>: only supported category names.
---
--- Examples: >lua
---
--- MiniIcons.get('default', 'file')
--- <
--- - `'directory'` - icon data for directory path.
--- Icon names:
--- - <Input>: any string, but only basename is used. Works with not present
--- paths (no check is done).
--- - <Built-in>: popular directory names not tied to language/software
--- (with few notable exceptions like Neovim, Git, etc.).
---
--- Examples: >lua
---
--- -- All of these will result in the same output
--- MiniIcons.get('directory', '.config')
--- MiniIcons.get('directory', '~/.config')
--- MiniIcons.get('directory', '/home/user/.config')
---
--- -- Results in different output
--- MiniIcons.get('directory', '.Config')
--- <
--- - `'extension'` - icon data for extension.
--- Icon names:
--- - <Input>: any string (without extra dot prefix).
--- - <Built-in>: popular extensions without associated filetype plus a set
--- for which filetype detection gives not good enough result.
---
--- Icon data is attempted to be resolved in the following order:
--- - List of user configured and built-in extensions (for better results).
--- Run `:=MiniIcons.list('extension')` to see them.
--- Used also if present as suffix after the dot (widest one preferred).
--- - Filetype as a result of |vim.filetype.match()| with placeholder
--- file name. Uses icon data from "filetype" category.
---
--- Examples: >lua
---
--- -- All of these will result in the same output
--- MiniIcons.get('extension', 'lua')
--- MiniIcons.get('extension', 'LUA')
--- MiniIcons.get('extension', 'my.lua')
--- <
--- - `'file'` - icon data for file path.
--- Icon names:
--- - <Input>: any string. Works with not present paths (no check is done).
--- - <Built-in>: popular file names not tied to language/software
--- (with few notable exceptions like Neovim, Git, etc.) plus a set which
--- has recognizab 10BC8 le extension but has special detectable filetype.
---
--- Icon data is attempted to be resolved in the following order:
--- - List of user configured and built-in file names (matched to basename
--- of the input exactly). Run `:=MiniIcons.list('flle')` to see them.
--- - Basename extension:
--- - Matched directly as `get('extension', ext)`, where `ext` is the
--- widest suffix after the dot.
--- - Considered only if `config.use_file_extension` returned `true`.
--- - Only recognizable extensions (i.e. not default fallback) are used.
--- - Filetype as a result of |vim.filetype.match()| with full input (not
--- basename) as `filename`. Uses icon data from "filetype" category.
---
--- Examples: >lua
---
--- -- All of these will result in the same output
--- MiniIcons.get('file', 'init.lua')
--- MiniIcons.get('file', '~/.config/nvim/init.lua')
--- MiniIcons.get('file', '/home/user/.config/nvim/init.lua')
---
--- -- Results in different output
--- MiniIcons.get('file', 'Init.lua')
--- MiniIcons.get('file', 'init.LUA')
---
--- -- Respects full path input in `vim.filetype.match()`
--- MiniIcons.get('file', '.git/info/attributes')
--- <
--- - `'filetype'` - icon data for 'filetype' values.
--- Icon names:
--- - <Input>: any string.
--- - <Built-in>: any filetype that is reasonably used in Neovim ecosystem.
--- This category is intended as a widest net for supporting use cases.
--- Users are encouraged to have a specific filetype detection set up.
---
--- Examples: >lua
---
--- MiniIcons.get('filetype', 'lua')
--- MiniIcons.get('filetype', 'help')
--- MiniIcons.get('filetype', 'minifiles')
--- <
--- - `'lsp'` - icon data for various "LSP kind" values.
--- Icon names:
--- - <Input>: any string.
--- - <Built-in>: only namesspace entries from LSP specification that are
--- can be displayed to user. Like `CompletionItemKind`, `SymbolKind`, etc.
---
--- Examples: >lua
---
--- MiniIcons.get('lsp', 'array')
--- MiniIcons.get('lsp', 'keyword')
--- <
--- - `'os'` - icon data for popular operating systems.
--- Icon names:
--- - <Input>: any string.
--- - <Built-in>: only operating systems which have `nf-md-*` class icon.
---
--- Examples: >lua
---
--- MiniIcons.get('os', 'linux')
--- MiniIcons.get('os', 'arch')
--- MiniIcons.get('os', 'macos')
--- <
---@param name string Icon name within category. Use |MiniIcons.list()| to get icon
--- names which are explicitly supported for specific category.
---
---@return ... Tuple of icon string, highlight group name it is suggested to be
--- highlighted with, and boolean indicating whether this icon was returned
--- as a result of fallback to default. Example: >lua
---
--- -- Results into `icon='󰢱'`, `hl='MiniIconsAzure'`, `is_default=false`
--- local icon, hl, is_default = MiniIcons.get('file', 'file.lua')
---
--- -- Results into `icon='󰈔'`, `hl='MiniIconsGrey'`, `is_default=true`
--- local icon, hl, is_default = MiniIcons.get('file', 'not-supported')
--- <
MiniIcons.get = function(category, name)
if not (type(category) == 'string' and type(name) == 'string') then
H.error('Both `category` and `name` should be string.')
end
-- Get "get" implementation now to show informative message for bad category
local getter = H.get_impl[category]
if getter == nil then H.error(vim.inspect(category) .. ' is not a supported category.') end
-- Try cache first
name = category == 'file' and name or (category == 'directory' and H.fs_basename(name) or name:lower())
local cached = H.cache_get(category, name)
if cached ~= nil then return cached[1], cached[2], cached[3] == true end
-- Get icon. Assume `nil` value to mean "fall back to category default".
local icon, hl = getter(name)
if type(icon) == 'table' then
icon, hl = H.style_icon(icon.glyph, name), icon.hl
end
-- Save to cache and return
return H.cache_set(category, name, icon, hl)
end
--- List explicitly supported icon names
---
---@param category string Category name supported by |MiniIcons.get()|.
---
---@return table Array of icon names which are explicitly supported for category.
--- Note, that `'file'` and `'extension'` categories support much more icon names
--- via their fallback to using |vim.filetype.match()| with `'filetype'` category.
MiniIcons.list = function(category)
local category_icons = H[category .. '_icons']
if category_icons == nil then H.error(vim.inspect(category) .. ' is not a supported category.') end
-- Output is a union of explicit built-in and custom icons
local res_map = {}
for k, _ in pairs(category_icons) do
res_map[k] = true
end
for k, _ in pairs(MiniIcons.config[category]) do
res_map[k] = true
end
local res = vim.tbl_keys(res_map)
table.sort(res)
return res
end
--- Mock 'nvim-web-devicons' module
---
--- Call this function to mock exported functions of 'nvim-tree/nvim-web-devicons'
--- plugin. It will mock all its functions which return icon data by
--- using |MiniIcons.get()| equivalent.
---
--- This function is useful if any plugins relevant to you depend solely on
--- 'nvim-web-devicons' and have not yet added an integration with 'mini.icons'.
---
--- Full example of usage: >lua
---
--- require('mini.icons').setup()
--- MiniIcons.mock_nvim_web_devicons()
--- <
--- Works without installed 'nvim-web-devicons' and even with it installed (needs
--- to be called after 'nvim-web-devicons' is set up).
MiniIcons.mock_nvim_web_devicons = function()
local M = {}
-- Main functions which get icon and highlight group
M.get_icon = function(name, ext, opts)
-- Preferring 'name' first leads to a slightly different behavior compared to
-- the original in case both `name` and `ext` is supplied:
-- - Original: try exact `name`, then `ext`, then extensions in `name`.
-- - This: use 'file' category and ignore `ext` completely.
-- In practice this seems like a better choice because it accounts for
-- special file names at the cost of ignoring `ext` if it conflicts with
-- `name` (which rarely happens) and very small overhead of recomputing
-- extension (which assumed to already be computed by the caller).
local is_file = type(name) == 'string'
local category = is_file and 'file' or 'extension'
local icon, hl, is_default = MiniIcons.get(category, is_file and name or ext)
if is_default and not (opts or {}).default then return nil, nil end
return icon, hl
end
M.get_icon_by_filetype = function(ft, opts)
local icon, hl, is_default = MiniIcons.get('filetype', ft)
if is_default and not (opts or {}).default then return nil, nil end
return icon, hl
end
-- Use default colors of default icon (#6d8086 and 66) by default
local get_hl_data = function(...) return vim.api.nvim_get_hl_by_name(...) end
local get_hex = function(hl)
if hl == nil then return nil end
return string.format('#%06x', get_hl_data(hl, true).foreground or 7176326)
end
local get_cterm = function(hl)
if hl == nil then return nil end
return get_hl_data(hl, false).foreground or 66
end
local with_hex = function(icon, hl) return icon, get_hex(hl) end
local with_cterm = function(icon, hl) return icon, get_cterm(hl) end
local with_hex_cterm = function(icon, hl) return icon, get_hex(hl), get_cterm(hl) end
M.get_icon_color = function(...) return with_hex(M.get_icon(...)) end
M.get_icon_cterm_color = function(...) return with_cterm(M.get_icon(...)) end
M.get_icon_colors = function(...) return with_hex_cterm(M.get_icon(...)) end
M.get_icon_color_by_filetype = function(...) return with_hex(M.get_icon_by_filetype(...)) end
M.get_icon_cterm_color_by_filetype = function(...) return with_cterm(M.get_icon_by_filetype(...)) end
M.get_icon_colors_by_filetype = function(...) return with_hex_cterm(M.get_icon_by_filetype(...)) end
M.get_icon_name_by_filetype = function(ft) return ft end
-- Mock `get_icons_*()` to the extent they are compatible with this module
local make_icon_tbl = function(category, name, output_name)
local icon, hl = MiniIcons.get(category, name)
return { icon = icon, color = get_hex(hl), cterm_color = tostring(get_cterm(hl)), name = output_name }
end
local make_category_tbl = function(category)
local res = {}
-- This won't list all supported names (due to fallback), but at least some
for _, name in ipairs(MiniIcons.list(category)) do
res[name] = make_icon_tbl(category, name, name)
end
return res
end
M.get_default_icon = function() return make_icon_tbl('default', 'file', 'Default') end
M.get_icons = function()
return vim.tbl_deep_extend(
'force',
{ [1] = M.get_default_icon() },
make_category_tbl('os'),
make_category_tbl('file'),
make_category_tbl('extension')
)
end
M.get_icons_by_desktop_environment = function() return {} end
M.get_icons_by_extension = function() return make_category_tbl('extension') end
M.get_icons_by_filename = function() return make_category_tbl('file') end
M.get_icons_by_operating_system = function() return make_category_tbl('os') end
M.get_icons_by_window_manager = function() return {} end
-- Should be no need in the these. Suggest using `MiniIcons.setup()`.
M.has_loaded = function() return true end
M.refresh = function() end
M.set_default_icon = function() end
M.set_icon = function() end
M.set_icon_by_filetype = function() end
M.set_up_highlights = function() end
M.setup = function() end
-- Mock. Prefer `package.preload` as it seems to be a better practice.
local modname = 'nvim-web-devicons'
if package.loaded[modname] == nil then
package.preload[modname] = function() return M end
else
package.loaded[modname] = M
end
vim.g.nvim_web_devicons = 1
end
--- Tweak built-in LSP kind names
---
--- Update in place appropriate maps in |vim.lsp.protocol| (`CompletionItemKind`
--- and `SymbolKind`) by using icon strings from "lsp" category. Only "numeric
--- id to kind name" part is updated (to preserve data from original map).
---
--- Updating is done in one of these modes:
--- - Append: add icon after text.
--- - Prepend: add icon before text (default).
--- - Replace: use icon instead of text.
---
--- Notes:
--- - Makes |mini.completion| show icons, as it uses built-in protocol map.
--- - Results in loading whole `vim.lsp` module, so might add significant amount
--- of time on startup. Call it lazily. For example, with |MiniDeps.later()|: >
---
--- require('mini.icons').setup()
--- MiniDeps.later(MiniIcons.tweak_lsp_kind)
--- <
---@param mode string|nil One of "prepend" (default), "append", "replace".
MiniIcons.tweak_lsp_kind = function(mode)
mode = mode or 'prepend'
local format
if mode == 'append' then format = function(kind) return kind .. ' ' .. MiniIcons.get('lsp', kind) end end
if mode == 'prepend' then format = function(kind) return MiniIcons.get('lsp', kind) .. ' ' .. kind end end
if mode == 'replace' then format = function(kind) return MiniIcons.get('lsp', kind) end end
if format == nil then H.error('`mode` should be one of "append", "prepend", "replace".') end
local protocol = vim.lsp.protocol
for i, kind in ipairs(protocol.CompletionItemKind) do
protocol.CompletionItemKind[i] = format(kind)
end
for i, kind in ipairs(protocol.SymbolKind) do
protocol.SymbolKind[i] = format(kind)
end
end
-- Helper data ================================================================
-- Module default config
H.default_config = MiniIcons.config
-- Cache tables organized to reduce memory footprint by reducing duplication:
-- - `cache` is nested and indexed by `category-name` pair with values being
-- number id in `cache_index`. Its purpose is to quickly get cache. Special
-- field `true` in each `category` table is made to contain an id of category
-- fallback icon data.
-- - `cache_index` is an array of "icon-hl-is_default" unique tables. Its
-- purpose is to store all unique return tuples per category.
-- - `cache_index_lookup` is nested and indexed by `hl-icon` with values being
-- number id in `cache_index`. Its purpose is to quickly add new "icon-hl"
-- tuple to cache.
H.cache = {}
H.cache_index = {}
H.cache_index_lookup = {}
-- Default icons per supported category
--stylua: ignore
H.default_icons = {
default = { glyph = '󰟢', hl = 'MiniIconsGrey' },
directory = { glyph = '󰉋', hl = 'MiniIconsAzure' },
extension = { glyph = '󰈔', hl = 'MiniIconsGrey' },
file = { glyph = '󰈔', hl = 'MiniIconsGrey' },
filetype = { glyph = '󰈔', hl = 'MiniIconsGrey' },
lsp = { glyph = '󰞋', hl = 'MiniIconsRed' },
os = { glyph = '󰟀', hl = 'MiniIconsPurple' },
}
-- Directory icons. Keys are some popular *language-agnostic* directory
-- basenames. Use only "folder-shaped" glyphs while prefering `nf-md-folder-*`
-- classes (unless glyph is designed specifically for the directory name)
--stylua: ignore
H.directory_icons = {
['.cache'] = { glyph = '󰪺', hl = 'MiniIconsCyan' },
['.config'] = { glyph = '󱁿', hl = 'MiniIconsCyan' },
['.git'] = { glyph = '', hl = 'MiniIconsOrange' },
['.github'] = { glyph = '', hl = 'MiniIconsAzure' },
['.local'] = { glyph = '󰉌', hl = 'MiniIconsCyan' },
['.vim'] = { glyph = '󰉋', hl = 'MiniIconsGreen' },
AppData = { glyph = '󰉌', hl = 'MiniIconsOrange' },
Applications = { glyph = '󱧺', hl = 'MiniIconsOrange' },
Desktop = { glyph = '󰚝', hl = 'MiniIconsOrange' },
Documents = { glyph = '󱧶', hl = 'MiniIconsOrange' },
Downloads = { glyph = '󰉍', hl = 'MiniIconsOrange' },
Favorites = { glyph = '󱃪', hl = 'MiniIconsOrange' },
Library = { glyph = '󰲂', hl = 'MiniIconsOrange' },
Music = { glyph = '󱍙', hl = 'MiniIconsOrange' },
Network = { glyph = '󰡰', hl = 'MiniIconsOrange' },
Pictures = { glyph = '󰉏', hl = 'MiniIconsOrange' },
ProgramData = { glyph = '󰉌', hl = 'MiniIconsOrange' },
Public = { glyph = '󱧰', hl = 'MiniIconsOrange' },
System = { glyph = '󱧼', hl = 'MiniIconsOrange' },
Templates = { glyph = '󱋣', hl = 'MiniIconsOrange' },
Trash = { glyph = '󱧴', hl = 'MiniIconsOrange' },
Users = { glyph = '󰉌', hl = 'MiniIconsOrange' },
Videos = { glyph = '󱞊', hl = 'MiniIconsOrange' },
Volumes = { glyph = '󰉓', hl = 'MiniIconsOrange' },
bin = { glyph = '󱧺', hl = 'MiniIconsYellow' },
build = { glyph = '󱧼', hl = 'MiniIconsGrey' },
boot = { glyph = '󰴋', hl = 'MiniIconsYellow' },
dev = { glyph = '󱧼', hl = 'MiniIconsYellow' },
doc = { glyph = '󱂷', hl = 'MiniIconsPurple' },
docs = { glyph = '󱂷', hl = 'MiniIconsPurple' },
etc = { glyph = '󱁿', hl = 'MiniIconsYellow' },
home = { glyph = '󱂵', hl = 'MiniIconsYellow' },
lib = { glyph = '󰲂', hl = 'MiniIconsYellow' },
media = { glyph = '󱧺', hl = 'MiniIconsYellow' },
mnt = { glyph = '󰉓', hl = 'MiniIconsYellow' },
['mini.nvim'] = { glyph = '󰚝', hl = 'MiniIconsRed' },
node_modules = { glyph = '', hl = 'MiniIconsGreen' },
nvim = { glyph = '󰉋', hl = 'MiniIconsGreen' },
opt = { glyph = '󰉗', hl = 'MiniIconsYellow' },
proc = { glyph = '󰢬', hl = 'MiniIconsYellow' },
root = { glyph = '󰷌', hl = 'MiniIconsYellow' },
sbin = { glyph = '󱧺', hl = 'MiniIconsYellow' },
src = { glyph = '󰴉', hl = 'MiniIconsPurple' },
srv = { glyph = '󱋣', hl = 'MiniIconsYellow' },
tmp = { glyph = '󰪺', hl = 'MiniIconsYellow' },
test = { glyph = '󱞊', hl = 'MiniIconsBlue' },
tests = { glyph = '󱞊', hl = 'MiniIconsBlue' },
usr = { glyph = '󰉌', hl = 'MiniIconsYellow' },
var = { glyph = '󱋣', hl = 'MiniIconsYellow' },
}
-- Extension icons
-- Value may be string with filetype's name to inherit from its icon data
--stylua: ignore
H.extension_icons = {
-- Extensions for which `vim.filetype.match()` mismatches or doesn't work.
-- Usually because matching depends on an actual buffer content.
h = { glyph = '󰫵', hl = 'MiniIconsPurple' },
ipynb = { glyph = '󰠮', hl = 'MiniIconsOrange' },
exs = { glyph = '', hl = 'MiniIconsPurple' },
purs = 'purescript',
tf = 'terraform',
-- Video
['3gp'] = { glyph = '󰈫', hl = 'MiniIconsYellow' },
avi = { glyph = '󰈫', hl = 'MiniIconsGrey' },
cast = { glyph = '󰈫', hl = 'MiniIconsRed' },
m4v = { glyph = '󰈫', hl = 'MiniIconsOrange' },
mkv = { glyph = '󰈫', hl = 'MiniIconsGreen' },
mov = { glyph = '󰈫', hl = 'MiniIconsCyan' },
mp4 = { glyph = '󰈫', hl = 'MiniIconsAzure' },
mpeg = { glyph = '󰈫', hl = 'MiniIconsPurple' },
mpg = { glyph = '󰈫', hl = 'MiniIconsPurple' },
webm = { glyph = '󰈫', hl = 'MiniIconsGrey' },
wmv = { glyph = '󰈫', hl = 'MiniIconsBlue' },
-- Audio
aac = { glyph = '󰈣', hl = 'MiniIconsYellow' },
aif = { glyph = '󰈣', hl = 'MiniIconsCyan' },
flac = { glyph = '󰈣', hl = 'MiniIconsOrange' },
m4a = { glyph = '󰈣', hl = 'MiniIconsPurple' },
mp3 = { glyph = '󰈣', hl = 'MiniIconsAzure' },
ogg = { glyph = '󰈣', hl = 'MiniIconsGrey' },
snd = { glyph = '󰈣', hl = 'MiniIconsRed' },
wav = { glyph = '󰈣', hl = 'MiniIconsGreen' },
wma = { glyph = '󰈣', hl = 'MiniIconsBlue' },
-- Image
bmp = { glyph = '󰈟', hl = 'MiniIconsGreen' },
eps = { glyph = '', hl = 'MiniIconsRed' },
gif = { glyph = '󰵸', hl = 'MiniIconsAzure' },
jpeg = { glyph = '󰈥', hl = 'MiniIconsOrange' },
jpg = { glyph = '󰈥', hl = 'MiniIconsOrange' },
png = { glyph = '󰸭', hl = 'MiniIconsPurple' },
tif = { glyph = '󰈟', hl = 'MiniIconsYellow' },
tiff = { glyph = '󰈟', hl = 'MiniIconsYellow' },
webp = { glyph = '󰈟', hl = 'MiniIconsBlue' },
-- Archives
['7z'] = { glyph = '󰗄', hl = 'MiniIconsBlue' },
bz = { glyph = '󰗄', hl = 'MiniIconsOrange' },
bz2 = { glyph = '󰗄', hl = 'MiniIconsOrange' },
bz3 = { glyph = '󰗄', hl = 'MiniIconsOrange' },
gz = { glyph = '󰗄', hl = 'MiniIconsGrey' },
rar = { glyph = '󰗄', hl = 'MiniIconsGreen' },
rpm = { glyph = '󰗄', hl = 'MiniIconsRed' },
sit = { glyph = '󰗄', hl = 'MiniIconsRed' },
tar = { glyph = '󰗄', hl = 'MiniIconsCyan' },
tgz = { glyph = '󰗄', hl = 'MiniIconsGrey' },
txz = { glyph = '󰗄', hl = 'MiniIconsPurple' },
xz = { glyph = '󰗄', hl = 'MiniIconsGreen' },
z = { glyph = '󰗄', hl = 'MiniIconsGrey' },
zip = { glyph = '󰗄', hl = 'MiniIconsAzure' },
zst = { glyph = '󰗄', hl = 'MiniIconsYellow' },
-- Software
doc = { glyph = '󱎒', hl = 'MiniIconsAzure' },
docm = { glyph = '󱎒', hl = 'MiniIconsAzure' },
docx = { glyph = '󱎒', hl = 'MiniIconsAzure' },
dot = { glyph = '󱎒', hl = 'MiniIconsAzure' },
dotx = { glyph = '󱎒', hl = 'MiniIconsAzure' },
exe = { glyph = '󰖳', hl = 'MiniIconsRed' },
pps = { glyph = '󱎐', hl = 'MiniIconsRed' },
ppsm = { glyph = '󱎐', hl = 'MiniIconsRed' },
ppsx = { glyph = '󱎐', hl = 'MiniIconsRed' },
ppt = { glyph = '󱎐', hl = 'MiniIconsRed' },
pptm = { glyph = '󱎐', hl = 'MiniIconsRed' },
pptx = { glyph = '󱎐', hl = 'MiniIconsRed' },
xls = { glyph = '󱎏', hl = 'MiniIconsGreen' },
xlsm = { glyph = '󱎏', hl = 'MiniIconsGreen' },
xlsx = { glyph = '󱎏', hl = 'MiniIconsGreen' },
xlt = { glyph = '󱎏', hl = 'MiniIconsGreen' },
xltm = { glyph = '󱎏', hl = 'MiniIconsGreen' },
xltx = { glyph = '󱎏', hl = 'MiniIconsGreen' },
['code-snippets'] = 'json',
}
-- File icons
-- Value may be string with filetype's name to inherit from its icon data
--stylua: ignore
H.file_icons = {
-- Popular special (mostly) language-agnostic file basenames
['.DS_Store'] = { glyph = '󰒓', hl = 'MiniIconsRed' },
['.bash_profile'] = { glyph = '󰒓', hl = 'MiniIconsGreen' },
['.bashrc'] = { glyph = '󰒓', hl = 'MiniIconsGreen' },
['.git'] = { glyph = '󰊢', hl = 'MiniIconsOrange' },
['.gitlab-ci.yml'] = { glyph = '󰮠', hl = 'MiniIconsOrange' },
['.gitkeep'] = { glyph = '󰊢', hl = 'MiniIconsRed' },
['.mailmap'] = { glyph = '󰊢', hl = 'MiniIconsCyan' },
['.npmignore'] = { glyph = '󰒓', hl = 'MiniIconsGrey' },
['.nvmrc'] = { glyph = '󰒓', hl = 'MiniIconsGreen' },
['.xinitrc'] = { glyph = '󰒓', hl = 'MiniIconsBlue' },
['.zshrc'] = { glyph = '󰒓', hl = 'MiniIconsGreen' },
CHANGELOG = { glyph = '󰉻', hl = 'MiniIconsBlue' },
['CHANGELOG.md'] = { glyph = '󰉻', hl = 'MiniIconsBlue' },
CODE_OF_CONDUCT = { glyph = '󱃱', hl = 'MiniIconsRed' },
['CODE_OF_CONDUCT.md'] = { glyph = '󱃱', hl = 'MiniIconsRed' },
CODEOWNERS = { glyph = '󰜻', hl = 'MiniIconsPurple' },
CONTRIBUTING = { glyph = '󰺾', hl = 'MiniIconsAzure' },
['CONTRIBUTING.md'] = { glyph = '󰺾', hl = 'MiniIconsAzure' },
['FUNDING.yml'] = { glyph = '󰇁', hl = 'MiniIconsGreen' },
LICENSE = { glyph = '', hl = 'MiniIconsCyan' },
['LICENSE.md'] = { glyph = '', hl = 'MiniIconsCyan' },
['LICENSE.txt'] = { glyph = '', hl = 'MiniIconsCyan' },
NEWS = { glyph = '󰎕', hl = 'MiniIconsBlue' },
['NEWS.md'] = { glyph = '󰎕', hl = 'MiniIconsBlue' },
PKGBUILD = { glyph = '󱁤', hl = 'MiniIconsPurple' },
README = { glyph = '', hl = 'MiniIconsYellow' },
['README.md'] = { glyph = '', hl = 'MiniIconsYellow' },
['README.txt'] = { glyph = '', hl = 'MiniIconsYellow' },
TODO = { glyph = '󰝖', hl = 'MiniIconsPurple' },
['TODO.md'] = { glyph = '󰝖', hl = 'MiniIconsPurple' },
['init.lua'] = { glyph = '', hl = 'MiniIconsGreen' },
-- Supported by `vim.filetype.match` but conflict with using extension first
['build.xml'] = 'ant',
['GNUmakefile.am'] = 'automake',
['Makefile.am'] = 'automake',
['makefile.am'] = 'automake',
['CMakeLists.txt'] = 'cmake',
['CMakeCache.txt'] = 'cmakecache',
['auto.master'] = 'conf',
['.oelint.cfg'] = 'dosini',
['.wakatime.cfg'] = 'dosini',
['pudb.cfg'] = 'dosini',
['setup.cfg'] = 'dosini',
['lltxxxxx.txt'] = 'gedcom',
['go.sum'] = 'gosum',
['go.work.sum'] = 'gosum',
['.indent.pro'] = 'indent',
['indent.pro'] = 'indent',
['ipf.rules'] = 'ipfilter',
['config.ld'] = 'lua',
['lynx.cfg'] = 'lynx',
['cm3.cfg'] = 'm3quake',
['maxima-init.mac'] = 'maxima',
['meson_options.txt'] = 'meson',
['.gitolite.rc'] = 'perl',
['example.gitolite.rc'] = 'perl',
['gitolite.rc'] = 'perl',
['main.cf.proto'] = 'pfmain',
['constraints.txt'] = 'requirements',
['requirements.txt'] = 'requirements',
['robots.txt'] = 'robots',
['tclsh.rc'] = 'tcl'
}
-- Filetype icons. Keys are filetypes explicitly supported by Neovim core
-- (i.e. present in `getcompletion('', 'filetype')` except technical ones)
-- and filetypes from some popular plugins.
-- Rough process of how glyphs and icons are chosen:
-- - Try to balance usage of highlight groups.
-- - Prefer using the following Nerd Fonts classes (from best to worst):
-- - `nf-md-*` (UTF codes seem to be more thought through). It is also
-- correctly has double width in Kitty.
-- - `nf-dev-*` (more supported devicons).
-- - `nf-seti-*` (more up to date extensions).
-- - If filetype is present in 'nvim-web-devicons', use highlight group with
-- most similar hue (based on OKLCH color space with equally spaced grid as
-- in 'mini.hues' and chroma=3 for grey cutoff; adjust manually if needed).
-- - Sets that have same/close glyphs but maybe different highlights:
-- - Generic configuration filetypes (".*conf.*", ".*rc", if stated in
-- filetype file description, etc.) have same glyph.
-- - Similar language: assembly ("asm"), SQL, Perl, HTML, CSV, shell.
-- - Log files.
-- - Make / build system.
-- - Related to Internet/Web.
-- - For newly assigned icons use semantically close (first by filetype origin,
-- then by name) abstract icons with `nf-md-*` Nerd Fonts class.
-- - If no semantically close abstract icon present, use plain letter/digit
-- icon (based on the first filetype character) with highlight groups picked
-- randomly to achieve overall balance (trying to minimize maximum number of
-- glyph-hl duplicates).
--stylua: ignore
H.filetype_icons = {
-- Neovim filetype plugins (i.e. recognized with vanilla Neovim)
['8th'] = { glyph = '󰭁', hl = 'MiniIconsYellow' },
a2ps = { glyph = '󰒓', hl = 'MiniIconsCyan' },
a65 = { glyph = '', hl = 'MiniIconsRed' },
aap = { glyph = '󰫮', hl = 'MiniIconsOrange' },
abap = { glyph = '󰫮', hl = 'MiniIconsGreen' },
abaqus = { glyph = '󰫮', hl = 'MiniIconsGreen' },
abc = { glyph = '󰝚', hl = 'MiniIconsAzure' },
abel = { glyph = '󰫮', hl = 'MiniIconsAzure' },
acedb = { glyph = '󰆼', hl = 'MiniIconsGrey' },
ada = { glyph = '󱁷', hl = 'MiniIconsAzure' },
aflex = { glyph = '󰫮', hl = 'MiniIconsCyan' },
ahdl = { glyph = '󰫮', hl = 'MiniIconsRed' },
aidl = { glyph = '󰫮', hl = 'MiniIconsYellow' },
alsaconf = { glyph = '󰒓', hl = 'MiniIconsPurple' },
amiga = { glyph = '󰫮', hl = 'MiniIconsCyan' },
aml = { glyph = '󰫮', hl = 'MiniIconsPurple' },
ampl = { glyph = '󰫮', hl = 'MiniIconsOrange' },
ant = { glyph = '󰫮', hl = 'MiniIconsRed' },
antlr = { glyph = '󰫮', hl = 'MiniIconsCyan' },
antlr4 = { glyph = '󰫮', hl = 'MiniIconsYellow' },
apache = { glyph = '󰒓', hl = 'MiniIconsGreen' },
apachestyle = { glyph = '󰒓', hl = 'MiniIconsGrey' },
applescript = { glyph = '󰀵', hl = 'MiniIconsYellow' },
aptconf = { glyph = '󰒓', hl = 'MiniIconsOrange' },
arch = { glyph = '󰣇', hl = 'MiniIconsBlue' },
arduino = { glyph = '', hl = 'MiniIconsAzure' },
art = { glyph = '󰫮', hl = 'MiniIconsPurple' },
asciidoc = { glyph = '󰪶', hl = 'MiniIconsYellow' },
asm = { glyph = '', hl = 'MiniIconsPurple' },
asm68k = { glyph = '', hl = 'MiniIconsRed' },
asmh8300 = { glyph = '', hl = 'MiniIconsOrange' },
asn = { glyph = '󰫮', hl = 'MiniIconsBlue' },
aspperl = { glyph = '', hl = 'MiniIconsBlue' },
aspvbs = { glyph = '󰫮', hl = 'MiniIconsGreen' },
asterisk = { glyph = '󰒓', hl = 'MiniIconsBlue' },
asteriskvm = { glyph = '󰒓', hl = 'MiniIconsGrey' },
astro = { glyph = '', hl = 'MiniIconsOrange' },
asy = { glyph = '󰫮', hl = 'MiniIconsAzure' },
atlas = { glyph = '󰫮', hl = 'MiniIconsAzure' },
authzed = { glyph = '󰫮', hl = 'MiniIconsYellow' },
autodoc = { glyph = '󰪶', hl = 'MiniIconsGreen' },
autohotkey = { glyph = '󰫮', hl = 'MiniIconsYellow' },
autoit = { glyph = '󰫮', hl = 'MiniIconsCyan' },
automake = { glyph = '󱁤', hl = 'MiniIconsPurple' },
ave = { glyph = '󰫮', hl = 'MiniIconsGrey' },
avra = { glyph = '', hl = 'MiniIconsPurple' },
awk = { glyph = '', hl = 'MiniIconsGrey' },
ayacc = { glyph = '󰫮', hl = 'MiniIconsCyan' },
b = { glyph = '󰫯', hl = 'MiniIconsYellow' },
baan = { glyph = '󰫯', hl = 'MiniIconsOrange' },
bash = { glyph = '', hl = 'MiniIconsGreen' },
basic = { glyph = '󰫯', hl = 'MiniIconsPurple' },
bass = { glyph = '󰋄', hl = 'MiniIconsBlue' },
bat = { glyph = '󰭟', hl = 'MiniIconsGrey' },
bc = { glyph = '󰫯', hl = 'MiniIconsCyan' },
bdf = { glyph = '󰛖', hl = 'MiniIconsRed' },
beancount = { glyph = '󰫯', hl = 'MiniIconsAzure' },
bib = { glyph = '󱉟', hl = 'MiniIconsYellow' },
bicep = { glyph = '', hl = 'MiniIconsCyan' },
bicepparam = { glyph = '', hl = 'MiniIconsPurple' },
bindzone = { glyph = '󰫯', hl = 'MiniIconsCyan' },
bitbake = { glyph = '󰃫', hl = 'MiniIconsOrange' },
blade = { glyph = '󰫐', hl = 'MiniIconsRed' },
0