Skip to content

Commit 23613a9

Browse files
committed
fix: Some file watching related vfs fixes
1 parent cd8eb0f commit 23613a9

File tree

4 files changed

+46
-12
lines changed

4 files changed

+46
-12
lines changed

crates/rust-analyzer/src/handlers/notification.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ pub(crate) fn handle_did_change_watched_files(
241241
state: &mut GlobalState,
242242
params: DidChangeWatchedFilesParams,
243243
) -> anyhow::Result<()> {
244-
for change in params.changes {
244+
for change in params.changes.iter().unique_by(|&it| &it.uri) {
245245
if let Ok(path) = from_proto::abs_path(&change.uri) {
246246
state.loader.handle.invalidate(path);
247247
}

crates/vfs-notify/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ impl NotifyActor {
136136
Message::Invalidate(path) => {
137137
let contents = read(path.as_path());
138138
let files = vec![(path, contents)];
139-
self.send(loader::Message::Loaded { files });
139+
self.send(loader::Message::Changed { files });
140140
}
141141
},
142142
Event::NotifyEvent(event) => {

crates/vfs/src/lib.rs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,21 @@ impl nohash_hasher::IsEnabled for FileId {}
9191
pub struct Vfs {
9292
interner: PathInterner,
9393
data: Vec<FileState>,
94+
// FIXME: This should be a HashMap<FileId, ChangeFile>
95+
// right now we do a nasty deduplication in GlobalState::process_changes that would be a lot
96+
// easier to handle here on insertion.
9497
changes: Vec<ChangedFile>,
98+
// The above FIXME would then also get rid of this probably
99+
created_this_cycle: Vec<FileId>,
95100
}
96101

97-
#[derive(Copy, PartialEq, PartialOrd, Clone)]
102+
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
98103
pub enum FileState {
104+
/// The file has been created this cycle.
105+
Created,
106+
/// The file exists.
99107
Exists,
108+
/// The file is deleted.
100109
Deleted,
101110
}
102111

@@ -121,6 +130,11 @@ impl ChangedFile {
121130
matches!(self.change, Change::Create(_) | Change::Delete)
122131
}
123132

133+
/// Returns `true` if the change is [`Create`](ChangeKind::Create).
134+
pub fn is_created(&self) -> bool {
135+
matches!(self.change, Change::Create(_))
136+
}
137+
124138
/// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
125139
pub fn is_modified(&self) -> bool {
126140
matches!(self.change, Change::Modify(_))
@@ -160,7 +174,9 @@ pub enum ChangeKind {
160174
impl Vfs {
161175
/// Id of the given path if it exists in the `Vfs` and is not deleted.
162176
pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
163-
self.interner.get(path).filter(|&it| matches!(self.get(it), FileState::Exists))
177+
self.interner
178+
.get(path)
179+
.filter(|&it| matches!(self.get(it), FileState::Exists | FileState::Created))
164180
}
165181

166182
/// File path corresponding to the given `file_id`.
@@ -178,7 +194,9 @@ impl Vfs {
178194
pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ {
179195
(0..self.data.len())
180196
.map(|it| FileId(it as u32))
181-
.filter(move |&file_id| matches!(self.get(file_id), FileState::Exists))
197+
.filter(move |&file_id| {
198+
matches!(self.get(file_id), FileState::Exists | FileState::Created)
199+
})
182200
.map(move |file_id| {
183201
let path = self.interner.lookup(file_id);
184202
(file_id, path)
@@ -193,27 +211,43 @@ impl Vfs {
193211
/// [`FileId`] for it.
194212
pub fn set_file_contents(&mut self, path: VfsPath, contents: Option<Vec<u8>>) -> bool {
195213
let file_id = self.alloc_file_id(path);
196-
let change_kind = match (self.get(file_id), contents) {
214+
let state = self.get(file_id);
215+
let change_kind = match (state, contents) {
197216
(FileState::Deleted, None) => return false,
198217
(FileState::Deleted, Some(v)) => Change::Create(v),
199-
(FileState::Exists, None) => Change::Delete,
200-
(FileState::Exists, Some(v)) => Change::Modify(v),
218+
(FileState::Exists | FileState::Created, None) => Change::Delete,
219+
(FileState::Exists | FileState::Created, Some(v)) => Change::Modify(v),
220+
};
221+
self.data[file_id.0 as usize] = match change_kind {
222+
Change::Create(_) => {
223+
self.created_this_cycle.push(file_id);
224+
FileState::Created
225+
}
226+
// If the file got created this cycle, make sure we keep it that way even
227+
// if a modify comes in
228+
Change::Modify(_) if matches!(state, FileState::Created) => FileState::Created,
229+
Change::Modify(_) => FileState::Exists,
230+
Change::Delete => FileState::Deleted,
201231
};
202232
let changed_file = ChangedFile { file_id, change: change_kind };
203-
self.data[file_id.0 as usize] =
204-
if changed_file.exists() { FileState::Exists } else { FileState::Deleted };
205233
self.changes.push(changed_file);
206234
true
207235
}
208236

209237
/// Drain and returns all the changes in the `Vfs`.
210238
pub fn take_changes(&mut self) -> Vec<ChangedFile> {
239+
for file_id in self.created_this_cycle.drain(..) {
240+
if self.data[file_id.0 as usize] == FileState::Created {
241+
// downgrade the file from `Created` to `Exists` as the cycle is done
242+
self.data[file_id.0 as usize] = FileState::Exists;
243+
}
244+
}
211245
mem::take(&mut self.changes)
212246
}
213247

214248
/// Provides a panic-less way to verify file_id validity.
215249
pub fn exists(&self, file_id: FileId) -> bool {
216-
matches!(self.get(file_id), FileState::Exists)
250+
matches!(self.get(file_id), FileState::Exists | FileState::Created)
217251
}
218252

219253
/// Returns the id associated with `path`

crates/vfs/src/loader.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub enum Message {
5858
/// The [`Config`] version.
5959
config_version: u32,
6060
},
61-
/// The handle loaded the following files' content.
61+
/// The handle loaded the following files' content for the first time.
6262
Loaded { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },
6363
/// The handle loaded the following files' content.
6464
Changed { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },

0 commit comments

Comments
 (0)