go-prompt/completion.go
2017-08-09 21:33:47 +09:00

136 lines
3.1 KiB
Go

package prompt
import (
"log"
"strings"
)
type Suggest struct {
Text string
Description string
}
type CompletionManager struct {
selected int // -1 means nothing one is selected.
tmp []Suggest
Max uint16
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)
return Suggest{}, false
}
return c.tmp[c.selected], true
}
func (c *CompletionManager) GetSuggestions() []Suggest {
return c.tmp
}
func (c *CompletionManager) Reset() {
c.selected = -1
c.Update("")
return
}
func (c *CompletionManager) Update(in string) {
c.tmp = c.completer(in)
return
}
func (c *CompletionManager) Previous() {
c.selected--
c.update()
return
}
func (c *CompletionManager) Next() {
c.selected++
c.update()
return
}
func (c *CompletionManager) Completing() bool {
return c.selected != -1
}
func (c *CompletionManager) update() {
max := int(c.Max)
if len(c.tmp) < max {
max = len(c.tmp)
}
if c.selected >= max {
c.Reset()
} else if c.selected < -1 {
c.selected = max - 1
}
}
func formatCompletions(completions []Suggest, max int) (new []Suggest, width int) {
num := len(completions)
new = make([]Suggest, num)
leftWidth := 0
rightWidth := 0
for i := 0; i < num; i++ {
if leftWidth < len([]rune(completions[i].Text)) {
leftWidth = len([]rune(completions[i].Text))
}
if rightWidth < len([]rune(completions[i].Description)) {
rightWidth = len([]rune(completions[i].Description))
}
}
if diff := max - completionMargin - leftWidth - rightWidth; diff < 0 {
if rightWidth > diff {
rightWidth += diff
} else if rightWidth+rightMargin > -diff {
leftWidth += rightWidth + rightMargin + diff
rightWidth = 0
}
}
if rightWidth == 0 {
width = leftWidth + leftMargin
} else {
width = leftWidth + leftMargin + rightWidth + rightMargin
}
for i := 0; i < num; i++ {
var newText string
var newDescription string
if l := len(completions[i].Text); l > leftWidth {
newText = leftPrefix + completions[i].Text[:leftWidth-len("...")] + "..." + leftSuffix
} else if l < width {
spaces := strings.Repeat(" ", leftWidth-len([]rune(completions[i].Text)))
newText = leftPrefix + completions[i].Text + spaces + leftSuffix
} else {
newText = leftPrefix + completions[i].Text + leftSuffix
}
if rightWidth == 0 {
newDescription = ""
} else if l := len(completions[i].Description); l > rightWidth {
newDescription = rightPrefix + completions[i].Description[:rightWidth-len("...")] + "..." + rightSuffix
} else if l < width {
spaces := strings.Repeat(" ", rightWidth-len([]rune(completions[i].Description)))
newDescription = rightPrefix + completions[i].Description + spaces + rightSuffix
} else {
newDescription = rightPrefix + completions[i].Description + rightSuffix
}
new[i] = Suggest{Text: newText, Description: newDescription}
}
return
}
func NewCompletionManager(completer Completer, max uint16) *CompletionManager {
return &CompletionManager{
selected: -1,
Max: max,
completer: completer,
}
}