diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java
index d8a050fff0c..7e40759e82e 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java
@@ -146,11 +146,22 @@ public class DefaultCodeFormatterConstants {
* FORMATTER / Option for alignment of conditional expression
* - option id: "org.eclipse.cdt.core.formatter.alignment_for_conditional_expression"
* - possible values: values returned by createAlignmentValue(boolean, int, int)
call
- * - default: createAlignmentValue(false, WRAP_ONE_PER_LINE, INDENT_DEFAULT)
+ * - default: createAlignmentValue(false, WRAP_COMPACT, INDENT_ON_COLUMN)
*
* @see #createAlignmentValue(boolean, int, int)
*/
public static final String FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION = CCorePlugin.PLUGIN_ID + ".formatter.alignment_for_conditional_expression"; //$NON-NLS-1$
+ /**
+ *
+ * FORMATTER / Option for alignment of a chain of conditional expressions.
+ * - option id: "org.eclipse.cdt.core.formatter.alignment_for_conditional_expression_chain"
+ * - possible values: values returned by createAlignmentValue(boolean, int, int)
call
+ * - default: createAlignmentValue(false, WRAP_COMPACT, INDENT_ON_COLUMN)
+ *
+ * @see #createAlignmentValue(boolean, int, int)
+ * @since 5.3
+ */
+ public static final String FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION_CHAIN = CCorePlugin.PLUGIN_ID + ".formatter.alignment_for_conditional_expression_chain"; //$NON-NLS-1$
/**
* * FORMATTER / Option for alignment of a declarator list diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java index 835361b9bff..c1187c2037a 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java @@ -172,7 +172,6 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, private static class ListOptions { final int fMode; int fSeparatorToken = Token.tCOMMA; - boolean fInsertNewLineBeforeListIfNecessary; boolean fSpaceBeforeSeparator; boolean fSpaceAfterSeparator = true; boolean fSpaceAfterOpeningParen; @@ -1223,6 +1222,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, final ListOptions options= new ListOptions(Alignment.M_COMPACT_SPLIT); options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_template_parameters; options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_template_parameters; + options.fTieBreakRule = Alignment.R_OUTERMOST; formatList(Arrays.asList(templateParameters), options, false, false, null); } scribe.printNextToken(new int[] { Token.tGT, Token.tSHIFTR }, preferences.insert_space_before_closing_angle_bracket_in_template_parameters); @@ -1485,7 +1485,6 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, private ListOptions createListOptionsForFunctionDeclarationParameters() { final ListOptions options= new ListOptions(preferences.alignment_for_parameters_in_method_declaration); - options.fInsertNewLineBeforeListIfNecessary= true; options.fSpaceBeforeOpeningParen= preferences.insert_space_before_opening_paren_in_method_declaration; options.fSpaceAfterOpeningParen= preferences.insert_space_after_opening_paren_in_method_declaration; options.fSpaceBeforeClosingParen= preferences.insert_space_before_closing_paren_in_method_declaration; @@ -2031,91 +2030,63 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, if (options.fSpaceAfterOpeningParen) { scribe.space(); } - Alignment wrapperAlignment = null; final int continuationIndentation= options.fContinuationIndentation >= 0 ? options.fContinuationIndentation : preferences.continuation_indentation; - if (options.fInsertNewLineBeforeListIfNecessary && - (options.fMode & Alignment.M_INDENT_ON_COLUMN) != 0) { - wrapperAlignment = scribe.createAlignment( - Alignment.COLUMN_WRAPPER, - Alignment.M_COMPACT_FIRST_BREAK_SPLIT, - Alignment.R_INNERMOST, - 1, - scribe.scanner.getCurrentPosition(), - continuationIndentation, - false); - scribe.enterAlignment(wrapperAlignment); - } - boolean success = false; + Alignment alignment = scribe.createAlignment( + Alignment.LIST_ELEMENTS_PREFIX + + (elements.isEmpty() ? "ellipsis" : elements.get(0).getClass().getSimpleName()), //$NON-NLS-1$ + options.fMode, + options.fTieBreakRule, + elementsLength + (addEllipsis ? 1 : 0), + scribe.scanner.getCurrentPosition(), + continuationIndentation, + false); + scribe.enterAlignment(alignment); + boolean ok = false; do { - if (wrapperAlignment != null) - scribe.alignFragment(wrapperAlignment, 0); - try { - Alignment alignment = scribe.createAlignment( - Alignment.LIST_ELEMENTS_PREFIX + - (elements.isEmpty() ? "ellipsis" : elements.get(0).getClass().getSimpleName()), //$NON-NLS-1$ - options.fMode, - options.fTieBreakRule, - elementsLength + (addEllipsis ? 1 : 0), - scribe.scanner.getCurrentPosition(), - wrapperAlignment == null ? continuationIndentation : 0, - false); - scribe.enterAlignment(alignment); - boolean ok = false; - do { - try { - int i; - for (i = 0; i < elementsLength; i++) { - final IASTNode node= elements.get(i); - if (i < alignment.fragmentCount - 1) { - scribe.setTailFormatter( - new TrailingTokenFormatter(options.fSeparatorToken, - options.fSpaceBeforeSeparator, - options.fSpaceAfterSeparator)); - } else { - scribe.setTailFormatter(tailFormatter); - } - scribe.alignFragment(alignment, i); - if (node instanceof ICPPASTConstructorChainInitializer) { - // Constructor chain initializer is a special case. - visit((ICPPASTConstructorChainInitializer) node); - } else { - node.accept(this); - } - if (i < alignment.fragmentCount - 1) { - scribe.runTailFormatter(); - } - } - if (addEllipsis) { - if (i > 0) { - scribe.printNextToken(options.fSeparatorToken, options.fSpaceBeforeSeparator); - scribe.printTrailingComment(); - } - scribe.alignFragment(alignment, i); - if (i > 0 && options.fSpaceAfterSeparator) { - scribe.space(); - } - scribe.printNextToken(Token.tELIPSE); - } - scribe.runTailFormatter(); - ok = true; - } catch (AlignmentException e) { - scribe.redoAlignment(e); - } catch (ASTProblemException e) { + int i; + for (i = 0; i < elementsLength; i++) { + final IASTNode node= elements.get(i); + if (i < alignment.fragmentCount - 1) { + scribe.setTailFormatter( + new TrailingTokenFormatter(options.fSeparatorToken, + options.fSpaceBeforeSeparator, + options.fSpaceAfterSeparator)); + } else { + scribe.setTailFormatter(tailFormatter); } - } while (!ok); - scribe.exitAlignment(alignment, true); - success = true; + scribe.alignFragment(alignment, i); + if (node instanceof ICPPASTConstructorChainInitializer) { + // Constructor chain initializer is a special case. + visit((ICPPASTConstructorChainInitializer) node); + } else { + node.accept(this); + } + if (i < alignment.fragmentCount - 1) { + scribe.runTailFormatter(); + } + } + if (addEllipsis) { + if (i > 0) { + scribe.printNextToken(options.fSeparatorToken, options.fSpaceBeforeSeparator); + scribe.printTrailingComment(); + } + scribe.alignFragment(alignment, i); + if (i > 0 && options.fSpaceAfterSeparator) { + scribe.space(); + } + scribe.printNextToken(Token.tELIPSE); + } + scribe.runTailFormatter(); + ok = true; } catch (AlignmentException e) { - if (wrapperAlignment == null) - throw e; scribe.redoAlignment(e); + } catch (ASTProblemException e) { } - } while (wrapperAlignment != null && !success); - if (wrapperAlignment != null) - scribe.exitAlignment(wrapperAlignment, true); + } while (!ok); + scribe.exitAlignment(alignment, true); } else if (tailFormatter != null) { tailFormatter.run(); } @@ -2180,72 +2151,89 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } private int visit(IASTConditionalExpression node) { + // Count nested conditional expressions. + int numConditions = 0; + for (IASTExpression expression = node; expression instanceof IASTConditionalExpression; + expression = ((IASTConditionalExpression) expression).getNegativeResultExpression()) { + numConditions++; + } + Runnable tailFormatter = scribe.takeTailFormatter(); + Alignment alignment = scribe.createAlignment( + Alignment.CONDITIONAL_EXPRESSION_CHAIN, + preferences.alignment_for_conditional_expression_chain, + Alignment.R_OUTERMOST, + numConditions, + scribe.scanner.getCurrentPosition()); + + scribe.enterAlignment(alignment); + boolean ok = false; + do { + try { + IASTConditionalExpression expression = node; + for (int i = 0; ; i++) { + scribe.alignFragment(alignment, i); + boolean last = i == numConditions - 1; + formatConditionalExpression(expression, last ? tailFormatter : null); + if (last) + break; + expression = (IASTConditionalExpression) expression.getNegativeResultExpression(); + } + ok = true; + } catch (AlignmentException e) { + scribe.redoAlignment(e); + } + } while (!ok); + scribe.exitAlignment(alignment, true); + + return PROCESS_SKIP; + } + + private void formatConditionalExpression(IASTConditionalExpression node, Runnable tailFormatter) { scribe.setTailFormatter(new TrailingTokenFormatter(Token.tQUESTION, node, preferences.insert_space_before_question_in_conditional, preferences.insert_space_after_question_in_conditional)); node.getLogicalConditionExpression().accept(this); scribe.runTailFormatter(); - Alignment wrapperAlignment = scribe.createAlignment( - Alignment.CONDITIONAL_EXPRESSION_WRAPPER, - Alignment.M_COMPACT_FIRST_BREAK_SPLIT, - Alignment.R_OUTERMOST, - 1, - scribe.scanner.getCurrentPosition(), - preferences.continuation_indentation, - false); - scribe.enterAlignment(wrapperAlignment); - boolean success = false; - do { - scribe.alignFragment(wrapperAlignment, 0); + final IASTExpression positiveExpression = node.getPositiveResultExpression(); + final IASTExpression negativeExpression = node.getNegativeResultExpression(); - try { - Alignment alignment = scribe.createAlignment( - Alignment.CONDITIONAL_EXPRESSION, - preferences.alignment_for_conditional_expression, - Alignment.R_OUTERMOST, - 2, - scribe.scanner.getCurrentPosition(), - 0, - false); - - scribe.enterAlignment(alignment); - boolean ok = false; - do { - try { - scribe.alignFragment(alignment, 0); - final IASTExpression positiveExpression = node.getPositiveResultExpression(); - final IASTExpression negativeExpression = node.getNegativeResultExpression(); - scribe.setTailFormatter(new TrailingTokenFormatter(Token.tCOLON, node, - preferences.insert_space_before_colon_in_conditional, - preferences.insert_space_after_colon_in_conditional)); - // A gcc extension allows the positive expression to be omitted. - if (positiveExpression != null) { - positiveExpression.accept(this); - } - scribe.runTailFormatter(); - - scribe.alignFragment(alignment, 1); - scribe.setTailFormatter(tailFormatter); - negativeExpression.accept(this); - scribe.runTailFormatter(); - ok = true; - } catch (AlignmentException e) { - scribe.redoAlignment(e); - } - } while (!ok); - scribe.exitAlignment(alignment, true); - success = true; - } catch (AlignmentException e) { - scribe.redoAlignment(e); - } - } while (!success); - scribe.exitAlignment(wrapperAlignment, true); + Alignment alignment = scribe.createAlignment( + Alignment.CONDITIONAL_EXPRESSION, + preferences.alignment_for_conditional_expression, + Alignment.R_OUTERMOST, + negativeExpression instanceof IASTConditionalExpression ? 1 : 2, + scribe.scanner.getCurrentPosition()); - return PROCESS_SKIP; - } + scribe.enterAlignment(alignment); + boolean ok = false; + do { + try { + scribe.alignFragment(alignment, 0); + scribe.setTailFormatter(new TrailingTokenFormatter(Token.tCOLON, node, + preferences.insert_space_before_colon_in_conditional, + preferences.insert_space_after_colon_in_conditional)); + // A gcc extension allows the positive expression to be omitted. + if (positiveExpression != null) { + positiveExpression.accept(this); + } + scribe.runTailFormatter(); + + if (!(negativeExpression instanceof IASTConditionalExpression)) { + scribe.alignFragment(alignment, 1); + scribe.setTailFormatter(tailFormatter); + negativeExpression.accept(this); + scribe.runTailFormatter(); + } + ok = true; + } catch (AlignmentException e) { + scribe.redoAlignment(e); + } + } while (!ok); + scribe.exitAlignment(alignment, true); + } private int visit(IASTFunctionCallExpression node) { Runnable tailFormatter = scribe.takeTailFormatter(); @@ -2284,7 +2272,6 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, } final ListOptions options= new ListOptions(preferences.alignment_for_arguments_in_method_invocation); options.fSeparatorToken = Token.tCOMMA; - options.fInsertNewLineBeforeListIfNecessary= true; options.fSpaceBeforeOpeningParen= preferences.insert_space_before_opening_paren_in_method_invocation; options.fSpaceAfterOpeningParen= preferences.insert_space_after_opening_paren_in_method_invocation; options.fSpaceBeforeClosingParen= preferences.insert_space_before_closing_paren_in_method_invocation; @@ -2393,7 +2380,6 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, do { try { scribe.alignFragment(alignment, 0); - node.getInitializerClause().accept(this); ok = true; } catch (AlignmentException e) { @@ -2656,7 +2642,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, Alignment expressionAlignment= scribe.createAlignment( Alignment.ASSIGNMENT_EXPRESSION, preferences.alignment_for_assignment, - Alignment.R_OUTERMOST, + Alignment.R_INNERMOST, 1, scribe.scanner.getCurrentPosition()); @@ -2717,70 +2703,42 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, scribe.space(); } - Alignment wrapperAlignment = null; - if ((preferences.alignment_for_overloaded_left_shift_chain & Alignment.M_INDENT_ON_COLUMN) != 0) { - wrapperAlignment = scribe.createAlignment( - Alignment.COLUMN_WRAPPER, - Alignment.M_COMPACT_FIRST_BREAK_SPLIT, - Alignment.R_INNERMOST, - 1, - scribe.scanner.getCurrentPosition(), - preferences.continuation_indentation, - false); - scribe.enterAlignment(wrapperAlignment); - } - boolean success = false; + Alignment alignment = scribe.createAlignment( + Alignment.OVERLOADED_LEFT_SHIFT_CHAIN, + preferences.alignment_for_overloaded_left_shift_chain, + Alignment.R_OUTERMOST, + elements.size(), + scribe.scanner.getCurrentPosition(), + preferences.continuation_indentation, + false); + scribe.enterAlignment(alignment); + boolean ok = false; do { - if (wrapperAlignment != null) - scribe.alignFragment(wrapperAlignment, 0); - try { - Alignment alignment = scribe.createAlignment( - Alignment.OVERLOADED_LEFT_SHIFT_CHAIN, - preferences.alignment_for_overloaded_left_shift_chain, - Alignment.R_OUTERMOST, - elements.size(), - scribe.scanner.getCurrentPosition(), - wrapperAlignment == null ? preferences.continuation_indentation : 0, - false); - scribe.enterAlignment(alignment); - boolean ok = false; - do { - try { - for (int i = 0; i < elements.size(); i++) { - scribe.alignFragment(alignment, i); - int token= peekNextToken(); - if (token == Token.tSHIFTL) { - scribe.printNextToken(token, preferences.insert_space_before_binary_operator); - scribe.printTrailingComment(); - if (preferences.insert_space_after_binary_operator) { - scribe.space(); - } - } - node= elements.get(i); - if (i == alignment.fragmentCount - 1) { - scribe.setTailFormatter(tailFormatter); - } - node.accept(this); + for (int i = 0; i < elements.size(); i++) { + scribe.alignFragment(alignment, i); + int token= peekNextToken(); + if (token == Token.tSHIFTL) { + scribe.printNextToken(token, preferences.insert_space_before_binary_operator); + scribe.printTrailingComment(); + if (preferences.insert_space_after_binary_operator) { + scribe.space(); } - scribe.runTailFormatter(); - ok = true; - } catch (AlignmentException e) { - scribe.redoAlignment(e); - } catch (ASTProblemException e) { } - } while (!ok); - scribe.exitAlignment(alignment, true); - success = true; + node= elements.get(i); + if (i == alignment.fragmentCount - 1) { + scribe.setTailFormatter(tailFormatter); + } + node.accept(this); + } + scribe.runTailFormatter(); + ok = true; } catch (AlignmentException e) { - if (wrapperAlignment == null) - throw e; scribe.redoAlignment(e); + } catch (ASTProblemException e) { } - } while (wrapperAlignment != null && !success); - if (wrapperAlignment != null) - scribe.exitAlignment(wrapperAlignment, true); - + } while (!ok); + scribe.exitAlignment(alignment, true); return PROCESS_SKIP; } @@ -3365,6 +3323,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, final ListOptions options= new ListOptions(Alignment.M_COMPACT_SPLIT); options.fSpaceAfterSeparator= preferences.insert_space_after_comma_in_template_arguments; options.fSpaceBeforeSeparator= preferences.insert_space_before_comma_in_template_arguments; + options.fTieBreakRule = Alignment.R_OUTERMOST; formatList(Arrays.asList(templateArguments), options, false, false, null); } if (peekNextToken() == Token.tSHIFTR) { diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/DefaultCodeFormatterOptions.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/DefaultCodeFormatterOptions.java index cff64a79311..5e940f6617a 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/DefaultCodeFormatterOptions.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/DefaultCodeFormatterOptions.java @@ -59,6 +59,7 @@ public class DefaultCodeFormatterOptions { public int alignment_for_base_clause_in_type_declaration; public int alignment_for_binary_expression; public int alignment_for_compact_if; + public int alignment_for_conditional_expression_chain; public int alignment_for_conditional_expression; public int alignment_for_declarator_list; public int alignment_for_enumerator_list; @@ -275,6 +276,7 @@ public class DefaultCodeFormatterOptions { options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_BINARY_EXPRESSION, getAlignment(this.alignment_for_binary_expression)); options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_COMPACT_IF, getAlignment(this.alignment_for_compact_if)); options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION, getAlignment(this.alignment_for_conditional_expression)); + options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION_CHAIN, getAlignment(this.alignment_for_conditional_expression_chain)); options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_DECLARATOR_LIST, getAlignment(this.alignment_for_declarator_list)); options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ENUMERATOR_LIST, getAlignment(this.alignment_for_enumerator_list)); options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_INITIALIZER_LIST, getAlignment(this.alignment_for_expressions_in_initializer_list)); @@ -528,9 +530,19 @@ public class DefaultCodeFormatterOptions { try { this.alignment_for_conditional_expression = Integer.parseInt((String) alignmentForConditionalExpressionOption); } catch (NumberFormatException e) { - this.alignment_for_conditional_expression = Alignment.M_ONE_PER_LINE_SPLIT; + this.alignment_for_conditional_expression = Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_ON_COLUMN; } catch (ClassCastException e) { - this.alignment_for_conditional_expression = Alignment.M_ONE_PER_LINE_SPLIT; + this.alignment_for_conditional_expression = Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_ON_COLUMN; + } + } + final Object alignmentForConditionalExpressionChainOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION_CHAIN); + if (alignmentForConditionalExpressionChainOption != null) { + try { + this.alignment_for_conditional_expression_chain = Integer.parseInt((String) alignmentForConditionalExpressionChainOption); + } catch (NumberFormatException e) { + this.alignment_for_conditional_expression_chain = Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_ON_COLUMN; + } catch (ClassCastException e) { + this.alignment_for_conditional_expression_chain = Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_ON_COLUMN; } } final Object alignmentForDeclaratorListOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_DECLARATOR_LIST); @@ -1484,7 +1496,8 @@ public class DefaultCodeFormatterOptions { this.alignment_for_base_clause_in_type_declaration = Alignment.M_NEXT_PER_LINE_SPLIT; this.alignment_for_binary_expression = Alignment.M_COMPACT_SPLIT; this.alignment_for_compact_if = Alignment.M_COMPACT_SPLIT; - this.alignment_for_conditional_expression = Alignment.M_NEXT_PER_LINE_SPLIT; + this.alignment_for_conditional_expression = Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_ON_COLUMN; + this.alignment_for_conditional_expression_chain = Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_ON_COLUMN; this.alignment_for_declarator_list = Alignment.M_COMPACT_SPLIT; this.alignment_for_enumerator_list = Alignment.M_ONE_PER_LINE_SPLIT; this.alignment_for_expressions_in_initializer_list = Alignment.M_COMPACT_SPLIT; diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/Scribe.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/Scribe.java index fc85663b663..834a7722152 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/Scribe.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/Scribe.java @@ -227,9 +227,7 @@ public class Scribe { } public void alignFragment(Alignment alignment, int fragmentIndex) { - alignment.fragmentIndex= fragmentIndex; - alignment.checkColumn(); - alignment.performFragmentEffect(); + alignment.alignFragment(fragmentIndex); } public void consumeNextToken() { @@ -577,11 +575,22 @@ public class Scribe { } public void handleLineTooLong() { - // Search for closest breakable alignment, using tie break rules - // look for outermost breakable one. + // Search for closest breakable alignment, using tie break rules. + // Look for innermost breakable one. int relativeDepth= 0; - int outerMostDepth= -1; Alignment targetAlignment= currentAlignment; + while (targetAlignment != null && targetAlignment.tieBreakRule == Alignment.R_INNERMOST) { + if (targetAlignment.couldBreak()) { + throwAlignmentException(AlignmentException.LINE_TOO_LONG, relativeDepth); + } + targetAlignment= targetAlignment.enclosing; + relativeDepth++; + } + + // Look for outermost breakable one. + relativeDepth= 0; + int outerMostDepth= -1; + targetAlignment= currentAlignment; while (targetAlignment != null) { if (targetAlignment.tieBreakRule == Alignment.R_OUTERMOST && targetAlignment.couldBreak()) { outerMostDepth= relativeDepth; @@ -592,7 +601,8 @@ public class Scribe { if (outerMostDepth >= 0) { throwAlignmentException(AlignmentException.LINE_TOO_LONG, outerMostDepth); } - // Look for innermost breakable one + // Look for innermost breakable one but don't stop if we encounter a R_OUTERMOST + // tie-breaking rule. relativeDepth= 0; targetAlignment= currentAlignment; while (targetAlignment != null) { diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/align/Alignment.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/align/Alignment.java index efab363a4da..c05c7964829 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/align/Alignment.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/align/Alignment.java @@ -11,6 +11,8 @@ *******************************************************************************/ package org.eclipse.cdt.internal.formatter.align; +import java.util.Arrays; + import org.eclipse.cdt.internal.formatter.Location; import org.eclipse.cdt.internal.formatter.Scribe; @@ -23,10 +25,9 @@ public class Alignment { // Alignment names. public static final String ASSIGNMENT_EXPRESSION = "assignmentExpression"; //$NON-NLS-1$ public static final String BINARY_EXPRESSION = "binaryExpression"; //$NON-NLS-1$ - public static final String COLUMN_WRAPPER = "columnWrapper"; //$NON-NLS-1$ public static final String COMPACT_IF = "compactIf"; //$NON-NLS-1$ - public static final String CONDITIONAL_EXPRESSION_WRAPPER = "conditionalExpressionWrapper"; //$NON-NLS-1$ public static final String CONDITIONAL_EXPRESSION = "conditionalExpression"; //$NON-NLS-1$ + public static final String CONDITIONAL_EXPRESSION_CHAIN = "conditionalExpressionChain"; //$NON-NLS-1$ public static final String DECLARATION_INITIALIZER = "declarationInitializer"; //$NON-NLS-1$ public static final String DESIGNATED_INITIALIZER = "designatedInitializer"; //$NON-NLS-1$ public static final String EXCEPTION_SPECIFICATION = "exceptionSpecification"; //$NON-NLS-1$ @@ -65,7 +66,7 @@ public class Alignment { // Break management public int originalIndentationLevel; public int breakIndentationLevel; - public int shiftBreakIndentationLevel; + public int alternativeBreakIndentationLevel; public int[] fragmentBreaks; public boolean wasSplit; public int currentFragmentStartLine; @@ -146,9 +147,9 @@ public class Alignment { public int tieBreakRule; // Alignment effects on a per fragment basis + public static final int BREAK_NOT_ALLOWED = -1; public static final int NONE = 0; - public static final int BREAK = 1; - public static final int BREAK_NOT_ALLOWED = 2; + public static final int BREAK = 2; // Chunk kind public static final int CHUNK_FIELD = 1; @@ -169,6 +170,7 @@ public class Alignment { this.wasSplit = false; this.fragmentIndentations = new int[this.fragmentCount]; this.fragmentBreaks = new int[this.fragmentCount]; + Arrays.fill(this.fragmentBreaks, (this.mode & M_FORCE) == 0 ? BREAK_NOT_ALLOWED : NONE); this.currentFragmentStartLine = this.scribe.line; int currentColumn = this.location.outputColumn; @@ -183,17 +185,14 @@ public class Alignment { if ((mode & M_INDENT_ON_COLUMN) != 0) { // Indent broken fragments at next indentation level, based on current column this.breakIndentationLevel = this.scribe.getNextIndentationLevel(currentColumn); - if (this.breakIndentationLevel == this.location.outputIndentationLevel) { - this.breakIndentationLevel += continuationIndent * indentSize; - } - if (continuationIndent == 0) { - this.fragmentBreaks[0] = BREAK_NOT_ALLOWED; - } + this.alternativeBreakIndentationLevel = + this.location.outputIndentationLevel + continuationIndent * indentSize; } else { int baseIndentationLevel = this.location.outputIndentationLevel; if (name != TRAILING_TEXT && this.scribe.currentAlignment != null && - (this.scribe.currentAlignment.mode & M_INDENT_ON_COLUMN) != 0) { - baseIndentationLevel = this.scribe.getNextIndentationLevel(currentColumn); + (this.scribe.currentAlignment.mode & M_INDENT_ON_COLUMN) != 0 && + this.scribe.currentAlignment.fragmentCount > 1) { + baseIndentationLevel = this.scribe.currentAlignment.breakIndentationLevel; } if ((mode & M_INDENT_BY_ONE) != 0) { // Indent broken fragments exactly one level deeper than current indentation @@ -201,11 +200,12 @@ public class Alignment { } else { this.breakIndentationLevel = baseIndentationLevel + continuationIndent * indentSize; } + this.alternativeBreakIndentationLevel = this.breakIndentationLevel; } - this.shiftBreakIndentationLevel = this.breakIndentationLevel + indentSize; // Check for forced alignments if ((this.mode & M_FORCE) != 0) { + this.fragmentBreaks[this.fragmentIndex] = NONE; couldBreak(); } } @@ -289,6 +289,15 @@ public class Alignment { i = this.fragmentIndex; do { if (this.fragmentBreaks[i] == NONE) { + if ((this.mode & M_INDENT_ON_COLUMN) != 0 && i == 0) { + if (this.breakIndentationLevel <= this.alternativeBreakIndentationLevel) { + // Does not make sense to break here unless indentation is reduced. + break; + } + // Change break indentation level and erase previously created breaks. + this.breakIndentationLevel = this.alternativeBreakIndentationLevel; + eraseExistingBreaks(i); + } this.fragmentBreaks[i] = BREAK; this.fragmentIndentations[i] = this.breakIndentationLevel; return wasSplit = true; @@ -308,7 +317,8 @@ public class Alignment { this.fragmentIndentations[0] = this.breakIndentationLevel; for (i = 1; i < this.fragmentCount; i++) { this.fragmentBreaks[i] = BREAK; - this.fragmentIndentations[i] = this.shiftBreakIndentationLevel; + this.fragmentIndentations[i] = + this.breakIndentationLevel + this.scribe.indentationSize; } return wasSplit = true; } @@ -335,7 +345,7 @@ public class Alignment { * #CCCC); */ case M_NEXT_PER_LINE_SPLIT: - if (this.fragmentBreaks[0] == NONE) { + if (this.fragmentBreaks[0] != BREAK) { if (this.fragmentCount > 1 && this.fragmentBreaks[1] == NONE) { if ((this.mode & M_INDENT_ON_COLUMN) != 0) { this.fragmentIndentations[0] = this.breakIndentationLevel; @@ -351,6 +361,15 @@ public class Alignment { } return false; // Cannot split better } + + private void eraseExistingBreaks(int startFragmentIndex) { + for (int j = startFragmentIndex + 1; j < this.fragmentIndentations.length; j++) { + if (this.fragmentBreaks[j] == BREAK) { + this.fragmentBreaks[j] = NONE; + this.fragmentIndentations[j] = 0; + } + } + } public Alignment getAlignment(String targetName) { if (targetName.equals(this.name)) return this; @@ -358,8 +377,27 @@ public class Alignment { return this.enclosing.getAlignment(targetName); } - - // perform alignment effect for current fragment + + public void alignFragment(int fragmentIndex) { + this.fragmentIndex= fragmentIndex; + if (this.fragmentBreaks[fragmentIndex] == BREAK_NOT_ALLOWED) { + this.fragmentBreaks[fragmentIndex] = NONE; // Allow line break. + } + switch (this.mode & SPLIT_MASK) { + case Alignment.M_NEXT_PER_LINE_SPLIT: + case Alignment.M_ONE_PER_LINE_SPLIT: + for (int i = fragmentIndex + 1; i < this.fragmentBreaks.length; i++) { + if (this.fragmentBreaks[i] == BREAK_NOT_ALLOWED) { + this.fragmentBreaks[i] = NONE; // Allow line break. + } + } + break; + } + checkColumn(); + performFragmentEffect(); + } + + // Performs alignment effect for current fragment. public void performFragmentEffect() { if ((this.mode & M_MULTICOLUMN) == 0) { switch (this.mode & SPLIT_MASK) { diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java index 03b146dc723..788dc08c87e 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java @@ -1137,9 +1137,8 @@ public class CodeFormatterTest extends BaseUITestCase { //int function_with_a_long_name(int, int); // //void test() { - // function_with_a_long_name(function(1000000, 2000000, 3000000, 4000000, - // 5000000), - // 6000000); + // function_with_a_long_name( + // function(1000000, 2000000, 3000000, 4000000, 5000000), 6000000); //} public void testFunctionCall_2() throws Exception { fOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, CCorePlugin.SPACE); @@ -2089,21 +2088,43 @@ public class CodeFormatterTest extends BaseUITestCase { //void test() { // int variable1 = 1000000 < 2000000 ? 3000000 + 40000000 : 8000000 + 90000000; - // int variable2 = 1000000 < 2000000 ? - // 3000000 + 40000000 : 8000000 + 900000000; - // int variable3 = 1000000 < 2000000 ? - // 3000000 + 4000000 + 5000000 + 6000000 + 7000000 : 8000000 + 9000000; - // int variable4 = 1000000 < 2000000 ? - // 3000000 + 4000000 + 5000000 + 6000000 + 7000000 : - // 8000000 + 90000000; - //} + // int variable2 = + // 1000000 < 2000000 ? 3000000 + 40000000 : 8000000 + 900000000; + // int variable3 = + // 1000000 < 2000000 ? + // 3000000 + 4000000 + 5000000 + 6000000 + 7000000 : + // 8000000 + 9000000; + // int variable4 = + // 1000000 < 2000000 ? + // 3000000 + 4000000 + 5000000 + 6000000 + 7000000 : + // 8000000 + 90000000; + //} public void testConditionalExpression() throws Exception { fOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, CCorePlugin.SPACE); - fOptions.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION, - Integer.toString(Alignment.M_COMPACT_SPLIT | Alignment.M_INDENT_ON_COLUMN)); assertFormatterResult(); } + //int variable_with_a_long_name, another_variable_with_a_long_name; + // + //int variable = variable_with_a_long_name < another_variable_with_a_long_name ? + //variable_with_a_long_name + another_variable_with_a_long_name : + //variable_with_a_long_name * 2 > another_variable_with_a_long_name ? + //variable_with_a_long_name + another_variable_with_a_long_name : + //variable_with_a_long_name - another_variable_with_a_long_name; + + //int variable_with_a_long_name, another_variable_with_a_long_name; + // + //int variable = + // variable_with_a_long_name < another_variable_with_a_long_name ? + // variable_with_a_long_name + another_variable_with_a_long_name : + // variable_with_a_long_name * 2 > another_variable_with_a_long_name ? + // variable_with_a_long_name + another_variable_with_a_long_name : + // variable_with_a_long_name - another_variable_with_a_long_name; + public void testConditionalExpressionChain() throws Exception { + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, CCorePlugin.SPACE); + assertFormatterResult(); + } + //// Breaking at '<=' is preferred to breaking at '+'. //bool x = 1000000 + 2000000 + 3000000 + 4000000 <= 5000000 + 6000000 + 7000000 + 8000000; @@ -2293,7 +2314,7 @@ public class CodeFormatterTest extends BaseUITestCase { // //void test() { // stream << (variable_with_a_long_name + another_variable_with_a_long_name) - // * variable_with_a_long_name + // * variable_with_a_long_name // << "01234567890123456789"; //} public void testOverloadedLeftShiftChain_4() throws Exception { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java index 0656445bf92..d32891c7e6b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java @@ -116,8 +116,8 @@ public final class CIndenter { prefBlockIndent= prefBlockIndent(); prefArrayIndent= prefArrayIndent(); prefArrayDeepIndent= prefArrayDeepIndent(); - prefTernaryDeepAlign= prefTernaryDeepAlign(); - prefTernaryIndent= prefTernaryIndent(); + prefTernaryDeepAlign= false; + prefTernaryIndent= prefContinuationIndent(); prefCaseIndent= prefCaseIndent(); prefCaseBlockIndent= prefCaseBlockIndent(); prefAssignmentIndent= prefAssignmentIndent(); @@ -183,30 +183,6 @@ public final class CIndenter { return true; } - private boolean prefTernaryDeepAlign() { - String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION); - try { - return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; - } catch (IllegalArgumentException e) { - // ignore and return default - } - return false; - } - - private int prefTernaryIndent() { - String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION); - try { - if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE) - return 1; - else - return prefContinuationIndent(); - } catch (IllegalArgumentException e) { - // ignore and return default - } - - return prefContinuationIndent(); - } - private int prefCaseIndent() { if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH))) return 1; @@ -1031,7 +1007,7 @@ public final class CIndenter { return skipToPreviousListItemOrListStart(); } fPosition= pos; - return skipToStatementStart(danglingElse, false); + return skipToPreviousListItemOrListStart(); case Symbols.TokenQUESTIONMARK: if (fPrefs.prefTernaryDeepAlign) { @@ -1041,7 +1017,7 @@ public final class CIndenter { } return fPosition; - // indentation for blockless introducers: + // Indentation for blockless introducers: case Symbols.TokenDO: case Symbols.TokenWHILE: case Symbols.TokenELSE: