Support updating the prefix dynamiacally (#30)
* Make possible to change the prefix dynamically * Add an example for using live-prefix * Apply live-prefix if it's enabled * Fix: rendering issue happened when the prefix is empty string Close #27 * Fix the title of propmt * Remove an excessive blank line * Refactor: Call `*Render.getCurrentPrefix()` in renderPrefix()
This commit is contained in:
parent
dda4d96c46
commit
e15ebadefe
|
@ -0,0 +1,48 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/c-bata/go-prompt"
|
||||
)
|
||||
|
||||
var LivePrefixState struct {
|
||||
LivePrefix string
|
||||
IsEnable bool
|
||||
}
|
||||
|
||||
func executor(in string) {
|
||||
fmt.Println("Your input: " + in)
|
||||
if in == "" {
|
||||
LivePrefixState.IsEnable = false
|
||||
LivePrefixState.LivePrefix = in
|
||||
return
|
||||
}
|
||||
LivePrefixState.LivePrefix = in + "> "
|
||||
LivePrefixState.IsEnable = true
|
||||
}
|
||||
|
||||
func completer(in prompt.Document) []prompt.Suggest {
|
||||
s := []prompt.Suggest{
|
||||
{Text: "users", Description: "Store the username and age"},
|
||||
{Text: "articles", Description: "Store the article text posted by user"},
|
||||
{Text: "comments", Description: "Store the text commented to articles"},
|
||||
{Text: "groups", Description: "Combine users with specific rules"},
|
||||
}
|
||||
return prompt.FilterHasPrefix(s, in.GetWordBeforeCursor(), true)
|
||||
}
|
||||
|
||||
func changeLivePrefix() (string, bool) {
|
||||
return LivePrefixState.LivePrefix , LivePrefixState.IsEnable
|
||||
}
|
||||
|
||||
func main() {
|
||||
p := prompt.New(
|
||||
executor,
|
||||
completer,
|
||||
prompt.OptionPrefix(">>> "),
|
||||
prompt.OptionLivePrefix(changeLivePrefix),
|
||||
prompt.OptionTitle("live-prefix-example"),
|
||||
)
|
||||
p.Run()
|
||||
}
|
|
@ -36,6 +36,14 @@ func OptionPrefix(x string) Option {
|
|||
}
|
||||
}
|
||||
|
||||
// OptionLivePrefix to change the prefix dynamically by callback function
|
||||
func OptionLivePrefix(f func() (prefix string, useLivePrefix bool)) Option {
|
||||
return func(p *Prompt) error {
|
||||
p.renderer.livePrefixCallback = f
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func OptionPrefixTextColor(x Color) Option {
|
||||
return func(p *Prompt) error {
|
||||
p.renderer.prefixTextColor = x
|
||||
|
@ -178,6 +186,7 @@ func New(executor Executor, completer Completer, opts ...Option) *Prompt {
|
|||
renderer: &Render{
|
||||
prefix: "> ",
|
||||
out: NewStandardOutputWriter(),
|
||||
livePrefixCallback: func() (string, bool) { return "", false },
|
||||
prefixTextColor: Blue,
|
||||
prefixBGColor: DefaultColor,
|
||||
inputTextColor: DefaultColor,
|
||||
|
|
40
render.go
40
render.go
|
@ -6,12 +6,13 @@ import (
|
|||
|
||||
// Render to render prompt information from state of Buffer.
|
||||
type Render struct {
|
||||
out ConsoleWriter
|
||||
prefix string
|
||||
title string
|
||||
row uint16
|
||||
col uint16
|
||||
// colors
|
||||
out ConsoleWriter
|
||||
prefix string
|
||||
livePrefixCallback func() (prefix string, useLivePrefix bool)
|
||||
title string
|
||||
row uint16
|
||||
col uint16
|
||||
// colors,
|
||||
prefixTextColor Color
|
||||
prefixBGColor Color
|
||||
inputTextColor Color
|
||||
|
@ -38,9 +39,18 @@ func (r *Render) Setup() {
|
|||
}
|
||||
}
|
||||
|
||||
// getCurrentPrefix to get current prefix.
|
||||
// If live-prefix is enabled, return live-prefix.
|
||||
func (r *Render) getCurrentPrefix() string {
|
||||
if prefix, ok := r.livePrefixCallback(); ok {
|
||||
return prefix
|
||||
}
|
||||
return r.prefix
|
||||
}
|
||||
|
||||
func (r *Render) renderPrefix() {
|
||||
r.out.SetColor(r.prefixTextColor, r.prefixBGColor, false)
|
||||
r.out.WriteStr(r.prefix)
|
||||
r.out.WriteStr(r.getCurrentPrefix())
|
||||
r.out.SetColor(DefaultColor, DefaultColor, false)
|
||||
}
|
||||
|
||||
|
@ -99,16 +109,17 @@ func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) {
|
|||
return
|
||||
}
|
||||
|
||||
prefix := r.getCurrentPrefix()
|
||||
formatted, width := formatSuggestions(
|
||||
suggestions,
|
||||
int(r.col)-len(r.prefix)-1, // -1 means a width of scrollbar
|
||||
int(r.col)-len(prefix)-1, // -1 means a width of scrollbar
|
||||
)
|
||||
formatted = formatted[completions.verticalScroll : completions.verticalScroll+windowHeight]
|
||||
l := len(formatted)
|
||||
r.prepareArea(windowHeight)
|
||||
|
||||
// +1 means a width of scrollbar.
|
||||
d := (len(r.prefix) + len(buf.Document().TextBeforeCursor()) + 1) % int(r.col)
|
||||
d := (len(prefix) + len(buf.Document().TextBeforeCursor()) + 1) % int(r.col)
|
||||
if d == 0 { // the cursor is on right end.
|
||||
r.out.CursorBackward(width)
|
||||
} else if d+width > int(r.col) {
|
||||
|
@ -143,7 +154,7 @@ func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) {
|
|||
// +1 means a width of scrollbar.
|
||||
r.out.CursorBackward(width + 1)
|
||||
}
|
||||
if d == 0 { // the cursor is on right end.
|
||||
if d == 0 && len(prefix) + len(buf.Text()) != 0 { // the cursor is on right end.
|
||||
// DON'T CURSOR DOWN HERE. Because the line doesn't erase properly.
|
||||
r.out.CursorForward(width + 1)
|
||||
} else if d+width > int(r.col) {
|
||||
|
@ -157,13 +168,15 @@ func (r *Render) renderCompletion(buf *Buffer, completions *CompletionManager) {
|
|||
|
||||
// Render renders to the console.
|
||||
func (r *Render) Render(buffer *Buffer, completion *CompletionManager) {
|
||||
prefix := r.getCurrentPrefix()
|
||||
|
||||
// Erasing
|
||||
r.out.CursorBackward(int(r.col) + len(buffer.Text()) + len(r.prefix))
|
||||
r.out.CursorBackward(int(r.col) + len(buffer.Text()) + len(prefix))
|
||||
r.out.EraseDown()
|
||||
|
||||
// prepare area
|
||||
line := buffer.Text()
|
||||
h := ((len(r.prefix) + len(line)) / int(r.col)) + 1 + int(completion.max)
|
||||
h := ((len(prefix) + len(line)) / int(r.col)) + 1 + int(completion.max)
|
||||
if h > int(r.row) || completionMargin > int(r.col) {
|
||||
r.renderWindowTooSmall()
|
||||
return
|
||||
|
@ -189,7 +202,8 @@ func (r *Render) Render(buffer *Buffer, completion *CompletionManager) {
|
|||
// BreakLine to break line.
|
||||
func (r *Render) BreakLine(buffer *Buffer) {
|
||||
// CR
|
||||
r.out.CursorBackward(int(r.col) + len(buffer.Text()) + len(r.prefix))
|
||||
prefix := r.getCurrentPrefix()
|
||||
r.out.CursorBackward(int(r.col) + len(buffer.Text()) + len(prefix))
|
||||
// Erasing and Render
|
||||
r.out.EraseDown()
|
||||
r.renderPrefix()
|
||||
|
|
Loading…
Reference in New Issue