aboutsummaryrefslogtreecommitdiffstats
path: root/crates/turtle/src/command/client
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-12 17:16:19 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-12 17:16:19 +0200
commit2ca7dd57b12861e8c9bbc9238cda612e0ff22ff3 (patch)
tree302a644f6a50d60cc8304c4498fe6bbb72ddaaa9 /crates/turtle/src/command/client
parentfeat(server): Really make users stateless (with tests) (diff)
downloadatuin-2ca7dd57b12861e8c9bbc9238cda612e0ff22ff3.zip
chore(treewide): Cleanup themes
Diffstat (limited to 'crates/turtle/src/command/client')
-rw-r--r--crates/turtle/src/command/client/daemon.rs36
-rw-r--r--crates/turtle/src/command/client/history.rs224
-rw-r--r--crates/turtle/src/command/client/search.rs4
-rw-r--r--crates/turtle/src/command/client/search/engines.rs8
-rw-r--r--crates/turtle/src/command/client/search/history_list.rs44
-rw-r--r--crates/turtle/src/command/client/search/inspector.rs52
-rw-r--r--crates/turtle/src/command/client/search/interactive.rs140
-rw-r--r--crates/turtle/src/command/client/stats.rs11
-rw-r--r--crates/turtle/src/command/client/store.rs14
-rw-r--r--crates/turtle/src/command/client/store/pull.rs12
-rw-r--r--crates/turtle/src/command/client/store/purge.rs4
-rw-r--r--crates/turtle/src/command/client/store/push.rs4
-rw-r--r--crates/turtle/src/command/client/store/rebuild.rs2
-rw-r--r--crates/turtle/src/command/client/store/rekey.rs1
-rw-r--r--crates/turtle/src/command/client/store/verify.rs4
-rw-r--r--crates/turtle/src/command/client/sync.rs6
-rw-r--r--crates/turtle/src/command/client/wrapped.rs18
17 files changed, 157 insertions, 427 deletions
diff --git a/crates/turtle/src/command/client/daemon.rs b/crates/turtle/src/command/client/daemon.rs
index cb5dd118..41cb04fe 100644
--- a/crates/turtle/src/command/client/daemon.rs
+++ b/crates/turtle/src/command/client/daemon.rs
@@ -22,16 +22,8 @@ use tokio::time::sleep;
#[derive(clap::Args, Debug)]
pub(crate) struct Cmd {
- /// Internal flag for daemonization
- #[arg(long, hide = true)]
- daemonize: bool,
-
- /// Also write daemon logs to the console (useful for debugging)
- #[arg(long)]
- show_logs: bool,
-
#[command(subcommand)]
- subcmd: Option<SubCmd>,
+ subcmd: SubCmd,
}
#[derive(Subcommand, Debug)]
@@ -67,8 +59,7 @@ impl Cmd {
#[cfg(unix)]
pub(crate) fn should_daemonize(&self) -> bool {
match &self.subcmd {
- Some(SubCmd::Start { daemonize, .. }) => *daemonize,
- None => self.daemonize,
+ SubCmd::Start { daemonize, .. } => *daemonize,
_ => false,
}
}
@@ -76,8 +67,7 @@ impl Cmd {
/// Returns `true` when logs should also be written to the console.
pub(crate) fn show_logs(&self) -> bool {
match &self.subcmd {
- Some(SubCmd::Start { show_logs, .. }) => *show_logs,
- None => self.show_logs,
+ SubCmd::Start { show_logs, .. } => *show_logs,
_ => false,
}
}
@@ -89,14 +79,10 @@ impl Cmd {
history_db: ClientSqlite,
) -> Result<()> {
match self.subcmd {
- None => {
- eprintln!("Warning: `atuin daemon` is deprecated, use `atuin daemon start`");
- run(settings, store, history_db, false).await
- }
- Some(SubCmd::Start { force, .. }) => run(settings, store, history_db, force).await,
- Some(SubCmd::Status) => status_cmd(&settings).await,
- Some(SubCmd::Stop) => stop_cmd(&settings).await,
- Some(SubCmd::Restart) => restart_cmd(&settings).await,
+ SubCmd::Start { force, .. } => run(settings, store, history_db, force).await,
+ SubCmd::Status => status_cmd(&settings).await,
+ SubCmd::Stop => stop_cmd(&settings).await,
+ SubCmd::Restart => restart_cmd(&settings).await,
}
}
}
@@ -331,7 +317,6 @@ async fn wait_until_ready(settings: &Settings, timeout: Duration) -> Result<Hist
}
}
-#[expect(clippy::unnecessary_wraps)]
fn ensure_autostart_supported(settings: &Settings) -> Result<()> {
#[cfg(unix)]
if settings.daemon.systemd_socket {
@@ -438,7 +423,12 @@ pub(crate) async fn start_history(settings: &Settings, history: History) -> Resu
Ok(resp.id)
}
-pub(crate) async fn end_history(settings: &Settings, id: String, duration: u64, exit: i64) -> Result<()> {
+pub(crate) async fn end_history(
+ settings: &Settings,
+ id: String,
+ duration: u64,
+ exit: i64,
+) -> Result<()> {
match async {
connect_client(settings)
.await?
diff --git a/crates/turtle/src/command/client/history.rs b/crates/turtle/src/command/client/history.rs
index 693098c0..2ddcb3a6 100644
--- a/crates/turtle/src/command/client/history.rs
+++ b/crates/turtle/src/command/client/history.rs
@@ -10,14 +10,10 @@ use clap::Subcommand;
use eyre::{Context, Result, bail};
use runtime_format::{FormatKey, FormatKeyError, ParseSegment, ParsedFmt};
-#[cfg(feature = "daemon")]
use super::daemon as daemon_cmd;
-#[cfg(feature = "daemon")]
use colored::Colorize;
-#[cfg(feature = "daemon")]
use serde::Serialize;
-#[cfg(feature = "daemon")]
use crate::atuin_daemon::history::{HistoryEventKind, TailHistoryReply};
use crate::atuin_client::{
@@ -31,13 +27,9 @@ use crate::atuin_client::{
},
};
-#[cfg(feature = "sync")]
-use crate::atuin_client::record;
-
-use log::{debug, warn};
+use log::debug;
use time::{OffsetDateTime, macros::format_description};
-#[cfg(feature = "daemon")]
use super::daemon;
use super::search::format_duration_into;
@@ -65,8 +57,10 @@ pub(crate) enum Cmd {
/// Finishes a new command in the history (adds time, exit code)
End {
id: String,
+
#[arg(long, short)]
exit: i64,
+
#[arg(long, short)]
duration: Option<u64>,
},
@@ -181,7 +175,6 @@ impl ListMode {
}
}
-#[expect(clippy::cast_sign_loss)]
pub(crate) fn print_list(
h: &[History],
list_mode: ListMode,
@@ -410,42 +403,6 @@ fn normalize_command_for_storage<'a>(command: &'a str, settings: &Settings) -> &
}
}
-async fn handle_start(
- db: &ClientSqlite,
- settings: &Settings,
- command: &str,
- author: Option<&str>,
- intent: Option<&str>,
-) -> Result<Option<String>> {
- // It's better for atuin to silently fail here and attempt to
- // store whatever is ran, than to throw an error to the terminal
- let cwd = utils::get_current_dir();
- let command = normalize_command_for_storage(command, settings);
-
- let mut h: History = History::capture()
- .timestamp(OffsetDateTime::now_utc())
- .command(command)
- .cwd(cwd)
- .build()
- .into();
- apply_start_metadata(&mut h, author, intent);
-
- if !h.should_save(settings) {
- return Ok(None);
- }
-
- let id = h.id.0.clone();
-
- // Silently ignore database errors to avoid breaking the shell
- // This is important when disk is full or database is locked
- if let Err(e) = db.save(&h).await {
- debug!("failed to save history: {e}");
- }
-
- Ok(Some(id))
-}
-
-#[cfg(feature = "daemon")]
async fn handle_daemon_start(
settings: &Settings,
command: &str,
@@ -482,65 +439,6 @@ async fn handle_daemon_start(
Ok(Some(resp))
}
-#[expect(unused_variables)]
-async fn handle_end(
- db: &ClientSqlite,
- store: SqliteStore,
- history_store: HistoryStore,
- settings: &Settings,
- id: &str,
- exit: i64,
- duration: Option<u64>,
-) -> Result<()> {
- if id.trim() == "" {
- return Ok(());
- }
-
- let Some(mut h) = db.load(id).await? else {
- warn!("history entry is missing");
- return Ok(());
- };
-
- if h.duration > 0 {
- debug!("cannot end history - already has duration");
-
- // returning OK as this can occur if someone Ctrl-c a prompt
- return Ok(());
- }
-
- if !settings.store_failed && exit > 0 {
- debug!("history has non-zero exit code, and store_failed is false");
-
- // the history has already been inserted half complete. remove it
- db.delete(h).await?;
-
- return Ok(());
- }
-
- h.exit = exit;
- h.duration = match duration {
- Some(value) => i64::try_from(value).context("command took over 292 years")?,
- None => i64::try_from((OffsetDateTime::now_utc() - h.timestamp).whole_nanoseconds())
- .context("command took over 292 years")?,
- };
-
- db.update(&h).await?;
- history_store.push(h).await?;
-
- if settings.sync.should_sync().await? {
- let (_, downloaded) =
- record::sync::sync(settings, &store, &history_store.encryption_key).await?;
- Settings::save_sync_time().await?;
-
- crate::sync::build(settings, &store, db, Some(&downloaded)).await?;
- } else {
- debug!("sync disabled! not syncing");
- }
-
- Ok(())
-}
-
-#[cfg(feature = "daemon")]
async fn handle_daemon_end(
settings: &Settings,
id: &str,
@@ -552,70 +450,24 @@ async fn handle_daemon_end(
Ok(())
}
-pub(super) async fn start_history_entry(
- settings: &Settings,
- command: &str,
- author: Option<&str>,
- intent: Option<&str>,
-) -> Result<Option<String>> {
- #[cfg(feature = "daemon")]
- if settings.daemon.enabled {
- return handle_daemon_start(settings, command, author, intent).await;
- }
-
- let db_path = PathBuf::from(settings.db_path.as_str());
- let db = ClientSqlite::new(db_path, settings.local_timeout).await?;
- handle_start(&db, settings, command, author, intent).await
-}
-
-pub(super) async fn end_history_entry(
- settings: &Settings,
- id: &str,
- exit: i64,
- duration: Option<u64>,
-) -> Result<()> {
- #[cfg(feature = "daemon")]
- if settings.daemon.enabled {
- return handle_daemon_end(settings, id, exit, duration).await;
- }
-
- let db_path = PathBuf::from(settings.db_path.as_str());
- let record_store_path = PathBuf::from(settings.record_store_path.as_str());
-
- let db = ClientSqlite::new(db_path, settings.local_timeout).await?;
- let store = SqliteStore::new(record_store_path, settings.local_timeout).await?;
-
- let encryption_key: [u8; 32] = encryption::load_key(settings)
- .context("could not load encryption key")?
- .into();
- let host_id = Settings::host_id().await?;
- let history_store = HistoryStore::new(store.clone(), host_id, encryption_key);
-
- handle_end(&db, store, history_store, settings, id, exit, duration).await
-}
-
-#[cfg(feature = "daemon")]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum TailKind {
Started,
Ended,
}
-#[cfg(feature = "daemon")]
#[derive(Clone, Debug, Eq, PartialEq)]
struct TailEvent {
kind: TailKind,
history: History,
}
-#[cfg(feature = "daemon")]
#[derive(Serialize)]
struct TailJsonEvent<'a> {
event: &'static str,
history: TailJsonHistory<'a>,
}
-#[cfg(feature = "daemon")]
#[derive(Serialize)]
struct TailJsonHistory<'a> {
id: &'a str,
@@ -642,7 +494,6 @@ struct TailJsonHistory<'a> {
finished_at: Option<String>,
}
-#[cfg(feature = "daemon")]
impl TailEvent {
fn from_proto(reply: TailHistoryReply) -> Result<Self> {
let history = reply
@@ -828,7 +679,6 @@ impl TailEvent {
}
}
-#[cfg(feature = "daemon")]
impl TailKind {
const fn as_str(self) -> &'static str {
match self {
@@ -846,12 +696,10 @@ impl TailKind {
}
}
-#[cfg(feature = "daemon")]
fn format_history_time(timestamp: OffsetDateTime, tz: Timezone) -> Result<String> {
Ok(timestamp.to_offset(tz.0).format(TIME_FMT)?)
}
-#[cfg(feature = "daemon")]
fn format_duration_ns(duration_ns: i64) -> String {
struct F(Duration);
impl Display for F {
@@ -863,7 +711,6 @@ fn format_duration_ns(duration_ns: i64) -> String {
F(Duration::from_nanos(duration_ns.max(0).cast_unsigned())).to_string()
}
-#[cfg(feature = "daemon")]
fn push_pretty_field(out: &mut String, label: &str, value: &str) {
out.push_str(" ");
let label = format!("{label}:");
@@ -885,7 +732,6 @@ fn push_pretty_field(out: &mut String, label: &str, value: &str) {
}
}
-#[cfg(feature = "daemon")]
fn normalize_optional_field(value: &str) -> Option<String> {
let trimmed = value.trim();
if trimmed.is_empty() {
@@ -896,7 +742,6 @@ fn normalize_optional_field(value: &str) -> Option<String> {
}
impl Cmd {
- #[cfg(feature = "daemon")]
async fn handle_tail(settings: &Settings) -> Result<()> {
let tty = std::io::stdout().is_terminal();
let mut client = daemon::tail_client(settings).await?;
@@ -918,7 +763,6 @@ impl Cmd {
Ok(())
}
- #[expect(clippy::too_many_lines, clippy::cast_possible_truncation)]
#[expect(clippy::too_many_arguments)]
#[expect(clippy::fn_params_excessive_bools)]
async fn handle_list(
@@ -1010,7 +854,6 @@ impl Cmd {
history_store.incremental_build(db, &[id]).await?;
}
- #[cfg(feature = "daemon")]
daemon_cmd::emit_event(settings, crate::atuin_daemon::DaemonEvent::HistoryPruned).await;
}
Ok(())
@@ -1058,7 +901,6 @@ impl Cmd {
let host_id = Settings::host_id().await?;
let history_store = HistoryStore::new(store.clone(), host_id, encryption_key);
- #[cfg(feature = "daemon")]
let ids = matches.iter().map(|h| h.id.clone()).collect::<Vec<_>>();
for entry in matches {
@@ -1067,7 +909,6 @@ impl Cmd {
history_store.incremental_build(db, &[id]).await?;
}
- #[cfg(feature = "daemon")]
daemon_cmd::emit_event(
settings,
crate::atuin_daemon::DaemonEvent::HistoryDeleted { ids },
@@ -1093,7 +934,7 @@ impl Cmd {
};
if let Some(id) =
- start_history_entry(settings, &command, author.as_deref(), intent.as_deref())
+ handle_daemon_start(settings, &command, author.as_deref(), intent.as_deref())
.await?
{
println!("{id}");
@@ -1102,16 +943,10 @@ impl Cmd {
Ok(())
}
Self::End { id, exit, duration } => {
- end_history_entry(settings, &id, exit, duration).await
+ handle_daemon_end(settings, &id, exit, duration).await
}
Self::Tail => {
- #[cfg(feature = "daemon")]
- {
- return Self::handle_tail(settings).await;
- }
-
- #[cfg(not(feature = "daemon"))]
- bail!("`atuin history tail` requires Atuin to be built with the `daemon` feature");
+ return Self::handle_tail(settings).await;
}
cmd => {
let context = current_context().await?;
@@ -1204,14 +1039,13 @@ impl Cmd {
#[cfg(test)]
mod tests {
- #[cfg(feature = "daemon")]
use time::macros::datetime;
use super::*;
#[test]
fn normalize_command_strips_trailing_spaces_and_tabs() {
- let settings = Settings::utc();
+ let settings = Settings::new().unwrap();
assert!(settings.strip_trailing_whitespace);
assert_eq!(normalize_command_for_storage("ls \t", &settings), "ls");
@@ -1219,7 +1053,7 @@ mod tests {
#[test]
fn normalize_command_preserves_escaped_trailing_space() {
- let settings = Settings::utc();
+ let settings = Settings::new().unwrap();
assert_eq!(
normalize_command_for_storage("printf foo\\ ", &settings),
@@ -1231,45 +1065,6 @@ mod tests {
);
}
- #[tokio::test]
- async fn handle_start_saves_trimmed_command() {
- let db = ClientSqlite::new("sqlite::memory:", 2.0).await.unwrap();
- let settings = Settings::utc();
-
- handle_start(&db, &settings, "ls \t", None, None)
- .await
- .unwrap();
-
- let history = db
- .before(OffsetDateTime::now_utc() + time::Duration::SECOND, 1)
- .await
- .unwrap()
- .pop()
- .unwrap();
- assert_eq!(history.command, "ls");
- }
-
- #[tokio::test]
- async fn handle_start_can_keep_trailing_whitespace() {
- let db = ClientSqlite::new("sqlite::memory:", 2.0).await.unwrap();
- let settings = Settings {
- strip_trailing_whitespace: false,
- ..Settings::utc()
- };
-
- handle_start(&db, &settings, "ls \t", None, None)
- .await
- .unwrap();
-
- let history = db
- .before(OffsetDateTime::now_utc() + time::Duration::SECOND, 1)
- .await
- .unwrap()
- .pop()
- .unwrap();
- assert_eq!(history.command, "ls \t");
- }
-
#[test]
fn test_format_string_no_panic() {
// Don't panic but provide helpful output (issue #2776)
@@ -1286,7 +1081,6 @@ mod tests {
assert!(std::panic::catch_unwind(|| parse_fmt("{time} - {command}")).is_ok());
}
- #[cfg(feature = "daemon")]
fn sample_tail_event(kind: TailKind) -> TailEvent {
TailEvent {
kind,
@@ -1306,7 +1100,6 @@ mod tests {
}
}
- #[cfg(feature = "daemon")]
#[test]
fn test_tail_json_output_contains_history_fields() {
let json = sample_tail_event(TailKind::Ended)
@@ -1321,7 +1114,6 @@ mod tests {
assert!(value.get("record").is_none());
}
- #[cfg(feature = "daemon")]
#[test]
fn test_tail_pretty_output_shows_pending_fields_for_started_events() {
let rendered = sample_tail_event(TailKind::Started)
diff --git a/crates/turtle/src/command/client/search.rs b/crates/turtle/src/command/client/search.rs
index 962e6b1e..bba48b8a 100644
--- a/crates/turtle/src/command/client/search.rs
+++ b/crates/turtle/src/command/client/search.rs
@@ -12,7 +12,6 @@ use crate::atuin_client::{
history::{History, store::HistoryStore},
record::sqlite_store::SqliteStore,
settings::{FilterMode, KeymapMode, SearchMode, Settings, Timezone},
- theme::Theme,
};
use super::history::ListMode;
@@ -160,7 +159,6 @@ impl Cmd {
db: ClientSqlite,
settings: &mut Settings,
store: SqliteStore,
- theme: &Theme,
) -> Result<()> {
let query = self.query.unwrap_or_else(|| {
std::env::var("ATUIN_QUERY").map_or_else(
@@ -226,7 +224,7 @@ impl Cmd {
let history_store = HistoryStore::new(store.clone(), host_id, encryption_key);
if self.interactive {
- let item = interactive::history(&query, settings, db, &history_store, theme).await?;
+ let item = interactive::history(&query, settings, db, &history_store).await?;
if let Some(result_file) = self.result_file {
let mut file = File::create(result_file)?;
diff --git a/crates/turtle/src/command/client/search/engines.rs b/crates/turtle/src/command/client/search/engines.rs
index a84c4798..94834221 100644
--- a/crates/turtle/src/command/client/search/engines.rs
+++ b/crates/turtle/src/command/client/search/engines.rs
@@ -8,22 +8,14 @@ use eyre::Result;
use super::cursor::Cursor;
-#[cfg(feature = "daemon")]
pub(crate) mod daemon;
pub(crate) mod db;
pub(crate) mod skim;
-#[expect(unused)] // settings is only used if daemon feature is enabled
pub(crate) fn engine(search_mode: SearchMode, settings: &Settings) -> Box<dyn SearchEngine> {
match search_mode {
SearchMode::Skim => Box::new(skim::Search::new()) as Box<_>,
- #[cfg(feature = "daemon")]
SearchMode::DaemonFuzzy => Box::new(daemon::Search::new(settings)) as Box<_>,
- #[cfg(not(feature = "daemon"))]
- SearchMode::DaemonFuzzy => {
- // Fall back to fuzzy mode if daemon feature is not enabled
- Box::new(db::Search(SearchMode::Fuzzy)) as Box<_>
- }
mode => Box::new(db::Search(mode)) as Box<_>,
}
}
diff --git a/crates/turtle/src/command/client/search/history_list.rs b/crates/turtle/src/command/client/search/history_list.rs
index 9d3a60e0..e46f37b7 100644
--- a/crates/turtle/src/command/client/search/history_list.rs
+++ b/crates/turtle/src/command/client/search/history_list.rs
@@ -5,7 +5,10 @@ use super::engines::SearchEngine;
use crate::atuin_client::{
history::History,
settings::{UiColumn, UiColumnType},
- theme::{Meaning, Theme},
+ theme::{
+ style_alerterror, style_alertinfo, style_alertwarn, style_annotation, style_base,
+ style_guidance,
+ },
};
use crate::atuin_common::utils::Escapable as _;
use itertools::Itertools;
@@ -39,7 +42,7 @@ pub(crate) struct HistoryList<'a> {
alternate_highlight: bool,
now: &'a dyn Fn() -> OffsetDateTime,
indicator: &'a str,
- theme: &'a Theme,
+
history_highlighter: HistoryHighlighter<'a>,
show_numeric_shortcuts: bool,
/// Columns to display (in order, after the indicator)
@@ -100,7 +103,7 @@ impl StatefulWidget for HistoryList<'_> {
alternate_highlight: self.alternate_highlight,
now: &self.now,
indicator: self.indicator,
- theme: self.theme,
+
history_highlighter: self.history_highlighter,
show_numeric_shortcuts: self.show_numeric_shortcuts,
columns: self.columns,
@@ -124,7 +127,7 @@ impl<'a> HistoryList<'a> {
alternate_highlight: bool,
now: &'a dyn Fn() -> OffsetDateTime,
indicator: &'a str,
- theme: &'a Theme,
+
history_highlighter: HistoryHighlighter<'a>,
show_numeric_shortcuts: bool,
columns: &'a [UiColumn],
@@ -136,7 +139,6 @@ impl<'a> HistoryList<'a> {
alternate_highlight,
now,
indicator,
- theme,
history_highlighter,
show_numeric_shortcuts,
columns,
@@ -173,7 +175,7 @@ struct DrawState<'a> {
alternate_highlight: bool,
now: &'a dyn Fn() -> OffsetDateTime,
indicator: &'a str,
- theme: &'a Theme,
+
history_highlighter: HistoryHighlighter<'a>,
show_numeric_shortcuts: bool,
columns: &'a [UiColumn],
@@ -203,7 +205,7 @@ impl DrawState<'_> {
.width
.saturating_sub(indicator_width + fixed_width);
- let style = self.theme.as_style(Meaning::Base);
+ let style = style_base();
// Render each configured column
for (idx, column) in self.columns.iter().enumerate() {
if idx != 0 {
@@ -251,11 +253,11 @@ impl DrawState<'_> {
}
fn duration(&mut self, h: &History, width: u16) {
- let style = self.theme.as_style(if h.success() {
- Meaning::AlertInfo
+ let style = if h.success() {
+ style_alertinfo()
} else {
- Meaning::AlertError
- });
+ style_alerterror()
+ };
let duration = Duration::from_nanos(u64::try_from(h.duration).unwrap_or(0));
let formatted = format_duration(duration);
let w = width as usize;
@@ -265,7 +267,7 @@ impl DrawState<'_> {
}
fn time(&mut self, h: &History, width: u16) {
- let style = self.theme.as_style(Meaning::Guidance);
+ let style = style_guidance();
// Account for the chance that h.timestamp is "in the future"
// This would mean that "since" is negative, and the unwrap here
@@ -284,13 +286,13 @@ impl DrawState<'_> {
}
fn command(&mut self, h: &History) {
- let mut style = self.theme.as_style(Meaning::Base);
+ let mut style = style_base();
let mut row_highlighted = false;
if !self.alternate_highlight && (self.y as usize + self.state.offset == self.state.selected)
{
row_highlighted = true;
// if not applying alternative highlighting to the whole row, color the command
- style = self.theme.as_style(Meaning::AlertError);
+ style = style_alerterror();
style.attributes.set(style::Attribute::Bold);
}
@@ -318,7 +320,7 @@ impl DrawState<'_> {
if row_highlighted {
// if the row is highlighted bold is not enough as the whole row is bold
// change the color too
- style = self.theme.as_style(Meaning::AlertWarn);
+ style = style_alertwarn();
}
style.attributes.set(style::Attribute::Bold);
}
@@ -332,7 +334,7 @@ impl DrawState<'_> {
/// Render the absolute datetime column (e.g., "2025-01-22 14:35")
fn datetime(&mut self, h: &History, width: u16) {
- let style = self.theme.as_style(Meaning::Annotation);
+ let style = style_annotation();
// Format: YYYY-MM-DD HH:MM
let formatted = h
.timestamp
@@ -348,7 +350,7 @@ impl DrawState<'_> {
/// Render the directory column (working directory, truncated)
fn directory(&mut self, h: &History, width: u16) {
- let style = self.theme.as_style(Meaning::Annotation);
+ let style = style_annotation();
let w = width as usize;
let cwd = &h.cwd;
let char_count = cwd.chars().count();
@@ -365,7 +367,7 @@ impl DrawState<'_> {
/// Render the host column (just the hostname)
fn host(&mut self, h: &History, width: u16) {
- let style = self.theme.as_style(Meaning::Annotation);
+ let style = style_annotation();
let w = width as usize;
// Database stores hostname as "hostname:username"
let host = h.hostname.split(':').next().unwrap_or(&h.hostname);
@@ -382,7 +384,7 @@ impl DrawState<'_> {
/// Render the user column
fn user(&mut self, h: &History, width: u16) {
- let style = self.theme.as_style(Meaning::Annotation);
+ let style = style_annotation();
let w = width as usize;
// Database stores hostname as "hostname:username"
let user = h.hostname.split(':').nth(1).unwrap_or("");
@@ -400,9 +402,9 @@ impl DrawState<'_> {
/// Render the exit code column
fn exit_code(&mut self, h: &History, width: u16) {
let style = if h.success() {
- self.theme.as_style(Meaning::AlertInfo)
+ style_alertinfo()
} else {
- self.theme.as_style(Meaning::AlertError)
+ style_alerterror()
};
let w = width as usize;
let display = format!("{:>w$}", h.exit);
diff --git a/crates/turtle/src/command/client/search/inspector.rs b/crates/turtle/src/command/client/search/inspector.rs
index a1bf803f..f7b40a26 100644
--- a/crates/turtle/src/command/client/search/inspector.rs
+++ b/crates/turtle/src/command/client/search/inspector.rs
@@ -4,6 +4,7 @@ use time::macros::format_description;
use crate::atuin_client::{
history::{History, HistoryStats},
settings::{Settings, Timezone},
+ theme::{style_annotation, style_base, style_important},
};
use ratatui::{
Frame,
@@ -17,7 +18,6 @@ use ratatui::{
use super::duration::format_duration;
-use super::super::theme::{Meaning, Theme};
use super::interactive::{Compactness, to_compactness};
#[expect(clippy::cast_sign_loss)]
@@ -31,7 +31,6 @@ pub(crate) fn draw_commands(
history: &History,
stats: &HistoryStats,
compact: bool,
- theme: &Theme,
) {
let commands = Layout::default()
.direction(if compact {
@@ -56,16 +55,16 @@ pub(crate) fn draw_commands(
let command = Paragraph::new(Text::from(Span::styled(
history.command.clone(),
- Style::from_crossterm(theme.as_style(Meaning::Important)),
+ Style::from_crossterm(style_important()),
)))
.block(if compact {
Block::new()
.borders(Borders::NONE)
- .style(Style::from_crossterm(theme.as_style(Meaning::Base)))
+ .style(Style::from_crossterm(style_base()))
} else {
Block::new()
.borders(Borders::ALL)
- .style(Style::from_crossterm(theme.as_style(Meaning::Base)))
+ .style(Style::from_crossterm(style_base()))
.title("Command")
.padding(Padding::horizontal(1))
});
@@ -79,11 +78,11 @@ pub(crate) fn draw_commands(
.block(if compact {
Block::new()
.borders(Borders::NONE)
- .style(Style::from_crossterm(theme.as_style(Meaning::Annotation)))
+ .style(Style::from_crossterm(style_annotation()))
} else {
Block::new()
.borders(Borders::ALL)
- .style(Style::from_crossterm(theme.as_style(Meaning::Annotation)))
+ .style(Style::from_crossterm(style_annotation()))
.title("Previous command")
.padding(Padding::horizontal(1))
});
@@ -99,13 +98,13 @@ pub(crate) fn draw_commands(
.block(if compact {
Block::new()
.borders(Borders::NONE)
- .style(Style::from_crossterm(theme.as_style(Meaning::Annotation)))
+ .style(Style::from_crossterm(style_annotation()))
} else {
Block::new()
.borders(Borders::ALL)
.title("Next command")
.padding(Padding::horizontal(1))
- .style(Style::from_crossterm(theme.as_style(Meaning::Annotation)))
+ .style(Style::from_crossterm(style_annotation()))
});
f.render_widget(previous, commands[0]);
@@ -119,7 +118,6 @@ pub(crate) fn draw_stats_table(
history: &History,
tz: Timezone,
stats: &HistoryStats,
- theme: &Theme,
) {
let duration = Duration::from_nanos(u64_or_zero(history.duration));
let avg_duration = Duration::from_nanos(stats.average_duration);
@@ -149,7 +147,7 @@ pub(crate) fn draw_stats_table(
Block::default()
.title("Command stats")
.borders(Borders::ALL)
- .style(Style::from_crossterm(theme.as_style(Meaning::Base)))
+ .style(Style::from_crossterm(style_base()))
.padding(Padding::vertical(1)),
);
@@ -196,7 +194,7 @@ fn sort_duration_over_time(durations: &[(String, i64)]) -> Vec<(String, i64)> {
.collect()
}
-fn draw_stats_charts(f: &mut Frame<'_>, parent: Rect, stats: &HistoryStats, theme: &Theme) {
+fn draw_stats_charts(f: &mut Frame<'_>, parent: Rect, stats: &HistoryStats) {
let exits: Vec<Bar> = stats
.exits
.iter()
@@ -211,7 +209,7 @@ fn draw_stats_charts(f: &mut Frame<'_>, parent: Rect, stats: &HistoryStats, them
.block(
Block::default()
.title("Exit code distribution")
- .style(Style::from_crossterm(theme.as_style(Meaning::Base)))
+ .style(Style::from_crossterm(style_base()))
.borders(Borders::ALL),
)
.bar_width(3)
@@ -235,7 +233,7 @@ fn draw_stats_charts(f: &mut Frame<'_>, parent: Rect, stats: &HistoryStats, them
.block(
Block::default()
.title("Runs per day")
- .style(Style::from_crossterm(theme.as_style(Meaning::Base)))
+ .style(Style::from_crossterm(style_base()))
.borders(Borders::ALL),
)
.bar_width(3)
@@ -261,7 +259,7 @@ fn draw_stats_charts(f: &mut Frame<'_>, parent: Rect, stats: &HistoryStats, them
.block(
Block::default()
.title("Duration over time")
- .style(Style::from_crossterm(theme.as_style(Meaning::Base)))
+ .style(Style::from_crossterm(style_base()))
.borders(Borders::ALL),
)
.bar_width(5)
@@ -291,14 +289,13 @@ pub(crate) fn draw(
history: &History,
stats: &HistoryStats,
settings: &Settings,
- theme: &Theme,
tz: Timezone,
) {
let compactness = to_compactness(f, settings);
match compactness {
- Compactness::Ultracompact => draw_ultracompact(f, chunk, history, stats, theme),
- _ => draw_full(f, chunk, history, stats, theme, tz),
+ Compactness::Ultracompact => draw_ultracompact(f, chunk, history, stats),
+ _ => draw_full(f, chunk, history, stats, tz),
}
}
@@ -307,9 +304,8 @@ pub(crate) fn draw_ultracompact(
chunk: Rect,
history: &History,
stats: &HistoryStats,
- theme: &Theme,
) {
- draw_commands(f, chunk, history, stats, true, theme);
+ draw_commands(f, chunk, history, stats, true);
}
pub(crate) fn draw_full(
@@ -317,7 +313,6 @@ pub(crate) fn draw_full(
chunk: Rect,
history: &History,
stats: &HistoryStats,
- theme: &Theme,
tz: Timezone,
) {
let vert_layout = Layout::default()
@@ -330,18 +325,15 @@ pub(crate) fn draw_full(
.constraints([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)])
.split(vert_layout[1]);
- draw_commands(f, vert_layout[0], history, stats, false, theme);
- draw_stats_table(f, stats_layout[0], history, tz, stats, theme);
- draw_stats_charts(f, stats_layout[1], stats, theme);
+ draw_commands(f, vert_layout[0], history, stats, false);
+ draw_stats_table(f, stats_layout[0], history, tz, stats);
+ draw_stats_charts(f, stats_layout[1], stats);
}
#[cfg(test)]
mod tests {
use super::draw_ultracompact;
- use crate::atuin_client::{
- history::{History, HistoryId, HistoryStats},
- theme::ThemeManager,
- };
+ use crate::atuin_client::history::{History, HistoryId, HistoryStats};
use ratatui::{backend::TestBackend, prelude::*};
use time::OffsetDateTime;
@@ -406,9 +398,7 @@ mod tests {
let prev = stats.previous.clone().unwrap();
let next = stats.next.clone().unwrap();
- let mut manager = ThemeManager::new(Some(true), Some("".to_string()));
- let theme = manager.load_theme("(none)", None);
- let _ = terminal.draw(|f| draw_ultracompact(f, chunk, &history, &stats, &theme));
+ let _ = terminal.draw(|f| draw_ultracompact(f, chunk, &history, &stats));
let mut lines = [" "; 5].map(|l| Line::from(l));
for (n, entry) in [prev, history, next].iter().enumerate() {
let mut l = lines[n].to_string();
diff --git a/crates/turtle/src/command/client/search/interactive.rs b/crates/turtle/src/command/client/search/interactive.rs
index 1d067e50..2c6af8cf 100644
--- a/crates/turtle/src/command/client/search/interactive.rs
+++ b/crates/turtle/src/command/client/search/interactive.rs
@@ -7,7 +7,10 @@ use std::{
use std::io::Read as _;
use crate::{
- atuin_client::database::ClientSqlite,
+ atuin_client::{
+ database::ClientSqlite,
+ theme::{style_annotation, style_base, style_important},
+ },
atuin_common::{shell::Shell, utils::Escapable as _},
};
use eyre::Result;
@@ -30,7 +33,6 @@ use crate::atuin_client::{
use crate::command::client::search::history_list::HistoryHighlighter;
use crate::command::client::search::keybindings::KeymapSet;
-use crate::command::client::theme::{Meaning, Theme};
use crate::{VERSION, command::client::search::engines};
use ratatui::{
@@ -42,7 +44,7 @@ use ratatui::{
execute, queue, terminal,
},
layout::{Alignment, Constraint, Direction, Layout},
- prelude::*,
+ prelude::Rect,
style::{Modifier, Style},
text::{Line, Span, Text},
widgets::{Block, BorderType, Borders, Clear, Padding, Paragraph, Tabs},
@@ -800,9 +802,6 @@ impl State {
}
}
- #[expect(clippy::bool_to_int_with_if)]
- #[expect(clippy::too_many_lines)]
- #[expect(clippy::too_many_arguments)]
fn draw(
&mut self,
f: &mut Frame,
@@ -810,17 +809,16 @@ impl State {
stats: Option<HistoryStats>,
inspecting: Option<&History>,
settings: &Settings,
- theme: &Theme,
+
popup_mode: bool,
) {
let area = f.area();
if popup_mode {
f.render_widget(Clear, area);
}
- self.draw_inner(f, area, results, stats, inspecting, settings, theme);
+ self.draw_inner(f, area, results, stats, inspecting, settings);
}
- #[expect(clippy::too_many_arguments)]
#[expect(clippy::too_many_lines)]
#[expect(clippy::bool_to_int_with_if)]
fn draw_inner(
@@ -831,7 +829,6 @@ impl State {
stats: Option<HistoryStats>,
inspecting: Option<&History>,
settings: &Settings,
- theme: &Theme,
) {
let compactness = to_compactness(f, settings);
let invert = settings.invert;
@@ -905,7 +902,7 @@ impl State {
.block(Block::default().borders(Borders::NONE))
.select(self.tab_index)
.style(Style::default())
- .highlight_style(Style::from_crossterm(theme.as_style(Meaning::Important)));
+ .highlight_style(Style::from_crossterm(style_important()));
f.render_widget(tabs, tabs_chunk);
}
@@ -928,13 +925,13 @@ impl State {
)
.split(header_chunk);
- let title = Self::build_title(theme);
+ let title = Self::build_title();
f.render_widget(title, header_chunks[0]);
- let help = self.build_help(settings, theme);
+ let help = self.build_help(settings);
f.render_widget(help, header_chunks[1]);
- let stats_tab = self.build_stats(theme);
+ let stats_tab = self.build_stats();
f.render_widget(stats_tab, header_chunks[2]);
let indicator: String = match compactness {
@@ -968,7 +965,6 @@ impl State {
self.keymap_mode,
&self.now,
indicator.as_str(),
- theme,
history_highlighter,
settings.show_numeric_shortcuts,
&settings.ui.columns,
@@ -999,7 +995,6 @@ impl State {
inspecting,
&stats.expect("Drawing inspector, but no stats"),
settings,
- theme,
settings.timezone,
);
}
@@ -1029,7 +1024,6 @@ impl State {
compactness,
preview_width,
preview_chunk.width.into(),
- theme,
);
#[expect(clippy::cast_possible_truncation)]
let prefix_width = settings
@@ -1083,9 +1077,9 @@ impl State {
));
}
- fn build_title(theme: &Theme) -> Paragraph<'_> {
+ fn build_title<'a>() -> Paragraph<'a> {
let title = {
- let style: Style = Style::from_crossterm(theme.as_style(Meaning::Base));
+ let style: Style = Style::from_crossterm(style_base());
Paragraph::new(Text::from(Span::styled(
format!("Atuin v{VERSION}"),
style.add_modifier(Modifier::BOLD),
@@ -1095,7 +1089,7 @@ impl State {
}
#[expect(clippy::unused_self)]
- fn build_help(&self, settings: &Settings, theme: &Theme) -> Paragraph<'_> {
+ fn build_help(&self, settings: &Settings) -> Paragraph<'_> {
match self.tab_index {
// search
0 => Paragraph::new(Text::from(Line::from(vec![
@@ -1129,16 +1123,16 @@ impl State {
_ => unreachable!("invalid tab index"),
}
- .style(Style::from_crossterm(theme.as_style(Meaning::Annotation)))
+ .style(Style::from_crossterm(style_annotation()))
.alignment(Alignment::Center)
}
- fn build_stats(&self, theme: &Theme) -> Paragraph<'_> {
+ fn build_stats(&self) -> Paragraph<'_> {
Paragraph::new(Text::from(Span::raw(format!(
"history count: {}",
self.history_count,
))))
- .style(Style::from_crossterm(theme.as_style(Meaning::Annotation)))
+ .style(Style::from_crossterm(style_annotation()))
.alignment(Alignment::Right)
}
@@ -1149,7 +1143,7 @@ impl State {
keymap_mode: KeymapMode,
now: &'a dyn Fn() -> OffsetDateTime,
indicator: &'a str,
- theme: &'a Theme,
+
history_highlighter: HistoryHighlighter<'a>,
show_numeric_shortcuts: bool,
columns: &'a [UiColumn],
@@ -1160,7 +1154,6 @@ impl State {
keymap_mode == KeymapMode::VimNormal,
now,
indicator,
- theme,
history_highlighter,
show_numeric_shortcuts,
columns,
@@ -1228,7 +1221,6 @@ impl State {
compactness: Compactness,
preview_width: u16,
chunk_width: usize,
- theme: &Theme,
) -> Paragraph<'_> {
let selected = self.results_state.selected();
let command = if results.is_empty() {
@@ -1264,8 +1256,7 @@ impl State {
.border_type(BorderType::Rounded)
.title(format!("{:─>width$}", "", width = chunk_width - 2)),
),
- _ => Paragraph::new(command)
- .style(Style::from_crossterm(theme.as_style(Meaning::Annotation))),
+ _ => Paragraph::new(command).style(Style::from_crossterm(style_annotation())),
}
}
}
@@ -1320,9 +1311,7 @@ impl Write for TerminalWriter {
/// Screen state captured from atuin pty-proxy's screen server.
#[cfg(unix)]
struct SavedScreen {
- #[expect(dead_code)]
rows: u16,
- #[expect(dead_code)]
cols: u16,
cursor_row: u16,
cursor_col: u16,
@@ -1555,7 +1544,6 @@ pub(crate) async fn history(
settings: &Settings,
mut db: ClientSqlite,
history_store: &HistoryStore,
- theme: &Theme,
) -> Result<String> {
let inline_height = if settings.shell_up_key_binding {
settings
@@ -1752,7 +1740,6 @@ pub(crate) async fn history(
stats.clone(),
inspecting.as_ref(),
settings,
- theme,
popup_mode,
);
})?;
@@ -1832,7 +1819,7 @@ pub(crate) async fn history(
terminal.clear()?;
}
terminal.draw(|f| {
- app.draw(f, &results, stats.clone(), inspecting.as_ref(), settings, theme, popup_mode);
+ app.draw(f, &results, stats.clone(), inspecting.as_ref(), settings, popup_mode);
})?;
},
r => {
@@ -1979,10 +1966,7 @@ pub(crate) async fn history(
// cli-clipboard only works on Windows, Mac, and Linux.
-#[cfg(all(
- feature = "clipboard",
- any(target_os = "windows", target_os = "macos", target_os = "linux")
-))]
+#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
fn set_clipboard(s: String) {
let mut ctx = arboard::Clipboard::new().unwrap();
ctx.set_text(s).unwrap();
@@ -1990,12 +1974,6 @@ fn set_clipboard(s: String) {
ctx.get_text().unwrap();
}
-#[cfg(not(all(
- feature = "clipboard",
- any(target_os = "windows", target_os = "macos", target_os = "linux")
-)))]
-fn set_clipboard(_s: String) {}
-
#[cfg(test)]
mod tests {
use crate::atuin_client::database::Context;
@@ -2018,7 +1996,7 @@ mod tests {
strategy: PreviewStrategy::Auto,
},
show_preview: true,
- ..Settings::utc()
+ ..Settings::now()
};
let settings_preview_auto_h2 = Settings {
@@ -2027,7 +2005,7 @@ mod tests {
},
show_preview: true,
max_preview_height: 2,
- ..Settings::utc()
+ ..Settings::now()
};
let settings_preview_h4 = Settings {
@@ -2036,7 +2014,7 @@ mod tests {
},
show_preview: true,
max_preview_height: 4,
- ..Settings::utc()
+ ..Settings::now()
};
let settings_preview_fixed = Settings {
@@ -2045,7 +2023,7 @@ mod tests {
},
show_preview: true,
max_preview_height: 15,
- ..Settings::utc()
+ ..Settings::now()
};
let cmd_60: History = History::capture()
@@ -2167,7 +2145,7 @@ mod tests {
// Test when there's no results, scrolling up or down doesn't underflow
#[test]
fn state_scroll_up_underflow() {
- let settings = Settings::utc();
+ let settings = Settings::now();
let mut state = State {
history_count: 0,
results_state: ListState::default(),
@@ -2212,7 +2190,7 @@ mod tests {
use crate::atuin_client::settings::Keys;
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
- let mut settings = Settings::utc();
+ let mut settings = Settings::now();
settings.keys = Keys {
scroll_exits: true,
exit_past_line_start: false,
@@ -2338,7 +2316,7 @@ mod tests {
fn test_vim_gg_multikey_sequence() {
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
- let settings = Settings::utc();
+ let settings = Settings::now();
let mut state = State {
history_count: 100,
@@ -2396,7 +2374,7 @@ mod tests {
fn test_vim_g_key_clears_on_other_input() {
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
- let settings = Settings::utc();
+ let settings = Settings::now();
let mut state = State {
history_count: 100,
@@ -2450,7 +2428,7 @@ mod tests {
fn test_vim_big_g_jump_to_bottom() {
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
- let settings = Settings::utc();
+ let settings = Settings::now();
let mut state = State {
history_count: 100,
@@ -2500,7 +2478,7 @@ mod tests {
fn test_vim_ctrl_u_d_half_page_scroll() {
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
- let settings = Settings::utc();
+ let settings = Settings::now();
let mut state = State {
history_count: 100,
@@ -2559,7 +2537,7 @@ mod tests {
fn test_vim_ctrl_f_b_full_page_scroll() {
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
- let settings = Settings::utc();
+ let settings = Settings::now();
let mut state = State {
history_count: 100,
@@ -2620,7 +2598,7 @@ mod tests {
/// Helper to build a State for executor tests.
fn make_executor_state(results_len: usize, selected: usize) -> State {
- let settings = Settings::utc();
+ let settings = Settings::now();
let mut state = State {
history_count: results_len as i64,
results_state: ListState::default(),
@@ -2664,7 +2642,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 50);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::SelectNext, &settings);
assert!(matches!(result, super::InputAction::Continue));
// Non-inverted: SelectNext = scroll_down = selected - 1
@@ -2676,7 +2654,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 50);
- let mut settings = Settings::utc();
+ let mut settings = Settings::now();
settings.invert = true;
let result = state.execute_action(&Action::SelectNext, &settings);
assert!(matches!(result, super::InputAction::Continue));
@@ -2689,7 +2667,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 50);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::SelectPrevious, &settings);
assert!(matches!(result, super::InputAction::Continue));
// Non-inverted: SelectPrevious = scroll_up = selected + 1
@@ -2701,7 +2679,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 0);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::VimEnterNormal, &settings);
assert!(matches!(result, super::InputAction::Continue));
assert_eq!(state.keymap_mode, KeymapMode::VimNormal);
@@ -2713,7 +2691,7 @@ mod tests {
let mut state = make_executor_state(100, 0);
state.keymap_mode = KeymapMode::VimNormal;
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::VimEnterInsert, &settings);
assert!(matches!(result, super::InputAction::Continue));
assert_eq!(state.keymap_mode, KeymapMode::VimInsert);
@@ -2724,7 +2702,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 5);
- let mut settings = Settings::utc();
+ let mut settings = Settings::now();
settings.enter_accept = true;
let result = state.execute_action(&Action::Accept, &settings);
assert!(matches!(result, super::InputAction::Accept(5)));
@@ -2736,7 +2714,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 5);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::ReturnSelection, &settings);
assert!(matches!(result, super::InputAction::Accept(5)));
assert!(!state.accept);
@@ -2747,7 +2725,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 5);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::AcceptNth(3), &settings);
assert!(matches!(result, super::InputAction::Accept(8)));
}
@@ -2757,7 +2735,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 50);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::ScrollToTop, &settings);
assert!(matches!(result, super::InputAction::Continue));
// Non-inverted: visual top = highest index
@@ -2769,7 +2747,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 50);
- let mut settings = Settings::utc();
+ let mut settings = Settings::now();
settings.invert = true;
let result = state.execute_action(&Action::ScrollToTop, &settings);
assert!(matches!(result, super::InputAction::Continue));
@@ -2782,7 +2760,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 50);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::ScrollToBottom, &settings);
assert!(matches!(result, super::InputAction::Continue));
// Non-inverted: visual bottom = index 0
@@ -2794,7 +2772,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 0);
- let settings = Settings::utc();
+ let settings = Settings::now();
assert_eq!(state.tab_index, 0);
state.execute_action(&Action::ToggleTab, &settings);
assert_eq!(state.tab_index, 1);
@@ -2807,7 +2785,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 0);
- let settings = Settings::utc();
+ let settings = Settings::now();
assert!(!state.prefix);
state.execute_action(&Action::EnterPrefixMode, &settings);
assert!(state.prefix);
@@ -2819,7 +2797,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 0);
- let mut settings = Settings::utc();
+ let mut settings = Settings::now();
settings.exit_mode = ExitMode::ReturnOriginal;
let result = state.execute_action(&Action::Exit, &settings);
@@ -2835,7 +2813,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 0);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::ReturnOriginal, &settings);
assert!(matches!(result, super::InputAction::ReturnOriginal));
}
@@ -2845,7 +2823,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 7);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::Copy, &settings);
assert!(matches!(result, super::InputAction::Copy(7)));
}
@@ -2855,7 +2833,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 7);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::Delete, &settings);
assert!(matches!(result, super::InputAction::Delete(7)));
}
@@ -2865,7 +2843,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 7);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::SwitchContext, &settings);
assert!(matches!(result, super::InputAction::SwitchContext(Some(7))));
}
@@ -2875,7 +2853,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 7);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::ClearContext, &settings);
assert!(matches!(result, super::InputAction::SwitchContext(None)));
}
@@ -2885,7 +2863,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 50);
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::Noop, &settings);
assert!(matches!(result, super::InputAction::Continue));
assert_eq!(state.results_state.selected(), 50);
@@ -2897,7 +2875,7 @@ mod tests {
let mut state = make_executor_state(100, 5);
state.tab_index = 1;
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::Accept, &settings);
assert!(matches!(result, super::InputAction::AcceptInspecting));
}
@@ -2907,7 +2885,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 0);
- let settings = Settings::utc();
+ let settings = Settings::now();
let original_mode = state.search_mode;
let result = state.execute_action(&Action::CycleSearchMode, &settings);
assert!(matches!(result, super::InputAction::Continue));
@@ -2923,7 +2901,7 @@ mod tests {
state.search.input.insert('h');
state.search.input.insert('i');
state.keymap_mode = KeymapMode::VimNormal;
- let settings = Settings::utc();
+ let settings = Settings::now();
let result = state.execute_action(&Action::VimSearchInsert, &settings);
assert!(matches!(result, super::InputAction::Continue));
// Should clear input and switch to insert mode
@@ -2936,7 +2914,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 0);
- let settings = Settings::utc();
+ let settings = Settings::now();
// Insert some text
state.search.input.insert('h');
@@ -2968,7 +2946,7 @@ mod tests {
use crate::command::client::search::keybindings::Action;
let mut state = make_executor_state(100, 0);
- let settings = Settings::utc();
+ let settings = Settings::now();
// Insert "hello"
state.search.input.insert('h');
@@ -2992,7 +2970,7 @@ mod tests {
use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use std::collections::HashMap;
- let mut settings = Settings::utc();
+ let mut settings = Settings::now();
// Configure tab to return-query
settings.keymap.emacs = HashMap::from([(
"tab".to_string(),
diff --git a/crates/turtle/src/command/client/stats.rs b/crates/turtle/src/command/client/stats.rs
index 17432bb2..9ea5e283 100644
--- a/crates/turtle/src/command/client/stats.rs
+++ b/crates/turtle/src/command/client/stats.rs
@@ -4,7 +4,7 @@ use interim::parse_date_string;
use time::{Duration, OffsetDateTime, Time};
use crate::atuin_client::database::ClientSqlite;
-use crate::atuin_client::{database::current_context, settings::Settings, theme::Theme};
+use crate::atuin_client::{database::current_context, settings::Settings};
use crate::atuin_history::stats::{compute, pretty_print};
@@ -36,12 +36,7 @@ pub(crate) struct Cmd {
}
impl Cmd {
- pub(crate) async fn run(
- &self,
- db: &ClientSqlite,
- settings: &Settings,
- theme: &Theme,
- ) -> Result<()> {
+ pub(crate) async fn run(&self, db: &ClientSqlite, settings: &Settings) -> Result<()> {
let context = current_context().await?;
let words = if self.period.is_empty() {
String::from("all")
@@ -79,7 +74,7 @@ impl Cmd {
let stats = compute(settings, &history, self.count, self.ngram_size);
if let Some(stats) = stats {
- pretty_print(stats, self.ngram_size, theme);
+ pretty_print(stats, self.ngram_size);
}
Ok(())
diff --git a/crates/turtle/src/command/client/store.rs b/crates/turtle/src/command/client/store.rs
index 347c4bee..bc57488d 100644
--- a/crates/turtle/src/command/client/store.rs
+++ b/crates/turtle/src/command/client/store.rs
@@ -2,18 +2,14 @@ use clap::Subcommand;
use eyre::Result;
use crate::atuin_client::{
- database::ClientSqlite, record::{sqlite_store::SqliteStore, store::Store}, settings::Settings
+ database::ClientSqlite, record::sqlite_store::SqliteStore, settings::Settings,
};
use itertools::Itertools;
use time::{OffsetDateTime, UtcOffset};
-#[cfg(feature = "sync")]
-mod push;
-
-#[cfg(feature = "sync")]
mod pull;
-
mod purge;
+mod push;
mod rebuild;
mod rekey;
mod verify;
@@ -37,11 +33,9 @@ pub(crate) enum Cmd {
Verify(verify::Verify),
/// Push all records to the remote sync server (one way sync)
- #[cfg(feature = "sync")]
Push(push::Push),
/// Pull records from the remote sync server (one way sync)
- #[cfg(feature = "sync")]
Pull(pull::Pull),
}
@@ -58,11 +52,7 @@ impl Cmd {
Self::Rekey(rekey) => rekey.run(settings, store).await,
Self::Verify(verify) => verify.run(settings, store).await,
Self::Purge(purge) => purge.run(settings, store).await,
-
- #[cfg(feature = "sync")]
Self::Push(push) => push.run(settings, store).await,
-
- #[cfg(feature = "sync")]
Self::Pull(pull) => pull.run(settings, store, database).await,
}
}
diff --git a/crates/turtle/src/command/client/store/pull.rs b/crates/turtle/src/command/client/store/pull.rs
index f2e628d6..3a0865be 100644
--- a/crates/turtle/src/command/client/store/pull.rs
+++ b/crates/turtle/src/command/client/store/pull.rs
@@ -2,7 +2,13 @@ use clap::Args;
use eyre::Result;
use crate::atuin_client::{
- database::ClientSqlite, encryption::load_key, record::{sqlite_store::SqliteStore, store::Store, sync::{self, Operation}}, settings::Settings
+ database::ClientSqlite,
+ encryption::load_key,
+ record::{
+ sqlite_store::SqliteStore,
+ sync::{self, Operation},
+ },
+ settings::Settings,
};
#[derive(Args, Debug)]
@@ -42,7 +48,7 @@ impl Pull {
// 3. Filter operations by
// a) are they a download op?
// b) are they for the host/tag we are pushing here?
- let client = sync::build_client(settings).await?;
+ let client = sync::build_client(settings)?;
let (diff, remote_index) = sync::diff(&client, &store).await?;
// Skip on --force: local was already wiped above, mismatch is the user's call.
@@ -53,7 +59,7 @@ impl Pull {
.map_err(crate::print_error::format_sync_error)?;
}
- let operations = sync::operations(diff, &store).await?;
+ let operations = sync::operations(diff, &store)?;
let operations = operations
.into_iter()
diff --git a/crates/turtle/src/command/client/store/purge.rs b/crates/turtle/src/command/client/store/purge.rs
index 3ed55787..a23f1886 100644
--- a/crates/turtle/src/command/client/store/purge.rs
+++ b/crates/turtle/src/command/client/store/purge.rs
@@ -2,9 +2,7 @@ use clap::Args;
use eyre::Result;
use crate::atuin_client::{
- encryption::load_key,
- record::{sqlite_store::SqliteStore, store::Store},
- settings::Settings,
+ encryption::load_key, record::sqlite_store::SqliteStore, settings::Settings,
};
#[derive(Args, Debug)]
diff --git a/crates/turtle/src/command/client/store/push.rs b/crates/turtle/src/command/client/store/push.rs
index beec613c..9d66b5b2 100644
--- a/crates/turtle/src/command/client/store/push.rs
+++ b/crates/turtle/src/command/client/store/push.rs
@@ -60,7 +60,7 @@ impl Push {
// 3. Filter operations by
// a) are they an upload op?
// b) are they for the host/tag we are pushing here?
- let client = sync::build_client(settings).await?;
+ let client = sync::build_client(settings)?;
let (diff, remote_index) = sync::diff(&client, &store).await?;
// Skip on --force: that path intentionally replaces remote with local.
@@ -71,7 +71,7 @@ impl Push {
.map_err(crate::print_error::format_sync_error)?;
}
- let operations = sync::operations(diff, &store).await?;
+ let operations = sync::operations(diff, &store)?;
let operations = operations
.into_iter()
diff --git a/crates/turtle/src/command/client/store/rebuild.rs b/crates/turtle/src/command/client/store/rebuild.rs
index bee1aa05..6be67cd0 100644
--- a/crates/turtle/src/command/client/store/rebuild.rs
+++ b/crates/turtle/src/command/client/store/rebuild.rs
@@ -1,7 +1,6 @@
use clap::Args;
use eyre::{Result, bail};
-#[cfg(feature = "daemon")]
use crate::command::client::daemon as daemon_cmd;
use crate::atuin_client::{
@@ -50,7 +49,6 @@ impl Rebuild {
history_store.build(database).await?;
- #[cfg(feature = "daemon")]
daemon_cmd::emit_event(settings, crate::atuin_daemon::DaemonEvent::HistoryRebuilt).await;
Ok(())
diff --git a/crates/turtle/src/command/client/store/rekey.rs b/crates/turtle/src/command/client/store/rekey.rs
index b99fb16a..e89d83c2 100644
--- a/crates/turtle/src/command/client/store/rekey.rs
+++ b/crates/turtle/src/command/client/store/rekey.rs
@@ -5,7 +5,6 @@ use tokio::{fs::File, io::AsyncWriteExt};
use crate::atuin_client::{
encryption::{decode_key, generate_encoded_key, load_key},
record::sqlite_store::SqliteStore,
- record::store::Store,
settings::Settings,
};
diff --git a/crates/turtle/src/command/client/store/verify.rs b/crates/turtle/src/command/client/store/verify.rs
index e91addcf..a39227f9 100644
--- a/crates/turtle/src/command/client/store/verify.rs
+++ b/crates/turtle/src/command/client/store/verify.rs
@@ -2,9 +2,7 @@ use clap::Args;
use eyre::Result;
use crate::atuin_client::{
- encryption::load_key,
- record::{sqlite_store::SqliteStore, store::Store},
- settings::Settings,
+ encryption::load_key, record::sqlite_store::SqliteStore, settings::Settings,
};
#[derive(Args, Debug)]
diff --git a/crates/turtle/src/command/client/sync.rs b/crates/turtle/src/command/client/sync.rs
index 84b74cc1..c29a82fc 100644
--- a/crates/turtle/src/command/client/sync.rs
+++ b/crates/turtle/src/command/client/sync.rs
@@ -4,7 +4,11 @@ use serde_json::json;
use crate::{
atuin_client::{
- database::ClientSqlite, encryption, history::store::HistoryStore, record::{sqlite_store::SqliteStore, store::Store, sync}, settings::Settings
+ database::ClientSqlite,
+ encryption,
+ history::store::HistoryStore,
+ record::{sqlite_store::SqliteStore, sync},
+ settings::Settings,
},
atuin_common::utils,
};
diff --git a/crates/turtle/src/command/client/wrapped.rs b/crates/turtle/src/command/client/wrapped.rs
index d502d3ec..2ce19bf7 100644
--- a/crates/turtle/src/command/client/wrapped.rs
+++ b/crates/turtle/src/command/client/wrapped.rs
@@ -4,7 +4,7 @@ use std::collections::{HashMap, HashSet};
use time::{Date, Duration, Month, OffsetDateTime, Time};
use crate::atuin_client::database::ClientSqlite;
-use crate::atuin_client::{settings::Settings, theme::Theme};
+use crate::atuin_client::settings::Settings;
use crate::atuin_history::stats::{Stats, compute};
@@ -31,7 +31,12 @@ impl WrappedStats {
.iter()
.filter(|(cmd, _)| {
let cmd = &cmd[0];
- cmd == "cd" || cmd == "ls" || cmd == "pwd" || cmd == "pushd" || cmd == "popd"
+ cmd == "cd"
+ || cmd == "ls"
+ || cmd == "ll"
+ || cmd == "pwd"
+ || cmd == "pushd"
+ || cmd == "popd"
})
.map(|(_, count)| count)
.sum();
@@ -267,12 +272,7 @@ fn print_fun_facts(wrapped_stats: &WrappedStats, stats: &Stats, year: i32) {
println!();
}
-pub(crate) async fn run(
- year: Option<i32>,
- db: &ClientSqlite,
- settings: &Settings,
- theme: &Theme,
-) -> Result<()> {
+pub(crate) async fn run(year: Option<i32>, db: &ClientSqlite, settings: &Settings) -> Result<()> {
let now = OffsetDateTime::now_utc().to_offset(settings.timezone.0);
let month = now.month();
@@ -318,7 +318,7 @@ pub(crate) async fn run(
);
println!("Your Top Commands:");
- crate::atuin_history::stats::pretty_print(stats.clone(), 1, theme);
+ crate::atuin_history::stats::pretty_print(stats.clone(), 1);
println!();
print_fun_facts(&wrapped_stats, &stats, year);