tasks: Add spawn option by tag (#25650)

Closes #19497
Fixed conflicts from https://github.com/zed-industries/zed/pull/19498
Added tags to tasks selector

Release Notes:

- Added ability to spawn tasks by tag with key bindings
- Added tags to tasks selector


https://github.com/user-attachments/assets/0eefea21-ec4e-407c-9d4f-2a0a4a0f74df

---------

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
Artem Evsikov 2025-04-04 17:20:09 +03:00 committed by GitHub
parent 80441f675b
commit 2f5a4f7e80
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 174 additions and 33 deletions

View file

@ -6,8 +6,10 @@ use editor::Editor;
use feature_flags::{Debugger, FeatureFlagViewExt};
use gpui::{App, AppContext as _, Context, Entity, Task, Window};
use modal::{TaskOverrides, TasksModal};
use project::{Location, TaskContexts, Worktree};
use task::{RevealTarget, TaskContext, TaskId, TaskModal, TaskVariables, VariableName};
use project::{Location, TaskContexts, TaskSourceKind, Worktree};
use task::{
RevealTarget, TaskContext, TaskId, TaskModal, TaskTemplate, TaskVariables, VariableName,
};
use workspace::tasks::schedule_task;
use workspace::{Workspace, tasks::schedule_resolved_task};
@ -117,7 +119,25 @@ fn spawn_task_or_modal(
let overrides = reveal_target.map(|reveal_target| TaskOverrides {
reveal_target: Some(reveal_target),
});
spawn_task_with_name(task_name.clone(), overrides, window, cx).detach_and_log_err(cx)
let name = task_name.clone();
spawn_tasks_filtered(move |(_, task)| task.label.eq(&name), overrides, window, cx)
.detach_and_log_err(cx)
}
Spawn::ByTag {
task_tag,
reveal_target,
} => {
let overrides = reveal_target.map(|reveal_target| TaskOverrides {
reveal_target: Some(reveal_target),
});
let tag = task_tag.clone();
spawn_tasks_filtered(
move |(_, task)| task.tags.contains(&tag),
overrides,
window,
cx,
)
.detach_and_log_err(cx)
}
Spawn::ViaModal { reveal_target } => toggle_modal(
workspace,
@ -169,18 +189,21 @@ pub fn toggle_modal(
}
}
fn spawn_task_with_name(
name: String,
fn spawn_tasks_filtered<F>(
mut predicate: F,
overrides: Option<TaskOverrides>,
window: &mut Window,
cx: &mut Context<Workspace>,
) -> Task<anyhow::Result<()>> {
) -> Task<anyhow::Result<()>>
where
F: FnMut((&TaskSourceKind, &TaskTemplate)) -> bool + 'static,
{
cx.spawn_in(window, async move |workspace, cx| {
let task_contexts = workspace.update_in(cx, |workspace, window, cx| {
task_contexts(workspace, window, cx)
})?;
let task_contexts = task_contexts.await;
let tasks = workspace.update(cx, |workspace, cx| {
let mut tasks = workspace.update(cx, |workspace, cx| {
let Some(task_inventory) = workspace
.project()
.read(cx)
@ -208,24 +231,31 @@ fn spawn_task_with_name(
let did_spawn = workspace
.update(cx, |workspace, cx| {
let (task_source_kind, mut target_task) =
tasks.into_iter().find(|(_, task)| task.label == name)?;
if let Some(overrides) = &overrides {
if let Some(target_override) = overrides.reveal_target {
target_task.reveal_target = target_override;
}
}
let default_context = TaskContext::default();
let active_context = task_contexts.active_context().unwrap_or(&default_context);
schedule_task(
workspace,
task_source_kind,
&target_task,
active_context,
false,
cx,
);
Some(())
tasks.retain_mut(|(task_source_kind, target_task)| {
if predicate((task_source_kind, target_task)) {
if let Some(overrides) = &overrides {
if let Some(target_override) = overrides.reveal_target {
target_task.reveal_target = target_override;
}
}
schedule_task(
workspace,
task_source_kind.clone(),
target_task,
active_context,
false,
cx,
);
true
} else {
false
}
});
if tasks.is_empty() { None } else { Some(()) }
})?
.is_some();
if !did_spawn {