feat: implement pagination

This commit is contained in:
Nao YONASHIRO 2018-02-12 17:40:47 +09:00
parent 95fb1dd6f4
commit 63302a5036
3 changed files with 52 additions and 12 deletions

@ -28,6 +28,8 @@ type CompletionManager struct {
tmp []Suggest tmp []Suggest
max uint16 max uint16
completer Completer completer Completer
verticalScroll int
} }
// GetSelectedSuggestion returns the selected item. // GetSelectedSuggestion returns the selected item.
@ -50,6 +52,7 @@ func (c *CompletionManager) GetSuggestions() []Suggest {
// Reset to select nothing. // Reset to select nothing.
func (c *CompletionManager) Reset() { func (c *CompletionManager) Reset() {
c.selected = -1 c.selected = -1
c.verticalScroll = 0
c.Update(*NewDocument()) c.Update(*NewDocument())
return return
} }
@ -62,6 +65,9 @@ func (c *CompletionManager) Update(in Document) {
// Previous to select the previous suggestion item. // Previous to select the previous suggestion item.
func (c *CompletionManager) Previous() { func (c *CompletionManager) Previous() {
if c.verticalScroll == c.selected && c.selected > 0 {
c.verticalScroll--
}
c.selected-- c.selected--
c.update() c.update()
return return
@ -69,6 +75,9 @@ func (c *CompletionManager) Previous() {
// Next to select the next suggestion item. // Next to select the next suggestion item.
func (c *CompletionManager) Next() { func (c *CompletionManager) Next() {
if c.verticalScroll+int(c.max)-1 == c.selected {
c.verticalScroll++
}
c.selected++ c.selected++
c.update() c.update()
return return
@ -84,10 +93,12 @@ func (c *CompletionManager) update() {
if len(c.tmp) < max { if len(c.tmp) < max {
max = len(c.tmp) max = len(c.tmp)
} }
if c.selected >= max {
if c.selected >= len(c.tmp) {
c.Reset() c.Reset()
} else if c.selected < -1 { } else if c.selected < -1 {
c.selected = max - 1 c.selected = len(c.tmp) - 1
c.verticalScroll = len(c.tmp) - max
} }
} }
@ -160,5 +171,7 @@ func NewCompletionManager(completer Completer, max uint16) *CompletionManager {
selected: -1, selected: -1,
max: max, max: max,
completer: completer, completer: completer,
verticalScroll: 0,
} }
} }

@ -194,6 +194,8 @@ func New(executor Executor, completer Completer, opts ...Option) *Prompt {
descriptionBGColor: Turquoise, descriptionBGColor: Turquoise,
selectedDescriptionTextColor: White, selectedDescriptionTextColor: White,
selectedDescriptionBGColor: Cyan, selectedDescriptionBGColor: Cyan,
scrollbarThumbColor: DarkGray,
scrollbarBGColor: Cyan,
}, },
buf: NewBuffer(), buf: NewBuffer(),
executor: executor, executor: executor,

@ -1,5 +1,9 @@
package prompt package prompt
import (
"math"
)
// Render to render prompt information from state of Buffer. // Render to render prompt information from state of Buffer.
type Render struct { type Render struct {
out ConsoleWriter out ConsoleWriter
@ -22,6 +26,8 @@ type Render struct {
descriptionBGColor Color descriptionBGColor Color
selectedDescriptionTextColor Color selectedDescriptionTextColor Color
selectedDescriptionBGColor Color selectedDescriptionBGColor Color
scrollbarThumbColor Color
scrollbarBGColor Color
} }
// Setup to initialize console output. // Setup to initialize console output.
@ -72,24 +78,34 @@ func (r *Render) renderWindowTooSmall() {
} }
func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) { func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) {
max := completions.max windowHeight := len(completions.tmp)
if max > r.row { if windowHeight > int(completions.max) {
max = r.row windowHeight = int(completions.max)
}
contentHeight := len(completions.tmp)
fractionVisible := float64(windowHeight) / float64(contentHeight)
fractionAbove := float64(completions.verticalScroll) / float64(contentHeight)
scrollbarHeight := int(math.Min(float64(windowHeight), math.Max(1, float64(windowHeight)*fractionVisible)))
scrollbarTop := int(float64(windowHeight) * fractionAbove)
isScrollThumb := func(row int) bool {
return scrollbarTop <= row && row <= scrollbarTop+scrollbarHeight
} }
suggestions := completions.GetSuggestions() suggestions := completions.GetSuggestions()
if l := len(completions.GetSuggestions()); l == 0 { if l := len(completions.GetSuggestions()); l == 0 {
return return
} else if l > int(max) {
suggestions = suggestions[:max]
} }
formatted, width := formatSuggestions( formatted, width := formatSuggestions(
suggestions, suggestions,
int(r.col)-len(r.prefix), int(r.col)-len(r.prefix)-1,
) )
formatted = formatted[completions.verticalScroll : completions.verticalScroll+windowHeight]
l := len(formatted) l := len(formatted)
r.prepareArea(l) r.prepareArea(windowHeight)
d := (len(r.prefix) + len(buf.Document().TextBeforeCursor())) % int(r.col) d := (len(r.prefix) + len(buf.Document().TextBeforeCursor())) % int(r.col)
if d == 0 { // the cursor is on right end. if d == 0 { // the cursor is on right end.
@ -98,23 +114,32 @@ func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) {
r.out.CursorBackward(d + width - int(r.col)) r.out.CursorBackward(d + width - int(r.col))
} }
selected := completions.selected - completions.verticalScroll
r.out.SetColor(White, Cyan, false) r.out.SetColor(White, Cyan, false)
for i := 0; i < l; i++ { for i := 0; i < l; i++ {
r.out.CursorDown(1) r.out.CursorDown(1)
if i == completions.selected { if i == selected {
r.out.SetColor(r.selectedSuggestionTextColor, r.selectedSuggestionBGColor, true) r.out.SetColor(r.selectedSuggestionTextColor, r.selectedSuggestionBGColor, true)
} else { } else {
r.out.SetColor(r.suggestionTextColor, r.suggestionBGColor, false) r.out.SetColor(r.suggestionTextColor, r.suggestionBGColor, false)
} }
r.out.WriteStr(formatted[i].Text) r.out.WriteStr(formatted[i].Text)
if i == completions.selected { if i == selected {
r.out.SetColor(r.selectedDescriptionTextColor, r.selectedDescriptionBGColor, false) r.out.SetColor(r.selectedDescriptionTextColor, r.selectedDescriptionBGColor, false)
} else { } else {
r.out.SetColor(r.descriptionTextColor, r.descriptionBGColor, false) r.out.SetColor(r.descriptionTextColor, r.descriptionBGColor, false)
} }
r.out.WriteStr(formatted[i].Description) r.out.WriteStr(formatted[i].Description)
r.out.CursorBackward(width)
if isScrollThumb(i) {
r.out.SetColor(DefaultColor, r.scrollbarThumbColor, false)
} else {
r.out.SetColor(DefaultColor, r.scrollbarBGColor, false)
}
r.out.WriteStr(" ")
r.out.CursorBackward(width + 1)
} }
if d == 0 { // the cursor is on right end. if d == 0 { // the cursor is on right end.
// DON'T CURSOR DOWN HERE. Because the line doesn't erase properly. // DON'T CURSOR DOWN HERE. Because the line doesn't erase properly.