1 /*
<lambda>null2 * 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.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
kcodenull160 fun 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 }