1 11 package org.eclipse.text.edits; 12 13 import java.util.ArrayList ; 14 import java.util.Collections ; 15 import java.util.Comparator ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 19 import org.eclipse.core.runtime.Assert; 20 21 import org.eclipse.jface.text.BadLocationException; 22 import org.eclipse.jface.text.IDocument; 23 import org.eclipse.jface.text.IRegion; 24 import org.eclipse.jface.text.Region; 25 26 74 public abstract class TextEdit { 75 76 80 public static final int NONE= 0; 81 82 88 public static final int CREATE_UNDO= 1 << 0; 89 90 97 public static final int UPDATE_REGIONS= 1 << 1; 98 99 private static class InsertionComparator implements Comparator { 100 public int compare(Object o1, Object o2) throws MalformedTreeException { 101 TextEdit edit1= (TextEdit)o1; 102 TextEdit edit2= (TextEdit)o2; 103 104 int offset1= edit1.getOffset(); 105 int length1= edit1.getLength(); 106 107 int offset2= edit2.getOffset(); 108 int length2= edit2.getLength(); 109 110 if (offset1 == offset2 && length1 == 0 && length2 == 0) { 111 return 0; 112 } 113 if (offset1 + length1 <= offset2) { 114 return -1; 115 } 116 if (offset2 + length2 <= offset1) { 117 return 1; 118 } 119 throw new MalformedTreeException( 120 null, edit1, 121 TextEditMessages.getString("TextEdit.overlapping")); } 123 } 124 125 private static final TextEdit[] EMPTY_ARRAY= new TextEdit[0]; 126 private static final InsertionComparator INSERTION_COMPARATOR= new InsertionComparator(); 127 128 private static final int DELETED_VALUE= -1; 129 130 private int fOffset; 131 private int fLength; 132 133 private TextEdit fParent; 134 private List fChildren; 135 136 int fDelta; 137 138 145 protected TextEdit(int offset, int length) { 146 Assert.isTrue(offset >= 0 && length >= 0); 147 fOffset= offset; 148 fLength= length; 149 fDelta= 0; 150 } 151 152 157 protected TextEdit(TextEdit source) { 158 fOffset= source.fOffset; 159 fLength= source.fLength; 160 fDelta= 0; 161 } 162 163 165 177 public final IRegion getRegion() { 178 return new Region(getOffset(), getLength()); 179 } 180 181 188 public int getOffset() { 189 return fOffset; 190 } 191 192 198 public int getLength() { 199 return fLength; 200 } 201 202 213 public final int getInclusiveEnd() { 214 return getOffset() + getLength() - 1; 215 } 216 217 228 public final int getExclusiveEnd() { 229 return getOffset() + getLength(); 230 } 231 232 238 public final boolean isDeleted() { 239 return fOffset == DELETED_VALUE && fLength == DELETED_VALUE; 240 } 241 242 249 public final void moveTree(int delta) { 250 Assert.isTrue(fParent == null); 251 Assert.isTrue(getOffset() + delta >= 0); 252 internalMoveTree(delta); 253 } 254 255 264 public boolean covers(TextEdit other) { 265 if (getLength() == 0 && !canZeroLengthCover()) 266 return false; 267 268 if (!other.isDefined()) 269 return true; 270 271 int thisOffset= getOffset(); 272 int otherOffset= other.getOffset(); 273 return thisOffset <= otherOffset && otherOffset + other.getLength() <= thisOffset + getLength(); 274 } 275 276 282 protected boolean canZeroLengthCover() { 283 return false; 284 } 285 286 293 boolean isDefined() { 294 return true; 295 } 296 297 299 305 public final TextEdit getParent() { 306 return fParent; 307 } 308 309 315 public final TextEdit getRoot() { 316 TextEdit result= this; 317 while (result.fParent != null) { 318 result= result.fParent; 319 } 320 return result; 321 } 322 323 332 public final void addChild(TextEdit child) throws MalformedTreeException { 333 internalAdd(child); 334 } 335 336 345 public final void addChildren(TextEdit[] edits) throws MalformedTreeException { 346 for (int i= 0; i < edits.length; i++) { 347 internalAdd(edits[i]); 348 } 349 } 350 351 362 public final TextEdit removeChild(int index) { 363 if (fChildren == null) 364 throw new IndexOutOfBoundsException ("Index: " + index + " Size: 0"); TextEdit result= (TextEdit)fChildren.remove(index); 366 result.internalSetParent(null); 367 if (fChildren.isEmpty()) 368 fChildren= null; 369 return result; 370 } 371 372 380 public final boolean removeChild(TextEdit child) { 381 Assert.isNotNull(child); 382 if (fChildren == null) 383 return false; 384 boolean result= fChildren.remove(child); 385 if (result) { 386 child.internalSetParent(null); 387 if (fChildren.isEmpty()) 388 fChildren= null; 389 } 390 return result; 391 } 392 393 399 public final TextEdit[] removeChildren() { 400 if (fChildren == null) 401 return EMPTY_ARRAY; 402 int size= fChildren.size(); 403 TextEdit[] result= new TextEdit[size]; 404 for (int i= 0; i < size; i++) { 405 result[i]= (TextEdit)fChildren.get(i); 406 result[i].internalSetParent(null); 407 } 408 fChildren= null; 409 return result; 410 } 411 412 419 public final boolean hasChildren() { 420 return fChildren != null && ! fChildren.isEmpty(); 421 } 422 423 429 public final TextEdit[] getChildren() { 430 if (fChildren == null) 431 return EMPTY_ARRAY; 432 return (TextEdit[])fChildren.toArray(new TextEdit[fChildren.size()]); 433 } 434 435 440 public final int getChildrenSize() { 441 if (fChildren == null) 442 return 0; 443 return fChildren.size(); 444 } 445 446 456 public static IRegion getCoverage(TextEdit[] edits) { 457 Assert.isTrue(edits != null && edits.length > 0); 458 459 int offset= Integer.MAX_VALUE; 460 int end= Integer.MIN_VALUE; 461 int deleted= 0; 462 for (int i= 0; i < edits.length; i++) { 463 TextEdit edit= edits[i]; 464 if (edit.isDeleted()) { 465 deleted++; 466 } else { 467 offset= Math.min(offset, edit.getOffset()); 468 end= Math.max(end, edit.getExclusiveEnd()); 469 } 470 } 471 if (edits.length == deleted) 472 return null; 473 474 return new Region(offset, end - offset); 475 } 476 477 481 void aboutToBeAdded(TextEdit parent) { 482 } 483 484 486 496 public final boolean equals(Object obj) { 497 return this == obj; } 499 500 509 public final int hashCode() { 510 return super.hashCode(); 511 } 512 513 516 public String toString() { 517 StringBuffer buffer= new StringBuffer (); 518 toStringWithChildren(buffer, 0); 519 return buffer.toString(); 520 } 521 522 530 void internalToString(StringBuffer buffer, int indent) { 531 for (int i= indent; i > 0; i--) { 532 buffer.append(" "); } 534 buffer.append("{"); String name= getClass().getName(); 536 int index= name.lastIndexOf('.'); 537 if (index != -1) { 538 buffer.append(name.substring(index + 1)); 539 } else { 540 buffer.append(name); 541 } 542 buffer.append("} "); if (isDeleted()) { 544 buffer.append("[deleted]"); } else { 546 buffer.append("["); buffer.append(getOffset()); 548 buffer.append(","); buffer.append(getLength()); 550 buffer.append("]"); } 552 } 553 554 562 private void toStringWithChildren(StringBuffer buffer, int indent) { 563 internalToString(buffer, indent); 564 if (fChildren != null) { 565 for (Iterator iterator= fChildren.iterator(); iterator.hasNext();) { 566 TextEdit child= (TextEdit) iterator.next(); 567 buffer.append('\n'); 568 child.toStringWithChildren(buffer, indent + 1); 569 } 570 } 571 } 572 573 575 582 public final TextEdit copy() { 583 TextEditCopier copier= new TextEditCopier(this); 584 return copier.perform(); 585 } 586 587 607 protected abstract TextEdit doCopy(); 608 609 619 protected void postProcessCopy(TextEditCopier copier) { 620 } 621 622 624 630 public final void accept(TextEditVisitor visitor) { 631 Assert.isNotNull(visitor); 632 visitor.preVisit(this); 634 accept0(visitor); 636 visitor.postVisit(this); 638 } 639 640 659 protected abstract void accept0(TextEditVisitor visitor); 660 661 662 672 protected final void acceptChildren(TextEditVisitor visitor) { 673 if (fChildren == null) 674 return; 675 Iterator iterator= fChildren.iterator(); 676 while (iterator.hasNext()) { 677 TextEdit curr= (TextEdit) iterator.next(); 678 curr.accept(visitor); 679 } 680 } 681 682 684 705 public final UndoEdit apply(IDocument document, int style) throws MalformedTreeException, BadLocationException { 706 try { 707 TextEditProcessor processor= new TextEditProcessor(document, this, style); 708 return processor.performEdits(); 709 } finally { 710 fParent= null; 712 } 713 } 714 715 731 public final UndoEdit apply(IDocument document) throws MalformedTreeException, BadLocationException { 732 return apply(document, CREATE_UNDO | UPDATE_REGIONS); 733 } 734 735 UndoEdit dispatchPerformEdits(TextEditProcessor processor) throws BadLocationException { 736 return processor.executeDo(); 737 } 738 739 void dispatchCheckIntegrity(TextEditProcessor processor) throws MalformedTreeException { 740 processor.checkIntegrityDo(); 741 } 742 743 745 void internalSetParent(TextEdit parent) { 746 if (parent != null) 747 Assert.isTrue(fParent == null); 748 fParent= parent; 749 } 750 751 void internalSetOffset(int offset) { 752 Assert.isTrue(offset >= 0); 753 fOffset= offset; 754 } 755 756 void internalSetLength(int length) { 757 Assert.isTrue(length >= 0); 758 fLength= length; 759 } 760 761 List internalGetChildren() { 762 return fChildren; 763 } 764 765 void internalSetChildren(List children) { 766 fChildren= children; 767 } 768 769 void internalAdd(TextEdit child) throws MalformedTreeException { 770 child.aboutToBeAdded(this); 771 if (child.isDeleted()) 772 throw new MalformedTreeException(this, child, TextEditMessages.getString("TextEdit.deleted_edit")); if (!covers(child)) 774 throw new MalformedTreeException(this, child, TextEditMessages.getString("TextEdit.range_outside")); if (fChildren == null) { 776 fChildren= new ArrayList (2); 777 } 778 int index= computeInsertionIndex(child); 779 fChildren.add(index, child); 780 child.internalSetParent(this); 781 } 782 783 private int computeInsertionIndex(TextEdit edit) throws MalformedTreeException { 784 int size= fChildren.size(); 785 if (size == 0) 786 return 0; 787 int lastIndex= size - 1; 788 TextEdit last= (TextEdit)fChildren.get(lastIndex); 789 if (last.getExclusiveEnd() <= edit.getOffset()) 790 return size; 791 try { 792 793 int index= Collections.binarySearch(fChildren, edit, INSERTION_COMPARATOR); 794 795 if (index < 0) 796 return -index - 1; 798 799 while (index < lastIndex && INSERTION_COMPARATOR.compare(fChildren.get(index), fChildren.get(index + 1)) == 0) 802 index++; 803 804 return index + 1; 805 806 } catch(MalformedTreeException e) { 807 e.setParent(this); 808 throw e; 809 } 810 } 811 812 814 820 void adjustOffset(int delta) { 821 if (isDeleted()) 822 return; 823 fOffset+= delta; 824 Assert.isTrue(fOffset >= 0); 825 } 826 827 833 void adjustLength(int delta) { 834 if (isDeleted()) 835 return; 836 fLength+= delta; 837 Assert.isTrue(fLength >= 0); 838 } 839 840 844 void markAsDeleted() { 845 fOffset= DELETED_VALUE; 846 fLength= DELETED_VALUE; 847 } 848 849 851 861 int traverseConsistencyCheck(TextEditProcessor processor, IDocument document, List sourceEdits) { 862 int result= 0; 863 if (fChildren != null) { 864 for (int i= fChildren.size() - 1; i >= 0; i--) { 865 TextEdit child= (TextEdit)fChildren.get(i); 866 result= Math.max(result, child.traverseConsistencyCheck(processor, document, sourceEdits)); 867 } 868 } 869 if (processor.considerEdit(this)) { 870 performConsistencyCheck(processor, document); 871 } 872 return result; 873 } 874 875 void performConsistencyCheck(TextEditProcessor processor, IDocument document) { 876 } 877 878 void traverseSourceComputation(TextEditProcessor processor, IDocument document) { 879 } 880 881 void performSourceComputation(TextEditProcessor processor, IDocument document) { 882 } 883 884 int traverseDocumentUpdating(TextEditProcessor processor, IDocument document) throws BadLocationException { 885 int delta= 0; 886 if (fChildren != null) { 887 for (int i= fChildren.size() - 1; i >= 0; i--) { 888 TextEdit child= (TextEdit)fChildren.get(i); 889 delta+= child.traverseDocumentUpdating(processor, document); 890 childDocumentUpdated(); 891 } 892 } 893 if (processor.considerEdit(this)) { 894 if (delta != 0) 895 adjustLength(delta); 896 int r= performDocumentUpdating(document); 897 if (r != 0) 898 adjustLength(r); 899 delta+= r; 900 } 901 return delta; 902 } 903 904 914 protected void childDocumentUpdated() { 915 } 916 917 abstract int performDocumentUpdating(IDocument document) throws BadLocationException; 918 919 int traverseRegionUpdating(TextEditProcessor processor, IDocument document, int accumulatedDelta, boolean delete) { 920 performRegionUpdating(accumulatedDelta, delete); 921 if (fChildren != null) { 922 boolean childDelete= delete || deleteChildren(); 923 for (Iterator iter= fChildren.iterator(); iter.hasNext();) { 924 TextEdit child= (TextEdit)iter.next(); 925 accumulatedDelta= child.traverseRegionUpdating(processor, document, accumulatedDelta, childDelete); 926 childRegionUpdated(); 927 } 928 } 929 return accumulatedDelta + fDelta; 930 } 931 932 944 protected void childRegionUpdated() { 945 } 946 947 void performRegionUpdating(int accumulatedDelta, boolean delete) { 948 if (delete) 949 markAsDeleted(); 950 else 951 adjustOffset(accumulatedDelta); 952 } 953 954 abstract boolean deleteChildren(); 955 956 void internalMoveTree(int delta) { 957 adjustOffset(delta); 958 if (fChildren != null) { 959 for (Iterator iter= fChildren.iterator(); iter.hasNext();) { 960 ((TextEdit)iter.next()).internalMoveTree(delta); 961 } 962 } 963 } 964 965 void deleteTree() { 966 markAsDeleted(); 967 if (fChildren != null) { 968 for (Iterator iter= fChildren.iterator(); iter.hasNext();) { 969 TextEdit child= (TextEdit)iter.next(); 970 child.deleteTree(); 971 } 972 } 973 } 974 } 975 976 | Popular Tags |