Extensible comment injector API

This commit is contained in:
Gregory.Shrago
2013-08-06 22:09:01 +04:00
parent 6b885adf26
commit 7273ccb136
17 changed files with 184 additions and 157 deletions
@@ -26,7 +26,7 @@ import com.intellij.psi.*;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.util.IncorrectOperationException;
import gnu.trove.THashMap;
import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport;
import org.intellij.plugins.intelliLang.inject.java.JavaLanguageInjectionSupport;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -42,7 +42,7 @@ public class MethodParameterInjection extends BaseInjection {
private final Map<String, MethodInfo> myParameterMap = new THashMap<String, MethodInfo>();
public MethodParameterInjection() {
super(LanguageInjectionSupport.JAVA_SUPPORT_ID);
super(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID);
}
@NotNull
@@ -69,7 +69,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
myConfiguration = configuration;
myProject = project;
myTemporaryPlacesRegistry = temporaryPlacesRegistry;
mySupport = InjectorUtils.findNotNullInjectionSupport(LanguageInjectionSupport.JAVA_SUPPORT_ID);
mySupport = InjectorUtils.findNotNullInjectionSupport(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID);
myXmlIndex = CachedValuesManager.getManager(myProject).createCachedValue(new CachedValueProvider<Collection<String>>() {
public Result<Collection<String>> compute() {
final Map<ElementPattern<?>, BaseInjection> map = new THashMap<ElementPattern<?>, BaseInjection>();
@@ -139,7 +139,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
if (!hasLiteral) return;
final Language tempLanguage = tempInjectedLanguage == null ? null : tempInjectedLanguage.getLanguage();
final PsiFile finalContainingFile = containingFile;
InjectionProcessor injectionProcessor = new InjectionProcessor(myConfiguration, operands) {
InjectionProcessor injectionProcessor = new InjectionProcessor(myConfiguration, mySupport, operands) {
@Override
protected void processInjection(Language language,
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> list,
@@ -162,7 +162,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
}
};
if (tempLanguage != null) {
BaseInjection baseInjection = new BaseInjection(LanguageInjectionSupport.JAVA_SUPPORT_ID);
BaseInjection baseInjection = new BaseInjection(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID);
baseInjection.setInjectedLanguageId(tempInjectedLanguage.getID());
injectionProcessor.processInjectionInner(baseInjection, false);
InjectorUtils.putInjectedFileUserData(registrar, LanguageInjectionSupport.TEMPORARY_INJECTED_LANGUAGE, tempInjectedLanguage);
@@ -175,12 +175,14 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
public static class InjectionProcessor {
private final Configuration myConfiguration;
private final LanguageInjectionSupport mySupport;
private final PsiElement[] myOperands;
private boolean myShouldStop;
private boolean myUnparsable;
public InjectionProcessor(Configuration configuration, PsiElement... operands) {
public InjectionProcessor(Configuration configuration, LanguageInjectionSupport support, PsiElement... operands) {
myConfiguration = configuration;
mySupport = support;
myOperands = operands;
}
@@ -301,11 +303,11 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
}
private boolean processCommentInjections(PsiVariable owner) {
Ref<PsiComment> causeRef = Ref.create();
Ref<PsiElement> causeRef = Ref.create();
PsiElement anchor = owner.getFirstChild() instanceof PsiComment?
(owner.getModifierList() != null? owner.getModifierList() : owner.getTypeElement()) : owner;
if (anchor == null) return true;
BaseInjection injection = InjectorUtils.findCommentInjection(anchor, LanguageInjectionSupport.JAVA_SUPPORT_ID, causeRef);
BaseInjection injection = mySupport.findInjectionComment(anchor, causeRef);
return injection == null || processCommentInjectionInner(owner, causeRef.get(), injection);
}
@@ -351,7 +353,7 @@ public class ConcatenationInjector implements ConcatenationAwareInjector {
final String id = AnnotationUtilEx.calcAnnotationValue(annotations, "value");
final String prefix = AnnotationUtilEx.calcAnnotationValue(annotations, "prefix");
final String suffix = AnnotationUtilEx.calcAnnotationValue(annotations, "suffix");
final BaseInjection injection = new BaseInjection(LanguageInjectionSupport.JAVA_SUPPORT_ID);
final BaseInjection injection = new BaseInjection(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID);
if (prefix != null) injection.setPrefix(prefix);
if (suffix != null) injection.setSuffix(suffix);
if (id != null) injection.setInjectedLanguageId(id);
@@ -61,6 +61,7 @@ import org.intellij.plugins.intelliLang.inject.config.ui.configurables.MethodPar
import org.intellij.plugins.intelliLang.util.ContextComputationProcessor;
import org.intellij.plugins.intelliLang.util.PsiUtilEx;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -75,6 +76,8 @@ import static org.intellij.plugins.intelliLang.inject.config.MethodParameterInje
*/
public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSupport {
@NonNls public static final String JAVA_SUPPORT_ID = "java";
private static boolean isMine(final PsiLanguageInjectionHost psiElement) {
return PsiUtilEx.isStringOrCharacterLiteral(psiElement);
}
@@ -93,6 +96,11 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
return new Configurable[]{new AdvancedSettingsUI(project, configuration)};
}
@Override
public boolean isApplicableTo(PsiLanguageInjectionHost host) {
return host instanceof PsiLiteralExpression;
}
public boolean addInjectionInPlace(final Language language, final PsiLanguageInjectionHost psiElement) {
if (!isMine(psiElement)) return false;
return doInjectInJava(psiElement.getProject(), psiElement, language.getID());
@@ -105,7 +113,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
final PsiLiteralExpression host = (PsiLiteralExpression)psiElement;
final Project project = host.getProject();
final Configuration configuration = Configuration.getProjectInstance(project);
collectInjections(host, configuration, injectionsMap, annotations);
collectInjections(host, configuration, this, injectionsMap, annotations);
if (injectionsMap.isEmpty() && annotations.isEmpty()) return false;
final ArrayList<BaseInjection> originalInjections = new ArrayList<BaseInjection>(injectionsMap.keySet());
@@ -129,7 +137,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
final PsiLiteralExpression host = (PsiLiteralExpression)psiElement;
final Project project = host.getProject();
final Configuration configuration = Configuration.getProjectInstance(project);
collectInjections(host, configuration, injectionsMap, annotations);
collectInjections(host, configuration, this, injectionsMap, annotations);
if (injectionsMap.isEmpty() || !annotations.isEmpty()) return false;
final BaseInjection originalInjection = injectionsMap.keySet().iterator().next();
@@ -146,7 +154,7 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
}
private BaseInjection showInjectionUI(final Project project, final MethodParameterInjection methodParameterInjection) {
private static BaseInjection showInjectionUI(final Project project, final MethodParameterInjection methodParameterInjection) {
final AbstractInjectionPanel panel = new MethodParameterPanel(methodParameterInjection, project);
panel.reset();
final DialogBuilder builder = new DialogBuilder(project);
@@ -343,10 +351,12 @@ public class JavaLanguageInjectionSupport extends AbstractLanguageInjectionSuppo
}
}
private static void collectInjections(final PsiLiteralExpression host, final Configuration configuration,
private static void collectInjections(PsiLiteralExpression host,
Configuration configuration,
JavaLanguageInjectionSupport support,
final HashMap<BaseInjection, Pair<PsiMethod, Integer>> injectionsMap,
final ArrayList<PsiElement> annotations) {
new ConcatenationInjector.InjectionProcessor(configuration, host) {
new ConcatenationInjector.InjectionProcessor(configuration, support, host) {
@Override
protected boolean processCommentInjectionInner(PsiVariable owner, PsiElement comment, BaseInjection injection) {
@@ -186,14 +186,10 @@ public class Configuration implements PersistentStateComponent<Element>, Modific
@NonNls public static final String COMPONENT_NAME = "LanguageInjectionConfiguration";
// element names
@NonNls private static final String TAG_INJECTION_NAME = "TAGS";
@NonNls private static final String ATTRIBUTE_INJECTION_NAME = "ATTRIBUTES";
@NonNls private static final String PARAMETER_INJECTION_NAME = "PARAMETERS";
@NonNls private static final String INSTRUMENTATION_TYPE_NAME = "INSTRUMENTATION";
@NonNls private static final String LANGUAGE_ANNOTATION_NAME = "LANGUAGE_ANNOTATION";
@NonNls private static final String PATTERN_ANNOTATION_NAME = "PATTERN_ANNOTATION";
@NonNls private static final String SUBST_ANNOTATION_NAME = "SUBST_ANNOTATION";
@NonNls private static final String ENTRY_NAME = "entry";
@NonNls private static final String RESOLVE_REFERENCES = "RESOLVE_REFERENCES";
@NonNls private static final String LOOK_FOR_VAR_ASSIGNMENTS = "LOOK_FOR_VAR_ASSIGNMENTS";
@NonNls private static final String USE_DFA_IF_AVAILABLE = "USE_DFA_IF_AVAILABLE";
@@ -242,7 +238,6 @@ public class Configuration implements PersistentStateComponent<Element>, Modific
for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) {
supports.put(support.getId(), support);
}
loadStateOld(element, supports.get(LanguageInjectionSupport.XML_SUPPORT_ID), supports.get(LanguageInjectionSupport.JAVA_SUPPORT_ID));
for (Element child : element.getChildren("injection")){
final String key = child.getAttributeValue("injector-id");
final LanguageInjectionSupport support = supports.get(key);
@@ -268,31 +263,6 @@ public class Configuration implements PersistentStateComponent<Element>, Modific
return places.length != 0 && result.length == 0? null : result;
}
private void loadStateOld(Element element, final LanguageInjectionSupport xmlSupport, final LanguageInjectionSupport javaSupport) {
if (xmlSupport != null) {
final Element xmlTagMarker = new Element("XmlTagInjection");
myInjections.get(LanguageInjectionSupport.XML_SUPPORT_ID).addAll(readExternal(element.getChild(TAG_INJECTION_NAME), new Factory<BaseInjection>() {
public BaseInjection create() {
return xmlSupport.createInjection(xmlTagMarker);
}
}));
final Element xmlAttributeMarker = new Element("XmlAttributeInjection");
myInjections.get(LanguageInjectionSupport.XML_SUPPORT_ID).addAll(readExternal(element.getChild(ATTRIBUTE_INJECTION_NAME), new Factory<BaseInjection>() {
public BaseInjection create() {
return xmlSupport.createInjection(xmlAttributeMarker);
}
}));
}
if (javaSupport != null) {
final Element javaMethodMarker = new Element("MethodParameterInjection");
myInjections.get(LanguageInjectionSupport.JAVA_SUPPORT_ID).addAll(readExternal(element.getChild(PARAMETER_INJECTION_NAME), new Factory<BaseInjection>() {
public BaseInjection create() {
return javaSupport.createInjection(javaMethodMarker);
}
}));
}
}
private static boolean readBoolean(Element element, String key, boolean defValue) {
final String value = JDOMExternalizerUtil.readField(element, key);
if (value == null) return defValue;
@@ -361,20 +331,6 @@ public class Configuration implements PersistentStateComponent<Element>, Modific
return element;
}
@SuppressWarnings({"unchecked"})
private static <T extends BaseInjection> List<T> readExternal(Element element, Factory<T> factory) {
final List<T> injections = new ArrayList<T>();
if (element != null) {
final List<Element> list = element.getChildren(ENTRY_NAME);
for (Element entry : list) {
final T o = factory.create();
o.loadState(entry);
injections.add(o);
}
}
return injections;
}
public static Configuration getInstance() {
return ServiceManager.getService(Configuration.class);
}
@@ -26,6 +26,7 @@ import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
@@ -36,6 +37,7 @@ import org.intellij.plugins.intelliLang.Configuration;
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.intellij.plugins.intelliLang.inject.config.ui.BaseInjectionPanel;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -45,10 +47,21 @@ import javax.swing.*;
*/
public abstract class AbstractLanguageInjectionSupport extends LanguageInjectionSupport {
public boolean useDefaultInjector(final PsiElement host) {
@Override
public boolean isApplicableTo(PsiLanguageInjectionHost host) {
return useDefaultInjector(host); // todo temporary plugin compatibility fix. TBR
}
public boolean useDefaultInjector(final PsiLanguageInjectionHost host) {
return false;
}
@Nullable
@Override
public BaseInjection findInjectionComment(@NotNull PsiElement host, @Nullable Ref<PsiElement> commentRef) {
return InjectorUtils.findCommentInjection(host, "comment", commentRef);
}
public boolean addInjectionInPlace(final Language language, final PsiLanguageInjectionHost psiElement) {
return false;
}
@@ -1,15 +1,15 @@
package org.intellij.plugins.intelliLang.inject;
import com.intellij.lang.Language;
import com.intellij.lang.injection.MultiHostInjector;
import com.intellij.lang.injection.MultiHostRegistrar;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.Trinity;
import com.intellij.psi.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.util.ArrayUtil;
import org.intellij.plugins.intelliLang.Configuration;
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -18,29 +18,53 @@ import java.util.List;
*/
public class CommentLanguageInjector implements MultiHostInjector {
private final LanguageInjectionSupport[] mySupports;
private final LanguageInjectionSupport myInjectorSupport = new AbstractLanguageInjectionSupport() {
@NotNull
@Override
public String getId() {
return "comment";
}
@Override
public boolean isApplicableTo(PsiLanguageInjectionHost host) {
return true;
}
@NotNull
@Override
public Class[] getPatternClasses() {
return ArrayUtil.EMPTY_CLASS_ARRAY;
}
};
/** @noinspection UnusedParameters*/
public CommentLanguageInjector(Configuration configuration) {
List<LanguageInjectionSupport> supports = new ArrayList<LanguageInjectionSupport>(InjectorUtils.getActiveInjectionSupports());
supports.add(myInjectorSupport);
mySupports = ArrayUtil.toObjectArray(supports, LanguageInjectionSupport.class);
}
@NotNull
public List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
return Collections.singletonList(PsiLanguageInjectionHost.class);
}
public void getLanguagesToInject(@NotNull final MultiHostRegistrar registrar, @NotNull final PsiElement context) {
if (!(context instanceof PsiLanguageInjectionHost) || !((PsiLanguageInjectionHost)context).isValidHost()) return;
PsiLanguageInjectionHost host = (PsiLanguageInjectionHost)context;
if (!host.isValidHost()) return;
if (context.getClass().getSimpleName().startsWith("XmlAttribute")) return; // no injection in XML attributes, they cannot be commented
ElementManipulator<PsiLanguageInjectionHost> manipulator = ElementManipulators.getManipulator(host);
if (manipulator == null) return;
TextRange rangeInElement = manipulator.getRangeInElement(host);
if (rangeInElement.isEmpty()) return;
PsiElement anchor = rangeInElement.getStartOffset() == 0 ? context.getParent() : context; // handle XmlText
BaseInjection injection = InjectorUtils.findCommentInjection(anchor, "comment", Ref.<PsiComment>create());
//BaseInjection injection = InjectorUtils.findCommentInjection(context, "comment", Ref.<PsiComment>create());
if (injection == null) return;
InjectedLanguage injectedLanguage = InjectedLanguage.create(injection.getInjectedLanguageId(), injection.getPrefix(), injection.getSuffix(), false);
Language language = injectedLanguage != null ? injectedLanguage.getLanguage() : null;
if (language != null) {
Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange> info =
Trinity.create(host, injectedLanguage, rangeInElement);
InjectorUtils.registerInjection(language, Collections.singletonList(info), context.getContainingFile(), registrar);
boolean applicableFound = false;
for (LanguageInjectionSupport support : mySupports) {
if (!support.isApplicableTo(host)) continue;
if (support == myInjectorSupport && applicableFound) continue;
applicableFound = true;
BaseInjection injection = support.findInjectionComment(host, null);
if (injection == null) continue;
if (!InjectorUtils.registerInjectionSimple(host, injection, support, registrar)) continue;
return;
}
}
}
@@ -16,11 +16,8 @@
package org.intellij.plugins.intelliLang.inject;
import com.intellij.lang.Language;
import com.intellij.lang.injection.MultiHostInjector;
import com.intellij.lang.injection.MultiHostRegistrar;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.Trinity;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.util.ArrayUtil;
@@ -28,7 +25,6 @@ import org.intellij.plugins.intelliLang.Configuration;
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -47,30 +43,18 @@ public final class DefaultLanguageInjector implements MultiHostInjector {
return Collections.singletonList(PsiLanguageInjectionHost.class);
}
public void getLanguagesToInject(@NotNull final MultiHostRegistrar registrar, @NotNull final PsiElement host) {
public void getLanguagesToInject(@NotNull final MultiHostRegistrar registrar, @NotNull final PsiElement context) {
if (!(context instanceof PsiLanguageInjectionHost) || !((PsiLanguageInjectionHost)context).isValidHost()) return;
PsiLanguageInjectionHost host = (PsiLanguageInjectionHost)context;
for (LanguageInjectionSupport support : mySupports) {
if (!support.isApplicableTo(host)) continue;
if (!support.useDefaultInjector(host)) continue;
for (BaseInjection injection : myInjectionConfiguration.getInjections(support.getId())) {
if (injection.acceptsPsiElement(host)) {
final Language language = InjectedLanguage.findLanguageById(injection.getInjectedLanguageId());
if (language == null) continue;
final InjectedLanguage injectedLanguage =
InjectedLanguage.create(injection.getInjectedLanguageId(), injection.getPrefix(), injection.getSuffix(), false);
List<TextRange> ranges = injection.getInjectedArea(host);
final List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> list =
new ArrayList<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>>(ranges.size());
for (TextRange range : ranges) {
list.add(Trinity.create((PsiLanguageInjectionHost)host, injectedLanguage, range));
}
//if (host.getChildren().length > 0) {
// host.putUserData(LanguageInjectionSupport.HAS_UNPARSABLE_FRAGMENTS, Boolean.TRUE);
//}
InjectorUtils.registerInjection(language, list, host.getContainingFile(), registrar);
InjectorUtils.registerSupport(support, true, registrar);
break;
}
if (!injection.acceptsPsiElement(host)) continue;
if (!InjectorUtils.registerInjectionSimple(host, injection, support, registrar)) continue;
return;
}
}
}
@@ -128,10 +128,10 @@ public class InjectLanguageAction implements IntentionAction {
try {
Language language = injectable.toLanguage();
for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) {
if (support.addInjectionInPlace(language, host)) {
((PsiModificationTrackerImpl)PsiManager.getInstance(project).getModificationTracker()).incCounter();
return;
}
if (!support.isApplicableTo(host)) continue;
if (!support.addInjectionInPlace(language, host)) continue;
((PsiModificationTrackerImpl)PsiManager.getInstance(project).getModificationTracker()).incCounter();
return;
}
if (TemporaryPlacesRegistry.getInstance(project).getLanguageInjectionSupport().addInjectionInPlace(language, host)) {
HintManager.getInstance().showInformationHint(editor, StringUtil.escapeXml(language.getDisplayName()) + " was temporarily injected");
@@ -16,10 +16,8 @@
package org.intellij.plugins.intelliLang.inject;
import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil;
import com.intellij.lang.Language;
import com.intellij.lang.injection.MultiHostRegistrar;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.*;
@@ -59,6 +57,32 @@ public class InjectorUtils {
}
public static boolean registerInjectionSimple(@NotNull PsiLanguageInjectionHost host,
@NotNull BaseInjection injection,
@Nullable LanguageInjectionSupport support,
@NotNull MultiHostRegistrar registrar) {
Language language = InjectedLanguage.findLanguageById(injection.getInjectedLanguageId());
if (language == null) return false;
InjectedLanguage injectedLanguage =
InjectedLanguage.create(injection.getInjectedLanguageId(), injection.getPrefix(), injection.getSuffix(), false);
List<TextRange> ranges = injection.getInjectedArea(host);
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> list = ContainerUtil.newArrayListWithExpectedSize(ranges.size());
for (TextRange range : ranges) {
list.add(Trinity.create(host, injectedLanguage, range));
}
//if (host.getChildren().length > 0) {
// host.putUserData(LanguageInjectionSupport.HAS_UNPARSABLE_FRAGMENTS, Boolean.TRUE);
//}
registerInjection(language, list, host.getContainingFile(), registrar);
if (support != null) {
registerSupport(support, true, registrar);
}
return !ranges.isEmpty();
}
public static void registerInjection(Language language, List<Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange>> list, PsiFile containingFile, MultiHostRegistrar registrar) {
// if language isn't injected when length == 0, subsequent edits will not cause the language to be injected as well.
// Maybe IDEA core is caching a bit too aggressively here?
@@ -196,12 +220,12 @@ public class InjectorUtils {
return true;
}
public static BaseInjection findCommentInjection(PsiElement context, final String supportId, final Ref<PsiComment> causeRef) {
public static BaseInjection findCommentInjection(PsiElement context, final String supportId, final Ref<PsiElement> causeRef) {
return findNearestComment(context, new NullableFunction<PsiComment, BaseInjection>() {
@Nullable
@Override
public BaseInjection fun(PsiComment comment) {
causeRef.set(comment);
if (causeRef != null) causeRef.set(comment);
String text = ElementManipulators.getValueText(comment).trim();
return detectInjectionFromText(supportId, text);
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.ui.SimpleColoredText;
@@ -31,6 +32,7 @@ import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Gregory.Shrago
@@ -44,9 +46,6 @@ public abstract class LanguageInjectionSupport {
public static Key<LanguageInjectionSupport> INJECTOR_SUPPORT = Key.create("INJECTOR_SUPPORT");
public static Key<LanguageInjectionSupport> SETTINGS_EDITOR = Key.create("SETTINGS_EDITOR");
@NonNls public static final String XML_SUPPORT_ID = "xml";
@NonNls public static final String JAVA_SUPPORT_ID = "java";
@NonNls
@NotNull
public abstract String getId();
@@ -54,7 +53,12 @@ public abstract class LanguageInjectionSupport {
@NotNull
public abstract Class[] getPatternClasses();
public abstract boolean useDefaultInjector(final PsiElement host);
public abstract boolean isApplicableTo(PsiLanguageInjectionHost host);
public abstract boolean useDefaultInjector(PsiLanguageInjectionHost host);
@Nullable
public abstract BaseInjection findInjectionComment(@NotNull PsiElement host, @Nullable Ref<PsiElement> commentRef);
public abstract boolean addInjectionInPlace(final Language language, final PsiLanguageInjectionHost psiElement);
@@ -47,18 +47,20 @@ public class TemporaryPlacesInjector implements MultiHostInjector {
}
public void getLanguagesToInject(@NotNull final MultiHostRegistrar registrar, @NotNull final PsiElement context) {
if (!(context instanceof PsiLanguageInjectionHost) || !((PsiLanguageInjectionHost)context).isValidHost()) return;
PsiLanguageInjectionHost host = (PsiLanguageInjectionHost)context;
PsiFile containingFile = context.getContainingFile();
InjectedLanguage injectedLanguage = myRegistry.getLanguageFor(host, containingFile);
Language language = injectedLanguage != null ? injectedLanguage.getLanguage() : null;
if (language != null) {
final ElementManipulator<PsiLanguageInjectionHost> manipulator = ElementManipulators.getManipulator(host);
if (manipulator == null) return;
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage,TextRange>> trinities =
Collections.singletonList(Trinity.create(host, injectedLanguage, manipulator.getRangeInElement(host)));
InjectorUtils.registerInjection(language, trinities, containingFile, registrar);
InjectorUtils.registerSupport(myRegistry.getLanguageInjectionSupport(), false, registrar);
}
if (language == null) return;
final ElementManipulator<PsiLanguageInjectionHost> manipulator = ElementManipulators.getManipulator(host);
if (manipulator == null) return;
List<Trinity<PsiLanguageInjectionHost, InjectedLanguage,TextRange>> trinities =
Collections.singletonList(Trinity.create(host, injectedLanguage, manipulator.getRangeInElement(host)));
InjectorUtils.registerInjection(language, trinities, containingFile, registrar);
InjectorUtils.registerSupport(myRegistry.getLanguageInjectionSupport(), false, registrar);
}
}
@@ -50,6 +50,11 @@ public class TemporaryPlacesRegistry {
return "temp";
}
@Override
public boolean isApplicableTo(PsiLanguageInjectionHost host) {
return true;
}
@NotNull
@Override
public Class[] getPatternClasses() {
@@ -23,7 +23,7 @@ import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlTag;
import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport;
import org.intellij.plugins.intelliLang.inject.xml.XmlLanguageInjectionSupport;
import org.intellij.plugins.intelliLang.util.StringMatcher;
import org.jaxen.JaxenException;
import org.jaxen.XPath;
@@ -60,7 +60,7 @@ public class AbstractTagInjection extends BaseInjection {
private boolean myApplyToSubTagTexts;
public AbstractTagInjection() {
super(LanguageInjectionSupport.XML_SUPPORT_ID);
super(XmlLanguageInjectionSupport.XML_SUPPORT_ID);
}
@NotNull
@@ -24,15 +24,13 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogBuilder;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlText;
import com.intellij.psi.xml.*;
import com.intellij.util.Consumer;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.ContainerUtil;
@@ -48,6 +46,7 @@ import org.intellij.plugins.intelliLang.inject.config.ui.XmlTagPanel;
import org.intellij.plugins.intelliLang.inject.config.ui.configurables.XmlAttributeInjectionConfigurable;
import org.intellij.plugins.intelliLang.inject.config.ui.configurables.XmlTagInjectionConfigurable;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -60,6 +59,8 @@ import java.util.Collections;
*/
public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSupport {
@NonNls public static final String XML_SUPPORT_ID = "xml";
private static boolean isMine(final PsiLanguageInjectionHost host) {
if (host instanceof XmlAttributeValue) {
final PsiElement p = host.getParent();
@@ -85,8 +86,16 @@ public class XmlLanguageInjectionSupport extends AbstractLanguageInjectionSuppor
return new Class[] {XmlPatterns.class};
}
public boolean useDefaultInjector(final PsiElement host) {
return false;
@Override
public boolean isApplicableTo(PsiLanguageInjectionHost host) {
return host instanceof XmlElement;
}
@Nullable
@Override
public BaseInjection findInjectionComment(@NotNull PsiElement host, @Nullable Ref<PsiElement> commentRef) {
if (host instanceof XmlAttributeValue) return null;
return InjectorUtils.findCommentInjection(host instanceof XmlText ? host.getParent() : host, getId(), commentRef);
}
@Override
@@ -63,7 +63,7 @@ public final class XmlLanguageInjector implements MultiHostInjector {
public XmlLanguageInjector(Configuration configuration) {
myConfiguration = configuration;
mySupport = InjectorUtils.findNotNullInjectionSupport(LanguageInjectionSupport.XML_SUPPORT_ID);
mySupport = InjectorUtils.findNotNullInjectionSupport(XmlLanguageInjectionSupport.XML_SUPPORT_ID);
}
@NotNull
@@ -104,7 +104,7 @@ public final class XmlLanguageInjector implements MultiHostInjector {
if (place instanceof XmlTag) {
final XmlTag xmlTag = (XmlTag)place;
List<BaseInjection> injections = myConfiguration.getInjections(LanguageInjectionSupport.XML_SUPPORT_ID);
List<BaseInjection> injections = myConfiguration.getInjections(XmlLanguageInjectionSupport.XML_SUPPORT_ID);
//noinspection ForLoopReplaceableByForEach
for (int i = 0, injectionsSize = injections.size(); i < injectionsSize; i++) {
final BaseInjection injection = injections.get(i);
@@ -168,7 +168,7 @@ public final class XmlLanguageInjector implements MultiHostInjector {
return;
}
List<BaseInjection> injections = myConfiguration.getInjections(LanguageInjectionSupport.XML_SUPPORT_ID);
List<BaseInjection> injections = myConfiguration.getInjections(XmlLanguageInjectionSupport.XML_SUPPORT_ID);
//noinspection ForLoopReplaceableByForEach
for (int i = 0, size = injections.size(); i < size; i++) {
BaseInjection injection = injections.get(i);
@@ -236,7 +236,7 @@ public final class XmlLanguageInjector implements MultiHostInjector {
Trinity<Long, Pattern, Collection<String>> index = myXmlIndex;
if (index == null || myConfiguration.getModificationCount() != index.first.longValue()) {
final Map<ElementPattern<?>, BaseInjection> map = new THashMap<ElementPattern<?>, BaseInjection>();
for (BaseInjection injection : myConfiguration.getInjections(LanguageInjectionSupport.XML_SUPPORT_ID)) {
for (BaseInjection injection : myConfiguration.getInjections(XmlLanguageInjectionSupport.XML_SUPPORT_ID)) {
for (InjectionPlace place : injection.getInjectionPlaces()) {
if (!place.isEnabled() || place.getElementPattern() == null) continue;
map.put(place.getElementPattern(), injection);
@@ -15,16 +15,14 @@
*/
package org.intellij.plugins.intelliLang.inject.groovy;
import com.intellij.lang.Language;
import com.intellij.lang.injection.MultiHostInjector;
import com.intellij.lang.injection.MultiHostRegistrar;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import org.intellij.plugins.intelliLang.Configuration;
import org.intellij.plugins.intelliLang.inject.InjectedLanguage;
import org.intellij.plugins.intelliLang.inject.InjectorUtils;
import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport;
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.intellij.plugins.intelliLang.util.AnnotationUtilEx;
import org.intellij.plugins.intelliLang.util.PsiUtilEx;
@@ -94,23 +92,14 @@ public class GrConcatenationInjector implements MultiHostInjector {
final PsiAnnotation[] annotations = getAnnotationFrom(annotationOwner, pair, true, true);
if (annotations.length > 0) {
final String id = AnnotationUtilEx.calcAnnotationValue(annotations, "value");
final String prefix = AnnotationUtilEx.calcAnnotationValue(annotations, "prefix");
final String suffix = AnnotationUtilEx.calcAnnotationValue(annotations, "suffix");
final BaseInjection injection = new BaseInjection(GroovyLanguageInjectionSupport.GROOVY_SUPPORT_ID);
if (prefix != null) injection.setPrefix(prefix);
if (suffix != null) injection.setSuffix(suffix);
if (id != null) injection.setInjectedLanguageId(id);
BaseInjection injection = new BaseInjection(GroovyLanguageInjectionSupport.GROOVY_SUPPORT_ID);
//todo suffixes & prefixes are not supported
final Language language = InjectedLanguage.findLanguageById(injection.getInjectedLanguageId());
injection.setPrefix(StringUtil.notNullize(AnnotationUtilEx.calcAnnotationValue(annotations, "prefix")));
injection.setSuffix(StringUtil.notNullize(AnnotationUtilEx.calcAnnotationValue(annotations, "suffix")));
injection.setInjectedLanguageId(StringUtil.notNullize(AnnotationUtilEx.calcAnnotationValue(annotations, "value")));
Trinity<PsiLanguageInjectionHost, InjectedLanguage, TextRange> info = Trinity.create(
host,
InjectedLanguage.create(injection.getInjectedLanguageId(), prefix, suffix, true),
ElementManipulators.getManipulator(host).getRangeInElement(host)
);
InjectorUtils.registerInjection(language, Collections.singletonList(info), host.getContainingFile(), registrar);
LanguageInjectionSupport support = InjectorUtils.findInjectionSupport(GroovyLanguageInjectionSupport.GROOVY_SUPPORT_ID);
InjectorUtils.registerInjectionSimple(host, injection, support, registrar);
}
}
@@ -62,10 +62,15 @@ public class GroovyLanguageInjectionSupport extends AbstractLanguageInjectionSup
return new Class[] {GroovyPatterns.class};
}
public boolean useDefaultInjector(final PsiElement host) {
@Override
public boolean isApplicableTo(PsiLanguageInjectionHost host) {
return host instanceof GroovyPsiElement;
}
public boolean useDefaultInjector(PsiLanguageInjectionHost host) {
return true;
}
@Override
public String getHelpId() {
return "reference.settings.language.injection.groovy";