Skip to content

Conversation

@Gelio
Copy link
Contributor

@Gelio Gelio commented Nov 5, 2022

When renaming or moving files/directories, neo-tree used to change the name of renamed buffers while retaining the same buffer numbers. It did not delete the old buffers and open new ones for editing.

This ended up crashing Neovim in the following scenario:

  • a BufWritePre autocmd was created to call vim.lsp.buf.format({ async = false })
  • there was an LSP client registered for the buffer
  • the buffer was opened and then put in the background (e.g. by :Neotree position=current)
  • the file was renamed/moved in neo-tree

The operation that caused the Neovim crash was the silent! write! that neo-tree executes on the buffer right after it is renamed. During that write, synchronous formatting is attempted in the BufWritePre autocmd.

My assumption is that the LSP server does not get a notification about the file rename and sends some invalid formatting information back to Neovim. Neovim cannot interpret it and crashes.

Crash backtrace: bt.txt

Peek.2022-11-05.14-07.rename.crash.mp4

The crash does not happen if the renamed buffer is currently visible, rather than being hidden (e.g. when the renamed buffer is in one window and neo-tree is opened in a vertical split). The crash also does not happen if I don't run vim.lsp.buf.format on BufWritePre. Neither of these is a great workaround, as I don't want to remember to keep files open or remove my formatting autocmd.

The approach to handling file renamed used in this commit is the same as used in the vim.lsp.util.rename. Instead of reusing the buffers in Neovim before and after rename, neo-tree deletes old buffers for the file paths before the rename, and opens new buffers for files after the rename. If old buffers were shown in some Neovim window, the code opens the new buffers in these windows.

Peek.2022-11-05.14-08.rename.after.fix.mp4

The code that handles modified buffers during rename calls silent! write! on the new buffers. This no longer crashes Neovim. The downside is that LSP clients are not attached at the moment write! is called, which means the files after the rename will not be formatted after neo-tree saves the modified content. Overall, this seems like a lesser evil compared to Neovim crashing on each rename.

All in all, the functionality seems to be the same before and after my fix, with the difference that I no longer get Neovim crashes when renaming files that have a formatting autocmd.

Related to #308

When renaming or moving files/directories, neo-tree used to change the
name of renamed buffers while retaining the same buffer numbers. It did
not delete the old buffers and open new ones for editing.

This ended up crashing Neovim in the following scenario:

* a `BufWritePre` autocmd was created to call
  `vim.lsp.buf.format({ async = false })`
* there was an LSP client registered for the buffer
* the buffer was opened and then put in the background (e.g. by
  `:Neotree position=current`)
* the file was renamed/moved in neo-tree

The operation that caused the Neovim crash was the `silent! write!` that
neo-tree executes on the buffer right after it is renamed. During that
write, synchronous formatting is attempted in the `BufWritePre` autocmd.

My assumption is that the LSP server does not get a notification about
the file rename and sends some invalid formatting information back to
Neovim. Neovim cannot interpret it and crashes.

The crash does not happen if the renamed buffer is currently visible,
rather than being hidden (e.g. when the renamed buffer is in one window
and neo-tree is opened in a vertical split).

The approach to handling file renamed used in this commit is the same as
used in the `vim.lsp.util.rename` [0]. Instead of reusing the buffers in
Neovim before and after rename, neo-tree deletes old buffers for the
file paths before the rename, and opens new buffers for files after the
rename. If old buffers were shown in some Neovim window, the code opens
the new buffers in these windows.

The code that handles modified buffers during rename calls `silent!
write!` on the new buffers. This no longer crashes Neovim. The downside
is that LSP clients are not attached at the moment `write!` is called,
which means the files after the rename will not be formatted after
neo-tree saves the modified content. Overall, this seems like a lesser
evil compared to Neovim crashing on each rename.

Related to #308

[0]: https://github.com/neovim/neovim/blob/234b8c5f3d57294dda06dbc6c1760e5983bd2c19/runtime/lua/vim/lsp/util.lua#L751-L775
@Gelio Gelio changed the title fix: delete old buffers on rename/move fix: crash when renaming files that have sync-formatting autocmd Nov 5, 2022
@codecov
Copy link

codecov bot commented Nov 5, 2022

Codecov Report

Merging #591 (e8d60de) into main (960b545) will decrease coverage by 0.00%.
The diff coverage is 0.00%.

@@            Coverage Diff             @@
##             main     #591      +/-   ##
==========================================
- Coverage   50.56%   50.56%   -0.01%     
==========================================
  Files          47       47              
  Lines        6053     6061       +8     
==========================================
+ Hits         3061     3065       +4     
- Misses       2992     2996       +4     
Impacted Files Coverage Δ
lua/neo-tree/sources/filesystem/lib/fs_actions.lua 3.98% <0.00%> (-0.12%) ⬇️
lua/neo-tree/sources/filesystem/init.lua 66.10% <0.00%> (+1.69%) ⬆️

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

Copy link
Contributor

@cseickel cseickel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work, thanks!

@cseickel cseickel merged commit 5c209e5 into nvim-neo-tree:main Nov 5, 2022
@Gelio Gelio deleted the delete-old-buffers-on-rename branch November 5, 2022 20:22
@Gelio
Copy link
Contributor Author

Gelio commented Nov 6, 2022

Thanks for merging my PRs!

What is the schedule of merging main into v2.x? I'm wondering if I should switch to main temporarily to have the fixes or wati a short time to see them on the stable branch

@cseickel
Copy link
Contributor

cseickel commented Nov 6, 2022

I just released. My normal rule is to let new changes sit in main for at least a day to see if there are any bugs reported.

@Gelio
Copy link
Contributor Author

Gelio commented Nov 6, 2022

I see, thanks for quick action!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants