package main import ( "strconv" "time" "github.com/nsf/termbox-go" ) const ( DefaultExpireTime = time.Second / 2 ) type EventBuffer struct { UpdateTime time.Time TimeoutLen time.Duration Buffer []termbox.Event CursorPos int } func NewEventBuffer() *EventBuffer { return &EventBuffer{ TimeoutLen: DefaultExpireTime, CursorPos: -1, } } func (eb *EventBuffer) checkExpiration() { if eb.TimeoutLen != -1 && time.Now().Sub(eb.UpdateTime) > eb.TimeoutLen { eb.Clear() } } func (eb *EventBuffer) StartsWith(r rune) bool { eb.checkExpiration() return len(eb.Buffer) > 0 && eb.Buffer[0].Ch == r } func (eb *EventBuffer) Add(event termbox.Event) { eb.checkExpiration() if event.Key == termbox.KeyCtrlU { eb.Clear() } else if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 { eb.Backspace() } else { eb.Buffer = append(eb.Buffer, event) } eb.UpdateTime = time.Now() } func (eb *EventBuffer) Backspace() { eb.checkExpiration() if len(eb.Buffer) >= 1 { eb.Buffer = eb.Buffer[:len(eb.Buffer)-1] } eb.UpdateTime = time.Now() } func (eb *EventBuffer) MoveCursorBack() { if eb.CursorPos > 0 { eb.CursorPos-- } } func (eb *EventBuffer) MoveCursorForward() { if eb.CursorPos < len(eb.Buffer) { eb.CursorPos++ } } func (eb *EventBuffer) SetCursorToStart() { eb.CursorPos = 0 } func (eb *EventBuffer) SetCursorToEnd() { eb.CursorPos = len(eb.Buffer) } func (eb *EventBuffer) Clear() { eb.Buffer = nil eb.UpdateTime = time.Now() } func (eb *EventBuffer) Events() []termbox.Event { eb.checkExpiration() return eb.Buffer } func (eb *EventBuffer) String() string { eb.checkExpiration() var ret string for _, v := range eb.Buffer { if v.Ch != 0 { ret = ret + string(v.Ch) } else { switch v.Key { case termbox.KeySpace: ret = ret + " " case termbox.KeyArrowUp: ret = ret + string(ChUpKeyValue) case termbox.KeyArrowRight: ret = ret + string(ChRightKeyValue) case termbox.KeyArrowDown: ret = ret + string(ChDownKeyValue) case termbox.KeyArrowLeft: ret = ret + string(ChLeftKeyValue) case termbox.KeyEnter: ret = ret + string(ChEnterKeyValue) } } } return ret } func (eb *EventBuffer) SetToString(s string) { eb.Clear() for _, v := range s { if v == '\n' { eb.Add(termbox.Event{Ch: 0, Key: termbox.KeyEnter}) } else { eb.Add(termbox.Event{Ch: v}) } } } func (eb *EventBuffer) MatchesString(s string) bool { eb.checkExpiration() if len(s) != len(eb.Buffer) { return false } return s == eb.String() } func (eb *EventBuffer) MatchesEvents(events []termbox.Event) bool { eb.checkExpiration() if len(events) != len(eb.Buffer) { return false } for k := range events { if events[k].Ch != eb.Buffer[k].Ch || events[k].Key != eb.Buffer[k].Key { return false } } return true } func (eb *EventBuffer) StartsWithKey(key termbox.Key) bool { eb.checkExpiration() if len(eb.Buffer) > 0 { return eb.Buffer[0].Key == key } return false } func (eb *EventBuffer) Size() int { eb.checkExpiration() return len(eb.Buffer) } func (eb *EventBuffer) IsNumber() bool { _, err := strconv.Atoi(eb.String()) return err == nil } func (eb *EventBuffer) Number() (int, error) { return strconv.Atoi(eb.String()) } func (eb *EventBuffer) OptNumber(def int) int { ret, err := strconv.Atoi(eb.String()) if err != nil { return def } return ret }