diff --git a/src/change_processor.rs b/src/change_processor.rs index c04fc14d..6838286e 100644 --- a/src/change_processor.rs +++ b/src/change_processor.rs @@ -111,11 +111,6 @@ impl ChangeProcessor { .spawn(move || { log::trace!("ChangeProcessor thread started"); - // Populate the RefPathIndex from existing meta/model files - // so that renames of instances with pre-existing Rojo_Ref_* - // attributes are handled correctly from the first rename. - task.populate_initial_ref_path_index(); - // Tracks when to run the next reconciliation pass. Set to // Some(future_instant) after VFS events arrive, cleared // after reconcile_tree() runs. This ensures we only do the @@ -260,61 +255,6 @@ impl JobThreadContext { rel_path(path, &self.project_root) } - /// Scan all `.meta.json5`, `.model.json5`, `.meta.json`, `.model.json` - /// files under the project root for existing `Rojo_Ref_*` attributes - /// and populate the `RefPathIndex`. This ensures pre-existing ref - /// attributes (from CLI syncback, manual edits, or previous sessions) - /// are indexed so rename path updates work from the first rename. - fn populate_initial_ref_path_index(&self) { - let mut count = 0; - let mut dirs_to_visit = vec![self.project_root.clone()]; - while let Some(dir) = dirs_to_visit.pop() { - let entries = match fs::read_dir(&dir) { - Ok(entries) => entries, - Err(_) => continue, - }; - for entry in entries.filter_map(|e| e.ok()) { - let path = entry.path(); - if path.is_dir() { - dirs_to_visit.push(path); - continue; - } - let name = match path.file_name().and_then(|n| n.to_str()) { - Some(n) => n, - None => continue, - }; - if !(name.ends_with(".meta.json5") - || name.ends_with(".model.json5") - || name.ends_with(".meta.json") - || name.ends_with(".model.json")) - { - continue; - } - if let Ok(bytes) = fs::read(&path) { - if let Ok(val) = crate::json::from_slice::(&bytes) { - if let Some(attrs) = val.get("attributes").and_then(|a| a.as_object()) { - let mut index = self.ref_path_index.lock().unwrap(); - for (key, value) in attrs { - if key.starts_with(crate::REF_PATH_ATTRIBUTE_PREFIX) { - if let Some(path_str) = value.as_str() { - index.add(path_str, &path); - count += 1; - } - } - } - } - } - } - } - } - if count > 0 { - log::info!( - "RefPathIndex: populated {} Rojo_Ref_* entries from existing meta/model files", - count - ); - } - } - /// Find the init file inside a directory-format script folder. /// Returns the path to the first `init.*.luau` or `init.*.lua` found. fn find_init_file(dir: &Path) -> Option { diff --git a/src/rojo_ref.rs b/src/rojo_ref.rs index c9872e81..4ea70326 100644 --- a/src/rojo_ref.rs +++ b/src/rojo_ref.rs @@ -298,6 +298,62 @@ impl RefPathIndex { } } + /// Scan all `.meta.json5`, `.model.json5`, `.meta.json`, `.model.json` + /// files under `root` for existing `Rojo_Ref_*` attributes and index them. + /// This ensures pre-existing ref attributes (from CLI syncback, manual + /// edits, or previous sessions) are indexed so rename path updates work + /// from the first rename. + pub fn populate_from_dir(&mut self, root: &Path) { + let mut count = 0usize; + let mut dirs_to_visit = vec![root.to_path_buf()]; + while let Some(dir) = dirs_to_visit.pop() { + let entries = match std::fs::read_dir(&dir) { + Ok(entries) => entries, + Err(_) => continue, + }; + for entry in entries.filter_map(|e| e.ok()) { + let path = entry.path(); + if path.is_dir() { + dirs_to_visit.push(path); + continue; + } + let name = match path.file_name().and_then(|n| n.to_str()) { + Some(n) => n, + None => continue, + }; + if !(name.ends_with(".meta.json5") + || name.ends_with(".model.json5") + || name.ends_with(".meta.json") + || name.ends_with(".model.json")) + { + continue; + } + if let Ok(bytes) = std::fs::read(&path) { + if let Ok(val) = + crate::json::from_slice::(&bytes) + { + if let Some(attrs) = val.get("attributes").and_then(|a| a.as_object()) { + for (key, value) in attrs { + if key.starts_with(crate::REF_PATH_ATTRIBUTE_PREFIX) { + if let Some(path_str) = value.as_str() { + self.add(path_str, &path); + count += 1; + } + } + } + } + } + } + } + } + if count > 0 { + log::info!( + "RefPathIndex: populated {} Rojo_Ref_* entries from existing meta/model files", + count + ); + } + } + /// Find all meta/model files that contain a `Rojo_Ref_*` attribute whose /// value equals `prefix` or starts with `prefix/`. These are the files /// that need updating when an instance at `prefix` is renamed. diff --git a/src/serve_session.rs b/src/serve_session.rs index 46788189..d67f7604 100644 --- a/src/serve_session.rs +++ b/src/serve_session.rs @@ -174,7 +174,11 @@ impl ServeSession { let (tree_mutation_sender, tree_mutation_receiver) = crossbeam_channel::unbounded(); let suppressed_paths = Arc::new(Mutex::new(std::collections::HashMap::new())); - let ref_path_index = Arc::new(Mutex::new(crate::RefPathIndex::new())); + let ref_path_index = { + let mut index = crate::RefPathIndex::new(); + index.populate_from_dir(root_project.folder_location()); + Arc::new(Mutex::new(index)) + }; let git_repo_root = crate::git::git_repo_root(root_project.folder_location());