mirror of
https://github.com/JetBrains/intellij-sdk-code-samples.git
synced 2025-07-28 01:07:49 +08:00
Add entry to content update. Minor edit.
Thanks Yuriy for the hint of regex groups in `value-pattern`.
This commit is contained in:
parent
66279c999e
commit
507fc60407
@ -9,6 +9,12 @@ See [GitHub Changelog](https://github.com/JetBrains/intellij-sdk-docs/commits/ma
|
|||||||
|
|
||||||
## 2021
|
## 2021
|
||||||
|
|
||||||
|
### November-21
|
||||||
|
|
||||||
|
Language Injection
|
||||||
|
: Add [Language Injection](language_injection.md) section that shows how the IntelliJ Platform handles different languages within the same source file.
|
||||||
|
|
||||||
|
|
||||||
### September-21
|
### September-21
|
||||||
|
|
||||||
IDE Infrastructure
|
IDE Infrastructure
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[//]: # (title: Language Injection)
|
[//]: # (title: Language Injection)
|
||||||
|
|
||||||
<!-- Copyright 2000-2020 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
<!-- Copyright 2000-2021 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. -->
|
||||||
|
|
||||||
Language injection is the way the IntelliJ Platform handles different languages within the same source file. Well-known examples are:
|
Language injection is the way the IntelliJ Platform handles different languages within the same source file. Well-known examples are:
|
||||||
|
|
||||||
@ -12,13 +12,13 @@ Injected code is always bound to a specific context that depends on the surround
|
|||||||
|
|
||||||
<tabs>
|
<tabs>
|
||||||
<tab title="Regex">
|
<tab title="Regex">
|
||||||
<img src="regex_language_injection.png" alt="Table of Contents" width="460" border-effect="line"/>
|
<img src="regex_language_injection.png" alt="Regex Language Injection" width="460" border-effect="line"/>
|
||||||
</tab>
|
</tab>
|
||||||
<tab title="SQL">
|
<tab title="SQL">
|
||||||
<img src="sql_language_injection.png" alt="Table of Contents" width="460" border-effect="line"/>
|
<img src="sql_language_injection.png" alt="SQL Language Injection" width="460" border-effect="line"/>
|
||||||
</tab>
|
</tab>
|
||||||
<tab title="Markdown">
|
<tab title="Markdown">
|
||||||
<img src="markdown_code_language_injection.png" alt="Table of Contents" width="460" border-effect="line"/>
|
<img src="markdown_code_language_injection.png" alt="Markdown Language Injection" width="460" border-effect="line"/>
|
||||||
</tab>
|
</tab>
|
||||||
</tabs>
|
</tabs>
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ The injections shown are configured through XML files and loaded automatically.
|
|||||||
Let’s take a look at the Java `String.matches()` method that injects the RegExp language into the string of the first argument.
|
Let’s take a look at the Java `String.matches()` method that injects the RegExp language into the string of the first argument.
|
||||||
In the IntelliLang settings, it is defined as one possible injection in Java code.
|
In the IntelliLang settings, it is defined as one possible injection in Java code.
|
||||||
|
|
||||||
<img src="language_injection_settings.png" alt="Table of Contents" width="706" border-effect="line"/>
|
{border-effect="line"}
|
||||||
|
|
||||||
Double-clicking on this entry shows the exact context where a RegExp can be injected, and `String.matches()` is one of several possibilities.
|
Double-clicking on this entry shows the exact context where a RegExp can be injected, and `String.matches()` is one of several possibilities.
|
||||||
On the plugin side, these entries are defined in the file [`javaInjections.xml`](upsource:///plugins/IntelliLang/java-support/resources/javaInjections.xml):
|
On the plugin side, these entries are defined in the file [`javaInjections.xml`](upsource:///plugins/IntelliLang/java-support/resources/javaInjections.xml):
|
||||||
@ -55,7 +55,12 @@ On the plugin side, these entries are defined in the file [`javaInjections.xml`]
|
|||||||
<injection language="RegExp" injector-id="java">
|
<injection language="RegExp" injector-id="java">
|
||||||
<display-name>String (java.lang)</display-name>
|
<display-name>String (java.lang)</display-name>
|
||||||
...
|
...
|
||||||
<place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("matches").withParameters("java.lang.String").definedInClass("java.lang.String"))]]></place>
|
<place><![CDATA[
|
||||||
|
psiParameter()
|
||||||
|
.ofMethod(0, psiMethod().withName("matches")
|
||||||
|
.withParameters("java.lang.String")
|
||||||
|
.definedInClass("java.lang.String"))
|
||||||
|
]]></place>
|
||||||
</injection>
|
</injection>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -107,13 +112,13 @@ For instance, injecting SQLite into Python code is specified by the following op
|
|||||||
|
|
||||||
Inside an injection, the following tags can be used:
|
Inside an injection, the following tags can be used:
|
||||||
|
|
||||||
| XML Tag | Description |
|
| XML Tag | Description |
|
||||||
|---------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `<display-name>` | A short name for the injection. |
|
| `<display-name>` | A short name for the injection. |
|
||||||
| `<place>` | The element pattern that defines where an injection will take place. The content is wrapped in `![CDATA[...]]`. |
|
| `<place>` | The element pattern that defines where an injection will take place. The content is wrapped in `![CDATA[...]]`. |
|
||||||
| `<prefix>` and `<suffix>` | Static content that is wrapped around the injected code, e.g., to make it a valid expression. For example, to a CSS color specification inside a string, it can be wrapped with the prefix `div { color:` and the suffix `;}` to make it a valid CSS expression. |
|
| `<prefix>` and `<suffix>` | Static content that is wrapped around the injected code, e.g., to make it a valid expression. For example, to a CSS color specification inside a string, it can be wrapped with the prefix `div { color:` and the suffix `;}` to make it a valid CSS expression. |
|
||||||
| `<value-pattern>` | A regex for the content that specifies when this injection should be applied. |
|
| `<value-pattern>` | A regex for the content that specifies when this injection should be applied. Regex groups can specify the text range of the injection (e.g. `^javascript:(.+)`, see [`xmlInjections-html.xml`](upsource:///plugins/IntelliLang/xml-support/resources/xmlInjections-html.xml)). |
|
||||||
| `<ignore-pattern>` | A regex for the content that specifies when this injection should not be applied. |
|
| `<ignore-pattern>` | A regex for the content that specifies when this injection should not be applied. |
|
||||||
|
|
||||||
#### Create an XML File to Load the Configuration
|
#### Create an XML File to Load the Configuration
|
||||||
|
|
||||||
@ -134,7 +139,9 @@ The injections are an optional dependency that only work when IntelliLang is ena
|
|||||||
Therefore, you load the configuration optionally in your main <path>plugin.xml</path>:
|
Therefore, you load the configuration optionally in your main <path>plugin.xml</path>:
|
||||||
|
|
||||||
````xml
|
````xml
|
||||||
<depends optional="true" config-file="myLanguageID-injections.xml">org.intellij.intelliLang</depends>
|
<depends optional="true" config-file="myLanguageID-injections.xml">
|
||||||
|
org.intellij.intelliLang
|
||||||
|
</depends>
|
||||||
````
|
````
|
||||||
|
|
||||||
## LanguageInjectionContributor and LanguageInjectionPerformer
|
## LanguageInjectionContributor and LanguageInjectionPerformer
|
||||||
@ -149,10 +156,12 @@ public final class MyConfigInjector implements LanguageInjectionContributor {
|
|||||||
public Injection getInjection(@NotNull PsiElement context) {
|
public Injection getInjection(@NotNull PsiElement context) {
|
||||||
if (!isConfigPlace(context)) return null;
|
if (!isConfigPlace(context)) return null;
|
||||||
if (shouldInjectYaml(context)) {
|
if (shouldInjectYaml(context)) {
|
||||||
return new SimpleInjection(YAMLLanguage.INSTANCE.getID(), "", "", null);
|
return new SimpleInjection(
|
||||||
|
YAMLLanguage.INSTANCE.getID(), "", "", null);
|
||||||
}
|
}
|
||||||
else if (shouldInjectJSON(context)) {
|
else if (shouldInjectJSON(context)) {
|
||||||
return new SimpleInjection(JsonLanguage.INSTANCE.getID(), "", "", null);
|
return new SimpleInjection(
|
||||||
|
JsonLanguage.INSTANCE.getID(), "", "", null);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -162,7 +171,9 @@ public Injection getInjection(@NotNull PsiElement context) {
|
|||||||
Register the implementation in your <path>plugin.xml</path>:
|
Register the implementation in your <path>plugin.xml</path>:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<languageInjectionContributor implementationClass="MyConfigInjector" language="YourLanguage"/>
|
<languageInjectionContributor
|
||||||
|
implementationClass="MyConfigInjector"
|
||||||
|
language="YourLanguage"/>
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want more control over how the injection should be done then implement the `com.intellij.languageInjectionPerformer` EP which allows for complex language injections, e.g. for concatenation or interpolation of strings.
|
If you want more control over how the injection should be done then implement the `com.intellij.languageInjectionPerformer` EP which allows for complex language injections, e.g. for concatenation or interpolation of strings.
|
||||||
@ -184,11 +195,15 @@ Plugin authors need to implement `getLanguagesToInject()` to provide a list of p
|
|||||||
For example, to inject regular expressions into Java string literal, you can override this method with something similar to this:
|
For example, to inject regular expressions into Java string literal, you can override this method with something similar to this:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
class MyRegExpToJavaInjector implements MultiHostInjector {
|
public class MyRegExpToJavaInjector implements MultiHostInjector {
|
||||||
void getLanguagesToInject(MultiHostRegistrar registrar, PsiElement context) {
|
public void getLanguagesToInject(
|
||||||
if (context instanceof PsiLiteralExpression && looksLikeAGoodPlaceToInject(context)) {
|
MultiHostRegistrar registrar, PsiElement context) {
|
||||||
registrar.startInjecting(REGEXP_LANG)
|
if (context instanceof PsiLiteralExpression &&
|
||||||
.addPlace(null,null,context,innerRangeStrippingQuotes(context));
|
looksLikeAGoodPlaceToInject(context)) {
|
||||||
|
registrar
|
||||||
|
.startInjecting(REGEXP_LANG)
|
||||||
|
.addPlace(null,null,
|
||||||
|
context,innerRangeStrippingQuotes(context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,7 +213,12 @@ A more complex example is when you need to inject into several fragments at once
|
|||||||
For example, if we have an XML-based DSL:
|
For example, if we have an XML-based DSL:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<myDSL><method><name>foo</name><body>System.out.println(42);</body></method></myDSL>
|
<myDSL>
|
||||||
|
<method>
|
||||||
|
<name>foo</name>
|
||||||
|
<body>System.out.println(42);</body>
|
||||||
|
</method>
|
||||||
|
</myDSL>
|
||||||
```
|
```
|
||||||
|
|
||||||
which should be converted to the equivalent Java code:
|
which should be converted to the equivalent Java code:
|
||||||
@ -210,13 +230,19 @@ class MyDsl { void foo() { System.out.println(42); } }
|
|||||||
Here, we need to inject Java into several places at once, i.e. method name and its body:
|
Here, we need to inject Java into several places at once, i.e. method name and its body:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
class MyBizarreDSLInjector implements MultiHostInjector {
|
public class MyBizarreDSLInjector implements MultiHostInjector {
|
||||||
void getLanguagesToInject(MultiHostRegistrar registrar, PsiElement context) {
|
public void getLanguagesToInject(
|
||||||
|
MultiHostRegistrar registrar, PsiElement context) {
|
||||||
if (isMethodTag(context)) {
|
if (isMethodTag(context)) {
|
||||||
registrar.startInjecting(JavaLanguage.INSTANCE);
|
registrar.startInjecting(JavaLanguage.INSTANCE);
|
||||||
// construct class header, method header, inject method name, append code block start
|
|
||||||
registrar.addPlace("class MyDsl { void ", "() {", context, rangeForMethodName(context));
|
// construct class header, method header,
|
||||||
// inject method body, append closing braces to form a valid Java class structure
|
// inject method name, append code block start
|
||||||
|
registrar.addPlace("class MyDsl { void ", "() {",
|
||||||
|
context, rangeForMethodName(context));
|
||||||
|
|
||||||
|
// inject method body, append closing braces
|
||||||
|
// to form a valid Java class structure
|
||||||
registrar.addPlace(null, "}}", context, rangeForBody(context));
|
registrar.addPlace(null, "}}", context, rangeForBody(context));
|
||||||
registrar.doneInjecting();
|
registrar.doneInjecting();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user