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  }