Jämför commits

...

2 Incheckningar

Upphovsman SHA1 Meddelande Datum
Albert S. ebcdfa5ff4 Print failed commands in red.
Optimized for dark terminals :-).

Closes: #8
2021-09-25 12:14:07 +02:00
Albert S. 0949ee422a Implement mode for reverse search in cwd
Add a mode selection mode to liner.

Add modes to search globally or in the cwd.
2021-09-25 11:52:39 +02:00
4 ändrade filer med 100 tillägg och 30 borttagningar

Visa fil

@ -2,8 +2,10 @@ package main
import ( import (
"database/sql" "database/sql"
"hs9001/liner"
"io" "io"
"log" "log"
"path/filepath"
"strings" "strings"
) )
@ -11,14 +13,32 @@ type history struct {
conn *sql.DB conn *sql.DB
} }
func (h *history) GetHistoryByPrefix(prefix string) (ph []string) { func createSearchOpts(query string, mode int) searchopts {
opts := searchopts{} opts := searchopts{}
o := "DESC" o := "DESC"
opts.order = &o opts.order = &o
lim := 100 lim := 100
opts.limit = &lim opts.limit = &lim
cmdqry := prefix + "%" opts.command = &query
opts.command = &cmdqry
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) results := search(h.conn, opts)
for e := results.Back(); e != nil; e = e.Prev() { for e := results.Back(); e != nil; e = e.Prev() {
entry, ok := e.Value.(*HistoryEntry) entry, ok := e.Value.(*HistoryEntry)
@ -29,14 +49,11 @@ func (h *history) GetHistoryByPrefix(prefix string) (ph []string) {
} }
return return
} }
func (h *history) GetHistoryByPattern(pattern string) (ph []string, pos []int) {
opts := searchopts{} func (h *history) GetHistoryByPattern(pattern string, mode int) (ph []string, pos []int) {
o := "DESC" cmdquery := "%" + pattern + "%"
opts.order = &o opts := createSearchOpts(cmdquery, mode)
lim := 100
opts.limit = &lim
cmdqry := "%" + pattern + "%"
opts.command = &cmdqry
results := search(h.conn, opts) results := search(h.conn, opts)
for e := results.Back(); e != nil; e = e.Prev() { for e := results.Back(); e != nil; e = e.Prev() {
entry, ok := e.Value.(*HistoryEntry) entry, ok := e.Value.(*HistoryEntry)

Visa fil

@ -37,8 +37,8 @@ type HistoryProvider interface {
WriteHistory(w io.Writer) (num int, err error) WriteHistory(w io.Writer) (num int, err error)
AppendHistory(item string) AppendHistory(item string)
ClearHistory() ClearHistory()
GetHistoryByPrefix(prefix string) (ph []string) GetHistoryByPrefix(prefix string, mode int) (ph []string)
GetHistoryByPattern(pattern string) (ph []string, pos []int) GetHistoryByPattern(pattern string, mode int) (ph []string, pos []int)
RLock() RLock()
RUnlock() RUnlock()
} }
@ -95,11 +95,11 @@ func (s *State) AppendHistory(item string) {
func (s *State) ClearHistory() { func (s *State) ClearHistory() {
s.historyProvider.ClearHistory() s.historyProvider.ClearHistory()
} }
func (s *State) getHistoryByPrefix(prefix string) (ph []string) { func (s *State) getHistoryByPrefix(prefix string, mode int) (ph []string) {
return s.historyProvider.GetHistoryByPrefix(prefix) return s.historyProvider.GetHistoryByPrefix(prefix, mode)
} }
func (s *State) getHistoryByPattern(pattern string) (ph []string, pos []int) { func (s *State) getHistoryByPattern(pattern string, mode int) (ph []string, pos []int) {
return s.historyProvider.GetHistoryByPattern(pattern) return s.historyProvider.GetHistoryByPattern(pattern, mode)
} }
// SetHistoryProvider allows you to set a custom provider // SetHistoryProvider allows you to set a custom provider

Visa fil

@ -90,6 +90,11 @@ const (
tabReverse tabReverse
) )
const (
ModeGlobal = iota
ModeWorkdir
)
func (s *State) refresh(prompt []rune, buf []rune, pos int) error { func (s *State) refresh(prompt []rune, buf []rune, pos int) error {
if s.columns == 0 { if s.columns == 0 {
return ErrInternal 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. // reverse intelligent search, implements a bash-like history search.
func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) { func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) {
p := "(reverse-i-search)`': " modeSelect := false
err := s.refresh([]rune(p), origLine, origPos) 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 { if err != nil {
return origLine, origPos, rune(esc), err 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) { getLine := func() ([]rune, []rune, int) {
search := string(line) search := string(line)
prompt := "(reverse-i-search)`%s': " return []rune(getPrompt(search)), []rune(foundLine), foundPos
return []rune(fmt.Sprintf(prompt, search)), []rune(foundLine), foundPos
} }
history, positions := s.getHistoryByPattern(string(line)) history, positions := s.getHistoryByPattern(string(line), currentMode)
historyPos := len(history) - 1 historyPos := len(history) - 1
for { for {
@ -450,6 +472,8 @@ func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, inter
} else { } else {
s.doBeep() s.doBeep()
} }
case ctrlA:
modeSelect = true
case ctrlS: // Search forward case ctrlS: // Search forward
if historyPos < len(history)-1 && historyPos >= 0 { if historyPos < len(history)-1 && historyPos >= 0 {
historyPos++ historyPos++
@ -467,7 +491,7 @@ func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, inter
pos -= n pos -= n
// For each char deleted, display the last matching line of history // 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 historyPos = len(history) - 1
if len(history) > 0 { if len(history) > 0 {
foundLine = history[historyPos] foundLine = history[historyPos]
@ -480,17 +504,28 @@ func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, inter
case ctrlG: // Cancel case ctrlG: // Cancel
return origLine, origPos, rune(esc), err 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: ctrlL, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ:
fallthrough fallthrough
case 0, ctrlC, esc, 28, 29, 30, 31: case 0, ctrlC, esc, 28, 29, 30, 31:
return []rune(foundLine), foundPos, next, err return []rune(foundLine), foundPos, next, err
default: 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:]...)...) line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
pos++ pos++
// For each keystroke typed, display the last matching line of history // 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 historyPos = len(history) - 1
if len(history) > 0 { if len(history) > 0 {
foundLine = history[historyPos] foundLine = history[historyPos]
@ -726,7 +761,7 @@ mainLoop:
case ctrlP: // up case ctrlP: // up
historyAction = true historyAction = true
if historyStale { if historyStale {
historyPrefix = s.getHistoryByPrefix(string(line)) historyPrefix = s.getHistoryByPrefix(string(line), ModeGlobal)
historyPos = len(historyPrefix) historyPos = len(historyPrefix)
historyStale = false historyStale = false
} }
@ -744,7 +779,7 @@ mainLoop:
case ctrlN: // down case ctrlN: // down
historyAction = true historyAction = true
if historyStale { if historyStale {
historyPrefix = s.getHistoryByPrefix(string(line)) historyPrefix = s.getHistoryByPrefix(string(line), ModeGlobal)
historyPos = len(historyPrefix) historyPos = len(historyPrefix)
historyStale = false historyStale = false
} }
@ -912,7 +947,7 @@ mainLoop:
case up: case up:
historyAction = true historyAction = true
if historyStale { if historyStale {
historyPrefix = s.getHistoryByPrefix(string(line)) historyPrefix = s.getHistoryByPrefix(string(line), ModeGlobal)
historyPos = len(historyPrefix) historyPos = len(historyPrefix)
historyStale = false historyStale = false
} }
@ -929,7 +964,7 @@ mainLoop:
case down: case down:
historyAction = true historyAction = true
if historyStale { if historyStale {
historyPrefix = s.getHistoryByPrefix(string(line)) historyPrefix = s.getHistoryByPrefix(string(line), ModeGlobal)
historyPos = len(historyPrefix) historyPos = len(historyPrefix)
historyStale = false historyStale = false
} }

20
main.go
Visa fil

@ -398,13 +398,31 @@ func main() {
results := search(conn, opts) results := search(conn, opts)
previousCmd := "" previousCmd := ""
fi, err := os.Stdout.Stat()
if err != nil {
panic(err)
}
//Don't print colors if output is piped
printColors := true
if (fi.Mode() & os.ModeCharDevice) == 0 {
printColors = false
}
for e := results.Front(); e != nil; e = e.Next() { for e := results.Front(); e != nil; e = e.Next() {
entry, ok := e.Value.(*HistoryEntry) entry, ok := e.Value.(*HistoryEntry)
if !ok { if !ok {
log.Panic("Failed to retrieve entries") log.Panic("Failed to retrieve entries")
} }
if !distinct || previousCmd != entry.cmd { if !distinct || previousCmd != entry.cmd {
fmt.Printf("%s\n", entry.cmd) prefix := ""
postfix := ""
if printColors && entry.retval != 0 {
prefix = "\033[38;5;88m"
postfix = "\033[0m"
}
fmt.Printf("%s%s%s\n", prefix, entry.cmd, postfix)
} }
previousCmd = entry.cmd previousCmd = entry.cmd
} }