boltbrowser/ui/bolt_tree_pane.go

233 lines
5.7 KiB
Go
Raw Normal View History

2022-04-20 21:22:43 +00:00
package ui
import (
"strings"
"git.bullercodeworks.com/brian/boltbrowser/models"
"git.bullercodeworks.com/brian/wandle"
"github.com/nsf/termbox-go"
)
type BoltTreePane struct {
x, y int
width int
height int
scrollRow int
active bool
buffer []string
currentPath []string
currentPathIdx int
filter string
db *models.BoltDB
message string
}
func NewBoltTreePane(x, y, w, h int) *BoltTreePane {
return &BoltTreePane{
x: x, y: y,
width: w, height: h,
}
}
func (w *BoltTreePane) Init() wandle.Cmd {
if w.db != nil {
w.buffer = w.db.Lines()
}
return nil
}
func (w *BoltTreePane) Update(msg wandle.Msg) wandle.Cmd {
if len(w.currentPath) == 0 {
w.currentPath = w.db.GetNextVisiblePath(nil, w.filter)
}
switch msg := msg.(type) {
case termbox.Event:
return w.handleTermboxEvent(msg)
}
return nil
}
func (w *BoltTreePane) handleTermboxEvent(msg termbox.Event) wandle.Cmd {
switch msg.Type {
case termbox.EventKey:
w.message = "Key Pressed: " + wandle.KeyToString(msg)
if msg.Ch == 'g' {
// Jump to Beginning
w.currentPath = w.db.GetNextVisiblePath(nil, w.filter)
return func() wandle.Msg { return nil }
} else if msg.Ch == 'G' {
// Jump to End
w.currentPath = w.db.GetPrevVisiblePath(nil, w.filter)
return func() wandle.Msg { return nil }
} else if msg.Key == termbox.KeyCtrlF {
w.jumpCursorDown(w.height / 2)
return func() wandle.Msg { return nil }
} else if msg.Key == termbox.KeyCtrlB {
w.jumpCursorDown(w.height / 2)
return func() wandle.Msg { return nil }
} else if msg.Ch == 'j' || msg.Key == termbox.KeyArrowDown {
w.moveCursorDown()
return func() wandle.Msg { return nil }
} else if msg.Ch == 'k' || msg.Key == termbox.KeyArrowUp {
w.moveCursorUp()
return func() wandle.Msg { return nil }
} else if msg.Ch == 'p' {
return func() wandle.Msg { return nil }
} else if msg.Ch == 'P' {
return func() wandle.Msg { return nil }
} else if msg.Ch == 'b' {
return func() wandle.Msg { return nil }
} else if msg.Ch == 'B' {
return func() wandle.Msg { return nil }
} else if msg.Ch == 'l' || msg.Key == termbox.KeyArrowRight || msg.Key == termbox.KeyEnter {
b, p, _ := w.db.GetGenericFromPath(w.currentPath)
// Select the current item
if b != nil {
w.db.ToggleOpenBucket(w.currentPath)
} else if p != nil {
// Edit the pair
}
return func() wandle.Msg { return nil }
} else if msg.Ch == 'h' || msg.Key == termbox.KeyArrowLeft {
b, _, e := w.db.GetGenericFromPath(w.currentPath)
if e == nil && b != nil && b.IsExpanded() {
w.db.CloseBucket(w.currentPath)
} else {
if len(w.currentPath) > 1 {
parent, err := w.db.GetBucketFromPath(w.currentPath[:len(w.currentPath)-1])
if err == nil {
w.db.CloseBucket(parent.GetPath())
w.currentPath = parent.GetPath()
}
} else {
}
}
return func() wandle.Msg { return nil }
}
}
return nil
}
func (w *BoltTreePane) View(style wandle.Style) {
treeOffset := 0
maxCursor := w.height * 2 / 3
if w.scrollRow > maxCursor {
treeOffset = w.scrollRow - maxCursor
}
if len(w.buffer) > 0 {
for k, v := range w.buffer[treeOffset:] {
wandle.Print(w.x, (w.y + k - 1), style, v)
}
}
wd, h := termbox.Size()
wandle.Print(wd, h-1, style, w.message)
}
func (w *BoltTreePane) IsActive() bool { return w.active }
func (w *BoltTreePane) SetActive(b bool) { w.active = b }
func (w *BoltTreePane) Focusable() bool { return true }
func (w *BoltTreePane) SetX(x int) { w.x = x }
func (w *BoltTreePane) SetY(y int) { w.y = y }
func (w *BoltTreePane) GetX() int { return w.x }
func (w *BoltTreePane) GetY() int { return w.y }
func (w *BoltTreePane) SetHeight(h int) { w.height = h }
func (w *BoltTreePane) GetHeight() int { return w.height }
func (w *BoltTreePane) SetWidth(wdt int) { w.height = wdt }
func (w *BoltTreePane) GetWidth() int { return w.width }
func (w *BoltTreePane) SetDB(db *models.BoltDB) {
w.db = db
w.RefreshBuffer()
}
func (w *BoltTreePane) RefreshBuffer() {
buckets := w.db.GetBuckets()
for i := range buckets {
w.buffer = append(w.buffer, buckets[i].Lines()...)
}
}
func (w *BoltTreePane) jumpCursorDown(distance int) {
paths, err := w.db.BuildVisiblePathSlice(w.filter)
if err != nil {
return
}
findPath := w.currentPath
for idx, pth := range paths {
startJump := true
for i := range pth {
if len(w.currentPath) > i && pth[i] != w.currentPath[i] {
startJump = false
}
}
if startJump {
distance--
if distance == 0 {
w.currentPath = paths[len(paths)-1-idx]
}
}
}
isCurPath := true
for i := range w.currentPath {
if w.currentPath[i] != findPath[i] {
isCurPath = false
break
}
}
if isCurPath {
w.currentPath = w.db.GetNextVisiblePath(nil, w.filter)
}
}
func (w *BoltTreePane) jumpCursorUp(distance int) {
paths, err := w.db.BuildVisiblePathSlice(w.filter)
if err != nil {
return
}
findPath := w.currentPath
for idx, pth := range paths {
startJump := true
for i := range pth {
if len(w.currentPath) > i && pth[i] != w.currentPath[i] {
startJump = false
}
}
if startJump {
distance--
if distance == 0 {
w.currentPath = paths[idx]
break
}
}
}
isCurPath := true
for i := range w.currentPath {
if w.currentPath[i] != findPath[i] {
isCurPath = false
break
}
}
if isCurPath {
w.currentPath = w.db.GetNextVisiblePath(nil, w.filter)
}
}
func (w *BoltTreePane) moveCursorUp() {
p := w.db.GetPrevVisiblePath(w.currentPath, w.filter)
if p != nil {
w.currentPath = p
}
}
func (w *BoltTreePane) moveCursorDown() {
p := w.db.GetNextVisiblePath(w.currentPath, w.filter)
if p != nil {
w.currentPath = p
}
}
func (w *BoltTreePane) comparePaths(p1, p2 []string) bool {
return strings.Join(p1, " → ") == strings.Join(p2, " → ")
}