diff --git a/crates/project/src/task_inventory.rs b/crates/project/src/task_inventory.rs index 1692f4202bebb54167422ab18e875040a12aad78..371449d4b615a077740a0ba1f913545359bc2222 100644 --- a/crates/project/src/task_inventory.rs +++ b/crates/project/src/task_inventory.rs @@ -586,6 +586,13 @@ impl Inventory { .global .entry(path.to_owned()) .insert_entry(new_templates.collect()); + self.last_scheduled_tasks.retain(|(kind, _)| { + if let TaskSourceKind::AbsPath { abs_path, .. } = kind { + abs_path != path + } else { + true + } + }); } TaskSettingsLocation::Worktree(location) => { let new_templates = new_templates.collect::>(); @@ -602,6 +609,18 @@ impl Inventory { .or_default() .insert(Arc::from(location.path), new_templates); } + self.last_scheduled_tasks.retain(|(kind, _)| { + if let TaskSourceKind::Worktree { + directory_in_worktree, + id, + .. + } = kind + { + *id != location.worktree_id || directory_in_worktree != location.path + } else { + true + } + }); } } @@ -756,6 +775,27 @@ mod test_inventory { }); } + pub(super) fn register_worktree_task_used( + inventory: &Entity, + worktree_id: WorktreeId, + task_name: &str, + cx: &mut TestAppContext, + ) { + inventory.update(cx, |inventory, cx| { + let (task_source_kind, task) = inventory + .list_tasks(None, None, Some(worktree_id), cx) + .into_iter() + .find(|(_, task)| task.label == task_name) + .unwrap_or_else(|| panic!("Failed to find task with name {task_name}")); + let id_base = task_source_kind.to_id_base(); + inventory.task_scheduled( + task_source_kind.clone(), + task.resolve_task(&id_base, &TaskContext::default()) + .unwrap_or_else(|| panic!("Failed to resolve task with name {task_name}")), + ); + }); + } + pub(super) async fn list_tasks( inventory: &Entity, worktree: Option, @@ -997,6 +1037,53 @@ mod tests { "2_task".to_string(), "1_a_task".to_string(), ], + "Most recently used task should be at the top" + ); + + let worktree_id = WorktreeId::from_usize(0); + let local_worktree_location = SettingsLocation { + worktree_id, + path: Path::new("foo"), + }; + inventory.update(cx, |inventory, _| { + inventory + .update_file_based_tasks( + TaskSettingsLocation::Worktree(local_worktree_location), + Some(&mock_tasks_from_names(["worktree_task_1"])), + ) + .unwrap(); + }); + assert_eq!( + resolved_task_names(&inventory, None, cx), + vec![ + "3_task".to_string(), + "1_task".to_string(), + "2_task".to_string(), + "1_a_task".to_string(), + ], + "Most recently used task should be at the top" + ); + assert_eq!( + resolved_task_names(&inventory, Some(worktree_id), cx), + vec![ + "3_task".to_string(), + "1_task".to_string(), + "2_task".to_string(), + "worktree_task_1".to_string(), + "1_a_task".to_string(), + ], + ); + register_worktree_task_used(&inventory, worktree_id, "worktree_task_1", cx); + assert_eq!( + resolved_task_names(&inventory, Some(worktree_id), cx), + vec![ + "worktree_task_1".to_string(), + "3_task".to_string(), + "1_task".to_string(), + "2_task".to_string(), + "1_a_task".to_string(), + ], + "Most recently used worktree task should be at the top" ); inventory.update(cx, |inventory, _| { @@ -1027,13 +1114,15 @@ mod tests { assert_eq!( resolved_task_names(&inventory, None, cx), vec![ - "3_task".to_string(), + "worktree_task_1".to_string(), + "1_a_task".to_string(), "1_task".to_string(), "2_task".to_string(), - "1_a_task".to_string(), + "3_task".to_string(), "10_hello".to_string(), "11_hello".to_string(), ], + "After global tasks update, worktree task usage is not erased and it's the first still; global task is back to regular order as its file was updated" ); register_task_used(&inventory, "11_hello", cx); @@ -1045,10 +1134,11 @@ mod tests { resolved_task_names(&inventory, None, cx), vec![ "11_hello".to_string(), - "3_task".to_string(), + "worktree_task_1".to_string(), + "1_a_task".to_string(), "1_task".to_string(), "2_task".to_string(), - "1_a_task".to_string(), + "3_task".to_string(), "10_hello".to_string(), ], ); @@ -1227,9 +1317,10 @@ mod tests { }) } - fn mock_tasks_from_names<'a>(task_names: impl Iterator + 'a) -> String { + fn mock_tasks_from_names<'a>(task_names: impl IntoIterator + 'a) -> String { serde_json::to_string(&serde_json::Value::Array( task_names + .into_iter() .map(|task_name| { json!({ "label": task_name,