private void splitToken(Token token, int tokenIndex, int splitPosition) { assert splitPosition > token.originalStart && splitPosition <= token.originalEnd; Token part1 = new Token(token.originalStart, splitPosition - 1, token.tokenType); Token part2 = new Token(splitPosition, token.originalEnd, token.tokenType); if (token.isSpaceBefore()) part1.spaceBefore(); part1.putLineBreaksBefore(token.getLineBreaksBefore()); if (token.isSpaceAfter()) part2.spaceAfter(); part2.putLineBreaksAfter(token.getLineBreaksAfter()); part1.setIndent(token.getIndent()); part2.setIndent(token.getIndent()); part1.setWrapPolicy(token.getWrapPolicy()); this.commentStructure.set(tokenIndex, part1); this.commentStructure.add(tokenIndex + 1, part2); }
this.counter = startPosition; List<Token> structure = commentToken.getInternalStructure(); if (structure == null || structure.isEmpty()) return startPosition + this.tm.getLength(commentToken, startPosition); commentToken.setIndent(this.tm.toIndent(startPosition, true)); this.lineStartPosition = commentToken.getIndent(); this.simulation = simulate; this.wrapDisabled = noWrap; Token endingToken = structure.get(structure.size() - 1); if (!simulate && endingToken.tokenType != TokenNameNotAToken) { structure.get(0).breakAfter(); endingToken.breakBefore(); endingToken.setAlign(1); this.lineCounter -= structure.get(1).getLineBreaksBefore(); structure.get(1).clearLineBreaksBefore(); Token last = structure.get(structure.size() - 1); this.lineCounter -= last.getLineBreaksBefore(); last.clearLineBreaksBefore();
private void preserveExistingLineBreaks() { // normally n empty lines = n+1 line breaks, but not at the file start and end Token first = this.tm.get(0); int startingBreaks = first.getLineBreaksBefore(); first.clearLineBreaksBefore(); first.putLineBreaksBefore(startingBreaks - 1); this.tm.traverse(0, new TokenTraverser() { boolean join_wrapped_lines = WrapPreparator.this.options.join_wrapped_lines; @Override protected boolean token(Token token, int index) { boolean isBetweenImports = index > WrapPreparator.this.importsStart && index < WrapPreparator.this.importsEnd; int lineBreaks = getLineBreaksToPreserve(getPrevious(), token, isBetweenImports); if (lineBreaks > 1 || (!this.join_wrapped_lines && token.isWrappable()) || index == 0) token.putLineBreaksBefore(lineBreaks); return true; } }); Token last = this.tm.get(this.tm.size() - 1); last.clearLineBreaksAfter(); int endingBreaks = getLineBreaksToPreserve(last, null, false); if (endingBreaks > 0) { last.putLineBreaksAfter(endingBreaks); } else if ((this.kind & (CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.K_MODULE_INFO)) != 0 && this.options.insert_new_line_at_end_of_file_if_missing) { last.breakAfter(); } }
private void handleBracePosition(Token openBraceToken, int closeBraceIndex, String bracePosition) { if (bracePosition.equals(DefaultCodeFormatterConstants.NEXT_LINE)) { openBraceToken.breakBefore(); } else if (bracePosition.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED)) { openBraceToken.breakBefore(); openBraceToken.indent(); if (closeBraceIndex + 1 < this.tm.size()) this.tm.get(closeBraceIndex + 1).unindent(); } else if (bracePosition.equals(DefaultCodeFormatterConstants.NEXT_LINE_ON_WRAP)) { openBraceToken.setNextLineOnWrap(); } }
char charBefore = commentToken.originalStart > 0 ? this.tm.charAt(commentToken.originalStart - 1) : 0; if (charBefore == ' ' || charBefore == '\t') commentToken.spaceBefore(); commentToken.spaceAfter(); existingBreaksBefore = this.tm.countLineBreaksBetween(previous, commentToken); if (existingBreaksBefore > 0) { commentToken.breakBefore(); commentToken.clearSpaceBefore(); existingBreaksAfter = this.tm.countLineBreaksBetween(commentToken, next); if (existingBreaksAfter > 0) commentToken.breakAfter(); if (previous.getWrapPolicy() != WrapPolicy.FORCE_FIRST_COLUMN) commentToken.setWrapPolicy(previous.getWrapPolicy()); } else { int i = commentIndex + 2; commentToken.putLineBreaksAfter(previous.getLineBreaksAfter()); previous.clearLineBreaksAfter(); } else if (existingBreaksAfter <= existingBreaksBefore && next != null commentToken.putLineBreaksBefore(next.getLineBreaksBefore()); next.clearLineBreaksBefore();
private boolean tokenizeMultilineComment(Token commentToken) { if (this.allowSubstituteWrapping == null || this.allowSubstituteWrapping.length < commentToken.countChars()) { this.allowSubstituteWrapping = new boolean[commentToken.countChars()]; Arrays.fill(this.allowSubstituteWrapping, 0, commentToken.countChars(), !isJavadoc); while (firstTokenEnd < commentToken.originalEnd - 1 && this.tm.charAt(firstTokenEnd + 1) == '*') firstTokenEnd++; Token first = new Token(commentToken.originalStart, firstTokenEnd, commentToken.tokenType); first.spaceAfter(); structure.add(first); || ScannerHelper.isWhitespace(c = this.tm.charAt(position))) { if (tokenStart < position) { Token outputToken = new Token(tokenStart, position - 1, commentToken.tokenType); outputToken.spaceBefore(); if (lineBreaks > 0) { if (cleanBlankLines) lineBreaks = 1; if (lineBreaks > 1 || !this.options.join_lines_in_comments) outputToken.putLineBreaksBefore(lineBreaks); outputToken.setWrapPolicy(WrapPolicy.DISABLE_WRAP); if (commentToken.tokenType == TokenNameCOMMENT_BLOCK && lineBreaks == 1 && structure.size() > 1) outputToken.putLineBreaksBefore(cleanBlankLines ? 1 : 2); if (this.tm.charAt(tokenStart + 1) == '@' && lineBreaks > 0 && this.firstTagToken == null) { : this.options.comment_new_lines_at_block_boundaries; if (!newLinesAtBoundries) {
public void wrapLineComment(Token commentToken, int startPosition) { List<Token> structure = commentToken.getInternalStructure(); if (structure == null || structure.isEmpty()) return; if (token.hasNLSTag()) { this.nlsTags.add(token); position += token.countChars() + (token.isSpaceBefore() ? 1 : 0); Token prefix = structure.get(0); if (prefix.tokenType == TokenNameWHITESPACE) { whitespace = new Token(prefix); whitespace.breakBefore(); whitespace.setIndent(indent); whitespace.setWrapPolicy(new WrapPolicy(WrapMode.WHERE_NECESSARY, commentIndex, 0)); prefix = structure.get(1); assert prefix.tokenType == TokenNameCOMMENT_LINE; if (!prefix.hasNLSTag()) prefix = new Token(commentToken.originalStart, prefixEnd, TokenNameCOMMENT_LINE); if (whitespace == null) { prefix.breakBefore(); prefix.setWrapPolicy(new WrapPolicy(WrapMode.WHERE_NECESSARY, commentIndex, 0)); for (int i = 0; i < structure.size(); i++) { Token token = structure.get(i); token.setIndent(indent); if (token.hasNLSTag()) { this.nlsTags.remove(token);
private void setTokenWrapPolicy(int index, WrapPolicy policy, boolean wrapPreceedingComments) { if (wrapPreceedingComments) { for (int i = index - 1; i >= 0; i--) { Token previous = this.tm.get(i); if (!previous.isComment()) break; if (previous.getLineBreaksAfter() == 0 && i == index - 1) index = i; if (previous.getLineBreaksBefore() > 0) previous.setWrapPolicy(policy); } } Token token = this.tm.get(index); if (token.getWrapPolicy() != WrapPolicy.DISABLE_WRAP) token.setWrapPolicy(policy); if (this.options.join_wrapped_lines && token.tokenType == TokenNameCOMMENT_BLOCK) { // allow wrap preparator to decide if this comment should be wrapped token.clearLineBreaksBefore(); } }
/** * Makes sure all new lines within given node will have wrap policy so that * wrap executor will fix their indentation if necessary. */ private void forceContinuousWrapping(ASTNode node, int parentIndex) { int parentIndent = this.tm.get(parentIndex).getIndent(); int indentChange = -parentIndent; int lineStart = this.tm.findFirstTokenInLine(parentIndex); for (int i = parentIndex; i >= lineStart; i--) { int align = this.tm.get(i).getAlign(); if (align > 0) { indentChange = -2 * parentIndent + align; break; } } Token previous = null; int from = this.tm.firstIndexIn(node, -1); int to = this.tm.lastIndexIn(node, -1); for (int i = from; i <= to; i++) { Token token = this.tm.get(i); if ((token.getLineBreaksBefore() > 0 || (previous != null && previous.getLineBreaksAfter() > 0)) && (token.getWrapPolicy() == null || token.getWrapPolicy().wrapMode == WrapMode.FORCED)) { int extraIndent = token.getIndent() + indentChange; token.setWrapPolicy(new WrapPolicy(WrapMode.FORCED, parentIndex, extraIndent)); token.setIndent(parentIndent + extraIndent); } previous = token; } }
private void handleBracedCode(ASTNode node, ASTNode nodeBeforeOpenBrace, String bracePosition, boolean indentBody) { int openBraceIndex = nodeBeforeOpenBrace == null ? this.tm.firstIndexIn(node, TokenNameLBRACE) : this.tm.firstIndexAfter(nodeBeforeOpenBrace, TokenNameLBRACE); int closeBraceIndex = this.tm.lastIndexIn(node, TokenNameRBRACE); Token openBraceToken = this.tm.get(openBraceIndex); Token closeBraceToken = this.tm.get(closeBraceIndex); handleBracePosition(openBraceToken, closeBraceIndex, bracePosition); openBraceToken.breakAfter(); closeBraceToken.breakBefore(); if (indentBody) { adjustEmptyLineAfter(openBraceIndex, 1); this.tm.get(openBraceIndex + 1).indent(); closeBraceToken.unindent(); } }
private void preserveWhitespace(Token commentToken, int commentIndex) { if (this.options.comment_preserve_white_space_between_code_and_line_comments && commentToken.getLineBreaksBefore() == 0 && commentIndex > 0) { commentToken.clearSpaceBefore(); List<Token> structure = commentToken.getInternalStructure(); if (structure != null && !structure.isEmpty()) structure.get(0).clearSpaceBefore(); Token previous = this.tm.get(commentIndex - 1); previous.clearSpaceAfter(); if (previous.originalEnd + 1 >= commentToken.originalStart) return; if (structure == null || structure.isEmpty()) { structure = new ArrayList<>(); structure.add(new Token(previous.originalEnd + 1, commentToken.originalEnd, TokenNameCOMMENT_LINE)); commentToken.setInternalStructure(structure); } else { structure.add(0, new Token(previous.originalEnd + 1, commentToken.originalStart - 1, TokenNameWHITESPACE)); } } }
if (this.options.number_of_empty_lines_to_preserve > 0 && preexistingBreaks > 1) return; // blank line will be preserved boolean isSpace = prev.isSpaceAfter() || token.isSpaceBefore(); if (prev.isComment() || token.isComment()) { if (preexistingBreaks > 0) return; // line break around a comment will be preserved isSpace = isSpace || charBefore == ' ' || charBefore == '\t'; if (prev.getLineBreaksAfter() > 0 || token.getLineBreaksBefore() > 0) { if (!breakIndexes.contains(i)) return; // extra line break within an item, can't remove it prev.clearLineBreaksAfter(); Token token = this.tm.get(i); token.clearLineBreaksBefore(); if (!items.isEmpty()) token.spaceBefore();
private void handleCompilerTags(Token commentToken, int commentIndex) { final String commentText = this.tm.toString(commentToken); final List<Token> structure = commentToken.getInternalStructure(); if (commentText.startsWith("//$FALL-THROUGH$") //$NON-NLS-1$ || commentText.startsWith("//$IDENTITY-COMPARISON$")) { //$NON-NLS-1$ structure.get(1).clearSpaceBefore(); } if (commentText.contains("//$IDENTITY-COMPARISON$")) { //$NON-NLS-1$ // make sure the whole line is not broken Token token = commentToken; for (int i = commentIndex; i > 0; i--) { Token left = this.tm.get(i - 1); if (this.tm.countLineBreaksBetween(left, token) > 0) break; token.clearLineBreaksBefore(); left.clearLineBreaksAfter(); token.setWrapPolicy(WrapPolicy.DISABLE_WRAP); token = left; } } }
private void formatCode(int javadocNoFormatCloseStart, int javadocNoFormatCloseEnd) { int openingTagLastIndex = tokenEndingAt(this.formatCodeTagOpenEnd); int closingTagFirstIndex = tokenStartingAt(javadocNoFormatCloseStart); int codeStartPosition = this.formatCodeTagOpenEnd + 1; int codeEndPosition = javadocNoFormatCloseStart - 1; StringBuilder codeBuilder = new StringBuilder(codeEndPosition - codeStartPosition + 1); int[] positionMapping = new int[codeEndPosition - codeStartPosition + 1]; // ^ index: original source position (minus startPosition), value: position in code string getCodeToFormat(codeStartPosition, codeEndPosition, codeBuilder, positionMapping); List<Token> formattedTokens = getCommentCodeFormatter().prepareFormattedCode(codeBuilder.toString()); if (formattedTokens == null) { disableFormattingExclusively(openingTagLastIndex, closingTagFirstIndex); closingTagFirstIndex = tokenStartingAt(javadocNoFormatCloseStart); cleanupHTMLElement(openingTagLastIndex, closingTagFirstIndex, false); return; } formattedTokens = translateFormattedTokens(codeStartPosition, formattedTokens, positionMapping, null); // there are too few linebreaks at the start and end Token start = formattedTokens.get(0); start.putLineBreaksBefore(start.getLineBreaksBefore() + 1); Token end = formattedTokens.get(formattedTokens.size() - 1); end.putLineBreaksAfter(end.getLineBreaksAfter() + 1); // and there may be too many line breaks before closing tag this.ctm.get(closingTagFirstIndex).clearLineBreaksBefore(); List<Token> tokensToReplace = this.commentStructure.subList(openingTagLastIndex + 1, closingTagFirstIndex); tokensToReplace.clear(); tokensToReplace.addAll(formattedTokens); cleanupHTMLElement(openingTagLastIndex, openingTagLastIndex + formattedTokens.size() + 1, true); }
public int getPositionInLine(int tokenIndex) { Token token = get(tokenIndex); // find the first token in line and calculate position of given token int firstTokenIndex = token.getLineBreaksBefore() > 0 ? tokenIndex : findFirstTokenInLine(tokenIndex); Token firstToken = get(firstTokenIndex); int startingPosition = toIndent(firstToken.getIndent(), firstToken.getWrapPolicy() != null); this.positionInLineCounter.value = tokenIndex; this.positionInLineCounter.counter = startingPosition; traverse(firstTokenIndex, this.positionInLineCounter); return Math.max(this.positionInLineCounter.counter, token.getAlign()); }
WrapInfo wi = wr.nextWrap; Token token = this.tm.get(wi.wrapTokenIndex); if (token.getWrapPolicy().wrapParentIndex < startTokenIndex && getWrapIndent(token) != wi.indent) { wrapResult = null; break; boolean wasLineBreak = token.getLineBreaksBefore() > 0; token.breakBefore(); try { wrapResult = findWraps(startTokenIndex, indent); } finally { if (!wasLineBreak) token.clearLineBreaksBefore();
private void alignAssignmentStatements(List<Statement> statements) { List<List<ExpressionStatement>> assignmentGroups = toAlignGroups(statements, n -> optionalCast(n, ExpressionStatement.class) .filter(es -> es.getExpression() instanceof Assignment)); this.alignGroups.addAll(assignmentGroups); AlignIndexFinder<ExpressionStatement> assignFinder = es -> { Assignment a = (Assignment) es.getExpression(); int operatorIndex = this.tm.firstIndexBefore(a.getRightHandSide(), -1); while (this.tm.get(operatorIndex).isComment()) operatorIndex--; return Optional.of(operatorIndex); }; assignmentGroups.forEach(ag -> alignNodes(ag, assignFinder)); if (this.options.align_with_spaces || this.options.tab_char != DefaultCodeFormatterOptions.TAB) { // align assign operators on their right side (e.g. +=, >>=) for (List<ExpressionStatement> group : assignmentGroups) { List<Token> assignTokens = group.stream() .map(assignFinder::findIndex) .filter(Optional::isPresent) .map(o -> this.tm.get(o.get())) .collect(toList()); int maxWidth = assignTokens.stream().mapToInt(Token::countChars).max().orElse(0); for (Token token : assignTokens) token.setAlign(token.getAlign() + maxWidth - token.countChars()); } } }
private void handleSeparateLineTag(int startPos, int endPos) { int openingTagIndex = tokenStartingAt(startPos); if (openingTagIndex > 1 && this.lastFormatCodeClosingTagIndex == openingTagIndex - 1) { Token token = this.ctm.get(openingTagIndex - 1); assert token.getLineBreaksAfter() == 2; token.clearLineBreaksAfter(); token.breakAfter(); } handleBreakBeforeTag(startPos, endPos, true); handleBreakAfterTag(startPos, endPos); }
private void handleBreakBeforeTag(int start, int end, boolean isOpeningTag) { int firstPartIndex = tokenStartingAt(start); int lastPartIndex = tokenEndingAt(end); Token firstPartToken = this.ctm.get(firstPartIndex); firstPartToken.setWrapPolicy(null); if (isOpeningTag) { firstPartToken.breakBefore(); this.ctm.get(lastPartIndex + 1).clearSpaceBefore(); } else { firstPartToken.clearSpaceBefore(); } }