summaryrefslogtreecommitdiffstats
path: root/lua/netrw-icons/init.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/netrw-icons/init.lua')
-rw-r--r--lua/netrw-icons/init.lua167
1 files changed, 167 insertions, 0 deletions
diff --git a/lua/netrw-icons/init.lua b/lua/netrw-icons/init.lua
new file mode 100644
index 0000000..608d479
--- /dev/null
+++ b/lua/netrw-icons/init.lua
@@ -0,0 +1,167 @@
+-- SPDX-License-Identifier: MIT
+--
+-- Copyright (c) 2026 Mikołaj Kozłowski
+--
+-- Portions of this file are derived from:
+-- prichrd/netrw.nvim (MIT)
+-- https://github.com/prichrd/netrw.nvim
+
+local M = {}
+local parse = require("netrw.parse")
+
+local icon_provider = nil
+
+local function get_icon_provider(prefer)
+ local providers = {}
+
+ local has_devicons, devicons = pcall(require, "nvim-web-devicons")
+ if has_devicons then
+ providers.devicons = devicons
+ end
+
+ local has_miniicons, miniicons = pcall(require, "mini.icons")
+ if has_miniicons then
+ providers.miniicons = miniicons
+ end
+
+ if prefer and providers[prefer] then
+ return { type = prefer, provider = providers[prefer] }
+ end
+
+ if providers.miniicons then
+ return { type = "miniicons", provider = providers.miniicons }
+ elseif providers.devicons then
+ return { type = "devicons", provider = providers.devicons }
+ end
+
+ return nil
+end
+
+local function get_file_icon(node)
+ if not icon_provider then
+ return nil, nil
+ end
+
+ if icon_provider.type == "devicons" then
+ local icon, hl = icon_provider.provider.get_icon(node.node, nil, { strict = true, default = false })
+ return icon, hl
+ elseif icon_provider.type == "miniicons" then
+ local icon, hl = icon_provider.provider.get("file", node.node)
+ return icon, hl
+ end
+
+ return nil, nil
+end
+
+local function get_lsp_diagnostics(bufnr, node)
+ local diagnostics = {}
+ local filepath = node.dir .. "/" .. node.node
+
+ local diag = vim.diagnostic.get(nil, { path = filepath })
+
+ for _, d in ipairs(diag) do
+ if d.severity == vim.diagnostic.severity.ERROR and M.options.lsp.error then
+ table.insert(diagnostics, { icon = "E", hl = "DiagnosticError" })
+ elseif d.severity == vim.diagnostic.severity.WARN and M.options.lsp.warn then
+ table.insert(diagnostics, { icon = "W", hl = "DiagnosticWarn" })
+ elseif d.severity == vim.diagnostic.severity.INFO and M.options.lsp.info then
+ table.insert(diagnostics, { icon = "I", hl = "DiagnosticInfo" })
+ elseif d.severity == vim.diagnostic.severity.HINT and M.options.lsp.hint then
+ table.insert(diagnostics, { icon = "H", hl = "DiagnosticHint" })
+ end
+ end
+
+ return diagnostics
+end
+
+local function draw(bufnr)
+ local namespace = vim.api.nvim_create_namespace("netrw")
+ vim.api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
+
+ local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
+
+ for i, line in ipairs(lines) do
+ local node = parse.get_node(line)
+ if node then
+ -- Draw file/dir icon on the left
+ if (node.type == parse.TYPE_FILE and M.options.file) or
+ (node.type == parse.TYPE_DIR and M.options.dir) then
+ local icon, hl = get_file_icon(node)
+ if icon then
+ local opts = {
+ id = i * 2, -- Unique ID for icon
+ virt_text = hl and { { icon .. " ", hl } } or { { icon .. " " } },
+ virt_text_pos = "inline",
+ }
+ vim.api.nvim_buf_set_extmark(bufnr, namespace, i - 1, node.icon_col, opts)
+ end
+ end
+
+ -- Draw LSP diagnostics on the right
+ if node.type == parse.TYPE_FILE then
+ local diagnostics = get_lsp_diagnostics(bufnr, node)
+ if #diagnostics > 0 then
+ local virt_text = {}
+ for _, diag in ipairs(diagnostics) do
+ table.insert(virt_text, { " " .. diag.icon, diag.hl })
+ end
+
+ local opts = {
+ id = i * 2 + 1, -- Unique ID for LSP
+ virt_text = virt_text,
+ virt_text_pos = "inline",
+ }
+ vim.api.nvim_buf_set_extmark(bufnr, namespace, i - 1, node.lsp_col, opts)
+ end
+ end
+ end
+ end
+end
+
+--- @class Config
+M.options = {}
+
+--- @class Config
+local default = {
+ -- Preferred icon provider:
+ -- nil -> auto-detect
+ -- "miniicons" -> use mini.icons
+ -- "devicons" -> use nvim-web-devicons
+ prefer = nil,
+
+ -- Show icons for files
+ file = true,
+
+ -- Show icons for directories
+ dir = true,
+
+ -- LSP diagnostics integration
+ lsp = {
+ info = false,
+ hint = false,
+ warn = true,
+ error = true,
+ }
+}
+
+---@param options Config|nil
+function M.setup(options)
+ M.options = vim.tbl_deep_extend("force", {}, default, options or {})
+
+ if M.options.file or M.options.dir then
+ icon_provider = get_icon_provider(M.options.prefer)
+ end
+
+ vim.api.nvim_create_autocmd({ "BufEnter", "DiagnosticChanged" }, {
+ pattern = "*",
+ group = vim.api.nvim_create_augroup("netrw_icons", { clear = true }),
+ callback = function(args)
+ if vim.bo[args.buf].filetype ~= "netrw" then
+ return
+ end
+ draw(args.buf)
+ end
+ })
+end
+
+return M