Skip to content

Commit adeae0e

Browse files
committed
feat: display running version in app tui
* Added `VersionInfo` component to display details about currently running version of `ssh-portfolio` inside the TUI * Reduced 5s wait for terminal info query to 1s (potential race condition?) * Export version string in CLI module for reuse in `VersionInfo` component * Include `-dirty` suffix if git tree is dirty (has uncommitted changes)
1 parent 84ce057 commit adeae0e

File tree

4 files changed

+106
-5
lines changed

4 files changed

+106
-5
lines changed

src/app.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub struct App {
4646
cat: Arc<Mutex<Cat>>,
4747
#[cfg(feature = "blog")]
4848
blog_posts: Arc<Mutex<BlogPosts>>,
49+
version_info: Arc<Mutex<VersionInfo>>,
4950
}
5051

5152
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
@@ -83,6 +84,8 @@ impl App {
8384
rt.block_on(content.try_lock()?.blog_content())?,
8485
)));
8586

87+
let version_info = Arc::new(Mutex::new(VersionInfo::new()));
88+
8689
Ok(Self {
8790
terminal_info,
8891
tick_rate,
@@ -105,6 +108,7 @@ impl App {
105108
cat,
106109
#[cfg(feature = "blog")]
107110
blog_posts,
111+
version_info,
108112
})
109113
}
110114

@@ -140,13 +144,14 @@ impl App {
140144
self.cat.try_lock()?.register_config_handler(self.config.clone())?;
141145
#[cfg(feature = "blog")]
142146
self.blog_posts.try_lock()?.register_config_handler(self.config.clone())?;
147+
self.version_info.try_lock()?.register_config_handler(self.config.clone())?;
143148

144-
for _ in 1..50 {
149+
for _ in 1..5 {
145150
if matches!(
146151
self.terminal_info.blocking_read().kind(),
147152
TerminalKind::Unsupported(UnsupportedReason::Unprobed)
148153
) {
149-
tracing::debug!("Waiting for 5s for terminal info to be probed");
154+
tracing::debug!("Waiting for for terminal info to be probed");
150155
std::thread::sleep(Duration::from_millis(100));
151156
}
152157
}
@@ -158,6 +163,7 @@ impl App {
158163
self.cat.try_lock()?.init(self.terminal_info.clone(), size)?;
159164
#[cfg(feature = "blog")]
160165
self.blog_posts.try_lock()?.init(self.terminal_info.clone(), size)?;
166+
self.version_info.try_lock()?.init(self.terminal_info.clone(), size)?;
161167

162168
Ok::<_, eyre::Error>(())
163169
})?;
@@ -377,6 +383,21 @@ impl App {
377383
)
378384
.map_err(std::io::Error::other)?;
379385

386+
// Render version and uptime version info
387+
self.version_info
388+
.try_lock()
389+
.map_err(std::io::Error::other)?
390+
.draw(
391+
frame,
392+
Rect {
393+
x: chunks[0].x,
394+
y: chunks[0].y + 1,
395+
width: chunks[0].width - 2,
396+
height: 1,
397+
},
398+
)
399+
.map_err(std::io::Error::other)?;
400+
380401
// Render the content
381402
let content_rect = Rect {
382403
x: chunks[1].x,

src/cli.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ use indoc::formatdoc;
33

44
use crate::config::{get_config_dir, get_data_dir};
55

6+
lazy_static::lazy_static! {
7+
pub static ref VERSION: String = {
8+
let mut version = format!("v{}-{}", env!("CARGO_PKG_VERSION"), &env!("VERGEN_GIT_SHA")[..7]);
9+
if env!("VERGEN_GIT_DIRTY") == "true" {
10+
version.push_str("-dirty");
11+
}
12+
13+
version
14+
};
15+
}
16+
617
#[derive(Parser, Debug)]
718
#[command(author, version = version(), about)]
819
pub struct Cli {
@@ -28,9 +39,8 @@ pub struct Cli {
2839
pub fn version() -> String {
2940
let author = clap::crate_authors!();
3041
let version_message = format!(
31-
"v{}-{} ({}, {})",
32-
env!("CARGO_PKG_VERSION"),
33-
&env!("VERGEN_GIT_SHA")[..7],
42+
"{} ({}, {})",
43+
*VERSION,
3444
env!("VERGEN_GIT_BRANCH"),
3545
env!("VERGEN_BUILD_DATE")
3646
);

src/components.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ mod cat;
2222
mod content;
2323
#[cfg(feature = "blog")]
2424
mod selection_list;
25+
mod version_info;
2526
mod tabs;
2627

2728
#[cfg(feature = "blog")]
@@ -31,6 +32,7 @@ pub use cat::*;
3132
pub use content::*;
3233
#[cfg(feature = "blog")]
3334
pub use selection_list::*;
35+
pub use version_info::*;
3436
pub use tabs::*;
3537

3638
/// `Component` is a trait that represents a visual and interactive element of the user interface.

src/components/version_info.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use std::default::Default;
2+
3+
use color_eyre::eyre::Result;
4+
use ratatui::prelude::*;
5+
use ratatui::widgets::Paragraph;
6+
use tokio::sync::mpsc::UnboundedSender;
7+
8+
use crate::action::Action;
9+
use crate::components::Component;
10+
use crate::config::Config;
11+
use crate::cli::VERSION;
12+
13+
#[derive(Debug, Default)]
14+
pub struct VersionInfo {
15+
config: Config,
16+
action_tx: Option<UnboundedSender<Action>>,
17+
}
18+
19+
impl VersionInfo {
20+
pub fn new() -> Self {
21+
Self { ..Default::default() }
22+
}
23+
24+
#[rustfmt::skip]
25+
pub fn status_content(&self) -> Line<'static> {
26+
let shell_style = Style::new().fg(Color::Indexed(183));
27+
Line::from(vec![
28+
Span::styled("󰇁 ", shell_style.dim()),
29+
Span::styled(env!("CARGO_PKG_NAME"), shell_style.bold()),
30+
Span::styled(format!(" ({}@{})", env!("VERGEN_GIT_BRANCH"), *VERSION), Style::new().fg(Color::Green).italic()),
31+
Span::styled("█", shell_style.add_modifier(Modifier::BOLD | Modifier::RAPID_BLINK)),
32+
])
33+
}
34+
}
35+
36+
impl Component for VersionInfo {
37+
fn register_config_handler(&mut self, config: Config) -> Result<()> {
38+
self.config = config;
39+
Ok(())
40+
}
41+
42+
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
43+
self.action_tx = Some(tx);
44+
Ok(())
45+
}
46+
47+
fn update(&mut self, action: Action) -> Result<Option<Action>> {
48+
match action {
49+
Action::Tick => {}
50+
Action::Render => {}
51+
_ => {}
52+
};
53+
54+
Ok(None)
55+
}
56+
57+
fn draw(
58+
&mut self,
59+
frame: &mut ratatui::Frame,
60+
area: ratatui::prelude::Rect,
61+
) -> Result<()> {
62+
Paragraph::new(self.status_content())
63+
.alignment(Alignment::Right)
64+
.render(area, frame.buffer_mut());
65+
66+
Ok(())
67+
}
68+
}

0 commit comments

Comments
 (0)