Search in sources :

Example 1 with ChangeInfo

use of com.intellij.pom.tree.events.ChangeInfo in project intellij-community by JetBrains.

the class XmlAspectImpl method update.

@Override
public void update(PomModelEvent event) {
    if (!event.getChangedAspects().contains(myTreeAspect))
        return;
    final TreeChangeEvent changeSet = (TreeChangeEvent) event.getChangeSet(myTreeAspect);
    if (changeSet == null)
        return;
    final ASTNode rootElement = changeSet.getRootElement();
    final PsiFile file = (PsiFile) rootElement.getPsi();
    if (!(file instanceof XmlFile))
        return;
    final XmlAspectChangeSetImpl xmlChangeSet = event.registerChangeSetIfAbsent(this, new XmlAspectChangeSetImpl(myModel));
    xmlChangeSet.addChangedFile((XmlFile) file);
    final ASTNode[] changedElements = changeSet.getChangedElements();
    final CharTable table = ((FileElement) changeSet.getRootElement()).getCharTable();
    for (ASTNode changedElement : changedElements) {
        TreeChange changesByElement = changeSet.getChangesByElement(changedElement);
        PsiElement psiElement = null;
        while (changedElement != null && (psiElement = changedElement.getPsi()) == null) {
            final ASTNode parent = changedElement.getTreeParent();
            final ChangeInfoImpl changeInfo = ChangeInfoImpl.create(ChangeInfo.CONTENTS_CHANGED, changedElement);
            changeInfo.compactChange(changesByElement);
            changesByElement = new TreeChangeImpl(parent);
            changesByElement.addChange(changedElement, changeInfo);
            changedElement = parent;
        }
        if (changedElement == null)
            continue;
        final TreeChange finalChangedElement = changesByElement;
        psiElement.accept(new XmlElementVisitor() {

            TreeChange myChange = finalChangedElement;

            @Override
            public void visitElement(PsiElement element) {
                final ASTNode child = element.getNode();
                final ASTNode treeParent = child.getTreeParent();
                if (treeParent == null)
                    return;
                final PsiElement parent = treeParent.getPsi();
                final ChangeInfoImpl changeInfo = ChangeInfoImpl.create(ChangeInfo.CONTENTS_CHANGED, child);
                changeInfo.compactChange(myChange);
                myChange = new TreeChangeImpl(treeParent);
                myChange.addChange(child, changeInfo);
                parent.accept(this);
            }

            @Override
            public void visitXmlAttribute(XmlAttribute attribute) {
                final ASTNode[] affectedChildren = myChange.getAffectedChildren();
                String oldName = null;
                String oldValue = null;
                for (final ASTNode treeElement : affectedChildren) {
                    final ChangeInfo changeByChild = myChange.getChangeByChild(treeElement);
                    final int changeType = changeByChild.getChangeType();
                    if (treeElement.getElementType() == XmlTokenType.XML_NAME) {
                        if (changeType == ChangeInfo.REMOVED) {
                            oldName = treeElement.getText();
                        } else if (changeType == ChangeInfo.REPLACE) {
                            oldName = ((ReplaceChangeInfo) changeByChild).getReplaced().getText();
                        }
                    }
                    if (treeElement.getElementType() == XmlElementType.XML_ATTRIBUTE_VALUE) {
                        if (changeType == ChangeInfo.REMOVED) {
                            oldValue = treeElement.getText();
                        } else if (changeType == ChangeInfo.REPLACE) {
                            oldValue = ((ReplaceChangeInfo) changeByChild).getReplaced().getText();
                        }
                    }
                }
                if (oldName != null && !oldName.equals(attribute.getName())) {
                    xmlChangeSet.add(new XmlAttributeSetImpl(attribute.getParent(), oldName, null));
                    xmlChangeSet.add(new XmlAttributeSetImpl(attribute.getParent(), attribute.getName(), attribute.getValue()));
                } else if (oldValue != null) {
                    xmlChangeSet.add(new XmlAttributeSetImpl(attribute.getParent(), attribute.getName(), attribute.getValue()));
                } else {
                    xmlChangeSet.add(new XmlElementChangedImpl(attribute));
                }
            }

            @Override
            public void visitXmlTag(XmlTag tag) {
                ASTNode[] affectedChildren = shortenChange(myChange.getAffectedChildren(), changeSet);
                for (final ASTNode treeElement : affectedChildren) {
                    if (!(treeElement.getPsi() instanceof XmlTagChild)) {
                        visitElement(tag);
                        return;
                    }
                }
                for (final ASTNode treeElement : affectedChildren) {
                    final ChangeInfo changeByChild = myChange.getChangeByChild(treeElement);
                    final int changeType = changeByChild.getChangeType();
                    final IElementType type = treeElement.getElementType();
                    if (type == TokenType.WHITE_SPACE)
                        continue;
                    /*
            if (type == ElementType.XML_NAME) {
              final XmlToken xmlToken = (XmlToken)((ReplaceChangeInfo)changeByChild).getReplaced();
              xmlChangeSet.add(new XmlTagNameChangedImpl(tag, xmlToken.getText()));
              continue;
            }
            */
                    final PsiElement element = treeElement.getPsi();
                    switch(changeType) {
                        case ChangeInfo.ADD:
                            xmlChangeSet.add(new XmlTagChildAddImpl(tag, (XmlTagChild) element));
                            break;
                        case ChangeInfo.REMOVED:
                            treeElement.putUserData(CharTable.CHAR_TABLE_KEY, table);
                            xmlChangeSet.add(new XmlTagChildRemovedImpl(tag, (XmlTagChild) element));
                            break;
                        case ChangeInfo.CONTENTS_CHANGED:
                            xmlChangeSet.add(new XmlTagChildChangedImpl(tag, (XmlTagChild) element));
                            break;
                        case ChangeInfo.REPLACE:
                            final PsiElement psi = ((ReplaceChangeInfo) changeByChild).getReplaced().getPsi();
                            if (psi instanceof XmlTagChild) {
                                final XmlTagChild replaced = (XmlTagChild) psi;
                                replaced.putUserData(CharTable.CHAR_TABLE_KEY, table);
                                xmlChangeSet.add(new XmlTagChildRemovedImpl(tag, replaced));
                                xmlChangeSet.add(new XmlTagChildAddImpl(tag, (XmlTagChild) element));
                            }
                            break;
                    }
                }
            }

            @Override
            public void visitXmlDocument(XmlDocument document) {
                xmlChangeSet.clear();
                xmlChangeSet.add(new XmlDocumentChangedImpl(document));
            }

            @Override
            public void visitFile(PsiFile file) {
                final XmlDocument document = ((XmlFile) file).getDocument();
                if (document != null) {
                    xmlChangeSet.clear();
                    xmlChangeSet.add(new XmlDocumentChangedImpl(document));
                }
            }
        });
    }
}
Also used : TreeChangeEvent(com.intellij.pom.tree.events.TreeChangeEvent) ChangeInfoImpl(com.intellij.pom.tree.events.impl.ChangeInfoImpl) CharTable(com.intellij.util.CharTable) ASTNode(com.intellij.lang.ASTNode) PsiFile(com.intellij.psi.PsiFile) PsiElement(com.intellij.psi.PsiElement) XmlElementVisitor(com.intellij.psi.XmlElementVisitor) ReplaceChangeInfo(com.intellij.pom.tree.events.ReplaceChangeInfo) TreeChangeImpl(com.intellij.pom.tree.events.impl.TreeChangeImpl) ReplaceChangeInfo(com.intellij.pom.tree.events.ReplaceChangeInfo) ChangeInfo(com.intellij.pom.tree.events.ChangeInfo) IElementType(com.intellij.psi.tree.IElementType) TreeChange(com.intellij.pom.tree.events.TreeChange) FileElement(com.intellij.psi.impl.source.tree.FileElement)

