github.com/elves/elvish@v0.15.0/pkg/cli/combobox.go (about)

     1  package cli
     2  
     3  import (
     4  	"github.com/elves/elvish/pkg/cli/term"
     5  )
     6  
     7  // ComboBox is a Widget that combines a ListBox and a CodeArea.
     8  type ComboBox interface {
     9  	Widget
    10  	// Returns the embedded codearea widget.
    11  	CodeArea() CodeArea
    12  	// Returns the embedded listbox widget.
    13  	ListBox() ListBox
    14  	// Forces the filtering to rerun.
    15  	Refilter()
    16  }
    17  
    18  // ComboBoxSpec specifies the configuration and initial state for ComboBox.
    19  type ComboBoxSpec struct {
    20  	CodeArea CodeAreaSpec
    21  	ListBox  ListBoxSpec
    22  	OnFilter func(ComboBox, string)
    23  }
    24  
    25  type comboBox struct {
    26  	codeArea CodeArea
    27  	listBox  ListBox
    28  	OnFilter func(ComboBox, string)
    29  
    30  	// Last filter value.
    31  	lastFilter string
    32  }
    33  
    34  // NewComboBox creates a new ComboBox from the given spec.
    35  func NewComboBox(spec ComboBoxSpec) ComboBox {
    36  	if spec.OnFilter == nil {
    37  		spec.OnFilter = func(ComboBox, string) {}
    38  	}
    39  	w := &comboBox{
    40  		codeArea: NewCodeArea(spec.CodeArea),
    41  		listBox:  NewListBox(spec.ListBox),
    42  		OnFilter: spec.OnFilter,
    43  	}
    44  	w.OnFilter(w, "")
    45  	return w
    46  }
    47  
    48  // Render renders the codearea and the listbox below it.
    49  func (w *comboBox) Render(width, height int) *term.Buffer {
    50  	buf := w.codeArea.Render(width, height)
    51  	bufListBox := w.listBox.Render(width, height-len(buf.Lines))
    52  	buf.Extend(bufListBox, false)
    53  	return buf
    54  }
    55  
    56  // Handle first lets the listbox handle the event, and if it is unhandled, lets
    57  // the codearea handle it. If the codearea has handled the event and the code
    58  // content has changed, it calls OnFilter with the new content.
    59  func (w *comboBox) Handle(event term.Event) bool {
    60  	if w.listBox.Handle(event) {
    61  		return true
    62  	}
    63  	if w.codeArea.Handle(event) {
    64  		filter := w.codeArea.CopyState().Buffer.Content
    65  		if filter != w.lastFilter {
    66  			w.OnFilter(w, filter)
    67  			w.lastFilter = filter
    68  		}
    69  		return true
    70  	}
    71  	return false
    72  }
    73  
    74  func (w *comboBox) Refilter() {
    75  	w.OnFilter(w, w.codeArea.CopyState().Buffer.Content)
    76  }
    77  
    78  func (w *comboBox) CodeArea() CodeArea { return w.codeArea }
    79  func (w *comboBox) ListBox() ListBox   { return w.listBox }