mirror of
https://github.com/ddworken/hishtory.git
synced 2025-06-26 06:52:23 +02:00
Add custom timestamp format as requested in the original HN thread
This commit is contained in:
parent
6f53fdd41e
commit
e72ef668ea
@ -114,6 +114,11 @@ But if you'd like to self-host the hishtory backend, you can! The backend is a s
|
|||||||
hiSHtory imports your existing shell history by default. If for some reason this didn't work (e.g. you had your shell history in a non-standard file), you can import it by piping it into `hishtory import` (e.g. `cat ~/.my_history | hishtory import`).
|
hiSHtory imports your existing shell history by default. If for some reason this didn't work (e.g. you had your shell history in a non-standard file), you can import it by piping it into `hishtory import` (e.g. `cat ~/.my_history | hishtory import`).
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Custom timestamp formats</summary>
|
||||||
|
You can configure a custom timestamp format for hiSHtory via `hishtory config-set timestamp-format '2006/Jan/2 15:04'`. The timestamp format string should be in [the format used by Go's `time.Format(...)`](https://pkg.go.dev/time#Time.Format).
|
||||||
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Uninstalling</summary>
|
<summary>Uninstalling</summary>
|
||||||
If you'd like to uninstall hishtory, just run `hishtory uninstall`. Note that this deletes the SQLite DB storing your history, so consider running a `hishtory export` first.
|
If you'd like to uninstall hishtory, just run `hishtory uninstall`. Note that this deletes the SQLite DB storing your history, so consider running a `hishtory export` first.
|
||||||
|
@ -2098,6 +2098,39 @@ echo bar`)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTimestampFormat(t *testing.T) {
|
||||||
|
// Setup
|
||||||
|
tester := zshTester{}
|
||||||
|
defer testutils.BackupAndRestore(t)()
|
||||||
|
userSecret := installHishtory(t, tester, "")
|
||||||
|
|
||||||
|
// Add some entries with fixed timestamps
|
||||||
|
tmz, err := time.LoadLocation("America/Los_Angeles")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load timezone: %v", err)
|
||||||
|
}
|
||||||
|
entry1 := testutils.MakeFakeHistoryEntry("table_cmd1")
|
||||||
|
entry1.StartTime = time.Unix(1650096186, 0).In(tmz)
|
||||||
|
entry1.EndTime = time.Unix(1650096190, 0).In(tmz)
|
||||||
|
manuallySubmitHistoryEntry(t, userSecret, entry1)
|
||||||
|
entry2 := testutils.MakeFakeHistoryEntry("table_cmd2")
|
||||||
|
entry2.StartTime = time.Unix(1650096196, 0).In(tmz)
|
||||||
|
entry2.EndTime = time.Unix(1650096220, 0).In(tmz)
|
||||||
|
entry2.CurrentWorkingDirectory = "~/foo/"
|
||||||
|
entry2.ExitCode = 3
|
||||||
|
manuallySubmitHistoryEntry(t, userSecret, entry2)
|
||||||
|
|
||||||
|
// Set a custom timestamp format
|
||||||
|
tester.RunInteractiveShell(t, ` hishtory config-set timestamp-format '2006/Jan/2 15:04'`)
|
||||||
|
|
||||||
|
// And check that it is displayed in both the tui and the classic view
|
||||||
|
out := hishtoryQuery(t, tester, "-pipefail")
|
||||||
|
compareGoldens(t, out, "TestTimestampFormat-query")
|
||||||
|
out = captureTerminalOutput(t, tester, []string{"hishtory SPACE tquery SPACE -pipefail ENTER"})
|
||||||
|
out = strings.TrimSpace(strings.Split(out, "hishtory tquery")[1])
|
||||||
|
compareGoldens(t, out, "TestTimestampFormat-tquery")
|
||||||
|
}
|
||||||
|
|
||||||
func TestRemoveDuplicateRows(t *testing.T) {
|
func TestRemoveDuplicateRows(t *testing.T) {
|
||||||
// Setup
|
// Setup
|
||||||
tester := zshTester{}
|
tester := zshTester{}
|
||||||
|
@ -174,6 +174,8 @@ type ClientConfig struct {
|
|||||||
IsOffline bool `json:"is_offline"`
|
IsOffline bool `json:"is_offline"`
|
||||||
// Whether duplicate commands should be displayed
|
// Whether duplicate commands should be displayed
|
||||||
FilterDuplicateCommands bool `json:"filter_duplicate_commands"`
|
FilterDuplicateCommands bool `json:"filter_duplicate_commands"`
|
||||||
|
// A format string for the timestamp
|
||||||
|
TimestampFormat string `json:"timestamp_format"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomColumnDefinition struct {
|
type CustomColumnDefinition struct {
|
||||||
@ -215,6 +217,9 @@ func GetConfig() (ClientConfig, error) {
|
|||||||
if config.DisplayedColumns == nil || len(config.DisplayedColumns) == 0 {
|
if config.DisplayedColumns == nil || len(config.DisplayedColumns) == 0 {
|
||||||
config.DisplayedColumns = []string{"Hostname", "CWD", "Timestamp", "Runtime", "Exit Code", "Command"}
|
config.DisplayedColumns = []string{"Hostname", "CWD", "Timestamp", "Runtime", "Exit Code", "Command"}
|
||||||
}
|
}
|
||||||
|
if config.TimestampFormat == "" {
|
||||||
|
config.TimestampFormat = "Jan 2 2006 15:04:05 MST"
|
||||||
|
}
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
client/lib/goldens/TestTimestampFormat-query
Normal file
3
client/lib/goldens/TestTimestampFormat-query
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Hostname CWD Timestamp Runtime Exit Code Command
|
||||||
|
localhost ~/foo/ 2022/Apr/16 01:03 24s 3 table_cmd2
|
||||||
|
localhost /tmp/ 2022/Apr/16 01:03 4s 2 table_cmd1
|
30
client/lib/goldens/TestTimestampFormat-tquery
Normal file
30
client/lib/goldens/TestTimestampFormat-tquery
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
-pipefail
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Search Query: > -pipefail
|
||||||
|
|
||||||
|
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Hostname CWD Timestamp Runtime Exit Code Command │
|
||||||
|
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||||
|
│ localhost ~/foo/ 2022/Apr/16 01:03 24s 3 table_cmd2 │
|
||||||
|
│ localhost /tmp/ 2022/Apr/16 01:03 4s 2 table_cmd1 │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
@ -435,7 +435,7 @@ func buildTableRow(ctx *context.Context, columnNames []string, entry data.Histor
|
|||||||
case "CWD":
|
case "CWD":
|
||||||
row = append(row, entry.CurrentWorkingDirectory)
|
row = append(row, entry.CurrentWorkingDirectory)
|
||||||
case "Timestamp":
|
case "Timestamp":
|
||||||
row = append(row, entry.StartTime.Format("Jan 2 2006 15:04:05 MST"))
|
row = append(row, entry.StartTime.Format(hctx.GetConf(ctx).TimestampFormat))
|
||||||
case "Runtime":
|
case "Runtime":
|
||||||
row = append(row, entry.EndTime.Sub(entry.StartTime).Round(time.Millisecond).String())
|
row = append(row, entry.EndTime.Sub(entry.StartTime).Round(time.Millisecond).String())
|
||||||
case "Exit Code":
|
case "Exit Code":
|
||||||
|
@ -184,6 +184,10 @@ func main() {
|
|||||||
vals := os.Args[3:]
|
vals := os.Args[3:]
|
||||||
config.DisplayedColumns = vals
|
config.DisplayedColumns = vals
|
||||||
lib.CheckFatalError(hctx.SetConfig(config))
|
lib.CheckFatalError(hctx.SetConfig(config))
|
||||||
|
case "timestamp-format":
|
||||||
|
val := os.Args[3]
|
||||||
|
config.TimestampFormat = val
|
||||||
|
lib.CheckFatalError(hctx.SetConfig(config))
|
||||||
case "custom-columns":
|
case "custom-columns":
|
||||||
log.Fatalf("Please use config-add and config-delete to interact with custom-columns")
|
log.Fatalf("Please use config-add and config-delete to interact with custom-columns")
|
||||||
default:
|
default:
|
||||||
@ -257,7 +261,6 @@ func main() {
|
|||||||
default:
|
default:
|
||||||
log.Fatalf("Unrecognized config key: %s", key)
|
log.Fatalf("Unrecognized config key: %s", key)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "reupload":
|
case "reupload":
|
||||||
// Purposefully undocumented since this command is generally not necessary to run
|
// Purposefully undocumented since this command is generally not necessary to run
|
||||||
lib.CheckFatalError(lib.Reupload(hctx.MakeContext()))
|
lib.CheckFatalError(lib.Reupload(hctx.MakeContext()))
|
||||||
@ -476,6 +479,3 @@ func export(ctx *context.Context, query string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(feature): Add a session_id column that corresponds to the shell session the command was run in
|
// TODO(feature): Add a session_id column that corresponds to the shell session the command was run in
|
||||||
|
|
||||||
// TODO: add a config option for timestamp formatting
|
|
||||||
// TODO: handle control-c in the TUI
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user