diff --git a/atuin-client/config.toml b/atuin-client/config.toml index 9a094f88..1ddaa12e 100644 --- a/atuin-client/config.toml +++ b/atuin-client/config.toml @@ -148,6 +148,10 @@ enter_accept = true ## Timeout (in seconds) for acquiring a local database connection (sqlite) # local_timeout = 5 +## Set this to true and Atuin will minimize motion in the UI - timers will not update live, etc. +## Alternatively, set env NO_MOTION=true +# prefers_reduced_motion = false + #[stats] # Set commands where we should consider the subcommand for statistics. Eg, kubectl get vs just kubectl #common_subcommands = [ diff --git a/atuin-client/src/settings.rs b/atuin-client/src/settings.rs index de6b10a4..833311c8 100644 --- a/atuin-client/src/settings.rs +++ b/atuin-client/src/settings.rs @@ -278,6 +278,7 @@ pub struct Settings { pub word_chars: String, pub scroll_context_lines: usize, pub history_format: String, + pub prefers_reduced_motion: bool, #[serde(with = "serde_regex", default = "RegexSet::empty")] pub history_filter: RegexSet, @@ -524,6 +525,13 @@ impl Settings { .set_default("keymap_mode", "emacs")? .set_default("keymap_mode_shell", "auto")? .set_default("keymap_cursor", HashMap::::new())? + .set_default( + "prefers_reduced_motion", + std::env::var("NO_MOTION") + .ok() + .map(|_| config::Value::new(None, config::ValueKind::Boolean(true))) + .unwrap_or_else(|| config::Value::new(None, config::ValueKind::Boolean(false))), + )? .add_source( Environment::with_prefix("atuin") .prefix_separator("_") diff --git a/atuin/src/command/client/search/history_list.rs b/atuin/src/command/client/search/history_list.rs index 7ae2c3d7..488ed89f 100644 --- a/atuin/src/command/client/search/history_list.rs +++ b/atuin/src/command/client/search/history_list.rs @@ -18,6 +18,7 @@ pub struct HistoryList<'a> { inverted: bool, /// Apply an alternative highlighting to the selected row alternate_highlight: bool, + now: &'a dyn Fn() -> OffsetDateTime, } #[derive(Default)] @@ -68,6 +69,7 @@ impl<'a> StatefulWidget for HistoryList<'a> { state, inverted: self.inverted, alternate_highlight: self.alternate_highlight, + now: &self.now, }; for item in self.history.iter().skip(state.offset).take(end - start) { @@ -84,12 +86,18 @@ impl<'a> StatefulWidget for HistoryList<'a> { } impl<'a> HistoryList<'a> { - pub fn new(history: &'a [History], inverted: bool, alternate_highlight: bool) -> Self { + pub fn new( + history: &'a [History], + inverted: bool, + alternate_highlight: bool, + now: &'a dyn Fn() -> OffsetDateTime, + ) -> Self { Self { history, block: None, inverted, alternate_highlight, + now, } } @@ -121,6 +129,7 @@ struct DrawState<'a> { state: &'a ListState, inverted: bool, alternate_highlight: bool, + now: &'a dyn Fn() -> OffsetDateTime, } // longest line prefix I could come up with @@ -160,7 +169,7 @@ impl DrawState<'_> { // would fail. // If the timestamp would otherwise be in the future, display // the time since as 0. - let since = OffsetDateTime::now_utc() - h.timestamp; + let since = (self.now)() - h.timestamp; let time = format_duration(since.try_into().unwrap_or_default()); // pad the time a little bit before we write. this aligns things nicely diff --git a/atuin/src/command/client/search/interactive.rs b/atuin/src/command/client/search/interactive.rs index 27c82f2c..1a94e36d 100644 --- a/atuin/src/command/client/search/interactive.rs +++ b/atuin/src/command/client/search/interactive.rs @@ -16,6 +16,7 @@ use crossterm::{ use eyre::Result; use futures_util::FutureExt; use semver::Version; +use time::OffsetDateTime; use unicode_width::UnicodeWidthStr; use atuin_client::{ @@ -69,6 +70,7 @@ pub struct State { search: SearchState, engine: Box, + now: Box OffsetDateTime + Send>, } #[derive(Clone, Copy)] @@ -550,7 +552,8 @@ impl State { match self.tab_index { 0 => { - let results_list = Self::build_results_list(style, results, self.keymap_mode); + let results_list = + Self::build_results_list(style, results, self.keymap_mode, &self.now); f.render_stateful_widget(results_list, results_list_chunk, &mut self.results_state); } @@ -652,13 +655,18 @@ impl State { stats } - fn build_results_list( + fn build_results_list<'a>( style: StyleState, - results: &[History], + results: &'a [History], keymap_mode: KeymapMode, - ) -> HistoryList<'_> { - let results_list = - HistoryList::new(results, style.invert, keymap_mode == KeymapMode::VimNormal); + now: &'a dyn Fn() -> OffsetDateTime, + ) -> HistoryList<'a> { + let results_list = HistoryList::new( + results, + style.invert, + keymap_mode == KeymapMode::VimNormal, + now, + ); if style.compact { results_list @@ -882,6 +890,12 @@ pub async fn history( value => value, }, current_cursor: None, + now: if settings.prefers_reduced_motion { + let now = OffsetDateTime::now_utc(); + Box::new(move || now) + } else { + Box::new(OffsetDateTime::now_utc) + }, }; app.initialize_keymap_cursor(settings);