src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/cli/modes/listing.go (about) 1 package modes 2 3 import ( 4 "errors" 5 6 "src.elv.sh/pkg/cli" 7 "src.elv.sh/pkg/cli/tk" 8 "src.elv.sh/pkg/ui" 9 ) 10 11 // Listing is a customizable mode for browsing through a list of items. It is 12 // based on the ComboBox widget. 13 type Listing interface { 14 tk.ComboBox 15 } 16 17 // ListingSpec specifies the configuration for the listing mode. 18 type ListingSpec struct { 19 // Key bindings. 20 Bindings tk.Bindings 21 // Caption of the listing. If empty, defaults to " LISTING ". 22 Caption string 23 // A function that takes the query string and returns a list of Item's and 24 // the index of the Item to select. Required. 25 GetItems func(query string) (items []ListingItem, selected int) 26 // A function to call when the user has accepted the selected item. If the 27 // return value is true, the listing will not be closed after accepting. 28 // If unspecified, the Accept function default to a function that does 29 // nothing other than returning false. 30 Accept func(string) 31 // Whether to automatically accept when there is only one item. 32 AutoAccept bool 33 } 34 35 // ListingItem is an item to show in the listing. 36 type ListingItem struct { 37 // Passed to the Accept callback in Config. 38 ToAccept string 39 // How the item is shown. 40 ToShow ui.Text 41 } 42 43 var errGetItemsMustBeSpecified = errors.New("GetItems must be specified") 44 45 // NewListing creates a new listing mode. 46 func NewListing(app cli.App, spec ListingSpec) (Listing, error) { 47 if spec.GetItems == nil { 48 return nil, errGetItemsMustBeSpecified 49 } 50 if spec.Accept == nil { 51 spec.Accept = func(string) {} 52 } 53 if spec.Caption == "" { 54 spec.Caption = " LISTING " 55 } 56 accept := func(s string) { 57 app.PopAddon() 58 spec.Accept(s) 59 } 60 w := tk.NewComboBox(tk.ComboBoxSpec{ 61 CodeArea: tk.CodeAreaSpec{ 62 Prompt: modePrompt(spec.Caption, true), 63 }, 64 ListBox: tk.ListBoxSpec{ 65 Bindings: spec.Bindings, 66 OnAccept: func(it tk.Items, i int) { 67 accept(it.(listingItems)[i].ToAccept) 68 }, 69 ExtendStyle: true, 70 }, 71 OnFilter: func(w tk.ComboBox, q string) { 72 it, selected := spec.GetItems(q) 73 w.ListBox().Reset(listingItems(it), selected) 74 if spec.AutoAccept && len(it) == 1 { 75 accept(it[0].ToAccept) 76 } 77 }, 78 }) 79 return w, nil 80 } 81 82 type listingItems []ListingItem 83 84 func (it listingItems) Len() int { return len(it) } 85 func (it listingItems) Show(i int) ui.Text { return it[i].ToShow }