Update Prompt type form string to fmt.Stringer.

On branch master
 Your branch is up to date with 'origin/master'.

 Changes to be committed:
	modified:   example/readline-demo/readline-demo.go
	modified:   example/readline-im/readline-im.go
	modified:   example/readline-multiline/readline-multiline.go
	modified:   example/readline-pass-strength/readline-pass-strength.go
	modified:   example/readline-remote/readline-remote-server/server.go
	modified:   operation.go
	new file:   prompt.go
	modified:   readline.go
	modified:   runebuf.go
	modified:   std.go
This commit is contained in:
luopengift 2018-10-13 23:42:23 +08:00
parent 2972be24d4
commit ee7dbdffca
10 changed files with 53 additions and 32 deletions

View File

@ -72,7 +72,7 @@ func filterInput(r rune) (rune, bool) {
func main() { func main() {
l, err := readline.NewEx(&readline.Config{ l, err := readline.NewEx(&readline.Config{
Prompt: "\033[31m»\033[0m ", Prompt: readline.StaticPrompt("\033[31m»\033[0m "),
HistoryFile: "/tmp/readline.tmp", HistoryFile: "/tmp/readline.tmp",
AutoComplete: completer, AutoComplete: completer,
InterruptPrompt: "^C", InterruptPrompt: "^C",
@ -88,7 +88,7 @@ func main() {
setPasswordCfg := l.GenPasswordConfig() setPasswordCfg := l.GenPasswordConfig()
setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) { setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
l.SetPrompt(fmt.Sprintf("Enter password(%v): ", len(line))) l.SetPrompt(readline.StaticPrompt(fmt.Sprintf("Enter password(%v): ", len(line))))
l.Refresh() l.Refresh()
return nil, 0, false return nil, 0, false
}) })
@ -124,7 +124,7 @@ func main() {
println("current mode: emacs") println("current mode: emacs")
} }
case line == "login": case line == "login":
pswd, err := l.ReadPassword("please enter your password: ") pswd, err := l.ReadPassword(readline.StaticPrompt("please enter your password: "))
if err != nil { if err != nil {
break break
} }
@ -141,7 +141,7 @@ func main() {
log.Println("setprompt <prompt>") log.Println("setprompt <prompt>")
break break
} }
l.SetPrompt(line[10:]) l.SetPrompt(readline.StaticPrompt(line[10:]))
case strings.HasPrefix(line, "say"): case strings.HasPrefix(line, "say"):
line := strings.TrimSpace(line[3:]) line := strings.TrimSpace(line[3:])
if len(line) == 0 { if len(line) == 0 {

View File

@ -18,7 +18,7 @@ func main() {
} }
defer rl.Close() defer rl.Close()
rl.SetPrompt("username: ") rl.SetPrompt(readline.StaticPrompt("username: "))
username, err := rl.Readline() username, err := rl.Readline()
if err != nil { if err != nil {
return return
@ -27,7 +27,7 @@ func main() {
log.SetOutput(rl.Stderr()) log.SetOutput(rl.Stderr())
fmt.Fprintln(rl, "Hi,", username+"! My name is Dave.") fmt.Fprintln(rl, "Hi,", username+"! My name is Dave.")
rl.SetPrompt(username + "> ") rl.SetPrompt(readline.StaticPrompt(username + "> "))
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {

View File

@ -8,7 +8,7 @@ import (
func main() { func main() {
rl, err := readline.NewEx(&readline.Config{ rl, err := readline.NewEx(&readline.Config{
Prompt: "> ", Prompt: readline.StaticPrompt("> "),
HistoryFile: "/tmp/readline-multiline", HistoryFile: "/tmp/readline-multiline",
DisableAutoSaveHistory: true, DisableAutoSaveHistory: true,
}) })
@ -29,12 +29,12 @@ func main() {
} }
cmds = append(cmds, line) cmds = append(cmds, line)
if !strings.HasSuffix(line, ";") { if !strings.HasSuffix(line, ";") {
rl.SetPrompt(">>> ") rl.SetPrompt(readline.StaticPrompt(">>> "))
continue continue
} }
cmd := strings.Join(cmds, " ") cmd := strings.Join(cmds, " ")
cmds = cmds[:0] cmds = cmds[:0]
rl.SetPrompt("> ") rl.SetPrompt(readline.StaticPrompt("> "))
rl.SaveHistory(cmd) rl.SaveHistory(cmd)
println(cmd) println(cmd)
} }

View File

@ -80,7 +80,7 @@ func createStrengthPrompt(password []rune) string {
} }
func main() { func main() {
rl, err := readline.New("") rl, err := readline.New(readline.StaticPrompt(""))
if err != nil { if err != nil {
return return
} }
@ -88,7 +88,7 @@ func main() {
setPasswordCfg := rl.GenPasswordConfig() setPasswordCfg := rl.GenPasswordConfig()
setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) { setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
rl.SetPrompt(createStrengthPrompt(line)) rl.SetPrompt(readline.StaticPrompt(createStrengthPrompt(line)))
rl.Refresh() rl.Refresh()
return nil, 0, false return nil, 0, false
}) })

View File

@ -8,7 +8,7 @@ import (
func main() { func main() {
cfg := &readline.Config{ cfg := &readline.Config{
Prompt: "readline-remote: ", Prompt: readline.StaticPrompt("readline-remote: "),
} }
handleFunc := func(rl *readline.Instance) { handleFunc := func(rl *readline.Instance) {
for { for {

View File

@ -2,6 +2,7 @@ package readline
import ( import (
"errors" "errors"
"fmt"
"io" "io"
"sync" "sync"
) )
@ -89,7 +90,7 @@ func NewOperation(t *Terminal, cfg *Config) *Operation {
return op return op
} }
func (o *Operation) SetPrompt(s string) { func (o *Operation) SetPrompt(s fmt.Stringer) {
o.buf.SetPrompt(s) o.buf.SetPrompt(s)
} }
@ -398,7 +399,7 @@ func (o *Operation) Runes() ([]rune, error) {
} }
} }
func (o *Operation) PasswordEx(prompt string, l Listener) ([]byte, error) { func (o *Operation) PasswordEx(prompt fmt.Stringer, l Listener) ([]byte, error) {
cfg := o.GenPasswordConfig() cfg := o.GenPasswordConfig()
cfg.Prompt = prompt cfg.Prompt = prompt
cfg.Listener = l cfg.Listener = l
@ -417,7 +418,7 @@ func (o *Operation) PasswordWithConfig(cfg *Config) ([]byte, error) {
return o.Slice() return o.Slice()
} }
func (o *Operation) Password(prompt string) ([]byte, error) { func (o *Operation) Password(prompt fmt.Stringer) ([]byte, error) {
return o.PasswordEx(prompt, nil) return o.PasswordEx(prompt, nil)
} }

11
prompt.go Normal file
View File

@ -0,0 +1,11 @@
package readline
type StaticPrompt string
func (s StaticPrompt) String() string {
return string(s)
}
func NewStaticPrompt(s string) StaticPrompt {
return StaticPrompt(s)
}

View File

@ -17,7 +17,10 @@
// //
package readline package readline
import "io" import (
"fmt"
"io"
)
type Instance struct { type Instance struct {
Config *Config Config *Config
@ -27,7 +30,7 @@ type Instance struct {
type Config struct { type Config struct {
// prompt supports ANSI escape sequence, so we can color some characters even in windows // prompt supports ANSI escape sequence, so we can color some characters even in windows
Prompt string Prompt fmt.Stringer
// readline will persist historys to file where HistoryFile specified // readline will persist historys to file where HistoryFile specified
HistoryFile string HistoryFile string
@ -175,7 +178,11 @@ func NewEx(cfg *Config) (*Instance, error) {
}, nil }, nil
} }
func New(prompt string) (*Instance, error) { type Prompter interface {
String() string
}
func New(prompt fmt.Stringer) (*Instance, error) {
return NewEx(&Config{Prompt: prompt}) return NewEx(&Config{Prompt: prompt})
} }
@ -183,7 +190,7 @@ func (i *Instance) ResetHistory() {
i.Operation.ResetHistory() i.Operation.ResetHistory()
} }
func (i *Instance) SetPrompt(s string) { func (i *Instance) SetPrompt(s fmt.Stringer) {
i.Operation.SetPrompt(s) i.Operation.SetPrompt(s)
} }
@ -224,11 +231,11 @@ func (i *Instance) ReadPasswordWithConfig(cfg *Config) ([]byte, error) {
return i.Operation.PasswordWithConfig(cfg) return i.Operation.PasswordWithConfig(cfg)
} }
func (i *Instance) ReadPasswordEx(prompt string, l Listener) ([]byte, error) { func (i *Instance) ReadPasswordEx(prompt fmt.Stringer, l Listener) ([]byte, error) {
return i.Operation.PasswordEx(prompt, l) return i.Operation.PasswordEx(prompt, l)
} }
func (i *Instance) ReadPassword(prompt string) ([]byte, error) { func (i *Instance) ReadPassword(prompt fmt.Stringer) ([]byte, error) {
return i.Operation.Password(prompt) return i.Operation.Password(prompt)
} }

View File

@ -3,6 +3,7 @@ package readline
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"fmt"
"io" "io"
"strconv" "strconv"
"strings" "strings"
@ -17,7 +18,7 @@ type runeBufferBck struct {
type RuneBuffer struct { type RuneBuffer struct {
buf []rune buf []rune
idx int idx int
prompt []rune prompt fmt.Stringer
w io.Writer w io.Writer
hadClean bool hadClean bool
@ -35,7 +36,7 @@ type RuneBuffer struct {
sync.Mutex sync.Mutex
} }
func (r* RuneBuffer) pushKill(text []rune) { func (r *RuneBuffer) pushKill(text []rune) {
r.lastKill = append([]rune{}, text...) r.lastKill = append([]rune{}, text...)
} }
@ -61,7 +62,7 @@ func (r *RuneBuffer) Restore() {
}) })
} }
func NewRuneBuffer(w io.Writer, prompt string, cfg *Config, width int) *RuneBuffer { func NewRuneBuffer(w io.Writer, prompt fmt.Stringer, cfg *Config, width int) *RuneBuffer {
rb := &RuneBuffer{ rb := &RuneBuffer{
w: w, w: w,
interactive: cfg.useInteractive(), interactive: cfg.useInteractive(),
@ -99,7 +100,7 @@ func (r *RuneBuffer) PromptLen() int {
} }
func (r *RuneBuffer) promptLen() int { func (r *RuneBuffer) promptLen() int {
return runes.WidthAll(runes.ColorFilter(r.prompt)) return runes.WidthAll(runes.ColorFilter([]rune(r.prompt.String())))
} }
func (r *RuneBuffer) RuneSlice(i int) []rune { func (r *RuneBuffer) RuneSlice(i int) []rune {
@ -221,7 +222,7 @@ func (r *RuneBuffer) DeleteWord() {
} }
for i := init + 1; i < len(r.buf); i++ { for i := init + 1; i < len(r.buf); i++ {
if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) { if !IsWordBreak(r.buf[i]) && IsWordBreak(r.buf[i-1]) {
r.pushKill(r.buf[r.idx:i-1]) r.pushKill(r.buf[r.idx : i-1])
r.Refresh(func() { r.Refresh(func() {
r.buf = append(r.buf[:r.idx], r.buf[i-1:]...) r.buf = append(r.buf[:r.idx], r.buf[i-1:]...)
}) })
@ -350,7 +351,7 @@ func (r *RuneBuffer) Yank() {
return return
} }
r.Refresh(func() { r.Refresh(func() {
buf := make([]rune, 0, len(r.buf) + len(r.lastKill)) buf := make([]rune, 0, len(r.buf)+len(r.lastKill))
buf = append(buf, r.buf[:r.idx]...) buf = append(buf, r.buf[:r.idx]...)
buf = append(buf, r.lastKill...) buf = append(buf, r.lastKill...)
buf = append(buf, r.buf[r.idx:]...) buf = append(buf, r.buf[r.idx:]...)
@ -478,7 +479,7 @@ func (r *RuneBuffer) print() {
func (r *RuneBuffer) output() []byte { func (r *RuneBuffer) output() []byte {
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
buf.WriteString(string(r.prompt)) buf.WriteString(r.prompt.String())
if r.cfg.EnableMask && len(r.buf) > 0 { if r.cfg.EnableMask && len(r.buf) > 0 {
buf.Write([]byte(strings.Repeat(string(r.cfg.MaskRune), len(r.buf)-1))) buf.Write([]byte(strings.Repeat(string(r.cfg.MaskRune), len(r.buf)-1)))
if r.buf[len(r.buf)-1] == '\n' { if r.buf[len(r.buf)-1] == '\n' {
@ -582,9 +583,9 @@ func (r *RuneBuffer) Set(buf []rune) {
r.SetWithIdx(len(buf), buf) r.SetWithIdx(len(buf), buf)
} }
func (r *RuneBuffer) SetPrompt(prompt string) { func (r *RuneBuffer) SetPrompt(prompt fmt.Stringer) {
r.Lock() r.Lock()
r.prompt = []rune(prompt) r.prompt = prompt //[]rune(prompt)
r.Unlock() r.Unlock()
} }

5
std.go
View File

@ -1,6 +1,7 @@
package readline package readline
import ( import (
"fmt"
"io" "io"
"os" "os"
"sync" "sync"
@ -54,13 +55,13 @@ func AddHistory(content string) error {
return ins.SaveHistory(content) return ins.SaveHistory(content)
} }
func Password(prompt string) ([]byte, error) { func Password(prompt fmt.Stringer) ([]byte, error) {
ins := getInstance() ins := getInstance()
return ins.ReadPassword(prompt) return ins.ReadPassword(prompt)
} }
// readline with global configs // readline with global configs
func Line(prompt string) (string, error) { func Line(prompt fmt.Stringer) (string, error) {
ins := getInstance() ins := getInstance()
ins.SetPrompt(prompt) ins.SetPrompt(prompt)
return ins.Readline() return ins.Readline()