From f9e305afa4682e6a0ccec6d7077d8194169b5e3a Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sat, 31 Aug 2024 09:28:20 +0100 Subject: [PATCH] feat(tui): hightlight status message in colour --- Cargo.lock | 64 +++++++++++++++++++ Cargo.toml | 1 + crates/cli/Cargo.toml | 1 + .../src/tui/actor/handlers/server_update.rs | 37 +++++++---- crates/cli/src/tui/actor/model.rs | 44 +++++++++---- .../cli/src/tui/components/repo/identity.rs | 11 +++- crates/cli/src/tui/components/repo/mod.rs | 7 +- 7 files changed, 135 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a482fbb..ed2e9522 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -320,6 +320,28 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bon" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b71187ef9d11cfa48c023d574a00ec5e4850dcb145ef51619d99cc119486cb" +dependencies = [ + "bon-macros", +] + +[[package]] +name = "bon-macros" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8407447d440da7b3de982f286d15e30e7646bef4ebca994eebebaa1690fd9c" +dependencies = [ + "darling", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.76", +] + [[package]] name = "bstr" version = "1.10.0" @@ -592,6 +614,41 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.76", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.76", +] + [[package]] name = "dashmap" version = "6.0.1" @@ -1041,6 +1098,7 @@ dependencies = [ "actix-rt", "anyhow", "assert2", + "bon", "bytes", "clap", "color-eyre", @@ -2350,6 +2408,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index 69ee2480..3d78df7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,7 @@ time = "0.3" standardwebhooks = "1.0" # boilerplate +bon = "2.0" derive_more = { version = "1.0.0-beta", features = [ "as_ref", "constructor", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 6dbe62fd..c1271bbf 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -52,6 +52,7 @@ actix = { workspace = true } actix-rt = { workspace = true } # boilerplate +bon = { workspace = true } derive_more = { workspace = true } derive-with = { workspace = true } anyhow = { workspace = true } diff --git a/crates/cli/src/tui/actor/handlers/server_update.rs b/crates/cli/src/tui/actor/handlers/server_update.rs index 1ff9c5a5..7e63a323 100644 --- a/crates/cli/src/tui/actor/handlers/server_update.rs +++ b/crates/cli/src/tui/actor/handlers/server_update.rs @@ -1,11 +1,17 @@ // use actix::Handler; +use ratatui::style::Color; use crate::{ server::actor::messages::{RepoUpdate, ServerUpdate}, tui::{actor::ServerState, Tui}, }; +static OKAY: Color = Color::Green; +static PREP: Color = Color::Gray; +static ACTING: Color = Color::Yellow; +static WARN: Color = Color::LightYellow; + impl Handler for Tui { type Result = (); @@ -35,50 +41,53 @@ impl Handler for Tui { RepoUpdate::Log { log } => { repo_state.update_log(log); } - RepoUpdate::ValidateRepo => repo_state.update_message("polling..."), + RepoUpdate::ValidateRepo => repo_state.update_message("polling...", ACTING), RepoUpdate::Okay { main, next, dev } => { repo_state.clear_alert(); - repo_state.update_message("okay"); + repo_state.update_message("okay", OKAY); *repo_state = repo_state.clone().ready(main, next, dev); } RepoUpdate::Alert { alert } => { repo_state.alert(alert); } RepoUpdate::CheckingCI => { - repo_state.update_message("Checking CI status"); + repo_state.update_message("Checking CI status", ACTING); } RepoUpdate::AdvancingNext { commit, force: _ } => { - repo_state.update_message(format!("advancing next to {commit}")); + repo_state + .update_message(format!("advancing next to {commit}"), ACTING); } RepoUpdate::AdvancingMain { commit } => { - repo_state.update_message(format!("advancing main to {commit}")); + repo_state + .update_message(format!("advancing main to {commit}"), ACTING); } RepoUpdate::Opening => { - repo_state.update_message("opening..."); + repo_state.update_message("opening...", PREP); } RepoUpdate::Opened => { - repo_state.update_message("opened"); + repo_state.update_message("opened", PREP); } RepoUpdate::LoadingConfigFromRepo => { - repo_state.update_message("loading config from repo..."); + repo_state.update_message("loading config from repo...", PREP); } RepoUpdate::ReceiveCIStatus { status } => { - repo_state.update_message(format!("ci status: {status:?}")); + repo_state.update_message(format!("ci status: {status:?}"), WARN); } RepoUpdate::ReceiveRepoConfig { repo_config: _ } => { - repo_state.update_message("loaded config from repo"); + repo_state.update_message("loaded config from repo", PREP); } RepoUpdate::RegisteringWebhook => { - repo_state.update_message("registering webhook..."); + repo_state.update_message("registering webhook...", PREP); } RepoUpdate::UnregisteringWebhook => { - repo_state.update_message("unregistering webhook..."); + repo_state.update_message("unregistering webhook...", PREP); } RepoUpdate::WebhookReceived { branch, push: _ } => { - repo_state.update_message(format!("webhook update: {branch:?}")); + repo_state + .update_message(format!("webhook update: {branch:?}"), ACTING); } RepoUpdate::RegisteredWebhook => { - repo_state.update_message("registered webhook"); + repo_state.update_message("registered webhook", PREP); } } } diff --git a/crates/cli/src/tui/actor/model.rs b/crates/cli/src/tui/actor/model.rs index 231fe415..cdd4c435 100644 --- a/crates/cli/src/tui/actor/model.rs +++ b/crates/cli/src/tui/actor/model.rs @@ -2,9 +2,9 @@ use ratatui::{ layout::Alignment, prelude::{Buffer, Rect}, - style::Stylize as _, + style::{Color, Style, Stylize as _}, symbols::border, - text::Line, + text::{Line, Span}, widgets::{block::Title, Block, Paragraph, StatefulWidget, Widget}, }; @@ -127,7 +127,10 @@ impl From for ServerState { repo_alias.clone(), RepoState::Configured { repo_alias, - message: "configured".into(), + message: RepoMessage::builder() + .text("configured".into()) + .style(Style::default().fg(Color::LightGreen)) + .build(), alert: None, branches: rc.branches().clone(), log: git::graph::Log::default(), @@ -137,7 +140,10 @@ impl From for ServerState { repo_alias.clone(), RepoState::Identified { repo_alias, - message: "identified".into(), + message: RepoMessage::builder() + .text("identified".into()) + .style(Style::default().fg(Color::Gray)) + .build(), alert: None, }, ), @@ -182,23 +188,37 @@ pub struct ForgeState { pub repos: BTreeMap, } +#[bon::builder] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct RepoMessage { + text: String, + style: Style, +} +impl From<&RepoMessage> for Span<'_> { + fn from(value: &RepoMessage) -> Self { + Self::default() + .content(value.text.clone()) + .style(value.style) + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub enum RepoState { Identified { repo_alias: RepoAlias, - message: String, + message: RepoMessage, alert: Option, }, Configured { repo_alias: RepoAlias, - message: String, + message: RepoMessage, alert: Option, branches: RepoBranches, log: Log, }, Ready { repo_alias: RepoAlias, - message: String, + message: RepoMessage, alert: Option, branches: RepoBranches, view_state: ViewState, @@ -241,14 +261,16 @@ impl RepoState { } #[tracing::instrument] - pub fn update_message(&mut self, msg: impl Into + std::fmt::Debug) { - let msg: String = msg.into(); + pub fn update_message(&mut self, msg: impl Into + std::fmt::Debug, colour: Color) { match self { Self::Identified { message, .. } | Self::Configured { message, .. } | Self::Ready { message, .. } => { info!(?msg, "updating ui"); - *message = msg; + *message = RepoMessage::builder() + .text(msg.into()) + .style(Style::default().fg(colour)) + .build(); } } } @@ -265,7 +287,7 @@ impl RepoState { pub fn alert(&mut self, msg: impl Into + std::fmt::Debug) { let msg: String = msg.into(); tracing::info!(%msg, "new tui alert"); - self.update_message("ALERT"); + self.update_message("ALERT", Color::Red); match self { Self::Identified { alert, .. } | Self::Configured { alert, .. } diff --git a/crates/cli/src/tui/components/repo/identity.rs b/crates/cli/src/tui/components/repo/identity.rs index d7b64d78..d95ee1e5 100644 --- a/crates/cli/src/tui/components/repo/identity.rs +++ b/crates/cli/src/tui/components/repo/identity.rs @@ -8,11 +8,13 @@ use ratatui::{ widgets::block::Title, }; +use crate::tui::actor::RepoMessage; + pub struct Identity<'a> { pub label: &'a str, pub repo_alias: &'a RepoAlias, pub alert: Option<&'a str>, - pub message: &'a str, + pub message: &'a RepoMessage, pub repo_branches: Option<&'a RepoBranches>, } impl<'a> Identity<'a> { @@ -20,7 +22,7 @@ impl<'a> Identity<'a> { label: &'a str, repo_alias: &'a RepoAlias, alert: Option<&'a str>, - message: &'a str, + message: &'a RepoMessage, repo_branches: Option<&'a RepoBranches>, ) -> Self { Self { @@ -56,7 +58,10 @@ impl<'a> Identity<'a> { vec![ Span::from(format!(" {repo_alias} ({label}) ")), alert, - Span::from(format!("({main}/{next}/{dev}) [{message}] ")), + Span::from(format!("({main}/{next}/{dev}) [")), + message.into(), + // Span::from(message.}, + Span::from("] "), ] } } diff --git a/crates/cli/src/tui/components/repo/mod.rs b/crates/cli/src/tui/components/repo/mod.rs index 5e1ada9b..830e2a6b 100644 --- a/crates/cli/src/tui/components/repo/mod.rs +++ b/crates/cli/src/tui/components/repo/mod.rs @@ -7,7 +7,10 @@ use git_next_core::{RepoAlias, RepoBranches}; use crate::{ git, - tui::{actor::RepoState, components::CommitLog}, + tui::{ + actor::{RepoMessage, RepoState}, + components::CommitLog, + }, }; use identity::Identity; @@ -97,7 +100,7 @@ impl<'a> Widget for RepoWidget<'a> { struct InnerRepoWidget<'a> { pub label: &'a str, pub repo_alias: &'a RepoAlias, - pub message: &'a str, + pub message: &'a RepoMessage, pub alert: Option<&'a str>, pub branches: Option<&'a RepoBranches>, pub log: Option<&'a git::graph::Log>,