Example 2 with ChangeInfo

use of com.intellij.pom.tree.events.ChangeInfo in project intellij-community by JetBrains.

the class TreeChangeImpl method add.

@Override
public void add(@NotNull final TreeChange value) {
    final TreeChangeImpl impl = (TreeChangeImpl) value;
    LOG.assertTrue(impl.myParent == myParent);
    for (final Pair<ASTNode, Integer> pair : impl.mySortedChanges) {
        final ASTNode child = pair.getFirst();
        ChangeInfo change = impl.myChanges.get(child);
        if (change.getChangeType() == ChangeInfo.REMOVED) {
            final ChangeInfo oldChange = myChanges.get(child);
            if (oldChange != null) {
                switch(oldChange.getChangeType()) {
                    case ChangeInfo.ADD:
                        removeChangeInternal(child);
                        break;
                    case ChangeInfo.REPLACE:
                        final ASTNode replaced = ((ReplaceChangeInfo) oldChange).getReplaced();
                        removeChangeInternal(child);
                        myChanges.put(replaced, ChangeInfoImpl.create(ChangeInfo.REMOVED, replaced));
                        addChangeAtOffset(replaced, getOldOffset(pair.getSecond().intValue()));
                        break;
                    case ChangeInfo.CONTENTS_CHANGED:
                        ((ChangeInfoImpl) change).setOldLength(oldChange.getOldLength());
                        myChanges.put(child, change);
                        break;
                }
            } else {
                myChanges.put(child, change);
                addChangeAtOffset(child, getOldOffset(pair.getSecond().intValue()));
            }
        } else if (change.getChangeType() == ChangeInfo.REPLACE) {
            ReplaceChangeInfo replaceChangeInfo = (ReplaceChangeInfo) change;
            final ASTNode replaced = replaceChangeInfo.getReplaced();
            final ChangeInfo oldChange = myChanges.get(replaced);
            if (oldChange != null) {
                switch(oldChange.getChangeType()) {
                    case ChangeInfo.ADD:
                        change = ChangeInfoImpl.create(ChangeInfo.ADD, child);
                        break;
                    case ChangeInfo.CONTENTS_CHANGED:
                        ((ChangeInfoImpl) change).setOldLength(oldChange.getOldLength());
                        break;
                    case ChangeInfo.REPLACE:
                        final ASTNode oldReplaced = ((ReplaceChangeInfo) oldChange).getReplaced();
                        ReplaceChangeInfoImpl rep = new ReplaceChangeInfoImpl(child);
                        rep.setReplaced(oldReplaced);
                        change = rep;
                        break;
                }
                removeChangeInternal(replaced);
            }
            addChange(child, change);
        } else {
            addChange(child, change);
        }
    }
}
Also used : ReplaceChangeInfo(com.intellij.pom.tree.events.ReplaceChangeInfo) ChangeInfo(com.intellij.pom.tree.events.ChangeInfo) ReplaceChangeInfo(com.intellij.pom.tree.events.ReplaceChangeInfo) ASTNode(com.intellij.lang.ASTNode)

