From 1d87821121091a91a02730c25924532dcbc03e25 Mon Sep 17 00:00:00 2001 From: skanehira Date: Wed, 30 Oct 2019 02:28:25 +0900 Subject: [PATCH] make json tree view --- gui/gui.go | 38 +++++++++++++++++++++ gui/tree.go | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 16 ++++++--- 3 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 gui/gui.go create mode 100644 gui/tree.go diff --git a/gui/gui.go b/gui/gui.go new file mode 100644 index 0000000..31996a6 --- /dev/null +++ b/gui/gui.go @@ -0,0 +1,38 @@ +package gui + +import ( + "log" + + "github.com/rivo/tview" +) + +type Gui struct { + Tree *Tree + App *tview.Application + Pages *tview.Pages +} + +func New() *Gui { + g := &Gui{ + Tree: NewTree(), + App: tview.NewApplication(), + Pages: tview.NewPages(), + } + return g +} + +func (g *Gui) Run(i interface{}) error { + g.Tree.UpdateView(g, i) + + grid := tview.NewGrid(). + AddItem(g.Tree, 0, 0, 1, 1, 0, 0, true) + + g.Pages.AddAndSwitchToPage("main", grid, true) + + if err := g.App.SetRoot(g.Pages, true).Run(); err != nil { + log.Println(err) + return err + } + + return nil +} diff --git a/gui/tree.go b/gui/tree.go new file mode 100644 index 0000000..2616871 --- /dev/null +++ b/gui/tree.go @@ -0,0 +1,95 @@ +package gui + +import ( + "fmt" + + "github.com/gdamore/tcell" + "github.com/rivo/tview" +) + +type Tree struct { + *tview.TreeView +} + +func NewTree() *Tree { + t := &Tree{ + TreeView: tview.NewTreeView(), + } + + t.SetBorder(true).SetTitle("json tree").SetTitleAlign(tview.AlignLeft) + return t +} + +func (t *Tree) UpdateView(g *Gui, i interface{}) { + g.App.QueueUpdateDraw(func() { + root := tview.NewTreeNode(".") + t.SetRoot(root).SetCurrentNode(root) + for _, node := range t.AddNode(i) { + root.AddChild(node) + } + }) +} + +func (t *Tree) AddNode(node interface{}) []*tview.TreeNode { + // e.g child is {"name": "gorilla", "lang": {"ja":"japan", "en": "english"}} + var nodes []*tview.TreeNode + + switch node := node.(type) { + case map[string]interface{}: + for k, v := range node { + newNode := t.NewNodeWithLiteral(k). + SetColor(tcell.ColorMediumSlateBlue).SetReference(k) + + list, isList := v.([]interface{}) + if isList && len(list) > 0 { + newNode.SetSelectable(true) + } + for _, n := range t.AddNode(v) { + newNode.AddChild(n) + } + nodes = append(nodes, newNode) + } + case []interface{}: + for i, v := range node { + if list, isList := v.([]interface{}); isList && len(list) > 0 { + numberNode := tview.NewTreeNode(fmt.Sprintf("[%d]", i+1)) + for _, n := range t.AddNode(v) { + numberNode.AddChild(n) + } + nodes = append(nodes, numberNode) + } else if m, isMap := v.(map[string]interface{}); isMap && len(m) > 0 { + numberNode := tview.NewTreeNode(fmt.Sprintf("[%d]", i+1)) + for _, n := range t.AddNode(v) { + numberNode.AddChild(n) + } + nodes = append(nodes, numberNode) + } else { + nodes = append(nodes, t.AddNode(v)...) + } + } + default: + nodes = append(nodes, t.NewNodeWithLiteral(node)) + } + return nodes +} + +func (t *Tree) NewNodeWithLiteral(i interface{}) *tview.TreeNode { + var text string + node := tview.NewTreeNode("") + switch v := i.(type) { + case int32: + text = fmt.Sprintf("%d", v) + case int64: + text = fmt.Sprintf("%d", v) + case float32: + text = fmt.Sprintf("%f", v) + case float64: + text = fmt.Sprintf("%f", v) + case bool: + text = fmt.Sprintf("%t", v) + case string: + text = v + } + + return node.SetText(text) +} diff --git a/main.go b/main.go index 0e4468a..80c0ceb 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "log" "os" + "github.com/skanehira/tson/gui" "golang.org/x/crypto/ssh/terminal" ) @@ -14,18 +15,25 @@ func run() int { if !terminal.IsTerminal(0) { b, err := ioutil.ReadAll(os.Stdin) if err != nil { - log.Println(err) + fmt.Fprintln(os.Stderr, err) return 1 } + if len(b) == 0 { + fmt.Println("json is empty") + return 0 + } + var t interface{} if err := json.Unmarshal(b, &t); err != nil { - log.Println(err) + fmt.Fprintln(os.Stderr, err) return 1 } - fmt.Println(t) + if err := gui.New().Run(t); err != nil { + log.Println(err) + return 1 + } } - return 0 }