-
Notifications
You must be signed in to change notification settings - Fork 258
Recipes
Welcome to the neo-tree.nvim wiki!
This is a place to share configuration recipes for functionality that others may want to copy or learn from.
Sometimes you may want to add a filter and leave that way because the filter captures the files you want to work on now. Other times you may just be using the filter as a quick way to find a file you want to open. In the latter case, you may want to clear the search when you open that file. This custom command offers that choice:
require("neo-tree").setup({
popup_border_style = "NC",
filesystem = {
window = {
mappings = {
["o"] = "open_and_clear_filter"
},
},
commands = {
open_and_clear_filter = function (state)
local node = state.tree:get_node()
if node and node.type == "file" then
local file_path = node:get_id()
-- reuse built-in commands to open and clear filter
local cmds = require("neo-tree.sources.filesystem.commands")
cmds.open(state)
cmds.clear_filter(state)
-- reveal the selected file without focusing the tree
require("neo-tree.sources.filesystem").navigate(state.path, file_path)
end
end,
}
}
})
Components are the blocks of text that get rendered for an item in the tree. Built-in components include things like "icon", "name", or "git_status". Adding a custom component involves two steps: defining a function to implement that component, and then using that component in a renderer.
If you want to override any built-in component, just add a component in your config with the same name. The example below is copied from the default icon component, which you can override to add your own special handling.
If you want to add custom icons based on a file or directory name, you can access a node's name with node.name
, and the full path with node.get_id()
or node.path
.
require("neo-tree").setup({
filesystem = {
components = {
icon = function(config, node, state)
local icon = config.default or " "
local padding = config.padding or " "
local highlight = config.highlight or highlights.FILE_ICON
if node.type == "directory" then
highlight = highlights.DIRECTORY_ICON
if node:is_expanded() then
icon = config.folder_open or "-"
else
icon = config.folder_closed or "+"
end
elseif node.type == "file" then
local success, web_devicons = pcall(require, "nvim-web-devicons")
if success then
local devicon, hl = web_devicons.get_icon(node.name, node.ext)
icon = devicon or icon
highlight = hl or highlight
end
end
return {
text = icon .. padding,
highlight = highlight,
}
end,
})
This example adds the index number of a file that has been marked with Harpoon:
require("neo-tree").setup({
filesystem = {
components = {
harpoon_index = function(config, node, state)
local Marked = require("harpoon.mark")
local path = node:get_id()
local succuss, index = pcall(Marked.get_index_of, path)
if succuss and index and index > 0 then
return {
text = string.format(" ⥤ %d", index), -- <-- Add your favorite harpoon like arrow here
highlight = config.highlight or "NeoTreeDirectoryIcon",
}
else
return {}
end
end
},
renderers = {
file = {
{"icon"},
{"name", use_git_status_colors = true},
{"harpoon_index"}, --> This is what actually adds the component in where you want it
{"diagnostics"},
{"git_status", highlight = "NeoTreeDimText"},
}
}
},
})
This example uses the file_open
event to close the Neo-tree window when a file is opened. This applies to all windows and all sources at once.
require("neo-tree").setup({
event_handlers = {
{
event = "file_opened",
handler = function(file_path)
--auto close
require("neo-tree").close_all()
end
},
}
})
If you want to use the search feature as a fuzzy finder rather than a sticky filter, you may want to clear the search as soon as a file is chosen. One way to handle that was shown above with a custom command, but you could also handle that in a more universal way by handling the "file_opened" event:
require("neo-tree").setup({
event_handlers = {
{
event = "file_opened",
handler = function(file_path)
require("neo-tree.sources.filesystem").reset_search()
end
},
}
})
If you want to take some custom action after a file has been renamed, you can handle the "file_renamed"
in your config and add your code to the handler. The most obvious use for this would be to cleanup references to that file within your project.
require("neo-tree").setup({
events = {
{
event = "file_renamed",
handler = function(args)
-- fix references to file
print(args.source, " renamed to ", args.destination)
end
},
{
event = "file_moved",
handler = function(args)
-- fix references to file
print(args.source, " moved to ", args.destination)
end
},
}
})
If you want to change the logic for where to open a file when using the built-in "open"
, "open_split"
, and "open_vsplit"
commands, the way to do that is by handling the "file_open_requested" event. Below is an example which includes the default logic used by Neo-tree.
NOTE: If you do open the file successfully, you must return { handled = true }
to prevent the next handler from opening the file again. If there are situations where you do want to pass it back to the built-in logic to be handled, return { handled = false }
.
"neo-tree").setup({
event_handlers = {
{
event = "file_open_requested",
handler = function(args)
local state = args.state
local path = args.path
local open_cmd = args.open_cmd or "edit"
-- use last window if possible
local suitable_window_found = false
local nt = require("neo-tree")
if nt.config.open_files_in_last_window then
local prior_window = nt.get_prior_window()
if prior_window > 0 then
local success = pcall(vim.api.nvim_set_current_win, prior_window)
if success then
suitable_window_found = true
end
end
end
-- find a suitable window to open the file in
if not suitable_window_found then
if state.window.position == "right" then
vim.cmd("wincmd t")
else
vim.cmd("wincmd w")
end
end
local attempts = 0
while attempts < 4 and vim.bo.filetype == "neo-tree" do
attempts = attempts + 1
vim.cmd("wincmd w")
end
if vim.bo.filetype == "neo-tree" then
-- Neo-tree must be the only window, restore it's status as a sidebar
local winid = vim.api.nvim_get_current_win()
local width = require("neo-tree.utils").get_value(state, "window.width", 40)
vim.cmd("vsplit " .. path)
vim.api.nvim_win_set_width(winid, width)
else
vim.cmd(open_cmd .. " " .. path)
end
-- If you don't return this, it will proceed to open the file using built-in logic.
return { handled = true }
end
},
},
})