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
{
38 private static final AnnotationHolderImpl EMPTY_ANNOTATION_HOLDER
= new AnnotationHolderImpl() {
39 public boolean add(final Annotation annotation
) {
44 public static List
<ProblemDescriptor
> createProblemDescriptors(final InspectionManager manager
, final DomElementProblemDescriptor problemDescriptor
) {
45 final ProblemHighlightType type
= getProblemHighlightType(problemDescriptor
);
46 return createProblemDescriptors(problemDescriptor
, new Function
<Pair
<TextRange
, PsiElement
>, ProblemDescriptor
>() {
47 public ProblemDescriptor
fun(final Pair
<TextRange
, PsiElement
> s
) {
48 return manager
.createProblemDescriptor(s
.second
, s
.first
, problemDescriptor
.getDescriptionTemplate(), type
, problemDescriptor
.getFixes());
53 private static ProblemHighlightType
getProblemHighlightType(final DomElementProblemDescriptor problemDescriptor
) {
54 if (problemDescriptor
instanceof DomElementResolveProblemDescriptor
) {
55 final TextRange range
= ((DomElementResolveProblemDescriptor
)problemDescriptor
).getPsiReference().getRangeInElement();
56 if (range
.getStartOffset() != range
.getEndOffset()) {
57 return ProblemHighlightType
.LIKE_UNKNOWN_SYMBOL
;
60 return ProblemHighlightType
.GENERIC_ERROR_OR_WARNING
;
63 public static List
<Annotation
> createAnnotations(final DomElementProblemDescriptor problemDescriptor
) {
65 return createProblemDescriptors(problemDescriptor
, new Function
<Pair
<TextRange
, PsiElement
>, Annotation
>() {
66 public Annotation
fun(final Pair
<TextRange
, PsiElement
> s
) {
67 String text
= problemDescriptor
.getDescriptionTemplate();
68 if (StringUtil
.isEmpty(text
)) text
= null;
69 final HighlightSeverity severity
= problemDescriptor
.getHighlightSeverity();
70 final AnnotationHolderImpl holder
= EMPTY_ANNOTATION_HOLDER
;
71 TextRange range
= s
.first
;
72 if (text
== null) range
= TextRange
.from(range
.getStartOffset(), 0);
73 range
= range
.shiftRight(s
.second
.getTextRange().getStartOffset());
74 final Annotation annotation
= createAnnotation(severity
, holder
, range
, text
);
75 if (problemDescriptor
instanceof DomElementResolveProblemDescriptor
) {
76 annotation
.setTextAttributes(CodeInsightColors
.WRONG_REFERENCES_ATTRIBUTES
);
83 private static Annotation
createAnnotation(final HighlightSeverity severity
, final AnnotationHolderImpl holder
, final TextRange range
,
85 if (severity
.compareTo(HighlightSeverity
.ERROR
) >= 0) return holder
.createErrorAnnotation(range
, text
);
86 if (severity
.compareTo(HighlightSeverity
.WARNING
) >= 0) return holder
.createWarningAnnotation(range
, text
);
87 if (severity
.compareTo(HighlightSeverity
.INFO
) >= 0) return holder
.createInformationAnnotation(range
, text
);
88 return holder
.createInfoAnnotation(range
, text
);
91 private static <T
> List
<T
> createProblemDescriptors(final DomElementProblemDescriptor problemDescriptor
, final Function
<Pair
<TextRange
, PsiElement
>, T
> creator
) {
92 final List
<T
> descritors
= new SmartList
<T
>();
94 if (problemDescriptor
instanceof DomElementResolveProblemDescriptor
) {
95 final PsiReference reference
= ((DomElementResolveProblemDescriptor
)problemDescriptor
).getPsiReference();
96 final PsiElement element
= reference
.getElement();
97 final TextRange referenceRange
= reference
.getRangeInElement();
98 final TextRange errorRange
;
99 if (referenceRange
.getStartOffset() == referenceRange
.getEndOffset()) {
100 if (element
instanceof XmlAttributeValue
) {
101 errorRange
= TextRange
.from(referenceRange
.getStartOffset() - 1, 2);
104 errorRange
= TextRange
.from(referenceRange
.getStartOffset(), 1);
107 errorRange
= referenceRange
;
109 descritors
.add(creator
.fun(Pair
.create(errorRange
, element
)));
113 final DomElement domElement
= problemDescriptor
.getDomElement();
114 final PsiElement psiElement
= getPsiElement(domElement
);
115 if (psiElement
!= null && StringUtil
.isNotEmpty(psiElement
.getText())) {
116 if (psiElement
instanceof XmlTag
) {
117 final XmlTag tag
= (XmlTag
)psiElement
;
118 addDescriptionsToTagEnds(tag
, descritors
, creator
);
122 int length
= psiElement
.getTextRange().getLength();
123 if (psiElement
instanceof XmlAttributeValue
) {
124 String value
= ((XmlAttributeValue
)psiElement
).getValue();
125 if (StringUtil
.isNotEmpty(value
)) {
126 start
= psiElement
.getText().indexOf(value
);
127 length
= value
.length();
130 return Arrays
.asList(creator
.fun(Pair
.create(TextRange
.from(start
, length
), psiElement
)));
133 final XmlTag tag
= getParentXmlTag(domElement
);
135 addDescriptionsToTagEnds(tag
, descritors
, creator
);
140 private static <T
> void addDescriptionsToTagEnds(final XmlTag tag
, final List
<T
> descritors
, Function
<Pair
<TextRange
, PsiElement
>, T
> creator
) {
141 final ASTNode node
= tag
.getNode();
143 final ASTNode startNode
= XmlChildRole
.START_TAG_NAME_FINDER
.findChild(node
);
145 final int startOffset
= tag
.getTextRange().getStartOffset();
146 descritors
.add(creator
.fun(Pair
.create(startNode
.getTextRange().shiftRight(-startOffset
), (PsiElement
)tag
)));
150 private static PsiElement
getPsiElement(final DomElement domElement
) {
151 if (domElement
instanceof GenericAttributeValue
) {
152 final GenericAttributeValue attributeValue
= (GenericAttributeValue
)domElement
;
153 final XmlAttributeValue value
= attributeValue
.getXmlAttributeValue();
154 return value
!= null && StringUtil
.isNotEmpty(value
.getText()) ? value
: attributeValue
.getXmlElement();
156 final XmlTag tag
= domElement
.getXmlTag();
157 if (domElement
instanceof GenericValue
&& tag
!= null) {
158 final XmlText
[] textElements
= tag
.getValue().getTextElements();
159 if (textElements
.length
> 0) {
160 return textElements
[0];
168 private static XmlTag
getParentXmlTag(final DomElement domElement
) {
169 DomElement parent
= domElement
.getParent();
170 while (parent
!= null) {
171 if (parent
.getXmlTag() != null) return parent
.getXmlTag();
172 parent
= parent
.getParent();