Skip to content
cseickel edited this page Jan 27, 2022 · 49 revisions

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.

Commands

Open and Clear Search

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

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.

Harpoon Index

Neo-tree with harpoon index

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"},
           }
          }
        },
      })

Events

Auto Close on Open File

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
          },

        }
      })

Clear Search after Opening File

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
          },

        }
      })

Handle Rename or Move File Event

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
    },
  }
})

Custom Window Chooser for File Open commands

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
    },
  },
})
Clone this wiki locally