Prefer project (worktree) tasks to language/global tasks in task::Spawn (#21706)
`Inventory::list_tasks()` in `project` crate now is ordered by task types. Worktree tasks comes first, language tasks second and global tasks last. That leads to `spawn_task_with_name()` from `task_ui` crate will find worktree task first, so it's possible to override global tasks at project level. * `Inventory::templates_from_settings()` splitted to `Inventory::global_templates_from_settings()` and `Inventory::worktree_templates_from_settings()`. * In tests function `list_tasks()` renamed to `list_tasks_sorted_by_last_used()`, because it call's `Inventory::used_and_current_resolved_tasks()`. Also added `list_tasks()` which calls `Inventory::list_tasks()`. Closes #20987 Release Notes: - Fix task::Spawn to search for task name in project tasks first.
This commit is contained in:
parent
ff2d20780f
commit
cbc226597c
1 changed files with 86 additions and 33 deletions
|
@ -81,7 +81,8 @@ impl Inventory {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pulls its task sources relevant to the worktree and the language given,
|
/// Pulls its task sources relevant to the worktree and the language given,
|
||||||
/// returns all task templates with their source kinds, in no specific order.
|
/// returns all task templates with their source kinds, worktree tasks first, language tasks second
|
||||||
|
/// and global tasks last. No specific order inside source kinds groups.
|
||||||
pub fn list_tasks(
|
pub fn list_tasks(
|
||||||
&self,
|
&self,
|
||||||
file: Option<Arc<dyn File>>,
|
file: Option<Arc<dyn File>>,
|
||||||
|
@ -92,13 +93,15 @@ impl Inventory {
|
||||||
let task_source_kind = language.as_ref().map(|language| TaskSourceKind::Language {
|
let task_source_kind = language.as_ref().map(|language| TaskSourceKind::Language {
|
||||||
name: language.name().0,
|
name: language.name().0,
|
||||||
});
|
});
|
||||||
|
let global_tasks = self.global_templates_from_settings();
|
||||||
let language_tasks = language
|
let language_tasks = language
|
||||||
.and_then(|language| language.context_provider()?.associated_tasks(file, cx))
|
.and_then(|language| language.context_provider()?.associated_tasks(file, cx))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|tasks| tasks.0.into_iter())
|
.flat_map(|tasks| tasks.0.into_iter())
|
||||||
.flat_map(|task| Some((task_source_kind.clone()?, task)));
|
.flat_map(|task| Some((task_source_kind.clone()?, task)))
|
||||||
|
.chain(global_tasks);
|
||||||
|
|
||||||
self.templates_from_settings(worktree)
|
self.worktree_templates_from_settings(worktree)
|
||||||
.chain(language_tasks)
|
.chain(language_tasks)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -165,14 +168,18 @@ impl Inventory {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let not_used_score = post_inc(&mut lru_score);
|
let not_used_score = post_inc(&mut lru_score);
|
||||||
|
let global_tasks = self.global_templates_from_settings();
|
||||||
let language_tasks = language
|
let language_tasks = language
|
||||||
.and_then(|language| language.context_provider()?.associated_tasks(file, cx))
|
.and_then(|language| language.context_provider()?.associated_tasks(file, cx))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|tasks| tasks.0.into_iter())
|
.flat_map(|tasks| tasks.0.into_iter())
|
||||||
.flat_map(|task| Some((task_source_kind.clone()?, task)));
|
.flat_map(|task| Some((task_source_kind.clone()?, task)))
|
||||||
let new_resolved_tasks = self
|
.chain(global_tasks);
|
||||||
.templates_from_settings(worktree)
|
let worktree_tasks = self
|
||||||
.chain(language_tasks)
|
.worktree_templates_from_settings(worktree)
|
||||||
|
.chain(language_tasks);
|
||||||
|
|
||||||
|
let new_resolved_tasks = worktree_tasks
|
||||||
.filter_map(|(kind, task)| {
|
.filter_map(|(kind, task)| {
|
||||||
let id_base = kind.to_id_base();
|
let id_base = kind.to_id_base();
|
||||||
Some((
|
Some((
|
||||||
|
@ -235,9 +242,8 @@ impl Inventory {
|
||||||
self.last_scheduled_tasks.retain(|(_, task)| &task.id != id);
|
self.last_scheduled_tasks.retain(|(_, task)| &task.id != id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn templates_from_settings(
|
fn global_templates_from_settings(
|
||||||
&self,
|
&self,
|
||||||
worktree: Option<WorktreeId>,
|
|
||||||
) -> impl '_ + Iterator<Item = (TaskSourceKind, TaskTemplate)> {
|
) -> impl '_ + Iterator<Item = (TaskSourceKind, TaskTemplate)> {
|
||||||
self.templates_from_settings
|
self.templates_from_settings
|
||||||
.global
|
.global
|
||||||
|
@ -252,28 +258,34 @@ impl Inventory {
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.chain(worktree.into_iter().flat_map(|worktree| {
|
}
|
||||||
self.templates_from_settings
|
|
||||||
.worktree
|
fn worktree_templates_from_settings(
|
||||||
.get(&worktree)
|
&self,
|
||||||
.into_iter()
|
worktree: Option<WorktreeId>,
|
||||||
.flatten()
|
) -> impl '_ + Iterator<Item = (TaskSourceKind, TaskTemplate)> {
|
||||||
.flat_map(|(directory, templates)| {
|
worktree.into_iter().flat_map(|worktree| {
|
||||||
templates.iter().map(move |template| (directory, template))
|
self.templates_from_settings
|
||||||
})
|
.worktree
|
||||||
.map(move |(directory, template)| {
|
.get(&worktree)
|
||||||
(
|
.into_iter()
|
||||||
TaskSourceKind::Worktree {
|
.flatten()
|
||||||
id: worktree,
|
.flat_map(|(directory, templates)| {
|
||||||
directory_in_worktree: directory.to_path_buf(),
|
templates.iter().map(move |template| (directory, template))
|
||||||
id_base: Cow::Owned(format!(
|
})
|
||||||
"local worktree tasks from directory {directory:?}"
|
.map(move |(directory, template)| {
|
||||||
)),
|
(
|
||||||
},
|
TaskSourceKind::Worktree {
|
||||||
template.clone(),
|
id: worktree,
|
||||||
)
|
directory_in_worktree: directory.to_path_buf(),
|
||||||
})
|
id_base: Cow::Owned(format!(
|
||||||
}))
|
"local worktree tasks from directory {directory:?}"
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
template.clone(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates in-memory task metadata from the JSON string given.
|
/// Updates in-memory task metadata from the JSON string given.
|
||||||
|
@ -407,6 +419,25 @@ mod test_inventory {
|
||||||
inventory: &Model<Inventory>,
|
inventory: &Model<Inventory>,
|
||||||
worktree: Option<WorktreeId>,
|
worktree: Option<WorktreeId>,
|
||||||
cx: &mut TestAppContext,
|
cx: &mut TestAppContext,
|
||||||
|
) -> Vec<(TaskSourceKind, String)> {
|
||||||
|
inventory.update(cx, |inventory, cx| {
|
||||||
|
let task_context = &TaskContext::default();
|
||||||
|
inventory
|
||||||
|
.list_tasks(None, None, worktree, cx)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(source_kind, task)| {
|
||||||
|
let id_base = source_kind.to_id_base();
|
||||||
|
Some((source_kind, task.resolve_task(&id_base, task_context)?))
|
||||||
|
})
|
||||||
|
.map(|(source_kind, resolved_task)| (source_kind, resolved_task.resolved_label))
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn list_tasks_sorted_by_last_used(
|
||||||
|
inventory: &Model<Inventory>,
|
||||||
|
worktree: Option<WorktreeId>,
|
||||||
|
cx: &mut TestAppContext,
|
||||||
) -> Vec<(TaskSourceKind, String)> {
|
) -> Vec<(TaskSourceKind, String)> {
|
||||||
let (used, current) = inventory.update(cx, |inventory, cx| {
|
let (used, current) = inventory.update(cx, |inventory, cx| {
|
||||||
inventory.used_and_current_resolved_tasks(worktree, None, &TaskContext::default(), cx)
|
inventory.used_and_current_resolved_tasks(worktree, None, &TaskContext::default(), cx)
|
||||||
|
@ -789,6 +820,30 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
list_tasks_sorted_by_last_used(&inventory, None, cx).await,
|
||||||
|
worktree_independent_tasks,
|
||||||
|
"Without a worktree, only worktree-independent tasks should be listed"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
list_tasks_sorted_by_last_used(&inventory, Some(worktree_1), cx).await,
|
||||||
|
worktree_1_tasks
|
||||||
|
.iter()
|
||||||
|
.chain(worktree_independent_tasks.iter())
|
||||||
|
.cloned()
|
||||||
|
.sorted_by_key(|(kind, label)| (task_source_kind_preference(kind), label.clone()))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
list_tasks_sorted_by_last_used(&inventory, Some(worktree_2), cx).await,
|
||||||
|
worktree_2_tasks
|
||||||
|
.iter()
|
||||||
|
.chain(worktree_independent_tasks.iter())
|
||||||
|
.cloned()
|
||||||
|
.sorted_by_key(|(kind, label)| (task_source_kind_preference(kind), label.clone()))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
list_tasks(&inventory, None, cx).await,
|
list_tasks(&inventory, None, cx).await,
|
||||||
worktree_independent_tasks,
|
worktree_independent_tasks,
|
||||||
|
@ -800,7 +855,6 @@ mod tests {
|
||||||
.iter()
|
.iter()
|
||||||
.chain(worktree_independent_tasks.iter())
|
.chain(worktree_independent_tasks.iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.sorted_by_key(|(kind, label)| (task_source_kind_preference(kind), label.clone()))
|
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -809,7 +863,6 @@ mod tests {
|
||||||
.iter()
|
.iter()
|
||||||
.chain(worktree_independent_tasks.iter())
|
.chain(worktree_independent_tasks.iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.sorted_by_key(|(kind, label)| (task_source_kind_preference(kind), label.clone()))
|
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue