smart-splits.nvim icon indicating copy to clipboard operation
smart-splits.nvim copied to clipboard

[Bug]: Won't exit snack explorer picker properly after rename attempt with `dressing.nvim`, `snacks.input.nvim`

Open woertsposzibllen4me opened this issue 6 months ago • 21 comments

Similar Issues

  • [x] Before filing, I have searched for similar issues.

Neovim Version

NVIM v0.12.0-dev-197+g1dbede5b93 Build type: RelWithDebInfo LuaJIT 2.1.1744317938

Multiplexer Integration

tmux

Multiplexer Version

This is an interal nvim thing.

Steps to Reproduce

  1. press <space>e to open explorer
  2. press r to rename some file
  3. press esc twice to espace dressing.nvim renaming buffer
  4. press C-l to try to access main eiditing window

Expected Behavior

Cursor moves from explorer picker to main window.

Actual Behavior

Cursor will not move.

this can be fixed with:

      {
        "<C-l>",
        function()
          if vim.bo.filetype == "snacks_picker_list" then
            local win_config = vim.api.nvim_win_get_config(0)
            if win_config.zindex == 33 then -- Snack explorer is on same zindex as main window
              vim.cmd("wincmd l")
            end
          else
            require("smart-splits").move_cursor_right()
          end
        end,
        desc = "Move to right split",
      },

Minimal Configuration to Reproduce

-- usage "nvim -u this_filename.lua"
vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()
vim.g.mapleader = " " -- Set leader key to space

--- @ diagnostic disable: missing-fields
require("lazy.minit").repro({
  spec = {
    {
      "folke/snacks.nvim",
      lazy = false,
      keys = {
        {
          "<leader>e",
          function()
            require("snacks").explorer()
          end,
        },
      },
    },
    {
      "stevearc/dressing.nvim",
      opts = {},
    },
    {
      "mrjones2014/smart-splits.nvim",
      lazy = false,
      opts = {
        at_edge = "stop",
      },
      keys = {
        {
          "<C-h>",
          function()
            require("smart-splits").move_cursor_left()
          end,
          desc = "Move to left split",
        },
        {
          "<C-j>",
          function()
            require("smart-splits").move_cursor_down()
          end,
          desc = "Move to bottom split",
        },
        {
          "<C-k>",
          function()
            require("smart-splits").move_cursor_up()
          end,
          desc = "Move to top split",
        },
        {
          "<C-l>",
          function()
            require("smart-splits").move_cursor_right()
          end,
          desc = "Move to right split",
        },
      },
    },
  },
})

Additional Details and/or Screenshots

I'm not sure you want to cover this case since it involves 2 others plugins but just reporting in case you'd want to. Something happens when the dressing buffer gets created that makes this plugin not recognize that we are in nvim anymore.

EDIT : This happens with snacks.input too

woertsposzibllen4me avatar Jun 13 '25 19:06 woertsposzibllen4me

Where'd you get the 33 value for zindex?

Technically Snacks.explorer() is a floating window so the plugin is "correctly" obeying floating window behavior. But it gets weird because Snacks.explorer is a floating window but it is designed not to look or behave like one.

I think rather than relying on zindex = 33 which might break other floating windows, we should find a way to specifically identity the Snacks explorer window.

mrjones2014 avatar Jun 23 '25 14:06 mrjones2014

If we do that then we can update utils.is_floating_window() to exclude Snacks.explorer() window so that smart-splits.nvim treats it like a non-floating window.

mrjones2014 avatar Jun 23 '25 14:06 mrjones2014

Yes Snack explorer is just a regular snacks picker, it doesn't have an individual filetype of anything else that I figured would help indentifying it reliably. The other snacks picker buffers I've looked at (ivy layout mostly: it has buffer + window on same plane) had a different zindex so for a personal use patch it was fine.

if you use

function capture_info()
  local win_config = vim.api.nvim_win_get_config(0)
  print("Window configuration: " .. vim.inspect(win_config))
end

you'll get, with varying values

