Skip to content
This repository has been archived by the owner on Apr 11, 2022. It is now read-only.

Commit

Permalink
adds tree structure drawing
Browse files Browse the repository at this point in the history
  • Loading branch information
gulyasm committed Mar 26, 2018
1 parent 860f258 commit eeb3ea4
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 26 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
default: build

installdep:
@go get -u github.com/golang/lint/golint
@go get -u
@go get github.com/golang/lint/golint
@go get

build: installdep
@go fmt
Expand Down
16 changes: 12 additions & 4 deletions jsonui.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (vp viewPosition) getCoordinates(maxX, maxY int) (int, int, int, int) {
return x0, y0, x1, y1
}

var helpWindowToggle bool = false
var helpWindowToggle = false

var viewPositions = map[string]viewPosition{
treeView: {
Expand Down Expand Up @@ -254,6 +254,14 @@ func getLine(s string, y int) string {
return lines[y]
}

var cleanPatterns = []string{
treeSignUpEnding,
treeSignDash,
treeSignUpMiddle,
treeSignVertical,
" (+)",
}

func findTreePosition(v *gocui.View) treePosition {
path := treePosition{}
ci := -1
Expand All @@ -263,10 +271,10 @@ func findTreePosition(v *gocui.View) treePosition {
s := v.Buffer()
for cy := y; cy >= 0; cy-- {
line := getLine(s, cy)

if strings.TrimSpace(line) == "+ ..." {
continue
for _, pattern := range cleanPatterns {
line = strings.Replace(line, pattern, "", -1)
}

if count := countIndex(line); count < ci || ci == -1 {
path = append(path, strings.TrimSpace(line))
ci = count
Expand Down
124 changes: 105 additions & 19 deletions tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ import (
"strings"
)

const (
treeSignDash = "─"
treeSignVertical = "│"
treeSignUpMiddle = "├"
treeSignUpEnding = "└"
)

type treePosition []string

func (t treePosition) empty() bool {
Expand All @@ -35,18 +42,26 @@ type treeNode interface {
draw(io.Writer, int, int) error
filter(query query) bool
find(treePosition) treeNode
search(query string) (treeNode, error)
isCollapsable() bool
toggleExpanded()
isExpanded() bool
}

type baseTreeNode struct {
isExpanded bool
expanded bool
}

func (n *baseTreeNode) isExpanded() bool {
return n.expanded
}

func (n *baseTreeNode) toggleExpanded() {
n.isExpanded = !n.isExpanded
n.expanded = !n.expanded
}

func (n baseTreeNode) expIcon() string {
if n.isExpanded {
if n.expanded {
return "[+]"
}
return "[-]"
Expand All @@ -57,6 +72,21 @@ type complexNode struct {
data map[string]treeNode
}

func (n complexNode) isCollapsable() bool {
return true
}
func (n complexNode) search(query string) (treeNode, error) {
filteredNode := &complexNode{
baseTreeNode{true},
map[string]treeNode{},
}
for key, value := range n.data {
if key == query {
filteredNode.data[key] = value
}
}
return filteredNode, nil
}
func (n complexNode) find(tp treePosition) treeNode {
if tp.empty() {
return &n
Expand Down Expand Up @@ -96,19 +126,35 @@ func (n complexNode) draw(writer io.Writer, padding, lvl int) error {
if lvl == 0 {
fmt.Fprintf(writer, "%s\n", "root")
}
if n.isExpanded {
keys := []string{}
for key := range n.data {
keys = append(keys, key)
keys := []string{}
for key := range n.data {
keys = append(keys, key)
}
sort.Strings(keys)
length := len(keys)
for i, key := range keys {
value, _ := n.data[key]
var char string
if i < length-1 {
char = treeSignUpMiddle
} else {
char = treeSignUpEnding
}
sort.Strings(keys)
for _, key := range keys {
value, _ := n.data[key]
fmt.Fprintf(writer, "%s%s\n", strings.Repeat(" ", padding+lvl*padding), key)
char += treeSignDash
expendedCharacter := ""
if value.isCollapsable() && !value.isExpanded() {
expendedCharacter += " (+)"
}
fmt.Fprintf(writer,
"%s%s %s%s\n",
strings.Repeat("│ ", lvl),
char,
key,
expendedCharacter,
)
if value.isExpanded() {
value.draw(writer, padding, lvl+1)
}
} else {
fmt.Fprintf(writer, "%s%s\n", strings.Repeat(" ", padding+lvl*padding), "+ ...")
}
return nil

Expand All @@ -123,6 +169,14 @@ type listNode struct {
data []treeNode
}

func (n listNode) isCollapsable() bool {
return true
}

func (n listNode) search(query string) (treeNode, error) {
return nil, nil

}
func (n listNode) find(tp treePosition) treeNode {
if tp.empty() {
return &n
Expand Down Expand Up @@ -153,15 +207,33 @@ func (n listNode) String(padding, lvl int) string {

func (n listNode) draw(writer io.Writer, padding, lvl int) error {
if lvl == 0 {
fmt.Fprintf(writer, "%s\n", "root (list)")
fmt.Fprintf(writer, "%s\n", "root")
}
if n.isExpanded {
for i, value := range n.data {
fmt.Fprintf(writer, "%s[%d]\n", strings.Repeat(" ", padding+lvl*padding), i)
length := len(n.data)
for i, value := range n.data {
var char string
if i < length-1 {
char = treeSignUpMiddle
} else {
char = treeSignUpEnding
}
char += treeSignDash
expendedCharacter := ""

if value.isCollapsable() && !value.isExpanded() {
expendedCharacter += " (+)"
}

fmt.Fprintf(writer,
"%s%s [%d]%s\n",
strings.Repeat("│ ", lvl),
char,
i,
expendedCharacter,
)
if value.isExpanded() {
value.draw(writer, padding, lvl+1)
}
} else {
fmt.Fprintf(writer, "%s%s\n", strings.Repeat(" ", padding+lvl*padding), "+ ...")
}
return nil

Expand All @@ -176,6 +248,12 @@ type floatNode struct {
data float64
}

func (n floatNode) isCollapsable() bool {
return false
}
func (n floatNode) search(query string) (treeNode, error) {
return nil, nil
}
func (n floatNode) find(tp treePosition) treeNode {
return nil

Expand All @@ -199,6 +277,10 @@ type stringNode struct {
data string
}

func (n stringNode) isCollapsable() bool {
return false
}

func (n stringNode) find(tp treePosition) treeNode {
return nil
}
Expand All @@ -207,6 +289,10 @@ func (n stringNode) String(_, _ int) string {
return fmt.Sprintf("%q", n.data)
}

func (n stringNode) search(query string) (treeNode, error) {
return nil, nil

}
func (n stringNode) draw(writer io.Writer, padding, lvl int) error {
//fmt.Fprintf(writer, "%s%q\n", strings.Repeat(" ", padding+padding*lvl), n.data)
return nil
Expand Down
47 changes: 47 additions & 0 deletions tree_search_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import "testing"

func TestSearchSimpleKeys(t *testing.T) {
raw := []byte(`{
"alma": "mu",
"name": "barack",
"age": 12,
"tags": ["good", "excellent", "ceu"]
}`)
tree, err := fromBytes(raw)
if err != nil {
t.Fatalf("failed to convert JSON to tree")
}
v, ok := tree.(*complexNode)
if !ok {
t.Fatalf("failed to convert tree to complexNode")
}

if len(v.data) != 4 {
t.Fatalf("root element should have 4 children")
}

subtree, err := tree.search("alma")
if err != nil {
t.Fatalf("failed to search tree: %q", err.Error())
}
if subtree == nil {
t.Fatalf("subtree returned nil")
}
v2, ok := subtree.(*complexNode)
if !ok {
t.Fatalf("failed to convert tree to complexNode")
}

if len(v2.data) != 1 {
t.Fatalf("searched subtree element should have 1 children")
}
anode, ok := v2.data["alma"]
if !ok {
t.Fatalf("first node should be alma node")
}
if anode.String(0, 0) != "\"mu\"" {
t.Fatalf("searched subtree element should be mu. Instead it was %q", anode.String(0, 0))
}
}
42 changes: 41 additions & 1 deletion tree_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,46 @@
package main

import "testing"
import (
"bytes"
"testing"
)

// TODO(gulyasm): write multi lvl draw
func TestDrawTree(t *testing.T) {
var json = []byte(`
{
"alma": 1,
"barack": {
"barack_1": 12,
"barack_2": "sdfsf",
"barack_3": [1,2,3],
"wazz_barack_4": "sdsfe"
},
"wazz": 1
}`)
var expected = `
root
├─ alma
├── barack
│ ├─ barack_1
│ ├─ barack_2
│ ├─ barack_3
│ │ ├─ [0]
│ │ ├─ [1]
│ │ └─ [2]
│ └─ wazz_barack_4
└── wazz
`
tree, err := fromBytes(json)
if err != nil {
t.Fatalf("failed to convert JSON to tree")
}
var result bytes.Buffer
tree.draw(&result, 2, 0)
if expected != result.String() {
t.Fatalf("tree drawing failed. Result tree:\n%s", result.String())
}
}

func TestListTree(t *testing.T) {
raw := []byte(`[1,234,35]`)
Expand Down

0 comments on commit eeb3ea4

Please sign in to comment.