tson/gui/gui.go

247 lines
5.5 KiB
Go
Raw Normal View History

2019-10-29 17:28:25 +00:00
package gui
import (
2019-10-31 15:25:43 +00:00
"bytes"
2019-10-30 13:28:53 +00:00
"encoding/json"
"fmt"
"io/ioutil"
2019-10-29 17:28:25 +00:00
"log"
2019-10-30 13:28:53 +00:00
"os"
2019-11-01 07:41:49 +00:00
"strconv"
2019-10-30 15:15:56 +00:00
"strings"
2019-10-29 17:28:25 +00:00
2019-10-30 08:01:39 +00:00
"github.com/gdamore/tcell"
2019-10-29 17:28:25 +00:00
"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)
2019-10-30 08:01:39 +00:00
g.Tree.SetKeybindings(g)
2019-10-29 17:28:25 +00:00
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
}
2019-10-30 08:01:39 +00:00
2019-10-30 12:47:05 +00:00
func (g *Gui) Modal(p tview.Primitive, width, height int) tview.Primitive {
return tview.NewGrid().
SetColumns(0, width, 0).
SetRows(0, height, 0).
AddItem(p, 1, 1, 1, 1, 0, 0, true)
}
2019-10-30 13:28:53 +00:00
func (g *Gui) Message(message, page string, doneFunc func()) {
doneLabel := "ok"
modal := tview.NewModal().
SetText(message).
AddButtons([]string{doneLabel}).
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
g.Pages.RemovePage("message")
g.Pages.SwitchToPage(page)
if buttonLabel == doneLabel {
doneFunc()
}
})
g.Pages.AddAndSwitchToPage("message", g.Modal(modal, 80, 29), true).ShowPage("main")
}
2019-10-30 15:15:56 +00:00
func (g *Gui) Input(text, label string, doneFunc func(text string)) {
2019-10-30 08:01:39 +00:00
input := tview.NewInputField().SetText(text)
2019-10-30 12:47:05 +00:00
input.SetBorder(true)
2019-10-30 15:15:56 +00:00
input.SetLabel(label).SetLabelWidth(7).SetDoneFunc(func(key tcell.Key) {
2019-10-30 08:01:39 +00:00
if key == tcell.KeyEnter {
doneFunc(input.GetText())
2019-10-30 12:53:08 +00:00
g.Pages.RemovePage("input")
2019-10-30 08:01:39 +00:00
}
})
2019-10-30 12:47:05 +00:00
g.Pages.AddAndSwitchToPage("input", g.Modal(input, 0, 3), true).ShowPage("main")
2019-10-30 08:01:39 +00:00
}
2019-10-30 13:28:53 +00:00
func (g *Gui) LoadJSON() {
pageName := "read_from_file"
form := tview.NewForm()
2019-10-30 13:38:42 +00:00
form.AddInputField("file", "", 0, nil, nil).
2019-10-30 13:28:53 +00:00
AddButton("read", func() {
file := form.GetFormItem(0).(*tview.InputField).GetText()
file = os.ExpandEnv(file)
b, err := ioutil.ReadFile(file)
if err != nil {
msg := fmt.Sprintf("can't read file: %s", err)
log.Println(msg)
g.Message(msg, "main", func() {})
return
}
var i interface{}
if err := json.Unmarshal(b, &i); err != nil {
msg := fmt.Sprintf("can't read file: %s", err)
log.Println(msg)
g.Message(msg, "main", func() {})
return
}
g.Tree.UpdateView(g, i)
g.Pages.RemovePage(pageName)
}).
AddButton("cancel", func() {
g.Pages.RemovePage(pageName)
})
form.SetBorder(true).SetTitle("read from file").
SetTitleAlign(tview.AlignLeft)
g.Pages.AddAndSwitchToPage(pageName, g.Modal(form, 0, 8), true).ShowPage("main")
}
2019-10-30 15:15:56 +00:00
func (g *Gui) Search() {
pageName := "search"
if g.Pages.HasPage(pageName) {
g.Pages.ShowPage(pageName)
} else {
input := tview.NewInputField()
input.SetBorder(true).SetTitle("search").SetTitleAlign(tview.AlignLeft)
input.SetChangedFunc(func(text string) {
root := *g.Tree.OriginRoot
g.Tree.SetRoot(&root)
if text != "" {
root := g.Tree.GetRoot()
root.SetChildren(g.walk(root, text))
}
})
input.SetLabel("word").SetLabelWidth(5).SetDoneFunc(func(key tcell.Key) {
if key == tcell.KeyEnter {
g.Pages.HidePage(pageName)
}
})
g.Pages.AddAndSwitchToPage(pageName, g.Modal(input, 0, 3), true).ShowPage("main")
}
}
func (g *Gui) walk(node *tview.TreeNode, text string) []*tview.TreeNode {
var nodes []*tview.TreeNode
2019-10-30 15:25:04 +00:00
if strings.Index(strings.ToLower(node.GetText()), text) != -1 {
2019-10-30 15:15:56 +00:00
nodes = append(nodes, node)
return nodes
}
for _, node := range node.GetChildren() {
nodes = append(nodes, g.walk(node, text)...)
}
return nodes
}
2019-10-31 15:25:43 +00:00
func (g *Gui) SaveJSON() {
pageName := "save_to_file"
form := tview.NewForm()
form.AddInputField("file", "", 0, nil, nil).
AddButton("save", func() {
fileName := form.GetFormItem(0).(*tview.InputField).GetText()
fileName = os.ExpandEnv(fileName)
2019-11-01 07:41:49 +00:00
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
2019-10-31 15:25:43 +00:00
enc.SetIndent("", " ")
2019-11-01 07:41:49 +00:00
if err := enc.Encode(g.makeJSON(g.Tree.GetRoot())); err != nil {
msg := fmt.Sprintf("can't marshal json: %s", err)
2019-10-31 15:25:43 +00:00
log.Println(msg)
g.Message(msg, "main", func() {})
return
}
2019-11-01 07:41:49 +00:00
if err := ioutil.WriteFile(fileName, buf.Bytes(), 0666); err != nil {
2019-10-31 15:25:43 +00:00
msg := fmt.Sprintf("can't create file: %s", err)
log.Println(msg)
g.Message(msg, "main", func() {})
return
}
g.Pages.RemovePage(pageName)
}).
AddButton("cancel", func() {
g.Pages.RemovePage(pageName)
})
form.SetBorder(true).SetTitle("save to file").
SetTitleAlign(tview.AlignLeft)
g.Pages.AddAndSwitchToPage(pageName, g.Modal(form, 0, 8), true).ShowPage("main")
}
2019-11-01 07:41:49 +00:00
func (g *Gui) makeJSON(node *tview.TreeNode) interface{} {
nodeType := node.GetReference().(Type)
children := node.GetChildren()
switch nodeType {
case Root:
if len(children) == 1 {
return g.makeJSON(children[0])
} else {
var i []interface{}
for _, n := range children {
i = append(i, g.makeJSON(n))
}
return i
}
case Object:
i := make(map[string]interface{})
for _, n := range children {
i[n.GetText()] = g.makeJSON(n)
}
return i
case Array:
var i []interface{}
for _, n := range children {
i = append(i, g.makeJSON(n))
}
return i
case Key:
v := node.GetChildren()[0]
if v.GetReference().(Type) == Value {
return g.parseValue(v)
}
return map[string]interface{}{
node.GetText(): g.makeJSON(v),
}
}
return g.parseValue(node)
}
func (g *Gui) parseValue(node *tview.TreeNode) interface{} {
v := node.GetText()
if i, err := strconv.Atoi(v); err == nil {
return i
} else if f, err := strconv.ParseFloat(v, 64); err == nil {
return f
}
return v
}