11:03:22 PM msg_show.lua_print Window configuration: {
  anchor = "NW",
  border = "none",
  col = 0,
  external = false,
  focusable = true,
  height = 51,
  hide = false,
  mouse = true,
  relative = "win",
  row = 3,
  width = 40,
  win = 1015,
  zindex = 33
}
I use this utility to see buffers info
M.capture_current_buffer_info = function()
  local bufname = vim.fn.bufname("%")
  local raw_representation = vim.inspect(bufname)
  local title = vim.o.titlestring
  local filetype = vim.bo.filetype
  local buftype = vim.bo.buftype
  local absolute_path = vim.fn.expand("%:p")
  local buf_vars = vim.b -- Buffer variables
  local win_config = vim.api.nvim_win_get_config(0)

  print("=== Buffer Info ===")
  print("Current buffer name: " .. bufname)
  print("Raw buffer name: " .. raw_representation)
  print("Current titlestring: " .. title)
  print("Current buffer type: " .. filetype)
  print("Current buffer type (buftype): " .. buftype)
  print("Absolute path: " .. absolute_path)
  print("Buffer variables: " .. vim.inspect(buf_vars))
  print("Window configuration: " .. vim.inspect(win_config))

  return { bufname = bufname, raw = raw_representation, title = title }
end

Idk much about how buffer vars work but maybe it could be easy to set one with vim.b.is_explorer = true at the explorer picker creation in snacks source code. Other than that I don't see a reliable way to indentify it.

At the end tho the snack explorer indentification matter is a workaround for the issue of the buffers created from dressing and snacks.input being the actual obstruction to this plugin's logic... though recognizing the situation and simply making an explicit call to wincmd direction is a pretty easy fix.

woertsposzibllen4me avatar Jun 23 '25 21:06 woertsposzibllen4me

the issue of the buffers created from dressing and snacks.input being the actual obstruction to this plugin's logic.

yep exactly.

Until such time that we can reliably detect these edge cases, I lean towards the solution being "just add docs".

mrjones2014 avatar Jun 24 '25 18:06 mrjones2014

I just ran across this thread today while looking for info on a different but possibly related issue with smart-splits.nvim and Snacks.explorer().

The issue is that running require("smart-splits").move_cursor_down() or _cursor_up() while the Snacks.explorer() pane is active will correctly navigate between the host panes (in my case Wezterm), but it simultaneously also moves the nvim cursor out of the explorer pane and makes another buffer active.

That is mostly just a weird side effect, as I can still navigate around nvim and host panes, it just doesn't save the nvim cursor location.

However, in addition, when the Snacks.explorer() pane is on the left edge of nvim and there is another Wezterm pane to the left of it, require("smart-splits").move_cursor_left() leaves the nvim cursor inside the explorer pane (so no side effect), but does not navigate between Wezterm panes successfully.

Something about this explorer window doesn't seem to play nice with smart-splits.

I apologize that I haven't dug into this more but just wanted to mention it somewhere and this seemed like it might be a relevant place.

kwertyops avatar Aug 11 '25 20:08 kwertyops

I use latest lazyvim in wezterm with smartsplits. I have an issue when I enter the snacks explorer, which is on the left, and then go to the right, it should go to my code editor, but it jumps to the wezterm pane, which is further on the right.

Is there any known solution for this?

Edit: Related to this issue: https://github.com/folke/snacks.nvim/issues/2245

romanorac avatar Oct 06 '25 09:10 romanorac

That happens when you have float_win_behavior = 'mux' because the snacks explorer window is technically a floating window.

Unfortunately there is not a great way to add special handling for it because it's also just a snacks picker in disguise, so the filetype is snacks_picker_list which is the same as normal pickers, which we do want to treat like normal picker windows.

However looking again, I think I missed some context in the original message. I would be okay with checking zindex == 33 in combination with the filetype being snacks_picker_list.

I'll put up a PR for yall to test.

mrjones2014 avatar Oct 06 '25 13:10 mrjones2014

Please test #380

