Fixed Paths

No need to track paths, just recurse over parents.
Also fixed an issue with some mode tracking.

Preparing to add ability to 'rename' buckets
This commit is contained in:
Brian Buller 2015-05-15 16:07:05 -05:00
parent f951ce9b64
commit be134e0632
2 changed files with 137 additions and 113 deletions

View File

@ -15,7 +15,6 @@ type BoltDB struct {
type BoltBucket struct {
name string
path []string
pairs []BoltPair
buckets []BoltBucket
parent *BoltBucket
@ -24,7 +23,6 @@ type BoltBucket struct {
}
type BoltPair struct {
path []string
parent *BoltBucket
key string
val string
@ -86,7 +84,7 @@ func (bd *BoltDB) getVisibleItemCount(path []string) (int, error) {
var ret_err error
if len(path) == 0 {
for i := range bd.buckets {
n, err := bd.getVisibleItemCount(bd.buckets[i].path)
n, err := bd.getVisibleItemCount(bd.buckets[i].GetPath())
if err != nil {
return 0, err
}
@ -105,7 +103,7 @@ func (bd *BoltDB) getVisibleItemCount(path []string) (int, error) {
vis += len(b.pairs)
// * recurse for buckets
for i := range b.buckets {
n, err := bd.getVisibleItemCount(b.buckets[i].path)
n, err := bd.getVisibleItemCount(b.buckets[i].GetPath())
if err != nil {
return 0, err
}
@ -132,45 +130,6 @@ func (bd *BoltDB) buildVisiblePathSlice() ([]string, error) {
return ret_slice, ret_err
}
/*
func (bd *BoltDB) buildVisiblePathSlice_old(path []string) ([]string, error) {
var ret_slice []string
var ret_err error
if len(path) == 0 {
for i := range bd.buckets {
n, err := bd.buildVisiblePathSlice(bd.buckets[i].path)
if err != nil {
return nil, err
}
ret_slice = append(ret_slice, n...)
}
} else {
b, err := bd.getBucketFromPath(path)
if err != nil {
return nil, err
}
// Add the bucket's path
ret_slice = append(ret_slice, strings.Join(b.path, "/"))
if b.expanded {
// This bucket is expanded, include it's children
// * recurse for buckets
for i := range b.buckets {
n, err := bd.buildVisiblePathSlice(b.buckets[i].path)
if err != nil {
return nil, err
}
ret_slice = append(ret_slice, n...)
}
// * one path for each pair
for i := range b.pairs {
ret_slice = append(ret_slice, strings.Join(b.pairs[i].path, "/"))
}
}
}
return ret_slice, ret_err
}
*/
func (bd *BoltDB) getPrevVisiblePath(path []string) []string {
vis_paths, err := bd.buildVisiblePathSlice()
if path == nil {
@ -265,10 +224,8 @@ func (bd *BoltDB) refreshDatabase() *BoltDB {
bb, err := readBucket(b)
if err == nil {
bb.name = string(nm)
bb.setPath([]string{bb.name})
bb.expanded = false
memBolt.buckets = append(memBolt.buckets, *bb)
//updatePaths(bb)
return nil
}
return err
@ -278,8 +235,11 @@ func (bd *BoltDB) refreshDatabase() *BoltDB {
}
func (b *BoltBucket) GetPath() []string {
b.path[len(b.path)-1] = b.name
return b.path
if b.parent != nil {
return append(b.parent.GetPath(), b.name)
} else {
return []string{b.name}
}
}
func (b *BoltBucket) buildVisiblePathSlice(prefix []string) ([]string, error) {
@ -337,19 +297,14 @@ func (b *BoltBucket) getPair(k string) (*BoltPair, error) {
return nil, errors.New("Pair Not Found")
}
func (b *BoltBucket) setPath(p []string) {
b.path = p
for i := range b.buckets {
b.buckets[i].setPath(append(p, b.buckets[i].name))
}
for i := range b.pairs {
b.pairs[i].path = append(p, b.pairs[i].key)
}
func (p *BoltPair) GetPath() []string {
return append(p.parent.GetPath(), p.key)
}
func deleteKey(path []string) error {
err := db.Update(func(tx *bolt.Tx) error {
// len(b.path)-1 is the key we need to delete, the rest are buckets leading to that key
// len(b.path)-1 is the key we need to delete,
// the rest are buckets leading to that key
if len(path) == 1 {
// Deleting a root bucket
return tx.DeleteBucket([]byte(path[0]))
@ -401,17 +356,6 @@ func readBucket(b *bolt.Bucket) (*BoltBucket, error) {
return bb, nil
}
func updatePaths(b *BoltBucket) {
for i := range b.buckets {
b.buckets[i].path = append(b.path, b.buckets[i].name)
updatePaths(&b.buckets[i])
}
for i := range b.pairs {
b.pairs[i].path = append(b.path, b.pairs[i].key)
}
}
/*
func renameBucket(path []string, name string) error {
err := db.Update(func(tx *bolt.Tx) error {
@ -437,9 +381,41 @@ func renameBucket(path []string, name string) error {
return err
}
*/
func updatePairKey(path []string, k string) error {
err := db.Update(func(tx *bolt.Tx) error {
// len(b.path)-1 is the key for the pair we're updating,
// the rest are buckets leading to that key
b := tx.Bucket([]byte(path[0]))
if b != nil {
if len(path) > 0 {
for i := range path[1 : len(path)-1] {
b = b.Bucket([]byte(path[i+1]))
if b == nil {
return errors.New("updatePairValue: Invalid Path")
}
}
}
bk := []byte(path[len(path)-1])
v := b.Get(bk)
err := b.Delete(bk)
if err == nil {
// Old pair has been deleted, now add the new one
err = b.Put([]byte(k), v)
}
// Now update the last key in the path
return err
} else {
return errors.New("updatePairValue: Invalid Path")
}
})
return err
}
func updatePairValue(path []string, v string) error {
err := db.Update(func(tx *bolt.Tx) error {
// len(b.path)-1 is the key we need to delete, the rest are buckets leading to that key
// len(b.GetPath())-1 is the key for the pair we're updating,
// the rest are buckets leading to that key
b := tx.Bucket([]byte(path[0]))
if b != nil {
if len(path) > 0 {
@ -528,10 +504,19 @@ func insertPair(path []string, k string, v string) error {
var f *os.File
func logToFile(s string) {
func logToFile(s string) error {
var err error
if f == nil {
f, _ = os.OpenFile("bolt-log", os.O_RDWR|os.O_APPEND, 0660)
f, err = os.OpenFile("bolt-log", os.O_RDWR|os.O_APPEND, 0660)
}
f.WriteString(s + "\n")
f.Sync()
if err != nil {
return err
}
if _, err = f.WriteString(s + "\n"); err != nil {
return err
}
if err = f.Sync(); err != nil {
return err
}
return nil
}

View File

@ -32,14 +32,17 @@ type BrowserScreen struct {
type BrowserMode int
const (
MODE_BROWSE = 16 // 0001 0000
MODE_CHANGE_VAL = 32 // 0010 0000
MODE_INSERT_BUCKET = 48 // 0011 0000
MODE_INSERT_PAIR = 64 // 0100 0000
MODE_INSERT_PAIR_KEY = 65 // 0100 0001
MODE_INSERT_PAIR_VAL = 66 // 0100 0010
MODE_DELETE = 128 // 1000 0000
MODE_MOD_TO_PARENT = 8 // 0000 1000
MODE_BROWSE = 16 // 0000 0001 0000
MODE_CHANGE = 32 // 0000 0010 0000
MODE_CHANGE_KEY = 33 // 0000 0010 0001
MODE_CHANGE_VAL = 34 // 0000 0010 0010
MODE_INSERT = 64 // 0000 0100 0000
MODE_INSERT_BUCKET = 65 // 0000 0100 0001
MODE_INSERT_PAIR = 68 // 0000 0100 0100
MODE_INSERT_PAIR_KEY = 69 // 0000 0100 0101
MODE_INSERT_PAIR_VAL = 70 // 0000 0100 0110
MODE_DELETE = 256 // 0001 0000 0000
MODE_MOD_TO_PARENT = 8 // 0000 0000 1000
)
type BoltType int
@ -55,9 +58,9 @@ func (screen *BrowserScreen) handleKeyEvent(event termbox.Event) int {
}
if screen.mode == MODE_BROWSE {
return screen.handleBrowseKeyEvent(event)
} else if screen.mode == MODE_CHANGE_VAL {
} else if screen.mode&MODE_CHANGE == MODE_CHANGE {
return screen.handleInputKeyEvent(event)
} else if screen.mode&MODE_INSERT_BUCKET == MODE_INSERT_BUCKET || screen.mode&MODE_INSERT_PAIR == MODE_INSERT_PAIR {
} else if screen.mode&MODE_INSERT == MODE_INSERT {
return screen.handleInsertKeyEvent(event)
} else if screen.mode == MODE_DELETE {
return screen.handleDeleteKeyEvent(event)
@ -119,11 +122,14 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int {
} else if event.Ch == 'e' {
b, p, _ := screen.db.getGenericFromPath(screen.current_path)
if b != nil {
screen.setMessage("Cannot edit a bucket")
screen.setMessage("Cannot edit a bucket, did you mean to (r)ename?")
} else if p != nil {
screen.startEditItem()
}
} else if event.Ch == 'r' {
screen.startRenameItem()
} else if event.Key == termbox.KeyEnter {
b, p, _ := screen.db.getGenericFromPath(screen.current_path)
if b != nil {
@ -152,9 +158,9 @@ func (screen *BrowserScreen) handleBrowseKeyEvent(event termbox.Event) int {
if len(screen.current_path) > 1 {
parent_bucket, err := screen.db.getBucketFromPath(screen.current_path[:len(screen.current_path)-1])
if err == nil {
screen.db.closeBucket(parent_bucket.path)
screen.db.closeBucket(parent_bucket.GetPath())
// Figure out how far up we need to move the cursor
screen.current_path = parent_bucket.path
screen.current_path = parent_bucket.GetPath()
}
} else {
screen.db.closeBucket(screen.current_path)
@ -174,15 +180,30 @@ func (screen *BrowserScreen) handleInputKeyEvent(event termbox.Event) int {
} else {
screen.input_modal.HandleKeyPress(event)
if screen.input_modal.IsDone() {
new_val := screen.input_modal.GetValue()
_, p, _ := screen.db.getGenericFromPath(screen.current_path)
if p != nil {
if updatePairValue(screen.current_path, new_val) != nil {
screen.setMessage("Error occurred updating Pair.")
} else {
p.val = new_val
screen.setMessage("Pair updated!")
screen.refreshDatabase()
if screen.mode == MODE_CHANGE_KEY {
new_key := screen.input_modal.GetValue()
_, p, _ := screen.db.getGenericFromPath(screen.current_path)
if p != nil {
if updatePairKey(screen.current_path, new_key) != nil {
screen.setMessage("Error occurred updating Pair.")
} else {
p.key = new_key
screen.current_path[len(screen.current_path)-1] = p.key
screen.setMessage("Pair updated!")
screen.refreshDatabase()
}
}
} else if screen.mode == MODE_CHANGE_VAL {
new_val := screen.input_modal.GetValue()
_, p, _ := screen.db.getGenericFromPath(screen.current_path)
if p != nil {
if updatePairValue(screen.current_path, new_val) != nil {
screen.setMessage("Error occurred updating Pair.")
} else {
p.val = new_val
screen.setMessage("Pair updated!")
screen.refreshDatabase()
}
}
}
screen.mode = MODE_BROWSE
@ -239,6 +260,7 @@ func (screen *BrowserScreen) handleInsertKeyEvent(event termbox.Event) int {
}
} else {
screen.input_modal.HandleKeyPress(event)
logToFile("> Insert Key Event")
if screen.input_modal.IsDone() {
new_val := screen.input_modal.GetValue()
screen.input_modal.Clear()
@ -264,18 +286,22 @@ func (screen *BrowserScreen) handleInsertKeyEvent(event termbox.Event) int {
}
if screen.mode&MODE_INSERT_BUCKET == MODE_INSERT_BUCKET {
logToFile(">> Inserting Bucket")
screen.setMessage(strings.Join(insert_path, "/"))
err := insertBucket(insert_path, new_val)
if err != nil {
screen.setMessage(fmt.Sprintf("%s => %s", err, insert_path))
logToFile(fmt.Sprintf(">> >> Error: %s", err))
}
screen.refreshDatabase()
screen.mode = MODE_BROWSE
screen.input_modal.Clear()
} else if screen.mode&MODE_INSERT_PAIR == MODE_INSERT_PAIR {
logToFile(">> Inserting Pair")
err := insertPair(insert_path, new_val, "")
if err != nil {
screen.setMessage(fmt.Sprintf("%s => %s", err, insert_path))
logToFile(fmt.Sprintf(">> >> Error: %s", err))
screen.refreshDatabase()
screen.mode = MODE_BROWSE
screen.input_modal.Clear()
@ -387,7 +413,6 @@ func (screen *BrowserScreen) drawFooter(style Style) {
_, height := termbox.Size()
termbox_util.DrawStringAtPoint(screen.message, 0, height-1, style.default_fg, style.default_bg)
}
func (screen *BrowserScreen) drawLeftPane(style Style) {
w, h := termbox.Size()
if w >= 80 {
@ -426,7 +451,6 @@ func (screen *BrowserScreen) drawLeftPane(style Style) {
y += bkt_h
}
}
func (screen *BrowserScreen) drawRightPane(style Style) {
w, h := termbox.Size()
if w >= 80 {
@ -443,7 +467,7 @@ func (screen *BrowserScreen) drawRightPane(style Style) {
termbox_util.DrawStringAtPoint(fmt.Sprintf("Buckets: %d", len(b.buckets)), start_x, start_y+1, style.default_fg, style.default_bg)
termbox_util.DrawStringAtPoint(fmt.Sprintf("Pairs: %d", len(b.pairs)), start_x, start_y+2, style.default_fg, style.default_bg)
} else if p != nil {
termbox_util.DrawStringAtPoint(fmt.Sprintf("Path: %s", strings.Join(p.path, "/")), start_x, start_y, style.default_fg, style.default_bg)
termbox_util.DrawStringAtPoint(fmt.Sprintf("Path: %s", strings.Join(p.GetPath(), "/")), start_x, start_y, style.default_fg, style.default_bg)
termbox_util.DrawStringAtPoint(fmt.Sprintf("Key: %s", p.key), start_x, start_y+1, style.default_fg, style.default_bg)
termbox_util.DrawStringAtPoint(fmt.Sprintf("Value: %s", p.val), start_x, start_y+2, style.default_fg, style.default_bg)
}
@ -471,16 +495,7 @@ func (screen *BrowserScreen) drawBucket(bkt *BoltBucket, style Style, y int) int
bucket_bg = style.cursor_bg
}
if len(bkt.path) == 0 {
// No bucket should have a 0 length path...
if bkt.parent == nil {
bkt.path = []string{bkt.name}
} else {
bkt.path = append(bkt.parent.path, bkt.name)
}
}
bkt_string := strings.Repeat(" ", len(bkt.path)*2) //screen.db.getDepthFromPath(bkt.path)*2)
bkt_string := strings.Repeat(" ", len(bkt.GetPath())*2) //screen.db.getDepthFromPath(bkt.GetPath())*2)
if bkt.expanded {
bkt_string = bkt_string + "- " + bkt.name + " "
bkt_string = fmt.Sprintf("%s%s", bkt_string, strings.Repeat(" ", (w-len(bkt_string))))
@ -510,14 +525,16 @@ func (screen *BrowserScreen) drawPair(bp *BoltPair, style Style, y int) int {
}
bucket_fg := style.default_fg
bucket_bg := style.default_bg
if comparePaths(screen.current_path, bp.path) {
if comparePaths(screen.current_path, bp.GetPath()) {
bucket_fg = style.cursor_fg
bucket_bg = style.cursor_bg
}
pair_string := strings.Repeat(" ", len(bp.path)*2) //screen.db.getDepthFromPath(bp.path)*2)
pair_string := strings.Repeat(" ", len(bp.GetPath())*2) //screen.db.getDepthFromPath(bp.GetPath())*2)
pair_string = fmt.Sprintf("%s%s: %s", pair_string, bp.key, bp.val)
pair_string = fmt.Sprintf("%s%s", pair_string, strings.Repeat(" ", (w-len(pair_string))))
if w-len(pair_string) > 0 {
pair_string = fmt.Sprintf("%s%s", pair_string, strings.Repeat(" ", (w-len(pair_string))))
}
termbox_util.DrawStringAtPoint(pair_string, 0, y, bucket_fg, bucket_bg)
return 1
}
@ -544,6 +561,25 @@ func (screen *BrowserScreen) startDeleteItem() bool {
}
func (screen *BrowserScreen) startEditItem() bool {
_, p, e := screen.db.getGenericFromPath(screen.current_path)
if e == nil {
w, h := termbox.Size()
inp_w, inp_h := (w / 2), 6
inp_x, inp_y := ((w / 2) - (inp_w / 2)), ((h / 2) - inp_h)
mod := termbox_util.CreateInputModal("", inp_x, inp_y, inp_w, inp_h, termbox.ColorWhite, termbox.ColorBlack)
if p != nil {
mod.SetTitle(termbox_util.AlignText(fmt.Sprintf("Input new value for '%s'", p.key), inp_w, termbox_util.ALIGN_CENTER))
mod.SetValue(p.val)
}
mod.Show()
screen.input_modal = mod
screen.mode = MODE_CHANGE_VAL
return true
}
return false
}
func (screen *BrowserScreen) startRenameItem() bool {
b, p, e := screen.db.getGenericFromPath(screen.current_path)
if e == nil {
w, h := termbox.Size()
@ -554,12 +590,12 @@ func (screen *BrowserScreen) startEditItem() bool {
mod.SetTitle(termbox_util.AlignText(fmt.Sprintf("Rename Bucket '%s' to:", b.name), inp_w, termbox_util.ALIGN_CENTER))
mod.SetValue(b.name)
} else if p != nil {
mod.SetTitle(termbox_util.AlignText(fmt.Sprintf("Input new value for '%s'", p.key), inp_w, termbox_util.ALIGN_CENTER))
mod.SetValue(p.val)
mod.SetTitle(termbox_util.AlignText(fmt.Sprintf("Rename Key '%s' to:", p.key), inp_w, termbox_util.ALIGN_CENTER))
mod.SetValue(p.key)
}
mod.Show()
screen.input_modal = mod
screen.mode = MODE_CHANGE_VAL
screen.mode = MODE_CHANGE_KEY
return true
}
return false
@ -615,15 +651,18 @@ func (screen *BrowserScreen) startInsertItem(tp BoltType) bool {
} else {
ins_path = strings.Join(screen.current_path, "/") + "/"
}
logToFile(" startInsertItem")
if tp == TYPE_BUCKET {
mod.SetTitle(termbox_util.AlignText("Create Bucket at "+ins_path, inp_w, termbox_util.ALIGN_CENTER))
screen.mode = MODE_INSERT_BUCKET
logToFile(" MODE_INSERT_BUCKET")
mod.Show()
return true
} else if tp == TYPE_PAIR {
mod.SetTitle(termbox_util.AlignText("Create Pair at "+ins_path, inp_w, termbox_util.ALIGN_CENTER))
mod.Show()
screen.mode = MODE_INSERT_PAIR
logToFile(" MODE_INSERT_PAIR")
return true
}
return false