KCode.kt revision af146d6a8c0efcf5682d14047c06866a5548f78f
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 14package android.databinding.tool.writer 15 16import android.databinding.tool.util.StringUtils 17import java.util.BitSet 18 19class 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 144fun 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