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 }