2 * Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved.
5 package com
.intellij
.util
.xml
.highlighting
;
7 import com
.intellij
.codeInsight
.daemon
.impl
.AnnotationHolderImpl
;
8 import com
.intellij
.codeInspection
.InspectionManager
;
9 import com
.intellij
.codeInspection
.ProblemDescriptor
;
10 import com
.intellij
.codeInspection
.ProblemHighlightType
;
11 import com
.intellij
.lang
.ASTNode
;
12 import com
.intellij
.lang
.annotation
.Annotation
;
13 import com
.intellij
.lang
.annotation
.HighlightSeverity
;
14 import com
.intellij
.openapi
.editor
.colors
.CodeInsightColors
;
15 import com
.intellij
.openapi
.util
.Pair
;
16 import com
.intellij
.openapi
.util
.TextRange
;
17 import com
.intellij
.openapi
.util
.text
.StringUtil
;
18 import com
.intellij
.psi
.PsiElement
;
19 import com
.intellij
.psi
.PsiReference
;
20 import com
.intellij
.psi
.xml
.XmlAttributeValue
;
21 import com
.intellij
.psi
.xml
.XmlChildRole
;
22 import com
.intellij
.psi
.xml
.XmlTag
;
23 import com
.intellij
.psi
.xml
.XmlText
;
24 import com
.intellij
.util
.Function
;
25 import com
.intellij
.util
.SmartList
;
26 import com
.intellij
.util
.xml
.DomElement
;
27 import com
.intellij
.util
.xml
.GenericAttributeValue
;
28 import com
.intellij
.util
.xml
.GenericValue
;
29 import org
.jetbrains
.annotations
.Nullable
;
31 import java
.util
.Arrays
;
32 import java
.util
.List
;
35 * User: Sergey.Vasiliev
37 public class DomElementsHighlightingUtil
{
39 private static final AnnotationHolderImpl EMPTY_ANNOTATION_HOLDER
= new AnnotationHolderImpl() {
40 public boolean add(final Annotation annotation
) {
45 private DomElementsHighlightingUtil() {
48 public static List
<ProblemDescriptor
> createProblemDescriptors(final InspectionManager manager
,
49 final DomElementProblemDescriptor problemDescriptor
) {
50 final ProblemHighlightType type
= getProblemHighlightType(problemDescriptor
);
51 return createProblemDescriptors(problemDescriptor
, new Function
<Pair
<TextRange
, PsiElement
>, ProblemDescriptor
>() {
52 public ProblemDescriptor
fun(final Pair
<TextRange
, PsiElement
> s
) {
54 .createProblemDescriptor(s
.second
, s
.first
, problemDescriptor
.getDescriptionTemplate(), type
, problemDescriptor
.getFixes());
59 private static ProblemHighlightType
getProblemHighlightType(final DomElementProblemDescriptor problemDescriptor
) {
60 if (problemDescriptor
instanceof DomElementResolveProblemDescriptor
) {
61 final TextRange range
= ((DomElementResolveProblemDescriptor
)problemDescriptor
).getPsiReference().getRangeInElement();
62 if (range
.getStartOffset() != range
.getEndOffset()) {
63 return ProblemHighlightType
.LIKE_UNKNOWN_SYMBOL
;
66 return ProblemHighlightType
.GENERIC_ERROR_OR_WARNING
;
69 public static List
<Annotation
> createAnnotations(final DomElementProblemDescriptor problemDescriptor
) {
71 return createProblemDescriptors(problemDescriptor
, new Function
<Pair
<TextRange
, PsiElement
>, Annotation
>() {
72 public Annotation
fun(final Pair
<TextRange
, PsiElement
> s
) {
73 String text
= problemDescriptor
.getDescriptionTemplate();
74 if (StringUtil
.isEmpty(text
)) text
= null;
75 final HighlightSeverity severity
= problemDescriptor
.getHighlightSeverity();
76 final AnnotationHolderImpl holder
= EMPTY_ANNOTATION_HOLDER
;
77 TextRange range
= s
.first
;
78 if (text
== null) range
= TextRange
.from(range
.getStartOffset(), 0);
79 range
= range
.shiftRight(s
.second
.getTextRange().getStartOffset());
80 final Annotation annotation
= createAnnotation(severity
, holder
, range
, text
);
81 if (problemDescriptor
instanceof DomElementResolveProblemDescriptor
) {
82 annotation
.setTextAttributes(CodeInsightColors
.WRONG_REFERENCES_ATTRIBUTES
);
89 private static Annotation
createAnnotation(final HighlightSeverity severity
,
90 final AnnotationHolderImpl holder
,
91 final TextRange range
,
93 if (severity
.compareTo(HighlightSeverity
.ERROR
) >= 0) return holder
.createErrorAnnotation(range
, text
);
94 if (severity
.compareTo(HighlightSeverity
.WARNING
) >= 0) return holder
.createWarningAnnotation(range
, text
);
95 if (severity
.compareTo(HighlightSeverity
.INFO
) >= 0) return holder
.createInformationAnnotation(range
, text
);
96 return holder
.createInfoAnnotation(range
, text
);
99 private static <T
> List
<T
> createProblemDescriptors(final DomElementProblemDescriptor problemDescriptor
,
100 final Function
<Pair
<TextRange
, PsiElement
>, T
> creator
) {
101 final List
<T
> descriptors
= new SmartList
<T
>();
103 if (problemDescriptor
instanceof DomElementResolveProblemDescriptor
) {
104 final PsiReference reference
= ((DomElementResolveProblemDescriptor
)problemDescriptor
).getPsiReference();
105 final PsiElement element
= reference
.getElement();
106 final TextRange referenceRange
= reference
.getRangeInElement();
107 final TextRange errorRange
;
108 if (referenceRange
.getStartOffset() == referenceRange
.getEndOffset()) {
109 if (element
instanceof XmlAttributeValue
) {
110 errorRange
= TextRange
.from(referenceRange
.getStartOffset() - 1, 2);
113 errorRange
= TextRange
.from(referenceRange
.getStartOffset(), 1);
117 errorRange
= referenceRange
;
119 descriptors
.add(creator
.fun(Pair
.create(errorRange
, element
)));
123 final DomElement domElement
= problemDescriptor
.getDomElement();
124 final PsiElement psiElement
= getPsiElement(domElement
);
125 final DomElementProblemDescriptor
.HighlightingType highlightingType
= problemDescriptor
.getHighlightingType();
127 if (highlightingType
== DomElementProblemDescriptor
.HighlightingType
.WHOLE_ELEMENT
) {
128 if (psiElement
instanceof XmlAttributeValue
) {
129 final PsiElement attr
= psiElement
.getParent();
130 descriptors
.add(creator
.fun(Pair
.create(new TextRange(0, attr
.getTextLength()), attr
)));
133 final XmlTag tag
= (XmlTag
)(psiElement
instanceof XmlTag ? psiElement
: psiElement
.getParent());
134 descriptors
.add(creator
.fun(Pair
.create(new TextRange(0, tag
.getTextLength()), (PsiElement
)tag
)));
139 if (psiElement
!= null && StringUtil
.isNotEmpty(psiElement
.getText())) {
140 if (psiElement
instanceof XmlTag
) {
141 final XmlTag tag
= (XmlTag
)psiElement
;
142 switch (highlightingType
) {
144 descriptors
.add(creator
.fun(Pair
.create(new TextRange(0, tag
.getTextLength()), (PsiElement
)tag
)));
147 addDescriptionsToTagEnds(tag
, descriptors
, creator
);
155 TextRange textRange
= problemDescriptor
.getTextRange();
157 if (textRange
== null) {
159 int length
= psiElement
.getTextRange().getLength();
160 if (psiElement
instanceof XmlAttributeValue
) {
161 String value
= ((XmlAttributeValue
)psiElement
).getValue();
162 if (StringUtil
.isNotEmpty(value
)) {
163 start
= psiElement
.getText().indexOf(value
);
164 length
= value
.length();
167 textRange
= TextRange
.from(start
, length
);
169 return Arrays
.asList(creator
.fun(Pair
.create(textRange
, psiElement
)));
172 final XmlTag tag
= getParentXmlTag(domElement
);
174 addDescriptionsToTagEnds(tag
, descriptors
, creator
);
179 private static <T
> void addDescriptionsToTagEnds(final XmlTag tag
,
180 final List
<T
> descriptors
,
181 Function
<Pair
<TextRange
, PsiElement
>, T
> creator
) {
182 final ASTNode node
= tag
.getNode();
184 final ASTNode startNode
= XmlChildRole
.START_TAG_NAME_FINDER
.findChild(node
);
186 final int startOffset
= tag
.getTextRange().getStartOffset();
187 assert startNode
!= null;
188 descriptors
.add(creator
.fun(Pair
.create(startNode
.getTextRange().shiftRight(-startOffset
), (PsiElement
)tag
)));
192 private static PsiElement
getPsiElement(final DomElement domElement
) {
193 if (domElement
instanceof GenericAttributeValue
) {
194 final GenericAttributeValue attributeValue
= (GenericAttributeValue
)domElement
;
195 final XmlAttributeValue value
= attributeValue
.getXmlAttributeValue();
196 return value
!= null && StringUtil
.isNotEmpty(value
.getText()) ? value
: attributeValue
.getXmlElement();
198 final XmlTag tag
= domElement
.getXmlTag();
199 if (domElement
instanceof GenericValue
&& tag
!= null) {
200 final XmlText
[] textElements
= tag
.getValue().getTextElements();
201 if (textElements
.length
> 0) {
202 return textElements
[0];
210 private static XmlTag
getParentXmlTag(final DomElement domElement
) {
211 DomElement parent
= domElement
.getParent();
212 while (parent
!= null) {
213 if (parent
.getXmlTag() != null) return parent
.getXmlTag();
214 parent
= parent
.getParent();