blob: 4055b9cffb9f191634d75c2a96e6cabe7602cb66 [file] [log] [blame]
package com.intellij.xml.arrangement;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.XmlElementVisitor;
import com.intellij.psi.codeStyle.arrangement.DefaultArrangementEntry;
import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.XML_ATTRIBUTE;
import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.XML_TAG;
/**
* @author Eugene.Kudelevsky
*/
public class XmlArrangementVisitor extends XmlElementVisitor {
private final Stack<XmlElementArrangementEntry> myStack = new Stack<XmlElementArrangementEntry>();
private final XmlArrangementParseInfo myInfo;
private final Collection<TextRange> myRanges;
public XmlArrangementVisitor(@NotNull XmlArrangementParseInfo info, @NotNull Collection<TextRange> ranges) {
myInfo = info;
myRanges = ranges;
}
@Override
public void visitXmlFile(XmlFile file) {
final XmlTag tag = file.getRootTag();
if (tag != null) {
tag.accept(this);
}
}
@Override
public void visitXmlTag(XmlTag tag) {
final XmlElementArrangementEntry entry = createNewEntry(
tag.getTextRange(), XML_TAG, null, null, true);
processEntry(entry, tag);
}
@Override
public void visitXmlAttribute(XmlAttribute attribute) {
final XmlElementArrangementEntry entry = createNewEntry(
attribute.getTextRange(), XML_ATTRIBUTE, attribute.getName(), attribute.getNamespace(), true);
processEntry(entry, null);
}
private void processEntry(@Nullable XmlElementArrangementEntry entry, @Nullable PsiElement nextElement) {
if (entry == null || nextElement == null) {
return;
}
myStack.push(entry);
try {
nextElement.acceptChildren(this);
}
finally {
myStack.pop();
}
}
@Nullable
private XmlElementArrangementEntry createNewEntry(@NotNull TextRange range,
@NotNull ArrangementSettingsToken type,
@Nullable String name,
@Nullable String namespace,
boolean canBeMatched) {
if (range.getStartOffset() == 0 && range.getEndOffset() == 0 || !isWithinBounds(range)) {
return null;
}
final DefaultArrangementEntry current = getCurrent();
final XmlElementArrangementEntry entry = new XmlElementArrangementEntry(
current, range, type, name, namespace, canBeMatched);
if (current == null) {
myInfo.addEntry(entry);
}
else {
current.addChild(entry);
}
return entry;
}
@Nullable
private DefaultArrangementEntry getCurrent() {
return myStack.isEmpty() ? null : myStack.peek();
}
private boolean isWithinBounds(@NotNull TextRange range) {
for (TextRange textRange : myRanges) {
if (textRange.intersects(range)) {
return true;
}
}
return false;
}
}