feat: implement pagination
This commit is contained in:
parent
95fb1dd6f4
commit
63302a5036
@ -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,
|
||||||
|
45
render.go
45
render.go
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user