diff --git a/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml b/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml
index 2ffa9f7c2325..624d146a0378 100644
--- a/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml
+++ b/python/IntelliLang-python/src/META-INF/intellilang-python-support.xml
@@ -7,5 +7,7 @@
+
+
\ No newline at end of file
diff --git a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyConfigurationInjector.java b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyConfigurationInjector.java
new file mode 100644
index 000000000000..f672f5d17ee6
--- /dev/null
+++ b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyConfigurationInjector.java
@@ -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;
+ }
+}
diff --git a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java
index 5a91db5ce994..43db1f20d814 100644
--- a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java
+++ b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyLanguageInjectionSupport.java
@@ -15,22 +15,14 @@
*/
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.jetbrains.python.patterns.PythonPatterns;
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.config.BaseInjection;
-import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.List;
-
/**
* @author yole
*/
@@ -54,33 +46,6 @@ public class PyLanguageInjectionSupport extends AbstractLanguageInjectionSupport
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 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
@Override
public String getHelpId() {
diff --git a/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyTemporaryInjector.java b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyTemporaryInjector.java
new file mode 100644
index 000000000000..d88905d623cf
--- /dev/null
+++ b/python/IntelliLang-python/src/com/jetbrains/python/intelliLang/PyTemporaryInjector.java
@@ -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;
+ }
+}
diff --git a/python/src/com/jetbrains/python/codeInsight/PyInjectionUtil.java b/python/src/com/jetbrains/python/codeInsight/PyInjectionUtil.java
index d68e6c61c47f..d0a49fe810d7 100644
--- a/python/src/com/jetbrains/python/codeInsight/PyInjectionUtil.java
+++ b/python/src/com/jetbrains/python/codeInsight/PyInjectionUtil.java
@@ -23,6 +23,7 @@ import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.Arrays;
import java.util.List;
import static com.jetbrains.python.inspections.PyStringFormatParser.*;
@@ -31,15 +32,22 @@ import static com.jetbrains.python.inspections.PyStringFormatParser.*;
* @author vlan
*/
public class PyInjectionUtil {
+ public static final List> ELEMENTS_TO_INJECT_IN =
+ Arrays.asList(PyStringLiteralExpression.class, PyParenthesizedExpression.class, PyBinaryExpression.class, PyCallExpression.class);
+
private PyInjectionUtil() {}
/**
- * Returns true if the element is the largest expression that represents a string literal, possibly with concatenation, parentheses,
- * or formatting.
+ * Returns the largest expression in the specified context that represents a string literal suitable for language injection, possibly
+ * with concatenation, parentheses, or formatting.
*/
- public static boolean isLargestStringLiteral(@NotNull PsiElement element) {
- final PsiElement parent = element.getParent();
- return isStringLiteralPart(element) && (parent == null || !isStringLiteralPart(parent));
+ @Nullable
+ public static PsiElement getLargestStringLiteral(@NotNull PsiElement context) {
+ PsiElement element = null;
+ for (PsiElement current = context; current != null && isStringLiteralPart(current); current = current.getParent()) {
+ element = current;
+ }
+ return element;
}
/**
diff --git a/python/src/com/jetbrains/python/codeInsight/PyInjectorBase.java b/python/src/com/jetbrains/python/codeInsight/PyInjectorBase.java
new file mode 100644
index 000000000000..48b62368af3d
--- /dev/null
+++ b/python/src/com/jetbrains/python/codeInsight/PyInjectorBase.java
@@ -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);
+}
diff --git a/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpInjector.java b/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpInjector.java
index 39c9aff38410..bb23c475a576 100644
--- a/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpInjector.java
+++ b/python/src/com/jetbrains/python/codeInsight/regexp/PythonRegexpInjector.java
@@ -67,7 +67,7 @@ public class PythonRegexpInjector implements MultiHostInjector {
@Override
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) {
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();
int index = ArrayUtil.indexOf(args, context);
PyCallExpression call = PsiTreeUtil.getParentOfType(context, PyCallExpression.class);