From ce37885f49e4877c84acf8d5dc79e1258d1d5a79 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 27 Mar 2024 20:49:10 +0100 Subject: [PATCH] Use different icons for terminal tasks (#9876) --- Cargo.lock | 4 +- crates/project/src/terminals.rs | 4 +- crates/terminal/Cargo.toml | 3 +- crates/terminal/src/terminal.rs | 55 ++++++++++++++++------- crates/terminal_view/src/terminal_view.rs | 21 ++++++--- 5 files changed, 60 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb12f2197c..cf7dae676e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,9 +87,9 @@ dependencies = [ [[package]] name = "alacritty_terminal" -version = "0.23.0-rc1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc2c16faa5425a10be102dda76f73d76049b44746e18ddeefc44d78bbe76cbce" +checksum = "f6d1ea4484c8676f295307a4892d478c70ac8da1dbd8c7c10830a504b7f1022f" dependencies = [ "base64 0.22.0", "bitflags 2.4.2", diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index 1752e608aa..812d8f1934 100644 --- a/crates/project/src/terminals.rs +++ b/crates/project/src/terminals.rs @@ -6,7 +6,7 @@ use smol::channel::bounded; use std::path::{Path, PathBuf}; use terminal::{ terminal_settings::{self, Shell, TerminalSettings, VenvSettingsContent}, - SpawnTask, TaskState, Terminal, TerminalBuilder, + SpawnTask, TaskState, TaskStatus, Terminal, TerminalBuilder, }; use util::ResultExt; @@ -53,7 +53,7 @@ impl Project { Some(TaskState { id: spawn_task.id, label: spawn_task.label, - completed: false, + status: TaskStatus::Running, completion_rx, }), Shell::WithArguments { diff --git a/crates/terminal/Cargo.toml b/crates/terminal/Cargo.toml index f47ee2db2e..1b4f1fdb13 100644 --- a/crates/terminal/Cargo.toml +++ b/crates/terminal/Cargo.toml @@ -14,8 +14,7 @@ doctest = false [dependencies] -# TODO: when new version of this crate is released, change it -alacritty_terminal = "0.23.0-rc1" +alacritty_terminal = "0.23" anyhow.workspace = true collections.workspace = true dirs = "4.0.0" diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 736202fcb0..287cbd8085 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -595,10 +595,36 @@ pub struct Terminal { pub struct TaskState { pub id: TaskId, pub label: String, - pub completed: bool, + pub status: TaskStatus, 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 { fn process_event(&mut self, event: &AlacTermEvent, cx: &mut ModelContext) { match event { @@ -630,7 +656,7 @@ impl Terminal { } AlacTermEvent::Exit => match &mut self.task { Some(task) => { - task.completed = true; + task.status.register_terminal_exit(); self.completion_tx.try_send(()).ok(); } None => cx.emit(Event::CloseTerminal), @@ -649,8 +675,11 @@ impl Terminal { self.events .push_back(InternalEvent::ColorRequest(*idx, fun_ptr.clone())); } - AlacTermEvent::ChildExit(_) => { - // TODO: Handle child exit + AlacTermEvent::ChildExit(error_code) => { + 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<()> { - match self.task() { - Some(task) => { - if task.completed { - Task::ready(()) - } else { - let mut completion_receiver = task.completion_rx.clone(); - cx.spawn(|_| async move { - completion_receiver.next().await; - }) - } + if let Some(task) = self.task() { + if task.status == TaskStatus::Running { + let mut completion_receiver = task.completion_rx.clone(); + return cx.spawn(|_| async move { + completion_receiver.next().await; + }); } - None => Task::ready(()), } + Task::ready(()) } } diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index fede824f89..c1f0de0590 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -20,7 +20,7 @@ use terminal::{ term::{search::RegexSearch, TermMode}, }, 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 ui::{h_flex, prelude::*, ContextMenu, Icon, IconName, Label}; @@ -788,10 +788,19 @@ impl Item for TerminalView { ) -> AnyElement { let terminal = self.terminal().read(cx); let title = terminal.title(true); - let icon = if terminal.task().is_some() { - IconName::Play - } else { - IconName::Terminal + let icon = match terminal.task() { + Some(terminal_task) => match &terminal_task.status { + TaskStatus::Unknown => IconName::ExclamationTriangle, + TaskStatus::Running => IconName::Play, + TaskStatus::Completed { success } => { + if *success { + IconName::Check + } else { + IconName::XCircle + } + } + }, + None => IconName::Terminal, }; h_flex() .gap_2() @@ -829,7 +838,7 @@ impl Item for TerminalView { fn is_dirty(&self, cx: &gpui::AppContext) -> bool { match self.terminal.read(cx).task() { - Some(task) => !task.completed, + Some(task) => task.status == TaskStatus::Running, None => self.has_bell(), } }