mrjones2014 avatar Oct 06 '25 13:10 mrjones2014

Thanks for a quick fix. The issue that I described above is solved with your commit:

return {
  "mrjones2014/smart-splits.nvim",
  commit = "c4afaf23141651845e6e1966d936d79ff8939e4d",
}

romanorac avatar Oct 06 '25 13:10 romanorac

Just a note -- I had tried a very similar fix to what you implemented here, and I didn't open a pull request because, while it did fix the original issue in this thread, it introduced two new side effects (as your fix does also):

  1. With Snacks.explorer active, all smart-splits directions (up, left, right, and down) now have the same behavior of moving the cursor to the first available normal split, even if a given direction should dead-end. In effect every direction seems to just be "move off of the explorer window".
  2. With Snacks.explorer active, it's no longer possible to move directly to another Wezterm pane because of the above.

I prefer this over the original bug, because I can work around the limitations, but I thought it was worth mentioning the side effects. I still have the issue, for example, that there's no way for me to move to a Wezterm pane that is to the left of the current pane. Previously it just didn't work (the cursor would stay inside the Snacks.explorer), but now a move_left() just goes into the main buffer, and then another move_left() goes back into Snacks.explorer in a loop, ad infinitum.

andrewhannum avatar Oct 06 '25 14:10 andrewhannum

The snacks.nvim special handling has been reverted: https://github.com/mrjones2014/smart-splits.nvim/pull/381

The special handling caused the inability to resize the snacks explorer. Reopening the issue for further discussion on how to handle it.

mrjones2014 avatar Oct 09 '25 13:10 mrjones2014

The resize bug only occurs when you have keyboard focus inside the snacks explorer. The bug does not occur when you have keyboard focus in the normal window:

https://github.com/user-attachments/assets/fc07ca16-dada-4dc3-95e5-76f701130131

I honestly prefer this resize bug over the navigation bug. I don't resize the snacks explorer all that often, but I frequently need to navigate out of it. So I would prefer to revert #381.

For anyone like me who'd rather work around the resize bug, you can add this to your config:

return {
  "mrjones2014/smart-splits.nvim",
  commit = "c4afaf23141651845e6e1966d936d79ff8939e4d",
}

Torsteinws avatar Oct 24 '25 16:10 Torsteinws

@Torsteinws I just had another thought; does the resize bug go away if you set snacks_picker_list and snacks_picker_input as ignored filetypes in smart-splits config?

If so I would be open to merging a PR that brings #380 behavior back, but make it configurable, adding those to the default values for ignored_filetypes in smart-splits default config, and adding a section in the documentation on it.

mrjones2014 avatar Oct 24 '25 17:10 mrjones2014

Unfortunately that does not make the resize bug go away.

This was the config I used to test it:

return {
  "mrjones2014/smart-splits.nvim",
  commit = "c4afaf23141651845e6e1966d936d79ff8939e4d",
  opts = {
    ignored_filetypes = { "snacks_picker_list", "snacks_picker_input" },
  },
}

Torsteinws avatar Oct 24 '25 17:10 Torsteinws

I found another issue that seems related.

It seems like smart-splits.nvim is not able to detect that it is on an edge when the keyboard focus is inside the snacks explorer.

For example, here it is not possible to navigate to the left pane when the snacks explorer is open:

https://github.com/user-attachments/assets/2586e2ef-a6e6-4771-aeca-4798004eab4e

And here you cannot navigate to the bottom pane if your keyboard focus is inside the snacks explorer:

https://github.com/user-attachments/assets/b541899a-151a-4d41-9f09-42e5a8e77d76

It's not really a big issue, but interesting to keep in mind when looking for a way to handle that misbehaving snacks explorer.

Torsteinws avatar Oct 24 '25 17:10 Torsteinws

Good news! The resize bug resolved itself after I updated all my plugins. I am currently using smart-splits.nvim pre #380, and everything works perfect now as far as I can tell.

Maybe you can consider to revert #380?

Torsteinws avatar Nov 21 '25 18:11 Torsteinws

