listbox: implement horizontal scrolling

Implement horizontal scrolling for selected lines that are longer than
dialog width. The following keys can be used:

Ctrl-a, Home	jump to beginning of line
Ctrl-e, End	jump to end of line
Left		move one character back
Right		move one character forward
Ctrl+b		move one word back
Ctrl+w		move one word forward

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Koni Marti 2022-10-20 23:55:27 +02:00 committed by Robin Jarry
parent 8153f59188
commit b860a64622
2 changed files with 64 additions and 1 deletions

View file

@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `:pipe -m git am -3` on patch series when `Message-Id` headers have not been
generated by `git send-email`.
- Overflowing text in header editors while composing can now be scrolled
horizontally.
## [0.13.0](https://git.sr.ht/~rjarry/aerc/refs/0.13.0) - 2022-10-20

View file

@ -9,6 +9,7 @@ import (
"git.sr.ht/~rjarry/aerc/lib/ui"
"git.sr.ht/~rjarry/aerc/logging"
"github.com/gdamore/tcell/v2"
"github.com/mattn/go-runewidth"
)
type ListBox struct {
@ -17,6 +18,7 @@ type ListBox struct {
lines []string
selected string
cursorPos int
horizPos int
jump int
showCursor bool
showFilter bool
@ -109,6 +111,17 @@ func (lb *ListBox) moveCursor(delta int) {
}
lb.selected = list[lb.cursorPos]
lb.showCursor = true
lb.horizPos = 0
}
func (lb *ListBox) moveHorizontal(delta int) {
lb.horizPos += delta
if lb.horizPos > len(lb.selected) {
lb.horizPos = len(lb.selected)
}
if lb.horizPos < 0 {
lb.horizPos = 0
}
}
func (lb *ListBox) filtered() []string {
@ -157,10 +170,22 @@ func (lb *ListBox) drawBox(ctx *ui.Context) {
y := 0
for i := lb.Scroll(); i < len(list) && y < h; i++ {
style := defaultStyle
line := runewidth.Truncate(list[i], w-1, "")
if lb.selected == list[i] && lb.showCursor {
style = selectedStyle
if len(list[i]) > w {
if len(list[i])-lb.horizPos < w {
lb.horizPos = len(list[i]) - w + 1
}
ctx.Printf(1, y, style, list[i])
rest := list[i][lb.horizPos:]
line = runewidth.Truncate(rest,
w-1, "")
if lb.horizPos > 0 && len(line) > 0 {
line = "" + line[1:]
}
}
}
ctx.Printf(1, y, style, line)
y += 1
}
@ -191,6 +216,42 @@ func (lb *ListBox) Invalidate() {
func (lb *ListBox) Event(event tcell.Event) bool {
if event, ok := event.(*tcell.EventKey); ok {
switch event.Key() {
case tcell.KeyLeft:
lb.moveHorizontal(-1)
lb.Invalidate()
return true
case tcell.KeyRight:
lb.moveHorizontal(+1)
lb.Invalidate()
return true
case tcell.KeyCtrlB:
line := lb.selected[:lb.horizPos]
fds := strings.Fields(line)
if len(fds) > 1 {
lb.moveHorizontal(
strings.LastIndex(line,
fds[len(fds)-1]) - lb.horizPos - 1)
} else {
lb.horizPos = 0
}
lb.Invalidate()
return true
case tcell.KeyCtrlW:
line := lb.selected[lb.horizPos+1:]
fds := strings.Fields(line)
if len(fds) > 1 {
lb.moveHorizontal(strings.Index(line, fds[1]))
}
lb.Invalidate()
return true
case tcell.KeyCtrlA, tcell.KeyHome:
lb.horizPos = 0
lb.Invalidate()
return true
case tcell.KeyCtrlE, tcell.KeyEnd:
lb.horizPos = len(lb.selected)
lb.Invalidate()
return true
case tcell.KeyCtrlP, tcell.KeyUp:
lb.moveCursor(-1)
lb.Invalidate()