Hilbish/readline/comp-map.go

141 lines
3.1 KiB
Go

package readline
import (
"fmt"
"strconv"
)
// initMap - Map display details. Called each time we want to be sure to have
// a working completion group either immediately, or later on. Generally defered.
func (g *CompletionGroup) initMap(rl *Instance) {
// We make the map anyway, especially if we need to use it later
if g.Descriptions == nil {
g.Descriptions = make(map[string]string)
}
// Compute size of each completion item box. Group independent
g.tcMaxLength = 1
for i := range g.Suggestions {
if len(g.Descriptions[g.Suggestions[i]]) > g.tcMaxLength {
g.tcMaxLength = len(g.Descriptions[g.Suggestions[i]])
}
}
g.tcPosX = 0
g.tcPosY = 0
g.tcOffset = 0
// Number of lines allowed to be printed for group
if len(g.Suggestions) > g.MaxLength {
g.tcMaxY = g.MaxLength
} else {
g.tcMaxY = len(g.Suggestions)
}
}
// moveTabMapHighlight - Moves the highlighting for currently selected completion item (map display)
func (g *CompletionGroup) moveTabMapHighlight(rl *Instance, x, y int) (done bool, next bool) {
g.tcPosY += x
g.tcPosY += y
// Lines
if g.tcPosY < 1 {
if rl.tabCompletionReverse {
if g.tcOffset > 0 {
g.tcPosY = 1
g.tcOffset--
} else {
return true, false
}
}
}
if g.tcPosY > g.tcMaxY {
g.tcPosY--
g.tcOffset++
}
if g.tcOffset+g.tcPosY < 1 && len(g.Suggestions) > 0 {
g.tcPosY = g.tcMaxY
g.tcOffset = len(g.Suggestions) - g.tcMaxY
}
if g.tcOffset < 0 {
g.tcOffset = 0
}
if g.tcOffset+g.tcPosY > len(g.Suggestions) {
g.tcOffset--
return true, true
}
return false, false
}
// writeMap - A map or list completion string
func (g *CompletionGroup) writeMap(rl *Instance) (comp string) {
if g.Name != "" {
// Print group title (changes with line returns depending on type)
comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, fmtEscape(g.Name), RESET)
rl.tcUsedY++
}
termWidth := GetTermWidth()
if termWidth < 20 {
// terminal too small. Probably better we do nothing instead of crash
// We are more conservative than lmorg, and push it to 20 instead of 10
return
}
// Set all necessary dimensions
maxLength := g.tcMaxLength
if maxLength > termWidth-9 {
maxLength = termWidth - 9
}
maxDescWidth := termWidth - maxLength - 4
cellWidth := strconv.Itoa(maxLength)
itemWidth := strconv.Itoa(maxDescWidth)
y := 0
// Highlighting function
highlight := func(y int) string {
if y == g.tcPosY && g.isCurrent {
return seqInvert
}
return ""
}
// String formating
var item, description string
for i := g.tcOffset; i < len(g.Suggestions); i++ {
y++ // Consider new item
if y > g.tcMaxY {
break
}
item = g.Suggestions[i]
if len(item) > maxDescWidth {
item = item[:maxDescWidth-3] + "..."
}
description = g.Descriptions[g.Suggestions[i]]
if len(description) > maxLength {
description = description[:maxLength-3] + "..."
}
comp += fmt.Sprintf("\r%-"+cellWidth+"s %s %-"+itemWidth+"s %s\n",
description, highlight(y), fmtEscape(item), seqReset)
}
// Add the equivalent of this group's size to final screen clearing
if len(g.Suggestions) > g.MaxLength {
rl.tcUsedY += g.MaxLength
} else {
rl.tcUsedY += len(g.Suggestions)
}
return
}