blob: 77c4394679c32367ae1189eb1f1cbbd38364e2f4 [file] [log] [blame]
/*
* Copyright 2002-2005 Sascha Weinreuter
*
* 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.plugins.xpathView.util;
import com.intellij.lang.annotation.AnnotationSession;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.xml.*;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.ASTNode;
import com.intellij.lang.LanguageAnnotators;
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class MyPsiUtil {
private static final Logger LOG = Logger.getInstance("org.intellij.plugins.xpathView.util.MyPsiUtil");
private MyPsiUtil() {
}
@Nullable
public static XmlElement findContextNode(@NotNull PsiFile psiFile, @NotNull Editor editor) {
PsiElement contextNode = psiFile.findElementAt(editor.getCaretModel().getOffset());
while (contextNode != null && !isValidContextNode(contextNode)) {
contextNode = contextNode.getParent();
}
if (LOG.isDebugEnabled()) {
LOG.debug("Returning context node: " + contextNode);
}
assert contextNode == null || contextNode instanceof XmlElement;
return (XmlElement)contextNode;
}
public static boolean isValidContextNode(@Nullable PsiElement contextNode) {
if (contextNode instanceof XmlTag) {
return true;
} else if (contextNode instanceof XmlDocument) {
return true;
}
return false;
}
@NotNull
public static PsiElement getNameElement(@NotNull XmlTag tag) {
final PsiElement element = findNameElement(tag);
if (element != null) {
return element;
}
LOG.error("Name element not found for " + tag);
return tag;
}
@Nullable
public static PsiElement findNameElement(@NotNull XmlTag tag) {
PsiElement[] children = tag.getChildren();
for (PsiElement child : children) {
if (isNameElement(child)) {
return child;
}
}
return null;
}
public static boolean isNameElement(@Nullable PsiElement child) {
if (child != null) {
if (child.getParent() instanceof XmlTag) {
if (child instanceof XmlToken) {
if (((XmlToken)child).getTokenType() == XmlTokenType.XML_NAME) {
return true;
}
} else if (child instanceof ASTNode) {
return ((ASTNode)child).getElementType() == XmlTokenType.XML_NAME;
}
}
}
return false;
}
public static String getAttributePrefix(@NotNull XmlAttribute attribute) {
final String name = attribute.getName();
if (name.indexOf(':') == -1) {
return "";
} else {
return name.substring(0, name.indexOf(':'));
}
}
public static boolean isStartTag(PsiElement contextNode) {
if (contextNode instanceof PsiWhiteSpace) {
PsiElement sibling = contextNode.getPrevSibling();
while (sibling != null && !isNameElement(sibling)) {
sibling = sibling.getPrevSibling();
}
return sibling != null;
} else if (contextNode instanceof XmlToken) {
if (((XmlToken)contextNode).getTokenType() == XmlTokenType.XML_START_TAG_START) return true;
if (((XmlToken)contextNode).getTokenType() == XmlTokenType.XML_TAG_END) return true;
if (((XmlToken)contextNode).getTokenType() == XmlTokenType.XML_EMPTY_ELEMENT_END) return true;
}
return false;
}
public static boolean isEndTag(PsiElement contextNode) {
if (contextNode instanceof PsiWhiteSpace) {
PsiElement sibling = contextNode.getPrevSibling();
while (sibling != null && !isNameElement(sibling)) {
sibling = sibling.getPrevSibling();
}
return sibling != null;
} else if (contextNode instanceof XmlToken) {
if (((XmlToken)contextNode).getTokenType() == XmlTokenType.XML_END_TAG_START) return true;
}
return false;
}
/**
* This method checks if the passed element's namespace is actually declared in the document or if has an
* implicit namespace URI which as of late, IDEA assigns to Ant files, Web descriptors and anything that has a
* DTD defined. For XPath queries this is very inconvenient when having to enter a namespace-prefix with every
* element-step. For XPath-Expression generation this results in more complex expressions than necessary.
*/
public static boolean isInDeclaredNamespace(XmlTag context, String nsUri, String nsPrefix) {
if (nsUri == null || nsUri.length() == 0 || nsPrefix != null && nsPrefix.length() > 0) {
return true;
}
do {
if (context.getLocalNamespaceDeclarations().containsValue(nsUri)) return true;
context = (XmlTag)(context.getParent() instanceof XmlTag ? context.getParent() : null);
} while (context != null);
return false;
}
public static String checkFile(final PsiFile file) {
final String[] error = new String[1];
file.accept(new PsiRecursiveElementVisitor() {
public void visitErrorElement(PsiErrorElement element) {
error[0] = element.getErrorDescription();
}
});
if (error[0] != null) return error[0];
final Annotator annotator = LanguageAnnotators.INSTANCE.forLanguage(file.getLanguage());
file.accept(new PsiRecursiveElementVisitor() {
public void visitElement(PsiElement element) {
annotator.annotate(element, new AnnotationHolderImpl(new AnnotationSession(file)) {
public Annotation createErrorAnnotation(@NotNull ASTNode astNode, String string) {
error[0] = string;
return super.createErrorAnnotation(astNode, string);
}
public Annotation createErrorAnnotation(@NotNull PsiElement element, String string) {
error[0] = string;
return super.createErrorAnnotation(element, string);
}
public Annotation createErrorAnnotation(@NotNull TextRange textRange, String string) {
error[0] = string;
return super.createErrorAnnotation(textRange, string);
}
});
super.visitElement(element);
}
});
return error[0];
}
}