1 11 package org.eclipse.jdt.internal.ui.text; 12 13 import org.eclipse.core.runtime.Assert; 14 15 import org.eclipse.jface.text.BadLocationException; 16 import org.eclipse.jface.text.IDocument; 17 import org.eclipse.jface.text.IRegion; 18 19 import org.eclipse.jdt.core.IJavaProject; 20 import org.eclipse.jdt.core.JavaCore; 21 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; 22 23 import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil; 24 25 26 37 public final class JavaIndenter { 38 39 43 private final class CorePrefs { 44 final boolean prefUseTabs; 45 final int prefTabSize; 46 final int prefIndentationSize; 47 final boolean prefArrayDimensionsDeepIndent; 48 final int prefArrayIndent; 49 final boolean prefArrayDeepIndent; 50 final boolean prefTernaryDeepAlign; 51 final int prefTernaryIndent; 52 final int prefCaseIndent; 53 final int prefAssignmentIndent; 54 final int prefCaseBlockIndent; 55 final int prefSimpleIndent; 56 final int prefBracketIndent; 57 final boolean prefMethodDeclDeepIndent; 58 final int prefMethodDeclIndent; 59 final boolean prefMethodCallDeepIndent; 60 final int prefMethodCallIndent; 61 final boolean prefParenthesisDeepIndent; 62 final int prefParenthesisIndent; 63 final int prefBlockIndent; 64 final int prefMethodBodyIndent; 65 final int prefTypeIndent; 66 final boolean prefIndentBracesForBlocks; 67 final boolean prefIndentBracesForArrays; 68 final boolean prefIndentBracesForMethods; 69 final boolean prefIndentBracesForTypes; 70 final int prefContinuationIndent; 71 final boolean prefHasGenerics; 72 final String prefTabChar; 73 74 private final IJavaProject fProject; 75 76 82 private boolean isStandalone() { 83 return JavaCore.getPlugin() == null; 84 } 85 86 93 private String getCoreFormatterOption(String key) { 94 if (fProject == null) 95 return JavaCore.getOption(key); 96 return fProject.getOption(key, true); 97 } 98 99 CorePrefs(IJavaProject project) { 100 fProject= project; 101 if (isStandalone()) { 102 prefUseTabs= true; 103 prefTabSize= 4; 104 prefIndentationSize= 4; 105 prefArrayDimensionsDeepIndent= true; 106 prefContinuationIndent= 2; 107 prefBlockIndent= 1; 108 prefArrayIndent= prefContinuationIndent; 109 prefArrayDeepIndent= true; 110 prefTernaryDeepAlign= false; 111 prefTernaryIndent= prefContinuationIndent; 112 prefCaseIndent= 0; 113 prefAssignmentIndent= prefBlockIndent; 114 prefCaseBlockIndent= prefBlockIndent; 115 prefIndentBracesForBlocks= false; 116 prefSimpleIndent= (prefIndentBracesForBlocks && prefBlockIndent == 0) ? 1 : prefBlockIndent; 117 prefBracketIndent= prefBlockIndent; 118 prefMethodDeclDeepIndent= true; 119 prefMethodDeclIndent= 1; 120 prefMethodCallDeepIndent= false; 121 prefMethodCallIndent= 1; 122 prefParenthesisDeepIndent= false; 123 prefParenthesisIndent= prefContinuationIndent; 124 prefMethodBodyIndent= 1; 125 prefTypeIndent= 1; 126 prefIndentBracesForArrays= false; 127 prefIndentBracesForMethods= false; 128 prefIndentBracesForTypes= false; 129 prefHasGenerics= false; 130 prefTabChar= JavaCore.TAB; 131 } else { 132 prefUseTabs= prefUseTabs(); 133 prefTabSize= prefTabSize(); 134 prefIndentationSize= prefIndentationSize(); 135 prefArrayDimensionsDeepIndent= prefArrayDimensionsDeepIndent(); 136 prefContinuationIndent= prefContinuationIndent(); 137 prefBlockIndent= prefBlockIndent(); 138 prefArrayIndent= prefArrayIndent(); 139 prefArrayDeepIndent= prefArrayDeepIndent(); 140 prefTernaryDeepAlign= prefTernaryDeepAlign(); 141 prefTernaryIndent= prefTernaryIndent(); 142 prefCaseIndent= prefCaseIndent(); 143 prefAssignmentIndent= prefAssignmentIndent(); 144 prefCaseBlockIndent= prefCaseBlockIndent(); 145 prefIndentBracesForBlocks= prefIndentBracesForBlocks(); 146 prefSimpleIndent= prefSimpleIndent(); 147 prefBracketIndent= prefBracketIndent(); 148 prefMethodDeclDeepIndent= prefMethodDeclDeepIndent(); 149 prefMethodDeclIndent= prefMethodDeclIndent(); 150 prefMethodCallDeepIndent= prefMethodCallDeepIndent(); 151 prefMethodCallIndent= prefMethodCallIndent(); 152 prefParenthesisDeepIndent= prefParenthesisDeepIndent(); 153 prefParenthesisIndent= prefParenthesisIndent(); 154 prefMethodBodyIndent= prefMethodBodyIndent(); 155 prefTypeIndent= prefTypeIndent(); 156 prefIndentBracesForArrays= prefIndentBracesForArrays(); 157 prefIndentBracesForMethods= prefIndentBracesForMethods(); 158 prefIndentBracesForTypes= prefIndentBracesForTypes(); 159 prefHasGenerics= hasGenerics(); 160 prefTabChar= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR); 161 } 162 } 163 164 private boolean prefUseTabs() { 165 return !JavaCore.SPACE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR)); 166 } 167 168 private int prefTabSize() { 169 return CodeFormatterUtil.getTabWidth(fProject); 170 } 171 172 private int prefIndentationSize() { 173 return CodeFormatterUtil.getIndentWidth(fProject); 174 } 175 176 private boolean prefArrayDimensionsDeepIndent() { 177 return true; } 179 180 private int prefArrayIndent() { 181 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_ARRAY_INITIALIZER); 182 try { 183 if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE) 184 return 1; 185 } catch (IllegalArgumentException e) { 186 } 188 189 return prefContinuationIndent(); } 191 192 private boolean prefArrayDeepIndent() { 193 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_ARRAY_INITIALIZER); 194 try { 195 return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; 196 } catch (IllegalArgumentException e) { 197 } 199 200 return true; 201 } 202 203 private boolean prefTernaryDeepAlign() { 204 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION); 205 try { 206 return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; 207 } catch (IllegalArgumentException e) { 208 } 210 return false; 211 } 212 213 private int prefTernaryIndent() { 214 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_CONDITIONAL_EXPRESSION); 215 try { 216 if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE) 217 return 1; 218 else 219 return prefContinuationIndent(); 220 } catch (IllegalArgumentException e) { 221 } 223 224 return prefContinuationIndent(); 225 } 226 227 private int prefCaseIndent() { 228 if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH))) 229 return prefBlockIndent(); 230 else 231 return 0; 232 } 233 234 private int prefAssignmentIndent() { 235 return prefBlockIndent(); 236 } 237 238 private int prefCaseBlockIndent() { 239 if (true) 240 return prefBlockIndent(); 241 242 if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_CASES))) 243 return prefBlockIndent(); 244 else 245 return 0; 246 } 247 248 private int prefSimpleIndent() { 249 if (prefIndentBracesForBlocks() && prefBlockIndent() == 0) 250 return 1; 251 else return prefBlockIndent(); 252 } 253 254 private int prefBracketIndent() { 255 return prefBlockIndent(); 256 } 257 258 private boolean prefMethodDeclDeepIndent() { 259 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION); 260 try { 261 return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; 262 } catch (IllegalArgumentException e) { 263 } 265 266 return true; 267 } 268 269 private int prefMethodDeclIndent() { 270 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION); 271 try { 272 if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE) 273 return 1; 274 else 275 return prefContinuationIndent(); 276 } catch (IllegalArgumentException e) { 277 } 279 return 1; 280 } 281 282 private boolean prefMethodCallDeepIndent() { 283 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION); 284 try { 285 return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; 286 } catch (IllegalArgumentException e) { 287 } 289 return false; } 291 292 private int prefMethodCallIndent() { 293 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION); 294 try { 295 if (DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_BY_ONE) 296 return 1; 297 else 298 return prefContinuationIndent(); 299 } catch (IllegalArgumentException e) { 300 } 302 303 return 1; } 305 306 private boolean prefParenthesisDeepIndent() { 307 if (true) return false; 309 310 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_CONTINUATION_INDENTATION); 311 try { 312 return DefaultCodeFormatterConstants.getIndentStyle(option) == DefaultCodeFormatterConstants.INDENT_ON_COLUMN; 313 } catch (IllegalArgumentException e) { 314 } 316 317 return false; } 319 320 private int prefParenthesisIndent() { 321 return prefContinuationIndent(); 322 } 323 324 private int prefBlockIndent() { 325 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_STATEMENTS_COMPARE_TO_BLOCK); 326 if (DefaultCodeFormatterConstants.FALSE.equals(option)) 327 return 0; 328 329 return 1; } 331 332 private int prefMethodBodyIndent() { 333 if (DefaultCodeFormatterConstants.FALSE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_STATEMENTS_COMPARE_TO_BODY))) 334 return 0; 335 336 return 1; } 338 339 private int prefTypeIndent() { 340 String option= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_TYPE_HEADER); 341 if (DefaultCodeFormatterConstants.FALSE.equals(option)) 342 return 0; 343 344 return 1; } 346 347 private boolean prefIndentBracesForBlocks() { 348 return DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_BLOCK)); 349 } 350 351 private boolean prefIndentBracesForArrays() { 352 return DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_ARRAY_INITIALIZER)); 353 } 354 355 private boolean prefIndentBracesForMethods() { 356 return DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION)); 357 } 358 359 private boolean prefIndentBracesForTypes() { 360 return DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION)); 361 } 362 363 private int prefContinuationIndent() { 364 try { 365 return Integer.parseInt(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_CONTINUATION_INDENTATION)); 366 } catch (NumberFormatException e) { 367 } 369 370 return 2; } 372 private boolean hasGenerics() { 373 return JavaCore.VERSION_1_5.compareTo(getCoreFormatterOption(JavaCore.COMPILER_SOURCE)) <= 0; 374 } 375 } 376 377 378 private final IDocument fDocument; 379 380 private int fIndent; 381 385 private int fAlign; 386 387 private int fPosition; 388 389 private int fPreviousPos; 390 391 private int fToken; 392 393 private int fLine; 394 398 private final JavaHeuristicScanner fScanner; 399 403 private final CorePrefs fPrefs; 404 405 412 public JavaIndenter(IDocument document, JavaHeuristicScanner scanner) { 413 this(document, scanner, null); 414 } 415 416 427 public JavaIndenter(IDocument document, JavaHeuristicScanner scanner, IJavaProject project) { 428 Assert.isNotNull(document); 429 Assert.isNotNull(scanner); 430 fDocument= document; 431 fScanner= scanner; 432 fPrefs= new CorePrefs(project); 433 } 434 435 443 public StringBuffer getReferenceIndentation(int offset) { 444 return getReferenceIndentation(offset, false); 445 } 446 447 456 private StringBuffer getReferenceIndentation(int offset, boolean assumeOpeningBrace) { 457 458 int unit; 459 if (assumeOpeningBrace) 460 unit= findReferencePosition(offset, Symbols.TokenLBRACE); 461 else 462 unit= findReferencePosition(offset, peekChar(offset)); 463 464 if (unit == JavaHeuristicScanner.NOT_FOUND) 466 return null; 467 468 return getLeadingWhitespace(unit); 469 470 } 471 472 480 public StringBuffer computeIndentation(int offset) { 481 return computeIndentation(offset, false); 482 } 483 484 493 public StringBuffer computeIndentation(int offset, boolean assumeOpeningBrace) { 494 495 StringBuffer reference= getReferenceIndentation(offset, assumeOpeningBrace); 496 497 if (fAlign != JavaHeuristicScanner.NOT_FOUND) { 499 try { 500 IRegion line= fDocument.getLineInformationOfOffset(fAlign); 502 int lineOffset= line.getOffset(); 503 return createIndent(lineOffset, fAlign, false); 504 } catch (BadLocationException e) { 505 return null; 506 } 507 } 508 509 if (reference == null) 510 return null; 511 512 return createReusingIndent(reference, fIndent); 514 } 515 516 524 private int computeVisualLength(CharSequence indent) { 525 final int tabSize= fPrefs.prefTabSize; 526 int length= 0; 527 for (int i= 0; i < indent.length(); i++) { 528 char ch= indent.charAt(i); 529 switch (ch) { 530 case '\t': 531 if (tabSize > 0) { 532 int reminder= length % tabSize; 533 length += tabSize - reminder; 534 } 535 break; 536 case ' ': 537 length++; 538 break; 539 } 540 } 541 return length; 542 } 543 544 552 private StringBuffer stripExceedingChars(StringBuffer reference, int indentLength) { 553 final int tabSize= fPrefs.prefTabSize; 554 int measured= 0; 555 int chars= reference.length(); 556 int i= 0; 557 for (; measured < indentLength && i < chars; i++) { 558 char ch= reference.charAt(i); 559 switch (ch) { 560 case '\t': 561 if (tabSize > 0) { 562 int reminder= measured % tabSize; 563 measured += tabSize - reminder; 564 } 565 break; 566 case ' ': 567 measured++; 568 break; 569 } 570 } 571 int deleteFrom= measured > indentLength ? i - 1 : i; 572 573 return reference.delete(deleteFrom, chars); 574 } 575 576 585 private StringBuffer getLeadingWhitespace(int offset) { 586 StringBuffer indent= new StringBuffer (); 587 try { 588 IRegion line= fDocument.getLineInformationOfOffset(offset); 589 int lineOffset= line.getOffset(); 590 int nonWS= fScanner.findNonWhitespaceForwardInAnyPartition(lineOffset, lineOffset + line.getLength()); 591 indent.append(fDocument.get(lineOffset, nonWS - lineOffset)); 592 return indent; 593 } catch (BadLocationException e) { 594 return indent; 595 } 596 } 597 598 618 private StringBuffer createIndent(int start, final int indent, final boolean convertSpaceRunsToTabs) { 619 final boolean convertTabs= fPrefs.prefUseTabs && convertSpaceRunsToTabs; 620 final int tabLen= fPrefs.prefTabSize; 621 final StringBuffer ret= new StringBuffer (); 622 try { 623 int spaces= 0; 624 while (start < indent) { 625 626 char ch= fDocument.getChar(start); 627 if (ch == '\t') { 628 ret.append('\t'); 629 spaces= 0; 630 } else if (convertTabs) { 631 spaces++; 632 if (spaces == tabLen) { 633 ret.append('\t'); 634 spaces= 0; 635 } 636 } else { 637 ret.append(' '); 638 } 639 640 start++; 641 } 642 while (spaces-- > 0) 644 ret.append(' '); 645 646 } catch (BadLocationException e) { 647 } 648 649 return ret; 650 } 651 652 662 private StringBuffer createReusingIndent(StringBuffer buffer, int additional) { 663 int refLength= computeVisualLength(buffer); 664 int addLength= fPrefs.prefIndentationSize * additional; int totalLength= Math.max(0, refLength + addLength); 666 667 668 int minLength= Math.min(totalLength, refLength); 671 int tabSize= fPrefs.prefTabSize; 672 int maxCopyLength= tabSize > 0 ? minLength - minLength % tabSize : minLength; stripExceedingChars(buffer, maxCopyLength); 674 675 676 int missing= totalLength - maxCopyLength; 678 final int tabs, spaces; 679 if (JavaCore.SPACE.equals(fPrefs.prefTabChar)) { 680 tabs= 0; 681 spaces= missing; 682 } else if (JavaCore.TAB.equals(fPrefs.prefTabChar)) { 683 tabs= tabSize > 0 ? missing / tabSize : 0; 684 spaces= tabSize > 0 ? missing % tabSize : missing; 685 } else if (DefaultCodeFormatterConstants.MIXED.equals(fPrefs.prefTabChar)) { 686 tabs= tabSize > 0 ? missing / tabSize : 0; 687 spaces= tabSize > 0 ? missing % tabSize : missing; 688 } else { 689 Assert.isTrue(false); 690 return null; 691 } 692 for(int i= 0; i < tabs; i++) 693 buffer.append('\t'); 694 for(int i= 0; i < spaces; i++) 695 buffer.append(' '); 696 return buffer; 697 } 698 699 709 public int findReferencePosition(int offset) { 710 return findReferencePosition(offset, peekChar(offset)); 711 } 712 713 720 private int peekChar(int offset) { 721 if (offset < fDocument.getLength()) { 722 try { 723 IRegion line= fDocument.getLineInformationOfOffset(offset); 724 int lineOffset= line.getOffset(); 725 int next= fScanner.nextToken(offset, lineOffset + line.getLength()); 726 return next; 727 } catch (BadLocationException e) { 728 } 729 } 730 return Symbols.TokenEOF; 731 } 732 733 759 public int findReferencePosition(int offset, int nextToken) { 760 boolean danglingElse= false; 761 boolean unindent= false; 762 boolean indent= false; 763 boolean matchBrace= false; 764 boolean matchParen= false; 765 boolean matchCase= false; 766 767 if (offset < fDocument.getLength()) { 773 try { 774 IRegion line= fDocument.getLineInformationOfOffset(offset); 775 int lineOffset= line.getOffset(); 776 int prevPos= Math.max(offset - 1, 0); 777 boolean isFirstTokenOnLine= fDocument.get(lineOffset, prevPos + 1 - lineOffset).trim().length() == 0; 778 int prevToken= fScanner.previousToken(prevPos, JavaHeuristicScanner.UNBOUND); 779 boolean bracelessBlockStart= fScanner.isBracelessBlockStart(prevPos, JavaHeuristicScanner.UNBOUND); 780 781 switch (nextToken) { 782 case Symbols.TokenELSE: 783 danglingElse= true; 784 break; 785 case Symbols.TokenCASE: 786 case Symbols.TokenDEFAULT: 787 if (isFirstTokenOnLine) 788 matchCase= true; 789 break; 790 case Symbols.TokenLBRACE: if (bracelessBlockStart && !fPrefs.prefIndentBracesForBlocks) 792 unindent= true; 793 else if ((prevToken == Symbols.TokenCOLON || prevToken == Symbols.TokenEQUAL || prevToken == Symbols.TokenRBRACKET) && !fPrefs.prefIndentBracesForArrays) 794 unindent= true; 795 else if (!bracelessBlockStart && fPrefs.prefIndentBracesForMethods) 796 indent= true; 797 break; 798 case Symbols.TokenRBRACE: if (isFirstTokenOnLine) 800 matchBrace= true; 801 break; 802 case Symbols.TokenRPAREN: 803 if (isFirstTokenOnLine) 804 matchParen= true; 805 break; 806 } 807 } catch (BadLocationException e) { 808 } 809 } else { 810 danglingElse= false; 812 } 813 814 int ref= findReferencePosition(offset, danglingElse, matchBrace, matchParen, matchCase); 815 if (unindent) 816 fIndent--; 817 if (indent) 818 fIndent++; 819 return ref; 820 } 821 822 843 public int findReferencePosition(int offset, boolean danglingElse, boolean matchBrace, boolean matchParen, boolean matchCase) { 844 fIndent= 0; fAlign= JavaHeuristicScanner.NOT_FOUND; 846 fPosition= offset; 847 848 if (matchBrace) { 853 if (skipScope(Symbols.TokenLBRACE, Symbols.TokenRBRACE)) { 854 try { 855 int lineOffset= fDocument.getLineOffset(fLine); 857 if (lineOffset <= fPosition && fDocument.get(lineOffset, fPosition - lineOffset).trim().length() == 0) 858 return fPosition; 859 } catch (BadLocationException e) { 860 } 862 int pos= skipToStatementStart(true, true); 864 fIndent= 0; return pos; 866 } else { 867 int pos= findReferencePosition(offset, danglingElse, false, matchParen, matchCase); 870 fIndent--; 871 return pos; 872 } 873 } 874 875 if (matchParen) { 877 if (skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN)) 878 return fPosition; 879 else { 880 int pos= findReferencePosition(offset, danglingElse, matchBrace, false, matchCase); 883 fIndent--; 884 return pos; 885 } 886 } 887 888 if (matchCase) { 891 return matchCaseAlignment(); 892 } 893 894 nextToken(); 895 switch (fToken) { 896 case Symbols.TokenGREATERTHAN: 897 case Symbols.TokenRBRACE: 898 int pos= fPosition; 901 if (!skipScope()) 902 fPosition= pos; 903 case Symbols.TokenSEMICOLON: 904 return skipToStatementStart(danglingElse, false); 908 909 case Symbols.TokenLPAREN: 911 case Symbols.TokenLBRACE: 912 case Symbols.TokenLBRACKET: 913 return handleScopeIntroduction(offset + 1); 914 915 case Symbols.TokenEOF: 916 return JavaHeuristicScanner.NOT_FOUND; 918 919 case Symbols.TokenEQUAL: 920 fIndent= fPrefs.prefAssignmentIndent; 922 return fPosition; 923 924 case Symbols.TokenCOLON: 925 fIndent= fPrefs.prefCaseBlockIndent; 927 return fPosition; 928 929 case Symbols.TokenQUESTIONMARK: 930 if (fPrefs.prefTernaryDeepAlign) { 931 setFirstElementAlignment(fPosition, offset + 1); 932 return fPosition; 933 } else { 934 fIndent= fPrefs.prefTernaryIndent; 935 return fPosition; 936 } 937 938 case Symbols.TokenDO: 940 case Symbols.TokenWHILE: 941 case Symbols.TokenELSE: 942 fIndent= fPrefs.prefSimpleIndent; 943 return fPosition; 944 945 case Symbols.TokenTRY: 946 return skipToStatementStart(danglingElse, false); 947 case Symbols.TokenRPAREN: 948 int line= fLine; 949 if (skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN)) { 950 int scope= fPosition; 951 nextToken(); 952 if (fToken == Symbols.TokenIF || fToken == Symbols.TokenWHILE || fToken == Symbols.TokenFOR) { 953 fIndent= fPrefs.prefSimpleIndent; 954 return fPosition; 955 } 956 fPosition= scope; 957 if (looksLikeMethodDecl()) { 958 return skipToStatementStart(danglingElse, false); 959 } 960 if (fToken == Symbols.TokenCATCH) { 961 return skipToStatementStart(danglingElse, false); 962 } 963 fPosition= scope; 964 if (looksLikeAnonymousTypeDecl()) { 965 return skipToStatementStart(danglingElse, false); 966 } 967 } 968 fPosition= offset; 970 fLine= line; 971 973 case Symbols.TokenCOMMA: 974 default: 979 return skipToPreviousListItemOrListStart(); 983 984 } 985 } 986 987 994 private int skipToStatementStart(boolean danglingElse, boolean isInBlock) { 995 final int NOTHING= 0; 996 final int READ_PARENS= 1; 997 final int READ_IDENT= 2; 998 int mayBeMethodBody= NOTHING; 999 boolean isTypeBody= false; 1000 while (true) { 1001 nextToken(); 1002 1003 if (isInBlock) { 1004 switch (fToken) { 1005 case Symbols.TokenIF: 1007 case Symbols.TokenELSE: 1008 case Symbols.TokenCATCH: 1009 case Symbols.TokenDO: 1010 case Symbols.TokenWHILE: 1011 case Symbols.TokenFINALLY: 1012 case Symbols.TokenFOR: 1013 case Symbols.TokenTRY: 1014 return fPosition; 1015 1016 case Symbols.TokenSTATIC: 1017 mayBeMethodBody= READ_IDENT; break; 1019 1020 case Symbols.TokenSYNCHRONIZED: 1021 if (mayBeMethodBody != READ_IDENT) 1024 return fPosition; 1025 break; 1026 1027 case Symbols.TokenCLASS: 1028 case Symbols.TokenINTERFACE: 1029 case Symbols.TokenENUM: 1030 isTypeBody= true; 1031 break; 1032 1033 case Symbols.TokenSWITCH: 1034 fIndent= fPrefs.prefCaseIndent; 1035 return fPosition; 1036 } 1037 } 1038 1039 switch (fToken) { 1040 case Symbols.TokenLPAREN: 1044 case Symbols.TokenLBRACE: 1045 case Symbols.TokenLBRACKET: 1046 case Symbols.TokenSEMICOLON: 1047 case Symbols.TokenEOF: 1048 if (isInBlock) 1049 fIndent= getBlockIndent(mayBeMethodBody == READ_IDENT, isTypeBody); 1050 return fPreviousPos; 1052 1053 case Symbols.TokenCOLON: 1054 int pos= fPreviousPos; 1055 if (!isConditional()) 1056 return pos; 1057 break; 1058 1059 case Symbols.TokenRBRACE: 1060 pos= fPreviousPos; if (skipScope() && looksLikeArrayInitializerIntro()) { 1064 continue; } else { 1066 if (isInBlock) 1067 fIndent= getBlockIndent(mayBeMethodBody == READ_IDENT, isTypeBody); 1068 return pos; } 1070 1071 case Symbols.TokenRPAREN: 1073 if (isInBlock) 1074 mayBeMethodBody= READ_PARENS; 1075 case Symbols.TokenRBRACKET: 1076 case Symbols.TokenGREATERTHAN: 1077 pos= fPreviousPos; 1078 if (skipScope()) 1079 break; 1080 else 1081 return pos; 1082 1083 case Symbols.TokenIF: 1087 if (danglingElse) 1088 return fPosition; 1089 else 1090 break; 1091 case Symbols.TokenELSE: 1092 pos= fPosition; 1094 if (skipNextIF()) 1095 break; 1096 else 1097 return pos; 1098 1099 case Symbols.TokenDO: 1100 return fPosition; 1102 1103 case Symbols.TokenWHILE: 1104 pos= fPosition; 1107 if (hasMatchingDo()) { 1108 break; 1110 } else { 1111 fPosition= pos; 1113 break; 1114 } 1115 case Symbols.TokenIDENT: 1116 if (mayBeMethodBody == READ_PARENS) 1117 mayBeMethodBody= READ_IDENT; 1118 break; 1119 1120 default: 1121 1123 } 1124 1125 } 1126 } 1127 1128 private int getBlockIndent(boolean isMethodBody, boolean isTypeBody) { 1129 if (isTypeBody) 1130 return fPrefs.prefTypeIndent + (fPrefs.prefIndentBracesForTypes ? 1 : 0); 1131 else if (isMethodBody) 1132 return fPrefs.prefMethodBodyIndent + (fPrefs.prefIndentBracesForMethods ? 1 : 0); 1133 else 1134 return fIndent; 1135 } 1136 1137 1143 private boolean isConditional() { 1144 while (true) { 1145 nextToken(); 1146 switch (fToken) { 1147 1148 case Symbols.TokenIDENT: 1150 case Symbols.TokenOTHER: continue; 1152 case Symbols.TokenCASE: 1153 return false; 1154 1155 default: 1156 return true; 1157 } 1158 } 1159 } 1160 1161 1169 private int matchCaseAlignment() { 1170 while (true) { 1171 nextToken(); 1172 switch (fToken) { 1173 case Symbols.TokenLPAREN: 1176 case Symbols.TokenLBRACKET: 1177 case Symbols.TokenEOF: 1178 return fPosition; 1179 case Symbols.TokenLBRACE: 1180 fIndent= fPrefs.prefCaseIndent; 1182 return fPosition; 1183 case Symbols.TokenCASE: 1184 case Symbols.TokenDEFAULT: 1185 fIndent= 0; 1187 return fPosition; 1188 1189 case Symbols.TokenRPAREN: 1191 case Symbols.TokenRBRACKET: 1192 case Symbols.TokenRBRACE: 1193 case Symbols.TokenGREATERTHAN: 1194 skipScope(); 1195 break; 1196 1197 default: 1198 continue; 1200 1201 } 1202 } 1203 } 1204 1205 1216 private int skipToPreviousListItemOrListStart() { 1217 int startLine= fLine; 1218 int startPosition= fPosition; 1219 while (true) { 1220 nextToken(); 1221 1222 if (fLine < startLine) { 1224 try { 1225 int lineOffset= fDocument.getLineOffset(startLine); 1226 int bound= Math.min(fDocument.getLength(), startPosition + 1); 1227 fAlign= fScanner.findNonWhitespaceForwardInAnyPartition(lineOffset, bound); 1228 } catch (BadLocationException e) { 1229 } 1231 return startPosition; 1232 } 1233 1234 switch (fToken) { 1235 case Symbols.TokenRPAREN: 1237 case Symbols.TokenRBRACKET: 1238 case Symbols.TokenRBRACE: 1239 case Symbols.TokenGREATERTHAN: 1240 skipScope(); 1241 break; 1242 1243 case Symbols.TokenLPAREN: 1245 case Symbols.TokenLBRACE: 1246 case Symbols.TokenLBRACKET: 1247 return handleScopeIntroduction(startPosition + 1); 1248 1249 case Symbols.TokenSEMICOLON: 1250 return fPosition; 1251 case Symbols.TokenQUESTIONMARK: 1252 if (fPrefs.prefTernaryDeepAlign) { 1253 setFirstElementAlignment(fPosition - 1, fPosition + 1); 1254 return fPosition; 1255 } else { 1256 fIndent= fPrefs.prefTernaryIndent; 1257 return fPosition; 1258 } 1259 case Symbols.TokenEOF: 1260 return 0; 1261 1262 } 1263 } 1264 } 1265 1266 1275 private boolean skipScope() { 1276 switch (fToken) { 1277 case Symbols.TokenRPAREN: 1278 return skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN); 1279 case Symbols.TokenRBRACKET: 1280 return skipScope(Symbols.TokenLBRACKET, Symbols.TokenRBRACKET); 1281 case Symbols.TokenRBRACE: 1282 return skipScope(Symbols.TokenLBRACE, Symbols.TokenRBRACE); 1283 case Symbols.TokenGREATERTHAN: 1284 if (!fPrefs.prefHasGenerics) 1285 return false; 1286 int storedPosition= fPosition; 1287 int storedToken= fToken; 1288 nextToken(); 1289 switch (fToken) { 1290 case Symbols.TokenIDENT: 1291 if (!JavaHeuristicScanner.isGenericStarter(getTokenContent())) 1292 break; 1293 case Symbols.TokenQUESTIONMARK: 1294 case Symbols.TokenGREATERTHAN: 1295 if (skipScope(Symbols.TokenLESSTHAN, Symbols.TokenGREATERTHAN)) 1296 return true; 1297 } 1298 fPosition= storedPosition; 1300 fToken= storedToken; 1301 return false; 1302 1303 default: 1304 Assert.isTrue(false); 1305 return false; 1306 } 1307 } 1308 1309 1315 private CharSequence getTokenContent() { 1316 return new DocumentCharacterIterator(fDocument, fPosition, fPreviousPos); 1317 } 1318 1319 1336 private int handleScopeIntroduction(int bound) { 1337 switch (fToken) { 1338 case Symbols.TokenLPAREN: 1340 int pos= fPosition; 1342 if (looksLikeMethodDecl()) { 1344 if (fPrefs.prefMethodDeclDeepIndent) 1345 return setFirstElementAlignment(pos, bound); 1346 else { 1347 fIndent= fPrefs.prefMethodDeclIndent; 1348 return pos; 1349 } 1350 } else { 1351 fPosition= pos; 1352 if (looksLikeMethodCall()) { 1353 if (fPrefs.prefMethodCallDeepIndent) 1354 return setFirstElementAlignment(pos, bound); 1355 else { 1356 fIndent= fPrefs.prefMethodCallIndent; 1357 return pos; 1358 } 1359 } else if (fPrefs.prefParenthesisDeepIndent) 1360 return setFirstElementAlignment(pos, bound); 1361 } 1362 1363 fIndent= fPrefs.prefParenthesisIndent; 1365 return pos; 1366 1367 case Symbols.TokenLBRACE: 1368 pos= fPosition; 1370 if (looksLikeArrayInitializerIntro()) 1372 if (fPrefs.prefArrayDeepIndent) 1373 return setFirstElementAlignment(pos, bound); 1374 else 1375 fIndent= fPrefs.prefArrayIndent; 1376 else 1377 fIndent= fPrefs.prefBlockIndent; 1378 1379 if (looksLikeArrayInitializerIntro() && !fPrefs.prefIndentBracesForArrays 1382 || !fPrefs.prefIndentBracesForBlocks) { 1383 fPosition= pos; return skipToStatementStart(true, true); } else { 1386 return pos; 1387 } 1388 1389 case Symbols.TokenLBRACKET: 1390 pos= fPosition; 1392 if (fPrefs.prefArrayDimensionsDeepIndent) { 1394 return setFirstElementAlignment(pos, bound); 1395 } 1396 1397 fIndent= fPrefs.prefBracketIndent; 1399 return pos; 1401 default: 1402 Assert.isTrue(false); 1403 return -1; } 1405 } 1406 1407 1417 private int setFirstElementAlignment(int scopeIntroducerOffset, int bound) { 1418 int firstPossible= scopeIntroducerOffset + 1; fAlign= fScanner.findNonWhitespaceForwardInAnyPartition(firstPossible, bound); 1420 if (fAlign == JavaHeuristicScanner.NOT_FOUND) 1421 fAlign= firstPossible; 1422 return fAlign; 1423 } 1424 1425 1426 1432 private boolean looksLikeArrayInitializerIntro() { 1433 nextToken(); 1434 if (fToken == Symbols.TokenEQUAL || skipBrackets()) { 1435 return true; 1436 } 1437 return false; 1438 } 1439 1440 1449 private boolean skipNextIF() { 1450 Assert.isTrue(fToken == Symbols.TokenELSE); 1451 1452 while (true) { 1453 nextToken(); 1454 switch (fToken) { 1455 case Symbols.TokenRPAREN: 1457 case Symbols.TokenRBRACKET: 1458 case Symbols.TokenRBRACE: 1459 case Symbols.TokenGREATERTHAN: 1460 skipScope(); 1461 break; 1462 1463 case Symbols.TokenIF: 1464 return true; 1466 case Symbols.TokenELSE: 1467 skipNextIF(); 1469 break; 1470 1471 case Symbols.TokenLPAREN: 1473 case Symbols.TokenLBRACE: 1474 case Symbols.TokenLBRACKET: 1475 case Symbols.TokenEOF: 1476 return false; 1477 } 1478 } 1479 } 1480 1481 1482 1491 private boolean hasMatchingDo() { 1492 Assert.isTrue(fToken == Symbols.TokenWHILE); 1493 nextToken(); 1494 switch (fToken) { 1495 case Symbols.TokenRBRACE: 1496 skipScope(); case Symbols.TokenSEMICOLON: 1498 skipToStatementStart(false, false); 1499 return fToken == Symbols.TokenDO; 1500 } 1501 return false; 1502 } 1503 1504 1511 private boolean skipBrackets() { 1512 if (fToken == Symbols.TokenRBRACKET) { 1513 nextToken(); 1514 if (fToken == Symbols.TokenLBRACKET) { 1515 return true; 1516 } 1517 } 1518 return false; 1519 } 1520 1521 1526 private void nextToken() { 1527 nextToken(fPosition); 1528 } 1529 1530 1537 private void nextToken(int start) { 1538 fToken= fScanner.previousToken(start - 1, JavaHeuristicScanner.UNBOUND); 1539 fPreviousPos= start; 1540 fPosition= fScanner.getPosition() + 1; 1541 try { 1542 fLine= fDocument.getLineOfOffset(fPosition); 1543 } catch (BadLocationException e) { 1544 fLine= -1; 1545 } 1546 } 1547 1548 1559 private boolean looksLikeMethodDecl() { 1560 1566 1567 nextToken(); 1568 if (fToken == Symbols.TokenIDENT) { do nextToken(); 1570 while (skipBrackets()); 1572 return fToken == Symbols.TokenIDENT; 1574 } 1575 return false; 1576 } 1577 1578 1587 private boolean looksLikeAnonymousTypeDecl() { 1588 1589 nextToken(); 1590 if (fToken == Symbols.TokenIDENT) { nextToken(); 1592 while (fToken == Symbols.TokenOTHER) { nextToken(); 1594 if (fToken != Symbols.TokenIDENT) return false; 1596 nextToken(); 1597 } 1598 return fToken == Symbols.TokenNEW; 1599 } 1600 return false; 1601 } 1602 1603 1613 private boolean looksLikeMethodCall() { 1614 nextToken(); 1616 return fToken == Symbols.TokenIDENT; } 1618 1619 1628 private boolean skipScope(int openToken, int closeToken) { 1629 1630 int depth= 1; 1631 1632 while (true) { 1633 nextToken(); 1634 1635 if (fToken == closeToken) { 1636 depth++; 1637 } else if (fToken == openToken) { 1638 depth--; 1639 if (depth == 0) 1640 return true; 1641 } else if (fToken == Symbols.TokenEOF) { 1642 return false; 1643 } 1644 } 1645 } 1646} 1647 | Popular Tags |