forked from mirror/readline
refactory
This commit is contained in:
parent
e9e6c35b06
commit
867002449c
|
@ -183,7 +183,7 @@ func (o *opCompleter) CompleteRefresh() {
|
|||
colWidth = w
|
||||
}
|
||||
}
|
||||
colNum := getWidth(o.op.cfg.StdoutFd) / (colWidth + o.candidateOff + 2)
|
||||
colNum := o.op.cfg.FuncGetWidth() / (colWidth + o.candidateOff + 2)
|
||||
o.candidateColNum = colNum
|
||||
buf := bytes.NewBuffer(nil)
|
||||
buf.Write(bytes.Repeat([]byte("\n"), lineCnt))
|
||||
|
|
16
operation.go
16
operation.go
|
@ -2,10 +2,7 @@ package readline
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -58,7 +55,7 @@ func (w *wrapWriter) Write(b []byte) (int, error) {
|
|||
func NewOperation(t *Terminal, cfg *Config) *Operation {
|
||||
op := &Operation{
|
||||
t: t,
|
||||
buf: NewRuneBuffer(t, cfg.Prompt, cfg.MaskRune, cfg),
|
||||
buf: NewRuneBuffer(t, cfg.Prompt, cfg),
|
||||
outchan: make(chan []rune),
|
||||
errchan: make(chan error),
|
||||
}
|
||||
|
@ -341,16 +338,7 @@ func (o *Operation) PasswordWithConfig(cfg *Config) ([]byte, error) {
|
|||
}
|
||||
|
||||
func (o *Operation) Password(prompt string) ([]byte, error) {
|
||||
w := o.Stdout()
|
||||
if prompt != "" {
|
||||
fmt.Fprintf(w, prompt)
|
||||
}
|
||||
o.t.EnterRawMode()
|
||||
defer o.t.ExitRawMode()
|
||||
|
||||
b, err := terminal.ReadPassword(int(o.cfg.Stdin.Fd()))
|
||||
fmt.Fprint(w, "\r\n")
|
||||
return b, err
|
||||
return o.PasswordEx(prompt, nil)
|
||||
}
|
||||
|
||||
func (o *Operation) SetTitle(t string) {
|
||||
|
|
|
@ -21,7 +21,7 @@ func (o *opPassword) EnterPasswordMode(cfg *Config) (err error) {
|
|||
|
||||
func (o *opPassword) PasswordConfig() *Config {
|
||||
return &Config{
|
||||
MaskRune: '*',
|
||||
EnableMask: true,
|
||||
InterruptPrompt: "\n",
|
||||
EOFPrompt: "\n",
|
||||
HistoryLimit: -1,
|
||||
|
|
18
readline.go
18
readline.go
|
@ -11,11 +11,6 @@ type Instance struct {
|
|||
Operation *Operation
|
||||
}
|
||||
|
||||
type FdReader interface {
|
||||
io.Reader
|
||||
Fd() uintptr
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
// prompt supports ANSI escape sequence, so we can color some characters even in windows
|
||||
Prompt string
|
||||
|
@ -39,12 +34,17 @@ type Config struct {
|
|||
InterruptPrompt string
|
||||
EOFPrompt string
|
||||
|
||||
Stdin FdReader
|
||||
FuncGetWidth func() int
|
||||
|
||||
Stdin io.Reader
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
|
||||
MaskRune rune
|
||||
EnableMask bool
|
||||
MaskRune rune
|
||||
|
||||
// erase the editing line after user submited it
|
||||
// it often use in IM.
|
||||
UniqueEditLine bool
|
||||
|
||||
// force use interactive even stdout is not a tty
|
||||
|
@ -100,6 +100,10 @@ func (c *Config) Init() error {
|
|||
c.EOFPrompt = ""
|
||||
}
|
||||
|
||||
if c.FuncGetWidth == nil {
|
||||
c.FuncGetWidth = genGetWidthFunc(c.StdoutFd)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
16
runebuf.go
16
runebuf.go
|
@ -18,7 +18,6 @@ type RuneBuffer struct {
|
|||
idx int
|
||||
prompt []rune
|
||||
w io.Writer
|
||||
mask rune
|
||||
|
||||
cleanInScreen bool
|
||||
interactive bool
|
||||
|
@ -41,10 +40,9 @@ func (r *RuneBuffer) Restore() {
|
|||
})
|
||||
}
|
||||
|
||||
func NewRuneBuffer(w io.Writer, prompt string, mask rune, cfg *Config) *RuneBuffer {
|
||||
func NewRuneBuffer(w io.Writer, prompt string, cfg *Config) *RuneBuffer {
|
||||
rb := &RuneBuffer{
|
||||
w: w,
|
||||
mask: mask,
|
||||
interactive: cfg.useInteractive(),
|
||||
cfg: cfg,
|
||||
}
|
||||
|
@ -58,7 +56,7 @@ func (r *RuneBuffer) SetConfig(cfg *Config) {
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) SetMask(m rune) {
|
||||
r.mask = m
|
||||
r.cfg.MaskRune = m
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) CurrentWidth(x int) int {
|
||||
|
@ -295,7 +293,7 @@ func (r *RuneBuffer) MoveToLineEnd() {
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) LineCount() int {
|
||||
return LineCount(r.cfg.StdoutFd, runes.WidthAll(r.buf)+r.PromptLen())
|
||||
return LineCount(r.cfg.FuncGetWidth, runes.WidthAll(r.buf)+r.PromptLen())
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) MoveTo(ch rune, prevChar, reverse bool) (success bool) {
|
||||
|
@ -329,7 +327,7 @@ func (r *RuneBuffer) MoveTo(ch rune, prevChar, reverse bool) (success bool) {
|
|||
|
||||
func (r *RuneBuffer) IdxLine() int {
|
||||
totalWidth := runes.WidthAll(r.buf[:r.idx]) + r.PromptLen()
|
||||
w := getWidth(r.cfg.StdoutFd)
|
||||
w := r.cfg.FuncGetWidth()
|
||||
if w <= 0 {
|
||||
return -1
|
||||
}
|
||||
|
@ -368,12 +366,12 @@ func (r *RuneBuffer) Refresh(f func()) {
|
|||
func (r *RuneBuffer) output() []byte {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
buf.WriteString(string(r.prompt))
|
||||
if r.mask != 0 && len(r.buf) > 0 {
|
||||
buf.Write([]byte(strings.Repeat(string(r.mask), len(r.buf)-1)))
|
||||
if r.cfg.EnableMask && len(r.buf) > 0 {
|
||||
buf.Write([]byte(strings.Repeat(string(r.cfg.MaskRune), len(r.buf)-1)))
|
||||
if r.buf[len(r.buf)-1] == '\n' {
|
||||
buf.Write([]byte{'\n'})
|
||||
} else {
|
||||
buf.Write([]byte(string(r.mask)))
|
||||
buf.Write([]byte(string(r.cfg.MaskRune)))
|
||||
}
|
||||
} else {
|
||||
buf.Write([]byte(string(r.buf)))
|
||||
|
|
|
@ -125,7 +125,7 @@ func (o *opSearch) SearchRefresh(x int) {
|
|||
}
|
||||
x = o.buf.CurrentWidth(x)
|
||||
x += o.buf.PromptLen()
|
||||
x = x % getWidth(o.cfg.StdoutFd)
|
||||
x = x % o.cfg.FuncGetWidth()
|
||||
|
||||
if o.markStart > 0 {
|
||||
o.buf.SetStyle(o.markStart, o.markEnd, "4")
|
||||
|
|
9
std.go
9
std.go
|
@ -17,6 +17,7 @@ var (
|
|||
stdOnce sync.Once
|
||||
)
|
||||
|
||||
// global instance will not submit history automatic
|
||||
func getInstance() *Instance {
|
||||
stdOnce.Do(func() {
|
||||
std, _ = NewEx(&Config{
|
||||
|
@ -26,6 +27,10 @@ func getInstance() *Instance {
|
|||
return std
|
||||
}
|
||||
|
||||
// let readline load history from filepath
|
||||
// and try to persist history into disk
|
||||
// set fp to "" to prevent readline persisting history to disk
|
||||
// so the `AddHistory` will return nil error forever.
|
||||
func SetHistoryPath(fp string) {
|
||||
ins := getInstance()
|
||||
cfg := ins.Config.Clone()
|
||||
|
@ -33,6 +38,7 @@ func SetHistoryPath(fp string) {
|
|||
ins.SetConfig(cfg)
|
||||
}
|
||||
|
||||
// set auto completer to global instance
|
||||
func SetAutoComplete(completer AutoCompleter) {
|
||||
ins := getInstance()
|
||||
cfg := ins.Config.Clone()
|
||||
|
@ -40,11 +46,14 @@ func SetAutoComplete(completer AutoCompleter) {
|
|||
ins.SetConfig(cfg)
|
||||
}
|
||||
|
||||
// add history to global instance manually
|
||||
// raise error only if `SetHistoryPath` is set with a non-empty path
|
||||
func AddHistory(content string) error {
|
||||
ins := getInstance()
|
||||
return ins.SaveHistory(content)
|
||||
}
|
||||
|
||||
// readline with global configs
|
||||
func Line(prompt string) (string, error) {
|
||||
ins := getInstance()
|
||||
ins.SetPrompt(prompt)
|
||||
|
|
|
@ -36,7 +36,7 @@ func NewTerminal(cfg *Config) (*Terminal, error) {
|
|||
}
|
||||
|
||||
func (t *Terminal) EnterRawMode() (err error) {
|
||||
t.state, err = MakeRaw(int(t.cfg.Stdin.Fd()))
|
||||
t.state, err = MakeRaw(int(t.cfg.StdinFd))
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ func (t *Terminal) ExitRawMode() (err error) {
|
|||
if t.state == nil {
|
||||
return
|
||||
}
|
||||
err = Restore(int(t.cfg.Stdin.Fd()), t.state)
|
||||
err = Restore(int(t.cfg.StdinFd), t.state)
|
||||
if err == nil {
|
||||
t.state = nil
|
||||
}
|
||||
|
|
10
utils.go
10
utils.go
|
@ -87,8 +87,8 @@ func escapeKey(r rune) rune {
|
|||
}
|
||||
|
||||
// calculate how many lines for N character
|
||||
func LineCount(stdoutFd int, w int) int {
|
||||
screenWidth := getWidth(stdoutFd)
|
||||
func LineCount(getWidth func() int, w int) int {
|
||||
screenWidth := getWidth()
|
||||
r := w / screenWidth
|
||||
if w%screenWidth != 0 {
|
||||
r++
|
||||
|
@ -116,3 +116,9 @@ func GetInt(s []string, def int) int {
|
|||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func genGetWidthFunc(fd int) func() int {
|
||||
return func() int {
|
||||
return getWidth(fd)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue