From 572db7f1826d4e6f77d3c5ec753777bcc0bb942e Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Tue, 9 Jul 2024 20:08:58 +0200 Subject: [PATCH] refactor: move clock to module in preparation for cli --- Cargo.toml | 1 + src/clock.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 100 ++++++++---------------------------------------- 3 files changed, 121 insertions(+), 85 deletions(-) create mode 100644 src/clock.rs diff --git a/Cargo.toml b/Cargo.toml index 1caa2fe..2ddba8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ categories = ["date-and-time"] [dependencies] +anyhow = "1.0.86" chrono = "0.4.38" libpt = { version = "0.6.0", features = ["cli"] } ratatui = "0.27.0" diff --git a/src/clock.rs b/src/clock.rs new file mode 100644 index 0000000..11ca7d7 --- /dev/null +++ b/src/clock.rs @@ -0,0 +1,105 @@ +#![warn(clippy::pedantic, clippy::style, clippy::nursery)] +#![allow(clippy::question_mark_used)] +use clap::Parser; +use libpt::cli::{args::VerbosityLevel, args::HELP_TEMPLATE, clap}; + +use chrono::SubsecRound; +use ratatui::crossterm::event::{ + self, poll, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers, +}; +use ratatui::layout::Alignment; +use ratatui::widgets::{Block, Padding}; +use ratatui::{ + backend::CrosstermBackend, + crossterm::{ + execute, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, + }, + layout::{Constraint, Direction, Layout, Rect}, + style::{Style, Stylize}, + widgets::Paragraph, + Terminal, +}; +use std::io::Stdout; +use std::time::Duration; + +/// Make your terminal into a big clock +#[derive(Parser, Debug, Clone, PartialEq, Eq, Hash)] +#[command(help_template = HELP_TEMPLATE)] +pub(crate) struct Clock { + #[command(flatten)] + pub verbose: VerbosityLevel, +} + +impl Clock { + pub(crate) fn run( + self, + terminal: &mut Terminal>, + ) -> anyhow::Result<()> { + loop { + let raw_time = chrono::Local::now().round_subsecs(0); + let splits: Vec = raw_time + .naive_local() + .to_string() + .split_whitespace() + .map(str::to_string) + .collect(); + let fdate: String = splits[0].clone(); + let ftime: String = splits[1].clone(); + terminal.draw(|frame| { + let root = frame.size(); + let space = Block::bordered() + .padding(Padding::new( + root.width / 8, + root.width / 8, + root.height / 8, + root.height / 8, + )) + .title(env!("CARGO_PKG_NAME")) + .title_bottom(env!("CARGO_PKG_VERSION")) + .title_alignment(Alignment::Center) + .title_style(Style::new().bold()); + let a = space.inner(root); + let parts = Self::partition(a); + let timew = tui_big_text::BigText::builder() + .style(Style::new().red()) + .lines(vec![ftime.into()]) + .alignment(Alignment::Center) + .build() + .expect("could not render time widget"); + let datew = Paragraph::new(fdate) + .blue() + .alignment(Alignment::Left) + .block(Block::new().padding(Padding::new( + parts.0.left(), + parts.0.right() / 3, + 0, + 0, + ))); + frame.render_widget(space, root); + frame.render_widget(timew, parts.1); + frame.render_widget(datew, parts.0); + })?; + if poll(Duration::from_millis(100))? { + if let Event::Key(key) = event::read()? { + if key.code == KeyCode::Char('q') + || key.code == KeyCode::Esc + || (key.modifiers.contains(KeyModifiers::CONTROL) + && key.code == KeyCode::Char('c')) + { + break; + } + } + } + } + Ok(()) + } + fn partition(r: Rect) -> (Rect, Rect) { + let part = Layout::default() + .direction(Direction::Vertical) + .constraints([Constraint::Percentage(13), Constraint::Min(0)]) + .split(r); + + (part[0], part[1]) + } +} diff --git a/src/main.rs b/src/main.rs index ac59d48..78d424a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,19 @@ -#![warn(clippy::pedantic, clippy::style, clippy::nursery)] -#![allow(clippy::question_mark_used)] +use std::io; -use chrono::SubsecRound; -use ratatui::crossterm::event::{ - self, poll, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers, +use libpt::cli::clap::Parser; +use ratatui::backend::CrosstermBackend; +use ratatui::crossterm::event::{DisableMouseCapture, EnableMouseCapture}; +use ratatui::crossterm::execute; +use ratatui::crossterm::terminal::{ + disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, }; -use ratatui::layout::Alignment; -use ratatui::widgets::{Block, Padding}; -use ratatui::{ - backend::CrosstermBackend, - crossterm::{ - execute, - terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, - }, - layout::{Constraint, Direction, Layout, Rect}, - style::{Style, Stylize}, - widgets::Paragraph, - Terminal, -}; -use std::{io, time::Duration}; +use ratatui::Terminal; -fn main() -> Result<(), io::Error> { +use self::clock::Clock; + +mod clock; + +fn main() -> anyhow::Result<()> { // setup terminal enable_raw_mode()?; let mut stdout = io::stdout(); @@ -28,62 +21,8 @@ fn main() -> Result<(), io::Error> { let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend)?; - loop { - let raw_time = chrono::Local::now().round_subsecs(0); - let splits: Vec = raw_time - .naive_local() - .to_string() - .split_whitespace() - .map(str::to_string) - .collect(); - let fdate: String = splits[0].clone(); - let ftime: String = splits[1].clone(); - terminal.draw(|frame| { - let root = frame.size(); - let space = Block::bordered() - .padding(Padding::new( - root.width / 8, - root.width / 8, - root.height / 8, - root.height / 8, - )) - .title(env!("CARGO_PKG_NAME")) - .title_bottom(env!("CARGO_PKG_VERSION")) - .title_alignment(Alignment::Center) - .title_style(Style::new().bold()); - let a = space.inner(root); - let parts = partition(a); - let timew = tui_big_text::BigText::builder() - .style(Style::new().red()) - .lines(vec![ftime.into()]) - .alignment(Alignment::Center) - .build() - .expect("could not render time widget"); - let datew = Paragraph::new(fdate) - .blue() - .alignment(Alignment::Left) - .block(Block::new().padding(Padding::new( - parts.0.left(), - parts.0.right() / 3, - 0, - 0, - ))); - frame.render_widget(space, root); - frame.render_widget(timew, parts.1); - frame.render_widget(datew, parts.0); - })?; - if poll(Duration::from_millis(100))? { - if let Event::Key(key) = event::read()? { - if key.code == KeyCode::Char('q') - || key.code == KeyCode::Esc - || (key.modifiers.contains(KeyModifiers::CONTROL) - && key.code == KeyCode::Char('c')) - { - break; - } - } - } - } + let clock = Clock::parse(); + clock.run(&mut terminal)?; // restore terminal disable_raw_mode()?; @@ -96,12 +35,3 @@ fn main() -> Result<(), io::Error> { Ok(()) } - -fn partition(r: Rect) -> (Rect, Rect) { - let part = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Percentage(13), Constraint::Min(0)]) - .split(r); - - (part[0], part[1]) -}