mirror of https://github.com/chzyer/readline.git
[example] Add a IM example
This commit is contained in:
parent
91ba4d48f0
commit
218eb7fff6
|
@ -26,6 +26,10 @@ Also works fine in windows
|
|||
|
||||
* [example/readline-demo](https://github.com/chzyer/readline/blob/master/example/readline-demo/readline-demo.go) The source code about the demo above
|
||||
|
||||
* [example/readline-im](https://github.com/chzyer/readline/blob/master/example/readline-im/readline-im.go) Example for how to write a IM program.
|
||||
|
||||
* [example/readline-multiline](https://github.com/chzyer/readline/blob/master/example/readline-multiline/readline-multiline.go) Example for how to parse command which can submit by multiple time.
|
||||
|
||||
* [example/readline-pass-strength](https://github.com/chzyer/readline/blob/master/example/readline-pass-strength/readline-pass-strength.go) A example about checking password strength, written by [@sahib](https://github.com/sahib)
|
||||
|
||||
# Todo
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/chzyer/readline"
|
||||
)
|
||||
import "log"
|
||||
|
||||
func main() {
|
||||
rl, err := readline.NewEx(&readline.Config{
|
||||
UniqueEditLine: true,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer rl.Close()
|
||||
|
||||
rl.SetPrompt("username: ")
|
||||
username, err := rl.Readline()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rl.ResetHistory()
|
||||
log.SetOutput(rl.Stderr())
|
||||
|
||||
fmt.Fprintln(rl, "Hi,", username+"! My name is Dave.")
|
||||
rl.SetPrompt(username + "> ")
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Duration(rand.Intn(20)) * 100 * time.Millisecond):
|
||||
case <-done:
|
||||
break loop
|
||||
}
|
||||
log.Println("Dave:", "hello")
|
||||
}
|
||||
log.Println("Dave:", "bye")
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
for {
|
||||
ln := rl.Line()
|
||||
if ln.CanContinue() {
|
||||
continue
|
||||
} else if ln.CanBreak() {
|
||||
break
|
||||
}
|
||||
log.Println(username+":", ln.Line)
|
||||
}
|
||||
rl.Clean()
|
||||
done <- struct{}{}
|
||||
<-done
|
||||
}
|
|
@ -37,6 +37,11 @@ func newOpHistory(cfg *Config) (o *opHistory) {
|
|||
return o
|
||||
}
|
||||
|
||||
func (o *opHistory) Reset() {
|
||||
o.history = list.New()
|
||||
o.current = nil
|
||||
}
|
||||
|
||||
func (o *opHistory) IsHistoryClosed() bool {
|
||||
return o.fd.Fd() == ^(uintptr(0))
|
||||
}
|
||||
|
|
23
operation.go
23
operation.go
|
@ -237,11 +237,16 @@ func (o *Operation) ioloop() {
|
|||
}
|
||||
|
||||
// treat as EOF
|
||||
o.buf.WriteString(o.cfg.EOFPrompt + "\n")
|
||||
if !o.cfg.UniqueEditLine {
|
||||
o.buf.WriteString(o.cfg.EOFPrompt + "\n")
|
||||
}
|
||||
o.buf.Reset()
|
||||
isUpdateHistory = false
|
||||
o.history.Revert()
|
||||
o.errchan <- io.EOF
|
||||
if o.cfg.UniqueEditLine {
|
||||
o.buf.Clean()
|
||||
}
|
||||
case CharInterrupt:
|
||||
if o.IsSearchMode() {
|
||||
o.t.KickRead()
|
||||
|
@ -257,9 +262,13 @@ func (o *Operation) ioloop() {
|
|||
o.buf.MoveToLineEnd()
|
||||
o.buf.Refresh(nil)
|
||||
hint := o.cfg.InterruptPrompt + "\n"
|
||||
o.buf.WriteString(hint)
|
||||
if !o.cfg.UniqueEditLine {
|
||||
o.buf.WriteString(hint)
|
||||
}
|
||||
remain := o.buf.Reset()
|
||||
remain = remain[:len(remain)-len([]rune(hint))]
|
||||
if !o.cfg.UniqueEditLine {
|
||||
remain = remain[:len(remain)-len([]rune(hint))]
|
||||
}
|
||||
isUpdateHistory = false
|
||||
o.history.Revert()
|
||||
o.errchan <- &InterruptError{remain}
|
||||
|
@ -419,6 +428,10 @@ func (op *Operation) SetConfig(cfg *Config) (*Config, error) {
|
|||
return old, nil
|
||||
}
|
||||
|
||||
func (o *Operation) ResetHistory() {
|
||||
o.history.Reset()
|
||||
}
|
||||
|
||||
// if err is not nil, it just mean it fail to write to file
|
||||
// other things goes fine.
|
||||
func (o *Operation) SaveHistory(content string) error {
|
||||
|
@ -431,6 +444,10 @@ func (o *Operation) Refresh() {
|
|||
}
|
||||
}
|
||||
|
||||
func (o *Operation) Clean() {
|
||||
o.buf.Clean()
|
||||
}
|
||||
|
||||
func FuncListener(f func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)) Listener {
|
||||
return &DumpListener{f: f}
|
||||
}
|
||||
|
|
25
readline.go
25
readline.go
|
@ -140,6 +140,10 @@ func New(prompt string) (*Instance, error) {
|
|||
return NewEx(&Config{Prompt: prompt})
|
||||
}
|
||||
|
||||
func (i *Instance) ResetHistory() {
|
||||
i.Operation.ResetHistory()
|
||||
}
|
||||
|
||||
func (i *Instance) SetPrompt(s string) {
|
||||
i.Operation.SetPrompt(s)
|
||||
}
|
||||
|
@ -189,6 +193,24 @@ func (i *Instance) ReadPassword(prompt string) ([]byte, error) {
|
|||
return i.Operation.Password(prompt)
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Line string
|
||||
Error error
|
||||
}
|
||||
|
||||
func (l *Result) CanContinue() bool {
|
||||
return len(l.Line) != 0 && l.Error == ErrInterrupt
|
||||
}
|
||||
|
||||
func (l *Result) CanBreak() bool {
|
||||
return !l.CanContinue() && l.Error != nil
|
||||
}
|
||||
|
||||
func (i *Instance) Line() *Result {
|
||||
ret, err := i.Readline()
|
||||
return &Result{ret, err}
|
||||
}
|
||||
|
||||
// err is one of (nil, io.EOF, readline.ErrInterrupt)
|
||||
func (i *Instance) Readline() (string, error) {
|
||||
return i.Operation.String()
|
||||
|
@ -211,6 +233,9 @@ func (i *Instance) Close() error {
|
|||
i.Operation.Close()
|
||||
return nil
|
||||
}
|
||||
func (i *Instance) Clean() {
|
||||
i.Operation.Clean()
|
||||
}
|
||||
|
||||
func (i *Instance) Write(b []byte) (int, error) {
|
||||
return i.Stdout().Write(b)
|
||||
|
|
12
runebuf.go
12
runebuf.go
|
@ -20,9 +20,9 @@ type RuneBuffer struct {
|
|||
prompt []rune
|
||||
w io.Writer
|
||||
|
||||
cleanInScreen bool
|
||||
interactive bool
|
||||
cfg *Config
|
||||
hadClean bool
|
||||
interactive bool
|
||||
cfg *Config
|
||||
|
||||
width int
|
||||
|
||||
|
@ -374,7 +374,7 @@ func (r *RuneBuffer) Refresh(f func()) {
|
|||
|
||||
func (r *RuneBuffer) print() {
|
||||
r.w.Write(r.output())
|
||||
r.cleanInScreen = false
|
||||
r.hadClean = false
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) output() []byte {
|
||||
|
@ -472,9 +472,9 @@ func (r *RuneBuffer) Clean() {
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) clean(idxLine int) {
|
||||
if r.cleanInScreen || !r.interactive {
|
||||
if r.hadClean || !r.interactive {
|
||||
return
|
||||
}
|
||||
r.cleanInScreen = true
|
||||
r.hadClean = true
|
||||
r.cleanOutput(r.w, idxLine)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue