[Bug]: Won't exit snack explorer picker properly after rename attempt with `dressing.nvim`, `snacks.input.nvim`
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
- press
<space>eto open explorer - press
rto rename some file - press
esctwice to espacedressing.nvimrenaming buffer - press
C-lto 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
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.
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.
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.
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".
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.
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
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.
Please test #380
Thanks for a quick fix. The issue that I described above is solved with your commit:
return {
"mrjones2014/smart-splits.nvim",
commit = "c4afaf23141651845e6e1966d936d79ff8939e4d",
}
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):
- 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".
- 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.
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.
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 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.
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" },
},
}
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.
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?
#380 was reverted almost immediately by #381
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!
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!
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" })
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.