diff --git a/history.go b/history.go index 028643d..46040de 100644 --- a/history.go +++ b/history.go @@ -2,8 +2,10 @@ package main import ( "database/sql" + "hs9001/liner" "io" "log" + "path/filepath" "strings" ) @@ -11,14 +13,32 @@ type history struct { conn *sql.DB } -func (h *history) GetHistoryByPrefix(prefix string) (ph []string) { +func createSearchOpts(query string, mode int) searchopts { opts := searchopts{} o := "DESC" opts.order = &o lim := 100 opts.limit = &lim - cmdqry := prefix + "%" - opts.command = &cmdqry + opts.command = &query + + switch mode { + case liner.ModeGlobal: + break + case liner.ModeWorkdir: + workdir, err := filepath.Abs(".") + if err != nil { + panic(err) + } + opts.workdir = &workdir + default: + panic("Invalid mode supplied") + } + return opts +} + +func (h *history) GetHistoryByPrefix(prefix string, mode int) (ph []string) { + cmdquery := prefix + "%" + opts := createSearchOpts(cmdquery, mode) results := search(h.conn, opts) for e := results.Back(); e != nil; e = e.Prev() { entry, ok := e.Value.(*HistoryEntry) @@ -29,14 +49,11 @@ func (h *history) GetHistoryByPrefix(prefix string) (ph []string) { } return } -func (h *history) GetHistoryByPattern(pattern string) (ph []string, pos []int) { - opts := searchopts{} - o := "DESC" - opts.order = &o - lim := 100 - opts.limit = &lim - cmdqry := "%" + pattern + "%" - opts.command = &cmdqry + +func (h *history) GetHistoryByPattern(pattern string, mode int) (ph []string, pos []int) { + cmdquery := "%" + pattern + "%" + opts := createSearchOpts(cmdquery, mode) + results := search(h.conn, opts) for e := results.Back(); e != nil; e = e.Prev() { entry, ok := e.Value.(*HistoryEntry) diff --git a/liner/common.go b/liner/common.go index bc8ecda..c4819fa 100644 --- a/liner/common.go +++ b/liner/common.go @@ -37,8 +37,8 @@ type HistoryProvider interface { WriteHistory(w io.Writer) (num int, err error) AppendHistory(item string) ClearHistory() - GetHistoryByPrefix(prefix string) (ph []string) - GetHistoryByPattern(pattern string) (ph []string, pos []int) + GetHistoryByPrefix(prefix string, mode int) (ph []string) + GetHistoryByPattern(pattern string, mode int) (ph []string, pos []int) RLock() RUnlock() } @@ -95,11 +95,11 @@ func (s *State) AppendHistory(item string) { func (s *State) ClearHistory() { s.historyProvider.ClearHistory() } -func (s *State) getHistoryByPrefix(prefix string) (ph []string) { - return s.historyProvider.GetHistoryByPrefix(prefix) +func (s *State) getHistoryByPrefix(prefix string, mode int) (ph []string) { + return s.historyProvider.GetHistoryByPrefix(prefix, mode) } -func (s *State) getHistoryByPattern(pattern string) (ph []string, pos []int) { - return s.historyProvider.GetHistoryByPattern(pattern) +func (s *State) getHistoryByPattern(pattern string, mode int) (ph []string, pos []int) { + return s.historyProvider.GetHistoryByPattern(pattern, mode) } // SetHistoryProvider allows you to set a custom provider diff --git a/liner/line.go b/liner/line.go index 3b40730..0324625 100644 --- a/liner/line.go +++ b/liner/line.go @@ -90,6 +90,11 @@ const ( tabReverse ) +const ( + ModeGlobal = iota + ModeWorkdir +) + func (s *State) refresh(prompt []rune, buf []rune, pos int) error { if s.columns == 0 { return ErrInternal @@ -411,8 +416,26 @@ func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interf // reverse intelligent search, implements a bash-like history search. func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) { - p := "(reverse-i-search)`': " - err := s.refresh([]rune(p), origLine, origPos) + modeSelect := false + currentMode := ModeGlobal + + getPrompt := func(arg string) string { + prompt := "" + switch currentMode { + case ModeWorkdir: + prompt = "(reverse:cwd)`%s': " + case ModeGlobal: + prompt = "(reverse:global)`%s': " + default: + panic("Invalid mode") + } + if modeSelect { + prompt = "(select mode)`%s': " + } + return fmt.Sprintf(prompt, arg) + } + + err := s.refresh([]rune(getPrompt("")), origLine, origPos) if err != nil { return origLine, origPos, rune(esc), err } @@ -426,11 +449,10 @@ func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, inter getLine := func() ([]rune, []rune, int) { search := string(line) - prompt := "(reverse-i-search)`%s': " - return []rune(fmt.Sprintf(prompt, search)), []rune(foundLine), foundPos + return []rune(getPrompt(search)), []rune(foundLine), foundPos } - history, positions := s.getHistoryByPattern(string(line)) + history, positions := s.getHistoryByPattern(string(line), currentMode) historyPos := len(history) - 1 for { @@ -450,6 +472,8 @@ func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, inter } else { s.doBeep() } + case ctrlA: + modeSelect = true case ctrlS: // Search forward if historyPos < len(history)-1 && historyPos >= 0 { historyPos++ @@ -467,7 +491,7 @@ func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, inter pos -= n // For each char deleted, display the last matching line of history - history, positions := s.getHistoryByPattern(string(line)) + history, positions := s.getHistoryByPattern(string(line), currentMode) historyPos = len(history) - 1 if len(history) > 0 { foundLine = history[historyPos] @@ -480,17 +504,28 @@ func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, inter case ctrlG: // Cancel return origLine, origPos, rune(esc), err - case tab, cr, lf, ctrlA, ctrlB, ctrlD, ctrlE, ctrlF, ctrlK, + case tab, cr, lf, ctrlB, ctrlD, ctrlE, ctrlF, ctrlK, ctrlL, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: fallthrough case 0, ctrlC, esc, 28, 29, 30, 31: return []rune(foundLine), foundPos, next, err default: + if modeSelect { + switch v { + case 'g': + currentMode = ModeGlobal + case 'w': + currentMode = ModeWorkdir + } + modeSelect = false + break + } + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) pos++ // For each keystroke typed, display the last matching line of history - history, positions = s.getHistoryByPattern(string(line)) + history, positions = s.getHistoryByPattern(string(line), currentMode) historyPos = len(history) - 1 if len(history) > 0 { foundLine = history[historyPos] @@ -726,7 +761,7 @@ mainLoop: case ctrlP: // up historyAction = true if historyStale { - historyPrefix = s.getHistoryByPrefix(string(line)) + historyPrefix = s.getHistoryByPrefix(string(line), ModeGlobal) historyPos = len(historyPrefix) historyStale = false } @@ -744,7 +779,7 @@ mainLoop: case ctrlN: // down historyAction = true if historyStale { - historyPrefix = s.getHistoryByPrefix(string(line)) + historyPrefix = s.getHistoryByPrefix(string(line), ModeGlobal) historyPos = len(historyPrefix) historyStale = false } @@ -912,7 +947,7 @@ mainLoop: case up: historyAction = true if historyStale { - historyPrefix = s.getHistoryByPrefix(string(line)) + historyPrefix = s.getHistoryByPrefix(string(line), ModeGlobal) historyPos = len(historyPrefix) historyStale = false } @@ -929,7 +964,7 @@ mainLoop: case down: historyAction = true if historyStale { - historyPrefix = s.getHistoryByPrefix(string(line)) + historyPrefix = s.getHistoryByPrefix(string(line), ModeGlobal) historyPos = len(historyPrefix) historyStale = false }