github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/utils/readline/tab.go (about) 1 package readline 2 3 import ( 4 "context" 5 ) 6 7 // TabDisplayType defines how the autocomplete suggestions display 8 type TabDisplayType int 9 10 const ( 11 // TabDisplayGrid is the default. It's where the screen below the prompt is 12 // divided into a grid with each suggestion occupying an individual cell. 13 TabDisplayGrid = iota 14 15 // TabDisplayList is where suggestions are displayed as a list with a 16 // description. The suggestion gets highlighted but both are searchable (ctrl+f) 17 TabDisplayList 18 19 // TabDisplayMap is where suggestions are displayed as a list with a 20 // description however the description is what gets highlighted and only 21 // that is searchable (ctrl+f). The benefit of TabDisplayMap is when your 22 // autocomplete suggestions are IDs rather than human terms. 23 TabDisplayMap 24 ) 25 26 func (rl *Instance) getTabCompletion() { 27 rl.tcOffset = 0 28 if rl.TabCompleter == nil { 29 return 30 } 31 32 if rl.delayedTabContext.cancel != nil { 33 rl.delayedTabContext.cancel() 34 } 35 36 rl.delayedTabContext = DelayedTabContext{rl: rl} 37 rl.delayedTabContext.Context, rl.delayedTabContext.cancel = context.WithCancel(context.Background()) 38 39 rl.tcr = rl.TabCompleter(rl.line.Runes(), rl.line.RunePos(), rl.delayedTabContext) 40 if rl.tcr == nil { 41 return 42 } 43 44 rl.tabMutex.Lock() 45 rl.tcPrefix, rl.tcSuggestions, rl.tcDescriptions, rl.tcDisplayType = rl.tcr.Prefix, rl.tcr.Suggestions, rl.tcr.Descriptions, rl.tcr.DisplayType 46 if len(rl.tcDescriptions) == 0 { 47 // probably not needed, but just in case someone doesn't initialize the 48 // map in their API call. 49 rl.tcDescriptions = make(map[string]string) 50 } 51 rl.tabMutex.Unlock() 52 53 rl.initTabCompletion() 54 } 55 56 func (rl *Instance) initTabCompletion() { 57 rl.modeTabCompletion = true 58 if rl.tcDisplayType == TabDisplayGrid { 59 rl.initTabGrid() 60 } else { 61 rl.initTabMap() 62 } 63 } 64 65 func (rl *Instance) moveTabCompletionHighlight(x, y int) { 66 if rl.tcDisplayType == TabDisplayGrid { 67 rl.moveTabGridHighlight(x, y) 68 } else { 69 rl.moveTabMapHighlight(x, y) 70 } 71 } 72 73 func (rl *Instance) writeTabCompletionStr() string { 74 if !rl.modeTabCompletion { 75 return "" 76 } 77 78 posX, posY := rl.lineWrapCellPos() 79 _, lineY := rl.lineWrapCellLen() 80 output := moveCursorDownStr(rl.hintY + lineY - posY) 81 output += "\r\n" + seqClearScreenBelow 82 83 switch rl.tcDisplayType { 84 case TabDisplayGrid: 85 output += rl.writeTabGridStr() 86 87 case TabDisplayMap: 88 output += rl.writeTabMapStr() 89 90 case TabDisplayList: 91 output += rl.writeTabMapStr() 92 93 default: 94 output += rl.writeTabGridStr() 95 } 96 97 output += moveCursorUpStr(rl.hintY + rl.tcUsedY + lineY - posY) 98 output += "\r" + moveCursorForwardsStr(posX) 99 100 return output 101 } 102 103 func (rl *Instance) resetTabCompletion() { 104 rl.modeTabCompletion = false 105 rl.tcOffset = 0 106 rl.tcUsedY = 0 107 rl.modeTabFind = false 108 rl.modeAutoFind = false 109 rl.tfLine = []rune{} 110 }