Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update from upstream #1

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode/*
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<img src="https://raw.githubusercontent.com/chzyer/readline/assets/logo_f.png" />
</p>

A powerful readline library in `Linux` `macOS` `Windows` `Solaris`
A powerful readline library in `Linux` `macOS` `Windows` `Solaris` `AIX`

## Guide

Expand Down
6 changes: 4 additions & 2 deletions complete.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@ func (o *opCompleter) CompleteRefresh() {
// -1 to avoid reach the end of line
width := o.width - 1
colNum := width / colWidth
colWidth += (width - (colWidth * colNum)) / colNum
if colNum != 0 {
colWidth += (width - (colWidth * colNum)) / colNum
}

o.candidateColNum = colNum
buf := bufio.NewWriter(o.w)
Expand All @@ -219,7 +221,7 @@ func (o *opCompleter) CompleteRefresh() {
}
buf.WriteString(string(same))
buf.WriteString(string(c))
buf.Write(bytes.Repeat([]byte(" "), colWidth-len(c)-len(same)))
buf.Write(bytes.Repeat([]byte(" "), colWidth-runes.WidthAll(c)-runes.WidthAll(same)))

if inSelect {
buf.WriteString("\033[0m")
Expand Down
1 change: 1 addition & 0 deletions example/readline-demo/readline-demo.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func main() {
panic(err)
}
defer l.Close()
l.CaptureExitSignal()

setPasswordCfg := l.GenPasswordConfig()
setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
Expand Down
17 changes: 5 additions & 12 deletions example/readline-pass-strength/readline-pass-strength.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"fmt"

"github.com/chzyer/readline"
zxcvbn "github.com/nbutton23/zxcvbn-go"
)

const (
Expand All @@ -50,30 +49,24 @@ func Colorize(msg string, color int) string {

func createStrengthPrompt(password []rune) string {
symbol, color := "", Red
strength := zxcvbn.PasswordStrength(string(password), nil)

switch {
case strength.Score <= 1:
case len(password) <= 1:
symbol = "✗"
color = Red
case strength.Score <= 2:
case len(password) <= 3:
symbol = "⚡"
color = Magenta
case strength.Score <= 3:
case len(password) <= 5:
symbol = "⚠"
color = Yellow
case strength.Score <= 4:
default:
symbol = "✔"
color = Green
}

prompt := Colorize(symbol, color)
if strength.Entropy > 0 {
entropy := fmt.Sprintf(" %3.0f", strength.Entropy)
prompt += Colorize(entropy, Cyan)
} else {
prompt += Colorize(" ENT", Cyan)
}
prompt += Colorize(" ENT", Cyan)

prompt += Colorize(" New Password: ", color)
return prompt
Expand Down
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/chzyer/readline

go 1.15

require (
github.com/chzyer/test v1.0.0
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5
)

require github.com/chzyer/logex v1.2.1
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
8 changes: 7 additions & 1 deletion operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func NewOperation(t *Terminal, cfg *Config) *Operation {
t: t,
buf: NewRuneBuffer(t, cfg.Prompt, cfg, width),
outchan: make(chan []rune),
errchan: make(chan error),
errchan: make(chan error, 1),
}
op.w = op.buf.w
op.SetConfig(cfg)
Expand Down Expand Up @@ -109,10 +109,12 @@ func (o *Operation) ioloop() {
keepInSearchMode := false
keepInCompleteMode := false
r := o.t.ReadRune()

if o.GetConfig().FuncFilterInputRune != nil {
var process bool
r, process = o.GetConfig().FuncFilterInputRune(r)
if !process {
o.t.KickRead()
o.buf.Refresh(nil) // to refresh the line
continue // ignore this rune
}
Expand Down Expand Up @@ -434,6 +436,10 @@ func (o *Operation) Slice() ([]byte, error) {
}

func (o *Operation) Close() {
select {
case o.errchan <- io.EOF:
default:
}
o.history.Close()
}

Expand Down
19 changes: 16 additions & 3 deletions readline.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
//
package readline

import "io"
import (
"io"
)

type Instance struct {
Config *Config
Expand Down Expand Up @@ -54,7 +56,7 @@ type Config struct {

FuncGetWidth func() int

Stdin io.Reader
Stdin io.ReadCloser
StdinWriter io.Writer
Stdout io.Writer
Stderr io.Writer
Expand Down Expand Up @@ -270,13 +272,24 @@ func (i *Instance) ReadSlice() ([]byte, error) {
}

// we must make sure that call Close() before process exit.
// if there has a pending reading operation, that reading will be interrupted.
// so you can capture the signal and call Instance.Close(), it's thread-safe.
func (i *Instance) Close() error {
i.Config.Stdin.Close()
i.Operation.Close()
if err := i.Terminal.Close(); err != nil {
return err
}
i.Operation.Close()
return nil
}

// call CaptureExitSignal when you want readline exit gracefully.
func (i *Instance) CaptureExitSignal() {
CaptureExitSignal(func() {
i.Close()
})
}

func (i *Instance) Clean() {
i.Operation.Clean()
}
Expand Down
3 changes: 2 additions & 1 deletion remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,12 @@ loop:
}
}

func (r *RemoteSvr) Close() {
func (r *RemoteSvr) Close() error {
if atomic.CompareAndSwapInt32(&r.closed, 0, 1) {
close(r.stopChan)
r.conn.Close()
}
return nil
}

func (r *RemoteSvr) readLoop(buf *bufio.Reader) {
Expand Down
6 changes: 3 additions & 3 deletions runebuf.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type RuneBuffer struct {
sync.Mutex
}

func (r* RuneBuffer) pushKill(text []rune) {
func (r *RuneBuffer) pushKill(text []rune) {
r.lastKill = append([]rune{}, text...)
}

Expand Down Expand Up @@ -221,7 +221,7 @@ func (r *RuneBuffer) DeleteWord() {
}
for i := init + 1; i < len(r.buf); i++ {
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.buf = append(r.buf[:r.idx], r.buf[i-1:]...)
})
Expand Down Expand Up @@ -350,7 +350,7 @@ func (r *RuneBuffer) Yank() {
return
}
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.lastKill...)
buf = append(buf, r.buf[r.idx:]...)
Expand Down
19 changes: 13 additions & 6 deletions std.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,22 +137,20 @@ func (c *CancelableStdin) Close() error {
type FillableStdin struct {
sync.Mutex
stdin io.Reader
stdinBuffer io.Reader
stdinBuffer io.ReadCloser
buf []byte
bufErr error
}

// NewFillableStdin gives you FillableStdin
func NewFillableStdin(stdin io.Reader) (io.Reader, io.Writer) {

func NewFillableStdin(stdin io.Reader) (io.ReadCloser, io.Writer) {
r, w := io.Pipe()
s := &FillableStdin{
stdinBuffer: r,
stdin: stdin,
}
s.ioloop()
return s, w

}

func (s *FillableStdin) ioloop() {
Expand All @@ -161,6 +159,11 @@ func (s *FillableStdin) ioloop() {
bufR := make([]byte, 100)
var n int
n, s.bufErr = s.stdinBuffer.Read(bufR)
if s.bufErr != nil {
if s.bufErr == io.ErrClosedPipe {
break
}
}
s.Lock()
s.buf = append(s.buf, bufR[:n]...)
s.Unlock()
Expand All @@ -184,7 +187,11 @@ func (s *FillableStdin) Read(p []byte) (n int, err error) {
return n, cerr
}
s.Unlock()
n, err = s.stdin.Read(p)
return n, err
}

return s.stdin.Read(p)

func (s *FillableStdin) Close() error {
s.stdinBuffer.Close()
return nil
}
2 changes: 1 addition & 1 deletion term.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd solaris
// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd os400 solaris

// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
Expand Down
2 changes: 1 addition & 1 deletion term_solaris.go → term_nosyscall6.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build solaris
// +build aix os400 solaris

package readline

Expand Down
16 changes: 16 additions & 0 deletions terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ func (t *Terminal) ioloop() {
var (
isEscape bool
isEscapeEx bool
isEscapeSS3 bool
expectNextChar bool
)

Expand Down Expand Up @@ -152,9 +153,15 @@ func (t *Terminal) ioloop() {
if isEscape {
isEscape = false
if r == CharEscapeEx {
// ^][
expectNextChar = true
isEscapeEx = true
continue
} else if r == CharO {
// ^]O
expectNextChar = true
isEscapeSS3 = true
continue
}
r = escapeKey(r, buf)
} else if isEscapeEx {
Expand All @@ -177,6 +184,15 @@ func (t *Terminal) ioloop() {
expectNextChar = true
continue
}
} else if isEscapeSS3 {
isEscapeSS3 = false
if key := readEscKey(r, buf); key != nil {
r = escapeSS3Key(key)
}
if r == 0 {
expectNextChar = true
continue
}
}

expectNextChar = true
Expand Down
34 changes: 34 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"container/list"
"fmt"
"os"
"os/signal"
"strconv"
"strings"
"sync"
"syscall"
"time"
"unicode"
)
Expand Down Expand Up @@ -41,6 +43,7 @@ const (
CharCtrlY = 25
CharCtrlZ = 26
CharEsc = 27
CharO = 79
CharEscapeEx = 91
CharBackspace = 127
)
Expand Down Expand Up @@ -121,6 +124,27 @@ func escapeExKey(key *escapeKeyPair) rune {
return r
}

// translate EscOX SS3 codes for up/down/etc.
func escapeSS3Key(key *escapeKeyPair) rune {
var r rune
switch key.typ {
case 'D':
r = CharBackward
case 'C':
r = CharForward
case 'A':
r = CharPrev
case 'B':
r = CharNext
case 'H':
r = CharLineStart
case 'F':
r = CharLineEnd
default:
}
return r
}

type escapeKeyPair struct {
attr string
typ rune
Expand Down Expand Up @@ -275,3 +299,13 @@ func Debug(o ...interface{}) {
fmt.Fprintln(f, o...)
f.Close()
}

func CaptureExitSignal(f func()) {
cSignal := make(chan os.Signal, 1)
signal.Notify(cSignal, os.Interrupt, syscall.SIGTERM)
go func() {
for range cSignal {
f()
}
}()
}
2 changes: 1 addition & 1 deletion utils_unix.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd solaris
// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd os400 solaris

package readline

Expand Down