/* * Copyright 2000-2013 JetBrains s.r.o. * * 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 com.intellij.coldFusion.model.files; import com.intellij.coldFusion.model.psi.*; import com.intellij.coldFusion.model.psi.impl.CfmlTagScriptImpl; import com.intellij.extapi.psi.PsiFileBase; import com.intellij.lang.Language; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by Lera Nikolaenko * Date: 24.02.2009 */ public class CfmlFile extends PsiFileBase { private final CachedValue<Map<String, CfmlImplicitVariable>> myImplicitVars; @NonNls public static final String CFMLVARIABLE_MARKER = "@cfmlvariable "; @NonNls public static final String CFMLJAVALOADER_MARKER = "@javaloader "; @NonNls public static final Pattern LOADER_DECL_PATTERN_TEMP = Pattern.compile("<!---[\\s]*" + CFMLJAVALOADER_MARKER + "[\\s]*name=\"([^\"]+)\".*[\\s]*(loadPaths=\"([^\"]*)\")[\\s]*--->[\\s]*"); @NonNls public static final Pattern IMPLICIT_VAR_DECL_PATTERN_TEMP = Pattern.compile( "<!---[\\s]*" + CFMLVARIABLE_MARKER + "[\\s]*name=\"([^\"]+)\"[\\s]*type=\"([^\"]*)\"[\\s]*--->[\\s]*"); CachedValueProvider<Map<String, CfmlImplicitVariable>> createImplicitVarsProvider() { return () -> { final Map<String, CfmlImplicitVariable> result = new THashMap<>(); this.accept(new PsiRecursiveElementVisitor() { @Override public void visitComment(final PsiComment comment) { final String text = comment.getText(); final String[] nameAndType = findVariableNameAndType(text); if (nameAndType == null) { return; } CfmlImplicitVariable var = ContainerUtil.getOrCreate(result, nameAndType[0], (Factory<CfmlImplicitVariable>)() -> new CfmlImplicitVariable(CfmlFile.this, comment, nameAndType[0])); var.setType(nameAndType[1]); } }); return CachedValueProvider.Result.create(result, this); }; } public CfmlFile(FileViewProvider viewProvider, @NotNull Language language) { super(viewProvider, language); myImplicitVars = CachedValuesManager.getManager(getManager().getProject()).createCachedValue(createImplicitVarsProvider(), false); } @NotNull public FileType getFileType() { return CfmlFileType.INSTANCE; } @NotNull public String getPresentableName() { return "CfmlFile:" + getName(); } public String toString() { return getPresentableName(); } @Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { if (!processExportableDeclarations(processor, state)) { return false; } return CfmlPsiUtil.processDeclarations(processor, state, lastParent, this); } private boolean processExportableDeclarations(PsiScopeProcessor processor, ResolveState state) { for (final CfmlImplicitVariable var : myImplicitVars.getValue().values()) { if (!processor.execute(var, state)) { return false; } } return true; } @Nullable private static String[] findVariableNameAndType(String text) { Matcher matcher = IMPLICIT_VAR_DECL_PATTERN_TEMP.matcher(text); Matcher javaLoaderMatcher = LOADER_DECL_PATTERN_TEMP.matcher(text); if (!matcher.matches()) { if (!javaLoaderMatcher.matches()) { return null; } else { return new String[]{javaLoaderMatcher.group(1), "javaloader"}; } } return new String[]{matcher.group(1), matcher.group(2)}; } @Nullable public CfmlImplicitVariable findImplicitVariable(String name) { return myImplicitVars.getValue().get(name); } public Collection<CfmlFunction> getGlobalFunctions() { final Collection<CfmlFunction> result = new LinkedList<>(); accept(new CfmlRecursiveElementVisitor() { @Override public void visitCfmlFunction(CfmlFunction function) { result.add(function); } @Override public void visitCfmlComponent(CfmlComponent component) { } @Override public void visitElement(PsiElement element) { if (element instanceof CfmlFile || element instanceof CfmlTag) { super.visitElement(element); } } }); return result; } @Nullable public CfmlComponent getComponentDefinition() { final Ref<CfmlComponent> ref = new Ref<>(null); accept(new CfmlRecursiveElementVisitor() { @Override public void visitCfmlFunction(CfmlFunction function) { } @Override public void visitCfmlComponent(CfmlComponent component) { ref.set(component); } @Override public void visitCfmlTag(CfmlTag tag) { if (tag instanceof CfmlTagScriptImpl) { super.visitCfmlTag(tag); } } @Override public void visitElement(PsiElement element) { if (element instanceof CfmlFile || element instanceof CfmlTagScriptImpl) { super.visitElement(element); } } }); return ref.get(); } public String getComponentQualifiedName(@NotNull String componentName) { CfmlImport[] childrenByClass = findChildrenByClass(CfmlImport.class); for (CfmlImport importStatement : childrenByClass) { if (importStatement.isImported(componentName)) { String importString = importStatement.getImportString(); return importString != null ? importString : ""; } } return componentName; } public Collection<String> getImportStrings() { Set<String> result = new HashSet<>(); CfmlImport[] childrenByClass = findChildrenByClass(CfmlImport.class); for (CfmlImport importStatement : childrenByClass) { String importString = importStatement.getImportString(); if (importString != null) { result.add(importString); } } return result; } }