mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-27 07:32:02 +03:00
Small improvements of the task terminal spawn behavior (#9399)
* Add a `reveal: always|never` field in task definitions from tasks.json , allowing to customize task terminal behavior on spawn * Ensure reveal: always reveals the terminal even if the old task is already running Release Notes: - Added a `reveal: always|never` (`always` is a default) field in task definitions from tasks.json , allowing to customize task terminal behavior on spawn --------- Co-authored-by: Piotr Osiewicz <piotr@zed.dev>
This commit is contained in:
parent
276139f792
commit
dcdd1ece1c
@ -5,6 +5,7 @@
|
|||||||
{
|
{
|
||||||
"label": "Example task",
|
"label": "Example task",
|
||||||
"command": "for i in {1..5}; do echo \"Hello $i/5\"; sleep 1; done",
|
"command": "for i in {1..5}; do echo \"Hello $i/5\"; sleep 1; done",
|
||||||
|
//"args": [],
|
||||||
// Env overrides for the command, will be appended to the terminal's environment from the settings.
|
// Env overrides for the command, will be appended to the terminal's environment from the settings.
|
||||||
"env": { "foo": "bar" },
|
"env": { "foo": "bar" },
|
||||||
// Current working directory to spawn the command into, defaults to current project root.
|
// Current working directory to spawn the command into, defaults to current project root.
|
||||||
@ -12,6 +13,10 @@
|
|||||||
// 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 task 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,
|
||||||
|
// What to do with the terminal pane and tab, after the command was started:
|
||||||
|
// * `always` — always show the terminal pane, add and focus the corresponding task's tab in it (default)
|
||||||
|
// * `never` — avoid changing current terminal pane focus, but still add/reuse the task's tab there
|
||||||
|
"reveal": "always"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -6,6 +6,7 @@ pub mod static_source;
|
|||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::ModelContext;
|
use gpui::ModelContext;
|
||||||
|
use static_source::RevealStrategy;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -34,6 +35,8 @@ pub struct SpawnInTerminal {
|
|||||||
pub use_new_terminal: bool,
|
pub use_new_terminal: bool,
|
||||||
/// Whether to allow multiple instances of the same task 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,
|
||||||
|
/// What to do with the terminal pane and tab, after the command was started.
|
||||||
|
pub reveal: RevealStrategy,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Keeps track of the file associated with a task and context of tasks execution (i.e. current file or current function)
|
/// Keeps track of the file associated with a task and context of tasks execution (i.e. current file or current function)
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{SpawnInTerminal, Task, TaskContext, TaskId, TaskSource};
|
use crate::{
|
||||||
|
static_source::RevealStrategy, SpawnInTerminal, Task, TaskContext, TaskId, TaskSource,
|
||||||
|
};
|
||||||
use gpui::{AppContext, Context, Model};
|
use gpui::{AppContext, Context, Model};
|
||||||
|
|
||||||
/// A storage and source of tasks generated out of user command prompt inputs.
|
/// A storage and source of tasks generated out of user command prompt inputs.
|
||||||
@ -48,6 +50,7 @@ impl Task for OneshotTask {
|
|||||||
env,
|
env,
|
||||||
use_new_terminal: Default::default(),
|
use_new_terminal: Default::default(),
|
||||||
allow_concurrent_runs: Default::default(),
|
allow_concurrent_runs: Default::default(),
|
||||||
|
reveal: RevealStrategy::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ impl Task for StaticTask {
|
|||||||
label: self.definition.label.clone(),
|
label: self.definition.label.clone(),
|
||||||
command: self.definition.command.clone(),
|
command: self.definition.command.clone(),
|
||||||
args: self.definition.args.clone(),
|
args: self.definition.args.clone(),
|
||||||
|
reveal: self.definition.reveal,
|
||||||
env: definition_env,
|
env: definition_env,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -64,6 +65,7 @@ pub struct StaticSource {
|
|||||||
|
|
||||||
/// Static task definition from the tasks 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)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub(crate) struct Definition {
|
pub(crate) struct Definition {
|
||||||
/// Human readable name of the task to display in the UI.
|
/// Human readable name of the task to display in the UI.
|
||||||
pub label: String,
|
pub label: String,
|
||||||
@ -84,6 +86,22 @@ pub(crate) struct Definition {
|
|||||||
/// Whether to allow multiple instances of the same task 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,
|
||||||
|
/// What to do with the terminal pane and tab, after the command was started:
|
||||||
|
/// * `always` — always show the terminal pane, add and focus the corresponding task's tab in it (default)
|
||||||
|
/// * `never` — avoid changing current terminal pane focus, but still add/reuse the task's tab there
|
||||||
|
#[serde(default)]
|
||||||
|
pub reveal: RevealStrategy,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What to do with the terminal pane and tab, after the command was started.
|
||||||
|
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum RevealStrategy {
|
||||||
|
/// Always show the terminal pane, add and focus the corresponding task's tab in it.
|
||||||
|
#[default]
|
||||||
|
Always,
|
||||||
|
/// Do not change terminal pane focus, but still add/reuse the task's tab there.
|
||||||
|
Never,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A group of Tasks defined in a JSON file.
|
/// A group of Tasks defined in a JSON file.
|
||||||
|
@ -39,7 +39,7 @@ use pty_info::PtyProcessInfo;
|
|||||||
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 task::{static_source::RevealStrategy, 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;
|
||||||
@ -289,6 +289,7 @@ pub struct SpawnTask {
|
|||||||
pub command: String,
|
pub command: String,
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
pub env: HashMap<String, String>,
|
pub env: HashMap<String, String>,
|
||||||
|
pub reveal: RevealStrategy,
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/alacritty/alacritty/blob/cb3a79dbf6472740daca8440d5166c1d4af5029e/extra/man/alacritty.5.scd?plain=1#L207-L213
|
// https://github.com/alacritty/alacritty/blob/cb3a79dbf6472740daca8440d5166c1d4af5029e/extra/man/alacritty.5.scd?plain=1#L207-L213
|
||||||
|
@ -14,7 +14,7 @@ use project::{Fs, ProjectEntryId};
|
|||||||
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 task::{static_source::RevealStrategy, SpawnInTerminal, TaskId};
|
||||||
use terminal::{
|
use terminal::{
|
||||||
terminal_settings::{Shell, TerminalDockPosition, TerminalSettings},
|
terminal_settings::{Shell, TerminalDockPosition, TerminalSettings},
|
||||||
SpawnTask,
|
SpawnTask,
|
||||||
@ -303,6 +303,7 @@ impl TerminalPanel {
|
|||||||
command: spawn_in_terminal.command.clone(),
|
command: spawn_in_terminal.command.clone(),
|
||||||
args: spawn_in_terminal.args.clone(),
|
args: spawn_in_terminal.args.clone(),
|
||||||
env: spawn_in_terminal.env.clone(),
|
env: spawn_in_terminal.env.clone(),
|
||||||
|
reveal: spawn_in_terminal.reveal,
|
||||||
};
|
};
|
||||||
// Set up shell args unconditionally, as tasks are always spawned inside of a shell.
|
// Set up shell args unconditionally, as tasks are always spawned inside of a shell.
|
||||||
let Some((shell, mut user_args)) = (match TerminalSettings::get_global(cx).shell.clone() {
|
let Some((shell, mut user_args)) = (match TerminalSettings::get_global(cx).shell.clone() {
|
||||||
@ -322,6 +323,7 @@ impl TerminalPanel {
|
|||||||
spawn_task.command = shell;
|
spawn_task.command = shell;
|
||||||
user_args.extend(["-i".to_owned(), "-c".to_owned(), command]);
|
user_args.extend(["-i".to_owned(), "-c".to_owned(), command]);
|
||||||
spawn_task.args = user_args;
|
spawn_task.args = user_args;
|
||||||
|
let reveal = spawn_task.reveal;
|
||||||
|
|
||||||
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;
|
||||||
@ -379,6 +381,20 @@ impl TerminalPanel {
|
|||||||
.ok();
|
.ok();
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
match reveal {
|
||||||
|
RevealStrategy::Always => {
|
||||||
|
self.activate_terminal_view(existing_item_index, cx);
|
||||||
|
let task_workspace = self.workspace.clone();
|
||||||
|
cx.spawn(|_, mut cx| async move {
|
||||||
|
task_workspace
|
||||||
|
.update(&mut cx, |workspace, cx| workspace.focus_panel::<Self>(cx))
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
RevealStrategy::Never => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,14 +404,20 @@ impl TerminalPanel {
|
|||||||
working_directory: Option<PathBuf>,
|
working_directory: Option<PathBuf>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
|
let reveal = spawn_task.reveal;
|
||||||
self.add_terminal(working_directory, Some(spawn_task), cx);
|
self.add_terminal(working_directory, Some(spawn_task), cx);
|
||||||
let task_workspace = self.workspace.clone();
|
match reveal {
|
||||||
cx.spawn(|_, mut cx| async move {
|
RevealStrategy::Always => {
|
||||||
task_workspace
|
let task_workspace = self.workspace.clone();
|
||||||
.update(&mut cx, |workspace, cx| workspace.focus_panel::<Self>(cx))
|
cx.spawn(|_, mut cx| async move {
|
||||||
.ok()
|
task_workspace
|
||||||
})
|
.update(&mut cx, |workspace, cx| workspace.focus_panel::<Self>(cx))
|
||||||
.detach();
|
.ok()
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
RevealStrategy::Never => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Create a new Terminal in the current working directory or the user's home directory
|
///Create a new Terminal in the current working directory or the user's home directory
|
||||||
@ -542,6 +564,7 @@ impl TerminalPanel {
|
|||||||
.workspace
|
.workspace
|
||||||
.update(cx, |workspace, _| workspace.project().clone())
|
.update(cx, |workspace, _| workspace.project().clone())
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
let reveal = spawn_task.reveal;
|
||||||
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
|
||||||
@ -551,14 +574,21 @@ impl TerminalPanel {
|
|||||||
terminal_to_replace.update(cx, |terminal_to_replace, cx| {
|
terminal_to_replace.update(cx, |terminal_to_replace, cx| {
|
||||||
terminal_to_replace.set_terminal(new_terminal, cx);
|
terminal_to_replace.set_terminal(new_terminal, cx);
|
||||||
});
|
});
|
||||||
self.activate_terminal_view(terminal_item_index, cx);
|
|
||||||
let task_workspace = self.workspace.clone();
|
match reveal {
|
||||||
cx.spawn(|_, mut cx| async move {
|
RevealStrategy::Always => {
|
||||||
task_workspace
|
self.activate_terminal_view(terminal_item_index, cx);
|
||||||
.update(&mut cx, |workspace, cx| workspace.focus_panel::<Self>(cx))
|
let task_workspace = self.workspace.clone();
|
||||||
.ok()
|
cx.spawn(|_, mut cx| async move {
|
||||||
})
|
task_workspace
|
||||||
.detach();
|
.update(&mut cx, |workspace, cx| workspace.focus_panel::<Self>(cx))
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
RevealStrategy::Never => {}
|
||||||
|
}
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user