go-prompt/completion.go

155 lines
3.2 KiB
Go
Raw Permalink Normal View History

2017-08-04 11:19:12 +00:00
package prompt
2017-08-09 12:33:47 +00:00
import (
"log"
"strings"
)
2017-08-12 09:55:36 +00:00
const (
shortenSuffix = "..."
leftPrefix = " "
leftSuffix = " "
rightPrefix = " "
rightSuffix = " "
leftMargin = len(leftPrefix + leftSuffix)
rightMargin = len(rightPrefix + rightSuffix)
completionMargin = leftMargin + rightMargin
)
2017-08-04 11:30:50 +00:00
type Suggest struct {
2017-08-04 11:19:12 +00:00
Text string
Description string
}
type CompletionManager struct {
2017-08-09 12:33:47 +00:00
selected int // -1 means nothing one is selected.
tmp []Suggest
2017-08-12 09:59:10 +00:00
max uint16
2017-08-09 12:33:47 +00:00
completer Completer
}
func (c *CompletionManager) GetSelectedSuggestion() (s Suggest, ok bool) {
if c.selected == -1 {
return Suggest{}, false
} else if c.selected < -1 {
log.Printf("[ERROR] shoud be reached here, selected=%d", c.selected)
2017-08-11 09:24:44 +00:00
c.selected = -1
2017-08-09 12:33:47 +00:00
return Suggest{}, false
}
return c.tmp[c.selected], true
}
func (c *CompletionManager) GetSuggestions() []Suggest {
return c.tmp
2017-08-04 11:19:12 +00:00
}
func (c *CompletionManager) Reset() {
c.selected = -1
c.Update(*NewDocument())
2017-08-04 11:19:12 +00:00
return
}
func (c *CompletionManager) Update(in Document) {
2017-08-09 12:33:47 +00:00
c.tmp = c.completer(in)
2017-08-04 11:19:12 +00:00
return
}
func (c *CompletionManager) Previous() {
c.selected--
2017-08-09 12:33:47 +00:00
c.update()
2017-08-04 11:19:12 +00:00
return
}
func (c *CompletionManager) Next() {
c.selected++
2017-08-09 12:33:47 +00:00
c.update()
2017-08-04 11:19:12 +00:00
return
}
func (c *CompletionManager) Completing() bool {
return c.selected != -1
}
2017-08-09 12:33:47 +00:00
func (c *CompletionManager) update() {
2017-08-12 09:59:10 +00:00
max := int(c.max)
2017-08-09 12:33:47 +00:00
if len(c.tmp) < max {
max = len(c.tmp)
2017-08-04 11:19:12 +00:00
}
if c.selected >= max {
c.Reset()
} else if c.selected < -1 {
c.selected = max - 1
}
}
2017-08-12 09:55:36 +00:00
func formatTexts(o []string, max int, prefix, suffix string) (new []string, width int) {
l := len(o)
n := make([]string, l)
lenPrefix := len([]rune(prefix))
lenSuffix := len([]rune(suffix))
lenShorten := len(shortenSuffix)
min := lenPrefix + lenSuffix + lenShorten
for i := 0; i < l; i++ {
if width < len([]rune(o[i])) {
width = len([]rune(o[i]))
}
}
if width == 0 {
return n, 0
}
if min >= max {
log.Println("[WARN] formatTexts: max is lower than length of prefix and suffix.")
return n, 0
}
2017-08-14 16:49:53 +00:00
if lenPrefix+width+lenSuffix > max {
2017-08-12 09:55:36 +00:00
width = max - lenPrefix - lenSuffix
}
for i := 0; i < l; i++ {
r := []rune(o[i])
x := len(r)
if x <= width {
spaces := strings.Repeat(" ", width-x)
n[i] = prefix + o[i] + spaces + suffix
} else if x > width {
2017-08-14 16:49:53 +00:00
n[i] = prefix + string(r[:width-lenShorten]) + shortenSuffix + suffix
2017-08-12 09:55:36 +00:00
}
}
return n, lenPrefix + width + lenSuffix
}
2017-08-12 09:59:10 +00:00
func formatSuggestions(suggests []Suggest, max int) (new []Suggest, width int) {
num := len(suggests)
2017-08-09 12:33:47 +00:00
new = make([]Suggest, num)
2017-08-12 09:55:36 +00:00
left := make([]string, num)
2017-08-09 12:33:47 +00:00
for i := 0; i < num; i++ {
2017-08-12 09:59:10 +00:00
left[i] = suggests[i].Text
2017-08-09 12:33:47 +00:00
}
2017-08-12 09:55:36 +00:00
right := make([]string, num)
for i := 0; i < num; i++ {
2017-08-12 09:59:10 +00:00
right[i] = suggests[i].Description
2017-08-09 12:33:47 +00:00
}
2017-08-12 09:55:36 +00:00
left, leftWidth := formatTexts(left, max, leftPrefix, leftSuffix)
if leftWidth == 0 {
return []Suggest{}, 0
2017-08-09 12:33:47 +00:00
}
2017-08-14 16:49:53 +00:00
right, rightWidth := formatTexts(right, max-leftWidth, rightPrefix, rightSuffix)
2017-08-09 12:33:47 +00:00
for i := 0; i < num; i++ {
2017-08-12 09:55:36 +00:00
new[i] = Suggest{Text: left[i], Description: right[i]}
2017-08-09 12:33:47 +00:00
}
2017-08-12 09:55:36 +00:00
return new, leftWidth + rightWidth
2017-08-09 12:33:47 +00:00
}
func NewCompletionManager(completer Completer, max uint16) *CompletionManager {
2017-08-04 11:19:12 +00:00
return &CompletionManager{
2017-08-09 12:33:47 +00:00
selected: -1,
2017-08-12 09:59:10 +00:00
max: max,
2017-08-09 12:33:47 +00:00
completer: completer,
2017-08-04 11:19:12 +00:00
}
}