Skip to content

Previous window is not selected unless :NvimTreeFocus is used #2262

@zhimsel

Description

@zhimsel
Contributor

Description

From #1985 (comment)

Is there really no way to open to the window that was previously active before selecting the nvim-tree window (regardless on navigation method)?

I have the same problem as @paulrouget, however I often use the mouse to start interacting with nvim-tree (to open a file, for instance). If I don't use :NvimTreeFocus, then it opens the file in the last window to have previously used :NvimTreeFocus (or presumably have been created by nvim-tree).

Would it be possible to use the lua equivalent of :winnr(#) (if it exists)?

Would it be possible to track the previous window by an event that fires every time you leave a window? Like maybe the WinLeave autocmd event? We could add another WinLeave autocmd similar to the one defined here, but using a negated pattern to ignore unwanted buffers like NvimTree_*.


TL;DR

This plugin can only track the "previous active window" when it's focused via :NvimTreeFocus. If the nvim-tree is focused by any other method, it will still refer to the window where :NvimTreeFocus was lat called, not the actual last window.

Neovim version

NVIM v0.9.0
Build type: Release
LuaJIT 2.1.0-beta3

Operating system and version

Linux 6.2.12-zen1-1-zen, MacOS 13.4

nvim-tree version

Latest master (0345117 as of testing)

Minimal config

vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1

vim.cmd [[set runtimepath=$VIMRUNTIME]]
vim.cmd [[set packpath=/tmp/nvt-min/site]]
local package_root = "/tmp/nvt-min/site/pack"
local install_path = package_root .. "/packer/start/packer.nvim"
local function load_plugins()
  require("packer").startup {
    {
      "wbthomason/packer.nvim",
      "nvim-tree/nvim-tree.lua",
      "nvim-tree/nvim-web-devicons",
      -- ADD PLUGINS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE
    },
    config = {
      package_root = package_root,
      compile_path = install_path .. "/plugin/packer_compiled.lua",
      display = { non_interactive = true },
    },
  }
end
if vim.fn.isdirectory(install_path) == 0 then
  print "Installing nvim-tree and dependencies."
  vim.fn.system { "git", "clone", "--depth=1", "https://github.com/wbthomason/packer.nvim", install_path }
end
load_plugins()
require("packer").sync()
vim.cmd [[autocmd User PackerComplete ++once echo "Ready!" | lua setup()]]
vim.opt.termguicolors = true
vim.opt.cursorline = true

-- MODIFY NVIM-TREE SETTINGS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE
_G.setup = function()
  require("nvim-tree").setup({
    actions = {
      open_file = {
        window_picker = {
          enable = false
        },
      },
    },
  })
end

Steps to reproduce

Setup

Open nvim-tree and open at least 2 files in splits (vertical/horizontal doesn't seem to matter). In this example I'll open file1, file2, and file3 in vertical splits in order (1 on the left, 3 on the right).

  1. nvim -nu /tmp/nvt-min.lua
  2. :NvimTreeOpen
  3. Select file1 and press <C-v>
  4. :NvimTreeFocus
  5. Select file2 and press <C-v>
  6. :NvimTreeFocus
  7. Select file3 and press <C-v>

The bug

  1. With window 3 selected (as it should be after the last step above), focus nvim-tree with :NvimTreeFocus
  2. Open another file with <CR>. The file opens in window 3, as it was the last window selected.
  3. Focus window 1 (with file1 open) with any method of your choice (mouse, <C-w>h, whatever)
  4. Focus nvim-tree this time with a method that doesn't involve calling :NvimTreeFocus, like clicking the window with the mouse, or using <C-w>h to move the cursor to the nvim-tree window.
  5. Open a file that is not currently open in a window with <CR>

Expected behavior

I would expect the file to be opened in window 1 (where file1 used to be), as it was the last window selected.

Actual behavior

The file is opened in window 3 (where file3 was), as it was the window selected when :NvimTreeFocus was last called.

Activity

alex-courtis

alex-courtis commented on Jun 11, 2023

@alex-courtis
Member

target_winid tracking for the previous window was added ~2021 #174

This is functional but incomplete, which explains this behaviour.

The # buffer is tracked per window so that will not be useful.

<c-w><c-p> can be used to switch to the previous window however I'm not seeing an obvious means of programatically finding the previously focused window.

It is tempting to remove target_winid however I must be mindful of Chesterton's fence

alex-courtis

alex-courtis commented on Jun 11, 2023

@alex-courtis
Member

We could manually track windows by tab, however this feels very wrong:

local log = require("nvim-tree.log")

local windows_by_tabpage = {
  previous = {},
  current = {},
}

local function remove_invalid(mapping)
  for t, w in pairs(mapping) do
    if not vim.api.nvim_tabpage_is_valid(t) or not vim.api.nvim_win_is_valid(w) then
      mapping[t] = nil
    end
  end
end

vim.api.nvim_create_autocmd({ "WinEnter", "WinLeave" }, {
  callback = function(d)
    local tabpage = vim.api.nvim_get_current_tabpage()
    local window = vim.api.nvim_get_current_win()

    -- set previous or current
    if d.event == "WinEnter" then
      windows_by_tabpage.current[tabpage] = window
    elseif d.event == "WinLeave" then
      windows_by_tabpage.previous[tabpage] = window
    end

    -- tidy closed windows/tabs
    remove_invalid(windows_by_tabpage.current)
    remove_invalid(windows_by_tabpage.previous)

    log.line("dev", "%s %s\n", d.event, vim.inspect(windows_by_tabpage))
  end,
})
zhimsel

zhimsel commented on Jun 12, 2023

@zhimsel
ContributorAuthor

To be honest, that doesn't feel "wrong" to me. It's a simple and effective (as far as I can tell) way to track the previous window. I haven't found a mechanism built into nvim that provides this function, probably because using these autocmds is easy and clean enough.

It's more thorough than only tracking the previous window when using :NvimTreeFocus.

zhimsel

zhimsel commented on Jun 12, 2023

@zhimsel
ContributorAuthor

I can attempt to put together a PR, if you could point me in the right directions for which parts of this plug-in are responsible for window tracking.

alex-courtis

alex-courtis commented on Jun 18, 2023

@alex-courtis
Member

I can attempt to put together a PR, if you could point me in the right directions for which parts of this plug-in are responsible for window tracking.

That would be fantastic!

  1. Add the tracking bits above to lib.lua. Call that from an autocommand in nvim-tree.lua
  2. Remove lib.target_winid. Any accessors should be changed to use the previous value.
  3. Find other places where we should also use the previous value.
added
PR pleasenvim-tree team does not have the bandwidth to implement; a PR will be gratefully appreciated
on Jun 18, 2023
bombela

bombela commented on Nov 25, 2023

@bombela

I am not 100% sure if this bug is the same I am encountering.

:tabedit $somepath select a file to open, and NvimTree will focus the previous tab and ask me which window I want to replace with the file.

If before opening the file I execute :NvimTreeFocus then NvimTree will open the file in a vertical split.

After that, with another :tabedid $somepath, NvimTree will replace itself with the opened file (no vertical split, no focus on the previous tab). This last behavior is similar to the original netrw, and what I expect.

alex-courtis

alex-courtis commented on Nov 25, 2023

@alex-courtis
Member

I am not 100% sure if this bug is the same I am encountering.

That splitting behaviour does sound different however I would not be surprised if the above fix resolved it.

I can't reproduce, however there are nvim and nvim-tree settings that would affect this sort of behaviour.

Can you please provide a reproducer with exact steps as per clean room replication?

added and removed
bugSomething isn't working
PR pleasenvim-tree team does not have the bandwidth to implement; a PR will be gratefully appreciated
on Dec 3, 2023
alex-courtis

alex-courtis commented on Mar 24, 2024

@alex-courtis
Member

See #2722

ahakanbaba

ahakanbaba commented on Apr 30, 2025

@ahakanbaba

Apologies if this is obviously wrong, I am recently getting into neovim.

But what problems do you see with this approach:

     actions = {
       open_file = {
        -- Open a window in the most recently used position
         window_picker = {
           enable = true,
           picker = function()

                -- Determine the last-accessed window’s number according to Neovim
                local prev_win_num = vim.fn.winnr('#')
                print(prev_win_num)
                -- If 0 is returned, it means there is no valid “previous” window

                if prev_win_num == 0 then
                  -- No window to return. I think this falls back to the default behavior
                  return 0
                end

                -- Convert the window number to its actual window ID
                local prev_win_id = vim.fn.win_getid(prev_win_num)
                return prev_win_id

           end,
         },
       },
alex-courtis

alex-courtis commented on May 2, 2025

@alex-courtis
Member

Apologies if this is obviously wrong, I am recently getting into neovim.

But what problems do you see with this approach:

That looks quite reasonable.

If that is working reliably for you I'd be grateful for a
wiki Recipe
Pull Request, we can decide at the time whether this is a fix or an optional feature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @bombela@alex-courtis@zhimsel@ahakanbaba

        Issue actions

          Previous window is not selected unless :NvimTreeFocus is used · Issue #2262 · nvim-tree/nvim-tree.lua