Rename runnables into tasks (#8119)

Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2024-02-21 14:56:43 +02:00 committed by GitHub
parent 45e2c01773
commit 2679457b02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 316 additions and 332 deletions

98
Cargo.lock generated
View file

@ -6898,7 +6898,6 @@ dependencies = [
"regex", "regex",
"release_channel", "release_channel",
"rpc", "rpc",
"runnable",
"schemars", "schemars",
"serde", "serde",
"serde_derive", "serde_derive",
@ -6908,6 +6907,7 @@ dependencies = [
"similar", "similar",
"smol", "smol",
"sum_tree", "sum_tree",
"task",
"tempfile", "tempfile",
"terminal", "terminal",
"text", "text",
@ -7756,49 +7756,6 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "runnable"
version = "0.1.0"
dependencies = [
"anyhow",
"collections",
"futures 0.3.28",
"gpui",
"parking_lot 0.11.2",
"schemars",
"serde",
"serde_json",
"serde_json_lenient",
"settings",
"smol",
"util",
]
[[package]]
name = "runnables_ui"
version = "0.1.0"
dependencies = [
"anyhow",
"db",
"editor",
"fs",
"futures 0.3.28",
"fuzzy",
"gpui",
"log",
"menu",
"picker",
"project",
"runnable",
"schemars",
"serde",
"serde_json",
"theme",
"ui",
"util",
"workspace",
]
[[package]] [[package]]
name = "rusqlite" name = "rusqlite"
version = "0.29.0" version = "0.29.0"
@ -9371,6 +9328,49 @@ version = "0.12.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae"
[[package]]
name = "task"
version = "0.1.0"
dependencies = [
"anyhow",
"collections",
"futures 0.3.28",
"gpui",
"parking_lot 0.11.2",
"schemars",
"serde",
"serde_json",
"serde_json_lenient",
"settings",
"smol",
"util",
]
[[package]]
name = "tasks_ui"
version = "0.1.0"
dependencies = [
"anyhow",
"db",
"editor",
"fs",
"futures 0.3.28",
"fuzzy",
"gpui",
"log",
"menu",
"picker",
"project",
"schemars",
"serde",
"serde_json",
"task",
"theme",
"ui",
"util",
"workspace",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.9.0" version = "3.9.0"
@ -9422,7 +9422,6 @@ dependencies = [
"ordered-float 2.10.0", "ordered-float 2.10.0",
"procinfo", "procinfo",
"rand 0.8.5", "rand 0.8.5",
"runnable",
"schemars", "schemars",
"serde", "serde",
"serde_derive", "serde_derive",
@ -9431,6 +9430,7 @@ dependencies = [
"shellexpand", "shellexpand",
"smallvec", "smallvec",
"smol", "smol",
"task",
"theme", "theme",
"thiserror", "thiserror",
"util", "util",
@ -9457,7 +9457,6 @@ dependencies = [
"procinfo", "procinfo",
"project", "project",
"rand 0.8.5", "rand 0.8.5",
"runnable",
"search", "search",
"serde", "serde",
"serde_derive", "serde_derive",
@ -9466,6 +9465,7 @@ dependencies = [
"shellexpand", "shellexpand",
"smallvec", "smallvec",
"smol", "smol",
"task",
"terminal", "terminal",
"theme", "theme",
"thiserror", "thiserror",
@ -11724,7 +11724,6 @@ dependencies = [
"parking_lot 0.11.2", "parking_lot 0.11.2",
"postage", "postage",
"project", "project",
"runnable",
"schemars", "schemars",
"serde", "serde",
"serde_derive", "serde_derive",
@ -11732,6 +11731,7 @@ dependencies = [
"settings", "settings",
"smallvec", "smallvec",
"sqlez", "sqlez",
"task",
"terminal", "terminal",
"theme", "theme",
"ui", "ui",
@ -11985,8 +11985,6 @@ dependencies = [
"rope", "rope",
"rpc", "rpc",
"rsa 0.4.0", "rsa 0.4.0",
"runnable",
"runnables_ui",
"rust-embed", "rust-embed",
"schemars", "schemars",
"search", "search",
@ -12000,6 +11998,8 @@ dependencies = [
"smallvec", "smallvec",
"smol", "smol",
"sum_tree", "sum_tree",
"task",
"tasks_ui",
"tempfile", "tempfile",
"terminal_view", "terminal_view",
"text", "text",

View file

@ -63,8 +63,8 @@ members = [
"crates/rich_text", "crates/rich_text",
"crates/rope", "crates/rope",
"crates/rpc", "crates/rpc",
"crates/runnable", "crates/task",
"crates/runnables_ui", "crates/tasks_ui",
"crates/search", "crates/search",
"crates/semantic_index", "crates/semantic_index",
"crates/settings", "crates/settings",
@ -155,8 +155,8 @@ release_channel = { path = "crates/release_channel" }
rich_text = { path = "crates/rich_text" } rich_text = { path = "crates/rich_text" }
rope = { path = "crates/rope" } rope = { path = "crates/rope" }
rpc = { path = "crates/rpc" } rpc = { path = "crates/rpc" }
runnable = { path = "crates/runnable" } task = { path = "crates/task" }
runnables_ui = { path = "crates/runnables_ui" } tasks_ui = { path = "crates/tasks_ui" }
search = { path = "crates/search" } search = { path = "crates/search" }
semantic_index = { path = "crates/semantic_index" } semantic_index = { path = "crates/semantic_index" }
settings = { path = "crates/settings" } settings = { path = "crates/settings" }

View file

@ -1,9 +1,9 @@
// Static runnables configuration. // Static tasks configuration.
// //
// Example: // Example:
// { // {
// "version": "1", // "version": "1",
// "runnables": [ // "tasks": [
// { // {
// "label": "human-readable label for UI", // "label": "human-readable label for UI",
// "command": "bash", // "command": "bash",
@ -15,7 +15,7 @@
// "cwd": "/path/to/working/directory", // "cwd": "/path/to/working/directory",
// // Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`. // // Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`.
// "use_new_terminal": false, // "use_new_terminal": false,
// // Whether to allow multiple instances of the same runnable to be run, or rather wait for the existing ones to finish, defaults to `false`. // // Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish, defaults to `false`.
// "allow_concurrent_runs": false // "allow_concurrent_runs": false
// } // }
// ] // ]
@ -23,5 +23,5 @@
// //
{ {
"version": "1", "version": "1",
"runnables": [] "tasks": []
} }

View file

@ -50,7 +50,7 @@ prettier.workspace = true
rand.workspace = true rand.workspace = true
regex.workspace = true regex.workspace = true
rpc.workspace = true rpc.workspace = true
runnable.workspace = true task.workspace = true
schemars.workspace = true schemars.workspace = true
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true

View file

@ -4,8 +4,8 @@ pub mod lsp_command;
pub mod lsp_ext_command; pub mod lsp_ext_command;
mod prettier_support; mod prettier_support;
pub mod project_settings; pub mod project_settings;
mod runnable_inventory;
pub mod search; pub mod search;
mod task_inventory;
pub mod terminals; pub mod terminals;
pub mod worktree; pub mod worktree;
@ -94,7 +94,7 @@ use util::{
pub use fs::*; pub use fs::*;
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX; pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
pub use runnable_inventory::Inventory; pub use task_inventory::Inventory;
pub use worktree::*; pub use worktree::*;
const MAX_SERVER_REINSTALL_ATTEMPT_COUNT: u64 = 4; const MAX_SERVER_REINSTALL_ATTEMPT_COUNT: u64 = 4;
@ -158,7 +158,7 @@ pub struct Project {
default_prettier: DefaultPrettier, default_prettier: DefaultPrettier,
prettiers_per_worktree: HashMap<WorktreeId, HashSet<Option<PathBuf>>>, prettiers_per_worktree: HashMap<WorktreeId, HashSet<Option<PathBuf>>>,
prettier_instances: HashMap<PathBuf, PrettierInstance>, prettier_instances: HashMap<PathBuf, PrettierInstance>,
runnables: Model<Inventory>, tasks: Model<Inventory>,
} }
pub enum LanguageServerToQuery { pub enum LanguageServerToQuery {
@ -621,7 +621,7 @@ impl Project {
.detach(); .detach();
let copilot_lsp_subscription = let copilot_lsp_subscription =
Copilot::global(cx).map(|copilot| subscribe_for_copilot_events(&copilot, cx)); Copilot::global(cx).map(|copilot| subscribe_for_copilot_events(&copilot, cx));
let runnables = Inventory::new(cx); let tasks = Inventory::new(cx);
Self { Self {
worktrees: Vec::new(), worktrees: Vec::new(),
@ -673,7 +673,7 @@ impl Project {
default_prettier: DefaultPrettier::default(), default_prettier: DefaultPrettier::default(),
prettiers_per_worktree: HashMap::default(), prettiers_per_worktree: HashMap::default(),
prettier_instances: HashMap::default(), prettier_instances: HashMap::default(),
runnables, tasks,
} }
}) })
} }
@ -697,7 +697,7 @@ impl Project {
.await?; .await?;
let this = cx.new_model(|cx| { let this = cx.new_model(|cx| {
let replica_id = response.payload.replica_id as ReplicaId; let replica_id = response.payload.replica_id as ReplicaId;
let runnables = Inventory::new(cx); let tasks = Inventory::new(cx);
// BIG CAUTION NOTE: The order in which we initialize fields here matters and it should match what's done in Self::local. // BIG CAUTION NOTE: The order in which we initialize fields here matters and it should match what's done in Self::local.
// Otherwise, you might run into issues where worktree id on remote is different than what's on local host. // Otherwise, you might run into issues where worktree id on remote is different than what's on local host.
// That's because Worktree's identifier is entity id, which should probably be changed. // That's because Worktree's identifier is entity id, which should probably be changed.
@ -782,7 +782,7 @@ impl Project {
default_prettier: DefaultPrettier::default(), default_prettier: DefaultPrettier::default(),
prettiers_per_worktree: HashMap::default(), prettiers_per_worktree: HashMap::default(),
prettier_instances: HashMap::default(), prettier_instances: HashMap::default(),
runnables, tasks,
}; };
this.set_role(role, cx); this.set_role(role, cx);
for worktree in worktrees { for worktree in worktrees {
@ -1065,8 +1065,8 @@ impl Project {
cx.notify(); cx.notify();
} }
pub fn runnable_inventory(&self) -> &Model<Inventory> { pub fn task_inventory(&self) -> &Model<Inventory> {
&self.runnables &self.tasks
} }
pub fn collaborators(&self) -> &HashMap<proto::PeerId, Collaborator> { pub fn collaborators(&self) -> &HashMap<proto::PeerId, Collaborator> {

View file

@ -1,14 +1,14 @@
//! Project-wide storage of the runnables available, capable of updating itself from the sources set. //! Project-wide storage of the tasks available, capable of updating itself from the sources set.
use std::{any::TypeId, path::Path, sync::Arc}; use std::{any::TypeId, path::Path, sync::Arc};
use gpui::{AppContext, Context, Model, ModelContext, Subscription}; use gpui::{AppContext, Context, Model, ModelContext, Subscription};
use runnable::{Runnable, RunnableId, Source}; use task::{Source, Task, TaskId};
/// Inventory tracks available runnables for a given project. /// Inventory tracks available tasks for a given project.
pub struct Inventory { pub struct Inventory {
sources: Vec<SourceInInventory>, sources: Vec<SourceInInventory>,
pub last_scheduled_runnable: Option<RunnableId>, pub last_scheduled_task: Option<TaskId>,
} }
struct SourceInInventory { struct SourceInInventory {
@ -21,11 +21,11 @@ impl Inventory {
pub(crate) fn new(cx: &mut AppContext) -> Model<Self> { pub(crate) fn new(cx: &mut AppContext) -> Model<Self> {
cx.new_model(|_| Self { cx.new_model(|_| Self {
sources: Vec::new(), sources: Vec::new(),
last_scheduled_runnable: None, last_scheduled_task: None,
}) })
} }
/// Registers a new runnables source, that would be fetched for available runnables. /// Registers a new tasks source, that would be fetched for available tasks.
pub fn add_source(&mut self, source: Model<Box<dyn Source>>, cx: &mut ModelContext<Self>) { pub fn add_source(&mut self, source: Model<Box<dyn Source>>, cx: &mut ModelContext<Self>) {
let _subscription = cx.observe(&source, |_, _, cx| { let _subscription = cx.observe(&source, |_, _, cx| {
cx.notify(); cx.notify();
@ -55,29 +55,25 @@ impl Inventory {
} }
/// Pulls its sources to list runanbles for the path given (up to the source to decide what to return for no path). /// Pulls its sources to list runanbles for the path given (up to the source to decide what to return for no path).
pub fn list_runnables( pub fn list_tasks(&self, path: Option<&Path>, cx: &mut AppContext) -> Vec<Arc<dyn Task>> {
&self, let mut tasks = Vec::new();
path: Option<&Path>,
cx: &mut AppContext,
) -> Vec<Arc<dyn Runnable>> {
let mut runnables = Vec::new();
for source in &self.sources { for source in &self.sources {
runnables.extend( tasks.extend(
source source
.source .source
.update(cx, |source, cx| source.runnables_for_path(path, cx)), .update(cx, |source, cx| source.tasks_for_path(path, cx)),
); );
} }
runnables tasks
} }
/// Returns the last scheduled runnable, if any of the sources contains one with the matching id. /// Returns the last scheduled task, if any of the sources contains one with the matching id.
pub fn last_scheduled_runnable(&self, cx: &mut AppContext) -> Option<Arc<dyn Runnable>> { pub fn last_scheduled_task(&self, cx: &mut AppContext) -> Option<Arc<dyn Task>> {
self.last_scheduled_runnable.as_ref().and_then(|id| { self.last_scheduled_task.as_ref().and_then(|id| {
// TODO straighten the `Path` story to understand what has to be passed here: or it will break in the future. // TODO straighten the `Path` story to understand what has to be passed here: or it will break in the future.
self.list_runnables(None, cx) self.list_tasks(None, cx)
.into_iter() .into_iter()
.find(|runnable| runnable.id() == id) .find(|task| task.id() == id)
}) })
} }
} }

View file

@ -5,7 +5,7 @@ use smol::channel::bounded;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use terminal::{ use terminal::{
terminal_settings::{self, Shell, TerminalSettings, VenvSettingsContent}, terminal_settings::{self, Shell, TerminalSettings, VenvSettingsContent},
RunableState, SpawnRunnable, Terminal, TerminalBuilder, SpawnTask, TaskState, Terminal, TerminalBuilder,
}; };
// #[cfg(target_os = "macos")] // #[cfg(target_os = "macos")]
@ -19,7 +19,7 @@ impl Project {
pub fn create_terminal( pub fn create_terminal(
&mut self, &mut self,
working_directory: Option<PathBuf>, working_directory: Option<PathBuf>,
spawn_runnable: Option<SpawnRunnable>, spawn_task: Option<SpawnTask>,
window: AnyWindowHandle, window: AnyWindowHandle,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> anyhow::Result<Model<Terminal>> { ) -> anyhow::Result<Model<Terminal>> {
@ -32,18 +32,18 @@ impl Project {
let python_settings = settings.detect_venv.clone(); let python_settings = settings.detect_venv.clone();
let (completion_tx, completion_rx) = bounded(1); let (completion_tx, completion_rx) = bounded(1);
let mut env = settings.env.clone(); let mut env = settings.env.clone();
let (spawn_runnable, shell) = if let Some(spawn_runnable) = spawn_runnable { let (spawn_task, shell) = if let Some(spawn_task) = spawn_task {
env.extend(spawn_runnable.env); env.extend(spawn_task.env);
( (
Some(RunableState { Some(TaskState {
id: spawn_runnable.id, id: spawn_task.id,
label: spawn_runnable.label, label: spawn_task.label,
completed: false, completed: false,
completion_rx, completion_rx,
}), }),
Shell::WithArguments { Shell::WithArguments {
program: spawn_runnable.command, program: spawn_task.command,
args: spawn_runnable.args, args: spawn_task.args,
}, },
) )
} else { } else {
@ -52,7 +52,7 @@ impl Project {
let terminal = TerminalBuilder::new( let terminal = TerminalBuilder::new(
working_directory.clone(), working_directory.clone(),
spawn_runnable, spawn_task,
shell, shell,
env, env,
Some(settings.blinking.clone()), Some(settings.blinking.clone()),

View file

@ -43,6 +43,6 @@ pub fn initial_local_settings_content() -> Cow<'static, str> {
asset_str::<SettingsAssets>("settings/initial_local_settings.json") asset_str::<SettingsAssets>("settings/initial_local_settings.json")
} }
pub fn initial_runnables_content() -> Cow<'static, str> { pub fn initial_tasks_content() -> Cow<'static, str> {
asset_str::<SettingsAssets>("settings/initial_runnables.json") asset_str::<SettingsAssets>("settings/initial_tasks.json")
} }

View file

@ -1,5 +1,5 @@
[package] [package]
name = "runnable" name = "task"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
publish = false publish = false

View file

@ -1,10 +1,10 @@
//! Baseline interface of Runnables in Zed: all runnables in Zed are intended to use those for implementing their own logic. //! Baseline interface of Tasks in Zed: all tasks in Zed are intended to use those for implementing their own logic.
#![deny(missing_docs)] #![deny(missing_docs)]
mod static_runnable;
pub mod static_source; pub mod static_source;
mod static_task;
pub use static_runnable::StaticRunnable; pub use static_task::StaticTask;
use collections::HashMap; use collections::HashMap;
use gpui::ModelContext; use gpui::ModelContext;
@ -12,16 +12,16 @@ use std::any::Any;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
/// Runnable identifier, unique within the application. /// Task identifier, unique within the application.
/// Based on it, runnable reruns and terminal tabs are managed. /// Based on it, task reruns and terminal tabs are managed.
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RunnableId(pub String); pub struct TaskId(pub String);
/// Contains all information needed by Zed to spawn a new terminal tab for the given runnable. /// Contains all information needed by Zed to spawn a new terminal tab for the given task.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SpawnInTerminal { pub struct SpawnInTerminal {
/// Id of the runnable to use when determining task tab affinity. /// Id of the task to use when determining task tab affinity.
pub id: RunnableId, pub id: TaskId,
/// Human readable name of the terminal tab. /// Human readable name of the terminal tab.
pub label: String, pub label: String,
/// Executable command to spawn. /// Executable command to spawn.
@ -34,37 +34,37 @@ pub struct SpawnInTerminal {
pub env: HashMap<String, String>, pub env: HashMap<String, String>,
/// Whether to use a new terminal tab or reuse the existing one to spawn the process. /// Whether to use a new terminal tab or reuse the existing one to spawn the process.
pub use_new_terminal: bool, pub use_new_terminal: bool,
/// Whether to allow multiple instances of the same runnable to be run, or rather wait for the existing ones to finish. /// Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish.
pub allow_concurrent_runs: bool, pub allow_concurrent_runs: bool,
/// Whether the command should be spawned in a separate shell instance. /// Whether the command should be spawned in a separate shell instance.
pub separate_shell: bool, pub separate_shell: bool,
} }
/// Represents a short lived recipe of a runnable, whose main purpose /// Represents a short lived recipe of a task, whose main purpose
/// is to get spawned. /// is to get spawned.
pub trait Runnable { pub trait Task {
/// Unique identifier of the runnable to spawn. /// Unique identifier of the task to spawn.
fn id(&self) -> &RunnableId; fn id(&self) -> &TaskId;
/// Human readable name of the runnable to display in the UI. /// Human readable name of the task to display in the UI.
fn name(&self) -> &str; fn name(&self) -> &str;
/// Task's current working directory. If `None`, current project's root will be used. /// Task's current working directory. If `None`, current project's root will be used.
fn cwd(&self) -> Option<&Path>; fn cwd(&self) -> Option<&Path>;
/// Sets up everything needed to spawn the runnable in the given directory (`cwd`). /// Sets up everything needed to spawn the task in the given directory (`cwd`).
/// If a runnable is intended to be spawned in the terminal, it should return the corresponding struct filled with the data necessary. /// If a task is intended to be spawned in the terminal, it should return the corresponding struct filled with the data necessary.
fn exec(&self, cwd: Option<PathBuf>) -> Option<SpawnInTerminal>; fn exec(&self, cwd: Option<PathBuf>) -> Option<SpawnInTerminal>;
} }
/// [`Source`] produces runnables that can be scheduled. /// [`Source`] produces tasks that can be scheduled.
/// ///
/// Implementations of this trait could be e.g. [`StaticSource`] that parses runnables from a .json files and provides process templates to be spawned; /// Implementations of this trait could be e.g. [`StaticSource`] that parses tasks from a .json files and provides process templates to be spawned;
/// another one could be a language server providing lenses with tests or build server listing all targets for a given project. /// another one could be a language server providing lenses with tests or build server listing all targets for a given project.
pub trait Source: Any { pub trait Source: Any {
/// A way to erase the type of the source, processing and storing them generically. /// A way to erase the type of the source, processing and storing them generically.
fn as_any(&mut self) -> &mut dyn Any; fn as_any(&mut self) -> &mut dyn Any;
/// Collects all runnables available for scheduling, for the path given. /// Collects all tasks available for scheduling, for the path given.
fn runnables_for_path( fn tasks_for_path(
&mut self, &mut self,
path: Option<&Path>, path: Option<&Path>,
cx: &mut ModelContext<Box<dyn Source>>, cx: &mut ModelContext<Box<dyn Source>>,
) -> Vec<Arc<dyn Runnable>>; ) -> Vec<Arc<dyn Task>>;
} }

View file

@ -1,4 +1,4 @@
//! A source of runnables, based on a static configuration, deserialized from the runnables config file, and related infrastructure for tracking changes to the file. //! A source of tasks, based on a static configuration, deserialized from the tasks config file, and related infrastructure for tracking changes to the file.
use std::{ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -12,20 +12,20 @@ use schemars::{gen::SchemaSettings, JsonSchema};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use util::ResultExt; use util::ResultExt;
use crate::{Runnable, Source, StaticRunnable}; use crate::{Source, StaticTask, Task};
use futures::channel::mpsc::UnboundedReceiver; use futures::channel::mpsc::UnboundedReceiver;
/// The source of runnables defined in a runnables config file. /// The source of tasks defined in a tasks config file.
pub struct StaticSource { pub struct StaticSource {
runnables: Vec<StaticRunnable>, tasks: Vec<StaticTask>,
_definitions: Model<TrackedFile<DefinitionProvider>>, _definitions: Model<TrackedFile<DefinitionProvider>>,
_subscription: Subscription, _subscription: Subscription,
} }
/// Static runnable definition from the runnables config file. /// Static task definition from the tasks config file.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub(crate) struct Definition { pub(crate) struct Definition {
/// Human readable name of the runnable to display in the UI. /// Human readable name of the task to display in the UI.
pub label: String, pub label: String,
/// Executable command to spawn. /// Executable command to spawn.
pub command: String, pub command: String,
@ -41,20 +41,20 @@ pub(crate) struct Definition {
/// Whether to use a new terminal tab or reuse the existing one to spawn the process. /// Whether to use a new terminal tab or reuse the existing one to spawn the process.
#[serde(default)] #[serde(default)]
pub use_new_terminal: bool, pub use_new_terminal: bool,
/// Whether to allow multiple instances of the same runnable to be run, or rather wait for the existing ones to finish. /// Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish.
#[serde(default)] #[serde(default)]
pub allow_concurrent_runs: bool, pub allow_concurrent_runs: bool,
} }
/// A group of Runnables defined in a JSON file. /// A group of Tasks defined in a JSON file.
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct DefinitionProvider { pub struct DefinitionProvider {
version: String, version: String,
runnables: Vec<Definition>, tasks: Vec<Definition>,
} }
impl DefinitionProvider { impl DefinitionProvider {
/// Generates JSON schema of Runnables JSON definition format. /// Generates JSON schema of Tasks JSON definition format.
pub fn generate_json_schema() -> serde_json_lenient::Value { pub fn generate_json_schema() -> serde_json_lenient::Value {
let schema = SchemaSettings::draft07() let schema = SchemaSettings::draft07()
.with(|settings| settings.option_add_null_type = false) .with(|settings| settings.option_add_null_type = false)
@ -107,33 +107,32 @@ impl<T: for<'a> Deserialize<'a> + PartialEq + 'static> TrackedFile<T> {
} }
impl StaticSource { impl StaticSource {
/// Initializes the static source, reacting on runnables config changes. /// Initializes the static source, reacting on tasks config changes.
pub fn new( pub fn new(
runnables_file_tracker: UnboundedReceiver<String>, tasks_file_tracker: UnboundedReceiver<String>,
cx: &mut AppContext, cx: &mut AppContext,
) -> Model<Box<dyn Source>> { ) -> Model<Box<dyn Source>> {
let definitions = let definitions = TrackedFile::new(DefinitionProvider::default(), tasks_file_tracker, cx);
TrackedFile::new(DefinitionProvider::default(), runnables_file_tracker, cx);
cx.new_model(|cx| { cx.new_model(|cx| {
let _subscription = cx.observe( let _subscription = cx.observe(
&definitions, &definitions,
|source: &mut Box<(dyn Source + 'static)>, new_definitions, cx| { |source: &mut Box<(dyn Source + 'static)>, new_definitions, cx| {
if let Some(static_source) = source.as_any().downcast_mut::<Self>() { if let Some(static_source) = source.as_any().downcast_mut::<Self>() {
static_source.runnables = new_definitions static_source.tasks = new_definitions
.read(cx) .read(cx)
.get() .get()
.runnables .tasks
.clone() .clone()
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(|(id, definition)| StaticRunnable::new(id, definition)) .map(|(id, definition)| StaticTask::new(id, definition))
.collect(); .collect();
cx.notify(); cx.notify();
} }
}, },
); );
Box::new(Self { Box::new(Self {
runnables: Vec::new(), tasks: Vec::new(),
_definitions: definitions, _definitions: definitions,
_subscription, _subscription,
}) })
@ -142,15 +141,15 @@ impl StaticSource {
} }
impl Source for StaticSource { impl Source for StaticSource {
fn runnables_for_path( fn tasks_for_path(
&mut self, &mut self,
_: Option<&Path>, _: Option<&Path>,
_: &mut ModelContext<Box<dyn Source>>, _: &mut ModelContext<Box<dyn Source>>,
) -> Vec<Arc<dyn Runnable>> { ) -> Vec<Arc<dyn Task>> {
self.runnables self.tasks
.clone() .clone()
.into_iter() .into_iter()
.map(|runnable| Arc::new(runnable) as Arc<dyn Runnable>) .map(|task| Arc::new(task) as Arc<dyn Task>)
.collect() .collect()
} }

View file

@ -1,26 +1,26 @@
//! Definitions of runnables with a static file config definition, not dependent on the application state. //! Definitions of tasks with a static file config definition, not dependent on the application state.
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use crate::{static_source::Definition, Runnable, RunnableId, SpawnInTerminal}; use crate::{static_source::Definition, SpawnInTerminal, Task, TaskId};
/// A single config file entry with the deserialized runnable definition. /// A single config file entry with the deserialized task definition.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct StaticRunnable { pub struct StaticTask {
id: RunnableId, id: TaskId,
definition: Definition, definition: Definition,
} }
impl StaticRunnable { impl StaticTask {
pub(super) fn new(id: usize, runnable: Definition) -> Self { pub(super) fn new(id: usize, task_definition: Definition) -> Self {
Self { Self {
id: RunnableId(format!("static_{}_{}", runnable.label, id)), id: TaskId(format!("static_{}_{}", task_definition.label, id)),
definition: runnable, definition: task_definition,
} }
} }
} }
impl Runnable for StaticRunnable { impl Task for StaticTask {
fn exec(&self, cwd: Option<PathBuf>) -> Option<SpawnInTerminal> { fn exec(&self, cwd: Option<PathBuf>) -> Option<SpawnInTerminal> {
Some(SpawnInTerminal { Some(SpawnInTerminal {
id: self.id.clone(), id: self.id.clone(),
@ -39,7 +39,7 @@ impl Runnable for StaticRunnable {
&self.definition.label &self.definition.label
} }
fn id(&self) -> &RunnableId { fn id(&self) -> &TaskId {
&self.id &self.id
} }

View file

@ -1,5 +1,5 @@
[package] [package]
name = "runnables_ui" name = "tasks_ui"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
publish = false publish = false
@ -17,7 +17,7 @@ log.workspace = true
menu.workspace = true menu.workspace = true
picker.workspace = true picker.workspace = true
project.workspace = true project.workspace = true
runnable.workspace = true task.workspace = true
schemars.workspace = true schemars.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true

View file

@ -1,9 +1,9 @@
use std::path::PathBuf; use std::path::PathBuf;
use gpui::{AppContext, ViewContext, WindowContext}; use gpui::{AppContext, ViewContext, WindowContext};
use modal::RunnablesModal; use modal::TasksModal;
pub use oneshot_source::OneshotSource; pub use oneshot_source::OneshotSource;
use runnable::Runnable; use task::Task;
use util::ResultExt; use util::ResultExt;
use workspace::Workspace; use workspace::Workspace;
@ -15,19 +15,18 @@ pub fn init(cx: &mut AppContext) {
|workspace: &mut Workspace, _: &mut ViewContext<Workspace>| { |workspace: &mut Workspace, _: &mut ViewContext<Workspace>| {
workspace workspace
.register_action(|workspace, _: &modal::Spawn, cx| { .register_action(|workspace, _: &modal::Spawn, cx| {
let inventory = workspace.project().read(cx).runnable_inventory().clone(); let inventory = workspace.project().read(cx).task_inventory().clone();
let workspace_handle = workspace.weak_handle(); let workspace_handle = workspace.weak_handle();
workspace.toggle_modal(cx, |cx| { workspace
RunnablesModal::new(inventory, workspace_handle, cx) .toggle_modal(cx, |cx| TasksModal::new(inventory, workspace_handle, cx))
})
}) })
.register_action(move |workspace, _: &modal::Rerun, cx| { .register_action(move |workspace, _: &modal::Rerun, cx| {
if let Some(runnable) = workspace.project().update(cx, |project, cx| { if let Some(task) = workspace.project().update(cx, |project, cx| {
project project
.runnable_inventory() .task_inventory()
.update(cx, |inventory, cx| inventory.last_scheduled_runnable(cx)) .update(cx, |inventory, cx| inventory.last_scheduled_task(cx))
}) { }) {
schedule_runnable(workspace, runnable.as_ref(), cx) schedule_task(workspace, task.as_ref(), cx)
}; };
}); });
}, },
@ -35,27 +34,23 @@ pub fn init(cx: &mut AppContext) {
.detach(); .detach();
} }
fn schedule_runnable( fn schedule_task(workspace: &Workspace, task: &dyn Task, cx: &mut ViewContext<'_, Workspace>) {
workspace: &Workspace, let cwd = match task.cwd() {
runnable: &dyn Runnable,
cx: &mut ViewContext<'_, Workspace>,
) {
let cwd = match runnable.cwd() {
Some(cwd) => Some(cwd.to_path_buf()), Some(cwd) => Some(cwd.to_path_buf()),
None => runnable_cwd(workspace, cx).log_err().flatten(), None => task_cwd(workspace, cx).log_err().flatten(),
}; };
let spawn_in_terminal = runnable.exec(cwd); let spawn_in_terminal = task.exec(cwd);
if let Some(spawn_in_terminal) = spawn_in_terminal { if let Some(spawn_in_terminal) = spawn_in_terminal {
workspace.project().update(cx, |project, cx| { workspace.project().update(cx, |project, cx| {
project.runnable_inventory().update(cx, |inventory, _| { project.task_inventory().update(cx, |inventory, _| {
inventory.last_scheduled_runnable = Some(runnable.id().clone()); inventory.last_scheduled_task = Some(task.id().clone());
}) })
}); });
cx.emit(workspace::Event::SpawnRunnable(spawn_in_terminal)); cx.emit(workspace::Event::SpawnTask(spawn_in_terminal));
} }
} }
fn runnable_cwd(workspace: &Workspace, cx: &mut WindowContext) -> anyhow::Result<Option<PathBuf>> { fn task_cwd(workspace: &Workspace, cx: &mut WindowContext) -> anyhow::Result<Option<PathBuf>> {
let project = workspace.project().read(cx); let project = workspace.project().read(cx);
let available_worktrees = project let available_worktrees = project
.worktrees() .worktrees()
@ -82,7 +77,7 @@ fn runnable_cwd(workspace: &Workspace, cx: &mut WindowContext) -> anyhow::Result
}); });
anyhow::ensure!( anyhow::ensure!(
cwd_for_active_entry.is_some(), cwd_for_active_entry.is_some(),
"Cannot determine runnable cwd for multiple worktrees" "Cannot determine task cwd for multiple worktrees"
); );
cwd_for_active_entry cwd_for_active_entry
} }

View file

@ -3,24 +3,24 @@ use std::sync::Arc;
use fuzzy::{StringMatch, StringMatchCandidate}; use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{ use gpui::{
actions, rems, AppContext, DismissEvent, EventEmitter, FocusableView, InteractiveElement, actions, rems, AppContext, DismissEvent, EventEmitter, FocusableView, InteractiveElement,
Model, ParentElement, Render, SharedString, Styled, Subscription, Task, View, ViewContext, Model, ParentElement, Render, SharedString, Styled, Subscription, View, ViewContext,
VisualContext, WeakView, VisualContext, WeakView,
}; };
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use project::Inventory; use project::Inventory;
use runnable::Runnable; use task::Task;
use ui::{v_flex, HighlightedLabel, ListItem, ListItemSpacing, Selectable}; use ui::{v_flex, HighlightedLabel, ListItem, ListItemSpacing, Selectable};
use util::ResultExt; use util::ResultExt;
use workspace::{ModalView, Workspace}; use workspace::{ModalView, Workspace};
use crate::{schedule_runnable, OneshotSource}; use crate::{schedule_task, OneshotSource};
actions!(runnables, [Spawn, Rerun]); actions!(task, [Spawn, Rerun]);
/// A modal used to spawn new runnables. /// A modal used to spawn new tasks.
pub(crate) struct RunnablesModalDelegate { pub(crate) struct TasksModalDelegate {
inventory: Model<Inventory>, inventory: Model<Inventory>,
candidates: Vec<Arc<dyn Runnable>>, candidates: Vec<Arc<dyn Task>>,
matches: Vec<StringMatch>, matches: Vec<StringMatch>,
selected_index: usize, selected_index: usize,
placeholder_text: Arc<str>, placeholder_text: Arc<str>,
@ -28,7 +28,7 @@ pub(crate) struct RunnablesModalDelegate {
last_prompt: String, last_prompt: String,
} }
impl RunnablesModalDelegate { impl TasksModalDelegate {
fn new(inventory: Model<Inventory>, workspace: WeakView<Workspace>) -> Self { fn new(inventory: Model<Inventory>, workspace: WeakView<Workspace>) -> Self {
Self { Self {
inventory, inventory,
@ -36,12 +36,12 @@ impl RunnablesModalDelegate {
candidates: Vec::new(), candidates: Vec::new(),
matches: Vec::new(), matches: Vec::new(),
selected_index: 0, selected_index: 0,
placeholder_text: Arc::from("Select runnable..."), placeholder_text: Arc::from("Select task..."),
last_prompt: String::default(), last_prompt: String::default(),
} }
} }
fn spawn_oneshot(&mut self, cx: &mut AppContext) -> Option<Arc<dyn Runnable>> { fn spawn_oneshot(&mut self, cx: &mut AppContext) -> Option<Arc<dyn Task>> {
let oneshot_source = self let oneshot_source = self
.inventory .inventory
.update(cx, |this, _| this.source::<OneshotSource>())?; .update(cx, |this, _| this.source::<OneshotSource>())?;
@ -54,20 +54,19 @@ impl RunnablesModalDelegate {
} }
} }
pub(crate) struct RunnablesModal { pub(crate) struct TasksModal {
picker: View<Picker<RunnablesModalDelegate>>, picker: View<Picker<TasksModalDelegate>>,
_subscription: Subscription, _subscription: Subscription,
} }
impl RunnablesModal { impl TasksModal {
pub(crate) fn new( pub(crate) fn new(
inventory: Model<Inventory>, inventory: Model<Inventory>,
workspace: WeakView<Workspace>, workspace: WeakView<Workspace>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let picker = cx.new_view(|cx| { let picker = cx
Picker::uniform_list(RunnablesModalDelegate::new(inventory, workspace), cx) .new_view(|cx| Picker::uniform_list(TasksModalDelegate::new(inventory, workspace), cx));
});
let _subscription = cx.subscribe(&picker, |_, _, _, cx| { let _subscription = cx.subscribe(&picker, |_, _, _, cx| {
cx.emit(DismissEvent); cx.emit(DismissEvent);
}); });
@ -77,7 +76,8 @@ impl RunnablesModal {
} }
} }
} }
impl Render for RunnablesModal {
impl Render for TasksModal {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl gpui::prelude::IntoElement { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl gpui::prelude::IntoElement {
v_flex() v_flex()
.w(rems(34.)) .w(rems(34.))
@ -90,15 +90,17 @@ impl Render for RunnablesModal {
} }
} }
impl EventEmitter<DismissEvent> for RunnablesModal {} impl EventEmitter<DismissEvent> for TasksModal {}
impl FocusableView for RunnablesModal {
impl FocusableView for TasksModal {
fn focus_handle(&self, cx: &gpui::AppContext) -> gpui::FocusHandle { fn focus_handle(&self, cx: &gpui::AppContext) -> gpui::FocusHandle {
self.picker.read(cx).focus_handle(cx) self.picker.read(cx).focus_handle(cx)
} }
} }
impl ModalView for RunnablesModal {}
impl PickerDelegate for RunnablesModalDelegate { impl ModalView for TasksModal {}
impl PickerDelegate for TasksModalDelegate {
type ListItem = ListItem; type ListItem = ListItem;
fn match_count(&self) -> usize { fn match_count(&self) -> usize {
@ -121,14 +123,14 @@ impl PickerDelegate for RunnablesModalDelegate {
&mut self, &mut self,
query: String, query: String,
cx: &mut ViewContext<picker::Picker<Self>>, cx: &mut ViewContext<picker::Picker<Self>>,
) -> Task<()> { ) -> gpui::Task<()> {
cx.spawn(move |picker, mut cx| async move { cx.spawn(move |picker, mut cx| async move {
let Some(candidates) = picker let Some(candidates) = picker
.update(&mut cx, |picker, cx| { .update(&mut cx, |picker, cx| {
picker.delegate.candidates = picker picker.delegate.candidates = picker
.delegate .delegate
.inventory .inventory
.update(cx, |inventory, cx| inventory.list_runnables(None, cx)); .update(cx, |inventory, cx| inventory.list_tasks(None, cx));
picker picker
.delegate .delegate
.candidates .candidates
@ -178,7 +180,7 @@ impl PickerDelegate for RunnablesModalDelegate {
fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<picker::Picker<Self>>) { fn confirm(&mut self, secondary: bool, cx: &mut ViewContext<picker::Picker<Self>>) {
let current_match_index = self.selected_index(); let current_match_index = self.selected_index();
let Some(runnable) = secondary let Some(task) = secondary
.then(|| self.spawn_oneshot(cx)) .then(|| self.spawn_oneshot(cx))
.flatten() .flatten()
.or_else(|| { .or_else(|| {
@ -193,7 +195,7 @@ impl PickerDelegate for RunnablesModalDelegate {
self.workspace self.workspace
.update(cx, |workspace, cx| { .update(cx, |workspace, cx| {
schedule_runnable(workspace, runnable.as_ref(), cx); schedule_task(workspace, task.as_ref(), cx);
}) })
.ok(); .ok();
cx.emit(DismissEvent); cx.emit(DismissEvent);
@ -210,10 +212,9 @@ impl PickerDelegate for RunnablesModalDelegate {
_cx: &mut ViewContext<picker::Picker<Self>>, _cx: &mut ViewContext<picker::Picker<Self>>,
) -> Option<Self::ListItem> { ) -> Option<Self::ListItem> {
let hit = &self.matches[ix]; let hit = &self.matches[ix];
//let runnable = self.candidates[target_index].metadata();
let highlights: Vec<_> = hit.positions.iter().copied().collect(); let highlights: Vec<_> = hit.positions.iter().copied().collect();
Some( Some(
ListItem::new(SharedString::from(format!("runnables-modal-{ix}"))) ListItem::new(SharedString::from(format!("tasks-modal-{ix}")))
.inset(true) .inset(true)
.spacing(ListItemSpacing::Sparse) .spacing(ListItemSpacing::Sparse)
.selected(selected) .selected(selected)

View file

@ -1,28 +1,26 @@
use std::sync::Arc; use std::sync::Arc;
use gpui::{AppContext, Model}; use gpui::{AppContext, Model};
use runnable::{Runnable, RunnableId, Source}; use task::{Source, SpawnInTerminal, Task, TaskId};
use ui::Context; use ui::Context;
pub struct OneshotSource { pub struct OneshotSource {
runnables: Vec<Arc<dyn runnable::Runnable>>, tasks: Vec<Arc<dyn Task>>,
} }
#[derive(Clone)] #[derive(Clone)]
struct OneshotRunnable { struct OneshotTask {
id: RunnableId, id: TaskId,
} }
impl OneshotRunnable { impl OneshotTask {
fn new(prompt: String) -> Self { fn new(prompt: String) -> Self {
Self { Self { id: TaskId(prompt) }
id: RunnableId(prompt),
}
} }
} }
impl Runnable for OneshotRunnable { impl Task for OneshotTask {
fn id(&self) -> &runnable::RunnableId { fn id(&self) -> &TaskId {
&self.id &self.id
} }
@ -34,11 +32,11 @@ impl Runnable for OneshotRunnable {
None None
} }
fn exec(&self, cwd: Option<std::path::PathBuf>) -> Option<runnable::SpawnInTerminal> { fn exec(&self, cwd: Option<std::path::PathBuf>) -> Option<SpawnInTerminal> {
if self.id().0.is_empty() { if self.id().0.is_empty() {
return None; return None;
} }
Some(runnable::SpawnInTerminal { Some(SpawnInTerminal {
id: self.id().clone(), id: self.id().clone(),
label: self.name().to_owned(), label: self.name().to_owned(),
command: self.id().0.clone(), command: self.id().0.clone(),
@ -54,12 +52,12 @@ impl Runnable for OneshotRunnable {
impl OneshotSource { impl OneshotSource {
pub fn new(cx: &mut AppContext) -> Model<Box<dyn Source>> { pub fn new(cx: &mut AppContext) -> Model<Box<dyn Source>> {
cx.new_model(|_| Box::new(Self { runnables: vec![] }) as Box<dyn Source>) cx.new_model(|_| Box::new(Self { tasks: Vec::new() }) as Box<dyn Source>)
} }
pub fn spawn(&mut self, prompt: String) -> Arc<dyn runnable::Runnable> { pub fn spawn(&mut self, prompt: String) -> Arc<dyn Task> {
let ret = Arc::new(OneshotRunnable::new(prompt)); let ret = Arc::new(OneshotTask::new(prompt));
self.runnables.push(ret.clone()); self.tasks.push(ret.clone());
ret ret
} }
} }
@ -69,11 +67,11 @@ impl Source for OneshotSource {
self self
} }
fn runnables_for_path( fn tasks_for_path(
&mut self, &mut self,
_path: Option<&std::path::Path>, _path: Option<&std::path::Path>,
_cx: &mut gpui::ModelContext<Box<dyn Source>>, _cx: &mut gpui::ModelContext<Box<dyn Source>>,
) -> Vec<Arc<dyn runnable::Runnable>> { ) -> Vec<Arc<dyn Task>> {
self.runnables.clone() self.tasks.clone()
} }
} }

View file

@ -24,7 +24,7 @@ libc = "0.2"
mio-extras = "2.0.6" mio-extras = "2.0.6"
ordered-float.workspace = true ordered-float.workspace = true
procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "0c13436f4fa8b126f46dd4a20106419b41666897", default-features = false } procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "0c13436f4fa8b126f46dd4a20106419b41666897", default-features = false }
runnable.workspace = true task.workspace = true
schemars.workspace = true schemars.workspace = true
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true

View file

@ -1,5 +1,7 @@
pub mod mappings; pub mod mappings;
pub use alacritty_terminal; pub use alacritty_terminal;
pub mod terminal_settings; pub mod terminal_settings;
use alacritty_terminal::{ use alacritty_terminal::{
@ -33,10 +35,10 @@ use mappings::mouse::{
use collections::{HashMap, VecDeque}; use collections::{HashMap, VecDeque};
use futures::StreamExt; use futures::StreamExt;
use procinfo::LocalProcessInfo; use procinfo::LocalProcessInfo;
use runnable::RunnableId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use settings::Settings; use settings::Settings;
use smol::channel::{Receiver, Sender}; use smol::channel::{Receiver, Sender};
use task::TaskId;
use terminal_settings::{AlternateScroll, Shell, TerminalBlink, TerminalSettings}; use terminal_settings::{AlternateScroll, Shell, TerminalBlink, TerminalSettings};
use theme::{ActiveTheme, Theme}; use theme::{ActiveTheme, Theme};
use util::truncate_and_trailoff; use util::truncate_and_trailoff;
@ -179,6 +181,7 @@ impl TerminalSize {
self.line_height self.line_height
} }
} }
impl Default for TerminalSize { impl Default for TerminalSize {
fn default() -> Self { fn default() -> Self {
TerminalSize::new( TerminalSize::new(
@ -282,8 +285,8 @@ impl Display for TerminalError {
} }
} }
pub struct SpawnRunnable { pub struct SpawnTask {
pub id: RunnableId, pub id: TaskId,
pub label: String, pub label: String,
pub command: String, pub command: String,
pub args: Vec<String>, pub args: Vec<String>,
@ -302,7 +305,7 @@ pub struct TerminalBuilder {
impl TerminalBuilder { impl TerminalBuilder {
pub fn new( pub fn new(
working_directory: Option<PathBuf>, working_directory: Option<PathBuf>,
runnable: Option<RunableState>, task: Option<TaskState>,
shell: Shell, shell: Shell,
env: HashMap<String, String>, env: HashMap<String, String>,
blink_settings: Option<TerminalBlink>, blink_settings: Option<TerminalBlink>,
@ -340,9 +343,9 @@ impl TerminalBuilder {
std::env::set_var("LC_ALL", "en_US.UTF-8"); std::env::set_var("LC_ALL", "en_US.UTF-8");
std::env::set_var("ZED_TERM", "true"); std::env::set_var("ZED_TERM", "true");
let scrolling_history = if runnable.is_some() { let scrolling_history = if task.is_some() {
// Runnables like `cargo build --all` may produce a lot of output, ergo allow maximum scrolling. // Tasks like `cargo build --all` may produce a lot of output, ergo allow maximum scrolling.
// After the runnable finishes, we do not allow appending to that terminal, so small runnables output should not // After the task finishes, we do not allow appending to that terminal, so small tasks output should not
// cause excessive memory usage over time. // cause excessive memory usage over time.
MAX_SCROLL_HISTORY_LINES MAX_SCROLL_HISTORY_LINES
} else { } else {
@ -417,7 +420,7 @@ impl TerminalBuilder {
let word_regex = RegexSearch::new(r#"[\w.\[\]:/@\-~]+"#).unwrap(); let word_regex = RegexSearch::new(r#"[\w.\[\]:/@\-~]+"#).unwrap();
let terminal = Terminal { let terminal = Terminal {
runnable, task,
pty_tx: Notifier(pty_tx), pty_tx: Notifier(pty_tx),
completion_tx, completion_tx,
term, term,
@ -593,11 +596,11 @@ pub struct Terminal {
hovered_word: bool, hovered_word: bool,
url_regex: RegexSearch, url_regex: RegexSearch,
word_regex: RegexSearch, word_regex: RegexSearch,
runnable: Option<RunableState>, task: Option<TaskState>,
} }
pub struct RunableState { pub struct TaskState {
pub id: RunnableId, pub id: TaskId,
pub label: String, pub label: String,
pub completed: bool, pub completed: bool,
pub completion_rx: Receiver<()>, pub completion_rx: Receiver<()>,
@ -632,9 +635,9 @@ impl Terminal {
AlacTermEvent::Bell => { AlacTermEvent::Bell => {
cx.emit(Event::Bell); cx.emit(Event::Bell);
} }
AlacTermEvent::Exit => match &mut self.runnable { AlacTermEvent::Exit => match &mut self.task {
Some(runnable) => { Some(task) => {
runnable.completed = true; task.completed = true;
self.completion_tx.try_send(()).ok(); self.completion_tx.try_send(()).ok();
} }
None => cx.emit(Event::CloseTerminal), None => cx.emit(Event::CloseTerminal),
@ -1361,8 +1364,8 @@ impl Terminal {
pub fn title(&self, truncate: bool) -> String { pub fn title(&self, truncate: bool) -> String {
const MAX_CHARS: usize = 25; const MAX_CHARS: usize = 25;
match &self.runnable { match &self.task {
Some(runnable_state) => truncate_and_trailoff(&runnable_state.label, MAX_CHARS), Some(task_state) => truncate_and_trailoff(&task_state.label, MAX_CHARS),
None => self None => self
.foreground_process_info .foreground_process_info
.as_ref() .as_ref()
@ -1399,17 +1402,17 @@ impl Terminal {
self.cmd_pressed && self.hovered_word self.cmd_pressed && self.hovered_word
} }
pub fn runnable(&self) -> Option<&RunableState> { pub fn task(&self) -> Option<&TaskState> {
self.runnable.as_ref() self.task.as_ref()
} }
pub fn wait_for_completed_runnable(&self, cx: &mut AppContext) -> Task<()> { pub fn wait_for_completed_task(&self, cx: &mut AppContext) -> Task<()> {
match self.runnable() { match self.task() {
Some(runnable) => { Some(task) => {
if runnable.completed { if task.completed {
Task::ready(()) Task::ready(())
} else { } else {
let mut completion_receiver = runnable.completion_rx.clone(); let mut completion_receiver = task.completion_rx.clone();
cx.spawn(|_| async move { cx.spawn(|_| async move {
completion_receiver.next().await; completion_receiver.next().await;
}) })
@ -1642,7 +1645,7 @@ mod tests {
assert_eq!( assert_eq!(
content.cells[content_index_for_mouse( content.cells[content_index_for_mouse(
point(Pixels::from(-10.), Pixels::from(-10.)), point(Pixels::from(-10.), Pixels::from(-10.)),
&content.size &content.size,
)] )]
.c, .c,
cells[0][0] cells[0][0]
@ -1650,7 +1653,7 @@ mod tests {
assert_eq!( assert_eq!(
content.cells[content_index_for_mouse( content.cells[content_index_for_mouse(
point(Pixels::from(1000.), Pixels::from(1000.)), point(Pixels::from(1000.), Pixels::from(1000.)),
&content.size &content.size,
)] )]
.c, .c,
cells[9][9] cells[9][9]

View file

@ -25,7 +25,7 @@ mio-extras = "2.0.6"
ordered-float.workspace = true ordered-float.workspace = true
procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "0c13436f4fa8b126f46dd4a20106419b41666897", default-features = false } procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "0c13436f4fa8b126f46dd4a20106419b41666897", default-features = false }
project.workspace = true project.workspace = true
runnable.workspace = true task.workspace = true
search.workspace = true search.workspace = true
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true

View file

@ -11,13 +11,13 @@ use gpui::{
}; };
use itertools::Itertools; use itertools::Itertools;
use project::{Fs, ProjectEntryId}; use project::{Fs, ProjectEntryId};
use runnable::RunnableId;
use search::{buffer_search::DivRegistrar, BufferSearchBar}; use search::{buffer_search::DivRegistrar, BufferSearchBar};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use settings::Settings; use settings::Settings;
use task::{SpawnInTerminal, TaskId};
use terminal::{ use terminal::{
terminal_settings::{Shell, TerminalDockPosition, TerminalSettings}, terminal_settings::{Shell, TerminalDockPosition, TerminalSettings},
SpawnRunnable, SpawnTask,
}; };
use ui::{h_flex, ButtonCommon, Clickable, IconButton, IconSize, Selectable, Tooltip}; use ui::{h_flex, ButtonCommon, Clickable, IconButton, IconSize, Selectable, Tooltip};
use util::{ResultExt, TryFutureExt}; use util::{ResultExt, TryFutureExt};
@ -57,7 +57,7 @@ pub struct TerminalPanel {
pending_serialization: Task<Option<()>>, pending_serialization: Task<Option<()>>,
pending_terminals_to_add: usize, pending_terminals_to_add: usize,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
deferred_runnables: HashMap<RunnableId, Task<()>>, deferred_tasks: HashMap<TaskId, Task<()>>,
} }
impl TerminalPanel { impl TerminalPanel {
@ -166,7 +166,7 @@ impl TerminalPanel {
width: None, width: None,
height: None, height: None,
pending_terminals_to_add: 0, pending_terminals_to_add: 0,
deferred_runnables: HashMap::default(), deferred_tasks: HashMap::default(),
_subscriptions: subscriptions, _subscriptions: subscriptions,
}; };
this this
@ -223,8 +223,8 @@ impl TerminalPanel {
panel._subscriptions.push(cx.subscribe( panel._subscriptions.push(cx.subscribe(
&workspace, &workspace,
|terminal_panel, _, e, cx| { |terminal_panel, _, e, cx| {
if let workspace::Event::SpawnRunnable(spawn_in_terminal) = e { if let workspace::Event::SpawnTask(spawn_in_terminal) = e {
terminal_panel.spawn_runnable(spawn_in_terminal, cx); terminal_panel.spawn_task(spawn_in_terminal, cx);
}; };
}, },
)) ))
@ -295,12 +295,8 @@ impl TerminalPanel {
}) })
} }
pub fn spawn_runnable( pub fn spawn_task(&mut self, spawn_in_terminal: &SpawnInTerminal, cx: &mut ViewContext<Self>) {
&mut self, let mut spawn_task = SpawnTask {
spawn_in_terminal: &runnable::SpawnInTerminal,
cx: &mut ViewContext<Self>,
) {
let mut spawn_runnable = SpawnRunnable {
id: spawn_in_terminal.id.clone(), id: spawn_in_terminal.id.clone(),
label: spawn_in_terminal.label.clone(), label: spawn_in_terminal.label.clone(),
command: spawn_in_terminal.command.clone(), command: spawn_in_terminal.command.clone(),
@ -317,28 +313,28 @@ impl TerminalPanel {
return; return;
}; };
let command = std::mem::take(&mut spawn_runnable.command); let command = std::mem::take(&mut spawn_task.command);
let args = std::mem::take(&mut spawn_runnable.args); let args = std::mem::take(&mut spawn_task.args);
spawn_runnable.command = shell; spawn_task.command = shell;
user_args.extend(["-c".to_owned(), command]); user_args.extend(["-c".to_owned(), command]);
user_args.extend(args); user_args.extend(args);
spawn_runnable.args = user_args; spawn_task.args = user_args;
} }
let working_directory = spawn_in_terminal.cwd.clone(); let working_directory = spawn_in_terminal.cwd.clone();
let allow_concurrent_runs = spawn_in_terminal.allow_concurrent_runs; let allow_concurrent_runs = spawn_in_terminal.allow_concurrent_runs;
let use_new_terminal = spawn_in_terminal.use_new_terminal; let use_new_terminal = spawn_in_terminal.use_new_terminal;
if allow_concurrent_runs && use_new_terminal { if allow_concurrent_runs && use_new_terminal {
self.spawn_in_new_terminal(spawn_runnable, working_directory, cx); self.spawn_in_new_terminal(spawn_task, working_directory, cx);
return; return;
} }
let terminals_for_runnable = self.terminals_for_runnable(&spawn_in_terminal.id, cx); let terminals_for_task = self.terminals_for_task(&spawn_in_terminal.id, cx);
if terminals_for_runnable.is_empty() { if terminals_for_task.is_empty() {
self.spawn_in_new_terminal(spawn_runnable, working_directory, cx); self.spawn_in_new_terminal(spawn_task, working_directory, cx);
return; return;
} }
let (existing_item_index, existing_terminal) = terminals_for_runnable let (existing_item_index, existing_terminal) = terminals_for_task
.last() .last()
.expect("covered no terminals case above") .expect("covered no terminals case above")
.clone(); .clone();
@ -349,28 +345,28 @@ impl TerminalPanel {
); );
self.replace_terminal( self.replace_terminal(
working_directory, working_directory,
spawn_runnable, spawn_task,
existing_item_index, existing_item_index,
existing_terminal, existing_terminal,
cx, cx,
); );
} else { } else {
self.deferred_runnables.insert( self.deferred_tasks.insert(
spawn_in_terminal.id.clone(), spawn_in_terminal.id.clone(),
cx.spawn(|terminal_panel, mut cx| async move { cx.spawn(|terminal_panel, mut cx| async move {
wait_for_terminals_tasks(terminals_for_runnable, &mut cx).await; wait_for_terminals_tasks(terminals_for_task, &mut cx).await;
terminal_panel terminal_panel
.update(&mut cx, |terminal_panel, cx| { .update(&mut cx, |terminal_panel, cx| {
if use_new_terminal { if use_new_terminal {
terminal_panel.spawn_in_new_terminal( terminal_panel.spawn_in_new_terminal(
spawn_runnable, spawn_task,
working_directory, working_directory,
cx, cx,
); );
} else { } else {
terminal_panel.replace_terminal( terminal_panel.replace_terminal(
working_directory, working_directory,
spawn_runnable, spawn_task,
existing_item_index, existing_item_index,
existing_terminal, existing_terminal,
cx, cx,
@ -385,11 +381,11 @@ impl TerminalPanel {
fn spawn_in_new_terminal( fn spawn_in_new_terminal(
&mut self, &mut self,
spawn_runnable: SpawnRunnable, spawn_task: SpawnTask,
working_directory: Option<PathBuf>, working_directory: Option<PathBuf>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
self.add_terminal(working_directory, Some(spawn_runnable), cx); self.add_terminal(working_directory, Some(spawn_task), cx);
let task_workspace = self.workspace.clone(); let task_workspace = self.workspace.clone();
cx.spawn(|_, mut cx| async move { cx.spawn(|_, mut cx| async move {
task_workspace task_workspace
@ -412,9 +408,9 @@ impl TerminalPanel {
this.update(cx, |this, cx| this.add_terminal(None, None, cx)) this.update(cx, |this, cx| this.add_terminal(None, None, cx))
} }
fn terminals_for_runnable( fn terminals_for_task(
&self, &self,
id: &RunnableId, id: &TaskId,
cx: &mut AppContext, cx: &mut AppContext,
) -> Vec<(usize, View<TerminalView>)> { ) -> Vec<(usize, View<TerminalView>)> {
self.pane self.pane
@ -423,8 +419,8 @@ impl TerminalPanel {
.enumerate() .enumerate()
.filter_map(|(index, item)| Some((index, item.act_as::<TerminalView>(cx)?))) .filter_map(|(index, item)| Some((index, item.act_as::<TerminalView>(cx)?)))
.filter_map(|(index, terminal_view)| { .filter_map(|(index, terminal_view)| {
let runnable_state = terminal_view.read(cx).terminal().read(cx).runnable()?; let task_state = terminal_view.read(cx).terminal().read(cx).task()?;
if &runnable_state.id == id { if &task_state.id == id {
Some((index, terminal_view)) Some((index, terminal_view))
} else { } else {
None None
@ -442,7 +438,7 @@ impl TerminalPanel {
fn add_terminal( fn add_terminal(
&mut self, &mut self,
working_directory: Option<PathBuf>, working_directory: Option<PathBuf>,
spawn_runnable: Option<SpawnRunnable>, spawn_task: Option<SpawnTask>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
let workspace = self.workspace.clone(); let workspace = self.workspace.clone();
@ -461,7 +457,7 @@ impl TerminalPanel {
let window = cx.window_handle(); let window = cx.window_handle();
if let Some(terminal) = workspace.project().update(cx, |project, cx| { if let Some(terminal) = workspace.project().update(cx, |project, cx| {
project project
.create_terminal(working_directory, spawn_runnable, window, cx) .create_terminal(working_directory, spawn_task, window, cx)
.log_err() .log_err()
}) { }) {
let terminal = Box::new(cx.new_view(|cx| { let terminal = Box::new(cx.new_view(|cx| {
@ -495,13 +491,7 @@ impl TerminalPanel {
.items() .items()
.filter_map(|item| { .filter_map(|item| {
let terminal_view = item.act_as::<TerminalView>(cx)?; let terminal_view = item.act_as::<TerminalView>(cx)?;
if terminal_view if terminal_view.read(cx).terminal().read(cx).task().is_some() {
.read(cx)
.terminal()
.read(cx)
.runnable()
.is_some()
{
None None
} else { } else {
let id = item.item_id().as_u64(); let id = item.item_id().as_u64();
@ -540,7 +530,7 @@ impl TerminalPanel {
fn replace_terminal( fn replace_terminal(
&self, &self,
working_directory: Option<PathBuf>, working_directory: Option<PathBuf>,
spawn_runnable: SpawnRunnable, spawn_task: SpawnTask,
terminal_item_index: usize, terminal_item_index: usize,
terminal_to_replace: View<TerminalView>, terminal_to_replace: View<TerminalView>,
cx: &mut ViewContext<'_, Self>, cx: &mut ViewContext<'_, Self>,
@ -552,7 +542,7 @@ impl TerminalPanel {
let window = cx.window_handle(); let window = cx.window_handle();
let new_terminal = project.update(cx, |project, cx| { let new_terminal = project.update(cx, |project, cx| {
project project
.create_terminal(working_directory, Some(spawn_runnable), window, cx) .create_terminal(working_directory, Some(spawn_task), window, cx)
.log_err() .log_err()
})?; })?;
terminal_to_replace.update(cx, |terminal_to_replace, cx| { terminal_to_replace.update(cx, |terminal_to_replace, cx| {
@ -571,15 +561,15 @@ impl TerminalPanel {
} }
async fn wait_for_terminals_tasks( async fn wait_for_terminals_tasks(
terminals_for_runnable: Vec<(usize, View<TerminalView>)>, terminals_for_task: Vec<(usize, View<TerminalView>)>,
cx: &mut AsyncWindowContext, cx: &mut AsyncWindowContext,
) { ) {
let pending_tasks = terminals_for_runnable.iter().filter_map(|(_, terminal)| { let pending_tasks = terminals_for_task.iter().filter_map(|(_, terminal)| {
terminal terminal
.update(cx, |terminal_view, cx| { .update(cx, |terminal_view, cx| {
terminal_view terminal_view
.terminal() .terminal()
.update(cx, |terminal, cx| terminal.wait_for_completed_runnable(cx)) .update(cx, |terminal, cx| terminal.wait_for_completed_task(cx))
}) })
.ok() .ok()
}); });

View file

@ -441,7 +441,7 @@ fn subscribe_for_terminal_events(
Event::TitleChanged => { Event::TitleChanged => {
cx.emit(ItemEvent::UpdateTab); cx.emit(ItemEvent::UpdateTab);
let terminal = this.terminal().read(cx); let terminal = this.terminal().read(cx);
if !terminal.runnable().is_some() { if !terminal.task().is_some() {
if let Some(foreground_info) = &terminal.foreground_process_info { if let Some(foreground_info) = &terminal.foreground_process_info {
let cwd = foreground_info.cwd.clone(); let cwd = foreground_info.cwd.clone();
@ -777,7 +777,7 @@ impl Item for TerminalView {
) -> AnyElement { ) -> AnyElement {
let terminal = self.terminal().read(cx); let terminal = self.terminal().read(cx);
let title = terminal.title(true); let title = terminal.title(true);
let icon = if terminal.runnable().is_some() { let icon = if terminal.task().is_some() {
IconName::Play IconName::Play
} else { } else {
IconName::Terminal IconName::Terminal
@ -817,8 +817,8 @@ impl Item for TerminalView {
} }
fn is_dirty(&self, cx: &gpui::AppContext) -> bool { fn is_dirty(&self, cx: &gpui::AppContext) -> bool {
match self.terminal.read(cx).runnable() { match self.terminal.read(cx).task() {
Some(runnable) => !runnable.completed, Some(task) => !task.completed,
None => self.has_bell(), None => self.has_bell(),
} }
} }
@ -883,7 +883,7 @@ impl Item for TerminalView {
} }
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) { fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
if !self.terminal().read(cx).runnable().is_some() { if !self.terminal().read(cx).task().is_some() {
cx.background_executor() cx.background_executor()
.spawn(TERMINAL_DB.update_workspace_id( .spawn(TERMINAL_DB.update_workspace_id(
workspace.database_id(), workspace.database_id(),

View file

@ -39,7 +39,7 @@ lazy_static::lazy_static! {
}; };
pub static ref SETTINGS: PathBuf = CONFIG_DIR.join("settings.json"); pub static ref SETTINGS: PathBuf = CONFIG_DIR.join("settings.json");
pub static ref KEYMAP: PathBuf = CONFIG_DIR.join("keymap.json"); pub static ref KEYMAP: PathBuf = CONFIG_DIR.join("keymap.json");
pub static ref RUNNABLES: PathBuf = CONFIG_DIR.join("runnables.json"); pub static ref TASKS: PathBuf = CONFIG_DIR.join("tasks.json");
pub static ref LAST_USERNAME: PathBuf = CONFIG_DIR.join("last-username.txt"); pub static ref LAST_USERNAME: PathBuf = CONFIG_DIR.join("last-username.txt");
pub static ref LOG: PathBuf = LOGS_DIR.join("Zed.log"); pub static ref LOG: PathBuf = LOGS_DIR.join("Zed.log");
pub static ref OLD_LOG: PathBuf = LOGS_DIR.join("Zed.log.old"); pub static ref OLD_LOG: PathBuf = LOGS_DIR.join("Zed.log.old");

View file

@ -40,7 +40,7 @@ node_runtime.workspace = true
parking_lot.workspace = true parking_lot.workspace = true
postage.workspace = true postage.workspace = true
project.workspace = true project.workspace = true
runnable.workspace = true task.workspace = true
schemars.workspace = true schemars.workspace = true
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true

View file

@ -50,7 +50,6 @@ pub use persistence::{
}; };
use postage::stream::Stream; use postage::stream::Stream;
use project::{Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId}; use project::{Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId};
use runnable::SpawnInTerminal;
use serde::Deserialize; use serde::Deserialize;
use settings::Settings; use settings::Settings;
use shared_screen::SharedScreen; use shared_screen::SharedScreen;
@ -66,6 +65,7 @@ use std::{
sync::{atomic::AtomicUsize, Arc, Weak}, sync::{atomic::AtomicUsize, Arc, Weak},
time::Duration, time::Duration,
}; };
use task::SpawnInTerminal;
use theme::{ActiveTheme, SystemAppearance, ThemeSettings}; use theme::{ActiveTheme, SystemAppearance, ThemeSettings};
pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView}; pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
pub use ui; pub use ui;
@ -468,7 +468,7 @@ pub enum Event {
PaneAdded(View<Pane>), PaneAdded(View<Pane>),
ContactRequestedJoin(u64), ContactRequestedJoin(u64),
WorkspaceCreated(WeakView<Workspace>), WorkspaceCreated(WeakView<Workspace>),
SpawnRunnable(SpawnInTerminal), SpawnTask(SpawnInTerminal),
} }
pub enum OpenVisible { pub enum OpenVisible {
@ -3004,7 +3004,9 @@ impl Workspace {
let mut item_tasks = Vec::new(); let mut item_tasks = Vec::new();
let mut leader_view_ids = Vec::new(); let mut leader_view_ids = Vec::new();
for view in &views { for view in &views {
let Some(id) = &view.id else { continue }; let Some(id) = &view.id else {
continue;
};
let id = ViewId::from_proto(id.clone())?; let id = ViewId::from_proto(id.clone())?;
let mut variant = view.variant.clone(); let mut variant = view.variant.clone();
if variant.is_none() { if variant.is_none() {
@ -3749,7 +3751,7 @@ enum ActivateInDirectionTarget {
} }
fn notify_if_database_failed(workspace: WindowHandle<Workspace>, cx: &mut AsyncAppContext) { fn notify_if_database_failed(workspace: WindowHandle<Workspace>, cx: &mut AsyncAppContext) {
const REPORT_ISSUE_URL: &str ="https://github.com/zed-industries/zed/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml"; const REPORT_ISSUE_URL: &str = "https://github.com/zed-industries/zed/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml";
workspace workspace
.update(cx, |workspace, cx| { .update(cx, |workspace, cx| {
@ -4193,7 +4195,7 @@ async fn join_channel_internal(
Status::SignedOut => return Err(ErrorCode::SignedOut.into()), Status::SignedOut => return Err(ErrorCode::SignedOut.into()),
Status::UpgradeRequired => return Err(ErrorCode::UpgradeRequired.into()), Status::UpgradeRequired => return Err(ErrorCode::UpgradeRequired.into()),
Status::ConnectionError | Status::ConnectionLost | Status::ReconnectionError { .. } => { Status::ConnectionError | Status::ConnectionLost | Status::ReconnectionError { .. } => {
return Err(ErrorCode::Disconnected.into()) return Err(ErrorCode::Disconnected.into());
} }
} }
} }
@ -4270,7 +4272,7 @@ pub fn join_channel(
&active_call, &active_call,
&mut cx, &mut cx,
) )
.await; .await;
// join channel succeeded, and opened a window // join channel succeeded, and opened a window
if matches!(result, Ok(true)) { if matches!(result, Ok(true)) {
@ -4305,16 +4307,16 @@ pub fn join_channel(
let detail: SharedString = match err.error_code() { let detail: SharedString = match err.error_code() {
ErrorCode::SignedOut => { ErrorCode::SignedOut => {
"Please sign in to continue.".into() "Please sign in to continue.".into()
}, }
ErrorCode::UpgradeRequired => { ErrorCode::UpgradeRequired => {
"Your are running an unsupported version of Zed. Please update to continue.".into() "Your are running an unsupported version of Zed. Please update to continue.".into()
}, }
ErrorCode::NoSuchChannel => { ErrorCode::NoSuchChannel => {
"No matching channel was found. Please check the link and try again.".into() "No matching channel was found. Please check the link and try again.".into()
}, }
ErrorCode::Forbidden => { ErrorCode::Forbidden => {
"This channel is private, and you do not have access. Please ask someone to add you and try again.".into() "This channel is private, and you do not have access. Please ask someone to add you and try again.".into()
}, }
ErrorCode::Disconnected => "Please check your internet connection and try again.".into(), ErrorCode::Disconnected => "Please check your internet connection and try again.".into(),
_ => format!("{}\n\nPlease try again.", err).into(), _ => format!("{}\n\nPlease try again.", err).into(),
}; };

View file

@ -88,8 +88,8 @@ release_channel.workspace = true
rope.workspace = true rope.workspace = true
rpc.workspace = true rpc.workspace = true
rsa = "0.4" rsa = "0.4"
runnable.workspace = true task.workspace = true
runnables_ui.workspace = true tasks_ui.workspace = true
rust-embed.workspace = true rust-embed.workspace = true
schemars.workspace = true schemars.workspace = true
search.workspace = true search.workspace = true

View file

@ -53,7 +53,7 @@ impl JsonLspAdapter {
}, },
cx, cx,
); );
let runnables_schema = runnable::static_source::DefinitionProvider::generate_json_schema(); let tasks_schema = task::static_source::DefinitionProvider::generate_json_schema();
serde_json::json!({ serde_json::json!({
"json": { "json": {
"format": { "format": {
@ -72,8 +72,8 @@ impl JsonLspAdapter {
"schema": KeymapFile::generate_json_schema(&action_names), "schema": KeymapFile::generate_json_schema(&action_names),
}, },
{ {
"fileMatch": [schema_file_match(&paths::RUNNABLES)], "fileMatch": [schema_file_match(&paths::TASKS)],
"schema": runnables_schema, "schema": tasks_schema,
} }
] ]
} }

View file

@ -244,7 +244,7 @@ fn main() {
outline::init(cx); outline::init(cx);
project_symbols::init(cx); project_symbols::init(cx);
project_panel::init(Assets, cx); project_panel::init(Assets, cx);
runnables_ui::init(cx); tasks_ui::init(cx);
channel::init(&client, user_store.clone(), cx); channel::init(&client, user_store.clone(), cx);
search::init(cx); search::init(cx);
semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx); semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx);

View file

@ -22,14 +22,14 @@ use project_panel::ProjectPanel;
use quick_action_bar::QuickActionBar; use quick_action_bar::QuickActionBar;
use release_channel::{AppCommitSha, ReleaseChannel}; use release_channel::{AppCommitSha, ReleaseChannel};
use rope::Rope; use rope::Rope;
use runnable::static_source::StaticSource;
use runnables_ui::OneshotSource;
use search::project_search::ProjectSearchBar; use search::project_search::ProjectSearchBar;
use settings::{ use settings::{
initial_local_settings_content, watch_config_file, KeymapFile, Settings, SettingsStore, initial_local_settings_content, watch_config_file, KeymapFile, Settings, SettingsStore,
DEFAULT_KEYMAP_PATH, DEFAULT_KEYMAP_PATH,
}; };
use std::{borrow::Cow, ops::Deref, path::Path, sync::Arc}; use std::{borrow::Cow, ops::Deref, path::Path, sync::Arc};
use task::static_source::StaticSource;
use tasks_ui::OneshotSource;
use terminal_view::terminal_panel::{self, TerminalPanel}; use terminal_view::terminal_panel::{self, TerminalPanel};
use util::{ use util::{
asset_str, asset_str,
@ -59,7 +59,7 @@ actions!(
OpenDefaultKeymap, OpenDefaultKeymap,
OpenDefaultSettings, OpenDefaultSettings,
OpenKeymap, OpenKeymap,
OpenRunnables, OpenTasks,
OpenLicenses, OpenLicenses,
OpenLocalSettings, OpenLocalSettings,
OpenLog, OpenLog,
@ -159,16 +159,16 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
let project = workspace.project().clone(); let project = workspace.project().clone();
if project.read(cx).is_local() { if project.read(cx).is_local() {
let runnables_file_rx = watch_config_file( let tasks_file_rx = watch_config_file(
&cx.background_executor(), &cx.background_executor(),
app_state.fs.clone(), app_state.fs.clone(),
paths::RUNNABLES.clone(), paths::TASKS.clone(),
); );
let static_source = StaticSource::new(runnables_file_rx, cx); let static_source = StaticSource::new(tasks_file_rx, cx);
let oneshot_source = OneshotSource::new(cx); let oneshot_source = OneshotSource::new(cx);
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
project.runnable_inventory().update(cx, |inventory, cx| { project.task_inventory().update(cx, |inventory, cx| {
inventory.add_source(oneshot_source, cx); inventory.add_source(oneshot_source, cx);
inventory.add_source(static_source, cx); inventory.add_source(static_source, cx);
}) })
@ -278,10 +278,10 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
}, },
) )
.register_action( .register_action(
move |_: &mut Workspace, _: &OpenRunnables, cx: &mut ViewContext<Workspace>| { move |_: &mut Workspace, _: &OpenTasks, cx: &mut ViewContext<Workspace>| {
open_settings_file( open_settings_file(
&paths::RUNNABLES, &paths::TASKS,
|| settings::initial_runnables_content().as_ref().into(), || settings::initial_tasks_content().as_ref().into(),
cx, cx,
); );
}, },