forked from mirror/readline
fix multiline
This commit is contained in:
parent
c4ec21b1c6
commit
4ae9d7e0fd
65
runebuf.go
65
runebuf.go
|
@ -2,6 +2,7 @@ package readline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -293,7 +294,8 @@ func (r *RuneBuffer) MoveToLineEnd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RuneBuffer) LineCount() int {
|
func (r *RuneBuffer) LineCount() int {
|
||||||
return LineCount(r.cfg.FuncGetWidth, 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) {
|
func (r *RuneBuffer) MoveTo(ch rune, prevChar, reverse bool) (success bool) {
|
||||||
|
@ -326,22 +328,9 @@ func (r *RuneBuffer) MoveTo(ch rune, prevChar, reverse bool) (success bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RuneBuffer) IdxLine() int {
|
func (r *RuneBuffer) IdxLine() int {
|
||||||
totalWidth := runes.WidthAll(r.buf[:r.idx]) + r.PromptLen()
|
sw := r.cfg.FuncGetWidth()
|
||||||
w := r.cfg.FuncGetWidth()
|
sp := SplitByLine(r.PromptLen(), sw, r.buf[:r.idx])
|
||||||
if w <= 0 {
|
return len(sp) - 1
|
||||||
return -1
|
|
||||||
}
|
|
||||||
line := totalWidth / w
|
|
||||||
|
|
||||||
// if cursor is in last colmun and not any character behind it
|
|
||||||
// the cursor will in the first line, otherwise will in the second line
|
|
||||||
// this situation only occurs in golang's Stdout
|
|
||||||
// TODO: figure out why
|
|
||||||
if totalWidth%w == 0 && len(r.buf) == r.idx && !isWindows {
|
|
||||||
line--
|
|
||||||
}
|
|
||||||
|
|
||||||
return line
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RuneBuffer) CursorLineCount() int {
|
func (r *RuneBuffer) CursorLineCount() int {
|
||||||
|
@ -373,11 +362,45 @@ func (r *RuneBuffer) output() []byte {
|
||||||
} else {
|
} else {
|
||||||
buf.Write([]byte(string(r.cfg.MaskRune)))
|
buf.Write([]byte(string(r.cfg.MaskRune)))
|
||||||
}
|
}
|
||||||
|
if len(r.buf) > r.idx {
|
||||||
|
buf.Write(runes.Backspace(r.buf[r.idx:]))
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
buf.Write([]byte(string(r.buf)))
|
sw := r.cfg.FuncGetWidth()
|
||||||
}
|
sp := SplitByLine(r.PromptLen(), sw, r.buf)
|
||||||
if len(r.buf) > r.idx {
|
written := 0
|
||||||
buf.Write(runes.Backspace(r.buf[r.idx:]))
|
idxInLine := 0
|
||||||
|
for idx, s := range sp {
|
||||||
|
buf.Write([]byte(s))
|
||||||
|
if r.idx > written && r.idx < written+len(s) {
|
||||||
|
idxInLine = r.idx - written
|
||||||
|
}
|
||||||
|
written += len(s)
|
||||||
|
|
||||||
|
if idx < len(sp)-1 && !isWindows {
|
||||||
|
buf.Write([]byte{'\n'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(r.buf) > r.idx {
|
||||||
|
targetLine := r.IdxLine()
|
||||||
|
currentLine := len(sp) - 1
|
||||||
|
// assert currentLine >= targetLine
|
||||||
|
if targetLine == 0 {
|
||||||
|
idxInLine += r.PromptLen()
|
||||||
|
}
|
||||||
|
buf.WriteString("\r")
|
||||||
|
if currentLine > targetLine {
|
||||||
|
buf.WriteString(fmt.Sprintf(
|
||||||
|
"\033[%vA", currentLine-targetLine,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
if idxInLine > 0 {
|
||||||
|
buf.WriteString(fmt.Sprintf(
|
||||||
|
"\033[%vC", idxInLine,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
24
utils.go
24
utils.go
|
@ -2,9 +2,12 @@ package readline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/chzyer/readline/runes"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -86,9 +89,26 @@ func escapeKey(r rune) rune {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SplitByLine(start, screenWidth int, rs []rune) []string {
|
||||||
|
var ret []string
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
currentWidth := start
|
||||||
|
for _, r := range rs {
|
||||||
|
w := runes.Width(r)
|
||||||
|
currentWidth += w
|
||||||
|
buf.WriteRune(r)
|
||||||
|
if currentWidth >= screenWidth {
|
||||||
|
ret = append(ret, buf.String())
|
||||||
|
buf.Reset()
|
||||||
|
currentWidth = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = append(ret, buf.String())
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
// calculate how many lines for N character
|
// calculate how many lines for N character
|
||||||
func LineCount(getWidth func() int, w int) int {
|
func LineCount(screenWidth, w int) int {
|
||||||
screenWidth := getWidth()
|
|
||||||
r := w / screenWidth
|
r := w / screenWidth
|
||||||
if w%screenWidth != 0 {
|
if w%screenWidth != 0 {
|
||||||
r++
|
r++
|
||||||
|
|
Loading…
Reference in New Issue