diff --git a/atuin-client/src/database.rs b/atuin-client/src/database.rs index 1a3dea1..c75a32c 100644 --- a/atuin-client/src/database.rs +++ b/atuin-client/src/database.rs @@ -80,16 +80,17 @@ pub trait Database: Send + Sync + 'static { context: &Context, max: Option, unique: bool, + include_deleted: bool, ) -> Result>; async fn range(&self, from: OffsetDateTime, to: OffsetDateTime) -> Result>; async fn update(&self, h: &History) -> Result<()>; - async fn history_count(&self) -> Result; + async fn history_count(&self, include_deleted: bool) -> Result; async fn last(&self) -> Result>; async fn before(&self, timestamp: OffsetDateTime, count: i64) -> Result>; - async fn delete(&self, mut h: History) -> Result<()>; + async fn delete(&self, h: History) -> Result<()>; async fn deleted(&self) -> Result>; // Yes I know, it's a lot. @@ -257,11 +258,15 @@ impl Database for Sqlite { context: &Context, max: Option, unique: bool, + include_deleted: bool, ) -> Result> { debug!("listing history"); let mut query = SqlBuilder::select_from(SqlName::new("history").alias("h").baquoted()); query.field("*").order_desc("timestamp"); + if !include_deleted { + query.and_where_is_null("deleted_at"); + } match filter { FilterMode::Global => &mut query, @@ -340,11 +345,13 @@ impl Database for Sqlite { Ok(res) } - async fn history_count(&self) -> Result { - let res: (i64,) = sqlx::query_as("select count(1) from history") - .fetch_one(&self.pool) - .await?; - + async fn history_count(&self, include_deleted: bool) -> Result { + let exclude_deleted: &str = if include_deleted { "" } else { "not" }; + let query = format!( + "select count(1) from history where deleted_at is {} null", + exclude_deleted + ); + let res: (i64,) = sqlx::query_as(&query).fetch_one(&self.pool).await?; Ok(res.0) } diff --git a/atuin-client/src/sync.rs b/atuin-client/src/sync.rs index ebfb47c..c2fc75f 100644 --- a/atuin-client/src/sync.rs +++ b/atuin-client/src/sync.rs @@ -48,7 +48,7 @@ async fn sync_download( let remote_deleted = HashSet::<&str>::from_iter(remote_status.deleted.iter().map(String::as_str)); - let initial_local = db.history_count().await?; + let initial_local = db.history_count(true).await?; let mut local_count = initial_local; let mut last_sync = if force { @@ -84,7 +84,7 @@ async fn sync_download( db.save_bulk(&history).await?; - local_count = db.history_count().await?; + local_count = db.history_count(true).await?; if history.len() < remote_status.page_size.try_into().unwrap() { break; @@ -137,7 +137,7 @@ async fn sync_upload( let initial_remote_count = client.count().await?; let mut remote_count = initial_remote_count; - let local_count = db.history_count().await?; + let local_count = db.history_count(true).await?; debug!("remote has {}, we have {}", remote_count, local_count); diff --git a/atuin/src/command/client/history.rs b/atuin/src/command/client/history.rs index b81d227..c9e0dd0 100644 --- a/atuin/src/command/client/history.rs +++ b/atuin/src/command/client/history.rs @@ -320,6 +320,7 @@ impl Cmd { cwd: bool, mode: ListMode, format: Option, + include_deleted: bool, print0: bool, reverse: bool, ) -> Result<()> { @@ -335,7 +336,10 @@ impl Cmd { }; let history = match (session, cwd) { - (None, None) => db.list(settings.filter_mode, &context, None, false).await?, + (None, None) => { + db.list(settings.filter_mode, &context, None, false, include_deleted) + .await? + } (None, Some(cwd)) => { let query = format!("select * from history where cwd = '{cwd}';"); db.query_history(&query).await? @@ -375,7 +379,7 @@ impl Cmd { let mode = ListMode::from_flags(human, cmd_only); let reverse = reverse; Self::handle_list( - db, settings, context, session, cwd, mode, format, print0, reverse, + db, settings, context, session, cwd, mode, format, false, print0, reverse, ) .await } diff --git a/atuin/src/command/client/search/engines.rs b/atuin/src/command/client/search/engines.rs index 878b143..ad84b6d 100644 --- a/atuin/src/command/client/search/engines.rs +++ b/atuin/src/command/client/search/engines.rs @@ -35,7 +35,7 @@ pub trait SearchEngine: Send + Sync + 'static { async fn query(&mut self, state: &SearchState, db: &mut dyn Database) -> Result> { if state.input.as_str().is_empty() { Ok(db - .list(state.filter_mode, &state.context, Some(200), true) + .list(state.filter_mode, &state.context, Some(200), true, false) .await? .into_iter() .collect::>()) diff --git a/atuin/src/command/client/search/interactive.rs b/atuin/src/command/client/search/interactive.rs index 5a2860a..bc93302 100644 --- a/atuin/src/command/client/search/interactive.rs +++ b/atuin/src/command/client/search/interactive.rs @@ -617,7 +617,7 @@ pub async fn history( let context = current_context(); - let history_count = db.history_count().await?; + let history_count = db.history_count(false).await?; let search_mode = if settings.shell_up_key_binding { settings .search_mode_shell_up_key_binding diff --git a/atuin/src/command/client/stats.rs b/atuin/src/command/client/stats.rs index 1293939..0814502 100644 --- a/atuin/src/command/client/stats.rs +++ b/atuin/src/command/client/stats.rs @@ -82,7 +82,8 @@ impl Cmd { }; let history = if words.as_str() == "all" { - db.list(FilterMode::Global, &context, None, false).await? + db.list(FilterMode::Global, &context, None, false, false) + .await? } else if words.trim() == "today" { let start = OffsetDateTime::now_local()?.replace_time(Time::MIDNIGHT); let end = start + Duration::days(1); diff --git a/atuin/src/command/client/sync.rs b/atuin/src/command/client/sync.rs index db7d8b7..d8c0a58 100644 --- a/atuin/src/command/client/sync.rs +++ b/atuin/src/command/client/sync.rs @@ -88,7 +88,7 @@ async fn run( println!( "Sync complete! {} items in history database, force: {}", - db.history_count().await?, + db.history_count(true).await?, force ); diff --git a/atuin/src/command/client/sync/status.rs b/atuin/src/command/client/sync/status.rs index 7ff9955..a4d6bbd 100644 --- a/atuin/src/command/client/sync/status.rs +++ b/atuin/src/command/client/sync/status.rs @@ -13,7 +13,7 @@ pub async fn run(settings: &Settings, db: &impl Database) -> Result<()> { let status = client.status().await?; let last_sync = Settings::last_sync()?; - let local_count = db.history_count().await?; + let local_count = db.history_count(false).await?; println!("Atuin v{VERSION} - Build rev {SHA}\n"); diff --git a/docs/docs/commands/list.md b/docs/docs/commands/list.md index 4d4f2a9..cd41f69 100644 --- a/docs/docs/commands/list.md +++ b/docs/docs/commands/list.md @@ -6,13 +6,15 @@ title: Listing History | Arg | Description | -| ---------------- | ----------------------------------------------------------------------------- | +|------------------|-------------------------------------------------------------------------------| | `--cwd`/`-c` | The directory to list history for (default: all dirs) | | `--session`/`-s` | Enable listing history for the current session only (default: false) | | `--human` | Use human-readable formatting for the timestamp and duration (default: false) | | `--cmd-only` | Show only the text of the command (default: false) | | `--reverse` | Reverse the order of the output (default: false) | | `--format` | Specify the formatting of a command (see below) | +| `--print0` | Terminate the output with a null, for better multiline support | + ## Format