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

@ -2,6 +2,7 @@
#![deny(missing_docs)]
mod debug_format;
mod serde_helpers;
pub mod static_source;
mod task_template;
mod vscode_format;

View file

@ -0,0 +1,64 @@
use schemars::{
SchemaGenerator,
schema::{ArrayValidation, InstanceType, Schema, SchemaObject, SingleOrVec, StringValidation},
};
use serde::de::{self, Deserializer, Visitor};
use std::fmt;
/// Generates a JSON schema for a non-empty string array.
pub fn non_empty_string_vec_json_schema(_: &mut SchemaGenerator) -> Schema {
Schema::Object(SchemaObject {
instance_type: Some(InstanceType::Array.into()),
array: Some(Box::new(ArrayValidation {
unique_items: Some(true),
items: Some(SingleOrVec::Single(Box::new(Schema::Object(
SchemaObject {
instance_type: Some(InstanceType::String.into()),
string: Some(Box::new(StringValidation {
min_length: Some(1), // Ensures string in the array is non-empty
..Default::default()
})),
..Default::default()
},
)))),
..Default::default()
})),
format: Some("vec-of-non-empty-strings".to_string()), // Use a custom format keyword
..Default::default()
})
}
/// Deserializes a non-empty string array.
pub fn non_empty_string_vec<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
D: Deserializer<'de>,
{
struct NonEmptyStringVecVisitor;
impl<'de> Visitor<'de> for NonEmptyStringVecVisitor {
type Value = Vec<String>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a list of non-empty strings")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Vec<String>, V::Error>
where
V: de::SeqAccess<'de>,
{
let mut vec = Vec::new();
while let Some(value) = seq.next_element::<String>()? {
if value.is_empty() {
return Err(de::Error::invalid_value(
de::Unexpected::Str(&value),
&"a non-empty string",
));
}
vec.push(value);
}
Ok(vec)
}
}
deserializer.deserialize_seq(NonEmptyStringVecVisitor)
}

View file

@ -1,16 +1,16 @@
use std::path::PathBuf;
use util::serde::default_true;
use anyhow::{Context, bail};
use collections::{HashMap, HashSet};
use schemars::{JsonSchema, r#gen::SchemaSettings};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::path::PathBuf;
use util::serde::default_true;
use util::{ResultExt, truncate_and_remove_front};
use crate::{
AttachConfig, ResolvedTask, RevealTarget, Shell, SpawnInTerminal, TCPHost, TaskContext, TaskId,
VariableName, ZED_VARIABLE_NAME_PREFIX,
serde_helpers::{non_empty_string_vec, non_empty_string_vec_json_schema},
};
/// A template definition of a Zed task to run.
@ -61,8 +61,10 @@ pub struct TaskTemplate {
/// If this task should start a debugger or not
#[serde(default, skip)]
pub task_type: TaskType,
/// Represents the tags which this template attaches to. Adding this removes this task from other UI.
#[serde(default)]
/// Represents the tags which this template attaches to.
/// Adding this removes this task from other UI and gives you ability to run it by tag.
#[serde(default, deserialize_with = "non_empty_string_vec")]
#[schemars(schema_with = "non_empty_string_vec_json_schema")]
pub tags: Vec<String>,
/// Which shell to use when spawning the task.
#[serde(default)]