From 74c7c809120a63d03ba3670d2a1c8177c139f868 Mon Sep 17 00:00:00 2001
From: Eric <xplzv@126.com>
Date: Wed, 20 Nov 2019 15:47:33 +0800
Subject: [PATCH] stash

---
 pkg/proxy/newcommandparser.go |  33 ++--
 pkg/proxy/parser.go           |   2 +-
 pkg/utils/newparser.go        | 274 ++++++++++++++++++++++++++++++++++
 3 files changed, 293 insertions(+), 16 deletions(-)
 create mode 100644 pkg/utils/newparser.go

diff --git a/pkg/proxy/newcommandparser.go b/pkg/proxy/newcommandparser.go
index 34b6341..3ade6c5 100644
--- a/pkg/proxy/newcommandparser.go
+++ b/pkg/proxy/newcommandparser.go
@@ -24,18 +24,22 @@ func (c *commandInput) readFromServer(p []byte) {
 }
 
 func (c *commandInput) Parse() string {
-	lines, ok := utils.ParseTerminalData([]byte(c.readFromUserInput.String()))
-
-	if ok {
-		fmt.Println("readFromUserInput lines: ", lines)
-		c.readFromUserInput.Reset()
-		c.readFromServerInput.Reset()
-		result := strings.Join(lines, "\r\n")
-		fmt.Println("readFromUserInput result: ", result, len(result))
-		return result
-	}
-
-	lines, _ = utils.ParseTerminalData([]byte(c.readFromServerInput.String()))
+	//p := utils.NewTerminalParser()
+
+	//lines, ok := utils.ParseTerminalData([]byte(c.readFromUserInput.String()))
+	//lines, ok := p.ParseLines(c.readFromUserInput.Bytes())
+	//if ok {
+	//	fmt.Println("readFromUserInput lines: ", lines)
+	//	c.readFromUserInput.Reset()
+	//	c.readFromServerInput.Reset()
+	//	result := strings.Join(lines, "\r\n")
+	//	fmt.Println("readFromUserInput result: ", result, len(result))
+	//	return result
+	//}
+	p := utils.NewTerminalParser()
+	pb := c.readFromServerInput.Bytes()
+	fmt.Println(len(pb))
+	lines, _ := p.ParseLines(pb)
 	fmt.Println("readFromServerInput lines: ", lines)
 	c.readFromUserInput.Reset()
 	c.readFromServerInput.Reset()
@@ -51,11 +55,10 @@ func (c *commandOut) readFromServer(p []byte) {
 }
 
 func (c *commandOut) Parse() string {
-	lines, _ := utils.ParseTerminalData([]byte(c.readFromServerOut.String()))
+	p := utils.NewTerminalParser()
+	lines, _ := p.ParseLines(c.readFromServerOut.Bytes())
 	c.readFromServerOut.Reset()
 	result := strings.Join(lines, "\r\n")
 	fmt.Println("commandOut: ", result)
 	return result
 }
-
-
diff --git a/pkg/proxy/parser.go b/pkg/proxy/parser.go
index ecbafc3..69d3b5a 100644
--- a/pkg/proxy/parser.go
+++ b/pkg/proxy/parser.go
@@ -131,7 +131,7 @@ func (p *Parser) parseInputState(b []byte) []byte {
 	}
 	p.inputPreState = p.inputState
 
-	p.cmdInputParser.readFromUser(b)
+	//p.cmdInputParser.readFromUser(b)
 
 	if bytes.Contains(b, charEnter) {
 		// 连续输入enter key, 结算上一条可能存在的命令结果
diff --git a/pkg/utils/newparser.go b/pkg/utils/newparser.go
new file mode 100644
index 0000000..8bb2fa5
--- /dev/null
+++ b/pkg/utils/newparser.go
@@ -0,0 +1,274 @@
+package utils
+
+import (
+	"bytes"
+	"unicode/utf8"
+)
+
+type TerminalParser struct {
+	// Escape contains a pointer to the escape codes for this terminal.
+	// It's always a valid pointer, although the escape codes themselves
+	// may be empty if the terminal doesn't support them.
+	Escape *EscapeCodes
+
+	// line is the current line being entered.
+	line []rune
+	// pos is the logical position of the cursor in line
+	pos int
+	// pasteActive is true iff there is a bracketed paste operation in
+	// progress.
+	pasteActive bool
+
+	// maxLine is the greatest value of cursorY so far.
+	maxLine int
+
+	// remainder contains the remainder of any partial key sequences after
+	// a read. It aliases into inBuf.
+	remainder []byte
+	inBuf     [256]byte
+}
+
+func NewTerminalParser() TerminalParser {
+	return TerminalParser{
+		Escape: &vt100EscapeCodes,
+	}
+}
+
+func (t *TerminalParser) ParseLines(p []byte) (lines []string, isOk bool) {
+	c := bytes.NewReader(p)
+	var err error
+	isOk = true
+	lineIsPasted := t.pasteActive
+	var line string
+	lines = make([]string, 0, 10)
+	for {
+		rest := t.remainder
+		lineOk := false
+		for !lineOk {
+			var key rune
+			key, rest = bytesToKey(rest, t.pasteActive)
+			if key == utf8.RuneError {
+				break
+			}
+			if !t.pasteActive {
+				if key == keyCtrlD {
+					if len(t.line) == 0 {
+						// as key has already handled, we need update remainder data,
+						t.remainder = rest
+						return
+					}
+				}
+				if key == keyPasteStart {
+					t.pasteActive = true
+					if len(t.line) == 0 {
+						lineIsPasted = true
+					}
+					continue
+				}
+			} else if key == keyPasteEnd {
+				t.pasteActive = false
+				continue
+			}
+			switch key {
+			case keyUp:
+				runes := []rune("")
+				t.setLine(runes, len(runes))
+				isOk = false
+				continue
+			case keyDown:
+				runes := []rune("")
+				t.setLine(runes, len(runes))
+				isOk = false
+				continue
+			}
+
+			if !t.pasteActive {
+				lineIsPasted = false
+			}
+			line, lineOk = t.handleKey(key)
+		}
+		if len(rest) > 0 {
+			n := copy(t.inBuf[:], rest)
+			t.remainder = t.inBuf[:n]
+		} else {
+			t.remainder = nil
+		}
+		if lineOk {
+			if lineIsPasted {
+				err = ErrPasteIndicator
+			}
+			lines = append(lines, line)
+		}
+
+		// t.remainder is a slice at the beginning of t.inBuf
+		// containing a partial key sequence
+		readBuf := t.inBuf[len(t.remainder):]
+		var n int
+
+		n, err = c.Read(readBuf)
+
+		t.remainder = t.inBuf[:n+len(t.remainder)]
+		if n == 0 && err != nil && len(t.remainder) == 0 {
+			lines = append(lines, string(t.line))
+			return
+		}
+	}
+}
+
+func (t *TerminalParser) eraseNPreviousChars(n int) {
+	if n == 0 {
+		return
+	}
+
+	if t.pos < n {
+		n = t.pos
+	}
+	t.pos -= n
+
+	copy(t.line[t.pos:], t.line[n+t.pos:])
+	t.line = t.line[:len(t.line)-n]
+}
+
+func (t *TerminalParser) countToLeftWord() int {
+	if t.pos == 0 {
+		return 0
+	}
+
+	pos := t.pos - 1
+	for pos > 0 {
+		if t.line[pos] != ' ' {
+			break
+		}
+		pos--
+	}
+	for pos > 0 {
+		if t.line[pos] == ' ' {
+			pos++
+			break
+		}
+		pos--
+	}
+
+	return t.pos - pos
+}
+
+func (t *TerminalParser) countToRightWord() int {
+	pos := t.pos
+	for pos < len(t.line) {
+		if t.line[pos] == ' ' {
+			break
+		}
+		pos++
+	}
+	for pos < len(t.line) {
+		if t.line[pos] != ' ' {
+			break
+		}
+		pos++
+	}
+	return pos - t.pos
+}
+
+func (t *TerminalParser) setLine(newLine []rune, newPos int) {
+	t.line = newLine
+	t.pos = newPos
+}
+
+func (t *TerminalParser) handleKey(key rune) (line string, ok bool) {
+	if t.pasteActive && key != keyEnter {
+		t.addKeyToLine(key)
+		return
+	}
+
+	switch key {
+	case keyBackspace:
+		if t.pos == 0 {
+			return
+		}
+		t.eraseNPreviousChars(1)
+	case keyAltLeft:
+		// move left by a word.
+		t.pos -= t.countToLeftWord()
+	case keyAltRight:
+		// move right by a word.
+		t.pos += t.countToRightWord()
+	case keyLeft:
+		if t.pos == 0 {
+			return
+		}
+		t.pos--
+	case keyRight:
+		if t.pos == len(t.line) {
+			return
+		}
+		t.pos++
+	case keyHome:
+		if t.pos == 0 {
+			return
+		}
+		t.pos = 0
+	case keyEnd:
+		if t.pos == len(t.line) {
+			return
+		}
+		t.pos = len(t.line)
+	case keyUp:
+		runes := []rune("")
+		t.setLine(runes, len(runes))
+	case keyDown:
+		runes := []rune("")
+		t.setLine(runes, len(runes))
+	case keyEnter:
+		line = string(t.line)
+		ok = true
+		t.line = t.line[:0]
+		t.pos = 0
+		t.maxLine = 0
+	case keyDeleteWord:
+		// Delete zero or more spaces and then one or more characters.
+		t.eraseNPreviousChars(t.countToLeftWord())
+	case keyDeleteLine:
+		// Delete everything from the current cursor position to the
+		// end of line.
+		//for i := t.pos; i < len(t.line); i++ {
+		//	t.advanceCursor(1)
+		//}
+		t.line = t.line[:t.pos]
+	case keyCtrlD:
+		// Erase the character under the current position.
+		// The EOF case when the line is empty is handled in
+		// readLine().
+		if t.pos < len(t.line) {
+			t.pos++
+			t.eraseNPreviousChars(1)
+		}
+	case keyCtrlU:
+		t.eraseNPreviousChars(t.pos)
+	case keyClearScreen:
+		// Erases the screen and moves the cursor to the home position.
+		//t.cursorX, t.cursorY = 0, 0
+		//t.advanceCursor(visualLength(t.prompt))
+		t.setLine(t.line, t.pos)
+	default:
+		if !isPrintable(key) {
+			return
+		}
+		if len(t.line) == maxLineLength {
+			return
+		}
+		t.addKeyToLine(key)
+	}
+	return
+}
+
+func (t *TerminalParser) addKeyToLine(key rune) {
+	if len(t.line) == cap(t.line) {
+		newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
+		copy(newLine, t.line)
+		t.line = newLine
+	}
+	t.line = t.line[:len(t.line)+1]
+	copy(t.line[t.pos+1:], t.line[t.pos:])
+	t.line[t.pos] = key
+	t.pos++
+}
-- 
2.18.0