From 2e25c7e7949d0680829645aa24cb356635c3b731 Mon Sep 17 00:00:00 2001 From: Anton Medvedev Date: Fri, 10 Nov 2023 19:51:24 +0100 Subject: [PATCH] Add support for json streams in interactive more --- json.go | 16 ++++++++++++---- main.go | 33 ++++++++++++++++++++++++++++++--- node.go | 11 +++++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/json.go b/json.go index 7508f9a..96c50e2 100644 --- a/json.go +++ b/json.go @@ -15,7 +15,7 @@ type jsonParser struct { skipFirstIdent bool } -func parse(data []byte) (line *node, err error) { +func parse(data []byte) (head *node, err error) { p := &jsonParser{ data: data, lineNumber: 1, @@ -27,9 +27,17 @@ func parse(data []byte) (line *node, err error) { } }() p.next() - line = p.parseValue() - if p.lastChar != 0 { - panic(fmt.Sprintf("Unexpected character %q after root node", p.lastChar)) + var next *node + for p.lastChar != 0 { + value := p.parseValue() + if head == nil { + head = value + next = head + } else { + value.index = -1 + next.adjacent(value) + next = value + } } return } diff --git a/main.go b/main.go index 3d7057a..ab38177 100644 --- a/main.go +++ b/main.go @@ -444,14 +444,30 @@ func (m *model) handleKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { m.showCursor = true case key.Matches(msg, keyMap.CollapseAll): - m.top.collapseRecursively() + n := m.top + for n != nil { + n.collapseRecursively() + if n.end == nil { + n = nil + } else { + n = n.end.next + } + } m.cursor = 0 m.head = m.top m.showCursor = true case key.Matches(msg, keyMap.ExpandAll): at := m.cursorPointsTo() - m.top.expandRecursively() + n := m.top + for n != nil { + n.expandRecursively() + if n.end == nil { + n = nil + } else { + n = n.end.next + } + } m.selectNode(at) case key.Matches(msg, keyMap.ToggleWrap): @@ -851,7 +867,7 @@ func (m *model) cursorKey() string { } func (m *model) selectByPath(path []any) *node { - n := m.top + n := m.currentTopNode() for _, part := range path { if n == nil { return nil @@ -866,6 +882,17 @@ func (m *model) selectByPath(path []any) *node { return n } +func (m *model) currentTopNode() *node { + at := m.cursorPointsTo() + if at == nil { + return nil + } + for at.parent() != nil { + at = at.parent() + } + return at +} + func (m *model) doSearch(s string) { m.search = newSearch() diff --git a/node.go b/node.go index 2925b0d..ac5eca4 100644 --- a/node.go +++ b/node.go @@ -20,6 +20,7 @@ type node struct { index int } +// append ands a node as a child to the current node (body of {...} or [...]). func (n *node) append(child *node) { if n.end == nil { n.end = n @@ -33,6 +34,16 @@ func (n *node) append(child *node) { } } +// adjacent adds a node as a sibling to the current node ({}{}{} or [][][]). +func (n *node) adjacent(child *node) { + end := n.end + if end == nil { + end = n + } + end.next = child + child.prev = end +} + func (n *node) insertChunk(chunk *node) { if n.chunkEnd == nil { n.insertAfter(chunk)