#380 was reverted almost immediately by #381

mrjones2014 avatar Nov 21 '25 18:11 mrjones2014

Oops, I meant to write #381 😂

I.E. I am running smart-splits pre #381 (but post #380) and the resize bug resolved itself after a recent update. Therefore maybe you can consider to revert #381.

Sorry for the confusion!

Torsteinws avatar Nov 21 '25 19:11 Torsteinws

Oh interesting! Could you narrow down the specific commit which fixes the issue? If I could better understand why its fixed, I'd definitely consider reverting #381!

mrjones2014 avatar Nov 22 '25 00:11 mrjones2014

I am also not seeing the resize issue anymore when pinning the plugin at #380, but the second bug that Torsteinws pointed out is still present.

@mrjones2014 Commit 913379c in snacks.nvim is what resolved the resize issue. Here's a minimal config that may help troubleshoot things further if necessary. Although, it seems that the bug was in snacks.nvim, as the commit that fixed it references this issue, which, itself, references this discussion that demonstrates the bug absent smart-splits.nvim.

-- vi: ts=2 sw=2 et

vim.env.LAZY_STDPATH = ".repro"

load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()

require("lazy.minit").repro({
  spec = {
    {
      "mrjones2014/smart-splits.nvim",
      commit = "c4afaf23141651845e6e1966d936d79ff8939e4d",
    },
    {
      "folke/snacks.nvim",
      commit = "913379ccd2679fc11462479205897e584496c855",  -- Append '^' to see the resize bug again.
      opts = { explorer = { enabled = true } },
      keys = {
        {
          "ge",
          function()
            Snacks.explorer()
          end,
          desc = "File Explorer",
        },
      },
    },
  },
})

-- Switch windows.
vim.keymap.set({ "n", "i", "t" }, "<M-h>", function()
  require("smart-splits").move_cursor_left()
end, { desc = "Go to Left Window" })
vim.keymap.set({ "n", "i", "t" }, "<M-j>", function()
  require("smart-splits").move_cursor_down()
end, { desc = "Go to Lower Window" })
vim.keymap.set({ "n", "i", "t" }, "<M-k>", function()
  require("smart-splits").move_cursor_up()
end, { desc = "Go to Upper Window" })
vim.keymap.set({ "n", "i", "t" }, "<M-l>", function()
  require("smart-splits").move_cursor_right()
end, { desc = "Go to Right Window" })
vim.keymap.set({ "n", "i", "t" }, "<M-;>", function()
  require("smart-splits").move_cursor_previous()
end, { desc = "Go to Previous Window" })

-- Resize windows.
vim.keymap.set({ "n", "i", "t" }, "<M-H>", function()
  require("smart-splits").resize_left()
end, { desc = "Resize Window Leftwards" })
vim.keymap.set({ "n", "i", "t" }, "<M-J>", function()
  require("smart-splits").resize_down()
end, { desc = "Resize Window Upwards" })
vim.keymap.set({ "n", "i", "t" }, "<M-K>", function()
  require("smart-splits").resize_up()
end, { desc = "Resize Window Downwards" })
vim.keymap.set({ "n", "i", "t" }, "<M-L>", function()
  require("smart-splits").resize_right()
end, { desc = "Resize Window Rightwards" })

pwnalone avatar Nov 22 '25 19:11 pwnalone

the second bug that Torsteinws https://github.com/mrjones2014/smart-splits.nvim/issues/342#issuecomment-3444220929 is still present.

Yeah, this is another weird case of "technically not a bug" because of how Snacks.explorer is weirdly using a floating window -- technically this plugin considers floating windows to never be at an edge.

However, since Snacks.explorer seems to always be at an edge (correct me if I am wrong), then I think we're safe now to treat the snacks explorer specially in the following ways:

  • Pretend it is not floating
  • Always assume it is at an edge

Let me know if anyone would like to PR this, otherwise I will probably not get to it for a bit with holidays and all coming up.

mrjones2014 avatar Nov 22 '25 20:11 mrjones2014