github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/elvish/edit/history/histlist.go (about) 1 package history 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 9 "github.com/u-root/u-root/cmds/elvish/edit/eddefs" 10 "github.com/u-root/u-root/cmds/elvish/edit/ui" 11 ) 12 13 // Command history listing mode. 14 15 // errStoreOffline is thrown when an operation requires the storage backend, but 16 // it is offline. 17 var errStoreOffline = errors.New("store offline") 18 19 type histlist struct { 20 all []string 21 dedup bool 22 caseInsensitive bool 23 last map[string]int 24 shown []string 25 index []int 26 indexWidth int 27 } 28 29 func newHistlist(cmds []string) *histlist { 30 last := make(map[string]int) 31 for i, entry := range cmds { 32 last[entry] = i 33 } 34 return &histlist{ 35 // This has to be here for the initialization to work :( 36 all: cmds, 37 dedup: true, 38 last: last, 39 indexWidth: len(strconv.Itoa(len(cmds) - 1)), 40 } 41 } 42 43 func (hl *histlist) Teardown() { 44 *hl = histlist{} 45 } 46 47 func (hl *histlist) ModeTitle(i int) string { 48 s := " HISTORY " 49 if hl.dedup { 50 s += "(dedup on) " 51 } 52 if hl.caseInsensitive { 53 s += "(case-insensitive) " 54 } 55 return s 56 } 57 58 func (*histlist) CursorOnModeLine() bool { 59 return true 60 } 61 62 func (hl *histlist) Len() int { 63 return len(hl.shown) 64 } 65 66 func (hl *histlist) Show(i int) (string, ui.Styled) { 67 return fmt.Sprintf("%d", hl.index[i]), ui.Unstyled(hl.shown[i]) 68 } 69 70 func (hl *histlist) Filter(filter string) int { 71 hl.shown = nil 72 hl.index = nil 73 dedup := hl.dedup 74 if hl.caseInsensitive { 75 filter = strings.ToLower(filter) 76 } 77 for i, entry := range hl.all { 78 fentry := entry 79 if hl.caseInsensitive { 80 fentry = strings.ToLower(entry) 81 } 82 if (!dedup || hl.last[entry] == i) && strings.Contains(fentry, filter) { 83 hl.index = append(hl.index, i) 84 hl.shown = append(hl.shown, entry) 85 } 86 } 87 // TODO: Maintain old selection 88 return len(hl.shown) - 1 89 } 90 91 // Editor interface. 92 93 func (hl *histlist) Accept(i int, ed eddefs.Editor) { 94 line := hl.shown[i] 95 buffer, _ := ed.Buffer() 96 if len(buffer) > 0 { 97 line = "\n" + line 98 } 99 ed.InsertAtDot(line) 100 } 101 102 func (hl *histlist) start(ed eddefs.Editor, fuser *Fuser, binding eddefs.BindingMap) { 103 cmds, err := getCmds(fuser) 104 if err != nil { 105 ed.Notify("%v", err) 106 return 107 } 108 109 *hl = *newHistlist(cmds) 110 111 ed.SetModeListing(binding, hl) 112 } 113 114 func getCmds(fuser *Fuser) ([]string, error) { 115 if fuser == nil { 116 return nil, errStoreOffline 117 } 118 return fuser.AllCmds() 119 } 120 121 func (hl *histlist) toggleDedup(ed eddefs.Editor) { 122 hl.dedup = !hl.dedup 123 ed.RefreshListing() 124 } 125 126 func (hl *histlist) toggleCaseSensitivity(ed eddefs.Editor) { 127 hl.caseInsensitive = !hl.caseInsensitive 128 ed.RefreshListing() 129 }