| 
 | 1 | +package plotly.internals  | 
 | 2 | + | 
 | 3 | +import argonaut._  | 
 | 4 | +import argonaut.PrettyParams.vectorMemo  | 
 | 5 | + | 
 | 6 | +final case class BetterPrinter(params: PrettyParams) {  | 
 | 7 | + | 
 | 8 | +  import params._  | 
 | 9 | + | 
 | 10 | +  private def addIndentation(s: String): Int => String = {  | 
 | 11 | +    val lastNewLineIndex = s.lastIndexOf("\n")  | 
 | 12 | +    if (lastNewLineIndex < 0) {  | 
 | 13 | +      _ => s  | 
 | 14 | +    } else {  | 
 | 15 | +      val afterLastNewLineIndex = lastNewLineIndex + 1  | 
 | 16 | +      val start = s.substring(0, afterLastNewLineIndex)  | 
 | 17 | +      val end = s.substring(afterLastNewLineIndex)  | 
 | 18 | +      n => start + indent * n + end  | 
 | 19 | +    }  | 
 | 20 | +  }  | 
 | 21 | + | 
 | 22 | +  private val openBraceText = "{"  | 
 | 23 | +  private val closeBraceText = "}"  | 
 | 24 | +  private val openArrayText = "["  | 
 | 25 | +  private val closeArrayText = "]"  | 
 | 26 | +  private val commaText = ","  | 
 | 27 | +  private val colonText = ":"  | 
 | 28 | +  private val nullText = "null"  | 
 | 29 | +  private val trueText = "true"  | 
 | 30 | +  private val falseText = "false"  | 
 | 31 | +  private val stringEnclosureText = "\""  | 
 | 32 | + | 
 | 33 | +  private val _lbraceLeft = addIndentation(lbraceLeft)  | 
 | 34 | +  private val _lbraceRight = addIndentation(lbraceRight)  | 
 | 35 | +  private val _rbraceLeft = addIndentation(rbraceLeft)  | 
 | 36 | +  private val _rbraceRight = addIndentation(rbraceRight)  | 
 | 37 | +  private val _lbracketLeft = addIndentation(lbracketLeft)  | 
 | 38 | +  private val _lbracketRight = addIndentation(lbracketRight)  | 
 | 39 | +  private val _rbracketLeft = addIndentation(rbracketLeft)  | 
 | 40 | +  private val _rbracketRight = addIndentation(rbracketRight)  | 
 | 41 | +  private val _lrbracketsEmpty = addIndentation(lrbracketsEmpty)  | 
 | 42 | +  private val _arrayCommaLeft = addIndentation(arrayCommaLeft)  | 
 | 43 | +  private val _arrayCommaRight = addIndentation(arrayCommaRight)  | 
 | 44 | +  private val _objectCommaLeft = addIndentation(objectCommaLeft)  | 
 | 45 | +  private val _objectCommaRight = addIndentation(objectCommaRight)  | 
 | 46 | +  private val _colonLeft = addIndentation(colonLeft)  | 
 | 47 | +  private val _colonRight = addIndentation(colonRight)  | 
 | 48 | + | 
 | 49 | +  private val lbraceMemo = vectorMemo{depth: Int => "%s%s%s".format(_lbraceLeft(depth), openBraceText, _lbraceRight(depth + 1))}  | 
 | 50 | +  private val rbraceMemo = vectorMemo{depth: Int => "%s%s%s".format(_rbraceLeft(depth), closeBraceText, _rbraceRight(depth + 1))}  | 
 | 51 | + | 
 | 52 | +  private val lbracketMemo = vectorMemo{depth: Int => "%s%s%s".format(_lbracketLeft(depth), openArrayText, _lbracketRight(depth + 1))}  | 
 | 53 | +  private val rbracketMemo = vectorMemo{depth: Int => "%s%s%s".format(_rbracketLeft(depth), closeArrayText, _rbracketRight(depth))}  | 
 | 54 | +  private val lrbracketsEmptyMemo = vectorMemo{depth: Int => "%s%s%s".format(openArrayText, _lrbracketsEmpty(depth), closeArrayText)}  | 
 | 55 | +  private val arrayCommaMemo = vectorMemo{depth: Int => "%s%s%s".format(_arrayCommaLeft(depth + 1), commaText, _arrayCommaRight(depth + 1))}  | 
 | 56 | +  private val objectCommaMemo = vectorMemo{depth: Int => "%s%s%s".format(_objectCommaLeft(depth + 1), commaText, _objectCommaRight(depth + 1))}  | 
 | 57 | +  private val colonMemo = vectorMemo{depth: Int => "%s%s%s".format(_colonLeft(depth + 1), colonText, _colonRight(depth + 1))}  | 
 | 58 | + | 
 | 59 | +  /**  | 
 | 60 | +    * Returns a string representation of a pretty-printed JSON value.  | 
 | 61 | +    */  | 
 | 62 | +  def render(j: Json): String = {  | 
 | 63 | + | 
 | 64 | +    import Json._  | 
 | 65 | +    import StringEscaping._  | 
 | 66 | + | 
 | 67 | +    def appendJsonString(builder: StringBuilder, jsonString: String): StringBuilder = {  | 
 | 68 | +      for (c <- jsonString) {  | 
 | 69 | +        if (isNormalChar(c))  | 
 | 70 | +          builder += c  | 
 | 71 | +        else  | 
 | 72 | +          builder.append(escape(c))  | 
 | 73 | +      }  | 
 | 74 | + | 
 | 75 | +      builder  | 
 | 76 | +    }  | 
 | 77 | + | 
 | 78 | +    def encloseJsonString(builder: StringBuilder, jsonString: JsonString): StringBuilder = {  | 
 | 79 | +      appendJsonString(builder.append(stringEnclosureText), jsonString).append(stringEnclosureText)  | 
 | 80 | +    }  | 
 | 81 | + | 
 | 82 | +    def trav(builder: StringBuilder, depth: Int, k: Json): StringBuilder = {  | 
 | 83 | + | 
 | 84 | +      def lbrace(builder: StringBuilder): StringBuilder = {  | 
 | 85 | +        builder.append(lbraceMemo(depth))  | 
 | 86 | +      }  | 
 | 87 | +      def rbrace(builder: StringBuilder): StringBuilder = {  | 
 | 88 | +        builder.append(rbraceMemo(depth))  | 
 | 89 | +      }  | 
 | 90 | +      def lbracket(builder: StringBuilder): StringBuilder = {  | 
 | 91 | +        builder.append(lbracketMemo(depth))  | 
 | 92 | +      }  | 
 | 93 | +      def rbracket(builder: StringBuilder): StringBuilder = {  | 
 | 94 | +        builder.append(rbracketMemo(depth))  | 
 | 95 | +      }  | 
 | 96 | +      def lrbracketsEmpty(builder: StringBuilder): StringBuilder = {  | 
 | 97 | +        builder.append(lrbracketsEmptyMemo(depth))  | 
 | 98 | +      }  | 
 | 99 | +      def arrayComma(builder: StringBuilder): StringBuilder = {  | 
 | 100 | +        builder.append(arrayCommaMemo(depth))  | 
 | 101 | +      }  | 
 | 102 | +      def objectComma(builder: StringBuilder): StringBuilder = {  | 
 | 103 | +        builder.append(objectCommaMemo(depth))  | 
 | 104 | +      }  | 
 | 105 | +      def colon(builder: StringBuilder): StringBuilder = {  | 
 | 106 | +        builder.append(colonMemo(depth))  | 
 | 107 | +      }  | 
 | 108 | + | 
 | 109 | +      k.fold[StringBuilder](  | 
 | 110 | +        builder.append(nullText)  | 
 | 111 | +        , bool => builder.append(if (bool) trueText else falseText)  | 
 | 112 | +        , n => n match {  | 
 | 113 | +          case JsonLong(x) => builder append x.toString  | 
 | 114 | +          case JsonDecimal(x) => builder append x  | 
 | 115 | +          case JsonBigDecimal(x) => builder append x.toString  | 
 | 116 | +        }  | 
 | 117 | +        , s => encloseJsonString(builder, s)  | 
 | 118 | +        , e => if (e.isEmpty) {  | 
 | 119 | +          lrbracketsEmpty(builder)  | 
 | 120 | +        } else {  | 
 | 121 | +          rbracket(e.foldLeft((true, lbracket(builder))){case ((firstElement, builder), subElement) =>  | 
 | 122 | +            val withComma = if (firstElement) builder else arrayComma(builder)  | 
 | 123 | +            val updatedBuilder = trav(withComma, depth + 1, subElement)  | 
 | 124 | +            (false, updatedBuilder)  | 
 | 125 | +          }._2)  | 
 | 126 | +        }  | 
 | 127 | +        , o => {  | 
 | 128 | +          rbrace((if (preserveOrder) o.toList else o.toMap).foldLeft((true, lbrace(builder))){case ((firstElement, builder), (key, value)) =>  | 
 | 129 | +            val ignoreKey = dropNullKeys && value.isNull  | 
 | 130 | +            if (ignoreKey) {  | 
 | 131 | +              (firstElement, builder)  | 
 | 132 | +            } else {  | 
 | 133 | +              val withComma = if (firstElement) builder else objectComma(builder)  | 
 | 134 | +              (false, trav(colon(encloseJsonString(withComma, key)), depth + 1, value))  | 
 | 135 | +            }  | 
 | 136 | +          }._2)  | 
 | 137 | +        }  | 
 | 138 | +      )  | 
 | 139 | +    }  | 
 | 140 | + | 
 | 141 | +    trav(new StringBuilder(), 0, j).toString()  | 
 | 142 | +  }  | 
 | 143 | + | 
 | 144 | +}  | 
0 commit comments