1 11 12 package org.eclipse.jdt.internal.formatter.comment; 13 14 import java.util.Iterator ; 15 import java.util.LinkedList ; 16 17 import org.eclipse.core.runtime.Assert; 18 19 import org.eclipse.text.edits.MalformedTreeException; 20 import org.eclipse.text.edits.TextEdit; 21 22 import org.eclipse.jface.text.BadLocationException; 23 import org.eclipse.jface.text.DefaultLineTracker; 24 import org.eclipse.jface.text.IDocument; 25 import org.eclipse.jface.text.ILineTracker; 26 import org.eclipse.jface.text.IRegion; 27 import org.eclipse.jface.text.Position; 28 29 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; 30 import org.eclipse.jdt.internal.formatter.CodeFormatterVisitor; 31 import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions; 32 import org.eclipse.jdt.internal.formatter.Scribe; 33 34 39 public class CommentRegion extends Position implements IHtmlTagDelimiters, IBorderAttributes, ICommentAttributes { 40 41 42 protected static final String COMMENT_RANGE_DELIMITER= " "; 44 45 private static final int COMMENT_PREFIX_LENGTH= 3; 46 47 48 private int fBorders= 0; 49 50 51 protected boolean fClear; 52 53 54 private final String fDelimiter; 55 56 57 private final IDocument fDocument; 58 59 60 private final LinkedList fLines= new LinkedList (); 61 62 63 protected final DefaultCodeFormatterOptions preferences; 64 65 66 private final LinkedList fRanges= new LinkedList (); 67 68 69 private final boolean fSingleLine; 70 71 72 private int fTabSize; 73 74 75 protected Scribe scribe; 76 77 84 public CommentRegion(final IDocument document, final Position position, final CodeFormatterVisitor formatter) { 85 super(position.getOffset(), position.getLength()); 86 87 this.preferences = formatter.preferences; 88 fDelimiter = this.preferences.line_separator; 89 fDocument= document; 90 91 fTabSize= DefaultCodeFormatterOptions.SPACE == this.preferences.tab_char ? this.preferences.indentation_size : this.preferences.tab_size; 92 93 this.scribe = formatter.scribe; 94 95 final ILineTracker tracker= new DefaultLineTracker(); 96 97 IRegion range= null; 98 CommentLine line= null; 99 100 tracker.set(getText(0, getLength())); 101 final int lines= tracker.getNumberOfLines(); 102 103 fSingleLine= lines == 1; 104 105 try { 106 107 for (int index= 0; index < lines; index++) { 108 109 range= tracker.getLineInformation(index); 110 line= createLine(); 111 line.append(new CommentRange(range.getOffset(), range.getLength())); 112 113 fLines.add(line); 114 } 115 116 } catch (BadLocationException exception) { 117 } 119 } 120 121 126 protected final void append(final CommentRange range) { 127 fRanges.addLast(range); 128 } 129 130 145 protected boolean canAppend(final CommentLine line, final CommentRange previous, final CommentRange next, final int index, final int width) { 146 return index == 0 || index + next.getLength() <= width; 147 } 148 149 158 protected boolean canFormat(final CommentRange previous, final CommentRange next) { 159 return previous != null; 160 } 161 162 169 public final TextEdit format(int indentationLevel, boolean returnEdit) { 170 final String probe= getText(0, CommentLine.NON_FORMAT_START_PREFIX.length()); 171 if (!probe.startsWith(CommentLine.NON_FORMAT_START_PREFIX)) { 172 173 int margin= this.preferences.comment_line_length; 174 String indentation= computeIndentation(indentationLevel); 175 margin= Math.max(COMMENT_PREFIX_LENGTH + 1, margin - stringToLength(indentation) - COMMENT_PREFIX_LENGTH); 176 177 tokenizeRegion(); 178 markRegion(); 179 wrapRegion(margin); 180 formatRegion(indentation, margin); 181 182 } 183 if (returnEdit) { 184 return this.scribe.getRootEdit(); 185 } 186 return null; 187 } 188 189 196 protected void formatRegion(final String indentation, final int width) { 197 198 final int last= fLines.size() - 1; 199 if (last >= 0) { 200 201 CommentLine lastLine= (CommentLine)fLines.get(last); 202 CommentRange lastRange= lastLine.getLast(); 203 lastLine.formatLowerBorder(lastRange, indentation, width); 204 205 CommentLine previous; 206 CommentLine next= null; 207 CommentRange range= null; 208 for (int line= last; line >= 0; line--) { 209 210 previous= next; 211 next= (CommentLine)fLines.get(line); 212 213 range= next.formatLine(previous, range, indentation, line); 214 } 215 next.formatUpperBorder(range, indentation, width); 216 } 217 } 218 219 224 protected final String getDelimiter() { 225 return fDelimiter; 226 } 227 228 238 protected String getDelimiter(final CommentLine predecessor, final CommentLine successor, final CommentRange previous, final CommentRange next, final String indentation) { 239 return fDelimiter + indentation + successor.getContentPrefix(); 240 } 241 242 250 protected String getDelimiter(final CommentRange previous, final CommentRange next) { 251 return COMMENT_RANGE_DELIMITER; 252 } 253 254 259 protected final IDocument getDocument() { 260 return fDocument; 261 } 262 263 268 protected final LinkedList getRanges() { 269 return fRanges; 270 } 271 272 277 protected final int getSize() { 278 return fLines.size(); 279 } 280 281 289 protected final String getText(final int position, final int count) { 290 291 String content= ""; try { 293 content= fDocument.get(getOffset() + position, count); 294 } catch (BadLocationException exception) { 295 } 297 return content; 298 } 299 300 308 protected final boolean hasBorder(final int border) { 309 return (fBorders & border) == border; 310 } 311 312 319 protected final boolean isAlphaNumeric(final CommentRange range) { 320 321 final String token= getText(range.getOffset(), range.getLength()); 322 323 for (int index= 0; index < token.length(); index++) { 324 if (!ScannerHelper.isLetterOrDigit(token.charAt(index))) 325 return false; 326 } 327 return true; 328 } 329 330 337 protected final boolean isNonAlphaNumeric(final CommentRange range) { 338 339 final String token= getText(range.getOffset(), range.getLength()); 340 341 for (int index= 0; index < token.length(); index++) { 342 if (ScannerHelper.isLetterOrDigit(token.charAt(index))) 343 return false; 344 } 345 return true; 346 } 347 348 354 protected final boolean isClearLines() { 355 return fClear; 356 } 357 358 364 protected final boolean isSingleLine() { 365 return fSingleLine; 366 } 367 368 376 protected final void logEdit(final String change, final int position, final int count) { 377 try { 378 final int base= getOffset() + position; 379 final String content= fDocument.get(base, count); 380 381 if (!change.equals(content)) { 382 if (count > 0) { 383 this.scribe.addReplaceEdit(base, base + count - 1, change); 384 } else { 385 this.scribe.addInsertEdit(base, change); 386 } 387 } 388 } catch (BadLocationException exception) { 389 CommentFormatterUtil.log(exception); 391 } catch (MalformedTreeException exception) { 392 CommentFormatterUtil.log(exception); 394 } 395 } 396 397 400 protected void markRegion() { 401 } 403 404 410 protected final void setBorder(final int border) { 411 fBorders |= border; 412 } 413 414 421 private String computeIndentation(int indentationLevel) { 422 if (DefaultCodeFormatterOptions.TAB == this.preferences.tab_char) 423 return replicate("\t", indentationLevel); 425 if (DefaultCodeFormatterOptions.SPACE == this.preferences.tab_char) 426 return replicate(" ", indentationLevel * this.preferences.tab_size); 428 if (DefaultCodeFormatterOptions.MIXED == this.preferences.tab_char) { 429 int tabSize= this.preferences.tab_size; 430 int indentSize= this.preferences.indentation_size; 431 int spaceEquivalents= indentationLevel * indentSize; 432 return replicate("\t", spaceEquivalents / tabSize) + replicate(" ", spaceEquivalents % tabSize); } 434 435 Assert.isTrue(false); 436 return null; 437 } 438 439 447 private String replicate(String string, int n) { 448 StringBuffer buffer= new StringBuffer (n*string.length()); 449 for (int i= 0; i < n; i++) 450 buffer.append(string); 451 return buffer.toString(); 452 } 453 454 460 protected final String stringToIndent(final String reference) { 461 return replicate(" ", stringToLength(reference)); } 463 464 470 protected final int stringToLength(final String reference) { 471 return expandTabs(reference).length(); 472 } 473 474 481 private String expandTabs(String string) { 482 StringBuffer expanded= new StringBuffer (); 483 for (int i= 0, n= string.length(), chars= 0; i < n; i++) { 484 char ch= string.charAt(i); 485 if (ch == '\t') { 486 for (; chars < fTabSize; chars++) 487 expanded.append(' '); 488 chars= 0; 489 } else { 490 expanded.append(ch); 491 chars++; 492 if (chars >= fTabSize) 493 chars= 0; 494 } 495 496 } 497 return expanded.toString(); 498 } 499 500 503 protected void tokenizeRegion() { 504 505 int index= 0; 506 CommentLine line= null; 507 508 for (final Iterator iterator= fLines.iterator(); iterator.hasNext(); index++) { 509 510 line= (CommentLine)iterator.next(); 511 512 line.scanLine(index); 513 line.tokenizeLine(index); 514 } 515 } 516 517 523 protected void wrapRegion(final int width) { 524 525 fLines.clear(); 526 527 int index= 0; 528 boolean adapted= false; 529 530 CommentLine successor= null; 531 CommentLine predecessor= null; 532 533 CommentRange previous= null; 534 CommentRange next= null; 535 536 while (!fRanges.isEmpty()) { 537 538 index= 0; 539 adapted= false; 540 541 predecessor= successor; 542 successor= createLine(); 543 fLines.add(successor); 544 545 while (!fRanges.isEmpty()) { 546 next= (CommentRange)fRanges.getFirst(); 547 548 if (canAppend(successor, previous, next, index, width)) { 549 550 if (!adapted && predecessor != null) { 551 552 successor.adapt(predecessor); 553 adapted= true; 554 } 555 556 fRanges.removeFirst(); 557 successor.append(next); 558 559 index += (next.getLength() + 1); 560 previous= next; 561 } else 562 break; 563 } 564 } 565 } 566 567 573 protected CommentLine createLine() { 574 return new SingleCommentLine(this); 575 } 576 } 577 | Popular Tags |