diff options
Diffstat (limited to 'core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/TextEditUtil.java')
-rw-r--r-- | core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/TextEditUtil.java | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/TextEditUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/TextEditUtil.java new file mode 100644 index 00000000000..3b5b2b6f5b1 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/TextEditUtil.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright (c) 2007, 2012 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Sergey Prigogin (Google) + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.rewrite.changegenerator; + +import org.eclipse.text.edits.CopyTargetEdit; +import org.eclipse.text.edits.DeleteEdit; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.MalformedTreeException; +import org.eclipse.text.edits.MoveSourceEdit; +import org.eclipse.text.edits.MoveTargetEdit; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.ReplaceEdit; +import org.eclipse.text.edits.TextEdit; + +public class TextEditUtil { + // Do not instantiate. All methods are static. + private TextEditUtil() { + } + + /** + * Degenerates the given edit tree into a list.<br> + * All nodes of the result are leafs.<br> + * <strong>The given edit is modified and can no longer be used.</strong> + * + * @param edit the edit tree to flatten + * @return a MultiTextEdit containing the list of edits + */ + public static MultiTextEdit flatten(TextEdit edit) { + MultiTextEdit result= new MultiTextEdit(); + flatten(edit, result); + return result; + } + + private static void flatten(TextEdit edit, MultiTextEdit result) { + if (edit.hasChildren()) { + TextEdit[] children= edit.getChildren(); + for (int i= 0; i < children.length; i++) { + TextEdit child= children[i]; + child.getParent().removeChild(0); + flatten(child, result); + } + } else if (!(edit instanceof MultiTextEdit)) { + result.addChild(edit); + } + } + + /** + * Create an edit which contains <code>edit1</code> and <code>edit2</code> + * <p><strong>The given edits are modified and they can no longer be used.</strong></p> + * + * @param edit1 the edit to merge with edit2 + * @param edit2 the edit to merge with edit1 + * @return the merged tree + * @throws MalformedTreeException if the two edits ovelap + */ + public static TextEdit merge(TextEdit edit1, TextEdit edit2) { + if (edit1 instanceof MultiTextEdit && !edit1.hasChildren()) { + return edit2; + } + + if (edit2 instanceof MultiTextEdit && !edit2.hasChildren()) { + return edit1; + } + + MultiTextEdit result= new MultiTextEdit(); + merge(edit1, edit2, result); + return result; + } + + private static void merge(TextEdit edit1, TextEdit edit2, MultiTextEdit result) { + if (edit1 instanceof MultiTextEdit && edit2 instanceof MultiTextEdit) { + MultiTextEdit multiTextEdit1= (MultiTextEdit) edit1; + if (!multiTextEdit1.hasChildren()) { + result.addChild(edit2); + return; + } + + MultiTextEdit multiTextEdit2= (MultiTextEdit) edit2; + if (!multiTextEdit2.hasChildren()) { + result.addChild(edit1); + return; + } + + TextEdit[] children1= multiTextEdit1.getChildren(); + TextEdit[] children2= multiTextEdit2.getChildren(); + + int i1= 0; + int i2= 0; + while (i1 < children1.length && i2 < children2.length) { + while (i1 < children1.length && children1[i1].getExclusiveEnd() < children2[i2].getOffset()) { + edit1.removeChild(0); + result.addChild(children1[i1]); + i1++; + } + if (i1 >= children1.length) + break; + + while (i2 < children2.length && children2[i2].getExclusiveEnd() < children1[i1].getOffset()) { + edit2.removeChild(0); + result.addChild(children2[i2]); + i2++; + } + if (i2 >= children2.length) + break; + + if (children1[i1].getExclusiveEnd() < children2[i2].getOffset()) + continue; + + edit1.removeChild(0); + edit2.removeChild(0); + merge(children1[i1], children2[i2], result); + + i1++; + i2++; + } + + while (i1 < children1.length) { + edit1.removeChild(0); + result.addChild(children1[i1]); + i1++; + } + + while (i2 < children2.length) { + edit2.removeChild(0); + result.addChild(children2[i2]); + i2++; + } + } else if (edit1 instanceof MultiTextEdit) { + TextEdit[] children= edit1.getChildren(); + + int i= 0; + while (children[i].getExclusiveEnd() < edit2.getOffset()) { + edit1.removeChild(0); + result.addChild(children[i]); + i++; + if (i >= children.length) { + result.addChild(edit2); + return; + } + } + edit1.removeChild(0); + merge(children[i], edit2, result); + i++; + while (i < children.length) { + edit1.removeChild(0); + result.addChild(children[i]); + i++; + } + } else if (edit2 instanceof MultiTextEdit) { + TextEdit[] children= edit2.getChildren(); + + int i= 0; + while (children[i].getExclusiveEnd() < edit1.getOffset()) { + edit2.removeChild(0); + result.addChild(children[i]); + i++; + if (i >= children.length) { + result.addChild(edit1); + return; + } + } + edit2.removeChild(0); + merge(edit1, children[i], result); + i++; + while (i < children.length) { + edit2.removeChild(0); + result.addChild(children[i]); + i++; + } + } else { + if (edit1.getExclusiveEnd() < edit2.getOffset()) { + result.addChild(edit1); + result.addChild(edit2); + } else { + result.addChild(edit2); + result.addChild(edit1); + } + } + } + + /** + * Returns the difference in the document length caused by the edit. {@code InsertEdit}s have + * positive delta, {@code DeleteEdit}s have negative one. + * @param edit the edit to determine delta for. + * @return the delta + */ + public static int delta(TextEdit edit) { + int delta = 0; + for (TextEdit child : edit.getChildren()) { + delta += delta(child); + } + delta += ownDelta(edit); + return delta; + } + + private static int ownDelta(TextEdit edit) { + if (edit instanceof DeleteEdit || edit instanceof MoveSourceEdit) { + return -edit.getLength(); + } else if (edit instanceof InsertEdit) { + return ((InsertEdit) edit).getText().length(); + } else if (edit instanceof ReplaceEdit) { + return ((ReplaceEdit) edit).getText().length() - edit.getLength(); + } else if (edit instanceof CopyTargetEdit) { + return ((CopyTargetEdit) edit).getSourceEdit().getLength(); + } else if (edit instanceof MoveTargetEdit) { + return ((MoveTargetEdit) edit).getSourceEdit().getLength(); + } + return 0; + } +} |