/*
* Copyright 2011 The authors
* 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.struts2.dom.struts.action;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xml.ConvertContext;
import com.intellij.util.xml.CustomReferenceConverter;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.GenericDomValue;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Provides self-reference/variants for {@code <action> "name"} (required for proper usage search).
*
* @author Yann Cébron
*/
public class ActionNameCustomReferenceConverter implements CustomReferenceConverter<String> {
@NonNls
private static final String ACTION_SUFFIX = "action";
private final Function<String, Object> ACTION_NAME_FUNCTION = s -> StringUtil.endsWithIgnoreCase(s, ACTION_SUFFIX) ?
StringUtil.replaceIgnoreCase(s, ACTION_SUFFIX, "") : s;
@NotNull
@Override
public PsiReference[] createReferences(final GenericDomValue<String> genericDomValue,
final PsiElement psiElement,
final ConvertContext convertContext) {
final PsiReferenceBase<PsiElement> ref = new PsiReferenceBase<PsiElement>(psiElement) {
@SuppressWarnings({"ConstantConditions"})
public PsiElement resolve() {
return genericDomValue.getParent().getXmlTag();
}
public boolean isSoft() {
return true;
}
// do nothing. the element will be renamed via PsiMetaData
public PsiElement handleElementRename(final String newElementName) throws IncorrectOperationException {
return getElement();
}
@NotNull
public Object[] getVariants() {
final DomElement invocationElement = convertContext.getInvocationElement();
final Action action = invocationElement.getParentOfType(Action.class, true);
assert action != null;
final PsiClass psiClass = action.searchActionClass();
if (psiClass == null) {
return EMPTY_ARRAY;
}
final Project project = psiClass.getProject();
final PsiClassType classType = PsiTypesUtil.getClassType(psiClass);
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
final SuggestedNameInfo info = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, classType);
final Set<String> variants = new HashSet<>(Arrays.asList(info.names));
variants.remove(ACTION_SUFFIX);
// remove existing action-names
final List<Action> actions = action.getStrutsPackage().getActions();
ContainerUtil.process(actions, action1 -> {
variants.remove(action1.getName().getStringValue());
return true;
});
return ContainerUtil.map2Array(variants, ACTION_NAME_FUNCTION);
}
};
return new PsiReference[]{ref};
}
}