elihunter173/dirbuf.nvim

File becomes unsaveable after accidentally navigating to dirbuf

andrewferrier opened this issue · 8 comments

I've had an issue with dirbuf.nvim for some time where occasionally files would become completely unsaveable, which is rare but very frustrating as all changes since the last save have to be discarded. It's hard to trigger, but I think I've finally managed to reliably create some recreation instructions. I'm pretty sure this is directly related to dirbuf, even though I'm not in a dirbuf buffer, because the - keymapping is involved, and dirbuf turns up in the error messages.

As always, thanks for all your hard work on the plugin!

Recreation instructions

  • Open NeoVim (I am using 0.7.2 on a Mac, but I think it happens on 0.8 on Linux too).
  • :set confirm
  • Open any regular file
  • Make a change (do not save)
  • Hit -
  • Wait for the prompt that says
Save changes to "dir/file.txt"?
[Y]es, (N)o, (C)ancel:
  • Hit <Esc>
  • See a message that says ENOTDIR: not a directory: "dir/file.txt"
  • Hit <Esc> again

Expected Behaviour

Can continue to edit file.

Actual Behaviour

File turns black (i.e. syntax highlighting is lost). Further editing is possible, but any attempt to save the file results in an error that looks like this:

Error detected while processing BufWriteCmd Autocommands for "<buffer=1>":
Cannot save dirbuf: Error while checking: ENOTDIR: not a directory: "dir/file.txt"

The only way forward at this point seems to be to discard the file changes with :q.

I haven't attempted to create a minimal init.lua, but if you cannot recreate, let me know and I'll try to do that.

I've managed to reproduce it on Linux as well. You have to run :set nohidden in addition to :set confirm.

I have a suspicion of what the issue might be but I'm not sure how to fix it yet

The issue is if line 182 fails (e.g. from not confirming), then line 183 is still executed which can mess up the current buffer as is seen here. I can't seem to find a way to get the return status of the edit command without resorting to hacks

dirbuf.nvim/lua/dirbuf.lua

Lines 182 to 183 in d610602

vim.cmd(keepalt .. " noautocmd edit " .. vim.fn.fnameescape(path))
M.init_dirbuf(history, history_index, true, from_path)

There is a try catch concept in VimScript, I wonder if that would help? Surround the command with it, set some kind of global flag if it fails?

https://stackoverflow.com/questions/5850103/try-catch-in-vimscript

Sadly that wouldn't work because edit is "failing" with actually raising an error. That is if you hit escape in the confirm window, :edit does nothing but control flow proceeds as normal.
And luckily vim.cmd() already converts Vimscript errors to Lua errors.

The fix I have in mind is a sanity check after the :edit. I should have that this week but I've been settling into my new apartment and buying furniture so who knows how much free time I'll have

Sadly that wouldn't work because edit is "failing" with actually raising an error. That is if you hit escape in the confirm window, :edit does nothing but control flow proceeds as normal.

And luckily vim.cmd() already converts Vimscript errors to Lua errors.

The fix I have in mind is a sanity check after the :edit. I should have that this week but I've been settling into my new apartment and buying furniture so who knows how much free time I'll have

Ok thanks. No probs - at least the issue is known and clearly defined now.

Finally got a chance to write and test the fix! Hitting escape in the confirm menu should leave things as expected. Let me know if you run into any other bugs :^)

Finally got a chance to write and test the fix! Hitting escape in the confirm menu should leave things as expected. Let me know if you run into any other bugs :^)

Cool, this seems to work/be fixed! Thanks very much for your all hard efforts here. I use dirbuf daily, great plugin :)