diff --git a/database.go b/database.go index 6b1d9a6..ca9e405 100644 --- a/database.go +++ b/database.go @@ -181,6 +181,34 @@ func renameBucket(node dbNode, name string) error { return err } +func searchEntry(path []string) error { + var found bool + db.View(func(tx *bbolt.Tx) error { //nolint:errcheck + _, err := getBucket(path, tx) + if err == nil { + found = true + return nil + } + if len(path) == 1 { + return errors.New("not found") + } + parent, err := getParentBucket(path, tx) + if err != nil { + return err + } + key := parent.Get([]byte(path[len(path)-1])) + if key != nil { + found = true + return nil + } + return nil + }) + if !found { + return errors.New("not found") + } + return nil +} + func getParentBucket(path []string, tx *bbolt.Tx) (*bbolt.Bucket, error) { if len(path) == 1 { // parent is root @@ -300,7 +328,7 @@ func copyBucket(node dbNode, newpath []string) error { if err != nil { return err } - oldBucket.ForEach(func(k, v []byte) error { + return oldBucket.ForEach(func(k, v []byte) error { if v == nil { if err := copyBucketContent(oldBucket, bucket); err != nil { return err @@ -312,23 +340,22 @@ func copyBucket(node dbNode, newpath []string) error { } return nil }) - return nil }) } -func copyBucketContent(old, new *bbolt.Bucket) error { - return old.ForEach(func(k, v []byte) error { +func copyBucketContent(src, dst *bbolt.Bucket) error { + return src.ForEach(func(k, v []byte) error { if v == nil { - nested, err := new.CreateBucket(k) + nested, err := dst.CreateBucket(k) if err != nil { return err } - oldnested := old.Bucket(k) + oldnested := src.Bucket(k) if err := copyBucketContent(oldnested, nested); err != nil { return err } } else { - if err := new.Put(k, v); err != nil { + if err := dst.Put(k, v); err != nil { return err } } @@ -345,7 +372,7 @@ func copyKey(node dbNode, newpath []string) error { if err != nil { return err } - return bucket.Put([]byte(newpath[len(newpath)-1]), []byte(node.value)) + return bucket.Put([]byte(newpath[len(newpath)-1]), node.value) }) } diff --git a/dialogs.go b/dialogs.go index 95cb100..680b483 100644 --- a/dialogs.go +++ b/dialogs.go @@ -126,7 +126,7 @@ func emptyForm(node dbNode, dialog string) *tview.Form { return form } -func moveForm(node dbNode, dialog string) *tview.Form { +func moveForm(node dbNode, dialog string) *tview.Form { //nolint:dupl currentPath := strings.Join(node.path, " ") form := tview.NewForm(). AddTextView("current path", currentPath, 0, 1, true, true). @@ -151,7 +151,7 @@ func moveForm(node dbNode, dialog string) *tview.Form { return form } -func copyForm(node dbNode, dialog string) *tview.Form { +func copyForm(node dbNode, dialog string) *tview.Form { //nolint:dupl currentPath := strings.Join(node.path, " ") form := tview.NewForm(). AddTextView("source path", currentPath, 0, 1, true, true). @@ -172,7 +172,7 @@ func copyForm(node dbNode, dialog string) *tview.Form { pager.RemovePage(dialog) app.SetFocus(tree) }) - form.SetBorder(true).SetTitle("Move Item").SetTitleAlign(tview.AlignCenter) + form.SetBorder(true).SetTitle("Copy Item").SetTitleAlign(tview.AlignCenter) return form } @@ -203,6 +203,26 @@ func renameForm(node dbNode, dialog string) *tview.Form { return form } +func searchForm(dialog string) *tview.Form { + form := tview.NewForm() + form.AddInputField("search path", "", 0, nil, nil). + AddButton("Cancel", func() { + pager.RemovePage(dialog) + }). + AddButton("Search", func() { + path := form.GetFormItem(0).(*tview.InputField).GetText() + searchPath := strings.Split(path, " ") + if err := searchEntry(searchPath); err != nil { + showError(err.Error()) + return + } + selectNode(searchPath) + pager.RemovePage(dialog) + }) + form.SetBorder(true).SetTitle("Search").SetTitleAlign(tview.AlignCenter) + return form +} + func editForm(node dbNode, dialog string) *tview.Form { value := prettyString(node.value) form := tview.NewForm(). diff --git a/main.go b/main.go index 93b495f..f9dfbc5 100644 --- a/main.go +++ b/main.go @@ -76,7 +76,7 @@ func main() { //nolint:funlen case tcell.KeyCtrlQ: app.Stop() case tcell.KeyCtrlC: - return nil + return tcell.NewEventKey(tcell.KeyCtrlC, 0, tcell.ModNone) } log.Println("app key handling: passing ", event.Name()) return event diff --git a/tree.go b/tree.go index 124bd52..9af3391 100644 --- a/tree.go +++ b/tree.go @@ -13,7 +13,7 @@ import ( func newTree(detail *tview.TextView) *tview.TreeView { //nolint:funlen treeKeys := []key{ - {"c", "(c) key or bucket"}, + {"c", "(c)opy key or bucket"}, {"b", "create new (b)ucket"}, {"d", "(d)elete key or bucket"}, {"e", "(e)mpty bucket or (e)dit key"}, @@ -21,12 +21,13 @@ func newTree(detail *tview.TextView) *tview.TreeView { //nolint:funlen {"m", "(m)ove key or bucket"}, {"o", "(o)pen file selection"}, {"r", "(r)ename key or bucket"}, + {"s", "(s)earch for key or bucket"}, {"x", "e(x)pand all nodes"}, {"?", "show help"}, {"Enter", "expand or colapse node"}, {"Ctrl-R", "reload database"}, {"Ctrl-C", "colapse all nodes"}, - {"Ctrl-C", "expand all nodes"}, + {"Ctrl-X", "expand all nodes"}, } rootDir := "." @@ -44,7 +45,7 @@ func newTree(detail *tview.TextView) *tview.TreeView { //nolint:funlen updateDetail(detail, node) }) tree.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { - log.Println("tree key handler", event.Key(), event.Rune(), event.Modifiers()) + log.Println("tree key handler", tcell.KeyNames[event.Key()]) switch event.Key() { // callapse all nodes case tcell.KeyCtrlC: @@ -70,9 +71,8 @@ func newTree(detail *tview.TextView) *tview.TreeView { //nolint:funlen // collapse node case 'c': node := getCurrentNode() - copy := dialog(copyForm(node, "dialog"), 60, 12) - pager.AddPage("dialog", copy, true, true) - tree.GetRoot().CollapseAll() + copied := dialog(copyForm(node, "dialog"), 60, 12) + pager.AddPage("dialog", copied, true, true) // add bucket case 'b': node := getCurrentNode() @@ -146,9 +146,13 @@ func newTree(detail *tview.TextView) *tview.TreeView { //nolint:funlen rename := modal(renameForm(node, "dialog"), 40, 10) pager.AddPage("dialog", rename, true, true) return nil + case 's': + search := modal(searchForm("dialog"), 40, 10) + pager.AddPage("dialog", search, true, true) + return nil // show help case '?': - help := helpDialog("Key Bindings", 100, 15, treeKeys, treeMoveKeys) + help := helpDialog("Key Bindings", 100, 20, treeKeys, treeMoveKeys) pager.AddPage("help", help, true, true) app.SetFocus(help) return nil