Switching browser screen to buffer data then display
This commit is contained in:
parent
930ee1799e
commit
72d7cc8280
2
main.go
2
main.go
@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var ProgramName = "boltbrowser"
|
var ProgramName = "boltbrowser"
|
||||||
var VersionNum = 1.2
|
var VersionNum = 2.0
|
||||||
|
|
||||||
var databaseFiles []string
|
var databaseFiles []string
|
||||||
var db *bolt.DB
|
var db *bolt.DB
|
||||||
|
10
screen.go
10
screen.go
@ -19,9 +19,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func defaultScreensForData(db *BoltDB) []Screen {
|
func defaultScreensForData(db *BoltDB) []Screen {
|
||||||
var viewPort ViewPort
|
browserScreen := BrowserScreen{db: db, rightViewPort: ViewPort{}, leftViewPort: ViewPort{}}
|
||||||
|
|
||||||
browserScreen := BrowserScreen{db: db, viewPort: viewPort}
|
|
||||||
aboutScreen := AboutScreen(0)
|
aboutScreen := AboutScreen(0)
|
||||||
screens := [...]Screen{
|
screens := [...]Screen{
|
||||||
&browserScreen,
|
&browserScreen,
|
||||||
@ -41,3 +39,9 @@ func layoutAndDrawScreen(screen Screen, style Style) {
|
|||||||
screen.drawScreen(style)
|
screen.drawScreen(style)
|
||||||
termbox.Flush()
|
termbox.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Line struct {
|
||||||
|
Text string
|
||||||
|
Fg termbox.Attribute
|
||||||
|
Bg termbox.Attribute
|
||||||
|
}
|
||||||
|
@ -20,16 +20,9 @@ AboutScreen is just a basic 'int' type that we can extend to make this screen
|
|||||||
*/
|
*/
|
||||||
type AboutScreen int
|
type AboutScreen int
|
||||||
|
|
||||||
func drawCommandsAtPoint(commands []Command, x int, y int, style Style) {
|
func drawCommandAtPoint(cmd Command, xPos int, yPos int, style Style) {
|
||||||
xPos, yPos := x, y
|
|
||||||
for index, cmd := range commands {
|
|
||||||
termboxUtil.DrawStringAtPoint(fmt.Sprintf("%6s", cmd.key), xPos, yPos, style.defaultFg, style.defaultBg)
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("%6s", cmd.key), xPos, yPos, style.defaultFg, style.defaultBg)
|
||||||
termboxUtil.DrawStringAtPoint(cmd.description, xPos+8, yPos, style.defaultFg, style.defaultBg)
|
termboxUtil.DrawStringAtPoint(cmd.description, xPos+8, yPos, style.defaultFg, style.defaultBg)
|
||||||
yPos++
|
|
||||||
if index > 2 && index%2 == 1 {
|
|
||||||
yPos++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (screen *AboutScreen) handleKeyEvent(event termbox.Event) int {
|
func (screen *AboutScreen) handleKeyEvent(event termbox.Event) int {
|
||||||
@ -96,36 +89,58 @@ func (screen *AboutScreen) drawScreen(style Style) {
|
|||||||
yPos++
|
yPos++
|
||||||
versionString := fmt.Sprintf("Version: %0.1f", VersionNum)
|
versionString := fmt.Sprintf("Version: %0.1f", VersionNum)
|
||||||
termboxUtil.DrawStringAtPoint(versionString, (width-len(versionString))/2, yPos, style.defaultFg, style.defaultBg)
|
termboxUtil.DrawStringAtPoint(versionString, (width-len(versionString))/2, yPos, style.defaultFg, style.defaultBg)
|
||||||
yPos++
|
|
||||||
|
|
||||||
commands1 := [...]Command{
|
commands1 := []Command{
|
||||||
{"h,←", "close parent"},
|
{"h,←", "close parent"},
|
||||||
{"j,↓", "down"},
|
{"j,↓", "down"},
|
||||||
{"k,↑", "up"},
|
{"k,↑", "up"},
|
||||||
{"l,→", "open item"},
|
{"l,→", "open item"},
|
||||||
|
{"J", "scroll right pane down"},
|
||||||
|
{"K", "scroll right pane up"},
|
||||||
|
{"", ""},
|
||||||
{"g", "goto top"},
|
{"g", "goto top"},
|
||||||
{"G", "goto bottom"},
|
{"G", "goto bottom"},
|
||||||
|
{"", ""},
|
||||||
{"ctrl+f", "jump down"},
|
{"ctrl+f", "jump down"},
|
||||||
{"ctrl+b", "jump up"},
|
{"ctrl+b", "jump up"},
|
||||||
}
|
}
|
||||||
|
|
||||||
commands2 := [...]Command{
|
commands2 := []Command{
|
||||||
{"p,P", "create pair/at parent"},
|
{"p,P", "create pair/at parent"},
|
||||||
{"b,B", "create bucket/at parent"},
|
{"b,B", "create bucket/at parent"},
|
||||||
{"e", "edit value of pair"},
|
{"e", "edit value of pair"},
|
||||||
{"r", "rename pair/bucket"},
|
{"r", "rename pair/bucket"},
|
||||||
|
{"", ""},
|
||||||
|
{"", ""},
|
||||||
{"D", "delete item"},
|
{"D", "delete item"},
|
||||||
{"x,X", "export as string/json to file"},
|
{"x,X", "export as string/json to file"},
|
||||||
|
{"", ""},
|
||||||
{"?", "this screen"},
|
{"?", "this screen"},
|
||||||
{"q", "quit program"},
|
{"q", "quit program"},
|
||||||
}
|
}
|
||||||
xPos = startX // + 20
|
var maxCmd1 int
|
||||||
|
for k := range commands1 {
|
||||||
|
tst := len(commands1[k].key) + 1 + len(commands1[k].description)
|
||||||
|
if tst > maxCmd1 {
|
||||||
|
maxCmd1 = tst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var maxCmd2 int
|
||||||
|
for k := range commands2 {
|
||||||
|
tst := len(commands2[k].key) + 1 + len(commands2[k].description)
|
||||||
|
if tst > maxCmd2 {
|
||||||
|
maxCmd2 = tst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xPos = (width / 2) - ((maxCmd1 + maxCmd2) / 2)
|
||||||
yPos++
|
yPos++
|
||||||
|
|
||||||
drawCommandsAtPoint(commands1[:], xPos, yPos+1, style)
|
for k := range commands1 {
|
||||||
drawCommandsAtPoint(commands2[:], xPos+20, yPos+1, style)
|
drawCommandAtPoint(commands1[k], xPos, yPos+1+k, style)
|
||||||
|
}
|
||||||
|
for k := range commands2 {
|
||||||
|
drawCommandAtPoint(commands2[k], xPos+40, yPos+1+k, style)
|
||||||
|
}
|
||||||
exitTxt := "Press any key to return to browser"
|
exitTxt := "Press any key to return to browser"
|
||||||
termboxUtil.DrawStringAtPoint(exitTxt, (width-len(exitTxt))/2, height-1, style.titleFg, style.titleBg)
|
termboxUtil.DrawStringAtPoint(exitTxt, (width-len(exitTxt))/2, height-1, style.titleFg, style.titleBg)
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ type ViewPort struct {
|
|||||||
bytesPerRow int
|
bytesPerRow int
|
||||||
numberOfRows int
|
numberOfRows int
|
||||||
firstRow int
|
firstRow int
|
||||||
|
scrollRow int
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -24,7 +25,8 @@ BrowserScreen holds all that's going on :D
|
|||||||
*/
|
*/
|
||||||
type BrowserScreen struct {
|
type BrowserScreen struct {
|
||||||
db *BoltDB
|
db *BoltDB
|
||||||
viewPort ViewPort
|
leftViewPort ViewPort
|
||||||
|
rightViewPort ViewPort
|
||||||
queuedCommand string
|
queuedCommand string
|
||||||
currentPath []string
|
currentPath []string
|
||||||
currentType int
|
currentType int
|
||||||
@ -37,6 +39,9 @@ type BrowserScreen struct {
|
|||||||
|
|
||||||
rightPaneHeight int
|
rightPaneHeight int
|
||||||
rightPaneCursor int
|
rightPaneCursor int
|
||||||
|
|
||||||
|
leftPaneBuffer []Line
|
||||||
|
rightPaneBuffer []Line
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -480,10 +485,15 @@ func (screen *BrowserScreen) moveCursorDown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
func (screen *BrowserScreen) moveRightPaneUp() bool {
|
func (screen *BrowserScreen) moveRightPaneUp() bool {
|
||||||
|
if screen.rightViewPort.scrollRow > 0 {
|
||||||
|
screen.rightViewPort.scrollRow--
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
func (screen *BrowserScreen) moveRightPaneDown() bool {
|
func (screen *BrowserScreen) moveRightPaneDown() bool {
|
||||||
return false
|
screen.rightViewPort.scrollRow++
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (screen *BrowserScreen) performLayout() {}
|
func (screen *BrowserScreen) performLayout() {}
|
||||||
@ -528,41 +538,35 @@ func (screen *BrowserScreen) drawFooter(style Style) {
|
|||||||
_, height := termbox.Size()
|
_, height := termbox.Size()
|
||||||
termboxUtil.DrawStringAtPoint(screen.message, 0, height-1, style.defaultFg, style.defaultBg)
|
termboxUtil.DrawStringAtPoint(screen.message, 0, height-1, style.defaultFg, style.defaultBg)
|
||||||
}
|
}
|
||||||
func (screen *BrowserScreen) drawLeftPane(style Style) {
|
|
||||||
w, h := termbox.Size()
|
|
||||||
if w > 80 {
|
|
||||||
w = w / 2
|
|
||||||
}
|
|
||||||
screen.viewPort.numberOfRows = h - 2
|
|
||||||
|
|
||||||
termboxUtil.FillWithChar('=', 0, 1, w, 1, style.defaultFg, style.defaultBg)
|
func (screen *BrowserScreen) buildLeftPane(style Style) {
|
||||||
y := 2
|
screen.leftPaneBuffer = nil
|
||||||
screen.viewPort.firstRow = y
|
|
||||||
if len(screen.currentPath) == 0 {
|
if len(screen.currentPath) == 0 {
|
||||||
screen.currentPath = screen.db.getNextVisiblePath(nil)
|
screen.currentPath = screen.db.getNextVisiblePath(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// So we know how much of the tree _wants_ to be visible
|
|
||||||
// we only have screen.viewPort.numberOfRows of space though
|
|
||||||
curPathSpot := 0
|
curPathSpot := 0
|
||||||
visPaths, err := screen.db.buildVisiblePathSlice()
|
visPaths, err := screen.db.buildVisiblePathSlice()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for idx, pth := range visPaths {
|
for idx, pth := range visPaths {
|
||||||
isCurPath := true
|
screen.leftPaneBuffer
|
||||||
for i := range pth {
|
|
||||||
if len(screen.currentPath) > i && pth[i] != screen.currentPath[i] {
|
|
||||||
isCurPath = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isCurPath {
|
|
||||||
curPathSpot = idx
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *BrowserScreen) drawLeftPane(style Style) {
|
||||||
|
screen.buildLeftPane(style)
|
||||||
|
w, h := termbox.Size()
|
||||||
|
if w > 80 {
|
||||||
|
w = w / 2
|
||||||
}
|
}
|
||||||
|
screen.leftViewPort.bytesPerRow = w
|
||||||
|
screen.leftViewPort.numberOfRows = h - 2
|
||||||
|
termboxUtil.FillWithChar('=', 0, 1, w, 1, style.defaultFg, style.defaultBg)
|
||||||
|
y := 2
|
||||||
|
screen.leftViewPort.firstRow = y
|
||||||
|
|
||||||
treeOffset := 0
|
treeOffset := 0
|
||||||
maxCursor := screen.viewPort.numberOfRows * 2 / 3
|
maxCursor := screen.leftViewPort.numberOfRows * 2 / 3
|
||||||
if curPathSpot > maxCursor {
|
if curPathSpot > maxCursor {
|
||||||
treeOffset = curPathSpot - maxCursor
|
treeOffset = curPathSpot - maxCursor
|
||||||
}
|
}
|
||||||
@ -573,38 +577,70 @@ func (screen *BrowserScreen) drawLeftPane(style Style) {
|
|||||||
y += bktH
|
y += bktH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (screen *BrowserScreen) drawRightPane(style Style) {
|
|
||||||
w, h := termbox.Size()
|
|
||||||
if w > 80 {
|
|
||||||
// Screen is wide enough, split it
|
|
||||||
termboxUtil.FillWithChar('=', 0, 1, w, 1, style.defaultFg, style.defaultBg)
|
|
||||||
termboxUtil.FillWithChar('|', (w / 2), screen.viewPort.firstRow-1, (w / 2), h, style.defaultFg, style.defaultBg)
|
|
||||||
// Clear the right pane
|
|
||||||
termboxUtil.FillWithChar(' ', (w/2)+1, screen.viewPort.firstRow, w, h, style.defaultFg, style.defaultBg)
|
|
||||||
|
|
||||||
|
func (screen *BrowserScreen) buildRightPane(style Style) {
|
||||||
|
screen.rightPaneBuffer = nil
|
||||||
b, p, err := screen.db.getGenericFromPath(screen.currentPath)
|
b, p, err := screen.db.getGenericFromPath(screen.currentPath)
|
||||||
startX := (w / 2) + 2
|
|
||||||
startY := 2
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if b != nil {
|
if b != nil {
|
||||||
pathString := fmt.Sprintf("Path: %s", strings.Join(stringifyPath(b.GetPath()), " → "))
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
startY += screen.drawMultilineText(pathString, 6, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
|
Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(b.GetPath()), " → ")), style.defaultFg, style.defaultBg})
|
||||||
bucketString := fmt.Sprintf("Buckets: %d", len(b.buckets))
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
startY += screen.drawMultilineText(bucketString, 9, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
|
Line{fmt.Sprintf("Buckets: %d", len(b.buckets)), style.defaultFg, style.defaultBg})
|
||||||
pairsString := fmt.Sprintf("Pairs: %d", len(b.pairs))
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
startY += screen.drawMultilineText(pairsString, 7, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
|
Line{fmt.Sprintf("Pairs: %d", len(b.pairs)), style.defaultFg, style.defaultBg})
|
||||||
} else if p != nil {
|
} else if p != nil {
|
||||||
pathString := fmt.Sprintf("Path: %s", strings.Join(stringifyPath(p.GetPath()), " → "))
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
startY += screen.drawMultilineText(pathString, 6, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
|
Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(p.GetPath()), " → ")), style.defaultFg, style.defaultBg})
|
||||||
keyString := fmt.Sprintf("Key: %s", stringify([]byte(p.key)))
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
startY += screen.drawMultilineText(keyString, 5, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
|
Line{fmt.Sprintf("Key: %s", stringify([]byte(p.key))), style.defaultFg, style.defaultBg})
|
||||||
valString := fmt.Sprintf("Value: %s", formatValue([]byte(p.val)))
|
|
||||||
startY += screen.drawMultilineText(valString, 7, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
|
value := strings.Split(string(formatValue([]byte(p.val))), "\n")
|
||||||
|
if len(value) == 1 {
|
||||||
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
|
Line{fmt.Sprintf("Value: %s", value[0]), style.defaultFg, style.defaultBg})
|
||||||
|
} else {
|
||||||
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
|
Line{"Value:", style.defaultFg, style.defaultBg})
|
||||||
|
for _, v := range value {
|
||||||
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
|
Line{v, style.defaultFg, style.defaultBg})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pathString := fmt.Sprintf("Path: %s", strings.Join(stringifyPath(screen.currentPath), " → "))
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
startY += screen.drawMultilineText(pathString, 6, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
|
Line{fmt.Sprintf("Path: %s", strings.Join(stringifyPath(screen.currentPath), " → ")), style.defaultFg, style.defaultBg})
|
||||||
startY += screen.drawMultilineText(err.Error(), 6, startX, startY, (w/2)-1, style.defaultFg, style.defaultBg)
|
screen.rightPaneBuffer = append(screen.rightPaneBuffer,
|
||||||
|
Line{err.Error(), termbox.ColorRed, termbox.ColorBlack})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *BrowserScreen) drawRightPane(style Style) {
|
||||||
|
screen.buildRightPane(style)
|
||||||
|
w, h := termbox.Size()
|
||||||
|
if w > 80 {
|
||||||
|
screen.rightViewPort.bytesPerRow = w / 2
|
||||||
|
screen.rightViewPort.numberOfRows = h - 2
|
||||||
|
// Screen is wide enough, split it
|
||||||
|
termboxUtil.FillWithChar('=', 0, 1, w, 1, style.defaultFg, style.defaultBg)
|
||||||
|
termboxUtil.FillWithChar('|', (w / 2), screen.rightViewPort.firstRow-1, (w / 2), h, style.defaultFg, style.defaultBg)
|
||||||
|
// Clear the right pane
|
||||||
|
termboxUtil.FillWithChar(' ', (w/2)+1, screen.rightViewPort.firstRow, w, h, style.defaultFg, style.defaultBg)
|
||||||
|
|
||||||
|
startX := (w / 2) + 2
|
||||||
|
startY := 2
|
||||||
|
maxScroll := len(screen.rightPaneBuffer)-screen.rightViewPort.numberOfRows
|
||||||
|
if maxScroll < 0 {
|
||||||
|
maxScroll = 0
|
||||||
|
}
|
||||||
|
if screen.rightViewPort.scrollRow > maxScroll {
|
||||||
|
screen.rightViewPort.scrollRow = maxScroll
|
||||||
|
}
|
||||||
|
if len(screen.rightPaneBuffer) > 0 {
|
||||||
|
for k, v := range screen.rightPaneBuffer[screen.rightViewPort.scrollRow:] {
|
||||||
|
termboxUtil.DrawStringAtPoint(v.Text, startX, (startY + k - 1), v.Fg, v.Bg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -631,6 +667,10 @@ func formatValueJSON(val []byte) ([]byte, error) {
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (screen *BrowserScreen) bucketToStrings(bkt *BoltBucket, style Style) []string {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* drawBucket
|
/* drawBucket
|
||||||
* @bkt *BoltBucket - The bucket to draw
|
* @bkt *BoltBucket - The bucket to draw
|
||||||
* @style Style - The style to use
|
* @style Style - The style to use
|
||||||
|
Loading…
Reference in New Issue
Block a user