1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
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;
}
}
|