mirror of
https://github.com/skanehira/tson
synced 2024-11-15 12:13:04 +00:00
Compare commits
No commits in common. "master" and "1.2.2" have entirely different histories.
29
README.md
29
README.md
@ -1,4 +1,3 @@
|
|||||||
# This repository is no longer to develop.
|
|
||||||
# tson
|
# tson
|
||||||
`tson` is JSON viewer and editor written in Go.
|
`tson` is JSON viewer and editor written in Go.
|
||||||
This tool displays JSON as a tree and you can search and edit key or values.
|
This tool displays JSON as a tree and you can search and edit key or values.
|
||||||
@ -27,32 +26,6 @@ $ curl -X POST http://gorilla/likes/regist | tson
|
|||||||
$ tson -url http://gorilla/likes/json
|
$ tson -url http://gorilla/likes/json
|
||||||
```
|
```
|
||||||
|
|
||||||
### Use `tson` as a library in your application
|
|
||||||
You can use tson in your application as following.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
tson "github.com/skanehira/tson/lib"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
j := []byte(`{"name":"gorilla"}`)
|
|
||||||
|
|
||||||
// tson.Edit([]byte) will return []byte, error
|
|
||||||
res, err := tson.Edit(j)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(string(res))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Keybinding
|
## Keybinding
|
||||||
### JSON tree
|
### JSON tree
|
||||||
|
|
||||||
@ -76,7 +49,7 @@ func main() {
|
|||||||
| e | edit json with $EDITOR |
|
| e | edit json with $EDITOR |
|
||||||
| q | quit tson |
|
| q | quit tson |
|
||||||
| Enter | edit node |
|
| Enter | edit node |
|
||||||
| / or f | search nodes |
|
| / | search nodes |
|
||||||
| ? | show helps |
|
| ? | show helps |
|
||||||
| space | expand/collaspe children nodes |
|
| space | expand/collaspe children nodes |
|
||||||
| ctrl-j | move to next parent node |
|
| ctrl-j | move to next parent node |
|
||||||
|
6
go.mod
6
go.mod
@ -6,10 +6,8 @@ require (
|
|||||||
github.com/creack/pty v1.1.9
|
github.com/creack/pty v1.1.9
|
||||||
github.com/gdamore/tcell v1.3.0
|
github.com/gdamore/tcell v1.3.0
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible
|
github.com/gofrs/uuid v3.2.0+incompatible
|
||||||
github.com/lucasb-eyer/go-colorful v1.0.3 // indirect
|
|
||||||
github.com/mattn/go-runewidth v0.0.6 // indirect
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/rivo/tview v0.0.0-20191129065140-82b05c9fb329
|
github.com/rivo/tview v0.0.0-20190324182152-8a9e26fab0ff
|
||||||
|
github.com/rivo/uniseg v0.1.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf
|
golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf
|
||||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect
|
|
||||||
)
|
)
|
||||||
|
12
go.sum
12
go.sum
@ -10,16 +10,14 @@ github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4
|
|||||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4=
|
github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4=
|
||||||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
||||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
|
||||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
|
||||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k=
|
|
||||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/rivo/tview v0.0.0-20191129065140-82b05c9fb329 h1:MubHhHJ4mB0A5wMcc2am0/51RydztIDoumyOd0r0yBw=
|
github.com/rivo/tview v0.0.0-20190324182152-8a9e26fab0ff h1:GrQgx8/nVONecTx4oGQ6O78pD8lVehvpQqeHGGPrCQM=
|
||||||
github.com/rivo/tview v0.0.0-20191129065140-82b05c9fb329/go.mod h1:/rBeY22VG2QprWnEqG57IBC8biVu3i0DOIjRLc9I8H0=
|
github.com/rivo/tview v0.0.0-20190324182152-8a9e26fab0ff/go.mod h1:J4W+hErFfITUbyFAEXizpmkuxX7ZN56dopxHB4XQhMw=
|
||||||
|
github.com/rivo/tview v0.0.0-20191018125527-685bf6da76c2 h1:GVXSfgXOMAeLvFH7IrpY3yYM8H3YekZEFcZ14q9gQXM=
|
||||||
|
github.com/rivo/tview v0.0.0-20191018125527-685bf6da76c2/go.mod h1:/rBeY22VG2QprWnEqG57IBC8biVu3i0DOIjRLc9I8H0=
|
||||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@ -33,8 +31,6 @@ golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeo
|
|||||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191018095205-727590c5006e h1:ZtoklVMHQy6BFRHkbG6JzK+S6rX82//Yeok1vMlizfQ=
|
golang.org/x/sys v0.0.0-20191018095205-727590c5006e h1:ZtoklVMHQy6BFRHkbG6JzK+S6rX82//Yeok1vMlizfQ=
|
||||||
golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
|
|
||||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
17
gui/gui.go
17
gui/gui.go
@ -150,7 +150,6 @@ func (g *Gui) LoadJSON() {
|
|||||||
log.Println(fmt.Sprintf("can't open file: %s", err))
|
log.Println(fmt.Sprintf("can't open file: %s", err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
i, err := UnMarshalJSON(file)
|
i, err := UnMarshalJSON(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -216,7 +215,7 @@ func (g *Gui) SaveJSONToFile(file string) error {
|
|||||||
enc := json.NewEncoder(&buf)
|
enc := json.NewEncoder(&buf)
|
||||||
enc.SetIndent("", " ")
|
enc.SetIndent("", " ")
|
||||||
|
|
||||||
if err := enc.Encode(g.MakeJSON(g.Tree.OriginRoot)); err != nil {
|
if err := enc.Encode(g.makeJSON(g.Tree.GetRoot())); err != nil {
|
||||||
log.Println(fmt.Sprintf("can't marshal json: %s", err))
|
log.Println(fmt.Sprintf("can't marshal json: %s", err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -229,7 +228,7 @@ func (g *Gui) SaveJSONToFile(file string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gui) MakeJSON(node *tview.TreeNode) interface{} {
|
func (g *Gui) makeJSON(node *tview.TreeNode) interface{} {
|
||||||
ref := node.GetReference().(Reference)
|
ref := node.GetReference().(Reference)
|
||||||
children := node.GetChildren()
|
children := node.GetChildren()
|
||||||
|
|
||||||
@ -237,25 +236,22 @@ func (g *Gui) MakeJSON(node *tview.TreeNode) interface{} {
|
|||||||
case Object:
|
case Object:
|
||||||
i := make(map[string]interface{})
|
i := make(map[string]interface{})
|
||||||
for _, n := range children {
|
for _, n := range children {
|
||||||
i[n.GetText()] = g.MakeJSON(n)
|
i[n.GetText()] = g.makeJSON(n)
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
case Array:
|
case Array:
|
||||||
var i []interface{}
|
var i []interface{}
|
||||||
for _, n := range children {
|
for _, n := range children {
|
||||||
i = append(i, g.MakeJSON(n))
|
i = append(i, g.makeJSON(n))
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
case Key:
|
case Key:
|
||||||
if len(node.GetChildren()) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
v := node.GetChildren()[0]
|
v := node.GetChildren()[0]
|
||||||
if v.GetReference().(Reference).JSONType == Value {
|
if v.GetReference().(Reference).JSONType == Value {
|
||||||
return g.parseValue(v)
|
return g.parseValue(v)
|
||||||
}
|
}
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
node.GetText(): g.MakeJSON(v),
|
node.GetText(): g.makeJSON(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +347,7 @@ func (g *Gui) EditWithEditor() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.Close()
|
f.Close()
|
||||||
|
defer os.RemoveAll(f.Name())
|
||||||
|
|
||||||
if err := g.SaveJSONToFile(f.Name()); err != nil {
|
if err := g.SaveJSONToFile(f.Name()); err != nil {
|
||||||
log.Println(fmt.Sprintf("can't write to temp file: %s", err))
|
log.Println(fmt.Sprintf("can't write to temp file: %s", err))
|
||||||
@ -422,7 +419,6 @@ func (g *Gui) EditWithEditor() {
|
|||||||
g.Message(err.Error(), "main", func() {})
|
g.Message(err.Error(), "main", func() {})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
i, err := UnMarshalJSON(f)
|
i, err := UnMarshalJSON(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -431,7 +427,6 @@ func (g *Gui) EditWithEditor() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
os.RemoveAll(f.Name())
|
|
||||||
g.Tree.UpdateView(g, i)
|
g.Tree.UpdateView(g, i)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ var (
|
|||||||
editNodes = fmt.Sprintf(RedColor, "e", " edit json with $EDITOR")
|
editNodes = fmt.Sprintf(RedColor, "e", " edit json with $EDITOR")
|
||||||
quitTson = fmt.Sprintf(RedColor, "q", " quit tson")
|
quitTson = fmt.Sprintf(RedColor, "q", " quit tson")
|
||||||
editNodeValue = fmt.Sprintf(RedColor, "Enter", "edit current node")
|
editNodeValue = fmt.Sprintf(RedColor, "Enter", "edit current node")
|
||||||
searchNodes = fmt.Sprintf(RedColor, "/ or f", " search nodes")
|
searchNodes = fmt.Sprintf(RedColor, "/", " search nodes")
|
||||||
toggleExpandNodes = fmt.Sprintf(RedColor, "space", " expand/collaspe nodes")
|
toggleExpandNodes = fmt.Sprintf(RedColor, "space", " expand/collaspe nodes")
|
||||||
moveNextParentNode = fmt.Sprintf(RedColor, "ctrl-j", "move to next parent node")
|
moveNextParentNode = fmt.Sprintf(RedColor, "ctrl-j", "move to next parent node")
|
||||||
movePreParentNode = fmt.Sprintf(RedColor, "ctrl-k", "move to previous parent node")
|
movePreParentNode = fmt.Sprintf(RedColor, "ctrl-k", "move to previous parent node")
|
||||||
|
32
gui/tree.go
32
gui/tree.go
@ -12,8 +12,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
moveNext int = iota + 1
|
moveToNext int = iota + 1
|
||||||
movePre
|
moveToPre
|
||||||
)
|
)
|
||||||
|
|
||||||
type Tree struct {
|
type Tree struct {
|
||||||
@ -67,15 +67,15 @@ func (t *Tree) AddNode(node interface{}) []*tview.TreeNode {
|
|||||||
case []interface{}:
|
case []interface{}:
|
||||||
for _, v := range node {
|
for _, v := range node {
|
||||||
id := uuid.Must(uuid.NewV4()).String()
|
id := uuid.Must(uuid.NewV4()).String()
|
||||||
switch v.(type) {
|
switch n := v.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
objectNode := tview.NewTreeNode("{object}").
|
r := reflect.ValueOf(n)
|
||||||
SetChildren(t.AddNode(v)).SetReference(Reference{ID: id, JSONType: Object})
|
if r.Kind() != reflect.Slice {
|
||||||
nodes = append(nodes, objectNode)
|
objectNode := tview.NewTreeNode("{object}").
|
||||||
case []interface{}:
|
SetChildren(t.AddNode(v)).SetReference(Reference{ID: id, JSONType: Object})
|
||||||
arrayNode := tview.NewTreeNode("{array}").
|
|
||||||
SetChildren(t.AddNode(v)).SetReference(Reference{ID: id, JSONType: Array})
|
nodes = append(nodes, objectNode)
|
||||||
nodes = append(nodes, arrayNode)
|
}
|
||||||
default:
|
default:
|
||||||
nodes = append(nodes, t.AddNode(v)...)
|
nodes = append(nodes, t.AddNode(v)...)
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ func (t *Tree) SetKeybindings(g *Gui) {
|
|||||||
g.LoadJSON()
|
g.LoadJSON()
|
||||||
case 's':
|
case 's':
|
||||||
g.SaveJSON()
|
g.SaveJSON()
|
||||||
case '/', 'f':
|
case '/':
|
||||||
g.Search()
|
g.Search()
|
||||||
case 'a':
|
case 'a':
|
||||||
g.AddNode()
|
g.AddNode()
|
||||||
@ -166,9 +166,9 @@ func (t *Tree) SetKeybindings(g *Gui) {
|
|||||||
|
|
||||||
switch event.Key() {
|
switch event.Key() {
|
||||||
case tcell.KeyCtrlJ:
|
case tcell.KeyCtrlJ:
|
||||||
t.moveNode(moveNext)
|
t.moveParent(moveToNext)
|
||||||
case tcell.KeyCtrlK:
|
case tcell.KeyCtrlK:
|
||||||
t.moveNode(movePre)
|
t.moveParent(moveToPre)
|
||||||
}
|
}
|
||||||
|
|
||||||
return event
|
return event
|
||||||
@ -189,19 +189,19 @@ func (t *Tree) CollapseValues(node *tview.TreeNode) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tree) moveNode(movement int) {
|
func (t *Tree) moveParent(movement int) {
|
||||||
current := t.GetCurrentNode()
|
current := t.GetCurrentNode()
|
||||||
t.GetRoot().Walk(func(node, parent *tview.TreeNode) bool {
|
t.GetRoot().Walk(func(node, parent *tview.TreeNode) bool {
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
children := parent.GetChildren()
|
children := parent.GetChildren()
|
||||||
for i, n := range children {
|
for i, n := range children {
|
||||||
if n.GetReference().(Reference).ID == current.GetReference().(Reference).ID {
|
if n.GetReference().(Reference).ID == current.GetReference().(Reference).ID {
|
||||||
if movement == moveNext {
|
if movement == moveToNext {
|
||||||
if i < len(children)-1 {
|
if i < len(children)-1 {
|
||||||
t.SetCurrentNode(children[i+1])
|
t.SetCurrentNode(children[i+1])
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else if movement == movePre {
|
} else if movement == moveToPre {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
t.SetCurrentNode(children[i-1])
|
t.SetCurrentNode(children[i-1])
|
||||||
return false
|
return false
|
||||||
|
28
lib/edit.go
28
lib/edit.go
@ -1,28 +0,0 @@
|
|||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/skanehira/tson/gui"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Edit use tson as a library
|
|
||||||
func Edit(b []byte) ([]byte, error) {
|
|
||||||
// dont output log
|
|
||||||
log.SetOutput(ioutil.Discard)
|
|
||||||
|
|
||||||
var i interface{}
|
|
||||||
if err := json.Unmarshal(b, &i); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
g := gui.New()
|
|
||||||
if err := g.Run(i); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Marshal(g.MakeJSON(g.Tree.GetRoot()))
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user