Task::spawn now takes an optional task name as an argument.

If it is not set, we fall back to opening a modal. This allows user to spawn tasks via keybind.
This commit is contained in:
Piotr Osiewicz 2024-03-08 14:26:12 +01:00
parent fa5dfe19f8
commit bf295eac90
2 changed files with 65 additions and 16 deletions

View file

@ -3,7 +3,7 @@ use std::{collections::HashMap, path::PathBuf};
use editor::Editor;
use gpui::{AppContext, ViewContext, WindowContext};
use language::Point;
use modal::TasksModal;
use modal::{Spawn, TasksModal};
use project::{Location, WorktreeId};
use task::{Task, TaskContext};
use util::ResultExt;
@ -15,15 +15,7 @@ pub fn init(cx: &mut AppContext) {
cx.observe_new_views(
|workspace: &mut Workspace, _: &mut ViewContext<Workspace>| {
workspace
.register_action(|workspace, _: &modal::Spawn, cx| {
let inventory = workspace.project().read(cx).task_inventory().clone();
let workspace_handle = workspace.weak_handle();
let cwd = task_cwd(workspace, cx).log_err().flatten();
let task_context = task_context(workspace, cwd, cx);
workspace.toggle_modal(cx, |cx| {
TasksModal::new(inventory, task_context, workspace_handle, cx)
})
})
.register_action(spawn_task_or_modal)
.register_action(move |workspace, action: &modal::Rerun, cx| {
if let Some((task, old_context)) =
workspace.project().update(cx, |project, cx| {
@ -47,6 +39,54 @@ pub fn init(cx: &mut AppContext) {
.detach();
}
fn spawn_task_or_modal(workspace: &mut Workspace, action: &Spawn, cx: &mut ViewContext<Workspace>) {
let inventory = workspace.project().read(cx).task_inventory().clone();
let workspace_handle = workspace.weak_handle();
let cwd = task_cwd(workspace, cx).log_err().flatten();
let task_context = task_context(workspace, cwd, cx);
if let Some(name) = action.task_name.clone() {
// Do not actually show the modal.
spawn_task_with_name(name.clone(), cx);
} else {
workspace.toggle_modal(cx, |cx| {
TasksModal::new(inventory, task_context, workspace_handle, cx)
})
}
}
fn spawn_task_with_name(name: String, cx: &mut ViewContext<Workspace>) {
cx.spawn(|workspace, mut cx| async move {
let did_spawn = workspace
.update(&mut cx, |this, cx| {
let active_item = this
.active_item(cx)
.and_then(|item| item.project_path(cx))
.map(|path| path.worktree_id);
let tasks = this.project().update(cx, |project, cx| {
project.task_inventory().update(cx, |inventory, cx| {
inventory.list_tasks(None, active_item, false, cx)
})
});
let (_, target_task) = tasks.into_iter().find(|(_, task)| task.name() == name)?;
let cwd = task_cwd(this, cx).log_err().flatten();
let task_context = task_context(this, cwd, cx);
schedule_task(this, target_task.as_ref(), task_context, cx);
Some(())
})
.ok()
.flatten()
.is_some();
if !did_spawn {
workspace
.update(&mut cx, |workspace, cx| {
spawn_task_or_modal(workspace, &Spawn::default(), cx);
})
.ok();
}
})
.detach();
}
fn task_context(
workspace: &Workspace,
cwd: Option<PathBuf>,

View file

@ -2,9 +2,9 @@ use std::{path::PathBuf, sync::Arc};
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
actions, impl_actions, rems, AppContext, DismissEvent, EventEmitter, FocusableView,
InteractiveElement, Model, ParentElement, Render, SharedString, Styled, Subscription, View,
ViewContext, VisualContext, WeakView,
impl_actions, rems, AppContext, DismissEvent, EventEmitter, FocusableView, InteractiveElement,
Model, ParentElement, Render, SharedString, Styled, Subscription, View, ViewContext,
VisualContext, WeakView,
};
use picker::{
highlighted_match_with_paths::{HighlightedMatchWithPaths, HighlightedText},
@ -18,7 +18,16 @@ use workspace::{ModalView, Workspace};
use crate::schedule_task;
use serde::Deserialize;
actions!(task, [Spawn]);
/// Spawn a task with name or open tasks modal
#[derive(PartialEq, Clone, Deserialize, Default)]
pub struct Spawn {
#[serde(default)]
/// Name of the task to spawn.
/// If it is not set, a modal with a list of available tasks is opened instead.
/// Defaults to None.
pub task_name: Option<String>,
}
/// Rerun last task
#[derive(PartialEq, Clone, Deserialize, Default)]
@ -31,7 +40,7 @@ pub struct Rerun {
pub reevaluate_context: bool,
}
impl_actions!(task, [Rerun]);
impl_actions!(task, [Rerun, Spawn]);
/// A modal used to spawn new tasks.
pub(crate) struct TasksModalDelegate {
@ -426,7 +435,7 @@ mod tests {
workspace: &View<Workspace>,
cx: &mut VisualTestContext,
) -> View<Picker<TasksModalDelegate>> {
cx.dispatch_action(crate::modal::Spawn);
cx.dispatch_action(crate::modal::Spawn::default());
workspace.update(cx, |workspace, cx| {
workspace
.active_modal::<TasksModal>(cx)