From 00826a5c075020a000948546cb9800489e7b182e Mon Sep 17 00:00:00 2001 From: verse91 Date: Sun, 19 Apr 2026 11:02:52 +0700 Subject: [PATCH] feat(history): add bash and fish --- integration/history.go | 70 +++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/integration/history.go b/integration/history.go index a50ebb6..1797d4a 100644 --- a/integration/history.go +++ b/integration/history.go @@ -8,6 +8,7 @@ import ( "sync" "github.com/versenilvis/fuzzyvn" + "github.com/versenilvis/iris/integration/shell" ) var ( @@ -15,6 +16,7 @@ var ( idMapCache map[string]int searcherCache *fuzzyvn.Searcher mu sync.Mutex + lastModTime int64 ) type HistResult struct { @@ -26,19 +28,40 @@ func init() { idMapCache = make(map[string]int) } -// SearchHistory reads the zsh history and searches using fuzzyvn (my own pkg) func SearchHistory(query string) ([]HistResult, error) { mu.Lock() defer mu.Unlock() + home, err := os.UserHomeDir() + if err != nil { + return nil, err + } + + shellName := "bash" + if shell.Current != nil { + shellName = shell.Current.GetName() + } + + var histFile string + switch shellName { + case "zsh": + histFile = filepath.Join(home, ".zsh_history") + case "fish": + histFile = filepath.Join(home, ".local", "share", "fish", "fish_history") + default: + histFile = filepath.Join(home, ".bash_history") + } + + if info, err := os.Stat(histFile); err == nil { + if info.ModTime().UnixNano() > lastModTime { + historyCache = nil // force reload + idMapCache = make(map[string]int) + lastModTime = info.ModTime().UnixNano() + } + } + // lazy load history if cache is empty if len(historyCache) == 0 { - home, err := os.UserHomeDir() - if err != nil { - return nil, err - } - - histFile := filepath.Join(home, ".zsh_history") file, err := os.Open(histFile) if err != nil { return nil, err @@ -50,11 +73,36 @@ func SearchHistory(query string) ([]HistResult, error) { scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() - // zsh history format: : ; - parts := strings.SplitN(line, ";", 2) cmd := line - if len(parts) == 2 { - cmd = parts[1] + + if shellName == "zsh" { + // zsh history format: : ; + parts := strings.SplitN(line, ";", 2) + if len(parts) == 2 { + cmd = parts[1] + } + } else if shellName == "bash" { + // bash history format can include timestamps starting with # + if strings.HasPrefix(line, "#") && len(line) > 1 { + + isTimestamp := true + for _, c := range line[1:] { + if c < '0' || c > '9' { + isTimestamp = false + break + } + } + if isTimestamp { + continue + } + } + } else if shellName == "fish" { + // simple parse for fish history (YAML-like) + if strings.HasPrefix(line, "- cmd: ") { + cmd = strings.TrimPrefix(line, "- cmd: ") + } else { + continue + } } cmd = strings.TrimSpace(cmd)