Skip to content
cseickel edited this page Jan 23, 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,
          }
        }
      })

Custom Callback after Rename

If you want to take some custom action after a file has been renamed, you can override the built-in rename command in your config and add your code to the callback provided for that action. The most obvious use for this would be to cleanup references to that file within your project.

      require("neo-tree").setup({
        filesystem = {
          commands = {
            rename = function(state)
              local cc = require("neo-tree.sources.common.commands")
              local fs = require("neo-tree.sources.filesystem")
              cc.rename(state, function(original_path, new_path)
                -- This is where you would do something like fix references to the file
                -- with an LSP server.
                -- <YOUR CODE HERE>
                print("MY CUSTOM CODE: Renamed " .. original_path .. " to " .. new_path)
                -- Don't forget to call fs.refresh() after you're done.
                fs.refresh()
              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
          },

        }
      })

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