@@ -124,8 +124,26 @@ func displayMetaAsTable(meta map[string]interface{}) error {
124124}
125125
126126func displayObjectAsKeyValueTable (obj map [string ]interface {}) error {
127- t := table .New (os .Stdout )
128- t .SetHeaders ("Property" , "Value" )
127+ return displayAsTree (obj , "" , true )
128+ }
129+
130+ func displayAsTree (data interface {}, prefix string , isRoot bool ) error {
131+ switch v := data .(type ) {
132+ case map [string ]interface {}:
133+ return displayObjectAsTree (v , prefix , isRoot )
134+ case []interface {}:
135+ return displayArrayAsTree (v , prefix , isRoot )
136+ default :
137+ fmt .Printf ("%s%s\n " , prefix , formatValue (v ))
138+ return nil
139+ }
140+ }
141+
142+ func displayObjectAsTree (obj map [string ]interface {}, prefix string , isRoot bool ) error {
143+ if len (obj ) == 0 {
144+ fmt .Printf ("%s%s\n " , prefix , tml .Sprintf ("<italic>(empty object)</italic>" ))
145+ return nil
146+ }
129147
130148 // Get sorted keys
131149 keys := make ([]string , 0 , len (obj ))
@@ -134,41 +152,99 @@ func displayObjectAsKeyValueTable(obj map[string]interface{}) error {
134152 }
135153 sort .Strings (keys )
136154
137- for _ , key := range keys {
155+ for i , key := range keys {
156+ isLast := i == len (keys )- 1
138157 value := obj [key ]
139158
140- // Handle nested structures specially
141- switch v := value .(type ) {
142- case []interface {}:
143- if len (v ) == 0 {
144- t .AddRow (key , tml .Sprintf ("<italic>(empty array)</italic>" ))
145- } else if isArrayOfObjects (v ) {
146- // For arrays of objects, show a summary
147- t .AddRow (key , fmt .Sprintf ("Array[%d objects]" , len (v )))
159+ // Determine tree characters
160+ var keyPrefix , childPrefix string
161+ if isRoot {
162+ keyPrefix = ""
163+ childPrefix = ""
164+ } else {
165+ if isLast {
166+ keyPrefix = prefix + "└── "
167+ childPrefix = prefix + " "
148168 } else {
149- // For arrays of simple values, show them inline if short
150- if len (v ) <= 3 {
151- values := make ([]string , len (v ))
152- for i , item := range v {
153- values [i ] = formatValue (item )
154- }
155- t .AddRow (key , fmt .Sprintf ("[%s]" , strings .Join (values , ", " )))
156- } else {
157- t .AddRow (key , fmt .Sprintf ("Array[%d items]" , len (v )))
158- }
169+ keyPrefix = prefix + "├── "
170+ childPrefix = prefix + "│ "
159171 }
172+ }
173+
174+ // Display the key
175+ if isRoot {
176+ fmt .Printf ("%s:\n " , tml .Sprintf ("<bold>%s</bold>" , key ))
177+ } else {
178+ fmt .Printf ("%s%s: " , keyPrefix , tml .Sprintf ("<bold>%s</bold>" , key ))
179+ }
180+
181+ // Handle the value
182+ switch val := value .(type ) {
160183 case map [string ]interface {}:
161- if len (v ) == 0 {
162- t .AddRow (key , tml .Sprintf ("<italic>(empty object)</italic>" ))
184+ if ! isRoot {
185+ fmt .Print ("\n " )
186+ }
187+ if err := displayAsTree (val , childPrefix , false ); err != nil {
188+ return err
189+ }
190+ case []interface {}:
191+ if ! isRoot {
192+ fmt .Print ("\n " )
193+ }
194+ if err := displayAsTree (val , childPrefix , false ); err != nil {
195+ return err
196+ }
197+ default :
198+ if isRoot {
199+ fmt .Printf (" %s\n " , formatValue (val ))
163200 } else {
164- t .AddRow (key , fmt .Sprintf ("Object[%d properties]" , len (v )))
201+ fmt .Printf ("%s\n " , formatValue (val ))
202+ }
203+ }
204+ }
205+
206+ return nil
207+ }
208+
209+ func displayArrayAsTree (arr []interface {}, prefix string , isRoot bool ) error {
210+ if len (arr ) == 0 {
211+ fmt .Printf ("%s%s\n " , prefix , tml .Sprintf ("<italic>(empty array)</italic>" ))
212+ return nil
213+ }
214+
215+ for i , item := range arr {
216+ isLast := i == len (arr )- 1
217+
218+ // Determine tree characters
219+ var itemPrefix , childPrefix string
220+ if isLast {
221+ itemPrefix = prefix + "└── "
222+ childPrefix = prefix + " "
223+ } else {
224+ itemPrefix = prefix + "├── "
225+ childPrefix = prefix + "│ "
226+ }
227+
228+ // Display array index
229+ fmt .Printf ("%s[%d]: " , itemPrefix , i )
230+
231+ // Handle the item
232+ switch val := item .(type ) {
233+ case map [string ]interface {}:
234+ fmt .Print ("\n " )
235+ if err := displayAsTree (val , childPrefix , false ); err != nil {
236+ return err
237+ }
238+ case []interface {}:
239+ fmt .Print ("\n " )
240+ if err := displayAsTree (val , childPrefix , false ); err != nil {
241+ return err
165242 }
166243 default :
167- t . AddRow ( key , formatValue (value ))
244+ fmt . Printf ( "%s \n " , formatValue (val ))
168245 }
169246 }
170247
171- t .Render ()
172248 return nil
173249}
174250
@@ -280,16 +356,129 @@ func formatCellValue(value interface{}) string {
280356 return tml .Sprintf ("<cyan>%s</cyan>" , strconv .Itoa (v ))
281357 case int64 :
282358 return tml .Sprintf ("<cyan>%s</cyan>" , strconv .FormatInt (v , 10 ))
359+ case []interface {}, map [string ]interface {}:
360+ // For nested structures in table cells, format as tree string
361+ return formatNestedAsTreeString (v , "" )
362+ default :
363+ return fmt .Sprintf ("%v" , v )
364+ }
365+ }
366+
367+ // formatNestedAsTreeString formats nested structures as a compact tree string for table cells
368+ func formatNestedAsTreeString (data interface {}, prefix string ) string {
369+ var result strings.Builder
370+
371+ switch v := data .(type ) {
372+ case map [string ]interface {}:
373+ if len (v ) == 0 {
374+ return "{}"
375+ }
376+
377+ // Get sorted keys
378+ keys := make ([]string , 0 , len (v ))
379+ for key := range v {
380+ keys = append (keys , key )
381+ }
382+ sort .Strings (keys )
383+
384+ for i , key := range keys {
385+ isLast := i == len (keys )- 1
386+ var keyPrefix , childPrefix string
387+
388+ if isLast {
389+ keyPrefix = prefix + "└── "
390+ childPrefix = prefix + " "
391+ } else {
392+ keyPrefix = prefix + "├── "
393+ childPrefix = prefix + "│ "
394+ }
395+
396+ if i > 0 {
397+ result .WriteString ("\n " )
398+ }
399+
400+ value := v [key ]
401+ switch val := value .(type ) {
402+ case map [string ]interface {}, []interface {}:
403+ result .WriteString (fmt .Sprintf ("%s%s:" , keyPrefix , key ))
404+ result .WriteString ("\n " )
405+ result .WriteString (formatNestedAsTreeString (val , childPrefix ))
406+ default :
407+ // Format the whole node (key + value)
408+ nodeText := fmt .Sprintf ("%s%s: %s" , keyPrefix , key , formatValuePlain (val ))
409+ result .WriteString (truncateNodeIfNeeded (nodeText , keyPrefix , key , formatValuePlain (val )))
410+ }
411+ }
412+
283413 case []interface {}:
284414 if len (v ) == 0 {
285415 return "[]"
286416 }
287- return fmt .Sprintf ("[%d items]" , len (v ))
288- case map [string ]interface {}:
289- if len (v ) == 0 {
290- return "{}"
417+
418+ for i , item := range v {
419+ isLast := i == len (v )- 1
420+ var itemPrefix , childPrefix string
421+
422+ if isLast {
423+ itemPrefix = prefix + "└── "
424+ childPrefix = prefix + " "
425+ } else {
426+ itemPrefix = prefix + "├── "
427+ childPrefix = prefix + "│ "
428+ }
429+
430+ if i > 0 {
431+ result .WriteString ("\n " )
432+ }
433+
434+ switch val := item .(type ) {
435+ case map [string ]interface {}, []interface {}:
436+ result .WriteString (fmt .Sprintf ("%s[%d]:" , itemPrefix , i ))
437+ result .WriteString ("\n " )
438+ result .WriteString (formatNestedAsTreeString (val , childPrefix ))
439+ default :
440+ // Format the whole node (index + value)
441+ nodeText := fmt .Sprintf ("%s[%d]: %s" , itemPrefix , i , formatValuePlain (val ))
442+ result .WriteString (truncateNodeIfNeeded (nodeText , itemPrefix , fmt .Sprintf ("[%d]" , i ), formatValuePlain (val )))
443+ }
291444 }
292- return fmt .Sprintf ("{%d props}" , len (v ))
445+ }
446+
447+ return result .String ()
448+ }
449+
450+ // truncateNodeIfNeeded truncates the whole node if it's longer than 32 chars and the value contains spaces
451+ func truncateNodeIfNeeded (fullNode , prefix , label , value string ) string {
452+ // Check if the value (not the whole node) contains spaces
453+ if len (fullNode ) > 32 && strings .Contains (value , " " ) {
454+ return fullNode [:32 ] + "..."
455+ }
456+ return fullNode
457+ }
458+
459+ // formatValuePlain formats values without color codes for tree strings
460+ func formatValuePlain (value interface {}) string {
461+ if value == nil {
462+ return "null"
463+ }
464+
465+ switch v := value .(type ) {
466+ case string :
467+ if v == "" {
468+ return "(empty)"
469+ }
470+ return v
471+ case bool :
472+ return strconv .FormatBool (v )
473+ case float64 :
474+ if v == float64 (int64 (v )) {
475+ return strconv .FormatInt (int64 (v ), 10 )
476+ }
477+ return strconv .FormatFloat (v , 'f' , - 1 , 64 )
478+ case int :
479+ return strconv .Itoa (v )
480+ case int64 :
481+ return strconv .FormatInt (v , 10 )
293482 default :
294483 return fmt .Sprintf ("%v" , v )
295484 }
0 commit comments