1 11 12 package org.eclipse.jface.text.formatter; 13 14 15 import java.util.ArrayList ; 16 import java.util.Collections ; 17 import java.util.HashMap ; 18 import java.util.List ; 19 import java.util.Map ; 20 21 import org.eclipse.core.runtime.Assert; 22 23 import org.eclipse.jface.text.BadLocationException; 24 import org.eclipse.jface.text.BadPositionCategoryException; 25 import org.eclipse.jface.text.DefaultPositionUpdater; 26 import org.eclipse.jface.text.DocumentEvent; 27 import org.eclipse.jface.text.IDocument; 28 import org.eclipse.jface.text.IDocumentExtension3; 29 import org.eclipse.jface.text.IPositionUpdater; 30 import org.eclipse.jface.text.IRegion; 31 import org.eclipse.jface.text.ITypedRegion; 32 import org.eclipse.jface.text.Position; 33 import org.eclipse.jface.text.TextUtilities; 34 import org.eclipse.jface.text.TypedPosition; 35 36 37 66 public class ContentFormatter implements IContentFormatter { 67 68 72 static class PositionReference implements Comparable { 73 74 75 protected Position fPosition; 76 77 protected boolean fRefersToOffset; 78 79 protected String fCategory; 80 81 88 protected PositionReference(Position position, boolean refersToOffset, String category) { 89 fPosition= position; 90 fRefersToOffset= refersToOffset; 91 fCategory= category; 92 } 93 94 99 protected int getOffset() { 100 return fPosition.getOffset(); 101 } 102 103 108 protected void setOffset(int offset) { 109 fPosition.setOffset(offset); 110 } 111 112 117 protected int getLength() { 118 return fPosition.getLength(); 119 } 120 121 126 protected void setLength(int length) { 127 fPosition.setLength(length); 128 } 129 130 136 protected boolean refersToOffset() { 137 return fRefersToOffset; 138 } 139 140 145 protected String getCategory() { 146 return fCategory; 147 } 148 149 154 protected Position getPosition() { 155 return fPosition; 156 } 157 158 163 protected int getCharacterPosition() { 164 if (fRefersToOffset) 165 return getOffset(); 166 return getOffset() + getLength(); 167 } 168 169 172 public int compareTo(Object obj) { 173 174 if (obj instanceof PositionReference) { 175 PositionReference r= (PositionReference) obj; 176 return getCharacterPosition() - r.getCharacterPosition(); 177 } 178 179 throw new ClassCastException (); 180 } 181 } 182 183 189 class NonDeletingPositionUpdater extends DefaultPositionUpdater { 190 191 196 protected NonDeletingPositionUpdater(String category) { 197 super(category); 198 } 199 200 203 protected boolean notDeleted() { 204 return true; 205 } 206 } 207 208 215 class RemoveAffectedPositions implements IPositionUpdater { 216 219 public void update(DocumentEvent event) { 220 removeAffectedPositions(event.getDocument()); 221 } 222 } 223 224 231 class UpdateAffectedPositions implements IPositionUpdater { 232 233 234 private int[] fPositions; 235 236 private int fOffset; 237 238 244 public UpdateAffectedPositions(int[] positions, int offset) { 245 fPositions= positions; 246 fOffset= offset; 247 } 248 249 252 public void update(DocumentEvent event) { 253 updateAffectedPositions(event.getDocument(), fPositions, fOffset); 254 } 255 } 256 257 258 259 private final static String PARTITIONING= "__formatter_partitioning"; 261 262 private Map fStrategies; 263 264 private boolean fIsPartitionAware= true; 265 266 267 private String [] fPartitionManagingCategories; 268 269 private List fOverlappingPositionReferences; 270 271 private IPositionUpdater fPartitioningUpdater; 272 276 private String fPartitioning; 277 281 private IDocument fDocument; 282 286 private String [] fExternalPartitonManagingCategories; 287 291 private boolean fNeedsComputation= true; 292 293 294 299 public ContentFormatter() { 300 fPartitioning= IDocumentExtension3.DEFAULT_PARTITIONING; 301 } 302 303 312 public void setFormattingStrategy(IFormattingStrategy strategy, String contentType) { 313 314 Assert.isNotNull(contentType); 315 316 if (fStrategies == null) 317 fStrategies= new HashMap (); 318 319 if (strategy == null) 320 fStrategies.remove(contentType); 321 else 322 fStrategies.put(contentType, strategy); 323 } 324 325 334 public void setPartitionManagingPositionCategories(String [] categories) { 335 fExternalPartitonManagingCategories= TextUtilities.copy(categories); 336 } 337 338 344 public void setDocumentPartitioning(String partitioning) { 345 fPartitioning= partitioning; 346 } 347 348 353 public void enablePartitionAwareFormatting(boolean enable) { 354 fIsPartitionAware= enable; 355 } 356 357 360 public IFormattingStrategy getFormattingStrategy(String contentType) { 361 362 Assert.isNotNull(contentType); 363 364 if (fStrategies == null) 365 return null; 366 367 return (IFormattingStrategy) fStrategies.get(contentType); 368 } 369 370 373 public void format(IDocument document, IRegion region) { 374 fNeedsComputation= true; 375 fDocument= document; 376 try { 377 378 if (fIsPartitionAware) 379 formatPartitions(region); 380 else 381 formatRegion(region); 382 383 } finally { 384 fNeedsComputation= true; 385 fDocument= null; 386 } 387 } 388 389 397 private void formatPartitions(IRegion region) { 398 399 addPartitioningUpdater(); 400 401 try { 402 403 TypedPosition[] ranges= getPartitioning(region); 404 if (ranges != null) { 405 start(ranges, getIndentation(region.getOffset())); 406 format(ranges); 407 stop(ranges); 408 } 409 410 } catch (BadLocationException x) { 411 } 412 413 removePartitioningUpdater(); 414 } 415 416 424 private void formatRegion(IRegion region) { 425 426 IFormattingStrategy strategy= getFormattingStrategy(IDocument.DEFAULT_CONTENT_TYPE); 427 if (strategy != null) { 428 strategy.formatterStarts(getIndentation(region.getOffset())); 429 format(strategy, new TypedPosition(region.getOffset(), region.getLength(), IDocument.DEFAULT_CONTENT_TYPE)); 430 strategy.formatterStops(); 431 } 432 } 433 434 448 private TypedPosition[] getPartitioning(IRegion region) throws BadLocationException { 449 450 ITypedRegion[] regions= TextUtilities.computePartitioning(fDocument, fPartitioning, region.getOffset(), region.getLength(), false); 451 TypedPosition[] positions= new TypedPosition[regions.length]; 452 453 for (int i= 0; i < regions.length; i++) { 454 positions[i]= new TypedPosition(regions[i]); 455 try { 456 fDocument.addPosition(PARTITIONING, positions[i]); 457 } catch (BadPositionCategoryException x) { 458 } 460 } 461 462 return positions; 463 } 464 465 472 private void start(TypedPosition[] regions, String indentation) { 473 for (int i= 0; i < regions.length; i++) { 474 IFormattingStrategy s= getFormattingStrategy(regions[i].getType()); 475 if (s != null) 476 s.formatterStarts(indentation); 477 } 478 } 479 480 487 private void format(TypedPosition[] ranges) { 488 for (int i= 0; i < ranges.length; i++) { 489 IFormattingStrategy s= getFormattingStrategy(ranges[i].getType()); 490 if (s != null) { 491 format(s, ranges[i]); 492 } 493 } 494 } 495 496 510 private void format(IFormattingStrategy strategy, TypedPosition region) { 511 try { 512 513 final int offset= region.getOffset(); 514 int length= region.getLength(); 515 516 String content= fDocument.get(offset, length); 517 final int[] positions= getAffectedPositions(offset, length); 518 String formatted= strategy.format(content, isLineStart(offset), getIndentation(offset), positions); 519 520 if (formatted != null && !formatted.equals(content)) { 521 522 IPositionUpdater first= new RemoveAffectedPositions(); 523 fDocument.insertPositionUpdater(first, 0); 524 IPositionUpdater last= new UpdateAffectedPositions(positions, offset); 525 fDocument.addPositionUpdater(last); 526 527 fDocument.replace(offset, length, formatted); 528 529 fDocument.removePositionUpdater(first); 530 fDocument.removePositionUpdater(last); 531 } 532 533 } catch (BadLocationException x) { 534 } 536 } 537 538 544 private void stop(TypedPosition[] regions) { 545 for (int i= 0; i < regions.length; i++) { 546 IFormattingStrategy s= getFormattingStrategy(regions[i].getType()); 547 if (s != null) 548 s.formatterStops(); 549 } 550 } 551 552 556 private void addPartitioningUpdater() { 557 fPartitioningUpdater= new NonDeletingPositionUpdater(PARTITIONING); 558 fDocument.addPositionCategory(PARTITIONING); 559 fDocument.addPositionUpdater(fPartitioningUpdater); 560 } 561 562 567 private void removePartitioningUpdater() { 568 569 try { 570 571 fDocument.removePositionUpdater(fPartitioningUpdater); 572 fDocument.removePositionCategory(PARTITIONING); 573 fPartitioningUpdater= null; 574 575 } catch (BadPositionCategoryException x) { 576 } 578 } 579 580 586 private String [] getPartitionManagingCategories() { 587 if (fNeedsComputation) { 588 fNeedsComputation= false; 589 fPartitionManagingCategories= TextUtilities.computePartitionManagingCategories(fDocument); 590 if (fPartitionManagingCategories == null) 591 fPartitionManagingCategories= fExternalPartitonManagingCategories; 592 } 593 return fPartitionManagingCategories; 594 } 595 596 603 private boolean ignoreCategory(String category) { 604 605 if (PARTITIONING.equals(category)) 606 return true; 607 608 String [] categories= getPartitionManagingCategories(); 609 if (categories != null) { 610 for (int i= 0; i < categories.length; i++) { 611 if (categories[i].equals(category)) 612 return true; 613 } 614 } 615 616 return false; 617 } 618 619 627 private void determinePositionsToUpdate(int offset, int length) { 628 629 String [] categories= fDocument.getPositionCategories(); 630 if (categories != null) { 631 for (int i= 0; i < categories.length; i++) { 632 633 if (ignoreCategory(categories[i])) 634 continue; 635 636 try { 637 638 Position[] positions= fDocument.getPositions(categories[i]); 639 640 for (int j= 0; j < positions.length; j++) { 641 642 Position p= positions[j]; 643 if (p.overlapsWith(offset, length)) { 644 645 if (offset < p.getOffset()) 646 fOverlappingPositionReferences.add(new PositionReference(p, true, categories[i])); 647 648 if (p.getOffset() + p.getLength() < offset + length) 649 fOverlappingPositionReferences.add(new PositionReference(p, false, categories[i])); 650 } 651 } 652 653 } catch (BadPositionCategoryException x) { 654 } 656 } 657 } 658 } 659 660 669 private int[] getAffectedPositions(int offset, int length) { 670 671 fOverlappingPositionReferences= new ArrayList (); 672 673 determinePositionsToUpdate(offset, length); 674 675 Collections.sort(fOverlappingPositionReferences); 676 677 int[] positions= new int[fOverlappingPositionReferences.size()]; 678 for (int i= 0; i < positions.length; i++) { 679 PositionReference r= (PositionReference) fOverlappingPositionReferences.get(i); 680 positions[i]= r.getCharacterPosition() - offset; 681 } 682 683 return positions; 684 } 685 686 692 private void removeAffectedPositions(IDocument document) { 693 int size= fOverlappingPositionReferences.size(); 694 for (int i= 0; i < size; i++) { 695 PositionReference r= (PositionReference) fOverlappingPositionReferences.get(i); 696 try { 697 document.removePosition(r.getCategory(), r.getPosition()); 698 } catch (BadPositionCategoryException x) { 699 } 701 } 702 } 703 704 712 protected void updateAffectedPositions(IDocument document, int[] positions, int offset) { 713 714 if (document != fDocument) 715 return; 716 717 if (positions.length == 0) 718 return; 719 720 for (int i= 0; i < positions.length; i++) { 721 722 PositionReference r= (PositionReference) fOverlappingPositionReferences.get(i); 723 724 if (r.refersToOffset()) 725 r.setOffset(offset + positions[i]); 726 else 727 r.setLength((offset + positions[i]) - r.getOffset()); 728 729 Position p= r.getPosition(); 730 String category= r.getCategory(); 731 if (!document.containsPosition(category, p.offset, p.length)) { 732 try { 733 if (positionAboutToBeAdded(document, category, p)) 734 document.addPosition(r.getCategory(), p); 735 } catch (BadPositionCategoryException x) { 736 } catch (BadLocationException x) { 738 } 740 } 741 742 } 743 744 fOverlappingPositionReferences= null; 745 } 746 747 756 protected boolean positionAboutToBeAdded(IDocument document, String category, Position position) { 757 return true; 758 } 759 760 767 private String getIndentation(int offset) { 768 769 try { 770 int start= fDocument.getLineOfOffset(offset); 771 start= fDocument.getLineOffset(start); 772 773 int end= start; 774 char c= fDocument.getChar(end); 775 while ('\t' == c || ' ' == c) 776 c= fDocument.getChar(++end); 777 778 return fDocument.get(start, end - start); 779 } catch (BadLocationException x) { 780 } 781 782 return ""; } 784 785 793 private boolean isLineStart(int offset) throws BadLocationException { 794 int start= fDocument.getLineOfOffset(offset); 795 start= fDocument.getLineOffset(start); 796 return (start == offset); 797 } 798 } 799 | Popular Tags |