Repository: atuinsh/atuin (language: rust)

Issue:
Make format for history configurable
I often forget which directory I ran a command from, and when I then find `./start.sh` in my history I'm only halfway there.

With the help of #619 I can find the directory, but I'd like this config:

`history_format` -- default format for `atuin history list`


Discussion / hints:
I'm a little discombobulated here by the PR noted above. It does seem like we should be able to use `YYYY-MM-DD HH:MM:SS` in the history list, but presently it simply gives relative time ago. I'd like to not only format it such that we have columns in a different order, but to have that particular specific timestamp for each command as well as the first column. I might even like to have the second column actually be relative time, but the timestamp most certainly must be present...
I'm not sure what this issue is asking for, and why `--format` does not achieve what is required. 

Happy to open an issue for implementing this if it's definitely required, but we should be able to achieve this with an alias

```
alias myhistory="atuin history list --format 'blah'"
```

> I might even like to have the second column actually be relative time, but the timestamp most certainly must be present...

This is exactly what the `{time}` part of the format arg does. It prints the timestamp, not the relative time.

For example

```
atuin history list --format "{time} - [{duration}] - {directory}$\t{command}"
```

Hmm, thanks, so what has not been clear is whether or not this tactic of showing the timestamp can be used within the normal history view when you press the up key, etc... 
I agree that an alias would perfectly solve this, this is merely a request to achieve the same without the need to create an alias.

Much in the same way as I have this in `.gitconfig` to modify what `git log` does by default:
```
[format]
        pretty = format:%C(yellow)%h %C(cyan)%>(12)%ad %Cgreen%<(7)%aN%Cred%d %Creset%s
```
@ylluminate could you open a separate issue please? This issue is not about the TUI format, it's about the CLI history list.

>  this is merely a request to achieve the same without the need to create an alias.

Makes sense. I'd just like to make sure we aren't adding config for things that aren't trivially solvable in other ways. 

I'd very happily review + merge a PR for this, but am unlikely to prioritise the work myself 

Fix patch:
diff --git a/atuin-client/config.toml b/atuin-client/config.toml
index d18d9783ef2..9a094f8811b 100644
--- a/atuin-client/config.toml
+++ b/atuin-client/config.toml
@@ -84,6 +84,9 @@
 ## alt-0 .. alt-9
 # ctrl_n_shortcuts = false
 
+## default history list format - can also be specified with the --format arg
+# history_format = "{time}\t{command}\t{duration}"
+
 ## prevent commands matching any of these regexes from being written to history.
 ## Note that these regular expressions are unanchored, i.e. if they don't start
 ## with ^ or end with $, they'll match anywhere in the command.
diff --git a/atuin-client/src/settings.rs b/atuin-client/src/settings.rs
index 122b8d57880..de6b10a42c0 100644
--- a/atuin-client/src/settings.rs
+++ b/atuin-client/src/settings.rs
@@ -277,6 +277,7 @@ pub struct Settings {
     pub word_jump_mode: WordJumpMode,
     pub word_chars: String,
     pub scroll_context_lines: usize,
+    pub history_format: String,
 
     #[serde(with = "serde_regex", default = "RegexSet::empty")]
     pub history_filter: RegexSet,
@@ -480,6 +481,7 @@ impl Settings {
         let session_path = data_dir.join("session");
 
         Ok(Config::builder()
+            .set_default("history_format", "{time}\t{command}\t{duration}")?
             .set_default("db_path", db_path.to_str())?
             .set_default("record_store_path", record_store_path.to_str())?
             .set_default("key_path", key_path.to_str())?
diff --git a/atuin/src/command/client/history.rs b/atuin/src/command/client/history.rs
index b91fc57abca..e983cc7b79b 100644
--- a/atuin/src/command/client/history.rs
+++ b/atuin/src/command/client/history.rs
@@ -366,7 +366,16 @@ impl Cmd {
             .list(&filters, &context, None, false, include_deleted)
             .await?;
 
-        print_list(&history, mode, format.as_deref(), print0, reverse);
+        print_list(
+            &history,
+            mode,
+            match format {
+                None => Some(settings.history_format.as_str()),
+                _ => format.as_deref(),
+            },
+            print0,
+            reverse,
+        );
 
         Ok(())
     }
@@ -449,7 +458,10 @@ impl Cmd {
                 print_list(
                     last,
                     ListMode::from_flags(human, cmd_only),
-                    format.as_deref(),
+                    match format {
+                        None => Some(settings.history_format.as_str()),
+                        _ => format.as_deref(),
+                    },
                     false,
                     true,
                 );
diff --git a/atuin/src/command/client/search.rs b/atuin/src/command/client/search.rs
index 6a70ed624b3..f724ef7fee3 100644
--- a/atuin/src/command/client/search.rs
+++ b/atuin/src/command/client/search.rs
@@ -176,8 +176,6 @@ impl Cmd {
                 eprintln!("{item}");
             }
         } else {
-            let list_mode = ListMode::from_flags(self.human, self.cmd_only);
-
             let opt_filter = OptFilters {
                 exit: self.exit,
                 exclude_exit: self.exclude_exit,
@@ -218,10 +216,14 @@ impl Cmd {
                         run_non_interactive(settings, opt_filter.clone(), &self.query, &db).await?;
                 }
             } else {
+                let format = match self.format {
+                    None => Some(settings.history_format.as_str()),
+                    _ => self.format.as_deref(),
+                };
                 super::history::print_list(
                     &entries,
-                    list_mode,
-                    self.format.as_deref(),
+                    ListMode::from_flags(self.human, self.cmd_only),
+                    format,
                     false,
                     true,
                 );


Test patch: