Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap notify::Watcher to handle vim's write-via-rename #1054

Closed
wants to merge 1 commit into from

Conversation

tomsmeding
Copy link
Contributor

The language server can request a watch on a file that is currently open in vim. If it does so, LanguageClient-neovim adds a file system watcher on that file. Doing this directly via notify::Watcher as it did before, however, goes wrong on systems where a file watch is really an inode watch, and vim writes to files by writing to a temporary file and then renaming over the original file. These systems include Linux and macOS.

Related:

src/watcher.rs Outdated Show resolved Hide resolved
UnwatchInfo::Directory(RecursiveMode::Recursive) => {
self.recursive_watcher
.as_mut()
.expect("FSWatch: inconsistent UnwatchInfo")
Copy link
Collaborator

@martskins martskins Jun 16, 2020

Choose a reason for hiding this comment

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

I honestly don't understand what the possible consequences of not shutting down the server would be in this case but my first thought would be to handle this case and return an error instead of expecting it. The expect calls on the lock calls I think are ok, but this one I'm not so sure.

Other than that this looks good to me, although @autozimu might be better suited to review this one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For both of the "inconsistent UnwatchInfo" expect calls, hitting them would mean that one the one hand we think there should be a watcher set up for the unwatched path, but on the other hand we find no such watcher in our data structures. This would mean a bug in the (my) watcher code.

If we don't panic there but just return an error, we are apparently in a situation where we're not sure exactly what watchers are or aren't active on what paths. In the end, I believe this would mean that the language server may get file change events that it didn't ask for, or may not get events for paths that it does have watched.

I'm not sure what your policy is in such situations. It might be possible to merge the two parallel data structures (dirs and unwatch_info), so that this case cannot occur. However, I'm personally not sure exactly how that would play with the Path interface; e.g. do parent and file_name behave predictably and sanely for multiple different ways of writing the same path? That is ultimately why I opted for the unwatch_info strategy.

But by all means, if you disagree this can change :)

Copy link
Owner

Choose a reason for hiding this comment

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

Firstly, thank you for taking time to tackle this.

On the point of expect calls, I would prefer to reduce the number of "hard errors" as much as possible. I do agree that in the unexpected case, we can only issuing an error and nothing more. But halting the whole program is a worse user experience, which also hinder future sophisticated error handling such as restarting the watch thread.

I haven't look through the the whole changes yet and I don't know much further on the parent and file_name topic. Will look further and update here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@autozimu Sorry to poll here, but were you intending to do some research and post here again, or are you waiting for me to do anything? I've been happily using my branch for a while now, and it seems to be working (though that doesn't mean the code is perfect, just a confirmation that it's not total crap).

@tomsmeding
Copy link
Contributor Author

Rebased onto latest dev, and squashed the two commits into one for good measure.

The language server can request a watch on a file that is currently open
in vim. If it does so, LanguageClient-neovim adds a file system watcher
on that file. Doing this directly via `notify::Watcher` as it did
before, however, goes wrong on systems where a file watch is really an
inode watch, and vim writes to files by writing to a temporary file and
then renaming over the original file. These systems include Linux and
macOS.
autozimu pushed a commit that referenced this pull request Sep 20, 2020
The language server can request a watch on a file that is currently open
in vim. If it does so, LanguageClient-neovim adds a file system watcher
on that file. Doing this directly via `notify::Watcher` as it did
before, however, goes wrong on systems where a file watch is really an
inode watch, and vim writes to files by writing to a temporary file and
then renaming over the original file. These systems include Linux and
macOS.
@autozimu
Copy link
Owner

Merged in via cccb87b

Thanks for contributing!

@autozimu autozimu closed this Sep 20, 2020
jez pushed a commit to jez/LanguageClient-neovim that referenced this pull request Feb 26, 2021
The language server can request a watch on a file that is currently open
in vim. If it does so, LanguageClient-neovim adds a file system watcher
on that file. Doing this directly via `notify::Watcher` as it did
before, however, goes wrong on systems where a file watch is really an
inode watch, and vim writes to files by writing to a temporary file and
then renaming over the original file. These systems include Linux and
macOS.
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.

3 participants