1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package optkl.codebuilders;
26
27 /**
28 * The base abstract class for a slew of fluent style builders.
29 * <p>
30 * At this level the builder just deals with basic appending, indenting, newline handling
31 *
32 * <pre>
33 * TextBuilder textBuilder = ....;
34 * textBuilder
35 * .nl()
36 * .in()
37 * .append("hello)
38 * .space()
39 * .append("world")
40 * .out();
41 *
42 * </pre>
43 *
44 * @author Gary Frost
45 */
46
47
48 public abstract class TextBuilder<T extends TextBuilder<T>> {
49 public static class State {
50 private final StringBuilder stringBuilder = new StringBuilder();
51 final public boolean indenting = true;
52 private int indent = 0;
53 private final String indentation = " ";
54 private boolean newLined = true;
55 public void indentation() {
56 for (int i = 0; i < indent; i++) {
57 stringBuilder.append(indentation);
58 }
59 }
60
61 public void indentIfNeededAndAppend(String text) {
62 if (indenting && newLined) {
63 indentation();
64 }
65 newLined = false;
66 stringBuilder.append(text);
67 }
68
69 public void preformatted(String text){
70 stringBuilder.append(text);
71 }
72
73 public void incIndent() {
74 indent++;
75 }
76 public void decIndent() {
77 indent--;
78 }
79
80 public void nl() {
81 newLined = true;
82 }
83
84 @Override
85 public String toString(){
86 return stringBuilder.toString();
87 }
88 }
89
90 private State state = new State();
91
92 public T clear() {
93 state = new State();
94 return self();
95 }
96
97 public String getText() {
98 return toString();
99 }
100
101
102
103 @SuppressWarnings("unchecked")
104 public T self() {
105 return (T) this;
106 }
107
108 private static String escape(char ch) {
109 return switch (ch) {
110 case '\b' -> "\\b";
111 case '\f' -> "\\f";
112 case '\n' -> "\\n";
113 case '\r' -> "\\r";
114 case '\t' -> "\\t";
115 case '\'' -> "\\'";
116 case '\"' -> "\\\"";
117 case '\\' -> "\\\\";
118 default -> (ch >= ' ' && ch <= '~') ? String.valueOf(ch) : String.format("\\u%04x", (int) ch);
119 };
120 }
121
122 public T escaped(String text) {
123 StringBuilder buf = new StringBuilder();
124 for (int i = 0; i < text.length(); i++) {
125 buf.append(escape(text.charAt(i)));
126 }
127 return emitText(buf.toString());
128 }
129
130 protected T emitText(String text) {
131 state.indentIfNeededAndAppend(text);
132 return self();
133 }
134
135 public T preformatted(String text){
136 state.preformatted(text);
137 return self();
138 }
139
140
141 public T identifier(String text, int padWidth) {
142 return emitText(text).emitText(" ".repeat(padWidth-text.length()));
143 }
144
145
146 public T intValue(int i) {
147 return emitText(Integer.toString(i));
148 }
149 public T intHexValue(int i) {
150 return emitText("0x").emitText(Integer.toHexString(i));
151 }
152
153 public final T literal(int i) {
154 return emitText(Integer.toString(i));
155 }
156
157 public final T literal(long i) {
158 return emitText(Long.toString(i));
159 }
160
161 public T in() {
162 state.incIndent();
163 return self();
164 }
165
166 public T out() {
167 state.decIndent();
168 return self();
169 }
170 public T nl() {
171 emitText("\n");
172 state.nl();
173 return self();
174 }
175 @Override
176 public final String toString() {
177 return state.toString();
178 }
179
180
181
182
183 }