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[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
kcodenull144 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