Example 3 with ChangeInfo

use of com.intellij.pom.tree.events.ChangeInfo in project intellij-community by JetBrains.

the class TreeChangeImpl method getOptimizedNodeOldOffset.

private int getOptimizedNodeOldOffset(ASTNode child, ChangeInfo changeInfo) {
    // we usually add / remove ranges so old offset can be tried to calculate from change with previous sibling
    ASTNode prevSibling = child.getTreePrev();
    if (prevSibling != null) {
        if (mySortedChanges.size() > 0) {
            Pair<ASTNode, Integer> pair = mySortedChanges.get(mySortedChanges.size() - 1);
            if (pair.getFirst() == prevSibling) {
                ChangeInfo prevSiblingChange = myChanges.get(prevSibling);
                if ((prevSiblingChange.getChangeType() == ChangeInfo.REMOVED && changeInfo.getChangeType() == ChangeInfo.REMOVED) || (prevSiblingChange.getChangeType() == ChangeInfo.ADD && changeInfo.getChangeType() == ChangeInfo.ADD)) {
                    int optimizedResult = pair.getSecond() + prevSiblingChange.getOldLength();
                    if (ourDoChecks && !ourReportedDifferentOptimizedNodeOldOffset) {
                        int oldOffset = calculateOldOffsetLinearly(child);
                        if (optimizedResult != oldOffset) {
                            LOG.error("Failed optimized node old offset check:" + changeInfo + ", previous:" + prevSibling + "," + prevSiblingChange);
                            ourReportedDifferentOptimizedNodeOldOffset = true;
                            optimizedResult = oldOffset;
                        }
                    }
                    return optimizedResult;
                }
            }
        }
    }
    return haveNotCalculated;
}
Also used : ChangeInfo(com.intellij.pom.tree.events.ChangeInfo) ReplaceChangeInfo(com.intellij.pom.tree.events.ReplaceChangeInfo) ASTNode(com.intellij.lang.ASTNode)

Example 4 with ChangeInfo

use of com.intellij.pom.tree.events.ChangeInfo in project intellij-community by JetBrains.

the class TreeChangeImpl method getOldOffset.

private int getOldOffset(int offset) {
    for (Pair<ASTNode, Integer> pair : mySortedChanges) {
        if (pair.getSecond() > offset)
            break;
        final ChangeInfo change = myChanges.get(pair.getFirst());
        offset += change.getOldLength() - getNewLength(change, pair.getFirst());
    }
    return offset;
}
Also used : ChangeInfo(com.intellij.pom.tree.events.ChangeInfo) ReplaceChangeInfo(com.intellij.pom.tree.events.ReplaceChangeInfo) ASTNode(com.intellij.lang.ASTNode)

Example 5 with ChangeInfo

