nvim-ide
nvim-ide copied to clipboard
Issues closing Nvim/Buffers
I've found a few "issues" while testing and i'm adding them individually so as to keep the discussions focused.
-
Just noticed
:q
on a buffer, which would normally close Nvim, seems to close the buffers, but keeps the left and right panels open, which need to be individually closed. -
Closing a buffer, with the panels open, means that the panels take up the entire viewport, then when I try to move to another buffer, it opens inside one of the IDE panels.
Same issue here, I think what we're asking for is, when closing a window, if the only remaining windows are all from nvim-ide, then close Neovim completely.
At the moment, the bigger issue for me is that when you close the buffer with the panels open, bnext
opens the panel in the to left panel.
The panels are normal Neovim windows. So use ":qa" instead. Just like if you had multiple neovim windows open and wanted to quit.
edit: https://github.com/ldelossa/nvim-ide/issues/14#issuecomment-1328509373
Ohhh this is cute. Hmm maybe this is worth adding to the WorkspaceController on start? Hide it behind a config flag like "auto_close" or something?
Yeah, same idea as how nvim-tree has an option to close Neovim if it’s the last window
I think the one I wrote there could be a bit more robust. Also I'm starting to think QuitPre might be the wrong event to track. I can't actually :qa
anymore unless it's strictly one remaining window + the panels.
Yeah I think you want to use WinClosed
With WinClosed, it will trigger on any window being closed, including completion windows, Noice's prompts, etc.
I'm not really sure what the best way to handle this is.
You could still catch the WinClosed event, but when you catch it, list all windows, search thru them, and if the only buffers you find in those Windows start with "component://" you can quit vim at that point.
Its a brute force approach but i think it will work.
This seems to work as expected:
vim.api.nvim_create_autocmd("WinClosed", {
pattern = {
"*"
},
callback = function()
vim.cmd("wincmd c")
local stdBufCount = 0
for _, v in ipairs(vim.api.nvim_list_wins()) do
local name = vim.fn.bufname(vim.api.nvim_win_get_buf(v))
if string.find(name, "component://*") then
goto continue
end
stdBufCount = stdBufCount + 1
::continue::
end
if stdBufCount == 0 then
vim.cmd("qa")
end
end
})
Basically what ldelossa was saying.
Why do you do the:
vim.cmd("wincmd c")
When "WinClosed" fires the window it matches for is already closed, why do you do the additional close of a window there?
The autocmd actually triggers before the window is closed, which I wasn't expecting. Found that by placing a print statement in after the loop; It print's before closing the window. I'm assuming the idea is you run some cleanup tasks for the window you're closing? Regardless, the issue was the window was still open, so looping over the current windows was still resulting in a normal window being present. Because of that, I would have to close one of the panel windows (being the only ones left) for it to actually close neovim.
The way it is right now, it functions the way I'd expect :q
to work. If you test it and it doesn't work that way, let me know as I might have something weird lurking in my config.
Aha! I must have read the docs wrong.
Okay, and it appears that the event is not recursive. So I dont think youll fire an event from this event, for the same window being closed, which is good 👌
I actually think you read the documentation correctly. I'm looking through the nvim source though and it looks like it fires the event before it actually closes the window?: https://github.com/neovim/neovim/blob/b2bb3973d9c7f25acfead2718d74fcf5b1e4551e/src/nvim/window.c#L2776
I might be reading it incorrectly.
Anyway, it might be up to nvim-ide to track the current state and if the only windows open are the panels, then close neovim/the current tab.
If your autocmd there works reliably, you can shove it right into the "WorkspaceController" init function I believe: https://github.com/ldelossa/nvim-ide/blob/e81fbd084f10b92bb6a4f62155e0fa1edbee9c7e/lua/ide/workspaces/workspace_controller.lua#L227
Guard it with a config flag, and lets see how that goes?
Let me test it more at work today and I'll give you a yay or nay on that.
Sounds great.
Broke almost immediately.
Played with it throughout the day when I could, came up with this:
vim.api.nvim_create_autocmd("WinEnter", {
pattern = {
"*"
},
callback = function()
local winCount = 0
local compWinCount = 0
for _, v in ipairs(vim.api.nvim_list_wins()) do
local name = vim.fn.bufname(vim.api.nvim_win_get_buf(v))
if string.find(name, "component://*") then
compWinCount = compWinCount + 1
end
winCount = winCount + 1
end
if stdBufCount == compWinCount then
vim.cmd("qa")
end
end
})
Using WinEnter
made sense since when you're quitting in the last "normal" window, it will close the window (as we talked about) and will run after the :q
. I think this is the best route.
My only concern: Though it doesn't seem to slow anything down when moving between windows, it is running two separate commands + a loop. If it gets integrated in to the codebase, we could probably instead use the .is_open()
to get which/how many panels are open, and then just compare that to the number returned by #vim.api.nvim_list_wins()
Hmm, maybe this is a bit more optimized? Basically, just try to quit ASAP when you see a window that's not a "component://" window.
vim.api.nvim_create_autocmd("WinEnter", {
pattern = {
"*"
},
callback = function()
-- optimize exit
local name = vim.fn.bufname(vim.api.nvim_win_get_buf(v))
if not string.find(name, "component://*") then
return
end
-- we are in a component win, search other wins to see if there are
-- any non-component wins.
for _, v in ipairs(vim.api.nvim_list_wins()) do
local name = vim.fn.bufname(vim.api.nvim_win_get_buf(v))
if not string.find(name, "component://*") then
return
end
end
-- only component wins left, exit
vim.cmd("qa")
end
})
You could keep track of and then check if the number of nvim-ide windows is equal to the total number of windows
You could keep track of and then check if the number of nvim-ide windows is equal to the total number of windows
That's what I was doing in the last iteration, but I think ldelossa has an idea there so this is my likely final iteration:
vim.api.nvim_create_autocmd("WinEnter", {
pattern = {
"*"
},
callback = function()
if not string.find(vim.fn.bufname(vim.api.nvim_win_get_buf(0)), "component://*") then
return
end
for _, v in ipairs(vim.api.nvim_list_wins()) do
if not string.find(vim.fn.bufname(vim.api.nvim_win_get_buf(v)), "component://*") then
return
end
end
vim.cmd("qa")
end
})
This doesn't work for me
Odd, works on my end. What happens for you?
It just doesn't seem to do anything. Can we put the autocmds into an augroup so I can inspect just that one augroup to further debug?
@mrjones2014 Not sure if this is your issue but I had to recompile with Packer to get everything working correctly. Also after changing auto_close
to false (to test that it would behave as expected)
Edit: I do think an augroup would be a good idea.
Hmm, I tried changing auto_close = false
then :PackerCompile
then change back auto_close = true
then :PackerCompile
and still no luck.
Have to ask, just to be sure, but did you make sure you're back on main?
I'm using my fork currently since I'm working on a PR, but I synced the fork with the main repo and merged main into my branch, so the changes are definitely there. I can see the changes in my local codebase.
I still can't get this working 🤔