summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHubert Hirtz <hubert@hirtzfr.eu>2020-06-12 11:24:35 +0200
committerHubert Hirtz <hubert@hirtzfr.eu>2020-06-12 11:24:35 +0200
commitbff8eb4f41daede6b2057804b222aed5dda114bb (patch)
tree4b44518383f96515325a1303f1394a61313a43cd
parentSplit lines between words (diff)
wip
Diffstat (limited to '')
-rw-r--r--cmd/irc/main.go6
-rw-r--r--ui/buffers.go40
-rw-r--r--ui/buffers_test.go87
-rw-r--r--ui/ui.go49
4 files changed, 146 insertions, 36 deletions
diff --git a/cmd/irc/main.go b/cmd/irc/main.go
index b11f34d..7b63d3c 100644
--- a/cmd/irc/main.go
+++ b/cmd/irc/main.go
@@ -84,6 +84,10 @@ func main() {
app.Exit()
case tcell.KeyCtrlL:
app.Resize()
+ case tcell.KeyCtrlU:
+ app.ScrollUp()
+ case tcell.KeyCtrlD:
+ app.ScrollDown()
case tcell.KeyCtrlN:
app.NextBuffer()
case tcell.KeyCtrlP:
@@ -202,7 +206,7 @@ func color(nick string) (c [3]rune) {
h := fnv.New32()
_, _ = h.Write([]byte(nick))
- sum := h.Sum32() % 14
+ sum := h.Sum32() % 96
if 1 <= sum {
sum++
diff --git a/ui/buffers.go b/ui/buffers.go
index 891b12f..c717691 100644
--- a/ui/buffers.go
+++ b/ui/buffers.go
@@ -22,6 +22,8 @@ func IsSplitRune(c rune) bool {
type Point struct {
X int
I int
+
+ Split bool
}
type Line struct {
@@ -62,30 +64,43 @@ func (line *Line) RenderedHeight(screenWidth int) (height int) {
}
func (line *Line) computeRenderedHeight(screenWidth int) {
+ var lastSP Point
line.renderedHeight = 1
- residualWidth := 0
+ x := 0
+ fmt.Printf("\n%d %q\n", screenWidth, line.Content)
for _, sp := range line.SplitPoints {
- w := sp.X + residualWidth
-
- if line.renderedHeight*screenWidth < w {
- line.renderedHeight += 1
- residualWidth = w % screenWidth
+ l := sp.X - lastSP.X
+
+ if !sp.Split && x == 0 {
+ // Don't add space at the beginning of a row
+ } else if screenWidth < l {
+ line.renderedHeight += (x + l) / screenWidth
+ x = (x + l) % screenWidth
+ } else if screenWidth < x+l {
+ line.renderedHeight++
+ x = l % screenWidth
+ } else {
+ x = (x + l) % screenWidth
}
+
+ fmt.Printf("%d %d %t occupied by %q\n", line.renderedHeight, x, sp.Split, line.Content[:sp.I])
+ lastSP = sp
}
}
func (line *Line) computeSplitPoints() {
var wb widthBuffer
- lastWasSplit := true
+ lastWasSplit := false
for i, r := range line.Content {
curIsSplit := IsSplitRune(r)
- if !lastWasSplit && curIsSplit {
+ if lastWasSplit != curIsSplit {
line.SplitPoints = append(line.SplitPoints, Point{
- X: wb.Width(),
- I: i,
+ X: wb.Width(),
+ I: i,
+ Split: curIsSplit,
})
}
@@ -95,8 +110,9 @@ func (line *Line) computeSplitPoints() {
if !lastWasSplit {
line.SplitPoints = append(line.SplitPoints, Point{
- X: wb.Width(),
- I: len(line.Content),
+ X: wb.Width(),
+ I: len(line.Content),
+ Split: true,
})
}
}
diff --git a/ui/buffers_test.go b/ui/buffers_test.go
index fdcbece..ca71864 100644
--- a/ui/buffers_test.go
+++ b/ui/buffers_test.go
@@ -8,6 +8,7 @@ func assertSplitPoints(t *testing.T, line string, expected []Point) {
if len(l.SplitPoints) != len(expected) {
t.Errorf("%q: expected %d split points got %d", line, len(expected), len(l.SplitPoints))
+ return
}
for i := 0; i < len(expected); i++ {
@@ -20,23 +21,31 @@ func assertSplitPoints(t *testing.T, line string, expected []Point) {
if e.I != a.I {
t.Errorf("%q, point #%d: expected I=%d got %d", line, i, e.I, a.I)
}
+ if e.Split != a.Split {
+ t.Errorf("%q, point #%d: expected Split=%t got %t", line, i, e.Split, a.Split)
+ }
}
}
func TestLineSplitPoints(t *testing.T) {
assertSplitPoints(t, "hello", []Point{
- {X: 5, I: 5},
+ {X: 5, I: 5, Split: true},
})
assertSplitPoints(t, "hello world", []Point{
- {X: 5, I: 5},
- {X: 11, I: 11},
+ {X: 5, I: 5, Split: true},
+ {X: 6, I: 6, Split: false},
+ {X: 11, I: 11, Split: true},
})
assertSplitPoints(t, "lorem ipsum dolor shit amet", []Point{
- {X: 5, I: 5},
- {X: 11, I: 11},
- {X: 17, I: 17},
- {X: 22, I: 22},
- {X: 27, I: 27},
+ {X: 5, I: 5, Split: true},
+ {X: 6, I: 6, Split: false},
+ {X: 11, I: 11, Split: true},
+ {X: 12, I: 12, Split: false},
+ {X: 17, I: 17, Split: true},
+ {X: 18, I: 18, Split: false},
+ {X: 22, I: 22, Split: true},
+ {X: 23, I: 23, Split: false},
+ {X: 27, I: 27, Split: true},
})
}
@@ -48,16 +57,64 @@ func assertRenderedHeight(t *testing.T, line string, width int, expected int) {
actual := l.RenderedHeight(width)
if actual != expected {
- t.Errorf("%q (width=%d) expected to take %d lines, takes %d", line, width, expected, actual)
+ t.Errorf("%q with width=%d expected to take %d lines, takes %d", line, width, expected, actual)
}
}
func TestRenderedHeight(t *testing.T) {
- assertRenderedHeight(t, "hello world", 100, 1)
- assertRenderedHeight(t, "hello world", 10, 2)
+ assertRenderedHeight(t, "0123456789", 1, 10)
+ assertRenderedHeight(t, "0123456789", 2, 5)
+ assertRenderedHeight(t, "0123456789", 3, 4)
+ assertRenderedHeight(t, "0123456789", 4, 3)
+ assertRenderedHeight(t, "0123456789", 5, 2)
+ assertRenderedHeight(t, "0123456789", 6, 2)
+ assertRenderedHeight(t, "0123456789", 7, 2)
+ assertRenderedHeight(t, "0123456789", 8, 2)
+ assertRenderedHeight(t, "0123456789", 9, 2)
+ assertRenderedHeight(t, "0123456789", 10, 1)
+ assertRenderedHeight(t, "0123456789", 11, 1)
+
+ // LEN=9, WIDTH=9
+ assertRenderedHeight(t, "take care", 1, 8) // |t|a|k|e|c|a|r|e|
+ assertRenderedHeight(t, "take care", 2, 4) // |ta|ke|ca|re|
+ assertRenderedHeight(t, "take care", 3, 3) // |tak|e c|are|
+ assertRenderedHeight(t, "take care", 4, 2) // |take|care|
+ assertRenderedHeight(t, "take care", 5, 2) // |take |care |
+ assertRenderedHeight(t, "take care", 6, 2) // |take |care |
+ assertRenderedHeight(t, "take care", 7, 2) // |take |care |
+ assertRenderedHeight(t, "take care", 8, 2) // |take |care |
+ assertRenderedHeight(t, "take care", 9, 1) // |take care|
+ assertRenderedHeight(t, "take care", 10, 1) // |take care |
+
+ // LEN=10, WIDTH=10
+ assertRenderedHeight(t, "take care", 1, 8) // |t|a|k|e|c|a|r|e|
+ assertRenderedHeight(t, "take care", 2, 4) // |ta|ke|ca|re|
+ assertRenderedHeight(t, "take care", 3, 4) // |tak|e |car|e |
+ assertRenderedHeight(t, "take care", 4, 2) // |take|care|
+ assertRenderedHeight(t, "take care", 5, 2) // |take |care |
+ assertRenderedHeight(t, "take care", 6, 2) // |take |care |
+ assertRenderedHeight(t, "take care", 7, 2) // |take |care |
+ assertRenderedHeight(t, "take care", 8, 2) // |take |care |
+ assertRenderedHeight(t, "take care", 9, 2) // |take |care |
+ assertRenderedHeight(t, "take care", 10, 1) // |take care|
+ assertRenderedHeight(t, "take care", 11, 1) // |take care |
- assertRenderedHeight(t, "have a good day!", 100, 1)
- assertRenderedHeight(t, "have a good day!", 10, 2)
- assertRenderedHeight(t, "have a good day!", 6, 3)
- assertRenderedHeight(t, "have a good day!", 4, 4)
+ // LEN=16, WIDTH=16
+ assertRenderedHeight(t, "have a good day!", 1, 13) // |h|a|v|e|a|g|o|o|d|d|a|y|!|
+ assertRenderedHeight(t, "have a good day!", 2, 7) // |ha|ve|a |go|od|da|y!|
+ assertRenderedHeight(t, "have a good day!", 3, 5) // |hav|e a|goo|d d|ay!|
+ assertRenderedHeight(t, "have a good day!", 4, 4) // |have|a |good|day!|
+ assertRenderedHeight(t, "have a good day!", 5, 3) // |have |a good|day! |
+ assertRenderedHeight(t, "have a good day!", 6, 3) // |have a|good |day! |
+ assertRenderedHeight(t, "have a good day!", 7, 3) // |have a |good |day! |
+ assertRenderedHeight(t, "have a good day!", 8, 3) // |have a |good |day! |
+ assertRenderedHeight(t, "have a good day!", 9, 2) // |have a |good day!|
+ assertRenderedHeight(t, "have a good day!", 10, 2) // |have a |good day! |
+ assertRenderedHeight(t, "have a good day!", 11, 2) // |have a good|day! |
+ assertRenderedHeight(t, "have a good day!", 12, 2) // |have a good |day! |
+ assertRenderedHeight(t, "have a good day!", 13, 2) // |have a good |day! |
+ assertRenderedHeight(t, "have a good day!", 14, 2) // |have a good |day! |
+ assertRenderedHeight(t, "have a good day!", 15, 2) // |have a good |day! |
+ assertRenderedHeight(t, "have a good day!", 16, 1) // |have a good day!|
+ assertRenderedHeight(t, "have a good day!", 17, 1) // |have a good day! |
}
diff --git a/ui/ui.go b/ui/ui.go
index 8581f18..cb5b7db 100644
--- a/ui/ui.go
+++ b/ui/ui.go
@@ -13,6 +13,8 @@ type UI struct {
exit atomic.Value // bool
bufferList BufferList
+ scrollAmt int
+
textInput []rune
textCursor int
}
@@ -80,6 +82,7 @@ func (ui *UI) CurrentBuffer() (title string) {
func (ui *UI) NextBuffer() {
ok := ui.bufferList.Next()
if ok {
+ ui.scrollAmt = 0
ui.drawBuffer()
ui.drawStatus()
}
@@ -88,11 +91,32 @@ func (ui *UI) NextBuffer() {
func (ui *UI) PreviousBuffer() {
ok := ui.bufferList.Previous()
if ok {
+ ui.scrollAmt = 0
ui.drawBuffer()
ui.drawStatus()
}
}
+func (ui *UI) ScrollUp() {
+ w, _ := ui.screen.Size()
+ ui.scrollAmt += w / 2
+ ui.drawBuffer()
+}
+
+func (ui *UI) ScrollDown() {
+ if ui.scrollAmt == 0 {
+ return
+ }
+
+ w, _ := ui.screen.Size()
+ ui.scrollAmt -= w / 2
+ if ui.scrollAmt < 0 {
+ ui.scrollAmt = 0
+ }
+
+ ui.drawBuffer()
+}
+
func (ui *UI) AddBuffer(title string) {
_, ok := ui.bufferList.Add(title)
if ok {
@@ -118,7 +142,11 @@ func (ui *UI) AddLine(buffer string, line string, t time.Time, isStatus bool) {
ui.bufferList.AddLine(idx, line, t, isStatus)
if idx == ui.bufferList.Current {
- ui.drawBuffer()
+ if 0 < ui.scrollAmt {
+ ui.scrollAmt++
+ } else {
+ ui.drawBuffer()
+ }
}
}
@@ -176,6 +204,7 @@ func (ui *UI) InputEnter() (content string) {
func (ui *UI) Resize() {
ui.bufferList.Invalidate()
+ ui.scrollAmt = 0
ui.draw()
}
@@ -242,17 +271,25 @@ func (ui *UI) drawBuffer() {
var colorState int
var fgColor, bgColor int
- y0 := h - 2
+ yEnd := h - 2
+ y0 := ui.scrollAmt + h - 2
for i := len(b.Content) - 1; 0 <= i; i-- {
line := &b.Content[i]
+ if y0 < 0 {
+ break
+ }
+
lineHeight := line.RenderedHeight(w)
y0 -= lineHeight
- y := y0
+ if yEnd <= y0 {
+ continue
+ }
rs := []rune(line.Content)
x := 0
+ y := y0
spIdx := 0
hasLineHadSplit := false
@@ -267,7 +304,7 @@ func (ui *UI) drawBuffer() {
hasLineHadSplit = false
}
- if IsSplitRune(r) {
+ if line.SplitPoints[spIdx].Split {
if i == line.SplitPoints[spIdx].I {
spIdx++
}
@@ -370,10 +407,6 @@ func (ui *UI) drawBuffer() {
x += runewidth.RuneWidth(r)
}
- if y0 < 0 {
- break
- }
-
st = tcell.StyleDefault
bold = false
italic = false