
org.tinygroup.commons.tools.IndentableStringBuilder Maven / Gradle / Ivy
/**
* Copyright (c) 1997-2013, www.tinygroup.org ([email protected]).
*
* Licensed under the GPL, Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/gpl.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tinygroup.commons.tools;
import java.util.ArrayList;
import static org.tinygroup.commons.tools.Assert.assertTrue;
import static org.tinygroup.commons.tools.Assert.unreachableCode;
import static org.tinygroup.commons.tools.BasicConstant.EMPTY_STRING;
import static org.tinygroup.commons.tools.ObjectUtil.defaultIfNull;
import static org.tinygroup.commons.tools.StringUtil.isEmpty;
/**
* 支持分级缩进的string builder。
*
* @author renhui
*/
public class IndentableStringBuilder extends NormalizableStringBuilder {
private final IndentStack indents = new IndentStack();
private final int defaultIndent;
private int indentLevel;
private int quoteLevel;
private boolean lazyAppendNewLine; // 推迟输出换行,推迟到下一个字符被输出前
private boolean lazyStartHangingIndent; // 推迟启动缩进,推迟到下一个换行后或下一个start()。其效果为悬挂缩进
private int hangingIndent;
public IndentableStringBuilder() {
this(-1);
}
public IndentableStringBuilder(int indent) {
this.defaultIndent = indent <= 0 ? 2 : indent;
}
public void clear() {
super.clear();
indents.clear();
indentLevel = 0;
quoteLevel = 0;
lazyAppendNewLine = false;
lazyStartHangingIndent = false;
hangingIndent = 0;
}
/** 此处收到的字符中,所有 CR/LF/CRLF 均已被规格化成统一的LF了。 */
protected void visit(char c) {
boolean newLine = endsWithNewLine();
if (c == LF && lazyStartHangingIndent) {
appendInternalNewLine();
doStartHanglingIndentIfRequired();
return;
}
// 在end quote后追加换行
if (!newLine && lazyAppendNewLine) {
appendInternalNewLine();
newLine = true;
}
// 输出begin quotes
for (; quoteLevel < indentLevel; quoteLevel++) {
String beginQuote = indents.getBeginQuote(quoteLevel);
if (isEmpty(beginQuote)) {
if (!newLine && indents.independent(quoteLevel)) {
appendInternalNewLine();
newLine = true;
}
} else {
if (newLine) {
appendIndent(quoteLevel);
} else {
if (!endsWith(" ")) {
appendInternal(" "); // begin quote前空一格
}
}
appendInternal(beginQuote);
appendInternalNewLine();
newLine = true;
}
}
lazyAppendNewLine = false;
// 输出字符
if (c == LF) {
appendInternalNewLine();
} else {
if (newLine) {
appendIndent(indentLevel);
}
appendInternal(c);
}
}
/** 创建一级缩进。 */
public IndentableStringBuilder start() {
return start(null, null, -1);
}
/** 创建一级缩进。 */
public IndentableStringBuilder start(int indent) {
return start(null, null, indent);
}
/** 创建一级缩进,使用指定的前后括弧。 */
public IndentableStringBuilder start(String beginQuote, String endQuote) {
return start(beginQuote, endQuote, -1);
}
/** 创建一级缩进,使用指定的前后括弧。 */
public IndentableStringBuilder start(String beginQuote, String endQuote, int indent) {
doStartHanglingIndentIfRequired();
indents.pushIndent(beginQuote, endQuote, indent);
indentLevel++;
return this;
}
/** 从下一个换行或start()开始悬挂缩进。 */
public IndentableStringBuilder startHangingIndent() {
return startHangingIndent(0);
}
/** 从下一个换行或start()开始悬挂缩进。 */
public IndentableStringBuilder startHangingIndent(int indentOffset) {
doStartHanglingIndentIfRequired();
lazyStartHangingIndent = true;
if (!lazyAppendNewLine && lineLength() - currentIndent() > 0 && quoteLevel >= indentLevel) {
hangingIndent = defaultIndent(lineLength() - currentIndent() + indentOffset);
} else {
hangingIndent = defaultIndent(indentOffset);
}
return this;
}
/** 确保悬挂缩进(如果有的话)已经启动。 */
private void doStartHanglingIndentIfRequired() {
if (lazyStartHangingIndent) {
lazyStartHangingIndent = false;
start(EMPTY_STRING, EMPTY_STRING, hangingIndent);
}
}
/** 结束一级缩进。注意,输出结果之前,须至少调用一次end(),以确保最后的换行可以被输出。 */
public IndentableStringBuilder end() {
flush();
// 结束未发生的悬挂缩进
if (lazyStartHangingIndent) {
if (!endsWithNewLine()) {
lazyAppendNewLine = true;
}
lazyStartHangingIndent = false;
return this;
}
// 对于刚开始就结束的,不输出end quote
if (indentLevel > quoteLevel) {
indentLevel--;
} else {
assertTrue(indentLevel == quoteLevel, "indentLevel != quoteLevel");
if (indentLevel > 0) {
indentLevel--;
quoteLevel--;
String endQuote = indents.getEndQuote(indentLevel);
if (!isEmpty(endQuote)) {
// 确保end quote之前换行
if (!endsWithNewLine()) {
appendInternalNewLine();
}
// 输出end quote
appendIndent(indentLevel);
appendInternal(endQuote);
}
lazyAppendNewLine = true;
}
}
indents.popIndent();
return this;
}
/** 取得当前缩进的数量。 */
public int currentIndent() {
return indents.getCurrentIndent();
}
/** 如果indent未指定,则取得默认indent。 */
private int defaultIndent(int indent) {
return indent <= 0 ? defaultIndent : indent;
}
private void appendIndent(int indentLevel) {
int indent = indents.getIndent(indentLevel - 1);
for (int j = 0; j < indent; j++) {
appendInternal(' ');
}
}
/** 存放缩进信息的栈。 */
private class IndentStack extends ArrayList
© 2015 - 2025 Weber Informatics LLC | Privacy Policy