From 7a65a3a313d17e25d372689c027b558c9cc07d54 Mon Sep 17 00:00:00 2001 From: Fasamii Date: Sat, 7 Feb 2026 15:41:38 +0100 Subject: Extended configuration options --- README.md | 153 ++++++++++++++++++++++++++++++++++++++------- lua/netrw-icons/init.lua | 156 ++++++++++++---------------------------------- lua/netrw-icons/parse.lua | 9 ++- 3 files changed, 175 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 94c7146..ccd226d 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,15 @@ # netrw-icons.nvim -An extension plugin for Neovim’s built-in `netrw` file explorer that adds: +A lightweight extension for Neovim's built-in `netrw` file explorer that adds file icons without replacing or modifying netrw's core functionality. - File and directory icons - LSP diagnostics indicators ## Features -- No replacement of `netrw` - pure extension -- File and directory icons inside `netrw` -- Supports multiple icon providers: - - `nvim-web-devicons` - - `mini.icons` -- LSP diagnostics integration +- **Icon support**: works with `nvim-web-devicons`, `mini.icons`, or manually specified via config +- **Customizable**: Override icons per file type or extension +- **Lightweight**: Minimal performance impact ## Requirements @@ -20,33 +17,141 @@ An extension plugin for Neovim’s built-in `netrw` file explorer that adds: - One of the following: - [`nvim-web-devicons`](https://github.com/nvim-tree/nvim-web-devicons) - [`mini.icons`](https://github.com/echasnovski/mini.nvim) -- Neovim built-in LSP (optional, for diagnostics) + ## Installation -Using `lazy.nvim`: +### Using [lazy.nvim](https://github.com/folke/lazy.nvim) ```lua { - "yourname/netrw-plus.nvim", + "Fasamii/netrw-icons.nvim", dependencies = { - "nvim-tree/nvim-web-devicons", -- or "nvim-mini/mini.icons", + "nvim-tree/nvim-web-devicons", -- or "echasnovski/mini.icons" }, config = function() - require("netrw-plus").setup({ - prefer = "devicons" -- if set to nil will detect automatically - - file = true, -- should display file icons - file_default = true, -- should use default icon for file + require("netrw-icons").setup() + end, +} +``` - dir = " ", -- directory icon set to false if none +### Using [packer.nvim](https://github.com/wbthomason/packer.nvim) - lsp = { -- which lsp diagnostics to display set lsp = false for none - info = false, - hint = false, - warn = true, - error = true, - } - }) +```lua +use { + "Fasamii/netrw-icons.nvim", + requires = { + "nvim-tree/nvim-web-devicons", -- or "echasnovski/mini.icons" + }, + config = function() + require("netrw-icons").setup() end, } +``` + +### Using [vim-plug](https://github.com/junegunn/vim-plug) + +```vim +Plug 'nvim-tree/nvim-web-devicons' " or 'echasnovski/mini.icons' +Plug 'Fasamii/netrw-icons.nvim' + +" In your init.vim or after plug#end() +lua require("netrw-icons").setup() +``` + + +## Configuration + +### Default Configuration + +```lua +require("netrw-icons").setup({ + -- Icon provider preference: "devicons", "miniicons", or nil for auto-detect + prefer = nil, + + -- Show generic file icon when no specific icon is found for a file type + icon_fallback = true, + + -- Icon definitions + file = { -- If you don't have any overrides you can just set to true + -- Custom icons per file extension + -- Can be a string (icon only) or a table { icon, highlight_group } + -- for example: lua = {"WOAH: ", "Function"}, + -- or lua = { "WOAH: " }, + + -- Reserved keys for special file types + dir = " ", -- Directory icon + sym = "", -- Symlink icon + exe = "", -- Executable icon + }, +}) +``` + +### Configuration Examples + +#### Minimal Setup + +```lua +require("netrw-icons").setup() +``` + +#### Prefer Specific Icon Provider + +```lua +require("netrw-icons").setup({ + prefer = "devicons", -- or "miniicons" +}) +``` + +#### Custom Icons + +```lua +require("netrw-icons").setup({ + file = { + dir = " ", + sym = " ", + exe = "EXEHERE: ", + + -- String format (icon only) + lua = "LUA ---->", + md = " ", + + -- Table format (icon + highlight group) + ts = { "󰛦 ", "Type" }, + }, +}) +``` + +#### Disable Default Icons + +```lua +require("netrw-icons").setup({ + icon_fallback = false, -- Only show icons for explicitly defined types found by provider or in + -- the file = {} table +}) +``` + +#### No Icons (Disable Plugin) + +```lua +require("netrw-icons").setup({ + file = false, -- Completely disable icons +}) +``` + +## Supported Netrw List Styles + +Currently, this plugin supports: +- **Style 3** (tree view): `let g:netrw_liststyle = 3` + +To enable tree view in netrw, add to your config: + +```vim +" In init.vim +let g:netrw_liststyle = 3 +``` + +```lua +-- In init.lua +vim.g.netrw_liststyle = 3 +``` diff --git a/lua/netrw-icons/init.lua b/lua/netrw-icons/init.lua index 9d7eec8..9262b4a 100644 --- a/lua/netrw-icons/init.lua +++ b/lua/netrw-icons/init.lua @@ -43,14 +43,14 @@ local function get_icon_from_provider(name) local provider = icon_provider.provider; local type = icon_provider.type; if type == "devicons" then - local symbol, hi = provider.get_icon(name, nil, { strict = true, default = M.options.file_default }); + local symbol, hi = provider.get_icon(name, nil, { strict = true, default = M.options.icon_fallback }); if symbol then return { symbol = symbol .. " ", hi = hi }; end elseif type == "miniicons" then local symbol, hi, is_default = provider.get("file", name) if symbol then - if is_default and not M.options.file_default then + if is_default and not M.options.icon_fallback then symbol = ""; end return { symbol = symbol .. " ", hi = hi }; @@ -61,83 +61,50 @@ local function get_icon_from_provider(name) return nil; end +local function get_icon_from_table(name, hi) + if M.options.file and type(M.options.file) == "table" then + local entry = M.options.file[name]; + if entry then + if type(entry) == "table" then + return { symbol = entry[1], hi = entry[2] } + else + if hi then + return { symbol = entry, hi = hi } + else + return { symbol = entry } + end + end + end + end +end local function get_icon(node) - if node.type == parse.TYPE_DIR and M.options.dir then - if M.options.dir then - return { symbol = M.options.dir, hi = "netrwDir" }; - end - elseif node.type == parse.TYPE_SYMLINK and M.options.sym then - if M.options.sym then - return { symbol = M.options.sym, hi = "netrwSymlink" }; - end - elseif node.type == parse.TYPE_FILE and M.options.file then - local file_type = vim.fn.fnamemodify(node.name, ":e"); - if string.sub(file_type, -1) == "*" then - return get_icon_from_provider("executable") + if node.type == parse.TYPE_DIR then + return get_icon_from_table("dir", "netrwDir"); + elseif node.type == parse.TYPE_SYMLINK then + return get_icon_from_table("sym", "netrwSymlink"); + elseif node.type == parse.TYPE_EXE then + return get_icon_from_table("exe", "netrwExe"); + else + if M.options.file then + local extension = vim.fn.fnamemodify(node.name, ":e"); + local from_table = get_icon_from_table(extension); + if from_table then + return from_table + else + return get_icon_from_provider(node.name); + end end - return get_icon_from_provider(node.name); end return nil; end --- local function get_lsp_diagnostics() --- local all_diagnostics = vim.diagnostic.get(nil); --- --- local file_diagnostics_map = {}; --- --- for _, diag in ipairs(all_diagnostics) do --- local diag_path = vim.api.nvim_buf_get_name(diag.bufnr); --- diag_path = vim.fn.fnamemodify(diag_path, ":p"); --- --- if not file_diagnostics_map[diag_path] then --- file_diagnostics_map[diag_path] = { info = 0, hint = 0, warn = 0, error = 0 }; --- end --- --- if diag.severity == vim.diagnostic.severity.ERROR and M.options.lsp.error then --- file_diagnostics_map[diag_path].error = file_diagnostics_map[diag_path].error + 1 --- elseif diag.severity == vim.diagnostic.severity.WARN and M.options.lsp.warn then --- file_diagnostics_map[diag_path].warn = file_diagnostics_map[diag_path].warn + 1 --- elseif diag.severity == vim.diagnostic.severity.INFO and M.options.lsp.info then --- file_diagnostics_map[diag_path].info = file_diagnostics_map[diag_path].info + 1 --- elseif diag.severity == vim.diagnostic.severity.HINT and M.options.lsp.hint then --- file_diagnostics_map[diag_path].hint = file_diagnostics_map[diag_path].hint + 1 --- end --- end --- --- return file_diagnostics_map; --- end - --- local function format_diagnostic(count, config, hi) --- if not config then --- return nil; --- end --- --- if count == 0 then --- return nil; --- end --- --- local prefix = ""; --- if type(config) == "string" then --- prefix = config; --- end --- --- return { (prefix .. tostring(count)), hi } --- end - - local function draw(bufnr) local namespace_icons = vim.api.nvim_create_namespace("netrw-icons") - -- local namespace_diagnostics = vim.api.nvim_create_namespace("netrw-diagnostics") local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) - -- local file_diagnostics_map = nil; - -- if M.options.lsp then - -- file_diagnostics_map = get_lsp_diagnostics(); - -- end - for i, line in ipairs(lines) do local node = parse.get_node(line) @@ -150,51 +117,12 @@ local function draw(bufnr) virt_text[2] = icon.hi; end - vim.api.nvim_buf_set_extmark(bufnr, namespace_icons, i - 1, node.icon, { id = i, virt_text_pos = "inline", virt_text = { virt_text }, }); end - - -- if M.options.lsp then - -- local diagnostics = nil; - -- - -- if file_diagnostics_map then - -- diagnostics = file_diagnostics_map[node.path]; - -- end - -- - -- if diagnostics then - -- local virt_text = { { " " } }; - -- local diag_items = { - -- { count = diagnostics.error, config = M.options.lsp.error, hl = "DiagnosticError" }, - -- { count = diagnostics.warn, config = M.options.lsp.warn, hl = "DiagnosticWarn" }, - -- { count = diagnostics.hint, config = M.options.lsp.hint, hl = "DiagnosticHint" }, - -- { count = diagnostics.info, config = M.options.lsp.info, hl = "DiagnosticInfo" }, - -- }; - -- - -- local has_diagnostics = false; - -- for _, item in ipairs(diag_items) do - -- local formated = format_diagnostic(item.count, item.config, item.hl); - -- if formated then - -- if has_diagnostics then - -- table.insert(virt_text, { " " }); - -- end - -- table.insert(virt_text, formated); - -- has_diagnostics = true; - -- end - -- end - -- - -- if has_diagnostics then - -- vim.api.nvim_buf_set_extmark(bufnr, namespace_diagnostics, i - 1, node.lsp, { - -- id = i, - -- virt_text_pos = "inline", - -- virt_text = virt_text, - -- }); - -- end - -- end - -- end end end end @@ -206,18 +134,14 @@ M.options = {} local default = { prefer = nil, - file = true, -- TODO: Accept table with extension -> icon mapping - file_default = true, - - dir = " ", - sym = " ", + icon_fallback = true, + file = { + dir = " ", + sym = " ", + exe = " ", - -- lsp = { - -- info = false, - -- hint = false, - -- warn = "W-", - -- error = "E-", - -- }, + py = { "", "Keyword" } + }, } ---@param options Config|nil diff --git a/lua/netrw-icons/parse.lua b/lua/netrw-icons/parse.lua index 911a1c6..5245645 100644 --- a/lua/netrw-icons/parse.lua +++ b/lua/netrw-icons/parse.lua @@ -10,7 +10,8 @@ local M = {} M.TYPE_DIR = 0 M.TYPE_FILE = 1 -M.TYPE_SYMLINK = 2 +M.TYPE_EXE = 2 +M.TYPE_SYMLINK = 3 ---@alias rwNode{name:string, icon:number, type:number} @@ -125,6 +126,10 @@ local parse_liststyle_3 = function(line) local name = content; + if name:sub(-1) == "*" then + type = M.TYPE_EXE; + end + local _, _, link, link_target = string.find(content, "^(.+)@\t%s*%-%->%s*(.+)") if link then type = M.TYPE_SYMLINK; @@ -138,9 +143,7 @@ local parse_liststyle_3 = function(line) return { name = name, - -- path = current_dir .. "/" .. name, icon = tree_end, - -- lsp = tree_end + #content, type = type, } end -- cgit v1.3