github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/pkg/jsoncolor/jsoncolor.go (about)

     1  package jsoncolor
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"strings"
     8  )
     9  
    10  const (
    11  	colorDelim  = "1;38" // bright white
    12  	colorKey    = "1;34" // bright blue
    13  	colorNull   = "36"   // cyan
    14  	colorString = "32"   // green
    15  	colorBool   = "33"   // yellow
    16  )
    17  
    18  // Write colorized JSON output parsed from reader
    19  func Write(w io.Writer, r io.Reader, indent string) error {
    20  	dec := json.NewDecoder(r)
    21  	dec.UseNumber()
    22  
    23  	var idx int
    24  	var stack []json.Delim
    25  
    26  	for {
    27  		t, err := dec.Token()
    28  		if err == io.EOF {
    29  			break
    30  		}
    31  		if err != nil {
    32  			return err
    33  		}
    34  
    35  		switch tt := t.(type) {
    36  		case json.Delim:
    37  			switch tt {
    38  			case '{', '[':
    39  				stack = append(stack, tt)
    40  				idx = 0
    41  				fmt.Fprintf(w, "\x1b[%sm%s\x1b[m", colorDelim, tt)
    42  				if dec.More() {
    43  					fmt.Fprint(w, "\n", strings.Repeat(indent, len(stack)))
    44  				}
    45  				continue
    46  			case '}', ']':
    47  				stack = stack[:len(stack)-1]
    48  				idx = 0
    49  				fmt.Fprintf(w, "\x1b[%sm%s\x1b[m", colorDelim, tt)
    50  			}
    51  		default:
    52  			b, err := json.Marshal(tt)
    53  			if err != nil {
    54  				return err
    55  			}
    56  
    57  			isKey := len(stack) > 0 && stack[len(stack)-1] == '{' && idx%2 == 0
    58  			idx++
    59  
    60  			var color string
    61  			if isKey {
    62  				color = colorKey
    63  			} else if tt == nil {
    64  				color = colorNull
    65  			} else {
    66  				switch t.(type) {
    67  				case string:
    68  					color = colorString
    69  				case bool:
    70  					color = colorBool
    71  				}
    72  			}
    73  
    74  			if color == "" {
    75  				_, _ = w.Write(b)
    76  			} else {
    77  				fmt.Fprintf(w, "\x1b[%sm%s\x1b[m", color, b)
    78  			}
    79  
    80  			if isKey {
    81  				fmt.Fprintf(w, "\x1b[%sm:\x1b[m ", colorDelim)
    82  				continue
    83  			}
    84  		}
    85  
    86  		if dec.More() {
    87  			fmt.Fprintf(w, "\x1b[%sm,\x1b[m\n%s", colorDelim, strings.Repeat(indent, len(stack)))
    88  		} else if len(stack) > 0 {
    89  			fmt.Fprint(w, "\n", strings.Repeat(indent, len(stack)-1))
    90  		} else {
    91  			fmt.Fprint(w, "\n")
    92  		}
    93  	}
    94  
    95  	return nil
    96  }