diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a8dbee..86d53a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,7 @@ jobs: profile: minimal toolchain: stable override: true + - name: Format + run: cargo fmt --check - name: Test - shell: bash run: cargo test diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..218e203 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/src/bin/uair/app.rs b/src/bin/uair/app.rs index b0b176c..610c971 100644 --- a/src/bin/uair/app.rs +++ b/src/bin/uair/app.rs @@ -1,15 +1,15 @@ -use std::io::{self, Write, Error as IoError, ErrorKind}; -use std::fs::{self, File}; -use std::time::{Duration, Instant}; -use uair::{Command, FetchArgs, ListenArgs, PauseArgs, ResumeArgs, JumpArgs}; -use log::{LevelFilter, error}; -use futures_lite::FutureExt; -use simplelog::{ColorChoice, Config as LogConfig, TermLogger, TerminalMode, WriteLogger}; -use crate::{Args, Error}; use crate::config::{Config, ConfigBuilder}; -use crate::socket::{Listener, Stream}; use crate::session::{Overridables, Session, SessionId}; +use crate::socket::{Listener, Stream}; use crate::timer::{State, UairTimer}; +use crate::{Args, Error}; +use futures_lite::FutureExt; +use log::{error, LevelFilter}; +use simplelog::{ColorChoice, Config as LogConfig, TermLogger, TerminalMode, WriteLogger}; +use std::fs::{self, File}; +use std::io::{self, Error as IoError, ErrorKind, Write}; +use std::time::{Duration, Instant}; +use uair::{Command, FetchArgs, JumpArgs, ListenArgs, PauseArgs, ResumeArgs}; pub struct App { data: AppData, @@ -23,13 +23,13 @@ impl App { LevelFilter::Info, LogConfig::default(), TerminalMode::Stderr, - ColorChoice::Auto + ColorChoice::Auto, )?; } else { WriteLogger::init( LevelFilter::Info, LogConfig::default(), - File::create(&args.log)? + File::create(&args.log)?, )?; } let timer = UairTimer::new(Duration::from_secs(1), args.quiet); @@ -52,7 +52,7 @@ impl App { Err(Error::ConfError(err)) => error!("{}", err), Err(Error::DeserError(err)) => error!("{}", err), Err(err) => return Err(err), - _ => {}, + _ => {} } } Ok(()) @@ -68,25 +68,33 @@ impl App { Event::Finished | Event::Command(Command::Resume(_) | Command::Next(_)) => { self.timer.state = self.data.initial_state(); } - Event::Command(Command::Prev(_)) => {}, + Event::Command(Command::Prev(_)) => {} Event::Jump(idx) => { self.timer.state = self.data.initial_jump(idx); } Event::Command(Command::Reload(_)) => self.data.read_conf::()?, - Event::Fetch(format, stream) => - self.data.handle_fetch_paused( - Some(&Overridables::new().format(&format)), - stream, - Duration::ZERO - ).await?, - Event::Listen(overrid, stream) => - self.timer.writer.add_stream(stream.into_blocking(), overrid), - Event::ListenExit(overrid, stream) => - self.data.handle_fetch_paused( - overrid.and_then(|o| self.data.curr_session().overrides.get(&o)), - stream, - Duration::ZERO - ).await?, + Event::Fetch(format, stream) => { + self.data + .handle_fetch_paused( + Some(&Overridables::new().format(&format)), + stream, + Duration::ZERO, + ) + .await? + } + Event::Listen(overrid, stream) => self + .timer + .writer + .add_stream(stream.into_blocking(), overrid), + Event::ListenExit(overrid, stream) => { + self.data + .handle_fetch_paused( + overrid.and_then(|o| self.data.curr_session().overrides.get(&o)), + stream, + Duration::ZERO, + ) + .await? + } _ => unreachable!(), } @@ -94,8 +102,12 @@ impl App { } async fn run_session(&mut self, start: Instant, dest: Instant) -> Result<(), Error> { - match self.timer.start(self.data.curr_session(), start, dest) - .or(self.data.handle_commands::()).await? { + match self + .timer + .start(self.data.curr_session(), start, dest) + .or(self.data.handle_commands::()) + .await? + { Event::Finished => { let res = self.data.curr_session().run_command(); self.timer.state = if self.data.sid.is_last() { @@ -105,29 +117,31 @@ impl App { }; res?; } - Event::Command(Command::Pause(_)) => - self.timer.state = State::Paused(dest - Instant::now()), - Event::Command(Command::Next(_)) => - self.timer.state = self.data.next_session(), - Event::Command(Command::Prev(_)) => - self.timer.state = self.data.prev_session(), - Event::Jump(idx) => - self.timer.state = self.data.jump_session(idx), + Event::Command(Command::Pause(_)) => { + self.timer.state = State::Paused(dest - Instant::now()) + } + Event::Command(Command::Next(_)) => self.timer.state = self.data.next_session(), + Event::Command(Command::Prev(_)) => self.timer.state = self.data.prev_session(), + Event::Jump(idx) => self.timer.state = self.data.jump_session(idx), Event::Command(Command::Reload(_)) => self.data.read_conf::()?, - Event::Fetch(format, stream) => - self.data.handle_fetch_resumed( - Some(&Overridables::new().format(&format)), - stream, - dest - ).await?, - Event::Listen(overrid, stream) => - self.timer.writer.add_stream(stream.into_blocking(), overrid), - Event::ListenExit(overrid, stream) => - self.data.handle_fetch_resumed( - overrid.and_then(|o| self.data.curr_session().overrides.get(&o)), - stream, - dest - ).await?, + Event::Fetch(format, stream) => { + self.data + .handle_fetch_resumed(Some(&Overridables::new().format(&format)), stream, dest) + .await? + } + Event::Listen(overrid, stream) => self + .timer + .writer + .add_stream(stream.into_blocking(), overrid), + Event::ListenExit(overrid, stream) => { + self.data + .handle_fetch_resumed( + overrid.and_then(|o| self.data.curr_session().overrides.get(&o)), + stream, + dest, + ) + .await? + } _ => unreachable!(), } Ok(()) @@ -136,7 +150,9 @@ impl App { async fn pause_session(&mut self, duration: Duration) -> Result<(), Error> { const DELTA: Duration = Duration::from_nanos(1_000_000_000 - 1); - self.timer.writer.write::(self.data.curr_session(), duration + DELTA)?; + self.timer + .writer + .write::(self.data.curr_session(), duration + DELTA)?; match self.data.handle_commands::().await? { Event::Finished => { @@ -151,28 +167,36 @@ impl App { Event::Command(Command::Resume(_)) => { let start = Instant::now(); self.timer.state = State::Resumed(start, start + duration); - self.timer.writer.write::(self.data.curr_session(), duration + DELTA)?; + self.timer + .writer + .write::(self.data.curr_session(), duration + DELTA)?; } - Event::Command(Command::Next(_)) => - self.timer.state = self.data.next_session(), - Event::Command(Command::Prev(_)) => - self.timer.state = self.data.prev_session(), + Event::Command(Command::Next(_)) => self.timer.state = self.data.next_session(), + Event::Command(Command::Prev(_)) => self.timer.state = self.data.prev_session(), Event::Jump(idx) => self.timer.state = self.data.jump_session(idx), Event::Command(Command::Reload(_)) => self.data.read_conf::()?, - Event::Fetch(format, stream) => - self.data.handle_fetch_paused( - Some(&Overridables::new().format(&format)), - stream, - duration + DELTA - ).await?, - Event::Listen(overrid, stream) => - self.timer.writer.add_stream(stream.into_blocking(), overrid), - Event::ListenExit(overrid, stream) => - self.data.handle_fetch_paused( - overrid.and_then(|o| self.data.curr_session().overrides.get(&o)), - stream, - duration + DELTA - ).await?, + Event::Fetch(format, stream) => { + self.data + .handle_fetch_paused( + Some(&Overridables::new().format(&format)), + stream, + duration + DELTA, + ) + .await? + } + Event::Listen(overrid, stream) => self + .timer + .writer + .add_stream(stream.into_blocking(), overrid), + Event::ListenExit(overrid, stream) => { + self.data + .handle_fetch_paused( + overrid.and_then(|o| self.data.curr_session().overrides.get(&o)), + stream, + duration + DELTA, + ) + .await? + } _ => unreachable!(), } Ok(()) @@ -208,12 +232,12 @@ impl AppData { } fn read_conf(&mut self) -> Result<(), Error> { - let conf_data = fs::read_to_string(&self.config_path).map_err(|_| + let conf_data = fs::read_to_string(&self.config_path).map_err(|_| { Error::IoError(IoError::new( ErrorKind::NotFound, format!("Could not load config file \"{}\"", self.config_path), - ) - ))?; + )) + })?; let config = ConfigBuilder::deserialize(&conf_data)?.build()?; let mut sid = SessionId::new(&config.sessions, config.iterations); @@ -240,39 +264,52 @@ impl AppData { let msg = stream.read(&mut buffer).await?; let command: Command = bincode::deserialize(&msg)?; match command { - Command::Pause(_) | Command::Toggle(_) if R => - return Ok(Event::Command(Command::Pause(PauseArgs {}))), - Command::Resume(_) | Command::Toggle(_) if !R => - return Ok(Event::Command(Command::Resume(ResumeArgs {}))), - Command::Next(_) if !self.sid.is_last() => - return Ok(Event::Command(command)), - Command::Prev(_) if !self.sid.is_first() => - return Ok(Event::Command(command)), + Command::Pause(_) | Command::Toggle(_) if R => { + return Ok(Event::Command(Command::Pause(PauseArgs {}))) + } + Command::Resume(_) | Command::Toggle(_) if !R => { + return Ok(Event::Command(Command::Resume(ResumeArgs {}))) + } + Command::Next(_) if !self.sid.is_last() => return Ok(Event::Command(command)), + Command::Prev(_) if !self.sid.is_first() => return Ok(Event::Command(command)), Command::Finish(_) => return Ok(Event::Finished), - Command::Jump(JumpArgs { id }) => if let Some(idx) = self.config.idmap.get(&id) { - return Ok(Event::Jump(*idx)); + Command::Jump(JumpArgs { id }) => { + if let Some(idx) = self.config.idmap.get(&id) { + return Ok(Event::Jump(*idx)); + } } Command::Reload(_) => return Ok(Event::Command(command)), - Command::Fetch(FetchArgs { format }) => - return Ok(Event::Fetch(format, stream)), - Command::Listen(ListenArgs { overrid, exit }) => return if exit { - Ok(Event::ListenExit(overrid, stream)) - } else { - Ok(Event::Listen(overrid, stream)) - }, + Command::Fetch(FetchArgs { format }) => return Ok(Event::Fetch(format, stream)), + Command::Listen(ListenArgs { overrid, exit }) => { + return if exit { + Ok(Event::ListenExit(overrid, stream)) + } else { + Ok(Event::Listen(overrid, stream)) + } + } _ => {} } } } - async fn handle_fetch_resumed(&self, overrides: Option<&Overridables>, mut stream: Stream, dest: Instant) -> Result<(), Error> { + async fn handle_fetch_resumed( + &self, + overrides: Option<&Overridables>, + mut stream: Stream, + dest: Instant, + ) -> Result<(), Error> { let remaining = dest - Instant::now(); let displayed = self.curr_session().display::(remaining, overrides); stream.write(format!("{}", displayed).as_bytes()).await?; Ok(()) } - async fn handle_fetch_paused(&self, overrides: Option<&Overridables>, mut stream: Stream, duration: Duration) -> Result<(), Error> { + async fn handle_fetch_paused( + &self, + overrides: Option<&Overridables>, + mut stream: Stream, + duration: Duration, + ) -> Result<(), Error> { let displayed = self.curr_session().display::(duration, overrides); stream.write(format!("{}", displayed).as_bytes()).await?; Ok(()) diff --git a/src/bin/uair/config.rs b/src/bin/uair/config.rs index 89437ac..c185eb4 100644 --- a/src/bin/uair/config.rs +++ b/src/bin/uair/config.rs @@ -1,10 +1,10 @@ +use crate::session::{Color, Overridables, Session, TimeFormatToken, Token}; +use serde::de::Error as _; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use std::time::Duration; use std::str::FromStr; -use serde::{Serialize, Deserialize}; -use serde::de::Error as _; +use std::time::Duration; use toml::de::Error; -use crate::session::{Color, Overridables, Session, Token, TimeFormatToken}; #[derive(Default)] pub struct Config { @@ -40,7 +40,10 @@ impl ConfigBuilder { for (idx, session) in self.sessions.into_iter().enumerate() { let session = session.build(&self.defaults, idx); if let Some(idx2) = idmap.get(&session.id) { - return Err(Error::custom(format!("Duplicate identifier {} present at index {} and {}.", session.id, idx, idx2))); + return Err(Error::custom(format!( + "Duplicate identifier {} present at index {} and {}.", + session.id, idx, idx2 + ))); } idmap.insert(session.id.clone(), idx); sessions.push(session); @@ -72,7 +75,7 @@ pub struct Defaults { command: String, #[serde(default = "Defaults::format")] format: String, - #[serde (default = "Defaults::time_format")] + #[serde(default = "Defaults::time_format")] time_format: String, #[serde(default = "Defaults::autostart")] autostart: bool, @@ -85,15 +88,33 @@ pub struct Defaults { } impl Defaults { - fn name() -> String { "Work".into() } - fn duration() -> Duration { Duration::from_secs(25 * 60) } - fn command() -> String { "notify-send 'Session Completed!'".into() } - fn format() -> String { "{time}\n".into() } - fn time_format() -> String { "%*-Yyear%P %*-Bmonth%P %*-Dday%P %*-Hh %*-Mm %*-Ss".into() } - fn autostart() -> bool { false } - fn paused_state_text() -> String { "⏸".into() } - fn resumed_state_text() -> String { "⏵".into() } - fn overrides() -> HashMap { HashMap::new() } + fn name() -> String { + "Work".into() + } + fn duration() -> Duration { + Duration::from_secs(25 * 60) + } + fn command() -> String { + "notify-send 'Session Completed!'".into() + } + fn format() -> String { + "{time}\n".into() + } + fn time_format() -> String { + "%*-Yyear%P %*-Bmonth%P %*-Dday%P %*-Hh %*-Mm %*-Ss".into() + } + fn autostart() -> bool { + false + } + fn paused_state_text() -> String { + "⏸".into() + } + fn resumed_state_text() -> String { + "⏵".into() + } + fn overrides() -> HashMap { + HashMap::new() + } } impl Default for Defaults { @@ -133,20 +154,34 @@ impl SessionBuilder { fn build(self, defaults: &Defaults, idx: usize) -> Session { let mut default_overrides = defaults.overrides.clone(); default_overrides.extend(self.overrides); - let overrides = default_overrides.into_iter().map(|(k, v)| { - let default = defaults.overrides.get(&k); - (k, v.build(default)) - }).collect(); + let overrides = default_overrides + .into_iter() + .map(|(k, v)| { + let default = defaults.overrides.get(&k); + (k, v.build(default)) + }) + .collect(); Session { id: self.id.unwrap_or_else(|| idx.to_string()), name: self.name.unwrap_or_else(|| defaults.name.clone()), duration: self.duration.unwrap_or_else(|| defaults.duration.clone()), command: self.command.unwrap_or_else(|| defaults.command.clone()), - format: self.format.map(|f| Token::parse(&f)).unwrap_or_else(|| Token::parse(&defaults.format)), - time_format: TimeFormatToken::parse(self.time_format.as_ref().unwrap_or_else(|| &defaults.time_format)), + format: self + .format + .map(|f| Token::parse(&f)) + .unwrap_or_else(|| Token::parse(&defaults.format)), + time_format: TimeFormatToken::parse( + self.time_format + .as_ref() + .unwrap_or_else(|| &defaults.time_format), + ), autostart: self.autostart.unwrap_or_else(|| defaults.autostart.clone()), - paused_state_text: self.paused_state_text.unwrap_or_else(|| defaults.paused_state_text.clone()), - resumed_state_text: self.resumed_state_text.unwrap_or_else(|| defaults.resumed_state_text.clone()), + paused_state_text: self + .paused_state_text + .unwrap_or_else(|| defaults.paused_state_text.clone()), + resumed_state_text: self + .resumed_state_text + .unwrap_or_else(|| defaults.resumed_state_text.clone()), overrides, } } @@ -189,10 +224,20 @@ impl OverridablesBuilder { let default_ob = OverridablesBuilder::default(); let defaults = defaults.unwrap_or(&default_ob); Overridables { - format: self.format.or(defaults.format.clone()).map(|f| Token::parse(&f)), - time_format: self.time_format.or(defaults.time_format.clone()).map(|f| TimeFormatToken::parse(&f)), - paused_state_text: self.paused_state_text.or(defaults.paused_state_text.clone()), - resumed_state_text: self.resumed_state_text.or(defaults.resumed_state_text.clone()), + format: self + .format + .or(defaults.format.clone()) + .map(|f| Token::parse(&f)), + time_format: self + .time_format + .or(defaults.time_format.clone()) + .map(|f| TimeFormatToken::parse(&f)), + paused_state_text: self + .paused_state_text + .or(defaults.paused_state_text.clone()), + resumed_state_text: self + .resumed_state_text + .or(defaults.resumed_state_text.clone()), } } } diff --git a/src/bin/uair/main.rs b/src/bin/uair/main.rs index 7de0f87..08c28ea 100644 --- a/src/bin/uair/main.rs +++ b/src/bin/uair/main.rs @@ -1,19 +1,19 @@ mod app; mod config; -mod socket; mod session; +mod socket; mod timer; -use std::env; -use std::io::{self, Write}; -use std::process::ExitCode; -use uair::get_socket_path; +use crate::app::App; use argh::FromArgs; use futures_lite::{FutureExt, StreamExt}; use log::error; use signal_hook::consts::signal::*; use signal_hook_async_std::Signals; -use crate::app::App; +use std::env; +use std::io::{self, Write}; +use std::process::ExitCode; +use uair::get_socket_path; fn main() -> ExitCode { let args: Args = argh::from_env(); @@ -33,7 +33,9 @@ fn main() -> ExitCode { Ok(app) => app, Err(err) => { error!("{}", err); - if enable_stderr { eprintln!("{}", err) } + if enable_stderr { + eprintln!("{}", err) + } return ExitCode::FAILURE; } }; diff --git a/src/bin/uair/session.rs b/src/bin/uair/session.rs index 1234ced..06ab3ea 100644 --- a/src/bin/uair/session.rs +++ b/src/bin/uair/session.rs @@ -1,12 +1,12 @@ +use humantime::format_duration; use std::collections::HashMap; use std::fmt::{self, Display, Formatter}; use std::io; use std::process; use std::time::Duration; -use humantime::format_duration; -use winnow::{Parser, PResult}; use winnow::combinator::{alt, opt, peek, preceded, repeat, rest}; use winnow::token::{any, one_of, take_until}; +use winnow::{PResult, Parser}; pub struct Session { pub id: String, @@ -22,11 +22,22 @@ pub struct Session { } impl Session { - pub fn display<'s, const R: bool>(&'s self, time: Duration, overrid: Option<&'s Overridables>) -> DisplayableSession<'s, R> { + pub fn display<'s, const R: bool>( + &'s self, + time: Duration, + overrid: Option<&'s Overridables>, + ) -> DisplayableSession<'s, R> { DisplayableSession { session: self, - time: DisplayableTime { time, format: overrid.and_then(|o| o.time_format.as_ref()).unwrap_or(&self.time_format) }, - format: overrid.and_then(|o| o.format.as_ref()).unwrap_or(&self.format), + time: DisplayableTime { + time, + format: overrid + .and_then(|o| o.time_format.as_ref()) + .unwrap_or(&self.time_format), + }, + format: overrid + .and_then(|o| o.format.as_ref()) + .unwrap_or(&self.format), pst_override: overrid.and_then(|o| o.paused_state_text.as_ref().map(|s| s.as_str())), rst_override: overrid.and_then(|o| o.resumed_state_text.as_ref().map(|s| s.as_str())), } @@ -60,14 +71,17 @@ impl Overridables { } pub fn format(self, format: &str) -> Self { - Overridables { format: Some(Token::parse(format)), ..self } + Overridables { + format: Some(Token::parse(format)), + ..self + } } } pub struct DisplayableSession<'s, const R: bool> { session: &'s Session, time: DisplayableTime<'s>, - format: &'s[Token], + format: &'s [Token], pst_override: Option<&'s str>, rst_override: Option<&'s str>, } @@ -77,16 +91,24 @@ impl<'s, const R: bool> Display for DisplayableSession<'s, R> { for token in self.format { match token { Token::Name => write!(f, "{}", self.session.name)?, - Token::Percent => write!(f, "{}", ( - self.time.time.as_secs_f32() * 100.0 / self.session.duration.as_secs_f32() - ) as u8)?, + Token::Percent => write!( + f, + "{}", + (self.time.time.as_secs_f32() * 100.0 / self.session.duration.as_secs_f32()) + as u8 + )?, Token::Time => write!(f, "{}", self.time)?, Token::Total => write!(f, "{}", format_duration(self.session.duration))?, - Token::State => write!(f, "{}", if R { - self.rst_override.unwrap_or(&self.session.resumed_state_text) - } else { - self.pst_override.unwrap_or(&self.session.paused_state_text) - })?, + Token::State => write!( + f, + "{}", + if R { + self.rst_override + .unwrap_or(&self.session.resumed_state_text) + } else { + self.pst_override.unwrap_or(&self.session.paused_state_text) + } + )?, Token::Color(Color::Black) => write!(f, "{}", "\x1b[0;30m")?, Token::Color(Color::Red) => write!(f, "{}", "\x1b[0;31m")?, Token::Color(Color::Green) => write!(f, "{}", "\x1b[0;32m")?, @@ -105,7 +127,7 @@ impl<'s, const R: bool> Display for DisplayableSession<'s, R> { struct DisplayableTime<'s> { time: Duration, - format: &'s[TimeFormatToken], + format: &'s [TimeFormatToken], } impl<'s> Display for DisplayableTime<'s> { @@ -151,7 +173,7 @@ impl<'s> Display for DisplayableTime<'s> { } TimeFormatToken::Literal(literal) if !skip => write!(f, "{}", literal)?, TimeFormatToken::Plural if !skip => write!(f, "{}", plural)?, - _ => {}, + _ => {} } } Ok(()) @@ -179,17 +201,23 @@ impl Token { for (i, c) in format.char_indices() { match c { '{' => open = Some(i), - '}' => if let Some(j) = open { - if let Ok(token) = (&format[j..=i]).parse() { - if k != j { tokens.push(Token::Literal(format[k..j].into())) }; - tokens.push(token); - k = i + 1; + '}' => { + if let Some(j) = open { + if let Ok(token) = (&format[j..=i]).parse() { + if k != j { + tokens.push(Token::Literal(format[k..j].into())) + }; + tokens.push(token); + k = i + 1; + } } } - _ => {}, + _ => {} } } - if k != format.len() { tokens.push(Token::Literal(format[k..].into())) }; + if k != format.len() { + tokens.push(Token::Literal(format[k..].into())) + }; tokens } @@ -205,11 +233,18 @@ pub enum TimeFormatToken { impl TimeFormatToken { pub fn parse(mut format: &str) -> Vec { - let res: PResult> = repeat(0.., alt(( - preceded("%", (opt(one_of('*')), opt(one_of(['-', '_', '0'])), opt(any)).map(Self::identify)), - take_until(0.., "%").map(|s: &str| TimeFormatToken::Literal(s.into())), - (peek(any), rest).map(|(_, s): (char, &str)| TimeFormatToken::Literal(s.into())), - ))).parse_next(&mut format); + let res: PResult> = repeat( + 0.., + alt(( + preceded( + "%", + (opt(one_of('*')), opt(one_of(['-', '_', '0'])), opt(any)).map(Self::identify), + ), + take_until(0.., "%").map(|s: &str| TimeFormatToken::Literal(s.into())), + (peek(any), rest).map(|(_, s): (char, &str)| TimeFormatToken::Literal(s.into())), + )), + ) + .parse_next(&mut format); res.unwrap() } @@ -231,11 +266,17 @@ impl TimeFormatToken { Some('P') => TimeFormatToken::Plural, _ => { let mut l = "%".to_string(); - if let Some(s) = star { l.push(s) }; - if let Some(f) = flag { l.push(f) }; - if let Some(c) = spec { l.push(c) }; + if let Some(s) = star { + l.push(s) + }; + if let Some(f) = flag { + l.push(f) + }; + if let Some(c) = spec { + l.push(c) + }; TimeFormatToken::Literal(l) - }, + } } } } @@ -324,7 +365,10 @@ impl SessionId { } pub fn jump(&self, idx: usize) -> SessionId { - SessionId { index: idx, ..*self } + SessionId { + index: idx, + ..*self + } } pub fn is_last(&self) -> bool { @@ -342,71 +386,95 @@ mod tests { #[test] fn parse_format() { - assert_eq!(&Token::parse("{cyan}{time}{end}\n"), &[ - Token::Color(Color::Cyan), - Token::Time, - Token::Color(Color::End), - Token::Literal("\n".into()), - ]); - assert_eq!(&Token::parse("String with {time} with some text ahead."), &[ - Token::Literal("String with ".into()), - Token::Time, - Token::Literal(" with some text ahead.".into()) - ]); - assert_eq!(&Token::parse("}}{}{{}{}}}{{}{{}}}"), &[ - Token::Literal("}}{}{{}{}}}{{}{{}}}".into()) - ]); - assert_eq!(&Token::parse("{time} text {time}"), &[ - Token::Time, - Token::Literal(" text ".into()), - Token::Time, - ]); + assert_eq!( + &Token::parse("{cyan}{time}{end}\n"), + &[ + Token::Color(Color::Cyan), + Token::Time, + Token::Color(Color::End), + Token::Literal("\n".into()), + ] + ); + assert_eq!( + &Token::parse("String with {time} with some text ahead."), + &[ + Token::Literal("String with ".into()), + Token::Time, + Token::Literal(" with some text ahead.".into()) + ] + ); + assert_eq!( + &Token::parse("}}{}{{}{}}}{{}{{}}}"), + &[Token::Literal("}}{}{{}{}}}{{}{{}}}".into())] + ); + assert_eq!( + &Token::parse("{time} text {time}"), + &[Token::Time, Token::Literal(" text ".into()), Token::Time,] + ); } #[test] fn parse_time_format() { - assert_eq!(&TimeFormatToken::parse("%H:%M:%S"), &[ - TimeFormatToken::Numeric(Numeric::Hour, Pad::Zero, false), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Numeric(Numeric::Minute, Pad::Zero, false), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Numeric(Numeric::Second, Pad::Zero, false), - ]); - assert_eq!(&TimeFormatToken::parse("%L:%M:%S"), &[ - TimeFormatToken::Literal("%L".into()), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Numeric(Numeric::Minute, Pad::Zero, false), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Numeric(Numeric::Second, Pad::Zero, false), - ]); - assert_eq!(&TimeFormatToken::parse("%H:%M:%"), &[ - TimeFormatToken::Numeric(Numeric::Hour, Pad::Zero, false), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Numeric(Numeric::Minute, Pad::Zero, false), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Literal("%".into()), - ]); - assert_eq!(&TimeFormatToken::parse("%_H:%-M:%S"), &[ - TimeFormatToken::Numeric(Numeric::Hour, Pad::Space, false), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Numeric(Numeric::Minute, Pad::None, false), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Numeric(Numeric::Second, Pad::Zero, false), - ]); - assert_eq!(&TimeFormatToken::parse("%H:%*-M:%S"), &[ - TimeFormatToken::Numeric(Numeric::Hour, Pad::Zero, false), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Numeric(Numeric::Minute, Pad::None, true), - TimeFormatToken::Literal(":".into()), - TimeFormatToken::Numeric(Numeric::Second, Pad::Zero, false), - ]); - assert_eq!(&TimeFormatToken::parse("%*-Hh %*-Mm %-Ss"), &[ - TimeFormatToken::Numeric(Numeric::Hour, Pad::None, true), - TimeFormatToken::Literal("h ".into()), - TimeFormatToken::Numeric(Numeric::Minute, Pad::None, true), - TimeFormatToken::Literal("m ".into()), - TimeFormatToken::Numeric(Numeric::Second, Pad::None, false), - TimeFormatToken::Literal("s".into()), - ]); + assert_eq!( + &TimeFormatToken::parse("%H:%M:%S"), + &[ + TimeFormatToken::Numeric(Numeric::Hour, Pad::Zero, false), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Numeric(Numeric::Minute, Pad::Zero, false), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Numeric(Numeric::Second, Pad::Zero, false), + ] + ); + assert_eq!( + &TimeFormatToken::parse("%L:%M:%S"), + &[ + TimeFormatToken::Literal("%L".into()), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Numeric(Numeric::Minute, Pad::Zero, false), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Numeric(Numeric::Second, Pad::Zero, false), + ] + ); + assert_eq!( + &TimeFormatToken::parse("%H:%M:%"), + &[ + TimeFormatToken::Numeric(Numeric::Hour, Pad::Zero, false), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Numeric(Numeric::Minute, Pad::Zero, false), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Literal("%".into()), + ] + ); + assert_eq!( + &TimeFormatToken::parse("%_H:%-M:%S"), + &[ + TimeFormatToken::Numeric(Numeric::Hour, Pad::Space, false), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Numeric(Numeric::Minute, Pad::None, false), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Numeric(Numeric::Second, Pad::Zero, false), + ] + ); + assert_eq!( + &TimeFormatToken::parse("%H:%*-M:%S"), + &[ + TimeFormatToken::Numeric(Numeric::Hour, Pad::Zero, false), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Numeric(Numeric::Minute, Pad::None, true), + TimeFormatToken::Literal(":".into()), + TimeFormatToken::Numeric(Numeric::Second, Pad::Zero, false), + ] + ); + assert_eq!( + &TimeFormatToken::parse("%*-Hh %*-Mm %-Ss"), + &[ + TimeFormatToken::Numeric(Numeric::Hour, Pad::None, true), + TimeFormatToken::Literal("h ".into()), + TimeFormatToken::Numeric(Numeric::Minute, Pad::None, true), + TimeFormatToken::Literal("m ".into()), + TimeFormatToken::Numeric(Numeric::Second, Pad::None, false), + TimeFormatToken::Literal("s".into()), + ] + ); } } diff --git a/src/bin/uair/socket.rs b/src/bin/uair/socket.rs index 3ef3d2d..7dc46a4 100644 --- a/src/bin/uair/socket.rs +++ b/src/bin/uair/socket.rs @@ -1,9 +1,9 @@ -use std::io::{self, Write}; -use std::fs; -use std::path::PathBuf; use async_net::unix::{UnixListener, UnixStream}; -use futures_lite::{AsyncReadExt, AsyncWriteExt}; use futures_lite::io::BlockOn; +use futures_lite::{AsyncReadExt, AsyncWriteExt}; +use std::fs; +use std::io::{self, Write}; +use std::path::PathBuf; pub struct Listener { path: PathBuf, @@ -12,7 +12,10 @@ pub struct Listener { impl Listener { pub fn new(path: &str) -> io::Result { - Ok(Listener { path: path.into(), listener: UnixListener::bind(path)? }) + Ok(Listener { + path: path.into(), + listener: UnixListener::bind(path)?, + }) } pub async fn listen(&self) -> io::Result { @@ -43,7 +46,9 @@ impl Stream { } pub fn into_blocking(self) -> BlockingStream { - BlockingStream { stream: BlockOn::new(self.stream) } + BlockingStream { + stream: BlockOn::new(self.stream), + } } } diff --git a/src/bin/uair/timer.rs b/src/bin/uair/timer.rs index 1c70523..c324014 100644 --- a/src/bin/uair/timer.rs +++ b/src/bin/uair/timer.rs @@ -1,11 +1,11 @@ -use std::io::{self, Stdout, Write}; -use std::fmt::Write as _; -use std::time::{Duration, Instant}; -use async_io::Timer; -use crate::Error; use crate::app::Event; use crate::session::Session; use crate::socket::BlockingStream; +use crate::Error; +use async_io::Timer; +use std::fmt::Write as _; +use std::io::{self, Stdout, Write}; +use std::time::{Duration, Instant}; pub struct UairTimer { interval: Duration, @@ -22,7 +22,12 @@ impl UairTimer { } } - pub async fn start(&mut self, session: &Session, start: Instant, dest: Instant) -> Result { + pub async fn start( + &mut self, + session: &Session, + start: Instant, + dest: Instant, + ) -> Result { let _guard = StateGuard(&mut self.state); let duration = dest - start; @@ -54,10 +59,17 @@ impl Writer { } } - pub fn write(&mut self, session: &Session, duration: Duration) -> Result<(), Error> { + pub fn write( + &mut self, + session: &Session, + duration: Duration, + ) -> Result<(), Error> { if let Some(stdout) = &mut self.stdout { _ = write!(self.buf, "{}", session.display::(duration, None)); - if write!(stdout, "{}", self.buf).and_then(|_| stdout.flush()).is_err() { + if write!(stdout, "{}", self.buf) + .and_then(|_| stdout.flush()) + .is_err() + { self.stdout = None; } self.buf.clear(); diff --git a/src/bin/uairctl/main.rs b/src/bin/uairctl/main.rs index cb44d8c..f4bff7f 100644 --- a/src/bin/uairctl/main.rs +++ b/src/bin/uairctl/main.rs @@ -1,9 +1,9 @@ +use argh::FromArgs; use std::io::{self, BufRead, BufReader, Read, Write}; use std::net::Shutdown; use std::os::unix::net::UnixStream; use std::str; -use uair::{Command, FetchArgs, get_socket_path}; -use argh::FromArgs; +use uair::{get_socket_path, Command, FetchArgs}; fn main() -> Result<(), Error> { let mut args: Args = argh::from_env(); @@ -30,7 +30,9 @@ fn main() -> Result<(), Error> { loop { reader.read_until(b'\0', &mut buf)?; - if buf.is_empty() { break; } + if buf.is_empty() { + break; + } write!(io::stdout(), "{}", str::from_utf8(&buf)?)?; buf.clear(); } @@ -64,7 +66,8 @@ fn unescape(input: &str) -> String { } } match u32::from_str_radix(&input[i + 1..i + 5], 16) - .map(|num| char::from_u32(num)) { + .map(|num| char::from_u32(num)) + { Ok(Some(num)) => res.push(num), _ => res.push_str(&input[i - 1..i + 5]), } @@ -77,7 +80,8 @@ fn unescape(input: &str) -> String { } } match u32::from_str_radix(&input[i + 1..i + 9], 16) - .map(|num| char::from_u32(num)) { + .map(|num| char::from_u32(num)) + { Ok(Some(num)) => res.push(num), _ => res.push_str(&input[i - 1..i + 9]), } diff --git a/src/lib.rs b/src/lib.rs index be4a1b7..e3f01ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ -use std::env; use argh::FromArgs; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; +use std::env; #[derive(FromArgs, Serialize, Deserialize)] #[argh(subcommand)]