All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.pom.xml.impl.XmlAspectImpl Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition xml-psi-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.pom.xml.impl;

import com.intellij.lang.ASTNode;
import com.intellij.pom.PomModel;
import com.intellij.pom.PomModelAspect;
import com.intellij.pom.event.PomModelEvent;
import com.intellij.pom.tree.TreeAspect;
import com.intellij.pom.tree.events.ChangeInfo;
import com.intellij.pom.tree.events.ReplaceChangeInfo;
import com.intellij.pom.tree.events.TreeChange;
import com.intellij.pom.tree.events.TreeChangeEvent;
import com.intellij.pom.tree.events.impl.ChangeInfoImpl;
import com.intellij.pom.tree.events.impl.TreeChangeImpl;
import com.intellij.pom.xml.XmlAspect;
import com.intellij.pom.xml.impl.events.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.TokenType;
import com.intellij.psi.XmlElementVisitor;
import com.intellij.psi.impl.source.tree.FileElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.xml.*;
import com.intellij.util.CharTable;

import java.util.Collections;

public class XmlAspectImpl implements XmlAspect {
  private final PomModel myModel;
  private final TreeAspect myTreeAspect;

  public XmlAspectImpl(PomModel model, TreeAspect aspect) {
    myModel = model;
    myTreeAspect = aspect;
    myModel.registerAspect(XmlAspect.class, this, Collections.singleton((PomModelAspect)myTreeAspect));
  }

  @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) {
            /*final IElementType type = treeElement.getElementType();
            if (type == ElementType.WHITE_SPACE) continue;
            if (type == ElementType.XML_NAME) {
              if (myChange.getChangeByChild(treeElement).getChangeType() == ChangeInfo.REPLACE) {
                continue;
              }
            }*/

            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));
          }
        }
      });
    }
  }

  private ASTNode[] shortenChange(ASTNode[] affectedChildren, TreeChangeEvent event) {
    // TODO
    return affectedChildren;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy