mirror of
https://github.com/ddworken/hishtory.git
synced 2025-03-26 23:46:23 +01:00
Add config option to filter out duplicate history entries as requested in #10
This commit is contained in:
parent
83ca625ad9
commit
6dea8a989e
11
README.md
11
README.md
@ -71,7 +71,6 @@ hishtory config-set displayed-columns CWD Command
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Custom Columns</summary>
|
||||
|
||||
@ -81,7 +80,6 @@ You can create custom column definitions that are populated from arbitrary comma
|
||||
hishtory config-add custom-column git_remote '(git remote -v 2>/dev/null | grep origin 1>/dev/null ) && git remote get-url origin || true'
|
||||
hishtory config-add displayed-columns git_remote
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
@ -89,6 +87,15 @@ hishtory config-add displayed-columns git_remote
|
||||
If you'd like to disable the control-R integration in your shell, you can do so by running `hishtory config-set enable-control-r false`.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Filtering duplicate entries</summary>
|
||||
By default, hishtory query will show all results even if this includes duplicate history entries. This helps you keep track of how many times you've run a command and in what contexts. If you'd rather disable this so that hiSHtory won't show duplicate entries, you can run:
|
||||
|
||||
```
|
||||
hishtory config-set filter-duplicate-commands true
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Offline Install</summary>
|
||||
If you don't need the ability to sync your shell history, you can install hiSHtory in offline mode.
|
||||
|
@ -2069,6 +2069,38 @@ echo bar`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveDuplicateRows(t *testing.T) {
|
||||
// Setup
|
||||
tester := bashTester{}
|
||||
defer testutils.BackupAndRestore(t)()
|
||||
installHishtory(t, tester, "")
|
||||
|
||||
// Record a few commands and check that they get recorded and all are displayed in a table
|
||||
tester.RunInteractiveShell(t, `echo foo
|
||||
echo foo
|
||||
echo baz
|
||||
echo baz
|
||||
echo foo`)
|
||||
out := tester.RunInteractiveShell(t, `hishtory export -pipefail`)
|
||||
compareGoldens(t, out, "testRemoveDuplicateRows-export")
|
||||
tester.RunInteractiveShell(t, `hishtory config-set displayed-columns 'Exit Code' Command`)
|
||||
out = tester.RunInteractiveShell(t, `hishtory query -pipefail`)
|
||||
compareGoldens(t, out, "testRemoveDuplicateRows-query")
|
||||
out = captureTerminalOutput(t, tester, []string{"hishtory SPACE tquery SPACE -pipefail ENTER"})
|
||||
out = strings.TrimSpace(strings.Split(out, "hishtory tquery")[1])
|
||||
compareGoldens(t, out, "testRemoveDuplicateRows-tquery")
|
||||
|
||||
// And change the config to filter out duplicate rows
|
||||
tester.RunInteractiveShell(t, `hishtory config-set filter-duplicate-commands true`)
|
||||
out = tester.RunInteractiveShell(t, `hishtory export -pipefail`)
|
||||
compareGoldens(t, out, "testRemoveDuplicateRows-enabled-export")
|
||||
out = tester.RunInteractiveShell(t, `hishtory query -pipefail`)
|
||||
compareGoldens(t, out, "testRemoveDuplicateRows-enabled-query")
|
||||
out = captureTerminalOutput(t, tester, []string{"hishtory SPACE tquery SPACE -pipefail ENTER"})
|
||||
out = strings.TrimSpace(strings.Split(out, "hishtory tquery")[1])
|
||||
compareGoldens(t, out, "testRemoveDuplicateRows-enabled-tquery")
|
||||
}
|
||||
|
||||
type deviceSet struct {
|
||||
deviceMap *map[device]deviceOp
|
||||
currentDevice *device
|
||||
|
@ -163,6 +163,8 @@ type ClientConfig struct {
|
||||
CustomColumns []CustomColumnDefinition `json:"custom_columns"`
|
||||
// Whether this is an offline instance of hishtory with no syncing
|
||||
IsOffline bool `json:"is_offline"`
|
||||
// Whether duplicate commands should be displayed
|
||||
FilterDuplicateCommands bool `json:"filter_duplicate_commands"`
|
||||
}
|
||||
|
||||
type CustomColumnDefinition struct {
|
||||
|
@ -0,0 +1,8 @@
|
||||
echo foo
|
||||
echo foo
|
||||
echo baz
|
||||
echo baz
|
||||
echo foo
|
||||
hishtory config-set displayed-columns 'Exit Code' Command
|
||||
source /Users/david/.bashrc
|
||||
hishtory config-set filter-duplicate-commands true
|
7
client/lib/goldens/testRemoveDuplicateRows-enabled-query
Normal file
7
client/lib/goldens/testRemoveDuplicateRows-enabled-query
Normal file
@ -0,0 +1,7 @@
|
||||
Exit Code Command
|
||||
0 hishtory config-set filter-duplicate-commands true
|
||||
0 source /Users/david/.bashrc
|
||||
0 hishtory config-set displayed-columns 'Exit Code' Command
|
||||
0 echo foo
|
||||
0 echo baz
|
||||
0 echo foo
|
30
client/lib/goldens/testRemoveDuplicateRows-enabled-tquery
Normal file
30
client/lib/goldens/testRemoveDuplicateRows-enabled-tquery
Normal file
@ -0,0 +1,30 @@
|
||||
-pipefail
|
||||
|
||||
|
||||
|
||||
Search Query: > -pipefail
|
||||
|
||||
┌───────────────────────────────────────────────────────────────────────────┐
|
||||
│ Exit Code Command │
|
||||
│───────────────────────────────────────────────────────────────────────────│
|
||||
│ 0 source /Users/david/.bashrc │
|
||||
│ 0 hishtory config-set filter-duplicate-commands true │
|
||||
│ 0 source /Users/david/.bashrc │
|
||||
│ 0 hishtory config-set displayed-columns 'Exit Code' Command │
|
||||
│ 0 echo foo │
|
||||
│ 0 echo baz │
|
||||
│ 0 echo foo │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────┘
|
5
client/lib/goldens/testRemoveDuplicateRows-export
Normal file
5
client/lib/goldens/testRemoveDuplicateRows-export
Normal file
@ -0,0 +1,5 @@
|
||||
echo foo
|
||||
echo foo
|
||||
echo baz
|
||||
echo baz
|
||||
echo foo
|
7
client/lib/goldens/testRemoveDuplicateRows-query
Normal file
7
client/lib/goldens/testRemoveDuplicateRows-query
Normal file
@ -0,0 +1,7 @@
|
||||
Exit Code Command
|
||||
0 hishtory config-set displayed-columns 'Exit Code' Command
|
||||
0 echo foo
|
||||
0 echo baz
|
||||
0 echo baz
|
||||
0 echo foo
|
||||
0 echo foo
|
30
client/lib/goldens/testRemoveDuplicateRows-tquery
Normal file
30
client/lib/goldens/testRemoveDuplicateRows-tquery
Normal file
@ -0,0 +1,30 @@
|
||||
-pipefail
|
||||
|
||||
|
||||
|
||||
Search Query: > -pipefail
|
||||
|
||||
┌───────────────────────────────────────────────────────────────────────────┐
|
||||
│ Exit Code Command │
|
||||
│───────────────────────────────────────────────────────────────────────────│
|
||||
│ 0 source /Users/david/.bashrc │
|
||||
│ 0 hishtory config-set displayed-columns 'Exit Code' Command │
|
||||
│ 0 echo foo │
|
||||
│ 0 echo baz │
|
||||
│ 0 echo baz │
|
||||
│ 0 echo foo │
|
||||
│ 0 echo foo │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────────────────┘
|
@ -461,7 +461,7 @@ func stringArrayToAnyArray(arr []string) []any {
|
||||
return ret
|
||||
}
|
||||
|
||||
func DisplayResults(ctx *context.Context, results []*data.HistoryEntry) error {
|
||||
func DisplayResults(ctx *context.Context, results []*data.HistoryEntry, numResults int) error {
|
||||
config := hctx.GetConf(ctx)
|
||||
headerFmt := color.New(color.FgGreen, color.Underline).SprintfFunc()
|
||||
|
||||
@ -472,12 +472,22 @@ func DisplayResults(ctx *context.Context, results []*data.HistoryEntry) error {
|
||||
tbl := table.New(columns...)
|
||||
tbl.WithHeaderFormatter(headerFmt)
|
||||
|
||||
for _, result := range results {
|
||||
row, err := buildTableRow(ctx, config.DisplayedColumns, *result)
|
||||
lastCommand := ""
|
||||
numRows := 0
|
||||
for _, entry := range results {
|
||||
if entry != nil && entry.Command == lastCommand && config.FilterDuplicateCommands {
|
||||
continue
|
||||
}
|
||||
row, err := buildTableRow(ctx, config.DisplayedColumns, *entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tbl.AddRow(stringArrayToAnyArray(row)...)
|
||||
numRows += 1
|
||||
lastCommand = entry.Command
|
||||
if numRows >= numResults {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
tbl.Print()
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
const TABLE_HEIGHT = 20
|
||||
const PADDED_NUM_ENTRIES = TABLE_HEIGHT * 3
|
||||
const PADDED_NUM_ENTRIES = TABLE_HEIGHT * 5
|
||||
|
||||
var selectedRow string = ""
|
||||
|
||||
@ -212,20 +212,26 @@ func (m model) View() string {
|
||||
|
||||
func getRows(ctx *context.Context, columnNames []string, query string, numEntries int) ([]table.Row, int, error) {
|
||||
db := hctx.GetDb(ctx)
|
||||
config := hctx.GetConf(ctx)
|
||||
data, err := Search(ctx, db, query, numEntries)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
var rows []table.Row
|
||||
lastCommand := ""
|
||||
for i := 0; i < numEntries; i++ {
|
||||
if i < len(data) {
|
||||
entry := data[i]
|
||||
if entry.Command == lastCommand && config.FilterDuplicateCommands {
|
||||
continue
|
||||
}
|
||||
entry.Command = strings.ReplaceAll(entry.Command, "\n", " ") // TODO: handle multi-line commands better here
|
||||
row, err := buildTableRow(ctx, columnNames, *entry)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to build row for entry=%#v: %v", entry, err)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
lastCommand = entry.Command
|
||||
} else {
|
||||
rows = append(rows, table.Row{})
|
||||
}
|
||||
|
14
hishtory.go
14
hishtory.go
@ -135,6 +135,8 @@ func main() {
|
||||
switch key {
|
||||
case "enable-control-r":
|
||||
fmt.Printf("%v", config.ControlRSearchEnabled)
|
||||
case "filter-duplicate-commands":
|
||||
fmt.Printf("%v", config.FilterDuplicateCommands)
|
||||
case "displayed-columns":
|
||||
for _, col := range config.DisplayedColumns {
|
||||
if strings.Contains(col, " ") {
|
||||
@ -162,6 +164,13 @@ func main() {
|
||||
}
|
||||
config.ControlRSearchEnabled = (val == "true")
|
||||
lib.CheckFatalError(hctx.SetConfig(config))
|
||||
case "filter-duplicate-commands":
|
||||
val := os.Args[3]
|
||||
if val != "true" && val != "false" {
|
||||
log.Fatalf("Unexpected config value %s, must be one of: true, false", val)
|
||||
}
|
||||
config.FilterDuplicateCommands = (val == "true")
|
||||
lib.CheckFatalError(hctx.SetConfig(config))
|
||||
case "displayed-columns":
|
||||
vals := os.Args[3:]
|
||||
config.DisplayedColumns = vals
|
||||
@ -313,9 +322,10 @@ func query(ctx *context.Context, query string) {
|
||||
}
|
||||
}
|
||||
lib.CheckFatalError(displayBannerIfSet(ctx))
|
||||
data, err := lib.Search(ctx, db, query, 25)
|
||||
numResults := 25
|
||||
data, err := lib.Search(ctx, db, query, numResults*5)
|
||||
lib.CheckFatalError(err)
|
||||
lib.CheckFatalError(lib.DisplayResults(ctx, data))
|
||||
lib.CheckFatalError(lib.DisplayResults(ctx, data, numResults))
|
||||
}
|
||||
|
||||
func displayBannerIfSet(ctx *context.Context) error {
|
||||
|
Loading…
Reference in New Issue
Block a user