github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/utils/readline/timer.go (about) 1 package readline 2 3 import ( 4 "context" 5 "sync/atomic" 6 7 "github.com/lmorg/murex/utils/lists" 8 ) 9 10 func delayedSyntaxTimer(rl *Instance, i int32) { 11 if rl.PasswordMask != 0 || rl.DelayedSyntaxWorker == nil { 12 return 13 } 14 15 if rl.cacheSyntax.Get(rl.line.Runes()) != "" { 16 return 17 } 18 19 if rl.line.CellLen()+rl.promptLen > rl.termWidth { 20 // line wraps, which is hard to do with random ANSI escape sequences 21 // so better we don't bother trying. 22 return 23 } 24 25 newLine := rl.DelayedSyntaxWorker(rl.line.Runes()) 26 var sLine string 27 28 if rl.SyntaxHighlighter != nil { 29 sLine = rl.SyntaxHighlighter(newLine) 30 } else { 31 sLine = string(newLine) 32 } 33 rl.cacheSyntax.Append(rl.line.Runes(), sLine) 34 35 if atomic.LoadInt32(&rl.delayedSyntaxCount) != i { 36 return 37 } 38 39 output := rl.moveCursorToStartStr() 40 output += sLine 41 output += rl.moveCursorFromEndToLinePosStr() 42 print(output) 43 } 44 45 // DelayedTabContext is a custom context interface for async updates to the tab completions 46 type DelayedTabContext struct { 47 rl *Instance 48 Context context.Context 49 cancel context.CancelFunc 50 } 51 52 // AppendSuggestions updates the tab completions with additional suggestions asynchronously 53 func (dtc *DelayedTabContext) AppendSuggestions(suggestions []string) { 54 if dtc == nil || dtc.rl == nil { 55 return 56 } 57 58 if !dtc.rl.modeTabCompletion { 59 return 60 } 61 62 max := dtc.rl.MaxTabCompleterRows * 20 63 64 if len(dtc.rl.tcSuggestions) == 0 { 65 dtc.rl.ForceHintTextUpdate(" ") 66 } 67 68 dtc.rl.tabMutex.Lock() 69 70 if dtc.rl.tcDescriptions == nil { 71 dtc.rl.tcDescriptions = make(map[string]string) 72 } 73 74 for i := range suggestions { 75 select { 76 case <-dtc.Context.Done(): 77 dtc.rl.tabMutex.Unlock() 78 return 79 80 default: 81 if dtc.rl.tcDescriptions[suggestions[i]] != "" || 82 (len(dtc.rl.tcSuggestions) < max && lists.Match(dtc.rl.tcSuggestions, suggestions[i])) { 83 // dedup 84 continue 85 } 86 dtc.rl.tcDescriptions[suggestions[i]] = dtc.rl.tcPrefix + suggestions[i] 87 dtc.rl.tcSuggestions = append(dtc.rl.tcSuggestions, suggestions[i]) 88 } 89 } 90 91 dtc.rl.tabMutex.Unlock() 92 93 output := dtc.rl.clearHelpersStr() 94 //dtc.rl.ForceHintTextUpdate(" ") 95 output += dtc.rl.renderHelpersStr() 96 print(output) 97 } 98 99 // AppendDescriptions updates the tab completions with additional suggestions + descriptions asynchronously 100 func (dtc *DelayedTabContext) AppendDescriptions(suggestions map[string]string) { 101 if dtc.rl == nil { 102 // This might legitimately happen with some tests 103 return 104 } 105 106 if !dtc.rl.modeTabCompletion { 107 return 108 } 109 110 max := dtc.rl.MaxTabCompleterRows * 20 111 112 if len(dtc.rl.tcSuggestions) == 0 { 113 dtc.rl.ForceHintTextUpdate(" ") 114 } 115 116 dtc.rl.tabMutex.Lock() 117 118 for k := range suggestions { 119 select { 120 case <-dtc.Context.Done(): 121 dtc.rl.tabMutex.Unlock() 122 return 123 124 default: 125 if dtc.rl.tcDescriptions[k] != "" || 126 (len(dtc.rl.tcSuggestions) < max && lists.Match(dtc.rl.tcSuggestions, k)) { 127 // dedup 128 continue 129 } 130 dtc.rl.tcDescriptions[k] = suggestions[k] 131 dtc.rl.tcSuggestions = append(dtc.rl.tcSuggestions, k) 132 } 133 } 134 135 dtc.rl.tabMutex.Unlock() 136 137 output := dtc.rl.clearHelpersStr() 138 //dtc.rl.ForceHintTextUpdate(" ") 139 output += dtc.rl.renderHelpersStr() 140 print(output) 141 } 142 143 func delayedPreviewTimer(rl *Instance, fn PreviewFuncT, size *PreviewSizeT, item string) { 144 var ctx context.Context 145 146 callback := func(lines []string, pos int, err error) { 147 select { 148 case <-ctx.Done(): 149 return 150 default: 151 // continue 152 } 153 154 if err != nil { 155 rl.ForceHintTextUpdate(err.Error()) 156 return 157 } 158 159 output, err := rl.previewDrawStr(lines[pos:], size) 160 161 if err != nil { 162 rl.previewCache = nil 163 print(output) 164 return 165 } 166 167 rl.previewCache = &previewCacheT{ 168 item: item, 169 pos: pos, 170 len: size.Height, 171 lines: lines, 172 size: size, 173 } 174 175 print(output) 176 } 177 178 ctx, rl.previewCancel = context.WithCancel(context.Background()) 179 fn(ctx, rl.line.Runes(), item, rl.PreviewImages, size, callback) 180 }