package requirejs; import com.intellij.lang.javascript.psi.JSLiteralExpression; import com.intellij.patterns.StandardPatterns; import com.intellij.psi.PsiReferenceContributor; import com.intellij.psi.PsiReferenceRegistrar; public class RequirejsPsiReferenceContributor extends PsiReferenceContributor { @Override public void registerReferenceProviders(PsiReferenceRegistrar psiReferenceRegistrar) { RequirejsPsiReferenceProvider provider = new RequirejsPsiReferenceProvider(); psiReferenceRegistrar.registerReferenceProvider(StandardPatterns.instanceOf(JSLiteralExpression.class), provider); } }
package requirejs; import com.intellij.ide.util.PropertiesComponent; import com.intellij.lang.javascript.psi.JSCallExpression; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.PsiReferenceProvider; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; public class RequirejsPsiReferenceProvider extends PsiReferenceProvider { @NotNull @Override public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) { Project project = psiElement.getProject(); PropertiesComponent properties = PropertiesComponent.getInstance(project); String webDirPrefString = properties.getValue("web_dir", "webfront/web"); VirtualFile webDir = project.getBaseDir().findFileByRelativePath(webDirPrefString); if (webDir == null) { return PsiReference.EMPTY_ARRAY; } try { String path = psiElement.getText(); if (isRequireCall(psiElement)) { PsiReference ref = new RequirejsReference(psiElement, new TextRange(1, path.length() - 1), project, webDir); return new PsiReference[] {ref}; } } catch (Exception ignored) {} return new PsiReference[0]; } public static boolean isRequireCall(PsiElement element) { PsiElement prevEl = element.getParent(); if (prevEl != null) { prevEl = prevEl.getParent(); } if (prevEl != null) { if (prevEl instanceof JSCallExpression) { try { if (prevEl.getChildren().length > 1) { if (prevEl.getChildren()[0].getText().toLowerCase().equals("require")) { return true; } } } catch (Exception ignored) {} } } return false; } }
@Nullable @Override public PsiElement resolve() { String path = element.getText(); path = path.replace("'", "").replace("\"", ""); if (path.startsWith("tpl!")) { path = path.replace("tpl!", ""); } else { path = path.concat(".js"); } if (path.startsWith("./")) { path = path.replaceFirst( ".", element .getContainingFile() .getVirtualFile() .getParent() .getPath() .replace(webDir.getPath(), "") ); } VirtualFile targetFile = webDir.findFileByRelativePath(path); if (targetFile != null) { return PsiManager.getInstance(project).findFile(targetFile); } return null; }
package requirejs; import com.intellij.codeInsight.completion.InsertHandler; import com.intellij.codeInsight.completion.InsertionContext; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; public class RequirejsLookupElement extends LookupElement { String path; PsiElement element; private InsertHandler<LookupElement> insertHandler = null; public RequirejsLookupElement(String path, InsertHandler<LookupElement> insertHandler, PsiElement element) { this.path = path; this.insertHandler = insertHandler; this.element = element; } public void handleInsert(InsertionContext context) { if (this.insertHandler != null) { this.insertHandler.handleInsert(context, this); } } @NotNull @Override public String getLookupString() { return path; } }
package requirejs; import com.intellij.codeInsight.completion.InsertHandler; import com.intellij.codeInsight.completion.InsertionContext; import com.intellij.codeInsight.lookup.LookupElement; public class RequirejsInsertHandler implements InsertHandler { private static final RequirejsInsertHandler instance = new RequirejsInsertHandler(); @Override public void handleInsert(InsertionContext insertionContext, LookupElement lookupElement) { if (lookupElement instanceof RequirejsLookupElement) { insertionContext.getDocument().replaceString( ((RequirejsLookupElement) lookupElement).element.getTextOffset() + 1, insertionContext.getTailOffset(), ((RequirejsLookupElement) lookupElement).path ); } } public static RequirejsInsertHandler getInstance() { return instance; } }
package requirejs; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl; import com.intellij.openapi.vfs.newvfs.impl.VirtualFileImpl; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiReference; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; public class RequirejsReference implements PsiReference { PsiElement element; TextRange textRange; Project project; VirtualFile webDir; public RequirejsReference(PsiElement element, TextRange textRange, Project project, VirtualFile webDir) { this.element = element; this.textRange = textRange; this.project = project; this.webDir = webDir; } @Override public PsiElement getElement() { return this.element; } @Nullable @Override public PsiElement resolve() { String path = element.getText(); path = path.replace("'", "").replace("\"", ""); if (path.startsWith("tpl!")) { path = path.replace("tpl!", ""); } else { path = path.concat(".js"); } if (path.startsWith("./")) { path = path.replaceFirst( ".", element .getContainingFile() .getVirtualFile() .getParent() .getPath() .replace(webDir.getPath(), "") ); } VirtualFile targetFile = webDir.findFileByRelativePath(path); if (targetFile != null) { return PsiManager.getInstance(project).findFile(targetFile); } return null; } @Override public String toString() { return getCanonicalText(); } @Override public boolean isSoft() { return false; } @NotNull @Override public Object[] getVariants() { ArrayList<String> files = filterFiles(this.element); ArrayList<LookupElement> completionResultSet = new ArrayList<LookupElement>(); for (int i = 0; i < files.size(); i++) { completionResultSet.add( new RequirejsLookupElement( files.get(i), RequirejsInsertHandler.getInstance(), this.element ) ); } return completionResultSet.toArray(); } protected ArrayList<String> getAllFilesInDirectory(VirtualFile directory) { ArrayList<String> files = new ArrayList<String>(); VirtualFile[] childrens = directory.getChildren(); if (childrens.length != 0) { for (int i = 0; i < childrens.length; i++) { if (childrens[i] instanceof VirtualDirectoryImpl) { files.addAll(getAllFilesInDirectory(childrens[i])); } else if (childrens[i] instanceof VirtualFileImpl) { files.add(childrens[i].getPath().replace(webDir.getPath() + "/", "")); } } } return files; } protected ArrayList<String> filterFiles (PsiElement element) { String value = element.getText().replace("'", "").replace("\"", "").replace("IntellijIdeaRulezzz ", ""); Boolean tpl = value.startsWith("tpl!"); String valuePath = value.replaceFirst("tpl!", ""); ArrayList<String> allFiles = getAllFilesInDirectory(webDir); ArrayList<String> trueFiles = new ArrayList<String>(); String file; for (int i = 0; i < allFiles.size(); i++) { file = allFiles.get(i); if (file.startsWith(valuePath)) { if (tpl && file.endsWith(".html")) { trueFiles.add("tpl!" + file); } else if (file.endsWith(".js")) { trueFiles.add(file.replace(".js", "")); } } } return trueFiles; } @Override public boolean isReferenceTo(PsiElement psiElement) { return false; } @Override public PsiElement bindToElement(@NotNull PsiElement psiElement) throws IncorrectOperationException { throw new IncorrectOperationException(); } @Override public PsiElement handleElementRename(String s) throws IncorrectOperationException { throw new IncorrectOperationException(); } @Override public TextRange getRangeInElement() { return textRange; } @NotNull @Override public String getCanonicalText() { return element.getText(); } }
@NotNull @Override public Object[] getVariants() { ArrayList<String> files = filterFiles(element); ArrayList<LookupElement> completionResultSet = new ArrayList<LookupElement>(); for (int i = 0; i < files.size(); i++) { completionResultSet.add( LookupElementBuilder .create(element, files.get(i)) .withInsertHandler( RequirejsInsertHandler.getInstance() ) ); } return completionResultSet.toArray(); }
@Override public void handleInsert(InsertionContext insertionContext, LookupElement lookupElement) { insertionContext.getDocument().replaceString( lookupElement.getPsiElement().getTextOffset() + 1, insertionContext.getTailOffset(), lookupElement.getLookupString() ); }
Source: https://habr.com/ru/post/189168/
All Articles