1 11 package org.eclipse.jdt.internal.formatter; 12 13 import java.util.Arrays ; 14 import java.util.Collections ; 15 import java.util.Comparator ; 16 import java.util.List ; 17 import java.util.Map ; 18 19 import org.eclipse.jdt.core.JavaCore; 20 import org.eclipse.jdt.core.compiler.CharOperation; 21 import org.eclipse.jdt.core.compiler.InvalidInputException; 22 import org.eclipse.jdt.core.dom.ASTVisitor; 23 import org.eclipse.jdt.core.dom.Annotation; 24 import org.eclipse.jdt.core.dom.Comment; 25 import org.eclipse.jdt.core.dom.CompilationUnit; 26 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 27 import org.eclipse.jdt.internal.compiler.parser.Scanner; 28 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; 29 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; 30 import org.eclipse.jdt.internal.formatter.align.Alignment; 31 import org.eclipse.jdt.internal.formatter.align.Alignment2; 32 import org.eclipse.jdt.internal.formatter.align.AlignmentException; 33 import org.eclipse.text.edits.MultiTextEdit; 34 import org.eclipse.text.edits.ReplaceEdit; 35 import org.eclipse.text.edits.TextEdit; 36 37 41 public class Scribe2 { 42 public static final String EMPTY_STRING = ""; 44 private static final int INITIAL_SIZE = 100; 45 46 private boolean checkLineWrapping; 47 48 public int column; 49 private List comments; 50 51 public Alignment2 currentAlignment; 53 public int currentToken; 54 55 private OptimizedReplaceEdit[] edits; 57 public int editsIndex; 58 59 public CodeFormatterVisitor2 formatter; 60 public int indentationLevel; 61 public int lastNumberOfNewLines; 62 public int line; 63 64 private String lineSeparator; 65 public Alignment2 memberAlignment; 66 public boolean needSpace = false; 67 68 public int nlsTagCounter; 69 public int pageWidth; 70 public boolean pendingSpace = false; 71 72 public Scanner scanner; 73 public int scannerEndPosition; 74 public int tabLength; 75 public int indentationSize; 76 private int textRegionEnd; 77 private int textRegionStart; 78 public int tabChar; 79 public int numberOfIndentations; 80 private boolean useTabsOnlyForLeadingIndents; 81 CompilationUnit unit; 82 83 84 private final boolean indentEmptyLines; 85 86 Scribe2(CodeFormatterVisitor2 formatter, Map settings, int offset, int length, CompilationUnit unit) { 87 if (settings != null) { 88 Object sourceLevelOption = settings.get(JavaCore.COMPILER_SOURCE); 89 long sourceLevel = ClassFileConstants.JDK1_3; 90 if (JavaCore.VERSION_1_4.equals(sourceLevelOption)) { 91 sourceLevel = ClassFileConstants.JDK1_4; 92 } else if (JavaCore.VERSION_1_5.equals(sourceLevelOption)) { 93 sourceLevel = ClassFileConstants.JDK1_5; 94 } 95 this.scanner = new Scanner(true, true, false, sourceLevel, null, null, true); 96 } else { 97 this.scanner = new Scanner(true, true, false, ClassFileConstants.JDK1_3, null, null, true); 98 } 99 this.formatter = formatter; 100 this.pageWidth = formatter.preferences.page_width; 101 this.tabLength = formatter.preferences.tab_size; 102 this.indentationLevel= 0; this.numberOfIndentations = 0; 104 this.useTabsOnlyForLeadingIndents = formatter.preferences.use_tabs_only_for_leading_indentations; 105 this.indentEmptyLines = formatter.preferences.indent_empty_lines; 106 this.tabChar = formatter.preferences.tab_char; 107 if (this.tabChar == DefaultCodeFormatterOptions.MIXED) { 108 this.indentationSize = formatter.preferences.indentation_size; 109 } else { 110 this.indentationSize = this.tabLength; 111 } 112 this.lineSeparator = formatter.preferences.line_separator; 113 this.indentationLevel = formatter.preferences.initial_indentation_level * this.indentationSize; 114 this.textRegionStart = offset; 115 this.textRegionEnd = offset + length - 1; 116 if (unit != null) { 117 this.unit = unit; 118 this.comments = unit.getCommentList(); 119 } 120 reset(); 121 } 122 123 private final void addDeleteEdit(int start, int end) { 124 if (this.edits.length == this.editsIndex) { 125 resize(); 127 } 128 addOptimizedReplaceEdit(start, end - start + 1, EMPTY_STRING); 129 } 130 131 public final void addInsertEdit(int insertPosition, String insertedString) { 132 if (this.edits.length == this.editsIndex) { 133 resize(); 135 } 136 addOptimizedReplaceEdit(insertPosition, 0, insertedString); 137 } 138 139 private final void addOptimizedReplaceEdit(int offset, int length, String replacement) { 140 if (this.editsIndex > 0) { 141 final OptimizedReplaceEdit previous = this.edits[this.editsIndex-1]; 143 final int previousOffset = previous.offset; 144 final int previousLength = previous.length; 145 final int endOffsetOfPreviousEdit = previousOffset + previousLength; 146 final int replacementLength = replacement.length(); 147 final String previousReplacement = previous.replacement; 148 final int previousReplacementLength = previousReplacement.length(); 149 if (previousOffset == offset && previousLength == length && (replacementLength == 0 || previousReplacementLength == 0)) { 150 if (this.currentAlignment != null) { 151 final Location2 location = this.currentAlignment.location; 152 if (location.editsIndex == this.editsIndex) { 153 location.editsIndex--; 154 location.textEdit = previous; 155 } 156 } 157 this.editsIndex--; 158 return; 159 } 160 if (endOffsetOfPreviousEdit == offset) { 161 if (length != 0) { 162 if (replacementLength != 0) { 163 this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousLength + length, previousReplacement + replacement); 164 } else if (previousLength + length == previousReplacementLength) { 165 boolean canBeRemoved = true; 167 loop: for (int i = previousOffset; i < previousOffset + previousReplacementLength; i++) { 168 if (scanner.source[i] != previousReplacement.charAt(i - previousOffset)) { 169 this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousReplacementLength, previousReplacement); 170 canBeRemoved = false; 171 break loop; 172 } 173 } 174 if (canBeRemoved) { 175 if (this.currentAlignment != null) { 176 final Location2 location = this.currentAlignment.location; 177 if (location.editsIndex == this.editsIndex) { 178 location.editsIndex--; 179 location.textEdit = previous; 180 } 181 } 182 this.editsIndex--; 183 } 184 } else { 185 this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousLength + length, previousReplacement); 186 } 187 } else { 188 if (replacementLength != 0) { 189 this.edits[this.editsIndex - 1] = new OptimizedReplaceEdit(previousOffset, previousLength, previousReplacement + replacement); 190 } 191 } 192 } else { 193 this.edits[this.editsIndex++] = new OptimizedReplaceEdit(offset, length, replacement); 194 } 195 } else { 196 this.edits[this.editsIndex++] = new OptimizedReplaceEdit(offset, length, replacement); 197 } 198 } 199 200 public final void addReplaceEdit(int start, int end, String replacement) { 201 if (this.edits.length == this.editsIndex) { 202 resize(); 204 } 205 addOptimizedReplaceEdit(start, end - start + 1, replacement); 206 } 207 208 public void alignFragment(Alignment2 alignment, int fragmentIndex){ 209 alignment.fragmentIndex = fragmentIndex; 210 alignment.checkColumn(); 211 alignment.performFragmentEffect(); 212 } 213 214 public void checkNLSTag(int sourceStart) { 215 if (hasNLSTag(sourceStart)) { 216 this.nlsTagCounter++; 217 } 218 } 219 public void consumeNextToken() { 220 printComment(); 221 try { 222 this.currentToken = this.scanner.getNextToken(); 223 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 224 } catch (InvalidInputException e) { 225 throw new AbortFormatting(e); 226 } 227 } 228 public Alignment2 createAlignment(String name, int mode, int count, int sourceRestart){ 229 return createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart); 230 } 231 232 public Alignment2 createAlignment(String name, int mode, int count, int sourceRestart, boolean adjust){ 233 return createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart, adjust); 234 } 235 236 public Alignment2 createAlignment(String name, int mode, int tieBreakRule, int count, int sourceRestart){ 237 return createAlignment(name, mode, tieBreakRule, count, sourceRestart, this.formatter.preferences.continuation_indentation, false); 238 } 239 240 public Alignment2 createAlignment(String name, int mode, int count, int sourceRestart, int continuationIndent, boolean adjust){ 241 return createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart, continuationIndent, adjust); 242 } 243 244 public Alignment2 createAlignment(String name, int mode, int tieBreakRule, int count, int sourceRestart, int continuationIndent, boolean adjust){ 245 Alignment2 alignment = new Alignment2(name, mode, tieBreakRule, this, count, sourceRestart, continuationIndent); 246 if (adjust && this.memberAlignment != null) { 248 Alignment2 current = this.memberAlignment; 249 while (current.enclosing != null) { 250 current = current.enclosing; 251 } 252 if ((current.mode & Alignment.M_MULTICOLUMN) != 0) { 253 final int indentSize = this.indentationSize; 254 switch(current.chunkKind) { 255 case Alignment.CHUNK_METHOD : 256 case Alignment.CHUNK_TYPE : 257 if ((mode & Alignment.M_INDENT_BY_ONE) != 0) { 258 alignment.breakIndentationLevel = this.indentationLevel + indentSize; 259 } else { 260 alignment.breakIndentationLevel = this.indentationLevel + continuationIndent * indentSize; 261 } 262 alignment.update(); 263 break; 264 case Alignment.CHUNK_FIELD : 265 if ((mode & Alignment.M_INDENT_BY_ONE) != 0) { 266 alignment.breakIndentationLevel = current.originalIndentationLevel + indentSize; 267 } else { 268 alignment.breakIndentationLevel = current.originalIndentationLevel + continuationIndent * indentSize; 269 } 270 alignment.update(); 271 break; 272 } 273 } else { 274 switch(current.mode & Alignment.SPLIT_MASK) { 275 case Alignment.M_COMPACT_SPLIT : 276 case Alignment.M_COMPACT_FIRST_BREAK_SPLIT : 277 case Alignment.M_NEXT_PER_LINE_SPLIT : 278 case Alignment.M_NEXT_SHIFTED_SPLIT : 279 case Alignment.M_ONE_PER_LINE_SPLIT : 280 final int indentSize = this.indentationSize; 281 switch(current.chunkKind) { 282 case Alignment.CHUNK_METHOD : 283 case Alignment.CHUNK_TYPE : 284 if ((mode & Alignment.M_INDENT_BY_ONE) != 0) { 285 alignment.breakIndentationLevel = this.indentationLevel + indentSize; 286 } else { 287 alignment.breakIndentationLevel = this.indentationLevel + continuationIndent * indentSize; 288 } 289 alignment.update(); 290 break; 291 case Alignment.CHUNK_FIELD : 292 if ((mode & Alignment.M_INDENT_BY_ONE) != 0) { 293 alignment.breakIndentationLevel = current.originalIndentationLevel + indentSize; 294 } else { 295 alignment.breakIndentationLevel = current.originalIndentationLevel + continuationIndent * indentSize; 296 } 297 alignment.update(); 298 break; 299 } 300 break; 301 } 302 } 303 } 304 return alignment; 305 } 306 307 public Alignment2 createMemberAlignment(String name, int mode, int count, int sourceRestart) { 308 Alignment2 mAlignment = createAlignment(name, mode, Alignment.R_INNERMOST, count, sourceRestart); 309 mAlignment.breakIndentationLevel = this.indentationLevel; 310 return mAlignment; 311 } 312 313 public void enterAlignment(Alignment2 alignment){ 314 alignment.enclosing = this.currentAlignment; 315 this.currentAlignment = alignment; 316 } 317 318 public void enterMemberAlignment(Alignment2 alignment) { 319 alignment.enclosing = this.memberAlignment; 320 this.memberAlignment = alignment; 321 } 322 323 public void exitAlignment(Alignment2 alignment, boolean discardAlignment){ 324 Alignment2 current = this.currentAlignment; 325 while (current != null){ 326 if (current == alignment) break; 327 current = current.enclosing; 328 } 329 if (current == null) { 330 throw new AbortFormatting("could not find matching alignment: "+alignment); } 332 this.indentationLevel = alignment.location.outputIndentationLevel; 333 this.numberOfIndentations = alignment.location.numberOfIndentations; 334 if (discardAlignment){ 335 this.currentAlignment = alignment.enclosing; 336 } 337 } 338 339 public void exitMemberAlignment(Alignment2 alignment){ 340 Alignment2 current = this.memberAlignment; 341 while (current != null){ 342 if (current == alignment) break; 343 current = current.enclosing; 344 } 345 if (current == null) { 346 throw new AbortFormatting("could not find matching alignment: "+alignment); } 348 this.indentationLevel = current.location.outputIndentationLevel; 349 this.numberOfIndentations = current.location.numberOfIndentations; 350 this.memberAlignment = current.enclosing; 351 } 352 353 public Alignment2 getAlignment(String name){ 354 if (this.currentAlignment != null) { 355 return this.currentAlignment.getAlignment(name); 356 } 357 return null; 358 } 359 360 364 public int getColumnIndentationLevel() { 365 return this.column - 1; 366 } 367 368 public String getEmptyLines(int linesNumber) { 369 if (this.nlsTagCounter > 0) { 370 return EMPTY_STRING; 371 } 372 StringBuffer buffer = new StringBuffer (); 373 if (lastNumberOfNewLines == 0) { 374 linesNumber++; for (int i = 0; i < linesNumber; i++) { 376 if (indentEmptyLines) printIndentationIfNecessary(buffer); 377 buffer.append(this.lineSeparator); 378 } 379 lastNumberOfNewLines += linesNumber; 380 line += linesNumber; 381 column = 1; 382 needSpace = false; 383 this.pendingSpace = false; 384 } else if (lastNumberOfNewLines == 1) { 385 for (int i = 0; i < linesNumber; i++) { 386 if (indentEmptyLines) printIndentationIfNecessary(buffer); 387 buffer.append(this.lineSeparator); 388 } 389 lastNumberOfNewLines += linesNumber; 390 line += linesNumber; 391 column = 1; 392 needSpace = false; 393 this.pendingSpace = false; 394 } else { 395 if ((lastNumberOfNewLines - 1) >= linesNumber) { 396 return EMPTY_STRING; 398 } 399 final int realNewLineNumber = linesNumber - lastNumberOfNewLines + 1; 400 for (int i = 0; i < realNewLineNumber; i++) { 401 if (indentEmptyLines) printIndentationIfNecessary(buffer); 402 buffer.append(this.lineSeparator); 403 } 404 lastNumberOfNewLines += realNewLineNumber; 405 line += realNewLineNumber; 406 column = 1; 407 needSpace = false; 408 this.pendingSpace = false; 409 } 410 return String.valueOf(buffer); 411 } 412 413 public OptimizedReplaceEdit getLastEdit() { 414 if (this.editsIndex > 0) { 415 return this.edits[this.editsIndex - 1]; 416 } 417 return null; 418 } 419 Alignment2 getMemberAlignment() { 420 return this.memberAlignment; 421 } 422 423 public String getNewLine() { 424 if (this.nlsTagCounter > 0) { 425 return EMPTY_STRING; 426 } 427 if (lastNumberOfNewLines >= 1) { 428 column = 1; return EMPTY_STRING; 430 } 431 line++; 432 lastNumberOfNewLines = 1; 433 column = 1; 434 needSpace = false; 435 this.pendingSpace = false; 436 return this.lineSeparator; 437 } 438 439 443 public int getNextIndentationLevel(int someColumn) { 444 int indent = someColumn - 1; 445 if (indent == 0) 446 return this.indentationLevel; 447 if (this.tabChar == DefaultCodeFormatterOptions.TAB) { 448 if (this.useTabsOnlyForLeadingIndents) { 449 return indent; 450 } 451 int rem = indent % this.indentationSize; 452 int addition = rem == 0 ? 0 : this.indentationSize - rem; return indent + addition; 454 } else { 455 return indent; 456 } 457 } 458 459 private String getPreserveEmptyLines(int count) { 460 if (count > 0) { 461 if (this.formatter.preferences.number_of_empty_lines_to_preserve != 0) { 462 int linesToPreserve = Math.min(count, this.formatter.preferences.number_of_empty_lines_to_preserve); 463 return this.getEmptyLines(linesToPreserve); 464 } else { 465 return getNewLine(); 466 } 467 } 468 return EMPTY_STRING; 469 } 470 471 public TextEdit getRootEdit() { 472 MultiTextEdit edit = null; 473 int length = this.textRegionEnd - this.textRegionStart + 1; 474 if (this.textRegionStart <= 0) { 475 if (length <= 0) { 476 edit = new MultiTextEdit(0, 0); 477 } else { 478 edit = new MultiTextEdit(0, this.textRegionEnd + 1); 479 } 480 } else { 481 edit = new MultiTextEdit(this.textRegionStart, this.textRegionEnd - this.textRegionStart + 1); 482 } 483 for (int i= 0, max = this.editsIndex; i < max; i++) { 484 OptimizedReplaceEdit currentEdit = edits[i]; 485 if (isValidEdit(currentEdit)) { 486 edit.addChild(new ReplaceEdit(currentEdit.offset, currentEdit.length, currentEdit.replacement)); 487 } 488 } 489 this.edits = null; 490 return edit; 491 } 492 493 public void handleLineTooLong() { 494 int relativeDepth = 0, outerMostDepth = -1; 497 Alignment2 targetAlignment = this.currentAlignment; 498 while (targetAlignment != null){ 499 if (targetAlignment.tieBreakRule == Alignment.R_OUTERMOST && targetAlignment.couldBreak()){ 500 outerMostDepth = relativeDepth; 501 } 502 targetAlignment = targetAlignment.enclosing; 503 relativeDepth++; 504 } 505 if (outerMostDepth >= 0) { 506 throw new AlignmentException(AlignmentException.LINE_TOO_LONG, outerMostDepth); 507 } 508 relativeDepth = 0; 510 targetAlignment = this.currentAlignment; 511 while (targetAlignment != null){ 512 if (targetAlignment.couldBreak()){ 513 throw new AlignmentException(AlignmentException.LINE_TOO_LONG, relativeDepth); 514 } 515 targetAlignment = targetAlignment.enclosing; 516 relativeDepth++; 517 } 518 } 520 521 524 private boolean hasNLSTag(int sourceStart) { 525 final Comment comment = this.unit.getAST().newBlockComment(); 526 comment.setSourceRange(sourceStart, 1); 527 int index = Collections.binarySearch(this.comments, comment, new Comparator () { 528 public int compare(Object o1, Object o2) { 529 Comment comment1 = (Comment) o1; 530 Comment comment2 = (Comment) o2; 531 return comment1.getStartPosition() - comment2.getStartPosition(); 532 } 533 }); 534 final int lineNumber = this.unit.getLineNumber(sourceStart); 535 if (index < 0) { 536 index = -index - 1; 537 final int commentLength = this.comments.size(); 538 for (int i = index; i < commentLength; i++) { 539 Comment currentComment = (Comment) comments.get(i); 540 final int start = currentComment.getStartPosition(); 541 if (this.unit.getLineNumber(start) == lineNumber) { 542 if (currentComment.isLineComment()) { 543 return CharOperation.indexOf(Scanner.TAG_PREFIX, this.scanner.source, true, start) != -1; 544 } 545 } else { 546 return false; 547 } 548 } 549 } 550 return false; 551 } 552 553 public void indent() { 554 this.indentationLevel += this.indentationSize; 555 this.numberOfIndentations++; 556 } 557 558 561 public void initializeScanner(char[] compilationUnitSource) { 562 this.scanner.setSource(compilationUnitSource); 563 this.scannerEndPosition = compilationUnitSource.length; 564 this.scanner.resetTo(0, this.scannerEndPosition); 565 this.edits = new OptimizedReplaceEdit[INITIAL_SIZE]; 566 } 567 568 private boolean isValidEdit(OptimizedReplaceEdit edit) { 569 final int editLength= edit.length; 570 final int editReplacementLength= edit.replacement.length(); 571 final int editOffset= edit.offset; 572 if (editLength != 0) { 573 if (this.textRegionStart <= editOffset && (editOffset + editLength - 1) <= this.textRegionEnd) { 574 if (editReplacementLength != 0 && editLength == editReplacementLength) { 575 for (int i = editOffset, max = editOffset + editLength; i < max; i++) { 576 if (scanner.source[i] != edit.replacement.charAt(i - editOffset)) { 577 return true; 578 } 579 } 580 return false; 581 } else { 582 return true; 583 } 584 } else if (editOffset + editLength == this.textRegionStart) { 585 int i = editOffset; 586 for (int max = editOffset + editLength; i < max; i++) { 587 int replacementStringIndex = i - editOffset; 588 if (replacementStringIndex >= editReplacementLength || scanner.source[i] != edit.replacement.charAt(replacementStringIndex)) { 589 break; 590 } 591 } 592 if (i - editOffset != editReplacementLength && i != editOffset + editLength - 1) { 593 edit.offset = textRegionStart; 594 edit.length = 0; 595 edit.replacement = edit.replacement.substring(i - editOffset); 596 return true; 597 } 598 } 599 } else if (this.textRegionStart <= editOffset && editOffset <= this.textRegionEnd) { 600 return true; 601 } else if (editOffset == this.scannerEndPosition && editOffset == this.textRegionEnd + 1) { 602 return true; 603 } 604 return false; 605 } 606 607 private void preserveEmptyLines(int count, int insertPosition) { 608 if (count > 0) { 609 if (this.formatter.preferences.number_of_empty_lines_to_preserve != 0) { 610 int linesToPreserve = Math.min(count, this.formatter.preferences.number_of_empty_lines_to_preserve); 611 this.printEmptyLines(linesToPreserve, insertPosition); 612 } else { 613 printNewLine(insertPosition); 614 } 615 } 616 } 617 618 private void print(char[] s, boolean considerSpaceIfAny) { 619 if (checkLineWrapping && s.length + column > this.pageWidth) { 620 handleLineTooLong(); 621 } 622 this.lastNumberOfNewLines = 0; 623 printIndentationIfNecessary(); 624 if (considerSpaceIfAny) { 625 this.space(); 626 } 627 if (this.pendingSpace) { 628 this.addInsertEdit(this.scanner.getCurrentTokenStartPosition(), " "); } 630 this.pendingSpace = false; 631 this.needSpace = false; 632 column += s.length; 633 needSpace = true; 634 } 635 636 private void printBlockComment(char[] s, boolean isJavadoc) { 637 int currentTokenStartPosition = this.scanner.getCurrentTokenStartPosition(); 638 int currentTokenEndPosition = this.scanner.getCurrentTokenEndPosition() + 1; 639 640 this.scanner.resetTo(currentTokenStartPosition, currentTokenEndPosition - 1); 641 int currentCharacter; 642 boolean isNewLine = false; 643 int start = currentTokenStartPosition; 644 int nextCharacterStart = currentTokenStartPosition; 645 printIndentationIfNecessary(); 646 if (this.pendingSpace) { 647 this.addInsertEdit(currentTokenStartPosition, " "); } 649 this.needSpace = false; 650 this.pendingSpace = false; 651 int previousStart = currentTokenStartPosition; 652 653 while (nextCharacterStart <= currentTokenEndPosition && (currentCharacter = this.scanner.getNextChar()) != -1) { 654 nextCharacterStart = this.scanner.currentPosition; 655 656 switch(currentCharacter) { 657 case '\r' : 658 start = previousStart; 659 isNewLine = true; 660 if (this.scanner.getNextChar('\n')) { 661 currentCharacter = '\n'; 662 nextCharacterStart = this.scanner.currentPosition; 663 } 664 break; 665 case '\n' : 666 start = previousStart; 667 isNewLine = true; 668 break; 669 default: 670 if (isNewLine) { 671 if (ScannerHelper.isWhitespace((char) currentCharacter)) { 672 int previousStartPosition = this.scanner.currentPosition; 673 while(currentCharacter != -1 && currentCharacter != '\r' && currentCharacter != '\n' && ScannerHelper.isWhitespace((char) currentCharacter)) { 674 previousStart = nextCharacterStart; 675 previousStartPosition = this.scanner.currentPosition; 676 currentCharacter = this.scanner.getNextChar(); 677 nextCharacterStart = this.scanner.currentPosition; 678 } 679 if (currentCharacter == '\r' || currentCharacter == '\n') { 680 nextCharacterStart = previousStartPosition; 681 } 682 } 683 this.column = 1; 684 this.line++; 685 686 StringBuffer buffer = new StringBuffer (); 687 buffer.append(this.lineSeparator); 688 printIndentationIfNecessary(buffer); 689 buffer.append(' '); 690 691 addReplaceEdit(start, previousStart - 1, String.valueOf(buffer)); 692 } else { 693 this.column += (nextCharacterStart - previousStart); 694 } 695 isNewLine = false; 696 } 697 previousStart = nextCharacterStart; 698 this.scanner.currentPosition = nextCharacterStart; 699 } 700 this.lastNumberOfNewLines = 0; 701 needSpace = false; 702 this.scanner.resetTo(currentTokenEndPosition, this.scannerEndPosition - 1); 703 if (isJavadoc) { 704 printNewLine(); 705 } 706 } 707 708 public void printEndOfCompilationUnit() { 709 try { 710 int currentTokenStartPosition = this.scanner.currentPosition; 712 boolean hasComment = false; 713 boolean hasLineComment = false; 714 boolean hasWhitespace = false; 715 int count = 0; 716 while (true) { 717 this.currentToken = this.scanner.getNextToken(); 718 switch(this.currentToken) { 719 case TerminalTokens.TokenNameWHITESPACE : 720 char[] whiteSpaces = this.scanner.getCurrentTokenSource(); 721 count = 0; 722 for (int i = 0, max = whiteSpaces.length; i < max; i++) { 723 switch(whiteSpaces[i]) { 724 case '\r' : 725 if ((i + 1) < max) { 726 if (whiteSpaces[i + 1] == '\n') { 727 i++; 728 } 729 } 730 count++; 731 break; 732 case '\n' : 733 count++; 734 } 735 } 736 if (count == 0) { 737 hasWhitespace = true; 738 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 739 } else if (hasComment) { 740 if (count == 1) { 741 this.printNewLine(this.scanner.getCurrentTokenStartPosition()); 742 } else { 743 preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition()); 744 } 745 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 746 } else if (hasLineComment) { 747 this.preserveEmptyLines(count, this.scanner.getCurrentTokenStartPosition()); 748 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 749 } else { 750 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 751 } 752 currentTokenStartPosition = this.scanner.currentPosition; 753 break; 754 case TerminalTokens.TokenNameCOMMENT_LINE : 755 if (count >= 1) { 756 if (count > 1) { 757 preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition()); 758 } else if (count == 1) { 759 printNewLine(this.scanner.getCurrentTokenStartPosition()); 760 } 761 } else if (hasWhitespace) { 762 space(); 763 } 764 hasWhitespace = false; 765 this.printCommentLine(this.scanner.getRawTokenSource()); 766 currentTokenStartPosition = this.scanner.currentPosition; 767 hasLineComment = true; 768 count = 0; 769 break; 770 case TerminalTokens.TokenNameCOMMENT_BLOCK : 771 if (count >= 1) { 772 if (count > 1) { 773 preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition()); 774 } else if (count == 1) { 775 printNewLine(this.scanner.getCurrentTokenStartPosition()); 776 } 777 } else if (hasWhitespace) { 778 space(); 779 } 780 hasWhitespace = false; 781 this.printBlockComment(this.scanner.getRawTokenSource(), false); 782 currentTokenStartPosition = this.scanner.currentPosition; 783 hasLineComment = false; 784 hasComment = true; 785 count = 0; 786 break; 787 case TerminalTokens.TokenNameCOMMENT_JAVADOC : 788 if (count >= 1) { 789 if (count > 1) { 790 preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition()); 791 } else if (count == 1) { 792 printNewLine(this.scanner.getCurrentTokenStartPosition()); 793 } 794 } else if (hasWhitespace) { 795 space(); 796 } 797 hasWhitespace = false; 798 this.printBlockComment(this.scanner.getRawTokenSource(), true); 799 currentTokenStartPosition = this.scanner.currentPosition; 800 hasLineComment = false; 801 hasComment = true; 802 count = 0; 803 break; 804 case TerminalTokens.TokenNameSEMICOLON : 805 char[] currentTokenSource = this.scanner.getRawTokenSource(); 806 this.print(currentTokenSource, this.formatter.preferences.insert_space_before_semicolon); 807 break; 808 case TerminalTokens.TokenNameEOF : 809 if (count >= 1 || this.formatter.preferences.insert_new_line_at_end_of_file_if_missing) { 810 this.printNewLine(this.scannerEndPosition); 811 } 812 return; 813 default : 814 this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); 816 return; 817 } 818 } 819 } catch (InvalidInputException e) { 820 throw new AbortFormatting(e); 821 } 822 } 823 824 public void printComment() { 825 try { 826 int currentTokenStartPosition = this.scanner.currentPosition; 828 boolean hasComment = false; 829 boolean hasLineComment = false; 830 boolean hasWhitespace = false; 831 int count = 0; 832 while ((this.currentToken = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { 833 switch(this.currentToken) { 834 case TerminalTokens.TokenNameWHITESPACE : 835 char[] whiteSpaces = this.scanner.getCurrentTokenSource(); 836 count = 0; 837 for (int i = 0, max = whiteSpaces.length; i < max; i++) { 838 switch(whiteSpaces[i]) { 839 case '\r' : 840 if ((i + 1) < max) { 841 if (whiteSpaces[i + 1] == '\n') { 842 i++; 843 } 844 } 845 count++; 846 break; 847 case '\n' : 848 count++; 849 } 850 } 851 if (count == 0) { 852 hasWhitespace = true; 853 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 854 } else if (hasComment) { 855 if (count == 1) { 856 this.printNewLine(this.scanner.getCurrentTokenStartPosition()); 857 } else { 858 preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition()); 859 } 860 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 861 } else if (hasLineComment) { 862 this.preserveEmptyLines(count, this.scanner.getCurrentTokenStartPosition()); 863 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 864 } else if (count != 0 && this.formatter.preferences.number_of_empty_lines_to_preserve != 0) { 865 addReplaceEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition(), this.getPreserveEmptyLines(count - 1)); 866 } else { 867 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 868 } 869 currentTokenStartPosition = this.scanner.currentPosition; 870 break; 871 case TerminalTokens.TokenNameCOMMENT_LINE : 872 if (count >= 1) { 873 if (count > 1) { 874 preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition()); 875 } else if (count == 1) { 876 printNewLine(this.scanner.getCurrentTokenStartPosition()); 877 } 878 } else if (hasWhitespace) { 879 space(); 880 } 881 hasWhitespace = false; 882 this.printCommentLine(this.scanner.getRawTokenSource()); 883 currentTokenStartPosition = this.scanner.currentPosition; 884 hasLineComment = true; 885 count = 0; 886 break; 887 case TerminalTokens.TokenNameCOMMENT_BLOCK : 888 if (count >= 1) { 889 if (count > 1) { 890 preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition()); 891 } else if (count == 1) { 892 printNewLine(this.scanner.getCurrentTokenStartPosition()); 893 } 894 } else if (hasWhitespace) { 895 space(); 896 } 897 hasWhitespace = false; 898 this.printBlockComment(this.scanner.getRawTokenSource(), false); 899 currentTokenStartPosition = this.scanner.currentPosition; 900 hasLineComment = false; 901 hasComment = true; 902 count = 0; 903 break; 904 case TerminalTokens.TokenNameCOMMENT_JAVADOC : 905 if (count >= 1) { 906 if (count > 1) { 907 preserveEmptyLines(count - 1, this.scanner.getCurrentTokenStartPosition()); 908 } else if (count == 1) { 909 printNewLine(this.scanner.getCurrentTokenStartPosition()); 910 } 911 } else if (hasWhitespace) { 912 space(); 913 } 914 hasWhitespace = false; 915 this.printBlockComment(this.scanner.getRawTokenSource(), true); 916 currentTokenStartPosition = this.scanner.currentPosition; 917 hasLineComment = false; 918 hasComment = true; 919 count = 0; 920 break; 921 default : 922 this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); 924 return; 925 } 926 } 927 } catch (InvalidInputException e) { 928 throw new AbortFormatting(e); 929 } 930 } 931 932 private void printCommentLine(char[] s) { 933 int currentTokenStartPosition = this.scanner.getCurrentTokenStartPosition(); 934 int currentTokenEndPosition = this.scanner.getCurrentTokenEndPosition() + 1; 935 if (CharOperation.indexOf(Scanner.TAG_PREFIX, this.scanner.source, true, currentTokenStartPosition) != -1) { 936 this.nlsTagCounter = 0; 937 } 938 this.scanner.resetTo(currentTokenStartPosition, currentTokenEndPosition - 1); 939 int currentCharacter; 940 int start = currentTokenStartPosition; 941 int nextCharacterStart = currentTokenStartPosition; 942 printIndentationIfNecessary(); 943 if (this.pendingSpace) { 944 this.addInsertEdit(currentTokenStartPosition, " "); } 946 this.needSpace = false; 947 this.pendingSpace = false; 948 int previousStart = currentTokenStartPosition; 949 950 loop: while (nextCharacterStart <= currentTokenEndPosition && (currentCharacter = this.scanner.getNextChar()) != -1) { 951 nextCharacterStart = this.scanner.currentPosition; 952 953 switch(currentCharacter) { 954 case '\r' : 955 start = previousStart; 956 break loop; 957 case '\n' : 958 start = previousStart; 959 break loop; 960 } 961 previousStart = nextCharacterStart; 962 } 963 if (start != currentTokenStartPosition) { 964 addReplaceEdit(start, currentTokenEndPosition - 1, lineSeparator); 965 } 966 line++; 967 column = 1; 968 needSpace = false; 969 this.pendingSpace = false; 970 lastNumberOfNewLines = 1; 971 if (this.currentAlignment != null) { 973 if (this.memberAlignment != null) { 974 if (this.currentAlignment.location.inputOffset > this.memberAlignment.location.inputOffset) { 976 if (this.currentAlignment.couldBreak() && this.currentAlignment.wasSplit) { 977 this.currentAlignment.performFragmentEffect(); 978 } 979 } else { 980 this.indentationLevel = Math.max(this.indentationLevel, this.memberAlignment.breakIndentationLevel); 981 } 982 } else if (this.currentAlignment.couldBreak() && this.currentAlignment.wasSplit) { 983 this.currentAlignment.performFragmentEffect(); 984 } 985 } 986 this.scanner.resetTo(currentTokenEndPosition, this.scannerEndPosition - 1); 987 } 988 public void printEmptyLines(int linesNumber) { 989 this.printEmptyLines(linesNumber, this.scanner.getCurrentTokenEndPosition() + 1); 990 } 991 992 private void printEmptyLines(int linesNumber, int insertPosition) { 993 final String buffer = getEmptyLines(linesNumber); 994 if (EMPTY_STRING == buffer) return; 995 996 addInsertEdit(insertPosition, buffer); 997 } 998 999 void printIndentationIfNecessary() { 1000 StringBuffer buffer = new StringBuffer (); 1001 printIndentationIfNecessary(buffer); 1002 if (buffer.length() > 0) { 1003 addInsertEdit(this.scanner.getCurrentTokenStartPosition(), buffer.toString()); 1004 this.pendingSpace = false; 1005 } 1006 } 1007 1008 private void printIndentationIfNecessary(StringBuffer buffer) { 1009 switch(this.tabChar) { 1010 case DefaultCodeFormatterOptions.TAB : 1011 boolean useTabsForLeadingIndents = this.useTabsOnlyForLeadingIndents; 1012 int numberOfLeadingIndents = this.numberOfIndentations; 1013 int indentationsAsTab = 0; 1014 if (useTabsForLeadingIndents) { 1015 while (this.column <= this.indentationLevel) { 1016 if (indentationsAsTab < numberOfLeadingIndents) { 1017 buffer.append('\t'); 1018 indentationsAsTab++; 1019 this.lastNumberOfNewLines = 0; 1020 int complement = this.tabLength - ((this.column - 1) % this.tabLength); this.column += complement; 1022 this.needSpace = false; 1023 } else { 1024 buffer.append(' '); 1025 this.column++; 1026 this.needSpace = false; 1027 } 1028 } 1029 } else { 1030 while (this.column <= this.indentationLevel) { 1031 buffer.append('\t'); 1032 this.lastNumberOfNewLines = 0; 1033 int complement = this.tabLength - ((this.column - 1) % this.tabLength); this.column += complement; 1035 this.needSpace = false; 1036 } 1037 } 1038 break; 1039 case DefaultCodeFormatterOptions.SPACE : 1040 while (this.column <= this.indentationLevel) { 1041 buffer.append(' '); 1042 this.column++; 1043 this.needSpace = false; 1044 } 1045 break; 1046 case DefaultCodeFormatterOptions.MIXED : 1047 useTabsForLeadingIndents = this.useTabsOnlyForLeadingIndents; 1048 numberOfLeadingIndents = this.numberOfIndentations; 1049 indentationsAsTab = 0; 1050 if (useTabsForLeadingIndents) { 1051 final int columnForLeadingIndents = numberOfLeadingIndents * this.indentationSize; 1052 while (this.column <= this.indentationLevel) { 1053 if (this.column <= columnForLeadingIndents) { 1054 if ((this.column - 1 + this.tabLength) <= this.indentationLevel) { 1055 buffer.append('\t'); 1056 this.column += this.tabLength; 1057 } else if ((this.column - 1 + this.indentationSize) <= this.indentationLevel) { 1058 for (int i = 0, max = this.indentationSize; i < max; i++) { 1060 buffer.append(' '); 1061 this.column++; 1062 } 1063 } else { 1064 buffer.append(' '); 1065 this.column++; 1066 } 1067 } else { 1068 for (int i = this.column, max = this.indentationLevel; i <= max; i++) { 1069 buffer.append(' '); 1070 this.column++; 1071 } 1072 } 1073 this.needSpace = false; 1074 } 1075 } else { 1076 while (this.column <= this.indentationLevel) { 1077 if ((this.column - 1 + this.tabLength) <= this.indentationLevel) { 1078 buffer.append('\t'); 1079 this.column += this.tabLength; 1080 } else if ((this.column - 1 + this.indentationSize) <= this.indentationLevel) { 1081 for (int i = 0, max = this.indentationSize; i < max; i++) { 1083 buffer.append(' '); 1084 this.column++; 1085 } 1086 } else { 1087 buffer.append(' '); 1088 this.column++; 1089 } 1090 this.needSpace = false; 1091 } 1092 } 1093 break; 1094 } 1095 } 1096 1097 1101 public void printModifiers(List modifiers, ASTVisitor visitor) { 1102 try { 1103 int modifiersIndex = 0; 1104 boolean isFirstModifier = true; 1105 int currentTokenStartPosition = this.scanner.currentPosition; 1106 boolean hasComment = false; 1107 while ((this.currentToken = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { 1108 switch(this.currentToken) { 1109 case TerminalTokens.TokenNamepublic : 1110 case TerminalTokens.TokenNameprotected : 1111 case TerminalTokens.TokenNameprivate : 1112 case TerminalTokens.TokenNamestatic : 1113 case TerminalTokens.TokenNameabstract : 1114 case TerminalTokens.TokenNamefinal : 1115 case TerminalTokens.TokenNamenative : 1116 case TerminalTokens.TokenNamesynchronized : 1117 case TerminalTokens.TokenNametransient : 1118 case TerminalTokens.TokenNamevolatile : 1119 case TerminalTokens.TokenNamestrictfp : 1120 this.print(this.scanner.getRawTokenSource(), !isFirstModifier); 1121 isFirstModifier = false; 1122 currentTokenStartPosition = this.scanner.currentPosition; 1123 modifiersIndex++; 1124 break; 1125 case TerminalTokens.TokenNameAT : 1126 if (!isFirstModifier) { 1127 this.space(); 1128 } 1129 this.scanner.resetTo(this.scanner.getCurrentTokenStartPosition(), this.scannerEndPosition - 1); 1130 ((Annotation) modifiers.get(modifiersIndex)).accept(visitor); 1131 if (this.formatter.preferences.insert_new_line_after_annotation) { 1132 this.printNewLine(); 1133 } 1134 isFirstModifier = false; 1135 currentTokenStartPosition = this.scanner.currentPosition; 1136 modifiersIndex++; 1137 break; 1138 case TerminalTokens.TokenNameCOMMENT_BLOCK : 1139 this.printBlockComment(this.scanner.getRawTokenSource(), false); 1140 currentTokenStartPosition = this.scanner.currentPosition; 1141 hasComment = true; 1142 break; 1143 case TerminalTokens.TokenNameCOMMENT_JAVADOC : 1144 this.printBlockComment(this.scanner.getRawTokenSource(), true); 1145 currentTokenStartPosition = this.scanner.currentPosition; 1146 hasComment = true; 1147 break; 1148 case TerminalTokens.TokenNameCOMMENT_LINE : 1149 this.printCommentLine(this.scanner.getRawTokenSource()); 1150 currentTokenStartPosition = this.scanner.currentPosition; 1151 break; 1152 case TerminalTokens.TokenNameWHITESPACE : 1153 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 1154 int count = 0; 1155 char[] whiteSpaces = this.scanner.getCurrentTokenSource(); 1156 for (int i = 0, max = whiteSpaces.length; i < max; i++) { 1157 switch(whiteSpaces[i]) { 1158 case '\r' : 1159 if ((i + 1) < max) { 1160 if (whiteSpaces[i + 1] == '\n') { 1161 i++; 1162 } 1163 } 1164 count++; 1165 break; 1166 case '\n' : 1167 count++; 1168 } 1169 } 1170 if (count >= 1 && hasComment) { 1171 printNewLine(); 1172 } 1173 currentTokenStartPosition = this.scanner.currentPosition; 1174 hasComment = false; 1175 break; 1176 default: 1177 this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); 1179 return; 1180 } 1181 } 1182 } catch (InvalidInputException e) { 1183 throw new AbortFormatting(e); 1184 } 1185 } 1186 1187 public void printNewLine() { 1188 if (this.nlsTagCounter > 0) { 1189 return; 1190 } 1191 if (lastNumberOfNewLines >= 1) { 1192 column = 1; return; 1194 } 1195 addInsertEdit(this.scanner.getCurrentTokenEndPosition() + 1, this.lineSeparator); 1196 line++; 1197 lastNumberOfNewLines = 1; 1198 column = 1; 1199 needSpace = false; 1200 this.pendingSpace = false; 1201 } 1202 1203 public void printNewLine(int insertPosition) { 1204 if (this.nlsTagCounter > 0) { 1205 return; 1206 } 1207 if (lastNumberOfNewLines >= 1) { 1208 column = 1; return; 1210 } 1211 addInsertEdit(insertPosition, this.lineSeparator); 1212 line++; 1213 lastNumberOfNewLines = 1; 1214 column = 1; 1215 needSpace = false; 1216 this.pendingSpace = false; 1217 } 1218 1219 public void printNextToken(int expectedTokenType){ 1220 printNextToken(expectedTokenType, false); 1221 } 1222 1223 public void printNextToken(int expectedTokenType, boolean considerSpaceIfAny){ 1224 printComment(); 1225 try { 1226 this.currentToken = this.scanner.getNextToken(); 1227 char[] currentTokenSource = this.scanner.getRawTokenSource(); 1228 if (expectedTokenType != this.currentToken) { 1229 throw new AbortFormatting("unexpected token type, expecting:"+expectedTokenType+", actual:"+this.currentToken); } 1231 this.print(currentTokenSource, considerSpaceIfAny); 1232 } catch (InvalidInputException e) { 1233 throw new AbortFormatting(e); 1234 } 1235 } 1236 1237 public void printNextToken(int[] expectedTokenTypes) { 1238 printNextToken(expectedTokenTypes, false); 1239 } 1240 1241 public void printNextToken(int[] expectedTokenTypes, boolean considerSpaceIfAny){ 1242 printComment(); 1243 try { 1244 this.currentToken = this.scanner.getNextToken(); 1245 char[] currentTokenSource = this.scanner.getRawTokenSource(); 1246 if (Arrays.binarySearch(expectedTokenTypes, this.currentToken) < 0) { 1247 StringBuffer expectations = new StringBuffer (5); 1248 for (int i = 0; i < expectedTokenTypes.length; i++){ 1249 if (i > 0) { 1250 expectations.append(','); 1251 } 1252 expectations.append(expectedTokenTypes[i]); 1253 } 1254 throw new AbortFormatting("unexpected token type, expecting:["+expectations.toString()+"], actual:"+this.currentToken); } 1256 this.print(currentTokenSource, considerSpaceIfAny); 1257 } catch (InvalidInputException e) { 1258 throw new AbortFormatting(e); 1259 } 1260 } 1261 1262 public void printArrayQualifiedReference(int numberOfTokens, int sourceEnd) { 1263 int currentTokenStartPosition = this.scanner.currentPosition; 1264 int numberOfIdentifiers = 0; 1265 try { 1266 do { 1267 this.printComment(); 1268 switch(this.currentToken = this.scanner.getNextToken()) { 1269 case TerminalTokens.TokenNameEOF : 1270 return; 1271 case TerminalTokens.TokenNameWHITESPACE : 1272 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 1273 currentTokenStartPosition = this.scanner.currentPosition; 1274 break; 1275 case TerminalTokens.TokenNameCOMMENT_BLOCK : 1276 case TerminalTokens.TokenNameCOMMENT_JAVADOC : 1277 this.printBlockComment(this.scanner.getRawTokenSource(), false); 1278 currentTokenStartPosition = this.scanner.currentPosition; 1279 break; 1280 case TerminalTokens.TokenNameCOMMENT_LINE : 1281 this.printCommentLine(this.scanner.getRawTokenSource()); 1282 currentTokenStartPosition = this.scanner.currentPosition; 1283 break; 1284 case TerminalTokens.TokenNameIdentifier : 1285 this.print(this.scanner.getRawTokenSource(), false); 1286 currentTokenStartPosition = this.scanner.currentPosition; 1287 if (++ numberOfIdentifiers == numberOfTokens) { 1288 this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); 1289 return; 1290 } 1291 break; 1292 case TerminalTokens.TokenNameDOT : 1293 this.print(this.scanner.getRawTokenSource(), false); 1294 currentTokenStartPosition = this.scanner.currentPosition; 1295 break; 1296 default: 1297 this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); 1298 return; 1299 } 1300 } while (this.scanner.currentPosition <= sourceEnd); 1301 } catch(InvalidInputException e) { 1302 throw new AbortFormatting(e); 1303 } 1304 } 1305 1343 private void printRule(StringBuffer stringBuffer) { 1344 for (int i = 0; i < this.pageWidth; i++){ 1345 if ((i % this.tabLength) == 0) { 1346 stringBuffer.append('+'); 1347 } else { 1348 stringBuffer.append('-'); 1349 } 1350 } 1351 stringBuffer.append(this.lineSeparator); 1352 1353 for (int i = 0; i < (pageWidth / tabLength); i++) { 1354 stringBuffer.append(i); 1355 stringBuffer.append('\t'); 1356 } 1357 } 1358 1359 public void printTrailingComment() { 1360 try { 1361 int currentTokenStartPosition = this.scanner.currentPosition; 1363 boolean hasWhitespaces = false; 1364 boolean hasComment = false; 1365 boolean hasLineComment = false; 1366 while ((this.currentToken = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { 1367 switch(this.currentToken) { 1368 case TerminalTokens.TokenNameWHITESPACE : 1369 int count = 0; 1370 char[] whiteSpaces = this.scanner.getCurrentTokenSource(); 1371 for (int i = 0, max = whiteSpaces.length; i < max; i++) { 1372 switch(whiteSpaces[i]) { 1373 case '\r' : 1374 if ((i + 1) < max) { 1375 if (whiteSpaces[i + 1] == '\n') { 1376 i++; 1377 } 1378 } 1379 count++; 1380 break; 1381 case '\n' : 1382 count++; 1383 } 1384 } 1385 if (hasLineComment) { 1386 if (count >= 1) { 1387 currentTokenStartPosition = this.scanner.getCurrentTokenStartPosition(); 1388 this.preserveEmptyLines(count, currentTokenStartPosition); 1389 addDeleteEdit(currentTokenStartPosition, this.scanner.getCurrentTokenEndPosition()); 1390 this.scanner.resetTo(this.scanner.currentPosition, this.scannerEndPosition - 1); 1391 return; 1392 } else { 1393 this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); 1394 return; 1395 } 1396 } else if (count >= 1) { 1397 if (hasComment) { 1398 this.printNewLine(this.scanner.getCurrentTokenStartPosition()); 1399 } 1400 this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); 1401 return; 1402 } else { 1403 hasWhitespaces = true; 1404 currentTokenStartPosition = this.scanner.currentPosition; 1405 addDeleteEdit(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition()); 1406 } 1407 break; 1408 case TerminalTokens.TokenNameCOMMENT_LINE : 1409 if (hasWhitespaces) { 1410 space(); 1411 } 1412 this.printCommentLine(this.scanner.getRawTokenSource()); 1413 currentTokenStartPosition = this.scanner.currentPosition; 1414 hasLineComment = true; 1415 break; 1416 case TerminalTokens.TokenNameCOMMENT_BLOCK : 1417 if (hasWhitespaces) { 1418 space(); 1419 } 1420 this.printBlockComment(this.scanner.getRawTokenSource(), false); 1421 currentTokenStartPosition = this.scanner.currentPosition; 1422 hasComment = true; 1423 break; 1424 default : 1425 this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); 1427 return; 1428 } 1429 } 1430 } catch (InvalidInputException e) { 1431 throw new AbortFormatting(e); 1432 } 1433 } 1434 1435 void redoAlignment(AlignmentException e){ 1436 if (e.relativeDepth > 0) { e.relativeDepth--; this.currentAlignment = this.currentAlignment.enclosing; throw e; } 1441 this.resetAt(this.currentAlignment.location); 1443 this.scanner.resetTo(this.currentAlignment.location.inputOffset, this.scanner.eofPosition); 1444 this.currentAlignment.chunkKind = 0; 1446 } 1447 1448 void redoMemberAlignment(AlignmentException e){ 1449 this.resetAt(this.memberAlignment.location); 1451 this.scanner.resetTo(this.memberAlignment.location.inputOffset, this.scanner.eofPosition); 1452 this.memberAlignment.chunkKind = 0; 1454 } 1455 1456 public void reset() { 1457 this.checkLineWrapping = true; 1458 this.line = 0; 1459 this.column = 1; 1460 this.editsIndex = 0; 1461 this.nlsTagCounter = 0; 1462 } 1463 1464 private void resetAt(Location2 location) { 1465 this.line = location.outputLine; 1466 this.column = location.outputColumn; 1467 this.indentationLevel = location.outputIndentationLevel; 1468 this.numberOfIndentations = location.numberOfIndentations; 1469 this.lastNumberOfNewLines = location.lastNumberOfNewLines; 1470 this.needSpace = location.needSpace; 1471 this.pendingSpace = location.pendingSpace; 1472 this.editsIndex = location.editsIndex; 1473 this.nlsTagCounter = location.nlsTagCounter; 1474 if (this.editsIndex > 0) { 1475 this.edits[this.editsIndex - 1] = location.textEdit; 1476 } 1477 } 1478 1479 private void resize() { 1480 System.arraycopy(this.edits, 0, (this.edits = new OptimizedReplaceEdit[this.editsIndex * 2]), 0, this.editsIndex); 1481 } 1482 1483 public void space() { 1484 if (!this.needSpace) return; 1485 this.lastNumberOfNewLines = 0; 1486 this.pendingSpace = true; 1487 this.column++; 1488 this.needSpace = false; 1489 } 1490 1491 public String toString() { 1492 StringBuffer stringBuffer = new StringBuffer (); 1493 stringBuffer 1494 .append("(page width = " + this.pageWidth + ") - (tabChar = "); switch(this.tabChar) { 1496 case DefaultCodeFormatterOptions.TAB : 1497 stringBuffer.append("TAB"); break; 1499 case DefaultCodeFormatterOptions.SPACE : 1500 stringBuffer.append("SPACE"); break; 1502 default : 1503 stringBuffer.append("MIXED"); } 1505 stringBuffer 1506 .append(") - (tabSize = " + this.tabLength + ")") .append(this.lineSeparator) 1508 .append("(line = " + this.line + ") - (column = " + this.column + ") - (identationLevel = " + this.indentationLevel + ")") .append(this.lineSeparator) 1510 .append("(needSpace = " + this.needSpace + ") - (lastNumberOfNewLines = " + this.lastNumberOfNewLines + ") - (checkLineWrapping = " + this.checkLineWrapping + ")") .append(this.lineSeparator) 1512 .append("==================================================================================") .append(this.lineSeparator); 1514 printRule(stringBuffer); 1515 return stringBuffer.toString(); 1516 } 1517 1518 public void unIndent() { 1519 this.indentationLevel -= this.indentationSize; 1520 this.numberOfIndentations--; 1521 } 1522} 1523 | Popular Tags |