github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/elvish/edit/history/histlist.go (about)

     1  package history
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/u-root/u-root/cmds/elvish/edit/eddefs"
    10  	"github.com/u-root/u-root/cmds/elvish/edit/ui"
    11  )
    12  
    13  // Command history listing mode.
    14  
    15  // errStoreOffline is thrown when an operation requires the storage backend, but
    16  // it is offline.
    17  var errStoreOffline = errors.New("store offline")
    18  
    19  type histlist struct {
    20  	all             []string
    21  	dedup           bool
    22  	caseInsensitive bool
    23  	last            map[string]int
    24  	shown           []string
    25  	index           []int
    26  	indexWidth      int
    27  }
    28  
    29  func newHistlist(cmds []string) *histlist {
    30  	last := make(map[string]int)
    31  	for i, entry := range cmds {
    32  		last[entry] = i
    33  	}
    34  	return &histlist{
    35  		// This has to be here for the initialization to work :(
    36  		all:        cmds,
    37  		dedup:      true,
    38  		last:       last,
    39  		indexWidth: len(strconv.Itoa(len(cmds) - 1)),
    40  	}
    41  }
    42  
    43  func (hl *histlist) Teardown() {
    44  	*hl = histlist{}
    45  }
    46  
    47  func (hl *histlist) ModeTitle(i int) string {
    48  	s := " HISTORY "
    49  	if hl.dedup {
    50  		s += "(dedup on) "
    51  	}
    52  	if hl.caseInsensitive {
    53  		s += "(case-insensitive) "
    54  	}
    55  	return s
    56  }
    57  
    58  func (*histlist) CursorOnModeLine() bool {
    59  	return true
    60  }
    61  
    62  func (hl *histlist) Len() int {
    63  	return len(hl.shown)
    64  }
    65  
    66  func (hl *histlist) Show(i int) (string, ui.Styled) {
    67  	return fmt.Sprintf("%d", hl.index[i]), ui.Unstyled(hl.shown[i])
    68  }
    69  
    70  func (hl *histlist) Filter(filter string) int {
    71  	hl.shown = nil
    72  	hl.index = nil
    73  	dedup := hl.dedup
    74  	if hl.caseInsensitive {
    75  		filter = strings.ToLower(filter)
    76  	}
    77  	for i, entry := range hl.all {
    78  		fentry := entry
    79  		if hl.caseInsensitive {
    80  			fentry = strings.ToLower(entry)
    81  		}
    82  		if (!dedup || hl.last[entry] == i) && strings.Contains(fentry, filter) {
    83  			hl.index = append(hl.index, i)
    84  			hl.shown = append(hl.shown, entry)
    85  		}
    86  	}
    87  	// TODO: Maintain old selection
    88  	return len(hl.shown) - 1
    89  }
    90  
    91  // Editor interface.
    92  
    93  func (hl *histlist) Accept(i int, ed eddefs.Editor) {
    94  	line := hl.shown[i]
    95  	buffer, _ := ed.Buffer()
    96  	if len(buffer) > 0 {
    97  		line = "\n" + line
    98  	}
    99  	ed.InsertAtDot(line)
   100  }
   101  
   102  func (hl *histlist) start(ed eddefs.Editor, fuser *Fuser, binding eddefs.BindingMap) {
   103  	cmds, err := getCmds(fuser)
   104  	if err != nil {
   105  		ed.Notify("%v", err)
   106  		return
   107  	}
   108  
   109  	*hl = *newHistlist(cmds)
   110  
   111  	ed.SetModeListing(binding, hl)
   112  }
   113  
   114  func getCmds(fuser *Fuser) ([]string, error) {
   115  	if fuser == nil {
   116  		return nil, errStoreOffline
   117  	}
   118  	return fuser.AllCmds()
   119  }
   120  
   121  func (hl *histlist) toggleDedup(ed eddefs.Editor) {
   122  	hl.dedup = !hl.dedup
   123  	ed.RefreshListing()
   124  }
   125  
   126  func (hl *histlist) toggleCaseSensitivity(ed eddefs.Editor) {
   127  	hl.caseInsensitive = !hl.caseInsensitive
   128  	ed.RefreshListing()
   129  }