| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- package picker
- import (
- "github.com/ayn2op/tview"
- "github.com/gdamore/tcell/v3"
- "github.com/sahilm/fuzzy"
- )
- type (
- SelectedFunc func(item Item)
- CancelFunc func()
- )
- type Picker struct {
- *tview.Flex
- input *tview.InputField
- list *tview.List
- onSelected SelectedFunc
- onCancel CancelFunc
- keyMap *KeyMap
- items Items
- filtered Items
- }
- func New() *Picker {
- p := &Picker{
- Flex: tview.NewFlex(),
- input: tview.NewInputField(),
- list: tview.NewList(),
- }
- // Show a horizontal bottom border to visually separate input from list.
- borderSet := tview.BorderSet{
- Bottom: tview.BoxDrawingsLightHorizontal,
- }
- borderSet.BottomLeft = borderSet.Bottom
- borderSet.BottomRight = borderSet.Bottom
- p.input.
- SetChangedFunc(p.onInputChanged).
- SetLabel("> ").
- SetBorders(tview.BordersBottom).
- SetBorderSet(borderSet).
- SetBorderStyle(tcell.StyleDefault.Dim(true)).
- SetInputCapture(p.onInputCapture)
- p.list.
- SetSelectedFunc(p.onListSelected).
- ShowSecondaryText(false).
- SetHighlightFullLine(true)
- p.
- SetDirection(tview.FlexRow).
- // bottom border + value
- AddItem(p.input, 2, 0, true).
- AddItem(p.list, 0, 1, false)
- p.Update()
- return p
- }
- func (p *Picker) SetKeyMap(keyMap *KeyMap) {
- p.keyMap = keyMap
- }
- func (p *Picker) SetSelectedFunc(onSelected SelectedFunc) {
- p.onSelected = onSelected
- }
- func (p *Picker) SetCancelFunc(onCancel CancelFunc) {
- p.onCancel = onCancel
- }
- func (p *Picker) ClearInput() {
- p.input.SetText("")
- }
- func (p *Picker) ClearList() {
- p.list.Clear()
- }
- func (p *Picker) ClearItems() {
- p.items = nil
- p.filtered = nil
- }
- func (p *Picker) AddItem(item Item) {
- p.items = append(p.items, item)
- }
- func (p *Picker) Update() {
- p.ClearInput()
- p.onInputChanged("")
- }
- func (p *Picker) onListSelected(index int, text, _ string, _ rune) {
- if p.onSelected != nil {
- if index >= 0 && index < len(p.filtered) {
- item := p.filtered[index]
- p.onSelected(item)
- }
- }
- }
- func (p *Picker) onInputChanged(text string) {
- var fuzzied Items
- if text == "" {
- fuzzied = append(fuzzied, p.items...)
- } else {
- matches := fuzzy.FindFrom(text, p.items)
- for _, match := range matches {
- fuzzied = append(fuzzied, p.items[match.Index])
- }
- }
- p.filtered = fuzzied
- p.ClearList()
- for _, item := range fuzzied {
- p.list.AddItem(item.Text, "", 0, nil)
- }
- }
- func (p *Picker) onInputCapture(event *tcell.EventKey) *tcell.EventKey {
- if p.keyMap == nil {
- return nil
- }
- handler := p.list.InputHandler()
- switch event.Name() {
- case p.keyMap.Up:
- handler(tcell.NewEventKey(tcell.KeyUp, "", tcell.ModNone), nil)
- return nil
- case p.keyMap.Down:
- handler(tcell.NewEventKey(tcell.KeyDown, "", tcell.ModNone), nil)
- return nil
- case p.keyMap.Top:
- handler(tcell.NewEventKey(tcell.KeyHome, "", tcell.ModNone), nil)
- return nil
- case p.keyMap.Bottom:
- handler(tcell.NewEventKey(tcell.KeyEnd, "", tcell.ModNone), nil)
- case p.keyMap.Select:
- handler(tcell.NewEventKey(tcell.KeyEnter, "", tcell.ModNone), nil)
- case p.keyMap.Cancel:
- if p.onCancel != nil {
- p.onCancel()
- }
- return nil
- }
- return event
- }
|