NVIM v0.10.2 Build type: Release LuaJIT 2.1.1713484068 Run "nvim -V1 -v" for more info
Operating System / Version
macos 15.0
Describe the Bug
theres a drop shadow along the edge which flickers when used with edgy.nvim
Screenshots, Traceback
Steps to Reproduce
Not actually sure what causes it, think its a win highlight and removing local highlights does nothing.
Expected Behavior
No drop shadow
Your Configuration
local M = {}
local git_utils = require("utils.git")
function M.set_neo_tree_root(new_root)
if new_root then
local neo_tree_loaded, _ = pcall(require, "neo-tree")
if neo_tree_loaded then
local manager = require("neo-tree.sources.manager")
local renderer = require("neo-tree.ui.renderer")
-- Check if the root has changed
local current_state = manager.get_state("filesystem")
if current_state and current_state.path == new_root then
-- Root hasn't changed, no need to update
return
end
-- Update the root for all tabs
for _, tabpage in ipairs(vim.api.nvim_list_tabpages()) do
local state = manager.get_state("filesystem", tabpage)
if state and state.path ~= new_root then
state.path = new_root
state.dirty = true
end
end
-- Refresh Neo-tree if it's visible in the current tab
local current_tabpage = vim.api.nvim_get_current_tabpage()
local state = manager.get_state("filesystem", current_tabpage)
if state and renderer.window_exists(state) and state.path ~= new_root then
manager.navigate("filesystem", new_root)
end
vim.g.cached_lsp_root = new_root
print("Neo-tree root set to: " .. new_root)
else
print("Neo-tree is not loaded")
end
end
end
local augroup = vim.api.nvim_create_augroup("TabGroupSwitch", { clear = true })
vim.api.nvim_create_autocmd("TabEnter", {
group = augroup,
callback = function()
vim.schedule(function()
if vim.g.cached_lsp_root then
M.set_neo_tree_root(vim.g.cached_lsp_root)
end
end)
end,
})
M.neo_tree = function()
local icons = require("core.ui.icons")
-- Helper function to check if a path is excluded
local function is_path_excluded(path, exclusions)
for _, exclusion in ipairs(exclusions) do
-- Trim whitespace and remove trailing slash if present
local pattern = exclusion:match("^%s*(.-)%s*/?$")
-- Escape all special regex characters
pattern = pattern:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")
-- Replace escaped '*' with '.-' for wildcard matching
pattern = pattern:gsub("%%%*", ".-")
-- Check if the pattern matches the full path (for absolute path patterns)
if pattern:sub(1, 2) == "%/" then
if path:match("^" .. pattern .. "$") then
return true
end
else
-- For relative patterns, match against path segments
local segments = {}
for segment in path:gmatch("[^/]+") do
table.insert(segments, segment)
end
-- Check if the pattern matches any complete segment
for i = #segments, 1, -1 do
if segments[i]:match("^" .. pattern .. "$") then
return true
end
end
end
end
return false
end
local windows_bindings = {
["zO"] = "expand_all_nodes",
["zC"] = "close_all_nodes",
["zZ"] = "toggle_auto_expand_width",
["zz"] = {
"toggle_node",
},
["<C-w>s"] = "open_split",
["<C-w>v"] = "open_vsplit",
["<C-w>T"] = "open_tabnew",
["<C-w>p"] = "open_with_window_picker",
["<M-y>"] = "copy_path_from_content_root",
["e"] = false,
["z"] = false,
["<Leader>"] = false,
["<M-u>"] = "refresh",
["<M-f>"] = "live_grep_at_path",
["<M-d>"] = "diffview_node",
["<M-g>"] = "lazy_git_at_path",
["<M-e>"] = "explorer_at_path",
["<M-o>"] = "telescope_find_and_open_file",
["<M-r>"] = "grug_replace",
["<M-t>"] = "open_in_terminal",
["E"] = "toggle_exclude_item",
["[g"] = "prev_git_modified",
["]g"] = "next_git_modified",
["_"] = "reset_root_to_lsp_common",
}
local user_exclusions = require("neoconf").get("exclusions")
local permanent_exclusions = require("utils.files").lua_converted_exclusion_patterns
local function custom_renderer(config, node, state)
local name = node.name
local path = node:get_id()
-- Check if the node is excluded or filtered
local is_user_excluded = is_path_excluded(path, user_exclusions)
local is_permanent_excluded = is_path_excluded(path, permanent_exclusions)
local is_filtered = node.filtered_by and next(node.filtered_by) ~= nil
-- Apply custom highlight if excluded or filtered
if is_permanent_excluded then
return {
{
text = name,
highlight = "NeoTreePermanentExcludedFileName",
},
}
elseif is_user_excluded or is_filtered then
return {
{
text = name,
highlight = "NeoTreeExcludedFileName",
},
}
end
-- Use the default renderer for non-excluded and non-filtered nodes
local default_renderer = require("neo-tree.sources.common.components").name
local default_result = default_renderer(config, node, state)
-- Ensure we're returning a table to prevent potential issues
if type(default_result) ~= "table" then
return { { text = tostring(default_result), highlight = "NeoTreeFileName" } }
end
return default_result
end
-- Update the toggle_exclude_item function
local function toggle_exclude_item(state)
local node = state.tree:get_node()
local path = node:get_id()
local is_permanent_excluded = is_path_excluded(path, permanent_exclusions)
if is_permanent_excluded then
vim.notify("Permanent exclusion found at " .. tostring(path), vim.log.levels.WARN)
return
end
require("utils.settings").toggle_string_in_table(path, "exclusions")
print("Toggle exclude item at " .. tostring(path))
pcall(function()
vim.cmd("Neotree close")
end)
vim.defer_fn(function()
require("neoconf.settings").refresh()
pcall(function()
vim.cmd("Lazy reload neo-tree.nvim")
end)
end, 100)
end
local event_handlers = {
{
event = "vim_buffer_changed",
handler = function(_)
vim.schedule(function()
if vim.g.cached_lsp_root then
M.set_neo_tree_root(vim.g.cached_lsp_root)
end
end)
end,
},
{
event = "neo_tree_buffer_enter",
handler = function(_)
vim.schedule(function()
vim.wo.statuscolumn = " "
end)
end,
},
{
event = "neo_tree_window_before_open",
handler = function(_) end,
},
{
event = "neo_tree_window_after_close",
handler = function(args)
if args.position == "left" or args.position == "right" then
vim.cmd("wincmd =")
end
end,
},
{
event = "neo_tree_window_after_open",
handler = function(args)
if args.position == "left" or args.position == "right" then
vim.cmd("wincmd =")
end
vim.schedule(function()
vim.wo.statuscolumn = " "
-- vim.g.minianimate_disable = false
end)
end,
},
{
event = "file_opened",
handler = function(file_path)
-- auto close
require("neo-tree.command").execute({ action = "close" })
end,
},
{
event = "neo_tree_buffer_leave",
handler = function()
local shown_buffers = {}
for _, win in ipairs(vim.api.nvim_list_wins()) do
shown_buffers[vim.api.nvim_win_get_buf(win)] = true
end
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if
not shown_buffers[buf]
and vim.api.nvim_buf_get_option(buf, "buftype") == "nofile"
and vim.api.nvim_buf_get_option(buf, "filetype") == "neo-tree"
then
vim.api.nvim_buf_delete(buf, {})
end
end
end,
},
}
local filesystem_commands = {
telescope_find_and_open_file = function(state)
local node = state.tree:get_node()
local path = node:get_id()
-- Check if the path is a file or a directory
local is_file = vim.fn.filereadable(path) == 1
-- If it's a file, get the parent directory
if is_file then
path = vim.fn.fnamemodify(path, ":h")
end
require("utils.telescope_utils").find_files({
paths = {
path,
},
cwd = path,
})
print("Searching for files in " .. tostring(path))
end,
copy_path_from_content_root = function(state)
local node = state.tree:get_node()
local absolute_path = node:get_id()
vim.ui.select({ "Absolute Path", "Relative Path" }, {
prompt = "Select path type to copy:",
format_item = function(item)
return item
end,
}, function(choice)
local result
if choice == "Absolute Path" then
result = absolute_path
else
-- Get the git root directory
local git_root = vim.fn.systemlist(
"git -C " .. vim.fn.escape(vim.fn.fnamemodify(absolute_path, ":h"), " ") .. " rev-parse --show-toplevel"
)[1]
if git_root and git_root ~= "" then
-- File is in a git repository
result = vim.fn.fnamemodify(absolute_path, ":p"):gsub(git_root .. "/", "")
else
-- File is not in a git repository, use full path
result = vim.fn.fnamemodify(absolute_path, ":p")
end
end
-- Copy the result to the clipboard
vim.fn.setreg("+", result)
-- Print a message to confirm the action
print("Copied to clipboard: " .. result)
end)
end,
live_grep_at_path = function(state)
local node = state.tree:get_node()
local path = node:get_id()
local exclusions = require("utils.files").get_rg_exclusions()
require("telescope").extensions.egrepify.search_given_files({ exclusions = exclusions, search_dirs = { path } })
print("Searching in " .. tostring(path))
end,
lazy_git_at_path = function(state)
local node = state.tree:get_node()
local path = node:get_id()
-- Use git_utils to find the closest Git directory
local git_dir = git_utils.get_closest_git_dir_to(path)
if git_dir then
require("lazygit").lazygit(git_dir)
print("Lazygit opened at " .. tostring(git_dir))
else
print("No Git repository found. Using the original path.")
require("lazygit").lazygit(path)
print("Lazygit opened at " .. tostring(path))
end
end,
explorer_at_path = function(state)
local node = state.tree:get_node()
local path = node:get_id()
require("yazi").yazi(nil, path)
print("Opening explorer at " .. tostring(path))
end,
diffview_node = function(state)
local node = state.tree:get_node()
local path = node:get_id()
-- Ensure we have a valid path
if not path then
print("Error: Unable to get path from node")
return
end
-- Get the full absolute path
local full_path = vim.fn.fnamemodify(path, ":p")
-- Check if the path exists
if vim.fn.isdirectory(full_path) == 1 or vim.fn.filereadable(full_path) == 1 then
-- Construct the DiffviewFileHistory command
local cmd = string.format("DiffviewFileHistory %s", vim.fn.fnameescape(full_path))
-- Execute the Diffview command
vim.cmd(cmd)
print("Opening Diffview File History for: " .. full_path)
else
print("Path does not exist or is not accessible: " .. full_path)
end
end,
grug_replace = function(state)
local node = state.tree:get_node()
local path = node:get_id()
vim.cmd(":Neotree close")
-- Check if the path is a file or directory
local is_single = false
local is_file = vim.fn.filereadable(path) == 1
local is_directory = vim.fn.isdirectory(path) == 1
if is_file then
is_single = true
elseif is_directory then
is_single = false
end
require("utils.search_utils").grug_search({
default_text = "",
paths = { path },
single_file_mode = is_single,
})
print("Replacing in " .. (is_single and "file: " or "directory: ") .. tostring(path))
end,
open_in_terminal = function(state)
local toggleterm = require("toggleterm")
local node = state.tree:get_node()
local path = node:get_id()
-- Use vim.fn.shellescape to properly escape the path
local escaped_path = vim.fn.shellescape(path)
-- Construct the command
local cmd = string.format("cd %s", escaped_path)
-- Use the toggleterm API to execute the command
toggleterm.exec(cmd, 99)
-- Focus the terminal
require("utils.terminal").focus_main_term()
-- Enter insert mode
vim.schedule(function()
vim.cmd("startinsert")
end)
print("Opening terminal in " .. tostring(path))
end,
toggle_exclude_item = toggle_exclude_item,
reset_root_to_lsp_common = require("utils.lsp").set_neo_tree_dir_to_lsp_common_root,
}
local full_opts = {
hide_root_node = true,
retain_hidden_root_indent = true,
sort_case_insensitive = true,
open_files_do_not_replace_types = { "terminal", "Trouble", "qf", "edgy", "neo-tree" },
use_popups_for_input = false,
popup_border_style = "single",
enable_git_status = false,
enable_diagnostics = false,
auto_clean_after_session_restore = true,
sources = {
"filesystem",
-- "buffers",
-- "git_status",
--"document_symbols",
},
event_handlers = event_handlers,
source_selector = {
winbar = true,
separator = "",
content_layout = "center",
sources = {
{
source = "filesystem",
display_name = icons.common.folder .. " DIR ",
},
-- {
-- source = "buffers",
-- display_name = icons.common.buffer .. " BUF ",
-- },
-- {
-- source = "git_status",
-- display_name = icons.common.git .. " GIT ",
-- },
-- {
-- source = "document_symbols",
-- display_name = icons.lsp.Module .. " DOC ",
-- },
},
},
default_component_configs = {
container = {
enable_character_fade = true,
},
indent = {
with_markers = false,
with_expanders = true,
expander_collapsed = "",
expander_expanded = "",
},
icon = {
folder_closed = icons.common.folder_close,
folder_open = icons.common.folder_open,
folder_empty = icons.common.folder_empty,
highlight = "NeoTreeFileIcon",
},
modified = {
symbol = icons.common.dot,
},
git_status = {
symbols = icons.git_status,
align = "right",
},
name = {
use_git_status_colors = false,
highlight = "NeoTreeFileName",
},
},
window = {
position = "left",
width = 40,
},
filesystem = {
components = {
name = custom_renderer,
},
window = {
mappings = windows_bindings,
},
commands = filesystem_commands,
bind_to_cwd = false,
-- netrw disabled, opening a directory opens neo-tree
-- in whatever position is specified in window.position
-- "open_current", -- netrw disabled, opening a directory opens within the
-- window like netrw would, regardless of window.position
-- "disabled", -- netrw left alone, neo-tree does not handle opening dirs
-- hijack_netrw_behavior = "disabled",
follow_current_file = {
enabled = true,
leave_dirs_open = true,
},
filtered_items = {
hide_dotfiles = false,
hide_gitignored = true,
hide_by_name = {
".git",
".idea",
".DS_Store",
},
always_show = {
".nvim.json",
},
show_hidden_count = false,
never_show = {
".DS_Store",
},
},
use_libuv_file_watcher = not _G.__os.is_windows,
},
diagnostics = {
autopreview = false,
autopreview_config = {},
autopreview_event = "neo_tree_buffer_enter",
bind_to_cwd = true,
diag_sort_function = "severity",
follow_behavior = {
always_focus_file = true,
expand_followed = true,
collapse_others = true,
},
follow_current_file = false,
group_dirs_and_files = true,
group_empty_dirs = true,
show_unloaded = true,
},
git_status = {
indent = {
padding = 0,
},
},
-- nesting_rules = require("neotree-file-nesting-config").nesting_rules,
}
return full_opts
end
M.neo_tree_setup = function()
require("neo-tree").setup(M.neo_tree())
end
return M
Did you check docs and existing issues?
Neovim Version (nvim -v)
NVIM v0.10.2 Build type: Release LuaJIT 2.1.1713484068 Run "nvim -V1 -v" for more info
Operating System / Version
macos 15.0
Describe the Bug
theres a drop shadow along the edge which flickers when used with edgy.nvim
Screenshots, Traceback
Steps to Reproduce
Not actually sure what causes it, think its a win highlight and removing local highlights does nothing.
Expected Behavior
No drop shadow
Your Configuration