commit bff8eb4

Hubert Hirtz  ·  2020-06-12 09:24:35 +0000 UTC
parent d448905
wip
4 files changed,  +146, -36
+5, -1
 1@@ -84,6 +84,10 @@ func main() {
 2 					app.Exit()
 3 				case tcell.KeyCtrlL:
 4 					app.Resize()
 5+				case tcell.KeyCtrlU:
 6+					app.ScrollUp()
 7+				case tcell.KeyCtrlD:
 8+					app.ScrollDown()
 9 				case tcell.KeyCtrlN:
10 					app.NextBuffer()
11 				case tcell.KeyCtrlP:
12@@ -202,7 +206,7 @@ func color(nick string) (c [3]rune) {
13 	h := fnv.New32()
14 	_, _ = h.Write([]byte(nick))
15 
16-	sum := h.Sum32() % 14
17+	sum := h.Sum32() % 96
18 
19 	if 1 <= sum {
20 		sum++
+28, -12
 1@@ -22,6 +22,8 @@ func IsSplitRune(c rune) bool {
 2 type Point struct {
 3 	X int
 4 	I int
 5+
 6+	Split bool
 7 }
 8 
 9 type Line struct {
10@@ -62,30 +64,43 @@ func (line *Line) RenderedHeight(screenWidth int) (height int) {
11 }
12 
13 func (line *Line) computeRenderedHeight(screenWidth int) {
14+	var lastSP Point
15 	line.renderedHeight = 1
16-	residualWidth := 0
17+	x := 0
18 
19+	fmt.Printf("\n%d %q\n", screenWidth, line.Content)
20 	for _, sp := range line.SplitPoints {
21-		w := sp.X + residualWidth
22-
23-		if line.renderedHeight*screenWidth < w {
24-			line.renderedHeight += 1
25-			residualWidth = w % screenWidth
26+		l := sp.X - lastSP.X
27+
28+		if !sp.Split && x == 0 {
29+			// Don't add space at the beginning of a row
30+		} else if screenWidth < l {
31+			line.renderedHeight += (x + l) / screenWidth
32+			x = (x + l) % screenWidth
33+		} else if screenWidth < x+l {
34+			line.renderedHeight++
35+			x = l % screenWidth
36+		} else {
37+			x = (x + l) % screenWidth
38 		}
39+
40+		fmt.Printf("%d %d %t occupied by %q\n", line.renderedHeight, x, sp.Split, line.Content[:sp.I])
41+		lastSP = sp
42 	}
43 }
44 
45 func (line *Line) computeSplitPoints() {
46 	var wb widthBuffer
47-	lastWasSplit := true
48+	lastWasSplit := false
49 
50 	for i, r := range line.Content {
51 		curIsSplit := IsSplitRune(r)
52 
53-		if !lastWasSplit && curIsSplit {
54+		if lastWasSplit != curIsSplit {
55 			line.SplitPoints = append(line.SplitPoints, Point{
56-				X: wb.Width(),
57-				I: i,
58+				X:     wb.Width(),
59+				I:     i,
60+				Split: curIsSplit,
61 			})
62 		}
63 
64@@ -95,8 +110,9 @@ func (line *Line) computeSplitPoints() {
65 
66 	if !lastWasSplit {
67 		line.SplitPoints = append(line.SplitPoints, Point{
68-			X: wb.Width(),
69-			I: len(line.Content),
70+			X:     wb.Width(),
71+			I:     len(line.Content),
72+			Split: true,
73 		})
74 	}
75 }
+72, -15
  1@@ -8,6 +8,7 @@ func assertSplitPoints(t *testing.T, line string, expected []Point) {
  2 
  3 	if len(l.SplitPoints) != len(expected) {
  4 		t.Errorf("%q: expected %d split points got %d", line, len(expected), len(l.SplitPoints))
  5+		return
  6 	}
  7 
  8 	for i := 0; i < len(expected); i++ {
  9@@ -20,23 +21,31 @@ func assertSplitPoints(t *testing.T, line string, expected []Point) {
 10 		if e.I != a.I {
 11 			t.Errorf("%q, point #%d: expected I=%d got %d", line, i, e.I, a.I)
 12 		}
 13+		if e.Split != a.Split {
 14+			t.Errorf("%q, point #%d: expected Split=%t got %t", line, i, e.Split, a.Split)
 15+		}
 16 	}
 17 }
 18 
 19 func TestLineSplitPoints(t *testing.T) {
 20 	assertSplitPoints(t, "hello", []Point{
 21-		{X: 5, I: 5},
 22+		{X: 5, I: 5, Split: true},
 23 	})
 24 	assertSplitPoints(t, "hello world", []Point{
 25-		{X: 5, I: 5},
 26-		{X: 11, I: 11},
 27+		{X: 5, I: 5, Split: true},
 28+		{X: 6, I: 6, Split: false},
 29+		{X: 11, I: 11, Split: true},
 30 	})
 31 	assertSplitPoints(t, "lorem ipsum dolor shit amet", []Point{
 32-		{X: 5, I: 5},
 33-		{X: 11, I: 11},
 34-		{X: 17, I: 17},
 35-		{X: 22, I: 22},
 36-		{X: 27, I: 27},
 37+		{X: 5, I: 5, Split: true},
 38+		{X: 6, I: 6, Split: false},
 39+		{X: 11, I: 11, Split: true},
 40+		{X: 12, I: 12, Split: false},
 41+		{X: 17, I: 17, Split: true},
 42+		{X: 18, I: 18, Split: false},
 43+		{X: 22, I: 22, Split: true},
 44+		{X: 23, I: 23, Split: false},
 45+		{X: 27, I: 27, Split: true},
 46 	})
 47 }
 48 
 49@@ -48,16 +57,64 @@ func assertRenderedHeight(t *testing.T, line string, width int, expected int) {
 50 	actual := l.RenderedHeight(width)
 51 
 52 	if actual != expected {
 53-		t.Errorf("%q (width=%d) expected to take %d lines, takes %d", line, width, expected, actual)
 54+		t.Errorf("%q with width=%d expected to take %d lines, takes %d", line, width, expected, actual)
 55 	}
 56 }
 57 
 58 func TestRenderedHeight(t *testing.T) {
 59-	assertRenderedHeight(t, "hello world", 100, 1)
 60-	assertRenderedHeight(t, "hello world", 10, 2)
 61+	assertRenderedHeight(t, "0123456789", 1, 10)
 62+	assertRenderedHeight(t, "0123456789", 2, 5)
 63+	assertRenderedHeight(t, "0123456789", 3, 4)
 64+	assertRenderedHeight(t, "0123456789", 4, 3)
 65+	assertRenderedHeight(t, "0123456789", 5, 2)
 66+	assertRenderedHeight(t, "0123456789", 6, 2)
 67+	assertRenderedHeight(t, "0123456789", 7, 2)
 68+	assertRenderedHeight(t, "0123456789", 8, 2)
 69+	assertRenderedHeight(t, "0123456789", 9, 2)
 70+	assertRenderedHeight(t, "0123456789", 10, 1)
 71+	assertRenderedHeight(t, "0123456789", 11, 1)
 72+
 73+	// LEN=9, WIDTH=9
 74+	assertRenderedHeight(t, "take care", 1, 8)  // |t|a|k|e|c|a|r|e|
 75+	assertRenderedHeight(t, "take care", 2, 4)  // |ta|ke|ca|re|
 76+	assertRenderedHeight(t, "take care", 3, 3)  // |tak|e c|are|
 77+	assertRenderedHeight(t, "take care", 4, 2)  // |take|care|
 78+	assertRenderedHeight(t, "take care", 5, 2)  // |take |care |
 79+	assertRenderedHeight(t, "take care", 6, 2)  // |take  |care  |
 80+	assertRenderedHeight(t, "take care", 7, 2)  // |take   |care   |
 81+	assertRenderedHeight(t, "take care", 8, 2)  // |take    |care    |
 82+	assertRenderedHeight(t, "take care", 9, 1)  // |take care|
 83+	assertRenderedHeight(t, "take care", 10, 1) // |take care |
 84+
 85+	// LEN=10, WIDTH=10
 86+	assertRenderedHeight(t, "take  care", 1, 8)  // |t|a|k|e|c|a|r|e|
 87+	assertRenderedHeight(t, "take  care", 2, 4)  // |ta|ke|ca|re|
 88+	assertRenderedHeight(t, "take  care", 3, 4)  // |tak|e  |car|e  |
 89+	assertRenderedHeight(t, "take  care", 4, 2)  // |take|care|
 90+	assertRenderedHeight(t, "take  care", 5, 2)  // |take |care |
 91+	assertRenderedHeight(t, "take  care", 6, 2)  // |take  |care  |
 92+	assertRenderedHeight(t, "take  care", 7, 2)  // |take   |care   |
 93+	assertRenderedHeight(t, "take  care", 8, 2)  // |take    |care    |
 94+	assertRenderedHeight(t, "take  care", 9, 2)  // |take     |care     |
 95+	assertRenderedHeight(t, "take  care", 10, 1) // |take  care|
 96+	assertRenderedHeight(t, "take  care", 11, 1) // |take  care |
 97 
 98-	assertRenderedHeight(t, "have a good day!", 100, 1)
 99-	assertRenderedHeight(t, "have a good day!", 10, 2)
100-	assertRenderedHeight(t, "have a good day!", 6, 3)
101-	assertRenderedHeight(t, "have a good day!", 4, 4)
102+	// LEN=16, WIDTH=16
103+	assertRenderedHeight(t, "have a good day!", 1, 13) // |h|a|v|e|a|g|o|o|d|d|a|y|!|
104+	assertRenderedHeight(t, "have a good day!", 2, 7)  // |ha|ve|a |go|od|da|y!|
105+	assertRenderedHeight(t, "have a good day!", 3, 5)  // |hav|e a|goo|d d|ay!|
106+	assertRenderedHeight(t, "have a good day!", 4, 4)  // |have|a   |good|day!|
107+	assertRenderedHeight(t, "have a good day!", 5, 3)  // |have |a good|day! |
108+	assertRenderedHeight(t, "have a good day!", 6, 3)  // |have a|good  |day!  |
109+	assertRenderedHeight(t, "have a good day!", 7, 3)  // |have a |good   |day!   |
110+	assertRenderedHeight(t, "have a good day!", 8, 3)  // |have a  |good    |day!    |
111+	assertRenderedHeight(t, "have a good day!", 9, 2)  // |have a   |good day!|
112+	assertRenderedHeight(t, "have a good day!", 10, 2) // |have a    |good day! |
113+	assertRenderedHeight(t, "have a good day!", 11, 2) // |have a good|day!       |
114+	assertRenderedHeight(t, "have a good day!", 12, 2) // |have a good |day!        |
115+	assertRenderedHeight(t, "have a good day!", 13, 2) // |have a good  |day!         |
116+	assertRenderedHeight(t, "have a good day!", 14, 2) // |have a good   |day!          |
117+	assertRenderedHeight(t, "have a good day!", 15, 2) // |have a good    |day!           |
118+	assertRenderedHeight(t, "have a good day!", 16, 1) // |have a good day!|
119+	assertRenderedHeight(t, "have a good day!", 17, 1) // |have a good day! |
120 }
+41, -8
  1@@ -13,6 +13,8 @@ type UI struct {
  2 	exit   atomic.Value // bool
  3 
  4 	bufferList BufferList
  5+	scrollAmt  int
  6+
  7 	textInput  []rune
  8 	textCursor int
  9 }
 10@@ -80,6 +82,7 @@ func (ui *UI) CurrentBuffer() (title string) {
 11 func (ui *UI) NextBuffer() {
 12 	ok := ui.bufferList.Next()
 13 	if ok {
 14+		ui.scrollAmt = 0
 15 		ui.drawBuffer()
 16 		ui.drawStatus()
 17 	}
 18@@ -88,11 +91,32 @@ func (ui *UI) NextBuffer() {
 19 func (ui *UI) PreviousBuffer() {
 20 	ok := ui.bufferList.Previous()
 21 	if ok {
 22+		ui.scrollAmt = 0
 23 		ui.drawBuffer()
 24 		ui.drawStatus()
 25 	}
 26 }
 27 
 28+func (ui *UI) ScrollUp() {
 29+	w, _ := ui.screen.Size()
 30+	ui.scrollAmt += w / 2
 31+	ui.drawBuffer()
 32+}
 33+
 34+func (ui *UI) ScrollDown() {
 35+	if ui.scrollAmt == 0 {
 36+		return
 37+	}
 38+
 39+	w, _ := ui.screen.Size()
 40+	ui.scrollAmt -= w / 2
 41+	if ui.scrollAmt < 0 {
 42+		ui.scrollAmt = 0
 43+	}
 44+
 45+	ui.drawBuffer()
 46+}
 47+
 48 func (ui *UI) AddBuffer(title string) {
 49 	_, ok := ui.bufferList.Add(title)
 50 	if ok {
 51@@ -118,7 +142,11 @@ func (ui *UI) AddLine(buffer string, line string, t time.Time, isStatus bool) {
 52 	ui.bufferList.AddLine(idx, line, t, isStatus)
 53 
 54 	if idx == ui.bufferList.Current {
 55-		ui.drawBuffer()
 56+		if 0 < ui.scrollAmt {
 57+			ui.scrollAmt++
 58+		} else {
 59+			ui.drawBuffer()
 60+		}
 61 	}
 62 }
 63 
 64@@ -176,6 +204,7 @@ func (ui *UI) InputEnter() (content string) {
 65 
 66 func (ui *UI) Resize() {
 67 	ui.bufferList.Invalidate()
 68+	ui.scrollAmt = 0
 69 	ui.draw()
 70 }
 71 
 72@@ -242,17 +271,25 @@ func (ui *UI) drawBuffer() {
 73 	var colorState int
 74 	var fgColor, bgColor int
 75 
 76-	y0 := h - 2
 77+	yEnd := h - 2
 78+	y0 := ui.scrollAmt + h - 2
 79 
 80 	for i := len(b.Content) - 1; 0 <= i; i-- {
 81 		line := &b.Content[i]
 82 
 83+		if y0 < 0 {
 84+			break
 85+		}
 86+
 87 		lineHeight := line.RenderedHeight(w)
 88 		y0 -= lineHeight
 89-		y := y0
 90+		if yEnd <= y0 {
 91+			continue
 92+		}
 93 
 94 		rs := []rune(line.Content)
 95 		x := 0
 96+		y := y0
 97 		spIdx := 0
 98 		hasLineHadSplit := false
 99 
100@@ -267,7 +304,7 @@ func (ui *UI) drawBuffer() {
101 				hasLineHadSplit = false
102 			}
103 
104-			if IsSplitRune(r) {
105+			if line.SplitPoints[spIdx].Split {
106 				if i == line.SplitPoints[spIdx].I {
107 					spIdx++
108 				}
109@@ -370,10 +407,6 @@ func (ui *UI) drawBuffer() {
110 			x += runewidth.RuneWidth(r)
111 		}
112 
113-		if y0 < 0 {
114-			break
115-		}
116-
117 		st = tcell.StyleDefault
118 		bold = false
119 		italic = false