commit 54b1008

Hubert Hirtz  ·  2020-08-10 08:35:22 +0000 UTC
parent 7ce0747
editor: Handle UP and DOWN keys
3 files changed,  +68, -16
M app.go
M app.go
+4, -0
 1@@ -232,6 +232,10 @@ func (app *App) handleUIEvent(ev tcell.Event) {
 2 			} else {
 3 				app.win.InputLeft()
 4 			}
 5+		case tcell.KeyUp:
 6+			app.win.InputUp()
 7+		case tcell.KeyDown:
 8+			app.win.InputDown()
 9 		case tcell.KeyHome:
10 			app.win.InputHome()
11 		case tcell.KeyEnd:
+54, -16
  1@@ -7,7 +7,9 @@ import (
  2 // editor is the text field where the user writes messages and commands.
  3 type editor struct {
  4 	// text contains the written runes. An empty slice means no text is written.
  5-	text []rune
  6+	text [][]rune
  7+
  8+	lineIdx int
  9 
 10 	// textWidth[i] contains the width of string(text[:i]). Therefore
 11 	// len(textWidth) is always strictly greater than 0 and textWidth[0] is
 12@@ -28,7 +30,7 @@ type editor struct {
 13 
 14 func newEditor(width int) editor {
 15 	return editor{
 16-		text:      []rune{},
 17+		text:      [][]rune{{}},
 18 		textWidth: []int{0},
 19 		width:     width,
 20 	}
 21@@ -43,17 +45,17 @@ func (e *editor) Resize(width int) {
 22 }
 23 
 24 func (e *editor) IsCommand() bool {
 25-	return len(e.text) != 0 && e.text[0] == '/'
 26+	return len(e.text[e.lineIdx]) != 0 && e.text[e.lineIdx][0] == '/'
 27 }
 28 
 29 func (e *editor) TextLen() int {
 30-	return len(e.text)
 31+	return len(e.text[e.lineIdx])
 32 }
 33 
 34 func (e *editor) PutRune(r rune) {
 35-	e.text = append(e.text, ' ')
 36-	copy(e.text[e.cursorIdx+1:], e.text[e.cursorIdx:])
 37-	e.text[e.cursorIdx] = r
 38+	e.text[e.lineIdx] = append(e.text[e.lineIdx], ' ')
 39+	copy(e.text[e.lineIdx][e.cursorIdx+1:], e.text[e.lineIdx][e.cursorIdx:])
 40+	e.text[e.lineIdx][e.cursorIdx] = r
 41 
 42 	rw := runeWidth(r)
 43 	tw := e.textWidth[len(e.textWidth)-1]
 44@@ -93,13 +95,14 @@ func (e *editor) remRuneAt(idx int) {
 45 	copy(e.textWidth[idx+1:], e.textWidth[idx+2:])
 46 	e.textWidth = e.textWidth[:len(e.textWidth)-1]
 47 
 48-	copy(e.text[idx:], e.text[idx+1:])
 49-	e.text = e.text[:len(e.text)-1]
 50+	copy(e.text[e.lineIdx][idx:], e.text[e.lineIdx][idx+1:])
 51+	e.text[e.lineIdx] = e.text[e.lineIdx][:len(e.text[e.lineIdx])-1]
 52 }
 53 
 54 func (e *editor) Flush() (content string) {
 55-	content = string(e.text)
 56-	e.text = e.text[:0]
 57+	content = string(e.text[e.lineIdx])
 58+	e.lineIdx = len(e.text)
 59+	e.text = append(e.text, []rune{})
 60 	e.textWidth = e.textWidth[:1]
 61 	e.cursorIdx = 0
 62 	e.offsetIdx = 0
 63@@ -107,13 +110,13 @@ func (e *editor) Flush() (content string) {
 64 }
 65 
 66 func (e *editor) Right() {
 67-	if e.cursorIdx == len(e.text) {
 68+	if e.cursorIdx == len(e.text[e.lineIdx]) {
 69 		return
 70 	}
 71 	e.cursorIdx++
 72 	if e.width <= e.textWidth[e.cursorIdx]-e.textWidth[e.offsetIdx] {
 73 		e.offsetIdx += 16
 74-		max := len(e.text) - 1
 75+		max := len(e.text[e.lineIdx]) - 1
 76 		if max < e.offsetIdx {
 77 			e.offsetIdx = max
 78 		}
 79@@ -139,20 +142,55 @@ func (e *editor) Home() {
 80 }
 81 
 82 func (e *editor) End() {
 83-	e.cursorIdx = len(e.text)
 84+	e.cursorIdx = len(e.text[e.lineIdx])
 85 	for e.width < e.textWidth[e.cursorIdx]-e.textWidth[e.offsetIdx]+16 {
 86 		e.offsetIdx++
 87 	}
 88 }
 89 
 90+func (e *editor) Up() {
 91+	if e.lineIdx == 0 {
 92+		return
 93+	}
 94+	e.lineIdx--
 95+	e.computeTextWidth()
 96+	e.cursorIdx = 0
 97+	e.offsetIdx = 0
 98+	e.End()
 99+}
100+
101+func (e *editor) Down() {
102+	if e.lineIdx == len(e.text)-1 {
103+		if len(e.text[e.lineIdx]) == 0 {
104+			return
105+		}
106+		e.Flush()
107+		return
108+	}
109+	e.lineIdx++
110+	e.computeTextWidth()
111+	e.cursorIdx = 0
112+	e.offsetIdx = 0
113+	e.End()
114+}
115+
116+func (e *editor) computeTextWidth() {
117+	e.textWidth = e.textWidth[:1]
118+	rw := 0
119+	for _, r := range e.text[e.lineIdx] {
120+		rw += runeWidth(r)
121+		e.textWidth = append(e.textWidth, rw)
122+	}
123+}
124+
125 func (e *editor) Draw(screen tcell.Screen, y int) {
126 	st := tcell.StyleDefault
127 
128 	x := 0
129 	i := e.offsetIdx
130 
131-	for i < len(e.text) && x < e.width {
132-		r := e.text[i]
133+	for i < len(e.text[e.lineIdx]) && x < e.width {
134+		r := e.text[e.lineIdx][i]
135 		screen.SetContent(x, y, r, nil, st)
136 		x += runeWidth(r)
137 		i++
+10, -0
 1@@ -166,6 +166,16 @@ func (ui *UI) InputEnd() {
 2 	ui.draw()
 3 }
 4 
 5+func (ui *UI) InputUp() {
 6+	ui.e.Up()
 7+	ui.draw()
 8+}
 9+
10+func (ui *UI) InputDown() {
11+	ui.e.Down()
12+	ui.draw()
13+}
14+
15 func (ui *UI) InputBackspace() (ok bool) {
16 	ok = ui.e.RemRune()
17 	if ok {