diff options
author | Kai Maetzel | 2003-09-23 08:37:09 +0000 |
---|---|---|
committer | Kai Maetzel | 2003-09-23 08:37:09 +0000 |
commit | 7aa98b634820f1462d460274a684fdc839154495 (patch) | |
tree | 5505298378f97ecd6ba983b436d6598930269f29 /org.eclipse.text/src/org/eclipse/text | |
parent | a5ad6bf0ae474c313bb8b8bf3af7a04617f82742 (diff) | |
download | eclipse.platform.text-7aa98b634820f1462d460274a684fdc839154495.tar.gz eclipse.platform.text-7aa98b634820f1462d460274a684fdc839154495.tar.xz eclipse.platform.text-7aa98b634820f1462d460274a684fdc839154495.zip |
updated edits
Diffstat (limited to 'org.eclipse.text/src/org/eclipse/text')
19 files changed, 888 insertions, 547 deletions
diff --git a/org.eclipse.text/src/org/eclipse/text/edits/AbstractTransferEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/AbstractTransferEdit.java deleted file mode 100644 index 192e26d204b..00000000000 --- a/org.eclipse.text/src/org/eclipse/text/edits/AbstractTransferEdit.java +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2003 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.text.edits; - -import java.util.Iterator; -import java.util.List; - -/** - * Abstract superclass for all transfer edits. Transfer edits are edits which copy or - * move a text region inside a document to another location. - * <p> - * This class isn't intended to be subclassed outside of the edit framework. Clients - * are only allowed to subclass <code>MultiTextEdit</code>. - * - * @since 3.0 - */ -public abstract class AbstractTransferEdit extends TextEdit { - - /* package */ int fMode; - /* package */ final static int UNDEFINED= 0; - /* package */ final static int INSERT= 1; - /* package */ final static int DELETE= 2; - - /* package */ AbstractTransferEdit(int offset, int length) { - super(offset, length); - } - - /* - * Copy constructor - */ - /* package */ AbstractTransferEdit(AbstractTransferEdit other) { - super(other); - - } - - /* package */ static void move(List children, int delta) { - if (children != null) { - for (Iterator iter= children.iterator(); iter.hasNext();) { - TextEdit edit= (TextEdit)iter.next(); - edit.adjustOffset(delta); - move(edit.internalGetChildren(), delta); - } - } - } -} diff --git a/org.eclipse.text/src/org/eclipse/text/edits/CopySourceEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/CopySourceEdit.java index b5ef61e4b0d..697245002f3 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/CopySourceEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/CopySourceEdit.java @@ -10,12 +10,11 @@ *******************************************************************************/ package org.eclipse.text.edits; +import java.util.List; + import org.eclipse.jface.text.Assert; import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.Document; -import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; /** * A copy source edit denotes the source of a copy operation. Copy @@ -34,13 +33,14 @@ import org.eclipse.jface.text.IRegion; * * @since 3.0 */ -public final class CopySourceEdit extends AbstractTransferEdit { +public final class CopySourceEdit extends TextEdit { - private String fContent= ""; //$NON-NLS-1$ private CopyTargetEdit fTarget; - /* package */ int fCounter; private ISourceModifier fModifier; - + + private String fSourceContent= ""; //$NON-NLS-1$ + private TextEdit fSourceRoot; + /** * Constructs a new copy source edit. * @@ -124,69 +124,165 @@ public final class CopySourceEdit extends AbstractTransferEdit { protected TextEdit doCopy() { return new CopySourceEdit(this); } + + //---- API for CopyTargetEdit ------------------------------------------------ + /* package */ String getContent() { + return fSourceContent; + } + + /* package */ void clearContent() { + fSourceContent= null; + } + /* non Java-doc * @see TextEdit#postProcessCopy */ protected void postProcessCopy(TextEditCopier copier) { if (fTarget != null) { - ((CopySourceEdit)copier.getCopy(this)).setTargetEdit((CopyTargetEdit)copier.getCopy(fTarget)); + CopySourceEdit source= (CopySourceEdit)copier.getCopy(this); + CopyTargetEdit target= (CopyTargetEdit)copier.getCopy(fTarget); + if (source != null && target != null) + source.setTargetEdit(target); } } + //---- pass one ---------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.text.edits.TextEdit#traversePassOne + */ + /* package */ void traversePassOne(TextEditProcessor processor, IDocument document) { + if (processor.considerEdit(this)) { + MultiTextEdit root= new MultiTextEdit(getOffset(), getLength()); + root.internalSetChildren(internalGetChildren()); + try { + fSourceContent= document.get(getOffset(), getLength()); + } catch (BadLocationException cannotHappen) { + Assert.isTrue(false); + } + fSourceRoot= root.copy(); + fixCopyTree(fSourceRoot); + fSourceRoot.moveTree(-getOffset()); + } + super.traversePassOne(processor, document); + } + /* non Java-doc - * @see TextEdit#checkIntegrity + * @see TextEdit#performPassOne */ - protected void checkIntegrity() throws MalformedTreeException { + /* package */ void performPassOne(TextEditProcessor processor, IDocument document) throws MalformedTreeException { if (fTarget == null) throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("CopySourceEdit.no_target")); //$NON-NLS-1$ if (fTarget.getSourceEdit() != this) throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("CopySourceEdit.different_source")); //$NON-NLS-1$ + + try { + if (fSourceRoot.hasChildren()) { + EditDocument subDocument= new EditDocument(fSourceContent); + fSourceRoot.apply(subDocument, TextEdit.NONE); + if (needsTransformation()) + applyTransformation(subDocument); + fSourceContent= subDocument.get(); + fSourceRoot= null; + } else { + if (needsTransformation()) { + EditDocument subDocument= new EditDocument(fSourceContent); + applyTransformation(subDocument); + fSourceContent= subDocument.get(); + } + } + } catch (BadLocationException cannotHappen) { + Assert.isTrue(false); + } } - /* package */ void perform(IDocument document) throws BadLocationException { - fContent= getContent(document); - if (++fCounter == 2 && !fTarget.isDeleted()) { - try { - IRegion region= fTarget.getRegion(); - document.replace(region.getOffset(), region.getLength(), fContent); - } finally { - clearContent(); - } + private boolean needsTransformation() { + return fModifier != null; + } + + private void applyTransformation(IDocument document) throws MalformedTreeException { + TextEdit newEdit= new MultiTextEdit(0, document.getLength()); + ReplaceEdit[] replaces= fModifier.getModifications(document.get()); + for (int i= 0; i < replaces.length; i++) { + newEdit.addChild(replaces[i]); + } + try { + newEdit.apply(document, TextEdit.NONE); + } catch (BadLocationException cannotHappen) { + Assert.isTrue(false); } } - - private String getContent(IDocument document) throws BadLocationException { - String result= document.get(getOffset(), getLength()); - if (fModifier != null) { - IDocument newDocument= new Document(result); - TextEdit newEdit= new MultiTextEdit(0, getLength()); - ReplaceEdit[] replaces= fModifier.getModifications(result); - try { - for (int i= 0; i < replaces.length; i++) { - newEdit.addChild(replaces[i]); + + private void fixCopyTree(TextEdit edit) { + TextEdit replacement= null; + if (edit instanceof MoveSourceEdit) { + MoveSourceEdit ms= (MoveSourceEdit)edit; + if (ms.getTargetEdit() == null) { + replacement= new DeleteEdit(ms.getOffset(), ms.getLength()); + } + } else if (edit instanceof MoveTargetEdit) { + MoveTargetEdit mt= (MoveTargetEdit)edit; + if (mt.getSourceEdit() == null) { + replacement= new RangeMarker(mt.getOffset(), mt.getLength()); + } + } else if (edit instanceof CopySourceEdit) { + CopySourceEdit cs= (CopySourceEdit)edit; + if (cs.getTargetEdit() == null) { + replacement= new RangeMarker(cs.getOffset(), cs.getLength()); + } + } else if (edit instanceof CopyTargetEdit) { + CopyTargetEdit ct= (CopyTargetEdit)edit; + if (ct.getSourceEdit() == null) { + replacement= new RangeMarker(ct.getOffset(), ct.getLength()); + } + } + if (replacement != null) { + // replace at parent + { + TextEdit parent= edit.getParent(); + List children= parent.internalGetChildren(); + + int index= children.indexOf(edit); + children.remove(index); + children.add(index, replacement); + edit.internalSetParent(null); + replacement.internalSetParent(parent); + } + + // move children + { + TextEdit[] children= edit.removeChildren(); + for (int i= 0; i < children.length; i++) { + TextEdit child= children[i]; + replacement.addChild(child); + fixCopyTree(child); } - newEdit.apply(newDocument); - } catch (MalformedTreeException e) { - throw new BadLocationException(); } - result= newDocument.get(); + } else { + TextEdit[] children= edit.getChildren(); + for (int i= 0; i < children.length; i++) { + fixCopyTree(children[i]); + } } - return result; } - /* package */ void update(DocumentEvent event, TreeIterationInfo info) { - // Executing the copy source edit means inserting the text - // at target position. So we have to update the edits around - // the target. - fTarget.update(event); - } + //---- pass two ---------------------------------------------------------------- - /* package */ String getContent() { - return fContent; + /* non Java-doc + * @see TextEdit#performPassTwo + */ + /* package */ int performPassTwo(IDocument document) throws BadLocationException { + fDelta= 0; + return fDelta; } + + //---- pass three ---------------------------------------------------------------- - /* package */ void clearContent() { - fContent= null; - } + /* non Java-doc + * @see TextEdit#deleteChildren + */ + /* package */ boolean deleteChildren() { + return false; + } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/CopyTargetEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/CopyTargetEdit.java index 12194c9285c..4b151c54506 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/CopyTargetEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/CopyTargetEdit.java @@ -13,7 +13,6 @@ package org.eclipse.text.edits; import org.eclipse.jface.text.Assert; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IRegion; /** * A copy target edit denotes the target of a copy operation. Copy @@ -31,7 +30,7 @@ import org.eclipse.jface.text.IRegion; * * @since 3.0 */ -public final class CopyTargetEdit extends AbstractTransferEdit { +public final class CopyTargetEdit extends TextEdit { private CopySourceEdit fSource; @@ -106,14 +105,17 @@ public final class CopyTargetEdit extends AbstractTransferEdit { */ protected void postProcessCopy(TextEditCopier copier) { if (fSource != null) { - ((CopyTargetEdit)copier.getCopy(this)).setSourceEdit((CopySourceEdit)copier.getCopy(fSource)); + CopyTargetEdit target= (CopyTargetEdit)copier.getCopy(this); + CopySourceEdit source= (CopySourceEdit)copier.getCopy(fSource); + if (target != null && source != null) + target.setSourceEdit(source); } } /* non Java-doc - * @see TextEdit#checkIntegrity + * @see TextEdit#performPassOne */ - protected void checkIntegrity() throws MalformedTreeException { + /* package */ void performPassOne(TextEditProcessor processor, IDocument document) throws MalformedTreeException { if (fSource == null) throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("CopyTargetEdit.no_source")); //$NON-NLS-1$ if (fSource.getTargetEdit() != this) @@ -121,16 +123,20 @@ public final class CopyTargetEdit extends AbstractTransferEdit { } /* non Java-doc - * @see TextEdit#perform + * @see TextEdit#performPassTwo */ - /* package */ void perform(IDocument document) throws BadLocationException { - if (++fSource.fCounter == 2 && !isDeleted()) { - try { - IRegion region= getRegion(); - document.replace(region.getOffset(), region.getLength(), fSource.getContent()); - } finally { - fSource.clearContent(); - } - } + /* package */ int performPassTwo(IDocument document) throws BadLocationException { + String source= fSource.getContent(); + document.replace(getOffset(), getLength(), source); + fDelta= source.length() - getLength(); + fSource.clearContent(); + return fDelta; + } + + /* non Java-doc + * @see TextEdit#deleteChildren + */ + /* package */ boolean deleteChildren() { + return false; } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/CopyingRangeMarker.java b/org.eclipse.text/src/org/eclipse/text/edits/CopyingRangeMarker.java index 3e5a7876141..31916527944 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/CopyingRangeMarker.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/CopyingRangeMarker.java @@ -51,9 +51,18 @@ public final class CopyingRangeMarker extends TextEdit { } /* non Java-doc - * @see TextEdit#perform + * @see TextEdit#performPassTwo */ - /* package */ final void perform(IDocument document) throws BadLocationException { + /* package */ int performPassTwo(IDocument document) throws BadLocationException { fText= document.get(getOffset(), getLength()); + fDelta= 0; + return fDelta; + } + + /* non Java-doc + * @see TextEdit#deleteChildren + */ + /* package */ boolean deleteChildren() { + return false; } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/DeleteEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/DeleteEdit.java index a9246087adf..e16cfdb09bc 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/DeleteEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/DeleteEdit.java @@ -11,7 +11,6 @@ package org.eclipse.text.edits; import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; /** @@ -49,17 +48,18 @@ public final class DeleteEdit extends TextEdit { } /* non Java-doc - * @see TextEdit#perform + * @see TextEdit#performPassTwo */ - /* package */ void perform(IDocument document) throws BadLocationException { + /* package */ int performPassTwo(IDocument document) throws BadLocationException { document.replace(getOffset(), getLength(), ""); //$NON-NLS-1$ + fDelta= -getLength(); + return fDelta; } /* non Java-doc - * @see TextEdit#update + * @see TextEdit#deleteChildren */ - /* package */ void update(DocumentEvent event, TreeIterationInfo info) { - markChildrenAsDeleted(); - super.update(event, info); - } + /* package */ boolean deleteChildren() { + return true; + } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/EditDocument.java b/org.eclipse.text/src/org/eclipse/text/edits/EditDocument.java new file mode 100644 index 00000000000..ef599db5272 --- /dev/null +++ b/org.eclipse.text/src/org/eclipse/text/edits/EditDocument.java @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.text.edits; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.BadPositionCategoryException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentListener; +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.jface.text.IDocumentPartitioningListener; +import org.eclipse.jface.text.IPositionUpdater; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.Position; + +/* package */ class EditDocument implements IDocument { + + private StringBuffer fBuffer; + + public EditDocument(String content) { + fBuffer= new StringBuffer(content); + } + + public void addDocumentListener(IDocumentListener listener) { + throw new UnsupportedOperationException(); + } + + public void addDocumentPartitioningListener(IDocumentPartitioningListener listener) { + throw new UnsupportedOperationException(); + } + + public void addPosition(Position position) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public void addPosition(String category, Position position) throws BadLocationException, BadPositionCategoryException { + throw new UnsupportedOperationException(); + } + + public void addPositionCategory(String category) { + throw new UnsupportedOperationException(); + } + + public void addPositionUpdater(IPositionUpdater updater) { + throw new UnsupportedOperationException(); + } + + public void addPrenotifiedDocumentListener(IDocumentListener documentAdapter) { + throw new UnsupportedOperationException(); + } + + public int computeIndexInCategory(String category, int offset) throws BadLocationException, BadPositionCategoryException { + throw new UnsupportedOperationException(); + } + + public int computeNumberOfLines(String text) { + throw new UnsupportedOperationException(); + } + + public ITypedRegion[] computePartitioning(int offset, int length) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public boolean containsPosition(String category, int offset, int length) { + throw new UnsupportedOperationException(); + } + + public boolean containsPositionCategory(String category) { + throw new UnsupportedOperationException(); + } + + public String get() { + return fBuffer.toString(); + } + + public String get(int offset, int length) throws BadLocationException { + char[] result= new char[length]; + fBuffer.getChars(offset, offset + length, result, 0); + return new String(result); + } + + public char getChar(int offset) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public String getContentType(int offset) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public IDocumentPartitioner getDocumentPartitioner() { + throw new UnsupportedOperationException(); + } + + public String[] getLegalContentTypes() { + throw new UnsupportedOperationException(); + } + + public String[] getLegalLineDelimiters() { + throw new UnsupportedOperationException(); + } + + public int getLength() { + return fBuffer.length(); + } + + public String getLineDelimiter(int line) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public IRegion getLineInformation(int line) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public IRegion getLineInformationOfOffset(int offset) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public int getLineLength(int line) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public int getLineOffset(int line) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public int getLineOfOffset(int offset) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public int getNumberOfLines() { + throw new UnsupportedOperationException(); + } + + public int getNumberOfLines(int offset, int length) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public ITypedRegion getPartition(int offset) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public String[] getPositionCategories() { + throw new UnsupportedOperationException(); + } + + public Position[] getPositions(String category) throws BadPositionCategoryException { + throw new UnsupportedOperationException(); + } + + public IPositionUpdater[] getPositionUpdaters() { + throw new UnsupportedOperationException(); + } + + public void insertPositionUpdater(IPositionUpdater updater, int index) { + throw new UnsupportedOperationException(); + } + + public void removeDocumentListener(IDocumentListener listener) { + throw new UnsupportedOperationException(); + } + + public void removeDocumentPartitioningListener(IDocumentPartitioningListener listener) { + throw new UnsupportedOperationException(); + } + + public void removePosition(Position position) { + throw new UnsupportedOperationException(); + } + + public void removePosition(String category, Position position) throws BadPositionCategoryException { + throw new UnsupportedOperationException(); + } + + public void removePositionCategory(String category) throws BadPositionCategoryException { + throw new UnsupportedOperationException(); + } + + public void removePositionUpdater(IPositionUpdater updater) { + throw new UnsupportedOperationException(); + } + + public void removePrenotifiedDocumentListener(IDocumentListener documentAdapter) { + throw new UnsupportedOperationException(); + } + + public void replace(int offset, int length, String text) throws BadLocationException { + fBuffer.replace(offset, offset + length, text); + } + + public int search(int startOffset, String findString, boolean forwardSearch, boolean caseSensitive, boolean wholeWord) throws BadLocationException { + throw new UnsupportedOperationException(); + } + + public void set(String text) { + throw new UnsupportedOperationException(); + } + + public void setDocumentPartitioner(IDocumentPartitioner partitioner) { + throw new UnsupportedOperationException(); + } +} diff --git a/org.eclipse.text/src/org/eclipse/text/edits/ISourceModifier.java b/org.eclipse.text/src/org/eclipse/text/edits/ISourceModifier.java index 38a53d692fb..bab1fcca18a 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/ISourceModifier.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/ISourceModifier.java @@ -22,13 +22,18 @@ package org.eclipse.text.edits; public interface ISourceModifier { /** * Returns the modification to be done to the passed - * string in form of replace edits. The caller of this - * method is responsible to apply the returned edits - * to the passed source. + * string in form of replace edits. The set of returned + * replace edits must modify disjoint text regions. + * Violating this requirement will result in a <code> + * BadLocationException</code> while executing the + * associated move or copy edit. + * <p> + * The caller of this method is responsible to apply + * the returned edits to the passed source. * * @param source the source to be copied or moved * @return an array of <code>ReplaceEdits</code> - * describing the modifications + * describing the modifications. */ public ReplaceEdit[] getModifications(String source); @@ -37,6 +42,8 @@ public interface ISourceModifier { * be used in a different text edit object. So it should be * created in a way that is doesn't conflict with other text edits * refering to this source modifier. + * + * @return the copy of the source modifier */ public ISourceModifier copy(); } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/InsertEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/InsertEdit.java index 7e8a91171d8..86be7567dc3 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/InsertEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/InsertEdit.java @@ -11,7 +11,6 @@ package org.eclipse.text.edits; import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; /** @@ -64,24 +63,25 @@ public final class InsertEdit extends TextEdit { } /* non Java-doc - * @see TextEdit#perform + * @see TextEdit#performPassTwo */ - /* package */ void perform(IDocument document) throws BadLocationException { + /* package */ int performPassTwo(IDocument document) throws BadLocationException { document.replace(getOffset(), getLength(), fText); + fDelta= fText.length() - getLength(); + return fDelta; } /* non Java-doc - * @see TextEdit#update + * @see TextEdit#deleteChildren */ - /* package */ void update(DocumentEvent event, TreeIterationInfo info) { - markChildrenAsDeleted(); - super.update(event, info); + /* package */ boolean deleteChildren() { + return false; } - + /* non Java-doc * @see java.lang.Object#toString() */ public String toString() { return super.toString() + " <<" + fText; //$NON-NLS-1$ - } + } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/MalformedTreeException.java b/org.eclipse.text/src/org/eclipse/text/edits/MalformedTreeException.java index 092532359b1..f5baec919a3 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/MalformedTreeException.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/MalformedTreeException.java @@ -54,4 +54,8 @@ public class MalformedTreeException extends RuntimeException { public TextEdit getChild() { return fChild; } + + /* package */ void setParent(TextEdit parent) { + fParent= parent; + } }
\ No newline at end of file diff --git a/org.eclipse.text/src/org/eclipse/text/edits/MoveSourceEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/MoveSourceEdit.java index b4b458a1fb2..dbd50e37d09 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/MoveSourceEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/MoveSourceEdit.java @@ -19,8 +19,6 @@ import java.util.Map; import org.eclipse.jface.text.Assert; import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.Document; -import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Region; @@ -43,15 +41,13 @@ import org.eclipse.jface.text.Region; * * @since 3.0 */ -public final class MoveSourceEdit extends AbstractTransferEdit { +public final class MoveSourceEdit extends TextEdit { - /* package */ int fCounter; private MoveTargetEdit fTarget; private ISourceModifier fModifier; - private String fContent; - private int fContentOffset; - private List fContentChildren; + private String fSourceContent; + private MultiTextEdit fSourceRoot; /** * Constructs a new move source edit. @@ -126,6 +122,23 @@ public final class MoveSourceEdit extends AbstractTransferEdit { public void setSourceModifier(ISourceModifier modifier) { fModifier= modifier; } + + //---- API for MoveTargetEdit --------------------------------------------- + + /* package */ String getContent() { + return fSourceContent; + } + + /* package */ MultiTextEdit getRoot() { + return fSourceRoot; + } + + /* package */ void clearContent() { + fSourceContent= null; + fSourceRoot= null; + } + + //---- Copying ------------------------------------------------------------- /* non Java-doc * @see TextEdit#doCopy @@ -139,133 +152,132 @@ public final class MoveSourceEdit extends AbstractTransferEdit { */ protected void postProcessCopy(TextEditCopier copier) { if (fTarget != null) { - ((MoveSourceEdit)copier.getCopy(this)).setTargetEdit((MoveTargetEdit)copier.getCopy(fTarget)); + MoveSourceEdit source= (MoveSourceEdit)copier.getCopy(this); + MoveTargetEdit target= (MoveTargetEdit)copier.getCopy(fTarget); + if (source != null && target != null) + source.setTargetEdit(target); + } + } + + //---- pass one ---------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.text.edits.TextEdit#traversePassOne + */ + /* package */ void traversePassOne(TextEditProcessor processor, IDocument document) { + // Do not process the children. The are covered by the actual + // perform operation. + if (processor.considerEdit(this)) { + performPassOne(processor, document); } } /* non Java-doc - * @see TextEdit#checkIntegrity + * @see TextEdit#performPassOne */ - protected void checkIntegrity() throws MalformedTreeException { + /* package */ void performPassOne(TextEditProcessor processor, IDocument document) throws MalformedTreeException { if (fTarget == null) throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("MoveSourceEdit.no_target")); //$NON-NLS-1$ if (fTarget.getSourceEdit() != this) throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("MoveSourceEdit.different_source")); //$NON-NLS-1$ - } - - /* non Java-doc - * @see TextEdit#perform - */ - /* package */ void perform(IDocument document) throws BadLocationException { - fCounter++; - switch(fCounter) { - // Position of move source > position of move target. - // Hence MoveTarget does the actual move. Move Source - // only deletes the content. - case 1: - fContent= getContent(document); - fContentOffset= getOffset(); - fContentChildren= internalGetChildren(); - fMode= DELETE; - document.replace(getOffset(), getLength(), ""); //$NON-NLS-1$ - // do this after executing the replace to be able to - // compute the number of children. - internalSetChildren(null); - break; - - // Position of move source < position of move target. - // Hence move source handles the delete and the - // insert at the target position. - case 2: - fContent= getContent(document); - fMode= DELETE; - document.replace(getOffset(), getLength(), ""); //$NON-NLS-1$ - if (!fTarget.isDeleted()) { - // Insert target - IRegion targetRange= fTarget.getRegion(); - fMode= INSERT; - document.replace(targetRange.getOffset(), targetRange.getLength(), fContent); + + try { + TextEdit[] children= removeChildren(); + if (children.length > 0) { + String content= document.get(getOffset(), getLength()); + EditDocument subDocument= new EditDocument(content); + fSourceRoot= new MultiTextEdit(getOffset(), getLength()); + fSourceRoot.addChildren(children); + fSourceRoot.moveTree(-getOffset()); + int processingStyle= getStyle(processor); + fSourceRoot.apply(subDocument, processingStyle); + if (needsTransformation()) + applyTransformation(subDocument, processingStyle); + fSourceContent= subDocument.get(); + } else { + fSourceContent= document.get(getOffset(), getLength()); + if (needsTransformation()) { + EditDocument subDocument= new EditDocument(fSourceContent); + applyTransformation(subDocument, getStyle(processor)); + fSourceContent= subDocument.get(); } - clearContent(); - break; - default: - Assert.isTrue(false, "Should never happen"); //$NON-NLS-1$ + } + } catch (BadLocationException cannotHappen) { + Assert.isTrue(false); } } - - /* package */ String getContent() { - return fContent; - } - /* package */ List getContentChildren() { - return fContentChildren; + private int getStyle(TextEditProcessor processor) { + // we never need undo while performing local edits. + if ((processor.getStyle() & TextEdit.UPDATE_REGIONS) != 0) + return TextEdit.UPDATE_REGIONS; + return TextEdit.NONE; } - /* package */ int getContentOffset() { - return fContentOffset; + //---- pass two ---------------------------------------------------------------- + + /* package */ int performPassTwo(IDocument document) throws BadLocationException { + document.replace(getOffset(), getLength(), ""); //$NON-NLS-1$ + fDelta= -getLength(); + return fDelta; } - /* package */ void clearContent() { - fContent= null; - fContentChildren= null; - fContentOffset= -1; + //---- pass three -------------------------------------------------------------- + + /* non Java-doc + * @see TextEdit#deleteChildren + */ + /* package */ boolean deleteChildren() { + return false; } - /* package */ void update(DocumentEvent event, TreeIterationInfo info) { - if (fMode == DELETE) { // source got deleted - super.update(event, info); - } else if (fMode == INSERT) { // text got inserted at target position - fTarget.update(event); - List children= internalGetChildren(); - if (children != null) { - internalSetChildren(null); - int moveDelta= fTarget.getOffset() - getOffset(); - move(children, moveDelta); - } - fTarget.internalSetChildren(children); - } else { - Assert.isTrue(false); - } - } + //---- content transformation -------------------------------------------------- - //---- content management -------------------------------------------------- + private boolean needsTransformation() { + return fModifier != null; + } - private String getContent(IDocument document) throws BadLocationException { - String result= document.get(getOffset(), getLength()); - if (fModifier != null) { - IDocument newDocument= new Document(result); + private void applyTransformation(IDocument document, int style) throws MalformedTreeException { + if ((style & TextEdit.UPDATE_REGIONS) != 0 && fSourceRoot != null) { Map editMap= new HashMap(); TextEdit newEdit= createEdit(editMap); - List replaces= new ArrayList(Arrays.asList(fModifier.getModifications(result))); + List replaces= new ArrayList(Arrays.asList(fModifier.getModifications(document.get()))); + insertEdits(newEdit, replaces); + try { + newEdit.apply(document, style); + } catch (BadLocationException cannotHappen) { + Assert.isTrue(false); + } + restorePositions(editMap); + } else { + MultiTextEdit newEdit= new MultiTextEdit(0, document.getLength()); + TextEdit[] replaces= fModifier.getModifications(document.get()); + for (int i= 0; i < replaces.length; i++) { + newEdit.addChild(replaces[i]); + } try { - insertEdits(newEdit, replaces); - newEdit.apply(newDocument); - } catch (MalformedTreeException e) { - throw new BadLocationException(); + newEdit.apply(document, style); + } catch (BadLocationException cannotHappen) { + Assert.isTrue(false); } - restorePositions(editMap, getOffset()); - result= newDocument.get(); } - return result; } private TextEdit createEdit(Map editMap) { - int delta= getOffset(); - MultiTextEdit result= new MultiTextEdit(0, getLength()); - // don't but the root edit into the edit map. The sourc edit - // will be updated by the perform method. - createEdit(this, result, editMap, delta); + MultiTextEdit result= new MultiTextEdit(0, fSourceRoot.getLength()); + editMap.put(result, fSourceRoot); + createEdit(fSourceRoot, result, editMap); return result; } - private static void createEdit(TextEdit source, TextEdit target, Map editMap, int delta) { + private static void createEdit(TextEdit source, TextEdit target, Map editMap) { TextEdit[] children= source.getChildren(); for (int i= 0; i < children.length; i++) { TextEdit child= children[i]; - RangeMarker marker= new RangeMarker(child.getOffset() - delta, child.getLength()); + RangeMarker marker= new RangeMarker(child.getOffset(), child.getLength()); target.addChild(marker); editMap.put(marker, child); - createEdit(child, marker, editMap, delta); + createEdit(child, marker, editMap); } } @@ -351,14 +363,14 @@ public final class MoveSourceEdit extends AbstractTransferEdit { return result; } - private static void restorePositions(Map editMap, int delta) { + private static void restorePositions(Map editMap) { for (Iterator iter= editMap.keySet().iterator(); iter.hasNext();) { TextEdit marker= (TextEdit)iter.next(); TextEdit edit= (TextEdit)editMap.get(marker); if (marker.isDeleted()) { edit.markAsDeleted(); } else { - edit.adjustOffset(marker.getOffset() - edit.getOffset() + delta); + edit.adjustOffset(marker.getOffset() - edit.getOffset()); edit.adjustLength(marker.getLength() - edit.getLength()); } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/MoveTargetEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/MoveTargetEdit.java index f79b8926628..f83623b3e73 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/MoveTargetEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/MoveTargetEdit.java @@ -10,11 +10,10 @@ *******************************************************************************/ package org.eclipse.text.edits; +import java.util.ArrayList; import java.util.List; -import org.eclipse.jface.text.Assert; import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; /** @@ -34,7 +33,7 @@ import org.eclipse.jface.text.IDocument; * * @since 3.0 */ -public final class MoveTargetEdit extends AbstractTransferEdit { +public final class MoveTargetEdit extends TextEdit { private MoveSourceEdit fSource; @@ -108,46 +107,69 @@ public final class MoveTargetEdit extends AbstractTransferEdit { */ protected void postProcessCopy(TextEditCopier copier) { if (fSource != null) { - ((MoveTargetEdit)copier.getCopy(this)).setSourceEdit((MoveSourceEdit)copier.getCopy(fSource)); + MoveTargetEdit target= (MoveTargetEdit)copier.getCopy(this); + MoveSourceEdit source= (MoveSourceEdit)copier.getCopy(fSource); + if (target != null && source != null) + target.setSourceEdit(source); } } + //---- pass one ---------------------------------------------------------------- + /* non Java-doc - * @see TextEdit#checkIntegrity + * @see TextEdit#performPassOne */ - protected void checkIntegrity() { + /* package */ void performPassOne(TextEditProcessor processor, IDocument document) throws MalformedTreeException { if (fSource == null) throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("MoveTargetEdit.no_source")); //$NON-NLS-1$ if (fSource.getTargetEdit() != this) throw new MalformedTreeException(getParent(), this, TextEditMessages.getString("MoveTargetEdit.different_target")); //$NON-NLS-1$ } + //---- pass two ---------------------------------------------------------------- + /* non Java-doc - * @see TextEdit#perform + * @see TextEdit#performPassTwo */ - /* package */ void perform(IDocument document) throws BadLocationException { - if (++fSource.fCounter == 2) { - String source= fSource.getContent(); - fMode= INSERT; - document.replace(getOffset(), getLength(), source); + /* package */ int performPassTwo(IDocument document) throws BadLocationException { + String source= fSource.getContent(); + document.replace(getOffset(), getLength(), source); + fDelta= source.length() - getLength(); + + MultiTextEdit sourceRoot= fSource.getRoot(); + if (sourceRoot != null) { + sourceRoot.moveTree(getOffset()); + TextEdit[] sourceChildren= sourceRoot.removeChildren(); + List children= new ArrayList(sourceChildren.length); + for (int i= 0; i < sourceChildren.length; i++) { + TextEdit child= sourceChildren[i]; + child.internalSetParent(this); + children.add(child); + } + internalSetChildren(children); } + fSource.clearContent(); + return fDelta; } - /* package */ void update(DocumentEvent event, TreeIterationInfo info) { - if (fMode == INSERT) { - // we have to substract the delta since <code>super.updateTextRange</code> - // add the delta to the move source's children. - int moveDelta= getOffset() - fSource.getContentOffset(); - - super.update(event, info); - - List sourceChildren= fSource.getContentChildren(); - move(sourceChildren, moveDelta); - internalSetChildren(sourceChildren); - + //---- pass three -------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.text.edits.TextEdit#traversePassThree + */ + /* package */ int traversePassThree(TextEditProcessor processor, IDocument document, int accumulatedDelta, boolean delete) { + // the children got already updated / normalized while they got removed + // from the source edit. So we only have to adjust the offset computed to + // far. + if (delete) { + deleteTree(); } else { - Assert.isTrue(false); + moveTree(accumulatedDelta); } - + return accumulatedDelta + fDelta; + } + + /* package */ boolean deleteChildren() { + return false; } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/MultiTextEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/MultiTextEdit.java index f09faf456b7..b28e329d48e 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/MultiTextEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/MultiTextEdit.java @@ -11,6 +11,7 @@ package org.eclipse.text.edits; import org.eclipse.jface.text.Assert; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; @@ -65,6 +66,22 @@ public class MultiTextEdit extends TextEdit { super(other); } + /** + * Checks the edit's integrity. + * <p> + * Note that this method <b>should only be called</b> by the edit + * framework and not by normal clients. + *<p> + * This default implementation does nothing. Subclasses may override + * if needed. + * + * @exception MalformedTreeException if the edit isn't in a valid state + * and can therefore not be executed + */ + protected void checkIntegrity() throws MalformedTreeException { + // does nothing + } + /* non Java-doc * @see TextEdit#copy */ @@ -72,14 +89,29 @@ public class MultiTextEdit extends TextEdit { Assert.isTrue(MultiTextEdit.class == getClass(), "Subclasses must reimplement copy0"); //$NON-NLS-1$ return new MultiTextEdit(this); } + + /* non Java-doc + * @see TextEdit#performPassOne + */ + /* package */ void performPassOne(TextEditProcessor processor, IDocument document) throws MalformedTreeException { + checkIntegrity(); + } /* non Java-doc - * @see TextEdit#perform + * @see TextEdit#performPassTwo */ - /* package */ final void perform(IDocument document) { - // do nothing. + /* package */ int performPassTwo(IDocument document) throws BadLocationException { + fDelta= 0; + return fDelta; } - + + /* non Java-doc + * @see TextEdit#deleteChildren + */ + /* package */ boolean deleteChildren() { + return false; + } + /* package */ void aboutToBeAdded(TextEdit parent) { defineRegion(parent.getOffset()); } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/RangeMarker.java b/org.eclipse.text/src/org/eclipse/text/edits/RangeMarker.java index 624c8f38b83..f5c5a55a67e 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/RangeMarker.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/RangeMarker.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.text.edits; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; /** @@ -38,16 +39,24 @@ public final class RangeMarker extends TextEdit { } /* non Java-doc - * @see TextEdit#perform + * @see TextEdit#copy */ - /* package */ final void perform(IDocument document) { - // do nothing + protected TextEdit doCopy() { + return new RangeMarker(this); } /* non Java-doc - * @see TextEdit#copy + * @see TextEdit#performPassTwo */ - protected TextEdit doCopy() { - return new RangeMarker(this); - } + /* package */ int performPassTwo(IDocument document) throws BadLocationException { + fDelta= 0; + return fDelta; + } + + /* non Java-doc + * @see TextEdit#deleteChildren + */ + /* package */ boolean deleteChildren() { + return false; + } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/ReplaceEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/ReplaceEdit.java index 00e37cb965d..0d059db273b 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/ReplaceEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/ReplaceEdit.java @@ -10,8 +10,8 @@ *******************************************************************************/ package org.eclipse.text.edits; +import org.eclipse.jface.text.Assert; import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; /** @@ -33,6 +33,7 @@ public final class ReplaceEdit extends TextEdit { */ public ReplaceEdit(int offset, int length, String text) { super(offset, length); + Assert.isNotNull(text); fText= text; } @@ -64,20 +65,21 @@ public final class ReplaceEdit extends TextEdit { } /* non Java-doc - * @see TextEdit#perform + * @see TextEdit#performPassTwo */ - /* package */ void perform(IDocument document) throws BadLocationException { + /* package */ int performPassTwo(IDocument document) throws BadLocationException { document.replace(getOffset(), getLength(), fText); + fDelta= fText.length() - getLength(); + return fDelta; } - + /* non Java-doc - * @see TextEdit#update + * @see TextEdit#deleteChildren */ - /* package */ void update(DocumentEvent event, TreeIterationInfo info) { - markChildrenAsDeleted(); - super.update(event, info); + /* package */ boolean deleteChildren() { + return true; } - + /* non Java-doc * @see java.lang.Object#toString() */ diff --git a/org.eclipse.text/src/org/eclipse/text/edits/TextEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/TextEdit.java index 87f899d1e5a..93a3b3a2ed0 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/TextEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/TextEdit.java @@ -11,14 +11,13 @@ package org.eclipse.text.edits; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.List; -import org.eclipse.text.edits.TreeIterationInfo.Visitor; - import org.eclipse.jface.text.Assert; import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.Region; @@ -64,15 +63,71 @@ import org.eclipse.jface.text.Region; */ public abstract class TextEdit { + /** + * Flags indicating that either <code>CREATE_UNDO</code> nor + * <code>UPDATE_REGIONS</code> is set. + */ + public static final int NONE= 0; + + /** + * Flags indicating that applying an edit tree to a document + * is supposed to create a corresponding undo edit. If not + * specified <code>null</code> is returned from method <code> + * apply</code>. + */ + public static final int CREATE_UNDO= 1 << 0; + + /** + * Flag indicating that the edit's region will be updated to + * reflect its position in the changed document. If not specified + * when applying an edit tree to a document the edit's region will + * be arbitrary. It is even not guaranteed that the tree is still + * well formed. + */ + public static final int UPDATE_REGIONS= 1 << 1; + + private static class InsertionComparator implements Comparator { + public int compare(Object o1, Object o2) { + TextEdit edit1 = (TextEdit) o1; + TextEdit edit2 = (TextEdit) o2; + + int offset1 = edit1.getOffset(); + int length1 = edit1.getLength(); + + int offset2 = edit2.getOffset(); + int length2 = edit2.getLength(); + + // make sure that a duplicate insertion point at the same offet is + // inserted last. Have to double check with the spec. It says the + // with identical values there is no guarantee which one will be + // found. + if (offset1 == offset2 && length1 == 0 && length2 == 0) { + return -1; + } + if (offset1 + length1 - 1 < offset2) { + return -1; + } + if (offset2 + length2 - 1 < offset1) { + return 1; + } + throw new MalformedTreeException( + null, edit1, + TextEditMessages.getString("TextEdit.overlapping")); //$NON-NLS-1$ + } + } + private static final TextEdit[] EMPTY_ARRAY= new TextEdit[0]; + private static final InsertionComparator INSERTION_COMPARATOR= new InsertionComparator(); private static final int DELETED_VALUE= -1; private int fOffset; private int fLength; - private TextEdit fParent; - private List fChildren; + /* package */ TextEdit fParent; + /* package */ List fChildren; + + /* package */ int fDelta; /** * Create a new text edit. Parent is initialized to <code> @@ -82,6 +137,7 @@ public abstract class TextEdit { Assert.isTrue(offset >= 0 && length >= 0); fOffset= offset; fLength= length; + fDelta= 0; } /** @@ -92,6 +148,7 @@ public abstract class TextEdit { protected TextEdit(TextEdit source) { fOffset= source.fOffset; fLength= source.fLength; + fDelta= 0; } //---- Region management ----------------------------------------------- @@ -283,7 +340,7 @@ public abstract class TextEdit { */ public final TextEdit[] removeChildren() { if (fChildren == null) - return new TextEdit[0]; + return EMPTY_ARRAY; int size= fChildren.size(); TextEdit[] result= new TextEdit[size]; for (int i= 0; i < size; i++) { @@ -479,6 +536,11 @@ public abstract class TextEdit { * execute an edit tree. * * @param document the document to be manipulated + * @param style flags controlling the execution of the edit tree. Valid + * flags are: <code>CREATE_UNDO</code> and </code>UPDATE_REGIONS</code>. + * @return a undo edit, if <code>CREATE_UNDO</code> is specified. Otherwise + * <code>null</code> is returned. + * * @exception MalformedTreeException is thrown if the tree isn't * in a valid state. This exception is thrown before any edit * is executed. So the document is still in its original state. @@ -490,9 +552,9 @@ public abstract class TextEdit { * @see #perform(IDocument) * @see TextEditProcessor#performEdits() */ - public final UndoEdit apply(IDocument document) throws MalformedTreeException, BadLocationException { + public final UndoEdit apply(IDocument document, int style) throws MalformedTreeException, BadLocationException { try { - TextEditProcessor processor= new TextEditProcessor(document, this); + TextEditProcessor processor= new TextEditProcessor(document, this, style); return processor.performEdits(); } finally { // unconnect from text edit processor @@ -501,34 +563,16 @@ public abstract class TextEdit { } /** - * Checks the edit's integrity. - * <p> - * Note that this method <b>should only be called</b> by the edit - * framework and not by normal clients. - *<p> - * This default implementation does nothing. Subclasses may override - * if needed. - * - * @exception MalformedTreeException if the edit isn't in a valid state - * and can therefore not be executed - */ - protected void checkIntegrity() throws MalformedTreeException { - // does nothing - } - - /** - * Performs the text edit. - * - * <p> - * Note that this method <b>should only be called</b> by the edit framework. - * - * @param document the actual document to manipulate + * Applies the edit tree rooted by this edit to the given document. This + * method is a convinence method for <code>apply(document, CREATE_UNDO | UPDATE_REGIONS) + * </code> * - * @see #apply(IDocument) + * @see #apply(IDocument, int) */ - /* package */ abstract void perform(IDocument document) throws BadLocationException; - - + public final UndoEdit apply(IDocument document) throws MalformedTreeException, BadLocationException { + return apply(document, CREATE_UNDO | UPDATE_REGIONS); + } + /* package */ UndoEdit dispatchPerformEdits(TextEditProcessor processor) throws BadLocationException { return processor.executeDo(); } @@ -581,20 +625,15 @@ public abstract class TextEdit { int size= fChildren.size(); if (size == 0) return 0; - int offset= edit.getOffset(); - int end= edit.getInclusiveEnd(); - for (int i= 0; i < size; i++) { - TextEdit other= (TextEdit)fChildren.get(i); - int childOffset= other.getOffset(); - int childEnd= other.getInclusiveEnd(); - // make sure that a duplicate insertion point at the same offet is inserted last - if (offset > childEnd || (offset == childOffset && edit.getLength() == 0 && other.getLength() == 0)) - continue; - if (end < childOffset) - return i; - throw new MalformedTreeException(this, edit, TextEditMessages.getString("TextEdit.overlapping")); //$NON-NLS-1$ + TextEdit last= (TextEdit)fChildren.get(size - 1); + if (last.getExclusiveEnd() <= edit.getOffset()) + return size; + try { + return -Collections.binarySearch(fChildren, edit,INSERTION_COMPARATOR) -1; + } catch(MalformedTreeException e) { + e.setParent(this); + throw e; } - return size; } //---- Offset & Length updating ------------------------------------------------- @@ -634,96 +673,81 @@ public abstract class TextEdit { fLength= DELETED_VALUE; } - /** - * Updates all previously executed edits. This method doesn't - * have any tree iteration info object hence it has to walk - * the tree by itself. This is slower than the corresponding - * update method that takes a <code>TreeIterationInfo</code> - * object. - * - * @param event the document event describing the change - */ - /* package */ final void update(DocumentEvent event) { - checkEvent(event); - int delta= getDelta(event); - if (fParent != null) - fParent.update(delta, this); - adjustLength(this, delta); - } - - private void update(int delta, TextEdit child) { - if (fParent != null) - fParent.update(delta, this); - // We have children. Otherwise we wouldn't end here. - boolean doIt= false; - for (Iterator iter= fChildren.iterator(); iter.hasNext();) { - TextEdit edit= (TextEdit)iter.next(); - if (doIt) { - adjustOffset(edit, delta); - } else { - if (edit == child) - doIt= true; + //---- New edit processing ---------------------------------------------- + + /* package */ void traversePassOne(TextEditProcessor processor, IDocument document) { + if (fChildren != null) { + for (int i= fChildren.size() - 1; i >= 0; i--) { + TextEdit child= (TextEdit)fChildren.get(i); + child.traversePassOne(processor, document); } } + if (processor.considerEdit(this)) { + performPassOne(processor, document); + } } - /** - * Updates all previously executed edits. - * - * @param event the document event describing the change - * @param info a tree iteration info object describing the - * position of the current edit in the tree. - */ - /* package */ void update(DocumentEvent event, TreeIterationInfo info) { - checkEvent(event); - final int delta= getDelta(event); - Visitor visitor= new Visitor() { - public void visit(TextEdit edit) { - adjustOffset(edit, delta); + /* package */ void performPassOne(TextEditProcessor processor, IDocument document) { + } + + /* package */ int traversePassTwo(TextEditProcessor processor, IDocument document) throws BadLocationException { + int delta= 0; + if (fChildren != null) { + for (int i= fChildren.size() - 1; i >= 0; i--) { + TextEdit child= (TextEdit)fChildren.get(i); + delta+= child.traversePassTwo(processor, document); } - }; - info.accept(visitor); - adjustLength(this, delta); + } + if (processor.considerEdit(this)) { + if (delta != 0) + adjustLength(delta); + int r= performPassTwo(document); + if (r != 0) + adjustLength(r); + delta+= r; + } + return delta; } + /* package */ abstract int performPassTwo(IDocument document) throws BadLocationException; - private void checkEvent(DocumentEvent event) { - int eventOffset= event.getOffset(); - int eventLength= event.getLength(); - Assert.isTrue(fOffset <= eventOffset && eventOffset + eventLength <= fOffset + fLength); - } - - /* package */ void markChildrenAsDeleted() { + /* package */ int traversePassThree(TextEditProcessor processor, IDocument document, int accumulatedDelta, boolean delete) { + performPassThree(accumulatedDelta, delete); if (fChildren != null) { + boolean childDelete= delete || deleteChildren(); for (Iterator iter= fChildren.iterator(); iter.hasNext();) { - TextEdit edit= (TextEdit)iter.next(); - if (!edit.isDeleted()) { - edit.markAsDeleted(); - edit.markChildrenAsDeleted(); - } + TextEdit child= (TextEdit)iter.next(); + accumulatedDelta= child.traversePassThree(processor, document, accumulatedDelta, childDelete); } - } + } + return accumulatedDelta + fDelta; } - /* package */ static int getDelta(DocumentEvent event) { - String text= event.getText(); - return (text == null ? -event.getLength() : text.length()) - event.getLength(); + /* package */ void performPassThree(int accumulatedDelta, boolean delete) { + if (delete) + markAsDeleted(); + else + adjustOffset(accumulatedDelta); } - private static void adjustOffset(TextEdit edit, int delta) { - edit.adjustOffset(delta); - List children= edit.internalGetChildren(); - if (children != null) { - for (Iterator iter= children.iterator(); iter.hasNext();) { - adjustOffset((TextEdit)iter.next(), delta); + /* package */ abstract boolean deleteChildren(); + + /* package */ void moveTree(int delta) { + adjustOffset(delta); + if (fChildren != null) { + for (Iterator iter= fChildren.iterator(); iter.hasNext();) { + ((TextEdit)iter.next()).moveTree(delta); } } } - private static void adjustLength(TextEdit edit, int delta) { - while (edit != null) { - edit.adjustLength(delta); - edit= edit.getParent(); + /* package */ void deleteTree() { + markAsDeleted(); + if (fChildren != null) { + for (Iterator iter= fChildren.iterator(); iter.hasNext();) { + TextEdit child= (TextEdit)iter.next(); + child.deleteTree(); + } } } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/TextEditProcessor.java b/org.eclipse.text/src/org/eclipse/text/edits/TextEditProcessor.java index b6218a7c43d..1acb48c7722 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/TextEditProcessor.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/TextEditProcessor.java @@ -10,9 +10,6 @@ *******************************************************************************/ package org.eclipse.text.edits; -import java.util.Iterator; -import java.util.List; - import org.eclipse.jface.text.Assert; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; @@ -31,6 +28,7 @@ public class TextEditProcessor { private IDocument fDocument; private TextEdit fRoot; + private int fStyle; private boolean fChecked; private MalformedTreeException fException; @@ -46,13 +44,14 @@ public class TextEditProcessor { * text edit processors. Clients must not modify the edit * (e.g adding new children) any longer. */ - public TextEditProcessor(IDocument document, TextEdit root) { + public TextEditProcessor(IDocument document, TextEdit root, int style) { Assert.isNotNull(document); Assert.isNotNull(root); fDocument= document; fRoot= root; if (fRoot instanceof MultiTextEdit) ((MultiTextEdit)fRoot).defineRegion(0); + fStyle= style; } /** @@ -74,6 +73,17 @@ public class TextEditProcessor { } /** + * Returns the style bits of the text edit processor + * + * @return the style bits + * @see TextEdit#CREATE_UNDO + * @see TextEdit#UPDATE_POSITIONS + */ + public int getStyle() { + return fStyle; + } + + /** * Checks if the processor can execute all its edits. * * @return <code>true</code> if the edits can be executed. Return <code>false @@ -123,22 +133,11 @@ public class TextEditProcessor { //---- checking -------------------------------------------------------------------- /* package */ void checkIntegrityDo() throws MalformedTreeException { - checkIntegrity(fRoot); + fRoot.traversePassOne(this, fDocument); if (fRoot.getExclusiveEnd() > fDocument.getLength()) throw new MalformedTreeException(null, fRoot, TextEditMessages.getString("TextEditProcessor.invalid_length")); //$NON-NLS-1$ } - private static void checkIntegrity(TextEdit root) throws MalformedTreeException { - root.checkIntegrity(); - List children= root.internalGetChildren(); - if (children != null) { - for (Iterator iter= children.iterator(); iter.hasNext();) { - TextEdit edit= (TextEdit)iter.next(); - checkIntegrity(edit); - } - } - } - /* package */ void checkIntegrityUndo() { if (fRoot.getExclusiveEnd() > fDocument.getLength()) throw new MalformedTreeException(null, fRoot, TextEditMessages.getString("TextEditProcessor.invalid_length")); //$NON-NLS-1$ @@ -147,51 +146,40 @@ public class TextEditProcessor { //---- execution -------------------------------------------------------------------- /* package */ UndoEdit executeDo() throws BadLocationException { - Updater.DoUpdater updater= null; + UndoCollector collector= new UndoCollector(fRoot); try { - updater= Updater.createDoUpdater(fRoot); - fDocument.addDocumentListener(updater); - updater.push(new TextEdit[] { fRoot }); - updater.setIndex(0); - execute(fRoot, updater); - updater.storeRegion(); - return updater.undo; - } finally { - if (updater != null) - fDocument.removeDocumentListener(updater); - } - } - - private void execute(TextEdit edit, Updater.DoUpdater updater) throws BadLocationException { - if (edit.hasChildren()) { - TextEdit[] children= edit.getChildren(); - updater.push(children); - for (int i= children.length - 1; i >= 0; i--) { - updater.setIndex(i); - execute(children[i], updater); + if (createUndo()) + collector.connect(fDocument); + fRoot.traversePassTwo(this, fDocument); + if (updateRegions()) { + fRoot.traversePassThree(this, fDocument, 0, false); } - updater.pop(); - } - if (considerEdit(edit)) { - updater.setActiveEdit(edit); - edit.perform(fDocument); + } finally { + collector.disconnect(fDocument); } + return collector.undo; } /* package */ UndoEdit executeUndo() throws BadLocationException { - Updater updater= null; + UndoCollector collector= new UndoCollector(fRoot); try { - updater= Updater.createUndoUpdater(fRoot); - fDocument.addDocumentListener(updater); + if (createUndo()) + collector.connect(fDocument); TextEdit[] edits= fRoot.getChildren(); for (int i= edits.length - 1; i >= 0; i--) { - edits[i].perform(fDocument); + edits[i].performPassTwo(fDocument); } - updater.storeRegion(); - return updater.undo; } finally { - if (updater != null) - fDocument.removeDocumentListener(updater); + collector.disconnect(fDocument); } - } + return collector.undo; + } + + private boolean createUndo() { + return (fStyle & TextEdit.CREATE_UNDO) != 0; + } + + private boolean updateRegions() { + return (fStyle & TextEdit.UPDATE_REGIONS) != 0; + } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/UndoCollector.java b/org.eclipse.text/src/org/eclipse/text/edits/UndoCollector.java new file mode 100644 index 00000000000..dd4b58fa4eb --- /dev/null +++ b/org.eclipse.text/src/org/eclipse/text/edits/UndoCollector.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.text.edits; + +import org.eclipse.jface.text.Assert; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentListener; + + +/* package */ class UndoCollector implements IDocumentListener { + + protected UndoEdit undo; + private int fOffset; + private int fLength; + + public UndoCollector(TextEdit root) { + fOffset= root.getOffset(); + fLength= root.getLength(); + } + + public void connect(IDocument document) { + document.addDocumentListener(this); + undo= new UndoEdit(); + } + + public void disconnect(IDocument document) { + if (undo != null) { + document.removeDocumentListener(this); + undo.defineRegion(fOffset, fLength); + } + } + + public void documentChanged(DocumentEvent event) { + fLength+= getDelta(event); + } + + private static int getDelta(DocumentEvent event) { + String text= event.getText(); + return (text == null ? -event.getLength() : text.length()) - event.getLength(); + } + + public void documentAboutToBeChanged(DocumentEvent event) { + int offset= event.getOffset(); + int currentLength= event.getLength(); + String currentText= null; + try { + currentText= event.getDocument().get(offset, currentLength); + } catch (BadLocationException cannotHappen) { + Assert.isTrue(false, "Can't happen"); //$NON-NLS-1$ + } + + undo.add(new ReplaceEdit(offset, event.getText().length(), currentText)); + } +} diff --git a/org.eclipse.text/src/org/eclipse/text/edits/UndoEdit.java b/org.eclipse.text/src/org/eclipse/text/edits/UndoEdit.java index ee5f0575648..40faa16dba9 100644 --- a/org.eclipse.text/src/org/eclipse/text/edits/UndoEdit.java +++ b/org.eclipse.text/src/org/eclipse/text/edits/UndoEdit.java @@ -69,9 +69,9 @@ public final class UndoEdit extends TextEdit { /* (non-Javadoc) * @see org.eclipse.text.edits.TextEdit#perform(org.eclipse.jface.text.IDocument) */ - void perform(IDocument document) throws BadLocationException { - // do nothing. Only the children modify the - // document + /* package */ int performPassTwo(IDocument document) throws BadLocationException { + fDelta= 0; + return fDelta; } /* package */ void add(ReplaceEdit edit) { @@ -87,5 +87,9 @@ public final class UndoEdit extends TextEdit { internalSetOffset(offset); internalSetLength(length); } + + /* package */ boolean deleteChildren() { + return false; + } } diff --git a/org.eclipse.text/src/org/eclipse/text/edits/Updater.java b/org.eclipse.text/src/org/eclipse/text/edits/Updater.java deleted file mode 100644 index 45887593d86..00000000000 --- a/org.eclipse.text/src/org/eclipse/text/edits/Updater.java +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2003 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.text.edits; - -import org.eclipse.jface.text.Assert; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.DocumentEvent; -import org.eclipse.jface.text.IDocumentListener; - - -/* package */ abstract class Updater implements IDocumentListener { - - protected UndoEdit undo= new UndoEdit(); - - public static Updater createUndoUpdater(TextEdit root) { - return new UndoUpdater(root); - } - - public static DoUpdater createDoUpdater(TextEdit root) { - return new DoUpdater(root); - } - - public static class DoUpdater extends Updater { - private TextEdit fRoot; - private TextEdit fActiveEdit; - private TreeIterationInfo fIterationInfo= new TreeIterationInfo(); - - public DoUpdater(TextEdit root) { - fRoot= root; - } - public void push(TextEdit[] edits) { - fIterationInfo.push(edits); - } - public void setIndex(int index) { - fIterationInfo.setIndex(index); - } - public void pop() { - fIterationInfo.pop(); - } - public void setActiveEdit(TextEdit edit) { - fActiveEdit= edit; - } - public void documentChanged(DocumentEvent event) { - fActiveEdit.update(event, fIterationInfo); - } - public void storeRegion() { - undo.defineRegion(fRoot.getOffset(), fRoot.getLength()); - } - } - - public static class UndoUpdater extends Updater { - private int fOffset; - private int fLength; - private UndoUpdater(TextEdit root) { - fOffset= root.getOffset(); - fLength= root.getLength(); - } - public void documentChanged(DocumentEvent event) { - fLength+= TextEdit.getDelta(event); - } - public void storeRegion() { - undo.defineRegion(fOffset, fLength); - } - } - - protected Updater() { - } - - public void documentAboutToBeChanged(DocumentEvent event) { - int offset= event.getOffset(); - int currentLength= event.getLength(); - String currentText= null; - try { - currentText= event.getDocument().get(offset, currentLength); - } catch (BadLocationException cannotHappen) { - Assert.isTrue(false, "Can't happen"); //$NON-NLS-1$ - } - - undo.add(new ReplaceEdit(offset, event.getText().length(), currentText)); - } - - public void documentChanged(DocumentEvent event) { - } - - public abstract void storeRegion(); -} |