Home | History | Annotate | Download | only in writer
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  * Licensed under the Apache License, Version 2.0 (the "License");
      4  * you may not use this file except in compliance with the License.
      5  * You may obtain a copy of the License at
      6  *      http://www.apache.org/licenses/LICENSE-2.0
      7  * Unless required by applicable law or agreed to in writing, software
      8  * distributed under the License is distributed on an "AS IS" BASIS,
      9  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     10  * See the License for the specific language governing permissions and
     11  * limitations under the License.
     12  */
     13 
     14 package android.databinding.tool.writer
     15 
     16 import android.databinding.tool.util.StringUtils
     17 import java.util.BitSet
     18 
     19 class KCode (private val s : String? = null){
     20 
     21     private var sameLine = false
     22 
     23     private val lineSeparator = StringUtils.LINE_SEPARATOR
     24 
     25     class Appendix(val glue : String, val code : KCode)
     26 
     27     private val nodes = arrayListOf<Any>()
     28 
     29     companion object {
     30         private val cachedIndentations = BitSet()
     31         private val indentCache = arrayListOf<String>()
     32         fun indent(n: Int): String {
     33             if (cachedIndentations.get(n)) {
     34                 return indentCache[n]
     35             }
     36             val s = (0..n-1).fold(""){prev, next -> "$prev    "}
     37             cachedIndentations.set(n, true )
     38             while (indentCache.size <= n) {
     39                 indentCache.add("");
     40             }
     41             indentCache[n] = s
     42             return s
     43         }
     44     }
     45 
     46     fun isNull(kcode : KCode?) = kcode == null || (kcode.nodes.isEmpty() && (kcode.s == null || kcode.s.trim() == ""))
     47 
     48     fun tab(vararg codes : KCode?) : KCode {
     49         codes.forEach { tab(it) }
     50         return this
     51     }
     52 
     53     fun tab(codes : Collection<KCode?> ) : KCode {
     54         codes.forEach { tab(it) }
     55         return this
     56     }
     57 
     58     infix fun tab(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
     59         val c = KCode(s)
     60         if (init != null) {
     61             c.init()
     62         }
     63         return tab(c)
     64     }
     65 
     66     fun tab(c : KCode?) : KCode {
     67         if (c == null || isNull(c)) {
     68             return this
     69         }
     70         nodes.add(c)
     71         return this
     72     }
     73 
     74     infix fun nl(c : KCode?) : KCode {
     75         if (c == null || isNull(c)) {
     76             return this
     77         }
     78         nodes.add(c)
     79         c.sameLine = true
     80         return this
     81     }
     82 
     83     infix fun nl(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
     84         val c = KCode(s)
     85         if (init != null) {
     86             c.init()
     87         }
     88         return nl(c)
     89     }
     90 
     91     fun app(glue : String = "", c : KCode?) : KCode {
     92         if (isNull(c)) {
     93             return this
     94         }
     95         nodes.add(Appendix(glue, c!!))
     96         return this
     97     }
     98 
     99     infix fun app(s : String) : KCode {
    100         val c = KCode(s)
    101         return app("", c)
    102     }
    103 
    104     fun app(glue : String = "", s : String?, init : (KCode.() -> Unit)? = null) : KCode {
    105         val c = KCode(s)
    106         if (init != null) {
    107             c.init()
    108         }
    109         return app(glue, c)
    110     }
    111 
    112 
    113     fun toS(n : Int, sb : StringBuilder) {
    114         if (s != null) {
    115             sb.append(s)
    116         }
    117         val newlineFirstNode = s != null || (nodes.isNotEmpty() && nodes.first() is Appendix)
    118         var addedChild = false
    119         nodes.forEach { when(it) {
    120             is Appendix -> {
    121                 sb.append(it.glue)
    122                 it.code.toS(n, sb)
    123             }
    124             is KCode -> {
    125                 val childTab = n + (if(it.sameLine) 0 else 1)
    126                 if (addedChild || newlineFirstNode) {
    127                     sb.append(lineSeparator)
    128                     sb.append("${indent(childTab)}")
    129                 }
    130                 it.toS(childTab, sb)
    131                 addedChild = true
    132             }
    133         } }
    134 
    135     }
    136 
    137     fun generate() : String {
    138         val sb = StringBuilder()
    139         toS(0, sb)
    140         return sb.toString()
    141     }
    142 }
    143 
    144 fun kcode(s : String?, init : (KCode.() -> Unit)? = null) : KCode {
    145     val c = KCode(s)
    146     if (init != null) {
    147         c.init()
    148     }
    149     return c
    150 }
    151