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

     1  // Package completion implements the UI for showing, filtering and inserting
     2  // completion candidates.
     3  package completion
     4  
     5  import (
     6  	"strings"
     7  
     8  	"github.com/elves/elvish/pkg/cli"
     9  	"github.com/elves/elvish/pkg/diag"
    10  	"github.com/elves/elvish/pkg/ui"
    11  )
    12  
    13  // Item represents a completion item, also known as a candidate.
    14  type Item struct {
    15  	// Used in the UI and for filtering.
    16  	ToShow string
    17  	// Style to use in the UI.
    18  	ShowStyle ui.Style
    19  	// Used when inserting a candidate.
    20  	ToInsert string
    21  }
    22  
    23  // Config keeps the configuration for the completion UI.
    24  type Config struct {
    25  	Binding cli.Handler
    26  	Name    string
    27  	Replace diag.Ranging
    28  	Items   []Item
    29  }
    30  
    31  // Start starts the completion UI.
    32  func Start(app cli.App, cfg Config) {
    33  	if len(cfg.Items) == 0 {
    34  		app.Notify("no candidates")
    35  		return
    36  	}
    37  	w := cli.NewComboBox(cli.ComboBoxSpec{
    38  		CodeArea: cli.CodeAreaSpec{
    39  			Prompt: cli.ModePrompt(" COMPLETING "+cfg.Name+" ", true),
    40  		},
    41  		ListBox: cli.ListBoxSpec{
    42  			Horizontal:     true,
    43  			OverlayHandler: cfg.Binding,
    44  			OnSelect: func(it cli.Items, i int) {
    45  				text := it.(items)[i].ToInsert
    46  				app.CodeArea().MutateState(func(s *cli.CodeAreaState) {
    47  					s.Pending = cli.PendingCode{
    48  						From: cfg.Replace.From, To: cfg.Replace.To, Content: text}
    49  				})
    50  			},
    51  			OnAccept: func(it cli.Items, i int) {
    52  				app.CodeArea().MutateState(func(s *cli.CodeAreaState) {
    53  					s.ApplyPending()
    54  				})
    55  				app.MutateState(func(s *cli.State) { s.Addon = nil })
    56  			},
    57  			ExtendStyle: true,
    58  		},
    59  		OnFilter: func(w cli.ComboBox, p string) {
    60  			w.ListBox().Reset(filter(cfg.Items, p), 0)
    61  		},
    62  	})
    63  	app.MutateState(func(s *cli.State) { s.Addon = w })
    64  	app.Redraw()
    65  }
    66  
    67  // Close closes the completion UI.
    68  func Close(app cli.App) {
    69  	app.CodeArea().MutateState(
    70  		func(s *cli.CodeAreaState) { s.Pending = cli.PendingCode{} })
    71  	app.MutateState(func(s *cli.State) { s.Addon = nil })
    72  	app.Redraw()
    73  }
    74  
    75  type items []Item
    76  
    77  func filter(all []Item, p string) items {
    78  	var filtered []Item
    79  	for _, candidate := range all {
    80  		if strings.Contains(candidate.ToShow, p) {
    81  			filtered = append(filtered, candidate)
    82  		}
    83  	}
    84  	return filtered
    85  }
    86  
    87  func (it items) Show(i int) ui.Text {
    88  	return ui.Text{&ui.Segment{Style: it[i].ShowStyle, Text: it[i].ToShow}}
    89  }
    90  
    91  func (it items) Len() int { return len(it) }