github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/cli/mode/listing.go (about) 1 package mode 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 accpeting. 28 // If unspecified, the Accept function default to a function that does 29 // nothing other than returning false. 30 Accept func(string) bool 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) bool { return false } 52 } 53 if spec.Caption == "" { 54 spec.Caption = " LISTING " 55 } 56 accept := func(s string) { 57 retain := spec.Accept(s) 58 if !retain { 59 app.SetAddon(nil, false) 60 } 61 } 62 w := tk.NewComboBox(tk.ComboBoxSpec{ 63 CodeArea: tk.CodeAreaSpec{ 64 Prompt: modePrompt(spec.Caption, true), 65 }, 66 ListBox: tk.ListBoxSpec{ 67 Bindings: spec.Bindings, 68 OnAccept: func(it tk.Items, i int) { 69 accept(it.(listingItems)[i].ToAccept) 70 }, 71 ExtendStyle: true, 72 }, 73 OnFilter: func(w tk.ComboBox, q string) { 74 it, selected := spec.GetItems(q) 75 w.ListBox().Reset(listingItems(it), selected) 76 if spec.AutoAccept && len(it) == 1 { 77 accept(it[0].ToAccept) 78 } 79 }, 80 }) 81 return w, nil 82 } 83 84 type listingItems []ListingItem 85 86 func (it listingItems) Len() int { return len(it) } 87 func (it listingItems) Show(i int) ui.Text { return it[i].ToShow }