mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-04 08:51:02 +07:00
Support for temporary and configuration-based IntelliLang injections in Python (PY-10983, PY-10721)
This commit is contained in:
@@ -7,5 +7,7 @@
|
|||||||
</extensions>
|
</extensions>
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
<patterns.patternClass className="com.jetbrains.python.patterns.PythonPatterns" alias="py"/>
|
<patterns.patternClass className="com.jetbrains.python.patterns.PythonPatterns" alias="py"/>
|
||||||
|
<multiHostInjector implementation="com.jetbrains.python.intelliLang.PyTemporaryInjector"/>
|
||||||
|
<multiHostInjector implementation="com.jetbrains.python.intelliLang.PyConfigurationInjector"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.jetbrains.python.intelliLang;
|
||||||
|
|
||||||
|
import com.intellij.lang.Language;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.jetbrains.python.codeInsight.PyInjectorBase;
|
||||||
|
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.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author vlan
|
||||||
|
*/
|
||||||
|
public class PyConfigurationInjector extends PyInjectorBase {
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Language getInjectedLanguage(@NotNull PsiElement context) {
|
||||||
|
for (LanguageInjectionSupport support : InjectorUtils.getActiveInjectionSupports()) {
|
||||||
|
if (support instanceof PyLanguageInjectionSupport) {
|
||||||
|
final Configuration configuration = Configuration.getInstance();
|
||||||
|
for (BaseInjection injection : configuration.getInjections(support.getId())) {
|
||||||
|
if (injection.acceptsPsiElement(context)) {
|
||||||
|
return InjectedLanguage.findLanguageById(injection.getInjectedLanguageId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,22 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.jetbrains.python.intelliLang;
|
package com.jetbrains.python.intelliLang;
|
||||||
|
|
||||||
import com.intellij.lang.Language;
|
|
||||||
import com.intellij.openapi.util.TextRange;
|
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import com.intellij.psi.PsiLanguageInjectionHost;
|
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||||
import com.jetbrains.python.patterns.PythonPatterns;
|
import com.jetbrains.python.patterns.PythonPatterns;
|
||||||
import com.jetbrains.python.psi.PyElement;
|
import com.jetbrains.python.psi.PyElement;
|
||||||
import com.jetbrains.python.psi.PyStringLiteralExpression;
|
|
||||||
import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport;
|
import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport;
|
||||||
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
|
|
||||||
import org.jdom.Element;
|
|
||||||
import org.jetbrains.annotations.NonNls;
|
import org.jetbrains.annotations.NonNls;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author yole
|
* @author yole
|
||||||
*/
|
*/
|
||||||
@@ -54,33 +46,6 @@ public class PyLanguageInjectionSupport extends AbstractLanguageInjectionSupport
|
|||||||
return host instanceof PyElement;
|
return host instanceof PyElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean useDefaultInjector(PsiLanguageInjectionHost host) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BaseInjection createInjection(Element element) {
|
|
||||||
// This is how DefaultLanguageInjector gets its injection ranges
|
|
||||||
return new BaseInjection(getId()) {
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public List<TextRange> getInjectedArea(PsiElement element) {
|
|
||||||
if (element instanceof PyStringLiteralExpression) {
|
|
||||||
return ((PyStringLiteralExpression)element).getStringValueTextRanges();
|
|
||||||
}
|
|
||||||
return super.getInjectedArea(element);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addInjectionInPlace(Language language, PsiLanguageInjectionHost psiElement) {
|
|
||||||
// XXX: Disable temporary injections via intention actions for Python elements, since TemporaryPlacesInjector cannot handle elements
|
|
||||||
// with multiple injection text ranges (PY-10691)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public String getHelpId() {
|
public String getHelpId() {
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.jetbrains.python.intelliLang;
|
||||||
|
|
||||||
|
import com.intellij.lang.Language;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import com.intellij.psi.PsiLanguageInjectionHost;
|
||||||
|
import com.jetbrains.python.codeInsight.PyInjectorBase;
|
||||||
|
import org.intellij.plugins.intelliLang.inject.InjectedLanguage;
|
||||||
|
import org.intellij.plugins.intelliLang.inject.TemporaryPlacesRegistry;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author vlan
|
||||||
|
*/
|
||||||
|
public class PyTemporaryInjector extends PyInjectorBase {
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Language getInjectedLanguage(@NotNull PsiElement context) {
|
||||||
|
final TemporaryPlacesRegistry registry = TemporaryPlacesRegistry.getInstance(context.getProject());
|
||||||
|
if (context instanceof PsiLanguageInjectionHost) {
|
||||||
|
final PsiFile file = context.getContainingFile();
|
||||||
|
final InjectedLanguage injectedLanguage = registry.getLanguageFor((PsiLanguageInjectionHost)context, file);
|
||||||
|
if (injectedLanguage != null) {
|
||||||
|
return injectedLanguage.getLanguage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import com.jetbrains.python.psi.*;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.jetbrains.python.inspections.PyStringFormatParser.*;
|
import static com.jetbrains.python.inspections.PyStringFormatParser.*;
|
||||||
@@ -31,15 +32,22 @@ import static com.jetbrains.python.inspections.PyStringFormatParser.*;
|
|||||||
* @author vlan
|
* @author vlan
|
||||||
*/
|
*/
|
||||||
public class PyInjectionUtil {
|
public class PyInjectionUtil {
|
||||||
|
public static final List<Class<? extends PyExpression>> ELEMENTS_TO_INJECT_IN =
|
||||||
|
Arrays.asList(PyStringLiteralExpression.class, PyParenthesizedExpression.class, PyBinaryExpression.class, PyCallExpression.class);
|
||||||
|
|
||||||
private PyInjectionUtil() {}
|
private PyInjectionUtil() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the element is the largest expression that represents a string literal, possibly with concatenation, parentheses,
|
* Returns the largest expression in the specified context that represents a string literal suitable for language injection, possibly
|
||||||
* or formatting.
|
* with concatenation, parentheses, or formatting.
|
||||||
*/
|
*/
|
||||||
public static boolean isLargestStringLiteral(@NotNull PsiElement element) {
|
@Nullable
|
||||||
final PsiElement parent = element.getParent();
|
public static PsiElement getLargestStringLiteral(@NotNull PsiElement context) {
|
||||||
return isStringLiteralPart(element) && (parent == null || !isStringLiteralPart(parent));
|
PsiElement element = null;
|
||||||
|
for (PsiElement current = context; current != null && isStringLiteralPart(current); current = current.getParent()) {
|
||||||
|
element = current;
|
||||||
|
}
|
||||||
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.jetbrains.python.codeInsight;
|
||||||
|
|
||||||
|
import com.intellij.lang.Language;
|
||||||
|
import com.intellij.lang.injection.MultiHostInjector;
|
||||||
|
import com.intellij.lang.injection.MultiHostRegistrar;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author vlan
|
||||||
|
*/
|
||||||
|
public abstract class PyInjectorBase implements MultiHostInjector {
|
||||||
|
@Override
|
||||||
|
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
|
||||||
|
final Language language = getInjectedLanguage(context);
|
||||||
|
if (language != null) {
|
||||||
|
final PsiElement element = PyInjectionUtil.getLargestStringLiteral(context);
|
||||||
|
if (element != null) {
|
||||||
|
registrar.startInjecting(language);
|
||||||
|
PyInjectionUtil.registerStringLiteralInjection(element, registrar);
|
||||||
|
registrar.doneInjecting();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
|
||||||
|
return PyInjectionUtil.ELEMENTS_TO_INJECT_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public abstract Language getInjectedLanguage(@NotNull PsiElement context);
|
||||||
|
}
|
||||||
@@ -67,7 +67,7 @@ public class PythonRegexpInjector implements MultiHostInjector {
|
|||||||
@Override
|
@Override
|
||||||
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
|
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
|
||||||
final PsiElement contextParent = context.getParent();
|
final PsiElement contextParent = context.getParent();
|
||||||
if (PyInjectionUtil.isLargestStringLiteral(context) && contextParent instanceof PyArgumentList) {
|
if (PyInjectionUtil.getLargestStringLiteral(context) == context && contextParent instanceof PyArgumentList) {
|
||||||
final PyExpression[] args = ((PyArgumentList)contextParent).getArguments();
|
final PyExpression[] args = ((PyArgumentList)contextParent).getArguments();
|
||||||
int index = ArrayUtil.indexOf(args, context);
|
int index = ArrayUtil.indexOf(args, context);
|
||||||
PyCallExpression call = PsiTreeUtil.getParentOfType(context, PyCallExpression.class);
|
PyCallExpression call = PsiTreeUtil.getParentOfType(context, PyCallExpression.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user