KCode.kt revision 6047998943beebd81e0ae1068df39c0cbee38628
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.set(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 public fun tab(vararg codes : KCode?) : KCode { 49 codes.forEach { tab(it) } 50 return this 51 } 52 53 public fun tab(codes : Collection<KCode?> ) : KCode { 54 codes.forEach { tab(it) } 55 return this 56 } 57 58 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 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 block(s : String, init : (KCode.() -> Unit)? = null) : KCode { 92 val c = KCode() 93 if (init != null) { 94 c.init() 95 } 96 return nl(s) { 97 app(" {") 98 tab(c) 99 nl("}") 100 } 101 } 102 103 fun app(glue : String = "", c : KCode?) : KCode { 104 if (isNull(c)) { 105 return this 106 } 107 nodes.add(Appendix(glue, c!!)) 108 return this 109 } 110 111 infix fun app(s : String) : KCode { 112 val c = KCode(s) 113 return app("", c) 114 } 115 116 fun app(glue : String = "", s : String?, init : (KCode.() -> Unit)? = null) : KCode { 117 val c = KCode(s) 118 if (init != null) { 119 c.init() 120 } 121 return app(glue, c) 122 } 123 124 125 fun toS(n : Int, sb : StringBuilder) { 126 if (s != null) { 127 sb.append(s) 128 } 129 val newlineFirstNode = s != null || (nodes.isNotEmpty() && nodes.first() is Appendix) 130 var addedChild = false 131 nodes.forEach { when(it) { 132 is Appendix -> { 133 sb.append(it.glue) 134 it.code.toS(n, sb) 135 } 136 is KCode -> { 137 val childTab = n + (if(it.sameLine) 0 else 1) 138 if (addedChild || newlineFirstNode) { 139 sb.append(lineSeparator) 140 } 141 if (!isNull(it)) { // avoid spaces for empty lines 142 if (it.s != null && it.s.trim() != "") { 143 sb.append("${indent(childTab)}") 144 } 145 it.toS(childTab, sb) 146 } 147 addedChild = true 148 } 149 } } 150 151 } 152 153 fun generate() : String { 154 val sb = StringBuilder() 155 toS(0, sb) 156 return sb.toString() 157 } 158} 159 160fun kcode(s : String?, init : (KCode.() -> Unit)? = null) : KCode { 161 val c = KCode(s) 162 if (init != null) { 163 c.init() 164 } 165 return c 166}