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 hat.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
50
51 public static class State {
52 private final StringBuilder stringBuilder = new StringBuilder();
53 final public boolean indenting = true;
54 private int indent = 0;
55 private final String indentation = " ";
56 private boolean newLined = true;
57 public void indentation() {
58 for (int i = 0; i < indent; i++) {
59 stringBuilder.append(indentation);
60 }
61 }
62
63 public void indentIfNeededAndAppend(String text) {
64 if (indenting && newLined) {
65 indentation();
66 }
67 newLined = false;
68 stringBuilder.append(text);
69 }
70
71 public void preformatted(String text){
72 stringBuilder.append(text);
73 }
74
75 public void incIndent() {
76 indent++;
77 }
78 public void decIndent() {
79 indent--;
80 }
81
82 public void nl() {
83 newLined = true;
84 }
85
86 @Override
87 public String toString(){
88 return stringBuilder.toString();
89 }
90 }
91
92 private State state = new State();
93
94 public T clear() {
95 state = new State();
96 return self();
97 }
98
99 public String getText() {
100 return toString();
101 }
102
103
104
105 @SuppressWarnings("unchecked")
106 public T self() {
107 return (T) this;
108 }
109
110 private static String escape(char ch) {
111 return switch (ch) {
112 case '\b' -> "\\b";
113 case '\f' -> "\\f";
114 case '\n' -> "\\n";
115 case '\r' -> "\\r";
116 case '\t' -> "\\t";
117 case '\'' -> "\\'";
118 case '\"' -> "\\\"";
119 case '\\' -> "\\\\";
120 default -> (ch >= ' ' && ch <= '~') ? String.valueOf(ch) : String.format("\\u%04x", (int) ch);
121 };
122 }
123
124 public T escaped(String text) {
125 StringBuilder buf = new StringBuilder();
126 for (int i = 0; i < text.length(); i++) {
127 buf.append(escape(text.charAt(i)));
128 }
129 return emitText(text);
130 }
131
132 T emitText(String text) {
133 state.indentIfNeededAndAppend(text);
134 return self();
135 }
136
137 public T preformatted(String text){
138 state.preformatted(text);
139 return self();
140 }
141
142
143 public T identifier(String text, int padWidth) {
144 return emitText(text).emitText(" ".repeat(padWidth-text.length()));
145 }
146
147
148 public T intValue(int i) {
149 return emitText(Integer.toString(i));
150 }
151 public T intHexValue(int i) {
152 return emitText("0x").emitText(Integer.toHexString(i));
153 }
154
155 public final T literal(int i) {
156 return emitText(Integer.toString(i));
157 }
158
159 public final T literal(long i) {
160 return emitText(Long.toString(i));
161 }
162
163 public T in() {
164 state.incIndent();
165 return self();
166 }
167
168 public T out() {
169 state.decIndent();
170 return self();
171 }
172 public T nl() {
173 emitText("\n");
174 state.nl();
175 return self();
176 }
177 @Override
178 public final String toString() {
179 return state.toString();
180 }
181
182
183
184
185 }