blob: ad5065cc785d74cacdd7429413cdd4936edf0d20 [file] [log] [blame]
/*
* Copyright 2000-2012 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 org.jetbrains.idea.maven.dom.references;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceProvider;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.util.ProcessingContext;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.dom.MavenDomUtil;
import org.jetbrains.idea.maven.dom.MavenPropertyResolver;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.utils.MavenJDOMUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MavenFilteredPropertyPsiReferenceProvider extends PsiReferenceProvider {
private static final Key<Pattern> KEY = Key.create("MavenFilteredPropertyPsiReferenceProvider:delimitersKey");
public static final Pattern DEFAULT_DELIMITERS = MavenPropertyResolver.PATTERN;
@NotNull
public static Pattern getDelimitersPattern(MavenProject mavenProject) {
Pattern res = mavenProject.getCachedValue(KEY);
if (res == null) {
Element cfg = mavenProject.getPluginConfiguration("org.apache.maven.plugins", "maven-resources-plugin");
if (cfg == null) {
res = DEFAULT_DELIMITERS;
}
else {
List<String> delimiters = MavenJDOMUtil.findChildrenValuesByPath(cfg, "delimiters", "delimiter");
if (delimiters.isEmpty() || delimiters.size() > 10) {
res = DEFAULT_DELIMITERS;
}
else {
StringBuilder patternBuilder = new StringBuilder();
for (String delimiter : delimiters) {
delimiter = delimiter.trim();
if (delimiter.isEmpty()) continue;
int ind = delimiter.indexOf('*');
if (ind >= 0) {
appendDelimiter(patternBuilder, delimiter.substring(0, ind), delimiter.substring(ind + 1));
}
else {
appendDelimiter(patternBuilder, delimiter, delimiter);
}
}
// <useDefaultDelimiters> is not used if custom delimiters are not present.
boolean useDefaultDelimiters = true;
String useDefaultDelimitersText = cfg.getChildText("useDefaultDelimiters");
if (StringUtil.isNotEmpty(useDefaultDelimitersText)) {
useDefaultDelimiters = Boolean.parseBoolean(useDefaultDelimitersText);
}
if (useDefaultDelimiters) {
appendDelimiter(patternBuilder, "${", "}");
appendDelimiter(patternBuilder, "@", "@");
}
res = Pattern.compile(patternBuilder.toString());
}
}
res = mavenProject.putCachedValue(KEY, res);
}
return res;
}
private static void appendDelimiter(StringBuilder pattern, String prefix, String suffix) {
if (pattern.length() > 0) {
pattern.append('|');
}
pattern.append(Pattern.quote(prefix)).append("(.+?)").append(Pattern.quote(suffix));
}
private static boolean shouldAddReference(@NotNull PsiElement element) {
if (element.getFirstChild() == element.getLastChild()) {
return true; // Add to all leaf elements
}
if (element instanceof XmlAttribute) {
return true;
}
return false; // Don't add references to all element to avoid performance problem.
}
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
if (!shouldAddReference(element)) {
// Add reference to element with one child or leaf element only to avoid performance problem.
return PsiReference.EMPTY_ARRAY;
}
if (!MavenDomUtil.isFilteredResourceFile(element)) return PsiReference.EMPTY_ARRAY;
String text = element.getText();
if (StringUtil.isEmptyOrSpaces(text)) return PsiReference.EMPTY_ARRAY;
MavenProject mavenProject = MavenDomUtil.findContainingProject(element);
if (mavenProject == null) return PsiReference.EMPTY_ARRAY;
List<PsiReference> res = null;
Pattern pattern = getDelimitersPattern(mavenProject);
Matcher matcher = pattern.matcher(text);
int groupCount = matcher.groupCount();
while (matcher.find()) {
String propertyName = null;
int from = 0;
for (int i = 0; i < groupCount; i++) {
propertyName = matcher.group(i + 1);
if (propertyName != null) {
from = matcher.start(i + 1);
break;
}
}
assert propertyName != null;
if (res == null) {
res = new ArrayList<PsiReference>();
}
TextRange range = TextRange.from(from, propertyName.length());
res.add(new MavenFilteredPropertyPsiReference(mavenProject, element, propertyName, range));
}
return res == null ? PsiReference.EMPTY_ARRAY : res.toArray(new PsiReference[res.size()]);
}
}