github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/shell/autocomplete/autocomplete.go (about)

     1  package autocomplete
     2  
     3  import (
     4  	"strings"
     5  	"time"
     6  
     7  	"github.com/lmorg/murex/lang"
     8  	"github.com/lmorg/murex/shell/hintsummary"
     9  	"github.com/lmorg/murex/utils/cache"
    10  	"github.com/lmorg/murex/utils/parser"
    11  	"github.com/lmorg/murex/utils/readline"
    12  )
    13  
    14  // AutoCompleteT is a struct designed for ease to pass common values around the
    15  // many functions for autocompletion. It's passed as a pointer and is only
    16  // intended for use by murex internal functions (ie not called by other funcs
    17  // external to the murex codebase)
    18  type AutoCompleteT struct {
    19  	Items             []string
    20  	Definitions       map[string]string
    21  	MinTabItemLength  int
    22  	TabDisplayType    readline.TabDisplayType
    23  	ErrCallback       func(error)
    24  	DelayedTabContext readline.DelayedTabContext
    25  	ParsedTokens      parser.ParsedTokens
    26  	CacheDynamic      bool
    27  	DoNotSort         bool
    28  	DoNotEscape       bool
    29  	TimeOut           time.Time
    30  	PreviewBlock      string
    31  }
    32  
    33  func (act *AutoCompleteT) append(items ...string) {
    34  	act.Items = append(act.Items, items...)
    35  }
    36  
    37  func (act *AutoCompleteT) appendDef(item, def string) {
    38  	act.Definitions[item] = def
    39  	act.append(item)
    40  }
    41  
    42  func (act *AutoCompleteT) largeMin() {
    43  	width := readline.GetTermWidth()
    44  	switch {
    45  	case width < 40:
    46  		act.MinTabItemLength = 10
    47  	case width < 30:
    48  		act.MinTabItemLength = 15
    49  	case width < 80:
    50  		act.MinTabItemLength = 20
    51  	case width < 120:
    52  		act.MinTabItemLength = 30
    53  	case width < 160:
    54  		act.MinTabItemLength = 40
    55  	default:
    56  		act.MinTabItemLength = 40
    57  	}
    58  }
    59  
    60  func (act *AutoCompleteT) disposable() *AutoCompleteT {
    61  	return &AutoCompleteT{
    62  		Items:             []string{},
    63  		Definitions:       make(map[string]string),
    64  		ErrCallback:       act.ErrCallback,
    65  		DelayedTabContext: act.DelayedTabContext,
    66  		ParsedTokens:      act.ParsedTokens,
    67  	}
    68  }
    69  
    70  // MatchFunction returns autocomplete suggestions for functions / executables
    71  // based on a partial string
    72  func MatchFunction(partial string, act *AutoCompleteT) {
    73  	switch {
    74  	case pathIsLocal(partial):
    75  		act.Items = matchLocal(partial, true)
    76  		act.Items = append(act.Items, matchDirs(partial, act)...)
    77  	default:
    78  		exes := allExecutables(true)
    79  		act.Items = matchExes(partial, exes)
    80  
    81  		for i := range act.Items {
    82  			var summary string
    83  			if cache.Read(cache.HINT_SUMMARY, partial+act.Items[i], &summary) {
    84  				act.Definitions[act.Items[i]] = summary
    85  			}
    86  		}
    87  	}
    88  }
    89  
    90  func CacheHints() {
    91  	exes := allExecutables(true)
    92  
    93  	for exe := range exes {
    94  		_ = hintsummary.Get(exe, true)
    95  	}
    96  }
    97  
    98  // MatchVars returns autocomplete suggestions for variables based on a partial
    99  // string
   100  func MatchVars(partial string) (items []string) {
   101  	vars := lang.DumpVariables(lang.ShellProcess)
   102  
   103  	for name := range vars {
   104  		if strings.HasPrefix(name, partial[1:]) {
   105  			items = append(items, name[len(partial)-1:])
   106  		}
   107  	}
   108  
   109  	return
   110  }
   111  
   112  // MatchFlags is the entry point for murex's complex system of flag matching
   113  func MatchFlags(act *AutoCompleteT) {
   114  	if act.ParsedTokens.ExpectParam || len(act.ParsedTokens.Parameters) == 0 {
   115  		act.ParsedTokens.Parameters = append(act.ParsedTokens.Parameters, "")
   116  	}
   117  
   118  	args := dynamicArgs{
   119  		exe:    act.ParsedTokens.FuncName,
   120  		params: make([]string, len(act.ParsedTokens.Parameters)),
   121  	}
   122  	copy(args.params, act.ParsedTokens.Parameters)
   123  
   124  	params := make([]string, len(act.ParsedTokens.Parameters))
   125  	copy(params, act.ParsedTokens.Parameters)
   126  
   127  	flags := ExesFlags[act.ParsedTokens.FuncName]
   128  
   129  	partial := act.ParsedTokens.Parameters[len(act.ParsedTokens.Parameters)-1]
   130  	exe := act.ParsedTokens.FuncName
   131  
   132  	pIndex := 0
   133  
   134  	act.TimeOut = time.Now().Add(1 * time.Second)
   135  
   136  	occurrences = 0
   137  	matchFlags(flags, 0, partial, exe, params, &pIndex, args, act)
   138  }