Changes driven by plugin revisions

This commit is contained in:
JohnHake 2020-02-10 09:40:22 -08:00
parent 72e4fafbe4
commit fe88cf3f03
41 changed files with 499 additions and 441 deletions

View File

@ -2,63 +2,31 @@
title: 7. Annotator
---
Annotator helps highlight and annotate any code based on specific rules.
An [Annotator](/reference_guide/custom_language_support/syntax_highlighting_and_error_highlighting.md#annotator) helps highlight and annotate any code based on specific rules.
This section adds annotation functionality to support the Simple language in the context of Java code.
### 7.1. Define an annotator
In this tutorial we will annotate usages of our properties within Java code.
Let's consider a literal which starts with *"simple:"* as a usage of our property.
* bullet item
{:toc}
## 7.1. Define an Annotator
The `SimpleAnnotator` subclasses [`Annotator`](upsource:///platform/analysis-api/src/com/intellij/lang/annotation/Annotator.java).
Consider a literal string that starts with "simple:" as a prefix of a Simple language key.
It isn't part of the Simple language, but it is a useful convention for detecting Simple language keys embedded as string literals in other languages, like Java.
Annotate the `simple:key` literal expression, and differentiate between a well-formed vs. an unresolved property:
```java
package com.simpleplugin;
import com.intellij.lang.annotation.*;
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.simpleplugin.psi.SimpleProperty;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class SimpleAnnotator implements Annotator {
@Override
public void annotate(@NotNull final PsiElement element, @NotNull AnnotationHolder holder) {
if (element instanceof PsiLiteralExpression) {
PsiLiteralExpression literalExpression = (PsiLiteralExpression) element;
String value = literalExpression.getValue() instanceof String ? (String) literalExpression.getValue() : null;
if (value != null && value.startsWith("simple" + ":")) {
Project project = element.getProject();
String key = value.substring(7);
List<SimpleProperty> properties = SimpleUtil.findProperties(project, key);
if (properties.size() == 1) {
TextRange range = new TextRange(element.getTextRange().getStartOffset() + 8,
element.getTextRange().getEndOffset() - 1);
Annotation annotation = holder.createInfoAnnotation(range, null);
annotation.setTextAttributes(DefaultLanguageHighlighterColors.LINE_COMMENT);
} else if (properties.size() == 0) {
TextRange range = new TextRange(element.getTextRange().getStartOffset() + 8,
element.getTextRange().getEndOffset() - 1);
holder.createErrorAnnotation(range, "Unresolved property");
}
}
}
}
}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleAnnotator.java %}
```
### 7.2. Register the annotator
## 7.2. Register the Annotator
Using an extension point, register the Simple language annotator class with the IntelliJ Platform:
```xml
<annotator language="JAVA" implementationClass="com.simpleplugin.SimpleAnnotator"/>
<extensions defaultExtensionNs="com.intellij">
<annotator language="JAVA" implementationClass="com.intellij.sdk.language.SimpleAnnotator"/>
</extensions>
```
### 7.3. Run the project
Let's define the following Java file and check if the IDE resolves a property.
## 7.3. Run the Project
As a test, define the following Java file containing a Simple language `prefix:value` pair:
```java
public class Test {
public static void main(String[] args) {
@ -67,9 +35,12 @@ public class Test {
}
```
![Annotator](img/annotator.png)
Open this Java file in an IDE Development Instance running the `simple_language` plugin to check if the IDE resolves a property:
If we type an undefined property name, it will annotate the code with a error.
![Annotator](img/annotator.png){:width="800px"}
![Unresolved property](img/unresolved_property.png)
If the property is an undefined name, the annotator will annotate the code with an error.
![Unresolved property](img/unresolved_property.png){:width="800px"}
Try changing the Simple language [color settings](/tutorials/custom_language_support/syntax_highlighter_and_color_settings_page.md#run-the-project-1) to differentiate the annotation from the default language color settings.

View File

@ -2,38 +2,49 @@
title: 16. Code Style Setting
---
Code style settings allow defining formatting options. A code style settings provider will create an instance of the settings, and also create an options page in order to edit them. In this example, we'll create a page that uses the default language code style settings, customised by a language code style settings provider.
[Code style settings](/reference_guide/custom_language_support/code_formatting.md#code-style-settings) enable defining formatting options.
A code style settings provider creates an instance of the settings, and also creates an options page in settings/preferences.
This example creates a settings/preferences page that uses the default language code style settings, customised by a language code style settings provider.
### 16.1. Define code style settings
* bullet list
{:toc}
## 16.1. Define Code Style Settings
Define a code style settings for Simple language by subclassing [`CustomCodeStyleSettings`](upsource:///platform/lang-api/src/com/intellij/psi/codeStyle/CustomCodeStyleSettings.java).
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleCodeStyleSettings.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleCodeStyleSettings.java %}
```
### 16.2. Define code style settings provider
## 16.2. Define Code Style Settings Provider
The code style settings provider gives the IntelliJ Platform a standard way to instantiate `CustomCodeStyleSettings` for the Simple language.
Define a code style settings provider for Simple language by subclassing [`CodeStyleSettingsProvider`](upsource:///platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsProvider.java).
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleCodeStyleSettingsProvider.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleCodeStyleSettingsProvider.java %}
```
### 16.3. Register the code style settings provider
## 16.3. Register the Code Style Settings Provider
The `SimpleCodeStyleSettingsProvider` implementation is registered with the IntelliJ Platform in `plugin.xml` using the `codeStyleSettingsProvider` extension point.
```xml
<codeStyleSettingsProvider implementation="com.simpleplugin.SimpleCodeStyleSettingsProvider"/>
<extensions defaultExtensionNs="com.intellij">
<codeStyleSettingsProvider implementation="com.intellij.sdk.language.SimpleCodeStyleSettingsProvider"/>
</extensions>
```
### 16.4. Define language code style settings provider
## 16.4. Define the Language Code Style Settings Provider
Define a code style settings provider for Simple language by subclassing [`LanguageCodeStyleSettingsProvider`](upsource:///platform/lang-api/src/com/intellij/psi/codeStyle/LanguageCodeStyleSettingsProvider.java), which provides common code style settings for a specific language.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleLanguageCodeStyleSettingsProvider.java %}
```
### 16.5. Register the language code style settings provider
## 16.5. Register the Language Code Style Settings Provider
The `SimpleLanguageCodeStyleSettingsProvider` implementation is registered with the IntelliJ Platform in `plugin.xml` using the `langCodeStyleSettingsProvider` extension point.
```xml
<langCodeStyleSettingsProvider implementation="com.simpleplugin.SimpleLanguageCodeStyleSettingsProvider"/>
<extensions defaultExtensionNs="com.intellij">
<langCodeStyleSettingsProvider implementation="com.intellij.sdk.language.SimpleLanguageCodeStyleSettingsProvider"/>
</extensions>
```
### 16.6. Run the project
## 16.6. Run the project
In the IDE Development Instance, open the Simple language code formatting page: **Preferences/Settings \| Editor \| Code Style \| Simple**.
![Code Style Settings](img/code_style_settings.png)

View File

@ -2,20 +2,32 @@
title: 17. Commenter
---
A commenter allows user to comment the code at the cursor or selected code automatically via corresponding actions.
A commenter enables the user to comment out line of code at the cursor or selected code automatically.
The [`Commenter`](upsource:///platform/core-api/src/com/intellij/lang/Commenter.java) defines support for "Comment with Line Comment" and "Comment with Block Comment" actions.
### 17.1. Define a commenter
* bullet list
{:toc}
## 17.1. Define a Commenter
The Simple language commenter subclasses `Commenter`.
This commenter defines the line comment prefix as "#".
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleCommenter.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleCommenter.java %}
```
### 17.2. Register the commenter
## 17.2. Register the Commenter
The `SimpleCommenter` implementation is registered with the IntelliJ Platform in `plugin.xml` using the `lang.commenter` extension point.
```xml
<lang.commenter language="Simple" implementationClass="com.simpleplugin.SimpleCommenter"/>
<extensions defaultExtensionNs="com.intellij">
<lang.commenter language="Simple" implementationClass="com.intellij.sdk.language.SimpleCommenter"/>
</extensions>
```
### 17.3. Run the project
## 17.3. Run the Project
Open the example Simple Language [properties file ](/tutorials/custom_language_support/lexer_and_parser_definition.md#47-run-the-project) in the IDE Development Instance.
Place the cursor at the `website` line.
Select **Code \| Comment with Line Comment**.
The line is converted to a comment.
Select **Code \| Comment with Line Comment** again, and the comment is converted back to active code.
![Commenter](img/commenter.png)
![Commenter](img/commenter.png) {:width="800px"}

View File

@ -2,23 +2,31 @@
title: 9. Completion Contributor
---
Custom languages provide code completion using one of [two approaches](/reference_guide/custom_language_support/code_completion.md).
The Simple language plugin implements the less complex of the two methods, reference completion.
The easiest way to provide completion is to use a completion contributor.
### 9.1. Define a completion contributor
Let's provide custom completion for values in property files.
* bullet list
{:toc}
## 9.1. Define a Completion Contributor
For the purposes of this tutorial, the `simple_language` plugin provides custom completion for values in Simple language property files.
Create a completion contributor by subclassing [`CompletionContributor`](upsource:///platform/analysis-api/src/com/intellij/codeInsight/completion/CompletionContributor.java).
This rudimentary completion contributor always adds "Hello" to the results set, regardless of context:
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleCompletionContributor.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleCompletionContributor.java %}
```
### 9.2. Register the completion contributor
## 9.2. Register the Completion Contributor
The `SimpleCompletionContributor` implementation is registered with the IntelliJ Platform using the `completion.contributor` extension point.
```xml
<completion.contributor language="Simple" implementationClass="com.simpleplugin.SimpleCompletionContributor"/>
<extensions defaultExtensionNs="com.intellij">
<completion.contributor language="Simple" implementationClass="com.intellij.sdk.language.SimpleCompletionContributor"/>
</extensions>
```
### 9.3. Run the project
## 9.3. Run the Project
Run the `simple_language` plugin in a Development Instance and open the [`test.simple`](/tutorials/custom_language_support/lexer_and_parser_definition.md#run-the-project) file.
Erase the property "English" and invoke [Basic Code Completion](https://www.jetbrains.com/help/idea/auto-completing-code.html#invoke-basic-completion).
The choice "Hello" is shown:
![Completion](img/completion.png)
![Completion](img/completion.png){:width="800px"}

View File

@ -2,23 +2,30 @@
title: 11. Find Usages Provider
---
A find usage provider uses a word scanner to build an index of words present in every file.
A scanner breaks the text into words, defines the context for each word and passes it to the find usage provider.
A [find usage provider](/reference_guide/custom_language_support/find_usages.md) uses a word scanner to build an index of words in every file.
A scanner breaks the text into words, defines the context for each word, and passes it to the find usage provider.
### 11.1. Define a find usages provider
* bullet list
{:toc}
## 11.1. Define a Find Usages Provider
The `SimpleFindUsagesProvider` is implements [`FindUsagesProvider`](upsource:///platform/indexing-api/src/com/intellij/lang/findUsages/FindUsagesProvider.java).
Using the [`DefaultWordsScanner`](upsource:///platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java) ensures the scanner implementation is thread-safe.
See the comments in `FindUsagesProvider` for more information.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleFindUsagesProvider.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleFindUsagesProvider.java %}
```
### 11.2. Register the find usages provider
## 11.2. Register the Find Usages Provider
The `SimpleFindUsagesProvider` implementation is registered with the IntelliJ Platform using the `lang.findUsagesProvider` extension point.
```xml
<lang.findUsagesProvider language="Simple" implementationClass="com.simpleplugin.SimpleFindUsagesProvider"/>
<extensions defaultExtensionNs="com.intellij">
<lang.findUsagesProvider language="Simple" implementationClass="com.intellij.sdk.language.SimpleFindUsagesProvider"/>
</extensions>
```
### 11.3. Run the project
## 11.3. Run the Project
Rebuild the project, and run `simple_language` in a Development Instance.
The IDE now supports [Find Usages](https://www.jetbrains.com/help/idea/find-highlight-usages.html) for any property with a reference:
Now we can call *Find Usages* for any property with a reference.
![Find Usages](img/find_usages.png)
![Find Usages](img/find_usages.png){:width="800px"}

View File

@ -2,24 +2,40 @@
title: 12. Folding Builder
---
A folding builder helps you to fold the code regions and replace it with specific text.
A folding builder identifies the folding regions in the code.
In this step of the tutorial the folding builder is used to identify folding regions and replace the regions with specific text.
Rather than the usual practice of using a folding builder to collapse a class, method, or comments to fewer lines, the folding builder will replace Simple language keys with their corresponding values.
### 12.1. Define a folding builder
* bullet list
{:toc}
Let's replace usages of properties with its values by default.
## 12.1. Define a Folding Builder
The `SimpleFoldingBuilder` will replace usages of properties with their values by default.
Start by subclassing [`FoldingBuilderEx`](upsource:///community/platform/core-api/src/com/intellij/lang/folding/FoldingBuilderEx.java)
Note that `SimpleFoldingBuilder` also implements `DumbAware`, which means the class is allowed to run in dumb mode, when indices are in background update.
The `buildFoldRegions()` method searches down a PSI tree from `root` to find all literal expressions containing the [simple prefix](/tutorials/custom_language_support/annotator.md#define-an-annotator) `simple:`.
The remainder of such a string is considered to contain a Simple language key, and so the text range is stored as a [`FoldingDescriptor`](upsource:///platform/core-api/src/com/intellij/lang/folding/FoldingDescriptor.java).
The `getPlaceholderText()` method retrieves the Simple language value corresponding to the key associated with the (ASTNode) provided.
The IntelliJ Platform uses the value to substitute for the key when the code is folded.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleFoldingBuilder.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleFoldingBuilder.java %}
```
### 12.2. Register the folding builder
## 12.2. Register the Folding Builder
The `SimpleFoldingBuilder` implementation is registered with the IntelliJ Platform using the `lang.foldingBuilder` extension point.
```xml
<lang.foldingBuilder language="JAVA" implementationClass="com.simpleplugin.SimpleFoldingBuilder"/>
<extensions defaultExtensionNs="com.intellij">
<lang.foldingBuilder language="JAVA" implementationClass="com.intellij.sdk.language.SimpleFoldingBuilder"/>
</extensions>
```
### 12.3. Run the project
## 12.3. Run the Project
Rebuild the project, and run `simple_language` in a Development Instance.
Now when a Java file is opened in the Editor it shows the property's value instead of the key.
This is because `SimpleFoldingBuilder.isCollapsedByDefault()` always returns `true`.
Try using **Code \| Folding \| Expand All** to show the key rather than the value.
Now when we open a Java file, it shows the property's value instead of the key.
![Folding](img/folding.png)
![Folding](img/folding.png){:width="800px"}

View File

@ -2,33 +2,38 @@
title: 15. Formatter
---
*A formatter allows to reformat the code automatically based on code style settings.*
The IntelliJ Platform includes a powerful framework for implementing formatting for custom languages.
A [formatter](/reference_guide/custom_language_support/code_formatting.md) enables reformatting code automatically based on code style settings.
The formatter controls spaces, indents, wrap, and alignment.
### 15.1. Define a block
The formatter uses the blocks to receive formatting rules for each PSI element.
Our goal is to cover each PSI element with such block. Since each block builds own children blocks we can generate extra blocks or skip any PSI elements.
* bullet list
{:toc}
## 15.1. Define a Block
The formatting model builds represents the formatting structure of a file as a tree of [`Block`](upsource:///platform/lang-api/src/com/intellij/formatting/Block.java) objects, with associated indent, wrap, alignment and spacing setting
The goal is to cover each PSI element with such a block.
Since each block builds its children's blocks, it can generate extra blocks or skip any PSI elements.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleBlock.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleBlock.java %}
```
### 15.2. Define a formatting model builder
Let's define a formatter which removes extra spaces except the single ones around the property separator.
## 15.2. Define a Formatting Model Builder
Define a formatter which removes extra spaces except the single spaces around the property separator.
For example, reformat `foo = bar` to `foo = bar`.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleFormattingModelBuilder.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleFormattingModelBuilder.java %}
```
### 15.3. Register the formatter
## 15.3. Register the Formatter
The `SimpleFormattingModelBuilder` implementation is registered with the IntelliJ Platform in `plugin.xml` using the `lang.formatter` extension point.
```xml
<lang.formatter language="Simple" implementationClass="com.simpleplugin.SimpleFormattingModelBuilder"/>
<extensions defaultExtensionNs="com.intellij">
<lang.formatter language="Simple" implementationClass="com.intellij.sdk.language.SimpleFormattingModelBuilder"/>
</extensions>
```
### 15.4. Run the project
## 15.4. Run the Project
Add some extra spaces around the `=` separator between `language` and `English`.
Reformat the code by selecting **Code \| Show Reformat File Dialog** and choose **Run**.
Now add some extra spaces and reformat the code via **Code \| Reformat Code**.
![Formatter](img/formatter.png)
![Formatter](img/formatter.png){:width="800px"}

View File

@ -2,14 +2,15 @@
title: 13. Go To Symbol Contributor
---
*A go to symbol contributor helps user to navigate to any PSI element by its name.*
A go to symbol contributor helps the user to navigate to any PSI element by its name.
### 13.1. Define helper method for generated PSI elements
To specify how a PSI element looks like in the *Go To Symbol* popup window, *Structure* tool window or another components, it should implement *getPresentation* method.
This means we need to define this method in our utility *com.simpleplugin.psi.impl.SimplePsiImplUtil* and regenerate the parser and PSI classes.
* bullet list
{:toc}
## 13.1. Define a Helper Method for Generated PSI Elements
To specify how a PSI element looks like in the *Go To Symbol* popup window, *Structure* tool window or another components, it should implement `getPresentation()`.
This means defining this method in the utility `com.intellij.sdk.language.psi.impl.SimplePsiImplUtil` and regenerate the parser and PSI classes.
Add the following method to `SimplePsiImplUtil`:
```java
public static ItemPresentation getPresentation(final SimpleProperty element) {
return new ItemPresentation() {
@ -34,29 +35,31 @@ public static ItemPresentation getPresentation(final SimpleProperty element) {
}
```
### 13.2. Update grammar and regenerate the parser
## 13.2. Update Grammar and Regenerate the Parser
Now add the `SimplePsiImplUtil.getPresentation()` to the `property` definition in the `Simple.bnf` grammar file by replacing the `property` definition with the lines below.
Don't forget to regenerate the parser after updating the file!
Right click on the `Simple.bnf` file and select **Generate Parser Code**.
```java
property ::= (KEY? SEPARATOR VALUE?) | KEY {mixin="com.simpleplugin.psi.impl.SimpleNamedElementImpl"
implements="com.simpleplugin.psi.SimpleNamedElement" methods=[getKey getValue getName setName getNameIdentifier getPresentation]}
property ::= (KEY? SEPARATOR VALUE?) | KEY {mixin="com.intellij.sdk.language.psi.impl.SimpleNamedElementImpl"
implements="com.intellij.sdk.language.psi.SimpleNamedElement" methods=[getKey getValue getName setName getNameIdentifier getPresentation]}
```
Regenerate the parser by right clicking on the `Simple.bnf` file and selecting _Generate Parser Code_.
### 13.3. Define a go to symbol contributor
## 13.3. Define a Go to Symbol Contributor
To enable the `simple_language` plugin to contribute items to "Navigate Class|File|Symbol" lists, subclass [`ChooseByNameContributor`](upsource:///platform/lang-api/src/com/intellij/navigation/ChooseByNameContributor.java) to create `SimpleChooseNameContributor`:
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleChooseByNameContributor.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleChooseByNameContributor.java %}
```
### 13.4. Register the go to symbol contributor
## 13.4. Register the go to symbol contributor
The `SimpleChooseByNameContributor` implementation is registered with the IntelliJ Platform using the `gotoSymbolContributor` extension point.
```xml
<gotoSymbolContributor implementation="com.simpleplugin.SimpleChooseByNameContributor"/>
<extensions defaultExtensionNs="com.intellij">
<gotoSymbolContributor implementation="com.intellij.sdk.language.SimpleChooseByNameContributor"/>
</extensions>
```
### 13.5. Run the project
## 13.5. Run the project
Rebuild the project, and run `simple_language` in a Development Instance.
The IDE now supports navigating to a property definition by name pattern via **Navigate \| Symbol** action.
Now we can navigate to a property definition by name pattern via **Navigate \| Symbol** action.
![Go To Symbol](img/go_to_symbol.png)
![Go To Symbol](img/go_to_symbol.png){:width="800px"}

View File

@ -2,40 +2,42 @@
title: 3. Grammar and Parser
---
### 3.1. Define a token type
Create a file in the `com.simpleplugin.psi` package.
In order for the IntelliJ Platform to parse a Simple language file, [tokens and elements](/reference_guide/custom_language_support/implementing_parser_and_psi.md) must be defined based on [`IElementType`](upsource:///platform/core-api/src/com/intellij/psi/tree/IElementType.java).
The Simple language grammar must also be defined in order to generate a parser.
* bullet item
{:toc}
## 3.1. Define a Token Type
Create `SimpleTokenType` in the `com.intellij.sdk.language.psi` package (see the `simple_language` code sample) by subclassing `IElementType`.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/psi/SimpleTokenType.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleTokenType.java %}
```
### 3.2. Define an element type
Create a file in the `com.simpleplugin.psi` package.
## 3.2. Define an Element Type
Create the `SimpleElementType` in the `com.intellij.sdk.language.psi` package by subclassing `IElementType`.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/psi/SimpleElementType.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementType.java %}
```
### 3.3. Define grammar
Define a grammar for the properties language with */com/simpleplugin/Simple.bnf* file.
## 3.3. Define the Grammar
Define a grammar for the Simple language in the `com/intellij/sdk/language/Simple.bnf` file.
```java
{
parserClass="com.simpleplugin.parser.SimpleParser"
parserClass="com.intellij.sdk.language.parser.SimpleParser"
extends="com.intellij.extapi.psi.ASTWrapperPsiElement"
psiClassPrefix="Simple"
psiImplClassSuffix="Impl"
psiPackage="com.simpleplugin.psi"
psiImplPackage="com.simpleplugin.psi.impl"
psiPackage="com.intellij.sdk.language.psi"
psiImplPackage="com.intellij.sdk.language.psi.impl"
elementTypeHolderClass="com.simpleplugin.psi.SimpleTypes"
elementTypeClass="com.simpleplugin.psi.SimpleElementType"
tokenTypeClass="com.simpleplugin.psi.SimpleTokenType"
elementTypeHolderClass="com.intellij.sdk.language.psi.SimpleTypes"
elementTypeClass="com.intellij.sdk.language.psi.SimpleElementType"
tokenTypeClass="com.intellij.sdk.language.psi.SimpleTokenType"
psiImplUtilClass="com.intellij.sdk.language.psi.impl.SimplePsiImplUtil"
}
simpleFile ::= item_*
@ -45,18 +47,17 @@ private item_ ::= (property|COMMENT|CRLF)
property ::= (KEY? SEPARATOR VALUE?) | KEY
```
As you see a properties file can contain properties, comments and line breaks.
As shown, a properties file can contain properties, comments, and line breaks.
The grammar defines how flexible the support for a language can be.
We specified that a property may have or may not have key and value.
This lets the IDE still recognise incorrectly defined properties and provide corresponding code analysis and quick-fixes.
The grammar defines the flexibility of the support for a language.
The above grammar specifies that a property may have or may not have key and value.
This allows the IntelliJ Platform to still recognise incorrectly defined properties and provide corresponding code analysis and quick-fixes.
Note that the `SimpleTypes` class in the `elementTypeHolderClass` field above specifies the name of a class that gets generated from the grammar, it doesn't exist at this point.
Note that the `SimpleTypes` class in the `elementTypeHolderClass` field above specifies the name of a class that gets generated from the grammar; it doesn't exist at this point.
### 3.4. Generate a parser
Now when the grammar is defined we can generate a parser with PSI classes via *Generate Parser Code* from the context menu on *Simple.bnf* file.
This will generate a parser and PSI elements in *gen* folder.
## 3.4. Generate a Parser
Now that the grammar is defined, generate a parser with PSI classes via **Generate Parser Code** from the context menu on the *Simple.bnf* file.
This will generate a parser and PSI elements in the `/src/main/gen` folder of the project.
Mark this folder as *Generated Sources Root* and make sure everything is compiled without errors.
![Parser](img/generated_parser.png)
![Parser](img/generated_parser.png){:width="800px"}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 352 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 135 KiB

View File

@ -2,63 +2,66 @@
title: 2. Language and File Type
---
The IntelliJ Platform [determines file type](/reference_guide/custom_language_support/registering_file_type.md) by examining the name of a file.
Each language has [Language](upsource:///platform/core-api/src/com/intellij/lang/Language.java) and [LanguageFileType](upsource:///platform/core-api/src/com/intellij/openapi/fileTypes/LanguageFileType.java) objects defining the language.
The `LanguageFileType` is registered with the IntelliJ Platform in the plugin configuration file.
### 2.1. Define a language
Note the case of the name of the language - `Simple`.
* bullet item
{:toc}
## 2.1. Define the Language
The language implemented in this tutorial is named "Simple" - note the case of the name.
The `SimpleLanguage` class is defined in the `com.intellij.sdk.language` package of the `simple_language` code sample:
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleLanguage.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleLanguage.java %}
```
### 2.2. Define an icon
Copy the
[icon](https://raw.githubusercontent.com/JetBrains/intellij-sdk-docs/master/code_samples/simple_language_plugin/src/com/simpleplugin/icons/jar-gray.png)
to **com.simpleplugin.icons** package.
## 2.2. Define an Icon
The [icon](https://raw.githubusercontent.com/JetBrains/intellij-sdk-docs/master/code_samples/simple_language_plugin/src/com/simpleplugin/icons/jar-gray.png) for the Simple language is defined by the `SimpleIcons` class.
There is nothing uniquely Simple language-specific about [defining the icon](/reference_guide/work_with_icons_and_images.md) itself.
The definition follows a pattern similar to defining, e.g., `SdkIcons`.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleIcons.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleIcons.java %}
```
### 2.3. Define a file type
## 2.3. Define a FileType
The Simple language file type is defined by subclassing `LanguageFileType`:
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleFileType.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleFileType.java %}
```
### 2.4. Define a file type factory
> **NOTE** When targeting 2019.2 or later only, please see [2.5.B](#b-register-file-type-20192-or-later)
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleFileTypeFactory.java %}
```
### 2.5. Register the file type factory
In plugin.xml add:
## 2.4. Register the FileType Directly
Direct registration is necessary when targeting version 2019.2 (and later) of the IntelliJ Platform.
No `FileTypeFactory` is required.
Instead, the file type is registered of file type is done via the `com.intellij.fileType` extension point in `plugin.xml`:
```xml
<extensions defaultExtensionNs="com.intellij">
<fileTypeFactory implementation="com.simpleplugin.SimpleFileTypeFactory"/>
<fileType name="Simple file" implementationClass="com.intellij.sdk.language.SimpleFileType" fieldName="INSTANCE"
language="Simple" extensions="simple"/>
</extensions>
```
### 2.5.B. Register file type (2019.2 or later)
Skip to [section 2.6](#26-run-the-project).
When matching via file extension, pattern or exact file name, registration of file type should be done via `com.intellij.fileType` extension point instead of implementing dedicated `FileTypeFactory`.
## 2.5. Register the FileType Using a Factory
This pattern is necessary when targeting versions of the IntelliJ Platform prior to 2019.2
### 2.5.1 Define a FileType Factory
First, define `SimpleFileTypeFactory` as a subclass of `FileTypeFactory`.
```java
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleFileTypeFactory.java %}
```
### 2.5.2 Register the FileType Factory
The `FileTypeFactory` is registered with the IntelliJ Platform using the `com.intellij.openapi.fileTypes.FileTypeFactory` extension point in `plugin.xml`.
```xml
<extensions defaultExtensionNs="com.intellij">
<fileType name="Simple file" implementationClass="com.simpleplugin.SimpleFileType" fieldName="INSTANCE"
language="Simple" extensions="simple"/>
<fileTypeFactory implementation="com.intellij.sdk.language.SimpleFileTypeFactory"/>
</extensions>
```
### 2.6. Run the project
## 2.6. Run the Project
Create an empty file with the extension `\*.simple` and IntelliJ IDEA will automatically associate it with our language.
Note the appearance of the Simple language file icon next to the `test.simple` file in the **Project Tool Window** and in the editor tab for the file.
Create a file with extension *.simple*
and IntelliJ IDEA will automatically associate it with our language.
![File Type Factory](img/file_type_factory.png)
![File Type Factory](img/file_type_factory.png){:width="800px"}

View File

@ -2,57 +2,61 @@
title: 4. Lexer and Parser Definition
---
The lexer defines how the contents of a file is broken into tokens.
The lexical analyzer defines how the [contents of a file are broken into tokens](/reference_guide/custom_language_support/implementing_lexer.md), which is the basis for supporting custom language features.
The easiest way to create a lexer is to use [JFlex](https://jflex.de/)
### 4.1. Define a lexer
Define */com/simpleplugin/Simple.flex* file with rules for our lexer.
* bullet item
{:toc}
## 4.1. Define a Lexer
Define a `Simple.flex` file with rules for the Simple language lexer, as demonstrated in `com.intellij.sdk.language.Simple.flex`.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/Simple.flex %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/Simple.flex %}
```
### 4.2. Generate a lexer class
## 4.2. Generate a Lexer Class
Now generate a lexer class via **JFlex Generator** from the context menu on `Simple.flex` file.
Now we can generate a lexer class via *JFlex Generator* from the context menu on `Simple.flex` file.
The Grammar-Kit plugin uses JFlex lexer generation.
If you run it for the first time, it offers you to choose a folder to download the JFlex library and skeleton to.
Choose the project root directory.
When run for the first time, it prompts for a destination folder to download the JFlex library and skeleton.
Choose the project root directory, for example `code_samples/simple_language`.
After that, the IDE generates the lexer: *com.simpleplugin.SimpleLexer*.
After that, the IDE generates the lexer under the `gen` directory, for example in `simple_language/src/main/gen/com/intellij/sdk/language/SimpleLexer`.
### 4.3. Define an adapter
See [Implementing Lexer](/reference_guide/custom_language_support/implementing_lexer.md) for more information about using _JFlex_ with the IntelliJ Platform.
## 4.3. Define a Lexer Adapter
The JFlex lexer needs to be adapted to the IntelliJ Platform Lexer API.
This is done by subclassing [`FlexAdapter`](upsource:///platform/core-api/src/com/intellij/lexer/FlexAdapter.java).
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleLexerAdapter.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleLexerAdapter.java %}
```
### 4.4. Define a root file
Create the class in the `com.simpleplugin.psi` namespace.
## 4.4. Define a Root File
The `SimpleFile` implementation is the top-level node of the [tree of `PsiElements`](/reference_guide/custom_language_support/implementing_parser_and_psi.md) for a Simple language file.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/psi/SimpleFile.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleFile.java %}
```
### 4.5. Define a parser definition
## 4.5. Define a Parser
The Simple language parser is defined by subclassing [`ParserDefinition`](upsource:///platform/core-api/src/com/intellij/lang/ParserDefinition.java).
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleParserDefinition.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleParserDefinition.java %}
```
### 4.6. Register the parser definition
## 4.6. Register the Parser Definition
Registering the parser definition in the `plugin.xml` file makes it available to the IntelliJ Platform.
The `lang.parserDefinition` extension point is used for registration.
For example, see `simple_language/src/main/resources/META-INF/plugin.xml`.
```xml
<lang.parserDefinition language="Simple" implementationClass="com.simpleplugin.SimpleParserDefinition"/>
<extensions defaultExtensionNs="com.intellij">
<lang.parserDefinition language="Simple" implementationClass="com.intellij.sdk.language.SimpleParserDefinition"/>
</extensions>
```
### 4.7. Run the project
Create a properties file with the following content:
```
## 4.7. Run the Project
With the `simple_language` plugin loaded in a Development Instance, create a `test.simple` properties file with the following content:
```text
# You are reading the ".properties" entry.
! The exclamation mark can also mark text as comments.
website = http://en.wikipedia.org/
@ -69,4 +73,4 @@ tab : \u0009
Now open the *PsiViewer* tool window and check how the lexer breaks the content of the file into tokens, and the parser parsed the tokens into PSI elements.
![PSI Elements](img/psi_elements.png)
![PSI Elements](img/psi_elements.png){:width="900px"}

View File

@ -2,31 +2,37 @@
title: 8. Line Marker Provider
---
Line markers help to annotate any code with icons on the gutter.
These icons may provide navigation to related code.
Line markers help annotate code with icons on the gutter.
These markers can provide navigation targets to related code.
### 8.1. Define a line marker provider
* bullet list
{:toc}
Let's annotate usages of our properties within Java code and provide navigation to the definition of these properties.
## 8.1. Define a Line Marker Provider
A line marker provider annotates usages of Simple language properties within Java code and provides navigation to the definition of these properties.
The visual marker will be a Simple language icon in the gutter of the Editor window.
The Simple language marker provider is subclassed from [`RelatedItemLineMarkerProvider`](upsource:///platform/lang-api/src/com/intellij/codeInsight/daemon/RelatedItemLineMarkerProvider.java).
For this example, override the `collectNavigationMarkers()` method to collect usage of a Simple language [key and separators](/tutorials/custom_language_support/language_and_filetype.md#define-the-language):
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleLineMarkerProvider.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleLineMarkerProvider.java %}
```
## More technical details for implementers
* Please return line marker info for exact element you were asked for.
For example, do not return class marker info if `getLineMarkerInfo()` was called for a method.
* Please return relevant line marker info for as small element as possible.
For example, do not return method marker for [`PsiMethod`](upsource:///java/java-psi-api/src/com/intellij/psi/PsiMethod.java). Instead, return it for the [`PsiIdentifier`](upsource:///java/java-psi-api/src/com/intellij/psi/PsiIdentifier.java) which is a name of this method.
### Even more technical details:
What happens when `LineMarkerProvider` returns something for too big PsiElement?
## 8.2. Best Practices for Implementing Line Marker Providers
This section addresses important details about implementing a marker provider.
The `collectNavigationMarkers()` method should:
* Only return line marker information consistent with the element passed into the method.
For example, do not return a _class_ marker if `getLineMarkerInfo()` was called with an element that corresponds to a _method_.
* Return line marker information for the appropriate element at the correct scope of the PSI tree.
For example, do not return method marker for [`PsiMethod`](upsource:///java/java-psi-api/src/com/intellij/psi/PsiMethod.java).
Instead, return it for the [`PsiIdentifier`](upsource:///java/java-psi-api/src/com/intellij/psi/PsiIdentifier.java) which contains the name of the method.
![Line Marker Location](img/line_marker_location.png){:width="900px"}
What happens when a `LineMarkerProvider` returns marker information for a `PsiElement` that is a higher node in the PSI tree?
For example, if `MyWrongLineMarkerProvider()` erroneously returns a `PsiMethod` instead of a `PsiIdentifier` element:
```java
public class MyLineMarkerProvider implements LineMarkerProvider {
public class MyWrongLineMarkerProvider implements LineMarkerProvider {
public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
if (element instanceof PsiMethod) return new LineMarkerInfo(element, ...);
return null;
@ -34,25 +40,20 @@ public class MyLineMarkerProvider implements LineMarkerProvider {
}
```
Inspection (specifically, [`LineMarkersPass`](upsource:///platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java)) for performance reasons queries all [`LineMarkerProviders`](upsource:///platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerProviders.java) in two passes:
The consequences of the `MyWrongLineMarkerProvider()` implementation have to do with how the IntelliJ Platform performs inspections.
For performance reasons, inspection, and specifically the [`LineMarkersPass`](upsource:///platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java) queries all [`LineMarkerProviders`](upsource:///platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerProviders.java) in two phases:
* The first pass is for all elements visible in the Editor window,
* The second pass is for the rest of the elements in the file.
* first pass for all elements in visible area
* second pass for all the rest elements
If providers return nothing for either area, its line markers are cleared.
So if e.g. a method is half-visible (its name is visible but part of its body isn't) and
some poorly written [`LineMarkerProvider`](upsource:///platform/lang-api/src/com/intellij/codeInsight/daemon/LineMarkerProvider.java) returned info for the `PsiMethod` instead of `PsiIdentifier` then:
* the first pass removes line marker info because whole `PsiMethod` is not visible.
* the second pass tries to add line marker info back because `LineMarkerProvider` is called for the `PsiMethod` at last.
As a result, line marker icon would blink annoyingly.
To fix this, rewrite `LineMarkerProvider` to return info for `PsiIdentifier` instead of `PsiMethod`:
If providers return nothing for either area, the line markers are cleared.
However, if a method like `actionPerformed()` is not completely visible in the Editor window (as shown in the image above,) and `MyWrongLineMarkerProvider()` returns marker info for the `PsiMethod` instead of `PsiIdentifier`, then:
* The first pass removes line marker info because whole `PsiMethod` isn't visible.
* The second pass tries to add a line marker because `MyWrongLineMarkerProvider()` is called for the `PsiMethod`.
As a result, _the line marker icon would blink annoyingly_.
To fix this problem, rewrite `MyWrongLineMarkerProvider` to return info for `PsiIdentifier` instead of `PsiMethod` as shown below:
```java
public class MyLineMarkerProvider implements LineMarkerProvider {
public class MyCorrectLineMarkerProvider implements LineMarkerProvider {
public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
if (element instanceof PsiIdentifier && element.getParent() instanceof PsiMethod) return new LineMarkerInfo(element, ...);
return null;
@ -60,14 +61,17 @@ public class MyLineMarkerProvider implements LineMarkerProvider {
}
```
### 8.2. Register the line marker provider
## 8.3. Register the Line Marker Provider
The `SimpleLineMarkerProvider` implementation is registered with the IntelliJ Platform using the `codeInsight.lineMarkerProvider` extension point.
```xml
<codeInsight.lineMarkerProvider language="JAVA" implementationClass="com.simpleplugin.SimpleLineMarkerProvider"/>
<extensions defaultExtensionNs="com.intellij">
<codeInsight.lineMarkerProvider language="JAVA" implementationClass="com.intellij.sdk.language.SimpleLineMarkerProvider"/>
</extensions>
```
### 8.3. Run the project
Now you see the icon on the gutter and can navigate to the property definition.
## 8.4. Run the Project
Run the `simple_language` plugin in a Development Instance and open the [Test file](/tutorials/custom_language_support/annotator.md#run-the-project).
Now the icon appears next to line 3 on the gutter.
A user can click on the icon to navigate to the property definition.
![Line Marker](img/line_marker.png)

View File

@ -2,24 +2,19 @@
title: 6. PSI Helpers and Utilities
---
Helper classes and utilities can be embedded in the code generated by Grammar-Kit.
### 6.1. Define helper methods for generated PSI elements
If we want to have custom methods in PSI classes we need to define them separately and ask Grammar-Kit to embed them into generated code.
Let's define a utility class with these helper methods.
* bullet item
{:toc}
## 6.1. Define Helper Methods for Generated PSI Elements
Custom methods in PSI classes are defined separately, and Grammar-Kit embeds them into generated code.
Define a utility class with these helper methods:
```java
package com.simpleplugin.psi.impl;
package com.intellij.sdk.language.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.navigation.ItemPresentation;
import com.intellij.psi.*;
import com.simpleplugin.SimpleIcons;
import com.simpleplugin.psi.*;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import com.intellij.sdk.language.psi.*;
public class SimplePsiImplUtil {
public static String getKey(SimpleProperty element) {
@ -31,7 +26,7 @@ public class SimplePsiImplUtil {
return null;
}
}
public static String getValue(SimpleProperty element) {
ASTNode valueNode = element.getNode().findChildByType(SimpleTypes.VALUE);
if (valueNode != null) {
@ -43,13 +38,12 @@ public class SimplePsiImplUtil {
}
```
Note that the `SimpleProperty` interface referenced in the code above is generated by the parser. Also note that the `element.getKey` method used in `getPresentableText` will not be defined - it's a method generated by the parser, which we'll fix below.
The parser generates the `SimpleProperty` interface referenced in the code above.
### 6.2. Update grammar and regenerate the parser
Now we tell to use this utility class in the grammar file via `psiImplUtilClass` attribute.
To tell which methods for which PSI classes must be used we specify methods for particular rule.
## 6.2. Update Grammar and Regenerate the Parser
Now the utility class is added to the grammar file via the `psiImplUtilClass` attribute.
Add methods for a particular rule to specify which one should be used for PSI classes.
Compare the last line of the grammar below to the [previous definition](/tutorials/custom_language_support/grammar_and_parser.md#33-define-the-grammar).
```java
{
@ -76,13 +70,12 @@ private item_ ::= (property|COMMENT|CRLF)
property ::= (KEY? SEPARATOR VALUE?) | KEY {methods=[getKey getValue]}
```
After we made our changes to the grammar we can regenerate the parser and PSI classes.
### 6.3. Define a utility to search properties
Now we need a utility class to search PSI elements for defined properties over the project.
We will use this utility later when implementing code assistance.
After making changes to the grammar, regenerate the parser and PSI classes.
## 6.3. Define a Utility to Search Properties
Create a utility class to search PSI elements for defined properties over the project.
This utility will be used later when implementing [code completion](https://www.jetbrains.com/help/idea/auto-completing-code.html).
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleUtil.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleUtil.java %}
```

View File

@ -2,35 +2,47 @@
title: 18. Quick Fix
---
A quick fix for a custom language supports the IntelliJ Platform-based IDE feature [Intention Actions](https://www.jetbrains.com/help/idea/intention-actions.html#apply-intention-actions).
For the Simple language, this tutorial adds a quick fix that helps to define an unresolved property from its usage.
A quick fix allows to apply an automatic changes to the code via **Show Intention Actions** (Alt + Enter).
Let's add a quick fix which helps to define an unresolved property from its usage.
### 18.1. Update the element factory
* bullet list
{:toc}
## 18.1. Update the Element Factory
The `SimpleElementFactory` is updated to include two new methods to support the user choice of creating a new property for the Simple language quick fix.
The new `createCRLF()` method supports adding a newline to the end of the [`test.simple`](/tutorials/custom_language_support/lexer_and_parser_definition.md#run-the-project) file before adding a new property.
A new overload of `createProperty()` creates a new `key`-`value` pair for Simple language.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/psi/SimpleElementFactory.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementFactory.java %}
```
### 18.2. Define an intention action
The quick fix will create a property in the file chosen by user, and navigate to this property after creation.
## 18.2. Define an Intention Action
The `SimpleCreatePropertyQuickFix` will create a property in the file chosen by the user - in this case a Java file containing a `prefix:key` - and navigate to this property after creation.
Under the hood, `SimpleCreatePropertyQuickFix` is an intention action.
For a more in-depth example of an intention action, see [`conditional_operator_intention`](/code_samples/conditional_operator_intention).
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/CreatePropertyQuickFix.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleCreatePropertyQuickFix.java %}
```
### 18.3. Update the annotator
Note the call to `registerFix`.
## 18.3. Update the Annotator
When a `badProperty` annotation is created, the `badProperty.registerFix()` method is called.
This method call registers the `SimpleCreatePropertyQuickFix` as the intention action for the Intellij Platform to use to correct the problem.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleAnnotator.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleAnnotator.java %}
```
### 18.4. Run the project
## 18.4. Run the project
Open the test [Java file](/tutorials/custom_language_support/annotator.md#run-the-project) in an IDE Development Instance running the `simple_language` plugin.
Now let's try to use a property which is not defined yet.
To test `SimpleCreatePropertyQuickFix`, change `simple:website` to `simple:website.url`.
The key `website.url` is highlighted by `SimpleAnnotator` as an invalid key, as shown below.
Choose "Create Property".
![Quick Fix](img/quick_fix.png)
![Quick Fix](img/quick_fix.png){:width="800px"}
The IDE will open the `test.simple` file and add `website.url` as a new key.
Add the new value `jetbrains.com` for the new `website.url` key.
![New Property](img/new_property.png){:width="800px"}
Now switch back to the Java file; the new key is highlighted as valid.

View File

@ -2,25 +2,24 @@
title: 10. Reference Contributor
---
References is one of the most important and tricky parts in the implementation of a custom language support.
The [References functionality](/reference_guide/custom_language_support/references_and_resolve.md) is one of the most important parts in the implementation of custom language support.
Resolving references means the ability to go from the usage of an element to its declaration, completion, rename refactoring, find usages, etc.
**Every element which can be renamed or referenced needs to implement `com.intellij.psi.PsiNamedElement` interface.**
> **Note** Every PSI element that can be renamed or referenced needs to implement [`PsiNamedElement`](upsource:///platform/core-api/src/com/intellij/psi/PsiNamedElement.java) interface.
### 10.1. Define a base named element class
* bullet list
{:toc}
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/psi/SimpleNamedElement.java %}
```
### 10.1. Define a Named Element Class
The simplified class diagram below shows how the Simple language fulfills the need to implement `PsiNamedElement`.
The `SimpleNamedElement` interface is subclassed from [`PsiNameIdentifierOwner`]().
The `SimpleNamedElementImpl` class implements the `SimpleNamedElement` interface and extends [`ASTWrapperPsiElement`](upsource:///platform/core-impl/src/com/intellij/extapi/psi/ASTWrapperPsiElement.java).
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/psi/impl/SimpleNamedElementImpl.java %}
```
### 10.2. Define helper methods for generated PSI elements
Since we need to implement new methods in PSI class, we should define them in the `SimplePsiImplUtil` class:
![SimpleNamedElementImpl class hierarchy](img/simple_named_element.png){:width="400px"}
## 10.2. Define Helper Methods for Generated PSI Elements
Modify `SimplePsiImplUtil` to support new methods that will get added to the PSI class for Simple language.
Note that `SimpleElementFactory` isn't defined until the [next step](#103-define-an-element-factory), so for now it shows as an error.
```java
public class SimplePsiImplUtil {
@ -55,89 +54,71 @@ public class SimplePsiImplUtil {
}
```
Note that the `SimpleElementFactory` class will show as an error. We'll create it next.
### 10.3. Define an element factory
## 10.3. Define an Element Factory
The `SimpleElementFactory` provides methods for creating `SimpleFile`.
```java
package com.simpleplugin.psi;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.simpleplugin.SimpleFileType;
public class SimpleElementFactory {
public static SimpleProperty createProperty(Project project, String name) {
final SimpleFile file = createFile(project, name);
return (SimpleProperty) file.getFirstChild();
}
public static SimpleFile createFile(Project project, String text) {
String name = "dummy.simple";
return (SimpleFile) PsiFileFactory.getInstance(project).
createFileFromText(name, SimpleFileType.INSTANCE, text);
}
}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/psi/SimpleElementFactory.java %}
```
### 10.4. Update grammar and regenerate the parser
Now we need to make corresponding changes to the grammar file and regenerate parser and PSI classes.
## 10.4. Update Grammar and Regenerate the Parser
Now make corresponding changes to the `Simple.bnf` grammar file by replacing the `property` definition with the line below.
Don't forget to regenerate the parser after updating the file!
Right click on the `Simple.bnf` file and select **Generate Parser Code**.
```java
property ::= (KEY? SEPARATOR VALUE?) | KEY {mixin="com.simpleplugin.psi.impl.SimpleNamedElementImpl"
implements="com.simpleplugin.psi.SimpleNamedElement" methods=[getKey getValue getName setName getNameIdentifier]}
property ::= (KEY? SEPARATOR VALUE?) | KEY {mixin="com.intellij.sdk.language.psi.impl.SimpleNamedElementImpl"
implements="com.intellij.sdk.language.psi.SimpleNamedElement" methods=[getKey getValue getName setName getNameIdentifier]}
```
Don't forget to regenerate the parser! Right click on the `Simple.bnf` file and select _Generate Parser Code_.
### 10.5. Define a reference
Now we need to define a reference class to resolve a property from it's usage.
## 10.5. Define a Reference
Now define a reference class to resolve a property from its usage.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleReference.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleReference.java %}
```
### 10.6. Define a reference contributor
A reference contributor allows you to provide references from elements in other languages such as Java to elements in your language.
Let's contribute a reference to each usage of a property.
## 10.6. Define a Reference Contributor
A reference contributor allows the `simple_language` plugin to provide references to Simple language from elements in other languages such as Java.
Create `SimpleReferenceContributor` by subclassing [`PsiReferenceContributor`](upsource:///platform/core-api/src/com/intellij/psi/PsiReferenceContributor.java).
Contribute a reference to each usage of a property:
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleReferenceContributor.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleReferenceContributor.java %}
```
### 10.7. Register the reference contributor
## 10.7. Register the Reference Contributor
The `SimpleReferenceContributor` implementation is registered with the IntelliJ Platform using the `psi.referenceContributor` extension point.
```xml
<psi.referenceContributor implementation="com.simpleplugin.SimpleReferenceContributor"/>
<extensions defaultExtensionNs="com.intellij">
<psi.referenceContributor implementation="com.intellij.sdk.language.SimpleReferenceContributor"/>
</extensions>
```
### 10.8. Run the project
## 10.8. Run the Project
Rebuild the project, and run `simple_language` in a Development Instance.
The IDE now resolves the property and provides [completion](https://www.jetbrains.com/help/idea/auto-completing-code.html#basic_completion) suggestions:
As you see the IDE now resolves the property and provides completion.
![Reference Contributor](img/reference_contributor.png){:width="800px"}
![Reference Contributor](img/reference_contributor.png)
The [Rename refactoring](https://www.jetbrains.com/help/idea/rename-refactorings.html#invoke-rename-refactoring) functionality is now available from definition and usages.
*Rename* refactoring available from definition and usages.
![Rename](img/rename.png)
### 10.9. Define a refactoring support provider
To allow in-place refactoring we should specify it explicitly in a refactoring support provider.
![Rename](img/rename.png){:width="800px"}
## 10.9. Define a Refactoring Support Provider
To allow in-place refactoring it is specified explicitly in a refactoring support provider.
Create `SimpleRefactoringSupportProvider` by subclassing [`RefactoringSupportProvider`](upsource:///platform/lang-api/src/com/intellij/lang/refactoring/RefactoringSupportProvider.java)
As long as an element is a `SimpleProperty` it is allowed to be refactored:
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleRefactoringSupportProvider.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleRefactoringSupportProvider.java %}
```
### 10.10. Register the refactoring support provider
## 10.10. Register the Refactoring Support Provider
The `SimpleRefactoringSupportProvider` implementation is registered with the IntelliJ Platform using the `lang.refactoringSupport` extension point.
```xml
<lang.refactoringSupport language="Simple" implementationClass="com.simpleplugin.SimpleRefactoringSupportProvider"/>
<extensions defaultExtensionNs="com.intellij">
<lang.refactoringSupport language="Simple" implementationClass="com.intellij.sdk.language.SimpleRefactoringSupportProvider"/>
</extensions>
```
### 10.11. Run the project
## 10.11. Run the Project
Rebuild the project, and run `simple_language` in a Development Instance.
The IDE now supports [refactoring](https://www.jetbrains.com/help/idea/rename-refactorings.html) suggestions:
![In Place Rename](img/in_place_rename.png)
![In Place Rename](img/in_place_rename.png){:width="800px"}

View File

@ -2,33 +2,46 @@
title: 14. Structure View Factory
---
The [structure view](/reference_guide/custom_language_support/structure_view.md) in the IntelliJ Platform-based IDE can be customized for a specific file type, including Simple language.
Creating a structure view factory allows showing the structure of any file in a **Structure** tool window for easy navigation between items.
A structure view factory allows to show the structure of any file in a *Structure* tool window for easy navigation between items.
### 14.1. Define a structure view factory
* bullet list
{:toc}
## 14.1. Define a Structure View Factory
The structure view factory implements [`PsiStructureViewFactory`](upsource:///community/platform/editor-ui-api/src/com/intellij/lang/PsiStructureViewFactory.java).
The `getStructureViewBuilder()` implementation reuses the IntelliJ Platform class [`TreeBasedStructureViewBuilder`](upsource:///community/platform/editor-ui-api/src/com/intellij/ide/structureView/TreeBasedStructureViewBuilder.java).
At this point the project will not compile until `SimpleStructureViewModel` is implemented below.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleStructureViewFactory.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewFactory.java %}
```
### 14.2. Define a structure view model
## 14.2. Define a Structure View Model
The `SimpleStructureViewModel` is created by implementing [`StructureViewModel`](upsource:///platform/editor-ui-api/src/com/intellij/ide/structureView/StructureViewModel.java), which defines the model for data displayed in the standard structure view.
It also extends [`StructureViewModelBase`](upsource:///community/platform/editor-ui-api/src/com/intellij/ide/structureView/StructureViewModelBase.java), an implementation that links the model to a text editor.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleStructureViewModel.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewModel.java %}
```
### 14.3. Define a structure view element
## 14.3. Define a Structure View Element
The `SimpleStructureViewElement` implements [`StructureViewTreeElement`](upsource:///platform/editor-ui-api/src/com/intellij/ide/structureView/StructureViewTreeElement.java) and [`SortableTreeElement`](upsource:///platform/editor-ui-api/src/com/intellij/ide/util/treeView/smartTree/SortableTreeElement.java).
The `StructureViewTreeElement` represents an element in the Structure View tree model.
The `SortableTreeElement` represents an item in a smart tree that allows using text other than the presentable text as a key for alphabetic sorting.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleStructureViewElement.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleStructureViewElement.java %}
```
### 14.4. Register the structure view factory
## 14.4. Register the Structure View Factory
The `SimpleStructureViewFactory` implementation is registered with the IntelliJ Platform in `plugin.xml` using the `lang.psiStructureViewFactory` extension point.
```xml
<lang.psiStructureViewFactory language="Simple" implementationClass="com.simpleplugin.SimpleStructureViewFactory"/>
<extensions defaultExtensionNs="com.intellij">
<lang.psiStructureViewFactory language="Simple" implementationClass="com.intellij.sdk.language.SimpleStructureViewFactory"/>
</extensions>
```
### 14.5. Run the project
## 14.5. Run the Project
Rebuild the project, and run `simple_language` in a Development Instance.
Open the `test.simple` file and choose **View \| Tool Windows \| Structure**.
The IDE now supports a structure view of the Simple language:
![Structure View](img/structure_view.png)
![Structure View](img/structure_view.png){:width="800px"}

View File

@ -2,41 +2,58 @@
title: 5. Syntax Highlighter and Color Settings Page
---
The first level of [syntax highlighting](/reference_guide/custom_language_support/syntax_highlighting_and_error_highlighting.md#lexer) is based on the lexer output, and is provided by `SyntaxHighlighter`.
A plugin can also define [color settings](/reference_guide/custom_language_support/syntax_highlighting_and_error_highlighting.md#color-settings) based on `ColorSettingPage` so the user can configure highlight colors.
The `SimpleSyntaxHighlighter`, `SimpleSyntaxHighlighterFactory`, and `SimpleColorSettingsPage` discussed on this page are demonstrated in the `simple_language` code sample.
### 5.1. Define a syntax highlighter
* bullet list
{:toc}
## 5.1. Define a Syntax Highlighter
The Simple language syntax highlighter class extends [`SyntaxHighlighterBase`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/fileTypes/SyntaxHighlighterBase.java).
As recommended in [Color Scheme Management](/reference_guide/color_scheme_management.md#text-attribute-key-dependency), the Simple language highlighting text attributes are specified as a dependency on one of standard Intellij Platform keys.
For the Simple language, only one scheme is defined.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleSyntaxHighlighter.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleSyntaxHighlighter.java %}
```
### 5.2. Define a syntax highlighter factory
### 5.2. Define a Syntax Highlighter Factory
The factory provides a standard way for the IntelliJ Platform to instantiate the syntax highlighter for Simple language files.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleSyntaxHighlighterFactory.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleSyntaxHighlighterFactory.java %}
```
### 5.3. Register the syntax highlighter factory
### 5.3. Register the Syntax Highlighter Factory
The factory is registered with the IntelliJ Platform using the plugin configuration file.
```xml
<lang.syntaxHighlighterFactory language="Simple" implementationClass="com.simpleplugin.SimpleSyntaxHighlighterFactory"/>
<extensions defaultExtensionNs="com.intellij">
<lang.syntaxHighlighterFactory language="Simple" implementationClass="com.intellij.sdk.language.SimpleSyntaxHighlighterFactory"/>
</extensions>
```
### 5.4. Run the project
### 5.4. Run the Project
Open the example Simple Language [properties file ](/tutorials/custom_language_support/lexer_and_parser_definition.md#47-run-the-project) in the IDE Development Instance.
The colors for Simple Language Key, Separator, and Value highlighting default to the IDE _Language Defaults_ for Keyword, Braces and Operators, and String, respectively.
![Syntax highlighter](img/syntax_highlighter.png)
### 5.5. Define a color settings page
![Syntax highlighter](img/syntax_highlighter.png){:width="800px"}
## 5.5. Define a Color Settings Page
The color settings page adds the ability for users to customize color settings for the highlighting in Simple language files.
The `SimpleColorSettingsPage` extends `ColorSettingsPage`.
```java
{% include /code_samples/simple_language_plugin/src/com/simpleplugin/SimpleColorSettingsPage.java %}
{% include /code_samples/simple_language/src/main/java/com/intellij/sdk/language/SimpleColorSettingsPage.java %}
```
### 5.6. Register the color settings page
### 5.6. Register the Color Settings Page
The settings page for Simple language colors is registered in the plugin configuration file as an extension.
```xml
<colorSettingsPage implementation="com.simpleplugin.SimpleColorSettingsPage"/>
<extensions defaultExtensionNs="com.intellij">
<colorSettingsPage implementation="com.intellij.sdk.language.SimpleColorSettingsPage"/>
</extensions>
```
### 5.7. Run the project
In the IDE Development Instance, open the Simple language highlight settings page: **Preferences/Settings \| Editor \| Color Scheme \| Simple**.
Each color initially inherits from a _Language Defaults_ value.
![Color Settings Page](img/color_settings_page.png)
![Color Settings Page](img/color_settings_page.png){:width="800px"}

View File

@ -2,14 +2,11 @@
title: Custom Language Support Tutorial
---
In this tutorial we will add support for
[.properties](https://en.wikipedia.org/wiki/.properties)
language and its usages within Java code.
The final code can be found in the [SamplePlugin repo on GitHub](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/simple_language_plugin).
This a step-by-step tutorial and it requires performing every step:
In this tutorial we will add support for a [.properties](https://en.wikipedia.org/wiki/.properties) language and its usages within Java code.
IntelliJ Platform support for custom languages is discussed in more depth in the [Custom Language](/reference_guide/custom_language_support.md) section.
The example plugin used in this tutorial is the `simple_language` code sample.
This a step-by-step tutorial, and it requires completing each step, in order:
* [1. Prerequisites](custom_language_support/prerequisites.md)
* [2. Language and File Type](custom_language_support/language_and_filetype.md)
* [3. Grammar and Parser](custom_language_support/grammar_and_parser.md)