summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFasamii <fasami0512@gmail.com>2026-02-05 22:53:13 +0100
committerFasamii <fasami0512@gmail.com>2026-02-05 22:53:13 +0100
commitb415d15d49e78382cd53c36f786f7ff2a6a263f9 (patch)
tree419effe2323d99dc0b825a40b664fa17111c1a45
parentd8df2abe655ec2468bf0f6ab898dd909f8c73479 (diff)
downloadnetrw-icons.nvim-b415d15d49e78382cd53c36f786f7ff2a6a263f9.tar.gz
netrw-icons.nvim-b415d15d49e78382cd53c36f786f7ff2a6a263f9.tar.bz2
netrw-icons.nvim-b415d15d49e78382cd53c36f786f7ff2a6a263f9.tar.xz
netrw-icons.nvim-b415d15d49e78382cd53c36f786f7ff2a6a263f9.tar.zst
semi working demo
-rw-r--r--lua/netrw-icons/init.lua151
-rw-r--r--lua/netrw-icons/parse.lua130
2 files changed, 164 insertions, 117 deletions
diff --git a/lua/netrw-icons/init.lua b/lua/netrw-icons/init.lua
index 608d479..4f378a2 100644
--- a/lua/netrw-icons/init.lua
+++ b/lua/netrw-icons/init.lua
@@ -7,7 +7,8 @@
-- https://github.com/prichrd/netrw.nvim
local M = {}
-local parse = require("netrw.parse")
+
+local parse = require("netrw-icons.parse")
local icon_provider = nil
@@ -37,43 +38,69 @@ local function get_icon_provider(prefer)
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
+local function get_icon_from_provider(name)
+ if icon_provider then
+ 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 = false });
+ if symbol then
+ return { symbol = symbol, hi = hi };
+ end
+ elseif type == "miniicons" then
+ local symbol, hi = provider.get("file", name)
+ if symbol then
+ return { symbol = symbol, hi = hi };
+ end
+ end
end
- return nil, nil
+ return 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" })
+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 = "Normal" };
+ end
+ elseif node.type == parse.TYPE_SYMLINK and M.options.sym then
+ if M.options.sym then
+ return { symbol = M.options.sym, hi = "Normal" };
+ 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("exe");
end
+ return get_icon_from_provider(node.name);
end
- return diagnostics
+ return nil;
end
+-- local function get_lsp_diagnostics(node)
+-- local diagnostics = {}
+-- local filepath = node.dir .. "/" .. node.node
+--
+-- -- FIXME: that foo takes bufnr not path
+-- 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)
@@ -82,37 +109,18 @@ local function draw(bufnr)
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
+ -- vim.print("[" .. line .. "] - ");
+ -- vim.print(node);
- 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
+ if node then
+ local icon = get_icon(node);
+ if icon then
+ vim.api.nvim_buf_set_extmark(bufnr, namespace, i - 1, node.icon - 1, {
+ id = i,
+ virt_text_pos = "inline",
+ virt_text = { { " " .. icon.symbol, icon.hi } },
+ });
end
end
end
@@ -123,19 +131,10 @@ 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
+ dir = "",
+ sym = false,
lsp = {
info = false,
hint = false,
@@ -150,15 +149,23 @@ function M.setup(options)
if M.options.file or M.options.dir then
icon_provider = get_icon_provider(M.options.prefer)
+ if not icon_provider then
+ error("No icon provider found");
+ end
end
- vim.api.nvim_create_autocmd({ "BufEnter", "DiagnosticChanged" }, {
- pattern = "*",
- group = vim.api.nvim_create_augroup("netrw_icons", { clear = true }),
+ vim.api.nvim_create_autocmd("BufModifiedSet", {
+ pattern = { "*" },
+ group = vim.api.nvim_create_augroup("netrw_icons", { clear = false }),
callback = function(args)
- if vim.bo[args.buf].filetype ~= "netrw" then
+ if not (vim.bo and vim.bo.filetype == "netrw") then
+ return
+ end
+
+ if vim.b.netrw_liststyle ~= 0 and vim.b.netrw_liststyle ~= 1 and vim.b.netrw_liststyle ~= 3 then
return
end
+
draw(args.buf)
end
})
diff --git a/lua/netrw-icons/parse.lua b/lua/netrw-icons/parse.lua
index 61460a0..c2f245c 100644
--- a/lua/netrw-icons/parse.lua
+++ b/lua/netrw-icons/parse.lua
@@ -12,11 +12,11 @@ M.TYPE_DIR = 0
M.TYPE_FILE = 1
M.TYPE_SYMLINK = 2
----@alias Word {dir:string, node:string, link:string|nil, extension:string|nil, type:number, icon_col:number, name_col:number, lsp_col:number}
+---@alias PWord {dir:string, node:string, link:string|nil, extension:string|nil, type:number, icon_col:number, name_col:number, lsp_col:number}
---@param line string
---@param curdir string
----@return Word|nil
+---@return PWord|nil
local parse_liststyle_0 = function(line, curdir)
local _, _, node, link = string.find(line, "^(.+)@\t%s*%-%->%s*(.+)")
if node then
@@ -64,7 +64,7 @@ end
---@param line string
---@param curdir string
----@return Word|nil
+---@return PWord|nil
local parse_liststyle_1 = function(line, curdir)
local _, _, node, link = string.find(line, "^(.+)@%s+")
if node then
@@ -111,62 +111,102 @@ local parse_liststyle_1 = function(line, curdir)
end
---@param line string
----@return Word|nil
+---@return PWord|nil
local parse_liststyle_3 = function(line)
- local curdir = vim.b.netrw_curdir
- local _, to = string.find(line, "^[|%s]*")
- local pipelessLine = string.sub(line, to + 1, #line)
+ local current_dir = vim.b.netrw_curdir;
+ local type = M.TYPE_FILE;
- if pipelessLine == "" then
- return nil
- end
+ local _, tree_end = string.find(line, "^[|%s]*");
- local _, _, node, link = string.find(pipelessLine, "^(.+)@\t%s*%-%->%s*(.+)")
- if node then
- return {
- dir = curdir,
- icon_col = to,
- name_col = to,
- lsp_col = to + #node,
- node = node,
- extension = vim.fn.fnamemodify(node, ":e"),
- link = link,
- type = M.TYPE_SYMLINK,
- }
+ local content = string.sub(line, tree_end + 1, #line);
+ if content == "" then
+ return nil;
end
- local _, _, dir = string.find(pipelessLine, "^(.*)/")
- if dir then
- return {
- dir = curdir,
- icon_col = to,
- name_col = to,
- lsp_col = to + #dir + 1,
- node = dir,
- type = M.TYPE_DIR,
- }
+ local _, _, link, link_target = string.find(content, "^(.+)@\t%s*%-%->%s*(.+)")
+ if link then
+ type = M.TYPE_SYMLINK;
end
- local ext = vim.fn.fnamemodify(pipelessLine, ":e")
- local clean_line = pipelessLine
- if string.sub(ext, -1) == "*" then
- ext = string.sub(ext, 1, -2)
- clean_line = string.sub(pipelessLine, 1, -2)
+ local _, _, dir = string.find(content, "^(.*)/")
+ if dir then
+ type = M.TYPE_DIR;
end
return {
- dir = curdir,
- icon_col = to,
- name_col = to,
- lsp_col = to + #clean_line,
- node = clean_line,
- extension = ext,
- type = M.TYPE_FILE,
+ name = link_target or content,
+ icon = tree_end,
+ type = type,
}
end
+
+
+
+-- local _, to = string.find(line, "^[|%s]*")
+-- if to ~= 0 then
+-- error("to: " .. to);
+-- end
+-- local pipelessLine = string.sub(line, to + 1, #line)
+--
+-- if pipelessLine == "" then
+-- return nil
+-- end
+--
+-- local _, _, node, link = string.find(pipelessLine, "^(.+)@\t%s*%-%->%s*(.+)")
+-- if node then
+-- return {
+-- dir = curdir,
+-- icon_col = to,
+-- name_col = to,
+-- lsp_col = to + #node,
+-- node = node,
+-- extension = vim.fn.fnamemodify(node, ":e"),
+-- link = link,
+-- type = M.TYPE_SYMLINK,
+-- }
+-- end
+--
+-- local _, _, dir = string.find(pipelessLine, "^(.*)/")
+-- if dir then
+-- return {
+-- dir = curdir,
+-- icon_col = to,
+-- name_col = to,
+-- lsp_col = to + #dir + 1,
+-- node = dir,
+-- type = M.TYPE_DIR,
+-- }
+-- end
+--
+-- local ext = vim.fn.fnamemodify(pipelessLine, ":e")
+-- local clean_line = pipelessLine
+-- if string.sub(ext, -1) == "*" then
+-- ext = string.sub(ext, 1, -2)
+-- clean_line = string.sub(pipelessLine, 1, -2)
+-- end
+--
+-- return {
+-- current_dir = vim.b.netrw_curdir,
+-- icon_col = to,
+-- name_col = to,
+-- lsp_col = to + #clean_line,
+-- node = clean_line,
+-- extension = ext,
+-- type = M.TYPE_FILE,
+-- }
+
+-- return {
+-- name = "name of the file",
+-- type = "type of the netrw element (dir, file, symlink)"
+-- path = "full path of the file",
+-- icon = "character after the | netrw symbol",
+-- lsp = "two characters after the filename end",
+-- }
+-- end
+
---@param line string
----@return Word|nil
+---@return PWord|nil
M.get_node = function(line)
if string.find(line, '^"') then
return nil