diff --git a/app/src/processing/mode/java/AutoFormat.java b/app/src/processing/mode/java/AutoFormat.java index 91d8a7cecd..db7b80a8ff 100644 --- a/app/src/processing/mode/java/AutoFormat.java +++ b/app/src/processing/mode/java/AutoFormat.java @@ -7,6 +7,7 @@ Original Copyright (c) 1997, 1998 Van Di-Han HO. All Rights Reserved. Updates Copyright (c) 2001 Jason Pell. Further updates Copyright (c) 2003 Martin Gomez, Ateneo de Manila University Additional updates Copyright (c) 2005-10 Ben Fry and Casey Reas + Even more updates Copyright (c) 2014 George Bateman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -48,50 +49,71 @@ public class AutoFormat implements Formatter { private final StringBuilder buf = new StringBuilder(); private final StringBuilder result = new StringBuilder(); + /** The number of spaces in one indent. Constant. */ private int indentValue; + + /** Set when the end of the chars array is reached. */ private boolean EOF; - private boolean a_flg, if_flg, s_flag, elseFlag; - + + private boolean inStatementFlag; // in a line of code + private boolean overflowFlag; // line overrunning? + private boolean startFlag; // No buf has yet been writen to this line. + private boolean if_flg; + private boolean elseFlag; + + /** -1 if not in array or if just after it, otherwise increases from 0. */ + private int arrayLevel; + private int arrayIndent; // Lowest value of the above for this line. + /** Number of ? entered without exiting at : of a?b:c structures. */ private int conditionalLevel; - - private int pos; - private int c_level; + private int[][] sp_flg; - private int[][] s_ind; + private boolean[][] s_ind; private int if_lev; - /** Number of curly brackets entered and not exited. */ + /** chars[pos] is where we're at. */ + private int pos; private int level; + /** Number of curly brackets entered and not exited, + excluding arrays. */ + private int curlyLvl; + /** Number of parentheses entered and not exited. */ private int parenLevel; - - private int[] ind; + + private boolean[] ind; private int[] p_flg; - private char l_char; private int[][] s_tabs; + + /** At every {, this has a true pushed if it's a do-while, + and a false otherwise. It is then popped at }. */ + private Stack doWhileFlags; + + /** At every (, this has a true pushed for if, while, or for, + and a false otherwise. Popped at ). */ + private Stack ifWhileForFlags; + private boolean jdoc_flag; - private char cc; + + /** The number of times to indent at a given point */ private int tabs; - private char c; - private char lastNonWhitespace = 0; - private final Stack castFlags = new Stack(); + /** The last non-space seen by nextChar(). */ + private char lastNonWhitespace = 0; private void handleMultiLineComment() { - final boolean saved_s_flag = s_flag; + final boolean savedStartFlag = startFlag; + buf.append(nextChar()); // So /*/ isn't self-closing. - char ch; - buf.append(ch = nextChar()); // extra char - while (true) { - buf.append(ch = nextChar()); - while (ch != '/') { + for (char ch = nextChar(); !EOF; ch = nextChar()) { + buf.append(ch); + while (ch != '/' && !EOF) { if (ch == '\n') { -// lineNumber++; writeIndentedComment(); - s_flag = true; + startFlag = true; } buf.append(ch = nextChar()); } @@ -102,75 +124,53 @@ private void handleMultiLineComment() { } writeIndentedComment(); - s_flag = saved_s_flag; + startFlag = savedStartFlag; jdoc_flag = false; return; } - + + /** + * Pumps nextChar into buf until \n or EOF, then calls + * writeIndentedLine() and sets startFlag to true. + */ private void handleSingleLineComment() { char ch = nextChar(); - while (ch != '\n') { + while (ch != '\n' && !EOF) { buf.append(ch); ch = nextChar(); } -// lineNumber++; writeIndentedLine(); - s_flag = true; + startFlag = true; } - -// /** -// * Transfers buf to result until a character is reached that -// * is neither \, \n, or in a string. \n is not written, but -// * writeIndentedLine is called on finding it. -// * @return The first character not listed above. -// */ -// private char get_string() { -// char ch1, ch2; -// while (true) { -// buf.append(ch1 = nextChar()); -// if (ch1 == '\\') { -// buf.append(nextChar()); -// } else if (ch1 == '\'' || ch1 == '\"') { -// buf.append(ch2 = nextChar()); -// while (!EOF && ch2 != ch1) { -// if (ch2 == '\\') { -// // Next char is escaped, ignore. -// buf.append(nextChar()); -// } -// buf.append(ch2 = nextChar()); -// } -// } else if (ch1 == '\n') { -// writeIndentedLine(); -// a_flg = true; -// } else { -// return ch1; -// } -// } -// } - private void writeIndentedLine() { if (buf.length() == 0) { - if (s_flag) { - s_flag = a_flg = elseFlag = false; - } + if (startFlag) startFlag = elseFlag = false; return; } - if (s_flag) { - final boolean shouldIndent = - (tabs > 0) && (buf.charAt(0) != '{') && a_flg; - if (shouldIndent) { + if (startFlag) { + // Indent suppressed at eg. if{ and when + // buf is close-brackets only followed by ';'. + boolean indentMore = !buf.toString().matches("[\\s\\]\\}\\)]+;") + && (buf.charAt(0) != '{' || arrayLevel >= 0) + && overflowFlag; + if (indentMore) { tabs++; + if (arrayIndent > 0) tabs += arrayIndent; } printIndentation(); - s_flag = false; - if (shouldIndent) { + startFlag = false; + if (indentMore) { tabs--; + if (arrayIndent > 0) tabs -= arrayIndent; } - a_flg = false; } + if (lastNonSpaceChar() == '}' && bufStarts("else")) { + result.append(' '); + } + if (elseFlag) { if (lastNonSpaceChar() == '}') { trimRight(result); @@ -178,86 +178,105 @@ private void writeIndentedLine() { } elseFlag = false; } + + // If we're still in a statement at \n, that's overflow. + overflowFlag = inStatementFlag; + arrayIndent = arrayLevel; result.append(buf); + buf.setLength(0); } - + + /** + * @return the last character in result not ' ' or '\n'. + */ private char lastNonSpaceChar() { for (int i = result.length() - 1; i >= 0; i--) { - char c_i = result.charAt(i); - if (c_i != ' ' && c_i != '\n') return c_i; + char chI = result.charAt(i); + if (chI != ' ' && chI != '\n') return chI; } return 0; } + /** + * Called by handleMultilineComment.
+ * Sets jdoc_flag if at the start of a doc comment. + * Sends buf to result with proper indents, then clears buf.
+ * Does nothing if buf is empty. + */ private void writeIndentedComment() { - final boolean saved_s_flag = s_flag; - if (buf.length() > 0) { - if (s_flag) { - printIndentation(); - s_flag = false; - } - int i = 0; - while (buf.charAt(i) == ' ') { - i++; - } - if (lookup_com("/**")) { - jdoc_flag = true; + if (buf.length() == 0) return; + + int firstNonSpace = 0; + while (buf.charAt(firstNonSpace) == ' ') firstNonSpace++; + if (lookup_com("/**")) jdoc_flag = true; + + if (startFlag) printIndentation(); + + if (buf.charAt(firstNonSpace) == '/' && buf.charAt(firstNonSpace+1) == '*') { + if (startFlag && lastNonWhitespace != ';') { + result.append(buf.substring(firstNonSpace)); + } else { + result.append(buf); } - if (buf.charAt(i) == '/' && buf.charAt(i + 1) == '*') { - if (saved_s_flag && getLastNonWhitespace() != ';') { - result.append(buf.substring(i)); - } else { - result.append(buf); - } + } else { + if (buf.charAt(firstNonSpace) == '*' || !jdoc_flag) { + result.append(" " + buf.substring(firstNonSpace)); } else { - if (buf.charAt(i) == '*' || !jdoc_flag) { - result.append((" " + buf.substring(i))); - } else { - result.append((" * " + buf.substring(i))); - } + result.append(" * " + buf.substring(firstNonSpace)); } - buf.setLength(0); } + buf.setLength(0); } + /** + * Makes tabs >= 0 and appends tabs*indentValue + * spaces to result. + */ private void printIndentation() { - if (tabs < 0) { + if (tabs <= 0) { tabs = 0; - } - if (tabs == 0) { return; } final int spaces = tabs * indentValue; - for (int k = 0; k < spaces; k++) { + for (int i = 0; i < spaces; i++) { result.append(' '); } } + /** + * @return chars[pos+1] or '\0' if out-of-bounds. + */ private char peek() { - if (pos + 1 >= chars.length) { - return 0; - } - return chars[pos + 1]; + return (pos + 1 >= chars.length) ? 0 : chars[pos + 1]; } - private int getLastNonWhitespace() { - return lastNonWhitespace; - } - - - private void advanceToNonSpace() { - if (EOF) { - return; + /** + * Sets pos to the position of the next character that is not ' ' + * in chars. If chars[pos] != ' ' already, it will still move on. + * Then sets EOF if pos has reached the end, or reverses pos by 1 if it + * has not. + *
Does nothing if EOF. + * @param allWsp (boolean) Eat newlines too (all of Character.isWhiteSpace()). + */ + private void advanceToNonSpace(boolean allWsp) { + if (EOF) return; + + if (allWsp) { + do { + pos++; + } while (pos < chars.length && Character.isWhitespace(chars[pos])); + } else { + do { + pos++; + } while (pos < chars.length && chars[pos] == ' '); } - do { - pos++; - } while (pos < chars.length && chars[pos] == ' '); + if (pos == chars.length - 1) { EOF = true; } else { @@ -266,35 +285,44 @@ private void advanceToNonSpace() { } + /** + * Increments pos, sets EOF if needed, and returns the new + * chars[pos] or zero if out-of-bounds. + * Sets lastNonWhitespace if chars[pos] isn't whitespace. + * Does nothing and returns zero if already at EOF. + */ private char nextChar() { - if (EOF) { - return '\0'; - } + if (EOF) return 0; pos++; - char retVal; - if (pos < chars.length) { - retVal = chars[pos]; - if (!Character.isWhitespace(retVal)) - lastNonWhitespace = retVal; - } else { - retVal = '\0'; - } - if (pos == chars.length-1) { - EOF = true; - } + if (pos >= chars.length - 1) EOF = true; + if (pos >= chars.length) return 0; + + char retVal = chars[pos]; + if (!Character.isWhitespace(retVal)) lastNonWhitespace = retVal; return retVal; } + /** + * Called after else. + */ private void gotElse() { - tabs = s_tabs[c_level][if_lev]; - p_flg[level] = sp_flg[c_level][if_lev]; - ind[level] = s_ind[c_level][if_lev]; + tabs = s_tabs[curlyLvl][if_lev]; + p_flg[level] = sp_flg[curlyLvl][if_lev]; + ind[level] = s_ind[curlyLvl][if_lev]; if_flg = true; + // We can't expect else to be followed by a semicolon, so must + // end the statemant manually. + inStatementFlag = false; } - private boolean readUntilNewLine() { + /** + * Pump any '\t' and ' ' to buf, handle any following comment, + * and if the next character is '\n', discard it. + * @return Whether a '\n' was found and discarded. + */ + private boolean readForNewLine() { final int savedTabs = tabs; char c = peek(); while (!EOF && (c == '\t' || c == ' ')) { @@ -319,7 +347,6 @@ private boolean readUntilNewLine() { if (c == '\n') { // eat it nextChar(); -// lineNumber++; tabs = savedTabs; return true; } @@ -327,211 +354,307 @@ private boolean readUntilNewLine() { } - private boolean lookup(final String keyword) { + /** + * @return last non-wsp in result+buf, or 0 on error. + */ + private char prevNonWhitespace() { + StringBuffer tot = new StringBuffer(); + tot.append(result); + tot.append(buf); + for (int i = tot.length()-1; i >= 0; i--) { + if (!Character.isWhitespace(tot.charAt(i))) + return tot.charAt(i); + } + return 0; + } + + + /** + * Sees if buf is of the form [optional whitespace][keyword][optional anything]. + * It won't allow keyword to be directly followed by an alphanumeric, _, or &. + * Will be different if keyword contains regex codes. + */ + private boolean bufStarts(final String keyword) { return Pattern.matches("^\\s*" + keyword + "(?![a-zA-Z0-9_&]).*$", buf); } + /** + * Sees if buf is of the form [optional anything][keyword][optional whitespace]. + * It won't allow keyword to be directly preceded by an alphanumeric, _, or &. + * Will be different if keyword contains regex codes. + */ + private boolean bufEnds(final String keyword) { + return Pattern.matches("^.*(?= 1 - && Character.isWhitespace(sb.charAt(sb.length() - 1))) + while (sb.length() >= 1 && Character.isWhitespace(sb.charAt(sb.length() - 1))) sb.setLength(sb.length() - 1); } + /** + * Entry point + */ public String format(final String source) { final String normalizedText = source.replaceAll("\r", ""); - final String cleanText = + final String cleanText = normalizedText + (normalizedText.endsWith("\n") ? "" : "\n"); + // Globals' description at top of file. result.setLength(0); indentValue = Preferences.getInteger("editor.tabs.size"); -// lineNumber = 0; - boolean forFlag = a_flg = if_flg = false; - s_flag = true; + boolean forFlag = if_flg = false; + startFlag = true; int forParenthLevel = 0; - conditionalLevel = parenLevel = c_level = if_lev = level = 0; + conditionalLevel = parenLevel = curlyLvl = if_lev = level = 0; tabs = 0; - jdoc_flag = false; + jdoc_flag = inStatementFlag = overflowFlag = false; + pos = arrayLevel = -1; int[] s_level = new int[10]; sp_flg = new int[20][10]; - s_ind = new int[20][10]; - int[] s_if_lev = new int[10]; - boolean[] s_if_flg = new boolean[10]; - ind = new int[10]; + s_ind = new boolean[20][10]; + int[] s_if_lev = new int[10]; // Stack + boolean[] s_if_flg = new boolean[10]; // Stack + ind = new boolean[10]; p_flg = new int[10]; s_tabs = new int[20][10]; - pos = -1; + doWhileFlags = new Stack(); + ifWhileForFlags = new Stack(); + chars = cleanText.toCharArray(); -// lineNumber = 1; EOF = false; // set in nextChar() when EOF while (!EOF) { - c = nextChar(); + char c = nextChar(); + switch (c) { default: + inStatementFlag = true; buf.append(c); - l_char = c; break; case ',': + inStatementFlag = true; trimRight(buf); - buf.append(c); - buf.append(' '); - advanceToNonSpace(); + buf.append(", "); + advanceToNonSpace(false); break; case ' ': case '\t': - elseFlag = lookup("else"); + elseFlag = bufEnds("else"); if (elseFlag) { gotElse(); - if ((!s_flag) || buf.length() > 0) { + if (!startFlag || buf.length() > 0) { buf.append(c); } writeIndentedLine(); - s_flag = false; + startFlag = false; break; } - if ((!s_flag) || buf.length() > 0) { - buf.append(c); - } + // Only allow in the line, to nuke the old indent. + if (!startFlag || buf.length() > 0) buf.append(c); break; case '\n': -// lineNumber++; - if (EOF) { - break; - } - elseFlag = lookup("else"); - if (elseFlag) { - gotElse(); - } + if (EOF) break; + + elseFlag = bufEnds("else"); + if (elseFlag) gotElse(); + if (lookup_com("//")) { - final char lastChar = buf.charAt(buf.length() - 1); - if (lastChar == '\n') { + if (buf.charAt(buf.length() - 1) == '\n') { buf.setLength(buf.length() - 1); } } - writeIndentedLine(); - result.append("\n"); - s_flag = true; if (elseFlag) { + writeIndentedLine(); + result.append("\n"); + p_flg[level]++; tabs++; - } else if (getLastNonWhitespace() == l_char) { - a_flg = true; + } else { + writeIndentedLine(); + result.append("\n"); } + startFlag = true; break; case '{': - elseFlag = lookup("else"); + elseFlag = bufEnds("else"); if (elseFlag) gotElse(); - if (s_if_lev.length == c_level) { + doWhileFlags.push(Boolean.valueOf(bufEnds("do"))); + + char prevChar = prevNonWhitespace(); + if (arrayLevel >= 0 || prevChar == '=' || prevChar == ']') { + // If we're already in an array (lvl >= 0), increment level. + // Otherwise, the presence of a = or ] indicates an array is starting + // and we should start counting (set lvl=0). + arrayLevel++; + buf.append(c); + break; // Nothing fancy. + } + + inStatementFlag = false; // eg. class declaration ends + + if (s_if_lev.length == curlyLvl) { s_if_lev = PApplet.expand(s_if_lev); s_if_flg = PApplet.expand(s_if_flg); } - s_if_lev[c_level] = if_lev; - s_if_flg[c_level] = if_flg; + s_if_lev[curlyLvl] = if_lev; + s_if_flg[curlyLvl] = if_flg; if_lev = 0; if_flg = false; - c_level++; - if (s_flag && p_flg[level] != 0) { + curlyLvl++; + if (startFlag && p_flg[level] != 0) { p_flg[level]--; tabs--; } + trimRight(buf); - if (buf.length() > 0 || - (result.length() > 0 && !Character.isWhitespace(result.charAt(result.length() - 1)))) + if (buf.length() > 0 || (result.length() > 0 && + !Character.isWhitespace(result.charAt(result.length() - 1)))) { buf.append(" "); + } buf.append(c); writeIndentedLine(); - readUntilNewLine(); + readForNewLine(); writeIndentedLine(); - - result.append("\n"); + + result.append('\n'); tabs++; - s_flag = true; + startFlag = true; + if (p_flg[level] > 0) { - ind[level] = 1; + ind[level] = true; level++; - s_level[level] = c_level; + s_level[level] = curlyLvl; } break; case '}': - c_level--; - if (c_level < 0) { - c_level = 0; + if (arrayLevel >= 0) { + // Even less fancy. Note that }s cannot end array behaviour; + // a semicolon is needed. + if (arrayLevel > 0) arrayLevel--; + if (arrayIndent > arrayLevel) arrayIndent = arrayLevel; buf.append(c); - writeIndentedLine(); + break; + } + inStatementFlag = false; + + curlyLvl--; + if (curlyLvl < 0) { + curlyLvl = 0; + buf.append(c); + writeIndentedLine(); } else { - if_lev = s_if_lev[c_level] - 1; - if (if_lev < 0) { - if_lev = 0; - } - if_flg = s_if_flg[c_level]; + if_lev = s_if_lev[curlyLvl] - 1; + if (if_lev < 0) if_lev = 0; + if_levSafe(); + + if_flg = s_if_flg[curlyLvl]; trimRight(buf); writeIndentedLine(); tabs--; trimRight(result); - result.append("\n"); + result.append('\n'); printIndentation(); result.append(c); - if (peek() == ';') { - result.append(nextChar()); + if (peek() == ';') result.append(nextChar()); + + // doWhileFlags contains a TRUE if and only if the + // corresponding { was preceeded (bufEnds) by "do". + // Just checking for while would fail on if(){} while(){}. + if (doWhileFlags.empty() || !doWhileFlags.pop().booleanValue() + || !new String(chars, pos+1, chars.length-pos-1).trim().startsWith("while")) { + readForNewLine(); + writeIndentedLine(); + result.append('\n'); + startFlag = true; + } else { + // Correct spacing in "} while". + result.append(' '); + advanceToNonSpace(true); + startFlag = false; } - readUntilNewLine(); - writeIndentedLine(); - result.append('\n'); - s_flag = true; - if (c_level < s_level[level]) { - if (level > 0) { - level--; - } - } - if (ind[level] != 0) { + if (curlyLvl < s_level[level] && level > 0) level--; + + if (ind[level]) { tabs -= p_flg[level]; p_flg[level] = 0; - ind[level] = 0; + ind[level] = false; } } break; case '"': case '\'': + inStatementFlag = true; buf.append(c); - cc = nextChar(); + char cc = nextChar(); while (!EOF && cc != c) { buf.append(cc); if (cc == '\\') { buf.append(cc = nextChar()); } if (cc == '\n') { -// lineNumber++; writeIndentedLine(); - s_flag = true; + startFlag = true; } cc = nextChar(); } buf.append(cc); - if (readUntilNewLine()) { - l_char = cc; + if (readForNewLine()) { // push a newline into the stream chars[pos--] = '\n'; } @@ -543,19 +666,23 @@ public String format(final String source) { trimRight(buf); buf.append("; "); // Not non-whitespace: allow \n. - advanceToNonSpace(); + advanceToNonSpace(false); break; } buf.append(c); + inStatementFlag = false; writeIndentedLine(); - if (p_flg[level] > 0 && ind[level] == 0) { + if (p_flg[level] > 0 && !ind[level]) { tabs -= p_flg[level]; p_flg[level] = 0; } - readUntilNewLine(); + readForNewLine(); writeIndentedLine(); result.append("\n"); - s_flag = true; + startFlag = true; + // Array behaviour ends at the end of a statement. + arrayLevel = -1; + if (if_lev > 0) { if (if_flg) { if_lev--; @@ -577,15 +704,14 @@ public String format(final String source) { break; case ':': - // Java 8 :: operator. + // Java 8 :: operator. if (peek() == ':') { - writeIndentedLine(); result.append(c).append(nextChar()); break; } // End a?b:c structures. - else if (conditionalLevel>0) { + else if (conditionalLevel > 0) { conditionalLevel--; buf.append(c); break; @@ -595,27 +721,23 @@ else if (forFlag) { trimRight(buf); buf.append(" : "); // Not to non-whitespace: allow \n. - advanceToNonSpace(); + advanceToNonSpace(false); break; } buf.append(c); + inStatementFlag = false; + arrayLevel = -1; // Unlikely to be needed; just in case. - if (!lookup("default") && !lookup("case")) { - s_flag = false; - writeIndentedLine(); - } else { - tabs--; - writeIndentedLine(); - tabs++; - } - if (peek() == ';') { - result.append(nextChar()); - } - readUntilNewLine(); + //Same format for case, default, and other labels. + tabs--; + writeIndentedLine(); + tabs++; + + readForNewLine(); writeIndentedLine(); result.append('\n'); - s_flag = true; + startFlag = true; break; case '/': @@ -637,69 +759,71 @@ else if (forFlag) { break; case ')': - - final boolean isCast = castFlags.isEmpty() ? false : castFlags.pop(); - parenLevel--; - + // If we're further back than the start of a for loop, we've // left it. - if (forFlag && forParenthLevel > parenLevel) { - forFlag = false; - } + if (forFlag && forParenthLevel > parenLevel) forFlag = false; - if (parenLevel < 0) { - parenLevel = 0; + if (parenLevel < 0) parenLevel = 0; + buf.append(c); + + boolean wasIfEtc = !ifWhileForFlags.empty() && ifWhileForFlags.pop().booleanValue(); + if (wasIfEtc) { + inStatementFlag = false; + arrayLevel = -1; // This is important as it allows arrays in if statements. } - buf.append(c); writeIndentedLine(); - if (readUntilNewLine()) { - chars[pos--] = '\n'; - if (parenLevel != 0) { - a_flg = true; - } else if (tabs > 0 && !isCast) { + // Short-circuiting means readForNewLine is only called for if/while/for; + // this is important. + if (wasIfEtc && readForNewLine()) { + chars[pos] = '\n'; + pos--; // Make nextChar() return the new '\n'. + if (parenLevel == 0) { p_flg[level]++; tabs++; - ind[level] = 0; + ind[level] = false; } } break; case '(': - castFlags.push(Pattern.matches("^.*?(?:int|color|float)\\s*$", buf)); + final boolean isFor = bufEnds("for"); + final boolean isIf = bufEnds("if"); - final boolean isFor = lookup("for"); - final boolean isIf = lookup("if"); - - if (isFor || isIf || lookup("while")) { + if (isFor || isIf || bufEnds("while")) { if (!Character.isWhitespace(buf.charAt(buf.length() - 1))) { buf.append(' '); } + ifWhileForFlags.push(true); + } else { + ifWhileForFlags.push(false); } buf.append(c); parenLevel++; - // isFor says "is it the start of a for?". If it is, we set forFlag and + // isFor says "Is it the start of a for?". If it is, we set forFlag and // forParenthLevel. If it is not parenth_lvl was incremented above and // that's it. - if (isFor) { - if (!forFlag) { - forParenthLevel = parenLevel; - forFlag = true; - } + if (isFor && !forFlag) { + forParenthLevel = parenLevel; + forFlag = true; } else if (isIf) { writeIndentedLine(); - s_tabs[c_level][if_lev] = tabs; - sp_flg[c_level][if_lev] = p_flg[level]; - s_ind[c_level][if_lev] = ind[level]; + s_tabs[curlyLvl][if_lev] = tabs; + sp_flg[curlyLvl][if_lev] = p_flg[level]; + s_ind[curlyLvl][if_lev] = ind[level]; if_lev++; + if_levSafe(); if_flg = true; } } // end switch } // end while not EOF + if (buf.length() > 0) writeIndentedLine(); + final String formatted = result.toString(); return formatted.equals(cleanText) ? source : formatted; }