use of com.intellij.pom.tree.events.ChangeInfo in project intellij-community by JetBrains.

the class TreeChangeImpl method addChange.

@Override
public void addChange(ASTNode child, @NotNull ChangeInfo changeInfo) {
    LOG.assertTrue(child.getTreeParent() == myParent);
    final ChangeInfo current = myChanges.get(child);
    if (current != null && changeInfo.getChangeType() == ChangeInfo.CONTENTS_CHANGED) {
        return;
    }
    if (changeInfo.getChangeType() == ChangeInfo.REPLACE) {
        final ReplaceChangeInfoImpl replaceChangeInfo = (ReplaceChangeInfoImpl) changeInfo;
        final ASTNode replaced = replaceChangeInfo.getReplaced();
        final ChangeInfo replacedInfo = myChanges.get(replaced);
        if (replacedInfo == null) {
            addChangeInternal(child, changeInfo);
        } else {
            switch(replacedInfo.getChangeType()) {
                case ChangeInfo.REPLACE:
                    replaceChangeInfo.setOldLength(replacedInfo.getOldLength());
                    replaceChangeInfo.setReplaced(((ReplaceChangeInfo) replacedInfo).getReplaced());
                    break;
                case ChangeInfo.ADD:
                    changeInfo = ChangeInfoImpl.create(ChangeInfo.ADD, replaced);
                    removeChangeInternal(replaced);
                    break;
            }
            addChangeInternal(child, changeInfo);
        }
        return;
    }
    if (current != null && current.getChangeType() == ChangeInfo.REMOVED) {
        if (changeInfo.getChangeType() == ChangeInfo.ADD) {
            if (!(child instanceof LeafElement)) {
                // remove/add -> changed
                changeInfo = ChangeInfoImpl.create(ChangeInfo.CONTENTS_CHANGED, child);
                ((ChangeInfoImpl) changeInfo).setOldLength(current.getOldLength());
                myChanges.put(child, changeInfo);
            } else {
                removeChangeInternal(child);
            }
        }
        return;
    }
    // add + remove == no op
    if (current != null && current.getChangeType() == ChangeInfo.ADD) {
        if (changeInfo.getChangeType() == ChangeInfo.REMOVED) {
            removeChangeInternal(child);
        }
        return;
    }
    if (changeInfo.getChangeType() == ChangeInfo.REMOVED) {
        if (child instanceof LeafElement) {
            final CharSequence charTabIndex = child.getChars();
            if (checkLeaf(child.getTreeNext(), charTabIndex) || checkLeaf(child.getTreePrev(), charTabIndex))
                return;
        }
        addChangeInternal(child, changeInfo);
        if (current != null) {
            ((ChangeInfoImpl) changeInfo).setOldLength(current.getOldLength());
        }
        return;
    }
    if (current == null) {
        addChangeInternal(child, changeInfo);
    }
}
Also used : ChangeInfo(com.intellij.pom.tree.events.ChangeInfo) ReplaceChangeInfo(com.intellij.pom.tree.events.ReplaceChangeInfo) ASTNode(com.intellij.lang.ASTNode) LeafElement(com.intellij.psi.impl.source.tree.LeafElement)

Aggregations

ASTNode (com.intellij.lang.ASTNode)13 ChangeInfo (com.intellij.pom.tree.events.ChangeInfo)13 ReplaceChangeInfo (com.intellij.pom.tree.events.ReplaceChangeInfo)11 TreeChange (com.intellij.pom.tree.events.TreeChange)3 ChangeInfoImpl (com.intellij.pom.tree.events.impl.ChangeInfoImpl)2 TreeChangeImpl (com.intellij.pom.tree.events.impl.TreeChangeImpl)2 PsiElement (com.intellij.psi.PsiElement)2 PsiFile (com.intellij.psi.PsiFile)2 Pair (com.intellij.openapi.util.Pair)1 TreeChangeEvent (com.intellij.pom.tree.events.TreeChangeEvent)1 XmlElementVisitor (com.intellij.psi.XmlElementVisitor)1 PsiManagerImpl (com.intellij.psi.impl.PsiManagerImpl)1 PsiTreeChangeEventImpl (com.intellij.psi.impl.PsiTreeChangeEventImpl)1 FileElement (com.intellij.psi.impl.source.tree.FileElement)1 LeafElement (com.intellij.psi.impl.source.tree.LeafElement)1 TreeElement (com.intellij.psi.impl.source.tree.TreeElement)1 IElementType (com.intellij.psi.tree.IElementType)1 CharTable (com.intellij.util.CharTable)1 THashMap (gnu.trove.THashMap)1