138 | 138 |
edge = EdgeTypeEnd
|
139 | 139 |
levelsEnded = append(levelsEnded, level)
|
140 | 140 |
}
|
141 | |
printValues(buf, 0, levelsEnded, edge, n.Meta, n.Value)
|
|
141 |
printValues(buf, 0, levelsEnded, edge, n)
|
142 | 142 |
}
|
143 | 143 |
if len(n.Nodes) > 0 {
|
144 | 144 |
printNodes(buf, level, levelsEnded, n.Nodes)
|
|
167 | 167 |
levelsEnded = append(levelsEnded, level)
|
168 | 168 |
edge = EdgeTypeEnd
|
169 | 169 |
}
|
170 | |
printValues(wr, level, levelsEnded, edge, node.Meta, node.Value)
|
|
170 |
printValues(wr, level, levelsEnded, edge, node)
|
171 | 171 |
if len(node.Nodes) > 0 {
|
172 | 172 |
printNodes(wr, level+1, levelsEnded, node.Nodes)
|
173 | 173 |
}
|
|
175 | 175 |
}
|
176 | 176 |
|
177 | 177 |
func printValues(wr io.Writer,
|
178 | |
level int, levelsEnded []int, edge EdgeType, meta MetaValue, val Value) {
|
|
178 |
level int, levelsEnded []int, edge EdgeType, node *node) {
|
179 | 179 |
|
180 | 180 |
for i := 0; i < level; i++ {
|
181 | 181 |
if isEnded(levelsEnded, i) {
|
|
184 | 184 |
}
|
185 | 185 |
fmt.Fprintf(wr, "%s%s", EdgeTypeLink, strings.Repeat(" ", IndentSize))
|
186 | 186 |
}
|
|
187 |
|
|
188 |
val := renderValue(level, node)
|
|
189 |
meta := node.Meta
|
|
190 |
|
187 | 191 |
if meta != nil {
|
188 | 192 |
fmt.Fprintf(wr, "%s [%v] %v\n", edge, meta, val)
|
189 | 193 |
return
|
|
198 | 202 |
}
|
199 | 203 |
}
|
200 | 204 |
return false
|
|
205 |
}
|
|
206 |
|
|
207 |
func renderValue(level int, node *node) Value {
|
|
208 |
lines := strings.Split(fmt.Sprintf("%v", node.Value), "\n")
|
|
209 |
|
|
210 |
// If value does not contain multiple lines, return itself.
|
|
211 |
if len(lines) < 2 {
|
|
212 |
return node.Value
|
|
213 |
}
|
|
214 |
|
|
215 |
// If value contains multiple lines,
|
|
216 |
// generate a padding and prefix each line with it.
|
|
217 |
pad := padding(level, node)
|
|
218 |
|
|
219 |
for i := 1; i < len(lines); i++ {
|
|
220 |
lines[i] = fmt.Sprintf("%s%s", pad, lines[i])
|
|
221 |
}
|
|
222 |
|
|
223 |
return strings.Join(lines, "\n")
|
|
224 |
}
|
|
225 |
|
|
226 |
// padding returns a padding for the multiline values with correctly placed link edges.
|
|
227 |
// It is generated by traversing the tree upwards (from leaf to the root of the tree)
|
|
228 |
// and, on each level, checking if the node the last one of its siblings.
|
|
229 |
// If a node is the last one, the padding on that level should be empty (there's nothing to link to below it).
|
|
230 |
// If a node is not the last one, the padding on that level should be the link edge so the sibling below is correctly connected.
|
|
231 |
func padding(level int, node *node) string {
|
|
232 |
links := make([]string, level+1)
|
|
233 |
|
|
234 |
for node.Root != nil {
|
|
235 |
if isLast(node) {
|
|
236 |
links[level] = strings.Repeat(" ", IndentSize+1)
|
|
237 |
} else {
|
|
238 |
links[level] = fmt.Sprintf("%s%s", EdgeTypeLink, strings.Repeat(" ", IndentSize))
|
|
239 |
}
|
|
240 |
level--
|
|
241 |
node = node.Root
|
|
242 |
}
|
|
243 |
|
|
244 |
return strings.Join(links, "")
|
|
245 |
}
|
|
246 |
|
|
247 |
// isLast checks if the node is the last one in the slice of its parent children
|
|
248 |
func isLast(n *node) bool {
|
|
249 |
return n == n.Root.FindLastNode()
|
201 | 250 |
}
|
202 | 251 |
|
203 | 252 |
type EdgeType string
|