/* * Copyright 2013-2015 Grzegorz Ligas <ligasgr@gmail.com> and other contributors * (see the CONTRIBUTORS file). * * 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 org.intellij.xquery.annotator; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.tree.IElementType; import org.intellij.xquery.annotator.comment.MisplacedCommentHighlighter; import org.intellij.xquery.annotator.duplicateFunction.ErrorAnnotationCreator; import org.intellij.xquery.annotator.function.UnresolvedFunctionChecker; import org.intellij.xquery.annotator.variable.UnresolvedVariableChecker; import org.intellij.xquery.annotator.xml.UnresolvedXmlNamespaceChecker; import org.intellij.xquery.annotator.xqdoc.XQDocHighlighter; import org.intellij.xquery.highlighting.XQuerySyntaxHighlighter; import org.intellij.xquery.psi.XQueryAnnotation; import org.intellij.xquery.psi.XQueryCaseClause; import org.intellij.xquery.psi.XQueryCompatibilityAnnotation; import org.intellij.xquery.psi.XQueryCountClause; import org.intellij.xquery.psi.XQueryCurrentItem; import org.intellij.xquery.psi.XQueryFile; import org.intellij.xquery.psi.XQueryForBinding; import org.intellij.xquery.psi.XQueryFunctionCall; import org.intellij.xquery.psi.XQueryFunctionDecl; import org.intellij.xquery.psi.XQueryFunctionInvocation; import org.intellij.xquery.psi.XQueryFunctionName; import org.intellij.xquery.psi.XQueryGroupByClause; import org.intellij.xquery.psi.XQueryGroupingVariable; import org.intellij.xquery.psi.XQueryItemType; import org.intellij.xquery.psi.XQueryLetBinding; import org.intellij.xquery.psi.XQueryMarklogicAnnotation; import org.intellij.xquery.psi.XQueryMarklogicCatchErrorList; import org.intellij.xquery.psi.XQueryMultiVariableBinding; import org.intellij.xquery.psi.XQueryNextItem; import org.intellij.xquery.psi.XQueryParam; import org.intellij.xquery.psi.XQueryPositionalVar; import org.intellij.xquery.psi.XQueryPreviousItem; import org.intellij.xquery.psi.XQueryTypeswitchDefaultReturnClause; import org.intellij.xquery.psi.XQueryVarDecl; import org.intellij.xquery.psi.XQueryVarName; import org.intellij.xquery.psi.XQueryVarRef; import org.intellij.xquery.psi.XQueryWindowClause; import org.intellij.xquery.psi.XQueryXmlTagNamespace; import org.jetbrains.annotations.NotNull; import static org.intellij.xquery.psi.XQueryTypes.EXPRCOMMENTCONTENT; import static org.intellij.xquery.psi.XQueryTypes.EXPR_COMMENT_END; import static org.intellij.xquery.psi.XQueryTypes.EXPR_COMMENT_START; public class XQueryAnnotator implements Annotator, DumbAware { private ErrorAnnotationCreator duplicateFunctionErrorCreator = new ErrorAnnotationCreator(); private XQDocHighlighter xQDocHighlighter = new XQDocHighlighter(); private MisplacedCommentHighlighter misplacedCommentHighlighter = new MisplacedCommentHighlighter(); private UnresolvedVariableChecker unresolvedVariableChecker = new UnresolvedVariableChecker(); private UnresolvedFunctionChecker unresolvedFunctionChecker = new UnresolvedFunctionChecker(); private UnresolvedXmlNamespaceChecker unresolvedXmlNamespaceChecker = new UnresolvedXmlNamespaceChecker(); @Override public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { IElementType elementType = element.getNode().getElementType(); if (element instanceof XQueryFunctionName) { duplicateFunctionErrorCreator.createDuplicateFunctionDeclarationError(holder, (XQueryFunctionName) element, (XQueryFile) element.getContainingFile()); } if (element instanceof PsiComment) { xQDocHighlighter.highlightXQDocTags((PsiComment) element, holder); } if (isPartOfMisplacedComment(elementType)) { misplacedCommentHighlighter.highlight(element, holder); } if (element instanceof XQueryVarRef) { unresolvedVariableChecker.check((XQueryVarRef) element, holder); } if (element instanceof XQueryFunctionInvocation) { unresolvedFunctionChecker.check((XQueryFunctionInvocation) element, holder); } if (element instanceof XQueryXmlTagNamespace) { unresolvedXmlNamespaceChecker.check((XQueryXmlTagNamespace) element, holder); } if (element instanceof XQueryItemType) { highlight(element, holder, XQuerySyntaxHighlighter.ITEM_TYPE); } PsiElement elementParent = element.getParent(); if (element instanceof XQueryFunctionName && elementParent instanceof XQueryFunctionCall) { highlight(element, holder, XQuerySyntaxHighlighter.FUNCTION_CALL); } if (element instanceof XQueryFunctionName && elementParent instanceof XQueryFunctionDecl) { highlight(element, holder, XQuerySyntaxHighlighter.FUNCTION_DECLARATION); } if (element instanceof XQueryVarName) { if (elementParent instanceof XQueryVarRef) { PsiReference reference = elementParent.getReference(); if (reference != null) { PsiElement resolvedReference = reference.resolve(); if (resolvedReference != null) { highlightVariable((XQueryVarName) element, holder, resolvedReference.getParent()); } } } else { highlightVariable((XQueryVarName) element, holder, elementParent); } } if (element instanceof XQueryCompatibilityAnnotation || element instanceof XQueryMarklogicAnnotation) { highlight(element, holder, XQuerySyntaxHighlighter.ANNOTATION); } if (element instanceof XQueryAnnotation) { highlight(((XQueryAnnotation) element).getAnnotationName(), holder, XQuerySyntaxHighlighter.ANNOTATION); highlight(new TextRange(element.getTextRange().getStartOffset(), element.getTextRange().getStartOffset() + 1), holder, XQuerySyntaxHighlighter.ANNOTATION); } } private boolean isPartOfMisplacedComment(IElementType type) { return type == EXPRCOMMENTCONTENT || type == EXPR_COMMENT_START || type == EXPR_COMMENT_END; } private void highlightVariable(XQueryVarName element, AnnotationHolder holder, PsiElement elementParent) { TextAttributes attributes = getAttributes(XQuerySyntaxHighlighter.PREFIXED_VARIABLE); if (element.getPrefix() != null && !new TextAttributes().equals(attributes)) { highlight(element, holder, XQuerySyntaxHighlighter.PREFIXED_VARIABLE); } else { if (elementParent instanceof XQueryParam) { highlight(element, holder, XQuerySyntaxHighlighter.PARAMETER); } else if (elementParent instanceof XQueryVarDecl) { highlight(element, holder, XQuerySyntaxHighlighter.GLOBAL_VARIABLE); } else if (isLocalVariableDeclaration(elementParent)) { highlight(element, holder, XQuerySyntaxHighlighter.LOCAL_VARIABLE); } } } private boolean isLocalVariableDeclaration(PsiElement element) { return element instanceof XQueryGroupByClause || element instanceof XQueryCurrentItem || element instanceof XQueryGroupingVariable || element instanceof XQueryLetBinding || element instanceof XQueryMarklogicCatchErrorList || element instanceof XQueryMultiVariableBinding || element instanceof XQueryNextItem || element instanceof XQueryPositionalVar || element instanceof XQueryPreviousItem || element instanceof XQueryCaseClause || element instanceof XQueryCountClause || element instanceof XQueryForBinding || element instanceof XQueryTypeswitchDefaultReturnClause || element instanceof XQueryWindowClause ; } private void highlight(PsiElement element, AnnotationHolder holder, TextAttributesKey attributesKey) { //TODO: start using createAnnotation in newer version to do highlighting even when there are errors // use HighlightInfoType.SYMBOL_TYPE_SEVERITY to satisfy UpdateHighlightersUtil.isCovered() highlight(element.getTextRange(), holder, attributesKey); } private void highlight(TextRange textRange, AnnotationHolder holder, TextAttributesKey attributesKey) { holder.createInfoAnnotation(textRange, null) .setEnforcedTextAttributes(getAttributes(attributesKey)); } private TextAttributes getAttributes(TextAttributesKey attributesKey) { return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(attributesKey); } }