/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.util;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.PsiElementFilter;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlText;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class InjectedElementEditor {
public static final String EDITOR = "_editor";
public static final Key<PsiFile> ORIGINAL_PSI_FILE = new Key<>("ORIGINAL_PSI_FILE");
public static final Key<IInjectedElementProvider> INJECTED_ELEMENT_PROVIDER = new Key<>("INJECTED_ELEMENT_PROVIDER");
public static final Key<Boolean> SINGLE_LINE_EDITOR = new Key<>("SINGLE_LINE_EDITOR");
public static PsiElement getHostInjectionXMLText(XmlTag parent, final String name) {
final PsiElement[] psiElements = PsiTreeUtil.collectElements(parent, new PsiElementFilter() {
@Override
public boolean isAccepted(PsiElement element) {
if (element instanceof XmlText) {
final XmlTag parent = PsiTreeUtil.getParentOfType(element, XmlTag.class);
if (parent != null && name.equals(parent.getName())) {
return true;
}
}
return false;
}
});
return psiElements.length == 0 ? null : psiElements[0];
}
public static PsiElement getHostInjectionXMLAttr(XmlTag parent, String attrName) {
final XmlAttribute attribute = parent.getAttribute(attrName);
return attribute == null ? null : attribute.getValueElement();
}
public static PsiFile getInjectionPsiElement(Project project, PsiElement hostInjection) {
final List<Pair<PsiElement, TextRange>> pairs = InjectedLanguageManager.getInstance(project).getInjectedPsiFiles(hostInjection);
if (pairs != null) {
for (Pair<PsiElement, TextRange> pair : pairs) {
final VirtualFile injectedFile = pair.first.getContainingFile().getVirtualFile();
final PsiFile injectedPsi = PsiManager.getInstance(project).findFile(injectedFile);
return injectedPsi;
}
}
return null;
}
public static boolean areInEquivalentFiles(PsiElement m1, PsiElement m2) {
final String name1 = getContainingClass(m1).getName();
final String name2 = getContainingClass(m2).getName();
return name1.equals(name2 + EDITOR) || name2.equals(name1 + EDITOR);
}
public static boolean isInEmbeddedEditor(PsiElement element) {
final PsiClass psiClass = getContainingClass(element);
return psiClass != null &&
psiClass.getName().endsWith(EDITOR) &&
psiClass.getContainingFile().getVirtualFile() != null && //this is for copy for GosuIdentifier <name>IntellijRulezz
psiClass.getContainingFile().getVirtualFile().getParent() == null; //virtual file parent is null for all light virtual files
}
@NotNull
public static PsiFile getOriginalFile(@NotNull PsiFile file) {
// TODO: before it was call to file.getContainingFile() but it should return this
PsiFile originalFile = file.getUserData(ORIGINAL_PSI_FILE);
if (originalFile == null) {
final IInjectedElementProvider editor = file.getUserData(INJECTED_ELEMENT_PROVIDER);
originalFile = editor != null ? editor.getInjectedFile() : null;
}
return originalFile != null ? originalFile : file;
}
@Nullable
public static PsiElement getOriginalElement(@NotNull PsiElement element) {
final PsiFile psiFile = element.getContainingFile();
final PsiFile originalFile = getOriginalFile(psiFile);
return originalFile != null ?
originalFile.equals(psiFile) ?
element : originalFile.findElementAt(element.getTextOffset())
: element;
}
@Nullable
public static PsiClass getContainingClass(@Nullable PsiElement element) {
while (element != null && !(element instanceof PsiClass)) {
element = element.getParent();
}
return (PsiClass) element;
}
}