package com.chrisfolger.needsmoredojo.intellij.reference; import com.chrisfolger.needsmoredojo.core.amd.filesystem.SourcesLocator; import com.chrisfolger.needsmoredojo.core.amd.psi.AMDPsiUtil; import com.intellij.lang.javascript.psi.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import org.apache.log4j.Logger; import org.apache.log4j.Priority; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; public class NlsLookupReference extends PsiReferenceBase<JSLiteralExpression> { private PsiElement qualifier; private JSIndexedPropertyAccessExpression accessor; private PsiFile file; public NlsLookupReference(PsiElement qualifier, JSIndexedPropertyAccessExpression accessor, JSLiteralExpression sourceElement) { super(sourceElement); this.qualifier = qualifier; this.accessor = accessor; } public List<JSProperty> getI18nKeys(PsiFile file) { final List<JSProperty> keys = new ArrayList<JSProperty>(); file.acceptChildren(new JSRecursiveElementVisitor() { @Override public void visitJSObjectLiteralExpression(JSObjectLiteralExpression node) { if(!node.getParent().getText().startsWith("root:")) { super.visitJSObjectLiteralExpression(node); return; } for(JSProperty property : node.getProperties()) { keys.add(property); } super.visitJSObjectLiteralExpression(node); } }); return keys; } public PsiFile getFileContainingI18nKeys() { if(file != null) { return file; } // get the list of defines // find one that matches // check to see if it's an i18n file // resolve the reference to the file PsiElement correctDefine = AMDPsiUtil.getDefineForVariable(qualifier.getContainingFile(), qualifier.getText()); // didn't get a define, so there is no reference to an i18n item if(correctDefine == null) { return null; } String defineText = correctDefine.getText(); defineText = defineText.substring(defineText.lastIndexOf("!") + 1).replaceAll("'", ""); PsiDirectory containingDirectory = correctDefine.getContainingFile().getParent(); if(containingDirectory == null && correctDefine.getContainingFile().getOriginalFile() != null) { containingDirectory = correctDefine.getContainingFile().getOriginalFile().getContainingDirectory(); } VirtualFile i18nFile = SourcesLocator.getAMDImportFile(correctDefine.getProject(), defineText + ".js", containingDirectory); if(i18nFile == null) { // probably not in the same directory as the dojo sources Logger.getLogger(NlsLookupReference.class).log(Priority.DEBUG, "can't find " + defineText + ".js"); return file; } PsiFile templateFile = PsiManager.getInstance(correctDefine.getProject()).findFile(i18nFile); file = templateFile; return templateFile; } @Nullable @Override public PsiElement resolve() { PsiFile templateFile = getFileContainingI18nKeys(); if(templateFile == null) { return accessor.getIndexExpression(); } for(JSProperty property : getI18nKeys(templateFile)) { String propertyText = accessor.getIndexExpression().getText(); propertyText = propertyText.substring(1, propertyText.length() - 1); if(property.getName().equals(propertyText)) { return property; } } return accessor.getIndexExpression(); } @NotNull @Override public Object[] getVariants() { PsiFile templateFile = getFileContainingI18nKeys(); if(templateFile == null) { return new Object[0]; } List<JSProperty> keys = getI18nKeys(file); List<Object> keyStrings = new ArrayList<Object>(); for(JSProperty key : keys) { keyStrings.add(key.getName()); } return keyStrings.toArray(); } }