package tui import ( "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) type InputFieldWithHistory struct { *tview.InputField history []string historyLimit int historyPointer int currentContent string } func NewInputFieldWithHistory(historyLimit int) *InputFieldWithHistory { return &InputFieldWithHistory{ InputField: tview.NewInputField(), historyLimit: historyLimit, } } func (f *InputFieldWithHistory) AddToHistory(s string) { // Stop scrolling history on history change, need to start scrolling again. defer func() { f.historyPointer = len(f.history) }() // Used history data for search prompt, so just make that data recent. if f.historyPointer != len(f.history) && s == f.history[f.historyPointer] { f.history = append(f.history[:f.historyPointer], f.history[f.historyPointer+1:]...) f.history = append(f.history, s) } if len(f.history) == f.historyLimit { f.history = f.history[1:] } f.history = append(f.history, s) } func (f *InputFieldWithHistory) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) { return f.WrapInputHandler(func(event *tcell.EventKey, _ func(tview.Primitive)) { switch event.Key() { case tcell.KeyDown: if len(f.history) == 0 { return } // Need to start iterating before. if f.historyPointer == len(f.history) { return } // Iterate to most recent prompts. f.historyPointer++ // Stop iterating over history. if f.historyPointer == len(f.history) { f.InputField.SetText(f.currentContent) return } f.InputField.SetText(f.history[f.historyPointer]) case tcell.KeyUp: if len(f.history) == 0 { return } // Start iterating over history. if f.historyPointer == len(f.history) { f.currentContent = f.InputField.GetText() } // End of history. if f.historyPointer == 0 { return } // Iterate to least recent prompts. f.historyPointer-- f.InputField.SetText(f.history[f.historyPointer]) default: f.InputField.InputHandler()(event, func(tview.Primitive) {}) } }) }