Use different icons for terminal tasks (#9876)

This commit is contained in:
Kirill Bulatov 2024-03-27 20:49:10 +01:00 committed by GitHub
parent 687d2a41d6
commit ce37885f49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 60 additions and 27 deletions

4
Cargo.lock generated
View file

@ -87,9 +87,9 @@ dependencies = [
[[package]] [[package]]
name = "alacritty_terminal" name = "alacritty_terminal"
version = "0.23.0-rc1" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc2c16faa5425a10be102dda76f73d76049b44746e18ddeefc44d78bbe76cbce" checksum = "f6d1ea4484c8676f295307a4892d478c70ac8da1dbd8c7c10830a504b7f1022f"
dependencies = [ dependencies = [
"base64 0.22.0", "base64 0.22.0",
"bitflags 2.4.2", "bitflags 2.4.2",

View file

@ -6,7 +6,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},
SpawnTask, TaskState, Terminal, TerminalBuilder, SpawnTask, TaskState, TaskStatus, Terminal, TerminalBuilder,
}; };
use util::ResultExt; use util::ResultExt;
@ -53,7 +53,7 @@ impl Project {
Some(TaskState { Some(TaskState {
id: spawn_task.id, id: spawn_task.id,
label: spawn_task.label, label: spawn_task.label,
completed: false, status: TaskStatus::Running,
completion_rx, completion_rx,
}), }),
Shell::WithArguments { Shell::WithArguments {

View file

@ -14,8 +14,7 @@ doctest = false
[dependencies] [dependencies]
# TODO: when new version of this crate is released, change it alacritty_terminal = "0.23"
alacritty_terminal = "0.23.0-rc1"
anyhow.workspace = true anyhow.workspace = true
collections.workspace = true collections.workspace = true
dirs = "4.0.0" dirs = "4.0.0"

View file

@ -595,10 +595,36 @@ pub struct Terminal {
pub struct TaskState { pub struct TaskState {
pub id: TaskId, pub id: TaskId,
pub label: String, pub label: String,
pub completed: bool, pub status: TaskStatus,
pub completion_rx: Receiver<()>, pub completion_rx: Receiver<()>,
} }
/// A status of the current terminal tab's task.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TaskStatus {
/// The task had been started, but got cancelled or somehow otherwise it did not
/// report its exit code before the terminal event loop was shut down.
Unknown,
/// The task is started and running currently.
Running,
/// After the start, the task stopped running and reported its error code back.
Completed { success: bool },
}
impl TaskStatus {
fn register_terminal_exit(&mut self) {
if self == &Self::Running {
*self = Self::Unknown;
}
}
fn register_task_exit(&mut self, error_code: i32) {
*self = TaskStatus::Completed {
success: error_code == 0,
};
}
}
impl Terminal { impl Terminal {
fn process_event(&mut self, event: &AlacTermEvent, cx: &mut ModelContext<Self>) { fn process_event(&mut self, event: &AlacTermEvent, cx: &mut ModelContext<Self>) {
match event { match event {
@ -630,7 +656,7 @@ impl Terminal {
} }
AlacTermEvent::Exit => match &mut self.task { AlacTermEvent::Exit => match &mut self.task {
Some(task) => { Some(task) => {
task.completed = true; task.status.register_terminal_exit();
self.completion_tx.try_send(()).ok(); self.completion_tx.try_send(()).ok();
} }
None => cx.emit(Event::CloseTerminal), None => cx.emit(Event::CloseTerminal),
@ -649,8 +675,11 @@ impl Terminal {
self.events self.events
.push_back(InternalEvent::ColorRequest(*idx, fun_ptr.clone())); .push_back(InternalEvent::ColorRequest(*idx, fun_ptr.clone()));
} }
AlacTermEvent::ChildExit(_) => { AlacTermEvent::ChildExit(error_code) => {
// TODO: Handle child exit if let Some(task) = &mut self.task {
task.status.register_task_exit(*error_code);
self.completion_tx.try_send(()).ok();
}
} }
} }
} }
@ -1381,19 +1410,15 @@ impl Terminal {
} }
pub fn wait_for_completed_task(&self, cx: &mut AppContext) -> Task<()> { pub fn wait_for_completed_task(&self, cx: &mut AppContext) -> Task<()> {
match self.task() { if let Some(task) = self.task() {
Some(task) => { if task.status == TaskStatus::Running {
if task.completed {
Task::ready(())
} else {
let mut completion_receiver = task.completion_rx.clone(); let mut completion_receiver = task.completion_rx.clone();
cx.spawn(|_| async move { return cx.spawn(|_| async move {
completion_receiver.next().await; completion_receiver.next().await;
}) });
} }
} }
None => Task::ready(()), Task::ready(())
}
} }
} }

View file

@ -20,7 +20,7 @@ use terminal::{
term::{search::RegexSearch, TermMode}, term::{search::RegexSearch, TermMode},
}, },
terminal_settings::{TerminalBlink, TerminalSettings, WorkingDirectory}, terminal_settings::{TerminalBlink, TerminalSettings, WorkingDirectory},
Clear, Copy, Event, MaybeNavigationTarget, Paste, ShowCharacterPalette, Terminal, Clear, Copy, Event, MaybeNavigationTarget, Paste, ShowCharacterPalette, TaskStatus, Terminal,
}; };
use terminal_element::TerminalElement; use terminal_element::TerminalElement;
use ui::{h_flex, prelude::*, ContextMenu, Icon, IconName, Label}; use ui::{h_flex, prelude::*, ContextMenu, Icon, IconName, Label};
@ -788,10 +788,19 @@ 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.task().is_some() { let icon = match terminal.task() {
IconName::Play Some(terminal_task) => match &terminal_task.status {
TaskStatus::Unknown => IconName::ExclamationTriangle,
TaskStatus::Running => IconName::Play,
TaskStatus::Completed { success } => {
if *success {
IconName::Check
} else { } else {
IconName::Terminal IconName::XCircle
}
}
},
None => IconName::Terminal,
}; };
h_flex() h_flex()
.gap_2() .gap_2()
@ -829,7 +838,7 @@ 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).task() { match self.terminal.read(cx).task() {
Some(task) => !task.completed, Some(task) => task.status == TaskStatus::Running,
None => self.has_bell(), None => self.has_bell(),
} }
} }