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 }
M
ui/ui.go
+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