github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/edit/lastcmd/lastcmd.go (about) 1 package lastcmd 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 8 "github.com/u-root/u-root/cmds/core/elvish/edit/eddefs" 9 "github.com/u-root/u-root/cmds/core/elvish/edit/ui" 10 "github.com/u-root/u-root/cmds/core/elvish/eval" 11 "github.com/u-root/u-root/cmds/core/elvish/eval/vars" 12 "github.com/u-root/u-root/cmds/core/elvish/parse/parseutil" 13 ) 14 15 type state struct { 16 line string 17 words []string 18 filtered []entry 19 minus bool 20 } 21 22 type entry struct { 23 i int 24 s string 25 } 26 27 // Init initializes the lastcmd module for an Editor. 28 func Init(ed eddefs.Editor, ns eval.Ns) { 29 lc := &state{} 30 binding := eddefs.EmptyBindingMap 31 32 subns := eval.Ns{ 33 "binding": vars.FromPtr(&binding), 34 } 35 subns.AddBuiltinFns("edit:lastcmd:", map[string]interface{}{ 36 "start": func() { lc.start(ed, binding) }, 37 "accept-line": func() { lc.acceptLine(ed) }, 38 }) 39 ns.AddNs("lastcmd", subns) 40 } 41 42 func newState(line string) *state { 43 return &state{line, parseutil.Wordify(line), nil, false} 44 } 45 46 func (*state) AutoAccept() bool { 47 return true 48 } 49 50 func (*state) ModeTitle(int) string { 51 return " LASTCMD " 52 } 53 54 func (s *state) Len() int { 55 return len(s.filtered) 56 } 57 58 func (s *state) Show(i int) (string, ui.Styled) { 59 entry := s.filtered[i] 60 var head string 61 if entry.i == -1 { 62 head = "M-1" 63 } else if s.minus { 64 head = fmt.Sprintf("%d", entry.i-len(s.words)) 65 } else { 66 head = fmt.Sprintf("%d", entry.i) 67 } 68 return head, ui.Unstyled(entry.s) 69 } 70 71 func (s *state) Filter(filter string) int { 72 s.filtered = nil 73 s.minus = len(filter) > 0 && filter[0] == '-' 74 if filter == "" || filter == "-" { 75 s.filtered = append(s.filtered, entry{-1, s.line}) 76 } else if _, err := strconv.Atoi(filter); err != nil { 77 return -1 78 } 79 // Quite inefficient way to filter by prefix of stringified index. 80 n := len(s.words) 81 for i, word := range s.words { 82 if filter == "" || 83 (!s.minus && strings.HasPrefix(strconv.Itoa(i), filter)) || 84 (s.minus && strings.HasPrefix(strconv.Itoa(i-n), filter)) { 85 s.filtered = append(s.filtered, entry{i, word}) 86 } 87 } 88 if len(s.filtered) == 0 { 89 return -1 90 } 91 return 0 92 } 93 94 func (s *state) Accept(i int, ed eddefs.Editor) { 95 ed.InsertAtDot(s.filtered[i].s) 96 ed.SetModeInsert() 97 } 98 99 func (s *state) start(ed eddefs.Editor, binding eddefs.BindingMap) { 100 ed.Notify("store offline, cannot start lastcmd mode") 101 } 102 103 func (s *state) acceptLine(ed eddefs.Editor) { 104 ed.InsertAtDot(s.line) 105 ed.SetModeInsert() 106 }